1 //: Boolean primitives
  2 
  3 :(before "End Primitive Recipe Declarations")
  4 AND,
  5 :(before "End Primitive Recipe Numbers")
  6 put(Recipe_ordinal, "and", AND);
  7 :(before "End Primitive Recipe Checks")
  8 case AND: {
  9   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
 10     if (!is_mu_scalar(inst.ingredients.at(i))) {
 11       raise << maybe(get(Recipe, r).name) << "'and' requires boolean ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end();
 12       goto finish_checking_instruction;
 13     }
 14   }
 15   if (SIZE(inst.products) > 1) {
 16     raise << maybe(get(Recipe, r).name) << "'and' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
 17     break;
 18   }
 19   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
 20     raise << maybe(get(Recipe, r).name) << "'and' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
 21     break;
 22   }
 23   break;
 24 }
 25 :(before "End Primitive Recipe Implementations")
 26 case AND: {
 27   bool result = true;
 28   for (int i = 0;  i < SIZE(ingredients);  ++i)
 29     result = result && ingredients.at(i).at(0);
 30   products.resize(1);
 31   products.at(0).push_back(result);
 32   break;
 33 }
 34 
 35 :(scenario and)
 36 def main [
 37   1:bool <- copy 1
 38   2:bool <- copy 0
 39   3:bool <- and 1:bool, 2:bool
 40 ]
 41 +mem: storing 0 in location 3
 42 
 43 :(scenario and_2)
 44 def main [
 45   1:bool <- and 1, 1
 46 ]
 47 +mem: storing 1 in location 1
 48 
 49 :(scenario and_multiple)
 50 def main [
 51   1:bool <- and 1, 1, 0
 52 ]
 53 +mem: storing 0 in location 1
 54 
 55 :(scenario and_multiple_2)
 56 def main [
 57   1:bool <- and 1, 1, 1
 58 ]
 59 +mem: storing 1 in location 1
 60 
 61 :(before "End Primitive Recipe Declarations")
 62 OR,
 63 :(before "End Primitive Recipe Numbers")
 64 put(Recipe_ordinal, "or", OR);
 65 :(before "End Primitive Recipe Checks")
 66 case OR: {
 67   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
 68     if (!is_mu_scalar(inst.ingredients.at(i))) {
 69       raise << maybe(get(Recipe, r).name) << "'and' requires boolean ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end();
 70       goto finish_checking_instruction;
 71     }
 72   }
 73   if (SIZE(inst.products) > 1) {
 74     raise << maybe(get(Recipe, r).name) << "'or' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
 75     break;
 76   }
 77   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
 78     raise << maybe(get(Recipe, r).name) << "'or' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
 79     break;
 80   }
 81   break;
 82 }
 83 :(before "End Primitive Recipe Implementations")
 84 case OR: {
 85   bool result = false;
 86   for (int i = 0;  i < SIZE(ingredients);  ++i)
 87     result = result || ingredients.at(i).at(0);
 88   products.resize(1);
 89   products.at(0).push_back(result);
 90   break;
 91 }
 92 
 93 :(scenario or)
 94 def main [
 95   1:bool <- copy 1
 96   2:bool <- copy 0
 97   3:bool <- or 1:bool, 2:bool
 98 ]
 99 +mem: storing 1 in location 3
100 
101 :(scenario or_2)
102 def main [
103   1:bool <- or 0, 0
104 ]
105 +mem: storing 0 in location 1
106 
107 :(scenario or_multiple)
108 def main [
109   1:bool <- and 0, 0, 0
110 ]
111 +mem: storing 0 in location 1
112 
113 :(scenario or_multiple_2)
114 def main [
115   1:bool <- or 0, 0, 1
116 ]
117 +mem: storing 1 in location 1
118 
119 :(before "End Primitive Recipe Declarations")
120 NOT,
121 :(before "End Primitive Recipe Numbers")
122 put(Recipe_ordinal, "not", NOT);
123 :(before "End Primitive Recipe Checks")
124 case NOT: {
125   if (SIZE(inst.products) != SIZE(inst.ingredients)) {
126     raise << "ingredients and products should match in '" << to_original_string(inst) << "'\n" << end();
127     break;
128   }
129   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
130     if (!is_mu_scalar(inst.ingredients.at(i))) {
131       raise << maybe(get(Recipe, r).name) << "'not' requires boolean ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end();
132       goto finish_checking_instruction;
133     }
134   }
135   for (int i = 0;  i < SIZE(inst.products);  ++i) {
136     if (is_dummy(inst.products.at(i))) continue;
137     if (!is_mu_boolean(inst.products.at(i))) {
138       raise << maybe(get(Recipe, r).name) << "'not' should yield a boolean, but got '" << inst.products.at(i).original_string << "'\n" << end();
139       goto finish_checking_instruction;
140     }
141   }
142   break;
143 }
144 :(before "End Primitive Recipe Implementations")
145 case NOT: {
146   products.resize(SIZE(ingredients));
147   for (int i = 0;  i < SIZE(ingredients);  ++i) {
148     products.at(i).push_back(!ingredients.at(i).at(0));
149   }
150   break;
151 }
152 
153 :(scenario not)
154 def main [
155   1:bool <- copy 1
156   2:bool <- not 1:bool
157 ]
158 +mem: storing 0 in location 2
159 
160 :(scenario not_multiple)
161 def main [
162   1:bool, 2:bool, 3:bool <- not 1, 0, 1
163 ]
164 +mem: storing 0 in location 1
165 +mem: storing 1 in location 2
166 +mem: storing 0 in location 3