import intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils, sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables type DepN = ref object pnode: PNode id, idx, lowLink: int onStack: bool kids: seq[DepN] hAQ, hIS, hB, hCmd: int when not defined(release): expls: seq[string] DepG = seq[DepN] when not defined(release): var idNames = newTable[int, string]() proc newDepN(id: int, pnode: PNode): DepN = new(result) result.id = id result.pnode = pnode result.idx = -1 result.lowLink = -1 result.onStack = false result.kids = @[] result.hAQ = -1 result.hIS = -1 result.hB = -1 result.hCmd = -1 when not defined(release): result.expls = @[] proc accQuoted(n: PNode): PIdent = var id = "" for i in 0 ..< n.len: let x = n[i] case x.kind of nkIdent: id.add(x.ident.s) of nkSym: id.add(x.sym.name.s) else: discard result = getIdent(id) proc addDecl(n: PNode; declares: var IntSet) = case n.kind of nkPostfix: addDecl(n[1], declares) of nkPragmaExpr: addDecl(n[0], declares) of nkIdent: declares.incl n.ident.id when not defined(release): idNames[n.ident.id] = n.ident.s of nkSym: declares.incl n.sym.name.id when not defined(release): idNames[n.sym.name.id] = n.sym.name.s of nkAccQuoted: let a = accQuoted(n) declares.incl a.id when not defined(release): idNames[a.id] = a.s of nkEnumFieldDef: addDecl(n[0], declares) else: discard proc computeDeps(n: PNode, declares, uses: var IntSet; topLevel: bool) = template deps(n) = computeDeps(n, declares, uses, false) template decl(n) = if topLevel: addDecl(n, declares) case n.kind of procDefs, nkMacroDef, nkTemplateDef: decl(n[0]) for i in 1..bodyPos: deps(n[i]) of nkLetSection, nkVarSection, nkUsingStmt: for a in n: if a.kind in {nkIdentDefs, nkVarTuple}: for j in countup(0, a.len-3): decl(a[j]) for j in a.len-2..a.len-1: deps(a[j]) of nkConstSection, nkTypeSection: for a in n: if a.len >= 3: decl(a[0]) for i in 1.. 0 if nb == 1: return parts[0] result = parts[0] / parts[1] for i in 2.. 1: for b in a: var s = newNode(a.kind) s.info = b.info s.add b result.add s else: result.add a proc haveSameKind(dns: seq[DepN]): bool = # Check if all the nodes in a strongly connected # component have the same kind result = true let kind = dns[0].pnode.kind for dn in dns: if dn.pnode.kind != kind: return false proc mergeSections(comps: seq[seq[DepN]], res: PNode) = # Merges typeSections and ConstSections when they form # a strong component (ex: circular type definition) for c in comps: assert c.len > 0 if c.len == 1: res.add c[0].pnode else: let fstn = c[0].pnode let kind = fstn.kind # always return to the original order when we got circular dependencies let cs = c.sortedByIt(it.id) if kind in {nkTypeSection, nkConstSection} and haveSameKind(cs): # Circular dependency between type or const sections, we just # need to merge them var sn = newNode(kind) for dn in cs: sn.add dn.pnode.sons[0] res.add sn else: # Problematic circular dependency, we arrange the nodes into # their original relative order and make sure to re-merge # consecutive type and const sections var wmsg = "Circular dependency detected. reorder pragma may not be able to" & " reorder some nodes properely" when not defined(release): wmsg &= ":\n" for i in 0..