diff options
-rwxr-xr-x | compiler/ast.nim | 3 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 72 | ||||
-rwxr-xr-x | compiler/types.nim | 7 | ||||
-rwxr-xr-x | compiler/wordrecg.nim | 7 |
4 files changed, 87 insertions, 2 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 10a3d8039..949c28c5f 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -567,6 +567,9 @@ type # for record types a nkRecord node # for enum types a list of symbols # else: unused + destructor*: PSym # destructor. warning: nil here may not necessary + # mean that there is no destructor. + # see instantiateDestructor in types.nim owner*: PSym # the 'owner' of the type sym*: PSym # types have the sym associated with them # it is used for converting types to strings diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 9c5efaf2d..f10c56880 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -768,6 +768,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, incl(s.flags, sfForward) elif sfBorrow in s.flags: semBorrow(c, n, s) sideEffectsCheck(c, s) + if result.sons[namePos].sym.name.id == ord(wDestroy): + if s.typ.sons.len == 2: + let typ = s.typ.sons[1].skipTypes({tyVar}) + typ.destructor = s if s.typ.callConv == ccClosure and s.owner.kind == skModule: localError(s.info, errXCannotBeClosure, s.name.s) closeScope(c.tab) # close scope for parameters @@ -856,6 +860,62 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = if result.isNil: LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) +proc insertDestructors(c: PContext, varSection: PNode): + tuple[outer: PNode, inner: PNode] = + # Accepts a var or let section. + # + # When a var section has variables with destructors + # the var section is split up and finally blocks are inserted + # immediately after all "destructable" vars + # + # In case there were no destrucable variables, the proc returns + # (nil, nil) and the enclosing stmt-list requires no modifications. + # + # Otherwise, after the try blocks are created, the rest of the enclosing + # stmt-list should be inserted in the most `inner` such block (corresponding + # to the last variable). + # + # `outer` is a statement list that should replace the original var section. + # It will include the new truncated var section followed by the outermost + # try block. + let totalVars = varSection.sonsLen + for j in countup(0, totalVars - 1): + let + varId = varSection[j][0] + varTyp = varId.sym.typ + info = varId.info + + if varTyp != nil and instantiateDestructor(varTyp): + var tryStmt = newNodeI(nkTryStmt, info) + + if j < totalVars - 1: + var remainingVars = newNodeI(varSection.kind, info) + remainingVars.sons = varSection.sons[(j+1)..(-1)] + let (outer, inner) = insertDestructors(c, remainingVars) + if outer != nil: + tryStmt.addSon(outer) + result.inner = inner + else: + result.inner = newNodeI(nkStmtList, info) + result.inner.addSon(remainingVars) + tryStmt.addSon(result.inner) + else: + result.inner = newNodeI(nkStmtList, info) + tryStmt.addSon(result.inner) + + tryStmt.addSon( + newNode(nkFinally, info, @[ + semStmt(c, newNode(nkCall, info, @[ + semSym(c, varId, varTyp.destructor, {}), + semSym(c, varId, varId.sym, {})]))])) + + result.outer = newNodeI(nkStmtList, info) + varSection.sons.setLen(j+1) + result.outer.addSon(varSection) + result.outer.addSon(tryStmt) + + return + proc SemStmt(c: PContext, n: PNode): PNode = const # must be last statements in a block: LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} @@ -893,11 +953,21 @@ proc SemStmt(c: PContext, n: PNode): PNode = return else: n.sons[i] = semStmt(c, n.sons[i]) - if n.sons[i].kind in LastBlockStmts: + case n.sons[i].kind + of nkVarSection, nkLetSection: + let (outer, inner) = insertDestructors(c, n.sons[i]) + if outer != nil: + n.sons[i] = outer + for j in countup(i+1, length-1): + inner.addSon(SemStmt(c, n.sons[j])) + n.sons.setLen(i+1) + return + of LastBlockStmts: for j in countup(i + 1, length - 1): case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil else: localError(n.sons[j].info, errStmtInvalidAfterReturn) + else: nil of nkRaiseStmt: result = semRaise(c, n) of nkVarSection: result = semVarOrLet(c, n, skVar) of nkLetSection: result = semVarOrLet(c, n, skLet) diff --git a/compiler/types.nim b/compiler/types.nim index 15390bed7..633524eff 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1054,4 +1054,11 @@ proc getReturnType*(s: PSym): PType = proc getSize(typ: PType): biggestInt = result = computeSize(typ) if result < 0: InternalError("getSize(" & $typ.kind & ')') + +proc instantiateDestructor*(typ: PType): bool = + # return true if the type already had a user-defined + # destructor or if the compiler generated a default + # member-wise one + if typ.destructor != nil: return true + return false diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 30a6b3c2c..af482966b 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -36,6 +36,9 @@ type wColon, wColonColon, wEquals, wDot, wDotDot, wStar, wMinus, wMagic, wThread, wFinal, wProfiler, wObjChecks, + + wDestroy, + wImmediate, wImportCpp, wImportObjC, wImportCompilerProc, wImportc, wExportc, wIncompleteStruct, @@ -110,7 +113,9 @@ const ":", "::", "=", ".", "..", "*", "-", - "magic", "thread", "final", "profiler", "objchecks", + "magic", "thread", "final", "profiler", "objchecks", + + "destroy", "immediate", "importcpp", "importobjc", "importcompilerproc", "importc", "exportc", "incompletestruct", |