runnableExample: put each example to its own file; fixes #7285

This commit is contained in:
Andreas Rumpf 2018-09-03 00:40:56 +02:00
commit 0d68ef9f11
2 changed files with 27 additions and 30 deletions

View file

@ -31,7 +31,7 @@ type
isPureRst: bool isPureRst: bool
conf*: ConfigRef conf*: ConfigRef
cache*: IdentCache cache*: IdentCache
runnableExamples*: PNode exampleCounter: int
PDoc* = ref TDocumentor ## Alias to type less. PDoc* = ref TDocumentor ## Alias to type less.
@ -285,29 +285,26 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[rope(esc(d.target, literal))]) [rope(esc(d.target, literal))])
proc testExamples*(d: PDoc) = proc testExample(d: PDoc; ex: PNode) =
if d.runnableExamples == nil or d.conf.errorCounter > 0: return if d.conf.errorCounter > 0: return
let outputDir = d.conf.getNimcacheDir / "runnableExamples" let outputDir = d.conf.getNimcacheDir / "runnableExamples"
createDir(outputDir) createDir(outputDir)
let inp = toFullPath(d.conf, d.runnableExamples.info) inc d.exampleCounter
let outp = outputDir / extractFilename(inp.changeFileExt"" & "_examples.nim") let outp = outputDir / extractFilename(d.filename.changeFileExt"" &
let nimcache = outp.changeFileExt"" & "_nimcache" "_examples" & $d.exampleCounter & ".nim")
renderModule(d.runnableExamples, inp, outp, conf = d.conf) #let nimcache = outp.changeFileExt"" & "_nimcache"
renderModule(ex, d.filename, outp, conf = d.conf)
let backend = if isDefined(d.conf, "js"): "js" let backend = if isDefined(d.conf, "js"): "js"
elif isDefined(d.conf, "cpp"): "cpp" elif isDefined(d.conf, "cpp"): "cpp"
elif isDefined(d.conf, "objc"): "objc" elif isDefined(d.conf, "objc"): "objc"
else: "c" else: "c"
if os.execShellCmd(os.getAppFilename() & " " & backend & if os.execShellCmd(os.getAppFilename() & " " & backend &
" --nimcache:" & nimcache & " -r " & outp) != 0: " --nimcache:" & outputDir & " -r " & outp) != 0:
quit "[Examples] failed: see " & outp quit "[Examples] failed: see " & outp
else: else:
# keep generated source file `outp` to allow inspection. # keep generated source file `outp` to allow inspection.
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp]) rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp])
removeFile(outp.changeFileExt(ExeExt)) removeFile(outp.changeFileExt(ExeExt))
try:
removeDir(nimcache)
except OSError:
discard
proc extractImports(n: PNode; result: PNode) = proc extractImports(n: PNode; result: PNode) =
if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}: if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
@ -317,16 +314,15 @@ proc extractImports(n: PNode; result: PNode) =
for i in 0..<n.safeLen: extractImports(n[i], result) for i in 0..<n.safeLen: extractImports(n[i], result)
proc prepareExamples(d: PDoc; n: PNode) = proc prepareExamples(d: PDoc; n: PNode) =
let inp = toFullPath(d.conf, n.info) var runnableExamples = newTree(nkStmtList,
if d.runnableExamples == nil: newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
d.runnableExamples = newTree(nkStmtList, runnableExamples.info = n.info
newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp))))
d.runnableExamples.info = n.info
let imports = newTree(nkStmtList) let imports = newTree(nkStmtList)
var savedLastSon = copyTree n.lastSon var savedLastSon = copyTree n.lastSon
extractImports(savedLastSon, imports) extractImports(savedLastSon, imports)
for imp in imports: d.runnableExamples.add imp for imp in imports: runnableExamples.add imp
d.runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon) runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
testExample(d, runnableExamples)
proc isRunnableExample(n: PNode): bool = proc isRunnableExample(n: PNode): bool =
# Templates and generics don't perform symbol lookups. # Templates and generics don't perform symbol lookups.
@ -873,7 +869,6 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
generateDoc(d, ast) generateDoc(d, ast)
writeOutput(d, conf.projectFull, HtmlExt) writeOutput(d, conf.projectFull, HtmlExt)
generateIndex(d) generateIndex(d)
testExamples(d)
proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string) = proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string) =
var filen = addFileExt(filename, "txt") var filen = addFileExt(filename, "txt")
@ -908,7 +903,6 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string)
d.modDesc = rope(modDesc) d.modDesc = rope(modDesc)
writeOutput(d, filename, outExt) writeOutput(d, filename, outExt)
generateIndex(d) generateIndex(d)
testExamples(d)
proc commandRst2Html*(cache: IdentCache, conf: ConfigRef) = proc commandRst2Html*(cache: IdentCache, conf: ConfigRef) =
commandRstAux(cache, conf, conf.projectFull, HtmlExt) commandRstAux(cache, conf, conf.projectFull, HtmlExt)
@ -932,7 +926,6 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
let filename = getOutFile(conf, conf.projectFull, JsonExt) let filename = getOutFile(conf, conf.projectFull, JsonExt)
if not writeRope(content, filename): if not writeRope(content, filename):
rawMessage(conf, errCannotOpenFile, filename) rawMessage(conf, errCannotOpenFile, filename)
testExamples(d)
proc commandTags*(cache: IdentCache, conf: ConfigRef) = proc commandTags*(cache: IdentCache, conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx, cache, conf) var ast = parseFile(conf.projectMainIdx, cache, conf)

View file

@ -21,42 +21,46 @@ type
module: PSym module: PSym
PGen = ref TGen PGen = ref TGen
template shouldProcess(g): bool =
(g.module.owner.id == g.doc.conf.mainPackageId and optWholeProject in g.doc.conf.globalOptions) or
sfMainModule in g.module.flags
template closeImpl(body: untyped) {.dirty.} = template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p) var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags let useWarning = sfMainModule notin g.module.flags
#echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId #echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
if (g.module.owner.id == g.doc.conf.mainPackageId and optWholeProject in g.doc.conf.globalOptions) or if shouldProcess(g):
sfMainModule in g.module.flags:
body body
try: try:
generateIndex(g.doc) generateIndex(g.doc)
testExamples(g.doc)
except IOError: except IOError:
discard discard
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl: closeImpl:
writeOutput(g.doc, toFilename(graph.config, FileIndex g.module.position), HtmlExt, useWarning) writeOutput(g.doc, toFullPath(graph.config, FileIndex g.module.position), HtmlExt, useWarning)
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl: closeImpl:
writeOutputJson(g.doc, toFilename(graph.config, FileIndex g.module.position), ".json", useWarning) writeOutputJson(g.doc, toFullPath(graph.config, FileIndex g.module.position), ".json", useWarning)
proc processNode(c: PPassContext, n: PNode): PNode = proc processNode(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) var g = PGen(c)
if shouldProcess(g):
generateDoc(g.doc, n) generateDoc(g.doc, n)
proc processNodeJson(c: PPassContext, n: PNode): PNode = proc processNodeJson(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) var g = PGen(c)
if shouldProcess(g):
generateJson(g.doc, n) generateJson(g.doc, n)
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module
var d = newDocumentor(toFilename(graph.config, FileIndex module.position), graph.cache, graph.config) var d = newDocumentor(toFullPath(graph.config, FileIndex module.position), graph.cache, graph.config)
d.hasToc = true d.hasToc = true
g.doc = d g.doc = d
result = g result = g