about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-03-21 02:53:34 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-03-21 02:53:34 -0700
commitd57bf669c20f1936af8674d549bfb01c01f68f4f (patch)
tree0d10ba2f55f1d7725c193871900ffb3152564d66
parentacc4792d2f7c787aad064876a1eb2d00bdf076b2 (diff)
downloadmu-d57bf669c20f1936af8674d549bfb01c01f68f4f.tar.gz
2804 - support stashing arrays
Now to extend 'stash' for arrays, just extend array-to-text-line instead
and perform the lookup inside it.
-rw-r--r--042name.cc11
-rw-r--r--047check_type_by_name.cc12
-rw-r--r--070text.mu7
-rw-r--r--071rewrite_stash.cc33
4 files changed, 50 insertions, 13 deletions
diff --git a/042name.cc b/042name.cc
index 6a9858a6..8cd6cd4f 100644
--- a/042name.cc
+++ b/042name.cc
@@ -110,14 +110,13 @@ int lookup_name(const reagent& r, const recipe_ordinal default_recipe) {
   return Name[default_recipe][r.name];
 }
 
-type_ordinal skip_addresses(type_tree* type, const string& recipe_name) {
+type_ordinal skip_addresses(type_tree* type) {
   type_ordinal address = get(Type_ordinal, "address");
   type_ordinal shared = get(Type_ordinal, "shared");
   for (; type; type = type->right) {
     if (type->value != address && type->value != shared)
       return type->value;
   }
-  raise << maybe(recipe_name) << "expected a container" << '\n' << end();
   return -1;
 }
 
@@ -220,7 +219,9 @@ if (inst.name == "get" || inst.name == "get-address") {
     raise << maybe(get(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, get(Recipe, r).name);
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type);
+    if (base_type == -1)
+      raise << maybe(get(Recipe, r).name) << "expected a container in '" << to_original_string(inst) << "'\n" << end();
     if (contains_key(Type, base_type)) {  // otherwise we'll raise an error elsewhere
       inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name));
       trace(9993, "name") << "element " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " is at offset " << no_scientific(inst.ingredients.at(1).value) << end();
@@ -261,7 +262,9 @@ if (inst.name == "maybe-convert") {
   assert(is_literal(inst.ingredients.at(1)));
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be an exclusive container, we don't have to canonize
-    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type, get(Recipe, r).name);
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type);
+    if (base_type == -1)
+      raise << maybe(get(Recipe, r).name) << "expected an exclusive-container in '" << to_original_string(inst) << "'\n" << end();
     if (contains_key(Type, base_type)) {  // otherwise we'll raise an error elsewhere
       inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name));
       trace(9993, "name") << "variant " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " has tag " << no_scientific(inst.ingredients.at(1).value) << end();
diff --git a/047check_type_by_name.cc b/047check_type_by_name.cc
index a1970915..ed45119f 100644
--- a/047check_type_by_name.cc
+++ b/047check_type_by_name.cc
@@ -26,11 +26,11 @@ void check_or_set_types_by_name(const recipe_ordinal r) {
     instruction& inst = caller.steps.at(i);
     for (int in = 0; in < SIZE(inst.ingredients); ++in) {
       deduce_missing_type(known, inst.ingredients.at(in));
-      check_type(known, inst.ingredients.at(in), r);
+      check_type(known, inst.ingredients.at(in), caller);
     }
     for (int out = 0; out < SIZE(inst.products); ++out) {
       deduce_missing_type(known, inst.products.at(out));
-      check_type(known, inst.products.at(out), r);
+      check_type(known, inst.products.at(out), caller);
     }
   }
 }
@@ -42,7 +42,7 @@ void deduce_missing_type(set<reagent>& known, reagent& x) {
   trace(9992, "transform") << x.name << " <= " << names_to_string(x.type) << end();
 }
 
-void check_type(set<reagent>& known, const reagent& x, const recipe_ordinal r) {
+void check_type(set<reagent>& known, const reagent& x, const recipe& caller) {
   if (is_literal(x)) return;
   if (is_integer(x.name)) return;  // if you use raw locations you're probably doing something unsafe
   if (!x.type) return;  // might get filled in by other logic later
@@ -51,16 +51,16 @@ void check_type(set<reagent>& known, const reagent& x, const recipe_ordinal r) {
     known.insert(x);
   }
   if (!types_strictly_match(known.find(x)->type, x.type)) {
-    raise << maybe(get(Recipe, r).name) << x.name << " used with multiple types\n" << end();
+    raise << maybe(caller.name) << x.name << " used with multiple types\n" << end();
     return;
   }
   if (x.type->name == "array") {
     if (!x.type->right) {
-      raise << maybe(get(Recipe, r).name) << x.name << " can't be just an array. What is it an array of?\n" << end();
+      raise << maybe(caller.name) << x.name << " can't be just an array. What is it an array of?\n" << end();
       return;
     }
     if (!x.type->right->right) {
-      raise << get(Recipe, r).name << " can't determine the size of array variable " << x.name << ". Either allocate it separately and make the type of " << x.name << " address:shared:..., or specify the length of the array in the type of " << x.name << ".\n" << end();
+      raise << caller.name << " can't determine the size of array variable " << x.name << ". Either allocate it separately and make the type of " << x.name << " address:shared:..., or specify the length of the array in the type of " << x.name << ".\n" << end();
       return;
     }
   }
diff --git a/070text.mu b/070text.mu
index b69db18a..24317a59 100644
--- a/070text.mu
+++ b/070text.mu
@@ -8,6 +8,13 @@ def to-text-line x:_elem -> y:address:shared:array:character [
   y <- to-text x
 ]
 
+# variant for arrays (since we can't pass them around otherwise)
+def array-to-text-line x:address:shared:array:_elem -> y:address:shared:array:character [
+  local-scope
+  load-ingredients
+  y <- to-text *x
+]
+
 # to-text on text is just the identity function
 def to-text x:address:shared:array:character -> y:address:shared:array:character [
   local-scope
diff --git a/071rewrite_stash.cc b/071rewrite_stash.cc
index a41fa72f..a1a3deef 100644
--- a/071rewrite_stash.cc
+++ b/071rewrite_stash.cc
@@ -8,7 +8,19 @@ recipe main [
   n:number <- copy 34
   stash n
 ]
-+transform: {stash_2_0: ("address" "shared" "array" "character")} <- to-text-line {n: ()}
++transform: {stash_2_0: ("address" "shared" "array" "character")} <- to-text-line {n: "number"}
++transform: stash {stash_2_0: ("address" "shared" "array" "character")}
+
+//: special case: rewrite attempts to stash contents of most arrays to avoid
+//: passing addresses around
+
+:(scenario rewrite_stashes_of_arrays)
+recipe main [
+  local-scope
+  n:address:shared:array:number <- new number:type, 3
+  stash *n
+]
++transform: {stash_2_0: ("address" "shared" "array" "character")} <- array-to-text-line {n: ("address" "shared" "array" "number")}
 +transform: stash {stash_2_0: ("address" "shared" "array" "character")}
 
 :(before "End Instruction Inserting/Deleting Transforms")
@@ -20,6 +32,7 @@ void rewrite_stashes_to_text(recipe_ordinal r) {
   trace(9991, "transform") << "--- rewrite 'stash' instructions in recipe " << caller.name << end();
   // in recipes without named locations, 'stash' is still not extensible
   if (contains_numeric_locations(caller)) return;
+  check_or_set_types_by_name(r);  // prerequisite
   rewrite_stashes_to_text(caller);
 }
 
@@ -29,11 +42,20 @@ void rewrite_stashes_to_text(recipe& caller) {
     instruction& inst = caller.steps.at(i);
     if (inst.name == "stash") {
       for (int j = 0; j < SIZE(inst.ingredients); ++j) {
+        assert(inst.ingredients.at(j).type);
         if (is_literal(inst.ingredients.at(j))) continue;
         if (is_mu_string(inst.ingredients.at(j))) continue;
         instruction def;
-        def.name = "to-text-line";
-        def.ingredients.push_back(inst.ingredients.at(j));
+        if (is_address_of_array(inst.ingredients.at(j))) {
+          def.name = "array-to-text-line";
+          reagent tmp = inst.ingredients.at(j);
+          drop_one_lookup(tmp);
+          def.ingredients.push_back(tmp);
+        }
+        else {
+          def.name = "to-text-line";
+          def.ingredients.push_back(inst.ingredients.at(j));
+        }
         ostringstream ingredient_name;
         ingredient_name << "stash_" << i << '_' << j << ":address:shared:array:character";
         def.products.push_back(reagent(ingredient_name.str()));
@@ -49,6 +71,11 @@ void rewrite_stashes_to_text(recipe& caller) {
   caller.steps.swap(new_instructions);
 }
 
+bool is_address_of_array(reagent x) {
+  if (!canonize_type(x)) return false;
+  return x.type->name == "array";
+}
+
 //: Make sure that the new system is strictly better than just the 'stash'
 //: primitive by itself.