Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
commit
b1c494a150
62 changed files with 818 additions and 442 deletions
|
|
@ -460,6 +460,8 @@ type
|
|||
# proc foo(T: typedesc, list: seq[T]): var T
|
||||
# proc foo(L: static[int]): array[L, int]
|
||||
# can be attached to ranges to indicate that the range
|
||||
# can be attached to generic procs with free standing
|
||||
# type parameters: e.g. proc foo[T]()
|
||||
# depends on unresolved static params.
|
||||
tfRetType, # marks return types in proc (used to detect type classes
|
||||
# used as return types for return type inference)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,23 @@ proc debug*(n: PSym) {.deprecated.}
|
|||
proc debug*(n: PType) {.deprecated.}
|
||||
proc debug*(n: PNode) {.deprecated.}
|
||||
|
||||
template mdbg*: bool {.dirty.} =
|
||||
when compiles(c.module):
|
||||
c.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(m.c.module):
|
||||
m.c.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(cl.c.module):
|
||||
cl.c.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(p):
|
||||
when compiles(p.lex):
|
||||
p.lex.fileIdx == gProjectMainIdx
|
||||
else:
|
||||
p.module.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(L.fileIdx):
|
||||
L.fileIdx == gProjectMainIdx
|
||||
else:
|
||||
false
|
||||
|
||||
# --------------------------- ident tables ----------------------------------
|
||||
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
|
||||
proc idTableGet*(t: TIdTable, key: int): RootRef
|
||||
|
|
|
|||
|
|
@ -80,9 +80,14 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
|
|||
expectedRegularParams = <s.typ.len
|
||||
givenRegularParams = totalParams - genericParams
|
||||
if givenRegularParams < 0: givenRegularParams = 0
|
||||
|
||||
if totalParams > expectedRegularParams + genericParams:
|
||||
globalError(n.info, errWrongNumberOfArguments)
|
||||
|
||||
if totalParams < genericParams:
|
||||
globalError(n.info, errMissingGenericParamsForTemplate,
|
||||
n.renderTree)
|
||||
|
||||
result = newNodeI(nkArgList, n.info)
|
||||
for i in 1 .. givenRegularParams:
|
||||
result.addSon n.sons[i]
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ type
|
|||
TTokTypes* = set[TTokType]
|
||||
|
||||
const
|
||||
weakTokens = {tkComma, tkSemiColon, tkColon,
|
||||
tkParRi, tkParDotRi, tkBracketRi, tkBracketDotRi,
|
||||
tkCurlyRi} # \
|
||||
# tokens that should not be considered for previousToken
|
||||
tokKeywordLow* = succ(tkSymbol)
|
||||
tokKeywordHigh* = pred(tkIntLit)
|
||||
TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]",
|
||||
|
|
@ -105,6 +109,9 @@ type
|
|||
# so that it is the correct default value
|
||||
base2, base8, base16
|
||||
|
||||
CursorPosition* {.pure.} = enum ## XXX remove this again
|
||||
None, InToken, BeforeToken, AfterToken
|
||||
|
||||
TToken* = object # a Nim token
|
||||
tokType*: TTokType # the type of the token
|
||||
indent*: int # the indentation; != -1 if the token has been
|
||||
|
|
@ -128,8 +135,11 @@ type
|
|||
# needs so much look-ahead
|
||||
currLineIndent*: int
|
||||
strongSpaces*, allowTabs*: bool
|
||||
cursor*: CursorPosition
|
||||
errorHandler*: TErrorHandler
|
||||
cache*: IdentCache
|
||||
when defined(nimsuggest):
|
||||
previousToken: TLineInfo
|
||||
|
||||
var gLinesCompiled*: int # all lines that have been compiled
|
||||
|
||||
|
|
@ -203,6 +213,8 @@ proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream;
|
|||
lex.currLineIndent = 0
|
||||
inc(lex.lineNumber, inputstream.lineOffset)
|
||||
lex.cache = cache
|
||||
when defined(nimsuggest):
|
||||
lex.previousToken.fileIndex = fileIdx
|
||||
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream;
|
||||
cache: IdentCache) =
|
||||
|
|
@ -235,6 +247,41 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
|||
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
|
||||
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
||||
|
||||
template tokenBegin(pos) {.dirty.} =
|
||||
when defined(nimsuggest):
|
||||
var colA = getColNumber(L, pos)
|
||||
|
||||
template tokenEnd(pos) {.dirty.} =
|
||||
when defined(nimsuggest):
|
||||
let colB = getColNumber(L, pos)+1
|
||||
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
||||
L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
|
||||
L.cursor = CursorPosition.InToken
|
||||
gTrackPos.col = colA.int16
|
||||
colA = 0
|
||||
|
||||
template tokenEndIgnore(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 in {ideSug, ideCon}:
|
||||
gTrackPos.fileIndex = trackPosInvalidFileIdx
|
||||
gTrackPos.line = -1
|
||||
colA = 0
|
||||
|
||||
template tokenEndPrevious(pos) =
|
||||
when defined(nimsuggest):
|
||||
# when we detect the cursor in whitespace, we attach the track position
|
||||
# to the token that came before that, but only if we haven't detected
|
||||
# the cursor in a string literal or comment:
|
||||
let colB = getColNumber(L, pos)
|
||||
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
||||
L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
|
||||
L.cursor = CursorPosition.BeforeToken
|
||||
gTrackPos = L.previousToken
|
||||
gTrackPosAttached = true
|
||||
colA = 0
|
||||
|
||||
{.push overflowChecks: off.}
|
||||
# We need to parse the largest uint literal without overflow checks
|
||||
proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
||||
|
|
@ -318,6 +365,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
|||
result.literal = ""
|
||||
result.base = base10
|
||||
startpos = L.bufpos
|
||||
tokenBegin(startPos)
|
||||
|
||||
# First stage: find out base, make verifications, build token literal string
|
||||
if L.buf[L.bufpos] == '0' and L.buf[L.bufpos + 1] in baseCodeChars + {'O'}:
|
||||
|
|
@ -526,6 +574,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
|||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
||||
except OverflowError, RangeError:
|
||||
lexMessageLitNum(L, errNumberOutOfRange, startpos)
|
||||
tokenEnd(postPos-1)
|
||||
L.bufpos = postPos
|
||||
|
||||
proc handleHexChar(L: var TLexer, xi: var int) =
|
||||
|
|
@ -642,21 +691,11 @@ proc handleCRLF(L: var TLexer, pos: int): int =
|
|||
result = nimlexbase.handleLF(L, 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) =
|
||||
var pos = L.bufpos + 1 # skip "
|
||||
var buf = L.buf # put `buf` in a register
|
||||
var line = L.lineNumber # save linenumber for better error message
|
||||
when defined(nimsuggest):
|
||||
var colA = getColNumber(L, pos)
|
||||
tokenBegin(pos)
|
||||
if buf[pos] == '\"' and buf[pos+1] == '\"':
|
||||
tok.tokType = tkTripleStrLit # long string literal:
|
||||
inc(pos, 2) # skip ""
|
||||
|
|
@ -672,18 +711,18 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
|
|||
of '\"':
|
||||
if buf[pos+1] == '\"' and buf[pos+2] == '\"' and
|
||||
buf[pos+3] != '\"':
|
||||
tokenRange(colA, pos+2)
|
||||
tokenEndIgnore(pos+2)
|
||||
L.bufpos = pos + 3 # skip the three """
|
||||
break
|
||||
add(tok.literal, '\"')
|
||||
inc(pos)
|
||||
of CR, LF:
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.literal, tnl)
|
||||
of nimlexbase.EndOfFile:
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
var line2 = L.lineNumber
|
||||
L.lineNumber = line
|
||||
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
|
||||
|
|
@ -704,11 +743,11 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
|
|||
inc(pos, 2)
|
||||
add(tok.literal, '"')
|
||||
else:
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
inc(pos) # skip '"'
|
||||
break
|
||||
elif c in {CR, LF, nimlexbase.EndOfFile}:
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
lexMessage(L, errClosingQuoteExpected)
|
||||
break
|
||||
elif (c == '\\') and not rawMode:
|
||||
|
|
@ -721,6 +760,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
|
|||
L.bufpos = pos
|
||||
|
||||
proc getCharacter(L: var TLexer, tok: var TToken) =
|
||||
tokenBegin(L.bufpos)
|
||||
inc(L.bufpos) # skip '
|
||||
var c = L.buf[L.bufpos]
|
||||
case c
|
||||
|
|
@ -730,12 +770,14 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
|
|||
tok.literal = $c
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
|
||||
tokenEndIgnore(L.bufpos)
|
||||
inc(L.bufpos) # skip '
|
||||
|
||||
proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var h: Hash = 0
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tokenBegin(pos)
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
case c
|
||||
|
|
@ -762,6 +804,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
|||
inc(pos)
|
||||
|
||||
else: break
|
||||
tokenEnd(pos-1)
|
||||
h = !$h
|
||||
tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
L.bufpos = pos
|
||||
|
|
@ -782,6 +825,7 @@ proc endOperator(L: var TLexer, tok: var TToken, pos: int,
|
|||
proc getOperator(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tokenBegin(pos)
|
||||
var h: Hash = 0
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
|
|
@ -789,6 +833,7 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
|||
h = h !& ord(c)
|
||||
inc(pos)
|
||||
endOperator(L, tok, pos, h)
|
||||
tokenEnd(pos-1)
|
||||
# advance pos but don't store it in L.bufpos so the next token (which might
|
||||
# be an operator too) gets the preceding spaces:
|
||||
tok.strongSpaceB = 0
|
||||
|
|
@ -803,8 +848,7 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
|
|||
var pos = start
|
||||
var buf = L.buf
|
||||
var toStrip = 0
|
||||
when defined(nimsuggest):
|
||||
var colA = getColNumber(L, pos)
|
||||
tokenBegin(pos)
|
||||
# detect the amount of indentation:
|
||||
if isDoc:
|
||||
toStrip = getColNumber(L, pos)
|
||||
|
|
@ -831,20 +875,20 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
|
|||
if isDoc:
|
||||
if buf[pos+1] == '#' and buf[pos+2] == '#':
|
||||
if nesting == 0:
|
||||
tokenRange(colA, pos+2)
|
||||
tokenEndIgnore(pos+2)
|
||||
inc(pos, 3)
|
||||
break
|
||||
dec nesting
|
||||
tok.literal.add ']'
|
||||
elif buf[pos+1] == '#':
|
||||
if nesting == 0:
|
||||
tokenRange(colA, pos+1)
|
||||
tokenEndIgnore(pos+1)
|
||||
inc(pos, 2)
|
||||
break
|
||||
dec nesting
|
||||
inc pos
|
||||
of CR, LF:
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
# strip leading whitespace:
|
||||
|
|
@ -856,7 +900,7 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
|
|||
inc pos
|
||||
dec c
|
||||
of nimlexbase.EndOfFile:
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
lexMessagePos(L, errGenerated, pos, "end of multiline comment expected")
|
||||
break
|
||||
else:
|
||||
|
|
@ -867,8 +911,6 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
|
|||
proc scanComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
when defined(nimsuggest):
|
||||
var colA = getColNumber(L, pos)
|
||||
tok.tokType = tkComment
|
||||
# iNumber contains the number of '\n' in the token
|
||||
tok.iNumber = 0
|
||||
|
|
@ -876,6 +918,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
|||
if buf[pos+2] == '[':
|
||||
skipMultiLineComment(L, tok, pos+3, true)
|
||||
return
|
||||
tokenBegin(pos)
|
||||
inc(pos, 2)
|
||||
|
||||
var toStrip = 0
|
||||
|
|
@ -889,7 +932,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
|||
if buf[pos] == '\\': lastBackslash = pos+1
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
var indent = 0
|
||||
|
|
@ -908,13 +951,14 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
|||
else:
|
||||
if buf[pos] > ' ':
|
||||
L.indentAhead = indent
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos)
|
||||
break
|
||||
L.bufpos = pos
|
||||
|
||||
proc skip(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tokenBegin(pos)
|
||||
tok.strongSpaceA = 0
|
||||
while true:
|
||||
case buf[pos]
|
||||
|
|
@ -925,6 +969,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
|||
if not L.allowTabs: lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
|
||||
inc(pos)
|
||||
of CR, LF:
|
||||
tokenEndPrevious(pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
var indent = 0
|
||||
|
|
@ -951,15 +996,24 @@ proc skip(L: var TLexer, tok: var TToken) =
|
|||
pos = L.bufpos
|
||||
buf = L.buf
|
||||
else:
|
||||
when defined(nimsuggest):
|
||||
var colA = getColNumber(L, pos)
|
||||
tokenBegin(pos)
|
||||
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
|
||||
tokenRange(colA, pos)
|
||||
tokenEndIgnore(pos+1)
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
tokenEndPrevious(pos-1)
|
||||
L.bufpos = pos
|
||||
|
||||
proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||
template atTokenEnd() {.dirty.} =
|
||||
when defined(nimsuggest):
|
||||
# we attach the cursor to the last *strong* token
|
||||
if tok.tokType notin weakTokens:
|
||||
L.previousToken.line = tok.line.int16
|
||||
L.previousToken.col = tok.col.int16
|
||||
|
||||
when defined(nimsuggest):
|
||||
L.cursor = CursorPosition.None
|
||||
fillToken(tok)
|
||||
if L.indentAhead >= 0:
|
||||
tok.indent = L.indentAhead
|
||||
|
|
@ -1007,6 +1061,10 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
|||
inc(L.bufpos)
|
||||
else:
|
||||
tok.tokType = tkParLe
|
||||
when defined(nimsuggest):
|
||||
if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
|
||||
tok.line == gTrackPos.line and gIdeCmd == ideCon:
|
||||
gTrackPos.col = tok.col.int16
|
||||
of ')':
|
||||
tok.tokType = tkParRi
|
||||
inc(L.bufpos)
|
||||
|
|
@ -1022,10 +1080,13 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
|||
inc(L.bufpos)
|
||||
of '.':
|
||||
when defined(nimsuggest):
|
||||
if L.fileIdx == gTrackPos.fileIndex and tok.col == gTrackPos.col and
|
||||
if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
|
||||
tok.line == gTrackPos.line and gIdeCmd == ideSug:
|
||||
tok.tokType = tkDot
|
||||
L.cursor = CursorPosition.InToken
|
||||
gTrackPos.col = tok.col.int16
|
||||
inc(L.bufpos)
|
||||
atTokenEnd()
|
||||
return
|
||||
if L.buf[L.bufpos+1] == ']':
|
||||
tok.tokType = tkBracketDotRi
|
||||
|
|
@ -1092,3 +1153,4 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
|||
tok.tokType = tkInvalid
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
inc(L.bufpos)
|
||||
atTokenEnd()
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ type
|
|||
errVarForOutParamNeeded,
|
||||
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
|
||||
errAmbiguousCallXYZ, errWrongNumberOfArguments,
|
||||
errWrongNumberOfArgumentsInCall,
|
||||
errMissingGenericParamsForTemplate,
|
||||
errXCannotBePassedToProcVar,
|
||||
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
|
||||
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
|
||||
|
|
@ -89,6 +91,7 @@ type
|
|||
errMainModuleMustBeSpecified,
|
||||
errXExpected,
|
||||
errTIsNotAConcreteType,
|
||||
errCastToANonConcreteType,
|
||||
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
||||
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
|
||||
|
|
@ -107,6 +110,7 @@ type
|
|||
errCannotInferTypeOfTheLiteral,
|
||||
errCannotInferReturnType,
|
||||
errGenericLambdaNotAllowed,
|
||||
errProcHasNoConcreteType,
|
||||
errCompilerDoesntSupportTarget,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
|
|
@ -269,6 +273,8 @@ const
|
|||
errButExpectedX: "but expected \'$1\'",
|
||||
errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
|
||||
errWrongNumberOfArguments: "wrong number of arguments",
|
||||
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
|
||||
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
|
||||
errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
|
||||
errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
|
||||
errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
|
||||
|
|
@ -326,6 +332,7 @@ const
|
|||
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
|
||||
errXExpected: "\'$1\' expected",
|
||||
errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
|
||||
errCastToANonConcreteType: "cannot cast to a non concrete type: \'$1\'",
|
||||
errInvalidSectionStart: "invalid section start",
|
||||
errGridTableNotImplemented: "grid table is not implemented",
|
||||
errGeneralParseError: "general parse error",
|
||||
|
|
@ -369,6 +376,7 @@ const
|
|||
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
|
||||
"it is used as an operand to another routine and the types " &
|
||||
"of the generic paramers can be inferred from the expected signature.",
|
||||
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
|
||||
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open \'$1\'",
|
||||
|
|
@ -739,6 +747,8 @@ proc `??`* (info: TLineInfo, filename: string): bool =
|
|||
const trackPosInvalidFileIdx* = -2 # special marker so that no suggestions
|
||||
# are produced within comments and string literals
|
||||
var gTrackPos*: TLineInfo
|
||||
var gTrackPosAttached*: bool ## whether the tracking position was attached to some
|
||||
## close token.
|
||||
|
||||
type
|
||||
MsgFlag* = enum ## flags altering msgWriteln behavior
|
||||
|
|
@ -863,6 +873,9 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
|||
proc `==`*(a, b: TLineInfo): bool =
|
||||
result = a.line == b.line and a.fileIndex == b.fileIndex
|
||||
|
||||
proc exactEquals*(a, b: TLineInfo): bool =
|
||||
result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col
|
||||
|
||||
proc writeContext(lastinfo: TLineInfo) =
|
||||
var info = lastinfo
|
||||
for i in countup(0, len(msgContext) - 1):
|
||||
|
|
|
|||
|
|
@ -392,6 +392,23 @@ proc findModule*(modulename, currentModule: string): string =
|
|||
result = findFile(m)
|
||||
patchModule()
|
||||
|
||||
proc findProjectNimFile*(pkg: string): string =
|
||||
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
|
||||
var candidates: seq[string] = @[]
|
||||
for k, f in os.walkDir(pkg, relative=true):
|
||||
if k == pcFile and f != "config.nims":
|
||||
let (_, name, ext) = splitFile(f)
|
||||
if ext in extensions:
|
||||
let x = changeFileExt(pkg / name, ".nim")
|
||||
if fileExists(x):
|
||||
candidates.add x
|
||||
for c in candidates:
|
||||
# nim-foo foo or foo nfoo
|
||||
if (pkg in c) or (c in pkg): return c
|
||||
if candidates.len >= 1:
|
||||
return candidates[0]
|
||||
return ""
|
||||
|
||||
proc canonDynlibName(s: string): string =
|
||||
let start = if s.startsWith("lib"): 3 else: 0
|
||||
let ende = strutils.find(s, {'(', ')', '.'})
|
||||
|
|
@ -420,11 +437,6 @@ proc binaryStrSearch*(x: openArray[string], y: string): int =
|
|||
return mid
|
||||
result = - 1
|
||||
|
||||
template nimdbg*: untyped = c.module.fileIdx == gProjectMainIdx
|
||||
template cnimdbg*: untyped = p.module.module.fileIdx == gProjectMainIdx
|
||||
template pnimdbg*: untyped = p.lex.fileIdx == gProjectMainIdx
|
||||
template lnimdbg*: untyped = L.fileIdx == gProjectMainIdx
|
||||
|
||||
proc parseIdeCmd*(s: string): IdeCmd =
|
||||
case s:
|
||||
of "sug": ideSug
|
||||
|
|
|
|||
|
|
@ -1846,6 +1846,7 @@ proc parseTypeDef(p: var TParser): PNode =
|
|||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
if p.tok.tokType == tkEquals:
|
||||
result.info = parLineInfo(p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
addSon(result, parseTypeDefAux(p))
|
||||
|
|
@ -2002,12 +2003,12 @@ proc parseStmt(p: var TParser): PNode =
|
|||
break
|
||||
p.hasProgress = false
|
||||
var a = complexOrSimpleStmt(p)
|
||||
if not p.hasProgress and p.tok.tokType == tkEof: break
|
||||
if a.kind != nkEmpty and p.hasProgress:
|
||||
if a.kind != nkEmpty:
|
||||
addSon(result, a)
|
||||
else:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p)
|
||||
if not p.hasProgress and p.tok.tokType == tkEof: break
|
||||
else:
|
||||
# the case statement is only needed for better error messages:
|
||||
case p.tok.tokType
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ proc commonType*(x, y: PType): PType =
|
|||
|
||||
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
|
||||
when defined(nimsuggest):
|
||||
suggestDecl(c, n, result)
|
||||
|
||||
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii
|
||||
|
|
@ -191,6 +193,8 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
|||
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
|
||||
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
|
||||
# incl(result.flags, sfGlobal)
|
||||
when defined(nimsuggest):
|
||||
suggestDecl(c, n, result)
|
||||
|
||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym
|
||||
|
|
@ -381,6 +385,13 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
|||
if sym == c.p.owner:
|
||||
globalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||
|
||||
let genericParams = if sfImmediate in sym.flags: 0
|
||||
else: sym.ast[genericParamsPos].len
|
||||
let suppliedParams = max(n.safeLen - 1, 0)
|
||||
|
||||
if suppliedParams < genericParams:
|
||||
globalError(n.info, errMissingGenericParamsForTemplate, n.renderTree)
|
||||
|
||||
#if c.evalContext == nil:
|
||||
# c.evalContext = c.createEvalContext(emStatic)
|
||||
result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
|
||||
|
|
|
|||
|
|
@ -411,6 +411,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
|||
let tm = typeRel(m, formal, arg, true)
|
||||
if tm in {isNone, isConvertible}: return nil
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
newInst.typ.flags.excl tfUnresolved
|
||||
markUsed(n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
result = newSymNode(newInst, n.info)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
# result = errorNode(c, n)
|
||||
if result.typ != nil:
|
||||
# XXX tyGenericInst here?
|
||||
if result.typ.kind == tyProc and tfUnresolved in result.typ.flags:
|
||||
localError(n.info, errProcHasNoConcreteType, n.renderTree)
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
elif {efWantStmt, efAllowStmt} * flags != {}:
|
||||
result.typ = newTypeS(tyVoid, c)
|
||||
|
|
@ -218,13 +220,16 @@ proc semConv(c: PContext, n: PNode): PNode =
|
|||
proc semCast(c: PContext, n: PNode): PNode =
|
||||
## Semantically analyze a casting ("cast[type](param)")
|
||||
checkSonsLen(n, 2)
|
||||
let targetType = semTypeNode(c, n.sons[0], nil)
|
||||
let castedExpr = semExprWithType(c, n.sons[1])
|
||||
if tfHasMeta in targetType.flags:
|
||||
localError(n.sons[0].info, errCastToANonConcreteType, $targetType)
|
||||
if not isCastable(targetType, castedExpr.typ):
|
||||
localError(n.info, errExprCannotBeCastToX, $targetType)
|
||||
result = newNodeI(nkCast, n.info)
|
||||
result.typ = semTypeNode(c, n.sons[0], nil)
|
||||
result.typ = targetType
|
||||
addSon(result, copyTree(n.sons[0]))
|
||||
addSon(result, semExprWithType(c, n.sons[1]))
|
||||
if not isCastable(result.typ, result.sons[1].typ):
|
||||
localError(result.info, errExprCannotBeCastToX,
|
||||
typeToString(result.typ))
|
||||
addSon(result, castedExpr)
|
||||
|
||||
proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
const
|
||||
|
|
@ -1054,7 +1059,9 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
# here at all!
|
||||
#if isSymChoice(n.sons[1]): return
|
||||
when defined(nimsuggest):
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
if gCmd == cmdIdeTools:
|
||||
suggestExpr(c, n)
|
||||
if exactEquals(gTrackPos, n[1].info): suggestExprNoCheck(c, n)
|
||||
|
||||
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
|
||||
if s != nil:
|
||||
|
|
@ -2234,6 +2241,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1)
|
||||
#when defined(nimsuggest):
|
||||
# if gIdeCmd == ideCon and gTrackPos == n.info: suggestExprNoCheck(c, n)
|
||||
let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
|
||||
var s = qualifiedLookUp(c, n.sons[0], mode)
|
||||
if s != nil:
|
||||
|
|
|
|||
|
|
@ -205,7 +205,8 @@ proc semCase(c: PContext, n: PNode): PNode =
|
|||
var typ = commonTypeBegin
|
||||
var hasElse = false
|
||||
var notOrdinal = false
|
||||
case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
|
||||
let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc})
|
||||
case caseTyp.kind
|
||||
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
||||
chckCovered = true
|
||||
of tyFloat..tyFloat128, tyString, tyError:
|
||||
|
|
@ -215,6 +216,9 @@ proc semCase(c: PContext, n: PNode): PNode =
|
|||
return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var x = n.sons[i]
|
||||
when defined(nimsuggest):
|
||||
if gIdeCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum:
|
||||
suggestEnum(c, x, caseTyp)
|
||||
case x.kind
|
||||
of nkOfBranch:
|
||||
checkMinSonsLen(x, 2)
|
||||
|
|
@ -499,6 +503,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
if hasEmpty(typ):
|
||||
localError(def.info, errCannotInferTypeOfTheLiteral,
|
||||
($typ.kind).substr(2).toLowerAscii)
|
||||
elif typ.kind == tyProc and tfUnresolved in typ.flags:
|
||||
localError(def.info, errProcHasNoConcreteType, def.renderTree)
|
||||
else:
|
||||
if symkind == skLet: localError(a.info, errLetNeedsInit)
|
||||
|
||||
|
|
@ -711,7 +717,11 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
|||
# we even look at the type definitions on the right
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||
when defined(nimsuggest):
|
||||
if gCmd == cmdIdeTools:
|
||||
inc c.inTypeContext
|
||||
suggestStmt(c, a)
|
||||
dec c.inTypeContext
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind != nkTypeDef: illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
|
|
|
|||
|
|
@ -1009,8 +1009,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
result.sons[0] = r
|
||||
result.n.typ = r
|
||||
|
||||
if genericParams != nil:
|
||||
if genericParams != nil and genericParams.len > 0:
|
||||
for n in genericParams:
|
||||
if {sfUsed, sfAnon} * n.sym.flags == {}:
|
||||
result.flags.incl tfUnresolved
|
||||
|
||||
if tfWildcard in n.sym.typ.flags:
|
||||
n.sym.kind = skType
|
||||
n.sym.typ.flags.excl tfWildcard
|
||||
|
|
|
|||
|
|
@ -1514,6 +1514,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
|||
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
copyCandidate(z, m)
|
||||
z.callee = arg.sons[i].typ
|
||||
if tfUnresolved in z.callee.flags: continue
|
||||
z.calleeSym = arg.sons[i].sym
|
||||
#if arg.sons[i].sym.name.s == "cmp":
|
||||
# ggDebug = true
|
||||
|
|
@ -1650,7 +1651,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
|
||||
incl(marker, formal.position)
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
|
||||
container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
|
||||
setSon(m.call, formal.position + 1, container)
|
||||
else:
|
||||
incrIndexType(container.typ)
|
||||
|
|
@ -1738,7 +1739,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
|
||||
if formal.typ.isVarargsUntyped:
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
|
||||
container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
|
||||
setSon(m.call, formal.position + 1, container)
|
||||
else:
|
||||
incrIndexType(container.typ)
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ type
|
|||
var
|
||||
suggestionResultHook*: proc (result: Suggest) {.closure.}
|
||||
suggestVersion*: int
|
||||
suggestMaxResults* = 10_000
|
||||
|
||||
#template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n"
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ template origModuleName(m: PSym): string = m.name.s
|
|||
proc findDocComment(n: PNode): PNode =
|
||||
if n == nil: return nil
|
||||
if not isNil(n.comment): return n
|
||||
if n.kind in {nkStmtList, nkStmtListExpr} and n.len > 0:
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkObjectTy, nkRecList} and n.len > 0:
|
||||
result = findDocComment(n.sons[0])
|
||||
if result != nil: return
|
||||
if n.len > 1:
|
||||
|
|
@ -104,11 +105,11 @@ proc cmpSuggestions(a, b: Suggest): int =
|
|||
# independent of hashing order:
|
||||
result = cmp(a.name.s, b.name.s)
|
||||
|
||||
proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo;
|
||||
proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
|
||||
quality: range[0..100]; prefix: PrefixMatch;
|
||||
inTypeContext: bool; scope: int): Suggest =
|
||||
new(result)
|
||||
result.section = parseIdeCmd(section)
|
||||
result.section = section
|
||||
result.quality = quality
|
||||
result.isGlobal = sfGlobal in s.flags
|
||||
result.tokenLen = s.name.s.len
|
||||
|
|
@ -120,15 +121,10 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo;
|
|||
result.globalUsages = s.allUsages.len
|
||||
var c = 0
|
||||
for u in s.allUsages:
|
||||
if u.fileIndex == li.fileIndex: inc c
|
||||
if u.fileIndex == info.fileIndex: inc c
|
||||
result.localUsages = c
|
||||
if optIdeTerse in gGlobalOptions:
|
||||
result.symkind = s.kind
|
||||
result.filePath = toFullPath(li)
|
||||
result.line = toLinenumber(li)
|
||||
result.column = toColumn(li)
|
||||
else:
|
||||
result.symkind = s.kind
|
||||
result.symkind = s.kind
|
||||
if optIdeTerse notin gGlobalOptions:
|
||||
result.qualifiedPath = @[]
|
||||
if not isLocal and s.kind != skModule:
|
||||
let ow = s.owner
|
||||
|
|
@ -143,11 +139,12 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo;
|
|||
result.forth = typeToString(s.typ)
|
||||
else:
|
||||
result.forth = ""
|
||||
result.filePath = toFullPath(li)
|
||||
result.line = toLinenumber(li)
|
||||
result.column = toColumn(li)
|
||||
when not defined(noDocgen):
|
||||
result.doc = s.extractDocComment
|
||||
let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info
|
||||
result.filePath = toFullPath(infox)
|
||||
result.line = toLinenumber(infox)
|
||||
result.column = toColumn(infox)
|
||||
|
||||
proc `$`*(suggest: Suggest): string =
|
||||
result = $suggest.section
|
||||
|
|
@ -181,18 +178,13 @@ proc `$`*(suggest: Suggest): string =
|
|||
result.add(sep)
|
||||
when not defined(noDocgen):
|
||||
result.add(suggest.doc.escape)
|
||||
if suggestVersion == 2:
|
||||
if suggestVersion == 0:
|
||||
result.add(sep)
|
||||
result.add($suggest.quality)
|
||||
if suggest.section == ideSug:
|
||||
result.add(sep)
|
||||
result.add($suggest.prefix)
|
||||
|
||||
proc symToSuggest(s: PSym, isLocal: bool, section: string;
|
||||
quality: range[0..100], prefix: PrefixMatch; inTypeContext: bool;
|
||||
scope: int): Suggest =
|
||||
result = symToSuggest(s, isLocal, section, s.info, quality, prefix, inTypeContext, scope)
|
||||
|
||||
proc suggestResult(s: Suggest) =
|
||||
if not isNil(suggestionResultHook):
|
||||
suggestionResultHook(s)
|
||||
|
|
@ -202,6 +194,10 @@ proc suggestResult(s: Suggest) =
|
|||
proc produceOutput(a: var Suggestions) =
|
||||
if gIdeCmd in {ideSug, ideCon}:
|
||||
a.sort cmpSuggestions
|
||||
when defined(debug):
|
||||
# debug code
|
||||
writeStackTrace()
|
||||
if a.len > suggestMaxResults: a.setLen(suggestMaxResults)
|
||||
if not isNil(suggestionResultHook):
|
||||
for s in a:
|
||||
suggestionResultHook(s)
|
||||
|
|
@ -237,10 +233,10 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
|
|||
result = true
|
||||
break
|
||||
|
||||
proc suggestField(c: PContext, s: PSym; f: PNode; outputs: var Suggestions) =
|
||||
proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) =
|
||||
var pm: PrefixMatch
|
||||
if filterSym(s, f, pm) and fieldVisible(c, s):
|
||||
outputs.add(symToSuggest(s, isLocal=true, $ideSug, 100, pm, c.inTypeContext > 0, 0))
|
||||
outputs.add(symToSuggest(s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0))
|
||||
|
||||
proc getQuality(s: PSym): range[0..100] =
|
||||
if s.typ != nil and s.typ.len > 1:
|
||||
|
|
@ -259,25 +255,25 @@ template wholeSymTab(cond, section: untyped) =
|
|||
let it {.inject.} = item
|
||||
var pm {.inject.}: PrefixMatch
|
||||
if cond:
|
||||
outputs.add(symToSuggest(it, isLocal = isLocal, section, getQuality(it),
|
||||
outputs.add(symToSuggest(it, isLocal = isLocal, section, info, getQuality(it),
|
||||
pm, c.inTypeContext > 0, scopeN))
|
||||
|
||||
proc suggestSymList(c: PContext, list, f: PNode, outputs: var Suggestions) =
|
||||
proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) =
|
||||
for i in countup(0, sonsLen(list) - 1):
|
||||
if list.sons[i].kind == nkSym:
|
||||
suggestField(c, list.sons[i].sym, f, outputs)
|
||||
suggestField(c, list.sons[i].sym, f, info, outputs)
|
||||
#else: InternalError(list.info, "getSymFromList")
|
||||
|
||||
proc suggestObject(c: PContext, n, f: PNode, outputs: var Suggestions) =
|
||||
proc suggestObject(c: PContext, n, f: PNode; info: TLineInfo, outputs: var Suggestions) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], f, outputs)
|
||||
for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], f, info, outputs)
|
||||
of nkRecCase:
|
||||
var L = sonsLen(n)
|
||||
if L > 0:
|
||||
suggestObject(c, n.sons[0], f, outputs)
|
||||
for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), f, outputs)
|
||||
of nkSym: suggestField(c, n.sym, f, outputs)
|
||||
suggestObject(c, n.sons[0], f, info, outputs)
|
||||
for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), f, info, outputs)
|
||||
of nkSym: suggestField(c, n.sym, f, info, outputs)
|
||||
else: discard
|
||||
|
||||
proc nameFits(c: PContext, s: PSym, n: PNode): bool =
|
||||
|
|
@ -301,8 +297,9 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
|
|||
result = false
|
||||
|
||||
proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var Suggestions) =
|
||||
let info = n.info
|
||||
wholeSymTab(filterSym(it, nil, pm) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
|
||||
$ideCon)
|
||||
ideCon)
|
||||
|
||||
proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
|
||||
if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil:
|
||||
|
|
@ -319,7 +316,8 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
|
|||
|
||||
proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Suggestions) =
|
||||
assert typ != nil
|
||||
wholeSymTab(filterSymNoOpr(it, f, pm) and typeFits(c, it, typ), $ideSug)
|
||||
let info = n.info
|
||||
wholeSymTab(filterSymNoOpr(it, f, pm) and typeFits(c, it, typ), ideSug)
|
||||
|
||||
proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) =
|
||||
# do not produce too many symbols:
|
||||
|
|
@ -331,8 +329,9 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) =
|
|||
for it in items(scope.symbols):
|
||||
var pm: PrefixMatch
|
||||
if filterSym(it, f, pm):
|
||||
outputs.add(symToSuggest(it, isLocal = isLocal, $ideSug, 0, pm, c.inTypeContext > 0, scopeN))
|
||||
if scope == c.topLevelScope and f.isNil: break
|
||||
outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, n.info, 0, pm,
|
||||
c.inTypeContext > 0, scopeN))
|
||||
#if scope == c.topLevelScope and f.isNil: break
|
||||
|
||||
proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) =
|
||||
# special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
|
||||
|
|
@ -340,7 +339,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
|||
var typ = n.typ
|
||||
var pm: PrefixMatch
|
||||
when defined(nimsuggest):
|
||||
if n.kind == nkSym and n.sym.kind == skError and suggestVersion == 2:
|
||||
if n.kind == nkSym and n.sym.kind == skError and suggestVersion == 0:
|
||||
# consider 'foo.|' where 'foo' is some not imported module.
|
||||
let fullPath = findModule(n.sym.name.s, n.info.toFullPath)
|
||||
if fullPath.len == 0:
|
||||
|
|
@ -352,8 +351,8 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
|||
else:
|
||||
for it in items(n.sym.tab):
|
||||
if filterSym(it, field, pm):
|
||||
outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -100))
|
||||
outputs.add(symToSuggest(m, isLocal=false, $ideMod, 100, PrefixMatch.None,
|
||||
outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100))
|
||||
outputs.add(symToSuggest(m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None,
|
||||
c.inTypeContext > 0, -99))
|
||||
|
||||
if typ == nil:
|
||||
|
|
@ -363,11 +362,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
|||
# all symbols accessible, because we are in the current module:
|
||||
for it in items(c.topLevelScope.symbols):
|
||||
if filterSym(it, field, pm):
|
||||
outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -99))
|
||||
outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
|
||||
else:
|
||||
for it in items(n.sym.tab):
|
||||
if filterSym(it, field, pm):
|
||||
outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -99))
|
||||
outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
|
||||
else:
|
||||
# fallback:
|
||||
suggestEverything(c, n, field, outputs)
|
||||
|
|
@ -375,7 +374,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
|||
# look up if the identifier belongs to the enum:
|
||||
var t = typ
|
||||
while t != nil:
|
||||
suggestSymList(c, t.n, field, outputs)
|
||||
suggestSymList(c, t.n, field, n.info, outputs)
|
||||
t = t.sons[0]
|
||||
suggestOperations(c, n, field, typ, outputs)
|
||||
else:
|
||||
|
|
@ -384,11 +383,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
|||
if typ.kind == tyObject:
|
||||
var t = typ
|
||||
while true:
|
||||
suggestObject(c, t.n, field, outputs)
|
||||
suggestObject(c, t.n, field, n.info, outputs)
|
||||
if t.sons[0] == nil: break
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
elif typ.kind == tyTuple and typ.n != nil:
|
||||
suggestSymList(c, typ.n, field, outputs)
|
||||
suggestSymList(c, typ.n, field, n.info, outputs)
|
||||
suggestOperations(c, n, field, orig, outputs)
|
||||
if typ != orig:
|
||||
suggestOperations(c, n, field, typ, outputs)
|
||||
|
|
@ -405,36 +404,12 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult =
|
|||
if current.line >= gTrackPos.line:
|
||||
return cpFuzzy
|
||||
|
||||
proc findClosestDot(n: PNode): PNode =
|
||||
if n.kind == nkDotExpr and inCheckpoint(n.info) == cpExact:
|
||||
result = n
|
||||
else:
|
||||
for i in 0.. <safeLen(n):
|
||||
result = findClosestDot(n.sons[i])
|
||||
if result != nil: return
|
||||
|
||||
proc findClosestCall(n: PNode): PNode =
|
||||
if n.kind in nkCallKinds and inCheckpoint(n.info) == cpExact:
|
||||
result = n
|
||||
else:
|
||||
for i in 0.. <safeLen(n):
|
||||
result = findClosestCall(n.sons[i])
|
||||
if result != nil: return
|
||||
|
||||
proc isTracked*(current: TLineInfo, tokenLen: int): bool =
|
||||
if current.fileIndex==gTrackPos.fileIndex and current.line==gTrackPos.line:
|
||||
let col = gTrackPos.col
|
||||
if col >= current.col and col <= current.col+tokenLen-1:
|
||||
return true
|
||||
|
||||
proc findClosestSym(n: PNode): PNode =
|
||||
if n.kind == nkSym and inCheckpoint(n.info) == cpExact:
|
||||
result = n
|
||||
elif n.kind notin {nkNone..nkNilLit}:
|
||||
for i in 0.. <sonsLen(n):
|
||||
result = findClosestSym(n.sons[i])
|
||||
if result != nil: return
|
||||
|
||||
when defined(nimsuggest):
|
||||
# Since TLineInfo defined a == operator that doesn't include the column,
|
||||
# we map TLineInfo to a unique int here for this lookup table:
|
||||
|
|
@ -453,26 +428,26 @@ var
|
|||
lastLineInfo*: TLineInfo
|
||||
|
||||
proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) =
|
||||
if suggestVersion < 2:
|
||||
if suggestVersion == 1:
|
||||
if usageSym == nil and isTracked(info, s.name.s.len):
|
||||
usageSym = s
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideUse, 100, PrefixMatch.None, false, 0))
|
||||
suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
|
||||
elif s == usageSym:
|
||||
if lastLineInfo != info:
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideUse, info, 100, PrefixMatch.None, false, 0))
|
||||
suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
|
||||
lastLineInfo = info
|
||||
|
||||
when defined(nimsuggest):
|
||||
proc listUsages*(s: PSym) =
|
||||
#echo "usages ", len(s.allUsages)
|
||||
for info in s.allUsages:
|
||||
let x = if info == s.info and info.col == s.info.col: "def" else: "use"
|
||||
let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse
|
||||
suggestResult(symToSuggest(s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0))
|
||||
|
||||
proc findDefinition(info: TLineInfo; s: PSym) =
|
||||
if s.isNil: return
|
||||
if isTracked(info, s.name.s.len):
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100, PrefixMatch.None, false, 0))
|
||||
suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
|
||||
suggestQuit()
|
||||
|
||||
proc ensureIdx[T](x: var T, y: int) =
|
||||
|
|
@ -484,7 +459,7 @@ proc ensureSeq[T](x: var seq[T]) =
|
|||
proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} =
|
||||
## misnamed: should be 'symDeclared'
|
||||
when defined(nimsuggest):
|
||||
if suggestVersion == 2:
|
||||
if suggestVersion == 0:
|
||||
if s.allUsages.isNil:
|
||||
s.allUsages = @[info]
|
||||
else:
|
||||
|
|
@ -496,13 +471,13 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in
|
|||
findDefinition(info, s)
|
||||
elif gIdeCmd == ideDus and s != nil:
|
||||
if isTracked(info, s.name.s.len):
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100, PrefixMatch.None, false, 0))
|
||||
suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
|
||||
findUsages(info, s, usageSym)
|
||||
elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex:
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideHighlight, info, 100, PrefixMatch.None, false, 0))
|
||||
suggestResult(symToSuggest(s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0))
|
||||
elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and
|
||||
isDecl:
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideOutline, info, 100, PrefixMatch.None, false, 0))
|
||||
suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
|
||||
|
||||
proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) =
|
||||
incl(s.flags, sfUsed)
|
||||
|
|
@ -525,40 +500,31 @@ proc safeSemExpr*(c: PContext, n: PNode): PNode =
|
|||
except ERecoverableError:
|
||||
result = ast.emptyNode
|
||||
|
||||
proc suggestExpr*(c: PContext, node: PNode) =
|
||||
if gTrackPos.line < 0: return
|
||||
var cp = inCheckpoint(node.info)
|
||||
if cp == cpNone: return
|
||||
proc sugExpr(c: PContext, n: PNode, outputs: var Suggestions) =
|
||||
if n.kind == nkDotExpr:
|
||||
var obj = safeSemExpr(c, n.sons[0])
|
||||
# it can happen that errnously we have collected the fieldname
|
||||
# of the next line, so we check the 'field' is actually on the same
|
||||
# line as the object to prevent this from happening:
|
||||
let prefix = if n.len == 2 and n[1].info.line == n[0].info.line and
|
||||
not gTrackPosAttached: n[1] else: nil
|
||||
suggestFieldAccess(c, obj, prefix, outputs)
|
||||
|
||||
#if optIdeDebug in gGlobalOptions:
|
||||
# echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ)
|
||||
#writeStackTrace()
|
||||
else:
|
||||
let prefix = if gTrackPosAttached: nil else: n
|
||||
suggestEverything(c, n, prefix, outputs)
|
||||
|
||||
proc suggestExprNoCheck*(c: PContext, n: PNode) =
|
||||
# This keeps semExpr() from coming here recursively:
|
||||
if c.compilesContextId > 0: return
|
||||
inc(c.compilesContextId)
|
||||
|
||||
var outputs: Suggestions = @[]
|
||||
if gIdeCmd == ideSug:
|
||||
var n = findClosestDot(node)
|
||||
if n == nil: n = node
|
||||
if n.kind == nkDotExpr:
|
||||
var obj = safeSemExpr(c, n.sons[0])
|
||||
# it can happen that errnously we have collected the fieldname
|
||||
# of the next line, so we check the 'field' is actually on the same
|
||||
# line as the object to prevent this from happening:
|
||||
let prefix = if n.len == 2 and n[1].info.line == n[0].info.line: n[1] else: nil
|
||||
suggestFieldAccess(c, obj, prefix, outputs)
|
||||
|
||||
#if optIdeDebug in gGlobalOptions:
|
||||
# echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ)
|
||||
#writeStackTrace()
|
||||
else:
|
||||
#let m = findClosestSym(node)
|
||||
#if m != nil:
|
||||
# suggestPrefix(c, m, outputs)
|
||||
#else:
|
||||
let prefix = if cp == cpExact: n else: nil
|
||||
suggestEverything(c, n, prefix, outputs)
|
||||
|
||||
sugExpr(c, n, outputs)
|
||||
elif gIdeCmd == ideCon:
|
||||
var n = findClosestCall(node)
|
||||
if n == nil: n = node
|
||||
if n.kind in nkCallKinds:
|
||||
var a = copyNode(n)
|
||||
var x = safeSemExpr(c, n.sons[0])
|
||||
|
|
@ -576,16 +542,32 @@ proc suggestExpr*(c: PContext, node: PNode) =
|
|||
produceOutput(outputs)
|
||||
suggestQuit()
|
||||
|
||||
proc suggestExpr*(c: PContext, n: PNode) =
|
||||
if exactEquals(gTrackPos, n.info): suggestExprNoCheck(c, n)
|
||||
|
||||
proc suggestDecl*(c: PContext, n: PNode; s: PSym) =
|
||||
let attached = gTrackPosAttached
|
||||
if attached: inc(c.inTypeContext)
|
||||
defer:
|
||||
if attached: dec(c.inTypeContext)
|
||||
suggestExpr(c, n)
|
||||
|
||||
proc suggestStmt*(c: PContext, n: PNode) =
|
||||
suggestExpr(c, n)
|
||||
|
||||
proc suggestEnum*(c: PContext; n: PNode; t: PType) =
|
||||
var outputs: Suggestions = @[]
|
||||
suggestSymList(c, t.n, nil, n.info, outputs)
|
||||
produceOutput(outputs)
|
||||
if outputs.len > 0: suggestQuit()
|
||||
|
||||
proc suggestSentinel*(c: PContext) =
|
||||
if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex: return
|
||||
if c.compilesContextId > 0: return
|
||||
inc(c.compilesContextId)
|
||||
var outputs: Suggestions = @[]
|
||||
# suggest everything:
|
||||
var isLocal = true
|
||||
var outputs: Suggestions = @[]
|
||||
var scopeN = 0
|
||||
for scope in walkScopes(c.currentScope):
|
||||
if scope == c.topLevelScope: isLocal = false
|
||||
|
|
@ -593,7 +575,7 @@ proc suggestSentinel*(c: PContext) =
|
|||
for it in items(scope.symbols):
|
||||
var pm: PrefixMatch
|
||||
if filterSymNoOpr(it, nil, pm):
|
||||
outputs.add(symToSuggest(it, isLocal = isLocal, $ideSug, 0, PrefixMatch.None, false, scopeN))
|
||||
outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN))
|
||||
|
||||
produceOutput(outputs)
|
||||
dec(c.compilesContextId)
|
||||
produceOutput(outputs)
|
||||
|
|
|
|||
|
|
@ -291,10 +291,13 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
|||
else:
|
||||
result = newTransNode(n.kind, n.info, 1)
|
||||
result[0] = lablCopy.PTransNode
|
||||
else:
|
||||
elif c.breakSyms.len > 0:
|
||||
# this check can fail for 'nim check'
|
||||
let labl = c.breakSyms[c.breakSyms.high]
|
||||
result = transformSons(c, n)
|
||||
result[0] = newSymNode(labl).PTransNode
|
||||
else:
|
||||
result = n.PTransNode
|
||||
|
||||
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type
|
|||
preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg
|
||||
|
||||
proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
|
||||
template `$`*(typ: PType): string = typeToString(typ)
|
||||
|
||||
proc base*(t: PType): PType =
|
||||
result = t.sons[0]
|
||||
|
|
@ -547,7 +548,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
|||
if prefer != preferExported:
|
||||
result.add("(" & typeToString(t.sons[0]) & ")")
|
||||
of tyProc:
|
||||
result = if tfIterator in t.flags: "iterator (" else: "proc ("
|
||||
result = if tfIterator in t.flags: "iterator " else: "proc "
|
||||
if tfUnresolved in t.flags: result.add "[*missing parameters*]"
|
||||
result.add "("
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
|
||||
add(result, t.n[i].sym.name.s)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue