continue working on ir

This commit is contained in:
2026-08-07 17:35:48 +10:00
parent 376d6ec73b
commit c8b0cfd928
8 changed files with 243 additions and 56 deletions

View File

@@ -7,6 +7,7 @@ sources = files(
'src/typechecker/typechecker.cpp', 'src/typechecker/typechecker.cpp',
'src/typechecker/type.cpp', 'src/typechecker/type.cpp',
'src/ir/ir.cpp', 'src/ir/ir.cpp',
'src/ir/irbuilder.cpp',
'src/compiler/compiler.cpp' 'src/compiler/compiler.cpp'
) )

View File

@@ -0,0 +1,59 @@
#pragma once
#include <cstdint>
#include <optional>
#include <variant>
#include <vector>
#include "../lexer/lexer.hpp"
namespace Solstice {
enum class InstructionType {
Jump, JumpIfTrue, JumpIfFalse, Return,
Call,
};
enum class ArgumentType {
None, Register, Function, Literal
};
class Argument {
std::variant<int64_t, std::string, Literal> value;
public:
ArgumentType type = ArgumentType::None;
std::optional<int64_t> getRegister();
std::optional<std::string> getString();
std::optional<Literal> getLiteral();
Argument() : type(ArgumentType::None) {}
Argument(ArgumentType type) : type(type) {}
Argument(int64_t value) : type(ArgumentType::Register), value(value) {}
Argument(std::string value) : type(ArgumentType::Function), value(value) {}
Argument(Literal value) : type(ArgumentType::Literal), value(value) {}
};
struct Instruction {
uint64_t tmpId;
std::vector<Argument> args;
InstructionType type;
};
struct BasicBlock {
std::vector<Instruction> instructions;
};
struct IRFunction {
std::vector<BasicBlock> blocks;
};
struct Program {
std::vector<IRFunction> functions;
};
}

65
src/ir/irbuilder.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "irbuilder.hpp"
#include "ir.hpp"
#include <stdexcept>
namespace Solstice {
void IRBuilder::buildNode(Node& node) {
switch (node.type) {
case NodeType::Root:
buildRootNode(node);
break;
case NodeType::Literal:
buildLiteralNode(node);
break;
case NodeType::Identifier:
buildIdentifierNode(node);
break;
case NodeType::FunctionBind:
buildFunctionBindNode(node);
break;
}
}
void IRBuilder::buildLiteralNode(Node& node) {
node.arg = *node.getLiteral();
}
void IRBuilder::buildIdentifierNode(Node& node) {
if (currentContext == nullptr) {
throw std::runtime_error("current context does not exist");
}
if (currentContext->variables.find(*node.getIdentifier()) == currentContext->variables.end()) {
throw std::runtime_error("identifier has not been assigned a virtual register");
}
node.arg = currentContext->variables[*node.getIdentifier()];
}
void IRBuilder::buildRootNode(Node& node) {
for (auto& child : node.children) {
buildNode(child);
}
}
void IRBuilder::buildFunctionBindNode(Node& node) {
IRContext context;
currentContext = &context;
IRFunction function;
currentFunction = &function;
// allocate one block, which is our start block
currentFunction->blocks.emplace_back();
currentBlock = &currentFunction->blocks[0];
}
void IRBuilder::build() {
buildNode(in);
}
void IRBuilder::optimise() {}
Program& IRBuilder::getProgram() {
return out;
}
}

43
src/ir/irbuilder.hpp Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
#include "ir.hpp"
#include "../parser/parser.hpp"
#include "../typechecker/typechecker.hpp"
#include <cstdint>
#include <unordered_map>
namespace Solstice {
struct IRContext {
std::unordered_map<std::string, int64_t> variables;
};
class IRBuilder {
Node in;
Program out;
Context tcContext;
IRContext* currentContext = nullptr;
BasicBlock* currentBlock = nullptr;
IRFunction* currentFunction = nullptr;
void buildNode(Node& node);
void buildRootNode(Node& node);
void buildLiteralNode(Node& node);
void buildIdentifierNode(Node& node);
void buildFunctionBindNode(Node& node);
public:
IRBuilder() = delete;
IRBuilder(const Node& node, const Context& context) : in(node), tcContext(context) {}
void build();
void optimise();
Program& getProgram();
};
}

View File

@@ -1,3 +1,4 @@
#include "ir/irbuilder.hpp"
#include "lexer/lexer.hpp" #include "lexer/lexer.hpp"
#include "parser/parser.hpp" #include "parser/parser.hpp"
#include "typechecker/typechecker.hpp" #include "typechecker/typechecker.hpp"
@@ -27,5 +28,13 @@ int main(int argc, char** argv) {
Solstice::TypeChecker typeChecker(parsed); Solstice::TypeChecker typeChecker(parsed);
typeChecker.checkTypes(); typeChecker.checkTypes();
Solstice::Context& context = typeChecker.getContext();
Solstice::IRBuilder irBuilder(parsed, context);
irBuilder.build();
irBuilder.optimise();
Solstice::Program& program = irBuilder.getProgram();
return 0; return 0;
} }

View File

@@ -6,6 +6,7 @@
#include "../lexer/lexer.hpp" #include "../lexer/lexer.hpp"
#include "../typechecker/type.hpp" #include "../typechecker/type.hpp"
#include "../ir/ir.hpp"
namespace Solstice { namespace Solstice {
@@ -43,6 +44,7 @@ namespace Solstice {
std::variant<Literal, std::string> data; std::variant<Literal, std::string> data;
PossibleType ptype; PossibleType ptype;
Argument arg;
Node() = delete; Node() = delete;
Node(NodeType type) : type(type) {} Node(NodeType type) : type(type) {}

View File

@@ -6,7 +6,7 @@ namespace Solstice {
void TypeChecker::initOverloads() { void TypeChecker::initOverloads() {
types = { context.types = {
{"Int", {BaseType::Int}}, {"Int", {BaseType::Int}},
{"String", {BaseType::String}}, {"String", {BaseType::String}},
{"Double", {BaseType::Double}}, {"Double", {BaseType::Double}},
@@ -19,7 +19,7 @@ namespace Solstice {
{"Object", {BaseType::Tuple}}, {"Object", {BaseType::Tuple}},
}; };
addOverloads = { context.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},
{{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double},
@@ -29,28 +29,28 @@ namespace Solstice {
{{BaseType::Char, BaseType::String}, BaseType::String}, {{BaseType::Char, BaseType::String}, BaseType::String},
{{BaseType::Char, BaseType::Char}, BaseType::Char} {{BaseType::Char, BaseType::Char}, BaseType::Char}
}; };
subtractOverloads = { context.subtractOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Int}, {{BaseType::Int, BaseType::Int}, BaseType::Int},
{{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Double}, BaseType::Double},
{{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double},
{{BaseType::Double, BaseType::Int}, BaseType::Double}, {{BaseType::Double, BaseType::Int}, BaseType::Double},
{{BaseType::Char, BaseType::Char}, BaseType::Char} {{BaseType::Char, BaseType::Char}, BaseType::Char}
}; };
multiplyOverloads = { context.multiplyOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Int}, {{BaseType::Int, BaseType::Int}, BaseType::Int},
{{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Double}, BaseType::Double},
{{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double},
{{BaseType::Double, BaseType::Int}, BaseType::Double}, {{BaseType::Double, BaseType::Int}, BaseType::Double},
{{BaseType::Char, BaseType::Char}, BaseType::Char} {{BaseType::Char, BaseType::Char}, BaseType::Char}
}; };
divideOverloads = { context.divideOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Double}, {{BaseType::Int, BaseType::Int}, BaseType::Double},
{{BaseType::Double, BaseType::Double}, BaseType::Double}, {{BaseType::Double, BaseType::Double}, BaseType::Double},
{{BaseType::Int, BaseType::Double}, BaseType::Double}, {{BaseType::Int, BaseType::Double}, BaseType::Double},
{{BaseType::Double, BaseType::Int}, BaseType::Double}, {{BaseType::Double, BaseType::Int}, BaseType::Double},
{{BaseType::Char, BaseType::Char}, BaseType::Char} {{BaseType::Char, BaseType::Char}, BaseType::Char}
}; };
equalOverloads = { context.equalOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Int, BaseType::Int}, BaseType::Bool},
{{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool},
{{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool},
@@ -59,7 +59,7 @@ namespace Solstice {
{{BaseType::Char, BaseType::Char}, BaseType::Bool}, {{BaseType::Char, BaseType::Char}, BaseType::Bool},
{{BaseType::Bool, BaseType::Bool}, BaseType::Bool}, {{BaseType::Bool, BaseType::Bool}, BaseType::Bool},
}; };
notEqualOverloads = { context.notEqualOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Int, BaseType::Int}, BaseType::Bool},
{{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool},
{{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool},
@@ -68,14 +68,14 @@ namespace Solstice {
{{BaseType::Char, BaseType::Char}, BaseType::Bool}, {{BaseType::Char, BaseType::Char}, BaseType::Bool},
{{BaseType::Bool, BaseType::Bool}, BaseType::Bool}, {{BaseType::Bool, BaseType::Bool}, BaseType::Bool},
}; };
greaterThanOverloads = { context.greaterThanOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Int, BaseType::Int}, BaseType::Bool},
{{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool},
{{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool},
{{BaseType::Double, BaseType::Int}, BaseType::Bool}, {{BaseType::Double, BaseType::Int}, BaseType::Bool},
{{BaseType::Char, BaseType::Char}, BaseType::Bool}, {{BaseType::Char, BaseType::Char}, BaseType::Bool},
}; };
lesserThanOverloads = { context.lesserThanOverloads = {
{{BaseType::Int, BaseType::Int}, BaseType::Bool}, {{BaseType::Int, BaseType::Int}, BaseType::Bool},
{{BaseType::Double, BaseType::Double}, BaseType::Bool}, {{BaseType::Double, BaseType::Double}, BaseType::Bool},
{{BaseType::Int, BaseType::Double}, BaseType::Bool}, {{BaseType::Int, BaseType::Double}, BaseType::Bool},
@@ -117,11 +117,11 @@ namespace Solstice {
throw std::runtime_error("FIXME identifier node does not contain identifier"); throw std::runtime_error("FIXME identifier node does not contain identifier");
} }
if (variables.find(*identifier) == variables.end()) { if (context.variables.find(*identifier) == context.variables.end()) {
throw std::runtime_error("unknown variable " + *identifier); throw std::runtime_error("unknown variable " + *identifier);
} }
node.ptype = variables[*identifier]; node.ptype = context.variables[*identifier];
} }
void TypeChecker::checkTupleNodeType(Node& node) { void TypeChecker::checkTupleNodeType(Node& node) {
@@ -136,7 +136,7 @@ namespace Solstice {
if (!id.has_value()) { if (!id.has_value()) {
throw std::runtime_error("FIXME identifier node does not contain identifier"); throw std::runtime_error("FIXME identifier node does not contain identifier");
} }
if (variables.find(*id) != variables.end()) { if (context.variables.find(*id) != context.variables.end()) {
throw std::runtime_error("Cannot overwrite existing bind/variable/function with new bind"); throw std::runtime_error("Cannot overwrite existing bind/variable/function with new bind");
} }
@@ -144,12 +144,12 @@ namespace Solstice {
if (node.children[1].ptype.possiblities.empty() && !node.children[1].ptype.unknownType) { if (node.children[1].ptype.possiblities.empty() && !node.children[1].ptype.unknownType) {
throw std::runtime_error("cannot assign name with no possible types"); throw std::runtime_error("cannot assign name with no possible types");
} }
variables[*id] = node.children[1].ptype; context.variables[*id] = node.children[1].ptype;
variables[*id].isConstant = true; context.variables[*id].isConstant = true;
// if not narrowed down to a single type yet, keep it open so later // if not narrowed down to a single type yet, keep it open so later
// usages of this name can continue narrowing it // usages of this name can continue narrowing it
if (!variables[*id].getOnlyType().has_value()) { if (!context.variables[*id].getOnlyType().has_value()) {
variables[*id].unknownType = true; context.variables[*id].unknownType = true;
} }
} }
static inline std::vector<std::vector<Type>> doCartesianProductOnTypeSets(const std::vector<PossibleType>& typeSets) { static inline std::vector<std::vector<Type>> doCartesianProductOnTypeSets(const std::vector<PossibleType>& typeSets) {
@@ -197,7 +197,7 @@ namespace Solstice {
if (!id.has_value()) { if (!id.has_value()) {
throw std::runtime_error("FIXME identifier node does not contain identifier"); throw std::runtime_error("FIXME identifier node does not contain identifier");
} }
if (variables.find(*id) != variables.end()) { if (context.variables.find(*id) != context.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");
} }
@@ -227,11 +227,11 @@ namespace Solstice {
if (!typeId.has_value()) { if (!typeId.has_value()) {
throw std::runtime_error("FIXME identifier node does not contain identifier"); throw std::runtime_error("FIXME identifier node does not contain identifier");
} }
if (types.find(*typeId) == types.end()) { if (context.types.find(*typeId) == context.types.end()) {
throw std::runtime_error("unknown type " + *typeId); throw std::runtime_error("unknown type " + *typeId);
} }
auto name = *arg.children[0].getIdentifier(); auto name = *arg.children[0].getIdentifier();
typeChecker.setVariable(name, types[*typeId]); typeChecker.setVariable(name, context.types[*typeId]);
paramNames.push_back(name); paramNames.push_back(name);
break; break;
} }
@@ -246,7 +246,7 @@ namespace Solstice {
// collect the (possibly still-polymorphic) narrowed argument types // collect the (possibly still-polymorphic) narrowed argument types
Function fn; Function fn;
for (const auto& name : paramNames) { for (const auto& name : paramNames) {
fn.argumentTypes.push_back(typeChecker.variables[name]); fn.argumentTypes.push_back(typeChecker.context.variables[name]);
} }
std::vector<std::vector<Type>> candidates = doCartesianProductOnTypeSets(fn.argumentTypes); std::vector<std::vector<Type>> candidates = doCartesianProductOnTypeSets(fn.argumentTypes);
@@ -276,23 +276,23 @@ namespace Solstice {
} }
} }
functions[*id] = fn; context.functions[*id] = fn;
} }
Narrowing TypeChecker::doesNodeChildrenNeedNarrowing(Node& node) { Narrowing TypeChecker::doesNodeChildrenNeedNarrowing(Node& node) {
Narrowing ret = Narrowing::None; Narrowing ret = Narrowing::None;
if ( if (
node.children[0].type == NodeType::Identifier && node.children[0].type == NodeType::Identifier &&
variables.find(*node.children[0].getIdentifier()) != variables.end() && context.variables.find(*node.children[0].getIdentifier()) != context.variables.end() &&
variables[*node.children[0].getIdentifier()].unknownType context.variables[*node.children[0].getIdentifier()].unknownType
) { ) {
ret = Narrowing::Left; ret = Narrowing::Left;
} }
if ( if (
node.children[1].type == NodeType::Identifier && node.children[1].type == NodeType::Identifier &&
variables.find(*node.children[1].getIdentifier()) != variables.end() && context.variables.find(*node.children[1].getIdentifier()) != context.variables.end() &&
variables[*node.children[1].getIdentifier()].unknownType context.variables[*node.children[1].getIdentifier()].unknownType
) { ) {
if (ret == Narrowing::Left) { if (ret == Narrowing::Left) {
ret = Narrowing::Both; ret = Narrowing::Both;
@@ -318,8 +318,8 @@ namespace Solstice {
// narrow types if we need to // narrow types if we need to
switch (doesNodeChildrenNeedNarrowing(node)) { switch (doesNodeChildrenNeedNarrowing(node)) {
case Narrowing::Both: { case Narrowing::Both: {
auto& leftVar = variables[*left.getIdentifier()]; auto& leftVar = context.variables[*left.getIdentifier()];
auto& rightVar = variables[*right.getIdentifier()]; auto& rightVar = context.variables[*right.getIdentifier()];
// an empty possibility set means "still fully open" (no prior // an empty possibility set means "still fully open" (no prior
// narrowing yet), so treat it as no constraint; otherwise only // narrowing yet), so treat it as no constraint; otherwise only
@@ -344,7 +344,7 @@ namespace Solstice {
break; break;
} }
case Narrowing::Left: { case Narrowing::Left: {
auto& leftVar = variables[*left.getIdentifier()]; auto& leftVar = context.variables[*left.getIdentifier()];
std::unordered_set<Type> newLeft; std::unordered_set<Type> newLeft;
for (const auto& [key, value] : overloads) { for (const auto& [key, value] : overloads) {
bool leftOk = leftVar.possiblities.empty() || leftVar.possiblities.find(key.left) != leftVar.possiblities.end(); bool leftOk = leftVar.possiblities.empty() || leftVar.possiblities.find(key.left) != leftVar.possiblities.end();
@@ -361,7 +361,7 @@ namespace Solstice {
break; break;
} }
case Narrowing::Right: { case Narrowing::Right: {
auto& rightVar = variables[*right.getIdentifier()]; auto& rightVar = context.variables[*right.getIdentifier()];
std::unordered_set<Type> newRight; std::unordered_set<Type> newRight;
for (const auto& [key, value] : overloads) { for (const auto& [key, value] : overloads) {
bool leftOk = left.ptype.possiblities.find(key.left) != left.ptype.possiblities.end(); bool leftOk = left.ptype.possiblities.find(key.left) != left.ptype.possiblities.end();
@@ -400,11 +400,11 @@ namespace Solstice {
throw std::runtime_error("identifier node does not contain identifier"); throw std::runtime_error("identifier node does not contain identifier");
} }
if (functions.find(*name) == functions.end()) { if (context.functions.find(*name) == context.functions.end()) {
throw std::runtime_error("unknown function " + *name); throw std::runtime_error("unknown function " + *name);
} }
auto& function = functions[*name]; auto& function = context.functions[*name];
node.ptype.possiblities.clear(); node.ptype.possiblities.clear();
node.ptype.unknownType = false; node.ptype.unknownType = false;
@@ -435,7 +435,7 @@ namespace Solstice {
} }
child.ptype.possiblities = newTypes; child.ptype.possiblities = newTypes;
} }
variables[*id].possiblities = child.ptype.possiblities; context.variables[*id].possiblities = child.ptype.possiblities;
} }
args.push_back(child.ptype); args.push_back(child.ptype);
} }
@@ -466,8 +466,8 @@ namespace Solstice {
if (!id.has_value()) { if (!id.has_value()) {
throw std::runtime_error("FIXME identifier node does not contain identifier"); throw std::runtime_error("FIXME identifier node does not contain identifier");
} }
if (variables.find(*id) != variables.end()) { if (context.variables.find(*id) != context.variables.end()) {
if (variables[*id].isConstant) { if (context.variables[*id].isConstant) {
throw std::runtime_error("cannot reassign existing bind"); throw std::runtime_error("cannot reassign existing bind");
} }
} }
@@ -479,11 +479,11 @@ namespace Solstice {
if (node.children[1].ptype.possiblities.empty() && !node.children[1].ptype.unknownType) { if (node.children[1].ptype.possiblities.empty() && !node.children[1].ptype.unknownType) {
throw std::runtime_error("cannot assign name with no possible types"); throw std::runtime_error("cannot assign name with no possible types");
} }
variables[*id] = node.children[1].ptype; context.variables[*id] = node.children[1].ptype;
// if not narrowed down to a single type yet, keep it open so later // if not narrowed down to a single type yet, keep it open so later
// usages of this name can continue narrowing it // usages of this name can continue narrowing it
if (!variables[*id].getOnlyType().has_value()) { if (!context.variables[*id].getOnlyType().has_value()) {
variables[*id].unknownType = true; context.variables[*id].unknownType = true;
} }
} }
@@ -505,7 +505,7 @@ namespace Solstice {
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
// narrow if required // narrow if required
narrowBinaryNode(node, addOverloads); narrowBinaryNode(node, context.addOverloads);
} }
@@ -513,49 +513,49 @@ namespace Solstice {
checkNodeType(node.children[0]); checkNodeType(node.children[0]);
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
narrowBinaryNode(node, subtractOverloads); narrowBinaryNode(node, context.subtractOverloads);
} }
void TypeChecker::checkMultiplyType(Node& node) { void TypeChecker::checkMultiplyType(Node& node) {
checkNodeType(node.children[0]); checkNodeType(node.children[0]);
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
narrowBinaryNode(node, multiplyOverloads); narrowBinaryNode(node, context.multiplyOverloads);
} }
void TypeChecker::checkDivideType(Node& node) { void TypeChecker::checkDivideType(Node& node) {
checkNodeType(node.children[0]); checkNodeType(node.children[0]);
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
narrowBinaryNode(node, divideOverloads); narrowBinaryNode(node, context.divideOverloads);
} }
void TypeChecker::checkEqualType(Node& node) { void TypeChecker::checkEqualType(Node& node) {
checkNodeType(node.children[0]); checkNodeType(node.children[0]);
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
narrowBinaryNode(node, equalOverloads); narrowBinaryNode(node, context.equalOverloads);
} }
void TypeChecker::checkNotEqualType(Node& node) { void TypeChecker::checkNotEqualType(Node& node) {
checkNodeType(node.children[0]); checkNodeType(node.children[0]);
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
narrowBinaryNode(node, notEqualOverloads); narrowBinaryNode(node, context.notEqualOverloads);
} }
void TypeChecker::checkGreaterThanType(Node& node) { void TypeChecker::checkGreaterThanType(Node& node) {
checkNodeType(node.children[0]); checkNodeType(node.children[0]);
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
narrowBinaryNode(node, greaterThanOverloads); narrowBinaryNode(node, context.greaterThanOverloads);
} }
void TypeChecker::checkLesserThanType(Node& node) { void TypeChecker::checkLesserThanType(Node& node) {
checkNodeType(node.children[0]); checkNodeType(node.children[0]);
checkNodeType(node.children[1]); checkNodeType(node.children[1]);
narrowBinaryNode(node, lesserThanOverloads); narrowBinaryNode(node, context.lesserThanOverloads);
} }
void TypeChecker::checkCImportType(Node& node) { void TypeChecker::checkCImportType(Node& node) {
@@ -564,25 +564,25 @@ namespace Solstice {
// Get function's type // Get function's type
Function function; Function function;
auto returnTypeId = *node.children[1].getIdentifier(); auto returnTypeId = *node.children[1].getIdentifier();
if (types.find(returnTypeId) == types.end()) { if (context.types.find(returnTypeId) == context.types.end()) {
throw std::runtime_error("Unknown type " + returnTypeId); throw std::runtime_error("Unknown type " + returnTypeId);
} }
auto returnType = types[returnTypeId]; auto returnType = context.types[returnTypeId];
std::vector<Type> functionTypes; std::vector<Type> functionTypes;
for (const auto& arg : node.children[2].children) { for (const auto& arg : node.children[2].children) {
auto argTypeId = *arg.getIdentifier(); auto argTypeId = *arg.getIdentifier();
if (types.find(argTypeId) == types.end()) { if (context.types.find(argTypeId) == context.types.end()) {
throw std::runtime_error("Unknown type " + argTypeId); throw std::runtime_error("Unknown type " + argTypeId);
} }
functionTypes.push_back(types[argTypeId]); functionTypes.push_back(context.types[argTypeId]);
} }
function.returnTypes[functionTypes] = returnType; function.returnTypes[functionTypes] = returnType;
if (functions.find(name) != functions.end()) { if (context.functions.find(name) != context.functions.end()) {
throw std::runtime_error("cannot override function with name " + name); throw std::runtime_error("cannot override function with name " + name);
} }
functions[name] = function; context.functions[name] = function;
} }
void TypeChecker::checkNodeType(Node& node) { void TypeChecker::checkNodeType(Node& node) {

View File

@@ -15,7 +15,7 @@ namespace Solstice {
Both Both
}; };
class TypeChecker { struct Context {
std::unordered_map<std::string, PossibleType> 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<std::string, Function> functions; std::unordered_map<std::string, Function> functions;
@@ -28,6 +28,10 @@ namespace Solstice {
std::unordered_map<TypePair, Type> notEqualOverloads; std::unordered_map<TypePair, Type> notEqualOverloads;
std::unordered_map<TypePair, Type> greaterThanOverloads; std::unordered_map<TypePair, Type> greaterThanOverloads;
std::unordered_map<TypePair, Type> lesserThanOverloads; std::unordered_map<TypePair, Type> lesserThanOverloads;
};
class TypeChecker {
Context context;
Node* input; Node* input;
@@ -78,21 +82,25 @@ namespace Solstice {
// Only for use as a public function. // Only for use as a public function.
void setVariable(const std::string& name, const Type& type) { void setVariable(const std::string& name, const Type& type) {
variables[name] = {{type}}; context.variables[name] = {{type}};
} }
void setVariableUnknown(const std::string& name) { void setVariableUnknown(const std::string& name) {
variables[name].unknownType = true; context.variables[name].unknownType = true;
} }
void checkTypes(); void checkTypes();
const Function* getFunction(const std::string& name) const { const Function* getFunction(const std::string& name) const {
auto it = functions.find(name); auto it = context.functions.find(name);
if (it == functions.end()) { if (it == context.functions.end()) {
return nullptr; return nullptr;
} }
return &it->second; return &it->second;
} }
Context& getContext() {
return context;
}
}; };
} }