diff --git a/meson.build b/meson.build index 5a200a6..9fde0ae 100644 --- a/meson.build +++ b/meson.build @@ -4,6 +4,8 @@ sources = files( 'src/main.cpp', 'src/lexer/lexer.cpp', 'src/parser/parser.cpp', + 'src/typechecker/typechecker.cpp', + 'src/typechecker/type.cpp', 'src/ir/ir.cpp', 'src/compiler/compiler.cpp' ) diff --git a/src/main.cpp b/src/main.cpp index 42a27ad..923c105 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include "lexer/lexer.hpp" #include "parser/parser.hpp" +#include "typechecker/typechecker.hpp" #include #include #include @@ -23,5 +24,8 @@ int main(int argc, char** argv) { auto parsed = parser.parse(); std::cout << parsed << std::endl; + Solstice::TypeChecker typeChecker(parsed); + typeChecker.checkTypes(); + return 0; } diff --git a/src/typechecker/type.cpp b/src/typechecker/type.cpp new file mode 100644 index 0000000..84071a1 --- /dev/null +++ b/src/typechecker/type.cpp @@ -0,0 +1,19 @@ +#include "type.hpp" + +namespace Solstice { + + bool operator==(const Type& left, const Type& right) { + if (left.type != right.type) { + return false; + } + if (left.type == BaseType::Object && left.fields != right.fields) { + return false; + } + return true; + } + + bool operator==(const TypePair& left, const TypePair& right) { + return left.left == right.left && left.right == right.right; + } + +} diff --git a/src/typechecker/type.hpp b/src/typechecker/type.hpp new file mode 100644 index 0000000..4dcbe1b --- /dev/null +++ b/src/typechecker/type.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include + +namespace Solstice { + enum class BaseType { + None, Int, Double, String, Char, Bool, Array, Pointer, Object + }; + + enum class Operator { + Add, Subtract, Multiply, Divide, Equal, NotEqual, GreaterThan, LesserThan + }; + + struct Type { + BaseType type = BaseType::None; + std::map fields; // use map for ordering + + Type() = delete; + Type(BaseType type) : type(type) {} + }; + + bool operator==(const Type& left, const Type& right); + + struct TypePair { + Type left; + Type right; + TypePair() = delete; + TypePair(const Type& left, const Type& right) : left(left), right(right) {} + }; + + bool operator==(const TypePair& left, const TypePair& right); +} + +namespace std { + template<> + struct hash { + size_t operator()(const Solstice::Type& t) const { + size_t output = std::hash{}((int)t.type); + for (const auto& [key, value] : t.fields) { + size_t keyHash = std::hash{}(key); + size_t valHash = std::hash{}(value); + + output ^= keyHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2); + output ^= valHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2); + } + return output; + } + }; + + template<> + struct hash { + size_t operator()(const Solstice::TypePair& t) const { + size_t leftHash = std::hash{}(t.left); + size_t rightHash = std::hash{}(t.right); + + leftHash ^= rightHash + 0x9e3779b97f4a7c15ULL + (leftHash << 6) + (leftHash >> 2); + return leftHash; + } + }; +} + +namespace Solstice { + + struct PossibleType { + std::unordered_set possiblities; + }; + +} diff --git a/src/typechecker/typechecker.cpp b/src/typechecker/typechecker.cpp new file mode 100644 index 0000000..d92abae --- /dev/null +++ b/src/typechecker/typechecker.cpp @@ -0,0 +1,72 @@ +#include "typechecker.hpp" + +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}, + }; + } + + +} diff --git a/src/typechecker/typechecker.hpp b/src/typechecker/typechecker.hpp new file mode 100644 index 0000000..96fbfcf --- /dev/null +++ b/src/typechecker/typechecker.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "type.hpp" +#include "../parser/parser.hpp" + +#include +#include + +namespace Solstice { + + class TypeChecker { + std::unordered_map variables; + std::unordered_map types; + + std::unordered_map addOverloads; + std::unordered_map subtractOverloads; + std::unordered_map multiplyOverloads; + std::unordered_map divideOverloads; + std::unordered_map equalOverloads; + std::unordered_map notEqualOverloads; + std::unordered_map greaterThanOverloads; + std::unordered_map lesserThanOverloads; + + Node& input; + + void initOverloads(); + + public: + + TypeChecker() = delete; + TypeChecker(Node& node) : input(node) { + initOverloads(); + } + + void checkTypes(); + }; +}