Refactor type system, print all errors in file

This commit is contained in:
2025-12-26 13:28:47 +11:00
parent 24ea348858
commit d8812fa14e
6 changed files with 189 additions and 50 deletions

View File

@@ -1,7 +1,6 @@
#include "parser.h"
#include "error.h"
#include <groundvm.h>
#include <iostream>
#include <cstring>
#define parseOneToken(token) Parser({token}).parse().children[0]
@@ -13,9 +12,9 @@ namespace Solstice {
return id.rfind("tmp_", 0) == 0;
}
std::map<std::string, SolDataType> variables;
std::map<std::string, std::string> variables;
SolDataType checkNodeReturnType(SolNode i) {
std::string checkNodeReturnType(SolNode i) {
switch (i.nodeType) {
case SolNodeType::Identifier: {
if (variables.find(i.outputId) != variables.end()) {
@@ -26,7 +25,7 @@ namespace Solstice {
break;
}
case SolNodeType::Value: {
return i.data.type;
return i.data.getTypeString();
}
case SolNodeType::Equal:
case SolNodeType::Inequal:
@@ -34,25 +33,25 @@ namespace Solstice {
case SolNodeType::Lesser:
case SolNodeType::EqGreater:
case SolNodeType::EqLesser:
return SolDataType::Bool;
return "bool";
break;
case SolNodeType::Add:
{
if (checkNodeReturnType(i.children[0]) == SolDataType::String && checkNodeReturnType(i.children[1]) == SolDataType::String) {
return SolDataType::String;
if (checkNodeReturnType(i.children[0]) == "string" && checkNodeReturnType(i.children[1]) == "string") {
return "string";
}
}
case SolNodeType::Subtract:
case SolNodeType::Multiply:
case SolNodeType::Divide:
{
if (checkNodeReturnType(i.children[0]) == SolDataType::Double) {
return SolDataType::Double;
if (checkNodeReturnType(i.children[0]) == "double") {
return "double";
}
if (checkNodeReturnType(i.children[1]) == SolDataType::Double) {
return SolDataType::Double;
if (checkNodeReturnType(i.children[1]) == "double") {
return "double";
}
return SolDataType::Int;
return "int";
break;
}
case SolNodeType::Puts:
@@ -62,10 +61,11 @@ namespace Solstice {
case SolNodeType::Set:
case SolNodeType::Root:
case SolNodeType::None:
return SolDataType::None;
case SolNodeType::FunctionDef:
return "none";
break;
}
return SolDataType::None;
return "none";
}
// SolData Implementation
@@ -74,6 +74,7 @@ namespace Solstice {
SolData::SolData(std::string in) : data(in), type(SolDataType::String) {}
SolData::SolData(char in) : data(in), type(SolDataType::Char) {}
SolData::SolData(bool in) : data(in), type(SolDataType::Bool) {}
SolData::SolData(SolFunction in) : data(in), type(SolDataType::Function) {}
std::optional<int64_t> SolData::getInt() {
if (type == SolDataType::Int) {
@@ -110,6 +111,26 @@ namespace Solstice {
return {};
}
}
std::optional<SolFunction> SolData::getFunction() {
if (type == SolDataType::Function) {
return std::get<SolFunction>(data);
} else {
return {};
}
}
std::string SolData::getTypeString() {
switch (type) {
case SolDataType::Int: return "int";
case SolDataType::Double: return "double";
case SolDataType::String: return "string";
case SolDataType::Char: return "char";
case SolDataType::Bool: return "bool";
case SolDataType::Function: return "function";
case SolDataType::None: return "none";
}
return "none";
}
// SolNode Implementation
SolNode::SolNode(SolNodeType nodeType) : nodeType(nodeType) {}
@@ -178,8 +199,8 @@ namespace Solstice {
break;
}
case SolNodeType::Add: {
ensure3(children[0], SolDataType::Int, SolDataType::Double, SolDataType::String, "operator '+'");
ensure3(children[1], SolDataType::Int, SolDataType::Double, SolDataType::String, "operator '+'");
ensure3(children[0], "int", "double", "string", "operator '+'");
ensure3(children[1], "int", "double", "string", "operator '+'");
ensuresame(children[0], children[1], "operator '+'");
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
@@ -197,8 +218,8 @@ namespace Solstice {
break;
}
case SolNodeType::Subtract: {
ensure2(children[0], SolDataType::Int, SolDataType::Double, "operator '-'");
ensure2(children[1], SolDataType::Int, SolDataType::Double, "operator '-'");
ensure2(children[0], "int", "double", "operator '-'");
ensure2(children[1], "int", "double", "operator '-'");
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(SUBTRACT);
@@ -215,8 +236,8 @@ namespace Solstice {
break;
}
case SolNodeType::Multiply: {
ensure2(children[0], SolDataType::Int, SolDataType::Double, "operator '*'");
ensure2(children[1], SolDataType::Int, SolDataType::Double, "operator '*'");
ensure2(children[0], "int", "double", "operator '*'");
ensure2(children[1], "int", "double", "operator '*'");
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(MULTIPLY);
@@ -233,8 +254,8 @@ namespace Solstice {
break;
}
case SolNodeType::Divide: {
ensure2(children[0], SolDataType::Int, SolDataType::Double, "operator '/'");
ensure2(children[1], SolDataType::Int, SolDataType::Double, "operator '/'");
ensure2(children[0], "int", "double", "operator '/'");
ensure2(children[1], "int", "double", "operator '/'");
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(DIVIDE);
@@ -478,7 +499,7 @@ namespace Solstice {
break;
}
case SolNodeType::If: {
ensure(children[0], SolDataType::Bool, "if condition");
ensure(children[0], "bool", "if condition");
auto conditionCode = children[0].generateCode();
code.insert(code.end(), conditionCode.begin(), conditionCode.end());
outputId = "tmp_" + std::to_string(tmpIdIterator++);
@@ -510,7 +531,7 @@ namespace Solstice {
break;
}
case SolNodeType::While: {
ensure(children[0], SolDataType::Bool, "while condition");
ensure(children[0], "bool", "while condition");
SolGroundCodeBlock startLabelBlock;
std::string startLabelIdString = "whilestart_" + std::to_string(labelIterator++);
std::string endLabelIdString = "whileend_" + std::to_string(labelIterator);
@@ -574,13 +595,14 @@ namespace Solstice {
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
code.push_back(codeBlock);
// Make sure we know what the variable type is
variables[children[0].outputId] = children[1].data.type;
variables[children[0].outputId] = children[1].data.getTypeString();
break;
}
case SolNodeType::FunctionCall: {
// Take care of in built functions
// This will be removed when inline ground is added
if (children[0].outputId == "input") {
ensure(children[1], SolDataType::String, "input function argument");
ensure(children[1], "string", "input function argument");
SolGroundCodeBlock inputCodeBlock;
if (children.size() > 1) {
GroundInstruction printInstruction = groundCreateInstruction(PRINT);
@@ -595,6 +617,7 @@ namespace Solstice {
code.push_back(inputCodeBlock);
break;
}
std::string fnToCall = children[0].outputId;
break;
}
@@ -728,6 +751,9 @@ namespace Solstice {
if (in == "while") {
return SolNodeType::While;
}
if (in == "def") {
return SolNodeType::FunctionDef;
}
if (in == "{") {
return SolNodeType::CodeBlockStart;
}
@@ -1154,6 +1180,93 @@ namespace Solstice {
rootNode.addNode(node);
}
}
case SolNodeType::FunctionDef: {
SolFunction fn;
auto nameTokenOpt = consume();
if (!nameTokenOpt || getNodeType(nameTokenOpt.value().value) != SolNodeType::Identifier) {
Error::syntaxError("Expected function name", tokenObj.line, tokenObj.lineContent);
}
std::string fnName = nameTokenOpt.value().value;
auto openParen = consume();
if (!openParen || openParen.value().value != "(") {
Error::syntaxError("Expected '(' after function name", tokenObj.line, tokenObj.lineContent);
}
std::string signature = "fun(";
bool first = true;
while (auto next = peek()) {
if (next.value().value == ")") {
consume();
break;
}
if (!first) {
auto comma = consume();
if (comma.value().value != ",") {
Error::syntaxError("Expected ',' between arguments", tokenObj.line, tokenObj.lineContent);
}
}
auto typeToken = consume();
if (!typeToken) Error::syntaxError("Expected type", tokenObj.line, tokenObj.lineContent);
std::string argType = typeToken.value().value;
auto argNameToken = consume();
if (!argNameToken) Error::syntaxError("Expected argument name", tokenObj.line, tokenObj.lineContent);
std::string argName = argNameToken.value().value;
fn.parameters.push_back({argName, argType});
if (!first) signature += ", ";
signature += argType;
first = false;
}
signature += ") ";
while (peek() && peek().value().value == "\n") consume();
auto next = peek();
if (next && next.value().value != "{") {
auto retTypeToken = consume();
fn.returnType = retTypeToken.value().value;
} else {
fn.returnType = "void";
}
signature += fn.returnType;
fn.signature = signature;
while (peek() && peek().value().value == "\n") consume();
auto brace = peek();
if (!brace || brace.value().value != "{") {
Error::syntaxError("Expected '{' starting function body", tokenObj.line, tokenObj.lineContent);
}
consume();
std::vector<Token> bodyTokens;
size_t brackets = 1;
while(auto t = consume()) {
if (t.value().value == "{") brackets++;
if (t.value().value == "}") brackets--;
if (brackets == 0) break;
bodyTokens.push_back(t.value());
}
if (brackets != 0) Error::syntaxError("Unclosed function body", tokenObj.line, tokenObj.lineContent);
auto parsedBody = Parser(bodyTokens).parse();
auto bodyNode = std::make_shared<SolNode>(SolNodeType::CodeBlock);
bodyNode->children = parsedBody.children;
fn.content = bodyNode;
SolNode fnNode(SolNodeType::FunctionDef);
fnNode.data = SolData(fn);
variables[fnName] = signature;
rootNode.addNode(fnNode);
break;
}
}
}
return rootNode;
@@ -1179,4 +1292,4 @@ namespace Solstice {
} // namespace Parser
}
}