Offer suggestions on bad identifier errors.

This commit is contained in:
Wilson Snyder 2019-07-13 20:30:32 -04:00
parent 0fef3b02ec
commit 173efbc829
25 changed files with 458 additions and 28 deletions

View File

@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.017 devel
** Offer suggestions on bad identifier errors.
*** Change MULTITOP to warning to help linting, see manual.
**** Show included-from filenames in warnings, bug1439. [Todd Strader]

View File

@ -57,7 +57,7 @@ typedef std::set<int> MTaskIdSet; // Set of mtaskIds for Var sorting
#define VN_IS(nodep,nodetypename) (AstNode::privateIs ## nodetypename(nodep))
// (V)erilator (N)ode cast: Cast to given type if can; effectively
// dynamic_cast(nodep)(nodetypename)
// dynamic_cast<nodetypename>(nodep)
#define VN_CAST(nodep,nodetypename) (AstNode::privateCast ## nodetypename(nodep))
#define VN_CAST_CONST(nodep,nodetypename) (AstNode::privateConstCast ## nodetypename(nodep) )
@ -1114,6 +1114,14 @@ public:
};
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs);
//######################################################################
// Callback base class to determine if node matches some formula
class VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const { return true; }
};
//######################################################################
// AstNode -- Base type of all Ast types

View File

@ -41,7 +41,10 @@ class V3LanguageWords {
void init();
};
public:
typedef KeywordMap::const_iterator const_iterator;
// METHODS
static const_iterator begin() { return s().s_kwdMap.begin(); }
static const_iterator end() { return s().s_kwdMap.end(); }
static string isKeyword(const string& kwd) {
KeywordMap::iterator it = s().s_kwdMap.find(kwd);
if (it == s().s_kwdMap.end()) return "";
@ -187,6 +190,62 @@ inline void V3LanguageWords::Singleton::init() {
addKwd("sensitive", "SystemC common word");
addKwd("sensitive_neg", "SystemC common word");
addKwd("sensitive_pos", "SystemC common word");
// Preprocessor defined words
addKwd("`__FILE__", "Verilog preprocessor directive");
addKwd("`__LINE__", "Verilog preprocessor directive");
addKwd("`accelerate", "Verilog-XL preprocessor directive");
addKwd("`autoexpand_vectornets", "Verilog-XL preprocessor directive");
addKwd("`begin_keywords", "Verilog preprocessor directive");
addKwd("`celldefine", "Verilog preprocessor directive");
addKwd("`default_decay_time", "Verilog preprocessor directive");
addKwd("`default_nettype", "Verilog preprocessor directive");
addKwd("`default_trireg_strength", "Verilog preprocessor directive");
addKwd("`define", "Verilog preprocessor directive");
addKwd("`delay_mode_distributed", "Verilog preprocessor directive");
addKwd("`delay_mode_path", "Verilog preprocessor directive");
addKwd("`delay_mode_unit", "Verilog preprocessor directive");
addKwd("`delay_mode_zero", "Verilog preprocessor directive");
addKwd("`disable_portfaults", "Verilog-XL preprocessor directive");
addKwd("`else", "Verilog preprocessor directive");
addKwd("`elsif", "Verilog preprocessor directive");
addKwd("`enable_portfaults", "Verilog-XL preprocessor directive");
addKwd("`end_keywords", "Verilog preprocessor directive");
addKwd("`endcelldefine", "Verilog preprocessor directive");
addKwd("`endif", "Verilog preprocessor directive");
addKwd("`endprotect", "Verilog preprocessor directive");
addKwd("`endprotected", "Verilog preprocessor directive");
addKwd("`error", "Verilog preprocessor directive");
addKwd("`expand_vectornets", "Verilog-XL preprocessor directive");
addKwd("`ifdef", "Verilog preprocessor directive");
addKwd("`ifndef", "Verilog preprocessor directive");
addKwd("`include", "Verilog preprocessor directive");
addKwd("`inline", "Verilog preprocessor directive");
addKwd("`line", "Verilog preprocessor directive");
addKwd("`noaccelerate", "Verilog-XL preprocessor directive");
addKwd("`noexpand_vectornets", "Verilog-XL preprocessor directive");
addKwd("`noremove_gatenames", "Verilog-XL preprocessor directive");
addKwd("`noremove_netnames", "Verilog-XL preprocessor directive");
addKwd("`nosuppress_faults", "Verilog-XL preprocessor directive");
addKwd("`nounconnected_drive", "Verilog-XL preprocessor directive");
addKwd("`portcoerce", "Verilog preprocessor directive");
addKwd("`pragma", "Verilog preprocessor directive");
addKwd("`protect", "Verilog preprocessor directive");
addKwd("`protected", "Verilog preprocessor directive");
addKwd("`remove_gatenames", "Verilog-XL preprocessor directive");
addKwd("`remove_netnames", "Verilog-XL preprocessor directive");
addKwd("`resetall", "Verilog preprocessor directive");
addKwd("`suppress_faults", "Verilog-XL preprocessor directive");
addKwd("`systemc_ctor", "Verilator preprocessor directive");
addKwd("`systemc_dtor", "Verilator preprocessor directive");
addKwd("`systemc_header", "Verilator preprocessor directive");
addKwd("`systemc_imp_header", "Verilator preprocessor directive");
addKwd("`systemc_implementation", "Verilator preprocessor directive");
addKwd("`systemc_interface", "Verilator preprocessor directive");
addKwd("`timescale", "Verilog preprocessor directive");
addKwd("`undef", "Verilog preprocessor directive");
addKwd("`undefineall", "Verilog preprocessor directive");
addKwd("`verilator_config", "Verilator preprocessor directive");
addKwd("`verilog", "Verilator preprocessor directive");
}
#endif // Guard

View File

@ -79,6 +79,50 @@
#include <map>
#include <vector>
//######################################################################
// Matcher classes (for suggestion matching)
class LinkNodeMatcherFTask : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const {
return VN_IS(nodep, NodeFTask);
}
};
class LinkNodeMatcherModport : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const {
return VN_IS(nodep, Modport);
}
};
class LinkNodeMatcherVar : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const {
return VN_IS(nodep, Var);
}
};
class LinkNodeMatcherVarIO : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const {
const AstVar* varp = VN_CAST_CONST(nodep, Var);
if (!varp) return false;
return varp->isIO();
}
};
class LinkNodeMatcherVarParam : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const {
const AstVar* varp = VN_CAST_CONST(nodep, Var);
if (!varp) return false;
return varp->isParam();
}
};
class LinkNodeMatcherVarOrScope : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const {
return VN_IS(nodep, Var) || VN_IS(nodep, Scope);
}
};
//######################################################################
// LinkDot state, as a visitor of each AstNode
@ -428,9 +472,14 @@ public:
ok = true;
}
}
if (!ok) ifacerefp->v3error("Modport not found under interface "
<<ifacerefp->prettyNameQ(ifacerefp->ifaceName())
<<": "<<ifacerefp->prettyNameQ(ifacerefp->modportName()));
if (!ok) {
string suggest = suggestSymFallback(
ifaceSymp, ifacerefp->modportName(), LinkNodeMatcherModport());
ifacerefp->v3error("Modport not found under interface "
<<ifacerefp->prettyNameQ(ifacerefp->ifaceName())<<": "
<<ifacerefp->prettyNameQ(ifacerefp->modportName())<<endl
<<(suggest.empty() ? "" : ifacerefp->warnMore()+suggest));
}
}
// Alias won't expand until interfaces and modport names are known; see notes at top
insertScopeAlias(SAMN_IFTOP, varSymp, ifOrPortSymp);
@ -601,6 +650,23 @@ public:
if (!foundp) baddot = dotname;
return foundp;
}
string suggestSymFallback(VSymEnt* lookupSymp, const string& name,
const VNodeMatcher& matcher) {
// Suggest alternative symbol in given point in hierarchy
// Does not support inline, as we find user-level errors before inlining
// For simplicity lookupSymp may be passed NULL result from findDotted
if (!lookupSymp) return "";
VSpellCheck speller;
lookupSymp->candidateIdFallback(&speller, &matcher);
return speller.bestCandidateMsg(name);
}
string suggestSymFlat(VSymEnt* lookupSymp, const string& name,
const VNodeMatcher& matcher) {
if (!lookupSymp) return "";
VSpellCheck speller;
lookupSymp->candidateIdFlat(&speller, &matcher);
return speller.bestCandidateMsg(name);
}
};
LinkDotState* LinkDotState::s_errorThisp = NULL;
@ -1611,11 +1677,21 @@ private:
if (!nodep->varp()) {
if (!noWarn) {
if (nodep->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) {
string suggest = m_statep->suggestSymFallback(
moduleSymp, nodep->name(), LinkNodeMatcherVar());
nodep->v3error("Signal definition not found, and implicit disabled with `default_nettype: "
<<nodep->prettyNameQ());
} else {
<<nodep->prettyNameQ()<<endl
<<(suggest.empty() ? "" : nodep->warnMore()+suggest));
}
// Bypass looking for suggestions if IMPLICIT is turned off
// as there could be thousands of these suppressed in large netlists
else if (!nodep->fileline()->warnIsOff(V3ErrorCode::IMPLICIT)) {
string suggest = m_statep->suggestSymFallback(
moduleSymp, nodep->name(), LinkNodeMatcherVar());
nodep->v3warn(IMPLICIT, "Signal definition not found, creating implicitly: "
<<nodep->prettyNameQ());
<<nodep->prettyNameQ()<<endl
<<(suggest.empty() ? "" : nodep->warnMore()+suggest));
}
}
AstVar* newp = new AstVar(nodep->fileline(), AstVarType::WIRE,
@ -1762,7 +1838,14 @@ private:
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
nodep->v3error(ucfirst(whatp)<<" not found: "<<nodep->prettyNameQ());
string suggest
= (nodep->param()
? m_statep->suggestSymFlat(
m_pinSymp, nodep->name(), LinkNodeMatcherVarParam())
: m_statep->suggestSymFlat(
m_pinSymp, nodep->name(), LinkNodeMatcherVarIO()));
nodep->v3error(ucfirst(whatp)<<" not found: "<<nodep->prettyNameQ()<<endl
<<(suggest.empty() ? "" : nodep->warnMore()+suggest));
}
else if (AstVar* refp = VN_CAST(foundp->nodep(), Var)) {
if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) {
@ -2050,8 +2133,11 @@ private:
} else if (m_ds.m_dotText=="") {
UINFO(7," ErrParseRef curSymp=se"<<cvtToHex(m_curSymp)
<<" ds="<<m_ds.ascii()<<endl);
string suggest = m_statep->suggestSymFallback(
m_ds.m_dotSymp, nodep->name(), VNodeMatcher());
nodep->v3error("Can't find definition of "<<expectWhat
<<": "<<nodep->prettyNameQ());
<<": "<<nodep->prettyNameQ()<<endl
<<(suggest.empty() ? "" : nodep->warnMore()+suggest));
} else {
nodep->v3error("Can't find definition of '"
<<(baddot!="" ? baddot : nodep->prettyName())
@ -2274,12 +2360,18 @@ private:
<<"'"<<" as a "<<foundp->nodep()->typeName()
<<" but expected a task/function");
} else if (nodep->dotted() == "") {
string suggest = m_statep->suggestSymFallback(
dotSymp, nodep->name(), LinkNodeMatcherFTask());
nodep->v3error("Can't find definition of task/function: "
<<nodep->prettyNameQ());
<<nodep->prettyNameQ()<<endl
<<(suggest.empty() ? "" : nodep->warnMore()+suggest));
} else {
string suggest = m_statep->suggestSymFallback(
dotSymp, nodep->name(), LinkNodeMatcherFTask());
nodep->v3error("Can't find definition of '"<<baddot
<<"' in dotted task/function: '"
<<nodep->dotted()+"."+nodep->prettyName()<<"'");
<<nodep->dotted()+"."+nodep->prettyName()<<"'\n"
<<(suggest.empty() ? "" : nodep->warnMore()+suggest));
okSymp->cellErrorScopes(nodep);
}
}

View File

@ -36,6 +36,7 @@
#include "V3File.h"
#include "V3ParseImp.h"
#include "V3PreShell.h"
#include "V3LanguageWords.h"
#include <cstdarg>
#include <fstream>
@ -132,6 +133,21 @@ void V3ParseImp::verilatorCmtBad(const char* textp) {
}
}
void V3ParseImp::errorPreprocDirective(const char* textp) {
// Find all `preprocessor spelling candidates
// Can't make this static as might get more defines later when read cells
VSpellCheck speller;
V3LanguageWords words;
for (V3LanguageWords::const_iterator it = words.begin(); it != words.end(); ++it) {
string ppDirective = it->first;
if (ppDirective[0] == '`') speller.pushCandidate(ppDirective);
}
V3PreShell::candidateDefines(&speller);
string suggest = speller.bestCandidateMsg(textp);
fileline()->v3error("Define or directive not defined: '"<<textp<<"'\n"
<<(suggest.empty() ? "" : fileline()->warnMore()+suggest));
}
void V3ParseImp::tag(const char* text) {
if (m_tagNodep) {
string tmp = text + strlen("/*verilator tag ");

View File

@ -148,6 +148,7 @@ public:
void verilatorCmtLintSave();
void verilatorCmtLintRestore();
void verilatorCmtBad(const char* text);
void errorPreprocDirective(const char* textp);
void tag(const char* text);
void tagNodep(AstNode* nodep) { m_tagNodep = nodep; }
AstNode* tagNodep() const { return m_tagNodep;}

View File

@ -27,6 +27,7 @@
#include "V3PreLex.h"
#include "V3PreProc.h"
#include "V3PreShell.h"
#include "V3String.h"
#include <cstdarg>
#include <cstdlib>
@ -233,6 +234,7 @@ public:
void insertUnreadbackAtBol(const string& text);
void addLineComment(int enterExit);
void dumpDefines(std::ostream& os);
void candidateDefines(VSpellCheck* spellerp);
// METHODS, callbacks
virtual void comment(const string& text); // Comment detected (if keepComments==2)
@ -818,7 +820,7 @@ void V3PreProcImp::addLineComment(int enterExit) {
}
void V3PreProcImp::dumpDefines(std::ostream& os) {
for (DefinesMap::iterator it = m_defines.begin(); it != m_defines.end(); ++it) {
for (DefinesMap::const_iterator it = m_defines.begin(); it != m_defines.end(); ++it) {
os<<"`define "<<it->first;
// No need to print "()" below as already part of params()
if (!it->second.params().empty()) os<<it->second.params();
@ -827,6 +829,12 @@ void V3PreProcImp::dumpDefines(std::ostream& os) {
}
}
void V3PreProcImp::candidateDefines(VSpellCheck* spellerp) {
for (DefinesMap::const_iterator it = m_defines.begin(); it != m_defines.end(); ++it) {
spellerp->pushCandidate(string("`") + it->first);
}
}
int V3PreProcImp::getRawToken() {
// Get a token from the file, whatever it may be.
while (1) {

View File

@ -35,6 +35,7 @@
#define fatalSrc(msg) v3fatalSrc(msg)
class V3InFilter;
class VSpellCheck;
class V3PreProc {
// This defines a preprocessor. Functions are virtual so implementation can be hidden.
@ -95,6 +96,7 @@ public:
void error(const string& msg) { fileline()->v3error(msg); } ///< Report an error
void fatal(const string& msg) { fileline()->v3fatalSrc(msg); } ///< Report a fatal error
virtual void dumpDefines(std::ostream& os) = 0; ///< Print list of `defines
virtual void candidateDefines(VSpellCheck* spellerp) = 0; ///< Spell check candidate defines
protected:
// CONSTUCTORS

View File

@ -187,3 +187,6 @@ void V3PreShell::undef(const string& name) {
void V3PreShell::dumpDefines(std::ostream& os) {
V3PreShellImp::s_preprocp->dumpDefines(os);
}
void V3PreShell::candidateDefines(VSpellCheck* spellerp) {
V3PreShellImp::s_preprocp->candidateDefines(spellerp);
}

View File

@ -29,6 +29,7 @@
class V3ParseImp;
class V3InFilter;
class VSpellCheck;
//============================================================================
@ -43,6 +44,7 @@ public:
static void defineCmdLine(const string& name, const string& value);
static void undef(const string& name);
static void dumpDefines(std::ostream& os);
static void candidateDefines(VSpellCheck* spellerp);
};
#endif // Guard

View File

@ -25,6 +25,8 @@
#include "V3String.h"
#include "V3Error.h"
#include <algorithm>
size_t VName::s_minLength = 32;
size_t VName::s_maxLength = 0; // Disabled
@ -273,7 +275,7 @@ string VHashSha1::digestSymbol() {
}
void VHashSha1::selfTestOne(const string& data, const string& data2,
const string& exp, const string& exp64) {
const string& exp, const string& exp64) {
VHashSha1 digest (data);
if (data2!="") digest.insert(data2);
if (VL_UNCOVERABLE(digest.digestHex() != exp)) {
@ -329,3 +331,138 @@ string VName::hashedName() {
return m_hashed;
}
}
//######################################################################
// VSpellCheck - Algorithm same as GCC's spellcheck.c
VSpellCheck::EditDistance VSpellCheck::editDistance(const string& s, const string& t) {
// Wagner-Fischer algorithm for the Damerau-Levenshtein distance
size_t sLen = s.length();
size_t tLen = t.length();
if (sLen == 0) return tLen;
if (tLen == 0) return sLen;
if (sLen >= LENGTH_LIMIT) return sLen;
if (tLen >= LENGTH_LIMIT) return tLen;
static EditDistance s_v_two_ago[LENGTH_LIMIT + 1];
static EditDistance s_v_one_ago[LENGTH_LIMIT + 1];
static EditDistance s_v_next[LENGTH_LIMIT + 1];
for (int i = 0; i < sLen + 1; i++) s_v_one_ago[i] = i;
for (int i = 0; i < tLen; i++) {
s_v_next[0] = i + 1;
for (int j = 0; j < sLen; j++) {
EditDistance cost =(s[j] == t[i] ? 0 : 1);
EditDistance deletion = s_v_next[j] + 1;
EditDistance insertion = s_v_one_ago[j + 1] + 1;
EditDistance substitution = s_v_one_ago[j] + cost;
EditDistance cheapest = std::min(deletion, insertion);
cheapest = std::min(cheapest, substitution);
if (i > 0 && j > 0 && s[j] == t[i - 1] && s[j - 1] == t[i]) {
EditDistance transposition = s_v_two_ago[j - 1] + 1;
cheapest = std::min(cheapest, transposition);
}
s_v_next[j + 1] = cheapest;
}
for (int j = 0; j < sLen + 1; j++) {
s_v_two_ago[j] = s_v_one_ago[j];
s_v_one_ago[j] = s_v_next[j];
}
}
EditDistance result = s_v_next[sLen];
return result;
}
VSpellCheck::EditDistance VSpellCheck::cutoffDistance(size_t goal_len, size_t candidate_len) {
// Return max acceptable edit distance
size_t max_length = std::max(goal_len, candidate_len);
size_t min_length = std::min(goal_len, candidate_len);
if (max_length <= 1) return 0;
if (max_length - min_length <= 1) return std::max(max_length / 3, (size_t)1);
return (max_length + 2) / 3;
}
string VSpellCheck::bestCandidateInfo(const string& goal,
EditDistance& distancer) {
string bestCandidate;
size_t gLen = goal.length();
distancer = LENGTH_LIMIT*10;
int suggestionLimit = 1000; // Avoid searching massive netlists
for (Candidates::const_iterator it = m_candidates.begin();
it != m_candidates.end(); ++it) {
const string candidate = *it;
size_t cLen = candidate.length();
// Min distance must be inserting/deleting to make lengths match
EditDistance min_distance = (cLen > gLen ? (cLen - gLen) : (gLen - cLen));
if (min_distance >= distancer) continue; // Short-circuit if already better
EditDistance cutoff = cutoffDistance(gLen, cLen);
if (min_distance > cutoff) continue; // Short-circuit if already too bad
EditDistance dist = editDistance(goal, candidate);
UINFO(9, "EditDistance dist="<<dist<<" cutoff="<<cutoff
<<" goal="<<goal<<" candidate="<<candidate<<endl);
if (dist < distancer && dist <= cutoff) {
distancer = dist;
bestCandidate = candidate;
}
}
// If goal matches candidate avoid suggesting replacing with self
if (distancer == 0) return "";
return bestCandidate;
}
void VSpellCheck::selfTestDistanceOne(const string& a, const string& b,
EditDistance expected) {
UASSERT_SELFTEST(EditDistance, editDistance(a, b), expected);
UASSERT_SELFTEST(EditDistance, editDistance(b, a), expected);
}
void VSpellCheck::selfTestSuggestOne(bool matches, const string& c, const string& goal,
EditDistance dist) {
EditDistance gdist;
VSpellCheck speller;
speller.pushCandidate(c);
string got = speller.bestCandidateInfo(goal, gdist/*ref*/);
if (matches) {
UASSERT_SELFTEST(string, got, c);
UASSERT_SELFTEST(EditDistance, gdist, dist);
} else {
UASSERT_SELFTEST(string, got, "");
}
}
void VSpellCheck::selfTest() {
{
selfTestDistanceOne("ab", "ac", 1);
selfTestDistanceOne("ab", "a", 1);
selfTestDistanceOne("a", "b", 1);
}
{
selfTestSuggestOne(true, "DEL_ETE", "DELETE", 1);
selfTestSuggestOne(true, "abcdef", "acbdef", 1);
selfTestSuggestOne(true, "db", "dc", 1);
selfTestSuggestOne(true, "db", "dba", 1);
// Negative suggestions
selfTestSuggestOne(false, "x", "y", 1);
selfTestSuggestOne(false, "sqrt", "assert", 3);
}
{
VSpellCheck speller;
UASSERT_SELFTEST(string, "", speller.bestCandidate(""));
}
{
VSpellCheck speller;
speller.pushCandidate("fred");
speller.pushCandidate("wilma");
speller.pushCandidate("barney");
UASSERT_SELFTEST(string, "fred", speller.bestCandidate("fre"));
UASSERT_SELFTEST(string, "wilma", speller.bestCandidate("whilma"));
UASSERT_SELFTEST(string, "barney", speller.bestCandidate("Barney"));
UASSERT_SELFTEST(string, "", speller.bestCandidate("nothing close"));
}
}

View File

@ -111,6 +111,50 @@ public:
static size_t maxLength() { return s_maxLength; }
};
//######################################################################
// VSpellCheck - Find near-match spelling suggestions given list of possibilities
class VSpellCheck {
// CONSTANTS
enum { NUM_CANDIDATE_LIMIT = 10000 }; // Avoid searching huge netlists
enum { LENGTH_LIMIT = 100 }; // Maximum string length to seach
// TYPES
typedef unsigned int EditDistance;
typedef std::vector<string> Candidates;
// MEMBERS
Candidates m_candidates; // Strings we try to match
public:
// CONSTRUCTORS
explicit VSpellCheck() {}
~VSpellCheck() {}
// METHODS
// Push a symbol table value to be considered as a candidate
// The first item pushed has highest priority, all else being equal
void pushCandidate(const string& s) {
if (m_candidates.size() < NUM_CANDIDATE_LIMIT) m_candidates.push_back(s);
}
// Return candidate is closest to provided string, or "" for none
string bestCandidate(const string& goal) {
EditDistance dist;
return bestCandidateInfo(goal, dist/*ref*/);
}
// Return friendly message
string bestCandidateMsg(const string& goal) {
string candidate = bestCandidate(goal);
if (candidate.empty()) return "";
else return string("... Suggested alternative: '")+candidate+"'";
}
static void selfTest();
private:
static EditDistance editDistance(const string& s, const string& t);
static EditDistance cutoffDistance(size_t goal_len, size_t candidate_len);
string bestCandidateInfo(const string& goal, EditDistance& distancer);
static void selfTestDistanceOne(const string& a, const string& b,
EditDistance expected);
static void selfTestSuggestOne(bool matches, const string& c, const string& goal,
EditDistance dist);
};
//######################################################################
#endif // guard

View File

@ -27,6 +27,7 @@
#include "V3Global.h"
#include "V3Ast.h"
#include "V3File.h"
#include "V3String.h"
#include <cstdarg>
#include <map>
@ -158,6 +159,23 @@ public:
if (m_fallbackp) return m_fallbackp->findIdFallback(name);
return NULL;
}
void candidateIdFlat(VSpellCheck* spellerp, const VNodeMatcher* matcherp) const {
// Suggest alternative symbol candidates without looking upward through symbol hierarchy
for (IdNameMap::const_iterator it = m_idNameMap.begin();
it != m_idNameMap.end(); ++it) {
const AstNode* nodep = it->second->nodep();
if (nodep && (!matcherp || matcherp->nodeMatch(nodep))) {
spellerp->pushCandidate(nodep->prettyName());
}
}
}
void candidateIdFallback(VSpellCheck* spellerp, const VNodeMatcher* matcherp) const {
// Suggest alternative symbol candidates with looking upward through symbol hierarchy
// Note VSpellCheck wants the most important (closest) items pushed first
candidateIdFlat(spellerp, matcherp);
// Then suggest the upper begin/end block or module
if (m_fallbackp) m_fallbackp->candidateIdFallback(spellerp, matcherp);
}
private:
void importOneSymbol(VSymGraph* graphp, const string& name, const VSymEnt* srcp) {
if (srcp->exported()

View File

@ -622,9 +622,10 @@ int main(int argc, char** argv, char** env) {
// Internal tests (after option parsing as need debug() setting,
// and after removing files as may make debug output)
VHashSha1::selfTest();
AstBasicDTypeKwd::selfTest();
if (v3Global.opt.debugSelfTest()) {
VHashSha1::selfTest();
VSpellCheck::selfTest();
V3Graph::selfTest();
V3TSP::selfTest();
V3ScoreboardBase::selfTest();

View File

@ -884,6 +884,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Preprocessor */
/* Common for all SYSC header states */
/* OPTIMIZE: we return one per line, make it one for the entire block */
/* If add to this list also add to V3LanguageWords.h */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
"`accelerate" { } // Verilog-XL compatibility
"`autoexpand_vectornets" { } // Verilog-XL compatibility
@ -941,6 +942,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"`systemc_interface" { BEGIN SYSCINT; }
"`verilator_config" { BEGIN VLT; }
"`verilog" { BEGIN PARSEP->lastVerilogState(); }
/* If add to this list also add to V3LanguageWords.h */
}
<SYSCHDR>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { FL; NEXTLINE(); yylval.strp = PARSEP->newString(yytext); return yaSCHDR; }
@ -961,7 +964,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Default rules - leave last */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT>{
"`"[a-zA-Z_0-9]+ { FL; yyerrorf("Define or directive not defined: %s", yytext); }
"`"[a-zA-Z_0-9]+ { FL; PARSEP->errorPreprocDirective(yytext); }
"//"[^\n]* { } /* throw away single line comments */
. { FL; return yytext[0]; } /* return single char ops. */
}

View File

@ -1,2 +1,3 @@
%Error: t/t_interface_modport_bad.v:22: Modport not found under interface 'ifc': 'oop_modport'
: ... Suggested alternative: 'out_modport'
%Error: Exiting due to

View File

@ -2,5 +2,7 @@
... Use "/* verilator lint_off IMPLICIT */" and lint_on around source to disable this message.
%Warning-IMPLICIT: t/t_lint_implicit.v:12: Signal definition not found, creating implicitly: 'nt0'
%Warning-IMPLICIT: t/t_lint_implicit.v:15: Signal definition not found, creating implicitly: 'dummy1'
: ... Suggested alternative: 'dummy_ip'
%Warning-IMPLICIT: t/t_lint_implicit.v:15: Signal definition not found, creating implicitly: 'dummy2'
: ... Suggested alternative: 'dummy1'
%Error: Exiting due to

View File

@ -1,6 +1,13 @@
%Error: t/t_lint_pindup_bad.v:17: Duplicate pin connection: 'i'
t/t_lint_pindup_bad.v:16: ... Location of original pin connection
%Error: t/t_lint_pindup_bad.v:18: Pin not found: '__pinNumber4'
%Error: t/t_lint_pindup_bad.v:14: Duplicate parameter pin connection: 'P'
%Warning-PINMISSING: t/t_lint_pindup_bad.v:18: Cell has missing pin: 'exists'
... Use "/* verilator lint_off PINMISSING */" and lint_on around source to disable this message.
%Error: t/t_lint_pindup_bad.v:20: Duplicate pin connection: 'i'
t/t_lint_pindup_bad.v:19: ... Location of original pin connection
%Error: t/t_lint_pindup_bad.v:21: Pin not found: 'nexist'
: ... Suggested alternative: 'exists'
%Error: t/t_lint_pindup_bad.v:15: Parameter pin not found: 'NEXIST'
: ... Suggested alternative: 'EXIST'
%Error: t/t_lint_pindup_bad.v:16: Duplicate parameter pin connection: 'P'
t/t_lint_pindup_bad.v:14: ... Location of original parameter pin connection
%Error: t/t_lint_pindup_bad.v:17: Duplicate parameter pin connection: 'P'
t/t_lint_pindup_bad.v:14: ... Location of original parameter pin connection
%Error: Exiting due to

View File

@ -11,19 +11,25 @@ module t
);
sub
#(, .P(2), .P(3))
#(, // Not found
.NEXIST(1), // Not found
.P(2),
.P(3)) // Dup
sub (.o(o),
.i(i),
.i(i2),
.i(i2), // Dup
.nexist(i2) // Not found
);
endmodule
module sub
#(parameter P=1)
#(parameter P=1,
parameter EXIST=9)
(
output wire o,
input wire i
input wire i,
input wire exists
);
assign o = ~i;

View File

@ -1,7 +1,13 @@
%Error: t/t_package_export.v:56: Can't find definition of scope/variable: 'PARAM2'
: ... Suggested alternative: 'PARAM1'
%Error: t/t_package_export.v:57: Can't find definition of scope/variable: 'PARAM3'
: ... Suggested alternative: 'PARAM1'
%Error: t/t_package_export.v:60: Can't find definition of scope/variable: 'PARAM2'
: ... Suggested alternative: 'PARAM1'
%Error: t/t_package_export.v:61: Can't find definition of scope/variable: 'PARAM3'
: ... Suggested alternative: 'PARAM1'
%Error: t/t_package_export.v:64: Can't find definition of scope/variable: 'PARAM2'
: ... Suggested alternative: 'PARAM1'
%Error: t/t_package_export.v:65: Can't find definition of scope/variable: 'PARAM3'
: ... Suggested alternative: 'PARAM1'
%Error: Exiting due to

View File

@ -1,2 +1,5 @@
%Error: t/t_pp_misdef_bad.v:10: Define or directive not defined: `NOTDEF
%Error: t/t_pp_misdef_bad.v:10: Define or directive not defined: '`NDEFINED'
: ... Suggested alternative: '`DEFINED'
%Error: t/t_pp_misdef_bad.v:13: Define or directive not defined: '`imescale'
: ... Suggested alternative: '`timescale'
%Error: Exiting due to

View File

@ -4,12 +4,13 @@
// without warranty, 2004 by Wilson Snyder.
module t;
`define A B
`define DEFINED
// NOTDEF isn't defined here:
`NOTDEF
// NDEFINED isn't defined here:
`NDEFINED
//`include "notfound"
// Botched directive (`timescale)
`imescale
initial $stop; // Should have failed

View File

@ -28,9 +28,12 @@
%Error: t/t_var_dup_bad.v:40: Duplicate pin connection: 'bad_duport'
t/t_var_dup_bad.v:40: ... Location of original pin connection
%Error: t/t_var_dup_bad.v:41: Can't find definition of variable: 'bad_mixport'
: ... Suggested alternative: 'bad_duport'
%Error: t/t_var_dup_bad.v:41: Duplicate pin connection: 'bad_mixport'
t/t_var_dup_bad.v:41: ... Location of original pin connection
%Error: t/t_var_dup_bad.v:42: Can't find definition of variable: 'bad_reout_port'
: ... Suggested alternative: 'bad_duport'
%Error: t/t_var_dup_bad.v:43: Can't find definition of variable: 'bad_rewire'
%Error: t/t_var_dup_bad.v:43: Can't find definition of variable: 'bad_rereg'
: ... Suggested alternative: 'bad_rewire'
%Error: Exiting due to

View File

@ -2,8 +2,11 @@
%Error: t/t_var_notfound_bad.v:18: Can't find definition of 'subsubz' in dotted scope/variable: 'sub.subsubz'
... Known scopes under 'sub': subsub
%Error: t/t_var_notfound_bad.v:19: Can't find definition of task/function: 'nofunc'
: ... Suggested alternative: 'notfunc'
%Error: t/t_var_notfound_bad.v:20: Can't find definition of 'nofuncs' in dotted task/function: 'sub.nofuncs'
: ... Suggested alternative: 'notfuncs'
... Known scopes under 'nofuncs': <no cells found>
%Error: t/t_var_notfound_bad.v:21: Can't find definition of task/function: 'notask'
: ... Suggested alternative: 'nottask'
%Error: t/t_var_notfound_bad.v:22: Found definition of 'a_var' as a VAR but expected a task/function
%Error: Exiting due to

View File

@ -1,3 +1,5 @@
%Error: t/t_var_suggest_bad.v:12: Can't find definition of variable: 'foobat'
: ... Suggested alternative: 'foobar'
%Error: t/t_var_suggest_bad.v:13: Can't find definition of task/function: 'boobat'
: ... Suggested alternative: 'boobar'
%Error: Exiting due to