diff --git a/src/parser.cpp b/src/parser.cpp index 8fac2c8..6cc29cf 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -204,561 +204,561 @@ namespace Solstice { std::string currentFunctionRetType = ""; const std::vector SolNode::generateCode() { - std::vector 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; + std::vector 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())); } - 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, 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::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, 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::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, 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 '/'"); - 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, 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::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, 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::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, 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::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, 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::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, 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::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, 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); - 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, 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); - 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, children[0].outputId.data())); - 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, 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(); - 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, 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: { - 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, children[0].outputId.data())); - groundAddReferenceToInstruction(&setInstruction, groundCreateReference(VALREF, children[1].outputId.data())); - 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); - // Take care of in built functions - // This will be removed when inline ground is added - if (children[0].outputId == "input") { - ensure(children[1], "string", "input function argument"); - SolGroundCodeBlock inputCodeBlock; - if (children.size() > 1) { - GroundInstruction printInstruction = groundCreateInstruction(PRINT); - groundAddReferenceToInstruction(&printInstruction, groundCreateReference(VALREF, children[1].outputId.data())); - inputCodeBlock.code.push_back(printInstruction); - if (isTemp(children[1].outputId)) inputCodeBlock.toBeDropped.push_back(children[1].outputId); - } - 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; } - 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, 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: { - 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, 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)); - - // Scope Management - auto variablebackup = variables; - std::string oldRetType = currentFunctionRetType; - - variables.clear(); - currentFunctionRetType = function.returnType; - - for (auto& pair : function.parameters) { - groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, pair.second.data())); - groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, pair.first.data())); - variables[pair.first] = pair.second; // Correctly map Name -> Type + case SolDataType::Double: { + auto dataopt = data.getDouble(); + if (dataopt) { + groundAddValueToInstruction(&gi, groundCreateValue(DOUBLE, dataopt.value())); } - - 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; } - 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]); + 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; } - code.push_back(codeBlock); - break; } - default: {} + codeBlock.code.push_back(gi); + code.push_back(codeBlock); + break; } - return code; + 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, 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::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, 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::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, 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 '/'"); + 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, 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::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, 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::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, 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::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, 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::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, 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::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, 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); + 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, 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); + 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, children[0].outputId.data())); + 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, 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(); + 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, 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: { + 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, children[0].outputId.data())); + groundAddReferenceToInstruction(&setInstruction, groundCreateReference(VALREF, children[1].outputId.data())); + 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); + // Take care of in built functions + // This will be removed when inline ground is added + if (children[0].outputId == "input") { + ensure(children[1], "string", "input function argument"); + SolGroundCodeBlock inputCodeBlock; + if (children.size() > 1) { + GroundInstruction printInstruction = groundCreateInstruction(PRINT); + groundAddReferenceToInstruction(&printInstruction, groundCreateReference(VALREF, children[1].outputId.data())); + inputCodeBlock.code.push_back(printInstruction); + if (isTemp(children[1].outputId)) inputCodeBlock.toBeDropped.push_back(children[1].outputId); + } + 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; + } + 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, 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: { + 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, 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)); + + // Scope Management + auto variablebackup = variables; + std::string oldRetType = currentFunctionRetType; + + variables.clear(); + currentFunctionRetType = function.returnType; + + for (auto& pair : function.parameters) { + groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, pair.second.data())); + groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, pair.first.data())); + 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; + } + default: {} + } + return code; } // Parser Implementation