Merge pull request #64 from BenceJanosSzabo/master
[deliverable/titan.core.git] / compiler2 / TypeCompat.cc
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 ******************************************************************************/
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 */
This page took 0.051652 seconds and 5 git commands to generate.