about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-10-29 17:15:09 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-10-29 17:15:09 -0700
commite6692482643dc007988188e2b19fbb9219ca2833 (patch)
treecbb805cba3bd46dfc7d71adaa2150d9acb5cc5ba
parent5a702544a6f8aa3fa520ba387a6c0e803e076476 (diff)
downloadmu-e6692482643dc007988188e2b19fbb9219ca2833.tar.gz
2321 - more preparations for static dispatch
Deduce operation id from name during transform rather than load, so that
earlier transforms have a chance to modify the name.
-rw-r--r--010vm.cc5
-rw-r--r--011load.cc11
-rw-r--r--013update_operation.cc31
-rw-r--r--020run.cc5
-rw-r--r--021check_instruction.cc2
-rw-r--r--040brace.cc51
-rw-r--r--041jump_target.cc10
-rw-r--r--042name.cc7
-rw-r--r--043new.cc2
-rw-r--r--044space.cc6
-rw-r--r--056recipe_header.cc8
-rw-r--r--072scenario_screen.cc2
12 files changed, 75 insertions, 65 deletions
diff --git a/010vm.cc b/010vm.cc
index 21dd28d0..bdf4ec17 100644
--- a/010vm.cc
+++ b/010vm.cc
@@ -33,6 +33,7 @@ struct instruction {
   bool is_label;
   string label;  // only if is_label
   string name;  // only if !is_label
+  string old_name;  // before our automatic rewrite rules
   recipe_ordinal operation;  // Recipe_ordinal[name]
   vector<reagent> ingredients;  // only if !is_label
   vector<reagent> products;  // only if !is_label
@@ -227,8 +228,8 @@ recipe::recipe() {
 instruction::instruction() :is_label(false), operation(IDLE) {
   // End instruction Constructor
 }
-void instruction::clear() { is_label=false; label.clear(); operation=IDLE; ingredients.clear(); products.clear(); }
-bool instruction::is_clear() { return !is_label && operation == IDLE; }
+void instruction::clear() { is_label=false; label.clear(); name.clear(); old_name.clear(); operation=IDLE; ingredients.clear(); products.clear(); }
+bool instruction::is_clear() { return !is_label && name.empty(); }
 
 // Reagents have the form <name>:<type>:<type>:.../<property>/<property>/...
 reagent::reagent(string s) :original_string(s), value(0), initialized(false), type(NULL) {
diff --git a/011load.cc b/011load.cc
index 2ac517c5..d848fd55 100644
--- a/011load.cc
+++ b/011load.cc
@@ -134,15 +134,8 @@ bool next_instruction(istream& in, instruction* curr) {
     raise_error << "instruction prematurely ended with '<-'\n" << end();
     return false;
   }
-  curr->name = *p;
-  if (Recipe_ordinal.find(*p) == Recipe_ordinal.end()) {
-    Recipe_ordinal[*p] = Next_recipe_ordinal++;
-  }
-  if (Recipe_ordinal[*p] == 0) {
-    raise_error << "Recipe " << *p << " has number 0, which is reserved for IDLE.\n" << end();
-    return false;
-  }
-  curr->operation = Recipe_ordinal[*p];  ++p;
+  curr->old_name = curr->name = *p;  p++;
+  // curr->operation will be set in a later layer
 
   for (; p != words.end(); ++p) {
     curr->ingredients.push_back(reagent(*p));
diff --git a/013update_operation.cc b/013update_operation.cc
new file mode 100644
index 00000000..edfda882
--- /dev/null
+++ b/013update_operation.cc
@@ -0,0 +1,31 @@
+//: Once all code is loaded, save operation ids of instructions and check that
+//: nothing's undefined.
+
+:(after "int main")
+  // do this before any other transforms
+  Transform.push_back(update_instruction_operations);
+
+:(code)
+void update_instruction_operations(recipe_ordinal r) {
+  trace(9991, "transform") << "--- compute instruction operations for recipe " << Recipe[r].name << end();
+  for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
+    instruction& inst = Recipe[r].steps.at(index);
+    if (inst.is_label) continue;
+    if (Recipe_ordinal.find(inst.name) == Recipe_ordinal.end()) {
+      raise_error << maybe(Recipe[r].name) << "instruction " << inst.name << " has no recipe\n" << end();
+      return;
+    }
+    inst.operation = Recipe_ordinal[inst.name];
+  }
+}
+
+// hook to suppress inserting recipe name into errors and warnings (for later layers)
+string maybe(string s) {
+  return s + ": ";
+}
+
+// temporarily suppress run
+void transform(string form) {
+  load(form);
+  transform_all();
+}
diff --git a/020run.cc b/020run.cc
index db82ec36..24a0a863 100644
--- a/020run.cc
+++ b/020run.cc
@@ -317,11 +317,6 @@ inline bool scalar(const vector<double>& x) {
   return SIZE(x) == 1;
 }
 
-// hook to suppress inserting recipe name into errors and warnings (for later layers)
-string maybe(string s) {
-  return s + ": ";
-}
-
 // helper for tests
 void run(string form) {
   vector<recipe_ordinal> tmp = load(form);
diff --git a/021check_instruction.cc b/021check_instruction.cc
index 6df7a2d1..035fe6ce 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -8,7 +8,7 @@
 //: sophisticated layer system I'd introduce the simpler version first and
 //: transform it in a separate layer or set of layers.
 
-:(after "int main")
+:(after "Transform.push_back(update_instruction_operations)")
   Transform.push_back(check_instruction);
 
 :(code)
diff --git a/040brace.cc b/040brace.cc
index aae9f3d7..afd97294 100644
--- a/040brace.cc
+++ b/040brace.cc
@@ -64,34 +64,34 @@ void transform_braces(const recipe_ordinal r) {
       continue;
     }
     if (inst.is_label) continue;
-    if (inst.operation != Recipe_ordinal["loop"]
-         && inst.operation != Recipe_ordinal["loop-if"]
-         && inst.operation != Recipe_ordinal["loop-unless"]
-         && inst.operation != Recipe_ordinal["break"]
-         && inst.operation != Recipe_ordinal["break-if"]
-         && inst.operation != Recipe_ordinal["break-unless"]) {
-      trace(9991, "transform") << inst.name << " ..." << end();
+    if (inst.old_name != "loop"
+         && inst.old_name != "loop-if"
+         && inst.old_name != "loop-unless"
+         && inst.old_name != "break"
+         && inst.old_name != "break-if"
+         && inst.old_name != "break-unless") {
+      trace(9991, "transform") << inst.old_name << " ..." << end();
       continue;
     }
     // check for errors
-    if (inst.name.find("-if") != string::npos || inst.name.find("-unless") != string::npos) {
+    if (inst.old_name.find("-if") != string::npos || inst.old_name.find("-unless") != string::npos) {
       if (inst.ingredients.empty()) {
-        raise_error << inst.name << " expects 1 or 2 ingredients, but got none\n" << end();
+        raise_error << inst.old_name << " expects 1 or 2 ingredients, but got none\n" << end();
         continue;
       }
     }
     // update instruction operation
-    if (inst.name.find("-if") != string::npos)
-      inst.operation = Recipe_ordinal["jump-if"];
-    else if (inst.name.find("-unless") != string::npos)
-      inst.operation = Recipe_ordinal["jump-unless"];
+    if (inst.old_name.find("-if") != string::npos)
+      inst.name = "jump-if";
+    else if (inst.old_name.find("-unless") != string::npos)
+      inst.name = "jump-unless";
     else
-      inst.operation = Recipe_ordinal["jump"];
+      inst.name = "jump";
     // check for explicitly provided targets
-    if (inst.name.find("-if") != string::npos || inst.name.find("-unless") != string::npos) {
+    if (inst.old_name.find("-if") != string::npos || inst.old_name.find("-unless") != string::npos) {
       // conditional branches check arg 1
       if (SIZE(inst.ingredients) > 1 && is_literal(inst.ingredients.at(1))) {
-        trace(9991, "transform") << "jump " << inst.ingredients.at(1).name << ":offset" << end();
+        trace(9991, "transform") << inst.name << ' ' << inst.ingredients.at(1).name << ":offset" << end();
         continue;
       }
     }
@@ -107,19 +107,17 @@ void transform_braces(const recipe_ordinal r) {
     target.type = new type_tree(Type_ordinal["offset"]);
     target.set_value(0);
     if (open_braces.empty())
-      raise_error << inst.name << " needs a '{' before\n" << end();
-    else if (inst.name.find("loop") != string::npos)
+      raise_error << inst.old_name << " needs a '{' before\n" << end();
+    else if (inst.old_name.find("loop") != string::npos)
       target.set_value(open_braces.top()-index);
     else  // break instruction
       target.set_value(matching_brace(open_braces.top(), braces, r) - index - 1);
     inst.ingredients.push_back(target);
     // log computed target
-    if (inst.name.find("-if") != string::npos)
-      trace(9991, "transform") << "jump-if " << inst.ingredients.at(0).name << ", " << no_scientific(target.value) << ":offset" << end();
-    else if (inst.name.find("-unless") != string::npos)
-      trace(9991, "transform") << "jump-unless " << inst.ingredients.at(0).name << ", " << no_scientific(target.value) << ":offset" << end();
-    else
+    if (inst.name == "jump")
       trace(9991, "transform") << "jump " << no_scientific(target.value) << ":offset" << end();
+    else
+      trace(9991, "transform") << inst.name << ' ' << inst.ingredients.at(0).name << ", " << no_scientific(target.value) << ":offset" << end();
   }
 }
 
@@ -136,12 +134,7 @@ long long int matching_brace(long long int index, const list<pair<int, long long
   return SIZE(Recipe[r].steps);  // exit current routine
 }
 
-// temporarily suppress run
-void transform(string form) {
-  load(form);
-  transform_all();
-}
-
+// todo: remove?
 //: Make sure these pseudo recipes get consistent numbers in all tests, even
 //: though they aren't implemented.
 
diff --git a/041jump_target.cc b/041jump_target.cc
index 7207c799..1f0e2212 100644
--- a/041jump_target.cc
+++ b/041jump_target.cc
@@ -39,18 +39,18 @@ void transform_labels(const recipe_ordinal r) {
   }
   for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
     instruction& inst = Recipe[r].steps.at(i);
-    if (inst.operation == Recipe_ordinal["jump"]) {
+    if (inst.name == "jump") {
       replace_offset(inst.ingredients.at(0), offset, i, r);
     }
-    if (inst.operation == Recipe_ordinal["jump-if"] || inst.operation == Recipe_ordinal["jump-unless"]) {
+    if (inst.name == "jump-if" || inst.name == "jump-unless") {
       replace_offset(inst.ingredients.at(1), offset, i, r);
     }
-    if ((inst.operation == Recipe_ordinal["loop"] || inst.operation == Recipe_ordinal["break"])
+    if ((inst.name == "loop" || inst.name == "break")
         && SIZE(inst.ingredients) == 1) {
       replace_offset(inst.ingredients.at(0), offset, i, r);
     }
-    if ((inst.operation == Recipe_ordinal["loop-if"] || inst.operation == Recipe_ordinal["loop-unless"]
-            || inst.operation == Recipe_ordinal["break-if"] || inst.operation == Recipe_ordinal["break-unless"])
+    if ((inst.name == "loop-if" || inst.name == "loop-unless"
+            || inst.name == "break-if" || inst.name == "break-unless")
         && SIZE(inst.ingredients) == 2) {
       replace_offset(inst.ingredients.at(1), offset, i, r);
     }
diff --git a/042name.cc b/042name.cc
index 6022fd93..6e56b2e3 100644
--- a/042name.cc
+++ b/042name.cc
@@ -193,14 +193,13 @@ recipe main [
 
 :(before "End transform_names(inst) Special-cases")
 // replace element names of containers with offsets
-if (inst.operation == Recipe_ordinal["get"]
-    || inst.operation == Recipe_ordinal["get-address"]) {
+if (inst.name == "get" || inst.name == "get-address") {
   if (SIZE(inst.ingredients) != 2) {
     raise_error << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(1)))
-    raise_error << maybe(Recipe[r].name) << "expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(Recipe[r].name) << "expected ingredient 1 of " << (inst.name == "get" ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be a container, we don't have to canonize
     type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type, Recipe[r].name);
@@ -234,7 +233,7 @@ recipe main [
 
 :(before "End transform_names(inst) Special-cases")
 // convert variant names of exclusive containers
-if (inst.operation == Recipe_ordinal["maybe-convert"]) {
+if (inst.name == "maybe-convert") {
   if (SIZE(inst.ingredients) != 2) {
     raise_error << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
     break;
diff --git a/043new.cc b/043new.cc
index 9c76adfb..72f3491b 100644
--- a/043new.cc
+++ b/043new.cc
@@ -30,7 +30,7 @@ trace(9999, "new") << "routine allocated memory from " << alloc << " to " << all
 Type_ordinal["type"] = 0;
 :(before "End transform_names(inst) Special-cases")
 // replace type names with type_ordinals
-if (inst.operation == Recipe_ordinal["new"]) {
+if (inst.name == "new") {
   // End NEW Transform Special-cases
   // first arg must be of type 'type'
   if (inst.ingredients.empty())
diff --git a/044space.cc b/044space.cc
index 56b494d5..dd579a4f 100644
--- a/044space.cc
+++ b/044space.cc
@@ -173,15 +173,15 @@ void try_reclaim_locals() {
   const recipe_ordinal r = Recipe_ordinal[current_recipe_name()];
   if (Recipe[r].steps.empty()) return;
   const instruction& inst = Recipe[r].steps.at(0);
-  if (inst.name != "local-scope") return;
+  if (inst.old_name != "local-scope") return;
   abandon(current_call().default_space,
           /*array length*/1+/*number-of-locals*/Name[r][""]);
 }
 
 void rewrite_default_space_instruction(instruction& curr) {
-  curr.operation = Recipe_ordinal["new"];
   if (!curr.ingredients.empty())
-    raise_error << "new-default-space can't take any ingredients\n" << end();
+    raise_error << curr.to_string() << " can't take any ingredients\n" << end();
+  curr.name = "new";
   curr.ingredients.push_back(reagent("location:type"));
   curr.ingredients.push_back(reagent("number-of-locals:literal"));
   if (!curr.products.empty())
diff --git a/056recipe_header.cc b/056recipe_header.cc
index 89ad945e..2ba0ac4b 100644
--- a/056recipe_header.cc
+++ b/056recipe_header.cc
@@ -65,14 +65,14 @@ if (curr.name == "load-ingredients") {
 
 :(scenarios transform)
 :(scenario recipe_headers_are_checked)
-% Hide_warnings = true;
+% Hide_errors = true;
 recipe add2 x:number, y:number -> z:number [
   local-scope
   load-ingredients
   z:address:number <- copy 0/raw
   reply z
 ]
-+warn: add2: replied with the wrong type at 'reply z'
++error: add2: replied with the wrong type at 'reply z'
 
 :(before "End One-time Setup")
   Transform.push_back(check_header_products);
@@ -86,11 +86,11 @@ void check_header_products(const recipe_ordinal r) {
     const instruction& inst = rr.steps.at(i);
     if (inst.operation != REPLY) continue;
     if (SIZE(rr.products) != SIZE(inst.ingredients)) {
-      raise << maybe(rr.name) << "tried to reply the wrong number of products in '" << inst.to_string() << "'\n" << end();
+      raise_error << maybe(rr.name) << "tried to reply the wrong number of products in '" << inst.to_string() << "'\n" << end();
     }
     for (long long int i = 0; i < SIZE(rr.products); ++i) {
       if (!types_match(rr.products.at(i), inst.ingredients.at(i))) {
-        raise << maybe(rr.name) << "replied with the wrong type at '" << inst.to_string() << "'\n" << end();
+        raise_error << maybe(rr.name) << "replied with the wrong type at '" << inst.to_string() << "'\n" << end();
       }
     }
   }
diff --git a/072scenario_screen.cc b/072scenario_screen.cc
index 11151eac..97002005 100644
--- a/072scenario_screen.cc
+++ b/072scenario_screen.cc
@@ -141,9 +141,7 @@ Name[r]["screen"] = SCREEN;
 // rewrite `assume-screen width, height` to
 // `screen:address:screen <- new-fake-screen width, height`
 if (curr.name == "assume-screen") {
-  curr.operation = Recipe_ordinal["new-fake-screen"];
   curr.name = "new-fake-screen";
-  assert(curr.operation);
   assert(curr.products.empty());
   curr.products.push_back(reagent("screen:address:screen"));
   curr.products.at(0).set_value(SCREEN);
ss='alt'>