Simplify V3LinkDot

This commit is contained in:
wsxarcher 2026-03-25 01:41:50 +01:00
parent ec8cf87d76
commit a28732ccf9
1 changed files with 70 additions and 150 deletions

View File

@ -92,7 +92,8 @@ static string dumpvarsTargetText(const AstNode* nodep) {
}
if (const AstCellArrayRef* const refp = VN_CAST(nodep, CellArrayRef)) {
string out = refp->name();
for (const AstNodeExpr* selp = refp->selp(); selp; selp = VN_CAST(selp->nextp(), NodeExpr)) {
for (const AstNodeExpr* selp = refp->selp(); selp;
selp = VN_CAST(selp->nextp(), NodeExpr)) {
out += "[" + dumpvarsTargetText(selp) + "]";
}
return out;
@ -3173,95 +3174,74 @@ class LinkDotResolveVisitor final : public VNVisitor {
}
} m_ds; // State to preserve across recursions
static string dumpvarsSymPathPiece(const AstNode* nodep) {
if (!nodep) return "";
if (const AstNodeModule* const modp = VN_CAST(nodep, NodeModule)) return modp->origName();
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) return cellp->origName();
if (const AstCellInline* const inlinep = VN_CAST(nodep, CellInline)) return inlinep->name();
if (const AstVarScope* const vscp = VN_CAST(nodep, VarScope)) return vscp->varp()->name();
return nodep->name();
}
static bool dumpvarsMatchesLocalModule(const VSymEnt* symp, const string& ident) {
if (!symp) return false;
if (const AstCell* const cellp = VN_CAST(symp->nodep(), Cell)) {
return cellp->modp() && cellp->modp()->origName() == ident;
}
if (const AstCellInline* const inlinep = VN_CAST(symp->nodep(), CellInline)) {
if (const AstCellInline* const inlinep = VN_CAST(symp->nodep(), CellInline))
return inlinep->origModName() == ident;
}
if (const AstNodeModule* const modp = VN_CAST(symp->nodep(), NodeModule)) {
if (const AstNodeModule* const modp = VN_CAST(symp->nodep(), NodeModule))
return modp->origName() == ident;
}
return false;
}
static string dumpvarsResolvedPath(VSymEnt* symp) {
std::vector<string> pieces;
for (VSymEnt* walkp = symp; walkp && walkp->parentp(); walkp = walkp->parentp()) {
const string piece = dumpvarsSymPathPiece(walkp->nodep());
if (!piece.empty()) pieces.push_back(piece);
}
std::reverse(pieces.begin(), pieces.end());
string path;
for (const string& piece : pieces) {
if (!path.empty()) path += '.';
path += piece;
for (VSymEnt* walkp = symp; walkp && walkp->parentp(); walkp = walkp->parentp()) {
const AstNode* const np = walkp->nodep();
const string piece = !np ? ""
: VN_IS(np, NodeModule) ? VN_AS(np, NodeModule)->origName()
: VN_IS(np, Cell) ? VN_AS(np, Cell)->origName()
: VN_IS(np, VarScope) ? VN_AS(np, VarScope)->varp()->name()
: np->name();
if (piece.empty()) continue;
path = path.empty() ? piece : piece + "." + path;
}
return path;
}
static bool dumpvarsHasBareTarget(AstNode* targetsp, const string& name) {
for (AstNode* tp = targetsp; tp; tp = tp->nextp()) {
if (dumpvarsTargetText(tp) == name) return true;
}
return false;
}
static string dumpvarsBracketToInternal(const string& ident) {
const string::size_type lbr = ident.find('[');
if (lbr == string::npos) return ident;
const string::size_type rbr = ident.find(']', lbr);
if (rbr == string::npos) return ident;
return ident.substr(0, lbr) + "__BRA__" + ident.substr(lbr + 1, rbr - lbr - 1)
+ "__KET__" + dumpvarsBracketToInternal(ident.substr(rbr + 1));
return ident.substr(0, lbr) + "__BRA__" + ident.substr(lbr + 1, rbr - lbr - 1) + "__KET__"
+ dumpvarsBracketToInternal(ident.substr(rbr + 1));
}
VSymEnt* findDumpvarsLocal(FileLine* refLocationp, const string& dotname, string& baddot,
VSymEnt*& okSymp) {
if (!m_curSymp) return nullptr;
string leftname = dotname;
string::size_type pos;
string ident;
if ((pos = leftname.find('.')) != string::npos) {
ident = leftname.substr(0, pos);
leftname = leftname.substr(pos + 1);
} else {
ident = leftname;
leftname = "";
}
const string::size_type dotPos = dotname.find('.');
const string ident = dotPos == string::npos ? dotname : dotname.substr(0, dotPos);
const string leftname = dotPos == string::npos ? "" : dotname.substr(dotPos + 1);
baddot = ident;
okSymp = m_curSymp;
string altIdent;
if (m_statep->forPrearray()) {
if ((pos = ident.rfind("__BRA__")) != string::npos) altIdent = ident.substr(0, pos);
if (altIdent.empty() && ident.find('[') != string::npos)
altIdent = ident.substr(0, ident.find('['));
}
VSymEnt* symp = nullptr;
if (dumpvarsMatchesLocalModule(m_curSymp, ident)) {
symp = m_curSymp;
} else {
symp = m_curSymp->findIdFallback(ident);
if (!symp && ident.find('[') != string::npos)
symp = m_curSymp->findIdFallback(dumpvarsBracketToInternal(ident));
if (!symp && !altIdent.empty()) symp = m_curSymp->findIdFallback(altIdent);
}
const auto findLocal = [&](const string& name) -> VSymEnt* {
if (dumpvarsMatchesLocalModule(m_curSymp, name)) return m_curSymp;
if (VSymEnt* const symp = m_curSymp->findIdFallback(name)) return symp;
const string internal = dumpvarsBracketToInternal(name);
if (internal != name) {
if (VSymEnt* const symp = m_curSymp->findIdFallback(internal)) return symp;
}
if (!m_statep->forPrearray()) return nullptr;
auto pos = name.rfind("__BRA__");
if (pos == string::npos) pos = name.find('[');
return (pos != string::npos && pos > 0)
? m_curSymp->findIdFallback(name.substr(0, pos))
: nullptr;
};
VSymEnt* const symp = findLocal(ident);
if (!symp) return nullptr;
if (leftname.empty()) {
okSymp = symp;
okSymp = symp;
if (leftname.empty()) return symp;
// Non-scope nodes (e.g. struct variables) don't have sub-symbols,
// accept the path without resolving further.
if (!(VN_IS(symp->nodep(), Cell) || VN_IS(symp->nodep(), CellInline)
|| VN_IS(symp->nodep(), NodeModule))) {
return symp;
}
return m_statep->findDotted(refLocationp, symp, leftname, baddot, okSymp, false);
@ -3273,112 +3253,52 @@ class LinkDotResolveVisitor final : public VNVisitor {
if (target.empty() || !m_curSymp) return target;
string baddot;
VSymEnt* matchSymp = nullptr;
VSymEnt* okSymp = nullptr;
const auto fail = [&]() {
fl->v3error("$dumpvars target not found: " << target);
return target;
};
const auto findFromRoot = [&](const string& path) {
return m_statep->findDotted(fl, m_statep->rootEntp(), path, baddot, okSymp, true);
};
// Step 1: Try local scope lookup.
if (findDumpvarsLocal(fl, target, baddot, matchSymp)) return target;
if (findDumpvarsLocal(fl, target, baddot, okSymp)) return target;
// Step 2: Try global lookup from $root.
if (VSymEnt* const rootSymp = m_statep->findDotted(
fl, m_statep->rootEntp(), target, baddot, matchSymp, true)) {
if (VSymEnt* const rootSymp = findFromRoot(target)) {
const string resolved = dumpvarsResolvedPath(rootSymp);
if (!resolved.empty()) return kDumpvarsResolved.make(resolved);
}
// Step 3: Defer single component to root lookup if available.
const string::size_type dotPos = target.find('.');
const string firstComp = (dotPos != string::npos) ? target.substr(0, dotPos) : target;
if (dotPos == string::npos)
return v3Global.opt.main() ? fail() : kDumpvarsRuntimeRoot.make(target);
if (dotPos == string::npos) {
if (v3Global.opt.main()) {
fl->v3error("$dumpvars target not found: " << target);
return target;
}
return kDumpvarsRuntimeRoot.make(target);
}
// Step 4: Multi-component "X.y.z" where X might be the runtime root.
const string firstComp = target.substr(0, dotPos);
const string remaining = target.substr(dotPos + 1);
// With --main, if the first component matches the local module,
// walk the remaining path through cell scopes to validate it.
if (!dumpvarsHasBareTarget(targetsp, firstComp) && v3Global.opt.main()
&& dumpvarsMatchesLocalModule(m_curSymp, firstComp)) {
string walkPath = remaining;
VSymEnt* walkSymp = m_curSymp;
bool errorOut = false;
while (!walkPath.empty() && walkSymp) {
// Extract first identifier (strip dots, brackets, __BRA__)
string ident = walkPath;
{
string::size_type cutPos = string::npos;
const string::size_type dp = ident.find('.');
if (dp != string::npos && dp < cutPos) cutPos = dp;
const string::size_type bp = ident.find('[');
if (bp != string::npos && (cutPos == string::npos || bp < cutPos))
cutPos = bp;
const string::size_type brp = ident.find("__BRA__");
if (brp != string::npos && (cutPos == string::npos || brp < cutPos))
cutPos = brp;
if (cutPos != string::npos) ident = ident.substr(0, cutPos);
}
VSymEnt* const childSymp = walkSymp->findIdFallback(ident);
if (!childSymp) {
errorOut = true;
break;
}
walkPath = walkPath.substr(ident.size());
if (!walkPath.empty() && walkPath[0] == '.') walkPath = walkPath.substr(1);
// Skip array subscript if present
if (!walkPath.empty() && walkPath[0] == '[') {
const string::size_type rb = walkPath.find(']');
if (rb != string::npos) walkPath = walkPath.substr(rb + 1);
if (!walkPath.empty() && walkPath[0] == '.') walkPath = walkPath.substr(1);
}
if (walkPath.substr(0, 7) == "__BRA__") {
const string::size_type ke = walkPath.find("__KET__");
if (ke != string::npos) walkPath = walkPath.substr(ke + 7);
if (!walkPath.empty() && walkPath[0] == '.') walkPath = walkPath.substr(1);
}
if (!VN_IS(childSymp->nodep(), Cell)
&& !VN_IS(childSymp->nodep(), CellInline)
&& !VN_IS(childSymp->nodep(), NodeModule)) {
return target;
}
walkSymp = childSymp;
}
if (errorOut) {
fl->v3error("$dumpvars target not found: " << target);
return target;
bool hasBareFirstComp = false;
for (AstNode* tp = targetsp; tp; tp = tp->nextp()) {
if (dumpvarsTargetText(tp) == firstComp) {
hasBareFirstComp = true;
break;
}
}
if (hasBareFirstComp) {
return findFromRoot(remaining) ? kDumpvarsRuntimeRoot.make(target) : fail();
}
if (v3Global.opt.main() && dumpvarsMatchesLocalModule(m_curSymp, firstComp)) {
if (!findDumpvarsLocal(fl, remaining, baddot, okSymp)) fail();
return target;
}
if (dumpvarsHasBareTarget(targetsp, firstComp)) {
string runtimeBaddot;
VSymEnt* runtimeMatchSymp = nullptr;
if (m_statep->findDotted(fl, m_statep->rootEntp(), remaining, runtimeBaddot,
runtimeMatchSymp, true)) {
return kDumpvarsRuntimeRoot.make(target);
}
fl->v3error("$dumpvars target not found: " << target);
if (findDumpvarsLocal(fl, firstComp, baddot, okSymp)
&& !(VN_IS(okSymp->nodep(), Cell) || VN_IS(okSymp->nodep(), CellInline)
|| VN_IS(okSymp->nodep(), NodeModule))) {
return target;
}
string localBaddot;
VSymEnt* localSymp = nullptr;
if (findDumpvarsLocal(fl, firstComp, localBaddot, localSymp)
&& !VN_IS(localSymp->nodep(), Cell) && !VN_IS(localSymp->nodep(), CellInline)
&& !VN_IS(localSymp->nodep(), NodeModule)) {
return target;
}
if (v3Global.opt.main()) {
fl->v3error("$dumpvars target not found: " << target);
return target;
}
// First component may be a runtime root name from C++; defer validation to runtime.
return kDumpvarsRuntimeRoot.make(target);
return v3Global.opt.main() ? fail() : kDumpvarsRuntimeRoot.make(target);
}
// METHODS - Variables