diff options
author | Dominik Picheta <dominikpicheta@gmail.com> | 2017-02-01 00:32:56 +0100 |
---|---|---|
committer | Dominik Picheta <dominikpicheta@gmail.com> | 2017-02-01 00:32:56 +0100 |
commit | e8c46d29cdfa604bf13294bc3505938fc243754d (patch) | |
tree | cc2f8d669a80b65e698c67cd06d2ed18ca0d9ab9 | |
parent | e88a0af494c0639c134b659ec0080b558c48e2ae (diff) | |
download | Nim-e8c46d29cdfa604bf13294bc3505938fc243754d.tar.gz |
WIP implementation of `except ExcType as ident` syntax. Refs #3691.
-rw-r--r-- | compiler/ast.nim | 7 | ||||
-rw-r--r-- | compiler/semstmts.nim | 37 | ||||
-rw-r--r-- | compiler/transf.nim | 31 | ||||
-rw-r--r-- | tests/exception/texcas.nim | 10 |
4 files changed, 82 insertions, 3 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index d9c886d7f..037de3dff 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1584,6 +1584,13 @@ proc skipStmtList*(n: PNode): PNode = else: result = n +proc toRef*(typ: PType): PType = + result = typ + if typ.kind == tyObject: + # Convert to a `ref T`. + result = newType(tyRef, typ.owner) + rawAddSon(result, typ) + when false: proc containsNil*(n: PNode): bool = # only for debugging diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index bbc83eca4..9d630d4bf 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -263,36 +263,67 @@ proc semTry(c: PContext, n: PNode): PNode = result = n inc c.p.inTryStmt checkMinSonsLen(n, 2) + var typ = commonTypeBegin n.sons[0] = semExprBranchScope(c, n.sons[0]) typ = commonType(typ, n.sons[0].typ) + var check = initIntSet() var last = sonsLen(n) - 1 for i in countup(1, last): var a = n.sons[i] checkMinSonsLen(a, 1) var length = sonsLen(a) + if a.kind == nkExceptBranch: # so that ``except [a, b, c]`` is supported: if length == 2 and a.sons[0].kind == nkBracket: a.sons[0..0] = a.sons[0].sons length = a.sonsLen + # Iterate through each exception type in the except branch. for j in countup(0, length-2): - var typ = semTypeNode(c, a.sons[j], nil) + var typeNode = a.sons[j] # e.g. `Exception` + var symbolNode: PNode = nil # e.g. `foobar` + # Handle the case where the `Exception as foobar` syntax is used. + if typeNode.kind == nkInfix: + 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) + if not symbolNode.isNil: + # 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 typ.kind == tyRef: typ = typ.sons[0] if typ.kind != tyObject: 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) + if symbolNode.isNil: + a.sons[j] = newTypeNode + a.sons[j].typ = typ + else: + a.sons[j].sons[1] = newTypeNode + a.sons[j].sons[1].typ = typ + if containsOrIncl(check, typ.id): localError(a.sons[j].info, errExceptionAlreadyHandled) elif a.kind != nkFinally: illFormedAst(n) + # last child of an nkExcept/nkFinally branch is a statement: a.sons[length-1] = semExprBranchScope(c, a.sons[length-1]) if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ) else: dec last + dec c.p.inTryStmt if isEmptyType(typ) or typ.kind == tyNil: discardCheck(c, n.sons[0]) diff --git a/compiler/transf.nim b/compiler/transf.nim index 6eed17b2a..3ff2fc86a 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -701,6 +701,35 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = else: result = s.PTransNode +proc transformExceptBranch(c: PTransf, n: PNode): PTransNode = + result = transformSons(c, n) + if n[0].kind == nkInfix: + let excTypeNode = n[0][1] + let actions = newTransNode(nkStmtList, n[1].info, 2) + # Generating `let exc = (excType)(getCurrentException())` + let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode)) + let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2) + convNode[0] = PTransNode(ast.emptyNode) + convNode[1] = excCall + PNode(convNode).typ = excTypeNode.typ.toRef() + + 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 + + actions[0] = letSection + actions[1] = transformSons(c, n[1]) + result[1] = actions + + # Replace the `Exception as foobar` with just `Exception`. + result[0] = result[0][1] + #debug(PNode(result)) + #echo(PNode(result)) + proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} = # symbols that expand to a complex constant (array, etc.) should not be # inlined, unless it's the empty array: @@ -851,6 +880,8 @@ proc transform(c: PTransf, n: PNode): PTransNode = if a.kind == nkSym: n.sons[1] = transformSymAux(c, a) return PTransNode(n) + of nkExceptBranch: + result = transformExceptBranch(c, n) else: result = transformSons(c, n) when false: diff --git a/tests/exception/texcas.nim b/tests/exception/texcas.nim new file mode 100644 index 000000000..ac6e5db62 --- /dev/null +++ b/tests/exception/texcas.nim @@ -0,0 +1,10 @@ +discard """ + output: '''Hello''' +""" + +try: + raise newException(Exception, "Hello") +except Exception as foobar: + echo(foobar.msg) + + |