From 1374e055798e8cdc52395aea4308f18b0a706592 Mon Sep 17 00:00:00 2001 From: cozis Date: Sat, 12 Mar 2022 22:47:23 +0100 Subject: [PATCH] simplified code and fixed a bug --- build.sh | 1 - samples/strcat.noja | 14 +- src/builtins/basic.c | 2 +- src/main.c | 374 ++++++++++++++++++++++++++++++++++++++++++- src/noja.c | 374 ------------------------------------------- src/noja.h | 2 - test.sh | 2 - 7 files changed, 379 insertions(+), 390 deletions(-) delete mode 100644 src/noja.c delete mode 100644 src/noja.h delete mode 100644 test.sh diff --git a/build.sh b/build.sh index 2df7311..c1d832e 100755 --- a/build.sh +++ b/build.sh @@ -82,7 +82,6 @@ ar rcs build/libnoja-runtime.a \ build/libnoja-objects.a gcc src/main.c \ - src/noja.c \ temp/o_staticmap.o \ temp/utils/hash.o \ temp/utils/stack.o \ diff --git a/samples/strcat.noja b/samples/strcat.noja index 657411d..e57a11a 100644 --- a/samples/strcat.noja +++ b/samples/strcat.noja @@ -1,20 +1,18 @@ - A = 'Hello'; B = ', '; C = 'world'; D = strcat(A, B, C); -fun append_esclamation_mark(A, n) -{ +fun append_esclamation_mark(A, n) { + if n == none: n = 1; i = 0; - while i < n: - { - A = strcat(A, '!'); - i = i + 1; - } + while i < n: { + A = strcat(A, '!'); + i = i + 1; + } return A; } diff --git a/src/builtins/basic.c b/src/builtins/basic.c index 9b0edbb..33582f6 100644 --- a/src/builtins/basic.c +++ b/src/builtins/basic.c @@ -136,7 +136,7 @@ const StaticMapSlot bins_basic[] = { { "newBuffer", SM_FUNCT, .as_funct = bin_newBuffer, .argc = 1 }, { "sliceBuffer", SM_FUNCT, .as_funct = bin_sliceBuffer, .argc = 3 }, - { "strcat", SM_FUNCT, .as_funct = bin_strcat }, + { "strcat", SM_FUNCT, .as_funct = bin_strcat, .argc = -1 }, { "type", SM_FUNCT, .as_funct = bin_type, .argc = 1 }, { "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 }, diff --git a/src/main.c b/src/main.c index e30fec9..5970187 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,377 @@ -#include "noja.h" +#include +#include +#include +#include +#include "o_staticmap.h" +#include "compiler/parse.h" +#include "compiler/compile.h" +#include "runtime/runtime.h" +#include "runtime/runtime_error.h" +#include "builtins/basic.h" + +static const char usage[] = + "Usage patterns:\n" + " $ noja run file.noja\n" + " $ noja run inline \"print('some noja code');\"\n" + " $ noja dis file.noja\n" + " $ noja dis inline \"print('some noja code');\"\n"; + +static _Bool interpret_file(const char *file); +static _Bool interpret_code(const char *code); +static _Bool disassemble_file(const char *file); +static _Bool disassemble_code(const char *code); + +static void print_error(const char *type, Error *error) +{ + if(type == NULL) + fprintf(stderr, "Error"); + else if(error->internal) + fprintf(stderr, "Internal Error"); + else + fprintf(stderr, "%s Error", type); + + fprintf(stderr, ": %s.", error->message); + +#ifdef DEBUG + if(error->file != NULL) + { + if(error->line > 0 && error->func != NULL) + fprintf(stderr, " (Reported in %s:%d in %s)", error->file, error->line, error->func); + else if(error->line > 0 && error->func == NULL) + fprintf(stderr, " (Reported in %s:%d)", error->file, error->line); + else if(error->line < 1 && error->func != NULL) + fprintf(stderr, " (Reported in %s in %s)", error->file, error->func); + } +#endif + + fprintf(stderr, "\n"); +} int main(int argc, char **argv) { - return noja(argc, argv) ? 0 : -1; + assert(argc > 0); + + if(argc == 1) + { + // $ noja + fprintf(stderr, "Error: Incorrect usage.\n\n"); + fprintf(stderr, usage); + return -1; + } + + if(!strcmp(argv[1], "run")) + { + Error error; + Error_Init(&error); + + if(argc == 2) + { + Error_Report(&error, 0, "Missing source file"); + print_error(NULL, &error); + Error_Free(&error); + return -1; + } + + _Bool r; + + if(!strcmp(argv[2], "inline")) + { + if(argc == 3) + { + Error_Report(&error, 0, "Missing source string"); + print_error(NULL, &error); + Error_Free(&error); + return -1; + } + + r = interpret_code(argv[3]); + } + else + r = interpret_file(argv[2]); + return r ? 0 : -1; + } + + if(!strcmp(argv[1], "dis")) + { + Error error; + Error_Init(&error); + + if(argc == 2) + { + Error_Report(&error, 0, "Missing source file"); + print_error(NULL, &error); + Error_Free(&error); + return -1; + } + + _Bool r; + + if(!strcmp(argv[2], "inline")) + { + if(argc == 3) + { + Error_Report(&error, 0, "Missing source string"); + print_error(NULL, &error); + Error_Free(&error); + return -1; + } + + r = disassemble_code(argv[3]); + } + else + r = disassemble_file(argv[2]); + return r ? 0 : -1; + } + + if(!strcmp(argv[1], "help")) + { + fprintf(stdout, usage); + return 0; + } + + fprintf(stderr, "Error: Incorrect usage.\n\n"); + fprintf(stderr, usage); + return -1; } +static _Bool interpret(Source *src) +{ + // Compile the code. This section transforms + // a [Source] into an [Executable]. + Executable *exe; + { + // Create a bump-pointer allocator to hold the AST. + BPAlloc *alloc = BPAlloc_Init(-1); + + if(alloc == NULL) + { + fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n"); + return 0; + } + + Error error; + Error_Init(&error); + + // NOTE: The AST is stored in the BPAlloc. It's + // lifetime is the same as the pool. + AST *ast = parse(src, alloc, &error); + + if(ast == NULL) + { + assert(error.occurred); + print_error("Parsing", &error); + Error_Free(&error); + BPAlloc_Free(alloc); + return 0; + } + + exe = compile(ast, alloc, &error); + + // We're done with the AST, independently from + // the compilation result. + BPAlloc_Free(alloc); + + if(exe == NULL) + { + assert(error.occurred); + print_error("Compilation", &error); + Error_Free(&error); + return 0; + } + } + + // Now execute it. + { + Runtime *runt = Runtime_New(-1, -1, NULL, NULL); + + if(runt == NULL) + { + Error error; + Error_Init(&error); + Error_Report(&error, 1, "Couldn't initialize runtime"); + print_error(NULL, &error); + Error_Free(&error); + Executable_Free(exe); + return 0; + } + + // We use a [RuntimeError] instead of a simple [Error] + // because the [RuntimeError] makes a snapshot of the + // runtime state when an error is reported. Other than + // this fact they are interchangable. Any function that + // expects a pointer to [Error] can receive a [RuntimeError] + // upcasted to [Error]. + RuntimeError error; + RuntimeError_Init(&error, runt); // Here we specify the runtime to snapshot in case of failure. + + Object *bins = Object_NewStaticMap(bins_basic, runt, (Error*) &error); + + if(bins == NULL) + { + assert(error.base.occurred == 1); + print_error(NULL, (Error*) &error); + RuntimeError_Free(&error); + Executable_Free(exe); + Runtime_Free(runt); + return 0; + } + + Runtime_SetBuiltins(runt, bins); + + Object *o = run(runt, (Error*) &error, exe, 0, NULL, NULL, 0); + + // NOTE: The pointer to the builtins object is invalidated + // now because it may be moved by the garbage collector. + + if(o == NULL) + { + print_error("Runtime", (Error*) &error); + + if(error.snapshot == NULL) + fprintf(stderr, "No snapshot available.\n"); + else + Snapshot_Print(error.snapshot, stderr); + + RuntimeError_Free(&error); + } + + Runtime_Free(runt); + Executable_Free(exe); + + return o != NULL; + } +} + +static _Bool disassemble(Source *src) +{ + // Compile the code. This section transforms + // a [Source] into an [Executable]. + Executable *exe; + { + // Create a bump-pointer allocator to hold the AST. + BPAlloc *alloc = BPAlloc_Init(-1); + + if(alloc == NULL) + { + fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n"); + return 0; + } + + Error error; + Error_Init(&error); + + // NOTE: The AST is stored in the BPAlloc. It's + // lifetime is the same as the pool. + AST *ast = parse(src, alloc, &error); + + if(ast == NULL) + { + assert(error.occurred); + print_error("Parsing", &error); + Error_Free(&error); + BPAlloc_Free(alloc); + return 0; + } + + exe = compile(ast, alloc, &error); + + // We're done with the AST, independently from + // the compilation result. + BPAlloc_Free(alloc); + + if(exe == NULL) + { + assert(error.occurred); + print_error("Compilation", &error); + Error_Free(&error); + return 0; + } + } + + Executable_Dump(exe); + return 1; +} + +static _Bool interpret_file(const char *file) +{ + Error error; + Error_Init(&error); + + Source *src = Source_FromFile(file, &error); + + if(src == NULL) + { + assert(error.occurred == 1); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } + + _Bool r = interpret(src); + + Source_Free(src); + return r; +} + +static _Bool interpret_code(const char *code) +{ + Error error; + Error_Init(&error); + + Source *src = Source_FromString(NULL, code, -1, &error); + + if(src == NULL) + { + assert(error.occurred); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } + + _Bool r = interpret(src); + + Source_Free(src); + return r; +} + +static _Bool disassemble_file(const char *file) +{ + Error error; + Error_Init(&error); + + Source *src = Source_FromFile(file, &error); + + if(src == NULL) + { + assert(error.occurred == 1); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } + + _Bool r = disassemble(src); + + Source_Free(src); + return r; +} + +static _Bool disassemble_code(const char *code) +{ + Error error; + Error_Init(&error); + + Source *src = Source_FromString(NULL, code, -1, &error); + + if(src == NULL) + { + assert(error.occurred); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } + + _Bool r = disassemble(src); + + Source_Free(src); + return r; +} \ No newline at end of file diff --git a/src/noja.c b/src/noja.c deleted file mode 100644 index bc3e8ba..0000000 --- a/src/noja.c +++ /dev/null @@ -1,374 +0,0 @@ -#include -#include -#include -#include -#include "o_staticmap.h" -#include "compiler/parse.h" -#include "compiler/compile.h" -#include "runtime/runtime.h" -#include "runtime/runtime_error.h" -#include "builtins/basic.h" - -static const char usage[] = - "Usage patterns:\n" - " $ noja run file.noja\n" - " $ noja run inline \"print('some noja code');\"\n" - " $ noja dis file.noja\n" - " $ noja dis inline \"print('some noja code');\"\n"; -static _Bool interpret_file(const char *file); -static _Bool interpret_code(const char *code); -static _Bool disassemble_file(const char *file); -static _Bool disassemble_code(const char *code); - -static void print_error(const char *type, Error *error) -{ - if(type == NULL) - fprintf(stderr, "Error"); - else if(error->internal) - fprintf(stderr, "Internal Error"); - else - fprintf(stderr, "%s Error", type); - - fprintf(stderr, ": %s. ", error->message); - - if(error->file != NULL) - { - if(error->line > 0 && error->func != NULL) - fprintf(stderr, "(Reported in %s:%d in %s)", error->file, error->line, error->func); - else if(error->line > 0 && error->func == NULL) - fprintf(stderr, "(Reported in %s:%d)", error->file, error->line); - else if(error->line < 1 && error->func != NULL) - fprintf(stderr, "(Reported in %s in %s)", error->file, error->func); - } - - fprintf(stderr, "\n"); -} - -_Bool noja(int argc, char **argv) -{ - assert(argc > 0); - - if(argc == 1) - { - // $ noja - fprintf(stderr, "Error: Incorrect usage.\n\n"); - fprintf(stderr, usage); - return 0; - } - - if(!strcmp(argv[1], "run")) - { - Error error; - Error_Init(&error); - - if(argc == 2) - { - Error_Report(&error, 0, "Missing source file"); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - _Bool r; - - if(!strcmp(argv[2], "inline")) - { - if(argc == 3) - { - Error_Report(&error, 0, "Missing source string"); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - r = interpret_code(argv[3]); - } - else - r = interpret_file(argv[2]); - return r; - } - - if(!strcmp(argv[1], "dis")) - { - Error error; - Error_Init(&error); - - if(argc == 2) - { - Error_Report(&error, 0, "Missing source file"); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - _Bool r; - - if(!strcmp(argv[2], "inline")) - { - if(argc == 3) - { - Error_Report(&error, 0, "Missing source string"); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - r = disassemble_code(argv[3]); - } - else - r = disassemble_file(argv[2]); - return r; - } - - if(!strcmp(argv[1], "help")) - { - fprintf(stdout, usage); - return 1; - } - - fprintf(stderr, "Error: Incorrect usage.\n\n"); - fprintf(stderr, usage); - return 0; -} - -static _Bool interpret(Source *src) -{ - // Compile the code. This section transforms - // a [Source] into an [Executable]. - Executable *exe; - { - // Create a bump-pointer allocator to hold the AST. - BPAlloc *alloc = BPAlloc_Init(-1); - - if(alloc == NULL) - { - fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n"); - return 0; - } - - Error error; - Error_Init(&error); - - // NOTE: The AST is stored in the BPAlloc. It's - // lifetime is the same as the pool. - AST *ast = parse(src, alloc, &error); - - if(ast == NULL) - { - assert(error.occurred); - print_error("Parsing", &error); - Error_Free(&error); - BPAlloc_Free(alloc); - return 0; - } - - exe = compile(ast, alloc, &error); - - // We're done with the AST, independently from - // the compilation result. - BPAlloc_Free(alloc); - - if(exe == NULL) - { - assert(error.occurred); - print_error("Compilation", &error); - Error_Free(&error); - return 0; - } - } - - // Now execute it. - { - Runtime *runt = Runtime_New(-1, -1, NULL, NULL); - - if(runt == NULL) - { - Error error; - Error_Init(&error); - Error_Report(&error, 1, "Couldn't initialize runtime"); - print_error(NULL, &error); - Error_Free(&error); - Executable_Free(exe); - return 0; - } - - // We use a [RuntimeError] instead of a simple [Error] - // because the [RuntimeError] makes a snapshot of the - // runtime state when an error is reported. Other than - // this fact they are interchangable. Any function that - // expects a pointer to [Error] can receive a [RuntimeError] - // upcasted to [Error]. - RuntimeError error; - RuntimeError_Init(&error, runt); // Here we specify the runtime to snapshot in case of failure. - - Object *bins = Object_NewStaticMap(bins_basic, runt, (Error*) &error); - - if(bins == NULL) - { - assert(error.base.occurred == 1); - print_error(NULL, (Error*) &error); - RuntimeError_Free(&error); - Executable_Free(exe); - Runtime_Free(runt); - return 0; - } - - Runtime_SetBuiltins(runt, bins); - - Object *o = run(runt, (Error*) &error, exe, 0, NULL, NULL, 0); - - // NOTE: The pointer to the builtins object is invalidated - // now because it may be moved by the garbage collector. - - if(o == NULL) - { - print_error("Runtime", (Error*) &error); - - if(error.snapshot == NULL) - fprintf(stderr, "No snapshot available.\n"); - else - Snapshot_Print(error.snapshot, stderr); - - RuntimeError_Free(&error); - } - - Runtime_Free(runt); - Executable_Free(exe); - - return o != NULL; - } -} - -static _Bool disassemble(Source *src) -{ - // Compile the code. This section transforms - // a [Source] into an [Executable]. - Executable *exe; - { - // Create a bump-pointer allocator to hold the AST. - BPAlloc *alloc = BPAlloc_Init(-1); - - if(alloc == NULL) - { - fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n"); - return 0; - } - - Error error; - Error_Init(&error); - - // NOTE: The AST is stored in the BPAlloc. It's - // lifetime is the same as the pool. - AST *ast = parse(src, alloc, &error); - - if(ast == NULL) - { - assert(error.occurred); - print_error("Parsing", &error); - Error_Free(&error); - BPAlloc_Free(alloc); - return 0; - } - - exe = compile(ast, alloc, &error); - - // We're done with the AST, independently from - // the compilation result. - BPAlloc_Free(alloc); - - if(exe == NULL) - { - assert(error.occurred); - print_error("Compilation", &error); - Error_Free(&error); - return 0; - } - } - - Executable_Dump(exe); - return 1; -} - -static _Bool interpret_file(const char *file) -{ - Error error; - Error_Init(&error); - - Source *src = Source_FromFile(file, &error); - - if(src == NULL) - { - assert(error.occurred == 1); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - _Bool r = interpret(src); - - Source_Free(src); - return r; -} - -static _Bool interpret_code(const char *code) -{ - Error error; - Error_Init(&error); - - Source *src = Source_FromString(NULL, code, -1, &error); - - if(src == NULL) - { - assert(error.occurred); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - _Bool r = interpret(src); - - Source_Free(src); - return r; -} - -static _Bool disassemble_file(const char *file) -{ - Error error; - Error_Init(&error); - - Source *src = Source_FromFile(file, &error); - - if(src == NULL) - { - assert(error.occurred == 1); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - _Bool r = disassemble(src); - - Source_Free(src); - return r; -} - -static _Bool disassemble_code(const char *code) -{ - Error error; - Error_Init(&error); - - Source *src = Source_FromString(NULL, code, -1, &error); - - if(src == NULL) - { - assert(error.occurred); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } - - _Bool r = disassemble(src); - - Source_Free(src); - return r; -} \ No newline at end of file diff --git a/src/noja.h b/src/noja.h deleted file mode 100644 index e241194..0000000 --- a/src/noja.h +++ /dev/null @@ -1,2 +0,0 @@ - -_Bool noja(int argc, char **argv); \ No newline at end of file diff --git a/test.sh b/test.sh deleted file mode 100644 index 57d89dc..0000000 --- a/test.sh +++ /dev/null @@ -1,2 +0,0 @@ -./build/test-parse tests/aux/parsing-tests.json -./build/test-objects \ No newline at end of file