2417 - support mutable ingredients in headers

If a name repeats between ingredients, we raise an error.
If a name repeats across ingredients and products, every call should
share the same name across the corresponding ingredients and products.
This commit is contained in:
Kartik K. Agaram 2015-11-10 19:19:53 -08:00
parent c4e7c10d15
commit c1585c88fa
7 changed files with 96 additions and 52 deletions

View File

@ -67,7 +67,7 @@ case REPLY: {
if (ingredient_index >= SIZE(caller_instruction.ingredients))
raise_error << maybe(current_recipe_name()) << "'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end();
if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).value != caller_instruction.ingredients.at(ingredient_index).value)
raise_error << maybe(current_recipe_name()) << "'same-as-ingredient' product from call to " << callee << " must be " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
raise_error << maybe(current_recipe_name()) << "'" << caller_instruction.to_string() << "' should write to " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
}
}
// End Reply
@ -117,7 +117,7 @@ recipe test1 [
10:number <- next-ingredient
reply 10:number/same-as-ingredient:0
]
+error: main: 'same-as-ingredient' product from call to test1 must be 1:number rather than 2:number
+error: main: '2:number <- test1 1:number' should write to 1:number rather than 2:number
:(scenario reply_same_as_ingredient_dummy)
# % Hide_errors = true;

View File

@ -134,10 +134,10 @@ recipe add2 x:number, y:number -> z:number [
+error: add2: replied with the wrong type at 'reply z'
:(after "Transform.push_back(check_types_by_name)")
Transform.push_back(check_header_products); // idempotent
Transform.push_back(check_reply_instructions_against_header); // idempotent
:(code)
void check_header_products(const recipe_ordinal r) {
void check_reply_instructions_against_header(const recipe_ordinal r) {
const recipe& rr = get(Recipe, r);
if (rr.products.empty()) return;
trace(9991, "transform") << "--- checking reply instructions against header for " << rr.name << end();
@ -154,6 +154,33 @@ void check_header_products(const recipe_ordinal r) {
}
}
:(scenario recipe_headers_check_for_duplicate_names)
% Hide_errors = true;
recipe add2 x:number, x:number -> z:number [
local-scope
load-ingredients
reply z
]
+error: add2: x can't repeat in the ingredients
:(before "End recipe Fields")
map<string, int> ingredient_index;
:(after "Transform.push_back(insert_fragments)")
Transform.push_back(check_and_update_header_reagents); // idempotent
:(code)
void check_and_update_header_reagents(const recipe_ordinal r) {
recipe& rr = get(Recipe, r);
if (rr.products.empty()) return;
trace(9991, "transform") << "--- checking reply instructions against header for " << rr.name << end();
for (long long int i = 0; i < SIZE(rr.ingredients); ++i) {
if (contains_key(rr.ingredient_index, rr.ingredients.at(i).name))
raise_error << maybe(rr.name) << rr.ingredients.at(i).name << " can't repeat in the ingredients\n" << end();
put(rr.ingredient_index, rr.ingredients.at(i).name, i);
}
}
//: Deduce types from the header if possible.
:(scenarios run)
@ -169,7 +196,7 @@ recipe add2 x:number, y:number -> z:number [
]
+mem: storing 8 in location 1
:(before "Transform.push_back(check_header_products)")
:(before "Transform.push_back(check_reply_instructions_against_header)")
Transform.push_back(deduce_types_from_header); // idempotent
:(code)
@ -236,18 +263,40 @@ recipe add2 x:number, y:number -> z:number [
]
+mem: storing 8 in location 1
:(after "Transform.push_back(insert_fragments)")
Transform.push_back(fill_in_reply_ingredients);
:(after "Transform.push_back(check_and_update_header_reagents)")
Transform.push_back(fill_in_reply_ingredients); // idempotent
:(code)
void fill_in_reply_ingredients(recipe_ordinal r) {
if (!get(Recipe, r).has_header) return;
trace(9991, "transform") << "--- fill in reply ingredients from header for recipe " << get(Recipe, r).name << end();
for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
instruction& inst = get(Recipe, r).steps.at(i);
if (inst.name == "reply" && inst.ingredients.empty()) {
for (long long int i = 0; i < SIZE(get(Recipe, r).products); ++i)
inst.ingredients.push_back(get(Recipe, r).products.at(i));
recipe& rr = get(Recipe, r);
if (!rr.has_header) return;
trace(9991, "transform") << "--- fill in reply ingredients from header for recipe " << rr.name << end();
for (long long int i = 0; i < SIZE(rr.steps); ++i) {
instruction& inst = rr.steps.at(i);
if (inst.name == "reply" && inst.ingredients.empty())
add_header_products(inst, rr);
}
// fall through reply
if (rr.steps.at(SIZE(rr.steps)-1).name != "reply") {
instruction inst;
inst.name = "reply";
add_header_products(inst, rr);
rr.steps.push_back(inst);
}
}
void add_header_products(instruction& inst, const recipe& rr) {
assert(inst.name == "reply");
// collect any products with the same names as ingredients
for (long long int i = 0; i < SIZE(rr.products); ++i) {
// if the ingredient is missing, add it from the header
if (SIZE(inst.ingredients) == i)
inst.ingredients.push_back(rr.products.at(i));
// if it's missing /same_as_ingredient, try to fill it in
if (contains_key(rr.ingredient_index, rr.products.at(i).name) && !has_property(inst.ingredients.at(i), "same_as_ingredient")) {
ostringstream same_as_ingredient;
same_as_ingredient << get(rr.ingredient_index, rr.products.at(i).name);
inst.ingredients.at(i).properties.push_back(pair<string, string_tree*>("same-as-ingredient", new string_tree(same_as_ingredient.str())));
}
}
}
@ -278,25 +327,6 @@ recipe add2 x:number, y:number -> z:number [
+transform: instruction: reply z:number
+mem: storing 8 in location 1
:(after "Transform.push_back(insert_fragments)")
Transform.push_back(deduce_fallthrough_reply);
:(code)
void deduce_fallthrough_reply(const recipe_ordinal r) {
recipe& rr = get(Recipe, r);
if (rr.products.empty()) return;
if (rr.steps.empty()) return;
if (rr.steps.at(SIZE(rr.steps)-1).name != "reply") {
instruction inst;
inst.operation = REPLY;
inst.name = "reply";
for (long long int i = 0; i < SIZE(rr.products); ++i) {
inst.ingredients.push_back(rr.products.at(i));
}
rr.steps.push_back(inst);
}
}
:(scenario reply_on_fallthrough_already_exists)
recipe main [
1:number/raw <- add2 3, 5
@ -310,3 +340,16 @@ recipe add2 x:number, y:number -> z:number [
+transform: instruction: reply z
-transform: instruction: reply z:number
+mem: storing 8 in location 1
:(scenario recipe_headers_perform_same_ingredient_check)
% Hide_errors = true;
recipe main [
1:number <- copy 34
2:number <- copy 34
3:number <- add2 1:number, 2:number
]
recipe add2 x:number, y:number -> x:number [
local-scope
load-ingredients
]
+error: main: '3:number <- add2 1:number, 2:number' should write to 1:number rather than 3:number

View File

@ -259,7 +259,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
]
# helper for tests
recipe editor-render screen:address:screen, editor:address:editor-data [
recipe editor-render screen:address:screen, editor:address:editor-data -> screen:address:screen [
local-scope
load-ingredients
left:number <- get *editor, left:offset

View File

@ -391,6 +391,7 @@ scenario run-updates-results [
1:address:array:character <- new [
recipe foo [
z:number <- add 2, 2
reply z
]]
# sandbox editor contains an instruction without storing outputs
2:address:array:character <- new [foo]
@ -405,9 +406,9 @@ z:number <- add 2, 2
. ┊ .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
.z:number <- add 2, 2 ┊ x.
.] ┊foo .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .
. ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
.reply z ┊foo .
.] ┊4 .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
. ┊ .
]
# make a change (incrementing one of the args to 'add'), then rerun
@ -426,9 +427,9 @@ z:number <- add 2, 2
. ┊ .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
.z:number <- add 2, 3 ┊ x.
.] ┊foo .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5 .
. ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
.reply z ┊foo .
.] ┊5 .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
. ┊ .
]
]

View File

@ -6,7 +6,7 @@ scenario clicking-on-a-sandbox-moves-it-to-editor [
# basic recipe
1:address:array:character <- new [
recipe foo [
add 2, 2
reply 4
]]
# run it
2:address:array:character <- new [foo]
@ -19,7 +19,7 @@ recipe foo [
. run (F4) .
. ┊ .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.
. add 2, 2 ┊ x.
. reply 4 ┊ x.
.] ┊foo .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .
. ┊━━━━━━━━━━━━━━━━━━━.
@ -37,7 +37,7 @@ recipe foo [
. run (F4) .
. ┊foo .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.
. add 2, 2 ┊ .
. reply 4 ┊ .
.] ┊ .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .
. ┊ .
@ -54,7 +54,7 @@ recipe foo [
. run (F4) .
. ┊0foo .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.
. add 2, 2 ┊ .
. reply 4 ┊ .
.] ┊ .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .
. ┊ .

View File

@ -6,7 +6,7 @@ scenario sandbox-click-on-result-toggles-color-to-green [
# basic recipe
1:address:array:character <- new [
recipe foo [
add 2, 2
reply 4
]]
# run it
2:address:array:character <- new [foo]
@ -19,7 +19,7 @@ recipe foo [
. run (F4) .
. ┊ .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.
. add 2, 2 ┊ x.
. reply 4 ┊ x.
.] ┊foo .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .
. ┊━━━━━━━━━━━━━━━━━━━.
@ -51,13 +51,13 @@ recipe foo [
. run (F4) .
.␣ ┊ .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.
. add 2, 2 ┊ x.
. reply 4 ┊ x.
.] ┊foo .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .
. ┊━━━━━━━━━━━━━━━━━━━.
. ┊ .
]
# now change the second arg of the 'add'
# now change the result
# then rerun
assume-console [
left-click 3, 11 # cursor to end of line
@ -75,7 +75,7 @@ recipe foo [
. .
. .
. .
. 5 .
. 3 .
. .
. .
]

View File

@ -80,7 +80,7 @@ scenario sandbox-shows-app-trace-and-result [
1:address:array:character <- new [
recipe foo [
stash [abc]
add 2, 2
reply 4
]]
# run it
2:address:array:character <- new [foo]
@ -94,7 +94,7 @@ recipe foo [
. ┊ .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.
. stash [abc] ┊ x.
. add 2, 2 ┊foo .
. reply 4 ┊foo .
.] ┊4 .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.
. ┊ .
@ -112,7 +112,7 @@ recipe foo [
. ┊ .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.
. stash [abc] ┊ x.
. add 2, 2 ┊foo .
. reply 4 ┊foo .
.] ┊abc .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .
. ┊━━━━━━━━━━━━━━━━━━━.