diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2017-11-06 01:12:42 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2017-11-06 01:12:42 -0800 |
commit | 3b776ac3843e925ee24f49e8df51ab6a1db6c085 (patch) | |
tree | 91bd75152023b6144d3af8c8e8e37a57cfb6867f | |
parent | c34a067564e2005a590bfd8730c90fed51cbb2c2 (diff) | |
download | mu-3b776ac3843e925ee24f49e8df51ab6a1db6c085.tar.gz |
4116 - support calling continuations with arguments
Surprisingly small change, considering how long it took me and how mind-bending it was. 'return-continuation-until-mark' now behaves like both call and return instructions, which made it hard to reason about.
-rw-r--r-- | 020run.cc | 2 | ||||
-rw-r--r-- | 076continuation.cc | 11 | ||||
-rw-r--r-- | continuation5.mu | 39 |
3 files changed, 45 insertions, 7 deletions
diff --git a/020run.cc b/020run.cc index 0da9fba7..b94d274a 100644 --- a/020run.cc +++ b/020run.cc @@ -64,6 +64,7 @@ void run_current_routine() { // Running One Instruction if (current_instruction().is_label) { ++current_step_index(); continue; } trace(Initial_callstack_depth + Trace_stream->callstack_depth, "run") << to_string(current_instruction()) << end(); +//? if (Foo) cerr << "run: " << to_string(current_instruction()) << '\n'; if (get_or_insert(Memory, 0) != 0) { raise << "something wrote to location 0; this should never happen\n" << end(); put(Memory, 0, 0); @@ -323,6 +324,7 @@ void write_memory(reagent/*copy*/ x, const vector<double>& data) { for (int offset = 0; offset < SIZE(data); ++offset) { assert(x.value+offset > 0); trace("mem") << "storing " << no_scientific(data.at(offset)) << " in location " << x.value+offset << end(); +//? if (Foo) cerr << "mem: storing " << no_scientific(data.at(offset)) << " in location " << x.value+offset << '\n'; put(Memory, x.value+offset, data.at(offset)); } } diff --git a/076continuation.cc b/076continuation.cc index e3be246d..5311fd67 100644 --- a/076continuation.cc +++ b/076continuation.cc @@ -60,7 +60,7 @@ recipe main [ 1:continuation <- call-with-continuation-mark f, 77 # 77 is an argument to f 2:number <- copy 5 { - 2:number <- call 1:continuation, 2:number # 2 is an argument to g, the 'top' of the continuation + 2:number <- call 1:continuation, 2:number # jump to 'return-continuation-until-mark' below 3:boolean <- greater-or-equal 2:number, 8 break-if 3:boolean loop @@ -73,10 +73,7 @@ recipe f [ ] recipe g [ 21:number <- next-ingredient - rewind-ingredients - return-continuation-until-mark - # calls of the continuation start from here - 22:number <- next-ingredient + 22:number <- return-continuation-until-mark 23:number <- add 22:number, 1 return 23:number ] @@ -218,10 +215,10 @@ if (current_instruction().ingredients.at(0).type->atom trace("trace") << "calling delimited continuation; growing callstack depth to " << Trace_stream->callstack_depth << end(); assert(Trace_stream->callstack_depth < 9000); // 9998-101 plus cushion } - ++current_step_index(); // skip past the return-continuation-until-mark ingredients.erase(ingredients.begin()); // drop the callee finish_call_housekeeping(to_instruction(caller), ingredients); - continue; + copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin())); + break; // record results of resuming 'return-continuation-until-mark' instruction } //: Ensure that the presence of a continuation keeps its stack frames from being reclaimed. diff --git a/continuation5.mu b/continuation5.mu new file mode 100644 index 00000000..fb00a4f5 --- /dev/null +++ b/continuation5.mu @@ -0,0 +1,39 @@ +# Example program showing that a 'paused' continuation can be 'resumed' with +# ingredients. +# +# Print out a list of numbers, first adding 0 to the first, 1 to the second, 2 +# to the third, and so on. + +def main [ + local-scope + l:&:list:num <- copy 0 + l <- push 3, l + l <- push 2, l + l <- push 1, l + k:continuation, x:num, done?:bool <- call-with-continuation-mark create-yielder, l + a:num <- copy 1 + { + break-if done? + $print x 10/newline + k, x:num, done?:bool <- call k, a # resume; x = a + next l value + a <- add a, 1 + loop + } +] + +def create-yielder l:&:list:num -> n:num, done?:bool [ + local-scope + load-ingredients + a:num <- copy 0 + { + done? <- equal l, 0 + break-if done? + n <- first l + l <- rest l + n <- add n, a + a <- return-continuation-until-mark n, done? # pause/resume + loop + } + return-continuation-until-mark -1, done? + assert 0/false, [called too many times, ran out of continuations to return] +] |