Consolidate class property handling
There are currently two mechanisms for handling class properties. One that
is used when a class property is accessed through an object and other when
a class property is used freestanding in a class method.
Both are very similar, but there are some small differences. E.g. one
supports arrays, the other supports nested properties.
```
class B;
int x;
endclass
class C;
B b;
B ba[2];
task t;
ba[0] = new; // Does work
this.ba[0] = new; // Does not work
b.x = 10; // Does not work
this.b.x = 10; // Does work
endtask
```
There is another problem where free standing properties take precedence
over local variables. E.g.
```
class C;
int x = 1;
task t();
int x = 2;
$display(x); // Should print 2, will print 1
endtask
endclass
```
The class property elaboration also ignores the package scope of the
identifier resulting in access to a class property being elaborated if
there is a property of the same name as the scoped identifier. E.g.
```
package P;
int x = 2;
endpackage
class C;
int x = 1;
task t;
$display(P::x); // Should print 2, will print 1
endtask
endclass
```
Consolidate the two implementation to use the same code path. This is
mainly done by letting the symbol search return a result for free standing
properties as if the property had been specified on the `this` object. I.e.
`prop` and `this.prop` will return the same result from the symbol search.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
dc10710198
commit
07e20376d7
6
PExpr.h
6
PExpr.h
|
|
@ -412,7 +412,6 @@ class PEIdent : public PExpr {
|
|||
bool is_force, bool is_cassign,
|
||||
NetNet *reg, ivl_type_t data_type,
|
||||
pform_name_t tail_path) const;
|
||||
NetAssign_*elaborate_lval_method_class_member_(Design*, NetScope*) const;
|
||||
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*,
|
||||
bool need_const_idx) const;
|
||||
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*,
|
||||
|
|
@ -511,11 +510,6 @@ class PEIdent : public PExpr {
|
|||
NetScope*found,
|
||||
bool need_const) const;
|
||||
|
||||
NetExpr*elaborate_expr_class_member_(Design*des,
|
||||
NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
|
||||
NetExpr *elaborate_expr_class_field_(Design*des, NetScope*scope,
|
||||
const symbol_search_results &sr,
|
||||
unsigned expr_wid,
|
||||
|
|
|
|||
200
elab_expr.cc
200
elab_expr.cc
|
|
@ -2601,7 +2601,37 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
|||
prop_name);
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(sr.net, pidx);
|
||||
NetExpr *canon_index = nullptr;
|
||||
ivl_type_t tmp_type = class_type->get_prop_type(pidx);
|
||||
if (const netuarray_t *tmp_ua = dynamic_cast<const netuarray_t*>(tmp_type)) {
|
||||
const std::vector<netrange_t> &dims = tmp_ua->static_dimensions();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " has " << dims.size() << " dimensions, "
|
||||
<< " got " << comp.index.size() << " indices." << endl;
|
||||
}
|
||||
|
||||
if (dims.size() != comp.index.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Got " << comp.index.size() << " indices, "
|
||||
<< "expecting " << dims.size()
|
||||
<< " to index the property " << class_type->get_prop_name(pidx) << "." << endl;
|
||||
des->errors++;
|
||||
} else {
|
||||
canon_index = make_canonical_index(des, scope, this,
|
||||
comp.index, tmp_ua, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate && canon_index) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " canonical index: " << *canon_index << endl;
|
||||
}
|
||||
|
||||
NetEProperty *tmp = new NetEProperty(sr.net, pidx, canon_index);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -4166,13 +4196,32 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
return expr_width_;
|
||||
}
|
||||
|
||||
// Look for a class property.
|
||||
if (gn_system_verilog() && sr.cls_val) {
|
||||
expr_type_ = sr.cls_val->base_type();
|
||||
expr_width_ = sr.cls_val->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = sr.cls_val->get_signed();
|
||||
return expr_width_;
|
||||
if (sr.net) {
|
||||
// Similarly, if this net is an object, the path tail may
|
||||
// be a class property.
|
||||
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);
|
||||
if (par)
|
||||
return test_width_parameter_(par, mode);
|
||||
|
||||
int pidx = class_type->property_idx_from_name(pname);
|
||||
if (pidx >= 0) {
|
||||
const name_component_t member_comp = sr.path_tail.front();
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
if (!member_comp.index.empty()) {
|
||||
const netuarray_t*tmp_ua = dynamic_cast<const netuarray_t*>(ptype);
|
||||
if (tmp_ua) ptype = tmp_ua->element_type();
|
||||
}
|
||||
expr_type_ = ptype->base_type();
|
||||
expr_width_ = ptype->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = ptype->get_signed();
|
||||
return expr_width_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_width != UINT_MAX) {
|
||||
|
|
@ -4221,27 +4270,6 @@ 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.
|
||||
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);
|
||||
if (par)
|
||||
return test_width_parameter_(par, mode);
|
||||
|
||||
int pidx = class_type->property_idx_from_name(pname);
|
||||
if (pidx >= 0) {
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
expr_type_ = ptype->base_type();
|
||||
expr_width_ = ptype->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = ptype->get_signed();
|
||||
return expr_width_;
|
||||
}
|
||||
}
|
||||
|
||||
size_t use_depth = name_tail.index.size();
|
||||
// Account for unpacked dimensions by assuming that the
|
||||
// unpacked dimensions are consumed first, so subtract
|
||||
|
|
@ -4321,10 +4349,6 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
ivl_assert(*this, use_scope);
|
||||
}
|
||||
|
||||
if (NetExpr* tmp = elaborate_expr_class_member_(des, scope, 0, flags)) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
symbol_search_results sr;
|
||||
symbol_search(this, des, use_scope, path_, &sr);
|
||||
|
||||
|
|
@ -4454,105 +4478,6 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guess that the path_ is the name of a member of a containing class,
|
||||
* and see how that works. If it turns out that the current scope is
|
||||
* not a method, or the name is not in the parent class, then
|
||||
* fail. Otherwise, return a NetEProperty.
|
||||
*/
|
||||
NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
||||
unsigned, unsigned) const
|
||||
{
|
||||
if (!gn_system_verilog())
|
||||
return 0;
|
||||
if (scope->parent() == 0)
|
||||
return 0;
|
||||
if (path_.size() != 1)
|
||||
return 0;
|
||||
|
||||
const netclass_t*class_type = find_class_containing_scope(*this, scope);
|
||||
if (class_type == 0)
|
||||
return 0;
|
||||
|
||||
const name_component_t&name_comp = path_.back();
|
||||
|
||||
perm_string member_name = name_comp.name;
|
||||
int pidx = class_type->property_idx_from_name(member_name);
|
||||
if (pidx < 0)
|
||||
return 0;
|
||||
|
||||
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||
ivl_assert(*this, scope_method);
|
||||
|
||||
NetNet*this_net = scope_method->find_signal(perm_string::literal(THIS_TOKEN));
|
||||
if (this_net == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
||||
<< "." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: "
|
||||
<< "Found member " << member_name
|
||||
<< " is a member of class " << class_type->get_name()
|
||||
<< ", context scope=" << scope_path(scope)
|
||||
<< ", type=" << *class_type->get_prop_type(pidx)
|
||||
<< ", so making a NetEProperty." << endl;
|
||||
}
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Local property " << class_type->get_prop_name(pidx)
|
||||
<< " is not accessible in this context."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
if (qual.test_static()) {
|
||||
return class_static_property_expression(this, class_type, member_name);
|
||||
}
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
ivl_type_t tmp_type = class_type->get_prop_type(pidx);
|
||||
if (const netuarray_t*tmp_ua = dynamic_cast<const netuarray_t*>(tmp_type)) {
|
||||
|
||||
const std::vector<netrange_t>&dims = tmp_ua->static_dimensions();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " has " << dims.size() << " dimensions, "
|
||||
<< " got " << name_comp.index.size() << " indices." << endl;
|
||||
}
|
||||
|
||||
if (dims.size() != name_comp.index.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Got " << name_comp.index.size() << " indices, "
|
||||
<< "expecting " << dims.size()
|
||||
<< " to index the property " << class_type->get_prop_name(pidx) << "." << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else {
|
||||
|
||||
canon_index = make_canonical_index(des, scope, this,
|
||||
name_comp.index, tmp_ua, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate && canon_index) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " canonical index: " << *canon_index << endl;
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(this_net, pidx, canon_index);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Elaborate an identifier in an expression. The identifier can be a
|
||||
* parameter name, a signal name or a memory name. It can also be a
|
||||
|
|
@ -4587,17 +4512,6 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
|||
<< endl;
|
||||
}
|
||||
|
||||
// Special case: Detect the special situation that this name
|
||||
// is the name of a variable in the class, and this is a class
|
||||
// method. We sense that this might be the case by noting that
|
||||
// the parent scope of where we are working is a
|
||||
// NetScope::CLASS, the path_ is a single component, and the
|
||||
// name is a property of the class. If that turns out to be
|
||||
// the case, then handle this specially.
|
||||
if (NetExpr*tmp = elaborate_expr_class_member_(des, scope, expr_wid, flags)) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (path_.size() > 1) {
|
||||
if (NEED_CONST & flags) {
|
||||
cerr << get_fileline() << ": error: A hierarchical reference"
|
||||
|
|
|
|||
197
elab_lval.cc
197
elab_lval.cc
|
|
@ -165,11 +165,6 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
<< "Elaborate l-value ident expression: " << *this << endl;
|
||||
}
|
||||
|
||||
/* Try to detect the special case that we are in a method and
|
||||
the identifier is a member of the class. */
|
||||
if (NetAssign_*tmp = elaborate_lval_method_class_member_(des, scope))
|
||||
return tmp;
|
||||
|
||||
/* Normally find the name in the passed scope. But if this is
|
||||
imported from a package, then located the variable from the
|
||||
package scope. */
|
||||
|
|
@ -364,132 +359,6 @@ NetAssign_*PEIdent::elaborate_lval_var_(Design *des, NetScope *scope,
|
|||
return lv;
|
||||
}
|
||||
|
||||
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
||||
NetScope*scope) const
|
||||
{
|
||||
if (!gn_system_verilog())
|
||||
return 0;
|
||||
if (scope->parent() == 0 || scope->type() == NetScope::CLASS)
|
||||
return 0;
|
||||
if (path_.size() != 1)
|
||||
return 0;
|
||||
|
||||
const netclass_t*class_type = find_class_containing_scope(*this, scope);
|
||||
if (class_type == 0)
|
||||
return 0;
|
||||
|
||||
const name_component_t&name_comp = path_.back();
|
||||
|
||||
perm_string member_name = name_comp.name;
|
||||
int pidx = class_type->property_idx_from_name(member_name);
|
||||
if (pidx < 0)
|
||||
return 0;
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
|
||||
if (qual.test_static()) {
|
||||
NetNet *sig = class_type->find_static_property(member_name);
|
||||
return elaborate_lval_var_(des, scope, false, false, sig,
|
||||
class_type, {});
|
||||
}
|
||||
|
||||
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||
ivl_assert(*this, scope_method);
|
||||
|
||||
NetNet*this_net = scope_method->find_signal(perm_string::literal(THIS_TOKEN));
|
||||
if (this_net == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
||||
<< "." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Ident " << member_name
|
||||
<< " is a property of class " << class_type->get_name() << endl;
|
||||
}
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
if (! name_comp.index.empty()) {
|
||||
ivl_type_t property_type = class_type->get_prop_type(pidx);
|
||||
|
||||
if (const netsarray_t* stype = dynamic_cast<const netsarray_t*> (property_type)) {
|
||||
canon_index = make_canonical_index(des, scope, this,
|
||||
name_comp.index, stype, false);
|
||||
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Index expressions don't apply to this type of property." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect assignment to constant properties. Note that the
|
||||
// initializer constructor MAY assign to constant properties,
|
||||
// as this is how the property gets its value.
|
||||
if (qual.test_const()) {
|
||||
if (class_type->get_prop_initialized(pidx)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else if (scope->basename()!="new" && scope->basename()!="new@") {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else {
|
||||
|
||||
// Mark this property as initialized. This is used
|
||||
// to know that we have initialized the constant
|
||||
// object so the next assignment will be marked as
|
||||
// illegal.
|
||||
class_type->set_prop_initialized(pidx);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Found initializers for property " << class_type->get_prop_name(pidx) << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ivl_type_t tmp_type = class_type->get_prop_type(pidx);
|
||||
if (const netuarray_t*tmp_ua = dynamic_cast<const netuarray_t*>(tmp_type)) {
|
||||
|
||||
const std::vector<netrange_t>&dims = tmp_ua->static_dimensions();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " has " << dims.size() << " dimensions, "
|
||||
<< " got " << name_comp.index.size() << " indices." << endl;
|
||||
if (canon_index) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Canonical index is:" << *canon_index << endl;
|
||||
};
|
||||
}
|
||||
|
||||
if (dims.size() != name_comp.index.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Got " << name_comp.index.size() << " indices, "
|
||||
<< "expecting " << dims.size()
|
||||
<< " to index the property " << class_type->get_prop_name(pidx) << "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
NetAssign_*this_lval = new NetAssign_(this_net);
|
||||
this_lval->set_property(member_name, pidx);
|
||||
if (canon_index) this_lval->set_word(canon_index);
|
||||
|
||||
return this_lval;
|
||||
}
|
||||
|
||||
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||
NetScope*scope,
|
||||
NetNet*reg,
|
||||
|
|
@ -1151,10 +1020,30 @@ NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope
|
|||
return lv;
|
||||
|
||||
} else if (qual.test_const()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this context." << endl;
|
||||
des->errors += 1;
|
||||
if (class_type->get_prop_initialized(pidx)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors++;
|
||||
} else if (scope->basename() != "new" && scope->basename() != "new@") {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors++;
|
||||
} else {
|
||||
// Mark this property as initialized. This is used
|
||||
// to know that we have initialized the constant
|
||||
// object so the next assignment will be marked as
|
||||
// illegal.
|
||||
class_type->set_prop_initialized(pidx);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Found initializers for property " << class_type->get_prop_name(pidx) << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lv = lv? new NetAssign_(lv) : new NetAssign_(sig);
|
||||
|
|
@ -1171,6 +1060,44 @@ NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope
|
|||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
NetExpr *canon_index = nullptr;
|
||||
if (!member_cur.index.empty()) {
|
||||
if (const netsarray_t *stype = dynamic_cast<const netsarray_t*>(ptype)) {
|
||||
canon_index = make_canonical_index(des, scope, this,
|
||||
member_cur.index, stype, false);
|
||||
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Index expressions don't apply to this type of property." << endl;
|
||||
des->errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (const netuarray_t *tmp_ua = dynamic_cast<const netuarray_t*>(ptype)) {
|
||||
const std::vector<netrange_t> &dims = tmp_ua->static_dimensions();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " has " << dims.size() << " dimensions, "
|
||||
<< " got " << member_cur.index.size() << " indices." << endl;
|
||||
if (canon_index) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Canonical index is:" << *canon_index << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (dims.size() != member_cur.index.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Got " << member_cur.index.size() << " indices, "
|
||||
<< "expecting " << dims.size()
|
||||
<< " to index the property " << class_type->get_prop_name(pidx) << "." << endl;
|
||||
des->errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (canon_index)
|
||||
lv->set_word(canon_index);
|
||||
|
||||
// If the current member is a class object, then get the
|
||||
// type. We may wind up iterating, and need the proper
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ struct symbol_search_results {
|
|||
inline symbol_search_results() {
|
||||
scope = 0;
|
||||
net = 0;
|
||||
cls_val = 0;
|
||||
par_val = 0;
|
||||
type = 0;
|
||||
eve = 0;
|
||||
|
|
@ -55,7 +54,6 @@ struct symbol_search_results {
|
|||
inline bool is_scope() const {
|
||||
if (net) return false;
|
||||
if (eve) return false;
|
||||
if (cls_val) return false;
|
||||
if (par_val) return false;
|
||||
if (scope) return true;
|
||||
return false;
|
||||
|
|
@ -64,7 +62,6 @@ struct symbol_search_results {
|
|||
inline bool is_found() const {
|
||||
if (net) return true;
|
||||
if (eve) return true;
|
||||
if (cls_val) return true;
|
||||
if (par_val) return true;
|
||||
if (scope) return true;
|
||||
return false;
|
||||
|
|
@ -75,8 +72,6 @@ struct symbol_search_results {
|
|||
NetScope*scope;
|
||||
// If this was a net, the signal itself.
|
||||
NetNet*net;
|
||||
// For a class property we only have type information.
|
||||
ivl_type_t cls_val;
|
||||
// If this was a parameter, the value expression and the
|
||||
// optional value dimensions.
|
||||
const NetExpr*par_val;
|
||||
|
|
|
|||
|
|
@ -187,16 +187,21 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
|
||||
// Static items are just normal signals and are found above.
|
||||
if (scope->type() == NetScope::CLASS) {
|
||||
netclass_t*clsnet = scope->find_class(des, scope->basename());
|
||||
const netclass_t *clsnet = scope->class_def();
|
||||
int pidx = clsnet->property_idx_from_name(path_tail.name);
|
||||
if (pidx >= 0) {
|
||||
ivl_type_t prop_type = clsnet->get_prop_type(pidx);
|
||||
const netuarray_t*tmp_ua = dynamic_cast<const netuarray_t*>(prop_type);
|
||||
if (tmp_ua) prop_type = tmp_ua->element_type();
|
||||
path.push_back(path_tail);
|
||||
// This is a class property being accessed in a
|
||||
// class method. Return `this` for the net and the
|
||||
// property name for the path tail.
|
||||
NetScope *scope_method = find_method_containing_scope(*li, start_scope);
|
||||
ivl_assert(*li, scope_method);
|
||||
res->net = scope_method->find_signal(perm_string::literal(THIS_TOKEN));
|
||||
ivl_assert(*li, res->net);
|
||||
res->scope = scope;
|
||||
res->cls_val = prop_type;
|
||||
res->path_head = path;
|
||||
ivl_assert(*li, path.empty());
|
||||
res->path_head.push_back(name_component_t(perm_string::literal(THIS_TOKEN)));
|
||||
res->path_tail.push_front(path_tail);
|
||||
res->type = clsnet;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue