A bunch more stuffs
This commit is contained in:
@@ -242,6 +242,60 @@ namespace Solstice {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case '=': {
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() && *peek() == '=') {
|
||||||
|
output.push_back(TT::Comparison_Equal);
|
||||||
|
consume();
|
||||||
|
} else {
|
||||||
|
output.push_back(TT::Assign_Set);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '/': {
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() && *peek() == '/') {
|
||||||
|
consume();
|
||||||
|
// comment
|
||||||
|
for (;;) {
|
||||||
|
auto next = consume();
|
||||||
|
if (!next.has_value()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*next == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (peek() && *peek() == '*') {
|
||||||
|
consume();
|
||||||
|
/* comment */
|
||||||
|
for (;;) {
|
||||||
|
auto next = consume();
|
||||||
|
if (!next.has_value()) {
|
||||||
|
throw std::runtime_error("unterminated multi-line comment");
|
||||||
|
}
|
||||||
|
if (*next == '*') {
|
||||||
|
if (peek() && *peek() == '/') {
|
||||||
|
consume();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output.push_back(TT::Assign_Set);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// all the delimiters
|
// all the delimiters
|
||||||
case '<':
|
case '<':
|
||||||
case '>':
|
case '>':
|
||||||
@@ -251,7 +305,6 @@ namespace Solstice {
|
|||||||
case ')':
|
case ')':
|
||||||
case '+':
|
case '+':
|
||||||
case '*':
|
case '*':
|
||||||
case '/':
|
|
||||||
case ',':
|
case ',':
|
||||||
{
|
{
|
||||||
if (!buf.empty()) {
|
if (!buf.empty()) {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ namespace Solstice {
|
|||||||
{TT::Comparison_NotEqual, NodeType::NotEqual},
|
{TT::Comparison_NotEqual, NodeType::NotEqual},
|
||||||
{TT::Comparison_GreaterThan, NodeType::GreaterThan},
|
{TT::Comparison_GreaterThan, NodeType::GreaterThan},
|
||||||
{TT::Comparison_LesserThan, NodeType::LesserThan},
|
{TT::Comparison_LesserThan, NodeType::LesserThan},
|
||||||
|
{TT::Assign_Type, NodeType::SetType},
|
||||||
|
{TT::Assign_Set, NodeType::Set},
|
||||||
|
{TT::Assign_Bind, NodeType::Bind},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<Literal> Node::getLiteral() const {
|
std::optional<Literal> Node::getLiteral() const {
|
||||||
@@ -52,6 +55,8 @@ namespace Solstice {
|
|||||||
return "Bind";
|
return "Bind";
|
||||||
case NodeType::Set:
|
case NodeType::Set:
|
||||||
return "Set";
|
return "Set";
|
||||||
|
case NodeType::SetType:
|
||||||
|
return "SetType";
|
||||||
case NodeType::Lambda:
|
case NodeType::Lambda:
|
||||||
return "Lambda";
|
return "Lambda";
|
||||||
case NodeType::FunctionCall:
|
case NodeType::FunctionCall:
|
||||||
@@ -383,6 +388,11 @@ namespace Solstice {
|
|||||||
case TT::Math_Multiply:
|
case TT::Math_Multiply:
|
||||||
case TT::Math_Divide:
|
case TT::Math_Divide:
|
||||||
return Precedence::Multiply;
|
return Precedence::Multiply;
|
||||||
|
case TT::Comparison_Equal:
|
||||||
|
case TT::Comparison_NotEqual:
|
||||||
|
case TT::Comparison_GreaterThan:
|
||||||
|
case TT::Comparison_LesserThan:
|
||||||
|
return Precedence::Compare;
|
||||||
case TT::Assign_Bind:
|
case TT::Assign_Bind:
|
||||||
case TT::Assign_Set:
|
case TT::Assign_Set:
|
||||||
case TT::Assign_Type:
|
case TT::Assign_Type:
|
||||||
@@ -417,6 +427,13 @@ namespace Solstice {
|
|||||||
case TT::Math_Subtract:
|
case TT::Math_Subtract:
|
||||||
case TT::Math_Multiply:
|
case TT::Math_Multiply:
|
||||||
case TT::Math_Divide:
|
case TT::Math_Divide:
|
||||||
|
case TT::Comparison_Equal:
|
||||||
|
case TT::Comparison_NotEqual:
|
||||||
|
case TT::Comparison_GreaterThan:
|
||||||
|
case TT::Comparison_LesserThan:
|
||||||
|
case TT::Assign_Set:
|
||||||
|
case TT::Assign_Bind:
|
||||||
|
case TT::Assign_Type:
|
||||||
return parseExpr(next->type);
|
return parseExpr(next->type);
|
||||||
case TT::OpenParen:
|
case TT::OpenParen:
|
||||||
return parseOpenParen();
|
return parseOpenParen();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Solstice {
|
|||||||
enum class NodeType {
|
enum class NodeType {
|
||||||
Root, Literal, Identifier, Expression, Tuple,
|
Root, Literal, Identifier, Expression, Tuple,
|
||||||
CodeBlock,
|
CodeBlock,
|
||||||
FunctionBind, Bind, Set,
|
FunctionBind, Bind, Set, SetType,
|
||||||
Lambda, FunctionCall,
|
Lambda, FunctionCall,
|
||||||
Add, Subtract, Multiply, Divide,
|
Add, Subtract, Multiply, Divide,
|
||||||
Equal, NotEqual, GreaterThan, LesserThan
|
Equal, NotEqual, GreaterThan, LesserThan
|
||||||
|
|||||||
@@ -56,4 +56,15 @@ namespace Solstice {
|
|||||||
return left.left == right.left && left.right == right.right;
|
return left.left == right.left && left.right == right.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<Type> PossibleType::getOnlyType() {
|
||||||
|
if (possiblities.size() != 1) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
for (const auto& type : possiblities) {
|
||||||
|
// just return one
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,13 @@ namespace Solstice {
|
|||||||
std::nullopt_t
|
std::nullopt_t
|
||||||
> fields = std::nullopt;
|
> fields = std::nullopt;
|
||||||
|
|
||||||
|
bool isConstant = false;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
Type() = delete;
|
Type() = default;
|
||||||
Type(BaseType type) : type(type) {}
|
Type(BaseType type) : type(type) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -106,6 +108,18 @@ namespace Solstice {
|
|||||||
|
|
||||||
PossibleType() = default;
|
PossibleType() = default;
|
||||||
PossibleType(const std::unordered_set<Type>& possiblities) : possiblities(possiblities) {}
|
PossibleType(const std::unordered_set<Type>& possiblities) : possiblities(possiblities) {}
|
||||||
|
|
||||||
|
std::optional<Type> getOnlyType();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Function {
|
||||||
|
PossibleType returnType = {{BaseType::None}};
|
||||||
|
std::vector<PossibleType> argumentTypes = {};
|
||||||
|
|
||||||
|
Function() = default;
|
||||||
|
Function(PossibleType returnType) : returnType(returnType) {}
|
||||||
|
Function(PossibleType returnType, std::vector<PossibleType> argumentTypes)
|
||||||
|
: returnType(returnType), argumentTypes(argumentTypes) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "typechecker.hpp"
|
#include "typechecker.hpp"
|
||||||
#include "type.hpp"
|
#include "type.hpp"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
|
|
||||||
@@ -107,21 +108,84 @@ namespace Solstice {
|
|||||||
throw std::runtime_error("unknown variable " + *identifier);
|
throw std::runtime_error("unknown variable " + *identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
node.ptype = variables[*identifier];
|
node.ptype = {{variables[*identifier]}};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeChecker::checkTupleNodeType(Node& node) {
|
void TypeChecker::checkTupleNodeType(Node& node) {
|
||||||
for (auto& child : node.children) {
|
for (auto& child : node.children) {
|
||||||
checkNodeType(child);
|
checkNodeType(child);
|
||||||
}
|
}
|
||||||
|
// TODO implemnt tuple type checking
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkBindNodeType(Node& node) {
|
||||||
|
auto id = node.children[0].getIdentifier();
|
||||||
|
if (!id.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME identifier node does not contain identifier");
|
||||||
|
}
|
||||||
|
if (variables.find(*id) != variables.end()) {
|
||||||
|
throw std::runtime_error("Cannot overwrite existing bind/variable/function with new bind");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNodeType(node.children[1]);
|
||||||
|
auto nodeType = node.children[1].ptype.getOnlyType();
|
||||||
|
if (!nodeType.has_value()) {
|
||||||
|
throw std::runtime_error("cannot assign ambiguous type to name");
|
||||||
|
}
|
||||||
|
variables[*id] = *nodeType;
|
||||||
|
variables[*id].isConstant = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkFunctionBindNodeType(Node& node) {
|
||||||
|
auto id = node.children[0].getIdentifier();
|
||||||
|
if (!id.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME identifier node does not contain identifier");
|
||||||
|
}
|
||||||
|
if (variables.find(*id) != variables.end()) {
|
||||||
|
throw std::runtime_error("Cannot overwrite existing bind/variable/function with new function");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNodeType(node.children[1]);
|
||||||
|
auto nodeType = node.children[1].ptype.getOnlyType();
|
||||||
|
if (!nodeType.has_value()) {
|
||||||
|
throw std::runtime_error("cannot assign ambiguous type to name");
|
||||||
|
}
|
||||||
|
variables[*id] = *nodeType;
|
||||||
|
variables[*id].isConstant = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkSetNodeType(Node& node) {
|
||||||
|
auto id = node.children[0].getIdentifier();
|
||||||
|
if (!id.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME identifier node does not contain identifier");
|
||||||
|
}
|
||||||
|
if (variables.find(*id) != variables.end()) {
|
||||||
|
if (variables[*id].isConstant) {
|
||||||
|
throw std::runtime_error("cannot reassign existing bind");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inFunction) {
|
||||||
|
throw std::runtime_error("mutable variables may only be used in functions");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNodeType(node.children[1]);
|
||||||
|
auto nodeType = node.children[1].ptype.getOnlyType();
|
||||||
|
if (!nodeType.has_value()) {
|
||||||
|
throw std::runtime_error("cannot assign ambiguous type to name");
|
||||||
|
}
|
||||||
|
variables[*id] = *nodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkCodeBlockType(Node& node) {}
|
||||||
|
|
||||||
|
|
||||||
void TypeChecker::checkNodeType(Node& node) {
|
void TypeChecker::checkNodeType(Node& node) {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
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) {
|
||||||
|
checkNodeType(child);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NodeType::Literal:
|
case NodeType::Literal:
|
||||||
checkLiteralNodeType(node);
|
checkLiteralNodeType(node);
|
||||||
@@ -135,6 +199,19 @@ namespace Solstice {
|
|||||||
case NodeType::Tuple:
|
case NodeType::Tuple:
|
||||||
checkTupleNodeType(node);
|
checkTupleNodeType(node);
|
||||||
break;
|
break;
|
||||||
|
case NodeType::Bind:
|
||||||
|
checkBindNodeType(node);
|
||||||
|
break;
|
||||||
|
case NodeType::FunctionBind:
|
||||||
|
checkFunctionBindNodeType(node);
|
||||||
|
break;
|
||||||
|
case NodeType::Set:
|
||||||
|
checkSetNodeType(node);
|
||||||
|
break;
|
||||||
|
case NodeType::CodeBlock:
|
||||||
|
checkCodeBlockType(node);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
|
|
||||||
class TypeChecker {
|
class TypeChecker {
|
||||||
std::unordered_map<std::string, PossibleType> variables;
|
std::unordered_map<std::string, Type> 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;
|
||||||
@@ -23,12 +23,20 @@ namespace Solstice {
|
|||||||
|
|
||||||
Node& input;
|
Node& input;
|
||||||
|
|
||||||
|
bool inFunction = false;
|
||||||
|
|
||||||
void initOverloads();
|
void initOverloads();
|
||||||
|
|
||||||
void checkLiteralNodeType(Node& node);
|
void checkLiteralNodeType(Node& node);
|
||||||
void checkIdentifierNodeType(Node& node);
|
void checkIdentifierNodeType(Node& node);
|
||||||
void checkTupleNodeType(Node& node);
|
void checkTupleNodeType(Node& node);
|
||||||
|
|
||||||
|
void checkBindNodeType(Node& node);
|
||||||
|
void checkFunctionBindNodeType(Node& node);
|
||||||
|
void checkSetNodeType(Node& node);
|
||||||
|
|
||||||
|
void checkCodeBlockType(Node& node);
|
||||||
|
|
||||||
void checkNodeType(Node& node);
|
void checkNodeType(Node& node);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user