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:
parent
7cbab49645
commit
d24b6667c6
10 changed files with 110 additions and 79 deletions
|
|
@ -1657,6 +1657,20 @@ proc toObject*(typ: PType): PType =
|
||||||
if result.kind == tyRef:
|
if result.kind == tyRef:
|
||||||
result = result.lastSon
|
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 =
|
proc findUnresolvedStatic*(n: PNode): PNode =
|
||||||
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
|
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
|
||||||
return n
|
return n
|
||||||
|
|
|
||||||
|
|
@ -779,91 +779,111 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||||
else:
|
else:
|
||||||
genOrdinalCase(p, t, d)
|
genOrdinalCase(p, t, d)
|
||||||
|
|
||||||
|
|
||||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
# code to generate:
|
# code to generate:
|
||||||
#
|
#
|
||||||
# XXX: There should be a standard dispatch algorithm
|
|
||||||
# that's used both here and with multi-methods
|
|
||||||
#
|
|
||||||
# try
|
# try
|
||||||
# {
|
# {
|
||||||
# myDiv(4, 9);
|
# myDiv(4, 9);
|
||||||
# } catch (NimException& exp) {
|
# } catch (NimExceptionType1&) {
|
||||||
# if (isObj(exp, EIO) {
|
# body
|
||||||
# ...
|
# goto LA_END;
|
||||||
# } else if (isObj(exp, ESystem) {
|
# } catch (NimExceptionType2&) {
|
||||||
# ...
|
# finallyPart()
|
||||||
# finallyPart()
|
# raise;
|
||||||
# raise;
|
# goto LA_END;
|
||||||
# } else {
|
# } catch (NimExceptionType3&) {goto LA1;}
|
||||||
# // general handler
|
# } catch (NimExceptionType4&) {goto LA1;}
|
||||||
# }
|
# } catch (NimExceptionType5&) {goto LA2;}
|
||||||
# }
|
# } catch (NimExceptionType6&) {goto LA2;}
|
||||||
# finallyPart();
|
# 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:
|
if not isEmptyType(t.typ) and d.k == locNone:
|
||||||
getTemp(p, t.typ, d)
|
getTemp(p, t.typ, d)
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
let exc = getTempName(p.module)
|
|
||||||
if getCompilerProc("Exception") != nil:
|
discard cgsym(p.module, "Exception")
|
||||||
discard cgsym(p.module, "Exception")
|
|
||||||
else:
|
|
||||||
discard cgsym(p.module, "E_Base")
|
|
||||||
add(p.nestedTryStmts, t)
|
add(p.nestedTryStmts, t)
|
||||||
startBlock(p, "try {$n")
|
startBlock(p, "try {$n")
|
||||||
expr(p, t.sons[0], d)
|
expr(p, t[0], d)
|
||||||
let length = sonsLen(t)
|
endBlock(p, ropecg(p.module, "}"))
|
||||||
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
|
|
||||||
if optStackTrace in p.options:
|
let end_label = getLabel(p)
|
||||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
|
||||||
inc p.inExceptBlock
|
|
||||||
var i = 1
|
|
||||||
var catchAllPresent = false
|
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:
|
# bug #4230: avoid false sharing between branches:
|
||||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
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 t[i].len == 1:
|
||||||
if blen == 1:
|
|
||||||
# general except section:
|
# general except section:
|
||||||
catchAllPresent = true
|
catchAllPresent = true
|
||||||
startBlock(p)
|
startBlock(p, "catch (...) {$n")
|
||||||
expr(p, t.sons[i].sons[0], d)
|
genExceptBranchBody(t[i][0])
|
||||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
|
||||||
endBlock(p)
|
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:
|
else:
|
||||||
var orExpr: Rope = nil
|
# cpp can't catch multiple types in one statement so we need a label and goto
|
||||||
for j in countup(0, blen - 2):
|
let label = getLabel(p)
|
||||||
assert(t.sons[i].sons[j].kind == nkType)
|
labeled_branches.add((label, t[i][^1]))
|
||||||
if orExpr != nil: add(orExpr, "||")
|
for j in 0..t[i].len-2:
|
||||||
appcg(p.module, orExpr,
|
assert(t[i][j].kind == nkType)
|
||||||
"#isObj($1.exp->m_type, $2)",
|
linefmt(p, cpsStmts, "catch ($1*) {goto $2;}$n",
|
||||||
[exc, genTypeInfo(p.module, t[i][j].typ, t[i][j].info)])
|
[getTypeDesc(p.module, t[i][j].typ), label])
|
||||||
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])
|
|
||||||
|
|
||||||
|
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")
|
line(p, cpsStmts, ~"throw;$n")
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
|
|
||||||
lineF(p, cpsStmts, "}$n", []) # end of catch block
|
# generate labeled branches bodies
|
||||||
dec p.inExceptBlock
|
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)
|
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) =
|
proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
# code to generate:
|
# code to generate:
|
||||||
|
|
|
||||||
|
|
@ -569,6 +569,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||||
elif m.compileToCpp:
|
elif m.compileToCpp:
|
||||||
appcg(m, result, " : public $1 {$n",
|
appcg(m, result, " : public $1 {$n",
|
||||||
[getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
|
[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
|
hasField = true
|
||||||
else:
|
else:
|
||||||
appcg(m, result, " {$n $1 Sup;$n",
|
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,
|
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||||
takeAddr: bool) =
|
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)
|
case analyseObjectWithTypeField(t)
|
||||||
of frNone:
|
of frNone:
|
||||||
discard
|
discard
|
||||||
|
|
|
||||||
|
|
@ -737,16 +737,10 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
localError(n.info, errExprCannotBeRaised)
|
localError(n.info, errExprCannotBeRaised)
|
||||||
|
|
||||||
# check if the given object inherits from Exception
|
# check if the given object inherits from Exception
|
||||||
var base = typ.lastSon
|
if not typ.lastSon.isException():
|
||||||
while true:
|
localError(n.info, "raised object of type $1 does not inherit from Exception",
|
||||||
if base.sym.magic == mException:
|
[typeToString(typ)])
|
||||||
break
|
|
||||||
if base.lastSon == nil:
|
|
||||||
localError(n.info,
|
|
||||||
"raised object of type $1 does not inherit from Exception",
|
|
||||||
[typeToString(typ)])
|
|
||||||
return
|
|
||||||
base = base.lastSon
|
|
||||||
|
|
||||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||||
if n.kind != nkGenericParams: illFormedAst(n)
|
if n.kind != nkGenericParams: illFormedAst(n)
|
||||||
|
|
|
||||||
|
|
@ -274,13 +274,6 @@ __clang__
|
||||||
# endif
|
# endif
|
||||||
# define NIM_BOOL bool
|
# define NIM_BOOL bool
|
||||||
# define NIM_NIL 0
|
# define NIM_NIL 0
|
||||||
struct NimException
|
|
||||||
{
|
|
||||||
NimException(struct Exception* exp, const char* msg): exp(exp), msg(msg) {}
|
|
||||||
|
|
||||||
struct Exception* exp;
|
|
||||||
const char* msg;
|
|
||||||
};
|
|
||||||
#else
|
#else
|
||||||
# ifdef bool
|
# ifdef bool
|
||||||
# define NIM_BOOL bool
|
# define NIM_BOOL bool
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,7 @@ proc raiseExceptionAux(e: ref Exception) =
|
||||||
quitOrDebug()
|
quitOrDebug()
|
||||||
else:
|
else:
|
||||||
pushCurrentException(e)
|
pushCurrentException(e)
|
||||||
{.emit: "throw NimException(`e`, `e`->name);".}
|
{.emit: "`e`->raise();".}
|
||||||
else:
|
else:
|
||||||
if excHandler != nil:
|
if excHandler != nil:
|
||||||
if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
|
if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
|
targets: "c cpp"
|
||||||
output: '''Check passed
|
output: '''Check passed
|
||||||
Check passed'''
|
Check passed'''
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
|
targets: "c cpp"
|
||||||
output: '''Hello
|
output: '''Hello
|
||||||
Hello
|
Hello
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
|
targets: "c cpp"
|
||||||
file: "tnestedreturn.nim"
|
file: "tnestedreturn.nim"
|
||||||
output: "A\nB\nC\n"
|
output: "A\nB\nC\n"
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue