Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Araq 2017-03-14 15:56:08 +01:00
commit b1c494a150
62 changed files with 818 additions and 442 deletions

View file

@ -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)

View file

@ -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

View file

@ -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]

View file

@ -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()

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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:

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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?

View file

@ -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)