Start working on type checker

This commit is contained in:
2026-08-01 22:12:05 +10:00
parent 372be46394
commit a8da871aa4
6 changed files with 205 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
#include "lexer/lexer.hpp"
#include "parser/parser.hpp"
#include "typechecker/typechecker.hpp"
#include <iostream>
#include <fstream>
#include <ostream>
@@ -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;
}

19
src/typechecker/type.cpp Normal file
View File

@@ -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;
}
}

71
src/typechecker/type.hpp Normal file
View File

@@ -0,0 +1,71 @@
#pragma once
#include <functional>
#include <unordered_set>
#include <map>
#include <string>
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<std::string, Type> 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<Solstice::Type> {
size_t operator()(const Solstice::Type& t) const {
size_t output = std::hash<int>{}((int)t.type);
for (const auto& [key, value] : t.fields) {
size_t keyHash = std::hash<std::string>{}(key);
size_t valHash = std::hash<Solstice::Type>{}(value);
output ^= keyHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
output ^= valHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
}
return output;
}
};
template<>
struct hash<Solstice::TypePair> {
size_t operator()(const Solstice::TypePair& t) const {
size_t leftHash = std::hash<Solstice::Type>{}(t.left);
size_t rightHash = std::hash<Solstice::Type>{}(t.right);
leftHash ^= rightHash + 0x9e3779b97f4a7c15ULL + (leftHash << 6) + (leftHash >> 2);
return leftHash;
}
};
}
namespace Solstice {
struct PossibleType {
std::unordered_set<Type> possiblities;
};
}

View File

@@ -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},
};
}
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include "type.hpp"
#include "../parser/parser.hpp"
#include <string>
#include <unordered_map>
namespace Solstice {
class TypeChecker {
std::unordered_map<std::string, Type> variables;
std::unordered_map<std::string, Type> types;
std::unordered_map<TypePair, Type> addOverloads;
std::unordered_map<TypePair, Type> subtractOverloads;
std::unordered_map<TypePair, Type> multiplyOverloads;
std::unordered_map<TypePair, Type> divideOverloads;
std::unordered_map<TypePair, Type> equalOverloads;
std::unordered_map<TypePair, Type> notEqualOverloads;
std::unordered_map<TypePair, Type> greaterThanOverloads;
std::unordered_map<TypePair, Type> lesserThanOverloads;
Node& input;
void initOverloads();
public:
TypeChecker() = delete;
TypeChecker(Node& node) : input(node) {
initOverloads();
}
void checkTypes();
};
}