From 87c5b32925549f05d950ad07c935417ef7eeebb9 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sun, 3 Sep 2017 17:35:22 -0700 Subject: 3990 --- html/071recipe.cc.html | 365 +++++++++++++++++++++++++------------------------ 1 file changed, 184 insertions(+), 181 deletions(-) (limited to 'html/071recipe.cc.html') diff --git a/html/071recipe.cc.html b/html/071recipe.cc.html index fec9a6f7..fd82590d 100644 --- a/html/071recipe.cc.html +++ b/html/071recipe.cc.html @@ -272,189 +272,192 @@ if ('onhashchange' in window) { 208 assert(r.type); 209 recipe result_header; // will contain only ingredients and products, nothing else 210 result_header.has_header = true; -211 if (r.type->atom) { -212 ¦ assert(r.type->name == "recipe"); -213 ¦ return result_header; -214 } -215 const type_tree* root_type = r.type->atom ? r.type : r.type->left; -216 assert(root_type->atom); -217 assert(root_type->name == "recipe"); -218 const type_tree* curr = r.type->right; -219 for (/*nada*/; curr && !curr->atom; curr = curr->right) { -220 ¦ if (curr->left->atom && curr->left->name == "->") { -221 ¦ ¦ curr = curr->right; // skip delimiter -222 ¦ ¦ goto read_products; -223 ¦ } -224 ¦ result_header.ingredients.push_back(next_recipe_reagent(curr->left)); -225 } -226 if (curr) { -227 ¦ assert(curr->atom); -228 ¦ result_header.ingredients.push_back(next_recipe_reagent(curr)); -229 ¦ return result_header; // no products -230 } -231 read_products: -232 for (/*nada*/; curr && !curr->atom; curr = curr->right) -233 ¦ result_header.products.push_back(next_recipe_reagent(curr->left)); -234 if (curr) { -235 ¦ assert(curr->atom); -236 ¦ result_header.products.push_back(next_recipe_reagent(curr)); -237 } -238 return result_header; -239 } -240 -241 :(before "End Unit Tests") -242 void test_from_reagent_atomic() { -243 reagent a("{f: recipe}"); -244 recipe r_header = from_reagent(a); -245 CHECK(r_header.ingredients.empty()); -246 CHECK(r_header.products.empty()); -247 } -248 void test_from_reagent_non_atomic() { -249 reagent a("{f: (recipe number -> number)}"); -250 recipe r_header = from_reagent(a); -251 CHECK_EQ(SIZE(r_header.ingredients), 1); -252 CHECK_EQ(SIZE(r_header.products), 1); -253 } -254 void test_from_reagent_reads_ingredient_at_end() { -255 reagent a("{f: (recipe number number)}"); -256 recipe r_header = from_reagent(a); -257 CHECK_EQ(SIZE(r_header.ingredients), 2); -258 CHECK(r_header.products.empty()); -259 } -260 void test_from_reagent_reads_sole_ingredient_at_end() { -261 reagent a("{f: (recipe number)}"); -262 recipe r_header = from_reagent(a); -263 CHECK_EQ(SIZE(r_header.ingredients), 1); -264 CHECK(r_header.products.empty()); -265 } -266 -267 :(code) -268 reagent next_recipe_reagent(const type_tree* curr) { -269 if (!curr->left) return reagent("recipe:"+curr->name); -270 reagent result; -271 result.name = "recipe"; -272 result.type = new type_tree(*curr); -273 return result; -274 } -275 -276 bool is_mu_recipe(const reagent& r) { -277 if (!r.type) return false; -278 if (r.type->atom) -279 ¦ return r.type->name == "recipe-literal"; -280 return r.type->left->atom && r.type->left->name == "recipe"; -281 } -282 -283 :(scenario copy_typecheck_recipe_variable) -284 % Hide_errors = true; -285 def main [ -286 3:num <- copy 34 # abc def -287 {1: (recipe number -> number)} <- copy f # store literal in a matching variable -288 {2: (recipe boolean -> boolean)} <- copy {1: (recipe number -> number)} # mismatch between recipe variables -289 ] -290 def f x:num -> y:num [ -291 local-scope -292 load-ingredients -293 y <- copy x -294 ] -295 +error: main: can't copy '{1: (recipe number -> number)}' to '{2: (recipe boolean -> boolean)}'; types don't match -296 -297 :(scenario copy_typecheck_recipe_variable_2) -298 % Hide_errors = true; -299 def main [ -300 {1: (recipe number -> number)} <- copy f # mismatch with a recipe literal -301 ] -302 def f x:bool -> y:bool [ -303 local-scope -304 load-ingredients -305 y <- copy x -306 ] -307 +error: main: can't copy 'f' to '{1: (recipe number -> number)}'; types don't match -308 -309 :(before "End Matching Types For Literal(to)") -310 if (is_mu_recipe(to)) { -311 if (!contains_key(Recipe, from.value)) { -312 ¦ raise << "trying to store recipe " << from.name << " into " << to_string(to) << " but there's no such recipe\n" << end(); -313 ¦ return false; -314 } -315 const recipe& rrhs = get(Recipe, from.value); -316 const recipe& rlhs = from_reagent(to); -317 for (long int i = 0; i < min(SIZE(rlhs.ingredients), SIZE(rrhs.ingredients)); ++i) { -318 ¦ if (!types_match(rlhs.ingredients.at(i), rrhs.ingredients.at(i))) -319 ¦ ¦ return false; -320 } -321 for (long int i = 0; i < min(SIZE(rlhs.products), SIZE(rrhs.products)); ++i) { -322 ¦ if (!types_match(rlhs.products.at(i), rrhs.products.at(i))) -323 ¦ ¦ return false; -324 } -325 return true; -326 } -327 -328 :(scenario call_variable_compound_ingredient) -329 def main [ -330 {1: (recipe (address number) -> number)} <- copy f -331 2:&:num <- copy 0 -332 3:num <- call {1: (recipe (address number) -> number)}, 2:&:num -333 ] -334 def f x:&:num -> y:num [ -335 local-scope -336 load-ingredients -337 y <- copy x -338 ] -339 $error: 0 -340 -341 //: make sure we don't accidentally break on a function literal -342 :(scenario jump_forbidden_on_recipe_literals) -343 % Hide_errors = true; -344 def foo [ -345 local-scope -346 ] -347 def main [ +211 // Begin Reagent->Recipe(r, recipe_header) +212 if (r.type->atom) { +213 ¦ assert(r.type->name == "recipe"); +214 ¦ return result_header; +215 } +216 const type_tree* root_type = r.type->atom ? r.type : r.type->left; +217 assert(root_type->atom); +218 assert(root_type->name == "recipe"); +219 const type_tree* curr = r.type->right; +220 for (/*nada*/; curr && !curr->atom; curr = curr->right) { +221 ¦ if (curr->left->atom && curr->left->name == "->") { +222 ¦ ¦ curr = curr->right; // skip delimiter +223 ¦ ¦ goto read_products; +224 ¦ } +225 ¦ result_header.ingredients.push_back(next_recipe_reagent(curr->left)); +226 } +227 if (curr) { +228 ¦ assert(curr->atom); +229 ¦ result_header.ingredients.push_back(next_recipe_reagent(curr)); +230 ¦ return result_header; // no products +231 } +232 read_products: +233 for (/*nada*/; curr && !curr->atom; curr = curr->right) +234 ¦ result_header.products.push_back(next_recipe_reagent(curr->left)); +235 if (curr) { +236 ¦ assert(curr->atom); +237 ¦ result_header.products.push_back(next_recipe_reagent(curr)); +238 } +239 return result_header; +240 } +241 +242 :(before "End Unit Tests") +243 void test_from_reagent_atomic() { +244 reagent a("{f: recipe}"); +245 recipe r_header = from_reagent(a); +246 CHECK(r_header.ingredients.empty()); +247 CHECK(r_header.products.empty()); +248 } +249 void test_from_reagent_non_atomic() { +250 reagent a("{f: (recipe number -> number)}"); +251 recipe r_header = from_reagent(a); +252 CHECK_EQ(SIZE(r_header.ingredients), 1); +253 CHECK_EQ(SIZE(r_header.products), 1); +254 } +255 void test_from_reagent_reads_ingredient_at_end() { +256 reagent a("{f: (recipe number number)}"); +257 recipe r_header = from_reagent(a); +258 CHECK_EQ(SIZE(r_header.ingredients), 2); +259 CHECK(r_header.products.empty()); +260 } +261 void test_from_reagent_reads_sole_ingredient_at_end() { +262 reagent a("{f: (recipe number)}"); +263 recipe r_header = from_reagent(a); +264 CHECK_EQ(SIZE(r_header.ingredients), 1); +265 CHECK(r_header.products.empty()); +266 } +267 +268 :(code) +269 reagent next_recipe_reagent(const type_tree* curr) { +270 if (!curr->left) return reagent("recipe:"+curr->name); +271 reagent result; +272 result.name = "recipe"; +273 result.type = new type_tree(*curr); +274 return result; +275 } +276 +277 bool is_mu_recipe(const reagent& r) { +278 if (!r.type) return false; +279 if (r.type->atom) { +280 ¦ // End is_mu_recipe Atom Cases(r) +281 ¦ return r.type->name == "recipe-literal"; +282 } +283 return r.type->left->atom && r.type->left->name == "recipe"; +284 } +285 +286 :(scenario copy_typecheck_recipe_variable) +287 % Hide_errors = true; +288 def main [ +289 3:num <- copy 34 # abc def +290 {1: (recipe number -> number)} <- copy f # store literal in a matching variable +291 {2: (recipe boolean -> boolean)} <- copy {1: (recipe number -> number)} # mismatch between recipe variables +292 ] +293 def f x:num -> y:num [ +294 local-scope +295 load-ingredients +296 y <- copy x +297 ] +298 +error: main: can't copy '{1: (recipe number -> number)}' to '{2: (recipe boolean -> boolean)}'; types don't match +299 +300 :(scenario copy_typecheck_recipe_variable_2) +301 % Hide_errors = true; +302 def main [ +303 {1: (recipe number -> number)} <- copy f # mismatch with a recipe literal +304 ] +305 def f x:bool -> y:bool [ +306 local-scope +307 load-ingredients +308 y <- copy x +309 ] +310 +error: main: can't copy 'f' to '{1: (recipe number -> number)}'; types don't match +311 +312 :(before "End Matching Types For Literal(to)") +313 if (is_mu_recipe(to)) { +314 if (!contains_key(Recipe, from.value)) { +315 ¦ raise << "trying to store recipe " << from.name << " into " << to_string(to) << " but there's no such recipe\n" << end(); +316 ¦ return false; +317 } +318 const recipe& rrhs = get(Recipe, from.value); +319 const recipe& rlhs = from_reagent(to); +320 for (long int i = 0; i < min(SIZE(rlhs.ingredients), SIZE(rrhs.ingredients)); ++i) { +321 ¦ if (!types_match(rlhs.ingredients.at(i), rrhs.ingredients.at(i))) +322 ¦ ¦ return false; +323 } +324 for (long int i = 0; i < min(SIZE(rlhs.products), SIZE(rrhs.products)); ++i) { +325 ¦ if (!types_match(rlhs.products.at(i), rrhs.products.at(i))) +326 ¦ ¦ return false; +327 } +328 return true; +329 } +330 +331 :(scenario call_variable_compound_ingredient) +332 def main [ +333 {1: (recipe (address number) -> number)} <- copy f +334 2:&:num <- copy 0 +335 3:num <- call {1: (recipe (address number) -> number)}, 2:&:num +336 ] +337 def f x:&:num -> y:num [ +338 local-scope +339 load-ingredients +340 y <- copy x +341 ] +342 $error: 0 +343 +344 //: make sure we don't accidentally break on a function literal +345 :(scenario jump_forbidden_on_recipe_literals) +346 % Hide_errors = true; +347 def foo [ 348 local-scope -349 { -350 ¦ break-if foo -351 } -352 ] -353 # error should be as if foo is not a recipe -354 +error: main: missing type for 'foo' in 'break-if foo' -355 -356 :(before "End JUMP_IF Checks") -357 check_for_recipe_literals(inst, get(Recipe, r)); -358 :(before "End JUMP_UNLESS Checks") -359 check_for_recipe_literals(inst, get(Recipe, r)); -360 :(code) -361 void check_for_recipe_literals(const instruction& inst, const recipe& caller) { -362 for (int i = 0; i < SIZE(inst.ingredients); ++i) { -363 ¦ if (is_mu_recipe(inst.ingredients.at(i))) { -364 ¦ ¦ raise << maybe(caller.name) << "missing type for '" << inst.ingredients.at(i).original_string << "' in '" << to_original_string(inst) << "'\n" << end(); -365 ¦ ¦ if (is_present_in_ingredients(caller, inst.ingredients.at(i).name)) -366 ¦ ¦ ¦ raise << " did you forget 'load-ingredients'?\n" << end(); -367 ¦ } -368 } -369 } -370 -371 :(scenario load_ingredients_missing_error_3) -372 % Hide_errors = true; -373 def foo {f: (recipe num -> num)} [ -374 local-scope -375 b:num <- call f, 1 -376 ] -377 +error: foo: missing type for 'f' in 'b:num <- call f, 1' -378 +error: did you forget 'load-ingredients'? -379 -380 :(before "End Mu Types Initialization") -381 put(Type_abbreviations, "function", new_type_tree("recipe")); +349 ] +350 def main [ +351 local-scope +352 { +353 ¦ break-if foo +354 } +355 ] +356 # error should be as if foo is not a recipe +357 +error: main: missing type for 'foo' in 'break-if foo' +358 +359 :(before "End JUMP_IF Checks") +360 check_for_recipe_literals(inst, get(Recipe, r)); +361 :(before "End JUMP_UNLESS Checks") +362 check_for_recipe_literals(inst, get(Recipe, r)); +363 :(code) +364 void check_for_recipe_literals(const instruction& inst, const recipe& caller) { +365 for (int i = 0; i < SIZE(inst.ingredients); ++i) { +366 ¦ if (is_mu_recipe(inst.ingredients.at(i))) { +367 ¦ ¦ raise << maybe(caller.name) << "missing type for '" << inst.ingredients.at(i).original_string << "' in '" << to_original_string(inst) << "'\n" << end(); +368 ¦ ¦ if (is_present_in_ingredients(caller, inst.ingredients.at(i).name)) +369 ¦ ¦ ¦ raise << " did you forget 'load-ingredients'?\n" << end(); +370 ¦ } +371 } +372 } +373 +374 :(scenario load_ingredients_missing_error_3) +375 % Hide_errors = true; +376 def foo {f: (recipe num -> num)} [ +377 local-scope +378 b:num <- call f, 1 +379 ] +380 +error: foo: missing type for 'f' in 'b:num <- call f, 1' +381 +error: did you forget 'load-ingredients'? 382 -383 :(scenario call_function) -384 def main [ -385 {1: (function number -> number)} <- copy f -386 2:num <- call {1: (function number -> number)}, 34 -387 ] -388 def f x:num -> y:num [ -389 local-scope -390 load-ingredients -391 y <- copy x -392 ] -393 +mem: storing 34 in location 2 +383 :(before "End Mu Types Initialization") +384 put(Type_abbreviations, "function", new_type_tree("recipe")); +385 +386 :(scenario call_function) +387 def main [ +388 {1: (function number -> number)} <- copy f +389 2:num <- call {1: (function number -> number)}, 34 +390 ] +391 def f x:num -> y:num [ +392 local-scope +393 load-ingredients +394 y <- copy x +395 ] +396 +mem: storing 34 in location 2 -- cgit 1.4.1-2-gfad0