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