diff options
author | Araq <rumpf_a@web.de> | 2012-11-05 19:48:49 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-11-05 19:48:49 +0100 |
commit | e54425b068f57bedaba3f15ff2c843d8570527ad (patch) | |
tree | cb8871df295cbe15577cc5692a41dbe35aaa77b3 | |
parent | 865d9cc6e6df872f7fa1a32536a3ae42c0384d51 (diff) | |
download | Nim-e54425b068f57bedaba3f15ff2c843d8570527ad.tar.gz |
system.onRaise improvements
-rwxr-xr-x | doc/manual.txt | 236 | ||||
-rwxr-xr-x | lib/system.nim | 5 | ||||
-rwxr-xr-x | lib/system/excpt.nim | 6 |
3 files changed, 133 insertions, 114 deletions
diff --git a/doc/manual.txt b/doc/manual.txt index 1ef3237ec..58a080b8c 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1969,116 +1969,6 @@ a special syntactic extension, the ``when`` construct is also available within ``object`` definitions. -Try statement -~~~~~~~~~~~~~ - -Syntax:: - - qualifiedIdent ::= symbol ['.' symbol] - exceptList ::= [qualifiedIdent (comma qualifiedIdent)* [comma]] - tryStmt ::= 'try' ':' stmt - ('except' exceptList ':' stmt)* - ['finally' ':' stmt] - -Example: - -.. code-block:: nimrod - # read the first two lines of a text file that should contain numbers - # and tries to add them - var - f: TFile - if open(f, "numbers.txt"): - try: - var a = readLine(f) - var b = readLine(f) - echo("sum: " & $(parseInt(a) + parseInt(b))) - except EOverflow: - echo("overflow!") - except EInvalidValue: - echo("could not convert string to integer") - except EIO: - echo("IO error!") - except: - echo("Unknown exception!") - finally: - close(f) - - - -The statements after the `try`:idx: are executed in sequential order unless -an exception ``e`` is raised. If the exception type of ``e`` matches any -of the list ``exceptlist`` the corresponding statements are executed. -The statements following the ``except`` clauses are called -`exception handlers`:idx:. - -The empty `except`:idx: clause is executed if there is an exception that is -in no list. It is similar to an ``else`` clause in ``if`` statements. - -If there is a `finally`:idx: clause, it is always executed after the -exception handlers. - -The exception is *consumed* in an exception handler. However, an -exception handler may raise another exception. If the exception is not -handled, it is propagated through the call stack. This means that often -the rest of the procedure - that is not within a ``finally`` clause - -is not executed (if an exception occurs). - - -Except and finally statements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -`except`:idx: and `finally`:idx: can also be used as a stand-alone statements. -Any statements following them in the current block will be considered to be -in an implicit try block: - -.. code-block:: nimrod - var f = open("numbers.txt") - finally: close(f) - ... - - -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 ~~~~~~~~~~~~~~~~ @@ -2781,6 +2671,132 @@ can be recursive or even mutually recursive. Mutually recursive types are only possible within a single ``type`` section. +Exception handling +------------------ + +Try statement +~~~~~~~~~~~~~ + +Syntax:: + + qualifiedIdent ::= symbol ['.' symbol] + exceptList ::= [qualifiedIdent (comma qualifiedIdent)* [comma]] + tryStmt ::= 'try' ':' stmt + ('except' exceptList ':' stmt)* + ['finally' ':' stmt] + +Example: + +.. code-block:: nimrod + # read the first two lines of a text file that should contain numbers + # and tries to add them + var + f: TFile + if open(f, "numbers.txt"): + try: + var a = readLine(f) + var b = readLine(f) + echo("sum: " & $(parseInt(a) + parseInt(b))) + except EOverflow: + echo("overflow!") + except EInvalidValue: + echo("could not convert string to integer") + except EIO: + echo("IO error!") + except: + echo("Unknown exception!") + finally: + close(f) + + + +The statements after the `try`:idx: are executed in sequential order unless +an exception ``e`` is raised. If the exception type of ``e`` matches any +of the list ``exceptlist`` the corresponding statements are executed. +The statements following the ``except`` clauses are called +`exception handlers`:idx:. + +The empty `except`:idx: clause is executed if there is an exception that is +in no list. It is similar to an ``else`` clause in ``if`` statements. + +If there is a `finally`:idx: clause, it is always executed after the +exception handlers. + +The exception is *consumed* in an exception handler. However, an +exception handler may raise another exception. If the exception is not +handled, it is propagated through the call stack. This means that often +the rest of the procedure - that is not within a ``finally`` clause - +is not executed (if an exception occurs). + + +Except and finally statements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`except`:idx: and `finally`:idx: can also be used as a stand-alone statements. +Any statements following them in the current block will be considered to be +in an implicit try block: + +.. code-block:: nimrod + var f = open("numbers.txt") + finally: close(f) + ... + + +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() + + +Exception tracking +~~~~~~~~~~~~~~~~~~ + +Nimrod supports `exception tracking`:idx:. XXX + +- Raises pragma +- Inference rules + * Forwarding rule + * Multi-method rule + * proc type rule +- Effects pragma + + Generics -------- diff --git a/lib/system.nim b/lib/system.nim index 579cbbc58..b4e552701 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 + hasRaiseAction: bool raiseAction: proc (e: ref E_Base): bool {.closure.} when defined(initAllocator): @@ -2047,7 +2048,9 @@ when not defined(EcmaScript) and not defined(NimrodVM): ## 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 + if not isNil(excHandler): + excHandler.hasRaiseAction = true + excHandler.raiseAction = action {.push stack_trace: off, profiler:off.} when defined(endb): diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 176395975..fa2622435 100755 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -51,8 +51,8 @@ proc popFrame {.compilerRtl, inl.} = proc setFrame(s: PFrame) {.compilerRtl, inl.} = framePtr = s -proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = - s.raiseAction = nil +proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = + s.hasRaiseAction = false s.prev = excHandler excHandler = s @@ -199,7 +199,7 @@ proc raiseExceptionAux(e: ref E_Base) = if globalRaiseHook != nil: if not globalRaiseHook(e): return if excHandler != nil: - if isNil(excHandler.raiseAction) or excHandler.raiseAction(e): + if not excHandler.hasRaiseAction or excHandler.raiseAction(e): pushCurrentException(e) c_longjmp(excHandler.context, 1) elif e[] of EOutOfMemory: |