From a31e17c0837c1067c0fca7d861bf27d333c0083e Mon Sep 17 00:00:00 2001 From: Botond Baranyi <botond.baranyi@ericsson.com> Date: Tue, 5 May 2020 14:03:44 +0200 Subject: [PATCH] Implemented object-oriented features - stage 6 (bug 552011) Change-Id: I3d60fb128be24c23c4d1825b80d8896422446f5a Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com> --- compiler2/Setting.cc | 2 +- compiler2/Setting.hh | 2 +- compiler2/Type.cc | 8 + compiler2/Type_chk.cc | 7 + compiler2/ttcn3/AST_ttcn3.cc | 97 ++++++-- compiler2/ttcn3/AST_ttcn3.hh | 4 +- compiler2/ttcn3/Statement.cc | 6 +- compiler2/ttcn3/TtcnTemplate.cc | 2 +- compiler2/ttcn3/Ttcnstuff.cc | 158 +++++++++---- compiler2/ttcn3/Ttcnstuff.hh | 12 +- .../Semantic_Analyser/oop/.gitignore | 2 + function_test/Semantic_Analyser/oop/Makefile | 14 ++ .../Semantic_Analyser/oop/oop_SE.ttcn | 217 ++++++++++++++++++ function_test/Semantic_Analyser/oop/t | 9 + 14 files changed, 473 insertions(+), 67 deletions(-) create mode 100644 function_test/Semantic_Analyser/oop/.gitignore create mode 100644 function_test/Semantic_Analyser/oop/Makefile create mode 100644 function_test/Semantic_Analyser/oop/oop_SE.ttcn create mode 100755 function_test/Semantic_Analyser/oop/t diff --git a/compiler2/Setting.cc b/compiler2/Setting.cc index 1a03a11d8..3e57713fe 100644 --- a/compiler2/Setting.cc +++ b/compiler2/Setting.cc @@ -606,7 +606,7 @@ namespace Common { return 0; } - const Ttcn::ClassTypeBody* Scope::get_scope_class() const + Ttcn::ClassTypeBody* Scope::get_scope_class() { if (parent_scope != NULL) { return parent_scope->get_scope_class(); diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh index dc5d47af2..0f5ab426d 100644 --- a/compiler2/Setting.hh +++ b/compiler2/Setting.hh @@ -615,7 +615,7 @@ public: virtual Module* get_scope_mod(); virtual Module* get_scope_mod_gen(); virtual bool is_class_scope() const { return false; } - virtual const Ttcn::ClassTypeBody* get_scope_class() const; + virtual Ttcn::ClassTypeBody* get_scope_class(); /** Returns the assignment referenced by \a p_ref. If no such * node, 0 is returned. */ virtual Assignment* get_ass_bySRef(Ref_simple *p_ref) =0; diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 19f5f90d6..928aea26a 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -1728,6 +1728,10 @@ namespace Common { return 0; } Assignment* ass = class_->get_local_ass_byId(id); + if (!class_->chk_visibility(ass, ref, subrefs->get_my_scope())) { + // the member is not visible (the error has already been reported) + return 0; + } switch (ass->get_asstype()) { case Assignment::A_VAR: case Assignment::A_VAR_TEMPLATE: @@ -1778,6 +1782,10 @@ namespace Common { return 0; } 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) + return 0; + } switch (ass->get_asstype()) { case Assignment::A_VAR: case Assignment::A_VAR_TEMPLATE: diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 80ccc86a3..8b47f46b5 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -3799,6 +3799,10 @@ 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; } @@ -3859,6 +3863,9 @@ void Type::chk_recursions(ReferenceChain& refch) case T_ARRAY: t->get_ofType()->chk_recursions(refch); break; + case T_CLASS: + t->get_class_type_body()->chk_recursions(refch); + break; default: break; } diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 544787f23..7363b51d6 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -307,7 +307,7 @@ namespace Ttcn { // ================================= FieldOrArrayRefs::FieldOrArrayRefs(const FieldOrArrayRefs& p) - : Node(p), refs_str_element(false) + : Node(p), refs_str_element(false), my_scope(NULL) { for (size_t i = 0; i < p.refs.size(); i++) refs.add(p.refs[i]->clone()); } @@ -333,6 +333,7 @@ namespace Ttcn { void FieldOrArrayRefs::set_my_scope(Scope *p_scope) { + my_scope = p_scope; for (size_t i = 0; i < refs.size(); i++) refs[i]->set_my_scope(p_scope); } @@ -3666,6 +3667,12 @@ namespace Ttcn { delete t; continue; } + else if (t->get_type_refd_last()->get_typetype() == Type::T_CLASS) { + ea.error("Class type `%s' cannot be added to the anytype", + t->get_typename().c_str()); + delete t; + continue; + } string field_name; const char* btn = Type::get_typename_builtin(t->get_typetype()); @@ -3883,6 +3890,10 @@ namespace Ttcn { error("Constant cannot be defined for signature `%s'", t->get_fullname().c_str()); break; + case Type::T_CLASS: + error("Constant cannot be defined for class type `%s'", + t->get_fullname().c_str()); + break; default: value_under_check = true; type->chk_this_value(value, 0, Type::EXPECTED_STATIC_VALUE, WARNING_FOR_INCOMPLETE, @@ -4069,6 +4080,10 @@ namespace Ttcn { error("External constant cannot be defined for signature `%s'", t->get_fullname().c_str()); break; + case Type::T_CLASS: + error("External constant cannot be defined for class type `%s'", + t->get_fullname().c_str()); + break; default: break; } @@ -4199,6 +4214,10 @@ namespace Ttcn { " `%s' which has runs on self clause", t->get_fullname().c_str()); break; } + case Type::T_CLASS: + error("Type of module parameter cannot be or embed class type `%s'", + t->get_fullname().c_str()); + break; default: #if defined(MINGW) checked = true; @@ -4367,6 +4386,10 @@ namespace Ttcn { " `%s' which has runs on self clause", t->get_fullname().c_str()); } break; + case Type::T_CLASS: + error("Type of template module parameter cannot be class type `%s'", + t->get_fullname().c_str()); + break; default: if (IMPLICIT_OMIT == has_implicit_omit_attr()) { error("Implicit omit not supported for template module parameters"); @@ -4584,6 +4607,10 @@ namespace Ttcn { error("Template cannot be defined for port type `%s'", t->get_fullname().c_str()); } + else if (t->get_typetype() == Type::T_CLASS) { + error("Template cannot be defined for class type `%s'", + t->get_fullname().c_str()); + } chk_modified(); chk_recursive_derivation(); type->chk_this_template_generic(body, @@ -5371,6 +5398,10 @@ namespace Ttcn { error("Template variable cannot be defined for port type `%s'", t->get_fullname().c_str()); } + else if (t->get_typetype() == Type::T_CLASS) { + error("Template variable cannot be defined for class type `%s'", + t->get_fullname().c_str()); + } if (initial_value) { initial_value->set_my_governor(type); @@ -6675,29 +6706,53 @@ namespace Ttcn { if (runs_on_ref && port_ref) { runs_on_ref->error("A `runs on' and a `port' clause cannot be present at the same time."); } - // checking the `runs on' clause - if (runs_on_ref) { - Error_Context cntxt2(runs_on_ref, "In `runs on' clause"); - runs_on_type = runs_on_ref->chk_comptype_ref(); - // override the scope of the formal parameter list - if (runs_on_type) { - Scope *runs_on_scope = get_runs_on_scope(runs_on_type); - runs_on_scope->set_parent_scope(my_scope); - fp_list->set_my_scope(runs_on_scope); - } + if (my_scope->is_class_scope()) { + // class methods inherit `runs on', `mtc' and `system' clauses from the class + ClassTypeBody* class_ = my_scope->get_scope_class(); + runs_on_type = class_->get_RunsOnType(); + mtc_type = class_->get_MtcType(); + system_type = class_->get_SystemType(); } - - // checking the `mtc' clause - if (mtc_ref) { - Error_Context cntxt2(mtc_ref, "In `mtc' clause"); - mtc_type = mtc_ref->chk_comptype_ref(); + else { // not in a class method + // checking the `runs on' clause + if (runs_on_ref) { + Error_Context cntxt2(runs_on_ref, "In `runs on' clause"); + runs_on_type = runs_on_ref->chk_comptype_ref(); + } + + // checking the `mtc' clause + if (mtc_ref) { + Error_Context cntxt2(mtc_ref, "In `mtc' clause"); + mtc_type = mtc_ref->chk_comptype_ref(); + } + + // checking the `system' clause + if (system_ref) { + Error_Context cntxt2(system_ref, "In `system' clause"); + system_type = system_ref->chk_comptype_ref(); + } } - // checking the `system' clause - if (system_ref) { - Error_Context cntxt2(system_ref, "In `system' clause"); - system_type = system_ref->chk_comptype_ref(); - } + // create scope units for the `runs on', `mtc' and `system' components, + // and link them in a row between the function's scope and the + // formal parameter list's scope + Scope* current_scope = my_scope; + if (system_type != NULL) { + Scope *system_scope = get_runs_on_scope(system_type); + system_scope->set_parent_scope(current_scope); + current_scope = system_scope; + } + if (mtc_type != NULL) { + Scope *mtc_scope = get_runs_on_scope(mtc_type); + mtc_scope->set_parent_scope(current_scope); + current_scope = mtc_scope; + } + if (runs_on_type != NULL) { + Scope *runs_on_scope = get_runs_on_scope(runs_on_type); + runs_on_scope->set_parent_scope(current_scope); + current_scope = runs_on_scope; + } + fp_list->set_my_scope(current_scope); // checking the formal parameter list, the check must come before the // chk_prototype() function call. diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index 695ddf5e3..deee24153 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -250,13 +250,15 @@ namespace Ttcn { /** Indicates whether the last array index refers to an element of a * string value. */ bool refs_str_element; + Common::Scope* my_scope; ///< %Scope. Not owned public: - FieldOrArrayRefs() : Node(), refs(), refs_str_element(false) { } + FieldOrArrayRefs() : Node(), refs(), refs_str_element(false), my_scope(NULL) { } FieldOrArrayRefs(const FieldOrArrayRefs& p); ~FieldOrArrayRefs(); FieldOrArrayRefs *clone() const; virtual void set_fullname(const string& p_fullname); virtual void set_my_scope(Scope *p_scope); + Scope *get_my_scope() const { return my_scope; } void add(FieldOrArrayRef *p_ref) { refs.add(p_ref); } size_t get_nof_refs() const { return refs.size(); } FieldOrArrayRef* get_ref(size_t i) const { return refs[i]; } diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 47ddccab1..37443c049 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -3247,8 +3247,12 @@ error: if (t_ass->get_asstype() == Common::Assignment::A_VAR) { // it could be a class object method Common::Assignment* last_method = NULL; - t_ass->get_Type()->get_field_type(ref_pard->get_subrefs(), + Common::Type* end_type = t_ass->get_Type()->get_field_type(ref_pard->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE, 0, false, &last_method); + if (end_type == NULL && last_method == NULL) { + // invalid subreferences (the error has already been reported) + return; + } if (last_method == NULL) { ref_pard->error("Reference to a function or altstep was expected"); } diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index ffd71a721..4770a8adc 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -31,7 +31,7 @@ #include "../main.hh" #include "../../common/dbgnew.hh" #include "Attributes.hh" -#include "Ttcnstuff.cc" +#include "Ttcnstuff.hh" namespace Ttcn { diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index d8954480e..9a2e25891 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -2986,7 +2986,8 @@ namespace Ttcn { 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), - base_type(p_base_type), runs_on_ref(p_runs_on_ref), mtc_ref(p_mtc_ref), system_ref(p_system_ref), + base_type(p_base_type), 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), default_constructor(false) { @@ -3035,7 +3036,7 @@ namespace Ttcn { { Common::Scope::set_fullname(p_fullname); if (base_type != NULL) { - base_type->set_fullname(p_fullname + ".<base_type>"); + base_type->set_fullname(p_fullname + ".<superclass>"); } if (runs_on_ref != NULL) { runs_on_ref->set_fullname(p_fullname + ".<runs_on_type>"); @@ -3099,10 +3100,36 @@ namespace Ttcn { Def_Constructor* ClassTypeBody::get_constructor() { - chk(); + if (!checked) { + chk(); + } return constructor; } + Type* ClassTypeBody::get_RunsOnType() + { + if (!checked) { + chk(); + } + return runs_on_type; + } + + Type* ClassTypeBody::get_MtcType() + { + if (!checked) { + chk(); + } + return mtc_type; + } + + Type* ClassTypeBody::get_SystemType() + { + if (!checked) { + chk(); + } + return system_type; + } + bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class) const { if (this == p_class) { @@ -3144,6 +3171,37 @@ namespace Ttcn { return ass; } + bool ClassTypeBody::chk_visibility(Common::Assignment* ass, + Common::Location* usage_loc, + Common::Scope* usage_scope) + { + if (ass->get_visibility() == PUBLIC) { + // it's public, so it doesn't matter where it's accessed from + return true; + } + + const ClassTypeBody* ref_scope_class = usage_scope->get_scope_class(); + const ClassTypeBody* ass_scope_class = ass->get_my_scope()->get_scope_class(); + if (ass_scope_class == NULL) { + FATAL_ERROR("ClassTypeBody::chk_visibility()"); + } + if (ref_scope_class == ass_scope_class) { + // the reference is inside the same class as the assignment => any visibility is fine + return true; + } + + if (ref_scope_class != NULL && + ass->get_visibility() == NOCHANGE && // i.e. protected + ref_scope_class->is_parent_class(ass_scope_class)) { + return true; + } + + usage_loc->error("The %s definition `%s' in class type `%s' is not visible " + "in this scope", ass->get_FormalParList() != NULL ? "method" : "member", + ass->get_id().get_dispname().c_str(), class_id->get_dispname().c_str()); + return false; + } + Common::Assignment* ClassTypeBody::get_ass_bySRef(Common::Ref_simple* p_ref) { if (p_ref == NULL || parent_scope == NULL) { @@ -3179,28 +3237,13 @@ namespace Ttcn { if (ass == NULL) { FATAL_ERROR("ClassTypeBody::get_ass_bySRef()"); } - - if (ass->get_visibility() == PUBLIC) { - // it's public, so it doesn't matter where it's accessed from - return ass; - } - const ClassTypeBody* ref_scope_class = p_ref->get_my_scope()->get_scope_class(); - if (ref_scope_class == this) { - // the reference is inside this class => any visibility is fine + if (chk_visibility(ass, p_ref, p_ref->get_my_scope())) { return ass; } - - if (ref_scope_class != NULL && - ass->get_visibility() == NOCHANGE && // i.e. protected - ref_scope_class->is_parent_class(this)) { - return ass; + else { + return NULL; } - - p_ref->error("The member definition `%s' in class type `%s'" - " is not visible in this scope", id->get_dispname().c_str(), - class_id->get_dispname().c_str()); - return NULL; } } return parent_scope->get_ass_bySRef(p_ref); @@ -3214,20 +3257,32 @@ namespace Ttcn { checked = true; // TODO: external? final? abstract? if (base_type != NULL) { + Error_Context cntxt(base_type, "In superclass definition"); base_type->chk(); + if (base_type->get_type_refd_last()->get_typetype() != Common::Type::T_CLASS) { + if (base_type->get_typetype() != Common::Type::T_ERROR) { + base_type->error("Class type expected instead of `%s'", + base_type->get_typename().c_str()); + } + delete base_type; + base_type = NULL; + } // TODO: additional checks for the base type } if (runs_on_ref != NULL) { - Common::Assignment* ass = runs_on_ref->get_refd_assignment(true); + Error_Context cntxt(runs_on_ref, "In `runs on' clause"); + runs_on_type = runs_on_ref->chk_comptype_ref(); // TODO } if (mtc_ref != NULL) { - Common::Assignment* ass = mtc_ref->get_refd_assignment(true); + Error_Context cntxt(mtc_ref, "In `mtc' clause"); + mtc_type = mtc_ref->chk_comptype_ref(); // TODO } if (system_ref != NULL) { - Common::Assignment* ass = system_ref->get_refd_assignment(true); + Error_Context cntxt(system_ref, "In `system' clause"); + system_type = system_ref->chk_comptype_ref(); // TODO } @@ -3253,24 +3308,26 @@ namespace Ttcn { if (base_type != NULL) { ClassTypeBody* base_class = base_type->get_type_refd_last()-> get_class_type_body(); - FormalParList* base_fp_list = base_class->get_constructor()-> - get_FormalParList(); - fp_list = base_fp_list->clone(); - ParsedActualParameters* parsed_ap_list = new ParsedActualParameters(); - for (size_t i = 0; i < base_fp_list->get_nof_fps(); ++i) { - // the actual parameters are references to the formal parameters of - // the base constructor (also present in this constructor) - Reference* ref = new Reference(NULL, - base_fp_list->get_fp_byIndex(i)->get_id().clone()); - Common::Value* val = new Value(Common::Value::V_REFD, ref); - Template* temp = new Template(val); - TemplateInstance* ti = new TemplateInstance(NULL, NULL, temp); - parsed_ap_list->add_ti(ti); + Def_Constructor* base_constructor = base_class->get_constructor(); + if (base_constructor != NULL) { + FormalParList* base_fp_list = base_constructor->get_FormalParList(); + fp_list = base_fp_list->clone(); + ParsedActualParameters* parsed_ap_list = new ParsedActualParameters(); + for (size_t i = 0; i < base_fp_list->get_nof_fps(); ++i) { + // the actual parameters are references to the formal parameters of + // the base constructor (also present in this constructor) + Reference* ref = new Reference(NULL, + base_fp_list->get_fp_byIndex(i)->get_id().clone()); + Common::Value* val = new Value(Common::Value::V_REFD, ref); + Template* temp = new Template(val); + TemplateInstance* ti = new TemplateInstance(NULL, NULL, temp); + parsed_ap_list->add_ti(ti); + } + base_call = new Reference(base_class->get_scope_mod()->get_modid().clone(), + base_class->get_id()->clone(), parsed_ap_list); } - base_call = new Reference(base_class->get_scope_mod()->get_modid().clone(), - base_class->get_id()->clone(), parsed_ap_list); } - else { + if (fp_list == NULL) { fp_list = new FormalParList; } StatementBlock* block = new StatementBlock(); @@ -3315,6 +3372,27 @@ namespace Ttcn { } } + void ClassTypeBody::chk_recursions(ReferenceChain& refch) + { + if (base_type != NULL) { + base_type->chk_recursions(refch); + } + + for (size_t i = 0; i < members->get_nof_asss(); ++i) { + Common::Assignment* def = members->get_ass_byIndex(i); + switch (def->get_asstype()) { + case Common::Assignment::A_CONST: + case Common::Assignment::A_VAR: + case Common::Assignment::A_TEMPLATE: + case Common::Assignment::A_VAR_TEMPLATE: + def->get_Type()->chk_recursions(refch); + break; + default: + break; + } + } + } + void ClassTypeBody::generate_code(output_struct* target) { target->header.class_decls = mputprintf(target->header.class_decls, diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh index 7bad71098..9ad4794da 100644 --- a/compiler2/ttcn3/Ttcnstuff.hh +++ b/compiler2/ttcn3/Ttcnstuff.hh @@ -762,8 +762,11 @@ class ClassTypeBody : public Common::Scope, public Common::Location { boolean abstract; Common::Type* base_type; Reference* runs_on_ref; + Type* runs_on_type; Reference* mtc_ref; + Type* mtc_type; Reference* system_ref; + Type* system_type; Definitions* members; StatementBlock* finally_block; /** set during semantic analysis to either a pointer to the constructor in @@ -788,17 +791,24 @@ public: void dump(unsigned level) const; virtual bool is_class_scope() const { return true; } - virtual const ClassTypeBody* get_scope_class() const { return this; } + virtual ClassTypeBody* get_scope_class() { return this; } Common::Identifier* get_id() const { return class_id; } Def_Constructor* get_constructor(); Common::Type* get_base_type() const { return base_type; } + Type* get_RunsOnType(); + Type* get_MtcType(); + Type* get_SystemType(); + bool is_parent_class(const ClassTypeBody* p_class) const; bool has_local_ass_withId(const Identifier& p_id); Common::Assignment* get_local_ass_byId(const Identifier& p_id); Common::Assignment* get_ass_bySRef(Common::Ref_simple* p_ref); + bool chk_visibility(Common::Assignment* ass, Common::Location* usage_loc, + Common::Scope* usage_scope); void chk(); + void chk_recursions(ReferenceChain& refch); void generate_code(output_struct* target); }; diff --git a/function_test/Semantic_Analyser/oop/.gitignore b/function_test/Semantic_Analyser/oop/.gitignore new file mode 100644 index 000000000..e2d293255 --- /dev/null +++ b/function_test/Semantic_Analyser/oop/.gitignore @@ -0,0 +1,2 @@ +!Makefile +!*.ttcn diff --git a/function_test/Semantic_Analyser/oop/Makefile b/function_test/Semantic_Analyser/oop/Makefile new file mode 100644 index 000000000..16a160593 --- /dev/null +++ b/function_test/Semantic_Analyser/oop/Makefile @@ -0,0 +1,14 @@ +############################################################################## +# Copyright (c) 2000-2020 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 +# +############################################################################## +include ../common.mk + +COMPILER_FLAGS += -k diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn new file mode 100644 index 000000000..42a4732a5 --- /dev/null +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -0,0 +1,217 @@ +/****************************************************************************** + * Copyright (c) 2000-2020 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 oop_SE { //^In TTCN-3 module// + +type component Comp { + var integer cv_comp; + const integer cc_comp := -1; +} + +type port Port message { + inout integer +} +with { + extension "internal" +} + +type record Rec { + integer num, + charstring str +} + +const integer c := 3; + +type class C0 { } + +type class C1 extends Nonexistent { } //^In type definition// //^In superclass definition// //There is no local or imported definition with name `Nonexistent'// + +type class C2 extends c { } //^In type definition// //^In superclass definition// //`c' is not a reference to a type// + +type class C3 extends Rec { } //^In type definition// //^In superclass definition// //Class type expected instead of `@oop_SE.Rec'// + + +type class C4 { + private var integer m_private_inherited; + /*protected*/ var charstring m_protected_inherited; + public var Rec m_public_inherited; + private function f_private_inherited() {} + /*protected*/ function f_protected_inherited() {} + public function f_public_inherited() {} +} + +type class C5 extends C4 { //^In type definition// + private var boolean m_private_own; + /*protected*/ var float m_protected_own; + public var octetstring m_public_own; + private function f_private_own() {} + /*protected*/ function f_protected_own() {} + public function f_public_own() {} + + public function f_member_access_inside() { //^In function definition// + log(m_private_inherited); //^In log statement// //The member definition `m_private_inherited' in class type `C5' is not visible in this scope// + log(m_protected_inherited); + log(m_public_inherited); + log(m_private_own); + log(m_protected_own); + log(m_public_own); + log(m_nonexistent); //^In log statement// //There is no local or imported definition with name `m_nonexistent'// + f_private_inherited(); //^In function or altstep instance// //The method definition `f_private_inherited' in class type `C5' is not visible in this scope// + f_protected_inherited(); + f_public_inherited(); + f_private_own(); + f_protected_own(); + f_public_own(); + f_nonexistent(); //^In function or altstep instance// //There is no local or imported definition with name `f_nonexistent'// + } +} + +function f_member_access_outside() { //^In function definition// + var C5 obj := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O); + log(obj.m_private_inherited); //^In log statement// //The member definition `m_private_inherited' in class type `C5' is not visible in this scope// + log(obj.m_protected_inherited); //^In log statement// //The member definition `m_protected_inherited' in class type `C5' is not visible in this scope// + log(obj.m_public_inherited); + log(obj.m_private_own); //^In log statement// //The member definition `m_private_own' in class type `C5' is not visible in this scope// + log(obj.m_protected_own); //^In log statement// //The member definition `m_protected_own' in class type `C5' is not visible in this scope// + log(obj.m_public_own); + log(obj.m_nonexistent); //^In log statement// //Reference to non-existent member `m_nonexistent' in class type `@oop_SE.C5'// + obj.f_private_inherited(); //^In function instance// //The method definition `f_private_inherited' in class type `C5' is not visible in this scope// + obj.f_protected_inherited(); //^In function instance// //The method definition `f_protected_inherited' in class type `C5' is not visible in this scope// + obj.f_public_inherited(); + obj.f_private_own(); //^In function instance// //The method definition `f_private_own' in class type `C5' is not visible in this scope// + obj.f_protected_own(); //^In function instance// //The method definition `f_protected_own' in class type `C5' is not visible in this scope// + obj.f_public_own(); + obj.f_nonexistent(); //^In function instance// //Reference to non-existent method `f_nonexistent' in class type `@oop_SE.C5'// +} + +type class C6 { //^In type definition// + public function f_member_access_other_class() { //^In function definition// + var C5 obj := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O); + log(obj.m_private_inherited); //^In log statement// //The member definition `m_private_inherited' in class type `C5' is not visible in this scope// + log(obj.m_protected_inherited); //^In log statement// //The member definition `m_protected_inherited' in class type `C5' is not visible in this scope// + log(obj.m_public_inherited); + log(obj.m_private_own); //^In log statement// //The member definition `m_private_own' in class type `C5' is not visible in this scope// + log(obj.m_protected_own); //^In log statement// //The member definition `m_protected_own' in class type `C5' is not visible in this scope// + log(obj.m_public_own); + log(obj.m_nonexistent); //^In log statement// //Reference to non-existent member `m_nonexistent' in class type `@oop_SE.C5'// + obj.f_private_inherited(); //^In function instance// //The method definition `f_private_inherited' in class type `C5' is not visible in this scope// + obj.f_protected_inherited(); //^In function instance// //The method definition `f_protected_inherited' in class type `C5' is not visible in this scope// + obj.f_public_inherited(); + obj.f_private_own(); //^In function instance// //The method definition `f_private_own' in class type `C5' is not visible in this scope// + obj.f_protected_own(); //^In function instance// //The method definition `f_protected_own' in class type `C5' is not visible in this scope// + obj.f_public_own(); + obj.f_nonexistent(); //^In function instance// //Reference to non-existent method `f_nonexistent' in class type `@oop_SE.C5'// + } +} + + +type class C7 extends C9 { //^In type definition// //^In superclass definition// + public const integer x1 := 1; +} + +type class C8 extends C7 { //^In type definition// //While checking embedded recursions\: Circular reference\: `@oop_SE.C8' -> `@oop_SE.C8.<superclass>' -> `@oop_SE.C7' -> `@oop_SE.C7.<superclass>' -> `@oop_SE.C9' -> `@oop_SE.C9.<superclass>' -> `@oop_SE.C8'// + private var integer x2; +} + +type class C9 extends C8 {} //^In type definition// //^In superclass definition// + +external const C0 ec_obj; //^In external constant definition// //External constant cannot be defined for class type `@oop_SE.C0'// +modulepar C0 mp_obj; //^In module parameter definition// //Type of module parameter cannot be or embed class type `@oop_SE.C0'// +modulepar template C0 mpt_obj; //^In template module parameter definition// //Type of template module parameter cannot be class type `@oop_SE.C0'// + +function f_defs() { //^In function definition// + const C0 c_obj := null; //^In constant definition// //Constant cannot be defined for class type `@oop_SE.C0'// + var C0 v_obj; + template C0 t_obj := *; //^In template definition// //Template cannot be defined for class type `@oop_SE.C0'// + var template C0 vt_obj; //^In template variable definition// //Template variable cannot be defined for class type `@oop_SE.C0'// +} + + +type record RecClass { //^In type definition// + C0 x //^In record field// //Class type `@oop_SE.C0' cannot be embedded into another type// +} + +type set SetClass { //^In type definition// + C0 x //^In set field// //Class type `@oop_SE.C0' cannot be embedded into another type// +} + +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 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 union UniClass { //^In type definition// + C0 x //^In union field// //Class type `@oop_SE.C0' cannot be embedded into another type// +} + +function f_embedded_types() { //^In function definition// + var RecClass v_rec := { x := C0.create }; + var SetClass v_set := { x := C0.create }; + var RecOfClass v_recof := { C0.create }; + 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; //^In variable assignment// //Reference to non-existent field `C0' in type `@oop_SE.anytype'// +} + + +function f_type_compatibility() { //^In function definition// + var C4 x1 := C4.create(1, "a", { 2, "b" }); + var C5 y1 := C4.create(1, "a", { 2, "b" }); //^In variable definition// //Incompatible class types: operation `create' should refer to `@oop_SE.C5' instead of `@oop_SE.C4'// + var C4 x2 := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O); + var C5 y2 := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O); + var C4 x3 := y1; + var C5 y3 := x1; //^In variable definition// //Type mismatch: a value of type `@oop_SE.C5' was expected instead of `@oop_SE.C4'// + x3 := y2; + y3 := x2; //^In variable assignment// //Type mismatch: a value of type `@oop_SE.C5' was expected instead of `@oop_SE.C4'// + log(x1.m_public_inherited); + log(y1.m_public_inherited); + log(x1.m_public_own); //^In log statement// //Reference to non-existent member `m_public_own' in class type `@oop_SE.C4'// + log(y1.m_public_own); + x1.f_public_inherited(); + y1.f_public_inherited(); + x1.f_public_own(); //^In function instance// //Reference to non-existent method `f_public_own' in class type `@oop_SE.C4'// + y1.f_public_own(); +} + + +type component CT_RunsOn { + var integer cv_runs_on; + const integer cc_runs_on := 0; +} + +type component CT_Mtc { + var integer cv_mtc; + const integer cc_mtc := 1; +} + +type component CT_System { + var integer cv_system; + const integer cc_system := 2; +} + +type class C10 runs on CT_RunsOn mtc CT_Mtc system CT_System { //^In type definition// + public function f_comp_visibility(in integer p1 := cc_runs_on, //^In function definition// //^In formal parameter list// + in integer p2 := cc_mtc, + in integer p3 := cc_system, + in integer p4 := cc_comp) { //^In parameter// //^In default value// //There is no local or imported definition with name `cc_comp'// + log(cv_runs_on); + log(cv_mtc); + log(cv_system); + log(cv_comp); //^In log statement// //There is no local or imported definition with name `cv_comp'// + } +} + + +} +with { + extension "anytype C0" //Class type `@oop_SE.C0' cannot be added to the anytype// +} diff --git a/function_test/Semantic_Analyser/oop/t b/function_test/Semantic_Analyser/oop/t new file mode 100755 index 000000000..3a4b58ec1 --- /dev/null +++ b/function_test/Semantic_Analyser/oop/t @@ -0,0 +1,9 @@ +#!/usr/bin/perl +# note this is called through "perl -w" +use strict; + +my $self = $0; +$self =~ s!/t!!; + +exec('make check --no-print-directory -s -C ' . $self); + -- GitLab