diff options
-rwxr-xr-x | rod/sem.nim | 20 | ||||
-rwxr-xr-x | rod/semdata.nim | 15 | ||||
-rwxr-xr-x | rod/seminst.nim | 9 | ||||
-rwxr-xr-x | rod/semstmts.nim | 12 |
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) |