summary refs log tree commit diff stats
path: root/compiler/reorder.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/reorder.nim')
-rw-r--r--compiler/reorder.nim124
1 files changed, 58 insertions, 66 deletions
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index 28e12ca2a..2f7c04af1 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -1,9 +1,17 @@
 
 import
-  intsets, ast, idents, algorithm, renderer, os, strutils,
+  ast, idents, renderer,
   msgs, modulegraphs, syntaxes, options, modulepaths,
   lineinfos
 
+import std/[algorithm, strutils, intsets]
+
+when defined(nimPreviewSlimSystem):
+  import std/assertions
+
+when defined(nimDebugReorder):
+  import std/tables
+
 type
   DepN = ref object
     pnode: PNode
@@ -11,36 +19,27 @@ type
     onStack: bool
     kids: seq[DepN]
     hAQ, hIS, hB, hCmd: int
-    when defined(debugReorder):
+    when defined(nimDebugReorder):
       expls: seq[string]
   DepG = seq[DepN]
 
-when defined(debugReorder):
+when defined(nimDebugReorder):
   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 defined(debugReorder):
+  result = DepN(id: id, pnode: pnode, idx: -1,
+                lowLink: -1, onStack: false,
+                kids: @[], hAQ: -1, hIS: -1,
+                hB: -1, hCmd: -1
+  )
+  when defined(nimDebugReorder):
     result.expls = @[]
 
 proc accQuoted(cache: IdentCache; 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
+    let ident = n[i].getPIdent
+    if ident != nil: id.add(ident.s)
   result = getIdent(cache, id)
 
 proc addDecl(cache: IdentCache; n: PNode; declares: var IntSet) =
@@ -49,16 +48,16 @@ proc addDecl(cache: IdentCache; n: PNode; declares: var IntSet) =
   of nkPragmaExpr: addDecl(cache, n[0], declares)
   of nkIdent:
     declares.incl n.ident.id
-    when defined(debugReorder):
+    when defined(nimDebugReorder):
       idNames[n.ident.id] = n.ident.s
   of nkSym:
     declares.incl n.sym.name.id
-    when defined(debugReorder):
+    when defined(nimDebugReorder):
       idNames[n.sym.name.id] = n.sym.name.s
   of nkAccQuoted:
     let a = accQuoted(cache, n)
     declares.incl a.id
-    when defined(debugReorder):
+    when defined(nimDebugReorder):
       idNames[a.id] = a.s
   of nkEnumFieldDef:
     addDecl(cache, n[0], declares)
@@ -103,34 +102,16 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
     if a.kind == nkExprColonExpr and a[0].kind == nkIdent and a[0].ident.s == "pragma":
       # user defined pragma
       decl(a[1])
+      for i in 1..<n.safeLen: deps(n[i])
     else:
       for i in 0..<n.safeLen: deps(n[i])
+  of nkMixinStmt, nkBindStmt: discard
   else:
+    # XXX: for callables, this technically adds the return type dep before args
     for i in 0..<n.safeLen: deps(n[i])
 
-proc cleanPath(s: string): string =
-  # Here paths may have the form A / B or "A/B"
-  result = ""
-  for c in s:
-    if c != ' ' and c != '\"':
-      result.add c
-
-proc joinPath(parts: seq[string]): string =
-  let nb = parts.len
-  assert nb > 0
-  if nb == 1:
-    return parts[0]
-  result = parts[0] / parts[1]
-  for i in 2..<parts.len:
-    result = result / parts[i]
-
-proc getIncludePath(n: PNode, modulePath: string): string =
-  let istr = n.renderTree.cleanPath
-  let (pdir, _) = modulePath.splitPath
-  let p = istr.split('/').joinPath.addFileExt("nim")
-  result = pdir / p
-
-proc hasIncludes(n:PNode): bool =
+proc hasIncludes(n: PNode): bool =
+  result = false
   for a in n:
     if a.kind == nkIncludeStmt:
       return true
@@ -212,8 +193,8 @@ proc mergeSections(conf: ConfigRef; comps: seq[seq[DepN]], res: PNode) =
         # their original relative order and make sure to re-merge
         # consecutive type and const sections
         var wmsg = "Circular dependency detected. `codeReordering` pragma may not be able to" &
-          " reorder some nodes properely"
-        when defined(debugReorder):
+          " reorder some nodes properly"
+        when defined(nimDebugReorder):
           wmsg &= ":\n"
           for i in 0..<cs.len-1:
             for j in i..<cs.len:
@@ -250,8 +231,9 @@ proc hasImportStmt(n: PNode): bool =
   # i it contains one
   case n.kind
   of nkImportStmt, nkFromStmt, nkImportExceptStmt:
-    return true
+    result = true
   of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
+    result = false
     for a in n:
       if a.hasImportStmt:
         return true
@@ -272,6 +254,7 @@ proc hasCommand(n: PNode): bool =
   of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse,
       nkStaticStmt, nkLetSection, nkConstSection, nkVarSection,
       nkIdentDefs:
+    result = false
     for a in n:
       if a.hasCommand:
         return true
@@ -284,6 +267,7 @@ proc hasCommand(n: DepN): bool =
   result = bool(n.hCmd)
 
 proc hasAccQuoted(n: PNode): bool =
+  result = false
   if n.kind == nkAccQuoted:
     return true
   for a in n:
@@ -299,6 +283,7 @@ proc hasAccQuotedDef(n: PNode): bool =
   of extendedProcDefs:
     result = n[0].hasAccQuoted
   of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
+    result = false
     for a in n:
       if hasAccQuotedDef(a):
         return true
@@ -319,6 +304,7 @@ proc hasBody(n: PNode): bool =
   of extendedProcDefs:
     result = n[^1].kind == nkStmtList
   of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
+    result = false
     for a in n:
       if a.hasBody:
         return true
@@ -331,10 +317,19 @@ proc hasBody(n: DepN): bool =
   result = bool(n.hB)
 
 proc intersects(s1, s2: IntSet): bool =
+  result = false
   for a in s1:
     if s2.contains(a):
       return true
 
+proc hasPushOrPopPragma(n: DepN): bool =
+  # Checks if the tree node has some pragmas that do not
+  # play well with reordering, like the push/pop pragma
+  # no crossing for push/pop barrier
+  let a = n.pnode
+  result = a.kind == nkPragma and a[0].kind == nkIdent and
+      (a[0].ident.s == "push" or a[0].ident.s == "pop")
+
 proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
   # Build a dependency graph
   result = newSeqOfCap[DepN](deps.len)
@@ -352,13 +347,13 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
       if j < i and nj.hasCommand and niHasCmd:
         # Preserve order for commands and calls
         ni.kids.add nj
-        when defined(debugReorder):
+        when defined(nimDebugReorder):
           ni.expls.add "both have commands and one comes after the other"
       elif j < i and nj.hasImportStmt:
         # Every node that comes after an import statement must
         # depend on that import
         ni.kids.add nj
-        when defined(debugReorder):
+        when defined(nimDebugReorder):
           ni.expls.add "parent is, or contains, an import statement and child comes after it"
       elif j < i and niHasBody and nj.hasAccQuotedDef:
         # Every function, macro, template... with a body depends
@@ -366,21 +361,28 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
         # That's because it is hard to detect the use of functions
         # like "[]=", "[]", "or" ... in their bodies.
         ni.kids.add nj
-        when defined(debugReorder):
+        when defined(nimDebugReorder):
           ni.expls.add "one declares a quoted identifier and the other has a body and comes after it"
       elif j < i and niHasBody and not nj.hasBody and
         intersects(deps[i][0], declares):
           # Keep function declaration before function definition
           ni.kids.add nj
-          when defined(debugReorder):
+          when defined(nimDebugReorder):
             for dep in deps[i][0]:
               if dep in declares:
                 ni.expls.add "one declares \"" & idNames[dep] & "\" and the other defines it"
+      elif hasPushOrPopPragma(nj):
+        # Every node that comes after a push/pop pragma must
+        # depend on it; vice versa
+        if j < i:
+          ni.kids.add nj
+        else:
+          nj.kids.add ni
       else:
         for d in declares:
           if uses.contains(d):
             ni.kids.add nj
-            when defined(debugReorder):
+            when defined(nimDebugReorder):
               ni.expls.add "one declares \"" & idNames[d] & "\" and the other uses it"
 
 proc strongConnect(v: var DepN, idx: var int, s: var seq[DepN],
@@ -409,24 +411,14 @@ proc strongConnect(v: var DepN, idx: var int, s: var seq[DepN],
 proc getStrongComponents(g: var DepG): seq[seq[DepN]] =
   ## Tarjan's algorithm. Performs a topological sort
   ## and detects strongly connected components.
-  result = newSeq[seq[DepN]]()
-  var s = newSeq[DepN]()
+  result = @[]
+  var s: seq[DepN] = @[]
   var idx = 0
   for v in g.mitems:
     if v.idx < 0:
       strongConnect(v, idx, s, result)
 
-proc hasForbiddenPragma(n: PNode): bool =
-  # Checks if the tree node has some pragmas that do not
-  # play well with reordering, like the push/pop pragma
-  for a in n:
-    if a.kind == nkPragma and a[0].kind == nkIdent and
-        a[0].ident.s == "push":
-      return true
-
 proc reorder*(graph: ModuleGraph, n: PNode, module: PSym): PNode =
-  if n.hasForbiddenPragma:
-    return n
   var includedFiles = initIntSet()
   let mpath = toFullPath(graph.config, module.fileIdx)
   let n = expandIncludes(graph, module, n, mpath,