1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "TypeCompat.hh"
12 #include "CompField.hh"
13 #include "ttcn3/ArrayDimensions.hh"
14 #include "ttcn3/TtcnTemplate.hh"
19 TypeCompatInfo::TypeCompatInfo(Module
*p_my_module
, Type
*p_type1
,
20 Type
*p_type2
, bool p_add_ref_str
,
21 bool p_strict
, bool p_is_temp
) :
22 m_my_module(p_my_module
), m_type1(p_type1
), m_type2(p_type2
),
23 m_strict(p_strict
), m_is_temp(p_is_temp
), m_needs_conversion(false),
24 m_erroneous(false), str1_elem(false), str2_elem(false)
26 if (p_type1
&& p_add_ref_str
) m_ref_str1
= p_type1
->get_typename();
27 if (p_type2
&& p_add_ref_str
) m_ref_str2
= p_type2
->get_typename();
30 void TypeCompatInfo::set_is_erroneous(Type
*p_type1
, Type
*p_type2
,
31 const string
& p_error_str
)
36 m_error_str
= p_error_str
;
39 string
TypeCompatInfo::get_error_str_str() const
41 // The resulting string should look like: "`f1.f2.f3...fn' [of type `tn']
42 // and `g1.g2.g3...gm' [of type `tm']". In run-time a simple error will
43 // occure with a similarly simple error message.
44 string ret_val
= "Type mismatch: `" + m_ref_str1
;
45 if (m_ref_str1
!= m_type1
->get_typename())
46 ret_val
+= ("' of type `" + m_type1
->get_typename());
47 ret_val
+= ("' and `" + m_ref_str2
);
48 if (m_ref_str2
!= m_type2
->get_typename())
49 ret_val
+= ("' of type `" + m_type2
->get_typename());
50 ret_val
+= "' are not compatible";
51 if (m_error_str
.size() > 0) ret_val
+= (": " + m_error_str
);
55 void TypeCompatInfo::add_type_conversion(Type
*p_from_type
, Type
*p_to_type
)
57 if (!m_my_module
) FATAL_ERROR("TypeCompatInfo::add_type_conversion()");
58 if (p_from_type
== p_to_type
) return;
59 TypeConv
*conv
= new TypeConv(p_from_type
, p_to_type
, m_is_temp
);
60 m_my_module
->add_type_conv(conv
);
63 void TypeCompatInfo::append_ref_str(int p_ref_no
, const string
& p_ref_str
)
65 string
& ref_str
= p_ref_no
== 0 ? m_ref_str1
: m_ref_str2
;
69 string
TypeConv::get_conv_func(Type
*p_from
, Type
*p_to
, Module
*p_mod
)
71 const char *from_name
= p_from
->get_genname_own().c_str();
72 const char *to_name
= p_to
->get_genname_own().c_str();
73 Module
*from_mod
= p_from
->get_my_scope()->get_scope_mod();
74 Module
*to_mod
= p_to
->get_my_scope()->get_scope_mod();
75 string ret_val
= "conv_" + (from_mod
!= p_mod
76 ? (from_mod
->get_modid().get_name() + "_") : string()) + from_name
+ "_" +
77 (to_mod
!= p_mod
? (to_mod
->get_modid().get_name() + "_") : string()) +
82 bool TypeConv::needs_conv_redir(TemplateInstance
*p_ti
, Reference
*p_ref
)
84 if (!use_runtime_2
) FATAL_ERROR("TypeConv::needs_conv_redir()");
87 Template
*templ_body
= p_ti
->get_Template();
88 Template::templatetype_t templ_body_tt
= templ_body
->get_templatetype();
89 switch (templ_body_tt
) {
90 case Template::SPECIFIC_VALUE
:
91 if (templ_body
->get_specific_value()->get_needs_conversion())
95 // If the first parameter needs conversion, go ahead. It's most
96 // probably a reference.
97 if (templ_body
->get_needs_conversion())
101 // Check if the value and the type specified for the template instance
102 // match. If not, we'll need a conversion.
103 if (p_ti
->get_Type()) {
104 Type
*ti_type
= p_ti
->get_Type()->get_type_refd_last();
105 Type
*val_type
= p_ref
->get_refd_assignment()->get_Type()
106 ->get_field_type(p_ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
107 ->get_type_refd_last();
108 if (ti_type
->is_structured_type() && val_type
->is_structured_type()
109 && ti_type
!= val_type
)
115 void TypeConv::gen_conv_code_redir(expression_struct
*p_expr
,
116 TemplateInstance
*p_ti
, Reference
*p_ref
)
118 if (!use_runtime_2
) FATAL_ERROR("TypeConv::gen_conv_code_redir()");
119 Template
*templ_body
= p_ti
->get_Template();
120 Template::templatetype_t templ_body_tt
= templ_body
->get_templatetype();
121 expression_struct expr_tmp
;
122 Code::init_expr(&expr_tmp
);
123 const string
& tmp_id1
= templ_body
->get_temporary_id();
124 const char *tmp_id_str1
= tmp_id1
.c_str();
125 const string
& tmp_id2
= templ_body
->get_temporary_id();
126 const char *tmp_id_str2
= tmp_id2
.c_str();
127 const string
& tmp_id3
= templ_body
->get_temporary_id();
128 const char *tmp_id_str3
= tmp_id3
.c_str();
129 Type
*my_gov
= p_ref
->get_refd_assignment()->get_Type()
130 ->get_field_type(p_ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
131 ->get_type_refd_last();
132 Type
*orig_type
= NULL
;
133 switch (templ_body_tt
) {
134 case Template::SPECIFIC_VALUE
: {
135 Value
*val
= templ_body
->get_specific_value();
136 if (val
->get_valuetype() == Value::V_REFD
)
137 orig_type
= val
->get_reference()->get_refd_assignment()->get_Type()
138 ->get_field_type(val
->get_reference()->get_subrefs(),
139 Type::EXPECTED_DYNAMIC_VALUE
)->get_type_refd_last();
141 case Template::TEMPLATE_REFD
: {
142 Reference
*ref
= templ_body
->get_reference();
143 if (!ref
) FATAL_ERROR("TypeConv::gen_conv_code_redir()");
144 orig_type
= ref
->get_refd_assignment()->get_Type()->get_field_type(ref
145 ->get_subrefs(), Type::EXPECTED_TEMPLATE
)->get_type_refd_last();
150 bool needs_back_conv
= orig_type
!= my_gov
;
151 // Try the template instance's explicit type specification. This will be
152 // the winner if we already have the type.
153 if (p_ti
->get_Type()) {
154 if (p_ti
->get_Type()->get_type_refd_last() != my_gov
) {
155 orig_type
= p_ti
->get_Type()->get_type_refd_last();
156 needs_back_conv
= false;
159 if (!orig_type
|| !my_gov
) FATAL_ERROR("TypeConv::gen_conv_code_redir()");
160 p_expr
->preamble
= mputprintf(p_expr
->preamble
,
161 "%s %s;\n" // For back-conversion.
162 "%s %s;\n" // To store the result of the operation, the "&()" part.
164 orig_type
->get_genname_template(templ_body
->get_my_scope()).c_str(),
165 tmp_id_str1
, orig_type
->get_genname_value(templ_body
->get_my_scope())
166 .c_str(), tmp_id_str2
, my_gov
->get_genname_template(templ_body
167 ->get_my_scope()).c_str(), tmp_id_str3
);
168 expr_tmp
.expr
= mputprintf(expr_tmp
.expr
, "%s = ",
169 !needs_back_conv
? tmp_id_str1
: tmp_id_str3
);
170 p_ti
->generate_code(&expr_tmp
);
171 p_expr
->preamble
= Code::merge_free_expr(p_expr
->preamble
, &expr_tmp
);
172 if (needs_back_conv
) {
173 TypeConv
*back_conv
= new TypeConv(my_gov
, orig_type
, true);
174 templ_body
->get_my_scope()->get_scope_mod()->add_type_conv(back_conv
);
175 p_expr
->preamble
= mputprintf(p_expr
->preamble
,
176 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' and "
177 "`%s' are not compatible at run-time\");\n",
178 TypeConv::get_conv_func(my_gov
, orig_type
, templ_body
->get_my_scope()
179 ->get_scope_mod()).c_str(), tmp_id_str1
, tmp_id_str3
, my_gov
180 ->get_typename().c_str(), orig_type
->get_typename().c_str());
182 // The back-converted template is the first argument.
183 p_expr
->expr
= mputprintf(p_expr
->expr
, "%s, &(%s)",
184 tmp_id_str1
, tmp_id_str2
);
185 Code::init_expr(&expr_tmp
);
186 p_ref
->generate_code(&expr_tmp
);
188 if (expr_tmp
.preamble
)
189 p_expr
->postamble
= mputstr(p_expr
->postamble
, expr_tmp
.preamble
);
190 // Finally, convert back to the original value. TODO: Simplify. Don't
191 // let the conversion die due to an unsuccessful receive operation.
192 p_expr
->postamble
= mputprintf(p_expr
->postamble
,
193 "if (%s.is_bound() && !%s(%s, %s)) TTCN_error(\"Values or templates "
194 "of types `%s' and `%s' are not compatible at run-time\");\n",
195 tmp_id_str2
, TypeConv::get_conv_func(orig_type
, my_gov
, templ_body
196 ->get_my_scope()->get_scope_mod()).c_str(), expr_tmp
.expr
, tmp_id_str2
,
197 orig_type
->get_typename().c_str(), my_gov
->get_typename().c_str());
199 if (expr_tmp
.postamble
)
200 p_expr
->postamble
= mputstr(p_expr
->postamble
, expr_tmp
.postamble
);
201 Code::free_expr(&expr_tmp
);
204 bool TypeConv::needs_conv_refd(GovernedSimple
*p_val_or_temp
)
206 if (!use_runtime_2
) FATAL_ERROR("TypeConv::needs_conv_refd()");
207 Type
*original_type
= NULL
;
208 Type
*current_type
= NULL
;
209 switch (p_val_or_temp
->get_st()) {
210 case Setting::S_TEMPLATE
: {
211 Template
*p_temp
= static_cast<Template
*>(p_val_or_temp
);
212 if (p_temp
->get_templatetype() != Template::TEMPLATE_REFD
) return false;
213 current_type
= p_temp
->get_my_governor()->get_type_refd_last();
214 Common::Reference
*ref
= p_temp
->get_reference();
215 if (!ref
) FATAL_ERROR("TypeConv::needs_conv_refd()");
216 original_type
= ref
->get_refd_assignment()->get_Type()
217 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_TEMPLATE
)
218 ->get_type_refd_last();
221 Value
*p_val
= static_cast<Value
*>(p_val_or_temp
);
222 if (p_val
->get_valuetype() != Value::V_REFD
) return false;
223 current_type
= p_val
->get_my_governor()->get_type_refd_last();
224 Common::Reference
*ref
= p_val
->get_reference();
225 if (!ref
) FATAL_ERROR("TypeConv::needs_conv_refd()");
226 original_type
= ref
->get_refd_assignment()->get_Type()
227 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
228 ->get_type_refd_last();
233 // We should have the scope at this point. Templates like "?" shouldn't
235 return p_val_or_temp
->get_my_scope()->get_scope_mod()
236 ->needs_type_conv(original_type
, current_type
);
239 // Always call needs_conv_refd() before this. It is assumed that the value
240 // is a reference and the conversion is necessary.
241 char *TypeConv::gen_conv_code_refd(char *p_str
, const char *p_name
,
242 GovernedSimple
*p_val_or_temp
)
244 if (!use_runtime_2
) FATAL_ERROR("TypeConv::gen_conv_code_refd()");
245 Type
*original_type
= NULL
;
246 Type
*current_type
= NULL
;
247 string
original_type_genname("<unknown>");
248 string
current_type_genname("<unknown>");
249 Common::Scope
*my_scope
= NULL
;
250 switch (p_val_or_temp
->get_st()) {
251 case Setting::S_TEMPLATE
: {
252 Template
*p_temp
= static_cast<Template
*>(p_val_or_temp
);
253 my_scope
= p_temp
->get_my_scope();
254 if (p_temp
->get_templatetype() != Template::TEMPLATE_REFD
)
255 FATAL_ERROR("TypeConv::gen_conv_code_refd()");
256 Common::Reference
*ref
= p_temp
->get_reference();
257 current_type
= p_temp
->get_my_governor()->get_type_refd_last();
258 original_type
= ref
->get_refd_assignment()->get_Type()
259 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_TEMPLATE
)
260 ->get_type_refd_last();
261 original_type_genname
= original_type
->get_genname_template(my_scope
);
262 current_type_genname
= current_type
->get_genname_template(my_scope
);
265 Value
*p_val
= static_cast<Value
*>(p_val_or_temp
);
266 my_scope
= p_val
->get_my_scope();
267 // We can't really handle other values and templates.
268 if (p_val
->get_valuetype() != Value::V_REFD
)
269 FATAL_ERROR("TypeConv::gen_conv_code_refd()");
270 Common::Reference
*ref
= p_val
->get_reference();
271 current_type
= p_val
->get_my_governor()->get_type_refd_last();
272 original_type
= ref
->get_refd_assignment()->get_Type()
273 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
274 ->get_type_refd_last();
275 original_type_genname
= original_type
->get_genname_value(my_scope
);
276 current_type_genname
= current_type
->get_genname_value(my_scope
);
279 FATAL_ERROR("TypeConv::gen_conv_code_refd()");
281 const string
& tmp_id1
= p_val_or_temp
->get_temporary_id();
282 const char *tmp_id_str1
= tmp_id1
.c_str(); // For "p_val/p_temp".
283 const string
& tmp_id2
= p_val_or_temp
->get_temporary_id();
284 const char *tmp_id_str2
= tmp_id2
.c_str(); // For converted "p_val/p_temp".
285 expression_struct expr
;
286 Code::init_expr(&expr
);
287 expr
.expr
= mputprintf(expr
.expr
,
288 "%s %s;\n%s = ", original_type_genname
.c_str(), tmp_id_str1
,
290 // Always save the value into a separate temporary. Who knows? It can
291 // avoid some problems with referencing complex expressions. The third
292 // argument passed to the conversion function is unused unless the type
293 // we're converting to is a T_CHOICE_{A,T}/T_ANYTYPE. Calling
294 // generate_code_init() directly may cause infinite recursion.
295 if (p_val_or_temp
->get_st() == Setting::S_V
)
296 static_cast<Value
*>(p_val_or_temp
)->get_reference()->generate_code(&expr
);
297 else static_cast<Template
*>(p_val_or_temp
)->get_reference()->generate_code(&expr
);
298 expr
.expr
= mputprintf(expr
.expr
,
300 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' and "
301 "`%s' are not compatible at run-time\")", // ";\n" will be added later.
302 current_type_genname
.c_str(), tmp_id_str2
, get_conv_func(original_type
,
303 current_type
, my_scope
->get_scope_mod()).c_str(), tmp_id_str2
,
304 tmp_id_str1
, original_type
->get_typename().c_str(),
305 current_type
->get_typename().c_str());
306 // Merge by hand. Code::merge_free_expr() puts an additional ";\n".
307 // "p_str" is just a local pointer here, it needs an mputprintf() at the
309 p_str
= Code::merge_free_expr(p_str
, &expr
);
310 return mputprintf(p_str
, "%s = %s;\n", p_name
, tmp_id_str2
);
313 void TypeConv::gen_conv_func(char **p_prototypes
, char **p_bodies
,
316 string from_name
= m_is_temp
? m_from
->get_genname_template(p_mod
)
317 : m_from
->get_genname_value(p_mod
);
318 string to_name
= m_is_temp
? m_to
->get_genname_template(p_mod
)
319 : m_to
->get_genname_value(p_mod
);
320 *p_prototypes
= mputprintf(*p_prototypes
,
321 "static boolean %s(%s& p_to_v, const %s& p_from_v);\n",
322 get_conv_func(m_from
, m_to
, p_mod
).c_str(), to_name
.c_str(),
324 *p_bodies
= mputprintf(*p_bodies
,
325 "static boolean %s(%s& p_to_v, const %s& p_from_v)\n{\n",
326 get_conv_func(m_from
, m_to
, p_mod
).c_str(), to_name
.c_str(),
328 switch (m_to
->get_typetype()) {
331 switch (m_from
->get_typetype()) {
334 gen_conv_func_record_set(p_bodies
, p_mod
);
337 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
340 gen_conv_func_array_record(p_bodies
, p_mod
);
343 FATAL_ERROR("TypeConv::gen_conv_func()");
347 switch (m_from
->get_typetype()) {
351 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
354 gen_conv_func_array_record_of(p_bodies
, p_mod
);
357 FATAL_ERROR("TypeConv::gen_conv_func()");
361 switch (m_from
->get_typetype()) {
364 gen_conv_func_array_record(p_bodies
, p_mod
);
368 gen_conv_func_array_record_of(p_bodies
, p_mod
);
371 FATAL_ERROR("TypeConv::gen_conv_func()");
376 switch (m_from
->get_typetype()) {
379 gen_conv_func_record_set(p_bodies
, p_mod
);
382 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
385 FATAL_ERROR("TypeConv::gen_conv_func()");
389 switch (m_from
->get_typetype()) {
393 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
396 FATAL_ERROR("TypeConv::gen_conv_func()");
399 case Type::T_CHOICE_A
:
400 case Type::T_CHOICE_T
:
401 switch (m_from
->get_typetype()) {
402 case Type::T_CHOICE_A
:
403 case Type::T_CHOICE_T
:
404 gen_conv_func_choice_anytype(p_bodies
, p_mod
);
407 FATAL_ERROR("TypeConv::gen_conv_func()");
410 case Type::T_ANYTYPE
:
411 switch (m_from
->get_typetype()) {
412 case Type::T_ANYTYPE
:
413 gen_conv_func_choice_anytype(p_bodies
, p_mod
);
416 FATAL_ERROR("TypeConv::gen_conv_func()");
420 FATAL_ERROR("TypeConv::gen_conv_func()");
423 *p_bodies
= mputprintf(*p_bodies
, "return TRUE;\n}\n\n");
426 // Conversions between records-records and sets-sets.
427 void TypeConv::gen_conv_func_record_set(char **p_bodies
, Module
*p_mod
)
429 Type::typetype_t m_from_tt
= m_from
->get_typetype();
430 Type::typetype_t m_to_tt
= m_to
->get_typetype();
434 if (m_to_tt
!= Type::T_SEQ_A
&& m_to_tt
!= Type::T_SEQ_T
)
435 FATAL_ERROR("TypeConv::gen_conv_func_record_set()");
439 if (m_to_tt
!= Type::T_SET_A
&& m_to_tt
!= Type::T_SET_T
)
440 FATAL_ERROR("TypeConv::gen_conv_func_record_set()");
443 FATAL_ERROR("TypeConv::gen_conv_func_record_set()");
446 for (size_t i
= 0; i
< m_to
->get_nof_comps(); i
++) {
447 CompField
*cf_to
= m_to
->get_comp_byIndex(i
);
448 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
449 const Identifier
& cf_id_to
= cf_to
->get_name();
450 const Identifier
& cf_id_from
= cf_from
->get_name();
451 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
452 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
453 string cf_type_to_name
= m_is_temp
? cf_type_to
454 ->get_genname_template(p_mod
) : cf_type_to
->get_genname_value(p_mod
);
455 if (!p_mod
->needs_type_conv(cf_type_from
, cf_type_to
)) {
456 *p_bodies
= mputprintf(*p_bodies
,
457 "if (p_from_v.%s().is_bound()) p_to_v.%s() = p_from_v.%s();\n",
458 cf_id_from
.get_name().c_str(), cf_id_to
.get_name().c_str(),
459 cf_id_from
.get_name().c_str());
461 const string
& tmp_id
= p_mod
->get_temporary_id();
462 const char *tmp_id_str
= tmp_id
.c_str();
463 *p_bodies
= mputprintf(*p_bodies
,
465 "if (!%s(%s, p_from_v.%s())) return FALSE;\n"
466 "if (%s.is_bound()) p_to_v.%s() = %s;\n",
467 cf_type_to_name
.c_str(), tmp_id_str
, get_conv_func(cf_type_from
,
468 cf_type_to
, p_mod
).c_str(), tmp_id_str
, cf_id_from
.get_name()
469 .c_str(), tmp_id_str
, cf_id_to
.get_name().c_str(), tmp_id_str
);
474 // Converting arrays to record types vice versa.
475 void TypeConv::gen_conv_func_array_record(char **p_bodies
, Module
*p_mod
)
477 Type::typetype_t m_from_tt
= m_from
->get_typetype();
478 Type::typetype_t m_to_tt
= m_to
->get_typetype();
482 if (m_to_tt
!= Type::T_ARRAY
)
483 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
486 if (m_to_tt
!= Type::T_SEQ_A
&& m_to_tt
!= Type::T_SEQ_T
)
487 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
490 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
493 // From array to a structure type.
494 if (m_from_tt
== Type::T_ARRAY
) {
495 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
496 Int of_type_from_offset
= m_from
->get_dimension()->get_offset();
497 for (size_t i
= 0; i
< m_to
->get_nof_comps(); i
++) {
498 CompField
*cf_to
= m_to
->get_comp_byIndex(i
);
499 const Identifier
& cf_id_to
= cf_to
->get_name();
500 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
501 string cf_type_to_name
= m_is_temp
? cf_type_to
502 ->get_genname_template(p_mod
) : cf_type_to
503 ->get_genname_value(p_mod
);
504 if (!p_mod
->needs_type_conv(of_type_from
, cf_type_to
)) {
505 *p_bodies
= mputprintf(*p_bodies
,
506 "if (p_from_v[%lu].is_bound()) p_to_v.%s() = p_from_v[%lu];\n",
507 (long unsigned)(i
+ of_type_from_offset
),
508 cf_id_to
.get_name().c_str(),
509 (long unsigned)(i
+ of_type_from_offset
));
511 const string
& tmp_id
= p_mod
->get_temporary_id();
512 const char *tmp_id_str
= tmp_id
.c_str();
513 *p_bodies
= mputprintf(*p_bodies
,
515 "if (!%s(%s, p_from_v[%lu])) return FALSE;\n"
516 "if (%s.is_bound()) p_to_v.%s() = %s;\n",
517 cf_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
518 cf_type_to
, p_mod
).c_str(), tmp_id_str
,
519 (long unsigned)(i
+ of_type_from_offset
),
520 tmp_id_str
, cf_id_to
.get_name().c_str(), tmp_id_str
);
523 // From a structure to an array. An example 6.3.2.2 shows that
524 // OMIT_VALUES should be skipped at assignments.
526 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
527 string of_type_to_name
= m_is_temp
? of_type_to
528 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
529 *p_bodies
= mputprintf(*p_bodies
,
530 "unsigned int index = %lu;\n",
531 (long unsigned)m_to
->get_dimension()->get_offset());
532 for (size_t i
= 0; i
< m_from
->get_nof_comps(); i
++) {
533 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
534 const Identifier
& cf_id_from
= cf_from
->get_name();
535 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
536 if (!p_mod
->needs_type_conv(cf_type_from
, of_type_to
)) {
537 *p_bodies
= mputprintf(*p_bodies
,
538 "if (p_from_v.%s().is_bound()) {\n",
539 cf_id_from
.get_name().c_str());
540 if (cf_from
->get_is_optional()) {
541 *p_bodies
= mputprintf(*p_bodies
,
542 "if (!(p_from_v.%s()%s)) p_to_v[index++] "
543 "= p_from_v.%s();\n",
544 cf_id_from
.get_name().c_str(), (m_is_temp
? ".is_omit()" :
545 " == OMIT_VALUE"), cf_id_from
.get_name().c_str());
547 *p_bodies
= mputprintf(*p_bodies
,
548 "p_to_v[index++] = p_from_v.%s();\n",
549 cf_id_from
.get_name().c_str());
551 // For unbound elements.
552 *p_bodies
= mputstr(*p_bodies
, "} else index++;\n");
554 const string
& tmp_id
= p_mod
->get_temporary_id();
555 const char *tmp_id_str
= tmp_id
.c_str();
556 *p_bodies
= mputprintf(*p_bodies
,
558 "if (!%s(%s, p_from_v.%s())) return FALSE;\n"
559 "if (%s.is_bound()) p_to_v[index++] = %s;\n",
560 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(cf_type_from
,
561 of_type_to
, p_mod
).c_str(), tmp_id_str
, cf_id_from
.get_name()
562 .c_str(), tmp_id_str
, tmp_id_str
);
568 // Conversions between arrays and between record ofs and arrays.
569 void TypeConv::gen_conv_func_array_record_of(char **p_bodies
, Module
*p_mod
)
571 Type::typetype_t m_from_tt
= m_from
->get_typetype();
572 Type::typetype_t m_to_tt
= m_to
->get_typetype();
575 if (m_to_tt
== Type::T_SEQOF
)
576 FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()");
581 FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()");
584 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
585 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
586 string of_type_to_name
= m_is_temp
? of_type_to
587 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
588 Int of_type_from_offset
= m_from_tt
== Type::T_ARRAY
? m_from
589 ->get_dimension()->get_offset() : 0;
590 Int of_type_to_offset
= m_to_tt
== Type::T_ARRAY
? m_to
->get_dimension()
592 // If we have two arrays the dimensions must match at this point. For
593 // record of types we need to check the current size.
594 if (m_from_tt
== Type::T_SEQOF
)
595 *p_bodies
= mputprintf(*p_bodies
,
596 "if (!p_from_v.is_bound() || p_from_v.size_of() != %lu) return FALSE;\n",
597 (long unsigned)m_to
->get_dimension()->get_size());
598 else if (m_to_tt
== Type::T_SEQOF
)
599 *p_bodies
= mputprintf(*p_bodies
, "p_to_v.set_size(%lu);\n",
600 (long unsigned)m_from
->get_dimension()->get_size());
601 for (size_t i
= 0; i
< m_from
->get_dimension()->get_size(); i
++) {
602 if (!p_mod
->needs_type_conv(of_type_from
, of_type_to
)) {
603 *p_bodies
= mputprintf(*p_bodies
,
604 "if (p_from_v[%lu].is_bound()) p_to_v[%lu] = p_from_v[%lu];\n",
605 (long unsigned)(i
+ of_type_from_offset
),
606 (long unsigned)(i
+ of_type_to_offset
),
607 (long unsigned)(i
+ of_type_from_offset
));
609 const string
& tmp_id
= p_mod
->get_temporary_id();
610 const char *tmp_id_str
= tmp_id
.c_str();
611 *p_bodies
= mputprintf(*p_bodies
,
613 "if (!%s(%s, p_from_v[%lu])) return FALSE;\n"
614 "if (%s.is_bound()) p_to_v[%lu] = %s;\n"
616 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
617 of_type_to
, p_mod
).c_str(), tmp_id_str
,
618 (long unsigned)(i
+ of_type_from_offset
), tmp_id_str
,
619 (long unsigned)(i
+ of_type_from_offset
), tmp_id_str
);
624 // Conversions from records or sets to record ofs or set ofs. Vice versa.
625 void TypeConv::gen_conv_func_record_set_record_of_set_of(char **p_bodies
, Module
*p_mod
)
627 Type::typetype_t m_from_tt
= m_from
->get_typetype();
628 Type::typetype_t m_to_tt
= m_to
->get_typetype();
632 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
)
633 // From record to record: this function was not supposed to be called
634 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
637 if (m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
638 || m_to_tt
== Type::T_SETOF
)
639 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
643 if (m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
)
644 // From set to set: this function was not supposed to be called
645 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
648 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
649 || m_to_tt
== Type::T_SEQOF
)
650 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
653 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
656 if (m_from_tt
== Type::T_SEQOF
|| m_from_tt
== Type::T_SETOF
) {
657 // From a list type to a structure.
658 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
659 || m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
) {
660 *p_bodies
= mputprintf(*p_bodies
,
661 "if (!p_from_v.is_bound() || p_from_v.size_of() != %lu) return FALSE;\n",
662 (long unsigned)m_to
->get_nof_comps());
663 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
664 for (size_t i
= 0; i
< m_to
->get_nof_comps(); i
++) {
665 CompField
*cf_to
= m_to
->get_comp_byIndex(i
);
666 const Identifier
& cf_id_to
= cf_to
->get_name();
667 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
668 string cf_type_to_name
= m_is_temp
? cf_type_to
669 ->get_genname_template(p_mod
) : cf_type_to
->get_genname_value(p_mod
);
670 if (!p_mod
->needs_type_conv(of_type_from
, cf_type_to
)) {
671 *p_bodies
= mputprintf(*p_bodies
,
672 "if (p_from_v[%lu].is_bound()) p_to_v.%s() = p_from_v[%lu];\n",
673 (long unsigned)i
, cf_id_to
.get_name().c_str(), (long unsigned)i
);
675 const string
& tmp_id
= p_mod
->get_temporary_id();
676 const char *tmp_id_str
= tmp_id
.c_str();
677 *p_bodies
= mputprintf(*p_bodies
,
679 "if (!%s(%s, p_from_v[%lu])) return FALSE;\n"
680 "if (%s.is_bound()) p_to_v.%s() = %s;\n",
681 cf_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
682 cf_type_to
, p_mod
).c_str(), tmp_id_str
, (long unsigned)i
,
683 tmp_id_str
, cf_id_to
.get_name().c_str(), tmp_id_str
);
685 // Unbound elements needs to be assigned as OMIT_VALUE.
686 if (cf_to
->get_is_optional())
687 *p_bodies
= mputprintf(*p_bodies
,
688 "else p_to_v.%s() = OMIT_VALUE;\n",
689 cf_id_to
.get_name().c_str());
691 // From a list type to a list type.
693 *p_bodies
= mputstr(*p_bodies
,
694 "p_to_v.set_size(p_from_v.size_of());\n"
695 "for (int i = 0; i < p_from_v.size_of(); i++) {\n");
696 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
697 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
698 string of_type_to_name
= m_is_temp
? of_type_to
699 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
700 if (!p_mod
->needs_type_conv(of_type_from
, of_type_to
)) {
701 *p_bodies
= mputstr(*p_bodies
,
702 "if (p_from_v[i].is_bound()) p_to_v[i] = p_from_v[i];\n}\n");
704 const string
& tmp_id
= p_mod
->get_temporary_id();
705 const char *tmp_id_str
= tmp_id
.c_str();
706 *p_bodies
= mputprintf(*p_bodies
,
708 "if (!%s(%s, p_from_v[i])) return FALSE;\n"
709 "if (%s.is_bound()) p_to_v[i] = %s;\n"
711 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
712 of_type_to
, p_mod
).c_str(), tmp_id_str
, tmp_id_str
, tmp_id_str
);
716 // From a structure to a structure. Hey...
717 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
718 || m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
) {
719 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
720 // From a structure to a list type.
722 *p_bodies
= mputprintf(*p_bodies
,
723 "p_to_v.set_size(%lu);\n",
724 (long unsigned)m_from
->get_nof_comps());
725 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
726 string of_type_to_name
= m_is_temp
? of_type_to
727 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
728 for (size_t i
= 0; i
< m_from
->get_nof_comps(); i
++) {
729 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
730 const Identifier
& cf_id_from
= cf_from
->get_name();
731 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
732 if (!p_mod
->needs_type_conv(cf_type_from
, of_type_to
)) {
733 *p_bodies
= mputprintf(*p_bodies
,
734 "if (p_from_v.%s().is_bound()", cf_id_from
.get_name().c_str());
735 if (cf_from
->get_is_optional()) {
736 // Additional check to avoid omitted fields.
737 *p_bodies
= mputprintf(*p_bodies
,
738 " && !(p_from_v.%s()%s)",
739 cf_id_from
.get_name().c_str(), (m_is_temp
? ".is_omit()" :
743 *p_bodies
= mputprintf(*p_bodies
,
744 ") p_to_v[%lu] = p_from_v.%s();\n", (long unsigned)i
,
745 cf_id_from
.get_name().c_str());
747 const string
& tmp_id
= p_mod
->get_temporary_id();
748 const char *tmp_id_str
= tmp_id
.c_str();
749 *p_bodies
= mputprintf(*p_bodies
,
751 "if (!%s(%s, p_from_v.%s())) return FALSE;\n"
752 "if (%s.is_bound()) p_to_v[%lu] = %s;\n",
753 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(cf_type_from
,
754 of_type_to
, p_mod
).c_str(), tmp_id_str
,
755 cf_id_from
.get_name().c_str(), tmp_id_str
, (long unsigned)i
,
763 void TypeConv::gen_conv_func_choice_anytype(char **p_bodies
, Module
*p_mod
)
765 Type::typetype_t from_tt
= m_from
->get_typetype();
766 Type::typetype_t to_tt
= m_to
->get_typetype();
768 case Type::T_CHOICE_A
:
769 case Type::T_CHOICE_T
:
770 if (to_tt
!= Type::T_CHOICE_A
&& to_tt
!= Type::T_CHOICE_T
)
771 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
773 case Type::T_ANYTYPE
:
774 if (to_tt
!= Type::T_ANYTYPE
)
775 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
778 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
780 // Anytype field accessors always have an "AT_" prefix.
781 const char *anytype_prefix
= from_tt
== Type::T_ANYTYPE
? "AT_" : "";
782 *p_bodies
= mputprintf(*p_bodies
,
783 "if (!p_from_v.is_bound()) return FALSE;\n"
784 "switch (p_from_v.get_selection()) {\n");
785 for (size_t i
= 0; i
< m_from
->get_nof_comps(); i
++) {
786 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
787 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
788 const Identifier
& cf_id_from
= cf_from
->get_name();
789 for (size_t j
= 0; j
< m_to
->get_nof_comps(); j
++) {
790 CompField
*cf_to
= m_to
->get_comp_byIndex(j
);
791 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
792 const Identifier
& cf_id_to
= cf_to
->get_name();
793 // We have at most one field with the same name, break the inner loop
794 // if found. If the two different types have the same field name, but
795 // they don't have a conversion function (e.g. an integer-boolean
796 // pair) don't generate the assignment. It's only an union specific
797 // problem, since they're compatible if they have at least one
798 // "compatible" field.
799 if (cf_id_from
.get_name() == cf_id_to
.get_name()) {
800 string from_name
= m_is_temp
? m_from
->get_genname_template(p_mod
)
801 : m_from
->get_genname_value(p_mod
);
802 string from_name_sel
= m_from
->get_genname_value(p_mod
);
803 if (p_mod
->needs_type_conv(cf_type_from
, cf_type_to
)) {
804 const string
& tmp_id
= p_mod
->get_temporary_id();
805 const char *tmp_id_str
= tmp_id
.c_str();
806 *p_bodies
= mputprintf(*p_bodies
,
807 "case %s::ALT_%s: {\n"
809 "if (!%s(%s, p_from_v.%s%s())) return FALSE;\n"
810 "if (%s.is_bound()) p_to_v = %s;\n"
812 from_name_sel
.c_str(), cf_id_from
.get_name().c_str(),
813 from_name
.c_str(), tmp_id_str
,
814 get_conv_func(cf_type_from
, cf_type_to
, p_mod
).c_str(),
815 tmp_id_str
, anytype_prefix
, cf_id_from
.get_name().c_str(),
816 tmp_id_str
, tmp_id_str
);
817 } else if (cf_type_from
->is_compatible(cf_type_to
, NULL
)) { // E.g. basic types.
818 // The same module + field name is required for anytype field
819 // types. Only for structured types.
820 bool both_structured
= cf_type_from
->is_structured_type()
821 && cf_type_to
->is_structured_type();
822 if (from_tt
== Type::T_ANYTYPE
&& both_structured
823 && cf_type_from
->get_my_scope()->get_scope_mod() !=
824 cf_type_to
->get_my_scope()->get_scope_mod())
826 *p_bodies
= mputprintf(*p_bodies
,
828 "if (p_from_v.%s%s().is_bound()) "
829 "p_to_v.%s%s() = p_from_v.%s%s();\n"
831 from_name_sel
.c_str(), cf_id_from
.get_name().c_str(),
832 anytype_prefix
, cf_id_from
.get_name().c_str(), anytype_prefix
,
833 cf_id_to
.get_name().c_str(), anytype_prefix
,
834 cf_id_from
.get_name().c_str());
840 *p_bodies
= mputprintf(*p_bodies
,
846 TypeChain::TypeChain() : m_first_double(-1) { }
848 TypeChain::~TypeChain()
850 while (!m_marked_states
.empty()) delete m_marked_states
.pop();
851 m_marked_states
.clear(); // Does nothing.
852 m_chain
.clear(); // (Type *)s should stay.
855 void TypeChain::add(Type
*p_type
)
857 if (m_first_double
== -1) {
858 for (size_t i
= 0; i
< m_chain
.size() && m_first_double
== -1; i
++)
859 if (m_chain
[i
] == p_type
)
860 m_first_double
= m_chain
.size();
865 void TypeChain::mark_state()
867 // FIXME: Dynamically allocated integers used only for bookkeeping.
868 m_marked_states
.push(new int(m_chain
.size()));
871 void TypeChain::previous_state()
873 if (m_marked_states
.empty()) FATAL_ERROR("TypeChain::previous_state()");
874 int state
= *m_marked_states
.top();
875 for (size_t i
= m_chain
.size() - 1; (int)i
>= state
; i
--)
876 m_chain
.replace(i
, 1);
877 delete m_marked_states
.pop();
878 if ((int)m_chain
.size() <= m_first_double
) m_first_double
= -1;
881 } /* namespace Common */