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