summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim11
-rw-r--r--compiler/semstmts.nim24
-rw-r--r--compiler/transf.nim9
-rw-r--r--web/news/e031_version_0_16_2.rst16
4 files changed, 41 insertions, 19 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 037de3dff..155113d8a 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1585,12 +1585,21 @@ proc skipStmtList*(n: PNode): PNode =
     result = n
 
 proc toRef*(typ: PType): PType =
+  ## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and
+  ## returned. Otherwise ``typ`` is simply returned as-is.
   result = typ
   if typ.kind == tyObject:
-    # Convert to a `ref T`.
     result = newType(tyRef, typ.owner)
     rawAddSon(result, typ)
 
+proc toObject*(typ: PType): PType =
+  ## If ``typ`` is a tyRef then its immediate son is returned (which in many
+  ## cases should be a ``tyObject``).
+  ## Otherwise ``typ`` is simply returned as-is.
+  result = typ
+  if result.kind == tyRef:
+    result = result.sons[0]
+
 when false:
   proc containsNil*(n: PNode): bool =
     # only for debugging
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 9d630d4bf..f428b4708 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -291,28 +291,24 @@ proc semTry(c: PContext, n: PNode): PNode =
           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]
+        var typ = semTypeNode(c, typeNode, nil).toObject()
         if typ.kind != tyObject:
           localError(a.sons[j].info, errExprCannotBeRaised)
 
         let newTypeNode = newNodeI(nkType, typeNode.info)
+        newTypeNode.typ = typ
         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
+          # 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 containsOrIncl(check, typ.id):
           localError(a.sons[j].info, errExceptionAlreadyHandled)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 3ff2fc86a..3a4e25eb5 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -707,12 +707,14 @@ proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
     let excTypeNode = n[0][1]
     let actions = newTransNode(nkStmtList, n[1].info, 2)
     # Generating `let exc = (excType)(getCurrentException())`
+    # -> getCurrentException()
     let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
+    # -> (excType)
     let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
     convNode[0] = PTransNode(ast.emptyNode)
     convNode[1] = excCall
     PNode(convNode).typ = excTypeNode.typ.toRef()
-
+    # -> let exc = ...
     let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
     identDefs[0] = PTransNode(n[0][2])
     identDefs[1] = PTransNode(ast.emptyNode)
@@ -720,15 +722,14 @@ proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
 
     let letSection = newTransNode(nkLetSection, n[1].info, 1)
     letSection[0] = identDefs
-
+    # Place the let statement and body of the 'except' branch into new stmtList.
     actions[0] = letSection
     actions[1] = transformSons(c, n[1])
+    # Overwrite 'except' branch body with our stmtList.
     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
diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst
index 4d9d99d16..225324c3a 100644
--- a/web/news/e031_version_0_16_2.rst
+++ b/web/news/e031_version_0_16_2.rst
@@ -25,3 +25,19 @@ Compiler Additions
 Language Additions
 ------------------
 
+- The ``try`` statement's ``except`` branches now support the binding of a
+caught exception to a variable:
+
+.. code-block:: nim
+  try:
+    raise newException(Exception, "Hello World")
+  except Exception as exc:
+    echo(exc.msg)
+
+This replaces the ``getCurrentException`` and ``getCurrentExceptionMsg()``
+procedures, although these procedures will remain in the stdlib for the
+foreseeable future. This new language feature is actually implemented using
+these procedures.
+
+In the near future we will be converting all exception types to refs to
+remove the need for the ``newException`` template.