fix other mandelbrot variants
[mu.git] / archive / 1.vm / 025compare.cc
blobbade3c9cca858cd063966d187aabb13180b0f29c
1 //: Comparison primitives
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;
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();
22 break;
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;
28 break;
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;
39 if (!equal(ingredients.at(i).begin(), ingredients.at(i).end(), exemplar.begin())) {
40 result = false;
41 break;
44 products.resize(1);
45 products.at(0).push_back(result);
46 break;
49 :(code)
50 void test_equal() {
51 run(
52 "def main [\n"
53 " 1:num <- copy 34\n"
54 " 2:num <- copy 33\n"
55 " 3:bool <- equal 1:num, 2:num\n"
56 "]\n"
58 CHECK_TRACE_CONTENTS(
59 "mem: location 1 is 34\n"
60 "mem: location 2 is 33\n"
61 "mem: storing 0 in location 3\n"
65 void test_equal_2() {
66 run(
67 "def main [\n"
68 " 1:num <- copy 34\n"
69 " 2:num <- copy 34\n"
70 " 3:bool <- equal 1:num, 2:num\n"
71 "]\n"
73 CHECK_TRACE_CONTENTS(
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() {
81 run(
82 "def main [\n"
83 " 1:bool <- equal 34, 34, 34\n"
84 "]\n"
86 CHECK_TRACE_CONTENTS(
87 "mem: storing 1 in location 1\n"
91 void test_equal_multiple_2() {
92 run(
93 "def main [\n"
94 " 1:bool <- equal 34, 34, 35\n"
95 "]\n"
97 CHECK_TRACE_CONTENTS(
98 "mem: storing 0 in location 1\n"
102 :(before "End Primitive Recipe Declarations")
103 NOT_EQUAL,
104 :(before "End Primitive Recipe Numbers")
105 put(Recipe_ordinal, "not-equal", NOT_EQUAL);
106 :(before "End Primitive Recipe Checks")
107 case NOT_EQUAL: {
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();
110 break;
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();
119 break;
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();
123 break;
125 break;
127 :(before "End Primitive Recipe Implementations")
128 case NOT_EQUAL: {
129 vector<double>& exemplar = ingredients.at(0);
130 products.resize(1);
131 if (SIZE(ingredients.at(1)) != SIZE(exemplar)) {
132 products.at(0).push_back(true);
133 break;
135 bool equal_ingredients = equal(ingredients.at(1).begin(), ingredients.at(1).end(), exemplar.begin());
136 products.at(0).push_back(!equal_ingredients);
137 break;
140 :(code)
141 void test_not_equal() {
142 run(
143 "def main [\n"
144 " 1:num <- copy 34\n"
145 " 2:num <- copy 33\n"
146 " 3:bool <- not-equal 1:num, 2:num\n"
147 "]\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() {
157 run(
158 "def main [\n"
159 " 1:num <- copy 34\n"
160 " 2:num <- copy 34\n"
161 " 3:bool <- not-equal 1:num, 2:num\n"
162 "]\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")
172 GREATER_THAN,
173 :(before "End Primitive Recipe Numbers")
174 put(Recipe_ordinal, "greater-than", GREATER_THAN);
175 :(before "End Primitive Recipe Checks")
176 case GREATER_THAN: {
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();
179 break;
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();
189 break;
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();
193 break;
195 break;
197 :(before "End Primitive Recipe Implementations")
198 case GREATER_THAN: {
199 bool result = true;
200 for (int i = /**/1; i < SIZE(ingredients); ++i) {
201 if (ingredients.at(i-1).at(0) <= ingredients.at(i).at(0)) {
202 result = false;
205 products.resize(1);
206 products.at(0).push_back(result);
207 break;
210 :(code)
211 void test_greater_than() {
212 run(
213 "def main [\n"
214 " 1:num <- copy 34\n"
215 " 2:num <- copy 33\n"
216 " 3:bool <- greater-than 1:num, 2:num\n"
217 "]\n"
219 CHECK_TRACE_CONTENTS(
220 "mem: storing 1 in location 3\n"
224 void test_greater_than_2() {
225 run(
226 "def main [\n"
227 " 1:num <- copy 34\n"
228 " 2:num <- copy 34\n"
229 " 3:bool <- greater-than 1:num, 2:num\n"
230 "]\n"
232 CHECK_TRACE_CONTENTS(
233 "mem: storing 0 in location 3\n"
237 void test_greater_than_multiple() {
238 run(
239 "def main [\n"
240 " 1:bool <- greater-than 36, 35, 34\n"
241 "]\n"
243 CHECK_TRACE_CONTENTS(
244 "mem: storing 1 in location 1\n"
248 void test_greater_than_multiple_2() {
249 run(
250 "def main [\n"
251 " 1:bool <- greater-than 36, 35, 35\n"
252 "]\n"
254 CHECK_TRACE_CONTENTS(
255 "mem: storing 0 in location 1\n"
259 :(before "End Primitive Recipe Declarations")
260 LESSER_THAN,
261 :(before "End Primitive Recipe Numbers")
262 put(Recipe_ordinal, "lesser-than", LESSER_THAN);
263 :(before "End Primitive Recipe Checks")
264 case LESSER_THAN: {
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();
267 break;
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();
277 break;
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();
281 break;
283 break;
285 :(before "End Primitive Recipe Implementations")
286 case LESSER_THAN: {
287 bool result = true;
288 for (int i = /**/1; i < SIZE(ingredients); ++i) {
289 if (ingredients.at(i-1).at(0) >= ingredients.at(i).at(0)) {
290 result = false;
293 products.resize(1);
294 products.at(0).push_back(result);
295 break;
298 :(code)
299 void test_lesser_than() {
300 run(
301 "def main [\n"
302 " 1:num <- copy 32\n"
303 " 2:num <- copy 33\n"
304 " 3:bool <- lesser-than 1:num, 2:num\n"
305 "]\n"
307 CHECK_TRACE_CONTENTS(
308 "mem: storing 1 in location 3\n"
312 void test_lesser_than_2() {
313 run(
314 "def main [\n"
315 " 1:num <- copy 34\n"
316 " 2:num <- copy 33\n"
317 " 3:bool <- lesser-than 1:num, 2:num\n"
318 "]\n"
320 CHECK_TRACE_CONTENTS(
321 "mem: storing 0 in location 3\n"
325 void test_lesser_than_multiple() {
326 run(
327 "def main [\n"
328 " 1:bool <- lesser-than 34, 35, 36\n"
329 "]\n"
331 CHECK_TRACE_CONTENTS(
332 "mem: storing 1 in location 1\n"
336 void test_lesser_than_multiple_2() {
337 run(
338 "def main [\n"
339 " 1:bool <- lesser-than 34, 35, 35\n"
340 "]\n"
342 CHECK_TRACE_CONTENTS(
343 "mem: storing 0 in location 1\n"
346 :(before "End Primitive Recipe Declarations")
347 GREATER_OR_EQUAL,
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();
354 break;
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();
364 break;
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();
368 break;
370 break;
372 :(before "End Primitive Recipe Implementations")
373 case GREATER_OR_EQUAL: {
374 bool result = true;
375 for (int i = /**/1; i < SIZE(ingredients); ++i) {
376 if (ingredients.at(i-1).at(0) < ingredients.at(i).at(0)) {
377 result = false;
380 products.resize(1);
381 products.at(0).push_back(result);
382 break;
385 :(code)
386 void test_greater_or_equal() {
387 run(
388 "def main [\n"
389 " 1:num <- copy 34\n"
390 " 2:num <- copy 33\n"
391 " 3:bool <- greater-or-equal 1:num, 2:num\n"
392 "]\n"
394 CHECK_TRACE_CONTENTS(
395 "mem: storing 1 in location 3\n"
399 void test_greater_or_equal_2() {
400 run(
401 "def main [\n"
402 " 1:num <- copy 34\n"
403 " 2:num <- copy 34\n"
404 " 3:bool <- greater-or-equal 1:num, 2:num\n"
405 "]\n"
407 CHECK_TRACE_CONTENTS(
408 "mem: storing 1 in location 3\n"
412 void test_greater_or_equal_3() {
413 run(
414 "def main [\n"
415 " 1:num <- copy 34\n"
416 " 2:num <- copy 35\n"
417 " 3:bool <- greater-or-equal 1:num, 2:num\n"
418 "]\n"
420 CHECK_TRACE_CONTENTS(
421 "mem: storing 0 in location 3\n"
425 void test_greater_or_equal_multiple() {
426 run(
427 "def main [\n"
428 " 1:bool <- greater-or-equal 36, 35, 35\n"
429 "]\n"
431 CHECK_TRACE_CONTENTS(
432 "mem: storing 1 in location 1\n"
436 void test_greater_or_equal_multiple_2() {
437 run(
438 "def main [\n"
439 " 1:bool <- greater-or-equal 36, 35, 36\n"
440 "]\n"
442 CHECK_TRACE_CONTENTS(
443 "mem: storing 0 in location 1\n"
447 :(before "End Primitive Recipe Declarations")
448 LESSER_OR_EQUAL,
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();
455 break;
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();
465 break;
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();
469 break;
471 break;
473 :(before "End Primitive Recipe Implementations")
474 case LESSER_OR_EQUAL: {
475 bool result = true;
476 for (int i = /**/1; i < SIZE(ingredients); ++i) {
477 if (ingredients.at(i-1).at(0) > ingredients.at(i).at(0)) {
478 result = false;
481 products.resize(1);
482 products.at(0).push_back(result);
483 break;
486 :(code)
487 void test_lesser_or_equal() {
488 run(
489 "def main [\n"
490 " 1:num <- copy 32\n"
491 " 2:num <- copy 33\n"
492 " 3:bool <- lesser-or-equal 1:num, 2:num\n"
493 "]\n"
495 CHECK_TRACE_CONTENTS(
496 "mem: storing 1 in location 3\n"
500 void test_lesser_or_equal_2() {
501 run(
502 "def main [\n"
503 " 1:num <- copy 33\n"
504 " 2:num <- copy 33\n"
505 " 3:bool <- lesser-or-equal 1:num, 2:num\n"
506 "]\n"
508 CHECK_TRACE_CONTENTS(
509 "mem: storing 1 in location 3\n"
513 void test_lesser_or_equal_3() {
514 run(
515 "def main [\n"
516 " 1:num <- copy 34\n"
517 " 2:num <- copy 33\n"
518 " 3:bool <- lesser-or-equal 1:num, 2:num\n"
519 "]\n"
521 CHECK_TRACE_CONTENTS(
522 "mem: storing 0 in location 3\n"
526 void test_lesser_or_equal_multiple() {
527 run(
528 "def main [\n"
529 " 1:bool <- lesser-or-equal 34, 35, 35\n"
530 "]\n"
532 CHECK_TRACE_CONTENTS(
533 "mem: storing 1 in location 1\n"
537 void test_lesser_or_equal_multiple_2() {
538 run(
539 "def main [\n"
540 " 1:bool <- lesser-or-equal 34, 35, 34\n"
541 "]\n"
543 CHECK_TRACE_CONTENTS(
544 "mem: storing 0 in location 1\n"
548 :(before "End Primitive Recipe Declarations")
549 MAX,
550 :(before "End Primitive Recipe Numbers")
551 put(Recipe_ordinal, "max", MAX);
552 :(before "End Primitive Recipe Checks")
553 case MAX: {
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();
556 break;
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();
566 break;
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();
570 break;
572 break;
574 :(before "End Primitive Recipe Implementations")
575 case MAX: {
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);
582 products.resize(1);
583 products.at(0).push_back(result);
584 break;
587 :(before "End Primitive Recipe Declarations")
588 MIN,
589 :(before "End Primitive Recipe Numbers")
590 put(Recipe_ordinal, "min", MIN);
591 :(before "End Primitive Recipe Checks")
592 case MIN: {
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();
595 break;
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();
605 break;
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();
609 break;
611 break;
613 :(before "End Primitive Recipe Implementations")
614 case MIN: {
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);
621 products.resize(1);
622 products.at(0).push_back(result);
623 break;