#include "typechecker.hpp" #include "type.hpp" #include #include namespace Solstice { void TypeChecker::initOverloads() { addOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Int}, {{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Int}, BaseType::Double}, {{BaseType::String, BaseType::String}, BaseType::String}, {{BaseType::String, BaseType::Char}, BaseType::String}, {{BaseType::Char, BaseType::String}, BaseType::String}, {{BaseType::Char, BaseType::Char}, BaseType::Char} }; subtractOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Int}, {{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Int}, BaseType::Double}, {{BaseType::Char, BaseType::Char}, BaseType::Char} }; multiplyOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Int}, {{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Int}, BaseType::Double}, {{BaseType::Char, BaseType::Char}, BaseType::Char} }; divideOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Double}, {{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Int}, BaseType::Double}, {{BaseType::Char, BaseType::Char}, BaseType::Char} }; equalOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Int}, BaseType::Bool}, {{BaseType::String, BaseType::String}, BaseType::Bool}, {{BaseType::Char, BaseType::Char}, BaseType::Bool}, {{BaseType::Bool, BaseType::Bool}, BaseType::Bool}, }; notEqualOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Int}, BaseType::Bool}, {{BaseType::String, BaseType::String}, BaseType::Bool}, {{BaseType::Char, BaseType::Char}, BaseType::Bool}, {{BaseType::Bool, BaseType::Bool}, BaseType::Bool}, }; greaterThanOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Int}, BaseType::Bool}, {{BaseType::Char, BaseType::Char}, BaseType::Bool}, }; lesserThanOverloads = { {{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Int}, BaseType::Bool}, {{BaseType::Char, BaseType::Char}, BaseType::Bool}, }; } void TypeChecker::checkLiteralNodeType(Node& node) { auto literal = node.getLiteral(); if (!literal.has_value()) { throw std::runtime_error("FIXME literal node does not contain literal"); } switch (literal->type) { case LiteralType::None: node.ptype = {{BaseType::None}}; break; case LiteralType::String: node.ptype = {{BaseType::String}}; break; case LiteralType::Int: node.ptype = {{BaseType::Int}}; break; case LiteralType::Double: node.ptype = {{BaseType::Double}}; break; case LiteralType::Bool: node.ptype = {{BaseType::Bool}}; break; case LiteralType::Char: node.ptype = {{BaseType::Char}}; break; } } void TypeChecker::checkIdentifierNodeType(Node& node) { auto identifier = node.getIdentifier(); if (!identifier.has_value()) { throw std::runtime_error("FIXME identifier node does not contain identifier"); } if (variables.find(*identifier) == variables.end()) { throw std::runtime_error("unknown variable " + *identifier); } node.ptype = {{variables[*identifier]}}; } void TypeChecker::checkTupleNodeType(Node& node) { for (auto& child : node.children) { checkNodeType(child); } // TODO implemnt tuple type checking } void TypeChecker::checkBindNodeType(Node& node) { auto id = node.children[0].getIdentifier(); if (!id.has_value()) { throw std::runtime_error("FIXME identifier node does not contain identifier"); } if (variables.find(*id) != variables.end()) { throw std::runtime_error("Cannot overwrite existing bind/variable/function with new bind"); } checkNodeType(node.children[1]); auto nodeType = node.children[1].ptype.getOnlyType(); if (!nodeType.has_value()) { throw std::runtime_error("cannot assign ambiguous type to name"); } variables[*id] = *nodeType; variables[*id].isConstant = true; } void TypeChecker::checkFunctionBindNodeType(Node& node) { auto id = node.children[0].getIdentifier(); if (!id.has_value()) { throw std::runtime_error("FIXME identifier node does not contain identifier"); } if (variables.find(*id) != variables.end()) { throw std::runtime_error("Cannot overwrite existing bind/variable/function with new function"); } checkNodeType(node.children[1]); auto nodeType = node.children[1].ptype.getOnlyType(); if (!nodeType.has_value()) { throw std::runtime_error("cannot assign ambiguous type to name"); } variables[*id] = *nodeType; variables[*id].isConstant = true; } void TypeChecker::checkSetNodeType(Node& node) { auto id = node.children[0].getIdentifier(); if (!id.has_value()) { throw std::runtime_error("FIXME identifier node does not contain identifier"); } if (variables.find(*id) != variables.end()) { if (variables[*id].isConstant) { throw std::runtime_error("cannot reassign existing bind"); } } if (!inFunction) { throw std::runtime_error("mutable variables may only be used in functions"); } checkNodeType(node.children[1]); auto nodeType = node.children[1].ptype.getOnlyType(); if (!nodeType.has_value()) { throw std::runtime_error("cannot assign ambiguous type to name"); } variables[*id] = *nodeType; } void TypeChecker::checkCodeBlockType(Node& node) {} void TypeChecker::checkNodeType(Node& node) { switch (node.type) { case NodeType::Root: node.ptype = {{}}; // no possible types for root node for (auto& child : node.children) { checkNodeType(child); } break; case NodeType::Literal: checkLiteralNodeType(node); break; case NodeType::Expression: checkNodeType(node.children[0]); break; case NodeType::Identifier: checkIdentifierNodeType(node); break; case NodeType::Tuple: checkTupleNodeType(node); break; case NodeType::Bind: checkBindNodeType(node); break; case NodeType::FunctionBind: checkFunctionBindNodeType(node); break; case NodeType::Set: checkSetNodeType(node); break; case NodeType::CodeBlock: checkCodeBlockType(node); break; } } void TypeChecker::checkTypes() { checkNodeType(input); } }