From 1780826a97e0ba3df1388e0db411d3894787caa9 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Sun, 22 Jan 2023 02:22:44 +0100 Subject: [PATCH] new testing infrastructure --- examples/http_server/main.noja | 2 +- report_test_suite_coverage.sh | 2 +- src/lib/assembler/assemble.c | 64 +- src/lib/builtins/basic.c | 4 +- src/lib/compiler/parse.c | 2 +- src/lib/runtime.c | 28 +- src/lib/runtime.h | 7 +- src/lib/utils/stack.c | 54 +- src/lib/utils/stack.h | 3 +- src/test/error.c | 14 + src/test/error.h | 14 + src/test/error.o | Bin 0 -> 4216 bytes src/test/field.c | 140 ++++ src/test/field.h | 20 + src/test/field.o | Bin 0 -> 10288 bytes src/test/main.c | 635 ++++-------------- src/test/main.h | 8 + src/test/main.o | Bin 0 -> 12512 bytes src/test/run.c | 210 ++++++ src/test/run.h | 21 + src/test/run.o | Bin 0 -> 16792 bytes src/test/scanner.c | 65 ++ src/test/scanner.h | 32 + src/test/scanner.o | Bin 0 -> 5360 bytes src/test/test.c | 86 +++ src/test/test.h | 12 + src/test/test.o | Bin 0 -> 8080 bytes test_bytecode | Bin 0 -> 184792 bytes .../dowhile/Testcase_010_000.noja-test} | 5 +- .../dowhile/Testcase_010_001.noja-test} | 5 +- .../dowhile/Testcase_010_002.noja-test} | 5 +- .../dowhile/Testcase_010_003.noja-test} | 5 +- .../dowhile/Testcase_010_004.noja-test} | 5 +- .../arithmetic/Testcase_002_000.noja-test} | 5 +- .../arithmetic/Testcase_002_001.noja-test} | 5 +- .../arithmetic/Testcase_002_002.noja-test} | 5 +- .../arithmetic/Testcase_002_003.noja-test} | 5 +- .../arithmetic/Testcase_002_004.noja-test} | 9 +- .../arithmetic/Testcase_002_005.noja-test} | 5 +- .../arithmetic/Testcase_002_006.noja-test} | 5 +- .../arithmetic/Testcase_002_007.noja-test} | 5 +- .../arithmetic/Testcase_002_008.noja-test} | 5 +- .../arithmetic/Testcase_002_009.noja-test} | 5 +- .../arithmetic/Testcase_002_010.noja-test} | 5 +- .../arithmetic/Testcase_002_011.noja-test} | 5 +- .../arithmetic/Testcase_002_023.noja-test} | 5 +- .../arithmetic/Testcase_002_024.noja-test} | 5 +- .../arithmetic/Testcase_002_025.noja-test} | 5 +- .../arithmetic/Testcase_002_026.noja-test} | 5 +- .../arithmetic/Testcase_002_027.noja-test} | 5 +- .../arithmetic/Testcase_002_028.noja-test} | 5 +- .../arithmetic/Testcase_002_029.noja-test} | 5 +- .../arithmetic/Testcase_002_030.noja-test} | 5 +- .../arithmetic/Testcase_002_031.noja-test} | 5 +- .../expr/array/Testcase_003_000.noja-test | 16 + .../expr/array/Testcase_003_001.noja-test} | 9 +- .../assignment/Testcase_005_000.noja-test} | 5 +- .../assignment/Testcase_005_001.noja-test} | 5 +- .../assignment/Testcase_005_002.noja-test} | 5 +- .../assignment/Testcase_005_003.noja-test} | 5 +- .../expr/logical/Testcase_002_021.noja-test} | 5 +- .../expr/logical/Testcase_002_022.noja-test} | 5 +- .../expr/logical/Testcase_002_032.noja-test} | 5 +- .../expr/logical/Testcase_002_033.noja-test} | 5 +- .../expr/map/Testcase_004_000.noja-test} | 5 +- .../expr/map/Testcase_004_001.noja-test} | 5 +- .../expr/map/Testcase_004_002.noja-test} | 5 +- .../expr/map/Testcase_004_003.noja-test} | 5 +- .../expr/map/Testcase_004_004.noja-test} | 5 +- .../expr/map/Testcase_004_005.noja-test} | 5 +- .../expr/postfix/Testcase_006_000.noja-test} | 5 +- .../expr/postfix/Testcase_006_001.noja-test} | 5 +- .../expr/postfix/Testcase_006_002.noja-test} | 5 +- .../expr/postfix/Testcase_007_000.noja-test} | 5 +- .../expr/postfix/Testcase_007_001.noja-test} | 5 +- .../expr/postfix/Testcase_007_002.noja-test} | 5 +- .../expr/prefix/Testcase_002_012.noja-test} | 5 +- .../expr/prefix/Testcase_002_013.noja-test} | 5 +- .../expr/prefix/Testcase_002_014.noja-test} | 5 +- .../expr/primary/primary_000.noja-test | 9 + .../expr/primary/primary_001.noja-test} | 5 +- .../expr/primary/primary_002.noja-test} | 5 +- .../expr/primary/primary_003.noja-test} | 5 +- .../expr/primary/primary_004.noja-test} | 5 +- .../expr/primary/primary_005.noja-test} | 5 +- .../expr/primary/primary_006.noja-test} | 5 +- .../expr/primary/primary_007.noja-test | 14 + .../expr/primary/primary_008.noja-test | 9 + .../expr/primary/primary_009.noja-test | 11 + .../expr/primary/primary_010.noja-test | 11 + .../expr/primary/primary_011.noja-test | 11 + .../expr/primary/primary_012.noja-test | 11 + .../expr/primary/primary_013.noja-test | 11 + .../expr/primary/primary_014.noja-test | 11 + .../relational/Testcase_002_015.noja-test} | 5 +- .../relational/Testcase_002_016.noja-test} | 5 +- .../relational/Testcase_002_017.noja-test} | 5 +- .../relational/Testcase_002_018.noja-test} | 5 +- .../relational/Testcase_002_019.noja-test} | 5 +- .../relational/Testcase_002_020.noja-test} | 5 +- .../Testcase_002_034.noja-test} | 5 +- .../func/Testcase_011_000.noja-test} | 7 +- .../func/Testcase_011_001.noja-test} | 7 +- .../func/Testcase_011_002.noja-test} | 7 +- .../func/Testcase_011_003.noja-test} | 7 +- .../func/Testcase_011_004.noja-test} | 7 +- .../func/Testcase_011_005.noja-test} | 7 +- .../func/Testcase_011_006.noja-test} | 7 +- .../func/Testcase_011_007.noja-test} | 7 +- .../func/Testcase_011_008.noja-test} | 7 +- .../func/Testcase_011_009.noja-test} | 7 +- .../func/Testcase_012_000.noja-test} | 7 +- .../func/Testcase_012_001.noja-test} | 7 +- .../func/Testcase_012_002.noja-test} | 7 +- .../func/Testcase_012_003.noja-test} | 7 +- .../ifelse/Testcase_008_000.noja-test} | 5 +- .../ifelse/Testcase_008_001.noja-test} | 5 +- .../ifelse/Testcase_008_002.noja-test} | 5 +- .../ifelse/Testcase_008_003.noja-test} | 5 +- .../compiler/other/Testcase_000_000.noja-test | 7 + .../other/Testcase_000_001.noja-test} | 7 +- .../while/Testcase_009_000.noja-test} | 5 +- .../while/Testcase_009_001.noja-test} | 5 +- .../while/Testcase_009_002.noja-test} | 5 +- .../while/Testcase_009_003.noja-test} | 5 +- .../while/Testcase_009_004.noja-test} | 5 +- tests/runtime/tcase_000.noja-test | 10 + tests/runtime/tcase_001.noja-test | 12 + tests/runtime/tcase_002.noja-test | 12 + tests/runtime/tcase_003.noja-test | 12 + tests/runtime/tcase_004.noja-test | 12 + tests/runtime/tcase_005.noja-test | 12 + tests/runtime/tcase_006.noja-test | 12 + tests/runtime/tcase_007.noja-test | 13 + tests/runtime/tcase_008.noja-test | 17 + tests/runtime/tcase_009.noja-test | 17 + tests/runtime/tcase_010.noja-test | 17 + tests/runtime/tcase_011.noja-test | 17 + tests/runtime/tcase_012.noja-test | 13 + tests/suite/Testcase_000_000 | 7 - tests/suite/Testcase_001_000 | 10 - tests/suite/Testcase_001_007 | 10 - tests/suite/Testcase_001_008 | 8 - tests/suite/Testcase_003_000 | 13 - tests/test.noja | 129 ---- 145 files changed, 1432 insertions(+), 938 deletions(-) mode change 100755 => 100644 examples/http_server/main.noja create mode 100644 src/test/error.c create mode 100644 src/test/error.h create mode 100644 src/test/error.o create mode 100644 src/test/field.c create mode 100644 src/test/field.h create mode 100644 src/test/field.o create mode 100644 src/test/main.h create mode 100644 src/test/main.o create mode 100644 src/test/run.c create mode 100644 src/test/run.h create mode 100644 src/test/run.o create mode 100644 src/test/scanner.c create mode 100644 src/test/scanner.h create mode 100644 src/test/scanner.o create mode 100644 src/test/test.c create mode 100644 src/test/test.h create mode 100644 src/test/test.o create mode 100755 test_bytecode rename tests/{suite/Testcase_010_000 => compiler/dowhile/Testcase_010_000.noja-test} (67%) rename tests/{suite/Testcase_010_001 => compiler/dowhile/Testcase_010_001.noja-test} (77%) rename tests/{suite/Testcase_010_002 => compiler/dowhile/Testcase_010_002.noja-test} (83%) rename tests/{suite/Testcase_010_003 => compiler/dowhile/Testcase_010_003.noja-test} (85%) rename tests/{suite/Testcase_010_004 => compiler/dowhile/Testcase_010_004.noja-test} (77%) rename tests/{suite/Testcase_002_000 => compiler/expr/arithmetic/Testcase_002_000.noja-test} (61%) rename tests/{suite/Testcase_002_001 => compiler/expr/arithmetic/Testcase_002_001.noja-test} (62%) rename tests/{suite/Testcase_002_002 => compiler/expr/arithmetic/Testcase_002_002.noja-test} (59%) rename tests/{suite/Testcase_002_003 => compiler/expr/arithmetic/Testcase_002_003.noja-test} (61%) rename tests/{suite/Testcase_002_004 => compiler/expr/arithmetic/Testcase_002_004.noja-test} (61%) rename tests/{suite/Testcase_002_005 => compiler/expr/arithmetic/Testcase_002_005.noja-test} (63%) rename tests/{suite/Testcase_002_006 => compiler/expr/arithmetic/Testcase_002_006.noja-test} (63%) rename tests/{suite/Testcase_002_007 => compiler/expr/arithmetic/Testcase_002_007.noja-test} (63%) rename tests/{suite/Testcase_002_008 => compiler/expr/arithmetic/Testcase_002_008.noja-test} (63%) rename tests/{suite/Testcase_002_009 => compiler/expr/arithmetic/Testcase_002_009.noja-test} (63%) rename tests/{suite/Testcase_002_010 => compiler/expr/arithmetic/Testcase_002_010.noja-test} (63%) rename tests/{suite/Testcase_002_011 => compiler/expr/arithmetic/Testcase_002_011.noja-test} (63%) rename tests/{suite/Testcase_002_023 => compiler/expr/arithmetic/Testcase_002_023.noja-test} (69%) rename tests/{suite/Testcase_002_024 => compiler/expr/arithmetic/Testcase_002_024.noja-test} (69%) rename tests/{suite/Testcase_002_025 => compiler/expr/arithmetic/Testcase_002_025.noja-test} (69%) rename tests/{suite/Testcase_002_026 => compiler/expr/arithmetic/Testcase_002_026.noja-test} (70%) rename tests/{suite/Testcase_002_027 => compiler/expr/arithmetic/Testcase_002_027.noja-test} (76%) rename tests/{suite/Testcase_002_028 => compiler/expr/arithmetic/Testcase_002_028.noja-test} (75%) rename tests/{suite/Testcase_002_029 => compiler/expr/arithmetic/Testcase_002_029.noja-test} (74%) rename tests/{suite/Testcase_002_030 => compiler/expr/arithmetic/Testcase_002_030.noja-test} (75%) rename tests/{suite/Testcase_002_031 => compiler/expr/arithmetic/Testcase_002_031.noja-test} (82%) create mode 100644 tests/compiler/expr/array/Testcase_003_000.noja-test rename tests/{suite/Testcase_003_001 => compiler/expr/array/Testcase_003_001.noja-test} (56%) rename tests/{suite/Testcase_005_000 => compiler/expr/assignment/Testcase_005_000.noja-test} (59%) rename tests/{suite/Testcase_005_001 => compiler/expr/assignment/Testcase_005_001.noja-test} (77%) rename tests/{suite/Testcase_005_002 => compiler/expr/assignment/Testcase_005_002.noja-test} (71%) rename tests/{suite/Testcase_005_003 => compiler/expr/assignment/Testcase_005_003.noja-test} (76%) rename tests/{suite/Testcase_002_021 => compiler/expr/logical/Testcase_002_021.noja-test} (79%) rename tests/{suite/Testcase_002_022 => compiler/expr/logical/Testcase_002_022.noja-test} (77%) rename tests/{suite/Testcase_002_032 => compiler/expr/logical/Testcase_002_032.noja-test} (91%) rename tests/{suite/Testcase_002_033 => compiler/expr/logical/Testcase_002_033.noja-test} (90%) rename tests/{suite/Testcase_004_000 => compiler/expr/map/Testcase_004_000.noja-test} (73%) rename tests/{suite/Testcase_004_001 => compiler/expr/map/Testcase_004_001.noja-test} (81%) rename tests/{suite/Testcase_004_002 => compiler/expr/map/Testcase_004_002.noja-test} (73%) rename tests/{suite/Testcase_004_003 => compiler/expr/map/Testcase_004_003.noja-test} (80%) rename tests/{suite/Testcase_004_005 => compiler/expr/map/Testcase_004_004.noja-test} (75%) rename tests/{suite/Testcase_004_004 => compiler/expr/map/Testcase_004_005.noja-test} (75%) rename tests/{suite/Testcase_006_000 => compiler/expr/postfix/Testcase_006_000.noja-test} (62%) rename tests/{suite/Testcase_006_001 => compiler/expr/postfix/Testcase_006_001.noja-test} (67%) rename tests/{suite/Testcase_006_002 => compiler/expr/postfix/Testcase_006_002.noja-test} (70%) rename tests/{suite/Testcase_007_000 => compiler/expr/postfix/Testcase_007_000.noja-test} (66%) rename tests/{suite/Testcase_007_001 => compiler/expr/postfix/Testcase_007_001.noja-test} (84%) rename tests/{suite/Testcase_007_002 => compiler/expr/postfix/Testcase_007_002.noja-test} (66%) rename tests/{suite/Testcase_002_012 => compiler/expr/prefix/Testcase_002_012.noja-test} (51%) rename tests/{suite/Testcase_002_013 => compiler/expr/prefix/Testcase_002_013.noja-test} (51%) rename tests/{suite/Testcase_002_014 => compiler/expr/prefix/Testcase_002_014.noja-test} (53%) create mode 100644 tests/compiler/expr/primary/primary_000.noja-test rename tests/{suite/Testcase_001_001 => compiler/expr/primary/primary_001.noja-test} (54%) rename tests/{suite/Testcase_001_002 => compiler/expr/primary/primary_002.noja-test} (63%) rename tests/{suite/Testcase_001_003 => compiler/expr/primary/primary_003.noja-test} (53%) rename tests/{suite/Testcase_001_004 => compiler/expr/primary/primary_004.noja-test} (53%) rename tests/{suite/Testcase_001_005 => compiler/expr/primary/primary_005.noja-test} (53%) rename tests/{suite/Testcase_001_006 => compiler/expr/primary/primary_006.noja-test} (52%) create mode 100644 tests/compiler/expr/primary/primary_007.noja-test create mode 100644 tests/compiler/expr/primary/primary_008.noja-test create mode 100644 tests/compiler/expr/primary/primary_009.noja-test create mode 100644 tests/compiler/expr/primary/primary_010.noja-test create mode 100644 tests/compiler/expr/primary/primary_011.noja-test create mode 100644 tests/compiler/expr/primary/primary_012.noja-test create mode 100644 tests/compiler/expr/primary/primary_013.noja-test create mode 100644 tests/compiler/expr/primary/primary_014.noja-test rename tests/{suite/Testcase_002_015 => compiler/expr/relational/Testcase_002_015.noja-test} (60%) rename tests/{suite/Testcase_002_016 => compiler/expr/relational/Testcase_002_016.noja-test} (60%) rename tests/{suite/Testcase_002_017 => compiler/expr/relational/Testcase_002_017.noja-test} (59%) rename tests/{suite/Testcase_002_018 => compiler/expr/relational/Testcase_002_018.noja-test} (59%) rename tests/{suite/Testcase_002_019 => compiler/expr/relational/Testcase_002_019.noja-test} (60%) rename tests/{suite/Testcase_002_020 => compiler/expr/relational/Testcase_002_020.noja-test} (60%) rename tests/{suite/Testcase_002_034 => compiler/expr/relational_and_logical/Testcase_002_034.noja-test} (91%) rename tests/{suite/Testcase_011_000 => compiler/func/Testcase_011_000.noja-test} (55%) rename tests/{suite/Testcase_011_001 => compiler/func/Testcase_011_001.noja-test} (66%) rename tests/{suite/Testcase_011_002 => compiler/func/Testcase_011_002.noja-test} (74%) rename tests/{suite/Testcase_011_003 => compiler/func/Testcase_011_003.noja-test} (70%) rename tests/{suite/Testcase_011_004 => compiler/func/Testcase_011_004.noja-test} (76%) rename tests/{suite/Testcase_011_005 => compiler/func/Testcase_011_005.noja-test} (75%) rename tests/{suite/Testcase_011_006 => compiler/func/Testcase_011_006.noja-test} (79%) rename tests/{suite/Testcase_011_007 => compiler/func/Testcase_011_007.noja-test} (79%) rename tests/{suite/Testcase_011_008 => compiler/func/Testcase_011_008.noja-test} (81%) rename tests/{suite/Testcase_011_009 => compiler/func/Testcase_011_009.noja-test} (84%) rename tests/{suite/Testcase_012_000 => compiler/func/Testcase_012_000.noja-test} (80%) rename tests/{suite/Testcase_012_001 => compiler/func/Testcase_012_001.noja-test} (78%) rename tests/{suite/Testcase_012_002 => compiler/func/Testcase_012_002.noja-test} (78%) rename tests/{suite/Testcase_012_003 => compiler/func/Testcase_012_003.noja-test} (82%) rename tests/{suite/Testcase_008_000 => compiler/ifelse/Testcase_008_000.noja-test} (63%) rename tests/{suite/Testcase_008_001 => compiler/ifelse/Testcase_008_001.noja-test} (69%) rename tests/{suite/Testcase_008_002 => compiler/ifelse/Testcase_008_002.noja-test} (72%) rename tests/{suite/Testcase_008_003 => compiler/ifelse/Testcase_008_003.noja-test} (79%) create mode 100644 tests/compiler/other/Testcase_000_000.noja-test rename tests/{suite/Testcase_000_001 => compiler/other/Testcase_000_001.noja-test} (51%) rename tests/{suite/Testcase_009_000 => compiler/while/Testcase_009_000.noja-test} (69%) rename tests/{suite/Testcase_009_001 => compiler/while/Testcase_009_001.noja-test} (78%) rename tests/{suite/Testcase_009_002 => compiler/while/Testcase_009_002.noja-test} (84%) rename tests/{suite/Testcase_009_003 => compiler/while/Testcase_009_003.noja-test} (85%) rename tests/{suite/Testcase_009_004 => compiler/while/Testcase_009_004.noja-test} (77%) create mode 100644 tests/runtime/tcase_000.noja-test create mode 100644 tests/runtime/tcase_001.noja-test create mode 100644 tests/runtime/tcase_002.noja-test create mode 100644 tests/runtime/tcase_003.noja-test create mode 100644 tests/runtime/tcase_004.noja-test create mode 100644 tests/runtime/tcase_005.noja-test create mode 100644 tests/runtime/tcase_006.noja-test create mode 100644 tests/runtime/tcase_007.noja-test create mode 100644 tests/runtime/tcase_008.noja-test create mode 100644 tests/runtime/tcase_009.noja-test create mode 100644 tests/runtime/tcase_010.noja-test create mode 100644 tests/runtime/tcase_011.noja-test create mode 100644 tests/runtime/tcase_012.noja-test delete mode 100644 tests/suite/Testcase_000_000 delete mode 100644 tests/suite/Testcase_001_000 delete mode 100644 tests/suite/Testcase_001_007 delete mode 100644 tests/suite/Testcase_001_008 delete mode 100644 tests/suite/Testcase_003_000 delete mode 100644 tests/test.noja diff --git a/examples/http_server/main.noja b/examples/http_server/main.noja old mode 100755 new mode 100644 index d0235af..5c9aa14 --- a/examples/http_server/main.noja +++ b/examples/http_server/main.noja @@ -168,4 +168,4 @@ router->plug("/logout", { } }); -error(serve("127.0.0.1", 8080, router)); +error(serve("127.0.0.1", 8080, router)); \ No newline at end of file diff --git a/report_test_suite_coverage.sh b/report_test_suite_coverage.sh index 8331060..5e7e52f 100755 --- a/report_test_suite_coverage.sh +++ b/report_test_suite_coverage.sh @@ -1,4 +1,4 @@ make -B BUILD_MODE=COVERAGE CC=gcc -./test tests/suite +./test tests/compiler/ tests/runtime/ make report firefox report/index.html \ No newline at end of file diff --git a/src/lib/assembler/assemble.c b/src/lib/assembler/assemble.c index 89ec85c..1fd15ee 100644 --- a/src/lib/assembler/assemble.c +++ b/src/lib/assembler/assemble.c @@ -107,12 +107,57 @@ static bool parseStringOperand(Context *ctx, Error *error, BPAlloc *alloc, Opera assert(ctx->cur < ctx->len && ctx->str[ctx->cur] == '"'); ctx->cur += 1; - size_t literal_offset = ctx->cur; + char buffer[1024]; + size_t used = 0; - // For now do a dumb copy into the buffer - // without considering special characters. - while(ctx->cur < ctx->len && ctx->str[ctx->cur] != '"') - ctx->cur += 1; + do { + + size_t offset = ctx->cur; + while (ctx->cur < ctx->len && ctx->str[ctx->cur] != '\\' && ctx->str[ctx->cur] != '"') + ctx->cur++; + size_t length = ctx->cur - offset; + + if (used + length > sizeof(buffer)) { + *ctx->error_offset = ctx->cur; + Error_Report(error, ErrorType_INTERNAL, "Buffer is too short to hold string literal"); + return false; + } + memcpy(buffer + used, ctx->str + offset, length); + used += length; + + if (ctx->cur < ctx->len && ctx->str[ctx->cur] == '\\') { + + ctx->cur++; + if (ctx->cur == ctx->len) { + *ctx->error_offset = ctx->cur; + Error_Report(error, ErrorType_SYNTAX, "End of source inside a string literal"); + return false; + } + + char c; + switch (ctx->str[ctx->cur]) { + case 'n': c = '\n'; break; + case 't': c = '\t'; break; + case 'r': c = '\r'; break; + case '"': c = '"'; break; + case '\\': c = '\\'; break; + default: + *ctx->error_offset = ctx->cur; + Error_Report(error, ErrorType_SYNTAX, "End of source inside a string literal"); + return false; + } + + if (used + 1 > sizeof(buffer)) { + *ctx->error_offset = ctx->cur; + Error_Report(error, ErrorType_INTERNAL, "Buffer is too short to hold string literal"); + return false; + } + buffer[used++] = c; + + ctx->cur++; + } + + } while (ctx->cur < ctx->len && ctx->str[ctx->cur] != '"'); if(ctx->cur == ctx->len) { *ctx->error_offset = ctx->cur; @@ -120,21 +165,18 @@ static bool parseStringOperand(Context *ctx, Error *error, BPAlloc *alloc, Opera return false; } - size_t literal_length = ctx->cur - literal_offset; - // Skip the ending double quotes. assert(ctx->cur < ctx->len && ctx->str[ctx->cur] == '"'); ctx->cur += 1; - char *copy = BPAlloc_Malloc(alloc, literal_length+1); + char *copy = BPAlloc_Malloc(alloc, used+1); if(copy == NULL) { *ctx->error_offset = ctx->cur; Error_Report(error, ErrorType_INTERNAL, "No memory"); return false; } - - memcpy(copy, ctx->str + literal_offset, literal_length); - copy[literal_length] = '\0'; + memcpy(copy, buffer, used); + copy[used] = '\0'; op->type = OPTP_STRING; op->as_string = copy; diff --git a/src/lib/builtins/basic.c b/src/lib/builtins/basic.c index 3d2ca18..789947f 100644 --- a/src/lib/builtins/basic.c +++ b/src/lib/builtins/basic.c @@ -115,7 +115,7 @@ static int bin_print(Runtime *runtime, Object **argv, unsigned int argc, Object UNUSED(error); for(int i = 0; i < (int) argc; i += 1) - Object_Print(argv[i], stdout); + Object_Print(argv[i], Runtime_GetOutputStream(runtime)); return 0; } @@ -178,7 +178,7 @@ static int bin_input(Runtime *runtime, Object **argv, unsigned int argc, Object while(1) { - char c = getc(stdin); + char c = getc(Runtime_GetInputStream(runtime)); if(c == '\n') break; diff --git a/src/lib/compiler/parse.c b/src/lib/compiler/parse.c index e459e20..b5b0267 100644 --- a/src/lib/compiler/parse.c +++ b/src/lib/compiler/parse.c @@ -446,7 +446,7 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error, int *error_offset) #ifdef DEBUG token_dest = fopen("tokens.txt", "wb"); #endif - + AST *ast = BPAlloc_Malloc(alloc, sizeof(AST)); if(ast == NULL) diff --git a/src/lib/runtime.c b/src/lib/runtime.c index b7dc696..3f1110a 100644 --- a/src/lib/runtime.c +++ b/src/lib/runtime.c @@ -82,6 +82,10 @@ struct xRuntime { Heap *heap; TimingTable *timing; + FILE *stdin; + FILE *stdout; + FILE *stderr; + FailedFrame failed_frame; }; @@ -112,12 +116,15 @@ RuntimeConfig Runtime_GetDefaultConfigs() .stack = 1024, .callback = { .func = NULL, .data = NULL }, .time = false, + .stdin = stdin, + .stdout = stdout, + .stderr = stderr, }; } Stack *Runtime_GetStack(Runtime *runtime) { - return Stack_Copy(runtime->stack, 1); + return runtime->stack; } Heap *Runtime_GetHeap(Runtime *runtime) @@ -352,6 +359,10 @@ Runtime *Runtime_New(RuntimeConfig config) runtime->builtins = NULL; runtime->frame = NULL; runtime->depth = 0; + + runtime->stdin = config.stdin; + runtime->stderr = config.stderr; + runtime->stdout = config.stdout; return runtime; } @@ -367,6 +378,21 @@ void Runtime_Free(Runtime *runtime) free(runtime); } +FILE *Runtime_GetErrorStream(Runtime *runtime) +{ + return runtime->stderr; +} + +FILE *Runtime_GetOutputStream(Runtime *runtime) +{ + return runtime->stdout; +} + +FILE *Runtime_GetInputStream(Runtime *runtime) +{ + return runtime->stdin; +} + _Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj) { ASSERT(runtime != NULL); diff --git a/src/lib/runtime.h b/src/lib/runtime.h index e563fd8..eeb1d56 100644 --- a/src/lib/runtime.h +++ b/src/lib/runtime.h @@ -51,12 +51,17 @@ typedef struct { bool time; size_t heap; size_t stack; + FILE *stdin; + FILE *stderr; + FILE *stdout; RuntimeCallback callback; } RuntimeConfig; Runtime* Runtime_New(RuntimeConfig config); void Runtime_Free(Runtime *runtime); - +FILE *Runtime_GetErrorStream(Runtime *runtime); +FILE *Runtime_GetInputStream(Runtime *runtime); +FILE *Runtime_GetOutputStream(Runtime *runtime); bool Runtime_plugDefaultBuiltins(Runtime *runtime, Error *error); bool Runtime_plugBuiltinsFromString(Runtime *runtime, const char *string, Error *error); bool Runtime_plugBuiltinsFromFile(Runtime *runtime, const char *file, Error *error); diff --git a/src/lib/utils/stack.c b/src/lib/utils/stack.c index 27fbec7..f6c5ad9 100644 --- a/src/lib/utils/stack.c +++ b/src/lib/utils/stack.c @@ -40,11 +40,6 @@ struct xStack { void *body[]; }; -_Bool Stack_IsReadOnlyCopy(Stack *s) -{ - return (uintptr_t) s & (uintptr_t) 1; -} - void *Stack_New(int size) { if(size < 0) @@ -63,18 +58,10 @@ void *Stack_New(int size) return s; } -static Stack *unmark(Stack *s) -{ - return (Stack*) ((intptr_t) s & ~ (intptr_t) 1); -} - void *Stack_Top(Stack *s, int n) { ASSERT(n <= 0); - // Remove readonly bit. - s = unmark(s); - if(s->used == 0) return NULL; @@ -88,12 +75,6 @@ void **Stack_TopRef(Stack *s, int n) { ASSERT(n <= 0); - if(Stack_IsReadOnlyCopy(s)) - return NULL; - - // Remove readonly bit. - s = unmark(s); - if(s->used == 0) return NULL; @@ -106,9 +87,6 @@ void **Stack_TopRef(Stack *s, int n) _Bool Stack_Pop(Stack *s, unsigned int n) { - if(Stack_IsReadOnlyCopy(s)) - return 0; - if(s->used < n) return 0; @@ -121,9 +99,6 @@ _Bool Stack_Push(Stack *s, void *item) ASSERT(s != NULL); ASSERT(item != NULL); - if(Stack_IsReadOnlyCopy(s)) - return 0; - if(s->used == s->size) return 0; @@ -132,51 +107,26 @@ _Bool Stack_Push(Stack *s, void *item) return 1; } -Stack *Stack_Copy(Stack *s, _Bool readonly) +Stack *Stack_Copy(Stack *s) { - if(Stack_IsReadOnlyCopy(s)) - { - // Reference is readonly, - // so the copy must be - // readonly. - readonly = 1; - - // Remove readonly bit. - s = unmark(s); - } - s->refs += 1; - - if(readonly) - return (Stack*) ((uintptr_t) s | (intptr_t) 1); - else - return s; + return s; } void Stack_Free(Stack *s) { - // Remove readonly bit. - s = unmark(s); - s->refs -= 1; ASSERT(s->refs >= 0); - if(s->refs == 0) free(s); } unsigned int Stack_Size(Stack *s) { - // Remove readonly bit. - s = unmark(s); - return s->used; } unsigned int Stack_Capacity(Stack *s) { - // Remove readonly bit. - s = unmark(s); - return s->size; } \ No newline at end of file diff --git a/src/lib/utils/stack.h b/src/lib/utils/stack.h index 8f85d9b..564138f 100644 --- a/src/lib/utils/stack.h +++ b/src/lib/utils/stack.h @@ -37,8 +37,7 @@ _Bool Stack_Pop(Stack *s, unsigned int n); _Bool Stack_Push(Stack *s, void *item); void Stack_Free(Stack *s); unsigned int Stack_Size(Stack *s); -Stack *Stack_Copy(Stack *s, _Bool readonly); +Stack *Stack_Copy(Stack *s); void **Stack_TopRef(Stack *s, int n); unsigned int Stack_Capacity(Stack *s); -_Bool Stack_IsReadOnlyCopy(Stack *s); #endif \ No newline at end of file diff --git a/src/test/error.c b/src/test/error.c new file mode 100644 index 0000000..4b1cca4 --- /dev/null +++ b/src/test/error.c @@ -0,0 +1,14 @@ +#include "error.h" + +const char *getErrorString(ErrorID error) +{ + switch (error) { + case ErrorID_VOID: return "No error"; + case ErrorID_OUTOFMEMORY: return "Out of memory"; + case ErrorID_DUPLFIELD: return "Duplicate field"; + case ErrorID_BADSYNTAX_NOAT: return "Missing '@' character"; + case ErrorID_BADSYNTAX_NONAME: return "Missing field name"; + case ErrorID_BADSYNTAX_NOFIELD: return "Missing field"; + } + return "???"; +} \ No newline at end of file diff --git a/src/test/error.h b/src/test/error.h new file mode 100644 index 0000000..c01f739 --- /dev/null +++ b/src/test/error.h @@ -0,0 +1,14 @@ +#ifndef TEST_ERROR_H +#define TEST_ERROR_H + +typedef enum { + ErrorID_VOID, + ErrorID_OUTOFMEMORY, + ErrorID_DUPLFIELD, + ErrorID_BADSYNTAX_NONAME, + ErrorID_BADSYNTAX_NOAT, + ErrorID_BADSYNTAX_NOFIELD, +} ErrorID; + +const char *getErrorString(ErrorID error); +#endif \ No newline at end of file diff --git a/src/test/error.o b/src/test/error.o new file mode 100644 index 0000000000000000000000000000000000000000..1e7b974c868bc345de45a86ddccdc9704cd1c9bb GIT binary patch literal 4216 zcmbtXU2GIp6uz^wOIsI8q2;Fmb;L^f+i7bG0!n{q3$1B)3A9EK(oUz--Id*$GBXP; z5iuH#4QWDsP#=8pL1SWKjNt)a42ds3`eMQ(51MFv(fFoK@SHp6w8QQ2q9>Vq&iU^7 zn>+WOyL)qJ^i)dI1d}Fu#G1ya5O<$gll!FDCw7SK;;+q5{XH?f_{-vrm3MBeWUgJf zHMBCk)bcKx3@>Gn-Abp1KOSD%CL!&|o`(-;;`eSA4zjR^g;o}tSg0f6()W4KaD3nM zMWGfN-mFn|s-C|f25WPbvTcQqFRdpVP zL~m~|R{9va19)1_)yrktsM>`wAXS&10yULxM5e<-qbB8)9CbOS<(LuabRAmBg-d1i z9LO6G(DY58At&N2+9!xg7fo*~f}C2ei2C|(KuT-Uv*Anh(Y9#MH8yAU#$AnDw5@eb zJFqORC!5WVG#}5tm_3%&nxVLTLT}ui1>ZK2&Gvvfl(HSL$YcaeHkev(D+BGVBh47D zZ|6rRTQNXgCT5)4DMbBd2!wtOdj&Fa2%Z#HB<>(zo>&AnE3XL6x6 zU2y`K3_{DkoSXB#(6K|$&jleEqE|FwSFE7K(`CmL^#C9mpq*xvPW(2@6Ew>kpf?g*U# zKIrLzf#b%$iRqdf)}n>Ub=9QS_2%=PW@oqAwLik;nQFps2M;VIZjpO<&g8KG-U1Jj zcKxi-=9{!#8|&(C!zS1b7(PgH3k@|ky_Xu;v>|mFEFwH<#KW5we?Cl_(-S)&*22|1 z>ZMahcoao@d5l#UaCu-8@P>650=kGb-=OB*HFg!@S6Byr(2L(vp-oP2}C%je8Vl(Ep9s$^}kG`A)?$ zLuWn|=8P3u!ki8QVM^5ZB19@P&UCFfS$1bVFqE=2J?%SJ$(A7Ba*Gc8M_8roI_v^T zg=u@$ssned>B3ECLf?m*4sJfui*C(?J8;hN!v%`%lqP3={LS`%$$$X3X7M$~n0+_^ z@pq22$d+Z~yWqk5sSlnw%~Qbp1mb?eJbV@HBz!O7>Wy-T=2eC<;&ccUjQL;v@f@jp z2IF)7H&BTYzH6MiKuLQ4Gt^{mlQF(O_F47)2LMyw30*n~yo*YVRNEeyOUnO%@_$VZ zm>(fEKlWKQCP3m>0vAzKE?caSE%{l1`K0zoghkz{@Doenv#%J=1X9mb?rC-!5GeU;_7-TUMp$52*nKL-r=1uYkvNMe73bY}eitbYdr##H^kp!`SKkhtpq zE#OJ(e?MXU@mCo8^LI(gjj0|`{ +#include +#include +#include +#include "field.h" + +static void freeFieldName(NojaTestField *field) +{ + if (field->name != field->name_maybe) + free(field->name); +} + +static void freeFieldBody(NojaTestField *field) +{ + if (field->body != field->body_maybe) + free(field->body); +} + +void freeField(NojaTestField *field) +{ + freeFieldName(field); + freeFieldBody(field); +} + +static ErrorID setFieldName(NojaTestField *field, const char *str, size_t len) +{ + if (len < sizeof(field->name_maybe)) + field->name = field->name_maybe; + else { + field->name = malloc(len+1); + if (field->name == NULL) + return ErrorID_OUTOFMEMORY; + } + memcpy(field->name, str, len); + field->name[len] = '\0'; + return ErrorID_VOID; +} + +static ErrorID setFieldBody(NojaTestField *field, const char *str, size_t len) +{ + if (len < sizeof(field->body_maybe)) + field->body = field->body_maybe; + else { + field->body = malloc(len+1); + if (field->body == NULL) + return ErrorID_OUTOFMEMORY; + } + memcpy(field->body, str, len); + field->body[len] = '\0'; + return ErrorID_VOID; +} + +static int isFieldNameCharacter(int c) +{ + return isalpha(c) || c == '_'; +} + +static ErrorID parseFieldName(NojaTestScanner *scanner, NojaTestField *field) +{ + size_t offset; + size_t length; + + offset = scanner->cur; + consumeCharactersThat(scanner, isFieldNameCharacter); + length = scanner->cur - offset; + + if (length == 0) + return ErrorID_BADSYNTAX_NONAME; // Missing field name token after '@' + + ErrorID error = setFieldName(field, scanner->src + offset, length); + if (error != ErrorID_VOID) return error; + + return ErrorID_VOID; +} + +static bool parseFieldBody(NojaTestScanner *scanner, NojaTestField *field) +{ + size_t offset; + size_t length; + + consumeCharactersThat(scanner, isspace); + + bool no_term; + char term; + + if (ifFollowsConsumeCharacter(scanner, '[')) { + no_term = false; + term = ']'; + } else if (ifFollowsConsumeCharacter(scanner, '{')) { + no_term = false; + term = '}'; + } else + no_term = true; + + offset = scanner->cur; + while (!noMoreCharacters(scanner) && !followsCharacter(scanner, '@') && (no_term || !followsCharacter(scanner, term))) + scanner->cur++; + length = scanner->cur - offset; + if (!no_term) + ifFollowsConsumeCharacter(scanner, term); + + return setFieldBody(field, scanner->src + offset, length); +} + +ErrorID findField(NojaTestScanner *scanner) +{ + consumeCharactersThat(scanner, isspace); + bool at_follows = ifFollowsConsumeCharacter(scanner, '@'); + if (!at_follows) { + if (noMoreCharacters(scanner)) + return ErrorID_BADSYNTAX_NOFIELD; + return ErrorID_BADSYNTAX_NOAT; + } + return ErrorID_VOID; +} + +// Returns: +// 0 if there are no more fields +// -1 on error +// 1 if a field was parsed +ErrorID parseField(NojaTestScanner *scanner, NojaTestField *field) +{ + ErrorID error; + + error = findField(scanner); + if (error != ErrorID_VOID) + return error; + + error = parseFieldName(scanner, field); + if (error != ErrorID_VOID) + return error; + + error = parseFieldBody(scanner, field); + if (error != ErrorID_VOID) { + freeFieldName(field); + return error; + } + + return ErrorID_VOID; +} diff --git a/src/test/field.h b/src/test/field.h new file mode 100644 index 0000000..237a965 --- /dev/null +++ b/src/test/field.h @@ -0,0 +1,20 @@ +#ifndef TEST_FIELD_H +#define TEST_FIELD_H + +#include +#include "error.h" +#include "scanner.h" + +typedef struct { + char name_maybe[128]; + char body_maybe[512]; + char *name; + char *body; + size_t name_len; + size_t body_len; +} NojaTestField; + +void freeField(NojaTestField *field); +ErrorID parseField(NojaTestScanner *scanner, NojaTestField *field); + +#endif \ No newline at end of file diff --git a/src/test/field.o b/src/test/field.o new file mode 100644 index 0000000000000000000000000000000000000000..91bb310298a47e4cceb29cf9ca2b1754e5adc36c GIT binary patch literal 10288 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 -#include -#include -#include -#include -#include -#include "../lib/executable.h" -#include "../lib/utils/source.h" -#include "../lib/compiler/compile.h" -#include "../lib/assembler/assemble.h" - -//Regular text -#define BLK "\e[0;30m" -#define RED "\e[0;31m" -#define GRN "\e[0;32m" -#define YEL "\e[0;33m" -#define BLU "\e[0;34m" -#define MAG "\e[0;35m" -#define CYN "\e[0;36m" -#define WHT "\e[0;37m" - -//Regular bold text -#define BBLK "\e[1;30m" -#define BRED "\e[1;31m" -#define BGRN "\e[1;32m" -#define BYEL "\e[1;33m" -#define BBLU "\e[1;34m" -#define BMAG "\e[1;35m" -#define BCYN "\e[1;36m" -#define BWHT "\e[1;37m" - -//Regular underline text -#define UBLK "\e[4;30m" -#define URED "\e[4;31m" -#define UGRN "\e[4;32m" -#define UYEL "\e[4;33m" -#define UBLU "\e[4;34m" -#define UMAG "\e[4;35m" -#define UCYN "\e[4;36m" -#define UWHT "\e[4;37m" - -//Regular background -#define BLKB "\e[40m" -#define REDB "\e[41m" -#define GRNB "\e[42m" -#define YELB "\e[43m" -#define BLUB "\e[44m" -#define MAGB "\e[45m" -#define CYNB "\e[46m" -#define WHTB "\e[47m" - -//High intensty background -#define BLKHB "\e[0;100m" -#define REDHB "\e[0;101m" -#define GRNHB "\e[0;102m" -#define YELHB "\e[0;103m" -#define BLUHB "\e[0;104m" -#define MAGHB "\e[0;105m" -#define CYNHB "\e[0;106m" -#define WHTHB "\e[0;107m" - -//High intensty text -#define HBLK "\e[0;90m" -#define HRED "\e[0;91m" -#define HGRN "\e[0;92m" -#define HYEL "\e[0;93m" -#define HBLU "\e[0;94m" -#define HMAG "\e[0;95m" -#define HCYN "\e[0;96m" -#define HWHT "\e[0;97m" - -//Bold high intensity text -#define BHBLK "\e[1;90m" -#define BHRED "\e[1;91m" -#define BHGRN "\e[1;92m" -#define BHYEL "\e[1;93m" -#define BHBLU "\e[1;94m" -#define BHMAG "\e[1;95m" -#define BHCYN "\e[1;96m" -#define BHWHT "\e[1;97m" - -//Reset -#define reset "\e[0m" -#define CRESET "\e[0m" -#define COLOR_RESET "\e[0m" - -// NOTE: From https://gist.github.com/RabaDabaDoba/145049536f815903c79944599c6f952a - -typedef enum { - TokenType_END, - TokenType_TEXT, - TokenType_DIRECTIVE_SOURCE, - TokenType_DIRECTIVE_BYTECODE, -} TokenType; - -typedef struct { - TokenType type; - size_t offset; - size_t length; -} Token; - -static bool startsWithSourceDirective(const char *str, size_t len) -{ - return (((7 < len && !isalpha(str[7])) || 7 == len) - && str[0] == '#' && str[1] == 's' - && str[2] == 'o' && str[3] == 'u' - && str[4] == 'r' && str[5] == 'c' - && str[6] == 'e'); -} - -static bool startsWithBytecodeDirective(const char *str, size_t len) -{ - return (((9 < len && !isalpha(str[9])) || 9 == len) - && str[0] == '#' && str[1] == 'b' - && str[2] == 'y' && str[3] == 't' - && str[4] == 'e' && str[5] == 'c' - && str[6] == 'o' && str[7] == 'd' - && str[8] == 'e'); -} - -static bool startsWithDirective(const char *str, size_t len) -{ - return startsWithSourceDirective(str, len) - || startsWithBytecodeDirective(str, len); -} - -static Token nextToken(const char *str, size_t len, size_t *cur_) -{ - size_t cur = *cur_; - - while(cur < len && isspace(str[cur])) - cur += 1; - - Token token; - if(cur == len) { - token.type = TokenType_END; - token.offset = cur; - token.length = 0; - } else if(startsWithSourceDirective(str + cur, len - cur)) { - token.type = TokenType_DIRECTIVE_SOURCE; - token.offset = cur; - cur += strlen("#source"); - token.length = cur - token.offset; - } else if(startsWithBytecodeDirective(str + cur, len - cur)) { - token.type = TokenType_DIRECTIVE_BYTECODE; - token.offset = cur; - cur += strlen("#bytecode"); - token.length = cur - token.offset; - } else { - token.type = TokenType_TEXT; - token.offset = cur; - - while(1) { - // Consume all characters until - // the next '#'. - while(cur < len && str[cur] != '#') - cur += 1; - - if(cur == len) - break; - - // If it's the start of a directive, - // stop the loop. If it was not, skip - // the '#'. - - if(startsWithDirective(str + cur, len - cur)) - break; - - cur += 1; // Skip the '#' - } - - token.length = cur - token.offset; - } - *cur_ = cur; - return token; -} - -typedef struct { - Source *source; - Source *bytecode; -} TestCase; - -static bool parseTestCaseSource(Source *source, TestCase *testcase) -{ - const char *str = Source_GetBody(source); - size_t len = Source_GetSize(source); - assert(str != NULL); - - bool no_source = true; - size_t source_offset; - size_t source_length; - - bool no_bytecode = true; - size_t bytecode_offset; - size_t bytecode_length; - - size_t cur = 0; - while(1) { - Token token = nextToken(str, len, &cur); - - if(token.type == TokenType_END) - break; - - if(token.type == TokenType_TEXT) { - fprintf(stderr, RED "Error" CRESET " :: Expected a directive at offset %ld\n", token.offset); - return false; - } - - assert(token.type == TokenType_DIRECTIVE_SOURCE - || token.type == TokenType_DIRECTIVE_BYTECODE); - - Token directive = token; - - size_t directive_body_offset; - size_t directive_body_length; - - size_t backup = cur; - token = nextToken(str, len, &cur); - switch(token.type) { - case TokenType_END: - case TokenType_DIRECTIVE_SOURCE: - case TokenType_DIRECTIVE_BYTECODE: - // Right after the previous directive - // there's either the end of the file - // or another directive. We assume - // that the directive is followed by - // and empty string. - directive_body_offset = token.offset; - directive_body_length = 0; - - // Put the cursor back so that this - // token is tokenized again at the - // start of the next iteration. - cur = backup; - break; - - case TokenType_TEXT: - directive_body_offset = token.offset; - directive_body_length = token.length; - break; - } - - if(directive.type == TokenType_DIRECTIVE_SOURCE) { - - if(no_source == false) { - fprintf(stderr, RED "Error" CRESET " :: #source directive specified twice.\n"); - return false; - } - - no_source = false; - source_offset = directive_body_offset; - source_length = directive_body_length; - - } else { - assert(directive.type == TokenType_DIRECTIVE_BYTECODE); - - if(no_bytecode == false) { - fprintf(stderr, RED "Error" CRESET " :: #bytecode directive specified twice.\n"); - return false; - } - - no_bytecode = false; - bytecode_offset = directive_body_offset; - bytecode_length = directive_body_length; - } - } - - if(no_source == true && no_bytecode == true) { - fprintf(stderr, RED "Error" CRESET " :: Missing both #source and #bytecode directives.\n"); - return false; - } - if(no_source == true) { - fprintf(stderr, RED "Error" CRESET " :: Missing #source directive.\n"); - return false; - } - if(no_bytecode == true) { - fprintf(stderr, RED "Error" CRESET " :: Missing #bytecode directive.\n"); - return false; - } - - { - Error error; - Error_Init(&error); - - testcase->source = Source_FromString("", str + source_offset, source_length, &error); - if(testcase->source == NULL) { - Error_Print(&error, ErrorType_UNSPECIFIED, stderr); - Error_Free(&error); - return false; - } - - testcase->bytecode = Source_FromString("", str + bytecode_offset, bytecode_length, &error); - if(testcase->bytecode == NULL) { - Error_Print(&error, ErrorType_UNSPECIFIED, stderr); - Source_Free(testcase->source); - Error_Free(&error); - return false; - } - Error_Free(&error); - } - return true; -} - -static Executable *compile_source_and_print_error_on_failure(Source *src) -{ - int error_offset; - Error error; - Error_Init(&error); - Executable *exe = compile(src, &error, &error_offset); - if(exe == NULL) { - Error_Print(&error, ErrorType_UNSPECIFIED, stderr); - Error_Free(&error); - return NULL; - } - Error_Free(&error); - return exe; -} - -typedef enum { - TestResult_PASSED, - TestResult_FAILED, - TestResult_ABORT, -} TestResult; - -static TestResult runTest(const char *file) -{ - Source *source; - { - Error error; - Error_Init(&error); - - source = Source_FromFile(file, &error); - if(source == NULL) { - Error_Print(&error, ErrorType_UNSPECIFIED, stderr); - Error_Free(&error); - return TestResult_ABORT; - } - Error_Free(&error); - } - - TestCase testcase; - { - if(!parseTestCaseSource(source, &testcase)) { - Source_Free(source); - return TestResult_ABORT; - } - } - - Source_Free(source); - - Executable *exe1 = compile_source_and_print_error_on_failure(testcase.source); - if(exe1 == NULL) { - Source_Free(testcase.source); - Source_Free(testcase.bytecode); - return TestResult_ABORT; - } - - Executable *exe2; - { - Error error; - Error_Init(&error); - int error_offset; - exe2 = assemble(testcase.bytecode, &error, &error_offset); - if(exe2 == NULL) { - Error_Print(&error, ErrorType_UNSPECIFIED, stderr); - Error_Free(&error); - Executable_Free(exe1); - Source_Free(testcase.source); - Source_Free(testcase.bytecode); - return TestResult_ABORT; - } - - Error_Free(&error); - } - - bool passed = Executable_Equiv(exe1, exe2, stderr, " " WHT "Log" CRESET " :: "); - - Executable_Free(exe1); - Executable_Free(exe2); - Source_Free(testcase.source); - Source_Free(testcase.bytecode); - - return passed - ? TestResult_PASSED - : TestResult_FAILED; -} - -static void runTestSuite(const char *folder) -{ - DIR *handle = opendir(folder); - if(handle == NULL) { - fprintf(stderr, RED "Error" CRESET " :: Failed to open folder '%s'.\n", folder); - return; - } - - size_t total_tests = 0; - size_t passed_tests = 0; - size_t failed_tests = 0; - size_t aborted_tests = 0; - size_t skipped_files = 0; - - size_t folder_len = strlen(folder); - - // If the folder path ends with a "/", - // but it's not the first character, - // then pop it. - if(folder_len > 0 && folder[folder_len-1] == '/') - folder_len -= 1; - - // Now we know for sure that the provided - // folder needs a trailing "/". - - char test_path[1024]; - - // Make sure the buffer can contain the - // folder's name (plus the trailing "/" - // and the null byte). - if(folder_len+2 > sizeof(test_path)) { - fprintf(stderr, RED "Error" CRESET " :: Suite folder name is too long\n"); - return; - } - memcpy(test_path, folder, folder_len); - test_path[folder_len] = '/'; - test_path[folder_len+1] = '\0'; - - // Now count the "/". - folder_len += 1; - - struct dirent *dir; - while((dir = readdir(handle)) != NULL) { - - const char *name = dir->d_name; - size_t name_len = strlen(name); - - if(dir->d_type != DT_REG) { - fprintf(stderr, " " WHT "Log" CRESET " :: Skipping '%s' (not a regular file).\n", name); - skipped_files += 1; - continue; - } - - if(folder_len + name_len >= sizeof(test_path)) { - fprintf(stderr, " " WHT "Log" CRESET " :: Skipping '%s' (path is too long).\n", name); - skipped_files += 1; - continue; - } - - // Remove the previous file's name - // by truncating the parent folder - // name with a null byte. - test_path[folder_len] = '\0'; - strcat(test_path, name); - - TestResult res = runTest(test_path); - switch(res) { - - case TestResult_PASSED: - fprintf(stdout, " " BLU "Test" CRESET " :: Passed (%s)\n", name); - passed_tests += 1; - break; - - case TestResult_FAILED: - fprintf(stdout, " " YEL "Test" CRESET " :: Failed (%s)\n", name); - failed_tests += 1; - break; - - case TestResult_ABORT: - fprintf(stdout, " " RED "Test" CRESET " :: Aborted (%s)\n", name); - aborted_tests += 1; - break; - } - total_tests += 1; - } - - fprintf(stdout, "\n"); - fprintf(stdout, "@-----SUMMARY-----@\n"); - fprintf(stdout, "| Total : %-3ld |\n", total_tests); - fprintf(stdout, "| Passed : %-3ld |\n", passed_tests); - fprintf(stdout, "| Failed : %-3ld |\n", failed_tests); - fprintf(stdout, "| Aborted : %-3ld |\n", aborted_tests); - fprintf(stdout, "| Skipped : %-3ld |\n", skipped_files); - fprintf(stdout, "@-----------------@\n"); - - closedir(handle); -} - -int main(int argc, char **argv) -{ - if(argc < 2) { - fprintf(stderr, RED "Error" CRESET " :: No test suite folder name was provided.\n"); - fprintf(stderr, WHT "Usage" CRESET " :: %s \n", argv[0]); - return -1; - } - - const char *folder = argv[1]; - runTestSuite(folder); - return 0; +#include +#include +#include +#include "main.h" +#include "run.h" +#include "../lib/run.h" +#include "../lib/runtime.h" +#include "../lib/executable.h" +#include "../lib/compiler/compile.h" +#include "../lib/assembler/assemble.h" + +static TestResult runCompilerTest(const char *inputs[static 2], FILE *log_stream); +static TestResult runRuntimeTest(const char *inputs[static 2], FILE *log_stream); + +static const TestType test_types[] = { + {.name="compiler", .routine=runCompilerTest, .fields=(const char*[]){"source", "bytecode", NULL}}, + {.name="runtime", .routine=runRuntimeTest, .fields=(const char*[]){"bytecode", "output", NULL}}, + {.name=NULL, .fields=NULL, .routine=NULL}, +}; + +int main(int argc, char **argv) +{ + TestBatchResults results = {.passed=0, .failed=0, .aborted=0, .batch_aborted=false}; + for (int i = 1; i < argc; i++) { + + const char *dir_name = argv[i]; + + TestBatchResults temp = runTestDirectory(test_types, dir_name, stderr); + if (temp.batch_aborted) + fprintf(stderr, "Error: Failed to run test batch\n"); + else { + results.passed += temp.passed; + results.failed += temp.failed; + results.aborted += temp.aborted; + } + } + fprintf(stderr, "SUMMARY: %ld passed, %ld failed, %ld aborted\n", + results.passed, results.failed, results.aborted); + return 0; +} + +static TestResult runCompilerTest(const char *inputs[static 2], FILE *log_stream) +{ + Error error; + Error_Init(&error); + + Source *srcA = Source_FromString("", inputs[0], -1, &error); + if (srcA == NULL) { + Error_Print(&error, ErrorType_UNSPECIFIED, log_stream); + Error_Free(&error); + return TestResult_ABORTED; + } + Source *srcB = Source_FromString("", inputs[1], -1, &error); + if (srcA == NULL) { + Error_Print(&error, ErrorType_UNSPECIFIED, log_stream); + Error_Free(&error); + Source_Free(srcA); + return TestResult_ABORTED; + } + + int error_offset; + Executable *exeA = compile(srcA, &error, &error_offset); + if (exeA == NULL) { + Error_Print(&error, ErrorType_UNSPECIFIED, log_stream); + Error_Free(&error); + Source_Free(srcA); + Source_Free(srcB); + return TestResult_ABORTED; + } + + Executable *exeB = assemble(srcB, &error, &error_offset); + if (exeB == NULL) { + Error_Print(&error, ErrorType_UNSPECIFIED, log_stream); + Error_Free(&error); + Source_Free(srcA); + Source_Free(srcB); + Executable_Free(exeA); + return TestResult_ABORTED; + } + + bool passed = Executable_Equiv(exeA, exeB, log_stream, "Info: "); + + Source_Free(srcA); + Source_Free(srcB); + Executable_Free(exeA); + Executable_Free(exeB); + return passed ? TestResult_PASSED : TestResult_FAILED; +} + +static TestResult runRuntimeTest(const char *inputs[static 2], FILE *log_stream) +{ + char buffer[1024]; + + FILE *output_stream = fmemopen(buffer, sizeof(buffer), "wb"); + if (output_stream == NULL) + return TestResult_ABORTED; + + RuntimeConfig config = Runtime_GetDefaultConfigs(); + config.stdout = output_stream; + + Runtime *runtime = Runtime_New(config); + if (runtime == NULL) { + fclose(output_stream); + return TestResult_ABORTED; + } + + Error error; + Error_Init(&error); + + if (!Runtime_plugDefaultBuiltins(runtime, &error)) { + Error_Print(&error, ErrorType_UNSPECIFIED, log_stream); + Error_Free(&error); + Runtime_PrintStackTrace(runtime, log_stream); + Runtime_Free(runtime); + fclose(output_stream); + return TestResult_ABORTED; + } + + if (!runBytecodeString(runtime, inputs[0], &error)) { + Error_Print(&error, ErrorType_UNSPECIFIED, log_stream); + Error_Free(&error); + Runtime_PrintStackTrace(runtime, log_stream); + Runtime_Free(runtime); + fclose(output_stream); + return TestResult_ABORTED; + } + fclose(output_stream); + + TestResult result; + if (!strcmp(buffer, inputs[1])) // No bounds checks + result = TestResult_PASSED; + else { + result = TestResult_FAILED; + fprintf(stderr, "Error: Expected output [%s] but got [%s]\n", inputs[1], buffer); + } + + Error_Free(&error); + Runtime_Free(runtime); + return result; } \ No newline at end of file diff --git a/src/test/main.h b/src/test/main.h new file mode 100644 index 0000000..7a349e2 --- /dev/null +++ b/src/test/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_H +#define MAIN_H +typedef enum { + TestResult_ABORTED, + TestResult_FAILED, + TestResult_PASSED, +} TestResult; +#endif \ No newline at end of file diff --git a/src/test/main.o b/src/test/main.o new file mode 100644 index 0000000000000000000000000000000000000000..7fa37a5b8f535ce1bf450463102b38b46a1c7e09 GIT binary patch literal 12512 zcmcIq4RBP~b-ue#i*~g_5|RuOn0TRJE7)2gA@di0^ka!t3<3+ufyD9iYWGRnu-aAL zzU9v*U=valnGEWb1Sd>_)5(-3?hKQZlwpiVI3c#{X%bJT6F2<{^;8}b(kXT_3FFqL z=bU@4bam0rc+%z$+IPS2o_o%@=l;BV@8fXC)=t0ACsgu@O=21;R){B7Oy^rD+aeZ< zTJf9mkG$6x8=Z_D{q>H~Lodcg^XHSXv7+U5AQKzyxYamu^w5ib@1EF+xmfE`CGsa8 z#C+_;MtoeS{8-2N*jP&ts=OK-BhlE2j-STH`d(Giqpy%;`S&}ne}2MS8XF5x#nCI5 zB9M6roz^wpSP>h`UyF@xdlQs^B9iVJy*aJ!BGxCJl#7iWx|NKr+CZ**0V;Uy2UG2P z`qxMN*rdzH-@ko3HhSR*JdBpcP8^${Lg{I2>=?<8fnTR&!5f!uLyC?5NcS{0dh9G# zJ9-%(BHtVvJ9PvJsqQ6oGsdkqOpxQhoQsaJv7-~g*oQE9PB+;8;SGWr@|E3@_D?|U zp^0b6=Mxk7P+~uxa(wjId1(_LBH!}|+XUU@{R|gMW^+M`=`LK;hS3895D9RE{6}njWpGaicfT&<>FFv9TkUQG@V`FTx-YHv$)F9*k|np-Q0qUn5WRc8E6bX0zDrFLIhS7{~10dSRKOI8I)iRfeH!M5~z`29f61h>j~6J z@G$}_CD=evEyusygJv>lb;k@7D9I4;5Nxi5g&NeMo+U>r(LOYm6j z831P`_%yk5PJ+in9@IH6fn5>@a8ZIM$hQdz`h(vD1wWLXG^e=s??8?QQ{etGdVd9j z4hRH;SWt!?hJKafut4_H09fqV>Fie^OS0cpvQ?r2D-@5Gy#!Q{I$JVdBu3`Prt`st zr8o%6J^=CGz~4L(x=uB(0voyoS*j9Tv=B>q)D>0GoT#h`%?WkG*rq0iiszv?gJ2~V z1Z7F6atJ^L_=6HveISKIHHuWDqfpWdc^bi?5^FK!LmBv~jD$)Eegz7oYbA|g^hUZ?(iA{2Pu5vQpi+Y7F!n>W1P{_w zsF7fG`0qhmWIkFgSyP4~jQAy5O98E8v@VD$R{F()D^Q^te;}|SbcH;nq4IA4Yj9ZI z_Q^(tm)86WI2v6=L98SB(&XK^;t*eU5WHRhhz6ujgo+_wi=w`g1;~f6@st+gukRk} zWXTBeI`sq4XC^^*k(6k_-nYhY9b~)(2ZA+z^PtqbB#e$*?caw7!0aT{aHO~0X48Te( z-K{8-=3Y3=coCLa<7W>qM(L*jOvgmFpql1~HGc81#PjF>5F+3oZvoS|_Lg1ciWKA` z5lZ8_@0;gaURD*h$`+N)^HmmCEPyISzD?n9xT|V?_+#O9VP6#(t`k<--7sE?mWgn9 z6Np1E&IeA4bb-j6awvhNfd$|V6GR4!LiY-MlvMewvT%4>Yk01vVJ%cHomL4WqY6ql zKwHXuzOE|tqI?PHX#ly3X077pS`?bM1R7IW<Adg;8jSRDtR-Y%MikZlhX@0-9$ie0S8hxwfGAV$|JL)m)3B z;sN-RLz&*sfMn7)0gA)tP1rM7VmpYn1aLZrbvFyhP<6wxS|&wHtKj)73SI`EP9 zcSG2SoR>^G1JNOLoAf{yf{^pve8RIkyS8=!0RwqD2Q^YzAYnS?4&-ddbX#t1A$4L0&@le^X3HK3`AZG zR0LlO1V0`KJ?vjv9Vqp$s1Epc2R{|O6bQT>sD3*T^fy!mLf;5}BTz9JSba87{Q^*R zlA1)W=9@s=$An~_*BPR!_5}idG9!8D&0OlBgLQI4u=(xJ4~UMb zh*0=-1v^@I?nDKkA0+Mmc+L?Jz&0`L!Huaskd6=LrhLLOJCS$6emXy#AzrzX%;uq=g`G_&F;Y1PYV#AOf+KZK zDW;=^Yzwq^IPUI&V+anljL2u$cXU9WCcqEZaa<>dk&(v|tZVmm@7&SR-qqO!af1<@ zNyOoVAuY|&GG)!~>hA66>2BRhuJ3bGo9j zXUDeI?%u9;HQDTRHnB&zS(u5?W*I)&adH^ht!>+Tdcj?2D+tN9h%McHk@m(lk#*7L z=*md_u$Rv`8wVY5CY1mfcN0S!VOgnP-5jYOjMNXra|besAvc@J=5zJ=%)V46Sx?g} z2ZcE=p4d}A;%4EL=Vje`nA_N$svwb$=Y~{qDw~0V#DIoHHUT~CsyK4DLU7ypw1{I~ z3m=XN97}4LQV~Xh=L)VQLLLN#8f(LN`h-YlA=cAtir^!n;PH^tdb+0%qP(pGCq%2P zsRozbmd&Q82MrB)m<6o@e%iPzX(&Sv?n@;dI~n)lBAIe+>U4WA1x{(xdUkhrZ|g2v z2w^sRj+=?6X$H38*;n>vPQV-*^o9gk9e@ES_G>eomWUHuSR-9~RjREKeh_+|Y3z zy2eQ-VFs%Sgp0S(0s)f>R=1oyhofV1QjniwOMCnJNL^olKI7%(;H+=V6Keci)5_?| z=4j(bC66xwI$Prb1Kt8Sr18Zv0j~|-nZqU)@|b)FdxUR)g>O-5aquL(h;W-mTQzuI zgFn$xR`CUY``kJHpMiud+kiYI+I^~W>t#O)$f7%b@%3CJ-no580T33x0cT0pl(#br zEo$9N4v{7I*LM_H^uC)(<37Wu@wf|7$r4yPGvVgbr|~PfxDK9vD7nU1?a0>x#&f`* zGmrhCk|pm96r6fmciw_fnI+E(Q*tU}iE@>l@wDKuIa{&>?Cxes*3@X2S!l@v*-R3U zB`WXW9s#BjTCCDF&O8cFI_Rnbex?iX2Mh2|7vS-*Fq{783h>Vt;J;gdzg&R-Ndf+! z3-E6j;NLC4zgK{_AjGq^x2ga?^)iHg!th8opGn$jc+U+P$r9TRUJMW8;0J>)H52gCraYGPo- zg{6D|D$z?4_G)`%JzDndu1w0~ca+`fW`}orAU-JHLiP@<%K1*%jZ6zd9@~lUK=fr8 zw?Wfy0nh{j8t(XPKD8GjEyVrwD^DRfS5GotWAJoE0o*2oS8HZF^SIW+iBkLzerSM% z^8gd>xN)sfyn`epj}QLPPnFc0U-9&zKo!DM@oEj$m7Bad|lxj)pKT=6TISL=}C&q5tcxK?0Nb|n(xqntr` zeb=x-z?8zD?~qM6yL&l#NaQmo&yH|SKO~h z4E}d4|EC6jiSd^V{tD|kWAMLc{Jg=#9UP^N6<49j0N_)ju^!{DE0 zKmXO>|C99;u^knke#Vss|1is|`Jv?BXTA3s^4D2j#Y4%z%>J|*@~S_w2CvqyQG-|W z;mZaeWBeBej~@Xsoj3Rd`!iwis{U1jmme&J_=Um0!+6r*7jS%T7(9MM#H8w}_`Je# z`@JE5iun%=emC{sC_1VS_)$em-mPYW#iG;OiNmGx$!9+b;}W?ayu){9A1IU4y@0^_Rh`{ei`s zEfu#WmRoG_CzxNsJgQZDEi}E#kXPRXH)-y1#rm11{fycJqX~2Wj2xye9$#j=B2+5d zs<*er;IA{Zny<;F9E@GX&55l0_uxC%HYqHwn{?7-DW zGy`80qHwPZUlic#nK69ejKa5u5x9amzQM{s`CKr3CqD z*8g|lXN!Le$6v)2 +#include +#include +#include +#include "run.h" +#include "test.h" + +static const TestType *findTestType(const TestType *test_types, const char *name) +{ + for (size_t i = 0; test_types[i].name != NULL; i++) + if (!strcmp(name, test_types[i].name)) + return test_types + i; + return NULL; +} + +TestResult runTestString(const TestType *test_types, const char *src, FILE *log_stream) +{ + NojaTest test; + ErrorID error = parseTest(src, &test); + if (error != ErrorID_VOID) { + fprintf(log_stream, "Error: %s\n", getErrorString(error)); + return TestResult_ABORTED; + } + + const char *type = queryTest(&test, "type"); + if (type == NULL) { + fprintf(log_stream, "Error: Test is missing the \"type\" field\n"); + return TestResult_ABORTED; + } + + const TestType *info = findTestType(test_types, type); + if (info == NULL) { + fprintf(log_stream, "Error: Invalid test type \"%s\"\n", type); + return TestResult_ABORTED; + } + + bool uses_type = false; + const char *ordered_fields[8]; + + size_t i = 0; + while (info->fields[i] != NULL) { + + uses_type = uses_type || !strcmp(info->fields[i], "type"); + + const char *field = queryTest(&test, info->fields[i]); + if (field == NULL) { + fprintf(log_stream, "Error: Test is missing the \"%s\" field, necessary for \"%s\" tests\n", info->fields[i], info->name); + return TestResult_ABORTED; + } + + if (i == sizeof(ordered_fields)/sizeof(ordered_fields[0])) + abort(); + + ordered_fields[i] = field; + i++; + } + size_t used_fields = i; + + size_t unused_fields = test.fields_count - used_fields; + if (!uses_type) unused_fields--; + + if (unused_fields > 0) + fprintf(log_stream, "Warning: %ld field of the test weren't used\n", unused_fields); + + TestResult result = info->routine(ordered_fields, log_stream); + + freeTest(&test); + return result; +} + +static char *getStreamData(FILE *file_stream, FILE *log_stream) +{ + size_t copied = 0, just_copied; + size_t capacity = 512; + char *content = NULL; + do { + + capacity *= 2; + + content = realloc(content, capacity); + if (content == NULL) { + fprintf(log_stream, "Error: Out of memory\n"); + return NULL; + } + + just_copied = fread(content + copied, 1, capacity - copied, file_stream); + copied += just_copied; + + } while (just_copied > 0); + + if (ferror(file_stream)) { + free(content); + fprintf(log_stream, "Error: Couldn't read file contents\n"); + return NULL; + } + + if (copied+1 >= capacity) { + content = realloc(content, capacity+1); + if (content == NULL) { + fprintf(log_stream, "Error: Out of memory"); + return NULL; + } + } + content[copied] = '\0'; + + return content; +} + +TestResult runTestFile(const TestType *test_types, const char *file, FILE *log_stream) +{ + FILE *file_stream = fopen(file, "rb"); + if (file_stream == NULL) { + fprintf(log_stream, "Error: Couldn't open file \"%s\" (%s)\n", file, strerror(errno)); + return TestResult_ABORTED; + } + + char *data = getStreamData(file_stream, log_stream); + if (data == NULL) { + fclose(file_stream); + return TestResult_ABORTED; + } + + TestResult result = runTestString(test_types, data, log_stream); + + free(data); + fclose(file_stream); + return result; +} + +static const char *getExtension(const char *file) +{ + int dot = -1; + for (int i = 0; file[i] != '\0'; i++) + if (file[i] == '.') + dot = i; + + return (dot == -1) ? "" : file + dot; +} + +TestBatchResults runTestDirectory(const TestType *test_types, const char *dir_name, FILE *log_stream) +{ + TestBatchResults results = {.passed=0, .failed=0, .aborted=0, .batch_aborted=false}; + + DIR *d = opendir(dir_name); + if (d == NULL) { + results.batch_aborted = true; + return results; + } + + struct dirent *ent; + while ((ent = readdir(d)) != NULL) { + + if (ent->d_name[0] == '.') { + //fprintf(log_stream, "Info: Ignoring file \"%s\"\n", ent->d_name); + continue; + } + + char full[1024]; + strcpy(full, dir_name); + if (dir_name[strlen(dir_name)-1] != '/') + strcat(full, "/"); + strcat(full, ent->d_name); + + if (ent->d_type == DT_DIR) { + TestBatchResults sub_results = runTestDirectory(test_types, full, log_stream); + if (!sub_results.batch_aborted) { + results.passed += sub_results.passed; + results.failed += sub_results.failed; + results.aborted += sub_results.aborted; + } + continue; + } + + if (ent->d_type == DT_UNKNOWN) { + abort(); + } + + if (ent->d_type != DT_REG) { + //fprintf(log_stream, "Info: Ignoring file \"%s\"\n", ent->d_name); + continue; + } + + const char *ext = getExtension(ent->d_name); + if (strcmp(ext, ".noja-test")) { + //fprintf(log_stream, "Info: Ignoring file \"%s\"\n", ent->d_name); + continue; + } + + TestResult result = runTestFile(test_types, full, log_stream); + switch (result) { + case TestResult_PASSED: + fprintf(log_stream, "Test %s .. PASSED\n", full); + results.passed++; + break; + + case TestResult_FAILED: + fprintf(log_stream, "Test %s .. FAILED\n", full); + results.failed++; + break; + + case TestResult_ABORTED: + fprintf(log_stream, "Test %s .. ABORTED\n", full); + results.aborted++; + break; + } + } + + closedir(d); + return results; +} diff --git a/src/test/run.h b/src/test/run.h new file mode 100644 index 0000000..5f8f9c8 --- /dev/null +++ b/src/test/run.h @@ -0,0 +1,21 @@ +#include +#include +#include +#include "main.h" + +typedef struct { + const char *name; + const char **fields; + TestResult (*routine)(const char **fields, FILE *log_stream); +} TestType; + +typedef struct { + size_t passed; + size_t failed; + size_t aborted; + bool batch_aborted; +} TestBatchResults; + +TestResult runTestFile(const TestType *test_types, const char *file, FILE *log_stream); +TestResult runTestString(const TestType *test_types, const char *src, FILE *log_stream); +TestBatchResults runTestDirectory(const TestType *test_types, const char *dir_name, FILE *log_stream); diff --git a/src/test/run.o b/src/test/run.o new file mode 100644 index 0000000000000000000000000000000000000000..c9d247773593daad331811417fb7ff0a49dd3eb3 GIT binary patch literal 16792 zcmb_j4{%e*nct`9wPjoWZ-Wgu2qz9C#5N{C!r$0n8JYh9(?UZ|$kMZ|MwVRZ2?J>w zf^m!D`ihf~CReV3yL2XH@-|pMDk{|Z1Yj+t2Q^jB_*f^z7#;TW%w_8NBg-u~q?6)O1 z{b{Q|ebGO7)$30`bjhDiUGSgwT}PHHTl~XYulv(y{l=KzIO~7)g6U7c<{$Q5LTb1a zS{MB3bN=+{OUOPnma6>}fh!IELEm-bQ#ky?%nwQ)J%QTZd_CjZBUf1|WBx(UEzJMO z)iDn3^r>y{-MHaTzqCnIhy756{lhu+b3oLe_FZot^N$?9fStobk|*P5dZ-uh!BhCj z?1jUEq%nx`4WTyw$U<}j1}EGRBNVO6X&1mFLqd6mN%Z^EL;Fy4@Dx@obvqary3(({ zf{y(VXU0FW92Gkh-i-=}4-3)ZAvrMNZQ##1#-W2!Csr(V$2jMwyZI|H_Qp^T3i(eD z^uCoQ-i0lVyU$maq!|(6j3lUe(4i)4ZH)TI1G1+%NZFKBZt8Wi|HqR zd{kH#=%=}jnOHLPGn@cYksdmPqL}@2Wivgr8<3KhMI;8V83)E}w}0??1P$;5Yi8Gh zZES&>Z1a^Fv>%p~NM(qb@KeO>#@p$kC~Babqf{N1;PCqEVgH>Tk@&V8v}5TEUY!T4 z`aG=av#_c!K!6|_e3uwz+-V;MjQQWTF2SONKi@USYKBF0%|H0iHI|wUJ!k!p!d1YX zC511dA`u$c5{B1b1BDm-Bg@L52IFtTvJ!%FPGETg?{&Wcyn_#2XC*_sZ-~eOtJ+HJ zdD0(AD-UkY>cN$6-~n}GhJUf|(m*>K3K5GP}-la36*OdX2Mhhyh-k z5ZjhaY|~rM2z{B{R3oJrE)euE%WN~Rg6gv%a%Oy)Y3Yn35?a-)%oe)=#0_JXssLf= zk?|3tR~AZv^%z|Uf9ALs;0An}&TK`$Om` z?)fDzvt^B`T)|Zu)t@%}>3eY}Ld5_gt3TaZ3TXA^>mUtXV~7ooRbWg{$zA%4;2sjy z#55Qhv*#+AkxejhLpZ$2CjRmQp?*XRU}WeTu)V@Wm@<=@QRJ`iXX7|5^^c%D@XOF< zG^B@K1bpxme!A>is8RA2Od?4zd#`L5_R`D8FyJGHNte{Do($tD3uexuHC%vc(Y*4& zUnC_$E~T&uN&J`C5>q3kuz3i~pFs1O^+hvu3MUFCy+dx~6L|jDlaGrC_F8$!puH9h zV+y_bI_4!5Um_7tEb-PS3z)s9-%@m^m9)K)q_;1UOh#foUc1-w)*(Zkw>x4*!v#`0 zBi|9*6^us0UK{0*&s$fYtOG96KdC<8klOC>#;lN)Oa>EsyxsAHkQJ)HD=ME2CSu?S zcp42$A#c1}xFt*uSP3gO+xDiC7WhU+H>PZ4>a+Udi9Mu=x>m(g(J%@mtRU)(THa7R zW?L~EOim`w5?#U*T|VA##iTqA*gK~_c^g=2jKx16Y(URgN31)(#M{vmizhIU!jz1S zh)I3Y+t}#c)VgJhudRSNp!U{|bsE&Va^vPs#8%`pTxC%3bi|kkKb)ll7*v5rCu6R+ zr!I!dbmt*ux4l z*?y|#kxcvP>DbP5b2q9J%Bqc=DefHbS@@SzQ*;n|h?rLN1hUDVnbj>oluE)|VF6Jt ziCG0GU%?7cX(coZ(fSSMY3ta`iXWcg1*ixR7%RCd{4Yl6Ja2Zt0*(qz{LZ}92ufm6 z{tM8S*7;q6kk#MGi+Vrmh60|;XK-FTCM zO2IoF8iKb1U%Vja(#5j@;$pHT@~A*$dw9If5)p9?MkqWL+EXI*G*hHs`=2!2;wmEuefatY2&F1JqMc;>WY>w_5m?8N8 zdJ1YZN5=+g!^}8TutrEfH&6=?CT2WYxk=F99k>a(u{;jT1xu~98yKFhlIl;8x}(LP z5ds&8ezp=5%p84o0Q2h4(B^L3Lb>}z&>@ym4+zMpnrtR&HuhJdQdMvbU@?xI22MGu z{SCSF9xWe0`R zIPzM?`szBVkF2j=D9IM7uR|;^*XSl9t1*Ey*49w(HrczDeA!7uFP$*-r4$C^$S>ew zDF;`2yG)=nowJgO5Hm_w;@BZUI;np>4Zc%aC@)SydYYqWw@SLA2v@T?dY<}g#7<<6 zUL$&DmDGQo=z6h1n4|9yeQO!|0tvho=WdP|jyZaPdKVMDkE|^v`V#fGieQ_g|JIpF z1$kg$OuE-V343rWq#us#B3PqUSBH~gxU11YRlY$Dg3eDo_#bri$Ug=a2o5IZEC51~17Z-NG24~*F3JX^N2OPDi3BK_X zK(RabR)$p`(y*IX7-n%Hm(ut^$S-mzyBjzP45On0dkSZPU=tu7u;(7PS5yHK%W4=a z7P<<@b(M@e29Jsb4#oG>pg`Fy7*KhRv7!)N8<(q?1FSQ^Qe}lv=+IYHWz4RT&P?HA z6jOo0;e7Q3=OLeJgwMF|H5&KSs3@Tl3|>q1lPha*Xw$jFH{8Q#IGshH7J$r{5xA)k zW}+O{+RR3Xp!9uQ@7JYX?__;sa~9Z~ps_9sGsNf)_>-G7%%r0@PsG04F~xua{YW>Zl8L5hq^qeX6l&Ui_oBd}1r586Gj=1z#EY*+etf-3fX~nc%uLS zMm637=|~(v*d>yCk^w7`h(?km))$P#pbH8b6AkE(CuCE+2g)YC=*U*aDn1yw!Sd;$ z2&u!%+{-!N&+D6bvHP3cV#ytbP@OeJ-bG#AtAL5I! zI?iv#>KvbmmD>xSX6_pJ%&~a|RJpm^_gs zbG*|1CifgeX!_@PfqOeIH52=J^>JS4F6SPz^bq%+=bkk@{~ZqF5yM-<-3QRgT31~q zuQ|@S`vvZ~2vLHu_T>ILcL0L2e2^Co^70{Gu@0ynUX%h$C;8N4yna8Q`U(s;#W`qs z0S>o3f9**CPV$lg?%vNUdO+eCB>@qrI?g>SxUsgG*MO88w0$~%8}N1;Z(GZYj`Mu? zWj+l8nhzm&_wsz#trfh;)lkVRaXzQpyy*GnPqt?u&MVBY7lOWxbJGh`1@UyvuW;4E zYQ?wd%~moMwOJq#@9qxREEMbyh9dSJh8G0^k-|w9=-3#*dw@W{oe;0!QYau_!C4^G z3kyNs3UssuR<^cn*}kE(bz5M=#tp6OeYiN#QafBCuw-Pf1!iKwJ}VHlVl0sCjVJ7` zR5z2h0)4?fU6#CR8Fw!r-~WXpz#HfaCM~BU^y1H=akxPcAE{U}(i5}7UVMQ^MV)wg zV?#sQmSzH>c-RWWhK8s1<m|Pqv;4BpHkHFw? z0F+{@H*EE;YQD?6xN$+_Ja0pvor+n@dn|A|5&|-q2=y+92Uo+Q1>S}pZ$o!5xhEFt zO~hmIRI(uz8;Hch4R)|AY9*mFX$M0OH1sFpwiUADi3V^CQ&DwW;)?&=Kl( z&?^7h;F*N-u>4}q1xQzKGW0MWu*$kq(Wr=tj69}_e7HcC#KM`B4+kQYlo%vfdN^75 zcw^l`$fhv+d@5-}eu?mirF2tpY${mwgO_>!Ba}fT_T1mQH5gxbQwJL;j#ZxfoXuLU4&mNzt~1l9bd`STj* zEof}MP2zZh!Se{->cAnE!P3AJ(imd&&c!OBjm6lznHjrFjp?2|_aQh@;d_dBSAkl* zefWw?zwBC7lT(iX+#61Umwf_5z+~`psg)+6C)47~g0BO-9O9Ci1%E6Hj($%z-s4$tyr`Ot|CKEGt6A_j0LQq^#|;6Bx_82QGX3YX z;Fq)DA7;V-2sqm9r_@!qh6S)xCbL_f1)r7$ugikpo&~49e!??#;zMD=_8wThZsW?< zb%BlT?OS}EfzH;I>wE!tm?T1d{pu+X4-`CQ_6HM5OB@|h13v4hqq`sa?QZskl$F>c z7`nxlFCWGX&u0P+zyk&zKXCkhAb<~Z*!hD|c*-M35YC?P{EEXd71)(!aRl$iujJss z58d#X1^%Fo4<_)D1VYg`9IxrrK7J%YF?enxV=UCaN7g|&JA*OAg%~zOSuHEE^TE{z z`xt+P0OfrLj=w)qcp=0e3qEtEz@Nfr5RUK3m=X%V&A|_sQyIKf)?0#Q%f)S%75igJ>fWBXMFk{xYN&;b;CPR$;+CZ62X3=cpgGx^+ z&36UiDCX32uf|_b{M#M;bs(esk2vs~9eBcl-{QazX!`FU{i6;#ci>(J{*eQB>iInF*D5~ul0WYfj`5l8(6fyeg5uvy{5uIpe&@P)NaMes_#buf zJIDLH1E1rt`x6I#n*)E}fzNW_cflDJi}G`T?6wh(emd>;Y5b28|K2S8f3NZXE%ARh z3;$0Y`0Zd@&DZZ8_*@6ROnk{F*Q0Zt(zG!A*$4gf16t!hl|ZZr{{9;W4n>{N6uy}9 z0QYb#3a=*raV=m$l2iy9V~z#+)n1EqBYr?pdhoo3MeVN&Uqs4Q$?gpQVZznEsQ6Fe z1VQPQRfhi_!s8k)zxZWrmxj-$aXqBr_miFj8lE8jw1$73_z!EiI$_zR?8ohy_-_mDs8T%qs}$p3dWJ#z_vPs3M}KY!5h^+e~8eWm{#(PbL` z3*x^?!@ouNTn!&2fAF{PSd{)jNiv^?pCNj)hW{t&4`{eScvQpF6t_JZ{vhFB*6=E# zAJ=dX@gLRje<%8R4Oi!YlNzqhE2lO5J<6Y-X!tc6*Y7p_Unrgi$*Fio37?_iACaC$ z4gWRiU83PLXuRzjejo97Y4}vK+ppo@BYIH7e@OG5*6@Xde@(-mA^b@VCzyRl!#_iQ zp3rcc#`R+j$6r%n`K^Xuk}xZx@u@f$6aO>~#~+DcnXTbB6TLvg|4ek7hA$?%L&J{~ z9n$b;h>mEuI_IhLv+{qC{7-58_=5l}4{G=m6t_n-JWP5HYIrm8e^bMMFV(Z}X!wVu z=Y)o!R@E*dGntpXp`KZRP*2!}k|5T#SX#71iUq93M)qT}_8o!F$ zA2nRrl|TF)e@>~mRZ~1v9KJ{MI9tQNMESW$!&Q9RHT-6Z&%K1J_^bQfUX5Sb9nf&) z=a)773i)$b!#U;2vl@=?T3EiX;oqite_g}zJ`T%Uge(8mJ?lk{U&Wu(dy0yu^1n*M zKalEKy@r>O{|hzzZ;0Qg;XTB^Rm1<8{I@i`j^Z|`;rQ-^<#7%F2E|9c$Ek6tdH+7~ ztN8qm?EXm8vx4y7X!tv%{{u~r^akGR=>1OFRdKG+aJ8@25w84E-|Nt_5a%>v5hm1~ ztKwI7edMo>dx-(VNTC!+i-xN_*{R_w|MzLQTGvN4Ti zt6B*w8f>)jm!XZ~Tgk?*WRf)|;*t=(VXG_E1K&r&H<*pG9qj5#Si67?g$YUoV?FQ# zBqs(xcCwTR*kg^McwZm>N)`U~!L}OVD>nF&7;bNghF?WB!q>2czcur < scanner->len && testfn(scanner->src[scanner->cur]); +} + +bool followsCharacter(NojaTestScanner *scanner, char c) +{ + return scanner->cur < scanner->len && scanner->src[scanner->cur] == c; +} + +bool noMoreCharacters(NojaTestScanner *scanner) +{ + return scanner->cur == scanner->len; +} + +bool ifFollowsConsumeCharacter(NojaTestScanner *scanner, char c) +{ + bool follows = followsCharacter(scanner, c); + if (follows) + scanner->cur++; + return follows; +} + +void consumeCharactersThat(NojaTestScanner *scanner, int (*testfn)(int c)) +{ + while (followsCharacterThat(scanner, testfn)) + scanner->cur++; +} +/* +#ifndef NDEBUG + +bool noMoreCharacters__wrapped(NojaTestScanner *scanner, const char *file, size_t line) +{ + fprintf(stderr, "noMoreCharacters(%p) - %s:%ld\n", scanner, file, line); + return noMoreCharacters(scanner); +} + +bool followsCharacter__wrapped(NojaTestScanner *scanner, char c, const char *file, size_t line) +{ + fprintf(stderr, "followsCharacter(%p, '%c') - %s:%ld\n", scanner, c, file, line); + return followsCharacter(scanner, c); +} + +bool followsCharacterThat__wrapped(NojaTestScanner *scanner, int (*testfn)(int c), const char *file, size_t line) +{ + fprintf(stderr, "followsCharacterThat(%p, %p) - %s:%ld\n", scanner, testfn, file, line); + return followsCharacterThat(scanner); +} + +void consumeCharactersThat__wrapped(NojaTestScanner *scanner, int (*testfn)(int c), const char *file, size_t line) +{ + fprintf(stderr, "consumeCharactersThat(%p, %p) - %s:%ld\n", scanner, testfn, file, line); + return consumeCharactersThat(scanner); +} + +bool ifFollowsConsumeCharacter__wrapped(NojaTestScanner *scanner, char c, const char *file, size_t line) +{ + fprintf(stderr, "ifFollowsConsumeCharacter(%p, '%c') - %s:%ld\n", scanner, c, file, line); + return ifFollowsConsumeCharacter(scanner); +} + +#endif +*/ \ No newline at end of file diff --git a/src/test/scanner.h b/src/test/scanner.h new file mode 100644 index 0000000..245e157 --- /dev/null +++ b/src/test/scanner.h @@ -0,0 +1,32 @@ +#ifndef TEST_SCANNER_H +#define TEST_SCANNER_H + +#include +#include + +typedef struct { + const char *src; + size_t cur, len; +} NojaTestScanner; + +bool noMoreCharacters(NojaTestScanner *scanner); +bool followsCharacter(NojaTestScanner *scanner, char c); +bool followsCharacterThat(NojaTestScanner *scanner, int (*testfn)(int c)); +void consumeCharactersThat(NojaTestScanner *scanner, int (*testfn)(int c)); +bool ifFollowsConsumeCharacter(NojaTestScanner *scanner, char c); +/* +#ifndef NDEBUG +bool noMoreCharacters__wrapped(NojaTestScanner *scanner, const char *file, size_t line); +bool followsCharacter__wrapped(NojaTestScanner *scanner, char c, const char *file, size_t line); +bool followsCharacterThat__wrapped(NojaTestScanner *scanner, int (*testfn)(int c), const char *file, size_t line); +void consumeCharactersThat__wrapped(NojaTestScanner *scanner, int (*testfn)(int c), const char *file, size_t line); +bool ifFollowsConsumeCharacter__wrapped(NojaTestScanner *scanner, char c, const char *file, size_t line); + +#define noMoreCharacters(scanner) noMoreCharacters__wrapped(scanner, __FILE__, __LINE__) +#define followsCharacter(scanner, c) followsCharacter__wrapped(scanner, c, __FILE__, __LINE__) +#define followsCharacterThat(scanner, testfn) followsCharacterThat__wrapped(scanner, testfn, __FILE__, __LINE__) +#define consumeCharactersThat(scanner, testfn) consumeCharacterThat__wrapped(scanner, testfn, __FILE__, __LINE__) +#define ifFollowsConsumeCharacter(scanner, c) ifFollowsConsumeCharacter__wrapped(scanner, c, __FILE__, __LINE__) +#endif +*/ +#endif \ No newline at end of file diff --git a/src/test/scanner.o b/src/test/scanner.o new file mode 100644 index 0000000000000000000000000000000000000000..f9be16957743f0c90cc303944a389844f9f89f1f GIT binary patch literal 5360 zcmbtWYit}>6}~g$S&zN(?%Gb;q~WneO`3}CtQWZ^ZjyGf8wnPq8S*%KlKtWUyRPYO_h_*;oAW~(uKT66U9x4*Q;7380TA?5+s3^#sbLXD% z?A_@fxYFEn&UYU7+;i{Td%wQ$@B^x%Flq|BkL^f=GWJ4#hp%$B%J#6`?C<%H{A;n+ z`*ZEWJB3>B$@gl#@Mdje;l0|%Nh6}wLT&a{|KpKR5SUR@ew}}rM0aIe-zq6UJx$sUA zrnH3vzmixdfdwmNNytuG^{>g0?>_)h@Q8jAMoK!g9J89%!Uf52gpD51T zXbP^mJMq7<8NPYx(v8V}%}5M@FWBH!@w@0U?J%fejna0#%g^ z^vw7+bbKgvRQm$(BZw-uaV4?~*g;dSV#P)|ds_*4^>SN?NB_gc(-8Uxz-5m^htMu$ z0Q@WTW5_BKna2_{eGoBd%2h<8U=x)n_EOFQ^ZPM9_3|mcbCuo0Xs2FwA$zDOP6nDX z))({+#GolxzZC}^J0ubo9!8(XW03=R+=x94^1w8VnJA408|RU=KKC!h?$HdiyZfr6 z9ii$lWn4Lso6Kst{kd^vVz_WCOy&-j&E5wPtiml!%iWtjlAX<-n1sa^8iO%?Qpsi` zjRKm?7}E?gJe-9J=OGCC7zY`W5mUK;AH}+JAC6Vsdu47PI*;m!QPjP#T6>f`_nnwT z-7cNGkM+BsnCuIXg8=d97$83_MJ%NIe>X~CJY5UvK^^agkFP9)X(w9p|46{>9#}Aq z)d5nJ_j6;=^K%eTr5yTRx!YMOw=Ao?c6eraX1dhvIN@5U<%H$ga>uc{VZ&z3x9W~# zd!~hfNoaE+Xf*7m+2*IIuCS3PHBjx*3&t`1qwD&Cb$y1ZL&}mqk0j8KAX(QBA!+Id zkUS5amU$5RA^3TRGD{E&Nak1tqD+b?Wq=^cQ6zyrjRc}2X+o!EmY^SWzpfY8^;_0; zrB%_#jfZp{zR{MRU)M*j>&inF-GDSl%N+PQ2&S$)tPVk$x~|hI@(xdwa@$?C%a(ht zuFhTrLHWA~;H_+YiVN=e1 znkj1qW&f^W;}ZM|9|8xA@AME*iGKp=IP^WU}y6aZ+cFC4_F8vS0HxPSXmw8v@= zHjVKccR-;@2NM}+(e*`QOf@!e*K?i5;KWa98cRIV5_&DVxe`dkYSG2ohr^A)CKC0b z3#uq^lIh;72>ho&vC$1W2Rz349YWkFK+yP_B14C#MO!{T7WiK+|LTK> z!3Uok>E{d%%Gf_5!dDop_wVhfeOBa${|Hu_aC+O|bxl05@k$|%&!9gd2#sI*KnV{- z+&x^ogVT!QMTQN{;u{0_yAXtiagx{D6i0XB{7A_6NcbTk&rA4>kZCXZ+81v~_D_kr{XxRZLLL%&%AfXWUf>j;@;@lqQ~Wsz z?+W>pgwuRJC*f-%pN7DZ;5yR(@iobw#@&$cS4EsFQXHDsPb7Pa^M-`?M4UIJI09x{ zl0C)wr-W0TY0qPwlcyhlO#_B*$$fi93?$=4fun8GzAE7~-_sIK^*k@(w7$h%oX2fCPy3gO4wTNI87IHoUgB}c=lKO)bNaP zT6Vt+yc%tCfpM5=xvQ%-JWNano&+Xb#qcD6CxVdSd1=C9;f(DCXGLtgz1;NbtG1ZX z|4EAAk845eNa3o2ksr%q8;}{>4;-F})ff>BUL4TqJemL=ed(-%w?1zNp+{W4X@4jW z6q$2d!E%C+e2n?O`r~<*HWZCNoZO5lws_yA&3{VFpAy6Q#zqo+NAM?lD<@`H<$vFYU-WTJ~N=iv&4X{lc|FjsN z_6d%UXN)|42pGnsJb~qHT5Ra2r2$DKdLFFP{C^>yY`DLYjr@q>c}jfJ?l0+2z5(0s zffJfa+l*}q|6(#I@HBsdUjzonm;DW4c#RANmHqMFN~`~xs6X9bSpNci +#include + +#include "test.h" +#include "error.h" +#include "field.h" + +static bool growFieldsArray(NojaTest *test) +{ + size_t new_capacity = 2 * test->fields_capacity; + + NojaTestField *new_fields; + if (test->fields == test->fields_maybe) { + new_fields = malloc(new_capacity * sizeof(NojaTestField)); + if (new_fields != NULL) + memcpy(new_fields, test->fields, test->fields_count * sizeof(NojaTestField)); + } else + new_fields = realloc(test->fields, new_capacity * sizeof(NojaTestField)); + + if (new_fields == NULL) + return false; + + test->fields = new_fields; + test->fields_capacity = new_capacity; + return true; +} + +void freeTest(NojaTest *test) +{ + for (size_t i = 0; i < test->fields_count; i++) + freeField(test->fields + i); + if (test->fields != test->fields_maybe) + free(test->fields); +} + +const char *queryTest(NojaTest *test, const char *name) +{ + for (size_t i = 0; i < test->fields_count; i++) + if (!strcmp(name, test->fields[i].name)) + return test->fields[i].body; + return NULL; +} + +ErrorID parseTest(const char *src, NojaTest *test) +{ + NojaTestScanner scanner = {.src=src, .len=strlen(src), .cur=0}; + + test->fields = test->fields_maybe; + test->fields_count = 0; + test->fields_capacity = sizeof(test->fields_maybe)/sizeof(test->fields_maybe[0]); + + bool done = false; + do { + + if (test->fields_count == test->fields_capacity) + if (!growFieldsArray(test)) { + freeTest(test); + return ErrorID_OUTOFMEMORY; + } + + NojaTestField *field = test->fields + test->fields_count; + + ErrorID error = parseField(&scanner, field); + switch (error) { + + case ErrorID_VOID: + // Before acknowledging the insertion + // by incrementing the field counter, + // check that the new field doesn't have + // a duplicate name + if (queryTest(test, field->name)) + return ErrorID_DUPLFIELD; + test->fields_count++; + break; + + case ErrorID_BADSYNTAX_NOFIELD: + done = true; + break; + + default: + freeTest(test); + return error; + } + } while (!done); + return ErrorID_VOID; +} \ No newline at end of file diff --git a/src/test/test.h b/src/test/test.h new file mode 100644 index 0000000..1c21295 --- /dev/null +++ b/src/test/test.h @@ -0,0 +1,12 @@ +#include "field.h" +#include "error.h" + +typedef struct { + NojaTestField fields_maybe[8]; + NojaTestField *fields; + size_t fields_count; + size_t fields_capacity; +} NojaTest; +ErrorID parseTest(const char *src, NojaTest *test); +const char *queryTest(NojaTest *test, const char *name); +void freeTest(NojaTest *test); diff --git a/src/test/test.o b/src/test/test.o new file mode 100644 index 0000000000000000000000000000000000000000..d7c05622a4d3a0b3ce33407000b2b3a8d530f1d1 GIT binary patch literal 8080 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 literal 0 HcmV?d00001 diff --git a/test_bytecode b/test_bytecode new file mode 100755 index 0000000000000000000000000000000000000000..8d78b092dbada3ab3917648a1375859a151c91ba GIT binary patch literal 184792 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 N{F*nEY*N|ie*vTR^4tIb literal 0 HcmV?d00001 diff --git a/tests/suite/Testcase_010_000 b/tests/compiler/dowhile/Testcase_010_000.noja-test similarity index 67% rename from tests/suite/Testcase_010_000 rename to tests/compiler/dowhile/Testcase_010_000.noja-test index c581cd0..8b34f6f 100644 --- a/tests/suite/Testcase_010_000 +++ b/tests/compiler/dowhile/Testcase_010_000.noja-test @@ -1,11 +1,12 @@ -#source +@type [compiler] +@source do {} while none; -#bytecode +@bytecode begin: PUSHNNE; diff --git a/tests/suite/Testcase_010_001 b/tests/compiler/dowhile/Testcase_010_001.noja-test similarity index 77% rename from tests/suite/Testcase_010_001 rename to tests/compiler/dowhile/Testcase_010_001.noja-test index cc874b5..ae250cc 100644 --- a/tests/suite/Testcase_010_001 +++ b/tests/compiler/dowhile/Testcase_010_001.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source do true; while none; false; -#bytecode +@bytecode begin: PUSHTRU; diff --git a/tests/suite/Testcase_010_002 b/tests/compiler/dowhile/Testcase_010_002.noja-test similarity index 83% rename from tests/suite/Testcase_010_002 rename to tests/compiler/dowhile/Testcase_010_002.noja-test index 86700e5..abcaac6 100644 --- a/tests/suite/Testcase_010_002 +++ b/tests/compiler/dowhile/Testcase_010_002.noja-test @@ -1,5 +1,6 @@ -#source +@type [compiler] +@source do { true; @@ -7,7 +8,7 @@ } while none; false; -#bytecode +@bytecode begin: PUSHTRU; diff --git a/tests/suite/Testcase_010_003 b/tests/compiler/dowhile/Testcase_010_003.noja-test similarity index 85% rename from tests/suite/Testcase_010_003 rename to tests/compiler/dowhile/Testcase_010_003.noja-test index e1629c6..b028200 100644 --- a/tests/suite/Testcase_010_003 +++ b/tests/compiler/dowhile/Testcase_010_003.noja-test @@ -1,5 +1,6 @@ -#source +@type [compiler] +@source do { true; @@ -8,7 +9,7 @@ } while none; false; -#bytecode +@bytecode begin: PUSHTRU; diff --git a/tests/suite/Testcase_010_004 b/tests/compiler/dowhile/Testcase_010_004.noja-test similarity index 77% rename from tests/suite/Testcase_010_004 rename to tests/compiler/dowhile/Testcase_010_004.noja-test index 460d40e..a02b65d 100644 --- a/tests/suite/Testcase_010_004 +++ b/tests/compiler/dowhile/Testcase_010_004.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source do break; while none; false; -#bytecode +@bytecode begin: JUMP end; diff --git a/tests/suite/Testcase_002_000 b/tests/compiler/expr/arithmetic/Testcase_002_000.noja-test similarity index 61% rename from tests/suite/Testcase_002_000 rename to tests/compiler/expr/arithmetic/Testcase_002_000.noja-test index d44c598..e57aaaf 100644 --- a/tests/suite/Testcase_002_000 +++ b/tests/compiler/expr/arithmetic/Testcase_002_000.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 + 7; -#bytecode +@bytecode PUSHINT 1; PUSHINT 7; diff --git a/tests/suite/Testcase_002_001 b/tests/compiler/expr/arithmetic/Testcase_002_001.noja-test similarity index 62% rename from tests/suite/Testcase_002_001 rename to tests/compiler/expr/arithmetic/Testcase_002_001.noja-test index a956da0..d408e7c 100644 --- a/tests/suite/Testcase_002_001 +++ b/tests/compiler/expr/arithmetic/Testcase_002_001.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 - 7; -#bytecode +@bytecode PUSHINT 1; PUSHINT 7; diff --git a/tests/suite/Testcase_002_002 b/tests/compiler/expr/arithmetic/Testcase_002_002.noja-test similarity index 59% rename from tests/suite/Testcase_002_002 rename to tests/compiler/expr/arithmetic/Testcase_002_002.noja-test index b860c58..a046e31 100644 --- a/tests/suite/Testcase_002_002 +++ b/tests/compiler/expr/arithmetic/Testcase_002_002.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 * 7; -#bytecode +@bytecode PUSHINT 1; PUSHINT 7; diff --git a/tests/suite/Testcase_002_003 b/tests/compiler/expr/arithmetic/Testcase_002_003.noja-test similarity index 61% rename from tests/suite/Testcase_002_003 rename to tests/compiler/expr/arithmetic/Testcase_002_003.noja-test index f958c90..9c84fad 100644 --- a/tests/suite/Testcase_002_003 +++ b/tests/compiler/expr/arithmetic/Testcase_002_003.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 / 7; -#bytecode +@bytecode PUSHINT 1; PUSHINT 7; diff --git a/tests/suite/Testcase_002_004 b/tests/compiler/expr/arithmetic/Testcase_002_004.noja-test similarity index 61% rename from tests/suite/Testcase_002_004 rename to tests/compiler/expr/arithmetic/Testcase_002_004.noja-test index bcf0202..9e7b143 100644 --- a/tests/suite/Testcase_002_004 +++ b/tests/compiler/expr/arithmetic/Testcase_002_004.noja-test @@ -1,12 +1,13 @@ -#source - +@type [compiler] +@source + 1.0 + 7; -#bytecode +@bytecode PUSHFLT 1.0; PUSHINT 7; ADD; POP 1; - EXIT; \ No newline at end of file + EXIT; diff --git a/tests/suite/Testcase_002_005 b/tests/compiler/expr/arithmetic/Testcase_002_005.noja-test similarity index 63% rename from tests/suite/Testcase_002_005 rename to tests/compiler/expr/arithmetic/Testcase_002_005.noja-test index 96dd5ed..4fdcede 100644 --- a/tests/suite/Testcase_002_005 +++ b/tests/compiler/expr/arithmetic/Testcase_002_005.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1.0 - 7; -#bytecode +@bytecode PUSHFLT 1.0; PUSHINT 7; diff --git a/tests/suite/Testcase_002_006 b/tests/compiler/expr/arithmetic/Testcase_002_006.noja-test similarity index 63% rename from tests/suite/Testcase_002_006 rename to tests/compiler/expr/arithmetic/Testcase_002_006.noja-test index 5b276fb..5a06d5e 100644 --- a/tests/suite/Testcase_002_006 +++ b/tests/compiler/expr/arithmetic/Testcase_002_006.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1.0 * 7; -#bytecode +@bytecode PUSHFLT 1.0; PUSHINT 7; diff --git a/tests/suite/Testcase_002_007 b/tests/compiler/expr/arithmetic/Testcase_002_007.noja-test similarity index 63% rename from tests/suite/Testcase_002_007 rename to tests/compiler/expr/arithmetic/Testcase_002_007.noja-test index fc3fa54..752f8db 100644 --- a/tests/suite/Testcase_002_007 +++ b/tests/compiler/expr/arithmetic/Testcase_002_007.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1.0 / 7; -#bytecode +@bytecode PUSHFLT 1.0; PUSHINT 7; diff --git a/tests/suite/Testcase_002_008 b/tests/compiler/expr/arithmetic/Testcase_002_008.noja-test similarity index 63% rename from tests/suite/Testcase_002_008 rename to tests/compiler/expr/arithmetic/Testcase_002_008.noja-test index 433bdaa..64312d8 100644 --- a/tests/suite/Testcase_002_008 +++ b/tests/compiler/expr/arithmetic/Testcase_002_008.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 + 7.0; -#bytecode +@bytecode PUSHINT 1; PUSHFLT 7.0; diff --git a/tests/suite/Testcase_002_009 b/tests/compiler/expr/arithmetic/Testcase_002_009.noja-test similarity index 63% rename from tests/suite/Testcase_002_009 rename to tests/compiler/expr/arithmetic/Testcase_002_009.noja-test index cc5f3ac..c8a1005 100644 --- a/tests/suite/Testcase_002_009 +++ b/tests/compiler/expr/arithmetic/Testcase_002_009.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 - 7.0; -#bytecode +@bytecode PUSHINT 1; PUSHFLT 7.0; diff --git a/tests/suite/Testcase_002_010 b/tests/compiler/expr/arithmetic/Testcase_002_010.noja-test similarity index 63% rename from tests/suite/Testcase_002_010 rename to tests/compiler/expr/arithmetic/Testcase_002_010.noja-test index a1ba078..42d3f9f 100644 --- a/tests/suite/Testcase_002_010 +++ b/tests/compiler/expr/arithmetic/Testcase_002_010.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 * 7.0; -#bytecode +@bytecode PUSHINT 1; PUSHFLT 7.0; diff --git a/tests/suite/Testcase_002_011 b/tests/compiler/expr/arithmetic/Testcase_002_011.noja-test similarity index 63% rename from tests/suite/Testcase_002_011 rename to tests/compiler/expr/arithmetic/Testcase_002_011.noja-test index fec4177..d83ff28 100644 --- a/tests/suite/Testcase_002_011 +++ b/tests/compiler/expr/arithmetic/Testcase_002_011.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 / 7.0; -#bytecode +@bytecode PUSHINT 1; PUSHFLT 7.0; diff --git a/tests/suite/Testcase_002_023 b/tests/compiler/expr/arithmetic/Testcase_002_023.noja-test similarity index 69% rename from tests/suite/Testcase_002_023 rename to tests/compiler/expr/arithmetic/Testcase_002_023.noja-test index ccf42a6..5341a6b 100644 --- a/tests/suite/Testcase_002_023 +++ b/tests/compiler/expr/arithmetic/Testcase_002_023.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 + 2 * 3; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_024 b/tests/compiler/expr/arithmetic/Testcase_002_024.noja-test similarity index 69% rename from tests/suite/Testcase_002_024 rename to tests/compiler/expr/arithmetic/Testcase_002_024.noja-test index 89a4bd9..24e4a62 100644 --- a/tests/suite/Testcase_002_024 +++ b/tests/compiler/expr/arithmetic/Testcase_002_024.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 * 2 + 3; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_025 b/tests/compiler/expr/arithmetic/Testcase_002_025.noja-test similarity index 69% rename from tests/suite/Testcase_002_025 rename to tests/compiler/expr/arithmetic/Testcase_002_025.noja-test index 9b384ff..961045d 100644 --- a/tests/suite/Testcase_002_025 +++ b/tests/compiler/expr/arithmetic/Testcase_002_025.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source (1 + 2) * 3; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_026 b/tests/compiler/expr/arithmetic/Testcase_002_026.noja-test similarity index 70% rename from tests/suite/Testcase_002_026 rename to tests/compiler/expr/arithmetic/Testcase_002_026.noja-test index 00949dc..faed49f 100644 --- a/tests/suite/Testcase_002_026 +++ b/tests/compiler/expr/arithmetic/Testcase_002_026.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 + (2 * 3); -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_027 b/tests/compiler/expr/arithmetic/Testcase_002_027.noja-test similarity index 76% rename from tests/suite/Testcase_002_027 rename to tests/compiler/expr/arithmetic/Testcase_002_027.noja-test index 2b8bdc9..9051178 100644 --- a/tests/suite/Testcase_002_027 +++ b/tests/compiler/expr/arithmetic/Testcase_002_027.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 * 2 * 3 * 4; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_028 b/tests/compiler/expr/arithmetic/Testcase_002_028.noja-test similarity index 75% rename from tests/suite/Testcase_002_028 rename to tests/compiler/expr/arithmetic/Testcase_002_028.noja-test index 16f4264..8f6bf86 100644 --- a/tests/suite/Testcase_002_028 +++ b/tests/compiler/expr/arithmetic/Testcase_002_028.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 * (2 * (3 * 4)); -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_029 b/tests/compiler/expr/arithmetic/Testcase_002_029.noja-test similarity index 74% rename from tests/suite/Testcase_002_029 rename to tests/compiler/expr/arithmetic/Testcase_002_029.noja-test index ad38c5e..1d64e0c 100644 --- a/tests/suite/Testcase_002_029 +++ b/tests/compiler/expr/arithmetic/Testcase_002_029.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 + 2 * 3 + 4; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_030 b/tests/compiler/expr/arithmetic/Testcase_002_030.noja-test similarity index 75% rename from tests/suite/Testcase_002_030 rename to tests/compiler/expr/arithmetic/Testcase_002_030.noja-test index 4b97dfd..6a765f5 100644 --- a/tests/suite/Testcase_002_030 +++ b/tests/compiler/expr/arithmetic/Testcase_002_030.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 * 2 + 3 * 4; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_031 b/tests/compiler/expr/arithmetic/Testcase_002_031.noja-test similarity index 82% rename from tests/suite/Testcase_002_031 rename to tests/compiler/expr/arithmetic/Testcase_002_031.noja-test index 435bb40..0264e10 100644 --- a/tests/suite/Testcase_002_031 +++ b/tests/compiler/expr/arithmetic/Testcase_002_031.noja-test @@ -1,10 +1,11 @@ -#source +@type [compiler] +@source A - B - C; A - B * C; -#bytecode +@bytecode PUSHVAR "A"; PUSHVAR "B"; diff --git a/tests/compiler/expr/array/Testcase_003_000.noja-test b/tests/compiler/expr/array/Testcase_003_000.noja-test new file mode 100644 index 0000000..2fa8dfd --- /dev/null +++ b/tests/compiler/expr/array/Testcase_003_000.noja-test @@ -0,0 +1,16 @@ +@type [compiler] + +@source + # This comment is because there + # can't be a '[' right before a + # tag. + [1]; + +@bytecode + + PUSHLST 1; + PUSHINT 0; + PUSHINT 1; + INSERT; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_003_001 b/tests/compiler/expr/array/Testcase_003_001.noja-test similarity index 56% rename from tests/suite/Testcase_003_001 rename to tests/compiler/expr/array/Testcase_003_001.noja-test index 1bb73a7..6789c7c 100644 --- a/tests/suite/Testcase_003_001 +++ b/tests/compiler/expr/array/Testcase_003_001.noja-test @@ -1,9 +1,12 @@ -#source - +@type [compiler] +@source + # This comment is because there + # can't be a '[' right before a + # tag. [true, false]; -#bytecode +@bytecode PUSHLST 2; diff --git a/tests/suite/Testcase_005_000 b/tests/compiler/expr/assignment/Testcase_005_000.noja-test similarity index 59% rename from tests/suite/Testcase_005_000 rename to tests/compiler/expr/assignment/Testcase_005_000.noja-test index 4d9fe79..e05f136 100644 --- a/tests/suite/Testcase_005_000 +++ b/tests/compiler/expr/assignment/Testcase_005_000.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source var = none; -#bytecode +@bytecode PUSHNNE; ASS "var"; diff --git a/tests/suite/Testcase_005_001 b/tests/compiler/expr/assignment/Testcase_005_001.noja-test similarity index 77% rename from tests/suite/Testcase_005_001 rename to tests/compiler/expr/assignment/Testcase_005_001.noja-test index 5139330..6463ed8 100644 --- a/tests/suite/Testcase_005_001 +++ b/tests/compiler/expr/assignment/Testcase_005_001.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source var[key] = none; -#bytecode +@bytecode PUSHNNE; PUSHVAR "var"; diff --git a/tests/suite/Testcase_005_002 b/tests/compiler/expr/assignment/Testcase_005_002.noja-test similarity index 71% rename from tests/suite/Testcase_005_002 rename to tests/compiler/expr/assignment/Testcase_005_002.noja-test index 1ce459e..5810e8b 100644 --- a/tests/suite/Testcase_005_002 +++ b/tests/compiler/expr/assignment/Testcase_005_002.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source A, B = func(); -#bytecode +@bytecode PUSHVAR "func"; CALL 0, 2; diff --git a/tests/suite/Testcase_005_003 b/tests/compiler/expr/assignment/Testcase_005_003.noja-test similarity index 76% rename from tests/suite/Testcase_005_003 rename to tests/compiler/expr/assignment/Testcase_005_003.noja-test index 54bb3c6..0c7d8ca 100644 --- a/tests/suite/Testcase_005_003 +++ b/tests/compiler/expr/assignment/Testcase_005_003.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source var.key = none; -#bytecode +@bytecode PUSHNNE; PUSHVAR "var"; diff --git a/tests/suite/Testcase_002_021 b/tests/compiler/expr/logical/Testcase_002_021.noja-test similarity index 79% rename from tests/suite/Testcase_002_021 rename to tests/compiler/expr/logical/Testcase_002_021.noja-test index 6ec054e..5f06a9a 100644 --- a/tests/suite/Testcase_002_021 +++ b/tests/compiler/expr/logical/Testcase_002_021.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 and 2; -#bytecode +@bytecode PUSHINT 1; JUMPIFNOTANDPOP false; diff --git a/tests/suite/Testcase_002_022 b/tests/compiler/expr/logical/Testcase_002_022.noja-test similarity index 77% rename from tests/suite/Testcase_002_022 rename to tests/compiler/expr/logical/Testcase_002_022.noja-test index 2445bf8..2686549 100644 --- a/tests/suite/Testcase_002_022 +++ b/tests/compiler/expr/logical/Testcase_002_022.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 or 2; -#bytecode +@bytecode PUSHINT 1; JUMPIFANDPOP true; diff --git a/tests/suite/Testcase_002_032 b/tests/compiler/expr/logical/Testcase_002_032.noja-test similarity index 91% rename from tests/suite/Testcase_002_032 rename to tests/compiler/expr/logical/Testcase_002_032.noja-test index 73c8208..1a45894 100644 --- a/tests/suite/Testcase_002_032 +++ b/tests/compiler/expr/logical/Testcase_002_032.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source A and B or C and D; -#bytecode +@bytecode PUSHVAR "A"; JUMPIFNOTANDPOP false_0; diff --git a/tests/suite/Testcase_002_033 b/tests/compiler/expr/logical/Testcase_002_033.noja-test similarity index 90% rename from tests/suite/Testcase_002_033 rename to tests/compiler/expr/logical/Testcase_002_033.noja-test index f2081e1..19aaff2 100644 --- a/tests/suite/Testcase_002_033 +++ b/tests/compiler/expr/logical/Testcase_002_033.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source X or Y and Z or W; -#bytecode +@bytecode PUSHVAR "X"; JUMPIFANDPOP true_0; diff --git a/tests/suite/Testcase_004_000 b/tests/compiler/expr/map/Testcase_004_000.noja-test similarity index 73% rename from tests/suite/Testcase_004_000 rename to tests/compiler/expr/map/Testcase_004_000.noja-test index cccccbd..4a95617 100644 --- a/tests/suite/Testcase_004_000 +++ b/tests/compiler/expr/map/Testcase_004_000.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source ({'name': 'Francesco'}); -#bytecode +@bytecode PUSHMAP 1; PUSHSTR "name"; diff --git a/tests/suite/Testcase_004_001 b/tests/compiler/expr/map/Testcase_004_001.noja-test similarity index 81% rename from tests/suite/Testcase_004_001 rename to tests/compiler/expr/map/Testcase_004_001.noja-test index c269970..387e6cb 100644 --- a/tests/suite/Testcase_004_001 +++ b/tests/compiler/expr/map/Testcase_004_001.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source ({'name': 'Francesco', 'age': 25}); -#bytecode +@bytecode PUSHMAP 2; diff --git a/tests/suite/Testcase_004_002 b/tests/compiler/expr/map/Testcase_004_002.noja-test similarity index 73% rename from tests/suite/Testcase_004_002 rename to tests/compiler/expr/map/Testcase_004_002.noja-test index 64b1b5d..f7a6ab4 100644 --- a/tests/suite/Testcase_004_002 +++ b/tests/compiler/expr/map/Testcase_004_002.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source ({name: 'Francesco'}); -#bytecode +@bytecode PUSHMAP 1; PUSHSTR "name"; diff --git a/tests/suite/Testcase_004_003 b/tests/compiler/expr/map/Testcase_004_003.noja-test similarity index 80% rename from tests/suite/Testcase_004_003 rename to tests/compiler/expr/map/Testcase_004_003.noja-test index 93aa640..093df67 100644 --- a/tests/suite/Testcase_004_003 +++ b/tests/compiler/expr/map/Testcase_004_003.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source ({name: 'Francesco', age: 25}); -#bytecode +@bytecode PUSHMAP 2; diff --git a/tests/suite/Testcase_004_005 b/tests/compiler/expr/map/Testcase_004_004.noja-test similarity index 75% rename from tests/suite/Testcase_004_005 rename to tests/compiler/expr/map/Testcase_004_004.noja-test index 803f8c5..cf87d59 100644 --- a/tests/suite/Testcase_004_005 +++ b/tests/compiler/expr/map/Testcase_004_004.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source ({+name: 'Francesco'}); -#bytecode +@bytecode PUSHMAP 1; PUSHVAR "name"; diff --git a/tests/suite/Testcase_004_004 b/tests/compiler/expr/map/Testcase_004_005.noja-test similarity index 75% rename from tests/suite/Testcase_004_004 rename to tests/compiler/expr/map/Testcase_004_005.noja-test index 803f8c5..cf87d59 100644 --- a/tests/suite/Testcase_004_004 +++ b/tests/compiler/expr/map/Testcase_004_005.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source ({+name: 'Francesco'}); -#bytecode +@bytecode PUSHMAP 1; PUSHVAR "name"; diff --git a/tests/suite/Testcase_006_000 b/tests/compiler/expr/postfix/Testcase_006_000.noja-test similarity index 62% rename from tests/suite/Testcase_006_000 rename to tests/compiler/expr/postfix/Testcase_006_000.noja-test index 57e10cd..0b7676f 100644 --- a/tests/suite/Testcase_006_000 +++ b/tests/compiler/expr/postfix/Testcase_006_000.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source func(); -#bytecode +@bytecode PUSHVAR "func"; CALL 0, 1; diff --git a/tests/suite/Testcase_006_001 b/tests/compiler/expr/postfix/Testcase_006_001.noja-test similarity index 67% rename from tests/suite/Testcase_006_001 rename to tests/compiler/expr/postfix/Testcase_006_001.noja-test index eb87b5a..2e59e9b 100644 --- a/tests/suite/Testcase_006_001 +++ b/tests/compiler/expr/postfix/Testcase_006_001.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source func(none); -#bytecode +@bytecode PUSHNNE; PUSHVAR "func"; diff --git a/tests/suite/Testcase_006_002 b/tests/compiler/expr/postfix/Testcase_006_002.noja-test similarity index 70% rename from tests/suite/Testcase_006_002 rename to tests/compiler/expr/postfix/Testcase_006_002.noja-test index 9c414f7..537238e 100644 --- a/tests/suite/Testcase_006_002 +++ b/tests/compiler/expr/postfix/Testcase_006_002.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source func(true, false); -#bytecode +@bytecode PUSHFLS; PUSHTRU; diff --git a/tests/suite/Testcase_007_000 b/tests/compiler/expr/postfix/Testcase_007_000.noja-test similarity index 66% rename from tests/suite/Testcase_007_000 rename to tests/compiler/expr/postfix/Testcase_007_000.noja-test index 5288c66..2e08f2d 100644 --- a/tests/suite/Testcase_007_000 +++ b/tests/compiler/expr/postfix/Testcase_007_000.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source set[key]; -#bytecode +@bytecode PUSHVAR "set"; PUSHVAR "key"; diff --git a/tests/suite/Testcase_007_001 b/tests/compiler/expr/postfix/Testcase_007_001.noja-test similarity index 84% rename from tests/suite/Testcase_007_001 rename to tests/compiler/expr/postfix/Testcase_007_001.noja-test index ca0e110..b580324 100644 --- a/tests/suite/Testcase_007_001 +++ b/tests/compiler/expr/postfix/Testcase_007_001.noja-test @@ -1,8 +1,9 @@ -#source +@type [compiler] +@source set["dog", "cow", "cat"]; -#bytecode +@bytecode PUSHVAR "set"; diff --git a/tests/suite/Testcase_007_002 b/tests/compiler/expr/postfix/Testcase_007_002.noja-test similarity index 66% rename from tests/suite/Testcase_007_002 rename to tests/compiler/expr/postfix/Testcase_007_002.noja-test index e4c75fe..84b235b 100644 --- a/tests/suite/Testcase_007_002 +++ b/tests/compiler/expr/postfix/Testcase_007_002.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source set.key; -#bytecode +@bytecode PUSHVAR "set"; PUSHSTR "key"; diff --git a/tests/suite/Testcase_002_012 b/tests/compiler/expr/prefix/Testcase_002_012.noja-test similarity index 51% rename from tests/suite/Testcase_002_012 rename to tests/compiler/expr/prefix/Testcase_002_012.noja-test index 09369d5..1e5f93b 100644 --- a/tests/suite/Testcase_002_012 +++ b/tests/compiler/expr/prefix/Testcase_002_012.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source -1; -#bytecode +@bytecode PUSHINT 1; NEG; diff --git a/tests/suite/Testcase_002_013 b/tests/compiler/expr/prefix/Testcase_002_013.noja-test similarity index 51% rename from tests/suite/Testcase_002_013 rename to tests/compiler/expr/prefix/Testcase_002_013.noja-test index 0cca545..febc6c7 100644 --- a/tests/suite/Testcase_002_013 +++ b/tests/compiler/expr/prefix/Testcase_002_013.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source +1; -#bytecode +@bytecode PUSHINT 1; POS; diff --git a/tests/suite/Testcase_002_014 b/tests/compiler/expr/prefix/Testcase_002_014.noja-test similarity index 53% rename from tests/suite/Testcase_002_014 rename to tests/compiler/expr/prefix/Testcase_002_014.noja-test index 11c53b0..c758895 100644 --- a/tests/suite/Testcase_002_014 +++ b/tests/compiler/expr/prefix/Testcase_002_014.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source not 1; -#bytecode +@bytecode PUSHINT 1; NOT; diff --git a/tests/compiler/expr/primary/primary_000.noja-test b/tests/compiler/expr/primary/primary_000.noja-test new file mode 100644 index 0000000..7a906fc --- /dev/null +++ b/tests/compiler/expr/primary/primary_000.noja-test @@ -0,0 +1,9 @@ +@type [compiler] + +@source + 1; + +@bytecode + PUSHINT 1; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_001_001 b/tests/compiler/expr/primary/primary_001.noja-test similarity index 54% rename from tests/suite/Testcase_001_001 rename to tests/compiler/expr/primary/primary_001.noja-test index 6b9d80f..3293a9f 100644 --- a/tests/suite/Testcase_001_001 +++ b/tests/compiler/expr/primary/primary_001.noja-test @@ -1,9 +1,10 @@ +@type [compiler] -#source +@source 6.7; -#bytecode +@bytecode PUSHFLT 6.7; POP 1; diff --git a/tests/suite/Testcase_001_002 b/tests/compiler/expr/primary/primary_002.noja-test similarity index 63% rename from tests/suite/Testcase_001_002 rename to tests/compiler/expr/primary/primary_002.noja-test index 17b2edc..238f9d4 100644 --- a/tests/suite/Testcase_001_002 +++ b/tests/compiler/expr/primary/primary_002.noja-test @@ -1,9 +1,10 @@ +@type [compiler] -#source +@source 'Hello, world!'; -#bytecode +@bytecode PUSHSTR "Hello, world!"; POP 1; diff --git a/tests/suite/Testcase_001_003 b/tests/compiler/expr/primary/primary_003.noja-test similarity index 53% rename from tests/suite/Testcase_001_003 rename to tests/compiler/expr/primary/primary_003.noja-test index dbad5cc..08d5f5f 100644 --- a/tests/suite/Testcase_001_003 +++ b/tests/compiler/expr/primary/primary_003.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source true; -#bytecode +@bytecode PUSHTRU; POP 1; diff --git a/tests/suite/Testcase_001_004 b/tests/compiler/expr/primary/primary_004.noja-test similarity index 53% rename from tests/suite/Testcase_001_004 rename to tests/compiler/expr/primary/primary_004.noja-test index b338cd8..c4473ae 100644 --- a/tests/suite/Testcase_001_004 +++ b/tests/compiler/expr/primary/primary_004.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source false; -#bytecode +@bytecode PUSHFLS; POP 1; diff --git a/tests/suite/Testcase_001_005 b/tests/compiler/expr/primary/primary_005.noja-test similarity index 53% rename from tests/suite/Testcase_001_005 rename to tests/compiler/expr/primary/primary_005.noja-test index 20e71b3..8701077 100644 --- a/tests/suite/Testcase_001_005 +++ b/tests/compiler/expr/primary/primary_005.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source none; -#bytecode +@bytecode PUSHNNE; POP 1; diff --git a/tests/suite/Testcase_001_006 b/tests/compiler/expr/primary/primary_006.noja-test similarity index 52% rename from tests/suite/Testcase_001_006 rename to tests/compiler/expr/primary/primary_006.noja-test index 295fd02..0f0e5c9 100644 --- a/tests/suite/Testcase_001_006 +++ b/tests/compiler/expr/primary/primary_006.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source ({}); -#bytecode +@bytecode PUSHMAP 0; POP 1; diff --git a/tests/compiler/expr/primary/primary_007.noja-test b/tests/compiler/expr/primary/primary_007.noja-test new file mode 100644 index 0000000..09428f5 --- /dev/null +++ b/tests/compiler/expr/primary/primary_007.noja-test @@ -0,0 +1,14 @@ + +@type [compiler] + +@source + # This comment is because there + # can't be a '[' right before a + # tag. + []; + +@bytecode + + PUSHLST 0; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/compiler/expr/primary/primary_008.noja-test b/tests/compiler/expr/primary/primary_008.noja-test new file mode 100644 index 0000000..0085103 --- /dev/null +++ b/tests/compiler/expr/primary/primary_008.noja-test @@ -0,0 +1,9 @@ + +@type [compiler] +@source + + {} + +@bytecode + + EXIT; \ No newline at end of file diff --git a/tests/compiler/expr/primary/primary_009.noja-test b/tests/compiler/expr/primary/primary_009.noja-test new file mode 100644 index 0000000..94535bd --- /dev/null +++ b/tests/compiler/expr/primary/primary_009.noja-test @@ -0,0 +1,11 @@ +@type [compiler] + +@source + + 'This \\ is a slash!'; + +@bytecode + + PUSHSTR "This \\ is a slash!"; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/compiler/expr/primary/primary_010.noja-test b/tests/compiler/expr/primary/primary_010.noja-test new file mode 100644 index 0000000..8c6ef6c --- /dev/null +++ b/tests/compiler/expr/primary/primary_010.noja-test @@ -0,0 +1,11 @@ +@type [compiler] + +@source + + 'This \n is a newline!'; + +@bytecode + + PUSHSTR "This \n is a newline!"; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/compiler/expr/primary/primary_011.noja-test b/tests/compiler/expr/primary/primary_011.noja-test new file mode 100644 index 0000000..b096d8e --- /dev/null +++ b/tests/compiler/expr/primary/primary_011.noja-test @@ -0,0 +1,11 @@ +@type [compiler] + +@source + + 'This \t is an horizontal tab!'; + +@bytecode + + PUSHSTR "This \t is an horizontal tab!"; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/compiler/expr/primary/primary_012.noja-test b/tests/compiler/expr/primary/primary_012.noja-test new file mode 100644 index 0000000..a0ab05c --- /dev/null +++ b/tests/compiler/expr/primary/primary_012.noja-test @@ -0,0 +1,11 @@ +@type [compiler] + +@source + + 'This \r is a special character!'; + +@bytecode + + PUSHSTR "This \r is a special character!"; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/compiler/expr/primary/primary_013.noja-test b/tests/compiler/expr/primary/primary_013.noja-test new file mode 100644 index 0000000..6a6cec2 --- /dev/null +++ b/tests/compiler/expr/primary/primary_013.noja-test @@ -0,0 +1,11 @@ +@type [compiler] + +@source + + 'Look at this \'!'; + +@bytecode + + PUSHSTR "Look at this '!"; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/compiler/expr/primary/primary_014.noja-test b/tests/compiler/expr/primary/primary_014.noja-test new file mode 100644 index 0000000..0d2122a --- /dev/null +++ b/tests/compiler/expr/primary/primary_014.noja-test @@ -0,0 +1,11 @@ +@type [compiler] + +@source + + "Look at this \"!"; + +@bytecode + + PUSHSTR "Look at this \"!"; + POP 1; + EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_002_015 b/tests/compiler/expr/relational/Testcase_002_015.noja-test similarity index 60% rename from tests/suite/Testcase_002_015 rename to tests/compiler/expr/relational/Testcase_002_015.noja-test index f2f065b..74a8422 100644 --- a/tests/suite/Testcase_002_015 +++ b/tests/compiler/expr/relational/Testcase_002_015.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 == 2; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_016 b/tests/compiler/expr/relational/Testcase_002_016.noja-test similarity index 60% rename from tests/suite/Testcase_002_016 rename to tests/compiler/expr/relational/Testcase_002_016.noja-test index 7614b0a..cad6de8 100644 --- a/tests/suite/Testcase_002_016 +++ b/tests/compiler/expr/relational/Testcase_002_016.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 != 2; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_017 b/tests/compiler/expr/relational/Testcase_002_017.noja-test similarity index 59% rename from tests/suite/Testcase_002_017 rename to tests/compiler/expr/relational/Testcase_002_017.noja-test index 546f488..9525622 100644 --- a/tests/suite/Testcase_002_017 +++ b/tests/compiler/expr/relational/Testcase_002_017.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 < 2; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_018 b/tests/compiler/expr/relational/Testcase_002_018.noja-test similarity index 59% rename from tests/suite/Testcase_002_018 rename to tests/compiler/expr/relational/Testcase_002_018.noja-test index d7c5df1..cdedeba 100644 --- a/tests/suite/Testcase_002_018 +++ b/tests/compiler/expr/relational/Testcase_002_018.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 > 2; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_019 b/tests/compiler/expr/relational/Testcase_002_019.noja-test similarity index 60% rename from tests/suite/Testcase_002_019 rename to tests/compiler/expr/relational/Testcase_002_019.noja-test index d9bdb4d..4b2969b 100644 --- a/tests/suite/Testcase_002_019 +++ b/tests/compiler/expr/relational/Testcase_002_019.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 <= 2; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_020 b/tests/compiler/expr/relational/Testcase_002_020.noja-test similarity index 60% rename from tests/suite/Testcase_002_020 rename to tests/compiler/expr/relational/Testcase_002_020.noja-test index 79b252e..0135431 100644 --- a/tests/suite/Testcase_002_020 +++ b/tests/compiler/expr/relational/Testcase_002_020.noja-test @@ -1,9 +1,10 @@ -#source +@type [compiler] +@source 1 >= 2; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_002_034 b/tests/compiler/expr/relational_and_logical/Testcase_002_034.noja-test similarity index 91% rename from tests/suite/Testcase_002_034 rename to tests/compiler/expr/relational_and_logical/Testcase_002_034.noja-test index 9ebf311..034fd51 100644 --- a/tests/suite/Testcase_002_034 +++ b/tests/compiler/expr/relational_and_logical/Testcase_002_034.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source 1 + 2 > 3 + 4; 1 + 2 < 3 + 4; 1 + 2 >= 3 + 4; 1 + 2 <= 3 + 4; -#bytecode +@bytecode PUSHINT 1; PUSHINT 2; diff --git a/tests/suite/Testcase_011_000 b/tests/compiler/func/Testcase_011_000.noja-test similarity index 55% rename from tests/suite/Testcase_011_000 rename to tests/compiler/func/Testcase_011_000.noja-test index 9c63008..c389f30 100644 --- a/tests/suite/Testcase_011_000 +++ b/tests/compiler/func/Testcase_011_000.noja-test @@ -1,11 +1,12 @@ -#source +@type [compiler] +@source fun X() {} -#bytecode +@bytecode - PUSHFUN fun, 0; + PUSHFUN fun, 0, "X"; JUMP end; fun: RETURN 0; diff --git a/tests/suite/Testcase_011_001 b/tests/compiler/func/Testcase_011_001.noja-test similarity index 66% rename from tests/suite/Testcase_011_001 rename to tests/compiler/func/Testcase_011_001.noja-test index 9f04e8d..f4f000c 100644 --- a/tests/suite/Testcase_011_001 +++ b/tests/compiler/func/Testcase_011_001.noja-test @@ -1,11 +1,12 @@ -#source +@type [compiler] +@source fun X() "Hello, world!"; -#bytecode +@bytecode - PUSHFUN fun, 0; + PUSHFUN fun, 0, "X"; JUMP end; fun: PUSHSTR "Hello, world!"; diff --git a/tests/suite/Testcase_011_002 b/tests/compiler/func/Testcase_011_002.noja-test similarity index 74% rename from tests/suite/Testcase_011_002 rename to tests/compiler/func/Testcase_011_002.noja-test index 37658ae..23def24 100644 --- a/tests/suite/Testcase_011_002 +++ b/tests/compiler/func/Testcase_011_002.noja-test @@ -1,14 +1,15 @@ -#source +@type [compiler] +@source fun X() { "Hello, world!"; return false; } -#bytecode +@bytecode - PUSHFUN fun, 0; + PUSHFUN fun, 0, "X"; JUMP end; fun: PUSHSTR "Hello, world!"; diff --git a/tests/suite/Testcase_011_003 b/tests/compiler/func/Testcase_011_003.noja-test similarity index 70% rename from tests/suite/Testcase_011_003 rename to tests/compiler/func/Testcase_011_003.noja-test index 608d508..fe2dc38 100644 --- a/tests/suite/Testcase_011_003 +++ b/tests/compiler/func/Testcase_011_003.noja-test @@ -1,13 +1,14 @@ -#source +@type [compiler] +@source fun nop(a) { return a; } -#bytecode +@bytecode - PUSHFUN fun, 1; + PUSHFUN fun, 1, "nop"; JUMP end; fun: ASS "a"; diff --git a/tests/suite/Testcase_011_004 b/tests/compiler/func/Testcase_011_004.noja-test similarity index 76% rename from tests/suite/Testcase_011_004 rename to tests/compiler/func/Testcase_011_004.noja-test index cc718c3..956ad66 100644 --- a/tests/suite/Testcase_011_004 +++ b/tests/compiler/func/Testcase_011_004.noja-test @@ -1,13 +1,14 @@ -#source +@type [compiler] +@source fun add(a, b) { return a + b; } -#bytecode +@bytecode - PUSHFUN fun, 2; + PUSHFUN fun, 2, "add"; JUMP end; fun: ASS "b"; diff --git a/tests/suite/Testcase_011_005 b/tests/compiler/func/Testcase_011_005.noja-test similarity index 75% rename from tests/suite/Testcase_011_005 rename to tests/compiler/func/Testcase_011_005.noja-test index 6fb92f7..985884a 100644 --- a/tests/suite/Testcase_011_005 +++ b/tests/compiler/func/Testcase_011_005.noja-test @@ -1,13 +1,14 @@ -#source +@type [compiler] +@source fun nop(a: None) { return a; } -#bytecode +@bytecode - PUSHFUN fun, 1; + PUSHFUN fun, 1, "nop"; JUMP end; fun: PUSHVAR "None"; diff --git a/tests/suite/Testcase_011_006 b/tests/compiler/func/Testcase_011_006.noja-test similarity index 79% rename from tests/suite/Testcase_011_006 rename to tests/compiler/func/Testcase_011_006.noja-test index 4d04c93..e2bcc2f 100644 --- a/tests/suite/Testcase_011_006 +++ b/tests/compiler/func/Testcase_011_006.noja-test @@ -1,13 +1,14 @@ -#source +@type [compiler] +@source fun add(a: int, b) { return a + b; } -#bytecode +@bytecode - PUSHFUN fun, 2; + PUSHFUN fun, 2, "add"; JUMP end; fun: ASS "b"; diff --git a/tests/suite/Testcase_011_007 b/tests/compiler/func/Testcase_011_007.noja-test similarity index 79% rename from tests/suite/Testcase_011_007 rename to tests/compiler/func/Testcase_011_007.noja-test index 8d05dba..926fbdd 100644 --- a/tests/suite/Testcase_011_007 +++ b/tests/compiler/func/Testcase_011_007.noja-test @@ -1,13 +1,14 @@ -#source +@type [compiler] +@source fun add(a, b: int) { return a + b; } -#bytecode +@bytecode - PUSHFUN fun, 2; + PUSHFUN fun, 2, "add"; JUMP end; fun: PUSHVAR "int"; diff --git a/tests/suite/Testcase_011_008 b/tests/compiler/func/Testcase_011_008.noja-test similarity index 81% rename from tests/suite/Testcase_011_008 rename to tests/compiler/func/Testcase_011_008.noja-test index 8d36d01..d359f1f 100644 --- a/tests/suite/Testcase_011_008 +++ b/tests/compiler/func/Testcase_011_008.noja-test @@ -1,13 +1,14 @@ -#source +@type [compiler] +@source fun add(a: int, b: int) { return a + b; } -#bytecode +@bytecode - PUSHFUN fun, 2; + PUSHFUN fun, 2, "add"; JUMP end; fun: PUSHVAR "int"; diff --git a/tests/suite/Testcase_011_009 b/tests/compiler/func/Testcase_011_009.noja-test similarity index 84% rename from tests/suite/Testcase_011_009 rename to tests/compiler/func/Testcase_011_009.noja-test index 1494c54..e47a272 100644 --- a/tests/suite/Testcase_011_009 +++ b/tests/compiler/func/Testcase_011_009.noja-test @@ -1,13 +1,14 @@ -#source +@type [compiler] +@source fun add(a: int | float, b: bool | Map) { return a + b; } -#bytecode +@bytecode - PUSHFUN fun, 2; + PUSHFUN fun, 2, "add"; JUMP end; fun: PUSHVAR "bool"; diff --git a/tests/suite/Testcase_012_000 b/tests/compiler/func/Testcase_012_000.noja-test similarity index 80% rename from tests/suite/Testcase_012_000 rename to tests/compiler/func/Testcase_012_000.noja-test index 70c893b..dbf4179 100644 --- a/tests/suite/Testcase_012_000 +++ b/tests/compiler/func/Testcase_012_000.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source fun nop(a = 1) {} -#bytecode +@bytecode - PUSHFUN nop, 1; + PUSHFUN nop, 1, "nop"; JUMP nop_end; nop: PUSHTYP; diff --git a/tests/suite/Testcase_012_001 b/tests/compiler/func/Testcase_012_001.noja-test similarity index 78% rename from tests/suite/Testcase_012_001 rename to tests/compiler/func/Testcase_012_001.noja-test index 6751111..fcfaf30 100644 --- a/tests/suite/Testcase_012_001 +++ b/tests/compiler/func/Testcase_012_001.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source fun nop(a = 1, b) {} -#bytecode +@bytecode - PUSHFUN nop, 2; + PUSHFUN nop, 2, "nop"; JUMP nop_end; nop: ASS "b"; diff --git a/tests/suite/Testcase_012_002 b/tests/compiler/func/Testcase_012_002.noja-test similarity index 78% rename from tests/suite/Testcase_012_002 rename to tests/compiler/func/Testcase_012_002.noja-test index 98fc52a..e282e64 100644 --- a/tests/suite/Testcase_012_002 +++ b/tests/compiler/func/Testcase_012_002.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source fun nop(a, b = true) {} -#bytecode +@bytecode - PUSHFUN nop, 2; + PUSHFUN nop, 2, "nop"; JUMP nop_end; nop: PUSHTYP; diff --git a/tests/suite/Testcase_012_003 b/tests/compiler/func/Testcase_012_003.noja-test similarity index 82% rename from tests/suite/Testcase_012_003 rename to tests/compiler/func/Testcase_012_003.noja-test index 8763941..06e7fdb 100644 --- a/tests/suite/Testcase_012_003 +++ b/tests/compiler/func/Testcase_012_003.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source fun nop(a: int = 1) {} -#bytecode +@bytecode - PUSHFUN nop, 1; + PUSHFUN nop, 1, "nop"; JUMP nop_end; nop: PUSHTYP; diff --git a/tests/suite/Testcase_008_000 b/tests/compiler/ifelse/Testcase_008_000.noja-test similarity index 63% rename from tests/suite/Testcase_008_000 rename to tests/compiler/ifelse/Testcase_008_000.noja-test index b9d0cfe..ec88577 100644 --- a/tests/suite/Testcase_008_000 +++ b/tests/compiler/ifelse/Testcase_008_000.noja-test @@ -1,10 +1,11 @@ -#source +@type [compiler] +@source if true: {} -#bytecode +@bytecode PUSHTRU; JUMPIFNOTANDPOP end; diff --git a/tests/suite/Testcase_008_001 b/tests/compiler/ifelse/Testcase_008_001.noja-test similarity index 69% rename from tests/suite/Testcase_008_001 rename to tests/compiler/ifelse/Testcase_008_001.noja-test index e092073..342a587 100644 --- a/tests/suite/Testcase_008_001 +++ b/tests/compiler/ifelse/Testcase_008_001.noja-test @@ -1,10 +1,11 @@ -#source +@type [compiler] +@source if true: none; -#bytecode +@bytecode PUSHTRU; JUMPIFNOTANDPOP end; diff --git a/tests/suite/Testcase_008_002 b/tests/compiler/ifelse/Testcase_008_002.noja-test similarity index 72% rename from tests/suite/Testcase_008_002 rename to tests/compiler/ifelse/Testcase_008_002.noja-test index a68fd35..3de0b69 100644 --- a/tests/suite/Testcase_008_002 +++ b/tests/compiler/ifelse/Testcase_008_002.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source if true: {} else {} -#bytecode +@bytecode PUSHTRU; JUMPIFNOTANDPOP end; diff --git a/tests/suite/Testcase_008_003 b/tests/compiler/ifelse/Testcase_008_003.noja-test similarity index 79% rename from tests/suite/Testcase_008_003 rename to tests/compiler/ifelse/Testcase_008_003.noja-test index cc31757..405723c 100644 --- a/tests/suite/Testcase_008_003 +++ b/tests/compiler/ifelse/Testcase_008_003.noja-test @@ -1,12 +1,13 @@ -#source +@type [compiler] +@source if none: true; else false; -#bytecode +@bytecode PUSHNNE; JUMPIFNOTANDPOP else; diff --git a/tests/compiler/other/Testcase_000_000.noja-test b/tests/compiler/other/Testcase_000_000.noja-test new file mode 100644 index 0000000..246dec9 --- /dev/null +++ b/tests/compiler/other/Testcase_000_000.noja-test @@ -0,0 +1,7 @@ +@type [compiler] + +@source + # (Empty source) + +@bytecode + EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_000_001 b/tests/compiler/other/Testcase_000_001.noja-test similarity index 51% rename from tests/suite/Testcase_000_001 rename to tests/compiler/other/Testcase_000_001.noja-test index 6301d1b..d9dd9d5 100644 --- a/tests/suite/Testcase_000_001 +++ b/tests/compiler/other/Testcase_000_001.noja-test @@ -1,10 +1,9 @@ +@type [compiler] -#source - +@source return none; -#bytecode - +@bytecode PUSHNNE; RETURN 1; EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_009_000 b/tests/compiler/while/Testcase_009_000.noja-test similarity index 69% rename from tests/suite/Testcase_009_000 rename to tests/compiler/while/Testcase_009_000.noja-test index 8b7944e..d3dc929 100644 --- a/tests/suite/Testcase_009_000 +++ b/tests/compiler/while/Testcase_009_000.noja-test @@ -1,10 +1,11 @@ -#source +@type [compiler] +@source while none: {} -#bytecode +@bytecode begin: PUSHNNE; diff --git a/tests/suite/Testcase_009_001 b/tests/compiler/while/Testcase_009_001.noja-test similarity index 78% rename from tests/suite/Testcase_009_001 rename to tests/compiler/while/Testcase_009_001.noja-test index 967f517..e9f2854 100644 --- a/tests/suite/Testcase_009_001 +++ b/tests/compiler/while/Testcase_009_001.noja-test @@ -1,11 +1,12 @@ -#source +@type [compiler] +@source while none: true; false; -#bytecode +@bytecode begin: PUSHNNE; diff --git a/tests/suite/Testcase_009_002 b/tests/compiler/while/Testcase_009_002.noja-test similarity index 84% rename from tests/suite/Testcase_009_002 rename to tests/compiler/while/Testcase_009_002.noja-test index 32e5603..f6a0ee0 100644 --- a/tests/suite/Testcase_009_002 +++ b/tests/compiler/while/Testcase_009_002.noja-test @@ -1,5 +1,6 @@ -#source +@type [compiler] +@source while none: { true; @@ -7,7 +8,7 @@ } false; -#bytecode +@bytecode begin: PUSHNNE; diff --git a/tests/suite/Testcase_009_003 b/tests/compiler/while/Testcase_009_003.noja-test similarity index 85% rename from tests/suite/Testcase_009_003 rename to tests/compiler/while/Testcase_009_003.noja-test index 8d400b9..a4042a7 100644 --- a/tests/suite/Testcase_009_003 +++ b/tests/compiler/while/Testcase_009_003.noja-test @@ -1,5 +1,6 @@ -#source +@type [compiler] +@source while none: { true; @@ -8,7 +9,7 @@ } false; -#bytecode +@bytecode begin: PUSHNNE; diff --git a/tests/suite/Testcase_009_004 b/tests/compiler/while/Testcase_009_004.noja-test similarity index 77% rename from tests/suite/Testcase_009_004 rename to tests/compiler/while/Testcase_009_004.noja-test index 0556869..147b91c 100644 --- a/tests/suite/Testcase_009_004 +++ b/tests/compiler/while/Testcase_009_004.noja-test @@ -1,11 +1,12 @@ -#source +@type [compiler] +@source while none: break; false; -#bytecode +@bytecode begin: PUSHNNE; diff --git a/tests/runtime/tcase_000.noja-test b/tests/runtime/tcase_000.noja-test new file mode 100644 index 0000000..67ed7e6 --- /dev/null +++ b/tests/runtime/tcase_000.noja-test @@ -0,0 +1,10 @@ +@type [runtime] + +@bytecode + PUSHNNE; + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [none] \ No newline at end of file diff --git a/tests/runtime/tcase_001.noja-test b/tests/runtime/tcase_001.noja-test new file mode 100644 index 0000000..e87e13f --- /dev/null +++ b/tests/runtime/tcase_001.noja-test @@ -0,0 +1,12 @@ +@type [runtime] + +@bytecode + + PUSHTRU; + + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [true] \ No newline at end of file diff --git a/tests/runtime/tcase_002.noja-test b/tests/runtime/tcase_002.noja-test new file mode 100644 index 0000000..57c8906 --- /dev/null +++ b/tests/runtime/tcase_002.noja-test @@ -0,0 +1,12 @@ +@type [runtime] + +@bytecode + + PUSHFLS; + + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [false] \ No newline at end of file diff --git a/tests/runtime/tcase_003.noja-test b/tests/runtime/tcase_003.noja-test new file mode 100644 index 0000000..457c871 --- /dev/null +++ b/tests/runtime/tcase_003.noja-test @@ -0,0 +1,12 @@ +@type [runtime] + +@bytecode + + PUSHINT 7; + + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [7] diff --git a/tests/runtime/tcase_004.noja-test b/tests/runtime/tcase_004.noja-test new file mode 100644 index 0000000..84b2e18 --- /dev/null +++ b/tests/runtime/tcase_004.noja-test @@ -0,0 +1,12 @@ +@type [runtime] + +@bytecode + + PUSHFLT 8.5; + + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [8.50] diff --git a/tests/runtime/tcase_005.noja-test b/tests/runtime/tcase_005.noja-test new file mode 100644 index 0000000..2f8b148 --- /dev/null +++ b/tests/runtime/tcase_005.noja-test @@ -0,0 +1,12 @@ +@type [runtime] + +@bytecode + + PUSHLST 0; + + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output {[]} diff --git a/tests/runtime/tcase_006.noja-test b/tests/runtime/tcase_006.noja-test new file mode 100644 index 0000000..8011914 --- /dev/null +++ b/tests/runtime/tcase_006.noja-test @@ -0,0 +1,12 @@ +@type [runtime] + +@bytecode + + PUSHNNETYP; + + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [None] \ No newline at end of file diff --git a/tests/runtime/tcase_007.noja-test b/tests/runtime/tcase_007.noja-test new file mode 100644 index 0000000..9256faa --- /dev/null +++ b/tests/runtime/tcase_007.noja-test @@ -0,0 +1,13 @@ +@type [runtime] + +@bytecode + + PUSHTRU; + PUSHTYP; + + PUSHVAR "print"; + CALL 1, 1; + POP 2; + EXIT; + +@output [bool] \ No newline at end of file diff --git a/tests/runtime/tcase_008.noja-test b/tests/runtime/tcase_008.noja-test new file mode 100644 index 0000000..95aa383 --- /dev/null +++ b/tests/runtime/tcase_008.noja-test @@ -0,0 +1,17 @@ +@type [runtime] + +@bytecode + + PUSHTRU; + JUMPIFNOTANDPOP ye; + PUSHINT 100; + JUMP end; +ye: + PUSHINT 300; +end: + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [100] \ No newline at end of file diff --git a/tests/runtime/tcase_009.noja-test b/tests/runtime/tcase_009.noja-test new file mode 100644 index 0000000..322c9ef --- /dev/null +++ b/tests/runtime/tcase_009.noja-test @@ -0,0 +1,17 @@ +@type [runtime] + +@bytecode + + PUSHFLS; + JUMPIFNOTANDPOP ye; + PUSHINT 100; + JUMP end; +ye: + PUSHINT 300; +end: + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [300] \ No newline at end of file diff --git a/tests/runtime/tcase_010.noja-test b/tests/runtime/tcase_010.noja-test new file mode 100644 index 0000000..5857ea0 --- /dev/null +++ b/tests/runtime/tcase_010.noja-test @@ -0,0 +1,17 @@ +@type [runtime] + +@bytecode + + PUSHTRU; + JUMPIFANDPOP ye; + PUSHINT 100; + JUMP end; +ye: + PUSHINT 300; +end: + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [300] \ No newline at end of file diff --git a/tests/runtime/tcase_011.noja-test b/tests/runtime/tcase_011.noja-test new file mode 100644 index 0000000..fffa255 --- /dev/null +++ b/tests/runtime/tcase_011.noja-test @@ -0,0 +1,17 @@ +@type [runtime] + +@bytecode + + PUSHFLS; + JUMPIFANDPOP ye; + PUSHINT 100; + JUMP end; +ye: + PUSHINT 300; +end: + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [100] \ No newline at end of file diff --git a/tests/runtime/tcase_012.noja-test b/tests/runtime/tcase_012.noja-test new file mode 100644 index 0000000..f57bf09 --- /dev/null +++ b/tests/runtime/tcase_012.noja-test @@ -0,0 +1,13 @@ +@type [runtime] + +@bytecode + + PUSHINT 23; + POS; + + PUSHVAR "print"; + CALL 1, 1; + POP 1; + EXIT; + +@output [23] \ No newline at end of file diff --git a/tests/suite/Testcase_000_000 b/tests/suite/Testcase_000_000 deleted file mode 100644 index e7d6b3f..0000000 --- a/tests/suite/Testcase_000_000 +++ /dev/null @@ -1,7 +0,0 @@ - -#source - - # (Empty source) - -#bytecode - EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_001_000 b/tests/suite/Testcase_001_000 deleted file mode 100644 index 9ff6226..0000000 --- a/tests/suite/Testcase_001_000 +++ /dev/null @@ -1,10 +0,0 @@ - -#source - - 1; - -#bytecode - - PUSHINT 1; - POP 1; - EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_001_007 b/tests/suite/Testcase_001_007 deleted file mode 100644 index 4317e6e..0000000 --- a/tests/suite/Testcase_001_007 +++ /dev/null @@ -1,10 +0,0 @@ - -#source - - []; - -#bytecode - - PUSHLST 0; - POP 1; - EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_001_008 b/tests/suite/Testcase_001_008 deleted file mode 100644 index 753a3b8..0000000 --- a/tests/suite/Testcase_001_008 +++ /dev/null @@ -1,8 +0,0 @@ - -#source - - {} - -#bytecode - - EXIT; \ No newline at end of file diff --git a/tests/suite/Testcase_003_000 b/tests/suite/Testcase_003_000 deleted file mode 100644 index 738c4a9..0000000 --- a/tests/suite/Testcase_003_000 +++ /dev/null @@ -1,13 +0,0 @@ - -#source - - [1]; - -#bytecode - - PUSHLST 1; - PUSHINT 0; - PUSHINT 1; - INSERT; - POP 1; - EXIT; \ No newline at end of file diff --git a/tests/test.noja b/tests/test.noja deleted file mode 100644 index a1aa511..0000000 --- a/tests/test.noja +++ /dev/null @@ -1,129 +0,0 @@ - -# Test the equal operator -{ - assert(1 == 1); - assert(1.0 == 1.0); - assert('--' == '--'); -} - -# Test assignment. -{ - a = 3; - assert(a == 3); -} - -# Test operations on integers. -{ - assert(4 == +4); - assert(0-4 == -4); - assert(1 + 1 == 2); - assert(2 * 3 == 6); - assert(6 / 3 == 2); - assert(4 < 5); - assert(4 > 3); - assert(4 <= 5); - assert(4 <= 4); - assert(4 >= 3); - assert(4 == 4); - assert(4 != 3); -} - -# Test operations on floats. -{ - assert(4.0 == +4.0); - assert(0-4.0 == -4.0); - assert(1.0 + 1.0 == 2.0); - assert(2.0 * 3.0 == 6.0); - assert(6.0 / 3.0 == 2.0); - assert(4.0 < 5.0); - assert(4.0 > 3.0); - assert(4.0 <= 5.0); - assert(4.0 <= 4.0); - assert(4.0 >= 3.0); - assert(4.0 == 4.0); - assert(4.0 != 3.0); -} - -# Test operations on strings. -{ - assert('hey' == 'hey'); - assert('hey' != 'hey2'); -} - -# Test operations on bools. -{ - assert(true); - assert(true == true); - assert(true != false); - assert(false == false); - assert(false != true); - assert(true == not false); - assert(false == not true); - assert((true and true ) == true); - assert((true and false) == false); - assert((false and true ) == false); - assert((false and false) == false); - assert((true or true ) == true); - assert((true or false) == true); - assert((false or true ) == true); - assert((false or false) == false); -} - -# Test short-circuitness of the logical operators -{ - # The assertions shouldn't trigger. - true or assert(false); - false and assert(false); -} - -# Test lists. -{ - [1]; [1.0]; ['x']; [1, 1]; [1.0, 1.0]; ['x', 'x']; -} - -# Test maps. -{ - ({}); - ({ '' : none }); - ({ 1 : none }); - ({ 1.0 : none }); - ({ none : none }); - ({ true : none }); - ({ false: none }); - ({ [] : none }); - ({ {} : none }); - ({ none : '' }); - ({ none : 1 }); - ({ none : 1.0 }); - ({ none : true }); - ({ none : false }); - ({ none : [] }); - ({ none : {} }); -} - -# Test if-else statements. -{ - if true: r = true; else r = false; - assert(r); - - if true: { r = true; } else { r = false; } - assert(r); - - if false: r = false; else r = true; - assert(r); - - if false: { r = false; } else { r = true; } - assert(r); -} - -# Test type variables -{ - assert(type(none) == None); - assert(type(1) == int); - assert(type(10.4) == float); - assert(type("Hello, world!") == String); - assert(type([]) == List); - assert(type({}) == Map); -} - -print('No assertion failed.\n'); \ No newline at end of file