From e2af486434c7ff401c412d890b490b4ac11ab321 Mon Sep 17 00:00:00 2001 From: BigEpsilon Date: Sat, 28 Oct 2017 11:33:35 +0200 Subject: Add sections (type, var, let, const, using) support for reorder pragma (#6326) --- compiler/modulepaths.nim | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 compiler/modulepaths.nim (limited to 'compiler/modulepaths.nim') diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim new file mode 100644 index 000000000..6b9865677 --- /dev/null +++ b/compiler/modulepaths.nim @@ -0,0 +1,78 @@ +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import ast, renderer, gorgeimpl, strutils, msgs, options, idents, ospaths + +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*(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(n.strVal, n.info.toFullPath().splitFile().dir) + except ValueError: + localError(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] + if n0.kind == nkIdent and n0.ident.id == getIdent("as").id: + # XXX hack ahead: + n.kind = nkImportAs + n.sons[0] = n.sons[1] + n.sons[1] = n.sons[2] + n.sons.setLen(2) + return getModuleName(n.sons[0]) + 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: + # hacky way to implement 'x / y /../ z': + result = getModuleName(n1) + result.add renderTree(n0, {renderNoComments}) + result.add getModuleName(n[2]) + of nkPrefix: + if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$": + result = lookupPackage(n[1], nil) + else: + # hacky way to implement 'x / y /../ z': + result = renderTree(n, {renderNoComments}).replace(" ") + of nkDotExpr: + result = renderTree(n, {renderNoComments}).replace(".", "/") + of nkImportAs: + result = getModuleName(n.sons[0]) + else: + localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree) + result = "" + +proc checkModuleName*(n: PNode; doLocalError=true): int32 = + # This returns the full canonical path for a given module import + let modulename = n.getModuleName + let fullPath = findModule(modulename, n.info.toFullPath) + if fullPath.len == 0: + if doLocalError: + localError(n.info, errCannotOpenFile, modulename) + result = InvalidFileIDX + else: + result = fullPath.fileInfoIdx \ No newline at end of file -- cgit 1.4.1-2-gfad0 From 29c075299d12111cf8925a14d544008fb416ec7e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Oct 2017 15:40:50 +0100 Subject: made nimresolve part of the compiler --- compiler/gorgeimpl.nim | 28 +-------- compiler/modulepaths.nim | 96 +++++++++++++++++++++++++++- compiler/semcall.nim | 2 +- compiler/sigmatch.nim | 2 +- koch.nim | 2 +- todo.txt | 3 +- tools/nimresolve.nim | 160 ----------------------------------------------- 7 files changed, 100 insertions(+), 193 deletions(-) delete mode 100644 tools/nimresolve.nim (limited to 'compiler/modulepaths.nim') diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index 4e1ce6d50..2c51752cd 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -7,8 +7,7 @@ # distribution, for details about the copyright. # -## Module that implements ``gorge`` for the compiler as well as -## the scriptable import mechanism. +## Module that implements ``gorge`` for the compiler. import msgs, securehash, os, osproc, streams, strutils, options @@ -56,28 +55,3 @@ proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) = result = p.readOutput except IOError, OSError: result = ("", -1) - -proc scriptableImport*(pkg, subdir: string; info: TLineInfo): string = - var cmd = getConfigVar("resolver.exe") - if cmd.len == 0: cmd = "nimresolve" - else: cmd = quoteShell(cmd) - cmd.add " --source:" - cmd.add quoteShell(info.toFullPath()) - cmd.add " --stdlib:" - cmd.add quoteShell(options.libpath) - cmd.add " --project:" - cmd.add quoteShell(gProjectFull) - if subdir.len != 0: - cmd.add " --subdir:" - cmd.add quoteShell(subdir) - if options.gNoNimblePath: - cmd.add " --nonimblepath" - cmd.add ' ' - cmd.add quoteShell(pkg) - let (res, exitCode) = opGorge(cmd, "", cmd, info) - if exitCode == 0: - result = res.strip() - elif res.len > 0: - localError(info, res) - else: - localError(info, "cannot resolve: " & (pkg / subdir)) diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 6b9865677..d7b5f147d 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -1,9 +1,103 @@ # +# +# The Nim Compiler +# (c) Copyright 2017 Contributors +# # See the file "copying.txt", included in this # distribution, for details about the copyright. # -import ast, renderer, gorgeimpl, strutils, msgs, options, idents, ospaths +import ast, renderer, strutils, msgs, options, idents, os + +import nimblecmd + +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 + +const stdlibDirs = [ + "pure", "core", "arch", + "pure/collections", + "pure/concurrency", "impure", + "wrappers", "wrappers/linenoise", + "windows", "posix", "js"] + +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 = + result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) proc lookupPackage(pkg, subdir: PNode): string = let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: "" diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 71afba324..5c0624a77 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -27,7 +27,7 @@ proc sameMethodDispatcher(a, b: PSym): bool = # method collide[T](a: TThing, b: TUnit[T]) is instantiated and not # method collide[T](a: TUnit[T], b: TThing)! This means we need to # *instantiate* every candidate! However, we don't keep more than 2-3 - # candidated around so we cannot implement that for now. So in order + # candidates around so we cannot implement that for now. So in order # to avoid subtle problems, the call remains ambiguous and needs to # be disambiguated by the programmer; this way the right generic is # instantiated. diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 38899182d..1494c5316 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -55,6 +55,7 @@ type # a distrinct type typedescMatched*: bool isNoCall*: bool # misused for generic type instantiations C[T] + mutabilityProblem*: uint8 # tyVar mismatch inferredTypes: seq[PType] # inferred types during the current signature # matching. they will be reset if the matching # is not successful. may replace the bindings @@ -66,7 +67,6 @@ type # or when the explain pragma is used. may be # triggered with an idetools command in the # future. - mutabilityProblem*: uint8 # tyVar mismatch inheritancePenalty: int # to prefer closest father object type TTypeRelFlag* = enum diff --git a/koch.nim b/koch.nim index b79e202b2..dd4213437 100644 --- a/koch.nim +++ b/koch.nim @@ -263,7 +263,7 @@ proc buildTools(latest: bool) = nimexec "c -o:" & nimgrepExe & " tools/nimgrep.nim" when defined(windows): buildVccTool() - nimexec "c -o:" & ("bin/nimresolve".exe) & " tools/nimresolve.nim" + #nimexec "c -o:" & ("bin/nimresolve".exe) & " tools/nimresolve.nim" buildNimble(latest) diff --git a/todo.txt b/todo.txt index 509e225b6..7c2a9088d 100644 --- a/todo.txt +++ b/todo.txt @@ -1,8 +1,7 @@ version 1.0 battle plan ======================= -- make nimresolve part of the Nim compiler and add support for - 'import staticExec()' +- make FlowVar compatible to Futures - remove 'mod x' type rule - implement x[^1] differently, no compiler magic - fix "high priority" bugs diff --git a/tools/nimresolve.nim b/tools/nimresolve.nim deleted file mode 100644 index a7a7a33bd..000000000 --- a/tools/nimresolve.nim +++ /dev/null @@ -1,160 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2017 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Standard tool that resolves import paths. - -import - os, strutils, parseopt - -import "../compiler/nimblecmd" - -# You can change these constants to build you own adapted resolver. -const - considerParentDirs = not defined(noParentProjects) - considerNimbleDirs = not defined(noNimbleDirs) - -const - Version = "1.0" - Usage = "nimresolve - Nim Resolve Package Path Version " & Version & """ - - (c) 2017 Andreas Rumpf -Usage: - nimresolve [options] package -Options: - --source:FILE the file that requests to resolve 'package' - --stdlib:PATH the path to use for the standard library - --project:FILE the main '.nim' file that was passed to the Nim compiler - --subdir:EXPR the subdir part in: 'import $pkg / subdir' - --noNimblePath do not search the Nimble path to resolve the package -""" - -proc writeHelp() = - stdout.write(Usage) - stdout.flushFile() - quit(0) - -proc writeVersion() = - stdout.write(Version & "\n") - stdout.flushFile() - quit(0) - -type - Task = object - source, stdlib, subdir, project, pkg: string - noNimblePath: bool - -proc findInNimbleDir(t: Task; dir: string): bool = - var best = "" - var bestv = "" - for k, p in os.walkDir(dir, relative=true): - if k == pcDir and p.len > t.pkg.len+1 and - p[t.pkg.len] == '-' and p.startsWith(t.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(t.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 t.subdir.len == 0: t.pkg else: t.subdir - let res = addFileExt(best / f, "nim") - if best.len > 0 and fileExists(res): - echo res - result = true - -const stdlibDirs = [ - "pure", "core", "arch", - "pure/collections", - "pure/concurrency", "impure", - "wrappers", "wrappers/linenoise", - "windows", "posix", "js"] - -proc resolve(t: Task) = - template attempt(a) = - let x = addFileExt(a, "nim") - if fileExists(x): - echo x - return - - case t.pkg - of "stdlib": - if t.subdir.len == 0: - echo t.stdlib - return - else: - for candidate in stdlibDirs: - attempt(t.stdlib / candidate / t.subdir) - of "root": - let root = t.project.splitFile.dir - if t.subdir.len == 0: - echo root - return - else: - attempt(root / t.subdir) - else: - when considerParentDirs: - var p = parentDir(t.source.splitFile.dir) - # support 'import $karax': - let f = if t.subdir.len == 0: t.pkg else: t.subdir - - while p.len > 0: - let dir = p / t.pkg - if dirExists(dir): - attempt(dir / f) - # 2nd attempt: try to use 'karax/karax' - attempt(dir / t.pkg / f) - # 3rd attempt: try to use 'karax/src/karax' - attempt(dir / "src" / f) - attempt(dir / "src" / t.pkg / f) - p = parentDir(p) - - when considerNimbleDirs: - if not t.noNimblePath: - var nimbleDir = getEnv("NIMBLE_DIR") - if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" - if findInNimbleDir(t, nimbleDir / "pkgs"): return - when not defined(windows): - if findInNimbleDir(t, "/opt/nimble/pkgs"): return - - quit "cannot resolve: " & (t.pkg / t.subdir) - -proc main = - var t: Task - t.subdir = "" - for kind, key, val in getopt(): - case kind - of cmdArgument: - t.pkg = key - of cmdLongoption, cmdShortOption: - case normalize(key) - of "source": t.source = val - of "stdlib": t.stdlib = val - of "project": t.project = val - of "subdir": t.subdir = val - of "nonimblepath": t.noNimblePath = true - of "help", "h": writeHelp() - of "version", "v": writeVersion() - else: writeHelp() - of cmdEnd: assert(false) # cannot happen - if t.pkg.len == 0: - quit "[Error] no package to resolve." - resolve(t) - -main() -- cgit 1.4.1-2-gfad0 From eee43e4f8febf3186186d96d59b3aa72502bf466 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 5 Nov 2017 16:33:26 +0100 Subject: fixes the new to be documented imports --- compiler/modulepaths.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'compiler/modulepaths.nim') diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index d7b5f147d..5d112c6b9 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -98,6 +98,7 @@ proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): strin proc scriptableImport(pkg, sub: string; info: TLineInfo): string = result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) + if result.isNil: result = "" proc lookupPackage(pkg, subdir: PNode): string = let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: "" @@ -166,7 +167,8 @@ proc checkModuleName*(n: PNode; doLocalError=true): int32 = let fullPath = findModule(modulename, n.info.toFullPath) if fullPath.len == 0: if doLocalError: - localError(n.info, errCannotOpenFile, modulename) + let m = if modulename.len > 0: modulename else: $n + localError(n.info, errCannotOpenFile, m) result = InvalidFileIDX else: - result = fullPath.fileInfoIdx \ No newline at end of file + result = fullPath.fileInfoIdx -- cgit 1.4.1-2-gfad0