about summary refs log tree commit diff stats
path: root/cpp/025call
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/025call')
-rw-r--r--cpp/025call77
1 files changed, 77 insertions, 0 deletions
diff --git a/cpp/025call b/cpp/025call
new file mode 100644
index 00000000..3683db12
--- /dev/null
+++ b/cpp/025call
@@ -0,0 +1,77 @@
+//: 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 4 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;
+  // End routine Fields
+  routine(recipe_number r);
+};
+:(code)
+  routine::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);
+}
+
+:(before "End Includes")
+#include <stack>
+using std::stack;