1 //: Arithmetic primitives
  2 
  3 :(before "End Primitive Recipe Declarations")
  4 ADD,
  5 :(before "End Primitive Recipe Numbers")
  6 put(Recipe_ordinal, "add", ADD);
  7 :(before "End Primitive Recipe Checks")
  8 case ADD: {
  9   // primary goal of these checks is to forbid address arithmetic
 10   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
 11     if (!is_mu_number(inst.ingredients.at(i))) {
 12       raise << maybe(get(Recipe, r).name) << "'add' requires number ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end();
 13       goto finish_checking_instruction;
 14     }
 15   }
 16   if (SIZE(inst.products) > 1) {
 17     raise << maybe(get(Recipe, r).name) << "'add' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
 18     break;
 19   }
 20   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
 21     raise << maybe(get(Recipe, r).name) << "'add' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
 22     break;
 23   }
 24   break;
 25 }
 26 :(before "End Primitive Recipe Implementations")
 27 case ADD: {
 28   double result = 0;
 29   for (int i = 0;  i < SIZE(ingredients);  ++i) {
 30     result += ingredients.at(i).at(0);
 31   }
 32   products.resize(1);
 33   products.at(0).push_back(result);
 34   break;
 35 }
 36 
 37 :(scenario add_literal)
 38 def main [
 39   1:num <- add 23, 34
 40 ]
 41 +mem: storing 57 in location 1
 42 
 43 :(scenario add)
 44 def main [
 45   1:num <- copy 23
 46   2:num <- copy 34
 47   3:num <- add 1:num, 2:num
 48 ]
 49 +mem: storing 57 in location 3
 50 
 51 :(scenario add_multiple)
 52 def main [
 53   1:num <- add 3, 4, 5
 54 ]
 55 +mem: storing 12 in location 1
 56 
 57 :(scenario add_checks_type)
 58 % Hide_errors = true;
 59 def main [
 60   1:num <- add 2:bool, 1
 61 ]
 62 +error: main: 'add' requires number ingredients, but got '2:bool'
 63 
 64 :(scenario add_checks_return_type)
 65 % Hide_errors = true;
 66 def main [
 67   1:address:num <- add 2, 2
 68 ]
 69 +error: main: 'add' should yield a number, but got '1:address:num'
 70 
 71 :(before "End Primitive Recipe Declarations")
 72 SUBTRACT,
 73 :(before "End Primitive Recipe Numbers")
 74 put(Recipe_ordinal, "subtract", SUBTRACT);
 75 :(before "End Primitive Recipe Checks")
 76 case SUBTRACT: {
 77   if (inst.ingredients.empty()) {
 78     raise << maybe(get(Recipe, r).name) << "'subtract' has no ingredients\n" << end();
 79     break;
 80   }
 81   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
 82     if (is_raw(inst.ingredients.at(i))) continue;  // permit address offset computations in tests
 83     if (!is_mu_number(inst.ingredients.at(i))) {
 84       raise << maybe(get(Recipe, r).name) << "'subtract' requires number ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end();
 85       goto finish_checking_instruction;
 86     }
 87   }
 88   if (SIZE(inst.products) > 1) {
 89     raise << maybe(get(Recipe, r).name) << "'subtract' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
 90     break;
 91   }
 92   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
 93     raise << maybe(get(Recipe, r).name) << "'subtract' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
 94     break;
 95   }
 96   break;
 97 }
 98 :(before "End Primitive Recipe Implementations")
 99 case SUBTRACT: {
100   double result = ingredients.at(0).at(0);
101   for (int i = 1;  i < SIZE(ingredients);  ++i)
102     result -= ingredients.at(i).at(0);
103   products.resize(1);
104   products.at(0).push_back(result);
105   break;
106 }
107 :(code)
108 bool is_raw(const reagent& r) {
109   return has_property(r, "raw");
110 }
111 
112 :(scenario subtract_literal)
113 def main [
114   1:num <- subtract 5, 2
115 ]
116 +mem: storing 3 in location 1
117 
118 :(scenario subtract)
119 def main [
120   1:num <- copy 23
121   2:num <- copy 34
122   3:num <- subtract 1:num, 2:num
123 ]
124 +mem: storing -11 in location 3
125 
126 :(scenario subtract_multiple)
127 def main [
128   1:num <- subtract 6, 3, 2
129 ]
130 +mem: storing 1 in location 1
131 
132 :(before "End Primitive Recipe Declarations")
133 MULTIPLY,
134 :(before "End Primitive Recipe Numbers")
135 put(Recipe_ordinal, "multiply", MULTIPLY);
136 :(before "End Primitive Recipe Checks")
137 case MULTIPLY: {
138   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
139     if (!is_mu_number(inst.ingredients.at(i))) {
140       raise << maybe(get(Recipe, r).name) << "'multiply' requires number ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end();
141       goto finish_checking_instruction;
142     }
143   }
144   if (SIZE(inst.products) > 1) {
145     raise << maybe(get(Recipe, r).name) << "'multiply' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
146     break;
147   }
148   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
149     raise << maybe(get(Recipe, r).name) << "'multiply' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
150     break;
151   }
152   break;
153 }
154 :(before "End Primitive Recipe Implementations")
155 case MULTIPLY: {
156   double result = 1;
157   for (int i = 0;  i < SIZE(ingredients);  ++i) {
158     result *= ingredients.at(i).at(0);
159   }
160   products.resize(1);
161   products.at(0).push_back(result);
162   break;
163 }
164 
165 :(scenario multiply_literal)
166 def main [
167   1:num <- multiply 2, 3
168 ]
169 +mem: storing 6 in location 1
170 
171 :(scenario multiply)
172 def main [
173   1:num <- copy 4
174   2:num <- copy 6
175   3:num <- multiply 1:num, 2:num
176 ]
177 +mem: storing 24 in location 3
178 
179 :(scenario multiply_multiple)
180 def main [
181   1:num <- multiply 2, 3, 4
182 ]
183 +mem: storing 24 in location 1
184 
185 :(before "End Primitive Recipe Declarations")
186 DIVIDE,
187 :(before "End Primitive Recipe Numbers")
188 put(Recipe_ordinal, "divide", DIVIDE);
189 :(before "End Primitive Recipe Checks")
190 case DIVIDE: {
191   if (inst.ingredients.empty()) {
192     raise << maybe(get(Recipe, r).name) << "'divide' has no ingredients\n" << end();
193     break;
194   }
195   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
196     if (!is_mu_number(inst.ingredients.at(i))) {
197       raise << maybe(get(Recipe, r).name) << "'divide' requires number ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end();
198       goto finish_checking_instruction;
199     }
200   }
201   if (SIZE(inst.products) > 1) {
202     raise << maybe(get(Recipe, r).name) << "'divide' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
203     break;
204   }
205   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
206     raise << maybe(get(Recipe, r).name) << "'divide' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
207     break;
208   }
209   break;
210 }
211 :(before "End Primitive Recipe Implementations")
212 case DIVIDE: {
213   double result = ingredients.at(0).at(0);
214   for (int i = 1;  i < SIZE(ingredients);  ++i)
215     result /= ingredients.at(i).at(0);
216   products.resize(1);
217   products.at(0).push_back(result);
218   break;
219 }
220 
221 :(scenario divide_literal)
222 def main [
223   1:num <- divide 8, 2
224 ]
225 +mem: storing 4 in location 1
226 
227 :(scenario divide)
228 def main [
229   1:num <- copy 27
230   2:num <- copy 3
231   3:num <- divide 1:num, 2:num
232 ]
233 +mem: storing 9 in location 3
234 
235 :(scenario divide_multiple)
236 def main [
237   1:num <- divide 12, 3, 2
238 ]
239 +mem: storing 2 in location 1
240 
241 //: Integer division
242 
243 :(before "End Primitive Recipe Declarations")
244 DIVIDE_WITH_REMAINDER,
245 :(before "End Primitive Recipe Numbers")
246 put(Recipe_ordinal, "divide-with-remainder", DIVIDE_WITH_REMAINDER);
247 :(before "End Primitive Recipe Checks")
248 case DIVIDE_WITH_REMAINDER: {
249   if (SIZE(inst.ingredients) != 2) {
250     raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
251     break;
252   }
253   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
254     raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
255     break;
256   }
257   if (SIZE(inst.products) > 2) {
258     raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' yields two products in '" << to_original_string(inst) << "'\n" << end();
259     break;
260   }
261   for (int i = 0;  i < SIZE(inst.products);  ++i) {
262     if (!is_dummy(inst.products.at(i)) && !is_mu_number(inst.products.at(i))) {
263       raise << maybe(get(Recipe, r).name) << "'divide-with-remainder' should yield a number, but got '" << inst.products.at(i).original_string << "'\n" << end();
264       goto finish_checking_instruction;
265     }
266   }
267   break;
268 }
269 :(before "End Primitive Recipe Implementations")
270 case DIVIDE_WITH_REMAINDER: {
271   products.resize(2);
272   // fractions will be dropped; very large numbers will overflow
273   long long int a = static_cast<long long int>(ingredients.at(0).at(0));
274   long long int b = static_cast<long long int>(ingredients.at(1).at(0));
275   if (b == 0) {
276     raise << maybe(current_recipe_name()) << "divide by zero in '" << to_original_string(current_instruction()) << "'\n" << end();
277     products.resize(2);
278     products.at(0).push_back(0);
279     products.at(1).push_back(0);
280     break;
281   }
282   long long int quotient = a / b;
283   long long int remainder = a % b;
284   products.at(0).push_back(static_cast<double>(quotient));
285   products.at(1).push_back(static_cast<double>(remainder));
286   break;
287 }
288 
289 :(scenario divide_with_remainder_literal)
290 def main [
291   1:num, 2:num <- divide-with-remainder 9, 2
292 ]
293 +mem: storing 4 in location 1
294 +mem: storing 1 in location 2
295 
296 :(scenario divide_with_remainder)
297 def main [
298   1:num <- copy 27
299   2:num <- copy 11
300   3:num, 4:num <- divide-with-remainder 1:num, 2:num
301 ]
302 +mem: storing 2 in location 3
303 +mem: storing 5 in location 4
304 
305 :(scenario divide_with_decimal_point)
306 def main [
307   1:num <- divide 5, 2
308 ]
309 +mem: storing 2.5 in location 1
310 
311 :(scenario divide_by_zero)
312 def main [
313   1:num <- divide 4, 0
314 ]
315 +mem: storing inf in location 1
316 
317 :(scenario divide_by_zero_2)
318 % Hide_errors = true;
319 def main [
320   1:num <- divide-with-remainder 4, 0
321 ]
322 # integer division can't return floating-point infinity
323 +error: main: divide by zero in '1:num <- divide-with-remainder 4, 0'
324 
325 //: Bitwise shifts
326 
327 :(before "End Primitive Recipe Declarations")
328 SHIFT_LEFT,
329 :(before "End Primitive Recipe Numbers")
330 put(Recipe_ordinal, "shift-left", SHIFT_LEFT);
331 :(before "End Primitive Recipe Checks")
332 case SHIFT_LEFT: {
333   if (SIZE(inst.ingredients) != 2) {
334     raise << maybe(get(Recipe, r).name) << "'shift-left' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
335     break;
336   }
337   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
338     raise << maybe(get(Recipe, r).name) << "'shift-left' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
339     break;
340   }
341   if (SIZE(inst.products) > 1) {
342     raise << maybe(get(Recipe, r).name) << "'shift-left' yields one product in '" << to_original_string(inst) << "'\n" << end();
343     break;
344   }
345   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
346     raise << maybe(get(Recipe, r).name) << "'shift-left' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
347     goto finish_checking_instruction;
348   }
349   break;
350 }
351 :(before "End Primitive Recipe Implementations")
352 case SHIFT_LEFT: {
353   // ingredients must be integers
354   int a = static_cast<int>(ingredients.at(0).at(0));
355   int b = static_cast<int>(ingredients.at(1).at(0));
356   products.resize(1);
357   if (b < 0) {
358     raise << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_original_string(current_instruction()) << "'\n" << end();
359     products.at(0).push_back(0);
360     break;
361   }
362   products.at(0).push_back(a<<b);
363   break;
364 }
365 
366 :(scenario shift_left_by_zero)
367 def main [
368   1:num <- shift-left 1, 0
369 ]
370 +mem: storing 1 in location 1
371 
372 :(scenario shift_left_1)
373 def main [
374   1:num <- shift-left 1, 4
375 ]
376 +mem: storing 16 in location 1
377 
378 :(scenario shift_left_2)
379 def main [
380   1:num <- shift-left 3, 2
381 ]
382 +mem: storing 12 in location 1
383 
384 :(scenario shift_left_by_negative)
385 % Hide_errors = true;
386 def main [
387   1:num <- shift-left 3, -1
388 ]
389 +error: main: second ingredient can't be negative in '1:num <- shift-left 3, -1'
390 
391 :(scenario shift_left_ignores_fractional_part)
392 def main [
393   1:num <- divide 3, 2
394   2:num <- shift-left 1:num, 1
395 ]
396 +mem: storing 2 in location 2
397 
398 :(before "End Primitive Recipe Declarations")
399 SHIFT_RIGHT,
400 :(before "End Primitive Recipe Numbers")
401 put(Recipe_ordinal, "shift-right", SHIFT_RIGHT);
402 :(before "End Primitive Recipe Checks")
403 case SHIFT_RIGHT: {
404   if (SIZE(inst.ingredients) != 2) {
405     raise << maybe(get(Recipe, r).name) << "'shift-right' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
406     break;
407   }
408   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
409     raise << maybe(get(Recipe, r).name) << "'shift-right' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
410     break;
411   }
412   if (SIZE(inst.products) > 1) {
413     raise << maybe(get(Recipe, r).name) << "'shift-right' yields one product in '" << to_original_string(inst) << "'\n" << end();
414     break;
415   }
416   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
417     raise << maybe(get(Recipe, r).name) << "'shift-right' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
418     goto finish_checking_instruction;
419   }
420   break;
421 }
422 :(before "End Primitive Recipe Implementations")
423 case SHIFT_RIGHT: {
424   // ingredients must be integers
425   int a = static_cast<int>(ingredients.at(0).at(0));
426   int b = static_cast<int>(ingredients.at(1).at(0));
427   products.resize(1);
428   if (b < 0) {
429     raise << maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_original_string(current_instruction()) << "'\n" << end();
430     products.at(0).push_back(0);
431     break;
432   }
433   products.at(0).push_back(a>>b);
434   break;
435 }
436 
437 :(scenario shift_right_by_zero)
438 def main [
439   1:num <- shift-right 1, 0
440 ]
441 +mem: storing 1 in location 1
442 
443 :(scenario shift_right_1)
444 def main [
445   1:num <- shift-right 1024, 1
446 ]
447 +mem: storing 512 in location 1
448 
449 :(scenario shift_right_2)
450 def main [
451   1:num <- shift-right 3, 1
452 ]
453 +mem: storing 1 in location 1
454 
455 :(scenario shift_right_by_negative)
456 % Hide_errors = true;
457 def main [
458   1:num <- shift-right 4, -1
459 ]
460 +error: main: second ingredient can't be negative in '1:num <- shift-right 4, -1'
461 
462 :(scenario shift_right_ignores_fractional_part)
463 def main [
464   1:num <- divide 3, 2
465   2:num <- shift-right 1:num, 1
466 ]
467 +mem: storing 0 in location 2
468 
469 :(before "End Primitive Recipe Declarations")
470 AND_BITS,
471 :(before "End Primitive Recipe Numbers")
472 put(Recipe_ordinal, "and-bits", AND_BITS);
473 :(before "End Primitive Recipe Checks")
474 case AND_BITS: {
475   if (SIZE(inst.ingredients) != 2) {
476     raise << maybe(get(Recipe, r).name) << "'and-bits' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
477     break;
478   }
479   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
480     raise << maybe(get(Recipe, r).name) << "'and-bits' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
481     break;
482   }
483   if (SIZE(inst.products) > 1) {
484     raise << maybe(get(Recipe, r).name) << "'and-bits' yields one product in '" << to_original_string(inst) << "'\n" << end();
485     break;
486   }
487   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
488     raise << maybe(get(Recipe, r).name) << "'and-bits' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
489     goto finish_checking_instruction;
490   }
491   break;
492 }
493 :(before "End Primitive Recipe Implementations")
494 case AND_BITS: {
495   // ingredients must be integers
496   int a = static_cast<int>(ingredients.at(0).at(0));
497   int b = static_cast<int>(ingredients.at(1).at(0));
498   products.resize(1);
499   products.at(0).push_back(a&b);
500   break;
501 }
502 
503 :(scenario and_bits_1)
504 def main [
505   1:num <- and-bits 8, 3
506 ]
507 +mem: storing 0 in location 1
508 
509 :(scenario and_bits_2)
510 def main [
511   1:num <- and-bits 3, 2
512 ]
513 +mem: storing 2 in location 1
514 
515 :(scenario and_bits_3)
516 def main [
517   1:num <- and-bits 14, 3
518 ]
519 +mem: storing 2 in location 1
520 
521 :(scenario and_bits_negative)
522 def main [
523   1:num <- and-bits -3, 4
524 ]
525 +mem: storing 4 in location 1
526 
527 :(before "End Primitive Recipe Declarations")
528 OR_BITS,
529 :(before "End Primitive Recipe Numbers")
530 put(Recipe_ordinal, "or-bits", OR_BITS);
531 :(before "End Primitive Recipe Checks")
532 case OR_BITS: {
533   if (SIZE(inst.ingredients) != 2) {
534     raise << maybe(get(Recipe, r).name) << "'or-bits' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
535     break;
536   }
537   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
538     raise << maybe(get(Recipe, r).name) << "'or-bits' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
539     break;
540   }
541   if (SIZE(inst.products) > 1) {
542     raise << maybe(get(Recipe, r).name) << "'or-bits' yields one product in '" << to_original_string(inst) << "'\n" << end();
543     break;
544   }
545   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
546     raise << maybe(get(Recipe, r).name) << "'or-bits' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
547     goto finish_checking_instruction;
548   }
549   break;
550 }
551 :(before "End Primitive Recipe Implementations")
552 case OR_BITS: {
553   // ingredients must be integers
554   int a = static_cast<int>(ingredients.at(0).at(0));
555   int b = static_cast<int>(ingredients.at(1).at(0));
556   products.resize(1);
557   products.at(0).push_back(a|b);
558   break;
559 }
560 
561 :(scenario or_bits_1)
562 def main [
563   1:num <- or-bits 3, 8
564 ]
565 +mem: storing 11 in location 1
566 
567 :(scenario or_bits_2)
568 def main [
569   1:num <- or-bits 3, 10
570 ]
571 +mem: storing 11 in location 1
572 
573 :(scenario or_bits_3)
574 def main [
575   1:num <- or-bits 4, 6
576 ]
577 +mem: storing 6 in location 1
578 
579 :(before "End Primitive Recipe Declarations")
580 XOR_BITS,
581 :(before "End Primitive Recipe Numbers")
582 put(Recipe_ordinal, "xor-bits", XOR_BITS);
583 :(before "End Primitive Recipe Checks")
584 case XOR_BITS: {
585   if (SIZE(inst.ingredients) != 2) {
586     raise << maybe(get(Recipe, r).name) << "'xor-bits' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end();
587     break;
588   }
589   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
590     raise << maybe(get(Recipe, r).name) << "'xor-bits' requires number ingredients, but got '" << to_original_string(inst) << "'\n" << end();
591     break;
592   }
593   if (SIZE(inst.products) > 1) {
594     raise << maybe(get(Recipe, r).name) << "'xor-bits' yields one product in '" << to_original_string(inst) << "'\n" << end();
595     break;
596   }
597   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
598     raise << maybe(get(Recipe, r).name) << "'xor-bits' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
599     goto finish_checking_instruction;
600   }
601   break;
602 }
603 :(before "End Primitive Recipe Implementations")
604 case XOR_BITS: {
605   // ingredients must be integers
606   int a = static_cast<int>(ingredients.at(0).at(0));
607   int b = static_cast<int>(ingredients.at(1).at(0));
608   products.resize(1);
609   products.at(0).push_back(a^b);
610   break;
611 }
612 
613 :(scenario xor_bits_1)
614 def main [
615   1:num <- xor-bits 3, 8
616 ]
617 +mem: storing 11 in location 1
618 
619 :(scenario xor_bits_2)
620 def main [
621   1:num <- xor-bits 3, 10
622 ]
623 +mem: storing 9 in location 1
624 
625 :(scenario xor_bits_3)
626 def main [
627   1:num <- xor-bits 4, 6
628 ]
629 +mem: storing 2 in location 1
630 
631 :(before "End Primitive Recipe Declarations")
632 FLIP_BITS,
633 :(before "End Primitive Recipe Numbers")
634 put(Recipe_ordinal, "flip-bits", FLIP_BITS);
635 :(before "End Primitive Recipe Checks")
636 case FLIP_BITS: {
637   if (SIZE(inst.ingredients) != 1) {
638     raise << maybe(get(Recipe, r).name) << "'flip-bits' requires exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
639     break;
640   }
641   if (!is_mu_number(inst.ingredients.at(0))) {
642     raise << maybe(get(Recipe, r).name) << "'flip-bits' requires a number ingredient, but got '" << to_original_string(inst) << "'\n" << end();
643     break;
644   }
645   if (SIZE(inst.products) > 1) {
646     raise << maybe(get(Recipe, r).name) << "'flip-bits' yields one product in '" << to_original_string(inst) << "'\n" << end();
647     break;
648   }
649   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
650     raise << maybe(get(Recipe, r).name) << "'flip-bits' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
651     goto finish_checking_instruction;
652   }
653   break;
654 }
655 :(before "End Primitive Recipe Implementations")
656 case FLIP_BITS: {
657   // ingredient must be integer
658   int a = static_cast<int>(ingredients.at(0).at(0));
659   products.resize(1);
660   products.at(0).push_back(~a);
661   break;
662 }
663 
664 :(scenario flip_bits_zero)
665 def main [
666   1:num <- flip-bits 0
667 ]
668 +mem: storing -1 in location 1
669 
670 :(scenario flip_bits_negative)
671 def main [
672   1:num <- flip-bits -1
673 ]
674 +mem: storing 0 in location 1
675 
676 :(scenario flip_bits_1)
677 def main [
678   1:num <- flip-bits 3
679 ]
680 +mem: storing -4 in location 1
681 
682 :(scenario flip_bits_2)
683 def main [
684   1:num <- flip-bits 12
685 ]
686 +mem: storing -13 in location 1
687 
688 :(before "End Primitive Recipe Declarations")
689 ROUND,
690 :(before "End Primitive Recipe Numbers")
691 put(Recipe_ordinal, "round", ROUND);
692 :(before "End Primitive Recipe Checks")
693 case ROUND: {
694   if (SIZE(inst.ingredients) != 1) {
695     raise << maybe(get(Recipe, r).name) << "'round' requires exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
696     break;
697   }
698   if (!is_mu_number(inst.ingredients.at(0))) {
699     raise << maybe(get(Recipe, r).name) << "first ingredient of 'round' should be a number, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
700     break;
701   }
702   break;
703 }
704 :(before "End Primitive Recipe Implementations")
705 case ROUND: {
706   products.resize(1);
707   products.at(0).push_back(rint(ingredients.at(0).at(0)));
708   break;
709 }
710 
711 :(scenario round_to_nearest_integer)
712 def main [
713   1:num <- round 12.2
714 ]
715 +mem: storing 12 in location 1
716 
717 :(scenario round_halves_toward_zero)
718 def main [
719   1:num <- round 12.5
720 ]
721 +mem: storing 12 in location 1
722 
723 :(scenario round_halves_toward_zero_2)
724 def main [
725   1:num <- round -12.5
726 ]
727 +mem: storing -12 in location 1
728 
729 :(before "End Primitive Recipe Declarations")
730 TRUNCATE,
731 :(before "End Primitive Recipe Numbers")
732 put(Recipe_ordinal, "truncate", TRUNCATE);
733 :(before "End Primitive Recipe Checks")
734 case TRUNCATE: {
735   if (SIZE(inst.ingredients) != 1) {
736     raise << maybe(get(Recipe, r).name) << "'truncate' requires exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
737     break;
738   }
739   if (!is_mu_number(inst.ingredients.at(0))) {
740     raise << maybe(get(Recipe, r).name) << "first ingredient of 'truncate' should be a number, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
741     break;
742   }
743   break;
744 }
745 :(before "End Primitive Recipe Implementations")
746 case TRUNCATE: {
747   products.resize(1);
748   products.at(0).push_back(trunc(ingredients.at(0).at(0)));
749   break;
750 }
751 
752 :(scenario truncate_to_nearest_integer)
753 def main [
754   1:num <- truncate 12.2
755 ]
756 +mem: storing 12 in location 1
757 
758 :(scenario truncate_negative)
759 def main [
760   1:num <- truncate -12.2
761 ]
762 +mem: storing -12 in location 1
763 
764 :(before "End Primitive Recipe Declarations")
765 SQUARE_ROOT,
766 :(before "End Primitive Recipe Numbers")
767 put(Recipe_ordinal, "square-root", SQUARE_ROOT);
768 :(before "End Primitive Recipe Checks")
769 case SQUARE_ROOT: {
770   if (SIZE(inst.ingredients) != 1) {
771     raise << maybe(get(Recipe, r).name) << "'square-root' requires exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
772     break;
773   }
774   if (!is_mu_number(inst.ingredients.at(0))) {
775     raise << maybe(get(Recipe, r).name) << "first ingredient of 'square-root' should be a number, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
776     break;
777   }
778   break;
779 }
780 :(before "End Primitive Recipe Implementations")
781 case SQUARE_ROOT: {
782   products.resize(1);
783   products.at(0).push_back(sqrt(ingredients.at(0).at(0)));
784   break;
785 }
786 
787 :(before "End Primitive Recipe Declarations")
788 CHARACTER_TO_CODE,
789 :(before "End Primitive Recipe Numbers")
790 put(Recipe_ordinal, "character-to-code", CHARACTER_TO_CODE);
791 :(before "End Primitive Recipe Checks")
792 case CHARACTER_TO_CODE: {
793   if (SIZE(inst.ingredients) != 1) {
794     raise << maybe(get(Recipe, r).name) << "'character-to-code' requires exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
795     break;
796   }
797   if (!is_mu_character(inst.ingredients.at(0))) {
798     raise << maybe(get(Recipe, r).name) << "first ingredient of 'character-to-code' should be a character, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
799     break;
800   }
801   if (SIZE(inst.products) != 1) {
802     raise << maybe(get(Recipe, r).name) << "'character-to-code' requires exactly one product, but got '" << to_original_string(inst) << "'\n" << end();
803     break;
804   }
805   if (!is_mu_number(inst.products.at(0))) {
806     raise << maybe(get(Recipe, r).name) << "first product of 'character-to-code' should be a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
807     break;
808   }
809   break;
810 }
811 :(before "End Primitive Recipe Implementations")
812 case CHARACTER_TO_CODE: {
813   double result = 0;
814   for (int i = 0;  i < SIZE(ingredients);  ++i) {
815     result += ingredients.at(i).at(0);
816   }
817   products.resize(1);
818   products.at(0).push_back(result);
819   break;
820 }
821 
822 :(before "End Includes")
823 #include <math.h>