1 //: Comparison primitives
3 :(before
"End Primitive Recipe Declarations")
5 :(before
"End Primitive Recipe Numbers")
6 put(Recipe_ordinal
, "equal", EQUAL
);
7 :(before
"End Primitive Recipe Checks")
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();
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
;
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();
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();
30 :(before
"End Primitive Recipe Implementations")
32 vector
<double>& exemplar
= ingredients
.at(0);
34 for (int i
= /*skip exemplar*/1; i
< SIZE(ingredients
); ++i
) {
35 if (SIZE(ingredients
.at(i
)) != SIZE(exemplar
)) {
39 if (!equal(ingredients
.at(i
).begin(), ingredients
.at(i
).end(), exemplar
.begin())) {
45 products
.at(0).push_back(result
);
55 " 3:bool <- equal 1:num, 2:num\n"
59 "mem: location 1 is 34\n"
60 "mem: location 2 is 33\n"
61 "mem: storing 0 in location 3\n"
70 " 3:bool <- equal 1:num, 2:num\n"
74 "mem: location 1 is 34\n"
75 "mem: location 2 is 34\n"
76 "mem: storing 1 in location 3\n"
80 void test_equal_multiple() {
83 " 1:bool <- equal 34, 34, 34\n"
87 "mem: storing 1 in location 1\n"
91 void test_equal_multiple_2() {
94 " 1:bool <- equal 34, 34, 35\n"
98 "mem: storing 0 in location 1\n"
102 :(before
"End Primitive Recipe Declarations")
104 :(before
"End Primitive Recipe Numbers")
105 put(Recipe_ordinal
, "not-equal", NOT_EQUAL
);
106 :(before
"End Primitive Recipe Checks")
108 if (SIZE(inst
.ingredients
) != 2) {
109 raise
<< maybe(get(Recipe
, r
).name
) << "'equal' needs two ingredients to compare in '" << to_original_string(inst
) << "'\n" << end();
112 const reagent
& exemplar
= inst
.ingredients
.at(0);
113 if (!types_match(inst
.ingredients
.at(1), exemplar
) && !types_match(exemplar
, inst
.ingredients
.at(1))) {
114 raise
<< maybe(get(Recipe
, r
).name
) << "'equal' expects ingredients to be all of the same type, but got '" << to_original_string(inst
) << "'\n" << end();
115 goto finish_checking_instruction
;
117 if (SIZE(inst
.products
) > 1) {
118 raise
<< maybe(get(Recipe
, r
).name
) << "'equal' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
121 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_boolean(inst
.products
.at(0))) {
122 raise
<< maybe(get(Recipe
, r
).name
) << "'equal' should yield a boolean, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
127 :(before
"End Primitive Recipe Implementations")
129 vector
<double>& exemplar
= ingredients
.at(0);
131 if (SIZE(ingredients
.at(1)) != SIZE(exemplar
)) {
132 products
.at(0).push_back(true);
135 bool equal_ingredients
= equal(ingredients
.at(1).begin(), ingredients
.at(1).end(), exemplar
.begin());
136 products
.at(0).push_back(!equal_ingredients
);
141 void test_not_equal() {
144 " 1:num <- copy 34\n"
145 " 2:num <- copy 33\n"
146 " 3:bool <- not-equal 1:num, 2:num\n"
149 CHECK_TRACE_CONTENTS(
150 "mem: location 1 is 34\n"
151 "mem: location 2 is 33\n"
152 "mem: storing 1 in location 3\n"
156 void test_not_equal_2() {
159 " 1:num <- copy 34\n"
160 " 2:num <- copy 34\n"
161 " 3:bool <- not-equal 1:num, 2:num\n"
164 CHECK_TRACE_CONTENTS(
165 "mem: location 1 is 34\n"
166 "mem: location 2 is 34\n"
167 "mem: storing 0 in location 3\n"
171 :(before
"End Primitive Recipe Declarations")
173 :(before
"End Primitive Recipe Numbers")
174 put(Recipe_ordinal
, "greater-than", GREATER_THAN
);
175 :(before
"End Primitive Recipe Checks")
177 if (SIZE(inst
.ingredients
) <= 1) {
178 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-than' needs at least two ingredients to compare in '" << to_original_string(inst
) << "'\n" << end();
181 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
182 if (!is_mu_number(inst
.ingredients
.at(i
))) {
183 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-than' can only compare numbers; got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
184 goto finish_checking_instruction
;
187 if (SIZE(inst
.products
) > 1) {
188 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-than' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
191 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_boolean(inst
.products
.at(0))) {
192 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-than' should yield a boolean, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
197 :(before
"End Primitive Recipe Implementations")
200 for (int i
= /**/1; i
< SIZE(ingredients
); ++i
) {
201 if (ingredients
.at(i
-1).at(0) <= ingredients
.at(i
).at(0)) {
206 products
.at(0).push_back(result
);
211 void test_greater_than() {
214 " 1:num <- copy 34\n"
215 " 2:num <- copy 33\n"
216 " 3:bool <- greater-than 1:num, 2:num\n"
219 CHECK_TRACE_CONTENTS(
220 "mem: storing 1 in location 3\n"
224 void test_greater_than_2() {
227 " 1:num <- copy 34\n"
228 " 2:num <- copy 34\n"
229 " 3:bool <- greater-than 1:num, 2:num\n"
232 CHECK_TRACE_CONTENTS(
233 "mem: storing 0 in location 3\n"
237 void test_greater_than_multiple() {
240 " 1:bool <- greater-than 36, 35, 34\n"
243 CHECK_TRACE_CONTENTS(
244 "mem: storing 1 in location 1\n"
248 void test_greater_than_multiple_2() {
251 " 1:bool <- greater-than 36, 35, 35\n"
254 CHECK_TRACE_CONTENTS(
255 "mem: storing 0 in location 1\n"
259 :(before
"End Primitive Recipe Declarations")
261 :(before
"End Primitive Recipe Numbers")
262 put(Recipe_ordinal
, "lesser-than", LESSER_THAN
);
263 :(before
"End Primitive Recipe Checks")
265 if (SIZE(inst
.ingredients
) <= 1) {
266 raise
<< maybe(get(Recipe
, r
).name
) << "'lesser-than' needs at least two ingredients to compare in '" << to_original_string(inst
) << "'\n" << end();
269 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
270 if (!is_mu_number(inst
.ingredients
.at(i
))) {
271 raise
<< maybe(get(Recipe
, r
).name
) << "'lesser-than' can only compare numbers; got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
272 goto finish_checking_instruction
;
275 if (SIZE(inst
.products
) > 1) {
276 raise
<< maybe(get(Recipe
, r
).name
) << "'lesser-than' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
279 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_boolean(inst
.products
.at(0))) {
280 raise
<< maybe(get(Recipe
, r
).name
) << "'lesser-than' should yield a boolean, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
285 :(before
"End Primitive Recipe Implementations")
288 for (int i
= /**/1; i
< SIZE(ingredients
); ++i
) {
289 if (ingredients
.at(i
-1).at(0) >= ingredients
.at(i
).at(0)) {
294 products
.at(0).push_back(result
);
299 void test_lesser_than() {
302 " 1:num <- copy 32\n"
303 " 2:num <- copy 33\n"
304 " 3:bool <- lesser-than 1:num, 2:num\n"
307 CHECK_TRACE_CONTENTS(
308 "mem: storing 1 in location 3\n"
312 void test_lesser_than_2() {
315 " 1:num <- copy 34\n"
316 " 2:num <- copy 33\n"
317 " 3:bool <- lesser-than 1:num, 2:num\n"
320 CHECK_TRACE_CONTENTS(
321 "mem: storing 0 in location 3\n"
325 void test_lesser_than_multiple() {
328 " 1:bool <- lesser-than 34, 35, 36\n"
331 CHECK_TRACE_CONTENTS(
332 "mem: storing 1 in location 1\n"
336 void test_lesser_than_multiple_2() {
339 " 1:bool <- lesser-than 34, 35, 35\n"
342 CHECK_TRACE_CONTENTS(
343 "mem: storing 0 in location 1\n"
346 :(before
"End Primitive Recipe Declarations")
348 :(before
"End Primitive Recipe Numbers")
349 put(Recipe_ordinal
, "greater-or-equal", GREATER_OR_EQUAL
);
350 :(before
"End Primitive Recipe Checks")
351 case GREATER_OR_EQUAL
: {
352 if (SIZE(inst
.ingredients
) <= 1) {
353 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst
) << "'\n" << end();
356 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
357 if (!is_mu_number(inst
.ingredients
.at(i
))) {
358 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-or-equal' can only compare numbers; got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
359 goto finish_checking_instruction
;
362 if (SIZE(inst
.products
) > 1) {
363 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
366 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_boolean(inst
.products
.at(0))) {
367 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-or-equal' should yield a boolean, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
372 :(before
"End Primitive Recipe Implementations")
373 case GREATER_OR_EQUAL
: {
375 for (int i
= /**/1; i
< SIZE(ingredients
); ++i
) {
376 if (ingredients
.at(i
-1).at(0) < ingredients
.at(i
).at(0)) {
381 products
.at(0).push_back(result
);
386 void test_greater_or_equal() {
389 " 1:num <- copy 34\n"
390 " 2:num <- copy 33\n"
391 " 3:bool <- greater-or-equal 1:num, 2:num\n"
394 CHECK_TRACE_CONTENTS(
395 "mem: storing 1 in location 3\n"
399 void test_greater_or_equal_2() {
402 " 1:num <- copy 34\n"
403 " 2:num <- copy 34\n"
404 " 3:bool <- greater-or-equal 1:num, 2:num\n"
407 CHECK_TRACE_CONTENTS(
408 "mem: storing 1 in location 3\n"
412 void test_greater_or_equal_3() {
415 " 1:num <- copy 34\n"
416 " 2:num <- copy 35\n"
417 " 3:bool <- greater-or-equal 1:num, 2:num\n"
420 CHECK_TRACE_CONTENTS(
421 "mem: storing 0 in location 3\n"
425 void test_greater_or_equal_multiple() {
428 " 1:bool <- greater-or-equal 36, 35, 35\n"
431 CHECK_TRACE_CONTENTS(
432 "mem: storing 1 in location 1\n"
436 void test_greater_or_equal_multiple_2() {
439 " 1:bool <- greater-or-equal 36, 35, 36\n"
442 CHECK_TRACE_CONTENTS(
443 "mem: storing 0 in location 1\n"
447 :(before
"End Primitive Recipe Declarations")
449 :(before
"End Primitive Recipe Numbers")
450 put(Recipe_ordinal
, "lesser-or-equal", LESSER_OR_EQUAL
);
451 :(before
"End Primitive Recipe Checks")
452 case LESSER_OR_EQUAL
: {
453 if (SIZE(inst
.ingredients
) <= 1) {
454 raise
<< maybe(get(Recipe
, r
).name
) << "'lesser-or-equal' needs at least two ingredients to compare in '" << to_original_string(inst
) << "'\n" << end();
457 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
458 if (!is_mu_number(inst
.ingredients
.at(i
))) {
459 raise
<< maybe(get(Recipe
, r
).name
) << "'lesser-or-equal' can only compare numbers; got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
460 goto finish_checking_instruction
;
463 if (SIZE(inst
.products
) > 1) {
464 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-or-equal' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
467 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_boolean(inst
.products
.at(0))) {
468 raise
<< maybe(get(Recipe
, r
).name
) << "'greater-or-equal' should yield a boolean, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
473 :(before
"End Primitive Recipe Implementations")
474 case LESSER_OR_EQUAL
: {
476 for (int i
= /**/1; i
< SIZE(ingredients
); ++i
) {
477 if (ingredients
.at(i
-1).at(0) > ingredients
.at(i
).at(0)) {
482 products
.at(0).push_back(result
);
487 void test_lesser_or_equal() {
490 " 1:num <- copy 32\n"
491 " 2:num <- copy 33\n"
492 " 3:bool <- lesser-or-equal 1:num, 2:num\n"
495 CHECK_TRACE_CONTENTS(
496 "mem: storing 1 in location 3\n"
500 void test_lesser_or_equal_2() {
503 " 1:num <- copy 33\n"
504 " 2:num <- copy 33\n"
505 " 3:bool <- lesser-or-equal 1:num, 2:num\n"
508 CHECK_TRACE_CONTENTS(
509 "mem: storing 1 in location 3\n"
513 void test_lesser_or_equal_3() {
516 " 1:num <- copy 34\n"
517 " 2:num <- copy 33\n"
518 " 3:bool <- lesser-or-equal 1:num, 2:num\n"
521 CHECK_TRACE_CONTENTS(
522 "mem: storing 0 in location 3\n"
526 void test_lesser_or_equal_multiple() {
529 " 1:bool <- lesser-or-equal 34, 35, 35\n"
532 CHECK_TRACE_CONTENTS(
533 "mem: storing 1 in location 1\n"
537 void test_lesser_or_equal_multiple_2() {
540 " 1:bool <- lesser-or-equal 34, 35, 34\n"
543 CHECK_TRACE_CONTENTS(
544 "mem: storing 0 in location 1\n"
548 :(before
"End Primitive Recipe Declarations")
550 :(before
"End Primitive Recipe Numbers")
551 put(Recipe_ordinal
, "max", MAX
);
552 :(before
"End Primitive Recipe Checks")
554 if (SIZE(inst
.ingredients
) <= 1) {
555 raise
<< maybe(get(Recipe
, r
).name
) << "'max' needs at least two ingredients to compare in '" << to_original_string(inst
) << "'\n" << end();
558 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
559 if (!is_mu_number(inst
.ingredients
.at(i
))) {
560 raise
<< maybe(get(Recipe
, r
).name
) << "'max' can only compare numbers; got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
561 goto finish_checking_instruction
;
564 if (SIZE(inst
.products
) > 1) {
565 raise
<< maybe(get(Recipe
, r
).name
) << "'max' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
568 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
569 raise
<< maybe(get(Recipe
, r
).name
) << "'max' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
574 :(before
"End Primitive Recipe Implementations")
576 int result
= ingredients
.at(0).at(0);
577 for (int i
= /**/1; i
< SIZE(ingredients
); ++i
) {
578 if (ingredients
.at(i
).at(0) > result
) {
579 result
= ingredients
.at(i
).at(0);
583 products
.at(0).push_back(result
);
587 :(before
"End Primitive Recipe Declarations")
589 :(before
"End Primitive Recipe Numbers")
590 put(Recipe_ordinal
, "min", MIN
);
591 :(before
"End Primitive Recipe Checks")
593 if (SIZE(inst
.ingredients
) <= 1) {
594 raise
<< maybe(get(Recipe
, r
).name
) << "'min' needs at least two ingredients to compare in '" << to_original_string(inst
) << "'\n" << end();
597 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
598 if (!is_mu_number(inst
.ingredients
.at(i
))) {
599 raise
<< maybe(get(Recipe
, r
).name
) << "'min' can only compare numbers; got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
600 goto finish_checking_instruction
;
603 if (SIZE(inst
.products
) > 1) {
604 raise
<< maybe(get(Recipe
, r
).name
) << "'min' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
607 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
608 raise
<< maybe(get(Recipe
, r
).name
) << "'min' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
613 :(before
"End Primitive Recipe Implementations")
615 int result
= ingredients
.at(0).at(0);
616 for (int i
= /**/1; i
< SIZE(ingredients
); ++i
) {
617 if (ingredients
.at(i
).at(0) < result
) {
618 result
= ingredients
.at(i
).at(0);
622 products
.at(0).push_back(result
);