disable the undocumented 'import ' feature; allow import std / strutils; fixes #2819; refs #6700

This commit is contained in:
Andreas Rumpf 2018-02-12 16:36:19 +01:00
commit cddc389784
3 changed files with 119 additions and 96 deletions

View file

@ -251,3 +251,12 @@ bar()
- The ``securehash`` module is now deprecated. Instead import ``std / sha1``. - The ``securehash`` module is now deprecated. Instead import ``std / sha1``.
- ``db_mysql`` module: ``DbConn`` is now a ``distinct`` type that doesn't expose the - ``db_mysql`` module: ``DbConn`` is now a ``distinct`` type that doesn't expose the
details of the underlying ``PMySQL`` type. details of the underlying ``PMySQL`` type.
- Standard library modules can now also be imported via the ``std`` pseudo-directory.
This is useful in order to distinguish between standard library and nimble package
imports:
```nim
import std / [strutils, os, osproc]
import someNimblePackage / [strutils, os]
```

View file

@ -274,9 +274,10 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
proc processPath(path: string, info: TLineInfo, proc processPath(path: string, info: TLineInfo,
notRelativeToProj = false): string = notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or let p = if os.isAbsolute(path) or '$' in path:
'$' in path:
path path
elif notRelativeToProj:
getCurrentDir() / path
else: else:
options.gProjectPath / path options.gProjectPath / path
try: try:

View file

@ -11,38 +11,39 @@ import ast, renderer, strutils, msgs, options, idents, os
import nimblecmd import nimblecmd
const when false:
considerParentDirs = not defined(noParentProjects) const
considerNimbleDirs = not defined(noNimbleDirs) considerParentDirs = not defined(noParentProjects)
considerNimbleDirs = not defined(noNimbleDirs)
proc findInNimbleDir(pkg, subdir, dir: string): string = proc findInNimbleDir(pkg, subdir, dir: string): string =
var best = "" var best = ""
var bestv = "" var bestv = ""
for k, p in os.walkDir(dir, relative=true): for k, p in os.walkDir(dir, relative=true):
if k == pcDir and p.len > pkg.len+1 and if k == pcDir and p.len > pkg.len+1 and
p[pkg.len] == '-' and p.startsWith(pkg): p[pkg.len] == '-' and p.startsWith(pkg):
let (_, a) = getPathVersion(p) let (_, a) = getPathVersion(p)
if bestv.len == 0 or bestv < a: if bestv.len == 0 or bestv < a:
bestv = a bestv = a
best = dir / p best = dir / p
if best.len > 0: if best.len > 0:
var f: File var f: File
if open(f, best / changeFileExt(pkg, ".nimble-link")): if open(f, best / changeFileExt(pkg, ".nimble-link")):
# the second line contains what we're interested in, see: # the second line contains what we're interested in, see:
# https://github.com/nim-lang/nimble#nimble-link # https://github.com/nim-lang/nimble#nimble-link
var override = "" var override = ""
discard readLine(f, override) discard readLine(f, override)
discard readLine(f, override) discard readLine(f, override)
close(f) close(f)
if not override.isAbsolute(): if not override.isAbsolute():
best = best / override best = best / override
else: else:
best = override best = override
let f = if subdir.len == 0: pkg else: subdir let f = if subdir.len == 0: pkg else: subdir
let res = addFileExt(best / f, "nim") let res = addFileExt(best / f, "nim")
if best.len > 0 and fileExists(res): if best.len > 0 and fileExists(res):
result = res result = res
const stdlibDirs = [ const stdlibDirs = [
"pure", "core", "arch", "pure", "core", "arch",
@ -51,65 +52,66 @@ const stdlibDirs = [
"wrappers", "wrappers/linenoise", "wrappers", "wrappers/linenoise",
"windows", "posix", "js"] "windows", "posix", "js"]
proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string = when false:
template attempt(a) = proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
let x = addFileExt(a, "nim") template attempt(a) =
if fileExists(x): return x let x = addFileExt(a, "nim")
if fileExists(x): return x
case pkg case pkg
of "stdlib": of "stdlib":
if subdir.len == 0: if subdir.len == 0:
return options.libpath 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: else:
for candidate in stdlibDirs: when considerParentDirs:
attempt(options.libpath / candidate / subdir) var p = parentDir(source.splitFile.dir)
of "root": # support 'import $karax':
let root = project.splitFile.dir let f = if subdir.len == 0: pkg else: subdir
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: while p.len > 0:
let dir = p / pkg let dir = p / pkg
if dirExists(dir): if dirExists(dir):
attempt(dir / f) attempt(dir / f)
# 2nd attempt: try to use 'karax/karax' # 2nd attempt: try to use 'karax/karax'
attempt(dir / pkg / f) attempt(dir / pkg / f)
# 3rd attempt: try to use 'karax/src/karax' # 3rd attempt: try to use 'karax/src/karax'
attempt(dir / "src" / f) attempt(dir / "src" / f)
attempt(dir / "src" / pkg / f) attempt(dir / "src" / pkg / f)
p = parentDir(p) p = parentDir(p)
when considerNimbleDirs: when considerNimbleDirs:
if not options.gNoNimblePath: if not options.gNoNimblePath:
var nimbleDir = getEnv("NIMBLE_DIR") var nimbleDir = getEnv("NIMBLE_DIR")
if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble"
result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs") 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 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 = proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
if result.isNil: result = "" if result.isNil: result = ""
proc lookupPackage(pkg, subdir: PNode): string = proc lookupPackage(pkg, subdir: PNode): string =
let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: "" let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
case pkg.kind case pkg.kind
of nkStrLit, nkRStrLit, nkTripleStrLit: of nkStrLit, nkRStrLit, nkTripleStrLit:
result = scriptableImport(pkg.strVal, sub, pkg.info) result = scriptableImport(pkg.strVal, sub, pkg.info)
of nkIdent: of nkIdent:
result = scriptableImport(pkg.ident.s, sub, pkg.info) result = scriptableImport(pkg.ident.s, sub, pkg.info)
else: else:
localError(pkg.info, "package name must be an identifier or string literal") localError(pkg.info, "package name must be an identifier or string literal")
result = "" result = ""
proc getModuleName*(n: PNode): string = proc getModuleName*(n: PNode): string =
# This returns a short relative module name without the nim extension # This returns a short relative module name without the nim extension
@ -136,23 +138,34 @@ proc getModuleName*(n: PNode): string =
n.sons[1] = n.sons[2] n.sons[1] = n.sons[2]
n.sons.setLen(2) n.sons.setLen(2)
return getModuleName(n.sons[0]) return getModuleName(n.sons[0])
if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$": when false:
if n0.kind == nkIdent and n0.ident.s == "/": if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
result = lookupPackage(n1[1], n[2]) if n0.kind == nkIdent and n0.ident.s == "/":
else: result = lookupPackage(n1[1], n[2])
localError(n.info, "only '/' supported with $package notation") else:
result = "" localError(n.info, "only '/' supported with $package notation")
result = ""
else: else:
let modname = getModuleName(n[2])
if $n1 == "std":
template attempt(a) =
let x = addFileExt(a, "nim")
if fileExists(x): return x
for candidate in stdlibDirs:
attempt(options.libpath / candidate / modname)
# hacky way to implement 'x / y /../ z': # hacky way to implement 'x / y /../ z':
result = getModuleName(n1) result = getModuleName(n1)
result.add renderTree(n0, {renderNoComments}) result.add renderTree(n0, {renderNoComments})
result.add getModuleName(n[2]) result.add modname
of nkPrefix: of nkPrefix:
if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$": when false:
result = lookupPackage(n[1], nil) if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
else: result = lookupPackage(n[1], nil)
# hacky way to implement 'x / y /../ z': else:
result = renderTree(n, {renderNoComments}).replace(" ") discard
# hacky way to implement 'x / y /../ z':
result = renderTree(n, {renderNoComments}).replace(" ")
of nkDotExpr: of nkDotExpr:
result = renderTree(n, {renderNoComments}).replace(".", "/") result = renderTree(n, {renderNoComments}).replace(".", "/")
of nkImportAs: of nkImportAs: