about summary refs log tree commit diff stats
path: root/056static_dispatch.cc
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-05-05 21:47:59 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-05-05 21:59:50 -0700
commite76a27f3edfa0703a204f3ab30ce01b58877f6af (patch)
treeb9ff84216ac81d78b6d14dbbf7211981cb30e153 /056static_dispatch.cc
parent5d5116e3343b5f6efa289e35e1c29b761db12068 (diff)
downloadmu-e76a27f3edfa0703a204f3ab30ce01b58877f6af.tar.gz
2929 - fix a bug in static dispatch
Thanks Caleb for finding this. We'd been using sandboxes for so long, I
hadn't tried a null/0 screen/console in a while and somewhere down the
road Mu stopped matching 0 against concrete addresses.
Diffstat (limited to '056static_dispatch.cc')
-rw-r--r--056static_dispatch.cc74
1 files changed, 63 insertions, 11 deletions
diff --git a/056static_dispatch.cc b/056static_dispatch.cc
index 353b4b50..5271fe13 100644
--- a/056static_dispatch.cc
+++ b/056static_dispatch.cc
@@ -175,14 +175,18 @@ string best_variant(instruction& inst, const recipe& caller_recipe) {
   if (!candidates.empty()) return best_variant(inst, candidates).name;
 
   // Static Dispatch Phase 2
-  //: (shape-shifting recipes in a later layer)
-  // End Static Dispatch Phase 2
+  candidates = strictly_matching_variants_except_literal_zero_against_address(inst, variants);
+  if (!candidates.empty()) return best_variant(inst, candidates).name;
 
   // Static Dispatch Phase 3
-  candidates = strictly_matching_variants_except_literal_against_boolean(inst, variants);
-  if (!candidates.empty()) return best_variant(inst, candidates).name;
+  //: (shape-shifting recipes in a later layer)
+  // End Static Dispatch Phase 3
 
   // Static Dispatch Phase 4
+  candidates = strictly_matching_variants_except_literal_against_address_or_boolean(inst, variants);
+  if (!candidates.empty()) return best_variant(inst, candidates).name;
+
+  // Static Dispatch Phase 5
   candidates = matching_variants(inst, variants);
   if (!candidates.empty()) return best_variant(inst, candidates).name;
 
@@ -240,28 +244,65 @@ bool all_header_reagents_strictly_match(const instruction& inst, const recipe& v
   return true;
 }
 
-// phase 3
-vector<recipe_ordinal> strictly_matching_variants_except_literal_against_boolean(const instruction& inst, vector<recipe_ordinal>& variants) {
+// phase 2
+vector<recipe_ordinal> strictly_matching_variants_except_literal_zero_against_address(const instruction& inst, vector<recipe_ordinal>& variants) {
+  vector<recipe_ordinal> result;
+  for (int i = 0; i < SIZE(variants); ++i) {
+    if (variants.at(i) == -1) continue;
+    trace(9992, "transform") << "checking variant (strict) " << i << ": " << header_label(variants.at(i)) << end();
+    if (all_header_reagents_strictly_match_except_literal_zero_against_address(inst, get(Recipe, variants.at(i))))
+      result.push_back(variants.at(i));
+  }
+  return result;
+}
+
+bool all_header_reagents_strictly_match_except_literal_zero_against_address(const instruction& inst, const recipe& variant) {
+  for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) {
+    if (!types_strictly_match_except_literal_zero_against_address(variant.ingredients.at(i), inst.ingredients.at(i))) {
+      trace(9993, "transform") << "strict match failed: ingredient " << i << end();
+      return false;
+    }
+  }
+  for (int i = 0; i < min(SIZE(inst.products), SIZE(variant.products)); ++i) {
+    if (is_dummy(inst.products.at(i))) continue;
+    if (!types_strictly_match(variant.products.at(i), inst.products.at(i))) {
+      trace(9993, "transform") << "strict match failed: product " << i << end();
+      return false;
+    }
+  }
+  return true;
+}
+
+bool types_strictly_match_except_literal_zero_against_address(const reagent& to, const reagent& from) {
+  // to sidestep type-checking, use /unsafe in the source.
+  // this will be highlighted in red inside vim. just for setting up some tests.
+  if (is_literal(from) && is_mu_address(to))
+    return from.name == "0";
+  return types_strictly_match(to, from);
+}
+
+// phase 4
+vector<recipe_ordinal> strictly_matching_variants_except_literal_against_address_or_boolean(const instruction& inst, vector<recipe_ordinal>& variants) {
   vector<recipe_ordinal> result;
   for (int i = 0; i < SIZE(variants); ++i) {
     if (variants.at(i) == -1) continue;
     trace(9992, "transform") << "checking variant (strict except literals-against-booleans) " << i << ": " << header_label(variants.at(i)) << end();
-    if (all_header_reagents_strictly_match_except_literal_against_boolean(inst, get(Recipe, variants.at(i))))
+    if (all_header_reagents_strictly_match_except_literal_against_address_or_boolean(inst, get(Recipe, variants.at(i))))
       result.push_back(variants.at(i));
   }
   return result;
 }
 
-bool all_header_reagents_strictly_match_except_literal_against_boolean(const instruction& inst, const recipe& variant) {
+bool all_header_reagents_strictly_match_except_literal_against_address_or_boolean(const instruction& inst, const recipe& variant) {
   for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) {
-    if (!types_strictly_match_except_literal_against_boolean(variant.ingredients.at(i), inst.ingredients.at(i))) {
+    if (!types_strictly_match_except_literal_against_address_or_boolean(variant.ingredients.at(i), inst.ingredients.at(i))) {
       trace(9993, "transform") << "strict match failed: ingredient " << i << end();
       return false;
     }
   }
   for (int i = 0; i < min(SIZE(variant.products), SIZE(inst.products)); ++i) {
     if (is_dummy(inst.products.at(i))) continue;
-    if (!types_strictly_match_except_literal_against_boolean(variant.products.at(i), inst.products.at(i))) {
+    if (!types_strictly_match_except_literal_against_address_or_boolean(variant.products.at(i), inst.products.at(i))) {
       trace(9993, "transform") << "strict match failed: product " << i << end();
       return false;
     }
@@ -269,7 +310,18 @@ bool all_header_reagents_strictly_match_except_literal_against_boolean(const ins
   return true;
 }
 
-// phase 4
+bool types_strictly_match_except_literal_against_address_or_boolean(const reagent& to, const reagent& from) {
+  // to sidestep type-checking, use /unsafe in the source.
+  // this will be highlighted in red inside vim. just for setting up some tests.
+  if (is_literal(from)
+      && to.type && to.type->value == get(Type_ordinal, "boolean"))
+    return boolean_matches_literal(to, from);
+  if (is_literal(from) && is_mu_address(to))
+    return from.name == "0";
+  return types_strictly_match(to, from);
+}
+
+// phase 5
 vector<recipe_ordinal> matching_variants(const instruction& inst, vector<recipe_ordinal>& variants) {
   vector<recipe_ordinal> result;
   for (int i = 0; i < SIZE(variants); ++i) {