mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
genTryCpp to catch by Nim type, ready for first review (#7196)
* Rewrite genTryCpp * correction * Implement polymorphic raise in cpp * revert backticks in emit * Cleanp a comment * revert test changes * better handling of <new> header
This commit is contained in:
@@ -1657,6 +1657,20 @@ proc toObject*(typ: PType): PType =
|
||||
if result.kind == tyRef:
|
||||
result = result.lastSon
|
||||
|
||||
proc isException*(t: PType): bool =
|
||||
# check if `y` is object type and it inherits from Exception
|
||||
assert(t != nil)
|
||||
|
||||
if t.kind != tyObject:
|
||||
return false
|
||||
|
||||
var base = t
|
||||
while base != nil:
|
||||
if base.sym.magic == mException:
|
||||
return true
|
||||
base = base.lastSon
|
||||
return false
|
||||
|
||||
proc findUnresolvedStatic*(n: PNode): PNode =
|
||||
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
|
||||
return n
|
||||
|
||||
@@ -779,91 +779,111 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
else:
|
||||
genOrdinalCase(p, t, d)
|
||||
|
||||
|
||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# code to generate:
|
||||
#
|
||||
# XXX: There should be a standard dispatch algorithm
|
||||
# that's used both here and with multi-methods
|
||||
#
|
||||
# try
|
||||
# {
|
||||
# myDiv(4, 9);
|
||||
# } catch (NimException& exp) {
|
||||
# if (isObj(exp, EIO) {
|
||||
# ...
|
||||
# } else if (isObj(exp, ESystem) {
|
||||
# ...
|
||||
# finallyPart()
|
||||
# raise;
|
||||
# } else {
|
||||
# // general handler
|
||||
# }
|
||||
# }
|
||||
# finallyPart();
|
||||
# } catch (NimExceptionType1&) {
|
||||
# body
|
||||
# goto LA_END;
|
||||
# } catch (NimExceptionType2&) {
|
||||
# finallyPart()
|
||||
# raise;
|
||||
# goto LA_END;
|
||||
# } catch (NimExceptionType3&) {goto LA1;}
|
||||
# } catch (NimExceptionType4&) {goto LA1;}
|
||||
# } catch (NimExceptionType5&) {goto LA2;}
|
||||
# } catch (NimExceptionType6&) {goto LA2;}
|
||||
# catch(...) {
|
||||
# // general handler
|
||||
# goto LA_END;
|
||||
# }
|
||||
# {LA1:
|
||||
# labeled_branch_body_LA1
|
||||
# goto LA_END;
|
||||
# }
|
||||
# {LA2:
|
||||
# labeled_branch_body_LA2
|
||||
# finallyPart()
|
||||
# raise;
|
||||
# goto LA_END;
|
||||
# }
|
||||
# LA_END:
|
||||
# finallyPart();
|
||||
|
||||
template genExceptBranchBody(body: PNode) {.dirty.} =
|
||||
if optStackTrace in p.options:
|
||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
||||
expr(p, body, d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
linefmt(p, cpsStmts, "goto $1;$n", end_label)
|
||||
|
||||
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
genLineDir(p, t)
|
||||
let exc = getTempName(p.module)
|
||||
if getCompilerProc("Exception") != nil:
|
||||
discard cgsym(p.module, "Exception")
|
||||
else:
|
||||
discard cgsym(p.module, "E_Base")
|
||||
|
||||
discard cgsym(p.module, "Exception")
|
||||
add(p.nestedTryStmts, t)
|
||||
startBlock(p, "try {$n")
|
||||
expr(p, t.sons[0], d)
|
||||
let length = sonsLen(t)
|
||||
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
|
||||
if optStackTrace in p.options:
|
||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
||||
inc p.inExceptBlock
|
||||
var i = 1
|
||||
expr(p, t[0], d)
|
||||
endBlock(p, ropecg(p.module, "}"))
|
||||
|
||||
let end_label = getLabel(p)
|
||||
var catchAllPresent = false
|
||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||
var labeled_branches: seq[tuple[label: Rope, body: PNode]] = @[] # generated after labels discovered
|
||||
|
||||
inc p.inExceptBlock
|
||||
for i in 1..<t.len:
|
||||
if t[i].kind != nkExceptBranch: break
|
||||
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
let blen = sonsLen(t.sons[i])
|
||||
if i > 1: addf(p.s(cpsStmts), "else ", [])
|
||||
if blen == 1:
|
||||
|
||||
if t[i].len == 1:
|
||||
# general except section:
|
||||
catchAllPresent = true
|
||||
startBlock(p)
|
||||
expr(p, t.sons[i].sons[0], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
startBlock(p, "catch (...) {$n")
|
||||
genExceptBranchBody(t[i][0])
|
||||
endBlock(p)
|
||||
|
||||
elif t[i].len == 2:
|
||||
startBlock(p, "catch ($1*) {$n", getTypeDesc(p.module, t[i][0].typ))
|
||||
genExceptBranchBody(t[i][^1])
|
||||
endBlock(p)
|
||||
|
||||
else:
|
||||
var orExpr: Rope = nil
|
||||
for j in countup(0, blen - 2):
|
||||
assert(t.sons[i].sons[j].kind == nkType)
|
||||
if orExpr != nil: add(orExpr, "||")
|
||||
appcg(p.module, orExpr,
|
||||
"#isObj($1.exp->m_type, $2)",
|
||||
[exc, genTypeInfo(p.module, t[i][j].typ, t[i][j].info)])
|
||||
lineF(p, cpsStmts, "if ($1) ", [orExpr])
|
||||
startBlock(p)
|
||||
expr(p, t.sons[i].sons[blen-1], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
endBlock(p)
|
||||
inc(i)
|
||||
|
||||
# reraise the exception if there was no catch all
|
||||
# and none of the handlers matched
|
||||
if not catchAllPresent:
|
||||
if i > 1: lineF(p, cpsStmts, "else ", [])
|
||||
startBlock(p)
|
||||
var finallyBlock = t.lastSon
|
||||
if finallyBlock.kind == nkFinally:
|
||||
#expr(p, finallyBlock.sons[0], d)
|
||||
genStmts(p, finallyBlock.sons[0])
|
||||
# cpp can't catch multiple types in one statement so we need a label and goto
|
||||
let label = getLabel(p)
|
||||
labeled_branches.add((label, t[i][^1]))
|
||||
for j in 0..t[i].len-2:
|
||||
assert(t[i][j].kind == nkType)
|
||||
linefmt(p, cpsStmts, "catch ($1*) {goto $2;}$n",
|
||||
[getTypeDesc(p.module, t[i][j].typ), label])
|
||||
|
||||
if not catchAllPresent and t[^1].kind == nkFinally:
|
||||
# finally requires catch all presence
|
||||
startBlock(p, "catch (...) {$n")
|
||||
genSimpleBlock(p, t[^1][0])
|
||||
line(p, cpsStmts, ~"throw;$n")
|
||||
endBlock(p)
|
||||
|
||||
lineF(p, cpsStmts, "}$n", []) # end of catch block
|
||||
dec p.inExceptBlock
|
||||
# generate labeled branches bodies
|
||||
for label, body in labeled_branches.items():
|
||||
startBlock(p)
|
||||
fixLabel(p, label)
|
||||
genExceptBranchBody(body)
|
||||
endBlock(p)
|
||||
fixLabel(p, end_label)
|
||||
|
||||
dec p.inExceptBlock
|
||||
discard pop(p.nestedTryStmts)
|
||||
if (i < length) and (t.sons[i].kind == nkFinally):
|
||||
genSimpleBlock(p, t.sons[i].sons[0])
|
||||
|
||||
if t[^1].kind == nkFinally:
|
||||
genSimpleBlock(p, t[^1][0])
|
||||
|
||||
proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
# code to generate:
|
||||
|
||||
@@ -569,6 +569,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||
elif m.compileToCpp:
|
||||
appcg(m, result, " : public $1 {$n",
|
||||
[getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
|
||||
if typ.isException:
|
||||
appcg(m, result, "virtual void raise() {throw this;}$n") # required for polymorphic exceptions
|
||||
hasField = true
|
||||
else:
|
||||
appcg(m, result, " {$n $1 Sup;$n",
|
||||
|
||||
@@ -260,6 +260,11 @@ proc rdCharLoc(a: TLoc): Rope =
|
||||
|
||||
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
takeAddr: bool) =
|
||||
if p.module.compileToCpp and t.isException:
|
||||
# init vtable in Exception object for polymorphic exceptions
|
||||
includeHeader(p.module, "<new>")
|
||||
linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
|
||||
|
||||
case analyseObjectWithTypeField(t)
|
||||
of frNone:
|
||||
discard
|
||||
|
||||
@@ -737,16 +737,10 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||
localError(n.info, errExprCannotBeRaised)
|
||||
|
||||
# check if the given object inherits from Exception
|
||||
var base = typ.lastSon
|
||||
while true:
|
||||
if base.sym.magic == mException:
|
||||
break
|
||||
if base.lastSon == nil:
|
||||
localError(n.info,
|
||||
"raised object of type $1 does not inherit from Exception",
|
||||
[typeToString(typ)])
|
||||
return
|
||||
base = base.lastSon
|
||||
if not typ.lastSon.isException():
|
||||
localError(n.info, "raised object of type $1 does not inherit from Exception",
|
||||
[typeToString(typ)])
|
||||
|
||||
|
||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||
if n.kind != nkGenericParams: illFormedAst(n)
|
||||
|
||||
@@ -274,13 +274,6 @@ __clang__
|
||||
# endif
|
||||
# define NIM_BOOL bool
|
||||
# define NIM_NIL 0
|
||||
struct NimException
|
||||
{
|
||||
NimException(struct Exception* exp, const char* msg): exp(exp), msg(msg) {}
|
||||
|
||||
struct Exception* exp;
|
||||
const char* msg;
|
||||
};
|
||||
#else
|
||||
# ifdef bool
|
||||
# define NIM_BOOL bool
|
||||
|
||||
@@ -320,7 +320,7 @@ proc raiseExceptionAux(e: ref Exception) =
|
||||
quitOrDebug()
|
||||
else:
|
||||
pushCurrentException(e)
|
||||
{.emit: "throw NimException(`e`, `e`->name);".}
|
||||
{.emit: "`e`->raise();".}
|
||||
else:
|
||||
if excHandler != nil:
|
||||
if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
discard """
|
||||
targets: "c cpp"
|
||||
output: '''Check passed
|
||||
Check passed'''
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
discard """
|
||||
targets: "c cpp"
|
||||
output: '''Hello
|
||||
Hello
|
||||
'''
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
discard """
|
||||
targets: "c cpp"
|
||||
file: "tnestedreturn.nim"
|
||||
output: "A\nB\nC\n"
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user