--define:nimQuirky exception handling for Nim; in preparation of a blog post
This commit is contained in:
parent
2ee2022c29
commit
cb9110c43d
7 changed files with 77 additions and 32 deletions
|
|
@ -167,7 +167,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
|||
let tryStmt = p.nestedTryStmts.pop
|
||||
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
|
||||
# Pop safe points generated by try
|
||||
if not tryStmt.inExcept:
|
||||
if not tryStmt.inExcept and not isDefined(p.config, "nimQuirky"):
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
|
||||
# Pop this try-stmt of the list of nested trys
|
||||
|
|
@ -382,7 +382,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
|||
blockLeaveActions(p,
|
||||
howManyTrys = p.nestedTryStmts.len,
|
||||
howManyExcepts = p.inExceptBlockLen)
|
||||
if (p.finallySafePoints.len > 0):
|
||||
if (p.finallySafePoints.len > 0) and not isDefined(p.config, "nimQuirky"):
|
||||
# If we're in a finally block, and we came here by exception
|
||||
# consume it before we return.
|
||||
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
|
||||
|
|
@ -919,29 +919,38 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
|||
#
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
p.module.includeHeader("<setjmp.h>")
|
||||
let quirkyExceptions = isDefined(p.config, "nimQuirky")
|
||||
if not quirkyExceptions:
|
||||
p.module.includeHeader("<setjmp.h>")
|
||||
genLineDir(p, t)
|
||||
var safePoint = getTempName(p.module)
|
||||
discard cgsym(p.module, "Exception")
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||
if isDefined(p.config, "nimStdSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||
elif isDefined(p.config, "nimSigSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
|
||||
elif isDefined(p.config, "nimRawSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
var safePoint: Rope
|
||||
if not quirkyExceptions:
|
||||
safePoint = getTempName(p.module)
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||
if isDefined(p.config, "nimStdSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||
elif isDefined(p.config, "nimSigSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
|
||||
elif isDefined(p.config, "nimRawSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
var length = sonsLen(t)
|
||||
add(p.nestedTryStmts, (t, false))
|
||||
expr(p, t.sons[0], d)
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
endBlock(p)
|
||||
startBlock(p, "else {$n")
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
genRestoreFrameAfterException(p)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
endBlock(p)
|
||||
startBlock(p, "else {$n")
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
genRestoreFrameAfterException(p)
|
||||
elif 1 < length and t.sons[1].kind == nkExceptBranch:
|
||||
startBlock(p, "if (#getCurrentException()) {$n")
|
||||
else:
|
||||
startBlock(p)
|
||||
p.nestedTryStmts[^1].inExcept = true
|
||||
var i = 1
|
||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||
|
|
@ -952,7 +961,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
|||
# general except section:
|
||||
if i > 1: lineF(p, cpsStmts, "else", [])
|
||||
startBlock(p)
|
||||
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
|
||||
expr(p, t.sons[i].sons[0], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
endBlock(p)
|
||||
|
|
@ -968,7 +978,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
|||
[genTypeInfo(p.module, t[i][j].typ, t[i][j].info)])
|
||||
if i > 1: line(p, cpsStmts, "else ")
|
||||
startBlock(p, "if ($1) {$n", [orExpr])
|
||||
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
|
||||
expr(p, t.sons[i].sons[blen-1], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
endBlock(p)
|
||||
|
|
@ -979,7 +990,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
|||
p.finallySafePoints.add(safePoint)
|
||||
genSimpleBlock(p, t.sons[i].sons[0])
|
||||
discard pop(p.finallySafePoints)
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
||||
|
||||
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
|
||||
var res = ""
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ type
|
|||
|
||||
proc `==`*(a, b: FileIndex): bool {.borrow.}
|
||||
|
||||
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||
proc raiseRecoverableError*(msg: string) {.noinline.} =
|
||||
raise newException(ERecoverableError, msg)
|
||||
|
||||
const
|
||||
|
|
|
|||
|
|
@ -864,7 +864,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
|||
incl(sym.flags, sfSideEffect)
|
||||
of wNoreturn:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, sfNoReturn)
|
||||
# Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode!
|
||||
if not isDefined(c.config, "nimQuirky"):
|
||||
incl(sym.flags, sfNoReturn)
|
||||
if sym.typ[0] != nil:
|
||||
localError(c.config, sym.ast[paramsPos][0].info,
|
||||
".noreturn with return type not allowed")
|
||||
|
|
@ -1119,7 +1121,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
|||
else: sym.flags.incl sfUsed
|
||||
of wLiftLocals: discard
|
||||
else: invalidPragma(c, it)
|
||||
elif sym == nil or (sym != nil and sym.kind in {skVar, skLet, skParam,
|
||||
elif sym == nil or (sym != nil and sym.kind in {skVar, skLet, skParam,
|
||||
skField, skProc, skFunc, skConverter, skMethod, skType}):
|
||||
n.sons[i] = semCustomPragma(c, it)
|
||||
elif sym != nil:
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
|||
if c.config.m.errorOutputs == {}:
|
||||
# fail fast:
|
||||
globalError(c.config, n.info, "type mismatch")
|
||||
return
|
||||
if errors.len == 0:
|
||||
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
|
|||
add(s, x.prc.name.s)
|
||||
msgWriteln(c.config, s)
|
||||
|
||||
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
|
||||
proc stackTraceB(c: PCtx, tos: PStackFrame, pc: int,
|
||||
msg: string, lineInfo: TLineInfo) =
|
||||
msgWriteln(c.config, "stack trace: (most recent call last)")
|
||||
stackTraceAux(c, tos, pc)
|
||||
|
|
@ -88,8 +88,14 @@ proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
|
|||
if c.mode == emRepl: globalError(c.config, lineInfo, msg)
|
||||
else: localError(c.config, lineInfo, msg)
|
||||
|
||||
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string) =
|
||||
stackTrace(c, tos, pc, msg, c.debug[pc])
|
||||
template stackTrace(c: PCtx, tos: PStackFrame, pc: int,
|
||||
msg: string, lineInfo: TLineInfo) =
|
||||
stackTraceB(c, tos, pc, msg, lineInfo)
|
||||
return
|
||||
|
||||
template stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string) =
|
||||
stackTraceB(c, tos, pc, msg, c.debug[pc])
|
||||
return
|
||||
|
||||
proc bailOut(c: PCtx; tos: PStackFrame) =
|
||||
stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " &
|
||||
|
|
@ -950,13 +956,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
decodeBC(rkInt)
|
||||
let a = regs[rb].node
|
||||
let b = regs[rc].node
|
||||
if a.kind == nkSym and a.sym.kind in skProcKinds and
|
||||
if a.kind == nkSym and a.sym.kind in skProcKinds and
|
||||
b.kind == nkSym and b.sym.kind in skProcKinds:
|
||||
regs[ra].intVal =
|
||||
if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1
|
||||
else: 0
|
||||
else:
|
||||
stackTrace(c, tos, pc, "node is not a proc symbol")
|
||||
else:
|
||||
stackTrace(c, tos, pc, "node is not a proc symbol")
|
||||
of opcEcho:
|
||||
let rb = instr.regB
|
||||
if rb == 1:
|
||||
|
|
|
|||
|
|
@ -2968,6 +2968,28 @@ when not declared(sysFatal):
|
|||
proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} =
|
||||
rawoutput(message)
|
||||
panic(arg)
|
||||
elif defined(nimQuirky):
|
||||
proc name(t: typedesc): string {.magic: "TypeTrait".}
|
||||
proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
|
||||
var buf = newStringOfCap(200)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, message)
|
||||
add(buf, " [")
|
||||
add(buf, name exceptn)
|
||||
add(buf, "]")
|
||||
echo buf
|
||||
quit 1
|
||||
|
||||
proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
|
||||
var buf = newStringOfCap(200)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, message)
|
||||
add(buf, arg)
|
||||
add(buf, " [")
|
||||
add(buf, name exceptn)
|
||||
add(buf, "]")
|
||||
echo buf
|
||||
quit 1
|
||||
else:
|
||||
proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
|
||||
var e: ref exceptn
|
||||
|
|
|
|||
|
|
@ -357,6 +357,8 @@ proc raiseExceptionAux(e: ref Exception) =
|
|||
raiseCounter.inc # skip zero at overflow
|
||||
e.raiseId = raiseCounter
|
||||
{.emit: "`e`->raise();".}
|
||||
elif defined(nimQuirky):
|
||||
if currException == nil: currException = e
|
||||
else:
|
||||
if excHandler != nil:
|
||||
if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue