summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-11-05 08:36:44 +0100
committerAraq <rumpf_a@web.de>2012-11-05 08:36:44 +0100
commit865d9cc6e6df872f7fa1a32536a3ae42c0384d51 (patch)
tree97e1c47dbaa15a54c9ab78275a78292bb0688fae
parent42c8fd1fe2e8a045741c18cd02f9410cb7a990f8 (diff)
downloadNim-865d9cc6e6df872f7fa1a32536a3ae42c0384d51.tar.gz
added system.onRaise to support a condition system
-rw-r--r--compiler/sempass2.nim4
-rwxr-xr-xdoc/manual.txt65
-rwxr-xr-xlib/system.nim9
-rwxr-xr-xlib/system/excpt.nim6
-rw-r--r--tests/run/tonraise.nim34
-rwxr-xr-xtodo.txt4
-rwxr-xr-xweb/news.txt14
7 files changed, 100 insertions, 36 deletions
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 86c7929d9..7c6fcf273 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -157,10 +157,8 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
     var it = n.sons[i]
     if whichPragma(it) == wEffects:
       # list the computed effects up to here:
-      pushInfoContext(n.info)
       listEffects(tracked)
-      popInfoContext()
-
+      
 proc raisesSpec*(n: PNode): PNode =
   for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
diff --git a/doc/manual.txt b/doc/manual.txt
index a85c1e753..1ef3237ec 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -1969,29 +1969,6 @@ a special syntactic extension, the ``when`` construct is also available
 within ``object`` definitions.
 
 
-Raise statement
-~~~~~~~~~~~~~~~
-
-Syntax::
-
-  raiseStmt ::= 'raise' [expr]
-
-Example:
-
-.. code-block:: nimrod
-  raise newEOS("operating system failed")
-
-Apart from built-in operations like array indexing, memory allocation, etc.
-the ``raise`` statement is the only way to raise an exception.
-
-.. XXX document this better!
-
-If no exception name is given, the current exception is `re-raised`:idx:. The
-`ENoExceptionToReraise`:idx: exception is raised if there is no exception to
-re-raise. It follows that the ``raise`` statement *always* raises an
-exception.
-
-
 Try statement
 ~~~~~~~~~~~~~
 
@@ -2060,6 +2037,48 @@ in an implicit try block:
   ...
 
 
+Raise statement
+~~~~~~~~~~~~~~~
+
+Syntax::
+
+  raiseStmt ::= 'raise' [expr]
+
+Example:
+
+.. code-block:: nimrod
+  raise newEOS("operating system failed")
+
+Apart from built-in operations like array indexing, memory allocation, etc.
+the ``raise`` statement is the only way to raise an exception.
+
+.. XXX document this better!
+
+If no exception name is given, the current exception is `re-raised`:idx:. The
+`ENoExceptionToReraise`:idx: exception is raised if there is no exception to
+re-raise. It follows that the ``raise`` statement *always* raises an
+exception (unless a raise hook has been provided).
+
+
+OnRaise builtin
+~~~~~~~~~~~~~~~
+
+``system.onRaise`` can be used to override the behaviour of ``raise`` for a
+single ``try`` statement. `onRaise`:idx: has to be called within the ``try`` 
+statement that should be affected.
+
+This allows for a Lisp-like `condition system`:idx:\:
+
+.. code-block:: nimrod
+  var myFile = open("broken.txt", fmWrite)
+  try:
+    onRaise(proc (e: ref E_Base): bool =
+      stdout.writeln "ok, writing to stdout instead")
+    myFile.writeln "writing to broken file"
+  finally:
+    myFile.close()
+
+
 Return statement
 ~~~~~~~~~~~~~~~~
 
diff --git a/lib/system.nim b/lib/system.nim
index 9caf38614..579cbbc58 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1941,6 +1941,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
       prev: PSafePoint # points to next safe point ON THE STACK
       status: int
       context: C_JmpBuf
+      raiseAction: proc (e: ref E_Base): bool {.closure.}
   
   when defined(initAllocator):
     initAllocator()
@@ -2040,6 +2041,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
       var e = getCurrentException()
       return if e == nil: "" else: e.msg
 
+    proc onRaise*(action: proc(e: ref E_Base): bool{.closure.}) =
+      ## can be used in a ``try`` statement to setup a Lisp-like
+      ## `condition system`:idx:\: This prevents the 'raise' statement to
+      ## raise an exception but instead calls ``action``.
+      ## If ``action`` returns false, the exception has been handled and
+      ## does not propagate further through the call stack.
+      if not isNil(excHandler): excHandler.raiseAction = action
+
   {.push stack_trace: off, profiler:off.}
   when defined(endb):
     include "system/debugger"
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index fd7557ef0..176395975 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -52,6 +52,7 @@ proc setFrame(s: PFrame) {.compilerRtl, inl.} =
   framePtr = s
 
 proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = 
+  s.raiseAction = nil
   s.prev = excHandler
   excHandler = s
 
@@ -198,8 +199,9 @@ proc raiseExceptionAux(e: ref E_Base) =
   if globalRaiseHook != nil:
     if not globalRaiseHook(e): return
   if excHandler != nil:
-    pushCurrentException(e)
-    c_longjmp(excHandler.context, 1)
+    if isNil(excHandler.raiseAction) or excHandler.raiseAction(e):
+      pushCurrentException(e)
+      c_longjmp(excHandler.context, 1)
   elif e[] of EOutOfMemory:
     writeToStdErr(e.name)
     quitOrDebug()
diff --git a/tests/run/tonraise.nim b/tests/run/tonraise.nim
new file mode 100644
index 000000000..1a555dd94
--- /dev/null
+++ b/tests/run/tonraise.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''i: 1
+success'''
+"""
+
+type
+  ESomething = object of E_Base
+  ESomeOtherErr = object of E_Base
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+proc foo() =
+  var i = 0
+  try:
+    inc i
+    onRaise(proc (e: ref E_Base): bool =
+      echo "i: ", i)
+    genErrors("errssor!")
+  except ESomething:
+    echo("ESomething happened")
+  except:
+    echo("Some other error happened")
+    
+  # test that raise handler is gone:
+  try:
+    genErrors("error!")
+  except ESomething:
+    echo "success"
+
+foo()
diff --git a/todo.txt b/todo.txt
index b88eab249..fb2f1c771 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,7 @@
 version 0.9.2
 =============
 
-- implement/generalize the effect system; checked exceptions
+- implement/generalize the effect system; document checked exceptions
 - overloading based on ASTs: 'constraint' should not be in PType but for the
   parameter *symbol*
 
@@ -96,8 +96,6 @@ Library
 Low priority
 ------------
 
-- make 'raiseHook' take a closure and provide push and pop for this
-  --> Lisp-style condition system
 - change how comments are part of the AST
 - ``with proc `+`(x, y: T): T`` for generic code
 - new feature: ``distinct T with operations``
diff --git a/web/news.txt b/web/news.txt
index a3ba80072..2dcf3f913 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -2,10 +2,10 @@
 News
 ====
 
-2012-XX-XX Version 0.9.XX released
-==================================
+2012-XX-XX Version 0.9.2 released
+=================================
 
-Version 0.8.XX has been released! Get it `here <download.html>`_. 
+Version 0.9.2 has been released! Get it `here <download.html>`_. 
 
 Bugfixes
 --------
@@ -15,6 +15,7 @@ Bugfixes
 Library Additions
 -----------------
 
+- Added ``system.onRaise`` to support a condition system.
 
 
 Changes affecting backwards compatibility
@@ -31,8 +32,11 @@ Language Additions
 ------------------
 
 - ``case expressions`` are now supported.
-- table constructors now mimic more closely the syntax of case... of...
-- Nimrod can now infer the return type of a proc from its body
+- Table constructors now mimic more closely the syntax of the ``case`` 
+  statement.
+- Nimrod can now infer the return type of a proc from its body.
+- Exception tracking has been added and the ``doc2`` command annotates possible
+  exceptions for you.
 
 
 2012-09-23 Version 0.9.0 released