added system.getStackTrace; docgen refactoring (incomplete)

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

View File

@@ -13,11 +13,14 @@
import
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 CommandRst2Html*()
proc CommandRst2TeX*()
#proc CommandBuildIndex*()
# implementation
type
@@ -29,9 +32,9 @@ type
TMetaEnum = enum
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
TDocumentor {.final.} = object # contains a module's documentation
target: TOutputTarget
options: TRstParseOptions
filename*: string # filename of the source file; without extension
basedir*: string # base directory (where to put the documentation)
modDesc*: PRope # module description
id*: int # for generating IDs
splitAfter*: int # split too long entries in the TOC
@@ -40,13 +43,10 @@ type
toc*, section*: TSections
indexFile*, theIndex*: PRstNode
indexValFilename*: string
indent*, verbatim*: int # for code generation
meta*: array[TMetaEnum, PRope]
PDoc = ref TDocumentor
var splitter: string = "<wbr />"
proc findIndexNode(n: PRstNode): PRstNode =
if n == nil:
result = nil
@@ -59,10 +59,31 @@ proc findIndexNode(n: PRstNode): PRstNode =
result = result.sons[0]
else:
result = nil
for i in countup(0, rsonsLen(n) - 1):
for i in countup(0, len(n) - 1):
result = findIndexNode(n.sons[i])
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) =
var
h: PRstNode
@@ -71,7 +92,7 @@ proc initIndexFile(d: PDoc) =
gIndexFile = addFileExt(gIndexFile, "txt")
d.indexValFilename = changeFileExt(extractFilename(d.filename), HtmlExt)
if ExistsFile(gIndexFile):
d.indexFile = rstParse(readFile(gIndexFile), gIndexFile, 0, 1,
d.indexFile = parseRst(readFile(gIndexFile), gIndexFile, 0, 1,
dummyHasToc, {roSupportRawDirective})
d.theIndex = findIndexNode(d.indexFile)
if (d.theIndex == nil) or (d.theIndex.kind != rnDefList):
@@ -81,17 +102,19 @@ proc initIndexFile(d: PDoc) =
d.indexFile = newRstNode(rnInner)
h = newRstNode(rnOverline)
h.level = 1
addSon(h, newRstNode(rnLeaf, "Index"))
addSon(d.indexFile, h)
add(h, newRstNode(rnLeaf, "Index"))
add(d.indexFile, h)
h = newRstNode(rnIndex)
addSon(h, nil) # no argument
addSon(h, nil) # no options
add(h, nil) # no argument
add(h, nil) # no options
d.theIndex = newRstNode(rnDefList)
addSon(h, d.theIndex)
addSon(d.indexFile, h)
add(h, d.theIndex)
add(d.indexFile, h)
proc newDocumentor(filename: string): PDoc =
new(result)
if gCmd != cmdRst2Tex: result.target = outHtml
else: result.target = outLatex
result.tocPart = @[]
result.filename = filename
result.id = 100
@@ -159,72 +182,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
if (frmt[i] != '$'): inc(i)
else: break
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 =
if gCmd != cmdRst2Tex: result = xml
else: result = tex
@@ -241,17 +199,17 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope
proc renderAux(d: PDoc, n: PRstNode, outer: string = "$1"): PRope =
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])
proc setIndexForSourceTerm(d: PDoc, name: PRstNode, id: int) =
if d.theIndex == nil: return
var h = newRstNode(rnHyperlink)
var a = newRstNode(rnLeaf, d.indexValFilename & disp("#", "") & $id)
addSon(h, a)
addSon(h, a)
add(h, a)
add(h, a)
a = newRstNode(rnIdx)
addSon(a, name)
add(a, name)
setIndexPair(d.theIndex, a, h)
proc renderIndexTerm(d: PDoc, n: PRstNode): PRope =
@@ -260,14 +218,14 @@ proc renderIndexTerm(d: PDoc, n: PRstNode): PRope =
[toRope(d.id), renderAux(d, n)])
var h = newRstNode(rnHyperlink)
var a = newRstNode(rnLeaf, d.indexValFilename & disp("#", "") & $d.id)
addSon(h, a)
addSon(h, a)
add(h, a)
add(h, a)
setIndexPair(d.theIndex, n, h)
proc genComment(d: PDoc, n: PNode): PRope =
var dummyHasToc: bool
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),
dummyHasToc,
d.options + {roSkipPounds}))
@@ -294,16 +252,16 @@ proc isVisible(n: PNode): bool =
elif n.kind == nkPragmaExpr:
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
of nkPostfix: result = getName(n.sons[1], splitAfter)
of nkPragmaExpr: result = getName(n.sons[0], splitAfter)
of nkSym: result = esc(n.sym.name.s, splitAfter)
of nkIdent: result = esc(n.ident.s, splitAfter)
of nkPostfix: result = getName(d, n.sons[1], splitAfter)
of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
of nkSym: result = esc(d.target, n.sym.name.s, splitAfter)
of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
of nkAccQuoted:
result = esc("`")
for i in 0.. <n.len: result.add(getName(n[i], splitAfter))
result.add esc("`")
result = esc(d.target, "`")
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
result.add esc(d.target, "`")
else:
internalError(n.info, "getName()")
result = ""
@@ -323,7 +281,7 @@ proc getRstName(n: PNode): PRstNode =
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
if not isVisible(nameNode): return
var name = toRope(getName(nameNode))
var name = toRope(getName(d, nameNode))
var result: PRope = nil
var literal = ""
var kind = tkEof
@@ -338,28 +296,28 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
break
of tkComment:
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
[toRope(esc(literal))])
[toRope(esc(d.target, literal))])
of tokKeywordLow..tokKeywordHigh:
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
[toRope(literal)])
of tkOpr:
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
[toRope(esc(literal))])
[toRope(esc(d.target, literal))])
of tkStrLit..tkTripleStrLit:
dispA(result, "<span class=\"StringLit\">$1</span>",
"\\spanStringLit{$1}", [toRope(esc(literal))])
"\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
of tkCharLit:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[toRope(esc(literal))])
[toRope(esc(d.target, literal))])
of tkIntLit..tkInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [toRope(esc(literal))])
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
of tkFloatLit..tkFloat64Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [toRope(esc(literal))])
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
of tkSymbol:
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:
app(result, literal)
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
@@ -368,19 +326,19 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[toRope(esc(literal))])
[toRope(esc(d.target, literal))])
inc(d.id)
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
["name", "header", "desc", "itemID"],
[name, result, comm, toRope(d.id)]))
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
["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)
proc renderHeadline(d: PDoc, n: PRstNode): PRope =
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))
if d.hasToc:
var length = len(d.tocPart)
@@ -400,7 +358,7 @@ proc renderHeadline(d: PDoc, n: PRstNode): PRope =
proc renderOverline(d: PDoc, n: PRstNode): PRope =
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
if d.meta[metaTitle] == nil:
d.meta[metaTitle] = t
@@ -411,123 +369,7 @@ proc renderOverline(d: PDoc, n: PRstNode): PRope =
"\\rstov$4{$3}\\label{$2}$n", [toRope(n.level),
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 =
result = dispF(
"<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
while j <= high(d.tocPart):
var a = abs(d.tocPart[j].n.level)
if (a == lvl):
if a == lvl:
app(result, renderTocEntry(d, d.tocPart[j]))
inc(j)
elif (a > lvl):
elif a > lvl:
app(result, renderTocEntries(d, j, a))
else:
break
@@ -566,7 +408,7 @@ proc renderImage(d: PDoc, n: PRstNode): PRope =
if options != nil: options = dispF("$1", "[$1]", [options])
result = dispF("<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
[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 =
result = dispF(
@@ -596,13 +438,13 @@ proc renderCodeBlock(d: PDoc, n: PRstNode): PRope =
case g.kind
of gtEof: break
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:
dispA(result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
toRope(esc(substr(m.text, g.start + 0, g.length + g.start - 1))),
toRope(tokenClassToStr[g.kind])])
toRope(esc(d.target, substr(m.text, g.start, g.length+g.start-1))),
toRope(tokenClassToStr[g.kind])])
deinitGeneralTokenizer(g)
if result != nil:
if result != nil:
result = dispF("<pre>$1</pre>", "\\begin{rstpre}$n$1$n\\end{rstpre}$n",
[result])
@@ -614,13 +456,13 @@ proc renderContainer(d: PDoc, n: PRstNode): PRope =
proc texColumns(n: PRstNode): string =
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 =
var b = false
if gCmd == cmdRst2Tex:
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 d.meta[metaAuthor] == nil:
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 rnFieldList:
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]))
if result != nil:
result = dispf(
@@ -705,9 +547,9 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
"\\begin{table}\\begin{rsttab}{" &
texColumns(n) & "|}$n\\hline$n$1\\end{rsttab}\\end{table}"))
of rnTableRow:
if rsonsLen(n) >= 1:
if len(n) >= 1:
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])])
result = dispf("<tr>$1</tr>$n", "$1\\\\$n\\hline$n", [result])
else:
@@ -770,7 +612,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
"\\texttt{$1}"))
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 rnTitle: d.meta[metaTitle] = renderRstToOut(d, n.sons[0])
@@ -863,7 +705,9 @@ proc genOutFile(d: PDoc): PRope =
proc generateIndex(d: PDoc) =
if d.theIndex != nil:
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) =
var content = genOutFile(d)
@@ -886,7 +730,7 @@ proc CommandRstAux(filename, outExt: string) =
var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen)
initIndexFile(d)
var rst = rstParse(readFile(filen), filen, 0, 1, d.hasToc,
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
{roSupportRawDirective})
d.modDesc = renderRstToOut(d, rst)
writeOutput(d, filename, outExt)

