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