diff --git a/elab_expr.cc b/elab_expr.cc index dc24c0294..7d5fbca09 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -4464,13 +4464,35 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, ivl_type_t ntype, unsigned) const { - NetENew*obj = new NetENew(ntype); + NetExpr*obj = new NetENew(ntype); obj->set_line(*this); // Find the constructor for the class. If there is no // constructor then the result of this expression is the // allocation alone. const netclass_t*ctype = dynamic_cast (ntype); + + // If there is an initializer function, then pass the object + // through that function first. Note tha the initializer + // function has no arguments other then the object itself. + if (NetScope*new1_scope = ctype->method_from_name(perm_string::literal("new@"))) { + NetFuncDef*def1 = new1_scope->func_def(); + ivl_assert(*this, def1); + ivl_assert(*this, def1->port_count()==1); + vector parms1 (1); + parms1[0] = obj; + + // The return value of the initializer is the "this" + // variable, instead of the "new&" scope name. + NetNet*res1 = new1_scope->find_signal(perm_string::literal("@")); + ivl_assert(*this, res1); + + NetESignal*eres = new NetESignal(res1); + NetEUFunc*tmp = new NetEUFunc(scope, new1_scope, eres, parms1, true); + tmp->set_line(*this); + obj = tmp; + } + NetScope*new_scope = ctype->method_from_name(perm_string::literal("new")); if (new_scope == 0) { // No constructor. diff --git a/elab_scope.cc b/elab_scope.cc index 285122d3f..91c1b9fb5 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -304,12 +304,6 @@ static void elaborate_scope_class(Design*des, NetScope*scope, << "Elaborate scope class " << pclass->pscope_name() << endl; } - if (! use_type->initialize.empty()) { - cerr << pclass->get_fileline() << ": sorry: " - << "Class property initializers not supported." << endl; - des->errors += 1; - } - // Class scopes have no parent scope, because references are // not allowed to escape a class method. NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()), diff --git a/elab_sig.cc b/elab_sig.cc index 35e867426..b9701ebdf 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -538,7 +538,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const elaborate_sig_wires_(des, scope); NetNet*ret_sig; - if (gn_system_verilog() && fname == "new") { + if (gn_system_verilog() && fname=="new" || fname=="new@") { // Special case: this is a constructor, so the return // signal is also the first argument. For example, the // source code for the definition may be: diff --git a/parse.y b/parse.y index 70eb07bd3..f436f28b5 100644 --- a/parse.y +++ b/parse.y @@ -673,7 +673,7 @@ class_declaration /* IEEE1800-2005: A.1.2 */ } class_items_opt K_endclass { // Process a class. - pform_end_class_declaration(); + pform_end_class_declaration(@8); } class_declaration_endlabel_opt { // Wrap up the class. diff --git a/pform.h b/pform.h index e8c656fb8..a6f24e439 100644 --- a/pform.h +++ b/pform.h @@ -189,7 +189,7 @@ extern void pform_class_property(const struct vlltype&loc, extern void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net); extern void pform_set_constructor_return(PFunction*net); -extern void pform_end_class_declaration(void); +extern void pform_end_class_declaration(const struct vlltype&loc); extern void pform_make_udp(perm_string name, list*parms, std::vector*decl, list*table, diff --git a/pform_pclass.cc b/pform_pclass.cc index 61698f7c1..c0ac9de55 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -111,9 +111,29 @@ PFunction*pform_push_constructor_scope(const struct vlltype&loc) return func; } -void pform_end_class_declaration(void) +void pform_end_class_declaration(const struct vlltype&loc) { assert(pform_cur_class); + + // If there were initializer statements, then collect them + // into an implicit constructor function. + if (! pform_cur_class->type->initialize.empty()) { + PFunction*func = pform_push_function_scope(loc, "new@", true); + func->set_ports(0); + pform_set_constructor_return(func); + pform_set_this_class(loc, func); + + class_type_t*use_class = pform_cur_class->type; + if (use_class->initialize.size() == 1) { + func->set_statement(use_class->initialize.front()); + } else { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + tmp->set_statement(use_class->initialize); + func->set_statement(tmp); + } + pform_pop_scope(); + } + pform_cur_class = 0; pform_pop_scope(); }