about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-09-15 13:46:13 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-09-15 14:04:22 -0700
commitb75d9d456cb36ad41ab735586473adbbf3444643 (patch)
tree4f3413a11bb93831e1e71d6a99d8bb1323de77d2
parentd63cddeac0f5fb7eeaeacf828765965e9b61b6ca (diff)
downloadmu-b75d9d456cb36ad41ab735586473adbbf3444643.tar.gz
3365 - create strings out of arbitrary types
The implementation is quite hacky. Let's see how future needs develop
before we try to clean it up.
-rw-r--r--059to_text.mu17
-rw-r--r--061text.mu29
-rw-r--r--062convert_ingredients_to_text.cc29
3 files changed, 72 insertions, 3 deletions
diff --git a/059to_text.mu b/059to_text.mu
index 207ade78..30761eb9 100644
--- a/059to_text.mu
+++ b/059to_text.mu
@@ -29,3 +29,20 @@ scenario array-to-text-line-early-warning-for-static-dispatch [
   x:text <- array-to-text-line n
   # just ensure there were no errors
 ]
+
+# finally, a specialization for single characters
+def to-text c:character -> y:text [
+  local-scope
+  load-ingredients
+  y <- new character:type, 1/capacity
+  *y <- put-index *y, 0, c
+]
+
+scenario character-to-text [
+  1:character <- copy 111/o
+  2:text <- to-text 1:character
+  3:array:character <- copy *2:text
+  memory-should-contain [
+    3:array:character <- [o]
+  ]
+]
diff --git a/061text.mu b/061text.mu
index a5b653ec..6961199e 100644
--- a/061text.mu
+++ b/061text.mu
@@ -299,10 +299,24 @@ def buffer-to-array in:address:buffer -> result:text [
   }
 ]
 
-def append -> result:text [
+# Append any number of texts together.
+# A later layer also translates calls to this to implicitly call to-text, so
+# append to string becomes effectively dynamically typed.
+#
+# Beware though: this hack restricts how much 'append' can be overridden. Any
+# new variants that match:
+#   append _:text, ___
+# will never ever get used.
+def append first:text -> result:text [
   local-scope
   load-ingredients
   buf:address:buffer <- new-buffer 30
+  # append first ingredient
+  {
+    break-unless first
+    buf <- append buf, first
+  }
+  # append remaining ingredients
   {
     arg:text, arg-found?:boolean <- next-ingredient
     break-unless arg-found?
@@ -366,6 +380,19 @@ scenario text-append-multiary [
   ]
 ]
 
+scenario text-append-multiary-heterogeneous-types [
+  run [
+    local-scope
+    n:number <- copy 34
+    c:character <- copy 111/o
+    z:text <- append [abc ], n, c
+    10:array:character/raw <- copy *z
+  ]
+  memory-should-contain [
+    10:array:character <- [abc 34o]
+  ]
+]
+
 scenario replace-character-in-text [
   run [
     local-scope
diff --git a/062convert_ingredients_to_text.cc b/062convert_ingredients_to_text.cc
index bdba51d2..eb5fbd22 100644
--- a/062convert_ingredients_to_text.cc
+++ b/062convert_ingredients_to_text.cc
@@ -60,6 +60,7 @@ Transform.push_back(convert_ingredients_to_text);
 void convert_ingredients_to_text(recipe_ordinal r) {
   recipe& caller = get(Recipe, r);
   trace(9991, "transform") << "--- convert some ingredients to text in recipe " << caller.name << end();
+//?   cerr << "--- convert some ingredients to text in recipe " << caller.name << '\n';
   // in recipes without named locations, 'stash' is still not extensible
   if (contains_numeric_locations(caller)) return;
   convert_ingredients_to_text(caller);
@@ -69,8 +70,10 @@ void convert_ingredients_to_text(recipe& caller) {
   vector<instruction> new_instructions;
   for (int i = 0; i < SIZE(caller.steps); ++i) {
     instruction& inst = caller.steps.at(i);
+    // all these cases are getting hairy. how can we make this extensible?
     if (inst.name == "stash") {
       for (int j = 0; j < SIZE(inst.ingredients); ++j) {
+        if (is_literal_string(inst.ingredients.at(j))) continue;
         ostringstream ingredient_name;
         ingredient_name << "stash_" << i << '_' << j << ":address:array:character";
         convert_ingredient_to_text(inst.ingredients.at(j), new_instructions, ingredient_name.str());
@@ -78,11 +81,26 @@ void convert_ingredients_to_text(recipe& caller) {
     }
     else if (inst.name == "trace") {
       for (int j = /*skip*/2; j < SIZE(inst.ingredients); ++j) {
+        if (is_literal_string(inst.ingredients.at(j))) continue;
         ostringstream ingredient_name;
         ingredient_name << "trace_" << i << '_' << j << ":address:array:character";
         convert_ingredient_to_text(inst.ingredients.at(j), new_instructions, ingredient_name.str());
       }
     }
+    else if (inst.old_name == "append") {
+      // override only variants that try to append to a string
+      // Beware: this hack restricts how much 'append' can be overridden. Any
+      // new variants that match:
+      //   append _:text, ___
+      // will never ever get used.
+      if (is_literal_string(inst.ingredients.at(0)) || is_mu_string(inst.ingredients.at(0))) {
+        for (int j = 0; j < SIZE(inst.ingredients); ++j) {
+          ostringstream ingredient_name;
+          ingredient_name << "append_" << i << '_' << j << ":address:array:character";
+          convert_ingredient_to_text(inst.ingredients.at(j), new_instructions, ingredient_name.str());
+        }
+      }
+    }
     trace(9993, "transform") << to_string(inst) << end();
     new_instructions.push_back(inst);
   }
@@ -93,7 +111,6 @@ void convert_ingredients_to_text(recipe& caller) {
 // replace r with converted text
 void convert_ingredient_to_text(reagent& r, vector<instruction>& out, const string& tmp_var) {
   if (!r.type) return;  // error; will be handled elsewhere
-  if (is_literal(r)) return;
   if (is_mu_string(r)) return;
   // don't try to extend static arrays
   if (is_static_array(r)) return;
@@ -127,10 +144,18 @@ bool is_static_array(const reagent& x) {
   return !x.type->atom && x.type->left->atom && x.type->left->name == "array";
 }
 
+:(scenarios run)
+:(scenario append_other_types_to_text)
+def main [
+  local-scope
+  a:text <- append [abc], 10, 11
+  expected:text <- new [abc1011]
+  10:boolean/raw <- equal a, expected
+]
+
 //: Make sure that the new system is strictly better than just the 'stash'
 //: primitive by itself.
 
-:(scenarios run)
 :(scenario rewrite_stash_continues_to_fall_back_to_default_implementation)
 # type without a to-text implementation
 container foo [