Add support for handling `super` keyword
SystemVerilog allows to use the `super` keyword to access properties and methods of a base class. This is useful if there is for example an identifier with the same name in the current class as in the base class and the code wants to access the base class identifier. To support this a bit of refactoring is required. Currently properties are internally referenced by name, this does not work if there are multiple properties of the same. Instead reference properties always by index. In addition when looking up an identifier that resolves to an object return both the type and the object itself. This is necessary since both `this` and `super` resolve to the same object, but each with a different type. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
7188f7b210
commit
c0adbd0deb
4
PExpr.h
4
PExpr.h
|
|
@ -417,6 +417,7 @@ class PEIdent : public PExpr {
|
|||
index_component_t::ctype_t,
|
||||
bool need_const_idx) const;
|
||||
NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*,
|
||||
const netclass_t *class_type,
|
||||
NetNet*,
|
||||
pform_name_t) const;
|
||||
bool elaborate_lval_net_packed_member_(Design*, NetScope*,
|
||||
|
|
@ -511,8 +512,7 @@ class PEIdent : public PExpr {
|
|||
unsigned flags) const;
|
||||
|
||||
NetExpr *elaborate_expr_class_field_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
const name_component_t&comp,
|
||||
const symbol_search_results &sr,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
|
||||
|
|
|
|||
82
elab_expr.cc
82
elab_expr.cc
|
|
@ -1480,8 +1480,7 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*,
|
|||
// and the scope is the scope where the instance lives. The class method
|
||||
// in turn defines it's own scope. Use that to find the return value.
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_CLASS) {
|
||||
NetNet*net = search_results.net;
|
||||
const netclass_t*class_type = net->class_type();
|
||||
const netclass_t *class_type = dynamic_cast<const netclass_t*>(search_results.type);
|
||||
ivl_assert(*this, class_type);
|
||||
NetScope*method = class_type->method_from_name(method_name);
|
||||
|
||||
|
|
@ -2536,12 +2535,26 @@ static NetExpr* class_static_property_expression(const LineInfo*li,
|
|||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
const name_component_t&comp,
|
||||
const symbol_search_results &sr,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const
|
||||
{
|
||||
const netclass_t*class_type = net->class_type();
|
||||
|
||||
const netclass_t *class_type = dynamic_cast<const netclass_t*>(sr.type);
|
||||
const name_component_t comp = sr.path_tail.front();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||
<< "Ident " << sr.path_head
|
||||
<< " look for property " << comp << endl;
|
||||
}
|
||||
|
||||
if (sr.path_tail.size() > 1) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Nested member path not yet supported for class properties."
|
||||
<< endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ivl_type_t par_type;
|
||||
const NetExpr *par_val = class_type->get_parameter(des, comp.name, par_type);
|
||||
|
|
@ -2562,7 +2575,7 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
|||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": check_for_class_property: "
|
||||
<< "Property " << comp.name
|
||||
<< " of net " << net->name()
|
||||
<< " of net " << sr.net->name()
|
||||
<< ", context scope=" << scope_path(scope)
|
||||
<< endl;
|
||||
}
|
||||
|
|
@ -2582,7 +2595,7 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
|||
prop_name);
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(net, comp.name);
|
||||
NetEProperty*tmp = new NetEProperty(sr.net, pidx);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -2751,6 +2764,7 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope,
|
|||
use_search_results.path_tail.push_back(search_results.path_head.back());
|
||||
use_search_results.path_head.push_back(name_component_t(perm_string::literal(THIS_TOKEN)));
|
||||
use_search_results.net = scope->find_signal(perm_string::literal(THIS_TOKEN));
|
||||
use_search_results.type = use_search_results.net->net_type();
|
||||
ivl_assert(*this, use_search_results.net);
|
||||
|
||||
return elaborate_expr_method_(des, scope, use_search_results);
|
||||
|
|
@ -3026,12 +3040,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
if (search_results.par_val)
|
||||
cerr << get_fileline() << ": PECallFunction::elaborate_expr_method_: "
|
||||
<< "search_results.par_val: " << *search_results.par_val << endl;
|
||||
if (search_results.par_type)
|
||||
if (search_results.type)
|
||||
cerr << get_fileline() << ": PECallFunction::elaborate_expr_method_: "
|
||||
<< "search_results.par_type: " << *search_results.par_type << endl;
|
||||
<< "search_results.type: " << *search_results.type << endl;
|
||||
}
|
||||
|
||||
if (search_results.par_val && search_results.par_type) {
|
||||
if (search_results.par_val && search_results.type) {
|
||||
return elaborate_expr_method_par_(des, scope, search_results);
|
||||
}
|
||||
|
||||
|
|
@ -3177,7 +3191,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
perm_string method_name = search_results.path_tail.back().name;
|
||||
|
||||
NetNet*net = search_results.net;
|
||||
const netclass_t*class_type = net->class_type();
|
||||
const netclass_t*class_type = dynamic_cast<const netclass_t*>(search_results.type);
|
||||
ivl_assert(*this, class_type);
|
||||
NetScope*method = class_type->method_from_name(method_name);
|
||||
|
||||
|
|
@ -3285,10 +3299,10 @@ NetExpr* PECallFunction::elaborate_expr_method_par_(Design*des, NetScope*scope,
|
|||
const
|
||||
{
|
||||
ivl_assert(*this, search_results.par_val);
|
||||
ivl_assert(*this, search_results.par_type);
|
||||
ivl_assert(*this, search_results.type);
|
||||
|
||||
const NetExpr*par_val = search_results.par_val;
|
||||
ivl_type_t par_type = search_results.par_type;
|
||||
ivl_type_t par_type = search_results.type;
|
||||
perm_string method_name = search_results.path_tail.back().name;
|
||||
|
||||
// If the parameter is of type string, then look for the standard string
|
||||
|
|
@ -4230,8 +4244,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
|
||||
// Similarly, if this net is an object, the path tail may
|
||||
// be a class property.
|
||||
if (sr.net->class_type() != 0 && !sr.path_tail.empty()) {
|
||||
const netclass_t*class_type = sr.net->class_type();
|
||||
const netclass_t *class_type = dynamic_cast<const netclass_t*>(sr.type);
|
||||
if (class_type && !sr.path_tail.empty()) {
|
||||
perm_string pname = peek_tail_name(sr.path_tail);
|
||||
ivl_type_t par_type;
|
||||
const NetExpr *par = class_type->get_parameter(des, pname, par_type);
|
||||
|
|
@ -4349,24 +4363,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
return check_for_struct_members(this, des, use_scope, net,
|
||||
sr.path_head.back().index,
|
||||
sr.path_tail);
|
||||
} else if (net->class_type()) {
|
||||
const name_component_t member_comp = sr.path_tail.front();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||
<< "Ident " << sr.path_head
|
||||
<< " look for property " << member_comp << endl;
|
||||
}
|
||||
|
||||
if (sr.path_tail.size() > 1) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Nested member path not yet supported in this context."
|
||||
<< endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return elaborate_expr_class_field_(des, scope, net,
|
||||
member_comp, 0, flags);
|
||||
} else if (dynamic_cast<const netclass_t*>(sr.type)) {
|
||||
return elaborate_expr_class_field_(des, scope, sr, 0, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4570,7 +4568,7 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
|||
<< " canonical index: " << *canon_index << endl;
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(this_net, member_name, canon_index);
|
||||
NetEProperty*tmp = new NetEProperty(this_net, pidx, canon_index);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -4667,7 +4665,7 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
return elaborate_expr_param_or_specparam_(des, scope, sr.par_val,
|
||||
sr.scope, sr.par_type,
|
||||
sr.scope, sr.type,
|
||||
expr_wid, flags);
|
||||
}
|
||||
|
||||
|
|
@ -4882,18 +4880,8 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sr.net->class_type() && !sr.path_tail.empty()) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||
"Ident " << sr.path_head
|
||||
<< " look for class property " << sr.path_tail
|
||||
<< endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, sr.path_tail.size() == 1);
|
||||
const name_component_t member_comp = sr.path_tail.front();
|
||||
return elaborate_expr_class_field_(des, use_scope,
|
||||
sr.net, member_comp,
|
||||
if (dynamic_cast<const netclass_t*>(sr.type) && !sr.path_tail.empty()) {
|
||||
return elaborate_expr_class_field_(des, use_scope, sr,
|
||||
expr_wid, flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
13
elab_lval.cc
13
elab_lval.cc
|
|
@ -285,8 +285,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
|
||||
// If the variable is a class object, then handle it with the
|
||||
// net_class_member_ method.
|
||||
if (reg->class_type() && !member_path.empty() && gn_system_verilog()) {
|
||||
NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, member_path);
|
||||
const netclass_t *class_type = dynamic_cast<const netclass_t *>(sr.type);
|
||||
if (class_type && !member_path.empty() && gn_system_verilog()) {
|
||||
NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, class_type, reg, member_path);
|
||||
return lv;
|
||||
}
|
||||
|
||||
|
|
@ -475,7 +476,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
|||
}
|
||||
|
||||
NetAssign_*this_lval = new NetAssign_(this_net);
|
||||
this_lval->set_property(member_name);
|
||||
this_lval->set_property(member_name, pidx);
|
||||
if (canon_index) this_lval->set_word(canon_index);
|
||||
|
||||
return this_lval;
|
||||
|
|
@ -1078,7 +1079,8 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|||
* obj, and member_path=base.x.
|
||||
*/
|
||||
NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
|
||||
NetNet*sig, pform_name_t member_path) const
|
||||
const netclass_t *class_type, NetNet*sig,
|
||||
pform_name_t member_path) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_class_member_: "
|
||||
|
|
@ -1086,7 +1088,6 @@ NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope
|
|||
<< " of " << sig->name() << "." << endl;
|
||||
}
|
||||
|
||||
const netclass_t*class_type = sig->class_type();
|
||||
ivl_assert(*this, class_type);
|
||||
|
||||
// Iterate over the member_path. This handles nested class
|
||||
|
|
@ -1149,7 +1150,7 @@ NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope
|
|||
}
|
||||
|
||||
lv = lv? new NetAssign_(lv) : new NetAssign_(sig);
|
||||
lv->set_property(method_name);
|
||||
lv->set_property(method_name, pidx);
|
||||
|
||||
// Now get the type of the property.
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
|
|
|
|||
|
|
@ -3906,7 +3906,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
"$ivl_queue_method$pop_back");
|
||||
}
|
||||
|
||||
if (const netclass_t*class_type = net->class_type()) {
|
||||
if (const netclass_t*class_type = dynamic_cast<const netclass_t*>(par_type)) {
|
||||
NetScope*task = class_type->method_from_name(method_name);
|
||||
if (task == 0) {
|
||||
// If an implicit this was added it is not an error if we
|
||||
|
|
|
|||
|
|
@ -158,10 +158,7 @@ const ivl_type_s* NetAssign_::net_type() const
|
|||
return ntype;
|
||||
|
||||
if (const netclass_t*class_type = dynamic_cast<const netclass_t*>(ntype)) {
|
||||
int pidx = class_type->property_idx_from_name(member_);
|
||||
ivl_assert(*this, pidx >= 0);
|
||||
ivl_type_t tmp = class_type->get_prop_type(pidx);
|
||||
return tmp;
|
||||
return class_type->get_prop_type(member_idx_);
|
||||
}
|
||||
|
||||
if (const netdarray_t*darray = dynamic_cast<const netdarray_t*> (ntype)) {
|
||||
|
|
@ -178,10 +175,7 @@ const ivl_type_s* NetAssign_::net_type() const
|
|||
if (member_.nil())
|
||||
return sig_->net_type();
|
||||
|
||||
int pidx = class_type->property_idx_from_name(member_);
|
||||
ivl_assert(*sig_, pidx >= 0);
|
||||
ivl_type_t tmp = class_type->get_prop_type(pidx);
|
||||
return tmp;
|
||||
return class_type->get_prop_type(member_idx_);
|
||||
}
|
||||
|
||||
if (const netdarray_t*darray = dynamic_cast<const netdarray_t*> (sig_->net_type())) {
|
||||
|
|
@ -246,10 +240,10 @@ void NetAssign_::set_part(NetExpr*base, unsigned wid,
|
|||
sel_type_ = sel_type;
|
||||
}
|
||||
|
||||
void NetAssign_::set_property(const perm_string&mname)
|
||||
void NetAssign_::set_property(const perm_string&mname, unsigned idx)
|
||||
{
|
||||
//ivl_assert(*sig_, sig_->class_type());
|
||||
member_ = mname;
|
||||
member_idx_ = idx;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -382,13 +382,12 @@ NetENull::~NetENull()
|
|||
{
|
||||
}
|
||||
|
||||
NetEProperty::NetEProperty(NetNet*net, perm_string pnam, NetExpr*idx)
|
||||
: net_(net), index_(idx)
|
||||
NetEProperty::NetEProperty(NetNet*net, size_t pidx, NetExpr*idx)
|
||||
: net_(net), pidx_(pidx), index_(idx)
|
||||
{
|
||||
const netclass_t*use_type = dynamic_cast<const netclass_t*>(net->net_type());
|
||||
assert(use_type);
|
||||
|
||||
pidx_ = use_type->property_idx_from_name(pnam);
|
||||
ivl_type_t prop_type = use_type->get_prop_type(pidx_);
|
||||
expr_width(prop_type->packed_width());
|
||||
cast_signed(prop_type->get_signed());
|
||||
|
|
|
|||
|
|
@ -2838,8 +2838,8 @@ class NetAssign_ {
|
|||
ivl_select_type_t = IVL_SEL_OTHER);
|
||||
// Set the member or property name if the signal type is a
|
||||
// class.
|
||||
void set_property(const perm_string&name);
|
||||
inline perm_string get_property(void) const { return member_; }
|
||||
void set_property(const perm_string&name, unsigned int idx);
|
||||
inline int get_property_idx(void) const { return member_idx_; }
|
||||
|
||||
// Determine if the assigned object is signed or unsigned.
|
||||
// This is used when determining the expression type for
|
||||
|
|
@ -2897,6 +2897,7 @@ class NetAssign_ {
|
|||
NetExpr*word_;
|
||||
// member/property if signal is a class.
|
||||
perm_string member_;
|
||||
int member_idx_ = -1;
|
||||
|
||||
bool signed_;
|
||||
bool turn_sig_to_wire_on_release_;
|
||||
|
|
@ -4579,7 +4580,7 @@ class NetENull : public NetExpr {
|
|||
*/
|
||||
class NetEProperty : public NetExpr {
|
||||
public:
|
||||
NetEProperty(NetNet*n, perm_string pname, NetExpr*canon_index =0);
|
||||
NetEProperty(NetNet*n, size_t pidx_, NetExpr*canon_index =0);
|
||||
~NetEProperty();
|
||||
|
||||
inline const NetNet* get_sig() const { return net_; }
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ struct symbol_search_results {
|
|||
net = 0;
|
||||
cls_val = 0;
|
||||
par_val = 0;
|
||||
par_type = 0;
|
||||
type = 0;
|
||||
eve = 0;
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ struct symbol_search_results {
|
|||
// If this was a parameter, the value expression and the
|
||||
// optional value dimensions.
|
||||
const NetExpr*par_val;
|
||||
ivl_type_t par_type;
|
||||
ivl_type_t type;
|
||||
// If this is a named event, ...
|
||||
NetEvent*eve;
|
||||
|
||||
|
|
|
|||
|
|
@ -132,12 +132,6 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
if (scope->genvar_tmp.str() && path_tail.name == scope->genvar_tmp)
|
||||
return false;
|
||||
|
||||
if (path_tail.name == "#") {
|
||||
cerr << li->get_fileline() << ": sorry: "
|
||||
<< "Implicit class handle \"super\" not supported." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// These items cannot be seen outside the bounding module where
|
||||
// the search starts. But we continue searching up because scope
|
||||
// names can match. For example:
|
||||
|
|
@ -151,10 +145,26 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
// ... top.not_ok; // Matches.
|
||||
// endmodule
|
||||
if (!passed_module_boundary) {
|
||||
// Special case `super` keyword. Return the `this` object, but
|
||||
// with the type of the base class.
|
||||
if (path_tail.name == "#") {
|
||||
if (NetNet *net = scope->find_signal(perm_string::literal(THIS_TOKEN))) {
|
||||
const netclass_t *class_type = dynamic_cast<const netclass_t*>(net->net_type());
|
||||
path.push_back(path_tail);
|
||||
res->scope = scope;
|
||||
res->net = net;
|
||||
res->type = class_type->get_super();
|
||||
res->path_head = path;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NetNet*net = scope->find_signal(path_tail.name)) {
|
||||
path.push_back(path_tail);
|
||||
res->scope = scope;
|
||||
res->net = net;
|
||||
res->type = net->net_type();
|
||||
res->path_head = path;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -167,7 +177,7 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_type)) {
|
||||
if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->type)) {
|
||||
path.push_back(path_tail);
|
||||
res->scope = scope;
|
||||
res->par_val = par;
|
||||
|
|
@ -326,7 +336,7 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
net = recurse.net;
|
||||
cls_val = recurse.cls_val;
|
||||
par = recurse.par_val;
|
||||
par_type = recurse.par_type;
|
||||
par_type = recurse.type;
|
||||
eve = recurse.eve;
|
||||
if (! flag) {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -179,8 +179,6 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con
|
|||
|
||||
cur->width_ = asn->lwidth();
|
||||
|
||||
ivl_type_t nest_type = 0;
|
||||
|
||||
if (asn->sig()) {
|
||||
cur->type_ = IVL_LVAL_REG;
|
||||
cur->n.sig = find_signal(des_, asn->sig());
|
||||
|
|
@ -188,7 +186,6 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con
|
|||
} else {
|
||||
const NetAssign_*asn_nest = asn->nest();
|
||||
ivl_assert(*li, asn_nest);
|
||||
nest_type = asn_nest->net_type();
|
||||
struct ivl_lval_s*cur_nest = new struct ivl_lval_s;
|
||||
make_single_lval_(li, cur_nest, asn_nest);
|
||||
|
||||
|
|
@ -209,22 +206,7 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con
|
|||
expr_ = 0;
|
||||
}
|
||||
|
||||
cur->property_idx = -1;
|
||||
perm_string pname = asn->get_property();
|
||||
if (!pname.nil()) {
|
||||
const netclass_t*use_type;
|
||||
switch (cur->type_) {
|
||||
case IVL_LVAL_LVAL:
|
||||
assert(nest_type);
|
||||
use_type = dynamic_cast<const netclass_t*> (nest_type);
|
||||
break;
|
||||
default:
|
||||
use_type = dynamic_cast<const netclass_t*> (cur->n.sig->net_type);
|
||||
break;
|
||||
}
|
||||
assert(use_type);
|
||||
cur->property_idx = use_type->property_idx_from_name(pname);
|
||||
}
|
||||
cur->property_idx = asn->get_property_idx();
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue