#include "parser.h" #include "error.h" #include "lexer.h" #include "solstice_stdlib.h" #include "argparser.h" #include #include #include #include #define parseOneToken(token) Parser({token}).parse().children[0] namespace Solstice { namespace Parser { char* copyString(std::string s) { char* str = (char*) malloc(s.size() + 1); strcpy(str, s.c_str()); return str; } bool isTemp(std::string id) { return id.rfind("tmp_", 0) == 0; } std::map variables; std::string checkNodeReturnType(SolNode i) { switch (i.nodeType) { case SolNodeType::Identifier: { if (variables.find(i.outputId) != variables.end()) { return variables[i.outputId]; } else { Error::syntaxError("Unknown variable " + i.outputId, i.line, i.lineContent); } break; } case SolNodeType::Value: { return i.data.getTypeString(); } case SolNodeType::Equal: case SolNodeType::Inequal: case SolNodeType::Greater: case SolNodeType::Lesser: case SolNodeType::EqGreater: case SolNodeType::EqLesser: return "bool"; break; case SolNodeType::Add: { 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]) == "double") { return "double"; } if (checkNodeReturnType(i.children[1]) == "double") { return "double"; } return "int"; break; } case SolNodeType::FunctionCall: { 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 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; } case SolNodeType::Puts: case SolNodeType::If: case SolNodeType::While: case SolNodeType::CodeBlock: case SolNodeType::Set: case SolNodeType::Root: case SolNodeType::None: case SolNodeType::FunctionDef: return "none"; break; } return "none"; } // 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) {} std::optional SolData::getInt() { if (type == SolDataType::Int) { return std::get(data); } else { return {}; } } std::optional SolData::getDouble() { if (type == SolDataType::Double) { return std::get(data); } else { return {}; } } std::optional SolData::getString() { if (type == SolDataType::String) { return std::get(data); } else { return {}; } } std::optional SolData::getChar() { if (type == SolDataType::Char) { return std::get(data); } else { return {}; } } std::optional SolData::getBool() { if (type == SolDataType::Bool) { return std::get(data); } else { return {}; } } std::optional SolData::getFunction() { if (type == SolDataType::Function) { return std::get(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) {} 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; } std::string currentFunctionRetType = ""; const std::vector SolNode::generateCode() { std::vector code; if (nodeType == SolNodeType::Root) { // Compile and insert standard library if (!ArgParser::nostdlib) { auto parsedStdlib = Parser(Lexer(getStdLib()).lex()).parse(); parsedStdlib.nodeType = SolNodeType::None; code = parsedStdlib.generateCode(); } } if (nodeType != SolNodeType::If && nodeType != SolNodeType::While && nodeType != SolNodeType::Struct) 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, copyString(outputId))); 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) { char* str = (char*) malloc(dataopt.value().size() + 1); strcpy(str, dataopt.value().c_str()); groundAddValueToInstruction(&gi, groundCreateValue(STRING, str)); } 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 '+'"); ensuresame(children[0], children[1], "operator '+'"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(ADD); if (children.size() < 2) { Error::typingError("Need more stuff to add", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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::Subtract: { ensure2(children[0], "int", "double", "operator '-'"); ensure2(children[1], "int", "double", "operator '-'"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(SUBTRACT); if (children.size() < 2) { Error::typingError("Need more stuff to subtract", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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 '*'"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(MULTIPLY); if (children.size() < 2) { Error::typingError("Need more stuff to multiply", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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 '/'"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(DIVIDE); if (children.size() < 2) { Error::typingError("Need more stuff to divide", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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::Equal: { ensuresame(children[0], children[1], "operator '=='"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(EQUAL); if (children.size() < 2) { Error::typingError("Need more stuff to equal", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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::Inequal: { ensuresame(children[0], children[1], "operator '!='"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(INEQUAL); if (children.size() < 2) { Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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::Greater: { ensuresame(children[0], children[1], "operator '>'"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(GREATER); if (children.size() < 2) { Error::typingError("Need more stuff to greater", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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::Lesser: { ensuresame(children[0], children[1], "operator '<'"); SolGroundCodeBlock codeBlock; outputId = "tmp_" + std::to_string(tmpIdIterator++); GroundInstruction gi = groundCreateInstruction(LESSER); if (children.size() < 2) { Error::typingError("Need more stuff to lesser", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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::EqGreater: { ensuresame(children[0], children[1], "operator '>='"); SolGroundCodeBlock codeBlock; if (children.size() < 2) { Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent); } 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, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); 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, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); 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, copyString(outputId))); 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, copyString(outputId))); groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false)); codeBlock.code.push_back(gi); // @end gi = groundCreateInstruction(CREATELABEL); groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId)); 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::EqLesser: { ensuresame(children[0], children[1], "operator '<='"); SolGroundCodeBlock codeBlock; if (children.size() < 2) { Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent); } 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, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); 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, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId))); 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, copyString(outputId))); 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, copyString(outputId))); groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false)); codeBlock.code.push_back(gi); // @end gi = groundCreateInstruction(CREATELABEL); groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId)); 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::Puts: { SolGroundCodeBlock codeBlock; exists(children[0]); GroundInstruction gi = groundCreateInstruction(PRINTLN); if (children.size() < 1) { Error::typingError("Need more stuff to puts", children[0].line, children[0].lineContent); } groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); codeBlock.code.push_back(gi); if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId); code.push_back(codeBlock); break; } case SolNodeType::If: { 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++); SolGroundCodeBlock codeBlock; codeBlock.toBeDropped.push_back(outputId); if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId); GroundInstruction gi = groundCreateInstruction(NOT); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); 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, copyString(outputId))); 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(); codeBlock.toBeDropped.clear(); 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"); 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); if (isTemp(children[0].outputId)) checkBlock.toBeDropped.push_back(children[0].outputId); GroundInstruction gi = groundCreateInstruction(NOT); groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId))); checkBlock.code.push_back(gi); GroundInstruction gi2 = groundCreateInstruction(IF); groundAddReferenceToInstruction(&gi2, groundCreateReference(VALREF, copyString(outputId))); 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: { if (variables.find(children[0].outputId) != variables.end()) { if (variables[children[0].outputId] != checkNodeReturnType(children[1])) { Error::typingError("Cannot change type of this variable", children[0].line, children[0].lineContent); } } exists(children[1]); SolGroundCodeBlock codeBlock; GroundInstruction setInstruction = groundCreateInstruction(SET); groundAddReferenceToInstruction(&setInstruction, groundCreateReference(DIRREF, copyString(children[0].outputId))); groundAddReferenceToInstruction(&setInstruction, groundCreateReference(VALREF, copyString(children[1].outputId))); codeBlock.code.push_back(setInstruction); 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] = checkNodeReturnType(children[1]); break; } case SolNodeType::FunctionCall: { checkNodeReturnType(*this); exists(children[0]); std::string fnToCall = children[0].outputId; outputId = "tmp_" + std::to_string(tmpIdIterator++); SolGroundCodeBlock codeBlock; GroundInstruction callInstruction = groundCreateInstruction(CALL); groundAddReferenceToInstruction(&callInstruction, groundCreateReference(FNREF, copyString(children[0].outputId))); for (int i = 1; i < children.size(); i++) { groundAddReferenceToInstruction(&callInstruction, groundCreateReference(VALREF, copyString(children[i].outputId))); } groundAddReferenceToInstruction(&callInstruction, groundCreateReference(DIRREF, copyString(outputId))); codeBlock.code.push_back(callInstruction); code.push_back(codeBlock); break; } case SolNodeType::Return: { 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); } SolGroundCodeBlock codeBlock; GroundInstruction returnInstruction = groundCreateInstruction(RETURN); groundAddReferenceToInstruction(&returnInstruction, groundCreateReference(VALREF, copyString(children[0].outputId))); 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)); // Scope Management auto variablebackup = variables; std::string oldRetType = currentFunctionRetType; variables.clear(); currentFunctionRetType = function.returnType; for (auto& pair : function.parameters) { groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, copyString(pair.second))); groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, copyString(pair.first))); variables[pair.first] = pair.second; // Correctly map Name -> Type } codeBlock.code.push_back(inst); code.push_back(codeBlock); codeBlock.code.clear(); // Generate body code with local variables visible auto childCode = function.content->generateCode(); code.insert(code.end(), childCode.begin(), childCode.end()); codeBlock.code.push_back(groundCreateInstruction(ENDFUN)); code.push_back(codeBlock); // Restore Scope variables = variablebackup; currentFunctionRetType = oldRetType; } break; } case SolNodeType::InlineGround: { GroundProgram program = groundParseFile(ground.c_str()); SolGroundCodeBlock codeBlock; for (size_t i = 0; i < program.size; i++) { codeBlock.code.push_back(program.instructions[i]); } code.push_back(codeBlock); break; } case SolNodeType::Struct: { //SolGroundCodeBlock preProcessCodeBlock; SolGroundCodeBlock codeBlock; GroundInstruction gi = groundCreateInstruction(STRUCT); // struct -name groundAddReferenceToInstruction(&gi, groundCreateReference(TYPEREF, copyString(outputId))); codeBlock.code.push_back(gi); // contents of struct for (SolNode& child : children) { if (child.nodeType == SolNodeType::Identifier) { gi = groundCreateInstruction(SET); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(child.outputId))); SolNode& valNode = child.children[0]; if (valNode.nodeType == SolNodeType::Value) { GroundValue gv; switch (valNode.data.type) { case SolDataType::String: gv = groundCreateValue(STRING, copyString(valNode.data.getString().value())); break; case SolDataType::Int: gv = groundCreateValue(INT, valNode.data.getInt().value()); break; case SolDataType::Double: gv = groundCreateValue(DOUBLE, valNode.data.getDouble().value()); break; case SolDataType::Char: gv = groundCreateValue(CHAR, valNode.data.getChar().value()); break; case SolDataType::Bool: gv = groundCreateValue(BOOL, valNode.data.getBool().value()); break; default: Error::syntaxError("Struct member must be assigned a value or identifier", valNode.line, valNode.lineContent); break; } groundAddValueToInstruction(&gi, gv); } else if (child.nodeType == SolNodeType::Identifier) { groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(valNode.outputId))); } else { Error::syntaxError("Struct member must be assigned a value or identifier", valNode.line, valNode.lineContent); } codeBlock.code.push_back(gi); } if (child.nodeType == SolNodeType::FunctionDef) { auto fnBlock = child.generateCode(); for (const auto& code : fnBlock) { codeBlock.code.insert(codeBlock.code.end(), code.code.begin(), code.code.end()); } } } codeBlock.code.push_back(groundCreateInstruction(ENDSTRUCT)); code.push_back(codeBlock); break; } default: {} } return code; } // Parser Implementation Parser::Parser(std::vector in) : tokensToParse(in) {} std::optional Parser::peek(int ahead) { if (current + ahead < size) { return tokensToParse[current + ahead]; } else { return {}; } } std::optional Parser::consume() { 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; } if (in == "-") { return SolNodeType::Subtract; } if (in == "*") { return SolNodeType::Multiply; } if (in == "/") { return SolNodeType::Divide; } if (in == "=" || in == ":") { return SolNodeType::Set; } if (in == "==") { return SolNodeType::Equal; } if (in == "!=") { return SolNodeType::Inequal; } if (in == ">=") { return SolNodeType::EqGreater; } if (in == "<=") { return SolNodeType::EqLesser; } if (in == ">") { return SolNodeType::Greater; } if (in == "<") { return SolNodeType::Lesser; } if (in == "puts") { return SolNodeType::Puts; } if (in == "if") { return SolNodeType::If; } if (in == "while") { return SolNodeType::While; } if (in == "def") { return SolNodeType::FunctionDef; } if (in == "return") { return SolNodeType::Return; } if (in == "ground") { return SolNodeType::InlineGround; } if (in == "struct") { return SolNodeType::Struct; } if (in == "new") { return SolNodeType::New; } if (in == "{") { return SolNodeType::CodeBlockStart; } if (in == "}") { return SolNodeType::CodeBlockEnd; } if (in == "(") { return SolNodeType::BracketStart; } if (in == ")") { return SolNodeType::BracketEnd; } return SolNodeType::Identifier; } 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) { Error::syntaxError("Unexpected end of input"); } Token tokenObj = tokenopt.value(); std::string token = tokenObj.value; SolNodeType type = getNodeType(token); if (type == SolNodeType::Value) { SolNode node(SolNodeType::Value); node.line = tokenObj.line; node.lineContent = tokenObj.lineContent; 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; idNode.line = tokenObj.line; idNode.lineContent = tokenObj.lineContent; auto peekOpt = peek(); if (peekOpt.has_value() && peekOpt.value().value == "(") { consume(); // ( SolNode fnCallNode(SolNodeType::FunctionCall); fnCallNode.line = tokenObj.line; fnCallNode.lineContent = tokenObj.lineContent; fnCallNode.addNode(idNode); std::vector tokens; size_t brackets = 1; while (auto t = consume()) { if (t.value().value == "(") brackets++; if (t.value().value == ")") brackets--; if (brackets == 0) break; tokens.push_back(t.value()); } if (brackets != 0) { Error::syntaxError("Unclosed function call bracket", tokenObj.line, tokenObj.lineContent); } auto args = Parser(tokens).parse(); for(auto& child : args.children) fnCallNode.addNode(child); return fnCallNode; } return idNode; } if (type == SolNodeType::BracketStart) { std::vector tokens; size_t brackets = 1; while (auto t = consume()) { if (t.value().value == "(") brackets++; if (t.value().value == ")") brackets--; if (brackets == 0) break; tokens.push_back(t.value()); } if (brackets != 0) { Error::syntaxError("Unclosed bracket", tokenObj.line, tokenObj.lineContent); } auto inner = Parser(tokens).parse(); if (inner.children.size() > 0) return inner.children[0]; return SolNode(SolNodeType::None); } Error::syntaxError("Unexpected token in expression: " + token, tokenObj.line, tokenObj.lineContent); return SolNode(SolNodeType::None); } SolNode Parser::parseExpression(int minPrec) { SolNode lhs = parsePrimary(); while(true) { auto opOpt = peek(); if (!opOpt) break; Token opToken = opOpt.value(); std::string op = opToken.value; int prec = getPrecedence(op); if (prec < minPrec) break; consume(); SolNode rhs = parseExpression(prec + 1); SolNode newNode(getNodeType(op)); newNode.line = opToken.line; newNode.lineContent = opToken.lineContent; newNode.addNode(lhs); newNode.addNode(rhs); lhs = newNode; } return lhs; } SolNode Parser::parse() { current = 0; size = tokensToParse.size(); SolNode rootNode(SolNodeType::Root); while (auto tokenopt = consume()) { Token tokenObj = tokenopt.value(); std::string token = tokenObj.value; switch (getNodeType(token)) { case SolNodeType::Value: { switch (getDataType(token)) { case SolDataType::Int: { SolNode intNode(SolNodeType::Value); intNode.setValue((int64_t) std::stoll(token)); intNode.line = tokenObj.line; intNode.lineContent = tokenObj.lineContent; rootNode.addNode(intNode); break; } case SolDataType::Double: { SolNode doubleNode(SolNodeType::Value); doubleNode.setValue(std::stod(token)); doubleNode.line = tokenObj.line; doubleNode.lineContent = tokenObj.lineContent; rootNode.addNode(doubleNode); break; } case SolDataType::String: { SolNode stringNode(SolNodeType::Value); stringNode.setValue(token.substr(1, token.size() - 2)); stringNode.line = tokenObj.line; stringNode.lineContent = tokenObj.lineContent; rootNode.addNode(stringNode); break; } case SolDataType::Char: { SolNode charNode(SolNodeType::Value); charNode.setValue(token[1]); charNode.line = tokenObj.line; charNode.lineContent = tokenObj.lineContent; rootNode.addNode(charNode); break; } case SolDataType::Bool: { SolNode boolNode(SolNodeType::Value); boolNode.setValue(token == "true"); boolNode.line = tokenObj.line; boolNode.lineContent = tokenObj.lineContent; rootNode.addNode(boolNode); break; } } break; } case SolNodeType::Add: case SolNodeType::Subtract: case SolNodeType::Multiply: case SolNodeType::Divide: { SolNode opNode(getNodeType(token)); opNode.line = tokenObj.line; opNode.lineContent = tokenObj.lineContent; if (rootNode.children.empty()) { Error::syntaxError("Expected operand before operator", tokenObj.line, tokenObj.lineContent); } 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); break; } case SolNodeType::Equal: case SolNodeType::Inequal: case SolNodeType::Lesser: case SolNodeType::Greater: case SolNodeType::EqLesser: case SolNodeType::EqGreater: { SolNode equalNode(getNodeType(token)); equalNode.line = tokenObj.line; equalNode.lineContent = tokenObj.lineContent; if (rootNode.children.empty()) { Error::syntaxError("Expected operand before comparison", tokenObj.line, tokenObj.lineContent); } equalNode.addNode(rootNode.children.back()); rootNode.children.pop_back(); std::vector tokens; while (auto tokenopt = consume()) { if (tokenopt.value().value == "\n") { break; } tokens.push_back(tokenopt.value()); } auto children = Parser(tokens).parse(); equalNode.addNode(children.children[0]); rootNode.addNode(equalNode); break; } case SolNodeType::Puts: { SolNode putsNode(SolNodeType::Puts); putsNode.line = tokenObj.line; putsNode.lineContent = tokenObj.lineContent; std::vector 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) { putsNode.addNode(child); } rootNode.addNode(putsNode); break; } case SolNodeType::If: { SolNode ifNode(SolNodeType::If); ifNode.line = tokenObj.line; ifNode.lineContent = tokenObj.lineContent; std::vector tokens; while (auto tokenopt = consume()) { if (tokenopt.value().value == "\n") { 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) { if (tokenopt.value().value == "{") { tokens.push_back(tokenopt.value()); while (auto tokenopt = consume()) { tokens.push_back(tokenopt.value()); if (tokenopt.value().value == "{") { brackets++; } if (tokenopt.value().value == "}") { brackets--; } if (brackets == 0) { break; } } if (brackets != 0) { Error::syntaxError("Unclosed code block", tokenopt.value().line, tokenopt.value().lineContent); } } else { Error::syntaxError("I want a code block instead of a " + tokenopt.value().value, tokenopt.value().line, tokenopt.value().lineContent); } } else { Error::syntaxError("Expected code block after if condition", ifNode.line, ifNode.lineContent); } auto childCodeBlock = Parser(tokens).parse(); ifNode.addNode(childCodeBlock.children[0]); rootNode.addNode(ifNode); break; } case SolNodeType::While: { SolNode whileNode(SolNodeType::While); whileNode.line = tokenObj.line; whileNode.lineContent = tokenObj.lineContent; std::vector tokens; while (auto tokenopt = consume()) { if (tokenopt.value().value == "\n") { 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) { if (tokenopt.value().value == "{") { tokens.push_back(tokenopt.value()); while (auto tokenopt = consume()) { tokens.push_back(tokenopt.value()); if (tokenopt.value().value == "{") { brackets++; } if (tokenopt.value().value == "}") { brackets--; } if (brackets == 0) { break; } } if (brackets != 0) { Error::syntaxError("Unclosed code block", tokenopt.value().line, tokenopt.value().lineContent); } } else { Error::syntaxError("I want a code block instead of a " + tokenopt.value().value, tokenopt.value().line, tokenopt.value().lineContent); } } else { Error::syntaxError("Expected code block after while condition", whileNode.line, whileNode.lineContent); } auto childCodeBlock = Parser(tokens).parse(); whileNode.addNode(childCodeBlock.children[0]); rootNode.addNode(whileNode); break; } case SolNodeType::CodeBlockStart: { SolNode codeBlockNode(SolNodeType::CodeBlock); codeBlockNode.line = tokenObj.line; codeBlockNode.lineContent = tokenObj.lineContent; size_t brackets = 1; std::vector tokens; while (auto tokenopt = consume()) { if (tokenopt.value().value == "{") { brackets++; } if (tokenopt.value().value == "}") { brackets--; } if (brackets == 0) { break; } tokens.push_back(tokenopt.value()); } if (brackets != 0) { Error::syntaxError("Unclosed code block", tokenObj.line, tokenObj.lineContent); } codeBlockNode.children = Parser(tokens).parse().children; rootNode.addNode(codeBlockNode); break; } case SolNodeType::Identifier: { SolNode idNode(SolNodeType::Identifier); idNode.outputId = token; idNode.line = tokenObj.line; idNode.lineContent = tokenObj.lineContent; rootNode.addNode(idNode); break; } case SolNodeType::Set: { SolNode setNode(SolNodeType::Set); setNode.line = tokenObj.line; setNode.lineContent = tokenObj.lineContent; setNode.addNode(rootNode.children.back()); rootNode.children.pop_back(); std::vector tokens; while (auto tokenopt = consume()) { if (tokenopt.value().value == "\n") { break; } tokens.push_back(tokenopt.value()); } auto children = Parser(tokens).parse(); setNode.addNode(children.children[0]); rootNode.addNode(setNode); break; } case SolNodeType::BracketStart: { // function call if (!rootNode.children.empty() && rootNode.children.back().nodeType == SolNodeType::Identifier) { SolNode fnCallNode(SolNodeType::FunctionCall); fnCallNode.line = tokenObj.line; fnCallNode.lineContent = tokenObj.lineContent; fnCallNode.addNode(rootNode.children.back()); rootNode.children.pop_back(); std::vector tokens; size_t brackets = 1; while (auto tokenopt = consume()) { if (tokenopt.value().value == "(") { brackets++; } if (tokenopt.value().value == ")") { brackets--; } // 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; } 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 { std::vector tokens; size_t brackets = 1; while (auto tokenopt = consume()) { if (tokenopt.value().value == "(") { brackets++; } if (tokenopt.value().value == ")") { brackets--; } if (brackets < 1) { break; } tokens.push_back(tokenopt.value()); } auto node = Parser(tokens).parse(); if (!node.children.empty()) { rootNode.addNode(node.children.back()); } } break; } 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); } 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 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(SolNodeType::CodeBlock); bodyNode->children = parsedBody.children; fn.content = bodyNode; SolNode fnNode(SolNodeType::FunctionDef); fnNode.data = SolData(fn); variables[fn.name] = signature; rootNode.addNode(fnNode); break; } case SolNodeType::Return: { SolNode returnNode(SolNodeType::Return); returnNode.line = tokenObj.line; returnNode.lineContent = tokenObj.lineContent; std::vector 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; } case SolNodeType::InlineGround: { SolNode groundNode(SolNodeType::InlineGround); consume(); // some funny token consume(); // { while (auto tokenopt = consume()) { if (tokenopt.value().value == "}") { break; } groundNode.ground += tokenopt.value().value + " "; } rootNode.addNode(groundNode); break; } case SolNodeType::Struct: { SolNode structNode(SolNodeType::Struct); structNode.line = tokenObj.line; structNode.lineContent = tokenObj.lineContent; auto nameopt = consume(); if (nameopt) { structNode.outputId = nameopt.value().value; } while (peek() && peek().value().value == "\n") { consume(); } auto openBrace = consume(); if (!openBrace || openBrace.value().value != "{") { Error::syntaxError("Expected '{' after struct name", tokenObj.line, tokenObj.lineContent); } std::vector tokens; int count = 1; while (auto tokenopt = consume()) { if (tokenopt.value().value == "{") { count++; } if (tokenopt.value().value == "}") { count--; } if (count < 1) { break; } tokens.push_back(tokenopt.value()); } if (count != 0) { Error::syntaxError("Unclosed struct body", tokenObj.line, tokenObj.lineContent); } for (size_t i = 0; i < tokens.size(); i++) { Token token = tokens[i]; if (token.value == "\n") { continue; } if (getNodeType(token.value) == SolNodeType::Identifier) { if (i + 2 >= tokens.size()) { Error::syntaxError("Expecting a value after the identifier", token.line, token.lineContent); continue; } if (getNodeType(tokens[i + 1].value) != SolNodeType::Set) { Error::syntaxError("Expected a set keyword ('=' or ':')", token.line, token.lineContent); continue; } if (getNodeType(tokens[i + 2].value) != SolNodeType::Identifier && getNodeType(tokens[i + 2].value) != SolNodeType::Value) { Error::syntaxError("Expected a value or identifier for default value", token.line, token.lineContent); continue; } SolNode idNode(SolNodeType::Identifier); idNode.outputId = token.value; idNode.line = token.line; idNode.lineContent = token.lineContent; SolNode valueNode = Parser({tokens[i + 2]}).parse().children[0]; idNode.addNode(valueNode); structNode.addNode(idNode); i += 2; continue; } else if (getNodeType(token.value) == SolNodeType::FunctionDef) { std::vector functionTokens; functionTokens.push_back(token); int funcCount = 0; i++; while (i < tokens.size()) { functionTokens.push_back(tokens[i]); if (tokens[i].value == "{") { funcCount++; } if (tokens[i].value == "}") { funcCount--; if (funcCount == 0) { break; } } i++; } if (funcCount != 0) { Error::syntaxError("Unclosed function in struct", token.line, token.lineContent); } SolNode functionNode = Parser(functionTokens).parse().children[0]; structNode.addNode(functionNode); } else { Error::syntaxError("Structs only support set statements and function definition", token.line, token.lineContent); } } rootNode.addNode(structNode); break; } case SolNodeType::New: { SolNode putsNode(SolNodeType::New); putsNode.line = tokenObj.line; putsNode.lineContent = tokenObj.lineContent; auto typeopt = consume(); rootNode.addNode(putsNode); break; } } } 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); char* droppedVar = (char*) malloc(tmpVar.size() + 1); strcpy(droppedVar, tmpVar.c_str()); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, droppedVar)); groundAddInstructionToProgram(&gp, gi); } } return gp; } } // namespace Parser }