diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-10-29 17:15:09 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-10-29 17:15:09 -0700 |
commit | e6692482643dc007988188e2b19fbb9219ca2833 (patch) | |
tree | cbb805cba3bd46dfc7d71adaa2150d9acb5cc5ba | |
parent | 5a702544a6f8aa3fa520ba387a6c0e803e076476 (diff) | |
download | mu-e6692482643dc007988188e2b19fbb9219ca2833.tar.gz |
2321 - more preparations for static dispatch
Deduce operation id from name during transform rather than load, so that earlier transforms have a chance to modify the name.
-rw-r--r-- | 010vm.cc | 5 | ||||
-rw-r--r-- | 011load.cc | 11 | ||||
-rw-r--r-- | 013update_operation.cc | 31 | ||||
-rw-r--r-- | 020run.cc | 5 | ||||
-rw-r--r-- | 021check_instruction.cc | 2 | ||||
-rw-r--r-- | 040brace.cc | 51 | ||||
-rw-r--r-- | 041jump_target.cc | 10 | ||||
-rw-r--r-- | 042name.cc | 7 | ||||
-rw-r--r-- | 043new.cc | 2 | ||||
-rw-r--r-- | 044space.cc | 6 | ||||
-rw-r--r-- | 056recipe_header.cc | 8 | ||||
-rw-r--r-- | 072scenario_screen.cc | 2 |
12 files changed, 75 insertions, 65 deletions
diff --git a/010vm.cc b/010vm.cc index 21dd28d0..bdf4ec17 100644 --- a/010vm.cc +++ b/010vm.cc @@ -33,6 +33,7 @@ struct instruction { bool is_label; string label; // only if is_label string name; // only if !is_label + string old_name; // before our automatic rewrite rules recipe_ordinal operation; // Recipe_ordinal[name] vector<reagent> ingredients; // only if !is_label vector<reagent> products; // only if !is_label @@ -227,8 +228,8 @@ recipe::recipe() { instruction::instruction() :is_label(false), operation(IDLE) { // End instruction Constructor } -void instruction::clear() { is_label=false; label.clear(); operation=IDLE; ingredients.clear(); products.clear(); } -bool instruction::is_clear() { return !is_label && operation == IDLE; } +void instruction::clear() { is_label=false; label.clear(); name.clear(); old_name.clear(); operation=IDLE; ingredients.clear(); products.clear(); } +bool instruction::is_clear() { return !is_label && name.empty(); } // Reagents have the form <name>:<type>:<type>:.../<property>/<property>/... reagent::reagent(string s) :original_string(s), value(0), initialized(false), type(NULL) { diff --git a/011load.cc b/011load.cc index 2ac517c5..d848fd55 100644 --- a/011load.cc +++ b/011load.cc @@ -134,15 +134,8 @@ bool next_instruction(istream& in, instruction* curr) { raise_error << "instruction prematurely ended with '<-'\n" << end(); return false; } - curr->name = *p; - if (Recipe_ordinal.find(*p) == Recipe_ordinal.end()) { - Recipe_ordinal[*p] = Next_recipe_ordinal++; - } - if (Recipe_ordinal[*p] == 0) { - raise_error << "Recipe " << *p << " has number 0, which is reserved for IDLE.\n" << end(); - return false; - } - curr->operation = Recipe_ordinal[*p]; ++p; + curr->old_name = curr->name = *p; p++; + // curr->operation will be set in a later layer for (; p != words.end(); ++p) { curr->ingredients.push_back(reagent(*p)); diff --git a/013update_operation.cc b/013update_operation.cc new file mode 100644 index 00000000..edfda882 --- /dev/null +++ b/013update_operation.cc @@ -0,0 +1,31 @@ +//: Once all code is loaded, save operation ids of instructions and check that +//: nothing's undefined. + +:(after "int main") + // do this before any other transforms + Transform.push_back(update_instruction_operations); + +:(code) +void update_instruction_operations(recipe_ordinal r) { + trace(9991, "transform") << "--- compute instruction operations for recipe " << Recipe[r].name << end(); + for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) { + instruction& inst = Recipe[r].steps.at(index); + if (inst.is_label) continue; + if (Recipe_ordinal.find(inst.name) == Recipe_ordinal.end()) { + raise_error << maybe(Recipe[r].name) << "instruction " << inst.name << " has no recipe\n" << end(); + return; + } + inst.operation = Recipe_ordinal[inst.name]; + } +} + +// hook to suppress inserting recipe name into errors and warnings (for later layers) +string maybe(string s) { + return s + ": "; +} + +// temporarily suppress run +void transform(string form) { + load(form); + transform_all(); +} diff --git a/020run.cc b/020run.cc index db82ec36..24a0a863 100644 --- a/020run.cc +++ b/020run.cc @@ -317,11 +317,6 @@ inline bool scalar(const vector<double>& x) { return SIZE(x) == 1; } -// hook to suppress inserting recipe name into errors and warnings (for later layers) -string maybe(string s) { - return s + ": "; -} - // helper for tests void run(string form) { vector<recipe_ordinal> tmp = load(form); diff --git a/021check_instruction.cc b/021check_instruction.cc index 6df7a2d1..035fe6ce 100644 --- a/021check_instruction.cc +++ b/021check_instruction.cc @@ -8,7 +8,7 @@ //: sophisticated layer system I'd introduce the simpler version first and //: transform it in a separate layer or set of layers. -:(after "int main") +:(after "Transform.push_back(update_instruction_operations)") Transform.push_back(check_instruction); :(code) diff --git a/040brace.cc b/040brace.cc index aae9f3d7..afd97294 100644 --- a/040brace.cc +++ b/040brace.cc @@ -64,34 +64,34 @@ void transform_braces(const recipe_ordinal r) { continue; } if (inst.is_label) continue; - if (inst.operation != Recipe_ordinal["loop"] - && inst.operation != Recipe_ordinal["loop-if"] - && inst.operation != Recipe_ordinal["loop-unless"] - && inst.operation != Recipe_ordinal["break"] - && inst.operation != Recipe_ordinal["break-if"] - && inst.operation != Recipe_ordinal["break-unless"]) { - trace(9991, "transform") << inst.name << " ..." << end(); + if (inst.old_name != "loop" + && inst.old_name != "loop-if" + && inst.old_name != "loop-unless" + && inst.old_name != "break" + && inst.old_name != "break-if" + && inst.old_name != "break-unless") { + trace(9991, "transform") << inst.old_name << " ..." << end(); continue; } // check for errors - if (inst.name.find("-if") != string::npos || inst.name.find("-unless") != string::npos) { + if (inst.old_name.find("-if") != string::npos || inst.old_name.find("-unless") != string::npos) { if (inst.ingredients.empty()) { - raise_error << inst.name << " expects 1 or 2 ingredients, but got none\n" << end(); + raise_error << inst.old_name << " expects 1 or 2 ingredients, but got none\n" << end(); continue; } } // update instruction operation - if (inst.name.find("-if") != string::npos) - inst.operation = Recipe_ordinal["jump-if"]; - else if (inst.name.find("-unless") != string::npos) - inst.operation = Recipe_ordinal["jump-unless"]; + if (inst.old_name.find("-if") != string::npos) + inst.name = "jump-if"; + else if (inst.old_name.find("-unless") != string::npos) + inst.name = "jump-unless"; else - inst.operation = Recipe_ordinal["jump"]; + inst.name = "jump"; // check for explicitly provided targets - if (inst.name.find("-if") != string::npos || inst.name.find("-unless") != string::npos) { + if (inst.old_name.find("-if") != string::npos || inst.old_name.find("-unless") != string::npos) { // conditional branches check arg 1 if (SIZE(inst.ingredients) > 1 && is_literal(inst.ingredients.at(1))) { - trace(9991, "transform") << "jump " << inst.ingredients.at(1).name << ":offset" << end(); + trace(9991, "transform") << inst.name << ' ' << inst.ingredients.at(1).name << ":offset" << end(); continue; } } @@ -107,19 +107,17 @@ void transform_braces(const recipe_ordinal r) { target.type = new type_tree(Type_ordinal["offset"]); target.set_value(0); if (open_braces.empty()) - raise_error << inst.name << " needs a '{' before\n" << end(); - else if (inst.name.find("loop") != string::npos) + raise_error << inst.old_name << " needs a '{' before\n" << end(); + else if (inst.old_name.find("loop") != string::npos) target.set_value(open_braces.top()-index); else // break instruction target.set_value(matching_brace(open_braces.top(), braces, r) - index - 1); inst.ingredients.push_back(target); // log computed target - if (inst.name.find("-if") != string::npos) - trace(9991, "transform") << "jump-if " << inst.ingredients.at(0).name << ", " << no_scientific(target.value) << ":offset" << end(); - else if (inst.name.find("-unless") != string::npos) - trace(9991, "transform") << "jump-unless " << inst.ingredients.at(0).name << ", " << no_scientific(target.value) << ":offset" << end(); - else + if (inst.name == "jump") trace(9991, "transform") << "jump " << no_scientific(target.value) << ":offset" << end(); + else + trace(9991, "transform") << inst.name << ' ' << inst.ingredients.at(0).name << ", " << no_scientific(target.value) << ":offset" << end(); } } @@ -136,12 +134,7 @@ long long int matching_brace(long long int index, const list<pair<int, long long return SIZE(Recipe[r].steps); // exit current routine } -// temporarily suppress run -void transform(string form) { - load(form); - transform_all(); -} - +// todo: remove? //: Make sure these pseudo recipes get consistent numbers in all tests, even //: though they aren't implemented. diff --git a/041jump_target.cc b/041jump_target.cc index 7207c799..1f0e2212 100644 --- a/041jump_target.cc +++ b/041jump_target.cc @@ -39,18 +39,18 @@ void transform_labels(const recipe_ordinal r) { } for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) { instruction& inst = Recipe[r].steps.at(i); - if (inst.operation == Recipe_ordinal["jump"]) { + if (inst.name == "jump") { replace_offset(inst.ingredients.at(0), offset, i, r); } - if (inst.operation == Recipe_ordinal["jump-if"] || inst.operation == Recipe_ordinal["jump-unless"]) { + if (inst.name == "jump-if" || inst.name == "jump-unless") { replace_offset(inst.ingredients.at(1), offset, i, r); } - if ((inst.operation == Recipe_ordinal["loop"] || inst.operation == Recipe_ordinal["break"]) + if ((inst.name == "loop" || inst.name == "break") && SIZE(inst.ingredients) == 1) { replace_offset(inst.ingredients.at(0), offset, i, r); } - if ((inst.operation == Recipe_ordinal["loop-if"] || inst.operation == Recipe_ordinal["loop-unless"] - || inst.operation == Recipe_ordinal["break-if"] || inst.operation == Recipe_ordinal["break-unless"]) + if ((inst.name == "loop-if" || inst.name == "loop-unless" + || inst.name == "break-if" || inst.name == "break-unless") && SIZE(inst.ingredients) == 2) { replace_offset(inst.ingredients.at(1), offset, i, r); } diff --git a/042name.cc b/042name.cc index 6022fd93..6e56b2e3 100644 --- a/042name.cc +++ b/042name.cc @@ -193,14 +193,13 @@ recipe main [ :(before "End transform_names(inst) Special-cases") // replace element names of containers with offsets -if (inst.operation == Recipe_ordinal["get"] - || inst.operation == Recipe_ordinal["get-address"]) { +if (inst.name == "get" || inst.name == "get-address") { if (SIZE(inst.ingredients) != 2) { raise_error << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end(); break; } if (!is_literal(inst.ingredients.at(1))) - raise_error << maybe(Recipe[r].name) << "expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end(); + raise_error << maybe(Recipe[r].name) << "expected ingredient 1 of " << (inst.name == "get" ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end(); if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) { // since first non-address in base type must be a container, we don't have to canonize type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type, Recipe[r].name); @@ -234,7 +233,7 @@ recipe main [ :(before "End transform_names(inst) Special-cases") // convert variant names of exclusive containers -if (inst.operation == Recipe_ordinal["maybe-convert"]) { +if (inst.name == "maybe-convert") { if (SIZE(inst.ingredients) != 2) { raise_error << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end(); break; diff --git a/043new.cc b/043new.cc index 9c76adfb..72f3491b 100644 --- a/043new.cc +++ b/043new.cc @@ -30,7 +30,7 @@ trace(9999, "new") << "routine allocated memory from " << alloc << " to " << all Type_ordinal["type"] = 0; :(before "End transform_names(inst) Special-cases") // replace type names with type_ordinals -if (inst.operation == Recipe_ordinal["new"]) { +if (inst.name == "new") { // End NEW Transform Special-cases // first arg must be of type 'type' if (inst.ingredients.empty()) diff --git a/044space.cc b/044space.cc index 56b494d5..dd579a4f 100644 --- a/044space.cc +++ b/044space.cc @@ -173,15 +173,15 @@ void try_reclaim_locals() { const recipe_ordinal r = Recipe_ordinal[current_recipe_name()]; if (Recipe[r].steps.empty()) return; const instruction& inst = Recipe[r].steps.at(0); - if (inst.name != "local-scope") return; + if (inst.old_name != "local-scope") return; abandon(current_call().default_space, /*array length*/1+/*number-of-locals*/Name[r][""]); } void rewrite_default_space_instruction(instruction& curr) { - curr.operation = Recipe_ordinal["new"]; if (!curr.ingredients.empty()) - raise_error << "new-default-space can't take any ingredients\n" << end(); + raise_error << curr.to_string() << " can't take any ingredients\n" << end(); + curr.name = "new"; curr.ingredients.push_back(reagent("location:type")); curr.ingredients.push_back(reagent("number-of-locals:literal")); if (!curr.products.empty()) diff --git a/056recipe_header.cc b/056recipe_header.cc index 89ad945e..2ba0ac4b 100644 --- a/056recipe_header.cc +++ b/056recipe_header.cc @@ -65,14 +65,14 @@ if (curr.name == "load-ingredients") { :(scenarios transform) :(scenario recipe_headers_are_checked) -% Hide_warnings = true; +% Hide_errors = true; recipe add2 x:number, y:number -> z:number [ local-scope load-ingredients z:address:number <- copy 0/raw reply z ] -+warn: add2: replied with the wrong type at 'reply z' ++error: add2: replied with the wrong type at 'reply z' :(before "End One-time Setup") Transform.push_back(check_header_products); @@ -86,11 +86,11 @@ void check_header_products(const recipe_ordinal r) { const instruction& inst = rr.steps.at(i); if (inst.operation != REPLY) continue; if (SIZE(rr.products) != SIZE(inst.ingredients)) { - raise << maybe(rr.name) << "tried to reply the wrong number of products in '" << inst.to_string() << "'\n" << end(); + raise_error << maybe(rr.name) << "tried to reply the wrong number of products in '" << inst.to_string() << "'\n" << end(); } for (long long int i = 0; i < SIZE(rr.products); ++i) { if (!types_match(rr.products.at(i), inst.ingredients.at(i))) { - raise << maybe(rr.name) << "replied with the wrong type at '" << inst.to_string() << "'\n" << end(); + raise_error << maybe(rr.name) << "replied with the wrong type at '" << inst.to_string() << "'\n" << end(); } } } diff --git a/072scenario_screen.cc b/072scenario_screen.cc index 11151eac..97002005 100644 --- a/072scenario_screen.cc +++ b/072scenario_screen.cc @@ -141,9 +141,7 @@ Name[r]["screen"] = SCREEN; // rewrite `assume-screen width, height` to // `screen:address:screen <- new-fake-screen width, height` if (curr.name == "assume-screen") { - curr.operation = Recipe_ordinal["new-fake-screen"]; curr.name = "new-fake-screen"; - assert(curr.operation); assert(curr.products.empty()); curr.products.push_back(reagent("screen:address:screen")); curr.products.at(0).set_value(SCREEN); |