Plain Markdown support. Directory support.

* Upgraded build common to version 1.9.
* Updated the release target in build.xml to take advantage of the new features
  of common build 1.9. The release target now copies over the libs and release
  resources.
* JLPMain now recognises directories in it's input list. It will add all the
  files in a given directory to the input list (including files in abitrarily
  nested subdirectories).
* Abstracted the parser behavior further. Processor no longer needs to know
  about Parboiled ParseRunners and can use non-Parboiled parsers.
* Created the JLPParser interface to support the new parser abstraction.
* JLPPegParser implements the new interface trivially by creating it's own parse
  runner and calling it with the input given.
* Added MarkdownParser, which does not actually parse the file, just creates the
  bare-bones SourceFile object needed for the generator to emit the Markdown
  contents.
This commit is contained in:
Jonathan Bernard
2011-12-25 23:11:21 -06:00
parent 9eb80e91a6
commit 1f9b6cc66d
9 changed files with 122 additions and 29 deletions

View File

@ -73,19 +73,27 @@ public class JLPMain {
// get files passed in
def filenames = opts.getArgs()
def inputFiles = (filenames.collect { filename ->
def inputFiles = []
filenames.each { filename ->
// create a File object
File file = new File(filename)
File file = new File(filename)
// if this is a relative path, resolve it against our path root
if (!file.isAbsolute()) { file = new File(pathRoot, filename) }
// warn the user about files that do not exist
if (!file.exists()) {
System.err.println
"'${file.canonicalPath}' does not exist: ignored." }
return file }).findAll { it.exists() }
// if this file does not exist, warn the user and skip it
if (!file.exists()) {
System.err.println(
"'${file.canonicalPath}' does not exist: ignored.")
return }
// if this file is a directory, add all the files in it (recurse
// into sub-directories and add their contents as well).
if (file.isDirectory()) { file.eachFileRecurse {
if (it.isFile()) { inputFiles << it }}}
else { inputFiles << file } }
Processor.process(outputDir, css, inputFiles)
}

View File

@ -0,0 +1,6 @@
package com.jdblabs.jlp;
import com.jdblabs.jlp.ast.SourceFile;
public interface JLPParser {
public SourceFile parse(String input); }

View File

@ -8,9 +8,10 @@ import org.parboiled.BaseParser;
import org.parboiled.Context;
import org.parboiled.Rule;
import org.parboiled.annotations.*;
import org.parboiled.parserunners.ReportingParseRunner;
@BuildParseTree
public class JLPPegParser extends BaseParser<Object> {
public class JLPPegParser extends BaseParser<Object> implements JLPParser {
int curLineNum = 1;
@ -31,6 +32,10 @@ public class JLPPegParser extends BaseParser<Object> {
public JLPPegParser() {
this("/**", "*/", "!#$%^&*()_-=+|;:'\",<>?~`", "///"); }
public SourceFile parse(String input) {
ReportingParseRunner rpr = new ReportingParseRunner(this.SourceFile());
return (SourceFile) rpr.run(input).resultValue; }
/**
* Parses the rule:
* SourceFile = (Block / DocBlock / CodeBlock)+

View File

@ -0,0 +1,20 @@
package com.jdblabs.jlp
import com.jdblabs.jlp.ast.*
public class MarkdownParser implements JLPParser {
public SourceFile parse(String input) {
def sourceFile = new SourceFile()
def block
def docBlock = new DocBlock(0)
def codeBlock = new CodeBlock(0)
def docText = new DocText(0)
docText.value = input
docBlock.docTexts << docText
block = new Block(codeBlock, docBlock, 0)
sourceFile.blocks << block
return sourceFile }}

View File

@ -2,7 +2,6 @@ package com.jdblabs.jlp
import org.parboiled.BaseParser
import org.parboiled.Parboiled
import org.parboiled.parserunners.ReportingParseRunner
/**
* Processor processes one batch of input files to create a set of output files.
@ -22,7 +21,7 @@ public class Processor {
// shortcut for docs[currentDocId]
public TargetDoc currentDoc
protected Map<String, BaseParser> parsers = [:]
protected Map<String, JLPParser> parsers = [:]
protected Map<String, JLPBaseGenerator> generators = [:]
public static void process(File outputDir, String css,
@ -61,11 +60,9 @@ public class Processor {
// TODO: add logic to configure or autodetect the correct parser for
// each file
def parser = getParser(sourceTypeForFile(currentDoc.sourceFile))
def parseRunner = new ReportingParseRunner(parser.SourceFile())
// TODO: error detection
currentDoc.sourceAST = parseRunner.run(
currentDoc.sourceFile.text).resultValue }
currentDoc.sourceAST = parser.parse(currentDoc.sourceFile.text) }
// run our generator parse phase (first pass over the ASTs)
processDocs {
@ -175,6 +172,7 @@ public class Processor {
case 'groovy': return 'groovy';
case 'java': return 'java';
case 'js': return 'javascript';
case 'md': return 'markdown';
default: return 'unknown'; }}
protected getGenerator(String sourceType) {
@ -187,13 +185,14 @@ public class Processor {
return generators[sourceType] }
protected getParser(String sourceType) {
println "Looking for a ${sourceType} parser."
if (parsers[sourceType] == null) {
switch(sourceType) {
case 'erlang':
parsers[sourceType] = Parboiled.createParser(
JLPPegParser, '%%')
println "Built an erlang parser."
break
case 'markdown':
parsers[sourceType] = new MarkdownParser()
break
case 'c':
case 'c++':
@ -203,7 +202,6 @@ public class Processor {
default:
parsers[sourceType] = Parboiled.createParser(JLPPegParser,
'/**', '*/', '!#$%^&*()_-=+|;:\'",<>?~`', '///')
println "Built a java parser."
break }}
return parsers[sourceType] }