summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-07-29 02:45:50 +0200
committerAraq <rumpf_a@web.de>2012-07-29 02:45:50 +0200
commit087b8621d32b65dde4a39952c0a53bbf5cc57414 (patch)
tree6833af36f7e394ba80ffcbac5cb41f6e898da77a
parent48e95fe9f9ce1a412e7fddc8293a2b1db7f46bbd (diff)
downloadNim-087b8621d32b65dde4a39952c0a53bbf5cc57414.tar.gz
improvements for idetools; system.compiles improved
-rwxr-xr-xcompiler/lookups.nim7
-rwxr-xr-xcompiler/msgs.nim3
-rwxr-xr-xcompiler/sem.nim3
-rwxr-xr-xcompiler/semdata.nim32
-rwxr-xr-xcompiler/semexprs.nim14
-rwxr-xr-xcompiler/suggest.nim73
-rwxr-xr-xtodo.txt1
7 files changed, 101 insertions, 32 deletions
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index b26ac808e..0ad1c7f01 100755
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -58,9 +58,14 @@ proc CloseScope*(tab: var TSymTab) =
   if tab.tos > len(tab.stack): InternalError("CloseScope")
   var it: TTabIter
   var s = InitTabIter(it, tab.stack[tab.tos-1])
+  var missingImpls = 0
   while s != nil:
     if sfForward in s.flags:
-      LocalError(s.info, errImplOfXexpected, getSymRepr(s))
+      # too many 'implementation of X' errors are annoying
+      # and slow 'suggest' down:
+      if missingImpls == 0:
+        LocalError(s.info, errImplOfXexpected, getSymRepr(s))
+      inc missingImpls
     elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options: 
       # BUGFIX: check options in s!
       if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 034fd38d8..edcb66274 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -483,6 +483,9 @@ proc UnknownLineInfo*(): TLineInfo =
 var 
   msgContext: seq[TLineInfo] = @[]
 
+proc getInfoContextLen*(): int = return msgContext.len
+proc setInfoContextLen*(L: int) = setLen(msgContext, L)
+
 proc pushInfoContext*(info: TLineInfo) = 
   msgContext.add(info)
   
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 63e401108..904adf955 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -198,11 +198,14 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
   if msgs.gErrorMax <= 1:
     result = SemStmtAndGenerateGenerics(c, n)
   else:
+    let oldContextLen = msgs.getInfoContextLen()
     try:
       result = SemStmtAndGenerateGenerics(c, n)
     except ERecoverableError:
       RecoverContext(c)
       result = ast.emptyNode
+      msgs.setInfoContextLen(oldContextLen)
+      if gCmd == cmdIdeTools: findSuggest(c, n)
   
 proc checkThreads(c: PContext) =
   if not needsGlobalAnalysis(): return
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 76ceafecf..fb5b8075a 100755
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -78,11 +78,41 @@ type
 var
   gGenericsCache: PGenericsCache # save for modularity
 
-proc newGenericsCache: PGenericsCache =
+proc newGenericsCache*(): PGenericsCache =
   new(result)
   initIdTable(result.InstTypes)
   result.generics = @[]
 
+proc tempContext*(c: PContext): PContext =
+  ## generates a temporary context so that side-effects can be rolled-back;
+  ## necessary for ``system.compiles``.
+  new(result)
+  result.module = c.module
+  result.p = c.p
+  # don't use the old cache:
+  result.generics = newGenericsCache()
+  result.friendModule = c.friendModule
+  result.InstCounter = c.InstCounter
+  result.threadEntries = @[]
+  # hrm, 'tab' is expensive to copy ... so we don't. We open a new scope
+  # instead to be able to undo scope changes. Not entirely correct for
+  # explicit 'global' vars though:
+  #shallowCopy(result.tab, c.tab)
+  assign(result.AmbiguousSymbols, c.AmbiguousSymbols)
+  result.InGenericContext = c.InGenericContext
+  result.InUnrolledContext = c.InUnrolledContext
+  result.InCompilesContext = c.InCompilesContext
+  result.converters = c.converters
+  result.semConstExpr = c.semConstExpr
+  result.semExpr = c.semExpr
+  result.semConstBoolExpr = c.semConstBoolExpr
+  assign(result.includedFiles, c.includedFiles) 
+  result.filename = c.filename
+  #shallowCopy(result.userPragmas, c.userPragmas) 
+  # XXX mark it as read-only:
+  result.evalContext = c.evalContext
+  
+
 proc newContext*(module: PSym, nimfile: string): PContext
 
 proc lastOptionEntry*(c: PContext): POptionEntry
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 0b07d84a9..fa39251e7 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1136,14 +1136,28 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # do not halt after first error:
   msgs.gErrorMax = high(int)
   
+  # open a scope for temporary symbol inclusions:
+  openScope(c.tab)
   let oldTos = c.tab.tos
   let oldOwnerLen = len(gOwners)
+  let oldGenerics = c.generics
+  let oldContextLen = msgs.getInfoContextLen()
+  
+  let oldInGenericContext = c.InGenericContext
+  let oldInUnrolledContext = c.InUnrolledContext
+  
+  c.generics = newGenericsCache()
   try:
     discard semExpr(c, n.sons[1])
     result.intVal = ord(msgs.gErrorCounter == oldErrorCount)
   except ERecoverableError:
     nil
   # undo symbol table changes (as far as it's possible):
+  closeScope(c.tab)
+  c.generics = oldGenerics
+  c.InGenericContext = oldInGenericContext
+  c.InUnrolledContext = oldInUnrolledContext
+  msgs.setInfoContextLen(oldContextLen)
   setlen(gOwners, oldOwnerLen)
   while c.tab.tos > oldTos: rawCloseScope(c.tab)
   dec c.InCompilesContext
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index ff1f9607f..e107730b8 100755
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -42,31 +42,33 @@ proc SymToStr(s: PSym, isLocal: bool, section: string): string =
 proc filterSym(s: PSym): bool {.inline.} = 
   result = s.name.s[0] in lexer.SymChars
 
-proc suggestField(s: PSym) = 
+proc suggestField(s: PSym, outputs: var int) = 
   if filterSym(s):
     OutWriteln(SymToStr(s, isLocal=true, sectionSuggest))
+    inc outputs
 
 template wholeSymTab(cond, section: expr) {.immediate.} = 
   for i in countdown(c.tab.tos-1, 0): 
     for it in items(c.tab.stack[i]): 
       if cond:
         OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section))
+        inc outputs
 
-proc suggestSymList(list: PNode) = 
+proc suggestSymList(list: PNode, outputs: var int) = 
   for i in countup(0, sonsLen(list) - 1): 
     if list.sons[i].kind != nkSym: InternalError(list.info, "getSymFromList")
-    suggestField(list.sons[i].sym)
+    suggestField(list.sons[i].sym, outputs)
 
-proc suggestObject(n: PNode) = 
+proc suggestObject(n: PNode, outputs: var int) = 
   case n.kind
   of nkRecList: 
-    for i in countup(0, sonsLen(n)-1): suggestObject(n.sons[i])
+    for i in countup(0, sonsLen(n)-1): suggestObject(n.sons[i], outputs)
   of nkRecCase: 
     var L = sonsLen(n)
     if L > 0:
-      suggestObject(n.sons[0])
-      for i in countup(1, L-1): suggestObject(lastSon(n.sons[i]))
-  of nkSym: suggestField(n.sym)
+      suggestObject(n.sons[0], outputs)
+      for i in countup(1, L-1): suggestObject(lastSon(n.sons[i]), outputs)
+  of nkSym: suggestField(n.sym, outputs)
   else: nil
 
 proc nameFits(c: PContext, s: PSym, n: PNode): bool = 
@@ -89,7 +91,7 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
   else:
     result = false
 
-proc suggestCall(c: PContext, n, nOrig: PNode) = 
+proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) = 
   wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
               sectionContext)
 
@@ -97,18 +99,19 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
   if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil:
     result = sigmatch.argtypeMatches(c, s.typ.sons[1], firstArg)
 
-proc suggestOperations(c: PContext, n: PNode, typ: PType) =
+proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) =
   assert typ != nil
   wholeSymTab(filterSym(it) and typeFits(c, it, typ), sectionSuggest)
 
-proc suggestEverything(c: PContext, n: PNode) =
+proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
   # do not produce too many symbols:
   for i in countdown(c.tab.tos-1, 1):
     for it in items(c.tab.stack[i]):
       if filterSym(it):
         OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, sectionSuggest))
+        inc outputs
 
-proc suggestFieldAccess(c: PContext, n: PNode) =
+proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
   # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
   # ``myObj``.
   var typ = n.Typ
@@ -120,34 +123,36 @@ proc suggestFieldAccess(c: PContext, n: PNode) =
         for it in items(c.tab.stack[ModuleTablePos]): 
           if filterSym(it): 
             OutWriteln(SymToStr(it, isLocal=false, sectionSuggest))
+            inc outputs
       else: 
         for it in items(n.sym.tab): 
           if filterSym(it): 
             OutWriteln(SymToStr(it, isLocal=false, sectionSuggest))
+            inc outputs
     else:
       # fallback:
-      suggestEverything(c, n)
+      suggestEverything(c, n, outputs)
   elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType: 
     # look up if the identifier belongs to the enum:
     var t = typ
     while t != nil: 
-      suggestSymList(t.n)
+      suggestSymList(t.n, outputs)
       t = t.sons[0]
-    suggestOperations(c, n, typ)
+    suggestOperations(c, n, typ, outputs)
   else:
     typ = skipTypes(typ, {tyGenericInst, tyVar, tyPtr, tyRef})
     if typ.kind == tyObject: 
       var t = typ
       while true: 
-        suggestObject(t.n)
+        suggestObject(t.n, outputs)
         if t.sons[0] == nil: break 
         t = skipTypes(t.sons[0], {tyGenericInst})
-      suggestOperations(c, n, typ)
+      suggestOperations(c, n, typ, outputs)
     elif typ.kind == tyTuple and typ.n != nil: 
-      suggestSymList(typ.n)
-      suggestOperations(c, n, typ)
+      suggestSymList(typ.n, outputs)
+      suggestOperations(c, n, typ, outputs)
     else:
-      suggestOperations(c, n, typ)
+      suggestOperations(c, n, typ, outputs)
 
 proc findClosestDot(n: PNode): PNode =
   if n.kind == nkDotExpr and msgs.inCheckpoint(n.info) == cpExact:
@@ -177,8 +182,6 @@ proc findClosestSym(n: PNode): PNode =
       result = findClosestSym(n.sons[i])
       if result != nil: return
 
-var recursiveCheck = 0
-
 proc safeSemExpr(c: PContext, n: PNode): PNode = 
   try:
     result = c.semExpr(c, n)
@@ -195,9 +198,10 @@ proc fuzzySemCheck(c: PContext, n: PNode): PNode =
 proc suggestExpr*(c: PContext, node: PNode) = 
   var cp = msgs.inCheckpoint(node.info)
   if cp == cpNone: return
-  # HACK: This keeps semExpr() from coming here recursively:
-  if recursiveCheck > 0: return
-  inc(recursiveCheck)
+  var outputs = 0
+  # This keeps semExpr() from coming here recursively:
+  if c.InCompilesContext > 0: return
+  inc(c.InCompilesContext)
   
   if optSuggest in gGlobalOptions:
     var n = findClosestDot(node)
@@ -206,9 +210,9 @@ proc suggestExpr*(c: PContext, node: PNode) =
     
     if n.kind == nkDotExpr and cp == cpExact:
       var obj = safeSemExpr(c, n.sons[0])
-      suggestFieldAccess(c, obj)
+      suggestFieldAccess(c, obj, outputs)
     else:
-      suggestEverything(c, n)
+      suggestEverything(c, n, outputs)
   
   if optContext in gGlobalOptions:
     var n = findClosestCall(node)
@@ -225,13 +229,22 @@ proc suggestExpr*(c: PContext, node: PNode) =
         var x = safeSemExpr(c, n.sons[i])
         if x.kind == nkEmpty or x.typ == nil: break
         addSon(a, x)
-      suggestCall(c, a, n)
+      suggestCall(c, a, n, outputs)
   
   if optDef in gGlobalOptions:
     var n = findClosestSym(fuzzySemCheck(c, node))
-    if n != nil: OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef))
-  quit(0)
+    if n != nil: 
+      OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef))
+      inc outputs
+      
+  dec(c.InCompilesContext)
+  if outputs > 0: quit(0)
 
 proc suggestStmt*(c: PContext, n: PNode) = 
   suggestExpr(c, n)
 
+proc findSuggest*(c: PContext, n: PNode) = 
+  if n == nil: return
+  suggestExpr(c, n)
+  for i in 0.. <safeLen(n):
+    findSuggest(c, n.sons[i])
diff --git a/todo.txt b/todo.txt
index 2668945fa..ac81d8250 100755
--- a/todo.txt
+++ b/todo.txt
@@ -23,6 +23,7 @@ version 0.9.0
 Bugs
 ----
 
+- bug: strange shallowCopy(result.tab, c.tab)
 - bug: pragma statements in combination with symbol files are evaluated twice
   but this can lead to compilation errors
 - bug: the parser is not strict enough with newlines: 'echo "a" echo "b"'