about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2017-11-06 01:12:42 -0800
committerKartik K. Agaram <vc@akkartik.com>2017-11-06 01:12:42 -0800
commit3b776ac3843e925ee24f49e8df51ab6a1db6c085 (patch)
tree91bd75152023b6144d3af8c8e8e37a57cfb6867f
parentc34a067564e2005a590bfd8730c90fed51cbb2c2 (diff)
downloadmu-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.cc2
-rw-r--r--076continuation.cc11
-rw-r--r--continuation5.mu39
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]
+]