summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2016-11-05 09:27:46 +0100
committerAraq <rumpf_a@web.de>2016-11-05 09:27:46 +0100
commit8fa3e0cb25c7fec8ea727270dec7700a2ec271e5 (patch)
tree361ddb292fc5115756f24fef9bffeab978352925
parent9e6fb3f696b2d28f900506b531a916457b4a263c (diff)
downloadNim-8fa3e0cb25c7fec8ea727270dec7700a2ec271e5.tar.gz
added missing module
-rw-r--r--compiler/modulegraphs.nim92
1 files changed, 92 insertions, 0 deletions
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
new file mode 100644
index 000000000..2c1671789
--- /dev/null
+++ b/compiler/modulegraphs.nim
@@ -0,0 +1,92 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2016 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the module graph data structure. The module graph
+## represents a complete Nim project. Single modules can either be kept in RAM
+## or stored in a ROD file. The ROD file mechanism is not yet integrated here.
+##
+## The caching of modules is critical for 'nimsuggest' and is tricky to get
+## right. If module E is being edited, we need autocompletion (and type
+## checking) for E but we don't want to recompile depending
+## modules right away for faster turnaround times. Instead we mark the module's
+## dependencies as 'dirty'. Let D be a dependency of E. If D is dirty, we
+## need to recompile it and all of its dependencies that are marked as 'dirty'.
+## 'nimsuggest sug' actually is invoked for the file being edited so we know
+## its content changed and there is no need to compute any checksums.
+## Instead of a recursive algorithm, we use an iterative algorithm:
+##
+## - If a module gets recompiled, its dependencies need to be updated.
+## - Its dependent module stays the same.
+##
+
+import ast, intsets
+
+type
+  ModuleGraph* = ref object
+    modules*: seq[PSym]  ## indexed by int32 fileIdx
+    packageSyms*: TStrTable
+    deps*: IntSet # the dependency graph or potentially its transitive closure.
+    suggestMode*: bool # whether we are in nimsuggest mode or not.
+    invalidTransitiveClosure: bool
+
+{.this: g.}
+
+proc newModuleGraph*(): ModuleGraph =
+  result = ModuleGraph()
+  initStrTable(result.packageSyms)
+  result.deps = initIntSet()
+  result.modules = @[]
+
+proc resetAllModules*(g: ModuleGraph) =
+  initStrTable(packageSyms)
+  deps = initIntSet()
+  modules = @[]
+
+proc getModule*(g: ModuleGraph; fileIdx: int32): PSym =
+  if fileIdx >= 0 and fileIdx < modules.len:
+    result = modules[fileIdx]
+
+proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
+
+proc addDep*(g: ModuleGraph; m: PSym, dep: int32) =
+  if suggestMode:
+    deps.incl m.position.dependsOn(dep)
+    # we compute the transitive closure later when quering the graph lazily.
+    # this improve efficiency quite a lot:
+    invalidTransitiveClosure = true
+
+proc transitiveClosure(g: var IntSet; n: int) =
+  # warshall's algorithm
+  for k in 0..<n:
+    for i in 0..<n:
+      for j in 0..<n:
+        if i != j and not g.contains(i.dependsOn(j)):
+          if g.contains(i.dependsOn(k)) and g.contains(k.dependsOn(j)):
+            g.incl i.dependsOn(j)
+
+proc markDirty*(g: ModuleGraph; fileIdx: int32) =
+  let m = getModule fileIdx
+  if m != nil: incl m.flags, sfDirty
+
+proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) =
+  # we need to mark its dependent modules D as dirty right away because after
+  # nimsuggest is done with this module, the module's dirty flag will be
+  # cleared but D still needs to be remembered as 'dirty'.
+  if invalidTransitiveClosure:
+    invalidTransitiveClosure = false
+    transitiveClosure(deps, modules.len)
+
+  # every module that *depends* on this file is also dirty:
+  for i in 0i32..<modules.len.int32:
+    let m = modules[i]
+    if m != nil and deps.contains(i.dependsOn(fileIdx)):
+      incl m.flags, sfDirty
+
+proc isDirty*(g: ModuleGraph; m: PSym): bool =
+  result = suggestMode and sfDirty in m.flags