about summary refs log tree commit diff stats
path: root/cpp
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-03-20 21:12:51 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-03-20 21:16:12 -0700
commita3d9828c190c86d9984a8e788f16dc10dfb95afa (patch)
tree3632b7319a88da648a99d595b38078ffd8d529b4 /cpp
parentad68bbce689969c4b0483a148c2a5260e9256fa7 (diff)
downloadmu-a3d9828c190c86d9984a8e788f16dc10dfb95afa.tar.gz
961 - done converting names?
I'm making two changes to how I compute field offsets:
  a) I just replace offset names up front, before I even manage field
  names. I don't bother disallowing x:integer and x:offset in the same
  function. Let's see if that leads us astray. Certainly saves code.

  b) I don't bother canonizing the first arg of a get since we know it
  has to have a type that is some number of 'address' followed by a
  record. Just assume that we have the right number of 'deref's.
Diffstat (limited to 'cpp')
-rw-r--r--cpp/.traces/convert_names_transforms_record_elements31
-rw-r--r--cpp/010vm5
-rw-r--r--cpp/018record2
-rw-r--r--cpp/020array1
-rw-r--r--cpp/025name48
5 files changed, 85 insertions, 2 deletions
diff --git a/cpp/.traces/convert_names_transforms_record_elements b/cpp/.traces/convert_names_transforms_record_elements
new file mode 100644
index 00000000..99c78e6a
--- /dev/null
+++ b/cpp/.traces/convert_names_transforms_record_elements
@@ -0,0 +1,31 @@
+parse/0: instruction: 18
+parse/0:   ingredient: {name: "0", value: 0, type: 4, properties: [0: point]}
+parse/0:   ingredient: {name: "y", value: 0, type: 0, properties: [y: offset]}
+parse/0:   product: {name: "a", value: 0, type: 1, properties: [a: integer]}
+parse/0: instruction: 18
+parse/0:   ingredient: {name: "0", value: 0, type: 4, properties: [0: point]}
+parse/0:   ingredient: {name: "x", value: 0, type: 0, properties: [x: offset]}
+parse/0:   product: {name: "b", value: 0, type: 1, properties: [b: integer]}
+name/0: field y of type point is at offset 1
+name/0: assign a 1
+name/0: field x of type point is at offset 0
+name/0: assign b 2
+after-brace/0: recipe main
+after-brace/0: get ...
+after-brace/0: get ...
+run/0: instruction main/0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is y
+run/0: address to copy is 1
+run/0: its type is 1
+mem/0: location 1 is 0
+run/0: product 0 is 0
+mem/0: storing in location 1
+run/0: instruction main/1
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is x
+run/0: address to copy is 0
+run/0: its type is 1
+mem/0: location 0 is 0
+run/0: product 0 is 0
+mem/0: storing in location 2
diff --git a/cpp/010vm b/cpp/010vm
index 45b4c3e5..d37dd83a 100644
--- a/cpp/010vm
+++ b/cpp/010vm
@@ -82,10 +82,13 @@ void setup_types() {
   // Mu Types Initialization.
   int integer = Type_number["integer"] = Next_type_number++;
   Type[integer].size = 1;
+  Type[integer].name = "integer";
   int address = Type_number["address"] = Next_type_number++;
   Type[address].size = 1;
+  Type[address].name = "address";
   int boolean = Type_number["boolean"] = Next_type_number++;
   Type[boolean].size = 1;
+  Type[boolean].name = "boolean";
   // End Mu Types Initialization.
 }
 :(before "End Setup")
