From b93ea5006ce98b46cd3000e62b18bcfe2f795d78 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 2 Feb 2025 17:26:47 +1100 Subject: [PATCH] Functions are WIP, read more They're no-ops in compilation for now, and param types aren't parsed. 'return' keyword needs to be implemented. Was distracted by bugfixes in v2 and v2-docs. --- scripts/funky.toy | 13 +++++++++++++ source/toy_ast.c | 11 +++++++++++ source/toy_ast.h | 12 ++++++++++++ source/toy_module_builder.c | 13 +++++++++---- source/toy_parser.c | 35 ++++++++++++++++++++++++++++++----- tests/cases/test_ast.c | 1 + 6 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 scripts/funky.toy diff --git a/scripts/funky.toy b/scripts/funky.toy new file mode 100644 index 0000000..ced83e1 --- /dev/null +++ b/scripts/funky.toy @@ -0,0 +1,13 @@ + + +fn name(param1, param2) { + //return 42; +} + +/* +fn name(param1: int, param2: float) { + return 42; +} +*/ + + diff --git a/source/toy_ast.c b/source/toy_ast.c index ef88d71..9ed5780 100644 --- a/source/toy_ast.c +++ b/source/toy_ast.c @@ -202,6 +202,17 @@ void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astH (*astHandle) = tmp; } +void Toy_private_emitAstFunctionDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* params, Toy_Ast* body) { + Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast)); + + tmp->type = TOY_AST_FN_DECLARE; + tmp->fnDeclare.name = name; + tmp->fnDeclare.params = params; + tmp->fnDeclare.body = body; + + (*astHandle) = tmp; +} + void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) { Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast)); diff --git a/source/toy_ast.h b/source/toy_ast.h index f9d1c88..8624b17 100644 --- a/source/toy_ast.h +++ b/source/toy_ast.h @@ -30,6 +30,8 @@ typedef enum Toy_AstType { TOY_AST_VAR_ASSIGN, TOY_AST_VAR_ACCESS, + TOY_AST_FN_DECLARE, + TOY_AST_PASS, TOY_AST_ERROR, TOY_AST_END, @@ -191,6 +193,13 @@ typedef struct Toy_AstVarAccess { Toy_Ast* child; } Toy_AstVarAccess; +typedef struct Toy_AstFnDeclare { + Toy_AstType type; + Toy_String* name; + Toy_Ast* params; + Toy_Ast* body; +} Toy_AstFnDeclare; + typedef struct Toy_AstPass { Toy_AstType type; } Toy_AstPass; @@ -223,6 +232,7 @@ union Toy_Ast { //see 'test_ast.c' for bitness tests Toy_AstVarDeclare varDeclare; Toy_AstVarAssign varAssign; Toy_AstVarAccess varAccess; + Toy_AstFnDeclare fnDeclare; Toy_AstPass pass; Toy_AstError error; Toy_AstEnd end; @@ -251,6 +261,8 @@ void Toy_private_emitAstVariableDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* expr); void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); +void Toy_private_emitAstFunctionDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* params, Toy_Ast* body); + void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); diff --git a/source/toy_module_builder.c b/source/toy_module_builder.c index dbdf5b0..ac856d0 100644 --- a/source/toy_module_builder.c +++ b/source/toy_module_builder.c @@ -899,10 +899,11 @@ static unsigned int writeInstructionAccess(Toy_ModuleBuilder** mb, Toy_AstVarAcc return 1; } -//routine structure -// static void writeModuleBuilderParam(Toy_ModuleBuilder* mb) { -// // -// } +static unsigned int writeInstructionFnDeclare(Toy_ModuleBuilder** mb, Toy_AstFnDeclare ast) { + (void)mb; + (void)ast; + return 0; +} static unsigned int writeModuleBuilderCode(Toy_ModuleBuilder** mb, Toy_Ast* ast) { if (ast == NULL) { @@ -1010,6 +1011,10 @@ static unsigned int writeModuleBuilderCode(Toy_ModuleBuilder** mb, Toy_Ast* ast) result += writeInstructionAccess(mb, ast->varAccess); break; + case TOY_AST_FN_DECLARE: + result += writeInstructionFnDeclare(mb, ast->fnDeclare); + break; + case TOY_AST_PASS: //NO-OP break; diff --git a/source/toy_parser.c b/source/toy_parser.c index 62c1339..b7ee2c8 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -890,7 +890,7 @@ static void makeVariableDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* p } } - //build the string + //build the name string Toy_String* nameStr = Toy_createNameStringLength(bucketHandle, nameToken.lexeme, nameToken.length, varType, constant); //if there's an assignment, read it, or default to null @@ -908,6 +908,31 @@ static void makeVariableDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* p consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of var statement"); } +static void makeFunctionDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) { + consume(parser, TOY_TOKEN_NAME, "Expected function name after 'fn' keyword"); + + if (parser->previous.length > 255) { + printError(parser, parser->previous, "Can't have a function name longer than 255 characters"); + Toy_private_emitAstError(bucketHandle, rootHandle); + return; + } + + //build the name string + Toy_Token nameToken = parser->previous; + Toy_String* nameStr = Toy_createNameStringLength(bucketHandle, nameToken.lexeme, nameToken.length, TOY_VALUE_FUNCTION, true); + + //read the function parameters, as a grouping + Toy_Ast* params = NULL; + parsePrecedence(bucketHandle, parser, ¶ms, PREC_GROUP); + + //read the body + Toy_Ast* body = NULL; + makeBlockStmt(bucketHandle, parser, &body); + + //finally, emit the declaration as an Ast + Toy_private_emitAstFunctionDeclaration(bucketHandle, rootHandle, nameStr, params, body); +} + static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) { //inner scope if (match(parser, TOY_TOKEN_OPERATOR_BRACE_LEFT)) { @@ -984,10 +1009,10 @@ static void makeDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, T makeVariableDeclarationStmt(bucketHandle, parser, rootHandle); } - // //function declarations - // else if (match(parser, TOY_TOKEN_KEYWORD_FUNCTION)) { - // makeFunctionDeclarationStmt(bucketHandle, parser, rootHandle); - // } + //function declarations + else if (match(parser, TOY_TOKEN_KEYWORD_FUNCTION)) { + makeFunctionDeclarationStmt(bucketHandle, parser, rootHandle); + } //otherwise else { diff --git a/tests/cases/test_ast.c b/tests/cases/test_ast.c index 4c23cab..c7df85b 100644 --- a/tests/cases/test_ast.c +++ b/tests/cases/test_ast.c @@ -50,6 +50,7 @@ int test_sizeof_ast(void) { TEST_SIZEOF(Toy_AstVarDeclare, 12 , 24); TEST_SIZEOF(Toy_AstVarAssign, 16 , 24); TEST_SIZEOF(Toy_AstVarAccess, 8 , 16); + TEST_SIZEOF(Toy_AstFnDeclare, 16 , 32); TEST_SIZEOF(Toy_AstPass, 4 , 4); TEST_SIZEOF(Toy_AstError, 4 , 4); TEST_SIZEOF(Toy_AstEnd, 4 , 4);