| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| /*LATEX |
| \documentclass[a4paper,12pt,oneside]{article} |
| |
| \usepackage[utf8]{inputenc} |
| \usepackage{amsmath} |
| \usepackage{amssymb} |
| \usepackage{listings} |
| |
| \lstset{basicstyle=\footnotesize\ttfamily\bf} |
| |
| \begin{document} |
| |
| \title{dart\_to\_latex.dart} |
| \author{The Dart project authors} |
| \date{} |
| |
| \maketitle |
| |
| \section*{Introduction} |
| |
| The purpose of this program is to extract comments of a special form from Dart |
| programs and put them into a .tex file in the order of their appearance in the |
| Dart program. |
| It allows writing elaborate documentation in the comments using formulas and |
| also use custom formatting commands. |
| |
| The comments that are put into the output .tex file are of the form |
| \lstinline!/*LATEX ... */!. |
| Additionally, all Dart lines marked with one-line comment \lstinline!//LATEX! |
| are also included to the output file and are put into \lstinline!verbatim! |
| environment. |
| Using \lstinline!//LATEX! sometimes conflicts with the default behavior of |
| \lstinline!dartfmt! formatting utility that may put the one-line comment to the |
| following line. |
| To address this issue one can use \lstinline!//LATEX-NEXT! comment right before |
| the line that should be inserted into the output. |
| */ |
| |
| /*LATEX |
| \section{Implementation Overview} |
| |
| First, the libraries for working with files and strings are imported. |
| */ |
| import "dart:io"; //LATEX |
| import "dart:core"; //LATEX |
| |
| /*LATEX |
| Most of the work is done in the Extractor class. |
| */ |
| |
| //LATEX-NEXT |
| class Extractor { |
| /*LATEX |
| There are some string constants that are used for text parsing. |
| */ |
| static final String latexMarker = "LATEX"; //LATEX |
| static final String latexNextMarker = "LATEX-NEXT"; //LATEX |
| static final String commentBegin = "/*"; //LATEX |
| static final String commentEnd = "*/"; //LATEX |
| static final String oneLineCommentBegin = "//"; //LATEX |
| |
| final String inputFilename; |
| final String outputFilename; |
| |
| final File inputFile; |
| final File outputFile; |
| |
| String input; |
| |
| /*LATEX |
| The actual parsing is done in the following methods. |
| */ |
| |
| //LATEX-NEXT |
| Extractor(this.inputFilename, this.outputFilename) |
| : inputFile = new File(inputFilename), |
| outputFile = new File(outputFilename) { |
| // Clear the output file at start. |
| outputFile.writeAsStringSync("", mode: FileMode.write, flush: true); |
| } |
| |
| //LATEX-NEXT |
| int findCommentEnd(int start) { |
| assert(start <= input.length); |
| assert(input.startsWith(commentBegin, start)); |
| |
| int balance = 1; |
| int i = start + commentBegin.length; |
| while (i < input.length && balance > 0) { |
| if (input.startsWith(commentBegin, i)) { |
| balance++; |
| i += commentBegin.length; |
| } else if (input.startsWith(commentEnd, i)) { |
| balance--; |
| i += commentEnd.length; |
| } else { |
| i++; |
| } |
| } |
| |
| if (balance > 0) { |
| return -1; |
| } |
| |
| return i; |
| } |
| |
| //LATEX-NEXT |
| void extractOneLineCommentsFrom(String text) { |
| List<String> lines = text.split("\n"); |
| List<String> outputLines = new List<String>(); |
| int i = 0; |
| while (i < lines.length) { |
| String line = lines[i]; |
| if (line.endsWith(oneLineCommentBegin + latexMarker)) { |
| outputLines.add(line.substring( |
| 0, line.length - (oneLineCommentBegin + latexMarker).length)); |
| i++; |
| } else if (line.endsWith(oneLineCommentBegin + latexNextMarker) && |
| i + 1 < lines.length) { |
| outputLines.add(lines[i + 1]); |
| i += 2; |
| } else { |
| i++; |
| } |
| } |
| if (outputLines.length > 0) { |
| outputLines.insert(0, r"\begin{verbatim}"); |
| outputLines.add(r"\end{verbatim}"); |
| } |
| for (String line in outputLines) { |
| outputFile.writeAsStringSync("$line\n", mode: FileMode.append); |
| } |
| } |
| |
| //LATEX-NEXT |
| void extractOneLineComments() { |
| int endIndex = input.indexOf(commentBegin); |
| while (endIndex != -1 && |
| !input.startsWith(commentBegin + latexMarker, endIndex)) { |
| endIndex = findCommentEnd(endIndex); |
| if (endIndex != -1) { |
| endIndex = input.indexOf(commentBegin, endIndex); |
| } |
| } |
| if (endIndex == -1) { |
| endIndex = input.length; |
| } |
| extractOneLineCommentsFrom(input.substring(0, endIndex)); |
| input = input.substring(endIndex); |
| } |
| |
| //LATEX-NEXT |
| void extractBlock() { |
| int startIndex = input.indexOf(commentBegin); |
| while (startIndex != -1 && |
| !input.startsWith(commentBegin + latexMarker, startIndex)) { |
| startIndex = findCommentEnd(startIndex); |
| if (startIndex != -1) { |
| startIndex = input.indexOf(commentBegin, startIndex); |
| } |
| } |
| if (startIndex == -1) { |
| startIndex = input.length; |
| } |
| input = input.substring(startIndex); |
| |
| if (input.startsWith(commentBegin + latexMarker)) { |
| int endIndex = findCommentEnd(0); |
| if (endIndex == -1) { |
| endIndex = input.length; |
| } |
| int latexBeginIndex = (commentBegin + latexMarker).length; |
| int latexEndIndex = input.substring(0, endIndex).endsWith(commentEnd) |
| ? endIndex - commentEnd.length |
| : endIndex; |
| outputFile.writeAsStringSync( |
| input.substring(latexBeginIndex, latexEndIndex) + "\n", |
| mode: FileMode.append); |
| input = input.substring(endIndex); |
| } |
| } |
| |
| //LATEX-NEXT |
| void run() { |
| input = inputFile.readAsStringSync(); |
| while (input.length > 0) { |
| extractOneLineComments(); |
| if (input.length > 0) extractBlock(); |
| } |
| } |
| } // class Extractor //LATEX |
| |
| /*LATEX |
| Finally, the entrance point of the program is defined. |
| After some trivial arguments check it creates an extractor instance and runs the |
| extraction. |
| */ |
| //LATEX-NEXT |
| main(List<String> arguments) { |
| // Arguments checks... //LATEX |
| if (arguments.length != 2) { |
| stderr.writeln("usage: dart dart_to_latex.dart input.dart output.tex"); |
| exit(1); |
| } |
| String inputFilename = arguments[0]; |
| String outputFilename = arguments[1]; |
| |
| Extractor parser = new Extractor(inputFilename, outputFilename); //LATEX |
| parser.run(); //LATEX |
| } //LATEX |
| |
| /*LATEX |
| \section{User Manual} |
| |
| \begin{enumerate} |
| \item \lstinline!dart dart_to_latex.dart input.dart output.tex! |
| \item \lstinline!pdflatex output.tex! |
| \end{enumerate} |
| */ |
| |
| /*LATEX |
| \section*{Conclusion} |
| |
| The presented program may have been written better. |
| It reads the entire input file into a \lstinline!String! variable and creates |
| sub-strings of the input during extraction. |
| A better approach would be to read the input program partially into a buffer, |
| maintain a set of indexes on it, and analyze it on the fly. |
| |
| The \LaTeX{} part of the program can also be improved. |
| For example, there is probably a better way to format the code fragmeents |
| inlined into paragraphs than using \lstinline1\lstinline!...!1. |
| |
| As a side note, one may use this tool to extract \LaTeX{} comments from programs |
| in some other languages like C++ and Java. |
| */ |
| |
| /*LATEX |
| \end{document} |
| */ |