//: Introduce a new transform to perform various checks in instructions before
//: we start running them. It'll be extensible, so that we can add checks for
//: new recipes as we extend 'run' to support them.
//:
//: Doing checking in a separate part complicates things, because the values
//: of variables in memory and the processor (current_recipe_name,
//: current_instruction) aren't available at checking time. If I had a more
//: sophisticated layer system I'd introduce the simpler version first and
//: transform it in a separate layer or set of layers.
:(before "End Checks")
Transform.push_back(check_instruction); // idempotent
:(code)
void check_instruction(const recipe_ordinal r) {
trace(101, "transform") << "--- perform checks for recipe " << get(Recipe, r).name << end();
map<string, vector<type_ordinal> > metadata;
for (int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
instruction& inst = get(Recipe, r).steps.at(i);
if (inst.is_label) continue;
switch (inst.operation) {
// Primitive Recipe Checks
case COPY: {
if (SIZE(inst.products) > SIZE(inst.ingredients)) {
raise << maybe(get(Recipe, r).name) << "too many products in '" << to_original_string(inst) << "'\n" << end();
break;
}
for (int i = 0; i < SIZE(inst.products); ++i) {
if (!types_coercible(inst.products.at(i), inst.ingredients.at(i))) {
raise << maybe(get(Recipe, r).name) << "can't copy '" << inst.ingredients.