summary refs log tree commit diff stats
path: root/nim/docgen.pas
diff options
context:
space:
mode:
Diffstat (limited to 'nim/docgen.pas')
-rwxr-xr-x[-rw-r--r--]nim/docgen.pas556
1 files changed, 359 insertions, 197 deletions
diff --git a/nim/docgen.pas b/nim/docgen.pas
index a72f64908..39a9069c7 100644..100755
--- a/nim/docgen.pas
+++ b/nim/docgen.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -24,6 +24,7 @@ uses
 
 procedure CommandDoc(const filename: string);
 procedure CommandRst2Html(const filename: string);
+procedure CommandRst2TeX(const filename: string);
 
 implementation
 
@@ -33,7 +34,7 @@ type
     refname, header: PRope;
   end;
   TSections = array [TSymKind] of PRope;
-  TMetaEnum = (metaNone, metaTitle, metaSubtitle);
+  TMetaEnum = (metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion);
   TDocumentor = record  // contains a module's documentation
     filename: string;   // filename of the source file; without extension
     basedir: string;    // base directory (where to put the documentation)
@@ -51,6 +52,9 @@ type
   end;
   PDoc = ^TDocumentor;
 
+var
+  splitter: string = '<wbr />';
+
 function findIndexNode(n: PRstNode): PRstNode;
 var
   i: int;
@@ -213,6 +217,8 @@ begin
   end
 end;
 
+// -------------------- dispatcher -------------------------------------------
+
 procedure addXmlChar(var dest: string; c: Char);
 begin
   case c of
@@ -224,6 +230,43 @@ begin
   end
 end;
 
+procedure addRtfChar(var dest: string; c: Char);
+begin
+  case c of
+    '{': add(dest, '\{');
+    '}': add(dest, '\}');
+    '\': add(dest, '\\');
+    else addChar(dest, c)
+  end
+end;
+
+procedure addTexChar(var dest: string; c: Char);
+begin
+  case c of
+    '_': add(dest, '\_');
+    '{': add(dest, '\symbol{123}');
+    '}': add(dest, '\symbol{125}');
+    '[': add(dest, '\symbol{91}');
+    ']': add(dest, '\symbol{93}');
+    '\': add(dest, '\symbol{92}');
+    '$': add(dest, '\$');
+    '&': add(dest, '\&');
+    '#': add(dest, '\#');
+    '%': add(dest, '\%');
+    '~': add(dest, '\symbol{126}');
+    '@': add(dest, '\symbol{64}');
+    '^': add(dest, '\symbol{94}');
+    '`': add(dest, '\symbol{96}');
+    else addChar(dest, c)
+  end
+end;
+
+procedure escChar(var dest: string; c: Char);
+begin
+  if gCmd <> cmdRst2Tex then addXmlChar(dest, c)
+  else addTexChar(dest, c);
+end;
+
 function nextSplitPoint(const s: string; start: int): int;
 begin
   result := start;
@@ -241,9 +284,7 @@ begin
   dec(result); // last valid index
 end;
 
-function toXml(const s: string; splitAfter: int = -1): string;
-const
-  splitter = '<wbr />';
+function esc(const s: string; splitAfter: int = -1): string;
 var
   i, j, k, partLen: int;
 begin
@@ -257,26 +298,52 @@ begin
         partLen := 0;
         add(result, splitter);
       end;
-      for i := j to k do addXmlChar(result, s[i]);
+      for i := j to k do escChar(result, s[i]);
       inc(partLen, k - j + 1);
       j := k+1;
     end;
   end
   else begin
-    for i := strStart to length(s)+strStart-1 do addXmlChar(result, s[i])
+    for i := strStart to length(s)+strStart-1 do escChar(result, s[i])
   end
 end;
 
-function renderRstToHtml(d: PDoc; n: PRstNode): PRope; forward;
+function disp(const xml, tex: string): string;
+begin  
+  if gCmd <> cmdRst2Tex then
+    result := xml
+  else
+    result := tex
+end;
+
+function dispF(const xml, tex: string; const args: array of PRope): PRope;
+begin
+  if gCmd <> cmdRst2Tex then
+    result := ropef(xml, args)
+  else
+    result := ropef(tex, args)
+end;
+
+procedure dispA(var dest: PRope; const xml, tex: string;
+                const args: array of PRope);
+begin
+  if gCmd <> cmdRst2Tex then
+    appf(dest, xml, args)
+  else
+    appf(dest, tex, args)
+end;
+
+// ---------------------------------------------------------------------------
+
+function renderRstToOut(d: PDoc; n: PRstNode): PRope; forward;
 
