mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
Better semiStmtList parsing (#15123)
* Better semiStmtList parsing * Add examples from forums and wiki * Move parseIfExpr near parseIfOrWhen * Update grammar
This commit is contained in:
@@ -523,15 +523,21 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode =
|
||||
|
||||
proc complexOrSimpleStmt(p: var Parser): PNode
|
||||
proc simpleExpr(p: var Parser, mode = pmNormal): PNode
|
||||
proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode
|
||||
|
||||
proc semiStmtList(p: var Parser, result: PNode) =
|
||||
inc p.inSemiStmtList
|
||||
result.add(complexOrSimpleStmt(p))
|
||||
# progress guaranteed
|
||||
while p.tok.tokType == tkSemiColon:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(complexOrSimpleStmt(p))
|
||||
withInd(p):
|
||||
# Be lenient with the first stmt/expr
|
||||
result.add if p.tok.tokType == tkIf: parseIfExpr(p, nkIfStmt) else: complexOrSimpleStmt(p)
|
||||
while true:
|
||||
if p.tok.tokType == tkSemiColon:
|
||||
getTok(p)
|
||||
if p.tok.tokType == tkParRi:
|
||||
break
|
||||
elif not (sameInd(p) or realInd(p)):
|
||||
parMessage(p, errInvalidIndentation)
|
||||
result.add complexOrSimpleStmt(p)
|
||||
dec p.inSemiStmtList
|
||||
result.transitionSonsKind(nkStmtListExpr)
|
||||
|
||||
@@ -540,10 +546,10 @@ proc parsePar(p: var Parser): PNode =
|
||||
#| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
#| | 'when' | 'var' | 'mixin'
|
||||
#| par = '(' optInd
|
||||
#| ( &parKeyw complexOrSimpleStmt ^+ ';'
|
||||
#| | ';' complexOrSimpleStmt ^+ ';'
|
||||
#| ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
#| | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
#| | pragmaStmt
|
||||
#| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )
|
||||
#| | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? )
|
||||
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||
#| optPar ')'
|
||||
#
|
||||
@@ -847,64 +853,6 @@ proc simpleExpr(p: var Parser, mode = pmNormal): PNode =
|
||||
when defined(nimpretty):
|
||||
dec p.em.doIndentMore
|
||||
|
||||
proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| condExpr = expr colcom expr optInd
|
||||
#| ('elif' expr colcom expr optInd)*
|
||||
#| 'else' colcom expr
|
||||
#| ifExpr = 'if' condExpr
|
||||
#| whenExpr = 'when' condExpr
|
||||
when true:
|
||||
result = newNodeP(kind, p)
|
||||
while true:
|
||||
getTok(p) # skip `if`, `when`, `elif`
|
||||
var branch = newNodeP(nkElifExpr, p)
|
||||
optInd(p, branch)
|
||||
branch.add(parseExpr(p))
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
skipComment(p, branch)
|
||||
result.add(branch)
|
||||
if p.tok.tokType != tkElif: break # or not sameOrNoInd(p): break
|
||||
if p.tok.tokType == tkElse: # and sameOrNoInd(p):
|
||||
var branch = newNodeP(nkElseExpr, p)
|
||||
eat(p, tkElse)
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
result.add(branch)
|
||||
else:
|
||||
var
|
||||
b: PNode
|
||||
wasIndented = false
|
||||
result = newNodeP(kind, p)
|
||||
|
||||
getTok(p)
|
||||
let branch = newNodeP(nkElifExpr, p)
|
||||
branch.add(parseExpr(p))
|
||||
colcom(p, branch)
|
||||
let oldInd = p.currInd
|
||||
if realInd(p):
|
||||
p.currInd = p.tok.indent
|
||||
wasIndented = true
|
||||
branch.add(parseExpr(p))
|
||||
result.add branch
|
||||
while sameInd(p) or not wasIndented:
|
||||
case p.tok.tokType
|
||||
of tkElif:
|
||||
b = newNodeP(nkElifExpr, p)
|
||||
getTok(p)
|
||||
optInd(p, b)
|
||||
b.add(parseExpr(p))
|
||||
of tkElse:
|
||||
b = newNodeP(nkElseExpr, p)
|
||||
getTok(p)
|
||||
else: break
|
||||
colcom(p, b)
|
||||
b.add(parseStmt(p))
|
||||
result.add(b)
|
||||
if b.kind == nkElseExpr: break
|
||||
if wasIndented:
|
||||
p.currInd = oldInd
|
||||
|
||||
proc parsePragma(p: var Parser): PNode =
|
||||
#| pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}')
|
||||
result = newNodeP(nkPragma, p)
|
||||
@@ -1574,6 +1522,30 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
|
||||
branch.add(parseStmt(p))
|
||||
result.add(branch)
|
||||
|
||||
proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode =
|
||||
#| condExpr = expr colcom expr optInd
|
||||
#| ('elif' expr colcom expr optInd)*
|
||||
#| 'else' colcom expr
|
||||
#| ifExpr = 'if' condExpr
|
||||
#| whenExpr = 'when' condExpr
|
||||
result = newNodeP(kind, p)
|
||||
while true:
|
||||
getTok(p) # skip `if`, `when`, `elif`
|
||||
var branch = newNodeP(nkElifExpr, p)
|
||||
optInd(p, branch)
|
||||
branch.add(parseExpr(p))
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
skipComment(p, branch)
|
||||
result.add(branch)
|
||||
if p.tok.tokType != tkElif: break
|
||||
if p.tok.tokType == tkElse:
|
||||
var branch = newNodeP(nkElseExpr, p)
|
||||
eat(p, tkElse)
|
||||
colcom(p, branch)
|
||||
branch.add(parseStmt(p))
|
||||
result.add(branch)
|
||||
|
||||
proc parseWhile(p: var Parser): PNode =
|
||||
#| whileStmt = 'while' expr colcom stmt
|
||||
result = newNodeP(nkWhileStmt, p)
|
||||
@@ -2269,17 +2241,11 @@ proc parseStmt(p: var Parser): PNode =
|
||||
# deprecate this syntax later
|
||||
break
|
||||
p.hasProgress = false
|
||||
var a = complexOrSimpleStmt(p)
|
||||
if a.kind != nkEmpty:
|
||||
result.add(a)
|
||||
else:
|
||||
# This is done to make the new 'if' expressions work better.
|
||||
# XXX Eventually we need to be more strict here.
|
||||
if p.tok.tokType notin {tkElse, tkElif}:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p)
|
||||
else:
|
||||
break
|
||||
if p.tok.tokType in {tkElse, tkElif}:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
getTok(p)
|
||||
|
||||
result.add complexOrSimpleStmt(p)
|
||||
if not p.hasProgress and p.tok.tokType == tkEof: break
|
||||
else:
|
||||
# the case statement is only needed for better error messages:
|
||||
|
||||
165
tests/parser/tstmtlists.nim
Normal file
165
tests/parser/tstmtlists.nim
Normal file
@@ -0,0 +1,165 @@
|
||||
discard """
|
||||
output: '''
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
hello
|
||||
1
|
||||
hello
|
||||
2
|
||||
hello
|
||||
3
|
||||
hello
|
||||
4
|
||||
hello
|
||||
5
|
||||
hello
|
||||
6
|
||||
hello
|
||||
7
|
||||
hello
|
||||
8
|
||||
hello
|
||||
9
|
||||
hello
|
||||
10
|
||||
hello
|
||||
1
|
||||
hello
|
||||
2
|
||||
hello
|
||||
3
|
||||
hello
|
||||
4
|
||||
hello
|
||||
5
|
||||
hello
|
||||
6
|
||||
hello
|
||||
7
|
||||
hello
|
||||
8
|
||||
hello
|
||||
9
|
||||
hello
|
||||
10
|
||||
'''
|
||||
"""
|
||||
|
||||
block: (
|
||||
discard;
|
||||
echo 1 + 1;
|
||||
)
|
||||
|
||||
block: (
|
||||
discard; #Haha
|
||||
#haha
|
||||
echo 1 + 1;
|
||||
)
|
||||
|
||||
block: (
|
||||
discard;
|
||||
#Hmm
|
||||
echo 1 +
|
||||
1;
|
||||
)
|
||||
|
||||
block: (
|
||||
discard
|
||||
echo "2"
|
||||
)
|
||||
|
||||
block: (
|
||||
discard;
|
||||
echo 1 +
|
||||
1
|
||||
)
|
||||
|
||||
block: (
|
||||
discard
|
||||
echo 1 +
|
||||
1
|
||||
)
|
||||
|
||||
block: (
|
||||
discard;
|
||||
discard
|
||||
)
|
||||
|
||||
block: (
|
||||
discard
|
||||
echo 1 + 1;
|
||||
)
|
||||
|
||||
block: (
|
||||
discard
|
||||
echo 1 + 1;
|
||||
)
|
||||
|
||||
block: (
|
||||
discard
|
||||
echo 1 +
|
||||
1;
|
||||
)
|
||||
|
||||
block: (
|
||||
discard;
|
||||
)
|
||||
|
||||
block: ( discard; echo 1 + #heh
|
||||
1;
|
||||
)
|
||||
|
||||
for i in 1..10:
|
||||
echo "hello"
|
||||
echo i
|
||||
|
||||
for i in 1..10: (
|
||||
echo "hello";
|
||||
echo i;
|
||||
)
|
||||
|
||||
proc square(inSeq: seq[float]): seq[float] = (
|
||||
result = newSeq[float](len(inSeq));
|
||||
for i, v in inSeq: (
|
||||
result[i] = v * v;
|
||||
)
|
||||
)
|
||||
|
||||
proc square2(inSeq: seq[float]): seq[float] =
|
||||
result = newSeq[float](len(inSeq));
|
||||
for i, v in inSeq: (
|
||||
result[i] = v * v;
|
||||
)
|
||||
|
||||
proc cstringCheck(tracked: int; n: int) =
|
||||
if true == false and (let a = high(int); let b = high(int);
|
||||
a.int8 == 8 and a.int8 notin {3..9}):
|
||||
echo(tracked, n)
|
||||
|
||||
template dim: int =
|
||||
(if int.high == 0:
|
||||
int.high
|
||||
else:
|
||||
int.high)
|
||||
|
||||
template dim2: int =
|
||||
(if int.high == 0:
|
||||
int.high
|
||||
else:
|
||||
int.high)
|
||||
|
||||
template dim: int =
|
||||
(
|
||||
if int.high == 0:
|
||||
int.high
|
||||
else:
|
||||
int.high)
|
||||
|
||||
Reference in New Issue
Block a user