about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--010vm.cc3
-rw-r--r--011load.cc4
-rw-r--r--057static_dispatch.cc45
3 files changed, 50 insertions, 2 deletions
diff --git a/010vm.cc b/010vm.cc
index e772e811..af3bcc98 100644
--- a/010vm.cc
+++ b/010vm.cc
@@ -35,6 +35,7 @@ struct instruction {
   string label;  // only if is_label
   string name;  // only if !is_label
   string old_name;  // before our automatic rewrite rules
+  string original_string;
   recipe_ordinal operation;  // get(Recipe_ordinal, name)
   vector<reagent> ingredients;  // only if !is_label
   vector<reagent> products;  // only if !is_label
@@ -228,7 +229,7 @@ recipe::recipe() {
 instruction::instruction() :is_label(false), operation(IDLE) {
   // End instruction Constructor
 }
-void instruction::clear() { is_label=false; label.clear(); name.clear(); old_name.clear(); operation=IDLE; ingredients.clear(); products.clear(); }
+void instruction::clear() { is_label=false; label.clear(); name.clear(); old_name.clear(); operation=IDLE; ingredients.clear(); products.clear(); original_string.clear(); }
 bool instruction::is_clear() { return !is_label && name.empty(); }
 
 // Reagents have the form <name>:<type>:<type>:.../<property>/<property>/...
diff --git a/011load.cc b/011load.cc
index 2c99bfff..dd1f9369 100644
--- a/011load.cc
+++ b/011load.cc
@@ -75,8 +75,10 @@ void slurp_body(istream& in, recipe& result) {
   while (next_instruction(in, &curr)) {
     // End Rewrite Instruction(curr, recipe result)
     trace(9992, "load") << "after rewriting: " << curr.to_string() << end();
-    if (!curr.is_clear())
+    if (!curr.is_clear()) {
+      curr.original_string = curr.to_string();
       result.steps.push_back(curr);
+    }
   }
 }
 
diff --git a/057static_dispatch.cc b/057static_dispatch.cc
index 368804e7..fc860a99 100644
--- a/057static_dispatch.cc
+++ b/057static_dispatch.cc
@@ -140,6 +140,15 @@ for (long long int i = 0; i < SIZE(caller.products); ++i) {
 :(after "Transform.push_back(transform_names)")
 Transform.push_back(resolve_ambiguous_calls);  // idempotent
 
+//: In a later layer we'll introduce recursion in resolve_ambiguous_calls, by
+//: having it generate code for shape-shifting recipes and then transform such
+//: code. This data structure will help error messages be more useful.
+//:
+//: We're punning the 'call' data structure just because it has slots for
+//: calling recipe and calling instruction.
+:(before "End Globals")
+list<call> resolve_stack;
+
 :(code)
 void resolve_ambiguous_calls(recipe_ordinal r) {
   recipe& caller_recipe = get(Recipe, r);
@@ -149,7 +158,12 @@ void resolve_ambiguous_calls(recipe_ordinal r) {
     instruction& inst = caller_recipe.steps.at(index);
     if (inst.is_label) continue;
     if (get_or_insert(Recipe_variants, inst.name).empty()) continue;
+    resolve_stack.push_front(call(r));
+    resolve_stack.front().running_step_index = index;
     replace_best_variant(inst, caller_recipe);
+    assert(resolve_stack.front().running_recipe == r);
+    assert(resolve_stack.front().running_step_index == index);
+    resolve_stack.pop_front();
   }
 }
 
@@ -172,7 +186,38 @@ void replace_best_variant(instruction& inst, const recipe& caller_recipe) {
   // End Instruction Dispatch(inst, best_score)
   if (best_score == -1 && get(Recipe_ordinal, inst.name) >= MAX_PRIMITIVE_RECIPES) {
     raise_error << maybe(caller_recipe.name) << "failed to find a matching call for '" << inst.to_string() << "'\n" << end();
+    for (list<call>::iterator p = /*skip*/++resolve_stack.begin(); p != resolve_stack.end(); ++p) {
+      const recipe& specializer_recipe = get(Recipe, p->running_recipe);
+      const instruction& specializer_inst = specializer_recipe.steps.at(p->running_step_index);
+      if (specializer_recipe.name != "interactive")
+        raise_error << "  (from '" << specializer_inst.to_string() << "' in " << specializer_recipe.name << ")\n" << end();
+      else
+        raise_error << "  (from '" << specializer_inst.to_string() << "')\n" << end();
+      // One special-case to help with the rewrite_stash transform. (cross-layer)
+      if (specializer_inst.products.at(0).name.find("stash_") == 0) {
+        instruction stash_inst;
+        if (next_stash(*p, &stash_inst)) {
+          if (specializer_recipe.name != "interactive")
+            raise_error << "  (part of '" << stash_inst.original_string << "' in " << specializer_recipe.name << ")\n" << end();
+          else
+            raise_error << "  (part of '" << stash_inst.original_string << "')\n" << end();
+        }
+      }
+    }
+  }
+}
+
+bool next_stash(const call& c, instruction* stash_inst) {
+  const recipe& specializer_recipe = get(Recipe, c.running_recipe);
+  long long int index = c.running_step_index;
+  for (++index; index < SIZE(specializer_recipe.steps); ++index) {
+    const instruction& inst = specializer_recipe.steps.at(index);
+    if (inst.name == "stash") {
+      *stash_inst = inst;
+      return true;
+    }
   }
+  return false;
 }
 
 long long int variant_score(const instruction& inst, recipe_ordinal variant) {