-function renderAux(d: PDoc; n: PRstNode; const outer: string = '$1';
-                   const inner: string = '$1'): PRope;
+function renderAux(d: PDoc; n: PRstNode; const outer: string = '$1'): PRope;
 var
   i: int;
 begin
   result := nil;
   for i := 0 to rsonsLen(n)-1 do
-    appf(result, inner, [renderRstToHtml(d, n.sons[i])]);
+    app(result, renderRstToOut(d, n.sons[i]));
   result := ropef(outer, [result]);
 end;
 
@@ -286,7 +353,8 @@ var
 begin
   if d.theIndex = nil then exit;
   h := newRstNode(rnHyperlink);
-  a := newRstNode(rnLeaf, d.indexValFilename +{&} '#' +{&} toString(id));
+  a := newRstNode(rnLeaf, d.indexValFilename +{&} disp('#'+'', '')
+                  +{&} toString(id));
   addSon(h, a);
   addSon(h, a);
   a := newRstNode(rnIdx);
@@ -299,9 +367,11 @@ var
   a, h: PRstNode;
 begin
   inc(d.id);
-  result := ropef('<em id="$1">$2</em>', [toRope(d.id), renderAux(d, n)]);
+  result := dispF('<em id="$1">$2</em>',
+                  '$2\label{$1}', [toRope(d.id), renderAux(d, n)]);
   h := newRstNode(rnHyperlink);
-  a := newRstNode(rnLeaf, d.indexValFilename +{&} '#' +{&} toString(d.id));
+  a := newRstNode(rnLeaf, d.indexValFilename +{&} disp('#'+'', '')
+                  +{&} toString(d.id));
   addSon(h, a);
   addSon(h, a);
   setIndexPair(d.theIndex, n, h);
@@ -312,10 +382,9 @@ var
   dummyHasToc: bool;
 begin
   if (n.comment <> snil) and startsWith(n.comment, '##') then
-    result := renderRstToHtml(d, rstParse(n.comment, true,
-                        toFilename(n.info),
-                        toLineNumber(n.info), toColumn(n.info),
-                        dummyHasToc))
+    result := renderRstToOut(d, rstParse(n.comment, true, toFilename(n.info),
+                                          toLineNumber(n.info),
+                                          toColumn(n.info), dummyHasToc))
   else
     result := nil;
 end;
@@ -359,9 +428,11 @@ begin
   case n.kind of
     nkPostfix: result := getName(n.sons[1], splitAfter);
     nkPragmaExpr: result := getName(n.sons[0], splitAfter);
-    nkSym: result := toXML(n.sym.name.s, splitAfter);
-    nkIdent: result := toXML(n.ident.s, splitAfter);
-    nkAccQuoted: result := '`' +{&} getName(n.sons[0], splitAfter) +{&} '`';
+    nkSym: result := esc(n.sym.name.s, splitAfter);
+    nkIdent: result := esc(n.ident.s, splitAfter);
+    nkAccQuoted:
+      result := esc('`'+'') +{&} getName(n.sons[0], splitAfter) +{&}
+                esc('`'+'');
     else begin
       internalError(n.info, 'getName()');
       result := ''
@@ -407,39 +478,47 @@ begin
     case kind of
       tkEof: break;
       tkComment:
-        appf(result, '<span class="Comment">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="Comment">$1</span>',
+                      '\spanComment{$1}',
+                      [toRope(esc(literal))]);
       tokKeywordLow..tokKeywordHigh:
-        appf(result, '<span class="Keyword">$1</span>',
+        dispA(result, '<span class="Keyword">$1</span>',
+                      '\spanKeyword{$1}',
                       [toRope(literal)]);
       tkOpr, tkHat:
-        appf(result, '<span class="Operator">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="Operator">$1</span>',
+                      '\spanOperator{$1}',
+                      [toRope(esc(literal))]);
       tkStrLit..tkTripleStrLit:
-        appf(result, '<span class="StringLit">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="StringLit">$1</span>',
+                      '\spanStringLit{$1}',
+                      [toRope(esc(literal))]);
       tkCharLit:
-        appf(result, '<span class="CharLit">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="CharLit">$1</span>',
+                      '\spanCharLit{$1}',
+                      [toRope(esc(literal))]);
       tkIntLit..tkInt64Lit:
-        appf(result, '<span class="DecNumber">$1</span>',
-                      [toRope(literal)]);
+        dispA(result, '<span class="DecNumber">$1</span>',
+                      '\spanDecNumber{$1}',
+                      [toRope(esc(literal))]);
       tkFloatLit..tkFloat64Lit:
-        appf(result, '<span class="FloatNumber">$1</span>',
-                      [toRope(literal)]);
+        dispA(result, '<span class="FloatNumber">$1</span>',
+                      '\spanFloatNumber{$1}',
+                      [toRope(esc(literal))]);
       tkSymbol:
-        appf(result, '<span class="Identifier">$1</span>',
-                      [toRope(literal)]);
-      tkInd, tkSad, tkDed, tkSpaces:
-        app(result, literal);
-        //appf(result, '<span class="Whitespace">$1</span>',
-        //              [toRope(literal)]);
+        dispA(result, '<span class="Identifier">$1</span>',
+                      '\spanIdentifier{$1}',
+                      [toRope(esc(literal))]);
+      tkInd, tkSad, tkDed, tkSpaces: begin
+        app(result, literal)
+      end;
       tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
       tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi,
       tkParDotLe, tkParDotRi, tkComma, tkSemiColon, tkColon,
       tkEquals, tkDot, tkDotDot, tkAccent:
-        appf(result, '<span class="Other">$1</span>',
-                      [toRope(literal)]);
+        dispA(result, '<span class="Other">$1</span>',
+                      '\spanOther{$1}',
+                      [toRope(esc(literal))]);
       else InternalError(n.info, 'docgen.genThing(' + toktypeToStr[kind] + ')');
     end
   end;
@@ -460,7 +539,7 @@ var
 begin
   result := nil;
   for i := 0 to rsonsLen(n)-1 do
-    app(result, renderRstToHtml(d, n.sons[i]));
+    app(result, renderRstToOut(d, n.sons[i]));
   refname := toRope(rstnodeToRefname(n));
   if d.hasToc then begin
     len := length(d.tocPart);
@@ -468,13 +547,17 @@ begin
     d.tocPart[len].refname := refname;
     d.tocPart[len].n := n;
     d.tocPart[len].header := result;
-    result := ropef('<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3'+
-                         '</a></h$1>',
-                         [toRope(n.level), d.tocPart[len].refname, result]);
+    result := dispF(
+      '<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3</a></h$1>',
+      '\rsth$4{$3}\label{$2}$n',
+      [toRope(n.level), d.tocPart[len].refname, result,
+       toRope(chr(n.level-1+ord('A'))+'')]);
   end
   else
-    result := ropef('<h$1 id="$2">$3</h$1>',
-                         [toRope(n.level), refname, result]);
+    result := dispF('<h$1 id="$2">$3</h$1>',
+                    '\rsth$4{$3}\label{$2}$n',
+                    [toRope(n.level), refname, result,
+                     toRope(chr(n.level-1+ord('A'))+'')]);
 end;
 
 function renderOverline(d: PDoc; n: PRstNode): PRope;
@@ -484,13 +567,15 @@ var
 begin
   t := nil;
   for i := 0 to rsonsLen(n)-1 do
-    app(t, renderRstToHtml(d, n.sons[i]));
+    app(t, renderRstToOut(d, n.sons[i]));
   result := nil;
   if d.meta[metaTitle] = nil then d.meta[metaTitle] := t
   else if d.meta[metaSubtitle] = nil then d.meta[metaSubtitle] := t
   else
-    result := ropef('<h$1 id="$2"><center>$3</center></h$1>',
-                         [toRope(n.level), toRope(rstnodeToRefname(n)), t]);
+    result := dispF('<h$1 id="$2"><center>$3</center></h$1>',
+                    '\rstov$4{$3}\label{$2}$n',
+                    [toRope(n.level), toRope(rstnodeToRefname(n)), t,
+                     toRope(chr(n.level-1+ord('A'))+'')]);
 end;
 
 function renderRstToRst(d: PDoc; n: PRstNode): PRope; forward;
@@ -645,8 +730,10 @@ end;
 
 function renderTocEntry(d: PDoc; const e: TTocEntry): PRope;
 begin
-  result := ropef('<li><a class="reference" id="$1_toc" href="#$1">$2' +
-                       '</a></li>$n', [e.refname, e.header]);
+  result := dispF(
+    '<li><a class="reference" id="$1_toc" href="#$1">$2</a></li>$n',
+    '\item\label{$1_toc} $2\ref{$1}$n',
+    [e.refname, e.header]);
 end;
 
 function renderTocEntries(d: PDoc; var j: int; lvl: int): PRope;
@@ -666,7 +753,8 @@ begin
       break
   end;
   if lvl > 1 then
-    result := ropef('<ul class="simple">$1</ul>', [result]);
+    result := dispF('<ul class="simple">$1</ul>',
+                    '\begin{enumerate}$1\end{enumerate}', [result]);
 end;
 
 function fieldAux(const s: string): PRope;
@@ -676,21 +764,28 @@ end;
 
 function renderImage(d: PDoc; n: PRstNode): PRope;
 var
-  s: string;
+  s, scale: string;
+  options: PRope;
 begin
-  result := ropef('<img src="$1"', [toRope(getArgument(n))]);
+  options := nil;
+  s := getFieldValue(n, 'scale');
+  if s <> '' then dispA(options, ' scale="$1"', ' scale=$1', [fieldAux(scale)]);
+  
   s := getFieldValue(n, 'height');
-  if s <> '' then appf(result, ' height="$1"', [fieldAux(s)]);
+  if s <> '' then dispA(options, ' height="$1"', ' height=$1', [fieldAux(s)]);
+  
   s := getFieldValue(n, 'width');
-  if s <> '' then appf(result, ' width="$1"', [fieldAux(s)]);
-  s := getFieldValue(n, 'scale');
-  if s <> '' then appf(result, ' scale="$1"', [fieldAux(s)]);
+  if s <> '' then dispA(options, ' width="$1"', ' width=$1', [fieldAux(s)]);
+  
   s := getFieldValue(n, 'alt');
-  if s <> '' then appf(result, ' alt="$1"', [fieldAux(s)]);
+  if s <> '' then dispA(options, ' alt="$1"', '', [fieldAux(s)]);
   s := getFieldValue(n, 'align');
-  if s <> '' then appf(result, ' align="$1"', [fieldAux(s)]);
-  app(result, ' />');
-  if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
+  if s <> '' then dispA(options, ' align="$1"', '', [fieldAux(s)]);
+    
+  if options <> nil then options := dispF('$1', '[$1]', [options]);
+  result := dispF('<img src="$1"$2 />',
+    '\includegraphics$2{$1}', [toRope(getArgument(n)), options]);
+  if rsonsLen(n) >= 3 then app(result, renderRstToOut(d, n.sons[2]))
 end;
 
 function renderCodeBlock(d: PDoc; n: PRstNode): PRope;
@@ -709,7 +804,7 @@ begin
   else lang := getSourceLanguage(langstr);
   if lang = langNone then begin
     rawMessage(warnLanguageXNotSupported, langstr);
-    result := ropef('<pre>$1</pre>', [toRope(m.text)])
+    result := toRope(m.text)
   end
   else begin
     initGeneralTokenizer(g, m.text);
@@ -717,164 +812,220 @@ begin
       getNextToken(g, lang);
       case g.kind of
         gtEof: break;
-        gtNone, gtWhitespace:
+        gtNone, gtWhitespace: begin
           app(result, ncopy(m.text, g.start+strStart,
-                            g.len+g.start-1+strStart));
+                            g.len+g.start-1+strStart))
+        end
         else
