summary refs log tree commit diff stats
path: root/compiler/ccgstmts.nim
diff options
context:
space:
mode:
authorcooldome <cdome@bk.ru>2018-02-12 20:23:34 +0000
committerAndreas Rumpf <rumpf_a@web.de>2018-02-12 21:23:34 +0100
commitd24b6667c6f74b61ea697bf91ce454f297ddac91 (patch)
tree85fed4537dfe34647f4a4800ccea14461ea92857 /compiler/ccgstmts.nim
parent7cbab49645541af01dbd5afac98df637b02a0c0a (diff)
downloadNim-d24b6667c6f74b61ea697bf91ce454f297ddac91.tar.gz
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
Diffstat (limited to 'compiler/ccgstmts.nim')
-rw-r--r--compiler/ccgstmts.nim142
1 files changed, 81 insertions, 61 deletions
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..<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")
-      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: