summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@gmail.com>2017-02-01 00:32:56 +0100
committerDominik Picheta <dominikpicheta@gmail.com>2017-02-01 00:32:56 +0100
commite8c46d29cdfa604bf13294bc3505938fc243754d (patch)
treecc2f8d669a80b65e698c67cd06d2ed18ca0d9ab9
parente88a0af494c0639c134b659ec0080b558c48e2ae (diff)
downloadNim-e8c46d29cdfa604bf13294bc3505938fc243754d.tar.gz
WIP implementation of `except ExcType as ident` syntax. Refs #3691.
-rw-r--r--compiler/ast.nim7
-rw-r--r--compiler/semstmts.nim37
-rw-r--r--compiler/transf.nim31
-rw-r--r--tests/exception/texcas.nim10
4 files changed, 82 insertions, 3 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index d9c886d7f..037de3dff 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1584,6 +1584,13 @@ proc skipStmtList*(n: PNode): PNode =
   else:
     result = n
 
+proc toRef*(typ: PType): PType =
+  result = typ
+  if typ.kind == tyObject:
+    # Convert to a `ref T`.
+    result = newType(tyRef, typ.owner)
+    rawAddSon(result, typ)
+
 when false:
   proc containsNil*(n: PNode): bool =
     # only for debugging
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index bbc83eca4..9d630d4bf 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -263,36 +263,67 @@ proc semTry(c: PContext, n: PNode): PNode =
   result = n
   inc c.p.inTryStmt
   checkMinSonsLen(n, 2)
+
   var typ = commonTypeBegin
   n.sons[0] = semExprBranchScope(c, n.sons[0])
   typ = commonType(typ, n.sons[0].typ)
+
   var check = initIntSet()
   var last = sonsLen(n) - 1
   for i in countup(1, last):
     var a = n.sons[i]
     checkMinSonsLen(a, 1)
     var length = sonsLen(a)
+
     if a.kind == nkExceptBranch:
       # so that ``except [a, b, c]`` is supported:
       if length == 2 and a.sons[0].kind == nkBracket:
         a.sons[0..0] = a.sons[0].sons
         length = a.sonsLen
 
+      # Iterate through each exception type in the except branch.
       for j in countup(0, length-2):
-        var typ = semTypeNode(c, a.sons[j], nil)
+        var typeNode = a.sons[j] # e.g. `Exception`
+        var symbolNode: PNode = nil # e.g. `foobar`
+        # Handle the case where the `Exception as foobar` syntax is used.
+        if typeNode.kind == nkInfix:
+          typeNode = a.sons[j].sons[1]
+          symbolNode = a.sons[j].sons[2]
+
+        # Resolve the type ident into a PType.
+        var typ = semTypeNode(c, typeNode, nil)
+        if not symbolNode.isNil:
+          # Add the exception ident to the symbol table.
+          let symbol = newSymG(skLet, symbolNode, c)
+          symbol.typ = typ.toRef()
+          addDecl(c, symbol)
+          # Overwrite symbol in AST with the symbol in the symbol table.
+          let symNode = newNodeI(nkSym, typeNode.info)
+          symNode.sym = symbol
+          a.sons[j].sons[2] = symNode
+
         if typ.kind == tyRef: typ = typ.sons[0]
         if typ.kind != tyObject:
           localError(a.sons[j].info, errExprCannotBeRaised)
-        a.sons[j] = newNodeI(nkType, a.sons[j].info)
-        a.sons[j].typ = typ
+
+        let newTypeNode = newNodeI(nkType, typeNode.info)
+        if symbolNode.isNil:
+          a.sons[j] = newTypeNode
+          a.sons[j].typ = typ
+        else:
+          a.sons[j].sons[1] = newTypeNode
+          a.sons[j].sons[1].typ = typ
+
         if containsOrIncl(check, typ.id):
           localError(a.sons[j].info, errExceptionAlreadyHandled)
     elif a.kind != nkFinally:
       illFormedAst(n)
+
     # last child of an nkExcept/nkFinally branch is a statement:
     a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
     if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
     else: dec last
+
   dec c.p.inTryStmt
   if isEmptyType(typ) or typ.kind == tyNil:
     discardCheck(c, n.sons[0])
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 6eed17b2a..3ff2fc86a 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -701,6 +701,35 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
     else:
       result = s.PTransNode
 
+proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
+  result = transformSons(c, n)
+  if n[0].kind == nkInfix:
+    let excTypeNode = n[0][1]
+    let actions = newTransNode(nkStmtList, n[1].info, 2)
+    # Generating `let exc = (excType)(getCurrentException())`
+    let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
+    let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
+    convNode[0] = PTransNode(ast.emptyNode)
+    convNode[1] = excCall
+    PNode(convNode).typ = excTypeNode.typ.toRef()
+
+    let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
+    identDefs[0] = PTransNode(n[0][2])
+    identDefs[1] = PTransNode(ast.emptyNode)
+    identDefs[2] = convNode
+
+    let letSection = newTransNode(nkLetSection, n[1].info, 1)
+    letSection[0] = identDefs
+
+    actions[0] = letSection
+    actions[1] = transformSons(c, n[1])
+    result[1] = actions
+
+    # Replace the `Exception as foobar` with just `Exception`.
+    result[0] = result[0][1]
+  #debug(PNode(result))
+  #echo(PNode(result))
+
 proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
   # symbols that expand to a complex constant (array, etc.) should not be
   # inlined, unless it's the empty array:
@@ -851,6 +880,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     if a.kind == nkSym:
       n.sons[1] = transformSymAux(c, a)
     return PTransNode(n)
+  of nkExceptBranch:
+    result = transformExceptBranch(c, n)
   else:
     result = transformSons(c, n)
   when false:
diff --git a/tests/exception/texcas.nim b/tests/exception/texcas.nim
new file mode 100644
index 000000000..ac6e5db62
--- /dev/null
+++ b/tests/exception/texcas.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''Hello'''
+"""
+
+try:
+  raise newException(Exception, "Hello")
+except Exception as foobar:
+  echo(foobar.msg)
+
+