From 41a2fa53c67efafdd166186c70e3f11b0c951508 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Fri, 6 Mar 2026 09:24:16 +1100 Subject: [PATCH] Start work on WASM compatibility, lambda fix --- src/codegen/codegen.c | 12 ++++--- src/main.c | 50 ++++++++++++++++---------- src/wasm_main.c | 81 +++++++++++++++++++++++++++++++++++++++++++ tests/closure.sols | 4 +-- 4 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 src/wasm_main.c diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 5144129..3d49838 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -735,6 +735,8 @@ ResultType(GroundProgram, charptr) generateLambdaNode(SolsNode* node, SolsScope* // Create a scope for lambda arguments SolsScope lambdaScope = copySolsScope(scope); + // Set the scope's return type + lambdaScope.returnType = *node->as.type.returnType; for (size_t i = 0; i < node->as.type.children.count; i++) { addVariableToScope(&lambdaScope, node->as.type.children.at[i].name, node->as.type.children.at[i].type); @@ -924,13 +926,13 @@ ResultType(GroundProgram, charptr) generateUseNode(SolsNode* node, SolsScope* sc if (lexer.error) { printf("While lexing file %s:\n", filePath.str); printf("Error while creating lexer: %s", lexer.as.error); - exit(1); + return Error(GroundProgram, charptr, "Error with use"); } ResultType(Nothing, charptr) lexed = lex(&lexer.as.success); if (lexed.error) { printf("While lexing file %s:\n", filePath.str); printf("%s\n", lexed.as.error); - exit(1); + return Error(GroundProgram, charptr, "Error with use"); } // Parse file @@ -938,13 +940,13 @@ ResultType(GroundProgram, charptr) generateUseNode(SolsNode* node, SolsScope* sc if (parser.error) { printf("While parsing file %s:\n", filePath.str); printf("Error while creating parser: %s\n", parser.as.error); - exit(1); + return Error(GroundProgram, charptr, "Error with use"); } ResultType(Nothing, charptr) parsed = parse(&parser.as.success); if (parsed.error) { printf("While parsing file %s:\n", filePath.str); printf("%s\n", parsed.as.error); - exit(1); + return Error(GroundProgram, charptr, "Error with use"); } SolsScope newScope = { @@ -958,7 +960,7 @@ ResultType(GroundProgram, charptr) generateUseNode(SolsNode* node, SolsScope* sc if (codegen.error) { printf("While generating code for file %s:\n", filePath.str); printf("%s\n", codegen.as.error); - exit(1); + return Error(GroundProgram, charptr, "Error with use"); } // Insert all the stuff into our scope diff --git a/src/main.c b/src/main.c index 2f0e8ff..1d34b11 100644 --- a/src/main.c +++ b/src/main.c @@ -15,7 +15,7 @@ #include typedef enum SolsAction { - SA_PRINT, SA_EXEC, SA_BYTECODE, SA_COMPILE + SA_PRINT, SA_EXEC, SA_BYTECODE, SA_COMPILE, SA_EXIT, SA_EXITOK } SolsAction; typedef struct Args { @@ -41,7 +41,8 @@ Args parseArgs(int argc, char** argv) { printf(" -b or --bytecode : Generates Ground bytecode (.grbc) and saves it to the provided filename\n"); printf(" -c or --compile : Compiles Ground to Linux x86_64 assembly, outputs a binary to the provided filename (experimental)\n"); printf(" If no extra arguments are provided, the generated Ground bytecode will be executed.\n"); - exit(0); + args.action = SA_EXIT; + return args; } else if (strcmp("-p", argv[i]) == 0 || strcmp("--print", argv[i]) == 0) { args.action = SA_PRINT; @@ -49,12 +50,14 @@ Args parseArgs(int argc, char** argv) { else if (strcmp("-b", argv[i]) == 0 || strcmp("--bytecode", argv[i]) == 0) { if (args.action != SA_EXEC) { printf("Expecting only one action\n"); - exit(1); + args.action = SA_EXIT; + return args; } args.action = SA_BYTECODE; if (i + 1 >= argc) { printf("Expecting file name after %s\n", argv[i]); - exit(1); + args.action = SA_EXIT; + return args; } i++; args.outputFile = argv[i]; @@ -62,12 +65,14 @@ Args parseArgs(int argc, char** argv) { else if (strcmp("-c", argv[i]) == 0 || strcmp("--compile", argv[i]) == 0) { if (args.action != SA_EXEC) { printf("Expecting only one action\n"); - exit(1); + args.action = SA_EXIT; + return args; } args.action = SA_COMPILE; if (i + 1 >= argc) { printf("Expecting file name after %s\n", argv[i]); - exit(1); + args.action = SA_EXIT; + return args; } i++; args.outputFile = argv[i]; @@ -79,7 +84,8 @@ Args parseArgs(int argc, char** argv) { if (args.inputFile == NULL) { printf("Usage: %s [-h] [--help] [-p] [--print] [-b ] [--bytecode ] [-c ] [--compile ]\n", argv[0]); - exit(1); + args.action = SA_EXIT; + return args; } return args; @@ -94,7 +100,7 @@ char* getFileContents(const char* filename) { fp = fopen(filename, "rb"); if (!fp) { perror(filename); - exit(1); + return NULL; } fseek(fp, 0L, SEEK_END); @@ -121,42 +127,50 @@ char* getFileContents(const char* filename) { int main(int argc, char** argv) { Args args = parseArgs(argc, argv); + + if (args.action == SA_EXIT) { + return 1; + } + if (args.action == SA_EXITOK) { + return 0; + } + char* fileContents = getFileContents(args.inputFile); if (fileContents == NULL) { printf("Couldn't read that file :(\n"); - exit(1); + return 1; } // Lex file ResultType(SolsLexer, charptr) lexer = createLexer(fileContents); if (lexer.error) { printf("Error while creating lexer: %s", lexer.as.error); - exit(1); + return 1; } ResultType(Nothing, charptr) lexed = lex(&lexer.as.success); if (lexed.error) { printf("%s\n", lexed.as.error); - exit(1); + return 1; } // Detect and parse types ResultType(SolsTokens, charptr) typed = addTypeInfo(&lexer.as.success.output); if (typed.error) { printf("%s\n", typed.as.error); - exit(1); + return 1; } // Parse file ResultType(SolsParser, charptr) parser = createSolsParser(&typed.as.success); if (parser.error) { printf("Error while creating parser: %s\n", parser.as.error); - exit(1); + return 1; } ResultType(Nothing, charptr) parsed = parse(&parser.as.success); if (parsed.error) { printf("%s\n", parsed.as.error); - exit(1); + return 1; } SolsScope scope = { @@ -169,7 +183,7 @@ int main(int argc, char** argv) { ResultType(GroundProgram, charptr) codegen = generateCode(&parser.as.success.output, &scope); if (codegen.error) { printf("%s\n", codegen.as.error); - exit(1); + return 1; } switch (args.action) { @@ -204,7 +218,7 @@ int main(int argc, char** argv) { #endif if (dirstatus != 0) { printf("Couldn't create temporary work directory\n"); - exit(1); + return 1; } // Write generated asm to .s @@ -227,7 +241,7 @@ int main(int argc, char** argv) { int nasmstatus = system(nasmcmd.str); if (nasmstatus != 0) { printf("command \"%s\" exited with code %d\n", nasmcmd.str, nasmstatus); - exit(1); + return 1; } // Link with ld @@ -240,7 +254,7 @@ int main(int argc, char** argv) { int ldstatus = system(ldcmd.str); if (ldstatus != 0) { printf("command \"%s\" exited with code %d\n", ldcmd.str, ldstatus); - exit(1); + return 1; } // Yay we compiled it diff --git a/src/wasm_main.c b/src/wasm_main.c new file mode 100644 index 0000000..67ab689 --- /dev/null +++ b/src/wasm_main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +#include "lexer/lexer.h" +#include "typeparser/typeparser.h" +#include "parser/parser.h" +#include "codegen/codegen.h" + +#include + + +static char out_buf[65536]; +static int out_pos = 0; + +// Defined by Ground +void wasm_print(const char* str); + +EMSCRIPTEN_KEEPALIVE +const char* solstice_run(char* source) { + out_pos = 0; + out_buf[0] = '\0'; + + // 1. Lex + ResultType(SolsLexer, charptr) lexer = createLexer(source); + if (lexer.error) { + snprintf(out_buf, sizeof(out_buf), + "[lex error] %s", lexer.as.error); + return out_buf; + } + ResultType(Nothing, charptr) lexed = lex(&lexer.as.success); + if (lexed.error) { + snprintf(out_buf, sizeof(out_buf), "%s", lexed.as.error); + return out_buf; + } + + // 2. Type parse + ResultType(SolsTokens, charptr) typed = addTypeInfo(&lexer.as.success.output); + if (typed.error) { + snprintf(out_buf, sizeof(out_buf), "%s", typed.as.error); + return out_buf; + } + + // 3. Parse + ResultType(SolsParser, charptr) parser = createSolsParser(&typed.as.success); + if (parser.error) { + snprintf(out_buf, sizeof(out_buf), + "[parse error] %s", parser.as.error); + return out_buf; + } + ResultType(Nothing, charptr) parsed = parse(&parser.as.success); + if (parsed.error) { + snprintf(out_buf, sizeof(out_buf), "%s", parsed.as.error); + return out_buf; + } + + // 4. Codegen + SolsScope scope = { + .variables = NULL, + .tmpCounter = 0, + .returnType = createSolsType(STT_INT).as.success + }; + ResultType(GroundProgram, charptr) codegen = + generateCode(&parser.as.success.output, &scope); + if (codegen.error) { + snprintf(out_buf, sizeof(out_buf), "%s", codegen.as.error); + return out_buf; + } + + // 5. Run + GroundValue retval = groundRunProgram(&codegen.as.success); + if (out_pos == 0) { + // Program produced no output — report exit code + snprintf(out_buf, sizeof(out_buf), + "[exited with code %d]", + retval.type == INT ? retval.data.intVal : 0); + } + + return out_buf; +} diff --git a/tests/closure.sols b/tests/closure.sols index 42a23f1..2c0992f 100644 --- a/tests/closure.sols +++ b/tests/closure.sols @@ -1,9 +1,9 @@ def createClosure(int x) fun(int) int { return lambda(int y) int { - x + y + return x + y } } myVar = createClosure(5) -puts myVar(3) \ No newline at end of file +puts myVar(3)