From 222c71ebe1a44af4c69526f09f6282efd0bb184d Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sun, 2 Aug 2026 08:59:18 +1000 Subject: [PATCH] Keep working on type checker --- src/parser/parser.hpp | 3 ++ src/typechecker/type.cpp | 46 ++++++++++++++++++++-- src/typechecker/type.hpp | 56 +++++++++++++++++++++++---- src/typechecker/typechecker.cpp | 68 +++++++++++++++++++++++++++++++++ src/typechecker/typechecker.hpp | 8 +++- 5 files changed, 169 insertions(+), 12 deletions(-) diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index 50e0071..10ac5c0 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -5,6 +5,7 @@ #include #include "../lexer/lexer.hpp" +#include "../typechecker/type.hpp" namespace Solstice { @@ -40,6 +41,8 @@ namespace Solstice { std::vector children; std::variant data; + PossibleType ptype; + Node() = delete; Node(NodeType type) : type(type) {} Node(NodeType type, const std::vector& children) : type(type), children(children) {} diff --git a/src/typechecker/type.cpp b/src/typechecker/type.cpp index 84071a1..4eb22ac 100644 --- a/src/typechecker/type.cpp +++ b/src/typechecker/type.cpp @@ -1,15 +1,55 @@ #include "type.hpp" +#include namespace Solstice { + std::optional> Type::getObject() const { + if (std::holds_alternative>(fields)) { + return std::get>(fields); + } + return {}; + } + std::optional> Type::getTuple() const { + if (std::holds_alternative>(fields)) { + return std::get>(fields); + } + return {}; + } + std::optional Type::getArrayOrPointer() const { + if (std::holds_alternative>(fields)) { + return *std::get>(fields); + } + return {}; + + } + 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; + switch (left.type) { + case BaseType::Object: { + auto leftObject = left.getObject(); + auto rightObject = right.getObject(); + + return *leftObject == *rightObject; + } + case BaseType::Tuple: { + auto leftTuple = left.getTuple(); + auto rightTuple = right.getTuple(); + + return *leftTuple == *rightTuple; + } + case BaseType::Array: + case BaseType::Pointer: { + auto leftType = left.getArrayOrPointer(); + auto rightType = right.getArrayOrPointer(); + + return *leftType == *rightType; + } + + default: return true; } - return true; } bool operator==(const TypePair& left, const TypePair& right) { diff --git a/src/typechecker/type.hpp b/src/typechecker/type.hpp index 4dcbe1b..4eae77e 100644 --- a/src/typechecker/type.hpp +++ b/src/typechecker/type.hpp @@ -1,13 +1,16 @@ #pragma once #include +#include +#include #include #include #include +#include namespace Solstice { enum class BaseType { - None, Int, Double, String, Char, Bool, Array, Pointer, Object + None, Int, Double, String, Char, Bool, Tuple, Array, Pointer, Object }; enum class Operator { @@ -16,7 +19,20 @@ namespace Solstice { struct Type { BaseType type = BaseType::None; - std::map fields; // use map for ordering + std::variant< + // object + std::map, // use map for ordering + // tuple + std::vector, + // array/pointer + std::shared_ptr, + // anything else + std::nullopt_t + > fields = std::nullopt; + + std::optional> getObject() const; + std::optional> getTuple() const; + std::optional getArrayOrPointer() const; Type() = delete; Type(BaseType type) : type(type) {} @@ -39,12 +55,33 @@ namespace std { 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); + switch (t.type) { + case Solstice::BaseType::Object: { + auto object = t.getObject(); + for (const auto& [key, value] : *object) { + 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); + } + break; + } + case Solstice::BaseType::Tuple: { + auto tuple = t.getTuple(); + for (const auto& type : *tuple) { + size_t typeHash = std::hash{}(type); + output ^= typeHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2); + } + break; + } + case Solstice::BaseType::Array: + case Solstice::BaseType::Pointer: { + auto type = t.getArrayOrPointer(); + size_t typeHash = std::hash{}(*type); + output ^= typeHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2); + } + default: break; } return output; } @@ -66,6 +103,9 @@ namespace Solstice { struct PossibleType { std::unordered_set possiblities; + + PossibleType() = default; + PossibleType(const std::unordered_set& possiblities) : possiblities(possiblities) {} }; } diff --git a/src/typechecker/typechecker.cpp b/src/typechecker/typechecker.cpp index d92abae..9e16ebf 100644 --- a/src/typechecker/typechecker.cpp +++ b/src/typechecker/typechecker.cpp @@ -1,4 +1,6 @@ #include "typechecker.hpp" +#include "type.hpp" +#include namespace Solstice { @@ -68,5 +70,71 @@ namespace Solstice { }; } + 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) {} + + void TypeChecker::checkNodeType(Node& node) { + switch (node.type) { + case NodeType::Root: + node.ptype = {{}}; // no possible types for root node + 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; + } + } + + void TypeChecker::checkTypes() { + checkNodeType(input); + } + } diff --git a/src/typechecker/typechecker.hpp b/src/typechecker/typechecker.hpp index 96fbfcf..494813a 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; @@ -25,6 +25,12 @@ namespace Solstice { void initOverloads(); + void checkLiteralNodeType(Node& node); + void checkIdentifierNodeType(Node& node); + void checkTupleNodeType(Node& node); + + void checkNodeType(Node& node); + public: TypeChecker() = delete;