codegen for user-defined destructors

This commit is contained in:
Zahary Karadjov 2012-05-25 19:02:14 +03:00
commit 337e1ecc7c
4 changed files with 87 additions and 2 deletions

View file

@ -567,6 +567,9 @@ type
# for record types a nkRecord node # for record types a nkRecord node
# for enum types a list of symbols # for enum types a list of symbols
# else: unused # 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 owner*: PSym # the 'owner' of the type
sym*: PSym # types have the sym associated with them sym*: PSym # types have the sym associated with them
# it is used for converting types to strings # it is used for converting types to strings

View file

@ -768,6 +768,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
incl(s.flags, sfForward) incl(s.flags, sfForward)
elif sfBorrow in s.flags: semBorrow(c, n, s) elif sfBorrow in s.flags: semBorrow(c, n, s)
sideEffectsCheck(c, 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: if s.typ.callConv == ccClosure and s.owner.kind == skModule:
localError(s.info, errXCannotBeClosure, s.name.s) localError(s.info, errXCannotBeClosure, s.name.s)
closeScope(c.tab) # close scope for parameters closeScope(c.tab) # close scope for parameters
@ -856,6 +860,62 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
if result.isNil: if result.isNil:
LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) 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 = proc SemStmt(c: PContext, n: PNode): PNode =
const # must be last statements in a block: const # must be last statements in a block:
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
@ -893,11 +953,21 @@ proc SemStmt(c: PContext, n: PNode): PNode =
return return
else: else:
n.sons[i] = semStmt(c, n.sons[i]) 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): for j in countup(i + 1, length - 1):
case n.sons[j].kind case n.sons[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
else: localError(n.sons[j].info, errStmtInvalidAfterReturn) else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
else: nil
of nkRaiseStmt: result = semRaise(c, n) of nkRaiseStmt: result = semRaise(c, n)
of nkVarSection: result = semVarOrLet(c, n, skVar) of nkVarSection: result = semVarOrLet(c, n, skVar)
of nkLetSection: result = semVarOrLet(c, n, skLet) of nkLetSection: result = semVarOrLet(c, n, skLet)

View file

@ -1055,3 +1055,10 @@ proc getSize(typ: PType): biggestInt =
result = computeSize(typ) result = computeSize(typ)
if result < 0: InternalError("getSize(" & $typ.kind & ')') 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

View file

@ -36,6 +36,9 @@ type
wColon, wColonColon, wEquals, wDot, wDotDot, wColon, wColonColon, wEquals, wDot, wDotDot,
wStar, wMinus, wStar, wMinus,
wMagic, wThread, wFinal, wProfiler, wObjChecks, wMagic, wThread, wFinal, wProfiler, wObjChecks,
wDestroy,
wImmediate, wImportCpp, wImportObjC, wImmediate, wImportCpp, wImportObjC,
wImportCompilerProc, wImportCompilerProc,
wImportc, wExportc, wIncompleteStruct, wImportc, wExportc, wIncompleteStruct,
@ -112,6 +115,8 @@ const
"*", "-", "*", "-",
"magic", "thread", "final", "profiler", "objchecks", "magic", "thread", "final", "profiler", "objchecks",
"destroy",
"immediate", "importcpp", "importobjc", "immediate", "importcpp", "importobjc",
"importcompilerproc", "importc", "exportc", "incompletestruct", "importcompilerproc", "importc", "exportc", "incompletestruct",
"align", "nodecl", "pure", "sideeffect", "align", "nodecl", "pure", "sideeffect",