added system.getStackTrace; docgen refactoring (incomplete)

This commit is contained in:
Araq 2012-05-06 01:16:36 +02:00
commit c323ec0155
13 changed files with 744 additions and 509 deletions

View file

@ -13,11 +13,14 @@
import import
ast, astalgo, strutils, hashes, options, nversion, msgs, os, ropes, idents, ast, astalgo, strutils, hashes, options, nversion, msgs, os, ropes, idents,
wordrecg, math, syntaxes, renderer, lexer, rst, times, highlite, importer wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
importer
proc CommandDoc*() proc CommandDoc*()
proc CommandRst2Html*() proc CommandRst2Html*()
proc CommandRst2TeX*() proc CommandRst2TeX*()
#proc CommandBuildIndex*()
# implementation # implementation
type type
@ -29,9 +32,9 @@ type
TMetaEnum = enum TMetaEnum = enum
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
TDocumentor {.final.} = object # contains a module's documentation TDocumentor {.final.} = object # contains a module's documentation
target: TOutputTarget
options: TRstParseOptions options: TRstParseOptions
filename*: string # filename of the source file; without extension filename*: string # filename of the source file; without extension
basedir*: string # base directory (where to put the documentation)
modDesc*: PRope # module description modDesc*: PRope # module description
id*: int # for generating IDs id*: int # for generating IDs
splitAfter*: int # split too long entries in the TOC splitAfter*: int # split too long entries in the TOC
@ -40,13 +43,10 @@ type
toc*, section*: TSections toc*, section*: TSections
indexFile*, theIndex*: PRstNode indexFile*, theIndex*: PRstNode
indexValFilename*: string indexValFilename*: string
indent*, verbatim*: int # for code generation
meta*: array[TMetaEnum, PRope] meta*: array[TMetaEnum, PRope]
PDoc = ref TDocumentor PDoc = ref TDocumentor
var splitter: string = "<wbr />"
proc findIndexNode(n: PRstNode): PRstNode = proc findIndexNode(n: PRstNode): PRstNode =
if n == nil: if n == nil:
result = nil result = nil
@ -59,10 +59,31 @@ proc findIndexNode(n: PRstNode): PRstNode =
result = result.sons[0] result = result.sons[0]
else: else:
result = nil result = nil
for i in countup(0, rsonsLen(n) - 1): for i in countup(0, len(n) - 1):
result = findIndexNode(n.sons[i]) result = findIndexNode(n.sons[i])
if result != nil: return if result != nil: return
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.TMsgKind, arg: string) {.procvar.} =
# translate msg kind:
var k: msgs.TMsgKind
case msgKind
of meCannotOpenFile: k = errCannotOpenFile
of meExpected: k = errXExpected
of meGridTableNotImplemented: k = errGridTableNotImplemented
of meNewSectionExpected: k = errNewSectionExpected
of meGeneralParseError: k = errGeneralParseError
of meInvalidDirective: k = errInvalidDirectiveX
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
GlobalError(newLineInfo(filename, line, col), k, arg)
proc parseRst(text, filename: string,
line, column: int, hasToc: var bool,
rstOptions: TRstParseOptions): PRstNode =
result = rstParse(text, filename, line, column, hasToc, rstOptions,
options.FindFile, compilerMsgHandler)
proc initIndexFile(d: PDoc) = proc initIndexFile(d: PDoc) =
var var
h: PRstNode h: PRstNode
@ -71,7 +92,7 @@ proc initIndexFile(d: PDoc) =
gIndexFile = addFileExt(gIndexFile, "txt") gIndexFile = addFileExt(gIndexFile, "txt")
d.indexValFilename = changeFileExt(extractFilename(d.filename), HtmlExt) d.indexValFilename = changeFileExt(extractFilename(d.filename), HtmlExt)
if ExistsFile(gIndexFile): if ExistsFile(gIndexFile):
d.indexFile = rstParse(readFile(gIndexFile), gIndexFile, 0, 1, d.indexFile = parseRst(readFile(gIndexFile), gIndexFile, 0, 1,
dummyHasToc, {roSupportRawDirective}) dummyHasToc, {roSupportRawDirective})
d.theIndex = findIndexNode(d.indexFile) d.theIndex = findIndexNode(d.indexFile)
if (d.theIndex == nil) or (d.theIndex.kind != rnDefList): if (d.theIndex == nil) or (d.theIndex.kind != rnDefList):
@ -81,17 +102,19 @@ proc initIndexFile(d: PDoc) =
d.indexFile = newRstNode(rnInner) d.indexFile = newRstNode(rnInner)
h = newRstNode(rnOverline) h = newRstNode(rnOverline)
h.level = 1 h.level = 1
addSon(h, newRstNode(rnLeaf, "Index")) add(h, newRstNode(rnLeaf, "Index"))
addSon(d.indexFile, h) add(d.indexFile, h)
h = newRstNode(rnIndex) h = newRstNode(rnIndex)
addSon(h, nil) # no argument add(h, nil) # no argument
addSon(h, nil) # no options add(h, nil) # no options
d.theIndex = newRstNode(rnDefList) d.theIndex = newRstNode(rnDefList)
addSon(h, d.theIndex) add(h, d.theIndex)
addSon(d.indexFile, h) add(d.indexFile, h)
proc newDocumentor(filename: string): PDoc = proc newDocumentor(filename: string): PDoc =
new(result) new(result)
if gCmd != cmdRst2Tex: result.target = outHtml
else: result.target = outLatex
result.tocPart = @[] result.tocPart = @[]
result.filename = filename result.filename = filename
result.id = 100 result.id = 100
@ -159,72 +182,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
if (frmt[i] != '$'): inc(i) if (frmt[i] != '$'): inc(i)
else: break else: break
if i - 1 >= start: app(result, substr(frmt, start, i - 1)) if i - 1 >= start: app(result, substr(frmt, start, i - 1))
proc addXmlChar(dest: var string, c: Char) =
case c
of '&': add(dest, "&amp;")
of '<': add(dest, "&lt;")
of '>': add(dest, "&gt;")
of '\"': add(dest, "&quot;")
else: add(dest, c)
proc addRtfChar(dest: var string, c: Char) =
case c
of '{': add(dest, "\\{")
of '}': add(dest, "\\}")
of '\\': add(dest, "\\\\")
else: add(dest, c)
proc addTexChar(dest: var string, c: Char) =
case c
of '_': add(dest, "\\_")
of '{': add(dest, "\\symbol{123}")
of '}': add(dest, "\\symbol{125}")
of '[': add(dest, "\\symbol{91}")
of ']': add(dest, "\\symbol{93}")
of '\\': add(dest, "\\symbol{92}")
of '$': add(dest, "\\$")
of '&': add(dest, "\\&")
of '#': add(dest, "\\#")
of '%': add(dest, "\\%")
of '~': add(dest, "\\symbol{126}")
of '@': add(dest, "\\symbol{64}")
of '^': add(dest, "\\symbol{94}")
of '`': add(dest, "\\symbol{96}")
else: add(dest, c)
proc escChar(dest: var string, c: Char) =
if gCmd != cmdRst2Tex: addXmlChar(dest, c)
else: addTexChar(dest, c)
proc nextSplitPoint(s: string, start: int): int =
result = start
while result < len(s) + 0:
case s[result]
of '_': return
of 'a'..'z':
if result + 1 < len(s) + 0:
if s[result + 1] in {'A'..'Z'}: return
else: nil
inc(result)
dec(result) # last valid index
proc esc(s: string, splitAfter: int = - 1): string =
result = ""
if splitAfter >= 0:
var partLen = 0
var j = 0
while j < len(s):
var k = nextSplitPoint(s, j)
if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
partLen = 0
add(result, splitter)
for i in countup(j, k): escChar(result, s[i])
inc(partLen, k - j + 1)
j = k + 1
else:
for i in countup(0, len(s) + 0 - 1): escChar(result, s[i])
proc disp(xml, tex: string): string = proc disp(xml, tex: string): string =
if gCmd != cmdRst2Tex: result = xml if gCmd != cmdRst2Tex: result = xml
else: result = tex else: result = tex
@ -241,17 +199,17 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope
proc renderAux(d: PDoc, n: PRstNode, outer: string = "$1"): PRope = proc renderAux(d: PDoc, n: PRstNode, outer: string = "$1"): PRope =
result = nil result = nil
for i in countup(0, rsonsLen(n) - 1): app(result, renderRstToOut(d, n.sons[i])) for i in countup(0, len(n) - 1): app(result, renderRstToOut(d, n.sons[i]))
result = ropef(outer, [result]) result = ropef(outer, [result])
proc setIndexForSourceTerm(d: PDoc, name: PRstNode, id: int) = proc setIndexForSourceTerm(d: PDoc, name: PRstNode, id: int) =
if d.theIndex == nil: return if d.theIndex == nil: return
var h = newRstNode(rnHyperlink) var h = newRstNode(rnHyperlink)
var a = newRstNode(rnLeaf, d.indexValFilename & disp("#", "") & $id) var a = newRstNode(rnLeaf, d.indexValFilename & disp("#", "") & $id)
addSon(h, a) add(h, a)
addSon(h, a) add(h, a)
a = newRstNode(rnIdx) a = newRstNode(rnIdx)
addSon(a, name) add(a, name)
setIndexPair(d.theIndex, a, h) setIndexPair(d.theIndex, a, h)
proc renderIndexTerm(d: PDoc, n: PRstNode): PRope = proc renderIndexTerm(d: PDoc, n: PRstNode): PRope =
@ -260,14 +218,14 @@ proc renderIndexTerm(d: PDoc, n: PRstNode): PRope =
[toRope(d.id), renderAux(d, n)]) [toRope(d.id), renderAux(d, n)])
var h = newRstNode(rnHyperlink) var h = newRstNode(rnHyperlink)
var a = newRstNode(rnLeaf, d.indexValFilename & disp("#", "") & $d.id) var a = newRstNode(rnLeaf, d.indexValFilename & disp("#", "") & $d.id)
addSon(h, a) add(h, a)
addSon(h, a) add(h, a)
setIndexPair(d.theIndex, n, h) setIndexPair(d.theIndex, n, h)
proc genComment(d: PDoc, n: PNode): PRope = proc genComment(d: PDoc, n: PNode): PRope =
var dummyHasToc: bool var dummyHasToc: bool
if n.comment != nil and startsWith(n.comment, "##"): if n.comment != nil and startsWith(n.comment, "##"):
result = renderRstToOut(d, rstParse(n.comment, toFilename(n.info), result = renderRstToOut(d, parseRst(n.comment, toFilename(n.info),
toLineNumber(n.info), toColumn(n.info), toLineNumber(n.info), toColumn(n.info),
dummyHasToc, dummyHasToc,
d.options + {roSkipPounds})) d.options + {roSkipPounds}))
@ -294,16 +252,16 @@ proc isVisible(n: PNode): bool =
elif n.kind == nkPragmaExpr: elif n.kind == nkPragmaExpr:
result = isVisible(n.sons[0]) result = isVisible(n.sons[0])
proc getName(n: PNode, splitAfter: int = - 1): string = proc getName(d: PDoc, n: PNode, splitAfter: int = - 1): string =
case n.kind case n.kind
of nkPostfix: result = getName(n.sons[1], splitAfter) of nkPostfix: result = getName(d, n.sons[1], splitAfter)
of nkPragmaExpr: result = getName(n.sons[0], splitAfter) of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
of nkSym: result = esc(n.sym.name.s, splitAfter) of nkSym: result = esc(d.target, n.sym.name.s, splitAfter)
of nkIdent: result = esc(n.ident.s, splitAfter) of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
of nkAccQuoted: of nkAccQuoted:
result = esc("`") result = esc(d.target, "`")
for i in 0.. <n.len: result.add(getName(n[i], splitAfter)) for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
result.add esc("`") result.add esc(d.target, "`")
else: else:
internalError(n.info, "getName()") internalError(n.info, "getName()")
result = "" result = ""
@ -323,7 +281,7 @@ proc getRstName(n: PNode): PRstNode =
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
if not isVisible(nameNode): return if not isVisible(nameNode): return
var name = toRope(getName(nameNode)) var name = toRope(getName(d, nameNode))
var result: PRope = nil var result: PRope = nil
var literal = "" var literal = ""
var kind = tkEof var kind = tkEof
@ -338,28 +296,28 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
break break
of tkComment: of tkComment:
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}", dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
[toRope(esc(literal))]) [toRope(esc(d.target, literal))])
of tokKeywordLow..tokKeywordHigh: of tokKeywordLow..tokKeywordHigh:
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}", dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
[toRope(literal)]) [toRope(literal)])
of tkOpr: of tkOpr:
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}", dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
[toRope(esc(literal))]) [toRope(esc(d.target, literal))])
of tkStrLit..tkTripleStrLit: of tkStrLit..tkTripleStrLit:
dispA(result, "<span class=\"StringLit\">$1</span>", dispA(result, "<span class=\"StringLit\">$1</span>",
"\\spanStringLit{$1}", [toRope(esc(literal))]) "\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
of tkCharLit: of tkCharLit:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}", dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[toRope(esc(literal))]) [toRope(esc(d.target, literal))])
of tkIntLit..tkInt64Lit: of tkIntLit..tkInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>", dispA(result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [toRope(esc(literal))]) "\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
of tkFloatLit..tkFloat64Lit: of tkFloatLit..tkFloat64Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>", dispA(result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [toRope(esc(literal))]) "\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
of tkSymbol: of tkSymbol:
dispA(result, "<span class=\"Identifier\">$1</span>", dispA(result, "<span class=\"Identifier\">$1</span>",
"\\spanIdentifier{$1}", [toRope(esc(literal))]) "\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
of tkInd, tkSad, tkDed, tkSpaces, tkInvalid: of tkInd, tkSad, tkDed, tkSpaces, tkInvalid:
app(result, literal) app(result, literal)
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi, of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
@ -368,19 +326,19 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
tkAccent, tkColonColon, tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[toRope(esc(literal))]) [toRope(esc(d.target, literal))])
inc(d.id) inc(d.id)
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
["name", "header", "desc", "itemID"], ["name", "header", "desc", "itemID"],
[name, result, comm, toRope(d.id)])) [name, result, comm, toRope(d.id)]))
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"), app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
["name", "header", "desc", "itemID"], [ ["name", "header", "desc", "itemID"], [
toRope(getName(nameNode, d.splitAfter)), result, comm, toRope(d.id)])) toRope(getName(d, nameNode, d.splitAfter)), result, comm, toRope(d.id)]))
setIndexForSourceTerm(d, getRstName(nameNode), d.id) setIndexForSourceTerm(d, getRstName(nameNode), d.id)
proc renderHeadline(d: PDoc, n: PRstNode): PRope = proc renderHeadline(d: PDoc, n: PRstNode): PRope =
result = nil result = nil
for i in countup(0, rsonsLen(n) - 1): app(result, renderRstToOut(d, n.sons[i])) for i in countup(0, len(n) - 1): app(result, renderRstToOut(d, n.sons[i]))
var refname = toRope(rstnodeToRefname(n)) var refname = toRope(rstnodeToRefname(n))
if d.hasToc: if d.hasToc:
var length = len(d.tocPart) var length = len(d.tocPart)
@ -400,7 +358,7 @@ proc renderHeadline(d: PDoc, n: PRstNode): PRope =
proc renderOverline(d: PDoc, n: PRstNode): PRope = proc renderOverline(d: PDoc, n: PRstNode): PRope =
var t: PRope = nil var t: PRope = nil
for i in countup(0, rsonsLen(n) - 1): app(t, renderRstToOut(d, n.sons[i])) for i in countup(0, len(n) - 1): app(t, renderRstToOut(d, n.sons[i]))
result = nil result = nil
if d.meta[metaTitle] == nil: if d.meta[metaTitle] == nil:
d.meta[metaTitle] = t d.meta[metaTitle] = t
@ -411,123 +369,7 @@ proc renderOverline(d: PDoc, n: PRstNode): PRope =
"\\rstov$4{$3}\\label{$2}$n", [toRope(n.level), "\\rstov$4{$3}\\label{$2}$n", [toRope(n.level),
toRope(rstnodeToRefname(n)), t, toRope($chr(n.level - 1 + ord('A')))]) toRope(rstnodeToRefname(n)), t, toRope($chr(n.level - 1 + ord('A')))])
proc renderRstToRst(d: PDoc, n: PRstNode): PRope
proc renderRstSons(d: PDoc, n: PRstNode): PRope =
for i in countup(0, rsonsLen(n) - 1):
app(result, renderRstToRst(d, n.sons[i]))
proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
# this is needed for the index generation; it may also be useful for
# debugging, but most code is already debugged...
const
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
result = nil
if n == nil: return
var ind = toRope(repeatChar(d.indent))
case n.kind
of rnInner:
result = renderRstSons(d, n)
of rnHeadline:
result = renderRstSons(d, n)
var L = ropeLen(result)
result = ropef("$n$1$2$n$1$3",
[ind, result, toRope(repeatChar(L, lvlToChar[n.level]))])
of rnOverline:
result = renderRstSons(d, n)
var L = ropeLen(result)
result = ropef("$n$1$3$n$1$2$n$1$3",
[ind, result, toRope(repeatChar(L, lvlToChar[n.level]))])
of rnTransition:
result = ropef("$n$n$1$2$n$n", [ind, toRope(repeatChar(78-d.indent, '-'))])
of rnParagraph:
result = renderRstSons(d, n)
result = ropef("$n$n$1$2", [ind, result])
of rnBulletItem:
inc(d.indent, 2)
result = renderRstSons(d, n)
if result != nil: result = ropef("$n$1* $2", [ind, result])
dec(d.indent, 2)
of rnEnumItem:
inc(d.indent, 4)
result = renderRstSons(d, n)
if result != nil: result = ropef("$n$1(#) $2", [ind, result])
dec(d.indent, 4)
of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
result = renderRstSons(d, n)
of rnDefName:
result = renderRstSons(d, n)
result = ropef("$n$n$1$2", [ind, result])
of rnDefBody:
inc(d.indent, 2)
result = renderRstSons(d, n)
if n.sons[0].kind != rnBulletList: result = ropef("$n$1 $2", [ind, result])
dec(d.indent, 2)
of rnField:
result = renderRstToRst(d, n.sons[0])
var L = max(ropeLen(result) + 3, 30)
inc(d.indent, L)
result = ropef("$n$1:$2:$3$4", [ind, result, toRope(
repeatChar(L - ropeLen(result) - 2)), renderRstToRst(d, n.sons[1])])
dec(d.indent, L)
of rnLineBlockItem:
result = renderRstSons(d, n)
result = ropef("$n$1| $2", [ind, result])
of rnBlockQuote:
inc(d.indent, 2)
result = renderRstSons(d, n)
dec(d.indent, 2)
of rnRef:
result = renderRstSons(d, n)
result = ropef("`$1`_", [result])
of rnHyperlink:
result = ropef("`$1 <$2>`_",
[renderRstToRst(d, n.sons[0]), renderRstToRst(d, n.sons[1])])
of rnGeneralRole:
result = renderRstToRst(d, n.sons[0])
result = ropef("`$1`:$2:", [result, renderRstToRst(d, n.sons[1])])
of rnSub:
result = renderRstSons(d, n)
result = ropef("`$1`:sub:", [result])
of rnSup:
result = renderRstSons(d, n)
result = ropef("`$1`:sup:", [result])
of rnIdx:
result = renderRstSons(d, n)
result = ropef("`$1`:idx:", [result])
of rnEmphasis:
result = renderRstSons(d, n)
result = ropef("*$1*", [result])
of rnStrongEmphasis:
result = renderRstSons(d, n)
result = ropef("**$1**", [result])
of rnTripleEmphasis:
result = renderRstSons(d, n)
result = ropef("***$1***", [result])
of rnInterpretedText:
result = renderRstSons(d, n)
result = ropef("`$1`", [result])
of rnInlineLiteral:
inc(d.verbatim)
result = renderRstSons(d, n)
result = ropef("``$1``", [result])
dec(d.verbatim)
of rnSmiley:
result = toRope(n.text)
of rnLeaf:
if (d.verbatim == 0) and (n.text == "\\"):
result = toRope("\\\\") # XXX: escape more special characters!
else:
result = toRope(n.text)
of rnIndex:
inc(d.indent, 3)
if n.sons[2] != nil: result = renderRstSons(d, n.sons[2])
dec(d.indent, 3)
result = ropef("$n$n$1.. index::$n$2", [ind, result])
of rnContents:
result = ropef("$n$n$1.. contents::", [ind])
else: rawMessage(errCannotRenderX, $n.kind)
proc renderTocEntry(d: PDoc, e: TTocEntry): PRope = proc renderTocEntry(d: PDoc, e: TTocEntry): PRope =
result = dispF( result = dispF(
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>$n", "<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>$n",
@ -537,10 +379,10 @@ proc renderTocEntries(d: PDoc, j: var int, lvl: int): PRope =
result = nil result = nil
while j <= high(d.tocPart): while j <= high(d.tocPart):
var a = abs(d.tocPart[j].n.level) var a = abs(d.tocPart[j].n.level)
if (a == lvl): if a == lvl:
app(result, renderTocEntry(d, d.tocPart[j])) app(result, renderTocEntry(d, d.tocPart[j]))
inc(j) inc(j)
elif (a > lvl): elif a > lvl:
app(result, renderTocEntries(d, j, a)) app(result, renderTocEntries(d, j, a))
else: else:
break break
@ -566,7 +408,7 @@ proc renderImage(d: PDoc, n: PRstNode): PRope =
if options != nil: options = dispF("$1", "[$1]", [options]) if options != nil: options = dispF("$1", "[$1]", [options])
result = dispF("<img src=\"$1\"$2 />", "\\includegraphics$2{$1}", result = dispF("<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
[toRope(getArgument(n)), options]) [toRope(getArgument(n)), options])
if rsonsLen(n) >= 3: app(result, renderRstToOut(d, n.sons[2])) if len(n) >= 3: app(result, renderRstToOut(d, n.sons[2]))
proc renderSmiley(d: PDoc, n: PRstNode): PRope = proc renderSmiley(d: PDoc, n: PRstNode): PRope =
result = dispF( result = dispF(
@ -596,13 +438,13 @@ proc renderCodeBlock(d: PDoc, n: PRstNode): PRope =
case g.kind case g.kind
of gtEof: break of gtEof: break
of gtNone, gtWhitespace: of gtNone, gtWhitespace:
app(result, substr(m.text, g.start + 0, g.length + g.start - 1)) app(result, substr(m.text, g.start, g.length + g.start - 1))
else: else:
dispA(result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [ dispA(result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
toRope(esc(substr(m.text, g.start + 0, g.length + g.start - 1))), toRope(esc(d.target, substr(m.text, g.start, g.length+g.start-1))),
toRope(tokenClassToStr[g.kind])]) toRope(tokenClassToStr[g.kind])])
deinitGeneralTokenizer(g) deinitGeneralTokenizer(g)
if result != nil: if result != nil:
result = dispF("<pre>$1</pre>", "\\begin{rstpre}$n$1$n\\end{rstpre}$n", result = dispF("<pre>$1</pre>", "\\begin{rstpre}$n$1$n\\end{rstpre}$n",
[result]) [result])
@ -614,13 +456,13 @@ proc renderContainer(d: PDoc, n: PRstNode): PRope =
proc texColumns(n: PRstNode): string = proc texColumns(n: PRstNode): string =
result = "" result = ""
for i in countup(1, rsonsLen(n)): add(result, "|X") for i in countup(1, len(n)): add(result, "|X")
proc renderField(d: PDoc, n: PRstNode): PRope = proc renderField(d: PDoc, n: PRstNode): PRope =
var b = false var b = false
if gCmd == cmdRst2Tex: if gCmd == cmdRst2Tex:
var fieldname = addNodes(n.sons[0]) var fieldname = addNodes(n.sons[0])
var fieldval = toRope(esc(strip(addNodes(n.sons[1])))) var fieldval = toRope(esc(d.target, strip(addNodes(n.sons[1]))))
if cmpIgnoreStyle(fieldname, "author") == 0: if cmpIgnoreStyle(fieldname, "author") == 0:
if d.meta[metaAuthor] == nil: if d.meta[metaAuthor] == nil:
d.meta[metaAuthor] = fieldval d.meta[metaAuthor] = fieldval
@ -657,7 +499,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
of rnDefBody: result = renderAux(d, n, disp("<dd>$1</dd>\n", "$1\n")) of rnDefBody: result = renderAux(d, n, disp("<dd>$1</dd>\n", "$1\n"))
of rnFieldList: of rnFieldList:
result = nil result = nil
for i in countup(0, rsonsLen(n) - 1): for i in countup(0, len(n) - 1):
app(result, renderRstToOut(d, n.sons[i])) app(result, renderRstToOut(d, n.sons[i]))
if result != nil: if result != nil:
result = dispf( result = dispf(
@ -705,9 +547,9 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
"\\begin{table}\\begin{rsttab}{" & "\\begin{table}\\begin{rsttab}{" &
texColumns(n) & "|}$n\\hline$n$1\\end{rsttab}\\end{table}")) texColumns(n) & "|}$n\\hline$n$1\\end{rsttab}\\end{table}"))
of rnTableRow: of rnTableRow:
if rsonsLen(n) >= 1: if len(n) >= 1:
result = renderRstToOut(d, n.sons[0]) result = renderRstToOut(d, n.sons[0])
for i in countup(1, rsonsLen(n) - 1): for i in countup(1, len(n) - 1):
dispa(result, "$1", " & $1", [renderRstToOut(d, n.sons[i])]) dispa(result, "$1", " & $1", [renderRstToOut(d, n.sons[i])])
result = dispf("<tr>$1</tr>$n", "$1\\\\$n\\hline$n", [result]) result = dispf("<tr>$1</tr>$n", "$1\\\\$n\\hline$n", [result])
else: else:
@ -770,7 +612,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>", "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
"\\texttt{$1}")) "\\texttt{$1}"))
of rnSmiley: result = renderSmiley(d, n) of rnSmiley: result = renderSmiley(d, n)
of rnLeaf: result = toRope(esc(n.text)) of rnLeaf: result = toRope(esc(d.target, n.text))
of rnContents: d.hasToc = true of rnContents: d.hasToc = true
of rnTitle: d.meta[metaTitle] = renderRstToOut(d, n.sons[0]) of rnTitle: d.meta[metaTitle] = renderRstToOut(d, n.sons[0])
@ -863,7 +705,9 @@ proc genOutFile(d: PDoc): PRope =
proc generateIndex(d: PDoc) = proc generateIndex(d: PDoc) =
if d.theIndex != nil: if d.theIndex != nil:
sortIndex(d.theIndex) sortIndex(d.theIndex)
writeRope(renderRstToRst(d, d.indexFile), gIndexFile) var content = newStringOfCap(2_000_000)
renderRstToRst(d.indexFile, content)
writeFile(gIndexFile, content)
proc writeOutput(d: PDoc, filename, outExt: string) = proc writeOutput(d: PDoc, filename, outExt: string) =
var content = genOutFile(d) var content = genOutFile(d)
@ -886,7 +730,7 @@ proc CommandRstAux(filename, outExt: string) =
var filen = addFileExt(filename, "txt") var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen) var d = newDocumentor(filen)
initIndexFile(d) initIndexFile(d)
var rst = rstParse(readFile(filen), filen, 0, 1, d.hasToc, var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
{roSupportRawDirective}) {roSupportRawDirective})
d.modDesc = renderRstToOut(d, rst) d.modDesc = renderRstToOut(d, rst)
writeOutput(d, filename, outExt) writeOutput(d, filename, outExt)

View file

@ -27,6 +27,8 @@ const
OpChars*: TCharSet = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', OpChars*: TCharSet = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'} '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
# don't forget to update the 'highlite' module if these charsets should change
type type
TTokType* = enum TTokType* = enum
tkInvalid, tkEof, # order is important here! tkInvalid, tkEof, # order is important here!

View file

@ -663,7 +663,7 @@ proc InternalError*(errMsg: string) =
rawMessage(errInternal, errMsg) rawMessage(errInternal, errMsg)
template AssertNotNil*(e: expr): expr = template AssertNotNil*(e: expr): expr =
if(e == nil): InternalError($InstantiationInfo()) if e == nil: InternalError($InstantiationInfo())
e e
template InternalAssert*(e: bool): stmt = template InternalAssert*(e: bool): stmt =

View file

@ -4,6 +4,8 @@
path="llvm" path="llvm"
path="$projectPath/.." path="$projectPath/.."
path="$nimrod/packages/docutils"
@if llvm_gcc or gcc: @if llvm_gcc or gcc:
# GCC, LLVM and Visual C++ have a problem to optimize some modules. # GCC, LLVM and Visual C++ have a problem to optimize some modules.
# This is really strange. # This is really strange.

View file

@ -33,6 +33,7 @@ Files: "doc/*.pdf"
Files: "doc/*.ini" Files: "doc/*.ini"
Start: "doc/overview.html" Start: "doc/overview.html"
[Other] [Other]
Files: "readme.txt;install.txt;contributors.txt" Files: "readme.txt;install.txt;contributors.txt"
Files: "configure;makefile" Files: "configure;makefile"
@ -56,6 +57,9 @@ Files: "compiler/*.nim"
Files: "build/empty.txt" Files: "build/empty.txt"
Files: "bin/empty.txt" Files: "bin/empty.txt"
Files: "packages/docutils/*.nim"
[Lib] [Lib]
Files: "lib/nimbase.h;lib/cycle.h" Files: "lib/nimbase.h;lib/cycle.h"
Files: "lib/*.nim" Files: "lib/*.nim"
@ -72,6 +76,7 @@ Files: "lib/wrappers/cairo/*.nim"
Files: "lib/wrappers/gtk/*.nim" Files: "lib/wrappers/gtk/*.nim"
Files: "lib/wrappers/lua/*.nim" Files: "lib/wrappers/lua/*.nim"
Files: "lib/wrappers/opengl/*.nim" Files: "lib/wrappers/opengl/*.nim"
Files: "lib/wrappers/readline/*.nim"
Files: "lib/wrappers/sdl/*.nim" Files: "lib/wrappers/sdl/*.nim"
Files: "lib/wrappers/x11/*.nim" Files: "lib/wrappers/x11/*.nim"
Files: "lib/wrappers/zip/*.nim" Files: "lib/wrappers/zip/*.nim"
@ -81,6 +86,7 @@ Files: "lib/windows/*.nim"
Files: "lib/posix/*.nim" Files: "lib/posix/*.nim"
Files: "lib/ecmas/*.nim" Files: "lib/ecmas/*.nim"
[Other] [Other]
Files: "examples/*.nim" Files: "examples/*.nim"
Files: "examples/gtk/*.nim" Files: "examples/gtk/*.nim"
@ -99,6 +105,7 @@ Files: "examples/*.txt"
Files: "examples/*.cfg" Files: "examples/*.cfg"
Files: "examples/*.tmpl" Files: "examples/*.tmpl"
[Windows] [Windows]
Files: "bin/nimrod.exe" Files: "bin/nimrod.exe"
Files: "bin/c2nim.exe" Files: "bin/c2nim.exe"
@ -112,21 +119,26 @@ Files: "start.bat"
BinPath: r"bin;dist\mingw\bin;dist" BinPath: r"bin;dist\mingw\bin;dist"
InnoSetup: "Yes" InnoSetup: "Yes"
[UnixBin] [UnixBin]
Files: "bin/nimrod" Files: "bin/nimrod"
[Unix] [Unix]
InstallScript: "yes" InstallScript: "yes"
UninstallScript: "yes" UninstallScript: "yes"
[InnoSetup] [InnoSetup]
path = r"c:\programme\inno setup 5\iscc.exe" path = r"c:\programme\inno setup 5\iscc.exe"
flags = "/Q" flags = "/Q"
[C_Compiler] [C_Compiler]
path = r"" path = r""
flags = "-w" flags = "-w"
[deb] [deb]
buildDepends: "gcc (>= 4:4.3.2)" buildDepends: "gcc (>= 4:4.3.2)"
pkgDepends: "gcc (>= 4:4.3.2)" pkgDepends: "gcc (>= 4:4.3.2)"

View file

@ -199,7 +199,7 @@ proc rawFindFile(f: string): string =
return result.canonicalizePath return result.canonicalizePath
result = "" result = ""
proc FindFile*(f: string): string = proc FindFile*(f: string): string {.procvar.} =
result = rawFindFile(f) result = rawFindFile(f)
if len(result) == 0: result = rawFindFile(toLower(f)) if len(result) == 0: result = rawFindFile(toLower(f))

View file

@ -1897,6 +1897,9 @@ when not defined(EcmaScript) and not defined(NimrodVM):
proc writeStackTrace*() proc writeStackTrace*()
## writes the current stack trace to ``stderr``. This is only works ## writes the current stack trace to ``stderr``. This is only works
## for debug builds. ## for debug builds.
proc getStackTrace*(): string
## gets the current stack trace. This is only works for debug builds.
{.push stack_trace: off.} {.push stack_trace: off.}
when hostCPU == "avr": when hostCPU == "avr":

View file

@ -246,6 +246,13 @@ proc WriteStackTrace() =
else: else:
writeToStdErr("No stack traceback available\n") writeToStdErr("No stack traceback available\n")
proc getStackTrace(): string =
when hasSomeStackTrace:
result = ""
rawWriteStackTrace(result)
else:
result = "No stack traceback available\n"
when defined(endb): when defined(endb):
var var
dbgAborting: bool # whether the debugger wants to abort dbgAborting: bool # whether the debugger wants to abort

View file

@ -1,18 +1,18 @@
# #
# #
# The Nimrod Compiler # Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# Source highlighter for programming or markup languages. ## Source highlighter for programming or markup languages.
# Currently only few languages are supported, other languages may be added. ## Currently only few languages are supported, other languages may be added.
# The interface supports one language nested in another. ## The interface supports one language nested in another.
import import
hashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, lexer strutils
type type
TTokenClass* = enum TTokenClass* = enum
@ -44,19 +44,15 @@ const
"Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink", "Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink",
"Label", "Reference", "Other"] "Label", "Reference", "Other"]
proc getSourceLanguage*(name: string): TSourceLanguage nimrodKeywords = slurp("doc/keywords.txt").split
proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string)
proc deinitGeneralTokenizer*(g: var TGeneralTokenizer)
proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage)
# implementation
proc getSourceLanguage(name: string): TSourceLanguage = proc getSourceLanguage*(name: string): TSourceLanguage =
for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)): for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)):
if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0: if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0:
return i return i
result = langNone result = langNone
proc initGeneralTokenizer(g: var TGeneralTokenizer, buf: string) = proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
g.buf = cstring(buf) g.buf = cstring(buf)
g.kind = low(TTokenClass) g.kind = low(TTokenClass)
g.start = 0 g.start = 0
@ -66,16 +62,20 @@ proc initGeneralTokenizer(g: var TGeneralTokenizer, buf: string) =
while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos) while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
g.pos = pos g.pos = pos
proc deinitGeneralTokenizer(g: var TGeneralTokenizer) = proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) =
nil nil
proc nimGetKeyword(id: string): TTokenClass = proc nimGetKeyword(id: string): TTokenClass =
var i = getIdent(id) for k in nimrodKeywords:
if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and if cmpIgnoreStyle(id, k) == 0: return gtKeyword
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): result = gtIdentifier
result = gtKeyword when false:
else: var i = getIdent(id)
result = gtIdentifier if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
result = gtKeyword
else:
result = gtIdentifier
proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int = proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
var pos = position var pos = position
@ -111,11 +111,16 @@ proc nimNumber(g: var TGeneralTokenizer, position: int): int =
while g.buf[pos] in decChars: inc(pos) while g.buf[pos] in decChars: inc(pos)
result = nimNumberPostfix(g, pos) result = nimNumberPostfix(g, pos)
const
OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
proc nimNextToken(g: var TGeneralTokenizer) = proc nimNextToken(g: var TGeneralTokenizer) =
const const
hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'} hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'}
octChars = {'0'..'7', '_'} octChars = {'0'..'7', '_'}
binChars = {'0'..'1', '_'} binChars = {'0'..'1', '_'}
SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
var pos = g.pos var pos = g.pos
g.start = g.pos g.start = g.pos
if g.state == gtStringLit: if g.state == gtStringLit:
@ -154,7 +159,7 @@ proc nimNextToken(g: var TGeneralTokenizer) =
while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos) while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos)
of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF': of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
var id = "" var id = ""
while g.buf[pos] in lexer.SymChars + {'_'}: while g.buf[pos] in SymChars + {'_'}:
add(id, g.buf[pos]) add(id, g.buf[pos])
inc(pos) inc(pos)
if (g.buf[pos] == '\"'): if (g.buf[pos] == '\"'):
@ -247,15 +252,15 @@ proc nimNextToken(g: var TGeneralTokenizer) =
of '\0': of '\0':
g.kind = gtEof g.kind = gtEof
else: else:
if g.buf[pos] in lexer.OpChars: if g.buf[pos] in OpChars:
g.kind = gtOperator g.kind = gtOperator
while g.buf[pos] in lexer.OpChars: inc(pos) while g.buf[pos] in OpChars: inc(pos)
else: else:
inc(pos) inc(pos)
g.kind = gtNone g.kind = gtNone
g.length = pos - g.pos g.length = pos - g.pos
if (g.kind != gtEof) and (g.length <= 0): if g.kind != gtEof and g.length <= 0:
InternalError("nimNextToken: " & $(g.buf)) assert false, "nimNextToken: produced an empty token"
g.pos = pos g.pos = pos
proc generalNumber(g: var TGeneralTokenizer, position: int): int = proc generalNumber(g: var TGeneralTokenizer, position: int): int =
@ -407,7 +412,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
inc(pos) inc(pos)
if hasPreprocessor in flags: if hasPreprocessor in flags:
g.kind = gtPreprocessor g.kind = gtPreprocessor
while g.buf[pos] in {' ', Tabulator}: inc(pos) while g.buf[pos] in {' ', '\t'}: inc(pos)
while g.buf[pos] in symChars: inc(pos) while g.buf[pos] in symChars: inc(pos)
else: else:
g.kind = gtOperator g.kind = gtOperator
@ -462,14 +467,15 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
of '\0': of '\0':
g.kind = gtEof g.kind = gtEof
else: else:
if g.buf[pos] in lexer.OpChars: if g.buf[pos] in OpChars:
g.kind = gtOperator g.kind = gtOperator
while g.buf[pos] in lexer.OpChars: inc(pos) while g.buf[pos] in OpChars: inc(pos)
else: else:
inc(pos) inc(pos)
g.kind = gtNone g.kind = gtNone
g.length = pos - g.pos g.length = pos - g.pos
if (g.kind != gtEof) and (g.length <= 0): InternalError("clikeNextToken") if g.kind != gtEof and g.length <= 0:
assert false, "clikeNextToken: produced an empty token"
g.pos = pos g.pos = pos
proc cNextToken(g: var TGeneralTokenizer) = proc cNextToken(g: var TGeneralTokenizer) =
@ -520,12 +526,12 @@ proc javaNextToken(g: var TGeneralTokenizer) =
"try", "void", "volatile", "while"] "try", "void", "volatile", "while"]
clikeNextToken(g, keywords, {}) clikeNextToken(g, keywords, {})
proc getNextToken(g: var TGeneralTokenizer, lang: TSourceLanguage) = proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) =
case lang case lang
of langNone: assert false
of langNimrod: nimNextToken(g) of langNimrod: nimNextToken(g)
of langCpp: cppNextToken(g) of langCpp: cppNextToken(g)
of langCsharp: csharpNextToken(g) of langCsharp: csharpNextToken(g)
of langC: cNextToken(g) of langC: cNextToken(g)
of langJava: javaNextToken(g) of langJava: javaNextToken(g)
else: InternalError("getNextToken")

View file

