about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-02-26 13:27:23 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-02-26 13:27:23 -0800
commitbff0fa450814fcadc4b35e3e740e8d9ee6370d11 (patch)
treef996ec84ec64e4e5305bb84f8b1160620a18ccf7
parent1b76245c6326c1d60494e102ed0141c7927a640f (diff)
downloadmu-bff0fa450814fcadc4b35e3e740e8d9ee6370d11.tar.gz
2713 - require booleans for boolean operations
Thanks Ella Couch for finding this bug. It's helped me find errors in
mu's code itself.
-rw-r--r--023boolean.cc23
-rw-r--r--025compare.cc48
-rw-r--r--031address.cc2
-rw-r--r--077hash.cc2
4 files changed, 70 insertions, 5 deletions
diff --git a/023boolean.cc b/023boolean.cc
index 40ce068e..558421a5 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -12,6 +12,14 @@ case AND: {
       goto finish_checking_instruction;
     }
   }
+  if (SIZE(inst.products) > 1) {
+    raise << maybe(get(Recipe, r).name) << "'and' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    break;
+  }
+  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "'and' should yield a boolean, but got " << inst.products.at(0).original_string << '\n' << end();
+    break;
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
@@ -62,6 +70,14 @@ case OR: {
       goto finish_checking_instruction;
     }
   }
+  if (SIZE(inst.products) > 1) {
+    raise << maybe(get(Recipe, r).name) << "'or' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    break;
+  }
+  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "'or' should yield a boolean, but got " << inst.products.at(0).original_string << '\n' << end();
+    break;
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
@@ -116,6 +132,13 @@ case NOT: {
       goto finish_checking_instruction;
     }
   }
+  for (long long int i = 0; i < SIZE(inst.products); ++i) {
+    if (is_dummy(inst.products.at(i))) continue;
+    if (!is_mu_boolean(inst.products.at(i))) {
+      raise << maybe(get(Recipe, r).name) << "'not' should yield a boolean, but got " << inst.products.at(i).original_string << '\n' << end();
+      goto finish_checking_instruction;
+    }
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
diff --git a/025compare.cc b/025compare.cc
index 59eb55b1..509e27fe 100644
--- a/025compare.cc
+++ b/025compare.cc
@@ -10,6 +10,14 @@ case EQUAL: {
     raise << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << to_string(inst) << "'\n" << end();
     break;
   }
+  if (SIZE(inst.products) > 1) {
+    raise << maybe(get(Recipe, r).name) << "'equal' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    break;
+  }
+  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "'equal' should yield a boolean, but got " << inst.products.at(0).original_string << '\n' << end();
+    break;
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
@@ -31,7 +39,7 @@ case EQUAL: {
 recipe main [
   1:number <- copy 34
   2:number <- copy 33
-  3:number <- equal 1:number, 2:number
+  3:boolean <- equal 1:number, 2:number
 ]
 +mem: location 1 is 34
 +mem: location 2 is 33
@@ -41,7 +49,7 @@ recipe main [
 recipe main [
   1:number <- copy 34
   2:number <- copy 34
-  3:number <- equal 1:number, 2:number
+  3:boolean <- equal 1:number, 2:number
 ]
 +mem: location 1 is 34
 +mem: location 2 is 34
@@ -49,13 +57,13 @@ recipe main [
 
 :(scenario equal_multiple)
 recipe main [
-  1:number <- equal 34, 34, 34
+  1:boolean <- equal 34, 34, 34
 ]
 +mem: storing 1 in location 1
 
 :(scenario equal_multiple_2)
 recipe main [
-  1:number <- equal 34, 34, 35
+  1:boolean <- equal 34, 34, 35
 ]
 +mem: storing 0 in location 1
 
@@ -75,6 +83,14 @@ case GREATER_THAN: {
       goto finish_checking_instruction;
     }
   }
+  if (SIZE(inst.products) > 1) {
+    raise << maybe(get(Recipe, r).name) << "'greater-than' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    break;
+  }
+  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "'greater-than' should yield a boolean, but got " << inst.products.at(0).original_string << '\n' << end();
+    break;
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
@@ -134,6 +150,14 @@ case LESSER_THAN: {
       goto finish_checking_instruction;
     }
   }
+  if (SIZE(inst.products) > 1) {
+    raise << maybe(get(Recipe, r).name) << "'lesser-than' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    break;
+  }
+  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "'lesser-than' should yield a boolean, but got " << inst.products.at(0).original_string << '\n' << end();
+    break;
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
@@ -193,6 +217,14 @@ case GREATER_OR_EQUAL: {
       goto finish_checking_instruction;
     }
   }
+  if (SIZE(inst.products) > 1) {
+    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    break;
+  }
+  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' should yield a boolean, but got " << inst.products.at(0).original_string << '\n' << end();
+    break;
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
@@ -260,6 +292,14 @@ case LESSER_OR_EQUAL: {
       goto finish_checking_instruction;
     }
   }
+  if (SIZE(inst.products) > 1) {
+    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_string(inst) << "'\n" << end();
+    break;
+  }
+  if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
+    raise << maybe(get(Recipe, r).name) << "'greater-or-equal' should yield a boolean, but got " << inst.products.at(0).original_string << '\n' << end();
+    break;
+  }
   break;
 }
 :(before "End Primitive Recipe Implementations")
diff --git a/031address.cc b/031address.cc
index 0d3f79f6..0577422d 100644
--- a/031address.cc
+++ b/031address.cc
@@ -83,6 +83,8 @@ recipe foo [
 
 :(after "bool is_mu_number(reagent r)")
   if (!canonize_type(r)) return false;
+:(after "bool is_mu_boolean(reagent r)")
+  if (!canonize_type(r)) return false;
 
 :(after "Update product While Type-checking Merge")
 if (!canonize_type(product)) continue;
diff --git a/077hash.cc b/077hash.cc
index 23f31ad0..682232dd 100644
--- a/077hash.cc
+++ b/077hash.cc
@@ -351,7 +351,7 @@ recipe main [
   1:address:shared:array:character <- new [abc]
   2:number <- hash 1:address:shared:array:character
   3:number <- hash_old 1:address:shared:array:character
-  4:number <- equal 2:number, 3:number
+  4:boolean <- equal 2:number, 3:number
 ]
 +mem: storing 1 in location 4