:(before "End Globals")
map<long long int, call_stack> Continuation;
long long int Next_continuation_id = 0;
:(before "End Setup")
Continuation.clear();
Next_continuation_id = 0;
:(before "End Mu Types Initialization")
type_ordinal continuation = Type_ordinal["continuation"] = Next_type_ordinal++;
Type[continuation].name = "continuation";
:(before "End Primitive Recipe Declarations")
CURRENT_CONTINUATION,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["current-continuation"] = CURRENT_CONTINUATION;
:(before "End Primitive Recipe Implementations")
case CURRENT_CONTINUATION: {
Continuation[Next_continuation_id] = Current_routine->calls;
++Continuation[Next_continuation_id].front().running_step_index;
products.resize(1);
products.at(0).push_back(Next_continuation_id);
++Next_continuation_id;
trace("current-continuation") << "new continuation " << Next_continuation_id << end();
break;
}
:(before "End Primitive Recipe Declarations")
CONTINUE_FROM,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["continue-from"] = CONTINUE_FROM;
:(before "End Primitive Recipe Implementations")
case CONTINUE_FROM: {
if (!scalar(ingredients.at(0))) {
raise << current_recipe_name() << ": first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
break;
}
long long int c = ingredients.at(0).at(0);
Current_routine->calls = Continuation[c];
continue;
}
:(scenario continuation)
recipe main [
1:number <- copy 0:literal
2:continuation <- current-continuation
{
3:boolean <- greater-or-equal 1:number, 3:literal
break-if 3:boolean
1:number <- add 1:number, 1:literal
continue-from 2:continuation
}
]
+mem: storing 1 in location 1
+mem: storing 2 in location 1
+mem: storing 3 in location 1
-mem: storing 4 in location 1
$current-continuation: 1
:(scenario continuation_inside_caller)
recipe main [
1:number <- copy 0:literal
2:continuation <- loop-body
{
3:boolean <- greater-or-equal 1:number, 3:literal
break-if 3:boolean
continue-from 2:continuation
}
]
recipe loop-body [
4:continuation <- current-continuation
1:number <- add 1:number, 1:literal
]
+mem: storing 1 in location 1
+mem: storing 2 in location 1
+mem: storing 3 in location 1
-mem: storing 4 in location 1
:(scenario delimited_continuation)
recipe main [
1:continuation <- create-delimited-continuation f:recipe 12:literal
2:number <- copy 5:literal
{
2:number <- call 1:continuation, 2:number
3:boolean <- greater-or-equal 2:number, 8:literal
break-if 3:boolean
loop
}
]
recipe f [
11:number <- next-ingredient
12:number <- g 11:number
reply 12:number
]
recipe g [
21:number <- next-ingredient
rewind-ingredients
reply-delimited-continuation
22:number <- next-ingredient
23:number <- add 22:number, 1:literal
reply 23:number
]
+mem: storing 12 in location 21
+run: 2:number <- copy 5:literal
+mem: storing 5 in location 2
+run: 2:number <- call 1:continuation, 2:number
+mem: storing 5 in location 22
+mem: storing 6 in location 2
+run: 2:number <- call 1:continuation, 2:number
+mem: storing 6 in location 22
+mem: storing 7 in location 2
+run: 2:number <- call 1:continuation, 2:number
+mem: storing 7 in location 22
+mem: storing 8 in location 2
-mem: storing 12 in location 22
-mem: storing 5 in location 21
-mem: storing 6 in location 21
-mem: storing 7 in location 21
-mem: storing 9 in location 2
:(before "End call Fields")
bool is_reset;
:(before "End call Constructor")
is_reset = false;
:(before "End Primitive Recipe Declarations")
CREATE_DELIMITED_CONTINUATION,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["create-delimited-continuation"] = CREATE_DELIMITED_CONTINUATION;
:(before "End Primitive Recipe Implementations")
case CREATE_DELIMITED_CONTINUATION: {
Current_routine->calls.front().is_reset = true;
Current_routine->calls.push_front(call(Recipe_ordinal[current_instruction().ingredients.at(0).name]));
ingredients.erase(ingredients.begin());
goto call_housekeeping;
}
:(before "End Globals")
map<long long int, call_stack> Delimited_continuation;
long long int Next_delimited_continuation_id = 0;
:(before "End Setup")
Delimited_continuation.clear();
Next_delimited_continuation_id = 0;
:(before "End Primitive Recipe Declarations")
REPLY_DELIMITED_CONTINUATION,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["reply-delimited-continuation"] = REPLY_DELIMITED_CONTINUATION;
:(before "End Primitive Recipe Implementations")
case REPLY_DELIMITED_CONTINUATION: {
Current_routine->calls.front().ingredient_atoms.clear();
Current_routine->calls.front().next_ingredient_to_process = 0;
call_stack::iterator find_reset(call_stack& c);
call_stack::iterator reset = find_reset(Current_routine->calls);
if (reset == Current_routine->calls.end()) {
raise << current_recipe_name() << ": couldn't find a 'reset' call to jump out to\n" << end();
break;
}
Delimited_continuation[Next_delimited_continuation_id] = call_stack(Current_routine->calls.begin(), reset);
while (Current_routine->calls.begin() != reset) {
--Callstack_depth;
Current_routine->calls.pop_front();
}
products.resize(1);
products.at(0).push_back(Next_delimited_continuation_id);
++Next_delimited_continuation_id;
break;
}
:(code)
call_stack::iterator find_reset(call_stack& c) {
for (call_stack::iterator p = c.begin(); p != c.end(); ++p)
if (p->is_reset) return p;
return c.end();
}
:(after "Begin Call")
if (!current_instruction().ingredients.at(0).properties.empty()
&& !current_instruction().ingredients.at(0).properties.at(0).second.empty()
&& current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "continuation") {
assert(scalar(ingredients.at(0)));
if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) {
raise << current_recipe_name() << ": no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end();
}
const call_stack& new_calls = Delimited_continuation[ingredients.at(0).at(0)];
for (call_stack::const_reverse_iterator p = new_calls.rbegin(); p != new_calls.rend(); ++p)
Current_routine->calls.push_front(*p);
++current_step_index();
ingredients.erase(ingredients.begin());
goto call_housekeeping;
}