mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-18 23:11:36 +00:00
system.onRaise improvements
This commit is contained in:
236
doc/manual.txt
236
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
|
||||
--------
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user