compiler refactoring; use typesafe path handing; docgen: render symbols between modules
This commit is contained in:
parent
b5730ec01f
commit
86556ebfdb
45 changed files with 816 additions and 504 deletions
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import
|
||||
os, strutils, strtabs, osproc, sets, lineinfos, platform,
|
||||
prefixmatches
|
||||
prefixmatches, pathutils
|
||||
|
||||
from terminal import isatty
|
||||
from times import utc, fromUnix, local, getTime, format, DateTime
|
||||
|
|
@ -135,7 +135,7 @@ type
|
|||
External ## file was introduced via .compile pragma
|
||||
|
||||
Cfile* = object
|
||||
cname*, obj*: string
|
||||
cname*, obj*: AbsoluteFile
|
||||
flags*: set[CFileFlag]
|
||||
CfileList* = seq[Cfile]
|
||||
|
||||
|
|
@ -203,13 +203,14 @@ type
|
|||
## symbols are always guaranteed to be style
|
||||
## insensitive. Otherwise hell would break lose.
|
||||
packageCache*: StringTableRef
|
||||
searchPaths*: seq[string]
|
||||
lazyPaths*: seq[string]
|
||||
outFile*, prefixDir*, libpath*, nimcacheDir*: string
|
||||
searchPaths*: seq[AbsoluteDir]
|
||||
lazyPaths*: seq[AbsoluteDir]
|
||||
outFile*: AbsoluteFile
|
||||
prefixDir*, libpath*, nimcacheDir*: AbsoluteDir
|
||||
dllOverrides, moduleOverrides*: StringTableRef
|
||||
projectName*: string # holds a name like 'nim'
|
||||
projectPath*: string # holds a path like /home/alice/projects/nim/compiler/
|
||||
projectFull*: string # projectPath/projectName
|
||||
projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/
|
||||
projectFull*: AbsoluteFile # projectPath/projectName
|
||||
projectIsStdin*: bool # whether we're compiling from stdin
|
||||
projectMainIdx*: FileIndex # the canonical path id of the main module
|
||||
command*: string # the main command (e.g. cc, check, scan, etc)
|
||||
|
|
@ -221,9 +222,9 @@ type
|
|||
# The string uses the formatting variables `path` and `line`.
|
||||
|
||||
# the used compiler
|
||||
cIncludes*: seq[string] # directories to search for included files
|
||||
cLibs*: seq[string] # directories to search for lib files
|
||||
cLinkedLibs*: seq[string] # libraries to link
|
||||
cIncludes*: seq[AbsoluteDir] # directories to search for included files
|
||||
cLibs*: seq[AbsoluteDir] # directories to search for lib files
|
||||
cLinkedLibs*: seq[string] # libraries to link
|
||||
|
||||
externalToLink*: seq[string] # files to link in addition to the file
|
||||
# we compiled (*)
|
||||
|
|
@ -302,12 +303,13 @@ proc newConfigRef*(): ConfigRef =
|
|||
packageCache: newPackageCache(),
|
||||
searchPaths: @[],
|
||||
lazyPaths: @[],
|
||||
outFile: "", prefixDir: "", libpath: "", nimcacheDir: "",
|
||||
outFile: AbsoluteFile"", prefixDir: AbsoluteDir"",
|
||||
libpath: AbsoluteDir"", nimcacheDir: AbsoluteDir"",
|
||||
dllOverrides: newStringTable(modeCaseInsensitive),
|
||||
moduleOverrides: newStringTable(modeStyleInsensitive),
|
||||
projectName: "", # holds a name like 'nim'
|
||||
projectPath: "", # holds a path like /home/alice/projects/nim/compiler/
|
||||
projectFull: "", # projectPath/projectName
|
||||
projectPath: AbsoluteDir"", # holds a path like /home/alice/projects/nim/compiler/
|
||||
projectFull: AbsoluteFile"", # projectPath/projectName
|
||||
projectIsStdin: false, # whether we're compiling from stdin
|
||||
projectMainIdx: FileIndex(0'i32), # the canonical path id of the main module
|
||||
command: "", # the main command (e.g. cc, check, scan, etc)
|
||||
|
|
@ -401,7 +403,7 @@ template optPreserveOrigSource*(conf: ConfigRef): untyped =
|
|||
optEmbedOrigSrc in conf.globalOptions
|
||||
|
||||
const
|
||||
genSubDir* = "nimcache"
|
||||
genSubDir* = RelativeDir"nimcache"
|
||||
NimExt* = "nim"
|
||||
RodExt* = "rod"
|
||||
HtmlExt* = "html"
|
||||
|
|
@ -409,10 +411,10 @@ const
|
|||
TagsExt* = "tags"
|
||||
TexExt* = "tex"
|
||||
IniExt* = "ini"
|
||||
DefaultConfig* = "nim.cfg"
|
||||
DefaultConfigNims* = "config.nims"
|
||||
DocConfig* = "nimdoc.cfg"
|
||||
DocTexConfig* = "nimdoc.tex.cfg"
|
||||
DefaultConfig* = RelativeFile"nim.cfg"
|
||||
DefaultConfigNims* = RelativeFile"config.nims"
|
||||
DocConfig* = RelativeFile"nimdoc.cfg"
|
||||
DocTexConfig* = RelativeFile"nimdoc.tex.cfg"
|
||||
|
||||
const oKeepVariableNames* = true
|
||||
|
||||
|
|
@ -437,56 +439,61 @@ proc getConfigVar*(conf: ConfigRef; key: string, default = ""): string =
|
|||
proc setConfigVar*(conf: ConfigRef; key, val: string) =
|
||||
conf.configVars[key] = val
|
||||
|
||||
proc getOutFile*(conf: ConfigRef; filename, ext: string): string =
|
||||
if conf.outFile != "": result = conf.outFile
|
||||
else: result = changeFileExt(filename, ext)
|
||||
proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): AbsoluteFile =
|
||||
if not conf.outFile.isEmpty: result = conf.outFile
|
||||
else: result = conf.projectPath / changeFileExt(filename, ext)
|
||||
|
||||
proc getPrefixDir*(conf: ConfigRef): string =
|
||||
proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
|
||||
## Gets the prefix dir, usually the parent directory where the binary resides.
|
||||
##
|
||||
## This is overridden by some tools (namely nimsuggest) via the ``conf.prefixDir``
|
||||
## global.
|
||||
if conf.prefixDir != "": result = conf.prefixDir
|
||||
else: result = splitPath(getAppDir()).head
|
||||
## field.
|
||||
if not conf.prefixDir.isEmpty: result = conf.prefixDir
|
||||
else: result = AbsoluteDir splitPath(getAppDir()).head
|
||||
|
||||
proc setDefaultLibpath*(conf: ConfigRef) =
|
||||
# set default value (can be overwritten):
|
||||
if conf.libpath == "":
|
||||
if conf.libpath.isEmpty:
|
||||
# choose default libpath:
|
||||
var prefix = getPrefixDir(conf)
|
||||
when defined(posix):
|
||||
if prefix == "/usr": conf.libpath = "/usr/lib/nim"
|
||||
elif prefix == "/usr/local": conf.libpath = "/usr/local/lib/nim"
|
||||
else: conf.libpath = joinPath(prefix, "lib")
|
||||
else: conf.libpath = joinPath(prefix, "lib")
|
||||
if prefix == AbsoluteDir"/usr":
|
||||
conf.libpath = AbsoluteDir"/usr/lib/nim"
|
||||
elif prefix == AbsoluteDir"/usr/local":
|
||||
conf.libpath = AbsoluteDir"/usr/local/lib/nim"
|
||||
else:
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
else:
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
|
||||
# Special rule to support other tools (nimble) which import the compiler
|
||||
# modules and make use of them.
|
||||
let realNimPath = findExe("nim")
|
||||
# Find out if $nim/../../lib/system.nim exists.
|
||||
let parentNimLibPath = realNimPath.parentDir.parentDir / "lib"
|
||||
if not fileExists(conf.libpath / "system.nim") and
|
||||
if not fileExists(conf.libpath.string / "system.nim") and
|
||||
fileExists(parentNimlibPath / "system.nim"):
|
||||
conf.libpath = parentNimLibPath
|
||||
conf.libpath = AbsoluteDir parentNimLibPath
|
||||
|
||||
proc canonicalizePath*(conf: ConfigRef; path: string): string =
|
||||
proc canonicalizePath*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
# on Windows, 'expandFilename' calls getFullPathName which doesn't do
|
||||
# case corrections, so we have to use this convoluted way of retrieving
|
||||
# the true filename (see tests/modules and Nimble uses 'import Uri' instead
|
||||
# of 'import uri'):
|
||||
when defined(windows):
|
||||
result = path.expandFilename
|
||||
for x in walkFiles(result):
|
||||
return x
|
||||
result = AbsoluteFile path.string.expandFilename
|
||||
for x in walkFiles(result.string):
|
||||
return AbsoluteFile x
|
||||
else:
|
||||
result = path.expandFilename
|
||||
result = AbsoluteFile path.string.expandFilename
|
||||
|
||||
proc shortenDir*(conf: ConfigRef; dir: string): string =
|
||||
proc shortenDir*(conf: ConfigRef; dir: string): string {.
|
||||
deprecated: "use 'relativeTo' instead".} =
|
||||
## returns the interesting part of a dir
|
||||
var prefix = conf.projectPath & DirSep
|
||||
var prefix = conf.projectPath.string & DirSep
|
||||
if startsWith(dir, prefix):
|
||||
return substr(dir, len(prefix))
|
||||
prefix = getPrefixDir(conf) & DirSep
|
||||
prefix = getPrefixDir(conf).string & DirSep
|
||||
if startsWith(dir, prefix):
|
||||
return substr(dir, len(prefix))
|
||||
result = dir
|
||||
|
|
@ -509,87 +516,87 @@ proc getOsCacheDir(): string =
|
|||
else:
|
||||
result = getHomeDir() / genSubDir
|
||||
|
||||
proc getNimcacheDir*(conf: ConfigRef): string =
|
||||
proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir =
|
||||
# XXX projectName should always be without a file extension!
|
||||
result = if conf.nimcacheDir.len > 0:
|
||||
result = if not conf.nimcacheDir.isEmpty:
|
||||
conf.nimcacheDir
|
||||
elif conf.cmd == cmdCompileToJS:
|
||||
shortenDir(conf, conf.projectPath) / genSubDir
|
||||
else: getOsCacheDir() / splitFile(conf.projectName).name &
|
||||
(if isDefined(conf, "release"): "_r" else: "_d")
|
||||
conf.projectPath / genSubDir
|
||||
else:
|
||||
AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
|
||||
(if isDefined(conf, "release"): "_r" else: "_d"))
|
||||
|
||||
proc pathSubs*(conf: ConfigRef; p, config: string): string =
|
||||
let home = removeTrailingDirSep(os.getHomeDir())
|
||||
result = unixToNativePath(p % [
|
||||
"nim", getPrefixDir(conf),
|
||||
"lib", conf.libpath,
|
||||
"nim", getPrefixDir(conf).string,
|
||||
"lib", conf.libpath.string,
|
||||
"home", home,
|
||||
"config", config,
|
||||
"projectname", conf.projectName,
|
||||
"projectpath", conf.projectPath,
|
||||
"projectdir", conf.projectPath,
|
||||
"nimcache", getNimcacheDir(conf)])
|
||||
"projectpath", conf.projectPath.string,
|
||||
"projectdir", conf.projectPath.string,
|
||||
"nimcache", getNimcacheDir(conf).string])
|
||||
if "~/" in result:
|
||||
result = result.replace("~/", home & '/')
|
||||
|
||||
proc toGeneratedFile*(conf: ConfigRef; path, ext: string): string =
|
||||
proc toGeneratedFile*(conf: ConfigRef; path: AbsoluteFile,
|
||||
ext: string): AbsoluteFile =
|
||||
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
|
||||
var (head, tail) = splitPath(path)
|
||||
#if len(head) > 0: head = shortenDir(head & dirSep)
|
||||
result = joinPath([getNimcacheDir(conf), changeFileExt(tail, ext)])
|
||||
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result
|
||||
let (head, tail) = splitPath(path.string)
|
||||
result = getNimcacheDir(conf) / RelativeFile changeFileExt(tail, ext)
|
||||
|
||||
proc completeGeneratedFilePath*(conf: ConfigRef; f: string, createSubDir: bool = true): string =
|
||||
var (head, tail) = splitPath(f)
|
||||
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
|
||||
var subdir = getNimcacheDir(conf) # / head
|
||||
proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
|
||||
createSubDir: bool = true): AbsoluteFile =
|
||||
let (head, tail) = splitPath(f.string)
|
||||
let subdir = getNimcacheDir(conf)
|
||||
if createSubDir:
|
||||
try:
|
||||
createDir(subdir)
|
||||
createDir(subdir.string)
|
||||
except OSError:
|
||||
writeLine(stdout, "cannot create directory: " & subdir)
|
||||
writeLine(stdout, "cannot create directory: " & subdir.string)
|
||||
quit(1)
|
||||
result = joinPath(subdir, tail)
|
||||
result = subdir / RelativeFile tail
|
||||
#echo "completeGeneratedFilePath(", f, ") = ", result
|
||||
|
||||
proc rawFindFile(conf: ConfigRef; f: string; suppressStdlib: bool): string =
|
||||
proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile =
|
||||
for it in conf.searchPaths:
|
||||
if suppressStdlib and it.startsWith(conf.libpath):
|
||||
if suppressStdlib and it.string.startsWith(conf.libpath.string):
|
||||
continue
|
||||
result = joinPath(it, f)
|
||||
if existsFile(result):
|
||||
result = it / f
|
||||
if fileExists(result):
|
||||
return canonicalizePath(conf, result)
|
||||
result = ""
|
||||
result = AbsoluteFile""
|
||||
|
||||
proc rawFindFile2(conf: ConfigRef; f: string): string =
|
||||
proc rawFindFile2(conf: ConfigRef; f: RelativeFile): AbsoluteFile =
|
||||
for i, it in conf.lazyPaths:
|
||||
result = joinPath(it, f)
|
||||
if existsFile(result):
|
||||
result = it / f
|
||||
if fileExists(result):
|
||||
# bring to front
|
||||
for j in countDown(i,1):
|
||||
swap(conf.lazyPaths[j], conf.lazyPaths[j-1])
|
||||
|
||||
return canonicalizePath(conf, result)
|
||||
result = ""
|
||||
result = AbsoluteFile""
|
||||
|
||||
template patchModule(conf: ConfigRef) {.dirty.} =
|
||||
if result.len > 0 and conf.moduleOverrides.len > 0:
|
||||
let key = getPackageName(conf, result) & "_" & splitFile(result).name
|
||||
if not result.isEmpty and conf.moduleOverrides.len > 0:
|
||||
let key = getPackageName(conf, result.string) & "_" & splitFile(result).name
|
||||
if conf.moduleOverrides.hasKey(key):
|
||||
let ov = conf.moduleOverrides[key]
|
||||
if ov.len > 0: result = ov
|
||||
if ov.len > 0: result = AbsoluteFile(ov)
|
||||
|
||||
proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): string {.procvar.} =
|
||||
proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile {.procvar.} =
|
||||
if f.isAbsolute:
|
||||
result = if f.existsFile: f else: ""
|
||||
result = if f.existsFile: AbsoluteFile(f) else: AbsoluteFile""
|
||||
else:
|
||||
result = rawFindFile(conf, f, suppressStdlib)
|
||||
if result.len == 0:
|
||||
result = rawFindFile(conf, f.toLowerAscii, suppressStdlib)
|
||||
if result.len == 0:
|
||||
result = rawFindFile2(conf, f)
|
||||
if result.len == 0:
|
||||
result = rawFindFile2(conf, f.toLowerAscii)
|
||||
result = rawFindFile(conf, RelativeFile f, suppressStdlib)
|
||||
if result.isEmpty:
|
||||
result = rawFindFile(conf, RelativeFile f.toLowerAscii, suppressStdlib)
|
||||
if result.isEmpty:
|
||||
result = rawFindFile2(conf, RelativeFile f)
|
||||
if result.isEmpty:
|
||||
result = rawFindFile2(conf, RelativeFile f.toLowerAscii)
|
||||
patchModule(conf)
|
||||
|
||||
const stdlibDirs = [
|
||||
|
|
@ -599,7 +606,7 @@ const stdlibDirs = [
|
|||
"wrappers", "wrappers/linenoise",
|
||||
"windows", "posix", "js"]
|
||||
|
||||
proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
|
||||
proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFile =
|
||||
# returns path to module
|
||||
const pkgPrefix = "pkg/"
|
||||
const stdPrefix = "std/"
|
||||
|
|
@ -610,13 +617,13 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
|
|||
if m.startsWith(stdPrefix):
|
||||
let stripped = m.substr(stdPrefix.len)
|
||||
for candidate in stdlibDirs:
|
||||
let path = (conf.libpath / candidate / stripped)
|
||||
let path = (conf.libpath.string / candidate / stripped)
|
||||
if fileExists(path):
|
||||
m = path
|
||||
break
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = currentPath / m
|
||||
if not existsFile(result):
|
||||
result = AbsoluteFile currentPath / m
|
||||
if not fileExists(result):
|
||||
result = findFile(conf, m)
|
||||
patchModule(conf)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue