mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 07:21:19 +00:00
more intuitive behaviour for 'discardable' in expression bodies
This commit is contained in:
@@ -1146,10 +1146,9 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||
# ``result``:
|
||||
if result.kind == nkSym and result.sym == c.p.resultSym:
|
||||
nil
|
||||
elif result.kind == nkNilLit or ImplicitlyDiscardable(result):
|
||||
# intended semantic: if it's 'discardable' and the context allows for it,
|
||||
# discard it. This is bad for chaining but nicer for C wrappers.
|
||||
# ambiguous :-(
|
||||
elif result.kind == nkNilLit:
|
||||
# or ImplicitlyDiscardable(result):
|
||||
# new semantic: 'result = x' triggers the void context
|
||||
result.typ = nil
|
||||
elif result.kind == nkStmtListExpr and result.typ.kind == tyNil:
|
||||
# to keep backwards compatibility bodies like:
|
||||
|
||||
@@ -120,7 +120,7 @@ proc fixNilType(n: PNode) =
|
||||
if isAtom(n):
|
||||
if n.kind != nkNilLit and n.typ != nil:
|
||||
localError(n.info, errDiscardValue)
|
||||
else:
|
||||
elif n.kind in {nkStmtList, nkStmtListExpr}:
|
||||
for it in n: fixNilType(it)
|
||||
n.typ = nil
|
||||
|
||||
@@ -165,7 +165,8 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||
let j = it.len-1
|
||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||
result.kind = nkIfExpr
|
||||
result.typ = typ
|
||||
# propagate any enforced VoidContext:
|
||||
result.typ = typ
|
||||
|
||||
proc semCase(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -220,7 +221,8 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||
var it = n.sons[i]
|
||||
let j = it.len-1
|
||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||
result.typ = typ
|
||||
# propagate any enforced VoidContext:
|
||||
result.typ = typ
|
||||
|
||||
proc semTry(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -264,7 +266,8 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||
var it = n.sons[i]
|
||||
let j = it.len-1
|
||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||
result.typ = typ
|
||||
# propagate any enforced VoidContext:
|
||||
result.typ = typ
|
||||
|
||||
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
||||
result = fitNode(c, typ, n)
|
||||
@@ -623,6 +626,8 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||
result = semForFields(c, n, call.sons[0].sym.magic)
|
||||
else:
|
||||
result = semForVars(c, n)
|
||||
# propagate any enforced VoidContext:
|
||||
result.typ = n.sons[length-1].typ
|
||||
closeScope(c.tab)
|
||||
|
||||
proc semRaise(c: PContext, n: PNode): PNode =
|
||||
@@ -1079,9 +1084,13 @@ proc semStmtList(c: PContext, n: PNode): PNode =
|
||||
var length = sonsLen(n)
|
||||
var voidContext = false
|
||||
var last = length-1
|
||||
while last > 0 and n.sons[last].kind in {nkPragma, nkCommentStmt,
|
||||
nkNilLit, nkEmpty}:
|
||||
dec last
|
||||
# by not allowing for nkCommentStmt etc. we ensure nkStmtListExpr actually
|
||||
# really *ends* in the expression that produces the type: The compiler now
|
||||
# relies on this fact and it's too much effort to change that. And arguably
|
||||
# 'R(); #comment' shouldn't produce R's type anyway.
|
||||
#while last > 0 and n.sons[last].kind in {nkPragma, nkCommentStmt,
|
||||
# nkNilLit, nkEmpty}:
|
||||
# dec last
|
||||
for i in countup(0, length - 1):
|
||||
case n.sons[i].kind
|
||||
of nkFinally, nkExceptBranch:
|
||||
|
||||
@@ -35,7 +35,14 @@ qualifiedIdent = symbol ('.' optInd ('type' | 'addr' | symbol))?
|
||||
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
|
||||
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
|
||||
castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
|
||||
generalizedLit ::= GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||
parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
|
||||
| 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
| 'when' | 'var' | 'mixin'
|
||||
par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
|
||||
| simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
|
||||
| (':' expr)? (',' (exprColonEqExpr comma?)*)? )?
|
||||
optPar ')'
|
||||
generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||
identOrLiteral = generalizedLit | symbol
|
||||
| INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
| UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||
@@ -43,7 +50,7 @@ identOrLiteral = generalizedLit | symbol
|
||||
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||
| CHAR_LIT
|
||||
| NIL
|
||||
| tupleConstr | arrayConstr | setOrTableConstr
|
||||
| par | arrayConstr | setOrTableConstr
|
||||
| castExpr
|
||||
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||
arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
|
||||
@@ -76,7 +83,8 @@ doBlocks = doBlock ^* IND{=}
|
||||
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||
expr = (ifExpr
|
||||
| whenExpr
|
||||
| caseExpr)
|
||||
| caseExpr
|
||||
| tryStmt)
|
||||
/ simpleExpr
|
||||
typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
|
||||
| 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
|
||||
|
||||
66
tests/run/tstmtexprs.nim
Normal file
66
tests/run/tstmtexprs.nim
Normal file
@@ -0,0 +1,66 @@
|
||||
discard """
|
||||
output: '''(bar: bar)
|
||||
1244
|
||||
6
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
145 23'''
|
||||
"""
|
||||
|
||||
import strutils
|
||||
|
||||
when true:
|
||||
proc test(foo: proc (x, y: int): bool) =
|
||||
echo foo(5, 5)
|
||||
|
||||
|
||||
type Foo = object
|
||||
bar: string
|
||||
|
||||
proc newfoo(): Foo =
|
||||
result.bar = "bar"
|
||||
|
||||
echo($newfoo())
|
||||
|
||||
|
||||
proc retInt(x, y: int): int =
|
||||
if (var yy = 0; yy != 0):
|
||||
echo yy
|
||||
else:
|
||||
echo(try: parseInt("1244") except EINvalidValue: -1)
|
||||
result = case x
|
||||
of 23: 3
|
||||
of 64:
|
||||
case y
|
||||
of 1: 2
|
||||
of 2: 3
|
||||
of 3: 6
|
||||
else: 8
|
||||
else: 1
|
||||
|
||||
echo retInt(64, 3)
|
||||
|
||||
proc buildString(): string =
|
||||
result = ""
|
||||
for x in 'a'..'z':
|
||||
result.add(x)
|
||||
|
||||
echo buildString()
|
||||
|
||||
#test(
|
||||
# proc (x, y: int): bool =
|
||||
# if x == 5: return true
|
||||
# if x == 2: return false
|
||||
# if y == 78: return true
|
||||
#)
|
||||
|
||||
proc q(): int {.discardable.} = 145
|
||||
proc p(): int =
|
||||
q()
|
||||
|
||||
proc p2(a: int): int =
|
||||
# result enforces a void context:
|
||||
if a == 2:
|
||||
result = 23
|
||||
q()
|
||||
|
||||
echo p(), " ", p2(2)
|
||||
2
todo.txt
2
todo.txt
@@ -28,6 +28,7 @@ version 0.9.4
|
||||
=============
|
||||
|
||||
- macros as type pragmas
|
||||
- effect propagation for callbacks
|
||||
- provide tool/API to track leaks/object counts
|
||||
- hybrid GC
|
||||
- use big blocks in the allocator
|
||||
@@ -52,7 +53,6 @@ version 0.9.X
|
||||
- improve the compiler as a service
|
||||
- better support for macros that rewrite procs
|
||||
- macros need access to types and symbols (partially implemented)
|
||||
- effect propagation for callbacks
|
||||
- perhaps: change comment handling in the AST
|
||||
- enforce 'simpleExpr' more often --> doesn't work; tkProc is
|
||||
part of primary!
|
||||
|
||||
@@ -100,12 +100,7 @@ Nimrod plays nice with others
|
||||
Roadmap to 1.0
|
||||
==============
|
||||
|
||||
Version 0.9.2
|
||||
* better interaction between macros, templates and overloading
|
||||
* the symbol binding rules for generics and templates may change again
|
||||
|
||||
Version 0.9.x
|
||||
* message passing performance will be greatly improved
|
||||
* the syntactic distinction between statements and expressions will be
|
||||
removed
|
||||
* the symbol binding rules for templates will change
|
||||
* a shared memory garbage collected heap will be provided
|
||||
* the need for forward declarations may be removed
|
||||
|
||||
Reference in New Issue
Block a user