From a28732ccf96487d1401daae0f9ab4033322d0f44 Mon Sep 17 00:00:00 2001 From: wsxarcher Date: Wed, 25 Mar 2026 01:41:50 +0100 Subject: [PATCH] Simplify V3LinkDot --- src/V3LinkDot.cpp | 220 +++++++++++++++------------------------------- 1 file changed, 70 insertions(+), 150 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7ccfbd6ce..e94bcc3f5 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -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 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