diff options
-rwxr-xr-x | rod/msgs.nim | 23 | ||||
-rwxr-xr-x | rod/sem.nim | 6 | ||||
-rwxr-xr-x | rod/semexprs.nim | 2 | ||||
-rwxr-xr-x | rod/seminst.nim | 6 | ||||
-rwxr-xr-x | rod/sigmatch.nim | 29 | ||||
-rw-r--r-- | rod/suggest.nim | 76 | ||||
-rwxr-xr-x | todo.txt | 3 |
7 files changed, 105 insertions, 40 deletions
diff --git a/rod/msgs.nim b/rod/msgs.nim index 00ec61941..ef3886344 100755 --- a/rod/msgs.nim +++ b/rod/msgs.nim @@ -398,8 +398,8 @@ proc UnknownLineInfo*(): TLineInfo = result.fileIndex = -1 var - filenames: seq[string] = @ [] - msgContext: seq[TLineInfo] = @ [] + filenames: seq[string] = @[] + msgContext: seq[TLineInfo] = @[] proc pushInfoContext*(info: TLineInfo) = msgContext.add(info) @@ -424,10 +424,10 @@ proc ToFilename*(info: TLineInfo): string = if info.fileIndex == - 1: result = "???" else: result = filenames[info.fileIndex] -proc ToLinenumber*(info: TLineInfo): int = +proc ToLinenumber*(info: TLineInfo): int {.inline.} = result = info.line -proc toColumn*(info: TLineInfo): int = +proc toColumn*(info: TLineInfo): int {.inline.} = result = info.col var checkPoints: seq[TLineInfo] = @[] @@ -453,11 +453,18 @@ proc MsgKindToString*(kind: TMsgKind): string = proc getMessageStr(msg: TMsgKind, arg: string): string = 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)): - if (current.line >= checkPoints[i].line) and - (current.fileIndex == (checkPoints[i].fileIndex)): - return true + if current.fileIndex == checkPoints[i].fileIndex: + if current.line == checkPoints[i].line and + abs(current.col-checkPoints[i].col) < 4: + return cpExact + if current.line >= checkPoints[i].line: + return cpFuzzy type TErrorHandling = enum doNothing, doAbort, doRaise diff --git a/rod/sem.nim b/rod/sem.nim index 66fc66cbe..eec579dda 100755 --- a/rod/sem.nim +++ b/rod/sem.nim @@ -28,8 +28,10 @@ proc considerAcc(n: PNode): PIdent = GlobalError(n.info, errIdentifierExpected, renderTree(n)) result = nil -proc isTopLevel(c: PContext): bool = - result = c.tab.tos <= 2 +proc isTopLevel(c: PContext): bool {.inline.} = + # 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 = result = newSym(kind, considerAcc(n), getCurrOwner()) diff --git a/rod/semexprs.nim b/rod/semexprs.nim index b16bf11dc..762eb951a 100755 --- a/rod/semexprs.nim +++ b/rod/semexprs.nim @@ -641,8 +641,6 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = checkSonsLen(n, 2) 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 ty = n.sons[0].Typ var f: PSym = nil diff --git a/rod/seminst.nim b/rod/seminst.nim index d32aff15e..3cd86b904 100755 --- a/rod/seminst.nim +++ b/rod/seminst.nim @@ -7,11 +7,7 @@ # distribution, for details about the copyright. # -# This module does the instantiation of generic procs. - -proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, - info: TLineInfo): PSym - # generates an instantiated proc +# This module implements the instantiation of generic procs. proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) = if (n.kind != nkGenericParams): diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim index dc0b1bbc4..b25008e1e 100755 --- a/rod/sigmatch.nim +++ b/rod/sigmatch.nim @@ -561,11 +561,17 @@ proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode = initCandidate(m, f) 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) = if sonsLen(father) <= at: setlen(father.sons, at + 1) 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 a = 1 # iterates over the actual given arguments 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 var formalLen = sonsLen(m.callee.n) addSon(m.call, copyTree(n.sons[0])) - var marker: TIntSet - IntSetInit(marker) var container: PNode = nil # constructed container var formal: PSym = nil while a < sonsLen(n): @@ -656,13 +660,26 @@ proc matches*(c: PContext, n: PNode, m: var TCandidate) = setSon(m.call, formal.position + 1, arg) inc(a) 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): - formal = m.callee.n.sons[f].sym + var formal = m.callee.n.sons[f].sym if not IntSetContainsOrIncl(marker, formal.position): if formal.ast == nil: if formal.typ.kind == tyOpenArray: - container = newNodeI(nkBracket, n.info) + var container = newNodeI(nkBracket, n.info) addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) else: diff --git a/rod/suggest.nim b/rod/suggest.nim index 5eaa2bd9e..bddb247c3 100644 --- a/rod/suggest.nim +++ b/rod/suggest.nim @@ -40,17 +40,11 @@ proc suggestField(s: PSym) = if filterSym(s): MessageOut(SymToStr(s, isLocal=true)) -proc suggestExpr*(c: PContext, n: PNode) = - if not msgs.inCheckpoint(n.info): return - +template wholeSymTab(cond: expr) = for i in countdown(c.tab.tos-1, 0): for it in items(c.tab.stack[i]): - if filterSym(it): + if cond: MessageOut(SymToStr(it, isLocal = i > ModuleTablePos)) - quit(0) - -proc suggestStmt*(c: PContext, n: PNode) = - suggestExpr(c, n) proc suggestSymList(list: PNode) = for i in countup(0, sonsLen(list) - 1): @@ -60,20 +54,45 @@ proc suggestSymList(list: PNode) = proc suggestObject(n: PNode) = case n.kind 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: var L = sonsLen(n) if L > 0: suggestObject(n.sons[0]) - for i in countup(1, L-1): - suggestObject(lastSon(n.sons[i])) + for i in countup(1, L-1): suggestObject(lastSon(n.sons[i])) of nkSym: suggestField(n.sym) else: nil +proc nameFits(c: PContext, s: PSym, n: PNode): bool = + result = n.sons[0].kind == nkSym and n.sons[0].sym.name.id == s.name.id + +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) = - nil + 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) = +proc suggestFieldAccess(c: PContext, n: PNode) = # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but # ``myObj``. var typ = n.Typ @@ -89,7 +108,7 @@ proc suggestFieldAccess*(c: PContext, n: PNode) = if filterSym(it): MessageOut(SymToStr(it, isLocal=false)) else: # fallback: - suggestExpr(c, n) + suggestEverything(c, n) elif typ.kind == tyEnum: # look up if the identifier belongs to the enum: var t = typ @@ -111,5 +130,32 @@ proc suggestFieldAccess*(c: PContext, n: PNode) = suggestOperations(c, n, typ) else: # fallback: - suggestExpr(c, n) + 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) diff --git a/todo.txt b/todo.txt index 3ce1fb65a..aa51ab09a 100755 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,4 @@ -- 'suggest' needs tweaking: support for '.' +- 'suggest' needs tweaking: end-token; testing! - stdout support for doc, pretty - thread support: threadvar on Windows seems broken; @@ -16,7 +16,6 @@ High priority (version 0.9.0) ============================= - - fix implicit generic routines - fix the streams implementation so that it uses methods - fix overloading resolution |