From a2fc138ba1967d6e5224e62ce85f8e4d2060ba48 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Thu, 9 Apr 2026 19:00:40 +1000 Subject: [PATCH] 'new' keyword --- src/codegen/codegen.c | 54 ++++++++++++++++++++++++++++++++++++++----- src/lexer/SolsType.c | 47 +++++++++++++++++++++++++++++++++---- src/lexer/SolsType.h | 16 +++++++++++-- src/lexer/lexer.c | 1 + src/parser/parser.c | 27 ++++++++++++++++++---- 5 files changed, 129 insertions(+), 16 deletions(-) diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 6c3efdf..84c1f55 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -41,7 +41,8 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) { case SNT_PUTS: case SNT_IF: case SNT_WHILE: - case SNT_CODE_BLOCK: + case SNT_CODE_BLOCK: + case SNT_STRUCT: case SNT_RETURN: { return Error(SolsType, charptr, "Specified node does not return data"); } @@ -229,6 +230,25 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) { case SNT_EXPR_IN_PAREN: { return getNodeType(&node->children.at[node->children.count - 1], scope); } + case SNT_NEW: { + SolsType type; + if (node->as.type.typeIsKnown) { + type = node->as.type; + } else { + SolsVariable* var = findSolsVariable(scope, node->as.type.identifierType); + if (var == NULL) { + Estr estr = CREATE_ESTR("Unable to find variable "); + APPEND_ESTR(estr, node->as.type.identifierType); + return Error(SolsType, charptr, estr.str); + } + type = var->typeinfo; + } + if (type.type == STT_OBJECT) { + return Error(SolsType, charptr, "Cannot use initialized type on new"); + } + type.type = STT_OBJECT; + return Success(SolsType, charptr, type); + } } return Error(SolsType, charptr, "Not yet implemented"); } @@ -724,14 +744,14 @@ ResultType(GroundProgram, charptr) generateLambdaNode(SolsNode* node, SolsScope* node->accessArg = groundCreateReference(VALREF, lambdaId); groundAddReferenceToInstruction(&signature, groundCreateReference(FNREF, lambdaId)); - ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(node->as.type.returnType); + ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(node->as.type.returnType, scope); 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); + ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&node->as.type.children.at[i].type, scope); if (arg.error) { return Error(GroundProgram, charptr, arg.as.error); } @@ -793,14 +813,14 @@ ResultType(GroundProgram, charptr) generateDefNode(SolsNode* node, SolsScope* sc node->accessArg = groundCreateReference(VALREF, fnName); groundAddReferenceToInstruction(&signature, groundCreateReference(FNREF, fnName)); - ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(node->as.type.returnType); + ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(node->as.type.returnType, scope); 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); + ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&node->as.type.children.at[i].type, scope); if (arg.error) { return Error(GroundProgram, charptr, arg.as.error); } @@ -1035,13 +1055,34 @@ ResultType(GroundProgram, charptr) generateStructNode(SolsNode* node, SolsScope* return Success(GroundProgram, charptr, constants); } +ResultType(GroundProgram, charptr) generateNewNode(SolsNode* node, SolsScope* scope) { + GroundProgram program = groundCreateProgram(); + GroundInstruction inst = groundCreateInstruction(INIT); + ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&node->as.type, scope); + if (arg.error) { + return Error(GroundProgram, charptr, arg.as.error); + } + char* tmpId = malloc(sizeof(char) * 64); + if (tmpId == NULL) { + return Error(GroundProgram, charptr, "Failed to allocate memory for tmp identifier"); + } + snprintf(tmpId, 64, "__SOLS_TMP_NEW_%zu", scope->tmpCounter++); + node->accessArg = groundCreateReference(VALREF, tmpId); + groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, tmpId)); + groundAddReferenceToInstruction(&inst, arg.as.success); + groundAddInstructionToProgram(&program, inst); + return Success(GroundProgram, charptr, program); +} + + 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 && node->type != SNT_DEF && node->type != SNT_STRUCT) { + if (node->type != SNT_IF && node->type != SNT_WHILE && node->type != SNT_LAMBDA && + node->type != SNT_DEF && node->type != SNT_STRUCT && node->type != SNT_NEW) { if (node->type == SNT_CODE_BLOCK) { backupScope = *scope; SolsScope newScope = copySolsScope(scope); @@ -1089,6 +1130,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope case SNT_USE: generate(Use); case SNT_GROUND: generate(InlineGround); case SNT_STRUCT: generate(Struct); + case SNT_NEW: generate(New); } return Success(GroundProgram, charptr, program); } diff --git a/src/lexer/SolsType.c b/src/lexer/SolsType.c index e77fb36..a868551 100644 --- a/src/lexer/SolsType.c +++ b/src/lexer/SolsType.c @@ -10,10 +10,37 @@ ResultType(SolsType, charptr) createSolsType(SolsTypeType in) { if (ptr == NULL) { return Error(SolsType, charptr, "Couldn't allocate memory (in createSolsType() function)"); } - SolsType type = { .type = in, .children.capacity = 32, .children.at = ptr }; + SolsType type = { + .type = in, + .identifierType = NULL, + .returnType = NULL, + .children.capacity = 32, + .children.count = 0, + .children.at = ptr, + .typeIsKnown = true, + .needsGroundStruct = false + }; return Success(SolsType, charptr, type); } +ResultType(SolsType, charptr) createIdentifiedSolsType(char* in) { + char* copy = malloc(strlen(in) + 1); + if (copy == NULL) { + return Error(SolsType, charptr, "Couldn't allocate memory (in createIdentifiedSolsType() function)"); + } + strcpy(copy, in); + return Success(SolsType, charptr, ((SolsType) { + .type = STT_UNKNOWN, + .identifierType = copy, + .returnType = NULL, + .children.capacity = 0, + .children.count = 0, + .children.at = NULL, + .typeIsKnown = false, + .needsGroundStruct = false + })); +} + ResultType(SolsType, charptr) copySolsType(SolsType* type) { SolsType ret = { .type = type->type, .children.count = type->children.count, .children.capacity = type->children.capacity}; @@ -144,7 +171,7 @@ bool compareTypes(SolsType* left, SolsType* right) { } } -ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type) { +ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type, struct SolsScope* scope) { switch (type->type) { case STT_INT: { return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "int")); @@ -168,8 +195,20 @@ ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type) { return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "struct")); } case STT_OBJECT: { - // FIXME Do this later - return Error(GroundArg, charptr, "FIXME"); + if (!type->needsGroundStruct) { + return Success(GroundArg, charptr, groundCreateReference(TYPEREF, type->identifierType)); + } else { + // FIXME do this later + return Error(GroundArg, charptr, "Anonymous structs are not supported yet"); + } + } + case STT_UNKNOWN: { + if (!type->needsGroundStruct) { + return Success(GroundArg, charptr, groundCreateReference(TYPEREF, type->identifierType)); + } else { + // FIXME do this later + return Error(GroundArg, charptr, "Anonymous structs are not supported yet"); + } } } return Error(GroundArg, charptr, "How did we get here?"); diff --git a/src/lexer/SolsType.h b/src/lexer/SolsType.h index 0194c0d..0a76f1d 100644 --- a/src/lexer/SolsType.h +++ b/src/lexer/SolsType.h @@ -8,7 +8,7 @@ #include "../include/nothing.h" typedef enum SolsTypeType { - STT_INT, STT_STRING, STT_DOUBLE, STT_BOOL, STT_CHAR, STT_FUN, STT_TEMPLATE, STT_OBJECT + STT_INT, STT_STRING, STT_DOUBLE, STT_BOOL, STT_CHAR, STT_FUN, STT_TEMPLATE, STT_OBJECT, STT_UNKNOWN } SolsTypeType; // Definition of charptr for Result() and ResultType() macros @@ -53,6 +53,12 @@ typedef struct SolsType { // For use when type is identified with a name char* identifierType; + // If type is identified with a name, record whether we have found the actual type + bool typeIsKnown; + + // If using anonymous struct, record whether we need to generate a Ground struct + bool needsGroundStruct; + // For use in functions struct SolsType* returnType; @@ -80,6 +86,10 @@ Result(SolsType, charptr); // Failure: char* detailing what went wrong (usually memory failure) ResultType(SolsType, charptr) createSolsType(SolsTypeType in); +// Creates a SolsType which is identified by a name. +// The type details are not known yet, so the type is marked as unknown. +ResultType(SolsType, charptr) createIdentifiedSolsType(char* in); + Result(Nothing, charptr); // Adds a child SolsType to a given SolsType. @@ -93,8 +103,10 @@ ResultType(SolsType, charptr) copySolsType(SolsType* type); Result(GroundArg, charptr); +struct SolsScope; + // Represents a SolsType as a GroundArg (in typeref form) -ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type); +ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type, struct SolsScope* scope); // Frees a SolsType void freeSolsType(SolsType* type); diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index babcb45..387dfff 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -16,6 +16,7 @@ struct _SolsTokenTypeMap SolsTokenTypeMap[] = { {"use", STT_KW_USE}, {"struct", STT_KW_STRUCT}, {"ground", STT_KW_GROUND}, + {"new", STT_KW_NEW}, {"{", STT_OPEN_CURLY}, {"}", STT_CLOSE_CURLY}, {"(", STT_OPEN_PAREN}, diff --git a/src/parser/parser.c b/src/parser/parser.c index e489004..ff194ce 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1193,7 +1193,7 @@ static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) { 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; + tmpType = createIdentifiedSolsType(next.as.success.as.idName).as.success; } else { return Error(Nothing, charptr, "Expecting a type or identifier of type in lambda argument list"); } @@ -1244,7 +1244,7 @@ static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) { 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; + *type.as.success.returnType = createIdentifiedSolsType(retType.as.success.as.idName).as.success; } else { return Error(Nothing, charptr, "Expecting return type or identifier of type after lambda argument list"); } @@ -1338,7 +1338,7 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) { 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; + tmpType = createIdentifiedSolsType(next.as.success.as.idName).as.success; } else { return Error(Nothing, charptr, "Expecting a type or identifier of type in def argument list"); } @@ -1389,7 +1389,7 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) { 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; + *type.as.success.returnType = createIdentifiedSolsType(retType.as.success.as.idName).as.success; } else { return Error(Nothing, charptr, "Expecting return type or identifier of type after def argument list"); } @@ -1805,6 +1805,24 @@ static inline ResultType(Nothing, charptr) parseStruct(SolsParser* parser) { return Success(Nothing, charptr, {}); } +ResultType(Nothing, charptr) parseNew(SolsParser* parser) { + ResultType(SolsNode, charptr) newNode = createSolsNode(SNT_NEW); + if (newNode.error) { + return Error(Nothing, charptr, newNode.as.error); + } + ResultType(SolsToken, Nothing) nameTok = parserConsume(parser); + if (nameTok.error || !(nameTok.as.success.type == STT_IDENTIFIER || nameTok.as.success.type == STT_TYPE)) { + return Error(Nothing, charptr, "Expecting identifier after 'new'"); + } + if (nameTok.as.success.type == STT_IDENTIFIER) { + newNode.as.success.as.type = createIdentifiedSolsType(nameTok.as.success.as.idName).as.success; + } else if (nameTok.as.success.type == STT_TYPE) { + newNode.as.success.as.type = nameTok.as.success.as.type; + } + addChildToSolsNode(parser->currentParent, newNode.as.success); + return Success(Nothing, charptr, {}); +} + ResultType(Nothing, charptr) parse(SolsParser* parser) { parser->currentParent = &parser->output; for (;;) { @@ -1822,6 +1840,7 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) { case STT_KW_LAMBDA: PARSER_HANDLE(Lambda); case STT_KW_RETURN: PARSER_HANDLE(Return); case STT_KW_STRUCT: PARSER_HANDLE(Struct); + case STT_KW_NEW: PARSER_HANDLE(New); case STT_KW_USE: PARSER_HANDLE(Use); case STT_KW_DEF: PARSER_HANDLE(Def); case STT_OP_SET: PARSER_HANDLE(Set);