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>