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)) { if (const AstCellArrayRef* const refp = VN_CAST(nodep, CellArrayRef)) {
string out = refp->name(); 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) + "]"; out += "[" + dumpvarsTargetText(selp) + "]";
} }
return out; return out;
@ -3173,95 +3174,74 @@ class LinkDotResolveVisitor final : public VNVisitor {
} }
} m_ds; // State to preserve across recursions } 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) { static bool dumpvarsMatchesLocalModule(const VSymEnt* symp, const string& ident) {
if (!symp) return false; if (!symp) return false;
if (const AstCell* const cellp = VN_CAST(symp->nodep(), Cell)) { if (const AstCell* const cellp = VN_CAST(symp->nodep(), Cell)) {
return cellp->modp() && cellp->modp()->origName() == ident; 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; 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 modp->origName() == ident;
}
return false; return false;
} }
static string dumpvarsResolvedPath(VSymEnt* symp) { 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; string path;
for (const string& piece : pieces) { for (VSymEnt* walkp = symp; walkp && walkp->parentp(); walkp = walkp->parentp()) {
if (!path.empty()) path += '.'; const AstNode* const np = walkp->nodep();
path += piece; 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; 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) { static string dumpvarsBracketToInternal(const string& ident) {
const string::size_type lbr = ident.find('['); const string::size_type lbr = ident.find('[');
if (lbr == string::npos) return ident; if (lbr == string::npos) return ident;
const string::size_type rbr = ident.find(']', lbr); const string::size_type rbr = ident.find(']', lbr);
if (rbr == string::npos) return ident; if (rbr == string::npos) return ident;
return ident.substr(0, lbr) + "__BRA__" + ident.substr(lbr + 1, rbr - lbr - 1) return ident.substr(0, lbr) + "__BRA__" + ident.substr(lbr + 1, rbr - lbr - 1) + "__KET__"
+ "__KET__" + dumpvarsBracketToInternal(ident.substr(rbr + 1)); + dumpvarsBracketToInternal(ident.substr(rbr + 1));
} }
VSymEnt* findDumpvarsLocal(FileLine* refLocationp, const string& dotname, string& baddot, VSymEnt* findDumpvarsLocal(FileLine* refLocationp, const string& dotname, string& baddot,
VSymEnt*& okSymp) { VSymEnt*& okSymp) {
if (!m_curSymp) return nullptr; if (!m_curSymp) return nullptr;
string leftname = dotname; const string::size_type dotPos = dotname.find('.');
string::size_type pos; const string ident = dotPos == string::npos ? dotname : dotname.substr(0, dotPos);
string ident; const string leftname = dotPos == string::npos ? "" : dotname.substr(dotPos + 1);
if ((pos = leftname.find('.')) != string::npos) {
ident = leftname.substr(0, pos);
leftname = leftname.substr(pos + 1);
} else {
ident = leftname;
leftname = "";
}
baddot = ident; baddot = ident;
okSymp = m_curSymp; 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; const auto findLocal = [&](const string& name) -> VSymEnt* {
if (dumpvarsMatchesLocalModule(m_curSymp, ident)) { if (dumpvarsMatchesLocalModule(m_curSymp, name)) return m_curSymp;
symp = m_curSymp; if (VSymEnt* const symp = m_curSymp->findIdFallback(name)) return symp;
} else { const string internal = dumpvarsBracketToInternal(name);
symp = m_curSymp->findIdFallback(ident); if (internal != name) {
if (!symp && ident.find('[') != string::npos) if (VSymEnt* const symp = m_curSymp->findIdFallback(internal)) return symp;
symp = m_curSymp->findIdFallback(dumpvarsBracketToInternal(ident)); }
if (!symp && !altIdent.empty()) symp = m_curSymp->findIdFallback(altIdent); 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 (!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 symp;
} }
return m_statep->findDotted(refLocationp, symp, leftname, baddot, okSymp, false); 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; if (target.empty() || !m_curSymp) return target;
string baddot; 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, okSymp)) return target;
if (findDumpvarsLocal(fl, target, baddot, matchSymp)) return target;
// Step 2: Try global lookup from $root. if (VSymEnt* const rootSymp = findFromRoot(target)) {
if (VSymEnt* const rootSymp = m_statep->findDotted(
fl, m_statep->rootEntp(), target, baddot, matchSymp, true)) {
const string resolved = dumpvarsResolvedPath(rootSymp); const string resolved = dumpvarsResolvedPath(rootSymp);
if (!resolved.empty()) return kDumpvarsResolved.make(resolved); 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::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) { const string firstComp = target.substr(0, dotPos);
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 remaining = target.substr(dotPos + 1); const string remaining = target.substr(dotPos + 1);
bool hasBareFirstComp = false;
// With --main, if the first component matches the local module, for (AstNode* tp = targetsp; tp; tp = tp->nextp()) {
// walk the remaining path through cell scopes to validate it. if (dumpvarsTargetText(tp) == firstComp) {
if (!dumpvarsHasBareTarget(targetsp, firstComp) && v3Global.opt.main() hasBareFirstComp = true;
&& dumpvarsMatchesLocalModule(m_curSymp, firstComp)) { break;
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;
} }
}
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; return target;
} }
if (dumpvarsHasBareTarget(targetsp, firstComp)) { if (findDumpvarsLocal(fl, firstComp, baddot, okSymp)
string runtimeBaddot; && !(VN_IS(okSymp->nodep(), Cell) || VN_IS(okSymp->nodep(), CellInline)
VSymEnt* runtimeMatchSymp = nullptr; || VN_IS(okSymp->nodep(), NodeModule))) {
if (m_statep->findDotted(fl, m_statep->rootEntp(), remaining, runtimeBaddot,
runtimeMatchSymp, true)) {
return kDumpvarsRuntimeRoot.make(target);
}
fl->v3error("$dumpvars target not found: " << target);
return target; return target;
} }
string localBaddot; return v3Global.opt.main() ? fail() : kDumpvarsRuntimeRoot.make(target);
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);
} }
// METHODS - Variables // METHODS - Variables