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
12 ******************************************************************************/
13 #include "TypeCompat.hh"
17 #include "CompField.hh"
18 #include "ttcn3/ArrayDimensions.hh"
19 #include "ttcn3/TtcnTemplate.hh"
24 TypeCompatInfo::TypeCompatInfo(Module
*p_my_module
, Type
*p_type1
,
25 Type
*p_type2
, bool p_add_ref_str
,
26 bool p_strict
, bool p_is_temp
) :
27 m_my_module(p_my_module
), m_type1(p_type1
), m_type2(p_type2
),
28 m_strict(p_strict
), m_is_temp(p_is_temp
), m_needs_conversion(false),
29 m_erroneous(false), str1_elem(false), str2_elem(false)
31 if (p_type1
&& p_add_ref_str
) m_ref_str1
= p_type1
->get_typename();
32 if (p_type2
&& p_add_ref_str
) m_ref_str2
= p_type2
->get_typename();
35 void TypeCompatInfo::set_is_erroneous(Type
*p_type1
, Type
*p_type2
,
36 const string
& p_error_str
)
41 m_error_str
= p_error_str
;
44 string
TypeCompatInfo::get_error_str_str() const
46 // The resulting string should look like: "`f1.f2.f3...fn' [of type `tn']
47 // and `g1.g2.g3...gm' [of type `tm']". In run-time a simple error will
48 // occure with a similarly simple error message.
49 string ret_val
= "Type mismatch: `" + m_ref_str1
;
50 if (m_ref_str1
!= m_type1
->get_typename())
51 ret_val
+= ("' of type `" + m_type1
->get_typename());
52 ret_val
+= ("' and `" + m_ref_str2
);
53 if (m_ref_str2
!= m_type2
->get_typename())
54 ret_val
+= ("' of type `" + m_type2
->get_typename());
55 ret_val
+= "' are not compatible";
56 if (m_error_str
.size() > 0) ret_val
+= (": " + m_error_str
);
60 void TypeCompatInfo::add_type_conversion(Type
*p_from_type
, Type
*p_to_type
)
62 if (!m_my_module
) FATAL_ERROR("TypeCompatInfo::add_type_conversion()");
63 if (p_from_type
== p_to_type
) return;
64 TypeConv
*conv
= new TypeConv(p_from_type
, p_to_type
, m_is_temp
);
65 m_my_module
->add_type_conv(conv
);
68 void TypeCompatInfo::append_ref_str(int p_ref_no
, const string
& p_ref_str
)
70 string
& ref_str
= p_ref_no
== 0 ? m_ref_str1
: m_ref_str2
;
74 string
TypeConv::get_conv_func(Type
*p_from
, Type
*p_to
, Module
*p_mod
)
76 const char *from_name
= p_from
->get_genname_own().c_str();
77 const char *to_name
= p_to
->get_genname_own().c_str();
78 Module
*from_mod
= p_from
->get_my_scope()->get_scope_mod();
79 Module
*to_mod
= p_to
->get_my_scope()->get_scope_mod();
80 string ret_val
= "conv_" + (from_mod
!= p_mod
81 ? (from_mod
->get_modid().get_name() + "_") : string()) + from_name
+ "_" +
82 (to_mod
!= p_mod
? (to_mod
->get_modid().get_name() + "_") : string()) +
87 bool TypeConv::needs_conv_redir(TemplateInstance
*p_ti
, Reference
*p_ref
)
89 if (!use_runtime_2
) FATAL_ERROR("TypeConv::needs_conv_redir()");
92 Template
*templ_body
= p_ti
->get_Template();
93 Template::templatetype_t templ_body_tt
= templ_body
->get_templatetype();
94 switch (templ_body_tt
) {
95 case Template::SPECIFIC_VALUE
:
96 if (templ_body
->get_specific_value()->get_needs_conversion())
100 // If the first parameter needs conversion, go ahead. It's most
101 // probably a reference.
102 if (templ_body
->get_needs_conversion())
106 // Check if the value and the type specified for the template instance
107 // match. If not, we'll need a conversion.
108 if (p_ti
->get_Type()) {
109 Type
*ti_type
= p_ti
->get_Type()->get_type_refd_last();
110 Type
*val_type
= p_ref
->get_refd_assignment()->get_Type()
111 ->get_field_type(p_ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
112 ->get_type_refd_last();
113 if (ti_type
->is_structured_type() && val_type
->is_structured_type()
114 && ti_type
!= val_type
)
120 void TypeConv::gen_conv_code_redir(expression_struct
*p_expr
,
121 TemplateInstance
*p_ti
, Reference
*p_ref
)
123 if (!use_runtime_2
) FATAL_ERROR("TypeConv::gen_conv_code_redir()");
124 Template
*templ_body
= p_ti
->get_Template();
125 Template::templatetype_t templ_body_tt
= templ_body
->get_templatetype();
126 expression_struct expr_tmp
;
127 Code::init_expr(&expr_tmp
);
128 const string
& tmp_id1
= templ_body
->get_temporary_id();
129 const char *tmp_id_str1
= tmp_id1
.c_str();
130 const string
& tmp_id2
= templ_body
->get_temporary_id();
131 const char *tmp_id_str2
= tmp_id2
.c_str();
132 const string
& tmp_id3
= templ_body
->get_temporary_id();
133 const char *tmp_id_str3
= tmp_id3
.c_str();
134 Type
*my_gov
= p_ref
->get_refd_assignment()->get_Type()
135 ->get_field_type(p_ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
136 ->get_type_refd_last();
137 Type
*orig_type
= NULL
;
138 switch (templ_body_tt
) {
139 case Template::SPECIFIC_VALUE
: {
140 Value
*val
= templ_body
->get_specific_value();
141 if (val
->get_valuetype() == Value::V_REFD
)
142 orig_type
= val
->get_reference()->get_refd_assignment()->get_Type()
143 ->get_field_type(val
->get_reference()->get_subrefs(),
144 Type::EXPECTED_DYNAMIC_VALUE
)->get_type_refd_last();
146 case Template::TEMPLATE_REFD
: {
147 Reference
*ref
= templ_body
->get_reference();
148 if (!ref
) FATAL_ERROR("TypeConv::gen_conv_code_redir()");
149 orig_type
= ref
->get_refd_assignment()->get_Type()->get_field_type(ref
150 ->get_subrefs(), Type::EXPECTED_TEMPLATE
)->get_type_refd_last();
155 bool needs_back_conv
= orig_type
!= my_gov
;
156 // Try the template instance's explicit type specification. This will be
157 // the winner if we already have the type.
158 if (p_ti
->get_Type()) {
159 if (p_ti
->get_Type()->get_type_refd_last() != my_gov
) {
160 orig_type
= p_ti
->get_Type()->get_type_refd_last();
161 needs_back_conv
= false;
164 if (!orig_type
|| !my_gov
) FATAL_ERROR("TypeConv::gen_conv_code_redir()");
165 p_expr
->preamble
= mputprintf(p_expr
->preamble
,
166 "%s %s;\n" // For back-conversion.
167 "%s %s;\n" // To store the result of the operation, the "&()" part.
169 orig_type
->get_genname_template(templ_body
->get_my_scope()).c_str(),
170 tmp_id_str1
, orig_type
->get_genname_value(templ_body
->get_my_scope())
171 .c_str(), tmp_id_str2
, my_gov
->get_genname_template(templ_body
172 ->get_my_scope()).c_str(), tmp_id_str3
);
173 expr_tmp
.expr
= mputprintf(expr_tmp
.expr
, "%s = ",
174 !needs_back_conv
? tmp_id_str1
: tmp_id_str3
);
175 p_ti
->generate_code(&expr_tmp
);
176 p_expr
->preamble
= Code::merge_free_expr(p_expr
->preamble
, &expr_tmp
);
177 if (needs_back_conv
) {
178 TypeConv
*back_conv
= new TypeConv(my_gov
, orig_type
, true);
179 templ_body
->get_my_scope()->get_scope_mod()->add_type_conv(back_conv
);
180 p_expr
->preamble
= mputprintf(p_expr
->preamble
,
181 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' and "
182 "`%s' are not compatible at run-time\");\n",
183 TypeConv::get_conv_func(my_gov
, orig_type
, templ_body
->get_my_scope()
184 ->get_scope_mod()).c_str(), tmp_id_str1
, tmp_id_str3
, my_gov
185 ->get_typename().c_str(), orig_type
->get_typename().c_str());
187 // The back-converted template is the first argument.
188 p_expr
->expr
= mputprintf(p_expr
->expr
, "%s, &(%s)",
189 tmp_id_str1
, tmp_id_str2
);
190 Code::init_expr(&expr_tmp
);
191 p_ref
->generate_code(&expr_tmp
);
193 if (expr_tmp
.preamble
)
194 p_expr
->postamble
= mputstr(p_expr
->postamble
, expr_tmp
.preamble
);
195 // Finally, convert back to the original value. TODO: Simplify. Don't
196 // let the conversion die due to an unsuccessful receive operation.
197 p_expr
->postamble
= mputprintf(p_expr
->postamble
,
198 "if (%s.is_bound() && !%s(%s, %s)) TTCN_error(\"Values or templates "
199 "of types `%s' and `%s' are not compatible at run-time\");\n",
200 tmp_id_str2
, TypeConv::get_conv_func(orig_type
, my_gov
, templ_body
201 ->get_my_scope()->get_scope_mod()).c_str(), expr_tmp
.expr
, tmp_id_str2
,
202 orig_type
->get_typename().c_str(), my_gov
->get_typename().c_str());
204 if (expr_tmp
.postamble
)
205 p_expr
->postamble
= mputstr(p_expr
->postamble
, expr_tmp
.postamble
);
206 Code::free_expr(&expr_tmp
);
209 bool TypeConv::needs_conv_refd(GovernedSimple
*p_val_or_temp
)
211 if (!use_runtime_2
) FATAL_ERROR("TypeConv::needs_conv_refd()");
212 Type
*original_type
= NULL
;
213 Type
*current_type
= NULL
;
214 switch (p_val_or_temp
->get_st()) {
215 case Setting::S_TEMPLATE
: {
216 Template
*p_temp
= static_cast<Template
*>(p_val_or_temp
);
217 if (p_temp
->get_templatetype() != Template::TEMPLATE_REFD
) return false;
218 current_type
= p_temp
->get_my_governor()->get_type_refd_last();
219 Common::Reference
*ref
= p_temp
->get_reference();
220 if (!ref
) FATAL_ERROR("TypeConv::needs_conv_refd()");
221 original_type
= ref
->get_refd_assignment()->get_Type()
222 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_TEMPLATE
)
223 ->get_type_refd_last();
226 Value
*p_val
= static_cast<Value
*>(p_val_or_temp
);
227 if (p_val
->get_valuetype() != Value::V_REFD
) return false;
228 current_type
= p_val
->get_my_governor()->get_type_refd_last();
229 Common::Reference
*ref
= p_val
->get_reference();
230 if (!ref
) FATAL_ERROR("TypeConv::needs_conv_refd()");
231 original_type
= ref
->get_refd_assignment()->get_Type()
232 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
233 ->get_type_refd_last();
238 // We should have the scope at this point. Templates like "?" shouldn't
240 return p_val_or_temp
->get_my_scope()->get_scope_mod()
241 ->needs_type_conv(original_type
, current_type
);
244 // Always call needs_conv_refd() before this. It is assumed that the value
245 // is a reference and the conversion is necessary.
246 char *TypeConv::gen_conv_code_refd(char *p_str
, const char *p_name
,
247 GovernedSimple
*p_val_or_temp
)
249 if (!use_runtime_2
) FATAL_ERROR("TypeConv::gen_conv_code_refd()");
250 Type
*original_type
= NULL
;
251 Type
*current_type
= NULL
;
252 string
original_type_genname("<unknown>");
253 string
current_type_genname("<unknown>");
254 Common::Scope
*my_scope
= NULL
;
255 switch (p_val_or_temp
->get_st()) {
256 case Setting::S_TEMPLATE
: {
257 Template
*p_temp
= static_cast<Template
*>(p_val_or_temp
);
258 my_scope
= p_temp
->get_my_scope();
259 if (p_temp
->get_templatetype() != Template::TEMPLATE_REFD
)
260 FATAL_ERROR("TypeConv::gen_conv_code_refd()");
261 Common::Reference
*ref
= p_temp
->get_reference();
262 current_type
= p_temp
->get_my_governor()->get_type_refd_last();
263 original_type
= ref
->get_refd_assignment()->get_Type()
264 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_TEMPLATE
)
265 ->get_type_refd_last();
266 original_type_genname
= original_type
->get_genname_template(my_scope
);
267 current_type_genname
= current_type
->get_genname_template(my_scope
);
270 Value
*p_val
= static_cast<Value
*>(p_val_or_temp
);
271 my_scope
= p_val
->get_my_scope();
272 // We can't really handle other values and templates.
273 if (p_val
->get_valuetype() != Value::V_REFD
)
274 FATAL_ERROR("TypeConv::gen_conv_code_refd()");
275 Common::Reference
*ref
= p_val
->get_reference();
276 current_type
= p_val
->get_my_governor()->get_type_refd_last();
277 original_type
= ref
->get_refd_assignment()->get_Type()
278 ->get_field_type(ref
->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE
)
279 ->get_type_refd_last();
280 original_type_genname
= original_type
->get_genname_value(my_scope
);
281 current_type_genname
= current_type
->get_genname_value(my_scope
);
284 FATAL_ERROR("TypeConv::gen_conv_code_refd()");
286 const string
& tmp_id1
= p_val_or_temp
->get_temporary_id();
287 const char *tmp_id_str1
= tmp_id1
.c_str(); // For "p_val/p_temp".
288 const string
& tmp_id2
= p_val_or_temp
->get_temporary_id();
289 const char *tmp_id_str2
= tmp_id2
.c_str(); // For converted "p_val/p_temp".
290 expression_struct expr
;
291 Code::init_expr(&expr
);
292 expr
.expr
= mputprintf(expr
.expr
,
293 "%s %s;\n%s = ", original_type_genname
.c_str(), tmp_id_str1
,
295 // Always save the value into a separate temporary. Who knows? It can
296 // avoid some problems with referencing complex expressions. The third
297 // argument passed to the conversion function is unused unless the type
298 // we're converting to is a T_CHOICE_{A,T}/T_ANYTYPE. Calling
299 // generate_code_init() directly may cause infinite recursion.
300 if (p_val_or_temp
->get_st() == Setting::S_V
)
301 static_cast<Value
*>(p_val_or_temp
)->get_reference()->generate_code(&expr
);
302 else static_cast<Template
*>(p_val_or_temp
)->get_reference()->generate_code(&expr
);
303 expr
.expr
= mputprintf(expr
.expr
,
305 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' and "
306 "`%s' are not compatible at run-time\")", // ";\n" will be added later.
307 current_type_genname
.c_str(), tmp_id_str2
, get_conv_func(original_type
,
308 current_type
, my_scope
->get_scope_mod()).c_str(), tmp_id_str2
,
309 tmp_id_str1
, original_type
->get_typename().c_str(),
310 current_type
->get_typename().c_str());
311 // Merge by hand. Code::merge_free_expr() puts an additional ";\n".
312 // "p_str" is just a local pointer here, it needs an mputprintf() at the
314 p_str
= Code::merge_free_expr(p_str
, &expr
);
315 return mputprintf(p_str
, "%s = %s;\n", p_name
, tmp_id_str2
);
318 void TypeConv::gen_conv_func(char **p_prototypes
, char **p_bodies
,
321 string from_name
= m_is_temp
? m_from
->get_genname_template(p_mod
)
322 : m_from
->get_genname_value(p_mod
);
323 string to_name
= m_is_temp
? m_to
->get_genname_template(p_mod
)
324 : m_to
->get_genname_value(p_mod
);
325 *p_prototypes
= mputprintf(*p_prototypes
,
326 "static boolean %s(%s& p_to_v, const %s& p_from_v);\n",
327 get_conv_func(m_from
, m_to
, p_mod
).c_str(), to_name
.c_str(),
329 *p_bodies
= mputprintf(*p_bodies
,
330 "static boolean %s(%s& p_to_v, const %s& p_from_v)\n{\n",
331 get_conv_func(m_from
, m_to
, p_mod
).c_str(), to_name
.c_str(),
333 switch (m_to
->get_typetype()) {
336 switch (m_from
->get_typetype()) {
339 gen_conv_func_record_set(p_bodies
, p_mod
);
342 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
345 gen_conv_func_array_record(p_bodies
, p_mod
);
348 FATAL_ERROR("TypeConv::gen_conv_func()");
352 switch (m_from
->get_typetype()) {
356 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
359 gen_conv_func_array_record_of(p_bodies
, p_mod
);
362 FATAL_ERROR("TypeConv::gen_conv_func()");
366 switch (m_from
->get_typetype()) {
369 gen_conv_func_array_record(p_bodies
, p_mod
);
373 gen_conv_func_array_record_of(p_bodies
, p_mod
);
376 FATAL_ERROR("TypeConv::gen_conv_func()");
381 switch (m_from
->get_typetype()) {
384 gen_conv_func_record_set(p_bodies
, p_mod
);
387 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
390 FATAL_ERROR("TypeConv::gen_conv_func()");
394 switch (m_from
->get_typetype()) {
398 gen_conv_func_record_set_record_of_set_of(p_bodies
, p_mod
);
401 FATAL_ERROR("TypeConv::gen_conv_func()");
404 case Type::T_CHOICE_A
:
405 case Type::T_CHOICE_T
:
406 switch (m_from
->get_typetype()) {
407 case Type::T_CHOICE_A
:
408 case Type::T_CHOICE_T
:
409 gen_conv_func_choice_anytype(p_bodies
, p_mod
);
412 FATAL_ERROR("TypeConv::gen_conv_func()");
415 case Type::T_ANYTYPE
:
416 switch (m_from
->get_typetype()) {
417 case Type::T_ANYTYPE
:
418 gen_conv_func_choice_anytype(p_bodies
, p_mod
);
421 FATAL_ERROR("TypeConv::gen_conv_func()");
425 FATAL_ERROR("TypeConv::gen_conv_func()");
428 *p_bodies
= mputprintf(*p_bodies
, "return TRUE;\n}\n\n");
431 // Conversions between records-records and sets-sets.
432 void TypeConv::gen_conv_func_record_set(char **p_bodies
, Module
*p_mod
)
434 Type::typetype_t m_from_tt
= m_from
->get_typetype();
435 Type::typetype_t m_to_tt
= m_to
->get_typetype();
439 if (m_to_tt
!= Type::T_SEQ_A
&& m_to_tt
!= Type::T_SEQ_T
)
440 FATAL_ERROR("TypeConv::gen_conv_func_record_set()");
444 if (m_to_tt
!= Type::T_SET_A
&& m_to_tt
!= Type::T_SET_T
)
445 FATAL_ERROR("TypeConv::gen_conv_func_record_set()");
448 FATAL_ERROR("TypeConv::gen_conv_func_record_set()");
451 for (size_t i
= 0; i
< m_to
->get_nof_comps(); i
++) {
452 CompField
*cf_to
= m_to
->get_comp_byIndex(i
);
453 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
454 const Identifier
& cf_id_to
= cf_to
->get_name();
455 const Identifier
& cf_id_from
= cf_from
->get_name();
456 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
457 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
458 string cf_type_to_name
= m_is_temp
? cf_type_to
459 ->get_genname_template(p_mod
) : cf_type_to
->get_genname_value(p_mod
);
460 if (!p_mod
->needs_type_conv(cf_type_from
, cf_type_to
)) {
461 *p_bodies
= mputprintf(*p_bodies
,
462 "if (p_from_v.%s().is_bound()) p_to_v.%s() = p_from_v.%s();\n",
463 cf_id_from
.get_name().c_str(), cf_id_to
.get_name().c_str(),
464 cf_id_from
.get_name().c_str());
466 const string
& tmp_id
= p_mod
->get_temporary_id();
467 const char *tmp_id_str
= tmp_id
.c_str();
468 *p_bodies
= mputprintf(*p_bodies
,
470 "if (!%s(%s, p_from_v.%s())) return FALSE;\n"
471 "if (%s.is_bound()) p_to_v.%s() = %s;\n",
472 cf_type_to_name
.c_str(), tmp_id_str
, get_conv_func(cf_type_from
,
473 cf_type_to
, p_mod
).c_str(), tmp_id_str
, cf_id_from
.get_name()
474 .c_str(), tmp_id_str
, cf_id_to
.get_name().c_str(), tmp_id_str
);
479 // Converting arrays to record types vice versa.
480 void TypeConv::gen_conv_func_array_record(char **p_bodies
, Module
*p_mod
)
482 Type::typetype_t m_from_tt
= m_from
->get_typetype();
483 Type::typetype_t m_to_tt
= m_to
->get_typetype();
487 if (m_to_tt
!= Type::T_ARRAY
)
488 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
491 if (m_to_tt
!= Type::T_SEQ_A
&& m_to_tt
!= Type::T_SEQ_T
)
492 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
495 FATAL_ERROR("TypeConv::gen_conv_func_array_record()");
498 // From array to a structure type.
499 if (m_from_tt
== Type::T_ARRAY
) {
500 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
501 Int of_type_from_offset
= m_from
->get_dimension()->get_offset();
502 for (size_t i
= 0; i
< m_to
->get_nof_comps(); i
++) {
503 CompField
*cf_to
= m_to
->get_comp_byIndex(i
);
504 const Identifier
& cf_id_to
= cf_to
->get_name();
505 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
506 string cf_type_to_name
= m_is_temp
? cf_type_to
507 ->get_genname_template(p_mod
) : cf_type_to
508 ->get_genname_value(p_mod
);
509 if (!p_mod
->needs_type_conv(of_type_from
, cf_type_to
)) {
510 *p_bodies
= mputprintf(*p_bodies
,
511 "if (p_from_v[%lu].is_bound()) p_to_v.%s() = p_from_v[%lu];\n",
512 (long unsigned)(i
+ of_type_from_offset
),
513 cf_id_to
.get_name().c_str(),
514 (long unsigned)(i
+ of_type_from_offset
));
516 const string
& tmp_id
= p_mod
->get_temporary_id();
517 const char *tmp_id_str
= tmp_id
.c_str();
518 *p_bodies
= mputprintf(*p_bodies
,
520 "if (!%s(%s, p_from_v[%lu])) return FALSE;\n"
521 "if (%s.is_bound()) p_to_v.%s() = %s;\n",
522 cf_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
523 cf_type_to
, p_mod
).c_str(), tmp_id_str
,
524 (long unsigned)(i
+ of_type_from_offset
),
525 tmp_id_str
, cf_id_to
.get_name().c_str(), tmp_id_str
);
528 // From a structure to an array. An example 6.3.2.2 shows that
529 // OMIT_VALUES should be skipped at assignments.
531 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
532 string of_type_to_name
= m_is_temp
? of_type_to
533 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
534 *p_bodies
= mputprintf(*p_bodies
,
535 "unsigned int index = %lu;\n",
536 (long unsigned)m_to
->get_dimension()->get_offset());
537 for (size_t i
= 0; i
< m_from
->get_nof_comps(); i
++) {
538 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
539 const Identifier
& cf_id_from
= cf_from
->get_name();
540 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
541 if (!p_mod
->needs_type_conv(cf_type_from
, of_type_to
)) {
542 *p_bodies
= mputprintf(*p_bodies
,
543 "if (p_from_v.%s().is_bound()) {\n",
544 cf_id_from
.get_name().c_str());
545 if (cf_from
->get_is_optional()) {
546 *p_bodies
= mputprintf(*p_bodies
,
547 "if (!(p_from_v.%s()%s)) p_to_v[index++] "
548 "= p_from_v.%s();\n",
549 cf_id_from
.get_name().c_str(), (m_is_temp
? ".is_omit()" :
550 " == OMIT_VALUE"), cf_id_from
.get_name().c_str());
552 *p_bodies
= mputprintf(*p_bodies
,
553 "p_to_v[index++] = p_from_v.%s();\n",
554 cf_id_from
.get_name().c_str());
556 // For unbound elements.
557 *p_bodies
= mputstr(*p_bodies
, "} else index++;\n");
559 const string
& tmp_id
= p_mod
->get_temporary_id();
560 const char *tmp_id_str
= tmp_id
.c_str();
561 *p_bodies
= mputprintf(*p_bodies
,
563 "if (!%s(%s, p_from_v.%s())) return FALSE;\n"
564 "if (%s.is_bound()) p_to_v[index++] = %s;\n",
565 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(cf_type_from
,
566 of_type_to
, p_mod
).c_str(), tmp_id_str
, cf_id_from
.get_name()
567 .c_str(), tmp_id_str
, tmp_id_str
);
573 // Conversions between arrays and between record ofs and arrays.
574 void TypeConv::gen_conv_func_array_record_of(char **p_bodies
, Module
*p_mod
)
576 Type::typetype_t m_from_tt
= m_from
->get_typetype();
577 Type::typetype_t m_to_tt
= m_to
->get_typetype();
580 if (m_to_tt
== Type::T_SEQOF
)
581 FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()");
586 FATAL_ERROR("TypeConv::gen_conv_func_array_record_of()");
589 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
590 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
591 string of_type_to_name
= m_is_temp
? of_type_to
592 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
593 Int of_type_from_offset
= m_from_tt
== Type::T_ARRAY
? m_from
594 ->get_dimension()->get_offset() : 0;
595 Int of_type_to_offset
= m_to_tt
== Type::T_ARRAY
? m_to
->get_dimension()
597 // If we have two arrays the dimensions must match at this point. For
598 // record of types we need to check the current size.
599 if (m_from_tt
== Type::T_SEQOF
)
600 *p_bodies
= mputprintf(*p_bodies
,
601 "if (!p_from_v.is_bound() || p_from_v.size_of() != %lu) return FALSE;\n",
602 (long unsigned)m_to
->get_dimension()->get_size());
603 else if (m_to_tt
== Type::T_SEQOF
)
604 *p_bodies
= mputprintf(*p_bodies
, "p_to_v.set_size(%lu);\n",
605 (long unsigned)m_from
->get_dimension()->get_size());
606 for (size_t i
= 0; i
< m_from
->get_dimension()->get_size(); i
++) {
607 if (!p_mod
->needs_type_conv(of_type_from
, of_type_to
)) {
608 *p_bodies
= mputprintf(*p_bodies
,
609 "if (p_from_v[%lu].is_bound()) p_to_v[%lu] = p_from_v[%lu];\n",
610 (long unsigned)(i
+ of_type_from_offset
),
611 (long unsigned)(i
+ of_type_to_offset
),
612 (long unsigned)(i
+ of_type_from_offset
));
614 const string
& tmp_id
= p_mod
->get_temporary_id();
615 const char *tmp_id_str
= tmp_id
.c_str();
616 *p_bodies
= mputprintf(*p_bodies
,
618 "if (!%s(%s, p_from_v[%lu])) return FALSE;\n"
619 "if (%s.is_bound()) p_to_v[%lu] = %s;\n"
621 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
622 of_type_to
, p_mod
).c_str(), tmp_id_str
,
623 (long unsigned)(i
+ of_type_from_offset
), tmp_id_str
,
624 (long unsigned)(i
+ of_type_from_offset
), tmp_id_str
);
629 // Conversions from records or sets to record ofs or set ofs. Vice versa.
630 void TypeConv::gen_conv_func_record_set_record_of_set_of(char **p_bodies
, Module
*p_mod
)
632 Type::typetype_t m_from_tt
= m_from
->get_typetype();
633 Type::typetype_t m_to_tt
= m_to
->get_typetype();
637 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
)
638 // From record to record: this function was not supposed to be called
639 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
642 if (m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
643 || m_to_tt
== Type::T_SETOF
)
644 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
648 if (m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
)
649 // From set to set: this function was not supposed to be called
650 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
653 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
654 || m_to_tt
== Type::T_SEQOF
)
655 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
658 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
661 if (m_from_tt
== Type::T_SEQOF
|| m_from_tt
== Type::T_SETOF
) {
662 // From a list type to a structure.
663 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
664 || m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
) {
665 *p_bodies
= mputprintf(*p_bodies
,
666 "if (!p_from_v.is_bound() || p_from_v.size_of() != %lu) return FALSE;\n",
667 (long unsigned)m_to
->get_nof_comps());
668 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
669 for (size_t i
= 0; i
< m_to
->get_nof_comps(); i
++) {
670 CompField
*cf_to
= m_to
->get_comp_byIndex(i
);
671 const Identifier
& cf_id_to
= cf_to
->get_name();
672 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
673 string cf_type_to_name
= m_is_temp
? cf_type_to
674 ->get_genname_template(p_mod
) : cf_type_to
->get_genname_value(p_mod
);
675 if (!p_mod
->needs_type_conv(of_type_from
, cf_type_to
)) {
676 *p_bodies
= mputprintf(*p_bodies
,
677 "if (p_from_v[%lu].is_bound()) p_to_v.%s() = p_from_v[%lu];\n",
678 (long unsigned)i
, cf_id_to
.get_name().c_str(), (long unsigned)i
);
680 const string
& tmp_id
= p_mod
->get_temporary_id();
681 const char *tmp_id_str
= tmp_id
.c_str();
682 *p_bodies
= mputprintf(*p_bodies
,
684 "if (!%s(%s, p_from_v[%lu])) return FALSE;\n"
685 "if (%s.is_bound()) p_to_v.%s() = %s;\n",
686 cf_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
687 cf_type_to
, p_mod
).c_str(), tmp_id_str
, (long unsigned)i
,
688 tmp_id_str
, cf_id_to
.get_name().c_str(), tmp_id_str
);
690 // Unbound elements needs to be assigned as OMIT_VALUE.
691 if (cf_to
->get_is_optional())
692 *p_bodies
= mputprintf(*p_bodies
,
693 "else p_to_v.%s() = OMIT_VALUE;\n",
694 cf_id_to
.get_name().c_str());
696 // From a list type to a list type.
698 *p_bodies
= mputstr(*p_bodies
,
699 "p_to_v.set_size(p_from_v.size_of());\n"
700 "for (int i = 0; i < p_from_v.size_of(); i++) {\n");
701 Type
*of_type_from
= m_from
->get_ofType()->get_type_refd_last();
702 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
703 string of_type_to_name
= m_is_temp
? of_type_to
704 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
705 if (!p_mod
->needs_type_conv(of_type_from
, of_type_to
)) {
706 *p_bodies
= mputstr(*p_bodies
,
707 "if (p_from_v[i].is_bound()) p_to_v[i] = p_from_v[i];\n}\n");
709 const string
& tmp_id
= p_mod
->get_temporary_id();
710 const char *tmp_id_str
= tmp_id
.c_str();
711 *p_bodies
= mputprintf(*p_bodies
,
713 "if (!%s(%s, p_from_v[i])) return FALSE;\n"
714 "if (%s.is_bound()) p_to_v[i] = %s;\n"
716 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(of_type_from
,
717 of_type_to
, p_mod
).c_str(), tmp_id_str
, tmp_id_str
, tmp_id_str
);
721 // From a structure to a structure. Hey...
722 if (m_to_tt
== Type::T_SEQ_A
|| m_to_tt
== Type::T_SEQ_T
723 || m_to_tt
== Type::T_SET_A
|| m_to_tt
== Type::T_SET_T
) {
724 FATAL_ERROR("TypeConv::gen_conv_func_record_set_record_of_set_of()");
725 // From a structure to a list type.
727 *p_bodies
= mputprintf(*p_bodies
,
728 "p_to_v.set_size(%lu);\n",
729 (long unsigned)m_from
->get_nof_comps());
730 Type
*of_type_to
= m_to
->get_ofType()->get_type_refd_last();
731 string of_type_to_name
= m_is_temp
? of_type_to
732 ->get_genname_template(p_mod
) : of_type_to
->get_genname_value(p_mod
);
733 for (size_t i
= 0; i
< m_from
->get_nof_comps(); i
++) {
734 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
735 const Identifier
& cf_id_from
= cf_from
->get_name();
736 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
737 if (!p_mod
->needs_type_conv(cf_type_from
, of_type_to
)) {
738 *p_bodies
= mputprintf(*p_bodies
,
739 "if (p_from_v.%s().is_bound()", cf_id_from
.get_name().c_str());
740 if (cf_from
->get_is_optional()) {
741 // Additional check to avoid omitted fields.
742 *p_bodies
= mputprintf(*p_bodies
,
743 " && !(p_from_v.%s()%s)",
744 cf_id_from
.get_name().c_str(), (m_is_temp
? ".is_omit()" :
748 *p_bodies
= mputprintf(*p_bodies
,
749 ") p_to_v[%lu] = p_from_v.%s();\n", (long unsigned)i
,
750 cf_id_from
.get_name().c_str());
752 const string
& tmp_id
= p_mod
->get_temporary_id();
753 const char *tmp_id_str
= tmp_id
.c_str();
754 *p_bodies
= mputprintf(*p_bodies
,
756 "if (!%s(%s, p_from_v.%s())) return FALSE;\n"
757 "if (%s.is_bound()) p_to_v[%lu] = %s;\n",
758 of_type_to_name
.c_str(), tmp_id_str
, get_conv_func(cf_type_from
,
759 of_type_to
, p_mod
).c_str(), tmp_id_str
,
760 cf_id_from
.get_name().c_str(), tmp_id_str
, (long unsigned)i
,
768 void TypeConv::gen_conv_func_choice_anytype(char **p_bodies
, Module
*p_mod
)
770 Type::typetype_t from_tt
= m_from
->get_typetype();
771 Type::typetype_t to_tt
= m_to
->get_typetype();
773 case Type::T_CHOICE_A
:
774 case Type::T_CHOICE_T
:
775 if (to_tt
!= Type::T_CHOICE_A
&& to_tt
!= Type::T_CHOICE_T
)
776 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
778 case Type::T_ANYTYPE
:
779 if (to_tt
!= Type::T_ANYTYPE
)
780 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
783 FATAL_ERROR("TypeConv::gen_conv_func_choice_anytype()");
785 // Anytype field accessors always have an "AT_" prefix.
786 const char *anytype_prefix
= from_tt
== Type::T_ANYTYPE
? "AT_" : "";
787 *p_bodies
= mputprintf(*p_bodies
,
788 "if (!p_from_v.is_bound()) return FALSE;\n"
789 "switch (p_from_v.get_selection()) {\n");
790 for (size_t i
= 0; i
< m_from
->get_nof_comps(); i
++) {
791 CompField
*cf_from
= m_from
->get_comp_byIndex(i
);
792 Type
*cf_type_from
= cf_from
->get_type()->get_type_refd_last();
793 const Identifier
& cf_id_from
= cf_from
->get_name();
794 for (size_t j
= 0; j
< m_to
->get_nof_comps(); j
++) {
795 CompField
*cf_to
= m_to
->get_comp_byIndex(j
);
796 Type
*cf_type_to
= cf_to
->get_type()->get_type_refd_last();
797 const Identifier
& cf_id_to
= cf_to
->get_name();
798 // We have at most one field with the same name, break the inner loop
799 // if found. If the two different types have the same field name, but
800 // they don't have a conversion function (e.g. an integer-boolean
801 // pair) don't generate the assignment. It's only an union specific
802 // problem, since they're compatible if they have at least one
803 // "compatible" field.
804 if (cf_id_from
.get_name() == cf_id_to
.get_name()) {
805 string from_name
= m_is_temp
? m_from
->get_genname_template(p_mod
)
806 : m_from
->get_genname_value(p_mod
);
807 string from_name_sel
= m_from
->get_genname_value(p_mod
);
808 if (p_mod
->needs_type_conv(cf_type_from
, cf_type_to
)) {
809 const string
& tmp_id
= p_mod
->get_temporary_id();
810 const char *tmp_id_str
= tmp_id
.c_str();
811 *p_bodies
= mputprintf(*p_bodies
,
812 "case %s::ALT_%s: {\n"
814 "if (!%s(%s, p_from_v.%s%s())) return FALSE;\n"
815 "if (%s.is_bound()) p_to_v = %s;\n"
817 from_name_sel
.c_str(), cf_id_from
.get_name().c_str(),
818 from_name
.c_str(), tmp_id_str
,
819 get_conv_func(cf_type_from
, cf_type_to
, p_mod
).c_str(),
820 tmp_id_str
, anytype_prefix
, cf_id_from
.get_name().c_str(),
821 tmp_id_str
, tmp_id_str
);
822 } else if (cf_type_from
->is_compatible(cf_type_to
, NULL
)) { // E.g. basic types.
823 // The same module + field name is required for anytype field
824 // types. Only for structured types.
825 bool both_structured
= cf_type_from
->is_structured_type()
826 && cf_type_to
->is_structured_type();
827 if (from_tt
== Type::T_ANYTYPE
&& both_structured
828 && cf_type_from
->get_my_scope()->get_scope_mod() !=
829 cf_type_to
->get_my_scope()->get_scope_mod())
831 *p_bodies
= mputprintf(*p_bodies
,
833 "if (p_from_v.%s%s().is_bound()) "
834 "p_to_v.%s%s() = p_from_v.%s%s();\n"
836 from_name_sel
.c_str(), cf_id_from
.get_name().c_str(),
837 anytype_prefix
, cf_id_from
.get_name().c_str(), anytype_prefix
,
838 cf_id_to
.get_name().c_str(), anytype_prefix
,
839 cf_id_from
.get_name().c_str());
845 *p_bodies
= mputprintf(*p_bodies
,
851 TypeChain::TypeChain() : m_first_double(-1) { }
853 TypeChain::~TypeChain()
855 while (!m_marked_states
.empty()) delete m_marked_states
.pop();
856 m_marked_states
.clear(); // Does nothing.
857 m_chain
.clear(); // (Type *)s should stay.
860 void TypeChain::add(Type
*p_type
)
862 if (m_first_double
== -1) {
863 for (size_t i
= 0; i
< m_chain
.size() && m_first_double
== -1; i
++)
864 if (m_chain
[i
] == p_type
)
865 m_first_double
= m_chain
.size();
870 void TypeChain::mark_state()
872 // FIXME: Dynamically allocated integers used only for bookkeeping.
873 m_marked_states
.push(new int(m_chain
.size()));
876 void TypeChain::previous_state()
878 if (m_marked_states
.empty()) FATAL_ERROR("TypeChain::previous_state()");
879 int state
= *m_marked_states
.top();
880 for (size_t i
= m_chain
.size() - 1; (int)i
>= state
; i
--)
881 m_chain
.replace(i
, 1);
882 delete m_marked_states
.pop();
883 if ((int)m_chain
.size() <= m_first_double
) m_first_double
= -1;
886 } /* namespace Common */