Files
highground-fork/src/parser.cpp

1456 lines
77 KiB
C++
Raw Normal View History

2025-12-21 12:06:55 +11:00
#include "parser.h"
2025-12-24 13:15:48 +11:00
#include "error.h"
2025-12-22 13:49:44 +11:00
#include <groundvm.h>
2025-12-21 12:06:55 +11:00
#include <cstring>
2025-12-28 13:41:05 +11:00
#include <string>
2025-12-21 12:06:55 +11:00
2025-12-25 22:37:40 +11:00
#define parseOneToken(token) Parser({token}).parse().children[0]
2025-12-21 12:06:55 +11:00
namespace Solstice {
namespace Parser {
2025-12-22 19:38:06 +11:00
bool isTemp(std::string id) {
return id.rfind("tmp_", 0) == 0;
}
std::map<std::string, std::string> variables;
2025-12-24 13:15:48 +11:00
std::string checkNodeReturnType(SolNode i) {
2025-12-24 13:15:48 +11:00
switch (i.nodeType) {
case SolNodeType::Identifier: {
if (variables.find(i.outputId) != variables.end()) {
return variables[i.outputId];
} else {
2025-12-29 10:30:07 +11:00
Error::syntaxError("Unknown variable " + i.outputId, i.line, i.lineContent);
2025-12-24 13:15:48 +11:00
}
break;
}
2025-12-24 14:31:43 +11:00
case SolNodeType::Value: {
return i.data.getTypeString();
2025-12-24 14:31:43 +11:00
}
2025-12-24 13:15:48 +11:00
case SolNodeType::Equal:
case SolNodeType::Inequal:
case SolNodeType::Greater:
case SolNodeType::Lesser:
case SolNodeType::EqGreater:
case SolNodeType::EqLesser:
return "bool";
2025-12-24 13:15:48 +11:00
break;
case SolNodeType::Add:
{
if (checkNodeReturnType(i.children[0]) == "string" && checkNodeReturnType(i.children[1]) == "string") {
return "string";
2025-12-24 13:15:48 +11:00
}
}
case SolNodeType::Subtract:
case SolNodeType::Multiply:
case SolNodeType::Divide:
{
if (checkNodeReturnType(i.children[0]) == "double") {
return "double";
2025-12-24 13:15:48 +11:00
}
if (checkNodeReturnType(i.children[1]) == "double") {
return "double";
2025-12-24 13:15:48 +11:00
}
return "int";
2025-12-24 13:15:48 +11:00
break;
}
2025-12-29 10:30:07 +11:00
case SolNodeType::FunctionCall: {
if (i.children[0].outputId == "input") {
if (i.children.size() > 1) {
ensure(i.children[1], "string", "input function argument");
}
return "string";
}
std::string funcName = i.children[0].outputId;
if (variables.find(funcName) == variables.end()) {
Error::syntaxError("Unknown function " + funcName, i.line, i.lineContent);
}
std::string signature = variables[funcName];
// Parse signature: fun(arg1, arg2) retType
if (signature.rfind("fun(", 0) != 0) {
// Not a function signature, maybe it's a variable being called?
Error::typingError(funcName + " is not a function", i.line, i.lineContent);
}
size_t endParen = signature.find(')');
if (endParen == std::string::npos) {
Error::typingError("Invalid function signature for " + funcName, i.line, i.lineContent);
}
std::string argsStr = signature.substr(4, endParen - 4);
std::string retType = signature.substr(endParen + 2); // skip ") "
std::vector<std::string> expectedArgs;
if (!argsStr.empty()) {
size_t start = 0;
size_t end = argsStr.find(", ");
while (end != std::string::npos) {
expectedArgs.push_back(argsStr.substr(start, end - start));
start = end + 2;
end = argsStr.find(", ", start);
}
expectedArgs.push_back(argsStr.substr(start));
}
// Check arguments
// children[0] is function name, children[1..] are args
if (i.children.size() - 1 != expectedArgs.size()) {
Error::typingError("Expected " + std::to_string(expectedArgs.size()) + " arguments for " + funcName + ", got " + std::to_string(i.children.size() - 1), i.line, i.lineContent);
return "none";
}
for (size_t k = 0; k < expectedArgs.size(); ++k) {
std::string argType = checkNodeReturnType(i.children[k + 1]);
if (argType != expectedArgs[k]) {
Error::typingError("Expected argument " + std::to_string(k + 1) + " of " + funcName + " to be " + expectedArgs[k] + ", got " + argType, i.children[k + 1].line, i.children[k + 1].lineContent);
}
}
return retType;
break;
}
2025-12-24 13:15:48 +11:00
case SolNodeType::Puts:
case SolNodeType::If:
case SolNodeType::While:
case SolNodeType::CodeBlock:
2025-12-24 14:31:43 +11:00
case SolNodeType::Set:
case SolNodeType::Root:
case SolNodeType::None:
case SolNodeType::FunctionDef:
return "none";
2025-12-24 13:15:48 +11:00
break;
}
return "none";
2025-12-24 13:15:48 +11:00
}
2025-12-21 12:06:55 +11:00
// SolData Implementation
SolData::SolData(int64_t in) : data(in), type(SolDataType::Int) {}
SolData::SolData(double in) : data(in), type(SolDataType::Double) {}
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) {}
2025-12-21 12:06:55 +11:00
std::optional<int64_t> SolData::getInt() {
if (type == SolDataType::Int) {
return std::get<int64_t>(data);
} else {
return {};
}
}
std::optional<double> SolData::getDouble() {
if (type == SolDataType::Double) {
return std::get<double>(data);
} else {
return {};
}
}
std::optional<std::string> SolData::getString() {
if (type == SolDataType::String) {
return std::get<std::string>(data);
} else {
return {};
}
}
std::optional<char> SolData::getChar() {
if (type == SolDataType::Char) {
return std::get<char>(data);
} else {
return {};
}
}
std::optional<bool> SolData::getBool() {
if (type == SolDataType::Bool) {
return std::get<bool>(data);
} else {
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";
}
2025-12-21 12:06:55 +11:00
// SolNode Implementation
SolNode::SolNode(SolNodeType nodeType) : nodeType(nodeType) {}
SolNode::SolNode(SolNodeType nodeType, SolData data) : data(data), nodeType(nodeType) {}
void SolNode::addNode(SolNode in) {
children.push_back(in);
}
void SolNode::setValue(SolData in) {
data = in;
}
2025-12-28 13:49:05 +11:00
std::string currentFunctionRetType = "";
2025-12-21 12:06:55 +11:00
const std::vector<SolGroundCodeBlock> SolNode::generateCode() {
std::vector<SolGroundCodeBlock> code;
if (nodeType != SolNodeType::If && nodeType != SolNodeType::While) for (auto& child : children) {
auto childCode = child.generateCode();
code.insert(code.end(), childCode.begin(), childCode.end());
}
switch (nodeType) {
case SolNodeType::Value: {
outputId = "tmp_" + std::to_string(tmpIdIterator++);
SolGroundCodeBlock codeBlock;
GroundInstruction gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
switch (data.type) {
case SolDataType::Int: {
auto dataopt = data.getInt();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(INT, dataopt.value()));
}
break;
}
case SolDataType::Double: {
auto dataopt = data.getDouble();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(DOUBLE, dataopt.value()));
}
break;
}
case SolDataType::String: {
auto dataopt = data.getString();
if (dataopt) {
2025-12-22 19:38:06 +11:00
char* str = (char*) malloc(dataopt.value().size() + 1);
strcpy(str, dataopt.value().c_str());
groundAddValueToInstruction(&gi, groundCreateValue(STRING, str));
2025-12-21 12:06:55 +11:00
}
break;
}
case SolDataType::Char: {
auto dataopt = data.getChar();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(CHAR, dataopt.value()));
}
break;
}
case SolDataType::Bool: {
auto dataopt = data.getBool();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, dataopt.value()));
}
break;
}
}
codeBlock.code.push_back(gi);
code.push_back(codeBlock);
break;
}
case SolNodeType::Add: {
ensure3(children[0], "int", "double", "string", "operator '+'");
ensure3(children[1], "int", "double", "string", "operator '+'");
2025-12-25 22:37:40 +11:00
ensuresame(children[0], children[1], "operator '+'");
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(ADD);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to add", children[0].line, children[0].lineContent);
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
2025-12-24 14:31:43 +11:00
case SolNodeType::Subtract: {
ensure2(children[0], "int", "double", "operator '-'");
ensure2(children[1], "int", "double", "operator '-'");
2025-12-24 14:31:43 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(SUBTRACT);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to subtract", children[0].line, children[0].lineContent);
2025-12-24 14:31:43 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
2025-12-24 16:22:51 +11:00
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
code.push_back(codeBlock);
break;
}
case SolNodeType::Multiply: {
ensure2(children[0], "int", "double", "operator '*'");
ensure2(children[1], "int", "double", "operator '*'");
2025-12-24 16:22:51 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(MULTIPLY);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to multiply", children[0].line, children[0].lineContent);
2025-12-24 16:22:51 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
code.push_back(codeBlock);
break;
}
case SolNodeType::Divide: {
ensure2(children[0], "int", "double", "operator '/'");
ensure2(children[1], "int", "double", "operator '/'");
2025-12-24 16:22:51 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(DIVIDE);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to divide", children[0].line, children[0].lineContent);
2025-12-24 16:22:51 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
2025-12-24 14:31:43 +11:00
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
code.push_back(codeBlock);
break;
}
2025-12-21 12:06:55 +11:00
case SolNodeType::Equal: {
2025-12-25 22:37:40 +11:00
ensuresame(children[0], children[1], "operator '=='");
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(EQUAL);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to equal", children[0].line, children[0].lineContent);
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::Inequal: {
2025-12-25 22:37:40 +11:00
ensuresame(children[0], children[1], "operator '!='");
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(INEQUAL);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent);
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
2025-12-22 13:49:44 +11:00
case SolNodeType::Greater: {
2025-12-25 22:37:40 +11:00
ensuresame(children[0], children[1], "operator '>'");
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(GREATER);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to greater", children[0].line, children[0].lineContent);
2025-12-22 13:49:44 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::Lesser: {
2025-12-25 22:37:40 +11:00
ensuresame(children[0], children[1], "operator '<'");
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(LESSER);
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to lesser", children[0].line, children[0].lineContent);
2025-12-22 13:49:44 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::EqGreater: {
2025-12-25 22:37:40 +11:00
ensuresame(children[0], children[1], "operator '>='");
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock;
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent);
2025-12-22 13:49:44 +11:00
}
outputId = "tmp_" + std::to_string(tmpIdIterator++);
std::string trueLabelIdString = "internal_true" + std::to_string(labelIterator++);
std::string falseLabelIdString = "internal_false" + std::to_string(labelIterator);
std::string endLabelIdString = "internal_end" + std::to_string(labelIterator);
char* trueLabelId = (char*) malloc(sizeof(char) * (trueLabelIdString.size() + 1));
strcpy(trueLabelId, trueLabelIdString.data());
char* falseLabelId = (char*) malloc(sizeof(char) * (falseLabelIdString.size() + 1));
strcpy(falseLabelId, falseLabelIdString.data());
char* endLabelId = (char*) malloc(sizeof(char) * (endLabelIdString.size() + 1));
strcpy(endLabelId, endLabelIdString.data());
// greater $tmp_0 $tmp_1 &cond
GroundInstruction gi = groundCreateInstruction(GREATER);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond0"));
codeBlock.code.push_back(gi);
// if &cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond0"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// equal $tmp_0 $tmp_1 &cond
gi = groundCreateInstruction(EQUAL);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond1"));
codeBlock.code.push_back(gi);
// if $cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond1"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// jump %false
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, falseLabelId));
codeBlock.code.push_back(gi);
// @true
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, trueLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x true
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, true));
codeBlock.code.push_back(gi);
// jump %end
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, endLabelId));
codeBlock.code.push_back(gi);
// @false
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, falseLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x false
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false));
codeBlock.code.push_back(gi);
// @end
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::EqLesser: {
2025-12-25 22:37:40 +11:00
ensuresame(children[0], children[1], "operator '<='");
2025-12-22 13:49:44 +11:00
SolGroundCodeBlock codeBlock;
if (children.size() < 2) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent);
2025-12-22 13:49:44 +11:00
}
outputId = "tmp_" + std::to_string(tmpIdIterator++);
std::string trueLabelIdString = "internal_true" + std::to_string(labelIterator++);
std::string falseLabelIdString = "internal_false" + std::to_string(labelIterator);
std::string endLabelIdString = "internal_end" + std::to_string(labelIterator);
char* trueLabelId = (char*) malloc(sizeof(char) * (trueLabelIdString.size() + 1));
strcpy(trueLabelId, trueLabelIdString.data());
char* falseLabelId = (char*) malloc(sizeof(char) * (falseLabelIdString.size() + 1));
strcpy(falseLabelId, falseLabelIdString.data());
char* endLabelId = (char*) malloc(sizeof(char) * (endLabelIdString.size() + 1));
strcpy(endLabelId, endLabelIdString.data());
// lesser $tmp_0 $tmp_1 &cond
GroundInstruction gi = groundCreateInstruction(LESSER);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond0"));
codeBlock.code.push_back(gi);
// if &cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond0"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// equal $tmp_0 $tmp_1 &cond
gi = groundCreateInstruction(EQUAL);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond1"));
codeBlock.code.push_back(gi);
// if $cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond1"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// jump %false
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, falseLabelId));
codeBlock.code.push_back(gi);
// @true
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, trueLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x true
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, true));
codeBlock.code.push_back(gi);
// jump %end
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, endLabelId));
codeBlock.code.push_back(gi);
// @false
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, falseLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x false
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false));
codeBlock.code.push_back(gi);
// @end
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
2025-12-21 12:06:55 +11:00
case SolNodeType::Puts: {
SolGroundCodeBlock codeBlock;
2025-12-24 14:31:43 +11:00
exists(children[0]);
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction(PRINTLN);
if (children.size() < 1) {
2025-12-25 22:37:40 +11:00
Error::typingError("Need more stuff to puts", children[0].line, children[0].lineContent);
2025-12-21 12:06:55 +11:00
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::If: {
ensure(children[0], "bool", "if condition");
2025-12-21 12:06:55 +11:00
auto conditionCode = children[0].generateCode();
code.insert(code.end(), conditionCode.begin(), conditionCode.end());
outputId = "tmp_" + std::to_string(tmpIdIterator++);
SolGroundCodeBlock codeBlock;
codeBlock.toBeDropped.push_back(outputId);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction(NOT);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
std::string labelIdString = "if_" + std::to_string(labelIterator++);
char* labelId = (char*) malloc(sizeof(char) * labelIdString.size() + 1);
strcpy(labelId, labelIdString.data());
GroundInstruction gi2 = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi2, groundCreateReference(VALREF, outputId.data()));
groundAddReferenceToInstruction(&gi2, groundCreateReference(LINEREF, labelId));
codeBlock.code.push_back(gi2);
code.push_back(codeBlock);
for (size_t i = 1; i < children.size(); i++) {
auto childCode = children[i].generateCode();
code.insert(code.end(), childCode.begin(), childCode.end());
}
codeBlock.code.clear();
2025-12-22 19:38:06 +11:00
codeBlock.toBeDropped.clear();
2025-12-21 12:06:55 +11:00
GroundInstruction gi3 = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi3, groundCreateReference(LABEL, labelId));
codeBlock.code.push_back(gi3);
code.push_back(codeBlock);
break;
}
case SolNodeType::While: {
ensure(children[0], "bool", "while condition");
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock startLabelBlock;
std::string startLabelIdString = "whilestart_" + std::to_string(labelIterator++);
std::string endLabelIdString = "whileend_" + std::to_string(labelIterator);
char* startLabelId = (char*) malloc(sizeof(char) * (startLabelIdString.size() + 1));
strcpy(startLabelId, startLabelIdString.data());
char* endLabelId = (char*) malloc(sizeof(char) * (endLabelIdString.size() + 1));
strcpy(endLabelId, endLabelIdString.data());
GroundInstruction startLabel = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&startLabel, groundCreateReference(LABEL, startLabelId));
startLabelBlock.code.push_back(startLabel);
code.push_back(startLabelBlock);
auto conditionCode = children[0].generateCode();
code.insert(code.end(), conditionCode.begin(), conditionCode.end());
SolGroundCodeBlock checkBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
checkBlock.toBeDropped.push_back(outputId);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) checkBlock.toBeDropped.push_back(children[0].outputId);
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction(NOT);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
checkBlock.code.push_back(gi);
GroundInstruction gi2 = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi2, groundCreateReference(VALREF, outputId.data()));
groundAddReferenceToInstruction(&gi2, groundCreateReference(LINEREF, endLabelId));
checkBlock.code.push_back(gi2);
code.push_back(checkBlock);
for (size_t i = 1; i < children.size(); i++) {
auto childCode = children[i].generateCode();
code.insert(code.end(), childCode.begin(), childCode.end());
}
SolGroundCodeBlock endBlock;
GroundInstruction gi3 = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi3, groundCreateReference(LINEREF, startLabelId));
endBlock.code.push_back(gi3);
GroundInstruction gi4 = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi4, groundCreateReference(LABEL, endLabelId));
endBlock.code.push_back(gi4);
code.push_back(endBlock);
break;
}
case SolNodeType::Identifier: {
break;
}
case SolNodeType::Set: {
2025-12-24 13:15:48 +11:00
if (variables.find(children[0].outputId) != variables.end()) {
if (variables[children[0].outputId] != checkNodeReturnType(children[1])) {
2025-12-25 22:37:40 +11:00
Error::typingError("Cannot change type of this variable", children[0].line, children[0].lineContent);
2025-12-24 13:15:48 +11:00
}
}
2025-12-24 14:31:43 +11:00
exists(children[1]);
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock codeBlock;
GroundInstruction setInstruction = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&setInstruction, groundCreateReference(DIRREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&setInstruction, groundCreateReference(VALREF, children[1].outputId.data()));
codeBlock.code.push_back(setInstruction);
2025-12-22 19:38:06 +11:00
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
2025-12-24 13:15:48 +11:00
// Make sure we know what the variable type is
variables[children[0].outputId] = children[1].data.getTypeString();
2025-12-21 12:06:55 +11:00
break;
}
case SolNodeType::FunctionCall: {
2025-12-29 10:30:07 +11:00
checkNodeReturnType(*this);
2025-12-21 12:06:55 +11:00
// Take care of in built functions
// This will be removed when inline ground is added
2025-12-21 12:06:55 +11:00
if (children[0].outputId == "input") {
ensure(children[1], "string", "input function argument");
2025-12-21 12:06:55 +11:00
SolGroundCodeBlock inputCodeBlock;
if (children.size() > 1) {
GroundInstruction printInstruction = groundCreateInstruction(PRINT);
groundAddReferenceToInstruction(&printInstruction, groundCreateReference(VALREF, children[1].outputId.data()));
inputCodeBlock.code.push_back(printInstruction);
2025-12-22 19:38:06 +11:00
if (isTemp(children[1].outputId)) inputCodeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
}
GroundInstruction inputInstruction = groundCreateInstruction(INPUT);
outputId = "tmp_" + std::to_string(tmpIdIterator++);
groundAddReferenceToInstruction(&inputInstruction, groundCreateReference(DIRREF, outputId.data()));
inputCodeBlock.code.push_back(inputInstruction);
code.push_back(inputCodeBlock);
break;
}
2025-12-26 13:50:14 +11:00
exists(children[0]);
std::string fnToCall = children[0].outputId;
2025-12-28 13:41:05 +11:00
outputId = "tmp_" + std::to_string(tmpIdIterator++);
SolGroundCodeBlock codeBlock;
GroundInstruction callInstruction = groundCreateInstruction(CALL);
groundAddReferenceToInstruction(&callInstruction, groundCreateReference(FNREF, children[0].outputId.data()));
for (int i = 1; i < children.size(); i++) {
groundAddReferenceToInstruction(&callInstruction, groundCreateReference(VALREF, children[i].outputId.data()));
}
groundAddReferenceToInstruction(&callInstruction, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(callInstruction);
code.push_back(codeBlock);
break;
}
case SolNodeType::Return: {
2025-12-29 10:30:07 +11:00
std::string retType = checkNodeReturnType(children[0]);
if (currentFunctionRetType != "" && retType != currentFunctionRetType) {
Error::typingError("Expected return type " + currentFunctionRetType + " but got " + retType, children[0].line, children[0].lineContent);
}
2025-12-28 13:41:05 +11:00
SolGroundCodeBlock codeBlock;
GroundInstruction returnInstruction = groundCreateInstruction(RETURN);
groundAddReferenceToInstruction(&returnInstruction, groundCreateReference(VALREF, children[0].outputId.data()));
codeBlock.code.push_back(returnInstruction);
code.push_back(codeBlock);
break;
}
case SolNodeType::FunctionDef: {
auto functionopt = data.getFunction();
if (functionopt.has_value()) {
SolFunction function = functionopt.value();
SolGroundCodeBlock codeBlock;
GroundInstruction inst = groundCreateInstruction(FUN);
char* fnName = (char*) malloc(sizeof(char) * (function.name.size() + 1));
strcpy(fnName, function.name.c_str());
char* retType = (char*) malloc(sizeof(char) * (function.returnType.size() + 1));
strcpy(retType, function.returnType.c_str());
groundAddReferenceToInstruction(&inst, groundCreateReference(FNREF, fnName));
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, retType));
2025-12-29 10:30:07 +11:00
// Scope Management
2025-12-28 13:41:05 +11:00
auto variablebackup = variables;
2025-12-29 10:30:07 +11:00
std::string oldRetType = currentFunctionRetType;
variables.clear();
currentFunctionRetType = function.returnType;
2025-12-28 13:41:05 +11:00
for (auto& pair : function.parameters) {
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, pair.second.data()));
groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, pair.first.data()));
2025-12-29 10:30:07 +11:00
variables[pair.first] = pair.second; // Correctly map Name -> Type
2025-12-28 13:41:05 +11:00
}
2025-12-29 10:30:07 +11:00
2025-12-28 13:41:05 +11:00
codeBlock.code.push_back(inst);
code.push_back(codeBlock);
codeBlock.code.clear();
2025-12-29 10:30:07 +11:00
// Generate body code with local variables visible
2025-12-28 13:41:05 +11:00
auto childCode = function.content->generateCode();
code.insert(code.end(), childCode.begin(), childCode.end());
2025-12-29 10:30:07 +11:00
2025-12-28 13:41:05 +11:00
codeBlock.code.push_back(groundCreateInstruction(ENDFUN));
code.push_back(codeBlock);
2025-12-29 10:30:07 +11:00
// Restore Scope
variables = variablebackup;
currentFunctionRetType = oldRetType;
2025-12-28 13:41:05 +11:00
}
2025-12-21 12:06:55 +11:00
break;
}
default: {}
}
return code;
}
// Parser Implementation
2025-12-25 22:37:40 +11:00
Parser::Parser(std::vector<Token> in) : tokensToParse(in) {}
2025-12-21 12:06:55 +11:00
2025-12-25 22:37:40 +11:00
std::optional<Token> Parser::peek(int ahead) {
2025-12-21 12:06:55 +11:00
if (current + ahead < size) {
return tokensToParse[current + ahead];
} else {
return {};
}
}
2025-12-25 22:37:40 +11:00
std::optional<Token> Parser::consume() {
2025-12-21 12:06:55 +11:00
if (current < size) {
return tokensToParse[current++];
} else {
return {};
}
}
// Helper functions
bool Parser::isInt(std::string in) {
for (const char& c : in) {
if (!std::isdigit(c)) {
return false;
}
}
return true;
}
bool Parser::isDouble(std::string in) {
bool foundDot = false;
for (const char& c : in) {
if (!std::isdigit(c)) {
if (!foundDot && c == '.') {
foundDot = true;
continue;
}
return false;
}
}
return true;
}
bool Parser::isString(std::string in) {
if (in.size() > 1 && in[0] == '"' && in.back() == '"') {
return true;
}
return false;
}
bool Parser::isChar(std::string in) {
if (in.size() == 3 && in[0] == '\'' && in.back() == '\'') {
return true;
}
return false;
}
bool Parser::isBool(std::string in) {
if (in == "true" || in == "false") {
return true;
}
return false;
}
SolDataType Parser::getDataType(std::string in) {
if (isInt(in)) {
return SolDataType::Int;
}
if (isDouble(in)) {
return SolDataType::Double;
}
if (isString(in)) {
return SolDataType::String;
}
if (isChar(in)) {
return SolDataType::Char;
}
if (isBool(in)) {
return SolDataType::Bool;
}
return SolDataType::None;
}
SolNodeType Parser::getNodeType(std::string in) {
if (getDataType(in) != SolDataType::None) {
return SolNodeType::Value;
}
if (in == "+") {
return SolNodeType::Add;
}
2025-12-24 14:31:43 +11:00
if (in == "-") {
return SolNodeType::Subtract;
}
if (in == "*") {
return SolNodeType::Multiply;
}
if (in == "/") {
return SolNodeType::Divide;
}
2025-12-21 12:06:55 +11:00
if (in == "=") {
return SolNodeType::Set;
}
if (in == "==") {
return SolNodeType::Equal;
}
if (in == "!=") {
return SolNodeType::Inequal;
}
2025-12-22 13:49:44 +11:00
if (in == ">=") {
return SolNodeType::EqGreater;
}
if (in == "<=") {
return SolNodeType::EqLesser;
}
if (in == ">") {
return SolNodeType::Greater;
}
if (in == "<") {
return SolNodeType::Lesser;
}
2025-12-21 12:06:55 +11:00
if (in == "puts") {
return SolNodeType::Puts;
}
if (in == "if") {
return SolNodeType::If;
}
if (in == "while") {
return SolNodeType::While;
}
if (in == "def") {
return SolNodeType::FunctionDef;
}
2025-12-28 13:41:05 +11:00
if (in == "return") {
return SolNodeType::Return;
}
2025-12-21 12:06:55 +11:00
if (in == "{") {
return SolNodeType::CodeBlockStart;
}
if (in == "}") {
return SolNodeType::CodeBlockEnd;
}
if (in == "(") {
return SolNodeType::BracketStart;
}
if (in == ")") {
return SolNodeType::BracketEnd;
}
return SolNodeType::Identifier;
}
2025-12-24 22:01:16 +11:00
int Parser::getPrecedence(std::string token) {
if (token == "*" || token == "/") return 2;
if (token == "+" || token == "-") return 1;
return 0;
}
SolNode Parser::parsePrimary() {
auto tokenopt = consume();
if (!tokenopt) {
2025-12-25 22:37:40 +11:00
Error::syntaxError("Unexpected end of input");
2025-12-24 22:01:16 +11:00
}
2025-12-25 22:37:40 +11:00
Token tokenObj = tokenopt.value();
std::string token = tokenObj.value;
2025-12-24 22:01:16 +11:00
SolNodeType type = getNodeType(token);
if (type == SolNodeType::Value) {
SolNode node(SolNodeType::Value);
2025-12-25 22:37:40 +11:00
node.line = tokenObj.line;
node.lineContent = tokenObj.lineContent;
2025-12-24 22:01:16 +11:00
switch (getDataType(token)) {
case SolDataType::Int: node.setValue((int64_t) std::stoll(token)); break;
case SolDataType::Double: node.setValue(std::stod(token)); break;
case SolDataType::String: node.setValue(token.substr(1, token.size() - 2)); break;
case SolDataType::Char: node.setValue(token[1]); break;
case SolDataType::Bool: node.setValue(token == "true"); break;
default: break;
}
return node;
}
if (type == SolNodeType::Identifier) {
SolNode idNode(SolNodeType::Identifier);
idNode.outputId = token;
2025-12-25 22:37:40 +11:00
idNode.line = tokenObj.line;
idNode.lineContent = tokenObj.lineContent;
auto peekOpt = peek();
if (peekOpt.has_value() && peekOpt.value().value == "(") {
2025-12-24 22:01:16 +11:00
consume(); // (
SolNode fnCallNode(SolNodeType::FunctionCall);
2025-12-25 22:37:40 +11:00
fnCallNode.line = tokenObj.line;
fnCallNode.lineContent = tokenObj.lineContent;
2025-12-24 22:01:16 +11:00
fnCallNode.addNode(idNode);
2025-12-25 22:37:40 +11:00
std::vector<Token> tokens;
2025-12-24 22:01:16 +11:00
size_t brackets = 1;
while (auto t = consume()) {
2025-12-25 22:37:40 +11:00
if (t.value().value == "(") brackets++;
if (t.value().value == ")") brackets--;
2025-12-24 22:01:16 +11:00
if (brackets == 0) break;
tokens.push_back(t.value());
}
2025-12-25 22:37:40 +11:00
if (brackets != 0) {
Error::syntaxError("Unclosed function call bracket", tokenObj.line, tokenObj.lineContent);
}
2025-12-24 22:01:16 +11:00
auto args = Parser(tokens).parse();
for(auto& child : args.children) fnCallNode.addNode(child);
return fnCallNode;
}
return idNode;
}
if (type == SolNodeType::BracketStart) {
2025-12-25 22:37:40 +11:00
std::vector<Token> tokens;
2025-12-24 22:01:16 +11:00
size_t brackets = 1;
while (auto t = consume()) {
2025-12-25 22:37:40 +11:00
if (t.value().value == "(") brackets++;
if (t.value().value == ")") brackets--;
2025-12-24 22:01:16 +11:00
if (brackets == 0) break;
tokens.push_back(t.value());
}
2025-12-25 22:37:40 +11:00
if (brackets != 0) {
Error::syntaxError("Unclosed bracket", tokenObj.line, tokenObj.lineContent);
}
2025-12-24 22:01:16 +11:00
auto inner = Parser(tokens).parse();
if (inner.children.size() > 0) return inner.children[0];
return SolNode(SolNodeType::None);
}
2025-12-25 22:37:40 +11:00
Error::syntaxError("Unexpected token in expression: " + token, tokenObj.line, tokenObj.lineContent);
2025-12-28 13:41:05 +11:00
return SolNode(SolNodeType::None);
2025-12-24 22:01:16 +11:00
}
SolNode Parser::parseExpression(int minPrec) {
SolNode lhs = parsePrimary();
while(true) {
auto opOpt = peek();
if (!opOpt) break;
2025-12-25 22:37:40 +11:00
Token opToken = opOpt.value();
std::string op = opToken.value;
2025-12-24 22:01:16 +11:00
int prec = getPrecedence(op);
if (prec < minPrec) break;
consume();
SolNode rhs = parseExpression(prec + 1);
SolNode newNode(getNodeType(op));
2025-12-25 22:37:40 +11:00
newNode.line = opToken.line;
newNode.lineContent = opToken.lineContent;
2025-12-24 22:01:16 +11:00
newNode.addNode(lhs);
newNode.addNode(rhs);
lhs = newNode;
}
return lhs;
}
2025-12-21 12:06:55 +11:00
SolNode Parser::parse() {
current = 0;
size = tokensToParse.size();
SolNode rootNode(SolNodeType::Root);
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
Token tokenObj = tokenopt.value();
std::string token = tokenObj.value;
2025-12-21 12:06:55 +11:00
switch (getNodeType(token)) {
case SolNodeType::Value: {
switch (getDataType(token)) {
case SolDataType::Int: {
SolNode intNode(SolNodeType::Value);
intNode.setValue((int64_t) std::stoll(token));
2025-12-25 22:37:40 +11:00
intNode.line = tokenObj.line;
intNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
rootNode.addNode(intNode);
break;
}
case SolDataType::Double: {
SolNode doubleNode(SolNodeType::Value);
doubleNode.setValue(std::stod(token));
2025-12-25 22:37:40 +11:00
doubleNode.line = tokenObj.line;
doubleNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
rootNode.addNode(doubleNode);
break;
}
case SolDataType::String: {
SolNode stringNode(SolNodeType::Value);
stringNode.setValue(token.substr(1, token.size() - 2));
2025-12-25 22:37:40 +11:00
stringNode.line = tokenObj.line;
stringNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
rootNode.addNode(stringNode);
break;
}
case SolDataType::Char: {
SolNode charNode(SolNodeType::Value);
charNode.setValue(token[1]);
2025-12-25 22:37:40 +11:00
charNode.line = tokenObj.line;
charNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
rootNode.addNode(charNode);
break;
}
case SolDataType::Bool: {
SolNode boolNode(SolNodeType::Value);
boolNode.setValue(token == "true");
2025-12-25 22:37:40 +11:00
boolNode.line = tokenObj.line;
boolNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
rootNode.addNode(boolNode);
break;
}
}
break;
}
2025-12-24 14:31:43 +11:00
case SolNodeType::Add:
case SolNodeType::Subtract:
case SolNodeType::Multiply:
case SolNodeType::Divide:
{
2025-12-24 22:01:16 +11:00
SolNode opNode(getNodeType(token));
2025-12-25 22:37:40 +11:00
opNode.line = tokenObj.line;
opNode.lineContent = tokenObj.lineContent;
2025-12-24 22:01:16 +11:00
if (rootNode.children.empty()) {
2025-12-25 22:37:40 +11:00
Error::syntaxError("Expected operand before operator", tokenObj.line, tokenObj.lineContent);
2025-12-21 12:06:55 +11:00
}
2025-12-24 22:01:16 +11:00
opNode.addNode(rootNode.children.back());
rootNode.children.pop_back();
// Parse RHS with higher precedence
SolNode rhs = parseExpression(getPrecedence(token) + 1);
opNode.addNode(rhs);
rootNode.addNode(opNode);
2025-12-21 12:06:55 +11:00
break;
}
2025-12-22 13:49:44 +11:00
case SolNodeType::Equal:
case SolNodeType::Inequal:
case SolNodeType::Lesser:
case SolNodeType::Greater:
case SolNodeType::EqLesser:
case SolNodeType::EqGreater:
{
SolNode equalNode(getNodeType(token));
2025-12-25 22:37:40 +11:00
equalNode.line = tokenObj.line;
equalNode.lineContent = tokenObj.lineContent;
2025-12-22 13:49:44 +11:00
if (rootNode.children.empty()) {
2025-12-25 22:37:40 +11:00
Error::syntaxError("Expected operand before comparison", tokenObj.line, tokenObj.lineContent);
2025-12-21 12:06:55 +11:00
}
2025-12-22 13:49:44 +11:00
equalNode.addNode(rootNode.children.back());
2025-12-21 12:06:55 +11:00
rootNode.children.pop_back();
2025-12-25 22:37:40 +11:00
std::vector<Token> tokens;
2025-12-22 13:49:44 +11:00
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "\n") {
2025-12-22 13:49:44 +11:00
break;
}
tokens.push_back(tokenopt.value());
2025-12-21 12:06:55 +11:00
}
2025-12-22 13:49:44 +11:00
auto children = Parser(tokens).parse();
equalNode.addNode(children.children[0]);
rootNode.addNode(equalNode);
2025-12-21 12:06:55 +11:00
break;
}
case SolNodeType::Puts: {
SolNode putsNode(SolNodeType::Puts);
2025-12-25 22:37:40 +11:00
putsNode.line = tokenObj.line;
putsNode.lineContent = tokenObj.lineContent;
std::vector<Token> tokens;
2025-12-21 12:06:55 +11:00
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "\n") {
2025-12-21 12:06:55 +11:00
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
for (auto& child : children.children) {
putsNode.addNode(child);
}
rootNode.addNode(putsNode);
break;
}
case SolNodeType::If: {
SolNode ifNode(SolNodeType::If);
2025-12-25 22:37:40 +11:00
ifNode.line = tokenObj.line;
ifNode.lineContent = tokenObj.lineContent;
std::vector<Token> tokens;
2025-12-21 12:06:55 +11:00
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "\n") {
2025-12-21 12:06:55 +11:00
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
ifNode.addNode(children.children[0]);
tokens.clear();
size_t brackets = 1;
auto tokenopt = consume();
if (tokenopt) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "{") {
2025-12-21 12:06:55 +11:00
tokens.push_back(tokenopt.value());
while (auto tokenopt = consume()) {
tokens.push_back(tokenopt.value());
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "{") {
2025-12-21 12:06:55 +11:00
brackets++;
}
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "}") {
2025-12-21 12:06:55 +11:00
brackets--;
}
if (brackets == 0) {
break;
}
}
2025-12-25 22:37:40 +11:00
if (brackets != 0) {
Error::syntaxError("Unclosed code block", tokenopt.value().line, tokenopt.value().lineContent);
}
2025-12-21 12:06:55 +11:00
} else {
2025-12-25 22:37:40 +11:00
Error::syntaxError("I want a code block instead of a " + tokenopt.value().value, tokenopt.value().line, tokenopt.value().lineContent);
2025-12-21 12:06:55 +11:00
}
} else {
2025-12-25 22:37:40 +11:00
Error::syntaxError("Expected code block after if condition", ifNode.line, ifNode.lineContent);
2025-12-21 12:06:55 +11:00
}
auto childCodeBlock = Parser(tokens).parse();
ifNode.addNode(childCodeBlock.children[0]);
rootNode.addNode(ifNode);
break;
}
case SolNodeType::While: {
SolNode whileNode(SolNodeType::While);
2025-12-25 22:37:40 +11:00
whileNode.line = tokenObj.line;
whileNode.lineContent = tokenObj.lineContent;
std::vector<Token> tokens;
2025-12-21 12:06:55 +11:00
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "\n") {
2025-12-21 12:06:55 +11:00
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
whileNode.addNode(children.children[0]);
tokens.clear();
size_t brackets = 1;
auto tokenopt = consume();
if (tokenopt) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "{") {
2025-12-21 12:06:55 +11:00
tokens.push_back(tokenopt.value());
while (auto tokenopt = consume()) {
tokens.push_back(tokenopt.value());
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "{") {
2025-12-21 12:06:55 +11:00
brackets++;
}
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "}") {
2025-12-21 12:06:55 +11:00
brackets--;
}
if (brackets == 0) {
break;
}
}
2025-12-25 22:37:40 +11:00
if (brackets != 0) {
Error::syntaxError("Unclosed code block", tokenopt.value().line, tokenopt.value().lineContent);
}
2025-12-21 12:06:55 +11:00
} else {
2025-12-25 22:37:40 +11:00
Error::syntaxError("I want a code block instead of a " + tokenopt.value().value, tokenopt.value().line, tokenopt.value().lineContent);
2025-12-21 12:06:55 +11:00
}
} else {
2025-12-25 22:37:40 +11:00
Error::syntaxError("Expected code block after while condition", whileNode.line, whileNode.lineContent);
2025-12-21 12:06:55 +11:00
}
auto childCodeBlock = Parser(tokens).parse();
whileNode.addNode(childCodeBlock.children[0]);
rootNode.addNode(whileNode);
break;
}
case SolNodeType::CodeBlockStart: {
SolNode codeBlockNode(SolNodeType::CodeBlock);
2025-12-25 22:37:40 +11:00
codeBlockNode.line = tokenObj.line;
codeBlockNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
size_t brackets = 1;
2025-12-25 22:37:40 +11:00
std::vector<Token> tokens;
2025-12-21 12:06:55 +11:00
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "{") {
2025-12-21 12:06:55 +11:00
brackets++;
}
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "}") {
2025-12-21 12:06:55 +11:00
brackets--;
}
if (brackets == 0) {
break;
}
tokens.push_back(tokenopt.value());
}
2025-12-25 22:37:40 +11:00
if (brackets != 0) {
Error::syntaxError("Unclosed code block", tokenObj.line, tokenObj.lineContent);
}
2025-12-21 12:06:55 +11:00
codeBlockNode.children = Parser(tokens).parse().children;
rootNode.addNode(codeBlockNode);
break;
}
case SolNodeType::Identifier: {
SolNode idNode(SolNodeType::Identifier);
idNode.outputId = token;
2025-12-25 22:37:40 +11:00
idNode.line = tokenObj.line;
idNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
rootNode.addNode(idNode);
break;
}
case SolNodeType::Set: {
SolNode setNode(SolNodeType::Set);
2025-12-25 22:37:40 +11:00
setNode.line = tokenObj.line;
setNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
setNode.addNode(rootNode.children.back());
rootNode.children.pop_back();
2025-12-25 22:37:40 +11:00
std::vector<Token> tokens;
2025-12-21 12:06:55 +11:00
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "\n") {
2025-12-21 12:06:55 +11:00
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
setNode.addNode(children.children[0]);
rootNode.addNode(setNode);
break;
}
case SolNodeType::BracketStart: {
2025-12-28 13:49:05 +11:00
// function call
2025-12-21 12:06:55 +11:00
if (rootNode.children.back().nodeType == SolNodeType::Identifier) {
SolNode fnCallNode(SolNodeType::FunctionCall);
2025-12-25 22:37:40 +11:00
fnCallNode.line = tokenObj.line;
fnCallNode.lineContent = tokenObj.lineContent;
2025-12-21 12:06:55 +11:00
fnCallNode.addNode(rootNode.children.back());
rootNode.children.pop_back();
2025-12-25 22:37:40 +11:00
std::vector<Token> tokens;
2025-12-21 12:06:55 +11:00
size_t brackets = 1;
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "(") {
2025-12-21 12:06:55 +11:00
brackets++;
}
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == ")") {
2025-12-21 12:06:55 +11:00
brackets--;
}
2025-12-28 13:49:05 +11:00
// comma, eval statement here
if (tokenopt.value().value == "," && brackets == 1) {
auto node = Parser(tokens).parse();
if (!node.children.empty()) fnCallNode.children.push_back(node.children[0]);
else {
Error::syntaxError("dingus");
}
tokens.clear();
continue;
}
2025-12-21 12:06:55 +11:00
if (brackets < 1) {
break;
}
tokens.push_back(tokenopt.value());
}
auto node = Parser(tokens).parse();
fnCallNode.children.insert(fnCallNode.children.end(), node.children.begin(), node.children.end());
rootNode.addNode(fnCallNode);
} else {
2025-12-25 22:37:40 +11:00
std::vector<Token> tokens;
2025-12-21 12:06:55 +11:00
size_t brackets = 1;
while (auto tokenopt = consume()) {
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == "(") {
2025-12-21 12:06:55 +11:00
brackets++;
}
2025-12-25 22:37:40 +11:00
if (tokenopt.value().value == ")") {
2025-12-21 12:06:55 +11:00
brackets--;
}
if (brackets < 1) {
break;
}
tokens.push_back(tokenopt.value());
}
auto node = Parser(tokens).parse();
node.nodeType = SolNodeType::Expression;
rootNode.addNode(node);
}
2025-12-26 13:50:14 +11:00
break;
2025-12-21 12:06:55 +11:00
}
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);
}
2025-12-28 13:41:05 +11:00
fn.name = 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);
2025-12-28 13:41:05 +11:00
variables[fn.name] = signature;
rootNode.addNode(fnNode);
break;
}
2025-12-28 13:41:05 +11:00
case SolNodeType::Return: {
SolNode returnNode(SolNodeType::Return);
returnNode.line = tokenObj.line;
returnNode.lineContent = tokenObj.lineContent;
std::vector<Token> tokens;
while (auto tokenopt = consume()) {
if (tokenopt.value().value == "\n") {
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
for (auto& child : children.children) {
returnNode.addNode(child);
}
rootNode.addNode(returnNode);
break;
}
2025-12-21 12:06:55 +11:00
}
}
return rootNode;
}
GroundProgram assembleProgram(SolNode& rootNode) {
GroundProgram gp = groundCreateProgram();
auto code = rootNode.generateCode();
for (int i = 0; i < code.size(); i++) {
for (const auto& inst : code[i].code) {
groundAddInstructionToProgram(&gp, inst);
}
for (auto& tmpVar : code[i].toBeDropped) {
GroundInstruction gi = groundCreateInstruction(DROP);
2025-12-22 19:38:06 +11:00
char* droppedVar = (char*) malloc(tmpVar.size() + 1);
strcpy(droppedVar, tmpVar.c_str());
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, droppedVar));
groundAddInstructionToProgram(&gp, gi);
}
2025-12-21 12:06:55 +11:00
}
return gp;
}
} // namespace Parser
}