diff options
-rw-r--r-- | compiler/semexprs.nim | 7 | ||||
-rw-r--r-- | compiler/semstmts.nim | 23 | ||||
-rw-r--r-- | doc/grammar.txt | 14 | ||||
-rw-r--r-- | tests/run/tstmtexprs.nim | 66 | ||||
-rw-r--r-- | todo.txt | 2 | ||||
-rw-r--r-- | web/index.txt | 9 |
6 files changed, 99 insertions, 22 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2ac603920..93dfc2f37 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4146b69a1..bca77e06a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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: diff --git a/doc/grammar.txt b/doc/grammar.txt index 59ae5b073..217007281 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -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' diff --git a/tests/run/tstmtexprs.nim b/tests/run/tstmtexprs.nim new file mode 100644 index 000000000..a69acd98b --- /dev/null +++ b/tests/run/tstmtexprs.nim @@ -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) diff --git a/todo.txt b/todo.txt index 9189e037f..764ba1e13 100644 --- a/todo.txt +++ b/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! diff --git a/web/index.txt b/web/index.txt index 99beb3743..9b90e94de 100644 --- a/web/index.txt +++ b/web/index.txt @@ -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 |