summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/astalgo.nim74
-rw-r--r--compiler/lookups.nim79
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/sem.nim8
-rw-r--r--compiler/semdata.nim29
-rw-r--r--compiler/semdestruct.nim2
-rw-r--r--compiler/semexprs.nim10
-rw-r--r--compiler/semgnrc.nim4
-rw-r--r--compiler/semstmts.nim8
-rw-r--r--compiler/semtempl.nim2
-rw-r--r--compiler/semtypes.nim6
11 files changed, 91 insertions, 133 deletions
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 16dd196b4..fd6774e7a 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -72,39 +72,6 @@ type
 proc InitIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
 proc NextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
 
-# -------------- symbol table ----------------------------------------------
-# Each TParser object (which represents a module being compiled) has its own
-# symbol table. A symbol table is organized as a stack of str tables. The
-# stack represents the different scopes.
-# Stack pointer:
-# 0                imported symbols from other modules
-# 1                module level
-# 2                proc level
-# 3                nested statements
-# ...
-#
-type
-  TScope = object
-    symbols*: TStrTable
-    parent*: PScope
-
-  PScope = ref TScope
-    
-  TSymTab*{.final.} = object 
-    tos*: Natural             # top of stack
-    stack*: seq[PScope]
-
-
-proc InitSymTab*(tab: var TSymTab)
-proc DeinitSymTab*(tab: var TSymTab)
-proc SymTabGet*(tab: TSymTab, s: PIdent): PSym
-proc SymTabGet*(tab: TSymTab, s: PIdent, filter: TSymKinds): PSym
-proc SymTabLocalGet*(tab: TSymTab, s: PIdent): PSym
-proc SymTabAdd*(tab: var TSymTab, e: PSym)
-proc SymTabAddAt*(tab: var TSymTab, e: PSym, at: Natural)
-proc SymTabAddUnique*(tab: var TSymTab, e: PSym): TResult
-proc SymTabAddUniqueAt*(tab: var TSymTab, e: PSym, at: Natural): TResult
-
 # these are for debugging only: They are not really deprecated, but I want
 # the warning so that release versions do not contain debugging statements:
 proc debug*(n: PSym) {.deprecated.}
@@ -710,44 +677,7 @@ proc NextIter(ti: var TTabIter, tab: TStrTable): PSym =
     result = tab.data[ti.h]
     Inc(ti.h)                 # ... and increment by one always
     if result != nil: break 
-  
-proc InitSymTab(tab: var TSymTab) = 
-  tab.tos = 0
-  tab.stack = EmptySeq
-
-proc DeinitSymTab(tab: var TSymTab) = 
-  tab.stack = nil
-
-proc SymTabLocalGet(tab: TSymTab, s: PIdent): PSym = 
-  result = StrTableGet(tab.stack[tab.tos - 1], s)
-
-proc SymTabGet(tab: TSymTab, s: PIdent): PSym = 
-  for i in countdown(tab.tos - 1, 0): 
-    result = StrTableGet(tab.stack[i], s)
-    if result != nil: return 
-  result = nil
 
-proc SymTabGet*(tab: TSymTab, s: PIdent, filter: TSymKinds): PSym =
-  for i in countdown(tab.tos - 1, 0): 
-    result = StrTableGet(tab.stack[i], s)
-    if result != nil and result.kind in filter: return
-  result = nil
-
-proc SymTabAddAt(tab: var TSymTab, e: PSym, at: Natural) = 
-  StrTableAdd(tab.stack[at], e)
-
-proc SymTabAdd(tab: var TSymTab, e: PSym) = 
-  StrTableAdd(tab.stack[tab.tos - 1], e)
-
-proc SymTabAddUniqueAt(tab: var TSymTab, e: PSym, at: Natural): TResult = 
-  if StrTableIncl(tab.stack[at], e): 
-    result = Failure
-  else: 
-    result = Success
-
-proc SymTabAddUnique(tab: var TSymTab, e: PSym): TResult = 
-  result = SymTabAddUniqueAt(tab, e, tab.tos - 1)
-  
 iterator items*(tab: TStrTable): PSym = 
   var it: TTabIter
   var s = InitTabIter(it, tab)
@@ -755,10 +685,6 @@ iterator items*(tab: TStrTable): PSym =
     yield s
     s = NextIter(it, tab)
 
-iterator items*(tab: TSymTab): PSym = 
-  for i in countdown(tab.tos-1, 0): 
-    for it in items(tab.stack[i]): yield it
-
 proc hasEmptySlot(data: TIdPairSeq): bool = 
   for h in countup(0, high(data)): 
     if data[h].key == nil: 
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 801d21dd4..cfed6e518 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -46,7 +46,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
   result.typ = errorType(c)
   incl(result.flags, sfDiscardable)
   # pretend it's imported from some unknown module to prevent cascading errors:
-  SymTabAddAt(c.tab, result, ast.ImportTablePos)
+  c.importTable.addSym(result)
 
 type 
   TOverloadIterMode* = enum 
@@ -63,8 +63,8 @@ proc getSymRepr*(s: PSym): string =
   case s.kind
   of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
   else: result = s.name.s
-  
-proc ensureNoMissingOrUnusedSymbols*(scope: PScope) =
+ 
+proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
   # check if all symbols have been used and defined:
   var it: TTabIter
   var s = InitTabIter(it, scope.symbols)
@@ -89,15 +89,15 @@ proc WrongRedefinition*(info: TLineInfo, s: string) =
 proc AddSym*(t: var TStrTable, n: PSym) = 
   if StrTableIncl(t, n): WrongRedefinition(n.info, n.name.s)
   
-proc addDecl*(c: PContext, sym: PSym) = 
-  if SymTabAddUnique(c.tab, sym) == Failure: 
+proc addDecl*(c: PContext, sym: PSym) =
+  if c.currentScope.addUnique(sym) == Failure:
     WrongRedefinition(sym.info, sym.Name.s)
 
 proc addPrelimDecl*(c: PContext, sym: PSym) =
-  discard SymTabAddUnique(c.tab, sym)
+  discard c.currentScope.addUnique(sym)
 
-proc addDeclAt*(c: PContext, sym: PSym, at: Natural) = 
-  if SymTabAddUniqueAt(c.tab, sym, at) == Failure: 
+proc addDeclAt*(scope: PScope, sym: PSym) =
+  if scope.addUnique(sym) == Failure:
     WrongRedefinition(sym.info, sym.Name.s)
 
 proc AddInterfaceDeclAux(c: PContext, sym: PSym) = 
@@ -106,35 +106,35 @@ proc AddInterfaceDeclAux(c: PContext, sym: PSym) =
     if c.module != nil: StrTableAdd(c.module.tab, sym)
     else: InternalError(sym.info, "AddInterfaceDeclAux")
 
-proc addInterfaceDeclAt*(c: PContext, sym: PSym, at: Natural) = 
-  addDeclAt(c, sym, at)
+proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
+  addDeclAt(scope, sym)
   AddInterfaceDeclAux(c, sym)
-  
-proc addOverloadableSymAt*(c: PContext, fn: PSym, at: Natural) = 
+
+proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
   if fn.kind notin OverloadableSyms: 
     InternalError(fn.info, "addOverloadableSymAt")
     return
-  var check = StrTableGet(c.tab.stack[at], fn.name)
+  var check = StrTableGet(scope.symbols, fn.name)
   if check != nil and check.Kind notin OverloadableSyms: 
     WrongRedefinition(fn.info, fn.Name.s)
   else:
-    SymTabAddAt(c.tab, fn, at)
+    scope.addSym(fn)
   
 proc addInterfaceDecl*(c: PContext, sym: PSym) = 
   # it adds the symbol to the interface if appropriate
   addDecl(c, sym)
   AddInterfaceDeclAux(c, sym)
 
-proc addInterfaceOverloadableSymAt*(c: PContext, sym: PSym, at: int) = 
+proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
   # it adds the symbol to the interface if appropriate
-  addOverloadableSymAt(c, sym, at)
+  addOverloadableSymAt(scope, sym)
   AddInterfaceDeclAux(c, sym)
 
 proc lookUp*(c: PContext, n: PNode): PSym = 
   # Looks up a symbol. Generates an error in case of nil.
   case n.kind
   of nkIdent:
-    result = SymtabGet(c.Tab, n.ident)
+    result = searchInScopes(c, n.ident)
     if result == nil: 
       LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
       result = errorSym(c, n)
@@ -142,7 +142,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
     result = n.sym
   of nkAccQuoted:
     var ident = considerAcc(n)
-    result = SymtabGet(c.Tab, ident)
+    result = searchInScopes(c, ident)
     if result == nil:
       LocalError(n.info, errUndeclaredIdentifier, ident.s)
       result = errorSym(c, n)
@@ -161,7 +161,7 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
   case n.kind
   of nkIdent, nkAccQuoted:
     var ident = considerAcc(n)
-    result = SymtabGet(c.Tab, ident)
+    result = searchInScopes(c, ident)
     if result == nil and checkUndeclared in flags: 
       LocalError(n.info, errUndeclaredIdentifier, ident.s)
       result = errorSym(c, n)
@@ -239,6 +239,47 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   else: nil
   if result != nil and result.kind == skStub: loadStub(result)
 
+proc openScope*(c: PContext): PScope {.discardable.} =
+  c.currentScope = PScope(parent: c.currentScope, symbols: newStrTable())
+  result = c.currentScope
+
+proc rawCloseScope*(c: PContext) =
+  c.currentScope = c.currentScope.parent
+
+proc closeScope*(c: PContext) =
+  ensureNoMissingOrUnusedSymbols(c.currentScope)
+  rawCloseScope(c)
+
+template addSym*(scope: PScope, s: PSym) =
+  StrTableAdd(scope.symbols, s)
+
+proc addUniqueSym*(scope: PScope, s: PSym): TResult =
+  if StrTableIncl(scope.symbols, s):
+    result = Failure
+  else:
+    result = Success
+
+iterator walkScopes*(scope: PScope): PScope =
+  var current = scope
+  while current != nil:
+    yield current
+    current = current.parent
+
+proc localSearchInScope*(c: PContext, s: PIdent): PSym =
+  result = StrTableGet(c.currentScope.symbols, s)
+
+proc searchInScopes*(c: PContext, s: PIdent): PSym =
+  for scope in walkScopes(c.currentScope):
+    result = StrTableGet(scope.symbols, s)
+    if result != nil: return
+  result = nil
+
+proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
+  for scope in walkScopes(c.currentScope):
+    result = StrTableGet(scope.symbols, s)
+    if result != nil and result.kind in filter: return
+  result = nil
+
 proc lastOverloadScope*(o: TOverloadIter): int =
   case o.mode
   of oimNoQualifier: result = o.stackPtr
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index ba761739a..e623acd06 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -409,7 +409,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
       if c < 0: sub = substr(str, b + 1)
       else: sub = substr(str, b + 1, c - 1)
       if sub != "": 
-        var e = SymtabGet(con.tab, getIdent(sub))
+        var e = searchInScopes(con, getIdent(sub))
         if e != nil: 
           if e.kind == skStub: loadStub(e)
           addSon(result, newSymNode(e))
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 8036dc913..bc6d2c9b6 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -247,15 +247,15 @@ proc myOpen(module: PSym): PPassContext =
   c.semTypeNode = semTypeNode
   pushProcCon(c, module)
   pushOwner(c.module)
-  openScope(c)                # scope for imported symbols
-  SymTabAdd(c.tab, module)    # a module knows itself
+  c.importTable = openScope(c)
+  c.importTable.addSym(module) # a module knows itself
   if sfSystemModule in module.flags: 
     magicsys.SystemModule = module # set global variable!
     InitSystem(c.tab)         # currently does nothing
   else: 
-    SymTabAdd(c.tab, magicsys.SystemModule) # import the "System" identifier
+    c.importTable.addSym magicsys.SystemModule # import the "System" identifier
     importAllSymbols(c, magicsys.SystemModule)
-  closeScope(c)               # scope for the module's symbols  
+  c.topLevelScope = openScope(c)
   result = c
 
 proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 8deb3799c..390e3825d 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -45,10 +45,18 @@ type
     efAllowDestructor
   TExprFlags* = set[TExprFlag]
     
+  TScope* = object
+    symbols*: TStrTable
+    parent*: PScope
+
+  PScope* = ref TScope
+
   PContext* = ref TContext
   TContext* = object of TPassContext # a context represents a module
     module*: PSym              # the module sym belonging to the context
-    currentScope*: PScope
+    currentScope*: PScope      # current scope
+    importTable*: PScope       # scope for all imported symbols
+    topLevelScope*: PScope     # scope for all top-level symbols
     p*: PProcCon               # procedure context
     friendModule*: PSym        # current friend module; may access private data;
                                # this is used so that generic instantiations
@@ -56,7 +64,6 @@ type
     InstCounter*: int          # to prevent endless instantiations
    
     threadEntries*: TSymSeq    # list of thread entries to check
-    tab*: TSymTab              # each module has its own symbol table
     AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
                                # store this info in the syms themselves!)
     InGenericContext*: int     # > 0 if we are in a generic type
@@ -83,8 +90,7 @@ type
                                # naming it multiple times
     generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
     lastGenericIdx*: int      # used for the generics stack
-    
-
+   
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
   result.genericSym = s
   result.inst = inst
@@ -112,20 +118,6 @@ proc PopOwner*()
 
 var gOwners*: seq[PSym] = @[]
 
-proc openScope*(c: PContext) =
-  c.currentScope = PScope(parent: c.currentScope, symbols: newStrTable())
-  c.tab.stack.add(c.currentScope)
-  inc c.tab.stack.tos
-
-proc rawCloseScope*(c: PContext) =
-  c.currentScope = c.currentScope.parent
-  c.tab.stack.setLen(c.tab.stack.len - 1)
-  dec c.tab.stack.tos
-
-proc closeScope*(c: PContext) =
-  ensureNoMissingOrUnusedSymbols(c.currentScope)
-  rawExitScope(c)
-
 proc getCurrOwner(): PSym = 
   # owner stack (used for initializing the
   # owner field of syms)
@@ -166,7 +158,6 @@ proc newOptionEntry(): POptionEntry =
 
 proc newContext(module: PSym): PContext =
   new(result)
-  InitSymTab(result.tab)
   result.AmbiguousSymbols = initIntset()
   initLinkedList(result.optionStack)
   initLinkedList(result.libs)
diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim
index 2383ac649..797d8895e 100644
--- a/compiler/semdestruct.nim
+++ b/compiler/semdestruct.nim
@@ -120,7 +120,7 @@ proc instantiateDestructor(c: PContext, typ: PType): bool =
   of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
     if instantiateDestructor(c, t.sons[0]):
       if rangeDestructorProc == nil:
-        rangeDestructorProc = SymtabGet(c.tab, getIdent"nimDestroyRange")
+        rangeDestructorProc = searchInScopes(c, getIdent"nimDestroyRange")
       t.destructor = rangeDestructorProc
       return true
     else:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index d15243342..8188722c6 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -328,9 +328,9 @@ proc semOpAux(c: PContext, n: PNode) =
 proc overloadedCallOpr(c: PContext, n: PNode): PNode = 
   # quick check if there is *any* () operator overloaded:
   var par = getIdent("()")
-  if SymtabGet(c.Tab, par) == nil: 
+  if searchInScopes(c, par) == nil:
     result = nil
-  else: 
+  else:
     result = newNodeI(nkCall, n.info)
     addSon(result, newIdentNode(par, n.info))
     for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
@@ -937,7 +937,7 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       addSon(result, copyTree(n[0]))
     else:
       var i = considerAcc(n.sons[1])
-      var f = SymTabGet(c.tab, i)
+      var f = searchInScopes(c, i)
       # if f != nil and f.kind == skStub: loadStub(f)
       # ``loadStub`` is not correct here as we don't care for ``f`` really
       if f != nil: 
@@ -1205,9 +1205,9 @@ proc SemYield(c: PContext, n: PNode): PNode =
 
 proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
   if onlyCurrentScope: 
-    result = SymtabLocalGet(c.tab, i)
+    result = localSearchInScope(c, i)
   else: 
-    result = SymtabGet(c.Tab, i) # no need for stub loading
+    result = searchInScopes(c, i) # no need for stub loading
 
 proc LookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = 
   case n.kind
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 7e51f3f17..3d54ed417 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -82,7 +82,7 @@ proc Lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
             ctx: var TIntSet): PNode =
   result = n
   let ident = considerAcc(n)
-  var s = SymtabGet(c.Tab, ident)
+  var s = searchInScopes(c, ident)
   if s == nil:
     if ident.id notin ctx and withinMixin notin flags:
       localError(n.info, errUndeclaredIdentifier, ident.s)
@@ -281,7 +281,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         of nkEnumFieldDef: a = n.sons[i].sons[0]
         of nkIdent: a = n.sons[i]
         else: illFormedAst(n)
-        addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
+        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
   of nkObjectTy, nkTupleTy: 
     nil
   of nkFormalParams: 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index bf7fdefcd..0998f45a5 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -800,7 +800,7 @@ proc lookupMacro(c: PContext, n: PNode): PSym =
     result = n.sym
     if result.kind notin {skMacro, skTemplate}: result = nil
   else:
-    result = SymtabGet(c.Tab, considerAcc(n), {skMacro, skTemplate})
+    result = searchInScopes(c, considerAcc(n), {skMacro, skTemplate})
 
 proc semProcAnnotation(c: PContext, prc: PNode): PNode =
   var n = prc.sons[pragmasPos]
@@ -894,6 +894,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   n.sons[namePos] = newSymNode(s)
   s.ast = n
   pushOwner(s)
+  var outerScope = c.currentScope
   openScope(c)
   var gp: PNode
   if n.sons[genericParamsPos].kind != nkEmpty: 
@@ -922,12 +923,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   if proto == nil: 
     s.typ.callConv = lastOptionEntry(c).defaultCC
     # add it here, so that recursive procs are possible:
-    # -2 because we have a scope open for parameters
     if sfGenSym in s.flags: nil
     elif kind in OverloadableSyms: 
-      addInterfaceOverloadableSymAt(c, s, c.tab.tos - 2)
+      addInterfaceOverloadableSymAt(c, outerScope, s)
     else: 
-      addInterfaceDeclAt(c, s, c.tab.tos - 2)
+      addInterfaceDeclAt(c, outerScope, s)
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, s, n.sons[pragmasPos], validPragmas)
     else:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 234ef5d2c..7f6b85631 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -413,7 +413,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   let curScope = c.tab.tos - 1
   var proto = SearchForProc(c, s, curScope)
   if proto == nil:
-    addInterfaceOverloadableSymAt(c, s, curScope)
+    addInterfaceOverloadableSymAt(c, c.currentScope, s)
   else:
     SymTabReplace(c.tab.stack[curScope], proto, s)
   if n.sons[patternPos].kind != nkEmpty:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 8e5a239dd..2c526f676 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -79,7 +79,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       incl(e.flags, sfExported)
       if not isPure: StrTableAdd(c.module.tab, e)
     addSon(result.n, newSymNode(e))
-    if sfGenSym notin e.flags and not isPure: addDeclAt(c, e, c.tab.tos - 1)
+    if sfGenSym notin e.flags and not isPure: addDecl(c, e)
     inc(counter)
 
 proc semSet(c: PContext, n: PNode, prev: PType): PType = 
@@ -616,7 +616,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     if genericParams == nil:
       # genericParams is nil when the proc is being instantiated
       # the resolved type will be in scope then
-      let s = SymtabGet(c.tab, paramTypId)
+      let s = searchInScopes(c, paramTypId)
       # tests/run/tinterf triggers this:
       if s != nil: result = s.typ
       else:
@@ -749,7 +749,7 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
   when false:
     if n.kind == nkSym:
       # for generics we need to lookup the type var again:
-      var s = SymtabGet(c.Tab, n.sym.name)
+      var s = searchInScopes(c, n.sym.name)
       if s != nil:
         if s.kind == skType and s.typ != nil:
           var t = n.sym.typ