diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-11-01 19:42:49 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-11-01 19:42:49 -0800 |
commit | 49c274f839e8768d50f6aca42c429081794182c6 (patch) | |
tree | 588d61a684f5eefcae38be936ab2db73c6eee688 | |
parent | a09697d0acadb7297415c49cb2abcc763eafb3f9 (diff) | |
download | mu-49c274f839e8768d50f6aca42c429081794182c6.tar.gz |
2342 - generalize generic recipes
Support for type ingredients anywhere. I've been working on this since commit 2331.
-rw-r--r-- | 057static_dispatch.cc | 2 | ||||
-rw-r--r-- | 059generic_recipe.cc | 134 |
2 files changed, 108 insertions, 28 deletions
diff --git a/057static_dispatch.cc b/057static_dispatch.cc index 6a86beba..35a703bf 100644 --- a/057static_dispatch.cc +++ b/057static_dispatch.cc @@ -108,12 +108,12 @@ void resolve_ambiguous_calls(recipe_ordinal r) { if (inst.is_label) continue; if (Recipe_variants.find(inst.name) == Recipe_variants.end()) continue; assert(!Recipe_variants[inst.name].empty()); - if (++Recipe_variants[inst.name].begin() == Recipe_variants[inst.name].end()) continue; replace_best_variant(inst); } } void replace_best_variant(instruction& inst) { + trace(9992, "transform") << "instruction " << inst.name << end(); vector<recipe_ordinal>& variants = Recipe_variants[inst.name]; long long int best_score = variant_score(inst, Recipe_ordinal[inst.name]); for (long long int i = 0; i < SIZE(variants); ++i) { diff --git a/059generic_recipe.cc b/059generic_recipe.cc index e6bd16ae..d7f2bbff 100644 --- a/059generic_recipe.cc +++ b/059generic_recipe.cc @@ -36,7 +36,7 @@ if (best_score == -1) { recipe_ordinal pick_matching_generic_variant(vector<recipe_ordinal>& variants, const instruction& inst, long long int& best_score) { recipe_ordinal result = 0; for (long long int i = 0; i < SIZE(variants); ++i) { - trace(9992, "transform") << "checking variant " << i << end(); + trace(9992, "transform") << "checking generic variant " << i << end(); long long int current_score = generic_variant_score(inst, variants.at(i)); trace(9992, "transform") << "final score: " << current_score << end(); if (current_score > best_score) { @@ -50,7 +50,7 @@ recipe_ordinal pick_matching_generic_variant(vector<recipe_ordinal>& variants, c long long int generic_variant_score(const instruction& inst, recipe_ordinal variant) { if (!any_type_ingredient_in_header(variant)) { - trace(9993, "tranform") << "no type ingredients" << end(); + trace(9993, "transform") << "no type ingredients" << end(); return -1; } const vector<reagent>& header_ingredients = Recipe[variant].ingredients; @@ -82,64 +82,125 @@ long long int generic_variant_score(const instruction& inst, recipe_ordinal vari bool any_type_ingredient_in_header(recipe_ordinal variant) { for (long long int i = 0; i < SIZE(Recipe[variant].ingredients); ++i) { - if (is_type_ingredient(Recipe[variant].ingredients.at(i))) + if (contains_type_ingredient_name(Recipe[variant].ingredients.at(i))) return true; } return false; } bool non_type_ingredients_match(const reagent& lhs, const reagent& rhs) { - if (is_type_ingredient(lhs)) return true; + if (contains_type_ingredient_name(lhs)) return true; return types_match(lhs, rhs); } +bool contains_type_ingredient_name(const reagent& x) { + return contains_type_ingredient_name(x.properties.at(0).second); +} + +bool contains_type_ingredient_name(const string_tree* type) { + if (!type) return false; + if (is_type_ingredient_name(type->value)) return true; + return contains_type_ingredient_name(type->left) || contains_type_ingredient_name(type->right); +} + +bool is_type_ingredient_name(const string& type) { + return !type.empty() && type.at(0) == '_'; +} + recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst) { string new_name = next_unused_recipe_name(inst.name); + trace(9993, "transform") << "switching " << inst.name << " to " << new_name << end(); assert(Recipe_ordinal.find(new_name) == Recipe_ordinal.end()); recipe_ordinal result = Recipe_ordinal[new_name] = Next_recipe_ordinal++; // make a copy + assert(Recipe.find(exemplar) != Recipe.end()); Recipe[result] = Recipe[exemplar]; recipe& new_recipe = Recipe[result]; // update its name new_recipe.name = new_name; + // update its contents + map<string, string> mappings; // weak references + compute_type_ingredient_mappings(Recipe[exemplar], inst, mappings); + replace_type_ingredients(new_recipe, mappings); + return result; +} + +void compute_type_ingredient_mappings(const recipe& exemplar, const instruction& inst, map<string, string>& mappings) { + for (long long int i = 0; i < SIZE(exemplar.ingredients); ++i) { + accumulate_type_ingredients(exemplar.ingredients.at(i), inst.ingredients.at(i), mappings); + } + for (long long int i = 0; i < SIZE(exemplar.products); ++i) { + accumulate_type_ingredients(exemplar.products.at(i), inst.products.at(i), mappings); + } +} + +void accumulate_type_ingredients(const reagent& base, const reagent& refinements, map<string, string>& mappings) { + accumulate_type_ingredients(base.properties.at(0).second, refinements.properties.at(0).second, mappings); +} + +void accumulate_type_ingredients(const string_tree* base, const string_tree* refinements, map<string, string>& mappings) { + if (!base) return; + assert(refinements); + if (!base->value.empty() && base->value.at(0) == '_') { + assert(!refinements->value.empty()); + if (mappings.find(base->value) == mappings.end()) { + trace(9993, "transform") << "adding mapping from " << base->value << " to " << refinements->value << end(); + mappings[base->value] = refinements->value; + } + else { + assert(mappings[base->value] == refinements->value); + } + } + else { + accumulate_type_ingredients(base->left, refinements->left, mappings); + } + accumulate_type_ingredients(base->right, refinements->right, mappings); +} + +void replace_type_ingredients(recipe& new_recipe, const map<string, string>& mappings) { // update its header - map<string, type_tree*> mappings; // weak references + if (mappings.empty()) return; + trace(9993, "transform") << "replacing in recipe header ingredients" << end(); for (long long int i = 0; i < SIZE(new_recipe.ingredients); ++i) { - if (!is_type_ingredient(new_recipe.ingredients.at(i))) continue; - type_tree* replacement_type = new type_tree(*inst.ingredients.at(i).type); - delete new_recipe.ingredients.at(i).type; - new_recipe.ingredients.at(i).type = replacement_type; - mappings[new_recipe.ingredients.at(i).name] = replacement_type; + replace_type_ingredients(new_recipe.ingredients.at(i), mappings); } + trace(9993, "transform") << "replacing in recipe header products" << end(); for (long long int i = 0; i < SIZE(new_recipe.products); ++i) { - if (!is_type_ingredient(new_recipe.products.at(i))) continue; - type_tree* replacement_type = new type_tree(*inst.products.at(i).type); - delete new_recipe.products.at(i).type; - new_recipe.products.at(i).type = replacement_type; - mappings[new_recipe.products.at(i).name] = replacement_type; + replace_type_ingredients(new_recipe.products.at(i), mappings); } // update its body for (long long int i = 0; i < SIZE(new_recipe.steps); ++i) { instruction& inst = new_recipe.steps.at(i); + trace(9993, "transform") << "replacing in instruction '" << inst.to_string() << "'" << end(); for (long long int j = 0; j < SIZE(inst.ingredients); ++j) { - if (mappings.find(inst.ingredients.at(j).name) != mappings.end()) { - delete inst.ingredients.at(j).type; - inst.ingredients.at(j).type = new type_tree(*mappings[inst.ingredients.at(j).name]); - } + replace_type_ingredients(inst.ingredients.at(j), mappings); } for (long long int j = 0; j < SIZE(inst.products); ++j) { - if (mappings.find(inst.products.at(j).name) != mappings.end()) { - delete inst.products.at(j).type; - inst.products.at(j).type = new type_tree(*mappings[inst.products.at(j).name]); - } + replace_type_ingredients(inst.products.at(j), mappings); } } - trace(9993, "transform") << "switching " << inst.name << " to " << new_name << end(); - return result; } -bool is_type_ingredient(const reagent& x) { - return x.properties.at(0).second->value.at(0) == '_'; +void replace_type_ingredients(reagent& x, const map<string, string>& mappings) { + if (!x.type) return; + trace(9993, "transform") << "replacing in ingredient " << x.original_string << end(); + // replace properties + replace_type_ingredients(x.properties.at(0).second, mappings); + // refresh types from properties + delete x.type; + x.type = new_type_tree(x.properties.at(0).second); + if (x.type) + trace(9993, "transform") << " after: " << dump_types(x) << end(); +} + +void replace_type_ingredients(string_tree* type, const map<string, string>& mappings) { + if (!type) return; + if (is_type_ingredient_name(type->value) && mappings.find(type->value) != mappings.end()) { + trace(9993, "transform") << type->value << " => " << mappings.find(type->value)->second << end(); + type->value = mappings.find(type->value)->second; + } + replace_type_ingredients(type->left, mappings); + replace_type_ingredients(type->right, mappings); } :(scenario generic_recipe_2) @@ -161,3 +222,22 @@ recipe foo a:_t -> result:_t [ ] +mem: storing 14 in location 11 +mem: storing 15 in location 12 + +:(scenario generic_recipe_nonroot) +% Hide_warnings = Hide_errors = true; +recipe main [ + 10:foo:point <- merge 14, 15, 16 + 20:point/raw <- bar 10:foo:point +] +# generic recipe with type ingredient following some other type +recipe bar a:foo:_t -> result:_t [ + local-scope + load-ingredients + result <- get a, x:offset +] +container foo:_t [ + x:_t + y:number +] ++mem: storing 14 in location 20 ++mem: storing 15 in location 21 |