Better semiStmtList parsing (#15123)
* Better semiStmtList parsing * Add examples from forums and wiki * Move parseIfExpr near parseIfOrWhen * Update grammar
This commit is contained in:
parent
10988d4840
commit
f3552b86c1
2 changed files with 209 additions and 78 deletions
|
|
@ -523,15 +523,21 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode =
|
||||||
|
|
||||||
proc complexOrSimpleStmt(p: var Parser): PNode
|
proc complexOrSimpleStmt(p: var Parser): PNode
|
||||||
proc simpleExpr(p: var Parser, mode = pmNormal): PNode
|
proc simpleExpr(p: var Parser, mode = pmNormal): PNode
|
||||||
|
proc parseIfExpr(p: var Parser, kind: TNodeKind): PNode
|
||||||
|
|
||||||
proc semiStmtList(p: var Parser, result: PNode) =
|
proc semiStmtList(p: var Parser, result: PNode) =
|
||||||
inc p.inSemiStmtList
|
inc p.inSemiStmtList
|
||||||
result.add(complexOrSimpleStmt(p))
|
withInd(p):
|
||||||
# progress guaranteed
|
# Be lenient with the first stmt/expr
|
||||||
while p.tok.tokType == tkSemiColon:
|
result.add if p.tok.tokType == tkIf: parseIfExpr(p, nkIfStmt) else: complexOrSimpleStmt(p)
|
||||||
|
while true:
|
||||||
|
if p.tok.tokType == tkSemiColon:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
if p.tok.tokType == tkParRi:
|
||||||
result.add(complexOrSimpleStmt(p))
|
break
|
||||||
|
elif not (sameInd(p) or realInd(p)):
|
||||||
|
parMessage(p, errInvalidIndentation)
|
||||||
|
result.add complexOrSimpleStmt(p)
|
||||||
dec p.inSemiStmtList
|
dec p.inSemiStmtList
|
||||||
result.transitionSonsKind(nkStmtListExpr)
|
result.transitionSonsKind(nkStmtListExpr)
|
||||||
|
|
||||||
|
|
@ -540,10 +546,10 @@ proc parsePar(p: var Parser): PNode =
|
||||||
#| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
#| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||||
#| | 'when' | 'var' | 'mixin'
|
#| | 'when' | 'var' | 'mixin'
|
||||||
#| par = '(' optInd
|
#| par = '(' optInd
|
||||||
#| ( &parKeyw complexOrSimpleStmt ^+ ';'
|
#| ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||||
#| | ';' complexOrSimpleStmt ^+ ';'
|
#| | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||||
#| | pragmaStmt
|
#| | pragmaStmt
|
||||||
#| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )
|
#| | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? )
|
||||||
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||||
#| optPar ')'
|
#| optPar ')'
|
||||||
#
|
#
|
||||||
|
|
@ -847,64 +853,6 @@ proc simpleExpr(p: var Parser, mode = pmNormal): PNode =
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
dec p.em.doIndentMore
|
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 =
|
proc parsePragma(p: var Parser): PNode =
|
||||||
#| pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}')
|
#| pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}')
|
||||||
result = newNodeP(nkPragma, p)
|
result = newNodeP(nkPragma, p)
|
||||||
|
|
@ -1574,6 +1522,30 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
|
||||||
branch.add(parseStmt(p))
|
branch.add(parseStmt(p))
|
||||||
result.add(branch)
|
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 =
|
proc parseWhile(p: var Parser): PNode =
|
||||||
#| whileStmt = 'while' expr colcom stmt
|
#| whileStmt = 'while' expr colcom stmt
|
||||||
result = newNodeP(nkWhileStmt, p)
|
result = newNodeP(nkWhileStmt, p)
|
||||||
|
|
@ -2269,17 +2241,11 @@ proc parseStmt(p: var Parser): PNode =
|
||||||
# deprecate this syntax later
|
# deprecate this syntax later
|
||||||
break
|
break
|
||||||
p.hasProgress = false
|
p.hasProgress = false
|
||||||
var a = complexOrSimpleStmt(p)
|
if p.tok.tokType in {tkElse, tkElif}:
|
||||||
if a.kind != nkEmpty:
|
parMessage(p, errInvalidIndentation)
|
||||||
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)
|
getTok(p)
|
||||||
else:
|
|
||||||
break
|
result.add complexOrSimpleStmt(p)
|
||||||
if not p.hasProgress and p.tok.tokType == tkEof: break
|
if not p.hasProgress and p.tok.tokType == tkEof: break
|
||||||
else:
|
else:
|
||||||
# the case statement is only needed for better error messages:
|
# 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)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue