diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 729ebd1..7c1bb8e 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -3,6 +3,7 @@ #include "SolsScope.h" #include +#include #include #include "../parser/SolsNode.h" @@ -207,6 +208,20 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) { case SNT_LAMBDA: { return Success(SolsType, charptr, node->as.type); } + case SNT_FUNCTION_CALL: { + SolsVariable* var = findSolsVariable(scope, node->as.idName); + if (var == NULL) { + Estr estr = CREATE_ESTR("Unable to find function "); + APPEND_ESTR(estr, node->as.idName); + return Error(SolsType, charptr, estr.str); + } + if (var->typeinfo.type != STT_FUN) { + Estr estr = CREATE_ESTR(node->as.idName); + APPEND_ESTR(estr, " is not a callable function"); + return Error(SolsType, charptr, estr.str); + } + return Success(SolsType, charptr, *var->typeinfo.returnType); + } } return Error(SolsType, charptr, "Not yet implemented"); } @@ -786,6 +801,59 @@ ResultType(GroundProgram, charptr) generateDefNode(SolsNode* node, SolsScope* sc return Success(GroundProgram, charptr, gp); } +ResultType(GroundProgram, charptr) generateFunctionCallNode(SolsNode* node, SolsScope* scope) { + + // Check whether the function exists and is callable + ResultType(SolsType, charptr) type = getNodeType(node, scope); + if (type.error) { + return Error(GroundProgram, charptr, type.as.error); + } + + SolsVariable* var = findSolsVariable(scope, node->as.idName); + if (var == NULL) { + return Error(GroundProgram, charptr, "Could not find variable"); + } + + // Ensure the argument types match the function types + if (node->children.count != var->typeinfo.children.count) { + return Error(GroundProgram, charptr, "Incorrect amount of arguments for function"); + } + + for (size_t i = 0; i < node->children.count; i++) { + ResultType(SolsType, charptr) type = getNodeType(&node->children.at[i], scope); + if (type.error) { + return Error(GroundProgram, charptr, type.as.error); + } + if (compareTypes(&type.as.success, &var->typeinfo.children.at[i].type) == false) { + return Error(GroundProgram, charptr, "Types incorrect for function call"); + } + } + + // Now that everything seems to be fine, call the function + GroundInstruction gi = groundCreateInstruction(CALL); + groundAddReferenceToInstruction(&gi, groundCreateReference(FNREF, node->as.idName)); + + for (size_t i = 0; i < node->children.count; i++) { + groundAddReferenceToInstruction(&gi, node->children.at[i].accessArg); + } + + char* returnStr = malloc(sizeof(char) * 64); + if (returnStr == NULL) { + return Error(GroundProgram, charptr, "Failed to allocate memory for tmp identifier"); + } + snprintf(returnStr, 64, "__SOLS_TMP_CALL_%zu", scope->tmpCounter++); + + groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, returnStr)); + + GroundProgram program = groundCreateProgram(); + groundAddInstructionToProgram(&program, gi); + + node->accessArg = groundCreateReference(VALREF, returnStr); + + return Success(GroundProgram, charptr, program); + +} + ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) { GroundProgram program = groundCreateProgram(); @@ -834,6 +902,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope case SNT_WHILE: generate(While); case SNT_LAMBDA: generate(Lambda); case SNT_DEF: generate(Def); + case SNT_FUNCTION_CALL: generate(FunctionCall); } return Success(GroundProgram, charptr, program); } diff --git a/src/parser/SolsNode.h b/src/parser/SolsNode.h index 8d83331..e9b75b6 100644 --- a/src/parser/SolsNode.h +++ b/src/parser/SolsNode.h @@ -11,7 +11,7 @@ #include "../lexer/SolsToken.h" typedef enum SolsNodeType { - SNT_IDENTIFIER, SNT_LITERAL, SNT_TYPE, SNT_CODE_BLOCK, SNT_OP_ADD, SNT_OP_SUB, SNT_OP_MUL, SNT_OP_DIV, SNT_OP_ADDTO, SNT_OP_SUBTO, SNT_OP_MULTO, SNT_OP_DIVTO, SNT_OP_INCREMENT, SNT_OP_DECREMENT, SNT_OP_SET, SNT_OP_GREATER, SNT_OP_LESSER, SNT_OP_EQUAL, SNT_OP_INEQUAL, SNT_OP_EQGREATER, SNT_OP_EQLESSER, SNT_DEF, SNT_LAMBDA, SNT_STRUCT, SNT_PUTS, SNT_IF, SNT_WHILE, SNT_NEW, SNT_GROUND, SNT_ROOT + SNT_IDENTIFIER, SNT_LITERAL, SNT_TYPE, SNT_CODE_BLOCK, SNT_OP_ADD, SNT_OP_SUB, SNT_OP_MUL, SNT_OP_DIV, SNT_OP_ADDTO, SNT_OP_SUBTO, SNT_OP_MULTO, SNT_OP_DIVTO, SNT_OP_INCREMENT, SNT_OP_DECREMENT, SNT_OP_SET, SNT_OP_GREATER, SNT_OP_LESSER, SNT_OP_EQUAL, SNT_OP_INEQUAL, SNT_OP_EQGREATER, SNT_OP_EQLESSER, SNT_DEF, SNT_LAMBDA, SNT_FUNCTION_CALL, SNT_STRUCT, SNT_PUTS, SNT_IF, SNT_WHILE, SNT_NEW, SNT_GROUND, SNT_ROOT } SolsNodeType; struct SolsNode; diff --git a/src/parser/parser.c b/src/parser/parser.c index 9119bc1..ac7170d 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1406,6 +1406,103 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) { return Success(Nothing, charptr, {}); } +static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser) { + + ResultType(SolsNode, charptr) node = createSolsNode(SNT_FUNCTION_CALL); + if (node.error) { + return Error(Nothing, charptr, node.as.error); + } + + ResultType(SolsToken, Nothing) idToken = parserPeek(parser, -1); + if (idToken.error) { + return Error(Nothing, charptr, "Couldn't get id token for some odd reason"); + } + + node.as.success.as.idName = idToken.as.success.as.idName; + + // create a node for each expression between commas + ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1); + if (peek.error) { + return Error(Nothing, charptr, "Expecting ')' or a value"); + } + SolsTokens tokens; + for (;;) { + ResultType(SolsTokens, charptr) resultTokens = createSolsTokens(); + if (resultTokens.error) { + return Error(Nothing, charptr, resultTokens.as.error); + } + tokens = resultTokens.as.success; + size_t curlys = 0; + size_t parens = 0; + for (;;) { + peek = parserPeek(parser, 1); + if (peek.error) { + return Error(Nothing, charptr, "Expecting ')'"); + } + if (peek.as.success.type == STT_OPEN_PAREN) { + parens++; + } + if (peek.as.success.type == STT_CLOSE_PAREN) { + if (parens == 0) { + break; + } + parens--; + } + if (peek.as.success.type == STT_OPEN_CURLY) { + curlys++; + } + if (peek.as.success.type == STT_CLOSE_CURLY) { + curlys--; + } + + if (curlys == 0 && parens == 0 && peek.as.success.type == STT_COMMA) { + break; + } + + addTokenToSolsTokens(&tokens, peek.as.success); + parserConsume(parser); + } + + ResultType(SolsParser, charptr) newParser = createSolsParser(&tokens); + if (newParser.error) { + return Error(Nothing, charptr, newParser.as.error); + } + newParser.as.success.currentParent = &newParser.as.success.output; + ResultType(Nothing, charptr) parsed = parse(&newParser.as.success); + if (parsed.error) { + addToParserErrors(parser, parsed.as.error); + return Success(Nothing, charptr, {}); + } + + if (newParser.as.success.output.children.count < 1) { + return Error(Nothing, charptr, "Expecting a value before ',' or ')'"); + } + addChildToSolsNode(&node.as.success, newParser.as.success.output.children.at[0]); + + peek = parserConsume(parser); + if (peek.error) { + return Error(Nothing, charptr, "Expecting ')' or ','"); + } + if (peek.as.success.type == STT_CLOSE_PAREN) { + break; + } + + addChildToSolsNode(parser->currentParent, node.as.success); + + } + + return Success(Nothing, charptr, {}); +} + +static inline ResultType(Nothing, charptr) parseOpenParen(SolsParser* parser) { + return Error(Nothing, charptr, "WIP"); +} + +static inline ResultType(Nothing, charptr) parseCloseParen(SolsParser* parser) { + (void)parser; + return Error(Nothing, charptr, "Extra closing parenthases"); +} + ResultType(Nothing, charptr) parse(SolsParser* parser) { parser->currentParent = &parser->output; for (;;) { @@ -1434,6 +1531,14 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) { case STT_OP_EQLESSER: PARSER_HANDLE(EqLesser); case STT_OPEN_CURLY: PARSER_HANDLE(CodeBlock); case STT_CLOSE_CURLY: PARSER_HANDLE(CloseCurly); + case STT_OPEN_PAREN: { + if (parser->output.children.count > 0 && parser->output.children.at[parser->output.children.count - 1].type == SNT_IDENTIFIER) { + PARSER_HANDLE(FunctionCall); + } else { + PARSER_HANDLE(OpenParen); + } + } + case STT_CLOSE_PAREN: PARSER_HANDLE(CloseParen); } } if (parser->errors.count > 0) {