diff --git a/compiler2/Code.cc b/compiler2/Code.cc index aaeca10944df27b80c83c9826c1460a08a7e2a46..67f1911eb949f845eb7a69603274df3a86ae21ef 100644 --- a/compiler2/Code.cc +++ b/compiler2/Code.cc @@ -83,7 +83,8 @@ namespace Common { output->intervals.static_function_bodies = NULL; } output->temp.constructor_init = NULL; - output->temp.constructor = NULL; + output->temp.constructor_preamble = NULL; + output->temp.constructor_block = NULL; } void Code::merge_output(output_struct *dest, output_struct *src) @@ -180,7 +181,7 @@ namespace Common { Free(output->intervals.static_conversion_function_bodies); Free(output->intervals.static_function_bodies); Free(output->temp.constructor_init); - Free(output->temp.constructor); + Free(output->temp.constructor_preamble); init_output(output, TRUE); } @@ -199,9 +200,9 @@ namespace Common { header = mputstr(header, cdef->decl); char*& source = in_class ? dest->temp.constructor_init : dest->source.global_vars; source = mputstr(source, cdef->def); - char*& pre_init = in_class ? dest->temp.constructor : dest->functions.pre_init; + char*& pre_init = in_class ? dest->temp.constructor_preamble : dest->functions.pre_init; pre_init = mputstr(pre_init, cdef->init); - char*& post_init = in_class ? dest->temp.constructor : dest->functions.post_init; + char*& post_init = in_class ? dest->temp.constructor_preamble : dest->functions.post_init; post_init = mputstr(post_init, cdef->post); } diff --git a/compiler2/Identifier.cc b/compiler2/Identifier.cc index 3ba27aa3ffa5181b85ff7523e806aa49129287a8..905bd39688adcc5e7772f6430c4b11a30873283c 100644 --- a/compiler2/Identifier.cc +++ b/compiler2/Identifier.cc @@ -458,7 +458,6 @@ namespace Common { {"bitand_", "bitand", "bitand"}, {"bitor_", "bitor", "bitor"}, {"bool_", "bool", "bool"}, - {"class_", "class", "class"}, {"compl_", "compl", "compl"}, {"delete_", "delete", "delete"}, {"double_", "double", "double"}, @@ -500,12 +499,14 @@ namespace Common { {"case__", "case", "case_"}, {"catch__", "catch", "catch_"}, {"char__", "char", "char_"}, + {"class__", "class", "class_"}, {"const__", "const", "const_"}, {"continue__", "continue", "continue_"}, {"default__", "default", "default_"}, {"do__", "do", "do_"}, {"else__", "else", "else_"}, {"false__", "false", "false_"}, + {"finally__", "finally", "finally_"}, {"float__", "float", "float_"}, {"for__", "for", "for_"}, {"goto__", "goto", "goto_"}, @@ -698,6 +699,7 @@ namespace Common { {"INTEGER", "INTEGER", "integer"}, {"ISO646String", "ISO646String", 0}, {"NumericString", "NumericString", 0}, + {"OBJECT", 0, "object"}, {"OBJID", "OBJECT IDENTIFIER", "objid"}, {"OCTETSTRING", "OCTET STRING", "octetstring"}, {"ObjectDescriptor", "ObjectDescriptor", 0}, @@ -726,6 +728,7 @@ namespace Common { {"INTEGER_", 0, "INTEGER"}, {"ISO646String_", 0, "ISO646String"}, {"NumericString_", 0, "NumericString"}, + {"OBJECT_", "OBJECT", "OBJECT"}, {"OBJID_", "OBJID", "OBJID"}, {"OCTETSTRING_", "OCTETSTRING", "OCTETSTRING"}, {"ObjectDescriptor_", 0, "ObjectDescriptor"}, diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 7daa287e20445ad3bcd1e13626044d759b91fa88..650c29264d5c21b6eee02d984853f347727b5ac2 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -749,6 +749,15 @@ namespace Ttcn { ref_usage_found(); Common::Assignment *ass = get_refd_assignment(); if (!ass) FATAL_ERROR("Reference::generate_code()"); + string const_prefix; // empty by default + if (gen_const_prefix) { + if (ass->get_asstype() == Common::Assignment::A_CONST) { + const_prefix = "const_"; + } + else if (ass->get_asstype() == Common::Assignment::A_TEMPLATE) { + const_prefix = "template_"; + } + } if (parlist) { // 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() @@ -761,7 +770,7 @@ namespace Ttcn { expr->expr = mputstr(expr->expr, LazyFuzzyParamData::in_lazy_or_fuzzy() ? LazyFuzzyParamData::add_ref_genname(ass, my_scope).c_str() : - ass->get_genname_from_scope(my_scope).c_str()); + (const_prefix + ass->get_genname_from_scope(my_scope)).c_str()); } if (subrefs.get_nof_refs() > 0) subrefs.generate_code(expr, ass); } @@ -1037,6 +1046,19 @@ namespace Ttcn { if (ass && check_parlist && !params_checked) { params_checked = true; FormalParList *fplist = ass->get_FormalParList(); + if (fplist == NULL && ass->get_asstype() == Common::Assignment::A_TYPE) { + Def_Type* def = dynamic_cast<Def_Type*>(ass); + if (def == NULL) { + FATAL_ERROR("Ref_pard::get_refd_assignment"); + } + Type* type = def->get_Type(); + 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(); + } + } if (fplist) { Error_Context cntxt(params, "In actual parameter list of %s", ass->get_description().c_str()); @@ -3491,7 +3513,7 @@ namespace Ttcn { chk(); return type; } - + void Def_Type::chk() { if (checked) return; @@ -4843,7 +4865,7 @@ namespace Ttcn { header = mputstr(header, cdef.decl); char*& source = in_class ? target->temp.constructor_init : target->source.global_vars; source = mputstr(source, cdef.def); - char*& init = in_class ? target->temp.constructor : target->functions.post_init; + char*& init = in_class ? target->temp.constructor_preamble : target->functions.post_init; init = mputstr(init, cdef.init); Code::free_cdef(&cdef); } @@ -5109,7 +5131,7 @@ namespace Ttcn { Code::merge_cdef(target, &cdef, in_class); Code::free_cdef(&cdef); if (initial_value) { - char*& init = in_class ? target->temp.constructor : + char*& init = in_class ? target->temp.constructor_preamble : target->functions.init_comp; init = initial_value->generate_code_init(init, initial_value->get_lhs_name().c_str()); @@ -5324,7 +5346,7 @@ namespace Ttcn { Code::merge_cdef(target, &cdef, in_class); Code::free_cdef(&cdef); if (initial_value) { - char*& init = in_class ? target->temp.constructor : + char*& init = in_class ? target->temp.constructor_preamble : target->functions.init_comp; if (Common::Type::T_SEQOF == initial_value->get_my_governor()->get_typetype() || Common::Type::T_ARRAY == initial_value->get_my_governor()->get_typetype()) { @@ -5684,11 +5706,11 @@ namespace Ttcn { bool in_class = my_scope->is_class_scope(); char*& header = in_class ? target->header.class_defs : target->header.global_vars; - char*& source = in_class ? target->temp.constructor : + char*& source = in_class ? target->temp.constructor_preamble : target->source.global_vars; - char*& pre_init = in_class ? target->temp.constructor : + char*& pre_init = in_class ? target->temp.constructor_preamble : target->functions.pre_init; - char*& post_init = in_class ? target->temp.constructor : + char*& post_init = in_class ? target->temp.constructor_preamble : target->functions.post_init; if (dimensions) { // timer array @@ -8490,6 +8512,8 @@ namespace Ttcn { if (p_fp_list == NULL || block == NULL) { FATAL_ERROR("Def_Constructor::Def_Constructor"); } + fp_list->set_my_def(this); + block->set_my_def(this); } Def_Constructor::~Def_Constructor() @@ -8499,7 +8523,7 @@ namespace Ttcn { delete block; } - Def_Constructor *Def_Constructor::clone() const + Def_Constructor* Def_Constructor::clone() const { FATAL_ERROR("Def_Constructor::clone"); } @@ -8516,13 +8540,14 @@ namespace Ttcn { void Def_Constructor::set_my_scope(Scope* p_scope) { - //bridgeScope.set_parent_scope(p_scope); - //bridgeScope.set_scopeMacro_name(id->get_dispname()); + bridgeScope.set_parent_scope(p_scope); + bridgeScope.set_scopeMacro_name(id->get_dispname()); - //Definition::set_my_scope(&bridgeScope); - Definition::set_my_scope(p_scope); // TODO + Definition::set_my_scope(&bridgeScope); + + fp_list->set_my_scope(&bridgeScope); if (base_call != NULL) { - base_call->set_my_scope(p_scope); + base_call->set_my_scope(fp_list); } block->set_my_scope(fp_list); } @@ -8535,12 +8560,36 @@ namespace Ttcn { void Def_Constructor::chk() { - // TODO + if (checked) { + return; + } + checked = true; + + Error_Context cntxt(this, "In constructor definition"); + + fp_list->chk(asstype); + + if (base_call != NULL) { + Common::Assignment* base_type_ass = base_call->get_refd_assignment(true); + // TODO + } + + block->chk(); + + if (!semantic_check_only) { + // prefix 'create' with the class name when forming parameter names + // to avoid collisions in the generated code + fp_list->set_genname(my_scope->get_scope_class()->get_id()->get_name() + + string("_") + get_genname()); + block->set_code_section(GovernedSimple::CS_INLINE); + } } void Def_Constructor::generate_code(output_struct *target, bool clean_up) { - // TODO + fp_list->generate_code_defval(target); + target->temp.constructor_block = block->generate_code(target->temp.constructor_block, + target->header.global_vars, target->source.global_vars); } void Def_Constructor::set_parent_path(WithAttribPath* p_path) @@ -8609,6 +8658,21 @@ namespace Ttcn { FATAL_ERROR("Ttcn::FormalPar::FormalPar(): invalid parameter type"); defval.ti = p_defval; } + + FormalPar::FormalPar(const FormalPar& p) + : Definition(p.asstype, p.id->clone()), type(p.type->clone()), my_parlist(0), + used_as_lvalue(false), template_restriction(p.template_restriction), + eval(p.eval), defval_generated(false), usage_found(false) + { + type->set_ownertype(Type::OT_FORMAL_PAR, this); + checked = p.checked; + if (checked) { + defval.ap = p.defval.ap != NULL ? p.defval.ap->clone() : NULL; + } + else { + defval.ti = p.defval.ti != NULL ? p.defval.ti->clone() : NULL; + } + } FormalPar::~FormalPar() { @@ -8619,7 +8683,7 @@ namespace Ttcn { FormalPar* FormalPar::clone() const { - FATAL_ERROR("FormalPar::clone"); + return new FormalPar(*this); } void FormalPar::set_fullname(const string& p_fullname) @@ -9599,6 +9663,15 @@ namespace Ttcn { // ================================= // ===== FormalParList // ================================= + + FormalParList::FormalParList(const FormalParList& p) + : Scope(), Location(), pars_v(), pars_m(), min_nof_pars(0), my_def(0), + checked(false), is_startable(false) + { + for (size_t i = 0; i < p.pars_v.size(); ++i) { + add_fp(p.pars_v[i]->clone()); + } + } FormalParList::~FormalParList() { @@ -9610,7 +9683,7 @@ namespace Ttcn { FormalParList *FormalParList::clone() const { - FATAL_ERROR("FormalParList::clone"); + return new FormalParList(*this); } void FormalParList::set_fullname(const string& p_fullname) @@ -10313,6 +10386,31 @@ namespace Ttcn { if (!a) FATAL_ERROR("ActualPar::ActualPar()"); act = a; } + + 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) + { + switch(selection) { + case AP_ERROR: + break; + case AP_VALUE: + val = p.val->clone(); + break; + case AP_TEMPLATE: + temp = p.temp->clone(); + break; + case AP_REF: + ref = p.ref->clone(); + break; + case AP_DEFAULT: + act = p.act; + break; + default: + FATAL_ERROR("ActualPar::ActualPar()"); + } + } ActualPar::~ActualPar() { @@ -10337,7 +10435,7 @@ namespace Ttcn { ActualPar *ActualPar::clone() const { - FATAL_ERROR("ActualPar::clone"); + return new ActualPar(*this); } void ActualPar::set_fullname(const string& p_fullname) diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index fa1eb6cd2c2c607b3004df5129c7eb95829a0846..117ba2a322534de7421d45ad85d5406cee1648ce 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -91,7 +91,7 @@ namespace Ttcn { * runtime checks for out and inout parameters after the call */ template_restriction_t gen_post_restriction_check; private: - /** Copy constructor not implemented */ + /** Copy constructor */ ActualPar(const ActualPar& p); /** %Assignment disabled */ ActualPar& operator=(const ActualPar& p); @@ -325,10 +325,11 @@ namespace Ttcn { */ class Reference : public Ref_base { ActualParList *parlist; + bool gen_const_prefix; public: Reference(Identifier *p_id); Reference(Identifier *p_modid, Identifier *p_id) - : Ref_base(p_modid, p_id), parlist(0) { } + : Ref_base(p_modid, p_id), parlist(0), gen_const_prefix(false) { } ~Reference(); virtual Reference *clone() const; virtual void set_my_scope(Scope* p_scope); @@ -336,6 +337,7 @@ namespace Ttcn { virtual Common::Assignment *get_refd_assignment(bool check_parlist = true); virtual const Identifier* get_modid(); virtual const Identifier* get_id(); + void set_gen_const_prefix() { gen_const_prefix = true; } /** Checks whether \a this points to a variable or value parameter. * Returns the type of the respective variable or variable field or NULL * in case of error. */ @@ -1751,7 +1753,7 @@ namespace Ttcn { StatementBlock* block; - //NameBridgingScope bridgeScope; + NameBridgingScope bridgeScope; /// Copy constructor disabled Def_Constructor(const Def_Constructor& p); @@ -1764,7 +1766,8 @@ namespace Ttcn { virtual Def_Constructor* clone() const; virtual void set_fullname(const string& p_fullname); virtual void set_my_scope(Scope* p_scope); - virtual FormalParList *get_FormalParList(); + virtual FormalParList* get_FormalParList(); + virtual Ref_pard* get_base_call() const { return base_call; } virtual void chk(); virtual void generate_code(output_struct *target, bool clean_up = false); virtual void set_parent_path(WithAttribPath* p_path); diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 0363c48f064109cd2e6151ec5feaa82c09c22038..dd5764afe1de9aac8390e2047402166627beace1 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -3248,6 +3248,10 @@ error: void Statement::chk_assignment() { Error_Context cntxt(this, "In variable assignment"); + Definition* sb_def = my_sb->get_my_def(); + if (sb_def != NULL && sb_def->get_asstype() == Common::Assignment::A_CONSTRUCTOR) { + ass->set_in_contructor(); + } ass->chk(); } @@ -8754,14 +8758,16 @@ error: Assignment::Assignment(Reference *p_ref, Template *p_templ) : asstype(ASS_UNKNOWN), ref(p_ref), templ(p_templ), self_ref(false), - template_restriction(TR_NONE), gen_restriction_check(false) + template_restriction(TR_NONE), gen_restriction_check(false), + in_constructor(false) { if(!ref || !templ) FATAL_ERROR("Ttcn::Assignment::Assignment"); } Assignment::Assignment(Reference *p_ref, Value *p_val) : asstype(ASS_VAR), ref(p_ref), val(p_val), self_ref(false), - template_restriction(TR_NONE), gen_restriction_check(false) + template_restriction(TR_NONE), gen_restriction_check(false), + in_constructor(false) { if(!ref || !val) FATAL_ERROR("Ttcn::Assignment::Assignment"); } @@ -8863,6 +8869,14 @@ error: case Common::Assignment::A_PAR_VAL_IN: t_ass->use_as_lvalue(*ref); // no break + case Common::Assignment::A_CONST: + if (t_ass->get_asstype() == Common::Assignment::A_CONST && + !in_constructor) { + ref->error("Reference to a variable or template variable was expected " + "instead of %s", t_ass->get_description().c_str()); + goto error; + } + // no break case Common::Assignment::A_VAR: case Common::Assignment::A_PAR_VAL_OUT: case Common::Assignment::A_PAR_VAL_INOUT: @@ -8881,6 +8895,14 @@ error: case Common::Assignment::A_PAR_TEMPL_IN: t_ass->use_as_lvalue(*ref); // no break + case Common::Assignment::A_TEMPLATE: + if (t_ass->get_asstype() == Common::Assignment::A_TEMPLATE && + !in_constructor) { + ref->error("Reference to a variable or template variable was expected " + "instead of %s", t_ass->get_description().c_str()); + goto error; + } + // no break case Common::Assignment::A_VAR_TEMPLATE: { Type::typetype_t tt = t_ass->get_Type()->get_typetype(); switch (tt) { @@ -9180,6 +9202,9 @@ error: const char *type_genname_str = type_genname.c_str(); expression_struct expr; Code::init_expr(&expr); + if (in_constructor) { + ref->set_gen_const_prefix(); + } ref->generate_code(&expr); if (rhs_copied) { @@ -9218,6 +9243,9 @@ error: // C++ equivalent of RHS is a single expression. expression_struct expr; Code::init_expr(&expr); + if (in_constructor) { + ref->set_gen_const_prefix(); + } ref->generate_code(&expr);// vu.s() if (rhs_copied) { str = mputprintf(str, "%s = %s;\n", @@ -9233,8 +9261,12 @@ error: } else { // The LHS is a single identifier. - const string& rhs_name = ref->get_refd_assignment() - ->get_genname_from_scope(ref->get_my_scope()); + Common::Assignment* refd_ass = ref->get_refd_assignment(); + string rhs_name = refd_ass->get_genname_from_scope(ref->get_my_scope()); + if (in_constructor && + refd_ass->get_asstype() == Common::Assignment::A_CONST) { + rhs_name = string("const_") + rhs_name; + } if (val->can_use_increment(ref)) { switch (val->get_optype()) { case Value::OPTYPE_ADD: @@ -9275,6 +9307,9 @@ error: const char *tmp_id_str = tmp_id.c_str(); expression_struct expr; Code::init_expr(&expr); + if (in_constructor) { + ref->set_gen_const_prefix(); + } ref->generate_code(&expr); if (rhs_copied) { @@ -9319,6 +9354,9 @@ error: // check. Skipped if conversion needed. expression_struct expr; Code::init_expr(&expr); + if (in_constructor) { + ref->set_gen_const_prefix(); + } ref->generate_code(&expr); if (rhs_copied) { str = mputprintf(str, "%s = %s;\n", @@ -9336,8 +9374,12 @@ error: } else { // LHS is a single identifier - const string& rhs_name = ref->get_refd_assignment() - ->get_genname_from_scope(ref->get_my_scope()); + Common::Assignment* refd_ass = ref->get_refd_assignment(); + string rhs_name = refd_ass->get_genname_from_scope(ref->get_my_scope()); + if (in_constructor && + refd_ass->get_asstype() == Common::Assignment::A_TEMPLATE) { + rhs_name = string("template_") + rhs_name; + } if (Common::Type::T_SEQOF == templ->get_my_governor()->get_typetype() || Common::Type::T_ARRAY == templ->get_my_governor()->get_typetype()) { str = mputprintf(str, "%s.remove_all_permutations();\n", (rhs_copied ? rhs_copy : rhs_name).c_str()); diff --git a/compiler2/ttcn3/Statement.hh b/compiler2/ttcn3/Statement.hh index 680c05a922357afa1bbe101551e89edf8eed4f6b..c69ce269cee129b60621c43302e8d100f8882f97 100644 --- a/compiler2/ttcn3/Statement.hh +++ b/compiler2/ttcn3/Statement.hh @@ -952,6 +952,7 @@ namespace Ttcn { template_restriction_t template_restriction; /** set in chk(), used by code generation */ bool gen_restriction_check; + bool in_constructor; Assignment(const Assignment& p); Assignment& operator=(const Assignment& p); @@ -965,6 +966,7 @@ namespace Ttcn { virtual void set_my_scope(Scope *p_scope); virtual void set_fullname(const string& p_fullname); virtual void dump(unsigned int level) const; + void set_in_contructor() { in_constructor = true; } private: void chk_unknown_ass(); void chk_var_ass(); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index b46e06a04eca3fd61661a511388294788f79d19e..5264f12257b507614d287a76581807eb1aed1210 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -24,6 +24,8 @@ #include "Attributes.hh" #include <errno.h> #include "Statement.hh" +#include "Templatestuff.hh" +#include "TtcnTemplate.hh" // implemented in coding_attrib_p.y extern Ttcn::ExtensionAttributes * parse_extattributes( @@ -2985,7 +2987,8 @@ namespace Ttcn { Definitions* p_members, StatementBlock* p_finally_block) : Scope(), Location(), class_id(p_class_id), 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), - members(p_members), finally_block(p_finally_block), checked(false) + members(p_members), finally_block(p_finally_block), constructor(NULL), checked(false), + default_constructor(false) { if (members == NULL) { FATAL_ERROR("ClassTypeBody::ClassTypeBody"); @@ -3004,6 +3007,8 @@ namespace Ttcn { system_ref = p.system_ref != NULL ? p.system_ref->clone() : NULL; members = p.members->clone(); finally_block = p.finally_block != NULL ? p.finally_block->clone() : NULL; + default_constructor = p.default_constructor; + constructor = default_constructor ? p.constructor->clone() : p.constructor; checked = p.checked; } @@ -3020,6 +3025,9 @@ namespace Ttcn { delete mtc_ref; delete runs_on_ref; delete system_ref; + if (default_constructor) { + delete constructor; + } } void ClassTypeBody::set_fullname(const string& p_fullname) @@ -3058,10 +3066,10 @@ namespace Ttcn { if (system_ref != NULL) { system_ref->set_my_scope(p_scope); } - //members->set_my_scope(p_scope); - /*if (finally_block != NULL) { - finally_block->set_my_scope(p_scope); - }*/ + members->set_parent_scope(this); + if (finally_block != NULL) { + finally_block->set_parent_scope(this); + } } void ClassTypeBody::dump(unsigned level) const @@ -3088,6 +3096,12 @@ namespace Ttcn { "Has" : "Doesn't have"); } + Def_Constructor* ClassTypeBody::get_constructor() + { + chk(); + return constructor; + } + bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class) const { if (this == p_class) { @@ -3193,12 +3207,87 @@ namespace Ttcn { // TODO } - members->set_parent_scope(this); members->chk_uniq(); members->chk(); + + for (size_t i = 0; i < members->get_nof_asss(); ++i) { + Common::Assignment* ass = members->get_ass_byIndex(i); + 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"); + } + break; + } + } + + if (constructor == NULL) { + // create a default constructor + Ref_pard* base_call = NULL; + FormalParList* fp_list = NULL; + 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); + } + base_call = new Ref_pard(base_class->get_scope_mod()->get_modid().clone(), + base_class->get_id()->clone(), parsed_ap_list); + } + else { + fp_list = new FormalParList; + } + StatementBlock* block = new StatementBlock(); + for (size_t i = 0; i < members->get_nof_asss(); ++i) { + Common::Assignment* member = members->get_ass_byIndex(i); + bool is_template = false; + switch (member->get_asstype()) { + case Common::Assignment::A_TEMPLATE: + case Common::Assignment::A_VAR_TEMPLATE: + is_template = true; + // no break + case Common::Assignment::A_CONST: + case Common::Assignment::A_VAR: { + // add a formal parameter for this member + Common::Identifier* id = new Common::Identifier( + Common::Identifier::ID_TTCN, string("p_") + member->get_id().get_ttcnname()); + FormalPar* fp = new FormalPar(is_template ? + Common::Assignment::A_PAR_TEMPL_IN : Common::Assignment::A_PAR_VAL_IN, + member->get_Type()->clone(), id, NULL); + fp_list->add_fp(fp); + // add a statement, that assigns the parameter's value to the member + Reference* ref_lhs = new Reference(NULL, member->get_id().clone()); + Reference* ref_rhs = new Reference(NULL, id->clone()); + Common::Value* val_rhs = new Value(Common::Value::V_REFD, ref_rhs); + Template* temp_rhs = new Template(val_rhs); + Assignment* par_ass = new Assignment(ref_lhs, temp_rhs); + Statement* stmt = new Statement(Statement::S_ASSIGNMENT, par_ass); + block->add_stmt(stmt); + break; } + default: + break; + } + } + constructor = new Def_Constructor(fp_list, base_call, block); + constructor->set_my_scope(this); + constructor->set_fullname(get_fullname() + ".<default_constructor>"); + constructor->chk(); + default_constructor = true; + } if (finally_block != NULL) { - finally_block->set_parent_scope(this); finally_block->chk(); } } @@ -3214,18 +3303,45 @@ namespace Ttcn { target->header.class_defs = mputprintf(target->header.class_defs, "class %s : public %s {\n", class_id->get_name().c_str(), base_type_name.c_str()); + // members members->generate_code(target); + if (default_constructor) { + target->source.methods = mputstr(target->source.methods, + "/* default constructor */\n"); + // code has not been generated for the constructor yet, since it's not + // in 'members' in this case + constructor->generate_code(target); + } // constructor + char* formal_par_list_str = NULL; + expression_struct_t base_call_expr; + Code::init_expr(&base_call_expr); + Ref_pard* base_call = constructor->get_base_call(); + if (base_call != NULL) { + base_call->generate_code(&base_call_expr); + } + // generate code for the base call first, so the formal parameter list + // knows which parameters are used and which aren't + formal_par_list_str = constructor->get_FormalParList()->generate_code( + memptystr()); + if (base_call_expr.expr == NULL) { + base_call_expr.expr = mprintf("%s()", base_type_name.c_str()); + } target->header.class_defs = mputprintf(target->header.class_defs, "public:\n" - "%s();\n", class_id->get_name().c_str()); + "%s(%s);\n", + class_id->get_name().c_str(), + formal_par_list_str != NULL ? formal_par_list_str : ""); target->source.methods = mputprintf(target->source.methods, - "%s::%s()\n" - ": %s()", + "%s::%s(%s)\n" + ": %s", class_id->get_name().c_str(), class_id->get_name().c_str(), - base_type_name.c_str()); + formal_par_list_str != NULL ? formal_par_list_str : "", + base_call_expr.expr); + Free(formal_par_list_str); + Code::free_expr(&base_call_expr); if (target->temp.constructor_init != NULL) { target->source.methods = mputstr(target->source.methods, target->temp.constructor_init); @@ -3233,13 +3349,18 @@ namespace Ttcn { target->temp.constructor_init = NULL; } target->source.methods = mputstr(target->source.methods, "\n{\n"); - if (target->temp.constructor != NULL) { + if (target->temp.constructor_preamble != NULL || + target->temp.constructor_block != NULL) { target->source.methods = create_location_object( target->source.methods, "FUNCTION", class_id->get_name().c_str()); target->source.methods = mputstr(target->source.methods, - target->temp.constructor); - Free(target->temp.constructor); - target->temp.constructor = NULL; + target->temp.constructor_preamble); + target->source.methods = mputstr(target->source.methods, + target->temp.constructor_block); + Free(target->temp.constructor_preamble); + Free(target->temp.constructor_block); + target->temp.constructor_preamble = NULL; + target->temp.constructor_block = NULL; } target->source.methods = mputstr(target->source.methods, "}\n\n"); diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh index f036abebfc7f2eb46d96e6d368ab806a891a98c0..a3a385569260f59b04b7a667fdba8eec9317cbf3 100644 --- a/compiler2/ttcn3/Ttcnstuff.hh +++ b/compiler2/ttcn3/Ttcnstuff.hh @@ -765,7 +765,11 @@ class ClassTypeBody : public Common::Scope, public Common::Location { Reference* system_ref; Definitions* members; StatementBlock* finally_block; + /** 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; bool checked; + bool default_constructor; /// true if the class uses a default constructor public: ClassTypeBody(Common::Identifier* p_class_id, boolean p_external, boolean p_final, @@ -783,6 +787,7 @@ public: virtual bool is_class_scope() const { return true; } virtual const ClassTypeBody* get_scope_class() const { return this; } Common::Identifier* get_id() const { return class_id; } + Def_Constructor* get_constructor(); bool is_parent_class(const ClassTypeBody* p_class) const; bool has_local_ass_withId(const Identifier& p_id); diff --git a/compiler2/ttcn3/compiler.h b/compiler2/ttcn3/compiler.h index 8564d87cfcb71ec37db605c6ece4c546e9abf686..c4c8059b4c29ed1242503b3415131819d6bfda44 100644 --- a/compiler2/ttcn3/compiler.h +++ b/compiler2/ttcn3/compiler.h @@ -69,7 +69,8 @@ extern "C" { } functions; struct { char* constructor_init; - char* constructor; + char* constructor_preamble; + char* constructor_block; } temp; struct { size_t pre_things_size; // Size of string_literals + global_vars diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn index e96b2a490fcdadc7ed5de5dcf8450a3fc1907164..f68960203dfb6838f2449773260102004b399b7f 100644 --- a/regression_test/oop/oop.ttcn +++ b/regression_test/oop/oop.ttcn @@ -17,12 +17,15 @@ type component CT { type port PT message { inout integer; } with { extension "internal" } +type record of integer IntList; + /////////////////////////////////////////////////// ///////////////////// CLASSES ///////////////////// /////////////////////////////////////////////////// type class BaseClass runs on CT mtc CT system CT { public const integer m_const := 1; + private const IntList m_const2 := { 1, 2, 3 }; /*protected*/ var charstring m_var; private template octetstring m_temp := ? length (1..4); public var template float m_var_temp; @@ -33,17 +36,17 @@ type class BaseClass runs on CT mtc CT system CT { //public template integer m_temp_pard(integer p) := p; // parameterized template members not supported // this would also be the implicit constructor (constructors are not yet implemented): - create(integer p_const, charstring p_var, - template octetstring p_temp, template float p_var_temp, - PT p_port, timer p_timer) { + create(integer p_const, IntList p_const2, charstring p_var, + template octetstring p_temp, template float p_var_temp) { m_const := p_const; m_const := 2; m_var := p_var; + m_const2[2] := p_const2[0]; m_temp := p_temp; m_temp := *; m_var_temp := p_var_temp; - m_port := p_port; - m_timer := p_timer; + //m_port := p_port; + //m_timer := p_timer; } public function f(in integer x) return integer { @@ -60,16 +63,16 @@ finally { log(m_var); } -type class SubClass extends BaseClass { - const octetstring m_const2 := 'AB'O; // the parser currently doesn't accept constants without initial value - - create(integer p_const := 1, charstring p_var, - template octetstring p_temp, template float p_var_temp, - PT p_port, timer p_timer) - : BaseClass(p_const, p_var, p_temp, p_var_temp, p_port, p_timer) { - m_const2 := 'FFFF'O; +type class SubClass extends BaseClass { + create(integer p_const := 1, IntList p_const2, charstring p_var, + template octetstring p_temp, template float p_var_temp) + : BaseClass(p_const, p_const2, p_var, p_temp, p_var_temp) { + m_const3 := 'FFFF'O; + m_var := m_var & "x"; } + const octetstring m_const3 := 'AB'O; // the parser currently doesn't accept constants without initial value + public function f(in integer x) return integer { //return super.f(x) - 1; // not supported yet m_var := m_var & int2str(x); @@ -78,10 +81,14 @@ type class SubClass extends BaseClass { } type class @final FinalClass extends SubClass { + private const integer m_final_const := 1; + private template charstring m_final_temp := ? length (1..4); + private var float m_final_var; + private var template octetstring m_final_var_temp; public function @final f(in integer x) return integer { //return super.super.f(x) + 1; // not supported yet m_var := m_var & int2str(x); - return x + 1; + return x + m_final_const; } } @@ -94,6 +101,10 @@ type class @abstract AbstractClass { } type class ConcreteClass extends AbstractClass { + create(octetstring p_const := 'AB'O) { + // for compilation only, to make sure there are no name clases between parameter default values + log(p_const); + } public function f_abs(inout integer x) return boolean { x := x + 1; return x > 0;