diff --git a/Makefile.in b/Makefile.in index 65223fb60..ace61b063 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 \ diff --git a/PExpr.cc b/PExpr.cc index 9ca575264..73679a4b1 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -215,12 +215,12 @@ PEBShift::~PEBShift() { } -PECallFunction::PECallFunction(const pform_name_t&n, const vector &parms) +PECallFunction::PECallFunction(const pform_name_t &n, const vector &parms) : path_(n), parms_(parms), is_overridden_(false) { } -PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const vector &parms) +PECallFunction::PECallFunction(PPackage *pkg, const pform_name_t &n, const vector &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 &parms) +PECallFunction::PECallFunction(PPackage *pkg, const pform_name_t &n, const list &parms) : path_(pkg, n), parms_(parms.begin(), parms.end()), is_overridden_(false) { } -PECallFunction::PECallFunction(perm_string n, const vector&parms) +PECallFunction::PECallFunction(perm_string n, const vector &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 &parms) +PECallFunction::PECallFunction(const pform_name_t &n, const list &parms) : path_(n), parms_(parms.begin(), parms.end()), is_overridden_(false) { } -PECallFunction::PECallFunction(perm_string n, const list&parms) -: package_(0), path_(pn_from_ps(n)), parms_(parms.begin(), parms.end()), is_overridden_(false) +PECallFunction::PECallFunction(perm_string n, const list &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&p, data_type_t *class_type) +PENewClass::PENewClass(const list &p, data_type_t *class_type) : parms_(p.begin(), p.end()), class_type_(class_type) { } diff --git a/PExpr.h b/PExpr.h index 8958ed62a..a70a6f1e7 100644 --- a/PExpr.h +++ b/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&p, + explicit PENewClass (const std::list &p, data_type_t *class_type = nullptr); ~PENewClass(); @@ -592,7 +592,7 @@ class PENewClass : public PExpr { NetExpr*obj, unsigned flags) const; private: - std::vectorparms_; + std::vector 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 &parms); + explicit PECallFunction(const pform_name_t &n, const std::vector &parms); // Call function defined in package. - explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::list &parms); + explicit PECallFunction(PPackage *pkg, const pform_name_t &n, const std::list &parms); // Used to convert a user function called as a task - explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::vector &parms); + explicit PECallFunction(PPackage *pkg, const pform_name_t &n, const std::vector &parms); // Call of system function (name is not hierarchical) - explicit PECallFunction(perm_string n, const std::vector &parms); + explicit PECallFunction(perm_string n, const std::vector &parms); explicit PECallFunction(perm_string n); // std::list versions. Should be removed! - explicit PECallFunction(const pform_name_t&n, const std::list &parms); - explicit PECallFunction(perm_string n, const std::list &parms); + explicit PECallFunction(const pform_name_t &n, const std::list &parms); + explicit PECallFunction(perm_string n, const std::list &parms); ~PECallFunction(); @@ -929,7 +929,7 @@ class PECallFunction : public PExpr { private: pform_scoped_name_t path_; - std::vector parms_; + std::vector parms_; // For system functions. bool is_overridden_; diff --git a/PTask.h b/PTask.h index 4702d0a12..7ea3e924a 100644 --- a/PTask.h +++ b/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&ports, - std::vector&pdefs) const; + std::vector &pdefs, + std::vector &port_names) const; void dump_ports_(std::ostream&out, unsigned ind) const; diff --git a/Statement.cc b/Statement.cc index 41d0bbb22..1dda37940 100644 --- a/Statement.cc +++ b/Statement.cc @@ -166,17 +166,17 @@ PNamedItem::SymbolType PBlock::symbol_type() const return BLOCK; } -PCallTask::PCallTask(const pform_name_t&n, const list&p) +PCallTask::PCallTask(const pform_name_t &n, const list &p) : package_(0), path_(n), parms_(p.begin(), p.end()) { } -PCallTask::PCallTask(PPackage*pkg, const pform_name_t&n, const list&p) +PCallTask::PCallTask(PPackage *pkg, const pform_name_t &n, const list &p) : package_(pkg), path_(n), parms_(p.begin(), p.end()) { } -PCallTask::PCallTask(perm_string n, const list&p) +PCallTask::PCallTask(perm_string n, const list &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&parms) +PChainConstructor::PChainConstructor(const list &parms) : parms_(parms.begin(), parms.end()) { } +PChainConstructor::PChainConstructor(const vector &parms) +: parms_(parms) +{ +} + PChainConstructor::~PChainConstructor() { } diff --git a/Statement.h b/Statement.h index d9b7f0faf..6aa2e9bca 100644 --- a/Statement.h +++ b/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&parms); - explicit PCallTask(const pform_name_t&n, const std::list&parms); - explicit PCallTask(perm_string n, const std::list&parms); + explicit PCallTask(PPackage *pkg, const pform_name_t &n, const std::list &parms); + explicit PCallTask(const pform_name_t &n, const std::list &parms); + explicit PCallTask(perm_string n, const std::list &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 &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 &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 parms_; + std::vector parms_; bool void_cast_ = false; }; @@ -320,17 +322,18 @@ class PCAssign : public Statement { */ class PChainConstructor : public Statement { public: - explicit PChainConstructor(const std::list&parms); + explicit PChainConstructor(const std::list &parms); + explicit PChainConstructor(const std::vector &parms); ~PChainConstructor(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void dump(std::ostream&out, unsigned ind) const; - inline const std::vector& chain_args(void) const + inline const std::vector& chain_args(void) const { return parms_; } private: - std::vector parms_; + std::vector parms_; }; class PCondit : public Statement { diff --git a/elab_expr.cc b/elab_expr.cc index 45773cede..1918908cf 100644 --- a/elab_expr.cc +++ b/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(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(parms_[0]))) { + if ((nparms == 1) && (dynamic_cast(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 (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 &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 (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 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 (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 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 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. diff --git a/elab_sig.cc b/elab_sig.cc index a855d9948..c3a0fc64f 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -688,7 +688,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const vectorports; vectorpdef; - elaborate_sig_ports_(des, scope, ports, pdef); + vector 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 vectorports; vectorpdefs; - elaborate_sig_ports_(des, scope, ports, pdefs); + vector 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&ports, vector&pdefs) const + vector &ports, + vector &pdefs, + vector &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: " diff --git a/elaborate.cc b/elaborate.cc index e858d6e1c..16c482f12 100644 --- a/elaborate.cc +++ b/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 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 &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 &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, vectorargv (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(net->net_type())) { - if (method_name=="itoa") + if (method_name == "itoa") { + static const std::vector 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 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 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 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 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 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 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 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 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(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 (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; diff --git a/map_named_args.cc b/map_named_args.cc new file mode 100644 index 000000000..fc108feef --- /dev/null +++ b/map_named_args.cc @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2023 Lars-Peter Clausen +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "PExpr.h" +#include "ivl_assert.h" +#include "map_named_args.h" +#include "netlist.h" + +#include + +std::vector map_named_args(Design *des, + const std::vector &names, + const std::vector &parms) +{ + std::vector 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 map_named_args(Design *des, NetBaseDef *def, + const std::vector &parms, + unsigned int off) +{ + std::vector 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); +} diff --git a/map_named_args.h b/map_named_args.h new file mode 100644 index 000000000..f0017198f --- /dev/null +++ b/map_named_args.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2023 Lars-Peter Clausen +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef MAP_NAMED_ARGS_H +#define MAP_NAMED_ARGS_H + +#include +#include "pform_types.h" + +class PExpr; +class Design; +class NetBaseDef; + +std::vector map_named_args(Design *des, + const std::vector &names, + const std::vector &parms); + +std::vector map_named_args(Design *des, NetBaseDef *def, + const std::vector &parms, + unsigned int off); + +#endif diff --git a/netmisc.cc b/netmisc.cc index 5954db89f..8f3f89b84 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -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); diff --git a/parse.y b/parse.y index 11e28dcc0..1aa5f0105 100644 --- a/parse.y +++ b/parse.y @@ -172,9 +172,9 @@ template void append(vector&out, const std::vector&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*lst) +static void argument_list_fixup(list *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*lst) */ static PECallFunction*make_call_function(perm_string tn, PExpr*arg) { - std::vector parms(1); - parms[0] = arg; + std::vector 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 parms(2); - parms[0] = arg1; - parms[1] = arg2; + std::vector 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*exprs; + std::list *args; } class_declaration_extends; struct { @@ -690,6 +693,10 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, %type attribute %type attribute_list attribute_instance_list attribute_list_opt +%type argument +%type argument_list +%type argument_list_parens argument_list_parens_opt + %type case_item %type case_items @@ -717,7 +724,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list %type expression_list_with_nuls expression_list_proper -%type argument_list_parens argument_list_parens_opt %type cont_assign cont_assign_list %type 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::listarg_list; + std::list 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 *expr = new std::list; + 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; } + { $$ = new std::list; } + ; 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::vectorempty; - 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."); - listpt; + std::list 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."); } - listpt; + list pt; PCallTask*tmp = new PCallTask(*$1, pt); FILE_NAME(tmp, @1); delete $1; diff --git a/pform.cc b/pform.cc index c2431ac5a..142df2c66 100644 --- a/pform.cc +++ b/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&parms) + const list &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&parms) + const list &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¶ms) + const list ¶ms) { PCallTask*elab_task = new PCallTask(name, params); FILE_NAME(elab_task, li); diff --git a/pform.h b/pform.h index 92d3edfb2..bb3dabfef 100644 --- a/pform.h +++ b/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*base_exprs, + std::list *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¶ms); + const std::list ¶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&parms); + const std::list &parms); extern PCallTask* pform_make_call_task(const struct vlltype&loc, const pform_name_t&name, - const std::list&parms); + const std::list &parms); extern void pform_make_foreach_declarations(const struct vlltype&loc, std::list*loop_vars); diff --git a/pform_analog.cc b/pform_analog.cc index b849f6b82..eb96cce61 100644 --- a/pform_analog.cc +++ b/pform_analog.cc @@ -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 parms (2); - parms[0] = new PEIdent(lex_strings.make(n1)); - FILE_NAME(parms[0], loc); + vector 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 parms (1); - parms[0] = new PEIdent(lex_strings.make(branch_name)); - FILE_NAME(parms[0], loc); + vector 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); diff --git a/pform_dump.cc b/pform_dump.cc index 735d0f923..1a43caaa5 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -345,15 +345,7 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const if (base_type) out << " extends "; if (! base_args.empty()) { - out << " ("; - for (list::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 << " {"; diff --git a/pform_pclass.cc b/pform_pclass.cc index f70fc8621..b438f4cde 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -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*base_exprs, + list *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::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; } } diff --git a/pform_types.h b/pform_types.h index ebdff6f0b..fb7a03f8a 100644 --- a/pform_types.h +++ b/pform_types.h @@ -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 base_type; - std::listbase_args; + std::vector base_args; bool virtual_class;