1 /******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
18 * Zalanyi, Balazs Andor
21 ******************************************************************************/
22 #include "../../common/dbgnew.hh"
23 #include "AST_ttcn3.hh"
24 #include "../Identifier.hh"
25 #include "../CompilerError.hh"
26 #include "../Setting.hh"
28 #include "../CompField.hh"
29 #include "../CompType.hh"
30 #include "../TypeCompat.hh"
31 #include "../Valuestuff.hh"
32 #include "../Value.hh"
33 #include "Ttcnstuff.hh"
34 #include "TtcnTemplate.hh"
35 #include "Templatestuff.hh"
36 #include "ArrayDimensions.hh"
39 #include "Statement.hh"
41 #include "Attributes.hh"
42 #include "PatternString.hh"
43 #include "../../common/version_internal.h"
44 #include "../CodeGenHelper.hh"
45 #include "../../common/JSON_Tokenizer.hh"
48 // implemented in coding_attrib_p.y
49 extern Ttcn::ExtensionAttributes
* parse_extattributes(
50 Ttcn::WithAttribPath
*w_attrib_path
);
52 // implemented in compiler.y
53 extern Ttcn::ErroneousAttributeSpec
* ttcn3_parse_erroneous_attr_spec_string(
54 const char* p_str
, const Common::Location
& str_loc
);
57 extern void init_coding_attrib_lex(const Ttcn::AttributeSpec
& attrib
);
58 extern int coding_attrib_parse();
59 extern void cleanup_coding_attrib_lex();
60 extern Ttcn::ExtensionAttributes
*extatrs
;
62 /** Create a field name in the anytype
64 * The output of this function will be used to create an identifier
65 * to be used as the field name in the anytype.
66 * The type_name may be a built-in type (e.g. "integer") or a user-defined
69 * If the name has multiple components (a fullname?), it keeps just the last
70 * component without any dots. *
71 * Also, the space in "universal charstring" needs to be replaced
72 * with an underscore to make it an identifier.
74 * Note: Prefixing with "AT_" is not done here, but in defUnionClass().
76 * @param type_name string
77 * @return string to be used as the identifier.
79 string
anytype_field(const string
& type_name
)
81 string
retval(type_name
);
83 // keep just the last part of the name
84 // TODO check if there's a way to get just the last component (note that fetching the string is done outside of this function)
85 size_t dot
= retval
.rfind('.');
86 if (dot
>= retval
.size()) dot
= 0;
88 retval
.replace(0, dot
, "");
93 extern Common::Modules
*modules
; // in main.cc
96 static const string
_T_("_T_");
101 using namespace Common
;
103 // =================================
104 // ===== FieldOrArrayRef
105 // =================================
107 FieldOrArrayRef::FieldOrArrayRef(const FieldOrArrayRef
& p
)
108 : Node(p
), Location(p
), ref_type(p
.ref_type
)
110 switch (p
.ref_type
) {
112 u
.id
= p
.u
.id
->clone();
115 u
.arp
= p
.u
.arp
->clone();
118 FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
122 FieldOrArrayRef::FieldOrArrayRef(Identifier
*p_id
)
123 : Node(), Location(), ref_type(FIELD_REF
)
125 if (!p_id
) FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
129 FieldOrArrayRef::FieldOrArrayRef(Value
*p_arp
)
130 : Node(), Location(), ref_type(ARRAY_REF
)
132 if (!p_arp
) FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
136 FieldOrArrayRef::~FieldOrArrayRef()
146 FATAL_ERROR("FieldOrArrayRef::~FieldOrArrayRef()");
150 FieldOrArrayRef
*FieldOrArrayRef::clone() const
152 return new FieldOrArrayRef(*this);
155 void FieldOrArrayRef::set_fullname(const string
& p_fullname
)
157 Node::set_fullname(p_fullname
);
158 if (ref_type
== ARRAY_REF
)
159 u
.arp
->set_fullname(p_fullname
+ ".<array_index>");
162 void FieldOrArrayRef::set_my_scope(Scope
*p_scope
)
164 if (ref_type
== ARRAY_REF
) u
.arp
->set_my_scope(p_scope
);
167 const Identifier
* FieldOrArrayRef::get_id() const
169 if (ref_type
!= FIELD_REF
) FATAL_ERROR("FieldOrArrayRef::get_id()");
173 Value
*FieldOrArrayRef::get_val() const
175 if (ref_type
!= ARRAY_REF
) FATAL_ERROR("FieldOrArrayRef::get_val()");
179 void FieldOrArrayRef::append_stringRepr(string
& str
) const
184 str
+= u
.id
->get_dispname();
188 str
+= u
.arp
->get_stringRepr();
192 str
+= "<unknown sub-reference>";
196 void FieldOrArrayRef::set_field_name_to_lowercase()
198 if (ref_type
!= FIELD_REF
) FATAL_ERROR("FieldOrArrayRef::set_field_name_to_lowercase()");
199 string new_name
= u
.id
->get_name();
200 if (isupper(new_name
[0])) {
201 new_name
[0] = tolower(new_name
[0]);
202 if (new_name
[new_name
.size() - 1] == '_') {
203 // an underscore is inserted at the end of the field name if it's
204 // a basic type's name (since it would conflict with the class generated
206 // remove the underscore, it won't conflict with anything if its name
207 // starts with a lowercase letter
208 new_name
.replace(new_name
.size() - 1, 1, "");
211 u
.id
= new Identifier(Identifier::ID_NAME
, new_name
);
215 // =================================
216 // ===== FieldOrArrayRefs
217 // =================================
219 FieldOrArrayRefs::FieldOrArrayRefs(const FieldOrArrayRefs
& p
)
220 : Node(p
), refs_str_element(false)
222 for (size_t i
= 0; i
< p
.refs
.size(); i
++) refs
.add(p
.refs
[i
]->clone());
225 FieldOrArrayRefs::~FieldOrArrayRefs()
227 for (size_t i
= 0; i
< refs
.size(); i
++) delete refs
[i
];
231 FieldOrArrayRefs
*FieldOrArrayRefs::clone() const
233 return new FieldOrArrayRefs(*this);
236 void FieldOrArrayRefs::set_fullname(const string
& p_fullname
)
238 Node::set_fullname(p_fullname
);
239 for (size_t i
= 0; i
< refs
.size(); i
++)
240 refs
[i
]->set_fullname(p_fullname
+
241 ".<sub_reference" + Int2string(i
+ 1) + ">");
244 void FieldOrArrayRefs::set_my_scope(Scope
*p_scope
)
246 for (size_t i
= 0; i
< refs
.size(); i
++) refs
[i
]->set_my_scope(p_scope
);
249 bool FieldOrArrayRefs::has_unfoldable_index() const
251 for (size_t i
= 0; i
< refs
.size(); i
++) {
252 FieldOrArrayRef
*ref
= refs
[i
];
253 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
) {
254 Value
*v
= ref
->get_val();
255 v
->set_lowerid_to_ref();
256 if (v
->is_unfoldable()) return true;
262 void FieldOrArrayRefs::remove_refs(size_t n
)
264 for (size_t i
= 0; i
< n
; i
++) delete refs
[i
];
265 refs
.replace(0, n
, NULL
);
266 set_fullname(get_fullname());
269 /* remove_last_field is used when unfolding references for
270 ischosen and ispresent function operands.
271 In this case it is NOT sure the last field exists.
272 Calling remove_last_field previously
273 will avoid getting the "variable...Has no member called..." error message.
274 The last field component will be checked as a separate step.
275 Warning: the removed Identifier has to be deleted later */
277 Identifier
* FieldOrArrayRefs::remove_last_field()
279 if (refs
.size() == 0) return 0;
280 size_t last_elem_ind
= refs
.size() - 1;
281 FieldOrArrayRef
* last_elem
= refs
[last_elem_ind
];
282 if (last_elem
->get_type() == FieldOrArrayRef::FIELD_REF
) {
283 Identifier
*ret_val
= last_elem
->get_id()->clone();
285 refs
.replace(last_elem_ind
, 1, NULL
);
290 void FieldOrArrayRefs::generate_code(expression_struct
*expr
,
291 Common::Assignment
*ass
, size_t nof_subrefs
/* = UINT_MAX*/)
294 bool is_template
= false;
295 switch (ass
->get_asstype()) {
296 case Common::Assignment::A_CONST
: // a Def_Const
297 case Common::Assignment::A_EXT_CONST
: // a Def_ExtConst
298 case Common::Assignment::A_MODULEPAR
: // a Def_Modulepar
299 case Common::Assignment::A_VAR
: // a Def_Var
300 case Common::Assignment::A_FUNCTION_RVAL
: // a Def_Function
301 case Common::Assignment::A_EXT_FUNCTION_RVAL
: // a Def_ExtFunction
302 case Common::Assignment::A_PAR_VAL_IN
: // a FormalPar
303 case Common::Assignment::A_PAR_VAL_OUT
: // a FormalPar
304 case Common::Assignment::A_PAR_VAL_INOUT
: // a FormalPar
305 // The type is important since the referred entities are value objects.
306 type
= ass
->get_Type();
308 case Common::Assignment::A_MODULEPAR_TEMP
: // a Def_Modulepar_Template
309 case Common::Assignment::A_TEMPLATE
: // a Def_Template
310 case Common::Assignment::A_VAR_TEMPLATE
: // a Def_Var_Template
311 case Common::Assignment::A_PAR_TEMPL_IN
: // a FormalPar
312 case Common::Assignment::A_PAR_TEMPL_OUT
: // a FormalPar
313 case Common::Assignment::A_PAR_TEMPL_INOUT
: // a FormalPar
314 // The type is semi-important because fields of anytype templates
316 type
= ass
->get_Type();
319 case Common::Assignment::A_TIMER
: // a Def_Timer
320 case Common::Assignment::A_PORT
: // a Def_Port
321 case Common::Assignment::A_FUNCTION_RTEMP
: // a Def_Function
322 case Common::Assignment::A_EXT_FUNCTION_RTEMP
: // a Def_ExtFunction
323 case Common::Assignment::A_PAR_TIMER
: // a FormalPar
324 case Common::Assignment::A_PAR_PORT
: // a FormalPar
325 // The type is not relevant (i.e. the optional fields do not require
326 // special handling).
330 // Reference to other definitions cannot occur during code generation.
331 FATAL_ERROR("FieldOrArrayRefs::generate_code()");
334 size_t n_refs
= (nof_subrefs
!= UINT_MAX
) ? nof_subrefs
: refs
.size();
335 for (size_t i
= 0; i
< n_refs
; i
++) {
336 if (type
) type
= type
->get_type_refd_last();
337 // type changes inside the loop; need to recompute "last" every time.
338 FieldOrArrayRef
*ref
= refs
[i
];
339 if (ref
->get_type() == FieldOrArrayRef::FIELD_REF
) {
340 // Write a call to the field accessor method.
341 // Fields of the anytype get a special prefix; see also:
342 // Template::generate_code_init_se, TypeConv::gen_conv_func_choice_anytype,
343 // defUnionClass and defUnionTemplate.
344 const Identifier
& id
= *ref
->get_id();
345 expr
->expr
= mputprintf(expr
->expr
, ".%s%s()",
346 ((type
!=0 && type
->get_typetype()==Type::T_ANYTYPE
) ? "AT_" : ""),
347 id
.get_name().c_str());
349 CompField
*cf
= type
->get_comp_byName(id
);
350 // If the field is optional, the return type of the accessor is an
351 // OPTIONAL<T>. Write a call to OPTIONAL<T>::operator(),
352 // which "reaches into" the OPTIONAL to get the contained type T.
353 // Don't do this at the end of the reference chain.
354 // Accessor methods for a foo_template return a bar_template
355 // and OPTIONAL<> is not involved, hence no "()".
356 if (!is_template
&& i
< n_refs
- 1 && cf
->get_is_optional())
357 expr
->expr
= mputstr(expr
->expr
, "()");
358 // Follow the field type.
359 type
= cf
->get_type();
362 // Generate code for array reference.
363 expr
->expr
= mputc(expr
->expr
, '[');
364 ref
->get_val()->generate_code_expr(expr
);
365 expr
->expr
= mputc(expr
->expr
, ']');
367 // Follow the embedded type.
368 switch (type
->get_typetype()) {
372 type
= type
->get_ofType();
375 // The index points to a string element.
376 // There are no further sub-references.
380 } // if (ref->get_type)
384 void FieldOrArrayRefs::append_stringRepr(string
& str
) const
386 for (size_t i
= 0; i
< refs
.size(); i
++) refs
[i
]->append_stringRepr(str
);
389 // =================================
391 // =================================
393 Ref_base::Ref_base(const Ref_base
& p
)
394 : Ref_simple(p
), subrefs(p
.subrefs
)
396 modid
= p
.modid
? p
.modid
->clone() : 0;
397 id
= p
.id
? p
.id
->clone() : 0;
398 params_checked
= p
.is_erroneous
;
401 Ref_base::Ref_base(Identifier
*p_modid
, Identifier
*p_id
)
402 : Ref_simple(), modid(p_modid
), id(p_id
), params_checked(false)
403 , usedInIsbound(false)
406 FATAL_ERROR("NULL parameter: Ttcn::Ref_base::Ref_base()");
409 Ref_base::~Ref_base()
415 void Ref_base::set_fullname(const string
& p_fullname
)
417 Ref_simple::set_fullname(p_fullname
);
418 subrefs
.set_fullname(p_fullname
);
421 void Ref_base::set_my_scope(Scope
*p_scope
)
423 Ref_simple::set_my_scope(p_scope
);
424 subrefs
.set_my_scope(p_scope
);
427 /* returns the referenced variable's base type or value */
428 Setting
* Ref_base::get_refd_setting()
430 Common::Assignment
*ass
= get_refd_assignment();
431 if (ass
) return ass
->get_Setting();
435 FieldOrArrayRefs
*Ref_base::get_subrefs()
437 if (!id
) get_modid();
438 if (subrefs
.get_nof_refs() == 0) return 0;
439 else return &subrefs
;
442 bool Ref_base::has_single_expr()
444 Common::Assignment
*ass
= get_refd_assignment();
445 if (!ass
) FATAL_ERROR("Ref_base::has_single_expr()");
446 for (size_t i
= 0; i
< subrefs
.get_nof_refs(); i
++) {
447 FieldOrArrayRef
*ref
= subrefs
.get_ref(i
);
448 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
&&
449 !ref
->get_val()->has_single_expr()) return false;
454 void Ref_base::set_code_section(
455 GovernedSimple::code_section_t p_code_section
)
457 for (size_t i
= 0; i
< subrefs
.get_nof_refs(); i
++) {
458 FieldOrArrayRef
*ref
= subrefs
.get_ref(i
);
459 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
)
460 ref
->get_val()->set_code_section(p_code_section
);
464 void Ref_base::generate_code_const_ref(expression_struct_t */
*expr*/
)
466 FATAL_ERROR("Ref_base::generate_code_const_ref()");
469 // =================================
471 // =================================
473 Reference::Reference(Identifier
*p_id
)
474 : Ref_base(), parlist(0)
476 subrefs
.add(new FieldOrArrayRef(p_id
));
479 Reference::~Reference()
487 * Common::PortTypeBody::PortTypeBody
489 * Common::TypeMappingTarget::TypeMappingTarget
490 * Common::PatternString::ps_elem_t::chk_ref */
491 Reference
*Reference::clone() const
493 return new Reference(*this);
496 string
Reference::get_dispname()
501 ret_val
+= modid
->get_dispname();
504 ret_val
+= id
->get_dispname();
505 subrefs
.append_stringRepr(ret_val
);
507 subrefs
.append_stringRepr(ret_val
);
508 // cut the leading dot
509 if (!ret_val
.empty() && ret_val
[0] == '.')
510 ret_val
.replace(0, 1, "");
515 Common::Assignment
* Reference::get_refd_assignment(bool check_parlist
)
517 Common::Assignment
*ass
= Ref_base::get_refd_assignment(check_parlist
);
518 // In fact calls Ref_simple::get_refd_assignment
519 if (ass
&& check_parlist
&& !params_checked
) {
520 params_checked
= true;
521 FormalParList
*fplist
= ass
->get_FormalParList();
523 if (fplist
->has_only_default_values()
524 && Common::Assignment::A_TEMPLATE
== ass
->get_asstype()) {
525 Ttcn::ParsedActualParameters params
;
526 Error_Context
cntxt(¶ms
, "In actual parameter list of %s",
527 ass
->get_description().c_str());
528 parlist
= new ActualParList();
529 is_erroneous
= fplist
->fold_named_and_chk(¶ms
, parlist
);
530 parlist
->set_fullname(get_fullname());
531 parlist
->set_my_scope(my_scope
);
533 error("Reference to parameterized definition `%s' without "
534 "actual parameter list", ass
->get_id().get_dispname().c_str());
541 const Identifier
* Reference::get_modid()
543 if (!id
) detect_modid();
547 const Identifier
* Reference::get_id()
549 if (!id
) detect_modid();
553 Type
*Reference::chk_variable_ref()
555 Common::Assignment
*t_ass
= get_refd_assignment();
556 if (!t_ass
) return 0;
557 switch (t_ass
->get_asstype()) {
558 case Common::Assignment::A_PAR_VAL_IN
:
559 t_ass
->use_as_lvalue(*this);
561 case Common::Assignment::A_VAR
:
562 case Common::Assignment::A_PAR_VAL_OUT
:
563 case Common::Assignment::A_PAR_VAL_INOUT
:
566 error("Reference to a variable or value parameter was "
567 "expected instead of %s", t_ass
->get_description().c_str());
570 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
571 Type
*ret_val
= t_ass
->get_Type()->get_field_type(t_subrefs
,
572 Type::EXPECTED_DYNAMIC_VALUE
);
573 if (ret_val
&& t_subrefs
&& t_subrefs
->refers_to_string_element()) {
574 error("Reference to a string element of type `%s' cannot be used in "
575 "this context", ret_val
->get_typename().c_str());
580 Type
*Reference::chk_comptype_ref()
582 Common::Assignment
*ass
= get_refd_assignment();
584 if (ass
->get_asstype() == Common::Assignment::A_TYPE
) {
585 Type
*t
= ass
->get_Type()->get_type_refd_last();
586 switch (t
->get_typetype()) {
590 case Type::T_COMPONENT
:
593 error("Reference `%s' does not refer to a component type",
594 get_dispname().c_str());
597 error("Reference `%s' does not refer to a type",
598 get_dispname().c_str());
604 bool Reference::has_single_expr()
606 if (!Ref_base::has_single_expr()) {
609 if (parlist
!= NULL
) {
610 for (size_t i
= 0; i
< parlist
->get_nof_pars(); i
++) {
611 if (!parlist
->get_par(i
)->has_single_expr()) {
619 void Reference::refd_param_usage_found()
621 Common::Assignment
*ass
= get_refd_assignment();
622 if (!ass
) FATAL_ERROR("Reference::refd_param_usage_found()");
623 switch (ass
->get_asstype()) {
624 case Common::Assignment::A_PAR_VAL_OUT
:
625 case Common::Assignment::A_PAR_TEMPL_OUT
:
626 case Common::Assignment::A_PAR_VAL
:
627 case Common::Assignment::A_PAR_VAL_IN
:
628 case Common::Assignment::A_PAR_VAL_INOUT
:
629 case Common::Assignment::A_PAR_TEMPL_IN
:
630 case Common::Assignment::A_PAR_TEMPL_INOUT
:
631 case Common::Assignment::A_PAR_PORT
:
632 case Common::Assignment::A_PAR_TIMER
: {
633 FormalPar
*fpar
= dynamic_cast<FormalPar
*>(ass
);
634 if (!fpar
) FATAL_ERROR("Reference::refd_param_usage_found()");
635 fpar
->set_usage_found();
642 void Reference::generate_code(expression_struct_t
*expr
)
644 refd_param_usage_found();
645 Common::Assignment
*ass
= get_refd_assignment();
646 if (!ass
) FATAL_ERROR("Reference::generate_code()");
648 // reference without parameters to a template that has only default formal parameters.
649 // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
650 expr
->expr
= mputprintf(expr
->expr
, "%s(",
651 ass
->get_genname_from_scope(my_scope
).c_str());
652 parlist
->generate_code_alias(expr
, ass
->get_FormalParList(),
653 ass
->get_RunsOnType(), false);
654 expr
->expr
= mputc(expr
->expr
, ')');
656 expr
->expr
= mputstr(expr
->expr
,
657 LazyParamData::in_lazy() ?
658 LazyParamData::add_ref_genname(ass
, my_scope
).c_str() :
659 ass
->get_genname_from_scope(my_scope
).c_str());
661 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
664 void Reference::generate_code_const_ref(expression_struct_t
*expr
)
666 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
667 if (!t_subrefs
|| t_subrefs
->get_nof_refs() == 0) {
672 refd_param_usage_found();
673 Common::Assignment
*ass
= get_refd_assignment();
674 if (!ass
) FATAL_ERROR("Reference::generate_code_const_ref()");
677 switch (ass
->get_asstype()) {
678 case Common::Assignment::A_MODULEPAR
:
679 case Common::Assignment::A_VAR
:
680 case Common::Assignment::A_FUNCTION_RVAL
:
681 case Common::Assignment::A_EXT_FUNCTION_RVAL
:
682 case Common::Assignment::A_PAR_VAL_IN
:
683 case Common::Assignment::A_PAR_VAL_OUT
:
684 case Common::Assignment::A_PAR_VAL_INOUT
: {
687 case Common::Assignment::A_MODULEPAR_TEMP
:
688 case Common::Assignment::A_TEMPLATE
:
689 case Common::Assignment::A_VAR_TEMPLATE
:
690 case Common::Assignment::A_PAR_TEMPL_IN
:
691 case Common::Assignment::A_PAR_TEMPL_OUT
:
692 case Common::Assignment::A_PAR_TEMPL_INOUT
: {
695 case Common::Assignment::A_CONST
:
696 case Common::Assignment::A_EXT_CONST
:
702 Type
*refd_gov
= ass
->get_Type();
704 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
705 refd_gov
->get_genname_template(get_my_scope()).c_str() );
707 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
708 refd_gov
->get_genname_value(get_my_scope()).c_str());
711 // reference without parameters to a template that has only default formal parameters.
712 // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
713 expr
->expr
= mputprintf(expr
->expr
, "%s(",
714 ass
->get_genname_from_scope(my_scope
).c_str());
715 parlist
->generate_code_alias(expr
, ass
->get_FormalParList(),
716 ass
->get_RunsOnType(), false);
717 expr
->expr
= mputc(expr
->expr
, ')');
719 expr
->expr
= mputstr(expr
->expr
,
720 LazyParamData::in_lazy() ?
721 LazyParamData::add_ref_genname(ass
, my_scope
).c_str() :
722 ass
->get_genname_from_scope(my_scope
).c_str());
724 expr
->expr
= mputstr(expr
->expr
, ")");
726 if (t_subrefs
&& t_subrefs
->get_nof_refs() > 0)
727 t_subrefs
->generate_code(expr
, ass
);
730 void Reference::generate_code_portref(expression_struct_t
*expr
,
733 refd_param_usage_found();
734 Common::Assignment
*ass
= get_refd_assignment();
735 if (!ass
) FATAL_ERROR("Reference::generate_code_portref()");
736 expr
->expr
= mputstr(expr
->expr
,
737 ass
->get_genname_from_scope(p_scope
).c_str());
738 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
742 void Reference::generate_code_ispresentbound(expression_struct_t
*expr
,
743 bool is_template
, const bool isbound
)
745 refd_param_usage_found();
746 Common::Assignment
*ass
= get_refd_assignment();
747 const string
& ass_id
= ass
->get_genname_from_scope(my_scope
);
748 const char *ass_id_str
= ass_id
.c_str();
750 if (subrefs
.get_nof_refs() > 0) {
751 const string
& tmp_generalid
= my_scope
->get_scope_mod_gen()
752 ->get_temporary_id();
753 const char *tmp_generalid_str
= tmp_generalid
.c_str();
755 expression_struct isbound_expr
;
756 Code::init_expr(&isbound_expr
);
757 isbound_expr
.preamble
= mputprintf(isbound_expr
.preamble
,
758 "boolean %s = %s.is_bound();\n", tmp_generalid_str
,
760 ass
->get_Type()->generate_code_ispresentbound(&isbound_expr
, &subrefs
, my_scope
->get_scope_mod_gen(),
761 tmp_generalid
, ass_id
, is_template
, isbound
);
763 expr
->preamble
= mputstr(expr
->preamble
, isbound_expr
.preamble
);
764 expr
->preamble
= mputstr(expr
->preamble
, isbound_expr
.expr
);
765 Code::free_expr(&isbound_expr
);
767 expr
->expr
= mputprintf(expr
->expr
, "%s", tmp_generalid_str
);
769 expr
->expr
= mputprintf(expr
->expr
, "%s.%s(%s)", ass_id_str
,
770 isbound
? "is_bound":"is_present",
771 (!isbound
&& is_template
&& omit_in_value_list
) ? "TRUE" : "");
775 void Reference::detect_modid()
777 // do nothing if detection is already performed
779 // the first element of subrefs must be an <id>
780 const Identifier
*first_id
= subrefs
.get_ref(0)->get_id(), *second_id
= 0;
781 if (subrefs
.get_nof_refs() > 1) {
782 FieldOrArrayRef
*second_ref
= subrefs
.get_ref(1);
783 if (second_ref
->get_type() == FieldOrArrayRef::FIELD_REF
) {
784 // the reference begins with <id>.<id> (most complicated case)
785 // there are 3 possible situations:
786 // 1. first_id points to a local definition (this has the priority)
787 // modid: 0, id: first_id
788 // 2. first_id points to an imported module (trivial case)
789 // modid: first_id, id: second_id
790 // 3. none of the above (first_id might be an imported symbol)
791 // modid: 0, id: first_id
792 // Note: Rule 1 has the priority because it can be overridden using
793 // the notation <id>.objid { ... }.<id> (modid and id are set in the
794 // constructor), but there is no work-around in the reverse way.
795 if (!my_scope
->has_ass_withId(*first_id
)
796 && my_scope
->is_valid_moduleid(*first_id
)) {
797 // rule 1 is not fulfilled, but rule 2 is fulfilled
798 second_id
= second_ref
->get_id();
800 } // else: the reference begins with <id>[<arrayref>] -> there is no modid
801 } // else: the reference consists of a single <id> -> there is no modid
803 modid
= first_id
->clone();
804 id
= second_id
->clone();
805 subrefs
.remove_refs(2);
808 id
= first_id
->clone();
809 subrefs
.remove_refs(1);
813 // =================================
815 // =================================
817 Ref_pard::Ref_pard(const Ref_pard
& p
)
818 : Ref_base(p
), parlist(p
.parlist
), expr_cache(0)
820 params
= p
.params
? p
.params
->clone() : 0;
823 Ref_pard::Ref_pard(Identifier
*p_modid
, Identifier
*p_id
,
824 ParsedActualParameters
*p_params
)
825 : Ref_base(p_modid
, p_id
), parlist(), params(p_params
), expr_cache(0)
828 FATAL_ERROR("Ttcn::Ref_pard::Ref_pard(): NULL parameter");
831 Ref_pard::~Ref_pard()
837 Ref_pard
*Ref_pard::clone() const
839 return new Ref_pard(*this);
842 void Ref_pard::set_fullname(const string
& p_fullname
)
844 Ref_base::set_fullname(p_fullname
);
845 parlist
.set_fullname(p_fullname
);
846 if (params
) params
->set_fullname(p_fullname
);
849 void Ref_pard::set_my_scope(Scope
*p_scope
)
851 Ref_base::set_my_scope(p_scope
);
852 parlist
.set_my_scope(p_scope
);
853 if (params
) params
->set_my_scope(p_scope
);
856 string
Ref_pard::get_dispname()
858 if (is_erroneous
) return string("erroneous");
861 ret_val
+= modid
->get_dispname();
864 ret_val
+= id
->get_dispname();
866 if (params_checked
) {
867 // used after semantic analysis
868 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++) {
869 if (i
> 0) ret_val
+= ", ";
870 parlist
.get_par(i
)->append_stringRepr(ret_val
);
873 // used before semantic analysis
874 for (size_t i
= 0; i
< params
->get_nof_tis(); i
++) {
875 if (i
> 0) ret_val
+= ", ";
876 params
->get_ti_byIndex(i
)->append_stringRepr(ret_val
);
880 subrefs
.append_stringRepr(ret_val
);
884 Common::Assignment
* Ref_pard::get_refd_assignment(bool check_parlist
)
886 Common::Assignment
*ass
= Ref_base::get_refd_assignment(check_parlist
);
887 if (ass
&& check_parlist
&& !params_checked
) {
888 params_checked
= true;
889 FormalParList
*fplist
= ass
->get_FormalParList();
891 Error_Context
cntxt(params
, "In actual parameter list of %s",
892 ass
->get_description().c_str());
893 is_erroneous
= fplist
->fold_named_and_chk(params
, &parlist
);
894 parlist
.set_fullname(get_fullname());
895 parlist
.set_my_scope(my_scope
);
896 // the parsed parameter list is no longer needed
900 params
->error("The referenced %s cannot have actual parameters",
901 ass
->get_description().c_str());
907 const Identifier
* Ref_pard::get_modid()
912 const Identifier
* Ref_pard::get_id()
917 ActualParList
*Ref_pard::get_parlist()
919 if (!params_checked
) FATAL_ERROR("Ref_pard::get_parlist()");
923 bool Ref_pard::chk_activate_argument()
925 Common::Assignment
*t_ass
= get_refd_assignment();
926 if (!t_ass
) return false;
927 if (t_ass
->get_asstype() != Common::Assignment::A_ALTSTEP
) {
928 error("Reference to an altstep was expected in the argument instead of "
929 "%s", t_ass
->get_description().c_str());
932 my_scope
->chk_runs_on_clause(t_ass
, *this, "activate");
933 // the altstep reference cannot have sub-references
934 if (get_subrefs()) FATAL_ERROR("Ref_pard::chk_activate_argument()");
935 FormalParList
*fp_list
= t_ass
->get_FormalParList();
936 // the altstep must have formal parameter list
937 if (!fp_list
) FATAL_ERROR("Ref_pard::chk_activate_argument()");
938 return fp_list
->chk_activate_argument(&parlist
,
939 t_ass
->get_description().c_str());
942 bool Ref_pard::has_single_expr()
944 if (!Ref_base::has_single_expr()) return false;
945 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++)
946 if (!parlist
.get_par(i
)->has_single_expr()) return false;
947 // if any formal parameter has lazy evaluation
948 Common::Assignment
*ass
= get_refd_assignment();
950 const FormalParList
*fplist
= ass
->get_FormalParList();
952 size_t num_formal
= fplist
->get_nof_fps();
953 for (size_t i
=0; i
<num_formal
; ++i
) {
954 const FormalPar
*fp
= fplist
->get_fp_byIndex(i
);
955 if (fp
->get_lazy_eval()) return false;
962 void Ref_pard::set_code_section(
963 GovernedSimple::code_section_t p_code_section
)
965 Ref_base::set_code_section(p_code_section
);
966 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++)
967 parlist
.get_par(i
)->set_code_section(p_code_section
);
970 void Ref_pard::generate_code(expression_struct_t
*expr
)
972 Common::Assignment
*ass
= get_refd_assignment();
973 // C++ function reference with actual parameter list
974 expr
->expr
= mputprintf(expr
->expr
, "%s(",
975 ass
->get_genname_from_scope(my_scope
).c_str());
976 parlist
.generate_code_alias(expr
, ass
->get_FormalParList(),
977 ass
->get_RunsOnType(),false);
978 expr
->expr
= mputc(expr
->expr
, ')');
980 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
983 void Ref_pard::generate_code_cached(expression_struct_t
*expr
)
986 expr
->expr
= mputstr(expr
->expr
, expr_cache
);
990 expr_cache
= mputstr(expr_cache
, expr
->expr
);
994 void Ref_pard::generate_code_const_ref(expression_struct_t
*expr
)
996 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
997 if (!t_subrefs
|| t_subrefs
->get_nof_refs() == 0) {
1002 Common::Assignment
*ass
= get_refd_assignment();
1003 if (!ass
) FATAL_ERROR("Ref_pard::generate_code_const_ref()");
1006 switch (ass
->get_asstype()) {
1007 case Common::Assignment::A_TEMPLATE
:
1008 if (NULL
== ass
->get_FormalParList()) {
1009 // not a parameterized template
1013 // else fall through
1014 case Common::Assignment::A_CONST
:
1015 case Common::Assignment::A_EXT_CONST
:
1016 case Common::Assignment::A_ALTSTEP
:
1017 case Common::Assignment::A_TESTCASE
:
1018 case Common::Assignment::A_FUNCTION
:
1019 case Common::Assignment::A_EXT_FUNCTION
:
1020 case Common::Assignment::A_FUNCTION_RVAL
:
1021 case Common::Assignment::A_EXT_FUNCTION_RVAL
:
1022 case Common::Assignment::A_FUNCTION_RTEMP
:
1023 case Common::Assignment::A_EXT_FUNCTION_RTEMP
:
1024 generate_code(expr
);
1026 case Common::Assignment::A_MODULEPAR
:
1027 case Common::Assignment::A_VAR
:
1028 case Common::Assignment::A_PAR_VAL_IN
:
1029 case Common::Assignment::A_PAR_VAL_OUT
:
1030 case Common::Assignment::A_PAR_VAL_INOUT
: {
1031 is_template
= false;
1033 case Common::Assignment::A_MODULEPAR_TEMP
:
1034 case Common::Assignment::A_VAR_TEMPLATE
:
1035 case Common::Assignment::A_PAR_TEMPL_IN
:
1036 case Common::Assignment::A_PAR_TEMPL_OUT
:
1037 case Common::Assignment::A_PAR_TEMPL_INOUT
: {
1041 is_template
= false;
1045 Type
*refd_gov
= ass
->get_Type();
1047 generate_code(expr
);
1052 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
1053 refd_gov
->get_genname_template(get_my_scope()).c_str() );
1055 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s%s&>(",
1056 refd_gov
->get_genname_value(get_my_scope()).c_str(),
1057 is_template
? "_template":"");
1060 expr
->expr
= mputprintf(expr
->expr
, "%s(",
1061 ass
->get_genname_from_scope(my_scope
).c_str());
1062 parlist
.generate_code_alias(expr
, ass
->get_FormalParList(),
1063 ass
->get_RunsOnType(), false);
1064 expr
->expr
= mputstr(expr
->expr
, "))");
1066 t_subrefs
->generate_code(expr
, ass
);
1069 // =================================
1070 // ===== NameBridgingScope
1071 // =================================
1072 string
NameBridgingScope::get_scopeMacro_name() const
1074 if (scopeMacro_name
.empty()) FATAL_ERROR("NameBridgingScope::get_scopeMacro_name()");
1075 return scopeMacro_name
;
1078 NameBridgingScope
*NameBridgingScope::clone() const
1080 FATAL_ERROR("NameBridgingScope::clone");
1083 Common::Assignment
* NameBridgingScope::get_ass_bySRef(Ref_simple
*p_ref
)
1085 return get_parent_scope()->get_ass_bySRef(p_ref
);
1088 // =================================
1089 // ===== RunsOnScope
1090 // =================================
1092 RunsOnScope::RunsOnScope(Type
*p_comptype
)
1093 : Scope(), component_type(p_comptype
)
1095 if (!p_comptype
|| p_comptype
->get_typetype() != Type::T_COMPONENT
)
1096 FATAL_ERROR("RunsOnScope::RunsOnScope()");
1097 component_type
->set_ownertype(Type::OT_RUNSON_SCOPE
, this);
1098 component_defs
= p_comptype
->get_CompBody();
1099 set_scope_name("runs on `" + p_comptype
->get_fullname() + "'");
1102 RunsOnScope
*RunsOnScope::clone() const
1104 FATAL_ERROR("RunsOnScope::clone()");
1107 void RunsOnScope::chk_uniq()
1109 // do not perform this check if the component type is defined in the same
1110 // module as the 'runs on' clause
1111 if (parent_scope
->get_scope_mod() == component_defs
->get_scope_mod())
1113 size_t nof_defs
= component_defs
->get_nof_asss();
1114 for (size_t i
= 0; i
< nof_defs
; i
++) {
1115 Common::Assignment
*comp_def
= component_defs
->get_ass_byIndex(i
);
1116 const Identifier
& id
= comp_def
->get_id();
1117 if (parent_scope
->has_ass_withId(id
)) {
1118 comp_def
->warning("Imported component element definition `%s' hides a "
1119 "definition at module scope", comp_def
->get_fullname().c_str());
1120 Reference
ref(0, id
.clone());
1121 Common::Assignment
*hidden_ass
= parent_scope
->get_ass_bySRef(&ref
);
1122 hidden_ass
->warning("Hidden definition `%s' is here",
1123 hidden_ass
->get_fullname().c_str());
1129 RunsOnScope
*RunsOnScope::get_scope_runs_on()
1134 Common::Assignment
*RunsOnScope::get_ass_bySRef(Ref_simple
*p_ref
)
1136 if (!p_ref
) FATAL_ERROR("Ttcn::RunsOnScope::get_ass_bySRef()");
1137 if (p_ref
->get_modid()) return parent_scope
->get_ass_bySRef(p_ref
);
1139 const Identifier
& id
= *p_ref
->get_id();
1140 if (component_defs
->has_local_ass_withId(id
)) {
1141 Common::Assignment
* ass
= component_defs
->get_local_ass_byId(id
);
1142 if (!ass
) FATAL_ERROR("Ttcn::RunsOnScope::get_ass_bySRef()");
1144 if (component_defs
->is_own_assignment(ass
)) return ass
;
1145 else if (ass
->get_visibility() == PUBLIC
) {
1149 p_ref
->error("The member definition `%s' in component type `%s'"
1150 " is not visible in this scope", id
.get_dispname().c_str(),
1151 component_defs
->get_id()->get_dispname().c_str());
1153 } else return parent_scope
->get_ass_bySRef(p_ref
);
1157 bool RunsOnScope::has_ass_withId(const Identifier
& p_id
)
1159 return component_defs
->has_ass_withId(p_id
)
1160 || parent_scope
->has_ass_withId(p_id
);
1163 // =================================
1165 // =================================
1167 FriendMod::FriendMod(Identifier
*p_modid
)
1168 : Node(), modid(p_modid
), w_attrib_path(0), parentgroup(0), checked(false)
1170 if (!p_modid
) FATAL_ERROR("NULL parameter: Ttcn::FriendMod::FriendMod()");
1171 set_fullname("<friends>."+modid
->get_dispname());
1174 FriendMod::~FriendMod()
1178 delete w_attrib_path
;
1181 FriendMod
*FriendMod::clone() const
1183 FATAL_ERROR("Ttcn::FriendMod::clone()");
1186 void FriendMod::set_fullname(const string
& p_fullname
)
1188 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
1191 void FriendMod::chk()
1193 if (checked
) return;
1195 Error_Context
cntxt(this, "In friend module declaration");
1197 if (w_attrib_path
) {
1198 w_attrib_path
->chk_global_attrib();
1199 w_attrib_path
->chk_no_qualif();
1205 void FriendMod::set_with_attr(MultiWithAttrib
* p_attrib
)
1207 if (w_attrib_path
) FATAL_ERROR("FriendMod::set_with_attr()");
1208 w_attrib_path
= new WithAttribPath();
1209 if (p_attrib
&& p_attrib
->get_nof_elements() > 0) {
1210 w_attrib_path
->set_with_attr(p_attrib
);
1214 WithAttribPath
* FriendMod::get_attrib_path()
1216 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1217 return w_attrib_path
;
1220 void FriendMod::set_parent_path(WithAttribPath
* p_path
)
1222 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1223 w_attrib_path
->set_parent(p_path
);
1226 void FriendMod::set_parent_group(Group
* p_group
)
1228 if(parentgroup
) FATAL_ERROR("FriendMod::set_parent_group");
1229 parentgroup
= p_group
;
1232 // =================================
1234 // =================================
1236 ImpMod::ImpMod(Identifier
*p_modid
)
1237 : Node(), mod(0), my_mod(0), imptype(I_UNDEF
), modid(p_modid
),
1238 language_spec(0), is_recursive(false),
1239 w_attrib_path(0), parentgroup(0), visibility(PRIVATE
)
1241 if (!p_modid
) FATAL_ERROR("NULL parameter: Ttcn::ImpMod::ImpMod()");
1242 set_fullname("<imports>." + modid
->get_dispname());
1248 delete language_spec
;
1250 delete w_attrib_path
;
1253 ImpMod
*ImpMod::clone() const
1255 FATAL_ERROR("No clone for you!");
1258 void ImpMod::set_fullname(const string
& p_fullname
)
1260 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
1265 if (w_attrib_path
) {
1266 w_attrib_path
->chk_global_attrib();
1267 w_attrib_path
->chk_no_qualif();
1271 void ImpMod::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
1273 Error_Context
cntxt(this, "In import definition");
1275 if (!modules
->has_mod_withId(*modid
)) {
1276 error("There is no module with identifier `%s'",
1277 modid
->get_dispname().c_str());
1281 Common::Module
*m
= modules
->get_mod_byId(*modid
);
1287 error("A module cannot import from itself");
1295 if (refch
.exists(my_mod
->get_fullname())) {
1296 if(my_mod
->get_moduletype()!=Common::Module::MOD_ASN
){ // Do not warning for circular import in ASN.1 module. It is legal
1297 my_mod
->warning("Circular import chain is not recommended: %s",
1298 refch
.get_dispstr(my_mod
->get_fullname()).c_str());
1303 refch
.add(my_mod
->get_fullname());
1305 if (ImpMod::I_IMPORTIMPORT
== imptype
){
1306 Ttcn::Module
* ttcnmodule
=static_cast<Ttcn::Module
*>(m
);
1307 const Imports
& imp
= ttcnmodule
->get_imports();
1309 for (size_t t
= 0; t
< imp
.impmods_v
.size(); t
++) {
1310 const ImpMod
*im
= imp
.impmods_v
[t
];
1311 const Identifier
& im_id
= im
->get_modid();
1312 Common::Module
*cm
= modules
->get_mod_byId(im_id
); // never NULL
1315 if (PRIVATE
!= im
->get_visibility()) {
1316 if (refch
.exists(m
->get_fullname())) {
1317 if(m
->get_moduletype()!=Common::Module::MOD_ASN
){ // Do not warning for circular import in ASN.1 module. It is legal
1318 m
->warning("Circular import chain is not recommended: %s",
1319 refch
.get_dispstr(m
->get_fullname()).c_str());
1324 refch
.add(m
->get_fullname());
1325 cm
->chk_imp(refch
, moduleStack
);
1331 //refch.mark_state();
1332 m
->chk_imp(refch
, moduleStack
);
1333 //refch.prev_state();
1338 size_t state
=moduleStack
.size();
1339 moduleStack
.replace(state
, moduleStack
.size() - state
);
1342 bool ImpMod::has_imported_def(const Identifier
& p_source_modid
,
1343 const Identifier
& p_id
, const Location
*loc
) const
1345 if (!mod
) return false;
1351 Common::Assignment
* return_assignment
= mod
->importAssignment(p_source_modid
, p_id
);
1352 if (return_assignment
!= NULL
) {
1359 case I_IMPORTIMPORT
:
1361 Ttcn::Module
*tm
= static_cast<Ttcn::Module
*>(mod
); // B
1363 const Imports
& imps
= tm
->get_imports();
1365 vector
<ImpMod
> tempusedImpMods
;
1366 for (size_t i
= 0, num
= imps
.impmods_v
.size(); i
< num
; ++i
) {
1367 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
1368 Common::Assignment
* return_assignment
= imps
.impmods_v
[i
]->
1369 get_imported_def(p_source_modid
, p_id
, loc
, referencechain
, tempusedImpMods
); // C
1370 referencechain
->reset();
1371 delete referencechain
;
1373 if (return_assignment
!= NULL
) {
1379 //satisfy destructor
1380 tempusedImpMods
.clear();
1385 FATAL_ERROR("ImpMod::get_imported_def");
1391 Common::Assignment
*ImpMod::get_imported_def(
1392 const Identifier
& p_source_modid
, const Identifier
& p_id
,
1393 const Location
*loc
, ReferenceChain
* refch
,
1394 vector
<ImpMod
>& usedImpMods
) const
1399 Common::Assignment
* result
= NULL
;
1404 result
= mod
->importAssignment(p_source_modid
, p_id
);
1405 if (result
!= NULL
) {
1406 usedImpMods
.add(const_cast<Ttcn::ImpMod
*>(this));
1410 case I_IMPORTIMPORT
:
1412 Ttcn::Module
*tm
= static_cast<Ttcn::Module
*>(mod
);
1414 const Imports
& imps
= tm
->get_imports();
1415 Common::Assignment
* t_ass
= NULL
;
1417 for (size_t i
= 0, num
= imps
.impmods_v
.size(); i
< num
; ++i
) {
1418 vector
<ImpMod
> tempusedImpMods
;
1420 refch
->mark_state();
1421 if (imps
.impmods_v
[i
]->get_visibility() == PUBLIC
) {
1422 t_ass
= imps
.impmods_v
[i
]->get_imported_def(p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1424 else if (imps
.impmods_v
[i
]->get_visibility() == FRIEND
) {
1425 t_ass
= imps
.impmods_v
[i
]->get_imported_def(p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1427 tempusedImpMods
.add(imps
.impmods_v
[i
]);
1430 refch
->prev_state();
1432 if (t_ass
!= NULL
) {
1433 bool visible
= true;
1434 for (size_t j
= 0; j
< tempusedImpMods
.size(); j
++) {
1435 ImpMod
* impmod_l
= tempusedImpMods
[j
];
1436 //check whether the module is TTCN
1437 if (impmod_l
->get_mod()->get_moduletype() == Common::Module::MOD_TTCN
) {
1438 // cast to ttcn module
1439 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(impmod_l
->get_mod());
1440 if (!ttcn_m
->is_visible(mod
->get_modid(), impmod_l
->get_visibility())) {
1446 for (size_t t
= 0; i
< tempusedImpMods
.size(); i
++) {
1447 usedImpMods
.add(tempusedImpMods
[t
]);
1452 } else if(result
!= t_ass
) {
1457 "It is not possible to resolve the reference unambiguously"
1458 ", as it can be resolved to `%s' and to `%s'",
1459 result
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
1465 tempusedImpMods
.clear();
1468 if (result
!= NULL
) {
1469 usedImpMods
.add(const_cast<Ttcn::ImpMod
*>(this));
1475 FATAL_ERROR("ImpMod::get_imported_def");
1480 void ImpMod::set_language_spec(const char *p_language_spec
)
1482 if (language_spec
) FATAL_ERROR("ImpMod::set_language_spec()");
1483 if (p_language_spec
) language_spec
= new string(p_language_spec
);
1486 void ImpMod::generate_code(output_struct
*target
)
1488 const char *module_name
= modid
->get_name().c_str();
1490 target
->header
.includes
= mputprintf(target
->header
.includes
,
1491 "#include \"%s.hh\"\n",
1492 duplicate_underscores
? module_name
: modid
->get_ttcnname().c_str());
1494 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
1495 "%s%s.pre_init_module();\n", module_name
,
1498 if (mod
->get_moduletype() == Common::Module::MOD_TTCN
) {
1499 target
->functions
.post_init
= mputprintf(target
->functions
.post_init
,
1500 "%s%s.post_init_module();\n", module_name
,
1506 void ImpMod::dump(unsigned level
) const
1508 DEBUG(level
, "Import from module %s", modid
->get_dispname().c_str());
1509 if (w_attrib_path
) {
1510 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
1512 DEBUG(level
+ 1, "Attributes:");
1513 attrib
->dump(level
+ 2);
1518 void ImpMod::set_with_attr(MultiWithAttrib
* p_attrib
)
1520 if (w_attrib_path
) FATAL_ERROR("ImpMod::set_with_attr()");
1521 w_attrib_path
= new WithAttribPath();
1522 if (p_attrib
&& p_attrib
->get_nof_elements() > 0) {
1523 w_attrib_path
->set_with_attr(p_attrib
);
1527 WithAttribPath
* ImpMod::get_attrib_path()
1529 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1530 return w_attrib_path
;
1533 void ImpMod::set_parent_path(WithAttribPath
* p_path
)
1535 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1536 w_attrib_path
->set_parent(p_path
);
1539 void ImpMod::set_parent_group(Group
* p_group
)
1541 if(parentgroup
) FATAL_ERROR("ImpMod::set_parent_group");
1542 parentgroup
= p_group
;
1545 // =================================
1547 // =================================
1551 for (size_t i
= 0; i
< impmods_v
.size(); i
++)
1552 delete impmods_v
[i
];
1556 Imports
*Imports::clone() const
1558 FATAL_ERROR("Ttcn::Imports::clone()");
1561 void Imports::add_impmod(ImpMod
*p_impmod
)
1563 if (!p_impmod
) FATAL_ERROR("Ttcn::Imports::add_impmod()");
1564 impmods_v
.add(p_impmod
);
1565 p_impmod
->set_my_mod(my_mod
);
1568 void Imports::set_my_mod(Module
*p_mod
)
1571 for(size_t i
= 0; i
< impmods_v
.size(); i
++)
1572 impmods_v
[i
]->set_my_mod(my_mod
);
1575 bool Imports::has_impmod_withId(const Identifier
& p_id
) const
1577 for (size_t i
= 0, size
= impmods_v
.size(); i
< size
; ++i
) {
1578 const ImpMod
* im
= impmods_v
[i
];
1579 const Identifier
& im_id
= im
->get_modid();
1580 const string
& im_name
= im_id
.get_name();
1581 if (p_id
.get_name() == im_name
) {
1582 // The identifier represents a module imported in the current module
1589 void Imports::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
1591 if (impmods_v
.size() <= 0) return;
1593 if (!my_mod
) FATAL_ERROR("Ttcn::Imports::chk_imp()");
1598 for(size_t n
= 0; n
< impmods_v
.size(); n
++)
1600 impmods_v
[n
]->chk();
1603 //TODO this whole thing should be moved into impmod::chk
1604 Identifier
address_id(Identifier::ID_TTCN
, string("address"));
1605 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1606 ImpMod
*im
= impmods_v
[n
];
1607 im
->chk_imp(refch
, moduleStack
);
1609 const Identifier
& im_id
= im
->get_modid();
1610 Common::Module
*m
= modules
->get_mod_byId(im_id
);
1613 if (m
->get_gen_code()) my_mod
->set_gen_code();
1614 } // next assignment
1617 bool Imports::has_imported_def(const Identifier
& p_id
, const Location
*loc
) const
1619 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1620 ImpMod
*im
= impmods_v
[n
];
1621 bool return_bool
= im
->has_imported_def(my_mod
->get_modid(), p_id
, loc
);
1622 if (return_bool
) return true;
1627 Common::Assignment
*Imports::get_imported_def(
1628 const Identifier
& p_source_modid
, const Identifier
& p_id
,
1629 const Location
*loc
, ReferenceChain
* refch
)
1631 vector
<ImpMod
> tempusedImpMods
;
1632 Common::Assignment
* result
= NULL
;
1633 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1634 ImpMod
*im
= impmods_v
[n
];
1635 refch
->mark_state();
1636 Common::Assignment
* ass
= im
->get_imported_def(
1637 p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1638 tempusedImpMods
.clear();
1639 refch
->prev_state();
1644 } else if(result
!= ass
&& loc
) {
1649 "It is not possible to resolve the reference unambiguously"
1650 ", as it can be resolved to `%s' and to `%s'",
1651 result
->get_fullname().c_str(), ass
->get_fullname().c_str());
1659 void Imports::get_imported_mods(Module::module_set_t
& p_imported_mods
) const
1661 for (size_t i
= 0; i
< impmods_v
.size(); i
++) {
1662 ImpMod
*im
= impmods_v
[i
];
1663 Common::Module
*m
= im
->get_mod();
1665 if (!p_imported_mods
.has_key(m
)) {
1666 p_imported_mods
.add(m
, 0);
1667 m
->get_visible_mods(p_imported_mods
);
1672 void Imports::generate_code(output_struct
*target
)
1674 target
->header
.includes
= mputstr(target
->header
.includes
,
1675 "#include <TTCN3.hh>\n");
1676 for (size_t i
= 0; i
< impmods_v
.size(); i
++) {
1677 ImpMod
*im
= impmods_v
[i
];
1678 Common::Module
*m
= im
->get_mod();
1679 // inclusion of m's header file can be eliminated if we find another
1680 // imported module that imports m
1681 bool covered
= false;
1682 for (size_t j
= 0; j
< impmods_v
.size(); j
++) {
1683 // skip over the same import definition
1684 if (j
== i
) continue;
1685 ImpMod
*im2
= impmods_v
[j
];
1686 Common::Module
*m2
= im2
->get_mod();
1687 // a module that is equivalent to the current module due to
1688 // circular imports cannot be used to cover anything
1689 if (m2
->is_visible(my_mod
)) continue;
1690 if (m2
->is_visible(m
) && !m
->is_visible(m2
)) {
1691 // m2 covers m (i.e. m is visible from m2)
1692 // and they are not in the same import loop
1697 // do not generate the #include if a covering module is found
1698 if (!covered
) im
->generate_code(target
);
1702 void Imports::generate_code(CodeGenHelper
& cgh
) {
1703 generate_code(cgh
.get_current_outputstruct());
1706 void Imports::dump(unsigned level
) const
1708 DEBUG(level
, "Imports (%lu pcs.)", (unsigned long) impmods_v
.size());
1709 for (size_t i
= 0; i
< impmods_v
.size(); i
++)
1710 impmods_v
[i
]->dump(level
+ 1);
1713 // =================================
1714 // ===== Definitions
1715 // =================================
1717 Definitions::~Definitions()
1719 for(size_t i
= 0; i
< ass_v
.size(); i
++) delete ass_v
[i
];
1724 Definitions
*Definitions::clone() const
1726 FATAL_ERROR("Definitions::clone");
1729 void Definitions::add_ass(Definition
*p_ass
)
1731 // it is too late to add a new one after it has been checked.
1732 if (checked
|| !p_ass
) FATAL_ERROR("Ttcn::OtherDefinitions::add_ass()");
1734 p_ass
->set_my_scope(this);
1737 void Definitions::set_fullname(const string
& p_fullname
)
1739 Common::Assignments::set_fullname(p_fullname
);
1740 for(size_t i
= 0; i
< ass_v
.size(); i
++) {
1741 Definition
*ass
= ass_v
[i
];
1742 ass
->set_fullname(p_fullname
+ "." + ass
->get_id().get_dispname());
1746 bool Definitions::has_local_ass_withId(const Identifier
& p_id
)
1748 if (!checked
) chk_uniq();
1749 return ass_m
.has_key(p_id
.get_name());
1752 Common::Assignment
* Definitions::get_local_ass_byId(const Identifier
& p_id
)
1754 if (!checked
) chk_uniq();
1755 return ass_m
[p_id
.get_name()];
1758 size_t Definitions::get_nof_asss()
1760 if (!checked
) chk_uniq();
1761 return ass_m
.size();
1764 size_t Definitions::get_nof_raw_asss()
1766 return ass_v
.size();
1769 Common::Assignment
* Definitions::get_ass_byIndex(size_t p_i
)
1771 if (!checked
) chk_uniq();
1772 return ass_m
.get_nth_elem(p_i
);
1775 Ttcn::Definition
* Definitions::get_raw_ass_byIndex(size_t p_i
) {
1779 void Definitions::chk_uniq()
1781 if (checked
) return;
1783 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1784 Definition
*ass
= ass_v
[i
];
1785 const Identifier
& id
= ass
->get_id();
1786 const string
& name
= id
.get_name();
1787 if (ass_m
.has_key(name
)) {
1788 const char *dispname_str
= id
.get_dispname().c_str();
1789 ass
->error("Duplicate definition with name `%s'", dispname_str
);
1790 ass_m
[name
]->note("Previous definition of `%s' is here", dispname_str
);
1792 ass_m
.add(name
, ass
);
1793 if (parent_scope
->is_valid_moduleid(id
)) {
1794 ass
->warning("Definition with name `%s' hides a module identifier",
1795 id
.get_dispname().c_str());
1802 void Definitions::chk()
1804 for (size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->chk();
1807 void Definitions::chk_for()
1809 if (checked
) return;
1812 // all checks are done in one iteration because
1813 // forward referencing is not allowed between the definitions
1814 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1815 Definition
*def
= ass_v
[i
];
1816 const Identifier
& id
= def
->get_id();
1817 const string
& name
= id
.get_name();
1818 if (ass_m
.has_key(name
)) {
1819 const char *dispname_str
= id
.get_dispname().c_str();
1820 def
->error("Duplicate definition with name `%s'", dispname_str
);
1821 ass_m
[name
]->note("Previous definition of `%s' is here", dispname_str
);
1823 ass_m
.add(name
, def
);
1825 if (parent_scope
->has_ass_withId(id
)) {
1826 const char *dispname_str
= id
.get_dispname().c_str();
1827 def
->error("Definition with identifier `%s' is not unique in the "
1828 "scope hierarchy", dispname_str
);
1829 Reference
ref(0, id
.clone());
1830 Common::Assignment
*ass
= parent_scope
->get_ass_bySRef(&ref
);
1831 if (!ass
) FATAL_ERROR("OtherDefinitions::chk_for()");
1832 ass
->note("Previous definition with identifier `%s' in higher "
1833 "scope unit is here", dispname_str
);
1834 } else if (parent_scope
->is_valid_moduleid(id
)) {
1835 def
->warning("Definition with name `%s' hides a module identifier",
1836 id
.get_dispname().c_str());
1844 void Definitions::set_genname(const string
& prefix
)
1846 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1847 Definition
*def
= ass_v
[i
];
1848 def
->set_genname(prefix
+ def
->get_id().get_name());
1852 void Definitions::generate_code(output_struct
* target
)
1854 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->generate_code(target
);
1857 void Definitions::generate_code(CodeGenHelper
& cgh
) {
1859 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->generate_code(cgh
);
1862 char* Definitions::generate_code_str(char *str
)
1864 for(size_t i
=0; i
<ass_v
.size(); i
++) {
1865 str
= ass_v
[i
]->update_location_object(str
);
1866 str
=ass_v
[i
]->generate_code_str(str
);
1871 void Definitions::ilt_generate_code(ILT
*ilt
)
1873 for(size_t i
=0; i
<ass_v
.size(); i
++)
1874 ass_v
[i
]->ilt_generate_code(ilt
);
1878 void Definitions::dump(unsigned level
) const
1880 DEBUG(level
, "Definitions: (%lu pcs.)", (unsigned long) ass_v
.size());
1881 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->dump(level
+ 1);
1884 // =================================
1886 // =================================
1888 Group::Group(Identifier
*p_id
)
1889 : Node(), Location(), parent_group(0), w_attrib_path(0), id(p_id
),
1892 if (!p_id
) FATAL_ERROR("Group::Group()");
1897 delete w_attrib_path
;
1900 for (size_t i
= 0; i
< group_v
.size(); i
++) delete group_v
[i
];
1904 friendmods_v
.clear();
1908 Group
* Group::clone() const
1910 FATAL_ERROR("Ttcn::Group::clone()");
1913 void Group::set_fullname(const string
& p_fullname
)
1915 Node::set_fullname(p_fullname
);
1916 for(size_t i
= 0; i
< group_v
.size() ; i
++)
1918 group_v
[i
]->set_fullname(p_fullname
+ ".<group " + Int2string(i
) + ">");
1920 if (w_attrib_path
) w_attrib_path
->set_fullname( p_fullname
1924 void Group::add_ass(Definition
* p_ass
)
1927 p_ass
->set_parent_group(this);
1930 void Group::add_group(Group
* p_group
)
1932 group_v
.add(p_group
);
1935 void Group::set_parent_group(Group
* p_parent_group
)
1937 if (parent_group
) FATAL_ERROR("Group::set_parent_group()");
1938 parent_group
= p_parent_group
;
1941 void Group::set_with_attr(MultiWithAttrib
* p_attrib
)
1943 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1944 w_attrib_path
->set_with_attr(p_attrib
);
1947 WithAttribPath
* Group::get_attrib_path()
1949 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1950 return w_attrib_path
;
1953 void Group::set_parent_path(WithAttribPath
* p_path
)
1955 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1956 w_attrib_path
->set_parent(p_path
);
1959 void Group::chk_uniq()
1961 if (checked
) return;
1965 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1966 Definition
*ass
= ass_v
[i
];
1967 const string
& ass_name
= ass
->get_id().get_name();
1968 if (!ass_m
.has_key(ass_name
)) ass_m
.add(ass_name
, ass
);
1971 for(size_t i
= 0; i
< group_v
.size(); i
++) {
1972 Group
*group
= group_v
[i
];
1973 const Identifier
& group_id
= group
->get_id();
1974 const string
& group_name
= group_id
.get_name();
1975 if (ass_m
.has_key(group_name
)) {
1976 group
->error("Group name `%s' clashes with a definition",
1977 group_id
.get_dispname().c_str());
1978 ass_m
[group_name
]->note("Definition of `%s' is here",
1979 group_id
.get_dispname().c_str());
1981 if (group_m
.has_key(group_name
)) {
1982 group
->error("Duplicate group with name `%s'",
1983 group_id
.get_dispname().c_str());
1984 group_m
[group_name
]->note("Group `%s' is already defined here",
1985 group_id
.get_dispname().c_str());
1986 } else group_m
.add(group_name
, group
);
1993 Error_Context
cntxt(this, "In group `%s'", id
->get_dispname().c_str());
1997 if (w_attrib_path
) {
1998 w_attrib_path
->chk_global_attrib();
1999 w_attrib_path
->chk_no_qualif();
2002 for(size_t i
= 0; i
< group_v
.size(); i
++) group_v
[i
]->chk();
2005 void Group::add_impmod(ImpMod
*p_impmod
)
2007 impmods_v
.add(p_impmod
);
2008 p_impmod
->set_parent_group(this);
2011 void Group::add_friendmod(FriendMod
*p_friendmod
)
2013 friendmods_v
.add(p_friendmod
);
2014 p_friendmod
->set_parent_group(this);
2017 void Group::dump(unsigned level
) const
2019 DEBUG(level
, "Group: %s", id
->get_dispname().c_str());
2020 DEBUG(level
+ 1, "Nested groups: (%lu pcs.)",
2021 (unsigned long) group_v
.size());
2022 for(size_t i
= 0; i
< group_v
.size(); i
++) group_v
[i
]->dump(level
+ 2);
2023 DEBUG(level
+ 1, "Nested definitions: (%lu pcs.)",
2024 (unsigned long) ass_v
.size());
2025 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->dump(level
+ 2);
2026 DEBUG(level
+ 1, "Nested imports: (%lu pcs.)",
2027 (unsigned long) impmods_v
.size());
2028 for(size_t i
= 0; i
< impmods_v
.size(); i
++) impmods_v
[i
]->dump(level
+ 2);
2029 if (w_attrib_path
) {
2030 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2032 DEBUG(level
+ 1, "Group Attributes:");
2033 attrib
->dump(level
+ 2);
2038 // =================================
2039 // ===== ControlPart
2040 // =================================
2042 ControlPart::ControlPart(StatementBlock
* p_block
)
2043 : Node(), Location(), block(p_block
), w_attrib_path(0)
2045 if (!p_block
) FATAL_ERROR("ControlPart::ControlPart()");
2048 ControlPart::~ControlPart()
2051 delete w_attrib_path
;
2054 ControlPart
* ControlPart::clone() const
2056 FATAL_ERROR("ControlPart::clone");
2059 void ControlPart::set_fullname(const string
& p_fullname
)
2061 block
->set_fullname(p_fullname
);
2062 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
2065 void ControlPart::set_my_scope(Scope
*p_scope
)
2067 bridgeScope
.set_parent_scope(p_scope
);
2068 string
temp("control");
2069 bridgeScope
.set_scopeMacro_name(temp
);
2071 block
->set_my_scope(&bridgeScope
);
2074 void ControlPart::chk()
2076 Error_Context
cntxt(this, "In control part");
2078 if (!semantic_check_only
)
2079 block
->set_code_section(GovernedSimple::CS_INLINE
);
2080 if (w_attrib_path
) {
2081 w_attrib_path
->chk_global_attrib();
2082 w_attrib_path
->chk_no_qualif();
2086 void ControlPart::generate_code(output_struct
*target
, Module
*my_module
)
2088 const char *module_dispname
= my_module
->get_modid().get_dispname().c_str();
2089 target
->functions
.control
=
2090 create_location_object(target
->functions
.control
, "CONTROLPART",
2092 target
->functions
.control
= mputprintf(target
->functions
.control
,
2093 "TTCN_Runtime::begin_controlpart(\"%s\");\n", module_dispname
);
2094 target
->functions
.control
=
2095 block
->generate_code(target
->functions
.control
);
2096 target
->functions
.control
= mputstr(target
->functions
.control
,
2097 "TTCN_Runtime::end_controlpart();\n");
2100 void ControlPart::set_with_attr(MultiWithAttrib
* p_attrib
)
2102 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2103 w_attrib_path
->set_with_attr(p_attrib
);
2106 WithAttribPath
* ControlPart::get_attrib_path()
2108 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2109 return w_attrib_path
;
2112 void ControlPart::set_parent_path(WithAttribPath
* p_path
)
2114 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2115 w_attrib_path
->set_parent(p_path
);
2116 block
->set_parent_path(w_attrib_path
);
2119 void ControlPart::dump(unsigned level
) const
2121 DEBUG(level
, "Control part");
2122 block
->dump(level
+ 1);
2123 if (w_attrib_path
) {
2124 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2126 DEBUG(level
+ 1, "Attributes:");
2127 attrib
->dump(level
+ 2);
2132 // =================================
2134 // =================================
2136 Module::Module(Identifier
*p_modid
)
2137 : Common::Module(MOD_TTCN
, p_modid
), language_spec(0), w_attrib_path(0),
2140 asss
= new Definitions();
2141 asss
->set_parent_scope(this);
2142 imp
= new Imports();
2143 imp
->set_my_mod(this);
2144 //modified_encodings = true; // Assume always true for TTCN modules
2149 delete language_spec
;
2151 for (size_t i
= 0; i
< group_v
.size(); i
++) delete group_v
[i
];
2155 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) delete friendmods_v
[i
];
2156 friendmods_v
.clear();
2158 for (size_t i
= 0; i
< runs_on_scopes
.size(); i
++)
2159 delete runs_on_scopes
[i
];
2160 runs_on_scopes
.clear();
2161 delete w_attrib_path
;
2164 void Module::add_group(Group
* p_group
)
2166 group_v
.add(p_group
);
2169 void Module::add_friendmod(FriendMod
*p_friendmod
)
2171 friendmods_v
.add(p_friendmod
);
2172 p_friendmod
->set_my_mod(this);
2175 Module
*Module::clone() const
2177 FATAL_ERROR("Ttcn::Module::clone()");
2180 Common::Assignment
*Module::importAssignment(const Identifier
& p_modid
,
2181 const Identifier
& p_id
) const
2183 if (asss
->has_local_ass_withId(p_id
)) {
2184 Common::Assignment
* ass
= asss
->get_local_ass_byId(p_id
);
2185 if (!ass
) FATAL_ERROR("Ttcn::Module::importAssignment()");
2187 switch(ass
->get_visibility()) {
2189 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) {
2190 if (friendmods_v
[i
]->get_modid() == p_modid
) return ass
;
2198 FATAL_ERROR("Ttcn::Module::importAssignment()");
2204 void Module::set_fullname(const string
& p_fullname
)
2206 Node::set_fullname(p_fullname
);
2207 asss
->set_fullname(p_fullname
);
2208 if (controlpart
) controlpart
->set_fullname(p_fullname
+ ".control");
2209 for(size_t i
= 0; i
< group_v
.size(); i
++)
2211 group_v
[i
]->set_fullname(p_fullname
+ ".<group " + Int2string(i
) + ">");
2213 if (w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
2217 Common::Assignments
*Module::get_scope_asss()
2222 bool Module::has_imported_ass_withId(const Identifier
& p_id
)
2224 const Location
*loc
= NULL
;
2225 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2226 const ImpMod
* im
= imp
->get_impmod(i
);
2227 //TODO use a reference instead of an identifier
2228 if(im
->has_imported_def(*modid
, p_id
, loc
)) return true;
2233 Common::Assignment
* Module::get_ass_bySRef(Ref_simple
*p_ref
)
2235 const Identifier
*r_modid
= p_ref
->get_modid();
2236 const Identifier
*r_id
= p_ref
->get_id();
2238 // the reference contains a module name
2239 if (r_modid
->get_name() != modid
->get_name()) {
2240 // the reference points to another module
2241 bool has_impmod_with_name
= false;
2242 Common::Assignment
* result_ass
= NULL
;
2243 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2244 const ImpMod
* im
= imp
->get_impmod(i
);
2245 const Identifier
& im_id
= im
->get_modid();
2246 const string
& im_name
= im_id
.get_name();
2247 if (r_modid
->get_name() == im_name
) {
2248 has_impmod_with_name
= true;
2249 vector
<ImpMod
> tempusedImpMods
;
2250 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
2251 Common::Assignment
*t_ass
= im
->get_imported_def(*modid
, *r_id
, p_ref
, referencechain
, tempusedImpMods
);
2252 referencechain
->reset();
2253 delete referencechain
;
2255 if (t_ass
!= NULL
) {
2256 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(im
->get_mod());
2257 if (!ttcn_m
->is_visible(*modid
, t_ass
->get_visibility())) {
2261 if (t_ass
!= NULL
) {
2262 if (result_ass
== NULL
) {
2264 } else if(result_ass
!= t_ass
) {
2266 "It is not possible to resolve the reference unambiguously"
2267 ", as it can be resolved to `%s' and to `%s'",
2268 result_ass
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
2272 tempusedImpMods
.clear();
2275 if (result_ass
) return result_ass
;
2277 if (has_impmod_with_name
) {
2278 p_ref
->error("There is no definition with name `%s' visible from "
2279 "module `%s'", r_id
->get_dispname().c_str(),
2280 r_modid
->get_dispname().c_str());
2282 if (modules
->has_mod_withId(*r_modid
)) {
2283 Common::Module
*m
= modules
->get_mod_byId(*r_modid
);
2284 if (m
->get_asss()->has_ass_withId(*r_id
)) {
2285 p_ref
->error("Definition with name `%s' is not imported from "
2286 "module `%s'", r_id
->get_dispname().c_str(),
2287 r_modid
->get_dispname().c_str());
2289 p_ref
->error("There is no definition with name `%s' in "
2290 "module `%s'", r_id
->get_dispname().c_str(),
2291 r_modid
->get_dispname().c_str());
2294 p_ref
->error("There is no module with name `%s'",
2295 r_modid
->get_dispname().c_str());
2300 // the reference points to the own module
2301 if (asss
->has_local_ass_withId(*r_id
)) {
2302 return asss
->get_local_ass_byId(*r_id
);
2304 p_ref
->error("There is no definition with name `%s' in "
2305 "module `%s'", r_id
->get_dispname().c_str(),
2306 r_modid
->get_dispname().c_str());
2310 // no module name is given in the reference
2311 if (asss
->has_local_ass_withId(*r_id
)) {
2312 return asss
->get_local_ass_byId(*r_id
);
2314 // the reference was not found locally -> look at the import list
2315 Common::Assignment
*t_result
= NULL
, *t_ass
= NULL
;
2316 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2317 const ImpMod
* im
= imp
->get_impmod(i
);
2319 vector
<ImpMod
> tempusedImpMods
;
2320 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
2321 t_ass
= im
->get_imported_def(*modid
, *r_id
, p_ref
, referencechain
, tempusedImpMods
);
2322 referencechain
->reset();
2324 delete referencechain
;
2325 if (t_ass
!= NULL
) {
2326 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(im
->get_mod());
2327 if (!ttcn_m
->is_visible(*modid
, t_ass
->get_visibility())) {
2331 if (t_ass
!= NULL
) {
2332 if (t_result
== NULL
) {
2334 } else if(t_result
!= t_ass
) {
2336 "It is not possible to resolve the reference unambiguously"
2337 ", as it can be resolved to `%s' and to `%s'",
2338 t_result
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
2342 tempusedImpMods
.clear();
2345 if (t_result
) return t_result
;
2347 p_ref
->error("There is no local or imported definition with name `%s'"
2348 ,r_id
->get_dispname().c_str());
2354 bool Module::is_valid_moduleid(const Identifier
& p_id
)
2356 // The identifier represents the current module
2357 if (p_id
.get_name() == modid
->get_name()) return true;
2358 // The identifier represents a module imported in the current module
2359 if(imp
->has_impmod_withId(p_id
)) return true;
2363 Common::Assignments
*Module::get_asss()
2368 bool Module::exports_sym(const Identifier
&)
2370 FATAL_ERROR("Ttcn::Module::exports_sym()");
2374 Type
*Module::get_address_type()
2376 Identifier
address_id(Identifier::ID_TTCN
, string("address"));
2377 // return NULL if address type is not defined
2378 if (!asss
->has_local_ass_withId(address_id
)) return 0;
2379 Common::Assignment
*t_ass
= asss
->get_local_ass_byId(address_id
);
2380 if (t_ass
->get_asstype() != Common::Assignment::A_TYPE
)
2381 FATAL_ERROR("Module::get_address_type(): address is not a type");
2382 return t_ass
->get_Type();
2385 void Module::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
2387 if (imp_checked
) return;
2388 const string
& module_name
= modid
->get_dispname();
2390 Error_Context backup
;
2391 Error_Context
cntxt(this, "In TTCN-3 module `%s'", module_name
.c_str());
2392 imp
->chk_imp(refch
, moduleStack
);
2395 collect_visible_mods();
2400 DEBUG(1, "Checking TTCN-3 module `%s'", modid
->get_dispname().c_str());
2401 Error_Context
cntxt(this, "In TTCN-3 module `%s'",
2402 modid
->get_dispname().c_str());
2403 if (w_attrib_path
) {
2404 w_attrib_path
->chk_global_attrib();
2405 w_attrib_path
->chk_no_qualif();
2407 // Check "extension" attributes in the module's "with" statement
2408 MultiWithAttrib
*multi
= w_attrib_path
->get_with_attr();
2409 if (multi
) for (size_t i
= 0; i
< multi
->get_nof_elements(); ++i
) {
2410 const SingleWithAttrib
*single
= multi
->get_element(i
);
2411 if (single
->get_attribKeyword() != SingleWithAttrib::AT_EXTENSION
) continue;
2412 // Parse the extension attribute
2413 // We circumvent parse_extattributes() in coding_attrib_p.y because
2414 // it processes all attributes in the "with" statement and
2415 // doesn't allow the removal on a case-by-case basis.
2417 init_coding_attrib_lex(single
->get_attribSpec());
2418 int result
= coding_attrib_parse();// 0=OK, 1=error, 2=out of memory
2419 cleanup_coding_attrib_lex();
2426 const size_t num_parsed
= extatrs
->size();
2427 for (size_t a
= 0; a
< num_parsed
; ++a
) {
2428 Ttcn::ExtensionAttribute
& ex
= extatrs
->get(0);
2430 switch (ex
.get_type()) {
2431 case Ttcn::ExtensionAttribute::VERSION_TEMPLATE
:
2432 case Ttcn::ExtensionAttribute::VERSION
: {
2433 char* act_product_number
;
2434 unsigned int act_suffix
, act_rel
, act_patch
, act_build
;
2436 (void)ex
.get_id(act_product_number
, act_suffix
, act_rel
, act_patch
, act_build
, extra_junk
);
2438 if (release
!= UINT_MAX
) {
2439 ex
.error("Duplicate 'version' attribute");
2442 product_number
= mcopystr(act_product_number
);
2443 suffix
= act_suffix
;
2447 extra
= mcopystr(extra_junk
);
2449 // Avoid propagating the attribute needlessly
2450 multi
->delete_element(i
--);
2454 case Ttcn::ExtensionAttribute::REQUIRES
: {
2455 // Imports have already been checked
2456 char* exp_product_number
;
2457 unsigned int exp_suffix
, exp_rel
, exp_patch
, exp_build
;
2459 Common::Identifier
*req_id
= ex
.get_id(exp_product_number
,
2460 exp_suffix
, exp_rel
, exp_patch
, exp_build
, exp_extra
);
2462 if (imp
->has_impmod_withId(*req_id
)) {
2463 Common::Module
* m
= modules
->get_mod_byId(*req_id
);
2464 if (m
->product_number
== NULL
&& exp_product_number
!= NULL
) {
2465 ex
.error("Module '%s' requires module '%s' of product %s"
2466 ", but it is not specified",
2467 this->modid
->get_dispname().c_str(), req_id
->get_dispname().c_str(),
2468 exp_product_number
);
2469 multi
->delete_element(i
--);
2472 } else if (exp_product_number
== NULL
&&
2473 m
->product_number
!= NULL
&& strcmp(m
->product_number
, "") > 0){
2474 ex
.warning("Module '%s' requires module '%s' of any product"
2475 ", while it specifies '%s'",
2476 this->modid
->get_dispname().c_str(),
2477 req_id
->get_dispname().c_str(), m
->product_number
);
2478 } else if (m
->product_number
!= NULL
&& exp_product_number
!= NULL
2479 && 0 != strcmp(m
->product_number
, exp_product_number
)) {
2480 char *req_product_identifier
=
2481 get_product_identifier(exp_product_number
,
2482 exp_suffix
, exp_rel
, exp_patch
, exp_build
);
2483 char *mod_product_identifier
=
2484 get_product_identifier(m
->product_number
,
2485 m
->suffix
, m
->release
, m
->patch
, m
->build
);
2487 ex
.error("Module '%s' requires version %s of module"
2488 " '%s', but only %s is available",
2489 this->modid
->get_dispname().c_str(), req_product_identifier
,
2490 req_id
->get_dispname().c_str(), mod_product_identifier
);
2491 Free(req_product_identifier
);
2492 Free(mod_product_identifier
);
2493 multi
->delete_element(i
--);
2497 // different suffixes are always incompatible
2498 // unless the special version number is used
2499 if (m
->suffix
!= exp_suffix
&& (m
->suffix
!= UINT_MAX
)) {
2500 char *req_product_identifier
=
2501 get_product_identifier(exp_product_number
,exp_suffix
, exp_rel
, exp_patch
, exp_build
);
2502 char *mod_product_identifier
=
2503 get_product_identifier(m
->product_number
,
2504 m
->suffix
, m
->release
, m
->patch
, m
->build
);
2506 ex
.error("Module '%s' requires version %s of module"
2507 " '%s', but only %s is available",
2508 this->modid
->get_dispname().c_str(), req_product_identifier
,
2509 req_id
->get_dispname().c_str(), mod_product_identifier
);
2510 Free(req_product_identifier
);
2511 Free(mod_product_identifier
);
2512 multi
->delete_element(i
--);
2516 if ( m
->release
< exp_rel
2517 ||(m
->release
== exp_rel
&& m
->patch
< exp_patch
)
2518 ||(m
->patch
== exp_patch
&& m
->build
< exp_build
)) {
2519 char *mod_bld_str
= buildstr(m
->build
);
2520 char *exp_bld_str
= buildstr(exp_build
);
2521 if (mod_bld_str
==0 || exp_bld_str
==0) FATAL_ERROR(
2522 "Ttcn::Module::chk() invalid build number");
2523 ex
.error("Module '%s' requires version R%u%c%s of module"
2524 " '%s', but only R%u%c%s is available",
2525 this->modid
->get_dispname().c_str(),
2526 exp_rel
, eri(exp_patch
), exp_bld_str
,
2527 req_id
->get_dispname().c_str(),
2528 m
->release
, eri(m
->patch
), mod_bld_str
);
2533 single
->error("No imported module named '%s'",
2534 req_id
->get_dispname().c_str());
2536 multi
->delete_element(i
--);
2540 case Ttcn::ExtensionAttribute::REQ_TITAN
: {
2541 char* exp_product_number
;
2542 unsigned int exp_suffix
, exp_minor
, exp_patch
, exp_build
;
2544 (void)ex
.get_id(exp_product_number
, exp_suffix
, exp_minor
, exp_patch
, exp_build
, exp_extra
);
2545 if (exp_product_number
!= NULL
&& strcmp(exp_product_number
,"CRL 113 200") != 0) {
2546 ex
.error("This module needs to be compiled with TITAN, but "
2547 " product number %s is not TITAN"
2548 , exp_product_number
);
2550 if (0 == exp_suffix
) {
2551 exp_suffix
= 1; // previous version number format did not list the suffix part
2553 // TTCN3_MAJOR is always 1
2554 int expected_version
= exp_suffix
* 1000000
2555 + exp_minor
* 10000 + exp_patch
* 100 + exp_build
;
2556 if (expected_version
> TTCN3_VERSION_MONOTONE
) {
2557 char *exp_product_identifier
=
2558 get_product_identifier(exp_product_number
, exp_suffix
, exp_minor
, exp_patch
, exp_build
);
2559 ex
.error("This module needs to be compiled with TITAN version"
2560 " %s or higher; version %s detected"
2561 , exp_product_identifier
, PRODUCT_NUMBER
);
2562 Free(exp_product_identifier
);
2564 multi
->delete_element(i
--);
2567 case Ttcn::ExtensionAttribute::PRINTING
: {
2568 ex
.error("Attribute 'printing' not allowed at module level");
2569 multi
->delete_element(i
--);
2575 // Let everything else propagate into the module.
2576 // Extension attributes in the module's "with" statement
2577 // may be impractical, but not outright erroneous.
2588 if (controlpart
) controlpart
->chk();
2589 if (control_ns
&& !*control_ns
) { // set but empty
2590 error("Invalid URI value for control namespace");
2592 if (control_ns_prefix
&& !*control_ns_prefix
) { // set but empty
2593 error("Empty NCName for the control namespace prefix is not allowed");
2595 // TODO proper URI and NCName validation
2598 void Module::chk_friends()
2600 map
<string
, FriendMod
> friends_m
;
2602 for(size_t i
= 0; i
< friendmods_v
.size(); i
++)
2604 FriendMod
* temp_friend
= friendmods_v
[i
];
2605 const Identifier
& friend_id
= temp_friend
->get_modid();
2606 const string
& friend_name
= friend_id
.get_name();
2607 if(friends_m
.has_key(friend_name
))
2609 temp_friend
->error("Duplicate friend module with name `%s'",
2610 friend_id
.get_dispname().c_str());
2611 friends_m
[friend_name
]->note("Friend module `%s' is already defined here",
2612 friend_id
.get_dispname().c_str());
2614 friends_m
.add(friend_name
, temp_friend
);
2617 friendmods_v
[i
]->chk();
2624 void Module::chk_groups()
2626 map
<string
,Common::Assignment
> ass_m
;
2628 for(size_t i
= 0; i
< asss
->get_nof_asss(); i
++)
2630 Common::Assignment
*temp_ass
= asss
->get_ass_byIndex(i
);
2631 if(!temp_ass
->get_parent_group())
2633 const string
& ass_name
= temp_ass
->get_id().get_name();
2634 if (!ass_m
.has_key(ass_name
)) ass_m
.add(ass_name
, temp_ass
);
2638 for(size_t i
= 0; i
< group_v
.size(); i
++)
2640 const Group
* group
= group_v
[i
];
2641 const Identifier
& group_id
= group
->get_id();
2642 const string
& group_name
= group_id
.get_name();
2643 if(ass_m
.has_key(group_name
))
2645 group
->error("Group name `%s' clashes with a definition",
2646 group_id
.get_dispname().c_str());
2647 ass_m
[group_name
]->note("Definition of `%s' is here",
2648 group_id
.get_dispname().c_str());
2650 if(group_m
.has_key(group_name
))
2652 group
->error("Duplicate group with name `%s'",
2653 group_id
.get_dispname().c_str());
2654 group_m
[group_name
]->note("Group `%s' is already defined here",
2655 group_id
.get_dispname().c_str());
2657 group_m
.add(group_name
,group_v
[i
]);
2663 for(size_t i
= 0; i
< group_v
.size(); i
++)
2669 void Module::get_imported_mods(module_set_t
& p_imported_mods
)
2671 imp
->get_imported_mods(p_imported_mods
);
2674 void Module::generate_code_internal(CodeGenHelper
& cgh
) {
2675 imp
->generate_code(cgh
);
2676 asss
->generate_code(cgh
);
2678 controlpart
->generate_code(cgh
.get_outputstruct(modid
->get_ttcnname()), this);
2681 RunsOnScope
*Module::get_runs_on_scope(Type
*comptype
)
2683 RunsOnScope
*ret_val
= new RunsOnScope(comptype
);
2684 runs_on_scopes
.add(ret_val
);
2685 ret_val
->set_parent_scope(asss
);
2686 ret_val
->chk_uniq();
2691 void Module::dump(unsigned level
) const
2693 DEBUG(level
, "TTCN-3 module: %s", modid
->get_dispname().c_str());
2695 if(imp
) imp
->dump(level
);
2696 if(asss
) asss
->dump(level
);
2698 for(size_t i
= 0; i
< group_v
.size(); i
++)
2700 group_v
[i
]->dump(level
);
2703 if(controlpart
) controlpart
->dump(level
);
2705 if (w_attrib_path
) {
2706 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2708 DEBUG(level
, "Module Attributes:");
2709 attrib
->dump(level
+ 1);
2714 void Module::set_language_spec(const char *p_language_spec
)
2716 if (language_spec
) FATAL_ERROR("Module::set_language_spec()");
2717 if (p_language_spec
) language_spec
= new string(p_language_spec
);
2720 void Module::add_ass(Definition
* p_ass
)
2722 asss
->add_ass(p_ass
);
2725 void Module::add_impmod(ImpMod
*p_impmod
)
2727 imp
->add_impmod(p_impmod
);
2730 void Module::add_controlpart(ControlPart
* p_controlpart
)
2732 if (!p_controlpart
|| controlpart
) FATAL_ERROR("Module::add_controlpart()");
2733 controlpart
= p_controlpart
;
2734 controlpart
->set_my_scope(asss
);
2737 void Module::set_with_attr(MultiWithAttrib
* p_attrib
)
2739 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2740 w_attrib_path
->set_with_attr(p_attrib
);
2743 WithAttribPath
* Module::get_attrib_path()
2745 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2746 return w_attrib_path
;
2749 void Module::set_parent_path(WithAttribPath
* p_path
)
2751 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2752 w_attrib_path
->set_parent(p_path
);
2755 bool Module::is_visible(const Identifier
& id
, visibility_t visibility
){
2757 if (visibility
== PUBLIC
) {
2760 if (visibility
== FRIEND
) {
2761 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) {
2762 if (friendmods_v
[i
]->get_modid() == id
) {
2770 void Module::generate_json_schema(JSON_Tokenizer
& json
, map
<Type
*, JSON_Tokenizer
>& json_refs
)
2772 // add a new property for this module
2773 json
.put_next_token(JSON_TOKEN_NAME
, modid
->get_ttcnname().c_str());
2775 // add type definitions into an object
2776 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2778 // cycle through each type, generate schema segment and reference when needed
2779 for (size_t i
= 0; i
< asss
->get_nof_asss(); ++i
) {
2780 Def_Type
* def
= dynamic_cast<Def_Type
*>(asss
->get_ass_byIndex(i
));
2782 Type
* t
= def
->get_Type();
2783 if (t
->has_encoding(Type::CT_JSON
)) {
2784 // insert type's schema segment
2785 t
->generate_json_schema(json
, false, false);
2787 if (json_refs_for_all_types
&& !json_refs
.has_key(t
)) {
2788 // create JSON schema reference for the type
2789 JSON_Tokenizer
* json_ref
= new JSON_Tokenizer
;
2790 json_refs
.add(t
, json_ref
);
2791 t
->generate_json_schema_ref(*json_ref
);
2797 // end of type definitions
2798 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2800 // insert function data
2801 for (size_t i
= 0; i
< asss
->get_nof_asss(); ++i
) {
2802 Def_ExtFunction
* def
= dynamic_cast<Def_ExtFunction
*>(asss
->get_ass_byIndex(i
));
2804 def
->generate_json_schema_ref(json_refs
);
2809 // =================================
2811 // =================================
2813 string
Definition::get_genname() const
2815 if (!genname
.empty()) return genname
;
2816 else return id
->get_name();
2819 namedbool
Definition::has_implicit_omit_attr() const {
2820 if (w_attrib_path
) {
2821 const vector
<SingleWithAttrib
>& real_attribs
=
2822 w_attrib_path
->get_real_attrib();
2823 for (size_t in
= real_attribs
.size(); in
> 0; in
--) {
2824 if (SingleWithAttrib::AT_OPTIONAL
==
2825 real_attribs
[in
-1]->get_attribKeyword()) {
2826 if ("implicit omit" ==
2827 real_attribs
[in
-1]->get_attribSpec().get_spec()) {
2828 return IMPLICIT_OMIT
;
2829 } else if ("explicit omit" ==
2830 real_attribs
[in
-1]->get_attribSpec().get_spec()) {
2831 return NOT_IMPLICIT_OMIT
;
2832 } // error reporting for other values is in chk_global_attrib
2836 return NOT_IMPLICIT_OMIT
;
2839 Definition::~Definition()
2841 delete w_attrib_path
;
2842 delete erroneous_attrs
;
2845 void Definition::set_fullname(const string
& p_fullname
)
2847 Common::Assignment::set_fullname(p_fullname
);
2848 if (w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
2849 if (erroneous_attrs
) erroneous_attrs
->set_fullname(p_fullname
+".<erroneous_attributes>");
2852 bool Definition::is_local() const
2854 if (!my_scope
) FATAL_ERROR("Definition::is_local()");
2855 for (Scope
*scope
= my_scope
; scope
; scope
= scope
->get_parent_scope()) {
2856 if (dynamic_cast<StatementBlock
*>(scope
)) return true;
2861 bool Definition::chk_identical(Definition
*)
2863 FATAL_ERROR("Definition::chk_identical()");
2867 void Definition::chk_erroneous_attr()
2869 if (!w_attrib_path
) return;
2870 const Ttcn::MultiWithAttrib
* attribs
= w_attrib_path
->get_local_attrib();
2871 if (!attribs
) return;
2872 for (size_t i
= 0; i
< attribs
->get_nof_elements(); i
++) {
2873 const Ttcn::SingleWithAttrib
* act_attr
= attribs
->get_element(i
);
2874 if (act_attr
->get_attribKeyword()==Ttcn::SingleWithAttrib::AT_ERRONEOUS
) {
2875 if (!use_runtime_2
) {
2876 error("`erroneous' attributes can be used only with the Function Test Runtime");
2877 note("If you need negative testing use the -R flag when generating the makefile");
2880 size_t nof_qualifiers
= act_attr
->get_attribQualifiers() ? act_attr
->get_attribQualifiers()->get_nof_qualifiers() : 0;
2881 dynamic_array
<Type
*> refd_type_array(nof_qualifiers
); // only the qualifiers pointing to existing fields will be added to erroneous_attrs objects
2882 if (nof_qualifiers
==0) {
2883 act_attr
->error("At least one qualifier must be specified for the `erroneous' attribute");
2885 // check if qualifiers point to existing fields
2886 for (size_t qi
=0; qi
<nof_qualifiers
; qi
++) {
2887 Qualifier
* act_qual
= const_cast<Qualifier
*>(act_attr
->get_attribQualifiers()->get_qualifier(qi
));
2888 act_qual
->set_my_scope(get_my_scope());
2889 Type
* field_type
= get_Type()->get_field_type(act_qual
, Type::EXPECTED_CONSTANT
);
2891 dynamic_array
<size_t> subrefs_array
;
2892 dynamic_array
<Type
*> type_array
;
2893 bool valid_indexes
= get_Type()->get_subrefs_as_array(act_qual
, subrefs_array
, type_array
);
2894 if (!valid_indexes
) field_type
= NULL
;
2895 if (act_qual
->refers_to_string_element()) {
2896 act_qual
->error("Reference to a string element cannot be used in this context");
2900 refd_type_array
.add(field_type
);
2903 // parse the attr. spec.
2904 ErroneousAttributeSpec
* err_attr_spec
= ttcn3_parse_erroneous_attr_spec_string(
2905 act_attr
->get_attribSpec().get_spec().c_str(), act_attr
->get_attribSpec());
2906 if (err_attr_spec
) {
2907 if (!erroneous_attrs
) erroneous_attrs
= new ErroneousAttributes(get_Type());
2908 // attr.spec will be owned by erroneous_attrs object
2909 erroneous_attrs
->add_spec(err_attr_spec
);
2910 err_attr_spec
->set_fullname(get_fullname());
2911 err_attr_spec
->set_my_scope(get_my_scope());
2912 err_attr_spec
->chk();
2913 // create qualifier - err.attr.spec. pairs
2914 for (size_t qi
=0; qi
<nof_qualifiers
; qi
++) {
2915 if (refd_type_array
[qi
] && (err_attr_spec
->get_indicator()!=ErroneousAttributeSpec::I_INVALID
)) {
2916 erroneous_attrs
->add_pair(act_attr
->get_attribQualifiers()->get_qualifier(qi
), err_attr_spec
);
2922 if (erroneous_attrs
) erroneous_attrs
->chk();
2925 char* Definition::generate_code_str(char *str
)
2927 FATAL_ERROR("Definition::generate_code_str()");
2931 void Definition::ilt_generate_code(ILT
*)
2933 FATAL_ERROR("Definition::ilt_generate_code()");
2936 char *Definition::generate_code_init_comp(char *str
, Definition
*)
2938 FATAL_ERROR("Definition::generate_code_init_comp()");
2942 void Definition::set_with_attr(MultiWithAttrib
* p_attrib
)
2944 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2945 w_attrib_path
->set_with_attr(p_attrib
);
2948 WithAttribPath
* Definition::get_attrib_path()
2950 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2951 return w_attrib_path
;
2954 void Definition::set_parent_path(WithAttribPath
* p_path
)
2956 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2957 w_attrib_path
->set_parent(p_path
);
2960 void Definition::set_parent_group(Group
* p_group
)
2962 if(parentgroup
) // there would be a leak!
2963 FATAL_ERROR("Definition::set_parent_group()");
2964 parentgroup
= p_group
;
2967 Group
* Definition::get_parent_group()
2972 void Definition::dump_internal(unsigned level
) const
2974 DEBUG(level
, "Move along, nothing to see here");
2977 void Definition::dump(unsigned level
) const
2979 dump_internal(level
);
2980 if (w_attrib_path
) {
2981 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2983 DEBUG(level
+ 1, "Definition Attributes:");
2984 attrib
->dump(level
+ 2);
2987 if (erroneous_attrs
) erroneous_attrs
->dump(level
+1);
2990 // =================================
2992 // =================================
2994 Def_Type::Def_Type(Identifier
*p_id
, Type
*p_type
)
2995 : Definition(A_TYPE
, p_id
), type(p_type
)
2997 if(!p_type
) FATAL_ERROR("Ttcn::Def_Type::Def_Type()");
2998 type
->set_ownertype(Type::OT_TYPE_DEF
, this);
3001 Def_Type::~Def_Type()
3006 Def_Type
*Def_Type::clone() const
3008 FATAL_ERROR("Def_Type::clone");
3011 void Def_Type::set_fullname(const string
& p_fullname
)
3013 Definition::set_fullname(p_fullname
);
3014 type
->set_fullname(p_fullname
);
3017 void Def_Type::set_my_scope(Scope
*p_scope
)
3019 bridgeScope
.set_parent_scope(p_scope
);
3020 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
3022 Definition::set_my_scope(&bridgeScope
);
3023 type
->set_my_scope(&bridgeScope
);
3027 Setting
*Def_Type::get_Setting()
3032 Type
*Def_Type::get_Type()
3038 void Def_Type::chk()
3040 if (checked
) return;
3042 Error_Context
cntxt(this, "In %s definition `%s'",
3043 type
->get_typetype() == Type::T_SIGNATURE
? "signature" : "type",
3044 id
->get_dispname().c_str());
3045 type
->set_genname(get_genname());
3046 if (!semantic_check_only
&& type
->get_typetype() == Type::T_COMPONENT
) {
3047 // the prefix of embedded definitions must be set before the checking
3048 type
->get_CompBody()->set_genname(get_genname() + "_component_");
3051 while (w_attrib_path
) { // not a loop, but we can _break_ out of it
3052 w_attrib_path
->chk_global_attrib();
3053 w_attrib_path
->chk_no_qualif();
3054 if (type
->get_typetype() != Type::T_ANYTYPE
) break;
3055 // This is the anytype; it must be empty (we're about to add the fields)
3056 if (type
->get_nof_comps() > 0) FATAL_ERROR("Def_Type::chk");
3058 Ttcn::ExtensionAttributes
*extattrs
= parse_extattributes(w_attrib_path
);
3059 if (extattrs
== 0) break; // NULL means parsing error
3061 size_t num_atrs
= extattrs
->size();
3062 for (size_t k
= 0; k
< num_atrs
; ++k
) {
3063 ExtensionAttribute
&ea
= extattrs
->get(k
);
3064 switch (ea
.get_type()) {
3065 case ExtensionAttribute::ANYTYPELIST
: {
3066 Types
*anytypes
= ea
.get_types();
3067 // List of types to be converted into fields for the anytype.
3068 // Make sure scope is set on all types in the list.
3069 anytypes
->set_my_scope(get_my_scope());
3071 // Convert the list of types into field names for the anytype
3072 for (size_t i
=0; i
< anytypes
->get_nof_types(); ++i
) {
3073 Type
*t
= anytypes
->extract_type_byIndex(i
);
3074 // we are now the owner of the Type.
3075 if (t
->get_typetype()==Type::T_ERROR
) { // should we give up?
3081 const char* btn
= Type::get_typename_builtin(t
->get_typetype());
3085 else if (t
->get_typetype() == Type::T_REFD
) {
3086 // Extract the identifier
3087 Common::Reference
*ref
= t
->get_Reference();
3088 Ttcn::Reference
*tref
= dynamic_cast<Ttcn::Reference
*>(ref
);
3089 if (!tref
) FATAL_ERROR("Def_Type::chk, wrong kind of reference");
3090 const Common::Identifier
*modid
= tref
->get_modid();
3092 ea
.error("Qualified name '%s' cannot be added to the anytype",
3093 tref
->get_dispname().c_str());
3097 field_name
= tref
->get_id()->get_ttcnname();
3100 // Can't happen here
3101 FATAL_ERROR("Unexpected type %d", t
->get_typetype());
3104 const string
& at_field
= anytype_field(field_name
);
3105 Identifier
*field_id
= new Identifier(Identifier::ID_TTCN
, at_field
);
3106 CompField
*cf
= new CompField(field_id
, t
, false, 0);
3107 cf
->set_location(ea
);
3108 cf
->set_fullname(get_fullname());
3114 w_attrib_path
->get_with_attr()->error("Type def can only have anytype");
3120 break; // do not loop
3123 // Now we can check the type
3125 type
->chk_constructor_name(*id
);
3126 if (id
->get_ttcnname() == "address") type
->chk_address();
3127 ReferenceChain
refch(type
, "While checking embedded recursions");
3128 type
->chk_recursions(refch
);
3130 if (type
->get_typetype()==Type::T_FUNCTION
3131 ||type
->get_typetype()==Type::T_ALTSTEP
3132 ||type
->get_typetype()==Type::T_TESTCASE
) {
3133 // TR 922. This is a function/altstep/testcase reference.
3134 // Set this definition as the definition for the formal parameters.
3135 type
->get_fat_parameters()->set_my_def(this);
3139 void Def_Type::generate_code(output_struct
*target
, bool)
3141 type
->generate_code(target
);
3142 if (type
->get_typetype() == Type::T_COMPONENT
) {
3143 // the C++ equivalents of embedded component element definitions must be
3144 // generated from outside Type::generate_code() because the function can
3145 // call itself recursively and create invalid (overlapped) initializer
3147 type
->get_CompBody()->generate_code(target
);
3151 void Def_Type::generate_code(CodeGenHelper
& cgh
) {
3152 type
->generate_code(cgh
.get_outputstruct(get_Type()));
3153 if (type
->get_typetype() == Type::T_COMPONENT
) {
3154 // the C++ equivalents of embedded component element definitions must be
3155 // generated from outside Type::generate_code() because the function can
3156 // call itself recursively and create invalid (overlapped) initializer
3158 type
->get_CompBody()->generate_code(cgh
.get_current_outputstruct());
3160 cgh
.finalize_generation(get_Type());
3164 void Def_Type::dump_internal(unsigned level
) const
3166 DEBUG(level
, "Type def: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3167 type
->dump(level
+ 1);
3170 void Def_Type::set_with_attr(MultiWithAttrib
* p_attrib
)
3172 if (!w_attrib_path
) {
3173 w_attrib_path
= new WithAttribPath();
3174 type
->set_parent_path(w_attrib_path
);
3176 type
->set_with_attr(p_attrib
);
3179 WithAttribPath
* Def_Type::get_attrib_path()
3181 if (!w_attrib_path
) {
3182 w_attrib_path
= new WithAttribPath();
3183 type
->set_parent_path(w_attrib_path
);
3185 return w_attrib_path
;
3188 void Def_Type::set_parent_path(WithAttribPath
* p_path
)
3190 if (!w_attrib_path
) {
3191 w_attrib_path
= new WithAttribPath();
3192 type
->set_parent_path(w_attrib_path
);
3194 w_attrib_path
->set_parent(p_path
);
3197 // =================================
3199 // =================================
3201 Def_Const::Def_Const(Identifier
*p_id
, Type
*p_type
, Value
*p_value
)
3202 : Definition(A_CONST
, p_id
)
3204 if (!p_type
|| !p_value
) FATAL_ERROR("Ttcn::Def_Const::Def_Const()");
3206 type
->set_ownertype(Type::OT_CONST_DEF
, this);
3208 value_under_check
=false;
3211 Def_Const::~Def_Const()
3217 Def_Const
*Def_Const::clone() const
3219 FATAL_ERROR("Def_Const::clone");
3222 void Def_Const::set_fullname(const string
& p_fullname
)
3224 Definition::set_fullname(p_fullname
);
3225 type
->set_fullname(p_fullname
+ ".<type>");
3226 value
->set_fullname(p_fullname
);
3229 void Def_Const::set_my_scope(Scope
*p_scope
)
3231 Definition::set_my_scope(p_scope
);
3232 type
->set_my_scope(p_scope
);
3233 value
->set_my_scope(p_scope
);
3236 Setting
*Def_Const::get_Setting()
3241 Type
*Def_Const::get_Type()
3248 Value
*Def_Const::get_Value()
3254 void Def_Const::chk()
3257 if (value_under_check
) {
3258 error("Circular reference in constant definition `%s'",
3259 id
->get_dispname().c_str());
3260 value_under_check
= false; // only report the error once for this definition
3264 Error_Context
cntxt(this, "In constant definition `%s'",
3265 id
->get_dispname().c_str());
3266 type
->set_genname(_T_
, get_genname());
3268 value
->set_my_governor(type
);
3269 type
->chk_this_value_ref(value
);
3271 if (w_attrib_path
) {
3272 w_attrib_path
->chk_global_attrib(true);
3273 switch (type
->get_type_refd_last()->get_typetype_ttcn3()) {
3276 case Type::T_CHOICE_T
:
3277 // These types may have qualified attributes
3279 case Type::T_SEQOF
: case Type::T_SETOF
:
3282 w_attrib_path
->chk_no_qualif();
3286 Type
*t
= type
->get_type_refd_last();
3287 switch (t
->get_typetype()) {
3289 error("Constant cannot be defined for port type `%s'",
3290 t
->get_fullname().c_str());
3292 case Type::T_SIGNATURE
:
3293 error("Constant cannot be defined for signature `%s'",
3294 t
->get_fullname().c_str());
3297 value_under_check
= true;
3298 type
->chk_this_value(value
, 0, Type::EXPECTED_CONSTANT
, INCOMPLETE_ALLOWED
,
3299 OMIT_NOT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr());
3300 value_under_check
= false;
3301 chk_erroneous_attr();
3302 if (erroneous_attrs
) value
->set_err_descr(erroneous_attrs
->get_err_descr());
3304 ReferenceChain
refch(type
, "While checking embedded recursions");
3305 value
->chk_recursions(refch
);
3309 if (!semantic_check_only
) {
3310 value
->set_genname_prefix("const_");
3311 value
->set_genname_recursive(get_genname());
3312 value
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3316 bool Def_Const::chk_identical(Definition
*p_def
)
3320 if (p_def
->get_asstype() != A_CONST
) {
3321 const char *dispname_str
= id
->get_dispname().c_str();
3322 error("Local definition `%s' is a constant, but the definition "
3323 "inherited from component type `%s' is a %s", dispname_str
,
3324 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
3325 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
3328 Def_Const
*p_def_const
= dynamic_cast<Def_Const
*>(p_def
);
3329 if (!p_def_const
) FATAL_ERROR("Def_Const::chk_identical()");
3330 if (!type
->is_identical(p_def_const
->type
)) {
3331 const char *dispname_str
= id
->get_dispname().c_str();
3332 type
->error("Local constant `%s' has type `%s', but the constant "
3333 "inherited from component type `%s' has type `%s'", dispname_str
,
3334 type
->get_typename().c_str(),
3335 p_def_const
->get_my_scope()->get_fullname().c_str(),
3336 p_def_const
->type
->get_typename().c_str());
3337 p_def_const
->note("The inherited constant `%s' is here", dispname_str
);
3339 } else if (!(*value
== *p_def_const
->value
)) {
3340 const char *dispname_str
= id
->get_dispname().c_str();
3341 value
->error("Local constant `%s' and the constant inherited from "
3342 "component type `%s' have different values", dispname_str
,
3343 p_def_const
->get_my_scope()->get_fullname().c_str());
3344 p_def_const
->note("The inherited constant `%s' is here", dispname_str
);
3349 void Def_Const::generate_code(output_struct
*target
, bool)
3351 type
->generate_code(target
);
3353 Code::init_cdef(&cdef
);
3354 type
->generate_code_object(&cdef
, value
);
3355 cdef
.init
= update_location_object(cdef
.init
);
3356 cdef
.init
= value
->generate_code_init(cdef
.init
,
3357 value
->get_lhs_name().c_str());
3358 Code::merge_cdef(target
, &cdef
);
3359 Code::free_cdef(&cdef
);
3362 void Def_Const::generate_code(Common::CodeGenHelper
& cgh
) {
3363 // constant definitions always go to its containing module
3364 generate_code(cgh
.get_current_outputstruct());
3367 char *Def_Const::generate_code_str(char *str
)
3369 const string
& t_genname
= get_genname();
3370 const char *genname_str
= t_genname
.c_str();
3371 if (value
->has_single_expr()) {
3372 // the value can be represented by a single C++ expression
3373 // the object is initialized by the constructor
3374 str
= mputprintf(str
, "%s %s(%s);\n",
3375 type
->get_genname_value(my_scope
).c_str(), genname_str
,
3376 value
->get_single_expr().c_str());
3378 // use the default constructor
3379 str
= mputprintf(str
, "%s %s;\n",
3380 type
->get_genname_value(my_scope
).c_str(), genname_str
);
3381 // the value is assigned using subsequent statements
3382 str
= value
->generate_code_init(str
, genname_str
);
3387 void Def_Const::ilt_generate_code(ILT
*ilt
)
3389 const string
& t_genname
= get_genname();
3390 const char *genname_str
= t_genname
.c_str();
3391 char*& def
=ilt
->get_out_def();
3392 char*& init
=ilt
->get_out_branches();
3393 def
= mputprintf(def
, "%s %s;\n", type
->get_genname_value(my_scope
).c_str(),
3395 init
= value
->generate_code_init(init
, genname_str
);
3398 char *Def_Const::generate_code_init_comp(char *str
, Definition
*)
3400 /* This function actually does nothing as \a this and \a base_defn are
3401 * exactly the same. */
3405 void Def_Const::dump_internal(unsigned level
) const
3407 DEBUG(level
, "Constant: %s @%p", id
->get_dispname().c_str(), (const void*)this);
3408 type
->dump(level
+ 1);
3409 value
->dump(level
+ 1);
3412 // =================================
3413 // ===== Def_ExtConst
3414 // =================================
3416 Def_ExtConst::Def_ExtConst(Identifier
*p_id
, Type
*p_type
)
3417 : Definition(A_EXT_CONST
, p_id
)
3419 if (!p_type
) FATAL_ERROR("Ttcn::Def_ExtConst::Def_ExtConst()");
3421 type
->set_ownertype(Type::OT_CONST_DEF
, this);
3424 Def_ExtConst::~Def_ExtConst()
3429 Def_ExtConst
*Def_ExtConst::clone() const
3431 FATAL_ERROR("Def_ExtConst::clone");
3434 void Def_ExtConst::set_fullname(const string
& p_fullname
)
3436 Definition::set_fullname(p_fullname
);
3437 type
->set_fullname(p_fullname
+ ".<type>");
3440 void Def_ExtConst::set_my_scope(Scope
*p_scope
)
3442 Definition::set_my_scope(p_scope
);
3443 type
->set_my_scope(p_scope
);
3446 Type
*Def_ExtConst::get_Type()
3452 void Def_ExtConst::chk()
3455 Error_Context
cntxt(this, "In external constant definition `%s'",
3456 id
->get_dispname().c_str());
3457 type
->set_genname(_T_
, get_genname());
3460 Type
*t
= type
->get_type_refd_last();
3461 switch (t
->get_typetype()) {
3463 error("External constant cannot be defined for port type `%s'",
3464 t
->get_fullname().c_str());
3466 case Type::T_SIGNATURE
:
3467 error("External constant cannot be defined for signature `%s'",
3468 t
->get_fullname().c_str());
3473 if (w_attrib_path
) {
3474 w_attrib_path
->chk_global_attrib();
3475 switch (type
->get_type_refd_last()->get_typetype()) {
3478 case Type::T_CHOICE_T
:
3479 // These types may have qualified attributes
3481 case Type::T_SEQOF
: case Type::T_SETOF
:
3484 w_attrib_path
->chk_no_qualif();
3490 void Def_ExtConst::generate_code(output_struct
*target
, bool)
3492 type
->generate_code(target
);
3493 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
3494 "extern const %s& %s;\n", type
->get_genname_value(my_scope
).c_str(),
3495 get_genname().c_str());
3498 void Def_ExtConst::generate_code(Common::CodeGenHelper
& cgh
) {
3499 // constant definitions always go to its containing module
3500 generate_code(cgh
.get_current_outputstruct());
3503 void Def_ExtConst::dump_internal(unsigned level
) const
3505 DEBUG(level
, "External constant: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3506 type
->dump(level
+ 1);
3509 // =================================
3510 // ===== Def_Modulepar
3511 // =================================
3513 Def_Modulepar::Def_Modulepar(Identifier
*p_id
, Type
*p_type
, Value
*p_defval
)
3514 : Definition(A_MODULEPAR
, p_id
)
3516 if (!p_type
) FATAL_ERROR("Ttcn::Def_Modulepar::Def_Modulepar()");
3518 type
->set_ownertype(Type::OT_MODPAR_DEF
, this);
3519 def_value
= p_defval
;
3522 Def_Modulepar::~Def_Modulepar()
3528 Def_Modulepar
* Def_Modulepar::clone() const
3530 FATAL_ERROR("Def_Modulepar::clone");
3533 void Def_Modulepar::set_fullname(const string
& p_fullname
)
3535 Definition::set_fullname(p_fullname
);
3536 type
->set_fullname(p_fullname
+ ".<type>");
3537 if (def_value
) def_value
->set_fullname(p_fullname
+ ".<default_value>");
3540 void Def_Modulepar::set_my_scope(Scope
*p_scope
)
3542 Definition::set_my_scope(p_scope
);
3543 type
->set_my_scope(p_scope
);
3544 if (def_value
) def_value
->set_my_scope(p_scope
);
3547 Type
*Def_Modulepar::get_Type()
3553 void Def_Modulepar::chk()
3556 Error_Context
cntxt(this, "In module parameter definition `%s'",
3557 id
->get_dispname().c_str());
3558 type
->set_genname(_T_
, get_genname());
3560 if (w_attrib_path
) {
3561 w_attrib_path
->chk_global_attrib();
3562 switch (type
->get_type_refd_last()->get_typetype()) {
3565 case Type::T_CHOICE_T
:
3566 // These types may have qualified attributes
3568 case Type::T_SEQOF
: case Type::T_SETOF
:
3571 w_attrib_path
->chk_no_qualif();
3575 map
<Type
*,void> type_chain
;
3576 map
<Type::typetype_t
, void> not_allowed
;
3577 not_allowed
.add(Type::T_PORT
, 0);
3578 Type
*t
= type
->get_type_refd_last();
3579 // if the type is valid the original will be returned
3580 Type::typetype_t tt
= t
->search_for_not_allowed_type(type_chain
, not_allowed
);
3582 not_allowed
.clear();
3585 error("Type of module parameter cannot be or embed port type `%s'",
3586 t
->get_fullname().c_str());
3588 case Type::T_SIGNATURE
:
3589 error("Type of module parameter cannot be signature `%s'",
3590 t
->get_fullname().c_str());
3592 case Type::T_FUNCTION
:
3593 case Type::T_ALTSTEP
:
3594 case Type::T_TESTCASE
:
3595 if (t
->get_fat_runs_on_self()) {
3596 error("Type of module parameter cannot be of function reference type"
3597 " `%s' which has runs on self clause", t
->get_fullname().c_str());
3605 Error_Context
cntxt2(def_value
, "In default value");
3606 def_value
->set_my_governor(type
);
3607 type
->chk_this_value_ref(def_value
);
3609 type
->chk_this_value(def_value
, 0, Type::EXPECTED_CONSTANT
, INCOMPLETE_ALLOWED
,
3610 OMIT_NOT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr());
3611 if (!semantic_check_only
) {
3612 def_value
->set_genname_prefix("modulepar_");
3613 def_value
->set_genname_recursive(get_genname());
3614 def_value
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3616 } else checked
= true;
3622 void Def_Modulepar::generate_code(output_struct
*target
, bool)
3624 type
->generate_code(target
);
3626 Code::init_cdef(&cdef
);
3627 const string
& t_genname
= get_genname();
3628 const char *name
= t_genname
.c_str();
3629 type
->generate_code_object(&cdef
, my_scope
, t_genname
, "modulepar_", false);
3631 cdef
.init
= update_location_object(cdef
.init
);
3632 cdef
.init
= def_value
->generate_code_init(cdef
.init
, def_value
->get_lhs_name().c_str());
3634 Code::merge_cdef(target
, &cdef
);
3635 Code::free_cdef(&cdef
);
3637 if (has_implicit_omit_attr()) {
3638 target
->functions
.post_init
= mputprintf(target
->functions
.post_init
,
3639 "modulepar_%s.set_implicit_omit();\n", name
);
3642 const char *dispname
= id
->get_dispname().c_str();
3643 target
->functions
.set_param
= mputprintf(target
->functions
.set_param
,
3644 "if (!strcmp(par_name, \"%s\")) {\n"
3645 "modulepar_%s.set_param(param);\n"
3647 "} else ", dispname
, name
);
3648 target
->functions
.get_param
= mputprintf(target
->functions
.get_param
,
3649 "if (!strcmp(par_name, \"%s\")) {\n"
3650 "return modulepar_%s.get_param(param_name);\n"
3651 "} else ", dispname
, name
);
3653 if (target
->functions
.log_param
) {
3654 // this is not the first modulepar
3655 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3656 "TTCN_Logger::log_event_str(\", %s := \");\n", dispname
);
3658 // this is the first modulepar
3659 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3660 "TTCN_Logger::log_event_str(\"%s := \");\n", dispname
);
3662 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3663 "%s.log();\n", name
);
3666 void Def_Modulepar::generate_code(Common::CodeGenHelper
& cgh
) {
3667 // module parameter definitions always go to its containing module
3668 generate_code(cgh
.get_current_outputstruct());
3671 void Def_Modulepar::dump_internal(unsigned level
) const
3673 DEBUG(level
, "Module parameter: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3674 type
->dump(level
+ 1);
3675 if (def_value
) def_value
->dump(level
+ 1);
3676 else DEBUG(level
+ 1, "No default value");
3679 // =================================
3680 // ===== Def_Modulepar_Template
3681 // =================================
3683 Def_Modulepar_Template::Def_Modulepar_Template(Identifier
*p_id
, Type
*p_type
, Template
*p_deftmpl
)
3684 : Definition(A_MODULEPAR_TEMP
, p_id
)
3686 if (!p_type
) FATAL_ERROR("Ttcn::Def_Modulepar_Template::Def_Modulepar_Template()");
3688 type
->set_ownertype(Type::OT_MODPAR_DEF
, this);
3689 def_template
= p_deftmpl
;
3692 Def_Modulepar_Template::~Def_Modulepar_Template()
3695 delete def_template
;
3698 Def_Modulepar_Template
* Def_Modulepar_Template::clone() const
3700 FATAL_ERROR("Def_Modulepar_Template::clone");
3703 void Def_Modulepar_Template::set_fullname(const string
& p_fullname
)
3705 Definition::set_fullname(p_fullname
);
3706 type
->set_fullname(p_fullname
+ ".<type>");
3707 if (def_template
) def_template
->set_fullname(p_fullname
+ ".<default_template>");
3710 void Def_Modulepar_Template::set_my_scope(Scope
*p_scope
)
3712 Definition::set_my_scope(p_scope
);
3713 type
->set_my_scope(p_scope
);
3714 if (def_template
) def_template
->set_my_scope(p_scope
);
3717 Type
*Def_Modulepar_Template::get_Type()
3723 void Def_Modulepar_Template::chk()
3726 Error_Context
cntxt(this, "In template module parameter definition `%s'",
3727 id
->get_dispname().c_str());
3728 if (w_attrib_path
) {
3729 w_attrib_path
->chk_global_attrib();
3730 switch (type
->get_type_refd_last()->get_typetype()) {
3733 case Type::T_CHOICE_T
:
3734 // These types may have qualified attributes
3736 case Type::T_SEQOF
: case Type::T_SETOF
:
3739 w_attrib_path
->chk_no_qualif();
3743 type
->set_genname(_T_
, get_genname());
3745 Type
*t
= type
->get_type_refd_last();
3746 switch (t
->get_typetype()) {
3748 error("Type of template module parameter cannot be port type `%s'",
3749 t
->get_fullname().c_str());
3751 case Type::T_SIGNATURE
:
3752 error("Type of template module parameter cannot be signature `%s'",
3753 t
->get_fullname().c_str());
3755 case Type::T_FUNCTION
:
3756 case Type::T_ALTSTEP
:
3757 case Type::T_TESTCASE
:
3758 if (t
->get_fat_runs_on_self()) {
3759 error("Type of template module parameter cannot be of function reference type"
3760 " `%s' which has runs on self clause", t
->get_fullname().c_str());
3764 if (has_implicit_omit_attr()) {
3765 error("Implicit omit not supported for template module parameters");
3771 Error_Context
cntxt2(def_template
, "In default template");
3772 def_template
->set_my_governor(type
);
3773 def_template
->flatten(false);
3774 if (def_template
->get_templatetype() == Template::CSTR_PATTERN
&&
3775 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
3776 def_template
->set_templatetype(Template::USTR_PATTERN
);
3777 def_template
->get_ustr_pattern()->set_pattern_type(
3778 PatternString::USTR_PATTERN
);
3780 type
->chk_this_template_ref(def_template
);
3782 type
->chk_this_template_generic(def_template
, INCOMPLETE_ALLOWED
,
3783 OMIT_ALLOWED
, ANY_OR_OMIT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr() ? IMPLICIT_OMIT
: NOT_IMPLICIT_OMIT
, 0);
3784 if (!semantic_check_only
) {
3785 def_template
->set_genname_prefix("modulepar_");
3786 def_template
->set_genname_recursive(get_genname());
3787 def_template
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3789 } else checked
= true;
3795 void Def_Modulepar_Template::generate_code(output_struct
*target
, bool)
3797 type
->generate_code(target
);
3799 Code::init_cdef(&cdef
);
3800 const string
& t_genname
= get_genname();
3801 const char *name
= t_genname
.c_str();
3802 type
->generate_code_object(&cdef
, my_scope
, t_genname
, "modulepar_", true);
3804 cdef
.init
= update_location_object(cdef
.init
);
3805 cdef
.init
= def_template
->generate_code_init(cdef
.init
, def_template
->get_lhs_name().c_str());
3807 Code::merge_cdef(target
, &cdef
);
3808 Code::free_cdef(&cdef
);
3810 if (has_implicit_omit_attr()) {
3811 FATAL_ERROR("Def_Modulepar_Template::generate_code()");
3814 const char *dispname
= id
->get_dispname().c_str();
3815 target
->functions
.set_param
= mputprintf(target
->functions
.set_param
,
3816 "if (!strcmp(par_name, \"%s\")) {\n"
3817 "modulepar_%s.set_param(param);\n"
3819 "} else ", dispname
, name
);
3820 target
->functions
.get_param
= mputprintf(target
->functions
.get_param
,
3821 "if (!strcmp(par_name, \"%s\")) {\n"
3822 "return modulepar_%s.get_param(param_name);\n"
3823 "} else ", dispname
, name
);
3825 if (target
->functions
.log_param
) {
3826 // this is not the first modulepar
3827 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3828 "TTCN_Logger::log_event_str(\", %s := \");\n", dispname
);
3830 // this is the first modulepar
3831 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3832 "TTCN_Logger::log_event_str(\"%s := \");\n", dispname
);
3834 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3835 "%s.log();\n", name
);
3838 void Def_Modulepar_Template::generate_code(Common::CodeGenHelper
& cgh
) {
3839 // module parameter definitions always go to its containing module
3840 generate_code(cgh
.get_current_outputstruct());
3843 void Def_Modulepar_Template::dump_internal(unsigned level
) const
3845 DEBUG(level
, "Module parameter: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3846 type
->dump(level
+ 1);
3847 if (def_template
) def_template
->dump(level
+ 1);
3848 else DEBUG(level
+ 1, "No default template");
3851 // =================================
3852 // ===== Def_Template
3853 // =================================
3855 Def_Template::Def_Template(template_restriction_t p_template_restriction
,
3856 Identifier
*p_id
, Type
*p_type
, FormalParList
*p_fpl
,
3857 Reference
*p_derived_ref
, Template
*p_body
)
3858 : Definition(A_TEMPLATE
, p_id
), type(p_type
), fp_list(p_fpl
),
3859 derived_ref(p_derived_ref
), base_template(0), recurs_deriv_checked(false),
3860 body(p_body
), template_restriction(p_template_restriction
),
3861 gen_restriction_check(false)
3863 if (!p_type
|| !p_body
) FATAL_ERROR("Ttcn::Def_Template::Def_Template()");
3864 type
->set_ownertype(Type::OT_TEMPLATE_DEF
, this);
3865 if (fp_list
) fp_list
->set_my_def(this);
3868 Def_Template::~Def_Template()
3876 Def_Template
*Def_Template::clone() const
3878 FATAL_ERROR("Def_Template::clone");
3881 void Def_Template::set_fullname(const string
& p_fullname
)
3883 Definition::set_fullname(p_fullname
);
3884 type
->set_fullname(p_fullname
+ ".<type>");
3885 if (fp_list
) fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
3887 derived_ref
->set_fullname(p_fullname
+ ".<derived_reference>");
3888 body
->set_fullname(p_fullname
);
3891 void Def_Template::set_my_scope(Scope
*p_scope
)
3893 bridgeScope
.set_parent_scope(p_scope
);
3894 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
3896 Definition::set_my_scope(&bridgeScope
);
3897 type
->set_my_scope(&bridgeScope
);
3898 if (derived_ref
) derived_ref
->set_my_scope(&bridgeScope
);
3900 fp_list
->set_my_scope(&bridgeScope
);
3901 body
->set_my_scope(fp_list
);
3902 } else body
->set_my_scope(&bridgeScope
);
3905 Setting
*Def_Template::get_Setting()
3907 return get_Template();
3910 Type
*Def_Template::get_Type()
3912 if (!checked
) chk();
3916 Template
*Def_Template::get_Template()
3918 if (!checked
) chk();
3922 FormalParList
*Def_Template::get_FormalParList()
3924 if (!checked
) chk();
3928 void Def_Template::chk()
3930 if (checked
) return;
3931 Error_Context
cntxt(this, "In template definition `%s'",
3932 id
->get_dispname().c_str());
3933 const string
& t_genname
= get_genname();
3934 type
->set_genname(_T_
, t_genname
);
3936 if (w_attrib_path
) {
3937 w_attrib_path
->chk_global_attrib(true);
3938 switch (type
->get_type_refd_last()->get_typetype_ttcn3()) {
3941 case Type::T_CHOICE_T
:
3942 // These types may have qualified attributes
3944 case Type::T_SEQOF
: case Type::T_SETOF
:
3947 w_attrib_path
->chk_no_qualif();
3953 fp_list
->chk(asstype
);
3954 if (local_scope
) error("Parameterized local template `%s' not supported",
3955 id
->get_dispname().c_str());
3958 // Merge the elements of "all from" into the list
3959 body
->flatten(false);
3961 body
->set_my_governor(type
);
3963 if (body
->get_templatetype() == Template::CSTR_PATTERN
&&
3964 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
3965 body
->set_templatetype(Template::USTR_PATTERN
);
3966 body
->get_ustr_pattern()->set_pattern_type(PatternString::USTR_PATTERN
);
3969 type
->chk_this_template_ref(body
);
3971 Type
*t
= type
->get_type_refd_last();
3972 if (t
->get_typetype() == Type::T_PORT
) {
3973 error("Template cannot be defined for port type `%s'",
3974 t
->get_fullname().c_str());
3977 chk_recursive_derivation();
3978 type
->chk_this_template_generic(body
, INCOMPLETE_ALLOWED
, OMIT_ALLOWED
,
3979 ANY_OR_OMIT_ALLOWED
, SUB_CHK
,
3980 has_implicit_omit_attr() ? IMPLICIT_OMIT
: NOT_IMPLICIT_OMIT
, 0);
3982 chk_erroneous_attr();
3983 if (erroneous_attrs
) body
->set_err_descr(erroneous_attrs
->get_err_descr());
3986 ReferenceChain
refch(type
, "While checking embedded recursions");
3987 body
->chk_recursions(refch
);
3989 if (template_restriction
!=TR_NONE
) {
3990 Error_Context
ec(this, "While checking template restriction `%s'",
3991 Template::get_restriction_name(template_restriction
));
3992 gen_restriction_check
=
3993 body
->chk_restriction("template definition", template_restriction
, body
);
3994 if (fp_list
&& template_restriction
!=TR_PRESENT
) {
3995 size_t nof_fps
= fp_list
->get_nof_fps();
3996 for (size_t i
=0; i
<nof_fps
; i
++) {
3997 FormalPar
* fp
= fp_list
->get_fp_byIndex(i
);
3998 // if formal par is not template then skip restriction checking,
3999 // templates can have only `in' parameters
4000 if (fp
->get_asstype()!=A_PAR_TEMPL_IN
) continue;
4001 template_restriction_t fp_tr
= fp
->get_template_restriction();
4002 switch (template_restriction
) {
4011 fp
->error("Formal parameter with template restriction `%s' "
4012 "not allowed here", Template::get_restriction_name(fp_tr
));
4015 fp
->error("Formal parameter without template restriction "
4016 "not allowed here");
4019 FATAL_ERROR("Ttcn::Def_Template::chk()");
4023 FATAL_ERROR("Ttcn::Def_Template::chk()");
4028 if (!semantic_check_only
) {
4029 if (fp_list
) fp_list
->set_genname(t_genname
);
4030 body
->set_genname_prefix("template_");
4031 body
->set_genname_recursive(t_genname
);
4032 body
->set_code_section(fp_list
? GovernedSimple::CS_INLINE
:
4033 GovernedSimple::CS_POST_INIT
);
4038 void Def_Template::chk_default() const
4040 if (!fp_list
) FATAL_ERROR("Def_Template::chk_default()");
4042 if (fp_list
->has_notused_defval())
4043 fp_list
->error("Only modified templates are allowed to use the not "
4044 "used symbol (`-') as the default parameter");
4047 Common::Assignment
*ass
= derived_ref
->get_refd_assignment(false);
4048 if (!ass
|| ass
->get_asstype() != A_TEMPLATE
) return; // Work locally.
4049 Def_Template
*base
= dynamic_cast<Def_Template
*>(ass
);
4050 if (!base
) FATAL_ERROR("Def_Template::chk_default()");
4051 FormalParList
*base_fpl
= base
->get_FormalParList();
4052 size_t nof_base_fps
= base_fpl
? base_fpl
->get_nof_fps() : 0;
4053 size_t nof_local_fps
= fp_list
? fp_list
->get_nof_fps() : 0;
4054 size_t min_fps
= nof_base_fps
;
4055 if (nof_local_fps
< nof_base_fps
) min_fps
= nof_local_fps
;
4056 for (size_t i
= 0; i
< min_fps
; i
++) {
4057 FormalPar
*base_fp
= base_fpl
->get_fp_byIndex(i
);
4058 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4059 if (local_fp
->has_notused_defval()) {
4060 if (base_fp
->has_defval()) {
4061 local_fp
->set_defval(base_fp
->get_defval());
4063 local_fp
->error("Not used symbol (`-') doesn't have the "
4064 "corresponding default parameter in the "
4069 // Additional parameters in the derived template with using the not used
4070 // symbol. TODO: Merge the loops.
4071 for (size_t i
= nof_base_fps
; i
< nof_local_fps
; i
++) {
4072 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4073 if (local_fp
->has_notused_defval())
4074 local_fp
->error("Not used symbol (`-') doesn't have the "
4075 "corresponding default parameter in the "
4080 void Def_Template::chk_modified()
4082 if (!derived_ref
) return;
4083 // Do not check the (non-existent) actual parameter list of the derived
4084 // reference against the formal parameter list of the base template.
4085 // According to TTCN-3 syntax the derived reference cannot have parameters
4086 // even if the base template is parameterized.
4087 Common::Assignment
*ass
= derived_ref
->get_refd_assignment(false);
4088 // Checking the existence and type compatibility of the base template.
4090 if (ass
->get_asstype() != A_TEMPLATE
) {
4091 derived_ref
->error("Reference to a template was expected in the "
4092 "`modifies' definition instead of %s",
4093 ass
->get_description().c_str());
4096 base_template
= dynamic_cast<Def_Template
*>(ass
);
4097 if (!base_template
) FATAL_ERROR("Def_Template::chk_modified()");
4098 Type
*base_type
= base_template
->get_Type();
4099 TypeCompatInfo
info_base(my_scope
->get_scope_mod(), type
, base_type
, true,
4101 TypeChain l_chain_base
;
4102 TypeChain r_chain_base
;
4103 if (!type
->is_compatible(base_type
, &info_base
, &l_chain_base
,
4105 if (info_base
.is_subtype_error()) {
4106 type
->error("%s", info_base
.get_subtype_error().c_str());
4108 if (!info_base
.is_erroneous()) {
4109 type
->error("The modified template has different type than base "
4110 "template `%s': `%s' was expected instead of `%s'",
4111 ass
->get_fullname().c_str(),
4112 base_type
->get_typename().c_str(),
4113 type
->get_typename().c_str());
4115 // Always use the format string.
4116 type
->error("%s", info_base
.get_error_str_str().c_str());
4119 if (info_base
.needs_conversion())
4120 body
->set_needs_conversion();
4122 // Check for restriction.
4123 if (Template::is_less_restrictive(base_template
->get_template_restriction(),
4124 template_restriction
)) {
4125 error("The template restriction is not the same or more "
4126 "restrictive as of base template `%s'", ass
->get_fullname().c_str());
4128 // Checking formal parameter lists.
4129 FormalParList
*base_fpl
= base_template
->get_FormalParList();
4130 size_t nof_base_fps
= base_fpl
? base_fpl
->get_nof_fps() : 0;
4131 size_t nof_local_fps
= fp_list
? fp_list
->get_nof_fps() : 0;
4133 if (nof_local_fps
< nof_base_fps
) {
4134 error("The modified template has fewer formal parameters than base "
4135 "template `%s': at least %lu parameter%s expected instead of %lu",
4136 ass
->get_fullname().c_str(), (unsigned long)nof_base_fps
,
4137 nof_base_fps
> 1 ? "s were" : " was", (unsigned long)nof_local_fps
);
4138 min_fps
= nof_local_fps
;
4139 } else min_fps
= nof_base_fps
;
4141 for (size_t i
= 0; i
< min_fps
; i
++) {
4142 FormalPar
*base_fp
= base_fpl
->get_fp_byIndex(i
);
4143 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4144 Error_Context
cntxt(local_fp
, "In formal parameter #%lu",
4145 (unsigned long)(i
+ 1));
4146 // Check for parameter kind equivalence (value or template).
4147 if (base_fp
->get_asstype() != local_fp
->get_asstype())
4148 local_fp
->error("The kind of parameter is not the same as in base "
4149 "template `%s': %s was expected instead of %s",
4150 ass
->get_fullname().c_str(), base_fp
->get_assname(),
4151 local_fp
->get_assname());
4152 // Check for type compatibility.
4153 Type
*base_fp_type
= base_fp
->get_Type();
4154 Type
*local_fp_type
= local_fp
->get_Type();
4155 TypeCompatInfo
info_par(my_scope
->get_scope_mod(), base_fp_type
,
4156 local_fp_type
, true, false);
4157 TypeChain l_chain_par
;
4158 TypeChain r_chain_par
;
4159 if (!base_fp_type
->is_compatible(local_fp_type
, &info_par
, &l_chain_par
,
4161 if (info_par
.is_subtype_error()) {
4162 local_fp_type
->error("%s", info_par
.get_subtype_error().c_str());
4164 if (!info_par
.is_erroneous()) {
4165 local_fp_type
->error("The type of parameter is not the same as in "
4166 "base template `%s': `%s' was expected instead "
4168 ass
->get_fullname().c_str(),
4169 base_fp_type
->get_typename().c_str(),
4170 local_fp_type
->get_typename().c_str());
4172 local_fp_type
->error("%s", info_par
.get_error_str_str().c_str());
4175 if (info_par
.needs_conversion())
4176 body
->set_needs_conversion();
4178 // Check for name equivalence.
4179 const Identifier
& base_fp_id
= base_fp
->get_id();
4180 const Identifier
& local_fp_id
= local_fp
->get_id();
4181 if (!(base_fp_id
== local_fp_id
))
4182 local_fp
->error("The name of parameter is not the same as in base "
4183 "template `%s': `%s' was expected instead of `%s'",
4184 ass
->get_fullname().c_str(),
4185 base_fp_id
.get_dispname().c_str(),
4186 local_fp_id
.get_dispname().c_str());
4187 // Check for restrictions: the derived must be same or more restrictive.
4188 if (base_fp
->get_asstype()==local_fp
->get_asstype() &&
4189 Template::is_less_restrictive(base_fp
->get_template_restriction(),
4190 local_fp
->get_template_restriction())) {
4191 local_fp
->error("The restriction of parameter is not the same or more "
4192 "restrictive as in base template `%s'", ass
->get_fullname().c_str());
4195 // Set the pointer to the body of base template.
4196 body
->set_base_template(base_template
->get_Template());
4199 void Def_Template::chk_recursive_derivation()
4201 if (recurs_deriv_checked
) return;
4202 if (base_template
) {
4203 ReferenceChain
refch(this, "While checking the chain of base templates");
4204 refch
.add(get_fullname());
4205 for (Def_Template
*iter
= base_template
; iter
; iter
= iter
->base_template
)
4207 if (iter
->recurs_deriv_checked
) break;
4208 else if (refch
.add(iter
->get_fullname()))
4209 iter
->recurs_deriv_checked
= true;
4213 recurs_deriv_checked
= true;
4216 void Def_Template::generate_code(output_struct
*target
, bool)
4218 type
->generate_code(target
);
4220 // Parameterized template. Generate code for a function which returns
4221 // a $(genname)_template and has the appropriate parameters.
4222 const string
& t_genname
= get_genname();
4223 const char *template_name
= t_genname
.c_str();
4224 const char *template_dispname
= id
->get_dispname().c_str();
4225 const string
& type_genname
= type
->get_genname_template(my_scope
);
4226 const char *type_genname_str
= type_genname
.c_str();
4228 // assemble the function body first (this also determines which parameters
4230 size_t nof_base_pars
= 0;
4231 char* function_body
= create_location_object(memptystr(), "TEMPLATE",
4233 if (base_template
) {
4234 // modified template
4235 function_body
= mputprintf(function_body
, "%s ret_val(%s",
4237 base_template
->get_genname_from_scope(my_scope
).c_str());
4238 if (base_template
->fp_list
) {
4239 // the base template is also parameterized
4240 function_body
= mputc(function_body
, '(');
4241 nof_base_pars
= base_template
->fp_list
->get_nof_fps();
4242 for (size_t i
= 0; i
< nof_base_pars
; i
++) {
4243 if (i
> 0) function_body
= mputstr(function_body
, ", ");
4244 function_body
= mputstr(function_body
,
4245 fp_list
->get_fp_byIndex(i
)->get_id().get_name().c_str());
4247 function_body
= mputc(function_body
, ')');
4249 function_body
= mputstr(function_body
, ");\n");
4252 function_body
= mputprintf(function_body
, "%s ret_val;\n",
4255 if (erroneous_attrs
&& erroneous_attrs
->get_err_descr()) {
4256 function_body
= erroneous_attrs
->get_err_descr()->
4257 generate_code_str(function_body
, string("ret_val"));
4259 function_body
= body
->generate_code_init(function_body
, "ret_val");
4260 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4261 function_body
= Template::generate_restriction_check_code(function_body
,
4262 "ret_val", template_restriction
);
4263 function_body
= mputstr(function_body
, "return ret_val;\n");
4264 // if the template modifies a parameterized template, then the inherited
4265 // formal parameters must always be displayed, otherwise generate a smart
4266 // formal parameter list (where the names of unused parameters are omitted)
4267 char *formal_par_list
= fp_list
->generate_code(memptystr(), nof_base_pars
);
4268 fp_list
->generate_code_defval(target
);
4270 target
->header
.function_prototypes
=
4271 mputprintf(target
->header
.function_prototypes
,
4272 "extern %s %s(%s);\n",
4273 type_genname_str
, template_name
, formal_par_list
);
4274 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
4278 "}\n\n", type_genname_str
, template_name
, formal_par_list
, function_body
);
4279 Free(formal_par_list
);
4280 Free(function_body
);
4282 // non-parameterized template
4284 Code::init_cdef(&cdef
);
4285 type
->generate_code_object(&cdef
, body
);
4286 cdef
.init
= update_location_object(cdef
.init
);
4287 if (base_template
) {
4288 // modified template
4289 if (base_template
->my_scope
->get_scope_mod_gen() ==
4290 my_scope
->get_scope_mod_gen()) {
4291 // if the base template is in the same module its body has to be
4292 // initialized first
4293 cdef
.init
= base_template
->body
->generate_code_init(cdef
.init
,
4294 base_template
->body
->get_lhs_name().c_str());
4296 if (use_runtime_2
&& body
->get_needs_conversion()) {
4297 Type
*body_type
= body
->get_my_governor()->get_type_refd_last();
4298 Type
*base_type
= base_template
->body
->get_my_governor()
4299 ->get_type_refd_last();
4300 if (!body_type
|| !base_type
)
4301 FATAL_ERROR("Def_Template::generate_code()");
4302 const string
& tmp_id
= body
->get_temporary_id();
4303 const char *tmp_id_str
= tmp_id
.c_str();
4304 // base template initialization
4305 cdef
.init
= mputprintf(cdef
.init
,
4307 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' "
4308 "and `%s' are not compatible at run-time\");\n"
4310 body_type
->get_genname_template(my_scope
).c_str(), tmp_id_str
,
4311 TypeConv::get_conv_func(base_type
, body_type
, my_scope
4312 ->get_scope_mod()).c_str(), tmp_id_str
, base_template
4313 ->get_genname_from_scope(my_scope
).c_str(), base_type
4314 ->get_typename().c_str(), body_type
->get_typename().c_str(),
4315 body
->get_lhs_name().c_str(), tmp_id_str
);
4317 cdef
.init
= mputprintf(cdef
.init
, "%s = %s;\n",
4318 body
->get_lhs_name().c_str(),
4319 base_template
->get_genname_from_scope(my_scope
).c_str());
4322 if (use_runtime_2
&& TypeConv::needs_conv_refd(body
))
4323 cdef
.init
= TypeConv::gen_conv_code_refd(cdef
.init
,
4324 body
->get_lhs_name().c_str(), body
);
4326 cdef
.init
= body
->generate_code_init(cdef
.init
,
4327 body
->get_lhs_name().c_str());
4328 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4329 cdef
.init
= Template::generate_restriction_check_code(cdef
.init
,
4330 body
->get_lhs_name().c_str(), template_restriction
);
4331 target
->header
.global_vars
= mputstr(target
->header
.global_vars
,
4333 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
4335 target
->functions
.post_init
= mputstr(target
->functions
.post_init
,
4337 Code::free_cdef(&cdef
);
4341 void Def_Template::generate_code(Common::CodeGenHelper
& cgh
) {
4342 generate_code(cgh
.get_outputstruct(this));
4345 char *Def_Template::generate_code_str(char *str
)
4347 const string
& t_genname
= get_genname();
4348 const char *genname_str
= t_genname
.c_str();
4349 const string
& type_genname
= type
->get_genname_template(my_scope
);
4350 const char *type_genname_str
= type_genname
.c_str();
4352 const char *dispname_str
= id
->get_dispname().c_str();
4353 NOTSUPP("Code generation for parameterized local template `%s'",
4355 str
= mputprintf(str
, "/* NOT SUPPORTED: template %s */\n",
4358 if (base_template
) {
4359 // non-parameterized modified template
4360 if (use_runtime_2
&& body
->get_needs_conversion()) {
4361 Type
*body_type
= body
->get_my_governor()->get_type_refd_last();
4362 Type
*base_type
= base_template
->body
->get_my_governor()
4363 ->get_type_refd_last();
4364 if (!body_type
|| !base_type
)
4365 FATAL_ERROR("Def_Template::generate_code_str()");
4366 const string
& tmp_id
= body
->get_temporary_id();
4367 const char *tmp_id_str
= tmp_id
.c_str();
4368 str
= mputprintf(str
,
4370 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' "
4371 "and `%s' are not compatible at run-time\");\n"
4373 body_type
->get_genname_template(my_scope
).c_str(), tmp_id_str
,
4374 TypeConv::get_conv_func(base_type
, body_type
, my_scope
4375 ->get_scope_mod()).c_str(), tmp_id_str
, base_template
4376 ->get_genname_from_scope(my_scope
).c_str(), base_type
4377 ->get_typename().c_str(), body_type
->get_typename().c_str(),
4378 type_genname_str
, genname_str
, tmp_id_str
);
4380 // the object is initialized from the base template by the
4382 str
= mputprintf(str
, "%s %s(%s);\n", type_genname_str
, genname_str
,
4383 base_template
->get_genname_from_scope(my_scope
).c_str());
4385 // the modified body is assigned in the subsequent statements
4386 str
= body
->generate_code_init(str
, genname_str
);
4388 // non-parameterized non-modified template
4389 if (body
->has_single_expr()) {
4390 // the object is initialized by the constructor
4391 str
= mputprintf(str
, "%s %s(%s);\n", type_genname_str
,
4392 genname_str
, body
->get_single_expr(false).c_str());
4393 // make sure the template's code is not generated twice (TR: HU56425)
4394 body
->set_code_generated();
4396 // the default constructor is used
4397 str
= mputprintf(str
, "%s %s;\n", type_genname_str
, genname_str
);
4398 // the body is assigned in the subsequent statements
4399 str
= body
->generate_code_init(str
, genname_str
);
4402 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4403 str
= Template::generate_restriction_check_code(str
, genname_str
,
4404 template_restriction
);
4409 void Def_Template::ilt_generate_code(ILT
*ilt
)
4411 const string
& t_genname
= get_genname();
4412 const char *genname_str
= t_genname
.c_str();
4413 char*& def
=ilt
->get_out_def();
4414 char*& init
=ilt
->get_out_branches();
4416 const char *dispname_str
= id
->get_dispname().c_str();
4417 NOTSUPP("Code generation for parameterized local template `%s'",
4419 def
= mputprintf(def
, "/* NOT SUPPORTED: template %s */\n", dispname_str
);
4420 init
= mputprintf(init
, "/* NOT SUPPORTED: template %s */\n",
4423 // non-parameterized template
4424 // use the default constructor for initialization
4425 def
= mputprintf(def
, "%s %s;\n",
4426 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4427 if (base_template
) {
4428 // copy the base template with an assignment
4429 init
= mputprintf(init
, "%s = %s;\n", genname_str
,
4430 base_template
->get_genname_from_scope(my_scope
).c_str());
4432 // finally assign the body
4433 init
= body
->generate_code_init(init
, genname_str
);
4434 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4435 init
= Template::generate_restriction_check_code(init
, genname_str
,
4436 template_restriction
);
4440 void Def_Template::dump_internal(unsigned level
) const
4442 DEBUG(level
, "Template: %s", id
->get_dispname().c_str());
4443 if (fp_list
) fp_list
->dump(level
+ 1);
4445 DEBUG(level
+ 1, "modifies: %s", derived_ref
->get_dispname().c_str());
4446 if (template_restriction
!=TR_NONE
)
4447 DEBUG(level
+ 1, "restriction: %s",
4448 Template::get_restriction_name(template_restriction
));
4449 type
->dump(level
+ 1);
4450 body
->dump(level
+ 1);
4453 // =================================
4455 // =================================
4457 Def_Var::Def_Var(Identifier
*p_id
, Type
*p_type
, Value
*p_initial_value
)
4458 : Definition(A_VAR
, p_id
), type(p_type
), initial_value(p_initial_value
)
4460 if (!p_type
) FATAL_ERROR("Ttcn::Def_Var::Def_Var()");
4461 type
->set_ownertype(Type::OT_VAR_DEF
, this);
4467 delete initial_value
;
4470 Def_Var
*Def_Var::clone() const
4472 FATAL_ERROR("Def_Var::clone");
4475 void Def_Var::set_fullname(const string
& p_fullname
)
4477 Definition::set_fullname(p_fullname
);
4478 type
->set_fullname(p_fullname
+ ".<type>");
4480 initial_value
->set_fullname(p_fullname
+ ".<initial_value>");
4483 void Def_Var::set_my_scope(Scope
*p_scope
)
4485 Definition::set_my_scope(p_scope
);
4486 type
->set_my_scope(p_scope
);
4487 if (initial_value
) initial_value
->set_my_scope(p_scope
);
4490 Type
*Def_Var::get_Type()
4499 Error_Context
cntxt(this, "In variable definition `%s'",
4500 id
->get_dispname().c_str());
4501 type
->set_genname(_T_
, get_genname());
4504 Type
*t
= type
->get_type_refd_last();
4505 switch (t
->get_typetype()) {
4507 error("Variable cannot be defined for port type `%s'",
4508 t
->get_fullname().c_str());
4510 case Type::T_SIGNATURE
:
4511 error("Variable cannot be defined for signature `%s'",
4512 t
->get_fullname().c_str());
4515 if (initial_value
) {
4516 initial_value
->set_my_governor(type
);
4517 type
->chk_this_value_ref(initial_value
);
4518 type
->chk_this_value(initial_value
, this, is_local() ?
4519 Type::EXPECTED_DYNAMIC_VALUE
: Type::EXPECTED_STATIC_VALUE
,
4520 INCOMPLETE_ALLOWED
, OMIT_NOT_ALLOWED
, SUB_CHK
);
4521 if (!semantic_check_only
) {
4522 initial_value
->set_genname_recursive(get_genname());
4523 initial_value
->set_code_section(GovernedSimple::CS_INLINE
);
4529 if (w_attrib_path
) {
4530 w_attrib_path
->chk_global_attrib();
4531 w_attrib_path
->chk_no_qualif();
4535 bool Def_Var::chk_identical(Definition
*p_def
)
4539 if (p_def
->get_asstype() != A_VAR
) {
4540 const char *dispname_str
= id
->get_dispname().c_str();
4541 error("Local definition `%s' is a variable, but the definition "
4542 "inherited from component type `%s' is a %s", dispname_str
,
4543 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4544 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4547 Def_Var
*p_def_var
= dynamic_cast<Def_Var
*>(p_def
);
4548 if (!p_def_var
) FATAL_ERROR("Def_Var::chk_identical()");
4549 if (!type
->is_identical(p_def_var
->type
)) {
4550 const char *dispname_str
= id
->get_dispname().c_str();
4551 type
->error("Local variable `%s' has type `%s', but the variable "
4552 "inherited from component type `%s' has type `%s'", dispname_str
,
4553 type
->get_typename().c_str(),
4554 p_def_var
->get_my_scope()->get_fullname().c_str(),
4555 p_def_var
->type
->get_typename().c_str());
4556 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4559 if (initial_value
) {
4560 if (p_def_var
->initial_value
) {
4561 if (!initial_value
->is_unfoldable() &&
4562 !p_def_var
->initial_value
->is_unfoldable() &&
4563 !(*initial_value
== *p_def_var
->initial_value
)) {
4564 const char *dispname_str
= id
->get_dispname().c_str();
4565 initial_value
->warning("Local variable `%s' and the variable "
4566 "inherited from component type `%s' have different initial values",
4567 dispname_str
, p_def_var
->get_my_scope()->get_fullname().c_str());
4568 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4571 const char *dispname_str
= id
->get_dispname().c_str();
4572 initial_value
->warning("Local variable `%s' has initial value, but "
4573 "the variable inherited from component type `%s' does not",
4574 dispname_str
, p_def_var
->get_my_scope()->get_fullname().c_str());
4575 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4577 } else if (p_def_var
->initial_value
) {
4578 const char *dispname_str
= id
->get_dispname().c_str();
4579 warning("Local variable `%s' does not have initial value, but the "
4580 "variable inherited from component type `%s' has", dispname_str
,
4581 p_def_var
->get_my_scope()->get_fullname().c_str());
4582 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4587 void Def_Var::generate_code(output_struct
*target
, bool clean_up
)
4589 type
->generate_code(target
);
4591 Code::init_cdef(&cdef
);
4592 type
->generate_code_object(&cdef
, my_scope
, get_genname(), 0, false);
4593 Code::merge_cdef(target
, &cdef
);
4594 Code::free_cdef(&cdef
);
4595 if (initial_value
) {
4596 target
->functions
.init_comp
=
4597 initial_value
->generate_code_init(target
->functions
.init_comp
,
4598 initial_value
->get_lhs_name().c_str());
4599 } else if (clean_up
) { // No initial value.
4600 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4601 "%s.clean_up();\n", get_genname().c_str());
4605 void Def_Var::generate_code(CodeGenHelper
& cgh
)
4607 generate_code(cgh
.get_outputstruct(this));
4610 char *Def_Var::generate_code_str(char *str
)
4612 const string
& t_genname
= get_genname();
4613 const char *genname_str
= t_genname
.c_str();
4614 if (initial_value
&& initial_value
->has_single_expr()) {
4615 // the initial value can be represented by a single C++ expression
4616 // the object is initialized by the constructor
4617 str
= mputprintf(str
, "%s %s(%s);\n",
4618 type
->get_genname_value(my_scope
).c_str(), genname_str
,
4619 initial_value
->get_single_expr().c_str());
4621 // use the default constructor
4622 str
= mputprintf(str
, "%s %s;\n",
4623 type
->get_genname_value(my_scope
).c_str(), genname_str
);
4624 if (initial_value
) {
4625 // the initial value is assigned using subsequent statements
4626 str
= initial_value
->generate_code_init(str
, genname_str
);
4632 void Def_Var::ilt_generate_code(ILT
*ilt
)
4634 const string
& t_genname
= get_genname();
4635 const char *genname_str
= t_genname
.c_str();
4636 char*& def
=ilt
->get_out_def();
4637 char*& init
=ilt
->get_out_branches();
4638 def
= mputprintf(def
, "%s %s;\n", type
->get_genname_value(my_scope
).c_str(),
4641 init
= initial_value
->generate_code_init(init
, genname_str
);
4644 char *Def_Var::generate_code_init_comp(char *str
, Definition
*base_defn
)
4646 if (initial_value
) {
4647 str
= initial_value
->generate_code_init(str
,
4648 base_defn
->get_genname_from_scope(my_scope
).c_str());
4653 void Def_Var::dump_internal(unsigned level
) const
4655 DEBUG(level
, "Variable %s", id
->get_dispname().c_str());
4656 type
->dump(level
+ 1);
4657 if (initial_value
) initial_value
->dump(level
+ 1);
4660 // =================================
4661 // ===== Def_Var_Template
4662 // =================================
4664 Def_Var_Template::Def_Var_Template(Identifier
*p_id
, Type
*p_type
,
4665 Template
*p_initial_value
, template_restriction_t p_template_restriction
)
4666 : Definition(A_VAR_TEMPLATE
, p_id
), type(p_type
),
4667 initial_value(p_initial_value
), template_restriction(p_template_restriction
)
4669 if (!p_type
) FATAL_ERROR("Ttcn::Def_Var_Template::Def_Var_Template()");
4670 type
->set_ownertype(Type::OT_VARTMPL_DEF
, this);
4673 Def_Var_Template::~Def_Var_Template()
4676 delete initial_value
;
4679 Def_Var_Template
*Def_Var_Template::clone() const
4681 FATAL_ERROR("Def_Var_Template::clone");
4684 void Def_Var_Template::set_fullname(const string
& p_fullname
)
4686 Definition::set_fullname(p_fullname
);
4687 type
->set_fullname(p_fullname
+ ".<type>");
4689 initial_value
->set_fullname(p_fullname
+ ".<initial_value>");
4692 void Def_Var_Template::set_my_scope(Scope
*p_scope
)
4694 Definition::set_my_scope(p_scope
);
4695 type
->set_my_scope(p_scope
);
4696 if (initial_value
) initial_value
->set_my_scope(p_scope
);
4699 Type
*Def_Var_Template::get_Type()
4705 void Def_Var_Template::chk()
4708 Error_Context
cntxt(this, "In template variable definition `%s'",
4709 id
->get_dispname().c_str());
4710 type
->set_genname(_T_
, get_genname());
4713 Type
*t
= type
->get_type_refd_last();
4714 if (t
->get_typetype() == Type::T_PORT
) {
4715 error("Template variable cannot be defined for port type `%s'",
4716 t
->get_fullname().c_str());
4719 if (initial_value
) {
4720 initial_value
->set_my_governor(type
);
4721 initial_value
->flatten(false);
4723 if (initial_value
->get_templatetype() == Template::CSTR_PATTERN
&&
4724 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
4725 initial_value
->set_templatetype(Template::USTR_PATTERN
);
4726 initial_value
->get_ustr_pattern()->set_pattern_type(
4727 PatternString::USTR_PATTERN
);
4730 type
->chk_this_template_ref(initial_value
);
4731 // temporary hack: to allow incomplete body as initial value
4732 // checking as a modified template, but without a base template
4733 type
->chk_this_template_generic(initial_value
, INCOMPLETE_ALLOWED
,
4734 OMIT_ALLOWED
, ANY_OR_OMIT_ALLOWED
, SUB_CHK
, IMPLICIT_OMIT
, 0);
4735 gen_restriction_check
=
4736 initial_value
->chk_restriction("template variable definition",
4737 template_restriction
, initial_value
);
4738 if (!semantic_check_only
) {
4739 initial_value
->set_genname_recursive(get_genname());
4740 initial_value
->set_code_section(GovernedSimple::CS_INLINE
);
4743 if (w_attrib_path
) {
4744 w_attrib_path
->chk_global_attrib();
4745 w_attrib_path
->chk_no_qualif();
4749 bool Def_Var_Template::chk_identical(Definition
*p_def
)
4753 if (p_def
->get_asstype() != A_VAR_TEMPLATE
) {
4754 const char *dispname_str
= id
->get_dispname().c_str();
4755 error("Local definition `%s' is a template variable, but the definition "
4756 "inherited from component type `%s' is a %s", dispname_str
,
4757 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4758 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4761 Def_Var_Template
*p_def_var_template
=
4762 dynamic_cast<Def_Var_Template
*>(p_def
);
4763 if (!p_def_var_template
) FATAL_ERROR("Def_Var_Template::chk_identical()");
4764 if (!type
->is_identical(p_def_var_template
->type
)) {
4765 const char *dispname_str
= id
->get_dispname().c_str();
4766 type
->error("Local template variable `%s' has type `%s', but the "
4767 "template variable inherited from component type `%s' has type `%s'",
4768 dispname_str
, type
->get_typename().c_str(),
4769 p_def_var_template
->get_my_scope()->get_fullname().c_str(),
4770 p_def_var_template
->type
->get_typename().c_str());
4771 p_def_var_template
->note("The inherited template variable `%s' is here",
4775 if (initial_value
) {
4776 if (!p_def_var_template
->initial_value
) {
4777 const char *dispname_str
= id
->get_dispname().c_str();
4778 initial_value
->warning("Local template variable `%s' has initial "
4779 "value, but the template variable inherited from component type "
4780 "`%s' does not", dispname_str
,
4781 p_def_var_template
->get_my_scope()->get_fullname().c_str());
4782 p_def_var_template
->note("The inherited template variable `%s' is here",
4785 } else if (p_def_var_template
->initial_value
) {
4786 const char *dispname_str
= id
->get_dispname().c_str();
4787 warning("Local template variable `%s' does not have initial value, but "
4788 "the template variable inherited from component type `%s' has",
4790 p_def_var_template
->get_my_scope()->get_fullname().c_str());
4791 p_def_var_template
->note("The inherited template variable `%s' is here",
4797 void Def_Var_Template::generate_code(output_struct
*target
, bool clean_up
)
4799 type
->generate_code(target
);
4801 Code::init_cdef(&cdef
);
4802 type
->generate_code_object(&cdef
, my_scope
, get_genname(), 0, true);
4803 Code::merge_cdef(target
, &cdef
);
4804 Code::free_cdef(&cdef
);
4805 if (initial_value
) {
4806 if (Common::Type::T_SEQOF
== initial_value
->get_my_governor()->get_typetype() ||
4807 Common::Type::T_ARRAY
== initial_value
->get_my_governor()->get_typetype()) {
4808 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4809 "%s.remove_all_permutations();\n", initial_value
->get_lhs_name().c_str());
4811 target
->functions
.init_comp
=
4812 initial_value
->generate_code_init(target
->functions
.init_comp
,
4813 initial_value
->get_lhs_name().c_str());
4814 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4815 target
->functions
.init_comp
= Template::generate_restriction_check_code(
4816 target
->functions
.init_comp
, initial_value
->get_lhs_name().c_str(),
4817 template_restriction
);
4818 } else if (clean_up
) { // No initial value.
4819 // Always reset component variables/variable templates on component
4820 // reinitialization. Fix for HM79493.
4821 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4822 "%s.clean_up();\n", get_genname().c_str());
4826 void Def_Var_Template::generate_code(CodeGenHelper
& cgh
)
4828 generate_code(cgh
.get_outputstruct(this));
4831 char *Def_Var_Template::generate_code_str(char *str
)
4833 const string
& t_genname
= get_genname();
4834 const char *genname_str
= t_genname
.c_str();
4835 if (initial_value
&& initial_value
->has_single_expr()) {
4836 // The initial value can be represented by a single C++ expression
4837 // the object is initialized by the constructor.
4838 str
= mputprintf(str
, "%s %s(%s);\n",
4839 type
->get_genname_template(my_scope
).c_str(), genname_str
,
4840 initial_value
->get_single_expr(false).c_str());
4842 // Use the default constructor.
4843 str
= mputprintf(str
, "%s %s;\n",
4844 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4845 if (initial_value
) {
4846 // The initial value is assigned using subsequent statements.
4847 if (use_runtime_2
&& TypeConv::needs_conv_refd(initial_value
))
4848 str
= TypeConv::gen_conv_code_refd(str
, genname_str
, initial_value
);
4849 else str
= initial_value
->generate_code_init(str
, genname_str
);
4852 if (initial_value
&& template_restriction
!= TR_NONE
4853 && gen_restriction_check
)
4854 str
= Template::generate_restriction_check_code(str
, genname_str
,
4855 template_restriction
);
4859 void Def_Var_Template::ilt_generate_code(ILT
*ilt
)
4861 const string
& t_genname
= get_genname();
4862 const char *genname_str
= t_genname
.c_str();
4863 char*& def
=ilt
->get_out_def();
4864 char*& init
=ilt
->get_out_branches();
4865 def
= mputprintf(def
, "%s %s;\n",
4866 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4867 if (initial_value
) {
4868 init
= initial_value
->generate_code_init(init
, genname_str
);
4869 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4870 init
= Template::generate_restriction_check_code(init
, genname_str
,
4871 template_restriction
);
4875 char *Def_Var_Template::generate_code_init_comp(char *str
,
4876 Definition
*base_defn
)
4878 if (initial_value
) {
4879 str
= initial_value
->generate_code_init(str
,
4880 base_defn
->get_genname_from_scope(my_scope
).c_str());
4881 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4882 str
= Template::generate_restriction_check_code(str
,
4883 base_defn
->get_genname_from_scope(my_scope
).c_str(),
4884 template_restriction
);
4889 void Def_Var_Template::dump_internal(unsigned level
) const
4891 DEBUG(level
, "Template variable %s", id
->get_dispname().c_str());
4892 if (template_restriction
!=TR_NONE
)
4893 DEBUG(level
+ 1, "restriction: %s",
4894 Template::get_restriction_name(template_restriction
));
4895 type
->dump(level
+ 1);
4896 if (initial_value
) initial_value
->dump(level
+ 1);
4899 // =================================
4901 // =================================
4903 Def_Timer::~Def_Timer()
4906 delete default_duration
;
4909 Def_Timer
*Def_Timer::clone() const
4911 FATAL_ERROR("Def_Timer::clone");
4914 void Def_Timer::set_fullname(const string
& p_fullname
)
4916 Definition::set_fullname(p_fullname
);
4917 if (dimensions
) dimensions
->set_fullname(p_fullname
+ ".<dimensions>");
4918 if (default_duration
)
4919 default_duration
->set_fullname(p_fullname
+ ".<default_duration>");
4922 void Def_Timer::set_my_scope(Scope
*p_scope
)
4924 Definition::set_my_scope(p_scope
);
4925 if (dimensions
) dimensions
->set_my_scope(p_scope
);
4926 if (default_duration
) default_duration
->set_my_scope(p_scope
);
4929 ArrayDimensions
*Def_Timer::get_Dimensions()
4931 if (!checked
) chk();
4935 void Def_Timer::chk()
4938 Error_Context
cntxt(this, "In timer definition `%s'",
4939 id
->get_dispname().c_str());
4940 if (dimensions
) dimensions
->chk();
4941 if (default_duration
) {
4942 Error_Context
cntxt2(default_duration
, "In default duration");
4943 if (dimensions
) chk_array_duration(default_duration
);
4944 else chk_single_duration(default_duration
);
4945 if (!semantic_check_only
) {
4946 default_duration
->set_code_section(GovernedSimple::CS_POST_INIT
);
4950 if (w_attrib_path
) {
4951 w_attrib_path
->chk_global_attrib();
4952 w_attrib_path
->chk_no_qualif();
4956 bool Def_Timer::chk_identical(Definition
*p_def
)
4960 if (p_def
->get_asstype() != A_TIMER
) {
4961 const char *dispname_str
= id
->get_dispname().c_str();
4962 error("Local definition `%s' is a timer, but the definition inherited "
4963 "from component type `%s' is a %s", dispname_str
,
4964 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4965 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4968 Def_Timer
*p_def_timer
= dynamic_cast<Def_Timer
*>(p_def
);
4969 if (!p_def_timer
) FATAL_ERROR("Def_Timer::chk_identical()");
4971 if (p_def_timer
->dimensions
) {
4972 if (!dimensions
->is_identical(p_def_timer
->dimensions
)) {
4973 const char *dispname_str
= id
->get_dispname().c_str();
4974 error("Local timer `%s' and the timer inherited from component type "
4975 "`%s' have different array dimensions", dispname_str
,
4976 p_def_timer
->get_my_scope()->get_fullname().c_str());
4977 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4981 const char *dispname_str
= id
->get_dispname().c_str();
4982 error("Local definition `%s' is a timer array, but the definition "
4983 "inherited from component type `%s' is a single timer", dispname_str
,
4984 p_def_timer
->get_my_scope()->get_fullname().c_str());
4985 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4988 } else if (p_def_timer
->dimensions
) {
4989 const char *dispname_str
= id
->get_dispname().c_str();
4990 error("Local definition `%s' is a single timer, but the definition "
4991 "inherited from component type `%s' is a timer array", dispname_str
,
4992 p_def_timer
->get_my_scope()->get_fullname().c_str());
4993 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4996 if (default_duration
) {
4997 if (p_def_timer
->default_duration
) {
4998 if (!default_duration
->is_unfoldable() &&
4999 !p_def_timer
->default_duration
->is_unfoldable() &&
5000 !(*default_duration
== *p_def_timer
->default_duration
)) {
5001 const char *dispname_str
= id
->get_dispname().c_str();
5002 default_duration
->warning("Local timer `%s' and the timer inherited "
5003 "from component type `%s' have different default durations",
5004 dispname_str
, p_def_timer
->get_my_scope()->get_fullname().c_str());
5005 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
5008 const char *dispname_str
= id
->get_dispname().c_str();
5009 default_duration
->error("Local timer `%s' has default duration, but "
5010 "the timer inherited from component type `%s' does not", dispname_str
,
5011 p_def_timer
->get_my_scope()->get_fullname().c_str());
5012 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
5015 } else if (p_def_timer
->default_duration
) {
5016 const char *dispname_str
= id
->get_dispname().c_str();
5017 error("Local timer `%s' does not have default duration, but the timer "
5018 "inherited from component type `%s' has", dispname_str
,
5019 p_def_timer
->get_my_scope()->get_fullname().c_str());
5020 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
5026 bool Def_Timer::has_default_duration(FieldOrArrayRefs
*p_subrefs
)
5028 // return true in case of any uncertainity
5029 if (!default_duration
) return false;
5030 else if (!dimensions
|| !p_subrefs
) return true;
5031 Value
*v
= default_duration
;
5032 size_t nof_dims
= dimensions
->get_nof_dims();
5033 size_t nof_refs
= p_subrefs
->get_nof_refs();
5034 size_t upper_limit
= nof_dims
< nof_refs
? nof_dims
: nof_refs
;
5035 for (size_t i
= 0; i
< upper_limit
; i
++) {
5036 v
= v
->get_value_refd_last();
5037 if (v
->get_valuetype() != Value::V_SEQOF
) break;
5038 FieldOrArrayRef
*ref
= p_subrefs
->get_ref(i
);
5039 if (ref
->get_type() != FieldOrArrayRef::ARRAY_REF
) return true;
5040 Value
*v_index
= ref
->get_val()->get_value_refd_last();
5041 if (v_index
->get_valuetype() != Value::V_INT
) return true;
5042 Int index
= v_index
->get_val_Int()->get_val()
5043 - dimensions
->get_dim_byIndex(i
)->get_offset();
5044 if (index
>= 0 && index
< static_cast<Int
>(v
->get_nof_comps()))
5045 v
= v
->get_comp_byIndex(index
);
5048 return v
->get_valuetype() != Value::V_NOTUSED
;
5051 void Def_Timer::chk_single_duration(Value
*dur
)
5053 dur
->chk_expr_float(is_local() ?
5054 Type::EXPECTED_DYNAMIC_VALUE
: Type::EXPECTED_STATIC_VALUE
);
5055 Value
*v
= dur
->get_value_refd_last();
5056 if (v
->get_valuetype() == Value::V_REAL
) {
5057 ttcn3float v_real
= v
->get_val_Real();
5058 if ( (v_real
<0.0) || isSpecialFloatValue(v_real
) ) {
5059 dur
->error("A non-negative float value was expected "
5060 "as timer duration instead of `%s'", Real2string(v_real
).c_str());
5065 void Def_Timer::chk_array_duration(Value
*dur
, size_t start_dim
)
5067 ArrayDimension
*dim
= dimensions
->get_dim_byIndex(start_dim
);
5068 bool array_size_known
= !dim
->get_has_error();
5069 size_t array_size
= 0;
5070 if (array_size_known
) array_size
= dim
->get_size();
5071 Value
*v
= dur
->get_value_refd_last();
5072 switch (v
->get_valuetype()) {
5073 case Value::V_ERROR
:
5075 case Value::V_SEQOF
: {
5076 size_t nof_vs
= v
->get_nof_comps();
5077 // Value-list notation.
5078 if (!v
->is_indexed()) {
5079 if (array_size_known
) {
5080 if (array_size
> nof_vs
) {
5081 dur
->error("Too few elements in the default duration of timer "
5082 "array: %lu was expected instead of %lu",
5083 (unsigned long)array_size
, (unsigned long)nof_vs
);
5084 } else if (array_size
< nof_vs
) {
5085 dur
->error("Too many elements in the default duration of timer "
5086 "array: %lu was expected instead of %lu",
5087 (unsigned long)array_size
, (unsigned long)nof_vs
);
5090 bool last_dimension
= start_dim
+ 1 >= dimensions
->get_nof_dims();
5091 for (size_t i
= 0; i
< nof_vs
; i
++) {
5092 Value
*array_v
= v
->get_comp_byIndex(i
);
5093 if (array_v
->get_valuetype() == Value::V_NOTUSED
) continue;
5094 if (last_dimension
) chk_single_duration(array_v
);
5095 else chk_array_duration(array_v
, start_dim
+ 1);
5098 // Indexed-notation.
5099 bool last_dimension
= start_dim
+ 1 >= dimensions
->get_nof_dims();
5100 map
<Int
, Int
> index_map
;
5101 for (size_t i
= 0; i
< nof_vs
; i
++) {
5102 Value
*array_v
= v
->get_comp_byIndex(i
);
5103 if (array_v
->get_valuetype() == Value::V_NOTUSED
) continue;
5104 if (last_dimension
) chk_single_duration(array_v
);
5105 else chk_array_duration(array_v
, start_dim
+ 1);
5106 Error_Context
cntxt(this, "In timer array element %lu",
5107 (unsigned long)(i
+ 1));
5108 Value
*index
= v
->get_index_byIndex(i
);
5109 dim
->chk_index(index
, Type::EXPECTED_DYNAMIC_VALUE
);
5110 if (index
->get_value_refd_last()->get_valuetype() == Value::V_INT
) {
5111 const int_val_t
*index_int
= index
->get_value_refd_last()
5113 if (*index_int
> INT_MAX
) {
5114 index
->error("An integer value less than `%d' was expected for "
5115 "indexing timer array instead of `%s'", INT_MAX
,
5116 (index_int
->t_str()).c_str());
5117 index
->set_valuetype(Value::V_ERROR
);
5119 Int index_val
= index_int
->get_val();
5120 if (index_map
.has_key(index_val
)) {
5121 index
->error("Duplicate index value `%s' for timer array "
5122 "elements `%s' and `%s'",
5123 Int2string(index_val
).c_str(),
5124 Int2string((Int
)i
+ 1).c_str(),
5125 Int2string(*index_map
[index_val
]).c_str());
5126 index
->set_valuetype(Value::V_ERROR
);
5128 index_map
.add(index_val
, new Int((Int
)i
+ 1));
5133 // It's not possible to have "index_map.size() > array_size", since we
5134 // add only correct constant-index values into the map. It's possible
5135 // to create partially initialized timer arrays.
5136 for (size_t i
= 0; i
< index_map
.size(); i
++)
5137 delete index_map
.get_nth_elem(i
);
5142 if (array_size_known
) {
5143 dur
->error("An array value (with %lu elements) was expected as "
5144 "default duration of timer array",
5145 (unsigned long)array_size
);
5147 dur
->error("An array value was expected as default duration of timer "
5150 dur
->set_valuetype(Value::V_ERROR
);
5155 void Def_Timer::generate_code(output_struct
*target
, bool)
5157 const string
& t_genname
= get_genname();
5158 const char *genname_str
= t_genname
.c_str();
5159 const string
& dispname
= id
->get_dispname();
5162 const string
& array_type
= dimensions
->get_timer_type();
5163 const char *array_type_str
= array_type
.c_str();
5164 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5165 "extern %s %s;\n", array_type_str
, genname_str
);
5166 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5167 "%s %s;\n", array_type_str
, genname_str
);
5168 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
, "{\n"
5169 "static const char * const timer_name = \"");
5170 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
5172 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
5174 "%s.set_name(timer_name);\n"
5175 "}\n", genname_str
);
5176 if (default_duration
) target
->functions
.post_init
=
5177 generate_code_array_duration(target
->functions
.post_init
, genname_str
,
5181 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5182 "extern TIMER %s;\n", genname_str
);
5183 if (default_duration
) {
5184 // has default duration
5185 Value
*v
= default_duration
->get_value_refd_last();
5186 if (v
->get_valuetype() == Value::V_REAL
) {
5187 // duration is known at compilation time -> set in the constructor
5188 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5189 "TIMER %s(\"%s\", %s);\n", genname_str
, dispname
.c_str(),
5190 v
->get_single_expr().c_str());
5192 // duration is known only at runtime -> set in post_init
5193 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5194 "TIMER %s(\"%s\");\n", genname_str
, dispname
.c_str());
5195 expression_struct expr
;
5196 Code::init_expr(&expr
);
5197 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5199 default_duration
->generate_code_expr(&expr
);
5200 expr
.expr
= mputc(expr
.expr
, ')');
5201 target
->functions
.post_init
=
5202 Code::merge_free_expr(target
->functions
.post_init
, &expr
);
5205 // does not have default duration
5206 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5207 "TIMER %s(\"%s\");\n", genname_str
, dispname
.c_str());
5212 void Def_Timer::generate_code(CodeGenHelper
& cgh
) {
5213 generate_code(cgh
.get_current_outputstruct());
5216 char *Def_Timer::generate_code_array_duration(char *str
,
5217 const char *object_name
, Value
*dur
, size_t start_dim
)
5219 ArrayDimension
*dim
= dimensions
->get_dim_byIndex(start_dim
);
5220 size_t dim_size
= dim
->get_size();
5221 Value
*v
= dur
->get_value_refd_last();
5222 if (v
->get_valuetype() != Value::V_SEQOF
5223 || (v
->get_nof_comps() != dim_size
&& !v
->is_indexed()))
5224 FATAL_ERROR("Def_Timer::generate_code_array_duration()");
5225 // Value-list notation.
5226 if (!v
->is_indexed()) {
5227 if (start_dim
+ 1 < dimensions
->get_nof_dims()) {
5228 // There are more dimensions, the elements of "v" are arrays a
5229 // temporary reference shall be introduced if the next dimension has
5230 // more than 1 elements.
5231 bool temp_ref_needed
=
5232 dimensions
->get_dim_byIndex(start_dim
+ 1)->get_size() > 1;
5233 for (size_t i
= 0; i
< dim_size
; i
++) {
5234 Value
*v_elem
= v
->get_comp_byIndex(i
);
5235 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5236 if (temp_ref_needed
) {
5237 const string
& tmp_id
= my_scope
->get_scope_mod_gen()
5238 ->get_temporary_id();
5239 const char *tmp_str
= tmp_id
.c_str();
5240 str
= mputprintf(str
, "{\n"
5241 "%s& %s = %s.array_element(%lu);\n",
5242 dimensions
->get_timer_type(start_dim
+ 1).c_str(),
5243 tmp_str
, object_name
, (unsigned long)i
);
5244 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5246 str
= mputstr(str
, "}\n");
5248 char *tmp_str
= mprintf("%s.array_element(%lu)", object_name
,
5250 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5256 // We are in the last dimension, the elements of "v" are floats.
5257 for (size_t i
= 0; i
< dim_size
; i
++) {
5258 Value
*v_elem
= v
->get_comp_byIndex(i
);
5259 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5260 expression_struct expr
;
5261 Code::init_expr(&expr
);
5262 expr
.expr
= mputprintf(expr
.expr
,
5263 "%s.array_element(%lu).set_default_duration(",
5264 object_name
, (unsigned long)i
);
5265 v_elem
->generate_code_expr(&expr
);
5266 expr
.expr
= mputc(expr
.expr
, ')');
5267 str
= Code::merge_free_expr(str
, &expr
);
5270 // Indexed-list notation.
5272 if (start_dim
+ 1 < dimensions
->get_nof_dims()) {
5273 bool temp_ref_needed
=
5274 dimensions
->get_dim_byIndex(start_dim
+ 1)->get_size() > 1;
5275 for (size_t i
= 0; i
< v
->get_nof_comps(); i
++) {
5276 Value
*v_elem
= v
->get_comp_byIndex(i
);
5277 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5278 if (temp_ref_needed
) {
5279 const string
& tmp_id
= my_scope
->get_scope_mod_gen()
5280 ->get_temporary_id();
5281 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5282 ->get_temporary_id();
5283 const char *tmp_str
= tmp_id
.c_str();
5284 str
= mputstr(str
, "{\n");
5285 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5286 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5288 str
= mputprintf(str
, "%s& %s = %s.array_element(%s);\n",
5289 dimensions
->get_timer_type(start_dim
+ 1).c_str(),
5290 tmp_str
, object_name
, idx_id
.c_str());
5291 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5293 str
= mputstr(str
, "}\n");
5295 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5296 ->get_temporary_id();
5297 str
= mputstr(str
, "{\n");
5298 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5299 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5301 char *tmp_str
= mprintf("%s.array_element(%s)", object_name
,
5303 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5305 str
= mputstr(str
, "}\n");
5310 for (size_t i
= 0; i
< v
->get_nof_comps(); i
++) {
5311 Value
*v_elem
= v
->get_comp_byIndex(i
);
5312 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5313 expression_struct expr
;
5314 Code::init_expr(&expr
);
5315 str
= mputstr(str
, "{\n");
5316 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5317 ->get_temporary_id();
5318 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5319 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5321 str
= mputprintf(str
,
5322 "%s.array_element(%s).set_default_duration(",
5323 object_name
, idx_id
.c_str());
5324 v_elem
->generate_code_expr(&expr
);
5325 expr
.expr
= mputc(expr
.expr
, ')');
5326 str
= Code::merge_free_expr(str
, &expr
);
5327 str
= mputstr(str
, "}\n");
5334 char *Def_Timer::generate_code_str(char *str
)
5336 const string
& t_genname
= get_genname();
5337 const char *genname_str
= t_genname
.c_str();
5338 const string
& dispname
= id
->get_dispname();
5341 const string
& array_type
= dimensions
->get_timer_type();
5342 const char *array_type_str
= array_type
.c_str();
5343 str
= mputprintf(str
, "%s %s;\n", array_type_str
, genname_str
);
5344 str
= mputstr(str
, "{\n"
5345 "static const char * const timer_name = \"");
5346 str
= mputstr(str
, dispname
.c_str());
5347 str
= mputprintf(str
, "\";\n"
5348 "%s.set_name(timer_name);\n"
5349 "}\n", genname_str
);
5350 if (default_duration
) str
= generate_code_array_duration(str
,
5351 genname_str
, default_duration
);
5354 if (default_duration
&& default_duration
->has_single_expr()) {
5355 // the default duration can be passed to the constructor
5356 str
= mputprintf(str
, "TIMER %s(\"%s\", %s);\n", genname_str
,
5357 dispname
.c_str(), default_duration
->get_single_expr().c_str());
5359 // only the name is passed to the constructor
5360 str
= mputprintf(str
, "TIMER %s(\"%s\");\n", genname_str
,
5362 if (default_duration
) {
5363 // the default duration is set explicitly
5364 expression_struct expr
;
5365 Code::init_expr(&expr
);
5366 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5368 default_duration
->generate_code_expr(&expr
);
5369 expr
.expr
= mputc(expr
.expr
, ')');
5370 str
= Code::merge_free_expr(str
, &expr
);
5377 void Def_Timer::ilt_generate_code(ILT
*ilt
)
5379 const string
& t_genname
= get_genname();
5380 const char *genname_str
= t_genname
.c_str();
5381 const string
& dispname
= id
->get_dispname();
5383 char*& def
= ilt
->get_out_def();
5384 char*& init
= ilt
->get_out_branches();
5388 const string
& array_type
= dimensions
->get_timer_type();
5389 const char *array_type_str
= array_type
.c_str();
5390 def
= mputprintf(def
, "%s %s;\n", array_type_str
, genname_str
);
5391 def
= mputstr(def
, "{\n"
5392 "static const char * const timer_names[] = { ");
5393 def
= dimensions
->generate_element_names(def
, dispname
);
5394 def
= mputprintf(def
, " };\n"
5395 "%s.set_name(%lu, timer_names);\n"
5396 "}\n", genname_str
, (unsigned long) dimensions
->get_array_size());
5397 if (default_duration
) init
= generate_code_array_duration(init
,
5398 genname_str
, default_duration
);
5401 if (default_duration
) {
5402 // has default duration
5403 Value
*v
= default_duration
->get_value_refd_last();
5404 if (v
->get_valuetype() == Value::V_REAL
) {
5405 // duration is known at compilation time -> set in the constructor
5406 def
= mputprintf(def
, "TIMER %s(\"%s\", %s);\n", genname_str
,
5407 dispname
.c_str(), v
->get_single_expr().c_str());
5409 // duration is known only at runtime -> set when control reaches the
5411 def
= mputprintf(def
, "TIMER %s(\"%s\");\n", genname_str
,
5413 expression_struct expr
;
5414 Code::init_expr(&expr
);
5415 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5417 default_duration
->generate_code_expr(&expr
);
5418 expr
.expr
= mputc(expr
.expr
, ')');
5419 init
= Code::merge_free_expr(init
, &expr
);
5422 // does not have default duration
5423 def
= mputprintf(def
, "TIMER %s(\"%s\");\n", genname_str
,
5429 char *Def_Timer::generate_code_init_comp(char *str
, Definition
*base_defn
)
5431 if (default_duration
) {
5432 Def_Timer
*base_timer_defn
= dynamic_cast<Def_Timer
*>(base_defn
);
5433 if (!base_timer_defn
|| !base_timer_defn
->default_duration
)
5434 FATAL_ERROR("Def_Timer::generate_code_init_comp()");
5435 // initializer is not needed if the default durations are the same
5436 // constants in both timers
5437 if (default_duration
->is_unfoldable() ||
5438 base_timer_defn
->default_duration
->is_unfoldable() ||
5439 !(*default_duration
== *base_timer_defn
->default_duration
)) {
5441 str
= generate_code_array_duration(str
,
5442 base_timer_defn
->get_genname_from_scope(my_scope
).c_str(),
5445 expression_struct expr
;
5446 Code::init_expr(&expr
);
5447 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5448 base_timer_defn
->get_genname_from_scope(my_scope
).c_str());
5449 default_duration
->generate_code_expr(&expr
);
5450 expr
.expr
= mputc(expr
.expr
, ')');
5451 str
= Code::merge_free_expr(str
, &expr
);
5458 void Def_Timer::dump_internal(unsigned level
) const
5460 DEBUG(level
, "Timer: %s", id
->get_dispname().c_str());
5461 if (dimensions
) dimensions
->dump(level
+ 1);
5462 if (default_duration
) {
5463 DEBUG(level
+ 1, "Default duration:");
5464 default_duration
->dump(level
+ 1);
5468 // =================================
5470 // =================================
5472 Def_Port::Def_Port(Identifier
*p_id
, Reference
*p_tref
,
5473 ArrayDimensions
*p_dims
)
5474 : Definition(A_PORT
, p_id
), type_ref(p_tref
), port_type(0),
5477 if (!p_tref
) FATAL_ERROR("Def_Port::Def_Port()");
5480 Def_Port::~Def_Port()
5486 Def_Port
*Def_Port::clone() const
5488 FATAL_ERROR("Def_Port::clone");
5491 void Def_Port::set_fullname(const string
& p_fullname
)
5493 Definition::set_fullname(p_fullname
);
5494 type_ref
->set_fullname(p_fullname
+ ".<type_ref>");
5495 if (dimensions
) dimensions
->set_fullname(p_fullname
);
5498 void Def_Port::set_my_scope(Scope
*p_scope
)
5500 Definition::set_my_scope(p_scope
);
5501 type_ref
->set_my_scope(p_scope
);
5502 if (dimensions
) dimensions
->set_my_scope(p_scope
);
5505 Type
*Def_Port::get_Type()
5511 ArrayDimensions
*Def_Port::get_Dimensions()
5513 if (!checked
) chk();
5517 void Def_Port::chk()
5519 if (checked
) return;
5521 Error_Context
cntxt(this, "In port definition `%s'",
5522 id
->get_dispname().c_str());
5523 Common::Assignment
*ass
= type_ref
->get_refd_assignment();
5525 if (ass
->get_asstype() == A_TYPE
) {
5526 Type
*t
= ass
->get_Type()->get_type_refd_last();
5527 if (t
->get_typetype() == Type::T_PORT
) port_type
= t
;
5528 else type_ref
->error("Type reference `%s' does not refer to a "
5529 "port type", type_ref
->get_dispname().c_str());
5530 } else type_ref
->error("Reference `%s' does not refer to a "
5531 "type", type_ref
->get_dispname().c_str());
5533 if (dimensions
) dimensions
->chk();
5534 if (w_attrib_path
) {
5535 w_attrib_path
->chk_global_attrib();
5536 w_attrib_path
->chk_no_qualif();
5540 bool Def_Port::chk_identical(Definition
*p_def
)
5544 if (p_def
->get_asstype() != A_PORT
) {
5545 const char *dispname_str
= id
->get_dispname().c_str();
5546 error("Local definition `%s' is a port, but the definition inherited "
5547 "from component type `%s' is a %s", dispname_str
,
5548 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
5549 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
5552 Def_Port
*p_def_port
= dynamic_cast<Def_Port
*>(p_def
);
5553 if (!p_def_port
) FATAL_ERROR("Def_Port::chk_identical()");
5554 if (port_type
&& p_def_port
->port_type
&&
5555 port_type
!= p_def_port
->port_type
) {
5556 const char *dispname_str
= id
->get_dispname().c_str();
5557 type_ref
->error("Local port `%s' has type `%s', but the port inherited "
5558 "from component type `%s' has type `%s'", dispname_str
,
5559 port_type
->get_typename().c_str(),
5560 p_def_port
->get_my_scope()->get_fullname().c_str(),
5561 p_def_port
->port_type
->get_typename().c_str());
5562 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5566 if (p_def_port
->dimensions
) {
5567 if (!dimensions
->is_identical(p_def_port
->dimensions
)) {
5568 const char *dispname_str
= id
->get_dispname().c_str();
5569 error("Local port `%s' and the port inherited from component type "
5570 "`%s' have different array dimensions", dispname_str
,
5571 p_def_port
->get_my_scope()->get_fullname().c_str());
5572 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5576 const char *dispname_str
= id
->get_dispname().c_str();
5577 error("Local definition `%s' is a port array, but the definition "
5578 "inherited from component type `%s' is a single port", dispname_str
,
5579 p_def_port
->get_my_scope()->get_fullname().c_str());
5580 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5583 } else if (p_def_port
->dimensions
) {
5584 const char *dispname_str
= id
->get_dispname().c_str();
5585 error("Local definition `%s' is a single port, but the definition "
5586 "inherited from component type `%s' is a port array", dispname_str
,
5587 p_def_port
->get_my_scope()->get_fullname().c_str());
5588 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5594 void Def_Port::generate_code(output_struct
*target
, bool)
5596 const string
& t_genname
= get_genname();
5597 const char *genname_str
= t_genname
.c_str();
5598 const string
& type_genname
= port_type
->get_genname_value(my_scope
);
5599 const string
& dispname
= id
->get_dispname();
5602 const string
& array_type
= dimensions
->get_port_type(type_genname
);
5603 const char *array_type_str
= array_type
.c_str();
5604 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5605 "extern %s %s;\n", array_type_str
, genname_str
);
5606 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5607 "%s %s;\n", array_type_str
, genname_str
);
5608 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
, "{\n"
5609 "static const char * const port_name = \"");
5610 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
5612 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
5614 "%s.set_name(port_name);\n"
5615 "}\n", genname_str
);
5618 const char *type_genname_str
= type_genname
.c_str();
5619 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5620 "extern %s %s;\n", type_genname_str
, genname_str
);
5621 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5622 "%s %s(\"%s\");\n", type_genname_str
, genname_str
, dispname
.c_str());
5624 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
5625 "%s.activate_port();\n", genname_str
);
5628 void Def_Port::generate_code(CodeGenHelper
& cgh
) {
5629 generate_code(cgh
.get_current_outputstruct());
5632 char *Def_Port::generate_code_init_comp(char *str
, Definition
*base_defn
)
5634 return mputprintf(str
, "%s.activate_port();\n",
5635 base_defn
->get_genname_from_scope(my_scope
).c_str());
5638 void Def_Port::dump_internal(unsigned level
) const
5640 DEBUG(level
, "Port: %s", id
->get_dispname().c_str());
5641 DEBUG(level
+ 1, "Port type:");
5642 type_ref
->dump(level
+ 2);
5643 if (dimensions
) dimensions
->dump(level
+ 1);
5646 // =================================
5647 // ===== Def_Function_Base
5648 // =================================
5650 Def_Function_Base::asstype_t
Def_Function_Base::determine_asstype(
5651 bool is_external
, bool has_return_type
, bool returns_template
)
5654 if (has_return_type
) {
5655 if (returns_template
) return A_EXT_FUNCTION_RTEMP
;
5656 else return A_EXT_FUNCTION_RVAL
;
5658 if (returns_template
)
5659 FATAL_ERROR("Def_Function_Base::determine_asstype()");
5660 return A_EXT_FUNCTION
;
5662 } else { // not an external function
5663 if (has_return_type
) {
5664 if (returns_template
) return A_FUNCTION_RTEMP
;
5665 else return A_FUNCTION_RVAL
;
5667 if (returns_template
)
5668 FATAL_ERROR("Def_Function_Base::determine_asstype()");
5674 Def_Function_Base::Def_Function_Base(const Def_Function_Base
& p
)
5675 : Definition(p
), prototype(PROTOTYPE_NONE
), input_type(0), output_type(0)
5677 fp_list
= p
.fp_list
->clone();
5678 fp_list
->set_my_def(this);
5679 return_type
= p
.return_type
? p
.return_type
->clone() : 0;
5680 template_restriction
= p
.template_restriction
;
5683 Def_Function_Base::Def_Function_Base(bool is_external
, Identifier
*p_id
,
5684 FormalParList
*p_fpl
, Type
*p_return_type
, bool returns_template
,
5685 template_restriction_t p_template_restriction
)
5686 : Definition(determine_asstype(is_external
, p_return_type
!= 0,
5687 returns_template
), p_id
), fp_list(p_fpl
), return_type(p_return_type
),
5688 prototype(PROTOTYPE_NONE
), input_type(0), output_type(0),
5689 template_restriction(p_template_restriction
)
5691 if (!p_fpl
) FATAL_ERROR("Def_Function_Base::Def_Function_Base()");
5692 fp_list
->set_my_def(this);
5693 if (return_type
) return_type
->set_ownertype(Type::OT_FUNCTION_DEF
, this);
5696 Def_Function_Base::~Def_Function_Base()
5702 void Def_Function_Base::set_fullname(const string
& p_fullname
)
5704 Definition::set_fullname(p_fullname
);
5705 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
5706 if (return_type
) return_type
->set_fullname(p_fullname
+ ".<return_type>");
5709 void Def_Function_Base::set_my_scope(Scope
*p_scope
)
5711 Definition::set_my_scope(p_scope
);
5712 fp_list
->set_my_scope(p_scope
);
5713 if (return_type
) return_type
->set_my_scope(p_scope
);
5716 Type
*Def_Function_Base::get_Type()
5718 if (!checked
) chk();
5722 FormalParList
*Def_Function_Base::get_FormalParList()
5724 if (!checked
) chk();
5728 const char *Def_Function_Base::get_prototype_name() const
5730 switch (prototype
) {
5731 case PROTOTYPE_NONE
:
5732 return "<no prototype>";
5733 case PROTOTYPE_CONVERT
:
5735 case PROTOTYPE_FAST
:
5737 case PROTOTYPE_BACKTRACK
:
5739 case PROTOTYPE_SLIDING
:
5742 return "<unknown prototype>";
5746 void Def_Function_Base::chk_prototype()
5748 switch (prototype
) {
5749 case PROTOTYPE_NONE
:
5750 // return immediately
5752 case PROTOTYPE_CONVERT
:
5753 case PROTOTYPE_FAST
:
5754 case PROTOTYPE_BACKTRACK
:
5755 case PROTOTYPE_SLIDING
:
5756 // perform the checks below
5759 FATAL_ERROR("Def_Function_Base::chk_prototype()");
5761 // checking the formal parameter list
5762 if (prototype
== PROTOTYPE_CONVERT
) {
5763 if (fp_list
->get_nof_fps() == 1) {
5764 FormalPar
*par
= fp_list
->get_fp_byIndex(0);
5765 if (par
->get_asstype() == A_PAR_VAL_IN
) {
5766 input_type
= par
->get_Type();
5768 par
->error("The parameter must be an `in' value parameter for "
5769 "attribute `prototype(%s)' instead of %s", get_prototype_name(),
5770 par
->get_assname());
5773 fp_list
->error("The function must have one parameter instead of %lu "
5774 "for attribute `prototype(%s)'", (unsigned long) fp_list
->get_nof_fps(),
5775 get_prototype_name());
5777 } else { // not PROTOTYPE_CONVERT
5778 if (fp_list
->get_nof_fps() == 2) {
5779 FormalPar
*first_par
= fp_list
->get_fp_byIndex(0);
5780 if (prototype
== PROTOTYPE_SLIDING
) {
5781 if (first_par
->get_asstype() == A_PAR_VAL_INOUT
) {
5782 Type
*first_par_type
= first_par
->get_Type();
5783 switch (first_par_type
->get_type_refd_last()
5784 ->get_typetype_ttcn3()) {
5789 input_type
= first_par_type
;
5792 first_par_type
->error("The type of the first parameter must be "
5793 "`octetstring' or `charstring' or `bitstring' for attribute "
5794 "`prototype(%s)' instead of `%s'", get_prototype_name(),
5795 first_par_type
->get_typename().c_str());
5798 first_par
->error("The first parameter must be an `inout' value "
5799 "parameter for attribute `prototype(%s)' instead of %s",
5800 get_prototype_name(), first_par
->get_assname());
5803 if (first_par
->get_asstype() == A_PAR_VAL_IN
) {
5804 input_type
= first_par
->get_Type();
5806 first_par
->error("The first parameter must be an `in' value "
5807 "parameter for attribute `prototype(%s)' instead of %s",
5808 get_prototype_name(), first_par
->get_assname());
5811 FormalPar
*second_par
= fp_list
->get_fp_byIndex(1);
5812 if (second_par
->get_asstype() == A_PAR_VAL_OUT
) {
5813 output_type
= second_par
->get_Type();
5815 second_par
->error("The second parameter must be an `out' value "
5816 "parameter for attribute `prototype(%s)' instead of %s",
5817 get_prototype_name(), second_par
->get_assname());
5820 fp_list
->error("The function must have two parameters for attribute "
5821 "`prototype(%s)' instead of %lu", get_prototype_name(),
5822 (unsigned long) fp_list
->get_nof_fps());
5825 // checking the return type
5826 if (prototype
== PROTOTYPE_FAST
) {
5828 return_type
->error("The function cannot have return type for "
5829 "attribute `prototype(%s)'", get_prototype_name());
5833 if (asstype
== A_FUNCTION_RTEMP
|| asstype
== A_EXT_FUNCTION_RTEMP
)
5834 return_type
->error("The function must return a value instead of a "
5835 "template for attribute `prototype(%s)'", get_prototype_name());
5836 if (prototype
== PROTOTYPE_CONVERT
) {
5837 output_type
= return_type
;
5839 switch (return_type
->get_type_refd_last()->get_typetype_ttcn3()) {
5844 return_type
->error("The return type of the function must be "
5845 "`integer' instead of `%s' for attribute `prototype(%s)'",
5846 return_type
->get_typename().c_str(), get_prototype_name());
5850 error("The function must have return type for attribute "
5851 "`prototype(%s)'", get_prototype_name());
5854 // checking the 'runs on' clause
5855 if (get_RunsOnType()) {
5856 error("The function cannot have `runs on' clause for attribute "
5857 "`prototype(%s)'", get_prototype_name());
5861 Type
*Def_Function_Base::get_input_type()
5863 if (!checked
) chk();
5867 Type
*Def_Function_Base::get_output_type()
5869 if (!checked
) chk();
5874 // =================================
5875 // ===== Def_Function
5876 // =================================
5878 Def_Function::Def_Function(Identifier
*p_id
, FormalParList
*p_fpl
,
5879 Reference
*p_runs_on_ref
, Type
*p_return_type
,
5880 bool returns_template
,
5881 template_restriction_t p_template_restriction
,
5882 StatementBlock
*p_block
)
5883 : Def_Function_Base(false, p_id
, p_fpl
, p_return_type
, returns_template
,
5884 p_template_restriction
),
5885 runs_on_ref(p_runs_on_ref
), runs_on_type(0), block(p_block
),
5886 is_startable(false), transparent(false)
5888 if (!p_block
) FATAL_ERROR("Def_Function::Def_Function()");
5889 block
->set_my_def(this);
5892 Def_Function::~Def_Function()
5898 Def_Function
*Def_Function::clone() const
5900 FATAL_ERROR("Def_Function::clone");
5903 void Def_Function::set_fullname(const string
& p_fullname
)
5905 Def_Function_Base::set_fullname(p_fullname
);
5906 if (runs_on_ref
) runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
5907 block
->set_fullname(p_fullname
+ ".<statement_block>");
5910 void Def_Function::set_my_scope(Scope
*p_scope
)
5912 bridgeScope
.set_parent_scope(p_scope
);
5913 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
5915 Def_Function_Base::set_my_scope(&bridgeScope
);
5916 if (runs_on_ref
) runs_on_ref
->set_my_scope(&bridgeScope
);
5917 block
->set_my_scope(fp_list
);
5920 Type
*Def_Function::get_RunsOnType()
5922 if (!checked
) chk();
5923 return runs_on_type
;
5926 RunsOnScope
*Def_Function::get_runs_on_scope(Type
*comptype
)
5928 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
5929 if (!my_module
) FATAL_ERROR("Def_Function::get_runs_on_scope()");
5930 return my_module
->get_runs_on_scope(comptype
);
5933 void Def_Function::chk()
5935 if (checked
) return;
5937 Error_Context
cntxt(this, "In function definition `%s'",
5938 id
->get_dispname().c_str());
5939 // checking the `runs on' clause
5941 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
5942 runs_on_type
= runs_on_ref
->chk_comptype_ref();
5943 // override the scope of the formal parameter list
5945 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
5946 runs_on_scope
->set_parent_scope(my_scope
);
5947 fp_list
->set_my_scope(runs_on_scope
);
5950 // checking the formal parameter list
5951 fp_list
->chk(asstype
);
5952 // checking of return type
5954 Error_Context
cntxt2(return_type
, "In return type");
5956 return_type
->chk_as_return_type(asstype
== A_FUNCTION_RVAL
,"function");
5958 // decision of startability
5959 is_startable
= runs_on_ref
!= 0;
5960 if (is_startable
&& !fp_list
->get_startability()) is_startable
= false;
5961 if (is_startable
&& return_type
&& return_type
->is_component_internal())
5962 is_startable
= false;
5963 // checking of statement block
5966 // checking the presence of return statements
5967 switch (block
->has_return()) {
5968 case StatementBlock::RS_NO
:
5969 error("The function has return type, but it does not have any return "
5972 case StatementBlock::RS_MAYBE
:
5973 error("The function has return type, but control might leave it "
5974 "without reaching a return statement");
5979 if (!semantic_check_only
) {
5980 fp_list
->set_genname(get_genname());
5981 block
->set_code_section(GovernedSimple::CS_INLINE
);
5983 if (w_attrib_path
) {
5984 w_attrib_path
->chk_global_attrib();
5985 w_attrib_path
->chk_no_qualif();
5986 Ttcn::ExtensionAttributes
* extattrs
= parse_extattributes(w_attrib_path
);
5987 if (extattrs
!= 0) { // NULL means parsing error
5988 size_t num_atrs
= extattrs
->size();
5989 for (size_t i
=0; i
< num_atrs
; ++i
) {
5990 ExtensionAttribute
&ea
= extattrs
->get(i
);
5991 switch (ea
.get_type()) {
5992 case ExtensionAttribute::PROTOTYPE
: {
5993 if (get_prototype() != Def_Function_Base::PROTOTYPE_NONE
) {
5994 ea
.error("Duplicate attribute `prototype'");
5996 Def_Function_Base::prototype_t proto
= ea
.get_proto();
5997 set_prototype(proto
);
6000 case ExtensionAttribute::ANYTYPELIST
: // ignore it
6001 case ExtensionAttribute::NONE
: // erroneous, do not issue an error
6004 case ExtensionAttribute::TRANSPARENT
:
6008 case ExtensionAttribute::ENCODE
:
6009 case ExtensionAttribute::DECODE
:
6010 case ExtensionAttribute::ERRORBEHAVIOR
:
6011 case ExtensionAttribute::PRINTING
:
6012 ea
.error("Extension attribute 'encode', 'decode', 'errorbehavior'"
6013 " or 'printing' can only be applied to external functions");
6016 default: // complain
6017 ea
.error("Function definition can only have the 'prototype'"
6018 " extension attribute");
6028 bool Def_Function::chk_startable()
6030 if (!checked
) chk();
6031 if (is_startable
) return true;
6032 if (!runs_on_ref
) error("Function `%s' cannot be started on a parallel "
6033 "test component because it does not have `runs on' clause",
6034 get_fullname().c_str());
6035 fp_list
->chk_startability("Function", get_fullname().c_str());
6036 if (return_type
&& return_type
->is_component_internal()) {
6037 map
<Type
*,void> type_chain
;
6038 char* err_str
= mprintf("the return type or embedded in the return type "
6039 "of function `%s' if it is started on a parallel test component",
6040 get_fullname().c_str());
6041 return_type
->chk_component_internal(type_chain
, err_str
);
6047 void Def_Function::generate_code(output_struct
*target
, bool)
6049 transparency_holder
glass(*this);
6050 const string
& t_genname
= get_genname();
6051 const char *genname_str
= t_genname
.c_str();
6052 const char *dispname_str
= id
->get_dispname().c_str();
6053 string return_type_name
;
6056 return_type_name
= "void";
6058 case A_FUNCTION_RVAL
:
6059 return_type_name
= return_type
->get_genname_value(my_scope
);
6061 case A_FUNCTION_RTEMP
:
6062 return_type_name
= return_type
->get_genname_template(my_scope
);
6065 FATAL_ERROR("Def_Function::generate_code()");
6067 const char *return_type_str
= return_type_name
.c_str();
6069 // assemble the function body first (this also determines which parameters
6071 char* body
= create_location_object(memptystr(), "FUNCTION", dispname_str
);
6072 if (!enable_set_bound_out_param
)
6073 body
= fp_list
->generate_code_set_unbound(body
); // conform the standard out parameter is unbound
6074 body
= fp_list
->generate_shadow_objects(body
);
6075 body
= block
->generate_code(body
);
6076 // smart formal parameter list (names of unused parameters are omitted)
6077 char *formal_par_list
= fp_list
->generate_code(memptystr());
6078 fp_list
->generate_code_defval(target
);
6079 // function prototype
6080 target
->header
.function_prototypes
=
6081 mputprintf(target
->header
.function_prototypes
, "extern %s %s(%s);\n",
6082 return_type_str
, genname_str
, formal_par_list
);
6085 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
6089 "}\n\n", return_type_str
, genname_str
, formal_par_list
, body
);
6090 Free(formal_par_list
);
6094 size_t nof_fps
= fp_list
->get_nof_fps();
6095 // use the full list of formal parameters here (since they are all logged)
6096 char *full_formal_par_list
= fp_list
->generate_code(memptystr(), nof_fps
);
6097 // starter function (stub)
6098 // function prototype
6099 target
->header
.function_prototypes
=
6100 mputprintf(target
->header
.function_prototypes
,
6101 "extern void start_%s(const COMPONENT& component_reference%s%s);\n",
6102 genname_str
, nof_fps
>0?", ":"", full_formal_par_list
);
6104 body
= mprintf("void start_%s(const COMPONENT& component_reference%s"
6107 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
6108 "TTCN_Logger::log_event_str(\"Starting function %s(\");\n",
6109 genname_str
, nof_fps
>0?", ":"", full_formal_par_list
, dispname_str
);
6110 for (size_t i
= 0; i
< nof_fps
; i
++) {
6111 if (i
> 0) body
= mputstr(body
,
6112 "TTCN_Logger::log_event_str(\", \");\n");
6113 body
= mputprintf(body
, "%s.log();\n",
6114 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6116 body
= mputprintf(body
,
6117 "TTCN_Logger::log_event_str(\") on component \");\n"
6118 "component_reference.log();\n"
6119 "TTCN_Logger::log_char('.');\n"
6120 "TTCN_Logger::end_event();\n"
6121 "Text_Buf text_buf;\n"
6122 "TTCN_Runtime::prepare_start_component(component_reference, "
6123 "\"%s\", \"%s\", text_buf);\n",
6124 my_scope
->get_scope_mod()->get_modid().get_dispname().c_str(),
6126 for (size_t i
= 0; i
< nof_fps
; i
++) {
6127 body
= mputprintf(body
, "%s.encode_text(text_buf);\n",
6128 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6130 body
= mputstr(body
, "TTCN_Runtime::send_start_component(text_buf);\n"
6132 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6136 // an entry in start_ptc_function
6137 body
= mprintf("if (!strcmp(function_name, \"%s\")) {\n",
6140 body
= fp_list
->generate_code_object(body
, "", ' ');
6141 for (size_t i
= 0; i
< nof_fps
; i
++) {
6142 body
= mputprintf(body
, "%s.decode_text(function_arguments);\n",
6143 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6145 body
= mputprintf(body
,
6146 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
6147 "TTCN_Logger::log_event_str(\"Starting function %s(\");\n",
6149 for (size_t i
= 0; i
< nof_fps
; i
++) {
6150 if (i
> 0) body
= mputstr(body
,
6151 "TTCN_Logger::log_event_str(\", \");\n");
6152 body
= mputprintf(body
, "%s.log();\n",
6153 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6155 body
= mputstr(body
, "TTCN_Logger::log_event_str(\").\");\n"
6156 "TTCN_Logger::end_event();\n");
6158 body
= mputprintf(body
,
6159 "TTCN_Logger::log_str(TTCN_Logger::PARALLEL_PTC, \"Starting function "
6160 "%s().\");\n", dispname_str
);
6162 body
= mputstr(body
,
6163 "TTCN_Runtime::function_started(function_arguments);\n");
6164 char *actual_par_list
=
6165 fp_list
->generate_code_actual_parlist(memptystr(), "");
6166 bool return_value_kept
= false;
6167 if (asstype
== A_FUNCTION_RVAL
) {
6168 // the return value is kept only if the function returns a value
6169 // (rather than a template) and the return type has the "done"
6170 // extension attribute
6171 for (Type
*t
= return_type
; ; t
= t
->get_type_refd()) {
6172 if (t
->has_done_attribute()) {
6173 return_value_kept
= true;
6175 } else if (!t
->is_ref()) break;
6178 if (return_value_kept
) {
6179 const string
& return_type_dispname
= return_type
->get_typename();
6180 const char *return_type_dispname_str
= return_type_dispname
.c_str();
6181 body
= mputprintf(body
, "%s ret_val(%s(%s));\n"
6182 "TTCN_Logger::begin_event(TTCN_PARALLEL);\n"
6183 "TTCN_Logger::log_event_str(\"Function %s returned %s : \");\n"
6185 "Text_Buf text_buf;\n"
6186 "TTCN_Runtime::prepare_function_finished(\"%s\", text_buf);\n"
6187 "ret_val.encode_text(text_buf);\n"
6188 "TTCN_Runtime::send_function_finished(text_buf);\n",
6189 return_type_str
, genname_str
, actual_par_list
, dispname_str
,
6190 return_type_dispname_str
, return_type_dispname_str
);
6192 body
= mputprintf(body
, "%s(%s);\n"
6193 "TTCN_Runtime::function_finished(\"%s\");\n",
6194 genname_str
, actual_par_list
, dispname_str
);
6196 Free(actual_par_list
);
6197 body
= mputstr(body
, "return TRUE;\n"
6199 target
->functions
.start
= mputstr(target
->functions
.start
, body
);
6201 Free(full_formal_par_list
);
6204 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6205 "%s.add_function(\"%s\", (genericfunc_t)&%s, ", get_module_object_name(),
6206 dispname_str
, genname_str
);
6208 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6209 "(genericfunc_t)&start_%s);\n", genname_str
);
6211 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
6215 void Def_Function::generate_code(CodeGenHelper
& cgh
) {
6216 generate_code(cgh
.get_current_outputstruct());
6219 void Def_Function::dump_internal(unsigned level
) const
6221 DEBUG(level
, "Function: %s", id
->get_dispname().c_str());
6222 DEBUG(level
+ 1, "Parameters:");
6223 fp_list
->dump(level
+ 1);
6225 DEBUG(level
+ 1, "Runs on clause:");
6226 runs_on_ref
->dump(level
+ 2);
6229 DEBUG(level
+ 1, "Return type:");
6230 return_type
->dump(level
+ 2);
6231 if (asstype
== A_FUNCTION_RTEMP
) DEBUG(level
+ 1, "Returns template");
6233 if (prototype
!= PROTOTYPE_NONE
)
6234 DEBUG(level
+ 1, "Prototype: %s", get_prototype_name());
6235 //DEBUG(level + 1, "Statement block:");
6236 block
->dump(level
+ 1);
6239 void Def_Function::set_parent_path(WithAttribPath
* p_path
) {
6240 Def_Function_Base::set_parent_path(p_path
);
6241 block
->set_parent_path(w_attrib_path
);
6244 // =================================
6245 // ===== Def_ExtFunction
6246 // =================================
6248 Def_ExtFunction::~Def_ExtFunction()
6250 delete encoding_options
;
6252 if (NULL
!= json_printing
) {
6253 delete json_printing
;
6257 Def_ExtFunction
*Def_ExtFunction::clone() const
6259 FATAL_ERROR("Def_ExtFunction::clone");
6262 void Def_ExtFunction::set_fullname(const string
& p_fullname
)
6264 Def_Function_Base::set_fullname(p_fullname
);
6265 if (eb_list
) eb_list
->set_fullname(p_fullname
+ ".<errorbehavior_list>");
6268 void Def_ExtFunction::set_encode_parameters(Type::MessageEncodingType_t
6269 p_encoding_type
, string
*p_encoding_options
)
6271 function_type
= EXTFUNC_ENCODE
;
6272 encoding_type
= p_encoding_type
;
6273 delete encoding_options
;
6274 encoding_options
= p_encoding_options
;
6277 void Def_ExtFunction::set_decode_parameters(Type::MessageEncodingType_t
6278 p_encoding_type
, string
*p_encoding_options
)
6280 function_type
= EXTFUNC_DECODE
;
6281 encoding_type
= p_encoding_type
;
6282 delete encoding_options
;
6283 encoding_options
= p_encoding_options
;
6286 void Def_ExtFunction::add_eb_list(Ttcn::ErrorBehaviorList
*p_eb_list
)
6288 if (!p_eb_list
) FATAL_ERROR("Def_ExtFunction::add_eb_list()");
6290 eb_list
->steal_ebs(p_eb_list
);
6293 eb_list
= p_eb_list
;
6294 eb_list
->set_fullname(get_fullname() + ".<errorbehavior_list>");
6298 void Def_ExtFunction::chk_function_type()
6300 switch (function_type
) {
6301 case EXTFUNC_MANUAL
:
6303 eb_list
->error("Attribute `errorbehavior' can only be used together "
6304 "with `encode' or `decode'");
6308 case EXTFUNC_ENCODE
:
6309 switch (prototype
) {
6310 case PROTOTYPE_NONE
:
6311 error("Attribute `encode' cannot be used without `prototype'");
6313 case PROTOTYPE_BACKTRACK
:
6314 case PROTOTYPE_SLIDING
:
6315 error("Attribute `encode' cannot be used with `prototype(%s)'",
6316 get_prototype_name());
6317 default: /* CONVERT and FAST allowed */
6322 if (!input_type
->has_encoding(encoding_type
, encoding_options
)) {
6323 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6324 input_type
->error("Input type `%s' does not support custom encoding '%s'",
6325 input_type
->get_typename().c_str(), encoding_options
->c_str());
6328 input_type
->error("Input type `%s' does not support %s encoding",
6329 input_type
->get_typename().c_str(),
6330 Type::get_encoding_name(encoding_type
));
6334 if (Common::Type::CT_XER
== encoding_type
6335 && input_type
->get_type_refd_last()->is_untagged()) {
6336 // "untagged" on the (toplevel) input type will have no effect.
6337 warning("UNTAGGED encoding attribute is ignored on top-level type");
6339 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6340 if (PROTOTYPE_CONVERT
!= prototype
) {
6341 error("Only `prototype(convert)' is allowed for custom encoding functions");
6344 // let the input type know that this is its encoding function
6345 input_type
->get_type_refd()->set_coding_function(true,
6346 get_genname_from_scope(input_type
->get_type_refd()->get_my_scope()));
6347 // treat this as a manual external function during code generation
6348 function_type
= EXTFUNC_MANUAL
;
6354 if(encoding_type
== Common::Type::CT_TEXT
) { // TEXT encoding supports both octetstring and charstring stream types
6355 Type
*stream_type
= Type::get_stream_type(encoding_type
,0);
6356 Type
*stream_type2
= Type::get_stream_type(encoding_type
,1);
6357 if ( (!stream_type
->is_identical(output_type
)) && (!stream_type2
->is_identical(output_type
)) ) {
6358 output_type
->error("The output type of %s encoding should be `%s' or `%s' "
6359 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6360 stream_type
->get_typename().c_str(),
6361 stream_type2
->get_typename().c_str(),
6362 output_type
->get_typename().c_str());
6365 Type
*stream_type
= Type::get_stream_type(encoding_type
);
6366 if (!stream_type
->is_identical(output_type
)) {
6367 output_type
->error("The output type of %s encoding should be `%s' "
6368 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6369 stream_type
->get_typename().c_str(),
6370 output_type
->get_typename().c_str());
6374 if (eb_list
) eb_list
->chk();
6375 chk_allowed_encode();
6377 case EXTFUNC_DECODE
:
6378 if (prototype
== PROTOTYPE_NONE
) {
6379 error("Attribute `decode' cannot be used without `prototype'");
6382 if(encoding_type
== Common::Type::CT_TEXT
) { // TEXT encoding supports both octetstring and charstring stream types
6383 Type
*stream_type
= Type::get_stream_type(encoding_type
,0);
6384 Type
*stream_type2
= Type::get_stream_type(encoding_type
,1);
6385 if ( (!stream_type
->is_identical(input_type
)) && (!stream_type2
->is_identical(input_type
)) ) {
6386 input_type
->error("The input type of %s decoding should be `%s' or `%s' "
6387 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6388 stream_type
->get_typename().c_str(),
6389 stream_type2
->get_typename().c_str(),
6390 input_type
->get_typename().c_str());
6393 Type
*stream_type
= Type::get_stream_type(encoding_type
);
6394 if (!stream_type
->is_identical(input_type
)) {
6395 input_type
->error("The input type of %s decoding should be `%s' "
6396 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6397 stream_type
->get_typename().c_str(),
6398 input_type
->get_typename().c_str());
6403 if (output_type
&& !output_type
->has_encoding(encoding_type
, encoding_options
)) {
6404 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6405 output_type
->error("Output type `%s' does not support custom encoding '%s'",
6406 output_type
->get_typename().c_str(), encoding_options
->c_str());
6409 output_type
->error("Output type `%s' does not support %s encoding",
6410 output_type
->get_typename().c_str(),
6411 Type::get_encoding_name(encoding_type
));
6415 if (Common::Type::CT_CUSTOM
== encoding_type
) {
6416 if (PROTOTYPE_SLIDING
!= prototype
) {
6417 error("Only `prototype(sliding)' is allowed for custom decoding functions");
6419 else if (output_type
) {
6420 // let the output type know that this is its decoding function
6421 output_type
->get_type_refd()->set_coding_function(false,
6422 get_genname_from_scope(output_type
->get_type_refd()->get_my_scope()));
6423 // treat this as a manual external function during code generation
6424 function_type
= EXTFUNC_MANUAL
;
6428 if (eb_list
) eb_list
->chk();
6429 chk_allowed_encode();
6432 FATAL_ERROR("Def_ExtFunction::chk()");
6436 void Def_ExtFunction::chk_allowed_encode()
6438 switch (encoding_type
) {
6440 if (enable_ber()) return; // ok
6443 if (enable_raw()) return; // ok
6446 if (enable_text()) return; // ok
6449 if (enable_xer()) return; // ok
6452 if (enable_per()) return; // ok?
6455 if (enable_json()) return;
6457 case Type::CT_CUSTOM
:
6458 return; // cannot be disabled
6460 FATAL_ERROR("Def_ExtFunction::chk_allowed_encode");
6464 error("%s encoding is disallowed by license or commandline options",
6465 Type::get_encoding_name(encoding_type
));
6468 void Def_ExtFunction::chk()
6470 if (checked
) return;
6472 Error_Context
cntxt(this, "In external function definition `%s'",
6473 id
->get_dispname().c_str());
6474 fp_list
->chk(asstype
);
6476 Error_Context
cntxt2(return_type
, "In return type");
6478 return_type
->chk_as_return_type(asstype
== A_EXT_FUNCTION_RVAL
,
6479 "external function");
6481 if (!semantic_check_only
) fp_list
->set_genname(get_genname());
6482 if (w_attrib_path
) {
6483 w_attrib_path
->chk_global_attrib();
6484 w_attrib_path
->chk_no_qualif();
6485 const Ttcn::ExtensionAttributes
* extattrs
= parse_extattributes(w_attrib_path
);
6486 if (extattrs
!= 0) {
6487 size_t num_atrs
= extattrs
->size();
6488 for (size_t i
=0; i
< num_atrs
; ++i
) {
6489 ExtensionAttribute
&ea
= extattrs
->get(i
);
6490 switch (ea
.get_type()) {
6491 case ExtensionAttribute::PROTOTYPE
: {
6492 if (get_prototype() != Def_Function_Base::PROTOTYPE_NONE
) {
6493 ea
.error("Duplicate attribute `prototype'");
6495 Def_Function_Base::prototype_t proto
= ea
.get_proto();
6496 set_prototype(proto
);
6499 case ExtensionAttribute::ENCODE
: {
6500 switch (get_function_type()) {
6501 case Def_ExtFunction::EXTFUNC_MANUAL
:
6503 case Def_ExtFunction::EXTFUNC_ENCODE
: {
6504 ea
.error("Duplicate attribute `encode'");
6506 case Def_ExtFunction::EXTFUNC_DECODE
: {
6507 ea
.error("Attributes `decode' and `encode' "
6508 "cannot be used at the same time");
6511 FATAL_ERROR("coding_attrib_parse(): invalid external function type");
6513 Type::MessageEncodingType_t et
;
6515 ea
.get_encdec_parameters(et
, opt
);
6516 set_encode_parameters(et
, opt
);
6519 case ExtensionAttribute::ERRORBEHAVIOR
: {
6520 add_eb_list(ea
.get_eb_list());
6523 case ExtensionAttribute::DECODE
: {
6524 switch (get_function_type()) {
6525 case Def_ExtFunction::EXTFUNC_MANUAL
:
6527 case Def_ExtFunction::EXTFUNC_ENCODE
: {
6528 ea
.error("Attributes `encode' and `decode' "
6529 "cannot be used at the same time");
6531 case Def_ExtFunction::EXTFUNC_DECODE
: {
6532 ea
.error("Duplicate attribute `decode'");
6535 FATAL_ERROR("coding_attrib_parse(): invalid external function type");
6537 Type::MessageEncodingType_t et
;
6539 ea
.get_encdec_parameters(et
, opt
);
6540 set_decode_parameters(et
, opt
);
6543 case ExtensionAttribute::PRINTING
: {
6544 json_printing
= ea
.get_printing();
6547 case ExtensionAttribute::ANYTYPELIST
:
6548 // ignore, because we can't distinguish between a local
6549 // "extension anytype" (which is bogus) and an inherited one
6550 // (which was meant for a type definition)
6553 case ExtensionAttribute::NONE
:
6554 // Ignore, do not issue "wrong type" error
6559 "Only the following extension attributes may be applied to "
6560 "external functions: 'prototype', 'encode', 'decode', 'errorbehavior'");
6568 chk_function_type();
6570 if (NULL
!= json_printing
&& (EXTFUNC_ENCODE
!= function_type
||
6571 Type::CT_JSON
!= encoding_type
)) {
6572 error("Attribute 'printing' is only allowed for JSON encoding functions.");
6576 char *Def_ExtFunction::generate_code_encode(char *str
)
6578 const char *function_name
= id
->get_dispname().c_str();
6579 const char *first_par_name
=
6580 fp_list
->get_fp_byIndex(0)->get_id().get_name().c_str();
6581 // producing debug printout of the input PDU
6582 str
= mputprintf(str
,
6584 "// written by %s in " __FILE__
" at %d\n"
6586 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6587 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6588 "TTCN_Logger::log_event_str(\"%s(): Encoding %s: \");\n"
6590 "TTCN_Logger::end_event();\n"
6593 , __FUNCTION__
, __LINE__
6595 , function_name
, input_type
->get_typename().c_str(), first_par_name
);
6596 // setting error behavior
6597 if (eb_list
) str
= eb_list
->generate_code(str
);
6598 else str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6599 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n");
6600 // encoding PDU into the buffer
6601 str
= mputstr(str
, "TTCN_Buffer ttcn_buffer;\n");
6602 str
= mputprintf(str
, "%s.encode(%s_descr_, ttcn_buffer, TTCN_EncDec::CT_%s",
6604 input_type
->get_genname_typedescriptor(my_scope
).c_str(),
6605 Type::get_encoding_name(encoding_type
));
6606 if (encoding_type
== Type::CT_JSON
) {
6607 if (json_printing
!= NULL
) {
6608 str
= json_printing
->generate_code(str
);
6610 str
= mputstr(str
, ", 0");
6613 if (encoding_options
) str
= mputprintf(str
, ", %s",
6614 encoding_options
->c_str());
6615 str
= mputstr(str
, ");\n");
6616 const char *result_name
;
6617 switch (prototype
) {
6618 case PROTOTYPE_CONVERT
:
6619 result_name
= "ret_val";
6620 // creating a local variable for the result stream
6621 str
= mputprintf(str
, "%s ret_val;\n",
6622 output_type
->get_genname_value(my_scope
).c_str());
6624 case PROTOTYPE_FAST
:
6625 result_name
= fp_list
->get_fp_byIndex(1)->get_id().get_name().c_str();
6628 FATAL_ERROR("Def_ExtFunction::generate_code_encode()");
6631 // taking the result from the buffer and producing debug printout
6632 str
= mputprintf(str
, "ttcn_buffer.get_string(%s);\n"
6633 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6634 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6635 "TTCN_Logger::log_event_str(\"%s(): Stream after encoding: \");\n"
6637 "TTCN_Logger::end_event();\n"
6638 "}\n", result_name
, function_name
, result_name
);
6639 // returning the result stream if necessary
6640 if (prototype
== PROTOTYPE_CONVERT
) str
= mputstr(str
, "return ret_val;\n");
6644 char *Def_ExtFunction::generate_code_decode(char *str
)
6646 const char *function_name
= id
->get_dispname().c_str();
6647 const char *first_par_name
=
6648 fp_list
->get_fp_byIndex(0)->get_id().get_name().c_str();
6649 // producing debug printout of the input stream
6650 str
= mputprintf(str
,
6652 "// written by %s in " __FILE__
" at %d\n"
6654 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6655 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6656 "TTCN_Logger::log_event_str(\"%s(): Stream before decoding: \");\n"
6658 "TTCN_Logger::end_event();\n"
6661 , __FUNCTION__
, __LINE__
6663 , function_name
, first_par_name
);
6664 // setting error behavior
6665 if (eb_list
) str
= eb_list
->generate_code(str
);
6666 else if (prototype
== PROTOTYPE_BACKTRACK
|| prototype
== PROTOTYPE_SLIDING
) {
6667 str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6668 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);\n");
6669 } else str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6670 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n");
6671 // creating a buffer from the input stream
6672 str
= mputprintf(str
, "TTCN_EncDec::clear_error();\n"
6673 "TTCN_Buffer ttcn_buffer(%s);\n", first_par_name
);
6674 const char *result_name
;
6675 if (prototype
== PROTOTYPE_CONVERT
) {
6676 // creating a local variable for the result
6677 str
= mputprintf(str
, "%s ret_val;\n",
6678 output_type
->get_genname_value(my_scope
).c_str());
6679 result_name
= "ret_val";
6681 result_name
= fp_list
->get_fp_byIndex(1)->get_id().get_name().c_str();
6683 if(encoding_type
==Type::CT_TEXT
){
6684 str
= mputprintf(str
,
6685 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6686 " TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_LOG_MATCHING, TTCN_EncDec::EB_WARNING);\n"
6689 str
= mputprintf(str
, "%s.decode(%s_descr_, ttcn_buffer, "
6690 "TTCN_EncDec::CT_%s", result_name
,
6691 output_type
->get_genname_typedescriptor(my_scope
).c_str(),
6692 Type::get_encoding_name(encoding_type
));
6693 if (encoding_options
) str
= mputprintf(str
, ", %s",
6694 encoding_options
->c_str());
6695 str
= mputstr(str
, ");\n");
6696 // producing debug printout of the result PDU
6697 str
= mputprintf(str
,
6698 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6699 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6700 "TTCN_Logger::log_event_str(\"%s(): Decoded %s: \");\n"
6702 "TTCN_Logger::end_event();\n"
6703 "}\n", function_name
, output_type
->get_typename().c_str(), result_name
);
6704 if (prototype
!= PROTOTYPE_SLIDING
) {
6705 // checking for remaining data in the buffer if decoding was successful
6706 str
= mputprintf(str
, "if (TTCN_EncDec::get_last_error_type() == "
6707 "TTCN_EncDec::ET_NONE) {\n"
6708 "if (ttcn_buffer.get_pos() < ttcn_buffer.get_len()-1 && "
6709 "TTCN_Logger::log_this_event(TTCN_WARNING)) {\n"
6710 "ttcn_buffer.cut();\n"
6711 "%s remaining_stream;\n"
6712 "ttcn_buffer.get_string(remaining_stream);\n"
6713 "TTCN_Logger::begin_event(TTCN_WARNING);\n"
6714 "TTCN_Logger::log_event_str(\"%s(): Warning: Data remained at the end "
6715 "of the stream after successful decoding: \");\n"
6716 "remaining_stream.log();\n"
6717 "TTCN_Logger::end_event();\n"
6718 "}\n", input_type
->get_genname_value(my_scope
).c_str(), function_name
);
6719 // closing the block and returning the appropriate result or status code
6720 if (prototype
== PROTOTYPE_BACKTRACK
) {
6721 str
= mputstr(str
, "return 0;\n"
6722 "} else return 1;\n");
6724 str
= mputstr(str
, "}\n");
6725 if (prototype
== PROTOTYPE_CONVERT
)
6726 str
= mputstr(str
, "return ret_val;\n");
6729 // result handling and debug printout for sliding decoders
6730 str
= mputprintf(str
, "switch (TTCN_EncDec::get_last_error_type()) {\n"
6731 "case TTCN_EncDec::ET_NONE:\n"
6732 // TTCN_Buffer::get_string will call OCTETSTRING::clean_up()
6733 "ttcn_buffer.cut();\n"
6734 "ttcn_buffer.get_string(%s);\n"
6735 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6736 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6737 "TTCN_Logger::log_event_str(\"%s(): Stream after decoding: \");\n"
6739 "TTCN_Logger::end_event();\n"
6742 "case TTCN_EncDec::ET_INCOMPL_MSG:\n"
6743 "case TTCN_EncDec::ET_LEN_ERR:\n"
6747 "}\n", first_par_name
, function_name
, first_par_name
);
6752 void Def_ExtFunction::generate_code(output_struct
*target
, bool)
6754 const string
& t_genname
= get_genname();
6755 const char *genname_str
= t_genname
.c_str();
6756 string return_type_name
;
6758 case A_EXT_FUNCTION
:
6759 return_type_name
= "void";
6761 case A_EXT_FUNCTION_RVAL
:
6762 return_type_name
= return_type
->get_genname_value(my_scope
);
6764 case A_EXT_FUNCTION_RTEMP
:
6765 return_type_name
= return_type
->get_genname_template(my_scope
);
6768 FATAL_ERROR("Def_ExtFunction::generate_code()");
6770 const char *return_type_str
= return_type_name
.c_str();
6771 char *formal_par_list
= fp_list
->generate_code(memptystr(), fp_list
->get_nof_fps());
6772 fp_list
->generate_code_defval(target
);
6773 // function prototype
6774 target
->header
.function_prototypes
=
6775 mputprintf(target
->header
.function_prototypes
, "extern %s %s(%s);\n",
6776 return_type_str
, genname_str
, formal_par_list
);
6778 if (function_type
!= EXTFUNC_MANUAL
) {
6779 // function body written by the compiler
6782 body
= mprintf("// written by %s in " __FILE__
" at %d\n"
6783 , __FUNCTION__
, __LINE__
);
6785 body
= mputprintf(body
,
6788 , return_type_str
, genname_str
, formal_par_list
);
6789 switch (function_type
) {
6790 case EXTFUNC_ENCODE
:
6791 body
= generate_code_encode(body
);
6793 case EXTFUNC_DECODE
:
6794 body
= generate_code_decode(body
);
6797 FATAL_ERROR("Def_ExtFunction::generate_code()");
6799 body
= mputstr(body
, "}\n\n");
6800 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6805 Free(formal_par_list
);
6807 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6808 "%s.add_function(\"%s\", (genericfunc_t)&%s, NULL);\n",
6809 get_module_object_name(), id
->get_dispname().c_str(), genname_str
);
6812 void Def_ExtFunction::generate_code(CodeGenHelper
& cgh
) {
6813 generate_code(cgh
.get_current_outputstruct());
6816 void Def_ExtFunction::dump_internal(unsigned level
) const
6818 DEBUG(level
, "External function: %s", id
->get_dispname().c_str());
6819 DEBUG(level
+ 1, "Parameters:");
6820 fp_list
->dump(level
+ 2);
6822 DEBUG(level
+ 1, "Return type:");
6823 return_type
->dump(level
+ 2);
6824 if(asstype
== A_EXT_FUNCTION_RTEMP
) DEBUG(level
+ 1, "Returns template");
6826 if (prototype
!= PROTOTYPE_NONE
)
6827 DEBUG(level
+ 1, "Prototype: %s", get_prototype_name());
6828 if (function_type
!= EXTFUNC_MANUAL
) {
6829 DEBUG(level
+ 1, "Automatically generated: %s",
6830 function_type
== EXTFUNC_ENCODE
? "encoder" : "decoder");
6831 DEBUG(level
+ 2, "Encoding type: %s",
6832 Type::get_encoding_name(encoding_type
));
6833 if (encoding_options
)
6834 DEBUG(level
+ 2, "Encoding options: %s", encoding_options
->c_str());
6836 if (eb_list
) eb_list
->dump(level
+ 1);
6839 void Def_ExtFunction::generate_json_schema_ref(map
<Type
*, JSON_Tokenizer
>& json_refs
)
6841 // only do anything if this is a JSON encoding or decoding function
6842 if (encoding_type
== Type::CT_JSON
&&
6843 (function_type
== EXTFUNC_ENCODE
|| function_type
== EXTFUNC_DECODE
)) {
6844 // retrieve the encoded type
6846 if (function_type
== EXTFUNC_ENCODE
) {
6847 // for encoding functions it's always the first parameter
6848 type
= fp_list
->get_fp_byIndex(0)->get_Type();
6850 // for decoding functions it depends on the prototype
6851 switch (prototype
) {
6852 case PROTOTYPE_CONVERT
:
6855 case PROTOTYPE_FAST
:
6856 case PROTOTYPE_BACKTRACK
:
6857 case PROTOTYPE_SLIDING
:
6858 type
= fp_list
->get_fp_byIndex(1)->get_Type();
6861 FATAL_ERROR("Def_ExtFunction::generate_json_schema_ref");
6865 // step over the type reference created for this function
6866 type
= type
->get_type_refd();
6868 JSON_Tokenizer
* json
= NULL
;
6869 if (json_refs
.has_key(type
)) {
6870 // the schema segment containing the type's reference already exists
6871 json
= json_refs
[type
];
6873 // the schema segment doesn't exist yet, create it and insert the reference
6874 json
= new JSON_Tokenizer
;
6875 json_refs
.add(type
, json
);
6876 type
->generate_json_schema_ref(*json
);
6879 // insert a property to specify which function this is (encoding or decoding)
6880 json
->put_next_token(JSON_TOKEN_NAME
, (function_type
== EXTFUNC_ENCODE
) ?
6881 "encoding" : "decoding");
6883 // place the function's info in an object
6884 json
->put_next_token(JSON_TOKEN_OBJECT_START
);
6886 // insert information related to the function's prototype in an array
6887 json
->put_next_token(JSON_TOKEN_NAME
, "prototype");
6888 json
->put_next_token(JSON_TOKEN_ARRAY_START
);
6890 // 1st element: external function prototype name (as string)
6892 case PROTOTYPE_CONVERT
:
6893 json
->put_next_token(JSON_TOKEN_STRING
, "\"convert\"");
6895 case PROTOTYPE_FAST
:
6896 json
->put_next_token(JSON_TOKEN_STRING
, "\"fast\"");
6898 case PROTOTYPE_BACKTRACK
:
6899 json
->put_next_token(JSON_TOKEN_STRING
, "\"backtrack\"");
6901 case PROTOTYPE_SLIDING
:
6902 json
->put_next_token(JSON_TOKEN_STRING
, "\"sliding\"");
6905 FATAL_ERROR("Def_ExtFunction::generate_json_schema_ref");
6908 // 2nd element: external function name
6909 char* func_name_str
= mprintf("\"%s\"", id
->get_dispname().c_str());
6910 json
->put_next_token(JSON_TOKEN_STRING
, func_name_str
);
6911 Free(func_name_str
);
6913 // the rest of the elements contain the names of the function's parameters (1 or 2)
6914 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
6915 char* param_str
= mprintf("\"%s\"",
6916 fp_list
->get_fp_byIndex(i
)->get_id().get_dispname().c_str());
6917 json
->put_next_token(JSON_TOKEN_STRING
, param_str
);
6921 // end of the prototype's array
6922 json
->put_next_token(JSON_TOKEN_ARRAY_END
);
6924 // insert error behavior data
6925 if (eb_list
!= NULL
) {
6926 json
->put_next_token(JSON_TOKEN_NAME
, "errorBehavior");
6927 json
->put_next_token(JSON_TOKEN_OBJECT_START
);
6929 // add each error behavior modification as a property
6930 for (size_t i
= 0; i
< eb_list
->get_nof_ebs(); ++i
) {
6931 ErrorBehaviorSetting
* eb
= eb_list
->get_ebs_byIndex(i
);
6932 json
->put_next_token(JSON_TOKEN_NAME
, eb
->get_error_type().c_str());
6933 char* handling_str
= mprintf("\"%s\"", eb
->get_error_handling().c_str());
6934 json
->put_next_token(JSON_TOKEN_STRING
, handling_str
);
6938 json
->put_next_token(JSON_TOKEN_OBJECT_END
);
6941 // insert printing type
6942 if (json_printing
!= NULL
) {
6943 json
->put_next_token(JSON_TOKEN_NAME
, "printing");
6944 json
->put_next_token(JSON_TOKEN_STRING
,
6945 (json_printing
->get_printing() == PrintingType::PT_PRETTY
) ?
6946 "\"pretty\"" : "\"compact\"");
6949 // end of this function's object
6950 json
->put_next_token(JSON_TOKEN_OBJECT_END
);
6954 // =================================
6955 // ===== Def_Altstep
6956 // =================================
6958 Def_Altstep::Def_Altstep(Identifier
*p_id
, FormalParList
*p_fpl
,
6959 Reference
*p_runs_on_ref
, StatementBlock
*p_sb
,
6961 : Definition(A_ALTSTEP
, p_id
), fp_list(p_fpl
), runs_on_ref(p_runs_on_ref
),
6962 runs_on_type(0), sb(p_sb
), ags(p_ags
)
6964 if (!p_fpl
|| !p_sb
|| !p_ags
)
6965 FATAL_ERROR("Def_Altstep::Def_Altstep()");
6966 fp_list
->set_my_def(this);
6967 sb
->set_my_def(this);
6968 ags
->set_my_def(this);
6969 ags
->set_my_sb(sb
, 0);
6972 Def_Altstep::~Def_Altstep()
6980 Def_Altstep
*Def_Altstep::clone() const
6982 FATAL_ERROR("Def_Altstep::clone");
6985 void Def_Altstep::set_fullname(const string
& p_fullname
)
6987 Definition::set_fullname(p_fullname
);
6988 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
6989 if (runs_on_ref
) runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
6990 sb
->set_fullname(p_fullname
+".<block>");
6991 ags
->set_fullname(p_fullname
+ ".<guards>");
6994 void Def_Altstep::set_my_scope(Scope
*p_scope
)
6996 bridgeScope
.set_parent_scope(p_scope
);
6997 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
6999 Definition::set_my_scope(&bridgeScope
);
7000 // the scope of the parameter list is set during checking
7001 if (runs_on_ref
) runs_on_ref
->set_my_scope(&bridgeScope
);
7002 sb
->set_my_scope(fp_list
);
7003 ags
->set_my_scope(sb
);
7006 Type
*Def_Altstep::get_RunsOnType()
7008 if (!checked
) chk();
7009 return runs_on_type
;
7012 FormalParList
*Def_Altstep::get_FormalParList()
7014 if (!checked
) chk();
7018 RunsOnScope
*Def_Altstep::get_runs_on_scope(Type
*comptype
)
7020 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
7021 if (!my_module
) FATAL_ERROR("Def_Altstep::get_runs_on_scope()");
7022 return my_module
->get_runs_on_scope(comptype
);
7025 void Def_Altstep::chk()
7027 if (checked
) return;
7029 Error_Context
cntxt(this, "In altstep definition `%s'",
7030 id
->get_dispname().c_str());
7031 Scope
*parlist_scope
= my_scope
;
7033 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
7034 runs_on_type
= runs_on_ref
->chk_comptype_ref();
7036 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
7037 runs_on_scope
->set_parent_scope(my_scope
);
7038 parlist_scope
= runs_on_scope
;
7041 fp_list
->set_my_scope(parlist_scope
);
7042 fp_list
->chk(asstype
);
7044 ags
->set_is_altstep();
7045 ags
->set_my_ags(ags
);
7046 ags
->set_my_laic_stmt(ags
, 0);
7048 if (!semantic_check_only
) {
7049 fp_list
->set_genname(get_genname());
7050 sb
->set_code_section(GovernedSimple::CS_INLINE
);
7051 ags
->set_code_section(GovernedSimple::CS_INLINE
);
7053 if (w_attrib_path
) {
7054 w_attrib_path
->chk_global_attrib();
7055 w_attrib_path
->chk_no_qualif();
7059 void Def_Altstep::generate_code(output_struct
*target
, bool)
7061 const string
& t_genname
= get_genname();
7062 const char *genname_str
= t_genname
.c_str();
7063 const char *dispname_str
= id
->get_dispname().c_str();
7065 // function for altstep instance:
7066 // assemble the function body first (this also determines which parameters
7068 char* body
= create_location_object(memptystr(), "ALTSTEP", dispname_str
);
7069 body
= fp_list
->generate_shadow_objects(body
);
7070 body
= sb
->generate_code(body
);
7071 body
= ags
->generate_code_altstep(body
);
7072 // generate a smart formal parameter list (omits unused parameter names)
7073 char *formal_par_list
= fp_list
->generate_code(memptystr());
7074 fp_list
->generate_code_defval(target
);
7076 // function for altstep instance: prototype
7077 target
->header
.function_prototypes
=
7078 mputprintf(target
->header
.function_prototypes
,
7079 "extern alt_status %s_instance(%s);\n", genname_str
, formal_par_list
);
7081 // function for altstep instance: body
7082 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
7083 "alt_status %s_instance(%s)\n"
7086 "}\n\n", genname_str
, formal_par_list
, body
);
7087 Free(formal_par_list
);
7090 char *actual_par_list
=
7091 fp_list
->generate_code_actual_parlist(memptystr(), "");
7093 // use a full formal parameter list for the rest of the functions
7094 char *full_formal_par_list
= fp_list
->generate_code(memptystr(),
7095 fp_list
->get_nof_fps());
7097 // wrapper function for stand-alone instantiation: prototype
7098 target
->header
.function_prototypes
=
7099 mputprintf(target
->header
.function_prototypes
,
7100 "extern void %s(%s);\n", genname_str
, full_formal_par_list
);
7102 // wrapper function for stand-alone instantiation: body
7103 target
->source
.function_bodies
=
7104 mputprintf(target
->source
.function_bodies
, "void %s(%s)\n"
7107 "boolean block_flag = FALSE;\n"
7108 "alt_status altstep_flag = ALT_UNCHECKED, "
7109 "default_flag = ALT_UNCHECKED;\n"
7111 "TTCN_Snapshot::take_new(block_flag);\n"
7112 "if (altstep_flag != ALT_NO) {\n"
7113 "altstep_flag = %s_instance(%s);\n"
7114 "if (altstep_flag == ALT_YES || altstep_flag == ALT_BREAK) return;\n"
7115 "else if (altstep_flag == ALT_REPEAT) goto altstep_begin;\n"
7117 "if (default_flag != ALT_NO) {\n"
7118 "default_flag = TTCN_Default::try_altsteps();\n"
7119 "if (default_flag == ALT_YES || default_flag == ALT_BREAK) return;\n"
7120 "else if (default_flag == ALT_REPEAT) goto altstep_begin;\n"
7122 "if (altstep_flag == ALT_NO && default_flag == ALT_NO) "
7123 "TTCN_error(\"None of the branches can be chosen in altstep %s.\");\n"
7124 "else block_flag = TRUE;\n"
7126 "}\n\n", genname_str
, full_formal_par_list
, genname_str
, actual_par_list
,
7129 // class for keeping the altstep in the default context
7130 // the class is for internal use, we do not need to publish it in the
7132 char* str
= mprintf("class %s_Default : public Default_Base {\n", genname_str
);
7133 str
= fp_list
->generate_code_object(str
, "par_");
7134 str
= mputprintf(str
, "public:\n"
7136 "alt_status call_altstep();\n"
7137 "};\n\n", genname_str
, full_formal_par_list
);
7138 target
->source
.class_defs
= mputstr(target
->source
.class_defs
, str
);
7140 // member functions of the class
7141 str
= mprintf("%s_Default::%s_Default(%s)\n"
7142 " : Default_Base(\"%s\")", genname_str
, genname_str
, full_formal_par_list
,
7144 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); i
++) {
7145 const char *fp_name_str
=
7146 fp_list
->get_fp_byIndex(i
)->get_id().get_name().c_str();
7147 str
= mputprintf(str
, ", par_%s(%s)", fp_name_str
, fp_name_str
);
7149 str
= mputstr(str
, "\n{\n}\n\n");
7150 char *actual_par_list_prefixed
=
7151 fp_list
->generate_code_actual_parlist(memptystr(), "par_");
7152 str
= mputprintf(str
, "alt_status %s_Default::call_altstep()\n"
7154 "return %s_instance(%s);\n"
7155 "}\n\n", genname_str
, genname_str
, actual_par_list_prefixed
);
7156 Free(actual_par_list_prefixed
);
7157 target
->source
.methods
= mputstr(target
->source
.methods
, str
);
7160 // function for default activation: prototype
7161 target
->header
.function_prototypes
=
7162 mputprintf(target
->header
.function_prototypes
,
7163 "extern Default_Base *activate_%s(%s);\n", genname_str
,
7164 full_formal_par_list
);
7166 // function for default activation: body
7167 str
= mprintf("Default_Base *activate_%s(%s)\n"
7168 "{\n", genname_str
, full_formal_par_list
);
7169 str
= mputprintf(str
, "return new %s_Default(%s);\n"
7170 "}\n\n", genname_str
, actual_par_list
);
7171 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7175 Free(full_formal_par_list
);
7176 Free(actual_par_list
);
7178 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7179 "%s.add_altstep(\"%s\", (genericfunc_t)&%s_instance, (genericfunc_t )&activate_%s, "
7180 "(genericfunc_t )&%s);\n", get_module_object_name(), dispname_str
, genname_str
,
7181 genname_str
, genname_str
);
7184 void Def_Altstep::generate_code(CodeGenHelper
& cgh
) {
7185 generate_code(cgh
.get_current_outputstruct());
7188 void Def_Altstep::dump_internal(unsigned level
) const
7190 DEBUG(level
, "Altstep: %s", id
->get_dispname().c_str());
7191 DEBUG(level
+ 1, "Parameters:");
7192 fp_list
->dump(level
+ 1);
7194 DEBUG(level
+ 1, "Runs on clause:");
7195 runs_on_ref
->dump(level
+ 2);
7198 DEBUG(level + 1, "Local definitions:");
7199 sb->dump(level + 2);
7201 DEBUG(level
+ 1, "Guards:");
7202 ags
->dump(level
+ 2);
7205 void Def_Altstep::set_parent_path(WithAttribPath
* p_path
) {
7206 Definition::set_parent_path(p_path
);
7207 sb
->set_parent_path(w_attrib_path
);
7210 // =================================
7211 // ===== Def_Testcase
7212 // =================================
7214 Def_Testcase::Def_Testcase(Identifier
*p_id
, FormalParList
*p_fpl
,
7215 Reference
*p_runs_on_ref
, Reference
*p_system_ref
,
7216 StatementBlock
*p_block
)
7217 : Definition(A_TESTCASE
, p_id
), fp_list(p_fpl
), runs_on_ref(p_runs_on_ref
),
7218 runs_on_type(0), system_ref(p_system_ref
), system_type(0), block(p_block
)
7220 if (!p_fpl
|| !p_runs_on_ref
|| !p_block
)
7221 FATAL_ERROR("Def_Testcase::Def_Testcase()");
7222 fp_list
->set_my_def(this);
7223 block
->set_my_def(this);
7226 Def_Testcase::~Def_Testcase()
7234 Def_Testcase
*Def_Testcase::clone() const
7236 FATAL_ERROR("Def_Testcase::clone");
7239 void Def_Testcase::set_fullname(const string
& p_fullname
)
7241 Definition::set_fullname(p_fullname
);
7242 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
7243 runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
7244 if (system_ref
) system_ref
->set_fullname(p_fullname
+ ".<system_type>");
7245 block
->set_fullname(p_fullname
+ ".<statement_block>");
7248 void Def_Testcase::set_my_scope(Scope
*p_scope
)
7250 bridgeScope
.set_parent_scope(p_scope
);
7251 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
7253 Definition::set_my_scope(&bridgeScope
);
7254 // the scope of the parameter list is set during checking
7255 runs_on_ref
->set_my_scope(&bridgeScope
);
7256 if (system_ref
) system_ref
->set_my_scope(&bridgeScope
);
7257 block
->set_my_scope(fp_list
);
7260 Type
*Def_Testcase::get_RunsOnType()
7262 if (!checked
) chk();
7263 return runs_on_type
;
7266 Type
*Def_Testcase::get_SystemType()
7268 if (!checked
) chk();
7272 FormalParList
*Def_Testcase::get_FormalParList()
7274 if (!checked
) chk();
7278 RunsOnScope
*Def_Testcase::get_runs_on_scope(Type
*comptype
)
7280 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
7281 if (!my_module
) FATAL_ERROR("Def_Testcase::get_runs_on_scope()");
7282 return my_module
->get_runs_on_scope(comptype
);
7285 void Def_Testcase::chk()
7287 if (checked
) return;
7289 Error_Context
cntxt(this, "In testcase definition `%s'",
7290 id
->get_dispname().c_str());
7291 Scope
*parlist_scope
= my_scope
;
7293 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
7294 runs_on_type
= runs_on_ref
->chk_comptype_ref();
7296 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
7297 runs_on_scope
->set_parent_scope(my_scope
);
7298 parlist_scope
= runs_on_scope
;
7302 Error_Context
cntxt2(system_ref
, "In `system' clause");
7303 system_type
= system_ref
->chk_comptype_ref();;
7305 fp_list
->set_my_scope(parlist_scope
);
7306 fp_list
->chk(asstype
);
7308 if (!semantic_check_only
) {
7309 fp_list
->set_genname(get_genname());
7310 block
->set_code_section(GovernedSimple::CS_INLINE
);
7312 if (w_attrib_path
) {
7313 w_attrib_path
->chk_global_attrib();
7314 w_attrib_path
->chk_no_qualif();
7318 void Def_Testcase::generate_code(output_struct
*target
, bool)
7320 const string
& t_genname
= get_genname();
7321 const char *genname_str
= t_genname
.c_str();
7322 const char *dispname_str
= id
->get_dispname().c_str();
7324 // assemble the function body first (this also determines which parameters
7327 // Checking whether the testcase was invoked from another one.
7328 // At this point the location information should refer to the execute()
7329 // statement rather than this testcase.
7330 char* body
= mputstr(memptystr(), "TTCN_Runtime::check_begin_testcase(has_timer, "
7332 body
= create_location_object(body
, "TESTCASE", dispname_str
);
7333 body
= fp_list
->generate_shadow_objects(body
);
7334 body
= mputprintf(body
, "try {\n"
7335 "TTCN_Runtime::begin_testcase(\"%s\", \"%s\", ",
7336 my_scope
->get_scope_mod()->get_modid().get_dispname().c_str(),
7338 ComponentTypeBody
*runs_on_body
= runs_on_type
->get_CompBody();
7339 body
= runs_on_body
->generate_code_comptype_name(body
);
7340 body
= mputstr(body
, ", ");
7342 body
= system_type
->get_CompBody()->generate_code_comptype_name(body
);
7343 else body
= runs_on_body
->generate_code_comptype_name(body
);
7344 body
= mputstr(body
, ", has_timer, timer_value);\n");
7345 body
= block
->generate_code(body
);
7346 body
= mputprintf(body
,
7347 "} catch (const TC_Error& tc_error) {\n"
7348 "} catch (const TC_End& tc_end) {\n"
7349 "TTCN_Logger::log_str(TTCN_FUNCTION, \"Test case %s was stopped.\");\n"
7350 "}\n", dispname_str
);
7351 body
= mputstr(body
, "return TTCN_Runtime::end_testcase();\n");
7353 // smart formal parameter list (names of unused parameters are omitted)
7354 char *formal_par_list
= fp_list
->generate_code(memptystr());
7355 fp_list
->generate_code_defval(target
);
7356 if (fp_list
->get_nof_fps() > 0)
7357 formal_par_list
= mputstr(formal_par_list
, ", ");
7358 formal_par_list
= mputstr(formal_par_list
,
7359 "boolean has_timer, double timer_value");
7361 // function prototype
7362 target
->header
.function_prototypes
=
7363 mputprintf(target
->header
.function_prototypes
,
7364 "extern verdicttype testcase_%s(%s);\n", genname_str
, formal_par_list
);
7367 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
7368 "verdicttype testcase_%s(%s)\n"
7371 "}\n\n", genname_str
, formal_par_list
, body
);
7372 Free(formal_par_list
);
7375 if (fp_list
->get_nof_fps() == 0) {
7376 // adding to the list of startable testcases
7377 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7378 "%s.add_testcase_nonpard(\"%s\", testcase_%s);\n",
7379 get_module_object_name(), dispname_str
, genname_str
);
7381 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7382 "%s.add_testcase_pard(\"%s\", (genericfunc_t)&testcase_%s);\n",
7383 get_module_object_name(), dispname_str
, genname_str
);
7385 // If every formal parameter has a default value, the testcase
7386 // might be callable after all.
7387 bool callable
= true;
7388 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
7389 FormalPar
*fp
= fp_list
->get_fp_byIndex(i
);
7390 if (!fp
->has_defval()) {
7397 // Write a wrapper, which acts as a no-param testcase
7398 // by calling the parameterized testcase with the default values.
7399 target
->header
.function_prototypes
=
7400 mputprintf(target
->header
.function_prototypes
,
7401 "extern verdicttype testcase_%s_defparams(boolean has_timer, double timer_value);\n",
7403 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
7404 "verdicttype testcase_%s_defparams(boolean has_timer, double timer_value) {\n"
7405 " return testcase_%s(",
7406 genname_str
, genname_str
);
7408 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
7409 FormalPar
*fp
= fp_list
->get_fp_byIndex(i
);
7410 ActualPar
*ap
= fp
->get_defval();
7411 switch (ap
->get_selection()) {
7412 case ActualPar::AP_VALUE
:
7413 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7414 ap
->get_Value()->get_genname_own(my_scope
).c_str());
7416 case ActualPar::AP_TEMPLATE
:
7417 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7418 ap
->get_TemplateInstance()->get_Template()->get_genname_own(my_scope
).c_str());
7420 case ActualPar::AP_REF
:
7421 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7422 ap
->get_Ref()->get_refd_assignment()->get_genname_from_scope(my_scope
).c_str());
7424 case ActualPar::AP_DEFAULT
:
7425 // Can't happen. This ActualPar was created by
7426 // Ttcn::FormalPar::chk_actual_par as the default value for
7427 // a FormalPar, and it only ever creates vale, template or ref.
7430 FATAL_ERROR("Def_Testcase::generate_code()");
7433 // always append a comma, because has_timer and timer_value follows
7434 target
->source
.function_bodies
= mputstrn(target
->source
.function_bodies
,
7438 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7439 "has_timer, timer_value);\n"
7441 // Add the non-parameterized wrapper *after* the parameterized one,
7442 // with the same name. Linear search will always find the first
7443 // (user-visible, parameterized) testcase.
7444 // TTCN_Module::execute_testcase knows that if after a parameterized
7445 // testcase another testcase with the same name follows,
7446 // it's the callable, non-parameterized wrapper.
7448 // TTCN_Module::list_testcases skips parameterized testcases;
7449 // it will now list the non-parameterized wrapper.
7450 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7451 "%s.add_testcase_nonpard(\"%s\", testcase_%s_defparams);\n",
7452 get_module_object_name(), dispname_str
, genname_str
);
7454 } // has formal parameters
7457 void Def_Testcase::generate_code(CodeGenHelper
& cgh
) {
7458 generate_code(cgh
.get_current_outputstruct());
7461 void Def_Testcase::dump_internal(unsigned level
) const
7463 DEBUG(level
, "Testcase: %s", id
->get_dispname().c_str());
7464 DEBUG(level
+ 1, "Parameters:");
7465 fp_list
->dump(level
+ 1);
7466 DEBUG(level
+ 1, "Runs on clause:");
7467 runs_on_ref
->dump(level
+ 2);
7469 DEBUG(level
+ 1, "System clause:");
7470 system_ref
->dump(level
+ 2);
7472 DEBUG(level
+ 1, "Statement block:");
7473 block
->dump(level
+ 2);
7476 void Def_Testcase::set_parent_path(WithAttribPath
* p_path
) {
7477 Definition::set_parent_path(p_path
);
7479 block
->set_parent_path(w_attrib_path
);
7482 // =================================
7484 // =================================
7486 FormalPar::FormalPar(asstype_t p_asstype
, Type
*p_type
, Identifier
* p_name
,
7487 TemplateInstance
*p_defval
, bool p_lazy_eval
)
7488 : Definition(p_asstype
, p_name
), type(p_type
), my_parlist(0),
7489 used_as_lvalue(false), template_restriction(TR_NONE
),
7490 lazy_eval(p_lazy_eval
), defval_generated(false), usage_found(false)
7492 switch (p_asstype
) {
7496 case A_PAR_VAL_INOUT
:
7497 case A_PAR_TEMPL_IN
:
7498 case A_PAR_TEMPL_OUT
:
7499 case A_PAR_TEMPL_INOUT
:
7503 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): invalid parameter type");
7506 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): NULL pointer");
7507 type
->set_ownertype(Type::OT_FORMAL_PAR
, this);
7508 defval
.ti
= p_defval
;
7511 FormalPar::FormalPar(asstype_t p_asstype
,
7512 template_restriction_t p_template_restriction
, Type
*p_type
,
7513 Identifier
* p_name
, TemplateInstance
*p_defval
, bool p_lazy_eval
)
7514 : Definition(p_asstype
, p_name
), type(p_type
), my_parlist(0),
7515 used_as_lvalue(false), template_restriction(p_template_restriction
),
7516 lazy_eval(p_lazy_eval
), defval_generated(false), usage_found(false)
7518 switch (p_asstype
) {
7519 case A_PAR_TEMPL_IN
:
7520 case A_PAR_TEMPL_OUT
:
7521 case A_PAR_TEMPL_INOUT
:
7524 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): parameter not template");
7527 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): NULL pointer");
7528 type
->set_ownertype(Type::OT_FORMAL_PAR
, this);
7529 defval
.ti
= p_defval
;
7532 FormalPar::FormalPar(asstype_t p_asstype
, Identifier
* p_name
,
7533 TemplateInstance
*p_defval
)
7534 : Definition(p_asstype
, p_name
), type(0), my_parlist(0),
7535 used_as_lvalue(false), template_restriction(TR_NONE
), lazy_eval(false),
7536 defval_generated(false), usage_found(false)
7538 if (p_asstype
!= A_PAR_TIMER
)
7539 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): invalid parameter type");
7540 defval
.ti
= p_defval
;
7543 FormalPar::~FormalPar()
7546 if (checked
) delete defval
.ap
;
7547 else delete defval
.ti
;
7550 FormalPar
* FormalPar::clone() const
7552 FATAL_ERROR("FormalPar::clone");
7555 void FormalPar::set_fullname(const string
& p_fullname
)
7557 Definition::set_fullname(p_fullname
);
7558 if (type
) type
->set_fullname(p_fullname
+ ".<type>");
7560 if (defval
.ap
) defval
.ap
->set_fullname(p_fullname
+ ".<default_value>");
7562 if (defval
.ti
) defval
.ti
->set_fullname(p_fullname
+ ".<default_value>");
7566 void FormalPar::set_my_scope(Scope
*p_scope
)
7568 Definition::set_my_scope(p_scope
);
7569 if (type
) type
->set_my_scope(p_scope
);
7571 if (defval
.ap
) defval
.ap
->set_my_scope(p_scope
);
7573 if (defval
.ti
) defval
.ti
->set_my_scope(p_scope
);
7577 bool FormalPar::is_local() const
7582 Type
*FormalPar::get_Type()
7584 if (!checked
) chk();
7585 if (!type
) FATAL_ERROR("FormalPar::get_Type()");
7589 void FormalPar::chk()
7591 if (checked
) return;
7593 TemplateInstance
*default_value
= defval
.ti
;
7597 Type
*t
= type
->get_type_refd_last();
7598 // checks for forbidden type <-> parameter combinations
7599 switch (t
->get_typetype()) {
7603 case A_PAR_VAL_INOUT
:
7604 asstype
= A_PAR_PORT
;
7607 error("Port type `%s' cannot be used as %s",
7608 t
->get_fullname().c_str(), get_assname());
7611 case Type::T_SIGNATURE
:
7613 case A_PAR_TEMPL_IN
:
7614 case A_PAR_TEMPL_OUT
:
7615 case A_PAR_TEMPL_INOUT
:
7618 error("Signature `%s' cannot be used as %s",
7619 t
->get_fullname().c_str(), get_assname());
7626 FATAL_ERROR("FormalPar::chk()");
7628 asstype
= A_PAR_VAL_IN
;
7633 } else if (asstype
!= A_PAR_TIMER
) FATAL_ERROR("FormalPar::chk()");
7635 if (default_value
) {
7636 Error_Context
cntxt(default_value
, "In default value");
7637 defval
.ap
= chk_actual_par(default_value
, Type::EXPECTED_STATIC_VALUE
);
7638 delete default_value
;
7639 if (!semantic_check_only
)
7640 defval
.ap
->set_code_section(GovernedSimple::CS_POST_INIT
);
7644 bool FormalPar::has_defval() const
7646 if (checked
) return defval
.ap
!= 0;
7647 else return defval
.ti
!= 0;
7650 bool FormalPar::has_notused_defval() const
7652 if (checked
) FATAL_ERROR("FormalPar::has_notused_defval");
7653 if (!defval
.ti
|| !defval
.ti
->get_Template())
7655 return defval
.ti
->get_Template()->get_templatetype()
7656 == Template::TEMPLATE_NOTUSED
;
7659 ActualPar
*FormalPar::get_defval() const
7661 if (!checked
) FATAL_ERROR("FormalPar::get_defval()");
7665 // Extract the TemplateInstance from an ActualPar.
7666 void FormalPar::set_defval(ActualPar
*defpar
)
7668 // ActualPar::clone() is not implemented, since we need such a function
7669 // only here only for AP_{VALUE,TEMPLATE} parameters. AP_ERROR can also
7670 // happen for Def_Template nodes, but they will be errors later.
7671 // FIXME: This function is Def_Template specific.
7672 if (!defval
.ti
->get_Template() || defval
.ti
->get_Template()
7673 ->get_templatetype() != Template::TEMPLATE_NOTUSED
)
7674 FATAL_ERROR("FormalPar::set_defval()");
7675 TemplateInstance
*reversed_ti
= 0;
7676 switch (defpar
->get_selection()) {
7677 case ActualPar::AP_VALUE
:
7678 reversed_ti
= new TemplateInstance(type
->clone(), 0, new Template
7679 (defpar
->get_Value()->clone())); // Trust the clone().
7681 case ActualPar::AP_TEMPLATE
:
7682 reversed_ti
= defpar
->get_TemplateInstance()->clone();
7684 case ActualPar::AP_ERROR
:
7685 break; // Can happen, but let it go.
7686 case ActualPar::AP_REF
:
7687 case ActualPar::AP_DEFAULT
:
7689 FATAL_ERROR("FormalPar::set_defval()");
7693 reversed_ti
->set_my_scope(get_my_scope());
7694 defval
.ti
= reversed_ti
;
7698 ActualPar
*FormalPar::chk_actual_par(TemplateInstance
*actual_par
,
7699 Type::expected_value_t exp_val
)
7701 if (!checked
) chk();
7705 return chk_actual_par_value(actual_par
, exp_val
);
7707 case A_PAR_VAL_INOUT
:
7708 return chk_actual_par_by_ref(actual_par
, false, exp_val
);
7709 case A_PAR_TEMPL_IN
:
7710 return chk_actual_par_template(actual_par
, exp_val
);
7711 case A_PAR_TEMPL_OUT
:
7712 case A_PAR_TEMPL_INOUT
:
7713 return chk_actual_par_by_ref(actual_par
, true, exp_val
);
7715 return chk_actual_par_timer(actual_par
, exp_val
);
7717 return chk_actual_par_port(actual_par
, exp_val
);
7719 FATAL_ERROR("FormalPar::chk_actual_par()");
7721 return 0; // to avoid warnings
7724 ActualPar
*FormalPar::chk_actual_par_value(TemplateInstance
*actual_par
,
7725 Type::expected_value_t exp_val
)
7727 actual_par
->chk_Type(type
);
7728 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7730 derived_ref
->error("An in-line modified template cannot be used as %s",
7732 actual_par
->chk_DerivedRef(type
);
7734 Template
*ap_template
= actual_par
->get_Template();
7735 if (ap_template
->is_Value()) {
7736 Value
*v
= ap_template
->get_Value();
7737 v
->set_my_governor(type
);
7738 type
->chk_this_value_ref(v
);
7739 type
->chk_this_value(v
, 0, exp_val
, INCOMPLETE_NOT_ALLOWED
,
7740 OMIT_NOT_ALLOWED
, SUB_CHK
);
7741 return new ActualPar(v
);
7743 actual_par
->error("A specific value without matching symbols "
7744 "was expected for a %s", get_assname());
7745 return new ActualPar();
7749 static void chk_defpar_value(const Value
* v
)
7751 Common::Reference
*vref
= v
->get_reference();
7752 Common::Assignment
*ass2
= vref
->get_refd_assignment();
7754 Scope
*scope
= ass2
->get_my_scope();
7755 ComponentTypeBody
*ctb
= dynamic_cast<ComponentTypeBody
*>(scope
);
7756 if (ctb
) { // this is a component variable
7757 v
->error("default value cannot refer to"
7758 " a template field of the component in the `runs on' clause");
7762 static void chk_defpar_template(const Template
*body
,
7763 Type::expected_value_t exp_val
)
7765 switch (body
->get_templatetype()) {
7766 case Template::TEMPLATE_ERROR
:
7767 break; // could be erroneous in the source; skip it
7768 case Template::TEMPLATE_NOTUSED
:
7769 case Template::OMIT_VALUE
:
7770 case Template::ANY_VALUE
:
7771 case Template::ANY_OR_OMIT
:
7772 break; // acceptable (?)
7773 case Template::TEMPLATE_INVOKE
: // calling a function is not acceptable
7774 body
->error("default value can not be a function invocation");
7776 case Template::VALUE_RANGE
: {
7777 ValueRange
*range
= body
->get_value_range();
7778 Value
*low
= range
->get_min_v();
7779 Type::typetype_t tt_low
= low
->get_expr_returntype(exp_val
);
7780 Value
*high
= range
->get_max_v();
7781 Type::typetype_t tt_high
= high
->get_expr_returntype(exp_val
);
7782 if (tt_low
== tt_high
) break;
7785 case Template::BSTR_PATTERN
:
7786 case Template::HSTR_PATTERN
:
7787 case Template::OSTR_PATTERN
:
7788 case Template::CSTR_PATTERN
:
7789 case Template::USTR_PATTERN
:
7790 break; // should be acceptable in all cases (if only fixed strings possible)
7792 case Template::SPECIFIC_VALUE
: {
7793 Common::Value
*v
= body
->get_specific_value();
7794 if (v
->get_valuetype() == Value::V_REFD
) chk_defpar_value(v
);
7797 case Template::ALL_FROM
:
7798 case Template::VALUE_LIST_ALL_FROM
:
7799 FATAL_ERROR("should have been flattened");
7801 case Template::SUPERSET_MATCH
:
7802 case Template::SUBSET_MATCH
:
7803 case Template::PERMUTATION_MATCH
:
7804 case Template::TEMPLATE_LIST
:
7805 case Template::COMPLEMENTED_LIST
:
7806 case Template::VALUE_LIST
: {
7807 // in template charstring par := charstring : ("foo", "bar", "baz")
7808 size_t num
= body
->get_nof_comps();
7809 for (size_t i
= 0; i
< num
; ++i
) {
7810 const Template
*tpl
= body
->get_temp_byIndex(i
);
7811 chk_defpar_template(tpl
, exp_val
);
7815 case Template::NAMED_TEMPLATE_LIST
: {
7816 size_t num
= body
->get_nof_comps();
7817 for (size_t i
= 0; i
< num
; ++i
) {
7818 const NamedTemplate
*nt
= body
->get_namedtemp_byIndex(i
);
7819 const Template
*tpl
= nt
->get_template();
7820 chk_defpar_template(tpl
, exp_val
);
7824 case Template::INDEXED_TEMPLATE_LIST
: {
7825 size_t num
= body
->get_nof_comps();
7826 for (size_t i
= 0; i
< num
; ++i
) {
7827 const IndexedTemplate
*it
= body
->get_indexedtemp_byIndex(i
);
7828 const Template
*tpl
= it
->get_template();
7829 chk_defpar_template(tpl
, exp_val
);
7833 case Template::TEMPLATE_REFD
: {
7834 Ref_base
*ref
= body
->get_reference();
7836 Ttcn::ActualParList
*aplist
= ref
->get_parlist();
7838 size_t num
= aplist
->get_nof_pars();
7839 for (size_t i
= 0; i
< num
; ++i
) {
7840 const Ttcn::ActualPar
*ap
= aplist
->get_par(i
);
7842 switch (ap
->get_selection()) {
7843 case ActualPar::AP_ERROR
: {
7845 case ActualPar::AP_VALUE
: {
7846 Value
*v
= ap
->get_Value(); // "v_variable" as the parameter of the template
7848 switch (v
->get_valuetype()) {
7849 case Value::V_REFD
: {
7850 chk_defpar_value(v
);
7856 case ActualPar::AP_TEMPLATE
: {
7857 // A component cannot contain a template definition, parameterized or not.
7858 // Therefore the template this actual par references, cannot be
7859 // a field of a component => no error possible, nothing to do.
7861 case ActualPar::AP_REF
: {
7862 // A template cannot have an out/inout parameter
7863 FATAL_ERROR("Template with out parameter?");
7865 case ActualPar::AP_DEFAULT
: {
7866 ap
= ap
->get_ActualPar();
7870 } // switch actual par selection
7874 } // switch templatetype
7878 // This function is called in two situations:
7879 // 1. FormalParList::chk calls FormalPar::chk to compute the default value
7880 // (make an ActualPar from a TemplateInstance).
7881 // In this case, defval.ti==0, and actual_par contains its old value.
7882 // This case is called only if the formal par has a default value.
7883 // 2. FormalParList::chk_actual_parlist calls FormalPar::chk_actual_par
7884 // to check the parameters supplied by the execute statement to the tc.
7885 // In this case, defval.ap has the value computed in case 1.
7886 ActualPar
*FormalPar::chk_actual_par_template(TemplateInstance
*actual_par
,
7887 Type::expected_value_t exp_val
)
7889 actual_par
->chk(type
);
7890 // actual_par->template_body may change: SPECIFIC_VALUE to TEMPLATE_REFD
7891 Definition
*fplist_def
= my_parlist
->get_my_def();
7892 // The parameter list belongs to this definition. If it's a function
7893 // or testcase, it may have a "runs on" clause.
7894 Def_Function
*parent_fn
= dynamic_cast<Def_Function
*>(fplist_def
);
7895 Type
*runs_on_type
= 0;
7896 if (parent_fn
) runs_on_type
= parent_fn
->get_RunsOnType();
7897 else { // not a function; maybe a testcase
7898 Def_Testcase
*parent_tc
= dynamic_cast<Def_Testcase
*>(fplist_def
);
7899 if (parent_tc
) runs_on_type
= parent_tc
->get_RunsOnType();
7902 // If it _has_ a runs on clause, the type must be a component.
7903 if (runs_on_type
->get_typetype() != Type::T_COMPONENT
) FATAL_ERROR("not component?");
7904 // The default value "shall not refer to elements of the component type
7905 // in the runs on clause"
7906 ComponentTypeBody
*runs_on_component
= runs_on_type
->get_CompBody();
7907 size_t compass
= runs_on_component
->get_nof_asss();
7908 for (size_t c
= 0; c
< compass
; c
++) {
7909 Assignment
*ass
= runs_on_component
->get_ass_byIndex(c
);
7914 Ttcn::Template
* body
= actual_par
->get_Template();
7915 if (exp_val
== Type::EXPECTED_STATIC_VALUE
7916 ||exp_val
== Type::EXPECTED_CONSTANT
) {
7917 chk_defpar_template(body
, exp_val
);
7919 // Rip out the type, derived ref and template from actual_par
7920 // (which may come from a function invocation or the definition
7921 // of the default value) and give it to the new ActualPar.
7922 ActualPar
*ret_val
= new ActualPar(
7923 new TemplateInstance(actual_par
->get_Type(),
7924 actual_par
->get_DerivedRef(), actual_par
->get_Template()));
7925 // Zero out these members because the caller will soon call delete
7926 // on actual_par, but they now belong to ret_val.
7927 // FIXME: should this really be in here, or outside in the caller before the delete ?
7928 actual_par
->release();
7930 if (template_restriction
!=TR_NONE
) {
7931 bool needs_runtime_check
=
7932 ret_val
->get_TemplateInstance()->chk_restriction(
7933 "template formal parameter", template_restriction
,
7934 ret_val
->get_TemplateInstance());
7935 if (needs_runtime_check
)
7936 ret_val
->set_gen_restriction_check(template_restriction
);
7941 ActualPar
*FormalPar::chk_actual_par_by_ref(TemplateInstance
*actual_par
,
7942 bool is_template
, Type::expected_value_t exp_val
)
7944 Type
*ap_type
= actual_par
->get_Type();
7946 ap_type
->warning("Explicit type specification is useless for an %s",
7948 actual_par
->chk_Type(type
);
7950 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7952 derived_ref
->error("An in-line modified template cannot be used as %s",
7954 actual_par
->chk_DerivedRef(type
);
7956 // needed for the error messages
7957 const char *expected_string
= is_template
?
7958 "template variable or template parameter" :
7959 "variable or value parameter";
7960 Template
*ap_template
= actual_par
->get_Template();
7961 if (ap_template
->is_Ref()) {
7962 Ref_base
*ref
= ap_template
->get_Ref();
7963 Common::Assignment
*ass
= ref
->get_refd_assignment();
7966 return new ActualPar();
7968 bool asstype_correct
= false;
7969 switch (ass
->get_asstype()) {
7971 ass
->use_as_lvalue(*ref
);
7972 if (get_asstype() == A_PAR_VAL_OUT
|| get_asstype() == A_PAR_TEMPL_OUT
) {
7973 ass
->warning("Passing an `in' parameter as another function's `out' parameter");
7978 case A_PAR_VAL_INOUT
:
7979 if (!is_template
) asstype_correct
= true;
7981 case A_PAR_TEMPL_IN
:
7982 ass
->use_as_lvalue(*ref
);
7983 if (get_asstype() == A_PAR_VAL_OUT
|| get_asstype() == A_PAR_TEMPL_OUT
) {
7984 ass
->warning("Passing an `in' parameter as another function's `out' parameter");
7987 case A_VAR_TEMPLATE
:
7988 case A_PAR_TEMPL_OUT
:
7989 case A_PAR_TEMPL_INOUT
:
7990 if (is_template
) asstype_correct
= true;
7995 if (asstype_correct
) {
7996 FieldOrArrayRefs
*t_subrefs
= ref
->get_subrefs();
7997 Type
*ref_type
= ass
->get_Type()->get_field_type(t_subrefs
, exp_val
);
7999 if (!type
->is_identical(ref_type
)) {
8000 ref
->error("Type mismatch: Reference to a %s of type "
8001 "`%s' was expected instead of `%s'", expected_string
,
8002 type
->get_typename().c_str(), ref_type
->get_typename().c_str());
8003 } else if (type
->get_sub_type() && ref_type
->get_sub_type() &&
8004 (type
->get_sub_type()->get_subtypetype()==ref_type
->get_sub_type()->get_subtypetype()) &&
8005 (!type
->get_sub_type()->is_compatible(ref_type
->get_sub_type()))) {
8006 ref
->error("Subtype mismatch: subtype %s has no common value with subtype %s",
8007 type
->get_sub_type()->to_string().c_str(),
8008 ref_type
->get_sub_type()->to_string().c_str());
8010 if (t_subrefs
&& t_subrefs
->refers_to_string_element()) {
8011 ref
->error("Reference to a string element of type `%s' cannot be "
8012 "used in this context", ref_type
->get_typename().c_str());
8016 ref
->error("Reference to a %s was expected for an %s instead of %s",
8017 expected_string
, get_assname(), ass
->get_description().c_str());
8019 ActualPar
* ret_val_ap
= new ActualPar(ref
);
8020 // restriction checking if this is a reference to a template variable
8021 // this is an 'out' or 'inout' template parameter
8022 if (is_template
&& asstype_correct
) {
8023 template_restriction_t refd_tr
;
8024 switch (ass
->get_asstype()) {
8025 case A_VAR_TEMPLATE
: {
8026 Def_Var_Template
* dvt
= dynamic_cast<Def_Var_Template
*>(ass
);
8027 if (!dvt
) FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
8028 refd_tr
= dvt
->get_template_restriction();
8030 case A_PAR_TEMPL_IN
:
8031 case A_PAR_TEMPL_OUT
:
8032 case A_PAR_TEMPL_INOUT
: {
8033 FormalPar
* fp
= dynamic_cast<FormalPar
*>(ass
);
8034 if (!fp
) FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
8035 refd_tr
= fp
->get_template_restriction();
8038 FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
8041 refd_tr
= Template::get_sub_restriction(refd_tr
, ref
);
8042 if (template_restriction
!=refd_tr
) {
8043 bool pre_call_check
=
8044 Template::is_less_restrictive(template_restriction
, refd_tr
);
8045 bool post_call_check
=
8046 Template::is_less_restrictive(refd_tr
, template_restriction
);
8047 if (pre_call_check
|| post_call_check
) {
8048 ref
->warning("Inadequate restriction on the referenced %s `%s', "
8049 "this may cause a dynamic test case error at runtime",
8050 ass
->get_assname(), ref
->get_dispname().c_str());
8051 ass
->note("Referenced %s is here", ass
->get_assname());
8054 ret_val_ap
->set_gen_restriction_check(template_restriction
);
8055 if (post_call_check
)
8056 ret_val_ap
->set_gen_post_restriction_check(refd_tr
);
8058 // for out and inout template parameters of external functions
8059 // always check because we do not trust user written C++ code
8060 if (refd_tr
!=TR_NONE
) {
8061 switch (my_parlist
->get_my_def()->get_asstype()) {
8062 case A_EXT_FUNCTION
:
8063 case A_EXT_FUNCTION_RVAL
:
8064 case A_EXT_FUNCTION_RTEMP
:
8065 ret_val_ap
->set_gen_post_restriction_check(refd_tr
);
8074 actual_par
->error("Reference to a %s was expected for an %s",
8075 expected_string
, get_assname());
8076 return new ActualPar();
8080 ActualPar
*FormalPar::chk_actual_par_timer(TemplateInstance
*actual_par
,
8081 Type::expected_value_t exp_val
)
8083 Type
*ap_type
= actual_par
->get_Type();
8085 ap_type
->error("Explicit type specification cannot be used for a "
8087 actual_par
->chk_Type(0);
8089 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
8091 derived_ref
->error("An in-line modified template cannot be used as "
8093 actual_par
->chk_DerivedRef(0);
8095 Template
*ap_template
= actual_par
->get_Template();
8096 if (ap_template
->is_Ref()) {
8097 Ref_base
*ref
= ap_template
->get_Ref();
8098 Common::Assignment
*ass
= ref
->get_refd_assignment();
8101 return new ActualPar();
8103 switch (ass
->get_asstype()) {
8105 ArrayDimensions
*dims
= ass
->get_Dimensions();
8106 if (dims
) dims
->chk_indices(ref
, "timer", false, exp_val
);
8107 else if (ref
->get_subrefs()) ref
->error("Reference to single %s "
8108 "cannot have field or array sub-references",
8109 ass
->get_description().c_str());
8112 if (ref
->get_subrefs()) ref
->error("Reference to %s cannot have "
8113 "field or array sub-references", ass
->get_description().c_str());
8116 ref
->error("Reference to a timer or timer parameter was expected for "
8117 "a timer parameter instead of %s", ass
->get_description().c_str());
8119 return new ActualPar(ref
);
8121 actual_par
->error("Reference to a timer or timer parameter was "
8122 "expected for a timer parameter");
8123 return new ActualPar();
8127 ActualPar
*FormalPar::chk_actual_par_port(TemplateInstance
*actual_par
,
8128 Type::expected_value_t exp_val
)
8130 Type
*ap_type
= actual_par
->get_Type();
8132 ap_type
->warning("Explicit type specification is useless for a port "
8134 actual_par
->chk_Type(type
);
8136 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
8138 derived_ref
->error("An in-line modified template cannot be used as "
8140 actual_par
->chk_DerivedRef(type
);
8142 Template
*ap_template
= actual_par
->get_Template();
8143 if (ap_template
->is_Ref()) {
8144 Ref_base
*ref
= ap_template
->get_Ref();
8145 Common::Assignment
*ass
= ref
->get_refd_assignment();
8148 return new ActualPar();
8150 bool asstype_correct
= false;
8151 switch (ass
->get_asstype()) {
8153 ArrayDimensions
*dims
= ass
->get_Dimensions();
8154 if (dims
) dims
->chk_indices(ref
, "port", false, exp_val
);
8155 else if (ref
->get_subrefs()) ref
->error("Reference to single %s "
8156 "cannot have field or array sub-references",
8157 ass
->get_description().c_str());
8158 asstype_correct
= true;
8161 if (ref
->get_subrefs()) ref
->error("Reference to %s cannot have "
8162 "field or array sub-references", ass
->get_description().c_str());
8163 asstype_correct
= true;
8166 ref
->error("Reference to a port or port parameter was expected for a "
8167 "port parameter instead of %s", ass
->get_description().c_str());
8169 if (asstype_correct
) {
8170 Type
*ref_type
= ass
->get_Type();
8171 if (ref_type
&& !type
->is_identical(ref_type
))
8172 ref
->error("Type mismatch: Reference to a port or port parameter "
8173 "of type `%s' was expected instead of `%s'",
8174 type
->get_typename().c_str(), ref_type
->get_typename().c_str());
8176 return new ActualPar(ref
);
8178 actual_par
->error("Reference to a port or port parameter was expected "
8179 "for a port parameter");
8180 return new ActualPar();
8184 void FormalPar::use_as_lvalue(const Location
& p_loc
)
8188 case A_PAR_TEMPL_IN
:
8191 FATAL_ERROR("FormalPar::use_as_lvalue()");
8193 if (!used_as_lvalue
) {
8194 Definition
*my_def
= my_parlist
->get_my_def();
8195 if (!my_def
) FATAL_ERROR("FormalPar::use_as_lvalue()");
8196 if (my_def
->get_asstype() == A_TEMPLATE
)
8197 p_loc
.error("Parameter `%s' of the template cannot be passed further "
8198 "as `out' or `inout' parameter", id
->get_dispname().c_str());
8200 // update the genname so that all references in the generated code
8201 // will point to the shadow object
8203 set_genname(id
->get_name() + "_shadow");
8205 used_as_lvalue
= true;
8210 char* FormalPar::generate_code_defval(char* str
)
8212 if (!defval
.ap
|| defval_generated
) return str
;
8213 defval_generated
= true;
8214 switch (defval
.ap
->get_selection()) {
8215 case ActualPar::AP_VALUE
: {
8216 Value
*val
= defval
.ap
->get_Value();
8217 if (use_runtime_2
&& TypeConv::needs_conv_refd(val
)) {
8218 str
= TypeConv::gen_conv_code_refd(str
, val
->get_lhs_name().c_str(), val
);
8220 str
= val
->generate_code_init(str
, val
->get_lhs_name().c_str());
8223 case ActualPar::AP_TEMPLATE
: {
8224 TemplateInstance
*ti
= defval
.ap
->get_TemplateInstance();
8225 Template
*temp
= ti
->get_Template();
8226 Ref_base
*dref
= ti
->get_DerivedRef();
8228 expression_struct expr
;
8229 Code::init_expr(&expr
);
8230 expr
.expr
= mputprintf(expr
.expr
, "%s = ",
8231 temp
->get_lhs_name().c_str());
8232 dref
->generate_code(&expr
);
8233 str
= Code::merge_free_expr(str
, &expr
, false);
8235 if (use_runtime_2
&& TypeConv::needs_conv_refd(temp
)) {
8236 str
= TypeConv::gen_conv_code_refd(str
, temp
->get_lhs_name().c_str(), temp
);
8238 str
= temp
->generate_code_init(str
, temp
->get_lhs_name().c_str());
8240 if (defval
.ap
->get_gen_restriction_check() != TR_NONE
) {
8241 str
= Template::generate_restriction_check_code(str
,
8242 temp
->get_lhs_name().c_str(), defval
.ap
->get_gen_restriction_check());
8245 case ActualPar::AP_REF
:
8248 FATAL_ERROR("FormalPar::generate_code()");
8253 void FormalPar::generate_code_defval(output_struct
*target
, bool)
8255 if (!defval
.ap
) return;
8256 switch (defval
.ap
->get_selection()) {
8257 case ActualPar::AP_VALUE
: {
8258 Value
*val
= defval
.ap
->get_Value();
8260 Code::init_cdef(&cdef
);
8261 type
->generate_code_object(&cdef
, val
);
8262 Code::merge_cdef(target
, &cdef
);
8263 Code::free_cdef(&cdef
);
8265 case ActualPar::AP_TEMPLATE
: {
8266 TemplateInstance
*ti
= defval
.ap
->get_TemplateInstance();
8267 Template
*temp
= ti
->get_Template();
8269 Code::init_cdef(&cdef
);
8270 type
->generate_code_object(&cdef
, temp
);
8271 Code::merge_cdef(target
, &cdef
);
8272 Code::free_cdef(&cdef
);
8274 case ActualPar::AP_REF
:
8277 FATAL_ERROR("FormalPar::generate_code()");
8279 target
->functions
.post_init
= generate_code_defval(target
->functions
.post_init
);
8282 char *FormalPar::generate_code_fpar(char *str
, bool display_unused
/* = false */)
8284 // the name of the parameter should not be displayed if the parameter is not
8285 // used (to avoid a compiler warning)
8286 bool display_name
= (usage_found
|| display_unused
|| (!enable_set_bound_out_param
&&
8287 (asstype
== A_PAR_VAL_OUT
|| asstype
== A_PAR_TEMPL_OUT
)));
8288 const char *name_str
= display_name
? id
->get_name().c_str() : "";
8292 str
= mputprintf(str
, "Lazy_Param<%s>& %s", type
->get_genname_value(my_scope
).c_str(), name_str
);
8294 str
= mputprintf(str
, "const %s& %s", type
->get_genname_value(my_scope
).c_str(), name_str
);
8298 case A_PAR_VAL_INOUT
:
8300 str
= mputprintf(str
, "%s& %s", type
->get_genname_value(my_scope
).c_str(),
8303 case A_PAR_TEMPL_IN
:
8305 str
= mputprintf(str
, "Lazy_Param<%s>& %s", type
->get_genname_template(my_scope
).c_str(), name_str
);
8307 str
= mputprintf(str
, "const %s& %s", type
->get_genname_template(my_scope
).c_str(), name_str
);
8310 case A_PAR_TEMPL_OUT
:
8311 case A_PAR_TEMPL_INOUT
:
8312 str
= mputprintf(str
, "%s& %s",
8313 type
->get_genname_template(my_scope
).c_str(), name_str
);
8316 str
= mputprintf(str
, "TIMER& %s", name_str
);
8319 FATAL_ERROR("FormalPar::generate_code()");
8324 string
FormalPar::get_reference_name(Scope
* scope
) const
8330 case A_PAR_TEMPL_IN
:
8331 ret_val
+= type
->get_genname_template(scope
);
8334 ret_val
+= type
->get_genname_value(scope
);
8339 ret_val
+= get_id().get_name();
8346 char *FormalPar::generate_code_object(char *str
, const char *p_prefix
, char refch
)
8348 const char *name_str
= id
->get_name().c_str();
8352 str
= mputprintf(str
, "Lazy_Param<%s> %s%s;\n", type
->get_genname_value(my_scope
).c_str(), p_prefix
, name_str
);
8354 str
= mputprintf(str
, "%s %s%s;\n", type
->get_genname_value(my_scope
).c_str(), p_prefix
, name_str
);
8358 case A_PAR_VAL_INOUT
:
8360 str
= mputprintf(str
, "%s%c %s%s;\n",
8361 type
->get_genname_value(my_scope
).c_str(), refch
, p_prefix
, name_str
);
8363 case A_PAR_TEMPL_IN
:
8365 str
= mputprintf(str
, "Lazy_Param<%s> %s%s;\n", type
->get_genname_template(my_scope
).c_str(), p_prefix
, name_str
);
8367 str
= mputprintf(str
, "%s %s%s;\n", type
->get_genname_template(my_scope
).c_str(), p_prefix
, name_str
);
8370 case A_PAR_TEMPL_OUT
:
8371 case A_PAR_TEMPL_INOUT
:
8372 str
= mputprintf(str
, "%s%c %s%s;\n",
8373 type
->get_genname_template(my_scope
).c_str(), refch
, p_prefix
, name_str
);
8376 str
= mputprintf(str
, "TIMER& %s%s;\n", p_prefix
, name_str
);
8379 FATAL_ERROR("FormalPar::generate_code_object()");
8384 char *FormalPar::generate_shadow_object(char *str
) const
8386 if (used_as_lvalue
&& !lazy_eval
) {
8387 const string
& t_genname
= get_genname();
8388 const char *genname_str
= t_genname
.c_str();
8389 const char *name_str
= id
->get_name().c_str();
8392 str
= mputprintf(str
, "%s %s(%s);\n",
8393 type
->get_genname_value(my_scope
).c_str(), genname_str
, name_str
);
8395 case A_PAR_TEMPL_IN
:
8396 str
= mputprintf(str
, "%s %s(%s);\n",
8397 type
->get_genname_template(my_scope
).c_str(), genname_str
, name_str
);
8400 FATAL_ERROR("FormalPar::generate_shadow_object()");
8406 char *FormalPar::generate_code_set_unbound(char *str
) const
8409 case A_PAR_TEMPL_OUT
:
8411 str
= mputprintf(str
, "%s.clean_up();\n", id
->get_name().c_str());
8419 void FormalPar::dump_internal(unsigned level
) const
8421 DEBUG(level
, "%s: %s", get_assname(), id
->get_dispname().c_str());
8422 if (type
) type
->dump(level
+ 1);
8425 DEBUG(level
+ 1, "default value:");
8426 defval
.ap
->dump(level
+ 2);
8430 DEBUG(level
+ 1, "default value:");
8431 defval
.ti
->dump(level
+ 2);
8436 // =================================
8437 // ===== FormalParList
8438 // =================================
8440 FormalParList::~FormalParList()
8442 size_t nof_pars
= pars_v
.size();
8443 for (size_t i
= 0; i
< nof_pars
; i
++) delete pars_v
[i
];
8448 FormalParList
*FormalParList::clone() const
8450 FATAL_ERROR("FormalParList::clone");
8453 void FormalParList::set_fullname(const string
& p_fullname
)
8455 Node::set_fullname(p_fullname
);
8456 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8457 FormalPar
*par
= pars_v
[i
];
8458 par
->set_fullname(p_fullname
+ "." + par
->get_id().get_dispname());
8462 void FormalParList::set_my_scope(Scope
*p_scope
)
8464 set_parent_scope(p_scope
);
8465 Node::set_my_scope(p_scope
);
8466 // the scope of parameters is set to the parent scope instead of this
8467 // because they cannot refer to each other
8468 for (size_t i
= 0; i
< pars_v
.size(); i
++) pars_v
[i
]->set_my_scope(p_scope
);
8471 void FormalParList::add_fp(FormalPar
*p_fp
)
8473 if (!p_fp
) FATAL_ERROR("NULL parameter: Ttcn::FormalParList::add_fp()");
8475 p_fp
->set_my_parlist(this);
8479 bool FormalParList::has_notused_defval() const
8481 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8482 if (pars_v
[i
]->has_notused_defval())
8488 bool FormalParList::has_only_default_values() const
8490 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8491 if (!pars_v
[i
]->has_defval()) {
8499 bool FormalParList::has_fp_withName(const Identifier
& p_name
)
8501 if (!checked
) chk(Definition::A_UNDEF
);
8502 return pars_m
.has_key(p_name
.get_name());
8505 FormalPar
*FormalParList::get_fp_byName(const Identifier
& p_name
)
8507 if (!checked
) chk(Definition::A_UNDEF
);
8508 return pars_m
[p_name
.get_name()];
8511 bool FormalParList::get_startability()
8513 if(!checked
) FATAL_ERROR("FormalParList::get_startability()");
8514 return is_startable
;
8517 Common::Assignment
*FormalParList::get_ass_bySRef(Common::Ref_simple
*p_ref
)
8519 if (!p_ref
|| !checked
) FATAL_ERROR("FormalParList::get_ass_bySRef()");
8520 if (p_ref
->get_modid()) return parent_scope
->get_ass_bySRef(p_ref
);
8522 const string
& name
= p_ref
->get_id()->get_name();
8523 if (pars_m
.has_key(name
)) return pars_m
[name
];
8524 else return parent_scope
->get_ass_bySRef(p_ref
);
8528 bool FormalParList::has_ass_withId(const Identifier
& p_id
)
8530 if (!checked
) FATAL_ERROR("Ttcn::FormalParList::has_ass_withId()");
8531 return pars_m
.has_key(p_id
.get_name())
8532 || parent_scope
->has_ass_withId(p_id
);
8535 void FormalParList::set_genname(const string
& p_prefix
)
8537 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8538 FormalPar
*par
= pars_v
[i
];
8539 const string
& par_name
= par
->get_id().get_name();
8540 if (par
->get_asstype() != Definition::A_PAR_TIMER
)
8541 par
->get_Type()->set_genname(p_prefix
, par_name
);
8542 if (par
->has_defval()) {
8543 string
embedded_genname(p_prefix
);
8544 embedded_genname
+= '_';
8545 embedded_genname
+= par_name
;
8546 embedded_genname
+= "_defval";
8547 ActualPar
*defval
= par
->get_defval();
8548 switch (defval
->get_selection()) {
8549 case ActualPar::AP_ERROR
:
8550 case ActualPar::AP_REF
:
8552 case ActualPar::AP_VALUE
: {
8553 Value
*v
= defval
->get_Value();
8554 v
->set_genname_prefix("const_");
8555 v
->set_genname_recursive(embedded_genname
);
8557 case ActualPar::AP_TEMPLATE
: {
8558 Template
*t
= defval
->get_TemplateInstance()->get_Template();
8559 t
->set_genname_prefix("template_");
8560 t
->set_genname_recursive(embedded_genname
);
8563 FATAL_ERROR("FormalParList::set_genname()");
8569 void FormalParList::chk(Definition::asstype_t deftype
)
8571 if (checked
) return;
8574 is_startable
= true;
8575 Error_Context
cntxt(this, "In formal parameter list");
8576 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8577 FormalPar
*par
= pars_v
[i
];
8578 const Identifier
& id
= par
->get_id();
8579 const string
& name
= id
.get_name();
8580 const char *dispname
= id
.get_dispname().c_str();
8581 if (pars_m
.has_key(name
)) {
8582 par
->error("Duplicate parameter with name `%s'", dispname
);
8583 pars_m
[name
]->note("Previous definition of `%s' is here", dispname
);
8585 pars_m
.add(name
, par
);
8586 if (parent_scope
&& parent_scope
->has_ass_withId(id
)) {
8587 par
->error("Parameter name `%s' is not unique in the scope "
8588 "hierarchy", dispname
);
8589 Reference
ref(0, id
.clone());
8590 Common::Assignment
*ass
= parent_scope
->get_ass_bySRef(&ref
);
8591 if (!ass
) FATAL_ERROR("FormalParList::chk()");
8592 ass
->note("Symbol `%s' is already defined here in a higher scope "
8596 Error_Context
cntxt2(par
, "In parameter `%s'", dispname
);
8598 // check whether the parameter type is allowed
8600 case Definition::A_TEMPLATE
:
8601 switch (par
->get_asstype()) {
8602 case Definition::A_PAR_VAL_IN
:
8603 case Definition::A_PAR_TEMPL_IN
:
8604 // these are allowed
8607 par
->error("A template cannot have %s", par
->get_assname());
8610 case Definition::A_TESTCASE
:
8611 switch (par
->get_asstype()) {
8612 case Definition::A_PAR_TIMER
:
8613 case Definition::A_PAR_PORT
:
8614 // these are forbidden
8615 par
->error("A testcase cannot have %s", par
->get_assname());
8620 // everything is allowed for functions and altsteps
8624 switch(par
->get_asstype()) {
8625 case Common::Assignment::A_PAR_VAL_IN
:
8626 case Common::Assignment::A_PAR_TEMPL_IN
:
8627 case Common::Assignment::A_PAR_VAL_INOUT
:
8628 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8629 if (is_startable
&& par
->get_Type()->is_component_internal())
8630 is_startable
= false;
8633 is_startable
= false;
8636 if (!par
->has_defval()) min_nof_pars
= i
+ 1;
8637 // the last parameter without a default value determines the minimum
8641 // check that @lazy paramterization not used in cases currently unsupported
8642 void FormalParList::chk_noLazyParams() {
8643 Error_Context
cntxt(this, "In formal parameter list");
8644 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8645 FormalPar
*par
= pars_v
[i
];
8646 if (par
->get_lazy_eval()) {
8647 par
->error("Formal parameter `%s' cannot be @lazy, not supported in this case.",
8648 par
->get_id().get_dispname().c_str());
8653 void FormalParList::chk_startability(const char *p_what
, const char *p_name
)
8655 if(!checked
) FATAL_ERROR("FormalParList::chk_startability()");
8656 if (is_startable
) return;
8657 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8658 FormalPar
*par
= pars_v
[i
];
8659 switch (par
->get_asstype()) {
8660 case Common::Assignment::A_PAR_VAL_IN
:
8661 case Common::Assignment::A_PAR_TEMPL_IN
:
8662 case Common::Assignment::A_PAR_VAL_INOUT
:
8663 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8664 if (par
->get_Type()->is_component_internal()) {
8665 map
<Type
*,void> type_chain
;
8666 char* err_str
= mprintf("a parameter or embedded in a parameter of "
8667 "a function used in a start operation. "
8668 "%s `%s' cannot be started on a parallel test component "
8669 "because of `%s'", p_what
, p_name
, par
->get_description().c_str());
8670 par
->get_Type()->chk_component_internal(type_chain
, err_str
);
8675 par
->error("%s `%s' cannot be started on a parallel test component "
8676 "because it has %s", p_what
, p_name
, par
->get_description().c_str());
8681 void FormalParList::chk_compatibility(FormalParList
* p_fp_list
,
8684 size_t nof_type_pars
= pars_v
.size();
8685 size_t nof_function_pars
= p_fp_list
->pars_v
.size();
8686 // check for the number of parameters
8687 if (nof_type_pars
!= nof_function_pars
) {
8688 p_fp_list
->error("Too %s parameters: %lu was expected instead of %lu",
8689 nof_type_pars
< nof_function_pars
? "many" : "few",
8690 (unsigned long) nof_type_pars
, (unsigned long) nof_function_pars
);
8692 size_t upper_limit
=
8693 nof_type_pars
< nof_function_pars
? nof_type_pars
: nof_function_pars
;
8694 for (size_t i
= 0; i
< upper_limit
; i
++) {
8695 FormalPar
*type_par
= pars_v
[i
];
8696 FormalPar
*function_par
= p_fp_list
->pars_v
[i
];
8697 Error_Context
cntxt(function_par
, "In parameter #%lu",
8698 (unsigned long) (i
+ 1));
8699 FormalPar::asstype_t type_par_asstype
= type_par
->get_asstype();
8700 FormalPar::asstype_t function_par_asstype
= function_par
->get_asstype();
8701 // check for parameter kind equivalence
8702 // (in, out or inout / value or template)
8703 if (type_par_asstype
!= function_par_asstype
) {
8704 function_par
->error("The kind of the parameter is not the same as in "
8705 "type `%s': %s was expected instead of %s", where
,
8706 type_par
->get_assname(), function_par
->get_assname());
8708 // check for type equivalence
8709 if (type_par_asstype
!= FormalPar::A_PAR_TIMER
&&
8710 function_par_asstype
!= FormalPar::A_PAR_TIMER
) {
8711 Type
*type_par_type
= type_par
->get_Type();
8712 Type
*function_par_type
= function_par
->get_Type();
8713 if (!type_par_type
->is_identical(function_par_type
)) {
8714 function_par_type
->error("The type of the parameter is not the same "
8715 "as in type `%s': `%s' was expected instead of `%s'", where
,
8716 type_par_type
->get_typename().c_str(),
8717 function_par_type
->get_typename().c_str());
8718 } else if (type_par_type
->get_sub_type() && function_par_type
->get_sub_type() &&
8719 (type_par_type
->get_sub_type()->get_subtypetype()==function_par_type
->get_sub_type()->get_subtypetype()) &&
8720 (!type_par_type
->get_sub_type()->is_compatible(function_par_type
->get_sub_type()))) {
8721 // TODO: maybe equivalence should be checked, or maybe that is too strict
8722 function_par_type
->error(
8723 "Subtype mismatch: subtype %s has no common value with subtype %s",
8724 type_par_type
->get_sub_type()->to_string().c_str(),
8725 function_par_type
->get_sub_type()->to_string().c_str());
8728 // check for template restriction equivalence
8729 if (type_par
->get_template_restriction()!=
8730 function_par
->get_template_restriction()) {
8731 function_par
->error("The template restriction of the parameter is "
8732 "not the same as in type `%s': %s restriction was expected instead "
8733 "of %s restriction", where
,
8734 type_par
->get_template_restriction()==TR_NONE
? "no" :
8735 Template::get_restriction_name(type_par
->get_template_restriction()),
8736 function_par
->get_template_restriction()==TR_NONE
? "no" :
8737 Template::get_restriction_name(function_par
->
8738 get_template_restriction()));
8740 // check for @lazy equivalence
8741 if (type_par
->get_lazy_eval()!=function_par
->get_lazy_eval()) {
8742 function_par
->error("Parameter @lazy-ness mismatch");
8744 // check for name equivalence
8745 const Identifier
& type_par_id
= type_par
->get_id();
8746 const Identifier
& function_par_id
= function_par
->get_id();
8747 if (type_par_id
!= function_par_id
) {
8748 function_par
->warning("The name of the parameter is not the same "
8749 "as in type `%s': `%s' was expected instead of `%s'", where
,
8750 type_par_id
.get_dispname().c_str(),
8751 function_par_id
.get_dispname().c_str());
8756 bool FormalParList::fold_named_and_chk(ParsedActualParameters
*p_paps
,
8757 ActualParList
*p_aplist
)
8759 const size_t num_named
= p_paps
->get_nof_nps();
8760 const size_t num_unnamed
= p_paps
->get_nof_tis();
8761 size_t num_actual
= num_unnamed
;
8763 // Construct a map to tell us what index a FormalPar has
8764 typedef map
<FormalPar
*, size_t> formalpar_map_t
;
8765 formalpar_map_t formalpar_map
;
8767 size_t num_fp
= get_nof_fps();
8768 for (size_t fpx
= 0; fpx
< num_fp
; ++fpx
) {
8769 FormalPar
*fp
= get_fp_byIndex(fpx
);
8770 formalpar_map
.add(fp
, new size_t(fpx
));
8773 // Go through the named parameters
8774 for (size_t i
= 0; i
< num_named
; ++i
) {
8775 NamedParam
*np
= p_paps
->extract_np_byIndex(i
);
8776 // We are now responsible for np.
8778 if (has_fp_withName(*np
->get_name())) {
8779 // there is a formal parameter with that name
8780 FormalPar
*fp
= get_fp_byName(*np
->get_name());
8781 const size_t is_at
= *formalpar_map
[fp
]; // the index of the formal par
8782 if (is_at
>= num_actual
) {
8783 // There is no actual par in the unnamed part.
8784 // Create one from the named param.
8786 // First, pad the gap with '-'
8787 for (; num_actual
< is_at
; ++num_actual
) {
8789 if (pars_v
[num_actual
]->has_defval()) {
8790 not_used
= new Template(Template::TEMPLATE_NOTUSED
);
8792 else { // cannot use '-' if no default value
8793 not_used
= new Template(Template::TEMPLATE_ERROR
);
8795 TemplateInstance
*new_ti
= new TemplateInstance(0, 0, not_used
);
8796 // Conjure a location info at the beginning of the unnamed part
8797 // (that is, the beginning of the actual parameter list)
8798 new_ti
->set_location(p_paps
->get_tis()->get_filename(),
8799 p_paps
->get_tis()->get_first_line(),
8800 p_paps
->get_tis()->get_first_column(), 0, 0);
8801 p_paps
->get_tis()->add_ti(new_ti
);
8803 TemplateInstance
* namedti
= np
->extract_ti();
8804 p_paps
->get_tis()->add_ti(namedti
);
8807 // There is already an actual par at that position, fetch it
8808 TemplateInstance
* ti
= p_paps
->get_tis()->get_ti_byIndex(is_at
);
8809 Template::templatetype_t tt
= ti
->get_Template()->get_templatetype();
8811 if (is_at
>= num_unnamed
&& !ti
->get_Type() && !ti
->get_DerivedRef()
8812 && (tt
== Template::TEMPLATE_NOTUSED
|| tt
== Template::TEMPLATE_ERROR
)) {
8813 // NotUsed in the named part => padding
8814 np
->error("Named parameter `%s' out of order",
8815 np
->get_name()->get_dispname().c_str());
8817 // attempt to override an original unnamed param with a named one
8818 np
->error("Formal parameter `%s' assigned more than once",
8819 np
->get_name()->get_dispname().c_str());
8823 else { // no formal parameter with that name
8825 switch (my_def
->get_asstype()) {
8826 case Common::Assignment::A_TYPE
: {
8827 Type
*t
= my_def
->get_Type();
8829 switch (t
? t
->get_typetype() : 0) {
8830 case Type::T_FUNCTION
:
8831 nam
= mcopystr("Function reference");
8833 case Type::T_ALTSTEP
:
8834 nam
= mcopystr("Altstep reference");
8836 case Type::T_TESTCASE
:
8837 nam
= mcopystr("Testcase reference");
8840 FATAL_ERROR("FormalParList::chk_actual_parlist() "
8841 "Unexpected type %s", t
->get_typename().c_str());
8842 } // switch(typetype)
8845 nam
= mcopystr(my_def
->get_assname());
8847 } // switch(asstype)
8849 *nam
&= ~('a'-'A'); // Make the first letter uppercase
8850 p_paps
->get_tis()->error("%s `%s' has no formal parameter `%s'",
8852 my_def
->get_fullname().c_str(),
8853 np
->get_name()->get_dispname().c_str());
8860 for (size_t fpx
= 0; fpx
< num_fp
; ++fpx
) {
8861 delete formalpar_map
.get_nth_elem(fpx
);
8863 formalpar_map
.clear();
8865 return chk_actual_parlist(p_paps
->get_tis(), p_aplist
);
8868 bool FormalParList::chk_actual_parlist(TemplateInstances
*p_tis
,
8869 ActualParList
*p_aplist
)
8871 size_t formal_pars
= pars_v
.size();
8872 size_t actual_pars
= p_tis
->get_nof_tis();
8873 // p_aplist->get_nof_pars() is usually 0 on entry
8874 bool error_flag
= false;
8876 if (min_nof_pars
== formal_pars
) {
8877 // none of the parameters have default value
8878 if (actual_pars
!= formal_pars
) {
8879 p_tis
->error("Too %s parameters: %lu was expected "
8880 "instead of %lu", actual_pars
< formal_pars
? "few" : "many",
8881 (unsigned long) formal_pars
, (unsigned long) actual_pars
);
8885 // some parameters have default value
8886 if (actual_pars
< min_nof_pars
) {
8887 p_tis
->error("Too few parameters: at least %lu "
8888 "was expected instead of %lu",
8889 (unsigned long) min_nof_pars
, (unsigned long) actual_pars
);
8891 } else if (actual_pars
> formal_pars
) {
8892 p_tis
->error("Too many parameters: at most %lu "
8893 "was expected instead of %lu",
8894 (unsigned long) formal_pars
, (unsigned long) actual_pars
);
8899 // Do not check actual parameters in excess of the formal ones
8900 size_t upper_limit
= actual_pars
< formal_pars
? actual_pars
: formal_pars
;
8901 for (size_t i
= 0; i
< upper_limit
; i
++) {
8902 TemplateInstance
*ti
= p_tis
->get_ti_byIndex(i
);
8904 // the formal parameter for the current actual parameter
8905 FormalPar
*fp
= pars_v
[i
];
8906 Error_Context
cntxt(ti
, "In parameter #%lu for `%s'",
8907 (unsigned long) (i
+ 1), fp
->get_id().get_dispname().c_str());
8908 if (!ti
->get_Type() && !ti
->get_DerivedRef() && ti
->get_Template()
8909 ->get_templatetype() == Template::TEMPLATE_NOTUSED
) {
8910 if (fp
->has_defval()) {
8911 ActualPar
*defval
= fp
->get_defval();
8912 p_aplist
->add(new ActualPar(defval
));
8913 if (defval
->is_erroneous()) error_flag
= true;
8915 ti
->error("Not used symbol (`-') cannot be used for parameter "
8916 "that does not have default value");
8917 p_aplist
->add(new ActualPar());
8920 } else if (!ti
->get_Type() && !ti
->get_DerivedRef() && ti
->get_Template()
8921 ->get_templatetype() == Template::TEMPLATE_ERROR
) {
8922 ti
->error("Parameter not specified");
8924 ActualPar
*ap
= fp
->chk_actual_par(ti
, Type::EXPECTED_DYNAMIC_VALUE
);
8926 if (ap
->is_erroneous()) error_flag
= true;
8930 // The rest of formal parameters have no corresponding actual parameters.
8931 // Create actual parameters for them based on their default values
8932 // (which must exist).
8933 for (size_t i
= upper_limit
; i
< formal_pars
; i
++) {
8934 FormalPar
*fp
= pars_v
[i
];
8935 if (fp
->has_defval()) {
8936 ActualPar
*defval
= fp
->get_defval();
8937 p_aplist
->add(new ActualPar(defval
));
8938 if (defval
->is_erroneous()) error_flag
= true;
8940 p_aplist
->add(new ActualPar()); // erroneous
8947 bool FormalParList::chk_activate_argument(ActualParList
*p_aplist
,
8948 const char* p_description
)
8950 bool ret_val
= true;
8951 for(size_t i
= 0; i
< p_aplist
->get_nof_pars(); i
++) {
8952 ActualPar
*t_ap
= p_aplist
->get_par(i
);
8953 if(t_ap
->get_selection() != ActualPar::AP_REF
) continue;
8954 FormalPar
*t_fp
= pars_v
[i
];
8955 switch(t_fp
->get_asstype()) {
8956 case Common::Assignment::A_PAR_VAL_OUT
:
8957 case Common::Assignment::A_PAR_VAL_INOUT
:
8958 case Common::Assignment::A_PAR_TEMPL_OUT
:
8959 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8960 case Common::Assignment::A_PAR_TIMER
:
8961 //the checking shall be performed for these parameter types
8963 case Common::Assignment::A_PAR_PORT
:
8964 // port parameters are always correct because ports can be defined
8965 // only in component types
8968 FATAL_ERROR("FormalParList::chk_activate_argument()");
8970 Ref_base
*t_ref
= t_ap
->get_Ref();
8971 Common::Assignment
*t_par_ass
= t_ref
->get_refd_assignment();
8972 if(!t_par_ass
) FATAL_ERROR("FormalParList::chk_activate_argument()");
8973 switch (t_par_ass
->get_asstype()) {
8974 case Common::Assignment::A_VAR
:
8975 case Common::Assignment::A_VAR_TEMPLATE
:
8976 case Common::Assignment::A_TIMER
:
8977 // it is not allowed to pass references of local variables or timers
8978 if (t_par_ass
->is_local()) {
8979 t_ref
->error("Parameter #%lu of %s refers to %s, which is a local "
8980 "definition within a statement block and may have shorter "
8981 "lifespan than the activated default. Only references to "
8982 "variables and timers defined in the component type can be passed "
8983 "to activated defaults", (unsigned long) (i
+ 1), p_description
,
8984 t_par_ass
->get_description().c_str());
8988 case Common::Assignment::A_PAR_VAL_IN
:
8989 case Common::Assignment::A_PAR_VAL_OUT
:
8990 case Common::Assignment::A_PAR_VAL_INOUT
:
8991 case Common::Assignment::A_PAR_TEMPL_IN
:
8992 case Common::Assignment::A_PAR_TEMPL_OUT
:
8993 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8994 case Common::Assignment::A_PAR_TIMER
: {
8995 // it is not allowed to pass references pointing to formal parameters
8996 // except for activate() statements within testcases
8997 // note: all defaults are deactivated at the end of the testcase
8998 FormalPar
*t_refd_fp
= dynamic_cast<FormalPar
*>(t_par_ass
);
8999 if (!t_refd_fp
) FATAL_ERROR("FormalParList::chk_activate_argument()");
9000 FormalParList
*t_fpl
= t_refd_fp
->get_my_parlist();
9001 if (!t_fpl
|| !t_fpl
->my_def
)
9002 FATAL_ERROR("FormalParList::chk_activate_argument()");
9003 if (t_fpl
->my_def
->get_asstype() != Common::Assignment::A_TESTCASE
) {
9004 t_ref
->error("Parameter #%lu of %s refers to %s, which may have "
9005 "shorter lifespan than the activated default. Only references to "
9006 "variables and timers defined in the component type can be passed "
9007 "to activated defaults", (unsigned long) (i
+ 1), p_description
,
9008 t_par_ass
->get_description().c_str());
9018 char *FormalParList::generate_code(char *str
, size_t display_unused
/* = 0 */)
9020 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9021 if (i
> 0) str
= mputstr(str
, ", ");
9022 str
= pars_v
[i
]->generate_code_fpar(str
, i
< display_unused
);
9027 char* FormalParList::generate_code_defval(char* str
)
9029 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9030 str
= pars_v
[i
]->generate_code_defval(str
);
9035 void FormalParList::generate_code_defval(output_struct
*target
)
9037 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9038 pars_v
[i
]->generate_code_defval(target
);
9042 char *FormalParList::generate_code_actual_parlist(char *str
,
9043 const char *p_prefix
)
9045 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
9046 if (i
> 0) str
= mputstr(str
, ", ");
9047 str
= mputstr(str
, p_prefix
);
9048 str
= mputstr(str
, pars_v
[i
]->get_id().get_name().c_str());
9053 char *FormalParList::generate_code_object(char *str
, const char *p_prefix
, char refch
)
9055 for (size_t i
= 0; i
< pars_v
.size(); i
++)
9056 str
= pars_v
[i
]->generate_code_object(str
, p_prefix
, refch
);
9060 char *FormalParList::generate_shadow_objects(char *str
) const
9062 for (size_t i
= 0; i
< pars_v
.size(); i
++)
9063 str
= pars_v
[i
]->generate_shadow_object(str
);
9067 char *FormalParList::generate_code_set_unbound(char *str
) const
9069 if (enable_set_bound_out_param
) return str
;
9070 for (size_t i
= 0; i
< pars_v
.size(); i
++)
9071 str
= pars_v
[i
]->generate_code_set_unbound(str
);
9076 void FormalParList::dump(unsigned level
) const
9078 size_t nof_pars
= pars_v
.size();
9079 DEBUG(level
, "formal parameters: %lu pcs.", (unsigned long) nof_pars
);
9080 for(size_t i
= 0; i
< nof_pars
; i
++) pars_v
[i
]->dump(level
+ 1);
9083 // =================================
9085 // =================================
9087 ActualPar::ActualPar(Value
*v
)
9088 : Node(), selection(AP_VALUE
), my_scope(0), gen_restriction_check(TR_NONE
),
9089 gen_post_restriction_check(TR_NONE
)
9091 if (!v
) FATAL_ERROR("ActualPar::ActualPar()");
9095 ActualPar::ActualPar(TemplateInstance
*t
)
9096 : Node(), selection(AP_TEMPLATE
), my_scope(0),
9097 gen_restriction_check(TR_NONE
), gen_post_restriction_check(TR_NONE
)
9099 if (!t
) FATAL_ERROR("ActualPar::ActualPar()");
9103 ActualPar::ActualPar(Ref_base
*r
)
9104 : Node(), selection(AP_REF
), my_scope(0), gen_restriction_check(TR_NONE
),
9105 gen_post_restriction_check(TR_NONE
)
9107 if (!r
) FATAL_ERROR("ActualPar::ActualPar()");
9111 ActualPar::ActualPar(ActualPar
*a
)
9112 : Node(), selection(AP_DEFAULT
), my_scope(0),
9113 gen_restriction_check(TR_NONE
), gen_post_restriction_check(TR_NONE
)
9115 if (!a
) FATAL_ERROR("ActualPar::ActualPar()");
9119 ActualPar::~ActualPar()
9134 break; // nothing to do with act
9136 FATAL_ERROR("ActualPar::~ActualPar()");
9140 ActualPar
*ActualPar::clone() const
9142 FATAL_ERROR("ActualPar::clone");
9145 void ActualPar::set_fullname(const string
& p_fullname
)
9147 Node::set_fullname(p_fullname
);
9152 val
->set_fullname(p_fullname
);
9155 temp
->set_fullname(p_fullname
);
9158 ref
->set_fullname(p_fullname
);
9163 FATAL_ERROR("ActualPar::set_fullname()");
9167 void ActualPar::set_my_scope(Scope
*p_scope
)
9174 val
->set_my_scope(p_scope
);
9177 temp
->set_my_scope(p_scope
);
9180 ref
->set_my_scope(p_scope
);
9183 switch (act
->selection
) {
9185 ref
->set_my_scope(p_scope
);
9192 FATAL_ERROR("ActualPar::set_my_scope()");
9196 FATAL_ERROR("ActualPar::set_my_scope()");
9200 Value
*ActualPar::get_Value() const
9202 if (selection
!= AP_VALUE
) FATAL_ERROR("ActualPar::get_Value()");
9206 TemplateInstance
*ActualPar::get_TemplateInstance() const
9208 if (selection
!= AP_TEMPLATE
)
9209 FATAL_ERROR("ActualPar::get_TemplateInstance()");
9213 Ref_base
*ActualPar::get_Ref() const
9215 if (selection
!= AP_REF
) FATAL_ERROR("ActualPar::get_Ref()");
9219 ActualPar
*ActualPar::get_ActualPar() const
9221 if (selection
!= AP_DEFAULT
) FATAL_ERROR("ActualPar::get_ActualPar()");
9225 void ActualPar::chk_recursions(ReferenceChain
& refch
)
9227 switch (selection
) {
9230 val
->chk_recursions(refch
);
9234 Ref_base
*derived_ref
= temp
->get_DerivedRef();
9236 ActualParList
*parlist
= derived_ref
->get_parlist();
9239 parlist
->chk_recursions(refch
);
9244 Ttcn::Def_Template
* defTemp
= temp
->get_Referenced_Base_Template();
9247 refch
.add(defTemp
->get_fullname());
9251 temp
->get_Template()->chk_recursions(refch
);
9259 bool ActualPar::has_single_expr()
9261 switch (selection
) {
9263 return val
->has_single_expr();
9265 if (gen_restriction_check
!=TR_NONE
||
9266 gen_post_restriction_check
!=TR_NONE
) return false;
9267 return temp
->has_single_expr();
9269 if (gen_restriction_check
!=TR_NONE
||
9270 gen_post_restriction_check
!=TR_NONE
) return false;
9271 if (use_runtime_2
&& ref
->get_subrefs() != NULL
) {
9272 FieldOrArrayRefs
* subrefs
= ref
->get_subrefs();
9273 for (size_t i
= 0; i
< subrefs
->get_nof_refs(); ++i
) {
9274 if (FieldOrArrayRef::ARRAY_REF
== subrefs
->get_ref(i
)->get_type()) {
9279 return ref
->has_single_expr();
9283 FATAL_ERROR("ActualPar::has_single_expr()");
9288 void ActualPar::set_code_section(
9289 GovernedSimple::code_section_t p_code_section
)
9291 switch (selection
) {
9293 val
->set_code_section(p_code_section
);
9296 temp
->set_code_section(p_code_section
);
9299 ref
->set_code_section(p_code_section
);
9305 void ActualPar::generate_code(expression_struct
*expr
, bool copy_needed
, bool lazy_param
, bool used_as_lvalue
) const
9307 switch (selection
) {
9309 if (lazy_param
) { // copy_needed doesn't matter in this case
9310 LazyParamData::init(used_as_lvalue
);
9311 LazyParamData::generate_code(expr
, val
, my_scope
);
9312 LazyParamData::clean();
9313 if (val
->get_valuetype() == Value::V_REFD
) {
9314 // check if the reference is a parameter, mark it as used if it is
9315 Reference
* ref
= dynamic_cast<Reference
*>(val
->get_reference());
9317 ref
->refd_param_usage_found();
9321 if (copy_needed
) expr
->expr
= mputprintf(expr
->expr
, "%s(",
9322 val
->get_my_governor()->get_genname_value(my_scope
).c_str());
9323 if (use_runtime_2
&& TypeConv::needs_conv_refd(val
)) {
9324 // Generate everything to preamble to be able to tackle the wrapper
9325 // constructor call. TODO: Reduce the number of temporaries created.
9326 const string
& tmp_id
= val
->get_temporary_id();
9327 const char *tmp_id_str
= tmp_id
.c_str();
9328 expr
->preamble
= mputprintf(expr
->preamble
, "%s %s;\n",
9329 val
->get_my_governor()->get_genname_value(my_scope
).c_str(),
9331 expr
->preamble
= TypeConv::gen_conv_code_refd(expr
->preamble
,
9333 expr
->expr
= mputstr(expr
->expr
, tmp_id_str
);
9334 } else val
->generate_code_expr(expr
);
9335 if (copy_needed
) expr
->expr
= mputc(expr
->expr
, ')');
9339 if (lazy_param
) { // copy_needed doesn't matter in this case
9340 LazyParamData::init(used_as_lvalue
);
9341 LazyParamData::generate_code(expr
, temp
, gen_restriction_check
, my_scope
);
9342 LazyParamData::clean();
9343 if (temp
->get_DerivedRef() != NULL
||
9344 temp
->get_Template()->get_templatetype() == Template::TEMPLATE_REFD
) {
9345 // check if the reference is a parameter, mark it as used if it is
9346 Reference
* ref
= dynamic_cast<Reference
*>(temp
->get_DerivedRef() != NULL
?
9347 temp
->get_DerivedRef() : temp
->get_Template()->get_reference());
9349 ref
->refd_param_usage_found();
9354 expr
->expr
= mputprintf(expr
->expr
, "%s(", temp
->get_Template()
9355 ->get_my_governor()->get_genname_template(my_scope
).c_str());
9356 if (use_runtime_2
&& TypeConv::needs_conv_refd(temp
->get_Template())) {
9357 const string
& tmp_id
= temp
->get_Template()->get_temporary_id();
9358 const char *tmp_id_str
= tmp_id
.c_str();
9359 expr
->preamble
= mputprintf(expr
->preamble
, "%s %s;\n",
9360 temp
->get_Template()->get_my_governor()
9361 ->get_genname_template(my_scope
).c_str(), tmp_id_str
);
9362 expr
->preamble
= TypeConv::gen_conv_code_refd(expr
->preamble
,
9363 tmp_id_str
, temp
->get_Template());
9364 // Not incorporated into gen_conv_code() yet.
9365 if (gen_restriction_check
!= TR_NONE
)
9366 expr
->preamble
= Template::generate_restriction_check_code(
9367 expr
->preamble
, tmp_id_str
, gen_restriction_check
);
9368 expr
->expr
= mputstr(expr
->expr
, tmp_id_str
);
9369 } else temp
->generate_code(expr
, gen_restriction_check
);
9370 if (copy_needed
) expr
->expr
= mputc(expr
->expr
, ')');
9374 if (lazy_param
) FATAL_ERROR("ActualPar::generate_code()"); // syntax error should have already happened
9375 if (copy_needed
) FATAL_ERROR("ActualPar::generate_code()");
9376 if (gen_restriction_check
!= TR_NONE
||
9377 gen_post_restriction_check
!= TR_NONE
) {
9378 // generate runtime check for restricted templates
9379 // code for reference + restriction check
9380 Common::Assignment
*ass
= ref
->get_refd_assignment();
9381 const string
& tmp_id
= my_scope
->get_scope_mod_gen()->get_temporary_id();
9382 const char *tmp_id_str
= tmp_id
.c_str();
9383 expression_struct ref_expr
;
9384 Code::init_expr(&ref_expr
);
9385 ref
->generate_code_const_ref(&ref_expr
);
9386 ref_expr
.preamble
= mputprintf(ref_expr
.preamble
, "%s& %s = %s;\n",
9387 ass
->get_Type()->get_genname_template(ref
->get_my_scope()).c_str(),
9388 tmp_id_str
, ref_expr
.expr
);
9389 if (gen_restriction_check
!= TR_NONE
) {
9390 ref_expr
.preamble
= Template::generate_restriction_check_code(
9391 ref_expr
.preamble
, tmp_id_str
, gen_restriction_check
);
9393 if (gen_post_restriction_check
!= TR_NONE
) {
9394 ref_expr
.postamble
= Template::generate_restriction_check_code(
9395 ref_expr
.postamble
, tmp_id_str
, gen_post_restriction_check
);
9397 // copy content of ref_expr to expr
9398 expr
->preamble
= mputstr(expr
->preamble
, ref_expr
.preamble
);
9399 expr
->expr
= mputprintf(expr
->expr
, "%s", tmp_id_str
);
9400 expr
->postamble
= mputstr(expr
->postamble
, ref_expr
.postamble
);
9401 Code::free_expr(&ref_expr
);
9403 ref
->generate_code(expr
);
9407 if (copy_needed
) FATAL_ERROR("ActualPar::generate_code()");
9408 switch (act
->selection
) {
9411 LazyParamData::generate_code_ap_default_ref(expr
, act
->ref
, my_scope
);
9413 act
->ref
->generate_code(expr
);
9418 LazyParamData::generate_code_ap_default_value(expr
, act
->val
, my_scope
);
9420 expr
->expr
= mputstr(expr
->expr
, act
->val
->get_genname_own(my_scope
).c_str());
9425 LazyParamData::generate_code_ap_default_ti(expr
, act
->temp
, my_scope
);
9427 expr
->expr
= mputstr(expr
->expr
, act
->temp
->get_Template()->get_genname_own(my_scope
).c_str());
9431 FATAL_ERROR("ActualPar::generate_code()");
9435 FATAL_ERROR("ActualPar::generate_code()");
9439 char *ActualPar::rearrange_init_code(char *str
, Common::Module
* usage_mod
)
9441 switch (selection
) {
9443 str
= val
->rearrange_init_code(str
);
9446 str
= temp
->rearrange_init_code(str
, usage_mod
);
9450 str
= act
->rearrange_init_code_defval(str
, usage_mod
);
9453 FATAL_ERROR("ActualPar::rearrange_init_code()");
9458 char *ActualPar::rearrange_init_code_defval(char *str
, Common::Module
* usage_mod
)
9460 switch (selection
) {
9462 if (val
->get_my_scope()->get_scope_mod_gen() == usage_mod
) {
9463 str
= val
->generate_code_init(str
, val
->get_lhs_name().c_str());
9467 str
= temp
->rearrange_init_code(str
, usage_mod
);
9468 Template
*t
= temp
->get_Template();
9469 if (t
->get_my_scope()->get_scope_mod_gen() == usage_mod
) {
9470 Ref_base
*dref
= temp
->get_DerivedRef();
9472 expression_struct expr
;
9473 Code::init_expr(&expr
);
9474 expr
.expr
= mputprintf(expr
.expr
, "%s = ", t
->get_lhs_name().c_str());
9475 dref
->generate_code(&expr
);
9476 str
= Code::merge_free_expr(str
, &expr
, false);
9478 str
= t
->generate_code_init(str
, t
->get_lhs_name().c_str());
9482 FATAL_ERROR("ActualPar::rearrange_init_code_defval()");
9487 void ActualPar::append_stringRepr(string
& str
) const
9489 switch (selection
) {
9491 str
+= val
->get_stringRepr();
9494 temp
->append_stringRepr(str
);
9497 str
+= ref
->get_dispname();
9503 str
+= "<erroneous actual parameter>";
9507 void ActualPar::dump(unsigned level
) const
9509 switch (selection
) {
9511 DEBUG(level
, "actual parameter: value");
9512 val
->dump(level
+ 1);
9515 DEBUG(level
, "actual parameter: template");
9516 temp
->dump(level
+ 1);
9519 DEBUG(level
, "actual parameter: referecne");
9520 ref
->dump(level
+ 1);
9523 DEBUG(level
, "actual parameter: default");
9526 DEBUG(level
, "actual parameter: erroneous");
9530 // =================================
9531 // ===== ActualParList
9532 // =================================
9534 ActualParList::ActualParList(const ActualParList
& p
)
9537 size_t nof_pars
= p
.params
.size();
9538 for (size_t i
= 0; i
< nof_pars
; i
++) params
.add(p
.params
[i
]->clone());
9541 ActualParList::~ActualParList()
9543 size_t nof_pars
= params
.size();
9544 for (size_t i
= 0; i
< nof_pars
; i
++) delete params
[i
];
9548 ActualParList
*ActualParList::clone() const
9550 return new ActualParList(*this);
9553 void ActualParList::set_fullname(const string
& p_fullname
)
9555 Node::set_fullname(p_fullname
);
9556 size_t nof_pars
= params
.size();
9557 for(size_t i
= 0; i
< nof_pars
; i
++)
9558 params
[i
]->set_fullname(p_fullname
+
9559 ".<parameter" + Int2string(i
+ 1) + ">");
9562 void ActualParList::set_my_scope(Scope
*p_scope
)
9564 size_t nof_pars
= params
.size();
9565 for (size_t i
= 0; i
< nof_pars
; i
++) params
[i
]->set_my_scope(p_scope
);
9568 void ActualParList::chk_recursions(ReferenceChain
& refch
)
9570 size_t nof_pars
= params
.size();
9571 for (size_t i
= 0; i
< nof_pars
; i
++)
9572 params
[i
]->chk_recursions(refch
);
9575 void ActualParList::generate_code_noalias(expression_struct
*expr
, FormalParList
*p_fpl
)
9577 size_t nof_pars
= params
.size();
9578 for (size_t i
= 0; i
< nof_pars
; i
++) {
9579 if (i
> 0) expr
->expr
= mputstr(expr
->expr
, ", ");
9580 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());
9584 void ActualParList::generate_code_alias(expression_struct
*expr
,
9585 FormalParList
*p_fpl
, Type
*p_comptype
, bool p_compself
)
9587 size_t nof_pars
= params
.size();
9588 // collect all value and template definitions that are passed by reference
9589 map
<Common::Assignment
*, void> value_refs
, template_refs
;
9590 for (size_t i
= 0; i
< nof_pars
; i
++) {
9591 ActualPar
*par
= params
[i
];
9592 if (par
->get_selection() == ActualPar::AP_DEFAULT
)
9593 par
= par
->get_ActualPar();
9594 if (par
->get_selection() == ActualPar::AP_REF
) {
9595 Common::Assignment
*ass
= par
->get_Ref()->get_refd_assignment();
9596 switch (ass
->get_asstype()) {
9597 case Common::Assignment::A_VAR
:
9598 case Common::Assignment::A_PAR_VAL_IN
:
9599 case Common::Assignment::A_PAR_VAL_OUT
:
9600 case Common::Assignment::A_PAR_VAL_INOUT
:
9601 if (!value_refs
.has_key(ass
)) value_refs
.add(ass
, 0);
9603 case Common::Assignment::A_VAR_TEMPLATE
:
9604 case Common::Assignment::A_PAR_TEMPL_IN
:
9605 case Common::Assignment::A_PAR_TEMPL_OUT
:
9606 case Common::Assignment::A_PAR_TEMPL_INOUT
:
9607 if (!template_refs
.has_key(ass
)) template_refs
.add(ass
, 0);
9613 // walk through the parameter list and generate the code
9614 // add an extra copy constructor call to the referenced value and template
9615 // parameters if the referred definition is also passed by reference to
9616 // another parameter
9617 for (size_t i
= 0; i
< nof_pars
; i
++) {
9618 if (i
> 0) expr
->expr
= mputstr(expr
->expr
, ", ");
9619 ActualPar
*par
= params
[i
];
9620 bool copy_needed
= false;
9621 // the copy constructor call is not needed if the parameter is copied
9622 // into a shadow object in the body of the called function
9623 if (!p_fpl
|| !p_fpl
->get_fp_byIndex(i
)->get_used_as_lvalue()) {
9624 switch (par
->get_selection()) {
9625 case ActualPar::AP_VALUE
: {
9626 Value
*v
= par
->get_Value();
9627 if (v
->get_valuetype() == Value::V_REFD
) {
9628 Common::Assignment
*t_ass
=
9629 v
->get_reference()->get_refd_assignment();
9630 if (value_refs
.has_key(t_ass
)) {
9631 // a reference to the same variable is also passed to the called
9634 } else if (p_comptype
|| p_compself
) {
9635 // the called definition has a 'runs on' clause so it can access
9636 // component variables
9637 switch (t_ass
->get_asstype()) {
9638 case Common::Assignment::A_PAR_VAL_OUT
:
9639 case Common::Assignment::A_PAR_VAL_INOUT
:
9640 // the parameter may be an alias of a component variable
9643 case Common::Assignment::A_VAR
:
9644 // copy is needed if t_ass is a component variable that is
9645 // visible by the called definition
9646 if (!t_ass
->is_local()) copy_needed
= true;
9647 /** \todo component type compatibility: check whether t_ass is
9648 * visible from p_comptype (otherwise copy is not needed) */
9655 case ActualPar::AP_TEMPLATE
: {
9656 TemplateInstance
*ti
= par
->get_TemplateInstance();
9657 if (!ti
->get_DerivedRef()) {
9658 Template
*t
= ti
->get_Template();
9659 if (t
->get_templatetype() == Template::TEMPLATE_REFD
) {
9660 Common::Assignment
*t_ass
=
9661 t
->get_reference()->get_refd_assignment();
9662 if (template_refs
.has_key(t_ass
)) {
9663 // a reference to the same variable is also passed to the called
9666 } else if (p_comptype
|| p_compself
) {
9667 // the called definition has a 'runs on' clause so it can access
9668 // component variables
9669 switch (t_ass
->get_asstype()) {
9670 case Common::Assignment::A_PAR_TEMPL_OUT
:
9671 case Common::Assignment::A_PAR_TEMPL_INOUT
:
9672 // the parameter may be an alias of a component variable
9675 case Common::Assignment::A_VAR_TEMPLATE
:
9676 // copy is needed if t_ass is a component variable that is
9677 // visible by the called definition
9678 if (!t_ass
->is_local()) copy_needed
= true;
9679 /** \todo component type compatibility: check whether t_ass is
9680 * visible from p_comptype (otherwise copy is not needed) */
9692 if (use_runtime_2
&& ActualPar::AP_REF
== par
->get_selection()) {
9693 // if the parameter references an element of a record of/set of, then
9694 // the record of object needs to know, so it doesn't delete the referenced
9696 Ref_base
* ref
= par
->get_Ref();
9697 FieldOrArrayRefs
* subrefs
= ref
->get_subrefs();
9698 if (subrefs
!= NULL
) {
9699 Common::Assignment
* ass
= ref
->get_refd_assignment();
9701 for (ref_i
= 0; ref_i
< subrefs
->get_nof_refs(); ++ref_i
) {
9702 FieldOrArrayRef
* subref
= subrefs
->get_ref(ref_i
);
9703 if (FieldOrArrayRef::ARRAY_REF
== subref
->get_type()) {
9704 // set the referenced index in each array in the subrefs
9705 expression_struct array_expr
;
9706 Code::init_expr(&array_expr
);
9707 // the array object's name contains the reference, followed by
9708 // the subrefs before the current array ref
9709 array_expr
.expr
= mcopystr(LazyParamData::in_lazy() ?
9710 LazyParamData::add_ref_genname(ass
, ref
->get_my_scope()).c_str() :
9711 ass
->get_genname_from_scope(ref
->get_my_scope()).c_str());
9713 subrefs
->generate_code(&array_expr
, ass
, ref_i
);
9715 expression_struct index_expr
;
9716 Code::init_expr(&index_expr
);
9717 subrefs
->get_ref(ref_i
)->get_val()->generate_code_expr(&index_expr
);
9718 // insert any preambles the array object or the index might have
9719 if (array_expr
.preamble
!= NULL
) {
9720 expr
->preamble
= mputstr(expr
->preamble
, array_expr
.preamble
);
9721 expr
->postamble
= mputstr(expr
->postamble
, array_expr
.preamble
);
9723 if (index_expr
.preamble
!= NULL
) {
9724 expr
->preamble
= mputstr(expr
->preamble
, index_expr
.preamble
);
9725 expr
->postamble
= mputstr(expr
->postamble
, index_expr
.preamble
);
9727 // let the array object know that the index is referenced before
9728 // calling the function, and let it know that it's now longer
9729 // referenced after the function call (this is done with the help
9730 // of the RefdIndexHandler's constructor and destructor)
9731 string tmp_id
= ref
->get_my_scope()->get_scope_mod_gen()->get_temporary_id();
9732 expr
->preamble
= mputprintf(expr
->preamble
,
9733 "RefdIndexHandler %s(&%s, %s);\n",
9734 tmp_id
.c_str(), array_expr
.expr
, index_expr
.expr
);
9735 // insert any postambles the array object or the index might have
9736 if (array_expr
.postamble
!= NULL
) {
9737 expr
->preamble
= mputstr(expr
->preamble
, array_expr
.postamble
);
9738 expr
->postamble
= mputstr(expr
->postamble
, array_expr
.postamble
);
9740 if (index_expr
.postamble
!= NULL
) {
9741 expr
->preamble
= mputstr(expr
->preamble
, index_expr
.postamble
);
9742 expr
->postamble
= mputstr(expr
->postamble
, index_expr
.postamble
);
9744 Code::free_expr(&array_expr
);
9745 Code::free_expr(&index_expr
);
9746 } // if (FieldOrArrayRef::ARRAY_REF == subref->get_type())
9748 } // if (subrefs != NULL)
9749 } // if (ActualPar::AP_REF == par->get_selection())
9751 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());
9754 template_refs
.clear();
9757 char *ActualParList::rearrange_init_code(char *str
, Common::Module
* usage_mod
)
9759 for (size_t i
= 0; i
< params
.size(); i
++)
9760 str
= params
[i
]->rearrange_init_code(str
, usage_mod
);
9764 void ActualParList::dump(unsigned level
) const
9766 DEBUG(level
, "actual parameter list: %lu parameters",
9767 (unsigned long) params
.size());
9768 for (size_t i
= 0; i
< params
.size(); i
++)
9769 params
[i
]->dump(level
+ 1);