diff options
Diffstat (limited to '030container.cc')
-rw-r--r-- | 030container.cc | 72 |
1 files changed, 52 insertions, 20 deletions
diff --git a/030container.cc b/030container.cc index 90f9d713..38682e96 100644 --- a/030container.cc +++ b/030container.cc @@ -379,11 +379,38 @@ container bar [ +parse: element: {x: "number"} +parse: element: {y: "number"} +//: if a container is defined again, the new fields add to the original definition +:(scenarios run) +:(scenario container_extend) +container foo [ + x:number +] +# add to previous definition +container foo [ + y:number +] +def main [ + 1:number <- copy 34 + 2:number <- copy 35 + 3:number <- get 1:foo, 0:offset + 4:number <- get 1:foo, 1:offset +] ++mem: storing 34 in location 3 ++mem: storing 35 in location 4 + :(before "End Command Handlers") else if (command == "container") { insert_container(command, CONTAINER, in); } +//: Even though we allow containers to be extended, we don't allow this after +//: a call to transform_all. But we do want to detect this situation and raise +//: an error. This field will help us raise such errors. +:(before "End type_info Fields") +int Num_calls_to_transform_all_at_first_definition; +:(before "End type_info Constructor") +Num_calls_to_transform_all_at_first_definition = -1; + :(code) void insert_container(const string& command, kind_of_type kind, istream& in) { skip_whitespace_but_not_newline(in); @@ -397,6 +424,15 @@ void insert_container(const string& command, kind_of_type kind, istream& in) { trace(9999, "parse") << "type number: " << get(Type_ordinal, name) << end(); skip_bracket(in, "'container' must begin with '['"); type_info& info = get_or_insert(Type, get(Type_ordinal, name)); + if (info.Num_calls_to_transform_all_at_first_definition == -1) { + // initial definition of this container + info.Num_calls_to_transform_all_at_first_definition = Num_calls_to_transform_all; + } + else if (info.Num_calls_to_transform_all_at_first_definition != Num_calls_to_transform_all) { + // extension after transform_all + raise << "there was a call to transform_all() between the definition of container " << name << " and a subsequent extension. This is not supported, since any recipes that used " << name << " values have already been transformed and 'frozen'.\n" << end(); + return; + } info.name = name; info.kind = kind; while (has_data(in)) { @@ -435,26 +471,6 @@ void skip_bracket(istream& in, string message) { raise << message << '\n' << end(); } -:(scenarios run) -:(scenario container_extend) -container foo [ - x:number -] - -# add to previous definition -container foo [ - y:number -] - -def main [ - 1:number <- copy 34 - 2:number <- copy 35 - 3:number <- get 1:foo, 0:offset - 4:number <- get 1:foo, 1:offset -] -+mem: storing 34 in location 3 -+mem: storing 35 in location 4 - //: ensure scenarios are consistent by always starting them at the same type //: number. :(before "End Setup") //: for tests @@ -462,6 +478,22 @@ Next_type_ordinal = 1000; :(before "End Test Run Initialization") assert(Next_type_ordinal < 1000); +:(code) +void test_error_on_transform_all_between_container_definition_and_extension() { + // define a container + run("container foo [\n" + " a:number\n" + "]\n"); + // try to extend the container after transform + transform_all(); + CHECK_TRACE_DOESNT_CONTAIN_ERROR(); + Hide_errors = true; + run("container foo [\n" + " b:number\n" + "]\n"); + CHECK_TRACE_CONTAINS_ERROR(); +} + //:: Allow container definitions anywhere in the codebase, but complain if you //:: can't find a definition at the end. |