about summary refs log tree commit diff stats
path: root/038new_text.cc
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-06-15 22:12:03 -0700
committerKartik Agaram <vc@akkartik.com>2018-06-15 22:12:03 -0700
commit0edd9b9fc60440213e4df926ea511419ee291f1e (patch)
tree84b22f7afdeb9110ad7105c5fc070dacff178502 /038new_text.cc
parent3f34ac9369978b396d00a4fd02c9fb06b8eea621 (diff)
downloadmu-0edd9b9fc60440213e4df926ea511419ee291f1e.tar.gz
4257 - abortive attempt at safe fat pointers
I've been working on this slowly over several weeks, but it's too hard
to support 0 as the null value for addresses. I constantly have to add
exceptions for scalar value corresponding to an address type (now
occupying 2 locations). The final straw is the test for 'reload':

  x:num <- reload text

'reload' returns an address. But there's no way to know that for
arbitrary instructions.

New plan: let's put this off for a bit and first create support for
literals. Then use 'null' instead of '0' for addresses everywhere. Then
it'll be easy to just change what 'null' means.
Diffstat (limited to '038new_text.cc')
-rw-r--r--038new_text.cc72
1 files changed, 42 insertions, 30 deletions
diff --git a/038new_text.cc b/038new_text.cc
index 4b666f1c..b2a5db75 100644
--- a/038new_text.cc
+++ b/038new_text.cc
@@ -4,23 +4,25 @@
 :(before "End Mu Types Initialization")
 put(Type_abbreviations, "text", new_type_tree("address:array:character"));
 
-:(scenario new_string)
+:(scenario new_text)
 def main [
   1:text <- new [abc def]
-  2:char <- index *1:text, 5
+  # location 2 is part of 1:text
+  3:char <- index *1:text, 5
 ]
 # number code for 'e'
-+mem: storing 101 in location 2
++mem: storing 101 in location 3
 
-:(scenario new_string_handles_unicode)
+:(scenario new_text_handles_unicode)
 def main [
   1:text <- new [a«c]
-  2:num <- length *1:text
-  3:char <- index *1:text, 1
+  # location 2 is part of 1:text
+  3:num <- length *1:text
+  4:char <- index *1:text, 1
 ]
-+mem: storing 3 in location 2
++mem: storing 3 in location 3
 # unicode for '«'
-+mem: storing 171 in location 3
++mem: storing 171 in location 4
 
 :(before "End NEW Check Special-cases")
 if (is_literal_text(inst.ingredients.at(0))) break;