-          appf(result, '<span class="$2">$1</span>',
-            [toRope(toXml(ncopy(m.text, g.start+strStart,
-                                g.len+g.start-1+strStart))),
-             toRope(tokenClassToStr[g.kind])]);
+          dispA(result,
+                '<span class="$2">$1</span>',
+                '\span$2{$1}',
+                [toRope(esc(ncopy(m.text, g.start+strStart,
+                                  g.len+g.start-1+strStart))),
+                 toRope(tokenClassToStr[g.kind])]);
       end;
     end;
     deinitGeneralTokenizer(g);
-    if result <> nil then result := ropef('<pre>$1</pre>', [result]);
-  end
+  end;
+  if result <> nil then
+    result := dispF('<pre>$1</pre>', '\begin{rstpre}$n$1$n\end{rstpre}$n',
+                    [result])
 end;
 
 function renderContainer(d: PDoc; n: PRstNode): PRope;
 var
   arg: PRope;
 begin
-  result := renderRstToHtml(d, n.sons[2]);
+  result := renderRstToOut(d, n.sons[2]);
   arg := toRope(strip(getArgument(n)));
-  if arg = nil then result := ropef('<div>$1</div>', [result])
-  else result := ropef('<div class="$1">$2</div>', [arg, result])  
+  if arg = nil then result := dispF('<div>$1</div>', '$1', [result])
+  else result := dispF('<div class="$1">$2</div>', '$2', [arg, result])  
+end;
+
+function texColumns(n: PRstNode): string;
+var
+  i: int;
+begin
+  result := '';
+  for i := 1 to rsonsLen(n) do add(result, '|X');
+end;
+
+function renderField(d: PDoc; n: PRstNode): PRope;
+var
+  fieldname: string;
+  fieldval: PRope;
+  b: bool;
+begin
+  b := false;
+  if gCmd = cmdRst2Tex then begin
+    fieldname := addNodes(n.sons[0]);
+    fieldval := toRope(esc(strip(addNodes(n.sons[1]))));
+    if cmpIgnoreStyle(fieldname, 'author') = 0 then begin
+      if d.meta[metaAuthor] = nil then begin
+        d.meta[metaAuthor] := fieldval;
+        b := true
+      end
+    end
+    else if cmpIgnoreStyle(fieldName, 'version') = 0 then begin
+      if d.meta[metaVersion] = nil then begin
+        d.meta[metaVersion] := fieldval;
+        b := true
+      end
+    end
+  end;
+  if b then result := nil
+  else result := renderAux(d, n, disp('<tr>$1</tr>$n', '$1'));
 end;
 
