Commit | Line | Data |
---|---|---|
970ed795 | 1 | /////////////////////////////////////////////////////////////////////////////// |
3abe9331 | 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
970ed795 EL |
3 | // All rights reserved. This program and the accompanying materials |
4 | // are made available under the terms of the Eclipse Public License v1.0 | |
5 | // which accompanies this distribution, and is available at | |
6 | // http://www.eclipse.org/legal/epl-v10.html | |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | #include "TypeCompat.hh" | |
9 | ||
10 | #include "AST.hh" | |
11 | #include "Type.hh" | |
12 | #include "CompField.hh" | |
13 | #include "ttcn3/ArrayDimensions.hh" | |
14 | #include "ttcn3/TtcnTemplate.hh" | |
15 | #include "main.hh" | |
16 | ||
17 | namespace Common { | |
18 | ||
19 | TypeCompatInfo::TypeCompatInfo(Module *p_my_module, Type *p_type1, | |
20 | Type *p_type2, bool p_add_ref_str, | |
21 | bool p_strict, bool p_is_temp) : | |
22 | m_my_module(p_my_module), m_type1(p_type1), m_type2(p_type2), | |
23 | m_strict(p_strict), m_is_temp(p_is_temp), m_needs_conversion(false), | |
24 | m_erroneous(false), str1_elem(false), str2_elem(false) | |
25 | { | |
26 | if (p_type1 && p_add_ref_str) m_ref_str1 = p_type1->get_typename(); | |
27 | if (p_type2 && p_add_ref_str) m_ref_str2 = p_type2->get_typename(); | |
28 | } | |
29 | ||
30 | void TypeCompatInfo::set_is_erroneous(Type *p_type1, Type *p_type2, | |
31 | const string& p_error_str) | |
32 | { | |
33 | m_erroneous = true; | |
34 | m_type1 = p_type1; | |
35 | m_type2 = p_type2; | |
36 | m_error_str = p_error_str; | |
37 | } | |
38 | ||
39 | string TypeCompatInfo::get_error_str_str() const | |
40 | { | |
41 | // The resulting string should look like: "`f1.f2.f3...fn' [of type `tn'] | |
42 | // and `g1.g2.g3...gm' [of type `tm']". In run-time a simple error will | |
43 | // occure with a similarly simple error message. | |
44 | string ret_val = "Type mismatch: `" + m_ref_str1; | |
45 | if (m_ref_str1 != m_type1->get_typename()) | |
46 | ret_val += ("' of type `" + m_type1->get_typename()); | |
47 | ret_val += ("' and `" + m_ref_str2); | |
48 | if (m_ref_str2 != m_type2->get_typename()) | |
49 | ret_val += ("' of type `" + m_type2->get_typename()); | |
50 | ret_val += "' are not compatible"; | |
51 | if (m_error_str.size() > 0) ret_val += (": " + m_error_str); | |
52 | return ret_val; | |
53 | } | |
54 | ||
55 | void TypeCompatInfo::add_type_conversion(Type *p_from_type, Type *p_to_type) | |
56 | { | |
57 | if (!m_my_module) FATAL_ERROR("TypeCompatInfo::add_type_conversion()"); | |
58 | if (p_from_type == p_to_type) return; | |
59 | TypeConv *conv = new TypeConv(p_from_type, p_to_type, m_is_temp); | |
60 | m_my_module->add_type_conv(conv); | |
61 | } | |
62 | ||
63 | void TypeCompatInfo::append_ref_str(int p_ref_no, const string& p_ref_str) | |
64 | { | |
65 | string& ref_str = p_ref_no == 0 ? m_ref_str1 : m_ref_str2; | |
66 | ref_str += p_ref_str; | |
67 | } | |
68 | ||
69 | string TypeConv::get_conv_func(Type *p_from, Type *p_to, Module *p_mod) | |
70 | { | |
71 | const char *from_name = p_from->get_genname_own().c_str(); | |
72 | const char *to_name = p_to->get_genname_own().c_str(); | |
73 | Module *from_mod = p_from->get_my_scope()->get_scope_mod(); | |
74 | Module *to_mod = p_to->get_my_scope()->get_scope_mod(); | |
75 | string ret_val = "conv_" + (from_mod != p_mod | |
76 | ? (from_mod->get_modid().get_name() + "_") : string()) + from_name + "_" + | |
77 | (to_mod != p_mod ? (to_mod->get_modid().get_name() + "_") : string()) + | |
78 | to_name; | |
79 | return ret_val; | |
80 | } | |
81 | ||
82 | bool TypeConv::needs_conv_redir(TemplateInstance *p_ti, Reference *p_ref) | |
83 | { | |
84 | if (!use_runtime_2) FATAL_ERROR("TypeConv::needs_conv_redir()"); | |
85 | if (!p_ref) | |
86 | return false; | |
87 | Template *templ_body = p_ti->get_Template(); | |
88 | Template::templatetype_t templ_body_tt = templ_body->get_templatetype(); | |
89 | switch (templ_body_tt) { | |
90 | case Template::SPECIFIC_VALUE: | |
91 | if (templ_body->get_specific_value()->get_needs_conversion()) | |
92 | return true; | |
93 | break; | |
94 | default: | |
95 | // If the first parameter needs conversion, go ahead. It's most | |
96 | // probably a reference. | |
97 | if (templ_body->get_needs_conversion()) | |
98 | return true; | |
99 | break; | |
100 | } | |
101 | // Check if the value and the type specified for the template instance | |
102 | // match. If not, we'll need a conversion. | |
103 | if (p_ti->get_Type()) { | |
104 | Type *ti_type = p_ti->get_Type()->get_type_refd_last(); | |
105 | Type *val_type = p_ref->get_refd_assignment()->get_Type() | |
106 | ->get_field_type(p_ref->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE) | |
107 | ->get_type_refd_last(); | |
108 | if (ti_type->is_structured_type() && val_type->is_structured_type() | |
109 | && ti_type != val_type) | |
110 | return true; | |
111 | } | |
112 | return false; | |
113 | } | |
114 | ||
115 | void TypeConv::gen_conv_code_redir(expression_struct *p_expr, | |
116 | TemplateInstance *p_ti, Reference *p_ref) | |
117 | { | |
118 | if (!use_runtime_2) FATAL_ERROR("TypeConv::gen_conv_code_redir()"); | |
119 | Template *templ_body = p_ti->get_Template(); | |
120 | Template::templatetype_t templ_body_tt = templ_body->get_templatetype(); | |
121 | expression_struct expr_tmp; | |
122 | Code::init_expr(&expr_tmp); | |
123 | const string& tmp_id1 = templ_body->get_temporary_id(); | |
124 | const char *tmp_id_str1 = tmp_id1.c_str(); | |
125 | const string& tmp_id2 = templ_body->get_temporary_id(); | |
126 | const char *tmp_id_str2 = tmp_id2.c_str(); | |
127 | const string& tmp_id3 = templ_body->get_temporary_id(); | |
128 | const char *tmp_id_str3 = tmp_id3.c_str(); | |
129 | Type *my_gov = p_ref->get_refd_assignment()->get_Type() | |
130 | ->get_field_type(p_ref->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE) | |
131 | ->get_type_refd_last(); | |
132 | Type *orig_type = NULL; | |
133 | switch (templ_body_tt) { | |
134 | case Template::SPECIFIC_VALUE: { | |
135 | Value *val = templ_body->get_specific_value(); | |
136 | if (val->get_valuetype() == Value::V_REFD) | |
137 | orig_type = val->get_reference()->get_refd_assignment()->get_Type() | |
138 | ->get_field_type(val->get_reference()->get_subrefs(), | |
139 | Type::EXPECTED_DYNAMIC_VALUE)->get_type_refd_last(); | |
140 | break; } | |
141 | case Template::TEMPLATE_REFD: { | |
142 | Reference *ref = templ_body->get_reference(); | |
143 | if (!ref) FATAL_ERROR("TypeConv::gen_conv_code_redir()"); | |
144 | orig_type = ref->get_refd_assignment()->get_Type()->get_field_type(ref | |
145 | ->get_subrefs(), Type::EXPECTED_TEMPLATE)->get_type_refd_last(); | |
146 | break; } | |
147 | default: | |
148 | break; | |
149 | } | |
150 | bool needs_back_conv = orig_type != my_gov; | |
151 | // Try the template instance's explicit type specification. This will be | |
152 | // the winner if we already have the type. | |
153 | if (p_ti->get_Type()) { | |
154 | if (p_ti->get_Type()->get_type_refd_last() != my_gov) { | |
155 | orig_type = p_ti->get_Type()->get_type_refd_last(); | |
156 | needs_back_conv = false; | |
157 | } | |
158 | } | |
159 | if (!orig_type || !my_gov) FATAL_ERROR("TypeConv::gen_conv_code_redir()"); | |
160 | p_expr->preamble = mputprintf(p_expr->preamble, | |
161 | "%s %s;\n" // For back-conversion. | |
162 | "%s %s;\n" // To store the result of the operation, the "&()" part. | |
163 | "%s %s;\n", | |
164 | orig_type->get_genname_template(templ_body->get_my_scope()).c_str(), | |
165 | tmp_id_str1, orig_type->get_genname_value(templ_body->get_my_scope()) | |
166 | .c_str(), tmp_id_str2, my_gov->get_genname_template(templ_body | |
167 | ->get_my_scope()).c_str(), tmp_id_str3); | |
168 | expr_tmp.expr = mputprintf(expr_tmp.expr, "%s = ", | |
169 | !needs_back_conv ? tmp_id_str1 : tmp_id_str3); | |
170 | p_ti->generate_code(&expr_tmp); | |
171 | p_expr->preamble = Code::merge_free_expr(p_expr->preamble, &expr_tmp); | |
172 | if (needs_back_conv) { | |
173 | TypeConv *back_conv = new TypeConv(my_gov, orig_type, true); | |
174 | templ_body->get_my_scope()->get_scope_mod()->add_type_conv(back_conv); | |
175 | p_expr->preamble = mputprintf(p_expr->preamble, | |
176 | "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' and " | |
177 | "`%s' are not compatible at run-time\");\n", | |
178 | TypeConv::get_conv_func(my_gov, orig_type, templ_body->get_my_scope() | |
179 | ->get_scope_mod()).c_str(), tmp_id_str1, tmp_id_str3, my_gov | |
180 | ->get_typename().c_str(), orig_type->get_typename().c_str()); | |
181 | } | |
182 | // The back-converted template is the first argument. | |
183 | p_expr->expr = mputprintf(p_expr->expr, "%s, &(%s)", | |
184 | tmp_id_str1, tmp_id_str2); | |
185 | Code::init_expr(&expr_tmp); | |
186 | p_ref->generate_code(&expr_tmp); | |
187 | // Hand-merge 1. | |
188 | if (expr_tmp.preamble) | |
189 | p_expr->postamble = mputstr(p_expr->postamble, expr_tmp.preamble); | |
190 | // Finally, convert back to the original value. TODO: Simplify. Don't | |
191 | // let the conversion die due to an unsuccessful receive operation. | |
192 | p_expr->postamble = mputprintf(p_expr->postamble, | |
193 | "if (%s.is_bound() && !%s(%s, %s)) TTCN_error(\"Values or templates " | |
194 | "of types `%s' and `%s' are not compatible at run-time\");\n", | |
195 | tmp_id_str2, TypeConv::get_conv_func(orig_type, my_gov, templ_body | |
196 | ->get_my_scope()->get_scope_mod()).c_str(), expr_tmp.expr, tmp_id_str2, | |
197 | orig_type->get_typename().c_str(), my_gov->get_typename().c_str()); | |
198 | // Hand-merge 2. | |
199 | if (expr_tmp.postamble) | |
200 | p_expr->postamble = mputstr(p_expr->postamble, expr_tmp.postamble); | |
201 | Code::free_expr(&expr_tmp); | |
202 | } | |
203 | ||
204 | bool TypeConv::needs_conv_refd(GovernedSimple *p_val_or_temp) | |
205 | { | |
206 | if (!use_runtime_2) FATAL_ERROR("TypeConv::needs_conv_refd()"); | |
207 | Type *original_type = NULL; | |
208 | Type *current_type = NULL; | |
209 | switch (p_val_or_temp->get_st()) { | |
210 | case Setting::S_TEMPLATE: { | |
211 | Template *p_temp = static_cast<Template *>(p_val_or_temp); | |
212 | if (p_temp->get_templatetype() != Template::TEMPLATE_REFD) return false; | |
213 | current_type = p_temp->get_my_governor()->get_type_refd_last(); | |
214 | Common::Reference *ref = p_temp->get_reference(); | |
215 | if (!ref) FATAL_ERROR("TypeConv::needs_conv_refd()"); | |
216 | original_type = ref->get_refd_assignment()->get_Type() | |
217 | ->get_field_type(ref->get_subrefs(), Type::EXPECTED_TEMPLATE) | |
218 | ->get_type_refd_last(); | |
219 | break; } | |
220 | case Setting::S_V: { | |
221 | Value *p_val = static_cast<Value *>(p_val_or_temp); | |
222 | if (p_val->get_valuetype() != Value::V_REFD) return false; | |
223 | current_type = p_val->get_my_governor()->get_type_refd_last(); | |
224 | Common::Reference *ref = p_val->get_reference(); | |
225 | if (!ref) FATAL_ERROR("TypeConv::needs_conv_refd()"); | |
226 | original_type = ref->get_refd_assignment()->get_Type() | |
227 | ->get_field_type(ref->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE) | |
228 | ->get_type_refd_last(); | |
229 | break; } | |
230 | default: | |
231 | return false; | |
232 | } | |
233 | // We should have the scope at this point. Templates like "?" shouldn't | |
234 | // reach this point. | |
235 | return p_val_or_temp->get_my_scope()->get_scope_mod() | |
236 | ->needs_type_conv(original_type, current_type); | |
237 | } | |
238 | ||
239 | // Always call needs_conv_refd() before this. It is assumed that the value | |
240 | // is a reference and the conversion is necessary. | |
241 | char *TypeConv::gen_conv_code_refd(char *p_str, const char *p_name, | |
242 | GovernedSimple *p_val_or_temp) | |
243 | { | |
244 | if (!use_runtime_2) FATAL_ERROR("TypeConv::gen_conv_code_refd()"); | |
245 | Type *original_type = NULL; | |
246 | Type *current_type = NULL; | |
247 | string original_type_genname("<unknown>"); | |
248 | string current_type_genname("<unknown>"); | |
249 | Common::Scope *my_scope = NULL; | |
250 | switch (p_val_or_temp->get_st()) { | |
251 | case Setting::S_TEMPLATE: { | |
252 | Template *p_temp = static_cast<Template *>(p_val_or_temp); | |
253 | my_scope = p_temp->get_my_scope(); | |
254 | if (p_temp->get_templatetype() != Template::TEMPLATE_REFD) | |
255 | FATAL_ERROR("TypeConv::gen_conv_code_refd()"); | |
256 | Common::Reference *ref = p_temp->get_reference(); | |
257 | current_type = p_temp->get_my_governor()->get_type_refd_last(); | |
258 | original_type = ref->get_refd_assignment()->get_Type() | |
259 | ->get_field_type(ref->get_subrefs(), Type::EXPECTED_TEMPLATE) | |
260 | ->get_type_refd_last(); | |
261 | original_type_genname = original_type->get_genname_template(my_scope); | |
262 | current_type_genname = current_type->get_genname_template(my_scope); | |
263 | break; } | |
264 | case Setting::S_V: { | |
265 | Value *p_val = static_cast<Value *>(p_val_or_temp); | |
266 | my_scope = p_val->get_my_scope(); | |
267 | // We can't really handle other values and templates. | |
268 | if (p_val->get_valuetype() != Value::V_REFD) | |
269 | FATAL_ERROR("TypeConv::gen_conv_code_refd()"); | |
270 | Common::Reference *ref = p_val->get_reference(); | |
271 | current_type = p_val->get_my_governor()->get_type_refd_last(); | |
272 | original_type = ref->get_refd_assignment()->get_Type() | |
273 | ->get_field_type(ref->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE) | |
274 | ->get_type_refd_last(); | |
275 | original_type_genname = original_type->get_genname_value(my_scope); | |
276 | current_type_genname = current_type->get_genname_value(my_scope); | |
277 | break; } | |
278 | default: | |
279 | FATAL_ERROR("TypeConv::gen_conv_code_refd()"); | |
280 | } | |
281 | const string& tmp_id1 = p_val_or_temp->get_temporary_id(); | |
282 | const char *tmp_id_str1 = tmp_id1.c_str(); // For "p_val/p_temp". | |
283 | const string& tmp_id2 = p_val_or_temp->get_temporary_id(); | |
284 | const char *tmp_id_str2 = tmp_id2.c_str(); // For converted "p_val/p_temp". | |
285 | expression_struct expr; | |
286 | Code::init_expr(&expr); | |
287 | expr.expr = mputprintf(expr.expr, | |
288 | "%s %s;\n%s = ", original_type_genname.c_str(), tmp_id_str1, | |
289 | tmp_id_str1); | |
290 | // Always save the value into a separate temporary. Who knows? It can | |
291 | // avoid some problems with referencing complex expressions. The third | |
292 | // argument passed to the conversion function is unused unless the type | |
293 | // we're converting to is a T_CHOICE_{A,T}/T_ANYTYPE. Calling | |
294 | // generate_code_init() directly may cause infinite recursion. | |
295 | if (p_val_or_temp->get_st() == Setting::S_V) | |
296 | static_cast<Value *>(p_val_or_temp)->get_reference()->generate_code(&expr); | |
297 | else static_cast<Template *>(p_val_or_temp)->get_reference()->generate_code(&expr); | |
298 | expr.expr = mputprintf(expr.expr, | |
299 | ";\n%s %s;\n" | |
300 | "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' and " | |
301 | "`%s' are not compatible at run-time\")", // ";\n" will be added later. | |
302 | current_type_genname.c_str(), tmp_id_str2, get_conv_func(original_type, | |
303 | current_type, my_scope->get_scope_mod()).c_str(), tmp_id_str2, | |
304 | tmp_id_str1, original_type->get_typename().c_str(), | |
305 | current_type->get_typename().c_str()); | |
306 | // Merge by hand. Code::merge_free_expr() puts an additional ";\n". | |
307 | // "p_str" is just a local pointer here, it needs an mputprintf() at the | |
308 | // end. | |
309 | p_str = Code::merge_free_expr(p_str, &expr); | |
310 | return mputprintf(p_str, "%s = %s;\n", p_name, tmp_id_str2); | |
311 | } | |
312 | ||
313 | void TypeConv::gen_conv_func(char **p_prototypes, char **p_bodies, | |
314 | Module *p_mod) | |
315 | { | |
316 | string from_name = m_is_temp ? m_from->get_genname_template(p_mod) | |
317 | : m_from->get_genname_value(p_mod); | |
318 | string to_name = m_is_temp ? m_to->get_genname_template(p_mod) | |
319 | : m_to->get_genname_value(p_mod); | |
320 | *p_prototypes = mputprintf(*p_prototypes, | |
321 | "static boolean %s(%s& p_to_v, const %s& p_from_v);\n", | |
322 | get_conv_func(m_from, m_to, p_mod).c_str(), to_name.c_str(), | |
323 | from_name.c_str()); | |
324 | *p_bodies = mputprintf(*p_bodies, | |
325 | "static boolean %s(%s& p_to_v, const %s& p_from_v)\n{\n", | |
326 | get_conv_func(m_from, m_to, p_mod).c_str(), to_name.c_str(), | |
327 | from_name.c_str()); | |
328 | switch (m_to->get_typetype()) { | |
329 | case Type::T_SEQ_A: | |
330 | case Type::T_SEQ_T: | |
331 | switch (m_from->get_typetype()) { | |
332 | case Type::T_SEQ_A: | |
333 | case Type::T_SEQ_T: | |
334 | gen_conv_func_record_set(p_bodies, p_mod); | |
335 | break; | |
336 | case Type::T_SEQOF: | |
337 | gen_conv_func_record_set_record_of_set_of(p_bodies, p_mod); | |
338 | break; | |
339 | case Type::T_ARRAY: | |
340 | gen_conv_func_array_record(p_bodies, p_mod); | |
341 | break; | |
342 | default: | |
343 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
344 | return; | |
345 | } break; | |
346 | case Type::T_SEQOF: | |
347 | switch (m_from->get_typetype()) { | |
348 | case Type::T_SEQ_A: | |
349 | case Type::T_SEQ_T: | |
350 | case Type::T_SEQOF: | |
351 | gen_conv_func_record_set_record_of_set_of(p_bodies, p_mod); | |
352 | break; | |
353 | case Type::T_ARRAY: | |
354 | gen_conv_func_array_record_of(p_bodies, p_mod); | |
355 | break; | |
356 | default: | |
357 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
358 | return; | |
359 | } break; | |
360 | case Type::T_ARRAY: | |
361 | switch (m_from->get_typetype()) { | |
362 | case Type::T_SEQ_A: | |
363 | case Type::T_SEQ_T: | |
364 | gen_conv_func_array_record(p_bodies, p_mod); | |
365 | break; | |
366 | case Type::T_SEQOF: | |
367 | case Type::T_ARRAY: | |
368 | gen_conv_func_array_record_of(p_bodies, p_mod); | |
369 | break; | |
370 | default: | |
371 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
372 | return; | |
373 | } break; | |
374 | case Type::T_SET_A: | |
375 | case Type::T_SET_T: | |
376 | switch (m_from->get_typetype()) { | |
377 | case Type::T_SET_A: | |
378 | case Type::T_SET_T: | |
379 | gen_conv_func_record_set(p_bodies, p_mod); | |
380 | break; | |
381 | case Type::T_SETOF: | |
382 | gen_conv_func_record_set_record_of_set_of(p_bodies, p_mod); | |
383 | break; | |
384 | default: | |
385 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
386 | return; | |
387 | } break; | |
388 | case Type::T_SETOF: | |
389 | switch (m_from->get_typetype()) { | |
390 | case Type::T_SET_A: | |
391 | case Type::T_SET_T: | |
392 | case Type::T_SETOF: | |
393 | gen_conv_func_record_set_record_of_set_of(p_bodies, p_mod); | |
394 | break; | |
395 | default: | |
396 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
397 | return; | |
398 | } break; | |
399 | case Type::T_CHOICE_A: | |
400 | case Type::T_CHOICE_T: | |
401 | switch (m_from->get_typetype()) { | |
402 | case Type::T_CHOICE_A: | |
403 | case Type::T_CHOICE_T: | |
404 | gen_conv_func_choice_anytype(p_bodies, p_mod); | |
405 | break; | |
406 | default: | |
407 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
408 | return; | |
409 | } break; | |
410 | case Type::T_ANYTYPE: | |
411 | switch (m_from->get_typetype()) { | |
412 | case Type::T_ANYTYPE: | |
413 | gen_conv_func_choice_anytype(p_bodies, p_mod); | |
414 | break; | |
415 | default: | |
416 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
417 | return; | |
418 | } break; | |
419 | default: | |
420 | FATAL_ERROR("TypeConv::gen_conv_func()"); | |
421 | return; | |
422 | } | |
423 | *p_bodies = mputprintf(*p_bodies, "return TRUE;\n}\n\n"); | |
424 | } | |
425 | ||
426 | // Conversions between records-records and sets-sets. | |
427 | void TypeConv::gen_conv_func_record_set(char **p_bodies, Module *p_mod) | |
428 | { | |
429 | Type::typetype_t m_from_tt = m_from->get_typetype(); | |
430 | Type::typetype_t m_to_tt = m_to->get_typetype(); | |
431 | switch (m_from_tt) { | |
432 | case Type::T_SEQ_A: | |
433 | case Type::T_SEQ_T: | |
434 | if (m_to_tt != Type::T_SEQ_A && m_to_tt != Type::T_SEQ_T) | |
435 | FATAL_ERROR("TypeConv::gen_conv_func_record_set()"); | |
436 | break; | |
437 | case Type::T_SET_A: | |
438 | case Type::T_SET_T: | |
439 | if (m_to_tt != Type::T_SET_A && m_to_tt != Type::T_SET_T) | |
440 | FATAL_ERROR("TypeConv::gen_conv_func_record_set()"); | |
441 | break; | |
442 | default: | |
443 | FATAL_ERROR("TypeConv::gen_conv_func_record_set()"); | |
444 | return; | |
445 | } | |
446 | for (size_t i = 0; i < m_to->get_nof_comps(); i++) { | |
447 | CompField *cf_to = m_to->get_comp_byIndex(i); | |
448 | CompField *cf_from = m_from->get_comp_byIndex(i); | |
449 | const Identifier& cf_id_to = cf_to->get_name(); | |
450 | const Identifier& cf_id_from = cf_from->get_name(); | |
451 | Type *cf_type_to = cf_to->get_type()->get_type_refd_last(); | |
452 | Type *cf_type_from = cf_from->get_type()->get_type_refd_last(); | |
453 | string cf_type_to_name = m_is_temp ? cf_type_to | |
454 | ->get_genname_template(p_mod) : cf_type_to->get_genname_value(p_mod); | |
455 | if (!p_mod->needs_type_conv(cf_type_from, cf_type_to)) { | |
456 | *p_bodies = mputprintf(*p_bodies, | |
457 | "if (p_from_v.%s().is_bound()) p_to_v.%s() = p_from_v.%s();\n", | |
458 | cf_id_from.get_name().c_str(), cf_id_to.get_name().c_str(), | |
459 | cf_id_from.get_name().c_str()); | |
460 | } else { | |
461 | const string& tmp_id = p_mod->get_temporary_id(); | |
462 | const char *tmp_id_str = tmp_id.c_str(); | |
463 | *p_bodies = mputprintf(*p_bodies, | |
464 | "%s %s;\n" | |
465 | "if (!%s(%s, p_from_v.%s())) return FALSE;\n" | |
466 | "if (%s.is_bound()) p_to_v.%s() = %s;\n", | |
467 | cf_type_to_name.c_str(), tmp_id_str, get_conv_func(cf_type_from, | |
468 | cf_type_to, p_mod).c_str(), tmp_id_str, cf_id_from.get_name() | |
469 | .c_str(), tmp_id_str, cf_id_to.get_name().c_str(), tmp_id_str); | |
470 | } | |
471 | } | |
472 | } | |
473 | ||
474 | // Converting arrays to record types vice versa. | |
475 | void TypeConv::gen_conv_func_array_record(char **p_bodies, Module *p_mod) | |
476 | { | |
477 | Type::typetype_t m_from_tt = m_from->get_typetype(); | |
478 | Type::typetype_t m_to_tt = m_to->get_typetype(); | |
479 | switch (m_from_tt) { | |
480 | case Type::T_SEQ_A: | |
481 | case Type::T_SEQ_T: | |
482 | if (m_to_tt != Type::T_ARRAY) | |
483 | FATAL_ERROR("TypeConv::gen_conv_func_array_record()"); | |
484 | break; | |
485 | case Type::T_ARRAY: | |
486 | if (m_to_tt != Type::T_SEQ_A && m_to_tt != Type::T_SEQ_T) | |
487 | FATAL_ERROR("TypeConv::gen_conv_func_array_record()"); | |
488 | break; | |
489 | default: | |
490 | FATAL_ERROR("TypeConv::gen_conv_func_array_record()"); | |
491 | return; | |
492 | } | |
493 | // From array to a structure type. | |
494 | if (m_from_tt == Type::T_ARRAY) { | |
495 | Type *of_type_from = m_from->get_ofType()->get_type_refd_last(); | |
496 | Int of_type_from_offset = m_from->get_dimension()->get_offset(); | |
497 | for (size_t i = 0; i < m_to->get_nof_comps(); i++) { | |
498 | CompField *cf_to = m_to->get_comp_byIndex(i); | |
499 | const Identifier& cf_id_to = cf_to->get_name(); | |
500 | Type *cf_type_to = cf_to->get_type()->get_type_refd_last(); | |
501 | string cf_type_to_name = m_is_temp ? cf_type_to | |
502 | ->get_genname_template(p_mod) : cf_type_to | |
503 | ->get_genname_value(p_mod); | |
504 | if (!p_mod->needs_type_conv(of_type_from, cf_type_to)) { | |
505 | *p_bodies = mputprintf(*p_bodies, | |
506 | "if (p_from_v[%lu].is_bound()) p_to_v.%s() = p_from_v[%lu];\n", | |
507 | (long unsigned)(i + of_type_from_offset), | |
508 | cf_id_to.get_name().c_str(), | |
509 | (long unsigned)(i + of_type_from_offset)); | |
510 | } else { | |
511 | const string& tmp_id = p_mod->get_temporary_id(); | |
512 | const char *tmp_id_str = tmp_id.c_str(); | |
513 | *p_bodies = mputprintf(*p_bodies, | |
514 | "%s %s;\n" | |
515 | "if (!%s(%s, p_from_v[%lu])) return FALSE;\n" | |
516 | "if (%s.is_bound()) p_to_v.%s() = %s;\n", | |
517 | cf_type_to_name.c_str(), tmp_id_str, get_conv_func(of_type_from, | |
518 | cf_type_to, p_mod).c_str(), tmp_id_str, | |
519 | (long unsigned)(i + of_type_from_offset), | |
520 | tmp_id_str, cf_id_to.get_name().c_str(), tmp_id_str); | |
521 | } | |
522 | } | |
523 | // From a structure to an array. An example 6.3.2.2 shows that | |
524 | // OMIT_VALUES should be skipped at assignments. | |
525 | } else { | |
526 | Type *of_type_to = m_to->get_ofType()->get_type_refd_last(); | |
527 | string of_type_to_name = m_is_temp ? of_type_to | |
528 | ->get_genname_template(p_mod) : of_type_to->get_genname_value(p_mod); | |
529 | *p_bodies = mputprintf(*p_bodies, | |
530 | "unsigned int index = %lu;\n", | |
531 | (long unsigned)m_to->get_dimension()->get_offset()); | |
532 | for (size_t i = 0; i < m_from->get_nof_comps(); i++) { | |
533 | CompField *cf_from = m_from->get_comp_byIndex(i); | |
534 | const Identifier& cf_id_from = cf_from->get_name(); | |
535 | Type *cf_type_from = cf_from->get_type()->get_type_refd_last(); | |
536 | if (!p_mod->needs_type_conv(cf_type_from, of_type_to)) { | |
537 | *p_bodies = mputprintf(*p_bodies, | |
538 | "if (p_from_v.%s().is_bound()) {\n", | |
539 | cf_id_from.get_name().c_str()); | |
540 | if (cf_from->get_is_optional()) { | |
541 | *p_bodies = mputprintf(*p_bodies, | |
542 | "if (!(p_from_v.%s()%s)) p_to_v[index++] " | |
543 | "= p_from_v.%s();\n", | |
544 | cf_id_from.get_name().c_str(), (m_is_temp ? ".is_omit()" : | |
545 | " == OMIT_VALUE"), cf_id_from.get_name().c_str()); | |
546 | } else { | |
547 | *p_bodies = mputprintf(*p_bodies, | |
548 | "p_to_v[index++] = p_from_v.%s();\n", | |
549 | cf_id_from.get_name().c_str()); | |
550 | } | |
551 | // For unbound elements. | |
552 | *p_bodies = mputstr(*p_bodies, "} else index++;\n"); | |
553 | } else { | |
554 | const string& tmp_id = p_mod->get_temporary_id(); | |
555 | const char *tmp_id_str = tmp_id.c_str(); | |
556 | *p_bodies = mputprintf(*p_bodies, | |
557 | "%s %s;\n" | |
558 | "if (!%s(%s, p_from_v.%s())) return FALSE;\n" | |
559 | "if (%s.is_bound()) p_to_v[index++] = %s;\n", | |
560 | of_type_to_name.c_str(), tmp_id_str, get_conv_func(cf_type_from, | |
561 | of_type_to, p_mod).c_str(), tmp_id_str, cf_id_from.get_name() | |
562 | .c_str(), tmp_id_str, tmp_id_str); | |
563 | } | |
564 | } | |
565 | } | |
566 | } | |
567 | ||
568 | // Conversions between arrays and between record ofs and arrays. | |
569 | void TypeConv::gen_conv_func_array_record_of(char **p_bodies, Module *p_mod) | |
570 | { | |
571 | Type::typetype_t m_from_tt = m_from->get_typetype(); | |
572 | Type::typetype_t m_to_tt = m_to->get_typetype(); | |
573 | switch (m_from_tt) { | |
574 | case Type::T_SEQOF: | |
575 | if (m_to_tt == Type::T_SEQOF) | |
576 | FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()"); | |
577 | break; | |
578 | case Type::T_ARRAY: | |
579 | break; | |
580 | default: | |
581 | FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()"); | |
582 | return; | |
583 | } | |
584 | Type *of_type_from = m_from->get_ofType()->get_type_refd_last(); | |
585 | Type *of_type_to = m_to->get_ofType()->get_type_refd_last(); | |
586 | string of_type_to_name = m_is_temp ? of_type_to | |
587 | ->get_genname_template(p_mod) : of_type_to->get_genname_value(p_mod); | |
588 | Int of_type_from_offset = m_from_tt == Type::T_ARRAY ? m_from | |
589 | ->get_dimension()->get_offset() : 0; | |
590 | Int of_type_to_offset = m_to_tt == Type::T_ARRAY ? m_to->get_dimension() | |
591 | ->get_offset() : 0; | |
592 | // If we have two arrays the dimensions must match at this point. For | |
593 | // record of types we need to check the current size. | |
594 | if (m_from_tt == Type::T_SEQOF) | |
595 | *p_bodies = mputprintf(*p_bodies, | |
596 | "if (!p_from_v.is_bound() || p_from_v.size_of() != %lu) return FALSE;\n", | |
597 | (long unsigned)m_to->get_dimension()->get_size()); | |
598 | else if (m_to_tt == Type::T_SEQOF) | |
599 | *p_bodies = mputprintf(*p_bodies, "p_to_v.set_size(%lu);\n", | |
600 | (long unsigned)m_from->get_dimension()->get_size()); | |
601 | for (size_t i = 0; i < m_from->get_dimension()->get_size(); i++) { | |
602 | if (!p_mod->needs_type_conv(of_type_from, of_type_to)) { | |
603 | *p_bodies = mputprintf(*p_bodies, | |
604 | "if (p_from_v[%lu].is_bound()) p_to_v[%lu] = p_from_v[%lu];\n", | |
605 | (long unsigned)(i + of_type_from_offset), | |
606 | (long unsigned)(i + of_type_to_offset), | |
607 | (long unsigned)(i + of_type_from_offset)); | |
608 | } else { | |
609 | const string& tmp_id = p_mod->get_temporary_id(); | |
610 | const char *tmp_id_str = tmp_id.c_str(); | |
611 | *p_bodies = mputprintf(*p_bodies, | |
612 | "%s %s;\n" | |
613 | "if (!%s(%s, p_from_v[%lu])) return FALSE;\n" | |
614 | "if (%s.is_bound()) p_to_v[%lu] = %s;\n" | |
615 | "}\n", | |
616 | of_type_to_name.c_str(), tmp_id_str, get_conv_func(of_type_from, | |
617 | of_type_to, p_mod).c_str(), tmp_id_str, | |
618 | (long unsigned)(i + of_type_from_offset), tmp_id_str, | |
619 | (long unsigned)(i + of_type_from_offset), tmp_id_str); | |
620 | } | |
621 | } | |
622 | } | |
623 | ||
624 | // Conversions from records or sets to record ofs or set ofs. Vice versa. | |
625 | void TypeConv::gen_conv_func_record_set_record_of_set_of(char **p_bodies, Module *p_mod) | |
626 | { | |
627 | Type::typetype_t m_from_tt = m_from->get_typetype(); | |
628 | Type::typetype_t m_to_tt = m_to->get_typetype(); | |
629 | switch (m_from_tt) { | |
630 | case Type::T_SEQ_A: | |
631 | case Type::T_SEQ_T: | |
632 | if (m_to_tt == Type::T_SEQ_A || m_to_tt == Type::T_SEQ_T) | |
633 | // From record to record: this function was not supposed to be called | |
634 | FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()"); | |
635 | break; | |
636 | case Type::T_SEQOF: | |
637 | if (m_to_tt == Type::T_SET_A || m_to_tt == Type::T_SET_T | |
638 | || m_to_tt == Type::T_SETOF) | |
639 | FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()"); | |
640 | break; | |
641 | case Type::T_SET_A: | |
642 | case Type::T_SET_T: | |
643 | if (m_to_tt == Type::T_SET_A || m_to_tt == Type::T_SET_T) | |
644 | // From set to set: this function was not supposed to be called | |
645 | FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()"); | |
646 | break; | |
647 | case Type::T_SETOF: | |
648 | if (m_to_tt == Type::T_SEQ_A || m_to_tt == Type::T_SEQ_T | |
649 | || m_to_tt == Type::T_SEQOF) | |
650 | FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()"); | |
651 | break; | |
652 | default: | |
653 | FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()"); | |
654 | return; | |
655 | } | |
656 | if (m_from_tt == Type::T_SEQOF || m_from_tt == Type::T_SETOF) { | |
657 | // From a list type to a structure. | |
658 | if (m_to_tt == Type::T_SEQ_A || m_to_tt == Type::T_SEQ_T | |
659 | || m_to_tt == Type::T_SET_A || m_to_tt == Type::T_SET_T) { | |
660 | *p_bodies = mputprintf(*p_bodies, | |
661 | "if (!p_from_v.is_bound() || p_from_v.size_of() != %lu) return FALSE;\n", | |
662 | (long unsigned)m_to->get_nof_comps()); | |
663 | Type *of_type_from = m_from->get_ofType()->get_type_refd_last(); | |
664 | for (size_t i = 0; i < m_to->get_nof_comps(); i++) { | |
665 | CompField *cf_to = m_to->get_comp_byIndex(i); | |
666 | const Identifier& cf_id_to = cf_to->get_name(); | |
667 | Type *cf_type_to = cf_to->get_type()->get_type_refd_last(); | |
668 | string cf_type_to_name = m_is_temp ? cf_type_to | |
669 | ->get_genname_template(p_mod) : cf_type_to->get_genname_value(p_mod); | |
670 | if (!p_mod->needs_type_conv(of_type_from, cf_type_to)) { | |
671 | *p_bodies = mputprintf(*p_bodies, | |
672 | "if (p_from_v[%lu].is_bound()) p_to_v.%s() = p_from_v[%lu];\n", | |
673 | (long unsigned)i, cf_id_to.get_name().c_str(), (long unsigned)i); | |
674 | } else { | |
675 | const string& tmp_id = p_mod->get_temporary_id(); | |
676 | const char *tmp_id_str = tmp_id.c_str(); | |
677 | *p_bodies = mputprintf(*p_bodies, | |
678 | "%s %s;\n" | |
679 | "if (!%s(%s, p_from_v[%lu])) return FALSE;\n" | |
680 | "if (%s.is_bound()) p_to_v.%s() = %s;\n", | |
681 | cf_type_to_name.c_str(), tmp_id_str, get_conv_func(of_type_from, | |
682 | cf_type_to, p_mod).c_str(), tmp_id_str, (long unsigned)i, | |
683 | tmp_id_str, cf_id_to.get_name().c_str(), tmp_id_str); | |
684 | } | |
685 | // Unbound elements needs to be assigned as OMIT_VALUE. | |
686 | if (cf_to->get_is_optional()) | |
687 | *p_bodies = mputprintf(*p_bodies, | |
688 | "else p_to_v.%s() = OMIT_VALUE;\n", | |
689 | cf_id_to.get_name().c_str()); | |
690 | } | |
691 | // From a list type to a list type. | |
692 | } else { | |
693 | *p_bodies = mputstr(*p_bodies, | |
694 | "p_to_v.set_size(p_from_v.size_of());\n" | |
695 | "for (int i = 0; i < p_from_v.size_of(); i++) {\n"); | |
696 | Type *of_type_from = m_from->get_ofType()->get_type_refd_last(); | |
697 | Type *of_type_to = m_to->get_ofType()->get_type_refd_last(); | |
698 | string of_type_to_name = m_is_temp ? of_type_to | |
699 | ->get_genname_template(p_mod) : of_type_to->get_genname_value(p_mod); | |
700 | if (!p_mod->needs_type_conv(of_type_from, of_type_to)) { | |
701 | *p_bodies = mputstr(*p_bodies, | |
702 | "if (p_from_v[i].is_bound()) p_to_v[i] = p_from_v[i];\n}\n"); | |
703 | } else { | |
704 | const string& tmp_id = p_mod->get_temporary_id(); | |
705 | const char *tmp_id_str = tmp_id.c_str(); | |
706 | *p_bodies = mputprintf(*p_bodies, | |
707 | "%s %s;\n" | |
708 | "if (!%s(%s, p_from_v[i])) return FALSE;\n" | |
709 | "if (%s.is_bound()) p_to_v[i] = %s;\n" | |
710 | "}\n", | |
711 | of_type_to_name.c_str(), tmp_id_str, get_conv_func(of_type_from, | |
712 | of_type_to, p_mod).c_str(), tmp_id_str, tmp_id_str, tmp_id_str); | |
713 | } | |
714 | } | |
715 | } else { | |
716 | // From a structure to a structure. Hey... | |
717 | if (m_to_tt == Type::T_SEQ_A || m_to_tt == Type::T_SEQ_T | |
718 | || m_to_tt == Type::T_SET_A || m_to_tt == Type::T_SET_T) { | |
719 | FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()"); | |
720 | // From a structure to a list type. | |
721 | } else { | |
722 | *p_bodies = mputprintf(*p_bodies, | |
723 | "p_to_v.set_size(%lu);\n", | |
724 | (long unsigned)m_from->get_nof_comps()); | |
725 | Type *of_type_to = m_to->get_ofType()->get_type_refd_last(); | |
726 | string of_type_to_name = m_is_temp ? of_type_to | |
727 | ->get_genname_template(p_mod) : of_type_to->get_genname_value(p_mod); | |
728 | for (size_t i = 0; i < m_from->get_nof_comps(); i++) { | |
729 | CompField *cf_from = m_from->get_comp_byIndex(i); | |
730 | const Identifier& cf_id_from = cf_from->get_name(); | |
731 | Type *cf_type_from = cf_from->get_type()->get_type_refd_last(); | |
732 | if (!p_mod->needs_type_conv(cf_type_from, of_type_to)) { | |
733 | *p_bodies = mputprintf(*p_bodies, | |
734 | "if (p_from_v.%s().is_bound()", cf_id_from.get_name().c_str()); | |
735 | if (cf_from->get_is_optional()) { | |
736 | // Additional check to avoid omitted fields. | |
737 | *p_bodies = mputprintf(*p_bodies, | |
738 | " && !(p_from_v.%s()%s)", | |
739 | cf_id_from.get_name().c_str(), (m_is_temp ? ".is_omit()" : | |
740 | " == OMIT_VALUE")); | |
741 | } | |
742 | // Final assignment. | |
743 | *p_bodies = mputprintf(*p_bodies, | |
744 | ") p_to_v[%lu] = p_from_v.%s();\n", (long unsigned)i, | |
745 | cf_id_from.get_name().c_str()); | |
746 | } else { | |
747 | const string& tmp_id = p_mod->get_temporary_id(); | |
748 | const char *tmp_id_str = tmp_id.c_str(); | |
749 | *p_bodies = mputprintf(*p_bodies, | |
750 | "%s %s;\n" | |
751 | "if (!%s(%s, p_from_v.%s())) return FALSE;\n" | |
752 | "if (%s.is_bound()) p_to_v[%lu] = %s;\n", | |
753 | of_type_to_name.c_str(), tmp_id_str, get_conv_func(cf_type_from, | |
754 | of_type_to, p_mod).c_str(), tmp_id_str, | |
755 | cf_id_from.get_name().c_str(), tmp_id_str, (long unsigned)i, | |
756 | tmp_id_str); | |
757 | } | |
758 | } | |
759 | } | |
760 | } | |
761 | } | |
762 | ||
763 | void TypeConv::gen_conv_func_choice_anytype(char **p_bodies, Module *p_mod) | |
764 | { | |
765 | Type::typetype_t from_tt = m_from->get_typetype(); | |
766 | Type::typetype_t to_tt = m_to->get_typetype(); | |
767 | switch (from_tt) { | |
768 | case Type::T_CHOICE_A: | |
769 | case Type::T_CHOICE_T: | |
770 | if (to_tt != Type::T_CHOICE_A && to_tt != Type::T_CHOICE_T) | |
771 | FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()"); | |
772 | break; | |
773 | case Type::T_ANYTYPE: | |
774 | if (to_tt != Type::T_ANYTYPE) | |
775 | FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()"); | |
776 | break; | |
777 | default: | |
778 | FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()"); | |
779 | } | |
780 | // Anytype field accessors always have an "AT_" prefix. | |
781 | const char *anytype_prefix = from_tt == Type::T_ANYTYPE ? "AT_" : ""; | |
782 | *p_bodies = mputprintf(*p_bodies, | |
783 | "if (!p_from_v.is_bound()) return FALSE;\n" | |
784 | "switch (p_from_v.get_selection()) {\n"); | |
785 | for (size_t i = 0; i < m_from->get_nof_comps(); i++) { | |
786 | CompField *cf_from = m_from->get_comp_byIndex(i); | |
787 | Type *cf_type_from = cf_from->get_type()->get_type_refd_last(); | |
788 | const Identifier& cf_id_from = cf_from->get_name(); | |
789 | for (size_t j = 0; j < m_to->get_nof_comps(); j++) { | |
790 | CompField *cf_to = m_to->get_comp_byIndex(j); | |
791 | Type *cf_type_to = cf_to->get_type()->get_type_refd_last(); | |
792 | const Identifier& cf_id_to = cf_to->get_name(); | |
793 | // We have at most one field with the same name, break the inner loop | |
794 | // if found. If the two different types have the same field name, but | |
795 | // they don't have a conversion function (e.g. an integer-boolean | |
796 | // pair) don't generate the assignment. It's only an union specific | |
797 | // problem, since they're compatible if they have at least one | |
798 | // "compatible" field. | |
799 | if (cf_id_from.get_name() == cf_id_to.get_name()) { | |
800 | string from_name = m_is_temp ? m_from->get_genname_template(p_mod) | |
801 | : m_from->get_genname_value(p_mod); | |
802 | string from_name_sel = m_from->get_genname_value(p_mod); | |
803 | if (p_mod->needs_type_conv(cf_type_from, cf_type_to)) { | |
804 | const string& tmp_id = p_mod->get_temporary_id(); | |
805 | const char *tmp_id_str = tmp_id.c_str(); | |
806 | *p_bodies = mputprintf(*p_bodies, | |
807 | "case %s::ALT_%s: {\n" | |
808 | "%s %s;\n" | |
809 | "if (!%s(%s, p_from_v.%s%s())) return FALSE;\n" | |
810 | "if (%s.is_bound()) p_to_v = %s;\n" | |
811 | "break; }\n", | |
812 | from_name_sel.c_str(), cf_id_from.get_name().c_str(), | |
813 | from_name.c_str(), tmp_id_str, | |
814 | get_conv_func(cf_type_from, cf_type_to, p_mod).c_str(), | |
815 | tmp_id_str, anytype_prefix, cf_id_from.get_name().c_str(), | |
816 | tmp_id_str, tmp_id_str); | |
817 | } else if (cf_type_from->is_compatible(cf_type_to, NULL)) { // E.g. basic types. | |
818 | // The same module + field name is required for anytype field | |
819 | // types. Only for structured types. | |
820 | bool both_structured = cf_type_from->is_structured_type() | |
821 | && cf_type_to->is_structured_type(); | |
822 | if (from_tt == Type::T_ANYTYPE && both_structured | |
823 | && cf_type_from->get_my_scope()->get_scope_mod() != | |
824 | cf_type_to->get_my_scope()->get_scope_mod()) | |
825 | break; | |
826 | *p_bodies = mputprintf(*p_bodies, | |
827 | "case %s::ALT_%s:\n" | |
828 | "if (p_from_v.%s%s().is_bound()) " | |
829 | "p_to_v.%s%s() = p_from_v.%s%s();\n" | |
830 | "break;\n", | |
831 | from_name_sel.c_str(), cf_id_from.get_name().c_str(), | |
832 | anytype_prefix, cf_id_from.get_name().c_str(), anytype_prefix, | |
833 | cf_id_to.get_name().c_str(), anytype_prefix, | |
834 | cf_id_from.get_name().c_str()); | |
835 | } | |
836 | break; | |
837 | } | |
838 | } | |
839 | } | |
840 | *p_bodies = mputprintf(*p_bodies, | |
841 | "default:\n" | |
842 | "return FALSE;\n" | |
843 | "}\n"); | |
844 | } | |
845 | ||
846 | TypeChain::TypeChain() : m_first_double(-1) { } | |
847 | ||
848 | TypeChain::~TypeChain() | |
849 | { | |
850 | while (!m_marked_states.empty()) delete m_marked_states.pop(); | |
851 | m_marked_states.clear(); // Does nothing. | |
852 | m_chain.clear(); // (Type *)s should stay. | |
853 | } | |
854 | ||
855 | void TypeChain::add(Type *p_type) | |
856 | { | |
857 | if (m_first_double == -1) { | |
858 | for (size_t i = 0; i < m_chain.size() && m_first_double == -1; i++) | |
859 | if (m_chain[i] == p_type) | |
860 | m_first_double = m_chain.size(); | |
861 | } | |
862 | m_chain.add(p_type); | |
863 | } | |
864 | ||
865 | void TypeChain::mark_state() | |
866 | { | |
867 | // FIXME: Dynamically allocated integers used only for bookkeeping. | |
868 | m_marked_states.push(new int(m_chain.size())); | |
869 | } | |
870 | ||
871 | void TypeChain::previous_state() | |
872 | { | |
873 | if (m_marked_states.empty()) FATAL_ERROR("TypeChain::previous_state()"); | |
874 | int state = *m_marked_states.top(); | |
875 | for (size_t i = m_chain.size() - 1; (int)i >= state; i--) | |
876 | m_chain.replace(i, 1); | |
877 | delete m_marked_states.pop(); | |
878 | if ((int)m_chain.size() <= m_first_double) m_first_double = -1; | |
879 | } | |
880 | ||
881 | } /* namespace Common */ |