https://github.com/akkartik/mu1/blob/master/024jump.cc
1
2
3 :(scenario jump_can_skip_instructions)
4 def main [
5 jump 1:offset
6 1:num <- copy 1
7 ]
8 +run: jump {1: "offset"}
9 -run: {1: "number"} <- copy {1: "literal"}
10 -mem: storing 1 in location 1
11
12 :(before "End Primitive Recipe Declarations")
13 JUMP,
14 :(before "End Primitive Recipe Numbers")
15 put(Recipe_ordinal, "jump", JUMP);
16 :(before "End Primitive Recipe Checks")
17 case JUMP: {
18 if (SIZE(inst.ingredients) != 1) {
19 raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly one ingredient\n" << end();
20 break;
21 }
22 if (!is_literal(inst.ingredients.at(0))) {
23 raise << maybe(get(Recipe, r).name) << "first ingredient of '" << to_original_string(inst) << "' should be a label or offset, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end();
24 break;
25 }
26 if (!inst.products.empty()) {
27 raise << maybe(get(Recipe, r).name) << "'jump' instructions write no products\n" << end();
28 break;
29 }
30 break;
31 }
32 :(before "End Primitive Recipe Implementations")
33 case JUMP: {
34 assert(current_instruction().ingredients.at(0).initialized);
35 current_step_index() += ingredients.at(0).at(0)+1;
36 trace(9998, "run") << "jumping to instruction " << current_step_index() << end();
37
38 write_products = false;
39 fall_through_to_next_instruction = false;
40 break;
41 }
42
43
44 :(before "End Mu Types Initialization")
45 put(Type_ordinal, "offset", 0);
46
47 :(scenario jump_backward)
48 def main [
49 jump 1:offset
50 jump 3:offset
51
52 jump -2:offset
53 ]
54 +run: jump {1: "offset"}
55 +run: jump {-2: "offset"}
56 +run: jump {3: "offset"}
57
58 :(scenario jump_takes_no_products)
59 % Hide_errors = true;
60 def main [
61 1:num <- jump 1
62 ]
63 +error: main: 'jump' instructions write no products
64
65 :(before "End Primitive Recipe Declarations")
66 JUMP_IF,
67 :(before "End Primitive Recipe Numbers")
68 put(Recipe_ordinal, "jump-if", JUMP_IF);
69 :(before "End Primitive Recipe Checks")
70 case JUMP_IF: {
71 if (SIZE(inst.ingredients) != 2) {
72 raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly two ingredients\n" << end();
73 break;
74 }
75 if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) {
76 raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a boolean for its first ingredient, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end();
77 break;
78 }
79 if (!is_literal(inst.ingredients.at(1))) {
80 raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a label or offset for its second ingredient, but '" << inst.ingredients.at(1).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(1).type) << "'\n" << end();
81 break;
82 }
83 if (!inst.products.empty()) {
84 raise << maybe(get(Recipe, r).name) << "'jump-if' instructions write no products\n" << end();
85 break;
86 }
87
88 break;
89 }
90 :(before "End Primitive Recipe Implementations")
91 case JUMP_IF: {
92 assert(current_instruction().ingredients.at(1).initialized);
93 if (!scalar_ingredient(ingredients, 0)) {
94 trace(9998, "run") << "jump-if fell through" << end();
95 break;
96 }
97 current_step_index() += ingredients.at(1).at(0)+1;
98 trace(9998, "run") << "jumping to instruction " << current_step_index() << end();
99
100 write_products = false;
101 fall_through_to_next_instruction = false;
102 break;
103 }
104
105 :(scenario jump_if)
106 def main [
107 jump-if 999, 1:offset
108 123:num <- copy 1
109 ]
110 +run: jump-if {999: "literal"}, {1: "offset"}
111 +run: jumping to instruction 2
112 -run: {123: "number"} <- copy {1: "literal"}
113 -mem: storing 1 in location 123
114
115 :(scenario jump_if_fallthrough)
116 def main [
117 jump-if 0, 1:offset
118 123:num <- copy 1
119 ]
120 +run: jump-if {0: "literal"}, {1: "offset"}
121 +run: jump-if fell through
122 +run: {123: "number"} <- copy {1: "literal"}
123 +mem: storing 1 in location 123
124
125 :(scenario jump_if_on_address)
126 def main [
127 10:num/alloc-id, 11:num <- copy 0, 999
128 jump-if 10:&:number, 1:offset
129 123:num <- copy 1
130 ]
131 +run: jump-if {10: ("address" "number")}, {1: "offset"}
132 +run: jumping to instruction 3
133 -run: {123: "number"} <- copy {1: "literal"}
134 -mem: storing 1 in location 123
135
136 :(before "End Primitive Recipe Declarations")
137 JUMP_UNLESS,
138 :(before "End Primitive Recipe Numbers")
139 put(Recipe_ordinal, "jump-unless", JUMP_UNLESS);
140 :(before "End Primitive Recipe Checks")
141 case JUMP_UNLESS: {
142 if (SIZE(inst.ingredients) != 2) {
143 raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly two ingredients\n" << end();
144 break;
145 }
146 if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) {
147 raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a boolean for its first ingredient, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end();
148 break;
149 }
150 if (!is_literal(inst.ingredients.at(1))) {
151 raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a label or offset for its second ingredient, but '" << inst.ingredients.at(1).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(1).type) << "'\n" << end();
152 break;
153 }
154 if (!inst.products.empty()) {
155 raise << maybe(get(Recipe, r).name) << "'jump' instructions write no products\n" << end();
156 break;
157 }
158
159 break;
160 }
161 :(before "End Primitive Recipe Implementations")
162 case JUMP_UNLESS: {
163 assert(current_instruction().ingredients.at(1).initialized);
164 if (scalar_ingredient(ingredients, 0)) {
165 trace(9998, "run") << "jump-unless fell through" << end();
166 break;
167 }
168 current_step_index() += ingredients.at(1).at(0)+1;
169 trace(9998, "run") << "jumping to instruction " << current_step_index() << end();
170
171 write_products = false;
172 fall_through_to_next_instruction = false;
173 break;
174 }
175
176 :(scenario jump_unless)
177 def main [
178 jump-unless 0, 1:offset
179 123:num <- copy 1
180 ]
181 +run: jump-unless {0: "literal"}, {1: "offset"}
182 +run: jumping to instruction 2
183 -run: {123: "number"} <- copy {1: "literal"}
184 -mem: storing 1 in location 123
185
186 :(scenario jump_unless_fallthrough)
187 def main [
188 jump-unless 999, 1:offset
189 123:num <- copy 1
190 ]
191 +run: jump-unless {999: "literal"}, {1: "offset"}
192 +run: jump-unless fell through
193 +run: {123: "number"} <- copy {1: "literal"}
194 +mem: storing 1 in location 123