next steps to perfect 'suggest'
This commit is contained in:
parent
fdde4d3a92
commit
310faca724
7 changed files with 106 additions and 41 deletions
23
rod/msgs.nim
23
rod/msgs.nim
|
|
@ -398,8 +398,8 @@ proc UnknownLineInfo*(): TLineInfo =
|
||||||
result.fileIndex = -1
|
result.fileIndex = -1
|
||||||
|
|
||||||
var
|
var
|
||||||
filenames: seq[string] = @ []
|
filenames: seq[string] = @[]
|
||||||
msgContext: seq[TLineInfo] = @ []
|
msgContext: seq[TLineInfo] = @[]
|
||||||
|
|
||||||
proc pushInfoContext*(info: TLineInfo) =
|
proc pushInfoContext*(info: TLineInfo) =
|
||||||
msgContext.add(info)
|
msgContext.add(info)
|
||||||
|
|
@ -424,10 +424,10 @@ proc ToFilename*(info: TLineInfo): string =
|
||||||
if info.fileIndex == - 1: result = "???"
|
if info.fileIndex == - 1: result = "???"
|
||||||
else: result = filenames[info.fileIndex]
|
else: result = filenames[info.fileIndex]
|
||||||
|
|
||||||
proc ToLinenumber*(info: TLineInfo): int =
|
proc ToLinenumber*(info: TLineInfo): int {.inline.} =
|
||||||
result = info.line
|
result = info.line
|
||||||
|
|
||||||
proc toColumn*(info: TLineInfo): int =
|
proc toColumn*(info: TLineInfo): int {.inline.} =
|
||||||
result = info.col
|
result = info.col
|
||||||
|
|
||||||
var checkPoints: seq[TLineInfo] = @[]
|
var checkPoints: seq[TLineInfo] = @[]
|
||||||
|
|
@ -453,11 +453,18 @@ proc MsgKindToString*(kind: TMsgKind): string =
|
||||||
proc getMessageStr(msg: TMsgKind, arg: string): string =
|
proc getMessageStr(msg: TMsgKind, arg: string): string =
|
||||||
result = `%`(msgKindToString(msg), [arg])
|
result = `%`(msgKindToString(msg), [arg])
|
||||||
|
|
||||||
proc inCheckpoint*(current: TLineInfo): bool =
|
type
|
||||||
|
TCheckPointResult* = enum
|
||||||
|
cpNone, cpFuzzy, cpExact
|
||||||
|
|
||||||
|
proc inCheckpoint*(current: TLineInfo): TCheckPointResult =
|
||||||
for i in countup(0, high(checkPoints)):
|
for i in countup(0, high(checkPoints)):
|
||||||
if (current.line >= checkPoints[i].line) and
|
if current.fileIndex == checkPoints[i].fileIndex:
|
||||||
(current.fileIndex == (checkPoints[i].fileIndex)):
|
if current.line == checkPoints[i].line and
|
||||||
return true
|
abs(current.col-checkPoints[i].col) < 4:
|
||||||
|
return cpExact
|
||||||
|
if current.line >= checkPoints[i].line:
|
||||||
|
return cpFuzzy
|
||||||
|
|
||||||
type
|
type
|
||||||
TErrorHandling = enum doNothing, doAbort, doRaise
|
TErrorHandling = enum doNothing, doAbort, doRaise
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,10 @@ proc considerAcc(n: PNode): PIdent =
|
||||||
GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc isTopLevel(c: PContext): bool =
|
proc isTopLevel(c: PContext): bool {.inline.} =
|
||||||
result = c.tab.tos <= 2
|
# if we encountered an error, we treat as top-level so that
|
||||||
|
# cascading errors are not that strange:
|
||||||
|
result = c.tab.tos <= 2 or msgs.gErrorCounter > 0
|
||||||
|
|
||||||
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
result = newSym(kind, considerAcc(n), getCurrOwner())
|
result = newSym(kind, considerAcc(n), getCurrOwner())
|
||||||
|
|
|
||||||
|
|
@ -641,8 +641,6 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags)
|
n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags)
|
||||||
if gCmd == cmdSuggest:
|
|
||||||
suggestFieldAccess(c, n.sons[0])
|
|
||||||
var i = considerAcc(n.sons[1])
|
var i = considerAcc(n.sons[1])
|
||||||
var ty = n.sons[0].Typ
|
var ty = n.sons[0].Typ
|
||||||
var f: PSym = nil
|
var f: PSym = nil
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module does the instantiation of generic procs.
|
# This module implements the instantiation of generic procs.
|
||||||
|
|
||||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|
||||||
info: TLineInfo): PSym
|
|
||||||
# generates an instantiated proc
|
|
||||||
|
|
||||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
|
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
|
||||||
if (n.kind != nkGenericParams):
|
if (n.kind != nkGenericParams):
|
||||||
|
|
|
||||||
|
|
@ -561,11 +561,17 @@ proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||||
initCandidate(m, f)
|
initCandidate(m, f)
|
||||||
result = paramTypesMatch(c, m, f, a, arg)
|
result = paramTypesMatch(c, m, f, a, arg)
|
||||||
|
|
||||||
|
proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||||
|
var m: TCandidate
|
||||||
|
initCandidate(m, f)
|
||||||
|
result = paramTypesMatch(c, m, f, a, nil) != nil
|
||||||
|
|
||||||
proc setSon(father: PNode, at: int, son: PNode) =
|
proc setSon(father: PNode, at: int, son: PNode) =
|
||||||
if sonsLen(father) <= at: setlen(father.sons, at + 1)
|
if sonsLen(father) <= at: setlen(father.sons, at + 1)
|
||||||
father.sons[at] = son
|
father.sons[at] = son
|
||||||
|
|
||||||
proc matches*(c: PContext, n: PNode, m: var TCandidate) =
|
proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
|
||||||
|
marker: var TIntSet) =
|
||||||
var f = 1 # iterates over formal parameters
|
var f = 1 # iterates over formal parameters
|
||||||
var a = 1 # iterates over the actual given arguments
|
var a = 1 # iterates over the actual given arguments
|
||||||
m.state = csMatch # until proven otherwise
|
m.state = csMatch # until proven otherwise
|
||||||
|
|
@ -573,8 +579,6 @@ proc matches*(c: PContext, n: PNode, m: var TCandidate) =
|
||||||
m.call.typ = base(m.callee) # may be nil
|
m.call.typ = base(m.callee) # may be nil
|
||||||
var formalLen = sonsLen(m.callee.n)
|
var formalLen = sonsLen(m.callee.n)
|
||||||
addSon(m.call, copyTree(n.sons[0]))
|
addSon(m.call, copyTree(n.sons[0]))
|
||||||
var marker: TIntSet
|
|
||||||
IntSetInit(marker)
|
|
||||||
var container: PNode = nil # constructed container
|
var container: PNode = nil # constructed container
|
||||||
var formal: PSym = nil
|
var formal: PSym = nil
|
||||||
while a < sonsLen(n):
|
while a < sonsLen(n):
|
||||||
|
|
@ -656,13 +660,26 @@ proc matches*(c: PContext, n: PNode, m: var TCandidate) =
|
||||||
setSon(m.call, formal.position + 1, arg)
|
setSon(m.call, formal.position + 1, arg)
|
||||||
inc(a)
|
inc(a)
|
||||||
inc(f)
|
inc(f)
|
||||||
f = 1
|
|
||||||
|
proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) =
|
||||||
|
# for 'suggest' support:
|
||||||
|
var marker: TIntSet
|
||||||
|
IntSetInit(marker)
|
||||||
|
matchesAux(c, n, m, marker)
|
||||||
|
|
||||||
|
proc matches*(c: PContext, n: PNode, m: var TCandidate) =
|
||||||
|
var marker: TIntSet
|
||||||
|
IntSetInit(marker)
|
||||||
|
matchesAux(c, n, m, marker)
|
||||||
|
if m.state == csNoMatch: return
|
||||||
|
# check that every formal parameter got a value:
|
||||||
|
var f = 1
|
||||||
while f < sonsLen(m.callee.n):
|
while f < sonsLen(m.callee.n):
|
||||||
formal = m.callee.n.sons[f].sym
|
var formal = m.callee.n.sons[f].sym
|
||||||
if not IntSetContainsOrIncl(marker, formal.position):
|
if not IntSetContainsOrIncl(marker, formal.position):
|
||||||
if formal.ast == nil:
|
if formal.ast == nil:
|
||||||
if formal.typ.kind == tyOpenArray:
|
if formal.typ.kind == tyOpenArray:
|
||||||
container = newNodeI(nkBracket, n.info)
|
var container = newNodeI(nkBracket, n.info)
|
||||||
addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ,
|
addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ,
|
||||||
container, m, c))
|
container, m, c))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -40,17 +40,11 @@ proc suggestField(s: PSym) =
|
||||||
if filterSym(s):
|
if filterSym(s):
|
||||||
MessageOut(SymToStr(s, isLocal=true))
|
MessageOut(SymToStr(s, isLocal=true))
|
||||||
|
|
||||||
proc suggestExpr*(c: PContext, n: PNode) =
|
template wholeSymTab(cond: expr) =
|
||||||
if not msgs.inCheckpoint(n.info): return
|
|
||||||
|
|
||||||
for i in countdown(c.tab.tos-1, 0):
|
for i in countdown(c.tab.tos-1, 0):
|
||||||
for it in items(c.tab.stack[i]):
|
for it in items(c.tab.stack[i]):
|
||||||
if filterSym(it):
|
if cond:
|
||||||
MessageOut(SymToStr(it, isLocal = i > ModuleTablePos))
|
MessageOut(SymToStr(it, isLocal = i > ModuleTablePos))
|
||||||
quit(0)
|
|
||||||
|
|
||||||
proc suggestStmt*(c: PContext, n: PNode) =
|
|
||||||
suggestExpr(c, n)
|
|
||||||
|
|
||||||
proc suggestSymList(list: PNode) =
|
proc suggestSymList(list: PNode) =
|
||||||
for i in countup(0, sonsLen(list) - 1):
|
for i in countup(0, sonsLen(list) - 1):
|
||||||
|
|
@ -60,20 +54,45 @@ proc suggestSymList(list: PNode) =
|
||||||
proc suggestObject(n: PNode) =
|
proc suggestObject(n: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
for i in countup(0, sonsLen(n) - 1): suggestObject(n.sons[i])
|
for i in countup(0, sonsLen(n)-1): suggestObject(n.sons[i])
|
||||||
of nkRecCase:
|
of nkRecCase:
|
||||||
var L = sonsLen(n)
|
var L = sonsLen(n)
|
||||||
if L > 0:
|
if L > 0:
|
||||||
suggestObject(n.sons[0])
|
suggestObject(n.sons[0])
|
||||||
for i in countup(1, L-1):
|
for i in countup(1, L-1): suggestObject(lastSon(n.sons[i]))
|
||||||
suggestObject(lastSon(n.sons[i]))
|
|
||||||
of nkSym: suggestField(n.sym)
|
of nkSym: suggestField(n.sym)
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
proc suggestOperations(c: PContext, n: PNode, typ: PType) =
|
proc nameFits(c: PContext, s: PSym, n: PNode): bool =
|
||||||
nil
|
result = n.sons[0].kind == nkSym and n.sons[0].sym.name.id == s.name.id
|
||||||
|
|
||||||
proc suggestFieldAccess*(c: PContext, n: PNode) =
|
proc argsFit(c: PContext, candidate: PSym, n: PNode): bool =
|
||||||
|
case candidate.kind
|
||||||
|
of skProc, skIterator, skMethod:
|
||||||
|
var m: TCandidate
|
||||||
|
initCandidate(m, candidate, nil)
|
||||||
|
sigmatch.partialMatch(c, n, m)
|
||||||
|
result = m.state != csNoMatch
|
||||||
|
of skTemplate, skMacro:
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
result = false
|
||||||
|
|
||||||
|
proc suggestCall*(c: PContext, n: PNode) =
|
||||||
|
wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n))
|
||||||
|
|
||||||
|
proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
|
||||||
|
if s.typ != nil and sonsLen(s.typ) > 1:
|
||||||
|
result = sigmatch.argtypeMatches(c, s.typ.sons[1], firstArg)
|
||||||
|
|
||||||
|
proc suggestOperations(c: PContext, n: PNode, typ: PType) =
|
||||||
|
assert typ != nil
|
||||||
|
wholeSymTab(filterSym(it) and typeFits(c, it, typ))
|
||||||
|
|
||||||
|
proc suggestEverything(c: PContext, n: PNode) =
|
||||||
|
wholeSymTab(filterSym(it))
|
||||||
|
|
||||||
|
proc suggestFieldAccess(c: PContext, n: PNode) =
|
||||||
# special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
|
# special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
|
||||||
# ``myObj``.
|
# ``myObj``.
|
||||||
var typ = n.Typ
|
var typ = n.Typ
|
||||||
|
|
@ -89,7 +108,7 @@ proc suggestFieldAccess*(c: PContext, n: PNode) =
|
||||||
if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
|
if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
|
||||||
else:
|
else:
|
||||||
# fallback:
|
# fallback:
|
||||||
suggestExpr(c, n)
|
suggestEverything(c, n)
|
||||||
elif typ.kind == tyEnum:
|
elif typ.kind == tyEnum:
|
||||||
# look up if the identifier belongs to the enum:
|
# look up if the identifier belongs to the enum:
|
||||||
var t = typ
|
var t = typ
|
||||||
|
|
@ -111,5 +130,32 @@ proc suggestFieldAccess*(c: PContext, n: PNode) =
|
||||||
suggestOperations(c, n, typ)
|
suggestOperations(c, n, typ)
|
||||||
else:
|
else:
|
||||||
# fallback:
|
# fallback:
|
||||||
|
suggestEverything(c, n)
|
||||||
|
|
||||||
|
proc suggestExpr*(c: PContext, n: PNode) =
|
||||||
|
var cp = msgs.inCheckpoint(n.info)
|
||||||
|
if cp == cpNone: return
|
||||||
|
block:
|
||||||
|
case n.kind
|
||||||
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand,
|
||||||
|
nkCallStrLit, nkMacroStmt:
|
||||||
|
var a = copyNode(n)
|
||||||
|
for i in 0..sonsLen(n)-1:
|
||||||
|
# use as many typed arguments as possible:
|
||||||
|
var x = c.semExpr(c, n.sons[i])
|
||||||
|
if x.kind == nkEmpty or x.typ == nil: break
|
||||||
|
addSon(a, x)
|
||||||
|
suggestCall(c, n)
|
||||||
|
break
|
||||||
|
of nkDotExpr:
|
||||||
|
if cp == cpExact:
|
||||||
|
var obj = c.semExpr(c, n.sons[0])
|
||||||
|
suggestFieldAccess(c, obj)
|
||||||
|
break
|
||||||
|
else: nil
|
||||||
|
suggestEverything(c, n)
|
||||||
|
quit(0)
|
||||||
|
|
||||||
|
proc suggestStmt*(c: PContext, n: PNode) =
|
||||||
suggestExpr(c, n)
|
suggestExpr(c, n)
|
||||||
|
|
||||||
|
|
|
||||||
3
todo.txt
3
todo.txt
|
|
@ -1,4 +1,4 @@
|
||||||
- 'suggest' needs tweaking: support for '.'
|
- 'suggest' needs tweaking: end-token; testing!
|
||||||
- stdout support for doc, pretty
|
- stdout support for doc, pretty
|
||||||
|
|
||||||
- thread support: threadvar on Windows seems broken;
|
- thread support: threadvar on Windows seems broken;
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
High priority (version 0.9.0)
|
High priority (version 0.9.0)
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
|
|
||||||
- fix implicit generic routines
|
- fix implicit generic routines
|
||||||
- fix the streams implementation so that it uses methods
|
- fix the streams implementation so that it uses methods
|
||||||
- fix overloading resolution
|
- fix overloading resolution
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue