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
13 ******************************************************************************/
14 #include "TypeCompat.hh"
18 #include "CompField.hh"
19 #include "ttcn3/ArrayDimensions.hh"
20 #include "ttcn3/TtcnTemplate.hh"
25 TypeCompatInfo::TypeCompatInfo(Module
*p_my_module
, Type
*p_type1
,
26 Type
*p_type2
, bool p_add_ref_str
,
27 bool p_strict
, bool p_is_temp
) :
28 m_my_module(p_my_module
), m_type1(p_type1
), m_type2(p_type2
),
29 m_strict(p_strict
), m_is_temp(p_is_temp
), m_needs_conversion(false),
30 m_erroneous(false), str1_elem(false), str2_elem(false)
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();
36 void TypeCompatInfo::set_is_erroneous(Type
*p_type1
, Type
*p_type2
,
37 const string
& p_error_str
)
42 m_error_str
= p_error_str
;
45 string
TypeCompatInfo::get_error_str_str() const
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
);
61 void TypeCompatInfo::add_type_conversion(Type
*p_from_type
, Type
*p_to_type
)
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
);
69 void TypeCompatInfo::append_ref_str(int p_ref_no
, const string
& p_ref_str
)
71 string
& ref_str
= p_ref_no
== 0 ? m_ref_str1
: m_ref_str2
;
75 string
TypeConv::get_conv_func(Type
*p_from
, Type
*p_to
, Module
*p_mod
)
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()) +
88 bool TypeConv::needs_conv_redir(TemplateInstance
*p_ti
, Reference
*p_ref
)
90 if (!use_runtime_2
) FATAL_ERROR("TypeConv::needs_conv_redir()");
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())
101 // If the first parameter needs conversion, go ahead. It's most
102 // probably a reference.
103 if (templ_body
->get_needs_conversion())
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
)
121 void TypeConv::gen_conv_code_redir(expression_struct
*p_expr
,
122 TemplateInstance
*p_ti
, Reference
*p_ref
)
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();
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();
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;
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.
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());
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
);
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());
205 if (expr_tmp
.postamble
)
206 p_expr
->postamble
= mputstr(p_expr
->postamble
, expr_tmp
.postamble
);
207 Code::free_expr(&expr_tmp
);
210 bool TypeConv::needs_conv_refd(GovernedSimple
*p_val_or_temp
)
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();
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();
239 // We should have the scope at this point. Templates like "?" shouldn't
241 return p_val_or_temp
->get_my_scope()->get_scope_mod()
242 ->needs_type_conv(original_type
, current_type
);
245 // Always call needs_conv_refd() before this. It is assumed that the value
246 // is a reference and the conversion is necessary.
247 char *TypeConv::gen_conv_code_refd(char *p_str
, const char *p_name
,
248 GovernedSimple
*p_val_or_temp
)
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
);
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
);
285 FATAL_ERROR("TypeConv::gen_conv_code_refd()");
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
,
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
,
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
315 p_str
= Code::merge_free_expr(p_str
, &expr
);
316 return mputprintf(p_str
, "%s = %s;\n", p_name
, tmp_id_str2
);
319 void TypeConv::gen_conv_func(char **p_prototypes
, char **p_bodies
,
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
,
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(),
330 *p_bodies
= mputprintf(*p_bodies
,
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(),
334 switch (m_to
->get_typetype()) {
337 switch (m_from
->get_typetype()) {
340 gen_conv_func_record_set(p_bodies
, p_mod
);
343 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
346 gen_conv_func_array_record(p_bodies
, p_mod
);
349 FATAL_ERROR("TypeConv::gen_conv_func()");
353 switch (m_from
->get_typetype()) {
357 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
360 gen_conv_func_array_record_of(p_bodies
, p_mod
);
363 FATAL_ERROR("TypeConv::gen_conv_func()");
367 switch (m_from
->get_typetype()) {
370 gen_conv_func_array_record(p_bodies
, p_mod
);
374 gen_conv_func_array_record_of(p_bodies
, p_mod
);
377 FATAL_ERROR("TypeConv::gen_conv_func()");
382 switch (m_from
->get_typetype()) {
385 gen_conv_func_record_set(p_bodies
, p_mod
);
388 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
391 FATAL_ERROR("TypeConv::gen_conv_func()");
395 switch (m_from
->get_typetype()) {
399 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
402 FATAL_ERROR("TypeConv::gen_conv_func()");
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
);
413 FATAL_ERROR("TypeConv::gen_conv_func()");
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
);
422 FATAL_ERROR("TypeConv::gen_conv_func()");
426 FATAL_ERROR("TypeConv::gen_conv_func()");
429 *p_bodies
= mputprintf(*p_bodies
, "return TRUE;\n}\n\n");
432 // Conversions between records-records and sets-sets.
433 void TypeConv::gen_conv_func_record_set(char **p_bodies
, Module
*p_mod
)
435 Type::typetype_t m_from_tt
= m_from
->get_typetype();
436 Type::typetype_t m_to_tt
= m_to
->get_typetype();
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()");
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()");
449 FATAL_ERROR("TypeConv::gen_conv_func_record_set()");
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());
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
,
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
);
480 // Converting arrays to record types vice versa.
481 void TypeConv::gen_conv_func_array_record(char **p_bodies
, Module
*p_mod
)
483 Type::typetype_t m_from_tt
= m_from
->get_typetype();
484 Type::typetype_t m_to_tt
= m_to
->get_typetype();
488 if (m_to_tt
!= Type::T_ARRAY
)
489 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
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()");
496 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
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
));
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
,
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
);
529 // From a structure to an array. An example 6.3.2.2 shows that
530 // OMIT_VALUES should be skipped at assignments.
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());
553 *p_bodies
= mputprintf(*p_bodies
,
554 "p_to_v[index++] = p_from_v.%s();\n",
555 cf_id_from
.get_name().c_str());
557 // For unbound elements.
558 *p_bodies
= mputstr(*p_bodies
, "} else index++;\n");
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
,
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
);
574 // Conversions between arrays and between record ofs and arrays.
575 void TypeConv::gen_conv_func_array_record_of(char **p_bodies
, Module
*p_mod
)
577 Type::typetype_t m_from_tt
= m_from
->get_typetype();
578 Type::typetype_t m_to_tt
= m_to
->get_typetype();
581 if (m_to_tt
== Type::T_SEQOF
)
582 FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()");
587 FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()");
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()
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
));
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
,
619 "if (!%s(%s, p_from_v[%lu])) return FALSE;\n"
620 "if (%s.is_bound()) p_to_v[%lu] = %s;\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
);
630 // Conversions from records or sets to record ofs or set ofs. Vice versa.
631 void TypeConv::gen_conv_func_record_set_record_of_set_of(char **p_bodies
, Module
*p_mod
)
633 Type::typetype_t m_from_tt
= m_from
->get_typetype();
634 Type::typetype_t m_to_tt
= m_to
->get_typetype();
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()");
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()");
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()");
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()");
659 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
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
);
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
,
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
);
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());
697 // From a list type to a list type.
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");
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
,
714 "if (!%s(%s, p_from_v[i])) return FALSE;\n"
715 "if (%s.is_bound()) p_to_v[i] = %s;\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
);
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.
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()" :
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());
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
,
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
,
769 void TypeConv::gen_conv_func_choice_anytype(char **p_bodies
, Module
*p_mod
)
771 Type::typetype_t from_tt
= m_from
->get_typetype();
772 Type::typetype_t to_tt
= m_to
->get_typetype();
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()");
779 case Type::T_ANYTYPE
:
780 if (to_tt
!= Type::T_ANYTYPE
)
781 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
784 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
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"
815 "if (!%s(%s, p_from_v.%s%s())) return FALSE;\n"
816 "if (%s.is_bound()) p_to_v = %s;\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())
832 *p_bodies
= mputprintf(*p_bodies
,
834 "if (p_from_v.%s%s().is_bound()) "
835 "p_to_v.%s%s() = p_from_v.%s%s();\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());
846 *p_bodies
= mputprintf(*p_bodies
,
852 TypeChain::TypeChain() : m_first_double(-1) { }
854 TypeChain::~TypeChain()
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.
861 void TypeChain::add(Type
*p_type
)
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();
871 void TypeChain::mark_state()
873 // FIXME: Dynamically allocated integers used only for bookkeeping.
874 m_marked_states
.push(new int(m_chain
.size()));
877 void TypeChain::previous_state()
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;
887 } /* namespace Common */