diff options
-rw-r--r-- | 020run.cc | 3 | ||||
-rw-r--r-- | 023jump.cc | 1 | ||||
-rw-r--r-- | 026assert.cc | 3 | ||||
-rw-r--r-- | 037call_reply.cc | 42 | ||||
-rw-r--r-- | 047jump_label.cc | 26 | ||||
-rw-r--r-- | 050scenario.cc | 13 | ||||
-rw-r--r-- | chessboard.mu | 142 | ||||
-rw-r--r-- | mu.vim | 2 | ||||
-rw-r--r-- | termbox/termbox.c | 12 |
9 files changed, 187 insertions, 57 deletions
diff --git a/020run.cc b/020run.cc index f92e2775..4a36b379 100644 --- a/020run.cc +++ b/020run.cc @@ -130,7 +130,8 @@ if (argc > 1) { :(before "End Main") if (!Run_tests) { setup(); - Trace_stream = new trace_stream; +//? Trace_file = "interactive"; //? 1 + START_TRACING_UNTIL_END_OF_SCOPE; //? Trace_stream->dump_layer = "all"; //? 2 transform_all(); recipe_number r = Recipe_number[string("main")]; diff --git a/023jump.cc b/023jump.cc index 807113f3..8349f44e 100644 --- a/023jump.cc +++ b/023jump.cc @@ -42,6 +42,7 @@ Recipe_number["jump-if"] = JUMP_IF; :(before "End Primitive Recipe Implementations") case JUMP_IF: { assert(current_instruction().ingredients.at(1).initialized); + trace("AAA") << current_instruction().to_string() << '\n'; assert(ingredients.size() == 2); assert(ingredients.at(0).size() == 1); // scalar if (!ingredients.at(0).at(0)) { diff --git a/026assert.cc b/026assert.cc index 7217d5c2..50456001 100644 --- a/026assert.cc +++ b/026assert.cc @@ -15,9 +15,8 @@ case ASSERT: { assert(ingredients.at(0).size() == 1); // scalar if (!ingredients.at(0).at(0)) { assert(isa_literal(current_instruction().ingredients.at(1))); -//? tb_shutdown(); //? 1 + tb_shutdown(); raise << current_instruction().ingredients.at(1).name << '\n' << die(); -//? exit(0); //? 1 } break; } diff --git a/037call_reply.cc b/037call_reply.cc index 81f9c7c2..e44fe205 100644 --- a/037call_reply.cc +++ b/037call_reply.cc @@ -62,6 +62,7 @@ recipe f [ //: ingredients unless they're also products. The /same-as-ingredient inside //: the recipe's 'reply' will help catch accidental misuse of such //: 'ingredient-results' (sometimes called in-out parameters in other languages). + :(scenario reply_same_as_ingredient) % Hide_warnings = true; recipe main [ @@ -90,3 +91,44 @@ string to_string(const vector<long long int>& in) { out << "]"; return out.str(); } + +//: Conditional reply. + +:(scenario reply_if) +recipe main [ + 1:integer <- test1 +] +recipe test1 [ + reply-if 0:literal, 34:literal + reply 35:literal +] ++mem: storing 35 in location 1 + +:(scenario reply_if2) +recipe main [ + 1:integer <- test1 +] +recipe test1 [ + reply-if 1:literal, 34:literal + reply 35:literal +] ++mem: storing 34 in location 1 + +:(before "End Rewrite Instruction(curr)") +// rewrite `reply-if a, b, c, ...` to +// ``` +// jump-unless a, 1:offset +// reply b, c, ... +// ``` +if (curr.name == "reply-if") { + assert(curr.products.empty()); + curr.operation = Recipe_number["jump-unless"]; + vector<reagent> results; + copy(++curr.ingredients.begin(), curr.ingredients.end(), inserter(results, results.end())); + curr.ingredients.resize(1); + curr.ingredients.push_back(reagent("1:offset")); + result.steps.push_back(curr); + curr.clear(); + curr.operation = Recipe_number["reply"]; + curr.ingredients.swap(results); +} diff --git a/047jump_label.cc b/047jump_label.cc index 9bc0c442..c9dcb4f5 100644 --- a/047jump_label.cc +++ b/047jump_label.cc @@ -24,25 +24,25 @@ void transform_labels(const recipe_number r) { instruction& inst = Recipe[r].steps.at(i); if (inst.operation == Recipe_number["jump"]) { //? cerr << inst.to_string() << '\n'; //? 1 - replace_offset(inst.ingredients.at(0), offset, r); + replace_offset(inst.ingredients.at(0), offset, i, r); } if (inst.operation == Recipe_number["jump-if"] || inst.operation == Recipe_number["jump-unless"]) { - replace_offset(inst.ingredients.at(1), offset, r); + replace_offset(inst.ingredients.at(1), offset, i, r); } if ((inst.operation == Recipe_number["loop"] || inst.operation == Recipe_number["break"]) && inst.ingredients.size() == 1) { - replace_offset(inst.ingredients.at(0), offset, r); + replace_offset(inst.ingredients.at(0), offset, i, r); } if ((inst.operation == Recipe_number["loop-if"] || inst.operation == Recipe_number["loop-unless"] || inst.operation == Recipe_number["break-if"] || inst.operation == Recipe_number["break-unless"]) && inst.ingredients.size() == 2) { - replace_offset(inst.ingredients.at(1), offset, r); + replace_offset(inst.ingredients.at(1), offset, i, r); } } } :(code) -void replace_offset(reagent& x, /*const*/ map<string, index_t>& offset, const recipe_number r) { +void replace_offset(reagent& x, /*const*/ map<string, index_t>& offset, const index_t current_offset, const recipe_number r) { //? cerr << "AAA " << x.to_string() << '\n'; //? 1 assert(isa_literal(x)); //? cerr << "BBB " << x.to_string() << '\n'; //? 1 @@ -52,7 +52,7 @@ void replace_offset(reagent& x, /*const*/ map<string, index_t>& offset, const re //? cerr << "DDD " << x.to_string() << '\n'; //? 1 if (offset.find(x.name) == offset.end()) raise << "can't find label " << x.name << " in routine " << Recipe[r].name << '\n'; - x.set_value(offset[x.name]); + x.set_value(offset[x.name]-current_offset); } :(scenario break_to_label) @@ -91,3 +91,17 @@ recipe main [ +target ] -mem: storing 0 in location 1 + +:(scenario jump_runs_code_after_label) +recipe main [ + # first a few lines of padding to exercise the offset computation + 1:integer <- copy 0:literal + 2:integer <- copy 0:literal + 3:integer <- copy 0:literal + jump +target:offset + 4:integer <- copy 0:literal + +target + 5:integer <- copy 0:literal +] ++mem: storing 0 in location 5 +-mem: storing 0 in location 4 diff --git a/050scenario.cc b/050scenario.cc index d950b7ae..af97b34a 100644 --- a/050scenario.cc +++ b/050scenario.cc @@ -88,7 +88,7 @@ time_t mu_time; time(&mu_time); cerr << "\nMu tests: " << ctime(&mu_time); for (index_t i = 0; i < Scenarios.size(); ++i) { //? cerr << Passed << '\n'; //? 1 -//? cerr << i << ": " << Scenarios.at(i).name << '\n'; //? 1 +//? cerr << i << ": " << Scenarios.at(i).name << '\n'; //? 2 run_mu_scenario(Scenarios.at(i)); if (Passed) cerr << "."; } @@ -294,6 +294,10 @@ recipe main [ // Like runs of contiguous '+' lines, order is important. The trace checks // that the lines are present *and* in the specified sequence. (There can be // other lines in between.) +// +// Be careful not to mix setting Hide_warnings and checking the trace in .mu +// files. It'll work in C++ scenarios, but the test failure gets silently +// hidden in mu scenarios. :(scenario trace_check_warns_on_failure) % Hide_warnings = true; @@ -319,8 +323,10 @@ case TRACE_SHOULD_CONTAIN: { // simplified version of check_trace_contents() that emits warnings rather // than just printing to stderr bool check_trace(const string& expected) { +//? cerr << "AAA " << expected << '\n'; //? 1 Trace_stream->newline(); vector<pair<string, string> > expected_lines = parse_trace(expected); +//? cerr << "BBB " << expected_lines.size() << '\n'; //? 1 if (expected_lines.empty()) return true; index_t curr_expected_line = 0; for (vector<pair<string, pair<int, string> > >::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { @@ -328,7 +334,10 @@ bool check_trace(const string& expected) { if (expected_lines.at(curr_expected_line).second != p->second.second) continue; // match ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; + if (curr_expected_line == expected_lines.size()) { +//? cerr << "ZZZ\n"; //? 1 + return true; + } } raise << "missing [" << expected_lines.at(curr_expected_line).second << "] " diff --git a/chessboard.mu b/chessboard.mu index 5cd2deb1..a5ba2627 100644 --- a/chessboard.mu +++ b/chessboard.mu @@ -152,100 +152,148 @@ container move [ to-rank:integer ] -# result:address:move <- read-move stdin:address:channel +# result:address:move, quit?:boolean, error?:boolean <- read-move stdin:address:channel, screen:address +# prints only error messages to screen recipe read-move [ default-space:address:array:location <- new location:type, 30:literal stdin:address:channel <- next-ingredient - from-file:integer <- read-file stdin:address:channel + screen:address <- next-ingredient +#? $print screen:address #? 1 + from-file:integer, quit?:boolean, error?:boolean <- read-file stdin:address:channel, screen:address + reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean + reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean #? return-to-console #? 1 - { - q-pressed?:boolean <- lesser-than from-file:integer, 0:literal - break-unless q-pressed?:boolean - reply 0:literal - } # construct the move object result:address:move <- new move:literal x:address:integer <- get-address result:address:move/deref, from-file:offset x:address:integer/deref <- copy from-file:integer x:address:integer <- get-address result:address:move/deref, from-rank:offset - x:address:integer/deref <- read-rank stdin:address:channel - expect-from-channel stdin:address:channel, 45:literal # '-' + x:address:integer/deref, quit?:boolean, error?:boolean <- read-rank stdin:address:channel, screen:address + reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean + reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean + error?:boolean <- expect-from-channel stdin:address:channel, 45:literal/dash, screen:address + reply-if error?:boolean, 0:literal/dummy, 0:literal/quit, error?:boolean x:address:integer <- get-address result:address:move/deref, to-file:offset - x:address:integer/deref <- read-file stdin:address:channel + x:address:integer/deref, quit?:boolean, error?:boolean <- read-file stdin:address:channel, screen:address + reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean + reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean x:address:integer <- get-address result:address:move/deref, to-rank:offset - x:address:integer/deref <- read-rank stdin:address:channel + x:address:integer/deref, quit?:boolean, error?:boolean <- read-rank stdin:address:channel, screen:address + reply-if quit?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean + reply-if error?:boolean, 0:literal/dummy, quit?:boolean, error?:boolean #? $exit #? 1 - expect-from-channel stdin:address:channel, 13:literal # newline - reply result:address:move + error?:boolean <- expect-from-channel stdin:address:channel, 13:literal/newline, screen:address + reply-if error?:boolean, 0:literal/dummy, 0:literal/quit, error?:boolean + reply result:address:move, quit?:boolean, error?:boolean ] +# file:integer, quit:boolean, error:boolean <- read-file stdin:address:channel, screen:address +# valid values for file: 0-7 recipe read-file [ default-space:address:array:location <- new location:type, 30:literal stdin:address:channel <- next-ingredient + screen:address <- next-ingredient c:character, stdin:address:channel <- read stdin:address:channel { q-pressed?:boolean <- equal c:character, 81:literal # 'Q' break-unless q-pressed?:boolean - reply -1:literal + reply 0:literal/dummy, 1:literal/quit, 0:literal/error } { q-pressed?:boolean <- equal c:character, 113:literal # 'q' break-unless q-pressed?:boolean - reply -1:literal + reply 0:literal/dummy, 1:literal/quit, 0:literal/error } file:integer <- subtract c:character, 97:literal # 'a' #? $print file:integer, [ #? 1 #? ] #? 1 # 'a' <= file <= 'h' - above-min:boolean <- greater-or-equal file:integer, 0:literal - assert above-min:boolean [file too low] - below-max:boolean <- lesser-than file:integer, 8:literal - assert below-max:boolean [file too high] - reply file:integer + { + above-min:boolean <- greater-or-equal file:integer, 0:literal + break-if above-min:boolean + error-message:address:array:character <- new [file too low: ] + print-string screen:address, error-message:address:array:character + print-character screen:address, c:character + cursor-to-next-line screen:address + reply 0:literal/dummy, 0:literal/quit, 1:literal/error + } + { + below-max:boolean <- lesser-than file:integer, 8:literal + break-if below-max:boolean + error-message:address:array:character <- new [file too high: ] + print-string screen:address, error-message:address:array:character + print-character screen:address, c:character + reply 0:literal/dummy, 0:literal/quit, 1:literal/error + } + reply file:integer, 0:literal/quit, 0:literal/error ] +# rank:integer <- read-rank stdin:address:channel, screen:address +# valid values: 0-7, -1 (quit), -2 (error) recipe read-rank [ default-space:address:array:location <- new location:type, 30:literal stdin:address:channel <- next-ingredient + screen:address <- next-ingredient c:character, stdin:address:channel <- read stdin:address:channel { q-pressed?:boolean <- equal c:character, 81:literal # 'Q' break-unless q-pressed?:boolean - reply -1:literal + reply 0:literal/dummy, 1:literal/quit, 0:literal/error } { q-pressed?:boolean <- equal c:character, 113:literal # 'q' break-unless q-pressed?:boolean - reply -1:literal + reply 0:literal/dummy, 1:literal/quit, 0:literal/error } rank:integer <- subtract c:character, 49:literal # '1' #? $print rank:integer, [ #? 1 #? ] #? 1 # assert'1' <= rank <= '8' - above-min:boolean <- greater-or-equal rank:integer 0:literal - assert above-min:boolean [rank too low] - below-max:boolean <- lesser-or-equal rank:integer 7:literal - assert below-max:boolean [rank too high] - reply rank:integer + { + above-min:boolean <- greater-or-equal rank:integer 0:literal + break-if above-min:boolean + error-message:address:array:character <- new [rank too low: ] + print-string screen:address, error-message:address:array:character + print-character screen:address, c:character + reply 0:literal/dummy, 0:literal/quit, 1:literal/error + } + { + below-max:boolean <- lesser-or-equal rank:integer 7:literal + break-if below-max:boolean + error-message:address:array:character <- new [rank too high: ] + print-string screen:address, error-message:address:array:character + print-character screen:address, c:character + reply 0:literal/dummy, 0:literal/quit, 1:literal/error + } + reply rank:integer, 0:literal/quit, 0:literal/error ] # read a character from the given channel and check that it's what we expect +# return true on error recipe expect-from-channel [ default-space:address:array:location <- new location:type, 30:literal stdin:address:channel <- next-ingredient expected:character <- next-ingredient + screen:address <- next-ingredient c:character, stdin:address:channel <- read stdin:address:channel match?:boolean <- equal c:character, expected:character - assert match?:boolean [expected character not found] + { + break-if match?:boolean + s:address:array:character <- new [expected character not found] + print-string screen:address, s:address:array:character + } + result:boolean <- not match?:boolean + reply result:boolean ] scenario read-move-blocking [ + assume-screen 20:literal/width, 2:literal/height run [ #? $start-tracing #? 1 1:address:channel <- init-channel 2:literal #? $print [aaa channel address: ], 1:address:channel, [ #? 1 #? ] #? 1 - 2:integer/routine <- start-running read-move:recipe, 1:address:channel + 2:integer/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input wait-for-routine 2:integer #? $print [bbb channel address: ], 1:address:channel, [ #? 1 @@ -333,9 +381,10 @@ F read-move-blocking: routine failed to terminate on newline] ] scenario read-move-quit [ + assume-screen 20:literal/width, 2:literal/height run [ 1:address:channel <- init-channel 2:literal - 2:integer/routine <- start-running read-move:recipe, 1:address:channel + 2:integer/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input wait-for-routine 2:integer 3:integer <- routine-state 2:integer/id @@ -359,10 +408,10 @@ F read-move-quit: routine failed to terminate on 'q'] ] scenario read-move-illegal-file [ + assume-screen 20:literal/width, 2:literal/height run [ - hide-warnings 1:address:channel <- init-channel 2:literal - 2:integer/routine <- start-running read-move:recipe, 1:address:channel + 2:integer/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input wait-for-routine 2:integer 3:integer <- routine-state 2:integer/id @@ -373,16 +422,17 @@ F read-move-file: routine failed to pause after coming up (before any keys were restart 2:integer/routine wait-for-routine 2:integer ] - trace-should-contain [ - warn: file too low + screen-should-contain [ + .file too low: 2 . + . . ] ] scenario read-move-illegal-rank [ + assume-screen 20:literal/width, 2:literal/height run [ - hide-warnings 1:address:channel <- init-channel 2:literal - 2:integer/routine <- start-running read-move:recipe, 1:address:channel + 2:integer/routine <- start-running read-move:recipe, 1:address:channel, screen:address # 'read-move' is waiting for input wait-for-routine 2:integer 3:integer <- routine-state 2:integer/id @@ -394,8 +444,9 @@ F read-move-file: routine failed to pause after coming up (before any keys were restart 2:integer/routine wait-for-routine 2:integer ] - trace-should-contain [ - warn: rank too high + screen-should-contain [ + .rank too high: a . + . . ] ] @@ -496,15 +547,20 @@ recipe chessboard [ msg:address:array:character <- new [Hit 'q' to exit. ] print-string 0:literal/screen, msg:address:array:character - cursor-to-next-line 0:literal/screen - msg:address:array:character <- new [move: ] - print-string 0:literal/screen, msg:address:array:character - m:address:move <- read-move buffered-stdin:address:channel - break-unless m:address:move + { + cursor-to-next-line 0:literal/screen + msg:address:array:character <- new [move: ] + print-string 0:literal/screen, msg:address:array:character + m:address:move, quit:boolean, error:boolean <- read-move buffered-stdin:address:channel, 0:literal/screen + break-if quit:boolean, +quit:offset + loop-if error:boolean + } board:address:array:address:array:character <- make-move board:address:array:address:array:character, m:address:move clear-screen 0:literal/screen loop } + +quit +#? $print [aaa] #? 1 return-to-console ] diff --git a/mu.vim b/mu.vim index 5c120676..a973fc1a 100644 --- a/mu.vim +++ b/mu.vim @@ -35,7 +35,7 @@ syntax match muDelimiter "[{}\[\]]" | highlight link muDelimiter Delimiter syntax match muLabel " [^a-zA-Z0-9 \[][a-zA-Z0-9-]\+" | highlight link muLabel Function syntax match muAssign " <- " | highlight link muAssign SpecialChar syntax match muAssign "\<raw\>" -syntax keyword muControl reply jump jump-if jump-unless loop loop-if loop-unless break-if break-unless | highlight link muControl Function +syntax keyword muControl reply reply-if reply-unless jump jump-if jump-unless loop loop-if loop-unless break-if break-unless | highlight link muControl Function " common keywords syntax keyword muFunc recipe default-space next-ingredient ingredient before after scenario run memory trace screen keyboard stalled finished | highlight link muFunc Statement diff --git a/termbox/termbox.c b/termbox/termbox.c index 2fbbf5b4..80aeb3a9 100644 --- a/termbox/termbox.c +++ b/termbox/termbox.c @@ -158,6 +158,8 @@ void tb_present(void) int x,y,w,i; struct tb_cell *back, *front; + assert(termw != -1); + /* invalidate cursor position */ lastx = LAST_COORD_INIT; lasty = LAST_COORD_INIT; @@ -203,12 +205,11 @@ void tb_present(void) void tb_set_cursor(int cx, int cy) { + assert(termw != -1); if (IS_CURSOR_HIDDEN(cursor_x, cursor_y) && !IS_CURSOR_HIDDEN(cx, cy)) bytebuffer_puts(&output_buffer, funcs[T_SHOW_CURSOR]); - if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y) && IS_CURSOR_HIDDEN(cx, cy)) bytebuffer_puts(&output_buffer, funcs[T_HIDE_CURSOR]); - cursor_x = cx; cursor_y = cy; if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y)) @@ -217,6 +218,7 @@ void tb_set_cursor(int cx, int cy) void tb_change_cell(int x, int y, uint32_t ch, uint16_t fg, uint16_t bg) { + assert(termw != -1); if ((unsigned)x >= (unsigned)back_buffer.width) return; if ((unsigned)y >= (unsigned)back_buffer.height) @@ -232,6 +234,7 @@ struct tb_cell *tb_cell_buffer() int tb_poll_event(struct tb_event *event) { + assert(termw != -1); return wait_fill_event(event, 0); } @@ -240,21 +243,25 @@ int tb_peek_event(struct tb_event *event, int timeout) struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; + assert(termw != -1); return wait_fill_event(event, &tv); } int tb_width(void) { + assert(termw != -1); return termw; } int tb_height(void) { + assert(termw != -1); return termh; } void tb_clear(void) { + assert(termw != -1); if (buffer_size_change_request) { update_size(); buffer_size_change_request = 0; @@ -264,6 +271,7 @@ void tb_clear(void) void tb_set_clear_attributes(uint16_t fg, uint16_t bg) { + assert(termw != -1); foreground = fg; background = bg; } |