stuffs
This commit is contained in:
@@ -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) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,12 +159,44 @@ namespace Solstice {
|
|||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkNodeType(node.children[1]);
|
// create sub-checker
|
||||||
auto nodeType = node.children[1].ptype.getOnlyType();
|
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();
|
||||||
|
|
||||||
|
auto nodeType = node.children[2].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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user