View File

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

View File

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

View File

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

View File

@@ -33,6 +33,7 @@ Files: "doc/*.pdf"
Files: "doc/*.ini"
Start: "doc/overview.html"
[Other]
Files: "readme.txt;install.txt;contributors.txt"
Files: "configure;makefile"
@@ -56,6 +57,9 @@ Files: "compiler/*.nim"
Files: "build/empty.txt"
Files: "bin/empty.txt"
Files: "packages/docutils/*.nim"
[Lib]
Files: "lib/nimbase.h;lib/cycle.h"
Files: "lib/*.nim"
@@ -72,6 +76,7 @@ Files: "lib/wrappers/cairo/*.nim"
Files: "lib/wrappers/gtk/*.nim"
Files: "lib/wrappers/lua/*.nim"
Files: "lib/wrappers/opengl/*.nim"
Files: "lib/wrappers/readline/*.nim"
Files: "lib/wrappers/sdl/*.nim"
Files: "lib/wrappers/x11/*.nim"
Files: "lib/wrappers/zip/*.nim"
@@ -81,6 +86,7 @@ Files: "lib/windows/*.nim"
Files: "lib/posix/*.nim"
Files: "lib/ecmas/*.nim"
[Other]
Files: "examples/*.nim"
Files: "examples/gtk/*.nim"
@@ -99,6 +105,7 @@ Files: "examples/*.txt"
Files: "examples/*.cfg"
Files: "examples/*.tmpl"
[Windows]
Files: "bin/nimrod.exe"
Files: "bin/c2nim.exe"
@@ -112,21 +119,26 @@ Files: "start.bat"
BinPath: r"bin;dist\mingw\bin;dist"
InnoSetup: "Yes"
[UnixBin]
Files: "bin/nimrod"
[Unix]
InstallScript: "yes"
UninstallScript: "yes"
[InnoSetup]
path = r"c:\programme\inno setup 5\iscc.exe"
flags = "/Q"
[C_Compiler]
path = r""
flags = "-w"
[deb]
buildDepends: "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
result = ""
proc FindFile*(f: string): string =
proc FindFile*(f: string): string {.procvar.} =
result = rawFindFile(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*()
## writes the current stack trace to ``stderr``. This is only works
## for debug builds.
proc getStackTrace*(): string
## gets the current stack trace. This is only works for debug builds.
{.push stack_trace: off.}
when hostCPU == "avr":

View File

@@ -246,6 +246,13 @@ proc WriteStackTrace() =
else:
writeToStdErr("No stack traceback available\n")
proc getStackTrace(): string =
when hasSomeStackTrace:
result = ""
rawWriteStackTrace(result)
else:
result = "No stack traceback available\n"
when defined(endb):
var
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
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# Source highlighter for programming or markup languages.
# Currently only few languages are supported, other languages may be added.
# The interface supports one language nested in another.
## Source highlighter for programming or markup languages.
## Currently only few languages are supported, other languages may be added.
## The interface supports one language nested in another.
import
hashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, lexer
import
strutils
type
TTokenClass* = enum
@@ -44,19 +44,15 @@ const
"Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink",
"Label", "Reference", "Other"]
proc getSourceLanguage*(name: string): TSourceLanguage
proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string)
proc deinitGeneralTokenizer*(g: var TGeneralTokenizer)
proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage)
# implementation
nimrodKeywords = slurp("doc/keywords.txt").split
proc getSourceLanguage(name: string): TSourceLanguage =
proc getSourceLanguage*(name: string): TSourceLanguage =
for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)):
if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0:
return i
result = langNone
proc initGeneralTokenizer(g: var TGeneralTokenizer, buf: string) =
proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
g.buf = cstring(buf)
g.kind = low(TTokenClass)
g.start = 0
@@ -66,16 +62,20 @@ proc initGeneralTokenizer(g: var TGeneralTokenizer, buf: string) =
while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
g.pos = pos
proc deinitGeneralTokenizer(g: var TGeneralTokenizer) =
proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) =
nil
proc nimGetKeyword(id: string): TTokenClass =
var i = getIdent(id)
if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
result = gtKeyword
else:
result = gtIdentifier
for k in nimrodKeywords:
if cmpIgnoreStyle(id, k) == 0: return gtKeyword
result = gtIdentifier
when false:
var i = getIdent(id)
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 =
var pos = position
@@ -111,11 +111,16 @@ proc nimNumber(g: var TGeneralTokenizer, position: int): int =
while g.buf[pos] in decChars: inc(pos)
result = nimNumberPostfix(g, pos)
const
OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
proc nimNextToken(g: var TGeneralTokenizer) =
const
hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'}
octChars = {'0'..'7', '_'}
binChars = {'0'..'1', '_'}
SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
var pos = g.pos
g.start = g.pos
if g.state == gtStringLit:
@@ -154,7 +159,7 @@ proc nimNextToken(g: var TGeneralTokenizer) =
while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos)
of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
var id = ""
while g.buf[pos] in lexer.SymChars + {'_'}:
while g.buf[pos] in SymChars + {'_'}:
add(id, g.buf[pos])
inc(pos)
if (g.buf[pos] == '\"'):
@@ -247,15 +252,15 @@ proc nimNextToken(g: var TGeneralTokenizer) =
of '\0':
g.kind = gtEof
else:
if g.buf[pos] in lexer.OpChars:
if g.buf[pos] in OpChars:
g.kind = gtOperator
while g.buf[pos] in lexer.OpChars: inc(pos)
while g.buf[pos] in OpChars: inc(pos)
else:
inc(pos)
g.kind = gtNone
g.length = pos - g.pos
if (g.kind != gtEof) and (g.length <= 0):
InternalError("nimNextToken: " & $(g.buf))
if g.kind != gtEof and g.length <= 0:
assert false, "nimNextToken: produced an empty token"
g.pos = pos
proc generalNumber(g: var TGeneralTokenizer, position: int): int =
@@ -407,7 +412,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
inc(pos)
if hasPreprocessor in flags:
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)
else:
g.kind = gtOperator
@@ -462,14 +467,15 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
of '\0':
g.kind = gtEof
else:
if g.buf[pos] in lexer.OpChars:
if g.buf[pos] in OpChars:
g.kind = gtOperator
while g.buf[pos] in lexer.OpChars: inc(pos)
while g.buf[pos] in OpChars: inc(pos)
else:
inc(pos)
g.kind = gtNone
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
proc cNextToken(g: var TGeneralTokenizer) =
@@ -520,12 +526,12 @@ proc javaNextToken(g: var TGeneralTokenizer) =
"try", "void", "volatile", "while"]
clikeNextToken(g, keywords, {})
proc getNextToken(g: var TGeneralTokenizer, lang: TSourceLanguage) =
proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) =
case lang
of langNone: assert false
of langNimrod: nimNextToken(g)
of langCpp: cppNextToken(g)
of langCsharp: csharpNextToken(g)
of langC: cNextToken(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
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements a *reStructuredText* parser. A large
# subset is provided.
## This module implements a `reStructuredText`:idx parser. A large
## subset is implemented. Some features of the `markdown`:idx: wiki syntax are
## also supported.
import
os, msgs, strutils, hashes, options
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
os, strutils, rstast
type
TRstParseOption* = enum ## options for the RST parser
roSkipPounds, ## skip ``#`` at line beginning (documentation
## embedded in Nimrod comments)
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)
roSupportMarkdown ## support additional features of markdown
TRstParseOptions* = set[TRstParseOption]
PRSTNode* = ref TRstNode
TRstNodeSeq* = seq[PRstNode]
TRSTNode*{.acyclic, final.} = object
kind*: TRstNodeKind
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
TMsgClass* = enum
mcHint = "Hint",
mcWarning = "Warning",
mcError = "Error"
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 addNodes*(n: PRstNode): 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].kind = tkIndent
proc addSon(father, son: PRstNode) =
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
type
TLevelMap = array[Char, int]
TSubstitution{.final.} = object
key*: string
value*: PRstNode
TSharedState {.final.} = object
options: TRstParseOptions # parsing options
uLevel*, oLevel*: int # counters for the section levels
subs*: seq[TSubstitution] # substitutions
refs*: seq[TSubstitution] # references
underlineToLevel*: TLevelMap # Saves for each possible title adornment
# character its level in the
# current document.
# This is for single underline adornments.
overlineToLevel*: TLevelMap # Saves for each possible title adornment
# character its level in the current
# document.
# This is for over-underline adornments.
options: TRstParseOptions # parsing options
uLevel, oLevel: int # counters for the section levels
subs: seq[TSubstitution] # substitutions
refs: seq[TSubstitution] # references
underlineToLevel: TLevelMap # Saves for each possible title adornment
# character its level in the
# current document.
# This is for single underline adornments.
overlineToLevel: TLevelMap # Saves for each possible title adornment
# character its level in the current
# document.
# This is for over-underline adornments.
msgHandler: TMsgHandler # How to handle errors.
findFile: TFindFileHandler # How to find files.
PSharedState = ref TSharedState
TRstParser = object of TObject
@@ -332,21 +279,57 @@ type
line*, col*: int
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)
result.subs = @[]
result.refs = @[]
result.options = options
proc tokInfo(p: TRstParser, tok: TToken): TLineInfo =
result = newLineInfo(p.filename, p.line + tok.line, p.col + tok.col)
result.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler
result.findFile = if isNil(findFile): defaultFindFile else: findFile
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) =
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 =
result = p.indentStack[high(p.indentStack)]
@@ -371,7 +354,7 @@ proc addNodesAux(n: PRstNode, result: var string) =
if n.kind == rnLeaf:
add(result, n.text)
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 =
result = ""
@@ -400,7 +383,7 @@ proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
else:
if (len(r) > 0): b = true
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 =
result = ""
@@ -433,7 +416,7 @@ proc setRef(p: var TRstParser, key: string, value: PRstNode) =
for i in countup(0, length - 1):
if key == p.s.refs[i].key:
if p.s.refs[i].value.addNodes != value.addNodes:
rstMessage(p, warnRedefinitionOfLabel, key)
rstMessage(p, mwRedefinitionOfLabel, key)
p.s.refs[i].value = value
return
@@ -456,7 +439,7 @@ proc cmpNodes(a, b: PRstNode): int =
proc sortIndex(a: PRstNode) =
# we use shellsort here; fast and simple
assert(a.kind == rnDefList)
var N = rsonsLen(a)
var N = len(a)
var h = 1
while true:
h = 3 * h + 1
@@ -478,14 +461,14 @@ proc eqRstNodes(a, b: PRstNode): bool =
if a.kind == rnLeaf:
result = a.text == b.text
else:
if rsonsLen(a) != rsonsLen(b): return
for i in countup(0, rsonsLen(a) - 1):
if len(a) != len(b): return
for i in countup(0, len(a) - 1):
if not eqRstNodes(a.sons[i], b.sons[i]): return
result = true
proc matchesHyperlink(h: PRstNode, filename: string): bool =
if h.kind == rnInner: # this may happen in broken indexes!
assert(rsonsLen(h) == 1)
assert(len(h) == 1)
result = matchesHyperlink(h.sons[0], filename)
elif h.kind == rnHyperlink:
var s = addNodes(h.sons[1])
@@ -498,14 +481,14 @@ proc clearIndex(index: PRstNode, filename: string) =
var
lastItem: int
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)
var val = index.sons[i].sons[1].sons[0]
if val.kind == rnInner: val = val.sons[0]
if val.kind == rnBulletList:
var items = rsonsLen(val)
var items = len(val)
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:
dec(items)
elif matchesHyperlink(val.sons[j].sons[0], filename):
@@ -520,7 +503,7 @@ proc clearIndex(index: PRstNode, filename: string) =
elif matchesHyperlink(val, filename):
index.sons[i] = nil
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 k != i: index.sons[k] = index.sons[i]
inc(k)
@@ -531,28 +514,28 @@ proc setIndexPair(index, key, val: PRstNode) =
assert(index.kind == rnDefList)
assert(key.kind != rnDefName)
a = newRstNode(rnDefName)
addSon(a, key)
for i in countup(0, rsonsLen(index) - 1):
add(a, key)
for i in countup(0, len(index) - 1):
if eqRstNodes(index.sons[i].sons[0], a):
assert(index.sons[i].sons[1].kind == rnDefBody)
e = index.sons[i].sons[1].sons[0]
if e.kind != rnBulletList:
e = newRstNode(rnBulletList)
b = newRstNode(rnBulletItem)
addSon(b, index.sons[i].sons[1].sons[0])
addSon(e, b)
add(b, index.sons[i].sons[1].sons[0])
add(e, b)
index.sons[i].sons[1].sons[0] = e
b = newRstNode(rnBulletItem)
addSon(b, val)
addSon(e, b)
add(b, val)
add(e, b)
return # key already exists
e = newRstNode(rnDefItem)
assert(val.kind != rnDefBody)
b = newRstNode(rnDefBody)
addSon(b, val)
addSon(e, a)
addSon(e, b)
addSon(index, e)
add(b, val)
add(e, a)
add(e, b)
add(index, e)
proc newLeaf(p: var TRstParser): PRstNode =
result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
@@ -562,15 +545,15 @@ proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
while true:
case p.tok[p.idx].kind
of tkWord, tkOther, tkWhite:
addSon(res, newLeaf(p))
add(res, newLeaf(p))
of tkPunct:
if p.tok[p.idx].symbol == endStr:
inc(p.idx)
break
else:
addSon(res, newLeaf(p))
add(res, newLeaf(p))
else:
rstMessage(p, errXexpected, endStr)
rstMessage(p, meExpected, endStr)
break
inc(p.idx)
result = res
@@ -578,12 +561,12 @@ proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
proc untilEol(p: var TRstParser): PRstNode =
result = newRstNode(rnInner)
while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
addSon(result, newLeaf(p))
add(result, newLeaf(p))
inc(p.idx)
proc expect(p: var TRstParser, tok: string) =
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 =
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) =
var sep = - 1
for i in countdown(rsonsLen(n) - 2, 0):
for i in countdown(len(n) - 2, 0):
if n.sons[i].text == "<":
sep = i
break
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(sep + 1, rsonsLen(n) - 2): addSon(b, n.sons[i])
for i in countup(0, sep - incr): add(a, 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 =
result = n
@@ -692,19 +675,19 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
var a = newRstNode(rnInner)
var b = newRstNode(rnInner)
fixupEmbeddedRef(n, a, b)
if rsonsLen(a) == 0:
if len(a) == 0:
result = newRstNode(rnStandaloneHyperlink)
addSon(result, b)
add(result, b)
else:
result = newRstNode(rnHyperlink)
addSon(result, a)
addSon(result, b)
add(result, a)
add(result, b)
setRef(p, rstnodeToRefname(a), b)
elif n.kind == rnInterpretedText:
n.kind = rnRef
else:
result = newRstNode(rnRef)
addSon(result, n)
add(result, n)
elif match(p, p.idx, ":w:"):
# a role:
if p.tok[p.idx + 1].symbol == "idx":
@@ -724,8 +707,8 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
else:
result = newRstNode(rnGeneralRole)
n.kind = rnInner
addSon(result, n)
addSon(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
add(result, n)
add(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
inc(p.idx, 3)
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}:
break
else: break
addSon(n, newLeaf(p))
add(n, newLeaf(p))
inc(p.idx)
addSon(father, n)
add(father, n)
else:
var n = newLeaf(p)
inc(p.idx)
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
addSon(father, n)
add(father, n)
proc parseBackslash(p: var TRstParser, father: PRstNode) =
assert(p.tok[p.idx].kind == tkPunct)
if p.tok[p.idx].symbol == "\\\\":
addSon(father, newRstNode(rnLeaf, "\\"))
add(father, newRstNode(rnLeaf, "\\"))
inc(p.idx)
elif p.tok[p.idx].symbol == "\\":
# XXX: Unicode?
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)
else:
addSon(father, newLeaf(p))
add(father, newLeaf(p))
inc(p.idx)
when false:
@@ -795,18 +778,18 @@ when false:
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
break
else: break
addSon(n, newLeaf(p))
add(n, newLeaf(p))
inc(p.idx)
addSon(father, n)
add(father, n)
elif not verbatim and roSupportSmilies in p.shared.options:
let n = parseSmiley(p)
if s != nil:
addSon(father, n)
add(father, n)
else:
var n = newLeaf(p)
inc(p.idx)
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,
interpretBackslash: bool) =
@@ -819,21 +802,21 @@ proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
elif interpretBackslash:
parseBackslash(p, father)
else:
addSon(father, newLeaf(p))
add(father, newLeaf(p))
inc(p.idx)
of tkAdornment, tkWord, tkOther:
addSon(father, newLeaf(p))
add(father, newLeaf(p))
inc(p.idx)
of tkIndent:
addSon(father, newRstNode(rnLeaf, " "))
add(father, newRstNode(rnLeaf, " "))
inc(p.idx)
if p.tok[p.idx].kind == tkIndent:
rstMessage(p, errXExpected, postfix)
rstMessage(p, meExpected, postfix)
break
of tkWhite:
addSon(father, newRstNode(rnLeaf, " "))
add(father, newRstNode(rnLeaf, " "))
inc(p.idx)
else: rstMessage(p, errXExpected, postfix)
else: rstMessage(p, meExpected, postfix)
proc parseInline(p: var TRstParser, father: PRstNode) =
case p.tok[p.idx].kind
@@ -842,54 +825,54 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
inc(p.idx)
var n = newRstNode(rnTripleEmphasis)
parseUntil(p, n, "***", true)
addSon(father, n)
add(father, n)
elif isInlineMarkupStart(p, "**"):
inc(p.idx)
var n = newRstNode(rnStrongEmphasis)
parseUntil(p, n, "**", true)
addSon(father, n)
add(father, n)
elif isInlineMarkupStart(p, "*"):
inc(p.idx)
var n = newRstNode(rnEmphasis)
parseUntil(p, n, "*", true)
addSon(father, n)
add(father, n)
elif isInlineMarkupStart(p, "``"):
inc(p.idx)
var n = newRstNode(rnInlineLiteral)
parseUntil(p, n, "``", false)
addSon(father, n)
add(father, n)
elif isInlineMarkupStart(p, "`"):
inc(p.idx)
var n = newRstNode(rnInterpretedText)
parseUntil(p, n, "`", true)
n = parsePostfix(p, n)
addSon(father, n)
add(father, n)
elif isInlineMarkupStart(p, "|"):
inc(p.idx)
var n = newRstNode(rnSubstitutionReferences)
parseUntil(p, n, "|", false)
addSon(father, n)
add(father, n)
else:
if roSupportSmilies in p.s.options:
let n = parseSmiley(p)
if n != nil:
addSon(father, n)
add(father, n)
return
parseBackslash(p, father)
of tkWord:
if roSupportSmilies in p.s.options:
let n = parseSmiley(p)
if n != nil:
addSon(father, n)
add(father, n)
return
parseURL(p, father)
of tkAdornment, tkOther, tkWhite:
if roSupportSmilies in p.s.options:
let n = parseSmiley(p)
if n != nil:
addSon(father, n)
add(father, n)
return
addSon(father, newLeaf(p))
add(father, newLeaf(p))
inc(p.idx)
else: nil
@@ -944,8 +927,7 @@ const
"title"]
proc getDirKind(s: string): TDirKind =
var i: int
i = binaryStrSearch(DirIds, s)
let i = find(DirIds, s)
if i >= 0: result = TDirKind(i)
else: result = dkNone
@@ -970,8 +952,8 @@ proc parseField(p: var TRstParser): PRstNode =
pushInd(p, indent)
parseSection(p, fieldbody)
popInd(p)
addSon(result, fieldname)
addSon(result, fieldbody)
add(result, fieldname)
add(result, fieldbody)
proc parseFields(p: var TRstParser): PRstNode =
result = nil
@@ -982,7 +964,7 @@ proc parseFields(p: var TRstParser): PRstNode =
result = newRstNode(rnFieldList)
if not atStart: inc(p.idx)
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
(p.tok[p.idx + 1].symbol == ":"):
inc(p.idx)
@@ -996,7 +978,7 @@ proc getFieldValue(n: PRstNode, fieldname: string): string =
#InternalError("getFieldValue (2): " & $n.sons[1].kind)
# We don't like internal errors here anymore as that would break the forum!
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]
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
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}):
add(n.text, p.tok[p.idx].symbol)
inc(p.idx)
addSon(result, n)
add(result, n)
proc getLevel(map: var TLevelMap, lvl: var int, c: Char): int =
if map[c] == 0:
@@ -1099,7 +1081,7 @@ proc whichSection(p: TRstParser): TRstNodeKind =
result = rnEnumList
elif match(p, p.idx, "+a+"):
result = rnGridTable
rstMessage(p, errGridTableNotImplemented)
rstMessage(p, meGridTableNotImplemented)
elif isDefList(p):
result = rnDefList
elif isOptionList(p):
@@ -1123,7 +1105,7 @@ proc parseLineBlock(p: var TRstParser): PRstNode =
while true:
var item = newRstNode(rnLineBlockItem)
parseSection(p, item)
addSon(result, item)
add(result, item)
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 + 2].kind == tkWhite):
@@ -1143,9 +1125,9 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
inc(p.idx)
case whichSection(p)
of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
addSon(result, newRstNode(rnLeaf, " "))
add(result, newRstNode(rnLeaf, " "))
of rnLineBlock:
addSonIfNotNil(result, parseLineBlock(p))
addIfNotNil(result, parseLineBlock(p))
else: break
else:
break
@@ -1153,9 +1135,9 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
if (p.tok[p.idx].symbol == "::") and
(p.tok[p.idx + 1].kind == tkIndent) and
(currInd(p) < p.tok[p.idx + 1].ival):
addSon(result, newRstNode(rnLeaf, ":"))
add(result, newRstNode(rnLeaf, ":"))
inc(p.idx) # skip '::'
addSon(result, parseLiteralBlock(p))
add(result, parseLiteralBlock(p))
break
else:
parseInline(p, result)
@@ -1222,7 +1204,7 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
getColumns(p, cols)
setlen(row, len(cols))
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
for j in countup(0, high(row)): row[j] = ""
# 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
getTokens(row[j], false, q.tok)
b = newRstNode(rnTableDataCell)
addSon(b, parseDoc(q))
addSon(a, b)
addSon(result, a)
add(b, parseDoc(q))
add(a, b)
add(result, a)
proc parseTransition(p: var TRstParser): PRstNode =
result = newRstNode(rnTransition)
@@ -1267,7 +1249,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
if p.tok[p.idx].kind == tkIndent:
inc(p.idx)
if p.tok[p.idx - 1].ival > currInd(p):
addSon(result, newRstNode(rnLeaf, " "))
add(result, newRstNode(rnLeaf, " "))
else:
break
else:
@@ -1288,7 +1270,7 @@ proc parseBulletList(p: var TRstParser): PRstNode =
while true:
var item = newRstNode(rnBulletItem)
parseSection(p, item)
addSon(result, item)
add(result, item)
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 + 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):
inc(p.idx)
break
addSon(a, newLeaf(p))
add(a, newLeaf(p))
inc(p.idx)
var j = tokenAfterNewline(p)
if (j > 0) and (p.tok[j - 1].kind == tkIndent) and
@@ -1320,9 +1302,9 @@ proc parseOptionList(p: var TRstParser): PRstNode =
else:
parseLine(p, b)
if (p.tok[p.idx].kind == tkIndent): inc(p.idx)
addSon(c, a)
addSon(c, b)
addSon(result, c)
add(c, a)
add(c, b)
add(result, c)
else:
break
@@ -1345,9 +1327,9 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
var b = newRstNode(rnDefBody)
parseSection(p, b)
var c = newRstNode(rnDefItem)
addSon(c, a)
addSon(c, b)
addSon(result, c)
add(c, a)
add(c, b)
add(result, c)
popInd(p)
else:
p.idx = j
@@ -1360,7 +1342,7 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
nil
else:
break
if rsonsLen(result) == 0: result = nil
if len(result) == 0: result = nil
proc parseEnumList(p: var TRstParser): PRstNode =
const
@@ -1381,7 +1363,7 @@ proc parseEnumList(p: var TRstParser): PRstNode =
while true:
var item = newRstNode(rnEnumItem)
parseSection(p, item)
addSon(result, item)
add(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
match(p, p.idx + 1, wildcards[w]):
inc(p.idx, wildpos[w] + 4)
@@ -1394,7 +1376,7 @@ proc parseEnumList(p: var TRstParser): PRstNode =
proc sonKind(father: PRstNode, i: int): TRstNodeKind =
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) =
while true:
@@ -1407,7 +1389,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
pushInd(p, p.tok[p.idx].ival)
var a = newRstNode(rnBlockQuote)
parseSection(p, a)
addSon(result, a)
add(result, a)
popInd(p)
else:
leave = true
@@ -1424,7 +1406,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
of rnLineblock: a = parseLineBlock(p)
of rnDirective: a = parseDotDot(p)
of rnEnumList: a = parseEnumList(p)
of rnLeaf: rstMessage(p, errNewSectionExpected)
of rnLeaf: rstMessage(p, meNewSectionExpected)
of rnParagraph: nil
of rnDefList: a = parseDefinitionList(p)
of rnFieldList:
@@ -1441,19 +1423,19 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
if a == nil and k != rnDirective:
a = newRstNode(rnParagraph)
parseParagraph(p, a)
addSonIfNotNil(result, a)
addIfNotNil(result, a)
if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
result.sons[0].kind = rnInner
proc parseSectionWrapper(p: var TRstParser): PRstNode =
result = newRstNode(rnInner)
parseSection(p, result)
while (result.kind == rnInner) and (rsonsLen(result) == 1):
while (result.kind == rnInner) and (len(result) == 1):
result = result.sons[0]
proc parseDoc(p: var TRstParser): PRstNode =
result = parseSectionWrapper(p)
if p.tok[p.idx].kind != tkEof: rstMessage(p, errGeneralParseError)
if p.tok[p.idx].kind != tkEof: rstMessage(p, meGeneralParseError)
type
TDirFlag = enum
@@ -1471,24 +1453,24 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
while True:
case p.tok[p.idx].kind
of tkWord, tkOther, tkPunct, tkAdornment:
addSon(args, newLeaf(p))
add(args, newLeaf(p))
inc(p.idx)
else: break
elif argIsWord in flags:
while p.tok[p.idx].kind == tkWhite: inc(p.idx)
if p.tok[p.idx].kind == tkWord:
addSon(args, newLeaf(p))
add(args, newLeaf(p))
inc(p.idx)
else:
args = nil
else:
parseLine(p, args)
addSon(result, args)
add(result, args)
if hasOptions in flags:
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and
(p.tok[p.idx + 1].symbol == ":"):
options = parseFields(p)
addSon(result, options)
add(result, options)
proc indFollows(p: TRstParser): bool =
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)
var content = contentParser(p)
popInd(p)
addSon(result, content)
add(result, content)
else:
addSon(result, nil)
add(result, nil)
proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
if indFollows(p):
@@ -1530,14 +1512,14 @@ proc dirInclude(p: var TRstParser): PRstNode =
result = nil
var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil)
var filename = strip(addNodes(n.sons[0]))
var path = findFile(filename)
var path = p.s.findFile(filename)
if path == "":
rstMessage(p, errCannotOpenFile, filename)
rstMessage(p, meCannotOpenFile, filename)
else:
# XXX: error handling; recursive file inclusion!
if getFieldValue(n, "literal") != "":
result = newRstNode(rnLiteralBlock)
addSon(result, newRstNode(rnLeaf, readFile(path)))
add(result, newRstNode(rnLeaf, readFile(path)))
else:
var q: TRstParser
initParser(q, p.s)
@@ -1552,17 +1534,17 @@ proc dirCodeBlock(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock)
var filename = strip(getFieldValue(result, "file"))
if filename != "":
var path = findFile(filename)
if path == "": rstMessage(p, errCannotOpenFile, filename)
var path = p.s.findFile(filename)
if path == "": rstMessage(p, meCannotOpenFile, filename)
var n = newRstNode(rnLiteralBlock)
addSon(n, newRstNode(rnLeaf, readFile(path)))
add(n, newRstNode(rnLeaf, readFile(path)))
result.sons[2] = n
result.kind = rnCodeBlock
proc dirContainer(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasArg}, parseSectionWrapper)
assert(result.kind == rnDirective)
assert(rsonsLen(result) == 3)
assert(len(result) == 3)
result.kind = rnContainer
proc dirImage(p: var TRstParser): PRstNode =
@@ -1590,16 +1572,16 @@ proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
contentParser: TSectionParser) =
var filename = getFieldValue(result, "file")
if filename.len > 0:
var path = findFile(filename)
var path = p.s.findFile(filename)
if path.len == 0:
rstMessage(p, errCannotOpenFile, filename)
rstMessage(p, meCannotOpenFile, filename)
else:
var f = readFile(path)
result = newRstNode(kind)
addSon(result, newRstNode(rnLeaf, f))
add(result, newRstNode(rnLeaf, f))
else:
result.kind = kind
addSon(result, parseDirBody(p, contentParser))
add(result, parseDirBody(p, contentParser))
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:
dirRawAux(p, result, rnRawLatex, parseLiteralBlock)
else:
rstMessage(p, errInvalidDirectiveX, result.sons[0].text)
rstMessage(p, meInvalidDirective, result.sons[0].text)
else:
dirRawAux(p, result, rnRaw, parseSectionWrapper)
@@ -1639,10 +1621,10 @@ proc parseDotDot(p: var TRstParser): PRstNode =
if roSupportRawDirective in p.s.options:
result = dirRaw(p)
else:
rstMessage(p, errInvalidDirectiveX, d)
rstMessage(p, meInvalidDirective, d)
of dkCodeblock: result = dirCodeBlock(p)
of dkIndex: result = dirIndex(p)
else: rstMessage(p, errInvalidDirectiveX, d)
else: rstMessage(p, meInvalidDirective, d)
popInd(p)
elif match(p, p.idx, " _"):
# hyperlink target:
@@ -1665,7 +1647,7 @@ proc parseDotDot(p: var TRstParser): PRstNode =
inc(p.idx)
b = dirImage(p)
else:
rstMessage(p, errInvalidDirectiveX, p.tok[p.idx].symbol)
rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol)
setSub(p, addNodes(a), b)
elif match(p, p.idx, " ["):
# footnotes, citations
@@ -1689,27 +1671,28 @@ proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
var key = addNodes(n)
var e = getEnv(key)
if e != "": result = newRstNode(rnLeaf, e)
else: rstMessage(p, warnUnknownSubstitutionX, key)
else: rstMessage(p, mwUnknownSubstitution, key)
of rnRef:
var y = findRef(p, rstnodeToRefname(n))
if y != nil:
result = newRstNode(rnHyperlink)
n.kind = rnInner
addSon(result, n)
addSon(result, y)
add(result, n)
add(result, y)
of rnLeaf:
nil
of rnContents:
p.hasToc = true
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,
line, column: int, hasToc: var bool,
options: TRstParseOptions): PRstNode =
proc rstParse*(text, filename: string,
line, column: int, hasToc: var bool,
options: TRstParseOptions,
findFile: TFindFileHandler = nil,
msgHandler: TMsgHandler = nil): PRstNode =
var p: TRstParser
if isNil(text): rawMessage(errCannotOpenFile, filename)
initParser(p, newSharedState(options))
initParser(p, newSharedState(options, findFile, msgHandler))
p.filename = filename
p.line = line
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
values of an enum.
- 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 ``strutils.continuesWith``.
- Added ``system.getStackTrace``.
- The GC supports (soft) realtime systems via ``GC_setMaxPause``
and ``GC_step`` procs.