Commit a31e17c0 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Implemented object-oriented features - stage 6 (bug 552011)



Change-Id: I3d60fb128be24c23c4d1825b80d8896422446f5a
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent e936965b
......@@ -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();
......
......@@ -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;
......
......@@ -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:
......
......@@ -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;
}
......
......@@ -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.
......
......@@ -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]; }
......
......@@ -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");
}
......
......@@ -31,7 +31,7 @@
#include "../main.hh"
#include "../../common/dbgnew.hh"
#include "Attributes.hh"
#include "Ttcnstuff.cc"
#include "Ttcnstuff.hh"
namespace Ttcn {
......
......@@ -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,
......
......@@ -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);
};
......
##############################################################################
# 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
/******************************************************************************
* 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;