https://github.com/akkartik/mu/blob/master/025compare.cc

      1 //: Comparison primitives
      2
      3 :(before "End Primitive Recipe Declarations")
      4 EQUAL,
      5 :(before "End Primitive Recipe Numbers")
      6 put(Recipe_ordinal, "equal", EQUAL);
      7 :(before "End Primitive Recipe Checks")
      8 case EQUAL: {
      9   if (SIZE(inst.ingredients) <= 1) {
     10     raise << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
     11     break;
     12   }
     13   const reagent& exemplar = inst.ingredients.at(0);
     14   for (int i = /*skip exemplar*/1;  i < SIZE(inst.ingredients);  ++i) {
     15     if (!types_match(inst.ingredients.at(i), exemplar) && !types_match(exemplar, inst.ingredients.at(i))) {
     16       raise << maybe(get(Recipe, r).name) << "'equal' expects ingredients to be all of the same type, but got '" << to_original_string(inst) << "'\n" << end();
     17       goto finish_checking_instruction;
     18     }
     19   }
     20   if (SIZE(inst.products) > 1) {
     21     raise << maybe(get(Recipe, r).name) << "'equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     22     break;
     23   }
     24   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
     25     raise << maybe(get(Recipe, r).name) << "'equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
     26     break;
     27   }
     28   break;
     29 }
     30 :(before "End Primitive Recipe Implementations")
     31 case EQUAL: {
     32   vector<double>& exemplar = ingredients.at(0);
     33   bool result = true;
     34   for (int i = /*skip exemplar*/1;  i < SIZE(ingredients);  ++i) {
     35     if (SIZE(ingredients.at(i)) != SIZE(exemplar)) {
     36       result = false;
     37       break;
     38     }
     39     if (!equal(ingredients.at(i).begin(), ingredients.at(i).end(), exemplar.begin())) {
     40       result = false;
     41       break;
     42     }
     43   }
     44   products.resize(1);
     45   products.at(0).push_back(result);
     46   break;
     47 }
     48
     49 :(scenario equal)
     50 def main [
     51   1:num <- copy 34
     52   2:num <- copy 33
     53   3:bool <- equal 1:num, 2:num
     54 ]
     55 +mem: location 1 is 34
     56 +mem: location 2 is 33
     57 +mem: storing 0 in location 3
     58
     59 :(scenario equal_2)
     60 def main [
     61   1:num <- copy 34
     62   2:num <- copy 34
     63   3:bool <- equal 1:num, 2:num
     64 ]
     65 +mem: location 1 is 34
     66 +mem: location 2 is 34
     67 +mem: storing 1 in location 3
     68
     69 :(scenario equal_multiple)
     70 def main [
     71   1:bool <- equal 34, 34, 34
     72 ]
     73 +mem: storing 1 in location 1
     74
     75 :(scenario equal_multiple_2)
     76 def main [
     77   1:bool <- equal 34, 34, 35
     78 ]
     79 +mem: storing 0 in location 1
     80
     81 :(before "End Primitive Recipe Declarations")
     82 NOT_EQUAL,
     83 :(before "End Primitive Recipe Numbers")
     84 put(Recipe_ordinal, "not-equal", NOT_EQUAL);
     85 :(before "End Primitive Recipe Checks")
     86 case NOT_EQUAL: {
     87   if (SIZE(inst.ingredients) != 2) {
     88     raise << maybe(get(Recipe, r).name) << "'equal' needs two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
     89     break;
     90   }
     91   const reagent& exemplar = inst.ingredients.at(0);
     92   if (!types_match(inst.ingredients.at(1), exemplar) && !types_match(exemplar, inst.ingredients.at(1))) {
     93     raise << maybe(get(Recipe, r).name) << "'equal' expects ingredients to be all of the same type, but got '" << to_original_string(inst) << "'\n" << end();
     94     goto finish_checking_instruction;
     95   }
     96   if (SIZE(inst.products) > 1) {
     97     raise << maybe(get(Recipe, r).name) << "'equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
     98     break;
     99   }
    100   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    101     raise << maybe(get(Recipe, r).name) << "'equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    102     break;
    103   }
    104   break;
    105 }
    106 :(before "End Primitive Recipe Implementations")
    107 case NOT_EQUAL: {
    108   vector<double>& exemplar = ingredients.at(0);
    109   products.resize(1);
    110   if (SIZE(ingredients.at(1)) != SIZE(exemplar)) {
    111     products.at(0).push_back(true);
    112     break;
    113   }
    114   bool equal_ingredients = equal(ingredients.at(1).begin(), ingredients.at(1).end(), exemplar.begin());
    115   products.at(0).push_back(!equal_ingredients);
    116   break;
    117 }
    118
    119 :(scenario not_equal)
    120 def main [
    121   1:num <- copy 34
    122   2:num <- copy 33
    123   3:bool <- not-equal 1:num, 2:num
    124 ]
    125 +mem: location 1 is 34
    126 +mem: location 2 is 33
    127 +mem: storing 1 in location 3
    128
    129 :(scenario not_equal_2)
    130 def main [
    131   1:num <- copy 34
    132   2:num <- copy 34
    133   3:bool <- not-equal 1:num, 2:num
    134 ]
    135 +mem: location 1 is 34
    136 +mem: location 2 is 34
    137 +mem: storing 0 in location 3
    138
    139 :(before "End Primitive Recipe Declarations")
    140 GREATER_THAN,
    141 :(before "End Primitive Recipe Numbers")
    142 put(Recipe_ordinal, "greater-than", GREATER_THAN);
    143 :(before "End Primitive Recipe Checks")
    144 case GREATER_THAN: {
    145   if (SIZE(inst.ingredients) <= 1) {
    146     raise << maybe(get(Recipe, r).name) << "'greater-than' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    147     break;
    148   }
    149   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    150     if (!is_mu_number(inst.ingredients.at(i))) {
    151       raise << maybe(get(Recipe, r).name) << "'greater-than' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
    152       goto finish_checking_instruction;
    153     }
    154   }
    155   if (SIZE(inst.products) > 1) {
    156     raise << maybe(get(Recipe, r).name) << "'greater-than' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    157     break;
    158   }
    159   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    160     raise << maybe(get(Recipe, r).name) << "'greater-than' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    161     break;
    162   }
    163   break;
    164 }
    165 :(before "End Primitive Recipe Implementations")
    166 case GREATER_THAN: {
    167   bool result = true;
    168   for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    169     if (ingredients.at(i-1).at(0) <= ingredients.at(i).at(0)) {
    170       result = false;
    171     }
    172   }
    173   products.resize(1);
    174   products.at(0).push_back(result);
    175   break;
    176 }
    177
    178 :(scenario greater_than)
    179 def main [
    180   1:num <- copy 34
    181   2:num <- copy 33
    182   3:bool <- greater-than 1:num, 2:num
    183 ]
    184 +mem: storing 1 in location 3
    185
    186 :(scenario greater_than_2)
    187 def main [
    188   1:num <- copy 34
    189   2:num <- copy 34
    190   3:bool <- greater-than 1:num, 2:num
    191 ]
    192 +mem: storing 0 in location 3
    193
    194 :(scenario greater_than_multiple)
    195 def main [
    196   1:bool <- greater-than 36, 35, 34
    197 ]
    198 +mem: storing 1 in location 1
    199
    200 :(scenario greater_than_multiple_2)
    201 def main [
    202   1:bool <- greater-than 36, 35, 35
    203 ]
    204 +mem: storing 0 in location 1
    205
    206 :(before "End Primitive Recipe Declarations")
    207 LESSER_THAN,
    208 :(before "End Primitive Recipe Numbers")
    209 put(Recipe_ordinal, "lesser-than", LESSER_THAN);
    210 :(before "End Primitive Recipe Checks")
    211 case LESSER_THAN: {
    212   if (SIZE(inst.ingredients) <= 1) {
    213     raise << maybe(get(Recipe, r).name) << "'lesser-than' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    214     break;
    215   }
    216   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    217     if (!is_mu_number(inst.ingredients.at(i))) {
    218       raise << maybe(get(Recipe, r).name) << "'lesser-than' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
    219       goto finish_checking_instruction;
    220     }
    221   }
    222   if (SIZE(inst.products) > 1) {
    223     raise << maybe(get(Recipe, r).name) << "'lesser-than' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    224     break;
    225   }
    226   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    227     raise << maybe(get(Recipe, r).name) << "'lesser-than' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    228     break;
    229   }
    230   break;
    231 }
    232 :(before "End Primitive Recipe Implementations")
    233 case LESSER_THAN: {
    234   bool result = true;
    235   for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    236     if (ingredients.at(i-1).at(0) >= ingredients.at(i).at(0)) {
    237       result = false;
    238     }
    239   }
    240   products.resize(1);
    241   products.at(0).push_back(result);
    242   break;
    243 }
    244
    245 :(scenario lesser_than)
    246 def main [
    247   1:num <- copy 32
    248   2:num <- copy 33
    249   3:bool <- lesser-than 1:num, 2:num
    250 ]
    251 +mem: storing 1 in location 3
    252
    253 :(scenario lesser_than_2)
    254 def main [
    255   1:num <- copy 34
    256   2:num <- copy 33
    257   3:bool <- lesser-than 1:num, 2:num
    258 ]
    259 +mem: storing 0 in location 3
    260
    261 :(scenario lesser_than_multiple)
    262 def main [
    263   1:bool <- lesser-than 34, 35, 36
    264 ]
    265 +mem: storing 1 in location 1
    266
    267 :(scenario lesser_than_multiple_2)
    268 def main [
    269   1:bool <- lesser-than 34, 35, 35
    270 ]
    271 +mem: storing 0 in location 1
    272
    273 :(before "End Primitive Recipe Declarations")
    274 GREATER_OR_EQUAL,
    275 :(before "End Primitive Recipe Numbers")
    276 put(Recipe_ordinal, "greater-or-equal", GREATER_OR_EQUAL);
    277 :(before "End Primitive Recipe Checks")
    278 case GREATER_OR_EQUAL: {
    279   if (SIZE(inst.ingredients) <= 1) {
    280     raise << maybe(get(Recipe, r).name) << "'greater-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    281     break;
    282   }
    283   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    284     if (!is_mu_number(inst.ingredients.at(i))) {
    285       raise << maybe(get(Recipe, r).name) << "'greater-or-equal' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
    286       goto finish_checking_instruction;
    287     }
    288   }
    289   if (SIZE(inst.products) > 1) {
    290     raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    291     break;
    292   }
    293   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    294     raise << maybe(get(Recipe, r).name) << "'greater-or-equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    295     break;
    296   }
    297   break;
    298 }
    299 :(before "End Primitive Recipe Implementations")
    300 case GREATER_OR_EQUAL: {
    301   bool result = true;
    302   for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    303     if (ingredients.at(i-1).at(0) < ingredients.at(i).at(0)) {
    304       result = false;
    305     }
    306   }
    307   products.resize(1);
    308   products.at(0).push_back(result);
    309   break;
    310 }
    311
    312 :(scenario greater_or_equal)
    313 def main [
    314   1:num <- copy 34
    315   2:num <- copy 33
    316   3:bool <- greater-or-equal 1:num, 2:num
    317 ]
    318 +mem: storing 1 in location 3
    319
    320 :(scenario greater_or_equal_2)
    321 def main [
    322   1:num <- copy 34
    323   2:num <- copy 34
    324   3:bool <- greater-or-equal 1:num, 2:num
    325 ]
    326 +mem: storing 1 in location 3
    327
    328 :(scenario greater_or_equal_3)
    329 def main [
    330   1:num <- copy 34
    331   2:num <- copy 35
    332   3:bool <- greater-or-equal 1:num, 2:num
    333 ]
    334 +mem: storing 0 in location 3
    335
    336 :(scenario greater_or_equal_multiple)
    337 def main [
    338   1:bool <- greater-or-equal 36, 35, 35
    339 ]
    340 +mem: storing 1 in location 1
    341
    342 :(scenario greater_or_equal_multiple_2)
    343 def main [
    344   1:bool <- greater-or-equal 36, 35, 36
    345 ]
    346 +mem: storing 0 in location 1
    347
    348 :(before "End Primitive Recipe Declarations")
    349 LESSER_OR_EQUAL,
    350 :(before "End Primitive Recipe Numbers")
    351 put(Recipe_ordinal, "lesser-or-equal", LESSER_OR_EQUAL);
    352 :(before "End Primitive Recipe Checks")
    353 case LESSER_OR_EQUAL: {
    354   if (SIZE(inst.ingredients) <= 1) {
    355     raise << maybe(get(Recipe, r).name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    356     break;
    357   }
    358   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    359     if (!is_mu_number(inst.ingredients.at(i))) {
    360       raise << maybe(get(Recipe, r).name) << "'lesser-or-equal' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
    361       goto finish_checking_instruction;
    362     }
    363   }
    364   if (SIZE(inst.products) > 1) {
    365     raise << maybe(get(Recipe, r).name) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    366     break;
    367   }
    368   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_boolean(inst.products.at(0))) {
    369     raise << maybe(get(Recipe, r).name) << "'greater-or-equal' should yield a boolean, but got '" << inst.products.at(0).original_string << "'\n" << end();
    370     break;
    371   }
    372   break;
    373 }
    374 :(before "End Primitive Recipe Implementations")
    375 case LESSER_OR_EQUAL: {
    376   bool result = true;
    377   for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    378     if (ingredients.at(i-1).at(0) > ingredients.at(i).at(0)) {
    379       result = false;
    380     }
    381   }
    382   products.resize(1);
    383   products.at(0).push_back(result);
    384   break;
    385 }
    386
    387 :(scenario lesser_or_equal)
    388 def main [
    389   1:num <- copy 32
    390   2:num <- copy 33
    391   3:bool <- lesser-or-equal 1:num, 2:num
    392 ]
    393 +mem: storing 1 in location 3
    394
    395 :(scenario lesser_or_equal_2)
    396 def main [
    397   1:num <- copy 33
    398   2:num <- copy 33
    399   3:bool <- lesser-or-equal 1:num, 2:num
    400 ]
    401 +mem: storing 1 in location 3
    402
    403 :(scenario lesser_or_equal_3)
    404 def main [
    405   1:num <- copy 34
    406   2:num <- copy 33
    407   3:bool <- lesser-or-equal 1:num, 2:num
    408 ]
    409 +mem: storing 0 in location 3
    410
    411 :(scenario lesser_or_equal_multiple)
    412 def main [
    413   1:bool <- lesser-or-equal 34, 35, 35
    414 ]
    415 +mem: storing 1 in location 1
    416
    417 :(scenario lesser_or_equal_multiple_2)
    418 def main [
    419   1:bool <- lesser-or-equal 34, 35, 34
    420 ]
    421 +mem: storing 0 in location 1
    422
    423 :(before "End Primitive Recipe Declarations")
    424 MAX,
    425 :(before "End Primitive Recipe Numbers")
    426 put(Recipe_ordinal, "max", MAX);
    427 :(before "End Primitive Recipe Checks")
    428 case MAX: {
    429   if (SIZE(inst.ingredients) <= 1) {
    430     raise << maybe(get(Recipe, r).name) << "'max' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    431     break;
    432   }
    433   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    434     if (!is_mu_number(inst.ingredients.at(i))) {
    435       raise << maybe(get(Recipe, r).name) << "'max' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
    436       goto finish_checking_instruction;
    437     }
    438   }
    439   if (SIZE(inst.products) > 1) {
    440     raise << maybe(get(Recipe, r).name) << "'max' yields exactly one product in '" << to_original_string(inst) << "'\n" << end();
    441     break;
    442   }
    443   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
    444     raise << maybe(get(Recipe, r).name) << "'max' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
    445     break;
    446   }
    447   break;
    448 }
    449 :(before "End Primitive Recipe Implementations")
    450 case MAX: {
    451   int result = ingredients.at(0).at(0);
    452   for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    453     if (ingredients.at(i).at(0) > result) {
    454       result = ingredients.at(i).at(0);
    455     }
    456   }
    457   products.resize(1);
    458   products.at(0).push_back(result);
    459   break;
    460 }
    461
    462 :(before "End Primitive Recipe Declarations")
    463 MIN,
    464 :(before "End Primitive Recipe Numbers")
    465 put(Recipe_ordinal, "min", MIN);
    466 :(before "End Primitive Recipe Checks")
    467 case MIN: {
    468   if (SIZE(inst.ingredients) <= 1) {
    469     raise << maybe(get(Recipe, r).name) << "'min' needs at least two ingredients to compare in '" << to_original_string(inst) << "'\n" << end();
    470     break;
    471   }
    472   for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
    473     if (!is_mu_number(inst.ingredients.at(i))) {
    474       raise << maybe(get(Recipe, r).name) << "'min' can only compare numbers; got '" << inst.ingredients.at(i).original_string << "'\n" << end();
    475       goto finish_checking_instruction;
    476     }
    477   }
    478   if (SIZE(inst.products) > 1) {
    479     raise << maybe(get(Recipe, r).name) << "'min' yields exactly 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) << "'min' should yield a number, but got '" << inst.products.at(0).original_string << "'\n" << end();
    484     break;
    485   }
    486   break;
    487 }
    488 :(before "End Primitive Recipe Implementations")
    489 case MIN: {
    490   int result = ingredients.at(0).at(0);
    491   for (int i = /**/1;  i < SIZE(ingredients);  ++i) {
    492     if (ingredients.at(i).at(0) < result) {
    493       result = ingredients.at(i).at(0);
    494     }
    495   }
    496   products.resize(1);
    497   products.at(0).push_back(result);
    498   break;
    499 }