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
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue