diff --git a/PClass.cc b/PClass.cc index b84d424e1..ba44d754a 100644 --- a/PClass.cc +++ b/PClass.cc @@ -20,7 +20,7 @@ # include "PClass.h" PClass::PClass(perm_string name, LexicalScope*parent) -: PScopeExtra(name, parent), type(0), chain(0) +: PScopeExtra(name, parent), type(0) { } diff --git a/PClass.h b/PClass.h index edeea0c5c..9282c094d 100644 --- a/PClass.h +++ b/PClass.h @@ -42,7 +42,6 @@ class PClass : public PScopeExtra, public LineInfo { public: class_type_t*type; - PChainConstructor*chain; }; #endif diff --git a/PExpr.h b/PExpr.h index 88b2a8382..7121e00f1 100644 --- a/PExpr.h +++ b/PExpr.h @@ -558,8 +558,7 @@ class PENewClass : public PExpr { private: NetExpr* elaborate_expr_constructor_(Design*des, NetScope*scope, const netclass_t*ctype, - NetExpr*obj, unsigned flags, - const netclass_t*derived) const; + NetExpr*obj, unsigned flags) const; private: std::vectorparms_; diff --git a/PFunction.cc b/PFunction.cc index f166e35b5..275a0e69b 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -21,6 +21,7 @@ # include "PTask.h" # include "Statement.h" # include +# include "ivl_assert.h" PFunction::PFunction(perm_string name, LexicalScope*parent, bool is_auto__) : PTaskFunc(name, parent), statement_(0) @@ -33,13 +34,37 @@ PFunction::~PFunction() { } -void PFunction::set_statement(Statement*s, bool rewrite_ok) +void PFunction::set_statement(Statement*s) { assert(s != 0); - assert(statement_ == 0 || rewrite_ok&&statement_); + assert(statement_ == 0); statement_ = s; } +void PFunction::push_statement_front(Statement*stmt) +{ + // This can only happen after the statement is initially set. + ivl_assert(*this, statement_); + + // Get the PBlock of the statement. If it is not a PBlock, + // then create one to wrap the existing statement and the new + // statement that we're pushing. + PBlock*blk = dynamic_cast (statement_); + if (blk == 0) { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + tmp->set_line(*this); + vectortmp_list(1); + tmp_list[0] = statement_; + tmp->set_statement(tmp_list); + + statement_ = tmp; + blk = tmp; + } + + // Now do the push. + blk->push_statement_front(stmt); +} + void PFunction::set_return(const data_type_t*t) { return_type_ = t; diff --git a/PTask.h b/PTask.h index c0898483d..87b0df958 100644 --- a/PTask.h +++ b/PTask.h @@ -113,11 +113,16 @@ class PFunction : public PTaskFunc { explicit PFunction(perm_string name, LexicalScope*parent, bool is_auto); ~PFunction(); - void set_statement(Statement *s, bool rewrite_flag =false); + void set_statement(Statement *s); void set_return(const data_type_t*t); inline Statement* get_statement() { return statement_; } + // Push this statement to the front of the existing + // definition. If the statement is a simple statement, make a + // block to contain the statements. + void push_statement_front(Statement*stmt); + // This is only used if this function is a constructor. In // that case, this method looks for a PChainConstructor in the // statement and extracts it if found. diff --git a/Statement.h b/Statement.h index 7c133f528..60ab166f6 100644 --- a/Statement.h +++ b/Statement.h @@ -288,6 +288,7 @@ class PChainConstructor : public Statement { PChainConstructor(const list&parms); ~PChainConstructor(); + virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; inline const std::vector& chain_args(void) const diff --git a/elab_expr.cc b/elab_expr.cc index 9578c8eef..53041e324 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -4677,7 +4677,7 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) /* * This elaborates the constructor for a class. This arranges for the - * call of parent class constructors, if present, and also + * call of class constructor, if present, and also * initializers in front of an explicit constructor. * * The derived argument is the type of the class derived from the @@ -4685,18 +4685,8 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) */ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, const netclass_t*ctype, - NetExpr*obj, unsigned flags, - const netclass_t*derived) const + NetExpr*obj, unsigned flags) const { - // If there is a super-class, then call the super-class - // constructors first. The results of the current class - // constructors cannot effect the superclass, so this is the - // right order of events. - if (const netclass_t*super_class = ctype->get_super()) { - obj = elaborate_expr_constructor_(des, scope, super_class, obj, flags, ctype); - } - - // 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. @@ -4718,18 +4708,11 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, obj = tmp; } - // The parameters for the constructor are the arguments of the - // new(...) expression, unless we are recursing, in which case - // we use the chained arguments. Note that the arguments to - // the chained constructor must be elaborated in the scope of - // the subclass (so that arguments can be passed down) so also - // select which scope we are going to use. - const vector&use_parms = derived? derived->get_chain_args() : parms_; NetScope*new_scope = ctype->method_from_name(perm_string::literal("new")); if (new_scope == 0) { // No constructor. - if (use_parms.size() > 0) { + if (parms_.size() > 0) { cerr << get_fileline() << ": error: " << "Class " << ctype->get_name() << " has no constructor, but you passed " << parms_.size() @@ -4746,9 +4729,9 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, // Are there too many arguments passed to the function. If so, // generate an error message. The case of too few arguments // will be handled below, when we run out of arguments. - if ((use_parms.size()+1) > def->port_count()) { + if ((parms_.size()+1) > def->port_count()) { cerr << get_fileline() << ": error: Parm count mismatch" - << " passing " << use_parms.size() << " arguments " + << " passing " << parms_.size() << " arguments " << " to constructor expecting " << (def->port_count()-1) << " arguments." << endl; des->errors += 1; @@ -4761,8 +4744,8 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, int parm_errors = 0; for (size_t idx = 1 ; idx < parms.size() ; idx += 1) { // While there are default arguments, check them. - if (idx <= use_parms.size() && use_parms[idx-1]) { - PExpr*tmp = use_parms[idx-1]; + if (idx <= parms_.size() && parms_[idx-1]) { + PExpr*tmp = parms_[idx-1]; parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->net_type(), def->port(idx)->data_type(), @@ -4818,7 +4801,7 @@ NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, // allocation alone. const netclass_t*ctype = dynamic_cast (ntype); - obj = elaborate_expr_constructor_(des, scope, ctype, obj, flags, 0); + obj = elaborate_expr_constructor_(des, scope, ctype, obj, flags); return obj; } diff --git a/elab_scope.cc b/elab_scope.cc index 70072915a..5f8d980e0 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -331,11 +331,19 @@ static void blend_class_constructors(PClass*pclass) // While we're here, look for a super.new() call. If we find // it, strip it out of the constructor and set it aside for // when we actually call the chained constructor. - if (use_new) - pclass->chain = use_new->extract_chain_constructor(); - else - pclass->chain = 0; + PChainConstructor*chain_new = use_new? use_new->extract_chain_constructor() : 0; + // If we do not have an explicit constructor chain, but there + // is a parent class, then create an implicit chain. + if (chain_new==0 && pclass->type->base_type!=0) { + listtmp_parms; + chain_new = new PChainConstructor(tmp_parms); + chain_new->set_line(*pclass); + } + + // If there are both an implicit and explicit constructor, + // then blend the implicit constructor into the explicit + // constructor. This eases the task for the elaborator later. if (use_new && use_new2) { // These constructors must be methods of the same class. ivl_assert(*use_new, use_new->method_of() == use_new2->method_of()); @@ -351,37 +359,23 @@ static void blend_class_constructors(PClass*pclass) use_new->set_statement(def_new); } - PBlock*blk_new = dynamic_cast (def_new); - - // If the statement for the constructor is not a block, - // then convert it into a block so that we can do other - // manipulations. - if (blk_new==0) { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - tmp->set_line(*def_new); - - vectortmp_list(1); - tmp_list[0] = def_new; - tmp->set_statement(tmp_list); - blk_new = tmp; - - use_new->set_statement(blk_new, true); - } - - ivl_assert(*blk_new, blk_new ->bl_type()==PBlock::BL_SEQ); - - if (def_new2) { - blk_new->push_statement_front(def_new2); - } + if (def_new2) use_new->push_statement_front(def_new2); // Now the implicit initializations are all built into // the constructor. Delete the "new@" constructor. pclass->funcs.erase(iter_new2); delete use_new2; use_new2 = 0; - } + if (chain_new) { + if (use_new2) { + use_new2->push_statement_front(chain_new); + } else { + use_new->push_statement_front(chain_new); + } + chain_new = 0; + } } static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) @@ -412,10 +406,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) } } - const static vectorno_args; - const vector&use_chain_args = (pclass&&pclass->chain)? pclass->chain->chain_args() : no_args; - - netclass_t*use_class = new netclass_t(use_type->name, use_base_class, use_chain_args); + netclass_t*use_class = new netclass_t(use_type->name, use_base_class); // Class scopes have no parent scope, because references are // not allowed to escape a class method. diff --git a/elaborate.cc b/elaborate.cc index cfede6a21..456295799 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3027,6 +3027,109 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const return res; } +NetProc* PChainConstructor::elaborate(Design*des, NetScope*scope) const +{ + assert(scope); + + if (debug_elaborate) { + cerr << get_fileline() << ": PChainConstructor::elaborate: " + << "Elaborate constructor chain in scope=" << scope_path(scope) << endl; + } + + // The scope is the .new function, so scope->parent() + // is the class. Use that to get the class type that we are + // constructing. + NetScope*scope_class = scope->parent(); + const netclass_t*class_this = scope_class->class_def(); + ivl_assert(*this, class_this); + + // We also need the super-class. + const netclass_t*class_super = class_this->get_super(); + if (class_super == 0) { + cerr << get_fileline() << ": error: " + << "Class " << class_this->get_name() + << " has no parent class for super.new constructor chaining." << endl; + des->errors += 1; + NetBlock*tmp = new NetBlock(NetBlock::SEQU, 0); + tmp->set_line(*this); + return tmp; + } + + // Need the "this" variable for the current constructor. We're + // going to pass this to the chained constructor. + NetNet*var_this = scope->find_signal(perm_string::literal("@")); + + // If super.new is an implicit constructor, then there are no + // arguments (other then "this" to worry about, so make a + // NetEUFunc and there we go. + if (NetScope*new_scope = class_super->method_from_name(perm_string::literal("new@"))) { + NetESignal*eres = new NetESignal(var_this); + vector parms(1); + parms[0] = eres; + NetEUFunc*tmp = new NetEUFunc(scope, new_scope, eres, parms, true); + tmp->set_line(*this); + + NetAssign_*lval_this = new NetAssign_(var_this); + NetAssign*stmt = new NetAssign(lval_this, tmp); + stmt->set_line(*this); + return stmt; + } + + // If super.new(...) is a user defined constructor, then call + // it. This is a bit more complicated because there may be arguments. + if (NetScope*new_scope = class_super->method_from_name(perm_string::literal("new"))) { + + int missing_parms = 0; + NetFuncDef*def = new_scope->func_def(); + ivl_assert(*this, def); + + NetESignal*eres = new NetESignal(var_this); + vector parms (def->port_count()); + parms[0] = eres; + + for (size_t idx = 1 ; idx < parms.size() ; idx += 1) { + if (idx <= parms_.size() && parms_[idx-1]) { + PExpr*tmp = parms_[idx-1]; + parms[idx] = elaborate_rval_expr(des, scope, + def->port(idx)->net_type(), + def->port(idx)->data_type(), + def->port(idx)->vector_width(), + tmp, false); + continue; + } + + if (NetExpr*tmp = def->port_defe(idx)) { + parms[idx] = tmp; + continue; + } + + missing_parms += 1; + parms[idx] = 0; + } + + if (missing_parms) { + cerr << get_fileline() << ": error: " + << "Missing " << missing_parms + << " arguments to constructor " << scope_path(new_scope) << "." << endl; + des->errors += 1; + } + + NetEUFunc*tmp = new NetEUFunc(scope, new_scope, eres, parms, true); + tmp->set_line(*this); + + NetAssign_*lval_this = new NetAssign_(var_this); + NetAssign*stmt = new NetAssign(lval_this, tmp); + stmt->set_line(*this); + return stmt; + } + + // There is no constructor at all in the parent, so skip it. + NetBlock*tmp = new NetBlock(NetBlock::SEQU, 0); + tmp->set_line(*this); + return tmp; + return 0; +} + NetProc* PCondit::elaborate(Design*des, NetScope*scope) const { assert(scope); diff --git a/netclass.cc b/netclass.cc index c460c24bf..f302585d1 100644 --- a/netclass.cc +++ b/netclass.cc @@ -23,8 +23,8 @@ using namespace std; -netclass_t::netclass_t(perm_string name, netclass_t*sup, const vector&chain_args) -: name_(name), super_(sup), chain_args_(chain_args), class_scope_(0) +netclass_t::netclass_t(perm_string name, netclass_t*sup) +: name_(name), super_(sup), class_scope_(0) { } diff --git a/netclass.h b/netclass.h index 63552753d..bdde11058 100644 --- a/netclass.h +++ b/netclass.h @@ -34,7 +34,7 @@ class PExpr; class netclass_t : public ivl_type_s { public: - netclass_t(perm_string class_name, netclass_t*par, const vector&pchain_args); + netclass_t(perm_string class_name, netclass_t*par); ~netclass_t(); // Set the property of the class during elaboration. Set the @@ -46,9 +46,6 @@ class netclass_t : public ivl_type_s { // is used for the elaboration of methods (tasks/functions). void set_class_scope(NetScope*cscope); - inline const std::vector& get_chain_args(void) const - { return chain_args_; } - // As an ivl_type_s object, the netclass is always an // ivl_VT_CLASS object. ivl_variable_type_t base_type() const; @@ -103,11 +100,9 @@ class netclass_t : public ivl_type_s { private: perm_string name_; // If this is derived from another base class, point to it - // here. The super constructor may take arguments, and the - // chain_parms_ are those arguments. + // here. netclass_t*super_; - std::vector chain_args_; - // Map properrty names to property table index. + // Map property names to property table index. std::map properties_; // Vector of properties. struct prop_t {