-function renderRstToHtml(d: PDoc; n: PRstNode): PRope;
+function renderRstToOut(d: PDoc; n: PRstNode): PRope;
 var
-  outer, inner: string;
+  i: int;
 begin
   if n = nil then begin result := nil; exit end;
-  outer := '$1';
-  inner := '$1';
   case n.kind of
-    rnInner: begin end;
-    rnHeadline: begin
-      result := renderHeadline(d, n); exit;
-    end;
-    rnOverline: begin
-      result := renderOverline(d, n);
-      exit;
-    end;
-    rnTransition: outer := '<hr />'+nl;
-    rnParagraph: outer := '<p>$1</p>'+nl;
-    rnBulletList: outer := '<ul class="simple">$1</ul>'+nl;
-    rnBulletItem, rnEnumItem: outer := '<li>$1</li>'+nl;
-    rnEnumList: outer := '<ol class="simple">$1</ol>'+nl;
-    rnDefList: outer := '<dl class="docutils">$1</dl>'+nl;
-    rnDefItem: begin end;
-    rnDefName: outer := '<dt>$1</dt>'+nl;
-    rnDefBody: outer := '<dd>$1</dd>'+nl;
-    rnFieldList:
-      outer := '<table class="docinfo" frame="void" rules="none">' +
-               '<col class="docinfo-name" />' +
-               '<col class="docinfo-content" />' +
-               '<tbody valign="top">$1' +
-               '</tbody></table>';
-    rnField: outer := '<tr>$1</tr>$n';
-    rnFieldName: outer := '<th class="docinfo-name">$1:</th>';
-    rnFieldBody: outer := '<td>$1</td>';
-    rnIndex: begin
-      result := renderRstToHtml(d, n.sons[2]);
-      exit
+    rnInner: result := renderAux(d, n);
+    rnHeadline: result := renderHeadline(d, n);
+    rnOverline: result := renderOverline(d, n);
+    rnTransition:
+      result := renderAux(d, n, disp('<hr />'+nl, '\hrule'+nl));
+    rnParagraph:
+      result := renderAux(d, n, disp('<p>$1</p>'+nl, '$1$n$n'));
+    rnBulletList:
+      result := renderAux(d, n, disp('<ul class="simple">$1</ul>'+nl,
+                                '\begin{itemize}$1\end{itemize}'+nl));
+    rnBulletItem, rnEnumItem:
+      result := renderAux(d, n, disp('<li>$1</li>'+nl, '\item $1'+nl));
+    rnEnumList:
+      result := renderAux(d, n, disp('<ol class="simple">$1</ol>'+nl,
+                                     '\begin{enumerate}$1\end{enumerate}'+nl));
+    rnDefList: 
+      result := renderAux(d, n, disp('<dl class="docutils">$1</dl>'+nl,
+                        '\begin{description}$1\end{description}'+nl));
+    rnDefItem: 
+      result := renderAux(d, n);
+    rnDefName:
+      result := renderAux(d, n, disp('<dt>$1</dt>'+nl, '\item[$1] '));
+    rnDefBody:
+      result := renderAux(d, n, disp('<dd>$1</dd>'+nl, '$1'+nl));
+    rnFieldList: begin
+      result := nil;
+      for i := 0 to rsonsLen(n)-1 do app(result, renderRstToOut(d, n.sons[i]));
+      if result <> nil then
+        result := dispf('<table class="docinfo" frame="void" rules="none">' +
+                        '<col class="docinfo-name" />' +
+                        '<col class="docinfo-content" />' +
+                        '<tbody valign="top">$1' +
+                        '</tbody></table>',
+                        '\begin{description}$1\end{description}'+nl, [result]);
     end;
+    rnField: result := renderField(d, n);
+    rnFieldName:
+      result := renderAux(d, n, disp(
+                  '<th class="docinfo-name">$1:</th>', '\item[$1:]'));
+    rnFieldBody:
+      result := renderAux(d, n, disp('<td>$1</td>', ' $1$n'));
+    rnIndex:
+      result := renderRstToOut(d, n.sons[2]);
 
     rnOptionList:
-      outer := '<table frame="void">$1</table>';
+      result := renderAux(d, n, disp('<table frame="void">$1</table>',
+                    '\begin{description}$n$1\end{description}'+nl));
     rnOptionListItem:
-      outer := '<tr>$1</tr>$n';
-    rnOptionGroup: outer := '<th align="left">$1</th>';
-    rnDescription: outer := '<td align="left">$1</td>$n';
+      result := renderAux(d, n, disp('<tr>$1</tr>$n', '$1'));
+    rnOptionGroup:
+      result := renderAux(d, n, disp('<th align="left">$1</th>', '\item[$1]'));
+    rnDescription:
+      result := renderAux(d, n, disp('<td align="left">$1</td>$n', ' $1$n'));
     rnOption,
     rnOptionString,
-    rnOptionArgument: InternalError('renderRstToHtml');
+    rnOptionArgument: InternalError('renderRstToOut');
 
-    rnLiteralBlock: outer := '<pre>$1</pre>'+nl;
-    rnQuotedLiteralBlock: InternalError('renderRstToHtml');
+    rnLiteralBlock: 
+      result := renderAux(d, n, disp('<pre>$1</pre>$n',
+                                     '\begin{rstpre}$n$1$n\end{rstpre}$n'));
+    rnQuotedLiteralBlock: InternalError('renderRstToOut');
 
-    rnLineBlock: outer := '<p>$1</p>';
-    rnLineBlockItem: outer := '$1<br />';
+    rnLineBlock: result := renderAux(d, n, disp('<p>$1</p>', '$1$n$n'));
+    rnLineBlockItem: result := renderAux(d, n, disp('$1<br />', '$1\\$n'));
 
-    rnBlockQuote: outer := '<blockquote><p>$1</p></blockquote>$n';
+    rnBlockQuote:
+      result := renderAux(d, n, disp('<blockquote><p>$1</p></blockquote>$n',
+                                     '\begin{quote}$1\end{quote}$n'));
 
-    rnTable, rnGridTable:
-      outer := '<table border="1" class="docutils">$1</table>';
-    rnTableRow: outer := '<tr>$1</tr>$n';
-    rnTableDataCell: outer := '<td>$1</td>';
-    rnTableHeaderCell: outer := '<th>$1</th>';
+    rnTable, rnGridTable: begin
+      result := renderAux(d, n,
+                          disp('<table border="1" class="docutils">$1</table>',
+                               '\begin{table}\begin{rsttab}{' +{&}
+                               texColumns(n) +{&}
+                               '|}$n\hline$n$1\end{rsttab}\end{table}'));
+    end;
+    rnTableRow: begin
+      if rsonsLen(n) >= 1 then begin
+        result := renderRstToOut(d, n.sons[0]);
+        for i := 1 to rsonsLen(n)-1 do
+          dispa(result, '$1', ' & $1', [renderRstToOut(d, n.sons[i])]);
+        result := dispf('<tr>$1</tr>$n', '$1\\$n\hline$n', [result]);
+      end
+      else
+        result := nil;
+    end;
+    rnTableDataCell: result := renderAux(d, n, disp('<td>$1</td>', '$1'));
+    rnTableHeaderCell:
+      result := renderAux(d, n, disp('<th>$1</th>', '\textbf{$1}'));
 
-    rnLabel: InternalError('renderRstToHtml'); // used for footnotes and other
-    rnFootnote: InternalError('renderRstToHtml'); // a footnote
+    rnLabel: InternalError('renderRstToOut'); // used for footnotes and other
+    rnFootnote: InternalError('renderRstToOut'); // a footnote
 
-    rnCitation: InternalError('renderRstToHtml');    // similar to footnote
-    rnRef: begin
-      result := ropef('<a class="reference external" href="#$2">$1</a>',
-                           [renderAux(d, n), toRope(rstnodeToRefname(n))]);
-      exit
-    end;
+    rnCitation: InternalError('renderRstToOut');    // similar to footnote
+    rnRef: 
+      result := dispF('<a class="reference external" href="#$2">$1</a>',
+                      '$1\ref{$2}',
+                      [renderAux(d, n), toRope(rstnodeToRefname(n))]);
     rnStandaloneHyperlink:
-      outer := '<a class="reference external" href="$1">$1</a>';
-    rnHyperlink: begin
-      result := ropef('<a class="reference external" href="$2">$1</a>',
-                           [renderRstToHtml(d, n.sons[0]),
-                            renderRstToHtml(d, n.sons[1])]);
-      exit
-    end;
-    rnDirArg, rnRaw: begin end;
-    rnImage, rnFigure: begin
-      result := renderImage(d, n);
-      exit
-    end;
-    rnCodeBlock: begin
-      result := renderCodeBlock(d, n);
-      exit
-    end;
-    rnContainer: begin 
-      result := renderContainer(d, n);
-      exit
-    end;
-    rnSubstitutionReferences, rnSubstitutionDef: outer := '|$1|';
-    rnDirective: outer := '';
+      result := renderAux(d, n, disp(
+                    '<a class="reference external" href="$1">$1</a>',
+                    '\href{$1}{$1}'));
+    rnHyperlink: 
+      result := dispF('<a class="reference external" href="$2">$1</a>',
+                      '\href{$2}{$1}',
+                      [renderRstToOut(d, n.sons[0]),
+                       renderRstToOut(d, n.sons[1])]);
+    rnDirArg, rnRaw: result := renderAux(d, n);
+    rnImage, rnFigure: result := renderImage(d, n);
+    rnCodeBlock: result := renderCodeBlock(d, n);
+    rnContainer: result := renderContainer(d, n);
+    rnSubstitutionReferences, rnSubstitutionDef:
+      result := renderAux(d, n, disp('|$1|', '|$1|'));
+    rnDirective: result := renderAux(d, n, '');
 
     // Inline markup:
-    rnGeneralRole: begin
-      result := ropef('<span class="$2">$1</span>',
-                           [renderRstToHtml(d, n.sons[0]),
-                            renderRstToHtml(d, n.sons[1])]);
-      exit
-    end;
-    rnSub: outer := '<sub>$1</sub>';
-    rnSup: outer := '<sup>$1</sup>';
-    rnEmphasis: outer := '<em>$1</em>';
-    rnStrongEmphasis: outer := '<strong>$1</strong>';
-    rnInterpretedText: outer := '<cite>$1</cite>';
+    rnGeneralRole: 
+      result := dispF('<span class="$2">$1</span>',
+                      '\span$2{$1}',
+                      [renderRstToOut(d, n.sons[0]),
+                       renderRstToOut(d, n.sons[1])]);
+    rnSub: result := renderAux(d, n, disp('<sub>$1</sub>', '\rstsub{$1}'));
+    rnSup: result := renderAux(d, n, disp('<sup>$1</sup>', '\rstsup{$1}'));
+    rnEmphasis: result := renderAux(d, n, disp('<em>$1</em>', '\emph{$1}'));
+    rnStrongEmphasis:
+      result := renderAux(d, n, disp('<strong>$1</strong>', '\textbf{$1}'));
+    rnInterpretedText:
+      result := renderAux(d, n, disp('<cite>$1</cite>', '\emph{$1}'));
     rnIdx: begin
       if d.theIndex = nil then
