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:
parent
102d85c4e5
commit
f6a51bc9db
|
|
@ -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 \
|
||||
|
|
|
|||
28
PExpr.cc
28
PExpr.cc
|
|
@ -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
18
PExpr.h
|
|
@ -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_;
|
||||
|
|
|
|||
3
PTask.h
3
PTask.h
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
13
Statement.cc
13
Statement.cc
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
21
Statement.h
21
Statement.h
|
|
@ -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 {
|
||||
|
|
|
|||
188
elab_expr.cc
188
elab_expr.cc
|
|
@ -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.
|
||||
|
|
|
|||
13
elab_sig.cc
13
elab_sig.cc
|
|
@ -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: "
|
||||
|
|
|
|||
241
elaborate.cc
241
elaborate.cc
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
95
parse.y
|
|
@ -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;
|
||||
|
|
|
|||
6
pform.cc
6
pform.cc
|
|
@ -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*>¶ms)
|
||||
const list<named_pexpr_t> ¶ms)
|
||||
{
|
||||
PCallTask*elab_task = new PCallTask(name, params);
|
||||
FILE_NAME(elab_task, li);
|
||||
|
|
|
|||
8
pform.h
8
pform.h
|
|
@ -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*>¶ms);
|
||||
const std::list<named_pexpr_t> ¶ms);
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 << " {";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue