Merge pull request #829 from larsclausen/class-super
Add support for handling `super` keyword
This commit is contained in:
commit
5347ba19cf
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;
|
||||
|
||||
|
|
|
|||
124
elab_expr.cc
124
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);
|
||||
|
|
@ -4322,12 +4336,6 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
{
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
NetNet* net = 0;
|
||||
ivl_type_t cls_val = 0;
|
||||
const NetExpr*par = 0;
|
||||
ivl_type_t par_type = 0;
|
||||
NetEvent* eve = 0;
|
||||
|
||||
NetScope*use_scope = scope;
|
||||
if (package_) {
|
||||
use_scope = des->find_package(package_->pscope_name());
|
||||
|
|
@ -4338,48 +4346,26 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
symbol_search(this, des, use_scope, path_, net, par, eve, par_type, cls_val);
|
||||
symbol_search_results sr;
|
||||
symbol_search(this, des, use_scope, path_, &sr);
|
||||
|
||||
if (net == 0 && gn_system_verilog() && path_.size() >= 2) {
|
||||
// NOTE: this is assuming the member_path is only one
|
||||
// component long, and that the use_path will wind up
|
||||
// being the path to the variable. This is not
|
||||
// necessarily true. Should fix this.
|
||||
pform_name_t use_path = path_;
|
||||
name_component_t member_comp = use_path.back();
|
||||
use_path.pop_back();
|
||||
|
||||
ivl_assert(*this, net == 0);
|
||||
symbol_search(this, des, use_scope, use_path, net, par, eve,
|
||||
par_type, cls_val);
|
||||
|
||||
if (net == 0) {
|
||||
// Nope, no struct/class with member.
|
||||
|
||||
} else if (net->struct_type() != 0) {
|
||||
pform_name_t member_path;
|
||||
member_path.push_back( member_comp );
|
||||
return check_for_struct_members(this, des, use_scope,
|
||||
net, use_path.back().index,
|
||||
member_path);
|
||||
|
||||
} else if (net->class_type()!=0) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||
<< "Ident " << use_path
|
||||
<< " look for property " << member_comp << endl;
|
||||
}
|
||||
|
||||
return elaborate_expr_class_field_(des, scope, net,
|
||||
member_comp, 0, flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (net == 0) {
|
||||
if (!sr.net) {
|
||||
cerr << get_fileline() << ": error: Unable to bind variable `"
|
||||
<< path_ << "' in `" << scope_path(use_scope) << "'" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
des->errors++;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NetNet *net = sr.net;
|
||||
|
||||
if (!sr.path_tail.empty()) {
|
||||
if (net->struct_type()) {
|
||||
return check_for_struct_members(this, des, use_scope, net,
|
||||
sr.path_head.back().index,
|
||||
sr.path_tail);
|
||||
} else if (dynamic_cast<const netclass_t*>(sr.type)) {
|
||||
return elaborate_expr_class_field_(des, scope, sr, 0, flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
|
|
@ -4582,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;
|
||||
}
|
||||
|
|
@ -4679,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);
|
||||
}
|
||||
|
||||
|
|
@ -4894,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
39
elab_lval.cc
39
elab_lval.cc
|
|
@ -159,9 +159,6 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
bool is_cassign,
|
||||
bool is_force) const
|
||||
{
|
||||
NetNet* reg = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent* eve = 0;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval: "
|
||||
|
|
@ -182,25 +179,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
ivl_assert(*this, use_scope);
|
||||
}
|
||||
|
||||
/* Try to find the base part of the path that names the
|
||||
variable. The remainer is the member path. For example, if
|
||||
the path is a.b.c.d, and a.b is the path to a variable,
|
||||
then a.b becomes the base_path and c.d becomes the
|
||||
member_path. If we cannot find the variable with any
|
||||
prefix, then the base_path will be empty after this loop
|
||||
and reg will remain nil. */
|
||||
pform_name_t base_path = path_;
|
||||
pform_name_t member_path;
|
||||
while (reg == 0 && !base_path.empty()) {
|
||||
symbol_search(this, des, use_scope, base_path, reg, par, eve);
|
||||
// Found it!
|
||||
if (reg != 0) break;
|
||||
// Not found. Try to pop another name off the base_path
|
||||
// and push it to the front of the member_path.
|
||||
member_path.push_front( base_path.back() );
|
||||
base_path.pop_back();
|
||||
}
|
||||
symbol_search_results sr;
|
||||
symbol_search(this, des, use_scope, path_, &sr);
|
||||
|
||||
NetNet *reg = sr.net;
|
||||
pform_name_t &base_path = sr.path_head;
|
||||
pform_name_t &member_path = sr.path_tail;
|
||||
|
||||
/* The l-value must be a variable. If not, then give up and
|
||||
print a useful error message. */
|
||||
|
|
@ -301,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;
|
||||
}
|
||||
|
||||
|
|
@ -491,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;
|
||||
|
|
@ -1094,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_: "
|
||||
|
|
@ -1102,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
|
||||
|
|
@ -1165,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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// Check that `super` keyword can be used to access members of the base class
|
||||
|
||||
class B;
|
||||
int x, y;
|
||||
|
||||
task set_y;
|
||||
y = 2000;
|
||||
endtask
|
||||
|
||||
function bit check_x;
|
||||
return x === 1000;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class C extends B;
|
||||
byte x, y;
|
||||
task set_x;
|
||||
super.x = 1000;
|
||||
endtask
|
||||
|
||||
function bit check_y;
|
||||
return super.y === 2000;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module test;
|
||||
C c;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.set_x;
|
||||
c.set_y;
|
||||
if (c.check_x() && c.check_y()) begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED");
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Check that `super` keyword can be used to call tasks of the base class
|
||||
|
||||
class B;
|
||||
task t;
|
||||
$display("PASSED");
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class C extends B;
|
||||
task t;
|
||||
$display("FAILED");
|
||||
endtask
|
||||
|
||||
task check;
|
||||
super.t;
|
||||
endtask
|
||||
endclass
|
||||
|
||||
module test;
|
||||
C c;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.check;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Check that `super` keyword can be used to call functions of the base class
|
||||
|
||||
class B;
|
||||
function int f;
|
||||
return 1;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class C extends B;
|
||||
function int f;
|
||||
return 2;
|
||||
endfunction
|
||||
|
||||
task check;
|
||||
if (super.f() === 1) begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED");
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
module test;
|
||||
C c;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.check;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Check that `this.super` is supported
|
||||
|
||||
class B;
|
||||
int x, y;
|
||||
|
||||
task set_y;
|
||||
y = 2000;
|
||||
endtask
|
||||
|
||||
function bit check_x;
|
||||
return x === 1000;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class C extends B;
|
||||
byte x, y;
|
||||
task set_x;
|
||||
this.super.x = 1000;
|
||||
endtask
|
||||
|
||||
function bit check_y;
|
||||
return this.super.y === 2000;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module test;
|
||||
C c;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.set_x;
|
||||
c.set_y;
|
||||
if (c.check_x() && c.check_y()) begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED");
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -587,6 +587,10 @@ sv_class_static_prop2 normal,-g2009 ivltests
|
|||
sv_class_static_prop3 normal,-g2009 ivltests
|
||||
sv_class_super1 normal,-g2009 ivltests
|
||||
sv_class_super2 normal,-g2009 ivltests
|
||||
sv_class_super3 normal,-g2009 ivltests
|
||||
sv_class_super4 normal,-g2009 ivltests
|
||||
sv_class_super5 normal,-g2009 ivltests
|
||||
sv_class_super6 normal,-g2009 ivltests
|
||||
sv_class_task1 normal,-g2009 ivltests
|
||||
sv_class_virt_new_fail CE,-g2009 ivltests
|
||||
sv_darray1 normal,-g2009 ivltests
|
||||
|
|
|
|||
|
|
@ -435,6 +435,10 @@ sv_class_static_prop2 CE,-g2009 ivltests
|
|||
sv_class_static_prop3 CE,-g2009 ivltests
|
||||
sv_class_super1 CE,-g2009 ivltests
|
||||
sv_class_super2 CE,-g2009 ivltests
|
||||
sv_class_super3 CE,-g2009 ivltests
|
||||
sv_class_super4 CE,-g2009 ivltests
|
||||
sv_class_super5 CE,-g2009 ivltests
|
||||
sv_class_super6 CE,-g2009 ivltests
|
||||
sv_class_task1 CE,-g2009 ivltests
|
||||
sv_end_label CE,-g2009 ivltests # Also generate
|
||||
sv_foreach2 CE,-g2009,-pallowsigned=1 ivltests
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
20
parse.y
20
parse.y
|
|
@ -1554,15 +1554,16 @@ import_export /* IEEE1800-2012: A.2.9 */
|
|||
;
|
||||
|
||||
implicit_class_handle /* IEEE1800-2005: A.8.4 */
|
||||
: K_this { $$ = pform_create_this(); }
|
||||
| K_super { $$ = pform_create_super(); }
|
||||
: K_this '.' { $$ = pform_create_this(); }
|
||||
| K_super '.' { $$ = pform_create_super(); }
|
||||
| K_this '.' K_super '.' { $$ = pform_create_super(); }
|
||||
;
|
||||
|
||||
/* `this` or `super` followed by an identifier */
|
||||
class_hierarchy_identifier
|
||||
: implicit_class_handle '.' hierarchy_identifier
|
||||
{ $1->splice($1->end(), *$3);
|
||||
delete $3;
|
||||
: implicit_class_handle hierarchy_identifier
|
||||
{ $1->splice($1->end(), *$2);
|
||||
delete $2;
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
|
@ -3793,10 +3794,9 @@ expr_primary
|
|||
pform_requires_sv(@1, "Empty function argument list");
|
||||
}
|
||||
|
||||
| implicit_class_handle
|
||||
{ PEIdent*tmp = new PEIdent(*$1);
|
||||
| K_this
|
||||
{ PEIdent*tmp = new PEIdent(perm_string::literal(THIS_TOKEN));
|
||||
FILE_NAME(tmp,@1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
|
|
@ -6693,8 +6693,8 @@ statement_item /* This is roughly statement_item in the LRM */
|
|||
beginning of a constructor, but let the elaborator figure that
|
||||
out. */
|
||||
|
||||
| implicit_class_handle '.' K_new argument_list_parens_opt ';'
|
||||
{ PChainConstructor*tmp = new PChainConstructor(*$4);
|
||||
| implicit_class_handle K_new argument_list_parens_opt ';'
|
||||
{ PChainConstructor*tmp = new PChainConstructor(*$3);
|
||||
FILE_NAME(tmp, @3);
|
||||
if (peek_head_name(*$1) == THIS_TOKEN) {
|
||||
yyerror(@1, "error: this.new is invalid syntax. Did you mean super.new?");
|
||||
|
|
|
|||
|
|
@ -87,7 +87,12 @@ ostream& operator<< (ostream&out, const index_component_t&that)
|
|||
|
||||
ostream& operator<< (ostream&out, const name_component_t&that)
|
||||
{
|
||||
out << that.name.str();
|
||||
if (that.name == THIS_TOKEN)
|
||||
out << "this";
|
||||
else if (that.name == SUPER_TOKEN)
|
||||
out << "super";
|
||||
else
|
||||
out << that.name.str();
|
||||
|
||||
typedef std::list<index_component_t>::const_iterator index_it_t;
|
||||
for (index_it_t idx = that.index.begin()
|
||||
|
|
|
|||
|
|
@ -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