# # # The Nim Compiler # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # This module implements lookup helpers. import intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, renderer, wordrecg, idgen, nimfix.prettybase proc ensureNoMissingOrUnusedSymbols(scope: PScope) proc noidentError(n, origin: PNode) = var m = "" if origin != nil: m.add "in expression '" & origin.renderTree & "': " m.add "identifier expected, but found '" & n.renderTree & "'" localError(n.info, m) proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent = ## Retrieve a PIdent from a PNode, taking into account accent nodes. ## ``origin`` can be nil. If it is not nil, it is used for a better ## error message. template handleError(n, origin: PNode) = noidentError(n, origin) result = getIdent"" case n.kind of nkIdent: result = n.ident of nkSym: result = n.sym.name of nkAccQuoted: case n.len of 0: handleError(n, origin) of 1: result = considerQuotedIdent(n.sons[0], origin) else: var id = "" for i in 0.. 0: err.add "\nThis might be caused by a recursive module dependency: " err.add c.recursiveDep # prevent excessive errors for 'nim check' c.recursiveDep = nil localError(info, errGenerated, err) proc lookUp*(c: PContext, n: PNode): PSym = # Looks up a symbol. Generates an error in case of nil. case n.kind of nkIdent: result = searchInScopes(c, n.ident).skipAlias(n) if result == nil: fixSpelling(n, n.ident, searchInScopes) errorUndeclaredIdentifier(c, n.info, n.ident.s) result = errorSym(c, n) of nkSym: result = n.sym of nkAccQuoted: var ident = considerQuotedIdent(n) result = searchInScopes(c, ident).skipAlias(n) if result == nil: fixSpelling(n, ident, searchInScopes) errorUndeclaredIdentifier(c, n.info, ident.s) result = errorSym(c, n) else: internalError(n.info, "lookUp") return if contains(c.ambiguousSymbols, result.id): errorUseQualifier(c, n.info, result) if result.kind == skStub: loadStub(result) type TLookupFlag* = enum checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage} case n.kind of nkIdent, nkAccQuoted: var ident = considerQuotedIdent(n) if checkModule in flags: result = searchInScopes(c, ident).skipAlias(n) else: result = searchInScopes(c, ident, allExceptModule).skipAlias(n) if result == nil and checkPureEnumFields in flags: result = strTableGet(c.pureEnumFields, ident) if result == nil and checkUndeclared in flags: fixSpelling(n, ident, searchInScopes) errorUndeclaredIdentifier(c, n.info, ident.s) result = errorSym(c, n) elif checkAmbiguity in flags and result != nil and contains(c.ambiguousSymbols, result.id): errorUseQualifier(c, n.info, result) of nkSym: result = n.sym if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id): errorUseQualifier(c, n.info, n.sym) of nkDotExpr: result = nil var m = qualifiedLookUp(c, n.sons[0], (flags*{checkUndeclared})+{checkModule}) if m != nil and m.kind == skModule: var ident: PIdent = nil if n.sons[1].kind == nkIdent: ident = n.sons[1].ident elif n.sons[1].kind == nkAccQuoted: ident = considerQuotedIdent(n.sons[1]) if ident != nil: if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n) else: result = strTableGet(m.tab, ident).skipAlias(n) if result == nil and checkUndeclared in flags: fixSpelling(n.sons[1], ident, searchInScopes) errorUndeclaredIdentifier(c, n.sons[1].info, ident.s) result = errorSym(c, n.sons[1]) elif n.sons[1].kind == nkSym: result = n.sons[1].sym elif checkUndeclared in flags and n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}: localError(n.sons[1].info, errIdentifierExpected, renderTree(n.sons[1])) result = errorSym(c, n.sons[1]) else: result = nil if result != nil and result.kind == skStub: loadStub(result) proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = case n.kind of nkIdent, nkAccQuoted: var ident = considerQuotedIdent(n) o.scope = c.currentScope o.mode = oimNoQualifier while true: result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n) if result != nil: break else: o.scope = o.scope.parent if o.scope == nil: break of nkSym: result = n.sym o.mode = oimDone of nkDotExpr: o.mode = oimOtherModule o.m = qualifiedLookUp(c, n.sons[0], {checkUndeclared, checkModule}) if o.m != nil and o.m.kind == skModule: var ident: PIdent = nil if n.sons[1].kind == nkIdent: ident = n.sons[1].ident elif n.sons[1].kind == nkAccQuoted: ident = considerQuotedIdent(n.sons[1], n) if ident != nil: if o.m == c.module: # a module may access its private members: result = initIdentIter(o.it, c.topLevelScope.symbols, ident).skipAlias(n) o.mode = oimSelfModule else: result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n) else: noidentError(n.sons[1], n) result = errorSym(c, n.sons[1]) of nkClosedSymChoice, nkOpenSymChoice: o.mode = oimSymChoice if n[0].kind == nkSym: result = n.sons[0].sym else: o.mode = oimDone return nil o.symChoiceIndex = 1 o.inSymChoice = initIntSet() incl(o.inSymChoice, result.id) else: discard if result != nil and result.kind == skStub: loadStub(result) proc lastOverloadScope*(o: TOverloadIter): int = case o.mode of oimNoQualifier: result = if o.scope.isNil: -1 else: o.scope.depthLevel of oimSelfModule: result = 1 of oimOtherModule: result = 0 else: result = -1 proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = case o.mode of oimDone: result = nil of oimNoQualifier: if o.scope != nil: result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n) while result == nil: o.scope = o.scope.parent if o.scope == nil: break result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n) # BUGFIX: o.it.name <-> n.ident else: result = nil of oimSelfModule: result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n) of oimOtherModule: result = nextIdentIter(o.it, o.m.tab).skipAlias(n) of oimSymChoice: if o.symChoiceIndex < sonsLen(n): result = n.sons[o.symChoiceIndex].sym incl(o.inSymChoice, result.id) inc o.symChoiceIndex elif n.kind == nkOpenSymChoice: # try 'local' symbols too for Koenig's lookup: o.mode = oimSymChoiceLocalLookup o.scope = c.currentScope result = firstIdentExcluding(o.it, o.scope.symbols, n.sons[0].sym.name, o.inSymChoice).skipAlias(n) while result == nil: o.scope = o.scope.parent if o.scope == nil: break result = firstIdentExcluding(o.it, o.scope.symbols, n.sons[0].sym.name, o.inSymChoice).skipAlias(n) of oimSymChoiceLocalLookup: result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n) while result == nil: o.scope = o.scope.parent if o.scope == nil: break result = firstIdentExcluding(o.it, o.scope.symbols, n.sons[0].sym.name, o.inSymChoice).skipAlias(n) if result != nil and result.kind == skStub: loadStub(result) proc pickSym*(c: PContext, n: PNode; kind: TSymKind; flags: TSymFlags = {}): PSym = var o: TOverloadIter var a = initOverloadIter(o, c, n) while a != nil: if a.kind == kind and flags <= a.flags: return a a = nextOverloadIter(o, c, n) proc isInfixAs*(n: PNode): bool = return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"