compiler refactoring; use typesafe path handing; docgen: render symbols between modules

This commit is contained in:
Andreas Rumpf 2018-09-07 01:53:09 +02:00 • committed by Araq
commit 86556ebfdb
44 changed files with 817 additions and 505 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View 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

View file

@ -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 =

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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, "")

View file

@ -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)

View file

@ -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)

View file

@ -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])

View file

@ -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)

View file

@ -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)

View file

@ -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

View 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:

View file

@ -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)

View file

@ -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)

Some files were not shown because too many files have changed in this diff Show more