From bf71a0dfacab8f345876e43835f8ae403da34707 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sun, 1 Mar 2026 13:39:27 +1100 Subject: [PATCH] Function calling now works, only need return --- build.c | 2 +- src/codegen/codegen.c | 25 +++++++++++++++--- src/parser/parser.c | 59 ++++++++++++++++++++++++++----------------- 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/build.c b/build.c index 743e33e..f2af3d1 100755 --- a/build.c +++ b/build.c @@ -7,7 +7,7 @@ if [[ ! -v OUTPUT ]]; then fi if [[ ! -v CFLAGS ]]; then - CFLAGS="-O3 -Wall -Wextra -pedantic" + CFLAGS="-O3 -Wall -Wextra -pedantic -ggdb" fi gcc "$0" -o "$OUTPUT" $CFLAGS -lgroundvm diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 7c1bb8e..48768cb 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -756,12 +756,31 @@ ResultType(GroundProgram, charptr) generateLambdaNode(SolsNode* node, SolsScope* ResultType(GroundProgram, charptr) generateDefNode(SolsNode* node, SolsScope* scope) { GroundProgram gp = groundCreateProgram(); + // Register the function in the current scope so calls can resolve it + // node->children.at[0] is the identifier node for the function name + if (node->children.count < 2 || node->children.at[0].type != SNT_IDENTIFIER) { + return Error(GroundProgram, charptr, "Invalid def node shape (expected name + body)"); + } + + char* fnName = node->children.at[0].as.idName; + SolsVariable* existing = findSolsVariable(scope, fnName); + if (existing == NULL) { + addVariableToScope(scope, fnName, node->as.type); + } else { + if (existing->typeinfo.type != STT_FUN) { + return Error(GroundProgram, charptr, "A non-function variable already exists with this name"); + } + if (compareTypes(&existing->typeinfo, &node->as.type) == false) { + return Error(GroundProgram, charptr, "Function already exists with a different type signature"); + } + } + // Generate function signature GroundInstruction signature = groundCreateInstruction(FUN); - node->accessArg = groundCreateReference(VALREF, node->children.at[0].as.idName); + node->accessArg = groundCreateReference(VALREF, fnName); - groundAddReferenceToInstruction(&signature, groundCreateReference(FNREF, node->children.at[0].as.idName)); + groundAddReferenceToInstruction(&signature, groundCreateReference(FNREF, fnName)); ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(node->as.type.returnType); if (arg.error) { return Error(GroundProgram, charptr, arg.as.error); @@ -794,7 +813,7 @@ ResultType(GroundProgram, charptr) generateDefNode(SolsNode* node, SolsScope* sc for (size_t i = 0; i < bodyCode.as.success.size; i++) { groundAddInstructionToProgram(&gp, bodyCode.as.success.instructions[i]); } - + // End the function groundAddInstructionToProgram(&gp, groundCreateInstruction(ENDFUN)); diff --git a/src/parser/parser.c b/src/parser/parser.c index ac7170d..08c840e 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1407,53 +1407,60 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) { } 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"); + // The identifier (function name) was already parsed as a node right before '(' + if (parser->currentParent->children.count < 1 || + parser->currentParent->children.at[parser->currentParent->children.count - 1].type != SNT_IDENTIFIER) { + return Error(Nothing, charptr, "Expecting identifier before '(' for function call"); } - node.as.success.as.idName = idToken.as.success.as.idName; + SolsNode callee = parser->currentParent->children.at[parser->currentParent->children.count - 1]; + parser->currentParent->children.count--; // remove callee identifier node; we'll replace it with the call node - // create a node for each expression between commas + node.as.success.as.idName = callee.as.idName; + node.as.success.line = callee.line; + + // Empty argument list: foo() ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1); if (peek.error) { return Error(Nothing, charptr, "Expecting ')' or a value"); } - SolsTokens tokens; + if (peek.as.success.type == STT_CLOSE_PAREN) { + parserConsume(parser); // consume ')' + addChildToSolsNode(parser->currentParent, node.as.success); + return Success(Nothing, charptr, {}); + } + + // Parse each argument expression separated by commas until ')' for (;;) { ResultType(SolsTokens, charptr) resultTokens = createSolsTokens(); if (resultTokens.error) { return Error(Nothing, charptr, resultTokens.as.error); } - tokens = resultTokens.as.success; + SolsTokens 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_OPEN_PAREN) parens++; if (peek.as.success.type == STT_CLOSE_PAREN) { - if (parens == 0) { - break; - } + if (parens == 0) break; parens--; } - if (peek.as.success.type == STT_OPEN_CURLY) { - curlys++; - } - if (peek.as.success.type == STT_CLOSE_CURLY) { - curlys--; - } + + 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; @@ -1468,6 +1475,7 @@ static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser) 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); @@ -1477,8 +1485,11 @@ static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser) if (newParser.as.success.output.children.count < 1) { return Error(Nothing, charptr, "Expecting a value before ',' or ')'"); } + + // One argument expression -> one AST node addChildToSolsNode(&node.as.success, newParser.as.success.output.children.at[0]); + // Consume ',' or ')' peek = parserConsume(parser); if (peek.error) { return Error(Nothing, charptr, "Expecting ')' or ','"); @@ -1486,11 +1497,13 @@ static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser) if (peek.as.success.type == STT_CLOSE_PAREN) { break; } - - addChildToSolsNode(parser->currentParent, node.as.success); - + if (peek.as.success.type != STT_COMMA) { + return Error(Nothing, charptr, "Expecting ',' or ')'"); + } } + // Add the fully-built call node once + addChildToSolsNode(parser->currentParent, node.as.success); return Success(Nothing, charptr, {}); }