stuffs
This commit is contained in:
@@ -17,9 +17,9 @@ namespace Solstice {
|
||||
Add, Subtract, Multiply, Divide, Equal, NotEqual, GreaterThan, LesserThan
|
||||
};
|
||||
|
||||
struct Type {
|
||||
BaseType type = BaseType::None;
|
||||
std::variant<
|
||||
struct Type;
|
||||
|
||||
using TypeData = std::variant<
|
||||
// object
|
||||
std::map<std::string, Type>, // use map for ordering
|
||||
// tuple
|
||||
@@ -28,16 +28,20 @@ namespace Solstice {
|
||||
std::shared_ptr<Type>,
|
||||
// anything else
|
||||
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::vector<Type>> getTuple() const;
|
||||
std::optional<Type> getArrayOrPointer() const;
|
||||
|
||||
TypeData fields = std::nullopt;
|
||||
|
||||
Type() = default;
|
||||
Type(BaseType type) : type(type) {}
|
||||
Type(BaseType type, TypeData fields) : type(type), fields(fields) {}
|
||||
};
|
||||
|
||||
bool operator==(const Type& left, const Type& right);
|
||||
@@ -99,6 +103,23 @@ namespace std {
|
||||
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 {
|
||||
@@ -106,6 +127,9 @@ namespace Solstice {
|
||||
struct PossibleType {
|
||||
std::unordered_set<Type> possiblities;
|
||||
|
||||
bool unknownType = false;
|
||||
bool isConstant = false;
|
||||
|
||||
PossibleType() = default;
|
||||
PossibleType(const std::unordered_set<Type>& possiblities) : possiblities(possiblities) {}
|
||||
|
||||
@@ -113,13 +137,9 @@ namespace Solstice {
|
||||
};
|
||||
|
||||
struct Function {
|
||||
PossibleType returnType = {{BaseType::None}};
|
||||
std::vector<PossibleType> argumentTypes = {};
|
||||
std::unordered_map<std::vector<Type>, Type> signatureToReturnType;
|
||||
|
||||
Function() = default;
|
||||
Function(PossibleType returnType) : returnType(returnType) {}
|
||||
Function(PossibleType returnType, std::vector<PossibleType> argumentTypes)
|
||||
: returnType(returnType), argumentTypes(argumentTypes) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,20 @@
|
||||
namespace Solstice {
|
||||
|
||||
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 = {
|
||||
{{BaseType::Int, BaseType::Int}, BaseType::Int},
|
||||
{{BaseType::Double, BaseType::Double}, BaseType::Double},
|
||||
@@ -132,7 +146,7 @@ namespace Solstice {
|
||||
if (!nodeType.has_value()) {
|
||||
throw std::runtime_error("cannot assign ambiguous type to name");
|
||||
}
|
||||
variables[*id] = *nodeType;
|
||||
variables[*id] = {{*nodeType}};
|
||||
variables[*id].isConstant = true;
|
||||
}
|
||||
|
||||
@@ -144,13 +158,45 @@ namespace Solstice {
|
||||
if (variables.find(*id) != variables.end()) {
|
||||
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[1].ptype.getOnlyType();
|
||||
auto nodeType = node.children[2].ptype.getOnlyType();
|
||||
if (!nodeType.has_value()) {
|
||||
throw std::runtime_error("cannot assign ambiguous type to name");
|
||||
}
|
||||
variables[*id] = *nodeType;
|
||||
variables[*id] = {{*nodeType}};
|
||||
variables[*id].isConstant = true;
|
||||
}
|
||||
|
||||
@@ -173,10 +219,21 @@ namespace Solstice {
|
||||
if (!nodeType.has_value()) {
|
||||
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) {
|
||||
@@ -184,7 +241,16 @@ namespace Solstice {
|
||||
case NodeType::Root:
|
||||
node.ptype = {{}}; // no possible types for root node
|
||||
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;
|
||||
case NodeType::Literal:
|
||||
@@ -211,12 +277,36 @@ namespace Solstice {
|
||||
case NodeType::CodeBlock:
|
||||
checkCodeBlockType(node);
|
||||
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() {
|
||||
checkNodeType(input);
|
||||
checkNodeType(*input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace Solstice {
|
||||
|
||||
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<TypePair, Type> addOverloads;
|
||||
@@ -21,7 +21,7 @@ namespace Solstice {
|
||||
std::unordered_map<TypePair, Type> greaterThanOverloads;
|
||||
std::unordered_map<TypePair, Type> lesserThanOverloads;
|
||||
|
||||
Node& input;
|
||||
Node* input;
|
||||
|
||||
bool inFunction = false;
|
||||
|
||||
@@ -37,15 +37,38 @@ namespace Solstice {
|
||||
|
||||
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);
|
||||
|
||||
public:
|
||||
|
||||
TypeChecker() = delete;
|
||||
TypeChecker(Node& node) : input(node) {
|
||||
TypeChecker(Node& node) : input(&node) {
|
||||
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();
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user