continue working on ir
This commit is contained in:
@@ -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'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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
65
src/ir/irbuilder.cpp
Normal 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 = ¤tFunction->blocks[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRBuilder::build() {
|
||||||
|
buildNode(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRBuilder::optimise() {}
|
||||||
|
|
||||||
|
Program& IRBuilder::getProgram() {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/ir/irbuilder.hpp
Normal file
43
src/ir/irbuilder.hpp
Normal 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();
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user