Merge pull request #2914 from yglukhov/js-exceptions
Fixed and slightly changed exception handling in JS.
This commit is contained in:
commit
042c0146cd
2 changed files with 50 additions and 33 deletions
|
|
@ -505,12 +505,12 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
||||||
proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
# code to generate:
|
# code to generate:
|
||||||
#
|
#
|
||||||
# var sp = {prev: excHandler, exc: null};
|
# ++excHandler;
|
||||||
# excHandler = sp;
|
|
||||||
# try {
|
# try {
|
||||||
# stmts;
|
# stmts;
|
||||||
# TMP = e
|
# } catch (EXC) {
|
||||||
# } catch (e) {
|
# var prevJSError = lastJSError; lastJSError = EXC;
|
||||||
|
# --excHandler;
|
||||||
# if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
|
# if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
|
||||||
# stmts;
|
# stmts;
|
||||||
# } else if (e.typ && e.typ == NTI32342) {
|
# } else if (e.typ && e.typ == NTI32342) {
|
||||||
|
|
@ -518,35 +518,41 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
# } else {
|
# } else {
|
||||||
# stmts;
|
# stmts;
|
||||||
# }
|
# }
|
||||||
|
# lastJSError = prevJSError;
|
||||||
# } finally {
|
# } finally {
|
||||||
# stmts;
|
# stmts;
|
||||||
# excHandler = excHandler.prev;
|
|
||||||
# }
|
# }
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
if not isEmptyType(n.typ):
|
if not isEmptyType(n.typ):
|
||||||
r.kind = resVal
|
r.kind = resVal
|
||||||
r.res = getTemp(p)
|
r.res = getTemp(p)
|
||||||
inc(p.unique)
|
inc(p.unique)
|
||||||
|
var i = 1
|
||||||
|
var length = sonsLen(n)
|
||||||
|
var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
|
||||||
|
if catchBranchesExist:
|
||||||
|
add(p.body, "++excHandler;" & tnl)
|
||||||
var safePoint = "Tmp$1" % [rope(p.unique)]
|
var safePoint = "Tmp$1" % [rope(p.unique)]
|
||||||
addf(p.body,
|
addf(p.body,
|
||||||
"var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
|
"" |
|
||||||
"local $1 = pcall(",
|
"local $1 = pcall(",
|
||||||
[safePoint])
|
[safePoint])
|
||||||
if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl)
|
if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl)
|
||||||
addf(p.body, "try {$n" | "function()$n", [])
|
addf(p.body, "try {$n" | "function()$n", [])
|
||||||
var length = sonsLen(n)
|
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
gen(p, n.sons[0], a)
|
gen(p, n.sons[0], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
var i = 1
|
var generalCatchBranchExists = false
|
||||||
if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch:
|
if p.target == targetJS and catchBranchesExist:
|
||||||
addf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n", [])
|
addf(p.body, "} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||||
|
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||||
elif p.target == targetLua:
|
elif p.target == targetLua:
|
||||||
addf(p.body, "end)$n", [])
|
addf(p.body, "end)$n", [])
|
||||||
while i < length and n.sons[i].kind == nkExceptBranch:
|
while i < length and n.sons[i].kind == nkExceptBranch:
|
||||||
let blen = sonsLen(n.sons[i])
|
let blen = sonsLen(n.sons[i])
|
||||||
if blen == 1:
|
if blen == 1:
|
||||||
# general except section:
|
# general except section:
|
||||||
|
generalCatchBranchExists = true
|
||||||
if i > 1: addf(p.body, "else {$n" | "else$n", [])
|
if i > 1: addf(p.body, "else {$n" | "else$n", [])
|
||||||
gen(p, n.sons[i].sons[0], a)
|
gen(p, n.sons[i].sons[0], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
|
|
@ -558,17 +564,22 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if n.sons[i].sons[j].kind != nkType:
|
if n.sons[i].sons[j].kind != nkType:
|
||||||
internalError(n.info, "genTryStmt")
|
internalError(n.info, "genTryStmt")
|
||||||
if orExpr != nil: add(orExpr, "||" | " or ")
|
if orExpr != nil: add(orExpr, "||" | " or ")
|
||||||
addf(orExpr, "isObj($1.exc.m_type, $2)",
|
addf(orExpr, "isObj(lastJSError.m_type, $1)",
|
||||||
[safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
|
[genTypeInfo(p, n.sons[i].sons[j].typ)])
|
||||||
if i > 1: add(p.body, "else ")
|
if i > 1: add(p.body, "else ")
|
||||||
addf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
|
addf(p.body, "if (lastJSError && ($2)) {$n" | "if $1.exc and ($2) then$n",
|
||||||
[safePoint, orExpr])
|
[safePoint, orExpr])
|
||||||
gen(p, n.sons[i].sons[blen - 1], a)
|
gen(p, n.sons[i].sons[blen - 1], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
addf(p.body, "}$n" | "end$n", [])
|
addf(p.body, "}$n" | "end$n", [])
|
||||||
inc(i)
|
inc(i)
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
add(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
|
if catchBranchesExist:
|
||||||
|
if not generalCatchBranchExists:
|
||||||
|
useMagic(p, "reraiseException")
|
||||||
|
add(p.body, "else {" & tnl & "reraiseException();" & tnl & "}" & tnl)
|
||||||
|
add(p.body, "lastJSError = prevJSError;" & tnl)
|
||||||
|
add(p.body, "} finally {" & tnl)
|
||||||
if i < length and n.sons[i].kind == nkFinally:
|
if i < length and n.sons[i].kind == nkFinally:
|
||||||
genStmt(p, n.sons[i].sons[0])
|
genStmt(p, n.sons[i].sons[0])
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
|
|
@ -1067,6 +1078,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
useMagic(p, "toJSStr") # Used in rawEcho
|
||||||
useMagic(p, "rawEcho")
|
useMagic(p, "rawEcho")
|
||||||
add(r.res, "rawEcho(")
|
add(r.res, "rawEcho(")
|
||||||
let n = n[1].skipConv
|
let n = n[1].skipConv
|
||||||
|
|
@ -1676,7 +1688,7 @@ proc genHeader(): Rope =
|
||||||
result = ("/* Generated by the Nim Compiler v$1 */$n" &
|
result = ("/* Generated by the Nim Compiler v$1 */$n" &
|
||||||
"/* (c) 2015 Andreas Rumpf */$n$n" &
|
"/* (c) 2015 Andreas Rumpf */$n$n" &
|
||||||
"var framePtr = null;$n" &
|
"var framePtr = null;$n" &
|
||||||
"var excHandler = null;$n" &
|
"var excHandler = 0;$n" &
|
||||||
"var lastJSError = null;$n") %
|
"var lastJSError = null;$n") %
|
||||||
[rope(VersionAsString)]
|
[rope(VersionAsString)]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ type
|
||||||
|
|
||||||
var
|
var
|
||||||
framePtr {.importc, nodecl, volatile.}: PCallFrame
|
framePtr {.importc, nodecl, volatile.}: PCallFrame
|
||||||
excHandler {.importc, nodecl, volatile.}: PSafePoint = nil
|
excHandler {.importc, nodecl, volatile.}: int = 0
|
||||||
# list of exception handlers
|
|
||||||
# a global variable for the root of all try blocks
|
|
||||||
lastJSError {.importc, nodecl, volatile.}: PJSError = nil
|
lastJSError {.importc, nodecl, volatile.}: PJSError = nil
|
||||||
|
|
||||||
{.push stacktrace: off, profiler:off.}
|
{.push stacktrace: off, profiler:off.}
|
||||||
|
|
@ -52,9 +50,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
|
||||||
result[0] = x
|
result[0] = x
|
||||||
|
|
||||||
proc getCurrentExceptionMsg*(): string =
|
proc getCurrentExceptionMsg*(): string =
|
||||||
if excHandler != nil and excHandler.exc != nil:
|
if lastJSError != nil:
|
||||||
return $excHandler.exc.msg
|
|
||||||
elif lastJSError != nil:
|
|
||||||
return $lastJSError.message
|
return $lastJSError.message
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -99,32 +95,41 @@ proc rawWriteStackTrace(): string =
|
||||||
else:
|
else:
|
||||||
result = "No stack traceback available\n"
|
result = "No stack traceback available\n"
|
||||||
|
|
||||||
proc raiseException(e: ref Exception, ename: cstring) {.
|
proc unhandledException(e: ref Exception) {.
|
||||||
compilerproc, asmNoStackFrame.} =
|
compilerproc, asmNoStackFrame.} =
|
||||||
e.name = ename
|
when NimStackTrace:
|
||||||
if excHandler != nil:
|
var buf = rawWriteStackTrace()
|
||||||
excHandler.exc = e
|
|
||||||
else:
|
else:
|
||||||
when NimStackTrace:
|
var buf = ""
|
||||||
var buf = rawWriteStackTrace()
|
|
||||||
else:
|
|
||||||
var buf = ""
|
|
||||||
if e.msg != nil and e.msg[0] != '\0':
|
if e.msg != nil and e.msg[0] != '\0':
|
||||||
add(buf, "Error: unhandled exception: ")
|
add(buf, "Error: unhandled exception: ")
|
||||||
add(buf, e.msg)
|
add(buf, e.msg)
|
||||||
else:
|
else:
|
||||||
add(buf, "Error: unhandled exception")
|
add(buf, "Error: unhandled exception")
|
||||||
add(buf, " [")
|
add(buf, " [")
|
||||||
add(buf, ename)
|
add(buf, e.name)
|
||||||
add(buf, "]\n")
|
add(buf, "]\n")
|
||||||
alert(buf)
|
alert(buf)
|
||||||
asm """throw `e`;"""
|
|
||||||
|
proc raiseException(e: ref Exception, ename: cstring) {.
|
||||||
|
compilerproc, asmNoStackFrame.} =
|
||||||
|
e.name = ename
|
||||||
|
when not defined(noUnhandledHandler):
|
||||||
|
if excHandler == 0:
|
||||||
|
unhandledException(e)
|
||||||
|
asm "throw `e`;"
|
||||||
|
|
||||||
proc reraiseException() {.compilerproc, asmNoStackFrame.} =
|
proc reraiseException() {.compilerproc, asmNoStackFrame.} =
|
||||||
if excHandler == nil:
|
if lastJSError == nil:
|
||||||
raise newException(ReraiseError, "no exception to reraise")
|
raise newException(ReraiseError, "no exception to reraise")
|
||||||
else:
|
else:
|
||||||
asm """throw excHandler.exc;"""
|
when not defined(noUnhandledHandler):
|
||||||
|
if excHandler == 0:
|
||||||
|
var isNimException : bool
|
||||||
|
asm "`isNimException` = lastJSError.m_type;"
|
||||||
|
if isNimException:
|
||||||
|
unhandledException(cast[ref Exception](lastJSError))
|
||||||
|
asm "throw lastJSError;"
|
||||||
|
|
||||||
proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
|
proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
|
||||||
raise newException(OverflowError, "over- or underflow")
|
raise newException(OverflowError, "over- or underflow")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue