summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2013-05-04 23:02:03 +0300
committerZahary Karadjov <zahary@gmail.com>2013-05-04 23:02:03 +0300
commit519d5b834ad9601c487b4cc183f80b713e2da53f (patch)
tree3155f9976a7ead7a265d18f1c3b5335921d95dc3
parent34cd22ba72e6b93b4f095d6424206627137d0ec6 (diff)
downloadNim-519d5b834ad9601c487b4cc183f80b713e2da53f.tar.gz
experimental support for answering idetools --def requests from
an in-memory index built during compilation in caas mode
-rw-r--r--compiler/commands.nim3
-rw-r--r--compiler/main.nim20
-rw-r--r--compiler/msgs.nim1
-rw-r--r--compiler/suggest.nim58
4 files changed, 72 insertions, 10 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 27da03bbe..de52a4062 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -215,7 +215,8 @@ proc track(arg: string, info: TLineInfo) =
     LocalError(info, errInvalidNumber, a[1])
   if parseUtils.parseInt(a[2], column) <= 0:
     LocalError(info, errInvalidNumber, a[2])
-  msgs.addCheckpoint(newLineInfo(a[0], line, column))
+  optTrackPos = newLineInfo(a[0], line, column)
+  msgs.addCheckpoint(optTrackPos)
 
 proc dynlibOverride(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
   if pass in {passCmd2, passPP}:
diff --git a/compiler/main.nim b/compiler/main.nim
index 46ef65e81..6e3b1a352 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -16,7 +16,7 @@ import
   wordrecg, sem, semdata, idents, passes, docgen, extccomp,
   cgen, jsgen, cgendata, json, nversion,
   platform, nimconf, importer, passaux, depends, evals, types, idgen,
-  tables, docgen2, service, magicsys, parser, crc, ccgutils
+  tables, docgen2, service, magicsys, parser, crc, ccgutils, sigmatch
 
 const
   has_LLVM_Backend = false
@@ -64,7 +64,7 @@ proc crcChanged(fileIdx: int32): bool =
     gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
                                        else: crcNotChanged
     # echo "TESTING CRC: ", fileIdx.toFilename, " ", result
-    
+  
   case gMemCacheData[fileIdx].crcStatus:
   of crcHasChanged:
     result = true
@@ -90,18 +90,19 @@ proc addDep(x: Psym, dep: int32) =
   gMemCacheData[x.position].deps.safeAdd(dep)
 
 proc ResetModule(fileIdx: int32) =
-  echo "HARD RESETTING ", fileIdx.toFilename
+  writeStackTrace()
+  # echo "HARD RESETTING ", fileIdx.toFilename
   gMemCacheData[fileIdx].needsRecompile = Yes
   gCompiledModules[fileIdx] = nil
   cgendata.gModules[fileIdx] = nil
+  resetSourceMap(fileIdx)
 
 proc ResetAllModules =
   for i in 0..gCompiledModules.high:
     if gCompiledModules[i] != nil:
       ResetModule(i.int32)
 
-  for m in cgenModules():
-    echo "CGEN MODULE FOUND"
+  # for m in cgenModules(): echo "CGEN MODULE FOUND"
 
 proc checkDepMem(fileIdx: int32): TNeedRecompile  =
   template markDirty =
@@ -112,15 +113,15 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile  =
     return gMemCacheData[fileIdx].needsRecompile
 
   if optForceFullMake in gGlobalOptions or
-     curCaasCmd != lastCaasCmd or
-     crcChanged(fileIdx): markDirty
+     crcChanged(fileIdx):
+       markDirty
   
   if gMemCacheData[fileIdx].deps != nil:
     gMemCacheData[fileIdx].needsRecompile = Probing
     for dep in gMemCacheData[fileIdx].deps:
       let d = checkDepMem(dep)
       if d in { Yes, Recompiled }:
-        echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
+        # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
         markDirty
   
   gMemCacheData[fileIdx].needsRecompile = No
@@ -381,6 +382,9 @@ proc CommandSuggest =
   semanticPasses()
   rodPass()
   compileProject()
+  if isServing:
+    if optDef in gGlobalOptions:
+      defFromSourceMap(optTrackPos)
 
 proc wantMainModule =
   if gProjectFull.len == 0:
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 6062ebd7f..a1eaf23bb 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -606,6 +606,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
   result = filename in info.toFilename
 
 var checkPoints*: seq[TLineInfo] = @[]
+var optTrackPos*: TLineInfo
 
 proc addCheckpoint*(info: TLineInfo) = 
   checkPoints.add(info)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 130666f4d..273347ef3 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -9,7 +9,9 @@
 
 ## This file implements features required for IDE support.
 
-# imported from sigmatch.nim
+# included from sigmatch.nim
+
+import algorithm
 
 const
   sep = '\t'
@@ -238,12 +240,66 @@ proc findDefinition(node: PNode, s: PSym) =
     SuggestWriteln(SymToStr(s, isLocal=false, sectionDef))
     SuggestQuit()
 
+type
+  TSourceMap = object
+    lines: seq[TLineMap]
+  
+  TEntry = object
+    pos: int
+    sym: PSym
+
+  TLineMap = object
+    entries: seq[TEntry]
+
+var
+  gSourceMaps: seq[TSourceMap] = @[]
+
+proc ensureIdx[T](x: var T, y: int) =
+  if x.len <= y: x.setLen(y+1)
+
+proc ensureSeq[T](x: var seq[T]) =
+  if x == nil: newSeq(x, 0)
+
+proc resetSourceMap*(fileIdx: int32) =
+  ensureIdx(gSourceMaps, fileIdx)
+  gSourceMaps[fileIdx].lines = @[]
+
+proc addToSourceMap(sym: Psym, info: TLineInfo) =
+  ensureIdx(gSourceMaps, info.fileIndex)
+  ensureSeq(gSourceMaps[info.fileIndex].lines)
+  ensureIdx(gSourceMaps[info.fileIndex].lines, info.line)
+  ensureSeq(gSourceMaps[info.fileIndex].lines[info.line].entries)
+  gSourceMaps[info.fileIndex].lines[info.line].entries.add(TEntry(pos: info.col, sym: sym))
+
+proc defFromLine(entries: var seq[TEntry], col: int32) =
+  # The sorting is done lazily here on purpose.
+  # No need to pay the price for it unless the user requests
+  # "goto definition" on a particular line
+  sort(entries) do (a,b: TEntry) -> int:
+    return cmp(a.pos, b.pos)
+  
+  for e in entries:
+    # currently, the line-infos for most expressions point to
+    # one position past the end of the expression. This means
+    # that the first expr that ends after the cursor column is
+    # the one we are looking for.
+    if e.pos >= col:
+      SuggestWriteln(SymToStr(e.sym, isLocal=false, sectionDef))
+      return
+
+proc defFromSourceMap*(i: TLineInfo) =
+  InternalAssert i.fileIndex < gSourceMaps.len and 
+                 i.line < gSourceMaps[i.fileIndex].lines.len
+  defFromLine(gSourceMaps[i.fileIndex].lines[i.line].entries, i.col)
+
 proc suggestSym*(n: PNode, s: PSym) {.inline.} =
   ## misnamed: should be 'symDeclared'
   if optUsages in gGlobalOptions:
     findUsages(n, s)
   if optDef in gGlobalOptions:
     findDefinition(n, s)
+  if isServing:
+    addToSourceMap(s, n.info)
 
 proc markUsed(n: PNode, s: PSym) =
   incl(s.flags, sfUsed)