diff --git a/src/typechecker/type.hpp b/src/typechecker/type.hpp index 858fba0..dca778b 100644 --- a/src/typechecker/type.hpp +++ b/src/typechecker/type.hpp @@ -17,9 +17,9 @@ namespace Solstice { Add, Subtract, Multiply, Divide, Equal, NotEqual, GreaterThan, LesserThan }; - struct Type { - BaseType type = BaseType::None; - std::variant< + struct Type; + + using TypeData = std::variant< // object std::map, // use map for ordering // tuple @@ -28,16 +28,20 @@ namespace Solstice { std::shared_ptr, // anything else std::nullopt_t - > fields = std::nullopt; + >; - bool isConstant = false; + struct Type { + BaseType type = BaseType::None; std::optional> getObject() const; std::optional> getTuple() const; std::optional getArrayOrPointer() const; + TypeData fields = std::nullopt; + Type() = default; Type(BaseType type) : type(type) {} + Type(BaseType type, TypeData fields) : type(type), fields(fields) {} }; bool operator==(const Type& left, const Type& right); @@ -99,6 +103,23 @@ namespace std { return leftHash; } }; + + template<> + struct hash> { + size_t operator()(const vector v) const { + size_t hash = 0; + for (const auto& type : v) { + size_t typeHash = std::hash{}(type); + if (hash == 0) { + hash = typeHash; + } else { + hash ^= typeHash + 0x9e3779b97f4a7c15ULL + (hash << 6) + (hash >> 2); + + } + } + return hash; + } + }; } namespace Solstice { @@ -106,6 +127,9 @@ namespace Solstice { struct PossibleType { std::unordered_set possiblities; + bool unknownType = false; + bool isConstant = false; + PossibleType() = default; PossibleType(const std::unordered_set& possiblities) : possiblities(possiblities) {} @@ -113,13 +137,9 @@ namespace Solstice { }; struct Function { - PossibleType returnType = {{BaseType::None}}; - std::vector argumentTypes = {}; + std::unordered_map, Type> signatureToReturnType; Function() = default; - Function(PossibleType returnType) : returnType(returnType) {} - Function(PossibleType returnType, std::vector argumentTypes) - : returnType(returnType), argumentTypes(argumentTypes) {} }; } diff --git a/src/typechecker/typechecker.cpp b/src/typechecker/typechecker.cpp index 4f812c4..63b9a81 100644 --- a/src/typechecker/typechecker.cpp +++ b/src/typechecker/typechecker.cpp @@ -6,6 +6,20 @@ namespace Solstice { void TypeChecker::initOverloads() { + + types = { + {"Int", {BaseType::Int}}, + {"String", {BaseType::String}}, + {"Double", {BaseType::Double}}, + {"Bool", {BaseType::Bool}}, + {"Char", {BaseType::Char}}, + {"None", {}}, + {"Tuple", {BaseType::Tuple}}, + {"Array", {BaseType::Array}}, + {"Pointer", {BaseType::Tuple}}, + {"Object", {BaseType::Tuple}}, + }; + addOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Int}, {{BaseType::Double, BaseType::Double}, BaseType::Double}, @@ -132,7 +146,7 @@ namespace Solstice { if (!nodeType.has_value()) { throw std::runtime_error("cannot assign ambiguous type to name"); } - variables[*id] = *nodeType; + variables[*id] = {{*nodeType}}; variables[*id].isConstant = true; } @@ -144,13 +158,45 @@ namespace Solstice { if (variables.find(*id) != variables.end()) { throw std::runtime_error("Cannot overwrite existing bind/variable/function with new function"); } + + // create sub-checker + TypeChecker typeChecker(*this); + typeChecker.setNode(node.children[2]); + + for (const auto& arg : node.children[1].children) { + switch (arg.type) { + case NodeType::Identifier: { + typeChecker.setVariableUnknown(*arg.getIdentifier()); + break; + } + case NodeType::SetType: { + // type annotation provided + if (arg.children[0].type != NodeType::Identifier && arg.children[1].type != NodeType::Identifier) { + throw std::runtime_error("Invalid function parameter definition"); + } + auto typeId = arg.children[1].getIdentifier(); + if (!typeId.has_value()) { + throw std::runtime_error("FIXME identifier node does not contain identifier"); + } + if (types.find(*typeId) == types.end()) { + throw std::runtime_error("unknown type " + *typeId); + } + typeChecker.setVariable(*arg.children[0].getIdentifier(), types[*typeId]); + break; + } + default: { + throw std::runtime_error("Invalid function parameter definition"); + } + } + } + + typeChecker.checkTypes(); - checkNodeType(node.children[1]); - auto nodeType = node.children[1].ptype.getOnlyType(); + auto nodeType = node.children[2].ptype.getOnlyType(); if (!nodeType.has_value()) { throw std::runtime_error("cannot assign ambiguous type to name"); } - variables[*id] = *nodeType; + variables[*id] = {{*nodeType}}; variables[*id].isConstant = true; } @@ -173,10 +219,21 @@ namespace Solstice { if (!nodeType.has_value()) { throw std::runtime_error("cannot assign ambiguous type to name"); } - variables[*id] = *nodeType; + variables[*id] = {{*nodeType}}; } - void TypeChecker::checkCodeBlockType(Node& node) {} + void TypeChecker::checkCodeBlockType(Node& node) { + + return; + } + + void TypeChecker::checkAddType(Node& node) { + // check node children + checkNodeType(node.children[0]); + checkNodeType(node.children[1]); + + + } void TypeChecker::checkNodeType(Node& node) { @@ -184,7 +241,16 @@ namespace Solstice { case NodeType::Root: node.ptype = {{}}; // no possible types for root node for (auto& child : node.children) { - checkNodeType(child); + // only allow certain node types in the root + switch (child.type) { + case NodeType::Bind: + case NodeType::FunctionBind: + checkNodeType(child); + break; + default: + throw std::runtime_error("Illegal node type in file root"); + + } } break; case NodeType::Literal: @@ -211,12 +277,36 @@ namespace Solstice { case NodeType::CodeBlock: checkCodeBlockType(node); break; + case NodeType::Add: + checkAddType(node); + break; + case NodeType::Subtract: + checkSubtractType(node); + break; + case NodeType::Multiply: + checkMultiplyType(node); + break; + case NodeType::Divide: + checkDivideType(node); + break; + case NodeType::Equal: + checkEqualType(node); + break; + case NodeType::NotEqual: + checkNotEqualType(node); + break; + case NodeType::GreaterThan: + checkGreaterThanType(node); + break; + case NodeType::LesserThan: + checkLesserThanType(node); + break; } } void TypeChecker::checkTypes() { - checkNodeType(input); + checkNodeType(*input); } diff --git a/src/typechecker/typechecker.hpp b/src/typechecker/typechecker.hpp index f068e95..d6552a3 100644 --- a/src/typechecker/typechecker.hpp +++ b/src/typechecker/typechecker.hpp @@ -9,7 +9,7 @@ namespace Solstice { class TypeChecker { - std::unordered_map variables; + std::unordered_map variables; std::unordered_map types; std::unordered_map addOverloads; @@ -21,7 +21,7 @@ namespace Solstice { std::unordered_map greaterThanOverloads; std::unordered_map lesserThanOverloads; - Node& input; + Node* input; bool inFunction = false; @@ -37,15 +37,38 @@ namespace Solstice { void checkCodeBlockType(Node& node); + void checkAddType(Node& node); + void checkSubtractType(Node& node); + void checkMultiplyType(Node& node); + void checkDivideType(Node& node); + + void checkEqualType(Node& node); + void checkNotEqualType(Node& node); + void checkGreaterThanType(Node& node); + void checkLesserThanType(Node& node); + void checkNodeType(Node& node); public: TypeChecker() = delete; - TypeChecker(Node& node) : input(node) { + TypeChecker(Node& node) : input(&node) { initOverloads(); } + void setNode(Node& node) { + input = &node; + } + + // Only for use as a public function. + void setVariable(const std::string& name, const Type& type) { + variables[name] = {{type}}; + } + + void setVariableUnknown(const std::string& name) { + variables[name].unknownType = true; + } + void checkTypes(); }; }