about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-07-03 19:38:21 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-07-03 19:38:21 -0700
commit7f73795cf5a5722dd6c05bee1e7c8c3f8eded8da (patch)
tree00871986797f79b9156c37dec25eb2071fda0d2c
parent608d5c9aa148801081d7dca80b6f3bfb5b285f08 (diff)
downloadmu-7f73795cf5a5722dd6c05bee1e7c8c3f8eded8da.tar.gz
1699 - first-class recipe types
It should now be easy to do dynamic dispatch, create higher-order
functions, etc.
-rw-r--r--012transform.cc1
-rw-r--r--020run.cc1
-rw-r--r--037call_variable.cc44
-rw-r--r--037recipe.cc51
-rw-r--r--038scheduler.cc8
5 files changed, 54 insertions, 51 deletions
diff --git a/012transform.cc b/012transform.cc
index 7cd4d698..1a7415c8 100644
--- a/012transform.cc
+++ b/012transform.cc
@@ -47,6 +47,7 @@ void parse_int_reagents() {
 
 void populate_value(reagent& r) {
   if (r.initialized) return;
+  // End Reagent-parsing Exceptions
   if (!is_integer(r.name)) return;
   r.set_value(to_integer(r.name));
 }
diff --git a/020run.cc b/020run.cc
index 2c069576..cecfd7b0 100644
--- a/020run.cc
+++ b/020run.cc
@@ -76,6 +76,7 @@ void run_current_routine()
     switch (current_instruction().operation) {
       // Primitive Recipe Implementations
       case COPY: {
+//?         if (!ingredients.empty()) cerr << current_instruction().ingredients.at(0).to_string() << ' ' << ingredients.at(0).at(0) << '\n'; //? 1
         copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin()));
         break;
       }
diff --git a/037call_variable.cc b/037call_variable.cc
deleted file mode 100644
index 9514ed95..00000000
--- a/037call_variable.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-//: push a variable recipe on the call stack
-
-:(scenario call_literal_recipe)
-recipe main [
-  1:number <- call f:recipe, 34:literal
-]
-recipe f [
-  2:number <- next-ingredient
-  reply 2:number
-]
-+mem: storing 34 in location 1
-
-:(scenario call_variable)
-recipe main [
-  1:number/recipe <- copy 1001:literal/f  # hack: assumes tests start recipes at 1000
-  2:number <- call 1:number/recipe, 34:literal
-]
-recipe f [  # recipe 1001
-  3:number <- next-ingredient
-  reply 3:number
-]
-+mem: storing 34 in location 2
-#? ?
-
-:(before "End Primitive Recipe Declarations")
-CALL,
-:(before "End Primitive Recipe Numbers")
-Recipe_number["call"] = CALL;
-:(before "End Primitive Recipe Implementations")
-case CALL: {
-  recipe_number r = 0;
-  if (current_instruction().ingredients.at(0).initialized) {
-    assert(scalar(ingredients.at(0)));
-    // 'call' received an integer recipe_number
-    r = ingredients.at(0).at(0);
-  }
-  else {
-    // 'call' received a literal recipe name
-    r = Recipe_number[current_instruction().ingredients.at(0).name];
-  }
-  Current_routine->calls.push_front(call(r));
-  ingredients.erase(ingredients.begin());  // drop the callee
-  goto complete_call;
-}
diff --git a/037recipe.cc b/037recipe.cc
new file mode 100644
index 00000000..a20994ea
--- /dev/null
+++ b/037recipe.cc
@@ -0,0 +1,51 @@
+//: So far we've been calling a fixed recipe in each instruction, but we'd
+//: also like to make the recipe a variable, pass recipes to "higher-order"
+//: recipes, return recipes from recipes and so on.
+
+:(scenario call_literal_recipe)
+recipe main [
+  1:number <- call f:recipe, 34:literal
+]
+recipe f [
+  2:number <- next-ingredient
+  reply 2:number
+]
++mem: storing 34 in location 1
+
+:(scenario call_variable)
+recipe main [
+  1:recipe-code <- copy f:recipe
+  2:number <- call 1:recipe-code, 34:literal
+]
+recipe f [
+  3:number <- next-ingredient
+  reply 3:number
+]
++mem: storing 34 in location 2
+#? ?
+
+:(before "End Mu Types Initialization")
+Type_number["recipe"] = 0;
+type_number recipe_code = Type_number["recipe-code"] = Next_type_number++;
+Type[recipe_code].name = "recipe-code";
+
+:(before "End Reagent-parsing Exceptions")
+if (r.properties.at(0).second.at(0) == "recipe") {
+  r.set_value(Recipe_number[r.name]);
+  return;
+}
+
+:(before "End Primitive Recipe Declarations")
+CALL,
+:(before "End Primitive Recipe Numbers")
+Recipe_number["call"] = CALL;
+:(before "End Primitive Recipe Implementations")
+case CALL: {
+  assert(scalar(ingredients.at(0)));
+  // todo: when we start doing type checking this will be a prime point of
+  // attention, so we don't accidentally allow external data to a program to
+  // run as code.
+  Current_routine->calls.push_front(call(ingredients.at(0).at(0)));
+  ingredients.erase(ingredients.begin());  // drop the callee
+  goto complete_call;
+}
diff --git a/038scheduler.cc b/038scheduler.cc
index 0857fe58..160753d4 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -127,10 +127,6 @@ Next_routine_id = 1;
 id = Next_routine_id;
 Next_routine_id++;
 
-//: it needs a new type: 'recipe'
-:(before "End Mu Types Initialization")
-Type_number["recipe"] = 0;
-
 //: routines save the routine that spawned them
 :(before "End routine Fields")
 // todo: really should be routine_id, but that's less efficient.
@@ -144,9 +140,7 @@ START_RUNNING,
 Recipe_number["start-running"] = START_RUNNING;
 :(before "End Primitive Recipe Implementations")
 case START_RUNNING: {
-  assert(is_literal(current_instruction().ingredients.at(0)));
-  assert(!current_instruction().ingredients.at(0).initialized);
-  routine* new_routine = new routine(Recipe_number[current_instruction().ingredients.at(0).name]);
+  routine* new_routine = new routine(ingredients.at(0).at(0));
 //?   cerr << new_routine->id << " -> " << Current_routine->id << '\n'; //? 1
   new_routine->parent_index = Current_routine_index;
   // populate ingredients