Chain class instance constructors with arguments.
This commit is contained in:
parent
0157a156fb
commit
d192f545ac
|
|
@ -20,7 +20,7 @@
|
|||
# include "PClass.h"
|
||||
|
||||
PClass::PClass(perm_string name, LexicalScope*parent)
|
||||
: PScopeExtra(name, parent)
|
||||
: PScopeExtra(name, parent), type(0), chain(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
3
PClass.h
3
PClass.h
|
|
@ -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
|
||||
|
|
|
|||
3
PExpr.h
3
PExpr.h
|
|
@ -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_;
|
||||
|
|
|
|||
15
PFunction.cc
15
PFunction.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
6
PTask.h
6
PTask.h
|
|
@ -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. */
|
||||
|
|
|
|||
30
Statement.cc
30
Statement.cc
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
25
Statement.h
25
Statement.h
|
|
@ -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:
|
||||
|
|
|
|||
35
elab_expr.cc
35
elab_expr.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
10
netclass.h
10
netclass.h
|
|
@ -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.
|
||||
|
|
|
|||
6
parse.y
6
parse.y
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue