Function definitions
This commit is contained in:
@@ -738,13 +738,61 @@ ResultType(GroundProgram, charptr) generateLambdaNode(SolsNode* node, SolsScope*
|
||||
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) {
|
||||
|
||||
GroundProgram program = groundCreateProgram();
|
||||
|
||||
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) {
|
||||
backupScope = *scope;
|
||||
SolsScope newScope = copySolsScope(scope);
|
||||
@@ -785,6 +833,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
|
||||
case SNT_IF: generate(If);
|
||||
case SNT_WHILE: generate(While);
|
||||
case SNT_LAMBDA: generate(Lambda);
|
||||
case SNT_DEF: generate(Def);
|
||||
}
|
||||
return Success(GroundProgram, charptr, program);
|
||||
}
|
||||
|
||||
@@ -1261,6 +1261,151 @@ static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) {
|
||||
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) {
|
||||
parser->currentParent = &parser->output;
|
||||
for (;;) {
|
||||
@@ -1275,6 +1420,7 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) {
|
||||
case STT_KW_IF: PARSER_HANDLE(If);
|
||||
case STT_KW_WHILE: PARSER_HANDLE(While);
|
||||
case STT_KW_LAMBDA: PARSER_HANDLE(Lambda);
|
||||
case STT_KW_DEF: PARSER_HANDLE(Def);
|
||||
case STT_OP_SET: PARSER_HANDLE(Set);
|
||||
case STT_OP_ADD: PARSER_HANDLE(Add);
|
||||
case STT_OP_SUB: PARSER_HANDLE(Sub);
|
||||
|
||||
Reference in New Issue
Block a user