@@ -29,6 +31,7 @@ if (inst.name == "new" && !inst.ingredients.empty() && is_literal_text(inst.ingr
 :(after "case NEW" following "Primitive Recipe Implementations")
   if (is_literal_text(current_instruction().ingredients.at(0))) {
     products.resize(1);
+    products.at(0).push_back(/*alloc id*/0);
     products.at(0).push_back(new_mu_text(current_instruction().ingredients.at(0).name));
     trace("mem") << "new string alloc: " << products.at(0).at(0) << end();
     break;
@@ -40,8 +43,9 @@ int new_mu_text(const string& contents) {
   int string_length = unicode_length(contents);
 //?   Total_alloc += string_length+1;
 //?   ++Num_alloc;
-  int result = allocate(string_length+/*array length*/1);
+  int result = allocate(/*array length*/1 + string_length);
   int curr_address = result;
+  ++curr_address;  // skip alloc id
   trace("mem") << "storing string length " << string_length << " in location " << curr_address << end();
   put(Memory, curr_address, string_length);
   ++curr_address;  // skip length
@@ -62,16 +66,16 @@ int new_mu_text(const string& contents) {
 
 //: a new kind of typo
 
-:(scenario string_literal_without_instruction)
+:(scenario literal_text_without_instruction)
 % Hide_errors = true;
 def main [
   [abc]
 ]
 +error: main: instruction '[abc]' has no recipe in '[abc]'
 
-//: stash recognizes strings
+//: stash recognizes texts
 
-:(scenario stash_string)
+:(scenario stash_text)
 def main [
   1:text <- new [abc]
   stash [foo:], 1:text
@@ -80,30 +84,29 @@ def main [
 
 :(before "End inspect Special-cases(r, data)")
 if (is_mu_text(r)) {
-  assert(scalar(data));
-  return read_mu_text(data.at(0));
+  return read_mu_text(data.at(/*skip alloc id*/1));
 }
 
 :(before "End $print Special-cases")
 else if (is_mu_text(current_instruction().ingredients.at(i))) {
-  cout << read_mu_text(ingredients.at(i).at(0));
+  cout << read_mu_text(ingredients.at(i).at(/*skip alloc id*/1));
 }
 
-:(scenario unicode_string)
+:(scenario unicode_text)
 def main [
   1:text <- new [♠]
   stash [foo:], 1:text
 ]
 +app: foo: ♠
 
-:(scenario stash_space_after_string)
+:(scenario stash_space_after_text)
 def main [
   1:text <- new [abc]
   stash 1:text, [foo]
 ]
 +app: abc foo
 
-:(scenario stash_string_as_array)
+:(scenario stash_text_as_array)
 def main [
   1:text <- new [abc]
   stash *1:text
@@ -114,15 +117,16 @@ def main [
 :(before "End Preprocess is_mu_text(reagent x)")
 if (!canonize_type(x)) return false;
 
-//: Allocate more to routine when initializing a literal string
-:(scenario new_string_overflow)
-% Initial_memory_per_routine = 2;
+//: Allocate more to routine when initializing a literal text
+:(scenario new_text_overflow)
+% Initial_memory_per_routine = 3;
 def main [
   1:address:num/raw <- new number:type
-  2:text/raw <- new [a]  # not enough room in initial page, if you take the array length into account
+  # location 2 is part of 1:address
+  3:text/raw <- new [a]  # not enough room in initial page, if you take the array length into account
 ]
-+new: routine allocated memory from 1000 to 1002
-+new: routine allocated memory from 1002 to 1004
++new: routine allocated memory from 1000 to 1003
++new: routine allocated memory from 1003 to 1006
 
 //: helpers
 :(code)
@@ -140,9 +144,9 @@ int unicode_length(const string& s) {
 
 string read_mu_text(int address) {
   if (address == 0) return "";
-  int length = get_or_insert(Memory, address);
+  int length = get_or_insert(Memory, address+/*alloc id*/1);
   if (length == 0) return "";
-  return read_mu_characters(address+1, length);
+  return read_mu_characters(address+/*alloc id*/1+/*length*/1, length);
 }
 
 string read_mu_characters(int start, int length) {
@@ -156,13 +160,21 @@ string read_mu_characters(int start, int length) {
 
 //: assert: perform sanity checks at runtime
 
-:(scenario assert)
+:(scenario assert_literal)
 % Hide_errors = true;  // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line.
 def main [
   assert 0, [this is an assert in Mu]
 ]
 +error: this is an assert in Mu
 
+:(scenario assert)
+% Hide_errors = true;  // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line.
+def main [
+  1:text <- new [this is an assert in Mu]
+  assert 0, 1:text
+]
++error: this is an assert in Mu
+
 :(before "End Primitive Recipe Declarations")
 ASSERT,
 :(before "End Primitive Recipe Numbers")
@@ -173,7 +185,7 @@ case ASSERT: {
     raise << maybe(get(Recipe, r).name) << "'assert' takes exactly two ingredients rather than '" << to_original_string(inst) << "'\n" << end();
     break;
   }
-  if (!is_mu_scalar(inst.ingredients.at(0))) {
+  if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) {
     raise << maybe(get(Recipe, r).name) << "'assert' requires a boolean for its first ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
     break;
   }
@@ -185,11 +197,11 @@ case ASSERT: {
 }
 :(before "End Primitive Recipe Implementations")
 case ASSERT: {
-  if (!ingredients.at(0).at(0)) {
+  if (!scalar_ingredient(ingredients, 0)) {
     if (is_literal_text(current_instruction().ingredients.at(1)))
       raise << current_instruction().ingredients.at(1).name << '\n' << end();
     else
-      raise << read_mu_text(ingredients.at(1).at(0)) << '\n' << end();
+      raise << read_mu_text(ingredients.at(1).at(/*skip alloc id*/1)) << '\n' << end();
     if (!Hide_errors) exit(1);
   }
   break;