Add ability for rst parser to continue on errors

This commit is contained in:
Joey Yakimowich-Payne 2020-05-08 18:48:44 -06:00
commit 926ae2ec64
5 changed files with 58 additions and 11 deletions

View file

@ -437,6 +437,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf.docSeeSrcUrl = arg conf.docSeeSrcUrl = arg
of "docroot": of "docroot":
conf.docRoot = if arg.len == 0: "@default" else: arg conf.docRoot = if arg.len == 0: "@default" else: arg
of "docignoreparseerrors":
conf.docIgnoreParseErrors = true
of "mainmodule", "m": of "mainmodule", "m":
discard "allow for backwards compatibility, but don't do anything" discard "allow for backwards compatibility, but don't do anything"
of "define", "d": of "define", "d":

View file

@ -146,8 +146,13 @@ proc parseRst(text, filename: string,
rstOptions: RstParseOptions; rstOptions: RstParseOptions;
conf: ConfigRef): PRstNode = conf: ConfigRef): PRstNode =
declareClosures() declareClosures()
var msgHandler: MsgHandler
if conf.docIgnoreParseErrors:
msgHandler = rst.noExceptionMsgHandler
else:
msgHandler = compilerMsgHandler
result = rstParse(text, filename, line, column, hasToc, rstOptions, result = rstParse(text, filename, line, column, hasToc, rstOptions,
docgenFindFile, compilerMsgHandler) docgenFindFile, msgHandler)
proc getOutFile2(conf: ConfigRef; filename: RelativeFile, proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
ext: string, dir: RelativeDir; guessTarget: bool): AbsoluteFile = ext: string, dir: RelativeDir; guessTarget: bool): AbsoluteFile =
@ -170,9 +175,14 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.module = module result.module = module
result.conf = conf result.conf = conf
result.cache = cache result.cache = cache
var msgHandler: MsgHandler
if conf.docIgnoreParseErrors:
msgHandler = rst.noExceptionMsgHandler
else:
msgHandler = defaultMsgHandler
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex), initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
conf.configVars, filename.string, {roSupportRawDirective, roSupportMarkdown}, conf.configVars, filename.string, {roSupportRawDirective, roSupportMarkdown},
docgenFindFile, compilerMsgHandler) docgenFindFile, msgHandler)
if conf.configVars.hasKey("doc.googleAnalytics"): if conf.configVars.hasKey("doc.googleAnalytics"):
result.analytics = """ result.analytics = """

View file

@ -274,6 +274,7 @@ type
docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \ docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`. # The string uses the formatting variables `path` and `line`.
docRoot*: string ## see nim --fullhelp for --docRoot docRoot*: string ## see nim --fullhelp for --docRoot
docIgnoreParseErrors*: bool ## continue parsing docs if errors occur
# the used compiler # the used compiler
cIncludes*: seq[AbsoluteDir] # directories to search for included files cIncludes*: seq[AbsoluteDir] # directories to search for included files

View file

@ -79,6 +79,7 @@ Advanced options:
--docSeeSrcUrl:url activate 'see source' for doc and doc2 commands --docSeeSrcUrl:url activate 'see source' for doc and doc2 commands
(see doc.item.seesrc in config/nimdoc.cfg) (see doc.item.seesrc in config/nimdoc.cfg)
--docInternal also generate documentation for non-exported symbols --docInternal also generate documentation for non-exported symbols
--docIgnoreParseErrors continue parsing docs if rst errors occur
--lineDir:on|off generation of #line directive on|off --lineDir:on|off generation of #line directive on|off
--embedsrc:on|off embeds the original source code as comments --embedsrc:on|off embeds the original source code as comments
in the generated output in the generated output

View file

@ -312,6 +312,14 @@ proc defaultMsgHandler*(filename: string, line, col: int, msgkind: MsgKind,
if mc == mcError: raise newException(EParseError, message) if mc == mcError: raise newException(EParseError, message)
else: writeLine(stdout, message) else: writeLine(stdout, message)
proc noExceptionMsgHandler*(filename: string, line, col: int, msgkind: MsgKind,
arg: string) {.procvar.} =
let mc = msgkind.whichMsgClass
let a = messages[msgkind] % arg
let message = "$1($2, $3) $4: $5" % [filename, $line, $col, $mc, a]
if mc == mcError: writeLine(stderr, message)
else: writeLine(stdout, message)
proc defaultFindFile*(filename: string): string {.procvar.} = proc defaultFindFile*(filename: string): string {.procvar.} =
if existsFile(filename): result = filename if existsFile(filename): result = filename
else: result = "" else: result = ""
@ -755,13 +763,23 @@ proc parseUntil(p: var RstParser, father: PRstNode, postfix: string,
inc(p.idx) inc(p.idx)
if p.tok[p.idx].kind == tkIndent: if p.tok[p.idx].kind == tkIndent:
rstMessage(p, meExpected, postfix, line, col) rstMessage(p, meExpected, postfix, line, col)
add(father, newLeaf(p))
inc(p.idx)
break break
of tkWhite: of tkWhite:
add(father, newRstNode(rnLeaf, " ")) add(father, newRstNode(rnLeaf, " "))
inc(p.idx) inc(p.idx)
else: rstMessage(p, meExpected, postfix, line, col) else:
rstMessage(p, meExpected, postfix, line, col)
add(father, newLeaf(p))
inc(p.idx)
break
proc parseMarkdownCodeblock(p: var RstParser): PRstNode = proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
let backupIndex = p.idx
# skip ```
inc(p.idx)
var args = newRstNode(rnDirArg) var args = newRstNode(rnDirArg)
if p.tok[p.idx].kind == tkWord: if p.tok[p.idx].kind == tkWord:
add(args, newLeaf(p)) add(args, newLeaf(p))
@ -773,7 +791,10 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkEof: of tkEof:
rstMessage(p, meExpected, "```") rstMessage(p, meExpected, "```")
break p.idx = backupIndex
result = newLeaf(p)
inc(p.idx)
return
of tkPunct: of tkPunct:
if p.tok[p.idx].symbol == "```": if p.tok[p.idx].symbol == "```":
inc(p.idx) inc(p.idx)
@ -817,36 +838,47 @@ proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool =
result = true result = true
proc parseInline(p: var RstParser, father: PRstNode) = proc parseInline(p: var RstParser, father: PRstNode) =
template addOrBackup(endTok) =
let prevTok = if (p.idx-1) < len(p.tok): p.tok[p.idx-1].symbol else: ""
if p.idx >= len(p.tok) - 1 and prevTok != endTok:
# we failed, so
p.idx = backupIndex
add(father, newLeaf(p))
inc(p.idx)
else:
add(father, n)
let backupIndex = p.idx
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkPunct: of tkPunct:
if isInlineMarkupStart(p, "***"): if isInlineMarkupStart(p, "***"):
var n = newRstNode(rnTripleEmphasis) var n = newRstNode(rnTripleEmphasis)
parseUntil(p, n, "***", true) parseUntil(p, n, "***", true)
add(father, n) addOrBackup("***")
elif isInlineMarkupStart(p, "**"): elif isInlineMarkupStart(p, "**"):
var n = newRstNode(rnStrongEmphasis) var n = newRstNode(rnStrongEmphasis)
parseUntil(p, n, "**", true) parseUntil(p, n, "**", true)
add(father, n) addOrBackup("**")
elif isInlineMarkupStart(p, "*"): elif isInlineMarkupStart(p, "*"):
var n = newRstNode(rnEmphasis) var n = newRstNode(rnEmphasis)
parseUntil(p, n, "*", true) parseUntil(p, n, "*", true)
add(father, n) addOrBackup("*")
elif roSupportMarkdown in p.s.options and p.tok[p.idx].symbol == "```": elif roSupportMarkdown in p.s.options and p.tok[p.idx].symbol == "```":
inc(p.idx)
add(father, parseMarkdownCodeblock(p)) add(father, parseMarkdownCodeblock(p))
elif isInlineMarkupStart(p, "``"): elif isInlineMarkupStart(p, "``"):
var n = newRstNode(rnInlineLiteral) var n = newRstNode(rnInlineLiteral)
parseUntil(p, n, "``", false) parseUntil(p, n, "``", false)
add(father, n) addOrBackup("``")
elif isInlineMarkupStart(p, "`"): elif isInlineMarkupStart(p, "`"):
var n = newRstNode(rnInterpretedText) var n = newRstNode(rnInterpretedText)
parseUntil(p, n, "`", true) parseUntil(p, n, "`", true)
n = parsePostfix(p, n) n = parsePostfix(p, n)
add(father, n) addOrBackup("`")
elif isInlineMarkupStart(p, "|"): elif isInlineMarkupStart(p, "|"):
var n = newRstNode(rnSubstitutionReferences) var n = newRstNode(rnSubstitutionReferences)
parseUntil(p, n, "|", false) parseUntil(p, n, "|", false)
add(father, n) addOrBackup("|")
elif roSupportMarkdown in p.s.options and elif roSupportMarkdown in p.s.options and
p.tok[p.idx].symbol == "[" and p.tok[p.idx+1].symbol != "[" and p.tok[p.idx].symbol == "[" and p.tok[p.idx+1].symbol != "[" and
parseMarkdownLink(p, father): parseMarkdownLink(p, father):
@ -1773,6 +1805,7 @@ proc parseDotDot(p: var RstParser): PRstNode =
b = dirImage(p) b = dirImage(p)
else: else:
rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol) rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol)
inc(p.idx)
setSub(p, addNodes(a), b) setSub(p, addNodes(a), b)
elif match(p, p.idx, " ["): elif match(p, p.idx, " ["):
# footnotes, citations # footnotes, citations