diff options
author | Araq <rumpf_a@web.de> | 2012-11-05 08:36:44 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-11-05 08:36:44 +0100 |
commit | 865d9cc6e6df872f7fa1a32536a3ae42c0384d51 (patch) | |
tree | 97e1c47dbaa15a54c9ab78275a78292bb0688fae | |
parent | 42c8fd1fe2e8a045741c18cd02f9410cb7a990f8 (diff) | |
download | Nim-865d9cc6e6df872f7fa1a32536a3ae42c0384d51.tar.gz |
added system.onRaise to support a condition system
-rw-r--r-- | compiler/sempass2.nim | 4 | ||||
-rwxr-xr-x | doc/manual.txt | 65 | ||||
-rwxr-xr-x | lib/system.nim | 9 | ||||
-rwxr-xr-x | lib/system/excpt.nim | 6 | ||||
-rw-r--r-- | tests/run/tonraise.nim | 34 | ||||
-rwxr-xr-x | todo.txt | 4 | ||||
-rwxr-xr-x | web/news.txt | 14 |
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 |