@ -1,95 +1,61 @@
# #
# #
# The Nimrod Compiler # Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# This module implements a *reStructuredText* parser. A large ## This module implements a `reStructuredText`:idx parser. A large
# subset is provided. ## subset is implemented. Some features of the `markdown`:idx: wiki syntax are
## also supported.
import import
os, msgs, strutils, hashes, options os, strutils, rstast
type
TRstNodeKind* = enum
rnInner, # an inner node or a root
rnHeadline, # a headline
rnOverline, # an over- and underlined headline
rnTransition, # a transition (the ------------- <hr> thingie)
rnParagraph, # a paragraph
rnBulletList, # a bullet list
rnBulletItem, # a bullet item
rnEnumList, # an enumerated list
rnEnumItem, # an enumerated item
rnDefList, # a definition list
rnDefItem, # an item of a definition list consisting of ...
rnDefName, # ... a name part ...
rnDefBody, # ... and a body part ...
rnFieldList, # a field list
rnField, # a field item
rnFieldName, # consisting of a field name ...
rnFieldBody, # ... and a field body
rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
rnLineBlock, # the | thingie
rnLineBlockItem, # sons of the | thing
rnBlockQuote, # text just indented
rnTable, rnGridTable, rnTableRow, rnTableHeaderCell, rnTableDataCell,
rnLabel, # used for footnotes and other things
rnFootnote, # a footnote
rnCitation, # similar to footnote
rnStandaloneHyperlink, rnHyperlink, rnRef, rnDirective, # a directive
rnDirArg, rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock,
rnRawHtml, rnRawLatex,
rnContainer, # ``container`` directive
rnIndex, # index directve:
# .. index::
# key
# * `file#id <file#id>`_
# * `file#id <file#id>'_
rnSubstitutionDef, # a definition of a substitution
rnGeneralRole, # Inline markup:
rnSub, rnSup, rnIdx,
rnEmphasis, # "*"
rnStrongEmphasis, # "**"
rnTripleEmphasis, # "***"
rnInterpretedText, # "`"
rnInlineLiteral, # "``"
rnSubstitutionReferences, # "|"
rnSmiley, # some smiley
rnLeaf # a leaf; the node's text field contains the
# leaf val
type type
TRstParseOption* = enum ## options for the RST parser TRstParseOption* = enum ## options for the RST parser
roSkipPounds, ## skip ``#`` at line beginning (documentation roSkipPounds, ## skip ``#`` at line beginning (documentation
## embedded in Nimrod comments) ## embedded in Nimrod comments)
roSupportSmilies, ## make the RST parser support smilies like ``:)`` roSupportSmilies, ## make the RST parser support smilies like ``:)``
roSupportRawDirective ## support the ``raw`` directive (don't support roSupportRawDirective, ## support the ``raw`` directive (don't support
## it for sandboxing) ## it for sandboxing)
roSupportMarkdown ## support additional features of markdown
TRstParseOptions* = set[TRstParseOption] TRstParseOptions* = set[TRstParseOption]
PRSTNode* = ref TRstNode TMsgClass* = enum
TRstNodeSeq* = seq[PRstNode] mcHint = "Hint",
TRSTNode*{.acyclic, final.} = object mcWarning = "Warning",
kind*: TRstNodeKind mcError = "Error"
text*: string # valid for leafs in the AST; and the title of
# the document or the section
level*: int # valid for some node kinds
sons*: TRstNodeSeq # the node's sons
TMsgKind* = enum ## the possible messages
meCannotOpenFile,
meExpected,
meGridTableNotImplemented,
meNewSectionExpected,
meGeneralParseError,
meInvalidDirective,
mwRedefinitionOfLabel,
mwUnknownSubstitution
TMsgHandler* = proc (filename: string, line, col: int, msgKind: TMsgKind,
arg: string) ## what to do in case of an error
TFindFileHandler* = proc (filename: string): string
const
messages: array [TMsgKind, string] = [
meCannotOpenFile: "cannot open '$1'",
meExpected: "'$1' expected",
meGridTableNotImplemented: "grid table is not implemented",
meNewSectionExpected: "new section expected",
meGeneralParseError: "general parse error",
meInvalidDirective: "invalid directive: '$1'",
mwRedefinitionOfLabel: "redefinition of label '$1'",
mwUnknownSubstitution: "unknown substitution '$1'"
]
proc rstParse*(text, filename: string,
line, column: int, hasToc: var bool,
options: TRstParseOptions): PRstNode
proc rsonsLen*(n: PRstNode): int
proc newRstNode*(kind: TRstNodeKind): PRstNode
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode
proc addSon*(father, son: PRstNode)
proc rstnodeToRefname*(n: PRstNode): string proc rstnodeToRefname*(n: PRstNode): string
proc addNodes*(n: PRstNode): string proc addNodes*(n: PRstNode): string
proc getFieldValue*(n: PRstNode, fieldname: string): string proc getFieldValue*(n: PRstNode, fieldname: string): string
@ -281,46 +247,27 @@ proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq) =
tokens[0].ival = len(tokens[0].symbol) tokens[0].ival = len(tokens[0].symbol)
tokens[0].kind = tkIndent tokens[0].kind = tkIndent
proc addSon(father, son: PRstNode) = type
add(father.sons, son)
proc addSonIfNotNil(father, son: PRstNode) =
if son != nil: addSon(father, son)
proc rsonsLen(n: PRstNode): int =
result = len(n.sons)
proc newRstNode(kind: TRstNodeKind): PRstNode =
new(result)
result.sons = @[]
result.kind = kind
proc newRstNode(kind: TRstNodeKind, s: string): PRstNode =
result = newRstNode(kind)
result.text = s
proc lastSon*(n: PRstNode): PRstNode =
result = n.sons[len(n.sons)-1]
type
TLevelMap = array[Char, int] TLevelMap = array[Char, int]
TSubstitution{.final.} = object TSubstitution{.final.} = object
key*: string key*: string
value*: PRstNode value*: PRstNode
TSharedState {.final.} = object TSharedState {.final.} = object
options: TRstParseOptions # parsing options options: TRstParseOptions # parsing options
uLevel*, oLevel*: int # counters for the section levels uLevel, oLevel: int # counters for the section levels
subs*: seq[TSubstitution] # substitutions subs: seq[TSubstitution] # substitutions
refs*: seq[TSubstitution] # references refs: seq[TSubstitution] # references
underlineToLevel*: TLevelMap # Saves for each possible title adornment underlineToLevel: TLevelMap # Saves for each possible title adornment
# character its level in the # character its level in the
# current document. # current document.
# This is for single underline adornments. # This is for single underline adornments.
overlineToLevel*: TLevelMap # Saves for each possible title adornment overlineToLevel: TLevelMap # Saves for each possible title adornment
# character its level in the current # character its level in the current
# document. # document.
# This is for over-underline adornments. # This is for over-underline adornments.
msgHandler: TMsgHandler # How to handle errors.
findFile: TFindFileHandler # How to find files.
PSharedState = ref TSharedState PSharedState = ref TSharedState
TRstParser = object of TObject TRstParser = object of TObject
@ -332,21 +279,57 @@ type
line*, col*: int line*, col*: int
hasToc*: bool hasToc*: bool
EParseError* = object of EInvalidValue
proc newSharedState(options: TRstParseOptions): PSharedState = when false:
proc tokInfo(p: TRstParser, tok: TToken): TLineInfo =
result = newLineInfo(p.filename, p.line + tok.line, p.col + tok.col)
proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
GlobalError(tokInfo(p, p.tok[p.idx]), msgKind, arg)
proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
GlobalError(tokInfo(p, p.tok[p.idx]), msgKind, p.tok[p.idx].symbol)
proc whichMsgClass*(k: TMsgKind): TMsgClass =
## returns which message class `k` belongs to.
case ($k)[1]
of 'e', 'E': result = mcError
of 'w', 'W': result = mcWarning
of 'h', 'H': result = mcHint
else: assert false, "msgkind does not fit naming scheme"
proc defaultMsgHandler(filename: string, line, col: int, msgkind: TMsgKind,
arg: string) =
let mc = msgKind.whichMsgClass
let a = messages[msgKind] % arg
let message = "$1($2, $3) $4: $5" % [filename, $line, $col, $mc, a]
if mc == mcError: raise newException(EParseError, message)
else: Writeln(stdout, message)
proc defaultFindFile(filename: string): string =
if existsFile(filename): result = filename
else: result = ""
proc newSharedState(options: TRstParseOptions,
findFile: TFindFileHandler,
msgHandler: TMsgHandler): PSharedState =
new(result) new(result)
result.subs = @[] result.subs = @[]
result.refs = @[] result.refs = @[]
result.options = options result.options = options
result.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler
proc tokInfo(p: TRstParser, tok: TToken): TLineInfo = result.findFile = if isNil(findFile): defaultFindFile else: findFile
result = newLineInfo(p.filename, p.line + tok.line, p.col + tok.col)
proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) = proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
GlobalError(tokInfo(p, p.tok[p.idx]), msgKind, arg) p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
p.col + p.tok[p.idx].col, msgKind, arg)
proc rstMessage(p: TRstParser, msgKind: TMsgKind) = proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
GlobalError(tokInfo(p, p.tok[p.idx]), msgKind, p.tok[p.idx].symbol) p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
p.col + p.tok[p.idx].col, msgKind,
p.tok[p.idx].symbol)
proc currInd(p: TRstParser): int = proc currInd(p: TRstParser): int =
result = p.indentStack[high(p.indentStack)] result = p.indentStack[high(p.indentStack)]
@ -371,7 +354,7 @@ proc addNodesAux(n: PRstNode, result: var string) =
if n.kind == rnLeaf: if n.kind == rnLeaf:
add(result, n.text) add(result, n.text)
else: else:
for i in countup(0, rsonsLen(n) - 1): addNodesAux(n.sons[i], result) for i in countup(0, len(n) - 1): addNodesAux(n.sons[i], result)
proc addNodes(n: PRstNode): string = proc addNodes(n: PRstNode): string =
result = "" result = ""
@ -400,7 +383,7 @@ proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
else: else:
if (len(r) > 0): b = true if (len(r) > 0): b = true
else: else:
for i in countup(0, rsonsLen(n) - 1): rstnodeToRefnameAux(n.sons[i], r, b) for i in countup(0, len(n) - 1): rstnodeToRefnameAux(n.sons[i], r, b)
proc rstnodeToRefname(n: PRstNode): string = proc rstnodeToRefname(n: PRstNode): string =
result = "" result = ""
@ -433,7 +416,7 @@ proc setRef(p: var TRstParser, key: string, value: PRstNode) =
for i in countup(0, length - 1): for i in countup(0, length - 1):
if key == p.s.refs[i].key: if key == p.s.refs[i].key:
if p.s.refs[i].value.addNodes != value.addNodes: if p.s.refs[i].value.addNodes != value.addNodes:
rstMessage(p, warnRedefinitionOfLabel, key) rstMessage(p, mwRedefinitionOfLabel, key)
p.s.refs[i].value = value p.s.refs[i].value = value
return return
@ -456,7 +439,7 @@ proc cmpNodes(a, b: PRstNode): int =
proc sortIndex(a: PRstNode) = proc sortIndex(a: PRstNode) =
# we use shellsort here; fast and simple # we use shellsort here; fast and simple
assert(a.kind == rnDefList) assert(a.kind == rnDefList)
var N = rsonsLen(a) var N = len(a)
var h = 1 var h = 1
while true: while true:
h = 3 * h + 1 h = 3 * h + 1
@ -478,14 +461,14 @@ proc eqRstNodes(a, b: PRstNode): bool =
if a.kind == rnLeaf: if a.kind == rnLeaf:
result = a.text == b.text result = a.text == b.text
else: else:
if rsonsLen(a) != rsonsLen(b): return if len(a) != len(b): return
for i in countup(0, rsonsLen(a) - 1): for i in countup(0, len(a) - 1):
if not eqRstNodes(a.sons[i], b.sons[i]): return if not eqRstNodes(a.sons[i], b.sons[i]): return
result = true result = true
proc matchesHyperlink(h: PRstNode, filename: string): bool = proc matchesHyperlink(h: PRstNode, filename: string): bool =
if h.kind == rnInner: # this may happen in broken indexes! if h.kind == rnInner: # this may happen in broken indexes!
assert(rsonsLen(h) == 1) assert(len(h) == 1)
result = matchesHyperlink(h.sons[0], filename) result = matchesHyperlink(h.sons[0], filename)
elif h.kind == rnHyperlink: elif h.kind == rnHyperlink:
var s = addNodes(h.sons[1]) var s = addNodes(h.sons[1])
@ -498,14 +481,14 @@ proc clearIndex(index: PRstNode, filename: string) =
var var
lastItem: int lastItem: int
assert(index.kind == rnDefList) assert(index.kind == rnDefList)
for i in countup(0, rsonsLen(index) - 1): for i in countup(0, len(index) - 1):
assert(index.sons[i].sons[1].kind == rnDefBody) assert(index.sons[i].sons[1].kind == rnDefBody)
var val = index.sons[i].sons[1].sons[0] var val = index.sons[i].sons[1].sons[0]
if val.kind == rnInner: val = val.sons[0] if val.kind == rnInner: val = val.sons[0]
if val.kind == rnBulletList: if val.kind == rnBulletList:
var items = rsonsLen(val) var items = len(val)
lastItem = - 1 # save the last valid item index lastItem = - 1 # save the last valid item index
for j in countup(0, rsonsLen(val) - 1): for j in countup(0, len(val) - 1):
if val.sons[j] == nil: if val.sons[j] == nil:
dec(items) dec(items)
elif matchesHyperlink(val.sons[j].sons[0], filename): elif matchesHyperlink(val.sons[j].sons[0], filename):
@ -520,7 +503,7 @@ proc clearIndex(index: PRstNode, filename: string) =
elif matchesHyperlink(val, filename): elif matchesHyperlink(val, filename):
index.sons[i] = nil index.sons[i] = nil
var k = 0 var k = 0
for i in countup(0, rsonsLen(index) - 1): for i in countup(0, len(index) - 1):
if index.sons[i] != nil: if index.sons[i] != nil:
if k != i: index.sons[k] = index.sons[i] if k != i: index.sons[k] = index.sons[i]
inc(k) inc(k)
@ -531,28 +514,28 @@ proc setIndexPair(index, key, val: PRstNode) =
assert(index.kind == rnDefList) assert(index.kind == rnDefList)
assert(key.kind != rnDefName) assert(key.kind != rnDefName)
a = newRstNode(rnDefName) a = newRstNode(rnDefName)
addSon(a, key) add(a, key)
for i in countup(0, rsonsLen(index) - 1): for i in countup(0, len(index) - 1):
if eqRstNodes(index.sons[i].sons[0], a): if eqRstNodes(index.sons[i].sons[0], a):
assert(index.sons[i].sons[1].kind == rnDefBody) assert(index.sons[i].sons[1].kind == rnDefBody)
e = index.sons[i].sons[1].sons[0] e = index.sons[i].sons[1].sons[0]
if e.kind != rnBulletList: if e.kind != rnBulletList:
e = newRstNode(rnBulletList) e = newRstNode(rnBulletList)
b = newRstNode(rnBulletItem) b = newRstNode(rnBulletItem)
addSon(b, index.sons[i].sons[1].sons[0]) add(b, index.sons[i].sons[1].sons[0])
addSon(e, b) add(e, b)
index.sons[i].sons[1].sons[0] = e index.sons[i].sons[1].sons[0] = e
b = newRstNode(rnBulletItem) b = newRstNode(rnBulletItem)
addSon(b, val) add(b, val)
addSon(e, b) add(e, b)
return # key already exists return # key already exists
e = newRstNode(rnDefItem) e = newRstNode(rnDefItem)
assert(val.kind != rnDefBody) assert(val.kind != rnDefBody)
b = newRstNode(rnDefBody) b = newRstNode(rnDefBody)
addSon(b, val) add(b, val)
addSon(e, a) add(e, a)
addSon(e, b) add(e, b)
addSon(index, e) add(index, e)
proc newLeaf(p: var TRstParser): PRstNode = proc newLeaf(p: var TRstParser): PRstNode =
result = newRstNode(rnLeaf, p.tok[p.idx].symbol) result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
@ -562,15 +545,15 @@ proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
while true: while true:
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkWord, tkOther, tkWhite: of tkWord, tkOther, tkWhite:
addSon(res, newLeaf(p)) add(res, newLeaf(p))
of tkPunct: of tkPunct:
if p.tok[p.idx].symbol == endStr: if p.tok[p.idx].symbol == endStr:
inc(p.idx) inc(p.idx)
break break
else: else:
addSon(res, newLeaf(p)) add(res, newLeaf(p))
else: else:
rstMessage(p, errXexpected, endStr) rstMessage(p, meExpected, endStr)
break break
inc(p.idx) inc(p.idx)
result = res result = res
@ -578,12 +561,12 @@ proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
proc untilEol(p: var TRstParser): PRstNode = proc untilEol(p: var TRstParser): PRstNode =
result = newRstNode(rnInner) result = newRstNode(rnInner)
while not (p.tok[p.idx].kind in {tkIndent, tkEof}): while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
addSon(result, newLeaf(p)) add(result, newLeaf(p))
inc(p.idx) inc(p.idx)
proc expect(p: var TRstParser, tok: string) = proc expect(p: var TRstParser, tok: string) =
if p.tok[p.idx].symbol == tok: inc(p.idx) if p.tok[p.idx].symbol == tok: inc(p.idx)
else: rstMessage(p, errXexpected, tok) else: rstMessage(p, meExpected, tok)
proc isInlineMarkupEnd(p: TRstParser, markup: string): bool = proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
result = p.tok[p.idx].symbol == markup result = p.tok[p.idx].symbol == markup
@ -676,13 +659,13 @@ proc match(p: TRstParser, start: int, expr: string): bool =
proc fixupEmbeddedRef(n, a, b: PRstNode) = proc fixupEmbeddedRef(n, a, b: PRstNode) =
var sep = - 1 var sep = - 1
for i in countdown(rsonsLen(n) - 2, 0): for i in countdown(len(n) - 2, 0):
if n.sons[i].text == "<": if n.sons[i].text == "<":
sep = i sep = i
break break
var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1 var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1
for i in countup(0, sep - incr): addSon(a, n.sons[i]) for i in countup(0, sep - incr): add(a, n.sons[i])
for i in countup(sep + 1, rsonsLen(n) - 2): addSon(b, n.sons[i]) for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i])
proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode = proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
result = n result = n
@ -692,19 +675,19 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
var a = newRstNode(rnInner) var a = newRstNode(rnInner)
var b = newRstNode(rnInner) var b = newRstNode(rnInner)
fixupEmbeddedRef(n, a, b) fixupEmbeddedRef(n, a, b)
if rsonsLen(a) == 0: if len(a) == 0:
result = newRstNode(rnStandaloneHyperlink) result = newRstNode(rnStandaloneHyperlink)
addSon(result, b) add(result, b)
else: else:
result = newRstNode(rnHyperlink) result = newRstNode(rnHyperlink)
addSon(result, a) add(result, a)
addSon(result, b) add(result, b)
setRef(p, rstnodeToRefname(a), b) setRef(p, rstnodeToRefname(a), b)
elif n.kind == rnInterpretedText: elif n.kind == rnInterpretedText:
n.kind = rnRef n.kind = rnRef
else: else:
result = newRstNode(rnRef) result = newRstNode(rnRef)
addSon(result, n) add(result, n)
elif match(p, p.idx, ":w:"): elif match(p, p.idx, ":w:"):
# a role: # a role:
if p.tok[p.idx + 1].symbol == "idx": if p.tok[p.idx + 1].symbol == "idx":
@ -724,8 +707,8 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
else: else:
result = newRstNode(rnGeneralRole) result = newRstNode(rnGeneralRole)
n.kind = rnInner n.kind = rnInner
addSon(result, n) add(result, n)
addSon(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol)) add(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
inc(p.idx, 3) inc(p.idx, 3)
proc matchVerbatim(p: TRstParser, start: int, expr: string): int = proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
@ -761,27 +744,27 @@ proc parseURL(p: var TRstParser, father: PRstNode) =
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}: if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
break break
else: break else: break
addSon(n, newLeaf(p)) add(n, newLeaf(p))
inc(p.idx) inc(p.idx)
addSon(father, n) add(father, n)
else: else:
var n = newLeaf(p) var n = newLeaf(p)
inc(p.idx) inc(p.idx)
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n) if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
addSon(father, n) add(father, n)
proc parseBackslash(p: var TRstParser, father: PRstNode) = proc parseBackslash(p: var TRstParser, father: PRstNode) =
assert(p.tok[p.idx].kind == tkPunct) assert(p.tok[p.idx].kind == tkPunct)
if p.tok[p.idx].symbol == "\\\\": if p.tok[p.idx].symbol == "\\\\":
addSon(father, newRstNode(rnLeaf, "\\")) add(father, newRstNode(rnLeaf, "\\"))
inc(p.idx) inc(p.idx)
elif p.tok[p.idx].symbol == "\\": elif p.tok[p.idx].symbol == "\\":
# XXX: Unicode? # XXX: Unicode?
inc(p.idx) inc(p.idx)
if p.tok[p.idx].kind != tkWhite: addSon(father, newLeaf(p)) if p.tok[p.idx].kind != tkWhite: add(father, newLeaf(p))
inc(p.idx) inc(p.idx)
else: else:
addSon(father, newLeaf(p)) add(father, newLeaf(p))
inc(p.idx) inc(p.idx)
when false: when false:
@ -795,18 +778,18 @@ when false:
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}: if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
break break
else: break else: break
addSon(n, newLeaf(p)) add(n, newLeaf(p))
inc(p.idx) inc(p.idx)
addSon(father, n) add(father, n)
elif not verbatim and roSupportSmilies in p.shared.options: elif not verbatim and roSupportSmilies in p.shared.options:
let n = parseSmiley(p) let n = parseSmiley(p)
if s != nil: if s != nil:
addSon(father, n) add(father, n)
else: else:
var n = newLeaf(p) var n = newLeaf(p)
inc(p.idx) inc(p.idx)
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n) if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
addSon(father, n) add(father, n)
proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string, proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
interpretBackslash: bool) = interpretBackslash: bool) =
@ -819,21 +802,21 @@ proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
elif interpretBackslash: elif interpretBackslash:
parseBackslash(p, father) parseBackslash(p, father)
else: else:
addSon(father, newLeaf(p)) add(father, newLeaf(p))
inc(p.idx) inc(p.idx)
of tkAdornment, tkWord, tkOther: of tkAdornment, tkWord, tkOther:
addSon(father, newLeaf(p)) add(father, newLeaf(p))
inc(p.idx) inc(p.idx)
of tkIndent: of tkIndent:
addSon(father, newRstNode(rnLeaf, " ")) add(father, newRstNode(rnLeaf, " "))
inc(p.idx) inc(p.idx)
if p.tok[p.idx].kind == tkIndent: if p.tok[p.idx].kind == tkIndent:
rstMessage(p, errXExpected, postfix) rstMessage(p, meExpected, postfix)
break break
of tkWhite: of tkWhite:
addSon(father, newRstNode(rnLeaf, " ")) add(father, newRstNode(rnLeaf, " "))
inc(p.idx) inc(p.idx)
else: rstMessage(p, errXExpected, postfix) else: rstMessage(p, meExpected, postfix)
proc parseInline(p: var TRstParser, father: PRstNode) = proc parseInline(p: var TRstParser, father: PRstNode) =
case p.tok[p.idx].kind case p.tok[p.idx].kind
@ -842,54 +825,54 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
inc(p.idx) inc(p.idx)
var n = newRstNode(rnTripleEmphasis) var n = newRstNode(rnTripleEmphasis)
parseUntil(p, n, "***", true) parseUntil(p, n, "***", true)
addSon(father, n) add(father, n)
elif isInlineMarkupStart(p, "**"): elif isInlineMarkupStart(p, "**"):
inc(p.idx) inc(p.idx)
var n = newRstNode(rnStrongEmphasis) var n = newRstNode(rnStrongEmphasis)
parseUntil(p, n, "**", true) parseUntil(p, n, "**", true)
addSon(father, n) add(father, n)
elif isInlineMarkupStart(p, "*"): elif isInlineMarkupStart(p, "*"):
inc(p.idx) inc(p.idx)
var n = newRstNode(rnEmphasis) var n = newRstNode(rnEmphasis)
parseUntil(p, n, "*", true) parseUntil(p, n, "*", true)
addSon(father, n) add(father, n)
elif isInlineMarkupStart(p, "``"): elif isInlineMarkupStart(p, "``"):
inc(p.idx) inc(p.idx)
var n = newRstNode(rnInlineLiteral) var n = newRstNode(rnInlineLiteral)
parseUntil(p, n, "``", false) parseUntil(p, n, "``", false)
addSon(father, n) add(father, n)
elif isInlineMarkupStart(p, "`"): elif isInlineMarkupStart(p, "`"):
inc(p.idx) inc(p.idx)
var n = newRstNode(rnInterpretedText) var n = newRstNode(rnInterpretedText)
parseUntil(p, n, "`", true) parseUntil(p, n, "`", true)
n = parsePostfix(p, n) n = parsePostfix(p, n)
addSon(father, n) add(father, n)
elif isInlineMarkupStart(p, "|"): elif isInlineMarkupStart(p, "|"):
inc(p.idx) inc(p.idx)
var n = newRstNode(rnSubstitutionReferences) var n = newRstNode(rnSubstitutionReferences)
parseUntil(p, n, "|", false) parseUntil(p, n, "|", false)
addSon(father, n) add(father, n)
else: else:
if roSupportSmilies in p.s.options: if roSupportSmilies in p.s.options:
let n = parseSmiley(p) let n = parseSmiley(p)
if n != nil: if n != nil:
addSon(father, n) add(father, n)
return return
parseBackslash(p, father) parseBackslash(p, father)
of tkWord: of tkWord:
if roSupportSmilies in p.s.options: if roSupportSmilies in p.s.options:
let n = parseSmiley(p) let n = parseSmiley(p)
if n != nil: if n != nil:
addSon(father, n) add(father, n)
return return
parseURL(p, father) parseURL(p, father)
of tkAdornment, tkOther, tkWhite: of tkAdornment, tkOther, tkWhite:
if roSupportSmilies in p.s.options: if roSupportSmilies in p.s.options:
let n = parseSmiley(p) let n = parseSmiley(p)
if n != nil: if n != nil:
addSon(father, n) add(father, n)
return return
addSon(father, newLeaf(p)) add(father, newLeaf(p))
inc(p.idx) inc(p.idx)
else: nil else: nil
@ -944,8 +927,7 @@ const
"title"] "title"]
proc getDirKind(s: string): TDirKind = proc getDirKind(s: string): TDirKind =
var i: int let i = find(DirIds, s)
i = binaryStrSearch(DirIds, s)
if i >= 0: result = TDirKind(i) if i >= 0: result = TDirKind(i)
else: result = dkNone else: result = dkNone
@ -970,8 +952,8 @@ proc parseField(p: var TRstParser): PRstNode =
pushInd(p, indent) pushInd(p, indent)
parseSection(p, fieldbody) parseSection(p, fieldbody)
popInd(p) popInd(p)
addSon(result, fieldname) add(result, fieldname)
addSon(result, fieldbody) add(result, fieldbody)
proc parseFields(p: var TRstParser): PRstNode = proc parseFields(p: var TRstParser): PRstNode =
result = nil result = nil
@ -982,7 +964,7 @@ proc parseFields(p: var TRstParser): PRstNode =
result = newRstNode(rnFieldList) result = newRstNode(rnFieldList)
if not atStart: inc(p.idx) if not atStart: inc(p.idx)
while true: while true:
addSon(result, parseField(p)) add(result, parseField(p))
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
(p.tok[p.idx + 1].symbol == ":"): (p.tok[p.idx + 1].symbol == ":"):
inc(p.idx) inc(p.idx)
@ -996,7 +978,7 @@ proc getFieldValue(n: PRstNode, fieldname: string): string =
#InternalError("getFieldValue (2): " & $n.sons[1].kind) #InternalError("getFieldValue (2): " & $n.sons[1].kind)
# We don't like internal errors here anymore as that would break the forum! # We don't like internal errors here anymore as that would break the forum!
return return
for i in countup(0, rsonsLen(n.sons[1]) - 1): for i in countup(0, len(n.sons[1]) - 1):
var f = n.sons[1].sons[i] var f = n.sons[1].sons[i]
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0: if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
result = addNodes(f.sons[1]) result = addNodes(f.sons[1])
@ -1032,7 +1014,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
while not (p.tok[p.idx].kind in {tkIndent, tkEof}): while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
add(n.text, p.tok[p.idx].symbol) add(n.text, p.tok[p.idx].symbol)
inc(p.idx) inc(p.idx)
addSon(result, n) add(result, n)
proc getLevel(map: var TLevelMap, lvl: var int, c: Char): int = proc getLevel(map: var TLevelMap, lvl: var int, c: Char): int =
if map[c] == 0: if map[c] == 0:
@ -1099,7 +1081,7 @@ proc whichSection(p: TRstParser): TRstNodeKind =
result = rnEnumList result = rnEnumList
elif match(p, p.idx, "+a+"): elif match(p, p.idx, "+a+"):
result = rnGridTable result = rnGridTable
rstMessage(p, errGridTableNotImplemented) rstMessage(p, meGridTableNotImplemented)
elif isDefList(p): elif isDefList(p):
result = rnDefList result = rnDefList
elif isOptionList(p): elif isOptionList(p):
@ -1123,7 +1105,7 @@ proc parseLineBlock(p: var TRstParser): PRstNode =
while true: while true:
var item = newRstNode(rnLineBlockItem) var item = newRstNode(rnLineBlockItem)
parseSection(p, item) parseSection(p, item)
addSon(result, item) add(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
(p.tok[p.idx + 1].symbol == "|") and (p.tok[p.idx + 1].symbol == "|") and
(p.tok[p.idx + 2].kind == tkWhite): (p.tok[p.idx + 2].kind == tkWhite):
@ -1143,9 +1125,9 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
inc(p.idx) inc(p.idx)
case whichSection(p) case whichSection(p)
of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective: of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
addSon(result, newRstNode(rnLeaf, " ")) add(result, newRstNode(rnLeaf, " "))
of rnLineBlock: of rnLineBlock:
addSonIfNotNil(result, parseLineBlock(p)) addIfNotNil(result, parseLineBlock(p))
else: break else: break
else: else:
break break
@ -1153,9 +1135,9 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
if (p.tok[p.idx].symbol == "::") and if (p.tok[p.idx].symbol == "::") and
(p.tok[p.idx + 1].kind == tkIndent) and (p.tok[p.idx + 1].kind == tkIndent) and
(currInd(p) < p.tok[p.idx + 1].ival): (currInd(p) < p.tok[p.idx + 1].ival):
addSon(result, newRstNode(rnLeaf, ":")) add(result, newRstNode(rnLeaf, ":"))
inc(p.idx) # skip '::' inc(p.idx) # skip '::'
addSon(result, parseLiteralBlock(p)) add(result, parseLiteralBlock(p))
break break
else: else:
parseInline(p, result) parseInline(p, result)
@ -1222,7 +1204,7 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
getColumns(p, cols) getColumns(p, cols)
setlen(row, len(cols)) setlen(row, len(cols))
if a != nil: if a != nil:
for j in 0..rsonsLen(a)-1: a.sons[j].kind = rnTableHeaderCell for j in 0..len(a)-1: a.sons[j].kind = rnTableHeaderCell
if p.tok[p.idx].kind == tkEof: break if p.tok[p.idx].kind == tkEof: break
for j in countup(0, high(row)): row[j] = "" for j in countup(0, high(row)): row[j] = ""
# the following while loop iterates over the lines a single cell may span: # the following while loop iterates over the lines a single cell may span:
@ -1248,9 +1230,9 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
q.filename = p.filename q.filename = p.filename
getTokens(row[j], false, q.tok) getTokens(row[j], false, q.tok)
b = newRstNode(rnTableDataCell) b = newRstNode(rnTableDataCell)
addSon(b, parseDoc(q)) add(b, parseDoc(q))
addSon(a, b) add(a, b)
addSon(result, a) add(result, a)
proc parseTransition(p: var TRstParser): PRstNode = proc parseTransition(p: var TRstParser): PRstNode =
result = newRstNode(rnTransition) result = newRstNode(rnTransition)
@ -1267,7 +1249,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
if p.tok[p.idx].kind == tkIndent: if p.tok[p.idx].kind == tkIndent:
inc(p.idx) inc(p.idx)
if p.tok[p.idx - 1].ival > currInd(p): if p.tok[p.idx - 1].ival > currInd(p):
addSon(result, newRstNode(rnLeaf, " ")) add(result, newRstNode(rnLeaf, " "))
else: else:
break break
else: else:
@ -1288,7 +1270,7 @@ proc parseBulletList(p: var TRstParser): PRstNode =
while true: while true:
var item = newRstNode(rnBulletItem) var item = newRstNode(rnBulletItem)
parseSection(p, item) parseSection(p, item)
addSon(result, item) add(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
(p.tok[p.idx + 1].symbol == bullet) and (p.tok[p.idx + 1].symbol == bullet) and
(p.tok[p.idx + 2].kind == tkWhite): (p.tok[p.idx + 2].kind == tkWhite):
@ -1309,7 +1291,7 @@ proc parseOptionList(p: var TRstParser): PRstNode =
if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1): if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1):
inc(p.idx) inc(p.idx)
break break
addSon(a, newLeaf(p)) add(a, newLeaf(p))
inc(p.idx) inc(p.idx)
var j = tokenAfterNewline(p) var j = tokenAfterNewline(p)
if (j > 0) and (p.tok[j - 1].kind == tkIndent) and if (j > 0) and (p.tok[j - 1].kind == tkIndent) and
@ -1320,9 +1302,9 @@ proc parseOptionList(p: var TRstParser): PRstNode =
else: else:
parseLine(p, b) parseLine(p, b)
if (p.tok[p.idx].kind == tkIndent): inc(p.idx) if (p.tok[p.idx].kind == tkIndent): inc(p.idx)
addSon(c, a) add(c, a)
addSon(c, b) add(c, b)
addSon(result, c) add(result, c)
else: else:
break break
@ -1345,9 +1327,9 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
var b = newRstNode(rnDefBody) var b = newRstNode(rnDefBody)
parseSection(p, b) parseSection(p, b)
var c = newRstNode(rnDefItem) var c = newRstNode(rnDefItem)
addSon(c, a) add(c, a)
addSon(c, b) add(c, b)
addSon(result, c) add(result, c)
popInd(p) popInd(p)
else: else:
p.idx = j p.idx = j
@ -1360,7 +1342,7 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
nil nil
else: else:
break break
if rsonsLen(result) == 0: result = nil if len(result) == 0: result = nil
proc parseEnumList(p: var TRstParser): PRstNode = proc parseEnumList(p: var TRstParser): PRstNode =
const const
@ -1381,7 +1363,7 @@ proc parseEnumList(p: var TRstParser): PRstNode =
while true: while true:
var item = newRstNode(rnEnumItem) var item = newRstNode(rnEnumItem)
parseSection(p, item) parseSection(p, item)
addSon(result, item) add(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
match(p, p.idx + 1, wildcards[w]): match(p, p.idx + 1, wildcards[w]):
inc(p.idx, wildpos[w] + 4) inc(p.idx, wildpos[w] + 4)
@ -1394,7 +1376,7 @@ proc parseEnumList(p: var TRstParser): PRstNode =
proc sonKind(father: PRstNode, i: int): TRstNodeKind = proc sonKind(father: PRstNode, i: int): TRstNodeKind =
result = rnLeaf result = rnLeaf
if i < rsonsLen(father): result = father.sons[i].kind if i < len(father): result = father.sons[i].kind
proc parseSection(p: var TRstParser, result: PRstNode) = proc parseSection(p: var TRstParser, result: PRstNode) =
while true: while true:
@ -1407,7 +1389,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
pushInd(p, p.tok[p.idx].ival) pushInd(p, p.tok[p.idx].ival)
var a = newRstNode(rnBlockQuote) var a = newRstNode(rnBlockQuote)
parseSection(p, a) parseSection(p, a)
addSon(result, a) add(result, a)
popInd(p) popInd(p)
else: else:
leave = true leave = true
@ -1424,7 +1406,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
of rnLineblock: a = parseLineBlock(p) of rnLineblock: a = parseLineBlock(p)
of rnDirective: a = parseDotDot(p) of rnDirective: a = parseDotDot(p)
of rnEnumList: a = parseEnumList(p) of rnEnumList: a = parseEnumList(p)
of rnLeaf: rstMessage(p, errNewSectionExpected) of rnLeaf: rstMessage(p, meNewSectionExpected)
of rnParagraph: nil of rnParagraph: nil
of rnDefList: a = parseDefinitionList(p) of rnDefList: a = parseDefinitionList(p)
of rnFieldList: of rnFieldList:
@ -1441,19 +1423,19 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
if a == nil and k != rnDirective: if a == nil and k != rnDirective:
a = newRstNode(rnParagraph) a = newRstNode(rnParagraph)
parseParagraph(p, a) parseParagraph(p, a)
addSonIfNotNil(result, a) addIfNotNil(result, a)
if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph: if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
result.sons[0].kind = rnInner result.sons[0].kind = rnInner
proc parseSectionWrapper(p: var TRstParser): PRstNode = proc parseSectionWrapper(p: var TRstParser): PRstNode =
result = newRstNode(rnInner) result = newRstNode(rnInner)
parseSection(p, result) parseSection(p, result)
while (result.kind == rnInner) and (rsonsLen(result) == 1): while (result.kind == rnInner) and (len(result) == 1):
result = result.sons[0] result = result.sons[0]
proc parseDoc(p: var TRstParser): PRstNode = proc parseDoc(p: var TRstParser): PRstNode =
result = parseSectionWrapper(p) result = parseSectionWrapper(p)
if p.tok[p.idx].kind != tkEof: rstMessage(p, errGeneralParseError) if p.tok[p.idx].kind != tkEof: rstMessage(p, meGeneralParseError)
type type
TDirFlag = enum TDirFlag = enum
@ -1471,24 +1453,24 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
while True: while True:
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkWord, tkOther, tkPunct, tkAdornment: of tkWord, tkOther, tkPunct, tkAdornment:
addSon(args, newLeaf(p)) add(args, newLeaf(p))
inc(p.idx) inc(p.idx)
else: break else: break
elif argIsWord in flags: elif argIsWord in flags:
while p.tok[p.idx].kind == tkWhite: inc(p.idx) while p.tok[p.idx].kind == tkWhite: inc(p.idx)
if p.tok[p.idx].kind == tkWord: if p.tok[p.idx].kind == tkWord:
addSon(args, newLeaf(p)) add(args, newLeaf(p))
inc(p.idx) inc(p.idx)
else: else:
args = nil args = nil
else: else:
parseLine(p, args) parseLine(p, args)
addSon(result, args) add(result, args)
if hasOptions in flags: if hasOptions in flags:
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and
(p.tok[p.idx + 1].symbol == ":"): (p.tok[p.idx + 1].symbol == ":"):
options = parseFields(p) options = parseFields(p)
addSon(result, options) add(result, options)
proc indFollows(p: TRstParser): bool = proc indFollows(p: TRstParser): bool =
result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p) result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p)
@ -1500,9 +1482,9 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags,
pushInd(p, p.tok[p.idx].ival) pushInd(p, p.tok[p.idx].ival)
var content = contentParser(p) var content = contentParser(p)
popInd(p) popInd(p)
addSon(result, content) add(result, content)
else: else:
addSon(result, nil) add(result, nil)
proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode = proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
if indFollows(p): if indFollows(p):
@ -1530,14 +1512,14 @@ proc dirInclude(p: var TRstParser): PRstNode =
result = nil result = nil
var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil) var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil)
var filename = strip(addNodes(n.sons[0])) var filename = strip(addNodes(n.sons[0]))
var path = findFile(filename) var path = p.s.findFile(filename)
if path == "": if path == "":
rstMessage(p, errCannotOpenFile, filename) rstMessage(p, meCannotOpenFile, filename)
else: else:
# XXX: error handling; recursive file inclusion! # XXX: error handling; recursive file inclusion!
if getFieldValue(n, "literal") != "": if getFieldValue(n, "literal") != "":
result = newRstNode(rnLiteralBlock) result = newRstNode(rnLiteralBlock)
addSon(result, newRstNode(rnLeaf, readFile(path))) add(result, newRstNode(rnLeaf, readFile(path)))
else: else:
var q: TRstParser var q: TRstParser
initParser(q, p.s) initParser(q, p.s)
@ -1552,17 +1534,17 @@ proc dirCodeBlock(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock) result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock)
var filename = strip(getFieldValue(result, "file")) var filename = strip(getFieldValue(result, "file"))
if filename != "": if filename != "":
var path = findFile(filename) var path = p.s.findFile(filename)
if path == "": rstMessage(p, errCannotOpenFile, filename) if path == "": rstMessage(p, meCannotOpenFile, filename)
var n = newRstNode(rnLiteralBlock) var n = newRstNode(rnLiteralBlock)
addSon(n, newRstNode(rnLeaf, readFile(path))) add(n, newRstNode(rnLeaf, readFile(path)))
result.sons[2] = n result.sons[2] = n
result.kind = rnCodeBlock result.kind = rnCodeBlock
proc dirContainer(p: var TRstParser): PRstNode = proc dirContainer(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasArg}, parseSectionWrapper) result = parseDirective(p, {hasArg}, parseSectionWrapper)
assert(result.kind == rnDirective) assert(result.kind == rnDirective)
assert(rsonsLen(result) == 3) assert(len(result) == 3)
result.kind = rnContainer result.kind = rnContainer
proc dirImage(p: var TRstParser): PRstNode = proc dirImage(p: var TRstParser): PRstNode =
@ -1590,16 +1572,16 @@ proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
contentParser: TSectionParser) = contentParser: TSectionParser) =
var filename = getFieldValue(result, "file") var filename = getFieldValue(result, "file")
if filename.len > 0: if filename.len > 0:
var path = findFile(filename) var path = p.s.findFile(filename)
if path.len == 0: if path.len == 0:
rstMessage(p, errCannotOpenFile, filename) rstMessage(p, meCannotOpenFile, filename)
else: else:
var f = readFile(path) var f = readFile(path)
result = newRstNode(kind) result = newRstNode(kind)
addSon(result, newRstNode(rnLeaf, f)) add(result, newRstNode(rnLeaf, f))
else: else:
result.kind = kind result.kind = kind
addSon(result, parseDirBody(p, contentParser)) add(result, parseDirBody(p, contentParser))
proc dirRaw(p: var TRstParser): PRstNode = proc dirRaw(p: var TRstParser): PRstNode =
# #
@ -1617,7 +1599,7 @@ proc dirRaw(p: var TRstParser): PRstNode =
elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0: elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0:
dirRawAux(p, result, rnRawLatex, parseLiteralBlock) dirRawAux(p, result, rnRawLatex, parseLiteralBlock)
else: else:
rstMessage(p, errInvalidDirectiveX, result.sons[0].text) rstMessage(p, meInvalidDirective, result.sons[0].text)
else: else:
dirRawAux(p, result, rnRaw, parseSectionWrapper) dirRawAux(p, result, rnRaw, parseSectionWrapper)
@ -1639,10 +1621,10 @@ proc parseDotDot(p: var TRstParser): PRstNode =
if roSupportRawDirective in p.s.options: if roSupportRawDirective in p.s.options:
result = dirRaw(p) result = dirRaw(p)
else: else:
rstMessage(p, errInvalidDirectiveX, d) rstMessage(p, meInvalidDirective, d)
of dkCodeblock: result = dirCodeBlock(p) of dkCodeblock: result = dirCodeBlock(p)
of dkIndex: result = dirIndex(p) of dkIndex: result = dirIndex(p)
else: rstMessage(p, errInvalidDirectiveX, d) else: rstMessage(p, meInvalidDirective, d)
popInd(p) popInd(p)
elif match(p, p.idx, " _"): elif match(p, p.idx, " _"):
# hyperlink target: # hyperlink target:
@ -1665,7 +1647,7 @@ proc parseDotDot(p: var TRstParser): PRstNode =
inc(p.idx) inc(p.idx)
b = dirImage(p) b = dirImage(p)
else: else:
rstMessage(p, errInvalidDirectiveX, p.tok[p.idx].symbol) rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol)
setSub(p, addNodes(a), b) setSub(p, addNodes(a), b)
elif match(p, p.idx, " ["): elif match(p, p.idx, " ["):
# footnotes, citations # footnotes, citations
@ -1689,27 +1671,28 @@ proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
var key = addNodes(n) var key = addNodes(n)
var e = getEnv(key) var e = getEnv(key)
if e != "": result = newRstNode(rnLeaf, e) if e != "": result = newRstNode(rnLeaf, e)
else: rstMessage(p, warnUnknownSubstitutionX, key) else: rstMessage(p, mwUnknownSubstitution, key)
of rnRef: of rnRef:
var y = findRef(p, rstnodeToRefname(n)) var y = findRef(p, rstnodeToRefname(n))
if y != nil: if y != nil:
result = newRstNode(rnHyperlink) result = newRstNode(rnHyperlink)
n.kind = rnInner n.kind = rnInner
addSon(result, n) add(result, n)
addSon(result, y) add(result, y)
of rnLeaf: of rnLeaf:
nil nil
of rnContents: of rnContents:
p.hasToc = true p.hasToc = true
else: else:
for i in countup(0, rsonsLen(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i]) for i in countup(0, len(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
proc rstParse(text, filename: string, proc rstParse*(text, filename: string,
line, column: int, hasToc: var bool, line, column: int, hasToc: var bool,
options: TRstParseOptions): PRstNode = options: TRstParseOptions,
findFile: TFindFileHandler = nil,
msgHandler: TMsgHandler = nil): PRstNode =
var p: TRstParser var p: TRstParser
if isNil(text): rawMessage(errCannotOpenFile, filename) initParser(p, newSharedState(options, findFile, msgHandler))
initParser(p, newSharedState(options))
p.filename = filename p.filename = filename
p.line = line p.line = line
p.col = column p.col = column

View file

@ -0,0 +1,288 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements an AST for the `reStructuredText`:idx parser.
import strutils
type
TRstNodeKind* = enum ## the possible node kinds of an PRstNode
rnInner, # an inner node or a root
rnHeadline, # a headline
rnOverline, # an over- and underlined headline
rnTransition, # a transition (the ------------- <hr> thingie)
rnParagraph, # a paragraph
rnBulletList, # a bullet list
rnBulletItem, # a bullet item
rnEnumList, # an enumerated list
rnEnumItem, # an enumerated item
rnDefList, # a definition list
rnDefItem, # an item of a definition list consisting of ...
rnDefName, # ... a name part ...
rnDefBody, # ... and a body part ...
rnFieldList, # a field list
rnField, # a field item
rnFieldName, # consisting of a field name ...
rnFieldBody, # ... and a field body
rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
rnLineBlock, # the | thingie
rnLineBlockItem, # sons of the | thing
rnBlockQuote, # text just indented
rnTable, rnGridTable, rnTableRow, rnTableHeaderCell, rnTableDataCell,
rnLabel, # used for footnotes and other things
rnFootnote, # a footnote
rnCitation, # similar to footnote
rnStandaloneHyperlink, rnHyperlink, rnRef, rnDirective, # a directive
rnDirArg, rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock,
rnRawHtml, rnRawLatex,
rnContainer, # ``container`` directive
rnIndex, # index directve:
# .. index::
# key
# * `file#id <file#id>`_
# * `file#id <file#id>'_
rnSubstitutionDef, # a definition of a substitution
rnGeneralRole, # Inline markup:
rnSub, rnSup, rnIdx,
rnEmphasis, # "*"
rnStrongEmphasis, # "**"
rnTripleEmphasis, # "***"
rnInterpretedText, # "`"
rnInlineLiteral, # "``"
rnSubstitutionReferences, # "|"
rnSmiley, # some smiley
rnLeaf # a leaf; the node's text field contains the
# leaf val
PRSTNode* = ref TRstNode ## an RST node
TRstNodeSeq* = seq[PRstNode]
TRSTNode* {.acyclic, final.} = object ## an RST node's description
kind*: TRstNodeKind ## the node's kind
text*: string ## valid for leafs in the AST; and the title of
## the document or the section
level*: int ## valid for some node kinds
sons*: TRstNodeSeq ## the node's sons
proc len*(n: PRstNode): int =
result = len(n.sons)
proc newRstNode*(kind: TRstNodeKind): PRstNode =
new(result)
result.sons = @[]
result.kind = kind
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
result = newRstNode(kind)
result.text = s
proc lastSon*(n: PRstNode): PRstNode =
result = n.sons[len(n.sons)-1]
proc add*(father, son: PRstNode) =
add(father.sons, son)
proc addIfNotNil*(father, son: PRstNode) =
if son != nil: add(father, son)
type
TRenderContext {.pure.} = object
indent: int
verbatim: int
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string)
proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
for i in countup(0, len(n) - 1):
renderRstToRst(d, n.sons[i], result)
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
# this is needed for the index generation; it may also be useful for
# debugging, but most code is already debugged...
const
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
if n == nil: return
var ind = repeatChar(d.indent)
case n.kind
of rnInner:
renderRstSons(d, n, result)
of rnHeadline:
result.add("\n")
result.add(ind)
let oldLen = result.len
renderRstSons(d, n, result)
let HeadlineLen = result.len - oldLen
result.add("\n")
result.add(ind)
result.add repeatChar(HeadlineLen, lvlToChar[n.level])
of rnOverline:
result.add("\n")
result.add(ind)
var headline = ""
renderRstSons(d, n, headline)
let lvl = repeatChar(headline.Len - d.indent, lvlToChar[n.level])
result.add(lvl)
result.add("\n")
result.add(headline)
result.add("\n")
result.add(ind)
result.add(lvl)
of rnTransition:
result.add("\n\n")
result.add(ind)
result.add repeatChar(78-d.indent, '-')
result.add("\n\n")
of rnParagraph:
result.add("\n\n")
result.add(ind)
renderRstSons(d, n, result)
of rnBulletItem:
inc(d.indent, 2)
var tmp = ""
renderRstSons(d, n, tmp)
if tmp.len > 0:
result.add("\n")
result.add(ind)
result.add("* ")
result.add(tmp)
dec(d.indent, 2)
of rnEnumItem:
inc(d.indent, 4)
var tmp = ""
renderRstSons(d, n, tmp)
if tmp.len > 0:
result.add("\n")
result.add(ind)
result.add("(#) ")
result.add(tmp)
dec(d.indent, 4)
of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
renderRstSons(d, n, result)
of rnDefName:
result.add("\n\n")
result.add(ind)
renderRstSons(d, n, result)
of rnDefBody:
inc(d.indent, 2)
if n.sons[0].kind != rnBulletList:
result.add("\n")
result.add(ind)
result.add(" ")
renderRstSons(d, n, result)
dec(d.indent, 2)
of rnField:
var tmp = ""
renderRstToRst(d, n.sons[0], tmp)
var L = max(tmp.len + 3, 30)
inc(d.indent, L)
result.add "\n"
result.add ind
result.add ':'
result.add tmp
result.add ':'
result.add repeatChar(L - tmp.len - 2)
renderRstToRst(d, n.sons[1], result)
dec(d.indent, L)
of rnLineBlockItem:
result.add("\n")
result.add(ind)
result.add("| ")
renderRstSons(d, n, result)
of rnBlockQuote:
inc(d.indent, 2)
renderRstSons(d, n, result)
dec(d.indent, 2)
of rnRef:
result.add("`")
renderRstSons(d, n, result)
result.add("`_")
of rnHyperlink:
result.add('`')
renderRstToRst(d, n.sons[0], result)
result.add(" <")
renderRstToRst(d, n.sons[1], result)
result.add(">`_")
of rnGeneralRole:
result.add('`')
renderRstToRst(d, n.sons[0],result)
result.add("`:")
renderRstToRst(d, n.sons[1],result)
result.add(':')
of rnSub:
result.add('`')
renderRstSons(d, n, result)
result.add("`:sub:")
of rnSup:
result.add('`')
renderRstSons(d, n, result)
result.add("`:sup:")
of rnIdx:
result.add('`')
renderRstSons(d, n, result)
result.add("`:idx:")
of rnEmphasis:
result.add("*")
renderRstSons(d, n, result)
result.add("*")
of rnStrongEmphasis:
result.add("**")
renderRstSons(d, n, result)
result.add("**")
of rnTripleEmphasis:
result.add("***")
renderRstSons(d, n, result)
result.add("***")
of rnInterpretedText:
result.add('`')
renderRstSons(d, n, result)
result.add('`')
of rnInlineLiteral:
inc(d.verbatim)
result.add("``")
renderRstSons(d, n, result)
result.add("``")
dec(d.verbatim)
of rnSmiley:
result.add(n.text)
of rnLeaf:
if d.verbatim == 0 and n.text == "\\":
result.add("\\\\") # XXX: escape more special characters!
else:
result.add(n.text)
of rnIndex:
result.add("\n\n")
result.add(ind)
result.add(".. index::\n")
inc(d.indent, 3)
if n.sons[2] != nil: renderRstSons(d, n.sons[2], result)
dec(d.indent, 3)
of rnContents:
result.add("\n\n")
result.add(ind)
result.add(".. contents::")
else:
result.add("Error: cannot render: " & $n.kind)
proc renderRstToRst*(n: PRstNode, result: var string) =
## renders `n` into its string representation and appends to `result`.
var d: TRenderContext
renderRstToRst(d, n, result)

View file

@ -0,0 +1,87 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a generator of HTML/Latex from `reStructuredText`:idx.
import strutils, strtabs, rstast
type
TOutputTarget* = enum ## which document type to generate
outHtml, # output is HTML
outLatex # output is Latex
proc addXmlChar(dest: var string, c: Char) =
case c
of '&': add(dest, "&amp;")
of '<': add(dest, "&lt;")
of '>': add(dest, "&gt;")
of '\"': add(dest, "&quot;")
else: add(dest, c)
proc addRtfChar(dest: var string, c: Char) =
case c
of '{': add(dest, "\\{")
of '}': add(dest, "\\}")
of '\\': add(dest, "\\\\")
else: add(dest, c)
proc addTexChar(dest: var string, c: Char) =
case c
of '_': add(dest, "\\_")
of '{': add(dest, "\\symbol{123}")
of '}': add(dest, "\\symbol{125}")
of '[': add(dest, "\\symbol{91}")
of ']': add(dest, "\\symbol{93}")
of '\\': add(dest, "\\symbol{92}")
of '$': add(dest, "\\$")
of '&': add(dest, "\\&")
of '#': add(dest, "\\#")
of '%': add(dest, "\\%")
of '~': add(dest, "\\symbol{126}")
of '@': add(dest, "\\symbol{64}")
of '^': add(dest, "\\symbol{94}")
of '`': add(dest, "\\symbol{96}")
else: add(dest, c)
var splitter*: string = "<wbr />"
proc escChar*(target: TOutputTarget, dest: var string, c: Char) {.inline.} =
case target
of outHtml: addXmlChar(dest, c)
of outLatex: addTexChar(dest, c)
proc nextSplitPoint*(s: string, start: int): int =
result = start
while result < len(s) + 0:
case s[result]
of '_': return
of 'a'..'z':
if result + 1 < len(s) + 0:
if s[result + 1] in {'A'..'Z'}: return
else: nil
inc(result)
dec(result) # last valid index
proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
result = ""
if splitAfter >= 0:
var partLen = 0
var j = 0
while j < len(s):
var k = nextSplitPoint(s, j)
if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
partLen = 0
add(result, splitter)
for i in countup(j, k): escChar(target, result, s[i])
inc(partLen, k - j + 1)
j = k + 1
else:
for i in countup(0, len(s) - 1): escChar(target, result, s[i])

View file

@ -42,9 +42,10 @@ Library Additions
- Added overload for ``system.items`` that can be used to iterate over the - Added overload for ``system.items`` that can be used to iterate over the
values of an enum. values of an enum.
- Added ``system.TInteger`` and ``system.TNumber`` type classes matching - Added ``system.TInteger`` and ``system.TNumber`` type classes matching
any of the corresponding type available in nimrod. any of the corresponding types available in nimrod.
- Added ``system.clamp`` to limit a value within an interval ``[a, b]``. - Added ``system.clamp`` to limit a value within an interval ``[a, b]``.
- Added ``strutils.continuesWith``. - Added ``strutils.continuesWith``.
- Added ``system.getStackTrace``.
- The GC supports (soft) realtime systems via ``GC_setMaxPause`` - The GC supports (soft) realtime systems via ``GC_setMaxPause``
and ``GC_step`` procs. and ``GC_step`` procs.