Function calling now works, only need return

This commit is contained in:
2026-03-01 13:39:27 +11:00
parent dc09883e46
commit bf71a0dfac
3 changed files with 59 additions and 27 deletions

View File

@@ -7,7 +7,7 @@ if [[ ! -v OUTPUT ]]; then
fi fi
if [[ ! -v CFLAGS ]]; then if [[ ! -v CFLAGS ]]; then
CFLAGS="-O3 -Wall -Wextra -pedantic" CFLAGS="-O3 -Wall -Wextra -pedantic -ggdb"
fi fi
gcc "$0" -o "$OUTPUT" $CFLAGS -lgroundvm gcc "$0" -o "$OUTPUT" $CFLAGS -lgroundvm

View File

@@ -756,12 +756,31 @@ ResultType(GroundProgram, charptr) generateLambdaNode(SolsNode* node, SolsScope*
ResultType(GroundProgram, charptr) generateDefNode(SolsNode* node, SolsScope* scope) { ResultType(GroundProgram, charptr) generateDefNode(SolsNode* node, SolsScope* scope) {
GroundProgram gp = groundCreateProgram(); 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 // Generate function signature
GroundInstruction signature = groundCreateInstruction(FUN); 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); ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(node->as.type.returnType);
if (arg.error) { if (arg.error) {
return Error(GroundProgram, charptr, arg.as.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++) { for (size_t i = 0; i < bodyCode.as.success.size; i++) {
groundAddInstructionToProgram(&gp, bodyCode.as.success.instructions[i]); groundAddInstructionToProgram(&gp, bodyCode.as.success.instructions[i]);
} }
// End the function // End the function
groundAddInstructionToProgram(&gp, groundCreateInstruction(ENDFUN)); groundAddInstructionToProgram(&gp, groundCreateInstruction(ENDFUN));

View File

@@ -1407,53 +1407,60 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
} }
static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser) { static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser) {
ResultType(SolsNode, charptr) node = createSolsNode(SNT_FUNCTION_CALL); ResultType(SolsNode, charptr) node = createSolsNode(SNT_FUNCTION_CALL);
if (node.error) { if (node.error) {
return Error(Nothing, charptr, node.as.error); return Error(Nothing, charptr, node.as.error);
} }
ResultType(SolsToken, Nothing) idToken = parserPeek(parser, -1); // The identifier (function name) was already parsed as a node right before '('
if (idToken.error) { if (parser->currentParent->children.count < 1 ||
return Error(Nothing, charptr, "Couldn't get id token for some odd reason"); 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); ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
if (peek.error) { if (peek.error) {
return Error(Nothing, charptr, "Expecting ')' or a value"); 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 (;;) { for (;;) {
ResultType(SolsTokens, charptr) resultTokens = createSolsTokens(); ResultType(SolsTokens, charptr) resultTokens = createSolsTokens();
if (resultTokens.error) { if (resultTokens.error) {
return Error(Nothing, charptr, resultTokens.as.error); return Error(Nothing, charptr, resultTokens.as.error);
} }
tokens = resultTokens.as.success; SolsTokens tokens = resultTokens.as.success;
size_t curlys = 0; size_t curlys = 0;
size_t parens = 0; size_t parens = 0;
for (;;) { for (;;) {
peek = parserPeek(parser, 1); peek = parserPeek(parser, 1);
if (peek.error) { if (peek.error) {
return Error(Nothing, charptr, "Expecting ')'"); 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 (peek.as.success.type == STT_CLOSE_PAREN) {
if (parens == 0) { if (parens == 0) break;
break;
}
parens--; parens--;
} }
if (peek.as.success.type == STT_OPEN_CURLY) {
curlys++; if (peek.as.success.type == STT_OPEN_CURLY) curlys++;
} if (peek.as.success.type == STT_CLOSE_CURLY) curlys--;
if (peek.as.success.type == STT_CLOSE_CURLY) {
curlys--;
}
if (curlys == 0 && parens == 0 && peek.as.success.type == STT_COMMA) { if (curlys == 0 && parens == 0 && peek.as.success.type == STT_COMMA) {
break; break;
@@ -1468,6 +1475,7 @@ static inline ResultType(Nothing, charptr) parseFunctionCall(SolsParser* parser)
return Error(Nothing, charptr, newParser.as.error); return Error(Nothing, charptr, newParser.as.error);
} }
newParser.as.success.currentParent = &newParser.as.success.output; newParser.as.success.currentParent = &newParser.as.success.output;
ResultType(Nothing, charptr) parsed = parse(&newParser.as.success); ResultType(Nothing, charptr) parsed = parse(&newParser.as.success);
if (parsed.error) { if (parsed.error) {
addToParserErrors(parser, parsed.as.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) { if (newParser.as.success.output.children.count < 1) {
return Error(Nothing, charptr, "Expecting a value before ',' or ')'"); 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]); addChildToSolsNode(&node.as.success, newParser.as.success.output.children.at[0]);
// Consume ',' or ')'
peek = parserConsume(parser); peek = parserConsume(parser);
if (peek.error) { if (peek.error) {
return Error(Nothing, charptr, "Expecting ')' or ','"); 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) { if (peek.as.success.type == STT_CLOSE_PAREN) {
break; break;
} }
if (peek.as.success.type != STT_COMMA) {
addChildToSolsNode(parser->currentParent, node.as.success); return Error(Nothing, charptr, "Expecting ',' or ')'");
}
} }
// Add the fully-built call node once
addChildToSolsNode(parser->currentParent, node.as.success);
return Success(Nothing, charptr, {}); return Success(Nothing, charptr, {});
} }