1
2
3
4
5 :(scenario transform_names)
6 def main [
7 x:num <- copy 0
8 ]
9 +name: assign x 1
10 +mem: storing 0 in location 1
11
12 :(scenarios transform)
13 :(scenario transform_names_fails_on_use_before_define)
14 % Hide_errors = true;
15 def main [
16 x:num <- copy y:num
17 ]
18 +error: main: tried to read ingredient 'y' in 'x:num <- copy y:num' but it hasn't been written to yet
19
20
21 :(after "Transform.push_back(compute_container_sizes)")
22 Transform.push_back(transform_names);
23
24 :(before "End Globals")
25 map<recipe_ordinal, map<string, int> > Name;
26
27
28
29 :(before "End Globals")
30 map<recipe_ordinal, map<string, int> > Name_snapshot;
31 :(before "End save_snapshots")
32 Name_snapshot = Name;
33 :(before "End restore_snapshots")
34 Name = Name_snapshot;
35
36 :(code)
37 void transform_names(const recipe_ordinal r) {
38 recipe& caller = get(Recipe, r);
39 trace(9991, "transform") << "--- transform names for recipe " << caller.name << end();
40 bool names_used = false;
41 bool numeric_locations_used = false;
42 map<string, int>& names = Name[r];
43
44 int& curr_idx = names[""];
45 ++curr_idx;
46 for (int i = 0; i < SIZE(caller.steps); ++i) {
47 ¦ instruction& inst = caller.steps.at(i);
48 ¦
49 ¦
50 ¦ for (int in = 0; in < SIZE(inst.ingredients); ++in) {
51 ¦ ¦ reagent& ingredient = inst.ingredients.at(in);
52 ¦ ¦
53 ¦ ¦ if (is_disqualified(ingredient, inst, caller.name)) continue;
54 ¦ ¦ if (is_numeric_location(ingredient)) numeric_locations_used = true;
55 ¦ ¦ if (is_named_location(ingredient)) names_used = true;
56 ¦ ¦ if (is_integer(ingredient.name)) continue;
57 ¦ ¦ if (!already_transformed(ingredient, names)) {
58 ¦ ¦ ¦ raise << maybe(caller.name) << "tried to read ingredient '" << ingredient.name << "' in '" << inst.original_string << "' but it hasn't been written to yet\n" << end();
59 ¦ ¦ ¦
60 ¦ ¦ ¦ return;
61 ¦ ¦ }
62 ¦ ¦ int v = lookup_name(ingredient, r);
63 ¦ ¦ if (v >= 0) {
64 ¦ ¦ ¦ ingredient.set_value(v);
65 ¦ ¦ ¦
66 ¦ ¦ }
67 ¦ ¦ else {
68 ¦ ¦ ¦ raise << maybe(caller.name) << "can't find a place to store '" << ingredient.name << "'\n" << end();
69 ¦ ¦ ¦ return;
70 ¦ ¦ }
71 ¦ }
72 ¦ for (int out = 0; out < SIZE(inst.products); ++out) {
73 ¦ ¦ reagent& product = inst.products.at(out);
74 ¦ ¦
75 ¦ ¦ if (is_disqualified(product, inst, caller.name)) continue;
76 ¦ ¦ if (is_numeric_location(product)) numeric_locations_used = true;
77 ¦ ¦ if (is_named_location(product)) names_used = true;
78 ¦ ¦ if (is_integer(product.name)) continue;
79 ¦ ¦ if (names.find(product.name) == names.end()) {
80 ¦ ¦ ¦ trace(9993, "name") << "assign " << product.name << " " << curr_idx << end();
81 ¦ ¦ ¦ names[product.name] = curr_idx;
82 ¦ ¦ ¦ curr_idx += size_of(product);
83 ¦ ¦ }
84 ¦ ¦ int v = lookup_name(product, r);
85 ¦ ¦ if (v >= 0) {
86 ¦ ¦ ¦ product.set_value(v);
87 ¦ ¦ ¦
88 ¦ ¦ }
89 ¦ ¦ else {
90 ¦ ¦ ¦ raise << maybe(caller.name) << "can't find a place to store '" << product.name << "'\n" << end();
91 ¦ ¦ ¦ return;
92 ¦ ¦ }
93 ¦ }
94 }
95 if (names_used && numeric_locations_used)
96 ¦ raise << maybe(caller.name) << "mixing variable names and numeric addresses\n" << end();
97 }
98
99 bool is_disqualified( reagent& x, const instruction& inst, const string& recipe_name) {
100 if (!x.type) {
101 ¦ raise << maybe(recipe_name) << "missing type for '" << x.original_string << "' in '" << inst.original_string << "'\n" << end();
102 ¦
103 ¦ return true;
104 }
105 if (is_raw(x)) return true;
106 if (is_literal(x)) return true;
107
108 if (x.initialized) return true;
109 return false;
110 }
111
112 bool already_transformed(const reagent& r, const map<string, int>& names) {
113 return contains_key(names, r.name);
114 }
115
116 int lookup_name(const reagent& r, const recipe_ordinal default_recipe) {
117 return Name[default_recipe][r.name];
118 }
119
120 type_ordinal skip_addresses(type_tree* type) {
121 while (type && is_compound_type_starting_with(type, "address"))
122 ¦ type = type->right;
123 if (!type) return -1;
124 if (type->atom) return type->value;
125 const type_tree* base_type = type;
126
127 if (base_type->atom)
128 ¦ return base_type->value;
129 assert(base_type->left->atom);
130 return base_type->left->value;
131 }
132
133 int find_element_name(const type_ordinal t, const string& name, const string& recipe_name) {
134 const type_info& container = get(Type, t);
135 for (int i = 0; i < SIZE(container.elements); ++i)
136 ¦ if (container.elements.at(i).name == name) return i;
137 raise << maybe(recipe_name) << "unknown element '" << name << "' in container '" << get(Type, t).name << "'\n" << end();
138 return -1;
139 }
140
141 bool is_numeric_location(const reagent& x) {
142 if (is_literal(x)) return false;
143 if (is_raw(x)) return false;
144 if (x.name == "0") return false;
145 return is_integer(x.name);
146 }
147
148 bool is_named_location(const reagent& x) {
149 if (is_literal(x)) return false;
150 if (is_raw(x)) return false;
151 if (is_special_name(x.name)) return false;
152 return !is_integer(x.name);
153 }
154
155
156 bool is_special_name(const string& s) {
157 if (s == "_") return true;
158 if (s == "0") return true;
159
160 return false;
161 }
162
163 :(scenario transform_names_supports_containers)
164 def main [
165 x:point <- merge 34, 35
166 y:num <- copy 3
167 ]
168 +name: assign x 1
169
170 +name: assign y 3
171
172 :(scenario transform_names_supports_static_arrays)
173 def main [
174 x:@:num:3 <- create-array
175 y:num <- copy 3
176 ]
177 +name: assign x 1
178
179 +name: assign y 5
180
181 :(scenario transform_names_passes_dummy)
182
183 def main [
184 _, x:num <- copy 0, 1
185 ]
186 +name: assign x 1
187 -name: assign _ 1
188
189
190 :(scenarios run)
191 :(scenario transform_names_passes_raw)
192 % Hide_errors = true;
193 def main [
194 x:num/raw <- copy 0
195 ]
196 -name: assign x 1
197 +error: can't write to location 0 in 'x:num/raw <- copy 0'
198
199 :(scenarios transform)
200 :(scenario transform_names_fails_when_mixing_names_and_numeric_locations)
201 % Hide_errors = true;
202 def main [
203 x:num <- copy 1:num
204 ]
205 +error: main: mixing variable names and numeric addresses
206
207 :(scenario transform_names_fails_when_mixing_names_and_numeric_locations_2)
208 % Hide_errors = true;
209 def main [
210 x:num <- copy 1
211 1:num <- copy x:num
212 ]
213 +error: main: mixing variable names and numeric addresses
214
215 :(scenario transform_names_does_not_fail_when_mixing_names_and_raw_locations)
216 def main [
217 x:num <- copy 1:num/raw
218 ]
219 -error: main: mixing variable names and numeric addresses
220 $error: 0
221
222 :(scenario transform_names_does_not_fail_when_mixing_names_and_literals)
223 def main [
224 x:num <- copy 1
225 ]
226 -error: main: mixing variable names and numeric addresses
227 $error: 0
228
229
230
231
232 :(before "End update GET offset_value in Check")
233 else {
234 if (!offset.initialized) {
235 ¦ raise << maybe(get(Recipe, r).name) << "uninitialized offset '" << offset.name << "' in '" << inst.original_string << "'\n" << end();
236 ¦ break;
237 }
238 offset_value = offset.value;
239 }
240
241 :(scenario transform_names_transforms_container_elements)
242 def main [
243 p:&:point <- copy 0
244 a:num <- get *p:&:point, y:offset
245 b:num <- get *p:&:point, x:offset
246 ]
247 +name: element y of type point is at offset 1
248 +name: element x of type point is at offset 0
249
250 :(before "End transform_names(inst) Special-cases")
251
252 if (inst.name == "get" || inst.name == "get-location" || inst.name == "put") {
253
254
255
256 if (SIZE(inst.ingredients) < 2)
257 ¦ break;
258 if (!is_literal(inst.ingredients.at(1)))
259 ¦ break;
260 if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
261 ¦
262 ¦ type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type);
263 ¦ if (contains_key(Type, base_type)) {
264 ¦ ¦ inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name));
265 ¦ ¦ trace(9993, "name") << "element " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " is at offset " << no_scientific(inst.ingredients.at(1).value) << end();
266 ¦ }
267 }
268 }
269
270 :(scenario missing_type_in_get)
271 % Hide_errors = true;
272 def main [
273 get a, x:offset
274 ]
275 +error: main: missing type for 'a' in 'get a, x:offset'
276
277
278 :(scenarios transform)
279 :(scenario transform_names_handles_containers)
280 def main [
281 a:point <- copy 0/unsafe
282 b:num <- copy 0/unsafe
283 ]
284 +name: assign a 1
285 +name: assign b 3
286
287
288
289 :(scenarios run)
290 :(scenario transform_names_handles_exclusive_containers)
291 def main [
292 12:num <- copy 1
293 13:num <- copy 35
294 14:num <- copy 36
295 20:point, 22:bool <- maybe-convert 12:number-or-point/unsafe, p:variant
296 ]
297 +name: variant p of type number-or-point has tag 1
298 +mem: storing 1 in location 22
299 +mem: storing 35 in location 20
300 +mem: storing 36 in location 21
301
302 :(before "End transform_names(inst) Special-cases")
303
304 if (inst.name == "maybe-convert") {
305 if (SIZE(inst.ingredients) != 2) {
306 ¦ raise << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << inst.original_string << "'\n" << end();
307 ¦ break;
308 }
309 assert(is_literal(inst.ingredients.at(1)));
310 if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
311 ¦
312 ¦ type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type);
313 ¦ if (contains_key(Type, base_type)) {
314 ¦ ¦ inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name));
315 ¦ ¦ trace(9993, "name") << "variant " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " has tag " << no_scientific(inst.ingredients.at(1).value) << end();
316 ¦ }
317 }
318 }
319
320 :(scenario missing_type_in_maybe_convert)
321 % Hide_errors = true;
322 def main [
323 maybe-convert a, x:variant
324 ]
325 +error: main: missing type for 'a' in 'maybe-convert a, x:variant'