nimsuggest: fixes nimsuggest bug #45; do not show suggestions in string literals or comments

This commit is contained in:
Araq 2017-03-08 12:53:21 +01:00
commit 1887390b0f
4 changed files with 96 additions and 7 deletions

View file

@ -642,10 +642,21 @@ proc handleCRLF(L: var TLexer, pos: int): int =
result = nimlexbase.handleLF(L, pos) result = nimlexbase.handleLF(L, pos)
else: result = pos else: result = pos
template tokenRange(colA, pos) =
when defined(nimsuggest):
let colB = getColNumber(L, pos)
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
L.lineNumber == gTrackPos.line and gIdeCmd == ideSug:
gTrackPos.fileIndex = trackPosInvalidFileIdx
gTrackPos.line = -1
colA = 0
proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
var pos = L.bufpos + 1 # skip " var pos = L.bufpos + 1 # skip "
var buf = L.buf # put `buf` in a register var buf = L.buf # put `buf` in a register
var line = L.lineNumber # save linenumber for better error message var line = L.lineNumber # save linenumber for better error message
when defined(nimsuggest):
var colA = getColNumber(L, pos)
if buf[pos] == '\"' and buf[pos+1] == '\"': if buf[pos] == '\"' and buf[pos+1] == '\"':
tok.tokType = tkTripleStrLit # long string literal: tok.tokType = tkTripleStrLit # long string literal:
inc(pos, 2) # skip "" inc(pos, 2) # skip ""
@ -661,15 +672,18 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
of '\"': of '\"':
if buf[pos+1] == '\"' and buf[pos+2] == '\"' and if buf[pos+1] == '\"' and buf[pos+2] == '\"' and
buf[pos+3] != '\"': buf[pos+3] != '\"':
tokenRange(colA, pos+2)
L.bufpos = pos + 3 # skip the three """ L.bufpos = pos + 3 # skip the three """
break break
add(tok.literal, '\"') add(tok.literal, '\"')
inc(pos) inc(pos)
of CR, LF: of CR, LF:
tokenRange(colA, pos)
pos = handleCRLF(L, pos) pos = handleCRLF(L, pos)
buf = L.buf buf = L.buf
add(tok.literal, tnl) add(tok.literal, tnl)
of nimlexbase.EndOfFile: of nimlexbase.EndOfFile:
tokenRange(colA, pos)
var line2 = L.lineNumber var line2 = L.lineNumber
L.lineNumber = line L.lineNumber = line
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart) lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
@ -690,9 +704,11 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
inc(pos, 2) inc(pos, 2)
add(tok.literal, '"') add(tok.literal, '"')
else: else:
tokenRange(colA, pos)
inc(pos) # skip '"' inc(pos) # skip '"'
break break
elif c in {CR, LF, nimlexbase.EndOfFile}: elif c in {CR, LF, nimlexbase.EndOfFile}:
tokenRange(colA, pos)
lexMessage(L, errClosingQuoteExpected) lexMessage(L, errClosingQuoteExpected)
break break
elif (c == '\\') and not rawMode: elif (c == '\\') and not rawMode:
@ -787,6 +803,8 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
var pos = start var pos = start
var buf = L.buf var buf = L.buf
var toStrip = 0 var toStrip = 0
when defined(nimsuggest):
var colA = getColNumber(L, pos)
# detect the amount of indentation: # detect the amount of indentation:
if isDoc: if isDoc:
toStrip = getColNumber(L, pos) toStrip = getColNumber(L, pos)
@ -813,17 +831,20 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
if isDoc: if isDoc:
if buf[pos+1] == '#' and buf[pos+2] == '#': if buf[pos+1] == '#' and buf[pos+2] == '#':
if nesting == 0: if nesting == 0:
tokenRange(colA, pos+2)
inc(pos, 3) inc(pos, 3)
break break
dec nesting dec nesting
tok.literal.add ']' tok.literal.add ']'
elif buf[pos+1] == '#': elif buf[pos+1] == '#':
if nesting == 0: if nesting == 0:
tokenRange(colA, pos+1)
inc(pos, 2) inc(pos, 2)
break break
dec nesting dec nesting
inc pos inc pos
of CR, LF: of CR, LF:
tokenRange(colA, pos)
pos = handleCRLF(L, pos) pos = handleCRLF(L, pos)
buf = L.buf buf = L.buf
# strip leading whitespace: # strip leading whitespace:
@ -835,6 +856,7 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
inc pos inc pos
dec c dec c
of nimlexbase.EndOfFile: of nimlexbase.EndOfFile:
tokenRange(colA, pos)
lexMessagePos(L, errGenerated, pos, "end of multiline comment expected") lexMessagePos(L, errGenerated, pos, "end of multiline comment expected")
break break
else: else:
@ -845,6 +867,8 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
proc scanComment(L: var TLexer, tok: var TToken) = proc scanComment(L: var TLexer, tok: var TToken) =
var pos = L.bufpos var pos = L.bufpos
var buf = L.buf var buf = L.buf
when defined(nimsuggest):
var colA = getColNumber(L, pos)
tok.tokType = tkComment tok.tokType = tkComment
# iNumber contains the number of '\n' in the token # iNumber contains the number of '\n' in the token
tok.iNumber = 0 tok.iNumber = 0
@ -865,7 +889,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
if buf[pos] == '\\': lastBackslash = pos+1 if buf[pos] == '\\': lastBackslash = pos+1
add(tok.literal, buf[pos]) add(tok.literal, buf[pos])
inc(pos) inc(pos)
tokenRange(colA, pos)
pos = handleCRLF(L, pos) pos = handleCRLF(L, pos)
buf = L.buf buf = L.buf
var indent = 0 var indent = 0
@ -884,6 +908,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
else: else:
if buf[pos] > ' ': if buf[pos] > ' ':
L.indentAhead = indent L.indentAhead = indent
tokenRange(colA, pos)
break break
L.bufpos = pos L.bufpos = pos
@ -926,7 +951,10 @@ proc skip(L: var TLexer, tok: var TToken) =
pos = L.bufpos pos = L.bufpos
buf = L.buf buf = L.buf
else: else:
when defined(nimsuggest):
var colA = getColNumber(L, pos)
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos) while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
tokenRange(colA, pos)
else: else:
break # EndOfFile also leaves the loop break # EndOfFile also leaves the loop
L.bufpos = pos L.bufpos = pos
@ -993,6 +1021,12 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
tok.tokType = tkBracketRi tok.tokType = tkBracketRi
inc(L.bufpos) inc(L.bufpos)
of '.': of '.':
when defined(nimsuggest):
if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
tok.line == gTrackPos.line and gIdeCmd == ideSug:
tok.tokType = tkDot
inc(L.bufpos)
return
if L.buf[L.bufpos+1] == ']': if L.buf[L.bufpos+1] == ']':
tok.tokType = tkBracketDotRi tok.tokType = tkBracketDotRi
inc(L.bufpos, 2) inc(L.bufpos, 2)

View file

@ -736,6 +736,8 @@ proc `??`* (info: TLineInfo, filename: string): bool =
# only for debugging purposes # only for debugging purposes
result = filename in info.toFilename result = filename in info.toFilename
const trackPosInvalidFileIdx* = -2 # special marker so that no suggestions
# are produced within comments and string literals
var gTrackPos*: TLineInfo var gTrackPos*: TLineInfo
type type

View file

@ -33,6 +33,7 @@ type
currInd: int # current indentation level currInd: int # current indentation level
firstTok, strongSpaces: bool # Has the first token been read? firstTok, strongSpaces: bool # Has the first token been read?
# Is strongSpaces on? # Is strongSpaces on?
hasProgress: bool # some while loop requires progress ensurance
lex*: TLexer # The lexer that is used for parsing lex*: TLexer # The lexer that is used for parsing
tok*: TToken # The current token tok*: TToken # The current token
inPragma*: int # Pragma level inPragma*: int # Pragma level
@ -71,6 +72,7 @@ proc getTok(p: var TParser) =
## Get the next token from the parser's lexer, and store it in the parser's ## Get the next token from the parser's lexer, and store it in the parser's
## `tok` member. ## `tok` member.
rawGetTok(p.lex, p.tok) rawGetTok(p.lex, p.tok)
p.hasProgress = true
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream, proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
cache: IdentCache; cache: IdentCache;
@ -310,6 +312,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
of tkAccent: of tkAccent:
result = newNodeP(nkAccQuoted, p) result = newNodeP(nkAccQuoted, p)
getTok(p) getTok(p)
# progress guaranteed
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkAccent: of tkAccent:
@ -339,7 +342,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
# BUGFIX: We must consume a token here to prevent endless loops! # BUGFIX: We must consume a token here to prevent endless loops!
# But: this really sucks for idetools and keywords, so we don't do it # But: this really sucks for idetools and keywords, so we don't do it
# if it is a keyword: # if it is a keyword:
if not isKeyword(p.tok.tokType): getTok(p) #if not isKeyword(p.tok.tokType): getTok(p)
result = ast.emptyNode result = ast.emptyNode
proc colonOrEquals(p: var TParser, a: PNode): PNode = proc colonOrEquals(p: var TParser, a: PNode): PNode =
@ -367,6 +370,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
#| exprList = expr ^+ comma #| exprList = expr ^+ comma
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
var a = parseExpr(p) var a = parseExpr(p)
addSon(result, a) addSon(result, a)
@ -392,6 +396,7 @@ proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed
while p.tok.tokType != endTok and p.tok.tokType != tkEof: while p.tok.tokType != endTok and p.tok.tokType != tkEof:
var a = exprColonEqExpr(p) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
@ -416,6 +421,7 @@ proc setOrTableConstr(p: var TParser): PNode =
getTok(p) # skip ':' getTok(p) # skip ':'
result.kind = nkTableConstr result.kind = nkTableConstr
else: else:
# progress guaranteed
while p.tok.tokType notin {tkCurlyRi, tkEof}: while p.tok.tokType notin {tkCurlyRi, tkEof}:
var a = exprColonEqExpr(p) var a = exprColonEqExpr(p)
if a.kind == nkExprColonExpr: result.kind = nkTableConstr if a.kind == nkExprColonExpr: result.kind = nkTableConstr
@ -472,6 +478,7 @@ proc simpleExpr(p: var TParser, mode = pmNormal): PNode
proc semiStmtList(p: var TParser, result: PNode) = proc semiStmtList(p: var TParser, result: PNode) =
inc p.inSemiStmtList inc p.inSemiStmtList
result.add(complexOrSimpleStmt(p)) result.add(complexOrSimpleStmt(p))
# progress guaranteed
while p.tok.tokType == tkSemiColon: while p.tok.tokType == tkSemiColon:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -533,6 +540,7 @@ proc parsePar(p: var TParser): PNode =
if p.tok.tokType == tkComma: if p.tok.tokType == tkComma:
getTok(p) getTok(p)
skipComment(p, a) skipComment(p, a)
# progress guaranteed
while p.tok.tokType != tkParRi and p.tok.tokType != tkEof: while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
var a = exprColonEqExpr(p) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
@ -657,6 +665,7 @@ proc namedParams(p: var TParser, callee: PNode,
let a = callee let a = callee
result = newNodeP(kind, p) result = newNodeP(kind, p)
addSon(result, a) addSon(result, a)
# progress guaranteed
exprColonEqExprListAux(p, endTok, result) exprColonEqExprListAux(p, endTok, result)
proc parseMacroColon(p: var TParser, x: PNode): PNode proc parseMacroColon(p: var TParser, x: PNode): PNode
@ -676,10 +685,12 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
else: else:
parMessage(p, warnDeprecated, parMessage(p, warnDeprecated,
"a [b] will be parsed as command syntax; spacing") "a [b] will be parsed as command syntax; spacing")
# progress guaranteed
while p.tok.indent < 0 or while p.tok.indent < 0 or
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent): (p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
case p.tok.tokType case p.tok.tokType
of tkParLe: of tkParLe:
# progress guaranteed
somePar() somePar()
result = namedParams(p, result, nkCall, tkParRi) result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr: if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
@ -687,17 +698,21 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
else: else:
parseDoBlocks(p, result) parseDoBlocks(p, result)
of tkDo: of tkDo:
# progress guaranteed
var a = result var a = result
result = newNodeP(nkCall, p) result = newNodeP(nkCall, p)
addSon(result, a) addSon(result, a)
parseDoBlocks(p, result) parseDoBlocks(p, result)
of tkDot: of tkDot:
# progress guaranteed
result = dotExpr(p, result) result = dotExpr(p, result)
result = parseGStrLit(p, result) result = parseGStrLit(p, result)
of tkBracketLe: of tkBracketLe:
# progress guaranteed
somePar() somePar()
result = namedParams(p, result, nkBracketExpr, tkBracketRi) result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe: of tkCurlyLe:
# progress guaranteed
somePar() somePar()
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
@ -708,7 +723,10 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
result = newNodeP(nkCommand, p) result = newNodeP(nkCommand, p)
addSon(result, a) addSon(result, a)
when true: when true:
# progress NOT guaranteed
p.hasProgress = false
addSon result, parseExpr(p) addSon result, parseExpr(p)
if not p.hasProgress: break
else: else:
while p.tok.tokType != tkEof: while p.tok.tokType != tkEof:
let x = parseExpr(p) let x = parseExpr(p)
@ -734,6 +752,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
var opPrec = getPrecedence(p.tok, p.strongSpaces) var opPrec = getPrecedence(p.tok, p.strongSpaces)
let modeB = if mode == pmTypeDef: pmTypeDesc else: mode let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
# the operator itself must not start on a new line: # the operator itself must not start on a new line:
# progress guaranteed
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p): while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
checkBinary(p) checkBinary(p)
var leftAssoc = 1-ord(isRightAssociative(p.tok)) var leftAssoc = 1-ord(isRightAssociative(p.tok))
@ -785,7 +804,9 @@ proc parsePragma(p: var TParser): PNode =
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}: while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
p.hasProgress = false
var a = exprColonEqExpr(p) var a = exprColonEqExpr(p)
if not p.hasProgress: break
addSon(result, a) addSon(result, a)
if p.tok.tokType == tkComma: if p.tok.tokType == tkComma:
getTok(p) getTok(p)
@ -833,6 +854,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
#| (':' optInd typeDesc)? ('=' optInd expr)?) #| (':' optInd typeDesc)? ('=' optInd expr)?)
var a: PNode var a: PNode
result = newNodeP(nkIdentDefs, p) result = newNodeP(nkIdentDefs, p)
# progress guaranteed
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
@ -870,6 +892,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
if p.tok.tokType == tkBracketLe: if p.tok.tokType == tkBracketLe:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}: while p.tok.tokType in {tkSymbol, tkAccent}:
var a = parseIdentColonEquals(p, {}) var a = parseIdentColonEquals(p, {})
addSon(result, a) addSon(result, a)
@ -883,6 +906,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
if realInd(p): if realInd(p):
withInd(p): withInd(p):
rawSkipComment(p, result) rawSkipComment(p, result)
# progress guaranteed
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
@ -909,6 +933,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
if hasParLe: if hasParLe:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
@ -989,6 +1014,7 @@ proc isExprStart(p: TParser): bool =
else: result = false else: result = false
proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) = proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
# progress guaranteed
while true: while true:
var s = parseSymbol(p, allowNil) var s = parseSymbol(p, allowNil)
if s.kind == nkEmpty: break if s.kind == nkEmpty: break
@ -1147,6 +1173,7 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
let body = parseStmt(p) let body = parseStmt(p)
stmtList.add body stmtList.add body
#addSon(result, makeStmtList(body)) #addSon(result, makeStmtList(body))
# progress guaranteed
while sameInd(p): while sameInd(p):
var b: PNode var b: PNode
case p.tok.tokType case p.tok.tokType
@ -1246,8 +1273,9 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
optInd(p, result) optInd(p, result)
while true: while true:
# was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
p.hasProgress = false
a = parseModuleName(p, kind) a = parseModuleName(p, kind)
if a.kind == nkEmpty: break if a.kind == nkEmpty or not p.hasProgress: break
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -1261,8 +1289,9 @@ proc parseIncludeStmt(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
while true: while true:
# was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
p.hasProgress = false
var a = parseExpr(p) var a = parseExpr(p)
if a.kind == nkEmpty: break if a.kind == nkEmpty or not p.hasProgress: break
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -1280,8 +1309,9 @@ proc parseFromStmt(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
while true: while true:
# p.tok.tokType notin {tkEof, tkSad, tkDed}: # p.tok.tokType notin {tkEof, tkSad, tkDed}:
p.hasProgress = false
a = parseExpr(p) a = parseExpr(p)
if a.kind == nkEmpty: break if a.kind == nkEmpty or not p.hasProgress: break
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -1474,6 +1504,7 @@ proc parseGenericParam(p: var TParser): PNode =
#| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)? #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
var a: PNode var a: PNode
result = newNodeP(nkIdentDefs, p) result = newNodeP(nkIdentDefs, p)
# progress guaranteed
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
@ -1503,6 +1534,7 @@ proc parseGenericParamList(p: var TParser): PNode =
result = newNodeP(nkGenericParams, p) result = newNodeP(nkGenericParams, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}: while p.tok.tokType in {tkSymbol, tkAccent}:
var a = parseGenericParam(p) var a = parseGenericParam(p)
addSon(result, a) addSon(result, a)
@ -1566,6 +1598,7 @@ proc parseSection(p: var TParser, kind: TNodeKind,
if realInd(p): if realInd(p):
withInd(p): withInd(p):
skipComment(p, result) skipComment(p, result)
# progress guaranteed
while sameInd(p): while sameInd(p):
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent, tkParLe: of tkSymbol, tkAccent, tkParLe:
@ -1607,6 +1640,7 @@ proc parseEnum(p: var TParser): PNode =
addSon(result, ast.emptyNode) addSon(result, ast.emptyNode)
optInd(p, result) optInd(p, result)
flexComment(p, result) flexComment(p, result)
# progress guaranteed
while true: while true:
var a = parseSymbol(p) var a = parseSymbol(p)
if a.kind == nkEmpty: return if a.kind == nkEmpty: return
@ -1641,6 +1675,7 @@ proc parseObjectWhen(p: var TParser): PNode =
#| ('elif' expr colcom objectPart COMMENT?)* #| ('elif' expr colcom objectPart COMMENT?)*
#| ('else' colcom objectPart COMMENT?)? #| ('else' colcom objectPart COMMENT?)?
result = newNodeP(nkRecWhen, p) result = newNodeP(nkRecWhen, p)
# progress guaranteed
while sameInd(p): while sameInd(p):
getTok(p) # skip `when`, `elif` getTok(p) # skip `when`, `elif`
var branch = newNodeP(nkElifBranch, p) var branch = newNodeP(nkElifBranch, p)
@ -1682,6 +1717,7 @@ proc parseObjectCase(p: var TParser): PNode =
if realInd(p): if realInd(p):
p.currInd = p.tok.indent p.currInd = p.tok.indent
wasIndented = true wasIndented = true
# progress guaranteed
while sameInd(p): while sameInd(p):
var b: PNode var b: PNode
case p.tok.tokType case p.tok.tokType
@ -1783,6 +1819,7 @@ proc parseTypeClass(p: var TParser): PNode =
if p.tok.tokType == tkOf and p.tok.indent < 0: if p.tok.tokType == tkOf and p.tok.indent < 0:
var a = newNodeP(nkOfInherit, p) var a = newNodeP(nkOfInherit, p)
getTok(p) getTok(p)
# progress guaranteed
while true: while true:
addSon(a, parseTypeDesc(p)) addSon(a, parseTypeDesc(p))
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
@ -1821,6 +1858,7 @@ proc parseVarTuple(p: var TParser): PNode =
result = newNodeP(nkVarTuple, p) result = newNodeP(nkVarTuple, p)
getTok(p) # skip '(' getTok(p) # skip '('
optInd(p, result) optInd(p, result)
# progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}: while p.tok.tokType in {tkSymbol, tkAccent}:
var a = identWithPragma(p) var a = identWithPragma(p)
addSon(result, a) addSon(result, a)
@ -1846,6 +1884,7 @@ proc parseBind(p: var TParser, k: TNodeKind): PNode =
result = newNodeP(k, p) result = newNodeP(k, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed
while true: while true:
var a = qualifiedIdent(p) var a = qualifiedIdent(p)
addSon(result, a) addSon(result, a)
@ -1961,8 +2000,10 @@ proc parseStmt(p: var TParser): PNode =
# XXX this ensures tnamedparamanonproc still compiles; # XXX this ensures tnamedparamanonproc still compiles;
# deprecate this syntax later # deprecate this syntax later
break break
p.hasProgress = false
var a = complexOrSimpleStmt(p) var a = complexOrSimpleStmt(p)
if a.kind != nkEmpty: if not p.hasProgress and p.tok.tokType == tkEof: break
if a.kind != nkEmpty and p.hasProgress:
addSon(result, a) addSon(result, a)
else: else:
parMessage(p, errExprExpected, p.tok) parMessage(p, errExprExpected, p.tok)
@ -1983,18 +2024,22 @@ proc parseStmt(p: var TParser): PNode =
while true: while true:
if p.tok.indent >= 0: if p.tok.indent >= 0:
parMessage(p, errInvalidIndentation) parMessage(p, errInvalidIndentation)
p.hasProgress = false
let a = simpleStmt(p) let a = simpleStmt(p)
let err = not p.hasProgress
if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
result.add(a) result.add(a)
if p.tok.tokType != tkSemiColon: break if p.tok.tokType != tkSemiColon: break
getTok(p) getTok(p)
if err and p.tok.tokType == tkEof: break
proc parseAll(p: var TParser): PNode = proc parseAll(p: var TParser): PNode =
## Parses the rest of the input stream held by the parser into a PNode. ## Parses the rest of the input stream held by the parser into a PNode.
result = newNodeP(nkStmtList, p) result = newNodeP(nkStmtList, p)
while p.tok.tokType != tkEof: while p.tok.tokType != tkEof:
p.hasProgress = false
var a = complexOrSimpleStmt(p) var a = complexOrSimpleStmt(p)
if a.kind != nkEmpty: if a.kind != nkEmpty and p.hasProgress:
addSon(result, a) addSon(result, a)
else: else:
parMessage(p, errExprExpected, p.tok) parMessage(p, errExprExpected, p.tok)
@ -2007,6 +2052,7 @@ proc parseTopLevelStmt(p: var TParser): PNode =
## Implements an iterator which, when called repeatedly, returns the next ## Implements an iterator which, when called repeatedly, returns the next
## top-level statement or emptyNode if end of stream. ## top-level statement or emptyNode if end of stream.
result = ast.emptyNode result = ast.emptyNode
# progress guaranteed
while true: while true:
if p.tok.indent != 0: if p.tok.indent != 0:
if p.firstTok and p.tok.indent < 0: discard if p.firstTok and p.tok.indent < 0: discard

View file

@ -1,3 +1,10 @@
nimsuggest
==========
- disable in string and comments
- bug "goto definition for gTrackPos" in suggest.nim
version 1.0 battle plan version 1.0 battle plan
======================= =======================