diff --git a/PTask.h b/PTask.h index cbd2d7e2a..a79e5f95c 100644 --- a/PTask.h +++ b/PTask.h @@ -110,6 +110,8 @@ class PFunction : public PTaskFunc { void set_statement(Statement *s); void set_return(const data_type_t*t); + inline Statement* get_statement() { return statement_; } + void elaborate_scope(Design*des, NetScope*scope) const; /* elaborate the ports and return value. */ diff --git a/Statement.cc b/Statement.cc index 79d63fb63..5ce819311 100644 --- a/Statement.cc +++ b/Statement.cc @@ -21,6 +21,7 @@ # include "Statement.h" # include "PExpr.h" +# include "ivl_assert.h" Statement::~Statement() { @@ -126,6 +127,17 @@ void PBlock::set_statement(const vector&st) list_ = st; } +void PBlock::push_statement_front(Statement*that) +{ + ivl_assert(*this, bl_type_==BL_SEQ); + + list_.resize(list_.size()+1); + for (size_t idx = list_.size()-1 ; idx > 0 ; idx -= 1) + list_[idx] = list_[idx-1]; + + list_[0] = that; +} + PCallTask::PCallTask(const pform_name_t&n, const list&p) : package_(0), path_(n), parms_(p.size()) { diff --git a/Statement.h b/Statement.h index 43f299443..82289be76 100644 --- a/Statement.h +++ b/Statement.h @@ -186,6 +186,10 @@ class PBlock : public PScope, public Statement { void set_statement(const std::vector&st); + // Copy the statement from that block to the front of this + // block. + void push_statement_front(Statement*that); + virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; diff --git a/elab_scope.cc b/elab_scope.cc index 91c1b9fb5..7c9ddf3c3 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -293,8 +293,60 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } -static void elaborate_scope_class(Design*des, NetScope*scope, - PClass*pclass) +/* + * If the pclass includes an implicit and explicit constructor, then + * merge the implicit constructor into the explicit constructor as + * statements in the beginning. + * + * This is not necessary for proper functionality, it is an + * optimization, so we can easily give up if it doesn't seem like it + * will obviously work. + */ +static void blend_class_constructors(PClass*pclass) +{ + perm_string new1 = perm_string::literal("new"); + perm_string new2 = perm_string::literal("new@"); + + map::iterator iter_new = pclass->funcs.find(new1); + if (iter_new == pclass->funcs.end()) + return; + + map::iterator iter_new2 = pclass->funcs.find(new2); + if (iter_new2 == pclass->funcs.end()) + return; + + PFunction*use_new = iter_new->second; + PFunction*use_new2 = iter_new2->second; + + // These constructors must be methods of the same class. + ivl_assert(*use_new, use_new->method_of() == use_new2->method_of()); + + Statement*def_new = use_new->get_statement(); + Statement*def_new2 = use_new2->get_statement(); + + // If either constructor has no definition, then give up. This + // might happen, for example, during parse errors or other + // degenerate situations. + if (def_new==0 || def_new2==0) + return; + + PBlock*blk_new = dynamic_cast (def_new); + + // For now, only do this if the functions are defined by + // statement blocks. That should be true by definition for + // implicit constructors, and common for explicit constructors. + if (blk_new==0) + return; + + ivl_assert(*blk_new, blk_new ->bl_type()==PBlock::BL_SEQ); + + blk_new->push_statement_front(def_new2); + + pclass->funcs.erase(iter_new2); + delete use_new2; +} + +static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) { class_type_t*use_type = pclass->type; netclass_t*use_class = new netclass_t(use_type->name); @@ -367,8 +419,10 @@ static void elaborate_scope_class(Design*des, NetScope*scope, static void elaborate_scope_classes(Design*des, NetScope*scope, const vector&classes) { - for (size_t idx = 0 ; idx < classes.size() ; idx += 1) + for (size_t idx = 0 ; idx < classes.size() ; idx += 1) { + blend_class_constructors(classes[idx]); elaborate_scope_class(des, scope, classes[idx]); + } } static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc,