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
commit d24b6667c6
10 changed files with 110 additions and 79 deletions

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: