2015-10-31 17:54:48 +00:00
|
|
|
//:: Like container definitions, recipes too can contain type parameters.
|
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-10-31 17:54:48 +00:00
|
|
|
10:point <- merge 14, 15
|
|
|
|
11:point <- foo 10:point
|
|
|
|
]
|
|
|
|
# non-matching variant
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:number -> result:number [
|
2015-10-31 17:54:48 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
result <- copy 34
|
|
|
|
]
|
2015-11-11 04:24:03 +00:00
|
|
|
# matching shape-shifting variant
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:_t -> result:_t [
|
2015-10-31 17:54:48 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
result <- copy a
|
|
|
|
]
|
|
|
|
+mem: storing 14 in location 11
|
|
|
|
+mem: storing 15 in location 12
|
|
|
|
|
2015-11-15 06:59:09 +00:00
|
|
|
//: Before anything else, disable transforms for shape-shifting recipes and
|
|
|
|
//: make sure we never try to actually run a shape-shifting recipe. We should
|
|
|
|
//: be rewriting such instructions to *specializations* with the type
|
|
|
|
//: ingredients filled in.
|
2015-11-05 07:44:46 +00:00
|
|
|
|
2015-11-08 06:56:06 +00:00
|
|
|
:(before "End Transform Checks")
|
|
|
|
if (any_type_ingredient_in_header(/*recipe_ordinal*/p->first)) continue;
|
2015-11-05 07:44:46 +00:00
|
|
|
|
2015-11-15 06:59:09 +00:00
|
|
|
:(after "Running One Instruction")
|
|
|
|
if (Current_routine->calls.front().running_step_index == 0
|
|
|
|
&& any_type_ingredient_in_header(Current_routine->calls.front().running_recipe)) {
|
2015-11-15 20:35:59 +00:00
|
|
|
//? DUMP("");
|
2016-02-26 21:04:55 +00:00
|
|
|
raise << "ran into unspecialized shape-shifting recipe " << current_recipe_name() << '\n' << end();
|
2016-02-28 02:49:53 +00:00
|
|
|
//? exit(0);
|
2015-11-15 06:59:09 +00:00
|
|
|
}
|
|
|
|
|
2015-11-15 08:37:29 +00:00
|
|
|
//: Make sure we don't match up literals with type ingredients without
|
|
|
|
//: specialization.
|
2016-01-31 06:22:52 +00:00
|
|
|
:(before "End Matching Types For Literal(to)")
|
|
|
|
if (contains_type_ingredient_name(to)) return false;
|
2015-11-15 08:37:29 +00:00
|
|
|
|
2015-11-28 02:01:55 +00:00
|
|
|
//: save original name of specialized recipes
|
|
|
|
:(before "End recipe Fields")
|
|
|
|
string original_name;
|
|
|
|
//: original name is only set during load
|
2016-02-12 01:42:20 +00:00
|
|
|
:(before "End Load Recipe Name")
|
2015-11-28 02:01:55 +00:00
|
|
|
result.original_name = result.name;
|
|
|
|
|
2016-05-06 04:47:59 +00:00
|
|
|
:(after "Static Dispatch Phase 3")
|
2016-02-12 00:13:10 +00:00
|
|
|
candidates = strictly_matching_shape_shifting_variants(inst, variants);
|
|
|
|
if (!candidates.empty()) {
|
|
|
|
recipe_ordinal exemplar = best_shape_shifting_variant(inst, candidates);
|
|
|
|
trace(9992, "transform") << "found variant to specialize: " << exemplar << ' ' << get(Recipe, exemplar).name << end();
|
|
|
|
recipe_ordinal new_recipe_ordinal = new_variant(exemplar, inst, caller_recipe);
|
|
|
|
if (new_recipe_ordinal == 0) goto skip_shape_shifting_variants;
|
|
|
|
variants.push_back(new_recipe_ordinal); // side-effect
|
|
|
|
recipe& variant = get(Recipe, new_recipe_ordinal);
|
|
|
|
// perform all transforms on the new specialization
|
|
|
|
if (!variant.steps.empty()) {
|
|
|
|
trace(9992, "transform") << "transforming new specialization: " << variant.name << end();
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int t = 0; t < SIZE(Transform); ++t) {
|
2016-04-28 05:28:55 +00:00
|
|
|
// one exception: skip tangle, which would have already occurred inside new_variant above
|
2016-05-25 01:58:23 +00:00
|
|
|
if (Transform.at(t) == /*disambiguate overloading*/static_cast<transform_fn>(insert_fragments))
|
|
|
|
continue;
|
2016-02-12 00:13:10 +00:00
|
|
|
(*Transform.at(t))(new_recipe_ordinal);
|
2015-11-28 01:54:34 +00:00
|
|
|
}
|
2015-10-31 17:54:48 +00:00
|
|
|
}
|
2016-02-12 00:13:10 +00:00
|
|
|
variant.transformed_until = SIZE(Transform)-1;
|
|
|
|
trace(9992, "transform") << "new specialization: " << variant.name << end();
|
|
|
|
return variant.name;
|
2015-10-31 17:54:48 +00:00
|
|
|
}
|
2016-02-12 00:13:10 +00:00
|
|
|
skip_shape_shifting_variants:;
|
2015-10-31 17:54:48 +00:00
|
|
|
|
2015-11-19 07:55:54 +00:00
|
|
|
//: make sure we have no unspecialized shape-shifting recipes being called
|
|
|
|
//: before running mu programs
|
|
|
|
|
|
|
|
:(before "End Instruction Operation Checks")
|
2015-12-14 09:30:56 +00:00
|
|
|
if (contains_key(Recipe, inst.operation) && inst.operation >= MAX_PRIMITIVE_RECIPES
|
2015-11-19 07:55:54 +00:00
|
|
|
&& any_type_ingredient_in_header(inst.operation)) {
|
2016-05-21 05:09:06 +00:00
|
|
|
raise << maybe(caller.name) << "instruction '" << inst.name << "' has no valid specialization\n" << end();
|
2015-11-19 07:55:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-25 03:06:13 +00:00
|
|
|
:(replace{} "bool types_strictly_match_except_literal_zero_against_address(const reagent& to, const reagent& from)")
|
|
|
|
bool types_strictly_match_except_literal_zero_against_address(const reagent& to, const reagent& from) {
|
|
|
|
if (is_literal(from) && is_mu_address(to))
|
|
|
|
return from.name == "0" && !contains_type_ingredient_name(to);
|
|
|
|
return types_strictly_match(to, from);
|
|
|
|
}
|
|
|
|
|
2015-10-31 17:54:48 +00:00
|
|
|
:(code)
|
2016-02-12 00:13:10 +00:00
|
|
|
// phase 2 of static dispatch
|
|
|
|
vector<recipe_ordinal> strictly_matching_shape_shifting_variants(const instruction& inst, vector<recipe_ordinal>& variants) {
|
|
|
|
vector<recipe_ordinal> result;
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(variants); ++i) {
|
2016-02-12 00:13:10 +00:00
|
|
|
if (variants.at(i) == -1) continue;
|
|
|
|
if (!any_type_ingredient_in_header(variants.at(i))) continue;
|
|
|
|
if (all_concrete_header_reagents_strictly_match(inst, get(Recipe, variants.at(i))))
|
|
|
|
result.push_back(variants.at(i));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool all_concrete_header_reagents_strictly_match(const instruction& inst, const recipe& variant) {
|
|
|
|
if (SIZE(inst.ingredients) < SIZE(variant.ingredients)) {
|
|
|
|
trace(9993, "transform") << "too few ingredients" << end();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (SIZE(variant.products) < SIZE(inst.products)) {
|
|
|
|
trace(9993, "transform") << "too few products" << end();
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(variant.ingredients); ++i) {
|
2016-02-21 04:05:52 +00:00
|
|
|
if (!concrete_type_names_strictly_match(variant.ingredients.at(i), inst.ingredients.at(i))) {
|
2016-02-12 00:13:10 +00:00
|
|
|
trace(9993, "transform") << "concrete-type match failed: ingredient " << i << end();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(inst.products); ++i) {
|
2016-02-12 00:13:10 +00:00
|
|
|
if (is_dummy(inst.products.at(i))) continue;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (!concrete_type_names_strictly_match(variant.products.at(i), inst.products.at(i))) {
|
2016-02-12 00:13:10 +00:00
|
|
|
trace(9993, "transform") << "strict match failed: product " << i << end();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tie-breaker for phase 2
|
|
|
|
recipe_ordinal best_shape_shifting_variant(const instruction& inst, vector<recipe_ordinal>& candidates) {
|
|
|
|
assert(!candidates.empty());
|
|
|
|
// primary score
|
2016-03-14 03:26:47 +00:00
|
|
|
int max_score = -1;
|
|
|
|
for (int i = 0; i < SIZE(candidates); ++i) {
|
|
|
|
int score = number_of_concrete_type_names(candidates.at(i));
|
2016-02-12 00:13:10 +00:00
|
|
|
assert(score > -1);
|
|
|
|
if (score > max_score) max_score = score;
|
|
|
|
}
|
|
|
|
// break any ties at max_score by a secondary score
|
2016-03-14 03:26:47 +00:00
|
|
|
int min_score2 = 999;
|
|
|
|
int best_index = 0;
|
|
|
|
for (int i = 0; i < SIZE(candidates); ++i) {
|
|
|
|
int score1 = number_of_concrete_type_names(candidates.at(i));
|
2016-02-12 00:13:10 +00:00
|
|
|
assert(score1 <= max_score);
|
|
|
|
if (score1 != max_score) continue;
|
|
|
|
const recipe& candidate = get(Recipe, candidates.at(i));
|
2016-03-14 03:26:47 +00:00
|
|
|
int score2 = (SIZE(candidate.products)-SIZE(inst.products))
|
2016-02-12 00:13:10 +00:00
|
|
|
+ (SIZE(inst.ingredients)-SIZE(candidate.ingredients));
|
|
|
|
assert(score2 < 999);
|
|
|
|
if (score2 < min_score2) {
|
|
|
|
min_score2 = score2;
|
|
|
|
best_index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return candidates.at(best_index);
|
|
|
|
}
|
|
|
|
|
2015-10-31 17:54:48 +00:00
|
|
|
bool any_type_ingredient_in_header(recipe_ordinal variant) {
|
2015-11-28 08:34:34 +00:00
|
|
|
const recipe& caller = get(Recipe, variant);
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(caller.ingredients); ++i) {
|
2015-11-28 08:34:34 +00:00
|
|
|
if (contains_type_ingredient_name(caller.ingredients.at(i)))
|
2015-10-31 17:54:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(caller.products); ++i) {
|
2015-11-28 08:34:34 +00:00
|
|
|
if (contains_type_ingredient_name(caller.products.at(i)))
|
2015-11-10 05:31:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-10-31 17:54:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-06 07:46:39 +00:00
|
|
|
bool concrete_type_names_strictly_match(reagent/*copy*/ to, reagent/*copy*/ from) {
|
2016-01-31 06:22:52 +00:00
|
|
|
canonize_type(to);
|
|
|
|
canonize_type(from);
|
2016-02-21 04:05:52 +00:00
|
|
|
return concrete_type_names_strictly_match(to.type, from.type, from);
|
2015-11-15 20:35:59 +00:00
|
|
|
}
|
|
|
|
|
2016-03-14 03:26:47 +00:00
|
|
|
int number_of_concrete_type_names(recipe_ordinal r) {
|
2015-11-28 08:34:34 +00:00
|
|
|
const recipe& caller = get(Recipe, r);
|
2016-03-14 03:26:47 +00:00
|
|
|
int result = 0;
|
|
|
|
for (int i = 0; i < SIZE(caller.ingredients); ++i)
|
2016-02-21 04:05:52 +00:00
|
|
|
result += number_of_concrete_type_names(caller.ingredients.at(i));
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(caller.products); ++i)
|
2016-02-21 04:05:52 +00:00
|
|
|
result += number_of_concrete_type_names(caller.products.at(i));
|
2015-11-28 08:34:34 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-03-14 03:26:47 +00:00
|
|
|
int number_of_concrete_type_names(const reagent& r) {
|
2016-02-21 04:05:52 +00:00
|
|
|
return number_of_concrete_type_names(r.type);
|
2015-11-28 08:34:34 +00:00
|
|
|
}
|
|
|
|
|
2016-03-14 03:26:47 +00:00
|
|
|
int number_of_concrete_type_names(const type_tree* type) {
|
2015-11-28 08:34:34 +00:00
|
|
|
if (!type) return 0;
|
2016-03-14 03:26:47 +00:00
|
|
|
int result = 0;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (!type->name.empty() && !is_type_ingredient_name(type->name))
|
2016-08-26 20:40:19 +00:00
|
|
|
++result;
|
2016-02-21 04:05:52 +00:00
|
|
|
result += number_of_concrete_type_names(type->left);
|
|
|
|
result += number_of_concrete_type_names(type->right);
|
2015-11-28 08:34:34 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-02-21 04:05:52 +00:00
|
|
|
bool concrete_type_names_strictly_match(const type_tree* to, const type_tree* from, const reagent& rhs_reagent) {
|
2016-01-31 06:22:52 +00:00
|
|
|
if (!to) return !from;
|
|
|
|
if (!from) return !to;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (is_type_ingredient_name(to->name)) return true; // type ingredient matches anything
|
|
|
|
if (to->name == "literal" && from->name == "literal")
|
2015-11-28 05:38:09 +00:00
|
|
|
return true;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (to->name == "literal"
|
|
|
|
&& Literal_type_names.find(from->name) != Literal_type_names.end())
|
2015-11-28 05:38:09 +00:00
|
|
|
return true;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (from->name == "literal"
|
|
|
|
&& Literal_type_names.find(to->name) != Literal_type_names.end())
|
2015-11-28 05:38:09 +00:00
|
|
|
return true;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (from->name == "literal" && to->name == "address")
|
2015-11-15 20:35:59 +00:00
|
|
|
return rhs_reagent.name == "0";
|
2016-02-21 04:05:52 +00:00
|
|
|
return to->name == from->name
|
|
|
|
&& concrete_type_names_strictly_match(to->left, from->left, rhs_reagent)
|
|
|
|
&& concrete_type_names_strictly_match(to->right, from->right, rhs_reagent);
|
2015-10-31 17:54:48 +00:00
|
|
|
}
|
|
|
|
|
2015-11-02 03:42:49 +00:00
|
|
|
bool contains_type_ingredient_name(const reagent& x) {
|
2016-02-21 04:05:52 +00:00
|
|
|
return contains_type_ingredient_name(x.type);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
|
2016-02-21 04:05:52 +00:00
|
|
|
bool contains_type_ingredient_name(const type_tree* type) {
|
2015-11-02 03:42:49 +00:00
|
|
|
if (!type) return false;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (is_type_ingredient_name(type->name)) return true;
|
2015-11-02 03:42:49 +00:00
|
|
|
return contains_type_ingredient_name(type->left) || contains_type_ingredient_name(type->right);
|
|
|
|
}
|
|
|
|
|
2015-11-11 03:56:41 +00:00
|
|
|
recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst, const recipe& caller_recipe) {
|
2015-10-31 17:54:48 +00:00
|
|
|
string new_name = next_unused_recipe_name(inst.name);
|
2015-11-06 21:22:16 +00:00
|
|
|
assert(!contains_key(Recipe_ordinal, new_name));
|
2015-11-08 06:56:06 +00:00
|
|
|
recipe_ordinal new_recipe_ordinal = put(Recipe_ordinal, new_name, Next_recipe_ordinal++);
|
2015-10-31 17:54:48 +00:00
|
|
|
// make a copy
|
2015-11-06 21:22:16 +00:00
|
|
|
assert(contains_key(Recipe, exemplar));
|
2015-11-08 06:56:06 +00:00
|
|
|
assert(!contains_key(Recipe, new_recipe_ordinal));
|
2016-05-25 01:58:23 +00:00
|
|
|
recipe new_recipe = get(Recipe, exemplar);
|
2015-11-28 02:01:55 +00:00
|
|
|
new_recipe.name = new_name;
|
2016-05-27 16:50:39 +00:00
|
|
|
new_recipe.is_autogenerated = true;
|
2016-05-25 01:58:23 +00:00
|
|
|
trace(9993, "transform") << "switching " << inst.name << " to specialized " << header_label(new_recipe) << end();
|
2016-04-28 05:28:55 +00:00
|
|
|
|
|
|
|
// Replace type ingredients with concrete types in new_recipe.
|
|
|
|
//
|
|
|
|
// preprocessing: micro-manage a couple of transforms
|
|
|
|
// a) perform tangle *before* replacing type ingredients, just in case
|
|
|
|
// inserted code involves type ingredients
|
2016-05-25 01:58:23 +00:00
|
|
|
insert_fragments(new_recipe);
|
2016-04-28 05:28:55 +00:00
|
|
|
// b) do the work of check_types_by_name while supporting type-ingredients
|
2015-11-08 06:56:06 +00:00
|
|
|
compute_type_names(new_recipe);
|
|
|
|
// that gives enough information to replace type-ingredients with concrete types
|
2015-11-10 07:02:23 +00:00
|
|
|
{
|
2016-02-22 04:30:02 +00:00
|
|
|
map<string, const type_tree*> mappings;
|
2015-11-11 03:56:41 +00:00
|
|
|
bool error = false;
|
|
|
|
compute_type_ingredient_mappings(get(Recipe, exemplar), inst, mappings, caller_recipe, &error);
|
2016-05-25 02:14:01 +00:00
|
|
|
if (!error) error = (SIZE(mappings) != type_ingredient_count_in_header(exemplar));
|
2015-11-11 03:56:41 +00:00
|
|
|
if (!error) replace_type_ingredients(new_recipe, mappings);
|
2016-02-22 04:30:02 +00:00
|
|
|
for (map<string, const type_tree*>::iterator p = mappings.begin(); p != mappings.end(); ++p)
|
2015-11-10 07:02:23 +00:00
|
|
|
delete p->second;
|
2016-05-25 01:58:23 +00:00
|
|
|
if (error) return 0;
|
2015-11-10 07:02:23 +00:00
|
|
|
}
|
2015-11-15 09:16:51 +00:00
|
|
|
ensure_all_concrete_types(new_recipe, get(Recipe, exemplar));
|
2016-05-25 01:58:23 +00:00
|
|
|
put(Recipe, new_recipe_ordinal, new_recipe);
|
2015-11-08 06:56:06 +00:00
|
|
|
return new_recipe_ordinal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void compute_type_names(recipe& variant) {
|
2015-11-08 21:58:40 +00:00
|
|
|
trace(9993, "transform") << "compute type names: " << variant.name << end();
|
2016-02-22 04:30:02 +00:00
|
|
|
map<string, type_tree*> type_names;
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(variant.ingredients); ++i)
|
2016-06-10 01:14:27 +00:00
|
|
|
save_or_deduce_type_name(variant.ingredients.at(i), type_names, variant, "");
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(variant.products); ++i)
|
2016-06-10 01:14:27 +00:00
|
|
|
save_or_deduce_type_name(variant.products.at(i), type_names, variant, "");
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(variant.steps); ++i) {
|
2015-11-08 06:56:06 +00:00
|
|
|
instruction& inst = variant.steps.at(i);
|
2016-02-19 21:42:45 +00:00
|
|
|
trace(9993, "transform") << " instruction: " << to_string(inst) << end();
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int in = 0; in < SIZE(inst.ingredients); ++in)
|
2016-07-22 02:22:03 +00:00
|
|
|
save_or_deduce_type_name(inst.ingredients.at(in), type_names, variant, " in '" + inst.original_string + "'");
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int out = 0; out < SIZE(inst.products); ++out)
|
2016-07-22 02:22:03 +00:00
|
|
|
save_or_deduce_type_name(inst.products.at(out), type_names, variant, " in '" + inst.original_string + "'");
|
2015-11-08 06:56:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-10 01:14:27 +00:00
|
|
|
void save_or_deduce_type_name(reagent& x, map<string, type_tree*>& type, const recipe& variant, const string& context) {
|
2016-02-22 04:30:02 +00:00
|
|
|
trace(9994, "transform") << " checking " << to_string(x) << ": " << names_to_string(x.type) << end();
|
|
|
|
if (!x.type && contains_key(type, x.name)) {
|
2016-05-17 22:43:07 +00:00
|
|
|
x.type = new type_tree(*get(type, x.name));
|
2016-02-22 04:30:02 +00:00
|
|
|
trace(9994, "transform") << " deducing type to " << names_to_string(x.type) << end();
|
2015-11-08 06:56:06 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-02-22 04:30:02 +00:00
|
|
|
if (!x.type) {
|
2016-06-10 01:14:27 +00:00
|
|
|
raise << maybe(variant.original_name) << "unknown type for '" << x.original_string << "'" << context << " (check the name for typos)\n" << end();
|
2015-11-08 06:56:06 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-02-22 04:30:02 +00:00
|
|
|
if (contains_key(type, x.name)) return;
|
2016-02-21 04:05:52 +00:00
|
|
|
if (x.type->name == "offset" || x.type->name == "variant") return; // special-case for container-access instructions
|
2016-02-22 04:30:02 +00:00
|
|
|
put(type, x.name, x.type);
|
2016-05-21 05:09:06 +00:00
|
|
|
trace(9993, "transform") << "type of '" << x.name << "' is " << names_to_string(x.type) << end();
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 04:30:02 +00:00
|
|
|
void compute_type_ingredient_mappings(const recipe& exemplar, const instruction& inst, map<string, const type_tree*>& mappings, const recipe& caller_recipe, bool* error) {
|
2016-03-14 03:26:47 +00:00
|
|
|
int limit = min(SIZE(inst.ingredients), SIZE(exemplar.ingredients));
|
|
|
|
for (int i = 0; i < limit; ++i) {
|
2015-11-11 04:14:50 +00:00
|
|
|
const reagent& exemplar_reagent = exemplar.ingredients.at(i);
|
2016-05-06 07:46:39 +00:00
|
|
|
reagent/*copy*/ ingredient = inst.ingredients.at(i);
|
2015-11-07 21:33:26 +00:00
|
|
|
canonize_type(ingredient);
|
2015-11-15 09:02:53 +00:00
|
|
|
if (is_mu_address(exemplar_reagent) && ingredient.name == "0") continue; // assume it matches
|
2015-11-11 04:14:50 +00:00
|
|
|
accumulate_type_ingredients(exemplar_reagent, ingredient, mappings, exemplar, inst, caller_recipe, error);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
2015-11-15 08:37:29 +00:00
|
|
|
limit = min(SIZE(inst.products), SIZE(exemplar.products));
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < limit; ++i) {
|
2015-11-11 04:14:50 +00:00
|
|
|
const reagent& exemplar_reagent = exemplar.products.at(i);
|
2016-05-06 07:46:39 +00:00
|
|
|
reagent/*copy*/ product = inst.products.at(i);
|
2016-03-19 22:57:10 +00:00
|
|
|
if (is_dummy(product)) continue;
|
2015-11-07 21:33:26 +00:00
|
|
|
canonize_type(product);
|
2015-11-11 04:14:50 +00:00
|
|
|
accumulate_type_ingredients(exemplar_reagent, product, mappings, exemplar, inst, caller_recipe, error);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-29 21:58:16 +00:00
|
|
|
int min(int a, int b) {
|
2015-11-15 08:37:29 +00:00
|
|
|
return (a < b) ? a : b;
|
|
|
|
}
|
|
|
|
|
2016-02-22 04:30:02 +00:00
|
|
|
void accumulate_type_ingredients(const reagent& exemplar_reagent, reagent& refinement, map<string, const type_tree*>& mappings, const recipe& exemplar, const instruction& call_instruction, const recipe& caller_recipe, bool* error) {
|
|
|
|
assert(refinement.type);
|
|
|
|
accumulate_type_ingredients(exemplar_reagent.type, refinement.type, mappings, exemplar, exemplar_reagent, call_instruction, caller_recipe, error);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 04:30:02 +00:00
|
|
|
void accumulate_type_ingredients(const type_tree* exemplar_type, const type_tree* refinement_type, map<string, const type_tree*>& mappings, const recipe& exemplar, const reagent& exemplar_reagent, const instruction& call_instruction, const recipe& caller_recipe, bool* error) {
|
2015-11-11 04:14:50 +00:00
|
|
|
if (!exemplar_type) return;
|
|
|
|
if (!refinement_type) {
|
2016-02-25 16:24:14 +00:00
|
|
|
// todo: make this smarter; only flag an error if exemplar_type contains some *new* type ingredient
|
2016-03-19 22:57:10 +00:00
|
|
|
raise << maybe(exemplar.name) << "missing type ingredient for " << exemplar_reagent.original_string << '\n' << end();
|
2016-03-21 09:25:52 +00:00
|
|
|
raise << " (called from '" << to_original_string(call_instruction) << "')\n" << end();
|
2015-11-05 08:57:23 +00:00
|
|
|
return;
|
2015-11-05 08:36:02 +00:00
|
|
|
}
|
2016-02-22 04:30:02 +00:00
|
|
|
if (is_type_ingredient_name(exemplar_type->name)) {
|
2016-02-28 02:49:53 +00:00
|
|
|
const type_tree* curr_refinement_type = NULL; // temporary heap allocation; must always be deleted before it goes out of scope
|
|
|
|
if (refinement_type->left)
|
|
|
|
curr_refinement_type = new type_tree(*refinement_type->left);
|
|
|
|
else if (exemplar_type->right)
|
|
|
|
// splice out refinement_type->right, it'll be used later by the exemplar_type->right
|
|
|
|
curr_refinement_type = new type_tree(refinement_type->name, refinement_type->value, NULL);
|
|
|
|
else
|
|
|
|
curr_refinement_type = new type_tree(*refinement_type);
|
|
|
|
assert(!curr_refinement_type->left);
|
2016-02-22 04:30:02 +00:00
|
|
|
if (!contains_key(mappings, exemplar_type->name)) {
|
2016-02-28 02:49:53 +00:00
|
|
|
trace(9993, "transform") << "adding mapping from " << exemplar_type->name << " to " << to_string(curr_refinement_type) << end();
|
|
|
|
put(mappings, exemplar_type->name, new type_tree(*curr_refinement_type));
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-02-28 02:49:53 +00:00
|
|
|
if (!deeply_equal_type_names(get(mappings, exemplar_type->name), curr_refinement_type)) {
|
2016-03-21 09:25:52 +00:00
|
|
|
raise << maybe(caller_recipe.name) << "no call found for '" << to_original_string(call_instruction) << "'\n" << end();
|
2015-11-11 03:56:41 +00:00
|
|
|
*error = true;
|
2016-02-28 02:49:53 +00:00
|
|
|
delete curr_refinement_type;
|
2015-11-11 03:56:41 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-02-22 04:30:02 +00:00
|
|
|
if (get(mappings, exemplar_type->name)->name == "literal") {
|
|
|
|
delete get(mappings, exemplar_type->name);
|
2016-02-28 02:49:53 +00:00
|
|
|
put(mappings, exemplar_type->name, new type_tree(*curr_refinement_type));
|
2015-11-28 05:38:09 +00:00
|
|
|
}
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
2016-02-28 02:49:53 +00:00
|
|
|
delete curr_refinement_type;
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-11-11 04:14:50 +00:00
|
|
|
accumulate_type_ingredients(exemplar_type->left, refinement_type->left, mappings, exemplar, exemplar_reagent, call_instruction, caller_recipe, error);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
2015-11-11 04:14:50 +00:00
|
|
|
accumulate_type_ingredients(exemplar_type->right, refinement_type->right, mappings, exemplar, exemplar_reagent, call_instruction, caller_recipe, error);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 04:30:02 +00:00
|
|
|
void replace_type_ingredients(recipe& new_recipe, const map<string, const type_tree*>& mappings) {
|
2015-10-31 17:54:48 +00:00
|
|
|
// update its header
|
2015-11-02 03:42:49 +00:00
|
|
|
if (mappings.empty()) return;
|
|
|
|
trace(9993, "transform") << "replacing in recipe header ingredients" << end();
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(new_recipe.ingredients); ++i)
|
2015-11-17 18:47:11 +00:00
|
|
|
replace_type_ingredients(new_recipe.ingredients.at(i), mappings, new_recipe);
|
2015-11-02 03:42:49 +00:00
|
|
|
trace(9993, "transform") << "replacing in recipe header products" << end();
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(new_recipe.products); ++i)
|
2015-11-17 18:47:11 +00:00
|
|
|
replace_type_ingredients(new_recipe.products.at(i), mappings, new_recipe);
|
2015-10-31 17:54:48 +00:00
|
|
|
// update its body
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(new_recipe.steps); ++i) {
|
2015-10-31 17:54:48 +00:00
|
|
|
instruction& inst = new_recipe.steps.at(i);
|
2016-02-19 21:42:45 +00:00
|
|
|
trace(9993, "transform") << "replacing in instruction '" << to_string(inst) << "'" << end();
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int j = 0; j < SIZE(inst.ingredients); ++j)
|
2015-11-17 18:47:11 +00:00
|
|
|
replace_type_ingredients(inst.ingredients.at(j), mappings, new_recipe);
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int j = 0; j < SIZE(inst.products); ++j)
|
2015-11-17 18:47:11 +00:00
|
|
|
replace_type_ingredients(inst.products.at(j), mappings, new_recipe);
|
2015-11-08 06:56:06 +00:00
|
|
|
// special-case for new: replace type ingredient in first ingredient *value*
|
2016-02-21 04:05:52 +00:00
|
|
|
if (inst.name == "new" && inst.ingredients.at(0).type->name != "literal-string") {
|
2016-02-22 04:30:02 +00:00
|
|
|
type_tree* type = parse_type_tree(inst.ingredients.at(0).name);
|
|
|
|
replace_type_ingredients(type, mappings);
|
|
|
|
inst.ingredients.at(0).name = inspect(type);
|
|
|
|
delete type;
|
2015-11-08 06:56:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-22 04:30:02 +00:00
|
|
|
void replace_type_ingredients(reagent& x, const map<string, const type_tree*>& mappings, const recipe& caller) {
|
|
|
|
string before = to_string(x);
|
2015-11-02 03:42:49 +00:00
|
|
|
trace(9993, "transform") << "replacing in ingredient " << x.original_string << end();
|
2016-02-22 04:30:02 +00:00
|
|
|
if (!x.type) {
|
2016-05-21 05:09:06 +00:00
|
|
|
raise << "specializing " << caller.original_name << ": missing type for '" << x.original_string << "'\n" << end();
|
2015-11-17 18:47:11 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-02-22 04:30:02 +00:00
|
|
|
replace_type_ingredients(x.type, mappings);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
|
|
|
|
2016-02-28 08:33:55 +00:00
|
|
|
// todo: too complicated and likely incomplete; maybe avoid replacing in place?
|
2016-02-22 04:30:02 +00:00
|
|
|
void replace_type_ingredients(type_tree* type, const map<string, const type_tree*>& mappings) {
|
2015-11-02 03:42:49 +00:00
|
|
|
if (!type) return;
|
2016-02-22 04:40:14 +00:00
|
|
|
if (contains_key(Type_ordinal, type->name)) // todo: ugly side effect
|
2016-02-22 04:30:02 +00:00
|
|
|
type->value = get(Type_ordinal, type->name);
|
2016-02-28 02:49:53 +00:00
|
|
|
if (!is_type_ingredient_name(type->name) || !contains_key(mappings, type->name)) {
|
|
|
|
replace_type_ingredients(type->left, mappings);
|
|
|
|
replace_type_ingredients(type->right, mappings);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const type_tree* replacement = get(mappings, type->name);
|
|
|
|
trace(9993, "transform") << type->name << " => " << names_to_string(replacement) << end();
|
2016-04-16 00:40:12 +00:00
|
|
|
if (!contains_key(Type_ordinal, replacement->name)) {
|
|
|
|
// error in program; should be reported elsewhere
|
|
|
|
return;
|
|
|
|
}
|
2016-02-28 02:49:53 +00:00
|
|
|
|
|
|
|
// type is a single type ingredient
|
|
|
|
assert(!type->left);
|
|
|
|
if (!type->right) assert(!replacement->left);
|
|
|
|
|
|
|
|
if (!replacement->right) {
|
|
|
|
if (!replacement->left) {
|
|
|
|
type->name = (replacement->name == "literal") ? "number" : replacement->name;
|
|
|
|
type->value = get(Type_ordinal, type->name);
|
2016-02-22 04:30:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-02-28 02:49:53 +00:00
|
|
|
type->name = "";
|
|
|
|
type->value = 0;
|
|
|
|
type->left = new type_tree(*replacement);
|
2016-02-22 04:30:02 +00:00
|
|
|
}
|
2016-02-28 02:49:53 +00:00
|
|
|
replace_type_ingredients(type->right, mappings);
|
|
|
|
}
|
|
|
|
// replace non-last type?
|
|
|
|
else if (type->right) {
|
|
|
|
type->name = "";
|
|
|
|
type->value = 0;
|
|
|
|
type->left = new type_tree(*replacement);
|
|
|
|
replace_type_ingredients(type->right, mappings);
|
|
|
|
}
|
|
|
|
// replace last type?
|
|
|
|
else {
|
|
|
|
type->name = replacement->name;
|
|
|
|
type->value = get(Type_ordinal, type->name);
|
|
|
|
type->right = new type_tree(*replacement->right);
|
2015-11-02 03:42:49 +00:00
|
|
|
}
|
2015-10-31 17:54:48 +00:00
|
|
|
}
|
2015-11-01 00:18:59 +00:00
|
|
|
|
2016-05-25 02:14:01 +00:00
|
|
|
int type_ingredient_count_in_header(recipe_ordinal variant) {
|
|
|
|
const recipe& caller = get(Recipe, variant);
|
|
|
|
set<string> type_ingredients;
|
|
|
|
for (int i = 0; i < SIZE(caller.ingredients); ++i)
|
|
|
|
accumulate_type_ingredients(caller.ingredients.at(i).type, type_ingredients);
|
|
|
|
for (int i = 0; i < SIZE(caller.products); ++i)
|
|
|
|
accumulate_type_ingredients(caller.products.at(i).type, type_ingredients);
|
|
|
|
return SIZE(type_ingredients);
|
|
|
|
}
|
|
|
|
|
|
|
|
void accumulate_type_ingredients(const type_tree* type, set<string>& out) {
|
|
|
|
if (!type) return;
|
|
|
|
if (is_type_ingredient_name(type->name)) out.insert(type->name);
|
|
|
|
accumulate_type_ingredients(type->left, out);
|
|
|
|
accumulate_type_ingredients(type->right, out);
|
|
|
|
}
|
|
|
|
|
2016-02-22 04:30:02 +00:00
|
|
|
type_tree* parse_type_tree(const string& s) {
|
|
|
|
istringstream in(s);
|
|
|
|
in >> std::noskipws;
|
|
|
|
return parse_type_tree(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_tree* parse_type_tree(istream& in) {
|
|
|
|
skip_whitespace_but_not_newline(in);
|
|
|
|
if (!has_data(in)) return NULL;
|
|
|
|
if (in.peek() == ')') {
|
|
|
|
in.get();
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-03-19 07:51:19 +00:00
|
|
|
if (in.peek() != '(')
|
|
|
|
return new type_tree(next_word(in), 0);
|
2016-02-22 04:30:02 +00:00
|
|
|
in.get(); // skip '('
|
|
|
|
type_tree* result = NULL;
|
|
|
|
type_tree** curr = &result;
|
|
|
|
while (in.peek() != ')') {
|
|
|
|
assert(has_data(in));
|
|
|
|
*curr = new type_tree("", 0);
|
|
|
|
skip_whitespace_but_not_newline(in);
|
|
|
|
if (in.peek() == '(')
|
|
|
|
(*curr)->left = parse_type_tree(in);
|
2016-03-19 07:51:19 +00:00
|
|
|
else
|
2016-02-22 04:30:02 +00:00
|
|
|
(*curr)->name = next_word(in);
|
|
|
|
curr = &(*curr)->right;
|
|
|
|
}
|
|
|
|
in.get(); // skip ')'
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
string inspect(const type_tree* x) {
|
2016-02-21 04:44:59 +00:00
|
|
|
ostringstream out;
|
|
|
|
dump_inspect(x, out);
|
|
|
|
return out.str();
|
|
|
|
}
|
|
|
|
|
2016-02-22 04:30:02 +00:00
|
|
|
void dump_inspect(const type_tree* x, ostream& out) {
|
2016-02-21 04:44:59 +00:00
|
|
|
if (!x->left && !x->right) {
|
2016-02-22 04:30:02 +00:00
|
|
|
out << x->name;
|
2016-02-21 04:44:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
out << '(';
|
2016-02-22 04:30:02 +00:00
|
|
|
for (const type_tree* curr = x; curr; curr = curr->right) {
|
2016-02-21 04:44:59 +00:00
|
|
|
if (curr != x) out << ' ';
|
|
|
|
if (curr->left)
|
|
|
|
dump_inspect(curr->left, out);
|
|
|
|
else
|
2016-02-22 04:30:02 +00:00
|
|
|
out << curr->name;
|
2016-02-21 04:44:59 +00:00
|
|
|
}
|
|
|
|
out << ')';
|
|
|
|
}
|
|
|
|
|
2015-11-15 09:16:51 +00:00
|
|
|
void ensure_all_concrete_types(/*const*/ recipe& new_recipe, const recipe& exemplar) {
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(new_recipe.ingredients); ++i)
|
2015-11-15 09:16:51 +00:00
|
|
|
ensure_all_concrete_types(new_recipe.ingredients.at(i), exemplar);
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(new_recipe.products); ++i)
|
2015-11-15 09:16:51 +00:00
|
|
|
ensure_all_concrete_types(new_recipe.products.at(i), exemplar);
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int i = 0; i < SIZE(new_recipe.steps); ++i) {
|
2015-11-15 09:16:51 +00:00
|
|
|
instruction& inst = new_recipe.steps.at(i);
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int j = 0; j < SIZE(inst.ingredients); ++j)
|
2015-11-15 09:16:51 +00:00
|
|
|
ensure_all_concrete_types(inst.ingredients.at(j), exemplar);
|
2016-03-14 03:26:47 +00:00
|
|
|
for (int j = 0; j < SIZE(inst.products); ++j)
|
2015-11-15 09:16:51 +00:00
|
|
|
ensure_all_concrete_types(inst.products.at(j), exemplar);
|
2015-11-08 06:56:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-15 09:16:51 +00:00
|
|
|
void ensure_all_concrete_types(/*const*/ reagent& x, const recipe& exemplar) {
|
2016-02-22 04:40:14 +00:00
|
|
|
if (!x.type || contains_type_ingredient_name(x.type)) {
|
2016-02-26 21:04:55 +00:00
|
|
|
raise << maybe(exemplar.name) << "failed to map a type to " << x.original_string << '\n' << end();
|
2016-02-23 02:35:52 +00:00
|
|
|
if (!x.type) x.type = new type_tree("", 0); // just to prevent crashes later
|
2015-11-08 06:56:06 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-11-15 09:16:51 +00:00
|
|
|
if (x.type->value == -1) {
|
2016-02-26 21:04:55 +00:00
|
|
|
raise << maybe(exemplar.name) << "failed to map a type to the unknown " << x.original_string << '\n' << end();
|
2015-11-08 06:56:06 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe_2)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-01 00:18:59 +00:00
|
|
|
10:point <- merge 14, 15
|
|
|
|
11:point <- foo 10:point
|
|
|
|
]
|
2015-11-11 04:24:03 +00:00
|
|
|
# non-matching shape-shifting variant
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:_t, b:_t -> result:number [
|
2015-11-01 00:18:59 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
result <- copy 34
|
|
|
|
]
|
2015-11-11 04:24:03 +00:00
|
|
|
# matching shape-shifting variant
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:_t -> result:_t [
|
2015-11-01 00:18:59 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
result <- copy a
|
|
|
|
]
|
|
|
|
+mem: storing 14 in location 11
|
|
|
|
+mem: storing 15 in location 12
|
2015-11-02 03:42:49 +00:00
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe_nonroot)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-02 03:42:49 +00:00
|
|
|
10:foo:point <- merge 14, 15, 16
|
|
|
|
20:point/raw <- bar 10:foo:point
|
|
|
|
]
|
2015-11-11 04:24:03 +00:00
|
|
|
# shape-shifting recipe with type ingredient following some other type
|
2016-03-08 09:30:14 +00:00
|
|
|
def bar a:foo:_t -> result:_t [
|
2015-11-02 03:42:49 +00:00
|
|
|
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
|
2015-11-09 23:19:51 +00:00
|
|
|
|
2016-02-28 02:49:53 +00:00
|
|
|
:(scenario shape_shifting_recipe_nested)
|
|
|
|
container c:_a:_b [
|
|
|
|
a:_a
|
|
|
|
b:_b
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-04-24 18:54:30 +00:00
|
|
|
s:address:array:character <- new [abc]
|
|
|
|
{x: (c (address array character) number)} <- merge s, 34
|
2016-02-28 02:49:53 +00:00
|
|
|
foo x
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:c:_bar:_baz [
|
2016-02-28 02:49:53 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
]
|
2016-07-11 04:47:24 +00:00
|
|
|
# no errors
|
2016-02-28 02:49:53 +00:00
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe_type_deduction_ignores_offsets)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-09 23:19:51 +00:00
|
|
|
10:foo:point <- merge 14, 15, 16
|
|
|
|
20:point/raw <- bar 10:foo:point
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def bar a:foo:_t -> result:_t [
|
2015-11-09 23:19:51 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
x:number <- copy 1
|
|
|
|
result <- get a, x:offset # shouldn't collide with other variable
|
|
|
|
]
|
|
|
|
container foo:_t [
|
|
|
|
x:_t
|
|
|
|
y:number
|
|
|
|
]
|
|
|
|
+mem: storing 14 in location 20
|
|
|
|
+mem: storing 15 in location 21
|
2015-11-10 05:31:21 +00:00
|
|
|
|
2016-01-31 06:30:08 +00:00
|
|
|
:(scenario shape_shifting_recipe_empty)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-01-31 06:30:08 +00:00
|
|
|
foo 1
|
|
|
|
]
|
|
|
|
# shape-shifting recipe with no body
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:_t [
|
2016-01-31 06:30:08 +00:00
|
|
|
]
|
|
|
|
# shouldn't crash
|
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-04-24 18:54:30 +00:00
|
|
|
1:address:foo:point <- bar 3
|
|
|
|
11:foo:point <- copy *1:address:foo:point
|
2015-11-10 05:31:21 +00:00
|
|
|
]
|
|
|
|
container foo:_t [
|
|
|
|
x:_t
|
|
|
|
y:number
|
|
|
|
]
|
2016-04-24 18:54:30 +00:00
|
|
|
def bar x:number -> result:address:foo:_t [
|
2015-11-10 05:31:21 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
# new refers to _t in its ingredient *value*
|
|
|
|
result <- new {(foo _t) : type}
|
|
|
|
]
|
|
|
|
+mem: storing 0 in location 11
|
|
|
|
+mem: storing 0 in location 12
|
|
|
|
+mem: storing 0 in location 13
|
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient_2)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-04-24 18:54:30 +00:00
|
|
|
1:address:foo:point <- bar 3
|
|
|
|
11:foo:point <- copy *1:address:foo:point
|
2015-11-10 07:02:23 +00:00
|
|
|
]
|
2016-04-24 18:54:30 +00:00
|
|
|
def bar x:number -> result:address:foo:_t [
|
2015-11-10 07:02:23 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
# new refers to _t in its ingredient *value*
|
|
|
|
result <- new {(foo _t) : type}
|
|
|
|
]
|
|
|
|
# container defined after use
|
|
|
|
container foo:_t [
|
|
|
|
x:_t
|
|
|
|
y:number
|
|
|
|
]
|
|
|
|
+mem: storing 0 in location 11
|
|
|
|
+mem: storing 0 in location 12
|
|
|
|
+mem: storing 0 in location 13
|
2015-11-10 07:26:15 +00:00
|
|
|
|
2016-03-19 22:57:10 +00:00
|
|
|
:(scenario shape_shifting_recipe_called_with_dummy)
|
|
|
|
def main [
|
|
|
|
_ <- bar 34
|
|
|
|
]
|
2016-04-24 18:54:30 +00:00
|
|
|
def bar x:_t -> result:address:_t [
|
2016-03-19 22:57:10 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
result <- copy 0
|
|
|
|
]
|
|
|
|
$error: 0
|
|
|
|
|
2016-03-19 07:24:52 +00:00
|
|
|
:(code)
|
|
|
|
// this one needs a little more fine-grained control
|
|
|
|
void test_shape_shifting_new_ingredient_does_not_pollute_global_namespace() {
|
|
|
|
// if you specialize a shape-shifting recipe that allocates a type-ingredient..
|
|
|
|
transform("def barz x:_elem [\n"
|
|
|
|
" local-scope\n"
|
|
|
|
" load-ingredients\n"
|
2016-04-24 18:54:30 +00:00
|
|
|
" y:address:number <- new _elem:type\n"
|
2016-03-19 07:24:52 +00:00
|
|
|
"]\n"
|
|
|
|
"def fooz [\n"
|
|
|
|
" local-scope\n"
|
|
|
|
" barz 34\n"
|
|
|
|
"]\n");
|
|
|
|
// ..and if you then try to load a new shape-shifting container with that
|
|
|
|
// type-ingredient
|
|
|
|
run("container foo:_elem [\n"
|
|
|
|
" x:_elem\n"
|
|
|
|
" y:number\n"
|
|
|
|
"]\n");
|
|
|
|
// then it should work as usual
|
|
|
|
reagent callsite("x:foo:point");
|
2016-04-30 17:09:38 +00:00
|
|
|
reagent element = element_type(callsite.type, 0);
|
2016-03-19 07:24:52 +00:00
|
|
|
CHECK_EQ(element.name, "x");
|
|
|
|
CHECK_EQ(element.type->name, "point");
|
|
|
|
CHECK(!element.type->right);
|
|
|
|
}
|
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe_supports_compound_types)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-04-24 18:54:30 +00:00
|
|
|
1:address:point <- new point:type
|
|
|
|
*1:address:point <- put *1:address:point, y:offset, 34
|
|
|
|
3:address:point <- bar 1:address:point # specialize _t to address:point
|
|
|
|
4:point <- copy *3:address:point
|
2015-11-10 07:26:15 +00:00
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def bar a:_t -> result:_t [
|
2015-11-10 07:26:15 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
result <- copy a
|
|
|
|
]
|
|
|
|
+mem: storing 34 in location 5
|
2015-11-11 03:56:41 +00:00
|
|
|
|
2015-11-11 04:24:03 +00:00
|
|
|
:(scenario shape_shifting_recipe_error)
|
2015-11-11 03:56:41 +00:00
|
|
|
% Hide_errors = true;
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-11 03:56:41 +00:00
|
|
|
a:number <- copy 3
|
2016-04-24 18:54:30 +00:00
|
|
|
b:address:number <- foo a
|
2015-11-11 03:56:41 +00:00
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:_t -> b:_t [
|
2015-11-11 03:56:41 +00:00
|
|
|
load-ingredients
|
|
|
|
b <- copy a
|
|
|
|
]
|
2016-04-24 18:54:30 +00:00
|
|
|
+error: main: no call found for 'b:address:number <- foo a'
|
2015-11-15 06:59:09 +00:00
|
|
|
|
|
|
|
:(scenario specialize_inside_recipe_without_header)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 06:59:09 +00:00
|
|
|
foo 3
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo [
|
2015-11-15 06:59:09 +00:00
|
|
|
local-scope
|
|
|
|
x:number <- next-ingredient # ensure no header
|
|
|
|
1:number/raw <- bar x # call a shape-shifting recipe
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def bar x:_elem -> y:_elem [
|
2015-11-15 06:59:09 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
y <- add x, 1
|
|
|
|
]
|
|
|
|
+mem: storing 4 in location 1
|
2015-11-15 08:37:29 +00:00
|
|
|
|
|
|
|
:(scenario specialize_with_literal)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 08:37:29 +00:00
|
|
|
local-scope
|
|
|
|
# permit literal to map to number
|
|
|
|
1:number/raw <- foo 3
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:_elem -> y:_elem [
|
2015-11-15 08:37:29 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
y <- add x, 1
|
|
|
|
]
|
|
|
|
+mem: storing 4 in location 1
|
|
|
|
|
|
|
|
:(scenario specialize_with_literal_2)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 08:37:29 +00:00
|
|
|
local-scope
|
|
|
|
# permit literal to map to character
|
|
|
|
1:character/raw <- foo 3
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:_elem -> y:_elem [
|
2015-11-15 08:37:29 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
y <- add x, 1
|
|
|
|
]
|
|
|
|
+mem: storing 4 in location 1
|
2015-11-15 09:02:53 +00:00
|
|
|
|
|
|
|
:(scenario specialize_with_literal_3)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 09:02:53 +00:00
|
|
|
local-scope
|
|
|
|
# permit '0' to map to address to shape-shifting type-ingredient
|
2016-04-24 18:54:30 +00:00
|
|
|
1:address:character/raw <- foo 0
|
2015-11-15 09:02:53 +00:00
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:address:_elem -> y:address:_elem [
|
2015-11-15 09:02:53 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
y <- copy x
|
|
|
|
]
|
|
|
|
+mem: storing 0 in location 1
|
|
|
|
$error: 0
|
2015-11-15 09:16:51 +00:00
|
|
|
|
|
|
|
:(scenario specialize_with_literal_4)
|
|
|
|
% Hide_errors = true;
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 09:16:51 +00:00
|
|
|
local-scope
|
|
|
|
# ambiguous call: what's the type of its ingredient?!
|
|
|
|
foo 0
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:address:_elem -> y:address:_elem [
|
2015-11-15 09:16:51 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
y <- copy x
|
|
|
|
]
|
2016-05-21 05:09:06 +00:00
|
|
|
+error: main: instruction 'foo' has no valid specialization
|
2015-11-15 09:44:58 +00:00
|
|
|
|
|
|
|
:(scenario specialize_with_literal_5)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 09:44:58 +00:00
|
|
|
foo 3, 4 # recipe mapping two variables to literals
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:_elem, y:_elem [
|
2015-11-15 09:44:58 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
1:number/raw <- add x, y
|
|
|
|
]
|
|
|
|
+mem: storing 7 in location 1
|
2015-11-15 20:35:59 +00:00
|
|
|
|
|
|
|
:(scenario multiple_shape_shifting_variants)
|
|
|
|
# try to call two different shape-shifting recipes with the same name
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 20:35:59 +00:00
|
|
|
e1:d1:number <- merge 3
|
|
|
|
e2:d2:number <- merge 4, 5
|
|
|
|
1:number/raw <- foo e1
|
|
|
|
2:number/raw <- foo e2
|
|
|
|
]
|
|
|
|
# the two shape-shifting definitions
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:d1:_elem -> b:number [
|
2015-11-15 20:35:59 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2015-11-15 20:35:59 +00:00
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:d2:_elem -> b:number [
|
2015-11-15 20:35:59 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 35
|
2015-11-15 20:35:59 +00:00
|
|
|
]
|
|
|
|
# the shape-shifting containers they use
|
|
|
|
container d1:_elem [
|
|
|
|
x:_elem
|
|
|
|
]
|
|
|
|
container d2:_elem [
|
|
|
|
x:number
|
|
|
|
y:_elem
|
|
|
|
]
|
|
|
|
+mem: storing 34 in location 1
|
|
|
|
+mem: storing 35 in location 2
|
|
|
|
|
|
|
|
:(scenario multiple_shape_shifting_variants_2)
|
|
|
|
# static dispatch between shape-shifting variants, _including pointer lookups_
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-15 20:35:59 +00:00
|
|
|
e1:d1:number <- merge 3
|
2016-04-24 18:54:30 +00:00
|
|
|
e2:address:d2:number <- new {(d2 number): type}
|
2015-11-15 20:35:59 +00:00
|
|
|
1:number/raw <- foo e1
|
|
|
|
2:number/raw <- foo *e2 # different from previous scenario
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:d1:_elem -> b:number [
|
2015-11-15 20:35:59 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2015-11-15 20:35:59 +00:00
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:d2:_elem -> b:number [
|
2015-11-15 20:35:59 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 35
|
2015-11-15 20:35:59 +00:00
|
|
|
]
|
|
|
|
container d1:_elem [
|
|
|
|
x:_elem
|
|
|
|
]
|
|
|
|
container d2:_elem [
|
|
|
|
x:number
|
|
|
|
y:_elem
|
|
|
|
]
|
|
|
|
+mem: storing 34 in location 1
|
|
|
|
+mem: storing 35 in location 2
|
2015-11-17 18:47:11 +00:00
|
|
|
|
|
|
|
:(scenario missing_type_in_shape_shifting_recipe)
|
|
|
|
% Hide_errors = true;
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-17 18:47:11 +00:00
|
|
|
a:d1:number <- merge 3
|
|
|
|
foo a
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:d1:_elem -> b:number [
|
2015-11-17 18:47:11 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
copy e # no such variable
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2015-11-17 18:47:11 +00:00
|
|
|
]
|
|
|
|
container d1:_elem [
|
|
|
|
x:_elem
|
|
|
|
]
|
2016-06-10 01:14:27 +00:00
|
|
|
+error: foo: unknown type for 'e' in 'copy e' (check the name for typos)
|
2016-05-21 05:09:06 +00:00
|
|
|
+error: specializing foo: missing type for 'e'
|
2015-11-17 18:47:11 +00:00
|
|
|
# and it doesn't crash
|
2015-11-17 19:25:00 +00:00
|
|
|
|
|
|
|
:(scenario missing_type_in_shape_shifting_recipe_2)
|
|
|
|
% Hide_errors = true;
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-17 19:25:00 +00:00
|
|
|
a:d1:number <- merge 3
|
|
|
|
foo a
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo a:d1:_elem -> b:number [
|
2015-11-17 19:25:00 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
get e, x:offset # unknown variable in a 'get', which does some extra checking
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2015-11-17 19:25:00 +00:00
|
|
|
]
|
|
|
|
container d1:_elem [
|
|
|
|
x:_elem
|
|
|
|
]
|
2016-06-10 01:14:27 +00:00
|
|
|
+error: foo: unknown type for 'e' in 'get e, x:offset' (check the name for typos)
|
2016-05-21 05:09:06 +00:00
|
|
|
+error: specializing foo: missing type for 'e'
|
2015-11-17 19:25:00 +00:00
|
|
|
# and it doesn't crash
|
2015-11-28 01:54:34 +00:00
|
|
|
|
|
|
|
:(scenarios transform)
|
|
|
|
:(scenario specialize_recursive_shape_shifting_recipe)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2015-11-28 01:54:34 +00:00
|
|
|
1:number <- copy 34
|
|
|
|
2:number <- foo 1:number
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:_elem -> y:number [
|
2015-11-28 01:54:34 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
{
|
|
|
|
break
|
|
|
|
y:number <- foo x
|
|
|
|
}
|
2016-03-08 09:30:14 +00:00
|
|
|
return y
|
2015-11-28 01:54:34 +00:00
|
|
|
]
|
2015-11-28 02:01:55 +00:00
|
|
|
+transform: new specialization: foo_2
|
2015-11-28 01:54:34 +00:00
|
|
|
# transform terminates
|
2015-11-28 08:34:34 +00:00
|
|
|
|
|
|
|
:(scenarios run)
|
|
|
|
:(scenario specialize_most_similar_variant)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-04-24 18:54:30 +00:00
|
|
|
1:address:number <- new number:type
|
|
|
|
2:number <- foo 1:address:number
|
2015-11-28 08:34:34 +00:00
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:_elem -> y:number [
|
2015-11-28 08:34:34 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2015-11-28 08:34:34 +00:00
|
|
|
]
|
2016-04-24 18:54:30 +00:00
|
|
|
def foo x:address:_elem -> y:number [
|
2015-11-28 08:34:34 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 35
|
2015-11-28 08:34:34 +00:00
|
|
|
]
|
|
|
|
+mem: storing 35 in location 2
|
2016-02-12 01:36:58 +00:00
|
|
|
|
|
|
|
:(scenario specialize_most_similar_variant_2)
|
|
|
|
# version with headers padded with lots of unrelated concrete types
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-02-12 01:36:58 +00:00
|
|
|
1:number <- copy 23
|
2016-04-24 18:54:30 +00:00
|
|
|
2:address:array:number <- copy 0
|
|
|
|
3:number <- foo 2:address:array:number, 1:number
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
|
|
|
# variant with concrete type
|
2016-04-24 18:54:30 +00:00
|
|
|
def foo dummy:address:array:number, x:number -> y:number, dummy:address:array:number [
|
2016-02-12 01:36:58 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
|
|
|
# shape-shifting variant
|
2016-04-24 18:54:30 +00:00
|
|
|
def foo dummy:address:array:number, x:_elem -> y:number, dummy:address:array:number [
|
2016-02-12 01:36:58 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 35
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
|
|
|
# prefer the concrete variant
|
|
|
|
+mem: storing 34 in location 3
|
|
|
|
|
|
|
|
:(scenario specialize_most_similar_variant_3)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-04-24 18:54:30 +00:00
|
|
|
1:address:array:character <- new [abc]
|
|
|
|
foo 1:address:array:character
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
2016-04-24 18:54:30 +00:00
|
|
|
def foo x:address:array:character [
|
2016-02-12 01:36:58 +00:00
|
|
|
2:number <- copy 34
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:address:_elem [
|
2016-02-12 01:36:58 +00:00
|
|
|
2:number <- copy 35
|
|
|
|
]
|
|
|
|
# make sure the more precise version was used
|
|
|
|
+mem: storing 34 in location 2
|
|
|
|
|
|
|
|
:(scenario specialize_literal_as_number)
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-02-12 01:36:58 +00:00
|
|
|
1:number <- foo 23
|
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:_elem -> y:number [
|
2016-02-12 01:36:58 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:character -> y:number [
|
2016-02-12 01:36:58 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 35
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
|
|
|
+mem: storing 34 in location 1
|
|
|
|
|
|
|
|
:(scenario specialize_literal_as_number_2)
|
|
|
|
# version calling with literal
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-02-12 01:36:58 +00:00
|
|
|
1:number <- foo 0
|
|
|
|
]
|
|
|
|
# variant with concrete type
|
2016-03-08 09:30:14 +00:00
|
|
|
def foo x:number -> y:number [
|
2016-02-12 01:36:58 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 34
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
|
|
|
# shape-shifting variant
|
2016-04-24 18:54:30 +00:00
|
|
|
def foo x:address:_elem -> y:number [
|
2016-02-12 01:36:58 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-03-08 09:30:14 +00:00
|
|
|
return 35
|
2016-02-12 01:36:58 +00:00
|
|
|
]
|
|
|
|
# prefer the concrete variant, ignore concrete types in scoring the shape-shifting variant
|
|
|
|
+mem: storing 34 in location 1
|
2016-04-16 00:40:12 +00:00
|
|
|
|
2016-05-06 04:47:59 +00:00
|
|
|
:(scenario specialize_literal_as_address)
|
|
|
|
def main [
|
|
|
|
1:number <- foo 0
|
|
|
|
]
|
|
|
|
# variant with concrete address type
|
|
|
|
def foo x:address:number -> y:number [
|
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
return 34
|
|
|
|
]
|
|
|
|
# shape-shifting variant
|
|
|
|
def foo x:address:_elem -> y:number [
|
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
return 35
|
|
|
|
]
|
|
|
|
# prefer the concrete variant, ignore concrete types in scoring the shape-shifting variant
|
|
|
|
+mem: storing 34 in location 1
|
|
|
|
|
2016-04-16 00:40:12 +00:00
|
|
|
:(scenario missing_type_during_specialization)
|
|
|
|
% Hide_errors = true;
|
|
|
|
# define a shape-shifting recipe
|
2016-04-16 05:34:08 +00:00
|
|
|
def foo a:_elem [
|
2016-04-16 00:40:12 +00:00
|
|
|
]
|
|
|
|
# define a container with field 'z'
|
|
|
|
container foo2 [
|
|
|
|
z:number
|
|
|
|
]
|
|
|
|
def main [
|
|
|
|
local-scope
|
|
|
|
x:foo2 <- merge 34
|
|
|
|
y:number <- get x, z:offse # typo in 'offset'
|
|
|
|
# define a variable with the same name 'z'
|
|
|
|
z:number <- copy 34
|
|
|
|
# trigger specialization of the shape-shifting recipe
|
2016-04-16 05:34:08 +00:00
|
|
|
foo z
|
|
|
|
]
|
|
|
|
# shouldn't crash
|
|
|
|
|
|
|
|
:(scenario missing_type_during_specialization2)
|
|
|
|
% Hide_errors = true;
|
|
|
|
# define a shape-shifting recipe
|
|
|
|
def foo a:_elem [
|
|
|
|
]
|
|
|
|
# define a container with field 'z'
|
|
|
|
container foo2 [
|
|
|
|
z:number
|
|
|
|
]
|
|
|
|
def main [
|
|
|
|
local-scope
|
|
|
|
x:foo2 <- merge 34
|
|
|
|
y:number <- get x, z:offse # typo in 'offset'
|
|
|
|
# define a variable with the same name 'z'
|
|
|
|
z:address:number <- copy 34
|
|
|
|
# trigger specialization of the shape-shifting recipe
|
|
|
|
foo *z
|
2016-04-16 00:40:12 +00:00
|
|
|
]
|
|
|
|
# shouldn't crash
|
2016-04-28 05:28:55 +00:00
|
|
|
|
|
|
|
:(scenario tangle_shape_shifting_recipe)
|
|
|
|
# shape-shifting recipe
|
|
|
|
def foo a:_elem [
|
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
<label1>
|
|
|
|
]
|
|
|
|
# tangle some code that refers to the type ingredient
|
|
|
|
after <label1> [
|
|
|
|
b:_elem <- copy a
|
|
|
|
]
|
|
|
|
# trigger specialization
|
|
|
|
def main [
|
|
|
|
local-scope
|
|
|
|
foo 34
|
|
|
|
]
|
2016-05-25 01:43:25 +00:00
|
|
|
$error: 0
|
2016-05-25 02:14:01 +00:00
|
|
|
|
|
|
|
:(scenario shape_shifting_recipe_coexists_with_primitive)
|
|
|
|
# recipe overloading a primitive with a generic type
|
|
|
|
def add a:address:foo:_elem [
|
|
|
|
assert 0, [should not get here]
|
|
|
|
]
|
|
|
|
def main [
|
|
|
|
# call primitive add with literal 0
|
|
|
|
add 0, 0
|
|
|
|
]
|
|
|
|
$error: 0
|