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

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



Change-Id: I1b91e35ad9da7b8b0d295a576e7ed4b527b2ee69
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 63af1556
......@@ -3731,7 +3731,7 @@ void Type::chk_Fat()
Error_Context cntxt2(u.fatref.return_type, "In return type");
u.fatref.return_type->chk();
u.fatref.return_type->chk_as_return_type(!u.fatref.returns_template,
"function type");
" function type");
if (u.fatref.is_startable && u.fatref.return_type->get_type_refd_last()
->get_typetype() == T_DEFAULT) u.fatref.is_startable = false;
......@@ -3920,7 +3920,7 @@ void Type::chk_as_return_type(bool as_value, const char* what)
Type *t = get_type_refd_last();
switch(t->get_typetype()) {
case Type::T_PORT:
error("Port type `%s' cannot be the return type of a %s"
error("Port type `%s' cannot be the return type of a%s"
, t->get_fullname().c_str(), what);
break;
case Type::T_SIGNATURE:
......@@ -6000,21 +6000,15 @@ void Type::chk_this_value_class(Value* value)
switch(v->get_valuetype()) {
case Value::V_TTCN3_NULL:
break; // OK
case Value::V_REFD:
// TODO
break;
case Value::V_EXPR:
switch (v->get_optype()) {
case Value::OPTYPE_CLASS_CREATE:
// TODO
break;
default:
// error
if (v->get_optype() == Value::OPTYPE_CLASS_CREATE) {
// OK
break;
}
break;
// else fall through
default:
// error
v->error("class value was expected");
break;
}
}
......
......@@ -4063,8 +4063,11 @@ namespace Common {
goto error;
case Assignment::A_TYPE:
if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) {
tmp_type = ass->get_Type();
break;
Ttcn::Reference* ttcn_ref = static_cast<Ttcn::Reference*>(u.ref.ref);
if (ttcn_ref->get_reftype() == Ref_simple::REF_THIS) {
tmp_type = ass->get_Type();
break;
}
}
// else fall through
default:
......@@ -8201,8 +8204,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case OPTYPE_CLASS_CREATE: { // r1 t_list2
Type* t = chk_expr_operand_undef_create();
if (u.expr.v_optype == OPTYPE_CLASS_CREATE) {
Ttcn::FormalParList* fp_list = t->get_class_type_body()->get_constructor()
->get_FormalParList();
Ttcn::ClassTypeBody* class_ = t->get_class_type_body();
if (class_->is_abstract()) {
error("Cannot create an instance of abstract class type `%s'",
class_->get_my_def()->get_Type()->get_typename().c_str());
}
Ttcn::FormalParList* fp_list = class_->get_constructor()->get_FormalParList();
Ttcn::ActualParList* parlist = new Ttcn::ActualParList;
bool is_erroneous = fp_list->chk_actual_parlist(u.expr.t_list2->get_tis(), parlist);
if (is_erroneous) {
......@@ -9602,8 +9609,11 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
break;
case Assignment::A_TYPE:
if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) {
u.ref.refd_last = this;
break;
Ttcn::Reference* ttcn_ref = static_cast<Ttcn::Reference*>(u.ref.ref);
if (ttcn_ref->get_reftype() == Ref_simple::REF_THIS) {
u.ref.refd_last = this;
break;
}
}
// else fall through
default:
......
......@@ -844,7 +844,6 @@ namespace Ttcn {
}
}
else { // params != NULL
FormalParList *fplist = NULL;
if (ass->get_asstype() == Common::Assignment::A_TYPE) {
Def_Type* def = dynamic_cast<Def_Type*>(ass);
if (def == NULL) {
......@@ -854,14 +853,10 @@ namespace Ttcn {
if (type->get_typetype() == Common::Type::T_CLASS) {
// if the referred assignment is a class type, then the reference and
// its parameters are meant for the constructor instead
fplist = type->get_class_type_body()->get_constructor()->
get_FormalParList();
ass = type->get_class_type_body()->get_constructor();
}
}
if (fplist == NULL) {
// if it's not a class type, retrieve the formal parameter list normally
fplist = ass->get_FormalParList();
}
FormalParList* fplist = ass->get_FormalParList();
if (fplist != NULL) {
Error_Context cntxt(params, "In actual parameter list of %s",
ass->get_description().c_str());
......@@ -6769,7 +6764,7 @@ namespace Ttcn {
if (return_type) {
Error_Context cntxt2(return_type, "In return type");
return_type->chk();
return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL,"function");
return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL," function");
}
if (w_attrib_path) {
......@@ -7454,7 +7449,7 @@ namespace Ttcn {
Error_Context cntxt2(return_type, "In return type");
return_type->chk();
return_type->chk_as_return_type(asstype == A_EXT_FUNCTION_RVAL,
"external function");
" external function");
}
if (!semantic_check_only) fp_list->set_genname(get_genname());
if (w_attrib_path) {
......@@ -8031,7 +8026,84 @@ namespace Ttcn {
void Def_AbsFunction::chk()
{
// TODO
if (checked) {
return;
}
checked = true;
Error_Context cntxt(this, "In abstract function definition `%s'",
id->get_dispname().c_str());
ClassTypeBody* my_class = my_scope->get_scope_class();
if (my_class == NULL) {
FATAL_ERROR("Def_AbsFunction::chk");
}
if (!my_class->is_abstract()) {
error("Concrete class type `%s' cannot have abstract methods",
my_class->get_my_def()->get_Type()->get_typename().c_str());
}
fp_list->chk(asstype);
if (return_type != NULL) {
Error_Context cntxt2(return_type, "In return type");
return_type->chk();
return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL,
"n abstract function");
}
if (!semantic_check_only) {
fp_list->set_genname(get_genname());
}
// TODO: with attributes
}
void Def_AbsFunction::chk_implementation(Common::Assignment* p_ass, Location* p_loc)
{
switch (p_ass->get_asstype()) {
case A_FUNCTION:
case A_FUNCTION_RVAL:
case A_FUNCTION_RTEMP: {
Def_Function* def_func = dynamic_cast<Def_Function*>(p_ass);
if (def_func == NULL) {
// it's an abstract function, which means it hasn't been implemented
p_loc->error("Missing implementation of abstract method `%s'",
get_fullname().c_str());
}
else {
// check whether they're identical
bool match = true;
if (asstype != p_ass->get_asstype()) {
match = false;
}
else if (return_type != NULL &&
!def_func->get_return_type()->is_identical(return_type)) {
match = false;
}
else {
FormalParList* other_fp_list = def_func->get_FormalParList();
if (other_fp_list->get_nof_fps() != fp_list->get_nof_fps()) {
match = false;
}
else {
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()) {
match = false;
}
}
}
}
if (!match) {
p_ass->error("The prototype of method `%s' is not identical to that "
"of inherited abstract method `%s'",
def_func->get_id().get_dispname().c_str(), get_fullname().c_str());
}
}
break; }
default:
p_ass->error("%s shadows inherited abstract method `%s'",
p_ass->get_description().c_str(), get_fullname().c_str());
break;
}
}
void Def_AbsFunction::generate_code(output_struct* target, bool)
......@@ -8746,9 +8818,39 @@ namespace Ttcn {
fp_list->chk(asstype);
ClassTypeBody* my_class = my_scope->get_scope_class();
ClassTypeBody* base_class = my_class->get_base_class();
if (base_call != NULL) {
Common::Assignment* base_type_ass = base_call->get_refd_assignment(true);
// TODO
Error_Context cntxt2(this, "In super-constructor call");
if (base_class == NULL) {
base_call->error("Class type `%s' does not have a superclass",
my_class->get_my_def()->get_Type()->get_typename().c_str());
}
else {
Common::Assignment* base_call_ass = base_call->get_refd_assignment(true);
if (base_call_ass != NULL) {
if (base_call_ass->get_asstype() != Common::Assignment::A_CONSTRUCTOR) {
base_call->error("Reference to constructor was expected instead of %s",
base_call_ass->get_assname());
}
else {
ClassTypeBody* base_call_class = base_call_ass->get_my_scope()->get_scope_class();
if (base_call_class != base_class) {
base_call->error("expected call to constructor of class type `%s', "
"instead of class type `%s'",
my_class->get_base_type()->get_typename().c_str(),
base_call_class->get_my_def()->get_Type()->get_typename().c_str());
}
}
}
}
}
else if (base_class != NULL) {
Def_Constructor* base_constructor = base_class->get_constructor();
if (base_constructor != NULL &&
!base_constructor->get_FormalParList()->has_only_default_values()) {
error("Missing super-constructor call");
}
}
block->chk();
......
......@@ -1385,8 +1385,12 @@ namespace Ttcn {
Type *get_input_type();
Type *get_output_type();
Type* get_return_type() const { return return_type; }
//virtual Type *get_RunsOnType();
template_restriction_t get_template_restriction()
{ return template_restriction; }
/** Checks and returns whether the function is startable.
* Reports the appropriate error message(s) if not. */
//bool chk_startable(Location* caller_location);
};
/**
......@@ -1611,8 +1615,8 @@ namespace Ttcn {
virtual ~Def_AbsFunction();
virtual Definition* clone() const;
virtual void chk();
void chk_implementation(Common::Assignment* p_ass, Location* p_loc);
virtual void generate_code(output_struct* target, bool clean_up = false);
// TODO
};
/**
......
......@@ -11512,7 +11512,8 @@ error:
Common::Assignment::asstype_t asstype = t_ass->get_asstype();
switch (asstype) {
case Common::Assignment::A_TYPE:
if (t_ass->get_Type()->get_typetype() != Common::Type::T_CLASS) {
if (t_ass->get_Type()->get_typetype() != Common::Type::T_CLASS ||
ref->get_reftype() != Common::Ref_simple::REF_THIS) {
ref->error("Reference to a value, template, timer, port or class object "
"was expected instead of %s", t_ass->get_description().c_str());
return;
......
......@@ -2986,7 +2986,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), built_in(FALSE), base_type(p_base_type),
abstract(p_abstract), built_in(FALSE), base_type(p_base_type), base_class(NULL),
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),
......@@ -3000,7 +3000,7 @@ namespace Ttcn {
ClassTypeBody::ClassTypeBody()
: Scope(), Location(), class_id(NULL), my_def(NULL), external(FALSE), final(FALSE),
abstract(TRUE), built_in(TRUE), base_type(NULL),
abstract(TRUE), built_in(TRUE), base_type(NULL), base_class(NULL),
runs_on_ref(NULL), runs_on_type(NULL), mtc_ref(NULL),
mtc_type(NULL), system_ref(NULL), system_type(NULL),
members(NULL), finally_block(NULL), constructor(NULL), checked(false),
......@@ -3018,6 +3018,7 @@ namespace Ttcn {
final = p.final;
abstract = p.abstract;
base_type = p.base_type != NULL ? p.base_type->clone() : NULL;
base_class = p.base_class;
runs_on_ref = p.runs_on_ref != NULL ? p.runs_on_ref->clone() : NULL;
mtc_ref = p.mtc_ref != NULL ? p.mtc_ref->clone() : NULL;
system_ref = p.system_ref != NULL ? p.system_ref->clone() : NULL;
......@@ -3047,6 +3048,7 @@ namespace Ttcn {
if (default_constructor) {
delete constructor;
}
abstract_functions.clear();
}
void ClassTypeBody::set_fullname(const string& p_fullname)
......@@ -3067,7 +3069,7 @@ namespace Ttcn {
if (system_ref != NULL) {
system_ref->set_fullname(p_fullname + ".<system_type>");
}
members->set_fullname(p_fullname + ".<members>");
members->set_fullname(p_fullname);
if (finally_block != NULL) {
finally_block->set_fullname(p_fullname + ".<finally_block>");
}
......@@ -3133,6 +3135,14 @@ namespace Ttcn {
return constructor;
}
ClassTypeBody* ClassTypeBody::get_base_class()
{
if (!checked) {
chk();
}
return base_class;
}
Type* ClassTypeBody::get_RunsOnType()
{
if (!checked) {
......@@ -3157,30 +3167,33 @@ namespace Ttcn {
return system_type;
}
bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class) const
bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class)
{
if (!checked) {
chk();
}
if (this == p_class || p_class->built_in) {
return true;
}
if (base_type == NULL) {
if (base_class == NULL) {
return false;
}
return base_type->get_type_refd_last()->get_class_type_body()->
is_parent_class(p_class);
return base_class->is_parent_class(p_class);
}
bool ClassTypeBody::has_local_ass_withId(const Identifier& p_id)
{
if (!checked) {
chk();
}
if (built_in) {
return false;
}
chk();
if (members->has_local_ass_withId(p_id)) {
return true;
}
if (base_type != NULL) {
return base_type->get_type_refd_last()->get_class_type_body()->
has_local_ass_withId(p_id);
return base_class->has_local_ass_withId(p_id);
}
else {
return false;
......@@ -3192,14 +3205,15 @@ namespace Ttcn {
if (built_in) {
FATAL_ERROR("ClassTypeBody::get_local_ass_byId");
}
chk();
if (!checked) {
chk();
}
Common::Assignment* ass = NULL;
if (members->has_local_ass_withId(p_id)) {
ass = members->get_local_ass_byId(p_id);
}
if (ass == NULL && base_type != NULL) {
ass = base_type->get_type_refd_last()->get_class_type_body()->
get_local_ass_byId(p_id);
if (ass == NULL && base_class != NULL) {
ass = base_class->get_local_ass_byId(p_id);
}
return ass;
}
......@@ -3216,8 +3230,8 @@ namespace Ttcn {
return true;
}
const ClassTypeBody* ref_scope_class = usage_scope->get_scope_class();
const ClassTypeBody* ass_scope_class = ass->get_my_scope()->get_scope_class();
ClassTypeBody* ref_scope_class = usage_scope->get_scope_class();
ClassTypeBody* ass_scope_class = ass->get_my_scope()->get_scope_class();
if (ass_scope_class == NULL) {
FATAL_ERROR("ClassTypeBody::chk_visibility()");
}
......@@ -3258,8 +3272,7 @@ namespace Ttcn {
else {
// send the reference to the base type, with the reftype changed to 'this'
p_ref->set_reftype(Ref_simple::REF_THIS);
Common::Assignment* ass = base_type->get_type_refd_last()->
get_class_type_body()->get_ass_bySRef(p_ref);
Common::Assignment* ass = base_class->get_ass_bySRef(p_ref);
p_ref->set_reftype(Ref_simple::REF_SUPER);
return ass;
}
......@@ -3294,7 +3307,10 @@ namespace Ttcn {
return;
}
checked = true;
// TODO: external? final? abstract?
if (final && abstract) {
error("Final classes cannot be abstract");
}
// TODO: external?
if (base_type != NULL) {
Error_Context cntxt(base_type, "In superclass definition");
base_type->chk();
......@@ -3306,11 +3322,14 @@ namespace Ttcn {
delete base_type;
base_type = NULL;
}
// TODO: additional checks for the base type
else {
base_class = base_type->get_type_refd_last()->get_class_type_body();
if (base_class->final) {
base_type->error("The superclass cannot be final");
}
}
}
ClassTypeBody* base_class = base_type != NULL ?
base_type->get_type_refd_last()->get_class_type_body() : NULL;
if (runs_on_ref != NULL) {
Error_Context cntxt(runs_on_ref, "In `runs on' clause");
runs_on_type = runs_on_ref->chk_comptype_ref();
......@@ -3375,7 +3394,6 @@ namespace Ttcn {
for (size_t i = 0; i < members->get_nof_asss(); ++i) {
Common::Assignment* ass = members->get_ass_byIndex(i, false);
if (ass->get_asstype() == Common::Assignment::A_CONSTRUCTOR) {
// TODO: check for multiple constructors, or is that handled by previous checks?
constructor = dynamic_cast<Def_Constructor*>(ass);
if (constructor == NULL) {
FATAL_ERROR("ClassTypeBody::chk");
......@@ -3453,6 +3471,46 @@ namespace Ttcn {
if (finally_block != NULL) {
finally_block->chk();
}
if (abstract) {
// create a map of all abstract functions (including inherited ones)
if (base_class != NULL && base_class->abstract) {
for (size_t i = 0; i < base_class->abstract_functions.size(); ++i) {
abstract_functions.add(base_class->abstract_functions.get_nth_key(i),
base_class->abstract_functions.get_nth_elem(i));
}
}
for (size_t i = 0; i < members->get_nof_asss(); ++i) {
Common::Assignment* ass = members->get_ass_byIndex(i, false);
switch (ass->get_asstype()) {
case Common::Assignment::A_FUNCTION:
case Common::Assignment::A_FUNCTION_RVAL:
case Common::Assignment::A_FUNCTION_RTEMP: {
Def_AbsFunction* def_abs_func = dynamic_cast<Def_AbsFunction*>(ass);
if (def_abs_func != NULL) {
const string& def_name = def_abs_func->get_id().get_name();
if (abstract_functions.has_key(def_name)) {
// TODO
}
else {
abstract_functions.add(def_name, def_abs_func);
}
}
break; }
default:
break;
}
}
}
if (!abstract && base_class != NULL && base_class->abstract) {
// all abstract methods from the base class have to be implemented in this class
for (size_t i = 0; i < base_class->abstract_functions.size(); ++i) {
Def_AbsFunction* def_abs_func = base_class->abstract_functions.get_nth_elem(i);
def_abs_func->chk_implementation(get_local_ass_byId(def_abs_func->get_id()), this);
}
}
// todo: name clashes with defs in the base class?
}
void ClassTypeBody::chk_recursions(ReferenceChain& refch)
......
......@@ -756,12 +756,13 @@ public:
class ClassTypeBody : public Common::Scope, public Common::Location {
Common::Identifier* class_id; // not owned
Definition* my_def; // pointer to the class type definition (not owned)
Def_Type* my_def; // pointer to the class type definition (not owned)
boolean external;
boolean final;
boolean abstract;
boolean built_in;
Common::Type* base_type;
ClassTypeBody* base_class; // not owned
Reference* runs_on_ref;
Type* runs_on_type;
Reference* mtc_ref;
......@@ -773,6 +774,7 @@ class ClassTypeBody : public Common::Scope, public Common::Location {
/** set during semantic analysis to either a pointer to the constructor in
* 'members', or the actual default constructor (if no constructor is defined) */
Def_Constructor* constructor;
map<string, Def_AbsFunction> abstract_functions;
bool checked;
bool default_constructor; /// true if the class uses a default constructor
......@@ -786,7 +788,9 @@ public:
ClassTypeBody* clone() const;
virtual ~ClassTypeBody();
void set_my_def(Definition* p_def) { my_def = p_def; }
void set_my_def(Def_Type* p_def) { my_def = p_def; }
Def_Type* get_my_def() { return my_def; }
boolean is_abstract() const { return abstract; }
void set_fullname(const string& p_fullname);
void set_my_scope(Scope* p_scope);
......@@ -797,13 +801,14 @@ public:
Common::Identifier* get_id() const { return class_id; }
Def_Constructor* get_constructor();
Common::Type* get_base_type() const { return base_type; }
ClassTypeBody* get_base_class();
boolean is_built_in() const { return built_in; }
Type* get_RunsOnType();
Type* get_MtcType();
Type* get_SystemType();
bool is_parent_class(const ClassTypeBody* p_class) const;
bool is_parent_class(const ClassTypeBody* p_class);
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);
......
......@@ -275,6 +275,113 @@ function f_no_comp_usage() { //^In function definition//
}
type class C15 {
public var integer v;
public function f() { }
public function g() return boolean { return true; }
}
function f_access_with_class_name() { //^In function definition//
log(C5.v); //^In log statement// //Reference to a value, template, timer, port or class object was expected instead of type `@oop_SE.C5'//
log(C5.g()); //^In log statement// //Reference to a value, template, timer, port or class object was expected instead of type `@oop_SE.C5'//
C5.f(); //Reference to a function or altstep was expected instead of type `@oop_SE.C5', which cannot be invoked//
C5.g(); //Reference to a function or altstep was expected instead of type `@oop_SE.C5', which cannot be invoked//
if (C5.g()) { log(1); } //^In if statement// //Reference to a value was expected instead of type `@oop_SE.C5'//
if (C5.v == 1) { log(2); } //^In if statement// //Reference to a value was expected instead of type `@oop_SE.C5'//
var integer x1 := C5.v + 1; //^In variable definition// //^In the left operand of operation// //Reference to a value was expected instead of type `@oop_SE.C5'//
var boolean x2 := C5.g(); //^In variable definition// //Reference to a value was expected instead of type `@oop_SE.C5'//
}
function f_init_values() { //^In function definition//
var integer v_int := 3;
var template integer vt_int := (1..10);
var C4 v1 := 1; //^In variable definition// //class value was expected//
var C4 v2 := v_int; //^In variable definition// //Type mismatch\: a value of type `@oop_SE.C4' was expected instead of `integer'//
var C4 v3 := valueof(vt_int) + v_int; //^In variable definition// //Incompatible value\: `@oop_SE.C4' value was expected//
var C4 v4 := CT_RunsOn.create; //^In variable definition// //Incompatible value\: `@oop_SE.C4' value was expected//
var C4 v5 := C11.create; //^In variable definition// //Incompatible class types\: operation `create' should refer to `@oop_SE.C4' instead of `@oop_SE.C11'//
}
type class C16 extends C15 { //^In type definition//
create() : C15(1) { } //Previous definition of `create' is here//
create(in integer p) : C15(p) { } //Duplicate definition with name `create'//
}
type class C17 { //^In type definition//
create() : C15(1) { } //^In constructor definition// //^In super-constructor call// //Class type `@oop_SE.C17' does not have a superclass//
}
type class C18 extends C15 { //^In type definition//
create() : C16() { } //^In constructor definition// //^In super-constructor call// //expected call to constructor of class type `@oop_SE.C15', instead of class type `@oop_SE.C16'//
}
type class C19 extends C15 { //^In type definition//