more intuitive behaviour for 'discardable' in expression bodies
This commit is contained in:
parent
af441e607f
commit
f8af7ed6b4
6 changed files with 99 additions and 22 deletions
|
|
@ -1146,10 +1146,9 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||||
# ``result``:
|
# ``result``:
|
||||||
if result.kind == nkSym and result.sym == c.p.resultSym:
|
if result.kind == nkSym and result.sym == c.p.resultSym:
|
||||||
nil
|
nil
|
||||||
elif result.kind == nkNilLit or ImplicitlyDiscardable(result):
|
elif result.kind == nkNilLit:
|
||||||
# intended semantic: if it's 'discardable' and the context allows for it,
|
# or ImplicitlyDiscardable(result):
|
||||||
# discard it. This is bad for chaining but nicer for C wrappers.
|
# new semantic: 'result = x' triggers the void context
|
||||||
# ambiguous :-(
|
|
||||||
result.typ = nil
|
result.typ = nil
|
||||||
elif result.kind == nkStmtListExpr and result.typ.kind == tyNil:
|
elif result.kind == nkStmtListExpr and result.typ.kind == tyNil:
|
||||||
# to keep backwards compatibility bodies like:
|
# to keep backwards compatibility bodies like:
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ proc fixNilType(n: PNode) =
|
||||||
if isAtom(n):
|
if isAtom(n):
|
||||||
if n.kind != nkNilLit and n.typ != nil:
|
if n.kind != nkNilLit and n.typ != nil:
|
||||||
localError(n.info, errDiscardValue)
|
localError(n.info, errDiscardValue)
|
||||||
else:
|
elif n.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
for it in n: fixNilType(it)
|
for it in n: fixNilType(it)
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
|
||||||
|
|
@ -165,7 +165,8 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||||
let j = it.len-1
|
let j = it.len-1
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||||
result.kind = nkIfExpr
|
result.kind = nkIfExpr
|
||||||
result.typ = typ
|
# propagate any enforced VoidContext:
|
||||||
|
result.typ = typ
|
||||||
|
|
||||||
proc semCase(c: PContext, n: PNode): PNode =
|
proc semCase(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -220,7 +221,8 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
let j = it.len-1
|
let j = it.len-1
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
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 =
|
proc semTry(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -264,7 +266,8 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
let j = it.len-1
|
let j = it.len-1
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
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 =
|
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
||||||
result = fitNode(c, typ, n)
|
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)
|
result = semForFields(c, n, call.sons[0].sym.magic)
|
||||||
else:
|
else:
|
||||||
result = semForVars(c, n)
|
result = semForVars(c, n)
|
||||||
|
# propagate any enforced VoidContext:
|
||||||
|
result.typ = n.sons[length-1].typ
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
|
|
||||||
proc semRaise(c: PContext, n: PNode): PNode =
|
proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -1079,9 +1084,13 @@ proc semStmtList(c: PContext, n: PNode): PNode =
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
var voidContext = false
|
var voidContext = false
|
||||||
var last = length-1
|
var last = length-1
|
||||||
while last > 0 and n.sons[last].kind in {nkPragma, nkCommentStmt,
|
# by not allowing for nkCommentStmt etc. we ensure nkStmtListExpr actually
|
||||||
nkNilLit, nkEmpty}:
|
# really *ends* in the expression that produces the type: The compiler now
|
||||||
dec last
|
# 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):
|
for i in countup(0, length - 1):
|
||||||
case n.sons[i].kind
|
case n.sons[i].kind
|
||||||
of nkFinally, nkExceptBranch:
|
of nkFinally, nkExceptBranch:
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,14 @@ qualifiedIdent = symbol ('.' optInd ('type' | 'addr' | symbol))?
|
||||||
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
|
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
|
||||||
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
|
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
|
||||||
castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
|
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
|
identOrLiteral = generalizedLit | symbol
|
||||||
| INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
| INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||||
| UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
| UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||||
|
|
@ -43,7 +50,7 @@ identOrLiteral = generalizedLit | symbol
|
||||||
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||||
| CHAR_LIT
|
| CHAR_LIT
|
||||||
| NIL
|
| NIL
|
||||||
| tupleConstr | arrayConstr | setOrTableConstr
|
| par | arrayConstr | setOrTableConstr
|
||||||
| castExpr
|
| castExpr
|
||||||
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||||
arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
|
arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
|
||||||
|
|
@ -76,7 +83,8 @@ doBlocks = doBlock ^* IND{=}
|
||||||
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||||
expr = (ifExpr
|
expr = (ifExpr
|
||||||
| whenExpr
|
| whenExpr
|
||||||
| caseExpr)
|
| caseExpr
|
||||||
|
| tryStmt)
|
||||||
/ simpleExpr
|
/ simpleExpr
|
||||||
typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
|
typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
|
||||||
| 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
|
| '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
|
- macros as type pragmas
|
||||||
|
- effect propagation for callbacks
|
||||||
- provide tool/API to track leaks/object counts
|
- provide tool/API to track leaks/object counts
|
||||||
- hybrid GC
|
- hybrid GC
|
||||||
- use big blocks in the allocator
|
- use big blocks in the allocator
|
||||||
|
|
@ -52,7 +53,6 @@ version 0.9.X
|
||||||
- improve the compiler as a service
|
- improve the compiler as a service
|
||||||
- better support for macros that rewrite procs
|
- better support for macros that rewrite procs
|
||||||
- macros need access to types and symbols (partially implemented)
|
- macros need access to types and symbols (partially implemented)
|
||||||
- effect propagation for callbacks
|
|
||||||
- perhaps: change comment handling in the AST
|
- perhaps: change comment handling in the AST
|
||||||
- enforce 'simpleExpr' more often --> doesn't work; tkProc is
|
- enforce 'simpleExpr' more often --> doesn't work; tkProc is
|
||||||
part of primary!
|
part of primary!
|
||||||
|
|
|
||||||
|
|
@ -100,12 +100,7 @@ Nimrod plays nice with others
|
||||||
Roadmap to 1.0
|
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
|
Version 0.9.x
|
||||||
* message passing performance will be greatly improved
|
* the symbol binding rules for templates will change
|
||||||
* the syntactic distinction between statements and expressions will be
|
* a shared memory garbage collected heap will be provided
|
||||||
removed
|
|
||||||
* the need for forward declarations may be removed
|
* the need for forward declarations may be removed
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue