added system.onRaise to support a condition system
This commit is contained in:
parent
42c8fd1fe2
commit
865d9cc6e6
7 changed files with 100 additions and 36 deletions
|
|
@ -157,10 +157,8 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if whichPragma(it) == wEffects:
|
if whichPragma(it) == wEffects:
|
||||||
# list the computed effects up to here:
|
# list the computed effects up to here:
|
||||||
pushInfoContext(n.info)
|
|
||||||
listEffects(tracked)
|
listEffects(tracked)
|
||||||
popInfoContext()
|
|
||||||
|
|
||||||
proc raisesSpec*(n: PNode): PNode =
|
proc raisesSpec*(n: PNode): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
|
|
|
||||||
|
|
@ -1969,29 +1969,6 @@ a special syntactic extension, the ``when`` construct is also available
|
||||||
within ``object`` definitions.
|
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
|
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
|
Return statement
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1941,6 +1941,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
prev: PSafePoint # points to next safe point ON THE STACK
|
prev: PSafePoint # points to next safe point ON THE STACK
|
||||||
status: int
|
status: int
|
||||||
context: C_JmpBuf
|
context: C_JmpBuf
|
||||||
|
raiseAction: proc (e: ref E_Base): bool {.closure.}
|
||||||
|
|
||||||
when defined(initAllocator):
|
when defined(initAllocator):
|
||||||
initAllocator()
|
initAllocator()
|
||||||
|
|
@ -2040,6 +2041,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
var e = getCurrentException()
|
var e = getCurrentException()
|
||||||
return if e == nil: "" else: e.msg
|
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.}
|
{.push stack_trace: off, profiler:off.}
|
||||||
when defined(endb):
|
when defined(endb):
|
||||||
include "system/debugger"
|
include "system/debugger"
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ proc setFrame(s: PFrame) {.compilerRtl, inl.} =
|
||||||
framePtr = s
|
framePtr = s
|
||||||
|
|
||||||
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
|
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
|
||||||
|
s.raiseAction = nil
|
||||||
s.prev = excHandler
|
s.prev = excHandler
|
||||||
excHandler = s
|
excHandler = s
|
||||||
|
|
||||||
|
|
@ -198,8 +199,9 @@ proc raiseExceptionAux(e: ref E_Base) =
|
||||||
if globalRaiseHook != nil:
|
if globalRaiseHook != nil:
|
||||||
if not globalRaiseHook(e): return
|
if not globalRaiseHook(e): return
|
||||||
if excHandler != nil:
|
if excHandler != nil:
|
||||||
pushCurrentException(e)
|
if isNil(excHandler.raiseAction) or excHandler.raiseAction(e):
|
||||||
c_longjmp(excHandler.context, 1)
|
pushCurrentException(e)
|
||||||
|
c_longjmp(excHandler.context, 1)
|
||||||
elif e[] of EOutOfMemory:
|
elif e[] of EOutOfMemory:
|
||||||
writeToStdErr(e.name)
|
writeToStdErr(e.name)
|
||||||
quitOrDebug()
|
quitOrDebug()
|
||||||
|
|
|
||||||
34
tests/run/tonraise.nim
Normal file
34
tests/run/tonraise.nim
Normal file
|
|
@ -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()
|
||||||
4
todo.txt
4
todo.txt
|
|
@ -1,7 +1,7 @@
|
||||||
version 0.9.2
|
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
|
- overloading based on ASTs: 'constraint' should not be in PType but for the
|
||||||
parameter *symbol*
|
parameter *symbol*
|
||||||
|
|
||||||
|
|
@ -96,8 +96,6 @@ Library
|
||||||
Low priority
|
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
|
- change how comments are part of the AST
|
||||||
- ``with proc `+`(x, y: T): T`` for generic code
|
- ``with proc `+`(x, y: T): T`` for generic code
|
||||||
- new feature: ``distinct T with operations``
|
- new feature: ``distinct T with operations``
|
||||||
|
|
|
||||||
14
web/news.txt
14
web/news.txt
|
|
@ -2,10 +2,10 @@
|
||||||
News
|
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
|
Bugfixes
|
||||||
--------
|
--------
|
||||||
|
|
@ -15,6 +15,7 @@ Bugfixes
|
||||||
Library Additions
|
Library Additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Added ``system.onRaise`` to support a condition system.
|
||||||
|
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
|
|
@ -31,8 +32,11 @@ Language Additions
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- ``case expressions`` are now supported.
|
- ``case expressions`` are now supported.
|
||||||
- table constructors now mimic more closely the syntax of case... of...
|
- Table constructors now mimic more closely the syntax of the ``case``
|
||||||
- Nimrod can now infer the return type of a proc from its body
|
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
|
2012-09-23 Version 0.9.0 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue