1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "../../common/dbgnew.hh"
9 #include "AST_ttcn3.hh"
10 #include "../Identifier.hh"
11 #include "../CompilerError.hh"
12 #include "../Setting.hh"
14 #include "../CompField.hh"
15 #include "../CompType.hh"
16 #include "../TypeCompat.hh"
17 #include "../Valuestuff.hh"
18 #include "../Value.hh"
19 #include "Ttcnstuff.hh"
20 #include "TtcnTemplate.hh"
21 #include "Templatestuff.hh"
22 #include "ArrayDimensions.hh"
25 #include "Statement.hh"
27 #include "Attributes.hh"
28 #include "PatternString.hh"
29 #include "../../common/version_internal.h"
30 #include "../CodeGenHelper.hh"
31 #include "../../common/JSON_Tokenizer.hh"
34 // implemented in coding_attrib_p.y
35 extern Ttcn::ExtensionAttributes
* parse_extattributes(
36 Ttcn::WithAttribPath
*w_attrib_path
);
38 // implemented in compiler.y
39 extern Ttcn::ErroneousAttributeSpec
* ttcn3_parse_erroneous_attr_spec_string(
40 const char* p_str
, const Common::Location
& str_loc
);
43 extern void init_coding_attrib_lex(const Ttcn::AttributeSpec
& attrib
);
44 extern int coding_attrib_parse();
45 extern void cleanup_coding_attrib_lex();
46 extern Ttcn::ExtensionAttributes
*extatrs
;
48 /** Create a field name in the anytype
50 * The output of this function will be used to create an identifier
51 * to be used as the field name in the anytype.
52 * The type_name may be a built-in type (e.g. "integer") or a user-defined
55 * If the name has multiple components (a fullname?), it keeps just the last
56 * component without any dots. *
57 * Also, the space in "universal charstring" needs to be replaced
58 * with an underscore to make it an identifier.
60 * Note: Prefixing with "AT_" is not done here, but in defUnionClass().
62 * @param type_name string
63 * @return string to be used as the identifier.
65 string
anytype_field(const string
& type_name
)
67 string
retval(type_name
);
69 // keep just the last part of the name
70 // TODO check if there's a way to get just the last component (note that fetching the string is done outside of this function)
71 size_t dot
= retval
.rfind('.');
72 if (dot
>= retval
.size()) dot
= 0;
74 retval
.replace(0, dot
, "");
79 extern Common::Modules
*modules
; // in main.cc
82 static const string
_T_("_T_");
87 using namespace Common
;
89 // =================================
90 // ===== FieldOrArrayRef
91 // =================================
93 FieldOrArrayRef::FieldOrArrayRef(const FieldOrArrayRef
& p
)
94 : Node(p
), Location(p
), ref_type(p
.ref_type
)
98 u
.id
= p
.u
.id
->clone();
101 u
.arp
= p
.u
.arp
->clone();
104 FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
108 FieldOrArrayRef::FieldOrArrayRef(Identifier
*p_id
)
109 : Node(), Location(), ref_type(FIELD_REF
)
111 if (!p_id
) FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
115 FieldOrArrayRef::FieldOrArrayRef(Value
*p_arp
)
116 : Node(), Location(), ref_type(ARRAY_REF
)
118 if (!p_arp
) FATAL_ERROR("FieldOrArrayRef::FieldOrArrayRef()");
122 FieldOrArrayRef::~FieldOrArrayRef()
132 FATAL_ERROR("FieldOrArrayRef::~FieldOrArrayRef()");
136 FieldOrArrayRef
*FieldOrArrayRef::clone() const
138 return new FieldOrArrayRef(*this);
141 void FieldOrArrayRef::set_fullname(const string
& p_fullname
)
143 Node::set_fullname(p_fullname
);
144 if (ref_type
== ARRAY_REF
)
145 u
.arp
->set_fullname(p_fullname
+ ".<array_index>");
148 void FieldOrArrayRef::set_my_scope(Scope
*p_scope
)
150 if (ref_type
== ARRAY_REF
) u
.arp
->set_my_scope(p_scope
);
153 const Identifier
* FieldOrArrayRef::get_id() const
155 if (ref_type
!= FIELD_REF
) FATAL_ERROR("FieldOrArrayRef::get_id()");
159 Value
*FieldOrArrayRef::get_val() const
161 if (ref_type
!= ARRAY_REF
) FATAL_ERROR("FieldOrArrayRef::get_val()");
165 void FieldOrArrayRef::append_stringRepr(string
& str
) const
170 str
+= u
.id
->get_dispname();
174 str
+= u
.arp
->get_stringRepr();
178 str
+= "<unknown sub-reference>";
182 // =================================
183 // ===== FieldOrArrayRefs
184 // =================================
186 FieldOrArrayRefs::FieldOrArrayRefs(const FieldOrArrayRefs
& p
)
187 : Node(p
), refs_str_element(false)
189 for (size_t i
= 0; i
< p
.refs
.size(); i
++) refs
.add(p
.refs
[i
]->clone());
192 FieldOrArrayRefs::~FieldOrArrayRefs()
194 for (size_t i
= 0; i
< refs
.size(); i
++) delete refs
[i
];
198 FieldOrArrayRefs
*FieldOrArrayRefs::clone() const
200 return new FieldOrArrayRefs(*this);
203 void FieldOrArrayRefs::set_fullname(const string
& p_fullname
)
205 Node::set_fullname(p_fullname
);
206 for (size_t i
= 0; i
< refs
.size(); i
++)
207 refs
[i
]->set_fullname(p_fullname
+
208 ".<sub_reference" + Int2string(i
+ 1) + ">");
211 void FieldOrArrayRefs::set_my_scope(Scope
*p_scope
)
213 for (size_t i
= 0; i
< refs
.size(); i
++) refs
[i
]->set_my_scope(p_scope
);
216 bool FieldOrArrayRefs::has_unfoldable_index() const
218 for (size_t i
= 0; i
< refs
.size(); i
++) {
219 FieldOrArrayRef
*ref
= refs
[i
];
220 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
) {
221 Value
*v
= ref
->get_val();
222 v
->set_lowerid_to_ref();
223 if (v
->is_unfoldable()) return true;
229 void FieldOrArrayRefs::remove_refs(size_t n
)
231 for (size_t i
= 0; i
< n
; i
++) delete refs
[i
];
232 refs
.replace(0, n
, NULL
);
233 set_fullname(get_fullname());
236 /* remove_last_field is used when unfolding references for
237 ischosen and ispresent function operands.
238 In this case it is NOT sure the last field exists.
239 Calling remove_last_field previously
240 will avoid getting the "variable...Has no member called..." error message.
241 The last field component will be checked as a separate step.
242 Warning: the removed Identifier has to be deleted later */
244 Identifier
* FieldOrArrayRefs::remove_last_field()
246 if (refs
.size() == 0) return 0;
247 size_t last_elem_ind
= refs
.size() - 1;
248 FieldOrArrayRef
* last_elem
= refs
[last_elem_ind
];
249 if (last_elem
->get_type() == FieldOrArrayRef::FIELD_REF
) {
250 Identifier
*ret_val
= last_elem
->get_id()->clone();
252 refs
.replace(last_elem_ind
, 1, NULL
);
257 void FieldOrArrayRefs::generate_code(expression_struct
*expr
,
258 Common::Assignment
*ass
, size_t nof_subrefs
/* = UINT_MAX*/)
261 bool is_template
= false;
262 switch (ass
->get_asstype()) {
263 case Common::Assignment::A_CONST
: // a Def_Const
264 case Common::Assignment::A_EXT_CONST
: // a Def_ExtConst
265 case Common::Assignment::A_MODULEPAR
: // a Def_Modulepar
266 case Common::Assignment::A_VAR
: // a Def_Var
267 case Common::Assignment::A_FUNCTION_RVAL
: // a Def_Function
268 case Common::Assignment::A_EXT_FUNCTION_RVAL
: // a Def_ExtFunction
269 case Common::Assignment::A_PAR_VAL_IN
: // a FormalPar
270 case Common::Assignment::A_PAR_VAL_OUT
: // a FormalPar
271 case Common::Assignment::A_PAR_VAL_INOUT
: // a FormalPar
272 // The type is important since the referred entities are value objects.
273 type
= ass
->get_Type();
275 case Common::Assignment::A_MODULEPAR_TEMP
: // a Def_Modulepar_Template
276 case Common::Assignment::A_TEMPLATE
: // a Def_Template
277 case Common::Assignment::A_VAR_TEMPLATE
: // a Def_Var_Template
278 case Common::Assignment::A_PAR_TEMPL_IN
: // a FormalPar
279 case Common::Assignment::A_PAR_TEMPL_OUT
: // a FormalPar
280 case Common::Assignment::A_PAR_TEMPL_INOUT
: // a FormalPar
281 // The type is semi-important because fields of anytype templates
283 type
= ass
->get_Type();
286 case Common::Assignment::A_TIMER
: // a Def_Timer
287 case Common::Assignment::A_PORT
: // a Def_Port
288 case Common::Assignment::A_FUNCTION_RTEMP
: // a Def_Function
289 case Common::Assignment::A_EXT_FUNCTION_RTEMP
: // a Def_ExtFunction
290 case Common::Assignment::A_PAR_TIMER
: // a FormalPar
291 case Common::Assignment::A_PAR_PORT
: // a FormalPar
292 // The type is not relevant (i.e. the optional fields do not require
293 // special handling).
297 // Reference to other definitions cannot occur during code generation.
298 FATAL_ERROR("FieldOrArrayRefs::generate_code()");
301 size_t n_refs
= (nof_subrefs
!= UINT_MAX
) ? nof_subrefs
: refs
.size();
302 for (size_t i
= 0; i
< n_refs
; i
++) {
303 if (type
) type
= type
->get_type_refd_last();
304 // type changes inside the loop; need to recompute "last" every time.
305 FieldOrArrayRef
*ref
= refs
[i
];
306 if (ref
->get_type() == FieldOrArrayRef::FIELD_REF
) {
307 // Write a call to the field accessor method.
308 // Fields of the anytype get a special prefix; see also:
309 // Template::generate_code_init_se, TypeConv::gen_conv_func_choice_anytype,
310 // defUnionClass and defUnionTemplate.
311 const Identifier
& id
= *ref
->get_id();
312 expr
->expr
= mputprintf(expr
->expr
, ".%s%s()",
313 ((type
!=0 && type
->get_typetype()==Type::T_ANYTYPE
) ? "AT_" : ""),
314 id
.get_name().c_str());
316 CompField
*cf
= type
->get_comp_byName(id
);
317 // If the field is optional, the return type of the accessor is an
318 // OPTIONAL<T>. Write a call to OPTIONAL<T>::operator(),
319 // which "reaches into" the OPTIONAL to get the contained type T.
320 // Don't do this at the end of the reference chain.
321 // Accessor methods for a foo_template return a bar_template
322 // and OPTIONAL<> is not involved, hence no "()".
323 if (!is_template
&& i
< n_refs
- 1 && cf
->get_is_optional())
324 expr
->expr
= mputstr(expr
->expr
, "()");
325 // Follow the field type.
326 type
= cf
->get_type();
329 // Generate code for array reference.
330 expr
->expr
= mputc(expr
->expr
, '[');
331 ref
->get_val()->generate_code_expr(expr
);
332 expr
->expr
= mputc(expr
->expr
, ']');
334 // Follow the embedded type.
335 switch (type
->get_typetype()) {
339 type
= type
->get_ofType();
342 // The index points to a string element.
343 // There are no further sub-references.
347 } // if (ref->get_type)
351 void FieldOrArrayRefs::append_stringRepr(string
& str
) const
353 for (size_t i
= 0; i
< refs
.size(); i
++) refs
[i
]->append_stringRepr(str
);
356 // =================================
358 // =================================
360 Ref_base::Ref_base(const Ref_base
& p
)
361 : Ref_simple(p
), subrefs(p
.subrefs
)
363 modid
= p
.modid
? p
.modid
->clone() : 0;
364 id
= p
.id
? p
.id
->clone() : 0;
365 params_checked
= p
.is_erroneous
;
368 Ref_base::Ref_base(Identifier
*p_modid
, Identifier
*p_id
)
369 : Ref_simple(), modid(p_modid
), id(p_id
), params_checked(false)
370 , usedInIsbound(false)
373 FATAL_ERROR("NULL parameter: Ttcn::Ref_base::Ref_base()");
376 Ref_base::~Ref_base()
382 void Ref_base::set_fullname(const string
& p_fullname
)
384 Ref_simple::set_fullname(p_fullname
);
385 subrefs
.set_fullname(p_fullname
);
388 void Ref_base::set_my_scope(Scope
*p_scope
)
390 Ref_simple::set_my_scope(p_scope
);
391 subrefs
.set_my_scope(p_scope
);
394 /* returns the referenced variable's base type or value */
395 Setting
* Ref_base::get_refd_setting()
397 Common::Assignment
*ass
= get_refd_assignment();
398 if (ass
) return ass
->get_Setting();
402 FieldOrArrayRefs
*Ref_base::get_subrefs()
404 if (!id
) get_modid();
405 if (subrefs
.get_nof_refs() == 0) return 0;
406 else return &subrefs
;
409 bool Ref_base::has_single_expr()
411 Common::Assignment
*ass
= get_refd_assignment();
412 if (!ass
) FATAL_ERROR("Ref_base::has_single_expr()");
413 for (size_t i
= 0; i
< subrefs
.get_nof_refs(); i
++) {
414 FieldOrArrayRef
*ref
= subrefs
.get_ref(i
);
415 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
&&
416 !ref
->get_val()->has_single_expr()) return false;
421 void Ref_base::set_code_section(
422 GovernedSimple::code_section_t p_code_section
)
424 for (size_t i
= 0; i
< subrefs
.get_nof_refs(); i
++) {
425 FieldOrArrayRef
*ref
= subrefs
.get_ref(i
);
426 if (ref
->get_type() == FieldOrArrayRef::ARRAY_REF
)
427 ref
->get_val()->set_code_section(p_code_section
);
431 void Ref_base::generate_code_const_ref(expression_struct_t */
*expr*/
)
433 FATAL_ERROR("Ref_base::generate_code_const_ref()");
436 // =================================
438 // =================================
440 Reference::Reference(Identifier
*p_id
)
441 : Ref_base(), parlist(0)
443 subrefs
.add(new FieldOrArrayRef(p_id
));
446 Reference::~Reference()
454 * Common::PortTypeBody::PortTypeBody
456 * Common::TypeMappingTarget::TypeMappingTarget
457 * Common::PatternString::ps_elem_t::chk_ref */
458 Reference
*Reference::clone() const
460 return new Reference(*this);
463 string
Reference::get_dispname()
468 ret_val
+= modid
->get_dispname();
471 ret_val
+= id
->get_dispname();
472 subrefs
.append_stringRepr(ret_val
);
474 subrefs
.append_stringRepr(ret_val
);
475 // cut the leading dot
476 if (!ret_val
.empty() && ret_val
[0] == '.')
477 ret_val
.replace(0, 1, "");
482 Common::Assignment
* Reference::get_refd_assignment(bool check_parlist
)
484 Common::Assignment
*ass
= Ref_base::get_refd_assignment(check_parlist
);
485 // In fact calls Ref_simple::get_refd_assignment
486 if (ass
&& check_parlist
&& !params_checked
) {
487 params_checked
= true;
488 FormalParList
*fplist
= ass
->get_FormalParList();
490 if (fplist
->has_only_default_values()
491 && Common::Assignment::A_TEMPLATE
== ass
->get_asstype()) {
492 Ttcn::ParsedActualParameters params
;
493 Error_Context
cntxt(¶ms
, "In actual parameter list of %s",
494 ass
->get_description().c_str());
495 parlist
= new ActualParList();
496 is_erroneous
= fplist
->fold_named_and_chk(¶ms
, parlist
);
497 parlist
->set_fullname(get_fullname());
498 parlist
->set_my_scope(my_scope
);
500 error("Reference to parameterized definition `%s' without "
501 "actual parameter list", ass
->get_id().get_dispname().c_str());
508 const Identifier
* Reference::get_modid()
510 if (!id
) detect_modid();
514 const Identifier
* Reference::get_id()
516 if (!id
) detect_modid();
520 Type
*Reference::chk_variable_ref()
522 Common::Assignment
*t_ass
= get_refd_assignment();
523 if (!t_ass
) return 0;
524 switch (t_ass
->get_asstype()) {
525 case Common::Assignment::A_PAR_VAL_IN
:
526 t_ass
->use_as_lvalue(*this);
528 case Common::Assignment::A_VAR
:
529 case Common::Assignment::A_PAR_VAL_OUT
:
530 case Common::Assignment::A_PAR_VAL_INOUT
:
533 error("Reference to a variable or value parameter was "
534 "expected instead of %s", t_ass
->get_description().c_str());
537 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
538 Type
*ret_val
= t_ass
->get_Type()->get_field_type(t_subrefs
,
539 Type::EXPECTED_DYNAMIC_VALUE
);
540 if (ret_val
&& t_subrefs
&& t_subrefs
->refers_to_string_element()) {
541 error("Reference to a string element of type `%s' cannot be used in "
542 "this context", ret_val
->get_typename().c_str());
547 Type
*Reference::chk_comptype_ref()
549 Common::Assignment
*ass
= get_refd_assignment();
551 if (ass
->get_asstype() == Common::Assignment::A_TYPE
) {
552 Type
*t
= ass
->get_Type()->get_type_refd_last();
553 switch (t
->get_typetype()) {
557 case Type::T_COMPONENT
:
560 error("Reference `%s' does not refer to a component type",
561 get_dispname().c_str());
564 error("Reference `%s' does not refer to a type",
565 get_dispname().c_str());
571 bool Reference::has_single_expr()
573 if (!Ref_base::has_single_expr()) {
576 if (parlist
!= NULL
) {
577 for (size_t i
= 0; i
< parlist
->get_nof_pars(); i
++) {
578 if (!parlist
->get_par(i
)->has_single_expr()) {
586 void Reference::generate_code(expression_struct_t
*expr
)
588 Common::Assignment
*ass
= get_refd_assignment();
589 if (!ass
) FATAL_ERROR("Reference::generate_code()");
591 // reference without parameters to a template that has only default formal parameters.
592 // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
593 expr
->expr
= mputprintf(expr
->expr
, "%s(",
594 ass
->get_genname_from_scope(my_scope
).c_str());
595 parlist
->generate_code_alias(expr
, ass
->get_FormalParList(),
596 ass
->get_RunsOnType(), false);
597 expr
->expr
= mputc(expr
->expr
, ')');
599 expr
->expr
= mputstr(expr
->expr
,
600 LazyParamData::in_lazy() ?
601 LazyParamData::add_ref_genname(ass
, my_scope
).c_str() :
602 ass
->get_genname_from_scope(my_scope
).c_str());
604 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
607 void Reference::generate_code_const_ref(expression_struct_t
*expr
)
609 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
610 if (!t_subrefs
|| t_subrefs
->get_nof_refs() == 0) {
615 Common::Assignment
*ass
= get_refd_assignment();
616 if (!ass
) FATAL_ERROR("Reference::generate_code_const_ref()");
619 switch (ass
->get_asstype()) {
620 case Common::Assignment::A_MODULEPAR
:
621 case Common::Assignment::A_VAR
:
622 case Common::Assignment::A_FUNCTION_RVAL
:
623 case Common::Assignment::A_EXT_FUNCTION_RVAL
:
624 case Common::Assignment::A_PAR_VAL_IN
:
625 case Common::Assignment::A_PAR_VAL_OUT
:
626 case Common::Assignment::A_PAR_VAL_INOUT
: {
629 case Common::Assignment::A_MODULEPAR_TEMP
:
630 case Common::Assignment::A_TEMPLATE
:
631 case Common::Assignment::A_VAR_TEMPLATE
:
632 case Common::Assignment::A_PAR_TEMPL_IN
:
633 case Common::Assignment::A_PAR_TEMPL_OUT
:
634 case Common::Assignment::A_PAR_TEMPL_INOUT
: {
637 case Common::Assignment::A_CONST
:
638 case Common::Assignment::A_EXT_CONST
:
644 Type
*refd_gov
= ass
->get_Type();
646 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
647 refd_gov
->get_genname_template(get_my_scope()).c_str() );
649 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
650 refd_gov
->get_genname_value(get_my_scope()).c_str());
653 // reference without parameters to a template that has only default formal parameters.
654 // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
655 expr
->expr
= mputprintf(expr
->expr
, "%s(",
656 ass
->get_genname_from_scope(my_scope
).c_str());
657 parlist
->generate_code_alias(expr
, ass
->get_FormalParList(),
658 ass
->get_RunsOnType(), false);
659 expr
->expr
= mputc(expr
->expr
, ')');
661 expr
->expr
= mputstr(expr
->expr
,
662 LazyParamData::in_lazy() ?
663 LazyParamData::add_ref_genname(ass
, my_scope
).c_str() :
664 ass
->get_genname_from_scope(my_scope
).c_str());
666 expr
->expr
= mputstr(expr
->expr
, ")");
668 if (t_subrefs
&& t_subrefs
->get_nof_refs() > 0)
669 t_subrefs
->generate_code(expr
, ass
);
672 void Reference::generate_code_portref(expression_struct_t
*expr
,
675 Common::Assignment
*ass
= get_refd_assignment();
676 if (!ass
) FATAL_ERROR("Reference::generate_code_portref()");
677 expr
->expr
= mputstr(expr
->expr
,
678 ass
->get_genname_from_scope(p_scope
).c_str());
679 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
683 void Reference::generate_code_ispresentbound(expression_struct_t
*expr
,
684 bool is_template
, const bool isbound
)
686 Common::Assignment
*ass
= get_refd_assignment();
687 const string
& ass_id
= ass
->get_genname_from_scope(my_scope
);
688 const char *ass_id_str
= ass_id
.c_str();
690 if (subrefs
.get_nof_refs() > 0) {
691 const string
& tmp_generalid
= my_scope
->get_scope_mod_gen()
692 ->get_temporary_id();
693 const char *tmp_generalid_str
= tmp_generalid
.c_str();
695 expression_struct isbound_expr
;
696 Code::init_expr(&isbound_expr
);
697 isbound_expr
.preamble
= mputprintf(isbound_expr
.preamble
,
698 "boolean %s = %s.is_bound();\n", tmp_generalid_str
,
700 ass
->get_Type()->generate_code_ispresentbound(&isbound_expr
, &subrefs
, my_scope
->get_scope_mod_gen(),
701 tmp_generalid
, ass_id
, is_template
, isbound
);
703 expr
->preamble
= mputstr(expr
->preamble
, isbound_expr
.preamble
);
704 expr
->preamble
= mputstr(expr
->preamble
, isbound_expr
.expr
);
705 Code::free_expr(&isbound_expr
);
707 expr
->expr
= mputprintf(expr
->expr
, "%s", tmp_generalid_str
);
709 expr
->expr
= mputprintf(expr
->expr
, "%s.%s()", ass_id_str
, isbound
? "is_bound":"is_present");
713 void Reference::detect_modid()
715 // do nothing if detection is already performed
717 // the first element of subrefs must be an <id>
718 const Identifier
*first_id
= subrefs
.get_ref(0)->get_id(), *second_id
= 0;
719 if (subrefs
.get_nof_refs() > 1) {
720 FieldOrArrayRef
*second_ref
= subrefs
.get_ref(1);
721 if (second_ref
->get_type() == FieldOrArrayRef::FIELD_REF
) {
722 // the reference begins with <id>.<id> (most complicated case)
723 // there are 3 possible situations:
724 // 1. first_id points to a local definition (this has the priority)
725 // modid: 0, id: first_id
726 // 2. first_id points to an imported module (trivial case)
727 // modid: first_id, id: second_id
728 // 3. none of the above (first_id might be an imported symbol)
729 // modid: 0, id: first_id
730 // Note: Rule 1 has the priority because it can be overridden using
731 // the notation <id>.objid { ... }.<id> (modid and id are set in the
732 // constructor), but there is no work-around in the reverse way.
733 if (!my_scope
->has_ass_withId(*first_id
)
734 && my_scope
->is_valid_moduleid(*first_id
)) {
735 // rule 1 is not fulfilled, but rule 2 is fulfilled
736 second_id
= second_ref
->get_id();
738 } // else: the reference begins with <id>[<arrayref>] -> there is no modid
739 } // else: the reference consists of a single <id> -> there is no modid
741 modid
= first_id
->clone();
742 id
= second_id
->clone();
743 subrefs
.remove_refs(2);
746 id
= first_id
->clone();
747 subrefs
.remove_refs(1);
751 // =================================
753 // =================================
755 Ref_pard::Ref_pard(const Ref_pard
& p
)
756 : Ref_base(p
), parlist(p
.parlist
), expr_cache(0)
758 params
= p
.params
? p
.params
->clone() : 0;
761 Ref_pard::Ref_pard(Identifier
*p_modid
, Identifier
*p_id
,
762 ParsedActualParameters
*p_params
)
763 : Ref_base(p_modid
, p_id
), parlist(), params(p_params
), expr_cache(0)
766 FATAL_ERROR("Ttcn::Ref_pard::Ref_pard(): NULL parameter");
769 Ref_pard::~Ref_pard()
775 Ref_pard
*Ref_pard::clone() const
777 return new Ref_pard(*this);
780 void Ref_pard::set_fullname(const string
& p_fullname
)
782 Ref_base::set_fullname(p_fullname
);
783 parlist
.set_fullname(p_fullname
);
784 if (params
) params
->set_fullname(p_fullname
);
787 void Ref_pard::set_my_scope(Scope
*p_scope
)
789 Ref_base::set_my_scope(p_scope
);
790 parlist
.set_my_scope(p_scope
);
791 if (params
) params
->set_my_scope(p_scope
);
794 string
Ref_pard::get_dispname()
796 if (is_erroneous
) return string("erroneous");
799 ret_val
+= modid
->get_dispname();
802 ret_val
+= id
->get_dispname();
804 if (params_checked
) {
805 // used after semantic analysis
806 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++) {
807 if (i
> 0) ret_val
+= ", ";
808 parlist
.get_par(i
)->append_stringRepr(ret_val
);
811 // used before semantic analysis
812 for (size_t i
= 0; i
< params
->get_nof_tis(); i
++) {
813 if (i
> 0) ret_val
+= ", ";
814 params
->get_ti_byIndex(i
)->append_stringRepr(ret_val
);
818 subrefs
.append_stringRepr(ret_val
);
822 Common::Assignment
* Ref_pard::get_refd_assignment(bool check_parlist
)
824 Common::Assignment
*ass
= Ref_base::get_refd_assignment(check_parlist
);
825 if (ass
&& check_parlist
&& !params_checked
) {
826 params_checked
= true;
827 FormalParList
*fplist
= ass
->get_FormalParList();
829 Error_Context
cntxt(params
, "In actual parameter list of %s",
830 ass
->get_description().c_str());
831 is_erroneous
= fplist
->fold_named_and_chk(params
, &parlist
);
832 parlist
.set_fullname(get_fullname());
833 parlist
.set_my_scope(my_scope
);
834 // the parsed parameter list is no longer needed
838 params
->error("The referenced %s cannot have actual parameters",
839 ass
->get_description().c_str());
845 const Identifier
* Ref_pard::get_modid()
850 const Identifier
* Ref_pard::get_id()
855 ActualParList
*Ref_pard::get_parlist()
857 if (!params_checked
) FATAL_ERROR("Ref_pard::get_parlist()");
861 bool Ref_pard::chk_activate_argument()
863 Common::Assignment
*t_ass
= get_refd_assignment();
864 if (!t_ass
) return false;
865 if (t_ass
->get_asstype() != Common::Assignment::A_ALTSTEP
) {
866 error("Reference to an altstep was expected in the argument instead of "
867 "%s", t_ass
->get_description().c_str());
870 my_scope
->chk_runs_on_clause(t_ass
, *this, "activate");
871 // the altstep reference cannot have sub-references
872 if (get_subrefs()) FATAL_ERROR("Ref_pard::chk_activate_argument()");
873 FormalParList
*fp_list
= t_ass
->get_FormalParList();
874 // the altstep must have formal parameter list
875 if (!fp_list
) FATAL_ERROR("Ref_pard::chk_activate_argument()");
876 return fp_list
->chk_activate_argument(&parlist
,
877 t_ass
->get_description().c_str());
880 bool Ref_pard::has_single_expr()
882 if (!Ref_base::has_single_expr()) return false;
883 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++)
884 if (!parlist
.get_par(i
)->has_single_expr()) return false;
885 // if any formal parameter has lazy evaluation
886 Common::Assignment
*ass
= get_refd_assignment();
888 const FormalParList
*fplist
= ass
->get_FormalParList();
890 size_t num_formal
= fplist
->get_nof_fps();
891 for (size_t i
=0; i
<num_formal
; ++i
) {
892 const FormalPar
*fp
= fplist
->get_fp_byIndex(i
);
893 if (fp
->get_lazy_eval()) return false;
900 void Ref_pard::set_code_section(
901 GovernedSimple::code_section_t p_code_section
)
903 Ref_base::set_code_section(p_code_section
);
904 for (size_t i
= 0; i
< parlist
.get_nof_pars(); i
++)
905 parlist
.get_par(i
)->set_code_section(p_code_section
);
908 void Ref_pard::generate_code(expression_struct_t
*expr
)
910 Common::Assignment
*ass
= get_refd_assignment();
911 // C++ function reference with actual parameter list
912 expr
->expr
= mputprintf(expr
->expr
, "%s(",
913 ass
->get_genname_from_scope(my_scope
).c_str());
914 parlist
.generate_code_alias(expr
, ass
->get_FormalParList(),
915 ass
->get_RunsOnType(),false);
916 expr
->expr
= mputc(expr
->expr
, ')');
918 if (subrefs
.get_nof_refs() > 0) subrefs
.generate_code(expr
, ass
);
921 void Ref_pard::generate_code_cached(expression_struct_t
*expr
)
924 expr
->expr
= mputstr(expr
->expr
, expr_cache
);
928 expr_cache
= mputstr(expr_cache
, expr
->expr
);
932 void Ref_pard::generate_code_const_ref(expression_struct_t
*expr
)
934 FieldOrArrayRefs
*t_subrefs
= get_subrefs();
935 if (!t_subrefs
|| t_subrefs
->get_nof_refs() == 0) {
940 Common::Assignment
*ass
= get_refd_assignment();
941 if (!ass
) FATAL_ERROR("Ref_pard::generate_code_const_ref()");
944 switch (ass
->get_asstype()) {
945 case Common::Assignment::A_CONST
:
946 case Common::Assignment::A_EXT_CONST
:
947 case Common::Assignment::A_ALTSTEP
:
948 case Common::Assignment::A_TESTCASE
:
949 case Common::Assignment::A_FUNCTION
:
950 case Common::Assignment::A_EXT_FUNCTION
:
953 case Common::Assignment::A_MODULEPAR
:
954 case Common::Assignment::A_VAR
:
955 case Common::Assignment::A_FUNCTION_RVAL
:
956 case Common::Assignment::A_EXT_FUNCTION_RVAL
:
957 case Common::Assignment::A_PAR_VAL_IN
:
958 case Common::Assignment::A_PAR_VAL_OUT
:
959 case Common::Assignment::A_PAR_VAL_INOUT
: {
962 case Common::Assignment::A_MODULEPAR_TEMP
:
963 case Common::Assignment::A_TEMPLATE
:
964 case Common::Assignment::A_VAR_TEMPLATE
:
965 case Common::Assignment::A_FUNCTION_RTEMP
:
966 case Common::Assignment::A_EXT_FUNCTION_RTEMP
:
967 case Common::Assignment::A_PAR_TEMPL_IN
:
968 case Common::Assignment::A_PAR_TEMPL_OUT
:
969 case Common::Assignment::A_PAR_TEMPL_INOUT
: {
977 Type
*refd_gov
= ass
->get_Type();
984 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s&>(",
985 refd_gov
->get_genname_template(get_my_scope()).c_str() );
987 expr
->expr
= mputprintf(expr
->expr
, "const_cast< const %s%s&>(",
988 refd_gov
->get_genname_value(get_my_scope()).c_str(),
989 is_template
? "_template":"");
992 expr
->expr
= mputprintf(expr
->expr
, "%s(",
993 ass
->get_genname_from_scope(my_scope
).c_str());
994 parlist
.generate_code_alias(expr
, ass
->get_FormalParList(),
995 ass
->get_RunsOnType(), false);
996 expr
->expr
= mputstr(expr
->expr
, "))");
998 t_subrefs
->generate_code(expr
, ass
);
1001 // =================================
1002 // ===== NameBridgingScope
1003 // =================================
1004 string
NameBridgingScope::get_scopeMacro_name() const
1006 if (scopeMacro_name
.empty()) FATAL_ERROR("NameBridgingScope::get_scopeMacro_name()");
1007 return scopeMacro_name
;
1010 NameBridgingScope
*NameBridgingScope::clone() const
1012 FATAL_ERROR("NameBridgingScope::clone");
1015 Common::Assignment
* NameBridgingScope::get_ass_bySRef(Ref_simple
*p_ref
)
1017 return get_parent_scope()->get_ass_bySRef(p_ref
);
1020 // =================================
1021 // ===== RunsOnScope
1022 // =================================
1024 RunsOnScope::RunsOnScope(Type
*p_comptype
)
1025 : Scope(), component_type(p_comptype
)
1027 if (!p_comptype
|| p_comptype
->get_typetype() != Type::T_COMPONENT
)
1028 FATAL_ERROR("RunsOnScope::RunsOnScope()");
1029 component_type
->set_ownertype(Type::OT_RUNSON_SCOPE
, this);
1030 component_defs
= p_comptype
->get_CompBody();
1031 set_scope_name("runs on `" + p_comptype
->get_fullname() + "'");
1034 RunsOnScope
*RunsOnScope::clone() const
1036 FATAL_ERROR("RunsOnScope::clone()");
1039 void RunsOnScope::chk_uniq()
1041 // do not perform this check if the component type is defined in the same
1042 // module as the 'runs on' clause
1043 if (parent_scope
->get_scope_mod() == component_defs
->get_scope_mod())
1045 size_t nof_defs
= component_defs
->get_nof_asss();
1046 for (size_t i
= 0; i
< nof_defs
; i
++) {
1047 Common::Assignment
*comp_def
= component_defs
->get_ass_byIndex(i
);
1048 const Identifier
& id
= comp_def
->get_id();
1049 if (parent_scope
->has_ass_withId(id
)) {
1050 comp_def
->warning("Imported component element definition `%s' hides a "
1051 "definition at module scope", comp_def
->get_fullname().c_str());
1052 Reference
ref(0, id
.clone());
1053 Common::Assignment
*hidden_ass
= parent_scope
->get_ass_bySRef(&ref
);
1054 hidden_ass
->warning("Hidden definition `%s' is here",
1055 hidden_ass
->get_fullname().c_str());
1061 RunsOnScope
*RunsOnScope::get_scope_runs_on()
1066 Common::Assignment
*RunsOnScope::get_ass_bySRef(Ref_simple
*p_ref
)
1068 if (!p_ref
) FATAL_ERROR("Ttcn::RunsOnScope::get_ass_bySRef()");
1069 if (p_ref
->get_modid()) return parent_scope
->get_ass_bySRef(p_ref
);
1071 const Identifier
& id
= *p_ref
->get_id();
1072 if (component_defs
->has_local_ass_withId(id
)) {
1073 Common::Assignment
* ass
= component_defs
->get_local_ass_byId(id
);
1074 if (!ass
) FATAL_ERROR("Ttcn::RunsOnScope::get_ass_bySRef()");
1076 if (component_defs
->is_own_assignment(ass
)) return ass
;
1077 else if (ass
->get_visibility() == PUBLIC
) {
1081 p_ref
->error("The member definition `%s' in component type `%s'"
1082 " is not visible in this scope", id
.get_dispname().c_str(),
1083 component_defs
->get_id()->get_dispname().c_str());
1085 } else return parent_scope
->get_ass_bySRef(p_ref
);
1089 bool RunsOnScope::has_ass_withId(const Identifier
& p_id
)
1091 return component_defs
->has_ass_withId(p_id
)
1092 || parent_scope
->has_ass_withId(p_id
);
1095 // =================================
1097 // =================================
1099 FriendMod::FriendMod(Identifier
*p_modid
)
1100 : Node(), modid(p_modid
), w_attrib_path(0), parentgroup(0), checked(false)
1102 if (!p_modid
) FATAL_ERROR("NULL parameter: Ttcn::FriendMod::FriendMod()");
1103 set_fullname("<friends>."+modid
->get_dispname());
1106 FriendMod::~FriendMod()
1110 delete w_attrib_path
;
1113 FriendMod
*FriendMod::clone() const
1115 FATAL_ERROR("Ttcn::FriendMod::clone()");
1118 void FriendMod::set_fullname(const string
& p_fullname
)
1120 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
1123 void FriendMod::chk()
1125 if (checked
) return;
1127 Error_Context
cntxt(this, "In friend module declaration");
1129 if (w_attrib_path
) {
1130 w_attrib_path
->chk_global_attrib();
1131 w_attrib_path
->chk_no_qualif();
1137 void FriendMod::set_with_attr(MultiWithAttrib
* p_attrib
)
1139 if (w_attrib_path
) FATAL_ERROR("FriendMod::set_with_attr()");
1140 w_attrib_path
= new WithAttribPath();
1141 if (p_attrib
&& p_attrib
->get_nof_elements() > 0) {
1142 w_attrib_path
->set_with_attr(p_attrib
);
1146 WithAttribPath
* FriendMod::get_attrib_path()
1148 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1149 return w_attrib_path
;
1152 void FriendMod::set_parent_path(WithAttribPath
* p_path
)
1154 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1155 w_attrib_path
->set_parent(p_path
);
1158 void FriendMod::set_parent_group(Group
* p_group
)
1160 if(parentgroup
) FATAL_ERROR("FriendMod::set_parent_group");
1161 parentgroup
= p_group
;
1164 // =================================
1166 // =================================
1168 ImpMod::ImpMod(Identifier
*p_modid
)
1169 : Node(), mod(0), my_mod(0), imptype(I_UNDEF
), modid(p_modid
),
1170 language_spec(0), is_recursive(false),
1171 w_attrib_path(0), parentgroup(0), visibility(PRIVATE
)
1173 if (!p_modid
) FATAL_ERROR("NULL parameter: Ttcn::ImpMod::ImpMod()");
1174 set_fullname("<imports>." + modid
->get_dispname());
1180 delete language_spec
;
1182 delete w_attrib_path
;
1185 ImpMod
*ImpMod::clone() const
1187 FATAL_ERROR("No clone for you!");
1190 void ImpMod::set_fullname(const string
& p_fullname
)
1192 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
1197 if (w_attrib_path
) {
1198 w_attrib_path
->chk_global_attrib();
1199 w_attrib_path
->chk_no_qualif();
1203 void ImpMod::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
1205 Error_Context
cntxt(this, "In import definition");
1207 if (!modules
->has_mod_withId(*modid
)) {
1208 error("There is no module with identifier `%s'",
1209 modid
->get_dispname().c_str());
1213 Common::Module
*m
= modules
->get_mod_byId(*modid
);
1219 error("A module cannot import from itself");
1227 if (refch
.exists(my_mod
->get_fullname())) {
1228 if(my_mod
->get_moduletype()!=Common::Module::MOD_ASN
){ // Do not warning for circular import in ASN.1 module. It is legal
1229 my_mod
->warning("Circular import chain is not recommended: %s",
1230 refch
.get_dispstr(my_mod
->get_fullname()).c_str());
1235 refch
.add(my_mod
->get_fullname());
1237 if (ImpMod::I_IMPORTIMPORT
== imptype
){
1238 Ttcn::Module
* ttcnmodule
=static_cast<Ttcn::Module
*>(m
);
1239 const Imports
& imp
= ttcnmodule
->get_imports();
1241 for (size_t t
= 0; t
< imp
.impmods_v
.size(); t
++) {
1242 const ImpMod
*im
= imp
.impmods_v
[t
];
1243 const Identifier
& im_id
= im
->get_modid();
1244 Common::Module
*cm
= modules
->get_mod_byId(im_id
); // never NULL
1247 if (PRIVATE
!= im
->get_visibility()) {
1248 if (refch
.exists(m
->get_fullname())) {
1249 if(m
->get_moduletype()!=Common::Module::MOD_ASN
){ // Do not warning for circular import in ASN.1 module. It is legal
1250 m
->warning("Circular import chain is not recommended: %s",
1251 refch
.get_dispstr(m
->get_fullname()).c_str());
1256 refch
.add(m
->get_fullname());
1257 cm
->chk_imp(refch
, moduleStack
);
1263 //refch.mark_state();
1264 m
->chk_imp(refch
, moduleStack
);
1265 //refch.prev_state();
1270 size_t state
=moduleStack
.size();
1271 moduleStack
.replace(state
, moduleStack
.size() - state
);
1274 bool ImpMod::has_imported_def(const Identifier
& p_source_modid
,
1275 const Identifier
& p_id
, const Location
*loc
) const
1277 if (!mod
) return false;
1283 Common::Assignment
* return_assignment
= mod
->importAssignment(p_source_modid
, p_id
);
1284 if (return_assignment
!= NULL
) {
1291 case I_IMPORTIMPORT
:
1293 Ttcn::Module
*tm
= static_cast<Ttcn::Module
*>(mod
); // B
1295 const Imports
& imps
= tm
->get_imports();
1297 vector
<ImpMod
> tempusedImpMods
;
1298 for (size_t i
= 0, num
= imps
.impmods_v
.size(); i
< num
; ++i
) {
1299 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
1300 Common::Assignment
* return_assignment
= imps
.impmods_v
[i
]->
1301 get_imported_def(p_source_modid
, p_id
, loc
, referencechain
, tempusedImpMods
); // C
1302 referencechain
->reset();
1303 delete referencechain
;
1305 if (return_assignment
!= NULL
) {
1311 //satisfy destructor
1312 tempusedImpMods
.clear();
1317 FATAL_ERROR("ImpMod::get_imported_def");
1323 Common::Assignment
*ImpMod::get_imported_def(
1324 const Identifier
& p_source_modid
, const Identifier
& p_id
,
1325 const Location
*loc
, ReferenceChain
* refch
,
1326 vector
<ImpMod
>& usedImpMods
) const
1331 Common::Assignment
* result
= NULL
;
1336 result
= mod
->importAssignment(p_source_modid
, p_id
);
1337 if (result
!= NULL
) {
1338 usedImpMods
.add(const_cast<Ttcn::ImpMod
*>(this));
1342 case I_IMPORTIMPORT
:
1344 Ttcn::Module
*tm
= static_cast<Ttcn::Module
*>(mod
);
1346 const Imports
& imps
= tm
->get_imports();
1347 Common::Assignment
* t_ass
= NULL
;
1349 for (size_t i
= 0, num
= imps
.impmods_v
.size(); i
< num
; ++i
) {
1350 vector
<ImpMod
> tempusedImpMods
;
1352 refch
->mark_state();
1353 if (imps
.impmods_v
[i
]->get_visibility() == PUBLIC
) {
1354 t_ass
= imps
.impmods_v
[i
]->get_imported_def(p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1356 else if (imps
.impmods_v
[i
]->get_visibility() == FRIEND
) {
1357 t_ass
= imps
.impmods_v
[i
]->get_imported_def(p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1359 tempusedImpMods
.add(imps
.impmods_v
[i
]);
1362 refch
->prev_state();
1364 if (t_ass
!= NULL
) {
1365 bool visible
= true;
1366 for (size_t j
= 0; j
< tempusedImpMods
.size(); j
++) {
1367 ImpMod
* impmod_l
= tempusedImpMods
[j
];
1368 //check whether the module is TTCN
1369 if (impmod_l
->get_mod()->get_moduletype() == Common::Module::MOD_TTCN
) {
1370 // cast to ttcn module
1371 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(impmod_l
->get_mod());
1372 if (!ttcn_m
->is_visible(mod
->get_modid(), impmod_l
->get_visibility())) {
1378 for (size_t t
= 0; i
< tempusedImpMods
.size(); i
++) {
1379 usedImpMods
.add(tempusedImpMods
[t
]);
1384 } else if(result
!= t_ass
) {
1389 "It is not possible to resolve the reference unambigously"
1390 ", as it can be resolved to `%s' and to `%s'",
1391 result
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
1397 tempusedImpMods
.clear();
1400 if (result
!= NULL
) {
1401 usedImpMods
.add(const_cast<Ttcn::ImpMod
*>(this));
1407 FATAL_ERROR("ImpMod::get_imported_def");
1412 void ImpMod::set_language_spec(const char *p_language_spec
)
1414 if (language_spec
) FATAL_ERROR("ImpMod::set_language_spec()");
1415 if (p_language_spec
) language_spec
= new string(p_language_spec
);
1418 void ImpMod::generate_code(output_struct
*target
)
1420 const char *module_name
= modid
->get_name().c_str();
1422 target
->header
.includes
= mputprintf(target
->header
.includes
,
1423 "#include \"%s.hh\"\n",
1424 duplicate_underscores
? module_name
: modid
->get_ttcnname().c_str());
1426 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
1427 "%s%s.pre_init_module();\n", module_name
,
1430 if (mod
->get_moduletype() == Common::Module::MOD_TTCN
) {
1431 target
->functions
.post_init
= mputprintf(target
->functions
.post_init
,
1432 "%s%s.post_init_module();\n", module_name
,
1438 void ImpMod::dump(unsigned level
) const
1440 DEBUG(level
, "Import from module %s", modid
->get_dispname().c_str());
1441 if (w_attrib_path
) {
1442 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
1444 DEBUG(level
+ 1, "Attributes:");
1445 attrib
->dump(level
+ 2);
1450 void ImpMod::set_with_attr(MultiWithAttrib
* p_attrib
)
1452 if (w_attrib_path
) FATAL_ERROR("ImpMod::set_with_attr()");
1453 w_attrib_path
= new WithAttribPath();
1454 if (p_attrib
&& p_attrib
->get_nof_elements() > 0) {
1455 w_attrib_path
->set_with_attr(p_attrib
);
1459 WithAttribPath
* ImpMod::get_attrib_path()
1461 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1462 return w_attrib_path
;
1465 void ImpMod::set_parent_path(WithAttribPath
* p_path
)
1467 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1468 w_attrib_path
->set_parent(p_path
);
1471 void ImpMod::set_parent_group(Group
* p_group
)
1473 if(parentgroup
) FATAL_ERROR("ImpMod::set_parent_group");
1474 parentgroup
= p_group
;
1477 // =================================
1479 // =================================
1483 for (size_t i
= 0; i
< impmods_v
.size(); i
++)
1484 delete impmods_v
[i
];
1488 Imports
*Imports::clone() const
1490 FATAL_ERROR("Ttcn::Imports::clone()");
1493 void Imports::add_impmod(ImpMod
*p_impmod
)
1495 if (!p_impmod
) FATAL_ERROR("Ttcn::Imports::add_impmod()");
1496 impmods_v
.add(p_impmod
);
1497 p_impmod
->set_my_mod(my_mod
);
1500 void Imports::set_my_mod(Module
*p_mod
)
1503 for(size_t i
= 0; i
< impmods_v
.size(); i
++)
1504 impmods_v
[i
]->set_my_mod(my_mod
);
1507 bool Imports::has_impmod_withId(const Identifier
& p_id
) const
1509 for (size_t i
= 0, size
= impmods_v
.size(); i
< size
; ++i
) {
1510 const ImpMod
* im
= impmods_v
[i
];
1511 const Identifier
& im_id
= im
->get_modid();
1512 const string
& im_name
= im_id
.get_name();
1513 if (p_id
.get_name() == im_name
) {
1514 // The identifier represents a module imported in the current module
1521 void Imports::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
1523 if (impmods_v
.size() <= 0) return;
1525 if (!my_mod
) FATAL_ERROR("Ttcn::Imports::chk_imp()");
1530 for(size_t n
= 0; n
< impmods_v
.size(); n
++)
1532 impmods_v
[n
]->chk();
1535 //TODO this whole thing should be moved into impmod::chk
1536 Identifier
address_id(Identifier::ID_TTCN
, string("address"));
1537 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1538 ImpMod
*im
= impmods_v
[n
];
1539 im
->chk_imp(refch
, moduleStack
);
1541 const Identifier
& im_id
= im
->get_modid();
1542 Common::Module
*m
= modules
->get_mod_byId(im_id
);
1545 if (m
->get_gen_code()) my_mod
->set_gen_code();
1546 } // next assignment
1549 bool Imports::has_imported_def(const Identifier
& p_id
, const Location
*loc
) const
1551 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1552 ImpMod
*im
= impmods_v
[n
];
1553 bool return_bool
= im
->has_imported_def(my_mod
->get_modid(), p_id
, loc
);
1554 if (return_bool
) return true;
1559 Common::Assignment
*Imports::get_imported_def(
1560 const Identifier
& p_source_modid
, const Identifier
& p_id
,
1561 const Location
*loc
, ReferenceChain
* refch
)
1563 vector
<ImpMod
> tempusedImpMods
;
1564 Common::Assignment
* result
= NULL
;
1565 for (size_t n
= 0; n
< impmods_v
.size(); n
++) {
1566 ImpMod
*im
= impmods_v
[n
];
1567 refch
->mark_state();
1568 Common::Assignment
* ass
= im
->get_imported_def(
1569 p_source_modid
, p_id
, loc
, refch
, tempusedImpMods
);
1570 tempusedImpMods
.clear();
1571 refch
->prev_state();
1576 } else if(result
!= ass
&& loc
) {
1581 "It is not possible to resolve the reference unambigously"
1582 ", as it can be resolved to `%s' and to `%s'",
1583 result
->get_fullname().c_str(), ass
->get_fullname().c_str());
1591 void Imports::get_imported_mods(Module::module_set_t
& p_imported_mods
) const
1593 for (size_t i
= 0; i
< impmods_v
.size(); i
++) {
1594 ImpMod
*im
= impmods_v
[i
];
1595 Common::Module
*m
= im
->get_mod();
1597 if (!p_imported_mods
.has_key(m
)) {
1598 p_imported_mods
.add(m
, 0);
1599 m
->get_visible_mods(p_imported_mods
);
1604 void Imports::generate_code(output_struct
*target
)
1606 bool base_lib_needed
= true;
1607 for (size_t i
= 0; i
< impmods_v
.size(); i
++) {
1608 ImpMod
*im
= impmods_v
[i
];
1609 Common::Module
*m
= im
->get_mod();
1610 // do not include the header file of the base library if a real
1611 // (not circular) imported module is found
1612 if (base_lib_needed
&& !m
->is_visible(my_mod
)) base_lib_needed
= false;
1613 // inclusion of m's header file can be eliminated if we find another
1614 // imported module that imports m
1615 bool covered
= false;
1616 for (size_t j
= 0; j
< impmods_v
.size(); j
++) {
1617 // skip over the same import definition
1618 if (j
== i
) continue;
1619 ImpMod
*im2
= impmods_v
[j
];
1620 Common::Module
*m2
= im2
->get_mod();
1621 // a module that is equivalent to the current module due to
1622 // circular imports cannot be used to cover anything
1623 if (m2
->is_visible(my_mod
)) continue;
1624 if (m2
->is_visible(m
) && !m
->is_visible(m2
)) {
1625 // m2 covers m (i.e. m is visible from m2)
1626 // and they are not in the same import loop
1631 // do not generate the #include if a covering module is found
1632 if (!covered
) im
->generate_code(target
);
1634 if (base_lib_needed
) {
1635 // if no real import was found the base library definitions has to be
1637 target
->header
.includes
= mputstr(target
->header
.includes
,
1638 "#include <TTCN3.hh>\n");
1642 void Imports::generate_code(CodeGenHelper
& cgh
) {
1643 generate_code(cgh
.get_current_outputstruct());
1646 void Imports::dump(unsigned level
) const
1648 DEBUG(level
, "Imports (%lu pcs.)", (unsigned long) impmods_v
.size());
1649 for (size_t i
= 0; i
< impmods_v
.size(); i
++)
1650 impmods_v
[i
]->dump(level
+ 1);
1653 // =================================
1654 // ===== Definitions
1655 // =================================
1657 Definitions::~Definitions()
1659 for(size_t i
= 0; i
< ass_v
.size(); i
++) delete ass_v
[i
];
1664 Definitions
*Definitions::clone() const
1666 FATAL_ERROR("Definitions::clone");
1669 void Definitions::add_ass(Definition
*p_ass
)
1671 // it is too late to add a new one after it has been checked.
1672 if (checked
|| !p_ass
) FATAL_ERROR("Ttcn::OtherDefinitions::add_ass()");
1674 p_ass
->set_my_scope(this);
1677 void Definitions::set_fullname(const string
& p_fullname
)
1679 Common::Assignments::set_fullname(p_fullname
);
1680 for(size_t i
= 0; i
< ass_v
.size(); i
++) {
1681 Definition
*ass
= ass_v
[i
];
1682 ass
->set_fullname(p_fullname
+ "." + ass
->get_id().get_dispname());
1686 bool Definitions::has_local_ass_withId(const Identifier
& p_id
)
1688 if (!checked
) chk_uniq();
1689 return ass_m
.has_key(p_id
.get_name());
1692 Common::Assignment
* Definitions::get_local_ass_byId(const Identifier
& p_id
)
1694 if (!checked
) chk_uniq();
1695 return ass_m
[p_id
.get_name()];
1698 size_t Definitions::get_nof_asss()
1700 if (!checked
) chk_uniq();
1701 return ass_m
.size();
1704 size_t Definitions::get_nof_raw_asss()
1706 return ass_v
.size();
1709 Common::Assignment
* Definitions::get_ass_byIndex(size_t p_i
)
1711 if (!checked
) chk_uniq();
1712 return ass_m
.get_nth_elem(p_i
);
1715 Ttcn::Definition
* Definitions::get_raw_ass_byIndex(size_t p_i
) {
1719 void Definitions::chk_uniq()
1721 if (checked
) return;
1723 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1724 Definition
*ass
= ass_v
[i
];
1725 const Identifier
& id
= ass
->get_id();
1726 const string
& name
= id
.get_name();
1727 if (ass_m
.has_key(name
)) {
1728 const char *dispname_str
= id
.get_dispname().c_str();
1729 ass
->error("Duplicate definition with name `%s'", dispname_str
);
1730 ass_m
[name
]->note("Previous definition of `%s' is here", dispname_str
);
1732 ass_m
.add(name
, ass
);
1733 if (parent_scope
->is_valid_moduleid(id
)) {
1734 ass
->warning("Definition with name `%s' hides a module identifier",
1735 id
.get_dispname().c_str());
1742 void Definitions::chk()
1744 for (size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->chk();
1747 void Definitions::chk_for()
1749 if (checked
) return;
1752 // all checks are done in one iteration because
1753 // forward referencing is not allowed between the definitions
1754 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1755 Definition
*def
= ass_v
[i
];
1756 const Identifier
& id
= def
->get_id();
1757 const string
& name
= id
.get_name();
1758 if (ass_m
.has_key(name
)) {
1759 const char *dispname_str
= id
.get_dispname().c_str();
1760 def
->error("Duplicate definition with name `%s'", dispname_str
);
1761 ass_m
[name
]->note("Previous definition of `%s' is here", dispname_str
);
1763 ass_m
.add(name
, def
);
1765 if (parent_scope
->has_ass_withId(id
)) {
1766 const char *dispname_str
= id
.get_dispname().c_str();
1767 def
->error("Definition with identifier `%s' is not unique in the "
1768 "scope hierarchy", dispname_str
);
1769 Reference
ref(0, id
.clone());
1770 Common::Assignment
*ass
= parent_scope
->get_ass_bySRef(&ref
);
1771 if (!ass
) FATAL_ERROR("OtherDefinitions::chk_for()");
1772 ass
->note("Previous definition with identifier `%s' in higher "
1773 "scope unit is here", dispname_str
);
1774 } else if (parent_scope
->is_valid_moduleid(id
)) {
1775 def
->warning("Definition with name `%s' hides a module identifier",
1776 id
.get_dispname().c_str());
1784 void Definitions::set_genname(const string
& prefix
)
1786 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1787 Definition
*def
= ass_v
[i
];
1788 def
->set_genname(prefix
+ def
->get_id().get_name());
1792 void Definitions::generate_code(output_struct
* target
)
1794 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->generate_code(target
);
1797 void Definitions::generate_code(CodeGenHelper
& cgh
) {
1799 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->generate_code(cgh
);
1802 char* Definitions::generate_code_str(char *str
)
1804 for(size_t i
=0; i
<ass_v
.size(); i
++) {
1805 str
= ass_v
[i
]->update_location_object(str
);
1806 str
=ass_v
[i
]->generate_code_str(str
);
1811 void Definitions::ilt_generate_code(ILT
*ilt
)
1813 for(size_t i
=0; i
<ass_v
.size(); i
++)
1814 ass_v
[i
]->ilt_generate_code(ilt
);
1818 void Definitions::dump(unsigned level
) const
1820 DEBUG(level
, "Definitions: (%lu pcs.)", (unsigned long) ass_v
.size());
1821 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->dump(level
+ 1);
1824 // =================================
1826 // =================================
1828 Group::Group(Identifier
*p_id
)
1829 : Node(), Location(), parent_group(0), w_attrib_path(0), id(p_id
),
1832 if (!p_id
) FATAL_ERROR("Group::Group()");
1837 delete w_attrib_path
;
1840 for (size_t i
= 0; i
< group_v
.size(); i
++) delete group_v
[i
];
1844 friendmods_v
.clear();
1848 Group
* Group::clone() const
1850 FATAL_ERROR("Ttcn::Group::clone()");
1853 void Group::set_fullname(const string
& p_fullname
)
1855 Node::set_fullname(p_fullname
);
1856 for(size_t i
= 0; i
< group_v
.size() ; i
++)
1858 group_v
[i
]->set_fullname(p_fullname
+ ".<group " + Int2string(i
) + ">");
1860 if (w_attrib_path
) w_attrib_path
->set_fullname( p_fullname
1864 void Group::add_ass(Definition
* p_ass
)
1867 p_ass
->set_parent_group(this);
1870 void Group::add_group(Group
* p_group
)
1872 group_v
.add(p_group
);
1875 void Group::set_parent_group(Group
* p_parent_group
)
1877 if (parent_group
) FATAL_ERROR("Group::set_parent_group()");
1878 parent_group
= p_parent_group
;
1881 void Group::set_with_attr(MultiWithAttrib
* p_attrib
)
1883 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1884 w_attrib_path
->set_with_attr(p_attrib
);
1887 WithAttribPath
* Group::get_attrib_path()
1889 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1890 return w_attrib_path
;
1893 void Group::set_parent_path(WithAttribPath
* p_path
)
1895 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
1896 w_attrib_path
->set_parent(p_path
);
1899 void Group::chk_uniq()
1901 if (checked
) return;
1905 for (size_t i
= 0; i
< ass_v
.size(); i
++) {
1906 Definition
*ass
= ass_v
[i
];
1907 const string
& ass_name
= ass
->get_id().get_name();
1908 if (!ass_m
.has_key(ass_name
)) ass_m
.add(ass_name
, ass
);
1911 for(size_t i
= 0; i
< group_v
.size(); i
++) {
1912 Group
*group
= group_v
[i
];
1913 const Identifier
& group_id
= group
->get_id();
1914 const string
& group_name
= group_id
.get_name();
1915 if (ass_m
.has_key(group_name
)) {
1916 group
->error("Group name `%s' clashes with a definition",
1917 group_id
.get_dispname().c_str());
1918 ass_m
[group_name
]->note("Definition of `%s' is here",
1919 group_id
.get_dispname().c_str());
1921 if (group_m
.has_key(group_name
)) {
1922 group
->error("Duplicate group with name `%s'",
1923 group_id
.get_dispname().c_str());
1924 group_m
[group_name
]->note("Group `%s' is already defined here",
1925 group_id
.get_dispname().c_str());
1926 } else group_m
.add(group_name
, group
);
1933 Error_Context
cntxt(this, "In group `%s'", id
->get_dispname().c_str());
1937 if (w_attrib_path
) {
1938 w_attrib_path
->chk_global_attrib();
1939 w_attrib_path
->chk_no_qualif();
1942 for(size_t i
= 0; i
< group_v
.size(); i
++) group_v
[i
]->chk();
1945 void Group::add_impmod(ImpMod
*p_impmod
)
1947 impmods_v
.add(p_impmod
);
1948 p_impmod
->set_parent_group(this);
1951 void Group::add_friendmod(FriendMod
*p_friendmod
)
1953 friendmods_v
.add(p_friendmod
);
1954 p_friendmod
->set_parent_group(this);
1957 void Group::dump(unsigned level
) const
1959 DEBUG(level
, "Group: %s", id
->get_dispname().c_str());
1960 DEBUG(level
+ 1, "Nested groups: (%lu pcs.)",
1961 (unsigned long) group_v
.size());
1962 for(size_t i
= 0; i
< group_v
.size(); i
++) group_v
[i
]->dump(level
+ 2);
1963 DEBUG(level
+ 1, "Nested definitions: (%lu pcs.)",
1964 (unsigned long) ass_v
.size());
1965 for(size_t i
= 0; i
< ass_v
.size(); i
++) ass_v
[i
]->dump(level
+ 2);
1966 DEBUG(level
+ 1, "Nested imports: (%lu pcs.)",
1967 (unsigned long) impmods_v
.size());
1968 for(size_t i
= 0; i
< impmods_v
.size(); i
++) impmods_v
[i
]->dump(level
+ 2);
1969 if (w_attrib_path
) {
1970 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
1972 DEBUG(level
+ 1, "Group Attributes:");
1973 attrib
->dump(level
+ 2);
1978 // =================================
1979 // ===== ControlPart
1980 // =================================
1982 ControlPart::ControlPart(StatementBlock
* p_block
)
1983 : Node(), Location(), block(p_block
), w_attrib_path(0)
1985 if (!p_block
) FATAL_ERROR("ControlPart::ControlPart()");
1988 ControlPart::~ControlPart()
1991 delete w_attrib_path
;
1994 ControlPart
* ControlPart::clone() const
1996 FATAL_ERROR("ControlPart::clone");
1999 void ControlPart::set_fullname(const string
& p_fullname
)
2001 block
->set_fullname(p_fullname
);
2002 if(w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
2005 void ControlPart::set_my_scope(Scope
*p_scope
)
2007 bridgeScope
.set_parent_scope(p_scope
);
2008 string
temp("control");
2009 bridgeScope
.set_scopeMacro_name(temp
);
2011 block
->set_my_scope(&bridgeScope
);
2014 void ControlPart::chk()
2016 Error_Context
cntxt(this, "In control part");
2018 if (!semantic_check_only
)
2019 block
->set_code_section(GovernedSimple::CS_INLINE
);
2020 if (w_attrib_path
) {
2021 w_attrib_path
->chk_global_attrib();
2022 w_attrib_path
->chk_no_qualif();
2026 void ControlPart::generate_code(output_struct
*target
, Module
*my_module
)
2028 const char *module_dispname
= my_module
->get_modid().get_dispname().c_str();
2029 target
->functions
.control
=
2030 create_location_object(target
->functions
.control
, "CONTROLPART",
2032 target
->functions
.control
= mputprintf(target
->functions
.control
,
2033 "TTCN_Runtime::begin_controlpart(\"%s\");\n", module_dispname
);
2034 target
->functions
.control
=
2035 block
->generate_code(target
->functions
.control
);
2036 target
->functions
.control
= mputstr(target
->functions
.control
,
2037 "TTCN_Runtime::end_controlpart();\n");
2040 void ControlPart::set_with_attr(MultiWithAttrib
* p_attrib
)
2042 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2043 w_attrib_path
->set_with_attr(p_attrib
);
2046 WithAttribPath
* ControlPart::get_attrib_path()
2048 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2049 return w_attrib_path
;
2052 void ControlPart::set_parent_path(WithAttribPath
* p_path
)
2054 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2055 w_attrib_path
->set_parent(p_path
);
2056 block
->set_parent_path(w_attrib_path
);
2059 void ControlPart::dump(unsigned level
) const
2061 DEBUG(level
, "Control part");
2062 block
->dump(level
+ 1);
2063 if (w_attrib_path
) {
2064 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2066 DEBUG(level
+ 1, "Attributes:");
2067 attrib
->dump(level
+ 2);
2072 // =================================
2074 // =================================
2076 Module::Module(Identifier
*p_modid
)
2077 : Common::Module(MOD_TTCN
, p_modid
), language_spec(0), w_attrib_path(0),
2080 asss
= new Definitions();
2081 asss
->set_parent_scope(this);
2082 imp
= new Imports();
2083 imp
->set_my_mod(this);
2084 //modified_encodings = true; // Assume always true for TTCN modules
2089 delete language_spec
;
2091 for (size_t i
= 0; i
< group_v
.size(); i
++) delete group_v
[i
];
2095 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) delete friendmods_v
[i
];
2096 friendmods_v
.clear();
2098 for (size_t i
= 0; i
< runs_on_scopes
.size(); i
++)
2099 delete runs_on_scopes
[i
];
2100 runs_on_scopes
.clear();
2101 delete w_attrib_path
;
2104 void Module::add_group(Group
* p_group
)
2106 group_v
.add(p_group
);
2109 void Module::add_friendmod(FriendMod
*p_friendmod
)
2111 friendmods_v
.add(p_friendmod
);
2112 p_friendmod
->set_my_mod(this);
2115 Module
*Module::clone() const
2117 FATAL_ERROR("Ttcn::Module::clone()");
2120 Common::Assignment
*Module::importAssignment(const Identifier
& p_modid
,
2121 const Identifier
& p_id
) const
2123 if (asss
->has_local_ass_withId(p_id
)) {
2124 Common::Assignment
* ass
= asss
->get_local_ass_byId(p_id
);
2125 if (!ass
) FATAL_ERROR("Ttcn::Module::importAssignment()");
2127 switch(ass
->get_visibility()) {
2129 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) {
2130 if (friendmods_v
[i
]->get_modid() == p_modid
) return ass
;
2138 FATAL_ERROR("Ttcn::Module::importAssignment()");
2144 void Module::set_fullname(const string
& p_fullname
)
2146 Node::set_fullname(p_fullname
);
2147 asss
->set_fullname(p_fullname
);
2148 if (controlpart
) controlpart
->set_fullname(p_fullname
+ ".control");
2149 for(size_t i
= 0; i
< group_v
.size(); i
++)
2151 group_v
[i
]->set_fullname(p_fullname
+ ".<group " + Int2string(i
) + ">");
2153 if (w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
2157 Common::Assignments
*Module::get_scope_asss()
2162 bool Module::has_imported_ass_withId(const Identifier
& p_id
)
2164 const Location
*loc
= NULL
;
2165 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2166 const ImpMod
* im
= imp
->get_impmod(i
);
2167 //TODO use a reference instead of an identifier
2168 if(im
->has_imported_def(*modid
, p_id
, loc
)) return true;
2173 Common::Assignment
* Module::get_ass_bySRef(Ref_simple
*p_ref
)
2175 const Identifier
*r_modid
= p_ref
->get_modid();
2176 const Identifier
*r_id
= p_ref
->get_id();
2178 // the reference contains a module name
2179 if (r_modid
->get_name() != modid
->get_name()) {
2180 // the reference points to another module
2181 bool has_impmod_with_name
= false;
2182 Common::Assignment
* result_ass
= NULL
;
2183 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2184 const ImpMod
* im
= imp
->get_impmod(i
);
2185 const Identifier
& im_id
= im
->get_modid();
2186 const string
& im_name
= im_id
.get_name();
2187 if (r_modid
->get_name() == im_name
) {
2188 has_impmod_with_name
= true;
2189 vector
<ImpMod
> tempusedImpMods
;
2190 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
2191 Common::Assignment
*t_ass
= im
->get_imported_def(*modid
, *r_id
, p_ref
, referencechain
, tempusedImpMods
);
2192 referencechain
->reset();
2193 delete referencechain
;
2195 if (t_ass
!= NULL
) {
2196 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(im
->get_mod());
2197 if (!ttcn_m
->is_visible(*modid
, t_ass
->get_visibility())) {
2201 if (t_ass
!= NULL
) {
2202 if (result_ass
== NULL
) {
2204 } else if(result_ass
!= t_ass
) {
2206 "It is not possible to resolve the reference unambigously"
2207 ", as it can be resolved to `%s' and to `%s'",
2208 result_ass
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
2212 tempusedImpMods
.clear();
2215 if (result_ass
) return result_ass
;
2217 if (has_impmod_with_name
) {
2218 p_ref
->error("There is no definition with name `%s' visible from "
2219 "module `%s'", r_id
->get_dispname().c_str(),
2220 r_modid
->get_dispname().c_str());
2222 if (modules
->has_mod_withId(*r_modid
)) {
2223 Common::Module
*m
= modules
->get_mod_byId(*r_modid
);
2224 if (m
->get_asss()->has_ass_withId(*r_id
)) {
2225 p_ref
->error("Definition with name `%s' is not imported from "
2226 "module `%s'", r_id
->get_dispname().c_str(),
2227 r_modid
->get_dispname().c_str());
2229 p_ref
->error("There is no definition with name `%s' in "
2230 "module `%s'", r_id
->get_dispname().c_str(),
2231 r_modid
->get_dispname().c_str());
2234 p_ref
->error("There is no module with name `%s'",
2235 r_modid
->get_dispname().c_str());
2240 // the reference points to the own module
2241 if (asss
->has_local_ass_withId(*r_id
)) {
2242 return asss
->get_local_ass_byId(*r_id
);
2244 p_ref
->error("There is no definition with name `%s' in "
2245 "module `%s'", r_id
->get_dispname().c_str(),
2246 r_modid
->get_dispname().c_str());
2250 // no module name is given in the reference
2251 if (asss
->has_local_ass_withId(*r_id
)) {
2252 return asss
->get_local_ass_byId(*r_id
);
2254 // the reference was not found locally -> look at the import list
2255 Common::Assignment
*t_result
= NULL
, *t_ass
= NULL
;
2256 for (size_t i
= 0, num
= imp
->get_imports_size(); i
< num
; ++i
) {
2257 const ImpMod
* im
= imp
->get_impmod(i
);
2259 vector
<ImpMod
> tempusedImpMods
;
2260 ReferenceChain
* referencechain
= new ReferenceChain(this, "NEW IMPORT REFERNCECHAIN");
2261 t_ass
= im
->get_imported_def(*modid
, *r_id
, p_ref
, referencechain
, tempusedImpMods
);
2262 referencechain
->reset();
2264 delete referencechain
;
2265 if (t_ass
!= NULL
) {
2266 Ttcn::Module
*ttcn_m
= static_cast<Ttcn::Module
*>(im
->get_mod());
2267 if (!ttcn_m
->is_visible(*modid
, t_ass
->get_visibility())) {
2271 if (t_ass
!= NULL
) {
2272 if (t_result
== NULL
) {
2274 } else if(t_result
!= t_ass
) {
2276 "It is not possible to resolve the reference unambigously"
2277 ", as it can be resolved to `%s' and to `%s'",
2278 t_result
->get_fullname().c_str(), t_ass
->get_fullname().c_str());
2282 tempusedImpMods
.clear();
2285 if (t_result
) return t_result
;
2287 p_ref
->error("There is no local or imported definition with name `%s'"
2288 ,r_id
->get_dispname().c_str());
2294 bool Module::is_valid_moduleid(const Identifier
& p_id
)
2296 // The identifier represents the current module
2297 if (p_id
.get_name() == modid
->get_name()) return true;
2298 // The identifier represents a module imported in the current module
2299 if(imp
->has_impmod_withId(p_id
)) return true;
2303 Common::Assignments
*Module::get_asss()
2308 bool Module::exports_sym(const Identifier
&)
2310 FATAL_ERROR("Ttcn::Module::exports_sym()");
2314 Type
*Module::get_address_type()
2316 Identifier
address_id(Identifier::ID_TTCN
, string("address"));
2317 // return NULL if address type is not defined
2318 if (!asss
->has_local_ass_withId(address_id
)) return 0;
2319 Common::Assignment
*t_ass
= asss
->get_local_ass_byId(address_id
);
2320 if (t_ass
->get_asstype() != Common::Assignment::A_TYPE
)
2321 FATAL_ERROR("Module::get_address_type(): address is not a type");
2322 return t_ass
->get_Type();
2325 void Module::chk_imp(ReferenceChain
& refch
, vector
<Common::Module
>& moduleStack
)
2327 if (imp_checked
) return;
2328 const string
& module_name
= modid
->get_dispname();
2330 Error_Context backup
;
2331 Error_Context
cntxt(this, "In TTCN-3 module `%s'", module_name
.c_str());
2332 imp
->chk_imp(refch
, moduleStack
);
2335 collect_visible_mods();
2340 DEBUG(1, "Checking TTCN-3 module `%s'", modid
->get_dispname().c_str());
2341 Error_Context
cntxt(this, "In TTCN-3 module `%s'",
2342 modid
->get_dispname().c_str());
2343 if (w_attrib_path
) {
2344 w_attrib_path
->chk_global_attrib();
2345 w_attrib_path
->chk_no_qualif();
2347 // Check "extension" attributes in the module's "with" statement
2348 MultiWithAttrib
*multi
= w_attrib_path
->get_with_attr();
2349 if (multi
) for (size_t i
= 0; i
< multi
->get_nof_elements(); ++i
) {
2350 const SingleWithAttrib
*single
= multi
->get_element(i
);
2351 if (single
->get_attribKeyword() != SingleWithAttrib::AT_EXTENSION
) continue;
2352 // Parse the extension attribute
2353 // We circumvent parse_extattributes() in coding_attrib_p.y because
2354 // it processes all attributes in the "with" statement and
2355 // doesn't allow the removal on a case-by-case basis.
2357 init_coding_attrib_lex(single
->get_attribSpec());
2358 int result
= coding_attrib_parse();// 0=OK, 1=error, 2=out of memory
2359 cleanup_coding_attrib_lex();
2366 const size_t num_parsed
= extatrs
->size();
2367 for (size_t a
= 0; a
< num_parsed
; ++a
) {
2368 Ttcn::ExtensionAttribute
& ex
= extatrs
->get(0);
2370 switch (ex
.get_type()) {
2371 case Ttcn::ExtensionAttribute::VERSION_TEMPLATE
:
2372 case Ttcn::ExtensionAttribute::VERSION
: {
2373 char* act_product_number
;
2374 unsigned int act_suffix
, act_rel
, act_patch
, act_build
;
2376 (void)ex
.get_id(act_product_number
, act_suffix
, act_rel
, act_patch
, act_build
, extra_junk
);
2378 if (release
!= UINT_MAX
) {
2379 ex
.error("Duplicate 'version' attribute");
2382 product_number
= mcopystr(act_product_number
);
2383 suffix
= act_suffix
;
2387 extra
= mcopystr(extra_junk
);
2389 // Avoid propagating the attribute needlessly
2390 multi
->delete_element(i
--);
2394 case Ttcn::ExtensionAttribute::REQUIRES
: {
2395 // Imports have already been checked
2396 char* exp_product_number
;
2397 unsigned int exp_suffix
, exp_rel
, exp_patch
, exp_build
;
2399 Common::Identifier
*req_id
= ex
.get_id(exp_product_number
,
2400 exp_suffix
, exp_rel
, exp_patch
, exp_build
, exp_extra
);
2402 if (imp
->has_impmod_withId(*req_id
)) {
2403 Common::Module
* m
= modules
->get_mod_byId(*req_id
);
2404 if (m
->product_number
== NULL
&& exp_product_number
!= NULL
) {
2405 ex
.error("Module '%s' requires module '%s' of product %s"
2406 ", but it is not specified",
2407 this->modid
->get_dispname().c_str(), req_id
->get_dispname().c_str(),
2408 exp_product_number
);
2409 multi
->delete_element(i
--);
2412 } else if (exp_product_number
== NULL
&&
2413 m
->product_number
!= NULL
&& strcmp(m
->product_number
, "") > 0){
2414 ex
.warning("Module '%s' requires module '%s' of any product"
2415 ", while it specifies '%s'",
2416 this->modid
->get_dispname().c_str(),
2417 req_id
->get_dispname().c_str(), m
->product_number
);
2418 } else if (m
->product_number
!= NULL
&& exp_product_number
!= NULL
2419 && 0 != strcmp(m
->product_number
, exp_product_number
)) {
2420 char *req_product_identifier
=
2421 get_product_identifier(exp_product_number
,
2422 exp_suffix
, exp_rel
, exp_patch
, exp_build
);
2423 char *mod_product_identifier
=
2424 get_product_identifier(m
->product_number
,
2425 m
->suffix
, m
->release
, m
->patch
, m
->build
);
2427 ex
.error("Module '%s' requires version %s of module"
2428 " '%s', but only %s is available",
2429 this->modid
->get_dispname().c_str(), req_product_identifier
,
2430 req_id
->get_dispname().c_str(), mod_product_identifier
);
2431 Free(req_product_identifier
);
2432 Free(mod_product_identifier
);
2433 multi
->delete_element(i
--);
2437 // different suffixes are always incompatible
2438 // unless the special version number is used
2439 if (m
->suffix
!= exp_suffix
&& (m
->suffix
!= UINT_MAX
)) {
2440 char *req_product_identifier
=
2441 get_product_identifier(exp_product_number
,exp_suffix
, exp_rel
, exp_patch
, exp_build
);
2442 char *mod_product_identifier
=
2443 get_product_identifier(m
->product_number
,
2444 m
->suffix
, m
->release
, m
->patch
, m
->build
);
2446 ex
.error("Module '%s' requires version %s of module"
2447 " '%s', but only %s is available",
2448 this->modid
->get_dispname().c_str(), req_product_identifier
,
2449 req_id
->get_dispname().c_str(), mod_product_identifier
);
2450 Free(req_product_identifier
);
2451 Free(mod_product_identifier
);
2452 multi
->delete_element(i
--);
2456 if ( m
->release
< exp_rel
2457 ||(m
->release
== exp_rel
&& m
->patch
< exp_patch
)
2458 ||(m
->patch
== exp_patch
&& m
->build
< exp_build
)) {
2459 char *mod_bld_str
= buildstr(m
->build
);
2460 char *exp_bld_str
= buildstr(exp_build
);
2461 if (mod_bld_str
==0 || exp_bld_str
==0) FATAL_ERROR(
2462 "Ttcn::Module::chk() invalid build number");
2463 ex
.error("Module '%s' requires version R%u%c%s of module"
2464 " '%s', but only R%u%c%s is available",
2465 this->modid
->get_dispname().c_str(),
2466 exp_rel
, eri(exp_patch
), exp_bld_str
,
2467 req_id
->get_dispname().c_str(),
2468 m
->release
, eri(m
->patch
), mod_bld_str
);
2473 single
->error("No imported module named '%s'",
2474 req_id
->get_dispname().c_str());
2476 multi
->delete_element(i
--);
2480 case Ttcn::ExtensionAttribute::REQ_TITAN
: {
2481 char* exp_product_number
;
2482 unsigned int exp_suffix
, exp_minor
, exp_patch
, exp_build
;
2484 (void)ex
.get_id(exp_product_number
, exp_suffix
, exp_minor
, exp_patch
, exp_build
, exp_extra
);
2485 if (exp_product_number
!= NULL
&& strcmp(exp_product_number
,"CRL 113 200") != 0) {
2486 ex
.error("This module needs to be compiled with TITAN, but "
2487 " product number %s is not TITAN"
2488 , exp_product_number
);
2490 if (0 == exp_suffix
) {
2491 exp_suffix
= 1; // previous version number format did not list the suffix part
2493 // TTCN3_MAJOR is always 1
2494 int expected_version
= exp_suffix
* 1000000
2495 + exp_minor
* 10000 + exp_patch
* 100 + exp_build
;
2496 if (expected_version
> TTCN3_VERSION_MONOTONE
) {
2497 char *exp_product_identifier
=
2498 get_product_identifier(exp_product_number
, exp_suffix
, exp_minor
, exp_patch
, exp_build
);
2499 ex
.error("This module needs to be compiled with TITAN version"
2500 " %s or higher; version %s detected"
2501 , exp_product_identifier
, PRODUCT_NUMBER
);
2502 Free(exp_product_identifier
);
2504 multi
->delete_element(i
--);
2507 case Ttcn::ExtensionAttribute::PRINTING
: {
2508 ex
.error("Attribute 'printing' not allowed at module level");
2509 multi
->delete_element(i
--);
2515 // Let everything else propagate into the module.
2516 // Extension attributes in the module's "with" statement
2517 // may be impractical, but not outright erroneous.
2528 if (controlpart
) controlpart
->chk();
2529 if (control_ns
&& !*control_ns
) { // set but empty
2530 error("Invalid URI value for control namespace");
2532 if (control_ns_prefix
&& !*control_ns_prefix
) { // set but empty
2533 error("Empty NCName for the control namespace prefix is not allowed");
2535 // TODO proper URI and NCName validation
2538 void Module::chk_friends()
2540 map
<string
, FriendMod
> friends_m
;
2542 for(size_t i
= 0; i
< friendmods_v
.size(); i
++)
2544 FriendMod
* temp_friend
= friendmods_v
[i
];
2545 const Identifier
& friend_id
= temp_friend
->get_modid();
2546 const string
& friend_name
= friend_id
.get_name();
2547 if(friends_m
.has_key(friend_name
))
2549 temp_friend
->error("Duplicate friend module with name `%s'",
2550 friend_id
.get_dispname().c_str());
2551 friends_m
[friend_name
]->note("Friend module `%s' is already defined here",
2552 friend_id
.get_dispname().c_str());
2554 friends_m
.add(friend_name
, temp_friend
);
2557 friendmods_v
[i
]->chk();
2564 void Module::chk_groups()
2566 map
<string
,Common::Assignment
> ass_m
;
2568 for(size_t i
= 0; i
< asss
->get_nof_asss(); i
++)
2570 Common::Assignment
*temp_ass
= asss
->get_ass_byIndex(i
);
2571 if(!temp_ass
->get_parent_group())
2573 const string
& ass_name
= temp_ass
->get_id().get_name();
2574 if (!ass_m
.has_key(ass_name
)) ass_m
.add(ass_name
, temp_ass
);
2578 for(size_t i
= 0; i
< group_v
.size(); i
++)
2580 const Group
* group
= group_v
[i
];
2581 const Identifier
& group_id
= group
->get_id();
2582 const string
& group_name
= group_id
.get_name();
2583 if(ass_m
.has_key(group_name
))
2585 group
->error("Group name `%s' clashes with a definition",
2586 group_id
.get_dispname().c_str());
2587 ass_m
[group_name
]->note("Definition of `%s' is here",
2588 group_id
.get_dispname().c_str());
2590 if(group_m
.has_key(group_name
))
2592 group
->error("Duplicate group with name `%s'",
2593 group_id
.get_dispname().c_str());
2594 group_m
[group_name
]->note("Group `%s' is already defined here",
2595 group_id
.get_dispname().c_str());
2597 group_m
.add(group_name
,group_v
[i
]);
2603 for(size_t i
= 0; i
< group_v
.size(); i
++)
2609 void Module::get_imported_mods(module_set_t
& p_imported_mods
)
2611 imp
->get_imported_mods(p_imported_mods
);
2614 void Module::generate_code_internal(CodeGenHelper
& cgh
) {
2615 imp
->generate_code(cgh
);
2616 asss
->generate_code(cgh
);
2618 controlpart
->generate_code(cgh
.get_outputstruct(modid
->get_ttcnname()), this);
2621 RunsOnScope
*Module::get_runs_on_scope(Type
*comptype
)
2623 RunsOnScope
*ret_val
= new RunsOnScope(comptype
);
2624 runs_on_scopes
.add(ret_val
);
2625 ret_val
->set_parent_scope(asss
);
2626 ret_val
->chk_uniq();
2631 void Module::dump(unsigned level
) const
2633 DEBUG(level
, "TTCN-3 module: %s", modid
->get_dispname().c_str());
2635 if(imp
) imp
->dump(level
);
2636 if(asss
) asss
->dump(level
);
2638 for(size_t i
= 0; i
< group_v
.size(); i
++)
2640 group_v
[i
]->dump(level
);
2643 if(controlpart
) controlpart
->dump(level
);
2645 if (w_attrib_path
) {
2646 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2648 DEBUG(level
, "Module Attributes:");
2649 attrib
->dump(level
+ 1);
2654 void Module::set_language_spec(const char *p_language_spec
)
2656 if (language_spec
) FATAL_ERROR("Module::set_language_spec()");
2657 if (p_language_spec
) language_spec
= new string(p_language_spec
);
2660 void Module::add_ass(Definition
* p_ass
)
2662 asss
->add_ass(p_ass
);
2665 void Module::add_impmod(ImpMod
*p_impmod
)
2667 imp
->add_impmod(p_impmod
);
2670 void Module::add_controlpart(ControlPart
* p_controlpart
)
2672 if (!p_controlpart
|| controlpart
) FATAL_ERROR("Module::add_controlpart()");
2673 controlpart
= p_controlpart
;
2674 controlpart
->set_my_scope(asss
);
2677 void Module::set_with_attr(MultiWithAttrib
* p_attrib
)
2679 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2680 w_attrib_path
->set_with_attr(p_attrib
);
2683 WithAttribPath
* Module::get_attrib_path()
2685 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2686 return w_attrib_path
;
2689 void Module::set_parent_path(WithAttribPath
* p_path
)
2691 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2692 w_attrib_path
->set_parent(p_path
);
2695 bool Module::is_visible(const Identifier
& id
, visibility_t visibility
){
2697 if (visibility
== PUBLIC
) {
2700 if (visibility
== FRIEND
) {
2701 for (size_t i
= 0; i
< friendmods_v
.size(); i
++) {
2702 if (friendmods_v
[i
]->get_modid() == id
) {
2710 void Module::generate_json_schema(JSON_Tokenizer
& json
, map
<Type
*, JSON_Tokenizer
>& json_refs
)
2712 // add a new property for this module
2713 json
.put_next_token(JSON_TOKEN_NAME
, modid
->get_ttcnname().c_str());
2715 // add type definitions into an object
2716 json
.put_next_token(JSON_TOKEN_OBJECT_START
);
2718 // cycle through each type, generate schema segment and reference when needed
2719 for (size_t i
= 0; i
< asss
->get_nof_asss(); ++i
) {
2720 Def_Type
* def
= dynamic_cast<Def_Type
*>(asss
->get_ass_byIndex(i
));
2722 Type
* t
= def
->get_Type();
2723 if (t
->has_encoding(Type::CT_JSON
)) {
2724 // insert type's schema segment
2725 t
->generate_json_schema(json
, false, false);
2727 if (json_refs_for_all_types
&& !json_refs
.has_key(t
)) {
2728 // create JSON schema reference for the type
2729 JSON_Tokenizer
* json_ref
= new JSON_Tokenizer
;
2730 json_refs
.add(t
, json_ref
);
2731 t
->generate_json_schema_ref(*json_ref
);
2737 // end of type definitions
2738 json
.put_next_token(JSON_TOKEN_OBJECT_END
);
2740 // insert function data
2741 for (size_t i
= 0; i
< asss
->get_nof_asss(); ++i
) {
2742 Def_ExtFunction
* def
= dynamic_cast<Def_ExtFunction
*>(asss
->get_ass_byIndex(i
));
2744 def
->generate_json_schema_ref(json_refs
);
2749 // =================================
2751 // =================================
2753 string
Definition::get_genname() const
2755 if (!genname
.empty()) return genname
;
2756 else return id
->get_name();
2759 namedbool
Definition::has_implicit_omit_attr() const {
2760 if (w_attrib_path
) {
2761 const vector
<SingleWithAttrib
>& real_attribs
=
2762 w_attrib_path
->get_real_attrib();
2763 for (size_t in
= real_attribs
.size(); in
> 0; in
--) {
2764 if (SingleWithAttrib::AT_OPTIONAL
==
2765 real_attribs
[in
-1]->get_attribKeyword()) {
2766 if ("implicit omit" ==
2767 real_attribs
[in
-1]->get_attribSpec().get_spec()) {
2768 return IMPLICIT_OMIT
;
2769 } else if ("explicit omit" ==
2770 real_attribs
[in
-1]->get_attribSpec().get_spec()) {
2771 return NOT_IMPLICIT_OMIT
;
2772 } // error reporting for other values is in chk_global_attrib
2776 return NOT_IMPLICIT_OMIT
;
2779 Definition::~Definition()
2781 delete w_attrib_path
;
2782 delete erroneous_attrs
;
2785 void Definition::set_fullname(const string
& p_fullname
)
2787 Common::Assignment::set_fullname(p_fullname
);
2788 if (w_attrib_path
) w_attrib_path
->set_fullname(p_fullname
+ ".<attribpath>");
2789 if (erroneous_attrs
) erroneous_attrs
->set_fullname(p_fullname
+".<erroneous_attributes>");
2792 bool Definition::is_local() const
2794 if (!my_scope
) FATAL_ERROR("Definition::is_local()");
2795 for (Scope
*scope
= my_scope
; scope
; scope
= scope
->get_parent_scope()) {
2796 if (dynamic_cast<StatementBlock
*>(scope
)) return true;
2801 bool Definition::chk_identical(Definition
*)
2803 FATAL_ERROR("Definition::chk_identical()");
2807 void Definition::chk_erroneous_attr()
2809 if (!w_attrib_path
) return;
2810 const Ttcn::MultiWithAttrib
* attribs
= w_attrib_path
->get_local_attrib();
2811 if (!attribs
) return;
2812 for (size_t i
= 0; i
< attribs
->get_nof_elements(); i
++) {
2813 const Ttcn::SingleWithAttrib
* act_attr
= attribs
->get_element(i
);
2814 if (act_attr
->get_attribKeyword()==Ttcn::SingleWithAttrib::AT_ERRONEOUS
) {
2815 if (!use_runtime_2
) {
2816 error("`erroneous' attributes can be used only with the Function Test Runtime");
2817 note("If you need negative testing use the -R flag when generating the makefile");
2820 size_t nof_qualifiers
= act_attr
->get_attribQualifiers() ? act_attr
->get_attribQualifiers()->get_nof_qualifiers() : 0;
2821 dynamic_array
<Type
*> refd_type_array(nof_qualifiers
); // only the qualifiers pointing to existing fields will be added to erroneous_attrs objects
2822 if (nof_qualifiers
==0) {
2823 act_attr
->error("At least one qualifier must be specified for the `erroneous' attribute");
2825 // check if qualifiers point to existing fields
2826 for (size_t qi
=0; qi
<nof_qualifiers
; qi
++) {
2827 Qualifier
* act_qual
= const_cast<Qualifier
*>(act_attr
->get_attribQualifiers()->get_qualifier(qi
));
2828 act_qual
->set_my_scope(get_my_scope());
2829 Type
* field_type
= get_Type()->get_field_type(act_qual
, Type::EXPECTED_CONSTANT
);
2831 dynamic_array
<size_t> subrefs_array
;
2832 dynamic_array
<Type
*> type_array
;
2833 bool valid_indexes
= get_Type()->get_subrefs_as_array(act_qual
, subrefs_array
, type_array
);
2834 if (!valid_indexes
) field_type
= NULL
;
2835 if (act_qual
->refers_to_string_element()) {
2836 act_qual
->error("Reference to a string element cannot be used in this context");
2840 refd_type_array
.add(field_type
);
2843 // parse the attr. spec.
2844 ErroneousAttributeSpec
* err_attr_spec
= ttcn3_parse_erroneous_attr_spec_string(
2845 act_attr
->get_attribSpec().get_spec().c_str(), act_attr
->get_attribSpec());
2846 if (err_attr_spec
) {
2847 if (!erroneous_attrs
) erroneous_attrs
= new ErroneousAttributes(get_Type());
2848 // attr.spec will be owned by erroneous_attrs object
2849 erroneous_attrs
->add_spec(err_attr_spec
);
2850 err_attr_spec
->set_fullname(get_fullname());
2851 err_attr_spec
->set_my_scope(get_my_scope());
2852 err_attr_spec
->chk();
2853 // create qualifier - err.attr.spec. pairs
2854 for (size_t qi
=0; qi
<nof_qualifiers
; qi
++) {
2855 if (refd_type_array
[qi
] && (err_attr_spec
->get_indicator()!=ErroneousAttributeSpec::I_INVALID
)) {
2856 erroneous_attrs
->add_pair(act_attr
->get_attribQualifiers()->get_qualifier(qi
), err_attr_spec
);
2862 if (erroneous_attrs
) erroneous_attrs
->chk();
2865 char* Definition::generate_code_str(char *str
)
2867 FATAL_ERROR("Definition::generate_code_str()");
2871 void Definition::ilt_generate_code(ILT
*)
2873 FATAL_ERROR("Definition::ilt_generate_code()");
2876 char *Definition::generate_code_init_comp(char *str
, Definition
*)
2878 FATAL_ERROR("Definition::generate_code_init_comp()");
2882 void Definition::set_with_attr(MultiWithAttrib
* p_attrib
)
2884 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2885 w_attrib_path
->set_with_attr(p_attrib
);
2888 WithAttribPath
* Definition::get_attrib_path()
2890 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2891 return w_attrib_path
;
2894 void Definition::set_parent_path(WithAttribPath
* p_path
)
2896 if (!w_attrib_path
) w_attrib_path
= new WithAttribPath();
2897 w_attrib_path
->set_parent(p_path
);
2900 void Definition::set_parent_group(Group
* p_group
)
2902 if(parentgroup
) // there would be a leak!
2903 FATAL_ERROR("Definition::set_parent_group()");
2904 parentgroup
= p_group
;
2907 Group
* Definition::get_parent_group()
2912 void Definition::dump_internal(unsigned level
) const
2914 DEBUG(level
, "Move along, nothing to see here");
2917 void Definition::dump(unsigned level
) const
2919 dump_internal(level
);
2920 if (w_attrib_path
) {
2921 MultiWithAttrib
*attrib
= w_attrib_path
->get_with_attr();
2923 DEBUG(level
+ 1, "Definition Attributes:");
2924 attrib
->dump(level
+ 2);
2927 if (erroneous_attrs
) erroneous_attrs
->dump(level
+1);
2930 // =================================
2932 // =================================
2934 Def_Type::Def_Type(Identifier
*p_id
, Type
*p_type
)
2935 : Definition(A_TYPE
, p_id
), type(p_type
)
2937 if(!p_type
) FATAL_ERROR("Ttcn::Def_Type::Def_Type()");
2938 type
->set_ownertype(Type::OT_TYPE_DEF
, this);
2941 Def_Type::~Def_Type()
2946 Def_Type
*Def_Type::clone() const
2948 FATAL_ERROR("Def_Type::clone");
2951 void Def_Type::set_fullname(const string
& p_fullname
)
2953 Definition::set_fullname(p_fullname
);
2954 type
->set_fullname(p_fullname
);
2957 void Def_Type::set_my_scope(Scope
*p_scope
)
2959 bridgeScope
.set_parent_scope(p_scope
);
2960 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
2962 Definition::set_my_scope(&bridgeScope
);
2963 type
->set_my_scope(&bridgeScope
);
2967 Setting
*Def_Type::get_Setting()
2972 Type
*Def_Type::get_Type()
2978 void Def_Type::chk()
2980 if (checked
) return;
2982 Error_Context
cntxt(this, "In %s definition `%s'",
2983 type
->get_typetype() == Type::T_SIGNATURE
? "signature" : "type",
2984 id
->get_dispname().c_str());
2985 type
->set_genname(get_genname());
2986 if (!semantic_check_only
&& type
->get_typetype() == Type::T_COMPONENT
) {
2987 // the prefix of embedded definitions must be set before the checking
2988 type
->get_CompBody()->set_genname(get_genname() + "_component_");
2991 while (w_attrib_path
) { // not a loop, but we can _break_ out of it
2992 w_attrib_path
->chk_global_attrib();
2993 w_attrib_path
->chk_no_qualif();
2994 if (type
->get_typetype() != Type::T_ANYTYPE
) break;
2995 // This is the anytype; it must be empty (we're about to add the fields)
2996 if (type
->get_nof_comps() > 0) FATAL_ERROR("Def_Type::chk");
2998 Ttcn::ExtensionAttributes
*extattrs
= parse_extattributes(w_attrib_path
);
2999 if (extattrs
== 0) break; // NULL means parsing error
3001 size_t num_atrs
= extattrs
->size();
3002 for (size_t k
= 0; k
< num_atrs
; ++k
) {
3003 ExtensionAttribute
&ea
= extattrs
->get(k
);
3004 switch (ea
.get_type()) {
3005 case ExtensionAttribute::ANYTYPELIST
: {
3006 Types
*anytypes
= ea
.get_types();
3007 // List of types to be converted into fields for the anytype.
3008 // Make sure scope is set on all types in the list.
3009 anytypes
->set_my_scope(get_my_scope());
3011 // Convert the list of types into field names for the anytype
3012 for (size_t i
=0; i
< anytypes
->get_nof_types(); ++i
) {
3013 Type
*t
= anytypes
->extract_type_byIndex(i
);
3014 // we are now the owner of the Type.
3015 if (t
->get_typetype()==Type::T_ERROR
) { // should we give up?
3021 const char* btn
= Type::get_typename_builtin(t
->get_typetype());
3025 else if (t
->get_typetype() == Type::T_REFD
) {
3026 // Extract the identifier
3027 Common::Reference
*ref
= t
->get_Reference();
3028 Ttcn::Reference
*tref
= dynamic_cast<Ttcn::Reference
*>(ref
);
3029 if (!tref
) FATAL_ERROR("Def_Type::chk, wrong kind of reference");
3030 const Common::Identifier
*modid
= tref
->get_modid();
3032 ea
.error("Qualified name '%s' cannot be added to the anytype",
3033 tref
->get_dispname().c_str());
3037 field_name
= tref
->get_id()->get_ttcnname();
3040 // Can't happen here
3041 FATAL_ERROR("Unexpected type %d", t
->get_typetype());
3044 const string
& at_field
= anytype_field(field_name
);
3045 Identifier
*field_id
= new Identifier(Identifier::ID_TTCN
, at_field
);
3046 CompField
*cf
= new CompField(field_id
, t
, false, 0);
3047 cf
->set_location(ea
);
3048 cf
->set_fullname(get_fullname());
3054 w_attrib_path
->get_with_attr()->error("Type def can only have anytype");
3060 break; // do not loop
3063 // Now we can check the type
3065 type
->chk_constructor_name(*id
);
3066 if (id
->get_ttcnname() == "address") type
->chk_address();
3067 ReferenceChain
refch(type
, "While checking embedded recursions");
3068 type
->chk_recursions(refch
);
3070 if (type
->get_typetype()==Type::T_FUNCTION
3071 ||type
->get_typetype()==Type::T_ALTSTEP
3072 ||type
->get_typetype()==Type::T_TESTCASE
) {
3073 // TR 922. This is a function/altstep/testcase reference.
3074 // Set this definition as the definition for the formal parameters.
3075 type
->get_fat_parameters()->set_my_def(this);
3079 void Def_Type::generate_code(output_struct
*target
, bool)
3081 type
->generate_code(target
);
3082 if (type
->get_typetype() == Type::T_COMPONENT
) {
3083 // the C++ equivalents of embedded component element definitions must be
3084 // generated from outside Type::generate_code() because the function can
3085 // call itself recursively and create invalid (overlapped) initializer
3087 type
->get_CompBody()->generate_code(target
);
3091 void Def_Type::generate_code(CodeGenHelper
& cgh
) {
3092 type
->generate_code(cgh
.get_outputstruct(get_Type()));
3093 if (type
->get_typetype() == Type::T_COMPONENT
) {
3094 // the C++ equivalents of embedded component element definitions must be
3095 // generated from outside Type::generate_code() because the function can
3096 // call itself recursively and create invalid (overlapped) initializer
3098 type
->get_CompBody()->generate_code(cgh
.get_current_outputstruct());
3100 cgh
.finalize_generation(get_Type());
3104 void Def_Type::dump_internal(unsigned level
) const
3106 DEBUG(level
, "Type def: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3107 type
->dump(level
+ 1);
3110 void Def_Type::set_with_attr(MultiWithAttrib
* p_attrib
)
3112 if (!w_attrib_path
) {
3113 w_attrib_path
= new WithAttribPath();
3114 type
->set_parent_path(w_attrib_path
);
3116 type
->set_with_attr(p_attrib
);
3119 WithAttribPath
* Def_Type::get_attrib_path()
3121 if (!w_attrib_path
) {
3122 w_attrib_path
= new WithAttribPath();
3123 type
->set_parent_path(w_attrib_path
);
3125 return w_attrib_path
;
3128 void Def_Type::set_parent_path(WithAttribPath
* p_path
)
3130 if (!w_attrib_path
) {
3131 w_attrib_path
= new WithAttribPath();
3132 type
->set_parent_path(w_attrib_path
);
3134 w_attrib_path
->set_parent(p_path
);
3137 // =================================
3139 // =================================
3141 Def_Const::Def_Const(Identifier
*p_id
, Type
*p_type
, Value
*p_value
)
3142 : Definition(A_CONST
, p_id
)
3144 if (!p_type
|| !p_value
) FATAL_ERROR("Ttcn::Def_Const::Def_Const()");
3146 type
->set_ownertype(Type::OT_CONST_DEF
, this);
3148 value_under_check
=false;
3151 Def_Const::~Def_Const()
3157 Def_Const
*Def_Const::clone() const
3159 FATAL_ERROR("Def_Const::clone");
3162 void Def_Const::set_fullname(const string
& p_fullname
)
3164 Definition::set_fullname(p_fullname
);
3165 type
->set_fullname(p_fullname
+ ".<type>");
3166 value
->set_fullname(p_fullname
);
3169 void Def_Const::set_my_scope(Scope
*p_scope
)
3171 Definition::set_my_scope(p_scope
);
3172 type
->set_my_scope(p_scope
);
3173 value
->set_my_scope(p_scope
);
3176 Setting
*Def_Const::get_Setting()
3181 Type
*Def_Const::get_Type()
3188 Value
*Def_Const::get_Value()
3194 void Def_Const::chk()
3197 if (value_under_check
) {
3198 error("Circular reference in constant definition `%s'",
3199 id
->get_dispname().c_str());
3200 value_under_check
= false; // only report the error once for this definition
3204 Error_Context
cntxt(this, "In constant definition `%s'",
3205 id
->get_dispname().c_str());
3206 type
->set_genname(_T_
, get_genname());
3208 value
->set_my_governor(type
);
3209 type
->chk_this_value_ref(value
);
3211 if (w_attrib_path
) {
3212 w_attrib_path
->chk_global_attrib(true);
3213 switch (type
->get_type_refd_last()->get_typetype_ttcn3()) {
3216 case Type::T_CHOICE_T
:
3217 // These types may have qualified attributes
3219 case Type::T_SEQOF
: case Type::T_SETOF
:
3222 w_attrib_path
->chk_no_qualif();
3226 Type
*t
= type
->get_type_refd_last();
3227 switch (t
->get_typetype()) {
3229 error("Constant cannot be defined for port type `%s'",
3230 t
->get_fullname().c_str());
3232 case Type::T_SIGNATURE
:
3233 error("Constant cannot be defined for signature `%s'",
3234 t
->get_fullname().c_str());
3237 value_under_check
= true;
3238 type
->chk_this_value(value
, 0, Type::EXPECTED_CONSTANT
, INCOMPLETE_ALLOWED
,
3239 OMIT_NOT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr());
3240 value_under_check
= false;
3241 chk_erroneous_attr();
3242 if (erroneous_attrs
) value
->set_err_descr(erroneous_attrs
->get_err_descr());
3244 ReferenceChain
refch(type
, "While checking embedded recursions");
3245 value
->chk_recursions(refch
);
3249 if (!semantic_check_only
) {
3250 value
->set_genname_prefix("const_");
3251 value
->set_genname_recursive(get_genname());
3252 value
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3256 bool Def_Const::chk_identical(Definition
*p_def
)
3260 if (p_def
->get_asstype() != A_CONST
) {
3261 const char *dispname_str
= id
->get_dispname().c_str();
3262 error("Local definition `%s' is a constant, but the definition "
3263 "inherited from component type `%s' is a %s", dispname_str
,
3264 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
3265 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
3268 Def_Const
*p_def_const
= dynamic_cast<Def_Const
*>(p_def
);
3269 if (!p_def_const
) FATAL_ERROR("Def_Const::chk_identical()");
3270 if (!type
->is_identical(p_def_const
->type
)) {
3271 const char *dispname_str
= id
->get_dispname().c_str();
3272 type
->error("Local constant `%s' has type `%s', but the constant "
3273 "inherited from component type `%s' has type `%s'", dispname_str
,
3274 type
->get_typename().c_str(),
3275 p_def_const
->get_my_scope()->get_fullname().c_str(),
3276 p_def_const
->type
->get_typename().c_str());
3277 p_def_const
->note("The inherited constant `%s' is here", dispname_str
);
3279 } else if (!(*value
== *p_def_const
->value
)) {
3280 const char *dispname_str
= id
->get_dispname().c_str();
3281 value
->error("Local constant `%s' and the constant inherited from "
3282 "component type `%s' have different values", dispname_str
,
3283 p_def_const
->get_my_scope()->get_fullname().c_str());
3284 p_def_const
->note("The inherited constant `%s' is here", dispname_str
);
3289 void Def_Const::generate_code(output_struct
*target
, bool)
3291 type
->generate_code(target
);
3293 Code::init_cdef(&cdef
);
3294 type
->generate_code_object(&cdef
, value
);
3295 cdef
.init
= update_location_object(cdef
.init
);
3296 cdef
.init
= value
->generate_code_init(cdef
.init
,
3297 value
->get_lhs_name().c_str());
3298 Code::merge_cdef(target
, &cdef
);
3299 Code::free_cdef(&cdef
);
3302 void Def_Const::generate_code(Common::CodeGenHelper
& cgh
) {
3303 // constant definitions always go to its containing module
3304 generate_code(cgh
.get_current_outputstruct());
3307 char *Def_Const::generate_code_str(char *str
)
3309 const string
& t_genname
= get_genname();
3310 const char *genname_str
= t_genname
.c_str();
3311 if (value
->has_single_expr()) {
3312 // the value can be represented by a single C++ expression
3313 // the object is initialized by the constructor
3314 str
= mputprintf(str
, "%s %s(%s);\n",
3315 type
->get_genname_value(my_scope
).c_str(), genname_str
,
3316 value
->get_single_expr().c_str());
3318 // use the default constructor
3319 str
= mputprintf(str
, "%s %s;\n",
3320 type
->get_genname_value(my_scope
).c_str(), genname_str
);
3321 // the value is assigned using subsequent statements
3322 str
= value
->generate_code_init(str
, genname_str
);
3327 void Def_Const::ilt_generate_code(ILT
*ilt
)
3329 const string
& t_genname
= get_genname();
3330 const char *genname_str
= t_genname
.c_str();
3331 char*& def
=ilt
->get_out_def();
3332 char*& init
=ilt
->get_out_branches();
3333 def
= mputprintf(def
, "%s %s;\n", type
->get_genname_value(my_scope
).c_str(),
3335 init
= value
->generate_code_init(init
, genname_str
);
3338 char *Def_Const::generate_code_init_comp(char *str
, Definition
*)
3340 /* This function actually does nothing as \a this and \a base_defn are
3341 * exactly the same. */
3345 void Def_Const::dump_internal(unsigned level
) const
3347 DEBUG(level
, "Constant: %s @%p", id
->get_dispname().c_str(), (const void*)this);
3348 type
->dump(level
+ 1);
3349 value
->dump(level
+ 1);
3352 // =================================
3353 // ===== Def_ExtConst
3354 // =================================
3356 Def_ExtConst::Def_ExtConst(Identifier
*p_id
, Type
*p_type
)
3357 : Definition(A_EXT_CONST
, p_id
)
3359 if (!p_type
) FATAL_ERROR("Ttcn::Def_ExtConst::Def_ExtConst()");
3361 type
->set_ownertype(Type::OT_CONST_DEF
, this);
3364 Def_ExtConst::~Def_ExtConst()
3369 Def_ExtConst
*Def_ExtConst::clone() const
3371 FATAL_ERROR("Def_ExtConst::clone");
3374 void Def_ExtConst::set_fullname(const string
& p_fullname
)
3376 Definition::set_fullname(p_fullname
);
3377 type
->set_fullname(p_fullname
+ ".<type>");
3380 void Def_ExtConst::set_my_scope(Scope
*p_scope
)
3382 Definition::set_my_scope(p_scope
);
3383 type
->set_my_scope(p_scope
);
3386 Type
*Def_ExtConst::get_Type()
3392 void Def_ExtConst::chk()
3395 Error_Context
cntxt(this, "In external constant definition `%s'",
3396 id
->get_dispname().c_str());
3397 type
->set_genname(_T_
, get_genname());
3400 Type
*t
= type
->get_type_refd_last();
3401 switch (t
->get_typetype()) {
3403 error("External constant cannot be defined for port type `%s'",
3404 t
->get_fullname().c_str());
3406 case Type::T_SIGNATURE
:
3407 error("External constant cannot be defined for signature `%s'",
3408 t
->get_fullname().c_str());
3413 if (w_attrib_path
) {
3414 w_attrib_path
->chk_global_attrib();
3415 switch (type
->get_type_refd_last()->get_typetype()) {
3418 case Type::T_CHOICE_T
:
3419 // These types may have qualified attributes
3421 case Type::T_SEQOF
: case Type::T_SETOF
:
3424 w_attrib_path
->chk_no_qualif();
3430 void Def_ExtConst::generate_code(output_struct
*target
, bool)
3432 type
->generate_code(target
);
3433 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
3434 "extern const %s& %s;\n", type
->get_genname_value(my_scope
).c_str(),
3435 get_genname().c_str());
3438 void Def_ExtConst::generate_code(Common::CodeGenHelper
& cgh
) {
3439 // constant definitions always go to its containing module
3440 generate_code(cgh
.get_current_outputstruct());
3443 void Def_ExtConst::dump_internal(unsigned level
) const
3445 DEBUG(level
, "External constant: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3446 type
->dump(level
+ 1);
3449 // =================================
3450 // ===== Def_Modulepar
3451 // =================================
3453 Def_Modulepar::Def_Modulepar(Identifier
*p_id
, Type
*p_type
, Value
*p_defval
)
3454 : Definition(A_MODULEPAR
, p_id
)
3456 if (!p_type
) FATAL_ERROR("Ttcn::Def_Modulepar::Def_Modulepar()");
3458 type
->set_ownertype(Type::OT_MODPAR_DEF
, this);
3459 def_value
= p_defval
;
3462 Def_Modulepar::~Def_Modulepar()
3468 Def_Modulepar
* Def_Modulepar::clone() const
3470 FATAL_ERROR("Def_Modulepar::clone");
3473 void Def_Modulepar::set_fullname(const string
& p_fullname
)
3475 Definition::set_fullname(p_fullname
);
3476 type
->set_fullname(p_fullname
+ ".<type>");
3477 if (def_value
) def_value
->set_fullname(p_fullname
+ ".<default_value>");
3480 void Def_Modulepar::set_my_scope(Scope
*p_scope
)
3482 Definition::set_my_scope(p_scope
);
3483 type
->set_my_scope(p_scope
);
3484 if (def_value
) def_value
->set_my_scope(p_scope
);
3487 Type
*Def_Modulepar::get_Type()
3493 void Def_Modulepar::chk()
3496 Error_Context
cntxt(this, "In module parameter definition `%s'",
3497 id
->get_dispname().c_str());
3498 type
->set_genname(_T_
, get_genname());
3500 if (w_attrib_path
) {
3501 w_attrib_path
->chk_global_attrib();
3502 switch (type
->get_type_refd_last()->get_typetype()) {
3505 case Type::T_CHOICE_T
:
3506 // These types may have qualified attributes
3508 case Type::T_SEQOF
: case Type::T_SETOF
:
3511 w_attrib_path
->chk_no_qualif();
3515 map
<Type
*,void> type_chain
;
3516 map
<Type::typetype_t
, void> not_allowed
;
3517 not_allowed
.add(Type::T_PORT
, 0);
3518 Type
*t
= type
->get_type_refd_last();
3519 // if the type is valid the original will be returned
3520 Type::typetype_t tt
= t
->search_for_not_allowed_type(type_chain
, not_allowed
);
3522 not_allowed
.clear();
3525 error("Type of module parameter cannot be or embed port type `%s'",
3526 t
->get_fullname().c_str());
3528 case Type::T_SIGNATURE
:
3529 error("Type of module parameter cannot be signature `%s'",
3530 t
->get_fullname().c_str());
3532 case Type::T_FUNCTION
:
3533 case Type::T_ALTSTEP
:
3534 case Type::T_TESTCASE
:
3535 if (t
->get_fat_runs_on_self()) {
3536 error("Type of module parameter cannot be of function reference type"
3537 " `%s' which has runs on self clause", t
->get_fullname().c_str());
3545 Error_Context
cntxt2(def_value
, "In default value");
3546 def_value
->set_my_governor(type
);
3547 type
->chk_this_value_ref(def_value
);
3549 type
->chk_this_value(def_value
, 0, Type::EXPECTED_CONSTANT
, INCOMPLETE_ALLOWED
,
3550 OMIT_NOT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr());
3551 if (!semantic_check_only
) {
3552 def_value
->set_genname_prefix("modulepar_");
3553 def_value
->set_genname_recursive(get_genname());
3554 def_value
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3556 } else checked
= true;
3562 void Def_Modulepar::generate_code(output_struct
*target
, bool)
3564 type
->generate_code(target
);
3566 Code::init_cdef(&cdef
);
3567 const string
& t_genname
= get_genname();
3568 const char *name
= t_genname
.c_str();
3569 type
->generate_code_object(&cdef
, my_scope
, t_genname
, "modulepar_", false);
3571 cdef
.init
= update_location_object(cdef
.init
);
3572 cdef
.init
= def_value
->generate_code_init(cdef
.init
, def_value
->get_lhs_name().c_str());
3574 Code::merge_cdef(target
, &cdef
);
3575 Code::free_cdef(&cdef
);
3577 if (has_implicit_omit_attr()) {
3578 target
->functions
.post_init
= mputprintf(target
->functions
.post_init
,
3579 "modulepar_%s.set_implicit_omit();\n", name
);
3582 const char *dispname
= id
->get_dispname().c_str();
3583 target
->functions
.set_param
= mputprintf(target
->functions
.set_param
,
3584 "if (!strcmp(par_name, \"%s\")) {\n"
3585 "modulepar_%s.set_param(param);\n"
3587 "} else ", dispname
, name
);
3589 if (target
->functions
.log_param
) {
3590 // this is not the first modulepar
3591 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3592 "TTCN_Logger::log_event_str(\", %s := \");\n", dispname
);
3594 // this is the first modulepar
3595 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3596 "TTCN_Logger::log_event_str(\"%s := \");\n", dispname
);
3598 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3599 "%s.log();\n", name
);
3602 void Def_Modulepar::generate_code(Common::CodeGenHelper
& cgh
) {
3603 // module parameter definitions always go to its containing module
3604 generate_code(cgh
.get_current_outputstruct());
3607 void Def_Modulepar::dump_internal(unsigned level
) const
3609 DEBUG(level
, "Module parameter: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3610 type
->dump(level
+ 1);
3611 if (def_value
) def_value
->dump(level
+ 1);
3612 else DEBUG(level
+ 1, "No default value");
3615 // =================================
3616 // ===== Def_Modulepar_Template
3617 // =================================
3619 Def_Modulepar_Template::Def_Modulepar_Template(Identifier
*p_id
, Type
*p_type
, Template
*p_deftmpl
)
3620 : Definition(A_MODULEPAR_TEMP
, p_id
)
3622 if (!p_type
) FATAL_ERROR("Ttcn::Def_Modulepar_Template::Def_Modulepar_Template()");
3624 type
->set_ownertype(Type::OT_MODPAR_DEF
, this);
3625 def_template
= p_deftmpl
;
3628 Def_Modulepar_Template::~Def_Modulepar_Template()
3631 delete def_template
;
3634 Def_Modulepar_Template
* Def_Modulepar_Template::clone() const
3636 FATAL_ERROR("Def_Modulepar_Template::clone");
3639 void Def_Modulepar_Template::set_fullname(const string
& p_fullname
)
3641 Definition::set_fullname(p_fullname
);
3642 type
->set_fullname(p_fullname
+ ".<type>");
3643 if (def_template
) def_template
->set_fullname(p_fullname
+ ".<default_template>");
3646 void Def_Modulepar_Template::set_my_scope(Scope
*p_scope
)
3648 Definition::set_my_scope(p_scope
);
3649 type
->set_my_scope(p_scope
);
3650 if (def_template
) def_template
->set_my_scope(p_scope
);
3653 Type
*Def_Modulepar_Template::get_Type()
3659 void Def_Modulepar_Template::chk()
3662 Error_Context
cntxt(this, "In template module parameter definition `%s'",
3663 id
->get_dispname().c_str());
3664 if (w_attrib_path
) {
3665 w_attrib_path
->chk_global_attrib();
3666 switch (type
->get_type_refd_last()->get_typetype()) {
3669 case Type::T_CHOICE_T
:
3670 // These types may have qualified attributes
3672 case Type::T_SEQOF
: case Type::T_SETOF
:
3675 w_attrib_path
->chk_no_qualif();
3679 type
->set_genname(_T_
, get_genname());
3681 Type
*t
= type
->get_type_refd_last();
3682 switch (t
->get_typetype()) {
3684 error("Type of template module parameter cannot be port type `%s'",
3685 t
->get_fullname().c_str());
3687 case Type::T_SIGNATURE
:
3688 error("Type of template module parameter cannot be signature `%s'",
3689 t
->get_fullname().c_str());
3691 case Type::T_FUNCTION
:
3692 case Type::T_ALTSTEP
:
3693 case Type::T_TESTCASE
:
3694 if (t
->get_fat_runs_on_self()) {
3695 error("Type of template module parameter cannot be of function reference type"
3696 " `%s' which has runs on self clause", t
->get_fullname().c_str());
3700 if (has_implicit_omit_attr()) {
3701 error("Implicit omit not supported for template module parameters");
3707 Error_Context
cntxt2(def_template
, "In default template");
3708 def_template
->set_my_governor(type
);
3709 def_template
->flatten(false);
3710 if (def_template
->get_templatetype() == Template::CSTR_PATTERN
&&
3711 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
3712 def_template
->set_templatetype(Template::USTR_PATTERN
);
3713 def_template
->get_ustr_pattern()->set_pattern_type(
3714 PatternString::USTR_PATTERN
);
3716 type
->chk_this_template_ref(def_template
);
3718 type
->chk_this_template_generic(def_template
, INCOMPLETE_ALLOWED
,
3719 OMIT_ALLOWED
, ANY_OR_OMIT_ALLOWED
, SUB_CHK
, has_implicit_omit_attr() ? IMPLICIT_OMIT
: NOT_IMPLICIT_OMIT
, 0);
3720 if (!semantic_check_only
) {
3721 def_template
->set_genname_prefix("modulepar_");
3722 def_template
->set_genname_recursive(get_genname());
3723 def_template
->set_code_section(GovernedSimple::CS_PRE_INIT
);
3725 } else checked
= true;
3731 void Def_Modulepar_Template::generate_code(output_struct
*target
, bool)
3733 type
->generate_code(target
);
3735 Code::init_cdef(&cdef
);
3736 const string
& t_genname
= get_genname();
3737 const char *name
= t_genname
.c_str();
3738 type
->generate_code_object(&cdef
, my_scope
, t_genname
, "modulepar_", true);
3740 cdef
.init
= update_location_object(cdef
.init
);
3741 cdef
.init
= def_template
->generate_code_init(cdef
.init
, def_template
->get_lhs_name().c_str());
3743 Code::merge_cdef(target
, &cdef
);
3744 Code::free_cdef(&cdef
);
3746 if (has_implicit_omit_attr()) {
3747 FATAL_ERROR("Def_Modulepar_Template::generate_code()");
3750 const char *dispname
= id
->get_dispname().c_str();
3751 target
->functions
.set_param
= mputprintf(target
->functions
.set_param
,
3752 "if (!strcmp(par_name, \"%s\")) {\n"
3753 "modulepar_%s.set_param(param);\n"
3755 "} else ", dispname
, name
);
3757 if (target
->functions
.log_param
) {
3758 // this is not the first modulepar
3759 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3760 "TTCN_Logger::log_event_str(\", %s := \");\n", dispname
);
3762 // this is the first modulepar
3763 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3764 "TTCN_Logger::log_event_str(\"%s := \");\n", dispname
);
3766 target
->functions
.log_param
= mputprintf(target
->functions
.log_param
,
3767 "%s.log();\n", name
);
3770 void Def_Modulepar_Template::generate_code(Common::CodeGenHelper
& cgh
) {
3771 // module parameter definitions always go to its containing module
3772 generate_code(cgh
.get_current_outputstruct());
3775 void Def_Modulepar_Template::dump_internal(unsigned level
) const
3777 DEBUG(level
, "Module parameter: %s @ %p", id
->get_dispname().c_str(), (const void*)this);
3778 type
->dump(level
+ 1);
3779 if (def_template
) def_template
->dump(level
+ 1);
3780 else DEBUG(level
+ 1, "No default template");
3783 // =================================
3784 // ===== Def_Template
3785 // =================================
3787 Def_Template::Def_Template(template_restriction_t p_template_restriction
,
3788 Identifier
*p_id
, Type
*p_type
, FormalParList
*p_fpl
,
3789 Reference
*p_derived_ref
, Template
*p_body
)
3790 : Definition(A_TEMPLATE
, p_id
), type(p_type
), fp_list(p_fpl
),
3791 derived_ref(p_derived_ref
), base_template(0), recurs_deriv_checked(false),
3792 body(p_body
), template_restriction(p_template_restriction
),
3793 gen_restriction_check(false)
3795 if (!p_type
|| !p_body
) FATAL_ERROR("Ttcn::Def_Template::Def_Template()");
3796 type
->set_ownertype(Type::OT_TEMPLATE_DEF
, this);
3797 if (fp_list
) fp_list
->set_my_def(this);
3800 Def_Template::~Def_Template()
3808 Def_Template
*Def_Template::clone() const
3810 FATAL_ERROR("Def_Template::clone");
3813 void Def_Template::set_fullname(const string
& p_fullname
)
3815 Definition::set_fullname(p_fullname
);
3816 type
->set_fullname(p_fullname
+ ".<type>");
3817 if (fp_list
) fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
3819 derived_ref
->set_fullname(p_fullname
+ ".<derived_reference>");
3820 body
->set_fullname(p_fullname
);
3823 void Def_Template::set_my_scope(Scope
*p_scope
)
3825 bridgeScope
.set_parent_scope(p_scope
);
3826 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
3828 Definition::set_my_scope(&bridgeScope
);
3829 type
->set_my_scope(&bridgeScope
);
3830 if (derived_ref
) derived_ref
->set_my_scope(&bridgeScope
);
3832 fp_list
->set_my_scope(&bridgeScope
);
3833 body
->set_my_scope(fp_list
);
3834 } else body
->set_my_scope(&bridgeScope
);
3837 Setting
*Def_Template::get_Setting()
3839 return get_Template();
3842 Type
*Def_Template::get_Type()
3844 if (!checked
) chk();
3848 Template
*Def_Template::get_Template()
3850 if (!checked
) chk();
3854 FormalParList
*Def_Template::get_FormalParList()
3856 if (!checked
) chk();
3860 void Def_Template::chk()
3862 if (checked
) return;
3863 Error_Context
cntxt(this, "In template definition `%s'",
3864 id
->get_dispname().c_str());
3865 const string
& t_genname
= get_genname();
3866 type
->set_genname(_T_
, t_genname
);
3868 if (w_attrib_path
) {
3869 w_attrib_path
->chk_global_attrib(true);
3870 switch (type
->get_type_refd_last()->get_typetype_ttcn3()) {
3873 case Type::T_CHOICE_T
:
3874 // These types may have qualified attributes
3876 case Type::T_SEQOF
: case Type::T_SETOF
:
3879 w_attrib_path
->chk_no_qualif();
3885 fp_list
->chk(asstype
);
3886 if (local_scope
) error("Parameterized local template `%s' not supported",
3887 id
->get_dispname().c_str());
3890 // Merge the elements of "all from" into the list
3891 body
->flatten(false);
3893 body
->set_my_governor(type
);
3895 if (body
->get_templatetype() == Template::CSTR_PATTERN
&&
3896 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
3897 body
->set_templatetype(Template::USTR_PATTERN
);
3898 body
->get_ustr_pattern()->set_pattern_type(PatternString::USTR_PATTERN
);
3901 type
->chk_this_template_ref(body
);
3903 Type
*t
= type
->get_type_refd_last();
3904 if (t
->get_typetype() == Type::T_PORT
) {
3905 error("Template cannot be defined for port type `%s'",
3906 t
->get_fullname().c_str());
3909 chk_recursive_derivation();
3910 type
->chk_this_template_generic(body
, INCOMPLETE_ALLOWED
, OMIT_ALLOWED
,
3911 ANY_OR_OMIT_ALLOWED
, SUB_CHK
,
3912 has_implicit_omit_attr() ? IMPLICIT_OMIT
: NOT_IMPLICIT_OMIT
, 0);
3914 chk_erroneous_attr();
3915 if (erroneous_attrs
) body
->set_err_descr(erroneous_attrs
->get_err_descr());
3918 ReferenceChain
refch(type
, "While checking embedded recursions");
3919 body
->chk_recursions(refch
);
3921 if (template_restriction
!=TR_NONE
) {
3922 Error_Context
ec(this, "While checking template restriction `%s'",
3923 Template::get_restriction_name(template_restriction
));
3924 gen_restriction_check
=
3925 body
->chk_restriction("template definition", template_restriction
);
3926 if (fp_list
&& template_restriction
!=TR_PRESENT
) {
3927 size_t nof_fps
= fp_list
->get_nof_fps();
3928 for (size_t i
=0; i
<nof_fps
; i
++) {
3929 FormalPar
* fp
= fp_list
->get_fp_byIndex(i
);
3930 // if formal par is not template then skip restriction checking,
3931 // templates can have only `in' parameters
3932 if (fp
->get_asstype()!=A_PAR_TEMPL_IN
) continue;
3933 template_restriction_t fp_tr
= fp
->get_template_restriction();
3934 switch (template_restriction
) {
3943 fp
->error("Formal parameter with template restriction `%s' "
3944 "not allowed here", Template::get_restriction_name(fp_tr
));
3947 fp
->error("Formal parameter without template restriction "
3948 "not allowed here");
3951 FATAL_ERROR("Ttcn::Def_Template::chk()");
3955 FATAL_ERROR("Ttcn::Def_Template::chk()");
3960 if (!semantic_check_only
) {
3961 if (fp_list
) fp_list
->set_genname(t_genname
);
3962 body
->set_genname_prefix("template_");
3963 body
->set_genname_recursive(t_genname
);
3964 body
->set_code_section(fp_list
? GovernedSimple::CS_INLINE
:
3965 GovernedSimple::CS_POST_INIT
);
3970 void Def_Template::chk_default() const
3972 if (!fp_list
) FATAL_ERROR("Def_Template::chk_default()");
3974 if (fp_list
->has_notused_defval())
3975 fp_list
->error("Only modified templates are allowed to use the not "
3976 "used symbol (`-') as the default parameter");
3979 Common::Assignment
*ass
= derived_ref
->get_refd_assignment(false);
3980 if (!ass
|| ass
->get_asstype() != A_TEMPLATE
) return; // Work locally.
3981 Def_Template
*base
= dynamic_cast<Def_Template
*>(ass
);
3982 if (!base
) FATAL_ERROR("Def_Template::chk_default()");
3983 FormalParList
*base_fpl
= base
->get_FormalParList();
3984 size_t nof_base_fps
= base_fpl
? base_fpl
->get_nof_fps() : 0;
3985 size_t nof_local_fps
= fp_list
? fp_list
->get_nof_fps() : 0;
3986 size_t min_fps
= nof_base_fps
;
3987 if (nof_local_fps
< nof_base_fps
) min_fps
= nof_local_fps
;
3988 for (size_t i
= 0; i
< min_fps
; i
++) {
3989 FormalPar
*base_fp
= base_fpl
->get_fp_byIndex(i
);
3990 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
3991 if (local_fp
->has_notused_defval()) {
3992 if (base_fp
->has_defval()) {
3993 local_fp
->set_defval(base_fp
->get_defval());
3995 local_fp
->error("Not used symbol (`-') doesn't have the "
3996 "corresponding default parameter in the "
4001 // Additional parameters in the derived template with using the not used
4002 // symbol. TODO: Merge the loops.
4003 for (size_t i
= nof_base_fps
; i
< nof_local_fps
; i
++) {
4004 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4005 if (local_fp
->has_notused_defval())
4006 local_fp
->error("Not used symbol (`-') doesn't have the "
4007 "corresponding default parameter in the "
4012 void Def_Template::chk_modified()
4014 if (!derived_ref
) return;
4015 // Do not check the (non-existent) actual parameter list of the derived
4016 // reference against the formal parameter list of the base template.
4017 // According to TTCN-3 syntax the derived reference cannot have parameters
4018 // even if the base template is parameterized.
4019 Common::Assignment
*ass
= derived_ref
->get_refd_assignment(false);
4020 // Checking the existence and type compatibility of the base template.
4022 if (ass
->get_asstype() != A_TEMPLATE
) {
4023 derived_ref
->error("Reference to a template was expected in the "
4024 "`modifies' definition instead of %s",
4025 ass
->get_description().c_str());
4028 base_template
= dynamic_cast<Def_Template
*>(ass
);
4029 if (!base_template
) FATAL_ERROR("Def_Template::chk_modified()");
4030 Type
*base_type
= base_template
->get_Type();
4031 TypeCompatInfo
info_base(my_scope
->get_scope_mod(), type
, base_type
, true,
4033 TypeChain l_chain_base
;
4034 TypeChain r_chain_base
;
4035 if (!type
->is_compatible(base_type
, &info_base
, &l_chain_base
,
4037 if (info_base
.is_subtype_error()) {
4038 type
->error("%s", info_base
.get_subtype_error().c_str());
4040 if (!info_base
.is_erroneous()) {
4041 type
->error("The modified template has different type than base "
4042 "template `%s': `%s' was expected instead of `%s'",
4043 ass
->get_fullname().c_str(),
4044 base_type
->get_typename().c_str(),
4045 type
->get_typename().c_str());
4047 // Always use the format string.
4048 type
->error("%s", info_base
.get_error_str_str().c_str());
4051 if (info_base
.needs_conversion())
4052 body
->set_needs_conversion();
4054 // Check for restriction.
4055 if (Template::is_less_restrictive(base_template
->get_template_restriction(),
4056 template_restriction
)) {
4057 error("The template restriction is not the same or more "
4058 "restrictive as of base template `%s'", ass
->get_fullname().c_str());
4060 // Checking formal parameter lists.
4061 FormalParList
*base_fpl
= base_template
->get_FormalParList();
4062 size_t nof_base_fps
= base_fpl
? base_fpl
->get_nof_fps() : 0;
4063 size_t nof_local_fps
= fp_list
? fp_list
->get_nof_fps() : 0;
4065 if (nof_local_fps
< nof_base_fps
) {
4066 error("The modified template has fewer formal parameters than base "
4067 "template `%s': at least %lu parameter%s expected instead of %lu",
4068 ass
->get_fullname().c_str(), (unsigned long)nof_base_fps
,
4069 nof_base_fps
> 1 ? "s were" : " was", (unsigned long)nof_local_fps
);
4070 min_fps
= nof_local_fps
;
4071 } else min_fps
= nof_base_fps
;
4073 for (size_t i
= 0; i
< min_fps
; i
++) {
4074 FormalPar
*base_fp
= base_fpl
->get_fp_byIndex(i
);
4075 FormalPar
*local_fp
= fp_list
->get_fp_byIndex(i
);
4076 Error_Context
cntxt(local_fp
, "In formal parameter #%lu",
4077 (unsigned long)(i
+ 1));
4078 // Check for parameter kind equivalence (value or template).
4079 if (base_fp
->get_asstype() != local_fp
->get_asstype())
4080 local_fp
->error("The kind of parameter is not the same as in base "
4081 "template `%s': %s was expected instead of %s",
4082 ass
->get_fullname().c_str(), base_fp
->get_assname(),
4083 local_fp
->get_assname());
4084 // Check for type compatibility.
4085 Type
*base_fp_type
= base_fp
->get_Type();
4086 Type
*local_fp_type
= local_fp
->get_Type();
4087 TypeCompatInfo
info_par(my_scope
->get_scope_mod(), base_fp_type
,
4088 local_fp_type
, true, false);
4089 TypeChain l_chain_par
;
4090 TypeChain r_chain_par
;
4091 if (!base_fp_type
->is_compatible(local_fp_type
, &info_par
, &l_chain_par
,
4093 if (info_par
.is_subtype_error()) {
4094 local_fp_type
->error("%s", info_par
.get_subtype_error().c_str());
4096 if (!info_par
.is_erroneous()) {
4097 local_fp_type
->error("The type of parameter is not the same as in "
4098 "base template `%s': `%s' was expected instead "
4100 ass
->get_fullname().c_str(),
4101 base_fp_type
->get_typename().c_str(),
4102 local_fp_type
->get_typename().c_str());
4104 local_fp_type
->error("%s", info_par
.get_error_str_str().c_str());
4107 if (info_par
.needs_conversion())
4108 body
->set_needs_conversion();
4110 // Check for name equivalence.
4111 const Identifier
& base_fp_id
= base_fp
->get_id();
4112 const Identifier
& local_fp_id
= local_fp
->get_id();
4113 if (!(base_fp_id
== local_fp_id
))
4114 local_fp
->error("The name of parameter is not the same as in base "
4115 "template `%s': `%s' was expected instead of `%s'",
4116 ass
->get_fullname().c_str(),
4117 base_fp_id
.get_dispname().c_str(),
4118 local_fp_id
.get_dispname().c_str());
4119 // Check for restrictions: the derived must be same or more restrictive.
4120 if (base_fp
->get_asstype()==local_fp
->get_asstype() &&
4121 Template::is_less_restrictive(base_fp
->get_template_restriction(),
4122 local_fp
->get_template_restriction())) {
4123 local_fp
->error("The restriction of parameter is not the same or more "
4124 "restrictive as in base template `%s'", ass
->get_fullname().c_str());
4127 // Set the pointer to the body of base template.
4128 body
->set_base_template(base_template
->get_Template());
4131 void Def_Template::chk_recursive_derivation()
4133 if (recurs_deriv_checked
) return;
4134 if (base_template
) {
4135 ReferenceChain
refch(this, "While checking the chain of base templates");
4136 refch
.add(get_fullname());
4137 for (Def_Template
*iter
= base_template
; iter
; iter
= iter
->base_template
)
4139 if (iter
->recurs_deriv_checked
) break;
4140 else if (refch
.add(iter
->get_fullname()))
4141 iter
->recurs_deriv_checked
= true;
4145 recurs_deriv_checked
= true;
4148 void Def_Template::generate_code(output_struct
*target
, bool)
4150 type
->generate_code(target
);
4152 // Parameterized template. Generate code for a function which returns
4153 // a $(genname)_template and has the appropriate parameters.
4154 const string
& t_genname
= get_genname();
4155 const char *template_name
= t_genname
.c_str();
4156 const char *template_dispname
= id
->get_dispname().c_str();
4157 const string
& type_genname
= type
->get_genname_template(my_scope
);
4158 const char *type_genname_str
= type_genname
.c_str();
4159 char *formal_par_list
= fp_list
->generate_code(memptystr());
4160 fp_list
->generate_code_defval(target
);
4161 target
->header
.function_prototypes
=
4162 mputprintf(target
->header
.function_prototypes
,
4163 "extern %s %s(%s);\n",
4164 type_genname_str
, template_name
, formal_par_list
);
4165 char *function_body
= mprintf("%s %s(%s)\n"
4166 "{\n", type_genname_str
, template_name
, formal_par_list
);
4167 function_body
= create_location_object(function_body
, "TEMPLATE",
4169 if (base_template
) {
4170 // modified template
4171 function_body
= mputprintf(function_body
, "%s ret_val(%s",
4173 base_template
->get_genname_from_scope(my_scope
).c_str());
4174 if (base_template
->fp_list
) {
4175 // the base template is also parameterized
4176 function_body
= mputc(function_body
, '(');
4177 size_t nof_base_pars
= base_template
->fp_list
->get_nof_fps();
4178 for (size_t i
= 0; i
< nof_base_pars
; i
++) {
4179 if (i
> 0) function_body
= mputstr(function_body
, ", ");
4180 function_body
= mputstr(function_body
,
4181 fp_list
->get_fp_byIndex(i
)->get_id().get_name().c_str());
4183 function_body
= mputc(function_body
, ')');
4185 function_body
= mputstr(function_body
, ");\n");
4188 function_body
= mputprintf(function_body
, "%s ret_val;\n",
4191 if (erroneous_attrs
&& erroneous_attrs
->get_err_descr()) {
4192 function_body
= erroneous_attrs
->get_err_descr()->
4193 generate_code_str(function_body
, string("ret_val"));
4195 function_body
= body
->generate_code_init(function_body
, "ret_val");
4196 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4197 function_body
= Template::generate_restriction_check_code(function_body
,
4198 "ret_val", template_restriction
);
4199 function_body
= mputstr(function_body
, "return ret_val;\n"
4201 target
->source
.function_bodies
=
4202 mputstr(target
->source
.function_bodies
, function_body
);
4203 Free(formal_par_list
);
4204 Free(function_body
);
4206 // non-parameterized template
4208 Code::init_cdef(&cdef
);
4209 type
->generate_code_object(&cdef
, body
);
4210 cdef
.init
= update_location_object(cdef
.init
);
4211 if (base_template
) {
4212 // modified template
4213 if (base_template
->my_scope
->get_scope_mod_gen() ==
4214 my_scope
->get_scope_mod_gen()) {
4215 // if the base template is in the same module its body has to be
4216 // initialized first
4217 cdef
.init
= base_template
->body
->generate_code_init(cdef
.init
,
4218 base_template
->body
->get_lhs_name().c_str());
4220 if (use_runtime_2
&& body
->get_needs_conversion()) {
4221 Type
*body_type
= body
->get_my_governor()->get_type_refd_last();
4222 Type
*base_type
= base_template
->body
->get_my_governor()
4223 ->get_type_refd_last();
4224 if (!body_type
|| !base_type
)
4225 FATAL_ERROR("Def_Template::generate_code()");
4226 const string
& tmp_id
= body
->get_temporary_id();
4227 const char *tmp_id_str
= tmp_id
.c_str();
4228 // base template initialization
4229 cdef
.init
= mputprintf(cdef
.init
,
4231 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' "
4232 "and `%s' are not compatible at run-time\");\n"
4234 body_type
->get_genname_template(my_scope
).c_str(), tmp_id_str
,
4235 TypeConv::get_conv_func(base_type
, body_type
, my_scope
4236 ->get_scope_mod()).c_str(), tmp_id_str
, base_template
4237 ->get_genname_from_scope(my_scope
).c_str(), base_type
4238 ->get_typename().c_str(), body_type
->get_typename().c_str(),
4239 body
->get_lhs_name().c_str(), tmp_id_str
);
4241 cdef
.init
= mputprintf(cdef
.init
, "%s = %s;\n",
4242 body
->get_lhs_name().c_str(),
4243 base_template
->get_genname_from_scope(my_scope
).c_str());
4246 if (use_runtime_2
&& TypeConv::needs_conv_refd(body
))
4247 cdef
.init
= TypeConv::gen_conv_code_refd(cdef
.init
,
4248 body
->get_lhs_name().c_str(), body
);
4250 cdef
.init
= body
->generate_code_init(cdef
.init
,
4251 body
->get_lhs_name().c_str());
4252 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4253 cdef
.init
= Template::generate_restriction_check_code(cdef
.init
,
4254 body
->get_lhs_name().c_str(), template_restriction
);
4255 target
->header
.global_vars
= mputstr(target
->header
.global_vars
,
4257 target
->source
.global_vars
= mputstr(target
->source
.global_vars
,
4259 target
->functions
.post_init
= mputstr(target
->functions
.post_init
,
4261 Code::free_cdef(&cdef
);
4265 void Def_Template::generate_code(Common::CodeGenHelper
& cgh
) {
4266 generate_code(cgh
.get_outputstruct(this));
4269 char *Def_Template::generate_code_str(char *str
)
4271 const string
& t_genname
= get_genname();
4272 const char *genname_str
= t_genname
.c_str();
4273 const string
& type_genname
= type
->get_genname_template(my_scope
);
4274 const char *type_genname_str
= type_genname
.c_str();
4276 const char *dispname_str
= id
->get_dispname().c_str();
4277 NOTSUPP("Code generation for parameterized local template `%s'",
4279 str
= mputprintf(str
, "/* NOT SUPPORTED: template %s */\n",
4282 if (base_template
) {
4283 // non-parameterized modified template
4284 if (use_runtime_2
&& body
->get_needs_conversion()) {
4285 Type
*body_type
= body
->get_my_governor()->get_type_refd_last();
4286 Type
*base_type
= base_template
->body
->get_my_governor()
4287 ->get_type_refd_last();
4288 if (!body_type
|| !base_type
)
4289 FATAL_ERROR("Def_Template::generate_code_str()");
4290 const string
& tmp_id
= body
->get_temporary_id();
4291 const char *tmp_id_str
= tmp_id
.c_str();
4292 str
= mputprintf(str
,
4294 "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' "
4295 "and `%s' are not compatible at run-time\");\n"
4297 body_type
->get_genname_template(my_scope
).c_str(), tmp_id_str
,
4298 TypeConv::get_conv_func(base_type
, body_type
, my_scope
4299 ->get_scope_mod()).c_str(), tmp_id_str
, base_template
4300 ->get_genname_from_scope(my_scope
).c_str(), base_type
4301 ->get_typename().c_str(), body_type
->get_typename().c_str(),
4302 type_genname_str
, genname_str
, tmp_id_str
);
4304 // the object is initialized from the base template by the
4306 str
= mputprintf(str
, "%s %s(%s);\n", type_genname_str
, genname_str
,
4307 base_template
->get_genname_from_scope(my_scope
).c_str());
4309 // the modified body is assigned in the subsequent statements
4310 str
= body
->generate_code_init(str
, genname_str
);
4312 // non-parameterized non-modified template
4313 if (body
->has_single_expr()) {
4314 // the object is initialized by the constructor
4315 str
= mputprintf(str
, "%s %s(%s);\n", type_genname_str
,
4316 genname_str
, body
->get_single_expr(false).c_str());
4318 // the default constructor is used
4319 str
= mputprintf(str
, "%s %s;\n", type_genname_str
, genname_str
);
4320 // the body is assigned in the subsequent statements
4321 str
= body
->generate_code_init(str
, genname_str
);
4324 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4325 str
= Template::generate_restriction_check_code(str
, genname_str
,
4326 template_restriction
);
4331 void Def_Template::ilt_generate_code(ILT
*ilt
)
4333 const string
& t_genname
= get_genname();
4334 const char *genname_str
= t_genname
.c_str();
4335 char*& def
=ilt
->get_out_def();
4336 char*& init
=ilt
->get_out_branches();
4338 const char *dispname_str
= id
->get_dispname().c_str();
4339 NOTSUPP("Code generation for parameterized local template `%s'",
4341 def
= mputprintf(def
, "/* NOT SUPPORTED: template %s */\n", dispname_str
);
4342 init
= mputprintf(init
, "/* NOT SUPPORTED: template %s */\n",
4345 // non-parameterized template
4346 // use the default constructor for initialization
4347 def
= mputprintf(def
, "%s %s;\n",
4348 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4349 if (base_template
) {
4350 // copy the base template with an assignment
4351 init
= mputprintf(init
, "%s = %s;\n", genname_str
,
4352 base_template
->get_genname_from_scope(my_scope
).c_str());
4354 // finally assign the body
4355 init
= body
->generate_code_init(init
, genname_str
);
4356 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4357 init
= Template::generate_restriction_check_code(init
, genname_str
,
4358 template_restriction
);
4362 void Def_Template::dump_internal(unsigned level
) const
4364 DEBUG(level
, "Template: %s", id
->get_dispname().c_str());
4365 if (fp_list
) fp_list
->dump(level
+ 1);
4367 DEBUG(level
+ 1, "modifies: %s", derived_ref
->get_dispname().c_str());
4368 if (template_restriction
!=TR_NONE
)
4369 DEBUG(level
+ 1, "restriction: %s",
4370 Template::get_restriction_name(template_restriction
));
4371 type
->dump(level
+ 1);
4372 body
->dump(level
+ 1);
4375 // =================================
4377 // =================================
4379 Def_Var::Def_Var(Identifier
*p_id
, Type
*p_type
, Value
*p_initial_value
)
4380 : Definition(A_VAR
, p_id
), type(p_type
), initial_value(p_initial_value
)
4382 if (!p_type
) FATAL_ERROR("Ttcn::Def_Var::Def_Var()");
4383 type
->set_ownertype(Type::OT_VAR_DEF
, this);
4389 delete initial_value
;
4392 Def_Var
*Def_Var::clone() const
4394 FATAL_ERROR("Def_Var::clone");
4397 void Def_Var::set_fullname(const string
& p_fullname
)
4399 Definition::set_fullname(p_fullname
);
4400 type
->set_fullname(p_fullname
+ ".<type>");
4402 initial_value
->set_fullname(p_fullname
+ ".<initial_value>");
4405 void Def_Var::set_my_scope(Scope
*p_scope
)
4407 Definition::set_my_scope(p_scope
);
4408 type
->set_my_scope(p_scope
);
4409 if (initial_value
) initial_value
->set_my_scope(p_scope
);
4412 Type
*Def_Var::get_Type()
4421 Error_Context
cntxt(this, "In variable definition `%s'",
4422 id
->get_dispname().c_str());
4423 type
->set_genname(_T_
, get_genname());
4426 Type
*t
= type
->get_type_refd_last();
4427 switch (t
->get_typetype()) {
4429 error("Variable cannot be defined for port type `%s'",
4430 t
->get_fullname().c_str());
4432 case Type::T_SIGNATURE
:
4433 error("Variable cannot be defined for signature `%s'",
4434 t
->get_fullname().c_str());
4437 if (initial_value
) {
4438 initial_value
->set_my_governor(type
);
4439 type
->chk_this_value_ref(initial_value
);
4440 type
->chk_this_value(initial_value
, this, is_local() ?
4441 Type::EXPECTED_DYNAMIC_VALUE
: Type::EXPECTED_STATIC_VALUE
,
4442 INCOMPLETE_ALLOWED
, OMIT_NOT_ALLOWED
, SUB_CHK
);
4443 if (!semantic_check_only
) {
4444 initial_value
->set_genname_recursive(get_genname());
4445 initial_value
->set_code_section(GovernedSimple::CS_INLINE
);
4451 if (w_attrib_path
) {
4452 w_attrib_path
->chk_global_attrib();
4453 w_attrib_path
->chk_no_qualif();
4457 bool Def_Var::chk_identical(Definition
*p_def
)
4461 if (p_def
->get_asstype() != A_VAR
) {
4462 const char *dispname_str
= id
->get_dispname().c_str();
4463 error("Local definition `%s' is a variable, but the definition "
4464 "inherited from component type `%s' is a %s", dispname_str
,
4465 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4466 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4469 Def_Var
*p_def_var
= dynamic_cast<Def_Var
*>(p_def
);
4470 if (!p_def_var
) FATAL_ERROR("Def_Var::chk_identical()");
4471 if (!type
->is_identical(p_def_var
->type
)) {
4472 const char *dispname_str
= id
->get_dispname().c_str();
4473 type
->error("Local variable `%s' has type `%s', but the variable "
4474 "inherited from component type `%s' has type `%s'", dispname_str
,
4475 type
->get_typename().c_str(),
4476 p_def_var
->get_my_scope()->get_fullname().c_str(),
4477 p_def_var
->type
->get_typename().c_str());
4478 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4481 if (initial_value
) {
4482 if (p_def_var
->initial_value
) {
4483 if (!initial_value
->is_unfoldable() &&
4484 !p_def_var
->initial_value
->is_unfoldable() &&
4485 !(*initial_value
== *p_def_var
->initial_value
)) {
4486 const char *dispname_str
= id
->get_dispname().c_str();
4487 initial_value
->warning("Local variable `%s' and the variable "
4488 "inherited from component type `%s' have different initial values",
4489 dispname_str
, p_def_var
->get_my_scope()->get_fullname().c_str());
4490 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4493 const char *dispname_str
= id
->get_dispname().c_str();
4494 initial_value
->warning("Local variable `%s' has initial value, but "
4495 "the variable inherited from component type `%s' does not",
4496 dispname_str
, p_def_var
->get_my_scope()->get_fullname().c_str());
4497 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4499 } else if (p_def_var
->initial_value
) {
4500 const char *dispname_str
= id
->get_dispname().c_str();
4501 warning("Local variable `%s' does not have initial value, but the "
4502 "variable inherited from component type `%s' has", dispname_str
,
4503 p_def_var
->get_my_scope()->get_fullname().c_str());
4504 p_def_var
->note("The inherited variable `%s' is here", dispname_str
);
4509 void Def_Var::generate_code(output_struct
*target
, bool clean_up
)
4511 type
->generate_code(target
);
4513 Code::init_cdef(&cdef
);
4514 type
->generate_code_object(&cdef
, my_scope
, get_genname(), 0, false);
4515 Code::merge_cdef(target
, &cdef
);
4516 Code::free_cdef(&cdef
);
4517 if (initial_value
) {
4518 target
->functions
.init_comp
=
4519 initial_value
->generate_code_init(target
->functions
.init_comp
,
4520 initial_value
->get_lhs_name().c_str());
4521 } else if (clean_up
) { // No initial value.
4522 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4523 "%s.clean_up();\n", get_genname().c_str());
4527 void Def_Var::generate_code(CodeGenHelper
& cgh
)
4529 generate_code(cgh
.get_outputstruct(this));
4532 char *Def_Var::generate_code_str(char *str
)
4534 const string
& t_genname
= get_genname();
4535 const char *genname_str
= t_genname
.c_str();
4536 if (initial_value
&& initial_value
->has_single_expr()) {
4537 // the initial value can be represented by a single C++ expression
4538 // the object is initialized by the constructor
4539 str
= mputprintf(str
, "%s %s(%s);\n",
4540 type
->get_genname_value(my_scope
).c_str(), genname_str
,
4541 initial_value
->get_single_expr().c_str());
4543 // use the default constructor
4544 str
= mputprintf(str
, "%s %s;\n",
4545 type
->get_genname_value(my_scope
).c_str(), genname_str
);
4546 if (initial_value
) {
4547 // the initial value is assigned using subsequent statements
4548 str
= initial_value
->generate_code_init(str
, genname_str
);
4554 void Def_Var::ilt_generate_code(ILT
*ilt
)
4556 const string
& t_genname
= get_genname();
4557 const char *genname_str
= t_genname
.c_str();
4558 char*& def
=ilt
->get_out_def();
4559 char*& init
=ilt
->get_out_branches();
4560 def
= mputprintf(def
, "%s %s;\n", type
->get_genname_value(my_scope
).c_str(),
4563 init
= initial_value
->generate_code_init(init
, genname_str
);
4566 char *Def_Var::generate_code_init_comp(char *str
, Definition
*base_defn
)
4568 if (initial_value
) {
4569 str
= initial_value
->generate_code_init(str
,
4570 base_defn
->get_genname_from_scope(my_scope
).c_str());
4575 void Def_Var::dump_internal(unsigned level
) const
4577 DEBUG(level
, "Variable %s", id
->get_dispname().c_str());
4578 type
->dump(level
+ 1);
4579 if (initial_value
) initial_value
->dump(level
+ 1);
4582 // =================================
4583 // ===== Def_Var_Template
4584 // =================================
4586 Def_Var_Template::Def_Var_Template(Identifier
*p_id
, Type
*p_type
,
4587 Template
*p_initial_value
, template_restriction_t p_template_restriction
)
4588 : Definition(A_VAR_TEMPLATE
, p_id
), type(p_type
),
4589 initial_value(p_initial_value
), template_restriction(p_template_restriction
)
4591 if (!p_type
) FATAL_ERROR("Ttcn::Def_Var_Template::Def_Var_Template()");
4592 type
->set_ownertype(Type::OT_VARTMPL_DEF
, this);
4595 Def_Var_Template::~Def_Var_Template()
4598 delete initial_value
;
4601 Def_Var_Template
*Def_Var_Template::clone() const
4603 FATAL_ERROR("Def_Var_Template::clone");
4606 void Def_Var_Template::set_fullname(const string
& p_fullname
)
4608 Definition::set_fullname(p_fullname
);
4609 type
->set_fullname(p_fullname
+ ".<type>");
4611 initial_value
->set_fullname(p_fullname
+ ".<initial_value>");
4614 void Def_Var_Template::set_my_scope(Scope
*p_scope
)
4616 Definition::set_my_scope(p_scope
);
4617 type
->set_my_scope(p_scope
);
4618 if (initial_value
) initial_value
->set_my_scope(p_scope
);
4621 Type
*Def_Var_Template::get_Type()
4627 void Def_Var_Template::chk()
4630 Error_Context
cntxt(this, "In template variable definition `%s'",
4631 id
->get_dispname().c_str());
4632 type
->set_genname(_T_
, get_genname());
4635 Type
*t
= type
->get_type_refd_last();
4636 if (t
->get_typetype() == Type::T_PORT
) {
4637 error("Template variable cannot be defined for port type `%s'",
4638 t
->get_fullname().c_str());
4641 if (initial_value
) {
4642 initial_value
->set_my_governor(type
);
4643 initial_value
->flatten(false);
4645 if (initial_value
->get_templatetype() == Template::CSTR_PATTERN
&&
4646 type
->get_type_refd_last()->get_typetype() == Type::T_USTR
) {
4647 initial_value
->set_templatetype(Template::USTR_PATTERN
);
4648 initial_value
->get_ustr_pattern()->set_pattern_type(
4649 PatternString::USTR_PATTERN
);
4652 type
->chk_this_template_ref(initial_value
);
4653 // temporary hack: to allow incomplete body as initial value
4654 // checking as a modified template, but without a base template
4655 type
->chk_this_template_generic(initial_value
, INCOMPLETE_ALLOWED
,
4656 OMIT_ALLOWED
, ANY_OR_OMIT_ALLOWED
, SUB_CHK
, IMPLICIT_OMIT
, 0);
4657 gen_restriction_check
=
4658 initial_value
->chk_restriction("template variable definition",
4659 template_restriction
);
4660 if (!semantic_check_only
) {
4661 initial_value
->set_genname_recursive(get_genname());
4662 initial_value
->set_code_section(GovernedSimple::CS_INLINE
);
4665 if (w_attrib_path
) {
4666 w_attrib_path
->chk_global_attrib();
4667 w_attrib_path
->chk_no_qualif();
4671 bool Def_Var_Template::chk_identical(Definition
*p_def
)
4675 if (p_def
->get_asstype() != A_VAR_TEMPLATE
) {
4676 const char *dispname_str
= id
->get_dispname().c_str();
4677 error("Local definition `%s' is a template variable, but the definition "
4678 "inherited from component type `%s' is a %s", dispname_str
,
4679 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4680 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4683 Def_Var_Template
*p_def_var_template
=
4684 dynamic_cast<Def_Var_Template
*>(p_def
);
4685 if (!p_def_var_template
) FATAL_ERROR("Def_Var_Template::chk_identical()");
4686 if (!type
->is_identical(p_def_var_template
->type
)) {
4687 const char *dispname_str
= id
->get_dispname().c_str();
4688 type
->error("Local template variable `%s' has type `%s', but the "
4689 "template variable inherited from component type `%s' has type `%s'",
4690 dispname_str
, type
->get_typename().c_str(),
4691 p_def_var_template
->get_my_scope()->get_fullname().c_str(),
4692 p_def_var_template
->type
->get_typename().c_str());
4693 p_def_var_template
->note("The inherited template variable `%s' is here",
4697 if (initial_value
) {
4698 if (!p_def_var_template
->initial_value
) {
4699 const char *dispname_str
= id
->get_dispname().c_str();
4700 initial_value
->warning("Local template variable `%s' has initial "
4701 "value, but the template variable inherited from component type "
4702 "`%s' does not", dispname_str
,
4703 p_def_var_template
->get_my_scope()->get_fullname().c_str());
4704 p_def_var_template
->note("The inherited template variable `%s' is here",
4707 } else if (p_def_var_template
->initial_value
) {
4708 const char *dispname_str
= id
->get_dispname().c_str();
4709 warning("Local template variable `%s' does not have initial value, but "
4710 "the template variable inherited from component type `%s' has",
4712 p_def_var_template
->get_my_scope()->get_fullname().c_str());
4713 p_def_var_template
->note("The inherited template variable `%s' is here",
4719 void Def_Var_Template::generate_code(output_struct
*target
, bool clean_up
)
4721 type
->generate_code(target
);
4723 Code::init_cdef(&cdef
);
4724 type
->generate_code_object(&cdef
, my_scope
, get_genname(), 0, true);
4725 Code::merge_cdef(target
, &cdef
);
4726 Code::free_cdef(&cdef
);
4727 if (initial_value
) {
4728 if (Common::Type::T_SEQOF
== initial_value
->get_my_governor()->get_typetype() ||
4729 Common::Type::T_ARRAY
== initial_value
->get_my_governor()->get_typetype()) {
4730 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4731 "%s.remove_all_permutations();\n", initial_value
->get_lhs_name().c_str());
4733 target
->functions
.init_comp
=
4734 initial_value
->generate_code_init(target
->functions
.init_comp
,
4735 initial_value
->get_lhs_name().c_str());
4736 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4737 target
->functions
.init_comp
= Template::generate_restriction_check_code(
4738 target
->functions
.init_comp
, initial_value
->get_lhs_name().c_str(),
4739 template_restriction
);
4740 } else if (clean_up
) { // No initial value.
4741 // Always reset component variables/variable templates on component
4742 // reinitialization. Fix for HM79493.
4743 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
4744 "%s.clean_up();\n", get_genname().c_str());
4748 void Def_Var_Template::generate_code(CodeGenHelper
& cgh
)
4750 generate_code(cgh
.get_outputstruct(this));
4753 char *Def_Var_Template::generate_code_str(char *str
)
4755 const string
& t_genname
= get_genname();
4756 const char *genname_str
= t_genname
.c_str();
4757 if (initial_value
&& initial_value
->has_single_expr()) {
4758 // The initial value can be represented by a single C++ expression
4759 // the object is initialized by the constructor.
4760 str
= mputprintf(str
, "%s %s(%s);\n",
4761 type
->get_genname_template(my_scope
).c_str(), genname_str
,
4762 initial_value
->get_single_expr(false).c_str());
4764 // Use the default constructor.
4765 str
= mputprintf(str
, "%s %s;\n",
4766 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4767 if (initial_value
) {
4768 // The initial value is assigned using subsequent statements.
4769 if (use_runtime_2
&& TypeConv::needs_conv_refd(initial_value
))
4770 str
= TypeConv::gen_conv_code_refd(str
, genname_str
, initial_value
);
4771 else str
= initial_value
->generate_code_init(str
, genname_str
);
4774 if (initial_value
&& template_restriction
!= TR_NONE
4775 && gen_restriction_check
)
4776 str
= Template::generate_restriction_check_code(str
, genname_str
,
4777 template_restriction
);
4781 void Def_Var_Template::ilt_generate_code(ILT
*ilt
)
4783 const string
& t_genname
= get_genname();
4784 const char *genname_str
= t_genname
.c_str();
4785 char*& def
=ilt
->get_out_def();
4786 char*& init
=ilt
->get_out_branches();
4787 def
= mputprintf(def
, "%s %s;\n",
4788 type
->get_genname_template(my_scope
).c_str(), genname_str
);
4789 if (initial_value
) {
4790 init
= initial_value
->generate_code_init(init
, genname_str
);
4791 if (template_restriction
!=TR_NONE
&& gen_restriction_check
)
4792 init
= Template::generate_restriction_check_code(init
, genname_str
,
4793 template_restriction
);
4797 char *Def_Var_Template::generate_code_init_comp(char *str
,
4798 Definition
*base_defn
)
4800 if (initial_value
) {
4801 str
= initial_value
->generate_code_init(str
,
4802 base_defn
->get_genname_from_scope(my_scope
).c_str());
4803 if (template_restriction
!= TR_NONE
&& gen_restriction_check
)
4804 str
= Template::generate_restriction_check_code(str
,
4805 base_defn
->get_genname_from_scope(my_scope
).c_str(),
4806 template_restriction
);
4811 void Def_Var_Template::dump_internal(unsigned level
) const
4813 DEBUG(level
, "Template variable %s", id
->get_dispname().c_str());
4814 if (template_restriction
!=TR_NONE
)
4815 DEBUG(level
+ 1, "restriction: %s",
4816 Template::get_restriction_name(template_restriction
));
4817 type
->dump(level
+ 1);
4818 if (initial_value
) initial_value
->dump(level
+ 1);
4821 // =================================
4823 // =================================
4825 Def_Timer::~Def_Timer()
4828 delete default_duration
;
4831 Def_Timer
*Def_Timer::clone() const
4833 FATAL_ERROR("Def_Timer::clone");
4836 void Def_Timer::set_fullname(const string
& p_fullname
)
4838 Definition::set_fullname(p_fullname
);
4839 if (dimensions
) dimensions
->set_fullname(p_fullname
+ ".<dimensions>");
4840 if (default_duration
)
4841 default_duration
->set_fullname(p_fullname
+ ".<default_duration>");
4844 void Def_Timer::set_my_scope(Scope
*p_scope
)
4846 Definition::set_my_scope(p_scope
);
4847 if (dimensions
) dimensions
->set_my_scope(p_scope
);
4848 if (default_duration
) default_duration
->set_my_scope(p_scope
);
4851 ArrayDimensions
*Def_Timer::get_Dimensions()
4853 if (!checked
) chk();
4857 void Def_Timer::chk()
4860 Error_Context
cntxt(this, "In timer definition `%s'",
4861 id
->get_dispname().c_str());
4862 if (dimensions
) dimensions
->chk();
4863 if (default_duration
) {
4864 Error_Context
cntxt2(default_duration
, "In default duration");
4865 if (dimensions
) chk_array_duration(default_duration
);
4866 else chk_single_duration(default_duration
);
4867 if (!semantic_check_only
) {
4868 default_duration
->set_code_section(GovernedSimple::CS_POST_INIT
);
4872 if (w_attrib_path
) {
4873 w_attrib_path
->chk_global_attrib();
4874 w_attrib_path
->chk_no_qualif();
4878 bool Def_Timer::chk_identical(Definition
*p_def
)
4882 if (p_def
->get_asstype() != A_TIMER
) {
4883 const char *dispname_str
= id
->get_dispname().c_str();
4884 error("Local definition `%s' is a timer, but the definition inherited "
4885 "from component type `%s' is a %s", dispname_str
,
4886 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
4887 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
4890 Def_Timer
*p_def_timer
= dynamic_cast<Def_Timer
*>(p_def
);
4891 if (!p_def_timer
) FATAL_ERROR("Def_Timer::chk_identical()");
4893 if (p_def_timer
->dimensions
) {
4894 if (!dimensions
->is_identical(p_def_timer
->dimensions
)) {
4895 const char *dispname_str
= id
->get_dispname().c_str();
4896 error("Local timer `%s' and the timer inherited from component type "
4897 "`%s' have different array dimensions", dispname_str
,
4898 p_def_timer
->get_my_scope()->get_fullname().c_str());
4899 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4903 const char *dispname_str
= id
->get_dispname().c_str();
4904 error("Local definition `%s' is a timer array, but the definition "
4905 "inherited from component type `%s' is a single timer", dispname_str
,
4906 p_def_timer
->get_my_scope()->get_fullname().c_str());
4907 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4910 } else if (p_def_timer
->dimensions
) {
4911 const char *dispname_str
= id
->get_dispname().c_str();
4912 error("Local definition `%s' is a single timer, but the definition "
4913 "inherited from component type `%s' is a timer array", dispname_str
,
4914 p_def_timer
->get_my_scope()->get_fullname().c_str());
4915 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4918 if (default_duration
) {
4919 if (p_def_timer
->default_duration
) {
4920 if (!default_duration
->is_unfoldable() &&
4921 !p_def_timer
->default_duration
->is_unfoldable() &&
4922 !(*default_duration
== *p_def_timer
->default_duration
)) {
4923 const char *dispname_str
= id
->get_dispname().c_str();
4924 default_duration
->warning("Local timer `%s' and the timer inherited "
4925 "from component type `%s' have different default durations",
4926 dispname_str
, p_def_timer
->get_my_scope()->get_fullname().c_str());
4927 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4930 const char *dispname_str
= id
->get_dispname().c_str();
4931 default_duration
->error("Local timer `%s' has default duration, but "
4932 "the timer inherited from component type `%s' does not", dispname_str
,
4933 p_def_timer
->get_my_scope()->get_fullname().c_str());
4934 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4937 } else if (p_def_timer
->default_duration
) {
4938 const char *dispname_str
= id
->get_dispname().c_str();
4939 error("Local timer `%s' does not have default duration, but the timer "
4940 "inherited from component type `%s' has", dispname_str
,
4941 p_def_timer
->get_my_scope()->get_fullname().c_str());
4942 p_def_timer
->note("The inherited timer `%s' is here", dispname_str
);
4948 bool Def_Timer::has_default_duration(FieldOrArrayRefs
*p_subrefs
)
4950 // return true in case of any uncertainity
4951 if (!default_duration
) return false;
4952 else if (!dimensions
|| !p_subrefs
) return true;
4953 Value
*v
= default_duration
;
4954 size_t nof_dims
= dimensions
->get_nof_dims();
4955 size_t nof_refs
= p_subrefs
->get_nof_refs();
4956 size_t upper_limit
= nof_dims
< nof_refs
? nof_dims
: nof_refs
;
4957 for (size_t i
= 0; i
< upper_limit
; i
++) {
4958 v
= v
->get_value_refd_last();
4959 if (v
->get_valuetype() != Value::V_SEQOF
) break;
4960 FieldOrArrayRef
*ref
= p_subrefs
->get_ref(i
);
4961 if (ref
->get_type() != FieldOrArrayRef::ARRAY_REF
) return true;
4962 Value
*v_index
= ref
->get_val()->get_value_refd_last();
4963 if (v_index
->get_valuetype() != Value::V_INT
) return true;
4964 Int index
= v_index
->get_val_Int()->get_val()
4965 - dimensions
->get_dim_byIndex(i
)->get_offset();
4966 if (index
>= 0 && index
< static_cast<Int
>(v
->get_nof_comps()))
4967 v
= v
->get_comp_byIndex(index
);
4970 return v
->get_valuetype() != Value::V_NOTUSED
;
4973 void Def_Timer::chk_single_duration(Value
*dur
)
4975 dur
->chk_expr_float(is_local() ?
4976 Type::EXPECTED_DYNAMIC_VALUE
: Type::EXPECTED_STATIC_VALUE
);
4977 Value
*v
= dur
->get_value_refd_last();
4978 if (v
->get_valuetype() == Value::V_REAL
) {
4979 ttcn3float v_real
= v
->get_val_Real();
4980 if ( (v_real
<0.0) || isSpecialFloatValue(v_real
) ) {
4981 dur
->error("A non-negative float value was expected "
4982 "as timer duration instead of `%s'", Real2string(v_real
).c_str());
4987 void Def_Timer::chk_array_duration(Value
*dur
, size_t start_dim
)
4989 ArrayDimension
*dim
= dimensions
->get_dim_byIndex(start_dim
);
4990 bool array_size_known
= !dim
->get_has_error();
4991 size_t array_size
= 0;
4992 if (array_size_known
) array_size
= dim
->get_size();
4993 Value
*v
= dur
->get_value_refd_last();
4994 switch (v
->get_valuetype()) {
4995 case Value::V_ERROR
:
4997 case Value::V_SEQOF
: {
4998 size_t nof_vs
= v
->get_nof_comps();
4999 // Value-list notation.
5000 if (!v
->is_indexed()) {
5001 if (array_size_known
) {
5002 if (array_size
> nof_vs
) {
5003 dur
->error("Too few elements in the default duration of timer "
5004 "array: %lu was expected instead of %lu",
5005 (unsigned long)array_size
, (unsigned long)nof_vs
);
5006 } else if (array_size
< nof_vs
) {
5007 dur
->error("Too many elements in the default duration of timer "
5008 "array: %lu was expected instead of %lu",
5009 (unsigned long)array_size
, (unsigned long)nof_vs
);
5012 bool last_dimension
= start_dim
+ 1 >= dimensions
->get_nof_dims();
5013 for (size_t i
= 0; i
< nof_vs
; i
++) {
5014 Value
*array_v
= v
->get_comp_byIndex(i
);
5015 if (array_v
->get_valuetype() == Value::V_NOTUSED
) continue;
5016 if (last_dimension
) chk_single_duration(array_v
);
5017 else chk_array_duration(array_v
, start_dim
+ 1);
5020 // Indexed-notation.
5021 bool last_dimension
= start_dim
+ 1 >= dimensions
->get_nof_dims();
5022 map
<Int
, Int
> index_map
;
5023 for (size_t i
= 0; i
< nof_vs
; i
++) {
5024 Value
*array_v
= v
->get_comp_byIndex(i
);
5025 if (array_v
->get_valuetype() == Value::V_NOTUSED
) continue;
5026 if (last_dimension
) chk_single_duration(array_v
);
5027 else chk_array_duration(array_v
, start_dim
+ 1);
5028 Error_Context
cntxt(this, "In timer array element %lu",
5029 (unsigned long)(i
+ 1));
5030 Value
*index
= v
->get_index_byIndex(i
);
5031 dim
->chk_index(index
, Type::EXPECTED_DYNAMIC_VALUE
);
5032 if (index
->get_value_refd_last()->get_valuetype() == Value::V_INT
) {
5033 const int_val_t
*index_int
= index
->get_value_refd_last()
5035 if (*index_int
> INT_MAX
) {
5036 index
->error("An integer value less than `%d' was expected for "
5037 "indexing timer array instead of `%s'", INT_MAX
,
5038 (index_int
->t_str()).c_str());
5039 index
->set_valuetype(Value::V_ERROR
);
5041 Int index_val
= index_int
->get_val();
5042 if (index_map
.has_key(index_val
)) {
5043 index
->error("Duplicate index value `%s' for timer array "
5044 "elements `%s' and `%s'",
5045 Int2string(index_val
).c_str(),
5046 Int2string((Int
)i
+ 1).c_str(),
5047 Int2string(*index_map
[index_val
]).c_str());
5048 index
->set_valuetype(Value::V_ERROR
);
5050 index_map
.add(index_val
, new Int((Int
)i
+ 1));
5055 // It's not possible to have "index_map.size() > array_size", since we
5056 // add only correct constant-index values into the map. It's possible
5057 // to create partially initialized timer arrays.
5058 for (size_t i
= 0; i
< index_map
.size(); i
++)
5059 delete index_map
.get_nth_elem(i
);
5064 if (array_size_known
) {
5065 dur
->error("An array value (with %lu elements) was expected as "
5066 "default duration of timer array",
5067 (unsigned long)array_size
);
5069 dur
->error("An array value was expected as default duration of timer "
5072 dur
->set_valuetype(Value::V_ERROR
);
5077 void Def_Timer::generate_code(output_struct
*target
, bool)
5079 const string
& t_genname
= get_genname();
5080 const char *genname_str
= t_genname
.c_str();
5081 const string
& dispname
= id
->get_dispname();
5084 const string
& array_type
= dimensions
->get_timer_type();
5085 const char *array_type_str
= array_type
.c_str();
5086 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5087 "extern %s %s;\n", array_type_str
, genname_str
);
5088 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5089 "%s %s;\n", array_type_str
, genname_str
);
5090 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
, "{\n"
5091 "static const char * const timer_name = \"");
5092 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
5094 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
5096 "%s.set_name(timer_name);\n"
5097 "}\n", genname_str
);
5098 if (default_duration
) target
->functions
.post_init
=
5099 generate_code_array_duration(target
->functions
.post_init
, genname_str
,
5103 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5104 "extern TIMER %s;\n", genname_str
);
5105 if (default_duration
) {
5106 // has default duration
5107 Value
*v
= default_duration
->get_value_refd_last();
5108 if (v
->get_valuetype() == Value::V_REAL
) {
5109 // duration is known at compilation time -> set in the constructor
5110 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5111 "TIMER %s(\"%s\", %s);\n", genname_str
, dispname
.c_str(),
5112 v
->get_single_expr().c_str());
5114 // duration is known only at runtime -> set in post_init
5115 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5116 "TIMER %s(\"%s\");\n", genname_str
, dispname
.c_str());
5117 expression_struct expr
;
5118 Code::init_expr(&expr
);
5119 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5121 default_duration
->generate_code_expr(&expr
);
5122 expr
.expr
= mputc(expr
.expr
, ')');
5123 target
->functions
.post_init
=
5124 Code::merge_free_expr(target
->functions
.post_init
, &expr
);
5127 // does not have default duration
5128 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5129 "TIMER %s(\"%s\");\n", genname_str
, dispname
.c_str());
5134 void Def_Timer::generate_code(CodeGenHelper
& cgh
) {
5135 generate_code(cgh
.get_current_outputstruct());
5138 char *Def_Timer::generate_code_array_duration(char *str
,
5139 const char *object_name
, Value
*dur
, size_t start_dim
)
5141 ArrayDimension
*dim
= dimensions
->get_dim_byIndex(start_dim
);
5142 size_t dim_size
= dim
->get_size();
5143 Value
*v
= dur
->get_value_refd_last();
5144 if (v
->get_valuetype() != Value::V_SEQOF
5145 || (v
->get_nof_comps() != dim_size
&& !v
->is_indexed()))
5146 FATAL_ERROR("Def_Timer::generate_code_array_duration()");
5147 // Value-list notation.
5148 if (!v
->is_indexed()) {
5149 if (start_dim
+ 1 < dimensions
->get_nof_dims()) {
5150 // There are more dimensions, the elements of "v" are arrays a
5151 // temporary reference shall be introduced if the next dimension has
5152 // more than 1 elements.
5153 bool temp_ref_needed
=
5154 dimensions
->get_dim_byIndex(start_dim
+ 1)->get_size() > 1;
5155 for (size_t i
= 0; i
< dim_size
; i
++) {
5156 Value
*v_elem
= v
->get_comp_byIndex(i
);
5157 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5158 if (temp_ref_needed
) {
5159 const string
& tmp_id
= my_scope
->get_scope_mod_gen()
5160 ->get_temporary_id();
5161 const char *tmp_str
= tmp_id
.c_str();
5162 str
= mputprintf(str
, "{\n"
5163 "%s& %s = %s.array_element(%lu);\n",
5164 dimensions
->get_timer_type(start_dim
+ 1).c_str(),
5165 tmp_str
, object_name
, (unsigned long)i
);
5166 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5168 str
= mputstr(str
, "}\n");
5170 char *tmp_str
= mprintf("%s.array_element(%lu)", object_name
,
5172 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5178 // We are in the last dimension, the elements of "v" are floats.
5179 for (size_t i
= 0; i
< dim_size
; i
++) {
5180 Value
*v_elem
= v
->get_comp_byIndex(i
);
5181 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5182 expression_struct expr
;
5183 Code::init_expr(&expr
);
5184 expr
.expr
= mputprintf(expr
.expr
,
5185 "%s.array_element(%lu).set_default_duration(",
5186 object_name
, (unsigned long)i
);
5187 v_elem
->generate_code_expr(&expr
);
5188 expr
.expr
= mputc(expr
.expr
, ')');
5189 str
= Code::merge_free_expr(str
, &expr
);
5192 // Indexed-list notation.
5194 if (start_dim
+ 1 < dimensions
->get_nof_dims()) {
5195 bool temp_ref_needed
=
5196 dimensions
->get_dim_byIndex(start_dim
+ 1)->get_size() > 1;
5197 for (size_t i
= 0; i
< v
->get_nof_comps(); i
++) {
5198 Value
*v_elem
= v
->get_comp_byIndex(i
);
5199 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5200 if (temp_ref_needed
) {
5201 const string
& tmp_id
= my_scope
->get_scope_mod_gen()
5202 ->get_temporary_id();
5203 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5204 ->get_temporary_id();
5205 const char *tmp_str
= tmp_id
.c_str();
5206 str
= mputstr(str
, "{\n");
5207 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5208 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5210 str
= mputprintf(str
, "%s& %s = %s.array_element(%s);\n",
5211 dimensions
->get_timer_type(start_dim
+ 1).c_str(),
5212 tmp_str
, object_name
, idx_id
.c_str());
5213 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5215 str
= mputstr(str
, "}\n");
5217 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5218 ->get_temporary_id();
5219 str
= mputstr(str
, "{\n");
5220 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5221 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5223 char *tmp_str
= mprintf("%s.array_element(%s)", object_name
,
5225 str
= generate_code_array_duration(str
, tmp_str
, v_elem
,
5227 str
= mputstr(str
, "}\n");
5232 for (size_t i
= 0; i
< v
->get_nof_comps(); i
++) {
5233 Value
*v_elem
= v
->get_comp_byIndex(i
);
5234 if (v_elem
->get_valuetype() == Value::V_NOTUSED
) continue;
5235 expression_struct expr
;
5236 Code::init_expr(&expr
);
5237 str
= mputstr(str
, "{\n");
5238 const string
& idx_id
= my_scope
->get_scope_mod_gen()
5239 ->get_temporary_id();
5240 str
= mputprintf(str
, "int %s;\n", idx_id
.c_str());
5241 str
= v
->get_index_byIndex(i
)->generate_code_init(str
,
5243 str
= mputprintf(str
,
5244 "%s.array_element(%s).set_default_duration(",
5245 object_name
, idx_id
.c_str());
5246 v_elem
->generate_code_expr(&expr
);
5247 expr
.expr
= mputc(expr
.expr
, ')');
5248 str
= Code::merge_free_expr(str
, &expr
);
5249 str
= mputstr(str
, "}\n");
5256 char *Def_Timer::generate_code_str(char *str
)
5258 const string
& t_genname
= get_genname();
5259 const char *genname_str
= t_genname
.c_str();
5260 const string
& dispname
= id
->get_dispname();
5263 const string
& array_type
= dimensions
->get_timer_type();
5264 const char *array_type_str
= array_type
.c_str();
5265 str
= mputprintf(str
, "%s %s;\n", array_type_str
, genname_str
);
5266 str
= mputstr(str
, "{\n"
5267 "static const char * const timer_name = \"");
5268 str
= mputstr(str
, dispname
.c_str());
5269 str
= mputprintf(str
, "\";\n"
5270 "%s.set_name(timer_name);\n"
5271 "}\n", genname_str
);
5272 if (default_duration
) str
= generate_code_array_duration(str
,
5273 genname_str
, default_duration
);
5276 if (default_duration
&& default_duration
->has_single_expr()) {
5277 // the default duration can be passed to the constructor
5278 str
= mputprintf(str
, "TIMER %s(\"%s\", %s);\n", genname_str
,
5279 dispname
.c_str(), default_duration
->get_single_expr().c_str());
5281 // only the name is passed to the constructor
5282 str
= mputprintf(str
, "TIMER %s(\"%s\");\n", genname_str
,
5284 if (default_duration
) {
5285 // the default duration is set explicitly
5286 expression_struct expr
;
5287 Code::init_expr(&expr
);
5288 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5290 default_duration
->generate_code_expr(&expr
);
5291 expr
.expr
= mputc(expr
.expr
, ')');
5292 str
= Code::merge_free_expr(str
, &expr
);
5299 void Def_Timer::ilt_generate_code(ILT
*ilt
)
5301 const string
& t_genname
= get_genname();
5302 const char *genname_str
= t_genname
.c_str();
5303 const string
& dispname
= id
->get_dispname();
5305 char*& def
= ilt
->get_out_def();
5306 char*& init
= ilt
->get_out_branches();
5310 const string
& array_type
= dimensions
->get_timer_type();
5311 const char *array_type_str
= array_type
.c_str();
5312 def
= mputprintf(def
, "%s %s;\n", array_type_str
, genname_str
);
5313 def
= mputstr(def
, "{\n"
5314 "static const char * const timer_names[] = { ");
5315 def
= dimensions
->generate_element_names(def
, dispname
);
5316 def
= mputprintf(def
, " };\n"
5317 "%s.set_name(%lu, timer_names);\n"
5318 "}\n", genname_str
, (unsigned long) dimensions
->get_array_size());
5319 if (default_duration
) init
= generate_code_array_duration(init
,
5320 genname_str
, default_duration
);
5323 if (default_duration
) {
5324 // has default duration
5325 Value
*v
= default_duration
->get_value_refd_last();
5326 if (v
->get_valuetype() == Value::V_REAL
) {
5327 // duration is known at compilation time -> set in the constructor
5328 def
= mputprintf(def
, "TIMER %s(\"%s\", %s);\n", genname_str
,
5329 dispname
.c_str(), v
->get_single_expr().c_str());
5331 // duration is known only at runtime -> set when control reaches the
5333 def
= mputprintf(def
, "TIMER %s(\"%s\");\n", genname_str
,
5335 expression_struct expr
;
5336 Code::init_expr(&expr
);
5337 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5339 default_duration
->generate_code_expr(&expr
);
5340 expr
.expr
= mputc(expr
.expr
, ')');
5341 init
= Code::merge_free_expr(init
, &expr
);
5344 // does not have default duration
5345 def
= mputprintf(def
, "TIMER %s(\"%s\");\n", genname_str
,
5351 char *Def_Timer::generate_code_init_comp(char *str
, Definition
*base_defn
)
5353 if (default_duration
) {
5354 Def_Timer
*base_timer_defn
= dynamic_cast<Def_Timer
*>(base_defn
);
5355 if (!base_timer_defn
|| !base_timer_defn
->default_duration
)
5356 FATAL_ERROR("Def_Timer::generate_code_init_comp()");
5357 // initializer is not needed if the default durations are the same
5358 // constants in both timers
5359 if (default_duration
->is_unfoldable() ||
5360 base_timer_defn
->default_duration
->is_unfoldable() ||
5361 !(*default_duration
== *base_timer_defn
->default_duration
)) {
5363 str
= generate_code_array_duration(str
,
5364 base_timer_defn
->get_genname_from_scope(my_scope
).c_str(),
5367 expression_struct expr
;
5368 Code::init_expr(&expr
);
5369 expr
.expr
= mputprintf(expr
.expr
, "%s.set_default_duration(",
5370 base_timer_defn
->get_genname_from_scope(my_scope
).c_str());
5371 default_duration
->generate_code_expr(&expr
);
5372 expr
.expr
= mputc(expr
.expr
, ')');
5373 str
= Code::merge_free_expr(str
, &expr
);
5380 void Def_Timer::dump_internal(unsigned level
) const
5382 DEBUG(level
, "Timer: %s", id
->get_dispname().c_str());
5383 if (dimensions
) dimensions
->dump(level
+ 1);
5384 if (default_duration
) {
5385 DEBUG(level
+ 1, "Default duration:");
5386 default_duration
->dump(level
+ 1);
5390 // =================================
5392 // =================================
5394 Def_Port::Def_Port(Identifier
*p_id
, Reference
*p_tref
,
5395 ArrayDimensions
*p_dims
)
5396 : Definition(A_PORT
, p_id
), type_ref(p_tref
), port_type(0),
5399 if (!p_tref
) FATAL_ERROR("Def_Port::Def_Port()");
5402 Def_Port::~Def_Port()
5408 Def_Port
*Def_Port::clone() const
5410 FATAL_ERROR("Def_Port::clone");
5413 void Def_Port::set_fullname(const string
& p_fullname
)
5415 Definition::set_fullname(p_fullname
);
5416 type_ref
->set_fullname(p_fullname
+ ".<type_ref>");
5417 if (dimensions
) dimensions
->set_fullname(p_fullname
);
5420 void Def_Port::set_my_scope(Scope
*p_scope
)
5422 Definition::set_my_scope(p_scope
);
5423 type_ref
->set_my_scope(p_scope
);
5424 if (dimensions
) dimensions
->set_my_scope(p_scope
);
5427 Type
*Def_Port::get_Type()
5433 ArrayDimensions
*Def_Port::get_Dimensions()
5435 if (!checked
) chk();
5439 void Def_Port::chk()
5441 if (checked
) return;
5443 Error_Context
cntxt(this, "In port definition `%s'",
5444 id
->get_dispname().c_str());
5445 Common::Assignment
*ass
= type_ref
->get_refd_assignment();
5447 if (ass
->get_asstype() == A_TYPE
) {
5448 Type
*t
= ass
->get_Type()->get_type_refd_last();
5449 if (t
->get_typetype() == Type::T_PORT
) port_type
= t
;
5450 else type_ref
->error("Type reference `%s' does not refer to a "
5451 "port type", type_ref
->get_dispname().c_str());
5452 } else type_ref
->error("Reference `%s' does not refer to a "
5453 "type", type_ref
->get_dispname().c_str());
5455 if (dimensions
) dimensions
->chk();
5456 if (w_attrib_path
) {
5457 w_attrib_path
->chk_global_attrib();
5458 w_attrib_path
->chk_no_qualif();
5462 bool Def_Port::chk_identical(Definition
*p_def
)
5466 if (p_def
->get_asstype() != A_PORT
) {
5467 const char *dispname_str
= id
->get_dispname().c_str();
5468 error("Local definition `%s' is a port, but the definition inherited "
5469 "from component type `%s' is a %s", dispname_str
,
5470 p_def
->get_my_scope()->get_fullname().c_str(), p_def
->get_assname());
5471 p_def
->note("The inherited definition of `%s' is here", dispname_str
);
5474 Def_Port
*p_def_port
= dynamic_cast<Def_Port
*>(p_def
);
5475 if (!p_def_port
) FATAL_ERROR("Def_Port::chk_identical()");
5476 if (port_type
&& p_def_port
->port_type
&&
5477 port_type
!= p_def_port
->port_type
) {
5478 const char *dispname_str
= id
->get_dispname().c_str();
5479 type_ref
->error("Local port `%s' has type `%s', but the port inherited "
5480 "from component type `%s' has type `%s'", dispname_str
,
5481 port_type
->get_typename().c_str(),
5482 p_def_port
->get_my_scope()->get_fullname().c_str(),
5483 p_def_port
->port_type
->get_typename().c_str());
5484 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5488 if (p_def_port
->dimensions
) {
5489 if (!dimensions
->is_identical(p_def_port
->dimensions
)) {
5490 const char *dispname_str
= id
->get_dispname().c_str();
5491 error("Local port `%s' and the port inherited from component type "
5492 "`%s' have different array dimensions", dispname_str
,
5493 p_def_port
->get_my_scope()->get_fullname().c_str());
5494 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5498 const char *dispname_str
= id
->get_dispname().c_str();
5499 error("Local definition `%s' is a port array, but the definition "
5500 "inherited from component type `%s' is a single port", dispname_str
,
5501 p_def_port
->get_my_scope()->get_fullname().c_str());
5502 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5505 } else if (p_def_port
->dimensions
) {
5506 const char *dispname_str
= id
->get_dispname().c_str();
5507 error("Local definition `%s' is a single port, but the definition "
5508 "inherited from component type `%s' is a port array", dispname_str
,
5509 p_def_port
->get_my_scope()->get_fullname().c_str());
5510 p_def_port
->note("The inherited port `%s' is here", dispname_str
);
5516 void Def_Port::generate_code(output_struct
*target
, bool)
5518 const string
& t_genname
= get_genname();
5519 const char *genname_str
= t_genname
.c_str();
5520 const string
& type_genname
= port_type
->get_genname_value(my_scope
);
5521 const string
& dispname
= id
->get_dispname();
5524 const string
& array_type
= dimensions
->get_port_type(type_genname
);
5525 const char *array_type_str
= array_type
.c_str();
5526 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5527 "extern %s %s;\n", array_type_str
, genname_str
);
5528 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5529 "%s %s;\n", array_type_str
, genname_str
);
5530 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
, "{\n"
5531 "static const char * const port_name = \"");
5532 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
5534 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
5536 "%s.set_name(port_name);\n"
5537 "}\n", genname_str
);
5540 const char *type_genname_str
= type_genname
.c_str();
5541 target
->header
.global_vars
= mputprintf(target
->header
.global_vars
,
5542 "extern %s %s;\n", type_genname_str
, genname_str
);
5543 target
->source
.global_vars
= mputprintf(target
->source
.global_vars
,
5544 "%s %s(\"%s\");\n", type_genname_str
, genname_str
, dispname
.c_str());
5546 target
->functions
.init_comp
= mputprintf(target
->functions
.init_comp
,
5547 "%s.activate_port();\n", genname_str
);
5550 void Def_Port::generate_code(CodeGenHelper
& cgh
) {
5551 generate_code(cgh
.get_current_outputstruct());
5554 char *Def_Port::generate_code_init_comp(char *str
, Definition
*base_defn
)
5556 return mputprintf(str
, "%s.activate_port();\n",
5557 base_defn
->get_genname_from_scope(my_scope
).c_str());
5560 void Def_Port::dump_internal(unsigned level
) const
5562 DEBUG(level
, "Port: %s", id
->get_dispname().c_str());
5563 DEBUG(level
+ 1, "Port type:");
5564 type_ref
->dump(level
+ 2);
5565 if (dimensions
) dimensions
->dump(level
+ 1);
5568 // =================================
5569 // ===== Def_Function_Base
5570 // =================================
5572 Def_Function_Base::asstype_t
Def_Function_Base::determine_asstype(
5573 bool is_external
, bool has_return_type
, bool returns_template
)
5576 if (has_return_type
) {
5577 if (returns_template
) return A_EXT_FUNCTION_RTEMP
;
5578 else return A_EXT_FUNCTION_RVAL
;
5580 if (returns_template
)
5581 FATAL_ERROR("Def_Function_Base::determine_asstype()");
5582 return A_EXT_FUNCTION
;
5584 } else { // not an external function
5585 if (has_return_type
) {
5586 if (returns_template
) return A_FUNCTION_RTEMP
;
5587 else return A_FUNCTION_RVAL
;
5589 if (returns_template
)
5590 FATAL_ERROR("Def_Function_Base::determine_asstype()");
5596 Def_Function_Base::Def_Function_Base(const Def_Function_Base
& p
)
5597 : Definition(p
), prototype(PROTOTYPE_NONE
), input_type(0), output_type(0)
5599 fp_list
= p
.fp_list
->clone();
5600 fp_list
->set_my_def(this);
5601 return_type
= p
.return_type
? p
.return_type
->clone() : 0;
5602 template_restriction
= p
.template_restriction
;
5605 Def_Function_Base::Def_Function_Base(bool is_external
, Identifier
*p_id
,
5606 FormalParList
*p_fpl
, Type
*p_return_type
, bool returns_template
,
5607 template_restriction_t p_template_restriction
)
5608 : Definition(determine_asstype(is_external
, p_return_type
!= 0,
5609 returns_template
), p_id
), fp_list(p_fpl
), return_type(p_return_type
),
5610 prototype(PROTOTYPE_NONE
), input_type(0), output_type(0),
5611 template_restriction(p_template_restriction
)
5613 if (!p_fpl
) FATAL_ERROR("Def_Function_Base::Def_Function_Base()");
5614 fp_list
->set_my_def(this);
5615 if (return_type
) return_type
->set_ownertype(Type::OT_FUNCTION_DEF
, this);
5618 Def_Function_Base::~Def_Function_Base()
5624 void Def_Function_Base::set_fullname(const string
& p_fullname
)
5626 Definition::set_fullname(p_fullname
);
5627 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
5628 if (return_type
) return_type
->set_fullname(p_fullname
+ ".<return_type>");
5631 void Def_Function_Base::set_my_scope(Scope
*p_scope
)
5633 Definition::set_my_scope(p_scope
);
5634 fp_list
->set_my_scope(p_scope
);
5635 if (return_type
) return_type
->set_my_scope(p_scope
);
5638 Type
*Def_Function_Base::get_Type()
5640 if (!checked
) chk();
5644 FormalParList
*Def_Function_Base::get_FormalParList()
5646 if (!checked
) chk();
5650 const char *Def_Function_Base::get_prototype_name() const
5652 switch (prototype
) {
5653 case PROTOTYPE_NONE
:
5654 return "<no prototype>";
5655 case PROTOTYPE_CONVERT
:
5657 case PROTOTYPE_FAST
:
5659 case PROTOTYPE_BACKTRACK
:
5661 case PROTOTYPE_SLIDING
:
5664 return "<unknown prototype>";
5668 void Def_Function_Base::chk_prototype()
5670 switch (prototype
) {
5671 case PROTOTYPE_NONE
:
5672 // return immediately
5674 case PROTOTYPE_CONVERT
:
5675 case PROTOTYPE_FAST
:
5676 case PROTOTYPE_BACKTRACK
:
5677 case PROTOTYPE_SLIDING
:
5678 // perform the checks below
5681 FATAL_ERROR("Def_Function_Base::chk_prototype()");
5683 // checking the formal parameter list
5684 if (prototype
== PROTOTYPE_CONVERT
) {
5685 if (fp_list
->get_nof_fps() == 1) {
5686 FormalPar
*par
= fp_list
->get_fp_byIndex(0);
5687 if (par
->get_asstype() == A_PAR_VAL_IN
) {
5688 input_type
= par
->get_Type();
5690 par
->error("The parameter must be an `in' value parameter for "
5691 "attribute `prototype(%s)' instead of %s", get_prototype_name(),
5692 par
->get_assname());
5695 fp_list
->error("The function must have one parameter instead of %lu "
5696 "for attribute `prototype(%s)'", (unsigned long) fp_list
->get_nof_fps(),
5697 get_prototype_name());
5699 } else { // not PROTOTYPE_CONVERT
5700 if (fp_list
->get_nof_fps() == 2) {
5701 FormalPar
*first_par
= fp_list
->get_fp_byIndex(0);
5702 if (prototype
== PROTOTYPE_SLIDING
) {
5703 if (first_par
->get_asstype() == A_PAR_VAL_INOUT
) {
5704 Type
*first_par_type
= first_par
->get_Type();
5705 switch (first_par_type
->get_type_refd_last()
5706 ->get_typetype_ttcn3()) {
5711 input_type
= first_par_type
;
5714 first_par_type
->error("The type of the first parameter must be "
5715 "`octetstring' or `charstring' or `bitstring' for attribute "
5716 "`prototype(%s)' instead of `%s'", get_prototype_name(),
5717 first_par_type
->get_typename().c_str());
5720 first_par
->error("The first parameter must be an `inout' value "
5721 "parameter for attribute `prototype(%s)' instead of %s",
5722 get_prototype_name(), first_par
->get_assname());
5725 if (first_par
->get_asstype() == A_PAR_VAL_IN
) {
5726 input_type
= first_par
->get_Type();
5728 first_par
->error("The first parameter must be an `in' value "
5729 "parameter for attribute `prototype(%s)' instead of %s",
5730 get_prototype_name(), first_par
->get_assname());
5733 FormalPar
*second_par
= fp_list
->get_fp_byIndex(1);
5734 if (second_par
->get_asstype() == A_PAR_VAL_OUT
) {
5735 output_type
= second_par
->get_Type();
5737 second_par
->error("The second parameter must be an `out' value "
5738 "parameter for attribute `prototype(%s)' instead of %s",
5739 get_prototype_name(), second_par
->get_assname());
5742 fp_list
->error("The function must have two parameters for attribute "
5743 "`prototype(%s)' instead of %lu", get_prototype_name(),
5744 (unsigned long) fp_list
->get_nof_fps());
5747 // checking the return type
5748 if (prototype
== PROTOTYPE_FAST
) {
5750 return_type
->error("The function cannot have return type for "
5751 "attribute `prototype(%s)'", get_prototype_name());
5755 if (asstype
== A_FUNCTION_RTEMP
|| asstype
== A_EXT_FUNCTION_RTEMP
)
5756 return_type
->error("The function must return a value instead of a "
5757 "template for attribute `prototype(%s)'", get_prototype_name());
5758 if (prototype
== PROTOTYPE_CONVERT
) {
5759 output_type
= return_type
;
5761 switch (return_type
->get_type_refd_last()->get_typetype_ttcn3()) {
5766 return_type
->error("The return type of the function must be "
5767 "`integer' instead of `%s' for attribute `prototype(%s)'",
5768 return_type
->get_typename().c_str(), get_prototype_name());
5772 error("The function must have return type for attribute "
5773 "`prototype(%s)'", get_prototype_name());
5776 // checking the 'runs on' clause
5777 if (get_RunsOnType()) {
5778 error("The function cannot have `runs on' clause for attribute "
5779 "`prototype(%s)'", get_prototype_name());
5783 Type
*Def_Function_Base::get_input_type()
5785 if (!checked
) chk();
5789 Type
*Def_Function_Base::get_output_type()
5791 if (!checked
) chk();
5796 // =================================
5797 // ===== Def_Function
5798 // =================================
5800 Def_Function::Def_Function(Identifier
*p_id
, FormalParList
*p_fpl
,
5801 Reference
*p_runs_on_ref
, Type
*p_return_type
,
5802 bool returns_template
,
5803 template_restriction_t p_template_restriction
,
5804 StatementBlock
*p_block
)
5805 : Def_Function_Base(false, p_id
, p_fpl
, p_return_type
, returns_template
,
5806 p_template_restriction
),
5807 runs_on_ref(p_runs_on_ref
), runs_on_type(0), block(p_block
),
5808 is_startable(false), transparent(false)
5810 if (!p_block
) FATAL_ERROR("Def_Function::Def_Function()");
5811 block
->set_my_def(this);
5814 Def_Function::~Def_Function()
5820 Def_Function
*Def_Function::clone() const
5822 FATAL_ERROR("Def_Function::clone");
5825 void Def_Function::set_fullname(const string
& p_fullname
)
5827 Def_Function_Base::set_fullname(p_fullname
);
5828 if (runs_on_ref
) runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
5829 block
->set_fullname(p_fullname
+ ".<statement_block>");
5832 void Def_Function::set_my_scope(Scope
*p_scope
)
5834 bridgeScope
.set_parent_scope(p_scope
);
5835 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
5837 Def_Function_Base::set_my_scope(&bridgeScope
);
5838 if (runs_on_ref
) runs_on_ref
->set_my_scope(&bridgeScope
);
5839 block
->set_my_scope(fp_list
);
5842 Type
*Def_Function::get_RunsOnType()
5844 if (!checked
) chk();
5845 return runs_on_type
;
5848 RunsOnScope
*Def_Function::get_runs_on_scope(Type
*comptype
)
5850 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
5851 if (!my_module
) FATAL_ERROR("Def_Function::get_runs_on_scope()");
5852 return my_module
->get_runs_on_scope(comptype
);
5855 void Def_Function::chk()
5857 if (checked
) return;
5859 Error_Context
cntxt(this, "In function definition `%s'",
5860 id
->get_dispname().c_str());
5861 // checking the `runs on' clause
5863 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
5864 runs_on_type
= runs_on_ref
->chk_comptype_ref();
5865 // override the scope of the formal parameter list
5867 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
5868 runs_on_scope
->set_parent_scope(my_scope
);
5869 fp_list
->set_my_scope(runs_on_scope
);
5872 // checking the formal parameter list
5873 fp_list
->chk(asstype
);
5874 // checking of return type
5876 Error_Context
cntxt2(return_type
, "In return type");
5878 return_type
->chk_as_return_type(asstype
== A_FUNCTION_RVAL
,"function");
5880 // decision of startability
5881 is_startable
= runs_on_ref
!= 0;
5882 if (is_startable
&& !fp_list
->get_startability()) is_startable
= false;
5883 if (is_startable
&& return_type
&& return_type
->is_component_internal())
5884 is_startable
= false;
5885 // checking of statement block
5888 // checking the presence of return statements
5889 switch (block
->has_return()) {
5890 case StatementBlock::RS_NO
:
5891 error("The function has return type, but it does not have any return "
5894 case StatementBlock::RS_MAYBE
:
5895 error("The function has return type, but control might leave it "
5896 "without reaching a return statement");
5901 if (!semantic_check_only
) {
5902 fp_list
->set_genname(get_genname());
5903 block
->set_code_section(GovernedSimple::CS_INLINE
);
5905 if (w_attrib_path
) {
5906 w_attrib_path
->chk_global_attrib();
5907 w_attrib_path
->chk_no_qualif();
5908 Ttcn::ExtensionAttributes
* extattrs
= parse_extattributes(w_attrib_path
);
5909 if (extattrs
!= 0) { // NULL means parsing error
5910 size_t num_atrs
= extattrs
->size();
5911 for (size_t i
=0; i
< num_atrs
; ++i
) {
5912 ExtensionAttribute
&ea
= extattrs
->get(i
);
5913 switch (ea
.get_type()) {
5914 case ExtensionAttribute::PROTOTYPE
: {
5915 if (get_prototype() != Def_Function_Base::PROTOTYPE_NONE
) {
5916 ea
.error("Duplicate attribute `prototype'");
5918 Def_Function_Base::prototype_t proto
= ea
.get_proto();
5919 set_prototype(proto
);
5922 case ExtensionAttribute::ANYTYPELIST
: // ignore it
5923 case ExtensionAttribute::NONE
: // erroneous, do not issue an error
5926 case ExtensionAttribute::TRANSPARENT
:
5930 case ExtensionAttribute::ENCODE
:
5931 case ExtensionAttribute::DECODE
:
5932 case ExtensionAttribute::ERRORBEHAVIOR
:
5933 case ExtensionAttribute::PRINTING
:
5934 ea
.error("Extension attribute 'encode', 'decode', 'errorbehavior'"
5935 " or 'printing' can only be applied to external functions");
5938 default: // complain
5939 ea
.error("Function definition can only have the 'prototype'"
5940 " extension attribute");
5950 bool Def_Function::chk_startable()
5952 if (!checked
) chk();
5953 if (is_startable
) return true;
5954 if (!runs_on_ref
) error("Function `%s' cannot be started on a parallel "
5955 "test component because it does not have `runs on' clause",
5956 get_fullname().c_str());
5957 fp_list
->chk_startability("Function", get_fullname().c_str());
5958 if (return_type
&& return_type
->is_component_internal()) {
5959 map
<Type
*,void> type_chain
;
5960 char* err_str
= mprintf("the return type or embedded in the return type "
5961 "of function `%s' if it is started on a parallel test component",
5962 get_fullname().c_str());
5963 return_type
->chk_component_internal(type_chain
, err_str
);
5969 void Def_Function::generate_code(output_struct
*target
, bool)
5971 transparency_holder
glass(*this);
5972 const string
& t_genname
= get_genname();
5973 const char *genname_str
= t_genname
.c_str();
5974 const char *dispname_str
= id
->get_dispname().c_str();
5975 string return_type_name
;
5978 return_type_name
= "void";
5980 case A_FUNCTION_RVAL
:
5981 return_type_name
= return_type
->get_genname_value(my_scope
);
5983 case A_FUNCTION_RTEMP
:
5984 return_type_name
= return_type
->get_genname_template(my_scope
);
5987 FATAL_ERROR("Def_Function::generate_code()");
5989 const char *return_type_str
= return_type_name
.c_str();
5990 char *formal_par_list
= fp_list
->generate_code(memptystr());
5991 fp_list
->generate_code_defval(target
);
5992 // function prototype
5993 target
->header
.function_prototypes
=
5994 mputprintf(target
->header
.function_prototypes
, "extern %s %s(%s);\n",
5995 return_type_str
, genname_str
, formal_par_list
);
5998 char *body
= mprintf("%s %s(%s)\n"
5999 "{\n", return_type_str
, genname_str
, formal_par_list
);
6000 body
= create_location_object(body
, "FUNCTION", dispname_str
);
6001 if (!enable_set_bound_out_param
)
6002 body
= fp_list
->generate_code_set_unbound(body
); // conform the standard out parameter is unbound
6003 body
= fp_list
->generate_shadow_objects(body
);
6004 body
= block
->generate_code(body
);
6005 body
= mputstr(body
, "}\n\n");
6006 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6011 size_t nof_fps
= fp_list
->get_nof_fps();
6012 // starter function (stub)
6013 // function prototype
6014 target
->header
.function_prototypes
=
6015 mputprintf(target
->header
.function_prototypes
,
6016 "extern void start_%s(const COMPONENT& component_reference%s%s);\n",
6017 genname_str
, nof_fps
>0?", ":"", formal_par_list
);
6019 body
= mprintf("void start_%s(const COMPONENT& component_reference%s"
6022 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
6023 "TTCN_Logger::log_event_str(\"Starting function %s(\");\n",
6024 genname_str
, nof_fps
>0?", ":"", formal_par_list
, dispname_str
);
6025 for (size_t i
= 0; i
< nof_fps
; i
++) {
6026 if (i
> 0) body
= mputstr(body
,
6027 "TTCN_Logger::log_event_str(\", \");\n");
6028 body
= mputprintf(body
, "%s.log();\n",
6029 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6031 body
= mputprintf(body
,
6032 "TTCN_Logger::log_event_str(\") on component \");\n"
6033 "component_reference.log();\n"
6034 "TTCN_Logger::log_char('.');\n"
6035 "TTCN_Logger::end_event();\n"
6036 "Text_Buf text_buf;\n"
6037 "TTCN_Runtime::prepare_start_component(component_reference, "
6038 "\"%s\", \"%s\", text_buf);\n",
6039 my_scope
->get_scope_mod()->get_modid().get_dispname().c_str(),
6041 for (size_t i
= 0; i
< nof_fps
; i
++) {
6042 body
= mputprintf(body
, "%s.encode_text(text_buf);\n",
6043 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6045 body
= mputstr(body
, "TTCN_Runtime::send_start_component(text_buf);\n"
6047 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6051 // an entry in start_ptc_function
6052 body
= mprintf("if (!strcmp(function_name, \"%s\")) {\n",
6055 body
= fp_list
->generate_code_object(body
, "", ' ');
6056 for (size_t i
= 0; i
< nof_fps
; i
++) {
6057 body
= mputprintf(body
, "%s.decode_text(function_arguments);\n",
6058 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6060 body
= mputprintf(body
,
6061 "TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_PTC);\n"
6062 "TTCN_Logger::log_event_str(\"Starting function %s(\");\n",
6064 for (size_t i
= 0; i
< nof_fps
; i
++) {
6065 if (i
> 0) body
= mputstr(body
,
6066 "TTCN_Logger::log_event_str(\", \");\n");
6067 body
= mputprintf(body
, "%s.log();\n",
6068 fp_list
->get_fp_byIndex(i
)->get_reference_name(my_scope
).c_str());
6070 body
= mputstr(body
, "TTCN_Logger::log_event_str(\").\");\n"
6071 "TTCN_Logger::end_event();\n");
6073 body
= mputprintf(body
,
6074 "TTCN_Logger::log_str(TTCN_Logger::PARALLEL_PTC, \"Starting function "
6075 "%s().\");\n", dispname_str
);
6077 body
= mputstr(body
,
6078 "TTCN_Runtime::function_started(function_arguments);\n");
6079 char *actual_par_list
=
6080 fp_list
->generate_code_actual_parlist(memptystr(), "");
6081 bool return_value_kept
= false;
6082 if (asstype
== A_FUNCTION_RVAL
) {
6083 // the return value is kept only if the function returns a value
6084 // (rather than a template) and the return type has the "done"
6085 // extension attribute
6086 for (Type
*t
= return_type
; ; t
= t
->get_type_refd()) {
6087 if (t
->has_done_attribute()) {
6088 return_value_kept
= true;
6090 } else if (!t
->is_ref()) break;
6093 if (return_value_kept
) {
6094 const string
& return_type_dispname
= return_type
->get_typename();
6095 const char *return_type_dispname_str
= return_type_dispname
.c_str();
6096 body
= mputprintf(body
, "%s ret_val(%s(%s));\n"
6097 "TTCN_Logger::begin_event(TTCN_PARALLEL);\n"
6098 "TTCN_Logger::log_event_str(\"Function %s returned %s : \");\n"
6100 "Text_Buf text_buf;\n"
6101 "TTCN_Runtime::prepare_function_finished(\"%s\", text_buf);\n"
6102 "ret_val.encode_text(text_buf);\n"
6103 "TTCN_Runtime::send_function_finished(text_buf);\n",
6104 return_type_str
, genname_str
, actual_par_list
, dispname_str
,
6105 return_type_dispname_str
, return_type_dispname_str
);
6107 body
= mputprintf(body
, "%s(%s);\n"
6108 "TTCN_Runtime::function_finished(\"%s\");\n",
6109 genname_str
, actual_par_list
, dispname_str
);
6111 Free(actual_par_list
);
6112 body
= mputstr(body
, "return TRUE;\n"
6114 target
->functions
.start
= mputstr(target
->functions
.start
, body
);
6117 Free(formal_par_list
);
6119 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6120 "%s.add_function(\"%s\", (genericfunc_t)&%s, ", get_module_object_name(),
6121 dispname_str
, genname_str
);
6123 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6124 "(genericfunc_t)&start_%s);\n", genname_str
);
6126 target
->functions
.pre_init
= mputstr(target
->functions
.pre_init
,
6130 void Def_Function::generate_code(CodeGenHelper
& cgh
) {
6131 generate_code(cgh
.get_current_outputstruct());
6134 void Def_Function::dump_internal(unsigned level
) const
6136 DEBUG(level
, "Function: %s", id
->get_dispname().c_str());
6137 DEBUG(level
+ 1, "Parameters:");
6138 fp_list
->dump(level
+ 1);
6140 DEBUG(level
+ 1, "Runs on clause:");
6141 runs_on_ref
->dump(level
+ 2);
6144 DEBUG(level
+ 1, "Return type:");
6145 return_type
->dump(level
+ 2);
6146 if (asstype
== A_FUNCTION_RTEMP
) DEBUG(level
+ 1, "Returns template");
6148 if (prototype
!= PROTOTYPE_NONE
)
6149 DEBUG(level
+ 1, "Prototype: %s", get_prototype_name());
6150 //DEBUG(level + 1, "Statement block:");
6151 block
->dump(level
+ 1);
6154 void Def_Function::set_parent_path(WithAttribPath
* p_path
) {
6155 Def_Function_Base::set_parent_path(p_path
);
6156 block
->set_parent_path(w_attrib_path
);
6159 // =================================
6160 // ===== Def_ExtFunction
6161 // =================================
6163 Def_ExtFunction::~Def_ExtFunction()
6165 delete encoding_options
;
6167 if (NULL
!= json_printing
) {
6168 delete json_printing
;
6172 Def_ExtFunction
*Def_ExtFunction::clone() const
6174 FATAL_ERROR("Def_ExtFunction::clone");
6177 void Def_ExtFunction::set_fullname(const string
& p_fullname
)
6179 Def_Function_Base::set_fullname(p_fullname
);
6180 if (eb_list
) eb_list
->set_fullname(p_fullname
+ ".<errorbehavior_list>");
6183 void Def_ExtFunction::set_encode_parameters(Type::MessageEncodingType_t
6184 p_encoding_type
, string
*p_encoding_options
)
6186 function_type
= EXTFUNC_ENCODE
;
6187 encoding_type
= p_encoding_type
;
6188 delete encoding_options
;
6189 encoding_options
= p_encoding_options
;
6192 void Def_ExtFunction::set_decode_parameters(Type::MessageEncodingType_t
6193 p_encoding_type
, string
*p_encoding_options
)
6195 function_type
= EXTFUNC_DECODE
;
6196 encoding_type
= p_encoding_type
;
6197 delete encoding_options
;
6198 encoding_options
= p_encoding_options
;
6201 void Def_ExtFunction::add_eb_list(Ttcn::ErrorBehaviorList
*p_eb_list
)
6203 if (!p_eb_list
) FATAL_ERROR("Def_ExtFunction::add_eb_list()");
6205 eb_list
->steal_ebs(p_eb_list
);
6208 eb_list
= p_eb_list
;
6209 eb_list
->set_fullname(get_fullname() + ".<errorbehavior_list>");
6213 void Def_ExtFunction::chk_function_type()
6215 switch (function_type
) {
6216 case EXTFUNC_MANUAL
:
6218 eb_list
->error("Attribute `errorbehavior' can only be used together "
6219 "with `encode' or `decode'");
6223 case EXTFUNC_ENCODE
:
6224 switch (prototype
) {
6225 case PROTOTYPE_NONE
:
6226 error("Attribute `encode' cannot be used without `prototype'");
6228 case PROTOTYPE_BACKTRACK
:
6229 case PROTOTYPE_SLIDING
:
6230 error("Attribute `encode' cannot be used with `prototype(%s)'",
6231 get_prototype_name());
6232 default: /* CONVERT and FAST allowed */
6237 if (!input_type
->has_encoding(encoding_type
)) {
6238 input_type
->error("Input type `%s' does not support %s encoding",
6239 input_type
->get_typename().c_str(),
6240 Type::get_encoding_name(encoding_type
));
6242 if (Common::Type::CT_XER
== encoding_type
6243 && input_type
->get_type_refd_last()->is_untagged()) {
6244 // "untagged" on the (toplevel) input type will have no effect.
6245 warning("UNTAGGED encoding attribute is ignored on top-level type");
6249 if(encoding_type
== Common::Type::CT_TEXT
){ // the TEXT encoding support both octetstring ans charstring stream type
6250 Type
*stream_type
= Type::get_stream_type(encoding_type
,0);
6251 Type
*stream_type2
= Type::get_stream_type(encoding_type
,1);
6252 if ( (!stream_type
->is_identical(output_type
)) && (!stream_type2
->is_identical(output_type
)) ) {
6253 input_type
->error("The output type of %s encoding should be `%s' or `%s' "
6254 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6255 stream_type
->get_typename().c_str(),
6256 stream_type2
->get_typename().c_str(),
6257 input_type
->get_typename().c_str());
6260 Type
*stream_type
= Type::get_stream_type(encoding_type
);
6261 if (!stream_type
->is_identical(output_type
)) {
6262 input_type
->error("The output type of %s encoding should be `%s' "
6263 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6264 stream_type
->get_typename().c_str(),
6265 input_type
->get_typename().c_str());
6269 if (eb_list
) eb_list
->chk();
6270 chk_allowed_encode();
6272 case EXTFUNC_DECODE
:
6273 if (prototype
== PROTOTYPE_NONE
) {
6274 error("Attribute `decode' cannot be used without `prototype'");
6277 if(encoding_type
== Common::Type::CT_TEXT
){ // the TEXT encoding support both octetstring ans charstring stream type
6278 Type
*stream_type
= Type::get_stream_type(encoding_type
,0);
6279 Type
*stream_type2
= Type::get_stream_type(encoding_type
,1);
6280 if ( (!stream_type
->is_identical(input_type
)) && (!stream_type2
->is_identical(input_type
)) ) {
6281 input_type
->error("The input type of %s encoding should be `%s' or `%s' "
6282 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6283 stream_type
->get_typename().c_str(),
6284 stream_type2
->get_typename().c_str(),
6285 input_type
->get_typename().c_str());
6288 Type
*stream_type
= Type::get_stream_type(encoding_type
);
6289 if (!stream_type
->is_identical(input_type
)) {
6290 input_type
->error("The input type of %s encoding should be `%s' "
6291 "instead of `%s'", Type::get_encoding_name(encoding_type
),
6292 stream_type
->get_typename().c_str(),
6293 input_type
->get_typename().c_str());
6298 if (output_type
&& !output_type
->has_encoding(encoding_type
)) {
6299 output_type
->error("Output type `%s' does not support %s encoding",
6300 output_type
->get_typename().c_str(),
6301 Type::get_encoding_name(encoding_type
));
6303 if (eb_list
) eb_list
->chk();
6304 chk_allowed_encode();
6307 FATAL_ERROR("Def_ExtFunction::chk()");
6311 void Def_ExtFunction::chk_allowed_encode()
6313 switch (encoding_type
) {
6315 if (enable_ber()) return; // ok
6318 if (enable_raw()) return; // ok
6321 if (enable_text()) return; // ok
6324 if (enable_xer()) return; // ok
6327 if (enable_per()) return; // ok?
6330 if (enable_json()) return;
6333 FATAL_ERROR("Def_ExtFunction::chk_allowed_encode");
6337 error("%s encoding is disallowed by license or commandline options",
6338 Type::get_encoding_name(encoding_type
));
6341 void Def_ExtFunction::chk()
6343 if (checked
) return;
6345 Error_Context
cntxt(this, "In external function definition `%s'",
6346 id
->get_dispname().c_str());
6347 fp_list
->chk(asstype
);
6349 Error_Context
cntxt2(return_type
, "In return type");
6351 return_type
->chk_as_return_type(asstype
== A_EXT_FUNCTION_RVAL
,
6352 "external function");
6354 if (!semantic_check_only
) fp_list
->set_genname(get_genname());
6355 if (w_attrib_path
) {
6356 w_attrib_path
->chk_global_attrib();
6357 w_attrib_path
->chk_no_qualif();
6358 const Ttcn::ExtensionAttributes
* extattrs
= parse_extattributes(w_attrib_path
);
6359 if (extattrs
!= 0) {
6360 size_t num_atrs
= extattrs
->size();
6361 for (size_t i
=0; i
< num_atrs
; ++i
) {
6362 ExtensionAttribute
&ea
= extattrs
->get(i
);
6363 switch (ea
.get_type()) {
6364 case ExtensionAttribute::PROTOTYPE
: {
6365 if (get_prototype() != Def_Function_Base::PROTOTYPE_NONE
) {
6366 ea
.error("Duplicate attribute `prototype'");
6368 Def_Function_Base::prototype_t proto
= ea
.get_proto();
6369 set_prototype(proto
);
6372 case ExtensionAttribute::ENCODE
: {
6373 switch (get_function_type()) {
6374 case Def_ExtFunction::EXTFUNC_MANUAL
:
6376 case Def_ExtFunction::EXTFUNC_ENCODE
: {
6377 ea
.error("Duplicate attribute `encode'");
6379 case Def_ExtFunction::EXTFUNC_DECODE
: {
6380 ea
.error("Attributes `decode' and `encode' "
6381 "cannot be used at the same time");
6384 FATAL_ERROR("coding_attrib_parse(): invalid external function type");
6386 Type::MessageEncodingType_t et
;
6388 ea
.get_encdec_parameters(et
, opt
);
6389 set_encode_parameters(et
, opt
);
6392 case ExtensionAttribute::ERRORBEHAVIOR
: {
6393 add_eb_list(ea
.get_eb_list());
6396 case ExtensionAttribute::DECODE
: {
6397 switch (get_function_type()) {
6398 case Def_ExtFunction::EXTFUNC_MANUAL
:
6400 case Def_ExtFunction::EXTFUNC_ENCODE
: {
6401 ea
.error("Attributes `encode' and `decode' "
6402 "cannot be used at the same time");
6404 case Def_ExtFunction::EXTFUNC_DECODE
: {
6405 ea
.error("Duplicate attribute `decode'");
6408 FATAL_ERROR("coding_attrib_parse(): invalid external function type");
6410 Type::MessageEncodingType_t et
;
6412 ea
.get_encdec_parameters(et
, opt
);
6413 set_decode_parameters(et
, opt
);
6416 case ExtensionAttribute::PRINTING
: {
6417 json_printing
= ea
.get_printing();
6420 case ExtensionAttribute::ANYTYPELIST
:
6421 // ignore, because we can't distinguish between a local
6422 // "extension anytype" (which is bogus) and an inherited one
6423 // (which was meant for a type definition)
6426 case ExtensionAttribute::NONE
:
6427 // Ignore, do not issue "wrong type" error
6432 "Only the following extension attributes may be applied to "
6433 "external functions: 'prototype', 'encode', 'decode', 'errorbehavior'");
6441 chk_function_type();
6443 if (NULL
!= json_printing
&& (EXTFUNC_ENCODE
!= function_type
||
6444 Type::CT_JSON
!= encoding_type
)) {
6445 error("Attribute 'printing' is only allowed for JSON encoding functions.");
6449 char *Def_ExtFunction::generate_code_encode(char *str
)
6451 const char *function_name
= id
->get_dispname().c_str();
6452 const char *first_par_name
=
6453 fp_list
->get_fp_byIndex(0)->get_id().get_name().c_str();
6454 // producing debug printout of the input PDU
6455 str
= mputprintf(str
,
6457 "// written by %s in " __FILE__
" at %d\n"
6459 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6460 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6461 "TTCN_Logger::log_event_str(\"%s(): Encoding %s: \");\n"
6463 "TTCN_Logger::end_event();\n"
6466 , __FUNCTION__
, __LINE__
6468 , function_name
, input_type
->get_typename().c_str(), first_par_name
);
6469 // setting error behavior
6470 if (eb_list
) str
= eb_list
->generate_code(str
);
6471 else str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6472 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n");
6473 // encoding PDU into the buffer
6474 str
= mputstr(str
, "TTCN_Buffer ttcn_buffer;\n");
6475 str
= mputprintf(str
, "%s.encode(%s_descr_, ttcn_buffer, TTCN_EncDec::CT_%s",
6477 input_type
->get_genname_typedescriptor(my_scope
).c_str(),
6478 Type::get_encoding_name(encoding_type
));
6479 if (encoding_type
== Type::CT_JSON
) {
6480 if (json_printing
!= NULL
) {
6481 str
= json_printing
->generate_code(str
);
6483 str
= mputstr(str
, ", 0");
6486 if (encoding_options
) str
= mputprintf(str
, ", %s",
6487 encoding_options
->c_str());
6488 str
= mputstr(str
, ");\n");
6489 const char *result_name
;
6490 switch (prototype
) {
6491 case PROTOTYPE_CONVERT
:
6492 result_name
= "ret_val";
6493 // creating a local variable for the result stream
6494 str
= mputprintf(str
, "%s ret_val;\n",
6495 output_type
->get_genname_value(my_scope
).c_str());
6497 case PROTOTYPE_FAST
:
6498 result_name
= fp_list
->get_fp_byIndex(1)->get_id().get_name().c_str();
6501 FATAL_ERROR("Def_ExtFunction::generate_code_encode()");
6504 // taking the result from the buffer and producing debug printout
6505 str
= mputprintf(str
, "ttcn_buffer.get_string(%s);\n"
6506 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6507 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6508 "TTCN_Logger::log_event_str(\"%s(): Stream after encoding: \");\n"
6510 "TTCN_Logger::end_event();\n"
6511 "}\n", result_name
, function_name
, result_name
);
6512 // returning the result stream if necessary
6513 if (prototype
== PROTOTYPE_CONVERT
) str
= mputstr(str
, "return ret_val;\n");
6517 char *Def_ExtFunction::generate_code_decode(char *str
)
6519 const char *function_name
= id
->get_dispname().c_str();
6520 const char *first_par_name
=
6521 fp_list
->get_fp_byIndex(0)->get_id().get_name().c_str();
6522 // producing debug printout of the input stream
6523 str
= mputprintf(str
,
6525 "// written by %s in " __FILE__
" at %d\n"
6527 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6528 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6529 "TTCN_Logger::log_event_str(\"%s(): Stream before decoding: \");\n"
6531 "TTCN_Logger::end_event();\n"
6534 , __FUNCTION__
, __LINE__
6536 , function_name
, first_par_name
);
6537 // setting error behavior
6538 if (eb_list
) str
= eb_list
->generate_code(str
);
6539 else if (prototype
== PROTOTYPE_BACKTRACK
|| prototype
== PROTOTYPE_SLIDING
) {
6540 str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6541 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);\n");
6542 } else str
= mputstr(str
, "TTCN_EncDec::set_error_behavior("
6543 "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);\n");
6544 // creating a buffer from the input stream
6545 str
= mputprintf(str
, "TTCN_EncDec::clear_error();\n"
6546 "TTCN_Buffer ttcn_buffer(%s);\n", first_par_name
);
6547 const char *result_name
;
6548 if (prototype
== PROTOTYPE_CONVERT
) {
6549 // creating a local variable for the result
6550 str
= mputprintf(str
, "%s ret_val;\n",
6551 output_type
->get_genname_value(my_scope
).c_str());
6552 result_name
= "ret_val";
6554 result_name
= fp_list
->get_fp_byIndex(1)->get_id().get_name().c_str();
6556 if(encoding_type
==Type::CT_TEXT
){
6557 str
= mputprintf(str
,
6558 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6559 " TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_LOG_MATCHING, TTCN_EncDec::EB_WARNING);\n"
6562 str
= mputprintf(str
, "%s.decode(%s_descr_, ttcn_buffer, "
6563 "TTCN_EncDec::CT_%s", result_name
,
6564 output_type
->get_genname_typedescriptor(my_scope
).c_str(),
6565 Type::get_encoding_name(encoding_type
));
6566 if (encoding_options
) str
= mputprintf(str
, ", %s",
6567 encoding_options
->c_str());
6568 str
= mputstr(str
, ");\n");
6569 // producing debug printout of the result PDU
6570 str
= mputprintf(str
,
6571 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6572 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6573 "TTCN_Logger::log_event_str(\"%s(): Decoded %s: \");\n"
6575 "TTCN_Logger::end_event();\n"
6576 "}\n", function_name
, output_type
->get_typename().c_str(), result_name
);
6577 if (prototype
!= PROTOTYPE_SLIDING
) {
6578 // checking for remaining data in the buffer if decoding was successful
6579 str
= mputprintf(str
, "if (TTCN_EncDec::get_last_error_type() == "
6580 "TTCN_EncDec::ET_NONE) {\n"
6581 "if (ttcn_buffer.get_pos() < ttcn_buffer.get_len()-1 && "
6582 "TTCN_Logger::log_this_event(TTCN_WARNING)) {\n"
6583 "ttcn_buffer.cut();\n"
6584 "%s remaining_stream;\n"
6585 "ttcn_buffer.get_string(remaining_stream);\n"
6586 "TTCN_Logger::begin_event(TTCN_WARNING);\n"
6587 "TTCN_Logger::log_event_str(\"%s(): Warning: Data remained at the end "
6588 "of the stream after successful decoding: \");\n"
6589 "remaining_stream.log();\n"
6590 "TTCN_Logger::end_event();\n"
6591 "}\n", input_type
->get_genname_value(my_scope
).c_str(), function_name
);
6592 // closing the block and returning the appropriate result or status code
6593 if (prototype
== PROTOTYPE_BACKTRACK
) {
6594 str
= mputstr(str
, "return 0;\n"
6595 "} else return 1;\n");
6597 str
= mputstr(str
, "}\n");
6598 if (prototype
== PROTOTYPE_CONVERT
)
6599 str
= mputstr(str
, "return ret_val;\n");
6602 // result handling and debug printout for sliding decoders
6603 str
= mputprintf(str
, "switch (TTCN_EncDec::get_last_error_type()) {\n"
6604 "case TTCN_EncDec::ET_NONE:\n"
6605 // TTCN_Buffer::get_string will call OCTETSTRING::clean_up()
6606 "ttcn_buffer.cut();\n"
6607 "ttcn_buffer.get_string(%s);\n"
6608 "if (TTCN_Logger::log_this_event(TTCN_Logger::DEBUG_ENCDEC)) {\n"
6609 "TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);\n"
6610 "TTCN_Logger::log_event_str(\"%s(): Stream after decoding: \");\n"
6612 "TTCN_Logger::end_event();\n"
6615 "case TTCN_EncDec::ET_INCOMPL_MSG:\n"
6616 "case TTCN_EncDec::ET_LEN_ERR:\n"
6620 "}\n", first_par_name
, function_name
, first_par_name
);
6625 void Def_ExtFunction::generate_code(output_struct
*target
, bool)
6627 const string
& t_genname
= get_genname();
6628 const char *genname_str
= t_genname
.c_str();
6629 string return_type_name
;
6631 case A_EXT_FUNCTION
:
6632 return_type_name
= "void";
6634 case A_EXT_FUNCTION_RVAL
:
6635 return_type_name
= return_type
->get_genname_value(my_scope
);
6637 case A_EXT_FUNCTION_RTEMP
:
6638 return_type_name
= return_type
->get_genname_template(my_scope
);
6641 FATAL_ERROR("Def_ExtFunction::generate_code()");
6643 const char *return_type_str
= return_type_name
.c_str();
6644 char *formal_par_list
= fp_list
->generate_code(memptystr());
6645 fp_list
->generate_code_defval(target
);
6646 // function prototype
6647 target
->header
.function_prototypes
=
6648 mputprintf(target
->header
.function_prototypes
, "extern %s %s(%s);\n",
6649 return_type_str
, genname_str
, formal_par_list
);
6651 if (function_type
!= EXTFUNC_MANUAL
) {
6652 // function body written by the compiler
6655 body
= mprintf("// written by %s in " __FILE__
" at %d\n"
6656 , __FUNCTION__
, __LINE__
);
6658 body
= mputprintf(body
,
6661 , return_type_str
, genname_str
, formal_par_list
);
6662 switch (function_type
) {
6663 case EXTFUNC_ENCODE
:
6664 body
= generate_code_encode(body
);
6666 case EXTFUNC_DECODE
:
6667 body
= generate_code_decode(body
);
6670 FATAL_ERROR("Def_ExtFunction::generate_code()");
6672 body
= mputstr(body
, "}\n\n");
6673 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6678 Free(formal_par_list
);
6680 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
6681 "%s.add_function(\"%s\", (genericfunc_t)&%s, NULL);\n",
6682 get_module_object_name(), id
->get_dispname().c_str(), genname_str
);
6685 void Def_ExtFunction::generate_code(CodeGenHelper
& cgh
) {
6686 generate_code(cgh
.get_current_outputstruct());
6689 void Def_ExtFunction::dump_internal(unsigned level
) const
6691 DEBUG(level
, "External function: %s", id
->get_dispname().c_str());
6692 DEBUG(level
+ 1, "Parameters:");
6693 fp_list
->dump(level
+ 2);
6695 DEBUG(level
+ 1, "Return type:");
6696 return_type
->dump(level
+ 2);
6697 if(asstype
== A_EXT_FUNCTION_RTEMP
) DEBUG(level
+ 1, "Returns template");
6699 if (prototype
!= PROTOTYPE_NONE
)
6700 DEBUG(level
+ 1, "Prototype: %s", get_prototype_name());
6701 if (function_type
!= EXTFUNC_MANUAL
) {
6702 DEBUG(level
+ 1, "Automatically generated: %s",
6703 function_type
== EXTFUNC_ENCODE
? "encoder" : "decoder");
6704 DEBUG(level
+ 2, "Encoding type: %s",
6705 Type::get_encoding_name(encoding_type
));
6706 if (encoding_options
)
6707 DEBUG(level
+ 2, "Encoding options: %s", encoding_options
->c_str());
6709 if (eb_list
) eb_list
->dump(level
+ 1);
6712 void Def_ExtFunction::generate_json_schema_ref(map
<Type
*, JSON_Tokenizer
>& json_refs
)
6714 // only do anything if this is a JSON encoding or decoding function
6715 if (encoding_type
== Type::CT_JSON
&&
6716 (function_type
== EXTFUNC_ENCODE
|| function_type
== EXTFUNC_DECODE
)) {
6717 // retrieve the encoded type
6719 if (function_type
== EXTFUNC_ENCODE
) {
6720 // for encoding functions it's always the first parameter
6721 type
= fp_list
->get_fp_byIndex(0)->get_Type();
6723 // for decoding functions it depends on the prototype
6724 switch (prototype
) {
6725 case PROTOTYPE_CONVERT
:
6728 case PROTOTYPE_FAST
:
6729 case PROTOTYPE_BACKTRACK
:
6730 case PROTOTYPE_SLIDING
:
6731 type
= fp_list
->get_fp_byIndex(1)->get_Type();
6734 FATAL_ERROR("Def_ExtFunction::generate_json_schema_ref");
6738 // step over the type reference created for this function
6739 type
= type
->get_type_refd();
6741 JSON_Tokenizer
* json
= NULL
;
6742 if (json_refs
.has_key(type
)) {
6743 // the schema segment containing the type's reference already exists
6744 json
= json_refs
[type
];
6746 // the schema segment doesn't exist yet, create it and insert the reference
6747 json
= new JSON_Tokenizer
;
6748 json_refs
.add(type
, json
);
6749 type
->generate_json_schema_ref(*json
);
6752 // insert a property to specify which function this is (encoding or decoding)
6753 json
->put_next_token(JSON_TOKEN_NAME
, (function_type
== EXTFUNC_ENCODE
) ?
6754 "encoding" : "decoding");
6756 // place the function's info in an object
6757 json
->put_next_token(JSON_TOKEN_OBJECT_START
);
6759 // insert information related to the function's prototype in an array
6760 json
->put_next_token(JSON_TOKEN_NAME
, "prototype");
6761 json
->put_next_token(JSON_TOKEN_ARRAY_START
);
6763 // 1st element: external function prototype name (as string)
6765 case PROTOTYPE_CONVERT
:
6766 json
->put_next_token(JSON_TOKEN_STRING
, "\"convert\"");
6768 case PROTOTYPE_FAST
:
6769 json
->put_next_token(JSON_TOKEN_STRING
, "\"fast\"");
6771 case PROTOTYPE_BACKTRACK
:
6772 json
->put_next_token(JSON_TOKEN_STRING
, "\"backtrack\"");
6774 case PROTOTYPE_SLIDING
:
6775 json
->put_next_token(JSON_TOKEN_STRING
, "\"sliding\"");
6778 FATAL_ERROR("Def_ExtFunction::generate_json_schema_ref");
6781 // 2nd element: external function name
6782 char* func_name_str
= mprintf("\"%s\"", id
->get_dispname().c_str());
6783 json
->put_next_token(JSON_TOKEN_STRING
, func_name_str
);
6784 Free(func_name_str
);
6786 // the rest of the elements contain the names of the function's parameters (1 or 2)
6787 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
6788 char* param_str
= mprintf("\"%s\"",
6789 fp_list
->get_fp_byIndex(i
)->get_id().get_dispname().c_str());
6790 json
->put_next_token(JSON_TOKEN_STRING
, param_str
);
6794 // end of the prototype's array
6795 json
->put_next_token(JSON_TOKEN_ARRAY_END
);
6797 // insert error behavior data
6798 if (eb_list
!= NULL
) {
6799 json
->put_next_token(JSON_TOKEN_NAME
, "errorBehavior");
6800 json
->put_next_token(JSON_TOKEN_OBJECT_START
);
6802 // add each error behavior modification as a property
6803 for (size_t i
= 0; i
< eb_list
->get_nof_ebs(); ++i
) {
6804 ErrorBehaviorSetting
* eb
= eb_list
->get_ebs_byIndex(i
);
6805 json
->put_next_token(JSON_TOKEN_NAME
, eb
->get_error_type().c_str());
6806 char* handling_str
= mprintf("\"%s\"", eb
->get_error_handling().c_str());
6807 json
->put_next_token(JSON_TOKEN_STRING
, handling_str
);
6811 json
->put_next_token(JSON_TOKEN_OBJECT_END
);
6814 // insert printing type
6815 if (json_printing
!= NULL
) {
6816 json
->put_next_token(JSON_TOKEN_NAME
, "printing");
6817 json
->put_next_token(JSON_TOKEN_STRING
,
6818 (json_printing
->get_printing() == PrintingType::PT_PRETTY
) ?
6819 "\"pretty\"" : "\"compact\"");
6822 // end of this function's object
6823 json
->put_next_token(JSON_TOKEN_OBJECT_END
);
6827 // =================================
6828 // ===== Def_Altstep
6829 // =================================
6831 Def_Altstep::Def_Altstep(Identifier
*p_id
, FormalParList
*p_fpl
,
6832 Reference
*p_runs_on_ref
, StatementBlock
*p_sb
,
6834 : Definition(A_ALTSTEP
, p_id
), fp_list(p_fpl
), runs_on_ref(p_runs_on_ref
),
6835 runs_on_type(0), sb(p_sb
), ags(p_ags
)
6837 if (!p_fpl
|| !p_sb
|| !p_ags
)
6838 FATAL_ERROR("Def_Altstep::Def_Altstep()");
6839 fp_list
->set_my_def(this);
6840 sb
->set_my_def(this);
6841 ags
->set_my_def(this);
6842 ags
->set_my_sb(sb
, 0);
6845 Def_Altstep::~Def_Altstep()
6853 Def_Altstep
*Def_Altstep::clone() const
6855 FATAL_ERROR("Def_Altstep::clone");
6858 void Def_Altstep::set_fullname(const string
& p_fullname
)
6860 Definition::set_fullname(p_fullname
);
6861 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
6862 if (runs_on_ref
) runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
6863 sb
->set_fullname(p_fullname
+".<block>");
6864 ags
->set_fullname(p_fullname
+ ".<guards>");
6867 void Def_Altstep::set_my_scope(Scope
*p_scope
)
6869 bridgeScope
.set_parent_scope(p_scope
);
6870 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
6872 Definition::set_my_scope(&bridgeScope
);
6873 // the scope of the parameter list is set during checking
6874 if (runs_on_ref
) runs_on_ref
->set_my_scope(&bridgeScope
);
6875 sb
->set_my_scope(fp_list
);
6876 ags
->set_my_scope(sb
);
6879 Type
*Def_Altstep::get_RunsOnType()
6881 if (!checked
) chk();
6882 return runs_on_type
;
6885 FormalParList
*Def_Altstep::get_FormalParList()
6887 if (!checked
) chk();
6891 RunsOnScope
*Def_Altstep::get_runs_on_scope(Type
*comptype
)
6893 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
6894 if (!my_module
) FATAL_ERROR("Def_Altstep::get_runs_on_scope()");
6895 return my_module
->get_runs_on_scope(comptype
);
6898 void Def_Altstep::chk()
6900 if (checked
) return;
6902 Error_Context
cntxt(this, "In altstep definition `%s'",
6903 id
->get_dispname().c_str());
6904 Scope
*parlist_scope
= my_scope
;
6906 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
6907 runs_on_type
= runs_on_ref
->chk_comptype_ref();
6909 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
6910 runs_on_scope
->set_parent_scope(my_scope
);
6911 parlist_scope
= runs_on_scope
;
6914 fp_list
->set_my_scope(parlist_scope
);
6915 fp_list
->chk(asstype
);
6917 ags
->set_is_altstep();
6918 ags
->set_my_ags(ags
);
6919 ags
->set_my_laic_stmt(ags
, 0);
6921 if (!semantic_check_only
) {
6922 fp_list
->set_genname(get_genname());
6923 sb
->set_code_section(GovernedSimple::CS_INLINE
);
6924 ags
->set_code_section(GovernedSimple::CS_INLINE
);
6926 if (w_attrib_path
) {
6927 w_attrib_path
->chk_global_attrib();
6928 w_attrib_path
->chk_no_qualif();
6932 void Def_Altstep::generate_code(output_struct
*target
, bool)
6934 const string
& t_genname
= get_genname();
6935 const char *genname_str
= t_genname
.c_str();
6936 const char *dispname_str
= id
->get_dispname().c_str();
6937 char *formal_par_list
= fp_list
->generate_code(memptystr());
6938 fp_list
->generate_code_defval(target
);
6940 // function for altstep instance: prototype
6941 target
->header
.function_prototypes
=
6942 mputprintf(target
->header
.function_prototypes
,
6943 "extern alt_status %s_instance(%s);\n", genname_str
, formal_par_list
);
6945 // function for altstep instance: body
6946 char *str
= mprintf("alt_status %s_instance(%s)\n"
6947 "{\n", genname_str
, formal_par_list
);
6948 str
= create_location_object(str
, "ALTSTEP", dispname_str
);
6949 str
= fp_list
->generate_shadow_objects(str
);
6950 str
= sb
->generate_code(str
);
6951 str
= ags
->generate_code_altstep(str
);
6952 str
= mputstr(str
, "}\n\n");
6953 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
6957 char *actual_par_list
=
6958 fp_list
->generate_code_actual_parlist(memptystr(), "");
6960 // wrapper function for stand-alone instantiation: prototype
6961 target
->header
.function_prototypes
=
6962 mputprintf(target
->header
.function_prototypes
,
6963 "extern void %s(%s);\n", genname_str
, formal_par_list
);
6965 // wrapper function for stand-alone instantiation: body
6966 target
->source
.function_bodies
=
6967 mputprintf(target
->source
.function_bodies
, "void %s(%s)\n"
6970 "boolean block_flag = FALSE;\n"
6971 "alt_status altstep_flag = ALT_UNCHECKED, "
6972 "default_flag = ALT_UNCHECKED;\n"
6974 "TTCN_Snapshot::take_new(block_flag);\n"
6975 "if (altstep_flag != ALT_NO) {\n"
6976 "altstep_flag = %s_instance(%s);\n"
6977 "if (altstep_flag == ALT_YES || altstep_flag == ALT_BREAK) return;\n"
6978 "else if (altstep_flag == ALT_REPEAT) goto altstep_begin;\n"
6980 "if (default_flag != ALT_NO) {\n"
6981 "default_flag = TTCN_Default::try_altsteps();\n"
6982 "if (default_flag == ALT_YES || default_flag == ALT_BREAK) return;\n"
6983 "else if (default_flag == ALT_REPEAT) goto altstep_begin;\n"
6985 "if (altstep_flag == ALT_NO && default_flag == ALT_NO) "
6986 "TTCN_error(\"None of the branches can be chosen in altstep %s.\");\n"
6987 "else block_flag = TRUE;\n"
6989 "}\n\n", genname_str
, formal_par_list
, genname_str
, actual_par_list
,
6992 // class for keeping the altstep in the default context
6993 // the class is for internal use, we do not need to publish it in the
6995 str
= mprintf("class %s_Default : public Default_Base {\n", genname_str
);
6996 str
= fp_list
->generate_code_object(str
, "par_");
6997 str
= mputprintf(str
, "public:\n"
6999 "alt_status call_altstep();\n"
7000 "};\n\n", genname_str
, formal_par_list
);
7001 target
->source
.class_defs
= mputstr(target
->source
.class_defs
, str
);
7003 // member functions of the class
7004 str
= mprintf("%s_Default::%s_Default(%s)\n"
7005 " : Default_Base(\"%s\")", genname_str
, genname_str
, formal_par_list
,
7007 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); i
++) {
7008 const char *fp_name_str
=
7009 fp_list
->get_fp_byIndex(i
)->get_id().get_name().c_str();
7010 str
= mputprintf(str
, ", par_%s(%s)", fp_name_str
, fp_name_str
);
7012 str
= mputstr(str
, "\n{\n}\n\n");
7013 char *actual_par_list_prefixed
=
7014 fp_list
->generate_code_actual_parlist(memptystr(), "par_");
7015 str
= mputprintf(str
, "alt_status %s_Default::call_altstep()\n"
7017 "return %s_instance(%s);\n"
7018 "}\n\n", genname_str
, genname_str
, actual_par_list_prefixed
);
7019 Free(actual_par_list_prefixed
);
7020 target
->source
.methods
= mputstr(target
->source
.methods
, str
);
7023 // function for default activation: prototype
7024 target
->header
.function_prototypes
=
7025 mputprintf(target
->header
.function_prototypes
,
7026 "extern Default_Base *activate_%s(%s);\n", genname_str
,
7029 // function for default activation: body
7030 str
= mprintf("Default_Base *activate_%s(%s)\n"
7031 "{\n", genname_str
, formal_par_list
);
7032 str
= mputprintf(str
, "return new %s_Default(%s);\n"
7033 "}\n\n", genname_str
, actual_par_list
);
7034 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7038 Free(formal_par_list
);
7039 Free(actual_par_list
);
7041 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7042 "%s.add_altstep(\"%s\", (genericfunc_t)&%s_instance, (genericfunc_t )&activate_%s, "
7043 "(genericfunc_t )&%s);\n", get_module_object_name(), dispname_str
, genname_str
,
7044 genname_str
, genname_str
);
7047 void Def_Altstep::generate_code(CodeGenHelper
& cgh
) {
7048 generate_code(cgh
.get_current_outputstruct());
7051 void Def_Altstep::dump_internal(unsigned level
) const
7053 DEBUG(level
, "Altstep: %s", id
->get_dispname().c_str());
7054 DEBUG(level
+ 1, "Parameters:");
7055 fp_list
->dump(level
+ 1);
7057 DEBUG(level
+ 1, "Runs on clause:");
7058 runs_on_ref
->dump(level
+ 2);
7061 DEBUG(level + 1, "Local definitions:");
7062 sb->dump(level + 2);
7064 DEBUG(level
+ 1, "Guards:");
7065 ags
->dump(level
+ 2);
7068 void Def_Altstep::set_parent_path(WithAttribPath
* p_path
) {
7069 Definition::set_parent_path(p_path
);
7070 sb
->set_parent_path(w_attrib_path
);
7073 // =================================
7074 // ===== Def_Testcase
7075 // =================================
7077 Def_Testcase::Def_Testcase(Identifier
*p_id
, FormalParList
*p_fpl
,
7078 Reference
*p_runs_on_ref
, Reference
*p_system_ref
,
7079 StatementBlock
*p_block
)
7080 : Definition(A_TESTCASE
, p_id
), fp_list(p_fpl
), runs_on_ref(p_runs_on_ref
),
7081 runs_on_type(0), system_ref(p_system_ref
), system_type(0), block(p_block
)
7083 if (!p_fpl
|| !p_runs_on_ref
|| !p_block
)
7084 FATAL_ERROR("Def_Testcase::Def_Testcase()");
7085 fp_list
->set_my_def(this);
7086 block
->set_my_def(this);
7089 Def_Testcase::~Def_Testcase()
7097 Def_Testcase
*Def_Testcase::clone() const
7099 FATAL_ERROR("Def_Testcase::clone");
7102 void Def_Testcase::set_fullname(const string
& p_fullname
)
7104 Definition::set_fullname(p_fullname
);
7105 fp_list
->set_fullname(p_fullname
+ ".<formal_par_list>");
7106 runs_on_ref
->set_fullname(p_fullname
+ ".<runs_on_type>");
7107 if (system_ref
) system_ref
->set_fullname(p_fullname
+ ".<system_type>");
7108 block
->set_fullname(p_fullname
+ ".<statement_block>");
7111 void Def_Testcase::set_my_scope(Scope
*p_scope
)
7113 bridgeScope
.set_parent_scope(p_scope
);
7114 bridgeScope
.set_scopeMacro_name(id
->get_dispname());
7116 Definition::set_my_scope(&bridgeScope
);
7117 // the scope of the parameter list is set during checking
7118 runs_on_ref
->set_my_scope(&bridgeScope
);
7119 if (system_ref
) system_ref
->set_my_scope(&bridgeScope
);
7120 block
->set_my_scope(fp_list
);
7123 Type
*Def_Testcase::get_RunsOnType()
7125 if (!checked
) chk();
7126 return runs_on_type
;
7129 Type
*Def_Testcase::get_SystemType()
7131 if (!checked
) chk();
7135 FormalParList
*Def_Testcase::get_FormalParList()
7137 if (!checked
) chk();
7141 RunsOnScope
*Def_Testcase::get_runs_on_scope(Type
*comptype
)
7143 Module
*my_module
= dynamic_cast<Module
*>(my_scope
->get_scope_mod());
7144 if (!my_module
) FATAL_ERROR("Def_Testcase::get_runs_on_scope()");
7145 return my_module
->get_runs_on_scope(comptype
);
7148 void Def_Testcase::chk()
7150 if (checked
) return;
7152 Error_Context
cntxt(this, "In testcase definition `%s'",
7153 id
->get_dispname().c_str());
7154 Scope
*parlist_scope
= my_scope
;
7156 Error_Context
cntxt2(runs_on_ref
, "In `runs on' clause");
7157 runs_on_type
= runs_on_ref
->chk_comptype_ref();
7159 Scope
*runs_on_scope
= get_runs_on_scope(runs_on_type
);
7160 runs_on_scope
->set_parent_scope(my_scope
);
7161 parlist_scope
= runs_on_scope
;
7165 Error_Context
cntxt2(system_ref
, "In `system' clause");
7166 system_type
= system_ref
->chk_comptype_ref();;
7168 fp_list
->set_my_scope(parlist_scope
);
7169 fp_list
->chk(asstype
);
7171 if (!semantic_check_only
) {
7172 fp_list
->set_genname(get_genname());
7173 block
->set_code_section(GovernedSimple::CS_INLINE
);
7175 if (w_attrib_path
) {
7176 w_attrib_path
->chk_global_attrib();
7177 w_attrib_path
->chk_no_qualif();
7181 void Def_Testcase::generate_code(output_struct
*target
, bool)
7183 const string
& t_genname
= get_genname();
7184 const char *genname_str
= t_genname
.c_str();
7185 const char *dispname_str
= id
->get_dispname().c_str();
7186 // formal parameter list
7187 char *formal_par_list
= fp_list
->generate_code(memptystr());
7188 fp_list
->generate_code_defval(target
);
7189 if (fp_list
->get_nof_fps() > 0)
7190 formal_par_list
= mputstr(formal_par_list
, ", ");
7191 formal_par_list
= mputstr(formal_par_list
,
7192 "boolean has_timer, double timer_value");
7194 // function prototype
7195 target
->header
.function_prototypes
=
7196 mputprintf(target
->header
.function_prototypes
,
7197 "extern verdicttype testcase_%s(%s);\n", genname_str
, formal_par_list
);
7200 char *body
= mprintf("verdicttype testcase_%s(%s)\n"
7201 "{\n", genname_str
, formal_par_list
);
7202 Free(formal_par_list
);
7203 // Checking whether the testcase was invoked from another one.
7204 // At this point the location information should refer to the execute()
7205 // statement rather than this testcase.
7206 body
= mputstr(body
, "TTCN_Runtime::check_begin_testcase(has_timer, "
7208 body
= create_location_object(body
, "TESTCASE", dispname_str
);
7209 body
= fp_list
->generate_shadow_objects(body
);
7210 body
= mputprintf(body
, "try {\n"
7211 "TTCN_Runtime::begin_testcase(\"%s\", \"%s\", ",
7212 my_scope
->get_scope_mod()->get_modid().get_dispname().c_str(),
7214 ComponentTypeBody
*runs_on_body
= runs_on_type
->get_CompBody();
7215 body
= runs_on_body
->generate_code_comptype_name(body
);
7216 body
= mputstr(body
, ", ");
7218 body
= system_type
->get_CompBody()->generate_code_comptype_name(body
);
7219 else body
= runs_on_body
->generate_code_comptype_name(body
);
7220 body
= mputstr(body
, ", has_timer, timer_value);\n");
7221 body
= block
->generate_code(body
);
7222 body
= mputprintf(body
,
7223 "} catch (const TC_Error& tc_error) {\n"
7224 "} catch (const TC_End& tc_end) {\n"
7225 "TTCN_Logger::log_str(TTCN_FUNCTION, \"Test case %s was stopped.\");\n"
7226 "}\n", dispname_str
);
7227 body
= mputstr(body
, "return TTCN_Runtime::end_testcase();\n"
7229 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7233 if (fp_list
->get_nof_fps() == 0) {
7234 // adding to the list of startable testcases
7235 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7236 "%s.add_testcase_nonpard(\"%s\", testcase_%s);\n",
7237 get_module_object_name(), dispname_str
, genname_str
);
7239 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7240 "%s.add_testcase_pard(\"%s\", (genericfunc_t)&testcase_%s);\n",
7241 get_module_object_name(), dispname_str
, genname_str
);
7243 // If every formal parameter has a default value, the testcase
7244 // might be callable after all.
7245 bool callable
= true;
7246 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
7247 FormalPar
*fp
= fp_list
->get_fp_byIndex(i
);
7248 if (!fp
->has_defval()) {
7255 // Write a wrapper, which acts as a no-param testcase
7256 // by calling the parameterized testcase with the default values.
7257 target
->header
.function_prototypes
=
7258 mputprintf(target
->header
.function_prototypes
,
7259 "extern verdicttype testcase_%s_defparams(boolean has_timer, double timer_value);\n",
7261 target
->source
.function_bodies
= mputprintf(target
->source
.function_bodies
,
7262 "verdicttype testcase_%s_defparams(boolean has_timer, double timer_value) {\n"
7263 " return testcase_%s(",
7264 genname_str
, genname_str
);
7266 for (size_t i
= 0; i
< fp_list
->get_nof_fps(); ++i
) {
7267 FormalPar
*fp
= fp_list
->get_fp_byIndex(i
);
7268 ActualPar
*ap
= fp
->get_defval();
7269 switch (ap
->get_selection()) {
7270 case ActualPar::AP_VALUE
:
7271 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7272 ap
->get_Value()->get_genname_own(my_scope
).c_str());
7274 case ActualPar::AP_TEMPLATE
:
7275 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7276 ap
->get_TemplateInstance()->get_Template()->get_genname_own(my_scope
).c_str());
7278 case ActualPar::AP_REF
:
7279 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7280 ap
->get_Ref()->get_refd_assignment()->get_genname_from_scope(my_scope
).c_str());
7282 case ActualPar::AP_DEFAULT
:
7283 // Can't happen. This ActualPar was created by
7284 // Ttcn::FormalPar::chk_actual_par as the default value for
7285 // a FormalPar, and it only ever creates vale, template or ref.
7288 FATAL_ERROR("Def_Testcase::generate_code()");
7291 // always append a comma, because has_timer and timer_value follows
7292 target
->source
.function_bodies
= mputstrn(target
->source
.function_bodies
,
7296 target
->source
.function_bodies
= mputstr(target
->source
.function_bodies
,
7297 "has_timer, timer_value);\n"
7299 // Add the non-parameterized wrapper *after* the parameterized one,
7300 // with the same name. Linear search will always find the first
7301 // (user-visible, parameterized) testcase.
7302 // TTCN_Module::execute_testcase knows that if after a parameterized
7303 // testcase another testcase with the same name follows,
7304 // it's the callable, non-parameterized wrapper.
7306 // TTCN_Module::list_testcases skips parameterized testcases;
7307 // it will now list the non-parameterized wrapper.
7308 target
->functions
.pre_init
= mputprintf(target
->functions
.pre_init
,
7309 "%s.add_testcase_nonpard(\"%s\", testcase_%s_defparams);\n",
7310 get_module_object_name(), dispname_str
, genname_str
);
7312 } // has formal parameters
7315 void Def_Testcase::generate_code(CodeGenHelper
& cgh
) {
7316 generate_code(cgh
.get_current_outputstruct());
7319 void Def_Testcase::dump_internal(unsigned level
) const
7321 DEBUG(level
, "Testcase: %s", id
->get_dispname().c_str());
7322 DEBUG(level
+ 1, "Parameters:");
7323 fp_list
->dump(level
+ 1);
7324 DEBUG(level
+ 1, "Runs on clause:");
7325 runs_on_ref
->dump(level
+ 2);
7327 DEBUG(level
+ 1, "System clause:");
7328 system_ref
->dump(level
+ 2);
7330 DEBUG(level
+ 1, "Statement block:");
7331 block
->dump(level
+ 2);
7334 void Def_Testcase::set_parent_path(WithAttribPath
* p_path
) {
7335 Definition::set_parent_path(p_path
);
7337 block
->set_parent_path(w_attrib_path
);
7340 // =================================
7342 // =================================
7344 FormalPar::FormalPar(asstype_t p_asstype
, Type
*p_type
, Identifier
* p_name
,
7345 TemplateInstance
*p_defval
, bool p_lazy_eval
)
7346 : Definition(p_asstype
, p_name
), type(p_type
), my_parlist(0),
7347 used_as_lvalue(false), template_restriction(TR_NONE
),
7348 lazy_eval(p_lazy_eval
)
7350 switch (p_asstype
) {
7354 case A_PAR_VAL_INOUT
:
7355 case A_PAR_TEMPL_IN
:
7356 case A_PAR_TEMPL_OUT
:
7357 case A_PAR_TEMPL_INOUT
:
7361 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): invalid parameter type");
7364 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): NULL pointer");
7365 type
->set_ownertype(Type::OT_FORMAL_PAR
, this);
7366 defval
.ti
= p_defval
;
7369 FormalPar::FormalPar(asstype_t p_asstype
,
7370 template_restriction_t p_template_restriction
, Type
*p_type
,
7371 Identifier
* p_name
, TemplateInstance
*p_defval
, bool p_lazy_eval
)
7372 : Definition(p_asstype
, p_name
), type(p_type
), my_parlist(0),
7373 used_as_lvalue(false), template_restriction(p_template_restriction
),
7374 lazy_eval(p_lazy_eval
)
7376 switch (p_asstype
) {
7377 case A_PAR_TEMPL_IN
:
7378 case A_PAR_TEMPL_OUT
:
7379 case A_PAR_TEMPL_INOUT
:
7382 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): parameter not template");
7385 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): NULL pointer");
7386 type
->set_ownertype(Type::OT_FORMAL_PAR
, this);
7387 defval
.ti
= p_defval
;
7390 FormalPar::FormalPar(asstype_t p_asstype
, Identifier
* p_name
,
7391 TemplateInstance
*p_defval
)
7392 : Definition(p_asstype
, p_name
), type(0), my_parlist(0),
7393 used_as_lvalue(false), template_restriction(TR_NONE
), lazy_eval(false)
7395 if (p_asstype
!= A_PAR_TIMER
)
7396 FATAL_ERROR("Ttcn::FormalPar::FormalPar(): invalid parameter type");
7397 defval
.ti
= p_defval
;
7400 FormalPar::~FormalPar()
7403 if (checked
) delete defval
.ap
;
7404 else delete defval
.ti
;
7407 FormalPar
* FormalPar::clone() const
7409 FATAL_ERROR("FormalPar::clone");
7412 void FormalPar::set_fullname(const string
& p_fullname
)
7414 Definition::set_fullname(p_fullname
);
7415 if (type
) type
->set_fullname(p_fullname
+ ".<type>");
7417 if (defval
.ap
) defval
.ap
->set_fullname(p_fullname
+ ".<default_value>");
7419 if (defval
.ti
) defval
.ti
->set_fullname(p_fullname
+ ".<default_value>");
7423 void FormalPar::set_my_scope(Scope
*p_scope
)
7425 Definition::set_my_scope(p_scope
);
7426 if (type
) type
->set_my_scope(p_scope
);
7428 if (defval
.ap
) defval
.ap
->set_my_scope(p_scope
);
7430 if (defval
.ti
) defval
.ti
->set_my_scope(p_scope
);
7434 bool FormalPar::is_local() const
7439 Type
*FormalPar::get_Type()
7441 if (!checked
) chk();
7442 if (!type
) FATAL_ERROR("FormalPar::get_Type()");
7446 void FormalPar::chk()
7448 if (checked
) return;
7450 TemplateInstance
*default_value
= defval
.ti
;
7454 Type
*t
= type
->get_type_refd_last();
7455 // checks for forbidden type <-> parameter combinations
7456 switch (t
->get_typetype()) {
7460 case A_PAR_VAL_INOUT
:
7461 asstype
= A_PAR_PORT
;
7464 error("Port type `%s' cannot be used as %s",
7465 t
->get_fullname().c_str(), get_assname());
7468 case Type::T_SIGNATURE
:
7470 case A_PAR_TEMPL_IN
:
7471 case A_PAR_TEMPL_OUT
:
7472 case A_PAR_TEMPL_INOUT
:
7475 error("Signature `%s' cannot be used as %s",
7476 t
->get_fullname().c_str(), get_assname());
7483 FATAL_ERROR("FormalPar::chk()");
7485 asstype
= A_PAR_VAL_IN
;
7490 } else if (asstype
!= A_PAR_TIMER
) FATAL_ERROR("FormalPar::chk()");
7492 if (default_value
) {
7493 Error_Context
cntxt(default_value
, "In default value");
7494 defval
.ap
= chk_actual_par(default_value
, Type::EXPECTED_STATIC_VALUE
);
7495 delete default_value
;
7496 if (!semantic_check_only
)
7497 defval
.ap
->set_code_section(GovernedSimple::CS_POST_INIT
);
7501 bool FormalPar::has_defval() const
7503 if (checked
) return defval
.ap
!= 0;
7504 else return defval
.ti
!= 0;
7507 bool FormalPar::has_notused_defval() const
7509 if (checked
) FATAL_ERROR("FormalPar::has_notused_defval");
7510 if (!defval
.ti
|| !defval
.ti
->get_Template())
7512 return defval
.ti
->get_Template()->get_templatetype()
7513 == Template::TEMPLATE_NOTUSED
;
7516 ActualPar
*FormalPar::get_defval() const
7518 if (!checked
) FATAL_ERROR("FormalPar::get_defval()");
7522 // Extract the TemplateInstance from an ActualPar.
7523 void FormalPar::set_defval(ActualPar
*defpar
)
7525 // ActualPar::clone() is not implemented, since we need such a function
7526 // only here only for AP_{VALUE,TEMPLATE} parameters. AP_ERROR can also
7527 // happen for Def_Template nodes, but they will be errors later.
7528 // FIXME: This function is Def_Template specific.
7529 if (!defval
.ti
->get_Template() || defval
.ti
->get_Template()
7530 ->get_templatetype() != Template::TEMPLATE_NOTUSED
)
7531 FATAL_ERROR("FormalPar::set_defval()");
7532 TemplateInstance
*reversed_ti
= 0;
7533 switch (defpar
->get_selection()) {
7534 case ActualPar::AP_VALUE
:
7535 reversed_ti
= new TemplateInstance(type
->clone(), 0, new Template
7536 (defpar
->get_Value()->clone())); // Trust the clone().
7538 case ActualPar::AP_TEMPLATE
:
7539 reversed_ti
= defpar
->get_TemplateInstance()->clone();
7541 case ActualPar::AP_ERROR
:
7542 break; // Can happen, but let it go.
7543 case ActualPar::AP_REF
:
7544 case ActualPar::AP_DEFAULT
:
7546 FATAL_ERROR("FormalPar::set_defval()");
7550 reversed_ti
->set_my_scope(get_my_scope());
7551 defval
.ti
= reversed_ti
;
7555 ActualPar
*FormalPar::chk_actual_par(TemplateInstance
*actual_par
,
7556 Type::expected_value_t exp_val
)
7558 if (!checked
) chk();
7562 return chk_actual_par_value(actual_par
, exp_val
);
7564 case A_PAR_VAL_INOUT
:
7565 return chk_actual_par_by_ref(actual_par
, false, exp_val
);
7566 case A_PAR_TEMPL_IN
:
7567 return chk_actual_par_template(actual_par
, exp_val
);
7568 case A_PAR_TEMPL_OUT
:
7569 case A_PAR_TEMPL_INOUT
:
7570 return chk_actual_par_by_ref(actual_par
, true, exp_val
);
7572 return chk_actual_par_timer(actual_par
, exp_val
);
7574 return chk_actual_par_port(actual_par
, exp_val
);
7576 FATAL_ERROR("FormalPar::chk_actual_par()");
7578 return 0; // to avoid warnings
7581 ActualPar
*FormalPar::chk_actual_par_value(TemplateInstance
*actual_par
,
7582 Type::expected_value_t exp_val
)
7584 actual_par
->chk_Type(type
);
7585 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7587 derived_ref
->error("An in-line modified template cannot be used as %s",
7589 actual_par
->chk_DerivedRef(type
);
7591 Template
*ap_template
= actual_par
->get_Template();
7592 if (ap_template
->is_Value()) {
7593 Value
*v
= ap_template
->get_Value();
7594 v
->set_my_governor(type
);
7595 type
->chk_this_value_ref(v
);
7596 type
->chk_this_value(v
, 0, exp_val
, INCOMPLETE_NOT_ALLOWED
,
7597 OMIT_NOT_ALLOWED
, SUB_CHK
);
7598 return new ActualPar(v
);
7600 actual_par
->error("A specific value without matching symbols "
7601 "was expected for a %s", get_assname());
7602 return new ActualPar();
7606 static void chk_defpar_value(const Value
* v
)
7608 Common::Reference
*vref
= v
->get_reference();
7609 Common::Assignment
*ass2
= vref
->get_refd_assignment();
7611 Scope
*scope
= ass2
->get_my_scope();
7612 ComponentTypeBody
*ctb
= dynamic_cast<ComponentTypeBody
*>(scope
);
7613 if (ctb
) { // this is a component variable
7614 v
->error("default value cannot refer to"
7615 " a template field of the component in the `runs on' clause");
7619 static void chk_defpar_template(const Template
*body
,
7620 Type::expected_value_t exp_val
)
7622 switch (body
->get_templatetype()) {
7623 case Template::TEMPLATE_ERROR
:
7624 break; // could be erroneous in the source; skip it
7625 case Template::TEMPLATE_NOTUSED
:
7626 case Template::OMIT_VALUE
:
7627 case Template::ANY_VALUE
:
7628 case Template::ANY_OR_OMIT
:
7629 break; // acceptable (?)
7630 case Template::TEMPLATE_INVOKE
: // calling a function is not acceptable
7631 body
->error("default value can not be a function invocation");
7633 case Template::VALUE_RANGE
: {
7634 ValueRange
*range
= body
->get_value_range();
7635 Value
*low
= range
->get_min_v();
7636 Type::typetype_t tt_low
= low
->get_expr_returntype(exp_val
);
7637 Value
*high
= range
->get_max_v();
7638 Type::typetype_t tt_high
= high
->get_expr_returntype(exp_val
);
7639 if (tt_low
== tt_high
) break;
7642 case Template::BSTR_PATTERN
:
7643 case Template::HSTR_PATTERN
:
7644 case Template::OSTR_PATTERN
:
7645 case Template::CSTR_PATTERN
:
7646 case Template::USTR_PATTERN
:
7647 break; // should be acceptable in all cases (if only fixed strings possible)
7649 case Template::SPECIFIC_VALUE
: {
7650 Common::Value
*v
= body
->get_specific_value();
7651 if (v
->get_valuetype() == Value::V_REFD
) chk_defpar_value(v
);
7654 case Template::ALL_FROM
:
7655 case Template::VALUE_LIST_ALL_FROM
:
7656 FATAL_ERROR("should have been flattened");
7658 case Template::SUPERSET_MATCH
:
7659 case Template::SUBSET_MATCH
:
7660 case Template::PERMUTATION_MATCH
:
7661 case Template::TEMPLATE_LIST
:
7662 case Template::COMPLEMENTED_LIST
:
7663 case Template::VALUE_LIST
: {
7664 // in template charstring par := charstring : ("foo", "bar", "baz")
7665 size_t num
= body
->get_nof_comps();
7666 for (size_t i
= 0; i
< num
; ++i
) {
7667 const Template
*tpl
= body
->get_temp_byIndex(i
);
7668 chk_defpar_template(tpl
, exp_val
);
7672 case Template::NAMED_TEMPLATE_LIST
: {
7673 size_t num
= body
->get_nof_comps();
7674 for (size_t i
= 0; i
< num
; ++i
) {
7675 const NamedTemplate
*nt
= body
->get_namedtemp_byIndex(i
);
7676 const Template
*tpl
= nt
->get_template();
7677 chk_defpar_template(tpl
, exp_val
);
7681 case Template::INDEXED_TEMPLATE_LIST
: {
7682 size_t num
= body
->get_nof_comps();
7683 for (size_t i
= 0; i
< num
; ++i
) {
7684 const IndexedTemplate
*it
= body
->get_indexedtemp_byIndex(i
);
7685 const Template
*tpl
= it
->get_template();
7686 chk_defpar_template(tpl
, exp_val
);
7690 case Template::TEMPLATE_REFD
: {
7691 Ref_base
*ref
= body
->get_reference();
7693 Ttcn::ActualParList
*aplist
= ref
->get_parlist();
7695 size_t num
= aplist
->get_nof_pars();
7696 for (size_t i
= 0; i
< num
; ++i
) {
7697 const Ttcn::ActualPar
*ap
= aplist
->get_par(i
);
7699 switch (ap
->get_selection()) {
7700 case ActualPar::AP_ERROR
: {
7702 case ActualPar::AP_VALUE
: {
7703 Value
*v
= ap
->get_Value(); // "v_variable" as the parameter of the template
7705 switch (v
->get_valuetype()) {
7706 case Value::V_REFD
: {
7707 chk_defpar_value(v
);
7713 case ActualPar::AP_TEMPLATE
: {
7714 // A component cannot contain a template definition, parameterized or not.
7715 // Therefore the template this actual par references, cannot be
7716 // a field of a component => no error possible, nothing to do.
7718 case ActualPar::AP_REF
: {
7719 // A template cannot have an out/inout parameter
7720 FATAL_ERROR("Template with out parameter?");
7722 case ActualPar::AP_DEFAULT
: {
7723 ap
= ap
->get_ActualPar();
7727 } // switch actual par selection
7731 } // switch templatetype
7735 // This function is called in two situations:
7736 // 1. FormalParList::chk calls FormalPar::chk to compute the default value
7737 // (make an ActualPar from a TemplateInstance).
7738 // In this case, defval.ti==0, and actual_par contains its old value.
7739 // This case is called only if the formal par has a default value.
7740 // 2. FormalParList::chk_actual_parlist calls FormalPar::chk_actual_par
7741 // to check the parameters supplied by the execute statement to the tc.
7742 // In this case, defval.ap has the value computed in case 1.
7743 ActualPar
*FormalPar::chk_actual_par_template(TemplateInstance
*actual_par
,
7744 Type::expected_value_t exp_val
)
7746 actual_par
->chk(type
);
7747 // actual_par->template_body may change: SPECIFIC_VALUE to TEMPLATE_REFD
7748 Definition
*fplist_def
= my_parlist
->get_my_def();
7749 // The parameter list belongs to this definition. If it's a function
7750 // or testcase, it may have a "runs on" clause.
7751 Def_Function
*parent_fn
= dynamic_cast<Def_Function
*>(fplist_def
);
7752 Type
*runs_on_type
= 0;
7753 if (parent_fn
) runs_on_type
= parent_fn
->get_RunsOnType();
7754 else { // not a function; maybe a testcase
7755 Def_Testcase
*parent_tc
= dynamic_cast<Def_Testcase
*>(fplist_def
);
7756 if (parent_tc
) runs_on_type
= parent_tc
->get_RunsOnType();
7759 // If it _has_ a runs on clause, the type must be a component.
7760 if (runs_on_type
->get_typetype() != Type::T_COMPONENT
) FATAL_ERROR("not component?");
7761 // The default value "shall not refer to elements of the component type
7762 // in the runs on clause"
7763 ComponentTypeBody
*runs_on_component
= runs_on_type
->get_CompBody();
7764 size_t compass
= runs_on_component
->get_nof_asss();
7765 for (size_t c
= 0; c
< compass
; c
++) {
7766 Assignment
*ass
= runs_on_component
->get_ass_byIndex(c
);
7771 Ttcn::Template
* body
= actual_par
->get_Template();
7772 if (exp_val
== Type::EXPECTED_STATIC_VALUE
7773 ||exp_val
== Type::EXPECTED_CONSTANT
) {
7774 chk_defpar_template(body
, exp_val
);
7776 // Rip out the type, derived ref and template from actual_par
7777 // (which may come from a function invocation or the definition
7778 // of the default value) and give it to the new ActualPar.
7779 ActualPar
*ret_val
= new ActualPar(
7780 new TemplateInstance(actual_par
->get_Type(),
7781 actual_par
->get_DerivedRef(), actual_par
->get_Template()));
7782 // Zero out these members because the caller will soon call delete
7783 // on actual_par, but they now belong to ret_val.
7784 // FIXME: should this really be in here, or outside in the caller before the delete ?
7785 actual_par
->release();
7787 if (template_restriction
!=TR_NONE
) {
7788 bool needs_runtime_check
=
7789 ret_val
->get_TemplateInstance()->chk_restriction(
7790 "template formal parameter", template_restriction
);
7791 if (needs_runtime_check
)
7792 ret_val
->set_gen_restriction_check(template_restriction
);
7797 ActualPar
*FormalPar::chk_actual_par_by_ref(TemplateInstance
*actual_par
,
7798 bool is_template
, Type::expected_value_t exp_val
)
7800 Type
*ap_type
= actual_par
->get_Type();
7802 ap_type
->warning("Explicit type specification is useless for an %s",
7804 actual_par
->chk_Type(type
);
7806 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7808 derived_ref
->error("An in-line modified template cannot be used as %s",
7810 actual_par
->chk_DerivedRef(type
);
7812 // needed for the error messages
7813 const char *expected_string
= is_template
?
7814 "template variable or template parameter" :
7815 "variable or value parameter";
7816 Template
*ap_template
= actual_par
->get_Template();
7817 if (ap_template
->is_Ref()) {
7818 Ref_base
*ref
= ap_template
->get_Ref();
7819 Common::Assignment
*ass
= ref
->get_refd_assignment();
7822 return new ActualPar();
7824 bool asstype_correct
= false;
7825 switch (ass
->get_asstype()) {
7827 ass
->use_as_lvalue(*ref
);
7828 if (get_asstype() == A_PAR_VAL_OUT
|| get_asstype() == A_PAR_TEMPL_OUT
) {
7829 ass
->warning("Passing an `in' parameter as another function's `out' parameter");
7834 case A_PAR_VAL_INOUT
:
7835 if (!is_template
) asstype_correct
= true;
7837 case A_PAR_TEMPL_IN
:
7838 ass
->use_as_lvalue(*ref
);
7839 if (get_asstype() == A_PAR_VAL_OUT
|| get_asstype() == A_PAR_TEMPL_OUT
) {
7840 ass
->warning("Passing an `in' parameter as another function's `out' parameter");
7843 case A_VAR_TEMPLATE
:
7844 case A_PAR_TEMPL_OUT
:
7845 case A_PAR_TEMPL_INOUT
:
7846 if (is_template
) asstype_correct
= true;
7851 if (asstype_correct
) {
7852 FieldOrArrayRefs
*t_subrefs
= ref
->get_subrefs();
7853 Type
*ref_type
= ass
->get_Type()->get_field_type(t_subrefs
, exp_val
);
7855 if (!type
->is_identical(ref_type
)) {
7856 ref
->error("Type mismatch: Reference to a %s of type "
7857 "`%s' was expected instead of `%s'", expected_string
,
7858 type
->get_typename().c_str(), ref_type
->get_typename().c_str());
7859 } else if (type
->get_sub_type() && ref_type
->get_sub_type() &&
7860 (type
->get_sub_type()->get_subtypetype()==ref_type
->get_sub_type()->get_subtypetype()) &&
7861 (!type
->get_sub_type()->is_compatible(ref_type
->get_sub_type()))) {
7862 ref
->error("Subtype mismatch: subtype %s has no common value with subtype %s",
7863 type
->get_sub_type()->to_string().c_str(),
7864 ref_type
->get_sub_type()->to_string().c_str());
7866 if (t_subrefs
&& t_subrefs
->refers_to_string_element()) {
7867 ref
->error("Reference to a string element of type `%s' cannot be "
7868 "used in this context", ref_type
->get_typename().c_str());
7872 ref
->error("Reference to a %s was expected for an %s instead of %s",
7873 expected_string
, get_assname(), ass
->get_description().c_str());
7875 ActualPar
* ret_val_ap
= new ActualPar(ref
);
7876 // restriction checking if this is a reference to a template variable
7877 // this is an 'out' or 'inout' template parameter
7878 if (is_template
&& asstype_correct
) {
7879 template_restriction_t refd_tr
;
7880 switch (ass
->get_asstype()) {
7881 case A_VAR_TEMPLATE
: {
7882 Def_Var_Template
* dvt
= dynamic_cast<Def_Var_Template
*>(ass
);
7883 if (!dvt
) FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
7884 refd_tr
= dvt
->get_template_restriction();
7886 case A_PAR_TEMPL_IN
:
7887 case A_PAR_TEMPL_OUT
:
7888 case A_PAR_TEMPL_INOUT
: {
7889 FormalPar
* fp
= dynamic_cast<FormalPar
*>(ass
);
7890 if (!fp
) FATAL_ERROR("Template::chk_restriction_refd()");
7891 refd_tr
= fp
->get_template_restriction();
7894 FATAL_ERROR("FormalPar::chk_actual_par_by_ref()");
7897 refd_tr
= Template::get_sub_restriction(refd_tr
, ref
);
7898 if (template_restriction
!=refd_tr
) {
7899 bool pre_call_check
=
7900 Template::is_less_restrictive(template_restriction
, refd_tr
);
7901 bool post_call_check
=
7902 Template::is_less_restrictive(refd_tr
, template_restriction
);
7903 if (pre_call_check
|| post_call_check
) {
7904 ref
->warning("Inadequate restriction on the referenced %s `%s', "
7905 "this may cause a dynamic test case error at runtime",
7906 ass
->get_assname(), ref
->get_dispname().c_str());
7907 ass
->note("Referenced %s is here", ass
->get_assname());
7910 ret_val_ap
->set_gen_restriction_check(template_restriction
);
7911 if (post_call_check
)
7912 ret_val_ap
->set_gen_post_restriction_check(refd_tr
);
7914 // for out and inout template parameters of external functions
7915 // always check because we do not trust user written C++ code
7916 if (refd_tr
!=TR_NONE
) {
7917 switch (my_parlist
->get_my_def()->get_asstype()) {
7918 case A_EXT_FUNCTION
:
7919 case A_EXT_FUNCTION_RVAL
:
7920 case A_EXT_FUNCTION_RTEMP
:
7921 ret_val_ap
->set_gen_post_restriction_check(refd_tr
);
7930 actual_par
->error("Reference to a %s was expected for an %s",
7931 expected_string
, get_assname());
7932 return new ActualPar();
7936 ActualPar
*FormalPar::chk_actual_par_timer(TemplateInstance
*actual_par
,
7937 Type::expected_value_t exp_val
)
7939 Type
*ap_type
= actual_par
->get_Type();
7941 ap_type
->error("Explicit type specification cannot be used for a "
7943 actual_par
->chk_Type(0);
7945 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7947 derived_ref
->error("An in-line modified template cannot be used as "
7949 actual_par
->chk_DerivedRef(0);
7951 Template
*ap_template
= actual_par
->get_Template();
7952 if (ap_template
->is_Ref()) {
7953 Ref_base
*ref
= ap_template
->get_Ref();
7954 Common::Assignment
*ass
= ref
->get_refd_assignment();
7957 return new ActualPar();
7959 switch (ass
->get_asstype()) {
7961 ArrayDimensions
*dims
= ass
->get_Dimensions();
7962 if (dims
) dims
->chk_indices(ref
, "timer", false, exp_val
);
7963 else if (ref
->get_subrefs()) ref
->error("Reference to single %s "
7964 "cannot have field or array sub-references",
7965 ass
->get_description().c_str());
7968 if (ref
->get_subrefs()) ref
->error("Reference to %s cannot have "
7969 "field or array sub-references", ass
->get_description().c_str());
7972 ref
->error("Reference to a timer or timer parameter was expected for "
7973 "a timer parameter instead of %s", ass
->get_description().c_str());
7975 return new ActualPar(ref
);
7977 actual_par
->error("Reference to a timer or timer parameter was "
7978 "expected for a timer parameter");
7979 return new ActualPar();
7983 ActualPar
*FormalPar::chk_actual_par_port(TemplateInstance
*actual_par
,
7984 Type::expected_value_t exp_val
)
7986 Type
*ap_type
= actual_par
->get_Type();
7988 ap_type
->warning("Explicit type specification is useless for a port "
7990 actual_par
->chk_Type(type
);
7992 Ref_base
*derived_ref
= actual_par
->get_DerivedRef();
7994 derived_ref
->error("An in-line modified template cannot be used as "
7996 actual_par
->chk_DerivedRef(type
);
7998 Template
*ap_template
= actual_par
->get_Template();
7999 if (ap_template
->is_Ref()) {
8000 Ref_base
*ref
= ap_template
->get_Ref();
8001 Common::Assignment
*ass
= ref
->get_refd_assignment();
8004 return new ActualPar();
8006 bool asstype_correct
= false;
8007 switch (ass
->get_asstype()) {
8009 ArrayDimensions
*dims
= ass
->get_Dimensions();
8010 if (dims
) dims
->chk_indices(ref
, "port", false, exp_val
);
8011 else if (ref
->get_subrefs()) ref
->error("Reference to single %s "
8012 "cannot have field or array sub-references",
8013 ass
->get_description().c_str());
8014 asstype_correct
= true;
8017 if (ref
->get_subrefs()) ref
->error("Reference to %s cannot have "
8018 "field or array sub-references", ass
->get_description().c_str());
8019 asstype_correct
= true;
8022 ref
->error("Reference to a port or port parameter was expected for a "
8023 "port parameter instead of %s", ass
->get_description().c_str());
8025 if (asstype_correct
) {
8026 Type
*ref_type
= ass
->get_Type();
8027 if (ref_type
&& !type
->is_identical(ref_type
))
8028 ref
->error("Type mismatch: Reference to a port or port parameter "
8029 "of type `%s' was expected instead of `%s'",
8030 type
->get_typename().c_str(), ref_type
->get_typename().c_str());
8032 return new ActualPar(ref
);
8034 actual_par
->error("Reference to a port or port parameter was expected "
8035 "for a port parameter");
8036 return new ActualPar();
8040 void FormalPar::use_as_lvalue(const Location
& p_loc
)
8044 case A_PAR_TEMPL_IN
:
8047 FATAL_ERROR("FormalPar::use_as_lvalue()");
8049 if (!used_as_lvalue
) {
8050 Definition
*my_def
= my_parlist
->get_my_def();
8051 if (!my_def
) FATAL_ERROR("FormalPar::use_as_lvalue()");
8052 if (my_def
->get_asstype() == A_TEMPLATE
)
8053 p_loc
.error("Parameter `%s' of the template cannot be passed further "
8054 "as `out' or `inout' parameter", id
->get_dispname().c_str());
8056 // update the genname so that all references in the generated code
8057 // will point to the shadow object
8059 set_genname(id
->get_name() + "_shadow");
8061 used_as_lvalue
= true;
8066 void FormalPar::generate_code_defval(output_struct
*target
, bool)
8068 if (!defval
.ap
) return;
8069 switch (defval
.ap
->get_selection()) {
8070 case ActualPar::AP_VALUE
: {
8071 Value
*val
= defval
.ap
->get_Value();
8073 Code::init_cdef(&cdef
);
8074 type
->generate_code_object(&cdef
, val
);
8075 Code::merge_cdef(target
, &cdef
);
8076 Code::free_cdef(&cdef
);
8077 if (use_runtime_2
&& TypeConv::needs_conv_refd(val
)) {
8078 target
->functions
.post_init
= TypeConv::gen_conv_code_refd(target
->
8079 functions
.post_init
, val
->get_lhs_name().c_str(), val
);
8081 target
->functions
.post_init
= val
->generate_code_init(
8082 target
->functions
.post_init
, val
->get_lhs_name().c_str());
8085 case ActualPar::AP_TEMPLATE
: {
8086 TemplateInstance
*ti
= defval
.ap
->get_TemplateInstance();
8087 Template
*temp
= ti
->get_Template();
8089 Code::init_cdef(&cdef
);
8090 type
->generate_code_object(&cdef
, temp
);
8091 Code::merge_cdef(target
, &cdef
);
8092 Code::free_cdef(&cdef
);
8093 Ref_base
*dref
= ti
->get_DerivedRef();
8095 expression_struct expr
;
8096 Code::init_expr(&expr
);
8097 expr
.expr
= mputprintf(expr
.expr
, "%s = ",
8098 temp
->get_lhs_name().c_str());
8099 dref
->generate_code(&expr
);
8100 target
->functions
.post_init
=
8101 Code::merge_free_expr(target
->functions
.post_init
, &expr
, false);
8103 if (use_runtime_2
&& TypeConv::needs_conv_refd(temp
)) {
8104 target
->functions
.post_init
= TypeConv::gen_conv_code_refd(target
->
8105 functions
.post_init
, temp
->get_lhs_name().c_str(), temp
);
8107 target
->functions
.post_init
=
8108 temp
->generate_code_init(target
->functions
.post_init
,
8109 temp
->get_lhs_name().c_str());
8111 if (defval
.ap
->get_gen_restriction_check() != TR_NONE
) {
8112 target
->functions
.post_init
=
8113 Template::generate_restriction_check_code(
8114 target
->functions
.post_init
, temp
->get_lhs_name().c_str(),
8115 defval
.ap
->get_gen_restriction_check());
8118 case ActualPar::AP_REF
:
8121 FATAL_ERROR("FormalPar::generate_code()");
8125 char *FormalPar::generate_code_fpar(char *str
)
8127 const char *name_str
= id
->get_name().c_str();
8131 str
= mputprintf(str
, "Lazy_Param<%s>& %s", type
->get_genname_value(my_scope
).c_str(), name_str
);
8133 str
= mputprintf(str
, "const %s& %s", type
->get_genname_value(my_scope
).c_str(), name_str
);
8137 case A_PAR_VAL_INOUT
:
8139 str
= mputprintf(str
, "%s& %s", type
->get_genname_value(my_scope
).c_str(),
8142 case A_PAR_TEMPL_IN
:
8144 str
= mputprintf(str
, "Lazy_Param<%s>& %s", type
->get_genname_template(my_scope
).c_str(), name_str
);
8146 str
= mputprintf(str
, "const %s& %s", type
->get_genname_template(my_scope
).c_str(), name_str
);
8149 case A_PAR_TEMPL_OUT
:
8150 case A_PAR_TEMPL_INOUT
:
8151 str
= mputprintf(str
, "%s& %s",
8152 type
->get_genname_template(my_scope
).c_str(), name_str
);
8155 str
= mputprintf(str
, "TIMER& %s", name_str
);
8158 FATAL_ERROR("FormalPar::generate_code()");
8163 string
FormalPar::get_reference_name(Scope
* scope
) const
8169 case A_PAR_TEMPL_IN
:
8170 ret_val
+= type
->get_genname_template(scope
);
8173 ret_val
+= type
->get_genname_value(scope
);
8178 ret_val
+= get_id().get_name();
8185 char *FormalPar::generate_code_object(char *str
, const char *p_prefix
, char refch
)
8187 const char *name_str
= id
->get_name().c_str();
8191 str
= mputprintf(str
, "Lazy_Param<%s> %s%s;\n", type
->get_genname_value(my_scope
).c_str(), p_prefix
, name_str
);
8193 str
= mputprintf(str
, "%s %s%s;\n", type
->get_genname_value(my_scope
).c_str(), p_prefix
, name_str
);
8197 case A_PAR_VAL_INOUT
:
8199 str
= mputprintf(str
, "%s%c %s%s;\n",
8200 type
->get_genname_value(my_scope
).c_str(), refch
, p_prefix
, name_str
);
8202 case A_PAR_TEMPL_IN
:
8204 str
= mputprintf(str
, "Lazy_Param<%s> %s%s;\n", type
->get_genname_template(my_scope
).c_str(), p_prefix
, name_str
);
8206 str
= mputprintf(str
, "%s %s%s;\n", type
->get_genname_template(my_scope
).c_str(), p_prefix
, name_str
);
8209 case A_PAR_TEMPL_OUT
:
8210 case A_PAR_TEMPL_INOUT
:
8211 str
= mputprintf(str
, "%s%c %s%s;\n",
8212 type
->get_genname_template(my_scope
).c_str(), refch
, p_prefix
, name_str
);
8215 str
= mputprintf(str
, "TIMER& %s%s;\n", p_prefix
, name_str
);
8218 FATAL_ERROR("FormalPar::generate_code_object()");
8223 char *FormalPar::generate_shadow_object(char *str
) const
8225 if (used_as_lvalue
&& !lazy_eval
) {
8226 const string
& t_genname
= get_genname();
8227 const char *genname_str
= t_genname
.c_str();
8228 const char *name_str
= id
->get_name().c_str();
8231 str
= mputprintf(str
, "%s %s(%s);\n",
8232 type
->get_genname_value(my_scope
).c_str(), genname_str
, name_str
);
8234 case A_PAR_TEMPL_IN
:
8235 str
= mputprintf(str
, "%s %s(%s);\n",
8236 type
->get_genname_template(my_scope
).c_str(), genname_str
, name_str
);
8239 FATAL_ERROR("FormalPar::generate_shadow_object()");
8245 char *FormalPar::generate_code_set_unbound(char *str
) const
8248 case A_PAR_TEMPL_OUT
:
8250 str
= mputprintf(str
, "%s.clean_up();\n", id
->get_name().c_str());
8258 void FormalPar::dump_internal(unsigned level
) const
8260 DEBUG(level
, "%s: %s", get_assname(), id
->get_dispname().c_str());
8261 if (type
) type
->dump(level
+ 1);
8264 DEBUG(level
+ 1, "default value:");
8265 defval
.ap
->dump(level
+ 2);
8269 DEBUG(level
+ 1, "default value:");
8270 defval
.ti
->dump(level
+ 2);
8275 // =================================
8276 // ===== FormalParList
8277 // =================================
8279 FormalParList::~FormalParList()
8281 size_t nof_pars
= pars_v
.size();
8282 for (size_t i
= 0; i
< nof_pars
; i
++) delete pars_v
[i
];
8287 FormalParList
*FormalParList::clone() const
8289 FATAL_ERROR("FormalParList::clone");
8292 void FormalParList::set_fullname(const string
& p_fullname
)
8294 Node::set_fullname(p_fullname
);
8295 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8296 FormalPar
*par
= pars_v
[i
];
8297 par
->set_fullname(p_fullname
+ "." + par
->get_id().get_dispname());
8301 void FormalParList::set_my_scope(Scope
*p_scope
)
8303 set_parent_scope(p_scope
);
8304 Node::set_my_scope(p_scope
);
8305 // the scope of parameters is set to the parent scope instead of this
8306 // because they cannot refer to each other
8307 for (size_t i
= 0; i
< pars_v
.size(); i
++) pars_v
[i
]->set_my_scope(p_scope
);
8310 void FormalParList::add_fp(FormalPar
*p_fp
)
8312 if (!p_fp
) FATAL_ERROR("NULL parameter: Ttcn::FormalParList::add_fp()");
8314 p_fp
->set_my_parlist(this);
8318 bool FormalParList::has_notused_defval() const
8320 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8321 if (pars_v
[i
]->has_notused_defval())
8327 bool FormalParList::has_only_default_values() const
8329 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8330 if (!pars_v
[i
]->has_defval()) {
8338 bool FormalParList::has_fp_withName(const Identifier
& p_name
)
8340 if (!checked
) chk(Definition::A_UNDEF
);
8341 return pars_m
.has_key(p_name
.get_name());
8344 FormalPar
*FormalParList::get_fp_byName(const Identifier
& p_name
)
8346 if (!checked
) chk(Definition::A_UNDEF
);
8347 return pars_m
[p_name
.get_name()];
8350 bool FormalParList::get_startability()
8352 if(!checked
) FATAL_ERROR("FormalParList::get_startability()");
8353 return is_startable
;
8356 Common::Assignment
*FormalParList::get_ass_bySRef(Common::Ref_simple
*p_ref
)
8358 if (!p_ref
|| !checked
) FATAL_ERROR("FormalParList::get_ass_bySRef()");
8359 if (p_ref
->get_modid()) return parent_scope
->get_ass_bySRef(p_ref
);
8361 const string
& name
= p_ref
->get_id()->get_name();
8362 if (pars_m
.has_key(name
)) return pars_m
[name
];
8363 else return parent_scope
->get_ass_bySRef(p_ref
);
8367 bool FormalParList::has_ass_withId(const Identifier
& p_id
)
8369 if (!checked
) FATAL_ERROR("Ttcn::FormalParList::has_ass_withId()");
8370 return pars_m
.has_key(p_id
.get_name())
8371 || parent_scope
->has_ass_withId(p_id
);
8374 void FormalParList::set_genname(const string
& p_prefix
)
8376 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8377 FormalPar
*par
= pars_v
[i
];
8378 const string
& par_name
= par
->get_id().get_name();
8379 if (par
->get_asstype() != Definition::A_PAR_TIMER
)
8380 par
->get_Type()->set_genname(p_prefix
, par_name
);
8381 if (par
->has_defval()) {
8382 string
embedded_genname(p_prefix
);
8383 embedded_genname
+= '_';
8384 embedded_genname
+= par_name
;
8385 embedded_genname
+= "_defval";
8386 ActualPar
*defval
= par
->get_defval();
8387 switch (defval
->get_selection()) {
8388 case ActualPar::AP_ERROR
:
8389 case ActualPar::AP_REF
:
8391 case ActualPar::AP_VALUE
: {
8392 Value
*v
= defval
->get_Value();
8393 v
->set_genname_prefix("const_");
8394 v
->set_genname_recursive(embedded_genname
);
8396 case ActualPar::AP_TEMPLATE
: {
8397 Template
*t
= defval
->get_TemplateInstance()->get_Template();
8398 t
->set_genname_prefix("template_");
8399 t
->set_genname_recursive(embedded_genname
);
8402 FATAL_ERROR("FormalParList::set_genname()");
8408 void FormalParList::chk(Definition::asstype_t deftype
)
8410 if (checked
) return;
8413 is_startable
= true;
8414 Error_Context
cntxt(this, "In formal parameter list");
8415 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8416 FormalPar
*par
= pars_v
[i
];
8417 const Identifier
& id
= par
->get_id();
8418 const string
& name
= id
.get_name();
8419 const char *dispname
= id
.get_dispname().c_str();
8420 if (pars_m
.has_key(name
)) {
8421 par
->error("Duplicate parameter with name `%s'", dispname
);
8422 pars_m
[name
]->note("Previous definition of `%s' is here", dispname
);
8424 pars_m
.add(name
, par
);
8425 if (parent_scope
&& parent_scope
->has_ass_withId(id
)) {
8426 par
->error("Parameter name `%s' is not unique in the scope "
8427 "hierarchy", dispname
);
8428 Reference
ref(0, id
.clone());
8429 Common::Assignment
*ass
= parent_scope
->get_ass_bySRef(&ref
);
8430 if (!ass
) FATAL_ERROR("FormalParList::chk()");
8431 ass
->note("Symbol `%s' is already defined here in a higher scope "
8435 Error_Context
cntxt2(par
, "In parameter `%s'", dispname
);
8437 // check whether the parameter type is allowed
8439 case Definition::A_TEMPLATE
:
8440 switch (par
->get_asstype()) {
8441 case Definition::A_PAR_VAL_IN
:
8442 case Definition::A_PAR_TEMPL_IN
:
8443 // these are allowed
8446 par
->error("A template cannot have %s", par
->get_assname());
8449 case Definition::A_TESTCASE
:
8450 switch (par
->get_asstype()) {
8451 case Definition::A_PAR_TIMER
:
8452 case Definition::A_PAR_PORT
:
8453 // these are forbidden
8454 par
->error("A testcase cannot have %s", par
->get_assname());
8459 // everything is allowed for functions and altsteps
8463 switch(par
->get_asstype()) {
8464 case Common::Assignment::A_PAR_VAL_IN
:
8465 case Common::Assignment::A_PAR_TEMPL_IN
:
8466 case Common::Assignment::A_PAR_VAL_INOUT
:
8467 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8468 if (is_startable
&& par
->get_Type()->is_component_internal())
8469 is_startable
= false;
8472 is_startable
= false;
8475 if (!par
->has_defval()) min_nof_pars
= i
+ 1;
8476 // the last parameter without a default value determines the minimum
8480 // check that @lazy paramterization not used in cases currently unsupported
8481 void FormalParList::chk_noLazyParams() {
8482 Error_Context
cntxt(this, "In formal parameter list");
8483 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8484 FormalPar
*par
= pars_v
[i
];
8485 if (par
->get_lazy_eval()) {
8486 par
->error("Formal parameter `%s' cannot be @lazy, not supported in this case.",
8487 par
->get_id().get_dispname().c_str());
8492 void FormalParList::chk_startability(const char *p_what
, const char *p_name
)
8494 if(!checked
) FATAL_ERROR("FormalParList::chk_startability()");
8495 if (is_startable
) return;
8496 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8497 FormalPar
*par
= pars_v
[i
];
8498 switch (par
->get_asstype()) {
8499 case Common::Assignment::A_PAR_VAL_IN
:
8500 case Common::Assignment::A_PAR_TEMPL_IN
:
8501 case Common::Assignment::A_PAR_VAL_INOUT
:
8502 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8503 if (par
->get_Type()->is_component_internal()) {
8504 map
<Type
*,void> type_chain
;
8505 char* err_str
= mprintf("a parameter or embedded in a parameter of "
8506 "a function used in a start operation. "
8507 "%s `%s' cannot be started on a parallel test component "
8508 "because of `%s'", p_what
, p_name
, par
->get_description().c_str());
8509 par
->get_Type()->chk_component_internal(type_chain
, err_str
);
8514 par
->error("%s `%s' cannot be started on a parallel test component "
8515 "because it has %s", p_what
, p_name
, par
->get_description().c_str());
8520 void FormalParList::chk_compatibility(FormalParList
* p_fp_list
,
8523 size_t nof_type_pars
= pars_v
.size();
8524 size_t nof_function_pars
= p_fp_list
->pars_v
.size();
8525 // check for the number of parameters
8526 if (nof_type_pars
!= nof_function_pars
) {
8527 p_fp_list
->error("Too %s parameters: %lu was expected instead of %lu",
8528 nof_type_pars
< nof_function_pars
? "many" : "few",
8529 (unsigned long) nof_type_pars
, (unsigned long) nof_function_pars
);
8531 size_t upper_limit
=
8532 nof_type_pars
< nof_function_pars
? nof_type_pars
: nof_function_pars
;
8533 for (size_t i
= 0; i
< upper_limit
; i
++) {
8534 FormalPar
*type_par
= pars_v
[i
];
8535 FormalPar
*function_par
= p_fp_list
->pars_v
[i
];
8536 Error_Context
cntxt(function_par
, "In parameter #%lu",
8537 (unsigned long) (i
+ 1));
8538 FormalPar::asstype_t type_par_asstype
= type_par
->get_asstype();
8539 FormalPar::asstype_t function_par_asstype
= function_par
->get_asstype();
8540 // check for parameter kind equivalence
8541 // (in, out or inout / value or template)
8542 if (type_par_asstype
!= function_par_asstype
) {
8543 function_par
->error("The kind of the parameter is not the same as in "
8544 "type `%s': %s was expected instead of %s", where
,
8545 type_par
->get_assname(), function_par
->get_assname());
8547 // check for type equivalence
8548 if (type_par_asstype
!= FormalPar::A_PAR_TIMER
&&
8549 function_par_asstype
!= FormalPar::A_PAR_TIMER
) {
8550 Type
*type_par_type
= type_par
->get_Type();
8551 Type
*function_par_type
= function_par
->get_Type();
8552 if (!type_par_type
->is_identical(function_par_type
)) {
8553 function_par_type
->error("The type of the parameter is not the same "
8554 "as in type `%s': `%s' was expected instead of `%s'", where
,
8555 type_par_type
->get_typename().c_str(),
8556 function_par_type
->get_typename().c_str());
8557 } else if (type_par_type
->get_sub_type() && function_par_type
->get_sub_type() &&
8558 (type_par_type
->get_sub_type()->get_subtypetype()==function_par_type
->get_sub_type()->get_subtypetype()) &&
8559 (!type_par_type
->get_sub_type()->is_compatible(function_par_type
->get_sub_type()))) {
8560 // TODO: maybe equivalence should be checked, or maybe that is too strict
8561 function_par_type
->error(
8562 "Subtype mismatch: subtype %s has no common value with subtype %s",
8563 type_par_type
->get_sub_type()->to_string().c_str(),
8564 function_par_type
->get_sub_type()->to_string().c_str());
8567 // check for template restriction equivalence
8568 if (type_par
->get_template_restriction()!=
8569 function_par
->get_template_restriction()) {
8570 function_par
->error("The template restriction of the parameter is "
8571 "not the same as in type `%s': %s restriction was expected instead "
8572 "of %s restriction", where
,
8573 type_par
->get_template_restriction()==TR_NONE
? "no" :
8574 Template::get_restriction_name(type_par
->get_template_restriction()),
8575 function_par
->get_template_restriction()==TR_NONE
? "no" :
8576 Template::get_restriction_name(function_par
->
8577 get_template_restriction()));
8579 // check for @lazy equivalence
8580 if (type_par
->get_lazy_eval()!=function_par
->get_lazy_eval()) {
8581 function_par
->error("Parameter @lazy-ness mismatch");
8583 // check for name equivalence
8584 const Identifier
& type_par_id
= type_par
->get_id();
8585 const Identifier
& function_par_id
= function_par
->get_id();
8586 if (type_par_id
!= function_par_id
) {
8587 function_par
->warning("The name of the parameter is not the same "
8588 "as in type `%s': `%s' was expected instead of `%s'", where
,
8589 type_par_id
.get_dispname().c_str(),
8590 function_par_id
.get_dispname().c_str());
8595 bool FormalParList::fold_named_and_chk(ParsedActualParameters
*p_paps
,
8596 ActualParList
*p_aplist
)
8598 const size_t num_named
= p_paps
->get_nof_nps();
8599 const size_t num_unnamed
= p_paps
->get_nof_tis();
8600 size_t num_actual
= num_unnamed
;
8602 // Construct a map to tell us what index a FormalPar has
8603 typedef map
<FormalPar
*, size_t> formalpar_map_t
;
8604 formalpar_map_t formalpar_map
;
8606 size_t num_fp
= get_nof_fps();
8607 for (size_t fpx
= 0; fpx
< num_fp
; ++fpx
) {
8608 FormalPar
*fp
= get_fp_byIndex(fpx
);
8609 formalpar_map
.add(fp
, new size_t(fpx
));
8612 // Go through the named parameters
8613 for (size_t i
= 0; i
< num_named
; ++i
) {
8614 NamedParam
*np
= p_paps
->extract_np_byIndex(i
);
8615 // We are now responsible for np.
8617 if (has_fp_withName(*np
->get_name())) {
8618 // there is a formal parameter with that name
8619 FormalPar
*fp
= get_fp_byName(*np
->get_name());
8620 const size_t is_at
= *formalpar_map
[fp
]; // the index of the formal par
8621 if (is_at
>= num_actual
) {
8622 // There is no actual par in the unnamed part.
8623 // Create one from the named param.
8625 // First, pad the gap with '-'
8626 for (; num_actual
< is_at
; ++num_actual
) {
8628 if (pars_v
[num_actual
]->has_defval()) {
8629 not_used
= new Template(Template::TEMPLATE_NOTUSED
);
8631 else { // cannot use '-' if no default value
8632 not_used
= new Template(Template::TEMPLATE_ERROR
);
8634 TemplateInstance
*new_ti
= new TemplateInstance(0, 0, not_used
);
8635 // Conjure a location info at the beginning of the unnamed part
8636 // (that is, the beginning of the actual parameter list)
8637 new_ti
->set_location(p_paps
->get_tis()->get_filename(),
8638 p_paps
->get_tis()->get_first_line(),
8639 p_paps
->get_tis()->get_first_column(), 0, 0);
8640 p_paps
->get_tis()->add_ti(new_ti
);
8642 TemplateInstance
* namedti
= np
->extract_ti();
8643 p_paps
->get_tis()->add_ti(namedti
);
8646 // There is already an actual par at that position, fetch it
8647 TemplateInstance
* ti
= p_paps
->get_tis()->get_ti_byIndex(is_at
);
8648 Template::templatetype_t tt
= ti
->get_Template()->get_templatetype();
8650 if (is_at
>= num_unnamed
&& !ti
->get_Type() && !ti
->get_DerivedRef()
8651 && (tt
== Template::TEMPLATE_NOTUSED
|| tt
== Template::TEMPLATE_ERROR
)) {
8652 // NotUsed in the named part => padding
8653 np
->error("Named parameter `%s' out of order",
8654 np
->get_name()->get_dispname().c_str());
8656 // attempt to override an original unnamed param with a named one
8657 np
->error("Formal parameter `%s' assigned more than once",
8658 np
->get_name()->get_dispname().c_str());
8662 else { // no formal parameter with that name
8664 switch (my_def
->get_asstype()) {
8665 case Common::Assignment::A_TYPE
: {
8666 Type
*t
= my_def
->get_Type();
8668 switch (t
? t
->get_typetype() : 0) {
8669 case Type::T_FUNCTION
:
8670 nam
= mcopystr("Function reference");
8672 case Type::T_ALTSTEP
:
8673 nam
= mcopystr("Altstep reference");
8675 case Type::T_TESTCASE
:
8676 nam
= mcopystr("Testcase reference");
8679 FATAL_ERROR("FormalParList::chk_actual_parlist() "
8680 "Unexpected type %s", t
->get_typename().c_str());
8681 } // switch(typetype)
8684 nam
= mcopystr(my_def
->get_assname());
8686 } // switch(asstype)
8688 *nam
&= ~('a'-'A'); // Make the first letter uppercase
8689 p_paps
->get_tis()->error("%s `%s' has no formal parameter `%s'",
8691 my_def
->get_fullname().c_str(),
8692 np
->get_name()->get_dispname().c_str());
8699 for (size_t fpx
= 0; fpx
< num_fp
; ++fpx
) {
8700 delete formalpar_map
.get_nth_elem(fpx
);
8702 formalpar_map
.clear();
8704 return chk_actual_parlist(p_paps
->get_tis(), p_aplist
);
8707 bool FormalParList::chk_actual_parlist(TemplateInstances
*p_tis
,
8708 ActualParList
*p_aplist
)
8710 size_t formal_pars
= pars_v
.size();
8711 size_t actual_pars
= p_tis
->get_nof_tis();
8712 // p_aplist->get_nof_pars() is usually 0 on entry
8713 bool error_flag
= false;
8715 if (min_nof_pars
== formal_pars
) {
8716 // none of the parameters have default value
8717 if (actual_pars
!= formal_pars
) {
8718 p_tis
->error("Too %s parameters: %lu was expected "
8719 "instead of %lu", actual_pars
< formal_pars
? "few" : "many",
8720 (unsigned long) formal_pars
, (unsigned long) actual_pars
);
8724 // some parameters have default value
8725 if (actual_pars
< min_nof_pars
) {
8726 p_tis
->error("Too few parameters: at least %lu "
8727 "was expected instead of %lu",
8728 (unsigned long) min_nof_pars
, (unsigned long) actual_pars
);
8730 } else if (actual_pars
> formal_pars
) {
8731 p_tis
->error("Too many parameters: at most %lu "
8732 "was expected instead of %lu",
8733 (unsigned long) formal_pars
, (unsigned long) actual_pars
);
8738 // Do not check actual parameters in excess of the formal ones
8739 size_t upper_limit
= actual_pars
< formal_pars
? actual_pars
: formal_pars
;
8740 for (size_t i
= 0; i
< upper_limit
; i
++) {
8741 TemplateInstance
*ti
= p_tis
->get_ti_byIndex(i
);
8743 // the formal parameter for the current actual parameter
8744 FormalPar
*fp
= pars_v
[i
];
8745 Error_Context
cntxt(ti
, "In parameter #%lu for `%s'",
8746 (unsigned long) (i
+ 1), fp
->get_id().get_dispname().c_str());
8747 if (!ti
->get_Type() && !ti
->get_DerivedRef() && ti
->get_Template()
8748 ->get_templatetype() == Template::TEMPLATE_NOTUSED
) {
8749 if (fp
->has_defval()) {
8750 ActualPar
*defval
= fp
->get_defval();
8751 p_aplist
->add(new ActualPar(defval
));
8752 if (defval
->is_erroneous()) error_flag
= true;
8754 ti
->error("Not used symbol (`-') cannot be used for parameter "
8755 "that does not have default value");
8756 p_aplist
->add(new ActualPar());
8759 } else if (!ti
->get_Type() && !ti
->get_DerivedRef() && ti
->get_Template()
8760 ->get_templatetype() == Template::TEMPLATE_ERROR
) {
8761 ti
->error("Parameter not specified");
8763 ActualPar
*ap
= fp
->chk_actual_par(ti
, Type::EXPECTED_DYNAMIC_VALUE
);
8765 if (ap
->is_erroneous()) error_flag
= true;
8769 // The rest of formal parameters have no corresponding actual parameters.
8770 // Create actual parameters for them based on their default values
8771 // (which must exist).
8772 for (size_t i
= upper_limit
; i
< formal_pars
; i
++) {
8773 FormalPar
*fp
= pars_v
[i
];
8774 if (fp
->has_defval()) {
8775 ActualPar
*defval
= fp
->get_defval();
8776 p_aplist
->add(new ActualPar(defval
));
8777 if (defval
->is_erroneous()) error_flag
= true;
8779 p_aplist
->add(new ActualPar()); // erroneous
8786 bool FormalParList::chk_activate_argument(ActualParList
*p_aplist
,
8787 const char* p_description
)
8789 bool ret_val
= true;
8790 for(size_t i
= 0; i
< p_aplist
->get_nof_pars(); i
++) {
8791 ActualPar
*t_ap
= p_aplist
->get_par(i
);
8792 if(t_ap
->get_selection() != ActualPar::AP_REF
) continue;
8793 FormalPar
*t_fp
= pars_v
[i
];
8794 switch(t_fp
->get_asstype()) {
8795 case Common::Assignment::A_PAR_VAL_OUT
:
8796 case Common::Assignment::A_PAR_VAL_INOUT
:
8797 case Common::Assignment::A_PAR_TEMPL_OUT
:
8798 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8799 case Common::Assignment::A_PAR_TIMER
:
8800 //the checking shall be performed for these parameter types
8802 case Common::Assignment::A_PAR_PORT
:
8803 // port parameters are always correct because ports can be defined
8804 // only in component types
8807 FATAL_ERROR("FormalParList::chk_activate_argument()");
8809 Ref_base
*t_ref
= t_ap
->get_Ref();
8810 Common::Assignment
*t_par_ass
= t_ref
->get_refd_assignment();
8811 if(!t_par_ass
) FATAL_ERROR("FormalParList::chk_activate_argument()");
8812 switch (t_par_ass
->get_asstype()) {
8813 case Common::Assignment::A_VAR
:
8814 case Common::Assignment::A_VAR_TEMPLATE
:
8815 case Common::Assignment::A_TIMER
:
8816 // it is not allowed to pass references of local variables or timers
8817 if (t_par_ass
->is_local()) {
8818 t_ref
->error("Parameter #%lu of %s refers to %s, which is a local "
8819 "definition within a statement block and may have shorter "
8820 "lifespan than the activated default. Only references to "
8821 "variables and timers defined in the component type can be passed "
8822 "to activated defaults", (unsigned long) (i
+ 1), p_description
,
8823 t_par_ass
->get_description().c_str());
8827 case Common::Assignment::A_PAR_VAL_IN
:
8828 case Common::Assignment::A_PAR_VAL_OUT
:
8829 case Common::Assignment::A_PAR_VAL_INOUT
:
8830 case Common::Assignment::A_PAR_TEMPL_IN
:
8831 case Common::Assignment::A_PAR_TEMPL_OUT
:
8832 case Common::Assignment::A_PAR_TEMPL_INOUT
:
8833 case Common::Assignment::A_PAR_TIMER
: {
8834 // it is not allowed to pass references pointing to formal parameters
8835 // except for activate() statements within testcases
8836 // note: all defaults are deactivated at the end of the testcase
8837 FormalPar
*t_refd_fp
= dynamic_cast<FormalPar
*>(t_par_ass
);
8838 if (!t_refd_fp
) FATAL_ERROR("FormalParList::chk_activate_argument()");
8839 FormalParList
*t_fpl
= t_refd_fp
->get_my_parlist();
8840 if (!t_fpl
|| !t_fpl
->my_def
)
8841 FATAL_ERROR("FormalParList::chk_activate_argument()");
8842 if (t_fpl
->my_def
->get_asstype() != Common::Assignment::A_TESTCASE
) {
8843 t_ref
->error("Parameter #%lu of %s refers to %s, which may have "
8844 "shorter lifespan than the activated default. Only references to "
8845 "variables and timers defined in the component type can be passed "
8846 "to activated defaults", (unsigned long) (i
+ 1), p_description
,
8847 t_par_ass
->get_description().c_str());
8857 char *FormalParList::generate_code(char *str
)
8859 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8860 if (i
> 0) str
= mputstr(str
, ", ");
8861 str
= pars_v
[i
]->generate_code_fpar(str
);
8866 void FormalParList::generate_code_defval(output_struct
*target
)
8868 for (size_t i
= 0; i
< pars_v
.size(); i
++)
8869 pars_v
[i
]->generate_code_defval(target
);
8872 char *FormalParList::generate_code_actual_parlist(char *str
,
8873 const char *p_prefix
)
8875 for (size_t i
= 0; i
< pars_v
.size(); i
++) {
8876 if (i
> 0) str
= mputstr(str
, ", ");
8877 str
= mputstr(str
, p_prefix
);
8878 str
= mputstr(str
, pars_v
[i
]->get_id().get_name().c_str());
8883 char *FormalParList::generate_code_object(char *str
, const char *p_prefix
, char refch
)
8885 for (size_t i
= 0; i
< pars_v
.size(); i
++)
8886 str
= pars_v
[i
]->generate_code_object(str
, p_prefix
, refch
);
8890 char *FormalParList::generate_shadow_objects(char *str
) const
8892 for (size_t i
= 0; i
< pars_v
.size(); i
++)
8893 str
= pars_v
[i
]->generate_shadow_object(str
);
8897 char *FormalParList::generate_code_set_unbound(char *str
) const
8899 if (enable_set_bound_out_param
) return str
;
8900 for (size_t i
= 0; i
< pars_v
.size(); i
++)
8901 str
= pars_v
[i
]->generate_code_set_unbound(str
);
8906 void FormalParList::dump(unsigned level
) const
8908 size_t nof_pars
= pars_v
.size();
8909 DEBUG(level
, "formal parameters: %lu pcs.", (unsigned long) nof_pars
);
8910 for(size_t i
= 0; i
< nof_pars
; i
++) pars_v
[i
]->dump(level
+ 1);
8913 // =================================
8915 // =================================
8917 ActualPar::ActualPar(Value
*v
)
8918 : Node(), selection(AP_VALUE
), my_scope(0), gen_restriction_check(TR_NONE
),
8919 gen_post_restriction_check(TR_NONE
)
8921 if (!v
) FATAL_ERROR("ActualPar::ActualPar()");
8925 ActualPar::ActualPar(TemplateInstance
*t
)
8926 : Node(), selection(AP_TEMPLATE
), my_scope(0),
8927 gen_restriction_check(TR_NONE
), gen_post_restriction_check(TR_NONE
)
8929 if (!t
) FATAL_ERROR("ActualPar::ActualPar()");
8933 ActualPar::ActualPar(Ref_base
*r
)
8934 : Node(), selection(AP_REF
), my_scope(0), gen_restriction_check(TR_NONE
),
8935 gen_post_restriction_check(TR_NONE
)
8937 if (!r
) FATAL_ERROR("ActualPar::ActualPar()");
8941 ActualPar::ActualPar(ActualPar
*a
)
8942 : Node(), selection(AP_DEFAULT
), my_scope(0),
8943 gen_restriction_check(TR_NONE
), gen_post_restriction_check(TR_NONE
)
8945 if (!a
) FATAL_ERROR("ActualPar::ActualPar()");
8949 ActualPar::~ActualPar()
8964 break; // nothing to do with act
8966 FATAL_ERROR("ActualPar::~ActualPar()");
8970 ActualPar
*ActualPar::clone() const
8972 FATAL_ERROR("ActualPar::clone");
8975 void ActualPar::set_fullname(const string
& p_fullname
)
8977 Node::set_fullname(p_fullname
);
8982 val
->set_fullname(p_fullname
);
8985 temp
->set_fullname(p_fullname
);
8988 ref
->set_fullname(p_fullname
);
8993 FATAL_ERROR("ActualPar::set_fullname()");
8997 void ActualPar::set_my_scope(Scope
*p_scope
)
9004 val
->set_my_scope(p_scope
);
9007 temp
->set_my_scope(p_scope
);
9010 ref
->set_my_scope(p_scope
);
9013 switch (act
->selection
) {
9015 ref
->set_my_scope(p_scope
);
9022 FATAL_ERROR("ActualPar::set_my_scope()");
9026 FATAL_ERROR("ActualPar::set_my_scope()");
9030 Value
*ActualPar::get_Value() const
9032 if (selection
!= AP_VALUE
) FATAL_ERROR("ActualPar::get_Value()");
9036 TemplateInstance
*ActualPar::get_TemplateInstance() const
9038 if (selection
!= AP_TEMPLATE
)
9039 FATAL_ERROR("ActualPar::get_TemplateInstance()");
9043 Ref_base
*ActualPar::get_Ref() const
9045 if (selection
!= AP_REF
) FATAL_ERROR("ActualPar::get_Ref()");
9049 ActualPar
*ActualPar::get_ActualPar() const
9051 if (selection
!= AP_DEFAULT
) FATAL_ERROR("ActualPar::get_ActualPar()");
9055 void ActualPar::chk_recursions(ReferenceChain
& refch
)
9057 switch (selection
) {
9060 val
->chk_recursions(refch
);
9064 Ref_base
*derived_ref
= temp
->get_DerivedRef();
9066 ActualParList
*parlist
= derived_ref
->get_parlist();
9069 parlist
->chk_recursions(refch
);
9074 Ttcn::Def_Template
* defTemp
= temp
->get_Referenced_Base_Template();
9077 refch
.add(defTemp
->get_fullname());
9081 temp
->get_Template()->chk_recursions(refch
);
9089 bool ActualPar::has_single_expr()
9091 switch (selection
) {
9093 return val
->has_single_expr();
9095 if (gen_restriction_check
!=TR_NONE
||
9096 gen_post_restriction_check
!=TR_NONE
) return false;
9097 return temp
->has_single_expr();
9099 if (gen_restriction_check
!=TR_NONE
||
9100 gen_post_restriction_check
!=TR_NONE
) return false;
9101 if (use_runtime_2
&& ref
->get_subrefs() != NULL
) {
9102 FieldOrArrayRefs
* subrefs
= ref
->get_subrefs();
9103 for (size_t i
= 0; i
< subrefs
->get_nof_refs(); ++i
) {
9104 if (FieldOrArrayRef::ARRAY_REF
== subrefs
->get_ref(i
)->get_type()) {
9109 return ref
->has_single_expr();
9113 FATAL_ERROR("ActualPar::has_single_expr()");
9118 void ActualPar::set_code_section(
9119 GovernedSimple::code_section_t p_code_section
)
9121 switch (selection
) {
9123 val
->set_code_section(p_code_section
);
9126 temp
->set_code_section(p_code_section
);
9129 ref
->set_code_section(p_code_section
);
9135 void ActualPar::generate_code(expression_struct
*expr
, bool copy_needed
, bool lazy_param
, bool used_as_lvalue
) const
9137 switch (selection
) {
9139 if (lazy_param
) { // copy_needed doesn't matter in this case
9140 LazyParamData::init(used_as_lvalue
);
9141 LazyParamData::generate_code(expr
, val
, my_scope
);
9142 LazyParamData::clean();
9144 if (copy_needed
) expr
->expr
= mputprintf(expr
->expr
, "%s(",
9145 val
->get_my_governor()->get_genname_value(my_scope
).c_str());
9146 if (use_runtime_2
&& TypeConv::needs_conv_refd(val
)) {
9147 // Generate everything to preamble to be able to tackle the wrapper
9148 // constructor call. TODO: Reduce the number of temporaries created.
9149 const string
& tmp_id
= val
->get_temporary_id();
9150 const char *tmp_id_str
= tmp_id
.c_str();
9151 expr
->preamble
= mputprintf(expr
->preamble
, "%s %s;\n",
9152 val
->get_my_governor()->get_genname_value(my_scope
).c_str(),
9154 expr
->preamble
= TypeConv::gen_conv_code_refd(expr
->preamble
,
9156 expr
->expr
= mputstr(expr
->expr
, tmp_id_str
);
9157 } else val
->generate_code_expr(expr
);
9158 if (copy_needed
) expr
->expr
= mputc(expr
->expr
, ')');
9162 if (lazy_param
) { // copy_needed doesn't matter in this case
9163 LazyParamData::init(used_as_lvalue
);
9164 LazyParamData::generate_code(expr
, temp
, gen_restriction_check
, my_scope
);
9165 LazyParamData::clean();
9168 expr
->expr
= mputprintf(expr
->expr
, "%s(", temp
->get_Template()
9169 ->get_my_governor()->get_genname_template(my_scope
).c_str());
9170 if (use_runtime_2
&& TypeConv::needs_conv_refd(temp
->get_Template())) {
9171 const string
& tmp_id
= temp
->get_Template()->get_temporary_id();
9172 const char *tmp_id_str
= tmp_id
.c_str();
9173 expr
->preamble
= mputprintf(expr
->preamble
, "%s %s;\n",
9174 temp
->get_Template()->get_my_governor()
9175 ->get_genname_template(my_scope
).c_str(), tmp_id_str
);
9176 expr
->preamble
= TypeConv::gen_conv_code_refd(expr
->preamble
,
9177 tmp_id_str
, temp
->get_Template());
9178 // Not incorporated into gen_conv_code() yet.
9179 if (gen_restriction_check
!= TR_NONE
)
9180 expr
->preamble
= Template::generate_restriction_check_code(
9181 expr
->preamble
, tmp_id_str
, gen_restriction_check
);
9182 expr
->expr
= mputstr(expr
->expr
, tmp_id_str
);
9183 } else temp
->generate_code(expr
, gen_restriction_check
);
9184 if (copy_needed
) expr
->expr
= mputc(expr
->expr
, ')');
9188 if (lazy_param
) FATAL_ERROR("ActualPar::generate_code()"); // syntax error should have already happened
9189 if (copy_needed
) FATAL_ERROR("ActualPar::generate_code()");
9190 if (gen_restriction_check
!= TR_NONE
||
9191 gen_post_restriction_check
!= TR_NONE
) {
9192 // generate runtime check for restricted templates
9193 // code for reference + restriction check
9194 Common::Assignment
*ass
= ref
->get_refd_assignment();
9195 const string
& tmp_id
= my_scope
->get_scope_mod_gen()->get_temporary_id();
9196 const char *tmp_id_str
= tmp_id
.c_str();
9197 expression_struct ref_expr
;
9198 Code::init_expr(&ref_expr
);
9199 ref
->generate_code_const_ref(&ref_expr
);
9200 ref_expr
.preamble
= mputprintf(ref_expr
.preamble
, "%s& %s = %s;\n",
9201 ass
->get_Type()->get_genname_template(ref
->get_my_scope()).c_str(),
9202 tmp_id_str
, ref_expr
.expr
);
9203 if (gen_restriction_check
!= TR_NONE
) {
9204 ref_expr
.preamble
= Template::generate_restriction_check_code(
9205 ref_expr
.preamble
, tmp_id_str
, gen_restriction_check
);
9207 if (gen_post_restriction_check
!= TR_NONE
) {
9208 ref_expr
.postamble
= Template::generate_restriction_check_code(
9209 ref_expr
.postamble
, tmp_id_str
, gen_post_restriction_check
);
9211 // copy content of ref_expr to expr
9212 expr
->preamble
= mputstr(expr
->preamble
, ref_expr
.preamble
);
9213 expr
->expr
= mputprintf(expr
->expr
, "%s", tmp_id_str
);
9214 expr
->postamble
= mputstr(expr
->postamble
, ref_expr
.postamble
);
9215 Code::free_expr(&ref_expr
);
9217 ref
->generate_code(expr
);
9221 if (copy_needed
) FATAL_ERROR("ActualPar::generate_code()");
9222 switch (act
->selection
) {
9225 LazyParamData::generate_code_ap_default_ref(expr
, act
->ref
, my_scope
);
9227 act
->ref
->generate_code(expr
);
9232 LazyParamData::generate_code_ap_default_value(expr
, act
->val
, my_scope
);
9234 expr
->expr
= mputstr(expr
->expr
, act
->val
->get_genname_own(my_scope
).c_str());
9239 LazyParamData::generate_code_ap_default_ti(expr
, act
->temp
, my_scope
);
9241 expr
->expr
= mputstr(expr
->expr
, act
->temp
->get_Template()->get_genname_own(my_scope
).c_str());
9245 FATAL_ERROR("ActualPar::generate_code()");
9249 FATAL_ERROR("ActualPar::generate_code()");
9253 char *ActualPar::rearrange_init_code(char *str
, bool is_local
)
9255 switch (selection
) {
9257 str
= val
->rearrange_init_code(str
);
9260 str
= temp
->rearrange_init_code(str
);
9264 if (is_local
) str
= act
->rearrange_init_code_defval(str
);
9267 FATAL_ERROR("ActualPar::rearrange_init_code()");
9272 char *ActualPar::rearrange_init_code_defval(char *str
)
9274 switch (selection
) {
9276 str
= val
->generate_code_init(str
, val
->get_lhs_name().c_str());
9279 str
= temp
->rearrange_init_code(str
);
9280 Ref_base
*dref
= temp
->get_DerivedRef();
9281 Template
*t
= temp
->get_Template();
9283 expression_struct expr
;
9284 Code::init_expr(&expr
);
9285 expr
.expr
= mputprintf(expr
.expr
, "%s = ", t
->get_lhs_name().c_str());
9286 dref
->generate_code(&expr
);
9287 str
= Code::merge_free_expr(str
, &expr
, false);
9289 str
= t
->generate_code_init(str
, t
->get_lhs_name().c_str());
9292 FATAL_ERROR("ActualPar::rearrange_init_code_defval()");
9297 void ActualPar::append_stringRepr(string
& str
) const
9299 switch (selection
) {
9301 str
+= val
->get_stringRepr();
9304 temp
->append_stringRepr(str
);
9307 str
+= ref
->get_dispname();
9313 str
+= "<erroneous actual parameter>";
9317 void ActualPar::dump(unsigned level
) const
9319 switch (selection
) {
9321 DEBUG(level
, "actual parameter: value");
9322 val
->dump(level
+ 1);
9325 DEBUG(level
, "actual parameter: template");
9326 temp
->dump(level
+ 1);
9329 DEBUG(level
, "actual parameter: referecne");
9330 ref
->dump(level
+ 1);
9333 DEBUG(level
, "actual parameter: default");
9336 DEBUG(level
, "actual parameter: erroneous");
9340 // =================================
9341 // ===== ActualParList
9342 // =================================
9344 ActualParList::ActualParList(const ActualParList
& p
)
9347 size_t nof_pars
= p
.params
.size();
9348 for (size_t i
= 0; i
< nof_pars
; i
++) params
.add(p
.params
[i
]->clone());
9351 ActualParList::~ActualParList()
9353 size_t nof_pars
= params
.size();
9354 for (size_t i
= 0; i
< nof_pars
; i
++) delete params
[i
];
9358 ActualParList
*ActualParList::clone() const
9360 return new ActualParList(*this);
9363 void ActualParList::set_fullname(const string
& p_fullname
)
9365 Node::set_fullname(p_fullname
);
9366 size_t nof_pars
= params
.size();
9367 for(size_t i
= 0; i
< nof_pars
; i
++)
9368 params
[i
]->set_fullname(p_fullname
+
9369 ".<parameter" + Int2string(i
+ 1) + ">");
9372 void ActualParList::set_my_scope(Scope
*p_scope
)
9374 size_t nof_pars
= params
.size();
9375 for (size_t i
= 0; i
< nof_pars
; i
++) params
[i
]->set_my_scope(p_scope
);
9378 void ActualParList::chk_recursions(ReferenceChain
& refch
)
9380 size_t nof_pars
= params
.size();
9381 for (size_t i
= 0; i
< nof_pars
; i
++)
9382 params
[i
]->chk_recursions(refch
);
9385 void ActualParList::generate_code_noalias(expression_struct
*expr
, FormalParList
*p_fpl
)
9387 size_t nof_pars
= params
.size();
9388 for (size_t i
= 0; i
< nof_pars
; i
++) {
9389 if (i
> 0) expr
->expr
= mputstr(expr
->expr
, ", ");
9390 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());
9394 void ActualParList::generate_code_alias(expression_struct
*expr
,
9395 FormalParList
*p_fpl
, Type
*p_comptype
, bool p_compself
)
9397 size_t nof_pars
= params
.size();
9398 // collect all value and template definitions that are passed by reference
9399 map
<Common::Assignment
*, void> value_refs
, template_refs
;
9400 for (size_t i
= 0; i
< nof_pars
; i
++) {
9401 ActualPar
*par
= params
[i
];
9402 if (par
->get_selection() == ActualPar::AP_DEFAULT
)
9403 par
= par
->get_ActualPar();
9404 if (par
->get_selection() == ActualPar::AP_REF
) {
9405 Common::Assignment
*ass
= par
->get_Ref()->get_refd_assignment();
9406 switch (ass
->get_asstype()) {
9407 case Common::Assignment::A_VAR
:
9408 case Common::Assignment::A_PAR_VAL_IN
:
9409 case Common::Assignment::A_PAR_VAL_OUT
:
9410 case Common::Assignment::A_PAR_VAL_INOUT
:
9411 if (!value_refs
.has_key(ass
)) value_refs
.add(ass
, 0);
9413 case Common::Assignment::A_VAR_TEMPLATE
:
9414 case Common::Assignment::A_PAR_TEMPL_IN
:
9415 case Common::Assignment::A_PAR_TEMPL_OUT
:
9416 case Common::Assignment::A_PAR_TEMPL_INOUT
:
9417 if (!template_refs
.has_key(ass
)) template_refs
.add(ass
, 0);
9423 // walk through the parameter list and generate the code
9424 // add an extra copy constructor call to the referenced value and template
9425 // parameters if the referred definition is also passed by reference to
9426 // another parameter
9427 for (size_t i
= 0; i
< nof_pars
; i
++) {
9428 if (i
> 0) expr
->expr
= mputstr(expr
->expr
, ", ");
9429 ActualPar
*par
= params
[i
];
9430 bool copy_needed
= false;
9431 // the copy constructor call is not needed if the parameter is copied
9432 // into a shadow object in the body of the called function
9433 if (!p_fpl
|| !p_fpl
->get_fp_byIndex(i
)->get_used_as_lvalue()) {
9434 switch (par
->get_selection()) {
9435 case ActualPar::AP_VALUE
: {
9436 Value
*v
= par
->get_Value();
9437 if (v
->get_valuetype() == Value::V_REFD
) {
9438 Common::Assignment
*t_ass
=
9439 v
->get_reference()->get_refd_assignment();
9440 if (value_refs
.has_key(t_ass
)) {
9441 // a reference to the same variable is also passed to the called
9444 } else if (p_comptype
|| p_compself
) {
9445 // the called definition has a 'runs on' clause so it can access
9446 // component variables
9447 switch (t_ass
->get_asstype()) {
9448 case Common::Assignment::A_PAR_VAL_OUT
:
9449 case Common::Assignment::A_PAR_VAL_INOUT
:
9450 // the parameter may be an alias of a component variable
9453 case Common::Assignment::A_VAR
:
9454 // copy is needed if t_ass is a component variable that is
9455 // visible by the called definition
9456 if (!t_ass
->is_local()) copy_needed
= true;
9457 /** \todo component type compatibility: check whether t_ass is
9458 * visible from p_comptype (otherwise copy is not needed) */
9465 case ActualPar::AP_TEMPLATE
: {
9466 TemplateInstance
*ti
= par
->get_TemplateInstance();
9467 if (!ti
->get_DerivedRef()) {
9468 Template
*t
= ti
->get_Template();
9469 if (t
->get_templatetype() == Template::TEMPLATE_REFD
) {
9470 Common::Assignment
*t_ass
=
9471 t
->get_reference()->get_refd_assignment();
9472 if (template_refs
.has_key(t_ass
)) {
9473 // a reference to the same variable is also passed to the called
9476 } else if (p_comptype
|| p_compself
) {
9477 // the called definition has a 'runs on' clause so it can access
9478 // component variables
9479 switch (t_ass
->get_asstype()) {
9480 case Common::Assignment::A_PAR_TEMPL_OUT
:
9481 case Common::Assignment::A_PAR_TEMPL_INOUT
:
9482 // the parameter may be an alias of a component variable
9485 case Common::Assignment::A_VAR_TEMPLATE
:
9486 // copy is needed if t_ass is a component variable that is
9487 // visible by the called definition
9488 if (!t_ass
->is_local()) copy_needed
= true;
9489 /** \todo component type compatibility: check whether t_ass is
9490 * visible from p_comptype (otherwise copy is not needed) */
9502 if (use_runtime_2
&& ActualPar::AP_REF
== par
->get_selection()) {
9503 // if the parameter references an element of a record of/set of, then
9504 // the record of object needs to know, so it doesn't delete the referenced
9506 Ref_base
* ref
= par
->get_Ref();
9507 FieldOrArrayRefs
* subrefs
= ref
->get_subrefs();
9508 if (subrefs
!= NULL
) {
9509 Common::Assignment
* ass
= ref
->get_refd_assignment();
9511 for (ref_i
= 0; ref_i
< subrefs
->get_nof_refs(); ++ref_i
) {
9512 FieldOrArrayRef
* subref
= subrefs
->get_ref(ref_i
);
9513 if (FieldOrArrayRef::ARRAY_REF
== subref
->get_type()) {
9514 // set the referenced index in each array in the subrefs
9515 expression_struct array_expr
;
9516 Code::init_expr(&array_expr
);
9517 // the array object's name contains the reference, followed by
9518 // the subrefs before the current array ref
9519 array_expr
.expr
= mcopystr(LazyParamData::in_lazy() ?
9520 LazyParamData::add_ref_genname(ass
, ref
->get_my_scope()).c_str() :
9521 ass
->get_genname_from_scope(ref
->get_my_scope()).c_str());
9523 subrefs
->generate_code(&array_expr
, ass
, ref_i
);
9525 expression_struct index_expr
;
9526 Code::init_expr(&index_expr
);
9527 subrefs
->get_ref(ref_i
)->get_val()->generate_code_expr(&index_expr
);
9528 // insert any preambles the array object or the index might have
9529 if (array_expr
.preamble
!= NULL
) {
9530 expr
->preamble
= mputstr(expr
->preamble
, array_expr
.preamble
);
9531 expr
->postamble
= mputstr(expr
->postamble
, array_expr
.preamble
);
9533 if (index_expr
.preamble
!= NULL
) {
9534 expr
->preamble
= mputstr(expr
->preamble
, index_expr
.preamble
);
9535 expr
->postamble
= mputstr(expr
->postamble
, index_expr
.preamble
);
9537 // let the array object know that the index is referenced before
9538 // calling the function, and let it know that it's now longer
9539 // referenced after the function call (this is done with the help
9540 // of the RefdIndexHandler's constructor and destructor)
9541 string tmp_id
= ref
->get_my_scope()->get_scope_mod_gen()->get_temporary_id();
9542 expr
->preamble
= mputprintf(expr
->preamble
,
9543 "RefdIndexHandler %s(&%s, %s);\n",
9544 tmp_id
.c_str(), array_expr
.expr
, index_expr
.expr
);
9545 // insert any postambles the array object or the index might have
9546 if (array_expr
.postamble
!= NULL
) {
9547 expr
->preamble
= mputstr(expr
->preamble
, array_expr
.postamble
);
9548 expr
->postamble
= mputstr(expr
->postamble
, array_expr
.postamble
);
9550 if (index_expr
.postamble
!= NULL
) {
9551 expr
->preamble
= mputstr(expr
->preamble
, index_expr
.postamble
);
9552 expr
->postamble
= mputstr(expr
->postamble
, index_expr
.postamble
);
9554 Code::free_expr(&array_expr
);
9555 Code::free_expr(&index_expr
);
9556 } // if (FieldOrArrayRef::ARRAY_REF == subref->get_type())
9558 } // if (subrefs != NULL)
9559 } // if (ActualPar::AP_REF == par->get_selection())
9561 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());
9564 template_refs
.clear();
9567 char *ActualParList::rearrange_init_code(char *str
, bool is_local
)
9569 for (size_t i
= 0; i
< params
.size(); i
++)
9570 str
= params
[i
]->rearrange_init_code(str
, is_local
);
9574 void ActualParList::dump(unsigned level
) const
9576 DEBUG(level
, "actual parameter list: %lu parameters",
9577 (unsigned long) params
.size());
9578 for (size_t i
= 0; i
< params
.size(); i
++)
9579 params
[i
]->dump(level
+ 1);