diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-11-29 01:00:30 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-11-29 01:00:30 -0800 |
commit | afb467ea0270c59f9fdcad9fe5303d0ed526177c (patch) | |
tree | a8254143010d612908b9b4cc534bf4ab1da199a7 | |
parent | c9b98c21ffea7a2e48e10e01b80dabad42641e57 (diff) | |
download | mu-afb467ea0270c59f9fdcad9fe5303d0ed526177c.tar.gz |
2606 - handle cycles inside stash
The idea is that to-text-line should truncate blindly past some threshold, even if to-text isn't smart enough to avoid infinite loops. Maybe I should define a 'truncating buffer' which stops once it fills up. That would be an easy way to eliminate all infinite loops in to-text-line.
-rw-r--r-- | 050scenario.cc | 9 | ||||
-rw-r--r-- | 053rewrite_stash.cc | 2 | ||||
-rw-r--r-- | 070text.mu | 10 | ||||
-rw-r--r-- | 073list.mu | 40 |
4 files changed, 52 insertions, 9 deletions
diff --git a/050scenario.cc b/050scenario.cc index 21afe341..10c65e21 100644 --- a/050scenario.cc +++ b/050scenario.cc @@ -438,25 +438,22 @@ case TRACE_SHOULD_CONTAIN: { :(code) // simplified version of check_trace_contents() that emits errors rather // than just printing to stderr -bool check_trace(const string& expected) { +void check_trace(const string& expected) { Trace_stream->newline(); vector<trace_line> expected_lines = parse_trace(expected); - if (expected_lines.empty()) return true; + if (expected_lines.empty()) return; long long int curr_expected_line = 0; for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { if (expected_lines.at(curr_expected_line).label != p->label) continue; if (expected_lines.at(curr_expected_line).contents != trim(p->contents)) continue; // match ++curr_expected_line; - if (curr_expected_line == SIZE(expected_lines)) { - return true; - } + if (curr_expected_line == SIZE(expected_lines)) return; } raise_error << "missing [" << expected_lines.at(curr_expected_line).contents << "] " << "in trace with label " << expected_lines.at(curr_expected_line).label << '\n' << end(); Passed = false; - return false; } vector<trace_line> parse_trace(const string& expected) { diff --git a/053rewrite_stash.cc b/053rewrite_stash.cc index df64baaf..b6602041 100644 --- a/053rewrite_stash.cc +++ b/053rewrite_stash.cc @@ -35,7 +35,7 @@ void rewrite_stashes_to_text_named(recipe& caller) { if (is_literal(inst.ingredients.at(j))) continue; if (is_mu_string(inst.ingredients.at(j))) continue; instruction def; - def.name = "to-text"; + def.name = "to-text-line"; def.ingredients.push_back(inst.ingredients.at(j)); ostringstream ingredient_name; ingredient_name << "stash_" << stash_instruction_idx << '_' << j << ":address:array:character"; diff --git a/070text.mu b/070text.mu index eb3875d0..5de21e41 100644 --- a/070text.mu +++ b/070text.mu @@ -1,6 +1,14 @@ # Some useful helpers for dealing with text (arrays of characters) -# to-text gets called implicitly in various places +# to-text-line gets called implicitly in various places +# define it to be identical to 'to-text' by default +recipe to-text-line x:_elem -> y:address:array:character [ + local-scope + load-ingredients + y <- to-text x +] + +# to-text on text is just the identity function recipe to-text x:address:array:character -> y:address:array:character [ local-scope load-ingredients diff --git a/073list.mu b/073list.mu index 7b7d9e18..7e068b60 100644 --- a/073list.mu +++ b/073list.mu @@ -61,6 +61,16 @@ recipe to-text in:address:list:_elem -> result:address:array:character [ result <- buffer-to-array buf ] +# variant of 'to-text' which stops printing after a few elements (and so is robust to cycles) +recipe to-text-line in:address:list:_elem -> result:address:array:character [ + local-scope +#? $print [to text line: list], 10/newline + load-ingredients + buf:address:buffer <- new-buffer 80 + buf <- to-buffer in, buf, 6 # max elements to display + result <- buffer-to-array buf +] + recipe to-buffer in:address:list:_elem, buf:address:buffer -> buf:address:buffer [ local-scope #? $print [to buffer: list], 10/newline @@ -85,7 +95,23 @@ recipe to-buffer in:address:list:_elem, buf:address:buffer -> buf:address:buffer n:number <- length *s buf <- append buf, s # and recurse - buf <- to-buffer next, buf + remaining:number, optional-ingredient-found?:boolean <- next-ingredient + { + break-if optional-ingredient-found? + # unlimited recursion + buf <- to-buffer next, buf + reply + } + { + break-unless remaining + # limited recursion + remaining <- subtract remaining, 1 + buf <- to-buffer next, buf, remaining + reply + } + # past recursion depth; insert ellipses and stop + s:address:array:character <- new [...] + append buf, s ] scenario stash-on-list-converts-to-text [ @@ -99,3 +125,15 @@ scenario stash-on-list-converts-to-text [ app: foo foo 6 -> 5 -> 4 ] ] + +scenario stash-handles-list-with-cycle [ + run [ + x:address:list:number <- push 4, 0 + y:address:address:list:number <- get-address *x, next:offset + *y <- copy x + stash [foo foo], x + ] + trace-should-contain [ + app: foo foo 4 -> 4 -> 4 -> 4 -> 4 -> 4 -> 4 -> ... + ] +] |