1 //: Arithmetic primitives
3 :(before
"End Primitive Recipe Declarations")
5 :(before
"End Primitive Recipe Numbers")
6 put(Recipe_ordinal
, "add", ADD
);
7 :(before
"End Primitive Recipe Checks")
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
;
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();
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();
26 :(before
"End Primitive Recipe Implementations")
29 for (int i
= 0; i
< SIZE(ingredients
); ++i
) {
30 result
+= ingredients
.at(i
).at(0);
33 products
.at(0).push_back(result
);
38 void test_add_literal() {
41 " 1:num <- add 23, 34\n"
45 "mem: storing 57 in location 1\n"
54 " 3:num <- add 1:num, 2:num\n"
58 "mem: storing 57 in location 3\n"
62 void test_add_multiple() {
65 " 1:num <- add 3, 4, 5\n"
69 "mem: storing 12 in location 1\n"
73 void test_add_checks_type() {
77 " 1:num <- add 2:bool, 1\n"
81 "error: main: 'add' requires number ingredients, but got '2:bool'\n"
85 void test_add_checks_return_type() {
89 " 1:&:num <- add 2, 2\n"
93 "error: main: 'add' should yield a number, but got '1:&:num'\n"
97 :(before
"End Primitive Recipe Declarations")
99 :(before
"End Primitive Recipe Numbers")
100 put(Recipe_ordinal
, "subtract", SUBTRACT
);
101 :(before
"End Primitive Recipe Checks")
103 if (inst
.ingredients
.empty()) {
104 raise
<< maybe(get(Recipe
, r
).name
) << "'subtract' has no ingredients\n" << end();
107 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
108 if (!is_mu_number(inst
.ingredients
.at(i
))) {
109 raise
<< maybe(get(Recipe
, r
).name
) << "'subtract' requires number ingredients, but got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
110 goto finish_checking_instruction
;
113 if (SIZE(inst
.products
) > 1) {
114 raise
<< maybe(get(Recipe
, r
).name
) << "'subtract' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
117 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
118 raise
<< maybe(get(Recipe
, r
).name
) << "'subtract' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
123 :(before
"End Primitive Recipe Implementations")
125 double result
= ingredients
.at(0).at(0);
126 for (int i
= 1; i
< SIZE(ingredients
); ++i
)
127 result
-= ingredients
.at(i
).at(0);
129 products
.at(0).push_back(result
);
134 void test_subtract_literal() {
137 " 1:num <- subtract 5, 2\n"
140 CHECK_TRACE_CONTENTS(
141 "mem: storing 3 in location 1\n"
145 void test_subtract() {
148 " 1:num <- copy 23\n"
149 " 2:num <- copy 34\n"
150 " 3:num <- subtract 1:num, 2:num\n"
153 CHECK_TRACE_CONTENTS(
154 "mem: storing -11 in location 3\n"
158 void test_subtract_multiple() {
161 " 1:num <- subtract 6, 3, 2\n"
164 CHECK_TRACE_CONTENTS(
165 "mem: storing 1 in location 1\n"
169 :(before
"End Primitive Recipe Declarations")
171 :(before
"End Primitive Recipe Numbers")
172 put(Recipe_ordinal
, "multiply", MULTIPLY
);
173 :(before
"End Primitive Recipe Checks")
175 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
176 if (!is_mu_number(inst
.ingredients
.at(i
))) {
177 raise
<< maybe(get(Recipe
, r
).name
) << "'multiply' requires number ingredients, but got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
178 goto finish_checking_instruction
;
181 if (SIZE(inst
.products
) > 1) {
182 raise
<< maybe(get(Recipe
, r
).name
) << "'multiply' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
185 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
186 raise
<< maybe(get(Recipe
, r
).name
) << "'multiply' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
191 :(before
"End Primitive Recipe Implementations")
194 for (int i
= 0; i
< SIZE(ingredients
); ++i
) {
195 result
*= ingredients
.at(i
).at(0);
198 products
.at(0).push_back(result
);
203 void test_multiply_literal() {
206 " 1:num <- multiply 2, 3\n"
209 CHECK_TRACE_CONTENTS(
210 "mem: storing 6 in location 1\n"
214 void test_multiply() {
219 " 3:num <- multiply 1:num, 2:num\n"
222 CHECK_TRACE_CONTENTS(
223 "mem: storing 24 in location 3\n"
227 void test_multiply_multiple() {
230 " 1:num <- multiply 2, 3, 4\n"
233 CHECK_TRACE_CONTENTS(
234 "mem: storing 24 in location 1\n"
238 :(before
"End Primitive Recipe Declarations")
240 :(before
"End Primitive Recipe Numbers")
241 put(Recipe_ordinal
, "divide", DIVIDE
);
242 :(before
"End Primitive Recipe Checks")
244 if (inst
.ingredients
.empty()) {
245 raise
<< maybe(get(Recipe
, r
).name
) << "'divide' has no ingredients\n" << end();
248 for (int i
= 0; i
< SIZE(inst
.ingredients
); ++i
) {
249 if (!is_mu_number(inst
.ingredients
.at(i
))) {
250 raise
<< maybe(get(Recipe
, r
).name
) << "'divide' requires number ingredients, but got '" << inst
.ingredients
.at(i
).original_string
<< "'\n" << end();
251 goto finish_checking_instruction
;
254 if (SIZE(inst
.products
) > 1) {
255 raise
<< maybe(get(Recipe
, r
).name
) << "'divide' yields exactly one product in '" << to_original_string(inst
) << "'\n" << end();
258 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
259 raise
<< maybe(get(Recipe
, r
).name
) << "'divide' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
264 :(before
"End Primitive Recipe Implementations")
266 double result
= ingredients
.at(0).at(0);
267 for (int i
= 1; i
< SIZE(ingredients
); ++i
)
268 result
/= ingredients
.at(i
).at(0);
270 products
.at(0).push_back(result
);
275 void test_divide_literal() {
278 " 1:num <- divide 8, 2\n"
281 CHECK_TRACE_CONTENTS(
282 "mem: storing 4 in location 1\n"
289 " 1:num <- copy 27\n"
291 " 3:num <- divide 1:num, 2:num\n"
294 CHECK_TRACE_CONTENTS(
295 "mem: storing 9 in location 3\n"
299 void test_divide_multiple() {
302 " 1:num <- divide 12, 3, 2\n"
305 CHECK_TRACE_CONTENTS(
306 "mem: storing 2 in location 1\n"
312 :(before
"End Primitive Recipe Declarations")
313 DIVIDE_WITH_REMAINDER
,
314 :(before
"End Primitive Recipe Numbers")
315 put(Recipe_ordinal
, "divide-with-remainder", DIVIDE_WITH_REMAINDER
);
316 :(before
"End Primitive Recipe Checks")
317 case DIVIDE_WITH_REMAINDER
: {
318 if (SIZE(inst
.ingredients
) != 2) {
319 raise
<< maybe(get(Recipe
, r
).name
) << "'divide-with-remainder' requires exactly two ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
322 if (!is_mu_number(inst
.ingredients
.at(0)) || !is_mu_number(inst
.ingredients
.at(1))) {
323 raise
<< maybe(get(Recipe
, r
).name
) << "'divide-with-remainder' requires number ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
326 if (SIZE(inst
.products
) > 2) {
327 raise
<< maybe(get(Recipe
, r
).name
) << "'divide-with-remainder' yields two products in '" << to_original_string(inst
) << "'\n" << end();
330 for (int i
= 0; i
< SIZE(inst
.products
); ++i
) {
331 if (!is_dummy(inst
.products
.at(i
)) && !is_mu_number(inst
.products
.at(i
))) {
332 raise
<< maybe(get(Recipe
, r
).name
) << "'divide-with-remainder' should yield a number, but got '" << inst
.products
.at(i
).original_string
<< "'\n" << end();
333 goto finish_checking_instruction
;
338 :(before
"End Primitive Recipe Implementations")
339 case DIVIDE_WITH_REMAINDER
: {
341 // fractions will be dropped; very large numbers will overflow
342 long long int a
= static_cast<long long int>(ingredients
.at(0).at(0));
343 long long int b
= static_cast<long long int>(ingredients
.at(1).at(0));
345 raise
<< maybe(current_recipe_name()) << "divide by zero in '" << to_original_string(current_instruction()) << "'\n" << end();
347 products
.at(0).push_back(0);
348 products
.at(1).push_back(0);
351 long long int quotient
= a
/ b
;
352 long long int remainder
= a
% b
;
353 products
.at(0).push_back(static_cast<double>(quotient
));
354 products
.at(1).push_back(static_cast<double>(remainder
));
359 void test_divide_with_remainder_literal() {
362 " 1:num, 2:num <- divide-with-remainder 9, 2\n"
365 CHECK_TRACE_CONTENTS(
366 "mem: storing 4 in location 1\n"
367 "mem: storing 1 in location 2\n"
371 void test_divide_with_remainder() {
374 " 1:num <- copy 27\n"
375 " 2:num <- copy 11\n"
376 " 3:num, 4:num <- divide-with-remainder 1:num, 2:num\n"
379 CHECK_TRACE_CONTENTS(
380 "mem: storing 2 in location 3\n"
381 "mem: storing 5 in location 4\n"
385 void test_divide_with_decimal_point() {
388 " 1:num <- divide 5, 2\n"
391 CHECK_TRACE_CONTENTS(
392 "mem: storing 2.5 in location 1\n"
396 void test_divide_by_zero() {
399 " 1:num <- divide 4, 0\n"
402 CHECK_TRACE_CONTENTS(
403 "mem: storing inf in location 1\n"
407 void test_divide_by_zero_2() {
411 " 1:num <- divide-with-remainder 4, 0\n"
414 // integer division can't return floating-point infinity
415 CHECK_TRACE_CONTENTS(
416 "error: main: divide by zero in '1:num <- divide-with-remainder 4, 0'\n"
422 :(before
"End Primitive Recipe Declarations")
424 :(before
"End Primitive Recipe Numbers")
425 put(Recipe_ordinal
, "shift-left", SHIFT_LEFT
);
426 :(before
"End Primitive Recipe Checks")
428 if (SIZE(inst
.ingredients
) != 2) {
429 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-left' requires exactly two ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
432 if (!is_mu_number(inst
.ingredients
.at(0)) || !is_mu_number(inst
.ingredients
.at(1))) {
433 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-left' requires number ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
436 if (SIZE(inst
.products
) > 1) {
437 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-left' yields one product in '" << to_original_string(inst
) << "'\n" << end();
440 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
441 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-left' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
442 goto finish_checking_instruction
;
446 :(before
"End Primitive Recipe Implementations")
448 // ingredients must be integers
449 int a
= static_cast<int>(ingredients
.at(0).at(0));
450 int b
= static_cast<int>(ingredients
.at(1).at(0));
453 raise
<< maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_original_string(current_instruction()) << "'\n" << end();
454 products
.at(0).push_back(0);
457 products
.at(0).push_back(a
<<b
);
462 void test_shift_left_by_zero() {
465 " 1:num <- shift-left 1, 0\n"
468 CHECK_TRACE_CONTENTS(
469 "mem: storing 1 in location 1\n"
473 void test_shift_left_1() {
476 " 1:num <- shift-left 1, 4\n"
479 CHECK_TRACE_CONTENTS(
480 "mem: storing 16 in location 1\n"
484 void test_shift_left_2() {
487 " 1:num <- shift-left 3, 2\n"
490 CHECK_TRACE_CONTENTS(
491 "mem: storing 12 in location 1\n"
495 void test_shift_left_by_negative() {
499 " 1:num <- shift-left 3, -1\n"
502 CHECK_TRACE_CONTENTS(
503 "error: main: second ingredient can't be negative in '1:num <- shift-left 3, -1'\n"
507 void test_shift_left_ignores_fractional_part() {
510 " 1:num <- divide 3, 2\n"
511 " 2:num <- shift-left 1:num, 1\n"
514 CHECK_TRACE_CONTENTS(
515 "mem: storing 2 in location 2\n"
519 :(before
"End Primitive Recipe Declarations")
521 :(before
"End Primitive Recipe Numbers")
522 put(Recipe_ordinal
, "shift-right", SHIFT_RIGHT
);
523 :(before
"End Primitive Recipe Checks")
525 if (SIZE(inst
.ingredients
) != 2) {
526 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-right' requires exactly two ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
529 if (!is_mu_number(inst
.ingredients
.at(0)) || !is_mu_number(inst
.ingredients
.at(1))) {
530 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-right' requires number ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
533 if (SIZE(inst
.products
) > 1) {
534 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-right' yields one product in '" << to_original_string(inst
) << "'\n" << end();
537 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
538 raise
<< maybe(get(Recipe
, r
).name
) << "'shift-right' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
539 goto finish_checking_instruction
;
543 :(before
"End Primitive Recipe Implementations")
545 // ingredients must be integers
546 int a
= static_cast<int>(ingredients
.at(0).at(0));
547 int b
= static_cast<int>(ingredients
.at(1).at(0));
550 raise
<< maybe(current_recipe_name()) << "second ingredient can't be negative in '" << to_original_string(current_instruction()) << "'\n" << end();
551 products
.at(0).push_back(0);
554 products
.at(0).push_back(a
>>b
);
559 void test_shift_right_by_zero() {
562 " 1:num <- shift-right 1, 0\n"
565 CHECK_TRACE_CONTENTS(
566 "mem: storing 1 in location 1\n"
570 void test_shift_right_1() {
573 " 1:num <- shift-right 1024, 1\n"
576 CHECK_TRACE_CONTENTS(
577 "mem: storing 512 in location 1\n"
581 void test_shift_right_2() {
584 " 1:num <- shift-right 3, 1\n"
587 CHECK_TRACE_CONTENTS(
588 "mem: storing 1 in location 1\n"
592 void test_shift_right_by_negative() {
596 " 1:num <- shift-right 4, -1\n"
599 CHECK_TRACE_CONTENTS(
600 "error: main: second ingredient can't be negative in '1:num <- shift-right 4, -1'\n"
604 void test_shift_right_ignores_fractional_part() {
607 " 1:num <- divide 3, 2\n"
608 " 2:num <- shift-right 1:num, 1\n"
611 CHECK_TRACE_CONTENTS(
612 "mem: storing 0 in location 2\n"
616 :(before
"End Primitive Recipe Declarations")
618 :(before
"End Primitive Recipe Numbers")
619 put(Recipe_ordinal
, "and-bits", AND_BITS
);
620 :(before
"End Primitive Recipe Checks")
622 if (SIZE(inst
.ingredients
) != 2) {
623 raise
<< maybe(get(Recipe
, r
).name
) << "'and-bits' requires exactly two ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
626 if (!is_mu_number(inst
.ingredients
.at(0)) || !is_mu_number(inst
.ingredients
.at(1))) {
627 raise
<< maybe(get(Recipe
, r
).name
) << "'and-bits' requires number ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
630 if (SIZE(inst
.products
) > 1) {
631 raise
<< maybe(get(Recipe
, r
).name
) << "'and-bits' yields one product in '" << to_original_string(inst
) << "'\n" << end();
634 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
635 raise
<< maybe(get(Recipe
, r
).name
) << "'and-bits' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
636 goto finish_checking_instruction
;
640 :(before
"End Primitive Recipe Implementations")
642 // ingredients must be integers
643 int a
= static_cast<int>(ingredients
.at(0).at(0));
644 int b
= static_cast<int>(ingredients
.at(1).at(0));
646 products
.at(0).push_back(a
&b
);
651 void test_and_bits_1() {
654 " 1:num <- and-bits 8, 3\n"
657 CHECK_TRACE_CONTENTS(
658 "mem: storing 0 in location 1\n"
662 void test_and_bits_2() {
665 " 1:num <- and-bits 3, 2\n"
668 CHECK_TRACE_CONTENTS(
669 "mem: storing 2 in location 1\n"
673 void test_and_bits_3() {
676 " 1:num <- and-bits 14, 3\n"
679 CHECK_TRACE_CONTENTS(
680 "mem: storing 2 in location 1\n"
684 void test_and_bits_negative() {
687 " 1:num <- and-bits -3, 4\n"
690 CHECK_TRACE_CONTENTS(
691 "mem: storing 4 in location 1\n"
695 :(before
"End Primitive Recipe Declarations")
697 :(before
"End Primitive Recipe Numbers")
698 put(Recipe_ordinal
, "or-bits", OR_BITS
);
699 :(before
"End Primitive Recipe Checks")
701 if (SIZE(inst
.ingredients
) != 2) {
702 raise
<< maybe(get(Recipe
, r
).name
) << "'or-bits' requires exactly two ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
705 if (!is_mu_number(inst
.ingredients
.at(0)) || !is_mu_number(inst
.ingredients
.at(1))) {
706 raise
<< maybe(get(Recipe
, r
).name
) << "'or-bits' requires number ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
709 if (SIZE(inst
.products
) > 1) {
710 raise
<< maybe(get(Recipe
, r
).name
) << "'or-bits' yields one product in '" << to_original_string(inst
) << "'\n" << end();
713 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
714 raise
<< maybe(get(Recipe
, r
).name
) << "'or-bits' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
715 goto finish_checking_instruction
;
719 :(before
"End Primitive Recipe Implementations")
721 // ingredients must be integers
722 int a
= static_cast<int>(ingredients
.at(0).at(0));
723 int b
= static_cast<int>(ingredients
.at(1).at(0));
725 products
.at(0).push_back(a
|b
);
730 void test_or_bits_1() {
733 " 1:num <- or-bits 3, 8\n"
736 CHECK_TRACE_CONTENTS(
737 "mem: storing 11 in location 1\n"
741 void test_or_bits_2() {
744 " 1:num <- or-bits 3, 10\n"
747 CHECK_TRACE_CONTENTS(
748 "mem: storing 11 in location 1\n"
752 void test_or_bits_3() {
755 " 1:num <- or-bits 4, 6\n"
758 CHECK_TRACE_CONTENTS(
759 "mem: storing 6 in location 1\n"
763 :(before
"End Primitive Recipe Declarations")
765 :(before
"End Primitive Recipe Numbers")
766 put(Recipe_ordinal
, "xor-bits", XOR_BITS
);
767 :(before
"End Primitive Recipe Checks")
769 if (SIZE(inst
.ingredients
) != 2) {
770 raise
<< maybe(get(Recipe
, r
).name
) << "'xor-bits' requires exactly two ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
773 if (!is_mu_number(inst
.ingredients
.at(0)) || !is_mu_number(inst
.ingredients
.at(1))) {
774 raise
<< maybe(get(Recipe
, r
).name
) << "'xor-bits' requires number ingredients, but got '" << to_original_string(inst
) << "'\n" << end();
777 if (SIZE(inst
.products
) > 1) {
778 raise
<< maybe(get(Recipe
, r
).name
) << "'xor-bits' yields one product in '" << to_original_string(inst
) << "'\n" << end();
781 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
782 raise
<< maybe(get(Recipe
, r
).name
) << "'xor-bits' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
783 goto finish_checking_instruction
;
787 :(before
"End Primitive Recipe Implementations")
789 // ingredients must be integers
790 int a
= static_cast<int>(ingredients
.at(0).at(0));
791 int b
= static_cast<int>(ingredients
.at(1).at(0));
793 products
.at(0).push_back(a
^b
);
798 void test_xor_bits_1() {
801 " 1:num <- xor-bits 3, 8\n"
804 CHECK_TRACE_CONTENTS(
805 "mem: storing 11 in location 1\n"
809 void test_xor_bits_2() {
812 " 1:num <- xor-bits 3, 10\n"
815 CHECK_TRACE_CONTENTS(
816 "mem: storing 9 in location 1\n"
820 void test_xor_bits_3() {
823 " 1:num <- xor-bits 4, 6\n"
826 CHECK_TRACE_CONTENTS(
827 "mem: storing 2 in location 1\n"
831 :(before
"End Primitive Recipe Declarations")
833 :(before
"End Primitive Recipe Numbers")
834 put(Recipe_ordinal
, "flip-bits", FLIP_BITS
);
835 :(before
"End Primitive Recipe Checks")
837 if (SIZE(inst
.ingredients
) != 1) {
838 raise
<< maybe(get(Recipe
, r
).name
) << "'flip-bits' requires exactly one ingredient, but got '" << to_original_string(inst
) << "'\n" << end();
841 if (!is_mu_number(inst
.ingredients
.at(0))) {
842 raise
<< maybe(get(Recipe
, r
).name
) << "'flip-bits' requires a number ingredient, but got '" << to_original_string(inst
) << "'\n" << end();
845 if (SIZE(inst
.products
) > 1) {
846 raise
<< maybe(get(Recipe
, r
).name
) << "'flip-bits' yields one product in '" << to_original_string(inst
) << "'\n" << end();
849 if (!inst
.products
.empty() && !is_dummy(inst
.products
.at(0)) && !is_mu_number(inst
.products
.at(0))) {
850 raise
<< maybe(get(Recipe
, r
).name
) << "'flip-bits' should yield a number, but got '" << inst
.products
.at(0).original_string
<< "'\n" << end();
851 goto finish_checking_instruction
;
855 :(before
"End Primitive Recipe Implementations")
857 // ingredient must be integer
858 int a
= static_cast<int>(ingredients
.at(0).at(0));
860 products
.at(0).push_back(~a
);
865 void test_flip_bits_zero() {
868 " 1:num <- flip-bits 0\n"
871 CHECK_TRACE_CONTENTS(
872 "mem: storing -1 in location 1\n"
876 void test_flip_bits_negative() {
879 " 1:num <- flip-bits -1\n"
882 CHECK_TRACE_CONTENTS(
883 "mem: storing 0 in location 1\n"
887 void test_flip_bits_1() {
890 " 1:num <- flip-bits 3\n"
893 CHECK_TRACE_CONTENTS(
894 "mem: storing -4 in location 1\n"
898 void test_flip_bits_2() {
901 " 1:num <- flip-bits 12\n"
904 CHECK_TRACE_CONTENTS(
905 "mem: storing -13 in location 1\n"
909 :(before
"End Primitive Recipe Declarations")
911 :(before
"End Primitive Recipe Numbers")
912 put(Recipe_ordinal
, "round", ROUND
);
913 :(before
"End Primitive Recipe Checks")
915 if (SIZE(inst
.ingredients
) != 1) {
916 raise
<< maybe(get(Recipe
, r
).name
) << "'round' requires exactly one ingredient, but got '" << to_original_string(inst
) << "'\n" << end();
919 if (!is_mu_number(inst
.ingredients
.at(0))) {
920 raise
<< maybe(get(Recipe
, r
).name
) << "first ingredient of 'round' should be a number, but got '" << inst
.ingredients
.at(0).original_string
<< "'\n" << end();
925 :(before
"End Primitive Recipe Implementations")
928 products
.at(0).push_back(rint(ingredients
.at(0).at(0)));
933 void test_round_to_nearest_integer() {
936 " 1:num <- round 12.2\n"
939 CHECK_TRACE_CONTENTS(
940 "mem: storing 12 in location 1\n"
944 void test_round_halves_toward_zero() {
947 " 1:num <- round 12.5\n"
950 CHECK_TRACE_CONTENTS(
951 "mem: storing 12 in location 1\n"
955 void test_round_halves_toward_zero_2() {
958 " 1:num <- round -12.5\n"
961 CHECK_TRACE_CONTENTS(
962 "mem: storing -12 in location 1\n"
966 :(before
"End Primitive Recipe Declarations")
968 :(before
"End Primitive Recipe Numbers")
969 put(Recipe_ordinal
, "truncate", TRUNCATE
);
970 :(before
"End Primitive Recipe Checks")
972 if (SIZE(inst
.ingredients
) != 1) {
973 raise
<< maybe(get(Recipe
, r
).name
) << "'truncate' requires exactly one ingredient, but got '" << to_original_string(inst
) << "'\n" << end();
976 if (!is_mu_number(inst
.ingredients
.at(0))) {
977 raise
<< maybe(get(Recipe
, r
).name
) << "first ingredient of 'truncate' should be a number, but got '" << inst
.ingredients
.at(0).original_string
<< "'\n" << end();
982 :(before
"End Primitive Recipe Implementations")
985 products
.at(0).push_back(trunc(ingredients
.at(0).at(0)));
990 void test_truncate_to_nearest_integer() {
993 " 1:num <- truncate 12.2\n"
996 CHECK_TRACE_CONTENTS(
997 "mem: storing 12 in location 1\n"
1001 void test_truncate_negative() {
1004 " 1:num <- truncate -12.2\n"
1007 CHECK_TRACE_CONTENTS(
1008 "mem: storing -12 in location 1\n"
1012 :(before
"End Primitive Recipe Declarations")
1014 :(before
"End Primitive Recipe Numbers")
1015 put(Recipe_ordinal
, "square-root", SQUARE_ROOT
);
1016 :(before
"End Primitive Recipe Checks")
1018 if (SIZE(inst
.ingredients
) != 1) {
1019 raise
<< maybe(get(Recipe
, r
).name
) << "'square-root' requires exactly one ingredient, but got '" << to_original_string(inst
) << "'\n" << end();
1022 if (!is_mu_number(inst
.ingredients
.at(0))) {
1023 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();
1028 :(before
"End Primitive Recipe Implementations")
1031 products
.at(0).push_back(sqrt(ingredients
.at(0).at(0)));
1035 :(before
"End Primitive Recipe Declarations")
1037 :(before
"End Primitive Recipe Numbers")
1038 put(Recipe_ordinal
, "character-to-code", CHARACTER_TO_CODE
);
1039 :(before
"End Primitive Recipe Checks")
1040 case CHARACTER_TO_CODE
: {
1041 if (SIZE(inst
.ingredients
) != 1) {
1042 raise
<< maybe(get(Recipe
, r
).name
) << "'character-to-code' requires exactly one ingredient, but got '" << to_original_string(inst
) << "'\n" << end();
1045 if (!is_mu_character(inst
.ingredients
.at(0))) {
1046 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();
1049 if (SIZE(inst
.products
) != 1) {
1050 raise
<< maybe(get(Recipe
, r
).name
) << "'character-to-code' requires exactly one product, but got '" << to_original_string(inst
) << "'\n" << end();
1053 if (!is_mu_number(inst
.products
.at(0))) {
1054 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();
1059 :(before
"End Primitive Recipe Implementations")
1060 case CHARACTER_TO_CODE
: {
1062 for (int i
= 0; i
< SIZE(ingredients
); ++i
) {
1063 result
+= ingredients
.at(i
).at(0);
1066 products
.at(0).push_back(result
);
1070 :(before
"End Includes")