1
2
3
4
5 :(before "End is_mu_container(type) Special-cases")
6 if (!type->atom)
7 return is_mu_container(get_base_type(type));
8 :(before "End is_mu_exclusive_container(type) Special-cases")
9 if (!type->atom)
10 return is_mu_exclusive_container(get_base_type(type));
11 :(after "Update GET base_type in Check")
12 base_type = get_base_type(base_type);
13 :(after "Update GET base_type in Run")
14 base_type = get_base_type(base_type);
15 :(after "Update PUT base_type in Check")
16 base_type = get_base_type(base_type);
17 :(after "Update PUT base_type in Run")
18 base_type = get_base_type(base_type);
19 :(after "Update MAYBE_CONVERT base_type in Check")
20 base_type = get_base_type(base_type);
21 :(after "Update base_type in size_of(type)")
22 base_type = get_base_type(base_type);
23 :(after "Update base_type in element_type")
24 base_type = get_base_type(base_type);
25 :(after "Update base_type in compute_container_address_offsets")
26 base_type = get_base_type(base_type);
27 :(after "Update base_type in append_container_address_offsets")
28 base_type = get_base_type(base_type);
29 :(after "Update element_base_type For Exclusive Container in append_addresses")
30 element_base_type = get_base_type(element_base_type);
31 :(after "Update base_type in skip_addresses")
32 base_type = get_base_type(base_type);
33 :(replace{} "const type_tree* get_base_type(const type_tree* t)")
34 const type_tree* get_base_type(const type_tree* t) {
35 const type_tree* result = t->atom ? t : t->left;
36 if (!result->atom)
37 ¦ raise << "invalid type " << to_string(t) << '\n' << end();
38 return result;
39 }
40
41 :(scenario ill_formed_container)
42 % Hide_errors = true;
43 def main [
44 {1: ((foo) num)} <- copy 0
45 ]
46
47
48 :(scenario size_of_shape_shifting_container)
49 container foo:_t [
50 x:_t
51 y:num
52 ]
53 def main [
54 1:foo:num <- merge 12, 13
55 3:foo:point <- merge 14, 15, 16
56 ]
57 +mem: storing 12 in location 1
58 +mem: storing 13 in location 2
59 +mem: storing 14 in location 3
60 +mem: storing 15 in location 4
61 +mem: storing 16 in location 5
62
63 :(scenario size_of_shape_shifting_container_2)
64
65 container foo:_a:_b [
66 x:_a
67 y:_b
68 ]
69 def main [
70 1:foo:num:bool <- merge 34, 1/true
71 ]
72 $error: 0
73
74 :(scenario size_of_shape_shifting_container_3)
75 container foo:_a:_b [
76 x:_a
77 y:_b
78 ]
79 def main [
80 1:text <- new [abc]
81
82 {2: (foo number (address array character))} <- merge 34/x, 1:text/y
83 ]
84 $error: 0
85
86 :(scenario size_of_shape_shifting_container_4)
87 container foo:_a:_b [
88 x:_a
89 y:_b
90 ]
91 container bar:_a:_b [
92
93 {data: (foo _a (address _b))}
94 ]
95 def main [
96 1:text <- new [abc]
97 2:bar:num:@:char <- merge 34/x, 1:text/y
98 ]
99 $error: 0
100
101 :(scenario shape_shifting_container_extend)
102 container foo:_a [
103 x:_a
104 ]
105 container foo:_a [
106 y:_a
107 ]
108 $error: 0
109
110 :(scenario shape_shifting_container_extend_error)
111 % Hide_errors = true;
112 container foo:_a [
113 x:_a
114 ]
115 container foo:_b [
116 y:_b
117 ]
118 +error: headers of container 'foo' must use identical type ingredients
119
120 :(scenario type_ingredient_must_start_with_underscore)
121 % Hide_errors = true;
122 container foo:t [
123 x:num
124 ]
125 +error: foo: type ingredient 't' must begin with an underscore
126
127 :(before "End Globals")
128
129
130
131
132
133 extern const int START_TYPE_INGREDIENTS = 2000;
134 :(before "End Commandline Parsing")
135 assert(Next_type_ordinal < START_TYPE_INGREDIENTS);
136
137 :(before "End type_info Fields")
138 map<string, type_ordinal> type_ingredient_names;
139
140
141
142 :(before "Check Container Field Types(info)")
143 if (!info.type_ingredient_names.empty()) continue;
144
145 :(before "End container Name Refinements")
146 if (name.find(':') != string::npos) {
147 trace(9999, "parse") << "container has type ingredients; parsing" << end();
148 if (!read_type_ingredients(name, command)) {
149 ¦
150 ¦ slurp_balanced_bracket(in);
151 ¦ return;
152 }
153 }
154
155 :(code)
156 bool read_type_ingredients(string& name, const string& command) {
157 string save_name = name;
158 istringstream in(save_name);
159 name = slurp_until(in, ':');
160 map<string, type_ordinal> type_ingredient_names;
161 if (!slurp_type_ingredients(in, type_ingredient_names, name)) {
162 ¦ return false;
163 }
164 if (contains_key(Type_ordinal, name)
165 ¦ ¦ && contains_key(Type, get(Type_ordinal, name))) {
166 ¦ const type_info& previous_info = get(Type, get(Type_ordinal, name));
167 ¦
168 ¦ if (!type_ingredients_match(type_ingredient_names, previous_info.type_ingredient_names)) {
169 ¦ ¦ raise << "headers of " << command << " '" << name << "' must use identical type ingredients\n" << end();
170 ¦ ¦ return false;
171 ¦ }
172 ¦ return true;
173 }
174
175 if (!contains_key(Type_ordinal, name) || get(Type_ordinal, name) == 0)
176 ¦ put(Type_ordinal, name, Next_type_ordinal++);
177 type_info& info = get_or_insert(Type, get(Type_ordinal, name));
178 info.type_ingredient_names.swap(type_ingredient_names);
179 return true;
180 }
181
182 bool slurp_type_ingredients(istream& in, map<string, type_ordinal>& out, const string& container_name) {
183 int next_type_ordinal = START_TYPE_INGREDIENTS;
184 while (has_data(in)) {
185 ¦ string curr = slurp_until(in, ':');
186 ¦ if (curr.empty()) {
187 ¦ ¦ raise << container_name << ": empty type ingredients not permitted\n" << end();
188 ¦ ¦ return false;
189 ¦ }
190 ¦ if (!starts_with(curr, "_")) {
191 ¦ ¦ raise << container_name << ": type ingredient '" << curr << "' must begin with an underscore\n" << end();
192 ¦ ¦ return false;
193 ¦ }
194 ¦ if (out.find(curr) != out.end()) {
195 ¦ ¦ raise << container_name << ": can't repeat type ingredient name'" << curr << "' in a single container definition\n" << end();
196 ¦ ¦ return false;
197 ¦ }
198 ¦ put(out, curr, next_type_ordinal++);
199 }
200 return true;
201 }
202
203 bool type_ingredients_match(const map<string, type_ordinal>& a, const map<string, type_ordinal>& b) {
204 if (SIZE(a) != SIZE(b)) return false;
205 for (map<string, type_ordinal>::const_iterator p = a.begin(); p != a.end(); ++p) {
206 ¦ if (!contains_key(b, p->first)) return false;
207 ¦ if (p->second != get(b, p->first)) return false;
208 }
209 return true;
210 }
211
212 :(before "End insert_container Special-cases")
213
214 else if (is_type_ingredient_name(type->name)) {
215 type->value = get(info.type_ingredient_names, type->name);
216 }
217 :(code)
218 bool is_type_ingredient_name(const string& type) {
219 return starts_with(type, "_");
220 }
221
222 :(before "End Container Type Checks")
223 if (type->value >= START_TYPE_INGREDIENTS
224 ¦ && (type->value - START_TYPE_INGREDIENTS) < SIZE(get(Type, type->value).type_ingredient_names))
225 return;
226
227 :(scenario size_of_shape_shifting_exclusive_container)
228 exclusive-container foo:_t [
229 x:_t
230 y:num
231 ]
232 def main [
233 1:foo:num <- merge 0/x, 34
234 3:foo:point <- merge 0/x, 15, 16
235 6:foo:point <- merge 1/y, 23
236 ]
237 +run: {1: ("foo" "number")} <- merge {0: "literal", "x": ()}, {34: "literal"}
238 +mem: storing 0 in location 1
239 +mem: storing 34 in location 2
240 +run: {3: ("foo" "point")} <- merge {0: "literal", "x": ()}, {15: "literal"}, {16: "literal"}
241 +mem: storing 0 in location 3
242 +mem: storing 15 in location 4
243 +mem: storing 16 in location 5
244 +run: {6: ("foo" "point")} <- merge {1: "literal", "y": ()}, {23: "literal"}
245 +mem: storing 1 in location 6
246 +mem: storing 23 in location 7
247 +run: return
248
249 % CHECK_EQ(trace_count_prefix("mem", "storing"), 7);
250
251 :(before "End variant_type Special-cases")
252 if (contains_type_ingredient(element))
253 replace_type_ingredients(element.type, type->right, info, " while computing variant type of exclusive-container");
254
255 :(scenario get_on_shape_shifting_container)
256 container foo:_t [
257 x:_t
258 y:num
259 ]
260 def main [
261 1:foo:point <- merge 14, 15, 16
262 2:num <- get 1:foo:point, y:offset
263 ]
264 +mem: storing 16 in location 2
265
266 :(scenario get_on_shape_shifting_container_2)
267 container foo:_t [
268 x:_t
269 y:num
270 ]
271 def main [
272 1:foo:point <- merge 14, 15, 16
273 2:point <- get 1:foo:point, x:offset
274 ]
275 +mem: storing 14 in location 2
276 +mem: storing 15 in location 3
277
278 :(scenario get_on_shape_shifting_container_3)
279 container foo:_t [
280 x:_t
281 y:num
282 ]
283 def main [
284 1:foo:&:point <- merge 34/unsafe, 48
285 3:&:point <- get 1:foo:&:point, x:offset
286 ]
287 +mem: storing 34 in location 3
288
289 :(scenario get_on_shape_shifting_container_inside_container)
290 container foo:_t [
291 x:_t
292 y:num
293 ]
294 container bar [
295 x:foo:point
296 y:num
297 ]
298 def main [
299 1:bar <- merge 14, 15, 16, 17
300 2:num <- get 1:bar, 1:offset
301 ]
302 +mem: storing 17 in location 2
303
304 :(scenario get_on_complex_shape_shifting_container)
305 container foo:_a:_b [
306 x:_a
307 y:_b
308 ]
309 def main [
310 1:text <- new [abc]
311 {2: (foo number (address array character))} <- merge 34/x, 1:text/y
312 3:text <- get {2: (foo number (address array character))}, y:offset
313 4:bool <- equal 1:text, 3:text
314 ]
315 +mem: storing 1 in location 4
316
317 :(before "End element_type Special-cases")
318 replace_type_ingredients(element, type, info, " while computing element type of container");
319 :(before "Compute Container Size(element, full_type)")
320 replace_type_ingredients(element, full_type, container_info, location_for_error_messages);
321 :(before "Compute Exclusive Container Size(element, full_type)")
322 replace_type_ingredients(element, full_type, exclusive_container_info, location_for_error_messages);
323 :(before "Compute Container Address Offset(element)")
324 replace_type_ingredients(element, type, info, location_for_error_messages);
325 if (contains_type_ingredient(element)) return;
326
327 :(after "Compute size_of Container")
328 assert(!contains_type_ingredient(type));
329 :(after "Compute size_of Exclusive Container")
330 assert(!contains_type_ingredient(type));
331
332 :(code)
333 bool contains_type_ingredient(const reagent& x) {
334 return contains_type_ingredient(x.type);
335 }
336
337 bool contains_type_ingredient(const type_tree* type) {
338 if (!type) return false;
339 if (type->atom) return type->value >= START_TYPE_INGREDIENTS;
340 return contains_type_ingredient(type->left) || contains_type_ingredient(type->right);
341 }
342
343 void replace_type_ingredients(reagent& element, const type_tree* caller_type, const type_info& info, const string& location_for_error_messages) {
344 if (contains_type_ingredient(element)) {
345 ¦ if (!caller_type->right)
346 ¦ ¦ raise << "illegal type " << names_to_string(caller_type) << " seems to be missing a type ingredient or three" << location_for_error_messages << '\n' << end();
347 ¦ replace_type_ingredients(element.type, caller_type->right, info, location_for_error_messages);
348 }
349 }
350
351
352 void replace_type_ingredients(type_tree* element_type, const type_tree* callsite_type, const type_info& container_info, const string& location_for_error_messages) {
353 if (!callsite_type) return;
354 if (!element_type) return;
355 if (!element_type->atom) {
356 ¦ if (element_type->right == NULL && is_type_ingredient(element_type->left)) {
357 ¦ ¦ int type_ingredient_index = to_type_ingredient_index(element_type->left);
358 ¦ ¦ if (corresponding(callsite_type, type_ingredient_index, is_final_type_ingredient(type_ingredient_index, container_info))->right) {
359 ¦ ¦ ¦
360 ¦ ¦ ¦ replace_type_ingredient_at(type_ingredient_index, element_type, callsite_type, container_info, location_for_error_messages);
361 ¦ ¦ ¦ return;
362 ¦ ¦ }
363 ¦ }
364 ¦ replace_type_ingredients(element_type->left, callsite_type, container_info, location_for_error_messages);
365 ¦ replace_type_ingredients(element_type->right, callsite_type, container_info, location_for_error_messages);
366 ¦ return;
367 }
368 if (is_type_ingredient(element_type))
369 ¦ replace_type_ingredient_at(to_type_ingredient_index(element_type), element_type, callsite_type, container_info, location_for_error_messages);
370 }
371
372 const type_tree* corresponding(const type_tree* type, int index, bool final) {
373 for (const type_tree* curr = type; curr; curr = curr->right, --index) {
374 ¦ assert_for_now(!curr->atom);
375 ¦ if (index == 0)
376 ¦ ¦ return final ? curr : curr->left;
377 }
378 assert_for_now(false);
379 }
380
381 bool is_type_ingredient(const type_tree* type) {
382 return type->atom && type->value >= START_TYPE_INGREDIENTS;
383 }
384
385 int to_type_ingredient_index(const type_tree* type) {
386 assert(type->atom);
387 return type->value-START_TYPE_INGREDIENTS;
388 }
389
390 void replace_type_ingredient_at(const int type_ingredient_index, type_tree* element_type, const type_tree* callsite_type, const type_info& container_info, const string& location_for_error_messages) {
391 if (!has_nth_type(callsite_type, type_ingredient_index)) {
392 ¦ raise << "illegal type " << names_to_string(callsite_type) << " seems to be missing a type ingredient or three" << location_for_error_messages << '\n' << end();
393 ¦ return;
394 }
395 *element_type = *nth_type_ingredient(callsite_type, type_ingredient_index, container_info);
396 }
397
398 const type_tree* nth_type_ingredient(const type_tree* callsite_type, int type_ingredient_index, const type_info& container_info) {
399 bool final = is_final_type_ingredient(type_ingredient_index, container_info);
400 const type_tree* curr = callsite_type;
401 for (int i = 0; i < type_ingredient_index; ++i) {
402 ¦ assert(curr);
403 ¦ assert(!curr->atom);
404
405 ¦ curr = curr->right;
406 }
407 assert(curr);
408 if (curr->atom) return curr;
409 if (!final) return curr->left;
410 if (!curr->right) return curr->left;
411 return curr;
412 }
413
414 bool is_final_type_ingredient(int type_ingredient_index, const type_info& container_info) {
415 for (map<string, type_ordinal>::const_iterator p = container_info.type_ingredient_names.begin();
416 ¦ ¦ ¦p != container_info.type_ingredient_names.end();
417 ¦ ¦ ¦++p) {
418 ¦ if (p->second > START_TYPE_INGREDIENTS+type_ingredient_index) return false;
419 }
420 return true;
421 }
422
423 :(before "End Unit Tests")
424 void test_replace_type_ingredients_entire() {
425 run("container foo:_elem [\n"
426 ¦ ¦ " x:_elem\n"
427 ¦ ¦ " y:num\n"
428 ¦ ¦ "]\n");
429 reagent callsite("x:foo:point");
430 reagent element = element_type(callsite.type, 0);
431 CHECK_EQ(to_string(element), "{x: \"point\"}");
432 }
433
434 void test_replace_type_ingredients_tail() {
435 run("container foo:_elem [\n"
436 ¦ ¦ " x:_elem\n"
437 ¦ ¦ "]\n"
438 ¦ ¦ "container bar:_elem [\n"
439 ¦ ¦ " x:foo:_elem\n"
440 ¦ ¦ "]\n");
441 reagent callsite("x:bar:point");
442 reagent element = element_type(callsite.type, 0);
443 CHECK_EQ(to_string(element), "{x: (\"foo\" \"point\")}");
444 }
445
446 void test_replace_type_ingredients_head_tail_multiple() {
447 run("container foo:_elem [\n"
448 ¦ ¦ " x:_elem\n"
449 ¦ ¦ "]\n"
450 ¦ ¦ "container bar:_elem [\n"
451 ¦ ¦ " x:foo:_elem\n"
452 ¦ ¦ "]\n");
453 reagent callsite("x:bar:address:array:character");
454 reagent element = element_type(callsite.type, 0);
455 CHECK_EQ(to_string(element), "{x: (\"foo\" \"address\" \"array\" \"character\")}");
456 }
457
458 void test_replace_type_ingredients_head_middle() {
459 run("container foo:_elem [\n"
460 ¦ ¦ " x:_elem\n"
461 ¦ ¦ "]\n"
462 ¦ ¦ "container bar:_elem [\n"
463 ¦ ¦ " x:foo:_elem:num\n"
464 ¦ ¦ "]\n");
465 reagent callsite("x:bar:address");
466 reagent element = element_type(callsite.type, 0);
467 CHECK_EQ(to_string(element), "{x: (\"foo\" \"address\" \"number\")}");
468 }
469
470 void test_replace_last_type_ingredient_with_multiple() {
471 run("container foo:_a:_b [\n"
472 ¦ ¦ " x:_a\n"
473 ¦ ¦ " y:_b\n"
474 ¦ ¦ "]\n");
475 reagent callsite("{f: (foo number (address array character))}");
476 reagent element1 = element_type(callsite.type, 0);
477 CHECK_EQ(to_string(element1), "{x: \"number\"}");
478 reagent element2 = element_type(callsite.type, 1);
479 CHECK_EQ(to_string(element2), "{y: (\"address\" \"array\" \"character\")}");
480 }
481
482 void test_replace_last_type_ingredient_inside_compound() {
483 run("container foo:_a:_b [\n"
484 ¦ ¦ " {x: (bar _a (address _b))}\n"
485 ¦ ¦ "]\n");
486 reagent callsite("f:foo:number:array:character");
487 reagent element = element_type(callsite.type, 0);
488 CHECK_EQ(names_to_string_without_quotes(element.type), "(bar number (address array character))");
489 }
490
491 void test_replace_middle_type_ingredient_with_multiple() {
492 run("container foo:_a:_b:_c [\n"
493 ¦ ¦ " x:_a\n"
494 ¦ ¦ " y:_b\n"
495 ¦ ¦ " z:_c\n"
496 ¦ ¦ "]\n");
497 reagent callsite("{f: (foo number (address array character) boolean)}");
498 reagent element1 = element_type(callsite.type, 0);
499 CHECK_EQ(to_string(element1), "{x: \"number\"}");
500 reagent element2 = element_type(callsite.type, 1);
501 CHECK_EQ(to_string(element2), "{y: (\"address\" \"array\" \"character\")}");
502 reagent element3 = element_type(callsite.type, 2);
503 CHECK_EQ(to_string(element3), "{z: \"boolean\"}");
504 }
505
506 void test_replace_middle_type_ingredient_with_multiple2() {
507 run("container foo:_key:_value [\n"
508 ¦ ¦ " key:_key\n"
509 ¦ ¦ " value:_value\n"
510 ¦ ¦ "]\n");
511 reagent callsite("{f: (foo (address array character) number)}");
512 reagent element = element_type(callsite.type, 0);
513 CHECK_EQ(to_string(element), "{key: (\"address\" \"array\" \"character\")}");
514 }
515
516 void test_replace_middle_type_ingredient_with_multiple3() {
517 run("container foo_table:_key:_value [\n"
518 ¦ ¦ " data:&:@:foo_table_row:_key:_value\n"
519 ¦ ¦ "]\n"
520 ¦ ¦ "\n"
521 ¦ ¦ "container foo_table_row:_key:_value [\n"
522 ¦ ¦ " key:_key\n"
523 ¦ ¦ " value:_value\n"
524 ¦ ¦ "]\n");
525 reagent callsite("{f: (foo_table (address array character) number)}");
526 reagent element = element_type(callsite.type, 0);
527 CHECK_EQ(to_string(element), "{data: (\"address\" \"array\" \"foo_table_row\" (\"address\" \"array\" \"character\") \"number\")}");
528 }
529
530 :(code)
531 bool has_nth_type(const type_tree* base, int n) {
532 assert(n >= 0);
533 if (!base) return false;
534 if (n == 0) return true;
535 return has_nth_type(base->right, n-1);
536 }
537
538 :(scenario get_on_shape_shifting_container_error)
539 % Hide_errors = true;
540 container foo:_t [
541 x:_t
542 y:num
543 ]
544 def main [
545 10:foo:point <- merge 14, 15, 16
546 1:num <- get 10:foo, 1:offset
547 ]
548 +error: illegal type "foo" seems to be missing a type ingredient or three in '1:num <- get 10:foo, 1:offset'
549
550
551
552
553
554
555
556 :(before "End compute_container_sizes Non-atom Special-cases")
557 const type_tree* root = get_base_type(type);
558 if (contains_key(Type, root->value)) {
559 type_info& info = get(Type, root->value);
560 if (info.kind == CONTAINER) {
561 ¦ compute_container_sizes(info, type, pending_metadata, location_for_error_messages);
562 ¦ return;
563 }
564 if (info.kind == EXCLUSIVE_CONTAINER) {
565 ¦ compute_exclusive_container_sizes(info, type, pending_metadata, location_for_error_messages);
566 ¦ return;
567 }
568 }
569
570 :(before "End Unit Tests")
571 void test_container_sizes_shape_shifting_container() {
572 run("container foo:_t [\n"
573 ¦ ¦ " x:num\n"
574 ¦ ¦ " y:_t\n"
575 ¦ ¦ "]\n");
576 reagent r("x:foo:point");
577 compute_container_sizes(r, "");
578 CHECK_EQ(r.metadata.size, 3);
579 }
580
581 void test_container_sizes_shape_shifting_exclusive_container() {
582 run("exclusive-container foo:_t [\n"
583 ¦ ¦ " x:num\n"
584 ¦ ¦ " y:_t\n"
585 ¦ ¦ "]\n");
586 reagent r("x:foo:point");
587 compute_container_sizes(r, "");
588 CHECK_EQ(r.metadata.size, 3);
589 reagent r2("x:foo:num");
590 compute_container_sizes(r2, "");
591 CHECK_EQ(r2.metadata.size, 2);
592 }
593
594 void test_container_sizes_compound_type_ingredient() {
595 run("container foo:_t [\n"
596 ¦ ¦ " x:num\n"
597 ¦ ¦ " y:_t\n"
598 ¦ ¦ "]\n");
599 reagent r("x:foo:&:point");
600 compute_container_sizes(r, "");
601 CHECK_EQ(r.metadata.size, 2);
602
603 reagent point("x:point");
604 CHECK(contains_key(Container_metadata, point.type));
605 CHECK_EQ(get(Container_metadata, point.type).size, 2);
606 }
607
608 void test_container_sizes_recursive_shape_shifting_container() {
609 run("container foo:_t [\n"
610 ¦ ¦ " x:num\n"
611 ¦ ¦ " y:&:foo:_t\n"
612 ¦ ¦ "]\n");
613 reagent r2("x:foo:num");
614 compute_container_sizes(r2, "");
615 CHECK_EQ(r2.metadata.size, 2);
616 }
617
618 :(before "End compute_container_address_offsets Non-atom Special-cases")
619 const type_tree* root = get_base_type(type);
620 type_info& info = get(Type, root->value);
621 if (info.kind == CONTAINER) {
622 compute_container_address_offsets(info, type, location_for_error_messages);
623 return;
624 }
625 if (info.kind == EXCLUSIVE_CONTAINER) {
626 compute_exclusive_container_address_offsets(info, type, location_for_error_messages);
627 return;
628 }
629
630 :(before "End Unit Tests")
631 void test_container_address_offsets_in_shape_shifting_container() {
632 run("container foo:_t [\n"
633 ¦ ¦ " x:num\n"
634 ¦ ¦ " y:_t\n"
635 ¦ ¦ "]\n");
636 reagent r("x:foo:&:num");
637 compute_container_sizes(r, "");
638 compute_container_address_offsets(r, "");
639 CHECK_EQ(SIZE(r.metadata.address), 1);
640 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
641 set<address_element_info>& offset_info = get(r.metadata.address, set<tag_condition_info>());
642 CHECK_EQ(SIZE(offset_info), 1);
643 CHECK_EQ(offset_info.begin()->offset, 1);
644 CHECK(offset_info.begin()->payload_type->atom);
645 CHECK_EQ(offset_info.begin()->payload_type->name, "number");
646 }
647
648 void test_container_address_offsets_in_nested_shape_shifting_container() {
649 run("container foo:_t [\n"
650 ¦ ¦ " x:num\n"
651 ¦ ¦ " y:_t\n"
652 ¦ ¦ "]\n"
653 ¦ ¦ "container bar:_t [\n"
654 ¦ ¦ " x:_t\n"
655 ¦ ¦ " y:foo:_t\n"
656 ¦ ¦ "]\n");
657 reagent r("x:bar:&:num");
658 CLEAR_TRACE;
659 compute_container_sizes(r, "");
660 compute_container_address_offsets(r, "");
661 CHECK_EQ(SIZE(r.metadata.address), 1);
662 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
663 set<address_element_info>& offset_info = get(r.metadata.address, set<tag_condition_info>());
664 CHECK_EQ(SIZE(offset_info), 2);
665 CHECK_EQ(offset_info.begin()->offset, 0);
666 CHECK(offset_info.begin()->payload_type->atom);
667 CHECK_EQ(offset_info.begin()->payload_type->name, "number");
668 CHECK_EQ((++offset_info.begin())->offset, 2);
669 CHECK((++offset_info.begin())->payload_type->atom);
670 CHECK_EQ((++offset_info.begin())->payload_type->name, "number");
671 }
672
673
674
675 :(scenario merge_check_shape_shifting_container_containing_exclusive_container)
676 container foo:_elem [
677 x:num
678 y:_elem
679 ]
680 exclusive-container bar [
681 x:num
682 y:num
683 ]
684 def main [
685 1:foo:bar <- merge 23, 1/y, 34
686 ]
687 +mem: storing 23 in location 1
688 +mem: storing 1 in location 2
689 +mem: storing 34 in location 3
690 $error: 0
691
692 :(scenario merge_check_shape_shifting_container_containing_exclusive_container_2)
693 % Hide_errors = true;
694 container foo:_elem [
695 x:num
696 y:_elem
697 ]
698 exclusive-container bar [
699 x:num
700 y:num
701 ]
702 def main [
703 1:foo:bar <- merge 23, 1/y, 34, 35
704 ]
705 +error: main: too many ingredients in '1:foo:bar <- merge 23, 1/y, 34, 35'
706
707 :(scenario merge_check_shape_shifting_exclusive_container_containing_container)
708 exclusive-container foo:_elem [
709 x:num
710 y:_elem
711 ]
712 container bar [
713 x:num
714 y:num
715 ]
716 def main [
717 1:foo:bar <- merge 1/y, 23, 34
718 ]
719 +mem: storing 1 in location 1
720 +mem: storing 23 in location 2
721 +mem: storing 34 in location 3
722 $error: 0
723
724 :(scenario merge_check_shape_shifting_exclusive_container_containing_container_2)
725 exclusive-container foo:_elem [
726 x:num
727 y:_elem
728 ]
729 container bar [
730 x:num
731 y:num
732 ]
733 def main [
734 1:foo:bar <- merge 0/x, 23
735 ]
736 $error: 0
737
738 :(scenario merge_check_shape_shifting_exclusive_container_containing_container_3)
739 % Hide_errors = true;
740 exclusive-container foo:_elem [
741 x:num
742 y:_elem
743 ]
744 container bar [
745 x:num
746 y:num
747 ]
748 def main [
749 1:foo:bar <- merge 1/y, 23
750 ]
751 +error: main: too few ingredients in '1:foo:bar <- merge 1/y, 23'