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