summary refs log tree commit diff stats
path: root/compiler/docgen.nim
diff options
context:
space:
mode:
authorawr1 <41453959+awr1@users.noreply.github.com>2018-09-04 16:33:52 -0500
committerGitHub <noreply@github.com>2018-09-04 16:33:52 -0500
commiteb668003bf35671d7358e5f54e05820c0f4aef3d (patch)
treee5c5d6315f8ba4a5dd647bf67a4d0afb609916e7 /compiler/docgen.nim
parent89ad1cc9b18db8320e5b170ee45888cf79d52001 (diff)
parent4aba2981dd47672744191bd17b39bb149f494637 (diff)
downloadNim-eb668003bf35671d7358e5f54e05820c0f4aef3d.tar.gz
Merge branch 'devel' into experimentalize-reorder
Diffstat (limited to 'compiler/docgen.nim')
-rw-r--r--compiler/docgen.nim61
1 files changed, 55 insertions, 6 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index b35452365..23d156e05 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -14,7 +14,7 @@
 import
   ast, strutils, strtabs, options, msgs, os, ropes, idents,
   wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
-  packages/docutils/rst, packages/docutils/rstgen, times,
+  packages/docutils/rst, packages/docutils/rstgen,
   packages/docutils/highlite, sempass2, json, xmltree, cgi,
   typesrenderer, astalgo, modulepaths, lineinfos, sequtils
 
@@ -31,6 +31,7 @@ type
     isPureRst: bool
     conf*: ConfigRef
     cache*: IdentCache
+    exampleCounter: int
 
   PDoc* = ref TDocumentor ## Alias to type less.
 
@@ -284,11 +285,56 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
       dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
             [rope(esc(d.target, literal))])
 
+proc testExample(d: PDoc; ex: PNode) =
+  if d.conf.errorCounter > 0: return
+  let outputDir = d.conf.getNimcacheDir / "runnableExamples"
+  createDir(outputDir)
+  inc d.exampleCounter
+  let outp = outputDir / extractFilename(d.filename.changeFileExt"" &
+      "_examples" & $d.exampleCounter & ".nim")
+  #let nimcache = outp.changeFileExt"" & "_nimcache"
+  renderModule(ex, d.filename, outp, 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
+  else:
+    # keep generated source file `outp` to allow inspection.
+    rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp])
+    removeFile(outp.changeFileExt(ExeExt))
+
+proc extractImports(n: PNode; result: PNode) =
+  if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
+    result.add copyTree(n)
+    n.kind = nkEmpty
+    return
+  for i in 0..<n.safeLen: extractImports(n[i], result)
+
+proc prepareExamples(d: PDoc; n: PNode) =
+  var runnableExamples = newTree(nkStmtList,
+      newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
+  runnableExamples.info = n.info
+  let imports = newTree(nkStmtList)
+  var savedLastSon = copyTree n.lastSon
+  extractImports(savedLastSon, imports)
+  for imp in imports: runnableExamples.add imp
+  runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
+  testExample(d, runnableExamples)
+
+proc isRunnableExample(n: PNode): bool =
+  # Templates and generics don't perform symbol lookups.
+  result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
+    n.kind == nkIdent and n.ident.s == "runnableExamples"
+
 proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
   case n.kind
   of nkCallKinds:
-    if n[0].kind == nkSym and n[0].sym.magic == mRunnableExamples and
+    if isRunnableExample(n[0]) and
         n.len >= 2 and n.lastSon.kind == nkStmtList:
+      prepareExamples(d, n)
       dispA(d.conf, dest, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
           "\n\\textbf{$1}\n", [rope"Examples:"])
       inc d.listingCounter
@@ -627,6 +673,10 @@ proc generateDoc*(d: PDoc, n: PNode) =
   of nkImportStmt:
     for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
   of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
+  of nkCallKinds:
+    var comm: Rope = nil
+    getAllRunnableExamples(d, n, comm)
+    if comm > nil: add(d.modDesc, comm)
   else: discard
 
 proc add(d: PDoc; j: JsonNode) =
@@ -787,14 +837,13 @@ proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
 
 proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
   var content = genOutFile(d)
-  var success = true
   if optStdout in d.conf.globalOptions:
     writeRope(stdout, content)
   else:
     let outfile = getOutFile2(d.conf, filename, outExt, "htmldocs")
-    success = writeRope(content, outfile)
-  if not success:
-    rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, filename)
+    createDir(outfile.parentDir)
+    if not writeRope(content, outfile):
+      rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, outfile)
 
 proc writeOutputJson*(d: PDoc, filename, outExt: string,
                       useWarning = false) =