From b9a156cfa65231575f50da0aa8c9936b362a36e1 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 3 Mar 2022 16:23:02 +0100 Subject: [PATCH 01/13] OOP: fixed name clash in the constructor and improved previous modifications to work with subreferences (issue #584) Signed-off-by: Botond Baranyi --- compiler2/Value.cc | 350 +++++++++++++++++- compiler2/Value.hh | 2 + compiler2/ttcn3/AST_ttcn3.cc | 200 +++++++--- compiler2/ttcn3/AST_ttcn3.hh | 6 + compiler2/ttcn3/TtcnTemplate.cc | 98 ++++- compiler2/ttcn3/TtcnTemplate.hh | 2 + compiler2/ttcn3/Ttcnstuff.cc | 2 +- .../Semantic_Analyser/oop/oop_SE.ttcn | 5 + regression_test/oop/oop2.ttcn | 31 +- 9 files changed, 625 insertions(+), 71 deletions(-) diff --git a/compiler2/Value.cc b/compiler2/Value.cc index bd2cf17e4..f0a72191f 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -13881,6 +13881,9 @@ void Value::chk_expr_operand_execute_refd(Value *v1, if (parlist) { str = parlist->rearrange_init_code(str, usage_mod); } + if (get_code_section() == CS_INIT_CLASS && get_value_refd_last() == this) { + str = rearrange_init_code_refd(str); + } break; } case V_INVOKE: { str = u.invoke.v->rearrange_init_code(str, usage_mod); @@ -14078,6 +14081,29 @@ void Value::chk_expr_operand_execute_refd(Value *v1, return str; } + char* Value::rearrange_init_code_refd(char* str) + { + Assignment* refd_ass = u.ref.ref->get_refd_assignment(); + if ((refd_ass->get_asstype() == Assignment::A_CONST || + refd_ass->get_asstype() == Assignment::A_VAR) && + refd_ass->get_my_scope()->get_parent_scope()->is_class_scope()) { + Ttcn::Reference* ttcn_ref = dynamic_cast(u.ref.ref); + if (ttcn_ref == NULL) { + FATAL_ERROR("Value::generate_code_init_refd"); + } + Value* v2 = refd_ass->get_Value(); + if (!ttcn_ref->is_gen_class_defpar_prefix() && + v2 != NULL && needs_init_precede(v2)) { + string lhs = v2->get_lhs_name(); + if (refd_ass->get_asstype() == Assignment::A_VAR) { + lhs = string("this->") + lhs; + } + str = v2->generate_code_init(str, lhs.c_str()); + } + } + return str; + } + char* Value::generate_code_tmp(char *str, const char *prefix, size_t& blockcount) { @@ -15985,19 +16011,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, { Value *v = get_value_refd_last(); if (v == this) { - Assignment* refd_ass = u.ref.ref->get_refd_assignment(); - if ((refd_ass->get_asstype() == Assignment::A_CONST || - refd_ass->get_asstype() == Assignment::A_VAR) && - refd_ass->get_my_scope()->get_parent_scope()->is_class_scope()) { - Ttcn::Reference* ttcn_ref = dynamic_cast(u.ref.ref); - if (ttcn_ref == NULL) { - FATAL_ERROR("Value::generate_code_init_refd"); - } - Value* v2 = refd_ass->get_Value(); - if (!ttcn_ref->is_gen_class_defpar_prefix() && - v2 != NULL && needs_init_precede(v2)) { // todo: defpar? - str = v2->generate_code_init(str, v2->get_lhs_name().c_str()); - } + if (get_code_section() == CS_INIT_CLASS) { + str = rearrange_init_code_refd(str); } // the referred value is not available at compile time // the code generation is based on the reference @@ -16940,6 +16955,29 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } } break; } + case V_SEQ: + case V_SET: + for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { + u.val_nvs->get_nv_byIndex(i)->get_value()->chk_ctor_defpar(default_ctor, in_base_call); + } + break; + case V_SEQOF: + case V_SETOF: + case V_ARRAY: + if (u.val_vs->is_indexed()) { + for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { + u.val_vs->get_iv_byIndex(i)->get_value()->chk_ctor_defpar(default_ctor, in_base_call); + } + } + else { + for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { + u.val_vs->get_v_byIndex(i)->chk_ctor_defpar(default_ctor, in_base_call); + } + } + break; + case V_CHOICE: + u.choice.alt_value->chk_ctor_defpar(default_ctor, in_base_call); + break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: @@ -17145,6 +17183,246 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } } + void Value::chk_class_member(Ttcn::ClassTypeBody* p_class) + { + switch (valuetype) { + case V_REFD: { + Ttcn::Reference* ttcn_ref = dynamic_cast(u.ref.ref); + if (ttcn_ref != NULL) { + ttcn_ref->chk_class_member(p_class); + if (ttcn_ref->has_parameters()) { + ttcn_ref->get_parlist()->chk_class_member(p_class); + } + } + break; } + case V_SEQ: + case V_SET: + for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { + u.val_nvs->get_nv_byIndex(i)->get_value()->chk_class_member(p_class); + } + break; + case V_SEQOF: + case V_SETOF: + case V_ARRAY: + if (u.val_vs->is_indexed()) { + for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { + u.val_vs->get_iv_byIndex(i)->get_value()->chk_class_member(p_class); + } + } + else { + for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { + u.val_vs->get_v_byIndex(i)->chk_class_member(p_class); + } + } + break; + case V_CHOICE: + u.choice.alt_value->chk_class_member(p_class); + break; + case V_EXPR: + switch (u.expr.v_optype) { + case OPTYPE_UNARYPLUS: + case OPTYPE_UNARYMINUS: + case OPTYPE_NOT: + case OPTYPE_NOT4B: + case OPTYPE_BIT2HEX: + case OPTYPE_BIT2INT: + case OPTYPE_BIT2OCT: + case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: + case OPTYPE_CBOR2JSON: + case OPTYPE_CHAR2INT: + case OPTYPE_CHAR2OCT: + case OPTYPE_FLOAT2INT: + case OPTYPE_FLOAT2STR: + case OPTYPE_HEX2BIT: + case OPTYPE_HEX2INT: + case OPTYPE_HEX2OCT: + case OPTYPE_HEX2STR: + case OPTYPE_INT2CHAR: + case OPTYPE_INT2FLOAT: + case OPTYPE_INT2STR: + case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: + case OPTYPE_JSON2CBOR: + case OPTYPE_OCT2BIT: + case OPTYPE_OCT2CHAR: + case OPTYPE_OCT2HEX: + case OPTYPE_OCT2INT: + case OPTYPE_OCT2STR: + case OPTYPE_STR2BIT: + case OPTYPE_STR2FLOAT: + case OPTYPE_STR2HEX: + case OPTYPE_STR2INT: + case OPTYPE_STR2OCT: + case OPTYPE_UNICHAR2INT: + case OPTYPE_UNICHAR2CHAR: + case OPTYPE_ENUM2INT: + case OPTYPE_ISCHOSEN_V: + case OPTYPE_GET_STRINGENCODING: + case OPTYPE_REMOVE_BOM: + case OPTYPE_DECODE_BASE64: + u.expr.v1->chk_class_member(p_class); + break; + case OPTYPE_DECODE: { + if (u.expr.r1->has_parameters()) { + u.expr.r1->get_parlist()->chk_class_member(p_class); + } + else { + u.expr.r1->chk_class_member(p_class); + } + if (u.expr.r2->has_parameters()) { + u.expr.r2->get_parlist()->chk_class_member(p_class); + } + else { + u.expr.r2->chk_class_member(p_class); + } + if (u.expr.v3 != NULL) { + u.expr.v3->chk_class_member(p_class); + } + if (u.expr.v4 != NULL) { + u.expr.v4->chk_class_member(p_class); + } + break; } + case OPTYPE_HOSTID: + if (u.expr.v1 != NULL) { + u.expr.v1->chk_class_member(p_class); + } + break; + case OPTYPE_ADD: + case OPTYPE_SUBTRACT: + case OPTYPE_MULTIPLY: + case OPTYPE_DIVIDE: + case OPTYPE_MOD: + case OPTYPE_REM: + case OPTYPE_CONCAT: + case OPTYPE_EQ: + case OPTYPE_LT: + case OPTYPE_GT: + case OPTYPE_NE: + case OPTYPE_GE: + case OPTYPE_LE: + case OPTYPE_AND: + case OPTYPE_OR: + case OPTYPE_XOR: + case OPTYPE_AND4B: + case OPTYPE_OR4B: + case OPTYPE_XOR4B: + case OPTYPE_SHL: + case OPTYPE_SHR: + case OPTYPE_ROTL: + case OPTYPE_ROTR: + case OPTYPE_INT2BIT: + case OPTYPE_INT2HEX: + case OPTYPE_INT2OCT: + u.expr.v1->chk_class_member(p_class); + u.expr.v2->chk_class_member(p_class); + break; + case OPTYPE_UNICHAR2OCT: // v1 [v2] + case OPTYPE_OCT2UNICHAR: + case OPTYPE_ENCODE_BASE64: + u.expr.v1->chk_class_member(p_class); + if (u.expr.v2 != NULL) { + u.expr.v2->chk_class_member(p_class); + } + break; + case OPTYPE_SUBSTR: + case OPTYPE_ENCODE: + u.expr.ti1->chk_class_member(p_class); + if (u.expr.v2 != NULL) { + u.expr.v2->chk_class_member(p_class); + } + if (u.expr.v3 != NULL) { + u.expr.v3->chk_class_member(p_class); + } + break; + case OPTYPE_REGEXP: + u.expr.ti1->chk_class_member(p_class); + u.expr.t2->chk_class_member(p_class); + u.expr.v3->chk_class_member(p_class); + break; + case OPTYPE_DECOMP: + u.expr.v1->chk_class_member(p_class); + u.expr.v2->chk_class_member(p_class); + u.expr.v3->chk_class_member(p_class); + break; + case OPTYPE_REPLACE: + u.expr.ti1->chk_class_member(p_class); + u.expr.v2->chk_class_member(p_class); + u.expr.v3->chk_class_member(p_class); + u.expr.ti4->chk_class_member(p_class); + break; + case OPTYPE_ISTEMPLATEKIND: + u.expr.ti1->chk_class_member(p_class); + u.expr.v2->chk_class_member(p_class); + break; + case OPTYPE_VALUEOF: + if (u.expr.subrefs2 != NULL) { + for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { + Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); + if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { + subref->get_val()->chk_class_member(p_class); + } + } + } + // fall through + case OPTYPE_LENGTHOF: + case OPTYPE_SIZEOF: + case OPTYPE_ISPRESENT: + case OPTYPE_TTCN2STRING: + u.expr.ti1->chk_class_member(p_class); + break; + case OPTYPE_ENCVALUE_UNICHAR: + u.expr.ti1->chk_class_member(p_class); + if (u.expr.v2 != NULL) { + u.expr.v2->chk_class_member(p_class); + } + if (u.expr.v3 != NULL) { + u.expr.v3->chk_class_member(p_class); + } + if (u.expr.v4 != NULL) { + u.expr.v4->chk_class_member(p_class); + } + break; + case OPTYPE_DECVALUE_UNICHAR: { + if (u.expr.r1->has_parameters()) { + u.expr.r1->get_parlist()->chk_class_member(p_class); + } + else { + u.expr.r1->chk_class_member(p_class); + } + if (u.expr.r2->has_parameters()) { + u.expr.r2->get_parlist()->chk_class_member(p_class); + } + else { + u.expr.r2->chk_class_member(p_class); + } + if (u.expr.v3 != NULL) { + u.expr.v3->chk_class_member(p_class); + } + if (u.expr.v4 != NULL) { + u.expr.v4->chk_class_member(p_class); + } + if (u.expr.v5 != NULL) { + u.expr.v5->chk_class_member(p_class); + } + break; } + case OPTYPE_ISCHOSEN_T: + case OPTYPE_ISVALUE: + u.expr.t1->chk_class_member(p_class); + break; + case OPTYPE_MATCH: + u.expr.v1->chk_class_member(p_class); + u.expr.t2->chk_class_member(p_class); + break; + default: + break; + } + break; + default: + break; + } + } + void Value::set_gen_class_defpar_prefix() { switch (valuetype) { @@ -17157,6 +17435,29 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } } break; } + case V_SEQ: + case V_SET: + for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { + u.val_nvs->get_nv_byIndex(i)->get_value()->set_gen_class_defpar_prefix(); + } + break; + case V_SEQOF: + case V_SETOF: + case V_ARRAY: + if (u.val_vs->is_indexed()) { + for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { + u.val_vs->get_iv_byIndex(i)->get_value()->set_gen_class_defpar_prefix(); + } + } + else { + for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { + u.val_vs->get_v_byIndex(i)->set_gen_class_defpar_prefix(); + } + } + break; + case V_CHOICE: + u.choice.alt_value->set_gen_class_defpar_prefix(); + break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: @@ -17368,6 +17669,29 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } } break; } + case V_SEQ: + case V_SET: + for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { + u.val_nvs->get_nv_byIndex(i)->get_value()->set_gen_class_base_call_postfix(); + } + break; + case V_SEQOF: + case V_SETOF: + case V_ARRAY: + if (u.val_vs->is_indexed()) { + for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { + u.val_vs->get_iv_byIndex(i)->get_value()->set_gen_class_base_call_postfix(); + } + } + else { + for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { + u.val_vs->get_v_byIndex(i)->set_gen_class_base_call_postfix(); + } + } + break; + case V_CHOICE: + u.choice.alt_value->set_gen_class_base_call_postfix(); + break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: diff --git a/compiler2/Value.hh b/compiler2/Value.hh index 5ef9c3316..14b35b8c8 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -893,6 +893,7 @@ namespace Common { * (e.g. function calls) and in operands of valueof or match * operations. */ char *rearrange_init_code(char *str, Common::Module* usage_mod); + char* rearrange_init_code_refd(char* str); /** * Generates a value for temporary use. Example: * @@ -1092,6 +1093,7 @@ namespace Common { bool get_is_in_brackets() const; void chk_ctor_defpar(bool default_ctor, bool in_base_call); + void chk_class_member(Ttcn::ClassTypeBody* p_class); void set_gen_class_defpar_prefix(); void set_gen_class_base_call_postfix(); diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 47c1c586f..39b5a28a7 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -1171,6 +1171,25 @@ namespace Ttcn { } } + void Reference::chk_class_member(ClassTypeBody* p_class) + { + Common::Assignment* ass = get_refd_assignment_last(); + Scope* ass_parent_scope = refd_ass->get_my_scope()->get_parent_scope(); + switch (ass->get_asstype()) { + case Common::Assignment::A_CONST: + case Common::Assignment::A_TEMPLATE: + case Common::Assignment::A_VAR: + case Common::Assignment::A_VAR_TEMPLATE: + case Common::Assignment::A_TIMER: + if (ass_parent_scope->is_class_scope() && ass_parent_scope->get_scope_class() == p_class) { + set_reftype(Ref_simple::REF_THIS); + } + break; + default: + break; + } + } + bool Reference::has_single_expr() { if (!Ref_base::has_single_expr()) { @@ -1286,24 +1305,10 @@ namespace Ttcn { { Common::Assignment *ass = get_refd_assignment(); if (!ass) FATAL_ERROR("Reference::generate_code()"); - if (reftype == REF_THIS) { - if (id != NULL) { - expr->expr = mputstr(expr->expr, "this->"); - } - else { // no 'id' means it's just a 'this' reference - string tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id(); - expr->preamble = mputprintf(expr->preamble, "%s %s(this);\n", - ass->get_Type()->get_genname_value(my_scope).c_str(), tmp_id.c_str()); - expr->expr = mputprintf(expr->expr, "%s", tmp_id.c_str()); - return; - } - } - else if (reftype == REF_SUPER) { - Common::Type* base_type = my_scope->get_scope_class()->get_base_type()-> - get_type_refd_last(); - expr->expr = mputprintf(expr->expr, "%s::", - base_type->get_class_type_body()->is_built_in() ? "OBJECT" : - base_type->get_genname_own(my_scope).c_str()); + generate_class_specific_expr(expr); + if (reftype == REF_THIS && id == NULL) { + // 'this' with no field reference has already been handled by 'generate_class_specific_expr' + return; } if (reftype == REF_VALUE) { expr->expr = mputstr(expr->expr, ass->get_genname_from_scope(my_scope).c_str()); @@ -1318,8 +1323,6 @@ namespace Ttcn { } else { string const_prefix; // empty by default string exception_postfix; // also empty by default - string defpar_init_prefix; - string defpar_base_call_postfix; if (gen_const_prefix) { if (ass->get_asstype() == Common::Assignment::A_CONST) { const_prefix = "const_"; @@ -1328,39 +1331,14 @@ namespace Ttcn { const_prefix = "template_"; } } - if (gen_class_defpar_prefix && ass->get_my_scope()->is_class_scope()) { - defpar_init_prefix = "p_class->"; - } - if (gen_class_base_call_postfix) { - switch (ass->get_asstype()) { - case Common::Assignment::A_PAR_VAL_IN: - case Common::Assignment::A_PAR_VAL_INOUT: - case Common::Assignment::A_PAR_VAL_OUT: - case Common::Assignment::A_PAR_TEMPL_IN: - case Common::Assignment::A_PAR_TEMPL_INOUT: - case Common::Assignment::A_PAR_TEMPL_OUT: - case Common::Assignment::A_PAR_TIMER: { - FormalPar* formal_par = dynamic_cast(ass); - if (formal_par == NULL) { - FATAL_ERROR("Reference::generate_code"); - } - Definition* fp_def = formal_par->get_my_parlist()->get_my_def(); - if (fp_def->get_asstype() == Common::Assignment::A_CONSTRUCTOR && formal_par->has_defval()) { - defpar_base_call_postfix = string("_defpar(this)"); - } - break; } - default: - break; - } - } if (ass->get_asstype() == Common::Assignment::A_EXCEPTION) { exception_postfix = "()"; } expr->expr = mputstr(expr->expr, LazyFuzzyParamData::in_lazy_or_fuzzy() ? LazyFuzzyParamData::add_ref_genname(ass, my_scope).c_str() : - (defpar_init_prefix + const_prefix + ass->get_genname_from_scope(my_scope) + - defpar_base_call_postfix + exception_postfix).c_str()); + (get_class_defpar_prefix() + const_prefix + ass->get_genname_from_scope(my_scope) + + get_class_base_call_postfix() + exception_postfix).c_str()); } } if (subrefs.get_nof_refs() > 0) subrefs.generate_code(expr, ass, my_scope); @@ -1427,14 +1405,11 @@ namespace Ttcn { refd_gov->get_genname_value(get_my_scope()).c_str()); } } + generate_class_specific_expr(&this_expr); string exception_postfix; if (ass->get_asstype() == Common::Assignment::A_EXCEPTION) { exception_postfix = "()"; } - string defpar_prefix; - if (gen_class_defpar_prefix && ass->get_my_scope()->is_class_scope()) { - defpar_prefix = "p_class->"; - } if (parlist != NULL) { // reference without parameters to a template that has only default formal parameters. // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code() @@ -1447,7 +1422,8 @@ namespace Ttcn { this_expr.expr = mputstr(this_expr.expr, LazyFuzzyParamData::in_lazy_or_fuzzy() ? LazyFuzzyParamData::add_ref_genname(ass, my_scope).c_str() : - (defpar_prefix + ass->get_genname_from_scope(my_scope) + exception_postfix).c_str()); + (get_class_defpar_prefix() + ass->get_genname_from_scope(my_scope) + + get_class_base_call_postfix() + exception_postfix).c_str()); } if (refd_gov->get_type_refd_last()->get_typetype() != Common::Type::T_CLASS) { this_expr.expr = mputstr(this_expr.expr, ")"); @@ -1635,6 +1611,80 @@ namespace Ttcn { } } + void Reference::generate_class_specific_expr(expression_struct_t *expr) + { + if (reftype != REF_THIS && reftype != REF_SUPER) { + return; + } + Common::Assignment *ass = get_refd_assignment(); + if (ass == NULL) { + FATAL_ERROR("Reference::generate_class_specific_expr()"); + } + if (reftype == REF_THIS) { + if (id != NULL && !gen_class_defpar_prefix) { + expr->expr = mputstr(expr->expr, "this->"); + } + else if (id == NULL) { // no 'id' means it's just a 'this' reference + string tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id(); + expr->preamble = mputprintf(expr->preamble, "%s %s(this);\n", + ass->get_Type()->get_genname_value(my_scope).c_str(), tmp_id.c_str()); + expr->expr = mputprintf(expr->expr, "%s", tmp_id.c_str()); + } + } + else if (reftype == REF_SUPER) { + Common::Type* base_type = my_scope->get_scope_class()->get_base_type()-> + get_type_refd_last(); + expr->expr = mputprintf(expr->expr, "%s::", + base_type->get_class_type_body()->is_built_in() ? "OBJECT" : + base_type->get_genname_own(my_scope).c_str()); + } + } + + string Reference::get_class_defpar_prefix() + { + if (gen_class_defpar_prefix) { + Common::Assignment *ass = get_refd_assignment(); + if (ass == NULL) { + FATAL_ERROR("Reference::get_class_defpar_prefix()"); + } + if (ass->get_my_scope()->is_class_scope()) { + return string("p_class->"); + } + } + return string(); + } + + string Reference::get_class_base_call_postfix() + { + if (gen_class_base_call_postfix) { + Common::Assignment *ass = get_refd_assignment(); + if (ass == NULL) { + FATAL_ERROR("Reference::get_class_base_call_postfix()"); + } + switch (ass->get_asstype()) { + case Common::Assignment::A_PAR_VAL_IN: + case Common::Assignment::A_PAR_VAL_INOUT: + case Common::Assignment::A_PAR_VAL_OUT: + case Common::Assignment::A_PAR_TEMPL_IN: + case Common::Assignment::A_PAR_TEMPL_INOUT: + case Common::Assignment::A_PAR_TEMPL_OUT: + case Common::Assignment::A_PAR_TIMER: { + FormalPar* formal_par = dynamic_cast(ass); + if (formal_par == NULL) { + FATAL_ERROR("Reference::get_class_base_call_postfix"); + } + Definition* fp_def = formal_par->get_my_parlist()->get_my_def(); + if (fp_def->get_asstype() == Common::Assignment::A_CONSTRUCTOR && formal_par->has_defval()) { + return string("_defpar(this)"); + } + break; } + default: + break; + } + } + return string(); + } + // ================================= // ===== NameBridgingScope @@ -4270,6 +4320,9 @@ namespace Ttcn { value->set_genname_recursive(get_genname()); value->set_code_section(my_scope->is_class_scope() ? GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_PRE_INIT); + if (my_scope->is_class_scope()) { + value->chk_class_member(my_scope->get_scope_class()); + } } } @@ -5068,6 +5121,9 @@ namespace Ttcn { body->set_code_section(fp_list ? GovernedSimple::CS_INLINE : (my_scope->is_class_scope() ? GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_POST_INIT)); + if (my_scope->is_class_scope()) { + body->chk_class_member(my_scope->get_scope_class()); + } } } @@ -5634,6 +5690,9 @@ namespace Ttcn { initial_value->set_genname_recursive(get_genname()); initial_value->set_code_section(my_scope->is_class_scope() ? GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_INLINE); + if (my_scope->is_class_scope()) { + initial_value->chk_class_member(my_scope->get_scope_class()); + } } } break; @@ -5907,6 +5966,9 @@ namespace Ttcn { initial_value->set_genname_recursive(get_genname()); initial_value->set_code_section(my_scope->is_class_scope() ? GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_INLINE); + if (my_scope->is_class_scope()) { + initial_value->chk_class_member(my_scope->get_scope_class()); + } } } if (w_attrib_path) { @@ -6121,6 +6183,9 @@ namespace Ttcn { if (!semantic_check_only) { default_duration->set_code_section(GovernedSimple::CS_POST_INIT); } + if (my_scope->is_class_scope()) { + default_duration->chk_class_member(my_scope->get_scope_class()); + } } checked = true; if (w_attrib_path) { @@ -10886,13 +10951,16 @@ namespace Ttcn { // check whether the parameter type is allowed switch (deftype) { case Definition::A_TEMPLATE: + case Definition::A_CONSTRUCTOR: switch (par->get_asstype()) { case Definition::A_PAR_VAL_IN: case Definition::A_PAR_TEMPL_IN: // these are allowed break; default: - par->error("A template cannot have %s", par->get_assname()); + par->error("A %s cannot have %s", + deftype == Definition::A_TEMPLATE ? "template" : "constructor", + par->get_assname()); } break; case Definition::A_TESTCASE: @@ -10901,6 +10969,7 @@ namespace Ttcn { case Definition::A_PAR_PORT: // these are forbidden par->error("A testcase cannot have %s", par->get_assname()); + break; default: break; } @@ -11639,6 +11708,23 @@ namespace Ttcn { } } + void ActualPar::chk_class_member(ClassTypeBody* p_class) + { + switch (selection) { + case AP_VALUE: + val->chk_class_member(p_class); + break; + case AP_TEMPLATE: + temp->chk_class_member(p_class); + break; + case AP_REF: + ref->chk_class_member(p_class); + break; + default: + break; + } + } + bool ActualPar::has_single_expr(FormalPar* formal_par) { switch (selection) { @@ -12194,6 +12280,14 @@ namespace Ttcn { } } + void ActualParList::chk_class_member(ClassTypeBody* p_class) + { + size_t nof_pars = params.size(); + for (size_t i = 0; i < nof_pars; i++) { + params[i]->chk_class_member(p_class); + } + } + void ActualParList::set_gen_class_defpar_prefix() { size_t nof_pars = params.size(); diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index 5311aa154..2700fc01d 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -123,6 +123,7 @@ namespace Ttcn { void chk_recursions(ReferenceChain& refch); void chk_ctor_defpar(bool default_ctor, bool in_base_call); + void chk_class_member(ClassTypeBody* p_class); /** Returns whether the actual parameter can be represented by an in-line * C++ expression. */ @@ -176,6 +177,7 @@ namespace Ttcn { void chk_immutability(); void chk_ctor_defpar(bool default_ctor, bool in_base_call); + void chk_class_member(ClassTypeBody* p_class); void set_gen_class_defpar_prefix(); void set_gen_class_base_call_postfix(); @@ -412,6 +414,7 @@ namespace Ttcn { Type *chk_comptype_ref(); bool chk_activate_argument(); void chk_ctor_defpar(bool default_ctor, bool in_base_call); + void chk_class_member(ClassTypeBody* p_class); virtual bool has_single_expr(); virtual void set_code_section(GovernedSimple::code_section_t p_code_section); virtual void generate_code(expression_struct_t *expr); @@ -445,6 +448,9 @@ namespace Ttcn { private: /** Detects whether the first identifier in subrefs is a module id */ void detect_modid(); + void generate_class_specific_expr(expression_struct_t *expr); + string get_class_defpar_prefix(); + string get_class_base_call_postfix(); }; /** diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index 5fb1d9b36..64a4932cb 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -3810,7 +3810,7 @@ end: break; case TEMPLATE_CONCAT: if (!use_runtime_2) { - FATAL_ERROR("Template::chk_ctor_defpar(bool default_ctor, bool in_base_call)"); + FATAL_ERROR("Template::chk_ctor_defpar()"); } u.concat.op1->chk_ctor_defpar(default_ctor, in_base_call); u.concat.op2->chk_ctor_defpar(default_ctor, in_base_call); @@ -3837,6 +3837,94 @@ end: } } + void Template::chk_class_member(ClassTypeBody* p_class) + { + switch (templatetype) { + case SPECIFIC_VALUE: + u.specific_value->chk_class_member(p_class); + break; + case TEMPLATE_REFD: + u.ref.ref->chk_class_member(p_class); + if (u.ref.ref->has_parameters()) { + for (size_t i = 0; i < u.ref.ref->get_parlist()->get_nof_pars(); i++) + u.ref.ref->get_parlist()->get_par(i)->chk_class_member(p_class); + } + break; + case TEMPLATE_INVOKE: + u.invoke.v->chk_class_member(p_class); + if (u.invoke.ap_list != NULL) { + for (size_t i = 0; i < u.invoke.ap_list->get_nof_pars(); i++) + u.invoke.ap_list->get_par(i)->chk_class_member(p_class); + } + break; + case TEMPLATE_LIST: + case VALUE_LIST: + case COMPLEMENTED_LIST: + case SUPERSET_MATCH: + case SUBSET_MATCH: + case PERMUTATION_MATCH: + case CONJUNCTION_MATCH: + for (size_t i = 0; i < u.templates->get_nof_ts(); i++) { + u.templates->get_t_byIndex(i)->chk_class_member(p_class); + } + break; + case NAMED_TEMPLATE_LIST: + for (size_t i = 0; i < u.named_templates->get_nof_nts(); i++) { + u.named_templates->get_nt_byIndex(i)->get_template()->chk_class_member(p_class); + } + break; + case INDEXED_TEMPLATE_LIST: + for (size_t i = 0; i get_nof_its(); i++) { + u.indexed_templates->get_it_byIndex(i)->get_template()->chk_class_member(p_class); + } + break; + case VALUE_RANGE: + if (u.value_range->get_min_v() != NULL) { + u.value_range->get_min_v()->chk_class_member(p_class); + } + if (u.value_range->get_max_v() != NULL) { + u.value_range->get_max_v()->chk_class_member(p_class); + } + break; + case CSTR_PATTERN: + case USTR_PATTERN: + //u.pstring->chk_class_member(p_class); todo + break; + case DECODE_MATCH: + if (u.dec_match.str_enc != NULL) { + u.dec_match.str_enc->chk_class_member(p_class); + } + u.dec_match.target->chk_class_member(p_class); + break; + case TEMPLATE_CONCAT: + if (!use_runtime_2) { + FATAL_ERROR("Template::chk_class_member()"); + } + u.concat.op1->chk_class_member(p_class); + u.concat.op2->chk_class_member(p_class); + break; + case IMPLICATION_MATCH: + u.implication.precondition->chk_class_member(p_class); + u.implication.implied_template->chk_class_member(p_class); + break; + case DYNAMIC_MATCH: + break; + default: + break; + } + if (length_restriction != NULL) { + if (length_restriction->get_is_range()) { + length_restriction->get_lower_value()->chk_class_member(p_class); + if (length_restriction->get_upper_value() != NULL) { + length_restriction->get_upper_value()->chk_class_member(p_class); + } + } + else { + length_restriction->get_single_value()->chk_class_member(p_class); + } + } + } + void Template::set_gen_class_defpar_prefix() { switch (templatetype) { @@ -6538,6 +6626,14 @@ compile_time: template_body->chk_ctor_defpar(default_ctor, in_base_call); } + void TemplateInstance::chk_class_member(ClassTypeBody* p_class) + { + if (derived_reference != NULL) { + derived_reference->chk_class_member(p_class); + } + template_body->chk_class_member(p_class); + } + void TemplateInstance::set_gen_class_defpar_prefix() { if (derived_reference != NULL) { diff --git a/compiler2/ttcn3/TtcnTemplate.hh b/compiler2/ttcn3/TtcnTemplate.hh index df0780838..c263ebf46 100644 --- a/compiler2/ttcn3/TtcnTemplate.hh +++ b/compiler2/ttcn3/TtcnTemplate.hh @@ -464,6 +464,7 @@ namespace Ttcn { const Location* usage_loc); void chk_ctor_defpar(bool default_ctor, bool in_base_call); + void chk_class_member(ClassTypeBody* p_class); void set_gen_class_defpar_prefix(); void set_gen_class_base_call_postfix(); @@ -651,6 +652,7 @@ namespace Ttcn { void chk_immutability() const ; void chk_ctor_defpar(bool default_ctor, bool in_base_call); + void chk_class_member(ClassTypeBody* p_class); void set_gen_class_defpar_prefix(); void set_gen_class_base_call_postfix(); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index caa641a51..03e6ba37e 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -3071,7 +3071,7 @@ namespace Ttcn { Reference* p_runs_on_ref, Reference* p_mtc_ref, Reference* p_system_ref, Definitions* p_members, StatementBlock* p_finally_block) : Scope(), Location(), class_id(p_class_id), my_def(NULL), external(p_external), final(p_final), - abstract(p_abstract), trait(p_trait), built_in(FALSE), base_type(NULL), base_traits(p_base_types), base_class(NULL), + abstract(p_abstract), trait(p_trait), built_in(FALSE), base_type(NULL), base_class(NULL), base_traits(p_base_types), runs_on_ref(p_runs_on_ref), runs_on_type(NULL), mtc_ref(p_mtc_ref), mtc_type(NULL), system_ref(p_system_ref), system_type(NULL), members(p_members), finally_block(p_finally_block), constructor(NULL), checked(false), diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index 1edc31f3d..c48065cd1 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -806,6 +806,11 @@ type class C64 extends C63 { //^In type definition// : C63(p1, p2, p3, p4) { } } +type class C65 { //^In type definition// + create(inout integer p1, //^In constructor definition// //^In formal parameter list// //^In parameter// //A constructor cannot have `inout' value parameter// + out charstring p2) { } //^In parameter// //A constructor cannot have `out' value parameter// +} + control { //^In control part// var C11 x := C11.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C11', which runs on component type `@oop_SE.CT_RunsOn'// //Cannot create value of class type `@oop_SE.C11', which has an `mtc' clause, in the control part.// //Cannot create value of class type `@oop_SE.C11', which has a `system' clause, in the control part.// diff --git a/regression_test/oop/oop2.ttcn b/regression_test/oop/oop2.ttcn index 0fa1f1ec0..34ecdba33 100644 --- a/regression_test/oop/oop2.ttcn +++ b/regression_test/oop/oop2.ttcn @@ -214,12 +214,12 @@ testcase tc_member_init_rearrange() runs on CT { type class C6 { private const integer c1 := 2; - private const charstring c2 := "x"; - /* protected */ var template Rec vt1 := { num := t1, str := int2str(c1) & c2 }; + private const Rec c2 := { 4, "x" }; + /* protected */ var template Rec vt1 := { num := t1, str := int2str(c1) & c2.str }; private template integer t1 := (0..100); // default constructor: - // create(template Rec vt1 := { num := t1, str := int2str(c1) & c2 }) { + // create(template Rec vt1 := { num := t1, str := int2str(c1) & c2.str }) { // this.vt1 = vt1; // } @@ -274,6 +274,30 @@ testcase tc_base_call_with_default_value_parameter() runs on CT { setverdict(pass); } +const charstring c_c8_exp := "abc"; + +type class C8 { + private var Rec v1 := { 10, "x" }; + private var template integer vt1 := (0 .. v1.num); + create(charstring v1) { + if (v1 != c_c8_exp) { + setverdict(fail, "v1 (parameter): ", v1); + } + if (this.v1 != { 10, "x" }) { + setverdict(fail, "this.v1: ", this.v1); + } + var template integer vt1_exp := (0 .. 10); + if (log2str(vt1) != log2str(vt1_exp)) { + setverdict(fail, "vt1: ", vt1); + } + } +} + +testcase tc_constructor_param_name_clash() runs on CT { + var C8 x := C8.create(c_c8_exp); // the actual tests are in the constructor + setverdict(pass); +} + control { execute(tc_constructor_default()); execute(tc_constructor_init()); @@ -282,6 +306,7 @@ control { execute(tc_member_init_rearrange()); execute(tc_references_in_default_values()); execute(tc_base_call_with_default_value_parameter()); + execute(tc_constructor_param_name_clash()); } } -- GitLab From debacc085b262705bfe92bf7fac4131a7ee66f11 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 3 Mar 2022 18:52:09 +0100 Subject: [PATCH 02/13] XER: fixed untagged optional union decoding error (issue #585) Signed-off-by: Botond Baranyi --- compiler2/union.c | 2 +- regression_test/XML/Makefile | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler2/union.c b/compiler2/union.c index a397195da..8ee0cbf2b 100644 --- a/compiler2/union.c +++ b/compiler2/union.c @@ -2012,7 +2012,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) } if (!sdef->isOptional) { src = mputstr(src, - " else {\n" + " else if (!(p_flavor & XER_OPTIONAL)) {\n" " ec_1.set_msg(\" \");\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, " "\"'%s' does not match any alternative\", elem_name);\n" diff --git a/regression_test/XML/Makefile b/regression_test/XML/Makefile index 43c226eaf..10dbffeee 100644 --- a/regression_test/XML/Makefile +++ b/regression_test/XML/Makefile @@ -30,7 +30,8 @@ endif XDIRS := $(wildcard $(SHADOWED)) xsdConverter \ HM60295 HN15589 HQ30408 HR49727 HU13380 $(RT2_ONLY) \ XmlWorkflow tpdValidTest AbstractBlock UseNilLong AttributeFormDefault \ -RecordOmit XSDBaseType LegacyUntaggedUnion Printing Bug570707 +RecordOmit XSDBaseType LegacyUntaggedUnion Printing Bug570707 \ +Issue545 Issue585 # List of fake targets: .PHONY: all dep clean run $(XDIRS) $(addsuffix /, $(XDIRS)) profile -- GitLab From bef321bb0ad951b3531bdb7eea9ed4b9276d83a6 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 3 Mar 2022 18:53:54 +0100 Subject: [PATCH 03/13] Added missing tests (issue #585) Signed-off-by: Botond Baranyi --- regression_test/XML/Issue585/.gitignore | 7 + regression_test/XML/Issue585/Issue585.ttcn | 63 +++++++++ regression_test/XML/Issue585/Makefile | 147 +++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 regression_test/XML/Issue585/.gitignore create mode 100644 regression_test/XML/Issue585/Issue585.ttcn create mode 100644 regression_test/XML/Issue585/Makefile diff --git a/regression_test/XML/Issue585/.gitignore b/regression_test/XML/Issue585/.gitignore new file mode 100644 index 000000000..a31edf842 --- /dev/null +++ b/regression_test/XML/Issue585/.gitignore @@ -0,0 +1,7 @@ +Issue585 +Issue585.exe +Issue585*.cc +Issue585*.hh +Issue585*.d +compile +Issue585*.log diff --git a/regression_test/XML/Issue585/Issue585.ttcn b/regression_test/XML/Issue585/Issue585.ttcn new file mode 100644 index 000000000..d457deb2d --- /dev/null +++ b/regression_test/XML/Issue585/Issue585.ttcn @@ -0,0 +1,63 @@ +/****************************************************************************** + * Copyright (c) 2000-2021 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ +module Issue585 { + +type record Rec { + integer num, + Uni1 u1 optional, + Uni2 u2 +} + +type union Uni1 { + charstring x1, + octetstring x2 +} +with { + variant "untagged"; +} + +type union Uni2 { + charstring y1, + octetstring y2 +} +with { + variant "untagged"; +} + +type component CT {} + +testcase tc_issue585() runs on CT { + var Rec val := { 4, omit, { y2 := 'ABCD'O } }; + var universal charstring enc := encvalue_unichar(val); + var universal charstring enc_exp := "\n\t4\n\tABCD\n\n\n"; + if (enc != enc_exp) { + setverdict(fail, "Encoding failed. Expected: ", enc_exp, ", got: ", enc); + } + var Rec dec; + var integer res := decvalue_unichar(enc, dec); + if (res != 0 or dec != val) { + setverdict(fail, "Decoding failed. Expected: ", val, ", got: ", dec, " (result: ", res, ")"); + } + setverdict(pass); +} + +control { + execute(tc_issue585()); +} + +} +with { + encode "XML"; + variant "elementFormQualified"; + variant "namespace as 'www.somewhere.com/xml2' prefix 'ns'"; + variant "controlNamespace 'http://www.w3.org/2001/XMLSchema-instance' prefix 'xsi'"; +} diff --git a/regression_test/XML/Issue585/Makefile b/regression_test/XML/Issue585/Makefile new file mode 100644 index 000000000..dc493ce71 --- /dev/null +++ b/regression_test/XML/Issue585/Makefile @@ -0,0 +1,147 @@ +############################################################################## +# Copyright (c) 2000-2021 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################## +TOPDIR = ../.. +include $(TOPDIR)/Makefile.regression + +# WARNING! This Makefile can be used with GNU make only. +# Other versions of make may report syntax errors in it. + +# +# Do NOT touch this line... +# +.PHONY: all archive check clean dep objects + +.SUFFIXES: .d + +# +# Set these variables... +# + +# Flags for the C++ preprocessor (and makedepend as well): +#CPPFLAGS += + +# Flags for dependency generation +CXXDEPFLAGS = -MM + +# Flags for the C++ compiler: +CXXFLAGS += -Wall + +# Flags for the linker: +#LDFLAGS += + +# Flags for the TTCN-3 and ASN.1 compiler: +#COMPILER_FLAGS += + +# Execution mode: (either ttcn3 or ttcn3-parallel) +TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) + +# +# You may change these variables. Add your files if necessary... +# + +# TTCN-3 modules of this project: +TTCN3_MODULES = Issue585.ttcn + +# ASN.1 modules of this project: +ASN1_MODULES = + +# C++ source & header files generated from the TTCN-3 & ASN.1 modules of +# this project: +GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) $(ASN1_MODULES:.asn=.cc) +GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh) +ifdef SPLIT_TO_SLICES +POSTFIXES := $(foreach file, $(SPLIT_TO_SLICES), $(addsuffix $(file), _part_)) +POSTFIXES := $(foreach file, $(POSTFIXES), $(addprefix $(file), .cc)) +GENERATED_SOURCES2 := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), $(POSTFIXES))) +GENERATED_SOURCES += $(GENERATED_SOURCES2) +endif +# C/C++ Source & header files of Test Ports, external functions and +# other modules: +USER_SOURCES = +USER_HEADERS = $(USER_SOURCES:.cc=.hh) + +# Object files of this project that are needed for the executable test suite: +OBJECTS = $(GENERATED_OBJECTS) $(USER_OBJECTS) + +GENERATED_OBJECTS = $(GENERATED_SOURCES:.cc=.o) + +USER_OBJECTS = $(USER_SOURCES:.cc=.o) + +DEPFILES = $(USER_OBJECTS:.o=.d) $(GENERATED_OBJECTS:.o=.d) + +# Other files of the project (Makefile, configuration files, etc.) +# that will be added to the archived source files: +OTHER_FILES = Makefile + +# The name of the executable test suite: +TARGET = Issue585$(EXESUFFIX) + +# +# Rules for building the executable... +# + +all: $(TARGET) ; + +objects: $(OBJECTS) compile; + +$(TARGET): $(OBJECTS) + if $(CXX) $(LDFLAGS) -o $@ $^ \ + -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) \ + -L$(OPENSSL_DIR)/lib -lcrypto \ + -L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \ + then : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi + +.cc.o .c.o: + $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $< + +.cc.d .c.d: + @echo Creating dependency file for '$<'; set -e; \ + $(CXX) $(CXXDEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $< \ + | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile + @if [ ! -f $@ ]; then $(RM) compile; $(MAKE) compile; fi + +compile: $(TTCN3_MODULES) $(ASN1_MODULES) + $(TTCN3_COMPILER) $(COMPILER_FLAGS) $^ - $? + touch $@ + +clean distclean: + -$(RM) $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) compile $(DEPFILES) \ + tags *.log + +dep: $(GENERATED_SOURCES) $(USER_SOURCES) ; + +ifeq ($(findstring n,$(MAKEFLAGS)),) +ifeq ($(filter clean distclean check compile archive diag,$(MAKECMDGOALS)),) +-include $(DEPFILES) +endif +endif + +diag: + $(TTCN3_COMPILER) -v 2>&1 + $(TTCN3_DIR)/bin/mctr_cli -v 2>&1 + $(CXX) -v 2>&1 + @echo TTCN3_DIR=$(TTCN3_DIR) + @echo OPENSSL_DIR=$(OPENSSL_DIR) + @echo XMLDIR=$(XMLDIR) + @echo PLATFORM=$(PLATFORM) + +# +# Add your rules here if necessary... +# + +run: $(TARGET) + ./$^ + -- GitLab From 44130d3d9ea2c95cd86f1027e98eebaa0711a610 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Tue, 8 Mar 2022 17:02:59 +0100 Subject: [PATCH 04/13] Added location information to formal parameter default value assignments (issue #581) Signed-off-by: Botond Baranyi --- compiler2/ttcn3/AST_ttcn3.cc | 2 ++ compiler2/ttcn3/Ttcnstuff.cc | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 39b5a28a7..4df106929 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -10464,6 +10464,7 @@ namespace Ttcn { } switch (defval.ap->get_selection()) { case ActualPar::AP_VALUE: { + str = update_location_object(str); Value *val = defval.ap->get_Value(); string tmp_id; if (defpar_wrapper != Common::Type::NO_DEFPAR_WRAPPER) { @@ -10486,6 +10487,7 @@ namespace Ttcn { break; } case ActualPar::AP_TEMPLATE: { if (!use_runtime_2 || defpar_wrapper != Common::Type::NO_DEFPAR_WRAPPER) { + str = update_location_object(str); TemplateInstance *ti = defval.ap->get_TemplateInstance(); string tmp_id; if (defpar_wrapper != Common::Type::NO_DEFPAR_WRAPPER) { diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index 03e6ba37e..ee5c6d9de 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -4199,6 +4199,12 @@ namespace Ttcn { "{\n" "if (def_) {\n", in_par ? "const " : "", par_type_str.c_str(), defpar_list.get_nth_elem(i), class_id->get_name().c_str()); + if (formal_par->get_filename() != NULL && formal_par->get_first_line() > 0) { + char* loc_obj_name = mprintf("class %s default parameter", class_id->get_dispname().c_str()); + local_struct->source.methods = formal_par->create_location_object( + local_struct->source.methods, "UNKNOWN", loc_obj_name); + Free(loc_obj_name); + } local_struct->source.methods = formal_par->generate_code_defval(local_struct->source.methods); local_struct->source.methods = mputstr(local_struct->source.methods, "def_ = FALSE;\n" -- GitLab From 5952fc78bd80f036e116db5385fae72784ad203f Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 17 Mar 2022 15:52:33 +0100 Subject: [PATCH 05/13] Fixed 'implicit omit' inside optional fields that are present (issue #588) Signed-off-by: Botond Baranyi --- core/Optional.hh | 10 +++++++++ regression_test/implicitOmit/config.cfg | 1 + regression_test/implicitOmit/io.ttcn | 28 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/core/Optional.hh b/core/Optional.hh index d0bea3faf..9b887384e 100644 --- a/core/Optional.hh +++ b/core/Optional.hh @@ -364,6 +364,8 @@ public: * Redirects the call to the optional value. */ virtual void remove_refd_index(int index); #endif + + void set_implicit_omit(); }; #if HAVE_GCC(4,6) @@ -1311,6 +1313,14 @@ int OPTIONAL::TEXT_decode(const TTCN_Typedescriptor_t& p_td, #endif +template +void OPTIONAL::set_implicit_omit() +{ + if (is_present()) { + optional_value->set_implicit_omit(); + } +} + #if defined(__GNUC__) && __GNUC__ >= 3 /** Note: These functions allow most efficient operation by passing the left * operand OMIT_VALUE as value instead of constant reference. diff --git a/regression_test/implicitOmit/config.cfg b/regression_test/implicitOmit/config.cfg index f8ea3a4b4..4610fa321 100644 --- a/regression_test/implicitOmit/config.cfg +++ b/regression_test/implicitOmit/config.cfg @@ -30,6 +30,7 @@ mrecof1 := { [1] := { c := "clinton" } } msetof1 := { [1] := { c := "clinton" } } mrecof2 := { [1] := { mr2 := { c := "clinton" } } } msetof2 := { [1] := { ms2 := { c := "clinton" } } } +mp_emb_opt := { m := { a := 2 } } [EXECUTE] io.control diff --git a/regression_test/implicitOmit/io.ttcn b/regression_test/implicitOmit/io.ttcn index 4d71ff9cb..3485cea51 100644 --- a/regression_test/implicitOmit/io.ttcn +++ b/regression_test/implicitOmit/io.ttcn @@ -37,6 +37,10 @@ type record MyRecord2 { MyRecord1 m } +type record MyRecord3 { + MyRecord1 m optional +} + type set MySet2 { MySet1 m } @@ -562,6 +566,29 @@ testcase tc_io_asn_record_empty() runs on O else { setverdict(fail, t_asn_rec_empty); } } +// Implicit omit for fields of records embedded in an optional field of another record +const MyRecord3 c_emb_opt := { m := { a := 2 } } +with { optional "implicit omit" } + +template MyRecord3 t_emb_opt := { m := { a := ? } } +with { optional "implicit omit" } + +modulepar MyRecord3 mp_emb_opt +with { optional "implicit omit" } + +testcase tc_io_embedded_optional() runs on O { + if (not isbound(c_emb_opt) or c_emb_opt.m.b != omit) { + setverdict(fail, "c_emb_opt: ", c_emb_opt); + } + if (not isbound(t_emb_opt) or log2str(t_emb_opt.m.b) != "omit") { + setverdict(fail, "t_emb_opt: ", t_emb_opt); + } + if (not isbound(mp_emb_opt) or mp_emb_opt.m.b != omit) { + setverdict(fail, "c_emb_opt: ", mp_emb_opt); + } + setverdict(pass); +} + control { execute(tc12()); execute(tc1ab()); @@ -605,6 +632,7 @@ execute(tc_HQ30261()) execute(tc_io_embedded()); execute(tc_io_notused()); execute(tc_io_asn_record_empty()); +execute(tc_io_embedded_optional()); } with { optional "implicit omit" -- GitLab From 16ea9caf6cc65768da0bd25a9f8e0d9132cb77a0 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 17 Mar 2022 15:55:41 +0100 Subject: [PATCH 06/13] Fixed copy-paste error Signed-off-by: Botond Baranyi --- regression_test/implicitOmit/io.ttcn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression_test/implicitOmit/io.ttcn b/regression_test/implicitOmit/io.ttcn index 3485cea51..b2e322fda 100644 --- a/regression_test/implicitOmit/io.ttcn +++ b/regression_test/implicitOmit/io.ttcn @@ -584,7 +584,7 @@ testcase tc_io_embedded_optional() runs on O { setverdict(fail, "t_emb_opt: ", t_emb_opt); } if (not isbound(mp_emb_opt) or mp_emb_opt.m.b != omit) { - setverdict(fail, "c_emb_opt: ", mp_emb_opt); + setverdict(fail, "mp_emb_opt: ", mp_emb_opt); } setverdict(pass); } -- GitLab From 79fe5fac523a98edfa7c1833fcf20c1806578794 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 17 Mar 2022 17:30:40 +0100 Subject: [PATCH 07/13] Made location information for parameter default value assignments more accurate (issue #581) Signed-off-by: Botond Baranyi --- compiler2/ttcn3/AST_ttcn3.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 4df106929..ed78fdc91 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -10464,8 +10464,8 @@ namespace Ttcn { } switch (defval.ap->get_selection()) { case ActualPar::AP_VALUE: { - str = update_location_object(str); Value *val = defval.ap->get_Value(); + str = val->update_location_object(str); string tmp_id; if (defpar_wrapper != Common::Type::NO_DEFPAR_WRAPPER) { tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id(); @@ -10487,8 +10487,8 @@ namespace Ttcn { break; } case ActualPar::AP_TEMPLATE: { if (!use_runtime_2 || defpar_wrapper != Common::Type::NO_DEFPAR_WRAPPER) { - str = update_location_object(str); TemplateInstance *ti = defval.ap->get_TemplateInstance(); + str = ti->get_Template()->update_location_object(str); string tmp_id; if (defpar_wrapper != Common::Type::NO_DEFPAR_WRAPPER) { tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id(); -- GitLab From 1a2bf75f551b37973b1810e85bb09be1f5302967 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Fri, 18 Mar 2022 10:37:10 +0100 Subject: [PATCH 08/13] Fixed an issue with the parameter default value location change (issue #581) Signed-off-by: Botond Baranyi --- compiler2/ttcn3/Ttcnstuff.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index 566b7f19e..16dd95b81 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -4199,9 +4199,11 @@ namespace Ttcn { "{\n" "if (def_) {\n", in_par ? "const " : "", par_type_str.c_str(), defpar_list.get_nth_elem(i), class_id->get_name().c_str()); - if (formal_par->get_filename() != NULL && formal_par->get_first_line() > 0) { + ActualPar* ap = formal_par->get_defval(); + Location* ap_loc = templ_par ? (Location*)ap->get_TemplateInstance()->get_Template() : (Location*)ap->get_Value(); + if (ap_loc->get_filename() != NULL && ap_loc->get_first_line() > 0) { char* loc_obj_name = mprintf("class %s default parameter", class_id->get_dispname().c_str()); - local_struct->source.methods = formal_par->create_location_object( + local_struct->source.methods = ap_loc->create_location_object( local_struct->source.methods, "UNKNOWN", loc_obj_name); Free(loc_obj_name); } -- GitLab From f691591ea492ccb1f1909492a2676762c83d0012 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Wed, 23 Mar 2022 17:45:56 +0100 Subject: [PATCH 09/13] OOP: fixed super-constructor call parameter code generation for structured values and templates (issue #591) Signed-off-by: Botond Baranyi --- compiler2/ttcn3/AST_ttcn3.cc | 105 ++++++++++++++++++++++++++++------ compiler2/ttcn3/AST_ttcn3.hh | 8 ++- compiler2/ttcn3/Ttcnstuff.cc | 8 ++- regression_test/oop/oop2.ttcn | 32 +++++++++++ 4 files changed, 131 insertions(+), 22 deletions(-) diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index ed78fdc91..253c6d727 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -11498,7 +11498,7 @@ namespace Ttcn { ActualPar::ActualPar(Value *v) : Node(), selection(AP_VALUE), my_scope(0), gen_restriction_check(TR_NONE), - gen_post_restriction_check(TR_NONE) + gen_post_restriction_check(TR_NONE), is_base_ctor_param(false) { if (!v) FATAL_ERROR("ActualPar::ActualPar()"); val = v; @@ -11506,7 +11506,8 @@ namespace Ttcn { ActualPar::ActualPar(TemplateInstance *t) : Node(), selection(AP_TEMPLATE), my_scope(0), - gen_restriction_check(TR_NONE), gen_post_restriction_check(TR_NONE) + gen_restriction_check(TR_NONE), gen_post_restriction_check(TR_NONE), + is_base_ctor_param(false) { if (!t) FATAL_ERROR("ActualPar::ActualPar()"); temp = t; @@ -11514,7 +11515,7 @@ namespace Ttcn { ActualPar::ActualPar(Reference *r) : Node(), selection(AP_REF), my_scope(0), gen_restriction_check(TR_NONE), - gen_post_restriction_check(TR_NONE) + gen_post_restriction_check(TR_NONE), is_base_ctor_param(false) { if (!r) FATAL_ERROR("ActualPar::ActualPar()"); ref = r; @@ -11522,7 +11523,8 @@ namespace Ttcn { ActualPar::ActualPar(ActualPar *a) : Node(), selection(AP_DEFAULT), my_scope(0), - gen_restriction_check(TR_NONE), gen_post_restriction_check(TR_NONE) + gen_restriction_check(TR_NONE), gen_post_restriction_check(TR_NONE), + is_base_ctor_param(false) { if (!a) FATAL_ERROR("ActualPar::ActualPar()"); act = a; @@ -11531,7 +11533,8 @@ namespace Ttcn { ActualPar::ActualPar(const ActualPar& p) : Node(), selection(p.selection), my_scope(p.my_scope), gen_restriction_check(p.gen_restriction_check), - gen_post_restriction_check(p.gen_post_restriction_check) + gen_post_restriction_check(p.gen_post_restriction_check), + is_base_ctor_param(false) { switch(selection) { case AP_ERROR: @@ -11809,7 +11812,7 @@ namespace Ttcn { } } - void ActualPar::set_gen_class_base_call_postfix() + void ActualPar::set_gen_class_base_call_postfix(FormalPar* formal_par) { switch (selection) { case AP_VALUE: @@ -11824,6 +11827,9 @@ namespace Ttcn { default: break; } + is_base_ctor_param = formal_par != NULL && + formal_par->get_my_parlist()->get_my_def() != NULL && + formal_par->get_my_parlist()->get_my_def()->get_asstype() == Definition::A_CONSTRUCTOR; } void ActualPar::generate_code(expression_struct *expr, bool copy_needed, @@ -11844,18 +11850,49 @@ namespace Ttcn { // constructor call. TODO: Reduce the number of temporaries created. const string& tmp_id = val->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); - expr->preamble = mputprintf(expr->preamble, "%s %s;\n", - val->get_my_governor()->get_genname_value(my_scope).c_str(), - tmp_id_str); + if (is_base_ctor_param) { + expr->preamble = mputprintf(expr->preamble, + "%s %s()\n" + "{\n" + "%s ret_val;\n", + val->get_my_governor()->get_genname_value(my_scope).c_str(), + tmp_id_str, val->get_my_governor()->get_genname_value(my_scope).c_str()); + } + else { + expr->preamble = mputprintf(expr->preamble, "%s %s;\n", + val->get_my_governor()->get_genname_value(my_scope).c_str(), + tmp_id_str); + } expr->preamble = TypeConv::gen_conv_code_refd(expr->preamble, - tmp_id_str, val); - expr_expr = mputstr(expr_expr, tmp_id_str); + is_base_ctor_param ? "ret_val" : tmp_id_str, val); + if (is_base_ctor_param) { + expr->preamble = mputstr(expr->preamble, + "return ret_val;\n" + "}\n\n"); + } + expr_expr = mputprintf(expr_expr, "%s%s", tmp_id_str, is_base_ctor_param ? "()" : ""); } else { expression_struct val_expr; Code::init_expr(&val_expr); val->generate_code_expr(&val_expr); if (val_expr.preamble != NULL) { - expr->preamble = mputstr(expr->preamble, val_expr.preamble); + if (is_base_ctor_param) { + const string& tmp_id = val->get_temporary_id(); + const char *tmp_id_str = tmp_id.c_str(); + expr->preamble = mputprintf(expr->preamble, + "%s %s()\n" + "{\n" + "%s" + "return %s;\n" + "}\n\n", + val->get_my_governor()->get_genname_value(my_scope).c_str(), + tmp_id_str, val_expr.preamble, val_expr.expr); + Free(val_expr.expr); + val_expr.expr = mprintf("%s()", tmp_id_str); + } + else { + expr->preamble = mputstr(expr->preamble, val_expr.preamble); + } } if (val_expr.postamble == NULL) { if (formal_par != NULL && @@ -11899,22 +11936,54 @@ namespace Ttcn { if (use_runtime_2 && TypeConv::needs_conv_refd(temp->get_Template())) { const string& tmp_id = temp->get_Template()->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); - expr->preamble = mputprintf(expr->preamble, "%s %s;\n", - temp->get_Template()->get_my_governor() - ->get_genname_template(my_scope).c_str(), tmp_id_str); + if (is_base_ctor_param) { + expr->preamble = mputprintf(expr->preamble, + "%s %s()\n" + "{\n" + "%s ret_val;\n", + temp->get_Template()->get_my_governor()->get_genname_template(my_scope).c_str(), + tmp_id_str, temp->get_Template()->get_my_governor() + ->get_genname_template(my_scope).c_str()); + } + else { + expr->preamble = mputprintf(expr->preamble, "%s %s;\n", + temp->get_Template()->get_my_governor() + ->get_genname_template(my_scope).c_str(), tmp_id_str); + } expr->preamble = TypeConv::gen_conv_code_refd(expr->preamble, tmp_id_str, temp->get_Template()); // Not incorporated into gen_conv_code() yet. if (gen_restriction_check != TR_NONE) expr->preamble = Template::generate_restriction_check_code( expr->preamble, tmp_id_str, gen_restriction_check); + if (is_base_ctor_param) { + expr->preamble = mputstr(expr->preamble, + "return ret_val;\n" + "}\n\n"); + } expr_expr = mputstr(expr_expr, tmp_id_str); } else { expression_struct temp_expr; Code::init_expr(&temp_expr); temp->generate_code(&temp_expr, gen_restriction_check); if (temp_expr.preamble != NULL) { - expr->preamble = mputstr(expr->preamble, temp_expr.preamble); + if (is_base_ctor_param) { + const string& tmp_id = temp->get_Template()->get_temporary_id(); + const char *tmp_id_str = tmp_id.c_str(); + expr->preamble = mputprintf(expr->preamble, + "%s %s()\n" + "{\n" + "%s" + "return %s;\n" + "}\n\n", + temp->get_Template()->get_my_governor()->get_genname_template(my_scope).c_str(), + tmp_id_str, temp_expr.preamble, temp_expr.expr); + Free(temp_expr.expr); + temp_expr.expr = mprintf("%s()", tmp_id_str); + } + else { + expr->preamble = mputstr(expr->preamble, temp_expr.preamble); + } } if (temp_expr.postamble == NULL) { expr_expr = mputstr(expr_expr, temp_expr.expr); @@ -12298,11 +12367,11 @@ namespace Ttcn { } } - void ActualParList::set_gen_class_base_call_postfix() + void ActualParList::set_gen_class_base_call_postfix(FormalParList* fp_list) { size_t nof_pars = params.size(); for (size_t i = 0; i < nof_pars; i++) { - params[i]->set_gen_class_base_call_postfix(); + params[i]->set_gen_class_base_call_postfix(fp_list != NULL ? fp_list->get_fp_byIndex(i) : NULL); } } diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index 2700fc01d..e0500a1d7 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -90,6 +90,8 @@ namespace Ttcn { /** if this is an actual template parameter of an external function add * runtime checks for out and inout parameters after the call */ template_restriction_t gen_post_restriction_check; + /** True if this is one of the base-constructor call's actual parameters. */ + bool is_base_ctor_param; private: /** Copy constructor */ ActualPar(const ActualPar& p); @@ -99,7 +101,7 @@ namespace Ttcn { /// Constructor for an erroneous object (fallback) ActualPar() : Node(), selection(AP_ERROR), my_scope(0), - gen_restriction_check(TR_NONE), gen_post_restriction_check(TR_NONE) {} + gen_restriction_check(TR_NONE), gen_post_restriction_check(TR_NONE), is_base_ctor_param(false) {} /// Actual par for an in value parameter ActualPar(Value *v); /// Actual par for an in template parameter @@ -131,7 +133,7 @@ namespace Ttcn { void set_code_section(GovernedSimple::code_section_t p_code_section); void set_gen_class_defpar_prefix(); - void set_gen_class_base_call_postfix(); + void set_gen_class_base_call_postfix(FormalPar* formal_par = NULL); /** Generates the C++ equivalent of \a this into \a expr. * Flag \a copy_needed indicates whether to add an extra copy constructor @@ -180,7 +182,7 @@ namespace Ttcn { void chk_class_member(ClassTypeBody* p_class); void set_gen_class_defpar_prefix(); - void set_gen_class_base_call_postfix(); + void set_gen_class_base_call_postfix(FormalParList* fp_list = NULL); /** Generates the C++ equivalent of the actual parameter list without * considering any aliasing between variables and 'in' parameters. */ void generate_code_noalias(expression_struct *expr, FormalParList *p_fpl); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index 16dd95b81..eb62de86e 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -4267,9 +4267,15 @@ namespace Ttcn { if (base_call != NULL) { ActualParList* ap_list = base_call->get_parlist(); if (ap_list != NULL) { - ap_list->set_gen_class_base_call_postfix(); + Def_Constructor* base_ctor = base_class->get_constructor(); + ap_list->set_gen_class_base_call_postfix( + base_ctor != NULL ? base_ctor->get_FormalParList() : NULL); } base_call->generate_code(&base_call_expr); + if (base_call_expr.preamble != NULL) { + local_struct->source.methods = mputstr(local_struct->source.methods, + base_call_expr.preamble); + } } // generate code for the base call first, so the formal parameter list // knows which parameters are used and which aren't diff --git a/regression_test/oop/oop2.ttcn b/regression_test/oop/oop2.ttcn index 34ecdba33..cae8b6031 100644 --- a/regression_test/oop/oop2.ttcn +++ b/regression_test/oop/oop2.ttcn @@ -298,6 +298,37 @@ testcase tc_constructor_param_name_clash() runs on CT { setverdict(pass); } + +type record of integer IntList; + +type class C9 { + create(Rec p1, template IntList p2) { + if (p1 != { num := 3, str := "abc" }) { + setverdict(fail, "p1: ", p1); + } + template IntList p2_exp := { 1, (1 .. 10), ? }; + if (log2str(p2) != log2str(p2_exp)) { + setverdict(fail, "p2: ", p2); + } + } +} + +template integer t_global := (1..10); + +function f_int(IntList p) return integer { + return sizeof(p); +} + +type class C10 extends C9 { + create(): C9( { f_int({ 1, 2, 3 }), "abc" }, { 1, t_global, ? } ) { } +} + +testcase tc_base_call_with_structure_parameter() runs on CT { + var C10 x := C10.create(); // the actual tests are in the constructor + setverdict(pass); +} + + control { execute(tc_constructor_default()); execute(tc_constructor_init()); @@ -307,6 +338,7 @@ control { execute(tc_references_in_default_values()); execute(tc_base_call_with_default_value_parameter()); execute(tc_constructor_param_name_clash()); + execute(tc_base_call_with_structure_parameter()); } } -- GitLab From ffbc229c4b6a4b9fbecb60bdcfac99ec68bb9338 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Wed, 23 Mar 2022 17:50:57 +0100 Subject: [PATCH 10/13] Added missing line to previous change (issue #591) Signed-off-by: Botond Baranyi --- compiler2/ttcn3/AST_ttcn3.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 253c6d727..ba979174e 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -11961,7 +11961,7 @@ namespace Ttcn { "return ret_val;\n" "}\n\n"); } - expr_expr = mputstr(expr_expr, tmp_id_str); + expr_expr = mputprintf(expr_expr, "%s%s", tmp_id_str, is_base_ctor_param ? "()" : ""); } else { expression_struct temp_expr; Code::init_expr(&temp_expr); -- GitLab From 8105324f1508ad0ec434f477d1235caea26f29a8 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Wed, 30 Mar 2022 18:33:48 +0200 Subject: [PATCH 11/13] OOP: updated presence checking operators and object methods (issue #596) Signed-off-by: Botond Baranyi --- compiler2/Type.cc | 19 +++---- compiler2/Type_codegen.cc | 16 +++--- compiler2/main.cc | 3 ++ compiler2/ttcn3/AST_ttcn3.cc | 14 +++-- compiler2/ttcn3/Ttcnstuff.cc | 44 +++++++++++++++ compiler2/ttcn3/Ttcnstuff.hh | 6 +++ core/OOP.hh | 102 +++++++++++++++++++---------------- regression_test/oop/oop.ttcn | 64 ++++++++++++++++++---- 8 files changed, 189 insertions(+), 79 deletions(-) diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 1641dcb5d..3f59a33bc 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -1804,17 +1804,18 @@ namespace Common { return 0; } Ttcn::ClassTypeBody* class_ = t->get_class_type_body(); - bool base_toString = false; + bool is_object_method = false; if (!class_->has_local_ass_withId(id)) { - if (id.get_name() == string("toString")) { - // the 'toString' method is not in the AST, but it is inherited by - // every class from the 'object' class - base_toString = true; + Ttcn::FormalParList* object_method_fplist = + Ttcn::ClassTypeBody::get_object_method_fplist(id.get_name()); + if (object_method_fplist != NULL) { + // the methods of the 'object' class are not in the AST, + // but they are inherited by every class + is_object_method = true; if (!ref->parameters_checked()) { - Ttcn::FormalParList fp_list; // empty formal parameter list Ttcn::ParsedActualParameters* parsed_pars = ref->get_parsed_pars(); Ttcn::ActualParList* ap_list = new Ttcn::ActualParList; - bool is_erroneous = fp_list.fold_named_and_chk(parsed_pars, ap_list); + bool is_erroneous = object_method_fplist->fold_named_and_chk(parsed_pars, ap_list); if (is_erroneous) { delete ap_list; return 0; @@ -1823,7 +1824,7 @@ namespace Common { ap_list->set_my_scope(parsed_pars->get_my_scope()); ref->set_parameter_list(ap_list, NULL); } - t = get_pooltype(T_USTR); + t = Ttcn::ClassTypeBody::get_object_method_return_type(id.get_name()); // todo: set *last_method } else { @@ -1834,7 +1835,7 @@ namespace Common { return 0; } } - if (!base_toString) { + if (!is_object_method) { Assignment* ass = class_->get_local_ass_byId(id); if (!class_->chk_visibility(ass, ref, subrefs->get_my_scope())) { // the method is not visible (the error has already been reported) diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc index 5eece2f0d..649ae034a 100644 --- a/compiler2/Type_codegen.cc +++ b/compiler2/Type_codegen.cc @@ -3172,9 +3172,11 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, const string& tmp_id2 = module->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); const char *tmp_id2_str = tmp_id2.c_str(); + bool next_is_class = next_t->get_type_refd_last()->typetype == T_CLASS; if (t->typetype == T_CLASS) { - expr->expr = mputprintf(expr->expr, "const %s%s %s = %s->%s;\n", + expr->expr = mputprintf(expr->expr, "%s%s%s %s = %s->%s;\n", + next_is_class ? "" : "const ", next_t->get_genname_value(module).c_str(), is_template ? "_template" : "", tmp_id2_str, tmp_generalid_str, id.get_name().c_str()); @@ -3198,8 +3200,8 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, } if (i != nof_refs - 1 || optype == ISCHOSEN) { - expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n", - global_id.c_str(), tmp_id2_str); + expr->expr = mputprintf(expr->expr, "%s = %s.is_%s();\n", + global_id.c_str(), tmp_id2_str, next_is_class ? "present" : "bound"); } if (i == nof_refs - 1) { switch (optype) { @@ -3253,7 +3255,9 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, const string& tmp_id = module->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); - expr->expr = mputprintf(expr->expr, "const %s%s %s = %s->%s(", + bool next_is_class = next_t->get_type_refd_last()->typetype == T_CLASS; + expr->expr = mputprintf(expr->expr, "%s%s%s %s = %s->%s(", + next_is_class ? "" : "const ", next_t->get_genname_value(module).c_str(), is_template ? "_template" : "", tmp_id_str, tmp_generalid_str, id.get_name().c_str()); @@ -3261,8 +3265,8 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, expr->expr = mputstr(expr->expr, ");\n"); if (i != nof_refs - 1 || optype == ISCHOSEN) { - expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n", - global_id.c_str(), tmp_id_str); + expr->expr = mputprintf(expr->expr, "%s = %s.is_%s();\n", + global_id.c_str(), tmp_id_str, next_is_class ? "present" : "bound"); } if (i == nof_refs - 1) { switch (optype) { diff --git a/compiler2/main.cc b/compiler2/main.cc index c191b41fd..794d5087c 100644 --- a/compiler2/main.cc +++ b/compiler2/main.cc @@ -61,6 +61,7 @@ #include "AST.hh" #include "asn1/AST_asn1.hh" #include "ttcn3/AST_ttcn3.hh" +#include "ttcn3/Ttcnstuff.hh" #include "CodeGenHelper.hh" #include "Stopwatch.hh" @@ -1272,6 +1273,8 @@ int main(int argc, char *argv[]) } } + Ttcn::ClassTypeBody::object_method_cleanup(); + if (Kflag) { while (tcov_files != NULL) { tcov_file_list *next_file = tcov_files->next; diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index ba979174e..db942e97c 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -496,16 +496,13 @@ namespace Ttcn { Free(prev_expr); } const Identifier& id = *ref->get_id(); - // 'ass' is null if the 'toString' method from the 'object' class is called + // 'ass' is null if one of the methods from the 'object' class is called Common::Assignment* ass = class_->has_local_ass_withId(id) ? class_->get_local_ass_byId(id) : NULL; expr->expr = mputprintf(expr->expr, "->%s(", id.get_name().c_str()); FormalParList* fp_list = ass != NULL ? ass->get_FormalParList() : - new FormalParList; // the formal parameter list of 'toString' is empty + ClassTypeBody::get_object_method_fplist(id.get_name()); ref->get_actual_par_list()->generate_code_noalias(expr, fp_list); - if (ass == NULL) { - delete fp_list; - } expr->expr = mputc(expr->expr, ')'); type = ass != NULL ? ass->get_Type() : Common::Type::get_pooltype(Common::Type::T_USTR); @@ -1505,9 +1502,10 @@ namespace Ttcn { expression_struct isbound_expr; Code::init_expr(&isbound_expr); + Common::Type* ass_type = ass->get_Type(); isbound_expr.preamble = mputprintf(isbound_expr.preamble, - "boolean %s = %s.is_bound();\n", tmp_generalid_str, - ass_id_str); + "boolean %s = %s.is_%s();\n", tmp_generalid_str, ass_id_str, + ass_type->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS ? "present" : "bound"); namedbool p_optype; if (optype == Value::OPTYPE_ISBOUND) { p_optype = ISBOUND; @@ -1520,7 +1518,7 @@ namespace Ttcn { } else { FATAL_ERROR("AST_ttcn3.cc::generate_code_ispresentboundchosen()"); } - ass->get_Type()->generate_code_ispresentboundchosen(&isbound_expr, &subrefs, my_scope->get_scope_mod_gen(), + ass_type->generate_code_ispresentboundchosen(&isbound_expr, &subrefs, my_scope->get_scope_mod_gen(), tmp_generalid, ass_id2, is_template, p_optype, field); expr->preamble = mputstr(expr->preamble, isbound_expr.preamble); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index eb62de86e..cc737ae0e 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -3066,6 +3066,9 @@ namespace Ttcn { // ===== ClassTypeBody // ================================= + FormalParList* ClassTypeBody::object_toString_fplist = NULL; + FormalParList* ClassTypeBody::object_equals_fplist = NULL; + ClassTypeBody::ClassTypeBody(Common::Identifier* p_class_id, boolean p_external, boolean p_final, boolean p_abstract, boolean p_trait, Types* p_base_types, Reference* p_runs_on_ref, Reference* p_mtc_ref, Reference* p_system_ref, @@ -4511,4 +4514,45 @@ namespace Ttcn { Free(user_info); } + FormalParList* ClassTypeBody::get_object_method_fplist(const string& p_id) + { + if (p_id == string("toString")) { + if (object_toString_fplist == NULL) { + object_toString_fplist = new FormalParList; + } + return object_toString_fplist; + } + else if (p_id == string("equals")) { + if (object_equals_fplist == NULL) { + object_equals_fplist = new FormalParList; + FormalPar* fp = new FormalPar(FormalPar::A_PAR_VAL_IN, new Common::Type(Common::Type::T_CLASS), + new Common::Identifier(Common::Identifier::ID_TTCN, string("obj")), NULL); + object_equals_fplist->add_fp(fp); + } + return object_equals_fplist; + } + else { + return NULL; + } + } + + Common::Type* ClassTypeBody::get_object_method_return_type(const string& p_id) + { + if (p_id == string("toString")) { + return Common::Type::get_pooltype(Common::Type::T_USTR); + } + else if (p_id == string("equals")) { + return Common::Type::get_pooltype(Common::Type::T_BOOL); + } + else { + return NULL; + } + } + + void ClassTypeBody::object_method_cleanup() + { + delete object_toString_fplist; + delete object_equals_fplist; + } + } // namespace Ttcn diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh index 9b5c9c51b..9f29c9fce 100644 --- a/compiler2/ttcn3/Ttcnstuff.hh +++ b/compiler2/ttcn3/Ttcnstuff.hh @@ -783,6 +783,8 @@ class ClassTypeBody : public Common::Scope, public Common::Location { bool checked; bool default_constructor; /// true if the class uses a default constructor map defpar_list; + static FormalParList* object_toString_fplist; + static FormalParList* object_equals_fplist; public: ClassTypeBody(Common::Identifier* p_class_id, boolean p_external, boolean p_final, @@ -832,6 +834,10 @@ public: void generate_code(output_struct* target); void generate_class_skeleton(output_struct* target); + + static FormalParList* get_object_method_fplist(const string& p_id); + static Common::Type* get_object_method_return_type(const string& p_id); + static void object_method_cleanup(); }; } diff --git a/core/OOP.hh b/core/OOP.hh index ecf8ffa5b..239ea48b3 100644 --- a/core/OOP.hh +++ b/core/OOP.hh @@ -17,51 +17,6 @@ #include "Logger.hh" #include -// OBJECT -// ------ - -class CLASS_BASE { - size_t ref_count; - boolean destructor; // true, if the destructor is currently running; - // also makes sure the object is not deleted again when inside the destructor - - CLASS_BASE(const CLASS_BASE&); // copy disabled - CLASS_BASE operator=(const CLASS_BASE&); // assignment disabled - boolean operator==(const CLASS_BASE&); // equality operator disabled -public: - CLASS_BASE(): ref_count(0), destructor(FALSE) {} - virtual ~CLASS_BASE() { - if (ref_count != 0) { - TTCN_error("Internal error: deleting an object with %lu reference(s) left.", ref_count); - } - } - void add_ref() { ++ref_count; } - boolean remove_ref() { - --ref_count; - if (destructor) { - return FALSE; - } - destructor = ref_count == 0; - return destructor; - } -}; - -class OBJECT : public CLASS_BASE { -private: - OBJECT(const OBJECT&); // copy disabled - OBJECT operator=(const OBJECT&); // assignment disabled - boolean operator==(const OBJECT&); // equality operator disabled -public: - OBJECT(): CLASS_BASE() { } - virtual ~OBJECT() { } - virtual void log() const { - TTCN_Logger::log_event_str("object: { }"); - } - virtual UNIVERSAL_CHARSTRING toString() { - return UNIVERSAL_CHARSTRING("Object"); - } - static const char* class_name() { return "object"; } -}; // OBJECT_REF // ---------- @@ -171,6 +126,10 @@ public: TTCN_error("Accessing a null reference."); } + const T* operator*() const { // de-referencing operator (for OBJECT::equals + return ptr; + } + T* operator->() { // de-referencing operator (for methods) if (ptr != NULL) { return ptr; @@ -195,11 +154,11 @@ public: } boolean is_bound() const { - return ptr != NULL; + return TRUE; } boolean is_value() const { - return ptr != NULL; + return TRUE; } boolean is_present() const { @@ -241,6 +200,55 @@ boolean operator!=(null_type, const OBJECT_REF& right_val) { // inequality op return right_val.ptr != NULL; } +// OBJECT +// ------ + +class CLASS_BASE { + size_t ref_count; + boolean destructor; // true, if the destructor is currently running; + // also makes sure the object is not deleted again when inside the destructor + + CLASS_BASE(const CLASS_BASE&); // copy disabled + CLASS_BASE operator=(const CLASS_BASE&); // assignment disabled + boolean operator==(const CLASS_BASE&); // equality operator disabled +public: + CLASS_BASE(): ref_count(0), destructor(FALSE) {} + virtual ~CLASS_BASE() { + if (ref_count != 0) { + TTCN_error("Internal error: deleting an object with %lu reference(s) left.", ref_count); + } + } + void add_ref() { ++ref_count; } + boolean remove_ref() { + --ref_count; + if (destructor) { + return FALSE; + } + destructor = ref_count == 0; + return destructor; + } +}; + +class OBJECT : public CLASS_BASE { +private: + OBJECT(const OBJECT&); // copy disabled + OBJECT operator=(const OBJECT&); // assignment disabled + boolean operator==(const OBJECT&); // equality operator disabled +public: + OBJECT(): CLASS_BASE() { } + virtual ~OBJECT() { } + virtual void log() const { + TTCN_Logger::log_event_str("object: { }"); + } + virtual UNIVERSAL_CHARSTRING toString() { + return UNIVERSAL_CHARSTRING("Object"); + } + virtual BOOLEAN equals(const OBJECT_REF& obj) { + return *obj == this; + } + static const char* class_name() { return "object"; } +}; + // EXCEPTION // --------- diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn index bca21d5a4..cf9812e7b 100644 --- a/regression_test/oop/oop.ttcn +++ b/regression_test/oop/oop.ttcn @@ -351,11 +351,21 @@ testcase tc_this() runs on CT { setverdict(pass); } + +type class Node { + var integer data; + var Node next; + public function get_next() return Node { return next; } + public function f() return integer { return 1; } +} + testcase tc_references() runs on CT { var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0); var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0); var FinalClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *); var BaseClass v_null := null; + var Node v_node := Node.create(2, null); + var FinalClass v_null2 := null; var BaseClass v_ref1; if (v_ref1 != null) { @@ -397,13 +407,13 @@ testcase tc_references() runs on CT { if (not isbound(v_sub)) { setverdict(fail, "#12"); } - if (isbound(v_null)) { + if (not isbound(v_null)) { setverdict(fail, "#13"); } if (not isvalue(v_final)) { setverdict(fail, "#14"); } - if (isvalue(v_null)) { + if (not isvalue(v_null)) { setverdict(fail, "#15"); } if (not ispresent(v_base)) { @@ -416,17 +426,40 @@ testcase tc_references() runs on CT { if (v_base2 != null) { setverdict(fail, "#18"); } + if (ispresent(v_null.get_var_temp())) { + setverdict(fail, "#19"); + } + if (ispresent(v_node.get_next())) { + setverdict(fail, "#20"); + } + if (ispresent(v_node.get_next().f())) { + setverdict(fail, "#21"); + } + if (isbound(v_null.get_var_temp())) { + setverdict(fail, "#22"); + } + if (not isbound(v_node.get_next())) { + setverdict(fail, "#23"); + } + if (isbound(v_node.get_next().f())) { + setverdict(fail, "#24"); + } + if (isvalue(v_null.get_var_temp())) { + setverdict(fail, "#25"); + } + if (not isvalue(v_node.get_next())) { + setverdict(fail, "#26"); + } + if (isvalue(v_node.get_next().f())) { + setverdict(fail, "#27"); + } + if (ischosen(v_null2.get_uni().cs)) { + setverdict(fail, "#28"); + } setverdict(pass); } -type class Node { - var integer data; - var Node next; - public function get_next() return Node { return next; } - public function f() return integer { return 1; } -} - function f_test(in Node p1, inout Node p2, out Node p3, in charstring p1_str, in charstring p2_str) return Node { if (log2str(p1) != p1_str) { @@ -508,6 +541,9 @@ type class Something { public function toString() return universal charstring { return "Something"; } + public function equals(object obj) return boolean { + return true; + } } testcase tc_object() runs on CT { @@ -537,6 +573,16 @@ testcase tc_object() runs on CT { if (log2str(v_node2.get_data()) != "Something" or log2str(v_node2.get_next().get_data()) != "Node") { setverdict(fail, "v_node2: ", v_node2); } + var object v_obj3 := v_obj; + if (not v_obj3.equals(v_obj)) { + setverdict(fail, "v_obj3 is not equal to v_obj"); + } + if (v_obj.equals(v_node)) { + setverdict(fail, "v_obj is equal to v_node"); + } + if (not v_smthn.equals(v_node)) { + setverdict(fail, "overriden 'equals' failed"); + } setverdict(pass); } -- GitLab From 59c307b3537c94c24c60259a70f2bcc9d79c1bd4 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 31 Mar 2022 17:49:04 +0200 Subject: [PATCH 12/13] OOP: added semantic checks for overriding/shadowing object methods (issue #596) Signed-off-by: Botond Baranyi --- compiler2/ttcn3/AST_ttcn3.cc | 31 +++++++++++----- compiler2/ttcn3/AST_ttcn3.hh | 1 + compiler2/ttcn3/Ttcnstuff.cc | 37 +++++++++++++++++++ core/OOP.hh | 2 +- .../Semantic_Analyser/oop/oop_SE.ttcn | 14 +++++++ 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index db942e97c..258b87c7b 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -7168,18 +7168,9 @@ namespace Ttcn { return false; } FormalParList* other_fp_list = p_other->get_FormalParList(); - if (other_fp_list->get_nof_fps() != fp_list->get_nof_fps()) { + if (!fp_list->is_identical(other_fp_list)) { return false; } - for (size_t i = 0; i < fp_list->get_nof_fps(); ++i) { - FormalPar* fp1 = fp_list->get_fp_byIndex(i); - FormalPar* fp2 = other_fp_list->get_fp_byIndex(i); - if (fp1->get_asstype() != fp2->get_asstype() || - !fp1->get_Type()->is_identical(fp2->get_Type()) || - fp1->get_id().get_name() != fp2->get_id().get_name()) { - return false; - } - } if (exceptions != NULL || p_other->exceptions != NULL) { if (exceptions == NULL || p_other->exceptions == NULL) { // one of them has exceptions, the other doesn't @@ -10881,6 +10872,26 @@ namespace Ttcn { || parent_scope->has_ass_withId(p_id); } + bool FormalParList::is_identical(const FormalParList* p_other) + { + if (p_other == NULL) { + FATAL_ERROR("FormalParList::is_identical"); + } + if (p_other->pars_v.size() != pars_v.size()) { + return false; + } + for (size_t i = 0; i < pars_v.size(); ++i) { + FormalPar* fp1 = pars_v[i]; + FormalPar* fp2 = p_other->pars_v[i]; + if (fp1->get_asstype() != fp2->get_asstype() || + !fp1->get_Type()->is_identical(fp2->get_Type()) || + fp1->get_id().get_name() != fp2->get_id().get_name()) { + return false; + } + } + return true; + } + void FormalParList::set_genname(const string& p_prefix) { for (size_t i = 0; i < pars_v.size(); i++) { diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index e0500a1d7..6a735abe8 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -2022,6 +2022,7 @@ namespace Ttcn { bool get_startability(); virtual Common::Assignment *get_ass_bySRef(Common::Ref_simple *p_ref); virtual bool has_ass_withId(const Identifier& p_id); + bool is_identical(const FormalParList* p_other); /** Checks the parameter list, which belongs to definition of type * \a deftype. */ void chk(Definition::asstype_t deftype); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index cc737ae0e..2899e814d 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -3832,6 +3832,43 @@ namespace Ttcn { } } + // check overriding/shadowing of 'object' methods + for (size_t i = 0; i < members->get_nof_asss(); ++i) { + Common::Assignment* def = members->get_ass_byIndex(i, false); + const Common::Identifier& id = def->get_id(); + FormalParList* fp_list = get_object_method_fplist(id.get_name()); + if (fp_list != NULL) { + switch (def->get_asstype()) { + case Common::Assignment::A_FUNCTION_RVAL: + case Common::Assignment::A_EXT_FUNCTION_RVAL: + if (def->get_visibility() == PUBLIC && + fp_list->is_identical(def->get_FormalParList())) { + Def_Function_Base* def_func = dynamic_cast(def); + Def_AbsFunction* def_func_abs = dynamic_cast(def_func); + if (def_func_abs == NULL && + def_func->get_return_type()->is_identical(get_object_method_return_type(id.get_name()))) { + break; // everything is in order + } + } + // otherwise fall through and display the prototype error + case Common::Assignment::A_FUNCTION: + case Common::Assignment::A_FUNCTION_RTEMP: + case Common::Assignment::A_EXT_FUNCTION: + case Common::Assignment::A_EXT_FUNCTION_RTEMP: + // currently all 'object' methods return a value, so these are erroneous by default + def->error("The prototype of method `%s' is not identical " + "to that of the method inherited from the 'object' class", + id.get_dispname().c_str()); + break; + default: + def->error("%s shadows a method inherited from the 'object' class", + def->get_description().c_str()); + name_clash = true; + break; + } + } + } + if (constructor != NULL && trait) { constructor->error("Trait class type `%s' cannot have a constructor", my_def->get_Type()->get_typename().c_str()); diff --git a/core/OOP.hh b/core/OOP.hh index 239ea48b3..d8a9724ff 100644 --- a/core/OOP.hh +++ b/core/OOP.hh @@ -126,7 +126,7 @@ public: TTCN_error("Accessing a null reference."); } - const T* operator*() const { // de-referencing operator (for OBJECT::equals + const T* operator*() const { // de-referencing operator (for OBJECT::equals) return ptr; } diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index c48065cd1..6ea5247b4 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -811,6 +811,20 @@ type class C65 { //^In type definition// out charstring p2) { } //^In parameter// //A constructor cannot have `out' value parameter// } +type class C66 { //^In type definition// + public function toString(in universal charstring prefix) return universal charstring { //The prototype of method `toString' is not identical to that of the method inherited from the 'object' class// + return prefix & "C66"; + } + public function equals(object obj) return integer { //The prototype of method `equals' is not identical to that of the method inherited from the 'object' class// + return -1; + } +} + +type class @abstract C67 { //^In type definition// + private var boolean equals; //variable `@oop_SE.C67.equals' shadows a method inherited from the 'object' class// + public function @abstract toString() return universal charstring; //The prototype of method `toString' is not identical to that of the method inherited from the 'object' class// +} + control { //^In control part// var C11 x := C11.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C11', which runs on component type `@oop_SE.CT_RunsOn'// //Cannot create value of class type `@oop_SE.C11', which has an `mtc' clause, in the control part.// //Cannot create value of class type `@oop_SE.C11', which has a `system' clause, in the control part.// -- GitLab From d086cb37ff89bd14f4c2fa3fd979cc4484883733 Mon Sep 17 00:00:00 2001 From: Botond Baranyi Date: Thu, 5 May 2022 19:04:01 +0200 Subject: [PATCH 13/13] OOP: classes embedded in structures - part 1 (issue #601) Signed-off-by: Botond Baranyi --- compiler2/Type.cc | 59 ++- compiler2/Type.hh | 2 + compiler2/Type_chk.cc | 4 - compiler2/Type_codegen.cc | 59 ++- compiler2/Value.cc | 47 +-- compiler2/datatypes.h | 2 + compiler2/record.c | 320 +++++++++-------- compiler2/record_of.c | 256 ++++++------- compiler2/ttcn3/AST_ttcn3.cc | 9 +- compiler2/ttcn3/Statement.cc | 2 +- compiler2/union.c | 335 +++++++++--------- core/OOP.hh | 51 ++- core/Optional.hh | 24 +- .../Semantic_Analyser/oop/oop_SE.ttcn | 29 +- regression_test/oop/oop.ttcn | 161 +++++++++ 15 files changed, 839 insertions(+), 521 deletions(-) diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 2a0232760..1a403127e 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -2129,18 +2129,36 @@ namespace Common { size_t nof_subrefs = subrefs->get_nof_refs(); if (nof_subrefs < 1) return false; Ttcn::FieldOrArrayRef *last_ref = subrefs->get_ref(nof_subrefs - 1); - if (last_ref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) return false; + if (last_ref->get_type() != Ttcn::FieldOrArrayRef::FIELD_REF) return false; // following the embedded types Type *t=get_type_refd_last(); for (size_t i = 0; i < nof_subrefs - 1; i++) { Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i); - if (ref->get_type() == Ttcn::FieldOrArrayRef::FIELD_REF) - t = t->get_comp_byName(*ref->get_id())->get_type(); - else t = t->get_ofType(); + switch (ref->get_type()) { + case Ttcn::FieldOrArrayRef::FIELD_REF: + t = (t->typetype == T_CLASS) ? + t->get_class_type_body()->get_local_ass_byId(*ref->get_id())->get_Type() : + t->get_comp_byName(*ref->get_id())->get_type(); + break; + case Ttcn::FieldOrArrayRef::ARRAY_REF: + t = t->get_ofType(); + break; + case Ttcn::FieldOrArrayRef::FUNCTION_REF: + if (t->get_class_type_body()->has_local_ass_withId(*ref->get_id())) { + t = t->get_class_type_body()->get_local_ass_byId(*ref->get_id())->get_Type(); + } + else { + t = Ttcn::ClassTypeBody::get_object_method_return_type(ref->get_id()->get_name()); + } + break; + default: + FATAL_ERROR("Type::field_is_optional"); + } t=t->get_type_refd_last(); } // now last_ref refers to a field of t - return t->get_comp_byName(*last_ref->get_id())->get_is_optional(); + return t->typetype != T_CLASS && + t->get_comp_byName(*last_ref->get_id())->get_is_optional(); } bool Type::is_root_basic(){ @@ -5962,6 +5980,37 @@ namespace Common { else return CT_CUSTOM; } + + bool Type::contains_class() + { + // this helps avoid infinite recursions in self-referencing types + if (RecursionTracker::is_happening(this)) { + return false; + } + RecursionTracker tracker(this); + switch (typetype) { + case T_CLASS: + return true; + case T_REFD: + return get_type_refd_last()->contains_class(); + case T_SEQ_T: + case T_SET_T: + case T_CHOICE_T: + for (size_t i = 0; i < u.secho.cfm->get_nof_comps(); ++i) { + if (u.secho.cfm->get_comp_byIndex(i)->get_type()->contains_class()) { + return true; + } + } + return false; + case T_SEQOF: + case T_SETOF: + case T_ARRAY: + return get_ofType()->contains_class(); + default: + return false; + } + } + bool Type::has_ei_withName(const Identifier& p_id) const { switch (typetype) { diff --git a/compiler2/Type.hh b/compiler2/Type.hh index 7f478a147..6b04f426f 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -864,6 +864,8 @@ namespace Common { static MessageEncodingType_t get_enc_type(const string& enc); + bool contains_class(); + private: void chk_Int_A(); void chk_Enum_A(); diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 599a5e47b..a955b96f2 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -3807,10 +3807,6 @@ void Type::chk_embedded(bool default_allowed, const char *error_msg) case T_DEFAULT: if (!default_allowed) error("Default type cannot be %s", error_msg); break; - case T_CLASS: - error("Class type `%s' cannot be %s", t->get_typename().c_str(), - error_msg); - break; default: break; } diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc index 649ae034a..8ea087707 100644 --- a/compiler2/Type_codegen.cc +++ b/compiler2/Type_codegen.cc @@ -253,6 +253,9 @@ void Type::generate_code_embedded_after(output_struct *target) void Type::generate_code_typedescriptor(output_struct *target) { + if (contains_class()) { + return; + } bool force_xer = FALSE; switch (get_type_refd_last()->typetype) { case T_PORT: @@ -1588,8 +1591,13 @@ void Type::generate_code_Choice(output_struct *target) sdef.xerUseUnion = xerattrib->useUnion_; sdef.xerUseTypeAttr = xerattrib->useType_ || xerattrib->useUnion_; } + + sdef.containsClass = contains_class(); + defUnionClass(&sdef, target); - defUnionTemplate(&sdef, target); + if (!sdef.containsClass) { + defUnionTemplate(&sdef, target); + } free_code_ot(sdef.ot); sdef.ot=0; @@ -2262,8 +2270,12 @@ void Type::generate_code_Se(output_struct *target) } } + sdef.containsClass = contains_class(); + defRecordClass(&sdef, target); - defRecordTemplate(&sdef, target); + if (!sdef.containsClass) { + defRecordTemplate(&sdef, target); + } for(size_t i = 0; i < sdef.totalElements; i++) { // free the array but not the strings @@ -2434,12 +2446,16 @@ void Type::generate_code_SeOf(output_struct *target) } } + sofdef.containsClass = contains_class(); + if (optimized_memalloc) { defRecordOfClassMemAllocOptimized(&sofdef, target); } else { defRecordOfClass(&sofdef, target); } - defRecordOfTemplate(&sofdef, target); + if (!sofdef.containsClass) { + defRecordOfTemplate(&sofdef, target); + } if (sofdef.nFollowers) { Free(sofdef.followers); @@ -2478,10 +2494,12 @@ void Type::generate_code_Array(output_struct *target) u.array.dimension->get_value_type(u.array.element_type, my_scope).c_str(), own_name); } - target->header.typedefs = mputprintf(target->header.typedefs, - "typedef %s %s_template;\n", - u.array.dimension->get_template_type(u.array.element_type, my_scope).c_str(), - own_name); + if (!contains_class()) { + target->header.typedefs = mputprintf(target->header.typedefs, + "typedef %s %s_template;\n", + u.array.dimension->get_template_type(u.array.element_type, my_scope).c_str(), + own_name); + } } void Type::generate_code_Fat(output_struct *target) @@ -2971,6 +2989,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, Type *t = this; Type *next_t; bool next_o; // next is optional value + bool next_is_class; size_t nof_refs = subrefs->get_nof_refs(); subrefs->clear_string_element_ref(); char *tmp_generalid_str = mcopystr(external_id.c_str()); @@ -3037,6 +3056,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, next_t = cf->get_type(); next_o = !is_template && cf->get_is_optional(); } + next_is_class = next_t->get_type_refd_last()->typetype == T_CLASS; switch (t->typetype) { case T_CHOICE_A: @@ -3172,7 +3192,6 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, const string& tmp_id2 = module->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); const char *tmp_id2_str = tmp_id2.c_str(); - bool next_is_class = next_t->get_type_refd_last()->typetype == T_CLASS; if (t->typetype == T_CLASS) { expr->expr = mputprintf(expr->expr, "%s%s%s %s = %s->%s;\n", @@ -3192,9 +3211,10 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, // If we would get the const ref of the field immediately then the // value in the const ref would be free-d instantly. expr->expr = mputprintf(expr->expr, - "const %s%s& %s = %s.%s%s();\n", + "%s%s%s%s %s = %s.%s%s();\n", + next_is_class ? "" : "const ", next_t->get_genname_value(module).c_str(), - is_template ? "_template" : "", + is_template ? "_template" : "", next_is_class ? "" : "&", tmp_id2_str, tmp_id_str, t->typetype == T_ANYTYPE ? "AT_" : "", id.get_name().c_str()); } @@ -3255,7 +3275,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, const string& tmp_id = module->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); - bool next_is_class = next_t->get_type_refd_last()->typetype == T_CLASS; + next_is_class = next_t->get_type_refd_last()->typetype == T_CLASS; expr->expr = mputprintf(expr->expr, "%s%s%s %s = %s->%s(", next_is_class ? "" : "const ", next_t->get_genname_value(module).c_str(), @@ -3346,6 +3366,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, } next_t = embedded_type; + next_is_class = next_t->get_type_refd_last()->typetype == T_CLASS; // check the index value Value *index_value = ref->get_val(); @@ -3386,21 +3407,21 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr, } else { if (is_template) { expr->expr = mputprintf(expr->expr, - "const %s& %s = %s[%s];\n", - next_t->get_genname_template(module).c_str(), - tmp_id_str, tmp_generalid_str, + "%s%s%s %s = %s[%s];\n", + next_is_class ? "" : "const ", next_t->get_genname_template(module).c_str(), + next_is_class ? "" : "&", tmp_id_str, tmp_generalid_str, tmp_index_id_str); } else { expr->expr = mputprintf(expr->expr, - "const %s%s& %s = %s[%s];\n", - next_t->get_genname_value(module).c_str(), - is_template?"_template":"", tmp_id_str, tmp_generalid_str, + "%s%s%s%s %s = %s[%s];\n", + next_is_class ? "" : "const ", next_t->get_genname_value(module).c_str(), + is_template?"_template":"", next_is_class ? "" : "&", tmp_id_str, tmp_generalid_str, tmp_index_id_str); } if (i != nof_refs - 1 || optype == ISCHOSEN) { - expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n", - global_id.c_str(), tmp_id_str); + expr->expr = mputprintf(expr->expr, "%s = %s.is_%s();\n", + global_id.c_str(), tmp_id_str, next_is_class ? "present" : "bound"); } if (i == nof_refs - 1) { switch (optype) { diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 7a813b8a0..d3be75355 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -14523,28 +14523,34 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_ISBOUND: { Template::templatetype_t temp = u.expr.ti1->get_Template() ->get_templatetype(); - // TODO: use get_refd_assignment instead to determine whether it's a template? + Ttcn::Reference* reference = NULL; if (temp == Template::SPECIFIC_VALUE) { - Value* specific_value = u.expr.ti1->get_Template() - ->get_specific_value(); + Value* specific_value = u.expr.ti1->get_Template()->get_specific_value(); if (specific_value->get_valuetype() == Value::V_REFD) { - Ttcn::Reference* reference = - dynamic_cast(specific_value->get_reference()); - if (reference != NULL && !reference->has_parameters()) { - reference->generate_code_ispresentboundchosen(expr, false, - u.expr.v_optype, NULL); - break; - } - } - } else if (temp == Template::TEMPLATE_REFD) { - Ttcn::Reference* reference = - dynamic_cast(u.expr.ti1->get_Template() - ->get_reference()); - if (reference != NULL && !reference->has_parameters()) { - reference->generate_code_ispresentboundchosen(expr, true, - u.expr.v_optype, NULL); - break; - } + reference = dynamic_cast(specific_value->get_reference()); + } + } + else if (temp == Template::TEMPLATE_REFD) { + reference = dynamic_cast(u.expr.ti1->get_Template()->get_reference()); + } + if (reference != NULL && !reference->has_parameters()) { + bool is_template = false; + switch (reference->get_refd_assignment()->get_asstype()) { + case Assignment::A_TEMPLATE: + case Assignment::A_VAR_TEMPLATE: + case Assignment::A_MODULEPAR_TEMP: + case Assignment::A_FUNCTION_RTEMP: + case Assignment::A_EXT_FUNCTION_RTEMP: + case Assignment::A_PAR_TEMPL_IN: + case Assignment::A_PAR_TEMPL_INOUT: + case Assignment::A_PAR_TEMPL_OUT: + is_template = true; + break; + default: + break; + } + reference->generate_code_ispresentboundchosen(expr, is_template, u.expr.v_optype, NULL); + break; } } // no break @@ -16813,7 +16819,6 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case V_NAMEDBITS: case V_UNDEF_LOWERID: case V_UNDEF_BLOCK: - case V_TTCN3_NULL: // these values cannot occur during code generation FATAL_ERROR("Value::needs_temp_ref()"); case V_INT: diff --git a/compiler2/datatypes.h b/compiler2/datatypes.h index 000ebdb29..2bbc51e93 100644 --- a/compiler2/datatypes.h +++ b/compiler2/datatypes.h @@ -134,6 +134,7 @@ typedef struct { boolean opentype_outermost; Opentype_t *ot; boolean isOptional; /**< this structure is an optional field in a record/set */ + boolean containsClass; } struct_def; /** record of, set of descriptor for code generation */ @@ -161,6 +162,7 @@ typedef struct { const char *oftypedescrname; /**< Type descr. variable of the elements */ size_t nFollowers; /**< number of optional fields following the record-of */ struct_field *followers; /**< information about following optional siblings */ + boolean containsClass; } struct_of_def; /* for processing enumerated type definitions */ diff --git a/compiler2/record.c b/compiler2/record.c index f054413d7..9b58b03e5 100644 --- a/compiler2/record.c +++ b/compiler2/record.c @@ -54,7 +54,7 @@ static void defRecordTemplate2(const struct_def *sdef, output_struct *output); void defRecordClass(const struct_def *sdef, output_struct *output) { - if (use_runtime_2) defRecordClass2(sdef, output); + if (use_runtime_2 && !sdef->containsClass) defRecordClass2(sdef, output); else defRecordClass1(sdef, output); } @@ -3643,12 +3643,12 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) const char *name = sdef->name, *dispname = sdef->dispname; const char* kind_str = sdef->kind == SET ? "set" : "record"; char *def = NULL, *src = NULL; - boolean ber_needed = sdef->isASN1 && enable_ber(); - boolean raw_needed = sdef->hasRaw && enable_raw(); - boolean text_needed = sdef->hasText && enable_text(); - boolean xer_needed = sdef->hasXer && enable_xer(); - boolean json_needed = sdef->hasJson && enable_json(); - boolean oer_needed = sdef->hasOer && enable_oer(); + boolean ber_needed = sdef->isASN1 && !sdef->containsClass && enable_ber(); + boolean raw_needed = sdef->hasRaw && !sdef->containsClass && enable_raw(); + boolean text_needed = sdef->hasText && !sdef->containsClass && enable_text(); + boolean xer_needed = sdef->hasXer && !sdef->containsClass && enable_xer(); + boolean json_needed = sdef->hasJson && !sdef->containsClass && enable_json(); + boolean oer_needed = sdef->hasOer && !sdef->containsClass && enable_oer(); /* class declaration code */ output->header.class_decls = mputprintf(output->header.class_decls, @@ -3755,10 +3755,15 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) src = mputstr(src, "}\n\n"); - def = mputstr(def, "const TTCN_Typedescriptor_t* get_descriptor() const;\n"); - src = mputprintf(src, - "const TTCN_Typedescriptor_t* %s::get_descriptor() const { return &%s_descr_; }\n", - name, name); + if (!sdef->containsClass) { + def = mputstr(def, "const TTCN_Typedescriptor_t* get_descriptor() const;\n"); + src = mputprintf(src, + "const TTCN_Typedescriptor_t* %s::get_descriptor() const { return &%s_descr_; }\n", + name, name); + } + else if (use_runtime_2) { // need to implement this, cause it's abstract in RT2 + def = mputstr(def, "const TTCN_Typedescriptor_t* get_descriptor() const { return NULL; }\n"); + } /* = operator */ def = mputprintf(def, " %s& operator=(const %s& other_value);\n", name, name); @@ -3922,90 +3927,103 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) } src = mputstr(src, "TTCN_Logger::log_event_str(\" }\");\n}\n\n"); - /* set param function */ - def = mputstr(def, " void set_param(Module_Param& param);\n"); - src = mputprintf - (src, - "void %s::set_param(Module_Param& param)\n{\n" - " param.basic_check(Module_Param::BC_VALUE, \"%s value\");\n" - " switch (param.get_type()) {\n" - " case Module_Param::MP_Value_List:\n" - " if (%lunElements, kind_str, dispname, (unsigned long)sdef->nElements); - - for (i = 0; i < sdef->nElements; ++i) { - src = mputprintf(src, - " if (param.get_size()>%lu && param.get_elem(%lu)->get_type()!=Module_Param::MP_NotUsed) %s().set_param(*param.get_elem(%lu));\n", - (unsigned long)i, (unsigned long)i, sdef->elements[i].name, (unsigned long)i); - } - src = mputstr(src, - " break;\n" - " case Module_Param::MP_Assignment_List: {\n" - " Vector value_used(param.get_size());\n" - " value_used.resize(param.get_size(), FALSE);\n"); - for (i = 0; i < sdef->nElements; ++i) { - src = mputprintf(src, - " for (size_t val_idx=0; val_idxget_id()->get_name(), \"%s\")) {\n" - " if (curr_param->get_type()!=Module_Param::MP_NotUsed) {\n" - " %s().set_param(*curr_param);\n" - " }\n" - " value_used[val_idx]=TRUE;\n" - " }\n" - " }\n" - , sdef->elements[i].dispname, sdef->elements[i].name); - } - src = mputprintf(src, - " for (size_t val_idx=0; val_idxerror(\"Non existent field name in type %s: %%s\", curr_param->get_id()->get_name());\n" - " break;\n" - " }\n" - " } break;\n" - " default:\n" - " param.type_error(\"%s value\", \"%s\");\n" - " }\n" - "}\n\n", dispname, kind_str, dispname); - - /* set implicit omit function, recursive */ - def = mputstr(def, " void set_implicit_omit();\n"); - src = mputprintf(src, "void %s::set_implicit_omit()\n{\n", name); - for (i = 0; i < sdef->nElements; i++) { - if (sdef->elements[i].isOptional) { + if (!sdef->containsClass) { + /* set param function */ + def = mputstr(def, " void set_param(Module_Param& param);\n"); + src = mputprintf + (src, + "void %s::set_param(Module_Param& param)\n{\n" + " param.basic_check(Module_Param::BC_VALUE, \"%s value\");\n" + " switch (param.get_type()) {\n" + " case Module_Param::MP_Value_List:\n" + " if (%lunElements, kind_str, dispname, (unsigned long)sdef->nElements); + + for (i = 0; i < sdef->nElements; ++i) { src = mputprintf(src, - "if (!%s().is_bound()) %s() = OMIT_VALUE;\n" - "else %s().set_implicit_omit();\n", - sdef->elements[i].name, sdef->elements[i].name, sdef->elements[i].name); - } else { + " if (param.get_size()>%lu && param.get_elem(%lu)->get_type()!=Module_Param::MP_NotUsed) %s().set_param(*param.get_elem(%lu));\n", + (unsigned long)i, (unsigned long)i, sdef->elements[i].name, (unsigned long)i); + } + src = mputstr(src, + " break;\n" + " case Module_Param::MP_Assignment_List: {\n" + " Vector value_used(param.get_size());\n" + " value_used.resize(param.get_size(), FALSE);\n"); + for (i = 0; i < sdef->nElements; ++i) { src = mputprintf(src, - "if (%s().is_bound()) %s().set_implicit_omit();\n", - sdef->elements[i].name, sdef->elements[i].name); + " for (size_t val_idx=0; val_idxget_id()->get_name(), \"%s\")) {\n" + " if (curr_param->get_type()!=Module_Param::MP_NotUsed) {\n" + " %s().set_param(*curr_param);\n" + " }\n" + " value_used[val_idx]=TRUE;\n" + " }\n" + " }\n" + , sdef->elements[i].dispname, sdef->elements[i].name); } - } - src = mputstr(src, "}\n\n"); + src = mputprintf(src, + " for (size_t val_idx=0; val_idxerror(\"Non existent field name in type %s: %%s\", curr_param->get_id()->get_name());\n" + " break;\n" + " }\n" + " } break;\n" + " default:\n" + " param.type_error(\"%s value\", \"%s\");\n" + " }\n" + "}\n\n", dispname, kind_str, dispname); + + /* set implicit omit function, recursive */ + def = mputstr(def, " void set_implicit_omit();\n"); + src = mputprintf(src, "void %s::set_implicit_omit()\n{\n", name); + for (i = 0; i < sdef->nElements; i++) { + if (sdef->elements[i].isOptional) { + src = mputprintf(src, + "if (!%s().is_bound()) %s() = OMIT_VALUE;\n" + "else %s().set_implicit_omit();\n", + sdef->elements[i].name, sdef->elements[i].name, sdef->elements[i].name); + } else { + src = mputprintf(src, + "if (%s().is_bound()) %s().set_implicit_omit();\n", + sdef->elements[i].name, sdef->elements[i].name); + } + } + src = mputstr(src, "}\n\n"); - /* text encoder function */ - def = mputstr(def, " void encode_text(Text_Buf& text_buf) const;\n"); - src = mputprintf(src,"void %s::encode_text(Text_Buf& text_buf) const\n{\n", - name); - for (i = 0; i < sdef->nElements; i++) { - src = mputprintf(src, "field_%s.encode_text(text_buf);\n", - sdef->elements[i].name); - } - src = mputstr(src, "}\n\n"); + /* text encoder function */ + def = mputstr(def, " void encode_text(Text_Buf& text_buf) const;\n"); + src = mputprintf(src,"void %s::encode_text(Text_Buf& text_buf) const\n{\n", + name); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, "field_%s.encode_text(text_buf);\n", + sdef->elements[i].name); + } + src = mputstr(src, "}\n\n"); - /* text decoder function */ - def = mputstr(def, " void decode_text(Text_Buf& text_buf);\n"); - src = mputprintf(src, "void %s::decode_text(Text_Buf& text_buf)\n{\n", - name); - for (i = 0; i < sdef->nElements; i++) { - src = mputprintf(src, "field_%s.decode_text(text_buf);\n", - sdef->elements[i].name); + /* text decoder function */ + def = mputstr(def, " void decode_text(Text_Buf& text_buf);\n"); + src = mputprintf(src, "void %s::decode_text(Text_Buf& text_buf)\n{\n", + name); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, "field_%s.decode_text(text_buf);\n", + sdef->elements[i].name); + } + src = mputstr(src, "}\n\n"); + } + else if (use_runtime_2) { + // implement abstract functions inherited by Base_Type (these are never called) + def = mputstr(def, + " void set_param(Module_Param&) { }\n" + " Module_Param* get_param(Module_Param_Name&) const { return NULL; }\n" + " void encode_text(Text_Buf&) const { }\n" + " void decode_text(Text_Buf&) { }\n" + " boolean is_equal(const Base_Type*) const { return FALSE; }\n" + " void set_value(const Base_Type*) { }\n" + " Base_Type* clone() const { return NULL; }\n\n"); } - src = mputstr(src, "}\n\n"); /* The common "classname::encode()" and "classname::decode()" functions */ if(ber_needed || raw_needed || text_needed || xer_needed || json_needed @@ -6483,68 +6501,70 @@ void defRecordTemplate1(const struct_def *sdef, output_struct *output) "}\n" "}\n\n"); - /*encode_text function*/ - def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); - src = mputprintf(src, - "void %s_template::encode_text(Text_Buf& text_buf) const\n" - "{\n" - "encode_text_base(text_buf);\n" - "switch (template_selection) {\n" - "case SPECIFIC_VALUE:\n", name); - for (i = 0; i < sdef->nElements; i++) { - src = mputprintf(src, "single_value->field_%s.encode_text(text_buf);\n", - sdef->elements[i].name); - } - src = mputprintf(src, - "case OMIT_VALUE:\n" - "case ANY_VALUE:\n" - "case ANY_OR_OMIT:\n" - "break;\n" - "case VALUE_LIST:\n" - "case COMPLEMENTED_LIST:\n" - "text_buf.push_int(value_list.n_values);\n" - "for (unsigned int list_count = 0; list_count < value_list.n_values; " - "list_count++)\n" - "value_list.list_value[list_count].encode_text(text_buf);\n" - "break;\n" - "default:\n" - "TTCN_error(\"Text encoder: Encoding an uninitialized/unsupported " - "template of type %s.\");\n" - "}\n" - "}\n\n", dispname); - - /*decode_text function*/ - def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); - src = mputprintf(src, - "void %s_template::decode_text(Text_Buf& text_buf)\n" - "{\n" - "clean_up();\n" - "decode_text_base(text_buf);\n" - "switch (template_selection) {\n" - "case SPECIFIC_VALUE:\n" - "single_value = new single_value_struct;\n", name); - for (i = 0; i < sdef->nElements; i++) { - src = mputprintf(src, "single_value->field_%s.decode_text(text_buf);\n", - sdef->elements[i].name); + if (!sdef->containsClass) { + /*encode_text function*/ + def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); + src = mputprintf(src, + "void %s_template::encode_text(Text_Buf& text_buf) const\n" + "{\n" + "encode_text_base(text_buf);\n" + "switch (template_selection) {\n" + "case SPECIFIC_VALUE:\n", name); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, "single_value->field_%s.encode_text(text_buf);\n", + sdef->elements[i].name); + } + src = mputprintf(src, + "case OMIT_VALUE:\n" + "case ANY_VALUE:\n" + "case ANY_OR_OMIT:\n" + "break;\n" + "case VALUE_LIST:\n" + "case COMPLEMENTED_LIST:\n" + "text_buf.push_int(value_list.n_values);\n" + "for (unsigned int list_count = 0; list_count < value_list.n_values; " + "list_count++)\n" + "value_list.list_value[list_count].encode_text(text_buf);\n" + "break;\n" + "default:\n" + "TTCN_error(\"Text encoder: Encoding an uninitialized/unsupported " + "template of type %s.\");\n" + "}\n" + "}\n\n", dispname); + + /*decode_text function*/ + def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); + src = mputprintf(src, + "void %s_template::decode_text(Text_Buf& text_buf)\n" + "{\n" + "clean_up();\n" + "decode_text_base(text_buf);\n" + "switch (template_selection) {\n" + "case SPECIFIC_VALUE:\n" + "single_value = new single_value_struct;\n", name); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, "single_value->field_%s.decode_text(text_buf);\n", + sdef->elements[i].name); + } + src = mputprintf(src, + "case OMIT_VALUE:\n" + "case ANY_VALUE:\n" + "case ANY_OR_OMIT:\n" + "break;\n" + "case VALUE_LIST:\n" + "case COMPLEMENTED_LIST:\n" + "value_list.n_values = text_buf.pull_int().get_val();\n" + "value_list.list_value = new %s_template[value_list.n_values];\n" + "for (unsigned int list_count = 0; list_count < value_list.n_values; " + "list_count++)\n" + "value_list.list_value[list_count].decode_text(text_buf);\n" + "break;\n" + "default:\n" + "TTCN_error(\"Text decoder: An unknown/unsupported selection was " + "received in a template of type %s.\");\n" + "}\n" + "}\n\n", name, dispname); } - src = mputprintf(src, - "case OMIT_VALUE:\n" - "case ANY_VALUE:\n" - "case ANY_OR_OMIT:\n" - "break;\n" - "case VALUE_LIST:\n" - "case COMPLEMENTED_LIST:\n" - "value_list.n_values = text_buf.pull_int().get_val();\n" - "value_list.list_value = new %s_template[value_list.n_values];\n" - "for (unsigned int list_count = 0; list_count < value_list.n_values; " - "list_count++)\n" - "value_list.list_value[list_count].decode_text(text_buf);\n" - "break;\n" - "default:\n" - "TTCN_error(\"Text decoder: An unknown/unsupported selection was " - "received in a template of type %s.\");\n" - "}\n" - "}\n\n", name, dispname); /* set_param() */ def = mputstr(def, "void set_param(Module_Param& param);\n"); diff --git a/compiler2/record_of.c b/compiler2/record_of.c index 1a8a6fe04..86ea63ee8 100644 --- a/compiler2/record_of.c +++ b/compiler2/record_of.c @@ -38,7 +38,7 @@ static void defRecordOfTemplate2(const struct_of_def *sdef, output_struct *outpu void defRecordOfClass(const struct_of_def *sdef, output_struct *output) { - if (use_runtime_2) defRecordOfClass2(sdef, output); + if (use_runtime_2 && !sdef->containsClass) defRecordOfClass2(sdef, output); else defRecordOfClass1(sdef, output); } @@ -55,12 +55,12 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) char *def = NULL, *src = NULL; const char *name = sdef->name, *dispname = sdef->dispname; const char *type = sdef->type; - boolean ber_needed = force_gen_seof || (sdef->isASN1 && enable_ber()); - boolean raw_needed = force_gen_seof || (sdef->hasRaw && enable_raw()); - boolean text_needed = force_gen_seof || (sdef->hasText && enable_text()); - boolean xer_needed = force_gen_seof || (sdef->hasXer && enable_xer()); - boolean json_needed = force_gen_seof || (sdef->hasJson && enable_json()); - boolean oer_needed = force_gen_seof || (sdef->hasOer && enable_oer()); + boolean ber_needed = force_gen_seof || (sdef->isASN1 && !sdef->containsClass && enable_ber()); + boolean raw_needed = force_gen_seof || (sdef->hasRaw && !sdef->containsClass && enable_raw()); + boolean text_needed = force_gen_seof || (sdef->hasText && !sdef->containsClass && enable_text()); + boolean xer_needed = force_gen_seof || (sdef->hasXer && !sdef->containsClass && enable_xer()); + boolean json_needed = force_gen_seof || (sdef->hasJson && !sdef->containsClass && enable_json()); + boolean oer_needed = force_gen_seof || (sdef->hasOer && !sdef->containsClass && enable_oer()); /* Class definition and private data members */ def = mputprintf(def, @@ -467,16 +467,18 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "}\n" "return ret_val;\n" "}\n\n", name, name, name, dispname, dispname, dispname, name, type, type, type); - def = mputprintf(def, - "%s replace(int index, int len, const %s_template& repl) const;\n\n", - name, name); - src = mputprintf(src, - "%s %s::replace(int index, int len, const %s_template& repl) const\n" - "{\n" - "if (!repl.is_value()) TTCN_error(\"The fourth argument of function " - "replace() is a template with non-specific value.\");\n" - "return replace(index, len, repl.valueof());\n" - "}\n\n", name, name, name); + if (!sdef->containsClass) { + def = mputprintf(def, + "%s replace(int index, int len, const %s_template& repl) const;\n\n", + name, name); + src = mputprintf(src, + "%s %s::replace(int index, int len, const %s_template& repl) const\n" + "{\n" + "if (!repl.is_value()) TTCN_error(\"The fourth argument of function " + "replace() is a template with non-specific value.\");\n" + "return replace(index, len, repl.valueof());\n" + "}\n\n", name, name, name); + } /* set_size function */ def = mputstr(def, "void set_size(int new_size);\n"); @@ -600,111 +602,125 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) "}\n" "}\n\n", name); - /* set_param function */ - def = mputstr(def, "void set_param(Module_Param& param);\n"); - src = mputprintf(src, - "void %s::set_param(Module_Param& param)\n" - "{\n" - " param.basic_check(Module_Param::BC_VALUE|Module_Param::BC_LIST, \"%s value\");\n" - " switch (param.get_operation_type()) {\n" - " case Module_Param::OT_ASSIGN:\n" - " if (param.get_type()==Module_Param::MP_Value_List && param.get_size()==0) {\n" - " *this = NULL_VALUE;\n" - " return;\n" - " }\n" - " switch (param.get_type()) {\n" - " case Module_Param::MP_Value_List:\n" - " set_size(param.get_size());\n" - " for (size_t i=0; iget_type()!=Module_Param::MP_NotUsed) {\n" - " (*this)[i].set_param(*curr);\n" - " if (!(*this)[i].is_bound()) {\n" - " delete val_ptr->value_elements[i];\n" - " val_ptr->value_elements[i] = NULL;\n" - " }\n" - " }\n" - " }\n" - " break;\n" - " case Module_Param::MP_Indexed_List:\n" - " for (size_t i=0; iget_id()->get_index()].set_param(*curr);\n" - " if (!(*this)[curr->get_id()->get_index()].is_bound()) {\n" - " delete val_ptr->value_elements[curr->get_id()->get_index()];\n" - " val_ptr->value_elements[curr->get_id()->get_index()] = NULL;\n" - " }\n" - " }\n" - " break;\n" - " default:\n" - " param.type_error(\"%s value\", \"%s\");\n" - " }\n" - " break;\n" - " case Module_Param::OT_CONCAT:\n" - " switch (param.get_type()) {\n" - " case Module_Param::MP_Value_List: {\n" - " if (!is_bound()) *this = NULL_VALUE;\n" - " int start_idx = lengthof();\n" - " for (size_t i=0; iget_type()!=Module_Param::MP_NotUsed)) {\n" - " (*this)[start_idx+(int)i].set_param(*curr);\n" - " }\n" - " }\n" - " } break;\n" - " case Module_Param::MP_Indexed_List:\n" - " param.error(\"Cannot concatenate an indexed value list\");\n" - " break;\n" - " default:\n" - " param.type_error(\"%s value\", \"%s\");\n" - " }\n" - " break;\n" - " default:\n" - " TTCN_error(\"Internal error: Unknown operation type.\");\n" - " }\n" - "}\n\n", name, sdef->kind == RECORD_OF ? "record of" : "set of", - sdef->kind == RECORD_OF ? "record of" : "set of", dispname, - sdef->kind == RECORD_OF ? "record of" : "set of", dispname); - - /* set implicit omit function, recursive */ - def = mputstr(def, " void set_implicit_omit();\n"); - src = mputprintf(src, - "void %s::set_implicit_omit()\n{\n" - "if (val_ptr == NULL) return;\n" - "for (int i = 0; i < val_ptr->n_elements; i++) {\n" - "if (val_ptr->value_elements[i] != NULL) val_ptr->value_elements[i]->set_implicit_omit();\n" - "}\n}\n\n", name); + if (!sdef->containsClass) { + /* set_param function */ + def = mputstr(def, "void set_param(Module_Param& param);\n"); + src = mputprintf(src, + "void %s::set_param(Module_Param& param)\n" + "{\n" + " param.basic_check(Module_Param::BC_VALUE|Module_Param::BC_LIST, \"%s value\");\n" + " switch (param.get_operation_type()) {\n" + " case Module_Param::OT_ASSIGN:\n" + " if (param.get_type()==Module_Param::MP_Value_List && param.get_size()==0) {\n" + " *this = NULL_VALUE;\n" + " return;\n" + " }\n" + " switch (param.get_type()) {\n" + " case Module_Param::MP_Value_List:\n" + " set_size(param.get_size());\n" + " for (size_t i=0; iget_type()!=Module_Param::MP_NotUsed) {\n" + " (*this)[i].set_param(*curr);\n" + " if (!(*this)[i].is_bound()) {\n" + " delete val_ptr->value_elements[i];\n" + " val_ptr->value_elements[i] = NULL;\n" + " }\n" + " }\n" + " }\n" + " break;\n" + " case Module_Param::MP_Indexed_List:\n" + " for (size_t i=0; iget_id()->get_index()].set_param(*curr);\n" + " if (!(*this)[curr->get_id()->get_index()].is_bound()) {\n" + " delete val_ptr->value_elements[curr->get_id()->get_index()];\n" + " val_ptr->value_elements[curr->get_id()->get_index()] = NULL;\n" + " }\n" + " }\n" + " break;\n" + " default:\n" + " param.type_error(\"%s value\", \"%s\");\n" + " }\n" + " break;\n" + " case Module_Param::OT_CONCAT:\n" + " switch (param.get_type()) {\n" + " case Module_Param::MP_Value_List: {\n" + " if (!is_bound()) *this = NULL_VALUE;\n" + " int start_idx = lengthof();\n" + " for (size_t i=0; iget_type()!=Module_Param::MP_NotUsed)) {\n" + " (*this)[start_idx+(int)i].set_param(*curr);\n" + " }\n" + " }\n" + " } break;\n" + " case Module_Param::MP_Indexed_List:\n" + " param.error(\"Cannot concatenate an indexed value list\");\n" + " break;\n" + " default:\n" + " param.type_error(\"%s value\", \"%s\");\n" + " }\n" + " break;\n" + " default:\n" + " TTCN_error(\"Internal error: Unknown operation type.\");\n" + " }\n" + "}\n\n", name, sdef->kind == RECORD_OF ? "record of" : "set of", + sdef->kind == RECORD_OF ? "record of" : "set of", dispname, + sdef->kind == RECORD_OF ? "record of" : "set of", dispname); - /* encoding / decoding functions */ - def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); - src = mputprintf(src, - "void %s::encode_text(Text_Buf& text_buf) const\n" - "{\n" - "if (val_ptr == NULL) " - "TTCN_error(\"Text encoder: Encoding an unbound value of type %s.\");\n" - "text_buf.push_int(val_ptr->n_elements);\n" - "for (int elem_count = 0; elem_count < val_ptr->n_elements; " - "elem_count++)\n" - "(*this)[elem_count].encode_text(text_buf);\n" - "}\n\n", name, dispname); + /* set implicit omit function, recursive */ + def = mputstr(def, " void set_implicit_omit();\n"); + src = mputprintf(src, + "void %s::set_implicit_omit()\n{\n" + "if (val_ptr == NULL) return;\n" + "for (int i = 0; i < val_ptr->n_elements; i++) {\n" + "if (val_ptr->value_elements[i] != NULL) val_ptr->value_elements[i]->set_implicit_omit();\n" + "}\n}\n\n", name); + + /* encoding / decoding functions */ + def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); + src = mputprintf(src, + "void %s::encode_text(Text_Buf& text_buf) const\n" + "{\n" + "if (val_ptr == NULL) " + "TTCN_error(\"Text encoder: Encoding an unbound value of type %s.\");\n" + "text_buf.push_int(val_ptr->n_elements);\n" + "for (int elem_count = 0; elem_count < val_ptr->n_elements; " + "elem_count++)\n" + "(*this)[elem_count].encode_text(text_buf);\n" + "}\n\n", name, dispname); - def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); - src = mputprintf(src, - "void %s::decode_text(Text_Buf& text_buf)\n" - "{\n" - "clean_up();\n" - "val_ptr = new recordof_setof_struct;\n" - "val_ptr->ref_count = 1;\n" - "val_ptr->n_elements = text_buf.pull_int().get_val();\n" - "if (val_ptr->n_elements < 0) TTCN_error(\"Text decoder: Negative size " - "was received for a value of type %s.\");\n" - "val_ptr->value_elements = (%s**)allocate_pointers(val_ptr->n_elements);\n" - "for (int elem_count = 0; elem_count < val_ptr->n_elements; " - "elem_count++) {\n" - "val_ptr->value_elements[elem_count] = new %s;\n" - "val_ptr->value_elements[elem_count]->decode_text(text_buf);\n" - "}\n" - "}\n\n", name, dispname, type, type); + def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); + src = mputprintf(src, + "void %s::decode_text(Text_Buf& text_buf)\n" + "{\n" + "clean_up();\n" + "val_ptr = new recordof_setof_struct;\n" + "val_ptr->ref_count = 1;\n" + "val_ptr->n_elements = text_buf.pull_int().get_val();\n" + "if (val_ptr->n_elements < 0) TTCN_error(\"Text decoder: Negative size " + "was received for a value of type %s.\");\n" + "val_ptr->value_elements = (%s**)allocate_pointers(val_ptr->n_elements);\n" + "for (int elem_count = 0; elem_count < val_ptr->n_elements; " + "elem_count++) {\n" + "val_ptr->value_elements[elem_count] = new %s;\n" + "val_ptr->value_elements[elem_count]->decode_text(text_buf);\n" + "}\n" + "}\n\n", name, dispname, type, type); + } + else if (use_runtime_2) { + // implement abstract functions inherited by Base_Type (these are never called) + def = mputstr(def, + " void set_param(Module_Param&) { }\n" + " Module_Param* get_param(Module_Param_Name&) const { return NULL; }\n" + " void encode_text(Text_Buf&) const { }\n" + " void decode_text(Text_Buf&) { }\n" + " boolean is_equal(const Base_Type*) const { return FALSE; }\n" + " void set_value(const Base_Type*) { }\n" + " Base_Type* clone() const { return NULL; }\n" + " const TTCN_Typedescriptor_t* get_descriptor() const { return NULL; }\n\n"); + } if(ber_needed || raw_needed || text_needed || xer_needed || json_needed || oer_needed) { diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index ce7c28c9a..22c2fb691 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -1230,7 +1230,7 @@ namespace Ttcn { FormalParList* fp_list = subref->get_formal_par_list(); for (size_t j = 0; j < ap_list->get_nof_pars(); ++j) { if (!ap_list->get_par(j)->has_single_expr( - fp_list != NULL ? fp_list->get_fp_byIndex(i) : NULL)) { + fp_list != NULL ? fp_list->get_fp_byIndex(j) : NULL)) { return false; } } @@ -4080,8 +4080,11 @@ namespace Ttcn { continue; } field_name = tref->get_id()->get_ttcnname(); - if (oop_features && field_name == string("object")) { - ea.error("Class type `object' cannot be added to the anytype"); + bool is_object = field_name == string("object"); + if (oop_features && (is_object || + t->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS)) { + ea.error("Class type `%s' cannot be added to the anytype", + is_object ? "object" : t->get_typename().c_str()); delete t; continue; } diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 5159ddd34..bcd15fb1d 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -3615,7 +3615,7 @@ namespace Ttcn { case Common::Assignment::A_PAR_VAL_IN: case Common::Assignment::A_PAR_VAL_INOUT: case Common::Assignment::A_PAR_VAL_OUT: - if (t_ass->get_Type()->get_type_refd_last()->get_typetype() != Common::Type::T_CLASS) { + if (!t_ass->get_Type()->contains_class()) { ref_pard->error("Reference to a function or altstep was expected " "instead of %s, which cannot be invoked", t_ass->get_description().c_str()); diff --git a/compiler2/union.c b/compiler2/union.c index 8ee0cbf2b..c843a07c6 100644 --- a/compiler2/union.c +++ b/compiler2/union.c @@ -77,12 +77,12 @@ void defUnionClass(struct_def const *sdef, output_struct *output) * for the anytype, otherwise the generated "INTEGER()" will look like * a constructor, upsetting the C++ compiler. AT_INTEGER() is ok. */ char *def = NULL, *src = NULL; - boolean ber_needed = sdef->isASN1 && enable_ber(); - boolean raw_needed = sdef->hasRaw && enable_raw(); - boolean text_needed = sdef->hasText && enable_text(); - boolean xer_needed = sdef->hasXer && enable_xer(); - boolean json_needed = sdef->hasJson && enable_json(); - boolean oer_needed = sdef->hasOer && enable_oer(); + boolean ber_needed = sdef->isASN1&& !sdef->containsClass && enable_ber(); + boolean raw_needed = sdef->hasRaw&& !sdef->containsClass && enable_raw(); + boolean text_needed = sdef->hasText&& !sdef->containsClass && enable_text(); + boolean xer_needed = sdef->hasXer&& !sdef->containsClass && enable_xer(); + boolean json_needed = sdef->hasJson&& !sdef->containsClass && enable_json(); + boolean oer_needed = sdef->hasOer&& !sdef->containsClass && enable_oer(); char *selection_type, *unbound_value, *selection_prefix; selection_type = mcopystr("union_selection_type"); @@ -312,7 +312,7 @@ void defUnionClass(struct_def const *sdef, output_struct *output) "union_selection = %s;\n" "}\n\n", unbound_value); - if (use_runtime_2) { + if (use_runtime_2 && !sdef->containsClass) { def = mputstr(def, "boolean is_equal(const Base_Type* other_value) const;\n" "void set_value(const Base_Type* other_value);\n" @@ -332,7 +332,8 @@ void defUnionClass(struct_def const *sdef, output_struct *output) name, name, name, name, name, name); - } else { + } + if (!use_runtime_2) { def = mputstr(def, "inline boolean is_present() const { return is_bound(); }\n"); } @@ -358,173 +359,187 @@ void defUnionClass(struct_def const *sdef, output_struct *output) } src = mputstr(src, "}\n\n"); - /* set_param function */ - def = mputstr(def, "void set_param(Module_Param& param);\n"); - src = mputprintf(src, "void %s::set_param(Module_Param& param)\n" - "{\n", name); - if (use_runtime_2) { - src = mputprintf(src, - " if (dynamic_cast(param.get_id()) != NULL &&\n" - " param.get_id()->next_name()) {\n" - // Haven't reached the end of the module parameter name - // => the name refers to one of the fields, not to the whole union - " char* param_field = param.get_id()->get_current_name();\n" - " if (param_field[0] >= '0' && param_field[0] <= '9') {\n" - " param.error(\"Unexpected array index in module parameter, expected a valid field\"\n" - " \" name for union type `%s'\");\n" - " }\n" - " ", dispname); - for (i = 0; i < sdef->nElements; i++) { + if (!sdef->containsClass) { + /* set_param function */ + def = mputstr(def, "void set_param(Module_Param& param);\n"); + src = mputprintf(src, "void %s::set_param(Module_Param& param)\n" + "{\n", name); + if (use_runtime_2) { src = mputprintf(src, - "if (strcmp(\"%s\", param_field) == 0) {\n" - " %s%s().set_param(param);\n" - " return;\n" - " } else ", - sdef->elements[i].dispname, at_field, sdef->elements[i].name); - } - src = mputprintf(src, - "param.error(\"Field `%%s' not found in union type `%s'\", param_field);\n" - " }\n", dispname); - } - src = mputstr(src, - " param.basic_check(Module_Param::BC_VALUE, \"union value\");\n" - " Module_Param_Ptr m_p = ¶m;\n"); - if (use_runtime_2) { - src = mputstr(src, - " if (param.get_type() == Module_Param::MP_Reference) {\n" - " m_p = param.get_referenced_param();\n" - " }\n"); - } - src = mputstr(src, - " if (m_p->get_type()==Module_Param::MP_Value_List && m_p->get_size()==0) return;\n" - " if (m_p->get_type()!=Module_Param::MP_Assignment_List) {\n" - " param.error(\"union value with field name was expected\");\n" - " }\n" - " Module_Param* mp_last = m_p->get_elem(m_p->get_size()-1);\n" - " char* last_name = mp_last->get_id()->get_name();\n"); - - for (i = 0; i < sdef->nElements; i++) { - src = mputprintf(src, - " if (!strcmp(last_name, \"%s\")) {\n" - " %s%s().set_param(*mp_last);\n" - " if (!%s%s().is_bound()) " - , sdef->elements[i].dispname, at_field, sdef->elements[i].name - , at_field, sdef->elements[i].name); - if (legacy_unbound_union_fields) { + " if (dynamic_cast(param.get_id()) != NULL &&\n" + " param.get_id()->next_name()) {\n" + // Haven't reached the end of the module parameter name + // => the name refers to one of the fields, not to the whole union + " char* param_field = param.get_id()->get_current_name();\n" + " if (param_field[0] >= '0' && param_field[0] <= '9') {\n" + " param.error(\"Unexpected array index in module parameter, expected a valid field\"\n" + " \" name for union type `%s'\");\n" + " }\n" + " ", dispname); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, + "if (strcmp(\"%s\", param_field) == 0) {\n" + " %s%s().set_param(param);\n" + " return;\n" + " } else ", + sdef->elements[i].dispname, at_field, sdef->elements[i].name); + } src = mputprintf(src, - "TTCN_warning(\"Alternative '%s' was selected for union of type '%s', " - "but its value is unbound\");\n" - , sdef->elements[i].dispname, sdef->dispname); + "param.error(\"Field `%%s' not found in union type `%s'\", param_field);\n" + " }\n", dispname); } - else { - // a union's alternative cannot be unbound - src = mputstr(src, "clean_up();\n"); + src = mputstr(src, + " param.basic_check(Module_Param::BC_VALUE, \"union value\");\n" + " Module_Param_Ptr m_p = ¶m;\n"); + if (use_runtime_2) { + src = mputstr(src, + " if (param.get_type() == Module_Param::MP_Reference) {\n" + " m_p = param.get_referenced_param();\n" + " }\n"); } src = mputstr(src, - " return;\n" - " }\n"); - } - src = mputprintf(src, - " mp_last->error(\"Field %%s does not exist in type %s.\", last_name);\n" - "}\n\n", dispname); - - /* get param function, RT2 only */ - if (use_runtime_2) { - def = mputstr(def, "Module_Param* get_param(Module_Param_Name& param_name) const;\n"); - src = mputprintf(src, - "Module_Param* %s::get_param(Module_Param_Name& param_name) const\n" - "{\n" - " if (!is_bound()) {\n" - " return new Module_Param_Unbound();\n" - " }\n" - " if (param_name.next_name()) {\n" - // Haven't reached the end of the module parameter name - // => the name refers to one of the fields, not to the whole union - " char* param_field = param_name.get_current_name();\n" - " if (param_field[0] >= '0' && param_field[0] <= '9') {\n" - " TTCN_error(\"Unexpected array index in module parameter reference, \"\n" - " \"expected a valid field name for union type `%s'\");\n" - " }\n" - " ", name, dispname); + " if (m_p->get_type()==Module_Param::MP_Value_List && m_p->get_size()==0) return;\n" + " if (m_p->get_type()!=Module_Param::MP_Assignment_List) {\n" + " param.error(\"union value with field name was expected\");\n" + " }\n" + " Module_Param* mp_last = m_p->get_elem(m_p->get_size()-1);\n" + " char* last_name = mp_last->get_id()->get_name();\n"); + for (i = 0; i < sdef->nElements; i++) { src = mputprintf(src, - "if (strcmp(\"%s\", param_field) == 0) {\n" - " return %s%s().get_param(param_name);\n" - " } else ", - sdef->elements[i].dispname, at_field, sdef->elements[i].name); + " if (!strcmp(last_name, \"%s\")) {\n" + " %s%s().set_param(*mp_last);\n" + " if (!%s%s().is_bound()) " + , sdef->elements[i].dispname, at_field, sdef->elements[i].name + , at_field, sdef->elements[i].name); + if (legacy_unbound_union_fields) { + src = mputprintf(src, + "TTCN_warning(\"Alternative '%s' was selected for union of type '%s', " + "but its value is unbound\");\n" + , sdef->elements[i].dispname, sdef->dispname); + } + else { + // a union's alternative cannot be unbound + src = mputstr(src, "clean_up();\n"); + } + src = mputstr(src, + " return;\n" + " }\n"); } src = mputprintf(src, - "TTCN_error(\"Field `%%s' not found in union type `%s'\", param_field);\n" - " }\n" - " Module_Param* mp_field = NULL;\n" - " switch(union_selection) {\n" - , name); - for (i = 0; i < sdef->nElements; ++i) { - src = mputprintf(src, - " case %s_%s:\n" - " mp_field = field_%s->get_param(param_name);\n" - " mp_field->set_id(new Module_Param_FieldName(mcopystr(\"%s\")));\n" - " break;\n" - , selection_prefix, sdef->elements[i].name - , sdef->elements[i].name, sdef->elements[i].dispname); + " mp_last->error(\"Field %%s does not exist in type %s.\", last_name);\n" + "}\n\n", dispname); + + /* get param function, RT2 only */ + if (use_runtime_2) { + def = mputstr(def, "Module_Param* get_param(Module_Param_Name& param_name) const;\n"); + src = mputprintf(src, + "Module_Param* %s::get_param(Module_Param_Name& param_name) const\n" + "{\n" + " if (!is_bound()) {\n" + " return new Module_Param_Unbound();\n" + " }\n" + " if (param_name.next_name()) {\n" + // Haven't reached the end of the module parameter name + // => the name refers to one of the fields, not to the whole union + " char* param_field = param_name.get_current_name();\n" + " if (param_field[0] >= '0' && param_field[0] <= '9') {\n" + " TTCN_error(\"Unexpected array index in module parameter reference, \"\n" + " \"expected a valid field name for union type `%s'\");\n" + " }\n" + " ", name, dispname); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, + "if (strcmp(\"%s\", param_field) == 0) {\n" + " return %s%s().get_param(param_name);\n" + " } else ", + sdef->elements[i].dispname, at_field, sdef->elements[i].name); } - src = mputstr(src, - " default:\n" - " break;\n" - " }\n" - " Module_Param_Assignment_List* m_p = new Module_Param_Assignment_List();\n" - " m_p->add_elem(mp_field);\n" - " return m_p;\n" - "}\n\n"); - } + src = mputprintf(src, + "TTCN_error(\"Field `%%s' not found in union type `%s'\", param_field);\n" + " }\n" + " Module_Param* mp_field = NULL;\n" + " switch(union_selection) {\n" + , name); + for (i = 0; i < sdef->nElements; ++i) { + src = mputprintf(src, + " case %s_%s:\n" + " mp_field = field_%s->get_param(param_name);\n" + " mp_field->set_id(new Module_Param_FieldName(mcopystr(\"%s\")));\n" + " break;\n" + , selection_prefix, sdef->elements[i].name + , sdef->elements[i].name, sdef->elements[i].dispname); + } + src = mputstr(src, + " default:\n" + " break;\n" + " }\n" + " Module_Param_Assignment_List* m_p = new Module_Param_Assignment_List();\n" + " m_p->add_elem(mp_field);\n" + " return m_p;\n" + "}\n\n"); + } - /* set implicit omit function, recursive */ - def = mputstr(def, " void set_implicit_omit();\n"); - src = mputprintf(src, - "void %s::set_implicit_omit()\n{\n" - "switch (union_selection) {\n", name); - for (i = 0; i < sdef->nElements; i++) { + /* set implicit omit function, recursive */ + def = mputstr(def, " void set_implicit_omit();\n"); src = mputprintf(src, - "case %s_%s:\n" - "field_%s->set_implicit_omit(); break;\n", - selection_prefix, sdef->elements[i].name, sdef->elements[i].name); - } - src = mputstr(src, "default: break;\n}\n}\n\n"); + "void %s::set_implicit_omit()\n{\n" + "switch (union_selection) {\n", name); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, + "case %s_%s:\n" + "field_%s->set_implicit_omit(); break;\n", + selection_prefix, sdef->elements[i].name, sdef->elements[i].name); + } + src = mputstr(src, "default: break;\n}\n}\n\n"); - /* encode_text function */ - def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); - src = mputprintf(src, "void %s::encode_text(Text_Buf& text_buf) const\n" - "{\n" - "text_buf.push_int(union_selection);\n" - "switch (union_selection) {\n", name); - for (i = 0; i < sdef->nElements; i++) { - src = mputprintf(src, "case %s_%s:\n" - "field_%s->encode_text(text_buf);\n" - "break;\n", selection_prefix, sdef->elements[i].name, - sdef->elements[i].name); + /* encode_text function */ + def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n"); + src = mputprintf(src, "void %s::encode_text(Text_Buf& text_buf) const\n" + "{\n" + "text_buf.push_int(union_selection);\n" + "switch (union_selection) {\n", name); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, "case %s_%s:\n" + "field_%s->encode_text(text_buf);\n" + "break;\n", selection_prefix, sdef->elements[i].name, + sdef->elements[i].name); + } + src = mputprintf(src, "default:\n" + "TTCN_error(\"Text encoder: Encoding an unbound value of union type " + "%s.\");\n" + "}\n" + "}\n\n", dispname); + + /* decode_text function */ + def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); + src = mputprintf(src, "void %s::decode_text(Text_Buf& text_buf)\n" + "{\n" + "switch ((%s)text_buf.pull_int().get_val()) {\n", name, selection_type); + for (i = 0; i < sdef->nElements; i++) { + src = mputprintf(src, "case %s_%s:\n" + "%s%s().decode_text(text_buf);\n" + "break;\n", selection_prefix, sdef->elements[i].name, + at_field, sdef->elements[i].name); + } + src = mputprintf(src, "default:\n" + "TTCN_error(\"Text decoder: Unrecognized union selector was received " + "for type %s.\");\n" + "}\n" + "}\n\n", dispname); } - src = mputprintf(src, "default:\n" - "TTCN_error(\"Text encoder: Encoding an unbound value of union type " - "%s.\");\n" - "}\n" - "}\n\n", dispname); - - /* decode_text function */ - def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n"); - src = mputprintf(src, "void %s::decode_text(Text_Buf& text_buf)\n" - "{\n" - "switch ((%s)text_buf.pull_int().get_val()) {\n", name, selection_type); - for (i = 0; i < sdef->nElements; i++) { - src = mputprintf(src, "case %s_%s:\n" - "%s%s().decode_text(text_buf);\n" - "break;\n", selection_prefix, sdef->elements[i].name, - at_field, sdef->elements[i].name); + else if (use_runtime_2) { + // implement abstract functions inherited by Base_Type (these are never called) + def = mputstr(def, + " void set_param(Module_Param&) { }\n" + " Module_Param* get_param(Module_Param_Name&) const { return NULL; }\n" + " void encode_text(Text_Buf&) const { }\n" + " void decode_text(Text_Buf&) { }\n" + " boolean is_equal(const Base_Type*) const { return FALSE; }\n" + " void set_value(const Base_Type*) { }\n" + " Base_Type* clone() const { return NULL; }\n" + " const TTCN_Typedescriptor_t* get_descriptor() const { return NULL; }\n\n"); } - src = mputprintf(src, "default:\n" - "TTCN_error(\"Text decoder: Unrecognized union selector was received " - "for type %s.\");\n" - "}\n" - "}\n\n", dispname); if(ber_needed || raw_needed || text_needed || xer_needed || json_needed || oer_needed) { diff --git a/core/OOP.hh b/core/OOP.hh index d8a9724ff..704d3b3d5 100644 --- a/core/OOP.hh +++ b/core/OOP.hh @@ -22,7 +22,11 @@ // ---------- template -class OBJECT_REF { +class OBJECT_REF +#ifdef TITAN_RUNTIME_2 + : public Base_Type +#endif +{ template friend boolean operator==(null_type, const OBJECT_REF& right_val); template @@ -188,6 +192,51 @@ public: } return new OBJECT_REF(new_ptr); } + +#ifdef TITAN_RUNTIME_2 + + boolean is_equal(const Base_Type*) const { + TTCN_error("Internal error: OBJECT_REF::is_equal called"); + return false; + } + + void set_value(const Base_Type*) { + TTCN_error("Internal error: OBJECT_REF::set_value called"); + } + + Base_Type* clone() const { + TTCN_error("Internal error: OBJECT_REF::clone called"); + return NULL; + } + + void set_param(Module_Param&) { + TTCN_error("Internal error: OBJECT_REF::set_param called"); + } + + Module_Param* get_param(Module_Param_Name&) const { + TTCN_error("Internal error: OBJECT_REF::get_param called"); + return NULL; + } + + boolean is_seof() const { + TTCN_error("Internal error: OBJECT_REF::is_seof called"); + return FALSE; + } + + void encode_text(Text_Buf&) const { + TTCN_error("Internal error: OBJECT_REF::encode_text called"); + } + + void decode_text(Text_Buf&) { + TTCN_error("Internal error: OBJECT_REF::decode_text called"); + } + + const TTCN_Typedescriptor_t* get_descriptor() const { + TTCN_error("Internal error: OBJECT_REF::get_descriptor called"); + return NULL; + } + +#endif }; template diff --git a/core/Optional.hh b/core/Optional.hh index 9b887384e..906095b9e 100644 --- a/core/Optional.hh +++ b/core/Optional.hh @@ -378,11 +378,7 @@ public: template Base_Type* OPTIONAL::get_opt_value() { -#ifdef TITAN_RUNTIME_2 if (!is_present()) -#else - if (optional_selection!=OPTIONAL_PRESENT) -#endif TTCN_error("Internal error: get_opt_value() called on a non-present optional field."); return optional_value; } @@ -390,11 +386,7 @@ Base_Type* OPTIONAL::get_opt_value() template const Base_Type* OPTIONAL::get_opt_value() const { -#ifdef TITAN_RUNTIME_2 if (!is_present()) -#else - if (optional_selection!=OPTIONAL_PRESENT) -#endif TTCN_error("Internal error: get_opt_value() const called on a non-present optional field."); return optional_value; } @@ -402,25 +394,13 @@ const Base_Type* OPTIONAL::get_opt_value() const template boolean OPTIONAL::is_seof() const { - return -#ifdef TITAN_RUNTIME_2 - (is_present()) -#else - (optional_selection==OPTIONAL_PRESENT) -#endif - ? optional_value->is_seof() : T_type().is_seof(); + return (is_present()) ? optional_value->is_seof() : T_type().is_seof(); } template const TTCN_Typedescriptor_t* OPTIONAL::get_descriptor() const { - return -#ifdef TITAN_RUNTIME_2 - (is_present()) -#else - (optional_selection==OPTIONAL_PRESENT) -#endif - ? optional_value->get_descriptor() : T_type().get_descriptor(); + return (is_present()) ? optional_value->get_descriptor() : T_type().get_descriptor(); } #endif diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index 6ea5247b4..6cbfc7f8c 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -155,25 +155,25 @@ function f_defs() { //^In function definition// } -type record RecClass { //^In type definition// - C0 x, //^In record field// //Class type `@oop_SE.C0' cannot be embedded into another type// - object y //^In record field// //Class type `object' cannot be embedded into another type// +type record RecClass { + C0 x, + object y } -type set SetClass { //^In type definition// - C0 x, //^In set field// //Class type `@oop_SE.C0' cannot be embedded into another type// - object y //^In set field// //Class type `object' cannot be embedded into another type// +type set SetClass { + C0 x, + object y } -type record of C0 RecOfClass; //^In type definition// //^In embedded type of record of// //Class type `@oop_SE.C0' cannot be embedded into another type// -type record of object RecOfObject; //^In type definition// //^In embedded type of record of// //Class type `object' cannot be embedded into another type// +type record of C0 RecOfClass; +type record of object RecOfObject; -type set of C0 SetOfClass; //^In type definition// //^In embedded type of set of// //Class type `@oop_SE.C0' cannot be embedded into another type// -type set of object SetOfObject; //^In type definition// //^In embedded type of set of// //Class type `object' cannot be embedded into another type// +type set of C0 SetOfClass; +type set of object SetOfObject; -type union UniClass { //^In type definition// - C0 x, //^In union field// //Class type `@oop_SE.C0' cannot be embedded into another type// - object y //^In union field// //Class type `object' cannot be embedded into another type// +type union UniClass { + C0 x, + object y } function f_embedded_types() { //^In function definition// @@ -183,7 +183,6 @@ function f_embedded_types() { //^In function definition// var SetOfClass v_setof := { C0.create }; var UniClass v_uni := { x := C0.create }; var anytype v_any; //^In variable definition// //^In type definition// - v_any.C0 := C0.create; } @@ -833,5 +832,5 @@ control { //^In control part// } with { - extension "anytype C0, object" //^In anytype field// //Class type `@oop_SE.C0' cannot be embedded into another type// //Class type `object' cannot be added to the anytype// + extension "anytype C0, object" //Class type `@oop_SE.C0' cannot be added to the anytype// //Class type `object' cannot be added to the anytype// } diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn index cf9812e7b..2b21672da 100644 --- a/regression_test/oop/oop.ttcn +++ b/regression_test/oop/oop.ttcn @@ -232,6 +232,32 @@ type class InternalClass extends ExternalClass { public external function f_ext2(); } +type record RecClass { + charstring name, + object obj +} + +type record of BaseClass BaseClassList; + +type BaseClass BaseClassArray[3]; + +type union UniClass { + BaseClass base, + AbstractClass abs, + integer not_a_class +} + +type union ClassElem { + BaseClass base, + SubClass sub, + FinalClass final +} + +type record of ClassElem ClassUniList; + +type ClassElem ClassUniArray[4]; + + testcase tc_members_and_methods() runs on CT { var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0)); v_base.members_and_methods_test(); @@ -245,16 +271,27 @@ testcase tc_logging() runs on CT { var BaseClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf); var BaseClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *); var TraitClass v_conc := ConcreteClass.create; + var RecClass v_rec_cls := { name := "sub", obj := ConcreteClass.create }; + var BaseClassList v_cls_list := { v_base, v_sub, v_final }; + var BaseClassArray v_cls_arr := { v_base, v_sub, v_final }; + var UniClass v_uni_cls := { abs := ConcreteClass.create }; log(v_base); log(v_sub); log(v_final); log(v_conc); + log(v_rec_cls); + log(v_cls_list); + log(v_cls_arr); + log(v_uni_cls); var charstring v_base_str := "BaseClass"; var charstring v_sub_str := "SubClass ( BaseClass )"; var charstring v_final_str := "FinalClass ( SubClass ( BaseClass ) )"; var charstring v_conc_str := "ConcreteClass ( AbstractClass, TraitClass )"; + var charstring v_rec_cls_str := "{ name := \"sub\", obj := " & v_conc_str & " }"; + var charstring v_cls_list_str := "{ " & v_base_str & ", " & v_sub_str & ", " & v_final_str & " }"; + var charstring v_uni_cls_str := "{ abs := " & v_conc_str & " }"; if (log2str(v_base) != v_base_str) { setverdict(fail, "v_base: ", v_base); @@ -268,6 +305,18 @@ testcase tc_logging() runs on CT { if (log2str(v_conc) != v_conc_str) { setverdict(fail, "v_conc: ", v_conc); } + if (log2str(v_rec_cls) != v_rec_cls_str) { + setverdict(fail, "v_rec_cls: ", v_rec_cls); + } + if (log2str(v_cls_list) != v_cls_list_str) { + setverdict(fail, "v_cls_list: ", v_cls_list); + } + if (log2str(v_cls_arr) != v_cls_list_str) { + setverdict(fail, "v_cls_arr: ", v_cls_arr); + } + if (log2str(v_uni_cls) != v_uni_cls_str) { + setverdict(fail, "v_uni_cls: ", v_uni_cls); + } setverdict(pass); } @@ -460,6 +509,117 @@ testcase tc_references() runs on CT { } +type union UniNode { + Node node, + octetstring raw +} + +testcase tc_references_in_structures() runs on CT { + var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0); + var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0); + var FinalClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *); + var BaseClass v_null := null; + var Node v_node := Node.create(2, null); + var FinalClass v_null2 := null; + var RecClass v_rec_cls := { name := "sub", obj := ConcreteClass.create }; + var ClassUniList v_cls_list := { { base := v_base }, { sub := v_sub }, { final := v_final }, { final := null } }; + var ClassUniArray v_cls_arr := { { base := v_base }, { sub := v_sub }, { final := v_final }, { final := null } }; + var UniClass v_uni_cls := { base := null }; + var UniNode v_uni_node := { node := v_node }; + + var RecClass v_ref1; + if (v_ref1.obj != null) { + setverdict(fail, "#1"); + } + v_ref1 := v_rec_cls; + if (v_ref1.obj != v_rec_cls.obj) { + setverdict(fail, "#2"); + } + var integer v_int := v_cls_list[2].final.f(1); + if (v_int != 9) { + setverdict(fail, "#3, ", v_cls_list[2].final.f(1)); + } + v_int := v_cls_list[2].final.f(2); + if (v_int != 10) { + setverdict(fail, "#4, ", v_int); + } + if (not isbound(v_cls_list[2].final.f2(3).list[1])) { + setverdict(fail, "#5"); + } + if (not isvalue(v_cls_arr[0].base.get_var_temp())) { + setverdict(fail, "#6"); + } + if (not ispresent(v_cls_list[0].base.get_var_temp())) { + setverdict(fail, "#7"); + } + if (ischosen(v_cls_list[2].final.get_uni().cs)) { + setverdict(fail, "#8"); + } + if (not ischosen(v_cls_arr[2].final.get_uni_temp().cs)) { + setverdict(fail, "#9"); + } + if (v_cls_list[2].final.f2(3).list[1] + v_cls_arr[2].final.f(-6) != v_cls_list[0].base.f(3) * float2int(valueof(v_cls_arr[1].sub.get_var_temp()))) { + setverdict(fail, "#10, ", v_cls_list[2].final.f2(3).list[1] + v_cls_arr[2].final.f(-6) != v_cls_list[0].base.f(3) * float2int(valueof(v_cls_arr[1].sub.get_var_temp()))); + } + if (match(v_cls_list[2].final.get_uni(), v_cls_arr[2].final.get_uni_temp())) { + setverdict(fail, "#11, ", match(v_cls_list[2].final.get_uni(), v_cls_arr[2].final.get_uni_temp())); + } + if (not isbound(v_cls_list[1].sub)) { + setverdict(fail, "#12"); + } + if (not isbound(v_uni_cls.base)) { + setverdict(fail, "#13"); + } + if (not isvalue(v_cls_list[2].final)) { + setverdict(fail, "#14"); + } + if (not isvalue(v_uni_cls.base)) { + setverdict(fail, "#15"); + } + if (not ispresent(v_cls_arr[0].base)) { + setverdict(fail, "#16"); + } + if (ispresent(v_uni_cls.base)) { + setverdict(fail, "#17"); + } + var UniClass v_uni_cls2 := v_uni_cls; + if (v_uni_cls2.base != null) { + setverdict(fail, "#18"); + } + if (ispresent(v_uni_cls.base.get_var_temp())) { + setverdict(fail, "#19"); + } + if (ispresent(v_uni_node.node.get_next())) { + setverdict(fail, "#20"); + } + if (ispresent(v_uni_node.node.get_next().f())) { + setverdict(fail, "#21"); + } + if (isbound(v_uni_cls.base.get_var_temp())) { + setverdict(fail, "#22"); + } + if (not isbound(v_uni_node.node.get_next())) { + setverdict(fail, "#23"); + } + if (isbound(v_uni_node.node.get_next().f())) { + setverdict(fail, "#24"); + } + if (isvalue(v_uni_cls.base.get_var_temp())) { + setverdict(fail, "#25"); + } + if (not isvalue(v_uni_node.node.get_next())) { + setverdict(fail, "#26"); + } + if (isvalue(v_uni_node.node.get_next().f())) { + setverdict(fail, "#27"); + } + if (ischosen(v_cls_list[3].final.get_uni().cs)) { + setverdict(fail, "#28"); + } + setverdict(pass); +} + + function f_test(in Node p1, inout Node p2, out Node p3, in charstring p1_str, in charstring p2_str) return Node { if (log2str(p1) != p1_str) { @@ -787,6 +947,7 @@ control { execute(tc_null()); execute(tc_this()); execute(tc_references()); + execute(tc_references_in_structures()); execute(tc_function_pars_and_retval()); execute(tc_function_pars_in()); execute(tc_object()); -- GitLab