about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-10-01 13:43:32 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-10-01 13:43:32 -0700
commit900e6a0efe72ffb1fa4ab098689493f408a060a8 (patch)
treeec3e6eb3e7b66dc9f2ba95a5d7e5d7d5732e8aa5
parent4814bf94e75ffdcbd2a4093eb1ab67851980a37a (diff)
downloadmu-900e6a0efe72ffb1fa4ab098689493f408a060a8.tar.gz
2227 - offset-checking for containers
-rw-r--r--021check_instruction.cc1
-rw-r--r--030container.cc91
-rw-r--r--031address.cc8
-rw-r--r--edit/010-warnings.mu30
4 files changed, 88 insertions, 42 deletions
diff --git a/021check_instruction.cc b/021check_instruction.cc
index cb332e7d..32317348 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -7,7 +7,6 @@
 
 :(code)
 void check_instruction(const recipe_ordinal r) {
-  if (Trace_stream && trace_count("warn") > 0) return;
   map<string, vector<type_ordinal> > metadata;
   for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
     instruction& inst = Recipe[r].steps.at(i);
diff --git a/030container.cc b/030container.cc
index 142688eb..89ba58de 100644
--- a/030container.cc
+++ b/030container.cc
@@ -26,13 +26,13 @@ recipe main [
 +mem: storing 34 in location 3
 +mem: storing 35 in location 4
 
-//: trying to copy to a differently-sized destination will fail
+//: trying to copy to a differently-typed destination will fail
 :(scenario copy_checks_size)
 % Hide_warnings = true;
 recipe main [
   2:point <- copy 1:number
 ]
-+warn: main: size mismatch in storing to 2:point (2 vs 1) at '2:point <- copy 1:number'
++warn: main: can't copy 1:number to 2:point; types don't match
 
 :(before "End Mu Types Initialization")
 // A more complex container, containing another container as one of its
@@ -122,38 +122,50 @@ recipe main [
 GET,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["get"] = GET;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case GET: {
-  if (SIZE(ingredients) != 2) {
-    raise << maybe(current_recipe_name()) << "'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+  if (SIZE(inst.ingredients) != 2) {
+    raise << maybe(Recipe[r].name) << "'get' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    break;
+  }
+  reagent base = inst.ingredients.at(0);
+  // Update GET base in Check
+  if (base.types.empty() || Type[base.types.at(0)].kind != container) {
+    raise << maybe(Recipe[r].name) << "first ingredient of 'get' should be a container, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    break;
+  }
+  type_ordinal base_type = base.types.at(0);
+  reagent offset = inst.ingredients.at(1);
+  if (!is_literal(offset) || !is_mu_scalar(offset)) {
+    raise << maybe(Recipe[r].name) << "second ingredient of 'get' should have type 'offset', but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
+  if (is_integer(offset.name)) {  // later layers permit non-integer offsets
+    long long int offset_value = to_integer(offset.name);
+    if (offset_value < 0 || offset_value >= SIZE(Type[base_type].elements)) {
+      raise << maybe(Recipe[r].name) << "invalid offset " << offset_value << " for " << Type[base_type].name << '\n' << end();
+      break;
+    }
+  }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case GET: {
   reagent base = current_instruction().ingredients.at(0);
+  // Update GET base in Run
   long long int base_address = base.value;
   if (base_address == 0) {
     raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
-  if (base.types.empty() || Type[base.types.at(0)].kind != container) {
-    raise << current_recipe_name () << ": first ingredient of 'get' should be a container, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
-    break;
-  }
   type_ordinal base_type = base.types.at(0);
-  if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << maybe(current_recipe_name()) << "second ingredient of 'get' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
-    break;
-  }
-  assert(scalar(ingredients.at(1)));
   long long int offset = ingredients.at(1).at(0);
+  if (offset < 0 || offset >= SIZE(Type[base_type].elements)) break;
   long long int src = base_address;
   for (long long int i = 0; i < offset; ++i) {
     src += size_of(Type[base_type].elements.at(i));
   }
   trace(Primitive_recipe_depth, "run") << "address to copy is " << src << end();
-  if (offset < 0 || offset >= SIZE(Type[base_type].elements)) {
-    raise << maybe(current_recipe_name()) << "invalid offset " << offset << " for " << Type[base_type].name << '\n' << end();
-    break;
-  }
   type_ordinal src_type = Type[base_type].elements.at(offset).at(0);
   trace(Primitive_recipe_depth, "run") << "its type is " << Type[src_type].name << end();
   reagent tmp;
@@ -206,29 +218,44 @@ recipe main [
 GET_ADDRESS,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["get-address"] = GET_ADDRESS;
-:(before "End Primitive Recipe Implementations")
+:(before "End Primitive Recipe Checks")
 case GET_ADDRESS: {
-  reagent base = current_instruction().ingredients.at(0);
-  long long int base_address = base.value;
-  if (base_address == 0) {
-    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+  if (SIZE(inst.ingredients) != 2) {
+    raise << maybe(Recipe[r].name) << "'get-address' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
+  reagent base = inst.ingredients.at(0);
+  // Update GET_ADDRESS base in Check
   if (base.types.empty() || Type[base.types.at(0)].kind != container) {
-    raise << current_recipe_name () << ": first ingredient of 'get-address' should be a container, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "first ingredient of 'get-address' should be a container, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   type_ordinal base_type = base.types.at(0);
-  if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << maybe(current_recipe_name()) << "second ingredient of 'get-address' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+  reagent offset = inst.ingredients.at(1);
+  if (!is_literal(offset) || !is_mu_scalar(offset)) {
+    raise << maybe(Recipe[r].name) << "second ingredient of 'get' should have type 'offset', but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
-  assert(scalar(ingredients.at(1)));
-  long long int offset = ingredients.at(1).at(0);
-  if (offset < 0 || offset >= SIZE(Type[base_type].elements)) {
-    raise << "invalid offset " << offset << " for " << Type[base_type].name << '\n' << end();
+  if (is_integer(offset.name)) {  // later layers permit non-integer offsets
+    long long int offset_value = to_integer(offset.name);
+    if (offset_value < 0 || offset_value >= SIZE(Type[base_type].elements)) {
+      raise << maybe(Recipe[r].name) << "invalid offset " << offset_value << " for " << Type[base_type].name << '\n' << end();
+      break;
+    }
+  }
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case GET_ADDRESS: {
+  reagent base = current_instruction().ingredients.at(0);
+  // Update GET_ADDRESS base in Run
+  long long int base_address = base.value;
+  if (base_address == 0) {
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
+  type_ordinal base_type = base.types.at(0);
+  long long int offset = ingredients.at(1).at(0);
   long long int result = base_address;
   for (long long int i = 0; i < offset; ++i) {
     result += size_of(Type[base_type].elements.at(i));
@@ -247,7 +274,7 @@ recipe main [
   14:number <- copy 36
   get-address 12:point-number/raw, 2:offset  # point-number occupies 3 locations but has only 2 fields; out of bounds
 ]
-+warn: invalid offset 2 for point-number
++warn: main: invalid offset 2 for point-number
 
 :(scenario get_address_out_of_bounds_2)
 % Hide_warnings = true;
@@ -257,7 +284,7 @@ recipe main [
   14:number <- copy 36
   get-address 12:point-number/raw, -1:offset
 ]
-+warn: invalid offset -1 for point-number
++warn: main: invalid offset -1 for point-number
 
 //:: Allow containers to be defined in mu code.
 
diff --git a/031address.cc b/031address.cc
index c074fe76..b01bc036 100644
--- a/031address.cc
+++ b/031address.cc
@@ -139,7 +139,9 @@ recipe main [
 ]
 +mem: storing 34 in location 4
 
-:(after "reagent base = " following "case GET:")
+:(after "Update GET base in Check")
+if (!canonize_type(base)) break;
+:(after "Update GET base in Run")
 base = canonize(base);
 
 :(scenario get_address_indirect)
@@ -152,7 +154,9 @@ recipe main [
 ]
 +mem: storing 2 in location 4
 
-:(after "reagent base = " following "case GET_ADDRESS:")
+:(after "Update GET_ADDRESS base in Check")
+if (!canonize_type(base)) break;
+:(after "Update GET_ADDRESS base in Run")
 base = canonize(base);
 
 //:: abbreviation for '/lookup': a prefix '*'
diff --git a/edit/010-warnings.mu b/edit/010-warnings.mu
index 10f05325..2bdcead2 100644
--- a/edit/010-warnings.mu
+++ b/edit/010-warnings.mu
@@ -97,6 +97,8 @@ recipe foo [
     .  get 123:number, foo:offset                      ┊                                                 .
     .]                                                 ┊                                                 .
     .foo: unknown element foo in container number      ┊                                                 .
+    .foo: first ingredient of 'get' should be a contai↩┊                                                 .
+    .ner, but got 123:number                           ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -107,6 +109,8 @@ recipe foo [
     .                                                                                                    .
     .                                                                                                    .
     .foo: unknown element foo in container number                                                        .
+    .foo: first ingredient of 'get' should be a contai                                                   .
+    .ner, but got 123:number                                                                             .
     .                                                                                                    .
   ]
 ]
@@ -133,6 +137,7 @@ recipe foo [
     .  x <- copy 0                                     ┊                                                 .
     .]                                                 ┊                                                 .
     .foo: missing type for x in 'x <- copy 0'          ┊                                                 .
+    .foo: can't copy 0 to x; types don't match         ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -184,14 +189,15 @@ recipe foo [
     event-loop screen:address, console:address, 3:address:programming-environment-data
   ]
   screen-should-contain [
-    .                                                                                 run (F4)           .
-    .                                                  ┊                                                 .
+    .  errors found                                                                   run (F4)           .
+    .                                                  ┊foo                                              .
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .  x:address:point <- new point:type               ┊                                                x.
-    .  get x:address:point, 1:offset                   ┊foo                                              .
-    .]                                                 ┊foo: first ingredient of 'get' should be a conta↩.
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊iner, but got x:address:point                    .
-    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .  x:address:point <- new point:type               ┊                                                 .
+    .  get x:address:point, 1:offset                   ┊                                                 .
+    .]                                                 ┊                                                 .
+    .foo: first ingredient of 'get' should be a contai↩┊                                                 .
+    .ner, but got x:address:point                      ┊                                                 .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
 ]
@@ -223,6 +229,8 @@ recipe foo [
     .]                                                 ┊                                                 .
     .foo: expected ingredient 1 of 'get' to have type ↩┊                                                 .
     .'offset'; got x:number                            ┊                                                 .
+    .foo: second ingredient of 'get' should have type ↩┊                                                 .
+    .'offset', but got x:number                        ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -296,6 +304,8 @@ scenario run-instruction-and-print-warnings [
     .                                                  ┊                                                x.
     .                                                  ┊get 1234:number, foo:offset                      .
     .                                                  ┊unknown element foo in container number          .
+    .                                                  ┊first ingredient of 'get' should be a container,↩.
+    .                                                  ┊ but got 1234:number                             .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .                                                  ┊                                                 .
   ]
@@ -316,6 +326,8 @@ scenario run-instruction-and-print-warnings [
     .                                                                                                    .
     .                                                                                                    .
     .                                                   unknown element foo in container number          .
+    .                                                   first ingredient of 'get' should be a container, .
+    .                                                    but got 1234:number                             .
     .                                                                                                    .
   ]
   screen-should-contain-in-color 245/grey, [
@@ -325,6 +337,8 @@ scenario run-instruction-and-print-warnings [
     .                                                  ┊                                                x.
     .                                                  ┊                                                 .
     .                                                  ┊                                                 .
+    .                                                  ┊                                                ↩.
+    .                                                  ┊                                                 .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .                                                  ┊                                                 .
   ]
@@ -354,6 +368,8 @@ scenario run-instruction-and-print-warnings-only-once [
     .                                                  ┊                                                x.
     .                                                  ┊get 1234:number, foo:offset                      .
     .                                                  ┊unknown element foo in container number          .
+    .                                                  ┊first ingredient of 'get' should be a container,↩.
+    .                                                  ┊ but got 1234:number                             .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .                                                  ┊                                                 .
   ]