about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-09-30 01:57:23 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-09-30 01:57:23 -0700
commit4e49b29e63b0d369b81318ac822dc06ce06786b5 (patch)
treed78b822660f33f40eea08c6747245fb729877073
parenta0d7a15594990974808cc613a4814d1f86471b5e (diff)
downloadmu-4e49b29e63b0d369b81318ac822dc06ce06786b5.tar.gz
2221
-rw-r--r--020run.cc1
-rw-r--r--021check_type_by_instruction.cc9
-rw-r--r--022arithmetic.cc3
-rw-r--r--023boolean.cc52
4 files changed, 46 insertions, 19 deletions
diff --git a/020run.cc b/020run.cc
index 910a1d2d..d1e405a7 100644
--- a/020run.cc
+++ b/020run.cc
@@ -91,7 +91,6 @@ void run_current_routine()
         cout << "not a primitive op: " << current_instruction().operation << '\n';
       }
     }
-    finish_instruction:
     if (SIZE(products) < SIZE(current_instruction().products)) {
       raise << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products! " << current_instruction().to_string() << end();
     }
diff --git a/021check_type_by_instruction.cc b/021check_type_by_instruction.cc
index 0ac5a530..b5fb8197 100644
--- a/021check_type_by_instruction.cc
+++ b/021check_type_by_instruction.cc
@@ -104,5 +104,12 @@ bool is_mu_number(reagent r) {
         || r.properties.at(0).second.at(0) == "literal";
   if (r.types.empty()) return false;
   if (r.types.at(0) == Type_ordinal["character"]) return true;  // permit arithmetic on unicode code points
-  return !r.types.empty() && r.types.at(0) == Type_ordinal["number"];
+  return r.types.at(0) == Type_ordinal["number"];
+}
+
+bool is_mu_scalar(reagent r) {
+  if (is_literal(r))
+    return r.properties.at(0).second.at(0) != "literal-string";
+  if (is_mu_array(r)) return false;
+  return size_of(r) == 1;
 }
diff --git a/022arithmetic.cc b/022arithmetic.cc
index 9eca7e11..66aefbc8 100644
--- a/022arithmetic.cc
+++ b/022arithmetic.cc
@@ -6,6 +6,7 @@ ADD,
 Recipe_ordinal["add"] = ADD;
 :(before "End Primitive Recipe Type Checks")
 case ADD: {
+  // primary goal of these checks is to forbid address arithmetic
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
       raise << Recipe[r].name << ": 'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
@@ -78,7 +79,7 @@ case SUBTRACT: {
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
-    if (is_raw(inst.ingredients.at(i))) continue;  // offsets in tests
+    if (is_raw(inst.ingredients.at(i))) continue;  // permit address offset computations in tests
     if (!is_mu_number(inst.ingredients.at(i))) {
       raise << Recipe[r].name << ": 'subtract' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
diff --git a/023boolean.cc b/023boolean.cc
index ead678cf..b0debe6b 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -4,16 +4,21 @@
 AND,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["and"] = AND;
+:(before "End Primitive Recipe Type Checks")
+case AND: {
+  for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
+    if (!is_mu_scalar(inst.ingredients.at(i))) {
+      raise << Recipe[r].name << ": 'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      goto finish_checking_instruction;
+    }
+  }
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case AND: {
   bool result = true;
-  for (long long int i = 0; i < SIZE(ingredients); ++i) {
-    if (!scalar(ingredients.at(i))) {
-      raise << current_recipe_name() << ": 'and' requires boolean ingredients, but got " << current_instruction().ingredients.at(i).original_string << '\n' << end();
-      goto finish_instruction;
-    }
+  for (long long int i = 0; i < SIZE(ingredients); ++i)
     result = result && ingredients.at(i).at(0);
-  }
   products.resize(1);
   products.at(0).push_back(result);
   break;
@@ -49,16 +54,21 @@ recipe main [
 OR,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["or"] = OR;
+:(before "End Primitive Recipe Type Checks")
+case OR: {
+  for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
+    if (!is_mu_scalar(inst.ingredients.at(i))) {
+      raise << Recipe[r].name << ": 'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      goto finish_checking_instruction;
+    }
+  }
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case OR: {
   bool result = false;
-  for (long long int i = 0; i < SIZE(ingredients); ++i) {
-    if (!scalar(ingredients.at(i))) {
-      raise << current_recipe_name() << ": 'or' requires boolean ingredients, but got " << current_instruction().ingredients.at(i).original_string << '\n' << end();
-      goto finish_instruction;
-    }
+  for (long long int i = 0; i < SIZE(ingredients); ++i)
     result = result || ingredients.at(i).at(0);
-  }
   products.resize(1);
   products.at(0).push_back(result);
   break;
@@ -94,14 +104,24 @@ recipe main [
 NOT,
 :(before "End Primitive Recipe Numbers")
 Recipe_ordinal["not"] = NOT;
+:(before "End Primitive Recipe Type Checks")
+case NOT: {
+  if (SIZE(inst.products) > SIZE(inst.ingredients)) {
+    raise << Recipe[r].name << ": 'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
+    break;
+  }
+  for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
+    if (!is_mu_scalar(inst.ingredients.at(i))) {
+      raise << Recipe[r].name << ": 'not' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      goto finish_checking_instruction;
+    }
+  }
+  break;
+}
 :(before "End Primitive Recipe Implementations")
 case NOT: {
   products.resize(SIZE(ingredients));
   for (long long int i = 0; i < SIZE(ingredients); ++i) {
-    if (!scalar(ingredients.at(i))) {
-      raise << current_recipe_name() << ": 'not' requires boolean ingredients, but got " << current_instruction().ingredients.at(i).original_string << '\n' << end();
-      goto finish_instruction;
-    }
     products.at(i).push_back(!ingredients.at(i).at(0));
   }
   break;