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 7837268b6..73679a4b1 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -99,14 +99,8 @@ PEAssignPattern::PEAssignPattern() } PEAssignPattern::PEAssignPattern(const list&p) -: parms_(p.size()) +: parms_(p.begin(), p.end()) { - size_t idx = 0; - for (list::const_iterator cur = p.begin() - ; cur != p.end() ; ++cur) { - parms_[idx] = *cur; - idx += 1; - } } PEAssignPattern::~PEAssignPattern() @@ -221,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) { } @@ -239,17 +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) -: path_(pkg, n), parms_(parms.size()), is_overridden_(false) +PECallFunction::PECallFunction(PPackage *pkg, const pform_name_t &n, const list &parms) +: path_(pkg, n), parms_(parms.begin(), parms.end()), is_overridden_(false) { - int tmp_idx = 0; - ivl_assert(*this, parms_.size() == parms.size()); - for (list::const_iterator idx = parms.begin() - ; idx != parms.end() ; ++idx) - parms_[tmp_idx++] = *idx; } -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) { } @@ -260,24 +249,14 @@ 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) -: path_(n), parms_(parms.size()), is_overridden_(false) +PECallFunction::PECallFunction(const pform_name_t &n, const list &parms) +: path_(n), parms_(parms.begin(), parms.end()), is_overridden_(false) { - int tmp_idx = 0; - ivl_assert(*this, parms_.size() == parms.size()); - for (list::const_iterator idx = parms.begin() - ; idx != parms.end() ; ++idx) - parms_[tmp_idx++] = *idx; } -PECallFunction::PECallFunction(perm_string n, const list&parms) -: path_(pn_from_ps(n)), parms_(parms.size()), is_overridden_(false) +PECallFunction::PECallFunction(perm_string n, const list &parms) +: path_(pn_from_ps(n)), parms_(parms.begin(), parms.end()), is_overridden_(false) { - int tmp_idx = 0; - ivl_assert(*this, parms_.size() == parms.size()); - for (list::const_iterator idx = parms.begin() - ; idx != parms.end() ; ++idx) - parms_[tmp_idx++] = *idx; } PECallFunction::~PECallFunction() @@ -286,31 +265,25 @@ 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; } PEConcat::PEConcat(const list&p, PExpr*r) -: parms_(p.size()), width_modes_(SIZED, p.size()), repeat_(r) +: parms_(p.begin(), p.end()), width_modes_(SIZED, p.size()), repeat_(r) { - int tmp_idx = 0; - ivl_assert(*this, parms_.size() == p.size()); - for (list::const_iterator idx = p.begin() - ; idx != p.end() ; ++idx) - parms_[tmp_idx++] = *idx; - tested_scope_ = 0; repeat_count_ = 1; } @@ -493,14 +466,9 @@ PENewClass::PENewClass(void) { } -PENewClass::PENewClass(const list&p, data_type_t *class_type) -: parms_(p.size()), class_type_(class_type) +PENewClass::PENewClass(const list &p, data_type_t *class_type) +: parms_(p.begin(), p.end()), class_type_(class_type) { - size_t tmp_idx = 0; - for (list::const_iterator cur = p.begin() - ; cur != p.end() ; ++ cur) { - parms_[tmp_idx++] = *cur; - } } PENewClass::~PENewClass() 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/PGate.cc b/PGate.cc index f7cc7f958..59ad57048 100644 --- a/PGate.cc +++ b/PGate.cc @@ -270,7 +270,7 @@ PGModule::PGModule(perm_string type, perm_string name, list*pins) } PGModule::PGModule(perm_string type, perm_string name, - named*pins, unsigned npins) + named_pexpr_t *pins, unsigned npins) : PGate(name, 0), bound_type_(0), type_(type), overrides_(0), pins_(pins), npins_(npins), parms_(0), nparms_(0) { @@ -292,7 +292,7 @@ void PGModule::set_parameters(list*o) overrides_ = o; } -void PGModule::set_parameters(named*pa, unsigned npa) +void PGModule::set_parameters(named_pexpr_t *pa, unsigned npa) { ivl_assert(*this, parms_ == 0); ivl_assert(*this, overrides_ == 0); diff --git a/PGate.h b/PGate.h index ab514f16b..2bb1c68dc 100644 --- a/PGate.h +++ b/PGate.h @@ -204,7 +204,7 @@ class PGModule : public PGate { // If the binding of ports is by name, this constructor takes // the bindings and stores them for later elaboration. explicit PGModule(perm_string type, perm_string name, - named*pins, unsigned npins); + named_pexpr_t *pins, unsigned npins); // If the module type is known by design, then use this // constructor. @@ -215,7 +215,7 @@ class PGModule : public PGate { // Parameter overrides can come as an ordered list, or a set // of named expressions. void set_parameters(std::list*o); - void set_parameters(named*pa, unsigned npa); + void set_parameters(named_pexpr_t *pa, unsigned npa); std::map attributes; @@ -232,11 +232,11 @@ class PGModule : public PGate { Module*bound_type_; perm_string type_; std::list*overrides_; - named*pins_; + named_pexpr_t *pins_; unsigned npins_; // These members support parameter override by name - named*parms_; + named_pexpr_t *parms_; unsigned nparms_; friend class delayed_elaborate_scope_mod_instances; diff --git a/PSpec.cc b/PSpec.cc index 54825344e..639e3e197 100644 --- a/PSpec.cc +++ b/PSpec.cc @@ -19,10 +19,11 @@ # include "PSpec.h" -PSpecPath::PSpecPath(unsigned src_cnt, unsigned dst_cnt, char polarity, - bool full_flag) +PSpecPath::PSpecPath(const std::list &src_list, + const std::list &dst_list, + char polarity, bool full_flag) : conditional(false), condition(0), edge(0), - src(src_cnt), dst(dst_cnt), + src(src_list.begin(), src_list.end()), dst(dst_list.begin(), dst_list.end()), data_source_expression(0) { full_flag_ = full_flag; diff --git a/PSpec.h b/PSpec.h index 7c34f5bf6..450fbd393 100644 --- a/PSpec.h +++ b/PSpec.h @@ -22,6 +22,7 @@ # include "LineInfo.h" # include "StringHeap.h" # include +# include class PExpr; @@ -56,8 +57,9 @@ class PExpr; class PSpecPath : public LineInfo { public: - PSpecPath(unsigned src_cnt, unsigned dst_cnt, char polarity, - bool full_flag); + PSpecPath(const std::list &src_list, + const std::list &dst_list, + char polarity, bool full_flag); ~PSpecPath(); void elaborate(class Design*des, class NetScope*scope) const; 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 7799eca73..1dda37940 100644 --- a/Statement.cc +++ b/Statement.cc @@ -166,37 +166,19 @@ PNamedItem::SymbolType PBlock::symbol_type() const return BLOCK; } -PCallTask::PCallTask(const pform_name_t&n, const list&p) -: package_(0), path_(n), parms_(p.size()) +PCallTask::PCallTask(const pform_name_t &n, const list &p) +: package_(0), path_(n), parms_(p.begin(), p.end()) { - list::const_iterator cur = p.begin(); - for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { - parms_[idx] = *cur; - ++cur; - } - ivl_assert(*this, cur == p.end()); } -PCallTask::PCallTask(PPackage*pkg, const pform_name_t&n, const list&p) -: package_(pkg), path_(n), parms_(p.size()) +PCallTask::PCallTask(PPackage *pkg, const pform_name_t &n, const list &p) +: package_(pkg), path_(n), parms_(p.begin(), p.end()) { - list::const_iterator cur = p.begin(); - for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { - parms_[idx] = *cur; - ++cur; - } - ivl_assert(*this, cur == p.end()); } -PCallTask::PCallTask(perm_string n, const list&p) -: package_(0), parms_(p.size()) +PCallTask::PCallTask(perm_string n, const list &p) +: package_(0), parms_(p.begin(), p.end()) { - list::const_iterator cur = p.begin(); - for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { - parms_[idx] = *cur; - ++cur; - } - ivl_assert(*this, cur == p.end()); path_.push_back(name_component_t(n)); } @@ -234,15 +216,14 @@ PCAssign::~PCAssign() delete expr_; } -PChainConstructor::PChainConstructor(const list&parms) -: parms_(parms.size()) +PChainConstructor::PChainConstructor(const list &parms) +: parms_(parms.begin(), parms.end()) +{ +} + +PChainConstructor::PChainConstructor(const vector &parms) +: parms_(parms) { - list::const_iterator cur = parms.begin(); - for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { - parms_[idx] = *cur; - ++cur; - } - ivl_assert(*this, cur == parms.end()); } PChainConstructor::~PChainConstructor() @@ -350,12 +331,8 @@ PForce::~PForce() } PForeach::PForeach(perm_string av, const list&ix, Statement*s) -: array_var_(av), index_vars_(ix.size()), statement_(s) +: array_var_(av), index_vars_(ix.begin(), ix.end()), statement_(s) { - size_t idx = 0; - for (list::const_iterator cur = ix.begin() - ; cur != ix.end() ; ++cur) - index_vars_[idx++] = *cur; } PForeach::~PForeach() 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/design_dump.cc b/design_dump.cc index 31f9915c3..7e8f50f7a 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -206,6 +206,18 @@ ostream& operator << (ostream&fd, NetCaseCmp::kind_t that) return fd; } +static std::ostream& operator << (std::ostream &out, const std::vector &exprs) +{ + for (size_t idx = 0; idx < exprs.size(); idx++) { + if (idx != 0) + out << ", "; + if (exprs[idx]) + out << *exprs[idx]; + } + + return out; +} + ostream& ivl_type_s::debug_dump(ostream&o) const { o << typeid(*this).name(); @@ -1650,17 +1662,7 @@ void NetSTask::dump(ostream&o, unsigned ind) const o << setw(ind) << "" << name_; if (! parms_.empty()) { - o << "("; - if (parms_[0]) - parms_[0]->dump(o); - - for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { - o << ", "; - if (parms_[idx]) - parms_[idx]->dump(o); - } - - o << ")"; + o << "(" << parms_ << ")"; } o << ";" << endl; } @@ -1702,15 +1704,7 @@ void NetEAccess::dump(ostream&o) const void NetEArrayPattern::dump(ostream&fd) const { - fd << "'{"; - if (items_.size() >= 1) { - if (items_[0]) fd << *items_[0]; - } - for (size_t idx = 1 ; idx < items_.size() ; idx += 1) { - fd << ", "; - if (items_[idx]) fd << *items_[idx]; - } - fd << "}"; + fd << "'{" << items_ << "}"; } void NetEBinary::dump(ostream&o) const @@ -1814,18 +1808,7 @@ void NetEConcat::dump(ostream&o) const if (repeat_ != 1) o << repeat_; - if (parms_[0]) - o << "{" << *parms_[0]; - else - o << "{"; - - for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { - if (parms_[idx]) - o << ", " << *parms_[idx]; - else - o << ", "; - } - o << "}"; + o << "{" << parms_ << "}"; } void NetEConst::dump(ostream&o) const @@ -1965,15 +1948,7 @@ void NetETernary::dump(ostream&o) const void NetEUFunc::dump(ostream&o) const { - o << scope_path(func_) << "("; - if (! parms_.empty()) { - parms_[0]->dump(o); - for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { - o << ", "; - parms_[idx]->dump(o); - } - } - o << ")"; + o << scope_path(func_) << "(" << parms_ << ")"; } void NetEUnary::dump(ostream&o) const 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/ivtest/ivltests/sv_named_arg_base1.v b/ivtest/ivltests/sv_named_arg_base1.v new file mode 100644 index 000000000..b6448fd08 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base1.v @@ -0,0 +1,25 @@ +// Check that binding task arguments by name is supported. + +module test; + + class B; + integer val; + + function new(integer a, integer b); + val = a + b * 10; + endfunction + endclass + + class C extends B(.b(2), .a(1)); + endclass + + initial begin + C c; + c = new; + if (c.val == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_base2.v b/ivtest/ivltests/sv_named_arg_base2.v new file mode 100644 index 000000000..42a379d8d --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base2.v @@ -0,0 +1,26 @@ +// Check that binding task arguments by name is supported and that a mix of +// positional and named arguments is supported. + +module test; + + class B; + integer val; + + function new(integer a, integer b, integer c); + val = a + b * 10 + c * 100; + endfunction + endclass + + class C extends B(1, .c(3), .b(2)); + endclass + + initial begin + C c; + c = new; + if (c.val == 321) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_base3.v b/ivtest/ivltests/sv_named_arg_base3.v new file mode 100644 index 000000000..e1954044c --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base3.v @@ -0,0 +1,27 @@ +// Check that binding task arguments by name is supported and that an empty +// value can be bound to the name, in which case the default argument value +// should be used. + +module test; + + class B; + integer val; + + function new(integer a, integer b = 2); + val = a + b * 10; + endfunction + endclass + + class C extends B(.a(1), .b()); + endclass + + initial begin + C c; + c = new; + if (c.val == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_base_fail1.v b/ivtest/ivltests/sv_named_arg_base_fail1.v new file mode 100644 index 000000000..378e0c067 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base_fail1.v @@ -0,0 +1,21 @@ +// Check that an error is reported when trying to bind an argument by nae that +// does not exist + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B(.b(2), .c(1)); // This should fail. `c` is not an arugment + // of the base constructor. + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_base_fail2.v b/ivtest/ivltests/sv_named_arg_base_fail2.v new file mode 100644 index 000000000..90180ab19 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base_fail2.v @@ -0,0 +1,21 @@ +// Check that an error is reported when trying to bind the same argument by name +// multiple times. + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B(.a(1), .a(2)); // This should fail. `a` is provided twice + // as a named argument. + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_base_fail3.v b/ivtest/ivltests/sv_named_arg_base_fail3.v new file mode 100644 index 000000000..10728a5fd --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base_fail3.v @@ -0,0 +1,21 @@ +// Check that an error is reported when trying to bind an argument by name that +// is also provided as a positional argument. + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B(1, .a(2)); // This should fail. `a` is provided both as a + // positional and named argument. + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_base_fail4.v b/ivtest/ivltests/sv_named_arg_base_fail4.v new file mode 100644 index 000000000..921fbd198 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base_fail4.v @@ -0,0 +1,21 @@ +// Check that an error is reported trying to provide a positional argument to a +// function after a named argument. + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B(.a(2), 1); // This should fail. Positional arguments must + // precede named arguments. + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_base_fail5.v b/ivtest/ivltests/sv_named_arg_base_fail5.v new file mode 100644 index 000000000..406143563 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_base_fail5.v @@ -0,0 +1,20 @@ +// Check that an error is reported when binding an empty value to an argument by +// name and the argument does not have a default value. + +module test; + + class B; + function new(integer a); + $display("FAILED"); + endfunction + endclass + + class C extends B(.a()); // This should fail. `a` has no default value. + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained1.v b/ivtest/ivltests/sv_named_arg_chained1.v new file mode 100644 index 000000000..d28a70969 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained1.v @@ -0,0 +1,28 @@ +// Check that binding task arguments by name is supported. + +module test; + + class B; + integer val; + + function new(integer a, integer b); + val = a + b * 10; + endfunction + endclass + + class C extends B; + function new; + super.new(.b(2), .a(1)); + endfunction + endclass + + initial begin + C c; + c = new; + if (c.val == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained2.v b/ivtest/ivltests/sv_named_arg_chained2.v new file mode 100644 index 000000000..2816a817d --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained2.v @@ -0,0 +1,29 @@ +// Check that binding task arguments by name is supported and that a mix of +// positional and named arguments is supported. + +module test; + + class B; + integer val; + + function new(integer a, integer b, integer c); + val = a + b * 10 + c * 100; + endfunction + endclass + + class C extends B; + function new; + super.new(1, .c(3), .b(2)); + endfunction + endclass + + initial begin + C c; + c = new; + if (c.val == 321) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained3.v b/ivtest/ivltests/sv_named_arg_chained3.v new file mode 100644 index 000000000..8af5a15c9 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained3.v @@ -0,0 +1,30 @@ +// Check that binding task arguments by name is supported and that an empty +// value can be bound to the name, in which case the default argument value +// should be used. + +module test; + + class B; + integer val; + + function new(integer a, integer b = 2); + val = a + b * 10; + endfunction + endclass + + class C extends B; + function new; + super.new(.a(1), .b()); + endfunction + endclass + + initial begin + C c; + c = new; + if (c.val == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained_fail1.v b/ivtest/ivltests/sv_named_arg_chained_fail1.v new file mode 100644 index 000000000..915664f60 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained_fail1.v @@ -0,0 +1,24 @@ +// Check that an error is reported when trying to bind an argument by nae that +// does not exist + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B; + function new; + super.new(.b(2), .c(1)); // This should fail. `c` is not an arugment of + // the base constructor. + endfunction + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained_fail2.v b/ivtest/ivltests/sv_named_arg_chained_fail2.v new file mode 100644 index 000000000..7002e7595 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained_fail2.v @@ -0,0 +1,24 @@ +// Check that an error is reported when trying to bind the same argument by name +// multiple times. + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B; + function new; + super.new(.a(1), .a(2)); // This should fail. `a` is provided twice as a + // named argument. + endfunction + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained_fail3.v b/ivtest/ivltests/sv_named_arg_chained_fail3.v new file mode 100644 index 000000000..7affb0f9f --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained_fail3.v @@ -0,0 +1,24 @@ +// Check that an error is reported when trying to bind an argument by name that +// is also provided as a positional argument. + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B; + function new; + super.new(1, .a(2)); // This should fail. `a` is provided both as a + // positional and named argument. + endfunction + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained_fail4.v b/ivtest/ivltests/sv_named_arg_chained_fail4.v new file mode 100644 index 000000000..4647ed6f8 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained_fail4.v @@ -0,0 +1,24 @@ +// Check that an error is reported trying to provide a positional argument to a +// function after a named argument. + +module test; + + class B; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + class C extends B; + function new; + super.new(.a(2), 1); // This should fail. Positional arguments must + // precede named arguments. + endfunction + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_chained_fail5.v b/ivtest/ivltests/sv_named_arg_chained_fail5.v new file mode 100644 index 000000000..abf44565e --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_chained_fail5.v @@ -0,0 +1,23 @@ +// Check that an error is reported when binding an empty value to an argument by +// name and the argument does not have a default value. + +module test; + + class B; + function new(integer a); + $display("FAILED"); + endfunction + endclass + + class C extends B; + function new; + super.new(.a()); // This should fail. `a` has no default value. + endfunction + endclass + + initial begin + C c; + c = new; + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func1.v b/ivtest/ivltests/sv_named_arg_func1.v new file mode 100644 index 000000000..c38b26adb --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func1.v @@ -0,0 +1,19 @@ +// Check that binding task arguments by name is supported. + +module test; + + function integer f(integer a, integer b); + return a + b * 10; + endfunction + + initial begin + integer x; + x = f(.b(2), .a(1)); + if (x == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func2.v b/ivtest/ivltests/sv_named_arg_func2.v new file mode 100644 index 000000000..49e211d79 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func2.v @@ -0,0 +1,20 @@ +// Check that binding task arguments by name is supported and that a mix of +// positional and named arguments is supported. + +module test; + + function integer f(integer a, integer b, integer c); + return a + b * 10 + c * 100; + endfunction + + initial begin + integer x; + x = f(1, .c(3), .b(2)); + if (x == 321) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func3.v b/ivtest/ivltests/sv_named_arg_func3.v new file mode 100644 index 000000000..9592f694e --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func3.v @@ -0,0 +1,21 @@ +// Check that binding task arguments by name is supported and that an empty +// value can be bound to the name, in which case the default argument value +// should be used. + +module test; + + function integer f(integer a, integer b = 2); + return a + b * 10; + endfunction + + initial begin + integer x; + x = f(.a(1), .b()); + if (x == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func_fail1.v b/ivtest/ivltests/sv_named_arg_func_fail1.v new file mode 100644 index 000000000..21d3b0494 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func_fail1.v @@ -0,0 +1,15 @@ +// Check that an error is reported when trying to bind an argument by nae that +// does not exist + +module test; + + function f(integer a, integer b); + $display("FAILED"); + endfunction + + initial begin + integer x; + x = f(.b(2), .c(1)); // This should fail. `c` is not an arugment of `f`. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func_fail2.v b/ivtest/ivltests/sv_named_arg_func_fail2.v new file mode 100644 index 000000000..662f37a14 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func_fail2.v @@ -0,0 +1,16 @@ +// Check that an error is reported when trying to bind the same argument by name +// multiple times. + +module test; + + function f(integer a, integer b); + $display("FAILED"); + endfunction + + initial begin + integer x; + x = f(.a(1), .a(2)); // This should fail. `a` is provided twice as a named + // argument. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func_fail3.v b/ivtest/ivltests/sv_named_arg_func_fail3.v new file mode 100644 index 000000000..6c8cbb1e7 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func_fail3.v @@ -0,0 +1,16 @@ +// Check that an error is reported when trying to bind an argument by name that +// is also provided as a positional argument. + +module test; + + function f(integer a, integer b); + $display("FAILED"); + endfunction + + initial begin + integer x; + x = f(1, .a(2)); // This should fail. `a` is provided both as a positional + // and named argument. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func_fail4.v b/ivtest/ivltests/sv_named_arg_func_fail4.v new file mode 100644 index 000000000..e8f8ca070 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func_fail4.v @@ -0,0 +1,16 @@ +// Check that an error is reported trying to provide a positional argument to a +// function after a named argument. + +module test; + + function f(integer a, integer b); + $display("FAILED"); + endfunction + + initial begin + integer x; + x = f(.a(2), 1); // This should fail. Positional arguments must precede + // named arguments. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_func_fail5.v b/ivtest/ivltests/sv_named_arg_func_fail5.v new file mode 100644 index 000000000..ad503d56e --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_func_fail5.v @@ -0,0 +1,15 @@ +// Check that an error is reported when binding an empty value to an argument by +// name and the argument does not have a default value. + +module test; + + function f(integer a); + $display("FAILED"); + endfunction + + initial begin + integer x; + x = f(.a()); // This should fail. `a` has no default value. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new1.v b/ivtest/ivltests/sv_named_arg_new1.v new file mode 100644 index 000000000..c316add56 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new1.v @@ -0,0 +1,22 @@ +// Check that binding task arguments by name is supported. + +module test; + + class C; + integer val; + + function new(integer a, integer b); + val = a + b * 10; + endfunction + endclass + + initial begin + C c; + c = new(.b(2), .a(1)); + if (c.val == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new2.v b/ivtest/ivltests/sv_named_arg_new2.v new file mode 100644 index 000000000..64c1fd8f8 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new2.v @@ -0,0 +1,23 @@ +// Check that binding task arguments by name is supported and that a mix of +// positional and named arguments is supported. + +module test; + + class C; + integer val; + + function new(integer a, integer b, integer c); + val = a + b * 10 + c * 100; + endfunction + endclass + + initial begin + C c; + c = new(1, .c(3), .b(2)); + if (c.val == 321) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new3.v b/ivtest/ivltests/sv_named_arg_new3.v new file mode 100644 index 000000000..80d09bdb0 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new3.v @@ -0,0 +1,24 @@ +// Check that binding task arguments by name is supported and that an empty +// value can be bound to the name, in which case the default argument value +// should be used. + +module test; + + class C; + integer val; + + function new(integer a, integer b = 2); + val = a + b * 10; + endfunction + endclass + + initial begin + C c; + c = new(.a(1), .b()); + if (c.val == 21) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new_fail1.v b/ivtest/ivltests/sv_named_arg_new_fail1.v new file mode 100644 index 000000000..e9d9403ce --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new_fail1.v @@ -0,0 +1,18 @@ +// Check that an error is reported when trying to bind an argument by nae that +// does not exist + +module test; + + class C; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + initial begin + C c; + c = new(.b(2), .c(1)); // This should fail. `c` is not an arugment of the + // constructor. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new_fail2.v b/ivtest/ivltests/sv_named_arg_new_fail2.v new file mode 100644 index 000000000..8b4e3468b --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new_fail2.v @@ -0,0 +1,18 @@ +// Check that an error is reported when trying to bind the same argument by name +// multiple times. + +module test; + + class C; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + initial begin + C c; + c = new(.a(1), .a(2)); // This should fail. `a` is provided twice as a named + // argument. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new_fail3.v b/ivtest/ivltests/sv_named_arg_new_fail3.v new file mode 100644 index 000000000..de94c4ff0 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new_fail3.v @@ -0,0 +1,18 @@ +// Check that an error is reported when trying to bind an argument by name that +// is also provided as a positional argument. + +module test; + + class C; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + initial begin + C c; + c = new(1, .a(2)); // This should fail. `a` is provided both as a positional + // and named argument. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new_fail4.v b/ivtest/ivltests/sv_named_arg_new_fail4.v new file mode 100644 index 000000000..4803cb5c4 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new_fail4.v @@ -0,0 +1,18 @@ +// Check that an error is reported trying to provide a positional argument to a +// function after a named argument. + +module test; + + class C; + function new(integer a, integer b); + $display("FAILED"); + endfunction + endclass + + initial begin + C c; + c = new(.a(2), 1); // This should fail. Positional arguments must precede + // named arguments. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_new_fail5.v b/ivtest/ivltests/sv_named_arg_new_fail5.v new file mode 100644 index 000000000..fc5bfcdfd --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_new_fail5.v @@ -0,0 +1,17 @@ +// Check that an error is reported when binding an empty value to an argument by +// name and the argument does not have a default value. + +module test; + + class C; + function new(integer a); + $display("FAILED"); + endfunction + endclass + + initial begin + C c; + c = new(.a()); // This should fail. `a` has no default value. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task1.v b/ivtest/ivltests/sv_named_arg_task1.v new file mode 100644 index 000000000..525c334b3 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task1.v @@ -0,0 +1,17 @@ +// Check that binding task arguments by name is supported. + +module test; + + task t(integer a, integer b); + if (a == 1 && b == 2) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + endtask + + initial begin + t(.b(2), .a(1)); + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task2.v b/ivtest/ivltests/sv_named_arg_task2.v new file mode 100644 index 000000000..b0c47d95e --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task2.v @@ -0,0 +1,18 @@ +// Check that binding task arguments by name is supported and that a mix of +// positional and named arguments is supported. + +module test; + + task t(integer a, integer b, integer c); + if (a == 1 && b == 2 && c == 3) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + endtask + + initial begin + t(1, .c(3), .b(2)); + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task3.v b/ivtest/ivltests/sv_named_arg_task3.v new file mode 100644 index 000000000..1018b7e2e --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task3.v @@ -0,0 +1,19 @@ +// Check that binding task arguments by name is supported and that an empty +// value can be bound to the name, in which case the default argument value +// should be used. + +module test; + + task t(integer a, integer b = 2); + if (a == 1 && b == 2) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + endtask + + initial begin + t(.a(1), .b()); + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task_fail1.v b/ivtest/ivltests/sv_named_arg_task_fail1.v new file mode 100644 index 000000000..2ede7b366 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task_fail1.v @@ -0,0 +1,14 @@ +// Check that an error is reported when trying to bind an argument by nae that +// does not exist + +module test; + + task t(integer a, integer b); + $display("FAILED"); + endtask + + initial begin + t(.b(2), .c(1)); + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task_fail2.v b/ivtest/ivltests/sv_named_arg_task_fail2.v new file mode 100644 index 000000000..1c3cbcca7 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task_fail2.v @@ -0,0 +1,14 @@ +// Check that an error is reported when trying to bind the same argument by name +// multiple times. + +module test; + + task t(integer a, integer b); + $display("FAILED"); + endtask + + initial begin + t(.a(1), .a(2)); + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task_fail3.v b/ivtest/ivltests/sv_named_arg_task_fail3.v new file mode 100644 index 000000000..dccb9c2ed --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task_fail3.v @@ -0,0 +1,14 @@ +// Check that an error is reported when trying to bind an argument by name that +// is also provided as a positional argument. + +module test; + + task t(integer a, integer b); + $display("FAILED"); + endtask + + initial begin + t(1, .a(2)); + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task_fail4.v b/ivtest/ivltests/sv_named_arg_task_fail4.v new file mode 100644 index 000000000..0e4aa101e --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task_fail4.v @@ -0,0 +1,15 @@ +// Check that an error is reported trying to provide a positional argument to a +// task after a named argument. + +module test; + + task t(integer a, integer b); + $display("FAILED"); + endtask + + initial begin + t(.a(2), 1); // This should fail. Positional arguments must precede + // named arguments. + end + +endmodule diff --git a/ivtest/ivltests/sv_named_arg_task_fail5.v b/ivtest/ivltests/sv_named_arg_task_fail5.v new file mode 100644 index 000000000..f549e1ed3 --- /dev/null +++ b/ivtest/ivltests/sv_named_arg_task_fail5.v @@ -0,0 +1,14 @@ +// Check that an error is reported when binding an empty value to an argument by +// name and the argument does not have a default value. + +module test; + + task t(integer a); + $display("FAILED"); + endtask + + initial begin + t(.a()); // This should fail. `a` has no default value. + end + +endmodule diff --git a/ivtest/vvp_tests/sv_named_arg_base1.json b/ivtest/vvp_tests/sv_named_arg_base1.json new file mode 100644 index 000000000..ef23d9462 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_base1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_base2.json b/ivtest/vvp_tests/sv_named_arg_base2.json new file mode 100644 index 000000000..3707d8096 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_base2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_base3.json b/ivtest/vvp_tests/sv_named_arg_base3.json new file mode 100644 index 000000000..34edbb3c8 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_base3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_base_fail1.json b/ivtest/vvp_tests/sv_named_arg_base_fail1.json new file mode 100644 index 000000000..c117c291e --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_base_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_base_fail2.json b/ivtest/vvp_tests/sv_named_arg_base_fail2.json new file mode 100644 index 000000000..e0e2ab1c7 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_base_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_base_fail3.json b/ivtest/vvp_tests/sv_named_arg_base_fail3.json new file mode 100644 index 000000000..ed2dc83cc --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_base_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_base_fail4.json b/ivtest/vvp_tests/sv_named_arg_base_fail4.json new file mode 100644 index 000000000..203a02860 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_base_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_base_fail5.json b/ivtest/vvp_tests/sv_named_arg_base_fail5.json new file mode 100644 index 000000000..04f7ce8a2 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_base_fail5.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_base_fail5.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained1.json b/ivtest/vvp_tests/sv_named_arg_chained1.json new file mode 100644 index 000000000..1187d39c6 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_chained1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained2.json b/ivtest/vvp_tests/sv_named_arg_chained2.json new file mode 100644 index 000000000..909ad3763 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_chained2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained3.json b/ivtest/vvp_tests/sv_named_arg_chained3.json new file mode 100644 index 000000000..b0270b485 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_chained3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained_fail1.json b/ivtest/vvp_tests/sv_named_arg_chained_fail1.json new file mode 100644 index 000000000..09ffa9ea7 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_chained_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained_fail2.json b/ivtest/vvp_tests/sv_named_arg_chained_fail2.json new file mode 100644 index 000000000..7fd51bd3b --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_chained_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained_fail3.json b/ivtest/vvp_tests/sv_named_arg_chained_fail3.json new file mode 100644 index 000000000..0a0d5ebbd --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_chained_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained_fail4.json b/ivtest/vvp_tests/sv_named_arg_chained_fail4.json new file mode 100644 index 000000000..7ae7f84c6 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_chained_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_chained_fail5.json b/ivtest/vvp_tests/sv_named_arg_chained_fail5.json new file mode 100644 index 000000000..1dd296eec --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_chained_fail5.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_chained_fail5.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func1.json b/ivtest/vvp_tests/sv_named_arg_func1.json new file mode 100644 index 000000000..0fe90f86a --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_func1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func2.json b/ivtest/vvp_tests/sv_named_arg_func2.json new file mode 100644 index 000000000..4d7363514 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_func2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func3.json b/ivtest/vvp_tests/sv_named_arg_func3.json new file mode 100644 index 000000000..f8037c5ce --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_func3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func_fail1.json b/ivtest/vvp_tests/sv_named_arg_func_fail1.json new file mode 100644 index 000000000..70da8a2bc --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_func_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func_fail2.json b/ivtest/vvp_tests/sv_named_arg_func_fail2.json new file mode 100644 index 000000000..611797c72 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_func_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func_fail3.json b/ivtest/vvp_tests/sv_named_arg_func_fail3.json new file mode 100644 index 000000000..9f4e80a3b --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_func_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func_fail4.json b/ivtest/vvp_tests/sv_named_arg_func_fail4.json new file mode 100644 index 000000000..c052b6262 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_func_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_func_fail5.json b/ivtest/vvp_tests/sv_named_arg_func_fail5.json new file mode 100644 index 000000000..2df8abb47 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_func_fail5.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_func_fail5.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new1.json b/ivtest/vvp_tests/sv_named_arg_new1.json new file mode 100644 index 000000000..6695b02a4 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_new1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new2.json b/ivtest/vvp_tests/sv_named_arg_new2.json new file mode 100644 index 000000000..6f4ec4d0b --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_new2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new3.json b/ivtest/vvp_tests/sv_named_arg_new3.json new file mode 100644 index 000000000..4c2009f8c --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_new3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new_fail1.json b/ivtest/vvp_tests/sv_named_arg_new_fail1.json new file mode 100644 index 000000000..efe60694e --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_new_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new_fail2.json b/ivtest/vvp_tests/sv_named_arg_new_fail2.json new file mode 100644 index 000000000..e5e1d890a --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_new_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new_fail3.json b/ivtest/vvp_tests/sv_named_arg_new_fail3.json new file mode 100644 index 000000000..a8cc1f8f0 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_new_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new_fail4.json b/ivtest/vvp_tests/sv_named_arg_new_fail4.json new file mode 100644 index 000000000..58128d0ae --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_new_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_new_fail5.json b/ivtest/vvp_tests/sv_named_arg_new_fail5.json new file mode 100644 index 000000000..5339eee9a --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_new_fail5.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_new_fail5.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task1.json b/ivtest/vvp_tests/sv_named_arg_task1.json new file mode 100644 index 000000000..10c7cc90c --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_task1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task2.json b/ivtest/vvp_tests/sv_named_arg_task2.json new file mode 100644 index 000000000..5ba8429ff --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_task2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task3.json b/ivtest/vvp_tests/sv_named_arg_task3.json new file mode 100644 index 000000000..1ffe13fab --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_named_arg_task3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task_fail1.json b/ivtest/vvp_tests/sv_named_arg_task_fail1.json new file mode 100644 index 000000000..cbddc6ade --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_task_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task_fail2.json b/ivtest/vvp_tests/sv_named_arg_task_fail2.json new file mode 100644 index 000000000..1b438073f --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_task_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task_fail3.json b/ivtest/vvp_tests/sv_named_arg_task_fail3.json new file mode 100644 index 000000000..cdf212dd4 --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_task_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task_fail4.json b/ivtest/vvp_tests/sv_named_arg_task_fail4.json new file mode 100644 index 000000000..cff8adbbe --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_task_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_named_arg_task_fail5.json b/ivtest/vvp_tests/sv_named_arg_task_fail5.json new file mode 100644 index 000000000..663c7d86c --- /dev/null +++ b/ivtest/vvp_tests/sv_named_arg_task_fail5.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_named_arg_task_fail5.v", + "iverilog-args" : [ "-g2005-sv" ] +} 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/named.h b/named.h index 1086637c5..fd85d9433 100644 --- a/named.h +++ b/named.h @@ -20,13 +20,14 @@ */ # include "StringHeap.h" +# include "libmisc/LineInfo.h" /* * There are lots of places where names are attached to objects. This * simple template expresses the lot. */ -template struct named { +template struct named : public LineInfo { perm_string name; T parm; }; diff --git a/netlist.cc b/netlist.cc index f1f825d16..561701b32 100644 --- a/netlist.cc +++ b/netlist.cc @@ -579,16 +579,10 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, : NetObj(s, n, calculate_count(unpacked)), type_(t), port_type_(NOT_A_PORT), local_flag_(false), net_type_(use_net_type), - discipline_(0), unpacked_dims_(unpacked.size()), + discipline_(0), unpacked_dims_(unpacked.begin(), unpacked.end()), eref_count_(0), lref_count_(0) { calculate_slice_widths_from_packed_dims_(); - size_t idx = 0; - for (list::const_iterator cur = unpacked.begin() - ; cur != unpacked.end() ; ++cur, idx += 1) { - unpacked_dims_[idx] = *cur; - } - ivl_assert(*this, idx == unpacked_dims_.size()); ivl_assert(*this, s); if (pin_count() == 0) { 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 24c3a27a0..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,22 +184,28 @@ 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; } -static std::list* make_named_numbers(perm_string name, long first, long last, PExpr*val =0) +static std::list* make_named_numbers(const struct vlltype &loc, + perm_string name, + long first, long last, + PExpr *val = nullptr) { std::list*lst = new std::list; named_pexpr_t tmp; @@ -210,6 +216,7 @@ static std::list* make_named_numbers(perm_string name, long first buf << name.str() << idx << ends; tmp.name = lex_strings.make(buf.str()); tmp.parm = val; + FILE_NAME(&tmp, loc); val = 0; lst->push_back(tmp); } @@ -220,6 +227,7 @@ static std::list* make_named_numbers(perm_string name, long first buf << name.str() << idx << ends; tmp.name = lex_strings.make(buf.str()); tmp.parm = val; + FILE_NAME(&tmp, loc); val = 0; lst->push_back(tmp); } @@ -227,12 +235,15 @@ static std::list* make_named_numbers(perm_string name, long first return lst; } -static std::list* make_named_number(perm_string name, PExpr*val =0) +static std::list* make_named_number(const struct vlltype &loc, + perm_string name, + PExpr *val = nullptr) { std::list*lst = new std::list; named_pexpr_t tmp; tmp.name = name; tmp.parm = val; + FILE_NAME(&tmp, loc); lst->push_back(tmp); return lst; } @@ -455,9 +466,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, std::list*let_port_lst; PLet::let_port_t*let_port_itm; - named_number_t* named_number; - std::list* named_numbers; - named_pexpr_t*named_pexpr; std::list*named_pexprs; struct parmvalue_t*parmvalue; @@ -505,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 { @@ -678,13 +686,17 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, %type tf_port_declaration tf_port_item tf_port_item_list %type tf_port_list tf_port_list_opt tf_port_list_parens_opt -%type modport_simple_port port_name parameter_value_byname +%type named_expression named_expression_opt port_name %type port_name_list parameter_value_byname_list %type port_conn_expression_list_with_nuls %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 @@ -712,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 @@ -884,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. @@ -927,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 @@ -1978,7 +1990,7 @@ modport_item modport_ports_list : modport_ports_declaration | modport_ports_list ',' modport_ports_declaration - | modport_ports_list ',' modport_simple_port + | modport_ports_list ',' named_expression { if (last_modport_port.type == MP_SIMPLE) { pform_add_modport_port(@3, last_modport_port.direction, $3->name, $3->parm); @@ -2012,7 +2024,7 @@ modport_ports_declaration delete[] $3; delete $1; } - | attribute_list_opt port_direction modport_simple_port + | attribute_list_opt port_direction named_expression { last_modport_port.type = MP_SIMPLE; last_modport_port.direction = $2; pform_add_modport_port(@3, $2, $3->name, $3->parm); @@ -2041,16 +2053,6 @@ modport_ports_declaration } ; -modport_simple_port - : '.' IDENTIFIER '(' expression ')' - { named_pexpr_t*tmp = new named_pexpr_t; - tmp->name = lex_strings.make($2); - tmp->parm = $4; - delete[]$2; - $$ = tmp; - } - ; - modport_tf_port : K_task IDENTIFIER tf_port_list_parens_opt | K_function data_type_or_implicit_or_void IDENTIFIER tf_port_list_parens_opt @@ -2256,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); @@ -2713,6 +2715,7 @@ attribute_list attribute : IDENTIFIER initializer_opt { named_pexpr_t*tmp = new named_pexpr_t; + FILE_NAME(tmp, @$); tmp->name = lex_strings.make($1); tmp->parm = $2; delete[]$1; @@ -2907,19 +2910,19 @@ enum_name : IDENTIFIER initializer_opt { perm_string name = lex_strings.make($1); delete[]$1; - $$ = make_named_number(name, $2); + $$ = make_named_number(@$, name, $2); } | IDENTIFIER '[' pos_neg_number ']' initializer_opt { perm_string name = lex_strings.make($1); long count = check_enum_seq_value(@1, $3, false); - $$ = make_named_numbers(name, 0, count-1, $5); + $$ = make_named_numbers(@$, name, 0, count-1, $5); delete[]$1; delete $3; } | IDENTIFIER '[' pos_neg_number ':' pos_neg_number ']' initializer_opt { perm_string name = lex_strings.make($1); - $$ = make_named_numbers(name, check_enum_seq_value(@1, $3, true), - check_enum_seq_value(@1, $5, true), $7); + $$ = make_named_numbers(@$, name, check_enum_seq_value(@1, $3, true), + check_enum_seq_value(@1, $5, true), $7); delete[]$1; delete $3; delete $5; @@ -3718,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; } ; @@ -3735,7 +3771,8 @@ argument_list_parens_opt : argument_list_parens { $$ = $1; } | - { $$ = new std::list; } + { $$ = new std::list; } + ; expression_list_proper : expression_list_proper ',' expression @@ -3878,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 @@ -3893,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); @@ -5553,16 +5582,21 @@ parameter_value_opt { $$ = 0; } ; -parameter_value_byname +named_expression : '.' IDENTIFIER '(' expression ')' { named_pexpr_t*tmp = new named_pexpr_t; + FILE_NAME(tmp, @$); tmp->name = lex_strings.make($2); tmp->parm = $4; delete[]$2; $$ = tmp; } + +named_expression_opt + : named_expression | '.' IDENTIFIER '(' ')' { named_pexpr_t*tmp = new named_pexpr_t; + FILE_NAME(tmp, @$); tmp->name = lex_strings.make($2); tmp->parm = 0; delete[]$2; @@ -5571,13 +5605,13 @@ parameter_value_byname ; parameter_value_byname_list - : parameter_value_byname + : named_expression_opt { std::list*tmp = new std::list; tmp->push_back(*$1); delete $1; $$ = tmp; } - | parameter_value_byname_list ',' parameter_value_byname + | parameter_value_byname_list ',' named_expression_opt { std::list*tmp = $1; tmp->push_back(*$3); delete $3; @@ -5646,25 +5680,14 @@ port_opt looking for the ports of a module declaration. */ port_name - : attribute_list_opt '.' IDENTIFIER '(' expression ')' - { named_pexpr_t*tmp = new named_pexpr_t; - tmp->name = lex_strings.make($3); - tmp->parm = $5; - delete[]$3; - delete $1; - $$ = tmp; + : attribute_list_opt named_expression_opt + { delete $1; + $$ = $2; } | attribute_list_opt '.' IDENTIFIER '(' error ')' { yyerror(@3, "error: Invalid port connection expression."); named_pexpr_t*tmp = new named_pexpr_t; - tmp->name = lex_strings.make($3); - tmp->parm = 0; - delete[]$3; - delete $1; - $$ = tmp; - } - | attribute_list_opt '.' IDENTIFIER '(' ')' - { named_pexpr_t*tmp = new named_pexpr_t; + FILE_NAME(tmp, @$); tmp->name = lex_strings.make($3); tmp->parm = 0; delete[]$3; @@ -5674,6 +5697,7 @@ port_name | attribute_list_opt '.' IDENTIFIER { pform_requires_sv(@3, "Implicit named port connections"); named_pexpr_t*tmp = new named_pexpr_t; + FILE_NAME(tmp, @$); tmp->name = lex_strings.make($3); tmp->parm = new PEIdent(lex_strings.make($3), true); FILE_NAME(tmp->parm, @3); @@ -5683,6 +5707,7 @@ port_name } | K_DOTSTAR { named_pexpr_t*tmp = new named_pexpr_t; + FILE_NAME(tmp, @$); tmp->name = lex_strings.make("*"); tmp->parm = 0; $$ = tmp; @@ -6559,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; @@ -6936,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 61da7ad75..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); @@ -2278,13 +2278,10 @@ static void pform_make_modgate(perm_string type, if (overrides && overrides->by_name) { unsigned cnt = overrides->by_name->size(); - named*byname = new named[cnt]; + named_pexpr_t *byname = new named_pexpr_t[cnt]; - list::iterator by_name_cur = overrides->by_name->begin(); - for (unsigned idx = 0 ; idx < cnt ; idx += 1, ++ by_name_cur) { - byname[idx].name = by_name_cur->name; - byname[idx].parm = by_name_cur->parm; - } + std::copy(overrides->by_name->begin(), overrides->by_name->end(), + byname); cur->set_parameters(byname, cnt); @@ -2311,13 +2308,11 @@ static void pform_make_modgate(perm_string type, std::list*attr) { unsigned npins = bind->size(); - named*pins = new named[npins]; - list::iterator bind_cur = bind->begin(); - for (unsigned idx = 0 ; idx < npins ; idx += 1, ++bind_cur) { - pins[idx].name = bind_cur->name; - pins[idx].parm = bind_cur->parm; - pform_declare_implicit_nets(bind_cur->parm); - } + named_pexpr_t *pins = new named_pexpr_t[npins]; + for (const auto &bind_cur : *bind) + pform_declare_implicit_nets(bind_cur.parm); + + std::copy(bind->begin(), bind->end(), pins); PGModule*cur = new PGModule(type, name, pins, npins); cur->set_line(li); @@ -2325,13 +2320,10 @@ static void pform_make_modgate(perm_string type, if (overrides && overrides->by_name) { unsigned cnt = overrides->by_name->size(); - named*byname = new named[cnt]; + named_pexpr_t *byname = new named_pexpr_t[cnt]; - list::iterator by_name_cur = overrides->by_name->begin(); - for (unsigned idx = 0 ; idx < cnt ; idx += 1, ++by_name_cur) { - byname[idx].name = by_name_cur->name; - byname[idx].parm = by_name_cur->parm; - } + std::copy(overrides->by_name->begin(), overrides->by_name->end(), + byname); cur->set_parameters(byname, cnt); @@ -3053,23 +3045,10 @@ extern PSpecPath* pform_make_specify_path(const struct vlltype&li, list*src, char pol, bool full_flag, list*dst) { - PSpecPath*path = new PSpecPath(src->size(), dst->size(), pol, full_flag); + PSpecPath*path = new PSpecPath(*src, *dst, pol, full_flag); FILE_NAME(path, li); - unsigned idx; - list::const_iterator cur; - - idx = 0; - for (idx = 0, cur = src->begin() ; cur != src->end() ; ++ idx, ++ cur) { - path->src[idx] = *cur; - } - ivl_assert(li, idx == path->src.size()); delete src; - - for (idx = 0, cur = dst->begin() ; cur != dst->end() ; ++ idx, ++ cur) { - path->dst[idx] = *cur; - } - ivl_assert(li, idx == path->dst.size()); delete dst; return path; 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 4f5ba286e..1a43caaa5 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -177,6 +177,35 @@ std::ostream& operator << (std::ostream&out, ivl_dis_domain_t dom) return out; } +static std::ostream& operator << (std::ostream &out, const std::vector &exprs) +{ + for (size_t idx = 0; idx < exprs.size(); idx++) { + if (idx != 0) + out << ", "; + if (exprs[idx]) + exprs[idx]->dump(out); + } + + return out; +} + +static std::ostream& operator << (std::ostream &out, + const std::vector &exprs) +{ + for (size_t idx = 0; idx < exprs.size(); idx++) { + if (idx != 0) + out << ", "; + if (!exprs[idx].name.nil()) + out << "." << exprs[idx].name << "("; + if (exprs[idx].parm) + exprs[idx].parm->dump(out); + if (!exprs[idx].name.nil()) + out << ")"; + } + + return out; +} + void data_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << typeid(*this).name() << endl; @@ -316,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 << " {"; @@ -380,15 +401,7 @@ void PExpr::dump(ostream&out) const void PEAssignPattern::dump(ostream&out) const { - out << "'{"; - if (parms_.size() > 0) { - parms_[0]->dump(out); - for (size_t idx = 1 ; idx < parms_.size() ; idx += 1) { - out << ", "; - parms_[idx]->dump(out); - } - } - out << "}"; + out << "'{" << parms_ << "}"; } void PEConcat::dump(ostream&out) const @@ -401,30 +414,14 @@ void PEConcat::dump(ostream&out) const return; } - out << "{"; - if (parms_[0]) out << *parms_[0]; - for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { - out << ", "; - if (parms_[idx]) out << *parms_[idx]; - } - - out << "}"; + out << "{" << parms_ << "}"; if (repeat_) out << "}"; } void PECallFunction::dump(ostream &out) const { - out << path_ << "("; - - if (! parms_.empty()) { - if (parms_[0]) parms_[0]->dump(out); - for (unsigned idx = 1; idx < parms_.size(); ++idx) { - out << ", "; - if (parms_[idx]) parms_[idx]->dump(out); - } - } - out << ")"; + out << path_ << "(" << parms_ << ")"; } void PECastSize::dump(ostream &out) const @@ -487,15 +484,7 @@ void PENewArray::dump(ostream&out) const void PENewClass::dump(ostream&out) const { - out << "class_new("; - if (parms_.size() > 0) { - parms_[0]->dump(out); - for (size_t idx = 1 ; idx < parms_.size() ; idx += 1) { - out << ", "; - if (parms_[idx]) parms_[idx]->dump(out); - } - } - out << ")"; + out << "class_new(" << parms_ << ")"; } void PENewCopy::dump(ostream&out) const @@ -830,14 +819,7 @@ void PGModule::dump(ostream&out, unsigned ind) const // If parameters are overridden by name, dump them. if (parms_) { assert(overrides_ == 0); - out << "#("; - for (unsigned idx = 0 ; idx < nparms_ ; idx += 1) { - if (idx > 0) out << ", "; - out << "." << parms_[idx].name << "("; - if (parms_[idx].parm) out << *parms_[idx].parm; - out << ")"; - } - out << ") "; + out << "#(" << parms_ << ") "; } out << get_name(); @@ -940,16 +922,7 @@ void PCallTask::dump(ostream&out, unsigned ind) const out << setw(ind) << "" << path_; if (! parms_.empty()) { - out << "("; - if (parms_[0]) - out << *parms_[0]; - - for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { - out << ", "; - if (parms_[idx]) - out << *parms_[idx]; - } - out << ")"; + out << "(" << parms_ << ")"; } out << "; /* " << get_fileline() << " */" << endl; @@ -1017,15 +990,7 @@ void PCase::dump(ostream&out, unsigned ind) const void PChainConstructor::dump(ostream&out, unsigned ind) const { - out << setw(ind) << "" << "super.new("; - if (parms_.size() > 0) { - if (parms_[0]) out << *parms_[0]; - } - for (size_t idx = 1 ; idx < parms_.size() ; idx += 1) { - out << ", "; - if (parms_[idx]) out << *parms_[idx]; - } - out << ");" << endl; + out << setw(ind) << "" << "super.new(" << parms_ << ")" <*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 234930445..fb7a03f8a 100644 --- a/pform_types.h +++ b/pform_types.h @@ -47,7 +47,6 @@ class PWire; class Statement; class netclass_t; class netenum_t; -typedef named named_number_t; typedef named named_pexpr_t; /* @@ -378,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;