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