summary refs log tree commit diff stats
path: root/compiler/incremental.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/incremental.nim')
-rw-r--r--compiler/incremental.nim188
1 files changed, 188 insertions, 0 deletions
diff --git a/compiler/incremental.nim b/compiler/incremental.nim
new file mode 100644
index 000000000..69dfb727e
--- /dev/null
+++ b/compiler/incremental.nim
@@ -0,0 +1,188 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2018 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Basic type definitions the module graph needs in order to support
+## incremental compilations.
+
+const nimIncremental* = defined(nimIncremental)
+
+import options, lineinfos
+
+when nimIncremental:
+  import ast, intsets, btrees, db_sqlite
+
+  type
+    Writer* = object
+      sstack*: seq[PSym]          # a stack of symbols to process
+      tstack*: seq[PType]         # a stack of types to process
+      tmarks*, smarks*: IntSet
+      forwardedSyms*: seq[PSym]
+
+    Reader* = object
+      syms*: BTree[int, PSym]
+      types*: BTree[int, PType]
+
+    IncrementalCtx* = object
+      db*: DbConn
+      w*: Writer
+      r*: Reader
+
+  proc init*(incr: var IncrementalCtx) =
+    incr.w.sstack = @[]
+    incr.w.tstack = @[]
+    incr.w.tmarks = initIntSet()
+    incr.w.smarks = initIntSet()
+    incr.w.forwardedSyms = @[]
+    incr.r.syms = initBTree[int, PSym]()
+    incr.r.types = initBTree[int, PType]()
+
+
+  proc hashFileCached*(conf: ConfigRef; fileIdx: FileIndex; fullpath: string): string =
+    result = msgs.getHash(fileIdx)
+    if result.len == 0:
+      result = $secureHashFile(fullpath)
+      msgs.setHash(fileIdx, result)
+
+
+  proc toDbFileId*(fileIdx: int32): int =
+    if fileIdx == -1: return -1
+    let fullpath = fileIdx.toFullPath
+    let row = db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
+      fullpath)
+    let id = row[0]
+    let fullhash = hashFileCached(fileIdx, fullpath)
+    if id.len == 0:
+      result = int db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
+        fullpath, fullhash)
+    else:
+      if row[1] != fullhash:
+        db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
+      result = parseInt(id)
+
+  proc fromDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; dbId: int): FileIndex =
+    if dbId == -1: return -1
+    let fullpath = db.getValue(sql"select fullpath from filenames where id = ?", dbId)
+    doAssert fullpath.len > 0, "cannot find file name for DB ID " & $dbId
+    result = fileInfoIdx(conf, fullpath)
+
+
+  proc addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef;
+                     module, fileIdx: FileIndex;
+                     isIncludeFile: bool) =
+    if conf.symbolFiles != v2Sf: return
+
+    let a = toDbFileId(incr, conf, module)
+    let b = toDbFileId(incr, conf, fileIdx)
+
+    incr.db.exec(sql"insert into deps(module, dependency, isIncludeFile) values (?, ?, ?)",
+      a, b, ord(isIncludeFile))
+
+  # --------------- Database model ---------------------------------------------
+
+  proc createDb*(db: DbConn) =
+    db.exec(sql"""
+      create table if not exists controlblock(
+        idgen integer not null
+      );
+    """)
+
+    db.exec(sql"""
+      create table if not exists filenames(
+        id integer primary key,
+        fullpath varchar(8000) not null,
+        fullHash varchar(256) not null
+      );
+    """)
+    db.exec sql"create index if not exists FilenameIx on filenames(fullpath);"
+
+    db.exec(sql"""
+      create table if not exists modules(
+        id integer primary key,
+        fullpath varchar(8000) not null,
+        interfHash varchar(256) not null,
+        fullHash varchar(256) not null,
+
+        created timestamp not null default (DATETIME('now'))
+      );""")
+    db.exec(sql"""create unique index if not exists SymNameIx on modules(fullpath);""")
+
+    db.exec(sql"""
+      create table if not exists deps(
+        id integer primary key,
+        module integer not null,
+        dependency integer not null,
+        isIncludeFile integer not null,
+        foreign key (module) references filenames(id),
+        foreign key (dependency) references filenames(id)
+      );""")
+    db.exec(sql"""create index if not exists DepsIx on deps(module);""")
+
+    db.exec(sql"""
+      create table if not exists types(
+        id integer primary key,
+        nimid integer not null,
+        module integer not null,
+        data blob not null,
+        foreign key (module) references module(id)
+      );
+    """)
+    db.exec sql"create index TypeByModuleIdx on types(module);"
+    db.exec sql"create index TypeByNimIdIdx on types(nimid);"
+
+    db.exec(sql"""
+      create table if not exists syms(
+        id integer primary key,
+        nimid integer not null,
+        module integer not null,
+        name varchar(256) not null,
+        data blob not null,
+        exported int not null,
+        foreign key (module) references module(id)
+      );
+    """)
+    db.exec sql"create index if not exists SymNameIx on syms(name);"
+    db.exec sql"create index SymByNameAndModuleIdx on syms(name, module);"
+    db.exec sql"create index SymByModuleIdx on syms(module);"
+    db.exec sql"create index SymByNimIdIdx on syms(nimid);"
+
+
+    db.exec(sql"""
+      create table if not exists toplevelstmts(
+        id integer primary key,
+        position integer not null,
+        module integer not null,
+        data blob not null,
+        foreign key (module) references module(id)
+      );
+    """)
+    db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);"
+    db.exec sql"create index TopLevelStmtByPositionIdx on toplevelstmts(position);"
+
+    db.exec(sql"""
+      create table if not exists statics(
+        id integer primary key,
+        module integer not null,
+        data blob not null,
+        foreign key (module) references module(id)
+      );
+    """)
+    db.exec sql"create index StaticsByModuleIdx on toplevelstmts(module);"
+    db.exec sql"insert into controlblock(idgen) values (0)"
+
+
+else:
+  type
+    IncrementalCtx* = object
+
+  template init*(incr: IncrementalCtx) = discard
+
+  template addModuleDep*(incr: var IncrementalCtx; conf: ConfigRef;
+                     module, fileIdx: FileIndex;
+                     isIncludeFile: bool) =
+    discard