commit
4285db6e02
8 changed files with 143 additions and 8 deletions
|
|
@ -1585,6 +1585,22 @@ proc skipStmtList*(n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
proc toRef*(typ: PType): PType =
|
||||||
|
## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and
|
||||||
|
## returned. Otherwise ``typ`` is simply returned as-is.
|
||||||
|
result = typ
|
||||||
|
if typ.kind == tyObject:
|
||||||
|
result = newType(tyRef, typ.owner)
|
||||||
|
rawAddSon(result, typ)
|
||||||
|
|
||||||
|
proc toObject*(typ: PType): PType =
|
||||||
|
## If ``typ`` is a tyRef then its immediate son is returned (which in many
|
||||||
|
## cases should be a ``tyObject``).
|
||||||
|
## Otherwise ``typ`` is simply returned as-is.
|
||||||
|
result = typ
|
||||||
|
if result.kind == tyRef:
|
||||||
|
result = result.lastSon
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc containsNil*(n: PNode): bool =
|
proc containsNil*(n: PNode): bool =
|
||||||
# only for debugging
|
# only for debugging
|
||||||
|
|
|
||||||
|
|
@ -434,3 +434,6 @@ proc pickSym*(c: PContext, n: PNode; kind: TSymKind;
|
||||||
if a.kind == kind and flags <= a.flags:
|
if a.kind == kind and flags <= a.flags:
|
||||||
return a
|
return a
|
||||||
a = nextOverloadIter(o, c, n)
|
a = nextOverloadIter(o, c, n)
|
||||||
|
|
||||||
|
proc isInfixAs*(n: PNode): bool =
|
||||||
|
return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"
|
||||||
|
|
@ -338,9 +338,16 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
checkMinSonsLen(a, 1)
|
checkMinSonsLen(a, 1)
|
||||||
var L = sonsLen(a)
|
var L = sonsLen(a)
|
||||||
|
openScope(c)
|
||||||
for j in countup(0, L-2):
|
for j in countup(0, L-2):
|
||||||
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
|
if a.sons[j].isInfixAs():
|
||||||
|
addTempDecl(c, getIdentNode(a.sons[j][2]), skLet)
|
||||||
|
a.sons[j].sons[1] = semGenericStmt(c, a.sons[j][1], flags+{withinTypeDesc}, ctx)
|
||||||
|
else:
|
||||||
|
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
|
||||||
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
of nkVarSection, nkLetSection:
|
of nkVarSection, nkLetSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
|
|
|
||||||
|
|
@ -263,36 +263,64 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
inc c.p.inTryStmt
|
inc c.p.inTryStmt
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
|
|
||||||
var typ = commonTypeBegin
|
var typ = commonTypeBegin
|
||||||
n.sons[0] = semExprBranchScope(c, n.sons[0])
|
n.sons[0] = semExprBranchScope(c, n.sons[0])
|
||||||
typ = commonType(typ, n.sons[0].typ)
|
typ = commonType(typ, n.sons[0].typ)
|
||||||
|
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
var last = sonsLen(n) - 1
|
var last = sonsLen(n) - 1
|
||||||
for i in countup(1, last):
|
for i in countup(1, last):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
checkMinSonsLen(a, 1)
|
checkMinSonsLen(a, 1)
|
||||||
var length = sonsLen(a)
|
var length = sonsLen(a)
|
||||||
|
openScope(c)
|
||||||
if a.kind == nkExceptBranch:
|
if a.kind == nkExceptBranch:
|
||||||
# so that ``except [a, b, c]`` is supported:
|
# so that ``except [a, b, c]`` is supported:
|
||||||
if length == 2 and a.sons[0].kind == nkBracket:
|
if length == 2 and a.sons[0].kind == nkBracket:
|
||||||
a.sons[0..0] = a.sons[0].sons
|
a.sons[0..0] = a.sons[0].sons
|
||||||
length = a.sonsLen
|
length = a.sonsLen
|
||||||
|
|
||||||
|
# Iterate through each exception type in the except branch.
|
||||||
for j in countup(0, length-2):
|
for j in countup(0, length-2):
|
||||||
var typ = semTypeNode(c, a.sons[j], nil)
|
var typeNode = a.sons[j] # e.g. `Exception`
|
||||||
if typ.kind == tyRef: typ = typ.sons[0]
|
var symbolNode: PNode = nil # e.g. `foobar`
|
||||||
|
# Handle the case where the `Exception as foobar` syntax is used.
|
||||||
|
if typeNode.isInfixAs():
|
||||||
|
typeNode = a.sons[j].sons[1]
|
||||||
|
symbolNode = a.sons[j].sons[2]
|
||||||
|
|
||||||
|
# Resolve the type ident into a PType.
|
||||||
|
var typ = semTypeNode(c, typeNode, nil).toObject()
|
||||||
if typ.kind != tyObject:
|
if typ.kind != tyObject:
|
||||||
localError(a.sons[j].info, errExprCannotBeRaised)
|
localError(a.sons[j].info, errExprCannotBeRaised)
|
||||||
a.sons[j] = newNodeI(nkType, a.sons[j].info)
|
|
||||||
a.sons[j].typ = typ
|
let newTypeNode = newNodeI(nkType, typeNode.info)
|
||||||
|
newTypeNode.typ = typ
|
||||||
|
if symbolNode.isNil:
|
||||||
|
a.sons[j] = newTypeNode
|
||||||
|
else:
|
||||||
|
a.sons[j].sons[1] = newTypeNode
|
||||||
|
# Add the exception ident to the symbol table.
|
||||||
|
let symbol = newSymG(skLet, symbolNode, c)
|
||||||
|
symbol.typ = typ.toRef()
|
||||||
|
addDecl(c, symbol)
|
||||||
|
# Overwrite symbol in AST with the symbol in the symbol table.
|
||||||
|
let symNode = newNodeI(nkSym, typeNode.info)
|
||||||
|
symNode.sym = symbol
|
||||||
|
a.sons[j].sons[2] = symNode
|
||||||
|
|
||||||
if containsOrIncl(check, typ.id):
|
if containsOrIncl(check, typ.id):
|
||||||
localError(a.sons[j].info, errExceptionAlreadyHandled)
|
localError(a.sons[j].info, errExceptionAlreadyHandled)
|
||||||
elif a.kind != nkFinally:
|
elif a.kind != nkFinally:
|
||||||
illFormedAst(n)
|
illFormedAst(n)
|
||||||
|
|
||||||
# last child of an nkExcept/nkFinally branch is a statement:
|
# last child of an nkExcept/nkFinally branch is a statement:
|
||||||
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
|
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
|
||||||
if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
|
if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
|
||||||
else: dec last
|
else: dec last
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
dec c.p.inTryStmt
|
dec c.p.inTryStmt
|
||||||
if isEmptyType(typ) or typ.kind == tyNil:
|
if isEmptyType(typ) or typ.kind == tyNil:
|
||||||
discardCheck(c, n.sons[0])
|
discardCheck(c, n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -398,9 +398,15 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
checkMinSonsLen(a, 1)
|
checkMinSonsLen(a, 1)
|
||||||
var L = sonsLen(a)
|
var L = sonsLen(a)
|
||||||
|
openScope(c)
|
||||||
for j in countup(0, L-2):
|
for j in countup(0, L-2):
|
||||||
a.sons[j] = semTemplBody(c, a.sons[j])
|
if a.sons[j].isInfixAs():
|
||||||
|
addLocalDecl(c, a.sons[j].sons[2], skLet)
|
||||||
|
a.sons[j].sons[1] = semTemplBody(c, a.sons[j][1])
|
||||||
|
else:
|
||||||
|
a.sons[j] = semTemplBody(c, a.sons[j])
|
||||||
a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
|
a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
|
||||||
|
closeScope(c)
|
||||||
of nkVarSection: semTemplSomeDecl(c, n, skVar)
|
of nkVarSection: semTemplSomeDecl(c, n, skVar)
|
||||||
of nkLetSection: semTemplSomeDecl(c, n, skLet)
|
of nkLetSection: semTemplSomeDecl(c, n, skLet)
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
import
|
import
|
||||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||||
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
||||||
lambdalifting, sempass2, lowerings
|
lambdalifting, sempass2, lowerings, lookups
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
|
|
@ -701,6 +701,36 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
else:
|
else:
|
||||||
result = s.PTransNode
|
result = s.PTransNode
|
||||||
|
|
||||||
|
proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
|
||||||
|
result = transformSons(c, n)
|
||||||
|
if n[0].isInfixAs():
|
||||||
|
let excTypeNode = n[0][1]
|
||||||
|
let actions = newTransNode(nkStmtList, n[1].info, 2)
|
||||||
|
# Generating `let exc = (excType)(getCurrentException())`
|
||||||
|
# -> getCurrentException()
|
||||||
|
let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
|
||||||
|
# -> (excType)
|
||||||
|
let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
|
||||||
|
convNode[0] = PTransNode(ast.emptyNode)
|
||||||
|
convNode[1] = excCall
|
||||||
|
PNode(convNode).typ = excTypeNode.typ.toRef()
|
||||||
|
# -> let exc = ...
|
||||||
|
let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
|
||||||
|
identDefs[0] = PTransNode(n[0][2])
|
||||||
|
identDefs[1] = PTransNode(ast.emptyNode)
|
||||||
|
identDefs[2] = convNode
|
||||||
|
|
||||||
|
let letSection = newTransNode(nkLetSection, n[1].info, 1)
|
||||||
|
letSection[0] = identDefs
|
||||||
|
# Place the let statement and body of the 'except' branch into new stmtList.
|
||||||
|
actions[0] = letSection
|
||||||
|
actions[1] = transformSons(c, n[1])
|
||||||
|
# Overwrite 'except' branch body with our stmtList.
|
||||||
|
result[1] = actions
|
||||||
|
|
||||||
|
# Replace the `Exception as foobar` with just `Exception`.
|
||||||
|
result[0] = result[0][1]
|
||||||
|
|
||||||
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
||||||
# symbols that expand to a complex constant (array, etc.) should not be
|
# symbols that expand to a complex constant (array, etc.) should not be
|
||||||
# inlined, unless it's the empty array:
|
# inlined, unless it's the empty array:
|
||||||
|
|
@ -851,6 +881,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
if a.kind == nkSym:
|
if a.kind == nkSym:
|
||||||
n.sons[1] = transformSymAux(c, a)
|
n.sons[1] = transformSymAux(c, a)
|
||||||
return PTransNode(n)
|
return PTransNode(n)
|
||||||
|
of nkExceptBranch:
|
||||||
|
result = transformExceptBranch(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
when false:
|
when false:
|
||||||
|
|
|
||||||
25
tests/exception/texcas.nim
Normal file
25
tests/exception/texcas.nim
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
discard """
|
||||||
|
output: '''Hello
|
||||||
|
Hello
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
proc test[T]() =
|
||||||
|
try:
|
||||||
|
raise newException(T, "Hello")
|
||||||
|
except T as foobar:
|
||||||
|
echo(foobar.msg)
|
||||||
|
doAssert(not declared(foobar))
|
||||||
|
|
||||||
|
template testTemplate(excType: typedesc) =
|
||||||
|
try:
|
||||||
|
raise newException(excType, "Hello")
|
||||||
|
except excType as foobar:
|
||||||
|
echo(foobar.msg)
|
||||||
|
doAssert(not declared(foobar))
|
||||||
|
|
||||||
|
proc test2() =
|
||||||
|
testTemplate(Exception)
|
||||||
|
doAssert(not declared(foobar))
|
||||||
|
|
||||||
|
test[Exception]()
|
||||||
|
test2()
|
||||||
|
|
@ -25,6 +25,23 @@ Compiler Additions
|
||||||
Language Additions
|
Language Additions
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- The ``try`` statement's ``except`` branches now support the binding of a
|
||||||
|
caught exception to a variable:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
try:
|
||||||
|
raise newException(Exception, "Hello World")
|
||||||
|
except Exception as exc:
|
||||||
|
echo(exc.msg)
|
||||||
|
|
||||||
|
This replaces the ``getCurrentException`` and ``getCurrentExceptionMsg()``
|
||||||
|
procedures, although these procedures will remain in the stdlib for the
|
||||||
|
foreseeable future. This new language feature is actually implemented using
|
||||||
|
these procedures.
|
||||||
|
|
||||||
|
In the near future we will be converting all exception types to refs to
|
||||||
|
remove the need for the ``newException`` template.
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
@ -88,4 +105,5 @@ via a commit, for a full list see
|
||||||
- Fixed "Cannot implement distinct seq with setLen"
|
- Fixed "Cannot implement distinct seq with setLen"
|
||||||
(`#5090 <https://github.com/nim-lang/Nim/issues/5090>`_)
|
(`#5090 <https://github.com/nim-lang/Nim/issues/5090>`_)
|
||||||
- Fixed "await inside array/dict literal produces invalid code"
|
- Fixed "await inside array/dict literal produces invalid code"
|
||||||
(`#5314 <https://github.com/nim-lang/Nim/issues/5314>`_)
|
(`#5314 <https://github.com/nim-lang/Nim/issues/5314>`_)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue