123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2017 Contributors
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
- pathutils
- when false:
- const
- considerParentDirs = not defined(noParentProjects)
- considerNimbleDirs = not defined(noNimbleDirs)
- proc findInNimbleDir(pkg, subdir, dir: string): string =
- var best = ""
- var bestv = ""
- for k, p in os.walkDir(dir, relative=true):
- if k == pcDir and p.len > pkg.len+1 and
- p[pkg.len] == '-' and p.startsWith(pkg):
- let (_, a) = getPathVersion(p)
- if bestv.len == 0 or bestv < a:
- bestv = a
- best = dir / p
- if best.len > 0:
- var f: File
- if open(f, best / changeFileExt(pkg, ".nimble-link")):
- # the second line contains what we're interested in, see:
- # https://github.com/nim-lang/nimble#nimble-link
- var override = ""
- discard readLine(f, override)
- discard readLine(f, override)
- close(f)
- if not override.isAbsolute():
- best = best / override
- else:
- best = override
- let f = if subdir.len == 0: pkg else: subdir
- let res = addFileExt(best / f, "nim")
- if best.len > 0 and fileExists(res):
- result = res
- when false:
- proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
- template attempt(a) =
- let x = addFileExt(a, "nim")
- if fileExists(x): return x
- case pkg
- of "stdlib":
- if subdir.len == 0:
- return options.libpath
- else:
- for candidate in stdlibDirs:
- attempt(options.libpath / candidate / subdir)
- of "root":
- let root = project.splitFile.dir
- if subdir.len == 0:
- return root
- else:
- attempt(root / subdir)
- else:
- when considerParentDirs:
- var p = parentDir(source.splitFile.dir)
- # support 'import $karax':
- let f = if subdir.len == 0: pkg else: subdir
- while p.len > 0:
- let dir = p / pkg
- if dirExists(dir):
- attempt(dir / f)
- # 2nd attempt: try to use 'karax/karax'
- attempt(dir / pkg / f)
- # 3rd attempt: try to use 'karax/src/karax'
- attempt(dir / "src" / f)
- attempt(dir / "src" / pkg / f)
- p = parentDir(p)
- when considerNimbleDirs:
- if not options.gNoNimblePath:
- var nimbleDir = getEnv("NIMBLE_DIR")
- if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble"
- result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs")
- if result.len > 0: return result
- when not defined(windows):
- result = findInNimbleDir(pkg, subdir, "/opt/nimble/pkgs")
- if result.len > 0: return result
- proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
- resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
- proc lookupPackage(pkg, subdir: PNode): string =
- let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
- case pkg.kind
- of nkStrLit, nkRStrLit, nkTripleStrLit:
- result = scriptableImport(pkg.strVal, sub, pkg.info)
- of nkIdent:
- result = scriptableImport(pkg.ident.s, sub, pkg.info)
- else:
- localError(pkg.info, "package name must be an identifier or string literal")
- result = ""
- proc getModuleName*(conf: ConfigRef; n: PNode): string =
- # This returns a short relative module name without the nim extension
- # e.g. like "system", "importer" or "somepath/module"
- # The proc won't perform any checks that the path is actually valid
- case n.kind
- of nkStrLit, nkRStrLit, nkTripleStrLit:
- try:
- result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
- except ValueError:
- localError(conf, n.info, "invalid path: " & n.strVal)
- result = n.strVal
- of nkIdent:
- result = n.ident.s
- of nkSym:
- result = n.sym.name.s
- of nkInfix:
- let n0 = n[0]
- let n1 = n[1]
- when false:
- if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
- if n0.kind == nkIdent and n0.ident.s == "/":
- result = lookupPackage(n1[1], n[2])
- else:
- localError(n.info, "only '/' supported with $package notation")
- result = ""
- else:
- let modname = getModuleName(conf, n[2])
- # hacky way to implement 'x / y /../ z':
- result = getModuleName(conf, n1)
- result.add renderTree(n0, {renderNoComments}).replace(" ")
- result.add modname
- of nkPrefix:
- when false:
- if n[0].kind == nkIdent and n[0].ident.s == "$":
- result = lookupPackage(n[1], nil)
- else:
- discard
- # hacky way to implement 'x / y /../ z':
- result = renderTree(n, {renderNoComments}).replace(" ")
- of nkDotExpr:
- localError(conf, n.info, warnDeprecated, "using '.' instead of '/' in import paths is deprecated")
- result = renderTree(n, {renderNoComments}).replace(".", "/")
- of nkImportAs:
- result = getModuleName(conf, n[0])
- else:
- localError(conf, n.info, "invalid module name: '$1'" % n.renderTree)
- result = ""
- proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
- # This returns the full canonical path for a given module import
- let modulename = getModuleName(conf, n)
- let fullPath = findModule(conf, modulename, toFullPath(conf, n.info))
- if fullPath.isEmpty:
- if doLocalError:
- let m = if modulename.len > 0: modulename else: $n
- localError(conf, n.info, "cannot open file: " & m)
- result = InvalidFileIdx
- else:
- result = fileInfoIdx(conf, fullPath)
|