#include "codegen.h" #include "SolsScope.h" #include #include "../parser/SolsNode.h" #include "../include/estr.h" #include "../include/uthash.h" // FIXME add proper erroring function char* createCodegenError(char* what) { Estr estr = CREATE_ESTR(what); APPEND_ESTR(estr, "\nthats an error"); return estr.str; } ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) { switch (node->type) { case SNT_PUTS: { return Error(SolsType, charptr, "Specified node does not return data"); } case SNT_OP_SET: { if (node->children.count < 2) { return Error(SolsType, charptr, "Not enough children to determine type"); } ResultType(SolsType, charptr) type = getNodeType(&node->children.at[0], scope); if (type.error) { return Error(SolsType, charptr, type.as.error); } return Success(SolsType, charptr, type.as.success); } case SNT_LITERAL: { switch (node->as.literal.type) { case SLT_INT: { return Success(SolsType, charptr, {STT_INT}); } case SLT_DOUBLE: { return Success(SolsType, charptr, {STT_DOUBLE}); } case SLT_STRING: { return Success(SolsType, charptr, {STT_STRING}); } case SLT_BOOL: { return Success(SolsType, charptr, {STT_BOOL}); } case SLT_CHAR: { return Success(SolsType, charptr, {STT_CHAR}); } } break; } case SNT_IDENTIFIER: { SolsVariable* var = findSolsVariable(scope, node->as.idName); if (var == NULL) { Estr estr = CREATE_ESTR("Unable to find variable "); APPEND_ESTR(estr, node->as.idName); return Error(SolsType, charptr, estr.str); } return Success(SolsType, charptr, var->typeinfo); } } return Error(SolsType, charptr, "Not yet implemented"); } static inline ResultType(GroundProgram, charptr) generateLiteralNode(SolsNode* node, SolsScope* scope) { // We don't even need to do anything lmao return Success(GroundProgram, charptr, groundCreateProgram()); } static inline ResultType(GroundProgram, charptr) generatePutsNode(SolsNode* node, SolsScope* scope) { if (node->children.count < 1) { return Error(GroundProgram, charptr, "puts requires arguments"); } GroundInstruction inst = groundCreateInstruction(PRINTLN); for (size_t i = 0; i < node->children.count; i++) { groundAddReferenceToInstruction(&inst, node->children.at[i].accessArg); } GroundProgram program = groundCreateProgram(); groundAddInstructionToProgram(&program, inst); return Success(GroundProgram, charptr, program); } static inline ResultType(GroundProgram, charptr) generateSetNode(SolsNode* node, SolsScope* scope) { if (node->children.count < 2) { return Error(GroundProgram, charptr, "set requires arguments"); } if (node->children.at[0].type != SNT_IDENTIFIER) { return Error(GroundProgram, charptr, "set requires an identifier before '='"); } SolsVariable* var = findSolsVariable(scope, node->as.idName); ResultType(SolsType, charptr) type = getNodeType(&node->children.at[1], scope); if (type.error) { return Error(GroundProgram, charptr, type.as.error); } if (var == NULL) { addVariableToScope(scope, node->children.at[0].as.idName, type.as.success); } else { ResultType(SolsType, charptr) type = getNodeType(&node->children.at[0], scope); if (type.error) { return Error(GroundProgram, charptr, type.as.error); } if (compareTypes(&var->typeinfo, &type.as.success) == false) { return Error(GroundProgram, charptr, "Type of variable cannot be changed"); } } addVariableToScope(scope, node->children.at[0].as.idName, type.as.success); GroundProgram gp = groundCreateProgram(); GroundInstruction gi = groundCreateInstruction(SET); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, node->children.at[0].as.idName)); groundAddReferenceToInstruction(&gi, node->children.at[1].accessArg); groundAddInstructionToProgram(&gp, gi); return Success(GroundProgram, charptr, gp); } ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) { GroundProgram program = groundCreateProgram(); // Generate code for all children before generating this node's code for (size_t i = 0; i < node->children.count; i++) { ResultType(GroundProgram, charptr) generated = generateCode(&node->children.at[i], scope); if (generated.error) { return Error(GroundProgram, charptr, createCodegenError(generated.as.error)); } for (size_t j = 0; j < generated.as.success.size; j++) { groundAddInstructionToProgram(&program, generated.as.success.instructions[j]); } } // Now generate code for this node switch (node->type) { case SNT_PUTS: generate(Puts); case SNT_LITERAL: generate(Literal); case SNT_OP_SET: generate(Set); } return Success(GroundProgram, charptr, program); }