stand-alone except and finally blocks
This is equivalent to the on-error and at-scope-exit operators in other languages
This commit is contained in:
parent
e2221ab310
commit
b1574bb0e0
4 changed files with 69 additions and 30 deletions
|
|
@ -998,7 +998,14 @@ proc parseTry(p: var TParser): PNode =
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
if b.kind == nkFinally: break
|
if b.kind == nkFinally: break
|
||||||
if b == nil: parMessage(p, errTokenExpected, "except")
|
if b == nil: parMessage(p, errTokenExpected, "except")
|
||||||
|
|
||||||
|
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
|
||||||
|
result = newNodeP(kind, p)
|
||||||
|
getTok(p)
|
||||||
|
eat(p, tkColon)
|
||||||
|
skipComment(p, result)
|
||||||
|
addSon(result, parseStmt(p))
|
||||||
|
|
||||||
proc parseFor(p: var TParser): PNode =
|
proc parseFor(p: var TParser): PNode =
|
||||||
result = newNodeP(nkForStmt, p)
|
result = newNodeP(nkForStmt, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -1393,6 +1400,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||||
of tkWhile: result = parseWhile(p)
|
of tkWhile: result = parseWhile(p)
|
||||||
of tkCase: result = parseCase(p)
|
of tkCase: result = parseCase(p)
|
||||||
of tkTry: result = parseTry(p)
|
of tkTry: result = parseTry(p)
|
||||||
|
of tkFinally: result = parseExceptBlock(p, nkFinally)
|
||||||
|
of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
|
||||||
of tkFor: result = parseFor(p)
|
of tkFor: result = parseFor(p)
|
||||||
of tkBlock: result = parseBlock(p)
|
of tkBlock: result = parseBlock(p)
|
||||||
of tkStatic: result = parseStatic(p)
|
of tkStatic: result = parseStatic(p)
|
||||||
|
|
|
||||||
|
|
@ -871,13 +871,33 @@ proc SemStmt(c: PContext, n: PNode): PNode =
|
||||||
of nkBlockStmt: result = semBlock(c, n)
|
of nkBlockStmt: result = semBlock(c, n)
|
||||||
of nkStmtList:
|
of nkStmtList:
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
for i in countup(0, length - 1):
|
for i in countup(0, length - 1):
|
||||||
n.sons[i] = semStmt(c, n.sons[i])
|
case n.sons[i].kind
|
||||||
if n.sons[i].kind in LastBlockStmts:
|
of nkFinally, nkExceptBranch:
|
||||||
for j in countup(i + 1, length - 1):
|
# stand-alone finally and except blocks are
|
||||||
case n.sons[j].kind
|
# transformed into regular try blocks:
|
||||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
#
|
||||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
# var f = fopen("somefile") | var f = fopen("somefile")
|
||||||
|
# finally: fcsole(f) | try:
|
||||||
|
# ... | ...
|
||||||
|
# | finally:
|
||||||
|
# | fclose(f)
|
||||||
|
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
||||||
|
var body = newNodeI(nkStmtList, n.sons[i].info)
|
||||||
|
if i < n.sonsLen - 1:
|
||||||
|
body.sons = n.sons[(i+1)..(-1)]
|
||||||
|
tryStmt.addSon(body)
|
||||||
|
tryStmt.addSon(n.sons[i])
|
||||||
|
n.sons[i] = semTry(c, tryStmt)
|
||||||
|
n.sons.setLen(i+1)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
n.sons[i] = semStmt(c, n.sons[i])
|
||||||
|
if n.sons[i].kind in LastBlockStmts:
|
||||||
|
for j in countup(i + 1, length - 1):
|
||||||
|
case n.sons[j].kind
|
||||||
|
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
||||||
|
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||||
of nkRaiseStmt: result = semRaise(c, n)
|
of nkRaiseStmt: result = semRaise(c, n)
|
||||||
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
||||||
of nkLetSection: result = semVarOrLet(c, n, skLet)
|
of nkLetSection: result = semVarOrLet(c, n, skLet)
|
||||||
|
|
|
||||||
|
|
@ -388,37 +388,37 @@ indentation tokens is already described in the `Lexical Analysis`_ section.
|
||||||
|
|
||||||
Nimrod allows user-definable operators.
|
Nimrod allows user-definable operators.
|
||||||
Binary operators have 10 different levels of precedence.
|
Binary operators have 10 different levels of precedence.
|
||||||
|
|
||||||
Relevant character
|
Relevant character
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
An operator symbol's *relevant character* is its first
|
An operator symbol's *relevant character* is its first
|
||||||
character unless the first character is ``\`` and its length is greater than 1
|
character unless the first character is ``\`` and its length is greater than 1
|
||||||
then it is the second character.
|
then it is the second character.
|
||||||
|
|
||||||
This rule allows to escape operator symbols with ``\`` and keeps the operator's
|
This rule allows to escape operator symbols with ``\`` and keeps the operator's
|
||||||
precedence and associativity; this is useful for meta programming.
|
precedence and associativity; this is useful for meta programming.
|
||||||
|
|
||||||
|
|
||||||
Associativity
|
Associativity
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
All binary operators are left-associative, except binary operators whose
|
All binary operators are left-associative, except binary operators whose
|
||||||
relevant char is ``^``.
|
relevant char is ``^``.
|
||||||
|
|
||||||
Precedence
|
Precedence
|
||||||
----------
|
----------
|
||||||
|
|
||||||
For operators that are not keywords the precedence is determined by the
|
For operators that are not keywords the precedence is determined by the
|
||||||
following rules:
|
following rules:
|
||||||
|
|
||||||
If the operator ends with ``=`` and its relevant character is none of
|
If the operator ends with ``=`` and its relevant character is none of
|
||||||
``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
|
``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
|
||||||
has the lowest precedence.
|
has the lowest precedence.
|
||||||
|
|
||||||
If the operator's relevant character is ``@`` it is a `sigil-like`:idx:
|
If the operator's relevant character is ``@`` it is a `sigil-like`:idx:
|
||||||
operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed
|
operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed
|
||||||
as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
|
as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
|
||||||
|
|
||||||
|
|
||||||
Otherwise precedence is determined by the relevant character.
|
Otherwise precedence is determined by the relevant character.
|
||||||
|
|
@ -1879,6 +1879,15 @@ handled, it is propagated through the call stack. This means that often
|
||||||
the rest of the procedure - that is not within a ``finally`` clause -
|
the rest of the procedure - that is not within a ``finally`` clause -
|
||||||
is not executed (if an exception occurs).
|
is not executed (if an exception occurs).
|
||||||
|
|
||||||
|
`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 = fopen("numbers.txt", "r")
|
||||||
|
finally: fcsole(f)
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
Return statement
|
Return statement
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ Language Additions
|
||||||
- ``when`` expressions are now allowed just like ``if`` expressions.
|
- ``when`` expressions are now allowed just like ``if`` expressions.
|
||||||
- The precedence for operators starting with ``@`` is different now
|
- The precedence for operators starting with ``@`` is different now
|
||||||
allowing for *sigil-like* operators.
|
allowing for *sigil-like* operators.
|
||||||
|
- Stand-alone ``finally`` and ``except`` blocks are now supported.
|
||||||
|
|
||||||
|
|
||||||
2012-02-09 Version 0.8.14 released
|
2012-02-09 Version 0.8.14 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue