https://github.com/akkartik/mu/blob/master/033exclusive_container.cc
1
2
3
4
5
6
7 :(before "End Mu Types Initialization")
8
9 {
10 type_ordinal tmp = put(Type_ordinal, "number-or-point", Next_type_ordinal++);
11 get_or_insert(Type, tmp);
12 get(Type, tmp).kind = EXCLUSIVE_CONTAINER;
13 get(Type, tmp).name = "number-or-point";
14 get(Type, tmp).elements.push_back(reagent("i:number"));
15 get(Type, tmp).elements.push_back(reagent("p:point"));
16 }
17
18
19
20
21 :(scenario copy_exclusive_container)
22
23 def main [
24 1:num <- copy 1
25 2:num <- copy 34
26 3:num <- copy 35
27 4:number-or-point <- copy 1:number-or-point/unsafe
28 ]
29 +mem: storing 1 in location 4
30 +mem: storing 34 in location 5
31 +mem: storing 35 in location 6
32
33 :(before "End size_of(type) Special-cases")
34 if (t.kind == EXCLUSIVE_CONTAINER) {
35
36
37 int result = 0;
38 for (int i = 0; i < SIZE(t.elements); ++i) {
39 reagent tmp;
40 tmp.type = new type_tree(*type);
41 int size = size_of(variant_type(tmp, i));
42 if (size > result) result = size;
43 }
44
45 return result+1;
46 }
47
48
49
50
51
52
53
54
55 :(before "End Mu Types Initialization")
56 put(Type_ordinal, "variant", 0);
57
58 :(scenario maybe_convert)
59 def main [
60 12:num <- copy 1
61 13:num <- copy 35
62 14:num <- copy 36
63 20:point, 22:bool <- maybe-convert 12:number-or-point/unsafe, 1:variant
64 ]
65
66 +mem: storing 1 in location 22
67
68 +mem: storing 35 in location 20
69 +mem: storing 36 in location 21
70
71 :(scenario maybe_convert_fail)
72 def main [
73 12:num <- copy 1
74 13:num <- copy 35
75 14:num <- copy 36
76 20:num, 21:bool <- maybe-convert 12:number-or-point/unsafe, 0:variant
77 ]
78
79 +mem: storing 0 in location 21
80
81
82 :(before "End Primitive Recipe Declarations")
83 MAYBE_CONVERT,
84 :(before "End Primitive Recipe Numbers")
85 put(Recipe_ordinal, "maybe-convert", MAYBE_CONVERT);
86 :(before "End Primitive Recipe Checks")
87 case MAYBE_CONVERT: {
88 const recipe& caller = get(Recipe, r);
89 if (SIZE(inst.ingredients) != 2) {
90 raise << maybe(caller.name) << "'maybe-convert' expects exactly 2 ingredients in '" << to_original_string(inst) << "'\n" << end();
91 break;
92 }
93 reagent base = inst.ingredients.at(0);
94
95 if (!base.type) {
96 raise << maybe(caller.name) << "first ingredient of 'maybe-convert' should be an exclusive-container, but got '" << base.original_string << "'\n" << end();
97 break;
98 }
99 const type_tree* base_type = base.type;
100
101 if (!base_type->atom || base_type->value == 0 || !contains_key(Type, base_type->value) || get(Type, base_type->value).kind != EXCLUSIVE_CONTAINER) {
102 raise << maybe(caller.name) << "first ingredient of 'maybe-convert' should be an exclusive-container, but got '" << base.original_string << "'\n" << end();
103 break;
104 }
105 if (!is_literal(inst.ingredients.at(1))) {
106 raise << maybe(caller.name) << "second ingredient of 'maybe-convert' should have type 'variant', but got '" << inst.ingredients.at(1).original_string << "'\n" << end();
107 break;
108 }
109 if (inst.products.empty()) break;
110 if (SIZE(inst.products) != 2) {
111 raise << maybe(caller.name) << "'maybe-convert' expects exactly 2 products in '" << to_original_string(inst) << "'\n" << end();
112 break;
113 }
114 reagent product = inst.products.at(0);
115
116 reagent& offset = inst.ingredients.at(1);
117 populate_value(offset);
118 if (offset.value >= SIZE(get(Type, base_type->value).elements)) {
119 raise << maybe(caller.name) << "invalid tag " << offset.value << " in '" << to_original_string(inst) << '\n' << end();
120 break;
121 }
122 const reagent& variant = variant_type(base, offset.value);
123 if (!types_coercible(product, variant)) {
124 raise << maybe(caller.name) << "'maybe-convert " << base.original_string << ", " << inst.ingredients.at(1).original_string << "' should write to " << to_string(variant.type) << " but '" << product.name << "' has type " << to_string(product.type) << '\n' << end();
125 break;
126 }
127 reagent status = inst.products.at(1);
128
129 if (!is_mu_boolean(status)) {
130 raise << maybe(get(Recipe, r).name) << "second product yielded by 'maybe-convert' should be a boolean, but tried to write to '" << inst.products.at(1).original_string << "'\n" << end();
131 break;
132 }
133 break;
134 }
135 :(before "End Primitive Recipe Implementations")
136 case MAYBE_CONVERT: {
137 reagent base = current_instruction().ingredients.at(0);
138
139 int base_address = base.value;
140 if (base_address == 0) {
141 raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << to_original_string(current_instruction()) << "'\n" << end();
142 break;
143 }
144 int tag = current_instruction().ingredients.at(1).value;
145 reagent product = current_instruction().products.at(0);
146
147 reagent status = current_instruction().products.at(1);
148
149
150 write_products = false;
151 if (tag == static_cast<int>(get_or_insert(Memory, base_address))) {
152 const reagent& variant = variant_type(base, tag);
153 trace("mem") << "storing 1 in location " << status.value << end();
154 put(Memory, status.value, 1);
155 if (!is_dummy(product)) {
156
157 for (int i = 0; i < size_of(variant); ++i) {
158 double val = get_or_insert(Memory, base_address+1+i);
159 trace("mem") << "storing " << no_scientific(val) << " in location " << product.value+i << end();
160 put(Memory, product.value+i, val);
161 }
162 }
163 }
164 else {
165 trace("mem") << "storing 0 in location " << status.value << end();
166 put(Memory, status.value, 0);
167 }
168 break;
169 }
170
171 :(code)
172 const reagent variant_type(const reagent& base, int tag) {
173 return variant_type(base.type, tag);
174 }
175
176 const reagent variant_type(const type_tree* type, int tag) {
177 assert(tag >= 0);
178 const type_tree* root_type = type->atom ? type : type->left;
179 assert(contains_key(Type, root_type->value));
180 assert(!get(Type, root_type->value).name.empty());
181 const type_info& info = get(Type, root_type->value);
182 assert(info.kind == EXCLUSIVE_CONTAINER);
183 reagent element = info.elements.at(tag);
184
185 return element;
186 }
187
188 :(scenario maybe_convert_product_type_mismatch)
189 % Hide_errors = true;
190 def main [
191 12:num <- copy 1
192 13:num <- copy 35
193 14:num <- copy 36
194 20:num, 21:bool <- maybe-convert 12:number-or-point/unsafe, 1:variant
195 ]
196 +error: main: 'maybe-convert 12:number-or-point/unsafe, 1:variant' should write to point but '20' has type number
197
198 :(scenario maybe_convert_dummy_product)
199 def main [
200 12:num <- copy 1
201 13:num <- copy 35
202 14:num <- copy 36
203 _, 21:bool <- maybe-convert 12:number-or-point/unsafe, 1:variant
204 ]
205 $error: 0
206
207
208
209 :(scenario exclusive_container)
210 exclusive-container foo [
211 x:num
212 y:num
213 ]
214 +parse: --- defining exclusive-container foo
215 +parse: element: {x: "number"}
216 +parse: element: {y: "number"}
217
218 :(before "End Command Handlers")
219 else if (command == "exclusive-container") {
220 insert_container(command, EXCLUSIVE_CONTAINER, in);
221 }
222
223
224
225
226 :(scenario exclusive_container_contains_array)
227 exclusive-container foo [
228 x:@:num:3
229 ]
230 $error: 0
231
232 :(scenario exclusive_container_disallows_dynamic_array_element)
233 % Hide_errors = true;
234 exclusive-container foo [
235 x:@:num
236 ]
237 +error: container 'foo' cannot determine size of element 'x'
238
239
240 :(scenario lift_to_exclusive_container)
241 exclusive-container foo [
242 x:num
243 y:num
244 ]
245 def main [
246 1:num <- copy 34
247 2:foo <- merge 0/x, 1:num
248 4:foo <- merge 1/y, 1:num
249 ]
250 +mem: storing 0 in location 2
251 +mem: storing 34 in location 3
252 +mem: storing 1 in location 4
253 +mem: storing 34 in location 5
254
255
256
257 :(scenario merge_handles_exclusive_container)
258 exclusive-container foo [
259 x:num
260 y:bar
261 ]
262 container bar [
263 z:num
264 ]
265 def main [
266 1:foo <- merge 0/x, 34
267 ]
268 +mem: storing 0 in location 1
269 +mem: storing 34 in location 2
270 $error: 0
271
272 :(scenario merge_requires_literal_tag_for_exclusive_container)
273 % Hide_errors = true;
274 exclusive-container foo [
275 x:num
276 y:bar
277 ]
278 container bar [
279 z:num
280 ]
281 def main [
282 1:num <- copy 0
283 2:foo <- merge 1:num, 34
284 ]
285 +error: main: ingredient 0 of 'merge' should be a literal, for the tag of exclusive-container 'foo' in '2:foo <- merge 1:num, 34'
286
287 :(scenario merge_handles_exclusive_container_inside_exclusive_container)
288 exclusive-container foo [
289 x:num
290 y:bar
291 ]
292 exclusive-container bar [
293 a:num
294 b:num
295 ]
296 def main [
297 1:num <- copy 0
298 2:bar <- merge 0/a, 34
299 4:foo <- merge 1/y, 2:bar
300 ]
301 +mem: storing 0 in location 5
302 +mem: storing 34 in location 6
303 $error: 0
304
305 :(before "End check_merge_call Special-cases")
306 case EXCLUSIVE_CONTAINER: {
307 assert(state.data.top().container_element_index == 0);
308 trace("transform") << "checking exclusive container " << to_string(container) << " vs ingredient " << ingredient_index << end();
309
310 if (types_strictly_match(container, inst.ingredients.at(ingredient_index)))
311 return;
312 if (!is_literal(ingredients.at(ingredient_index))) {
313 raise << maybe(caller.name) << "ingredient " << ingredient_index << " of 'merge' should be a literal, for the tag of exclusive-container '" << container_info.name << "' in '" << to_original_string(inst) << "'\n" << end();
314 return;
315 }
316 reagent ingredient = ingredients.at(ingredient_index);
317 populate_value(ingredient);
318 if (ingredient.value >= SIZE(container_info.elements)) {
319 raise << maybe(caller.name) << "invalid tag at " << ingredient_index << " for '" << container_info.name << "' in '" << to_original_string(inst) << "'\n" << end();
320 return;
321 }
322 const reagent& variant = variant_type(container, ingredient.value);
323 trace("transform") << "tag: " << ingredient.value << end();
324
325 state.data.pop();
326 state.data.push(merge_check_point(variant, 0));
327 ++ingredient_index;
328 break;
329 }
330
331 :(scenario merge_check_container_containing_exclusive_container)
332 container foo [
333 x:num
334 y:bar
335 ]
336 exclusive-container bar [
337 x:num
338 y:num
339 ]
340 def main [
341 1:foo <- merge 23, 1/y, 34
342 ]
343 +mem: storing 23 in location 1
344 +mem: storing 1 in location 2
345 +mem: storing 34 in location 3
346 $error: 0
347
348 :(scenario merge_check_container_containing_exclusive_container_2)
349 % Hide_errors = true;
350 container foo [
351 x:num
352 y:bar
353 ]
354 exclusive-container bar [
355 x:num
356 y:num
357 ]
358 def main [
359 1:foo <- merge 23, 1/y, 34, 35
360 ]
361 +error: main: too many ingredients in '1:foo <- merge 23, 1/y, 34, 35'
362
363 :(scenario merge_check_exclusive_container_containing_container)
364 exclusive-container foo [
365 x:num
366 y:bar
367 ]
368 container bar [
369 x:num
370 y:num
371 ]
372 def main [
373 1:foo <- merge 1/y, 23, 34
374 ]
375 +mem: storing 1 in location 1
376 +mem: storing 23 in location 2
377 +mem: storing 34 in location 3
378 $error: 0
379
380 :(scenario merge_check_exclusive_container_containing_container_2)
381 exclusive-container foo [
382 x:num
383 y:bar
384 ]
385 container bar [
386 x:num
387 y:num
388 ]
389 def main [
390 1:foo <- merge 0/x, 23
391 ]
392 $error: 0
393
394 :(scenario merge_check_exclusive_container_containing_container_3)
395 % Hide_errors = true;
396 exclusive-container foo [
397 x:num
398 y:bar
399 ]
400 container bar [
401 x:num
402 y:num
403 ]
404 def main [
405 1:foo <- merge 1/y, 23
406 ]
407 +error: main: too few ingredients in '1:foo <- merge 1/y, 23'
408
409 :(scenario merge_check_exclusive_container_containing_container_4)
410 exclusive-container foo [
411 x:num
412 y:bar
413 ]
414 container bar [
415 a:num
416 b:num
417 ]
418 def main [
419 1:bar <- merge 23, 24
420 3:foo <- merge 1/y, 1:bar
421 ]
422 $error: 0
423
424
425
426 :(before "End size_mismatch(x) Special-cases")
427 if (current_step_index() < SIZE(Current_routine->steps())
428 && current_instruction().operation == MERGE
429 && !current_instruction().products.empty()
430 && current_instruction().products.at(0).type) {
431 reagent x = current_instruction().products.at(0);
432
433 const type_tree* root_type = x.type->atom ? x.type : x.type->left;
434 assert(root_type->atom);
435 if (get(Type, root_type->value).kind == EXCLUSIVE_CONTAINER)
436 return size_of(x) < SIZE(data);
437 }
438
439 :(scenario merge_exclusive_container_with_mismatched_sizes)
440 container foo [
441 x:num
442 y:num
443 ]
444 exclusive-container bar [
445 x:num
446 y:foo
447 ]
448 def main [
449 1:num <- copy 34
450 2:num <- copy 35
451 3:bar <- merge 0/x, 1:num
452 6:bar <- merge 1/foo, 1:num, 2:num
453 ]
454 +mem: storing 0 in location 3
455 +mem: storing 34 in location 4
456
457 +mem: storing 1 in location 6
458 +mem: storing 34 in location 7
459 +mem: storing 35 in location 8