about summary refs log tree commit diff stats
path: root/cpp/021call
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-03-17 08:42:38 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-03-17 09:06:48 -0700
commitb1bbe92da37dd44df458ffa122e052612bb9eff3 (patch)
tree976cde85c97d4877eb8c1e5151a919406fdd1049 /cpp/021call
parentc062697c9ff3c8cb0938f56bed3df2af3d122bd6 (diff)
downloadmu-b1bbe92da37dd44df458ffa122e052612bb9eff3.tar.gz
945 - move 'transform' layer to before 'run'
Diffstat (limited to 'cpp/021call')
-rw-r--r--cpp/021call70
1 files changed, 70 insertions, 0 deletions
diff --git a/cpp/021call b/cpp/021call
new file mode 100644
index 00000000..2e0000c0
--- /dev/null
+++ b/cpp/021call
@@ -0,0 +1,70 @@
+//: So far the recipes we define can't run each other. Let's change that.
+:(scenario "calling_recipe")
+recipe main [
+  f
+]
+recipe f [
+  3:integer <- add 2:literal, 2:literal
+]
++mem: storing in location 3
+
+:(before "struct routine {")
+// Everytime a recipe runs another, we interrupt it and start running the new
+// recipe. When that finishes, we continue this one where we left off.
+// This requires maintaining a 'stack' of interrupted recipes or 'calls'.
+struct call {
+  recipe_number running_recipe;
+  size_t pc;
+  // End Call Fields
+  call(recipe_number r) :running_recipe(r), pc(0) {}
+};
+typedef stack<call> call_stack;
+
+:(replace{} "struct routine")
+struct routine {
+  call_stack calls;
+  routine(recipe_number r) {
+    calls.push(call(r));
+  }
+};
+//: now update routine's helpers
+:(replace{} "inline size_t& running_at(routine& rr)")
+inline size_t& running_at(routine& rr) {
+  return rr.calls.top().pc;
+}
+:(replace{} "inline string recipe_name(routine& rr)")
+inline string recipe_name(routine& rr) {
+  return Recipe[rr.calls.top().running_recipe].name;
+}
+:(replace{} "inline vector<instruction>& steps(routine& rr)")
+inline vector<instruction>& steps(routine& rr) {
+  return Recipe[rr.calls.top().running_recipe].steps;
+}
+
+:(replace{} "default:" following "End Primitive Recipe Implementations.")
+default: {
+  // not a primitive; try to look for a matching recipe
+  if (Recipe.find(instructions[pc].operation) == Recipe.end()) {
+    raise << "undefined operation " << instructions[pc].operation << ": " << instructions[pc].name << '\n';
+    break;
+  }
+  rr.calls.push(call(instructions[pc].operation));
+  continue;  // not done with caller; don't increment pc
+}
+
+//: finally, we need to fix the termination conditions for the run loop
+
+:(replace{} "inline bool done(routine& rr)")
+inline bool done(routine& rr) {
+  return rr.calls.empty();
+}
+
+:(before "Running one instruction.")
+// when we reach the end of one call, we may reach the end of the one below
+// it, and the one below that, and so on
+while (running_at(rr) >= steps(rr).size()) {
+  rr.calls.pop();
+  if (rr.calls.empty()) return;
+  // todo: no results returned warning
+  ++running_at(rr);
+}