diff options
-rw-r--r-- | 010vm.cc | 30 | ||||
-rw-r--r-- | 011load.cc | 20 | ||||
-rw-r--r-- | 012transform.cc | 7 | ||||
-rw-r--r-- | 020run.cc | 19 | ||||
-rw-r--r-- | 030container.cc | 33 | ||||
-rw-r--r-- | 037new.cc | 1 | ||||
-rw-r--r-- | 042name.cc | 13 | ||||
-rw-r--r-- | 056static_dispatch.cc | 14 | ||||
-rw-r--r-- | 058shape_shifting_recipe.cc | 19 | ||||
-rw-r--r-- | 091run_interactive.cc | 123 |
10 files changed, 92 insertions, 187 deletions
diff --git a/010vm.cc b/010vm.cc index 56148f2a..1120280c 100644 --- a/010vm.cc +++ b/010vm.cc @@ -208,6 +208,36 @@ assert(Next_recipe_ordinal < 1000); // recipes being tested didn't overflow int :(before "End Setup") Next_recipe_ordinal = 1000; // consistent new numbers for each test +//: One final detail: tests can modify our global tables of recipes and types, +//: so we need some way to clean up after each test is done so it doesn't +//: influence later ones. +:(before "End Globals") +map<string, recipe_ordinal> Recipe_ordinal_snapshot; +map<recipe_ordinal, recipe> Recipe_snapshot; +map<string, type_ordinal> Type_ordinal_snapshot; +map<type_ordinal, type_info> Type_snapshot; +:(before "End One-time Setup") +save_snapshots(); +:(before "End Setup") +restore_snapshots(); + +:(code) +void save_snapshots() { + Recipe_ordinal_snapshot = Recipe_ordinal; + Recipe_snapshot = Recipe; + Type_ordinal_snapshot = Type_ordinal; + Type_snapshot = Type; + // End save_snapshots +} + +void restore_snapshots() { + Recipe = Recipe_snapshot; + Recipe_ordinal = Recipe_ordinal_snapshot; + Type_ordinal = Type_ordinal_snapshot; + Type = Type_snapshot; + // End restore_snapshots +} + //:: Helpers diff --git a/011load.cc b/011load.cc index ee8df684..d71a67b5 100644 --- a/011load.cc +++ b/011load.cc @@ -60,8 +60,6 @@ int slurp_recipe(istream& in) { slurp_body(in, result); // End Recipe Body(result) put(Recipe, get(Recipe_ordinal, result.name), result); - // track added recipes because we may need to undo them in tests; see below - Recently_added_recipes.push_back(get(Recipe_ordinal, result.name)); return get(Recipe_ordinal, result.name); } @@ -228,24 +226,6 @@ void show_rest_of_stream(istream& in) { exit(0); } -//: Have tests clean up any recipes they added. -:(before "End Globals") -vector<recipe_ordinal> Recently_added_recipes; -int Reserved_for_tests = 1000; -:(before "End Setup") -clear_recently_added_recipes(); -:(code) -void clear_recently_added_recipes() { - for (int i = 0; i < SIZE(Recently_added_recipes); ++i) { - if (Recently_added_recipes.at(i) >= Reserved_for_tests // don't renumber existing recipes, like 'interactive' - && contains_key(Recipe, Recently_added_recipes.at(i))) // in case previous test had duplicate definitions - Recipe_ordinal.erase(get(Recipe, Recently_added_recipes.at(i)).name); - Recipe.erase(Recently_added_recipes.at(i)); - } - // Clear Other State For Recently_added_recipes - Recently_added_recipes.clear(); -} - :(scenario parse_comment_outside_recipe) # this comment will be dropped by the tangler, so we need a dummy recipe to stop that def f1 [ diff --git a/012transform.cc b/012transform.cc index 0130cd16..a416c20a 100644 --- a/012transform.cc +++ b/012transform.cc @@ -56,13 +56,6 @@ void transform_all() { // End Transform All } -// Later we'll have transforms create recipes out of other recipes. This -// helper will help ensure we don't lose the new recipes. -void transform_permanently() { - transform_all(); - Recently_added_recipes.clear(); -} - void parse_int_reagents() { trace(9991, "transform") << "--- parsing any uninitialized reagents as integers" << end(); for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p) { diff --git a/020run.cc b/020run.cc index 41154f06..f3891cf6 100644 --- a/020run.cc +++ b/020run.cc @@ -136,8 +136,7 @@ inline const vector<instruction>& routine::steps() const { // Load .mu Core //? Trace_file = "interactive"; //? START_TRACING_UNTIL_END_OF_SCOPE; -load_permanently("core.mu"); -transform_permanently(); +load_file_or_directory("core.mu"); //? DUMP(""); //? exit(0); @@ -152,14 +151,15 @@ if (argc > 1) { // ignore argv past '--'; that's commandline args for 'main' while (argc > 0) { if (string(*argv) == "--") break; - load_permanently(*argv); + load_file_or_directory(*argv); argv++; argc--; } - transform_permanently(); if (Run_tests) Recipe.erase(get(Recipe_ordinal, "main")); // End Loading .mu Files } +transform_all(); +save_snapshots(); //: Step 3: if we aren't running tests, locate a recipe called 'main' and //: start running it. @@ -209,9 +209,9 @@ void cleanup_main() { atexit(cleanup_main); :(code) -void load_permanently(string filename) { +void load_file_or_directory(string filename) { if (is_directory(filename)) { - load_all_permanently(filename); + load_all(filename); return; } ifstream fin(filename.c_str()); @@ -222,9 +222,6 @@ void load_permanently(string filename) { trace(9990, "load") << "=== " << filename << end(); load(fin); fin.close(); - // freeze everything so it doesn't get cleared by tests - Recently_added_recipes.clear(); - // End load_permanently. } bool is_directory(string path) { @@ -233,13 +230,13 @@ bool is_directory(string path) { return info.st_mode & S_IFDIR; } -void load_all_permanently(string dir) { +void load_all(string dir) { dirent** files; int num_files = scandir(dir.c_str(), &files, NULL, alphasort); for (int i = 0; i < num_files; ++i) { string curr_file = files[i]->d_name; if (isdigit(curr_file.at(0))) - load_permanently(dir+'/'+curr_file); + load_file_or_directory(dir+'/'+curr_file); free(files[i]); files[i] = NULL; } diff --git a/030container.cc b/030container.cc index 4cc0d58e..a29f7171 100644 --- a/030container.cc +++ b/030container.cc @@ -416,7 +416,6 @@ void insert_container(const string& command, kind_of_type kind, istream& in) { trace(9999, "parse") << "type number: " << get(Type_ordinal, name) << end(); skip_bracket(in, "'container' must begin with '['"); type_info& info = get_or_insert(Type, get(Type_ordinal, name)); - Recently_added_types.push_back(get(Type_ordinal, name)); info.name = name; info.kind = kind; while (has_data(in)) { @@ -475,40 +474,12 @@ def main [ +mem: storing 34 in location 3 +mem: storing 35 in location 4 -//: ensure types created in one scenario don't leak outside it. -:(before "End Globals") -vector<type_ordinal> Recently_added_types; -:(before "End load_permanently") //: for non-tests -Recently_added_types.clear(); +//: ensure scenarios are consistent by always starting them at the same type +//: number. :(before "End Setup") //: for tests -for (int i = 0; i < SIZE(Recently_added_types); ++i) { - if (!contains_key(Type, Recently_added_types.at(i))) continue; - Type_ordinal.erase(get(Type, Recently_added_types.at(i)).name); - // todo: why do I explicitly need to provide this? - for (int j = 0; j < SIZE(Type.at(Recently_added_types.at(i)).elements); ++j) - Type.at(Recently_added_types.at(i)).elements.at(j).clear(); - Type.erase(Recently_added_types.at(i)); -} -Recently_added_types.clear(); -// delete recent type references -// can't rely on Recently_added_types to cleanup Type_ordinal, because of deliberately misbehaving tests with references to undefined types -map<string, type_ordinal>::iterator p = Type_ordinal.begin(); -while(p != Type_ordinal.end()) { - // save current item - string name = p->first; - type_ordinal t = p->second; - // increment iterator - ++p; - // now delete current item if necessary - if (t >= 1000) Type_ordinal.erase(name); -} -//: lastly, ensure scenarios are consistent by always starting them at the -//: same type number. Next_type_ordinal = 1000; :(before "End Test Run Initialization") assert(Next_type_ordinal < 1000); -:(before "End Setup") -Next_type_ordinal = 1000; //:: Allow container definitions anywhere in the codebase, but complain if you //:: can't find a definition at the end. diff --git a/037new.cc b/037new.cc index d7daa397..feebd58e 100644 --- a/037new.cc +++ b/037new.cc @@ -55,6 +55,7 @@ def main [ +mem: storing 0 in location 3 :(before "End Globals") +const int Reserved_for_tests = 1000; int Memory_allocated_until = Reserved_for_tests; int Initial_memory_per_routine = 100000; :(before "End Setup") diff --git a/042name.cc b/042name.cc index 46e3a816..872b5678 100644 --- a/042name.cc +++ b/042name.cc @@ -23,10 +23,15 @@ Transform.push_back(transform_names); // idempotent :(before "End Globals") map<recipe_ordinal, map<string, int> > Name; -:(after "Clear Other State For Recently_added_recipes") -for (int i = 0; i < SIZE(Recently_added_recipes); ++i) { - Name.erase(Recently_added_recipes.at(i)); -} + +//: the Name map is a global, so save it before tests and reset it for every +//: test, just to be safe. +:(before "End Globals") +map<recipe_ordinal, map<string, int> > Name_snapshot; +:(before "End save_snapshots") +Name_snapshot = Name; +:(before "End restore_snapshots") +Name = Name_snapshot; :(code) void transform_names(const recipe_ordinal r) { diff --git a/056static_dispatch.cc b/056static_dispatch.cc index da97ea80..263dc2bf 100644 --- a/056static_dispatch.cc +++ b/056static_dispatch.cc @@ -21,13 +21,13 @@ def test a:number, b:number -> z:number [ map<string, vector<recipe_ordinal> > Recipe_variants; :(before "End One-time Setup") put(Recipe_variants, "main", vector<recipe_ordinal>()); // since we manually added main to Recipe_ordinal -:(before "Clear Other State For Recently_added_recipes") -for (map<string, vector<recipe_ordinal> >::iterator p = Recipe_variants.begin(); p != Recipe_variants.end(); ++p) { - for (int i = 0; i < SIZE(p->second); ++i) { - if (find(Recently_added_recipes.begin(), Recently_added_recipes.end(), p->second.at(i)) != Recently_added_recipes.end()) - p->second.at(i) = -1; // just leave a ghost - } -} + +:(before "End Globals") +map<string, vector<recipe_ordinal> > Recipe_variants_snapshot; +:(before "End save_snapshots") +Recipe_variants_snapshot = Recipe_variants; +:(before "End restore_snapshots") +Recipe_variants = Recipe_variants_snapshot; :(before "End Load Recipe Header(result)") // there can only ever be one variant for main diff --git a/058shape_shifting_recipe.cc b/058shape_shifting_recipe.cc index 2046c622..f80edb3b 100644 --- a/058shape_shifting_recipe.cc +++ b/058shape_shifting_recipe.cc @@ -41,23 +41,6 @@ if (Current_routine->calls.front().running_step_index == 0 :(before "End Matching Types For Literal(to)") if (contains_type_ingredient_name(to)) return false; -//: We'll be creating recipes without loading them from anywhere by -//: *specializing* existing recipes. -//: -//: Keep track of these new recipes in a separate variable in addition to -//: Recently_added_recipes, so that edit/ can clear them before reloading to -//: regenerate errors. -:(before "End Globals") -vector<recipe_ordinal> Recently_added_shape_shifting_recipes; -:(before "End Setup") -Recently_added_shape_shifting_recipes.clear(); - -//: make sure we don't clear any of these recipes when we start running tests -:(before "End Loading .mu Files") -Recently_added_recipes.clear(); -Recently_added_types.clear(); -Recently_added_shape_shifting_recipes.clear(); - //: save original name of specialized recipes :(before "End recipe Fields") string original_name; @@ -243,8 +226,6 @@ recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst, con // make a copy assert(contains_key(Recipe, exemplar)); assert(!contains_key(Recipe, new_recipe_ordinal)); - Recently_added_recipes.push_back(new_recipe_ordinal); - Recently_added_shape_shifting_recipes.push_back(new_recipe_ordinal); put(Recipe, new_recipe_ordinal, get(Recipe, exemplar)); recipe& new_recipe = get(Recipe, new_recipe_ordinal); new_recipe.name = new_name; diff --git a/091run_interactive.cc b/091run_interactive.cc index 1e6bf9c2..b84d8ca9 100644 --- a/091run_interactive.cc +++ b/091run_interactive.cc @@ -62,8 +62,6 @@ bool Track_most_recent_products = false; :(before "End Tracing") trace_stream* Save_trace_stream = NULL; string Save_trace_file; -vector<recipe_ordinal> Save_recently_added_recipes; -vector<recipe_ordinal> Save_recently_added_shape_shifting_recipes; :(before "End Setup") Track_most_recent_products = false; :(code) @@ -79,9 +77,9 @@ bool run_interactive(int address) { Memory.erase(i); } string command = trim(strip_comments(read_mu_string(address))); - if (command.empty()) return false; Name[get(Recipe_ordinal, "interactive")].clear(); run_code_begin(/*snapshot_recently_added_recipes*/true); + if (command.empty()) return false; // don't kill the current routine on parse errors routine* save_current_routine = Current_routine; Current_routine = NULL; @@ -108,16 +106,22 @@ bool run_interactive(int address) { return true; } +//: Carefully update all state to exactly how it was -- including snapshots. + +:(before "End Globals") +map<string, recipe_ordinal> Recipe_ordinal_snapshot_stash; +map<recipe_ordinal, recipe> Recipe_snapshot_stash; +map<string, type_ordinal> Type_ordinal_snapshot_stash; +map<type_ordinal, type_info> Type_snapshot_stash; +map<recipe_ordinal, map<string, int> > Name_snapshot_stash; +map<string, vector<recipe_ordinal> > Recipe_variants_snapshot_stash; +:(code) void run_code_begin(bool snapshot_recently_added_recipes) { // stuff to undo later, in run_code_end() Hide_errors = true; Disable_redefine_checks = true; - if (snapshot_recently_added_recipes) { - Save_recently_added_recipes = Recently_added_recipes; - Recently_added_recipes.clear(); - Save_recently_added_shape_shifting_recipes = Recently_added_shape_shifting_recipes; - Recently_added_shape_shifting_recipes.clear(); - } + if (snapshot_recently_added_recipes) + stash_snapshots(); Save_trace_stream = Trace_stream; Save_trace_file = Trace_file; Trace_file = ""; @@ -134,13 +138,28 @@ void run_code_end() { Trace_file = Save_trace_file; Save_trace_file.clear(); Recipe.erase(get(Recipe_ordinal, "interactive")); // keep past sandboxes from inserting errors - if (!Save_recently_added_recipes.empty()) { - clear_recently_added_recipes(); - Recently_added_recipes = Save_recently_added_recipes; - Save_recently_added_recipes.clear(); - Recently_added_shape_shifting_recipes = Save_recently_added_shape_shifting_recipes; - Save_recently_added_shape_shifting_recipes.clear(); - } + if (!Recipe_snapshot_stash.empty()) + unstash_snapshots(); +} + +// keep sync'd with save_snapshots and restore_snapshots +void stash_snapshots() { + Recipe_ordinal_snapshot_stash = Recipe_ordinal_snapshot; + Recipe_snapshot_stash = Recipe_snapshot; + Type_ordinal_snapshot_stash = Type_ordinal_snapshot; + Type_snapshot_stash = Type_snapshot; + Name_snapshot_stash = Name_snapshot; + Recipe_variants_snapshot_stash = Recipe_variants_snapshot; + save_snapshots(); +} +void unstash_snapshots() { + restore_snapshots(); + Recipe_ordinal_snapshot = Recipe_ordinal_snapshot_stash; Recipe_ordinal_snapshot_stash.clear(); + Recipe_snapshot = Recipe_snapshot_stash; Recipe_snapshot_stash.clear(); + Type_ordinal_snapshot = Type_ordinal_snapshot_stash; Type_ordinal_snapshot_stash.clear(); + Type_snapshot = Type_snapshot_stash; Type_snapshot_stash.clear(); + Name_snapshot = Name_snapshot_stash; Name_snapshot_stash.clear(); + Recipe_variants_snapshot = Recipe_variants_snapshot_stash; Recipe_variants_snapshot_stash.clear(); } :(before "End Load Recipes") @@ -161,8 +180,6 @@ load(string( "$cleanup-run-interactive\n" + "return output, errors, screen, stashes, completed?\n" + "]\n"); -transform_all(); -Recently_added_recipes.clear(); //: adjust errors in the sandbox :(after "string maybe(string s)") @@ -315,31 +332,6 @@ b:number <- copy 0 # no errors +mem: storing 0 in location 3 -:(code) -void test_run_interactive_cleans_up_any_created_specializations() { - // define a generic recipe - assert(!contains_key(Recipe_ordinal, "foo")); - load("recipe foo x:_elem -> n:number [\n" - " return 34\n" - "]\n"); - assert(SIZE(Recently_added_recipes) == 1); // foo - assert(variant_count("foo") == 1); - // run-interactive a call that specializes this recipe - run("recipe main [\n" - " 1:number/raw <- copy 0\n" - " 2:address:shared:array:character <- new [foo 1:number/raw]\n" - " run-interactive 2:address:shared:array:character\n" - "]\n"); - assert(SIZE(Recently_added_recipes) == 2); // foo, main - // check that number of variants doesn't change - CHECK_EQ(variant_count("foo"), 1); -} - -int variant_count(string recipe_name) { - if (!contains_key(Recipe_variants, recipe_name)) return 0; - return non_ghost_size(get(Recipe_variants, recipe_name)); -} - :(before "End Globals") string Most_recent_products; :(before "End Setup") @@ -456,25 +448,6 @@ case RELOAD: { } :(before "End Primitive Recipe Implementations") case RELOAD: { - // clear any containers in advance - for (int i = 0; i < SIZE(Recently_added_types); ++i) { - if (!contains_key(Type, Recently_added_types.at(i))) continue; - Type_ordinal.erase(get(Type, Recently_added_types.at(i)).name); - Type.erase(Recently_added_types.at(i)); - } - for (map<string, vector<recipe_ordinal> >::iterator p = Recipe_variants.begin(); p != Recipe_variants.end(); ++p) { - vector<recipe_ordinal>& variants = p->second; - for (int i = 0; i < SIZE(p->second); ++i) { - if (variants.at(i) == -1) continue; - if (find(Recently_added_shape_shifting_recipes.begin(), Recently_added_shape_shifting_recipes.end(), variants.at(i)) != Recently_added_shape_shifting_recipes.end()) - variants.at(i) = -1; // ghost - } - } - for (int i = 0; i < SIZE(Recently_added_shape_shifting_recipes); ++i) { - Recipe_ordinal.erase(get(Recipe, Recently_added_shape_shifting_recipes.at(i)).name); - Recipe.erase(Recently_added_shape_shifting_recipes.at(i)); - } - Recently_added_shape_shifting_recipes.clear(); string code = read_mu_string(ingredients.at(0).at(0)); run_code_begin(/*snapshot_recently_added_recipes*/false); routine* save_current_routine = Current_routine; @@ -503,29 +476,3 @@ def main [ 1:number/raw <- copy 34 ] +mem: storing 34 in location 1 - -:(code) -void test_reload_cleans_up_any_created_specializations() { - // define a generic recipe and a call to it - assert(!contains_key(Recipe_ordinal, "foo")); - assert(variant_count("foo") == 0); - // a call that specializes this recipe - run("recipe main [\n" - " local-scope\n" - " x:address:shared:array:character <- new [recipe foo x:_elem -> n:number [\n" - "local-scope\n" - "load-ingredients\n" - "return 34\n" - "]\n" - "recipe main2 [\n" - "local-scope\n" - "load-ingredients\n" - "x:number <- copy 34\n" - "foo x:number\n" - "]]\n" - " reload x\n" - "]\n"); - // check that number of variants includes specialization - assert(SIZE(Recently_added_recipes) == 4); // foo, main, main2, foo specialization - CHECK_EQ(variant_count("foo"), 2); -} |