Titan Core Initial Contribution
[deliverable/titan.core.git] / compiler2 / TypeCompat.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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 #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 */
This page took 0.055393 seconds and 5 git commands to generate.