@@ -99,10 +102,12 @@ void setup_types() {
 //  storing bank balance next to a person's name might require a record, and
 //  high scores in a game might need an array of numbers.
 struct type_info {
+  string name;
   size_t size;
   bool is_record;
   bool is_array;
   vector<vector<type_number> > elements;  // only if is_record
+  vector<string> element_names;  // only if is_record
   vector<type_number> element;  // only if is_array
   // End type_info Fields.
   type_info() :size(0), is_record(false), is_array(false) {}
diff --git a/cpp/018record b/cpp/018record
index 3a9b3c37..062f35cf 100644
--- a/cpp/018record
+++ b/cpp/018record
@@ -4,6 +4,7 @@
 int point = Type_number["point"] = Next_type_number++;
 Type[point].size = 2;
 Type[point].is_record = true;
+Type[point].name = "point";
 vector<type_number> i;
 i.push_back(integer);
 Type[point].elements.push_back(i);
@@ -77,6 +78,7 @@ recipe main [
 int point_integer = Type_number["point-integer"] = Next_type_number++;
 Type[point_integer].size = 2;
 Type[point_integer].is_record = true;
+Type[point_integer].name = "point-integer";
 vector<type_number> p2;
 p2.push_back(point);
 Type[point_integer].elements.push_back(p2);
diff --git a/cpp/020array b/cpp/020array
index 709fd65a..457ed366 100644
--- a/cpp/020array
+++ b/cpp/020array
@@ -4,6 +4,7 @@
 int integer_array = Type_number["integer-array"] = Next_type_number++;
 Type[integer_array].is_array = true;
 Type[integer_array].element.push_back(integer);
+Type[integer_array].name = "integer-array";
 
 //: Arrays can be copied around with a single instruction just like integers,
 //: no matter how large they are.
diff --git a/cpp/025name b/cpp/025name
index 606f4d2b..f226d8e6 100644
--- a/cpp/025name
+++ b/cpp/025name
@@ -28,7 +28,21 @@ void transform_names(const recipe_number r) {
   for (size_t i = 0; i < Recipe[r].steps.size(); ++i) {
 //?     cout << "instruction " << i << '\n'; //? 2
     instruction& inst = Recipe[r].steps[i];
-    // map names to addresses
+    // 1: replace element names of records with offsets
+    if (inst.operation == Recipe_number["get"]
+        || inst.operation == Recipe_number["get-address"]) {
+      // at least 2 args, and second arg is offset
+      assert(inst.ingredients.size() >= 2);
+      assert(!inst.ingredients[1].types.empty());
+      assert(inst.ingredients[1].types[0] == 0);
+      if (inst.ingredients[1].name.find_first_not_of("0123456789") == string::npos) continue;
+      // since first non-address in base type must be a record, we don't have to canonize
+      type_number record = skip_addresses(inst.ingredients[0].types);
+      inst.ingredients[1].value = find_element_name(record, inst.ingredients[1].name);
+      inst.ingredients[1].initialized = true;
+      trace("name") << "field " << inst.ingredients[1].name << " of type " << Type[record].name << " is at offset " << inst.ingredients[1].value;
+    }
+    // 2: map names to addresses
     for (size_t in = 0; in < inst.ingredients.size(); ++in) {
 //?       cout << "ingredient " << inst.ingredients[in].name << '\n'; //? 1
       if (inst.ingredients[in].name != "default_space"
@@ -42,7 +56,7 @@ void transform_names(const recipe_number r) {
         inst.ingredients[in].initialized = true;
       }
     }
-    // replace names with addresses
+    // 3: replace names with addresses
     for (size_t out = 0; out < inst.products.size(); ++out) {
 //?       cout << "product " << out << '/' << inst.products.size() << " " << inst.products[out].name << '\n'; //? 3
 //?       cout << inst.products[out].types[0] << '\n'; //? 1
@@ -62,6 +76,24 @@ void transform_names(const recipe_number r) {
   }
 }
 
+type_number skip_addresses(const vector<type_number>& types) {
+  for (size_t i = 0; i < types.size(); ++i) {
+    if (types[i] != Type_number["address"]) return types[i];
+  }
+  raise << "expected a record" << '\n' << die();
+  return -1;
+}
+
+int find_element_name(const type_number t, const string& name) {
+  const type_info& record = Type[t];
+//?   cout << "looking for field " << name << " in type " << record.name << " with " << record.element_names.size() << " fields\n"; //? 1
+  for (size_t i = 0; i < record.element_names.size(); ++i) {
+    if (record.element_names[i] == name) return i;
+  }
+  raise << "unknown element " << name << " in record " << t << '\n' << die();
+  return -1;
+}
+
 :(scenario "convert_names_passes_dummy")
 # _ is just a dummy result that never gets consumed
 recipe main [
@@ -77,3 +109,15 @@ recipe main [
 ]
 +name: assign x 1
 -name: assign default_space 1
+
+//: update our running example record for the next test
+:(before "End Mu Types Initialization")
+Type[point].element_names.push_back("x");
+Type[point].element_names.push_back("y");
+:(scenario "convert_names_transforms_record_elements")
+recipe main [
+  a:integer <- get 0:point, y:offset
+  b:integer <- get 0:point, x:offset
+]
++name: field y of type point is at offset 1
++name: field x of type point is at offset 0