This commit is contained in:
2026-08-02 15:14:43 +10:00
parent 16846d13bb
commit cf79fd00b9
3 changed files with 154 additions and 21 deletions

View File

@@ -17,9 +17,9 @@ namespace Solstice {
Add, Subtract, Multiply, Divide, Equal, NotEqual, GreaterThan, LesserThan Add, Subtract, Multiply, Divide, Equal, NotEqual, GreaterThan, LesserThan
}; };
struct Type { struct Type;
BaseType type = BaseType::None;
std::variant< using TypeData = std::variant<
// object // object
std::map<std::string, Type>, // use map for ordering std::map<std::string, Type>, // use map for ordering
// tuple // tuple
@@ -28,16 +28,20 @@ namespace Solstice {
std::shared_ptr<Type>, std::shared_ptr<Type>,
// anything else // anything else
std::nullopt_t std::nullopt_t
> fields = std::nullopt; >;
bool isConstant = false; struct Type {
BaseType type = BaseType::None;
std::optional<std::map<std::string, Type>> getObject() const; std::optional<std::map<std::string, Type>> getObject() const;
std::optional<std::vector<Type>> getTuple() const; std::optional<std::vector<Type>> getTuple() const;
std::optional<Type> getArrayOrPointer() const; std::optional<Type> getArrayOrPointer() const;
TypeData fields = std::nullopt;
Type() = default; Type() = default;
Type(BaseType type) : type(type) {} Type(BaseType type) : type(type) {}
Type(BaseType type, TypeData fields) : type(type), fields(fields) {}
}; };
bool operator==(const Type& left, const Type& right); bool operator==(const Type& left, const Type& right);
@@ -99,6 +103,23 @@ namespace std {
return leftHash; return leftHash;
} }
}; };
template<>
struct hash<vector<Solstice::Type>> {
size_t operator()(const vector<Solstice::Type> v) const {
size_t hash = 0;
for (const auto& type : v) {
size_t typeHash = std::hash<Solstice::Type>{}(type);
if (hash == 0) {
hash = typeHash;
} else {
hash ^= typeHash + 0x9e3779b97f4a7c15ULL + (hash << 6) + (hash >> 2);
}
}
return hash;
}
};
} }
namespace Solstice { namespace Solstice {
@@ -106,6 +127,9 @@ namespace Solstice {
struct PossibleType { struct PossibleType {
std::unordered_set<Type> possiblities; std::unordered_set<Type> possiblities;
bool unknownType = false;
bool isConstant = false;
PossibleType() = default; PossibleType() = default;
PossibleType(const std::unordered_set<Type>& possiblities) : possiblities(possiblities) {} PossibleType(const std::unordered_set<Type>& possiblities) : possiblities(possiblities) {}
@@ -113,13 +137,9 @@ namespace Solstice {
}; };
struct Function { struct Function {
PossibleType returnType = {{BaseType::None}}; std::unordered_map<std::vector<Type>, Type> signatureToReturnType;
std::vector<PossibleType> argumentTypes = {};
Function() = default; Function() = default;
Function(PossibleType returnType) : returnType(returnType) {}
Function(PossibleType returnType, std::vector<PossibleType> argumentTypes)
: returnType(returnType), argumentTypes(argumentTypes) {}
}; };
} }

View File

@@ -6,6 +6,20 @@
namespace Solstice { namespace Solstice {
void TypeChecker::initOverloads() { 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 = { addOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Int}, {{BaseType::Int, BaseType::Int}, BaseType::Int},
{{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Double}, BaseType::Double},
@@ -132,7 +146,7 @@ namespace Solstice {
if (!nodeType.has_value()) { if (!nodeType.has_value()) {
throw std::runtime_error("cannot assign ambiguous type to name"); throw std::runtime_error("cannot assign ambiguous type to name");
} }
variables[*id] = *nodeType; variables[*id] = {{*nodeType}};
variables[*id].isConstant = true; variables[*id].isConstant = true;
} }
@@ -144,13 +158,45 @@ namespace Solstice {
if (variables.find(*id) != variables.end()) { if (variables.find(*id) != variables.end()) {
throw std::runtime_error("Cannot overwrite existing bind/variable/function with new function"); 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[2].ptype.getOnlyType();
auto nodeType = node.children[1].ptype.getOnlyType();
if (!nodeType.has_value()) { if (!nodeType.has_value()) {
throw std::runtime_error("cannot assign ambiguous type to name"); throw std::runtime_error("cannot assign ambiguous type to name");
} }
variables[*id] = *nodeType; variables[*id] = {{*nodeType}};
variables[*id].isConstant = true; variables[*id].isConstant = true;
} }
@@ -173,10 +219,21 @@ namespace Solstice {
if (!nodeType.has_value()) { if (!nodeType.has_value()) {
throw std::runtime_error("cannot assign ambiguous type to name"); 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) { void TypeChecker::checkNodeType(Node& node) {
@@ -184,7 +241,16 @@ namespace Solstice {
case NodeType::Root: case NodeType::Root:
node.ptype = {{}}; // no possible types for root node node.ptype = {{}}; // no possible types for root node
for (auto& child : node.children) { 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; break;
case NodeType::Literal: case NodeType::Literal:
@@ -211,12 +277,36 @@ namespace Solstice {
case NodeType::CodeBlock: case NodeType::CodeBlock:
checkCodeBlockType(node); checkCodeBlockType(node);
break; 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() { void TypeChecker::checkTypes() {
checkNodeType(input); checkNodeType(*input);
} }

View File

@@ -9,7 +9,7 @@
namespace Solstice { namespace Solstice {
class TypeChecker { class TypeChecker {
std::unordered_map<std::string, Type> variables; std::unordered_map<std::string, PossibleType> variables;
std::unordered_map<std::string, Type> types; std::unordered_map<std::string, Type> types;
std::unordered_map<TypePair, Type> addOverloads; std::unordered_map<TypePair, Type> addOverloads;
@@ -21,7 +21,7 @@ namespace Solstice {
std::unordered_map<TypePair, Type> greaterThanOverloads; std::unordered_map<TypePair, Type> greaterThanOverloads;
std::unordered_map<TypePair, Type> lesserThanOverloads; std::unordered_map<TypePair, Type> lesserThanOverloads;
Node& input; Node* input;
bool inFunction = false; bool inFunction = false;
@@ -37,15 +37,38 @@ namespace Solstice {
void checkCodeBlockType(Node& node); 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); void checkNodeType(Node& node);
public: public:
TypeChecker() = delete; TypeChecker() = delete;
TypeChecker(Node& node) : input(node) { TypeChecker(Node& node) : input(&node) {
initOverloads(); 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(); void checkTypes();
}; };
} }