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:
cooldome
2018-02-12 20:23:34 +00:00
committed by Andreas Rumpf
parent 7cbab49645
commit d24b6667c6
10 changed files with 110 additions and 79 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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",

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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):

View File

@@ -1,4 +1,5 @@
discard """
targets: "c cpp"
output: '''Check passed
Check passed'''
"""

View File

@@ -1,4 +1,5 @@
discard """
targets: "c cpp"
output: '''Hello
Hello
'''

View File

@@ -1,4 +1,5 @@
discard """
targets: "c cpp"
file: "tnestedreturn.nim"
output: "A\nB\nC\n"
"""