1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 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 "../../common/dbgnew.hh"
9 #include "AST_ttcn3.hh"
10 #include "../Identifier.hh"
11 #include "../CompilerError.hh"
12 #include "../Setting.hh"
14 #include "../CompField.hh"
15 #include "../CompType.hh"
16 #include "../TypeCompat.hh"
17 #include "../Valuestuff.hh"
18 #include "../Value.hh"
19 #include "Ttcnstuff.hh"
20 #include "TtcnTemplate.hh"
21 #include "Templatestuff.hh"
22 #include "ArrayDimensions.hh"
25 #include "Statement.hh"
27 #include "Attributes.hh"
28 #include "PatternString.hh"
29 #include "../../common/version_internal.h"
30 #include "../CodeGenHelper.hh"
31 #include "../../common/JSON_Tokenizer.hh"
34 // implemented in coding_attrib_p.y
35 extern Ttcn::ExtensionAttributes
* parse_extattributes(
36 Ttcn::WithAttribPath
*w_attrib_path
);
38 // implemented in compiler.y
39 extern Ttcn::ErroneousAttributeSpec
* ttcn3_parse_erroneous_attr_spec_string(
40 const char* p_str
, const Common::Location
& str_loc
);
43 extern void init_coding_attrib_lex(const Ttcn::AttributeSpec
& attrib
);
44 extern int coding_attrib_parse();
45 extern void cleanup_coding_attrib_lex();
46 extern Ttcn::ExtensionAttributes
*extatrs
;
48 /** Create a field name in the anytype
50 * The output of this function will be used to create an identifier
51 * to be used as the field name in the anytype.
52 * The type_name may be a built-in type (e.g. "integer") or a user-defined
55 * If the name has multiple components (a fullname?), it keeps just the last
56 * component without any dots. *
57 * Also, the space in "universal charstring" needs to be replaced
58 * with an underscore to make it an identifier.
60 * Note: Prefixing with "AT_" is not done here, but in defUnionClass().
62 * @param type_name string
63 * @return string to be used as the identifier.
65 string
anytype_field(const string
& type_name
)
67 string
retval(type_name
);
69 // keep just the last part of the name
70 // TODO check if there's a way to get just the last component (note that fetching the string is done outside of this function)
71 size_t dot
= retval
.rfind('.');
72 if (dot
>= retval
.size()) dot
= 0;
74 retval
.replace(0, dot
, "");
79 extern Common::Modules
*modules
; // in main.cc
82 static const string
_T_("_T_");
87 using namespace Common
;
89 // =================================
90 // ===== FieldOrArrayRef
91 // =================================
93 FieldOrArrayRef::FieldOrArrayRef(const FieldOrArrayRef
& p
)
94 : Node(p
), Location(p
), ref_type(p
.ref_type
)
98 u
.id
= p
.u
.id
->clone();
101 u
.arp
= p
.u
.arp
->clone();
104 FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
108 FieldOrArrayRef::FieldOrArrayRef(Identifier
*p_id
)
109 : Node(), Location(), ref_type(FIELD_REF
)
111 if (!p_id
) FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
115 FieldOrArrayRef::FieldOrArrayRef(Value
*p_arp
)
116 : Node(), Location(), ref_type(ARRAY_REF
)
118 if (!p_arp
) FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
122 FieldOrArrayRef::~FieldOrArrayRef()
132 FATAL_ERROR("FieldOrArrayRef::~FieldOrArrayRef()");
136 FieldOrArrayRef
*FieldOrArrayRef::clone() const
138 return new FieldOrArrayRef(*this);
141 void FieldOrArrayRef::set_fullname(const string
& p_fullname
)
143 Node::set_fullname(p_fullname
);
144 if (ref_type
== ARRAY_REF
)
145 u
.arp
->set_fullname(p_fullname
+ ".<array_index>");
148 void FieldOrArrayRef::set_my_scope(Scope
*p_scope
)
150 if (ref_type
== ARRAY_REF
) u
.arp
->set_my_scope(p_scope
);
153 const Identifier
* FieldOrArrayRef::get_id() const
155 if (ref_type
!= FIELD_REF
) FATAL_ERROR("FieldOrArrayRef::get_id()");
159 Value
*FieldOrArrayRef::get_val() const
161 if (ref_type
!= ARRAY_REF
) FATAL_ERROR("FieldOrArrayRef::get_val()");
165 void FieldOrArrayRef::append_stringRepr(string
& str
) const
170 str
+= u
.id
->get_dispname();
174 str
+= u
.arp
->get_stringRepr();
178 str
+= "<unknown sub-reference>";
182 void FieldOrArrayRef::set_field_name_to_lowercase()
184 if (ref_type
!= FIELD_REF
) FATAL_ERROR("FieldOrArrayRef::set_field_name_to_lowercase()");
185 string new_name
= u
.id
->get_name();
186 if (isupper(new_name
[0])) {
187 new_name
[0] = tolower(new_name
[0]);
188 if (new_name
[new_name
.size() - 1] == '_') {
189 // an underscore is inserted at the end of the field name if it's
190 // a basic type's name (since it would conflict with the class generated
192 // remove the underscore, it won't conflict with anything if its name
193 // starts with a lowercase letter
194 new_name
.replace(new_name
.size() - 1, 1, "");
197 u
.id
= new Identifier(Identifier::ID_NAME
, new_name
);
201 // =================================
202 // ===== FieldOrArrayRefs
203 // =================================
205 FieldOrArrayRefs::FieldOrArrayRefs(const FieldOrArrayRefs
& p
)
206 : Node(p
), refs_str_element(false)
208 for (size_t i
= 0; i
< p
.refs
.size(); i
++) refs
.add(p
.refs
[i
]->clone());
211 FieldOrArrayRefs::~FieldOrArrayRefs()
213 for (size_t i
= 0; i
< refs
.size(); i
++) delete refs
[i
];
217 FieldOrArrayRefs
*FieldOrArrayRefs::clone() const
219 return new FieldOrArrayRefs(*this);
222 void FieldOrArrayRefs::set_fullname(const string
& p_fullname
)
224 Node::set_fullname(p_fullname
);
225 for (size_t i
= 0; i
< refs
.size(); i
++)
226 refs
[i
]->set_fullname(p_fullname
+
227 ".<sub_reference" + Int2string(i
+ 1) + ">");
230 void FieldOrArrayRefs::set_my_scope(Scope
*p_scope
)
232 for (size_t i
= 0; i
< refs
.size(); i
++) refs
[i
]->set_my_scope(p_scope
);
235 bool FieldOrArrayRefs::has_unfoldable_index() const
237 for (size_t i
= 0; i
< refs
.size(); i
++) {
238 FieldOrArrayRef
*ref
= refs
[i
];
239 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
) {
240 Value
*v
= ref
->get_val();
241 v
->set_lowerid_to_ref();
242 if (v
->is_unfoldable()) return true;
248 void FieldOrArrayRefs::remove_refs(size_t n
)
250 for (size_t i
= 0; i
< n
; i
++) delete refs
[i
];
251 refs
.replace(0, n
, NULL
);
252 set_fullname(get_fullname());
255 /* remove_last_field is used when unfolding references for
256 ischosen and ispresent function operands.
257 In this case it is NOT sure the last field exists.
258 Calling remove_last_field previously
259 will avoid getting the "variable...Has no member called..." error message.
260 The last field component will be checked as a separate step.
261 Warning: the removed Identifier has to be deleted later */
263 Identifier
* FieldOrArrayRefs::remove_last_field()
265 if (refs
.size() == 0) return 0;
266 size_t last_elem_ind
= refs
.size() - 1;
267 FieldOrArrayRef
* last_elem
= refs
[last_elem_ind
];
268 if (last_elem
->get_type() == FieldOrArrayRef::FIELD_REF
) {
269 Identifier
*ret_val
= last_elem
->get_id()->clone();
271 refs
.replace(last_elem_ind
, 1, NULL
);
276 void FieldOrArrayRefs::generate_code(expression_struct
*expr
,
277 Common::Assignment
*ass
, size_t nof_subrefs
/* = UINT_MAX*/)
280 bool is_template
= false;
281 switch (ass
->get_asstype()) {
282 case Common::Assignment::A_CONST
: // a Def_Const
283 case Common::Assignment::A_EXT_CONST
: // a Def_ExtConst
284 case Common::Assignment::A_MODULEPAR
: // a Def_Modulepar
285 case Common::Assignment::A_VAR
: // a Def_Var
286 case Common::Assignment::A_FUNCTION_RVAL
: // a Def_Function
287 case Common::Assignment::A_EXT_FUNCTION_RVAL
: // a Def_ExtFunction
288 case Common::Assignment::A_PAR_VAL_IN
: // a FormalPar
289 case Common::Assignment::A_PAR_VAL_OUT
: // a FormalPar
290 case Common::Assignment::A_PAR_VAL_INOUT
: // a FormalPar
291 // The type is important since the referred entities are value objects.
292 type
= ass
->get_Type();
294 case Common::Assignment::A_MODULEPAR_TEMP
: // a Def_Modulepar_Template
295 case Common::Assignment::A_TEMPLATE
: // a Def_Template
296 case Common::Assignment::A_VAR_TEMPLATE
: // a Def_Var_Template
297 case Common::Assignment::A_PAR_TEMPL_IN
: // a FormalPar
298 case Common::Assignment::A_PAR_TEMPL_OUT
: // a FormalPar
299 case Common::Assignment::A_PAR_TEMPL_INOUT
: // a FormalPar
300 // The type is semi-important because fields of anytype templates
302 type
= ass
->get_Type();
305 case Common::Assignment::A_TIMER
: // a Def_Timer
306 case Common::Assignment::A_PORT
: // a Def_Port
307 case Common::Assignment::A_FUNCTION_RTEMP
: // a Def_Function
308 case Common::Assignment::A_EXT_FUNCTION_RTEMP
: // a Def_ExtFunction
309 case Common::Assignment::A_PAR_TIMER
: // a FormalPar
310 case Common::Assignment::A_PAR_PORT
: // a FormalPar
311 // The type is not relevant (i.e. the optional fields do not require
312 // special handling).
316 // Reference to other definitions cannot occur during code generation.
317 FATAL_ERROR("FieldOrArrayRefs::generate_code()");
320 size_t n_refs
= (nof_subrefs
!= UINT_MAX
) ? nof_subrefs
: refs
.size();
321 for (size_t i
= 0; i
< n_refs
; i
++) {
322 if (type
) type
= type
->get_type_refd_last();
323 // type changes inside the loop; need to recompute "last" every time.
324 FieldOrArrayRef
*ref
= refs
[i
];
325 if (ref
->get_type() == FieldOrArrayRef::FIELD_REF
) {
326 // Write a call to the field accessor method.
327 // Fields of the anytype get a special prefix; see also:
328 // Template::generate_code_init_se, TypeConv::gen_conv_func_choice_anytype,
329 // defUnionClass and defUnionTemplate.
330 const Identifier
& id
= *ref
->get_id();
331 expr
->expr
= mputprintf(expr
->expr
, ".%s%s()",
332 ((type
!=0 && type
->get_typetype()==Type::T_ANYTYPE
) ? "AT_" : ""),
333 id
.get_name().c_str());
335 CompField
*cf
= type
->get_comp_byName(id
);
336 // If the field is optional, the return type of the accessor is an
337 // OPTIONAL<T>. Write a call to OPTIONAL<T>::operator(),
338 // which "reaches into" the OPTIONAL to get the contained type T.
339 // Don't do this at the end of the reference chain.
340 // Accessor methods for a foo_template return a bar_template
341 // and OPTIONAL<> is not involved, hence no "()".
342 if (!is_template
&& i
< n_refs
- 1 && cf
->get_is_optional())
343 expr
->expr
= mputstr(expr
->expr
, "()");
344 // Follow the field type.
345 type
= cf
->get_type();
348 // Generate code for array reference.
349 expr
->expr
= mputc(expr
->expr
, '[');
350 ref
->get_val()->generate_code_expr(expr
);
351 expr
->expr
= mputc(expr
->expr
, ']');
353 // Follow the embedded type.
354 switch (type
->get_typetype()) {
358 type
= type
->get_ofType();
361 // The index points to a string element.
362 // There are no further sub-references.
366 } // if (ref->get_type)
370 void FieldOrArrayRefs::append_stringRepr(string
& str
) const
372 for (size_t i
= 0; i
< refs
.size(); i
++) refs
[i
]->append_stringRepr(str
);
375 // =================================
377 // =================================
379 Ref_base::Ref_base(const Ref_base
& p
)
380 : Ref_simple(p
), subrefs(p
.subrefs
)
382 modid
= p
.modid
? p
.modid
->clone() : 0;
383 id
= p
.id
? p
.id
->clone() : 0;
384 params_checked
= p
.is_erroneous
;
387 Ref_base::Ref_base(Identifier
*p_modid
, Identifier
*p_id
)
388 : Ref_simple(), modid(p_modid
), id(p_id
), params_checked(false)
389 , usedInIsbound(false)
392 FATAL_ERROR("NULL parameter: Ttcn::Ref_base::Ref_base()");
395 Ref_base::~Ref_base()
401 void Ref_base::set_fullname(const string
& p_fullname
)
403 Ref_simple::set_fullname(p_fullname
);
404 subrefs
.set_fullname(p_fullname
);
407 void Ref_base::set_my_scope(Scope
*p_scope
)
409 Ref_simple::set_my_scope(p_scope
);
410 subrefs
.set_my_scope(p_scope
);
413 /* returns the referenced variable's base type or value */
414 Setting
* Ref_base::get_refd_setting()
416 Common::Assignment
*ass
= get_refd_assignment();
417 if (ass
) return ass
->get_Setting();
421 FieldOrArrayRefs
*Ref_base::get_subrefs()
423 if (!id
) get_modid();
424 if (subrefs
.get_nof_refs() == 0) return 0;
425 else return &subrefs
;
428 bool Ref_base::has_single_expr()
430 Common::Assignment
*ass
= get_refd_assignment();
431 if (!ass
) FATAL_ERROR("Ref_base::has_single_expr()");
432 for (size_t i
= 0; i
< subrefs
.get_nof_refs(); i
++) {
433 FieldOrArrayRef
*ref
= subrefs
.get_ref(i
);
434 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
&&
435 !ref
->get_val()->has_single_expr()) return false;
440 void Ref_base::set_code_section(
441 GovernedSimple::code_section_t p_code_section
)
443 for (size_t i
= 0; i
< subrefs
.get_nof_refs(); i
++) {
444 FieldOrArrayRef
*ref
= subrefs
.get_ref(i
);
445 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
)
446 ref
->get_val()->set_code_section(p_code_section
);
450 void Ref_base::generate_code_const_ref(expression_struct_t */
*expr*/
)
452 FATAL_ERROR("Ref_base::generate_code_const_ref()");
455 // =================================
457 // =================================
459 Reference::Reference(Identifier
*p_id
)
460 : Ref_base(), parlist(0)
462 subrefs
.add(new FieldOrArrayRef(p_id
));
465 Reference::~Reference()
473 * Common::PortTypeBody::PortTypeBody
475 * Common::TypeMappingTarget::TypeMappingTarget
476 * Common::PatternString::ps_elem_t::chk_ref */
477 Reference
*Reference::clone() const
479 return new Reference(*this);
482 string
Reference::get_dispname()
487 ret_val
+= modid
->get_dispname();
490 ret_val
+= id
->get_dispname();
491 subrefs
.append_stringRepr(ret_val
);
493 subrefs
.append_stringRepr(ret_val
);
494 // cut the leading dot
495 if (!ret_val
.empty() && ret_val
[0] == '.')
496 ret_val
.replace(0, 1, "");
501 Common::Assignment
* Reference::get_refd_assignment(bool check_parlist
)
503 Common::Assignment
*ass
= Ref_base::get_refd_assignment(check_parlist
);
504 // In fact calls Ref_simple::get_refd_assignment
505 if (ass
&& check_parlist
&& !params_checked
) {
506 params_checked
= true;
507 FormalParList
*fplist
= ass
->get_FormalParList();
509 if (fplist
->has_only_default_values()
510 && Common::Assignment::A_TEMPLATE
== ass
->get_asstype()) {
511 Ttcn::ParsedActualParameters params
;
512 Error_Context
cntxt(¶ms
, "In actual parameter list of %s",
513 ass
->get_description().c_str());
514 parlist
= new ActualParList();
515 is_erroneous
= fplist
->fold_named_and_chk(¶ms
, parlist
);
516 parlist
->set_fullname(get_fullname());
517 parlist
->set_my_scope(my_scope
);
519 error("Reference to parameterized definition `%s' without "
520 "actual parameter list", ass
->get_id().get_dispname().c_str());
527 const Identifier
* Reference::get_modid()
529 if (!id
) detect_modid();
533 const Identifier
* Reference::get_id()
535 if (!id
) detect_modid();
539 Type
*Reference::chk_variable_ref()
541 Common::Assignment
*t_ass
= get_refd_assignment();
542 if (!t_ass
) return 0;
543 switch (t_ass
->get_asstype()) {
544 case Common::Assignment::A_PAR_VAL_IN
:
545 t_ass
->use_as_lvalue(*this);
547 case Common::Assignment::A_VAR
:
548 case Common::Assignment::A_PAR_VAL_OUT
:
549 case Common::Assignment::A_PAR_VAL_INOUT
:
552 error("Reference to a variable or value parameter was "
553 "expected instead of %s", t_ass
->get_description().c_str());
556 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
557 Type
*ret_val
= t_ass
->get_Type()->get_field_type(t_subrefs
,
558 Type::EXPECTED_DYNAMIC_VALUE
);
559 if (ret_val
&& t_subrefs
&& t_subrefs
->refers_to_string_element()) {
560 error("Reference to a string element of type `%s' cannot be used in "
561 "this context", ret_val
->get_typename().c_str());
566 Type
*Reference::chk_comptype_ref()
568 Common::Assignment
*ass
= get_refd_assignment();
570 if (ass
->get_asstype() == Common::Assignment::A_TYPE
) {
571 Type
*t
= ass
->get_Type()->get_type_refd_last();
572 switch (t
->get_typetype()) {
576 case Type::T_COMPONENT
:
579 error("Reference `%s' does not refer to a component type",
580 get_dispname().c_str());
583 error("Reference `%s' does not refer to a type",
584 get_dispname().c_str());
590 bool Reference::has_single_expr()
592 if (!Ref_base::has_single_expr()) {
595 if (parlist
!= NULL
) {
596 for (size_t i
= 0; i
< parlist
->get_nof_pars(); i
++) {
597 if (!parlist
->get_par(i
)->has_single_expr()) {
605 void Reference::refd_param_usage_found()
607 Common::Assignment
*ass
= get_refd_assignment();
608 if (!ass
) FATAL_ERROR("Reference::refd_param_usage_found()");
609 switch (ass
->get_asstype()) {
610 case Common::Assignment::A_PAR_VAL_OUT
:
611 case Common::Assignment::A_PAR_TEMPL_OUT
:
612 case Common::Assignment::A_PAR_VAL
:
613 case Common::Assignment::A_PAR_VAL_IN
:
614 case Common::Assignment::A_PAR_VAL_INOUT
:
615 case Common::Assignment::A_PAR_TEMPL_IN
:
616 case Common::Assignment::A_PAR_TEMPL_INOUT
:
617 case Common::Assignment::A_PAR_PORT
:
618 case Common::Assignment::A_PAR_TIMER
: {
619 FormalPar
*fpar
= dynamic_cast<FormalPar
*>(ass
);
620 if (!fpar
) FATAL_ERROR("Reference::refd_param_usage_found()");
621 fpar
->set_usage_found();
628 void Reference::generate_code(expression_struct_t
*expr
)
630 refd_param_usage_found();
631 Common::Assignment
*ass
= get_refd_assignment();
632 if (!ass
) FATAL_ERROR("Reference::generate_code()");
634 // reference without parameters to a template that has only default formal parameters.
635 // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
636 expr
->expr
= mputprintf(expr
->expr
, "%s(",
637 ass
->get_genname_from_scope(my_scope
).c_str());
638 parlist
->generate_code_alias(expr
, ass
->get_FormalParList(),
639 ass
->get_RunsOnType(), false);
640 expr
->expr
= mputc(expr
->expr
, ')');
642 expr
->expr
= mputstr(expr
->expr
,
643 LazyParamData::in_lazy() ?
644 LazyParamData::add_ref_genname(ass
, my_scope
).c_str() :
645 ass
->get_genname_from_scope(my_scope
).c_str());
647 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
650 void Reference::generate_code_const_ref(expression_struct_t
*expr
)
652 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
653 if (!t_subrefs
|| t_subrefs
->get_nof_refs() == 0) {
658 refd_param_usage_found();
659 Common::Assignment
*ass
= get_refd_assignment();
660 if (!ass
) FATAL_ERROR("Reference::generate_code_const_ref()");
663 switch (ass
->get_asstype()) {
664 case Common::Assignment::A_MODULEPAR
:
665 case Common::Assignment::A_VAR
:
666 case Common::Assignment::A_FUNCTION_RVAL
:
667 case Common::Assignment::A_EXT_FUNCTION_RVAL
:
668 case Common::Assignment::A_PAR_VAL_IN
:
669 case Common::Assignment::A_PAR_VAL_OUT
:
670 case Common::Assignment::A_PAR_VAL_INOUT
: {
673 case Common::Assignment::A_MODULEPAR_TEMP
:
674 case Common::Assignment::A_TEMPLATE
:
675 case Common::Assignment::A_VAR_TEMPLATE
:
676 case Common::Assignment::A_PAR_TEMPL_IN
:
677 case Common::Assignment::A_PAR_TEMPL_OUT
:
678 case Common::Assignment::A_PAR_TEMPL_INOUT
: {
681 case Common::Assignment::A_CONST
:
682 case Common::Assignment::A_EXT_CONST
:
688 Type
*refd_gov
= ass
->get_Type();
690 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
691 refd_gov
->get_genname_template(get_my_scope()).c_str() );
693 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
694 refd_gov
->get_genname_value(get_my_scope()).c_str());
697 // reference without parameters to a template that has only default formal parameters.
698 // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
699 expr
->expr
= mputprintf(expr
->expr
, "%s(",
700 ass
->get_genname_from_scope(my_scope
).c_str());
701 parlist
->generate_code_alias(expr
, ass
->get_FormalParList(),
702 ass
->get_RunsOnType(), false);
703 expr
->expr
= mputc(expr
->expr
, ')');
705 expr
->expr
= mputstr(expr
->expr
,
706 LazyParamData::in_lazy() ?
707 LazyParamData::add_ref_genname(ass
, my_scope
).c_str() :
708 ass
->get_genname_from_scope(my_scope
).c_str());
710 expr
->expr
= mputstr(expr
->expr
, ")");
712 if (t_subrefs
&& t_subrefs
->get_nof_refs() > 0)
713 t_subrefs
->generate_code(expr
, ass
);
716 void Reference::generate_code_portref(expression_struct_t
*expr
,
719 refd_param_usage_found();
720 Common::Assignment
*ass
= get_refd_assignment();
721 if (!ass
) FATAL_ERROR("Reference::generate_code_portref()");
722 expr
->expr
= mputstr(expr
->expr
,
723 ass
->get_genname_from_scope(p_scope
).c_str());
724 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
728 void Reference::generate_code_ispresentbound(expression_struct_t
*expr
,
729 bool is_template
, const bool isbound
)
731 refd_param_usage_found();
732 Common::Assignment
*ass
= get_refd_assignment();
733 const string
& ass_id
= ass
->get_genname_from_scope(my_scope
);
734 const char *ass_id_str
= ass_id
.c_str();
736 if (subrefs
.get_nof_refs() > 0) {
737 const string
& tmp_generalid
= my_scope
->get_scope_mod_gen()
738 ->get_temporary_id();
739 const char *tmp_generalid_str
= tmp_generalid
.c_str();
741 expression_struct isbound_expr
;
742 Code::init_expr(&isbound_expr
);
743 isbound_expr
.preamble
= mputprintf(isbound_expr
.preamble
,
744 "boolean %s = %s.is_bound();\n", tmp_generalid_str
,
746 ass
->get_Type()->generate_code_ispresentbound(&isbound_expr
, &subrefs
, my_scope
->get_scope_mod_gen(),
747 tmp_generalid
, ass_id
, is_template
, isbound
);
749 expr
->preamble
= mputstr(expr
->preamble
, isbound_expr
.preamble
);
750 expr
->preamble
= mputstr(expr
->preamble
, isbound_expr
.expr
);
751 Code::free_expr(&isbound_expr
);
753 expr
->expr
= mputprintf(expr
->expr
, "%s", tmp_generalid_str
);
755 expr
->expr
= mputprintf(expr
->expr
, "%s.%s(%s)", ass_id_str
,
756 isbound
? "is_bound":"is_present",
757 (!isbound
&& is_template
&& omit_in_value_list
) ? "TRUE" : "");
761 void Reference::detect_modid()
763 // do nothing if detection is already performed
765 // the first element of subrefs must be an <id>
766 const Identifier
*first_id
= subrefs
.get_ref(0)->get_id(), *second_id
= 0;
767 if (subrefs
.get_nof_refs() > 1) {
768 FieldOrArrayRef
*second_ref
= subrefs
.get_ref(1);
769 if (second_ref
->get_type() == FieldOrArrayRef::FIELD_REF
) {
770 // the reference begins with <id>.<id> (most complicated case)
771 // there are 3 possible situations:
772 // 1. first_id points to a local definition (this has the priority)
773 // modid: 0, id: first_id
774 // 2. first_id points to an imported module (trivial case)
775 // modid: first_id, id: second_id
776 // 3. none of the above (first_id might be an imported symbol)
777 // modid: 0, id: first_id
778 // Note: Rule 1 has the priority because it can be overridden using
779 // the notation <id>.objid { ... }.<id> (modid and id are set in the
780 // constructor), but there is no work-around in the reverse way.
781 if (!my_scope
->has_ass_withId(*first_id
)
782 && my_scope
->is_valid_moduleid(*first_id
)) {
783 // rule 1 is not fulfilled, but rule 2 is fulfilled
784 second_id
= second_ref
->get_id();
786 } // else: the reference begins with <id>[<arrayref>] -> there is no modid
787 } // else: the reference consists of a single <id> -> there is no modid
789 modid
= first_id
->clone();
790 id
= second_id
->clone();
791 subrefs
.remove_refs(2);
794 id
= first_id
->clone();
795 subrefs
.remove_refs(1);
799 // =================================
801 // =================================
803 Ref_pard::Ref_pard(const Ref_pard
& p
)
804 : Ref_base(p
), parlist(p
.parlist
), expr_cache(0)
806 params
= p
.params
? p
.params
->clone() : 0;
809 Ref_pard::Ref_pard(Identifier
*p_modid
, Identifier
*p_id
,
810 ParsedActualParameters
*p_params
)
811 : Ref_base(p_modid
, p_id
), parlist(), params(p_params
), expr_cache(0)
814 FATAL_ERROR("Ttcn::Ref_pard::Ref_pard(): NULL parameter");
817 Ref_pard::~Ref_pard()
823 Ref_pard
*Ref_pard::clone() const
825 return new Ref_pard(*this);
828 void Ref_pard::set_fullname(const string
& p_fullname
)
830 Ref_base::set_fullname(p_fullname
);
831 parlist
.set_fullname(p_fullname
);
832 if (params
) params
->set_fullname(p_fullname
);
835 void Ref_pard::set_my_scope(Scope
*p_scope
)
837 Ref_base::set_my_scope(p_scope
);
838 parlist
.set_my_scope(p_scope
);
839 if (params
) params
->set_my_scope(p_scope
);
842 string
Ref_pard::get_dispname()
844 if (is_erroneous
) return string("erroneous");
847 ret_val
+= modid
->get_dispname();
850 ret_val
+= id
->get_dispname();
852 if (params_checked
) {
853 // used after semantic analysis
854 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++) {
855 if (i
> 0) ret_val
+= ", ";
856 parlist
.get_par(i
)->append_stringRepr(ret_val
);
859 // used before semantic analysis
860 for (size_t i
= 0; i
< params
->get_nof_tis(); i
++) {
861 if (i
> 0) ret_val
+= ", ";
862 params
->get_ti_byIndex(i
)->append_stringRepr(ret_val
);
866 subrefs
.append_stringRepr(ret_val
);
870 Common::Assignment
* Ref_pard::get_refd_assignment(bool check_parlist
)
872 Common::Assignment
*ass
= Ref_base::get_refd_assignment(check_parlist
);
873 if (ass
&& check_parlist
&& !params_checked
) {
874 params_checked
= true;
875 FormalParList
*fplist
= ass
->get_FormalParList();
877 Error_Context
cntxt(params
, "In actual parameter list of %s",
878 ass
->get_description().c_str());
879 is_erroneous
= fplist
->fold_named_and_chk(params
, &parlist
);
880 parlist
.set_fullname(get_fullname());
881 parlist
.set_my_scope(my_scope
);
882 // the parsed parameter list is no longer needed
886 params
->error("The referenced %s cannot have actual parameters",
887 ass
->get_description().c_str());
893 const Identifier
* Ref_pard::get_modid()
898 const Identifier
* Ref_pard::get_id()
903 ActualParList
*Ref_pard::get_parlist()
905 if (!params_checked
) FATAL_ERROR("Ref_pard::get_parlist()");
909 bool Ref_pard::chk_activate_argument()
911 Common::Assignment
*t_ass
= get_refd_assignment();
912 if (!t_ass
) return false;
913 if (t_ass
->get_asstype() != Common::Assignment::A_ALTSTEP
) {
914 error("Reference to an altstep was expected in the argument instead of "
915 "%s", t_ass
->get_description().c_str());
918 my_scope
->chk_runs_on_clause(t_ass
, *this, "activate");
919 // the altstep reference cannot have sub-references
920 if (get_subrefs()) FATAL_ERROR("Ref_pard::chk_activate_argument()");
921 FormalParList
*fp_list
= t_ass
->get_FormalParList();
922 // the altstep must have formal parameter list
923 if (!fp_list
) FATAL_ERROR("Ref_pard::chk_activate_argument()");
924 return fp_list
->chk_activate_argument(&parlist
,
925 t_ass
->get_description().c_str());
928 bool Ref_pard::has_single_expr()
930 if (!Ref_base::has_single_expr()) return false;
931 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++)
932 if (!parlist
.get_par(i
)->has_single_expr()) return false;
933 // if any formal parameter has lazy evaluation
934 Common::Assignment
*ass
= get_refd_assignment();
936 const FormalParList
*fplist
= ass
->get_FormalParList();
938 size_t num_formal
= fplist
->get_nof_fps();
939 for (size_t i
=0; i
<num_formal
; ++i
) {
940 const FormalPar
*fp
= fplist
->get_fp_byIndex(i
);
941 if (fp
->get_lazy_eval()) return false;
948 void Ref_pard::set_code_section(
949 GovernedSimple::code_section_t p_code_section
)
951 Ref_base::set_code_section(p_code_section
);
952 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++)
953 parlist
.get_par(i
)->set_code_section(p_code_section
);
956 void Ref_pard::generate_code(expression_struct_t
*expr
)
958 Common::Assignment
*ass
= get_refd_assignment();
959 // C++ function reference with actual parameter list
960 expr
->expr
= mputprintf(expr
->expr
, "%s(",
961 ass
->get_genname_from_scope(my_scope
).c_str());
962 parlist
.generate_code_alias(expr
, ass
->get_FormalParList(),
963 ass
->get_RunsOnType(),false);
964 expr
->expr
= mputc(expr
->expr
, ')');
966 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
969 void Ref_pard::generate_code_cached(expression_struct_t
*expr
)
972 expr
->expr
= mputstr(expr
->expr
, expr_cache
);
976 expr_cache
= mputstr(expr_cache
, expr
->expr
);
980 void Ref_pard::generate_code_const_ref(expression_struct_t
*expr
)
982 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
983 if (!t_subrefs
|| t_subrefs
->get_nof_refs() == 0) {
988 Common::Assignment
*ass
= get_refd_assignment();
989 if (!ass
) FATAL_ERROR("Ref_pard::generate_code_const_ref()");
992 switch (ass
->get_asstype()) {
993 case Common::Assignment::A_TEMPLATE
:
994 if (NULL
== ass
->get_FormalParList()) {
995 // not a parameterized template
1000 case Common::Assignment::A_CONST
:
1001 case Common::Assignment::A_EXT_CONST
:
1002 case Common::Assignment::A_ALTSTEP
:
1003 case Common::Assignment::A_TESTCASE
:
1004 case Common::Assignment::A_FUNCTION
:
1005 case Common::Assignment::A_EXT_FUNCTION
:
1006 case Common::Assignment::A_FUNCTION_RVAL
:
1007 case Common::Assignment::A_EXT_FUNCTION_RVAL
:
1008 case Common::Assignment::A_FUNCTION_RTEMP
:
1009 case Common::Assignment::A_EXT_FUNCTION_RTEMP
:
1010 generate_code(expr
);
1012 case Common::Assignment::A_MODULEPAR
:
1013 case Common::Assignment::A_VAR
:
1014 case Common::Assignment::A_PAR_VAL_IN
:
1015 case Common::Assignment::A_PAR_VAL_OUT
:
1016 case Common::Assignment::A_PAR_VAL_INOUT
: {
1017 is_template
= false;
1019 case Common::Assignment::A_MODULEPAR_TEMP
:
1020 case Common::Assignment::A_VAR_TEMPLATE
:
1021 case Common::Assignment::A_PAR_TEMPL_IN
:
1022 case Common::Assignment::A_PAR_TEMPL_OUT
:
1023 case Common::Assignment::A_PAR_TEMPL_INOUT
: {
1027 is_template
= false;
1031 Type
*refd_gov
= ass
->get_Type();
1033 generate_code(expr
);
1038 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
1039 refd_gov
->get_genname_template(get_my_scope()).c_str() );
1041 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s%s&>(",
1042 refd_gov
->get_genname_value(get_my_scope()).c_str(),
1043 is_template
? "_template":"");
1046 expr
->expr
= mputprintf(expr
->expr
, "%s(",
1047 ass
->get_genname_from_scope(my_scope
).c_str());
1048 parlist
.generate_code_alias(expr
, ass
->get_FormalParList(),
1049 ass
->get_RunsOnType(), false);
1050 expr
->expr
= mputstr(expr
->expr
, "))");
1052 t_subrefs
->generate_code(expr
, ass
);
1055 // =================================
1056 // ===== NameBridgingScope
1057 // =================================
1058 string
NameBridgingScope::get_scopeMacro_name() const
1060 if (scopeMacro_name
.empty()) FATAL_ERROR("NameBridgingScope::get_scopeMacro_name()");
1061 return scopeMacro_name
;
1064 NameBridgingScope
*NameBridgingScope::clone() const
1066 FATAL_ERROR("NameBridgingScope::clone");
1069 Common::Assignment
* NameBridgingScope::get_ass_bySRef(Ref_simple
*p_ref
)
1071 return get_parent_scope()->get_ass_bySRef(p_ref
);
1074 // =================================
1075 // ===== RunsOnScope
1076 // =================================
1078 RunsOnScope::RunsOnScope(Type
*p_comptype
)
1079 : Scope(), component_type(p_comptype
)
1081 if (!p_comptype
|| p_comptype
->get_typetype() != Type::T_COMPONENT
)
1082 FATAL_ERROR("RunsOnScope::RunsOnScope()");
1083 component_type
->set_ownertype(Type::OT_RUNSON_SCOPE
, this);
1084 component_defs
= p_comptype
->get_CompBody();
1085 set_scope_name("runs on `" + p_comptype
->get_fullname() + "'");
1088 RunsOnScope
*RunsOnScope::clone() const
1090 FATAL_ERROR("RunsOnScope::clone()");
1093 void RunsOnScope::chk_uniq()
1095 // do not perform this check if the component type is defined in the same
1096 // module as the 'runs on' clause
1097 if (parent_scope
->get_scope_mod() == component_defs
->get_scope_mod())
1099 size_t nof_defs
= component_defs
->get_nof_asss();
1100 for (size_t i
= 0; i
< nof_defs
; i
++) {
1101 Common::Assignment
*comp_def
= component_defs
->get_ass_byIndex(i
);
1102 const Identifier
& id
= comp_def
->get_id();
1103 if (parent_scope
->has_ass_withId(id
)) {
1104 comp_def
->warning("Imported component element definition `%s' hides a "
1105 "definition at module scope", comp_def
->get_fullname().c_str());
1106 Reference
ref(0, id
.clone());
1107 Common::Assignment
*hidden_ass
= parent_scope
->get_ass_bySRef(&ref
);
1108 hidden_ass
->warning("Hidden definition `%s' is here",
1109 hidden_ass
->get_fullname().c_str());
1115 RunsOnScope
*RunsOnScope::get_scope_runs_on()
1120 Common::Assignment
*RunsOnScope::get_ass_bySRef(Ref_simple
*p_ref
)
1122 if (!p_ref
) FATAL_ERROR("Ttcn::RunsOnScope::get_ass_bySRef()");
1123 if (p_ref
->get_modid()) return parent_scope
->get_ass_bySRef(p_ref
);
1125 const Identifier
& id
= *p_ref
->get_id();
1126 if (component_defs
->has_local_ass_withId(id
)) {
1127 Common::Assignment
* ass
= component_defs
->get_local_ass_byId(id
);
1128 if (!ass
) FATAL_ERROR("Ttcn::RunsOnScope::get_ass_bySRef()");
1130 if (component_defs
->is_own_assignment(ass
)) return ass
;
1131 else if (ass
->get_visibility() == PUBLIC
) {
1135 p_ref
->error("The member definition `%s' in component type `%s'"
1136 " is not visible in this scope", id
.get_dispname().c_str(),
1137 component_defs
->get_id()->get_dispname().c_str());
1139 } else return parent_scope
->get_ass_bySRef(p_ref
);
1143 bool RunsOnScope::has_ass_withId(const Identifier
& p_id
)
1145 return component_defs
->has_ass_withId(p_id
)
1146 || parent_scope
->has_ass_withId(p_id
);
1149 // =================================
1151 // =================================
1153 FriendMod::FriendMod(Identifier
*p_modid
)
1154 : Node(), modid(p_modid
), w_attrib_path(0), parentgroup(0), checked(false)
1156 if (!p_modid
) FATAL_ERROR("NULL parameter: Ttcn::FriendMod::FriendMod()");
1157 set_fullname("<friends>."+modid
->get_dispname());
1160 FriendMod::~FriendMod()
1164 delete w_attrib_path
;
1167 FriendMod
*FriendMod::clone() const
1169 FATAL_ERROR("Ttcn::FriendMod::clone()");
1172 void FriendMod::set_fullname(const string
& p_fullname
)
1174 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
1177 void FriendMod::chk()
1179 if (checked
) return;
1181 Error_Context
cntxt(this, "In friend module declaration");
1183 if (w_attrib_path
) {
1184 w_attrib_path
->chk_global_attrib();
1185 w_attrib_path
->chk_no_qualif();
1191 void FriendMod::set_with_attr(MultiWithAttrib
* p_attrib
)
1193 if (w_attrib_path
) FATAL_ERROR("FriendMod::set_with_attr()");
1194 w_attrib_path
= new WithAttribPath();
1195 if (p_attrib
&& p_attrib
->get_nof_elements() > 0) {
1196 w_attrib_path
->set_with_attr(p_attrib
);
1200 WithAttribPath
* FriendMod::get_attrib_path()
1202 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1203 return w_attrib_path
;
1206 void FriendMod::set_parent_path(WithAttribPath
* p_path
)
1208 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1209 w_attrib_path
->set_parent(p_path
);
1212 void FriendMod::set_parent_group(Group
* p_group
)
1214 if(parentgroup
) FATAL_ERROR("FriendMod::set_parent_group");
1215 parentgroup
= p_group
;
1218 // =================================
1220 // =================================
1222 ImpMod::ImpMod(Identifier
*p_modid
)
1223 : Node(), mod(0), my_mod(0), imptype(I_UNDEF
), modid(p_modid
),
1224 language_spec(0), is_recursive(false),
1225 w_attrib_path(0), parentgroup(0), visibility(PRIVATE
)
1227 if (!p_modid
) FATAL_ERROR("NULL parameter: Ttcn::ImpMod::ImpMod()");
1228 set_fullname("<imports>." + modid
->get_dispname());
1234 delete language_spec
;
1236 delete w_attrib_path
;
1239 ImpMod
*ImpMod::clone() const
1241 FATAL_ERROR("No clone for you!");
1244 void ImpMod::set_fullname(const string
& p_fullname
)
1246 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
1251 if (w_attrib_path
) {
1252 w_attrib_path
->chk_global_attrib();
1253 w_attrib_path
->chk_no_qualif();
1257 void ImpMod::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
1259 Error_Context
cntxt(this, "In import definition");
1261 if (!modules
->has_mod_withId(*modid
)) {
1262 error("There is no module with identifier `%s'",
1263 modid
->get_dispname().c_str());
1267 Common::Module
*m
= modules
->get_mod_byId(*modid
);
1273 error("A module cannot import from itself");
1281 if (refch
.exists(my_mod
->get_fullname())) {
1282 if(my_mod
->get_moduletype()!=Common::Module::MOD_ASN
){ // Do not warning for circular import in ASN.1 module. It is legal
1283 my_mod
->warning("Circular import chain is not recommended: %s",
1284 refch
.get_dispstr(my_mod
->get_fullname()).c_str());
1289 refch
.add(my_mod
->get_fullname());
1291 if (ImpMod::I_IMPORTIMPORT
== imptype
){
1292 Ttcn::Module
* ttcnmodule
=static_cast<Ttcn::Module
*>(m
);
1293 const Imports
& imp
= ttcnmodule
->get_imports();
1295 for (size_t t
= 0; t
< imp
.impmods_v
.size(); t
++) {
1296 const ImpMod
*im
= imp
.impmods_v
[t
];
1297 const Identifier
& im_id
= im
->get_modid();
1298 Common::Module
*cm
= modules
->get_mod_byId(im_id
); // never NULL
1301 if (PRIVATE
!= im
->get_visibility()) {
1302 if (refch
.exists(m
->get_fullname())) {
1303 if(m
->get_moduletype()!=Common::Module::MOD_ASN
){ // Do not warning for circular import in ASN.1 module. It is legal
1304 m
->warning("Circular import chain is not recommended: %s",
1305 refch
.get_dispstr(m
->get_fullname()).c_str());
1310 refch
.add(m
->get_fullname());
1311 cm
->chk_imp(refch
, moduleStack
);
1317 //refch.mark_state();
1318 m
->chk_imp(refch
, moduleStack
);
1319 //refch.prev_state();
1324 size_t state
=moduleStack
.size();
1325 moduleStack
.replace(state
, moduleStack
.size() - state
);
1328 bool ImpMod::has_imported_def(const Identifier
& p_source_modid
,
1329 const Identifier
& p_id
, const Location
*loc
) const
1331 if (!mod
) return false;
1337 Common::Assignment
* return_assignment
= mod
->importAssignment(p_source_modid
, p_id
);
1338 if (return_assignment
!= NULL
) {
1345 case I_IMPORTIMPORT
:
1347 Ttcn::Module
*tm
= static_cast<Ttcn::Module
*>(mod
); // B
1349 const Imports
& imps
= tm
->get_imports();
1351 vector
<ImpMod
> tempusedImpMods
;
1352 for (size_t i
= 0, num
= imps
.impmods_v
.size(); i
< num
; ++i
) {
1353 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
1354 Common::Assignment
* return_assignment
= imps
.impmods_v
[i
]->
1355 get_imported_def(p_source_modid
, p_id
, loc
, referencechain
, tempusedImpMods
); // C
1356 referencechain
->reset();
1357 delete referencechain
;
1359 if (return_assignment
!= NULL
) {
1365 //satisfy destructor
1366 tempusedImpMods
.clear();
1371 FATAL_ERROR("ImpMod::get_imported_def");
1377 Common::Assignment
*ImpMod::get_imported_def(
1378 const Identifier
& p_source_modid
, const Identifier
& p_id
,
1379 const Location
*loc
, ReferenceChain
* refch
,
1380 vector
<ImpMod
>& usedImpMods
) const
1385 Common::Assignment
* result
= NULL
;
1390 result
= mod
->importAssignment(p_source_modid
, p_id
);
1391 if (result
!= NULL
) {
1392 usedImpMods
.add(const_cast<Ttcn::ImpMod
*>(this));
1396 case I_IMPORTIMPORT
:
1398 Ttcn::Module
*tm
= static_cast<Ttcn::Module
*>(mod
);
1400 const Imports
& imps
= tm
->get_imports();
1401 Common::Assignment
* t_ass
= NULL
;
1403 for (size_t i
= 0, num
= imps
.impmods_v
.size(); i
< num
; ++i
) {
1404 vector
<ImpMod
> tempusedImpMods
;
1406 refch
->mark_state();
1407 if (imps
.impmods_v
[i
]->get_visibility() == PUBLIC
) {
1408 t_ass
= imps
.impmods_v
[i
]->get_imported_def(p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1410 else if (imps
.impmods_v
[i
]->get_visibility() == FRIEND
) {
1411 t_ass
= imps
.impmods_v
[i
]->get_imported_def(p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1413 tempusedImpMods
.add(imps
.impmods_v
[i
]);
1416 refch
->prev_state();
1418 if (t_ass
!= NULL
) {
1419 bool visible
= true;
1420 for (size_t j
= 0; j
< tempusedImpMods
.size(); j
++) {
1421 ImpMod
* impmod_l
= tempusedImpMods
[j
];
1422 //check whether the module is TTCN
1423 if (impmod_l
->get_mod()->get_moduletype() == Common::Module::MOD_TTCN
) {
1424 // cast to ttcn module
1425 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(impmod_l
->get_mod());
1426 if (!ttcn_m
->is_visible(mod
->get_modid(), impmod_l
->get_visibility())) {
1432 for (size_t t
= 0; i
< tempusedImpMods
.size(); i
++) {
1433 usedImpMods
.add(tempusedImpMods
[t
]);
1438 } else if(result
!= t_ass
) {
1443 "It is not possible to resolve the reference unambiguously"
1444 ", as it can be resolved to `%s' and to `%s'",
1445 result
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
1451 tempusedImpMods
.clear();
1454 if (result
!= NULL
) {
1455 usedImpMods
.add(const_cast<Ttcn::ImpMod
*>(this));
1461 FATAL_ERROR("ImpMod::get_imported_def");
1466 void ImpMod::set_language_spec(const char *p_language_spec
)
1468 if (language_spec
) FATAL_ERROR("ImpMod::set_language_spec()");
1469 if (p_language_spec
) language_spec
= new string(p_language_spec
);
1472 void ImpMod::generate_code(output_struct
*target
)
1474 const char *module_name
= modid
->get_name().c_str();
1476 target
->header
.includes
= mputprintf(target
->header
.includes
,
1477 "#include \"%s.hh\"\n",
1478 duplicate_underscores
? module_name
: modid
->get_ttcnname().c_str());
1480 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
1481 "%s%s.pre_init_module();\n", module_name
,
1484 if (mod
->get_moduletype() == Common::Module::MOD_TTCN
) {
1485 target
->functions
.post_init
= mputprintf(target
->functions
.post_init
,
1486 "%s%s.post_init_module();\n", module_name
,
1492 void ImpMod::dump(unsigned level
) const
1494 DEBUG(level
, "Import from module %s", modid
->get_dispname().c_str());
1495 if (w_attrib_path
) {
1496 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
1498 DEBUG(level
+ 1, "Attributes:");
1499 attrib
->dump(level
+ 2);
1504 void ImpMod::set_with_attr(MultiWithAttrib
* p_attrib
)
1506 if (w_attrib_path
) FATAL_ERROR("ImpMod::set_with_attr()");
1507 w_attrib_path
= new WithAttribPath();
1508 if (p_attrib
&& p_attrib
->get_nof_elements() > 0) {
1509 w_attrib_path
->set_with_attr(p_attrib
);
1513 WithAttribPath
* ImpMod::get_attrib_path()
1515 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1516 return w_attrib_path
;
1519 void ImpMod::set_parent_path(WithAttribPath
* p_path
)
1521 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1522 w_attrib_path
->set_parent(p_path
);
1525 void ImpMod::set_parent_group(Group
* p_group
)
1527 if(parentgroup
) FATAL_ERROR("ImpMod::set_parent_group");
1528 parentgroup
= p_group
;
1531 // =================================
1533 // =================================
1537 for (size_t i
= 0; i
< impmods_v
.size(); i
++)
1538 delete impmods_v
[i
];
1542 Imports
*Imports::clone() const
1544 FATAL_ERROR("Ttcn::Imports::clone()");
1547 void Imports::add_impmod(ImpMod
*p_impmod
)
1549 if (!p_impmod
) FATAL_ERROR("Ttcn::Imports::add_impmod()");
1550 impmods_v
.add(p_impmod
);
1551 p_impmod
->set_my_mod(my_mod
);
1554 void Imports::set_my_mod(Module
*p_mod
)
1557 for(size_t i
= 0; i
< impmods_v
.size(); i
++)
1558 impmods_v
[i
]->set_my_mod(my_mod
);
1561 bool Imports::has_impmod_withId(const Identifier
& p_id
) const
1563 for (size_t i
= 0, size
= impmods_v
.size(); i
< size
; ++i
) {
1564 const ImpMod
* im
= impmods_v
[i
];
1565 const Identifier
& im_id
= im
->get_modid();
1566 const string
& im_name
= im_id
.get_name();
1567 if (p_id
.get_name() == im_name
) {
1568 // The identifier represents a module imported in the current module
1575 void Imports::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
1577 if (impmods_v
.size() <= 0) return;
1579 if (!my_mod
) FATAL_ERROR("Ttcn::Imports::chk_imp()");
1584 for(size_t n
= 0; n
< impmods_v
.size(); n
++)
1586 impmods_v
[n
]->chk();
1589 //TODO this whole thing should be moved into impmod::chk
1590 Identifier
address_id(Identifier::ID_TTCN
, string("address"));
1591 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1592 ImpMod
*im
= impmods_v
[n
];
1593 im
->chk_imp(refch
, moduleStack
);
1595 const Identifier
& im_id
= im
->get_modid();
1596 Common::Module
*m
= modules
->get_mod_byId(im_id
);
1599 if (m
->get_gen_code()) my_mod
->set_gen_code();
1600 } // next assignment
1603 bool Imports::has_imported_def(const Identifier
& p_id
, const Location
*loc
) const
1605 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1606 ImpMod
*im
= impmods_v
[n
];
1607 bool return_bool
= im
->has_imported_def(my_mod
->get_modid(), p_id
, loc
);
1608 if (return_bool
) return true;
1613 Common::Assignment
*Imports::get_imported_def(
1614 const Identifier
& p_source_modid
, const Identifier
& p_id
,
1615 const Location
*loc
, ReferenceChain
* refch
)
1617 vector
<ImpMod
> tempusedImpMods
;
1618 Common::Assignment
* result
= NULL
;
1619 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1620 ImpMod
*im
= impmods_v
[n
];
1621 refch
->mark_state();
1622 Common::Assignment
* ass
= im
->get_imported_def(
1623 p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1624 tempusedImpMods
.clear();
1625 refch
->prev_state();
1630 } else if(result
!= ass
&& loc
) {
1635 "It is not possible to resolve the reference unambiguously"
1636 ", as it can be resolved to `%s' and to `%s'",
1637 result
->get_fullname().c_str(), ass
->get_fullname().c_str());
1645 void Imports::get_imported_mods(Module::module_set_t
& p_imported_mods
) const
1647 for (size_t i
= 0; i
< impmods_v
.size(); i
++) {
1648 ImpMod
*im
= impmods_v
[i
];
1649 Common::Module
*m
= im
->get_mod();
1651 if (!p_imported_mods
.has_key(m
)) {
1652 p_imported_mods
.add(m
, 0);
1653 m
->get_visible_mods(p_imported_mods
);
1658 void Imports::generate_code(output_struct
*target
)
1660 target
->header
.includes
= mputstr(target
->header
.includes
,
1661 "#include <TTCN3.hh>\n");
1662 for (size_t i
= 0; i
< impmods_v
.size(); i
++) {
1663 ImpMod
*im
= impmods_v
[i
];
1664 Common::Module
*m
= im
->get_mod();
1665 // inclusion of m's header file can be eliminated if we find another
1666 // imported module that imports m
1667 bool covered
= false;
1668 for (size_t j
= 0; j
< impmods_v
.size(); j
++) {
1669 // skip over the same import definition
1670 if (j
== i
) continue;
1671 ImpMod
*im2
= impmods_v
[j
];
1672 Common::Module
*m2
= im2
->get_mod();
1673 // a module that is equivalent to the current module due to
1674 // circular imports cannot be used to cover anything
1675 if (m2
->is_visible(my_mod
)) continue;
1676 if (m2
->is_visible(m
) && !m
->is_visible(m2
)) {
1677 // m2 covers m (i.e. m is visible from m2)
1678 // and they are not in the same import loop
1683 // do not generate the #include if a covering module is found
1684 if (!covered
) im
->generate_code(target
);
1688 void Imports::generate_code(CodeGenHelper
& cgh
) {
1689 generate_code(cgh
.get_current_outputstruct());
1692 void Imports::dump(unsigned level
) const
1694 DEBUG(level
, "Imports (%lu pcs.)", (unsigned long) impmods_v
.size());
1695 for (size_t i
= 0; i
< impmods_v
.size(); i
++)
1696 impmods_v
[i
]->dump(level
+ 1);
1699 // =================================
1700 // ===== Definitions
1701 // =================================
1703 Definitions::~Definitions()
1705 for(size_t i
= 0; i
< ass_v
.size(); i
++) delete ass_v
[i
];
1710 Definitions
*Definitions::clone() const
1712 FATAL_ERROR("Definitions::clone");
1715 void Definitions::add_ass(Definition
*p_ass
)
1717 // it is too late to add a new one after it has been checked.
1718 if (checked
|| !p_ass
) FATAL_ERROR("Ttcn::OtherDefinitions::add_ass()");
1720 p_ass
->set_my_scope(this);
1723 void Definitions::set_fullname(const string
& p_fullname
)
1725 Common::Assignments::set_fullname(p_fullname
);
1726 for(size_t i
= 0; i
< ass_v
.size(); i
++) {
1727 Definition
*ass
= ass_v
[i
];
1728 ass
->set_fullname(p_fullname
+ "." + ass
->get_id().get_dispname());
1732 bool Definitions::has_local_ass_withId(const Identifier
& p_id
)
1734 if (!checked
) chk_uniq();
1735 return ass_m
.has_key(p_id
.get_name());
1738 Common::Assignment
* Definitions::get_local_ass_byId(const Identifier
& p_id
)
1740 if (!checked
) chk_uniq();
1741 return ass_m
[p_id
.get_name()];
1744 size_t Definitions::get_nof_asss()
1746 if (!checked
) chk_uniq();
1747 return ass_m
.size();
1750 size_t Definitions::get_nof_raw_asss()
1752 return ass_v
.size();
1755 Common::Assignment
* Definitions::get_ass_byIndex(size_t p_i
)
1757 if (!checked
) chk_uniq();
1758 return ass_m
.get_nth_elem(p_i
);
1761 Ttcn::Definition
* Definitions::get_raw_ass_byIndex(size_t p_i
) {
1765 void Definitions::chk_uniq()
1767 if (checked
) return;
1769 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1770 Definition
*ass
= ass_v
[i
];
1771 const Identifier
& id
= ass
->get_id();
1772 const string
& name
= id
.get_name();
1773 if (ass_m
.has_key(name
)) {
1774 const char *dispname_str
= id
.get_dispname().c_str();
1775 ass
->error("Duplicate definition with name `%s'", dispname_str
);
1776 ass_m
[name
]->note("Previous definition of `%s' is here", dispname_str
);
1778 ass_m
.add(name
, ass
);
1779 if (parent_scope
->is_valid_moduleid(id
)) {
1780 ass
->warning("Definition with name `%s' hides a module identifier",
1781 id
.get_dispname().c_str());
1788 void Definitions::chk()
1790 for (size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->chk();
1793 void Definitions::chk_for()
1795 if (checked
) return;
1798 // all checks are done in one iteration because
1799 // forward referencing is not allowed between the definitions
1800 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1801 Definition
*def
= ass_v
[i
];
1802 const Identifier
& id
= def
->get_id();
1803 const string
& name
= id
.get_name();
1804 if (ass_m
.has_key(name
)) {
1805 const char *dispname_str
= id
.get_dispname().c_str();
1806 def
->error("Duplicate definition with name `%s'", dispname_str
);
1807 ass_m
[name
]->note("Previous definition of `%s' is here", dispname_str
);
1809 ass_m
.add(name
, def
);
1811 if (parent_scope
->has_ass_withId(id
)) {
1812 const char *dispname_str
= id
.get_dispname().c_str();
1813 def
->error("Definition with identifier `%s' is not unique in the "
1814 "scope hierarchy", dispname_str
);
1815 Reference
ref(0, id
.clone());
1816 Common::Assignment
*ass
= parent_scope
->get_ass_bySRef(&ref
);
1817 if (!ass
) FATAL_ERROR("OtherDefinitions::chk_for()");
1818 ass
->note("Previous definition with identifier `%s' in higher "
1819 "scope unit is here", dispname_str
);
1820 } else if (parent_scope
->is_valid_moduleid(id
)) {
1821 def
->warning("Definition with name `%s' hides a module identifier",
1822 id
.get_dispname().c_str());
1830 void Definitions::set_genname(const string
& prefix
)
1832 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1833 Definition
*def
= ass_v
[i
];
1834 def
->set_genname(prefix
+ def
->get_id().get_name());
1838 void Definitions::generate_code(output_struct
* target
)
1840 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->generate_code(target
);
1843 void Definitions::generate_code(CodeGenHelper
& cgh
) {
1845 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->generate_code(cgh
);
1848 char* Definitions::generate_code_str(char *str
)
1850 for(size_t i
=0; i
<ass_v
.size(); i
++) {
1851 str
= ass_v
[i
]->update_location_object(str
);
1852 str
=ass_v
[i
]->generate_code_str(str
);
1857 void Definitions::ilt_generate_code(ILT
*ilt
)
1859 for(size_t i
=0; i
<ass_v
.size(); i
++)
1860 ass_v
[i
]->ilt_generate_code(ilt
);
1864 void Definitions::dump(unsigned level
) const
1866 DEBUG(level
, "Definitions: (%lu pcs.)", (unsigned long) ass_v
.size());
1867 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->dump(level
+ 1);
1870 // =================================
1872 // =================================
1874 Group::Group(Identifier
*p_id
)
1875 : Node(), Location(), parent_group(0), w_attrib_path(0), id(p_id
),
1878 if (!p_id
) FATAL_ERROR("Group::Group()");
1883 delete w_attrib_path
;
1886 for (size_t i
= 0; i
< group_v
.size(); i
++) delete group_v
[i
];
1890 friendmods_v
.clear();
1894 Group
* Group::clone() const
1896 FATAL_ERROR("Ttcn::Group::clone()");
1899 void Group::set_fullname(const string
& p_fullname
)
1901 Node::set_fullname(p_fullname
);
1902 for(size_t i
= 0; i
< group_v
.size() ; i
++)
1904 group_v
[i
]->set_fullname(p_fullname
+ ".<group " + Int2string(i
) + ">");
1906 if (w_attrib_path
) w_attrib_path
->set_fullname( p_fullname
1910 void Group::add_ass(Definition
* p_ass
)
1913 p_ass
->set_parent_group(this);
1916 void Group::add_group(Group
* p_group
)
1918 group_v
.add(p_group
);
1921 void Group::set_parent_group(Group
* p_parent_group
)
1923 if (parent_group
) FATAL_ERROR("Group::set_parent_group()");
1924 parent_group
= p_parent_group
;
1927 void Group::set_with_attr(MultiWithAttrib
* p_attrib
)
1929 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1930 w_attrib_path
->set_with_attr(p_attrib
);
1933 WithAttribPath
* Group::get_attrib_path()
1935 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1936 return w_attrib_path
;
1939 void Group::set_parent_path(WithAttribPath
* p_path
)
1941 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1942 w_attrib_path
->set_parent(p_path
);
1945 void Group::chk_uniq()
1947 if (checked
) return;
1951 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1952 Definition
*ass
= ass_v
[i
];
1953 const string
& ass_name
= ass
->get_id().get_name();
1954 if (!ass_m
.has_key(ass_name
)) ass_m
.add(ass_name
, ass
);
1957 for(size_t i
= 0; i
< group_v
.size(); i
++) {
1958 Group
*group
= group_v
[i
];
1959 const Identifier
& group_id
= group
->get_id();
1960 const string
& group_name
= group_id
.get_name();
1961 if (ass_m
.has_key(group_name
)) {
1962 group
->error("Group name `%s' clashes with a definition",
1963 group_id
.get_dispname().c_str());
1964 ass_m
[group_name
]->note("Definition of `%s' is here",
1965 group_id
.get_dispname().c_str());
1967 if (group_m
.has_key(group_name
)) {
1968 group
->error("Duplicate group with name `%s'",
1969 group_id
.get_dispname().c_str());
1970 group_m
[group_name
]->note("Group `%s' is already defined here",
1971 group_id
.get_dispname().c_str());
1972 } else group_m
.add(group_name
, group
);
1979 Error_Context
cntxt(this, "In group `%s'", id
->get_dispname().c_str());
1983 if (w_attrib_path
) {
1984 w_attrib_path
->chk_global_attrib();
1985 w_attrib_path
->chk_no_qualif();
1988 for(size_t i
= 0; i
< group_v
.size(); i
++) group_v
[i
]->chk();
1991 void Group::add_impmod(ImpMod
*p_impmod
)
1993 impmods_v
.add(p_impmod
);
1994 p_impmod
->set_parent_group(this);
1997 void Group::add_friendmod(FriendMod
*p_friendmod
)
1999 friendmods_v
.add(p_friendmod
);
2000 p_friendmod
->set_parent_group(this);
2003 void Group::dump(unsigned level
) const
2005 DEBUG(level
, "Group: %s", id
->get_dispname().c_str());
2006 DEBUG(level
+ 1, "Nested groups: (%lu pcs.)",
2007 (unsigned long) group_v
.size());
2008 for(size_t i
= 0; i
< group_v
.size(); i
++) group_v
[i
]->dump(level
+ 2);
2009 DEBUG(level
+ 1, "Nested definitions: (%lu pcs.)",
2010 (unsigned long) ass_v
.size());
2011 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->dump(level
+ 2);
2012 DEBUG(level
+ 1, "Nested imports: (%lu pcs.)",
2013 (unsigned long) impmods_v
.size());
2014 for(size_t i
= 0; i
< impmods_v
.size(); i
++) impmods_v
[i
]->dump(level
+ 2);
2015 if (w_attrib_path
) {
2016 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2018 DEBUG(level
+ 1, "Group Attributes:");
2019 attrib
->dump(level
+ 2);
2024 // =================================
2025 // ===== ControlPart
2026 // =================================
2028 ControlPart::ControlPart(StatementBlock
* p_block
)
2029 : Node(), Location(), block(p_block
), w_attrib_path(0)
2031 if (!p_block
) FATAL_ERROR("ControlPart::ControlPart()");
2034 ControlPart::~ControlPart()
2037 delete w_attrib_path
;
2040 ControlPart
* ControlPart::clone() const
2042 FATAL_ERROR("ControlPart::clone");
2045 void ControlPart::set_fullname(const string
& p_fullname
)
2047 block
->set_fullname(p_fullname
);
2048 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
2051 void ControlPart::set_my_scope(Scope
*p_scope
)
2053 bridgeScope
.set_parent_scope(p_scope
);
2054 string
temp("control");
2055 bridgeScope
.set_scopeMacro_name(temp
);
2057 block
->set_my_scope(&bridgeScope
);
2060 void ControlPart::chk()
2062 Error_Context
cntxt(this, "In control part");
2064 if (!semantic_check_only
)
2065 block
->set_code_section(GovernedSimple::CS_INLINE
);
2066 if (w_attrib_path
) {
2067 w_attrib_path
->chk_global_attrib();
2068 w_attrib_path
->chk_no_qualif();
2072 void ControlPart::generate_code(output_struct
*target
, Module
*my_module
)
2074 const char *module_dispname
= my_module
->get_modid().get_dispname().c_str();
2075 target
->functions
.control
=
2076 create_location_object(target
->functions
.control
, "CONTROLPART",
2078 target
->functions
.control
= mputprintf(target
->functions
.control
,
2079 "TTCN_Runtime::begin_controlpart(\"%s\");\n", module_dispname
);
2080 target
->functions
.control
=
2081 block
->generate_code(target
->functions
.control
);
2082 target
->functions
.control
= mputstr(target
->functions
.control
,
2083 "TTCN_Runtime::end_controlpart();\n");
2086 void ControlPart::set_with_attr(MultiWithAttrib
* p_attrib
)
2088 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2089 w_attrib_path
->set_with_attr(p_attrib
);
2092 WithAttribPath
* ControlPart::get_attrib_path()
2094 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2095 return w_attrib_path
;
2098 void ControlPart::set_parent_path(WithAttribPath
* p_path
)
2100 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2101 w_attrib_path
->set_parent(p_path
);
2102 block
->set_parent_path(w_attrib_path
);
2105 void ControlPart::dump(unsigned level
) const
2107 DEBUG(level
, "Control part");
2108 block
->dump(level
+ 1);
2109 if (w_attrib_path
) {
2110 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2112 DEBUG(level
+ 1, "Attributes:");
2113 attrib
->dump(level
+ 2);
2118 // =================================
2120 // =================================
2122 Module::Module(Identifier
*p_modid
)
2123 : Common::Module(MOD_TTCN
, p_modid
), language_spec(0), w_attrib_path(0),
2126 asss
= new Definitions();
2127 asss
->set_parent_scope(this);
2128 imp
= new Imports();
2129 imp
->set_my_mod(this);
2130 //modified_encodings = true; // Assume always true for TTCN modules
2135 delete language_spec
;
2137 for (size_t i
= 0; i
< group_v
.size(); i
++) delete group_v
[i
];
2141 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) delete friendmods_v
[i
];
2142 friendmods_v
.clear();
2144 for (size_t i
= 0; i
< runs_on_scopes
.size(); i
++)
2145 delete runs_on_scopes
[i
];
2146 runs_on_scopes
.clear();
2147 delete w_attrib_path
;
2150 void Module::add_group(Group
* p_group
)
2152 group_v
.add(p_group
);
2155 void Module::add_friendmod(FriendMod
*p_friendmod
)
2157 friendmods_v
.add(p_friendmod
);
2158 p_friendmod
->set_my_mod(this);
2161 Module
*Module::clone() const
2163 FATAL_ERROR("Ttcn::Module::clone()");
2166 Common::Assignment
*Module::importAssignment(const Identifier
& p_modid
,
2167 const Identifier
& p_id
) const
2169 if (asss
->has_local_ass_withId(p_id
)) {
2170 Common::Assignment
* ass
= asss
->get_local_ass_byId(p_id
);
2171 if (!ass
) FATAL_ERROR("Ttcn::Module::importAssignment()");
2173 switch(ass
->get_visibility()) {
2175 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) {
2176 if (friendmods_v
[i
]->get_modid() == p_modid
) return ass
;
2184 FATAL_ERROR("Ttcn::Module::importAssignment()");
2190 void Module::set_fullname(const string
& p_fullname
)
2192 Node::set_fullname(p_fullname
);
2193 asss
->set_fullname(p_fullname
);
2194 if (controlpart
) controlpart
->set_fullname(p_fullname
+ ".control");
2195 for(size_t i
= 0; i
< group_v
.size(); i
++)
2197 group_v
[i
]->set_fullname(p_fullname
+ ".<group " + Int2string(i
) + ">");
2199 if (w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
2203 Common::Assignments
*Module::get_scope_asss()
2208 bool Module::has_imported_ass_withId(const Identifier
& p_id
)
2210 const Location
*loc
= NULL
;
2211 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2212 const ImpMod
* im
= imp
->get_impmod(i
);
2213 //TODO use a reference instead of an identifier
2214 if(im
->has_imported_def(*modid
, p_id
, loc
)) return true;
2219 Common::Assignment
* Module::get_ass_bySRef(Ref_simple
*p_ref
)
2221 const Identifier
*r_modid
= p_ref
->get_modid();
2222 const Identifier
*r_id
= p_ref
->get_id();
2224 // the reference contains a module name
2225 if (r_modid
->get_name() != modid
->get_name()) {
2226 // the reference points to another module
2227 bool has_impmod_with_name
= false;
2228 Common::Assignment
* result_ass
= NULL
;
2229 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2230 const ImpMod
* im
= imp
->get_impmod(i
);
2231 const Identifier
& im_id
= im
->get_modid();
2232 const string
& im_name
= im_id
.get_name();
2233 if (r_modid
->get_name() == im_name
) {
2234 has_impmod_with_name
= true;
2235 vector
<ImpMod
> tempusedImpMods
;
2236 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
2237 Common::Assignment
*t_ass
= im
->get_imported_def(*modid
, *r_id
, p_ref
, referencechain
, tempusedImpMods
);
2238 referencechain
->reset();
2239 delete referencechain
;
2241 if (t_ass
!= NULL
) {
2242 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(im
->get_mod());
2243 if (!ttcn_m
->is_visible(*modid
, t_ass
->get_visibility())) {
2247 if (t_ass
!= NULL
) {
2248 if (result_ass
== NULL
) {
2250 } else if(result_ass
!= t_ass
) {
2252 "It is not possible to resolve the reference unambiguously"
2253 ", as it can be resolved to `%s' and to `%s'",
2254 result_ass
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
2258 tempusedImpMods
.clear();
2261 if (result_ass
) return result_ass
;
2263 if (has_impmod_with_name
) {
2264 p_ref
->error("There is no definition with name `%s' visible from "
2265 "module `%s'", r_id
->get_dispname().c_str(),
2266 r_modid
->get_dispname().c_str());
2268 if (modules
->has_mod_withId(*r_modid
)) {
2269 Common::Module
*m
= modules
->get_mod_byId(*r_modid
);
2270 if (m
->get_asss()->has_ass_withId(*r_id
)) {
2271 p_ref
->error("Definition with name `%s' is not imported from "
2272 "module `%s'", r_id
->get_dispname().c_str(),
2273 r_modid
->get_dispname().c_str());
2275 p_ref
->error("There is no definition with name `%s' in "
2276 "module `%s'", r_id
->get_dispname().c_str(),
2277 r_modid
->get_dispname().c_str());
2280 p_ref
->error("There is no module with name `%s'",
2281 r_modid
->get_dispname().c_str());
2286 // the reference points to the own module
2287 if (asss
->has_local_ass_withId(*r_id
)) {
2288 return asss
->get_local_ass_byId(*r_id
);
2290 p_ref
->error("There is no definition with name `%s' in "
2291 "module `%s'", r_id
->get_dispname().c_str(),
2292 r_modid
->get_dispname().c_str());
2296 // no module name is given in the reference
2297 if (asss
->has_local_ass_withId(*r_id
)) {
2298 return asss
->get_local_ass_byId(*r_id
);
2300 // the reference was not found locally -> look at the import list
2301 Common::Assignment
*t_result
= NULL
, *t_ass
= NULL
;
2302 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2303 const ImpMod
* im
= imp
->get_impmod(i
);
2305 vector
<ImpMod
> tempusedImpMods
;
2306 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
2307 t_ass
= im
->get_imported_def(*modid
, *r_id
, p_ref
, referencechain
, tempusedImpMods
);
2308 referencechain
->reset();
2310 delete referencechain
;
2311 if (t_ass
!= NULL
) {
2312 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(im
->get_mod());
2313 if (!ttcn_m
->is_visible(*modid
, t_ass
->get_visibility())) {
2317 if (t_ass
!= NULL
) {
2318 if (t_result
== NULL
) {
2320 } else if(t_result
!= t_ass
) {
2322 "It is not possible to resolve the reference unambiguously"
2323 ", as it can be resolved to `%s' and to `%s'",
2324 t_result
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
2328 tempusedImpMods
.clear();
2331 if (t_result
) return t_result
;
2333 p_ref
->error("There is no local or imported definition with name `%s'"
2334 ,r_id
->get_dispname().c_str());
2340 bool Module::is_valid_moduleid(const Identifier
& p_id
)
2342 // The identifier represents the current module
2343 if (p_id
.get_name() == modid
->get_name()) return true;
2344 // The identifier represents a module imported in the current module
2345 if(imp
->has_impmod_withId(p_id
)) return true;
2349 Common::Assignments
*Module::get_asss()
2354 bool Module::exports_sym(const Identifier
&)
2356 FATAL_ERROR("Ttcn::Module::exports_sym()");
2360 Type
*Module::get_address_type()
2362 Identifier
address_id(Identifier::ID_TTCN
, string("address"));
2363 // return NULL if address type is not defined
2364 if (!asss
->has_local_ass_withId(address_id
)) return 0;
2365 Common::Assignment
*t_ass
= asss
->get_local_ass_byId(address_id
);
2366 if (t_ass
->get_asstype() != Common::Assignment::A_TYPE
)
2367 FATAL_ERROR("Module::get_address_type(): address is not a type");
2368 return t_ass
->get_Type();
2371 void Module::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
2373 if (imp_checked
) return;
2374 const string
& module_name
= modid
->get_dispname();
2376 Error_Context backup
;
2377 Error_Context
cntxt(this, "In TTCN-3 module `%s'", module_name
.c_str());
2378 imp
->chk_imp(refch
, moduleStack
);
2381 collect_visible_mods();
2386 DEBUG(1, "Checking TTCN-3 module `%s'", modid
->get_dispname().c_str());
2387 Error_Context
cntxt(this, "In TTCN-3 module `%s'",
2388 modid
->get_dispname().c_str());
2389 if (w_attrib_path
) {
2390 w_attrib_path
->chk_global_attrib();
2391 w_attrib_path
->chk_no_qualif();
2393 // Check "extension" attributes in the module's "with" statement
2394 MultiWithAttrib
*multi
= w_attrib_path
->get_with_attr();
2395 if (multi
) for (size_t i
= 0; i
< multi
->get_nof_elements(); ++i
) {
2396 const SingleWithAttrib
*single
= multi
->get_element(i
);
2397 if (single
->get_attribKeyword() != SingleWithAttrib::AT_EXTENSION
) continue;
2398 // Parse the extension attribute
2399 // We circumvent parse_extattributes() in coding_attrib_p.y because
2400 // it processes all attributes in the "with" statement and
2401 // doesn't allow the removal on a case-by-case basis.
2403 init_coding_attrib_lex(single
->get_attribSpec());
2404 int result
= coding_attrib_parse();// 0=OK, 1=error, 2=out of memory
2405 cleanup_coding_attrib_lex();
2412 const size_t num_parsed
= extatrs
->size();
2413 for (size_t a
= 0; a
< num_parsed
; ++a
) {
2414 Ttcn::ExtensionAttribute
& ex
= extatrs
->get(0);
2416 switch (ex
.get_type()) {
2417 case Ttcn::ExtensionAttribute::VERSION_TEMPLATE
:
2418 case Ttcn::ExtensionAttribute::VERSION
: {
2419 char* act_product_number
;
2420 unsigned int act_suffix
, act_rel
, act_patch
, act_build
;
2422 (void)ex
.get_id(act_product_number
, act_suffix
, act_rel
, act_patch
, act_build
, extra_junk
);
2424 if (release
!= UINT_MAX
) {
2425 ex
.error("Duplicate 'version' attribute");
2428 product_number
= mcopystr(act_product_number
);
2429 suffix
= act_suffix
;
2433 extra
= mcopystr(extra_junk
);
2435 // Avoid propagating the attribute needlessly
2436 multi
->delete_element(i
--);
2440 case Ttcn::ExtensionAttribute::REQUIRES
: {
2441 // Imports have already been checked
2442 char* exp_product_number
;
2443 unsigned int exp_suffix
, exp_rel
, exp_patch
, exp_build
;
2445 Common::Identifier
*req_id
= ex
.get_id(exp_product_number
,
2446 exp_suffix
, exp_rel
, exp_patch
, exp_build
, exp_extra
);
2448 if (imp
->has_impmod_withId(*req_id
)) {
2449 Common::Module
* m
= modules
->get_mod_byId(*req_id
);
2450 if (m
->product_number
== NULL
&& exp_product_number
!= NULL
) {
2451 ex
.error("Module '%s' requires module '%s' of product %s"
2452 ", but it is not specified",
2453 this->modid
->get_dispname().c_str(), req_id
->get_dispname().c_str(),
2454 exp_product_number
);
2455 multi
->delete_element(i
--);
2458 } else if (exp_product_number
== NULL
&&
2459 m
->product_number
!= NULL
&& strcmp(m
->product_number
, "") > 0){
2460 ex
.warning("Module '%s' requires module '%s' of any product"
2461 ", while it specifies '%s'",
2462 this->modid
->get_dispname().c_str(),
2463 req_id
->get_dispname().c_str(), m
->product_number
);
2464 } else if (m
->product_number
!= NULL
&& exp_product_number
!= NULL
2465 && 0 != strcmp(m
->product_number
, exp_product_number
)) {
2466 char *req_product_identifier
=
2467 get_product_identifier(exp_product_number
,
2468 exp_suffix
, exp_rel
, exp_patch
, exp_build
);
2469 char *mod_product_identifier
=
2470 get_product_identifier(m
->product_number
,
2471 m
->suffix
, m
->release
, m
->patch
, m
->build
);
2473 ex
.error("Module '%s' requires version %s of module"
2474 " '%s', but only %s is available",
2475 this->modid
->get_dispname().c_str(), req_product_identifier
,
2476 req_id
->get_dispname().c_str(), mod_product_identifier
);
2477 Free(req_product_identifier
);
2478 Free(mod_product_identifier
);
2479 multi
->delete_element(i
--);
2483 // different suffixes are always incompatible
2484 // unless the special version number is used
2485 if (m
->suffix
!= exp_suffix
&& (m
->suffix
!= UINT_MAX
)) {
2486 char *req_product_identifier
=
2487 get_product_identifier(exp_product_number
,exp_suffix
, exp_rel
, exp_patch
, exp_build
);
2488 char *mod_product_identifier
=
2489 get_product_identifier(m
->product_number
,
2490 m
->suffix
, m
->release
, m
->patch
, m
->build
);
2492 ex
.error("Module '%s' requires version %s of module"
2493 " '%s', but only %s is available",
2494 this->modid
->get_dispname().c_str(), req_product_identifier
,
2495 req_id
->get_dispname().c_str(), mod_product_identifier
);
2496 Free(req_product_identifier
);
2497 Free(mod_product_identifier
);
2498 multi
->delete_element(i
--);
2502 if ( m
->release
< exp_rel
2503 ||(m
->release
== exp_rel
&& m
->patch
< exp_patch
)
2504 ||(m
->patch
== exp_patch
&& m
->build
< exp_build
)) {
2505 char *mod_bld_str
= buildstr(m
->build
);
2506 char *exp_bld_str
= buildstr(exp_build
);
2507 if (mod_bld_str
==0 || exp_bld_str
==0) FATAL_ERROR(
2508 "Ttcn::Module::chk() invalid build number");
2509 ex
.error("Module '%s' requires version R%u%c%s of module"
2510 " '%s', but only R%u%c%s is available",
2511 this->modid
->get_dispname().c_str(),
2512 exp_rel
, eri(exp_patch
), exp_bld_str
,
2513 req_id
->get_dispname().c_str(),
2514 m
->release
, eri(m
->patch
), mod_bld_str
);
2519 single
->error("No imported module named '%s'",
2520 req_id
->get_dispname().c_str());
2522 multi
->delete_element(i
--);
2526 case Ttcn::ExtensionAttribute::REQ_TITAN
: {
2527 char* exp_product_number
;
2528 unsigned int exp_suffix
, exp_minor
, exp_patch
, exp_build
;
2530 (void)ex
.get_id(exp_product_number
, exp_suffix
, exp_minor
, exp_patch
, exp_build
, exp_extra
);
2531 if (exp_product_number
!= NULL
&& strcmp(exp_product_number
,"CRL 113 200") != 0) {
2532 ex
.error("This module needs to be compiled with TITAN, but "
2533 " product number %s is not TITAN"
2534 , exp_product_number
);
2536 if (0 == exp_suffix
) {
2537 exp_suffix
= 1; // previous version number format did not list the suffix part
2539 // TTCN3_MAJOR is always 1
2540 int expected_version
= exp_suffix
* 1000000
2541 + exp_minor
* 10000 + exp_patch
* 100 + exp_build
;
2542 if (expected_version
> TTCN3_VERSION_MONOTONE
) {
2543 char *exp_product_identifier
=
2544 get_product_identifier(exp_product_number
, exp_suffix
, exp_minor
, exp_patch
, exp_build
);
2545 ex
.error("This module needs to be compiled with TITAN version"
2546 " %s or higher; version %s detected"
2547 , exp_product_identifier
, PRODUCT_NUMBER
);
2548 Free(exp_product_identifier
);
2550 multi
->delete_element(i
--);
2553 case Ttcn::ExtensionAttribute::PRINTING
: {
2554 ex
.error("Attribute 'printing' not allowed at module level");
2555 multi
->delete_element(i
--);
2561 // Let everything else propagate into the module.
2562 // Extension attributes in the module's "with" statement
2563 // may be impractical, but not outright erroneous.
2574 if (controlpart
) controlpart
->chk();
2575 if (control_ns
&& !*control_ns
) { // set but empty
2576 error("Invalid URI value for control namespace");
2578 if (control_ns_prefix
&& !*control_ns_prefix
) { // set but empty
2579 error("Empty NCName for the control namespace prefix is not allowed");
2581 // TODO proper URI and NCName validation
2584 void Module::chk_friends()
2586 map
<string
, FriendMod
> friends_m
;
2588 for(size_t i
= 0; i
< friendmods_v
.size(); i
++)
2590 FriendMod
* temp_friend
= friendmods_v
[i
];
2591 const Identifier
& friend_id
= temp_friend
->get_modid();
2592 const string
& friend_name
= friend_id
.get_name();
2593 if(friends_m
.has_key(friend_name
))
2595 temp_friend
->error("Duplicate friend module with name `%s'",
2596 friend_id
.get_dispname().c_str());
2597 friends_m
[friend_name
]->note("Friend module `%s' is already defined here",
2598 friend_id
.get_dispname().c_str());
2600 friends_m
.add(friend_name
, temp_friend
);
2603 friendmods_v
[i
]->chk();
2610 void Module::chk_groups()
2612 map
<string
,Common::Assignment
> ass_m
;
2614 for(size_t i
= 0; i
< asss
->get_nof_asss(); i
++)
2616 Common::Assignment
*temp_ass
= asss
->get_ass_byIndex(i
);
2617 if(!temp_ass
->get_parent_group())
2619 const string
& ass_name
= temp_ass
->get_id().get_name();
2620 if (!ass_m
.has_key(ass_name
)) ass_m
.add(ass_name
, temp_ass
);
2624 for(size_t i
= 0; i
< group_v
.size(); i
++)
2626 const Group
* group
= group_v
[i
];
2627 const Identifier
& group_id
= group
->get_id();
2628 const string
& group_name
= group_id
.get_name();
2629 if(ass_m
.has_key(group_name
))
2631 group
->error("Group name `%s' clashes with a definition",
2632 group_id
.get_dispname().c_str());
2633 ass_m
[group_name
]->note("Definition of `%s' is here",
2634 group_id
.get_dispname().c_str());
2636 if(group_m
.has_key(group_name
))
2638 group
->error("Duplicate group with name `%s'",
2639 group_id
.get_dispname().c_str());
2640 group_m
[group_name
]->note("Group `%s' is already defined here",
2641 group_id
.get_dispname().c_str());
2643 group_m
.add(group_name
,group_v
[i
]);
2649 for(size_t i
= 0; i
< group_v
.size(); i
++)
2655 void Module::get_imported_mods(module_set_t
& p_imported_mods
)
2657 imp
->get_imported_mods(p_imported_mods
);
2660 void Module::generate_code_internal(CodeGenHelper
& cgh
) {
2661 imp
->generate_code(cgh
);
2662 asss
->generate_code(cgh
);
2664 controlpart
->generate_code(cgh
.get_outputstruct(modid
->get_ttcnname()), this);
2667 RunsOnScope
*Module::get_runs_on_scope(Type
*comptype
)
2669 RunsOnScope
*ret_val
= new RunsOnScope(comptype
);
2670 runs_on_scopes
.add(ret_val
);
2671 ret_val
->set_parent_scope(asss
);
2672 ret_val
->chk_uniq();
2677 void Module::dump(unsigned level
) const
2679 DEBUG(level
, "TTCN-3 module: %s", modid
->get_dispname().c_str());
2681 if(imp
) imp
->dump(level
);
2682 if(asss
) asss
->dump(level
);
2684 for(size_t i
= 0; i
< group_v
.size(); i
++)
2686 group_v
[i
]->dump(level
);
2689 if(controlpart
) controlpart
->dump(level
);
2691 if (w_attrib_path
) {
2692 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2694 DEBUG(level
, "Module Attributes:");
2695 attrib
->dump(level
+ 1);
2700 void Module::set_language_spec(const char *p_language_spec
)
2702 if (language_spec
) FATAL_ERROR("Module::set_language_spec()");
2703 if (p_language_spec
) language_spec
= new string(p_language_spec
);
2706 void Module::add_ass(Definition
* p_ass
)
2708 asss
->add_ass(p_ass
);
2711 void Module::add_impmod(ImpMod
*p_impmod
)
2713 imp
->add_impmod(p_impmod
);
2716 void Module::add_controlpart(ControlPart
* p_controlpart
)
2718 if (!p_controlpart
|| controlpart
) FATAL_ERROR("Module::add_controlpart()");
2719 controlpart
= p_controlpart
;
2720 controlpart
->set_my_scope(asss
);
2723 void Module::set_with_attr(MultiWithAttrib
* p_attrib
)
2725 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2726 w_attrib_path
->set_with_attr(p_attrib
);
2729 WithAttribPath
* Module::get_attrib_path()
2731 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2732 return w_attrib_path
;
2735 void Module::set_parent_path(WithAttribPath
* p_path
)
2737 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2738 w_attrib_path
->set_parent(p_path
);
2741 bool Module::is_visible(const Identifier
& id
, visibility_t visibility
){
2743 if (visibility
== PUBLIC
) {
2746 if (visibility
== FRIEND
) {
2747 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) {
2748 if (friendmods_v
[i
]->get_modid() == id
) {
2756 void Module::generate_json_schema(JSON_Tokenizer
& json
, map
<Type
*, JSON_Tokenizer
>& json_refs
)
2758 // add a new property for this module
2759 json
.put_next_token(JSON_TOKEN_NAME
, modid
->get_ttcnname().c_str());
2761 // add type definitions into an object
2762 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2764 // cycle through each type, generate schema segment and reference when needed
2765 for (size_t i
= 0; i
< asss
->get_nof_asss(); ++i
) {
2766 Def_Type
* def
= dynamic_cast<Def_Type
*>(asss
->get_ass_byIndex(i
));
2768 Type
* t
= def
->get_Type();
2769 if (t
->has_encoding(Type::CT_JSON
)) {
2770 // insert type's schema segment
2771 t
->generate_json_schema(json
, false, false);
2773 if (json_refs_for_all_types
&& !json_refs
.has_key(t
)) {
2774 // create JSON schema reference for the type
2775 JSON_Tokenizer
* json_ref
= new JSON_Tokenizer
;
2776 json_refs
.add(t
, json_ref
);
2777 t
->generate_json_schema_ref(*json_ref
);
2783 // end of type definitions
2784 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2786 // insert function data
2787 for (size_t i
= 0; i
< asss
->get_nof_asss(); ++i
) {
2788 Def_ExtFunction
* def
= dynamic_cast<Def_ExtFunction
*>(asss
->get_ass_byIndex(i
));
2790 def
->generate_json_schema_ref(json_refs
);
2795 // =================================
2797 // =================================
2799 string
Definition::get_genname() const
2801 if (!genname
.empty()) return genname
;
2802 else return id
->get_name();
2805 namedbool
Definition::has_implicit_omit_attr() const {
2806 if (w_attrib_path
) {
2807 const vector
<SingleWithAttrib
>& real_attribs
=
2808 w_attrib_path
->get_real_attrib();
2809 for (size_t in
= real_attribs
.size(); in
> 0; in
--) {
2810 if (SingleWithAttrib::AT_OPTIONAL
==
2811 real_attribs
[in
-1]->get_attribKeyword()) {
2812 if ("implicit omit" ==
2813 real_attribs
[in
-1]->get_attribSpec().get_spec()) {
2814 return IMPLICIT_OMIT
;
2815 } else if ("explicit omit" ==
2816 real_attribs
[in
-1]->get_attribSpec().get_spec()) {
2817 return NOT_IMPLICIT_OMIT
;
2818 } // error reporting for other values is in chk_global_attrib
2822 return NOT_IMPLICIT_OMIT
;
2825 Definition::~Definition()
2827 delete w_attrib_path
;
2828 delete erroneous_attrs
;
2831 void Definition::set_fullname(const string
& p_fullname
)
2833 Common::Assignment::set_fullname(p_fullname
);
2834 if (w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
2835 if (erroneous_attrs
) erroneous_attrs
->set_fullname(p_fullname
+".<erroneous_attributes>");
2838 bool Definition::is_local() const
2840 if (!my_scope
) FATAL_ERROR("Definition::is_local()");
2841 for (Scope
*scope
= my_scope
; scope
; scope
= scope
->get_parent_scope()) {
2842 if (dynamic_cast<StatementBlock
*>(scope
)) return true;
2847 bool Definition::chk_identical(Definition
*)
2849 FATAL_ERROR("Definition::chk_identical()");
2853 void Definition::chk_erroneous_attr()
2855 if (!w_attrib_path
) return;
2856 const Ttcn::MultiWithAttrib
* attribs
= w_attrib_path
->get_local_attrib();
2857 if (!attribs
) return;
2858 for (size_t i
= 0; i
< attribs
->get_nof_elements(); i
++) {
2859 const Ttcn::SingleWithAttrib
* act_attr
= attribs
->get_element(i
);
2860 if (act_attr
->get_attribKeyword()==Ttcn::SingleWithAttrib::AT_ERRONEOUS
) {
2861 if (!use_runtime_2
) {
2862 error("`erroneous' attributes can be used only with the Function Test Runtime");
2863 note("If you need negative testing use the -R flag when generating the makefile");
2866 size_t nof_qualifiers
= act_attr
->get_attribQualifiers() ? act_attr
->get_attribQualifiers()->get_nof_qualifiers() : 0;
2867 dynamic_array
<Type
*> refd_type_array(nof_qualifiers
); // only the qualifiers pointing to existing fields will be added to erroneous_attrs objects
2868 if (nof_qualifiers
==0) {
2869 act_attr
->error("At least one qualifier must be specified for the `erroneous' attribute");
2871 // check if qualifiers point to existing fields
2872 for (size_t qi
=0; qi
<nof_qualifiers
; qi
++) {
2873 Qualifier
* act_qual
= const_cast<Qualifier
*>(act_attr
->get_attribQualifiers()->get_qualifier(qi
));
2874 act_qual
->set_my_scope(get_my_scope());
2875 Type
* field_type
= get_Type()->get_field_type(act_qual
, Type::EXPECTED_CONSTANT
);
2877 dynamic_array
<size_t> subrefs_array
;
2878 dynamic_array
<Type
*> type_array
;
2879 bool valid_indexes
= get_Type()->get_subrefs_as_array(act_qual
, subrefs_array
, type_array
);
2880 if (!valid_indexes
) field_type
= NULL
;
2881 if (act_qual
->refers_to_string_element()) {
2882 act_qual
->error("Reference to a string element cannot be used in this context");
2886 refd_type_array
.add(field_type
);
2889 // parse the attr. spec.
2890 ErroneousAttributeSpec
* err_attr_spec
= ttcn3_parse_erroneous_attr_spec_string(
2891 act_attr
->get_attribSpec().get_spec().c_str(), act_attr
->get_attribSpec());
2892 if (err_attr_spec
) {
2893 if (!erroneous_attrs
) erroneous_attrs
= new ErroneousAttributes(get_Type());
2894 // attr.spec will be owned by erroneous_attrs object
2895 erroneous_attrs
->add_spec(err_attr_spec
);
2896 err_attr_spec
->set_fullname(get_fullname());
2897 err_attr_spec
->set_my_scope(get_my_scope());
2898 err_attr_spec
->chk();
2899 // create qualifier - err.attr.spec. pairs
2900 for (size_t qi
=0; qi
<nof_qualifiers
; qi
++) {
2901 if (refd_type_array
[qi
] && (err_attr_spec
->get_indicator()!=ErroneousAttributeSpec::I_INVALID
)) {
2902 erroneous_attrs
->add_pair(act_attr
->get_attribQualifiers()->get_qualifier(qi
), err_attr_spec
);
2908 if (erroneous_attrs
) erroneous_attrs
->chk();
2911 char* Definition::generate_code_str(char *str
)
2913 FATAL_ERROR("Definition::generate_code_str()");
2917 void Definition::ilt_generate_code(ILT
*)
2919 FATAL_ERROR("Definition::ilt_generate_code()");
2922 char *Definition::generate_code_init_comp(char *str
, Definition
*)
2924 FATAL_ERROR("Definition::generate_code_init_comp()");
2928 void Definition::set_with_attr(MultiWithAttrib
* p_attrib
)
2930 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2931 w_attrib_path
->set_with_attr(p_attrib
);
2934 WithAttribPath
* Definition::get_attrib_path()
2936 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2937 return w_attrib_path
;
2940 void Definition::set_parent_path(WithAttribPath
* p_path
)
2942 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2943 w_attrib_path
->set_parent(p_path
);
2946 void Definition::set_parent_group(Group
* p_group
)
2948 if(parentgroup
) // there would be a leak!
2949 FATAL_ERROR("Definition::set_parent_group()");
2950 parentgroup
= p_group
;
2953 Group
* Definition::get_parent_group()
2958 void Definition::dump_internal(unsigned level
) const
2960 DEBUG(level
, "Move along, nothing to see here");
2963 void Definition::dump(unsigned level
) const
2965 dump_internal(level
);
2966 if (w_attrib_path
) {
2967 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2969 DEBUG(level
+ 1, "Definition Attributes:");
2970 attrib
->dump(level
+ 2);
2973 if (erroneous_attrs
) erroneous_attrs
->dump(level
+1);
2976 // =================================
2978 // =================================
2980 Def_Type::Def_Type(Identifier
*p_id
, Type
*p_type
)
2981 : Definition(A_TYPE
, p_id
), type(p_type
)
2983 if(!p_type
) FATAL_ERROR("Ttcn::Def_Type::Def_Type()");
2984 type
->set_ownertype(Type::OT_TYPE_DEF
, this);
2987 Def_Type::~Def_Type()
2992 Def_Type
*Def_Type::clone() const
2994 FATAL_ERROR("Def_Type::clone");
2997 void Def_Type::set_fullname(const string
& p_fullname
)
2999 Definition::set_fullname(p_fullname
);
3000 type
->set_fullname(p_fullname
);
3003 void Def_Type::set_my_scope(Scope
*p_scope
)
3005 bridgeScope
.set_parent_scope(p_scope
);
3006 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
3008 Definition::set_my_scope(&bridgeScope
);
3009 type
->set_my_scope(&bridgeScope
);
3013 Setting
*Def_Type::get_Setting()
3018 Type
*Def_Type::get_Type()
3024 void Def_Type::chk()
3026 if (checked
) return;
3028 Error_Context
cntxt(this, "In %s definition `%s'",
3029 type
->get_typetype() == Type::T_SIGNATURE
? "signature" : "type",
3030 id
->get_dispname().c_str());
3031 type
->set_genname(get_genname());
3032 if (!semantic_check_only
&& type
->get_typetype() == Type::T_COMPONENT
) {
3033 // the prefix of embedded definitions must be set before the checking
3034 type
->get_CompBody()->set_genname(get_genname() + "_component_");
3037 while (w_attrib_path
) { // not a loop, but we can _break_ out of it
3038 w_attrib_path
->chk_global_attrib();
3039 w_attrib_path
->chk_no_qualif();
3040 if (type
->get_typetype() != Type::T_ANYTYPE
) break;
3041 // This is the anytype; it must be empty (we're about to add the fields)
3042 if (type
->get_nof_comps() > 0) FATAL_ERROR("Def_Type::chk");
3044 Ttcn::ExtensionAttributes
*extattrs
= parse_extattributes(w_attrib_path
);
3045 if (extattrs
== 0) break; // NULL means parsing error
3047 size_t num_atrs
= extattrs
->size();
3048 for (size_t k
= 0; k
< num_atrs
; ++k
) {
3049 ExtensionAttribute
&ea
= extattrs
->get(k
);
3050 switch (ea
.get_type()) {
3051 case ExtensionAttribute::ANYTYPELIST
: {
3052 Types
*anytypes
= ea
.get_types();
3053 // List of types to be converted into fields for the anytype.
3054 // Make sure scope is set on all types in the list.
3055 anytypes
->set_my_scope(get_my_scope());
3057 // Convert the list of types into field names for the anytype
3058 for (size_t i
=0; i
< anytypes
->get_nof_types(); ++i
) {
3059 Type
*t
= anytypes
->extract_type_byIndex(i
);
3060 // we are now the owner of the Type.
3061 if (t
->get_typetype()==Type::T_ERROR
) { // should we give up?
3067 const char* btn
= Type::get_typename_builtin(t
->get_typetype());
3071 else if (t
->get_typetype() == Type::T_REFD
) {
3072 // Extract the identifier
3073 Common::Reference
*ref
= t
->get_Reference();
3074 Ttcn::Reference
*tref
= dynamic_cast<Ttcn::Reference
*>(ref
);
3075 if (!tref
) FATAL_ERROR("Def_Type::chk, wrong kind of reference");
3076 const Common::Identifier
*modid
= tref
->get_modid();
3078 ea
.error("Qualified name '%s' cannot be added to the anytype",
3079 tref
->get_dispname().c_str());
3083 field_name
= tref
->get_id()->get_ttcnname();
3086 // Can't happen here
3087 FATAL_ERROR("Unexpected type %d", t
->get_typetype());
3090 const string
& at_field
= anytype_field(field_name
);
3091 Identifier
*field_id
= new Identifier(Identifier::ID_TTCN
, at_field
);
3092 CompField
*cf
= new CompField(field_id
, t
, false, 0);
3093 cf
->set_location(ea
);
3094 cf
->set_fullname(get_fullname());
3100 w_attrib_path
->get_with_attr()->error("Type def can only have anytype");
3106 break; // do not loop
3109 // Now we can check the type
3111 type
->chk_constructor_name(*id
);
3112 if (id
->get_ttcnname() == "address") type
->chk_address();
3113 ReferenceChain
refch(type
, "While checking embedded recursions");
3114 type
->chk_recursions(refch
);
3116 if (type
->get_typetype()==Type::T_FUNCTION
3117 ||type
->get_typetype()==Type::T_ALTSTEP
3118 ||type
->get_typetype()==Type::T_TESTCASE
) {
3119 // TR 922. This is a function/altstep/testcase reference.
3120 // Set this definition as the definition for the formal parameters.
3121 type
->get_fat_parameters()->set_my_def(this);
3125 void Def_Type::generate_code(output_struct
*target
, bool)
3127 type
->generate_code(target
);
3128 if (type
->get_typetype() == Type::T_COMPONENT
) {
3129 // the C++ equivalents of embedded component element definitions must be
3130 // generated from outside Type::generate_code() because the function can
3131 // call itself recursively and create invalid (overlapped) initializer
3133 type
->get_CompBody()->generate_code(target
);
3137 void Def_Type::generate_code(CodeGenHelper
& cgh
) {
3138 type
->generate_code(cgh
.get_outputstruct(get_Type()));
3139 if (type
->get_typetype() == Type::T_COMPONENT
) {
3140 // the C++ equivalents of embedded component element definitions must be
3141 // generated from outside Type::generate_code() because the function can
3142 // call itself recursively and create invalid (overlapped) initializer
3144 type
->get_CompBody()->generate_code(cgh
.get_current_outputstruct());
3146 cgh
.finalize_generation(get_Type());
3150 void Def_Type::dump_internal(unsigned level
) const
3152 DEBUG(level
, "Type def: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3153 type
->dump(level
+ 1);
3156 void Def_Type::set_with_attr(MultiWithAttrib
* p_attrib
)
3158 if (!w_attrib_path
) {
3159 w_attrib_path
= new WithAttribPath();
3160 type
->set_parent_path(w_attrib_path
);
3162 type
->set_with_attr(p_attrib
);
3165 WithAttribPath
* Def_Type::get_attrib_path()
3167 if (!w_attrib_path
) {
3168 w_attrib_path
= new WithAttribPath();
3169 type
->set_parent_path(w_attrib_path
);
3171 return w_attrib_path
;
3174 void Def_Type::set_parent_path(WithAttribPath
* p_path
)
3176 if (!w_attrib_path
) {
3177 w_attrib_path
= new WithAttribPath();
3178 type
->set_parent_path(w_attrib_path
);
3180 w_attrib_path
->set_parent(p_path
);
3183 // =================================
3185 // =================================
3187 Def_Const::Def_Const(Identifier
*p_id
, Type
*p_type
, Value
*p_value
)
3188 : Definition(A_CONST
, p_id
)
3190 if (!p_type
|| !p_value
) FATAL_ERROR("Ttcn::Def_Const::Def_Const()");
3192 type
->set_ownertype(Type::OT_CONST_DEF
, this);
3194 value_under_check
=false;
3197 Def_Const::~Def_Const()
3203 Def_Const
*Def_Const::clone() const
3205 FATAL_ERROR("Def_Const::clone");
3208 void Def_Const::set_fullname(const string
& p_fullname
)
3210 Definition::set_fullname(p_fullname
);
3211 type
->set_fullname(p_fullname
+ ".<type>");
3212 value
->set_fullname(p_fullname
);
3215 void Def_Const::set_my_scope(Scope
*p_scope
)
3217 Definition::set_my_scope(p_scope
);
3218 type
->set_my_scope(p_scope
);
3219 value
->set_my_scope(p_scope
);
3222 Setting
*Def_Const::get_Setting()
3227 Type
*Def_Const::get_Type()
3234 Value
*Def_Const::get_Value()
3240 void Def_Const::chk()
3243 if (value_under_check
) {
3244 error("Circular reference in constant definition `%s'",
3245 id
->get_dispname().c_str());
3246 value_under_check
= false; // only report the error once for this definition
3250 Error_Context
cntxt(this, "In constant definition `%s'",
3251 id
->get_dispname().c_str());
3252 type
->set_genname(_T_
, get_genname());
3254 value
->set_my_governor(type
);
3255 type
->chk_this_value_ref(value
);
3257 if (w_attrib_path
) {
3258 w_attrib_path
->chk_global_attrib(true);
3259 switch (type
->get_type_refd_last()->get_typetype_ttcn3()) {
3262 case Type::T_CHOICE_T
:
3263 // These types may have qualified attributes
3265 case Type::T_SEQOF
: case Type::T_SETOF
:
3268 w_attrib_path
->chk_no_qualif();
3272 Type
*t
= type
->get_type_refd_last();
3273 switch (t
->get_typetype()) {
3275 error("Constant cannot be defined for port type `%s'",
3276 t
->get_fullname().c_str());
3278 case Type::T_SIGNATURE
:
3279 error("Constant cannot be defined for signature `%s'",
3280 t
->get_fullname().c_str());
3283 value_under_check
= true;
3284 type
->chk_this_value(value
, 0, Type::EXPECTED_CONSTANT
, INCOMPLETE_ALLOWED
,
3285 OMIT_NOT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr());
3286 value_under_check
= false;
3287 chk_erroneous_attr();
3288 if (erroneous_attrs
) value
->set_err_descr(erroneous_attrs
->get_err_descr());
3290 ReferenceChain
refch(type
, "While checking embedded recursions");
3291 value
->chk_recursions(refch
);
3295 if (!semantic_check_only
) {
3296 value
->set_genname_prefix("const_");
3297 value
->set_genname_recursive(get_genname());
3298 value
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3302 bool Def_Const::chk_identical(Definition
*p_def
)
3306 if (p_def
->get_asstype() != A_CONST
) {
3307 const char *dispname_str
= id
->get_dispname().c_str();
3308 error("Local definition `%s' is a constant, but the definition "
3309 "inherited from component type `%s' is a %s", dispname_str
,
3310 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
3311 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
3314 Def_Const
*p_def_const
= dynamic_cast<Def_Const
*>(p_def
);
3315 if (!p_def_const
) FATAL_ERROR("Def_Const::chk_identical()");
3316 if (!type
->is_identical(p_def_const
->type
)) {
3317 const char *dispname_str
= id
->get_dispname().c_str();
3318 type
->error("Local constant `%s' has type `%s', but the constant "
3319 "inherited from component type `%s' has type `%s'", dispname_str
,
3320 type
->get_typename().c_str(),
3321 p_def_const
->get_my_scope()->get_fullname().c_str(),
3322 p_def_const
->type
->get_typename().c_str());
3323 p_def_const
->note("The inherited constant `%s' is here", dispname_str
);
3325 } else if (!(*value
== *p_def_const
->value
)) {
3326 const char *dispname_str
= id
->get_dispname().c_str();
3327 value
->error("Local constant `%s' and the constant inherited from "
3328 "component type `%s' have different values", dispname_str
,
3329 p_def_const
->get_my_scope()->get_fullname().c_str());
3330 p_def_const
->note("The inherited constant `%s' is here", dispname_str
);
3335 void Def_Const::generate_code(output_struct
*target
, bool)
3337 type
->generate_code(target
);
3339 Code::init_cdef(&cdef
);
3340 type
->generate_code_object(&cdef
, value
);
3341 cdef
.init
= update_location_object(cdef
.init
);
3342 cdef
.init
= value
->generate_code_init(cdef
.init
,
3343 value
->get_lhs_name().c_str());
3344 Code::merge_cdef(target
, &cdef
);
3345 Code::free_cdef(&cdef
);
3348 void Def_Const::generate_code(Common::CodeGenHelper
& cgh
) {
3349 // constant definitions always go to its containing module
3350 generate_code(cgh
.get_current_outputstruct());
3353 char *Def_Const::generate_code_str(char *str
)
3355 const string
& t_genname
= get_genname();
3356 const char *genname_str
= t_genname
.c_str();
3357 if (value
->has_single_expr()) {
3358 // the value can be represented by a single C++ expression
3359 // the object is initialized by the constructor
3360 str
= mputprintf(str
, "%s %s(%s);\n",
3361 type
->get_genname_value(my_scope
).c_str(), genname_str
,
3362 value
->get_single_expr().c_str());
3364 // use the default constructor
3365 str
= mputprintf(str
, "%s %s;\n",
3366 type
->get_genname_value(my_scope
).c_str(), genname_str
);
3367 // the value is assigned using subsequent statements
3368 str
= value
->generate_code_init(str
, genname_str
);
3373 void Def_Const::ilt_generate_code(ILT
*ilt
)
3375 const string
& t_genname
= get_genname();
3376 const char *genname_str
= t_genname
.c_str();
3377 char*& def
=ilt
->get_out_def();
3378 char*& init
=ilt
->get_out_branches();
3379 def
= mputprintf(def
, "%s %s;\n", type
->get_genname_value(my_scope
).c_str(),
3381 init
= value
->generate_code_init(init
, genname_str
);
3384 char *Def_Const::generate_code_init_comp(char *str
, Definition
*)
3386 /* This function actually does nothing as \a this and \a base_defn are
3387 * exactly the same. */
3391 void Def_Const::dump_internal(unsigned level
) const
3393 DEBUG(level
, "Constant: %s @%p", id
->get_dispname().c_str(), (const void*)this);
3394 type
->dump(level
+ 1);
3395 value
->dump(level
+ 1);
3398 // =================================
3399 // ===== Def_ExtConst
3400 // =================================
3402 Def_ExtConst::Def_ExtConst(Identifier
*p_id
, Type
*p_type
)
3403 : Definition(A_EXT_CONST
, p_id
)
3405 if (!p_type
) FATAL_ERROR("Ttcn::Def_ExtConst::Def_ExtConst()");
3407 type
->set_ownertype(Type::OT_CONST_DEF
, this);
3410 Def_ExtConst::~Def_ExtConst()
3415 Def_ExtConst
*Def_ExtConst::clone() const
3417 FATAL_ERROR("Def_ExtConst::clone");
3420 void Def_ExtConst::set_fullname(const string
& p_fullname
)
3422 Definition::set_fullname(p_fullname
);
3423 type
->set_fullname(p_fullname
+ ".<type>");
3426 void Def_ExtConst::set_my_scope(Scope
*p_scope
)
3428 Definition::set_my_scope(p_scope
);
3429 type
->set_my_scope(p_scope
);
3432 Type
*Def_ExtConst::get_Type()
3438 void Def_ExtConst::chk()
3441 Error_Context
cntxt(this, "In external constant definition `%s'",
3442 id
->get_dispname().c_str());
3443 type
->set_genname(_T_
, get_genname());
3446 Type
*t
= type
->get_type_refd_last();
3447 switch (t
->get_typetype()) {
3449 error("External constant cannot be defined for port type `%s'",
3450 t
->get_fullname().c_str());
3452 case Type::T_SIGNATURE
:
3453 error("External constant cannot be defined for signature `%s'",
3454 t
->get_fullname().c_str());
3459 if (w_attrib_path
) {
3460 w_attrib_path
->chk_global_attrib();
3461 switch (type
->get_type_refd_last()->get_typetype()) {
3464 case Type::T_CHOICE_T
:
3465 // These types may have qualified attributes
3467 case Type::T_SEQOF
: case Type::T_SETOF
:
3470 w_attrib_path
->chk_no_qualif();
3476 void Def_ExtConst::generate_code(output_struct
*target
, bool)
3478 type
->generate_code(target
);
3479 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
3480 "extern const %s& %s;\n", type
->get_genname_value(my_scope
).c_str(),
3481 get_genname().c_str());
3484 void Def_ExtConst::generate_code(Common::CodeGenHelper
& cgh
) {
3485 // constant definitions always go to its containing module
3486 generate_code(cgh
.get_current_outputstruct());
3489 void Def_ExtConst::dump_internal(unsigned level
) const
3491 DEBUG(level
, "External constant: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3492 type
->dump(level
+ 1);
3495 // =================================
3496 // ===== Def_Modulepar
3497 // =================================
3499 Def_Modulepar::Def_Modulepar(Identifier
*p_id
, Type
*p_type
, Value
*p_defval
)
3500 : Definition(A_MODULEPAR
, p_id
)
3502 if (!p_type
) FATAL_ERROR("Ttcn::Def_Modulepar::Def_Modulepar()");
3504 type
->set_ownertype(Type::OT_MODPAR_DEF
, this);
3505 def_value
= p_defval
;
3508 Def_Modulepar::~Def_Modulepar()
3514 Def_Modulepar
* Def_Modulepar::clone() const
3516 FATAL_ERROR("Def_Modulepar::clone");
3519 void Def_Modulepar::set_fullname(const string
& p_fullname
)
3521 Definition::set_fullname(p_fullname
);
3522 type
->set_fullname(p_fullname
+ ".<type>");
3523 if (def_value
) def_value
->set_fullname(p_fullname
+ ".<default_value>");
3526 void Def_Modulepar::set_my_scope(Scope
*p_scope
)
3528 Definition::set_my_scope(p_scope
);
3529 type
->set_my_scope(p_scope
);
3530 if (def_value
) def_value
->set_my_scope(p_scope
);
3533 Type
*Def_Modulepar::get_Type()
3539 void Def_Modulepar::chk()
3542 Error_Context
cntxt(this, "In module parameter definition `%s'",
3543 id
->get_dispname().c_str());
3544 type
->set_genname(_T_
, get_genname());
3546 if (w_attrib_path
) {
3547 w_attrib_path
->chk_global_attrib();
3548 switch (type
->get_type_refd_last()->get_typetype()) {
3551 case Type::T_CHOICE_T
:
3552 // These types may have qualified attributes
3554 case Type::T_SEQOF
: case Type::T_SETOF
:
3557 w_attrib_path
->chk_no_qualif();
3561 map
<Type
*,void> type_chain
;
3562 map
<Type::typetype_t
, void> not_allowed
;
3563 not_allowed
.add(Type::T_PORT
, 0);
3564 Type
*t
= type
->get_type_refd_last();
3565 // if the type is valid the original will be returned
3566 Type::typetype_t tt
= t
->search_for_not_allowed_type(type_chain
, not_allowed
);
3568 not_allowed
.clear();
3571 error("Type of module parameter cannot be or embed port type `%s'",
3572 t
->get_fullname().c_str());
3574 case Type::T_SIGNATURE
:
3575 error("Type of module parameter cannot be signature `%s'",
3576 t
->get_fullname().c_str());
3578 case Type::T_FUNCTION
:
3579 case Type::T_ALTSTEP
:
3580 case Type::T_TESTCASE
:
3581 if (t
->get_fat_runs_on_self()) {
3582 error("Type of module parameter cannot be of function reference type"
3583 " `%s' which has runs on self clause", t
->get_fullname().c_str());
3591 Error_Context
cntxt2(def_value
, "In default value");
3592 def_value
->set_my_governor(type
);
3593 type
->chk_this_value_ref(def_value
);
3595 type
->chk_this_value(def_value
, 0, Type::EXPECTED_CONSTANT
, INCOMPLETE_ALLOWED
,
3596 OMIT_NOT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr());
3597 if (!semantic_check_only
) {
3598 def_value
->set_genname_prefix("modulepar_");
3599 def_value
->set_genname_recursive(get_genname());
3600 def_value
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3602 } else checked
= true;
3608 void Def_Modulepar::generate_code(output_struct
*target
, bool)
3610 type
->generate_code(target
);
3612 Code::init_cdef(&cdef
);
3613 const string
& t_genname
= get_genname();
3614 const char *name
= t_genname
.c_str();
3615 type
->generate_code_object(&cdef
, my_scope
, t_genname
, "modulepar_", false);
3617 cdef
.init
= update_location_object(cdef
.init
);
3618 cdef
.init
= def_value
->generate_code_init(cdef
.init
, def_value
->get_lhs_name().c_str());
3620 Code::merge_cdef(target
, &cdef
);
3621 Code::free_cdef(&cdef
);
3623 if (has_implicit_omit_attr()) {
3624 target
->functions
.post_init
= mputprintf(target
->functions
.post_init
,
3625 "modulepar_%s.set_implicit_omit();\n", name
);
3628 const char *dispname
= id
->get_dispname().c_str();
3629 target
->functions
.set_param
= mputprintf(target
->functions
.set_param
,
3630 "if (!strcmp(par_name, \"%s\")) {\n"
3631 "modulepar_%s.set_param(param);\n"
3633 "} else ", dispname
, name
);
3634 target
->functions
.get_param
= mputprintf(target
->functions
.get_param
,
3635 "if (!strcmp(par_name, \"%s\")) {\n"
3636 "return modulepar_%s.get_param(param_name);\n"
3637 "} else ", dispname
, name
);
3639 if (target
->functions
.log_param
) {
3640 // this is not the first modulepar
3641 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3642 "TTCN_Logger::log_event_str(\", %s := \");\n", dispname
);
3644 // this is the first modulepar
3645 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3646 "TTCN_Logger::log_event_str(\"%s := \");\n", dispname
);
3648 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3649 "%s.log();\n", name
);
3652 void Def_Modulepar::generate_code(Common::CodeGenHelper
& cgh
) {
3653 // module parameter definitions always go to its containing module
3654 generate_code(cgh
.get_current_outputstruct());
3657 void Def_Modulepar::dump_internal(unsigned level
) const
3659 DEBUG(level
, "Module parameter: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3660 type
->dump(level
+ 1);
3661 if (def_value
) def_value
->dump(level
+ 1);
3662 else DEBUG(level
+ 1, "No default value");
3665 // =================================
3666 // ===== Def_Modulepar_Template
3667 // =================================
3669 Def_Modulepar_Template::Def_Modulepar_Template(Identifier
*p_id
, Type
*p_type
, Template
*p_deftmpl
)
3670 : Definition(A_MODULEPAR_TEMP
, p_id
)
3672 if (!p_type
) FATAL_ERROR("Ttcn::Def_Modulepar_Template::Def_Modulepar_Template()");
3674 type
->set_ownertype(Type::OT_MODPAR_DEF
, this);
3675 def_template
= p_deftmpl
;
3678 Def_Modulepar_Template::~Def_Modulepar_Template()
3681 delete def_template
;
3684 Def_Modulepar_Template
* Def_Modulepar_Template::clone() const
3686 FATAL_ERROR("Def_Modulepar_Template::clone");
3689 void Def_Modulepar_Template::set_fullname(const string
& p_fullname
)
3691 Definition::set_fullname(p_fullname
);
3692 type
->set_fullname(p_fullname
+ ".<type>");
3693 if (def_template
) def_template
->set_fullname(p_fullname
+ ".<default_template>");
3696 void Def_Modulepar_Template::set_my_scope(Scope
*p_scope
)
3698 Definition::set_my_scope(p_scope
);
3699 type
->set_my_scope(p_scope
);
3700 if (def_template
) def_template
->set_my_scope(p_scope
);
3703 Type
*Def_Modulepar_Template::get_Type()
3709 void Def_Modulepar_Template::chk()
3712 Error_Context
cntxt(this, "In template module parameter definition `%s'",
3713 id
->get_dispname().c_str());
3714 if (w_attrib_path
) {
3715 w_attrib_path
->chk_global_attrib();
3716 switch (type
->get_type_refd_last()->get_typetype()) {
3719 case Type::T_CHOICE_T
:
3720 // These types may have qualified attributes
3722 case Type::T_SEQOF
: case Type::T_SETOF
:
3725 w_attrib_path
->chk_no_qualif();
3729 type
->set_genname(_T_
, get_genname());
3731 Type
*t
= type
->get_type_refd_last();
3732 switch (t
->get_typetype()) {
3734 error("Type of template module parameter cannot be port type `%s'",
3735 t
->get_fullname().c_str());
3737 case Type::T_SIGNATURE
:
3738 error("Type of template module parameter cannot be signature `%s'",
3739 t
->get_fullname().c_str());
3741 case Type::T_FUNCTION
:
3742 case Type::T_ALTSTEP
:
3743 case Type::T_TESTCASE
:
3744 if (t
->get_fat_runs_on_self()) {
3745 error("Type of template module parameter cannot be of function reference type"
3746 " `%s' which has runs on self clause", t
->get_fullname().c_str());
3750 if (has_implicit_omit_attr()) {
3751 error("Implicit omit not supported for template module parameters");
3757 Error_Context
cntxt2(def_template
, "In default template");
3758 def_template
->set_my_governor(type
);
3759 def_template
->flatten(false);
3760 if (def_template
->get_templatetype() == Template::CSTR_PATTERN
&&
3761 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
3762 def_template
->set_templatetype(Template::USTR_PATTERN
);
3763 def_template
->get_ustr_pattern()->set_pattern_type(
3764 PatternString::USTR_PATTERN
);
3766 type
->chk_this_template_ref(def_template
);
3768 type
->chk_this_template_generic(def_template
, INCOMPLETE_ALLOWED
,
3769 OMIT_ALLOWED
, ANY_OR_OMIT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr() ? IMPLICIT_OMIT
: NOT_IMPLICIT_OMIT
, 0);
3770 if (!semantic_check_only
) {
3771 def_template
->set_genname_prefix("modulepar_");
3772 def_template
->set_genname_recursive(get_genname());
3773 def_template
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3775 } else checked
= true;
3781 void Def_Modulepar_Template::generate_code(output_struct
*target
, bool)
3783 type
->generate_code(target
);
3785 Code::init_cdef(&cdef
);
3786 const string
& t_genname
= get_genname();
3787 const char *name
= t_genname
.c_str();
3788 type
->generate_code_object(&cdef
, my_scope
, t_genname
, "modulepar_", true);
3790 cdef
.init
= update_location_object(cdef
.init
);
3791 cdef
.init
= def_template
->generate_code_init(cdef
.init
, def_template
->get_lhs_name().c_str());
3793 Code::merge_cdef(target
, &cdef
);
3794 Code::free_cdef(&cdef
);
3796 if (has_implicit_omit_attr()) {
3797 FATAL_ERROR("Def_Modulepar_Template::generate_code()");
3800 const char *dispname
= id
->get_dispname().c_str();
3801 target
->functions
.set_param
= mputprintf(target
->functions
.set_param
,
3802 "if (!strcmp(par_name, \"%s\")) {\n"
3803 "modulepar_%s.set_param(param);\n"
3805 "} else ", dispname
, name
);
3806 target
->functions
.get_param
= mputprintf(target
->functions
.get_param
,
3807 "if (!strcmp(par_name, \"%s\")) {\n"
3808 "return modulepar_%s.get_param(param_name);\n"
3809 "} else ", dispname
, name
);
3811 if (target
->functions
.log_param
) {
3812 // this is not the first modulepar
3813 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3814 "TTCN_Logger::log_event_str(\", %s := \");\n", dispname
);
3816 // this is the first modulepar
3817 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3818 "TTCN_Logger::log_event_str(\"%s := \");\n", dispname
);
3820 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3821 "%s.log();\n", name
);
3824 void Def_Modulepar_Template::generate_code(Common::CodeGenHelper
& cgh
) {
3825 // module parameter definitions always go to its containing module
3826 generate_code(cgh
.get_current_outputstruct());
3829 void Def_Modulepar_Template::dump_internal(unsigned level
) const
3831 DEBUG(level
, "Module parameter: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3832 type
->dump(level
+ 1);
3833 if (def_template
) def_template
->dump(level
+ 1);
3834 else DEBUG(level
+ 1, "No default template");
3837 // =================================
3838 // ===== Def_Template
3839 // =================================
3841 Def_Template::Def_Template(template_restriction_t p_template_restriction
,
3842 Identifier
*p_id
, Type
*p_type
, FormalParList
*p_fpl
,
3843 Reference
*p_derived_ref
, Template
*p_body
)
3844 : Definition(A_TEMPLATE
, p_id
), type(p_type
), fp_list(p_fpl
),
3845 derived_ref(p_derived_ref
), base_template(0), recurs_deriv_checked(false),
3846 body(p_body
), template_restriction(p_template_restriction
),
3847 gen_restriction_check(false)
3849 if (!p_type
|| !p_body
) FATAL_ERROR("Ttcn::Def_Template::Def_Template()");
3850 type
->set_ownertype(Type::OT_TEMPLATE_DEF
, this);
3851 if (fp_list
) fp_list
->set_my_def(this);
3854 Def_Template::~Def_Template()
3862 Def_Template
*Def_Template::clone() const
3864 FATAL_ERROR("Def_Template::clone");
3867 void Def_Template::set_fullname(const string
& p_fullname
)
3869 Definition::set_fullname(p_fullname
);
3870 type
->set_fullname(p_fullname
+ ".<type>");
3871 if (fp_list
) fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
3873 derived_ref
->set_fullname(p_fullname
+ ".<derived_reference>");
3874 body
->set_fullname(p_fullname
);
3877 void Def_Template::set_my_scope(Scope
*p_scope
)
3879 bridgeScope
.set_parent_scope(p_scope
);
3880 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
3882 Definition::set_my_scope(&bridgeScope
);
3883 type
->set_my_scope(&bridgeScope
);
3884 if (derived_ref
) derived_ref
->set_my_scope(&bridgeScope
);
3886 fp_list
->set_my_scope(&bridgeScope
);
3887 body
->set_my_scope(fp_list
);
3888 } else body
->set_my_scope(&bridgeScope
);
3891 Setting
*Def_Template::get_Setting()
3893 return get_Template();
3896 Type
*Def_Template::get_Type()
3898 if (!checked
) chk();
3902 Template
*Def_Template::get_Template()
3904 if (!checked
) chk();
3908 FormalParList
*Def_Template::get_FormalParList()
3910 if (!checked
) chk();
3914 void Def_Template::chk()
3916 if (checked
) return;
3917 Error_Context
cntxt(this, "In template definition `%s'",
3918 id
->get_dispname().c_str());
3919 const string
& t_genname
= get_genname();
3920 type
->set_genname(_T_
, t_genname
);
3922 if (w_attrib_path
) {
3923 w_attrib_path
->chk_global_attrib(true);
3924 switch (type
->get_type_refd_last()->get_typetype_ttcn3()) {
3927 case Type::T_CHOICE_T
:
3928 // These types may have qualified attributes
3930 case Type::T_SEQOF
: case Type::T_SETOF
:
3933 w_attrib_path
->chk_no_qualif();
3939 fp_list
->chk(asstype
);
3940 if (local_scope
) error("Parameterized local template `%s' not supported",
3941 id
->get_dispname().c_str());
3944 // Merge the elements of "all from" into the list
3945 body
->flatten(false);
3947 body
->set_my_governor(type
);
3949 if (body
->get_templatetype() == Template::CSTR_PATTERN
&&
3950 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
3951 body
->set_templatetype(Template::USTR_PATTERN
);
3952 body
->get_ustr_pattern()->set_pattern_type(PatternString::USTR_PATTERN
);
3955 type
->chk_this_template_ref(body
);
3957 Type
*t
= type
->get_type_refd_last();
3958 if (t
->get_typetype() == Type::T_PORT
) {
3959 error("Template cannot be defined for port type `%s'",
3960 t
->get_fullname().c_str());
3963 chk_recursive_derivation();
3964 type
->chk_this_template_generic(body
, INCOMPLETE_ALLOWED
, OMIT_ALLOWED
,
3965 ANY_OR_OMIT_ALLOWED
, SUB_CHK
,
3966 has_implicit_omit_attr() ? IMPLICIT_OMIT
: NOT_IMPLICIT_OMIT
, 0);
3968 chk_erroneous_attr();
3969 if (erroneous_attrs
) body
->set_err_descr(erroneous_attrs
->get_err_descr());
3972 ReferenceChain
refch(type
, "While checking embedded recursions");
3973 body
->chk_recursions(refch
);
3975 if (template_restriction
!=TR_NONE
) {
3976 Error_Context
ec(this, "While checking template restriction `%s'",
3977 Template::get_restriction_name(template_restriction
));
3978 gen_restriction_check
=
3979 body
->chk_restriction("template definition", template_restriction
, body
);
3980 if (fp_list
&& template_restriction
!=TR_PRESENT
) {
3981 size_t nof_fps
= fp_list
->get_nof_fps();
3982 for (size_t i
=0; i
<nof_fps
; i
++) {
3983 FormalPar
* fp
= fp_list
->get_fp_byIndex(i
);
3984 // if formal par is not template then skip restriction checking,
3985 // templates can have only `in' parameters
3986 if (fp
->get_asstype()!=A_PAR_TEMPL_IN
) continue;
3987 template_restriction_t fp_tr
= fp
->get_template_restriction();
3988 switch (template_restriction
) {
3997 fp
->error("Formal parameter with template restriction `%s' "
3998 "not allowed here", Template::get_restriction_name(fp_tr
));
4001 fp
->error("Formal parameter without template restriction "
4002 "not allowed here");
4005 FATAL_ERROR("Ttcn::Def_Template::chk()");
4009 FATAL_ERROR("Ttcn::Def_Template::chk()");
4014 if (!semantic_check_only
) {
4015 if (fp_list
) fp_list
->set_genname(t_genname
);
4016 body
->set_genname_prefix("template_");
4017 body
->set_genname_recursive(t_genname
);
4018 body
->set_code_section(fp_list
? GovernedSimple::CS_INLINE
:
4019 GovernedSimple::CS_POST_INIT
);
4024 void Def_Template::chk_default() const
4026 if (!fp_list
) FATAL_ERROR("Def_Template::chk_default()");
4028 if (fp_list
->has_notused_defval())
4029 fp_list
->error("Only modified templates are allowed to use the not "
4030 "used symbol (`-') as the default parameter");
4033 Common::Assignment
*ass
= derived_ref
->get_refd_assignment(false);
4034 if (!ass
|| ass
->get_asstype() != A_TEMPLATE
) return; // Work locally.
4035 Def_Template
*base
= dynamic_cast<Def_Template
*>(ass
);
4036 if (!base
) FATAL_ERROR("Def_Template::chk_default()");
4037 FormalParList
*base_fpl
= base
->get_FormalParList();
4038 size_t nof_base_fps
= base_fpl
? base_fpl
->get_nof_fps() : 0;
4039 size_t nof_local_fps
= fp_list
? fp_list
->get_nof_fps() : 0;
4040 size_t min_fps
= nof_base_fps
;
4041 if (nof_local_fps
< nof_base_fps
) min_fps
= nof_local_fps
;
4042 for (size_t i
= 0; i
< min_fps
; i
++) {
4043 FormalPar
*base_fp
= base_fpl
->get_fp_byIndex(i
);
4044 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4045 if (local_fp
->has_notused_defval()) {
4046 if (base_fp
->has_defval()) {
4047 local_fp
->set_defval(base_fp
->get_defval());
4049 local_fp
->error("Not used symbol (`-') doesn't have the "
4050 "corresponding default parameter in the "
4055 // Additional parameters in the derived template with using the not used
4056 // symbol. TODO: Merge the loops.
4057 for (size_t i
= nof_base_fps
; i
< nof_local_fps
; i
++) {
4058 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4059 if (local_fp
->has_notused_defval())
4060 local_fp
->error("Not used symbol (`-') doesn't have the "
4061 "corresponding default parameter in the "
4066 void Def_Template::chk_modified()
4068 if (!derived_ref
) return;
4069 // Do not check the (non-existent) actual parameter list of the derived
4070 // reference against the formal parameter list of the base template.
4071 // According to TTCN-3 syntax the derived reference cannot have parameters
4072 // even if the base template is parameterized.
4073 Common::Assignment
*ass
= derived_ref
->get_refd_assignment(false);
4074 // Checking the existence and type compatibility of the base template.
4076 if (ass
->get_asstype() != A_TEMPLATE
) {
4077 derived_ref
->error("Reference to a template was expected in the "
4078 "`modifies' definition instead of %s",
4079 ass
->get_description().c_str());
4082 base_template
= dynamic_cast<Def_Template
*>(ass
);
4083 if (!base_template
) FATAL_ERROR("Def_Template::chk_modified()");
4084 Type
*base_type
= base_template
->get_Type();
4085 TypeCompatInfo
info_base(my_scope
->get_scope_mod(), type
, base_type
, true,
4087 TypeChain l_chain_base
;
4088 TypeChain r_chain_base
;
4089 if (!type
->is_compatible(base_type
, &info_base
, &l_chain_base
,
4091 if (info_base
.is_subtype_error()) {
4092 type
->error("%s", info_base
.get_subtype_error().c_str());
4094 if (!info_base
.is_erroneous()) {
4095 type
->error("The modified template has different type than base "
4096 "template `%s': `%s' was expected instead of `%s'",
4097 ass
->get_fullname().c_str(),
4098 base_type
->get_typename().c_str(),
4099 type
->get_typename().c_str());
4101 // Always use the format string.
4102 type
->error("%s", info_base
.get_error_str_str().c_str());
4105 if (info_base
.needs_conversion())
4106 body
->set_needs_conversion();
4108 // Check for restriction.
4109 if (Template::is_less_restrictive(base_template
->get_template_restriction(),
4110 template_restriction
)) {
4111 error("The template restriction is not the same or more "
4112 "restrictive as of base template `%s'", ass
->get_fullname().c_str());
4114 // Checking formal parameter lists.
4115 FormalParList
*base_fpl
= base_template
->get_FormalParList();
4116 size_t nof_base_fps
= base_fpl
? base_fpl
->get_nof_fps() : 0;
4117 size_t nof_local_fps
= fp_list
? fp_list
->get_nof_fps() : 0;
4119 if (nof_local_fps
< nof_base_fps
) {
4120 error("The modified template has fewer formal parameters than base "
4121 "template `%s': at least %lu parameter%s expected instead of %lu",
4122 ass
->get_fullname().c_str(), (unsigned long)nof_base_fps
,
4123 nof_base_fps
> 1 ? "s were" : " was", (unsigned long)nof_local_fps
);
4124 min_fps
= nof_local_fps
;
4125 } else min_fps
= nof_base_fps
;
4127 for (size_t i
= 0; i
< min_fps
; i
++) {
4128 FormalPar
*base_fp
= base_fpl
->get_fp_byIndex(i
);
4129 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4130 Error_Context
cntxt(local_fp
, "In formal parameter #%lu",
4131 (unsigned long)(i
+ 1));
4132 // Check for parameter kind equivalence (value or template).
4133 if (base_fp
->get_asstype() != local_fp
->get_asstype())
4134 local_fp
->error("The kind of parameter is not the same as in base "
4135 "template `%s': %s was expected instead of %s",
4136 ass
->get_fullname().c_str(), base_fp
->get_assname(),
4137 local_fp
->get_assname());
4138 // Check for type compatibility.
4139 Type
*base_fp_type
= base_fp
->get_Type();
4140 Type
*local_fp_type
= local_fp
->get_Type();
4141 TypeCompatInfo
info_par(my_scope
->get_scope_mod(), base_fp_type
,
4142 local_fp_type
, true, false);
4143 TypeChain l_chain_par
;
4144 TypeChain r_chain_par
;
4145 if (!base_fp_type
->is_compatible(local_fp_type
, &info_par
, &l_chain_par
,
4147 if (info_par
.is_subtype_error()) {
4148 local_fp_type
->error("%s", info_par
.get_subtype_error().c_str());
4150 if (!info_par
.is_erroneous()) {
4151 local_fp_type
->error("The type of parameter is not the same as in "
4152 "base template `%s': `%s' was expected instead "
4154 ass
->get_fullname().c_str(),
4155 base_fp_type
->get_typename().c_str(),
4156 local_fp_type
->get_typename().c_str());
4158 local_fp_type
->error("%s", info_par
.get_error_str_str().c_str());
4161 if (info_par
.needs_conversion())
4162 body
->set_needs_conversion();
4164 // Check for name equivalence.
4165 const Identifier
& base_fp_id
= base_fp
->get_id();
4166 const Identifier
& local_fp_id
= local_fp
->get_id();
4167 if (!(base_fp_id
== local_fp_id
))
4168 local_fp
->error("The name of parameter is not the same as in base "
4169 "template `%s': `%s' was expected instead of `%s'",
4170 ass
->get_fullname().c_str(),
4171 base_fp_id
.get_dispname().c_str(),
4172 local_fp_id
.get_dispname().c_str());
4173 // Check for restrictions: the derived must be same or more restrictive.
4174 if (base_fp
->get_asstype()==local_fp
->get_asstype() &&
4175 Template::is_less_restrictive(base_fp
->get_template_restriction(),
4176 local_fp
->get_template_restriction())) {
4177 local_fp
->error("The restriction of parameter is not the same or more "
4178 "restrictive as in base template `%s'", ass
->get_fullname().c_str());
4181 // Set the pointer to the body of base template.
4182 body
->set_base_template(base_template
->get_Template());
4185 void Def_Template::chk_recursive_derivation()
4187 if (recurs_deriv_checked
) return;
4188 if (base_template
) {
4189 ReferenceChain
refch(this, "While checking the chain of base templates");
4190 refch
.add(get_fullname());
4191 for (Def_Template
*iter
= base_template
; iter
; iter
= iter
->base_template
)
4193 if (iter
->recurs_deriv_checked
) break;
4194 else if (refch
.add(iter
->get_fullname()))
4195 iter
->recurs_deriv_checked
= true;
4199 recurs_deriv_checked
= true;
4202 void Def_Template::generate_code(output_struct
*target
, bool)
4204 type
->generate_code(target
);
4206 // Parameterized template. Generate code for a function which returns
4207 // a $(genname)_template and has the appropriate parameters.
4208 const string
& t_genname
= get_genname();
4209 const char *template_name
= t_genname
.c_str();
4210 const char *template_dispname
= id
->get_dispname().c_str();
4211 const string
& type_genname
= type
->get_genname_template(my_scope
);
4212 const char *type_genname_str
= type_genname
.c_str();
4214 // assemble the function body first (this also determines which parameters
4216 size_t nof_base_pars
= 0;
4217 char* function_body
= create_location_object(memptystr(), "TEMPLATE",
4219 if (base_template
) {
4220 // modified template
4221 function_body
= mputprintf(function_body
, "%s ret_val(%s",
4223 base_template
->get_genname_from_scope(my_scope
).c_str());
4224 if (base_template
->fp_list
) {
4225 // the base template is also parameterized
4226 function_body
= mputc(function_body
, '(');
4227 nof_base_pars
= base_template
->fp_list
->get_nof_fps();
4228 for (size_t i
= 0; i
< nof_base_pars
; i
++) {
4229 if (i
> 0) function_body
= mputstr(function_body
, ", ");
4230 function_body
= mputstr(function_body
,
4231 fp_list
->get_fp_byIndex(i
)->get_id().get_name().c_str());
4233 function_body
= mputc(function_body
, ')');
4235 function_body
= mputstr(function_body
, ");\n");
4238 function_body
= mputprintf(function_body
, "%s ret_val;\n",
4241 if (erroneous_attrs
&& erroneous_attrs
->get_err_descr()) {
4242 function_body
= erroneous_attrs
->get_err_descr()->
4243 generate_code_str(function_body
, string("ret_val"));
4245 function_body
= body
->generate_code_init(function_body
, "ret_val");
4246 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4247 function_body
= Template::generate_restriction_check_code(function_body
,
4248 "ret_val", template_restriction
);
4249 function_body
= mputstr(function_body
, "return ret_val;\n");
4250 // if the template modifies a parameterized template, then the inherited
4251 // formal parameters must always be displayed, otherwise generate a smart
4252 // formal parameter list (where the names of unused parameters are omitted)
4253 char *formal_par_list
= fp_list
->generate_code(memptystr(), nof_base_pars
);
4254 fp_list
->generate_code_defval(target
);
4256 target
->header
.function_prototypes
=
4257 mputprintf(target
->header
.function_prototypes
,
4258 "extern %s %s(%s);\n",
4259 type_genname_str
, template_name
, formal_par_list
);
4260 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
4264 "}\n\n", type_genname_str
, template_name
, formal_par_list
, function_body
);
4265 Free(formal_par_list
);
4266 Free(function_body
);
4268 // non-parameterized template
4270 Code::init_cdef(&cdef
);
4271 type
->generate_code_object(&cdef
, body
);
4272 cdef
.init
= update_location_object(cdef
.init
);
4273 if (base_template
) {
4274 // modified template
4275 if (base_template
->my_scope
->get_scope_mod_gen() ==
4276 my_scope
->get_scope_mod_gen()) {
4277 // if the base template is in the same module its body has to be
4278 // initialized first
4279 cdef
.init
= base_template
->body
->generate_code_init(cdef
.init
,
4280 base_template
->body
->get_lhs_name().c_str());
4282 if (use_runtime_2
&& body
->get_needs_conversion()) {
4283 Type
*body_type
= body
->get_my_governor()->get_type_refd_last();
4284 Type
*base_type
= base_template
->body
->get_my_governor()
4285 ->get_type_refd_last();
4286 if (!body_type
|| !base_type
)
4287 FATAL_ERROR("Def_Template::generate_code()");
4288 const string
& tmp_id
= body
->get_temporary_id();
4289 const char *tmp_id_str
= tmp_id
.c_str();
4290 // base template initialization
4291 cdef
.init
= mputprintf(cdef
.init
,
4293 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' "
4294 "and `%s' are not compatible at run-time\");\n"
4296 body_type
->get_genname_template(my_scope
).c_str(), tmp_id_str
,
4297 TypeConv::get_conv_func(base_type
, body_type
, my_scope
4298 ->get_scope_mod()).c_str(), tmp_id_str
, base_template
4299 ->get_genname_from_scope(my_scope
).c_str(), base_type
4300 ->get_typename().c_str(), body_type
->get_typename().c_str(),
4301 body
->get_lhs_name().c_str(), tmp_id_str
);
4303 cdef
.init
= mputprintf(cdef
.init
, "%s = %s;\n",
4304 body
->get_lhs_name().c_str(),
4305 base_template
->get_genname_from_scope(my_scope
).c_str());
4308 if (use_runtime_2
&& TypeConv::needs_conv_refd(body
))
4309 cdef
.init
= TypeConv::gen_conv_code_refd(cdef
.init
,
4310 body
->get_lhs_name().c_str(), body
);
4312 cdef
.init
= body
->generate_code_init(cdef
.init
,
4313 body
->get_lhs_name().c_str());
4314 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4315 cdef
.init
= Template::generate_restriction_check_code(cdef
.init
,
4316 body
->get_lhs_name().c_str(), template_restriction
);
4317 target
->header
.global_vars
= mputstr(target
->header
.global_vars
,
4319 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
4321 target
->functions
.post_init
= mputstr(target
->functions
.post_init
,
4323 Code::free_cdef(&cdef
);
4327 void Def_Template::generate_code(Common::CodeGenHelper
& cgh
) {
4328 generate_code(cgh
.get_outputstruct(this));
4331 char *Def_Template::generate_code_str(char *str
)
4333 const string
& t_genname
= get_genname();
4334 const char *genname_str
= t_genname
.c_str();
4335 const string
& type_genname
= type
->get_genname_template(my_scope
);
4336 const char *type_genname_str
= type_genname
.c_str();
4338 const char *dispname_str
= id
->get_dispname().c_str();
4339 NOTSUPP("Code generation for parameterized local template `%s'",
4341 str
= mputprintf(str
, "/* NOT SUPPORTED: template %s */\n",
4344 if (base_template
) {
4345 // non-parameterized modified template
4346 if (use_runtime_2
&& body
->get_needs_conversion()) {
4347 Type
*body_type
= body
->get_my_governor()->get_type_refd_last();
4348 Type
*base_type
= base_template
->body
->get_my_governor()
4349 ->get_type_refd_last();
4350 if (!body_type
|| !base_type
)
4351 FATAL_ERROR("Def_Template::generate_code_str()");
4352 const string
& tmp_id
= body
->get_temporary_id();
4353 const char *tmp_id_str
= tmp_id
.c_str();
4354 str
= mputprintf(str
,
4356 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' "
4357 "and `%s' are not compatible at run-time\");\n"
4359 body_type
->get_genname_template(my_scope
).c_str(), tmp_id_str
,
4360 TypeConv::get_conv_func(base_type
, body_type
, my_scope
4361 ->get_scope_mod()).c_str(), tmp_id_str
, base_template
4362 ->get_genname_from_scope(my_scope
).c_str(), base_type
4363 ->get_typename().c_str(), body_type
->get_typename().c_str(),
4364 type_genname_str
, genname_str
, tmp_id_str
);
4366 // the object is initialized from the base template by the
4368 str
= mputprintf(str
, "%s %s(%s);\n", type_genname_str
, genname_str
,
4369 base_template
->get_genname_from_scope(my_scope
).c_str());
4371 // the modified body is assigned in the subsequent statements
4372 str
= body
->generate_code_init(str
, genname_str
);
4374 // non-parameterized non-modified template
4375 if (body
->has_single_expr()) {
4376 // the object is initialized by the constructor
4377 str
= mputprintf(str
, "%s %s(%s);\n", type_genname_str
,
4378 genname_str
, body
->get_single_expr(false).c_str());
4379 // make sure the template's code is not generated twice (TR: HU56425)
4380 body
->set_code_generated();
4382 // the default constructor is used
4383 str
= mputprintf(str
, "%s %s;\n", type_genname_str
, genname_str
);
4384 // the body is assigned in the subsequent statements
4385 str
= body
->generate_code_init(str
, genname_str
);
4388 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4389 str
= Template::generate_restriction_check_code(str
, genname_str
,
4390 template_restriction
);
4395 void Def_Template::ilt_generate_code(ILT
*ilt
)
4397 const string
& t_genname
= get_genname();
4398 const char *genname_str
= t_genname
.c_str();
4399 char*& def
=ilt
->get_out_def();
4400 char*& init
=ilt
->get_out_branches();
4402 const char *dispname_str
= id
->get_dispname().c_str();
4403 NOTSUPP("Code generation for parameterized local template `%s'",
4405 def
= mputprintf(def
, "/* NOT SUPPORTED: template %s */\n", dispname_str
);
4406 init
= mputprintf(init
, "/* NOT SUPPORTED: template %s */\n",
4409 // non-parameterized template
4410 // use the default constructor for initialization
4411 def
= mputprintf(def
, "%s %s;\n",
4412 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4413 if (base_template
) {
4414 // copy the base template with an assignment
4415 init
= mputprintf(init
, "%s = %s;\n", genname_str
,
4416 base_template
->get_genname_from_scope(my_scope
).c_str());
4418 // finally assign the body
4419 init
= body
->generate_code_init(init
, genname_str
);
4420 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4421 init
= Template::generate_restriction_check_code(init
, genname_str
,
4422 template_restriction
);
4426 void Def_Template::dump_internal(unsigned level
) const
4428 DEBUG(level
, "Template: %s", id
->get_dispname().c_str());
4429 if (fp_list
) fp_list
->dump(level
+ 1);
4431 DEBUG(level
+ 1, "modifies: %s", derived_ref
->get_dispname().c_str());
4432 if (template_restriction
!=TR_NONE
)
4433 DEBUG(level
+ 1, "restriction: %s",
4434 Template::get_restriction_name(template_restriction
));
4435 type
->dump(level
+ 1);
4436 body
->dump(level
+ 1);
4439 // =================================
4441 // =================================
4443 Def_Var::Def_Var(Identifier
*p_id
, Type
*p_type
, Value
*p_initial_value
)
4444 : Definition(A_VAR
, p_id
), type(p_type
), initial_value(p_initial_value
)
4446 if (!p_type
) FATAL_ERROR("Ttcn::Def_Var::Def_Var()");
4447 type
->set_ownertype(Type::OT_VAR_DEF
, this);
4453 delete initial_value
;
4456 Def_Var
*Def_Var::clone() const
4458 FATAL_ERROR("Def_Var::clone");
4461 void Def_Var::set_fullname(const string
& p_fullname
)
4463 Definition::set_fullname(p_fullname
);
4464 type
->set_fullname(p_fullname
+ ".<type>");
4466 initial_value
->set_fullname(p_fullname
+ ".<initial_value>");
4469 void Def_Var::set_my_scope(Scope
*p_scope
)
4471 Definition::set_my_scope(p_scope
);
4472 type
->set_my_scope(p_scope
);
4473 if (initial_value
) initial_value
->set_my_scope(p_scope
);
4476 Type
*Def_Var::get_Type()
4485 Error_Context
cntxt(this, "In variable definition `%s'",
4486 id
->get_dispname().c_str());
4487 type
->set_genname(_T_
, get_genname());
4490 Type
*t
= type
->get_type_refd_last();
4491 switch (t
->get_typetype()) {
4493 error("Variable cannot be defined for port type `%s'",
4494 t
->get_fullname().c_str());
4496 case Type::T_SIGNATURE
:
4497 error("Variable cannot be defined for signature `%s'",
4498 t
->get_fullname().c_str());
4501 if (initial_value
) {
4502 initial_value
->set_my_governor(type
);
4503 type
->chk_this_value_ref(initial_value
);
4504 type
->chk_this_value(initial_value
, this, is_local() ?
4505 Type::EXPECTED_DYNAMIC_VALUE
: Type::EXPECTED_STATIC_VALUE
,
4506 INCOMPLETE_ALLOWED
, OMIT_NOT_ALLOWED
, SUB_CHK
);
4507 if (!semantic_check_only
) {
4508 initial_value
->set_genname_recursive(get_genname());
4509 initial_value
->set_code_section(GovernedSimple::CS_INLINE
);
4515 if (w_attrib_path
) {
4516 w_attrib_path
->chk_global_attrib();
4517 w_attrib_path
->chk_no_qualif();
4521 bool Def_Var::chk_identical(Definition
*p_def
)
4525 if (p_def
->get_asstype() != A_VAR
) {
4526 const char *dispname_str
= id
->get_dispname().c_str();
4527 error("Local definition `%s' is a variable, but the definition "
4528 "inherited from component type `%s' is a %s", dispname_str
,
4529 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4530 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4533 Def_Var
*p_def_var
= dynamic_cast<Def_Var
*>(p_def
);
4534 if (!p_def_var
) FATAL_ERROR("Def_Var::chk_identical()");
4535 if (!type
->is_identical(p_def_var
->type
)) {
4536 const char *dispname_str
= id
->get_dispname().c_str();
4537 type
->error("Local variable `%s' has type `%s', but the variable "
4538 "inherited from component type `%s' has type `%s'", dispname_str
,
4539 type
->get_typename().c_str(),
4540 p_def_var
->get_my_scope()->get_fullname().c_str(),
4541 p_def_var
->type
->get_typename().c_str());
4542 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4545 if (initial_value
) {
4546 if (p_def_var
->initial_value
) {
4547 if (!initial_value
->is_unfoldable() &&
4548 !p_def_var
->initial_value
->is_unfoldable() &&
4549 !(*initial_value
== *p_def_var
->initial_value
)) {
4550 const char *dispname_str
= id
->get_dispname().c_str();
4551 initial_value
->warning("Local variable `%s' and the variable "
4552 "inherited from component type `%s' have different initial values",
4553 dispname_str
, p_def_var
->get_my_scope()->get_fullname().c_str());
4554 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4557 const char *dispname_str
= id
->get_dispname().c_str();
4558 initial_value
->warning("Local variable `%s' has initial value, but "
4559 "the variable inherited from component type `%s' does not",
4560 dispname_str
, p_def_var
->get_my_scope()->get_fullname().c_str());
4561 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4563 } else if (p_def_var
->initial_value
) {
4564 const char *dispname_str
= id
->get_dispname().c_str();
4565 warning("Local variable `%s' does not have initial value, but the "
4566 "variable inherited from component type `%s' has", dispname_str
,
4567 p_def_var
->get_my_scope()->get_fullname().c_str());
4568 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4573 void Def_Var::generate_code(output_struct
*target
, bool clean_up
)
4575 type
->generate_code(target
);
4577 Code::init_cdef(&cdef
);
4578 type
->generate_code_object(&cdef
, my_scope
, get_genname(), 0, false);
4579 Code::merge_cdef(target
, &cdef
);
4580 Code::free_cdef(&cdef
);
4581 if (initial_value
) {
4582 target
->functions
.init_comp
=
4583 initial_value
->generate_code_init(target
->functions
.init_comp
,
4584 initial_value
->get_lhs_name().c_str());
4585 } else if (clean_up
) { // No initial value.
4586 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4587 "%s.clean_up();\n", get_genname().c_str());
4591 void Def_Var::generate_code(CodeGenHelper
& cgh
)
4593 generate_code(cgh
.get_outputstruct(this));
4596 char *Def_Var::generate_code_str(char *str
)
4598 const string
& t_genname
= get_genname();
4599 const char *genname_str
= t_genname
.c_str();
4600 if (initial_value
&& initial_value
->has_single_expr()) {
4601 // the initial value can be represented by a single C++ expression
4602 // the object is initialized by the constructor
4603 str
= mputprintf(str
, "%s %s(%s);\n",
4604 type
->get_genname_value(my_scope
).c_str(), genname_str
,
4605 initial_value
->get_single_expr().c_str());
4607 // use the default constructor
4608 str
= mputprintf(str
, "%s %s;\n",
4609 type
->get_genname_value(my_scope
).c_str(), genname_str
);
4610 if (initial_value
) {
4611 // the initial value is assigned using subsequent statements
4612 str
= initial_value
->generate_code_init(str
, genname_str
);
4618 void Def_Var::ilt_generate_code(ILT
*ilt
)
4620 const string
& t_genname
= get_genname();
4621 const char *genname_str
= t_genname
.c_str();
4622 char*& def
=ilt
->get_out_def();
4623 char*& init
=ilt
->get_out_branches();
4624 def
= mputprintf(def
, "%s %s;\n", type
->get_genname_value(my_scope
).c_str(),
4627 init
= initial_value
->generate_code_init(init
, genname_str
);
4630 char *Def_Var::generate_code_init_comp(char *str
, Definition
*base_defn
)
4632 if (initial_value
) {
4633 str
= initial_value
->generate_code_init(str
,
4634 base_defn
->get_genname_from_scope(my_scope
).c_str());
4639 void Def_Var::dump_internal(unsigned level
) const
4641 DEBUG(level
, "Variable %s", id
->get_dispname().c_str());
4642 type
->dump(level
+ 1);
4643 if (initial_value
) initial_value
->dump(level
+ 1);
4646 // =================================
4647 // ===== Def_Var_Template
4648 // =================================
4650 Def_Var_Template::Def_Var_Template(Identifier
*p_id
, Type
*p_type
,
4651 Template
*p_initial_value
, template_restriction_t p_template_restriction
)
4652 : Definition(A_VAR_TEMPLATE
, p_id
), type(p_type
),
4653 initial_value(p_initial_value
), template_restriction(p_template_restriction
)
4655 if (!p_type
) FATAL_ERROR("Ttcn::Def_Var_Template::Def_Var_Template()");
4656 type
->set_ownertype(Type::OT_VARTMPL_DEF
, this);
4659 Def_Var_Template::~Def_Var_Template()
4662 delete initial_value
;
4665 Def_Var_Template
*Def_Var_Template::clone() const
4667 FATAL_ERROR("Def_Var_Template::clone");
4670 void Def_Var_Template::set_fullname(const string
& p_fullname
)
4672 Definition::set_fullname(p_fullname
);
4673 type
->set_fullname(p_fullname
+ ".<type>");
4675 initial_value
->set_fullname(p_fullname
+ ".<initial_value>");
4678 void Def_Var_Template::set_my_scope(Scope
*p_scope
)
4680 Definition::set_my_scope(p_scope
);
4681 type
->set_my_scope(p_scope
);
4682 if (initial_value
) initial_value
->set_my_scope(p_scope
);
4685 Type
*Def_Var_Template::get_Type()
4691 void Def_Var_Template::chk()
4694 Error_Context
cntxt(this, "In template variable definition `%s'",
4695 id
->get_dispname().c_str());
4696 type
->set_genname(_T_
, get_genname());
4699 Type
*t
= type
->get_type_refd_last();
4700 if (t
->get_typetype() == Type::T_PORT
) {
4701 error("Template variable cannot be defined for port type `%s'",
4702 t
->get_fullname().c_str());
4705 if (initial_value
) {
4706 initial_value
->set_my_governor(type
);
4707 initial_value
->flatten(false);
4709 if (initial_value
->get_templatetype() == Template::CSTR_PATTERN
&&
4710 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
4711 initial_value
->set_templatetype(Template::USTR_PATTERN
);
4712 initial_value
->get_ustr_pattern()->set_pattern_type(
4713 PatternString::USTR_PATTERN
);
4716 type
->chk_this_template_ref(initial_value
);
4717 // temporary hack: to allow incomplete body as initial value
4718 // checking as a modified template, but without a base template
4719 type
->chk_this_template_generic(initial_value
, INCOMPLETE_ALLOWED
,
4720 OMIT_ALLOWED
, ANY_OR_OMIT_ALLOWED
, SUB_CHK
, IMPLICIT_OMIT
, 0);
4721 gen_restriction_check
=
4722 initial_value
->chk_restriction("template variable definition",
4723 template_restriction
, initial_value
);
4724 if (!semantic_check_only
) {
4725 initial_value
->set_genname_recursive(get_genname());
4726 initial_value
->set_code_section(GovernedSimple::CS_INLINE
);
4729 if (w_attrib_path
) {
4730 w_attrib_path
->chk_global_attrib();
4731 w_attrib_path
->chk_no_qualif();
4735 bool Def_Var_Template::chk_identical(Definition
*p_def
)
4739 if (p_def
->get_asstype() != A_VAR_TEMPLATE
) {
4740 const char *dispname_str
= id
->get_dispname().c_str();
4741 error("Local definition `%s' is a template variable, but the definition "
4742 "inherited from component type `%s' is a %s", dispname_str
,
4743 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4744 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4747 Def_Var_Template
*p_def_var_template
=
4748 dynamic_cast<Def_Var_Template
*>(p_def
);
4749 if (!p_def_var_template
) FATAL_ERROR("Def_Var_Template::chk_identical()");
4750 if (!type
->is_identical(p_def_var_template
->type
)) {
4751 const char *dispname_str
= id
->get_dispname().c_str();
4752 type
->error("Local template variable `%s' has type `%s', but the "
4753 "template variable inherited from component type `%s' has type `%s'",
4754 dispname_str
, type
->get_typename().c_str(),
4755 p_def_var_template
->get_my_scope()->get_fullname().c_str(),
4756 p_def_var_template
->type
->get_typename().c_str());
4757 p_def_var_template
->note("The inherited template variable `%s' is here",
4761 if (initial_value
) {
4762 if (!p_def_var_template
->initial_value
) {
4763 const char *dispname_str
= id
->get_dispname().c_str();
4764 initial_value
->warning("Local template variable `%s' has initial "
4765 "value, but the template variable inherited from component type "
4766 "`%s' does not", dispname_str
,
4767 p_def_var_template
->get_my_scope()->get_fullname().c_str());
4768 p_def_var_template
->note("The inherited template variable `%s' is here",
4771 } else if (p_def_var_template
->initial_value
) {
4772 const char *dispname_str
= id
->get_dispname().c_str();
4773 warning("Local template variable `%s' does not have initial value, but "
4774 "the template variable inherited from component type `%s' has",
4776 p_def_var_template
->get_my_scope()->get_fullname().c_str());
4777 p_def_var_template
->note("The inherited template variable `%s' is here",
4783 void Def_Var_Template::generate_code(output_struct
*target
, bool clean_up
)
4785 type
->generate_code(target
);
4787 Code::init_cdef(&cdef
);
4788 type
->generate_code_object(&cdef
, my_scope
, get_genname(), 0, true);
4789 Code::merge_cdef(target
, &cdef
);
4790 Code::free_cdef(&cdef
);
4791 if (initial_value
) {
4792 if (Common::Type::T_SEQOF
== initial_value
->get_my_governor()->get_typetype() ||
4793 Common::Type::T_ARRAY
== initial_value
->get_my_governor()->get_typetype()) {
4794 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4795 "%s.remove_all_permutations();\n", initial_value
->get_lhs_name().c_str());
4797 target
->functions
.init_comp
=
4798 initial_value
->generate_code_init(target
->functions
.init_comp
,
4799 initial_value
->get_lhs_name().c_str());
4800 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4801 target
->functions
.init_comp
= Template::generate_restriction_check_code(
4802 target
->functions
.init_comp
, initial_value
->get_lhs_name().c_str(),
4803 template_restriction
);
4804 } else if (clean_up
) { // No initial value.
4805 // Always reset component variables/variable templates on component
4806 // reinitialization. Fix for HM79493.
4807 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4808 "%s.clean_up();\n", get_genname().c_str());
4812 void Def_Var_Template::generate_code(CodeGenHelper
& cgh
)
4814 generate_code(cgh
.get_outputstruct(this));
4817 char *Def_Var_Template::generate_code_str(char *str
)
4819 const string
& t_genname
= get_genname();
4820 const char *genname_str
= t_genname
.c_str();
4821 if (initial_value
&& initial_value
->has_single_expr()) {
4822 // The initial value can be represented by a single C++ expression
4823 // the object is initialized by the constructor.
4824 str
= mputprintf(str
, "%s %s(%s);\n",
4825 type
->get_genname_template(my_scope
).c_str(), genname_str
,
4826 initial_value
->get_single_expr(false).c_str());
4828 // Use the default constructor.
4829 str
= mputprintf(str
, "%s %s;\n",
4830 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4831 if (initial_value
) {
4832 // The initial value is assigned using subsequent statements.
4833 if (use_runtime_2
&& TypeConv::needs_conv_refd(initial_value
))
4834 str
= TypeConv::gen_conv_code_refd(str
, genname_str
, initial_value
);
4835 else str
= initial_value
->generate_code_init(str
, genname_str
);
4838 if (initial_value
&& template_restriction
!= TR_NONE
4839 && gen_restriction_check
)
4840 str
= Template::generate_restriction_check_code(str
, genname_str
,
4841 template_restriction
);
4845 void Def_Var_Template::ilt_generate_code(ILT
*ilt
)
4847 const string
& t_genname
= get_genname();
4848 const char *genname_str
= t_genname
.c_str();
4849 char*& def
=ilt
->get_out_def();
4850 char*& init
=ilt
->get_out_branches();
4851 def
= mputprintf(def
, "%s %s;\n",
4852 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4853 if (initial_value
) {
4854 init
= initial_value
->generate_code_init(init
, genname_str
);
4855 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4856 init
= Template::generate_restriction_check_code(init
, genname_str
,
4857 template_restriction
);
4861 char *Def_Var_Template::generate_code_init_comp(char *str
,
4862 Definition
*base_defn
)
4864 if (initial_value
) {
4865 str
= initial_value
->generate_code_init(str
,
4866 base_defn
->get_genname_from_scope(my_scope
).c_str());
4867 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4868 str
= Template::generate_restriction_check_code(str
,
4869 base_defn
->get_genname_from_scope(my_scope
).c_str(),
4870 template_restriction
);
4875 void Def_Var_Template::dump_internal(unsigned level
) const
4877 DEBUG(level
, "Template variable %s", id
->get_dispname().c_str());
4878 if (template_restriction
!=TR_NONE
)
4879 DEBUG(level
+ 1, "restriction: %s",
4880 Template::get_restriction_name(template_restriction
));
4881 type
->dump(level
+ 1);
4882 if (initial_value
) initial_value
->dump(level
+ 1);
4885 // =================================
4887 // =================================
4889 Def_Timer::~Def_Timer()
4892 delete default_duration
;
4895 Def_Timer
*Def_Timer::clone() const
4897 FATAL_ERROR("Def_Timer::clone");
4900 void Def_Timer::set_fullname(const string
& p_fullname
)
4902 Definition::set_fullname(p_fullname
);
4903 if (dimensions
) dimensions
->set_fullname(p_fullname
+ ".<dimensions>");
4904 if (default_duration
)
4905 default_duration
->set_fullname(p_fullname
+ ".<default_duration>");
4908 void Def_Timer::set_my_scope(Scope
*p_scope
)
4910 Definition::set_my_scope(p_scope
);
4911 if (dimensions
) dimensions
->set_my_scope(p_scope
);
4912 if (default_duration
) default_duration
->set_my_scope(p_scope
);
4915 ArrayDimensions
*Def_Timer::get_Dimensions()
4917 if (!checked
) chk();
4921 void Def_Timer::chk()
4924 Error_Context
cntxt(this, "In timer definition `%s'",
4925 id
->get_dispname().c_str());
4926 if (dimensions
) dimensions
->chk();
4927 if (default_duration
) {
4928 Error_Context
cntxt2(default_duration
, "In default duration");
4929 if (dimensions
) chk_array_duration(default_duration
);
4930 else chk_single_duration(default_duration
);
4931 if (!semantic_check_only
) {
4932 default_duration
->set_code_section(GovernedSimple::CS_POST_INIT
);
4936 if (w_attrib_path
) {
4937 w_attrib_path
->chk_global_attrib();
4938 w_attrib_path
->chk_no_qualif();
4942 bool Def_Timer::chk_identical(Definition
*p_def
)
4946 if (p_def
->get_asstype() != A_TIMER
) {
4947 const char *dispname_str
= id
->get_dispname().c_str();
4948 error("Local definition `%s' is a timer, but the definition inherited "
4949 "from component type `%s' is a %s", dispname_str
,
4950 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4951 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4954 Def_Timer
*p_def_timer
= dynamic_cast<Def_Timer
*>(p_def
);
4955 if (!p_def_timer
) FATAL_ERROR("Def_Timer::chk_identical()");
4957 if (p_def_timer
->dimensions
) {
4958 if (!dimensions
->is_identical(p_def_timer
->dimensions
)) {
4959 const char *dispname_str
= id
->get_dispname().c_str();
4960 error("Local timer `%s' and the timer inherited from component type "
4961 "`%s' have different array dimensions", dispname_str
,
4962 p_def_timer
->get_my_scope()->get_fullname().c_str());
4963 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4967 const char *dispname_str
= id
->get_dispname().c_str();
4968 error("Local definition `%s' is a timer array, but the definition "
4969 "inherited from component type `%s' is a single timer", dispname_str
,
4970 p_def_timer
->get_my_scope()->get_fullname().c_str());
4971 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4974 } else if (p_def_timer
->dimensions
) {
4975 const char *dispname_str
= id
->get_dispname().c_str();
4976 error("Local definition `%s' is a single timer, but the definition "
4977 "inherited from component type `%s' is a timer array", dispname_str
,
4978 p_def_timer
->get_my_scope()->get_fullname().c_str());
4979 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4982 if (default_duration
) {
4983 if (p_def_timer
->default_duration
) {
4984 if (!default_duration
->is_unfoldable() &&
4985 !p_def_timer
->default_duration
->is_unfoldable() &&
4986 !(*default_duration
== *p_def_timer
->default_duration
)) {
4987 const char *dispname_str
= id
->get_dispname().c_str();
4988 default_duration
->warning("Local timer `%s' and the timer inherited "
4989 "from component type `%s' have different default durations",
4990 dispname_str
, p_def_timer
->get_my_scope()->get_fullname().c_str());
4991 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4994 const char *dispname_str
= id
->get_dispname().c_str();
4995 default_duration
->error("Local timer `%s' has default duration, but "
4996 "the timer inherited from component type `%s' does not", dispname_str
,
4997 p_def_timer
->get_my_scope()->get_fullname().c_str());
4998 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
5001 } else if (p_def_timer
->default_duration
) {
5002 const char *dispname_str
= id
->get_dispname().c_str();
5003 error("Local timer `%s' does not have default duration, but the timer "
5004 "inherited from component type `%s' has", dispname_str
,
5005 p_def_timer
->get_my_scope()->get_fullname().c_str());
5006 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
5012 bool Def_Timer::has_default_duration(FieldOrArrayRefs
*p_subrefs
)
5014 // return true in case of any uncertainity
5015 if (!default_duration
) return false;
5016 else if (!dimensions
|| !p_subrefs
) return true;
5017 Value
*v
= default_duration
;
5018 size_t nof_dims
= dimensions
->get_nof_dims();
5019 size_t nof_refs
= p_subrefs
->get_nof_refs();
5020 size_t upper_limit
= nof_dims
< nof_refs
? nof_dims
: nof_refs
;
5021 for (size_t i
= 0; i
< upper_limit
; i
++) {
5022 v
= v
->get_value_refd_last();
5023 if (v
->get_valuetype() != Value::V_SEQOF
) break;
5024 FieldOrArrayRef
*ref
= p_subrefs
->get_ref(i
);
5025 if (ref
->get_type() != FieldOrArrayRef::ARRAY_REF
) return true;
5026 Value
*v_index
= ref
->get_val()->get_value_refd_last();
5027 if (v_index
->get_valuetype() != Value::V_INT
) return true;
5028 Int index
= v_index
->get_val_Int()->get_val()
5029 - dimensions
->get_dim_byIndex(i
)->get_offset();
5030 if (index
>= 0 && index
< static_cast<Int
>(v
->get_nof_comps()))
5031 v
= v
->get_comp_byIndex(index
);
5034 return v
->get_valuetype() != Value::V_NOTUSED
;
5037 void Def_Timer::chk_single_duration(Value
*dur
)
5039 dur
->chk_expr_float(is_local() ?
5040 Type::EXPECTED_DYNAMIC_VALUE
: Type::EXPECTED_STATIC_VALUE
);
5041 Value
*v
= dur
->get_value_refd_last();
5042 if (v
->get_valuetype() == Value::V_REAL
) {
5043 ttcn3float v_real
= v
->get_val_Real();
5044 if ( (v_real
<0.0) || isSpecialFloatValue(v_real
) ) {
5045 dur
->error("A non-negative float value was expected "
5046 "as timer duration instead of `%s'", Real2string(v_real
).c_str());
5051 void Def_Timer::chk_array_duration(Value
*dur
, size_t start_dim
)
5053 ArrayDimension
*dim
= dimensions
->get_dim_byIndex(start_dim
);
5054 bool array_size_known
= !dim
->get_has_error();
5055 size_t array_size
= 0;
5056 if (array_size_known
) array_size
= dim
->get_size();
5057 Value
*v
= dur
->get_value_refd_last();
5058 switch (v
->get_valuetype()) {
5059 case Value::V_ERROR
:
5061 case Value::V_SEQOF
: {
5062 size_t nof_vs
= v
->get_nof_comps();
5063 // Value-list notation.
5064 if (!v
->is_indexed()) {
5065 if (array_size_known
) {
5066 if (array_size
> nof_vs
) {
5067 dur
->error("Too few elements in the default duration of timer "
5068 "array: %lu was expected instead of %lu",
5069 (unsigned long)array_size
, (unsigned long)nof_vs
);
5070 } else if (array_size
< nof_vs
) {
5071 dur
->error("Too many elements in the default duration of timer "
5072 "array: %lu was expected instead of %lu",
5073 (unsigned long)array_size
, (unsigned long)nof_vs
);
5076 bool last_dimension
= start_dim
+ 1 >= dimensions
->get_nof_dims();
5077 for (size_t i
= 0; i
< nof_vs
; i
++) {
5078 Value
*array_v
= v
->get_comp_byIndex(i
);
5079 if (array_v
->get_valuetype() == Value::V_NOTUSED
) continue;
5080 if (last_dimension
) chk_single_duration(array_v
);
5081 else chk_array_duration(array_v
, start_dim
+ 1);
5084 // Indexed-notation.
5085 bool last_dimension
= start_dim
+ 1 >= dimensions
->get_nof_dims();
5086 map
<Int
, Int
> index_map
;
5087 for (size_t i
= 0; i
< nof_vs
; i
++) {
5088 Value
*array_v
= v
->get_comp_byIndex(i
);
5089 if (array_v
->get_valuetype() == Value::V_NOTUSED
) continue;
5090 if (last_dimension
) chk_single_duration(array_v
);
5091 else chk_array_duration(array_v
, start_dim
+ 1);
5092 Error_Context
cntxt(this, "In timer array element %lu",
5093 (unsigned long)(i
+ 1));
5094 Value
*index
= v
->get_index_byIndex(i
);
5095 dim
->chk_index(index
, Type::EXPECTED_DYNAMIC_VALUE
);
5096 if (index
->get_value_refd_last()->get_valuetype() == Value::V_INT
) {
5097 const int_val_t
*index_int
= index
->get_value_refd_last()
5099 if (*index_int
> INT_MAX
) {
5100 index
->error("An integer value less than `%d' was expected for "
5101 "indexing timer array instead of `%s'", INT_MAX
,
5102 (index_int
->t_str()).c_str());
5103 index
->set_valuetype(Value::V_ERROR
);
5105 Int index_val
= index_int
->get_val();
5106 if (index_map
.has_key(index_val
)) {
5107 index
->error("Duplicate index value `%s' for timer array "
5108 "elements `%s' and `%s'",
5109 Int2string(index_val
).c_str(),
5110 Int2string((Int
)i
+ 1).c_str(),
5111 Int2string(*index_map
[index_val
]).c_str());
5112 index
->set_valuetype(Value::V_ERROR
);
5114 index_map
.add(index_val
, new Int((Int
)i
+ 1));
5119 // It's not possible to have "index_map.size() > array_size", since we
5120 // add only correct constant-index values into the map. It's possible
5121 // to create partially initialized timer arrays.
5122 for (size_t i
= 0; i
< index_map
.size(); i
++)
5123 delete index_map
.get_nth_elem(i
);
5128 if (array_size_known
) {
5129 dur
->error("An array value (with %lu elements) was expected as "
5130 "default duration of timer array",
5131 (unsigned long)array_size
);
5133 dur
->error("An array value was expected as default duration of timer "
5136 dur
->set_valuetype(Value::V_ERROR
);
5141 void Def_Timer::generate_code(output_struct
*target
, bool)
5143 const string
& t_genname
= get_genname();
5144 const char *genname_str
= t_genname
.c_str();
5145 const string
& dispname
= id
->get_dispname();
5148 const string
& array_type
= dimensions
->get_timer_type();
5149 const char *array_type_str
= array_type
.c_str();
5150 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5151 "extern %s %s;\n", array_type_str
, genname_str
);
5152 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5153 "%s %s;\n", array_type_str
, genname_str
);
5154 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
, "{\n"
5155 "static const char * const timer_name = \"");
5156 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
5158 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
5160 "%s.set_name(timer_name);\n"
5161 "}\n", genname_str
);
5162 if (default_duration
) target
->functions
.post_init
=
5163 generate_code_array_duration(target
->functions
.post_init
, genname_str
,
5167 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5168 "extern TIMER %s;\n", genname_str
);
5169 if (default_duration
) {
5170 // has default duration
5171 Value
*v
= default_duration
->get_value_refd_last();
5172 if (v
->get_valuetype() == Value::V_REAL
) {
5173 // duration is known at compilation time -> set in the constructor
5174 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5175 "TIMER %s(\"%s\", %s);\n", genname_str
, dispname
.c_str(),
5176 v
->get_single_expr().c_str());
5178 // duration is known only at runtime -> set in post_init
5179 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5180 "TIMER %s(\"%s\");\n", genname_str
, dispname
.c_str());
5181 expression_struct expr
;
5182 Code::init_expr(&expr
);
5183 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5185 default_duration
->generate_code_expr(&expr
);
5186 expr
.expr
= mputc(expr
.expr
, ')');
5187 target
->functions
.post_init
=
5188 Code::merge_free_expr(target
->functions
.post_init
, &expr
);
5191 // does not have default duration
5192 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5193 "TIMER %s(\"%s\");\n", genname_str
, dispname
.c_str());
5198 void Def_Timer::generate_code(CodeGenHelper
& cgh
) {
5199 generate_code(cgh
.get_current_outputstruct());
5202 char *Def_Timer::generate_code_array_duration(char *str
,
5203 const char *object_name
, Value
*dur
, size_t start_dim
)
5205 ArrayDimension
*dim
= dimensions
->get_dim_byIndex(start_dim
);
5206 size_t dim_size
= dim
->get_size();
5207 Value
*v
= dur
->get_value_refd_last();
5208 if (v
->get_valuetype() != Value::V_SEQOF
5209 || (v
->get_nof_comps() != dim_size
&& !v
->is_indexed()))
5210 FATAL_ERROR("Def_Timer::generate_code_array_duration()");
5211 // Value-list notation.
5212 if (!v
->is_indexed()) {
5213 if (start_dim
+ 1 < dimensions
->get_nof_dims()) {
5214 // There are more dimensions, the elements of "v" are arrays a
5215 // temporary reference shall be introduced if the next dimension has
5216 // more than 1 elements.
5217 bool temp_ref_needed
=
5218 dimensions
->get_dim_byIndex(start_dim
+ 1)->get_size() > 1;
5219 for (size_t i
= 0; i
< dim_size
; i
++) {
5220 Value
*v_elem
= v
->get_comp_byIndex(i
);
5221 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5222 if (temp_ref_needed
) {
5223 const string
& tmp_id
= my_scope
->get_scope_mod_gen()
5224 ->get_temporary_id();
5225 const char *tmp_str
= tmp_id
.c_str();
5226 str
= mputprintf(str
, "{\n"
5227 "%s& %s = %s.array_element(%lu);\n",
5228 dimensions
->get_timer_type(start_dim
+ 1).c_str(),
5229 tmp_str
, object_name
, (unsigned long)i
);
5230 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5232 str
= mputstr(str
, "}\n");
5234 char *tmp_str
= mprintf("%s.array_element(%lu)", object_name
,
5236 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5242 // We are in the last dimension, the elements of "v" are floats.
5243 for (size_t i
= 0; i
< dim_size
; i
++) {
5244 Value
*v_elem
= v
->get_comp_byIndex(i
);
5245 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5246 expression_struct expr
;
5247 Code::init_expr(&expr
);
5248 expr
.expr
= mputprintf(expr
.expr
,
5249 "%s.array_element(%lu).set_default_duration(",
5250 object_name
, (unsigned long)i
);
5251 v_elem
->generate_code_expr(&expr
);
5252 expr
.expr
= mputc(expr
.expr
, ')');
5253 str
= Code::merge_free_expr(str
, &expr
);
5256 // Indexed-list notation.
5258 if (start_dim
+ 1 < dimensions
->get_nof_dims()) {
5259 bool temp_ref_needed
=
5260 dimensions
->get_dim_byIndex(start_dim
+ 1)->get_size() > 1;
5261 for (size_t i
= 0; i
< v
->get_nof_comps(); i
++) {
5262 Value
*v_elem
= v
->get_comp_byIndex(i
);
5263 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5264 if (temp_ref_needed
) {
5265 const string
& tmp_id
= my_scope
->get_scope_mod_gen()
5266 ->get_temporary_id();
5267 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5268 ->get_temporary_id();
5269 const char *tmp_str
= tmp_id
.c_str();
5270 str
= mputstr(str
, "{\n");
5271 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5272 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5274 str
= mputprintf(str
, "%s& %s = %s.array_element(%s);\n",
5275 dimensions
->get_timer_type(start_dim
+ 1).c_str(),
5276 tmp_str
, object_name
, idx_id
.c_str());
5277 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5279 str
= mputstr(str
, "}\n");
5281 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5282 ->get_temporary_id();
5283 str
= mputstr(str
, "{\n");
5284 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5285 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5287 char *tmp_str
= mprintf("%s.array_element(%s)", object_name
,
5289 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5291 str
= mputstr(str
, "}\n");
5296 for (size_t i
= 0; i
< v
->get_nof_comps(); i
++) {
5297 Value
*v_elem
= v
->get_comp_byIndex(i
);
5298 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5299 expression_struct expr
;
5300 Code::init_expr(&expr
);
5301 str
= mputstr(str
, "{\n");
5302 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5303 ->get_temporary_id();
5304 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5305 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5307 str
= mputprintf(str
,
5308 "%s.array_element(%s).set_default_duration(",
5309 object_name
, idx_id
.c_str());
5310 v_elem
->generate_code_expr(&expr
);
5311 expr
.expr
= mputc(expr
.expr
, ')');
5312 str
= Code::merge_free_expr(str
, &expr
);
5313 str
= mputstr(str
, "}\n");
5320 char *Def_Timer::generate_code_str(char *str
)
5322 const string
& t_genname
= get_genname();
5323 const char *genname_str
= t_genname
.c_str();
5324 const string
& dispname
= id
->get_dispname();
5327 const string
& array_type
= dimensions
->get_timer_type();
5328 const char *array_type_str
= array_type
.c_str();
5329 str
= mputprintf(str
, "%s %s;\n", array_type_str
, genname_str
);
5330 str
= mputstr(str
, "{\n"
5331 "static const char * const timer_name = \"");
5332 str
= mputstr(str
, dispname
.c_str());
5333 str
= mputprintf(str
, "\";\n"
5334 "%s.set_name(timer_name);\n"
5335 "}\n", genname_str
);
5336 if (default_duration
) str
= generate_code_array_duration(str
,
5337 genname_str
, default_duration
);
5340 if (default_duration
&& default_duration
->has_single_expr()) {
5341 // the default duration can be passed to the constructor
5342 str
= mputprintf(str
, "TIMER %s(\"%s\", %s);\n", genname_str
,
5343 dispname
.c_str(), default_duration
->get_single_expr().c_str());
5345 // only the name is passed to the constructor
5346 str
= mputprintf(str
, "TIMER %s(\"%s\");\n", genname_str
,
5348 if (default_duration
) {
5349 // the default duration is set explicitly
5350 expression_struct expr
;
5351 Code::init_expr(&expr
);
5352 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5354 default_duration
->generate_code_expr(&expr
);
5355 expr
.expr
= mputc(expr
.expr
, ')');
5356 str
= Code::merge_free_expr(str
, &expr
);
5363 void Def_Timer::ilt_generate_code(ILT
*ilt
)
5365 const string
& t_genname
= get_genname();
5366 const char *genname_str
= t_genname
.c_str();
5367 const string
& dispname
= id
->get_dispname();
5369 char*& def
= ilt
->get_out_def();
5370 char*& init
= ilt
->get_out_branches();
5374 const string
& array_type
= dimensions
->get_timer_type();
5375 const char *array_type_str
= array_type
.c_str();
5376 def
= mputprintf(def
, "%s %s;\n", array_type_str
, genname_str
);
5377 def
= mputstr(def
, "{\n"
5378 "static const char * const timer_names[] = { ");
5379 def
= dimensions
->generate_element_names(def
, dispname
);
5380 def
= mputprintf(def
, " };\n"
5381 "%s.set_name(%lu, timer_names);\n"
5382 "}\n", genname_str
, (unsigned long) dimensions
->get_array_size());
5383 if (default_duration
) init
= generate_code_array_duration(init
,
5384 genname_str
, default_duration
);
5387 if (default_duration
) {
5388 // has default duration
5389 Value
*v
= default_duration
->get_value_refd_last();
5390 if (v
->get_valuetype() == Value::V_REAL
) {
5391 // duration is known at compilation time -> set in the constructor
5392 def
= mputprintf(def
, "TIMER %s(\"%s\", %s);\n", genname_str
,
5393 dispname
.c_str(), v
->get_single_expr().c_str());
5395 // duration is known only at runtime -> set when control reaches the
5397 def
= mputprintf(def
, "TIMER %s(\"%s\");\n", genname_str
,
5399 expression_struct expr
;
5400 Code::init_expr(&expr
);
5401 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5403 default_duration
->generate_code_expr(&expr
);
5404 expr
.expr
= mputc(expr
.expr
, ')');
5405 init
= Code::merge_free_expr(init
, &expr
);
5408 // does not have default duration
5409 def
= mputprintf(def
, "TIMER %s(\"%s\");\n", genname_str
,
5415 char *Def_Timer::generate_code_init_comp(char *str
, Definition
*base_defn
)
5417 if (default_duration
) {
5418 Def_Timer
*base_timer_defn
= dynamic_cast<Def_Timer
*>(base_defn
);
5419 if (!base_timer_defn
|| !base_timer_defn
->default_duration
)
5420 FATAL_ERROR("Def_Timer::generate_code_init_comp()");
5421 // initializer is not needed if the default durations are the same
5422 // constants in both timers
5423 if (default_duration
->is_unfoldable() ||
5424 base_timer_defn
->default_duration
->is_unfoldable() ||
5425 !(*default_duration
== *base_timer_defn
->default_duration
)) {
5427 str
= generate_code_array_duration(str
,
5428 base_timer_defn
->get_genname_from_scope(my_scope
).c_str(),
5431 expression_struct expr
;
5432 Code::init_expr(&expr
);
5433 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5434 base_timer_defn
->get_genname_from_scope(my_scope
).c_str());
5435 default_duration
->generate_code_expr(&expr
);
5436 expr
.expr
= mputc(expr
.expr
, ')');
5437 str
= Code::merge_free_expr(str
, &expr
);
5444 void Def_Timer::dump_internal(unsigned level
) const
5446 DEBUG(level
, "Timer: %s", id
->get_dispname().c_str());
5447 if (dimensions
) dimensions
->dump(level
+ 1);
5448 if (default_duration
) {
5449 DEBUG(level
+ 1, "Default duration:");
5450 default_duration
->dump(level
+ 1);
5454 // =================================
5456 // =================================
5458 Def_Port::Def_Port(Identifier
*p_id
, Reference
*p_tref
,
5459 ArrayDimensions
*p_dims
)
5460 : Definition(A_PORT
, p_id
), type_ref(p_tref
), port_type(0),
5463 if (!p_tref
) FATAL_ERROR("Def_Port::Def_Port()");
5466 Def_Port::~Def_Port()
5472 Def_Port
*Def_Port::clone() const
5474 FATAL_ERROR("Def_Port::clone");
5477 void Def_Port::set_fullname(const string
& p_fullname
)
5479 Definition::set_fullname(p_fullname
);
5480 type_ref
->set_fullname(p_fullname
+ ".<type_ref>");
5481 if (dimensions
) dimensions
->set_fullname(p_fullname
);
5484 void Def_Port::set_my_scope(Scope
*p_scope
)
5486 Definition::set_my_scope(p_scope
);
5487 type_ref
->set_my_scope(p_scope
);
5488 if (dimensions
) dimensions
->set_my_scope(p_scope
);
5491 Type
*Def_Port::get_Type()
5497 ArrayDimensions
*Def_Port::get_Dimensions()
5499 if (!checked
) chk();
5503 void Def_Port::chk()
5505 if (checked
) return;
5507 Error_Context
cntxt(this, "In port definition `%s'",
5508 id
->get_dispname().c_str());
5509 Common::Assignment
*ass
= type_ref
->get_refd_assignment();
5511 if (ass
->get_asstype() == A_TYPE
) {
5512 Type
*t
= ass
->get_Type()->get_type_refd_last();
5513 if (t
->get_typetype() == Type::T_PORT
) port_type
= t
;
5514 else type_ref
->error("Type reference `%s' does not refer to a "
5515 "port type", type_ref
->get_dispname().c_str());
5516 } else type_ref
->error("Reference `%s' does not refer to a "
5517 "type", type_ref
->get_dispname().c_str());
5519 if (dimensions
) dimensions
->chk();
5520 if (w_attrib_path
) {
5521 w_attrib_path
->chk_global_attrib();
5522 w_attrib_path
->chk_no_qualif();
5526 bool Def_Port::chk_identical(Definition
*p_def
)
5530 if (p_def
->get_asstype() != A_PORT
) {
5531 const char *dispname_str
= id
->get_dispname().c_str();
5532 error("Local definition `%s' is a port, but the definition inherited "
5533 "from component type `%s' is a %s", dispname_str
,
5534 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
5535 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
5538 Def_Port
*p_def_port
= dynamic_cast<Def_Port
*>(p_def
);
5539 if (!p_def_port
) FATAL_ERROR("Def_Port::chk_identical()");
5540 if (port_type
&& p_def_port
->port_type
&&
5541 port_type
!= p_def_port
->port_type
) {
5542 const char *dispname_str
= id
->get_dispname().c_str();
5543 type_ref
->error("Local port `%s' has type `%s', but the port inherited "
5544 "from component type `%s' has type `%s'", dispname_str
,
5545 port_type
->get_typename().c_str(),
5546 p_def_port
->get_my_scope()->get_fullname().c_str(),
5547 p_def_port
->port_type
->get_typename().c_str());
5548 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5552 if (p_def_port
->dimensions
) {
5553 if (!dimensions
->is_identical(p_def_port
->dimensions
)) {
5554 const char *dispname_str
= id
->get_dispname().c_str();
5555 error("Local port `%s' and the port inherited from component type "
5556 "`%s' have different array dimensions", dispname_str
,
5557 p_def_port
->get_my_scope()->get_fullname().c_str());
5558 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5562 const char *dispname_str
= id
->get_dispname().c_str();
5563 error("Local definition `%s' is a port array, but the definition "
5564 "inherited from component type `%s' is a single port", dispname_str
,
5565 p_def_port
->get_my_scope()->get_fullname().c_str());
5566 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5569 } else if (p_def_port
->dimensions
) {
5570 const char *dispname_str
= id
->get_dispname().c_str();
5571 error("Local definition `%s' is a single port, but the definition "
5572 "inherited from component type `%s' is a port array", dispname_str
,
5573 p_def_port
->get_my_scope()->get_fullname().c_str());
5574 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5580 void Def_Port::generate_code(output_struct
*target
, bool)
5582 const string
& t_genname
= get_genname();
5583 const char *genname_str
= t_genname
.c_str();
5584 const string
& type_genname
= port_type
->get_genname_value(my_scope
);
5585 const string
& dispname
= id
->get_dispname();
5588 const string
& array_type
= dimensions
->get_port_type(type_genname
);
5589 const char *array_type_str
= array_type
.c_str();
5590 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5591 "extern %s %s;\n", array_type_str
, genname_str
);
5592 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5593 "%s %s;\n", array_type_str
, genname_str
);
5594 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
, "{\n"
5595 "static const char * const port_name = \"");
5596 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
5598 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
5600 "%s.set_name(port_name);\n"
5601 "}\n", genname_str
);
5604 const char *type_genname_str
= type_genname
.c_str();
5605 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5606 "extern %s %s;\n", type_genname_str
, genname_str
);
5607 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5608 "%s %s(\"%s\");\n", type_genname_str
, genname_str
, dispname
.c_str());
5610 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
5611 "%s.activate_port();\n", genname_str
);
5614 void Def_Port::generate_code(CodeGenHelper
& cgh
) {
5615 generate_code(cgh
.get_current_outputstruct());
5618 char *Def_Port::generate_code_init_comp(char *str
, Definition
*base_defn
)
5620 return mputprintf(str
, "%s.activate_port();\n",
5621 base_defn
->get_genname_from_scope(my_scope
).c_str());
5624 void Def_Port::dump_internal(unsigned level
) const
5626 DEBUG(level
, "Port: %s", id
->get_dispname().c_str());
5627 DEBUG(level
+ 1, "Port type:");
5628 type_ref
->dump(level
+ 2);
5629 if (dimensions
) dimensions
->dump(level
+ 1);
5632 // =================================
5633 // ===== Def_Function_Base
5634 // =================================
5636 Def_Function_Base::asstype_t
Def_Function_Base::determine_asstype(
5637 bool is_external
, bool has_return_type
, bool returns_template
)
5640 if (has_return_type
) {
5641 if (returns_template
) return A_EXT_FUNCTION_RTEMP
;
5642 else return A_EXT_FUNCTION_RVAL
;
5644 if (returns_template
)
5645 FATAL_ERROR("Def_Function_Base::determine_asstype()");
5646 return A_EXT_FUNCTION
;
5648 } else { // not an external function
5649 if (has_return_type
) {
5650 if (returns_template
) return A_FUNCTION_RTEMP
;
5651 else return A_FUNCTION_RVAL
;
5653 if (returns_template
)
5654 FATAL_ERROR("Def_Function_Base::determine_asstype()");
5660 Def_Function_Base::Def_Function_Base(const Def_Function_Base
& p
)
5661 : Definition(p
), prototype(PROTOTYPE_NONE
), input_type(0), output_type(0)
5663 fp_list
= p
.fp_list
->clone();
5664 fp_list
->set_my_def(this);
5665 return_type
= p
.return_type
? p
.return_type
->clone() : 0;
5666 template_restriction
= p
.template_restriction
;
5669 Def_Function_Base::Def_Function_Base(bool is_external
, Identifier
*p_id
,
5670 FormalParList
*p_fpl
, Type
*p_return_type
, bool returns_template
,
5671 template_restriction_t p_template_restriction
)
5672 : Definition(determine_asstype(is_external
, p_return_type
!= 0,
5673 returns_template
), p_id
), fp_list(p_fpl
), return_type(p_return_type
),
5674 prototype(PROTOTYPE_NONE
), input_type(0), output_type(0),
5675 template_restriction(p_template_restriction
)
5677 if (!p_fpl
) FATAL_ERROR("Def_Function_Base::Def_Function_Base()");
5678 fp_list
->set_my_def(this);
5679 if (return_type
) return_type
->set_ownertype(Type::OT_FUNCTION_DEF
, this);
5682 Def_Function_Base::~Def_Function_Base()
5688 void Def_Function_Base::set_fullname(const string
& p_fullname
)
5690 Definition::set_fullname(p_fullname
);
5691 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
5692 if (return_type
) return_type
->set_fullname(p_fullname
+ ".<return_type>");
5695 void Def_Function_Base::set_my_scope(Scope
*p_scope
)
5697 Definition::set_my_scope(p_scope
);
5698 fp_list
->set_my_scope(p_scope
);
5699 if (return_type
) return_type
->set_my_scope(p_scope
);
5702 Type
*Def_Function_Base::get_Type()
5704 if (!checked
) chk();
5708 FormalParList
*Def_Function_Base::get_FormalParList()
5710 if (!checked
) chk();
5714 const char *Def_Function_Base::get_prototype_name() const
5716 switch (prototype
) {
5717 case PROTOTYPE_NONE
:
5718 return "<no prototype>";
5719 case PROTOTYPE_CONVERT
:
5721 case PROTOTYPE_FAST
:
5723 case PROTOTYPE_BACKTRACK
:
5725 case PROTOTYPE_SLIDING
:
5728 return "<unknown prototype>";
5732 void Def_Function_Base::chk_prototype()
5734 switch (prototype
) {
5735 case PROTOTYPE_NONE
:
5736 // return immediately
5738 case PROTOTYPE_CONVERT
:
5739 case PROTOTYPE_FAST
:
5740 case PROTOTYPE_BACKTRACK
:
5741 case PROTOTYPE_SLIDING
:
5742 // perform the checks below
5745 FATAL_ERROR("Def_Function_Base::chk_prototype()");
5747 // checking the formal parameter list
5748 if (prototype
== PROTOTYPE_CONVERT
) {
5749 if (fp_list
->get_nof_fps() == 1) {
5750 FormalPar
*par
= fp_list
->get_fp_byIndex(0);
5751 if (par
->get_asstype() == A_PAR_VAL_IN
) {
5752 input_type
= par
->get_Type();
5754 par
->error("The parameter must be an `in' value parameter for "
5755 "attribute `prototype(%s)' instead of %s", get_prototype_name(),
5756 par
->get_assname());
5759 fp_list
->error("The function must have one parameter instead of %lu "
5760 "for attribute `prototype(%s)'", (unsigned long) fp_list
->get_nof_fps(),
5761 get_prototype_name());
5763 } else { // not PROTOTYPE_CONVERT
5764 if (fp_list
->get_nof_fps() == 2) {
5765 FormalPar
*first_par
= fp_list
->get_fp_byIndex(0);
5766 if (prototype
== PROTOTYPE_SLIDING
) {
5767 if (first_par
->get_asstype() == A_PAR_VAL_INOUT
) {
5768 Type
*first_par_type
= first_par
->get_Type();
5769 switch (first_par_type
->get_type_refd_last()
5770 ->get_typetype_ttcn3()) {
5775 input_type
= first_par_type
;
5778 first_par_type
->error("The type of the first parameter must be "
5779 "`octetstring' or `charstring' or `bitstring' for attribute "
5780 "`prototype(%s)' instead of `%s'", get_prototype_name(),
5781 first_par_type
->get_typename().c_str());
5784 first_par
->error("The first parameter must be an `inout' value "
5785 "parameter for attribute `prototype(%s)' instead of %s",
5786 get_prototype_name(), first_par
->get_assname());
5789 if (first_par
->get_asstype() == A_PAR_VAL_IN
) {
5790 input_type
= first_par
->get_Type();
5792 first_par
->error("The first parameter must be an `in' value "
5793 "parameter for attribute `prototype(%s)' instead of %s",
5794 get_prototype_name(), first_par
->get_assname());
5797 FormalPar
*second_par
= fp_list
->get_fp_byIndex(1);
5798 if (second_par
->get_asstype() == A_PAR_VAL_OUT
) {
5799 output_type
= second_par
->get_Type();
5801 second_par
->error("The second parameter must be an `out' value "
5802 "parameter for attribute `prototype(%s)' instead of %s",
5803 get_prototype_name(), second_par
->get_assname());
5806 fp_list
->error("The function must have two parameters for attribute "
5807 "`prototype(%s)' instead of %lu", get_prototype_name(),
5808 (unsigned long) fp_list
->get_nof_fps());
5811 // checking the return type
5812 if (prototype
== PROTOTYPE_FAST
) {
5814 return_type
->error("The function cannot have return type for "
5815 "attribute `prototype(%s)'", get_prototype_name());
5819 if (asstype
== A_FUNCTION_RTEMP
|| asstype
== A_EXT_FUNCTION_RTEMP
)
5820 return_type
->error("The function must return a value instead of a "
5821 "template for attribute `prototype(%s)'", get_prototype_name());
5822 if (prototype
== PROTOTYPE_CONVERT
) {
5823 output_type
= return_type
;
5825 switch (return_type
->get_type_refd_last()->get_typetype_ttcn3()) {
5830 return_type
->error("The return type of the function must be "
5831 "`integer' instead of `%s' for attribute `prototype(%s)'",
5832 return_type
->get_typename().c_str(), get_prototype_name());
5836 error("The function must have return type for attribute "
5837 "`prototype(%s)'", get_prototype_name());
5840 // checking the 'runs on' clause
5841 if (get_RunsOnType()) {
5842 error("The function cannot have `runs on' clause for attribute "
5843 "`prototype(%s)'", get_prototype_name());
5847 Type
*Def_Function_Base::get_input_type()
5849 if (!checked
) chk();
5853 Type
*Def_Function_Base::get_output_type()
5855 if (!checked
) chk();
5860 // =================================
5861 // ===== Def_Function
5862 // =================================
5864 Def_Function::Def_Function(Identifier
*p_id
, FormalParList
*p_fpl
,
5865 Reference
*p_runs_on_ref
, Type
*p_return_type
,
5866 bool returns_template
,
5867 template_restriction_t p_template_restriction
,
5868 StatementBlock
*p_block
)
5869 : Def_Function_Base(false, p_id
, p_fpl
, p_return_type
, returns_template
,
5870 p_template_restriction
),
5871 runs_on_ref(p_runs_on_ref
), runs_on_type(0), block(p_block
),
5872 is_startable(false), transparent(false)
5874 if (!p_block
) FATAL_ERROR("Def_Function::Def_Function()");
5875 block
->set_my_def(this);
5878 Def_Function::~Def_Function()
5884 Def_Function
*Def_Function::clone() const
5886 FATAL_ERROR("Def_Function::clone");
5889 void Def_Function::set_fullname(const string
& p_fullname
)
5891 Def_Function_Base::set_fullname(p_fullname
);
5892 if (runs_on_ref
) runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
5893 block
->set_fullname(p_fullname
+ ".<statement_block>");
5896 void Def_Function::set_my_scope(Scope
*p_scope
)
5898 bridgeScope
.set_parent_scope(p_scope
);
5899 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
5901 Def_Function_Base::set_my_scope(&bridgeScope
);
5902 if (runs_on_ref
) runs_on_ref
->set_my_scope(&bridgeScope
);
5903 block
->set_my_scope(fp_list
);
5906 Type
*Def_Function::get_RunsOnType()
5908 if (!checked
) chk();
5909 return runs_on_type
;
5912 RunsOnScope
*Def_Function::get_runs_on_scope(Type
*comptype
)
5914 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
5915 if (!my_module
) FATAL_ERROR("Def_Function::get_runs_on_scope()");
5916 return my_module
->get_runs_on_scope(comptype
);
5919 void Def_Function::chk()
5921 if (checked
) return;
5923 Error_Context
cntxt(this, "In function definition `%s'",
5924 id
->get_dispname().c_str());
5925 // checking the `runs on' clause
5927 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
5928 runs_on_type
= runs_on_ref
->chk_comptype_ref();
5929 // override the scope of the formal parameter list
5931 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
5932 runs_on_scope
->set_parent_scope(my_scope
);
5933 fp_list
->set_my_scope(runs_on_scope
);
5936 // checking the formal parameter list
5937 fp_list
->chk(asstype
);
5938 // checking of return type
5940 Error_Context
cntxt2(return_type
, "In return type");
5942 return_type
->chk_as_return_type(asstype
== A_FUNCTION_RVAL
,"function");
5944 // decision of startability
5945 is_startable
= runs_on_ref
!= 0;
5946 if (is_startable
&& !fp_list
->get_startability()) is_startable
= false;
5947 if (is_startable
&& return_type
&& return_type
->is_component_internal())
5948 is_startable
= false;
5949 // checking of statement block
5952 // checking the presence of return statements
5953 switch (block
->has_return()) {
5954 case StatementBlock::RS_NO
:
5955 error("The function has return type, but it does not have any return "
5958 case StatementBlock::RS_MAYBE
:
5959 error("The function has return type, but control might leave it "
5960 "without reaching a return statement");
5965 if (!semantic_check_only
) {
5966 fp_list
->set_genname(get_genname());
5967 block
->set_code_section(GovernedSimple::CS_INLINE
);
5969 if (w_attrib_path
) {
5970 w_attrib_path
->chk_global_attrib();
5971 w_attrib_path
->chk_no_qualif();
5972 Ttcn::ExtensionAttributes
* extattrs
= parse_extattributes(w_attrib_path
);
5973 if (extattrs
!= 0) { // NULL means parsing error
5974 size_t num_atrs
= extattrs
->size();
5975 for (size_t i
=0; i
< num_atrs
; ++i
) {
5976 ExtensionAttribute
&ea
= extattrs
->get(i
);
5977 switch (ea
.get_type()) {
5978 case ExtensionAttribute::PROTOTYPE
: {
5979 if (get_prototype() != Def_Function_Base::PROTOTYPE_NONE
) {
5980 ea
.error("Duplicate attribute `prototype'");
5982 Def_Function_Base::prototype_t proto
= ea
.get_proto();
5983 set_prototype(proto
);
5986 case ExtensionAttribute::ANYTYPELIST
: // ignore it
5987 case ExtensionAttribute::NONE
: // erroneous, do not issue an error
5990 case ExtensionAttribute::TRANSPARENT
:
5994 case ExtensionAttribute::ENCODE
:
5995 case ExtensionAttribute::DECODE
:
5996 case ExtensionAttribute::ERRORBEHAVIOR
:
5997 case ExtensionAttribute::PRINTING
:
5998 ea
.error("Extension attribute 'encode', 'decode', 'errorbehavior'"
5999 " or 'printing' can only be applied to external functions");
6002 default: // complain
6003 ea
.error("Function definition can only have the 'prototype'"
6004 " extension attribute");
6014 bool Def_Function::chk_startable()
6016 if (!checked
) chk();
6017 if (is_startable
) return true;
6018 if (!runs_on_ref
) error("Function `%s' cannot be started on a parallel "
6019 "test component because it does not have `runs on' clause",
6020 get_fullname().c_str());
6021 fp_list
->chk_startability("Function", get_fullname().c_str());
6022 if (return_type
&& return_type
->is_component_internal()) {
6023 map
<Type
*,void> type_chain
;
6024 char* err_str
= mprintf("the return type or embedded in the return type "
6025 "of function `%s' if it is started on a parallel test component",
6026 get_fullname().c_str());
6027 return_type
->chk_component_internal(type_chain
, err_str
);
6033 void Def_Function::generate_code(output_struct
*target
, bool)
6035 transparency_holder
glass(*this);
6036 const string
& t_genname
= get_genname();
6037 const char *genname_str
= t_genname
.c_str();
6038 const char *dispname_str
= id
->get_dispname().c_str();
6039 string return_type_name
;
6042 return_type_name
= "void";
6044 case A_FUNCTION_RVAL
:
6045 return_type_name
= return_type
->get_genname_value(my_scope
);
6047 case A_FUNCTION_RTEMP
:
6048 return_type_name
= return_type
->get_genname_template(my_scope
);
6051 FATAL_ERROR("Def_Function::generate_code()");
6053 const char *return_type_str
= return_type_name
.c_str();
6055 // assemble the function body first (this also determines which parameters
6057 char* body
= create_location_object(memptystr(), "FUNCTION", dispname_str
);
6058 if (!enable_set_bound_out_param
)
6059 body
= fp_list
->generate_code_set_unbound(body
); // conform the standard out parameter is unbound
6060 body
= fp_list
->generate_shadow_objects(body
);
6061 body
= block
->generate_code(body
);
6062 // smart formal parameter list (names of unused parameters are omitted)
6063 char *formal_par_list
= fp_list
->generate_code(memptystr());
6064 fp_list
->generate_code_defval(target
);
6065 // function prototype
6066 target
->header
.function_prototypes
=
6067 mputprintf(target
->header
.function_prototypes
, "extern %s %s(%s);\n",
6068 return_type_str
, genname_str
, formal_par_list
);
6071 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
6075 "}\n\n", return_type_str
, genname_str
, formal_par_list
, body
);
6076 Free(formal_par_list
);
6080 size_t nof_fps
= fp_list
->get_nof_fps();
6081 // use the full list of formal parameters here (since they are all logged)
6082 char *full_formal_par_list
= fp_list
->generate_code(memptystr(), nof_fps
);
6083 // starter function (stub)
6084 // function prototype
6085 target
->header
.function_prototypes
=
6086 mputprintf(target
->header
.function_prototypes
,
6087 "extern void start_%s(const COMPONENT& component_reference%s%s);\n",
6088 genname_str
, nof_fps
>0?", ":"", full_formal_par_list
);
6090 body
= mprintf("void start_%s(const COMPONENT& component_reference%s"
6093 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
6094 "TTCN_Logger::log_event_str(\"Starting function %s(\");\n",
6095 genname_str
, nof_fps
>0?", ":"", full_formal_par_list
, dispname_str
);
6096 for (size_t i
= 0; i
< nof_fps
; i
++) {
6097 if (i
> 0) body
= mputstr(body
,
6098 "TTCN_Logger::log_event_str(\", \");\n");
6099 body
= mputprintf(body
, "%s.log();\n",
6100 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6102 body
= mputprintf(body
,
6103 "TTCN_Logger::log_event_str(\") on component \");\n"
6104 "component_reference.log();\n"
6105 "TTCN_Logger::log_char('.');\n"
6106 "TTCN_Logger::end_event();\n"
6107 "Text_Buf text_buf;\n"
6108 "TTCN_Runtime::prepare_start_component(component_reference, "
6109 "\"%s\", \"%s\", text_buf);\n",
6110 my_scope
->get_scope_mod()->get_modid().get_dispname().c_str(),
6112 for (size_t i
= 0; i
< nof_fps
; i
++) {
6113 body
= mputprintf(body
, "%s.encode_text(text_buf);\n",
6114 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6116 body
= mputstr(body
, "TTCN_Runtime::send_start_component(text_buf);\n"
6118 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6122 // an entry in start_ptc_function
6123 body
= mprintf("if (!strcmp(function_name, \"%s\")) {\n",
6126 body
= fp_list
->generate_code_object(body
, "", ' ');
6127 for (size_t i
= 0; i
< nof_fps
; i
++) {
6128 body
= mputprintf(body
, "%s.decode_text(function_arguments);\n",
6129 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6131 body
= mputprintf(body
,
6132 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
6133 "TTCN_Logger::log_event_str(\"Starting function %s(\");\n",
6135 for (size_t i
= 0; i
< nof_fps
; i
++) {
6136 if (i
> 0) body
= mputstr(body
,
6137 "TTCN_Logger::log_event_str(\", \");\n");
6138 body
= mputprintf(body
, "%s.log();\n",
6139 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6141 body
= mputstr(body
, "TTCN_Logger::log_event_str(\").\");\n"
6142 "TTCN_Logger::end_event();\n");
6144 body
= mputprintf(body
,
6145 "TTCN_Logger::log_str(TTCN_Logger::PARALLEL_PTC, \"Starting function "
6146 "%s().\");\n", dispname_str
);
6148 body
= mputstr(body
,
6149 "TTCN_Runtime::function_started(function_arguments);\n");
6150 char *actual_par_list
=
6151 fp_list
->generate_code_actual_parlist(memptystr(), "");
6152 bool return_value_kept
= false;
6153 if (asstype
== A_FUNCTION_RVAL
) {
6154 // the return value is kept only if the function returns a value
6155 // (rather than a template) and the return type has the "done"
6156 // extension attribute
6157 for (Type
*t
= return_type
; ; t
= t
->get_type_refd()) {
6158 if (t
->has_done_attribute()) {
6159 return_value_kept
= true;
6161 } else if (!t
->is_ref()) break;
6164 if (return_value_kept
) {
6165 const string
& return_type_dispname
= return_type
->get_typename();
6166 const char *return_type_dispname_str
= return_type_dispname
.c_str();
6167 body
= mputprintf(body
, "%s ret_val(%s(%s));\n"
6168 "TTCN_Logger::begin_event(TTCN_PARALLEL);\n"
6169 "TTCN_Logger::log_event_str(\"Function %s returned %s : \");\n"
6171 "Text_Buf text_buf;\n"
6172 "TTCN_Runtime::prepare_function_finished(\"%s\", text_buf);\n"
6173 "ret_val.encode_text(text_buf);\n"
6174 "TTCN_Runtime::send_function_finished(text_buf);\n",
6175 return_type_str
, genname_str
, actual_par_list
, dispname_str
,
6176 return_type_dispname_str
, return_type_dispname_str
);
6178 body
= mputprintf(body
, "%s(%s);\n"
6179 "TTCN_Runtime::function_finished(\"%s\");\n",
6180 genname_str
, actual_par_list
, dispname_str
);
6182 Free(actual_par_list
);
6183 body
= mputstr(body
, "return TRUE;\n"
6185 target
->functions
.start
= mputstr(target
->functions
.start
, body
);
6187 Free(full_formal_par_list
);
6190 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6191 "%s.add_function(\"%s\", (genericfunc_t)&%s, ", get_module_object_name(),
6192 dispname_str
, genname_str
);
6194 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6195 "(genericfunc_t)&start_%s);\n", genname_str
);
6197 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
6201 void Def_Function::generate_code(CodeGenHelper
& cgh
) {
6202 generate_code(cgh
.get_current_outputstruct());
6205 void Def_Function::dump_internal(unsigned level
) const
6207 DEBUG(level
, "Function: %s", id
->get_dispname().c_str());
6208 DEBUG(level
+ 1, "Parameters:");
6209 fp_list
->dump(level
+ 1);
6211 DEBUG(level
+ 1, "Runs on clause:");
6212 runs_on_ref
->dump(level
+ 2);
6215 DEBUG(level
+ 1, "Return type:");
6216 return_type
->dump(level
+ 2);
6217 if (asstype
== A_FUNCTION_RTEMP
) DEBUG(level
+ 1, "Returns template");
6219 if (prototype
!= PROTOTYPE_NONE
)
6220 DEBUG(level
+ 1, "Prototype: %s", get_prototype_name());
6221 //DEBUG(level + 1, "Statement block:");
6222 block
->dump(level
+ 1);
6225 void Def_Function::set_parent_path(WithAttribPath
* p_path
) {
6226 Def_Function_Base::set_parent_path(p_path
);
6227 block
->set_parent_path(w_attrib_path
);
6230 // =================================
6231 // ===== Def_ExtFunction
6232 // =================================
6234 Def_ExtFunction::~Def_ExtFunction()
6236 delete encoding_options
;
6238 if (NULL
!= json_printing
) {
6239 delete json_printing
;
6243 Def_ExtFunction
*Def_ExtFunction::clone() const
6245 FATAL_ERROR("Def_ExtFunction::clone");
6248 void Def_ExtFunction::set_fullname(const string
& p_fullname
)
6250 Def_Function_Base::set_fullname(p_fullname
);
6251 if (eb_list
) eb_list
->set_fullname(p_fullname
+ ".<errorbehavior_list>");
6254 void Def_ExtFunction::set_encode_parameters(Type::MessageEncodingType_t
6255 p_encoding_type
, string
*p_encoding_options
)
6257 function_type
= EXTFUNC_ENCODE
;
6258 encoding_type
= p_encoding_type
;
6259 delete encoding_options
;
6260 encoding_options
= p_encoding_options
;
6263 void Def_ExtFunction::set_decode_parameters(Type::MessageEncodingType_t
6264 p_encoding_type
, string
*p_encoding_options
)
6266 function_type
= EXTFUNC_DECODE
;
6267 encoding_type
= p_encoding_type
;
6268 delete encoding_options
;
6269 encoding_options
= p_encoding_options
;
6272 void Def_ExtFunction::add_eb_list(Ttcn::ErrorBehaviorList
*p_eb_list
)
6274 if (!p_eb_list
) FATAL_ERROR("Def_ExtFunction::add_eb_list()");
6276 eb_list
->steal_ebs(p_eb_list
);
6279 eb_list
= p_eb_list
;
6280 eb_list
->set_fullname(get_fullname() + ".<errorbehavior_list>");
6284 void Def_ExtFunction::chk_function_type()
6286 switch (function_type
) {
6287 case EXTFUNC_MANUAL
:
6289 eb_list
->error("Attribute `errorbehavior' can only be used together "
6290 "with `encode' or `decode'");
6294 case EXTFUNC_ENCODE
:
6295 switch (prototype
) {
6296 case PROTOTYPE_NONE
:
6297 error("Attribute `encode' cannot be used without `prototype'");
6299 case PROTOTYPE_BACKTRACK
:
6300 case PROTOTYPE_SLIDING
:
6301 error("Attribute `encode' cannot be used with `prototype(%s)'",
6302 get_prototype_name());
6303 default: /* CONVERT and FAST allowed */
6308 if (!input_type
->has_encoding(encoding_type
, encoding_options
)) {
6309 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6310 input_type
->error("Input type `%s' does not support custom encoding '%s'",
6311 input_type
->get_typename().c_str(), encoding_options
->c_str());
6314 input_type
->error("Input type `%s' does not support %s encoding",
6315 input_type
->get_typename().c_str(),
6316 Type::get_encoding_name(encoding_type
));
6320 if (Common::Type::CT_XER
== encoding_type
6321 && input_type
->get_type_refd_last()->is_untagged()) {
6322 // "untagged" on the (toplevel) input type will have no effect.
6323 warning("UNTAGGED encoding attribute is ignored on top-level type");
6325 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6326 if (PROTOTYPE_CONVERT
!= prototype
) {
6327 error("Only `prototype(convert)' is allowed for custom encoding functions");
6330 // let the input type know that this is its encoding function
6331 input_type
->get_type_refd()->set_coding_function(true,
6332 get_genname_from_scope(input_type
->get_type_refd()->get_my_scope()));
6333 // treat this as a manual external function during code generation
6334 function_type
= EXTFUNC_MANUAL
;
6340 if(encoding_type
== Common::Type::CT_TEXT
) { // TEXT encoding supports both octetstring and charstring stream types
6341 Type
*stream_type
= Type::get_stream_type(encoding_type
,0);
6342 Type
*stream_type2
= Type::get_stream_type(encoding_type
,1);
6343 if ( (!stream_type
->is_identical(output_type
)) && (!stream_type2
->is_identical(output_type
)) ) {
6344 output_type
->error("The output type of %s encoding should be `%s' or `%s' "
6345 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6346 stream_type
->get_typename().c_str(),
6347 stream_type2
->get_typename().c_str(),
6348 output_type
->get_typename().c_str());
6351 Type
*stream_type
= Type::get_stream_type(encoding_type
);
6352 if (!stream_type
->is_identical(output_type
)) {
6353 output_type
->error("The output type of %s encoding should be `%s' "
6354 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6355 stream_type
->get_typename().c_str(),
6356 output_type
->get_typename().c_str());
6360 if (eb_list
) eb_list
->chk();
6361 chk_allowed_encode();
6363 case EXTFUNC_DECODE
:
6364 if (prototype
== PROTOTYPE_NONE
) {
6365 error("Attribute `decode' cannot be used without `prototype'");
6368 if(encoding_type
== Common::Type::CT_TEXT
) { // TEXT encoding supports both octetstring and charstring stream types
6369 Type
*stream_type
= Type::get_stream_type(encoding_type
,0);
6370 Type
*stream_type2
= Type::get_stream_type(encoding_type
,1);
6371 if ( (!stream_type
->is_identical(input_type
)) && (!stream_type2
->is_identical(input_type
)) ) {
6372 input_type
->error("The input type of %s decoding should be `%s' or `%s' "
6373 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6374 stream_type
->get_typename().c_str(),
6375 stream_type2
->get_typename().c_str(),
6376 input_type
->get_typename().c_str());
6379 Type
*stream_type
= Type::get_stream_type(encoding_type
);
6380 if (!stream_type
->is_identical(input_type
)) {
6381 input_type
->error("The input type of %s decoding should be `%s' "
6382 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6383 stream_type
->get_typename().c_str(),
6384 input_type
->get_typename().c_str());
6389 if (output_type
&& !output_type
->has_encoding(encoding_type
, encoding_options
)) {
6390 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6391 output_type
->error("Output type `%s' does not support custom encoding '%s'",
6392 output_type
->get_typename().c_str(), encoding_options
->c_str());
6395 output_type
->error("Output type `%s' does not support %s encoding",
6396 output_type
->get_typename().c_str(),
6397 Type::get_encoding_name(encoding_type
));
6401 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6402 if (PROTOTYPE_SLIDING
!= prototype
) {
6403 error("Only `prototype(sliding)' is allowed for custom decoding functions");
6405 else if (output_type
) {
6406 // let the output type know that this is its decoding function
6407 output_type
->get_type_refd()->set_coding_function(false,
6408 get_genname_from_scope(output_type
->get_type_refd()->get_my_scope()));
6409 // treat this as a manual external function during code generation
6410 function_type
= EXTFUNC_MANUAL
;
6414 if (eb_list
) eb_list
->chk();
6415 chk_allowed_encode();
6418 FATAL_ERROR("Def_ExtFunction::chk()");
6422 void Def_ExtFunction::chk_allowed_encode()
6424 switch (encoding_type
) {
6426 if (enable_ber()) return; // ok
6429 if (enable_raw()) return; // ok
6432 if (enable_text()) return; // ok
6435 if (enable_xer()) return; // ok
6438 if (enable_per()) return; // ok?
6441 if (enable_json()) return;
6443 case Type::CT_CUSTOM
:
6444 return; // cannot be disabled
6446 FATAL_ERROR("Def_ExtFunction::chk_allowed_encode");
6450 error("%s encoding is disallowed by license or commandline options",
6451 Type::get_encoding_name(encoding_type
));
6454 void Def_ExtFunction::chk()
6456 if (checked
) return;
6458 Error_Context
cntxt(this, "In external function definition `%s'",
6459 id
->get_dispname().c_str());
6460 fp_list
->chk(asstype
);
6462 Error_Context
cntxt2(return_type
, "In return type");
6464 return_type
->chk_as_return_type(asstype
== A_EXT_FUNCTION_RVAL
,
6465 "external function");
6467 if (!semantic_check_only
) fp_list
->set_genname(get_genname());
6468 if (w_attrib_path
) {
6469 w_attrib_path
->chk_global_attrib();
6470 w_attrib_path
->chk_no_qualif();
6471 const Ttcn::ExtensionAttributes
* extattrs
= parse_extattributes(w_attrib_path
);
6472 if (extattrs
!= 0) {
6473 size_t num_atrs
= extattrs
->size();
6474 for (size_t i
=0; i
< num_atrs
; ++i
) {
6475 ExtensionAttribute
&ea
= extattrs
->get(i
);
6476 switch (ea
.get_type()) {
6477 case ExtensionAttribute::PROTOTYPE
: {
6478 if (get_prototype() != Def_Function_Base::PROTOTYPE_NONE
) {
6479 ea
.error("Duplicate attribute `prototype'");
6481 Def_Function_Base::prototype_t proto
= ea
.get_proto();
6482 set_prototype(proto
);
6485 case ExtensionAttribute::ENCODE
: {
6486 switch (get_function_type()) {
6487 case Def_ExtFunction::EXTFUNC_MANUAL
:
6489 case Def_ExtFunction::EXTFUNC_ENCODE
: {
6490 ea
.error("Duplicate attribute `encode'");
6492 case Def_ExtFunction::EXTFUNC_DECODE
: {
6493 ea
.error("Attributes `decode' and `encode' "
6494 "cannot be used at the same time");
6497 FATAL_ERROR("coding_attrib_parse(): invalid external function type");
6499 Type::MessageEncodingType_t et
;
6501 ea
.get_encdec_parameters(et
, opt
);
6502 set_encode_parameters(et
, opt
);
6505 case ExtensionAttribute::ERRORBEHAVIOR
: {
6506 add_eb_list(ea
.get_eb_list());
6509 case ExtensionAttribute::DECODE
: {
6510 switch (get_function_type()) {
6511 case Def_ExtFunction::EXTFUNC_MANUAL
:
6513 case Def_ExtFunction::EXTFUNC_ENCODE
: {
6514 ea
.error("Attributes `encode' and `decode' "
6515 "cannot be used at the same time");
6517 case Def_ExtFunction::EXTFUNC_DECODE
: {
6518 ea
.error("Duplicate attribute `decode'");
6521 FATAL_ERROR("coding_attrib_parse(): invalid external function type");
6523 Type::MessageEncodingType_t et
;
6525 ea
.get_encdec_parameters(et
, opt
);
6526 set_decode_parameters(et
, opt
);
6529 case ExtensionAttribute::PRINTING
: {
6530 json_printing
= ea
.get_printing();
6533 case ExtensionAttribute::ANYTYPELIST
:
6534 // ignore, because we can't distinguish between a local
6535 // "extension anytype" (which is bogus) and an inherited one
6536 // (which was meant for a type definition)
6539 case ExtensionAttribute::NONE
:
6540 // Ignore, do not issue "wrong type" error
6545 "Only the following extension attributes may be applied to "
6546 "external functions: 'prototype', 'encode', 'decode', 'errorbehavior'");
6554 chk_function_type();
6556 if (NULL
!= json_printing
&& (EXTFUNC_ENCODE
!= function_type
||
6557 Type::CT_JSON
!= encoding_type
)) {
6558 error("Attribute 'printing' is only allowed for JSON encoding functions.");
6562 char *Def_ExtFunction::generate_code_encode(char *str
)
6564 const char *function_name
= id
->get_dispname().c_str();
6565 const char *first_par_name
=
6566 fp_list
->get_fp_byIndex(0)->get_id().get_name().c_str();
6567 // producing debug printout of the input PDU
6568 str
= mputprintf(str
,
6570 "// written by %s in " __FILE__
" at %d\n"
6572 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6573 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6574 "TTCN_Logger::log_event_str(\"%s(): Encoding %s: \");\n"
6576 "TTCN_Logger::end_event();\n"
6579 , __FUNCTION__
, __LINE__
6581 , function_name
, input_type
->get_typename().c_str(), first_par_name
);
6582 // setting error behavior
6583 if (eb_list
) str
= eb_list
->generate_code(str
);
6584 else str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6585 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n");
6586 // encoding PDU into the buffer
6587 str
= mputstr(str
, "TTCN_Buffer ttcn_buffer;\n");
6588 str
= mputprintf(str
, "%s.encode(%s_descr_, ttcn_buffer, TTCN_EncDec::CT_%s",
6590 input_type
->get_genname_typedescriptor(my_scope
).c_str(),
6591 Type::get_encoding_name(encoding_type
));
6592 if (encoding_type
== Type::CT_JSON
) {
6593 if (json_printing
!= NULL
) {
6594 str
= json_printing
->generate_code(str
);
6596 str
= mputstr(str
, ", 0");
6599 if (encoding_options
) str
= mputprintf(str
, ", %s",
6600 encoding_options
->c_str());
6601 str
= mputstr(str
, ");\n");
6602 const char *result_name
;
6603 switch (prototype
) {
6604 case PROTOTYPE_CONVERT
:
6605 result_name
= "ret_val";
6606 // creating a local variable for the result stream
6607 str
= mputprintf(str
, "%s ret_val;\n",
6608 output_type
->get_genname_value(my_scope
).c_str());
6610 case PROTOTYPE_FAST
:
6611 result_name
= fp_list
->get_fp_byIndex(1)->get_id().get_name().c_str();
6614 FATAL_ERROR("Def_ExtFunction::generate_code_encode()");
6617 // taking the result from the buffer and producing debug printout
6618 str
= mputprintf(str
, "ttcn_buffer.get_string(%s);\n"
6619 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6620 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6621 "TTCN_Logger::log_event_str(\"%s(): Stream after encoding: \");\n"
6623 "TTCN_Logger::end_event();\n"
6624 "}\n", result_name
, function_name
, result_name
);
6625 // returning the result stream if necessary
6626 if (prototype
== PROTOTYPE_CONVERT
) str
= mputstr(str
, "return ret_val;\n");
6630 char *Def_ExtFunction::generate_code_decode(char *str
)
6632 const char *function_name
= id
->get_dispname().c_str();
6633 const char *first_par_name
=
6634 fp_list
->get_fp_byIndex(0)->get_id().get_name().c_str();
6635 // producing debug printout of the input stream
6636 str
= mputprintf(str
,
6638 "// written by %s in " __FILE__
" at %d\n"
6640 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6641 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6642 "TTCN_Logger::log_event_str(\"%s(): Stream before decoding: \");\n"
6644 "TTCN_Logger::end_event();\n"
6647 , __FUNCTION__
, __LINE__
6649 , function_name
, first_par_name
);
6650 // setting error behavior
6651 if (eb_list
) str
= eb_list
->generate_code(str
);
6652 else if (prototype
== PROTOTYPE_BACKTRACK
|| prototype
== PROTOTYPE_SLIDING
) {
6653 str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6654 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);\n");
6655 } else str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6656 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n");
6657 // creating a buffer from the input stream
6658 str
= mputprintf(str
, "TTCN_EncDec::clear_error();\n"
6659 "TTCN_Buffer ttcn_buffer(%s);\n", first_par_name
);
6660 const char *result_name
;
6661 if (prototype
== PROTOTYPE_CONVERT
) {
6662 // creating a local variable for the result
6663 str
= mputprintf(str
, "%s ret_val;\n",
6664 output_type
->get_genname_value(my_scope
).c_str());
6665 result_name
= "ret_val";
6667 result_name
= fp_list
->get_fp_byIndex(1)->get_id().get_name().c_str();
6669 if(encoding_type
==Type::CT_TEXT
){
6670 str
= mputprintf(str
,
6671 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6672 " TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_LOG_MATCHING, TTCN_EncDec::EB_WARNING);\n"
6675 str
= mputprintf(str
, "%s.decode(%s_descr_, ttcn_buffer, "
6676 "TTCN_EncDec::CT_%s", result_name
,
6677 output_type
->get_genname_typedescriptor(my_scope
).c_str(),
6678 Type::get_encoding_name(encoding_type
));
6679 if (encoding_options
) str
= mputprintf(str
, ", %s",
6680 encoding_options
->c_str());
6681 str
= mputstr(str
, ");\n");
6682 // producing debug printout of the result PDU
6683 str
= mputprintf(str
,
6684 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6685 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6686 "TTCN_Logger::log_event_str(\"%s(): Decoded %s: \");\n"
6688 "TTCN_Logger::end_event();\n"
6689 "}\n", function_name
, output_type
->get_typename().c_str(), result_name
);
6690 if (prototype
!= PROTOTYPE_SLIDING
) {
6691 // checking for remaining data in the buffer if decoding was successful
6692 str
= mputprintf(str
, "if (TTCN_EncDec::get_last_error_type() == "
6693 "TTCN_EncDec::ET_NONE) {\n"
6694 "if (ttcn_buffer.get_pos() < ttcn_buffer.get_len()-1 && "
6695 "TTCN_Logger::log_this_event(TTCN_WARNING)) {\n"
6696 "ttcn_buffer.cut();\n"
6697 "%s remaining_stream;\n"
6698 "ttcn_buffer.get_string(remaining_stream);\n"
6699 "TTCN_Logger::begin_event(TTCN_WARNING);\n"
6700 "TTCN_Logger::log_event_str(\"%s(): Warning: Data remained at the end "
6701 "of the stream after successful decoding: \");\n"
6702 "remaining_stream.log();\n"
6703 "TTCN_Logger::end_event();\n"
6704 "}\n", input_type
->get_genname_value(my_scope
).c_str(), function_name
);
6705 // closing the block and returning the appropriate result or status code
6706 if (prototype
== PROTOTYPE_BACKTRACK
) {
6707 str
= mputstr(str
, "return 0;\n"
6708 "} else return 1;\n");
6710 str
= mputstr(str
, "}\n");
6711 if (prototype
== PROTOTYPE_CONVERT
)
6712 str
= mputstr(str
, "return ret_val;\n");
6715 // result handling and debug printout for sliding decoders
6716 str
= mputprintf(str
, "switch (TTCN_EncDec::get_last_error_type()) {\n"
6717 "case TTCN_EncDec::ET_NONE:\n"
6718 // TTCN_Buffer::get_string will call OCTETSTRING::clean_up()
6719 "ttcn_buffer.cut();\n"
6720 "ttcn_buffer.get_string(%s);\n"
6721 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6722 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6723 "TTCN_Logger::log_event_str(\"%s(): Stream after decoding: \");\n"
6725 "TTCN_Logger::end_event();\n"
6728 "case TTCN_EncDec::ET_INCOMPL_MSG:\n"
6729 "case TTCN_EncDec::ET_LEN_ERR:\n"
6733 "}\n", first_par_name
, function_name
, first_par_name
);
6738 void Def_ExtFunction::generate_code(output_struct
*target
, bool)
6740 const string
& t_genname
= get_genname();
6741 const char *genname_str
= t_genname
.c_str();
6742 string return_type_name
;
6744 case A_EXT_FUNCTION
:
6745 return_type_name
= "void";
6747 case A_EXT_FUNCTION_RVAL
:
6748 return_type_name
= return_type
->get_genname_value(my_scope
);
6750 case A_EXT_FUNCTION_RTEMP
:
6751 return_type_name
= return_type
->get_genname_template(my_scope
);
6754 FATAL_ERROR("Def_ExtFunction::generate_code()");
6756 const char *return_type_str
= return_type_name
.c_str();
6757 char *formal_par_list
= fp_list
->generate_code(memptystr(), fp_list
->get_nof_fps());
6758 fp_list
->generate_code_defval(target
);
6759 // function prototype
6760 target
->header
.function_prototypes
=
6761 mputprintf(target
->header
.function_prototypes
, "extern %s %s(%s);\n",
6762 return_type_str
, genname_str
, formal_par_list
);
6764 if (function_type
!= EXTFUNC_MANUAL
) {
6765 // function body written by the compiler
6768 body
= mprintf("// written by %s in " __FILE__
" at %d\n"
6769 , __FUNCTION__
, __LINE__
);
6771 body
= mputprintf(body
,
6774 , return_type_str
, genname_str
, formal_par_list
);
6775 switch (function_type
) {
6776 case EXTFUNC_ENCODE
:
6777 body
= generate_code_encode(body
);
6779 case EXTFUNC_DECODE
:
6780 body
= generate_code_decode(body
);
6783 FATAL_ERROR("Def_ExtFunction::generate_code()");
6785 body
= mputstr(body
, "}\n\n");
6786 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6791 Free(formal_par_list
);
6793 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6794 "%s.add_function(\"%s\", (genericfunc_t)&%s, NULL);\n",
6795 get_module_object_name(), id
->get_dispname().c_str(), genname_str
);
6798 void Def_ExtFunction::generate_code(CodeGenHelper
& cgh
) {
6799 generate_code(cgh
.get_current_outputstruct());
6802 void Def_ExtFunction::dump_internal(unsigned level
) const
6804 DEBUG(level
, "External function: %s", id
->get_dispname().c_str());
6805 DEBUG(level
+ 1, "Parameters:");
6806 fp_list
->dump(level
+ 2);
6808 DEBUG(level
+ 1, "Return type:");
6809 return_type
->dump(level
+ 2);
6810 if(asstype
== A_EXT_FUNCTION_RTEMP
) DEBUG(level
+ 1, "Returns template");
6812 if (prototype
!= PROTOTYPE_NONE
)
6813 DEBUG(level
+ 1, "Prototype: %s", get_prototype_name());
6814 if (function_type
!= EXTFUNC_MANUAL
) {
6815 DEBUG(level
+ 1, "Automatically generated: %s",
6816 function_type
== EXTFUNC_ENCODE
? "encoder" : "decoder");
6817 DEBUG(level
+ 2, "Encoding type: %s",
6818 Type::get_encoding_name(encoding_type
));
6819 if (encoding_options
)
6820 DEBUG(level
+ 2, "Encoding options: %s", encoding_options
->c_str());
6822 if (eb_list
) eb_list
->dump(level
+ 1);
6825 void Def_ExtFunction::generate_json_schema_ref(map
<Type
*, JSON_Tokenizer
>& json_refs
)
6827 // only do anything if this is a JSON encoding or decoding function
6828 if (encoding_type
== Type::CT_JSON
&&
6829 (function_type
== EXTFUNC_ENCODE
|| function_type
== EXTFUNC_DECODE
)) {
6830 // retrieve the encoded type
6832 if (function_type
== EXTFUNC_ENCODE
) {
6833 // for encoding functions it's always the first parameter
6834 type
= fp_list
->get_fp_byIndex(0)->get_Type();
6836 // for decoding functions it depends on the prototype
6837 switch (prototype
) {
6838 case PROTOTYPE_CONVERT
:
6841 case PROTOTYPE_FAST
:
6842 case PROTOTYPE_BACKTRACK
:
6843 case PROTOTYPE_SLIDING
:
6844 type
= fp_list
->get_fp_byIndex(1)->get_Type();
6847 FATAL_ERROR("Def_ExtFunction::generate_json_schema_ref");
6851 // step over the type reference created for this function
6852 type
= type
->get_type_refd();
6854 JSON_Tokenizer
* json
= NULL
;
6855 if (json_refs
.has_key(type
)) {
6856 // the schema segment containing the type's reference already exists
6857 json
= json_refs
[type
];
6859 // the schema segment doesn't exist yet, create it and insert the reference
6860 json
= new JSON_Tokenizer
;
6861 json_refs
.add(type
, json
);
6862 type
->generate_json_schema_ref(*json
);
6865 // insert a property to specify which function this is (encoding or decoding)
6866 json
->put_next_token(JSON_TOKEN_NAME
, (function_type
== EXTFUNC_ENCODE
) ?
6867 "encoding" : "decoding");
6869 // place the function's info in an object
6870 json
->put_next_token(JSON_TOKEN_OBJECT_START
);
6872 // insert information related to the function's prototype in an array
6873 json
->put_next_token(JSON_TOKEN_NAME
, "prototype");
6874 json
->put_next_token(JSON_TOKEN_ARRAY_START
);
6876 // 1st element: external function prototype name (as string)
6878 case PROTOTYPE_CONVERT
:
6879 json
->put_next_token(JSON_TOKEN_STRING
, "\"convert\"");
6881 case PROTOTYPE_FAST
:
6882 json
->put_next_token(JSON_TOKEN_STRING
, "\"fast\"");
6884 case PROTOTYPE_BACKTRACK
:
6885 json
->put_next_token(JSON_TOKEN_STRING
, "\"backtrack\"");
6887 case PROTOTYPE_SLIDING
:
6888 json
->put_next_token(JSON_TOKEN_STRING
, "\"sliding\"");
6891 FATAL_ERROR("Def_ExtFunction::generate_json_schema_ref");
6894 // 2nd element: external function name
6895 char* func_name_str
= mprintf("\"%s\"", id
->get_dispname().c_str());
6896 json
->put_next_token(JSON_TOKEN_STRING
, func_name_str
);
6897 Free(func_name_str
);
6899 // the rest of the elements contain the names of the function's parameters (1 or 2)
6900 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
6901 char* param_str
= mprintf("\"%s\"",
6902 fp_list
->get_fp_byIndex(i
)->get_id().get_dispname().c_str());
6903 json
->put_next_token(JSON_TOKEN_STRING
, param_str
);
6907 // end of the prototype's array
6908 json
->put_next_token(JSON_TOKEN_ARRAY_END
);
6910 // insert error behavior data
6911 if (eb_list
!= NULL
) {
6912 json
->put_next_token(JSON_TOKEN_NAME
, "errorBehavior");
6913 json
->put_next_token(JSON_TOKEN_OBJECT_START
);
6915 // add each error behavior modification as a property
6916 for (size_t i
= 0; i
< eb_list
->get_nof_ebs(); ++i
) {
6917 ErrorBehaviorSetting
* eb
= eb_list
->get_ebs_byIndex(i
);
6918 json
->put_next_token(JSON_TOKEN_NAME
, eb
->get_error_type().c_str());
6919 char* handling_str
= mprintf("\"%s\"", eb
->get_error_handling().c_str());
6920 json
->put_next_token(JSON_TOKEN_STRING
, handling_str
);
6924 json
->put_next_token(JSON_TOKEN_OBJECT_END
);
6927 // insert printing type
6928 if (json_printing
!= NULL
) {
6929 json
->put_next_token(JSON_TOKEN_NAME
, "printing");
6930 json
->put_next_token(JSON_TOKEN_STRING
,
6931 (json_printing
->get_printing() == PrintingType::PT_PRETTY
) ?
6932 "\"pretty\"" : "\"compact\"");
6935 // end of this function's object
6936 json
->put_next_token(JSON_TOKEN_OBJECT_END
);
6940 // =================================
6941 // ===== Def_Altstep
6942 // =================================
6944 Def_Altstep::Def_Altstep(Identifier
*p_id
, FormalParList
*p_fpl
,
6945 Reference
*p_runs_on_ref
, StatementBlock
*p_sb
,
6947 : Definition(A_ALTSTEP
, p_id
), fp_list(p_fpl
), runs_on_ref(p_runs_on_ref
),
6948 runs_on_type(0), sb(p_sb
), ags(p_ags
)
6950 if (!p_fpl
|| !p_sb
|| !p_ags
)
6951 FATAL_ERROR("Def_Altstep::Def_Altstep()");
6952 fp_list
->set_my_def(this);
6953 sb
->set_my_def(this);
6954 ags
->set_my_def(this);
6955 ags
->set_my_sb(sb
, 0);
6958 Def_Altstep::~Def_Altstep()
6966 Def_Altstep
*Def_Altstep::clone() const
6968 FATAL_ERROR("Def_Altstep::clone");
6971 void Def_Altstep::set_fullname(const string
& p_fullname
)
6973 Definition::set_fullname(p_fullname
);
6974 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
6975 if (runs_on_ref
) runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
6976 sb
->set_fullname(p_fullname
+".<block>");
6977 ags
->set_fullname(p_fullname
+ ".<guards>");
6980 void Def_Altstep::set_my_scope(Scope
*p_scope
)
6982 bridgeScope
.set_parent_scope(p_scope
);
6983 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
6985 Definition::set_my_scope(&bridgeScope
);
6986 // the scope of the parameter list is set during checking
6987 if (runs_on_ref
) runs_on_ref
->set_my_scope(&bridgeScope
);
6988 sb
->set_my_scope(fp_list
);
6989 ags
->set_my_scope(sb
);
6992 Type
*Def_Altstep::get_RunsOnType()
6994 if (!checked
) chk();
6995 return runs_on_type
;
6998 FormalParList
*Def_Altstep::get_FormalParList()
7000 if (!checked
) chk();
7004 RunsOnScope
*Def_Altstep::get_runs_on_scope(Type
*comptype
)
7006 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
7007 if (!my_module
) FATAL_ERROR("Def_Altstep::get_runs_on_scope()");
7008 return my_module
->get_runs_on_scope(comptype
);
7011 void Def_Altstep::chk()
7013 if (checked
) return;
7015 Error_Context
cntxt(this, "In altstep definition `%s'",
7016 id
->get_dispname().c_str());
7017 Scope
*parlist_scope
= my_scope
;
7019 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
7020 runs_on_type
= runs_on_ref
->chk_comptype_ref();
7022 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
7023 runs_on_scope
->set_parent_scope(my_scope
);
7024 parlist_scope
= runs_on_scope
;
7027 fp_list
->set_my_scope(parlist_scope
);
7028 fp_list
->chk(asstype
);
7030 ags
->set_is_altstep();
7031 ags
->set_my_ags(ags
);
7032 ags
->set_my_laic_stmt(ags
, 0);
7034 if (!semantic_check_only
) {
7035 fp_list
->set_genname(get_genname());
7036 sb
->set_code_section(GovernedSimple::CS_INLINE
);
7037 ags
->set_code_section(GovernedSimple::CS_INLINE
);
7039 if (w_attrib_path
) {
7040 w_attrib_path
->chk_global_attrib();
7041 w_attrib_path
->chk_no_qualif();
7045 void Def_Altstep::generate_code(output_struct
*target
, bool)
7047 const string
& t_genname
= get_genname();
7048 const char *genname_str
= t_genname
.c_str();
7049 const char *dispname_str
= id
->get_dispname().c_str();
7051 // function for altstep instance:
7052 // assemble the function body first (this also determines which parameters
7054 char* body
= create_location_object(memptystr(), "ALTSTEP", dispname_str
);
7055 body
= fp_list
->generate_shadow_objects(body
);
7056 body
= sb
->generate_code(body
);
7057 body
= ags
->generate_code_altstep(body
);
7058 // generate a smart formal parameter list (omits unused parameter names)
7059 char *formal_par_list
= fp_list
->generate_code(memptystr());
7060 fp_list
->generate_code_defval(target
);
7062 // function for altstep instance: prototype
7063 target
->header
.function_prototypes
=
7064 mputprintf(target
->header
.function_prototypes
,
7065 "extern alt_status %s_instance(%s);\n", genname_str
, formal_par_list
);
7067 // function for altstep instance: body
7068 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
7069 "alt_status %s_instance(%s)\n"
7072 "}\n\n", genname_str
, formal_par_list
, body
);
7073 Free(formal_par_list
);
7076 char *actual_par_list
=
7077 fp_list
->generate_code_actual_parlist(memptystr(), "");
7079 // use a full formal parameter list for the rest of the functions
7080 char *full_formal_par_list
= fp_list
->generate_code(memptystr(),
7081 fp_list
->get_nof_fps());
7083 // wrapper function for stand-alone instantiation: prototype
7084 target
->header
.function_prototypes
=
7085 mputprintf(target
->header
.function_prototypes
,
7086 "extern void %s(%s);\n", genname_str
, full_formal_par_list
);
7088 // wrapper function for stand-alone instantiation: body
7089 target
->source
.function_bodies
=
7090 mputprintf(target
->source
.function_bodies
, "void %s(%s)\n"
7093 "boolean block_flag = FALSE;\n"
7094 "alt_status altstep_flag = ALT_UNCHECKED, "
7095 "default_flag = ALT_UNCHECKED;\n"
7097 "TTCN_Snapshot::take_new(block_flag);\n"
7098 "if (altstep_flag != ALT_NO) {\n"
7099 "altstep_flag = %s_instance(%s);\n"
7100 "if (altstep_flag == ALT_YES || altstep_flag == ALT_BREAK) return;\n"
7101 "else if (altstep_flag == ALT_REPEAT) goto altstep_begin;\n"
7103 "if (default_flag != ALT_NO) {\n"
7104 "default_flag = TTCN_Default::try_altsteps();\n"
7105 "if (default_flag == ALT_YES || default_flag == ALT_BREAK) return;\n"
7106 "else if (default_flag == ALT_REPEAT) goto altstep_begin;\n"
7108 "if (altstep_flag == ALT_NO && default_flag == ALT_NO) "
7109 "TTCN_error(\"None of the branches can be chosen in altstep %s.\");\n"
7110 "else block_flag = TRUE;\n"
7112 "}\n\n", genname_str
, full_formal_par_list
, genname_str
, actual_par_list
,
7115 // class for keeping the altstep in the default context
7116 // the class is for internal use, we do not need to publish it in the
7118 char* str
= mprintf("class %s_Default : public Default_Base {\n", genname_str
);
7119 str
= fp_list
->generate_code_object(str
, "par_");
7120 str
= mputprintf(str
, "public:\n"
7122 "alt_status call_altstep();\n"
7123 "};\n\n", genname_str
, full_formal_par_list
);
7124 target
->source
.class_defs
= mputstr(target
->source
.class_defs
, str
);
7126 // member functions of the class
7127 str
= mprintf("%s_Default::%s_Default(%s)\n"
7128 " : Default_Base(\"%s\")", genname_str
, genname_str
, full_formal_par_list
,
7130 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); i
++) {
7131 const char *fp_name_str
=
7132 fp_list
->get_fp_byIndex(i
)->get_id().get_name().c_str();
7133 str
= mputprintf(str
, ", par_%s(%s)", fp_name_str
, fp_name_str
);
7135 str
= mputstr(str
, "\n{\n}\n\n");
7136 char *actual_par_list_prefixed
=
7137 fp_list
->generate_code_actual_parlist(memptystr(), "par_");
7138 str
= mputprintf(str
, "alt_status %s_Default::call_altstep()\n"
7140 "return %s_instance(%s);\n"
7141 "}\n\n", genname_str
, genname_str
, actual_par_list_prefixed
);
7142 Free(actual_par_list_prefixed
);
7143 target
->source
.methods
= mputstr(target
->source
.methods
, str
);
7146 // function for default activation: prototype
7147 target
->header
.function_prototypes
=
7148 mputprintf(target
->header
.function_prototypes
,
7149 "extern Default_Base *activate_%s(%s);\n", genname_str
,
7150 full_formal_par_list
);
7152 // function for default activation: body
7153 str
= mprintf("Default_Base *activate_%s(%s)\n"
7154 "{\n", genname_str
, full_formal_par_list
);
7155 str
= mputprintf(str
, "return new %s_Default(%s);\n"
7156 "}\n\n", genname_str
, actual_par_list
);
7157 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7161 Free(full_formal_par_list
);
7162 Free(actual_par_list
);
7164 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7165 "%s.add_altstep(\"%s\", (genericfunc_t)&%s_instance, (genericfunc_t )&activate_%s, "
7166 "(genericfunc_t )&%s);\n", get_module_object_name(), dispname_str
, genname_str
,
7167 genname_str
, genname_str
);
7170 void Def_Altstep::generate_code(CodeGenHelper
& cgh
) {
7171 generate_code(cgh
.get_current_outputstruct());
7174 void Def_Altstep::dump_internal(unsigned level
) const
7176 DEBUG(level
, "Altstep: %s", id
->get_dispname().c_str());
7177 DEBUG(level
+ 1, "Parameters:");
7178 fp_list
->dump(level
+ 1);
7180 DEBUG(level
+ 1, "Runs on clause:");
7181 runs_on_ref
->dump(level
+ 2);
7184 DEBUG(level + 1, "Local definitions:");
7185 sb->dump(level + 2);
7187 DEBUG(level
+ 1, "Guards:");
7188 ags
->dump(level
+ 2);
7191 void Def_Altstep::set_parent_path(WithAttribPath
* p_path
) {
7192 Definition::set_parent_path(p_path
);
7193 sb
->set_parent_path(w_attrib_path
);
7196 // =================================
7197 // ===== Def_Testcase
7198 // =================================
7200 Def_Testcase::Def_Testcase(Identifier
*p_id
, FormalParList
*p_fpl
,
7201 Reference
*p_runs_on_ref
, Reference
*p_system_ref
,
7202 StatementBlock
*p_block
)
7203 : Definition(A_TESTCASE
, p_id
), fp_list(p_fpl
), runs_on_ref(p_runs_on_ref
),
7204 runs_on_type(0), system_ref(p_system_ref
), system_type(0), block(p_block
)
7206 if (!p_fpl
|| !p_runs_on_ref
|| !p_block
)
7207 FATAL_ERROR("Def_Testcase::Def_Testcase()");
7208 fp_list
->set_my_def(this);
7209 block
->set_my_def(this);
7212 Def_Testcase::~Def_Testcase()
7220 Def_Testcase
*Def_Testcase::clone() const
7222 FATAL_ERROR("Def_Testcase::clone");
7225 void Def_Testcase::set_fullname(const string
& p_fullname
)
7227 Definition::set_fullname(p_fullname
);
7228 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
7229 runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
7230 if (system_ref
) system_ref
->set_fullname(p_fullname
+ ".<system_type>");
7231 block
->set_fullname(p_fullname
+ ".<statement_block>");
7234 void Def_Testcase::set_my_scope(Scope
*p_scope
)
7236 bridgeScope
.set_parent_scope(p_scope
);
7237 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
7239 Definition::set_my_scope(&bridgeScope
);
7240 // the scope of the parameter list is set during checking
7241 runs_on_ref
->set_my_scope(&bridgeScope
);
7242 if (system_ref
) system_ref
->set_my_scope(&bridgeScope
);
7243 block
->set_my_scope(fp_list
);
7246 Type
*Def_Testcase::get_RunsOnType()
7248 if (!checked
) chk();
7249 return runs_on_type
;
7252 Type
*Def_Testcase::get_SystemType()
7254 if (!checked
) chk();
7258 FormalParList
*Def_Testcase::get_FormalParList()
7260 if (!checked
) chk();
7264 RunsOnScope
*Def_Testcase::get_runs_on_scope(Type
*comptype
)
7266 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
7267 if (!my_module
) FATAL_ERROR("Def_Testcase::get_runs_on_scope()");
7268 return my_module
->get_runs_on_scope(comptype
);
7271 void Def_Testcase::chk()
7273 if (checked
) return;
7275 Error_Context
cntxt(this, "In testcase definition `%s'",
7276 id
->get_dispname().c_str());
7277 Scope
*parlist_scope
= my_scope
;
7279 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
7280 runs_on_type
= runs_on_ref
->chk_comptype_ref();
7282 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
7283 runs_on_scope
->set_parent_scope(my_scope
);
7284 parlist_scope
= runs_on_scope
;
7288 Error_Context
cntxt2(system_ref
, "In `system' clause");
7289 system_type
= system_ref
->chk_comptype_ref();;
7291 fp_list
->set_my_scope(parlist_scope
);
7292 fp_list
->chk(asstype
);
7294 if (!semantic_check_only
) {
7295 fp_list
->set_genname(get_genname());
7296 block
->set_code_section(GovernedSimple::CS_INLINE
);
7298 if (w_attrib_path
) {
7299 w_attrib_path
->chk_global_attrib();
7300 w_attrib_path
->chk_no_qualif();
7304 void Def_Testcase::generate_code(output_struct
*target
, bool)
7306 const string
& t_genname
= get_genname();
7307 const char *genname_str
= t_genname
.c_str();
7308 const char *dispname_str
= id
->get_dispname().c_str();
7310 // assemble the function body first (this also determines which parameters
7313 // Checking whether the testcase was invoked from another one.
7314 // At this point the location information should refer to the execute()
7315 // statement rather than this testcase.
7316 char* body
= mputstr(memptystr(), "TTCN_Runtime::check_begin_testcase(has_timer, "
7318 body
= create_location_object(body
, "TESTCASE", dispname_str
);
7319 body
= fp_list
->generate_shadow_objects(body
);
7320 body
= mputprintf(body
, "try {\n"
7321 "TTCN_Runtime::begin_testcase(\"%s\", \"%s\", ",
7322 my_scope
->get_scope_mod()->get_modid().get_dispname().c_str(),
7324 ComponentTypeBody
*runs_on_body
= runs_on_type
->get_CompBody();
7325 body
= runs_on_body
->generate_code_comptype_name(body
);
7326 body
= mputstr(body
, ", ");
7328 body
= system_type
->get_CompBody()->generate_code_comptype_name(body
);
7329 else body
= runs_on_body
->generate_code_comptype_name(body
);
7330 body
= mputstr(body
, ", has_timer, timer_value);\n");
7331 body
= block
->generate_code(body
);
7332 body
= mputprintf(body
,
7333 "} catch (const TC_Error& tc_error) {\n"
7334 "} catch (const TC_End& tc_end) {\n"
7335 "TTCN_Logger::log_str(TTCN_FUNCTION, \"Test case %s was stopped.\");\n"
7336 "}\n", dispname_str
);
7337 body
= mputstr(body
, "return TTCN_Runtime::end_testcase();\n");
7339 // smart formal parameter list (names of unused parameters are omitted)
7340 char *formal_par_list
= fp_list
->generate_code(memptystr());
7341 fp_list
->generate_code_defval(target
);
7342 if (fp_list
->get_nof_fps() > 0)
7343 formal_par_list
= mputstr(formal_par_list
, ", ");
7344 formal_par_list
= mputstr(formal_par_list
,
7345 "boolean has_timer, double timer_value");
7347 // function prototype
7348 target
->header
.function_prototypes
=
7349 mputprintf(target
->header
.function_prototypes
,
7350 "extern verdicttype testcase_%s(%s);\n", genname_str
, formal_par_list
);
7353 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
7354 "verdicttype testcase_%s(%s)\n"
7357 "}\n\n", genname_str
, formal_par_list
, body
);
7358 Free(formal_par_list
);
7361 if (fp_list
->get_nof_fps() == 0) {
7362 // adding to the list of startable testcases
7363 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7364 "%s.add_testcase_nonpard(\"%s\", testcase_%s);\n",
7365 get_module_object_name(), dispname_str
, genname_str
);
7367 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7368 "%s.add_testcase_pard(\"%s\", (genericfunc_t)&testcase_%s);\n",
7369 get_module_object_name(), dispname_str
, genname_str
);
7371 // If every formal parameter has a default value, the testcase
7372 // might be callable after all.
7373 bool callable
= true;
7374 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
7375 FormalPar
*fp
= fp_list
->get_fp_byIndex(i
);
7376 if (!fp
->has_defval()) {
7383 // Write a wrapper, which acts as a no-param testcase
7384 // by calling the parameterized testcase with the default values.
7385 target
->header
.function_prototypes
=
7386 mputprintf(target
->header
.function_prototypes
,
7387 "extern verdicttype testcase_%s_defparams(boolean has_timer, double timer_value);\n",
7389 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
7390 "verdicttype testcase_%s_defparams(boolean has_timer, double timer_value) {\n"
7391 " return testcase_%s(",
7392 genname_str
, genname_str
);
7394 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
7395 FormalPar
*fp
= fp_list
->get_fp_byIndex(i
);
7396 ActualPar
*ap
= fp
->get_defval();
7397 switch (ap
->get_selection()) {
7398 case ActualPar::AP_VALUE
:
7399 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7400 ap
->get_Value()->get_genname_own(my_scope
).c_str());
7402 case ActualPar::AP_TEMPLATE
:
7403 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7404 ap
->get_TemplateInstance()->get_Template()->get_genname_own(my_scope
).c_str());
7406 case ActualPar::AP_REF
:
7407 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7408 ap
->get_Ref()->get_refd_assignment()->get_genname_from_scope(my_scope
).c_str());
7410 case ActualPar::AP_DEFAULT
:
7411 // Can't happen. This ActualPar was created by
7412 // Ttcn::FormalPar::chk_actual_par as the default value for
7413 // a FormalPar, and it only ever creates vale, template or ref.
7416 FATAL_ERROR("Def_Testcase::generate_code()");
7419 // always append a comma, because has_timer and timer_value follows
7420 target
->source
.function_bodies
= mputstrn(target
->source
.function_bodies
,
7424 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7425 "has_timer, timer_value);\n"
7427 // Add the non-parameterized wrapper *after* the parameterized one,
7428 // with the same name. Linear search will always find the first
7429 // (user-visible, parameterized) testcase.
7430 // TTCN_Module::execute_testcase knows that if after a parameterized
7431 // testcase another testcase with the same name follows,
7432 // it's the callable, non-parameterized wrapper.
7434 // TTCN_Module::list_testcases skips parameterized testcases;
7435 // it will now list the non-parameterized wrapper.
7436 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7437 "%s.add_testcase_nonpard(\"%s\", testcase_%s_defparams);\n",
7438 get_module_object_name(), dispname_str
, genname_str
);
7440 } // has formal parameters
7443 void Def_Testcase::generate_code(CodeGenHelper
& cgh
) {
7444 generate_code(cgh
.get_current_outputstruct());
7447 void Def_Testcase::dump_internal(unsigned level
) const
7449 DEBUG(level
, "Testcase: %s", id
->get_dispname().c_str());
7450 DEBUG(level
+ 1, "Parameters:");
7451 fp_list
->dump(level
+ 1);
7452 DEBUG(level
+ 1, "Runs on clause:");
7453 runs_on_ref
->dump(level
+ 2);
7455 DEBUG(level
+ 1, "System clause:");
7456 system_ref
->dump(level
+ 2);
7458 DEBUG(level
+ 1, "Statement block:");
7459 block
->dump(level
+ 2);
7462 void Def_Testcase::set_parent_path(WithAttribPath
* p_path
) {
7463 Definition::set_parent_path(p_path
);
7465 block
->set_parent_path(w_attrib_path
);
7468 // =================================
7470 // =================================
7472 FormalPar::FormalPar(asstype_t p_asstype
, Type
*p_type
, Identifier
* p_name
,
7473 TemplateInstance
*p_defval
, bool p_lazy_eval
)
7474 : Definition(p_asstype
, p_name
), type(p_type
), my_parlist(0),
7475 used_as_lvalue(false), template_restriction(TR_NONE
),
7476 lazy_eval(p_lazy_eval
), defval_generated(false), usage_found(false)
7478 switch (p_asstype
) {
7482 case A_PAR_VAL_INOUT
:
7483 case A_PAR_TEMPL_IN
:
7484 case A_PAR_TEMPL_OUT
:
7485 case A_PAR_TEMPL_INOUT
:
7489 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): invalid parameter type");
7492 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): NULL pointer");
7493 type
->set_ownertype(Type::OT_FORMAL_PAR
, this);
7494 defval
.ti
= p_defval
;
7497 FormalPar::FormalPar(asstype_t p_asstype
,
7498 template_restriction_t p_template_restriction
, Type
*p_type
,
7499 Identifier
* p_name
, TemplateInstance
*p_defval
, bool p_lazy_eval
)
7500 : Definition(p_asstype
, p_name
), type(p_type
), my_parlist(0),
7501 used_as_lvalue(false), template_restriction(p_template_restriction
),
7502 lazy_eval(p_lazy_eval
), defval_generated(false), usage_found(false)
7504 switch (p_asstype
) {
7505 case A_PAR_TEMPL_IN
:
7506 case A_PAR_TEMPL_OUT
:
7507 case A_PAR_TEMPL_INOUT
:
7510 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): parameter not template");
7513 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): NULL pointer");
7514 type
->set_ownertype(Type::OT_FORMAL_PAR
, this);
7515 defval
.ti
= p_defval
;
7518 FormalPar::FormalPar(asstype_t p_asstype
, Identifier
* p_name
,
7519 TemplateInstance
*p_defval
)
7520 : Definition(p_asstype
, p_name
), type(0), my_parlist(0),
7521 used_as_lvalue(false), template_restriction(TR_NONE
), lazy_eval(false),
7522 defval_generated(false), usage_found(false)
7524 if (p_asstype
!= A_PAR_TIMER
)
7525 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): invalid parameter type");
7526 defval
.ti
= p_defval
;
7529 FormalPar::~FormalPar()
7532 if (checked
) delete defval
.ap
;
7533 else delete defval
.ti
;
7536 FormalPar
* FormalPar::clone() const
7538 FATAL_ERROR("FormalPar::clone");
7541 void FormalPar::set_fullname(const string
& p_fullname
)
7543 Definition::set_fullname(p_fullname
);
7544 if (type
) type
->set_fullname(p_fullname
+ ".<type>");
7546 if (defval
.ap
) defval
.ap
->set_fullname(p_fullname
+ ".<default_value>");
7548 if (defval
.ti
) defval
.ti
->set_fullname(p_fullname
+ ".<default_value>");
7552 void FormalPar::set_my_scope(Scope
*p_scope
)
7554 Definition::set_my_scope(p_scope
);
7555 if (type
) type
->set_my_scope(p_scope
);
7557 if (defval
.ap
) defval
.ap
->set_my_scope(p_scope
);
7559 if (defval
.ti
) defval
.ti
->set_my_scope(p_scope
);
7563 bool FormalPar::is_local() const
7568 Type
*FormalPar::get_Type()
7570 if (!checked
) chk();
7571 if (!type
) FATAL_ERROR("FormalPar::get_Type()");
7575 void FormalPar::chk()
7577 if (checked
) return;
7579 TemplateInstance
*default_value
= defval
.ti
;
7583 Type
*t
= type
->get_type_refd_last();
7584 // checks for forbidden type <-> parameter combinations
7585 switch (t
->get_typetype()) {
7589 case A_PAR_VAL_INOUT
:
7590 asstype
= A_PAR_PORT
;
7593 error("Port type `%s' cannot be used as %s",
7594 t
->get_fullname().c_str(), get_assname());
7597 case Type::T_SIGNATURE
:
7599 case A_PAR_TEMPL_IN
:
7600 case A_PAR_TEMPL_OUT
:
7601 case A_PAR_TEMPL_INOUT
:
7604 error("Signature `%s' cannot be used as %s",
7605 t
->get_fullname().c_str(), get_assname());
7612 FATAL_ERROR("FormalPar::chk()");
7614 asstype
= A_PAR_VAL_IN
;
7619 } else if (asstype
!= A_PAR_TIMER
) FATAL_ERROR("FormalPar::chk()");
7621 if (default_value
) {
7622 Error_Context
cntxt(default_value
, "In default value");
7623 defval
.ap
= chk_actual_par(default_value
, Type::EXPECTED_STATIC_VALUE
);
7624 delete default_value
;
7625 if (!semantic_check_only
)
7626 defval
.ap
->set_code_section(GovernedSimple::CS_POST_INIT
);
7630 bool FormalPar::has_defval() const
7632 if (checked
) return defval
.ap
!= 0;
7633 else return defval
.ti
!= 0;
7636 bool FormalPar::has_notused_defval() const
7638 if (checked
) FATAL_ERROR("FormalPar::has_notused_defval");
7639 if (!defval
.ti
|| !defval
.ti
->get_Template())
7641 return defval
.ti
->get_Template()->get_templatetype()
7642 == Template::TEMPLATE_NOTUSED
;
7645 ActualPar
*FormalPar::get_defval() const
7647 if (!checked
) FATAL_ERROR("FormalPar::get_defval()");
7651 // Extract the TemplateInstance from an ActualPar.
7652 void FormalPar::set_defval(ActualPar
*defpar
)
7654 // ActualPar::clone() is not implemented, since we need such a function
7655 // only here only for AP_{VALUE,TEMPLATE} parameters. AP_ERROR can also
7656 // happen for Def_Template nodes, but they will be errors later.
7657 // FIXME: This function is Def_Template specific.
7658 if (!defval
.ti
->get_Template() || defval
.ti
->get_Template()
7659 ->get_templatetype() != Template::TEMPLATE_NOTUSED
)
7660 FATAL_ERROR("FormalPar::set_defval()");
7661 TemplateInstance
*reversed_ti
= 0;
7662 switch (defpar
->get_selection()) {
7663 case ActualPar::AP_VALUE
:
7664 reversed_ti
= new TemplateInstance(type
->clone(), 0, new Template
7665 (defpar
->get_Value()->clone())); // Trust the clone().
7667 case ActualPar::AP_TEMPLATE
:
7668 reversed_ti
= defpar
->get_TemplateInstance()->clone();
7670 case ActualPar::AP_ERROR
:
7671 break; // Can happen, but let it go.
7672 case ActualPar::AP_REF
:
7673 case ActualPar::AP_DEFAULT
:
7675 FATAL_ERROR("FormalPar::set_defval()");
7679 reversed_ti
->set_my_scope(get_my_scope());
7680 defval
.ti
= reversed_ti
;
7684 ActualPar
*FormalPar::chk_actual_par(TemplateInstance
*actual_par
,
7685 Type::expected_value_t exp_val
)
7687 if (!checked
) chk();
7691 return chk_actual_par_value(actual_par
, exp_val
);
7693 case A_PAR_VAL_INOUT
:
7694 return chk_actual_par_by_ref(actual_par
, false, exp_val
);
7695 case A_PAR_TEMPL_IN
:
7696 return chk_actual_par_template(actual_par
, exp_val
);
7697 case A_PAR_TEMPL_OUT
:
7698 case A_PAR_TEMPL_INOUT
:
7699 return chk_actual_par_by_ref(actual_par
, true, exp_val
);
7701 return chk_actual_par_timer(actual_par
, exp_val
);
7703 return chk_actual_par_port(actual_par
, exp_val
);
7705 FATAL_ERROR("FormalPar::chk_actual_par()");
7707 return 0; // to avoid warnings
7710 ActualPar
*FormalPar::chk_actual_par_value(TemplateInstance
*actual_par
,
7711 Type::expected_value_t exp_val
)
7713 actual_par
->chk_Type(type
);
7714 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7716 derived_ref
->error("An in-line modified template cannot be used as %s",
7718 actual_par
->chk_DerivedRef(type
);
7720 Template
*ap_template
= actual_par
->get_Template();
7721 if (ap_template
->is_Value()) {
7722 Value
*v
= ap_template
->get_Value();
7723 v
->set_my_governor(type
);
7724 type
->chk_this_value_ref(v
);
7725 type
->chk_this_value(v
, 0, exp_val
, INCOMPLETE_NOT_ALLOWED
,
7726 OMIT_NOT_ALLOWED
, SUB_CHK
);
7727 return new ActualPar(v
);
7729 actual_par
->error("A specific value without matching symbols "
7730 "was expected for a %s", get_assname());
7731 return new ActualPar();
7735 static void chk_defpar_value(const Value
* v
)
7737 Common::Reference
*vref
= v
->get_reference();
7738 Common::Assignment
*ass2
= vref
->get_refd_assignment();
7740 Scope
*scope
= ass2
->get_my_scope();
7741 ComponentTypeBody
*ctb
= dynamic_cast<ComponentTypeBody
*>(scope
);
7742 if (ctb
) { // this is a component variable
7743 v
->error("default value cannot refer to"
7744 " a template field of the component in the `runs on' clause");
7748 static void chk_defpar_template(const Template
*body
,
7749 Type::expected_value_t exp_val
)
7751 switch (body
->get_templatetype()) {
7752 case Template::TEMPLATE_ERROR
:
7753 break; // could be erroneous in the source; skip it
7754 case Template::TEMPLATE_NOTUSED
:
7755 case Template::OMIT_VALUE
:
7756 case Template::ANY_VALUE
:
7757 case Template::ANY_OR_OMIT
:
7758 break; // acceptable (?)
7759 case Template::TEMPLATE_INVOKE
: // calling a function is not acceptable
7760 body
->error("default value can not be a function invocation");
7762 case Template::VALUE_RANGE
: {
7763 ValueRange
*range
= body
->get_value_range();
7764 Value
*low
= range
->get_min_v();
7765 Type::typetype_t tt_low
= low
->get_expr_returntype(exp_val
);
7766 Value
*high
= range
->get_max_v();
7767 Type::typetype_t tt_high
= high
->get_expr_returntype(exp_val
);
7768 if (tt_low
== tt_high
) break;
7771 case Template::BSTR_PATTERN
:
7772 case Template::HSTR_PATTERN
:
7773 case Template::OSTR_PATTERN
:
7774 case Template::CSTR_PATTERN
:
7775 case Template::USTR_PATTERN
:
7776 break; // should be acceptable in all cases (if only fixed strings possible)
7778 case Template::SPECIFIC_VALUE
: {
7779 Common::Value
*v
= body
->get_specific_value();
7780 if (v
->get_valuetype() == Value::V_REFD
) chk_defpar_value(v
);
7783 case Template::ALL_FROM
:
7784 case Template::VALUE_LIST_ALL_FROM
:
7785 FATAL_ERROR("should have been flattened");
7787 case Template::SUPERSET_MATCH
:
7788 case Template::SUBSET_MATCH
:
7789 case Template::PERMUTATION_MATCH
:
7790 case Template::TEMPLATE_LIST
:
7791 case Template::COMPLEMENTED_LIST
:
7792 case Template::VALUE_LIST
: {
7793 // in template charstring par := charstring : ("foo", "bar", "baz")
7794 size_t num
= body
->get_nof_comps();
7795 for (size_t i
= 0; i
< num
; ++i
) {
7796 const Template
*tpl
= body
->get_temp_byIndex(i
);
7797 chk_defpar_template(tpl
, exp_val
);
7801 case Template::NAMED_TEMPLATE_LIST
: {
7802 size_t num
= body
->get_nof_comps();
7803 for (size_t i
= 0; i
< num
; ++i
) {
7804 const NamedTemplate
*nt
= body
->get_namedtemp_byIndex(i
);
7805 const Template
*tpl
= nt
->get_template();
7806 chk_defpar_template(tpl
, exp_val
);
7810 case Template::INDEXED_TEMPLATE_LIST
: {
7811 size_t num
= body
->get_nof_comps();
7812 for (size_t i
= 0; i
< num
; ++i
) {
7813 const IndexedTemplate
*it
= body
->get_indexedtemp_byIndex(i
);
7814 const Template
*tpl
= it
->get_template();
7815 chk_defpar_template(tpl
, exp_val
);
7819 case Template::TEMPLATE_REFD
: {
7820 Ref_base
*ref
= body
->get_reference();
7822 Ttcn::ActualParList
*aplist
= ref
->get_parlist();
7824 size_t num
= aplist
->get_nof_pars();
7825 for (size_t i
= 0; i
< num
; ++i
) {
7826 const Ttcn::ActualPar
*ap
= aplist
->get_par(i
);
7828 switch (ap
->get_selection()) {
7829 case ActualPar::AP_ERROR
: {
7831 case ActualPar::AP_VALUE
: {
7832 Value
*v
= ap
->get_Value(); // "v_variable" as the parameter of the template
7834 switch (v
->get_valuetype()) {
7835 case Value::V_REFD
: {
7836 chk_defpar_value(v
);
7842 case ActualPar::AP_TEMPLATE
: {
7843 // A component cannot contain a template definition, parameterized or not.
7844 // Therefore the template this actual par references, cannot be
7845 // a field of a component => no error possible, nothing to do.
7847 case ActualPar::AP_REF
: {
7848 // A template cannot have an out/inout parameter
7849 FATAL_ERROR("Template with out parameter?");
7851 case ActualPar::AP_DEFAULT
: {
7852 ap
= ap
->get_ActualPar();
7856 } // switch actual par selection
7860 } // switch templatetype
7864 // This function is called in two situations:
7865 // 1. FormalParList::chk calls FormalPar::chk to compute the default value
7866 // (make an ActualPar from a TemplateInstance).
7867 // In this case, defval.ti==0, and actual_par contains its old value.
7868 // This case is called only if the formal par has a default value.
7869 // 2. FormalParList::chk_actual_parlist calls FormalPar::chk_actual_par
7870 // to check the parameters supplied by the execute statement to the tc.
7871 // In this case, defval.ap has the value computed in case 1.
7872 ActualPar
*FormalPar::chk_actual_par_template(TemplateInstance
*actual_par
,
7873 Type::expected_value_t exp_val
)
7875 actual_par
->chk(type
);
7876 // actual_par->template_body may change: SPECIFIC_VALUE to TEMPLATE_REFD
7877 Definition
*fplist_def
= my_parlist
->get_my_def();
7878 // The parameter list belongs to this definition. If it's a function
7879 // or testcase, it may have a "runs on" clause.
7880 Def_Function
*parent_fn
= dynamic_cast<Def_Function
*>(fplist_def
);
7881 Type
*runs_on_type
= 0;
7882 if (parent_fn
) runs_on_type
= parent_fn
->get_RunsOnType();
7883 else { // not a function; maybe a testcase
7884 Def_Testcase
*parent_tc
= dynamic_cast<Def_Testcase
*>(fplist_def
);
7885 if (parent_tc
) runs_on_type
= parent_tc
->get_RunsOnType();
7888 // If it _has_ a runs on clause, the type must be a component.
7889 if (runs_on_type
->get_typetype() != Type::T_COMPONENT
) FATAL_ERROR("not component?");
7890 // The default value "shall not refer to elements of the component type
7891 // in the runs on clause"
7892 ComponentTypeBody
*runs_on_component
= runs_on_type
->get_CompBody();
7893 size_t compass
= runs_on_component
->get_nof_asss();
7894 for (size_t c
= 0; c
< compass
; c
++) {
7895 Assignment
*ass
= runs_on_component
->get_ass_byIndex(c
);
7900 Ttcn::Template
* body
= actual_par
->get_Template();
7901 if (exp_val
== Type::EXPECTED_STATIC_VALUE
7902 ||exp_val
== Type::EXPECTED_CONSTANT
) {
7903 chk_defpar_template(body
, exp_val
);
7905 // Rip out the type, derived ref and template from actual_par
7906 // (which may come from a function invocation or the definition
7907 // of the default value) and give it to the new ActualPar.
7908 ActualPar
*ret_val
= new ActualPar(
7909 new TemplateInstance(actual_par
->get_Type(),
7910 actual_par
->get_DerivedRef(), actual_par
->get_Template()));
7911 // Zero out these members because the caller will soon call delete
7912 // on actual_par, but they now belong to ret_val.
7913 // FIXME: should this really be in here, or outside in the caller before the delete ?
7914 actual_par
->release();
7916 if (template_restriction
!=TR_NONE
) {
7917 bool needs_runtime_check
=
7918 ret_val
->get_TemplateInstance()->chk_restriction(
7919 "template formal parameter", template_restriction
,
7920 ret_val
->get_TemplateInstance());
7921 if (needs_runtime_check
)
7922 ret_val
->set_gen_restriction_check(template_restriction
);
7927 ActualPar
*FormalPar::chk_actual_par_by_ref(TemplateInstance
*actual_par
,
7928 bool is_template
, Type::expected_value_t exp_val
)
7930 Type
*ap_type
= actual_par
->get_Type();
7932 ap_type
->warning("Explicit type specification is useless for an %s",
7934 actual_par
->chk_Type(type
);
7936 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7938 derived_ref
->error("An in-line modified template cannot be used as %s",
7940 actual_par
->chk_DerivedRef(type
);
7942 // needed for the error messages
7943 const char *expected_string
= is_template
?
7944 "template variable or template parameter" :
7945 "variable or value parameter";
7946 Template
*ap_template
= actual_par
->get_Template();
7947 if (ap_template
->is_Ref()) {
7948 Ref_base
*ref
= ap_template
->get_Ref();
7949 Common::Assignment
*ass
= ref
->get_refd_assignment();
7952 return new ActualPar();
7954 bool asstype_correct
= false;
7955 switch (ass
->get_asstype()) {
7957 ass
->use_as_lvalue(*ref
);
7958 if (get_asstype() == A_PAR_VAL_OUT
|| get_asstype() == A_PAR_TEMPL_OUT
) {
7959 ass
->warning("Passing an `in' parameter as another function's `out' parameter");
7964 case A_PAR_VAL_INOUT
:
7965 if (!is_template
) asstype_correct
= true;
7967 case A_PAR_TEMPL_IN
:
7968 ass
->use_as_lvalue(*ref
);
7969 if (get_asstype() == A_PAR_VAL_OUT
|| get_asstype() == A_PAR_TEMPL_OUT
) {
7970 ass
->warning("Passing an `in' parameter as another function's `out' parameter");
7973 case A_VAR_TEMPLATE
:
7974 case A_PAR_TEMPL_OUT
:
7975 case A_PAR_TEMPL_INOUT
:
7976 if (is_template
) asstype_correct
= true;
7981 if (asstype_correct
) {
7982 FieldOrArrayRefs
*t_subrefs
= ref
->get_subrefs();
7983 Type
*ref_type
= ass
->get_Type()->get_field_type(t_subrefs
, exp_val
);
7985 if (!type
->is_identical(ref_type
)) {
7986 ref
->error("Type mismatch: Reference to a %s of type "
7987 "`%s' was expected instead of `%s'", expected_string
,
7988 type
->get_typename().c_str(), ref_type
->get_typename().c_str());
7989 } else if (type
->get_sub_type() && ref_type
->get_sub_type() &&
7990 (type
->get_sub_type()->get_subtypetype()==ref_type
->get_sub_type()->get_subtypetype()) &&
7991 (!type
->get_sub_type()->is_compatible(ref_type
->get_sub_type()))) {
7992 ref
->error("Subtype mismatch: subtype %s has no common value with subtype %s",
7993 type
->get_sub_type()->to_string().c_str(),
7994 ref_type
->get_sub_type()->to_string().c_str());
7996 if (t_subrefs
&& t_subrefs
->refers_to_string_element()) {
7997 ref
->error("Reference to a string element of type `%s' cannot be "
7998 "used in this context", ref_type
->get_typename().c_str());
8002 ref
->error("Reference to a %s was expected for an %s instead of %s",
8003 expected_string
, get_assname(), ass
->get_description().c_str());
8005 ActualPar
* ret_val_ap
= new ActualPar(ref
);
8006 // restriction checking if this is a reference to a template variable
8007 // this is an 'out' or 'inout' template parameter
8008 if (is_template
&& asstype_correct
) {
8009 template_restriction_t refd_tr
;
8010 switch (ass
->get_asstype()) {
8011 case A_VAR_TEMPLATE
: {
8012 Def_Var_Template
* dvt
= dynamic_cast<Def_Var_Template
*>(ass
);
8013 if (!dvt
) FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
8014 refd_tr
= dvt
->get_template_restriction();
8016 case A_PAR_TEMPL_IN
:
8017 case A_PAR_TEMPL_OUT
:
8018 case A_PAR_TEMPL_INOUT
: {
8019 FormalPar
* fp
= dynamic_cast<FormalPar
*>(ass
);
8020 if (!fp
) FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
8021 refd_tr
= fp
->get_template_restriction();
8024 FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
8027 refd_tr
= Template::get_sub_restriction(refd_tr
, ref
);
8028 if (template_restriction
!=refd_tr
) {
8029 bool pre_call_check
=
8030 Template::is_less_restrictive(template_restriction
, refd_tr
);
8031 bool post_call_check
=
8032 Template::is_less_restrictive(refd_tr
, template_restriction
);
8033 if (pre_call_check
|| post_call_check
) {
8034 ref
->warning("Inadequate restriction on the referenced %s `%s', "
8035 "this may cause a dynamic test case error at runtime",
8036 ass
->get_assname(), ref
->get_dispname().c_str());
8037 ass
->note("Referenced %s is here", ass
->get_assname());
8040 ret_val_ap
->set_gen_restriction_check(template_restriction
);
8041 if (post_call_check
)
8042 ret_val_ap
->set_gen_post_restriction_check(refd_tr
);
8044 // for out and inout template parameters of external functions
8045 // always check because we do not trust user written C++ code
8046 if (refd_tr
!=TR_NONE
) {
8047 switch (my_parlist
->get_my_def()->get_asstype()) {
8048 case A_EXT_FUNCTION
:
8049 case A_EXT_FUNCTION_RVAL
:
8050 case A_EXT_FUNCTION_RTEMP
:
8051 ret_val_ap
->set_gen_post_restriction_check(refd_tr
);
8060 actual_par
->error("Reference to a %s was expected for an %s",
8061 expected_string
, get_assname());
8062 return new ActualPar();
8066 ActualPar
*FormalPar::chk_actual_par_timer(TemplateInstance
*actual_par
,
8067 Type::expected_value_t exp_val
)
8069 Type
*ap_type
= actual_par
->get_Type();
8071 ap_type
->error("Explicit type specification cannot be used for a "
8073 actual_par
->chk_Type(0);
8075 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
8077 derived_ref
->error("An in-line modified template cannot be used as "
8079 actual_par
->chk_DerivedRef(0);
8081 Template
*ap_template
= actual_par
->get_Template();
8082 if (ap_template
->is_Ref()) {
8083 Ref_base
*ref
= ap_template
->get_Ref();
8084 Common::Assignment
*ass
= ref
->get_refd_assignment();
8087 return new ActualPar();
8089 switch (ass
->get_asstype()) {
8091 ArrayDimensions
*dims
= ass
->get_Dimensions();
8092 if (dims
) dims
->chk_indices(ref
, "timer", false, exp_val
);
8093 else if (ref
->get_subrefs()) ref
->error("Reference to single %s "
8094 "cannot have field or array sub-references",
8095 ass
->get_description().c_str());
8098 if (ref
->get_subrefs()) ref
->error("Reference to %s cannot have "
8099 "field or array sub-references", ass
->get_description().c_str());
8102 ref
->error("Reference to a timer or timer parameter was expected for "
8103 "a timer parameter instead of %s", ass
->get_description().c_str());
8105 return new ActualPar(ref
);
8107 actual_par
->error("Reference to a timer or timer parameter was "
8108 "expected for a timer parameter");
8109 return new ActualPar();
8113 ActualPar
*FormalPar::chk_actual_par_port(TemplateInstance
*actual_par
,
8114 Type::expected_value_t exp_val
)
8116 Type
*ap_type
= actual_par
->get_Type();
8118 ap_type
->warning("Explicit type specification is useless for a port "
8120 actual_par
->chk_Type(type
);
8122 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
8124 derived_ref
->error("An in-line modified template cannot be used as "
8126 actual_par
->chk_DerivedRef(type
);
8128 Template
*ap_template
= actual_par
->get_Template();
8129 if (ap_template
->is_Ref()) {
8130 Ref_base
*ref
= ap_template
->get_Ref();
8131 Common::Assignment
*ass
= ref
->get_refd_assignment();
8134 return new ActualPar();
8136 bool asstype_correct
= false;
8137 switch (ass
->get_asstype()) {
8139 ArrayDimensions
*dims
= ass
->get_Dimensions();
8140 if (dims
) dims
->chk_indices(ref
, "port", false, exp_val
);
8141 else if (ref
->get_subrefs()) ref
->error("Reference to single %s "
8142 "cannot have field or array sub-references",
8143 ass
->get_description().c_str());
8144 asstype_correct
= true;
8147 if (ref
->get_subrefs()) ref
->error("Reference to %s cannot have "
8148 "field or array sub-references", ass
->get_description().c_str());
8149 asstype_correct
= true;
8152 ref
->error("Reference to a port or port parameter was expected for a "
8153 "port parameter instead of %s", ass
->get_description().c_str());
8155 if (asstype_correct
) {
8156 Type
*ref_type
= ass
->get_Type();
8157 if (ref_type
&& !type
->is_identical(ref_type
))
8158 ref
->error("Type mismatch: Reference to a port or port parameter "
8159 "of type `%s' was expected instead of `%s'",
8160 type
->get_typename().c_str(), ref_type
->get_typename().c_str());
8162 return new ActualPar(ref
);
8164 actual_par
->error("Reference to a port or port parameter was expected "
8165 "for a port parameter");
8166 return new ActualPar();
8170 void FormalPar::use_as_lvalue(const Location
& p_loc
)
8174 case A_PAR_TEMPL_IN
:
8177 FATAL_ERROR("FormalPar::use_as_lvalue()");
8179 if (!used_as_lvalue
) {
8180 Definition
*my_def
= my_parlist
->get_my_def();
8181 if (!my_def
) FATAL_ERROR("FormalPar::use_as_lvalue()");
8182 if (my_def
->get_asstype() == A_TEMPLATE
)
8183 p_loc
.error("Parameter `%s' of the template cannot be passed further "
8184 "as `out' or `inout' parameter", id
->get_dispname().c_str());
8186 // update the genname so that all references in the generated code
8187 // will point to the shadow object
8189 set_genname(id
->get_name() + "_shadow");
8191 used_as_lvalue
= true;
8196 char* FormalPar::generate_code_defval(char* str
)
8198 if (!defval
.ap
|| defval_generated
) return str
;
8199 defval_generated
= true;
8200 switch (defval
.ap
->get_selection()) {
8201 case ActualPar::AP_VALUE
: {
8202 Value
*val
= defval
.ap
->get_Value();
8203 if (use_runtime_2
&& TypeConv::needs_conv_refd(val
)) {
8204 str
= TypeConv::gen_conv_code_refd(str
, val
->get_lhs_name().c_str(), val
);
8206 str
= val
->generate_code_init(str
, val
->get_lhs_name().c_str());
8209 case ActualPar::AP_TEMPLATE
: {
8210 TemplateInstance
*ti
= defval
.ap
->get_TemplateInstance();
8211 Template
*temp
= ti
->get_Template();
8212 Ref_base
*dref
= ti
->get_DerivedRef();
8214 expression_struct expr
;
8215 Code::init_expr(&expr
);
8216 expr
.expr
= mputprintf(expr
.expr
, "%s = ",
8217 temp
->get_lhs_name().c_str());
8218 dref
->generate_code(&expr
);
8219 str
= Code::merge_free_expr(str
, &expr
, false);
8221 if (use_runtime_2
&& TypeConv::needs_conv_refd(temp
)) {
8222 str
= TypeConv::gen_conv_code_refd(str
, temp
->get_lhs_name().c_str(), temp
);
8224 str
= temp
->generate_code_init(str
, temp
->get_lhs_name().c_str());
8226 if (defval
.ap
->get_gen_restriction_check() != TR_NONE
) {
8227 str
= Template::generate_restriction_check_code(str
,
8228 temp
->get_lhs_name().c_str(), defval
.ap
->get_gen_restriction_check());
8231 case ActualPar::AP_REF
:
8234 FATAL_ERROR("FormalPar::generate_code()");
8239 void FormalPar::generate_code_defval(output_struct
*target
, bool)
8241 if (!defval
.ap
) return;
8242 switch (defval
.ap
->get_selection()) {
8243 case ActualPar::AP_VALUE
: {
8244 Value
*val
= defval
.ap
->get_Value();
8246 Code::init_cdef(&cdef
);
8247 type
->generate_code_object(&cdef
, val
);
8248 Code::merge_cdef(target
, &cdef
);
8249 Code::free_cdef(&cdef
);
8251 case ActualPar::AP_TEMPLATE
: {
8252 TemplateInstance
*ti
= defval
.ap
->get_TemplateInstance();
8253 Template
*temp
= ti
->get_Template();
8255 Code::init_cdef(&cdef
);
8256 type
->generate_code_object(&cdef
, temp
);
8257 Code::merge_cdef(target
, &cdef
);
8258 Code::free_cdef(&cdef
);
8260 case ActualPar::AP_REF
:
8263 FATAL_ERROR("FormalPar::generate_code()");
8265 target
->functions
.post_init
= generate_code_defval(target
->functions
.post_init
);
8268 char *FormalPar::generate_code_fpar(char *str
, bool display_unused
/* = false */)
8270 // the name of the parameter should not be displayed if the parameter is not
8271 // used (to avoid a compiler warning)
8272 bool display_name
= (usage_found
|| display_unused
|| (!enable_set_bound_out_param
&&
8273 (asstype
== A_PAR_VAL_OUT
|| asstype
== A_PAR_TEMPL_OUT
)));
8274 const char *name_str
= display_name
? id
->get_name().c_str() : "";
8278 str
= mputprintf(str
, "Lazy_Param<%s>& %s", type
->get_genname_value(my_scope
).c_str(), name_str
);
8280 str
= mputprintf(str
, "const %s& %s", type
->get_genname_value(my_scope
).c_str(), name_str
);
8284 case A_PAR_VAL_INOUT
:
8286 str
= mputprintf(str
, "%s& %s", type
->get_genname_value(my_scope
).c_str(),
8289 case A_PAR_TEMPL_IN
:
8291 str
= mputprintf(str
, "Lazy_Param<%s>& %s", type
->get_genname_template(my_scope
).c_str(), name_str
);
8293 str
= mputprintf(str
, "const %s& %s", type
->get_genname_template(my_scope
).c_str(), name_str
);
8296 case A_PAR_TEMPL_OUT
:
8297 case A_PAR_TEMPL_INOUT
:
8298 str
= mputprintf(str
, "%s& %s",
8299 type
->get_genname_template(my_scope
).c_str(), name_str
);
8302 str
= mputprintf(str
, "TIMER& %s", name_str
);
8305 FATAL_ERROR("FormalPar::generate_code()");
8310 string
FormalPar::get_reference_name(Scope
* scope
) const
8316 case A_PAR_TEMPL_IN
:
8317 ret_val
+= type
->get_genname_template(scope
);
8320 ret_val
+= type
->get_genname_value(scope
);
8325 ret_val
+= get_id().get_name();
8332 char *FormalPar::generate_code_object(char *str
, const char *p_prefix
, char refch
)
8334 const char *name_str
= id
->get_name().c_str();
8338 str
= mputprintf(str
, "Lazy_Param<%s> %s%s;\n", type
->get_genname_value(my_scope
).c_str(), p_prefix
, name_str
);
8340 str
= mputprintf(str
, "%s %s%s;\n", type
->get_genname_value(my_scope
).c_str(), p_prefix
, name_str
);
8344 case A_PAR_VAL_INOUT
:
8346 str
= mputprintf(str
, "%s%c %s%s;\n",
8347 type
->get_genname_value(my_scope
).c_str(), refch
, p_prefix
, name_str
);
8349 case A_PAR_TEMPL_IN
:
8351 str
= mputprintf(str
, "Lazy_Param<%s> %s%s;\n", type
->get_genname_template(my_scope
).c_str(), p_prefix
, name_str
);
8353 str
= mputprintf(str
, "%s %s%s;\n", type
->get_genname_template(my_scope
).c_str(), p_prefix
, name_str
);
8356 case A_PAR_TEMPL_OUT
:
8357 case A_PAR_TEMPL_INOUT
:
8358 str
= mputprintf(str
, "%s%c %s%s;\n",
8359 type
->get_genname_template(my_scope
).c_str(), refch
, p_prefix
, name_str
);
8362 str
= mputprintf(str
, "TIMER& %s%s;\n", p_prefix
, name_str
);
8365 FATAL_ERROR("FormalPar::generate_code_object()");
8370 char *FormalPar::generate_shadow_object(char *str
) const
8372 if (used_as_lvalue
&& !lazy_eval
) {
8373 const string
& t_genname
= get_genname();
8374 const char *genname_str
= t_genname
.c_str();
8375 const char *name_str
= id
->get_name().c_str();
8378 str
= mputprintf(str
, "%s %s(%s);\n",
8379 type
->get_genname_value(my_scope
).c_str(), genname_str
, name_str
);
8381 case A_PAR_TEMPL_IN
:
8382 str
= mputprintf(str
, "%s %s(%s);\n",
8383 type
->get_genname_template(my_scope
).c_str(), genname_str
, name_str
);
8386 FATAL_ERROR("FormalPar::generate_shadow_object()");
8392 char *FormalPar::generate_code_set_unbound(char *str
) const
8395 case A_PAR_TEMPL_OUT
:
8397 str
= mputprintf(str
, "%s.clean_up();\n", id
->get_name().c_str());
8405 void FormalPar::dump_internal(unsigned level
) const
8407 DEBUG(level
, "%s: %s", get_assname(), id
->get_dispname().c_str());
8408 if (type
) type
->dump(level
+ 1);
8411 DEBUG(level
+ 1, "default value:");
8412 defval
.ap
->dump(level
+ 2);
8416 DEBUG(level
+ 1, "default value:");
8417 defval
.ti
->dump(level
+ 2);
8422 // =================================
8423 // ===== FormalParList
8424 // =================================
8426 FormalParList::~FormalParList()
8428 size_t nof_pars
= pars_v
.size();
8429 for (size_t i
= 0; i
< nof_pars
; i
++) delete pars_v
[i
];
8434 FormalParList
*FormalParList::clone() const
8436 FATAL_ERROR("FormalParList::clone");
8439 void FormalParList::set_fullname(const string
& p_fullname
)
8441 Node::set_fullname(p_fullname
);
8442 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8443 FormalPar
*par
= pars_v
[i
];
8444 par
->set_fullname(p_fullname
+ "." + par
->get_id().get_dispname());
8448 void FormalParList::set_my_scope(Scope
*p_scope
)
8450 set_parent_scope(p_scope
);
8451 Node::set_my_scope(p_scope
);
8452 // the scope of parameters is set to the parent scope instead of this
8453 // because they cannot refer to each other
8454 for (size_t i
= 0; i
< pars_v
.size(); i
++) pars_v
[i
]->set_my_scope(p_scope
);
8457 void FormalParList::add_fp(FormalPar
*p_fp
)
8459 if (!p_fp
) FATAL_ERROR("NULL parameter: Ttcn::FormalParList::add_fp()");
8461 p_fp
->set_my_parlist(this);
8465 bool FormalParList::has_notused_defval() const
8467 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8468 if (pars_v
[i
]->has_notused_defval())
8474 bool FormalParList::has_only_default_values() const
8476 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8477 if (!pars_v
[i
]->has_defval()) {
8485 bool FormalParList::has_fp_withName(const Identifier
& p_name
)
8487 if (!checked
) chk(Definition::A_UNDEF
);
8488 return pars_m
.has_key(p_name
.get_name());
8491 FormalPar
*FormalParList::get_fp_byName(const Identifier
& p_name
)
8493 if (!checked
) chk(Definition::A_UNDEF
);
8494 return pars_m
[p_name
.get_name()];
8497 bool FormalParList::get_startability()
8499 if(!checked
) FATAL_ERROR("FormalParList::get_startability()");
8500 return is_startable
;
8503 Common::Assignment
*FormalParList::get_ass_bySRef(Common::Ref_simple
*p_ref
)
8505 if (!p_ref
|| !checked
) FATAL_ERROR("FormalParList::get_ass_bySRef()");
8506 if (p_ref
->get_modid()) return parent_scope
->get_ass_bySRef(p_ref
);
8508 const string
& name
= p_ref
->get_id()->get_name();
8509 if (pars_m
.has_key(name
)) return pars_m
[name
];
8510 else return parent_scope
->get_ass_bySRef(p_ref
);
8514 bool FormalParList::has_ass_withId(const Identifier
& p_id
)
8516 if (!checked
) FATAL_ERROR("Ttcn::FormalParList::has_ass_withId()");
8517 return pars_m
.has_key(p_id
.get_name())
8518 || parent_scope
->has_ass_withId(p_id
);
8521 void FormalParList::set_genname(const string
& p_prefix
)
8523 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8524 FormalPar
*par
= pars_v
[i
];
8525 const string
& par_name
= par
->get_id().get_name();
8526 if (par
->get_asstype() != Definition::A_PAR_TIMER
)
8527 par
->get_Type()->set_genname(p_prefix
, par_name
);
8528 if (par
->has_defval()) {
8529 string
embedded_genname(p_prefix
);
8530 embedded_genname
+= '_';
8531 embedded_genname
+= par_name
;
8532 embedded_genname
+= "_defval";
8533 ActualPar
*defval
= par
->get_defval();
8534 switch (defval
->get_selection()) {
8535 case ActualPar::AP_ERROR
:
8536 case ActualPar::AP_REF
:
8538 case ActualPar::AP_VALUE
: {
8539 Value
*v
= defval
->get_Value();
8540 v
->set_genname_prefix("const_");
8541 v
->set_genname_recursive(embedded_genname
);
8543 case ActualPar::AP_TEMPLATE
: {
8544 Template
*t
= defval
->get_TemplateInstance()->get_Template();
8545 t
->set_genname_prefix("template_");
8546 t
->set_genname_recursive(embedded_genname
);
8549 FATAL_ERROR("FormalParList::set_genname()");
8555 void FormalParList::chk(Definition::asstype_t deftype
)
8557 if (checked
) return;
8560 is_startable
= true;
8561 Error_Context
cntxt(this, "In formal parameter list");
8562 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8563 FormalPar
*par
= pars_v
[i
];
8564 const Identifier
& id
= par
->get_id();
8565 const string
& name
= id
.get_name();
8566 const char *dispname
= id
.get_dispname().c_str();
8567 if (pars_m
.has_key(name
)) {
8568 par
->error("Duplicate parameter with name `%s'", dispname
);
8569 pars_m
[name
]->note("Previous definition of `%s' is here", dispname
);
8571 pars_m
.add(name
, par
);
8572 if (parent_scope
&& parent_scope
->has_ass_withId(id
)) {
8573 par
->error("Parameter name `%s' is not unique in the scope "
8574 "hierarchy", dispname
);
8575 Reference
ref(0, id
.clone());
8576 Common::Assignment
*ass
= parent_scope
->get_ass_bySRef(&ref
);
8577 if (!ass
) FATAL_ERROR("FormalParList::chk()");
8578 ass
->note("Symbol `%s' is already defined here in a higher scope "
8582 Error_Context
cntxt2(par
, "In parameter `%s'", dispname
);
8584 // check whether the parameter type is allowed
8586 case Definition::A_TEMPLATE
:
8587 switch (par
->get_asstype()) {
8588 case Definition::A_PAR_VAL_IN
:
8589 case Definition::A_PAR_TEMPL_IN
:
8590 // these are allowed
8593 par
->error("A template cannot have %s", par
->get_assname());
8596 case Definition::A_TESTCASE
:
8597 switch (par
->get_asstype()) {
8598 case Definition::A_PAR_TIMER
:
8599 case Definition::A_PAR_PORT
:
8600 // these are forbidden
8601 par
->error("A testcase cannot have %s", par
->get_assname());
8606 // everything is allowed for functions and altsteps
8610 switch(par
->get_asstype()) {
8611 case Common::Assignment::A_PAR_VAL_IN
:
8612 case Common::Assignment::A_PAR_TEMPL_IN
:
8613 case Common::Assignment::A_PAR_VAL_INOUT
:
8614 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8615 if (is_startable
&& par
->get_Type()->is_component_internal())
8616 is_startable
= false;
8619 is_startable
= false;
8622 if (!par
->has_defval()) min_nof_pars
= i
+ 1;
8623 // the last parameter without a default value determines the minimum
8627 // check that @lazy paramterization not used in cases currently unsupported
8628 void FormalParList::chk_noLazyParams() {
8629 Error_Context
cntxt(this, "In formal parameter list");
8630 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8631 FormalPar
*par
= pars_v
[i
];
8632 if (par
->get_lazy_eval()) {
8633 par
->error("Formal parameter `%s' cannot be @lazy, not supported in this case.",
8634 par
->get_id().get_dispname().c_str());
8639 void FormalParList::chk_startability(const char *p_what
, const char *p_name
)
8641 if(!checked
) FATAL_ERROR("FormalParList::chk_startability()");
8642 if (is_startable
) return;
8643 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8644 FormalPar
*par
= pars_v
[i
];
8645 switch (par
->get_asstype()) {
8646 case Common::Assignment::A_PAR_VAL_IN
:
8647 case Common::Assignment::A_PAR_TEMPL_IN
:
8648 case Common::Assignment::A_PAR_VAL_INOUT
:
8649 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8650 if (par
->get_Type()->is_component_internal()) {
8651 map
<Type
*,void> type_chain
;
8652 char* err_str
= mprintf("a parameter or embedded in a parameter of "
8653 "a function used in a start operation. "
8654 "%s `%s' cannot be started on a parallel test component "
8655 "because of `%s'", p_what
, p_name
, par
->get_description().c_str());
8656 par
->get_Type()->chk_component_internal(type_chain
, err_str
);
8661 par
->error("%s `%s' cannot be started on a parallel test component "
8662 "because it has %s", p_what
, p_name
, par
->get_description().c_str());
8667 void FormalParList::chk_compatibility(FormalParList
* p_fp_list
,
8670 size_t nof_type_pars
= pars_v
.size();
8671 size_t nof_function_pars
= p_fp_list
->pars_v
.size();
8672 // check for the number of parameters
8673 if (nof_type_pars
!= nof_function_pars
) {
8674 p_fp_list
->error("Too %s parameters: %lu was expected instead of %lu",
8675 nof_type_pars
< nof_function_pars
? "many" : "few",
8676 (unsigned long) nof_type_pars
, (unsigned long) nof_function_pars
);
8678 size_t upper_limit
=
8679 nof_type_pars
< nof_function_pars
? nof_type_pars
: nof_function_pars
;
8680 for (size_t i
= 0; i
< upper_limit
; i
++) {
8681 FormalPar
*type_par
= pars_v
[i
];
8682 FormalPar
*function_par
= p_fp_list
->pars_v
[i
];
8683 Error_Context
cntxt(function_par
, "In parameter #%lu",
8684 (unsigned long) (i
+ 1));
8685 FormalPar::asstype_t type_par_asstype
= type_par
->get_asstype();
8686 FormalPar::asstype_t function_par_asstype
= function_par
->get_asstype();
8687 // check for parameter kind equivalence
8688 // (in, out or inout / value or template)
8689 if (type_par_asstype
!= function_par_asstype
) {
8690 function_par
->error("The kind of the parameter is not the same as in "
8691 "type `%s': %s was expected instead of %s", where
,
8692 type_par
->get_assname(), function_par
->get_assname());
8694 // check for type equivalence
8695 if (type_par_asstype
!= FormalPar::A_PAR_TIMER
&&
8696 function_par_asstype
!= FormalPar::A_PAR_TIMER
) {
8697 Type
*type_par_type
= type_par
->get_Type();
8698 Type
*function_par_type
= function_par
->get_Type();
8699 if (!type_par_type
->is_identical(function_par_type
)) {
8700 function_par_type
->error("The type of the parameter is not the same "
8701 "as in type `%s': `%s' was expected instead of `%s'", where
,
8702 type_par_type
->get_typename().c_str(),
8703 function_par_type
->get_typename().c_str());
8704 } else if (type_par_type
->get_sub_type() && function_par_type
->get_sub_type() &&
8705 (type_par_type
->get_sub_type()->get_subtypetype()==function_par_type
->get_sub_type()->get_subtypetype()) &&
8706 (!type_par_type
->get_sub_type()->is_compatible(function_par_type
->get_sub_type()))) {
8707 // TODO: maybe equivalence should be checked, or maybe that is too strict
8708 function_par_type
->error(
8709 "Subtype mismatch: subtype %s has no common value with subtype %s",
8710 type_par_type
->get_sub_type()->to_string().c_str(),
8711 function_par_type
->get_sub_type()->to_string().c_str());
8714 // check for template restriction equivalence
8715 if (type_par
->get_template_restriction()!=
8716 function_par
->get_template_restriction()) {
8717 function_par
->error("The template restriction of the parameter is "
8718 "not the same as in type `%s': %s restriction was expected instead "
8719 "of %s restriction", where
,
8720 type_par
->get_template_restriction()==TR_NONE
? "no" :
8721 Template::get_restriction_name(type_par
->get_template_restriction()),
8722 function_par
->get_template_restriction()==TR_NONE
? "no" :
8723 Template::get_restriction_name(function_par
->
8724 get_template_restriction()));
8726 // check for @lazy equivalence
8727 if (type_par
->get_lazy_eval()!=function_par
->get_lazy_eval()) {
8728 function_par
->error("Parameter @lazy-ness mismatch");
8730 // check for name equivalence
8731 const Identifier
& type_par_id
= type_par
->get_id();
8732 const Identifier
& function_par_id
= function_par
->get_id();
8733 if (type_par_id
!= function_par_id
) {
8734 function_par
->warning("The name of the parameter is not the same "
8735 "as in type `%s': `%s' was expected instead of `%s'", where
,
8736 type_par_id
.get_dispname().c_str(),
8737 function_par_id
.get_dispname().c_str());
8742 bool FormalParList::fold_named_and_chk(ParsedActualParameters
*p_paps
,
8743 ActualParList
*p_aplist
)
8745 const size_t num_named
= p_paps
->get_nof_nps();
8746 const size_t num_unnamed
= p_paps
->get_nof_tis();
8747 size_t num_actual
= num_unnamed
;
8749 // Construct a map to tell us what index a FormalPar has
8750 typedef map
<FormalPar
*, size_t> formalpar_map_t
;
8751 formalpar_map_t formalpar_map
;
8753 size_t num_fp
= get_nof_fps();
8754 for (size_t fpx
= 0; fpx
< num_fp
; ++fpx
) {
8755 FormalPar
*fp
= get_fp_byIndex(fpx
);
8756 formalpar_map
.add(fp
, new size_t(fpx
));
8759 // Go through the named parameters
8760 for (size_t i
= 0; i
< num_named
; ++i
) {
8761 NamedParam
*np
= p_paps
->extract_np_byIndex(i
);
8762 // We are now responsible for np.
8764 if (has_fp_withName(*np
->get_name())) {
8765 // there is a formal parameter with that name
8766 FormalPar
*fp
= get_fp_byName(*np
->get_name());
8767 const size_t is_at
= *formalpar_map
[fp
]; // the index of the formal par
8768 if (is_at
>= num_actual
) {
8769 // There is no actual par in the unnamed part.
8770 // Create one from the named param.
8772 // First, pad the gap with '-'
8773 for (; num_actual
< is_at
; ++num_actual
) {
8775 if (pars_v
[num_actual
]->has_defval()) {
8776 not_used
= new Template(Template::TEMPLATE_NOTUSED
);
8778 else { // cannot use '-' if no default value
8779 not_used
= new Template(Template::TEMPLATE_ERROR
);
8781 TemplateInstance
*new_ti
= new TemplateInstance(0, 0, not_used
);
8782 // Conjure a location info at the beginning of the unnamed part
8783 // (that is, the beginning of the actual parameter list)
8784 new_ti
->set_location(p_paps
->get_tis()->get_filename(),
8785 p_paps
->get_tis()->get_first_line(),
8786 p_paps
->get_tis()->get_first_column(), 0, 0);
8787 p_paps
->get_tis()->add_ti(new_ti
);
8789 TemplateInstance
* namedti
= np
->extract_ti();
8790 p_paps
->get_tis()->add_ti(namedti
);
8793 // There is already an actual par at that position, fetch it
8794 TemplateInstance
* ti
= p_paps
->get_tis()->get_ti_byIndex(is_at
);
8795 Template::templatetype_t tt
= ti
->get_Template()->get_templatetype();
8797 if (is_at
>= num_unnamed
&& !ti
->get_Type() && !ti
->get_DerivedRef()
8798 && (tt
== Template::TEMPLATE_NOTUSED
|| tt
== Template::TEMPLATE_ERROR
)) {
8799 // NotUsed in the named part => padding
8800 np
->error("Named parameter `%s' out of order",
8801 np
->get_name()->get_dispname().c_str());
8803 // attempt to override an original unnamed param with a named one
8804 np
->error("Formal parameter `%s' assigned more than once",
8805 np
->get_name()->get_dispname().c_str());
8809 else { // no formal parameter with that name
8811 switch (my_def
->get_asstype()) {
8812 case Common::Assignment::A_TYPE
: {
8813 Type
*t
= my_def
->get_Type();
8815 switch (t
? t
->get_typetype() : 0) {
8816 case Type::T_FUNCTION
:
8817 nam
= mcopystr("Function reference");
8819 case Type::T_ALTSTEP
:
8820 nam
= mcopystr("Altstep reference");
8822 case Type::T_TESTCASE
:
8823 nam
= mcopystr("Testcase reference");
8826 FATAL_ERROR("FormalParList::chk_actual_parlist() "
8827 "Unexpected type %s", t
->get_typename().c_str());
8828 } // switch(typetype)
8831 nam
= mcopystr(my_def
->get_assname());
8833 } // switch(asstype)
8835 *nam
&= ~('a'-'A'); // Make the first letter uppercase
8836 p_paps
->get_tis()->error("%s `%s' has no formal parameter `%s'",
8838 my_def
->get_fullname().c_str(),
8839 np
->get_name()->get_dispname().c_str());
8846 for (size_t fpx
= 0; fpx
< num_fp
; ++fpx
) {
8847 delete formalpar_map
.get_nth_elem(fpx
);
8849 formalpar_map
.clear();
8851 return chk_actual_parlist(p_paps
->get_tis(), p_aplist
);
8854 bool FormalParList::chk_actual_parlist(TemplateInstances
*p_tis
,
8855 ActualParList
*p_aplist
)
8857 size_t formal_pars
= pars_v
.size();
8858 size_t actual_pars
= p_tis
->get_nof_tis();
8859 // p_aplist->get_nof_pars() is usually 0 on entry
8860 bool error_flag
= false;
8862 if (min_nof_pars
== formal_pars
) {
8863 // none of the parameters have default value
8864 if (actual_pars
!= formal_pars
) {
8865 p_tis
->error("Too %s parameters: %lu was expected "
8866 "instead of %lu", actual_pars
< formal_pars
? "few" : "many",
8867 (unsigned long) formal_pars
, (unsigned long) actual_pars
);
8871 // some parameters have default value
8872 if (actual_pars
< min_nof_pars
) {
8873 p_tis
->error("Too few parameters: at least %lu "
8874 "was expected instead of %lu",
8875 (unsigned long) min_nof_pars
, (unsigned long) actual_pars
);
8877 } else if (actual_pars
> formal_pars
) {
8878 p_tis
->error("Too many parameters: at most %lu "
8879 "was expected instead of %lu",
8880 (unsigned long) formal_pars
, (unsigned long) actual_pars
);
8885 // Do not check actual parameters in excess of the formal ones
8886 size_t upper_limit
= actual_pars
< formal_pars
? actual_pars
: formal_pars
;
8887 for (size_t i
= 0; i
< upper_limit
; i
++) {
8888 TemplateInstance
*ti
= p_tis
->get_ti_byIndex(i
);
8890 // the formal parameter for the current actual parameter
8891 FormalPar
*fp
= pars_v
[i
];
8892 Error_Context
cntxt(ti
, "In parameter #%lu for `%s'",
8893 (unsigned long) (i
+ 1), fp
->get_id().get_dispname().c_str());
8894 if (!ti
->get_Type() && !ti
->get_DerivedRef() && ti
->get_Template()
8895 ->get_templatetype() == Template::TEMPLATE_NOTUSED
) {
8896 if (fp
->has_defval()) {
8897 ActualPar
*defval
= fp
->get_defval();
8898 p_aplist
->add(new ActualPar(defval
));
8899 if (defval
->is_erroneous()) error_flag
= true;
8901 ti
->error("Not used symbol (`-') cannot be used for parameter "
8902 "that does not have default value");
8903 p_aplist
->add(new ActualPar());
8906 } else if (!ti
->get_Type() && !ti
->get_DerivedRef() && ti
->get_Template()
8907 ->get_templatetype() == Template::TEMPLATE_ERROR
) {
8908 ti
->error("Parameter not specified");
8910 ActualPar
*ap
= fp
->chk_actual_par(ti
, Type::EXPECTED_DYNAMIC_VALUE
);
8912 if (ap
->is_erroneous()) error_flag
= true;
8916 // The rest of formal parameters have no corresponding actual parameters.
8917 // Create actual parameters for them based on their default values
8918 // (which must exist).
8919 for (size_t i
= upper_limit
; i
< formal_pars
; i
++) {
8920 FormalPar
*fp
= pars_v
[i
];
8921 if (fp
->has_defval()) {
8922 ActualPar
*defval
= fp
->get_defval();
8923 p_aplist
->add(new ActualPar(defval
));
8924 if (defval
->is_erroneous()) error_flag
= true;
8926 p_aplist
->add(new ActualPar()); // erroneous
8933 bool FormalParList::chk_activate_argument(ActualParList
*p_aplist
,
8934 const char* p_description
)
8936 bool ret_val
= true;
8937 for(size_t i
= 0; i
< p_aplist
->get_nof_pars(); i
++) {
8938 ActualPar
*t_ap
= p_aplist
->get_par(i
);
8939 if(t_ap
->get_selection() != ActualPar::AP_REF
) continue;
8940 FormalPar
*t_fp
= pars_v
[i
];
8941 switch(t_fp
->get_asstype()) {
8942 case Common::Assignment::A_PAR_VAL_OUT
:
8943 case Common::Assignment::A_PAR_VAL_INOUT
:
8944 case Common::Assignment::A_PAR_TEMPL_OUT
:
8945 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8946 case Common::Assignment::A_PAR_TIMER
:
8947 //the checking shall be performed for these parameter types
8949 case Common::Assignment::A_PAR_PORT
:
8950 // port parameters are always correct because ports can be defined
8951 // only in component types
8954 FATAL_ERROR("FormalParList::chk_activate_argument()");
8956 Ref_base
*t_ref
= t_ap
->get_Ref();
8957 Common::Assignment
*t_par_ass
= t_ref
->get_refd_assignment();
8958 if(!t_par_ass
) FATAL_ERROR("FormalParList::chk_activate_argument()");
8959 switch (t_par_ass
->get_asstype()) {
8960 case Common::Assignment::A_VAR
:
8961 case Common::Assignment::A_VAR_TEMPLATE
:
8962 case Common::Assignment::A_TIMER
:
8963 // it is not allowed to pass references of local variables or timers
8964 if (t_par_ass
->is_local()) {
8965 t_ref
->error("Parameter #%lu of %s refers to %s, which is a local "
8966 "definition within a statement block and may have shorter "
8967 "lifespan than the activated default. Only references to "
8968 "variables and timers defined in the component type can be passed "
8969 "to activated defaults", (unsigned long) (i
+ 1), p_description
,
8970 t_par_ass
->get_description().c_str());
8974 case Common::Assignment::A_PAR_VAL_IN
:
8975 case Common::Assignment::A_PAR_VAL_OUT
:
8976 case Common::Assignment::A_PAR_VAL_INOUT
:
8977 case Common::Assignment::A_PAR_TEMPL_IN
:
8978 case Common::Assignment::A_PAR_TEMPL_OUT
:
8979 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8980 case Common::Assignment::A_PAR_TIMER
: {
8981 // it is not allowed to pass references pointing to formal parameters
8982 // except for activate() statements within testcases
8983 // note: all defaults are deactivated at the end of the testcase
8984 FormalPar
*t_refd_fp
= dynamic_cast<FormalPar
*>(t_par_ass
);
8985 if (!t_refd_fp
) FATAL_ERROR("FormalParList::chk_activate_argument()");
8986 FormalParList
*t_fpl
= t_refd_fp
->get_my_parlist();
8987 if (!t_fpl
|| !t_fpl
->my_def
)
8988 FATAL_ERROR("FormalParList::chk_activate_argument()");
8989 if (t_fpl
->my_def
->get_asstype() != Common::Assignment::A_TESTCASE
) {
8990 t_ref
->error("Parameter #%lu of %s refers to %s, which may have "
8991 "shorter lifespan than the activated default. Only references to "
8992 "variables and timers defined in the component type can be passed "
8993 "to activated defaults", (unsigned long) (i
+ 1), p_description
,
8994 t_par_ass
->get_description().c_str());
9004 char *FormalParList::generate_code(char *str
, size_t display_unused
/* = 0 */)
9006 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9007 if (i
> 0) str
= mputstr(str
, ", ");
9008 str
= pars_v
[i
]->generate_code_fpar(str
, i
< display_unused
);
9013 char* FormalParList::generate_code_defval(char* str
)
9015 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9016 str
= pars_v
[i
]->generate_code_defval(str
);
9021 void FormalParList::generate_code_defval(output_struct
*target
)
9023 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9024 pars_v
[i
]->generate_code_defval(target
);
9028 char *FormalParList::generate_code_actual_parlist(char *str
,
9029 const char *p_prefix
)
9031 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9032 if (i
> 0) str
= mputstr(str
, ", ");
9033 str
= mputstr(str
, p_prefix
);
9034 str
= mputstr(str
, pars_v
[i
]->get_id().get_name().c_str());
9039 char *FormalParList::generate_code_object(char *str
, const char *p_prefix
, char refch
)
9041 for (size_t i
= 0; i
< pars_v
.size(); i
++)
9042 str
= pars_v
[i
]->generate_code_object(str
, p_prefix
, refch
);
9046 char *FormalParList::generate_shadow_objects(char *str
) const
9048 for (size_t i
= 0; i
< pars_v
.size(); i
++)
9049 str
= pars_v
[i
]->generate_shadow_object(str
);
9053 char *FormalParList::generate_code_set_unbound(char *str
) const
9055 if (enable_set_bound_out_param
) return str
;
9056 for (size_t i
= 0; i
< pars_v
.size(); i
++)
9057 str
= pars_v
[i
]->generate_code_set_unbound(str
);
9062 void FormalParList::dump(unsigned level
) const
9064 size_t nof_pars
= pars_v
.size();
9065 DEBUG(level
, "formal parameters: %lu pcs.", (unsigned long) nof_pars
);
9066 for(size_t i
= 0; i
< nof_pars
; i
++) pars_v
[i
]->dump(level
+ 1);
9069 // =================================
9071 // =================================
9073 ActualPar::ActualPar(Value
*v
)
9074 : Node(), selection(AP_VALUE
), my_scope(0), gen_restriction_check(TR_NONE
),
9075 gen_post_restriction_check(TR_NONE
)
9077 if (!v
) FATAL_ERROR("ActualPar::ActualPar()");
9081 ActualPar::ActualPar(TemplateInstance
*t
)
9082 : Node(), selection(AP_TEMPLATE
), my_scope(0),
9083 gen_restriction_check(TR_NONE
), gen_post_restriction_check(TR_NONE
)
9085 if (!t
) FATAL_ERROR("ActualPar::ActualPar()");
9089 ActualPar::ActualPar(Ref_base
*r
)
9090 : Node(), selection(AP_REF
), my_scope(0), gen_restriction_check(TR_NONE
),
9091 gen_post_restriction_check(TR_NONE
)
9093 if (!r
) FATAL_ERROR("ActualPar::ActualPar()");
9097 ActualPar::ActualPar(ActualPar
*a
)
9098 : Node(), selection(AP_DEFAULT
), my_scope(0),
9099 gen_restriction_check(TR_NONE
), gen_post_restriction_check(TR_NONE
)
9101 if (!a
) FATAL_ERROR("ActualPar::ActualPar()");
9105 ActualPar::~ActualPar()
9120 break; // nothing to do with act
9122 FATAL_ERROR("ActualPar::~ActualPar()");
9126 ActualPar
*ActualPar::clone() const
9128 FATAL_ERROR("ActualPar::clone");
9131 void ActualPar::set_fullname(const string
& p_fullname
)
9133 Node::set_fullname(p_fullname
);
9138 val
->set_fullname(p_fullname
);
9141 temp
->set_fullname(p_fullname
);
9144 ref
->set_fullname(p_fullname
);
9149 FATAL_ERROR("ActualPar::set_fullname()");
9153 void ActualPar::set_my_scope(Scope
*p_scope
)
9160 val
->set_my_scope(p_scope
);
9163 temp
->set_my_scope(p_scope
);
9166 ref
->set_my_scope(p_scope
);
9169 switch (act
->selection
) {
9171 ref
->set_my_scope(p_scope
);
9178 FATAL_ERROR("ActualPar::set_my_scope()");
9182 FATAL_ERROR("ActualPar::set_my_scope()");
9186 Value
*ActualPar::get_Value() const
9188 if (selection
!= AP_VALUE
) FATAL_ERROR("ActualPar::get_Value()");
9192 TemplateInstance
*ActualPar::get_TemplateInstance() const
9194 if (selection
!= AP_TEMPLATE
)
9195 FATAL_ERROR("ActualPar::get_TemplateInstance()");
9199 Ref_base
*ActualPar::get_Ref() const
9201 if (selection
!= AP_REF
) FATAL_ERROR("ActualPar::get_Ref()");
9205 ActualPar
*ActualPar::get_ActualPar() const
9207 if (selection
!= AP_DEFAULT
) FATAL_ERROR("ActualPar::get_ActualPar()");
9211 void ActualPar::chk_recursions(ReferenceChain
& refch
)
9213 switch (selection
) {
9216 val
->chk_recursions(refch
);
9220 Ref_base
*derived_ref
= temp
->get_DerivedRef();
9222 ActualParList
*parlist
= derived_ref
->get_parlist();
9225 parlist
->chk_recursions(refch
);
9230 Ttcn::Def_Template
* defTemp
= temp
->get_Referenced_Base_Template();
9233 refch
.add(defTemp
->get_fullname());
9237 temp
->get_Template()->chk_recursions(refch
);
9245 bool ActualPar::has_single_expr()
9247 switch (selection
) {
9249 return val
->has_single_expr();
9251 if (gen_restriction_check
!=TR_NONE
||
9252 gen_post_restriction_check
!=TR_NONE
) return false;
9253 return temp
->has_single_expr();
9255 if (gen_restriction_check
!=TR_NONE
||
9256 gen_post_restriction_check
!=TR_NONE
) return false;
9257 if (use_runtime_2
&& ref
->get_subrefs() != NULL
) {
9258 FieldOrArrayRefs
* subrefs
= ref
->get_subrefs();
9259 for (size_t i
= 0; i
< subrefs
->get_nof_refs(); ++i
) {
9260 if (FieldOrArrayRef::ARRAY_REF
== subrefs
->get_ref(i
)->get_type()) {
9265 return ref
->has_single_expr();
9269 FATAL_ERROR("ActualPar::has_single_expr()");
9274 void ActualPar::set_code_section(
9275 GovernedSimple::code_section_t p_code_section
)
9277 switch (selection
) {
9279 val
->set_code_section(p_code_section
);
9282 temp
->set_code_section(p_code_section
);
9285 ref
->set_code_section(p_code_section
);
9291 void ActualPar::generate_code(expression_struct
*expr
, bool copy_needed
, bool lazy_param
, bool used_as_lvalue
) const
9293 switch (selection
) {
9295 if (lazy_param
) { // copy_needed doesn't matter in this case
9296 LazyParamData::init(used_as_lvalue
);
9297 LazyParamData::generate_code(expr
, val
, my_scope
);
9298 LazyParamData::clean();
9299 if (val
->get_valuetype() == Value::V_REFD
) {
9300 // check if the reference is a parameter, mark it as used if it is
9301 Reference
* ref
= dynamic_cast<Reference
*>(val
->get_reference());
9303 ref
->refd_param_usage_found();
9307 if (copy_needed
) expr
->expr
= mputprintf(expr
->expr
, "%s(",
9308 val
->get_my_governor()->get_genname_value(my_scope
).c_str());
9309 if (use_runtime_2
&& TypeConv::needs_conv_refd(val
)) {
9310 // Generate everything to preamble to be able to tackle the wrapper
9311 // constructor call. TODO: Reduce the number of temporaries created.
9312 const string
& tmp_id
= val
->get_temporary_id();
9313 const char *tmp_id_str
= tmp_id
.c_str();
9314 expr
->preamble
= mputprintf(expr
->preamble
, "%s %s;\n",
9315 val
->get_my_governor()->get_genname_value(my_scope
).c_str(),
9317 expr
->preamble
= TypeConv::gen_conv_code_refd(expr
->preamble
,
9319 expr
->expr
= mputstr(expr
->expr
, tmp_id_str
);
9320 } else val
->generate_code_expr(expr
);
9321 if (copy_needed
) expr
->expr
= mputc(expr
->expr
, ')');
9325 if (lazy_param
) { // copy_needed doesn't matter in this case
9326 LazyParamData::init(used_as_lvalue
);
9327 LazyParamData::generate_code(expr
, temp
, gen_restriction_check
, my_scope
);
9328 LazyParamData::clean();
9329 if (temp
->get_DerivedRef() != NULL
||
9330 temp
->get_Template()->get_templatetype() == Template::TEMPLATE_REFD
) {
9331 // check if the reference is a parameter, mark it as used if it is
9332 Reference
* ref
= dynamic_cast<Reference
*>(temp
->get_DerivedRef() != NULL
?
9333 temp
->get_DerivedRef() : temp
->get_Template()->get_reference());
9335 ref
->refd_param_usage_found();
9340 expr
->expr
= mputprintf(expr
->expr
, "%s(", temp
->get_Template()
9341 ->get_my_governor()->get_genname_template(my_scope
).c_str());
9342 if (use_runtime_2
&& TypeConv::needs_conv_refd(temp
->get_Template())) {
9343 const string
& tmp_id
= temp
->get_Template()->get_temporary_id();
9344 const char *tmp_id_str
= tmp_id
.c_str();
9345 expr
->preamble
= mputprintf(expr
->preamble
, "%s %s;\n",
9346 temp
->get_Template()->get_my_governor()
9347 ->get_genname_template(my_scope
).c_str(), tmp_id_str
);
9348 expr
->preamble
= TypeConv::gen_conv_code_refd(expr
->preamble
,
9349 tmp_id_str
, temp
->get_Template());
9350 // Not incorporated into gen_conv_code() yet.
9351 if (gen_restriction_check
!= TR_NONE
)
9352 expr
->preamble
= Template::generate_restriction_check_code(
9353 expr
->preamble
, tmp_id_str
, gen_restriction_check
);
9354 expr
->expr
= mputstr(expr
->expr
, tmp_id_str
);
9355 } else temp
->generate_code(expr
, gen_restriction_check
);
9356 if (copy_needed
) expr
->expr
= mputc(expr
->expr
, ')');
9360 if (lazy_param
) FATAL_ERROR("ActualPar::generate_code()"); // syntax error should have already happened
9361 if (copy_needed
) FATAL_ERROR("ActualPar::generate_code()");
9362 if (gen_restriction_check
!= TR_NONE
||
9363 gen_post_restriction_check
!= TR_NONE
) {
9364 // generate runtime check for restricted templates
9365 // code for reference + restriction check
9366 Common::Assignment
*ass
= ref
->get_refd_assignment();
9367 const string
& tmp_id
= my_scope
->get_scope_mod_gen()->get_temporary_id();
9368 const char *tmp_id_str
= tmp_id
.c_str();
9369 expression_struct ref_expr
;
9370 Code::init_expr(&ref_expr
);
9371 ref
->generate_code_const_ref(&ref_expr
);
9372 ref_expr
.preamble
= mputprintf(ref_expr
.preamble
, "%s& %s = %s;\n",
9373 ass
->get_Type()->get_genname_template(ref
->get_my_scope()).c_str(),
9374 tmp_id_str
, ref_expr
.expr
);
9375 if (gen_restriction_check
!= TR_NONE
) {
9376 ref_expr
.preamble
= Template::generate_restriction_check_code(
9377 ref_expr
.preamble
, tmp_id_str
, gen_restriction_check
);
9379 if (gen_post_restriction_check
!= TR_NONE
) {
9380 ref_expr
.postamble
= Template::generate_restriction_check_code(
9381 ref_expr
.postamble
, tmp_id_str
, gen_post_restriction_check
);
9383 // copy content of ref_expr to expr
9384 expr
->preamble
= mputstr(expr
->preamble
, ref_expr
.preamble
);
9385 expr
->expr
= mputprintf(expr
->expr
, "%s", tmp_id_str
);
9386 expr
->postamble
= mputstr(expr
->postamble
, ref_expr
.postamble
);
9387 Code::free_expr(&ref_expr
);
9389 ref
->generate_code(expr
);
9393 if (copy_needed
) FATAL_ERROR("ActualPar::generate_code()");
9394 switch (act
->selection
) {
9397 LazyParamData::generate_code_ap_default_ref(expr
, act
->ref
, my_scope
);
9399 act
->ref
->generate_code(expr
);
9404 LazyParamData::generate_code_ap_default_value(expr
, act
->val
, my_scope
);
9406 expr
->expr
= mputstr(expr
->expr
, act
->val
->get_genname_own(my_scope
).c_str());
9411 LazyParamData::generate_code_ap_default_ti(expr
, act
->temp
, my_scope
);
9413 expr
->expr
= mputstr(expr
->expr
, act
->temp
->get_Template()->get_genname_own(my_scope
).c_str());
9417 FATAL_ERROR("ActualPar::generate_code()");
9421 FATAL_ERROR("ActualPar::generate_code()");
9425 char *ActualPar::rearrange_init_code(char *str
, Common::Module
* usage_mod
)
9427 switch (selection
) {
9429 str
= val
->rearrange_init_code(str
);
9432 str
= temp
->rearrange_init_code(str
, usage_mod
);
9436 str
= act
->rearrange_init_code_defval(str
, usage_mod
);
9439 FATAL_ERROR("ActualPar::rearrange_init_code()");
9444 char *ActualPar::rearrange_init_code_defval(char *str
, Common::Module
* usage_mod
)
9446 switch (selection
) {
9448 if (val
->get_my_scope()->get_scope_mod_gen() == usage_mod
) {
9449 str
= val
->generate_code_init(str
, val
->get_lhs_name().c_str());
9453 str
= temp
->rearrange_init_code(str
, usage_mod
);
9454 Template
*t
= temp
->get_Template();
9455 if (t
->get_my_scope()->get_scope_mod_gen() == usage_mod
) {
9456 Ref_base
*dref
= temp
->get_DerivedRef();
9458 expression_struct expr
;
9459 Code::init_expr(&expr
);
9460 expr
.expr
= mputprintf(expr
.expr
, "%s = ", t
->get_lhs_name().c_str());
9461 dref
->generate_code(&expr
);
9462 str
= Code::merge_free_expr(str
, &expr
, false);
9464 str
= t
->generate_code_init(str
, t
->get_lhs_name().c_str());
9468 FATAL_ERROR("ActualPar::rearrange_init_code_defval()");
9473 void ActualPar::append_stringRepr(string
& str
) const
9475 switch (selection
) {
9477 str
+= val
->get_stringRepr();
9480 temp
->append_stringRepr(str
);
9483 str
+= ref
->get_dispname();
9489 str
+= "<erroneous actual parameter>";
9493 void ActualPar::dump(unsigned level
) const
9495 switch (selection
) {
9497 DEBUG(level
, "actual parameter: value");
9498 val
->dump(level
+ 1);
9501 DEBUG(level
, "actual parameter: template");
9502 temp
->dump(level
+ 1);
9505 DEBUG(level
, "actual parameter: referecne");
9506 ref
->dump(level
+ 1);
9509 DEBUG(level
, "actual parameter: default");
9512 DEBUG(level
, "actual parameter: erroneous");
9516 // =================================
9517 // ===== ActualParList
9518 // =================================
9520 ActualParList::ActualParList(const ActualParList
& p
)
9523 size_t nof_pars
= p
.params
.size();
9524 for (size_t i
= 0; i
< nof_pars
; i
++) params
.add(p
.params
[i
]->clone());
9527 ActualParList::~ActualParList()
9529 size_t nof_pars
= params
.size();
9530 for (size_t i
= 0; i
< nof_pars
; i
++) delete params
[i
];
9534 ActualParList
*ActualParList::clone() const
9536 return new ActualParList(*this);
9539 void ActualParList::set_fullname(const string
& p_fullname
)
9541 Node::set_fullname(p_fullname
);
9542 size_t nof_pars
= params
.size();
9543 for(size_t i
= 0; i
< nof_pars
; i
++)
9544 params
[i
]->set_fullname(p_fullname
+
9545 ".<parameter" + Int2string(i
+ 1) + ">");
9548 void ActualParList::set_my_scope(Scope
*p_scope
)
9550 size_t nof_pars
= params
.size();
9551 for (size_t i
= 0; i
< nof_pars
; i
++) params
[i
]->set_my_scope(p_scope
);
9554 void ActualParList::chk_recursions(ReferenceChain
& refch
)
9556 size_t nof_pars
= params
.size();
9557 for (size_t i
= 0; i
< nof_pars
; i
++)
9558 params
[i
]->chk_recursions(refch
);
9561 void ActualParList::generate_code_noalias(expression_struct
*expr
, FormalParList
*p_fpl
)
9563 size_t nof_pars
= params
.size();
9564 for (size_t i
= 0; i
< nof_pars
; i
++) {
9565 if (i
> 0) expr
->expr
= mputstr(expr
->expr
, ", ");
9566 params
[i
]->generate_code(expr
, false, p_fpl
&& p_fpl
->get_fp_byIndex(i
)->get_lazy_eval(), p_fpl
&& p_fpl
->get_fp_byIndex(i
)->get_used_as_lvalue());
9570 void ActualParList::generate_code_alias(expression_struct
*expr
,
9571 FormalParList
*p_fpl
, Type
*p_comptype
, bool p_compself
)
9573 size_t nof_pars
= params
.size();
9574 // collect all value and template definitions that are passed by reference
9575 map
<Common::Assignment
*, void> value_refs
, template_refs
;
9576 for (size_t i
= 0; i
< nof_pars
; i
++) {
9577 ActualPar
*par
= params
[i
];
9578 if (par
->get_selection() == ActualPar::AP_DEFAULT
)
9579 par
= par
->get_ActualPar();
9580 if (par
->get_selection() == ActualPar::AP_REF
) {
9581 Common::Assignment
*ass
= par
->get_Ref()->get_refd_assignment();
9582 switch (ass
->get_asstype()) {
9583 case Common::Assignment::A_VAR
:
9584 case Common::Assignment::A_PAR_VAL_IN
:
9585 case Common::Assignment::A_PAR_VAL_OUT
:
9586 case Common::Assignment::A_PAR_VAL_INOUT
:
9587 if (!value_refs
.has_key(ass
)) value_refs
.add(ass
, 0);
9589 case Common::Assignment::A_VAR_TEMPLATE
:
9590 case Common::Assignment::A_PAR_TEMPL_IN
:
9591 case Common::Assignment::A_PAR_TEMPL_OUT
:
9592 case Common::Assignment::A_PAR_TEMPL_INOUT
:
9593 if (!template_refs
.has_key(ass
)) template_refs
.add(ass
, 0);
9599 // walk through the parameter list and generate the code
9600 // add an extra copy constructor call to the referenced value and template
9601 // parameters if the referred definition is also passed by reference to
9602 // another parameter
9603 for (size_t i
= 0; i
< nof_pars
; i
++) {
9604 if (i
> 0) expr
->expr
= mputstr(expr
->expr
, ", ");
9605 ActualPar
*par
= params
[i
];
9606 bool copy_needed
= false;
9607 // the copy constructor call is not needed if the parameter is copied
9608 // into a shadow object in the body of the called function
9609 if (!p_fpl
|| !p_fpl
->get_fp_byIndex(i
)->get_used_as_lvalue()) {
9610 switch (par
->get_selection()) {
9611 case ActualPar::AP_VALUE
: {
9612 Value
*v
= par
->get_Value();
9613 if (v
->get_valuetype() == Value::V_REFD
) {
9614 Common::Assignment
*t_ass
=
9615 v
->get_reference()->get_refd_assignment();
9616 if (value_refs
.has_key(t_ass
)) {
9617 // a reference to the same variable is also passed to the called
9620 } else if (p_comptype
|| p_compself
) {
9621 // the called definition has a 'runs on' clause so it can access
9622 // component variables
9623 switch (t_ass
->get_asstype()) {
9624 case Common::Assignment::A_PAR_VAL_OUT
:
9625 case Common::Assignment::A_PAR_VAL_INOUT
:
9626 // the parameter may be an alias of a component variable
9629 case Common::Assignment::A_VAR
:
9630 // copy is needed if t_ass is a component variable that is
9631 // visible by the called definition
9632 if (!t_ass
->is_local()) copy_needed
= true;
9633 /** \todo component type compatibility: check whether t_ass is
9634 * visible from p_comptype (otherwise copy is not needed) */
9641 case ActualPar::AP_TEMPLATE
: {
9642 TemplateInstance
*ti
= par
->get_TemplateInstance();
9643 if (!ti
->get_DerivedRef()) {
9644 Template
*t
= ti
->get_Template();
9645 if (t
->get_templatetype() == Template::TEMPLATE_REFD
) {
9646 Common::Assignment
*t_ass
=
9647 t
->get_reference()->get_refd_assignment();
9648 if (template_refs
.has_key(t_ass
)) {
9649 // a reference to the same variable is also passed to the called
9652 } else if (p_comptype
|| p_compself
) {
9653 // the called definition has a 'runs on' clause so it can access
9654 // component variables
9655 switch (t_ass
->get_asstype()) {
9656 case Common::Assignment::A_PAR_TEMPL_OUT
:
9657 case Common::Assignment::A_PAR_TEMPL_INOUT
:
9658 // the parameter may be an alias of a component variable
9661 case Common::Assignment::A_VAR_TEMPLATE
:
9662 // copy is needed if t_ass is a component variable that is
9663 // visible by the called definition
9664 if (!t_ass
->is_local()) copy_needed
= true;
9665 /** \todo component type compatibility: check whether t_ass is
9666 * visible from p_comptype (otherwise copy is not needed) */
9678 if (use_runtime_2
&& ActualPar::AP_REF
== par
->get_selection()) {
9679 // if the parameter references an element of a record of/set of, then
9680 // the record of object needs to know, so it doesn't delete the referenced
9682 Ref_base
* ref
= par
->get_Ref();
9683 FieldOrArrayRefs
* subrefs
= ref
->get_subrefs();
9684 if (subrefs
!= NULL
) {
9685 Common::Assignment
* ass
= ref
->get_refd_assignment();
9687 for (ref_i
= 0; ref_i
< subrefs
->get_nof_refs(); ++ref_i
) {
9688 FieldOrArrayRef
* subref
= subrefs
->get_ref(ref_i
);
9689 if (FieldOrArrayRef::ARRAY_REF
== subref
->get_type()) {
9690 // set the referenced index in each array in the subrefs
9691 expression_struct array_expr
;
9692 Code::init_expr(&array_expr
);
9693 // the array object's name contains the reference, followed by
9694 // the subrefs before the current array ref
9695 array_expr
.expr
= mcopystr(LazyParamData::in_lazy() ?
9696 LazyParamData::add_ref_genname(ass
, ref
->get_my_scope()).c_str() :
9697 ass
->get_genname_from_scope(ref
->get_my_scope()).c_str());
9699 subrefs
->generate_code(&array_expr
, ass
, ref_i
);
9701 expression_struct index_expr
;
9702 Code::init_expr(&index_expr
);
9703 subrefs
->get_ref(ref_i
)->get_val()->generate_code_expr(&index_expr
);
9704 // insert any preambles the array object or the index might have
9705 if (array_expr
.preamble
!= NULL
) {
9706 expr
->preamble
= mputstr(expr
->preamble
, array_expr
.preamble
);
9707 expr
->postamble
= mputstr(expr
->postamble
, array_expr
.preamble
);
9709 if (index_expr
.preamble
!= NULL
) {
9710 expr
->preamble
= mputstr(expr
->preamble
, index_expr
.preamble
);
9711 expr
->postamble
= mputstr(expr
->postamble
, index_expr
.preamble
);
9713 // let the array object know that the index is referenced before
9714 // calling the function, and let it know that it's now longer
9715 // referenced after the function call (this is done with the help
9716 // of the RefdIndexHandler's constructor and destructor)
9717 string tmp_id
= ref
->get_my_scope()->get_scope_mod_gen()->get_temporary_id();
9718 expr
->preamble
= mputprintf(expr
->preamble
,
9719 "RefdIndexHandler %s(&%s, %s);\n",
9720 tmp_id
.c_str(), array_expr
.expr
, index_expr
.expr
);
9721 // insert any postambles the array object or the index might have
9722 if (array_expr
.postamble
!= NULL
) {
9723 expr
->preamble
= mputstr(expr
->preamble
, array_expr
.postamble
);
9724 expr
->postamble
= mputstr(expr
->postamble
, array_expr
.postamble
);
9726 if (index_expr
.postamble
!= NULL
) {
9727 expr
->preamble
= mputstr(expr
->preamble
, index_expr
.postamble
);
9728 expr
->postamble
= mputstr(expr
->postamble
, index_expr
.postamble
);
9730 Code::free_expr(&array_expr
);
9731 Code::free_expr(&index_expr
);
9732 } // if (FieldOrArrayRef::ARRAY_REF == subref->get_type())
9734 } // if (subrefs != NULL)
9735 } // if (ActualPar::AP_REF == par->get_selection())
9737 par
->generate_code(expr
, copy_needed
, p_fpl
&& p_fpl
->get_fp_byIndex(i
)->get_lazy_eval(), p_fpl
&& p_fpl
->get_fp_byIndex(i
)->get_used_as_lvalue());
9740 template_refs
.clear();
9743 char *ActualParList::rearrange_init_code(char *str
, Common::Module
* usage_mod
)
9745 for (size_t i
= 0; i
< params
.size(); i
++)
9746 str
= params
[i
]->rearrange_init_code(str
, usage_mod
);
9750 void ActualParList::dump(unsigned level
) const
9752 DEBUG(level
, "actual parameter list: %lu parameters",
9753 (unsigned long) params
.size());
9754 for (size_t i
= 0; i
< params
.size(); i
++)
9755 params
[i
]->dump(level
+ 1);