Add support for binding function/task arguments by name

In addition to providing positional arguments for task and functions
SystemVerilog allows to bind arguments by name. This is similar to how
module ports can be bound by name.

```
task t(int a, int b); ... endtask
...
t(.b(1), .a(2));
```

Extend the parser and elaboration stage to be able to handle this. During
elaboration the named argument list is transformed into a purely positional
list so that later stages like synthesis do not have to care about the
names.

For system functions and tasks all arguments must be unnamed, otherwise an
error will be reported.

In addition to functions and tasks arguments can also be bound by name for
the various different ways of invoking a class constructor.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2023-01-06 19:13:29 -08:00
parent 102d85c4e5
commit f6a51bc9db
19 changed files with 504 additions and 274 deletions

View File

@ -114,7 +114,8 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
net_event.o net_expr.o net_func.o \
net_func_eval.o net_link.o net_modulo.o \
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
net_udp.o map_named_args.o \
pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
pform_disciplines.o pform_dump.o pform_package.o pform_pclass.o \
pform_types.o \
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o vpi_modules.o target.o \

View File

@ -215,12 +215,12 @@ PEBShift::~PEBShift()
{
}
PECallFunction::PECallFunction(const pform_name_t&n, const vector<PExpr *> &parms)
PECallFunction::PECallFunction(const pform_name_t &n, const vector<named_pexpr_t> &parms)
: path_(n), parms_(parms), is_overridden_(false)
{
}
PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const vector<PExpr *> &parms)
PECallFunction::PECallFunction(PPackage *pkg, const pform_name_t &n, const vector<named_pexpr_t> &parms)
: path_(pkg, n), parms_(parms), is_overridden_(false)
{
}
@ -233,12 +233,12 @@ static pform_name_t pn_from_ps(perm_string n)
return tmp;
}
PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const list<PExpr *> &parms)
PECallFunction::PECallFunction(PPackage *pkg, const pform_name_t &n, const list<named_pexpr_t> &parms)
: path_(pkg, n), parms_(parms.begin(), parms.end()), is_overridden_(false)
{
}
PECallFunction::PECallFunction(perm_string n, const vector<PExpr*>&parms)
PECallFunction::PECallFunction(perm_string n, const vector<named_pexpr_t> &parms)
: path_(pn_from_ps(n)), parms_(parms), is_overridden_(false)
{
}
@ -249,13 +249,13 @@ PECallFunction::PECallFunction(perm_string n)
}
// NOTE: Anachronism. Try to work all use of svector out.
PECallFunction::PECallFunction(const pform_name_t&n, const list<PExpr *> &parms)
PECallFunction::PECallFunction(const pform_name_t &n, const list<named_pexpr_t> &parms)
: path_(n), parms_(parms.begin(), parms.end()), is_overridden_(false)
{
}
PECallFunction::PECallFunction(perm_string n, const list<PExpr*>&parms)
: package_(0), path_(pn_from_ps(n)), parms_(parms.begin(), parms.end()), is_overridden_(false)
PECallFunction::PECallFunction(perm_string n, const list<named_pexpr_t> &parms)
: path_(pn_from_ps(n)), parms_(parms.begin(), parms.end()), is_overridden_(false)
{
}
@ -265,18 +265,18 @@ PECallFunction::~PECallFunction()
void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
{
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx])
parms_[idx]->declare_implicit_nets(scope, type);
for (const auto &parm : parms_) {
if (parm.parm)
parm.parm->declare_implicit_nets(scope, type);
}
}
bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
{
bool flag = false;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx])
flag |= parms_[idx]->has_aa_term(des, scope);
for (const auto &parm : parms_) {
if (parm.parm)
flag |= parm.parm->has_aa_term(des, scope);
}
return flag;
}
@ -466,7 +466,7 @@ PENewClass::PENewClass(void)
{
}
PENewClass::PENewClass(const list<PExpr*>&p, data_type_t *class_type)
PENewClass::PENewClass(const list<named_pexpr_t> &p, data_type_t *class_type)
: parms_(p.begin(), p.end()), class_type_(class_type)
{
}

18
PExpr.h
View File

@ -570,7 +570,7 @@ class PENewClass : public PExpr {
// New without (or with default) constructor
explicit PENewClass ();
// New with constructor arguments
explicit PENewClass (const std::list<PExpr*>&p,
explicit PENewClass (const std::list<named_pexpr_t> &p,
data_type_t *class_type = nullptr);
~PENewClass();
@ -592,7 +592,7 @@ class PENewClass : public PExpr {
NetExpr*obj, unsigned flags) const;
private:
std::vector<PExpr*>parms_;
std::vector<named_pexpr_t> parms_;
data_type_t *class_type_;
};
@ -895,20 +895,20 @@ class PETernary : public PExpr {
*/
class PECallFunction : public PExpr {
public:
explicit PECallFunction(const pform_name_t&n, const std::vector<PExpr *> &parms);
explicit PECallFunction(const pform_name_t &n, const std::vector<named_pexpr_t> &parms);
// Call function defined in package.
explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::list<PExpr *> &parms);
explicit PECallFunction(PPackage *pkg, const pform_name_t &n, const std::list<named_pexpr_t> &parms);
// Used to convert a user function called as a task
explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::vector<PExpr *> &parms);
explicit PECallFunction(PPackage *pkg, const pform_name_t &n, const std::vector<named_pexpr_t> &parms);
// Call of system function (name is not hierarchical)
explicit PECallFunction(perm_string n, const std::vector<PExpr *> &parms);
explicit PECallFunction(perm_string n, const std::vector<named_pexpr_t> &parms);
explicit PECallFunction(perm_string n);
// std::list versions. Should be removed!
explicit PECallFunction(const pform_name_t&n, const std::list<PExpr *> &parms);
explicit PECallFunction(perm_string n, const std::list<PExpr *> &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);
~PECallFunction();
@ -929,7 +929,7 @@ class PECallFunction : public PExpr {
private:
pform_scoped_name_t path_;
std::vector<PExpr *> parms_;
std::vector<named_pexpr_t> parms_;
// For system functions.
bool is_overridden_;

View File

@ -63,7 +63,8 @@ class PTaskFunc : public PScope, public PNamedItem {
// default value expressions, if any.
void elaborate_sig_ports_(Design*des, NetScope*scope,
std::vector<NetNet*>&ports,
std::vector<NetExpr*>&pdefs) const;
std::vector<NetExpr*> &pdefs,
std::vector<perm_string> &port_names) const;
void dump_ports_(std::ostream&out, unsigned ind) const;

View File

@ -166,17 +166,17 @@ PNamedItem::SymbolType PBlock::symbol_type() const
return BLOCK;
}
PCallTask::PCallTask(const pform_name_t&n, const list<PExpr*>&p)
PCallTask::PCallTask(const pform_name_t &n, const list<named_pexpr_t> &p)
: package_(0), path_(n), parms_(p.begin(), p.end())
{
}
PCallTask::PCallTask(PPackage*pkg, const pform_name_t&n, const list<PExpr*>&p)
PCallTask::PCallTask(PPackage *pkg, const pform_name_t &n, const list<named_pexpr_t> &p)
: package_(pkg), path_(n), parms_(p.begin(), p.end())
{
}
PCallTask::PCallTask(perm_string n, const list<PExpr*>&p)
PCallTask::PCallTask(perm_string n, const list<named_pexpr_t> &p)
: package_(0), parms_(p.begin(), p.end())
{
path_.push_back(name_component_t(n));
@ -216,11 +216,16 @@ PCAssign::~PCAssign()
delete expr_;
}
PChainConstructor::PChainConstructor(const list<PExpr*>&parms)
PChainConstructor::PChainConstructor(const list<named_pexpr_t> &parms)
: parms_(parms.begin(), parms.end())
{
}
PChainConstructor::PChainConstructor(const vector<named_pexpr_t> &parms)
: parms_(parms)
{
}
PChainConstructor::~PChainConstructor()
{
}

View File

@ -223,9 +223,9 @@ class PBreak : public Statement {
class PCallTask : public Statement {
public:
explicit PCallTask(PPackage*pkg, const pform_name_t&n, const std::list<PExpr*>&parms);
explicit PCallTask(const pform_name_t&n, const std::list<PExpr*>&parms);
explicit PCallTask(perm_string n, const std::list<PExpr*>&parms);
explicit PCallTask(PPackage *pkg, const pform_name_t &n, const std::list<named_pexpr_t> &parms);
explicit PCallTask(const pform_name_t &n, const std::list<named_pexpr_t> &parms);
explicit PCallTask(perm_string n, const std::list<named_pexpr_t> &parms);
~PCallTask();
const pform_name_t& path() const;
@ -253,11 +253,13 @@ class PCallTask : public Statement {
NetProc*elaborate_sys_task_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const;
const char *sys_task_name,
const std::vector<perm_string> &parm_names = {}) const;
NetProc*elaborate_queue_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const;
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const;
NetProc*elaborate_method_func_(NetScope*scope,
NetNet*net,
ivl_type_t type,
@ -267,7 +269,7 @@ class PCallTask : public Statement {
PPackage*package_;
pform_name_t path_;
std::vector<PExpr*> parms_;
std::vector<named_pexpr_t> parms_;
bool void_cast_ = false;
};
@ -320,17 +322,18 @@ class PCAssign : public Statement {
*/
class PChainConstructor : public Statement {
public:
explicit PChainConstructor(const std::list<PExpr*>&parms);
explicit PChainConstructor(const std::list<named_pexpr_t> &parms);
explicit PChainConstructor(const std::vector<named_pexpr_t> &parms);
~PChainConstructor();
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void dump(std::ostream&out, unsigned ind) const;
inline const std::vector<PExpr*>& chain_args(void) const
inline const std::vector<named_pexpr_t>& chain_args(void) const
{ return parms_; }
private:
std::vector<PExpr*> parms_;
std::vector<named_pexpr_t> parms_;
};
class PCondit : public Statement {

View File

@ -40,6 +40,7 @@
# include "netscalar.h"
# include "util.h"
# include "ivl_assert.h"
# include "map_named_args.h"
using namespace std;
@ -1374,7 +1375,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
// The Icarus Verilog specific $ivlh_to_unsigned() system
// task takes a second argument which is the output
// size. This can be an arbitrary constant function.
PExpr*pexpr = parms_[1];
PExpr *pexpr = parms_[1].parm;
if (pexpr == 0) {
cerr << get_fileline() << ": error: "
<< "Missing $ivlh_to_unsigned width." << endl;
@ -1396,7 +1397,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
// The argument width is self-determined and doesn't
// affect the result width.
width_mode_t arg_mode = SIZED;
parms_[0]->test_width(des, scope, arg_mode);
parms_[0].parm->test_width(des, scope, arg_mode);
expr_type_ = pexpr->expr_type();
expr_width_ = value;
@ -1406,7 +1407,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
}
if (name=="$signed" || name=="$unsigned") {
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
if (expr == 0)
return 0;
@ -1423,7 +1424,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
}
if (name=="$sizeof" || name=="$bits") {
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
if (expr == 0)
return 0;
@ -1450,7 +1451,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
}
if (name=="$is_signed") {
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
if (expr == 0)
return 0;
@ -1887,6 +1888,17 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
{
perm_string name = peek_tail_name(path_);
// System functions don't have named parameters
for (const auto &parm : parms_) {
if (!parm.name.nil()) {
des->errors++;
cerr << parm.get_fileline() << ": error: "
<< "The system function `" << name
<< "` has no argument called `" << parm.name << "`."
<< endl;
}
}
/* Catch the special case that the system function is the
$ivl_unsigned function. In this case the second argument is
the size of the expression, but should already be accounted
@ -1894,7 +1906,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
if (name=="$ivlh_to_unsigned") {
ivl_assert(*this, parms_.size()==2);
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
ivl_assert(*this, expr);
NetExpr*sub = expr->elaborate_expr(des, scope, expr->expr_width(), flags);
return cast_to_width_(sub, expr_wid);
@ -1904,7 +1916,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
function. Its argument will be evaluated as a self-determined
expression. */
if (name=="$signed" || name=="$unsigned") {
if ((parms_.size() != 1) || (parms_[0] == 0)) {
if ((parms_.size() != 1) || !parms_[0].parm) {
cerr << get_fileline() << ": error: The " << name
<< " function takes exactly one(1) argument." << endl;
des->errors += 1;
@ -1922,7 +1934,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: "
<< name << " expression is the argument cast to expr_wid=" << expr_wid << endl;
}
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags);
return cast_to_width_(sub, expr_wid);
@ -1933,7 +1945,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
sub-expression is not used, so the expression itself can be
deleted. */
if (name=="$sizeof" || name=="$bits") {
if ((parms_.size() != 1) || (parms_[0] == 0)) {
if ((parms_.size() != 1) || !parms_[0].parm) {
cerr << get_fileline() << ": error: The " << name
<< " function takes exactly one(1) argument." << endl;
des->errors += 1;
@ -1944,7 +1956,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
cerr << get_fileline() << ": warning: $sizeof is deprecated."
<< " Use $bits() instead." << endl;
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
uint64_t use_width = 0;
if (PETypename*type_expr = dynamic_cast<PETypename*>(expr)) {
@ -1991,14 +2003,14 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
a single bit flag -- 1 if the expression is signed, 0
otherwise. */
if (name=="$is_signed") {
if ((parms_.size() != 1) || (parms_[0] == 0)) {
if ((parms_.size() != 1) || !parms_[0].parm) {
cerr << get_fileline() << ": error: The " << name
<< " function takes exactly one(1) argument." << endl;
des->errors += 1;
return 0;
}
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
verinum val (expr->has_sign() ? verinum::V1 : verinum::V0, 1);
NetEConst*sub = new NetEConst(val);
@ -2039,7 +2051,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
expression if one is created. */
/* These functions can work in a constant context with a signal expression. */
if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0]))) {
if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0].parm))) {
if (strcmp(name, "$dimensions") == 0) need_const = false;
else if (strcmp(name, "$high") == 0) need_const = false;
else if (strcmp(name, "$increment") == 0) need_const = false;
@ -2053,7 +2065,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
unsigned parm_errors = 0;
unsigned missing_parms = 0;
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
PExpr*expr = parms_[idx];
PExpr *expr = parms_[idx].parm;
if (expr) {
NetExpr*tmp = elab_sys_task_arg(des, scope, name, idx,
expr, need_const);
@ -2092,7 +2104,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
NetBranch*branch = 0;
if (parms_.size() == 1) {
PExpr*arg1 = parms_[0];
PExpr *arg1 = parms_[0].parm;
PEIdent*arg_ident = dynamic_cast<PEIdent*> (arg1);
ivl_assert(*this, arg_ident);
@ -2147,7 +2159,7 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
const pform_scoped_name_t&use_path,
perm_string method_name,
NetExpr*expr,
PExpr*parg, unsigned args)
const std::vector<named_pexpr_t> &parms)
{
if (debug_elaborate) {
cerr << li->get_fileline() << ": " << __func__ << ": "
@ -2168,9 +2180,9 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
// The "num()" method returns the number of elements. This is
// actually a static constant, and can be replaced at compile time
// with a constant value.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".num() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2184,9 +2196,9 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
// The "first()" method returns the first enumeration value. This
// doesn't actually care about the constant value, and instead
// returns as a constant literal the first value of the enumeration.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".first() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2201,9 +2213,9 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
// The "last()" method returns the first enumeration value. This
// doesn't actually care about the constant value, and instead
// returns as a constant literal the last value of the enumeration.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".last() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2216,34 +2228,14 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
NetESFunc*sys_expr;
// Process the method argument if it is available.
NetExpr* count = 0;
if (args != 0 && parg) {
count = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
parg);
if (count == 0) {
cerr << li->get_fileline() << ": error: unable to elaborate "
"enumeration method argument " << use_path << "."
<< method_name << "(" << parg << ")." << endl;
args = 0;
des->errors += 1;
} else if (NetEEvent*evt = dynamic_cast<NetEEvent*> (count)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' cannot be an enumeration "
"method argument." << endl;
args = 0;
des->errors += 1;
}
}
if (method_name == "name") {
// The "name()" method returns the name of the current enumeration
// value. The generated system task takes the enumeration
// definition and the enumeration value. The return value is the
// string name of the enumeration.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".name() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2257,37 +2249,51 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
sys_expr->parm(0, def);
sys_expr->parm(1, expr);
} else if (method_name == "next") {
// The "next()" method returns the next enumeration value.
if (args > 1) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".next() take at "
"most one argument." << endl;
des->errors += 1;
}
sys_expr = new NetESFunc("$ivl_enum_method$next", netenum,
2 + (args != 0));
NetENetenum* def = new NetENetenum(netenum);
def->set_line(*li);
sys_expr->parm(0, def);
sys_expr->parm(1, expr);
if (args != 0) sys_expr->parm(2, count);
} else if (method_name == "next" || method_name == "prev") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("N"),
};
auto args = map_named_args(des, parm_names, parms);
} else if (method_name == "prev") {
// The "prev()" method returns the previous enumeration value.
if (args > 1) {
// Process the method argument if it is available.
NetExpr *count = nullptr;
if (args.size() != 0 && args[0]) {
count = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
args[0]);
if (!count) {
cerr << li->get_fileline() << ": error: unable to elaborate "
"enumeration method argument " << use_path << "."
<< method_name << "(" << args[0] << ")." << endl;
des->errors++;
} else if (NetEEvent *evt = dynamic_cast<NetEEvent*> (count)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' cannot be an enumeration "
"method argument." << endl;
des->errors++;
}
}
// The "next()" and "prev()" methods returns the next or previous enumeration value.
if (args.size() > 1) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".prev() take at "
"method " << use_path << " takes at "
"most one argument." << endl;
des->errors += 1;
}
sys_expr = new NetESFunc("$ivl_enum_method$prev", netenum,
2 + (args != 0));
const char *func_name;
if (method_name == "next")
func_name = "$ivl_enum_method$next";
else
func_name = "$ivl_enum_method$prev";
sys_expr = new NetESFunc(func_name, netenum,
2 + (count != nullptr));
NetENetenum* def = new NetENetenum(netenum);
def->set_line(*li);
sys_expr->parm(0, def);
sys_expr->parm(1, expr);
if (args != 0) sys_expr->parm(2, count);
if (count) sys_expr->parm(2, count);
} else {
// This is an unknown enumeration method.
@ -3119,9 +3125,12 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
des->errors += 1;
}
auto args = map_named_args(des, def, parms_, parm_off);
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
unsigned pidx = idx + parm_off;
PExpr*tmp = (idx < actual_count) ? parms_[idx] : NULL;
PExpr *tmp = args[idx];
if (tmp) {
parms[pidx] = elaborate_rval_expr(des, scope,
def->port(pidx)->net_type(),
@ -3354,12 +3363,10 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
// Get the method name that we are looking for.
perm_string method_name = search_results.path_tail.back().name;
PExpr*tmp = parms_.size() ? parms_[0] : NULL;
return check_for_enum_methods(this, des, scope,
netenum, path_,
method_name, sub_expr,
tmp, parms_.size());
parms_);
}
// Class methods. Generate function call to the class method.
@ -3437,6 +3444,17 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
}
if (method_name == "substr") {
if (parms_.size() != 2)
cerr << get_fileline() << ": error: Method `substr()`"
<< " requires 2 arguments, got " << parms_.size()
<< "." << endl;
static const std::vector<perm_string> parm_names = {
perm_string::literal("i"),
perm_string::literal("j")
};
auto args = map_named_args(des, parm_names, parms_);
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$substr",
&netstring_t::type_string, 3);
sys_expr->set_line(*this);
@ -3444,16 +3462,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
// First argument is the source string.
sys_expr->parm(0, sub_expr);
ivl_assert(*this, parms_.size() == 2);
NetExpr*tmp;
for (int i = 0; i < 2; i++) {
if (!args[i])
continue;
tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
parms_[0], false);
sys_expr->parm(1, tmp);
tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
parms_[1], false);
sys_expr->parm(2, tmp);
auto expr = elaborate_rval_expr(des, scope,
&netvector_t::atom2u32,
args[i], false);
sys_expr->parm(i + 1, expr);
}
return sys_expr;
}
@ -4943,7 +4960,7 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
return check_for_enum_methods(this, des, scope,
netenum, sr.path_head,
member_comp.name,
expr, NULL, 0);
expr, {});
}
ivl_assert(*this, sr.path_tail.empty());
@ -6661,8 +6678,8 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
// generate an error message. The case of too few arguments
// will be handled below, when we run out of arguments.
if ((parms_.size()+1) > def->port_count()) {
cerr << get_fileline() << ": error: Parm count mismatch"
<< " passing " << parms_.size() << " arguments "
cerr << get_fileline() << ": error: Argument count mismatch."
<< " Passing " << parms_.size() << " arguments"
<< " to constructor expecting " << (def->port_count()-1)
<< " arguments." << endl;
des->errors += 1;
@ -6671,14 +6688,15 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
vector<NetExpr*> parms (def->port_count());
parms[0] = obj;
auto args = map_named_args(des, def, parms_, 1);
int missing_parms = 0;
for (size_t idx = 1 ; idx < parms.size() ; idx += 1) {
// While there are default arguments, check them.
if (idx <= parms_.size() && parms_[idx-1]) {
PExpr*tmp = parms_[idx-1];
if (args[idx - 1]) {
parms[idx] = elaborate_rval_expr(des, scope,
def->port(idx)->net_type(),
tmp, false);
args[idx - 1], false);
// NOTE: if elaborate_rval_expr fails, it will return a
// nullptr, but it will also increment des->errors so there
// is nothing we need to do here.

View File

@ -688,7 +688,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
vector<NetNet*>ports;
vector<NetExpr*>pdef;
elaborate_sig_ports_(des, scope, ports, pdef);
vector<perm_string> port_names;
elaborate_sig_ports_(des, scope, ports, pdef, port_names);
NetFuncDef*def = new NetFuncDef(scope, ret_sig, ports, pdef);
@ -722,7 +723,8 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
vector<NetNet*>ports;
vector<NetExpr*>pdefs;
elaborate_sig_ports_(des, scope, ports, pdefs);
vector<perm_string> port_names;
elaborate_sig_ports_(des, scope, ports, pdefs, port_names);
NetTaskDef*def = new NetTaskDef(scope, ports, pdefs);
scope->set_task_def(def);
@ -732,11 +734,14 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
}
void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
vector<NetNet*>&ports, vector<NetExpr*>&pdefs) const
vector<NetNet*> &ports,
vector<NetExpr*> &pdefs,
vector<perm_string> &port_names) const
{
if (ports_ == 0) {
ports.clear();
pdefs.clear();
port_names.clear();
/* Make sure the function has at least one input
port. If it fails this test, print an error
@ -755,6 +760,7 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
ports.resize(ports_->size());
pdefs.resize(ports_->size());
port_names.resize(ports_->size());
for (size_t idx = 0 ; idx < ports_->size() ; idx += 1) {
@ -817,6 +823,7 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
}
ports[idx] = tmp;
port_names[idx] = port_name;
pdefs[idx] = tmp_def;
if (scope->type()==NetScope::FUNC && tmp->port_type()!=NetNet::PINPUT) {
cerr << tmp->get_fileline() << ": error: "

View File

@ -54,6 +54,7 @@
# include "parse_api.h"
# include "compiler.h"
# include "ivl_assert.h"
# include "map_named_args.h"
using namespace std;
@ -3301,12 +3302,12 @@ NetProc* PChainConstructor::elaborate(Design*des, NetScope*scope) const
vector<NetExpr*> parms (def->port_count());
parms[0] = eres;
auto args = map_named_args(des, def, parms_, 1);
for (size_t idx = 1 ; idx < parms.size() ; idx += 1) {
if (idx <= parms_.size() && parms_[idx-1]) {
PExpr*tmp = parms_[idx-1];
if (args[idx - 1]) {
parms[idx] = elaborate_rval_expr(des, scope,
def->port(idx)->net_type(),
tmp, false);
args[idx - 1], false);
continue;
}
@ -3480,12 +3481,19 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
perm_string name = peek_tail_name(path_);
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
PExpr*ex = parms_[idx];
if (ex != 0) {
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
} else {
eparms[idx] = 0;
auto &parm = parms_[idx];
// System functions don't have named parameters
if (!parm.name.nil()) {
cerr << parm.get_fileline() << ": error: "
<< "The system task `" << name
<< "` has no argument called `" << parm.name
<< "`." << endl;
des->errors++;
}
eparms[idx] = elab_sys_task_arg(des, scope, name, idx,
parm.parm);
}
// Special case: Specify blocks are turned off, and this is an
@ -3615,7 +3623,8 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const
{
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
@ -3638,17 +3647,17 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
<< "method takes no arguments." << endl;
des->errors += 1;
}
} else if (parm_names.size() != parms_.size()) {
cerr << get_fileline() << ": error: " << method_name
<< "() method takes " << parm_names.size() << " arguments, got "
<< parms_.size() << "." << endl;
des->errors++;
}
auto args = map_named_args(des, parm_names, parms_);
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
PExpr*ex = parms_[idx];
if (ex != 0) {
argv[idx+1] = elab_sys_task_arg(des, scope,
method_name,
idx, ex);
} else {
argv[idx+1] = 0;
}
argv[idx + 1] = elab_sys_task_arg(des, scope, method_name,
idx, args[idx]);
}
NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv);
@ -3663,7 +3672,8 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const
{
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
@ -3696,33 +3706,38 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
vector<NetExpr*>argv (nparms+1);
argv[0] = sig;
if (method_name != "insert") {
if ((nparms == 0) || (parms_[0] == 0)) {
argv[1] = 0;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else
argv[1] = elab_and_eval(des, scope, parms_[0], context_width,
false, false, base_type);
} else {
if ((nparms == 0) || (parms_[0] == 0)) {
argv[1] = 0;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else
argv[1] = elab_and_eval(des, scope, parms_[0], 32,
false, false, IVL_VT_LOGIC);
if ((nparms < 2) || (parms_[1] == 0)) {
argv[2] = 0;
auto args = map_named_args(des, parm_names, parms_);
if (method_name != "insert") {
if (nparms == 0 || !args[0]) {
argv[1] = nullptr;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else {
argv[1] = elab_and_eval(des, scope, args[0], context_width,
false, false, base_type);
}
} else {
if (nparms == 0 || !args[0]) {
argv[1] = nullptr;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else {
argv[1] = elab_and_eval(des, scope, args[0], context_width,
false, false, IVL_VT_LOGIC);
}
if (nparms < 2 || !args[1]) {
argv[2] = nullptr;
cerr << get_fileline() << ": error: " << method_name
<< "() methods second argument is missing." << endl;
des->errors += 1;
} else
argv[2] = elab_and_eval(des, scope, parms_[1], context_width,
} else {
argv[2] = elab_and_eval(des, scope, args[1], context_width,
false, false, base_type);
}
}
NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv);
@ -3814,34 +3829,65 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
// Is this a method of a "string" type?
if (dynamic_cast<const netstring_t*>(net->net_type())) {
if (method_name=="itoa")
if (method_name == "itoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$itoa");
else if (method_name=="hextoa")
"$ivl_string_method$itoa",
parm_names);
} else if (method_name == "hextoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$hextoa");
else if (method_name=="octtoa")
"$ivl_string_method$hextoa",
parm_names);
} else if (method_name == "octtoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$octtoa");
else if (method_name=="bintoa")
"$ivl_string_method$octtoa",
parm_names);
} else if (method_name == "bintoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$bintoa");
else if (method_name=="realtoa")
"$ivl_string_method$bintoa",
parm_names);
} else if (method_name == "realtoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("r")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$realtoa");
"$ivl_string_method$realtoa",
parm_names);
}
}
// Is this a delete method for dynamic arrays or queues?
if (net->darray_type()) {
if (method_name=="delete")
if (method_name == "delete") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("index")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_darray_method$delete");
else if (method_name=="size")
"$ivl_darray_method$delete",
parm_names);
} else if (method_name == "size") {
// This returns an int. It could be removed, but keep for now.
return elaborate_method_func_(scope, net,
&netvector_t::atom2s32,
method_name, "$size");
else if (method_name=="reverse") {
} else if (method_name == "reverse") {
cerr << get_fileline() << ": sorry: 'reverse()' "
"array sorting method is not currently supported."
<< endl;
@ -3870,25 +3916,42 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
if (net->queue_type()) {
const netdarray_t*use_darray = net->darray_type();
if (method_name == "push_back")
if (method_name == "push_back") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
"$ivl_queue_method$push_back");
else if (method_name == "push_front")
"$ivl_queue_method$push_back",
parm_names);
} else if (method_name == "push_front") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
"$ivl_queue_method$push_front");
else if (method_name == "insert")
"$ivl_queue_method$push_front",
parm_names);
} else if (method_name == "insert") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("index"),
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
"$ivl_queue_method$insert");
else if (method_name == "pop_front")
"$ivl_queue_method$insert",
parm_names);
} else if (method_name == "pop_front") {
return elaborate_method_func_(scope, net,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_front");
else if (method_name == "pop_back")
} else if (method_name == "pop_back") {
return elaborate_method_func_(scope, net,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_back");
}
}
if (const netclass_t*class_type = dynamic_cast<const netclass_t*>(par_type)) {
@ -4096,9 +4159,11 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
expression the r-value. We know by definition that the port
is a reg type, so this elaboration is pretty obvious. */
for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) {
unsigned int off = use_this ? 1 : 0;
size_t parms_idx = use_this? idx-1 : idx;
auto args = map_named_args(des, def, parms_, off);
for (unsigned int idx = off; idx < parm_count; idx++) {
size_t parms_idx = idx - off;
NetNet*port = def->port(idx);
ivl_assert(*this, port->port_type() != NetNet::NOT_A_PORT);
@ -4111,9 +4176,9 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
NetExpr*rv = 0;
if (parms_idx < parms_.size() && parms_[parms_idx]) {
if (args[parms_idx]) {
rv = elaborate_rval_expr(des, scope, port->net_type(),
parms_ [parms_idx]);
args[parms_idx]);
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' can not be a user "
@ -4161,9 +4226,9 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
expression that can be a target to a procedural
assignment, including a memory word. */
for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) {
for (unsigned int idx = off; idx < parm_count; idx++) {
size_t parms_idx = use_this? idx-1 : idx;
size_t parms_idx = idx - off;
NetNet*port = def->port(idx);
@ -4179,12 +4244,12 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
message. Note that the elaborate_lval method already
printed a detailed message for the latter case. */
NetAssign_*lv = 0;
if (parms_idx < parms_.size() && parms_[parms_idx]) {
lv = parms_[parms_idx]->elaborate_lval(des, scope, false, false);
if (args[parms_idx]) {
lv = args[parms_idx]->elaborate_lval(des, scope, false, false);
if (lv == 0) {
cerr << parms_[parms_idx]->get_fileline() << ": error: "
cerr << args[parms_idx]->get_fileline() << ": error: "
<< "I give up on task port " << (idx+1)
<< " expression: " << *parms_[parms_idx] << endl;
<< " expression: " << *args[parms_idx] << endl;
}
} else if (port->port_type() == NetNet::POUTPUT) {
// Output ports were skipped earlier, so
@ -4335,19 +4400,25 @@ bool PCallTask::elaborate_elab(Design*des, NetScope*scope) const
bool const_parms = true;
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
PExpr*ex = parms_[idx];
if (ex != 0) {
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
if (!check_parm_is_const(eparms[idx])) {
cerr << get_fileline() << ": error: Elaboration task "
<< name << "() parameter [" << idx+1 << "] '"
<< *eparms[idx] << "' is not constant." << endl;
des->errors += 1;
const_parms = false;
}
} else {
eparms[idx] = 0;
}
auto &parm = parms_[idx];
// Elaboration tasks don't have named parameters
if (!parm.name.nil()) {
cerr << parm.get_fileline() << ": error: "
<< "The elaboration system task `" << name
<< "` has no argument called `" << parm.name
<< "`." << endl;
des->errors++;
}
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, parm.parm);
if (!check_parm_is_const(eparms[idx])) {
cerr << get_fileline() << ": error: Elaboration task "
<< name << "() parameter [" << idx+1 << "] '"
<< *eparms[idx] << "' is not constant." << endl;
des->errors += 1;
const_parms = false;
}
}
if (!const_parms) return true;

75
map_named_args.cc Normal file
View File

@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: 2023 Lars-Peter Clausen <lars@metafoo.de>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "PExpr.h"
#include "ivl_assert.h"
#include "map_named_args.h"
#include "netlist.h"
#include <iostream>
std::vector<PExpr*> map_named_args(Design *des,
const std::vector<perm_string> &names,
const std::vector<named_pexpr_t> &parms)
{
std::vector<PExpr*> args(names.size());
bool has_named = false;
for (size_t i = 0; i < parms.size(); i++) {
if (parms[i].name.nil()) {
if (!parms[i].parm)
continue;
if (has_named) {
std::cerr << parms[i].get_fileline() << ": error: "
<< "Positional argument must preceded "
<< "named arguments."
<< std::endl;
} else if (i < args.size()) {
args[i] = parms[i].parm;
}
continue;
}
has_named = true;
bool found = false;
for (size_t j = 0; j < names.size(); j++) {
if (names[j] == parms[i].name) {
if (args[j]) {
std::cerr << parms[i].get_fileline() << ": error: "
<< "Argument `"
<< parms[i].name
<< "` has already been specified."
<< std::endl;
des->errors++;
} else {
args[j] = parms[i].parm;
}
found = true;
break;
}
}
if (!found) {
std::cerr << parms[i].get_fileline() << ": error: "
<< "No argument called `"
<< parms[i].name << "`."
<< std::endl;
des->errors++;
}
}
return args;
}
std::vector<PExpr*> map_named_args(Design *des, NetBaseDef *def,
const std::vector<named_pexpr_t> &parms,
unsigned int off)
{
std::vector<perm_string> names;
for (size_t j = off; j < def->port_count(); j++)
names.push_back(def->port(j)->name());
return map_named_args(des, names, parms);
}

22
map_named_args.h Normal file
View File

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2023 Lars-Peter Clausen <lars@metafoo.de>
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef MAP_NAMED_ARGS_H
#define MAP_NAMED_ARGS_H
#include <vector>
#include "pform_types.h"
class PExpr;
class Design;
class NetBaseDef;
std::vector<PExpr*> map_named_args(Design *des,
const std::vector<perm_string> &names,
const std::vector<named_pexpr_t> &parms);
std::vector<PExpr*> map_named_args(Design *des, NetBaseDef *def,
const std::vector<named_pexpr_t> &parms,
unsigned int off);
#endif

View File

@ -1046,6 +1046,9 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
unsigned arg_idx, PExpr*pe, bool need_const)
{
if (!pe)
return nullptr;
PExpr::width_mode_t mode = PExpr::SIZED;
pe->test_width(des, scope, mode);

95
parse.y
View File

@ -172,9 +172,9 @@ template <class T> void append(vector<T>&out, const std::vector<T>&in)
* The parser parses an empty argument list as an argument list with an single
* empty argument. Fix this up here and replace it with an empty list.
*/
static void argument_list_fixup(list<PExpr*>*lst)
static void argument_list_fixup(list<named_pexpr_t> *lst)
{
if (lst->size() == 1 && !lst->front())
if (lst->size() == 1 && lst->front().name.nil() && !lst->front().parm)
lst->clear();
}
@ -184,17 +184,20 @@ static void argument_list_fixup(list<PExpr*>*lst)
*/
static PECallFunction*make_call_function(perm_string tn, PExpr*arg)
{
std::vector<PExpr*> parms(1);
parms[0] = arg;
std::vector<named_pexpr_t> parms(1);
parms[0].parm = arg;
parms[0].set_line(*arg);
PECallFunction*tmp = new PECallFunction(tn, parms);
return tmp;
}
static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
{
std::vector<PExpr*> parms(2);
parms[0] = arg1;
parms[1] = arg2;
std::vector<named_pexpr_t> parms(2);
parms[0].parm = arg1;
parms[0].set_line(*arg1);
parms[1].parm = arg2;
parms[1].set_line(*arg2);
PECallFunction*tmp = new PECallFunction(tn, parms);
return tmp;
}
@ -510,7 +513,7 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
struct {
data_type_t*type;
std::list<PExpr*>*exprs;
std::list<named_pexpr_t> *args;
} class_declaration_extends;
struct {
@ -690,6 +693,10 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
%type <named_pexpr> attribute
%type <named_pexprs> attribute_list attribute_instance_list attribute_list_opt
%type <named_pexpr> argument
%type <named_pexprs> argument_list
%type <named_pexprs> argument_list_parens argument_list_parens_opt
%type <citem> case_item
%type <citems> case_items
@ -717,7 +724,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
%type <expr> delay_value delay_value_simple
%type <exprs> delay1 delay3 delay3_opt delay_value_list
%type <exprs> expression_list_with_nuls expression_list_proper
%type <exprs> argument_list_parens argument_list_parens_opt
%type <exprs> cont_assign cont_assign_list
%type <decl_assignment> variable_decl_assignment
@ -889,7 +895,7 @@ class_declaration /* IEEE1800-2005: A.1.2 */
class_type_t *class_type= new class_type_t(name);
FILE_NAME(class_type, @4);
pform_set_typedef(@4, name, class_type, nullptr);
pform_start_class_declaration(@2, class_type, $5.type, $5.exprs, $1);
pform_start_class_declaration(@2, class_type, $5.type, $5.args, $1);
}
class_items_opt K_endclass
{ // Process a class.
@ -932,11 +938,12 @@ class_declaration_endlabel_opt
class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */
: K_extends ps_type_identifier argument_list_parens_opt
{ $$.type = $2;
$$.exprs = $3;
{ $$.type = $2;
$$.args = $3;
}
|
{ $$.type = 0; $$.exprs = 0; }
{ $$ = {nullptr, nullptr};
}
;
/* The class_items_opt and class_items rules together implement the
@ -2251,7 +2258,7 @@ simple_immediate_assertion_statement /* IEEE1800-2012 A.6.10 */
: assert_or_assume '(' expression ')' statement_or_null %prec less_than_K_else
{
if (gn_supported_assertions_flag) {
std::list<PExpr*>arg_list;
std::list<named_pexpr_t> arg_list;
PCallTask*tmp1 = new PCallTask(lex_strings.make("$error"), arg_list);
FILE_NAME(tmp1, @1);
PCondit*tmp2 = new PCondit($3, $5, tmp1);
@ -3714,12 +3721,45 @@ expression_list_with_nuls
}
;
argument
: expression
{ named_pexpr_t *tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = perm_string();
tmp->parm = $1;
$$ = tmp;
}
| named_expression_opt
{ $$ = $1;
}
|
{ named_pexpr_t *tmp = new named_pexpr_t;
tmp->name = perm_string();
tmp->parm = nullptr;
$$ = tmp;
}
;
argument_list
: argument
{ std::list<named_pexpr_t> *expr = new std::list<named_pexpr_t>;
expr->push_back(*$1);
delete $1;
$$ = expr;
}
| argument_list ',' argument
{ $1->push_back(*$3);
delete $3;
$$ = $1;
}
;
/* An argument list enclosed in parenthesis. The parser will parse '()' as a
* argument list with an single empty item. We fix this up once the list
* parsing is done by replacing it with the empty list.
*/
argument_list_parens
: '(' expression_list_with_nuls ')'
: '(' argument_list ')'
{ argument_list_fixup($2);
$$ = $2; }
;
@ -3731,7 +3771,8 @@ argument_list_parens_opt
: argument_list_parens
{ $$ = $1; }
|
{ $$ = new std::list<PExpr*>; }
{ $$ = new std::list<named_pexpr_t>; }
;
expression_list_proper
: expression_list_proper ',' expression
@ -3874,12 +3915,14 @@ expr_primary
delete $2;
$$ = tmp;
}
| SYSTEM_IDENTIFIER '(' expression_list_proper ')'
| SYSTEM_IDENTIFIER argument_list_parens
{ perm_string tn = lex_strings.make($1);
PECallFunction*tmp = new PECallFunction(tn, *$3);
PECallFunction *tmp = new PECallFunction(tn, *$2);
if ($2->empty())
pform_requires_sv(@1, "Empty function argument list");
FILE_NAME(tmp, @1);
delete[]$1;
delete $3;
delete $2;
$$ = tmp;
}
| package_scope hierarchy_identifier { lex_in_package_scope(0); } argument_list_parens
@ -3889,16 +3932,6 @@ expr_primary
delete $4;
$$ = tmp;
}
| SYSTEM_IDENTIFIER '(' ')'
{ perm_string tn = lex_strings.make($1);
const std::vector<PExpr*>empty;
PECallFunction*tmp = new PECallFunction(tn, empty);
FILE_NAME(tmp, @1);
delete[]$1;
$$ = tmp;
pform_requires_sv(@1, "Empty function argument list");
}
| K_this
{ PEIdent*tmp = new PEIdent(perm_string::literal(THIS_TOKEN));
FILE_NAME(tmp,@1);
@ -6551,7 +6584,7 @@ subroutine_call
}
| hierarchy_identifier '(' error ')'
{ yyerror(@3, "error: Syntax error in task arguments.");
list<PExpr*>pt;
std::list<named_pexpr_t> pt;
PCallTask*tmp = pform_make_call_task(@1, *$1, pt);
delete $1;
$$ = tmp;
@ -6928,7 +6961,7 @@ statement_item /* This is roughly statement_item in the LRM */
} else {
yyerror(@2, "error: Constraint block can only be applied to randomize method.");
}
list<PExpr*>pt;
list<named_pexpr_t> pt;
PCallTask*tmp = new PCallTask(*$1, pt);
FILE_NAME(tmp, @1);
delete $1;

View File

@ -927,7 +927,7 @@ typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt)
PECallFunction* pform_make_call_function(const struct vlltype&loc,
const pform_name_t&name,
const list<PExpr*>&parms)
const list<named_pexpr_t> &parms)
{
if (gn_system_verilog())
check_potential_imports(loc, name.front().name, true);
@ -939,7 +939,7 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc,
PCallTask* pform_make_call_task(const struct vlltype&loc,
const pform_name_t&name,
const list<PExpr*>&parms)
const list<named_pexpr_t> &parms)
{
if (gn_system_verilog())
check_potential_imports(loc, name.front().name, true);
@ -1732,7 +1732,7 @@ void pform_endgenerate(bool end_conditional)
void pform_make_elab_task(const struct vlltype&li,
perm_string name,
const list<PExpr*>&params)
const list<named_pexpr_t> &params)
{
PCallTask*elab_task = new PCallTask(name, params);
FILE_NAME(elab_task, li);

View File

@ -173,7 +173,7 @@ extern void pform_endmodule(const char*, bool inside_celldefine,
extern void pform_start_class_declaration(const struct vlltype&loc,
class_type_t*type,
data_type_t*base_type,
std::list<PExpr*>*base_exprs,
std::list<named_pexpr_t> *base_args,
bool virtual_class);
extern void pform_class_property(const struct vlltype&loc,
property_qualifier_t pq,
@ -307,7 +307,7 @@ bool pform_error_in_generate(const vlltype&loc, const char *type);
extern void pform_make_elab_task(const struct vlltype&li,
perm_string name,
const std::list<PExpr*>&params);
const std::list<named_pexpr_t> &params);
extern void pform_set_typedef(const struct vlltype&loc, perm_string name,
data_type_t*data_type,
@ -322,10 +322,10 @@ extern void pform_set_type_referenced(const struct vlltype&loc, const char*name)
*/
extern PECallFunction* pform_make_call_function(const struct vlltype&loc,
const pform_name_t&name,
const std::list<PExpr*>&parms);
const std::list<named_pexpr_t> &parms);
extern PCallTask* pform_make_call_task(const struct vlltype&loc,
const pform_name_t&name,
const std::list<PExpr*>&parms);
const std::list<named_pexpr_t> &parms);
extern void pform_make_foreach_declarations(const struct vlltype&loc,
std::list<perm_string>*loop_vars);

View File

@ -46,12 +46,12 @@ void pform_make_analog_behavior(const struct vlltype&loc, ivl_process_type_t pt,
PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,
char*name, char*n1, char*n2)
{
vector<PExpr*> parms (2);
parms[0] = new PEIdent(lex_strings.make(n1));
FILE_NAME(parms[0], loc);
vector<named_pexpr_t> parms (2);
parms[0].parm = new PEIdent(lex_strings.make(n1));
FILE_NAME(parms[0].parm, loc);
parms[1] = new PEIdent(lex_strings.make(n2));
FILE_NAME(parms[1], loc);
parms[1].parm = new PEIdent(lex_strings.make(n2));
FILE_NAME(parms[1].parm, loc);
PECallFunction*res = new PECallFunction(lex_strings.make(name), parms);
FILE_NAME(res, loc);
@ -61,9 +61,9 @@ PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,
PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,
char*name, char*branch_name)
{
vector<PExpr*> parms (1);
parms[0] = new PEIdent(lex_strings.make(branch_name));
FILE_NAME(parms[0], loc);
vector<named_pexpr_t> parms (1);
parms[0].parm = new PEIdent(lex_strings.make(branch_name));
FILE_NAME(parms[0].parm, loc);
PECallFunction*res = new PECallFunction(lex_strings.make(name), parms);
FILE_NAME(res, loc);

View File

@ -345,15 +345,7 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const
if (base_type) out << " extends <type>";
if (! base_args.empty()) {
out << " (";
for (list<PExpr*>::const_iterator cur = base_args.begin()
; cur != base_args.end() ; ++cur) {
const PExpr*curp = *cur;
if (cur != base_args.begin())
out << ", ";
curp->dump(out);
}
out << ")";
out << " (" << base_args << ")";
}
out << " {";

View File

@ -43,7 +43,7 @@ static PClass*pform_cur_class = 0;
void pform_start_class_declaration(const struct vlltype&loc,
class_type_t*type,
data_type_t*base_type,
list<PExpr*>*base_exprs,
list<named_pexpr_t> *base_args,
bool virtual_class)
{
PClass*class_scope = pform_push_class_scope(loc, type->name);
@ -55,13 +55,12 @@ void pform_start_class_declaration(const struct vlltype&loc,
type->base_type.reset(base_type);
type->virtual_class = virtual_class;
ivl_assert(loc, type->base_args.empty());
if (base_exprs) {
for (list<PExpr*>::iterator cur = base_exprs->begin()
; cur != base_exprs->end() ; ++ cur) {
type->base_args.push_back(*cur);
}
delete base_exprs;
if (base_args) {
type->base_args.insert(type->base_args.begin(), base_args->begin(),
base_args->end());
delete base_args;
}
}

View File

@ -377,7 +377,7 @@ struct class_type_t : public data_type_t {
// hierarchy. If there are arguments to the base class, then
// put them in the base_args vector.
std::unique_ptr<data_type_t> base_type;
std::list<PExpr*>base_args;
std::vector<named_pexpr_t> base_args;
bool virtual_class;