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.
This commit is contained in:
Kartik K. Agaram 2015-11-29 01:00:30 -08:00
parent c9b98c21ff
commit afb467ea02
4 changed files with 52 additions and 9 deletions

View File

@ -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) {

View File

@ -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";

View File

@ -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

View File

@ -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 -> ...
]
]