SV: chained method calls a().b()
Add parsing and elaboration for chained calls on expression results, with sv_call_chain_method1 regression. Split from steveicarus/iverilog#1330 (part 02/6).
This commit is contained in:
parent
15689210c1
commit
4a505546a1
25
PExpr.cc
25
PExpr.cc
|
|
@ -271,12 +271,28 @@ PECallFunction::PECallFunction(perm_string n, const list<named_pexpr_t> &parms)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PECallFunction::PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
|
||||||
|
const vector<named_pexpr_t> &parms)
|
||||||
|
: path_(method), parms_(parms), chain_prefix_(chain_prefix), is_overridden_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PECallFunction::PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
|
||||||
|
const list<named_pexpr_t> &parms)
|
||||||
|
: path_(method), parms_(parms.begin(), parms.end()),
|
||||||
|
chain_prefix_(chain_prefix), is_overridden_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
PECallFunction::~PECallFunction()
|
PECallFunction::~PECallFunction()
|
||||||
{
|
{
|
||||||
|
delete chain_prefix_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
|
void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
|
||||||
{
|
{
|
||||||
|
if (chain_prefix_)
|
||||||
|
chain_prefix_->declare_implicit_nets(scope, type);
|
||||||
for (const auto &parm : parms_) {
|
for (const auto &parm : parms_) {
|
||||||
if (parm.parm)
|
if (parm.parm)
|
||||||
parm.parm->declare_implicit_nets(scope, type);
|
parm.parm->declare_implicit_nets(scope, type);
|
||||||
|
|
@ -285,12 +301,13 @@ void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type
|
||||||
|
|
||||||
bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
|
bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
bool flag = false;
|
if (chain_prefix_ && chain_prefix_->has_aa_term(des, scope))
|
||||||
|
return true;
|
||||||
for (const auto &parm : parms_) {
|
for (const auto &parm : parms_) {
|
||||||
if (parm.parm)
|
if (parm.parm && parm.parm->has_aa_term(des, scope))
|
||||||
flag |= parm.parm->has_aa_term(des, scope);
|
return true;
|
||||||
}
|
}
|
||||||
return flag;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PEConcat::PEConcat(const list<PExpr*>&p, PExpr*r)
|
PEConcat::PEConcat(const list<PExpr*>&p, PExpr*r)
|
||||||
|
|
|
||||||
22
PExpr.h
22
PExpr.h
|
|
@ -920,8 +920,18 @@ class PECallFunction : public PExpr {
|
||||||
explicit PECallFunction(const pform_name_t &n, const std::list<named_pexpr_t> &parms);
|
explicit PECallFunction(const pform_name_t &n, const std::list<named_pexpr_t> &parms);
|
||||||
explicit PECallFunction(perm_string n, const std::list<named_pexpr_t> &parms);
|
explicit PECallFunction(perm_string n, const std::list<named_pexpr_t> &parms);
|
||||||
|
|
||||||
|
// SystemVerilog: prefix().method(args) — prefix elaborates to a class handle.
|
||||||
|
explicit PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
|
||||||
|
const std::vector<named_pexpr_t> &parms);
|
||||||
|
explicit PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
|
||||||
|
const std::list<named_pexpr_t> &parms);
|
||||||
|
|
||||||
~PECallFunction() override;
|
~PECallFunction() override;
|
||||||
|
|
||||||
|
// For chained-call resolution (path is only the final method name).
|
||||||
|
const pform_scoped_name_t& peek_path(void) const { return path_; }
|
||||||
|
const PExpr* peek_chain_prefix(void) const { return chain_prefix_; }
|
||||||
|
|
||||||
virtual void dump(std::ostream &) const override;
|
virtual void dump(std::ostream &) const override;
|
||||||
|
|
||||||
virtual void declare_implicit_nets(LexicalScope*scope, NetNet::Type type) override;
|
virtual void declare_implicit_nets(LexicalScope*scope, NetNet::Type type) override;
|
||||||
|
|
@ -940,6 +950,8 @@ class PECallFunction : public PExpr {
|
||||||
private:
|
private:
|
||||||
pform_scoped_name_t path_;
|
pform_scoped_name_t path_;
|
||||||
std::vector<named_pexpr_t> parms_;
|
std::vector<named_pexpr_t> parms_;
|
||||||
|
// If non-null, this call is prefix().tail_name(...) (SV method chain).
|
||||||
|
PExpr* chain_prefix_ = nullptr;
|
||||||
|
|
||||||
// For system functions.
|
// For system functions.
|
||||||
bool is_overridden_;
|
bool is_overridden_;
|
||||||
|
|
@ -985,8 +997,18 @@ class PECallFunction : public PExpr {
|
||||||
perm_string method_name,
|
perm_string method_name,
|
||||||
const std::vector<named_pexpr_t>*src_parms) const;
|
const std::vector<named_pexpr_t>*src_parms) const;
|
||||||
|
|
||||||
|
NetExpr* elaborate_class_method_net_this_(Design*des, NetScope*scope,
|
||||||
|
NetExpr* this_expr,
|
||||||
|
const netclass_t*class_type,
|
||||||
|
perm_string method_name,
|
||||||
|
const std::vector<named_pexpr_t>*src_parms) const;
|
||||||
|
|
||||||
NetExpr* elaborate_expr_method_chained_(Design*des, NetScope*scope,
|
NetExpr* elaborate_expr_method_chained_(Design*des, NetScope*scope,
|
||||||
symbol_search_results&search_results) const;
|
symbol_search_results&search_results) const;
|
||||||
|
|
||||||
|
NetExpr* elaborate_expr_chain_(Design*des, NetScope*scope, unsigned flags) const;
|
||||||
|
|
||||||
|
unsigned test_width_chain_(Design*des, NetScope*scope, width_mode_t&mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
133
elab_expr.cc
133
elab_expr.cc
|
|
@ -55,6 +55,53 @@ bool type_is_vectorable(ivl_variable_type_t type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For a().b()… call chains, find the class type of the prefix expression
|
||||||
|
* (the value before the final ".method(args)").
|
||||||
|
*/
|
||||||
|
static const netclass_t* resolve_call_chain_prefix_class(Design*des, NetScope*scope,
|
||||||
|
PECallFunction* link)
|
||||||
|
{
|
||||||
|
if (link == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (link->peek_chain_prefix() == 0) {
|
||||||
|
symbol_search_results sr;
|
||||||
|
if (!symbol_search(link, des, scope, link->peek_path(), UINT_MAX, &sr))
|
||||||
|
return 0;
|
||||||
|
if (!sr.is_scope() || sr.scope->type() != NetScope::FUNC)
|
||||||
|
return 0;
|
||||||
|
NetFuncDef* fundef = sr.scope->func_def();
|
||||||
|
ivl_assert(*link, fundef);
|
||||||
|
NetScope* dscope = fundef->scope();
|
||||||
|
NetNet* res = dscope->find_signal(dscope->basename());
|
||||||
|
if (res == 0)
|
||||||
|
return 0;
|
||||||
|
return dynamic_cast<const netclass_t*>(res->net_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
PECallFunction* inner = dynamic_cast<PECallFunction*>(
|
||||||
|
const_cast<PExpr*>(link->peek_chain_prefix()));
|
||||||
|
if (inner == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const netclass_t* recv_class = resolve_call_chain_prefix_class(des, scope, inner);
|
||||||
|
if (recv_class == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
perm_string mname = peek_tail_name(link->peek_path());
|
||||||
|
NetScope* mscope = recv_class->method_from_name(mname);
|
||||||
|
if (mscope == 0)
|
||||||
|
return 0;
|
||||||
|
NetFuncDef* mdef = mscope->func_def();
|
||||||
|
if (mdef == 0)
|
||||||
|
return 0;
|
||||||
|
NetNet* mres = mscope->find_signal(mscope->basename());
|
||||||
|
if (mres == 0)
|
||||||
|
return 0;
|
||||||
|
return dynamic_cast<const netclass_t*>(mres->net_type());
|
||||||
|
}
|
||||||
|
|
||||||
static ivl_nature_t find_access_function(const pform_scoped_name_t &path)
|
static ivl_nature_t find_access_function(const pform_scoped_name_t &path)
|
||||||
{
|
{
|
||||||
if (path.package || path.name.size() != 1)
|
if (path.package || path.name.size() != 1)
|
||||||
|
|
@ -1752,9 +1799,53 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned PECallFunction::test_width_chain_(Design*des, NetScope*scope,
|
||||||
|
width_mode_t&)
|
||||||
|
{
|
||||||
|
PECallFunction* inner_pf = dynamic_cast<PECallFunction*>(chain_prefix_);
|
||||||
|
if (inner_pf == 0) {
|
||||||
|
expr_width_ = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const netclass_t* cls = resolve_call_chain_prefix_class(des, scope, inner_pf);
|
||||||
|
if (cls == 0) {
|
||||||
|
expr_width_ = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
perm_string mname = peek_tail_name(path_);
|
||||||
|
NetScope* mscope = cls->method_from_name(mname);
|
||||||
|
if (mscope == 0) {
|
||||||
|
expr_width_ = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetFuncDef* mdef = mscope->func_def();
|
||||||
|
if (mdef == 0 || mdef->is_void()) {
|
||||||
|
expr_width_ = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet* mres = mscope->find_signal(mscope->basename());
|
||||||
|
if (mres == 0) {
|
||||||
|
expr_width_ = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_type_ = mres->data_type();
|
||||||
|
expr_width_ = mres->vector_width();
|
||||||
|
min_width_ = expr_width_;
|
||||||
|
signed_flag_ = mres->get_signed();
|
||||||
|
return expr_width_;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned PECallFunction::test_width(Design*des, NetScope*scope,
|
unsigned PECallFunction::test_width(Design*des, NetScope*scope,
|
||||||
width_mode_t&mode)
|
width_mode_t&mode)
|
||||||
{
|
{
|
||||||
|
if (chain_prefix_)
|
||||||
|
return test_width_chain_(des, scope, mode);
|
||||||
|
|
||||||
if (debug_elaborate) {
|
if (debug_elaborate) {
|
||||||
cerr << get_fileline() << ": PECallFunction::test_width: "
|
cerr << get_fileline() << ": PECallFunction::test_width: "
|
||||||
<< "path_: " << path_ << endl;
|
<< "path_: " << path_ << endl;
|
||||||
|
|
@ -2902,6 +2993,9 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope,
|
||||||
{
|
{
|
||||||
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
|
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
|
||||||
|
|
||||||
|
if (chain_prefix_)
|
||||||
|
return elaborate_expr_chain_(des, scope, flags);
|
||||||
|
|
||||||
// Search for the symbol. This should turn up a scope.
|
// Search for the symbol. This should turn up a scope.
|
||||||
symbol_search_results search_results;
|
symbol_search_results search_results;
|
||||||
bool search_flag = symbol_search(this, des, scope, path_, UINT_MAX, &search_results);
|
bool search_flag = symbol_search(this, des, scope, path_, UINT_MAX, &search_results);
|
||||||
|
|
@ -3267,6 +3361,18 @@ NetExpr* PECallFunction::elaborate_class_method_net_(Design*des, NetScope*scope,
|
||||||
NetNet*net, const netclass_t*class_type,
|
NetNet*net, const netclass_t*class_type,
|
||||||
perm_string method_name,
|
perm_string method_name,
|
||||||
const vector<named_pexpr_t>*src_parms) const
|
const vector<named_pexpr_t>*src_parms) const
|
||||||
|
{
|
||||||
|
NetESignal*ethis = new NetESignal(net);
|
||||||
|
ethis->set_line(*this);
|
||||||
|
return elaborate_class_method_net_this_(des, scope, ethis, class_type,
|
||||||
|
method_name, src_parms);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetExpr* PECallFunction::elaborate_class_method_net_this_(Design*des, NetScope*scope,
|
||||||
|
NetExpr* this_expr,
|
||||||
|
const netclass_t*class_type,
|
||||||
|
perm_string method_name,
|
||||||
|
const vector<named_pexpr_t>*src_parms) const
|
||||||
{
|
{
|
||||||
NetScope*method = class_type->method_from_name(method_name);
|
NetScope*method = class_type->method_from_name(method_name);
|
||||||
|
|
||||||
|
|
@ -3295,9 +3401,7 @@ NetExpr* PECallFunction::elaborate_class_method_net_(Design*des, NetScope*scope,
|
||||||
vector<NetExpr*> parms(def->port_count());
|
vector<NetExpr*> parms(def->port_count());
|
||||||
ivl_assert(*this, def->port_count() >= 1);
|
ivl_assert(*this, def->port_count() >= 1);
|
||||||
|
|
||||||
NetESignal*ethis = new NetESignal(net);
|
parms[0] = this_expr;
|
||||||
ethis->set_line(*this);
|
|
||||||
parms[0] = ethis;
|
|
||||||
|
|
||||||
elaborate_arguments_(des, scope, def, false, parms, 1, src_parms);
|
elaborate_arguments_(des, scope, def, false, parms, 1, src_parms);
|
||||||
|
|
||||||
|
|
@ -3307,6 +3411,29 @@ NetExpr* PECallFunction::elaborate_class_method_net_(Design*des, NetScope*scope,
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetExpr* PECallFunction::elaborate_expr_chain_(Design*des, NetScope*scope,
|
||||||
|
unsigned flags) const
|
||||||
|
{
|
||||||
|
ivl_assert(*this, chain_prefix_);
|
||||||
|
NetExpr* inner = chain_prefix_->elaborate_expr(des, scope, -1, flags);
|
||||||
|
if (inner == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const netclass_t* cls = dynamic_cast<const netclass_t*>(inner->net_type());
|
||||||
|
if (cls == 0) {
|
||||||
|
cerr << get_fileline() << ": error: "
|
||||||
|
<< "The prefix of a chained call (a().b()) must be an expression "
|
||||||
|
<< "with class type." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
delete inner;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
perm_string method_name = peek_tail_name(path_);
|
||||||
|
return elaborate_class_method_net_this_(des, scope, inner, cls,
|
||||||
|
method_name, &parms_);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle obj.m1().m2(args): arguments apply only to the last call; intermediate
|
* Handle obj.m1().m2(args): arguments apply only to the last call; intermediate
|
||||||
* methods must be class methods returning class handles.
|
* methods must be class methods returning class handles.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Chained call: function returns class handle, then method on result (a().b()).
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
class C;
|
||||||
|
function int f;
|
||||||
|
f = 7;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
function C get_c;
|
||||||
|
get_c = new;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
int x;
|
||||||
|
x = get_c().f();
|
||||||
|
if (x !== 7) begin
|
||||||
|
$display("FAILED");
|
||||||
|
end else begin
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -273,6 +273,7 @@ sv_byte_array_string_fail2 vvp_tests/sv_byte_array_string_fail2.json
|
||||||
sv_byte_array_string_fail3 vvp_tests/sv_byte_array_string_fail3.json
|
sv_byte_array_string_fail3 vvp_tests/sv_byte_array_string_fail3.json
|
||||||
sv_byte_array_string_fail4 vvp_tests/sv_byte_array_string_fail4.json
|
sv_byte_array_string_fail4 vvp_tests/sv_byte_array_string_fail4.json
|
||||||
sv_byte_array_string_fail5 vvp_tests/sv_byte_array_string_fail5.json
|
sv_byte_array_string_fail5 vvp_tests/sv_byte_array_string_fail5.json
|
||||||
|
sv_call_chain_method1 vvp_tests/sv_call_chain_method1.json
|
||||||
sv_chained_constructor1 vvp_tests/sv_chained_constructor1.json
|
sv_chained_constructor1 vvp_tests/sv_chained_constructor1.json
|
||||||
sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json
|
sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json
|
||||||
sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json
|
sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_call_chain_method1.v",
|
||||||
|
"iverilog-args" : [ "-g2012" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "Classes are not supported",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
34
parse.y
34
parse.y
|
|
@ -931,7 +931,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
||||||
%type <spec_optional_args> timeskew_fullskew_opt_remain_active_flag
|
%type <spec_optional_args> timeskew_fullskew_opt_remain_active_flag
|
||||||
|
|
||||||
%type <expr> assignment_pattern expression expression_opt expr_mintypmax
|
%type <expr> assignment_pattern expression expression_opt expr_mintypmax
|
||||||
%type <expr> expr_primary_or_typename expr_primary
|
%type <expr> expr_primary_or_typename expr_primary call_chain_expr
|
||||||
%type <expr> class_new dynamic_array_new
|
%type <expr> class_new dynamic_array_new
|
||||||
%type <expr> net_decl_initializer_opt var_decl_initializer_opt initializer_opt
|
%type <expr> net_decl_initializer_opt var_decl_initializer_opt initializer_opt
|
||||||
%type <expr> inc_or_dec_expression inside_expression lpvalue
|
%type <expr> inc_or_dec_expression inside_expression lpvalue
|
||||||
|
|
@ -4238,6 +4238,26 @@ expr_primary_or_typename
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* SystemVerilog: a().b() — call a function, then invoke a method on the
|
||||||
|
returned class handle. Extends with further ".id(args)" as needed. */
|
||||||
|
|
||||||
|
call_chain_expr
|
||||||
|
: hierarchy_identifier attribute_list_opt argument_list_parens
|
||||||
|
{ PECallFunction*tmp = pform_make_call_function(@1, *$1, *$3);
|
||||||
|
delete $1;
|
||||||
|
delete $2;
|
||||||
|
delete $3;
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
|
| call_chain_expr '.' hierarchy_identifier attribute_list_opt argument_list_parens
|
||||||
|
{ PECallFunction*tmp = pform_make_chained_call_function(@2, $1, *$3, *$5);
|
||||||
|
delete $3;
|
||||||
|
delete $4;
|
||||||
|
delete $5;
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
expr_primary
|
expr_primary
|
||||||
: number
|
: number
|
||||||
{ assert($1);
|
{ assert($1);
|
||||||
|
|
@ -4297,6 +4317,11 @@ expr_primary
|
||||||
/* The hierarchy_identifier rule matches simple identifiers as well as
|
/* The hierarchy_identifier rule matches simple identifiers as well as
|
||||||
indexed arrays and part selects */
|
indexed arrays and part selects */
|
||||||
|
|
||||||
|
/* SV call chains get_c1().f() — must come before bare hierarchy_identifier
|
||||||
|
so `id (` is not reduced as PEIdent + error. */
|
||||||
|
| call_chain_expr
|
||||||
|
{ $$ = $1;
|
||||||
|
}
|
||||||
| hierarchy_identifier
|
| hierarchy_identifier
|
||||||
{ PEIdent*tmp = pform_new_ident(@1, *$1);
|
{ PEIdent*tmp = pform_new_ident(@1, *$1);
|
||||||
FILE_NAME(tmp, @1);
|
FILE_NAME(tmp, @1);
|
||||||
|
|
@ -4347,13 +4372,6 @@ expr_primary
|
||||||
function call. If a system identifier, then a system function
|
function call. If a system identifier, then a system function
|
||||||
call. It can also be a call to a class method (function). */
|
call. It can also be a call to a class method (function). */
|
||||||
|
|
||||||
| hierarchy_identifier attribute_list_opt argument_list_parens
|
|
||||||
{ PECallFunction*tmp = pform_make_call_function(@1, *$1, *$3);
|
|
||||||
delete $1;
|
|
||||||
delete $2;
|
|
||||||
delete $3;
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
|
||||||
| class_hierarchy_identifier argument_list_parens
|
| class_hierarchy_identifier argument_list_parens
|
||||||
{ PECallFunction*tmp = pform_make_call_function(@1, *$1, *$2);
|
{ PECallFunction*tmp = pform_make_call_function(@1, *$1, *$2);
|
||||||
delete $1;
|
delete $1;
|
||||||
|
|
|
||||||
18
pform.cc
18
pform.cc
|
|
@ -975,6 +975,24 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc,
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PECallFunction* pform_make_chained_call_function(const struct vlltype&loc,
|
||||||
|
PExpr*prefix,
|
||||||
|
const pform_name_t&method,
|
||||||
|
const list<named_pexpr_t> &parms)
|
||||||
|
{
|
||||||
|
if (!gn_system_verilog()) {
|
||||||
|
pform_requires_sv(loc, "Chained calls like a().b()");
|
||||||
|
delete prefix;
|
||||||
|
return new PECallFunction(method, parms);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_potential_imports(loc, method.front().name, true);
|
||||||
|
|
||||||
|
PECallFunction*tmp = new PECallFunction(prefix, method, parms);
|
||||||
|
FILE_NAME(tmp, loc);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
PCallTask* pform_make_call_task(const struct vlltype&loc,
|
PCallTask* pform_make_call_task(const struct vlltype&loc,
|
||||||
const pform_name_t&name,
|
const pform_name_t&name,
|
||||||
const list<named_pexpr_t> &parms)
|
const list<named_pexpr_t> &parms)
|
||||||
|
|
|
||||||
4
pform.h
4
pform.h
|
|
@ -333,6 +333,10 @@ extern void pform_set_type_referenced(const struct vlltype&loc, const char*name)
|
||||||
extern PECallFunction* pform_make_call_function(const struct vlltype&loc,
|
extern PECallFunction* pform_make_call_function(const struct vlltype&loc,
|
||||||
const pform_name_t&name,
|
const pform_name_t&name,
|
||||||
const std::list<named_pexpr_t> &parms);
|
const std::list<named_pexpr_t> &parms);
|
||||||
|
extern PECallFunction* pform_make_chained_call_function(const struct vlltype&loc,
|
||||||
|
PExpr*prefix,
|
||||||
|
const pform_name_t&method,
|
||||||
|
const std::list<named_pexpr_t> &parms);
|
||||||
extern PCallTask* pform_make_call_task(const struct vlltype&loc,
|
extern PCallTask* pform_make_call_task(const struct vlltype&loc,
|
||||||
const pform_name_t&name,
|
const pform_name_t&name,
|
||||||
const std::list<named_pexpr_t> &parms);
|
const std::list<named_pexpr_t> &parms);
|
||||||
|
|
|
||||||
|
|
@ -421,6 +421,10 @@ void PEConcat::dump(ostream&out) const
|
||||||
|
|
||||||
void PECallFunction::dump(ostream &out) const
|
void PECallFunction::dump(ostream &out) const
|
||||||
{
|
{
|
||||||
|
if (peek_chain_prefix()) {
|
||||||
|
peek_chain_prefix()->dump(out);
|
||||||
|
out << ".";
|
||||||
|
}
|
||||||
out << path_ << "(" << parms_ << ")";
|
out << path_ << "(" << parms_ << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue