summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xrod/sem.nim20
-rwxr-xr-xrod/semdata.nim15
-rwxr-xr-xrod/seminst.nim9
-rwxr-xr-xrod/semstmts.nim12
4 files changed, 33 insertions, 23 deletions
diff --git a/rod/sem.nim b/rod/sem.nim
index 1ede5f7f8..bb948ffc9 100755
--- a/rod/sem.nim
+++ b/rod/sem.nim
@@ -29,9 +29,7 @@ proc considerAcc(n: PNode): PIdent =
     result = nil
 
 proc isTopLevel(c: PContext): bool {.inline.} = 
-  # if we encountered an error, we treat as top-level so that
-  # cascading errors are not that strange:
-  result = c.tab.tos <= 2 or msgs.gErrorCounter > 0
+  result = c.tab.tos <= 2
 
 proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = 
   result = newSym(kind, considerAcc(n), getCurrOwner())
@@ -166,7 +164,7 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   if (c.p != nil): InternalError(module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
   c.semExpr = semExprNoFlags
-  c.p = newProcCon(module)
+  pushProcCon(c, module)
   pushOwner(c.module)
   openScope(c.tab)            # scope for imported symbols
   SymTabAdd(c.tab, module)    # a module knows itself
@@ -179,7 +177,8 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   openScope(c.tab)            # scope for the module's symbols  
   result = c
 
-proc myOpenCached(module: PSym, filename: string, rd: PRodReader): PPassContext = 
+proc myOpenCached(module: PSym, filename: string, 
+                  rd: PRodReader): PPassContext = 
   var c = PContext(myOpen(module, filename))
   c.fromCache = true
   result = c
@@ -195,6 +194,14 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
       if result.kind != nkEmpty: addSon(a, result)
       result = a
 
+proc RecoverContext(c: PContext) = 
+  # clean up in case of a semantic error: We clean up the stacks, etc. This is
+  # faster than wrapping every stack operation in a 'try finally' block and 
+  # requires far less code.
+  while c.tab.tos-1 > ModuleTablePos: rawCloseScope(c.tab)
+  while getCurrOwner().kind != skModule: popOwner()
+  while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
+
 proc myProcess(context: PPassContext, n: PNode): PNode = 
   var c = PContext(context)    
   # no need for an expensive 'try' if we stop after the first error anyway:
@@ -204,6 +211,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
     try:
       result = SemStmtAndGenerateGenerics(c, n)
     except ERecoverableError:
+      RecoverContext(c)
       result = ast.emptyNode
   
 proc myClose(context: PPassContext, n: PNode): PNode = 
@@ -216,7 +224,7 @@ proc myClose(context: PPassContext, n: PNode): PNode =
     InternalError(n.info, "n is not nil") #result := n;
   addCodeForGenerics(c, result)
   popOwner()
-  c.p = nil
+  popProcCon(c)
 
 proc semPass(): TPass = 
   initPass(result)
diff --git a/rod/semdata.nim b/rod/semdata.nim
index 702e00059..e052a0baf 100755
--- a/rod/semdata.nim
+++ b/rod/semdata.nim
@@ -23,14 +23,15 @@ type
     Notes*: TNoteKinds
 
   POptionEntry* = ref TOptionEntry
+  PProcCon* = ref TProcCon
   TProcCon*{.final.} = object # procedure context; also used for top-level
                               # statements
     owner*: PSym              # the symbol this context belongs to
     resultSym*: PSym          # the result symbol (if we are in a proc)
     nestedLoopCounter*: int   # whether we are in a loop or not
     nestedBlockCounter*: int  # whether we are in a block or not
+    next*: PProcCon           # used for stacking procedure contexts
   
-  PProcCon* = ref TProcCon
   PContext* = ref TContext
   TContext* = object of TPassContext # a context represents a module
     module*: PSym             # the module sym belonging to the context
@@ -58,7 +59,6 @@ var gInstTypes*: TIdTable # map PType to PType
 
 proc newContext*(module: PSym, nimfile: string): PContext
 
-proc newProcCon*(owner: PSym): PProcCon
 proc lastOptionEntry*(c: PContext): POptionEntry
 proc newOptionEntry*(): POptionEntry
 proc addConverter*(c: PContext, conv: PSym)
@@ -97,10 +97,15 @@ proc PopOwner() =
 proc lastOptionEntry(c: PContext): POptionEntry = 
   result = POptionEntry(c.optionStack.tail)
 
-proc newProcCon(owner: PSym): PProcCon = 
+proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = 
   if owner == nil: InternalError("owner is nil")
-  new(result)
-  result.owner = owner
+  var x: PProcCon
+  new(x)
+  x.owner = owner
+  x.next = c.p
+  c.p = x
+
+proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
 
 proc newOptionEntry(): POptionEntry = 
   new(result)
diff --git a/rod/seminst.nim b/rod/seminst.nim
index 99fd1fb87..e37c6e0fc 100755
--- a/rod/seminst.nim
+++ b/rod/seminst.nim
@@ -68,13 +68,12 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   # generates an instantiated proc
   var 
     oldPrc, oldMod: PSym
-    oldP: PProcCon
     n: PNode
   if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
   inc(c.InstCounter)
-  oldP = c.p # restore later
   # NOTE: for access of private fields within generics from a different module
   # and other identifiers we fake the current module temporarily!
+  # XXX bad hack!
   oldMod = c.module
   c.module = getModule(fn)
   result = copySym(fn, false)
@@ -105,17 +104,17 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     GenericCacheAdd(c, fn, result)
     addDecl(c, result)
     if n.sons[codePos].kind != nkEmpty: 
-      c.p = newProcCon(result)
+      pushProcCon(c, result)
       if result.kind in {skProc, skMethod, skConverter}: 
         addResult(c, result.typ.sons[0], n.info)
         addResultNode(c, n)
       n.sons[codePos] = semStmtScope(c, n.sons[codePos])
-  else: 
+      popProcCon(c)
+  else:
     result = oldPrc
   popInfoContext()
   closeScope(c.tab)           # close scope for parameters
   popOwner()
-  c.p = oldP                  # restore
   c.module = oldMod
   dec(c.InstCounter)
   
diff --git a/rod/semstmts.nim b/rod/semstmts.nim
index 5ec504708..71d523540 100755
--- a/rod/semstmts.nim
+++ b/rod/semstmts.nim
@@ -638,7 +638,6 @@ proc semLambda(c: PContext, n: PNode): PNode =
   checkSonsLen(n, codePos + 1)
   var s = newSym(skProc, getIdent(":anonymous"), getCurrOwner())
   s.info = n.info
-  var oldP = c.p                  # restore later
   s.ast = n
   n.sons[namePos] = newSymNode(s)
   pushOwner(s)
@@ -658,15 +657,15 @@ proc semLambda(c: PContext, n: PNode): PNode =
   if n.sons[codePos].kind != nkEmpty: 
     if sfImportc in s.flags: 
       LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
-    c.p = newProcCon(s)
+    pushProcCon(c, s)
     addResult(c, s.typ.sons[0], n.info)
     n.sons[codePos] = semStmtScope(c, n.sons[codePos])
     addResultNode(c, n)
+    popProcCon(c)
   else: 
     LocalError(n.info, errImplOfXexpected, s.name.s)
   closeScope(c.tab)           # close scope for parameters
   popOwner()
-  c.p = oldP                  # restore
   result.typ = s.typ
 
 proc semProcAux(c: PContext, n: PNode, kind: TSymKind, 
@@ -678,7 +677,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   checkSonsLen(n, codePos + 1)
   var s = semIdentDef(c, n.sons[0], kind)
   n.sons[namePos] = newSymNode(s)
-  var oldP = c.p                  # restore later
   if sfStar in s.flags: incl(s.flags, sfInInterface)
   s.ast = n
   pushOwner(s)
@@ -704,7 +702,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   proto = SearchForProc(c, s, c.tab.tos - 2) # -2 because we have a scope open
                                              # for parameters
   if proto == nil: 
-    if oldP.owner.kind != skModule: 
+    if c.p.owner.kind != skModule: 
       s.typ.callConv = ccClosure
     else: 
       s.typ.callConv = lastOptionEntry(c).defaultCC 
@@ -743,13 +741,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     if sfBorrow in s.flags: 
       LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
     if n.sons[genericParamsPos].kind == nkEmpty: 
-      c.p = newProcCon(s)
+      pushProcCon(c, s)
       if (s.typ.sons[0] != nil) and (kind != skIterator): 
         addResult(c, s.typ.sons[0], n.info)
       if sfImportc notin s.flags: 
         # no semantic checking for importc:
         n.sons[codePos] = semStmtScope(c, n.sons[codePos])
       if s.typ.sons[0] != nil and kind != skIterator: addResultNode(c, n)
+      popProcCon(c)
     else: 
       if s.typ.sons[0] != nil and kind != skIterator: 
         addDecl(c, newSym(skUnknown, getIdent("result"), nil))
@@ -764,7 +763,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   sideEffectsCheck(c, s)
   closeScope(c.tab)           # close scope for parameters
   popOwner()
-  c.p = oldP                  # restore
   
 proc semIterator(c: PContext, n: PNode): PNode = 
   result = semProcAux(c, n, skIterator, iteratorPragmas)