-        outer := '<em>$1</em>'
-      else begin
-        result := renderIndexTerm(d, n); exit
-      end
+        result := renderAux(d, n, disp('<em>$1</em>', '\emph{$1}'))
+      else
+        result := renderIndexTerm(d, n);
     end;
     rnInlineLiteral:
-      outer := '<tt class="docutils literal"><span class="pre">'
-             +{&} '$1</span></tt>';
-    rnLeaf: begin
-      result := toRope(toXml(n.text));
-      exit
-    end;
-    rnContents: begin
-      d.hasToc := true;
-      exit;
-    end;
-    rnTitle: begin
-      d.meta[metaTitle] := renderRstToHtml(d, n.sons[0]);
-      exit
-    end;
-    else InternalError('renderRstToHtml');
-  end;
-  result := renderAux(d, n, outer, inner);
+      result := renderAux(d, n, disp(
+        '<tt class="docutils literal"><span class="pre">$1</span></tt>',
+        '\texttt{$1}'));
+    rnLeaf: result := toRope(esc(n.text));
+    rnContents: d.hasToc := true;
+    rnTitle: d.meta[metaTitle] := renderRstToOut(d, n.sons[0]);
+    else InternalError('renderRstToOut');
+  end
 end;
 
 procedure generateDoc(d: PDoc; n: PNode);
@@ -929,7 +1080,7 @@ begin
     [toRope(ord(kind)), title, toRope(ord(kind)+50), d.toc[kind]]);
 end;
 
-function genHtmlFile(d: PDoc): PRope;
+function genOutFile(d: PDoc): PRope;
 var
   code, toc, title, content: PRope;
   bodyname: string;
@@ -947,8 +1098,7 @@ begin
   end;
   if toc <> nil then
     toc := ropeFormatNamedVars(getConfigVar('doc.toc'), ['content'], [toc]);
-  for i := low(TSymKind) to high(TSymKind) do
-    app(code, d.section[i]);
+  for i := low(TSymKind) to high(TSymKind) do app(code, d.section[i]);
   if d.meta[metaTitle] <> nil then
     title := d.meta[metaTitle]
   else
@@ -962,9 +1112,10 @@ begin
     [title, toc, d.modDesc, toRope(getDateStr()), toRope(getClockStr()), code]);
   if not (optCompileOnly in gGlobalOptions) then
     code := ropeFormatNamedVars(getConfigVar('doc.file'),
-      ['title', 'tableofcontents', 'moduledesc', 'date', 'time', 'content'],
-      [title, toc, d.modDesc,
-       toRope(getDateStr()), toRope(getClockStr()), content])
+      ['title', 'tableofcontents', 'moduledesc', 'date', 'time',
+       'content', 'author', 'version'],
+      [title, toc, d.modDesc, toRope(getDateStr()), toRope(getClockStr()),
+       content, d.meta[metaAuthor], d.meta[metaVersion]])
   else
     code := content;
   result := code;
@@ -989,11 +1140,11 @@ begin
   initIndexFile(d);
   d.hasToc := true;
   generateDoc(d, ast);
-  writeRope(genHtmlFile(d), getOutFile(filename, HtmlExt));
+  writeRope(genOutFile(d), getOutFile(filename, HtmlExt));
   generateIndex(d);
 end;
 
-procedure CommandRst2Html(const filename: string);
+procedure CommandRstAux(const filename, outExt: string);
 var
   filen: string;
   d: PDoc;
@@ -1004,10 +1155,21 @@ begin
   d := newDocumentor(filen);
   initIndexFile(d);
   rst := rstParse(readFile(filen), false, filen, 0, 1, d.hasToc);
-  d.modDesc := renderRstToHtml(d, rst);
-  code := genHtmlFile(d);
-  writeRope(code, getOutFile(filename, HtmlExt));
+  d.modDesc := renderRstToOut(d, rst);
+  code := genOutFile(d);
+  writeRope(code, getOutFile(filename, outExt));
   generateIndex(d);
 end;
 
+procedure CommandRst2Html(const filename: string);
+begin
+  CommandRstAux(filename, HtmlExt);
+end;
+
+procedure CommandRst2TeX(const filename: string);
+begin
+  splitter := '\-';
+  CommandRstAux(filename, TexExt);
+end;
+
 end.