refs #15667 improve invalid indentation errors, report when & where = could be missing (#16397)

* refs #15667 improve invalid indentation errors

* also show line info where = is missing

* add test

* add more tests
This commit is contained in:
Timothee Cour
2021-04-10 01:55:39 -05:00
committed by GitHub
parent 1822ed384a
commit 08262206d3
3 changed files with 74 additions and 4 deletions

View File

@@ -163,6 +163,7 @@ proc prettyTok*(tok: Token): string =
else: $tok
proc printTok*(conf: ConfigRef; tok: Token) =
# xxx factor with toLocation
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok)
proc initToken*(L: var Token) =

View File

@@ -44,6 +44,9 @@ type
hasProgress: bool # some while loop requires progress ensurance
lex*: Lexer # The lexer that is used for parsing
tok*: Token # The current token
lineStartPrevious*: int
lineNumberPrevious*: int
bufposPrevious*: int
inPragma*: int # Pragma level
inSemiStmtList*: int
emptyNode: PNode
@@ -77,7 +80,7 @@ proc eat*(p: var Parser, tokType: TokType)
proc skipInd*(p: var Parser)
proc optPar*(p: var Parser)
proc optInd*(p: var Parser, n: PNode)
proc indAndComment*(p: var Parser, n: PNode)
proc indAndComment*(p: var Parser, n: PNode, maybeMissEquals = false)
proc setBaseFlags*(n: PNode, base: NumericalBase)
proc parseSymbol*(p: var Parser, mode = smNormal): PNode
proc parseTry(p: var Parser; isExpr: bool): PNode
@@ -100,6 +103,9 @@ template prettySection(body) =
proc getTok(p: var Parser) =
## Get the next token from the parser's lexer, and store it in the parser's
## `tok` member.
p.lineNumberPrevious = p.lex.lineNumber
p.lineStartPrevious = p.lex.lineStart
p.bufposPrevious = p.lex.bufpos
rawGetTok(p.lex, p.tok)
p.hasProgress = true
when defined(nimpretty):
@@ -223,9 +229,13 @@ proc parLineInfo(p: Parser): TLineInfo =
## Retrieve the line information associated with the parser's current state.
result = getLineInfo(p.lex, p.tok)
proc indAndComment(p: var Parser, n: PNode) =
proc indAndComment(p: var Parser, n: PNode, maybeMissEquals = false) =
if p.tok.indent > p.currInd:
if p.tok.tokType == tkComment: rawSkipComment(p, n)
elif maybeMissEquals:
let col = p.bufposPrevious - p.lineStartPrevious
var info = newLineInfo(p.lex.fileIdx, p.lineNumberPrevious, col)
parMessage(p, "invalid indentation, maybe you forgot a '=' at $1 ?" % [p.lex.config$info])
else: parMessage(p, errInvalidIndentation)
else:
skipComment(p, n)
@@ -1773,13 +1783,14 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
else: result.add(p.emptyNode)
# empty exception tracking:
result.add(p.emptyNode)
if p.tok.tokType == tkEquals and p.validInd:
let maybeMissEquals = p.tok.tokType != tkEquals
if (not maybeMissEquals) and p.validInd:
getTok(p)
skipComment(p, result)
result.add(parseStmt(p))
else:
result.add(p.emptyNode)
indAndComment(p, result)
indAndComment(p, result, maybeMissEquals)
proc newCommentStmt(p: var Parser): PNode =
#| commentStmt = COMMENT

58
tests/parser/t15667.nim Normal file
View File

@@ -0,0 +1,58 @@
discard """
cmd: "nim check $options $file"
action: "reject"
nimout: '''
t15667.nim(23, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(22, 13) ?
t15667.nim(28, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(26, 13) ?
t15667.nim(33, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(31, 25) ?
t15667.nim(42, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(38, 12) ?
t15667.nim(56, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(55, 13) ?
'''
"""
# line 20
block:
proc fn1()
discard
block:
proc fn2()
#
discard
block:
proc fn3() {.exportc.}
#
discard
block: # complex example
proc asdfasdfsd() {. exportc,
inline
.} # foo
#[
bar
]#
discard
block: # xxx this doesn't work yet (only a bare `invalid indentation` error)
proc fn5()
##
discard
block: # ditto
proc fn6*()
## foo bar
runnableExamples: discard
block:
proc fn8()
runnableExamples:
discard
discard