From ee0243bd8a89ea4158231e364996f91c90ea819e Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Wed, 6 Sep 2023 06:54:51 +0200 Subject: [PATCH] Added __JUMP_IF__ operation, its generator, and a a test --- CMakeLists.txt | 1 + include/molasses/generator_primitives.h | 3 + .../generator_primitives_x86_64_linux.cpp | 10 +++ src/molasses/parser_primitives.cpp | 37 ++++++++- tests/001.exp | 2 +- tests/002.exp | 2 +- tests/003.exp | 2 +- tests/005.exp | 2 +- tests/006.exp | 2 +- tests/007.exp | 2 +- tests/007/exit-with-3.mol | 2 +- tests/008.exp | 82 +++++++++++++++++++ tests/008/exit-with-3.mol | 13 +++ tests/008/library.mol | 39 +++++++++ 14 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 tests/008.exp create mode 100644 tests/008/exit-with-3.mol create mode 100644 tests/008/library.mol diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bab386..ad4b5e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ add_expect_test(id004 ./tests/004.exp) add_expect_test(id005 ./tests/005.exp) add_expect_test(id006 ./tests/006.exp) add_expect_test(id007 ./tests/007.exp) +add_expect_test(id008 ./tests/008.exp) diff --git a/include/molasses/generator_primitives.h b/include/molasses/generator_primitives.h index 24556b6..ad50f10 100644 --- a/include/molasses/generator_primitives.h +++ b/include/molasses/generator_primitives.h @@ -14,6 +14,9 @@ namespace molasses { template std::vector generate_goto(const std::string& target); + template + std::vector generate_jump_if(const std::string& target); + template std::vector generate_push_int32(int32_t target); diff --git a/src/molasses/generator_primitives_x86_64_linux.cpp b/src/molasses/generator_primitives_x86_64_linux.cpp index 237af1c..0c30104 100644 --- a/src/molasses/generator_primitives_x86_64_linux.cpp +++ b/src/molasses/generator_primitives_x86_64_linux.cpp @@ -549,6 +549,16 @@ namespace molasses { }; } + template<> + std::vector generate_jump_if(const std::string& target) { + return { + " popq %rax\n", + " pushq %rax\n", + " cmpq $0, %rax\n" + " jne "+marshal(target)+"\n" + }; + } + template<> std::vector generate_return() { return { diff --git a/src/molasses/parser_primitives.cpp b/src/molasses/parser_primitives.cpp index 6189dc2..f29154b 100644 --- a/src/molasses/parser_primitives.cpp +++ b/src/molasses/parser_primitives.cpp @@ -107,6 +107,13 @@ namespace molasses { effective_snapshots[idx] = type_stack; it = ahead; ++idx; + } else if(auto ahead = it; ++ahead != consumed_stream.end() and (lexer_state.dictionary.at(*ahead) == "__JUMP_IF__")) { + if(type_stack.empty()) return false; + if(type_stack.back() != "i64") return false; + //type_stack.pop_back(); // JUMP_IF does not consume its test variable + effective_snapshots[idx] = type_stack; + it = ahead; + ++idx; } else if(symbol.is_string) { type_stack.emplace_back("u8 ptr"); } else if(auto is_int32 = try_parse_int32(symbol_text); is_int32) { @@ -134,7 +141,8 @@ namespace molasses { PROC_KW, END_KW, LABEL_KW, - GOTO_KW + GOTO_KW, + JUMP_IF_KW }; lexed_output fake; @@ -144,6 +152,7 @@ namespace molasses { fake.dictionary[END_KW] = "__END__"; fake.dictionary[LABEL_KW] = "__LABEL__"; fake.dictionary[GOTO_KW] = "__GOTO__"; + fake.dictionary[JUMP_IF_KW] = "__JUMP_IF__"; auto tokens = concatenate(fake, lexer_data); @@ -221,10 +230,13 @@ namespace molasses { std::vector> sub_bodies; std::map found_labels; std::map found_gotos; + std::map found_jump_ifs; while(*it != END_KW) { - if(auto ahead = it; ++ahead != tokens.symbols.end() and (*ahead == GOTO_KW or *ahead == LABEL_KW)) { + if(auto ahead = it; ++ahead != tokens.symbols.end() and (*ahead == GOTO_KW or *ahead == JUMP_IF_KW or *ahead == LABEL_KW)) { if(*ahead == GOTO_KW) { found_gotos[tokens.dictionary[*it]] = body.size(); + } else if(*ahead == JUMP_IF_KW) { + found_jump_ifs[tokens.dictionary[*it]] = body.size(); } else if(*ahead == LABEL_KW) { auto label_value = tokens.dictionary[*it]; if(found_labels.contains(label_value)) { @@ -251,6 +263,14 @@ namespace molasses { throw orphan_goto_error(body[index], dest); } + sub_bodies.emplace_back(std::min(index, found_labels[dest]), std::max(index, found_labels[dest])); + } + + for(auto& [dest, index] : found_jump_ifs) { + if(not found_labels.contains(dest)) { + throw orphan_goto_error(body[index], dest); + } + sub_bodies.emplace_back(std::min(index, found_labels[dest]), std::max(index, found_labels[dest])); } @@ -290,7 +310,14 @@ namespace molasses { for(auto it = _body.begin(); it != _body.end(); ++it) { auto elem = *it; auto token = lexer_data.dictionary.at(elem); - if(auto ahead = it; ++ahead != _body.end() and (lexer_data.dictionary.at(*ahead) == "__GOTO__" or lexer_data.dictionary.at(*ahead) == "__LABEL__")) { + if( + auto ahead = it; + ++ahead != _body.end() and ( + lexer_data.dictionary.at(*ahead) == "__GOTO__" + or lexer_data.dictionary.at(*ahead) == "__LABEL__" + or lexer_data.dictionary.at(*ahead) == "__JUMP_IF__" + ) + ) { if(lexer_data.dictionary.at(*ahead) == "__GOTO__") { for(auto&& instruction : generate_goto(name() + " in " + token)) { ops.push_back(instruction); @@ -299,6 +326,10 @@ namespace molasses { for(auto&& instruction : generate_label(name() + " in " + token)) { ops.push_back(instruction); } + } else if(lexer_data.dictionary.at(*ahead) == "__JUMP_IF__") { + for(auto&& instruction : generate_jump_if(name() + " in " + token)) { + ops.push_back(instruction); + } } it = ahead; } else if(elem.is_string) { diff --git a/tests/001.exp b/tests/001.exp index f996424..4f65223 100644 --- a/tests/001.exp +++ b/tests/001.exp @@ -1,7 +1,7 @@ #!/usr/bin/expect set SUGAR_EXECUTABLE $::env(SUGAR_EXECUTABLE) -set BUILD_NAME 001. +set BUILD_NAME 001 proc abort {reason} { puts "test failed $reason" diff --git a/tests/002.exp b/tests/002.exp index 1837c4a..f9edf1c 100644 --- a/tests/002.exp +++ b/tests/002.exp @@ -1,7 +1,7 @@ #!/usr/bin/expect set SUGAR_EXECUTABLE $::env(SUGAR_EXECUTABLE) -set BUILD_NAME 002. +set BUILD_NAME 002 proc abort {reason} { puts "test failed $reason" diff --git a/tests/003.exp b/tests/003.exp index eb06973..e57d4cb 100644 --- a/tests/003.exp +++ b/tests/003.exp @@ -1,7 +1,7 @@ #!/usr/bin/expect set SUGAR_EXECUTABLE $::env(SUGAR_EXECUTABLE) -set BUILD_NAME 003. +set BUILD_NAME 003 proc abort {reason} { puts "test failed $reason" diff --git a/tests/005.exp b/tests/005.exp index ef0520e..dc2d02c 100644 --- a/tests/005.exp +++ b/tests/005.exp @@ -1,7 +1,7 @@ #!/usr/bin/expect set SUGAR_EXECUTABLE $::env(SUGAR_EXECUTABLE) -set BUILD_NAME 005. +set BUILD_NAME 005 proc abort {reason} { puts "test failed $reason" diff --git a/tests/006.exp b/tests/006.exp index 5e77865..ae75750 100644 --- a/tests/006.exp +++ b/tests/006.exp @@ -1,7 +1,7 @@ #!/usr/bin/expect set SUGAR_EXECUTABLE $::env(SUGAR_EXECUTABLE) -set BUILD_NAME 006. +set BUILD_NAME 006 proc abort {reason} { puts "test failed $reason" diff --git a/tests/007.exp b/tests/007.exp index ee0bd2e..fb65a3f 100644 --- a/tests/007.exp +++ b/tests/007.exp @@ -1,7 +1,7 @@ #!/usr/bin/expect set SUGAR_EXECUTABLE $::env(SUGAR_EXECUTABLE) -set BUILD_NAME 007. +set BUILD_NAME 007 proc abort {reason} { puts "test failed $reason" diff --git a/tests/007/exit-with-3.mol b/tests/007/exit-with-3.mol index 1e3409f..29d1a35 100644 --- a/tests/007/exit-with-3.mol +++ b/tests/007/exit-with-3.mol @@ -2,6 +2,6 @@ __PROC__ main __--__ __DO__ -11_i64 "\tHello world\n" write-out +13_i64 "\tHello world\n" write-out 1 2_i32 + i32-to-i64 exit __END__ diff --git a/tests/008.exp b/tests/008.exp new file mode 100644 index 0000000..0f5ace1 --- /dev/null +++ b/tests/008.exp @@ -0,0 +1,82 @@ +#!/usr/bin/expect + +set SUGAR_EXECUTABLE $::env(SUGAR_EXECUTABLE) +set BUILD_NAME 008 + +proc abort {reason} { + puts "test failed $reason" + exit 1 +} + +spawn -noecho $SUGAR_EXECUTABLE tests/008/exit-with-3.mol tests/008/library.mol lex-all merge-all +expect { + error { abort "failed to parse" } + eof { abort "cannot find the symbol main in lexed output" } + main +} +expect eof +lassign [wait] pid spawnid os_error_flag value +if {$value != 0} { + abort "compiler crashed" +} + +# ------------------------------------------------------------------- + +spawn -noecho $SUGAR_EXECUTABLE tests/008/exit-with-3.mol tests/008/library.mol lex-all merge-all parse +expect { + error { abort "failed to parse" } + eof { abort "cannot find the main procedure" } + main +} +expect eof +lassign [wait] pid spawnid os_error_flag value +if {$value != 0} { + abort "compiler crashed" +} + +# ------------------------------------------------------------------- + +spawn -noecho $SUGAR_EXECUTABLE tests/008/exit-with-3.mol tests/008/library.mol lex-all merge-all parse +expect { + error { abort "failed to parse" } + eof { abort "cannot find the exit-syscall-number procedure" } + exit-syscall-number +} +expect eof +lassign [wait] pid spawnid os_error_flag value +if {$value != 0} { + abort "compiler crashed" +} + +# ------------------------------------------------------------------- + +spawn -noecho $SUGAR_EXECUTABLE tests/008/exit-with-3.mol lex tests/008/library.mol lex merge parse /tmp/sugar.generated.$BUILD_NAME generate assemble +expect { + error { abort "failed to compile" } + eof { abort "didn't run clang" } + clang +} +expect { + error { abort "failed to link" } + eof { abort "didn't run ld" } + ld +} +expect eof +lassign [wait] pid spawnid os_error_flag value +if {$value != 0} { + abort "compiler crashed" +} + +# ------------------------------------------------------------------- + +spawn -noecho /tmp/sugar.generated.$BUILD_NAME +expect { + error { abort "failed to compile" } + eof { abort "didn't output" } + Hello +} +expect eof +lassign [wait] pid spawnid os_error_flag value +if {$value != 3} { + abort "executable didn't return exit code 3 but $value instead" +} \ No newline at end of file diff --git a/tests/008/exit-with-3.mol b/tests/008/exit-with-3.mol new file mode 100644 index 0000000..acd410e --- /dev/null +++ b/tests/008/exit-with-3.mol @@ -0,0 +1,13 @@ +__PROC__ main +__--__ +__DO__ + +10_i64 +"SAUSAGE" __LABEL__ +13_i64 "\tHello world\n" write-out + +-1_i64 +_i64 +"SAUSAGE" __JUMP_IF__ drop_i64 + +1 2_i32 + i32-to-i64 exit +__END__ diff --git a/tests/008/library.mol b/tests/008/library.mol new file mode 100644 index 0000000..112f9d5 --- /dev/null +++ b/tests/008/library.mol @@ -0,0 +1,39 @@ +__PROC__ write-syscall-number +__--__ +i64 +__DO__ +1_i64 +__END__ + +__PROC__ stdout-fd +__--__ +i64 +__DO__ +1_i64 +__END__ + +__PROC__ exit-syscall-number +__--__ +i64 +__DO__ +60_i64 +__END__ + +__PROC__ exit +i64 +__--__ +__DO__ +"POTAT" __LABEL__ +exit-syscall-number syscall1 drop_i64 +60_i64 +"POTAT" __GOTO__ +drop_i64 +__END__ + +__PROC__ write-out +i64 +u8 ptr +__--__ +__DO__ +u8-ptr_to_i64 stdout-fd write-syscall-number syscall3 drop_i64 +__END__ \ No newline at end of file