mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
compiler refactoring; use typesafe path handing; docgen: render symbols between modules
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils,
|
||||
intsets, platform, llstream, tables, sighashes
|
||||
intsets, platform, llstream, tables, sighashes, pathutils
|
||||
|
||||
# Careful! Section marks need to contain a tabulator so that they cannot
|
||||
# be part of C string literals.
|
||||
@@ -226,7 +226,7 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||
when not defined(nimhygiene):
|
||||
{.pragma: inject.}
|
||||
|
||||
template withCFile(cfilename: string, body: untyped) =
|
||||
template withCFile(cfilename: AbsoluteFile, body: untyped) =
|
||||
var s = llStreamOpen(cfilename, fmRead)
|
||||
if s == nil: return
|
||||
var L {.inject.}: TBaseLexer
|
||||
@@ -238,7 +238,7 @@ template withCFile(cfilename: string, body: untyped) =
|
||||
body
|
||||
closeBaseLexer(L)
|
||||
|
||||
proc readMergeInfo*(cfilename: string, m: BModule) =
|
||||
proc readMergeInfo*(cfilename: AbsoluteFile, m: BModule) =
|
||||
## reads the merge meta information into `m`.
|
||||
withCFile(cfilename):
|
||||
readKey(L, k)
|
||||
@@ -251,7 +251,7 @@ type
|
||||
f: TCFileSections
|
||||
p: TCProcSections
|
||||
|
||||
proc readMergeSections(cfilename: string, m: var TMergeSections) =
|
||||
proc readMergeSections(cfilename: AbsoluteFile, m: var TMergeSections) =
|
||||
## reads the merge sections into `m`.
|
||||
withCFile(cfilename):
|
||||
readKey(L, k)
|
||||
@@ -285,7 +285,7 @@ proc mergeRequired*(m: BModule): bool =
|
||||
#echo "not empty: ", i, " ", m.initProc.s[i]
|
||||
return true
|
||||
|
||||
proc mergeFiles*(cfilename: string, m: BModule) =
|
||||
proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) =
|
||||
## merges the C file with the old version on hard disc.
|
||||
var old: TMergeSections
|
||||
readMergeSections(cfilename, old)
|
||||
|
||||
@@ -14,7 +14,7 @@ import
|
||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
|
||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
||||
lowerings, semparallel, tables, sets, ndi, lineinfos
|
||||
lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils
|
||||
|
||||
import strutils except `%` # collides with ropes.`%`
|
||||
|
||||
@@ -1064,7 +1064,8 @@ proc genFilenames(m: BModule): Rope =
|
||||
discard cgsym(m, "dbgRegisterFilename")
|
||||
result = nil
|
||||
for i in 0..<m.config.m.fileInfos.len:
|
||||
result.addf("dbgRegisterFilename($1);$N", [m.config.m.fileInfos[i].projPath.makeCString])
|
||||
result.addf("dbgRegisterFilename($1);$N",
|
||||
[m.config.m.fileInfos[i].projPath.string.makeCString])
|
||||
|
||||
proc genMainProc(m: BModule) =
|
||||
const
|
||||
@@ -1348,7 +1349,7 @@ proc initProcOptions(m: BModule): TOptions =
|
||||
let opts = m.config.options
|
||||
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
|
||||
|
||||
proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||
proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule =
|
||||
new(result)
|
||||
result.g = g
|
||||
result.tmpBase = rope("TM" & $hashOwner(module) & "_")
|
||||
@@ -1376,7 +1377,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||
incl result.flags, preventStackTrace
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
|
||||
else: ""
|
||||
else: AbsoluteFile""
|
||||
open(result.ndi, ndiName, g.config)
|
||||
|
||||
proc nullify[T](arr: var T) =
|
||||
@@ -1427,7 +1428,7 @@ proc resetCgenModules*(g: BModuleList) =
|
||||
for m in cgenModules(g): resetModule(m)
|
||||
|
||||
proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
|
||||
result = rawNewModule(g, module, toFullPath(conf, module.position.FileIndex))
|
||||
result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
|
||||
|
||||
proc newModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
|
||||
# we should create only one cgen module for each module sym
|
||||
@@ -1446,7 +1447,7 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
|
||||
injectG()
|
||||
result = newModule(g, module, graph.config)
|
||||
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
|
||||
let f = if graph.config.headerFile.len > 0: graph.config.headerFile
|
||||
let f = if graph.config.headerFile.len > 0: AbsoluteFile graph.config.headerFile
|
||||
else: graph.config.projectFull
|
||||
g.generatedHeader = rawNewModule(g, module,
|
||||
changeFileExt(completeCFilePath(graph.config, f), hExt))
|
||||
@@ -1477,9 +1478,9 @@ proc writeHeader(m: BModule) =
|
||||
if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
|
||||
result.addf("#endif /* $1 */$n", [guard])
|
||||
if not writeRope(result, m.filename):
|
||||
rawMessage(m.config, errCannotOpenFile, m.filename)
|
||||
rawMessage(m.config, errCannotOpenFile, m.filename.string)
|
||||
|
||||
proc getCFile(m: BModule): string =
|
||||
proc getCFile(m: BModule): AbsoluteFile =
|
||||
let ext =
|
||||
if m.compileToCpp: ".cpp"
|
||||
elif m.config.cmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
|
||||
@@ -1523,18 +1524,18 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
|
||||
if not equalsFile(code, cfile.cname):
|
||||
if isDefined(m.config, "nimdiff"):
|
||||
if fileExists(cfile.cname):
|
||||
copyFile(cfile.cname, cfile.cname & ".backup")
|
||||
echo "diff ", cfile.cname, ".backup ", cfile.cname
|
||||
copyFile(cfile.cname.string, cfile.cname.string & ".backup")
|
||||
echo "diff ", cfile.cname.string, ".backup ", cfile.cname.string
|
||||
else:
|
||||
echo "new file ", cfile.cname
|
||||
echo "new file ", cfile.cname.string
|
||||
if not writeRope(code, cfile.cname):
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.cname)
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.cname.string)
|
||||
return
|
||||
if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname):
|
||||
if fileExists(cfile.obj) and os.fileNewer(cfile.obj.string, cfile.cname.string):
|
||||
result = false
|
||||
else:
|
||||
if not writeRope(code, cfile.cname):
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.cname)
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.cname.string)
|
||||
|
||||
# We need 2 different logics here: pending modules (including
|
||||
# 'nim__dat') may require file merging for the combination of dead code
|
||||
@@ -1570,14 +1571,14 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
finishTypeDescriptions(m)
|
||||
var code = genModule(m, cf)
|
||||
if not writeRope(code, cfile):
|
||||
rawMessage(m.config, errCannotOpenFile, cfile)
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.string)
|
||||
addFileToCompile(m.config, cf)
|
||||
else:
|
||||
# Consider: first compilation compiles ``system.nim`` and produces
|
||||
# ``system.c`` but then compilation fails due to an error. This means
|
||||
# that ``system.o`` is missing, so we need to call the C compiler for it:
|
||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
|
||||
if not fileExists(cf.obj): cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
close(m.ndi)
|
||||
|
||||
@@ -1592,7 +1593,7 @@ proc updateCachedModule(m: BModule) =
|
||||
|
||||
var code = genModule(m, cf)
|
||||
if not writeRope(code, cfile):
|
||||
rawMessage(m.config, errCannotOpenFile, cfile)
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.string)
|
||||
else:
|
||||
cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, passes, options, intsets, platform, sighashes,
|
||||
tables, ndi, lineinfos
|
||||
tables, ndi, lineinfos, pathutils
|
||||
|
||||
from modulegraphs import ModuleGraph
|
||||
|
||||
@@ -136,8 +136,8 @@ type
|
||||
s*: TCFileSections # sections of the C file
|
||||
flags*: set[Codegenflag]
|
||||
module*: PSym
|
||||
filename*: string
|
||||
cfilename*: string # filename of the module (including path,
|
||||
filename*: AbsoluteFile
|
||||
cfilename*: AbsoluteFile # filename of the module (including path,
|
||||
# without extension)
|
||||
tmpBase*: Rope # base for temp identifier generation
|
||||
typeCache*: TypeCache # cache the generated types
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2018 Nim contributors
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix
|
||||
|
||||
# TODO: nimfix should use this; currently out of sync
|
||||
|
||||
import
|
||||
compiler/[options, idents, nimconf, scriptconfig, extccomp, commands, msgs, lineinfos, modulegraphs, condsyms],
|
||||
std/os
|
||||
options, idents, nimconf, scriptconfig, extccomp, commands, msgs,
|
||||
lineinfos, modulegraphs, condsyms, os, pathutils
|
||||
|
||||
type
|
||||
NimProg* = ref object
|
||||
@@ -21,27 +28,27 @@ proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
|
||||
self.processCmdLine(passCmd1, "", conf)
|
||||
if self.supportsStdinFile and conf.projectName == "-":
|
||||
conf.projectName = "stdinfile"
|
||||
conf.projectFull = "stdinfile"
|
||||
conf.projectPath = canonicalizePath(conf, getCurrentDir())
|
||||
conf.projectFull = AbsoluteFile "stdinfile"
|
||||
conf.projectPath = AbsoluteDir getCurrentDir()
|
||||
conf.projectIsStdin = true
|
||||
elif conf.projectName != "":
|
||||
try:
|
||||
conf.projectFull = canonicalizePath(conf, conf.projectName)
|
||||
conf.projectFull = canonicalizePath(conf, AbsoluteFile conf.projectName)
|
||||
except OSError:
|
||||
conf.projectFull = conf.projectName
|
||||
conf.projectFull = AbsoluteFile conf.projectName
|
||||
let p = splitFile(conf.projectFull)
|
||||
let dir = if p.dir.len > 0: p.dir else: getCurrentDir()
|
||||
conf.projectPath = canonicalizePath(conf, dir)
|
||||
let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir
|
||||
conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir)
|
||||
conf.projectName = p.name
|
||||
else:
|
||||
conf.projectPath = canonicalizePath(conf, getCurrentDir())
|
||||
conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile getCurrentDir())
|
||||
|
||||
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool =
|
||||
loadConfigs(DefaultConfig, cache, conf) # load all config files
|
||||
if self.suggestMode:
|
||||
conf.command = "nimsuggest"
|
||||
|
||||
proc runNimScriptIfExists(path: string)=
|
||||
proc runNimScriptIfExists(path: AbsoluteFile)=
|
||||
if fileExists(path):
|
||||
runNimScript(cache, path, freshDefines = false, conf)
|
||||
|
||||
@@ -53,8 +60,8 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi
|
||||
runNimScriptIfExists(getUserConfigPath(DefaultConfigNims))
|
||||
|
||||
if optSkipParentConfigFiles notin conf.globalOptions:
|
||||
for dir in parentDirs(conf.projectPath, fromRoot = true, inclusive = false):
|
||||
runNimScriptIfExists(dir / DefaultConfigNims)
|
||||
for dir in parentDirs(conf.projectPath.string, fromRoot = true, inclusive = false):
|
||||
runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims)
|
||||
|
||||
if optSkipProjConfigFile notin conf.globalOptions:
|
||||
runNimScriptIfExists(conf.projectPath / DefaultConfigNims)
|
||||
@@ -63,10 +70,10 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi
|
||||
if not self.suggestMode:
|
||||
runNimScriptIfExists(scriptFile)
|
||||
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
||||
if fileExists(scriptFile) and scriptFile.cmpPaths(conf.projectFull) == 0:
|
||||
if fileExists(scriptFile) and scriptFile == conf.projectFull:
|
||||
return false
|
||||
else:
|
||||
if scriptFile.cmpPaths(conf.projectFull) != 0:
|
||||
if scriptFile != conf.projectFull:
|
||||
runNimScriptIfExists(scriptFile)
|
||||
else:
|
||||
# 'nimsuggest foo.nims' means to just auto-complete the NimScript file
|
||||
|
||||
@@ -26,7 +26,8 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
|
||||
wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, lineinfos
|
||||
wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, lineinfos,
|
||||
pathutils
|
||||
|
||||
# but some have deps to imported modules. Yay.
|
||||
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
|
||||
@@ -208,7 +209,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
|
||||
proc processCompile(conf: ConfigRef; filename: string) =
|
||||
var found = findFile(conf, filename)
|
||||
if found == "": found = filename
|
||||
if found.isEmpty: found = AbsoluteFile filename
|
||||
extccomp.addExternalFileToCompile(conf, found)
|
||||
|
||||
const
|
||||
@@ -292,31 +293,32 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
|
||||
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
|
||||
notRelativeToProj = false): string =
|
||||
notRelativeToProj = false): AbsoluteDir =
|
||||
let p = if os.isAbsolute(path) or '$' in path:
|
||||
path
|
||||
elif notRelativeToProj:
|
||||
getCurrentDir() / path
|
||||
else:
|
||||
conf.projectPath / path
|
||||
conf.projectPath.string / path
|
||||
try:
|
||||
result = pathSubs(conf, p, toFullPath(conf, info).splitFile().dir)
|
||||
result = AbsoluteDir pathSubs(conf, p, toFullPath(conf, info).splitFile().dir)
|
||||
except ValueError:
|
||||
localError(conf, info, "invalid path: " & p)
|
||||
result = p
|
||||
result = AbsoluteDir p
|
||||
|
||||
proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string =
|
||||
let path = if path[0] == '"': strutils.unescape(path) else: path
|
||||
proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): AbsoluteDir =
|
||||
let path = if path.len > 0 and path[0] == '"': strutils.unescape(path)
|
||||
else: path
|
||||
let basedir = toFullPath(conf, info).splitFile().dir
|
||||
let p = if os.isAbsolute(path) or '$' in path:
|
||||
path
|
||||
else:
|
||||
basedir / path
|
||||
try:
|
||||
result = pathSubs(conf, p, basedir)
|
||||
result = AbsoluteDir pathSubs(conf, p, basedir)
|
||||
except ValueError:
|
||||
localError(conf, info, "invalid path: " & p)
|
||||
result = p
|
||||
result = AbsoluteDir p
|
||||
|
||||
const
|
||||
errInvalidNumber = "$1 is not a valid number"
|
||||
@@ -331,9 +333,9 @@ proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
|
||||
if parseUtils.parseInt(a[3], column) <= 0:
|
||||
localError(conf, info, errInvalidNumber % a[2])
|
||||
|
||||
let dirtyOriginalIdx = fileInfoIdx(conf, a[1])
|
||||
let dirtyOriginalIdx = fileInfoIdx(conf, AbsoluteFile a[1])
|
||||
if dirtyOriginalIdx.int32 >= 0:
|
||||
msgs.setDirtyFile(conf, dirtyOriginalIdx, a[0])
|
||||
msgs.setDirtyFile(conf, dirtyOriginalIdx, AbsoluteFile a[0])
|
||||
|
||||
conf.m.trackPos = newLineInfo(dirtyOriginalIdx, line, column)
|
||||
|
||||
@@ -345,7 +347,7 @@ proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
|
||||
localError(conf, info, errInvalidNumber % a[1])
|
||||
if parseUtils.parseInt(a[2], column) <= 0:
|
||||
localError(conf, info, errInvalidNumber % a[2])
|
||||
conf.m.trackPos = newLineInfo(conf, a[0], line, column)
|
||||
conf.m.trackPos = newLineInfo(conf, AbsoluteFile a[0], line, column)
|
||||
|
||||
proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if pass in {passCmd2, passPP}:
|
||||
@@ -359,14 +361,16 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
case switch.normalize
|
||||
of "path", "p":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
addPath(conf, if pass == passPP: processCfgPath(conf, arg, info) else: processPath(conf, arg, info), info)
|
||||
addPath(conf, if pass == passPP: processCfgPath(conf, arg, info)
|
||||
else: processPath(conf, arg, info), info)
|
||||
of "nimblepath", "babelpath":
|
||||
# keep the old name for compat
|
||||
if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
var path = processPath(conf, arg, info, notRelativeToProj=true)
|
||||
let nimbleDir = getEnv("NIMBLE_DIR")
|
||||
if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs"
|
||||
let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR")
|
||||
if not nimbleDir.isEmpty and pass == passPP:
|
||||
path = nimbleDir / RelativeDir"pkgs"
|
||||
nimblePath(conf, path, info)
|
||||
of "nonimblepath", "nobabelpath":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
@@ -374,20 +378,14 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "excludepath":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
let path = processPath(conf, arg, info)
|
||||
|
||||
conf.searchPaths.keepItIf(cmpPaths(it, path) != 0)
|
||||
conf.lazyPaths.keepItIf(cmpPaths(it, path) != 0)
|
||||
|
||||
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
|
||||
let strippedPath = path[0 .. (len(path) - 2)]
|
||||
conf.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
|
||||
conf.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
|
||||
conf.searchPaths.keepItIf(it != path)
|
||||
conf.lazyPaths.keepItIf(it != path)
|
||||
of "nimcache":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.nimcacheDir = processPath(conf, arg, info, true)
|
||||
of "out", "o":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.outFile = arg
|
||||
conf.outFile = AbsoluteFile arg
|
||||
of "docseesrcurl":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.docSeeSrcUrl = arg
|
||||
@@ -411,7 +409,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
if pass in {passCmd2, passPP}: processCompile(conf, arg)
|
||||
of "link":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: addExternalFileToLink(conf, arg)
|
||||
if pass in {passCmd2, passPP}:
|
||||
addExternalFileToLink(conf, AbsoluteFile arg)
|
||||
of "debuginfo":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
incl(conf.globalOptions, optCDebug)
|
||||
@@ -581,7 +580,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
if pass in {passCmd2, passPP}: conf.cLibs.add processPath(conf, arg, info)
|
||||
of "clib":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: conf.cLinkedLibs.add processPath(conf, arg, info)
|
||||
if pass in {passCmd2, passPP}:
|
||||
conf.cLinkedLibs.add processPath(conf, arg, info).string
|
||||
of "header":
|
||||
if conf != nil: conf.headerFile = arg
|
||||
incl(conf.globalOptions, optGenIndex)
|
||||
@@ -742,7 +742,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||
|
||||
template gCmdLineInfo*(): untyped = newLineInfo(config, "command line", 1, 1)
|
||||
template gCmdLineInfo*(): untyped = newLineInfo(config, AbsoluteFile"command line", 1, 1)
|
||||
|
||||
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
|
||||
var cmd, arg: string
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
# This module implements a dependency file generator.
|
||||
|
||||
import
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, modulepaths
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, modulepaths,
|
||||
pathutils
|
||||
|
||||
from modulegraphs import ModuleGraph
|
||||
|
||||
@@ -45,10 +46,10 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
else:
|
||||
discard
|
||||
|
||||
proc generateDot*(graph: ModuleGraph; project: string) =
|
||||
proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
|
||||
let b = Backend(graph.backend)
|
||||
discard writeRope("digraph $1 {$n$2}$n" % [
|
||||
rope(changeFileExt(extractFilename(project), "")), b.dotGraph],
|
||||
rope(project.splitFile.name), b.dotGraph],
|
||||
changeFileExt(project, "dot"))
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
|
||||
|
||||
@@ -16,7 +16,8 @@ import
|
||||
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
|
||||
packages/docutils/rst, packages/docutils/rstgen,
|
||||
packages/docutils/highlite, sempass2, json, xmltree, cgi,
|
||||
typesrenderer, astalgo, modulepaths, lineinfos, sequtils, intsets
|
||||
typesrenderer, astalgo, modulepaths, lineinfos, sequtils, intsets,
|
||||
pathutils
|
||||
|
||||
type
|
||||
TSections = array[TSymKind, Rope]
|
||||
@@ -34,6 +35,8 @@ type
|
||||
exampleCounter: int
|
||||
emitted: IntSet # we need to track which symbols have been emitted
|
||||
# already. See bug #3655
|
||||
destFile*: AbsoluteFile
|
||||
thisDir*: AbsoluteDir
|
||||
|
||||
PDoc* = ref TDocumentor ## Alias to type less.
|
||||
|
||||
@@ -48,12 +51,12 @@ proc whichType(d: PDoc; n: PNode): PSym =
|
||||
|
||||
proc attachToType(d: PDoc; p: PSym): PSym =
|
||||
let params = p.ast.sons[paramsPos]
|
||||
# first check the first parameter, then the return type,
|
||||
# then the other parameter:
|
||||
template check(i) =
|
||||
result = whichType(d, params[i])
|
||||
if result != nil: return result
|
||||
|
||||
# first check the first parameter, then the return type,
|
||||
# then the other parameter:
|
||||
if params.len > 1: check(1)
|
||||
if params.len > 0: check(0)
|
||||
for i in 2..<params.len: check(i)
|
||||
@@ -74,10 +77,10 @@ template declareClosures =
|
||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||
of mwUnsupportedField: k = warnFieldXNotSupported
|
||||
globalError(conf, newLineInfo(conf, filename, line, col), k, arg)
|
||||
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
|
||||
|
||||
proc docgenFindFile(s: string): string {.procvar.} =
|
||||
result = options.findFile(conf, s)
|
||||
result = options.findFile(conf, s).string
|
||||
if result.len == 0:
|
||||
result = getCurrentDir() / s
|
||||
if not existsFile(result): result = ""
|
||||
@@ -90,13 +93,24 @@ proc parseRst(text, filename: string,
|
||||
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
proc newDocumentor*(filename: string; cache: IdentCache; conf: ConfigRef): PDoc =
|
||||
proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
|
||||
ext: string, dir: RelativeDir): AbsoluteFile =
|
||||
if optWholeProject in conf.globalOptions:
|
||||
# This is correct, for 'nim doc --project' we interpret the '--out' option as an
|
||||
# absolute directory, not as a filename!
|
||||
let d = if conf.outFile.isEmpty: conf.projectPath / dir else: AbsoluteDir(conf.outFile)
|
||||
createDir(d)
|
||||
result = d / changeFileExt(filename, ext)
|
||||
else:
|
||||
result = getOutFile(conf, filename, ext)
|
||||
|
||||
proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef): PDoc =
|
||||
declareClosures()
|
||||
new(result)
|
||||
result.conf = conf
|
||||
result.cache = cache
|
||||
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
|
||||
conf.configVars, filename, {roSupportRawDirective},
|
||||
conf.configVars, filename.string, {roSupportRawDirective},
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
if conf.configVars.hasKey("doc.googleAnalytics"):
|
||||
@@ -120,8 +134,12 @@ proc newDocumentor*(filename: string; cache: IdentCache; conf: ConfigRef): PDoc
|
||||
result.jArray = newJArray()
|
||||
initStrTable result.types
|
||||
result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) =
|
||||
localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
|
||||
localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1),
|
||||
warnUser, "only 'rst2html' supports the ':test:' attribute")
|
||||
result.emitted = initIntSet()
|
||||
result.destFile = getOutFile2(conf, relativeTo(filename, conf.projectPath),
|
||||
HtmlExt, RelativeDir"htmldocs")
|
||||
result.thisDir = result.destFile.splitFile.dir
|
||||
|
||||
proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||
if conf.cmd != cmdRst2tex: addf(dest, xml, args)
|
||||
@@ -227,6 +245,10 @@ proc getPlainDocstring(n: PNode): string =
|
||||
result = getPlainDocstring(n.sons[i])
|
||||
if result.len > 0: return
|
||||
|
||||
proc belongsToPackage(conf: ConfigRef; module: PSym): bool =
|
||||
result = module.kind == skModule and module.owner != nil and
|
||||
module.owner.id == conf.mainPackageId
|
||||
|
||||
proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRenderFlags = {}) =
|
||||
var r: TSrcGen
|
||||
var literal = ""
|
||||
@@ -259,8 +281,22 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
|
||||
dispA(d.conf, result, "<span class=\"FloatNumber\">$1</span>",
|
||||
"\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
|
||||
of tkSymbol:
|
||||
dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
|
||||
let s = getTokSym(r)
|
||||
if s != nil and s.kind == skType and sfExported in s.flags and
|
||||
s.owner != nil and belongsToPackage(d.conf, s.owner) and
|
||||
d.target == outHtml:
|
||||
|
||||
let full = AbsoluteFile toFullPath(d.conf, FileIndex s.owner.position)
|
||||
let tmp = getOutFile2(d.conf, full.relativeTo(d.conf.projectPath),
|
||||
HtmlExt, RelativeDir"htmldocs")
|
||||
|
||||
let external = tmp.relativeTo(d.thisDir, '/')
|
||||
result.addf "<a href=\"$1#$2\"><span class=\"Identifier\">$3</span></a>",
|
||||
[rope changeFileExt(external, "html").string, rope literal,
|
||||
rope(esc(d.target, literal))]
|
||||
else:
|
||||
dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
|
||||
of tkSpaces, tkInvalid:
|
||||
add(result, literal)
|
||||
of tkCurlyDotLe:
|
||||
@@ -290,23 +326,24 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
|
||||
|
||||
proc testExample(d: PDoc; ex: PNode) =
|
||||
if d.conf.errorCounter > 0: return
|
||||
let outputDir = d.conf.getNimcacheDir / "runnableExamples"
|
||||
let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples"
|
||||
createDir(outputDir)
|
||||
inc d.exampleCounter
|
||||
let outp = outputDir / extractFilename(d.filename.changeFileExt"" &
|
||||
"_examples" & $d.exampleCounter & ".nim")
|
||||
let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" &
|
||||
"_examples" & $d.exampleCounter & ".nim"))
|
||||
#let nimcache = outp.changeFileExt"" & "_nimcache"
|
||||
renderModule(ex, d.filename, outp, conf = d.conf)
|
||||
renderModule(ex, d.filename, outp.string, conf = d.conf)
|
||||
let backend = if isDefined(d.conf, "js"): "js"
|
||||
elif isDefined(d.conf, "cpp"): "cpp"
|
||||
elif isDefined(d.conf, "objc"): "objc"
|
||||
else: "c"
|
||||
if os.execShellCmd(os.getAppFilename() & " " & backend &
|
||||
" --nimcache:" & outputDir & " -r " & outp) != 0:
|
||||
quit "[Examples] failed: see " & outp
|
||||
" --nimcache:" & quoteShell(outputDir) &
|
||||
" -r " & quoteShell(outp)) != 0:
|
||||
quit "[Examples] failed: see " & outp.string
|
||||
else:
|
||||
# keep generated source file `outp` to allow inspection.
|
||||
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp])
|
||||
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
|
||||
removeFile(outp.changeFileExt(ExeExt))
|
||||
|
||||
proc extractImports(n: PNode; result: PNode) =
|
||||
@@ -449,10 +486,8 @@ proc newUniquePlainSymbol(d: PDoc, original: string): string =
|
||||
result = original
|
||||
d.seenSymbols[original] = ""
|
||||
return
|
||||
|
||||
# Iterate over possible numeric variants of the original name.
|
||||
var count = 2
|
||||
|
||||
while true:
|
||||
result = original & "_" & $count
|
||||
if not d.seenSymbols.hasKey(result):
|
||||
@@ -460,7 +495,6 @@ proc newUniquePlainSymbol(d: PDoc, original: string): string =
|
||||
break
|
||||
count += 1
|
||||
|
||||
|
||||
proc complexName(k: TSymKind, n: PNode, baseName: string): string =
|
||||
## Builds a complex unique href name for the node.
|
||||
##
|
||||
@@ -482,11 +516,9 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
|
||||
of skTemplate: result.add(".t" & defaultParamSeparator)
|
||||
of skConverter: result.add(".c" & defaultParamSeparator)
|
||||
else: discard
|
||||
|
||||
if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams:
|
||||
result.add(renderParamTypes(n[paramsPos]))
|
||||
|
||||
|
||||
proc isCallable(n: PNode): bool =
|
||||
## Returns true if `n` contains a callable node.
|
||||
case n.kind
|
||||
@@ -495,7 +527,6 @@ proc isCallable(n: PNode): bool =
|
||||
else:
|
||||
result = false
|
||||
|
||||
|
||||
proc docstringSummary(rstText: string): string =
|
||||
## Returns just the first line or a brief chunk of text from a rst string.
|
||||
##
|
||||
@@ -523,7 +554,6 @@ proc docstringSummary(rstText: string): string =
|
||||
result.delete(pos, last)
|
||||
result.add("…")
|
||||
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
if not isVisible(d, nameNode): return
|
||||
let
|
||||
@@ -545,8 +575,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
break
|
||||
plainName.add(literal)
|
||||
|
||||
# Render the HTML hyperlink.
|
||||
nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments, renderDocComments})
|
||||
nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments,
|
||||
renderDocComments, renderSyms})
|
||||
|
||||
inc(d.id)
|
||||
let
|
||||
@@ -563,16 +593,18 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
var seeSrcRope: Rope = nil
|
||||
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
|
||||
if docItemSeeSrc.len > 0:
|
||||
let cwd = canonicalizePath(d.conf, getCurrentDir())
|
||||
var path = toFullPath(d.conf, n.info)
|
||||
if path.startsWith(cwd):
|
||||
path = path[cwd.len+1 .. ^1].replace('\\', '/')
|
||||
let path = relativeTo(AbsoluteFile toFullPath(d.conf, n.info), d.conf.projectPath, '/')
|
||||
when false:
|
||||
let cwd = canonicalizePath(d.conf, getCurrentDir())
|
||||
var path = toFullPath(d.conf, n.info)
|
||||
if path.startsWith(cwd):
|
||||
path = path[cwd.len+1 .. ^1].replace('\\', '/')
|
||||
let gitUrl = getConfigVar(d.conf, "git.url")
|
||||
if gitUrl.len > 0:
|
||||
let commit = getConfigVar(d.conf, "git.commit", "master")
|
||||
let develBranch = getConfigVar(d.conf, "git.devel", "devel")
|
||||
dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
|
||||
["path", "line", "url", "commit", "devel"], [rope path,
|
||||
["path", "line", "url", "commit", "devel"], [rope path.string,
|
||||
rope($n.info.line), rope gitUrl, rope commit, rope develBranch])])
|
||||
|
||||
add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
|
||||
@@ -611,9 +643,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||
name = getName(d, nameNode)
|
||||
comm = $genRecComment(d, n)
|
||||
r: TSrcGen
|
||||
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
|
||||
result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||
"col": %n.info.col}
|
||||
if comm.len > 0:
|
||||
@@ -626,7 +656,6 @@ proc checkForFalse(n: PNode): bool =
|
||||
|
||||
proc traceDeps(d: PDoc, it: PNode) =
|
||||
const k = skModule
|
||||
|
||||
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
|
||||
let sep = it[0]
|
||||
let dir = it[1]
|
||||
@@ -637,11 +666,16 @@ proc traceDeps(d: PDoc, it: PNode) =
|
||||
for x in it[2]:
|
||||
a.sons[2] = x
|
||||
traceDeps(d, a)
|
||||
else:
|
||||
elif it.kind == nkSym and belongsToPackage(d.conf, it.sym):
|
||||
let full = AbsoluteFile toFullPath(d.conf, FileIndex it.sym.position)
|
||||
let tmp = getOutFile2(d.conf, full.relativeTo(d.conf.projectPath), HtmlExt,
|
||||
RelativeDir"htmldocs")
|
||||
let external = relativeTo(tmp, d.thisDir, '/')
|
||||
if d.section[k] != nil: add(d.section[k], ", ")
|
||||
dispA(d.conf, d.section[k],
|
||||
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
|
||||
"$1", [rope(splitFile(getModuleName(d.conf, it)).name)])
|
||||
"<a class=\"reference external\" href=\"$2\">$1</a>",
|
||||
"$1", [rope esc(d.target, it.sym.name.s),
|
||||
rope changeFileExt(external, "html").string])
|
||||
|
||||
proc generateDoc*(d: PDoc, n: PNode) =
|
||||
case n.kind
|
||||
@@ -829,29 +863,23 @@ proc genOutFile(d: PDoc): Rope =
|
||||
|
||||
proc generateIndex*(d: PDoc) =
|
||||
if optGenIndex in d.conf.globalOptions:
|
||||
writeIndexFile(d[], splitFile(d.conf.outFile).dir /
|
||||
splitFile(d.filename).name & IndexExt)
|
||||
let dest = getOutFile2(d.conf, relativeTo(AbsoluteFile d.filename, d.conf.projectPath),
|
||||
IndexExt, RelativeDir"index")
|
||||
writeIndexFile(d[], dest.string)
|
||||
|
||||
proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
|
||||
if optWholeProject in conf.globalOptions:
|
||||
let d = if conf.outFile != "": conf.outFile else: dir
|
||||
createDir(d)
|
||||
result = d / changeFileExt(filename, ext)
|
||||
else:
|
||||
result = getOutFile(conf, filename, ext)
|
||||
|
||||
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
proc writeOutput*(d: PDoc, useWarning = false) =
|
||||
var content = genOutFile(d)
|
||||
if optStdout in d.conf.globalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
let outfile = getOutFile2(d.conf, filename, outExt, "htmldocs")
|
||||
createDir(outfile.parentDir)
|
||||
template outfile: untyped = d.destFile
|
||||
#let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt, "htmldocs")
|
||||
createDir(outfile.splitFile.dir)
|
||||
if not writeRope(content, outfile):
|
||||
rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, outfile)
|
||||
rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile,
|
||||
outfile.string)
|
||||
|
||||
proc writeOutputJson*(d: PDoc, filename, outExt: string,
|
||||
useWarning = false) =
|
||||
proc writeOutputJson*(d: PDoc, useWarning = false) =
|
||||
let content = %*{"orig": d.filename,
|
||||
"nimble": getPackageName(d.conf, d.filename),
|
||||
"entries": d.jArray}
|
||||
@@ -859,8 +887,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string,
|
||||
write(stdout, $content)
|
||||
else:
|
||||
var f: File
|
||||
if open(f, getOutFile2(d.conf, splitFile(filename).name,
|
||||
outExt, "jsondocs"), fmWrite):
|
||||
if open(f, d.destFile.string, fmWrite):
|
||||
write(f, $content)
|
||||
close(f)
|
||||
else:
|
||||
@@ -872,26 +899,27 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
|
||||
var d = newDocumentor(conf.projectFull, cache, conf)
|
||||
d.hasToc = true
|
||||
generateDoc(d, ast)
|
||||
writeOutput(d, conf.projectFull, HtmlExt)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
|
||||
proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string) =
|
||||
proc commandRstAux(cache: IdentCache, conf: ConfigRef;
|
||||
filename: AbsoluteFile, outExt: string) =
|
||||
var filen = addFileExt(filename, "txt")
|
||||
var d = newDocumentor(filen, cache, conf)
|
||||
d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string;
|
||||
status: int; content: string) =
|
||||
var outp: string
|
||||
var outp: AbsoluteFile
|
||||
if filename.len == 0:
|
||||
inc(d.id)
|
||||
let nameOnly = splitFile(d.filename).name
|
||||
let subdir = getNimcacheDir(conf) / nameOnly
|
||||
let subdir = getNimcacheDir(conf) / RelativeDir(nameOnly)
|
||||
createDir(subdir)
|
||||
outp = subdir / (nameOnly & "_snippet_" & $d.id & ".nim")
|
||||
outp = subdir / RelativeFile(nameOnly & "_snippet_" & $d.id & ".nim")
|
||||
elif isAbsolute(filename):
|
||||
outp = filename
|
||||
outp = AbsoluteFile filename
|
||||
else:
|
||||
# Nim's convention: every path is relative to the file it was written in:
|
||||
outp = splitFile(d.filename).dir / filename
|
||||
outp = splitFile(d.filename).dir.AbsoluteDir / RelativeFile(filename)
|
||||
writeFile(outp, content)
|
||||
let cmd = cmd % quoteShell(outp)
|
||||
rawMessage(conf, hintExecuting, cmd)
|
||||
@@ -899,14 +927,12 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string)
|
||||
rawMessage(conf, errGenerated, "executing of external program failed: " & cmd)
|
||||
|
||||
d.isPureRst = true
|
||||
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
|
||||
var rst = parseRst(readFile(filen.string), filen.string, 0, 1, d.hasToc,
|
||||
{roSupportRawDirective}, conf)
|
||||
var modDesc = newStringOfCap(30_000)
|
||||
#d.modDesc = newMutableRope(30_000)
|
||||
renderRstToOut(d[], rst, modDesc)
|
||||
#freezeMutableRope(d.modDesc)
|
||||
d.modDesc = rope(modDesc)
|
||||
writeOutput(d, filename, outExt)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
|
||||
proc commandRst2Html*(cache: IdentCache, conf: ConfigRef) =
|
||||
@@ -928,9 +954,9 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
#echo getOutFile(gProjectFull, JsonExt)
|
||||
let filename = getOutFile(conf, conf.projectFull, JsonExt)
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
|
||||
if not writeRope(content, filename):
|
||||
rawMessage(conf, errCannotOpenFile, filename)
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
var ast = parseFile(conf.projectMainIdx, cache, conf)
|
||||
@@ -945,12 +971,12 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
#echo getOutFile(gProjectFull, TagsExt)
|
||||
let filename = getOutFile(conf, conf.projectFull, TagsExt)
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
|
||||
if not writeRope(content, filename):
|
||||
rawMessage(conf, errCannotOpenFile, filename)
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) =
|
||||
var content = mergeIndexes(conf.projectFull).rope
|
||||
var content = mergeIndexes(conf.projectFull.string).rope
|
||||
|
||||
let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
@@ -958,6 +984,6 @@ proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) =
|
||||
["Index".rope, nil, nil, rope(getDateStr()),
|
||||
rope(getClockStr()), content, nil, nil, nil])
|
||||
# no analytics because context is not available
|
||||
let filename = getOutFile(conf, "theindex", HtmlExt)
|
||||
let filename = getOutFile(conf, RelativeFile"theindex", HtmlExt)
|
||||
if not writeRope(code, filename):
|
||||
rawMessage(conf, errCannotOpenFile, filename)
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
# semantic checking.
|
||||
|
||||
import
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen, lineinfos
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen, lineinfos,
|
||||
pathutils
|
||||
|
||||
from modulegraphs import ModuleGraph
|
||||
|
||||
@@ -38,11 +39,11 @@ template closeImpl(body: untyped) {.dirty.} =
|
||||
|
||||
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
closeImpl:
|
||||
writeOutput(g.doc, toFullPath(graph.config, FileIndex g.module.position), HtmlExt, useWarning)
|
||||
writeOutput(g.doc, useWarning)
|
||||
|
||||
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
closeImpl:
|
||||
writeOutputJson(g.doc, toFullPath(graph.config, FileIndex g.module.position), ".json", useWarning)
|
||||
writeOutputJson(g.doc, useWarning)
|
||||
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -60,7 +61,8 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
|
||||
var g: PGen
|
||||
new(g)
|
||||
g.module = module
|
||||
var d = newDocumentor(toFullPath(graph.config, FileIndex module.position), graph.cache, graph.config)
|
||||
var d = newDocumentor(AbsoluteFile toFullPath(graph.config, FileIndex module.position),
|
||||
graph.cache, graph.config)
|
||||
d.hasToc = true
|
||||
g.doc = d
|
||||
result = g
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import
|
||||
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||
lineinfos, std / sha1, streams
|
||||
lineinfos, std / sha1, streams, pathutils
|
||||
|
||||
type
|
||||
TInfoCCProp* = enum # properties of the C compiler:
|
||||
@@ -429,12 +429,13 @@ proc initVars*(conf: ConfigRef) =
|
||||
if len(conf.ccompilerpath) == 0:
|
||||
conf.ccompilerpath = getConfigVar(conf, conf.cCompiler, ".path")
|
||||
|
||||
proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string =
|
||||
proc completeCFilePath*(conf: ConfigRef; cfile: AbsoluteFile,
|
||||
createSubDir: bool = true): AbsoluteFile =
|
||||
result = completeGeneratedFilePath(conf, cfile, createSubDir)
|
||||
|
||||
proc toObjFile*(conf: ConfigRef; filename: string): string =
|
||||
proc toObjFile*(conf: ConfigRef; filename: AbsoluteFile): AbsoluteFile =
|
||||
# Object file for compilation
|
||||
result = filename & "." & CC[conf.cCompiler].objExt
|
||||
result = AbsoluteFile(filename.string & "." & CC[conf.cCompiler].objExt)
|
||||
|
||||
proc addFileToCompile*(conf: ConfigRef; cf: Cfile) =
|
||||
conf.toCompile.add(cf)
|
||||
@@ -447,8 +448,8 @@ proc resetCompilationLists*(conf: ConfigRef) =
|
||||
# Maybe we can do that in checkDep on the other hand?
|
||||
conf.externalToLink.setLen 0
|
||||
|
||||
proc addExternalFileToLink*(conf: ConfigRef; filename: string) =
|
||||
conf.externalToLink.insert(filename, 0)
|
||||
proc addExternalFileToLink*(conf: ConfigRef; filename: AbsoluteFile) =
|
||||
conf.externalToLink.insert(filename.string, 0)
|
||||
|
||||
proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int =
|
||||
rawMessage(conf, msg, cmd)
|
||||
@@ -459,14 +460,15 @@ proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) =
|
||||
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||
cmd)
|
||||
|
||||
proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) =
|
||||
let (dir, name, ext) = splitFile(projectFile)
|
||||
let filename = getNimcacheDir(conf) / addFileExt("compile_" & name,
|
||||
platform.OS[conf.target.targetOS].scriptExt)
|
||||
proc generateScript(conf: ConfigRef; projectFile: AbsoluteFile, script: Rope) =
|
||||
let (_, name, _) = splitFile(projectFile)
|
||||
let filename = getNimcacheDir(conf) / RelativeFile(addFileExt("compile_" & name,
|
||||
platform.OS[conf.target.targetOS].scriptExt))
|
||||
if writeRope(script, filename):
|
||||
copyFile(conf.libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h")
|
||||
copyFile(conf.libpath / RelativeFile"nimbase.h",
|
||||
getNimcacheDir(conf) / RelativeFile"nimbase.h")
|
||||
else:
|
||||
rawMessage(conf, errGenerated, "could not write to file: " & filename)
|
||||
rawMessage(conf, errGenerated, "could not write to file: " & filename.string)
|
||||
|
||||
proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string =
|
||||
result = getConfigVar(conf, c, ".options.speed")
|
||||
@@ -490,7 +492,7 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
|
||||
# `optGenMapping` is included here for niminst.
|
||||
result = conf.globalOptions * {optGenScript, optGenMapping} != {}
|
||||
|
||||
proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
|
||||
proc cFileSpecificOptions(conf: ConfigRef; cfilename: AbsoluteFile): string =
|
||||
result = conf.compileOptions
|
||||
for option in conf.compileOptionsCmd:
|
||||
if strutils.find(result, option, 0) < 0:
|
||||
@@ -513,7 +515,7 @@ proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
|
||||
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||
|
||||
proc getCompileOptions(conf: ConfigRef): string =
|
||||
result = cFileSpecificOptions(conf, "__dummy__")
|
||||
result = cFileSpecificOptions(conf, AbsoluteFile"__dummy__")
|
||||
|
||||
proc getLinkOptions(conf: ConfigRef): string =
|
||||
result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
|
||||
@@ -526,8 +528,8 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} =
|
||||
result = (optGenScript in conf.globalOptions and conf.target.targetOS == osWindows) or
|
||||
(conf.target.hostOS == osWindows)
|
||||
|
||||
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string =
|
||||
result = if conf.cmd == cmdCompileToCpp and not cfile.endsWith(".c"):
|
||||
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string =
|
||||
result = if conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c"):
|
||||
CC[compiler].cppCompiler
|
||||
else:
|
||||
CC[compiler].compilerExe
|
||||
@@ -539,7 +541,7 @@ proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string
|
||||
proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
|
||||
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
||||
elif optMixedMode in conf.globalOptions and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler
|
||||
else: getCompilerExe(conf, compiler, "")
|
||||
else: getCompilerExe(conf, compiler, AbsoluteFile"")
|
||||
|
||||
proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
|
||||
var c = conf.cCompiler
|
||||
@@ -565,43 +567,42 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
|
||||
includeCmd = ""
|
||||
compilePattern = getCompilerExe(conf, c, cfile.cname)
|
||||
|
||||
var cf = if noAbsolutePaths(conf): extractFilename(cfile.cname)
|
||||
var cf = if noAbsolutePaths(conf): AbsoluteFile extractFilename(cfile.cname.string)
|
||||
else: cfile.cname
|
||||
|
||||
var objfile =
|
||||
if cfile.obj.len == 0:
|
||||
if cfile.obj.isEmpty:
|
||||
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf):
|
||||
toObjFile(conf, cf)
|
||||
toObjFile(conf, cf).string
|
||||
else:
|
||||
completeCFilePath(conf, toObjFile(conf, cf))
|
||||
completeCFilePath(conf, toObjFile(conf, cf)).string
|
||||
elif noAbsolutePaths(conf):
|
||||
extractFilename(cfile.obj)
|
||||
extractFilename(cfile.obj.string)
|
||||
else:
|
||||
cfile.obj
|
||||
cfile.obj.string
|
||||
|
||||
# D files are required by nintendo switch libs for
|
||||
# compilation. They are basically a list of all includes.
|
||||
let dfile = objfile.changeFileExt(".d").quoteShell()
|
||||
|
||||
objfile = quoteShell(objfile)
|
||||
cf = quoteShell(cf)
|
||||
let cfsh = quoteShell(cf)
|
||||
result = quoteShell(compilePattern % [
|
||||
"dfile", dfile,
|
||||
"file", cf, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nim", getPrefixDir(conf),
|
||||
"nim", getPrefixDir(conf), "lib", conf.libpath])
|
||||
"file", cfsh, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nim", getPrefixDir(conf).string,
|
||||
"lib", conf.libpath.string])
|
||||
add(result, ' ')
|
||||
addf(result, CC[c].compileTmpl, [
|
||||
"dfile", dfile,
|
||||
"file", cf, "objfile", objfile,
|
||||
"file", cfsh, "objfile", objfile,
|
||||
"options", options, "include", includeCmd,
|
||||
"nim", quoteShell(getPrefixDir(conf)),
|
||||
"nim", quoteShell(getPrefixDir(conf)),
|
||||
"lib", quoteShell(conf.libpath)])
|
||||
|
||||
proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
|
||||
result = secureHash(
|
||||
$secureHashFile(cfile.cname) &
|
||||
$secureHashFile(cfile.cname.string) &
|
||||
platform.OS[conf.target.targetOS].name &
|
||||
platform.CPU[conf.target.targetCPU].name &
|
||||
extccomp.CC[conf.cCompiler].name &
|
||||
@@ -614,14 +615,14 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
|
||||
var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
|
||||
var currentHash = footprint(conf, cfile)
|
||||
var f: File
|
||||
if open(f, hashFile, fmRead):
|
||||
if open(f, hashFile.string, fmRead):
|
||||
let oldHash = parseSecureHash(f.readLine())
|
||||
close(f)
|
||||
result = oldHash != currentHash
|
||||
else:
|
||||
result = true
|
||||
if result:
|
||||
if open(f, hashFile, fmWrite):
|
||||
if open(f, hashFile.string, fmWrite):
|
||||
f.writeLine($currentHash)
|
||||
close(f)
|
||||
|
||||
@@ -630,7 +631,7 @@ proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
|
||||
c.flags.incl CfileFlag.Cached
|
||||
conf.toCompile.add(c)
|
||||
|
||||
proc addExternalFileToCompile*(conf: ConfigRef; filename: string) =
|
||||
proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) =
|
||||
var c = Cfile(cname: filename,
|
||||
obj: toObjFile(conf, completeCFilePath(conf, filename, false)),
|
||||
flags: {CfileFlag.External})
|
||||
@@ -650,11 +651,11 @@ proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var
|
||||
add(script, compileCmd)
|
||||
add(script, "\n")
|
||||
|
||||
proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||
proc getLinkCmd(conf: ConfigRef; projectfile: AbsoluteFile, objfiles: string): string =
|
||||
if optGenStaticLib in conf.globalOptions:
|
||||
var libname: string
|
||||
if conf.outFile.len > 0:
|
||||
libname = conf.outFile.expandTilde
|
||||
if not conf.outFile.isEmpty:
|
||||
libname = conf.outFile.string.expandTilde
|
||||
if not libname.isAbsolute():
|
||||
libname = getCurrentDir() / libname
|
||||
else:
|
||||
@@ -679,13 +680,13 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||
else:
|
||||
exefile = splitFile(projectfile).name & platform.OS[conf.target.targetOS].exeExt
|
||||
builddll = ""
|
||||
if conf.outFile.len > 0:
|
||||
exefile = conf.outFile.expandTilde
|
||||
if not conf.outFile.isEmpty:
|
||||
exefile = conf.outFile.string.expandTilde
|
||||
if not exefile.isAbsolute():
|
||||
exefile = getCurrentDir() / exefile
|
||||
if not noAbsolutePaths(conf):
|
||||
if not exefile.isAbsolute():
|
||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||
exefile = string(splitFile(projectfile).dir / RelativeFile(exefile))
|
||||
when false:
|
||||
if optCDebug in conf.globalOptions:
|
||||
writeDebugInfo(exefile.changeFileExt("ndb"))
|
||||
@@ -693,7 +694,7 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||
|
||||
# Map files are required by Nintendo Switch compilation. They are a list
|
||||
# of all function calls in the library and where they come from.
|
||||
let mapfile = quoteShell(getNimcacheDir(conf) / splitFile(projectFile).name & ".map")
|
||||
let mapfile = quoteShell(getNimcacheDir(conf) / RelativeFile(splitFile(projectFile).name & ".map"))
|
||||
|
||||
let linkOptions = getLinkOptions(conf) & " " &
|
||||
getConfigVar(conf, conf.cCompiler, ".options.linker")
|
||||
@@ -703,7 +704,7 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||
result = quoteShell(result % ["builddll", builddll,
|
||||
"mapfile", mapfile,
|
||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||
"exefile", exefile, "nim", getPrefixDir(conf), "lib", conf.libpath])
|
||||
"exefile", exefile, "nim", getPrefixDir(conf).string, "lib", conf.libpath.string])
|
||||
result.add ' '
|
||||
addf(result, linkTmpl, ["builddll", builddll,
|
||||
"mapfile", mapfile,
|
||||
@@ -761,7 +762,7 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx:
|
||||
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||
cmds.join())
|
||||
|
||||
proc callCCompiler*(conf: ConfigRef; projectfile: string) =
|
||||
proc callCCompiler*(conf: ConfigRef; projectfile: AbsoluteFile) =
|
||||
var
|
||||
linkCmd: string
|
||||
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||
@@ -787,7 +788,7 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) =
|
||||
add(objfiles, quoteShell(
|
||||
addFileExt(objFile, CC[conf.cCompiler].objExt)))
|
||||
for x in conf.toCompile:
|
||||
let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj
|
||||
let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj.string
|
||||
add(objfiles, ' ')
|
||||
add(objfiles, quoteShell(objFile))
|
||||
|
||||
@@ -804,7 +805,7 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) =
|
||||
#from json import escapeJson
|
||||
import json
|
||||
|
||||
proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
|
||||
template lit(x: untyped) = f.write x
|
||||
template str(x: untyped) =
|
||||
when compiles(escapeJson(x, buf)):
|
||||
@@ -821,7 +822,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
let compileCmd = getCompileCFileCmd(conf, it)
|
||||
if pastStart: lit "],\L"
|
||||
lit "["
|
||||
str it.cname
|
||||
str it.cname.string
|
||||
lit ", "
|
||||
str compileCmd
|
||||
pastStart = true
|
||||
@@ -851,11 +852,10 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
|
||||
var buf = newStringOfCap(50)
|
||||
|
||||
let file = projectfile.splitFile.name
|
||||
let jsonFile = toGeneratedFile(conf, file, "json")
|
||||
let jsonFile = toGeneratedFile(conf, projectfile, "json")
|
||||
|
||||
var f: File
|
||||
if open(f, jsonFile, fmWrite):
|
||||
if open(f, jsonFile.string, fmWrite):
|
||||
lit "{\"compile\":[\L"
|
||||
cfiles(conf, f, buf, conf.toCompile, false)
|
||||
lit "],\L\"link\":[\L"
|
||||
@@ -868,11 +868,10 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
lit "\L}\L"
|
||||
close(f)
|
||||
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
let file = projectfile.splitFile.name
|
||||
let jsonFile = toGeneratedFile(conf, file, "json")
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
|
||||
let jsonFile = toGeneratedFile(conf, projectfile, "json")
|
||||
try:
|
||||
let data = json.parseFile(jsonFile)
|
||||
let data = json.parseFile(jsonFile.string)
|
||||
let toCompile = data["compile"]
|
||||
doAssert toCompile.kind == JArray
|
||||
var cmds: TStringSeq = @[]
|
||||
@@ -896,11 +895,11 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
except:
|
||||
when declared(echo):
|
||||
echo getCurrentException().getStackTrace()
|
||||
quit "error evaluating JSON file: " & jsonFile
|
||||
quit "error evaluating JSON file: " & jsonFile.string
|
||||
|
||||
proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
|
||||
for it in list:
|
||||
addf(result, "--file:r\"$1\"$N", [rope(it.cname)])
|
||||
addf(result, "--file:r\"$1\"$N", [rope(it.cname.string)])
|
||||
|
||||
proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
|
||||
if optGenMapping notin conf.globalOptions: return
|
||||
@@ -914,9 +913,9 @@ proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
|
||||
getConfigVar(conf, conf.cCompiler, ".options.linker")))
|
||||
|
||||
add(code, "\n[Environment]\nlibpath=")
|
||||
add(code, strutils.escape(conf.libpath))
|
||||
add(code, strutils.escape(conf.libpath.string))
|
||||
|
||||
addf(code, "\n[Symbols]$n$1", [symbolMapping])
|
||||
let filename = joinPath(conf.projectPath, "mapping.txt")
|
||||
let filename = conf.projectPath / RelativeFile"mapping.txt"
|
||||
if not writeRope(code, filename):
|
||||
rawMessage(conf, errGenerated, "could not write to file: " & filename)
|
||||
rawMessage(conf, errGenerated, "could not write to file: " & filename.string)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
renderer, filters, lineinfos
|
||||
renderer, filters, lineinfos, pathutils
|
||||
|
||||
type
|
||||
TParseState = enum
|
||||
@@ -199,7 +199,8 @@ proc parseLine(p: var TTmplParser) =
|
||||
inc(j)
|
||||
llStreamWrite(p.outp, "\\n\"")
|
||||
|
||||
proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode; conf: ConfigRef): PLLStream =
|
||||
proc filterTmpl*(stdin: PLLStream, filename: AbsoluteFile,
|
||||
call: PNode; conf: ConfigRef): PLLStream =
|
||||
var p: TTmplParser
|
||||
p.config = conf
|
||||
p.info = newLineInfo(conf, filename, 0, 0)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
renderer
|
||||
renderer, pathutils
|
||||
|
||||
proc invalidPragma(conf: ConfigRef; n: PNode) =
|
||||
localError(conf, n.info,
|
||||
@@ -47,7 +47,7 @@ proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool):
|
||||
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
|
||||
else: invalidPragma(conf, n)
|
||||
|
||||
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
|
||||
var pattern = strArg(conf, call, "startswith", 1, "")
|
||||
var leading = boolArg(conf, call, "leading", 2, true)
|
||||
var trailing = boolArg(conf, call, "trailing", 3, true)
|
||||
@@ -61,7 +61,7 @@ proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNo
|
||||
llStreamWriteln(result, line)
|
||||
llStreamClose(stdin)
|
||||
|
||||
proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
|
||||
var sub = strArg(conf, call, "sub", 1, "")
|
||||
if len(sub) == 0: invalidPragma(conf, call)
|
||||
var by = strArg(conf, call, "by", 2, "")
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Module that implements ``gorge`` for the compiler.
|
||||
|
||||
import msgs, std / sha1, os, osproc, streams, strutils, options,
|
||||
lineinfos
|
||||
lineinfos, pathutils
|
||||
|
||||
proc readOutput(p: Process): (string, int) =
|
||||
result[0] = ""
|
||||
@@ -26,7 +26,7 @@ proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (str
|
||||
let workingDir = parentDir(toFullPath(conf, info))
|
||||
if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
|
||||
let h = secureHash(cmd & "\t" & input & "\t" & cache)
|
||||
let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt")
|
||||
let filename = toGeneratedFile(conf, AbsoluteFile("gorge_" & $h), "txt").string
|
||||
var f: File
|
||||
if open(f, filename):
|
||||
result = (f.readAll, 0)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## This module contains a simple persistent id generator.
|
||||
|
||||
import idents, strutils, os, options
|
||||
import idents, strutils, os, options, pathutils
|
||||
|
||||
var gFrontEndId*: int
|
||||
|
||||
@@ -36,18 +36,18 @@ proc setId*(id: int) {.inline.} =
|
||||
proc idSynchronizationPoint*(idRange: int) =
|
||||
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
|
||||
|
||||
proc toGid(conf: ConfigRef; f: string): string =
|
||||
proc toGid(conf: ConfigRef; f: AbsoluteFile): string =
|
||||
# we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
|
||||
# will cause strange bugs if multiple projects are in the same folder, so
|
||||
# we simply use a project independent name:
|
||||
result = options.completeGeneratedFilePath(conf, "nim.gid")
|
||||
result = options.completeGeneratedFilePath(conf, AbsoluteFile"nim.gid").string
|
||||
|
||||
proc saveMaxIds*(conf: ConfigRef; project: string) =
|
||||
proc saveMaxIds*(conf: ConfigRef; project: AbsoluteFile) =
|
||||
var f = open(toGid(conf, project), fmWrite)
|
||||
f.writeLine($gFrontEndId)
|
||||
f.close()
|
||||
|
||||
proc loadMaxIds*(conf: ConfigRef; project: string) =
|
||||
proc loadMaxIds*(conf: ConfigRef; project: AbsoluteFile) =
|
||||
var f: File
|
||||
if open(f, toGid(conf, project), fmRead):
|
||||
var line = newStringOfCap(20)
|
||||
|
||||
@@ -7,15 +7,12 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements the symbol importing mechanism.
|
||||
## This module implements the symbol importing mechanism.
|
||||
|
||||
import
|
||||
intsets, strutils, os, ast, astalgo, msgs, options, idents, lookups,
|
||||
semdata, passes, renderer, modulepaths, sigmatch, lineinfos
|
||||
|
||||
proc evalImport*(c: PContext, n: PNode): PNode
|
||||
proc evalFrom*(c: PContext, n: PNode): PNode
|
||||
|
||||
proc readExceptSet*(c: PContext, n: PNode): IntSet =
|
||||
assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
|
||||
result = initIntSet()
|
||||
@@ -140,7 +137,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
|
||||
c.config.options)
|
||||
|
||||
proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
|
||||
var f = checkModuleName(c.config, n)
|
||||
let f = checkModuleName(c.config, n)
|
||||
if f != InvalidFileIDX:
|
||||
let L = c.graph.importStack.len
|
||||
let recursion = c.graph.importStack.find(f)
|
||||
@@ -168,7 +165,8 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
|
||||
else:
|
||||
message(c.config, n.info, warnDeprecated, result.name.s)
|
||||
suggestSym(c.config, n.info, result, c.graph.usageSym, false)
|
||||
importStmtResult.add newStrNode(toFullPath(c.config, f), n.info)
|
||||
importStmtResult.add newSymNode(result, n.info)
|
||||
#newStrNode(toFullPath(c.config, f), n.info)
|
||||
|
||||
proc transformImportAs(c: PContext; n: PNode): PNode =
|
||||
if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as":
|
||||
@@ -188,7 +186,7 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
|
||||
importAllSymbolsExcept(c, m, emptySet)
|
||||
#importForwarded(c, m.ast, emptySet)
|
||||
|
||||
proc evalImport(c: PContext, n: PNode): PNode =
|
||||
proc evalImport*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkImportStmt, n.info)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let it = n.sons[i]
|
||||
@@ -212,7 +210,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
impMod(c, it, result)
|
||||
|
||||
proc evalFrom(c: PContext, n: PNode): PNode =
|
||||
proc evalFrom*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkImportStmt, n.info)
|
||||
checkMinSonsLen(n, 2, c.config)
|
||||
n.sons[0] = transformImportAs(c, n.sons[0])
|
||||
|
||||
@@ -32,7 +32,7 @@ import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer,
|
||||
intsets, cgmeth, lowerings, sighashes, lineinfos, rodutils
|
||||
intsets, cgmeth, lowerings, sighashes, lineinfos, rodutils, pathutils
|
||||
|
||||
from modulegraphs import ModuleGraph
|
||||
|
||||
@@ -2265,7 +2265,7 @@ proc genClass(conf: ConfigRef; obj: PType; content: Rope; ext: string) =
|
||||
"class $#$# {$n$#$n}$n") %
|
||||
[rope(VersionAsString), cls, extends, content]
|
||||
|
||||
let outfile = changeFileExt(completeCFilePath(conf, $cls), ext)
|
||||
let outfile = changeFileExt(completeCFilePath(conf, AbsoluteFile $cls), ext)
|
||||
discard writeRopeIfNotEqual(result, outfile)
|
||||
|
||||
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
@@ -2279,11 +2279,11 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
else: "nimsystem"
|
||||
let code = wholeCode(graph, m)
|
||||
let outfile =
|
||||
if m.config.outFile.len > 0:
|
||||
if m.config.outFile.isAbsolute: m.config.outFile
|
||||
else: getCurrentDir() / m.config.outFile
|
||||
if not m.config.outFile.isEmpty:
|
||||
if m.config.outFile.string.isAbsolute: m.config.outFile
|
||||
else: AbsoluteFile(getCurrentDir() / m.config.outFile.string)
|
||||
else:
|
||||
changeFileExt(completeCFilePath(m.config, f), ext)
|
||||
changeFileExt(completeCFilePath(m.config, AbsoluteFile f), ext)
|
||||
discard writeRopeIfNotEqual(genHeader() & code, outfile)
|
||||
for obj, content in items(globals.classes):
|
||||
genClass(m.config, obj, content, ext)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
import
|
||||
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
|
||||
wordrecg, lineinfos
|
||||
wordrecg, lineinfos, pathutils
|
||||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
@@ -232,7 +232,7 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
|
||||
lex.previousToken.fileIndex = fileIdx
|
||||
lex.config = config
|
||||
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream;
|
||||
proc openLexer*(lex: var TLexer, filename: AbsoluteFile, inputstream: PLLStream;
|
||||
cache: IdentCache; config: ConfigRef) =
|
||||
openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module contains the ``TMsgKind`` enum as well as the
|
||||
## ``TLineInfo`` object.
|
||||
|
||||
import ropes, tables
|
||||
import ropes, tables, pathutils
|
||||
|
||||
const
|
||||
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
|
||||
@@ -179,8 +179,8 @@ const
|
||||
|
||||
type
|
||||
TFileInfo* = object
|
||||
fullPath*: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
fullPath*: AbsoluteFile # This is a canonical full filesystem path
|
||||
projPath*: RelativeFile # This is relative to the project's root
|
||||
shortName*: string # short name of the module
|
||||
quotedName*: Rope # cached quoted short name for codegen
|
||||
# purposes
|
||||
@@ -191,7 +191,7 @@ type
|
||||
# used for better error messages and
|
||||
# embedding the original source in the
|
||||
# generated code
|
||||
dirtyfile*: string # the file that is actually read into memory
|
||||
dirtyfile*: AbsoluteFile # the file that is actually read into memory
|
||||
# and parsed; usually "" but is used
|
||||
# for 'nimsuggest'
|
||||
hash*: string # the checksum of the file
|
||||
|
||||
@@ -14,7 +14,7 @@ import
|
||||
strutils, os, intsets, strtabs
|
||||
|
||||
import options, ast, astalgo, msgs, semdata, ropes, idents,
|
||||
lineinfos
|
||||
lineinfos, pathutils
|
||||
|
||||
const
|
||||
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||
@@ -42,7 +42,7 @@ proc overwriteFiles*(conf: ConfigRef) =
|
||||
let newFile = if gOverWrite: conf.m.fileInfos[i].fullpath
|
||||
else: conf.m.fileInfos[i].fullpath.changeFileExt(".pretty.nim")
|
||||
try:
|
||||
var f = open(newFile, fmWrite)
|
||||
var f = open(newFile.string, fmWrite)
|
||||
for line in conf.m.fileInfos[i].lines:
|
||||
if doStrip:
|
||||
f.write line.strip(leading = false, trailing = true)
|
||||
@@ -51,7 +51,7 @@ proc overwriteFiles*(conf: ConfigRef) =
|
||||
f.write(conf.m.fileInfos[i], "\L")
|
||||
f.close
|
||||
except IOError:
|
||||
rawMessage(conf, errGenerated, "cannot open file: " & newFile)
|
||||
rawMessage(conf, errGenerated, "cannot open file: " & newFile.string)
|
||||
|
||||
proc `=~`(s: string, a: openArray[string]): bool =
|
||||
for x in a:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Low-level streams for high performance.
|
||||
|
||||
import
|
||||
strutils
|
||||
strutils, pathutils
|
||||
|
||||
# support '-d:useGnuReadline' for backwards compatibility:
|
||||
when not defined(windows) and (defined(useGnuReadline) or defined(useLinenoise)):
|
||||
@@ -41,10 +41,10 @@ proc llStreamOpen*(f: File): PLLStream =
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
|
||||
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream =
|
||||
proc llStreamOpen*(filename: AbsoluteFile, mode: FileMode): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsFile
|
||||
if not open(result.f, filename, mode): result = nil
|
||||
if not open(result.f, filename.string, mode): result = nil
|
||||
|
||||
proc llStreamOpen*(): PLLStream =
|
||||
new(result)
|
||||
|
||||
@@ -19,7 +19,7 @@ import
|
||||
cgen, jsgen, json, nversion,
|
||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||
docgen2, parser, modules, ccgutils, sigmatch, ropes,
|
||||
modulegraphs, tables, rod, lineinfos
|
||||
modulegraphs, tables, rod, lineinfos, pathutils
|
||||
|
||||
from magicsys import resetSysTypes
|
||||
|
||||
@@ -30,8 +30,8 @@ proc semanticPasses(g: ModuleGraph) =
|
||||
registerPass g, verbosePass
|
||||
registerPass g, semPass
|
||||
|
||||
proc writeDepsFile(g: ModuleGraph; project: string) =
|
||||
let f = open(changeFileExt(project, "deps"), fmWrite)
|
||||
proc writeDepsFile(g: ModuleGraph; project: AbsoluteFile) =
|
||||
let f = open(changeFileExt(project, "deps").string, fmWrite)
|
||||
for m in g.modules:
|
||||
if m != nil:
|
||||
f.writeLine(toFullPath(g.config, m.position.FileIndex))
|
||||
@@ -47,8 +47,9 @@ proc commandGenDepend(graph: ModuleGraph) =
|
||||
let project = graph.config.projectFull
|
||||
writeDepsFile(graph, project)
|
||||
generateDot(graph, project)
|
||||
execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") &
|
||||
' ' & changeFileExt(project, "dot"))
|
||||
execExternalProgram(graph.config, "dot -Tpng -o" &
|
||||
changeFileExt(project, "png").string &
|
||||
' ' & changeFileExt(project, "dot").string)
|
||||
|
||||
proc commandCheck(graph: ModuleGraph) =
|
||||
graph.config.errorMax = high(int) # do not stop after first error
|
||||
@@ -126,7 +127,7 @@ proc commandEval(graph: ModuleGraph; exp: string) =
|
||||
makeStdinModule(graph))
|
||||
|
||||
proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
var f = addFileExt(mainCommandArg(config), NimExt)
|
||||
var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt)
|
||||
var stream = llStreamOpen(f, fmRead)
|
||||
if stream != nil:
|
||||
var
|
||||
@@ -140,7 +141,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
if tok.tokType == tkEof: break
|
||||
closeLexer(L)
|
||||
else:
|
||||
rawMessage(config, errGenerated, "cannot open file: " & f)
|
||||
rawMessage(config, errGenerated, "cannot open file: " & f.string)
|
||||
|
||||
const
|
||||
PrintRopeCacheStats = false
|
||||
@@ -231,11 +232,11 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
for s in definedSymbolNames(conf.symbols): definedSymbols.elems.add(%s)
|
||||
|
||||
var libpaths = newJArray()
|
||||
for dir in conf.searchPaths: libpaths.elems.add(%dir)
|
||||
for dir in conf.searchPaths: libpaths.elems.add(%dir.string)
|
||||
|
||||
var dumpdata = % [
|
||||
(key: "version", val: %VersionAsString),
|
||||
(key: "project_path", val: %conf.projectFull),
|
||||
(key: "project_path", val: %conf.projectFull.string),
|
||||
(key: "defined_symbols", val: definedSymbols),
|
||||
(key: "lib_paths", val: libpaths)
|
||||
]
|
||||
@@ -247,7 +248,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
for s in definedSymbolNames(conf.symbols): msgWriteln(conf, s, {msgStdout, msgSkipHook})
|
||||
msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook})
|
||||
|
||||
for it in conf.searchPaths: msgWriteln(conf, it)
|
||||
for it in conf.searchPaths: msgWriteln(conf, it.string)
|
||||
of "check":
|
||||
conf.cmd = cmdCheck
|
||||
commandCheck(graph)
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ast, renderer, strutils, msgs, options, idents, os, lineinfos
|
||||
|
||||
import nimblecmd
|
||||
import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
|
||||
pathutils, nimblecmd
|
||||
|
||||
when false:
|
||||
const
|
||||
@@ -160,7 +159,7 @@ 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.len == 0:
|
||||
if fullPath.isEmpty:
|
||||
if doLocalError:
|
||||
let m = if modulename.len > 0: modulename else: $n
|
||||
localError(conf, n.info, "cannot open file: " & m)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import
|
||||
ast, astalgo, magicsys, std / sha1, msgs, cgendata, sigmatch, options,
|
||||
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod,
|
||||
lineinfos
|
||||
lineinfos, pathutils
|
||||
|
||||
proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
magicsys.resetSysTypes(g)
|
||||
@@ -102,19 +102,21 @@ proc connectCallbacks*(graph: ModuleGraph) =
|
||||
proc compileSystemModule*(graph: ModuleGraph) =
|
||||
if graph.systemModule == nil:
|
||||
connectCallbacks(graph)
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim")
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
|
||||
graph.config.libpath / RelativeFile"system.nim")
|
||||
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
|
||||
|
||||
proc wantMainModule*(conf: ConfigRef) =
|
||||
if conf.projectFull.len == 0:
|
||||
fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename")
|
||||
if conf.projectFull.isEmpty:
|
||||
fatal(conf, newLineInfo(conf, AbsoluteFile"command line", 1, 1), errGenerated,
|
||||
"command expects a filename")
|
||||
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
|
||||
|
||||
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
|
||||
connectCallbacks(graph)
|
||||
let conf = graph.config
|
||||
wantMainModule(conf)
|
||||
let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim")
|
||||
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
|
||||
let projectFile = if projectFileIdx == InvalidFileIDX: conf.projectMainIdx else: projectFileIdx
|
||||
graph.importStack.add projectFile
|
||||
if projectFile == systemFileIdx:
|
||||
@@ -123,8 +125,11 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
|
||||
graph.compileSystemModule()
|
||||
discard graph.compileModule(projectFile, {sfMainModule})
|
||||
|
||||
proc makeModule*(graph: ModuleGraph; filename: string): PSym =
|
||||
proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
|
||||
result = graph.newModule(fileInfoIdx(graph.config, filename))
|
||||
result.id = getID()
|
||||
|
||||
proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule"stdin"
|
||||
proc makeModule*(graph: ModuleGraph; filename: string): PSym =
|
||||
result = makeModule(graph, AbsoluteFile filename)
|
||||
|
||||
proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule(AbsoluteFile"stdin")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
import
|
||||
options, strutils, os, tables, ropes, platform, terminal, macros,
|
||||
lineinfos
|
||||
lineinfos, pathutils
|
||||
|
||||
proc toCChar*(c: char; result: var string) =
|
||||
case c
|
||||
@@ -35,20 +35,20 @@ proc makeCString*(s: string): Rope =
|
||||
add(result, rope(res))
|
||||
|
||||
|
||||
proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
|
||||
result.fullPath = fullPath
|
||||
#shallow(result.fullPath)
|
||||
result.projPath = projPath
|
||||
#shallow(result.projPath)
|
||||
let fileName = projPath.extractFilename
|
||||
let fileName = fullPath.extractFilename
|
||||
result.shortName = fileName.changeFileExt("")
|
||||
result.quotedName = fileName.makeCString
|
||||
result.quotedFullName = fullPath.makeCString
|
||||
result.quotedFullName = fullPath.string.makeCString
|
||||
result.lines = @[]
|
||||
when defined(nimpretty):
|
||||
if result.fullPath.len > 0:
|
||||
if not result.fullPath.isEmpty:
|
||||
try:
|
||||
result.fullContent = readFile(result.fullPath)
|
||||
result.fullContent = readFile(result.fullPath.string)
|
||||
except IOError:
|
||||
#rawMessage(errCannotOpenFile, result.fullPath)
|
||||
# XXX fixme
|
||||
@@ -58,39 +58,39 @@ when defined(nimpretty):
|
||||
proc fileSection*(conf: ConfigRef; fid: FileIndex; a, b: int): string =
|
||||
substr(conf.m.fileInfos[fid.int].fullContent, a, b)
|
||||
|
||||
proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
|
||||
proc fileInfoKnown*(conf: ConfigRef; filename: AbsoluteFile): bool =
|
||||
var
|
||||
canon: string
|
||||
canon: AbsoluteFile
|
||||
try:
|
||||
canon = canonicalizePath(conf, filename)
|
||||
except:
|
||||
canon = filename
|
||||
result = conf.m.filenameToIndexTbl.hasKey(canon)
|
||||
result = conf.m.filenameToIndexTbl.hasKey(canon.string)
|
||||
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex =
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool): FileIndex =
|
||||
var
|
||||
canon: string
|
||||
canon: AbsoluteFile
|
||||
pseudoPath = false
|
||||
|
||||
try:
|
||||
canon = canonicalizePath(conf, filename)
|
||||
shallow(canon)
|
||||
shallow(canon.string)
|
||||
except:
|
||||
canon = filename
|
||||
# The compiler uses "filenames" such as `command line` or `stdin`
|
||||
# This flag indicates that we are working with such a path here
|
||||
pseudoPath = true
|
||||
|
||||
if conf.m.filenameToIndexTbl.hasKey(canon):
|
||||
result = conf.m.filenameToIndexTbl[canon]
|
||||
if conf.m.filenameToIndexTbl.hasKey(canon.string):
|
||||
result = conf.m.filenameToIndexTbl[canon.string]
|
||||
else:
|
||||
isKnownFile = false
|
||||
result = conf.m.fileInfos.len.FileIndex
|
||||
conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: filename
|
||||
else: shortenDir(conf, canon)))
|
||||
conf.m.filenameToIndexTbl[canon] = result
|
||||
conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: RelativeFile filename
|
||||
else: relativeTo(canon, conf.projectPath)))
|
||||
conf.m.filenameToIndexTbl[canon.string] = result
|
||||
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex =
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
|
||||
var dummy: bool
|
||||
result = fileInfoIdx(conf, filename, dummy)
|
||||
|
||||
@@ -99,7 +99,7 @@ proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
result.line = uint16(line)
|
||||
result.col = int16(col)
|
||||
|
||||
proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} =
|
||||
proc newLineInfo*(conf: ConfigRef; filename: AbsoluteFile, line, col: int): TLineInfo {.inline.} =
|
||||
result = newLineInfo(fileInfoIdx(conf, filename), line, col)
|
||||
|
||||
|
||||
@@ -152,13 +152,16 @@ proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo =
|
||||
else: result = conf.m.msgContext[i]
|
||||
|
||||
template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
(if fileIdx.int32 < 0 or conf == nil: "???" else: conf.m.fileInfos[fileIdx.int32].projPath)
|
||||
if fileIdx.int32 < 0 or conf == nil:
|
||||
"???"
|
||||
else:
|
||||
conf.m.fileInfos[fileIdx.int32].projPath.string
|
||||
|
||||
proc toFullPath*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
if fileIdx.int32 < 0 or conf == nil: result = "???"
|
||||
else: result = conf.m.fileInfos[fileIdx.int32].fullPath
|
||||
else: result = conf.m.fileInfos[fileIdx.int32].fullPath.string
|
||||
|
||||
proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: string) =
|
||||
proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
assert fileIdx.int32 >= 0
|
||||
conf.m.fileInfos[fileIdx.int32].dirtyFile = filename
|
||||
|
||||
@@ -170,10 +173,10 @@ proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
assert fileIdx.int32 >= 0
|
||||
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
|
||||
|
||||
proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): AbsoluteFile =
|
||||
if fileIdx.int32 < 0:
|
||||
result = "???"
|
||||
elif conf.m.fileInfos[fileIdx.int32].dirtyFile.len > 0:
|
||||
result = AbsoluteFile"???"
|
||||
elif not conf.m.fileInfos[fileIdx.int32].dirtyFile.isEmpty:
|
||||
result = conf.m.fileInfos[fileIdx.int32].dirtyFile
|
||||
else:
|
||||
result = conf.m.fileInfos[fileIdx.int32].fullPath
|
||||
@@ -188,9 +191,9 @@ proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
|
||||
if info.fileIndex.int32 < 0:
|
||||
result = "???"
|
||||
elif optListFullPaths in conf.globalOptions:
|
||||
result = conf.m.fileInfos[info.fileIndex.int32].fullPath
|
||||
result = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
|
||||
else:
|
||||
result = conf.m.fileInfos[info.fileIndex.int32].projPath
|
||||
result = conf.m.fileInfos[info.fileIndex.int32].projPath.string
|
||||
|
||||
proc toLinenumber*(info: TLineInfo): int {.inline.} =
|
||||
result = int info.line
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module implements the generation of ``.ndi`` files for better debugging
|
||||
## support of Nim code. "ndi" stands for "Nim debug info".
|
||||
|
||||
import ast, msgs, ropes, options
|
||||
import ast, msgs, ropes, options, pathutils
|
||||
|
||||
type
|
||||
NdiFile* = object
|
||||
@@ -30,10 +30,10 @@ proc doWrite(f: var NdiFile; s: PSym; conf: ConfigRef) =
|
||||
template writeMangledName*(f: NdiFile; s: PSym; conf: ConfigRef) =
|
||||
if f.enabled: doWrite(f, s, conf)
|
||||
|
||||
proc open*(f: var NdiFile; filename: string; conf: ConfigRef) =
|
||||
f.enabled = filename.len > 0
|
||||
proc open*(f: var NdiFile; filename: AbsoluteFile; conf: ConfigRef) =
|
||||
f.enabled = not filename.isEmpty
|
||||
if f.enabled:
|
||||
f.f = open(filename, fmWrite, 8000)
|
||||
f.f = open(filename.string, fmWrite, 8000)
|
||||
f.buf = newStringOfCap(20)
|
||||
|
||||
proc close*(f: var NdiFile) =
|
||||
|
||||
@@ -21,7 +21,8 @@ when defined(i386) and defined(windows) and defined(vcc):
|
||||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
extccomp, strutils, os, osproc, platform, main, parseopt,
|
||||
nodejs, scriptconfig, idents, modulegraphs, lineinfos, cmdlinehelper
|
||||
nodejs, scriptconfig, idents, modulegraphs, lineinfos, cmdlinehelper,
|
||||
pathutils
|
||||
|
||||
when hasTinyCBackend:
|
||||
import tccgen
|
||||
@@ -30,12 +31,12 @@ when defined(profiler) or defined(memProfiler):
|
||||
{.hint: "Profiling support is turned on!".}
|
||||
import nimprof
|
||||
|
||||
proc prependCurDir(f: string): string =
|
||||
proc prependCurDir(f: AbsoluteFile): AbsoluteFile =
|
||||
when defined(unix):
|
||||
if os.isAbsolute(f): result = f
|
||||
else: result = "./" & f
|
||||
if os.isAbsolute(f.string): result = f
|
||||
else: result = AbsoluteFile("./" & f.string)
|
||||
else:
|
||||
result = f
|
||||
result = AbsoluteFile f
|
||||
|
||||
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
@@ -78,15 +79,15 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
if optRun in conf.globalOptions:
|
||||
if conf.cmd == cmdCompileToJS:
|
||||
var ex: string
|
||||
if conf.outFile.len > 0:
|
||||
if not conf.outFile.isEmpty:
|
||||
ex = conf.outFile.prependCurDir.quoteShell
|
||||
else:
|
||||
ex = quoteShell(
|
||||
completeCFilePath(conf, changeFileExt(conf.projectFull, "js").prependCurDir))
|
||||
execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
|
||||
else:
|
||||
var binPath: string
|
||||
if conf.outFile.len > 0:
|
||||
var binPath: AbsoluteFile
|
||||
if not conf.outFile.isEmpty:
|
||||
# If the user specified an outFile path, use that directly.
|
||||
binPath = conf.outFile.prependCurDir
|
||||
else:
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
## Implements some helper procs for Nimble (Nim's package manager) support.
|
||||
|
||||
import parseutils, strutils, strtabs, os, options, msgs, sequtils,
|
||||
lineinfos
|
||||
lineinfos, pathutils
|
||||
|
||||
proc addPath*(conf: ConfigRef; path: string, info: TLineInfo) =
|
||||
proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
|
||||
if not conf.searchPaths.contains(path):
|
||||
conf.searchPaths.insert(path, 0)
|
||||
|
||||
@@ -112,9 +112,9 @@ proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
|
||||
if not path.isAbsolute():
|
||||
path = p / path
|
||||
|
||||
if not contains(conf.searchPaths, path):
|
||||
if not contains(conf.searchPaths, AbsoluteDir path):
|
||||
message(conf, info, hintPath, path)
|
||||
conf.lazyPaths.insert(path, 0)
|
||||
conf.lazyPaths.insert(AbsoluteDir path, 0)
|
||||
|
||||
proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
|
||||
var packages = newStringTable(modeStyleInsensitive)
|
||||
@@ -126,9 +126,9 @@ proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
|
||||
for p in packages.chosen:
|
||||
addNimblePath(conf, p, info)
|
||||
|
||||
proc nimblePath*(conf: ConfigRef; path: string, info: TLineInfo) =
|
||||
addPathRec(conf, path, info)
|
||||
addNimblePath(conf, path, info)
|
||||
proc nimblePath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
|
||||
addPathRec(conf, path.string, info)
|
||||
addNimblePath(conf, path.string, info)
|
||||
|
||||
when isMainModule:
|
||||
proc v(s: string): Version = s.newVersion
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
||||
options, idents, wordrecg, strtabs, lineinfos
|
||||
options, idents, wordrecg, strtabs, lineinfos, pathutils
|
||||
|
||||
# ---------------- configuration file parser -----------------------------
|
||||
# we use Nim's scanner here to save space and work
|
||||
@@ -201,8 +201,8 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
else:
|
||||
processSwitch(s, val, passPP, info, config)
|
||||
|
||||
proc readConfigFile(
|
||||
filename: string; cache: IdentCache; config: ConfigRef): bool =
|
||||
proc readConfigFile(filename: AbsoluteFile; cache: IdentCache;
|
||||
config: ConfigRef): bool =
|
||||
var
|
||||
L: TLexer
|
||||
tok: TToken
|
||||
@@ -219,24 +219,24 @@ proc readConfigFile(
|
||||
closeLexer(L)
|
||||
return true
|
||||
|
||||
proc getUserConfigPath*(filename: string): string =
|
||||
result = joinPath([getConfigDir(), "nim", filename])
|
||||
proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
|
||||
result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
|
||||
|
||||
proc getSystemConfigPath*(conf: ConfigRef; filename: string): string =
|
||||
proc getSystemConfigPath*(conf: ConfigRef; filename: RelativeFile): AbsoluteFile =
|
||||
# try standard configuration file (installation did not distribute files
|
||||
# the UNIX way)
|
||||
let p = getPrefixDir(conf)
|
||||
result = joinPath([p, "config", filename])
|
||||
result = p / RelativeDir"config" / filename
|
||||
when defined(unix):
|
||||
if not existsFile(result): result = joinPath([p, "etc/nim", filename])
|
||||
if not existsFile(result): result = "/etc/nim/" & filename
|
||||
if not fileExists(result): result = p / RelativeDir"etc/nim" / filename
|
||||
if not fileExists(result): result = AbsoluteDir"/etc/nim" / filename
|
||||
|
||||
proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
|
||||
proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) =
|
||||
setDefaultLibpath(conf)
|
||||
|
||||
var configFiles = newSeq[string]()
|
||||
var configFiles = newSeq[AbsoluteFile]()
|
||||
|
||||
template readConfigFile(path: string) =
|
||||
template readConfigFile(path) =
|
||||
let configPath = path
|
||||
if readConfigFile(configPath, cache, conf):
|
||||
add(configFiles, configPath)
|
||||
@@ -247,10 +247,10 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
|
||||
if optSkipUserConfigFile notin conf.globalOptions:
|
||||
readConfigFile(getUserConfigPath(cfg))
|
||||
|
||||
let pd = if conf.projectPath.len > 0: conf.projectPath else: getCurrentDir()
|
||||
let pd = if not conf.projectPath.isEmpty: conf.projectPath else: AbsoluteDir(getCurrentDir())
|
||||
if optSkipParentConfigFiles notin conf.globalOptions:
|
||||
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
|
||||
readConfigFile(dir / cfg)
|
||||
for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
|
||||
readConfigFile(AbsoluteDir(dir) / cfg)
|
||||
|
||||
if optSkipProjConfigFile notin conf.globalOptions:
|
||||
readConfigFile(pd / cfg)
|
||||
@@ -264,4 +264,4 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
|
||||
|
||||
for filename in configFiles:
|
||||
# delayed to here so that `hintConf` is honored
|
||||
rawMessage(conf, hintConf, filename)
|
||||
rawMessage(conf, hintConf, filename.string)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import
|
||||
ast, astalgo, modules, passes, condsyms,
|
||||
options, sem, semdata, llstream, vm, vmdef,
|
||||
modulegraphs, idents, os
|
||||
modulegraphs, idents, os, pathutils
|
||||
|
||||
type
|
||||
Interpreter* = ref object ## Use Nim as an interpreter with this object
|
||||
@@ -103,8 +103,8 @@ proc createInterpreter*(scriptName: string;
|
||||
registerPass(graph, evalPass)
|
||||
|
||||
for p in searchPaths:
|
||||
conf.searchPaths.add(p)
|
||||
if conf.libpath.len == 0: conf.libpath = p
|
||||
conf.searchPaths.add(AbsoluteDir p)
|
||||
if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
|
||||
|
||||
var m = graph.makeModule(scriptName)
|
||||
incl(m.flags, sfMainModule)
|
||||
|
||||
@@ -15,6 +15,6 @@ const
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1223" # modify this if the rod-format changes!
|
||||
|
||||
NimCompilerApiVersion* = 2 ## Check for the existance of this before accessing it
|
||||
NimCompilerApiVersion* = 3 ## Check for the existance of this before accessing it
|
||||
## as older versions of the compiler API do not
|
||||
## declare this.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -41,10 +41,10 @@ proc getPackageName*(conf: ConfigRef; path: string): string =
|
||||
dec parents
|
||||
if parents <= 0: break
|
||||
|
||||
proc withPackageName*(conf: ConfigRef; path: string): string =
|
||||
let x = getPackageName(conf, path)
|
||||
proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
let x = getPackageName(conf, path.string)
|
||||
if x.len == 0:
|
||||
result = path
|
||||
else:
|
||||
let (p, file, ext) = path.splitFile
|
||||
result = (p / (x & '_' & file)) & ext
|
||||
result = p / RelativeFile((x & '_' & file) & ext)
|
||||
|
||||
@@ -27,7 +27,8 @@ when isMainModule:
|
||||
outp.close
|
||||
|
||||
import
|
||||
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, lineinfos
|
||||
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, lineinfos,
|
||||
pathutils
|
||||
|
||||
when defined(nimpretty2):
|
||||
import layouter
|
||||
@@ -114,7 +115,7 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
|
||||
p.strongSpaces = strongSpaces
|
||||
p.emptyNode = newNode(nkEmpty)
|
||||
|
||||
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
|
||||
proc openParser*(p: var TParser, filename: AbsoluteFile, inputStream: PLLStream,
|
||||
cache: IdentCache; config: ConfigRef;
|
||||
strongSpaces=false) =
|
||||
openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces)
|
||||
@@ -2235,7 +2236,7 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
|
||||
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
|
||||
# spaces...
|
||||
parser.lex.errorHandler = errorHandler
|
||||
openParser(parser, filename, stream, cache, config, false)
|
||||
openParser(parser, AbsoluteFile filename, stream, cache, config, false)
|
||||
|
||||
result = parser.parseAll
|
||||
closeParser(parser)
|
||||
|
||||
@@ -14,7 +14,7 @@ import
|
||||
strutils, options, ast, astalgo, llstream, msgs, platform, os,
|
||||
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
||||
nimsets, syntaxes, times, idgen, modulegraphs, reorder, rod,
|
||||
lineinfos
|
||||
lineinfos, pathutils
|
||||
|
||||
|
||||
type
|
||||
@@ -106,7 +106,7 @@ proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
|
||||
|
||||
proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
|
||||
let fullPath = findModule(conf, module, relativeTo)
|
||||
if fullPath.len == 0:
|
||||
if fullPath.isEmpty:
|
||||
result = InvalidFileIDX
|
||||
else:
|
||||
result = fileInfoIdx(conf, fullPath)
|
||||
@@ -160,7 +160,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
|
||||
let filename = toFullPathConsiderDirty(graph.config, fileIdx)
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if s == nil:
|
||||
rawMessage(graph.config, errCannotOpenFile, filename)
|
||||
rawMessage(graph.config, errCannotOpenFile, filename.string)
|
||||
return false
|
||||
else:
|
||||
s = stream
|
||||
|
||||
254
compiler/pathutils.nim
Normal file
254
compiler/pathutils.nim
Normal file
@@ -0,0 +1,254 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2018 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Path handling utilities for Nim. Strictly typed code in order
|
||||
## to avoid the never ending time sink in getting path handling right.
|
||||
## Might be a candidate for the stdlib later.
|
||||
|
||||
import os, strutils
|
||||
|
||||
type
|
||||
AbsoluteFile* = distinct string
|
||||
AbsoluteDir* = distinct string
|
||||
RelativeFile* = distinct string
|
||||
RelativeDir* = distinct string
|
||||
|
||||
proc isEmpty*(x: AbsoluteFile): bool {.inline.} = x.string.len == 0
|
||||
proc isEmpty*(x: AbsoluteDir): bool {.inline.} = x.string.len == 0
|
||||
proc isEmpty*(x: RelativeFile): bool {.inline.} = x.string.len == 0
|
||||
proc isEmpty*(x: RelativeDir): bool {.inline.} = x.string.len == 0
|
||||
|
||||
proc copyFile*(source, dest: AbsoluteFile) =
|
||||
os.copyFile(source.string, dest.string)
|
||||
|
||||
proc removeFile*(x: AbsoluteFile) {.borrow.}
|
||||
|
||||
proc splitFile*(x: AbsoluteFile): tuple[dir: AbsoluteDir, name, ext: string] =
|
||||
let (a, b, c) = splitFile(x.string)
|
||||
result = (dir: AbsoluteDir(a), name: b, ext: c)
|
||||
|
||||
proc extractFilename*(x: AbsoluteFile): string {.borrow.}
|
||||
|
||||
proc fileExists*(x: AbsoluteFile): bool {.borrow.}
|
||||
proc dirExists*(x: AbsoluteDir): bool {.borrow.}
|
||||
|
||||
proc quoteShell*(x: AbsoluteFile): string {.borrow.}
|
||||
proc quoteShell*(x: AbsoluteDir): string {.borrow.}
|
||||
|
||||
proc cmpPaths*(x, y: AbsoluteDir): int {.borrow.}
|
||||
|
||||
proc createDir*(x: AbsoluteDir) {.borrow.}
|
||||
|
||||
type
|
||||
PathIter = object
|
||||
i, prev: int
|
||||
notFirst: bool
|
||||
|
||||
proc hasNext(it: PathIter; x: string): bool =
|
||||
it.i < x.len
|
||||
|
||||
proc next(it: var PathIter; x: string): (int, int) =
|
||||
it.prev = it.i
|
||||
if not it.notFirst and x[it.i] in {DirSep, AltSep}:
|
||||
# absolute path:
|
||||
inc it.i
|
||||
else:
|
||||
while it.i < x.len and x[it.i] notin {DirSep, AltSep}: inc it.i
|
||||
if it.i > it.prev:
|
||||
result = (it.prev, it.i-1)
|
||||
elif hasNext(it, x):
|
||||
result = next(it, x)
|
||||
|
||||
# skip all separators:
|
||||
while it.i < x.len and x[it.i] in {DirSep, AltSep}: inc it.i
|
||||
it.notFirst = true
|
||||
|
||||
iterator dirs(x: string): (int, int) =
|
||||
var it: PathIter
|
||||
while hasNext(it, x): yield next(it, x)
|
||||
|
||||
when false:
|
||||
iterator dirs(x: string): (int, int) =
|
||||
var i = 0
|
||||
var first = true
|
||||
while i < x.len:
|
||||
let prev = i
|
||||
if first and x[i] in {DirSep, AltSep}:
|
||||
# absolute path:
|
||||
inc i
|
||||
else:
|
||||
while i < x.len and x[i] notin {DirSep, AltSep}: inc i
|
||||
if i > prev:
|
||||
yield (prev, i-1)
|
||||
first = false
|
||||
# skip all separators:
|
||||
while i < x.len and x[i] in {DirSep, AltSep}: inc i
|
||||
|
||||
proc isDot(x: string; bounds: (int, int)): bool =
|
||||
bounds[1] == bounds[0] and x[bounds[0]] == '.'
|
||||
|
||||
proc isDotDot(x: string; bounds: (int, int)): bool =
|
||||
bounds[1] == bounds[0] + 1 and x[bounds[0]] == '.' and x[bounds[0]+1] == '.'
|
||||
|
||||
proc isSlash(x: string; bounds: (int, int)): bool =
|
||||
bounds[1] == bounds[0] and x[bounds[0]] in {DirSep, AltSep}
|
||||
|
||||
proc canon(x: string; result: var string; state: var int) =
|
||||
# state: 0th bit set if isAbsolute path. Other bits count
|
||||
# the number of path components.
|
||||
for b in dirs(x):
|
||||
if (state shr 1 == 0) and isSlash(x, b):
|
||||
result.add DirSep
|
||||
state = state or 1
|
||||
elif result.len > (state and 1) and isDotDot(x, b):
|
||||
var d = result.len
|
||||
# f/..
|
||||
while d > (state and 1) and result[d-1] != DirSep:
|
||||
dec d
|
||||
setLen(result, d)
|
||||
elif isDot(x, b):
|
||||
discard "discard the dot"
|
||||
else:
|
||||
if result.len > (state and 1): result.add DirSep
|
||||
result.add substr(x, b[0], b[1])
|
||||
inc state, 2
|
||||
|
||||
proc canon(x: string): string =
|
||||
# - Turn multiple slashes into single slashes.
|
||||
# - Resolve '/foo/../bar' to '/bar'.
|
||||
# - Remove './' from the path.
|
||||
result = newStringOfCap(x.len)
|
||||
var state = 0
|
||||
canon(x, result, state)
|
||||
|
||||
when FileSystemCaseSensitive:
|
||||
template `!=?`(a, b: char): bool = toLowerAscii(a) != toLowerAscii(b)
|
||||
else:
|
||||
template `!=?`(a, b: char): bool = a != b
|
||||
|
||||
proc relativeTo(full, base: string; sep = DirSep): string =
|
||||
if full.len == 0: return ""
|
||||
var f, b: PathIter
|
||||
var ff = (0, -1)
|
||||
var bb = (0, -1) # (int, int)
|
||||
result = newStringOfCap(full.len)
|
||||
# skip the common prefix:
|
||||
while f.hasNext(full) and b.hasNext(base):
|
||||
ff = next(f, full)
|
||||
bb = next(b, base)
|
||||
let diff = ff[1] - ff[0]
|
||||
if diff != bb[1] - bb[0]: break
|
||||
var same = true
|
||||
for i in 0..diff:
|
||||
if full[i + ff[0]] !=? base[i + bb[0]]:
|
||||
same = false
|
||||
break
|
||||
if not same: break
|
||||
ff = (0, -1)
|
||||
bb = (0, -1)
|
||||
# for i in 0..diff:
|
||||
# result.add base[i + bb[0]]
|
||||
|
||||
# /foo/bar/xxx/ -- base
|
||||
# /foo/bar/baz -- full path
|
||||
# ../baz
|
||||
# every directory that is in 'base', needs to add '..'
|
||||
while true:
|
||||
if bb[1] >= bb[0]:
|
||||
if result.len > 0 and result[^1] != sep:
|
||||
result.add sep
|
||||
result.add ".."
|
||||
if not b.hasNext(base): break
|
||||
bb = b.next(base)
|
||||
|
||||
# add the rest of 'full':
|
||||
while true:
|
||||
if ff[1] >= ff[0]:
|
||||
if result.len > 0 and result[^1] != sep:
|
||||
result.add sep
|
||||
for i in 0..ff[1] - ff[0]:
|
||||
result.add full[i + ff[0]]
|
||||
if not f.hasNext(full): break
|
||||
ff = f.next(full)
|
||||
|
||||
when true:
|
||||
proc eqImpl(x, y: string): bool =
|
||||
when FileSystemCaseSensitive:
|
||||
result = toLowerAscii(canon x) == toLowerAscii(canon y)
|
||||
else:
|
||||
result = canon(x) == canon(y)
|
||||
|
||||
proc `==`*(x, y: AbsoluteFile): bool = eqImpl(x.string, y.string)
|
||||
proc `==`*(x, y: AbsoluteDir): bool = eqImpl(x.string, y.string)
|
||||
proc `==`*(x, y: RelativeFile): bool = eqImpl(x.string, y.string)
|
||||
proc `==`*(x, y: RelativeDir): bool = eqImpl(x.string, y.string)
|
||||
|
||||
proc `/`*(base: AbsoluteDir; f: RelativeFile): AbsoluteFile =
|
||||
assert isAbsolute(base.string)
|
||||
assert(not isAbsolute(f.string))
|
||||
result = AbsoluteFile newStringOfCap(base.string.len + f.string.len)
|
||||
var state = 0
|
||||
canon(base.string, result.string, state)
|
||||
canon(f.string, result.string, state)
|
||||
|
||||
proc `/`*(base: AbsoluteDir; f: RelativeDir): AbsoluteDir =
|
||||
assert isAbsolute(base.string)
|
||||
assert(not isAbsolute(f.string))
|
||||
result = AbsoluteDir newStringOfCap(base.string.len + f.string.len)
|
||||
var state = 0
|
||||
canon(base.string, result.string, state)
|
||||
canon(f.string, result.string, state)
|
||||
|
||||
proc relativeTo*(fullPath: AbsoluteFile, baseFilename: AbsoluteDir;
|
||||
sep = DirSep): RelativeFile =
|
||||
RelativeFile(relativeTo(fullPath.string, baseFilename.string, sep))
|
||||
|
||||
proc toAbsolute*(file: string; base: AbsoluteDir): AbsoluteFile =
|
||||
if isAbsolute(file): result = AbsoluteFile(file)
|
||||
else: result = base / RelativeFile file
|
||||
|
||||
proc changeFileExt*(x: AbsoluteFile; ext: string): AbsoluteFile {.borrow.}
|
||||
proc changeFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.}
|
||||
|
||||
proc addFileExt*(x: AbsoluteFile; ext: string): AbsoluteFile {.borrow.}
|
||||
proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.}
|
||||
|
||||
proc writeFile*(x: AbsoluteFile; content: string) {.borrow.}
|
||||
|
||||
when isMainModule and defined(posix):
|
||||
doAssert canon"/foo/../bar" == "/bar"
|
||||
doAssert canon"foo/../bar" == "bar"
|
||||
|
||||
doAssert canon"/f/../bar///" == "/bar"
|
||||
doAssert canon"f/..////bar" == "bar"
|
||||
|
||||
doAssert canon"../bar" == "../bar"
|
||||
doAssert canon"/../bar" == "/../bar"
|
||||
|
||||
doAssert canon("foo/../../bar/") == "../bar"
|
||||
doAssert canon("./bla/blob/") == "bla/blob"
|
||||
doAssert canon(".hiddenFile") == ".hiddenFile"
|
||||
doAssert canon("./bla/../../blob/./zoo.nim") == "../blob/zoo.nim"
|
||||
|
||||
doAssert canon("C:/file/to/this/long") == "C:/file/to/this/long"
|
||||
doAssert canon("") == ""
|
||||
doAssert canon("foobar") == "foobar"
|
||||
doAssert canon("f/////////") == "f"
|
||||
|
||||
doAssert relativeTo("/foo/bar//baz.nim", "/foo") == "bar/baz.nim"
|
||||
|
||||
doAssert relativeTo("/Users/me/bar/z.nim", "/Users/other/bad") == "../../me/bar/z.nim"
|
||||
|
||||
doAssert relativeTo("/Users/me/bar/z.nim", "/Users/other") == "../me/bar/z.nim"
|
||||
doAssert relativeTo("/Users///me/bar//z.nim", "//Users/") == "me/bar/z.nim"
|
||||
doAssert relativeTo("/Users/me/bar/z.nim", "/Users/me") == "bar/z.nim"
|
||||
doAssert relativeTo("", "/users/moo") == ""
|
||||
doAssert relativeTo("foo", "") == "foo"
|
||||
|
||||
echo string(AbsoluteDir"/Users/me///" / RelativeFile"z.nim")
|
||||
@@ -12,7 +12,7 @@
|
||||
import
|
||||
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
|
||||
wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
|
||||
types, lookups, lineinfos
|
||||
types, lookups, lineinfos, pathutils
|
||||
|
||||
const
|
||||
FirstCallConv* = wNimcall
|
||||
@@ -442,26 +442,22 @@ proc processUndef(c: PContext, n: PNode) =
|
||||
else:
|
||||
invalidPragma(c, n)
|
||||
|
||||
type
|
||||
TLinkFeature = enum
|
||||
linkNormal, linkSys
|
||||
|
||||
proc relativeFile(c: PContext; n: PNode; ext=""): string =
|
||||
proc relativeFile(c: PContext; n: PNode; ext=""): AbsoluteFile =
|
||||
var s = expectStrLit(c, n)
|
||||
if ext.len > 0 and splitFile(s).ext == "":
|
||||
s = addFileExt(s, ext)
|
||||
result = parentDir(toFullPath(c.config, n.info)) / s
|
||||
result = AbsoluteFile parentDir(toFullPath(c.config, n.info)) / s
|
||||
if not fileExists(result):
|
||||
if isAbsolute(s): result = s
|
||||
if isAbsolute(s): result = AbsoluteFile s
|
||||
else:
|
||||
result = findFile(c.config, s)
|
||||
if result.len == 0: result = s
|
||||
if result.isEmpty: result = AbsoluteFile s
|
||||
|
||||
proc processCompile(c: PContext, n: PNode) =
|
||||
proc docompile(c: PContext; it: PNode; src, dest: string) =
|
||||
proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile) =
|
||||
var cf = Cfile(cname: src, obj: dest, flags: {CfileFlag.External})
|
||||
extccomp.addExternalFileToCompile(c.config, cf)
|
||||
recordPragma(c, it, "compile", src, dest)
|
||||
recordPragma(c, it, "compile", src.string, dest.string)
|
||||
|
||||
proc getStrLit(c: PContext, n: PNode; i: int): string =
|
||||
n.sons[i] = c.semConstExpr(c, n[i])
|
||||
@@ -478,30 +474,23 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
let dest = getStrLit(c, it, 1)
|
||||
var found = parentDir(toFullPath(c.config, n.info)) / s
|
||||
for f in os.walkFiles(found):
|
||||
let obj = completeCFilePath(c.config, dest % extractFilename(f))
|
||||
docompile(c, it, f, obj)
|
||||
let obj = completeCFilePath(c.config, AbsoluteFile(dest % extractFilename(f)))
|
||||
docompile(c, it, AbsoluteFile f, obj)
|
||||
else:
|
||||
let s = expectStrLit(c, n)
|
||||
var found = parentDir(toFullPath(c.config, n.info)) / s
|
||||
var found = AbsoluteFile(parentDir(toFullPath(c.config, n.info)) / s)
|
||||
if not fileExists(found):
|
||||
if isAbsolute(s): found = s
|
||||
if isAbsolute(s): found = AbsoluteFile s
|
||||
else:
|
||||
found = findFile(c.config, s)
|
||||
if found.len == 0: found = s
|
||||
if found.isEmpty: found = AbsoluteFile s
|
||||
let obj = toObjFile(c.config, completeCFilePath(c.config, found, false))
|
||||
docompile(c, it, found, obj)
|
||||
|
||||
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
||||
proc processLink(c: PContext, n: PNode) =
|
||||
let found = relativeFile(c, n, CC[c.config.cCompiler].objExt)
|
||||
case feature
|
||||
of linkNormal:
|
||||
extccomp.addExternalFileToLink(c.config, found)
|
||||
recordPragma(c, n, "link", found)
|
||||
of linkSys:
|
||||
let dest = c.config.libpath / completeCFilePath(c.config, found, false)
|
||||
extccomp.addExternalFileToLink(c.config, dest)
|
||||
recordPragma(c, n, "link", dest)
|
||||
else: internalError(c.config, n.info, "processCommonLink")
|
||||
extccomp.addExternalFileToLink(c.config, found)
|
||||
recordPragma(c, n, "link", found.string)
|
||||
|
||||
proc pragmaBreakpoint(c: PContext, n: PNode) =
|
||||
discard getOptionalStr(c, n, "")
|
||||
@@ -594,8 +583,9 @@ proc pragmaLine(c: PContext, n: PNode) =
|
||||
elif y.kind != nkIntLit:
|
||||
localError(c.config, n.info, errIntLiteralExpected)
|
||||
else:
|
||||
# XXX this produces weird paths which are not properly resolved:
|
||||
n.info.fileIndex = msgs.fileInfoIdx(c.config, x.strVal)
|
||||
# XXX check if paths are properly resolved this way:
|
||||
let dir = toFullPath(c.config, n.info).splitFile.dir
|
||||
n.info.fileIndex = fileInfoIdx(c.config, AbsoluteDir(dir) / RelativeFile(x.strVal))
|
||||
n.info.line = uint16(y.intVal)
|
||||
else:
|
||||
localError(c.config, n.info, "tuple expected")
|
||||
@@ -959,8 +949,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wDefine: processDefine(c, it)
|
||||
of wUndef: processUndef(c, it)
|
||||
of wCompile: processCompile(c, it)
|
||||
of wLink: processCommonLink(c, it, linkNormal)
|
||||
of wLinksys: processCommonLink(c, it, linkSys)
|
||||
of wLink: processLink(c, it)
|
||||
of wPassl:
|
||||
let s = expectStrLit(c, it)
|
||||
extccomp.addLinkOption(c.config, s)
|
||||
|
||||
@@ -15,11 +15,12 @@ import
|
||||
type
|
||||
TRenderFlag* = enum
|
||||
renderNone, renderNoBody, renderNoComments, renderDocComments,
|
||||
renderNoPragmas, renderIds, renderNoProcDefs
|
||||
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms
|
||||
TRenderFlags* = set[TRenderFlag]
|
||||
TRenderTok* = object
|
||||
kind*: TTokType
|
||||
length*: int16
|
||||
sym*: PSym
|
||||
|
||||
TRenderTokSeq* = seq[TRenderTok]
|
||||
TSrcGen* = object
|
||||
@@ -105,11 +106,12 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
|
||||
g.inGenericParams = false
|
||||
g.config = config
|
||||
|
||||
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
proc addTok(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
|
||||
var length = len(g.tokens)
|
||||
setLen(g.tokens, length + 1)
|
||||
g.tokens[length].kind = kind
|
||||
g.tokens[length].length = int16(len(s))
|
||||
g.tokens[length].sym = sym
|
||||
add(g.buf, s)
|
||||
|
||||
proc addPendingNL(g: var TSrcGen) =
|
||||
@@ -165,11 +167,11 @@ proc dedent(g: var TSrcGen) =
|
||||
dec(g.pendingNL, IndentWidth)
|
||||
dec(g.lineLen, IndentWidth)
|
||||
|
||||
proc put(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
proc put(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
|
||||
if kind != tkSpaces:
|
||||
addPendingNL(g)
|
||||
if len(s) > 0:
|
||||
addTok(g, kind, s)
|
||||
addTok(g, kind, s, sym)
|
||||
inc(g.lineLen, len(s))
|
||||
else:
|
||||
g.pendingWhitespace = s.len
|
||||
@@ -836,7 +838,7 @@ proc gident(g: var TSrcGen, n: PNode) =
|
||||
t = tkSymbol
|
||||
else:
|
||||
t = tkOpr
|
||||
put(g, t, s)
|
||||
put(g, t, s, if n.kind == nkSym and renderSyms in g.flags: n.sym else: nil)
|
||||
if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags):
|
||||
when defined(debugMagics):
|
||||
put(g, tkIntLit, $n.sym.id & $n.sym.magic)
|
||||
@@ -1541,3 +1543,9 @@ proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
|
||||
inc(r.idx)
|
||||
else:
|
||||
kind = tkEof
|
||||
|
||||
proc getTokSym*(r: TSrcGen): PSym =
|
||||
if r.idx > 0 and r.idx <= len(r.tokens):
|
||||
result = r.tokens[r.idx-1].sym
|
||||
else:
|
||||
result = nil
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
|
||||
renderer, rodutils, idents, astalgo, btrees, magicsys, cgmeth, extccomp,
|
||||
btrees, trees, condsyms, nversion
|
||||
btrees, trees, condsyms, nversion, pathutils
|
||||
|
||||
## Todo:
|
||||
## - Dependency computation should use *signature* hashes in order to
|
||||
@@ -796,7 +796,7 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
|
||||
flags: {CfileFlag.External})
|
||||
extccomp.addExternalFileToCompile(g.config, cf)
|
||||
of "link":
|
||||
extccomp.addExternalFileToLink(g.config, n[1].strVal)
|
||||
extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal)
|
||||
of "passl":
|
||||
extccomp.addLinkOption(g.config, n[1].strVal)
|
||||
of "passc":
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
import
|
||||
hashes
|
||||
|
||||
from pathutils import AbsoluteFile
|
||||
|
||||
type
|
||||
FormatStr* = string # later we may change it to CString for better
|
||||
# performance of the code generator (assignments
|
||||
@@ -183,9 +185,9 @@ proc writeRope*(f: File, r: Rope) =
|
||||
## writes a rope to a file.
|
||||
for s in leaves(r): write(f, s)
|
||||
|
||||
proc writeRope*(head: Rope, filename: string): bool =
|
||||
proc writeRope*(head: Rope, filename: AbsoluteFile): bool =
|
||||
var f: File
|
||||
if open(f, filename, fmWrite):
|
||||
if open(f, filename.string, fmWrite):
|
||||
if head != nil: writeRope(f, head)
|
||||
close(f)
|
||||
result = true
|
||||
@@ -314,16 +316,16 @@ proc equalsFile*(r: Rope, f: File): bool =
|
||||
result = readBuffer(f, addr(buf[0]), 1) == 0 and
|
||||
btotal == rtotal # check that we've read all
|
||||
|
||||
proc equalsFile*(r: Rope, filename: string): bool =
|
||||
proc equalsFile*(r: Rope, filename: AbsoluteFile): bool =
|
||||
## returns true if the contents of the file `f` equal `r`. If `f` does not
|
||||
## exist, false is returned.
|
||||
var f: File
|
||||
result = open(f, filename)
|
||||
result = open(f, filename.string)
|
||||
if result:
|
||||
result = equalsFile(r, f)
|
||||
close(f)
|
||||
|
||||
proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
|
||||
proc writeRopeIfNotEqual*(r: Rope, filename: AbsoluteFile): bool =
|
||||
# returns true if overwritten
|
||||
if not equalsFile(r, filename):
|
||||
result = writeRope(r, filename)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import
|
||||
ast, modules, idents, passes, passaux, condsyms,
|
||||
options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs,
|
||||
os, times, osproc, wordrecg, strtabs, modulegraphs, lineinfos
|
||||
os, times, osproc, wordrecg, strtabs, modulegraphs, lineinfos, pathutils
|
||||
|
||||
# we support 'cmpIgnoreStyle' natively for efficiency:
|
||||
from strutils import cmpIgnoreStyle, contains
|
||||
@@ -105,7 +105,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
cbconf exists:
|
||||
setResult(a, options.existsConfigVar(conf, a.getString 0))
|
||||
cbconf nimcacheDir:
|
||||
setResult(a, options.getNimcacheDir(conf))
|
||||
setResult(a, options.getNimcacheDir(conf).string)
|
||||
cbconf paramStr:
|
||||
setResult(a, os.paramStr(int a.getInt 0))
|
||||
cbconf paramCount:
|
||||
@@ -120,8 +120,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
if arg.len > 0:
|
||||
conf.projectName = arg
|
||||
let path =
|
||||
if conf.projectName.isAbsolute: conf.projectName
|
||||
else: conf.projectPath / conf.projectName
|
||||
if conf.projectName.isAbsolute: AbsoluteFile(conf.projectName)
|
||||
else: conf.projectPath / RelativeFile(conf.projectName)
|
||||
try:
|
||||
conf.projectFull = canonicalizePath(conf, path)
|
||||
except OSError:
|
||||
@@ -149,9 +149,9 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
cbconf cppDefine:
|
||||
options.cppDefine(conf, a.getString(0))
|
||||
|
||||
proc runNimScript*(cache: IdentCache; scriptName: string;
|
||||
proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
freshDefines=true; conf: ConfigRef) =
|
||||
rawMessage(conf, hintConf, scriptName)
|
||||
rawMessage(conf, hintConf, scriptName.string)
|
||||
|
||||
let graph = newModuleGraph(cache, conf)
|
||||
connectCallbacks(graph)
|
||||
@@ -169,7 +169,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
|
||||
|
||||
var m = graph.makeModule(scriptName)
|
||||
incl(m.flags, sfMainModule)
|
||||
graph.vm = setupVM(m, cache, scriptName, graph)
|
||||
graph.vm = setupVM(m, cache, scriptName.string, graph)
|
||||
|
||||
graph.compileSystemModule() # TODO: see why this unsets hintConf in conf.notes
|
||||
discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
# included from sigmatch.nim
|
||||
|
||||
import algorithm, prefixmatches, lineinfos
|
||||
import algorithm, prefixmatches, lineinfos, pathutils
|
||||
from wordrecg import wDeprecated
|
||||
|
||||
when defined(nimsuggest):
|
||||
@@ -319,7 +319,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
||||
if n.kind == nkSym and n.sym.kind == skError and c.config.suggestVersion == 0:
|
||||
# consider 'foo.|' where 'foo' is some not imported module.
|
||||
let fullPath = findModule(c.config, n.sym.name.s, toFullPath(c.config, n.info))
|
||||
if fullPath.len == 0:
|
||||
if fullPath.isEmpty:
|
||||
# error: no known module name:
|
||||
typ = nil
|
||||
else:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser,
|
||||
filters, filter_tmpl, renderer, lineinfos
|
||||
filters, filter_tmpl, renderer, lineinfos, pathutils
|
||||
|
||||
type
|
||||
TFilterKind* = enum
|
||||
@@ -58,7 +58,7 @@ proc containsShebang(s: string, i: int): bool =
|
||||
while j < s.len and s[j] in Whitespace: inc(j)
|
||||
result = s[j] == '/'
|
||||
|
||||
proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache;
|
||||
proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache;
|
||||
config: ConfigRef): PNode =
|
||||
result = newNode(nkEmpty)
|
||||
var s = llStreamOpen(filename, fmRead)
|
||||
@@ -100,7 +100,7 @@ proc getCallee(conf: ConfigRef; n: PNode): PIdent =
|
||||
else:
|
||||
localError(conf, n.info, "invalid filter: " & renderTree(n))
|
||||
|
||||
proc applyFilter(p: var TParsers, n: PNode, filename: string,
|
||||
proc applyFilter(p: var TParsers, n: PNode, filename: AbsoluteFile,
|
||||
stdin: PLLStream): PLLStream =
|
||||
var ident = getCallee(p.config, n)
|
||||
var f = getFilter(ident)
|
||||
@@ -121,7 +121,7 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string,
|
||||
msgWriteln(p.config, result.s)
|
||||
rawMessage(p.config, hintCodeEnd, [])
|
||||
|
||||
proc evalPipe(p: var TParsers, n: PNode, filename: string,
|
||||
proc evalPipe(p: var TParsers, n: PNode, filename: AbsoluteFile,
|
||||
start: PLLStream): PLLStream =
|
||||
assert p.config != nil
|
||||
result = start
|
||||
@@ -161,8 +161,8 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode
|
||||
p: TParsers
|
||||
f: File
|
||||
let filename = toFullPathConsiderDirty(config, fileIdx)
|
||||
if not open(f, filename):
|
||||
rawMessage(config, errGenerated, "cannot open file: " & filename)
|
||||
if not open(f, filename.string):
|
||||
rawMessage(config, errGenerated, "cannot open file: " & filename.string)
|
||||
return
|
||||
openParsers(p, fileIdx, llStreamOpen(f), cache, config)
|
||||
result = parseAll(p)
|
||||
|
||||
@@ -13,7 +13,7 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): str
|
||||
try:
|
||||
var filename = parentDir(toFullPath(conf, info)) / file
|
||||
if not fileExists(filename):
|
||||
filename = findFile(conf, file)
|
||||
filename = findFile(conf, file).string
|
||||
result = readFile(filename)
|
||||
# we produce a fake include statement for every slurped filename, so that
|
||||
# the module dependencies are accurate:
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import pathutils
|
||||
|
||||
template setX(k, field) {.dirty.} =
|
||||
var s: seq[TFullReg]
|
||||
move(s, cast[seq[TFullReg]](a.slots))
|
||||
@@ -38,6 +40,8 @@ proc setResult*(a: VmArgs; n: PNode) =
|
||||
s[a.ra].kind = rkNode
|
||||
s[a.ra].node = n
|
||||
|
||||
proc setResult*(a: VmArgs; v: AbsoluteDir) = setResult(a, v.string)
|
||||
|
||||
proc setResult*(a: VmArgs; v: seq[string]) =
|
||||
var s: seq[TFullReg]
|
||||
move(s, cast[seq[TFullReg]](a.slots))
|
||||
|
||||
@@ -82,7 +82,7 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
|
||||
|
||||
proc getProjectPathWrapper(a: VmArgs) =
|
||||
setResult a, c.config.projectPath
|
||||
setResult a, c.config.projectPath.string
|
||||
|
||||
wrap1f_math(sqrt)
|
||||
wrap1f_math(ln)
|
||||
|
||||
@@ -20,7 +20,8 @@ import compiler / [options, commands, modules, sem,
|
||||
passes, passaux, msgs, nimconf,
|
||||
extccomp, condsyms,
|
||||
sigmatch, ast, scriptconfig,
|
||||
idents, modulegraphs, vm, prefixmatches, lineinfos, cmdlinehelper]
|
||||
idents, modulegraphs, vm, prefixmatches, lineinfos, cmdlinehelper,
|
||||
pathutils]
|
||||
|
||||
when defined(windows):
|
||||
import winlean
|
||||
@@ -158,10 +159,11 @@ proc symFromInfo(graph: ModuleGraph; trackPos: TLineInfo): PSym =
|
||||
if m != nil and m.ast != nil:
|
||||
result = findNode(m.ast, trackPos)
|
||||
|
||||
proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
|
||||
proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int;
|
||||
graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
myLog("cmd: " & $cmd & ", file: " & file & ", dirtyFile: " & dirtyfile &
|
||||
myLog("cmd: " & $cmd & ", file: " & file.string &
|
||||
", dirtyFile: " & dirtyfile.string &
|
||||
"[" & $line & ":" & $col & "]")
|
||||
conf.ideCmd = cmd
|
||||
if cmd == ideChk:
|
||||
@@ -175,8 +177,8 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
|
||||
var isKnownFile = true
|
||||
let dirtyIdx = fileInfoIdx(conf, file, isKnownFile)
|
||||
|
||||
if dirtyfile.len != 0: msgs.setDirtyFile(conf, dirtyIdx, dirtyfile)
|
||||
else: msgs.setDirtyFile(conf, dirtyIdx, "")
|
||||
if not dirtyfile.isEmpty: msgs.setDirtyFile(conf, dirtyIdx, dirtyfile)
|
||||
else: msgs.setDirtyFile(conf, dirtyIdx, AbsoluteFile"")
|
||||
|
||||
conf.m.trackPos = newLineInfo(dirtyIdx, line, col)
|
||||
conf.m.trackPosAttached = false
|
||||
@@ -186,7 +188,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
|
||||
if not isKnownFile:
|
||||
graph.compileProject()
|
||||
if conf.suggestVersion == 0 and conf.ideCmd in {ideUse, ideDus} and
|
||||
dirtyfile.len == 0:
|
||||
dirtyfile.isEmpty:
|
||||
discard "no need to recompile anything"
|
||||
else:
|
||||
let modIdx = graph.parentModule(dirtyIdx)
|
||||
@@ -204,12 +206,12 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
|
||||
proc executeEpc(cmd: IdeCmd, args: SexpNode;
|
||||
graph: ModuleGraph) =
|
||||
let
|
||||
file = args[0].getStr
|
||||
file = AbsoluteFile args[0].getStr
|
||||
line = args[1].getNum
|
||||
column = args[2].getNum
|
||||
var dirtyfile = ""
|
||||
var dirtyfile = AbsoluteFile""
|
||||
if len(args) > 3:
|
||||
dirtyfile = args[3].getStr("")
|
||||
dirtyfile = AbsoluteFile args[3].getStr("")
|
||||
execute(cmd, file, dirtyfile, int(line), int(column), graph)
|
||||
|
||||
proc returnEpc(socket: Socket, uid: BiggestInt, s: SexpNode|string,
|
||||
@@ -431,11 +433,11 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) =
|
||||
i += parseInt(cmd, col, i)
|
||||
|
||||
if conf.ideCmd == ideKnown:
|
||||
results.send(Suggest(section: ideKnown, quality: ord(fileInfoKnown(conf, orig))))
|
||||
results.send(Suggest(section: ideKnown, quality: ord(fileInfoKnown(conf, AbsoluteFile orig))))
|
||||
else:
|
||||
if conf.ideCmd == ideChk:
|
||||
for cm in cachedMsgs: errorHook(conf, cm.info, cm.msg, cm.sev)
|
||||
execute(conf.ideCmd, orig, dirtyfile, line, col, graph)
|
||||
execute(conf.ideCmd, AbsoluteFile orig, AbsoluteFile dirtyfile, line, col, graph)
|
||||
sentinel()
|
||||
|
||||
proc recompileFullProject(graph: ModuleGraph) =
|
||||
@@ -451,7 +453,7 @@ proc mainThread(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
if gLogging:
|
||||
for it in conf.searchPaths:
|
||||
log(it)
|
||||
log(it.string)
|
||||
|
||||
proc wrHook(line: string) {.closure.} =
|
||||
if gMode == mepc:
|
||||
@@ -496,7 +498,7 @@ proc mainCommand(graph: ModuleGraph) =
|
||||
wantMainModule(conf)
|
||||
|
||||
if not fileExists(conf.projectFull):
|
||||
quit "cannot find file: " & conf.projectFull
|
||||
quit "cannot find file: " & conf.projectFull.string
|
||||
|
||||
add(conf.searchPaths, conf.libpath)
|
||||
|
||||
@@ -518,9 +520,9 @@ proc mainCommand(graph: ModuleGraph) =
|
||||
of mtcp: createThread(inputThread, replTcp, (gPort, gAddress))
|
||||
of mepc: createThread(inputThread, replEpc, (gPort, gAddress))
|
||||
of mcmdsug: createThread(inputThread, replCmdline,
|
||||
(gPort, "sug \"" & conf.projectFull & "\":" & gAddress))
|
||||
(gPort, "sug \"" & conf.projectFull.string & "\":" & gAddress))
|
||||
of mcmdcon: createThread(inputThread, replCmdline,
|
||||
(gPort, "con \"" & conf.projectFull & "\":" & gAddress))
|
||||
(gPort, "con \"" & conf.projectFull.string & "\":" & gAddress))
|
||||
mainThread(graph)
|
||||
joinThread(inputThread)
|
||||
close(requests)
|
||||
@@ -602,11 +604,12 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
if binaryPath == "":
|
||||
raise newException(IOError,
|
||||
"Cannot find Nim standard library: Nim compiler not in PATH")
|
||||
conf.prefixDir = binaryPath.splitPath().head.parentDir()
|
||||
if not dirExists(conf.prefixDir / "lib"): conf.prefixDir = ""
|
||||
conf.prefixDir = AbsoluteDir binaryPath.splitPath().head.parentDir()
|
||||
if not dirExists(conf.prefixDir / RelativeDir"lib"):
|
||||
conf.prefixDir = AbsoluteDir""
|
||||
|
||||
#msgs.writelnHook = proc (line: string) = log(line)
|
||||
myLog("START " & conf.projectFull)
|
||||
myLog("START " & conf.projectFull.string)
|
||||
|
||||
discard self.loadConfigsAndRunMainCommand(cache, conf)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user