Chain class instance constructors with arguments.

This commit is contained in:
Stephen Williams 2013-11-03 15:20:30 -08:00
parent 0157a156fb
commit d192f545ac
13 changed files with 144 additions and 19 deletions

View File

@ -20,7 +20,7 @@
# include "PClass.h"
PClass::PClass(perm_string name, LexicalScope*parent)
: PScopeExtra(name, parent)
: PScopeExtra(name, parent), type(0), chain(0)
{
}

View File

@ -24,6 +24,8 @@
# include "StringHeap.h"
# include <iostream>
class PChainConstructor;
/*
* SystemVerilog supports class declarations with their own lexical
* scope, etc. The parser arranges for these to be created and
@ -40,6 +42,7 @@ class PClass : public PScopeExtra, public LineInfo {
public:
class_type_t*type;
PChainConstructor*chain;
};
#endif

View File

@ -558,7 +558,8 @@ class PENewClass : public PExpr {
private:
NetExpr* elaborate_expr_constructor_(Design*des, NetScope*scope,
const netclass_t*ctype,
NetExpr*obj, unsigned flags) const;
NetExpr*obj, unsigned flags,
const netclass_t*derived) const;
private:
std::vector<PExpr*>parms_;

View File

@ -19,6 +19,7 @@
# include "config.h"
# include "PTask.h"
# include "Statement.h"
# include <cassert>
PFunction::PFunction(perm_string name, LexicalScope*parent, bool is_auto__)
@ -43,3 +44,17 @@ void PFunction::set_return(const data_type_t*t)
{
return_type_ = t;
}
PChainConstructor* PFunction::extract_chain_constructor()
{
PChainConstructor*res = 0;
if (res = dynamic_cast<PChainConstructor*> (statement_)) {
statement_ = 0;
} else if (PBlock*blk = dynamic_cast<PBlock*>(statement_)) {
res = blk->extract_chain_constructor();
}
return res;
}

View File

@ -29,6 +29,7 @@ class Design;
class NetExpr;
class NetNet;
class NetScope;
class PChainConstructor;
class PWire;
class Statement;
class PExpr;
@ -117,6 +118,11 @@ class PFunction : public PTaskFunc {
inline Statement* get_statement() { return statement_; }
// 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.
PChainConstructor*extract_chain_constructor();
void elaborate_scope(Design*des, NetScope*scope) const;
/* elaborate the ports and return value. */

View File

@ -115,6 +115,21 @@ PBlock::~PBlock()
delete list_[idx];
}
PChainConstructor* PBlock::extract_chain_constructor()
{
if (list_.empty())
return 0;
if (PChainConstructor*res = dynamic_cast<PChainConstructor*> (list_[0])) {
for (size_t idx = 0 ; idx < list_.size()-1 ; idx += 1)
list_[idx] = list_[idx+1];
list_.resize(list_.size()-1);
return res;
}
return 0;
}
void PBlock::set_join_type(PBlock::BL_TYPE type)
{
assert(bl_type_ == BL_PAR);
@ -206,6 +221,21 @@ PCAssign::~PCAssign()
delete expr_;
}
PChainConstructor::PChainConstructor(const list<PExpr*>&parms)
: parms_(parms.size())
{
list<PExpr*>::const_iterator cur = parms.begin();
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
parms_[idx] = *cur;
++cur;
}
assert(cur == parms.end());
}
PChainConstructor::~PChainConstructor()
{
}
PCondit::PCondit(PExpr*ex, Statement*i, Statement*e)
: expr_(ex), if_(i), else_(e)
{

View File

@ -31,6 +31,7 @@
# include "HName.h"
# include "LineInfo.h"
class PExpr;
class PChainConstructor;
class PPackage;
class Statement;
class PEventStatement;
@ -181,6 +182,11 @@ class PBlock : public PScope, public Statement {
BL_TYPE bl_type() const { return bl_type_; }
// This is only used if this block is the statement list for a
// constructor. We look for a PChainConstructor as the first
// statement, and if it is there, extract it.
PChainConstructor*extract_chain_constructor();
// If the bl_type() is BL_PAR, it is possible to replace it
// with JOIN_NONE or JOIN_ANY. This is to help the parser.
void set_join_type(BL_TYPE);
@ -272,6 +278,25 @@ class PCAssign : public Statement {
PExpr*expr_;
};
/*
* This represents the syntax "super.new(...)". This is not really an
* executable statement, but the elaborator will handle these
* specially and will remove them from the statement stream. If any
*/
class PChainConstructor : public Statement {
public:
PChainConstructor(const list<PExpr*>&parms);
~PChainConstructor();
virtual void dump(ostream&out, unsigned ind) const;
inline const std::vector<PExpr*>& chain_args(void) const
{ return parms_; }
private:
std::vector<PExpr*> parms_;
};
class PCondit : public Statement {
public:

View File

@ -4679,13 +4679,21 @@ 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
* initializers in front of an explicit constructor.
*
* The derived argument is the type of the class derived from the
* current one. This is used to get chained constructor arguments, if necessary.
*/
NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
const netclass_t*ctype,
NetExpr*obj, unsigned flags) const
NetExpr*obj, unsigned flags,
const netclass_t*derived) 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);
obj = elaborate_expr_constructor_(des, scope, super_class, obj, flags, ctype);
}
@ -4710,10 +4718,18 @@ 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<PExpr*>&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 (parms_.size() > 0) {
if (use_parms.size() > 0) {
cerr << get_fileline() << ": error: "
<< "Class " << ctype->get_name()
<< " has no constructor, but you passed " << parms_.size()
@ -4730,9 +4746,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 ((parms_.size()+1) > def->port_count()) {
if ((use_parms.size()+1) > def->port_count()) {
cerr << get_fileline() << ": error: Parm count mismatch"
<< " passing " << parms_.size() << " arguments "
<< " passing " << use_parms.size() << " arguments "
<< " to constructor expecting " << (def->port_count()-1)
<< " arguments." << endl;
des->errors += 1;
@ -4745,9 +4761,10 @@ 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 <= parms_.size() && parms_[idx-1]) {
PExpr*tmp = parms_[idx-1];
parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->net_type(),
if (idx <= use_parms.size() && use_parms[idx-1]) {
PExpr*tmp = use_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);
@ -4801,7 +4818,7 @@ NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope,
// allocation alone.
const netclass_t*ctype = dynamic_cast<const netclass_t*> (ntype);
obj = elaborate_expr_constructor_(des, scope, ctype, obj, flags);
obj = elaborate_expr_constructor_(des, scope, ctype, obj, flags, 0);
return obj;
}

View File

@ -311,6 +311,12 @@ static void blend_class_constructors(PClass*pclass)
if (iter_new == pclass->funcs.end())
return;
// 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.
pclass->chain = iter_new->second->extract_chain_constructor();
map<perm_string,PFunction*>::iterator iter_new2 = pclass->funcs.find(new2);
if (iter_new2 == pclass->funcs.end())
return;
@ -374,7 +380,10 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
}
}
netclass_t*use_class = new netclass_t(use_type->name, use_base_class);
const static vector<PExpr*>no_args;
const vector<PExpr*>&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);
// Class scopes have no parent scope, because references are
// not allowed to escape a class method.

View File

@ -23,8 +23,8 @@
using namespace std;
netclass_t::netclass_t(perm_string name, netclass_t*sup)
: name_(name), super_(sup), class_scope_(0)
netclass_t::netclass_t(perm_string name, netclass_t*sup, const vector<PExpr*>&chain_args)
: name_(name), super_(sup), chain_args_(chain_args), class_scope_(0)
{
}

View File

@ -30,10 +30,11 @@ class Design;
class NetNet;
class NetScope;
class PClass;
class PExpr;
class netclass_t : public ivl_type_s {
public:
netclass_t(perm_string class_name, netclass_t*par);
netclass_t(perm_string class_name, netclass_t*par, const vector<PExpr*>&pchain_args);
~netclass_t();
// Set the property of the class during elaboration. Set the
@ -45,6 +46,9 @@ 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<PExpr*>& 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;
@ -99,8 +103,10 @@ class netclass_t : public ivl_type_s {
private:
perm_string name_;
// If this is derived from another base class, point to it
// here.
// here. The super constructor may take arguments, and the
// chain_parms_ are those arguments.
netclass_t*super_;
std::vector<PExpr*> chain_args_;
// Map properrty names to property table index.
std::map<perm_string,size_t> properties_;
// Vector of properties.

View File

@ -5853,9 +5853,9 @@ statement_item /* This is roughly statement_item in the LRM */
out. */
| implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' ';'
{ yyerror(@1, "sorry: Calls to superclass constructor not supported.");
yyerrok;
$$ = new PNoop;
{ PChainConstructor*tmp = new PChainConstructor(*$5);
FILE_NAME(tmp, @3);
$$ = tmp;
}
| hierarchy_identifier '(' error ')' ';'
{ yyerror(@3, "error: Syntax error in task arguments.");

View File

@ -821,6 +821,19 @@ void PCase::dump(ostream&out, unsigned ind) const
out << setw(ind) << "" << "endcase" << endl;
}
void PChainConstructor::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "super.new(";
if (parms_.size() > 0) {
if (parms_[0]) out << *parms_[0];
}
for (size_t idx = 1 ; idx < parms_.size() ; idx += 1) {
out << ", ";
if (parms_[idx]) out << *parms_[idx];
}
out << ");" << endl;
}
void PCondit::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "if (" << *expr_ << ")" << endl;