mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
Try/Catch support for native JS exceptions (#8955)
* Try/Catch support for native JS exceptions * Better tests
This commit is contained in:
@@ -1739,13 +1739,14 @@ proc isException*(t: PType): bool =
|
||||
return false
|
||||
|
||||
proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
assert(t != nil)
|
||||
assert t != nil
|
||||
|
||||
if optNoCppExceptions in conf.globalOptions:
|
||||
return false
|
||||
|
||||
let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst})
|
||||
|
||||
if base.sym != nil and sfCompileToCpp in base.sym.flags:
|
||||
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
|
||||
result = true
|
||||
|
||||
proc isInfixAs*(n: PNode): bool =
|
||||
|
||||
@@ -615,7 +615,6 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n.sons[0], a)
|
||||
moveInto(p, a, r)
|
||||
var generalCatchBranchExists = false
|
||||
let dollar = rope("")
|
||||
if catchBranchesExist:
|
||||
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||
@@ -631,15 +630,42 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if i > 1: lineF(p, "}$n", [])
|
||||
else:
|
||||
var orExpr: Rope = nil
|
||||
var excAlias: PNode = nil
|
||||
|
||||
useMagic(p, "isObj")
|
||||
for j in countup(0, blen - 2):
|
||||
if n.sons[i].sons[j].kind != nkType:
|
||||
var throwObj: PNode
|
||||
let it = n.sons[i].sons[j]
|
||||
|
||||
if it.isInfixAs():
|
||||
throwObj = it[1]
|
||||
excAlias = it[2]
|
||||
# If this is a ``except exc as sym`` branch there must be no following
|
||||
# nodes
|
||||
doAssert orExpr == nil
|
||||
elif it.kind == nkType:
|
||||
throwObj = it
|
||||
else:
|
||||
internalError(p.config, n.info, "genTryStmt")
|
||||
|
||||
if orExpr != nil: add(orExpr, "||")
|
||||
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
|
||||
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
|
||||
# Generate the correct type checking code depending on whether this is a
|
||||
# NIM-native or a JS-native exception
|
||||
# if isJsObject(throwObj.typ):
|
||||
if isImportedException(throwObj.typ, p.config):
|
||||
addf(orExpr, "lastJSError instanceof $1",
|
||||
[throwObj.typ.sym.loc.r])
|
||||
else:
|
||||
addf(orExpr, "isObj(lastJSError.m_type, $1)",
|
||||
[genTypeInfo(p, throwObj.typ)])
|
||||
|
||||
if i > 1: line(p, "else ")
|
||||
lineF(p, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
||||
lineF(p, "if (lastJSError && ($1)) {$n", [orExpr])
|
||||
# If some branch requires a local alias introduce it here. This is needed
|
||||
# since JS cannot do ``catch x as y``.
|
||||
if excAlias != nil:
|
||||
excAlias.sym.loc.r = mangleName(p.module, excAlias.sym)
|
||||
lineF(p, "var $1 = lastJSError;$n", excAlias.sym.loc.r)
|
||||
gen(p, n.sons[i].sons[blen - 1], a)
|
||||
moveInto(p, a, r)
|
||||
lineF(p, "}$n", [])
|
||||
@@ -650,7 +676,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
line(p, "else {\L")
|
||||
line(p, "\treraiseException();\L")
|
||||
line(p, "}\L")
|
||||
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
|
||||
lineF(p, "lastJSError = prevJSError;$n")
|
||||
line(p, "} finally {\L")
|
||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
if i < length and n.sons[i].kind == nkFinally:
|
||||
|
||||
@@ -89,6 +89,17 @@ var
|
||||
jsFilename* {.importc: "__filename", nodecl.}: cstring
|
||||
## JavaScript's __filename pseudo-variable
|
||||
|
||||
# Exceptions
|
||||
type
|
||||
JsError* {.importc: "Error".} = object of JsRoot
|
||||
message*: cstring
|
||||
JsEvalError* {.importc: "EvalError".} = object of JsError
|
||||
JsRangeError* {.importc: "RangeError".} = object of JsError
|
||||
JsReferenceError* {.importc: "ReferenceError".} = object of JsError
|
||||
JsSyntaxError* {.importc: "SyntaxError".} = object of JsError
|
||||
JsTypeError* {.importc: "TypeError".} = object of JsError
|
||||
JsURIError* {.importc: "URIError".} = object of JsError
|
||||
|
||||
# New
|
||||
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
||||
## Creates a new empty JsObject
|
||||
|
||||
31
tests/js/tnativeexc.nim
Normal file
31
tests/js/tnativeexc.nim
Normal file
@@ -0,0 +1,31 @@
|
||||
discard """
|
||||
action: "run"
|
||||
"""
|
||||
|
||||
import jsffi
|
||||
|
||||
# Can catch JS exceptions
|
||||
try:
|
||||
asm """throw new Error('a new error');"""
|
||||
except JsError as e:
|
||||
doAssert e.message == "a new error"
|
||||
except:
|
||||
doAssert false
|
||||
|
||||
# Can distinguish different exceptions
|
||||
try:
|
||||
asm """JSON.parse(';;');"""
|
||||
except JsEvalError:
|
||||
doAssert false
|
||||
except JsSyntaxError as se:
|
||||
doAssert se.message == "Unexpected token ; in JSON at position 0"
|
||||
except JsError as e:
|
||||
doAssert false
|
||||
|
||||
# Can catch parent exception
|
||||
try:
|
||||
asm """throw new SyntaxError();"""
|
||||
except JsError as e:
|
||||
discard
|
||||
except:
|
||||
doAssert false
|
||||
Reference in New Issue
Block a user