nimsuggest: fixes nimsuggest bug #45; do not show suggestions in string literals or comments
This commit is contained in:
parent
23a303c536
commit
1887390b0f
4 changed files with 96 additions and 7 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
7
todo.txt
7
todo.txt
|
|
@ -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
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue