From 5fe060d582d4a82444243a28b18085c971a85628 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 27 Jul 2018 17:07:52 -0700 Subject: 4447 --- html/021check_instruction.cc.html | 368 +++++++++++++++++--------------------- 1 file changed, 162 insertions(+), 206 deletions(-) (limited to 'html/021check_instruction.cc.html') diff --git a/html/021check_instruction.cc.html b/html/021check_instruction.cc.html index 2e20d819..b9b5109c 100644 --- a/html/021check_instruction.cc.html +++ b/html/021check_instruction.cc.html @@ -75,21 +75,21 @@ if ('onhashchange' in window) { 13 14 :(code) 15 void check_instruction(const recipe_ordinal r) { - 16 trace(9991, "transform") << "--- perform checks for recipe " << get(Recipe, r).name << end(); + 16 trace(9991, "transform") << "--- perform checks for recipe " << get(Recipe, r).name << end(); 17 map<string, vector<type_ordinal> > metadata; 18 for (int i = 0; i < SIZE(get(Recipe, r).steps); ++i) { 19 instruction& inst = get(Recipe, r).steps.at(i); 20 if (inst.is_label) continue; 21 switch (inst.operation) { 22 // Primitive Recipe Checks - 23 case COPY: { + 23 case COPY: { 24 if (SIZE(inst.products) > SIZE(inst.ingredients)) { - 25 raise << maybe(get(Recipe, r).name) << "too many products in '" << to_original_string(inst) << "'\n" << end(); + 25 raise << maybe(get(Recipe, r).name) << "too many products in '" << to_original_string(inst) << "'\n" << end(); 26 break; 27 } 28 for (int i = 0; i < SIZE(inst.products); ++i) { 29 if (!types_coercible(inst.products.at(i), inst.ingredients.at(i))) { - 30 raise << maybe(get(Recipe, r).name) << "can't copy '" << inst.ingredients.at(i).original_string << "' to '" << inst.products.at(i).original_string << "'; types don't match\n" << end(); + 30 raise << maybe(get(Recipe, r).name) << "can't copy '" << inst.ingredients.at(i).original_string << "' to '" << inst.products.at(i).original_string << "'; types don't match\n" << end(); 31 goto finish_checking_instruction; 32 } 33 } @@ -129,213 +129,169 @@ if ('onhashchange' in window) { 67 :(scenario write_scalar_to_address_disallowed) 68 % Hide_errors = true; 69 def main [ - 70 1:address:num <- copy 34 + 70 1:&:num <- copy 34 71 ] - 72 +error: main: can't copy '34' to '1:address:num'; types don't match + 72 +error: main: can't copy '34' to '1:&:num'; types don't match 73 - 74 :(scenario write_address_to_number_allowed) - 75 def main [ - 76 1:address:num <- copy 12/unsafe - 77 2:num <- copy 1:address:num - 78 ] - 79 +mem: storing 12 in location 2 - 80 $error: 0 + 74 :(scenario write_address_to_character_disallowed) + 75 % Hide_errors = true; + 76 def main [ + 77 1:&:num <- copy 12/unsafe + 78 2:char <- copy 1:&:num + 79 ] + 80 +error: main: can't copy '1:&:num' to '2:char'; types don't match 81 - 82 :(scenario write_address_to_character_disallowed) - 83 % Hide_errors = true; - 84 def main [ - 85 1:address:num <- copy 12/unsafe - 86 2:char <- copy 1:address:num - 87 ] - 88 +error: main: can't copy '1:address:num' to '2:char'; types don't match - 89 - 90 :(scenario write_number_to_character_allowed) - 91 def main [ - 92 1:num <- copy 97 - 93 2:char <- copy 1:num - 94 ] - 95 $error: 0 - 96 - 97 :(scenario write_boolean_to_number_allowed) - 98 def main [ - 99 1:bool <- copy 1/true -100 2:num <- copy 1:bool -101 ] -102 +mem: storing 1 in location 2 -103 $error: 0 -104 -105 :(scenario write_number_to_boolean_disallowed) -106 % Hide_errors = true; -107 def main [ -108 1:num <- copy 34 -109 2:bool <- copy 1:num -110 ] -111 +error: main: can't copy '1:num' to '2:bool'; types don't match -112 -113 :(code) -114 // types_match with some leniency -115 bool types_coercible(const reagent& to, const reagent& from) { -116 if (types_match(to, from)) return true; -117 if (is_mu_address(from) && is_real_mu_number(to)) return true; -118 if (is_mu_boolean(from) && is_real_mu_number(to)) return true; -119 if (is_real_mu_number(from) && is_mu_character(to)) return true; -120 // End types_coercible Special-cases -121 return false; -122 } -123 -124 bool types_match(const reagent& to, const reagent& from) { -125 // to sidestep type-checking, use /unsafe in the source. -126 // this will be highlighted in red inside vim. just for setting up some tests. -127 if (is_unsafe(from)) return true; -128 if (is_literal(from)) { -129 if (is_mu_array(to)) return false; -130 // End Matching Types For Literal(to) -131 // allow writing 0 to any address -132 if (is_mu_address(to)) return from.name == "0"; -133 if (!to.type) return false; -134 if (is_mu_boolean(to)) return from.name == "0" || from.name == "1"; -135 return size_of(to) == 1; // literals are always scalars -136 } -137 return types_strictly_match(to, from); -138 } -139 -140 //: copy arguments for later layers -141 bool types_strictly_match(reagent/*copy*/ to, reagent/*copy*/ from) { -142 // End Preprocess types_strictly_match(reagent to, reagent from) -143 if (to.type == NULL) return false; // error -144 if (is_literal(from) && to.type->value == Number_type_ordinal) return true; -145 // to sidestep type-checking, use /unsafe in the source. -146 // this will be highlighted in red inside vim. just for setting up some tests. -147 if (is_unsafe(from)) return true; -148 // '_' never raises type error -149 if (is_dummy(to)) return true; -150 if (!to.type) return !from.type; -151 return types_strictly_match(to.type, from.type); + 82 :(scenario write_number_to_character_allowed) + 83 def main [ + 84 1:num <- copy 97 + 85 2:char <- copy 1:num + 86 ] + 87 $error: 0 + 88 + 89 :(code) + 90 // types_match with some leniency + 91 bool types_coercible(reagent/*copy*/ to, reagent/*copy*/ from) { + 92 // Begin types_coercible(reagent to, reagent from) + 93 if (types_match_sub(to, from)) return true; + 94 if (is_real_mu_number(from) && is_mu_character(to)) return true; + 95 // End types_coercible Special-cases + 96 return false; + 97 } + 98 + 99 bool types_match_sub(const reagent& to, const reagent& from) { +100 // to sidestep type-checking, use /unsafe in the source. +101 // this will be highlighted in red inside vim. just for setting up some tests. +102 if (is_unsafe(from)) return true; +103 if (is_literal(from)) { +104 if (is_mu_array(to)) return false; +105 // End Matching Types For Literal(to) +106 if (!to.type) return false; +107 // allow writing null to any address +108 if (is_mu_address(to)) return from.name == "null"; +109 return size_of(to) == 1; // literals are always scalars +110 } +111 return types_strictly_match_sub(to, from); +112 } +113 // variant for others to call +114 bool types_match(reagent/*copy*/ to, reagent/*copy*/ from) { +115 // Begin types_match(reagent to, reagent from) +116 return types_match_sub(to, from); +117 } +118 +119 //: copy arguments for later layers +120 bool types_strictly_match_sub(const reagent& to, const reagent& from) { +121 if (to.type == NULL) return false; // error +122 if (is_literal(from) && to.type->value == Number_type_ordinal) return true; +123 // to sidestep type-checking, use /unsafe in the source. +124 // this will be highlighted in red inside vim. just for setting up some tests. +125 if (is_unsafe(from)) return true; +126 // '_' never raises type error +127 if (is_dummy(to)) return true; +128 if (!to.type) return !from.type; +129 return types_strictly_match(to.type, from.type); +130 } +131 // variant for others to call +132 bool types_strictly_match(reagent/*copy*/ to, reagent/*copy*/ from) { +133 // Begin types_strictly_match(reagent to, reagent from) +134 return types_strictly_match_sub(to, from); +135 } +136 +137 bool types_strictly_match(const type_tree* to, const type_tree* from) { +138 if (from == to) return true; +139 if (!to) return false; +140 if (!from) return to->atom && to->value == 0; +141 if (from->atom != to->atom) return false; +142 if (from->atom) { +143 if (from->value == -1) return from->name == to->name; +144 return from->value == to->value; +145 } +146 if (types_strictly_match(to->left, from->left) && types_strictly_match(to->right, from->right)) +147 return true; +148 // fallback: (x) == x +149 if (to->right == NULL && types_strictly_match(to->left, from)) return true; +150 if (from->right == NULL && types_strictly_match(to, from->left)) return true; +151 return false; 152 } 153 -154 bool types_strictly_match(const type_tree* to, const type_tree* from) { -155 if (from == to) return true; -156 if (!to) return false; -157 if (!from) return to->atom && to->value == 0; -158 if (from->atom != to->atom) return false; -159 if (from->atom) { -160 if (from->value == -1) return from->name == to->name; -161 return from->value == to->value; -162 } -163 if (types_strictly_match(to->left, from->left) && types_strictly_match(to->right, from->right)) -164 return true; -165 // fallback: (x) == x -166 if (to->right == NULL && types_strictly_match(to->left, from)) return true; -167 if (from->right == NULL && types_strictly_match(to, from->left)) return true; -168 return false; -169 } -170 -171 void test_unknown_type_does_not_match_unknown_type() { -172 reagent a("a:foo"); -173 reagent b("b:bar"); -174 CHECK(!types_strictly_match(a, b)); -175 } -176 -177 void test_unknown_type_matches_itself() { -178 reagent a("a:foo"); -179 reagent b("b:foo"); -180 CHECK(types_strictly_match(a, b)); -181 } -182 -183 void test_type_abbreviations_match_raw_types() { -184 put(Type_abbreviations, "text", new_type_tree("address:array:character")); -185 // a has type (address buffer (address array character)) -186 reagent a("a:address:buffer:text"); -187 expand_type_abbreviations(a.type); -188 // b has type (address buffer address array character) -189 reagent b("b:address:buffer:address:array:character"); -190 CHECK(types_strictly_match(a, b)); -191 delete Type_abbreviations["text"]; -192 put(Type_abbreviations, "text", NULL); -193 } -194 -195 //: helpers -196 -197 bool is_unsafe(const reagent& r) { -198 return has_property(r, "unsafe"); -199 } -200 -201 bool is_mu_array(reagent/*copy*/ r) { -202 // End Preprocess is_mu_array(reagent r) -203 return is_mu_array(r.type); -204 } -205 bool is_mu_array(const type_tree* type) { -206 if (!type) return false; -207 if (is_literal(type)) return false; -208 if (type->atom) return false; -209 if (!type->left->atom) { -210 raise << "invalid type " << to_string(type) << '\n' << end(); -211 return false; -212 } -213 return type->left->value == Array_type_ordinal; -214 } -215 -216 bool is_mu_address(reagent/*copy*/ r) { -217 // End Preprocess is_mu_address(reagent r) -218 return is_mu_address(r.type); -219 } -220 bool is_mu_address(const type_tree* type) { -221 if (!type) return false; -222 if (is_literal(type)) return false; -223 if (type->atom) return false; -224 if (!type->left->atom) { -225 raise << "invalid type " << to_string(type) << '\n' << end(); -226 return false; -227 } -228 return type->left->value == Address_type_ordinal; -229 } -230 -231 bool is_mu_boolean(reagent/*copy*/ r) { -232 // End Preprocess is_mu_boolean(reagent r) -233 if (!r.type) return false; -234 if (is_literal(r)) return false; -235 if (!r.type->atom) return false; -236 return r.type->value == Boolean_type_ordinal; -237 } -238 -239 bool is_mu_number(reagent/*copy*/ r) { -240 if (is_mu_character(r.type)) return true; // permit arithmetic on unicode code points -241 return is_real_mu_number(r); -242 } -243 -244 bool is_real_mu_number(reagent/*copy*/ r) { -245 // End Preprocess is_mu_number(reagent r) -246 if (!r.type) return false; -247 if (!r.type->atom) return false; -248 if (is_literal(r)) { -249 return r.type->name == "literal-fractional-number" -250 || r.type->name == "literal"; -251 } -252 return r.type->value == Number_type_ordinal; -253 } -254 -255 bool is_mu_character(reagent/*copy*/ r) { -256 // End Preprocess is_mu_character(reagent r) -257 return is_mu_character(r.type); -258 } -259 bool is_mu_character(const type_tree* type) { -260 if (!type) return false; -261 if (!type->atom) return false; -262 if (is_literal(type)) return false; -263 return type->value == Character_type_ordinal; -264 } -265 -266 bool is_mu_scalar(reagent/*copy*/ r) { -267 return is_mu_scalar(r.type); -268 } -269 bool is_mu_scalar(const type_tree* type) { -270 if (!type) return false; -271 if (is_mu_address(type)) return true; -272 if (!type->atom) return false; -273 if (is_literal(type)) -274 return type->name != "literal-string"; -275 return size_of(type) == 1; -276 } +154 void test_unknown_type_does_not_match_unknown_type() { +155 reagent a("a:foo"); +156 reagent b("b:bar"); +157 CHECK(!types_strictly_match(a, b)); +158 } +159 +160 void test_unknown_type_matches_itself() { +161 reagent a("a:foo"); +162 reagent b("b:foo"); +163 CHECK(types_strictly_match(a, b)); +164 } +165 +166 void test_type_abbreviations_match_raw_types() { +167 put(Type_abbreviations, "text", new_type_tree("address:array:character")); +168 // a has type (address buffer (address array character)) +169 reagent a("a:address:buffer:text"); +170 expand_type_abbreviations(a.type); +171 // b has type (address buffer address array character) +172 reagent b("b:address:buffer:address:array:character"); +173 CHECK(types_strictly_match(a, b)); +174 delete Type_abbreviations["text"]; +175 put(Type_abbreviations, "text", NULL); +176 } +177 +178 //: helpers +179 +180 bool is_unsafe(const reagent& r) { +181 return has_property(r, "unsafe"); +182 } +183 +184 bool is_mu_array(reagent/*copy*/ r) { +185 // End Preprocess is_mu_array(reagent r) +186 return is_mu_array(r.type); +187 } +188 bool is_mu_array(const type_tree* type) { +189 if (!type) return false; +190 if (is_literal(type)) return false; +191 if (type->atom) return false; +192 if (!type->left->atom) { +193 raise << "invalid type " << to_string(type) << '\n' << end(); +194 return false; +195 } +196 return type->left->value == Array_type_ordinal; +197 } +198 +199 bool is_mu_boolean(reagent/*copy*/ r) { +200 // End Preprocess is_mu_boolean(reagent r) +201 if (!r.type) return false; +202 if (is_literal(r)) return false; +203 if (!r.type->atom) return false; +204 return r.type->value == Boolean_type_ordinal; +205 } +206 +207 bool is_mu_number(reagent/*copy*/ r) { +208 if (is_mu_character(r.type)) return true; // permit arithmetic on unicode code points +209 return is_real_mu_number(r); +210 } +211 +212 bool is_real_mu_number(reagent/*copy*/ r) { +213 // End Preprocess is_mu_number(reagent r) +214 if (!r.type) return false; +215 if (!r.type->atom) return false; +216 if (is_literal(r)) { +217 return r.type->name == "literal-fractional-number" +218 || r.type->name == "literal"; +219 } +220 return r.type->value == Number_type_ordinal; +221 } +222 +223 bool is_mu_character(reagent/*copy*/ r) { +224 // End Preprocess is_mu_character(reagent r) +225 return is_mu_character(r.type); +226 } +227 bool is_mu_character(const type_tree* type) { +228 if (!type) return false; +229 if (!type->atom) return false; +230 if (is_literal(type)) return false; +231 return type->value == Character_type_ordinal; +232 } -- cgit 1.4.1-2-gfad0