Function definitions

This commit is contained in:
2026-02-28 20:27:47 +11:00
parent a434304e95
commit 955927e021
2 changed files with 196 additions and 1 deletions

View File

@@ -738,13 +738,61 @@ ResultType(GroundProgram, charptr) generateLambdaNode(SolsNode* node, SolsScope*
return Success(GroundProgram, charptr, gp); return Success(GroundProgram, charptr, gp);
} }
ResultType(GroundProgram, charptr) generateDefNode(SolsNode* node, SolsScope* scope) {
GroundProgram gp = groundCreateProgram();
// Generate function signature
GroundInstruction signature = groundCreateInstruction(FUN);
node->accessArg = groundCreateReference(VALREF, node->children.at[0].as.idName);
groundAddReferenceToInstruction(&signature, groundCreateReference(FNREF, node->children.at[0].as.idName));
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(node->as.type.returnType);
if (arg.error) {
return Error(GroundProgram, charptr, arg.as.error);
}
groundAddReferenceToInstruction(&signature, arg.as.success);
for (size_t i = 0; i < node->as.type.children.count; i++) {
// Add type
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&node->as.type.children.at[i].type);
if (arg.error) {
return Error(GroundProgram, charptr, arg.as.error);
}
groundAddReferenceToInstruction(&signature, arg.as.success);
// Add arg name
groundAddReferenceToInstruction(&signature, groundCreateReference(DIRREF, node->as.type.children.at[i].name));
}
groundAddInstructionToProgram(&gp, signature);
// Create a scope for function arguments
SolsScope functionScope = copySolsScope(scope);
for (size_t i = 0; i < node->as.type.children.count; i++) {
addVariableToScope(&functionScope, node->as.type.children.at[i].name, node->as.type.children.at[i].type);
}
// Generate children and add then to this program
ResultType(GroundProgram, charptr) bodyCode = generateCode(&node->children.at[1], &functionScope);
if (bodyCode.error) return bodyCode;
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));
return Success(GroundProgram, charptr, gp);
}
ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) { ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) {
GroundProgram program = groundCreateProgram(); GroundProgram program = groundCreateProgram();
SolsScope backupScope = {NULL, 0}; SolsScope backupScope = {NULL, 0};
if (node->type != SNT_IF && node->type != SNT_WHILE && node->type != SNT_LAMBDA) { if (node->type != SNT_IF && node->type != SNT_WHILE && node->type != SNT_LAMBDA && node->type != SNT_DEF) {
if (node->type == SNT_CODE_BLOCK) { if (node->type == SNT_CODE_BLOCK) {
backupScope = *scope; backupScope = *scope;
SolsScope newScope = copySolsScope(scope); SolsScope newScope = copySolsScope(scope);
@@ -785,6 +833,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
case SNT_IF: generate(If); case SNT_IF: generate(If);
case SNT_WHILE: generate(While); case SNT_WHILE: generate(While);
case SNT_LAMBDA: generate(Lambda); case SNT_LAMBDA: generate(Lambda);
case SNT_DEF: generate(Def);
} }
return Success(GroundProgram, charptr, program); return Success(GroundProgram, charptr, program);
} }

View File

@@ -1261,6 +1261,151 @@ static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) {
return Success(Nothing, charptr, {}); return Success(Nothing, charptr, {});
} }
static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
// Consume and validate the function name identifier
ResultType(SolsToken, Nothing) nameTok = parserConsume(parser);
if (nameTok.error || nameTok.as.success.type != STT_IDENTIFIER) {
return Error(Nothing, charptr, "Expecting function name after 'def'");
}
ResultType(SolsToken, Nothing) openBracket = parserConsume(parser);
if (openBracket.error || openBracket.as.success.type != STT_OPEN_PAREN) {
return Error(Nothing, charptr, "Expecting '(' after function name in 'def'");
}
ResultType(SolsType, charptr) type = createSolsType(STT_FUN);
if (type.error) {
return Error(Nothing, charptr, type.as.error);
}
ResultType(SolsNode, charptr) node = createSolsNode(SNT_DEF);
if (node.error) {
return Error(Nothing, charptr, node.as.error);
}
// Add function name as the first child node
ResultType(SolsNode, charptr) nameNode = createSolsNode(SNT_IDENTIFIER, nameTok.as.success.as.idName);
if (nameNode.error) {
return Error(Nothing, charptr, nameNode.as.error);
}
nameNode.as.success.line = nameTok.as.success.line;
nameNode.as.success.accessArg = (GroundArg) {
.type = VALREF,
.value.refName = nameTok.as.success.as.idName
};
addChildToSolsNode(&node.as.success, nameNode.as.success);
// Parse type signature
for (;;) {
ResultType(SolsToken, Nothing) next = parserPeek(parser, 1);
if (next.error) {
return Error(Nothing, charptr, "Expecting ')' at end of def argument list");
}
if (next.as.success.type == STT_CLOSE_PAREN) {
parserConsume(parser);
break;
}
if (type.error) {
return Error(Nothing, charptr, type.as.error);
}
// Pattern of type, name, comma
SolsType tmpType;
if (next.as.success.type == STT_TYPE) {
tmpType = next.as.success.as.type;
} else if (next.as.success.type == STT_IDENTIFIER) {
tmpType.identifierType = next.as.success.as.idName;
} else {
return Error(Nothing, charptr, "Expecting a type or identifier of type in def argument list");
}
parserConsume(parser);
char* argName;
next = parserPeek(parser, 1);
if (next.as.success.type == STT_IDENTIFIER) {
argName = next.as.success.as.idName;
} else {
return Error(Nothing, charptr, "Expecting identifier after type in def argument list");
}
// Add type to constructed SolsType
addChildToSolsType(&type.as.success, tmpType, argName);
parserConsume(parser);
next = parserPeek(parser, 1);
if (next.error) {
return Error(Nothing, charptr, "Expecting a comma or closing bracket");
}
if (next.as.success.type == STT_CLOSE_PAREN) {
parserConsume(parser);
break;
}
if (next.as.success.type != STT_COMMA) {
return Error(Nothing, charptr, "Expecting a comma or closing bracket");
}
parserConsume(parser);
}
// Parse return type after argument list
ResultType(SolsToken, Nothing) retType = parserPeek(parser, 1);
if (retType.error) {
return Error(Nothing, charptr, "Expecting return type or identifier of type after def argument list");
}
if (retType.as.success.type == STT_TYPE) {
type.as.success.returnType = malloc(sizeof(SolsType));
if (type.as.success.returnType == NULL) {
return Error(Nothing, charptr, "Failed to allocate memory for type");
}
*type.as.success.returnType = retType.as.success.as.type;
} else if (retType.as.success.type == STT_IDENTIFIER) {
type.as.success.returnType = malloc(sizeof(SolsType));
if (type.as.success.returnType == NULL) {
return Error(Nothing, charptr, "Failed to allocate memory for type");
}
type.as.success.returnType->identifierType = retType.as.success.as.idName;
} else {
return Error(Nothing, charptr, "Expecting return type or identifier of type after def argument list");
}
// Add type to node
node.as.success.as.type = type.as.success;
parserConsume(parser); // Consumes return type
// Skip newlines before the opening curly brace
while (parserPeek(parser, 1).as.success.type == STT_LINE_END) {
parserConsume(parser);
}
ResultType(SolsToken, Nothing) openCurly = parserConsume(parser);
if (openCurly.error || openCurly.as.success.type != STT_OPEN_CURLY) {
return Error(Nothing, charptr, "Expecting opening curly brace ({) for def body");
}
// Add node to parent
addChildToSolsNode(parser->currentParent, node.as.success);
// Parse code block
ResultType(Nothing, charptr) res = parseCodeBlock(parser);
if (res.error) return res;
// Last child of parent is code block, we need to move it
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
parser->currentParent->children.count--;
// We need to get the actual node from the parent to modify it
SolsNode* defNode = &parser->currentParent->children.at[parser->currentParent->children.count - 1];
addChildToSolsNode(defNode, codeBlock);
return Success(Nothing, charptr, {});
}
ResultType(Nothing, charptr) parse(SolsParser* parser) { ResultType(Nothing, charptr) parse(SolsParser* parser) {
parser->currentParent = &parser->output; parser->currentParent = &parser->output;
for (;;) { for (;;) {
@@ -1275,6 +1420,7 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) {
case STT_KW_IF: PARSER_HANDLE(If); case STT_KW_IF: PARSER_HANDLE(If);
case STT_KW_WHILE: PARSER_HANDLE(While); case STT_KW_WHILE: PARSER_HANDLE(While);
case STT_KW_LAMBDA: PARSER_HANDLE(Lambda); case STT_KW_LAMBDA: PARSER_HANDLE(Lambda);
case STT_KW_DEF: PARSER_HANDLE(Def);
case STT_OP_SET: PARSER_HANDLE(Set); case STT_OP_SET: PARSER_HANDLE(Set);
case STT_OP_ADD: PARSER_HANDLE(Add); case STT_OP_ADD: PARSER_HANDLE(Add);
case STT_OP_SUB: PARSER_HANDLE(Sub); case STT_OP_SUB: PARSER_HANDLE(Sub);