From d24b6667c6f74b61ea697bf91ce454f297ddac91 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 12 Feb 2018 20:23:34 +0000 Subject: 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 header --- compiler/ccgstmts.nim | 142 ++++++++++++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 61 deletions(-) (limited to 'compiler/ccgstmts.nim') diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index c085c82db..9c7bced33 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -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.. 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") - 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") + startBlock(p, "catch (...) {$n") + genExceptBranchBody(t[i][0]) 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]) + elif t[i].len == 2: + startBlock(p, "catch ($1*) {$n", getTypeDesc(p.module, t[i][0].typ)) + genExceptBranchBody(t[i][^1]) + endBlock(p) + else: + # 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: -- cgit 1.4.1-2-gfad0