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

@ -1,13 +1,20 @@
<project name="Jonathan's Literate Programming" basedir="." default="release">
<import file="jdb-build-1.6.xml"/>
<import file="jdb-build-1.9.xml"/>
<property environment="env"/>
<property file="project.properties"/>
<target name="release" depends="build">
<mkdir dir="${release.dir}/lib"/>
<copy file="${build.dir}/${name}-${version}.${build.number}.jar"
tofile="${release.dir}/${name}-${version}.jar"/>
<copy file="${basedir}/jlp" todir="${release.dir}"/>
<copy todir="${release.dir}">
<fileset dir="${resources.dir}/release"/>
</copy>
<copy todir="${release.dir}/lib">
<fileset dir="${build.dir}/lib/runtime/jar"/>
</copy>
</target>
</project>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<project name="Jonathan Bernard Build Common">
<project name="Jonathan Bernard Build Common"
xmlns:ivy="antlib:org.apache.ivy.ant">
<property environment="env"/>
@ -16,6 +17,7 @@
<property name="build.dir" value="${basedir}/build"/>
<property name="lib.dir" value="${basedir}/lib"/>
<property name="resources.dir" value="${basedir}/resources"/>
<property name="splash.image" value="splash.png"/>
<!--======== PATHS ========-->
<path id="groovy.classpath">
@ -59,9 +61,25 @@
</target>
<!--======== LIBRARY TARGETS ========-->
<target name="lib" depends="-lib-local,-lib-ivy"/>
<target name="-lib" depends="-lib-local,-lib-ivy,lib"/>
<target name="lib"/>
<target name="-lib-ivy" unless="${lib.local}"/>
<target name="-init-ivy">
<ivy:settings id="ivy.settings" file="ivysettings.xml"/>
</target>
<target name="-lib-ivy" depends="-init-ivy" unless="${lib.local}">
<ivy:retrieve settingsRef="ivy.settings"
pattern="${lib.dir}/[conf]/[type]/[artifact]-[revision].[ext]"
conf="compile,runtime"/>
</target>
<target name="-lib-groovy" if="${lib.local}">
<copy todir="${build.dir}/lib/runtime/jar">
<fileset dir="${env.GROOVY_HOME}/embeddable"/>
</copy>
</target>
<target name="-lib-local" if="${lib.local}">
<echo message="Resolving libraries locally."/>
@ -96,7 +114,7 @@
</target>
<!--======== COMPILATION TARGETS ========-->
<target name="-compile-groovy" depends="-init,-init-groovy,lib">
<target name="-compile-groovy" depends="-init,-init-groovy,-lib,-lib-groovy">
<mkdir dir="${build.dir}/main/classes"/>
<groovyc srcdir="${src.dir}/main" destdir="${build.dir}/main/classes"
includeAntRuntime="false">
@ -109,7 +127,7 @@
</groovyc>
</target>
<target name="-compile-java" depends="-init,lib">
<target name="-compile-java" depends="-init,-lib">
<mkdir dir="${build.dir}/main/classes"/>
<javac srcdir="${src.dir}/main" destdir="${build.dir}/main/classes"
includeAntRuntime="false" classpathref="compile-libs"/>
@ -178,13 +196,42 @@
</target>
<!--======== BUILD TARGETS ========-->
<target name="-build-modular"
<target name="-build-modular-lib" unless="executable.jar"
depends="compile,increment-build-number,resources">
<jar destfile="${build.dir}/${name}-${version}.${build.number}.jar"
basedir="${build.dir}/main/classes"/>
</target>
<target name="-build-modular-executable" if="executable.jar"
depends="compile,increment-build-number,resources">
<pathconvert property="jar.classpath" pathsep=" " refid="runtime-libs">
<mapper>
<chainedmapper>
<!-- remove absolute path -->
<flattenmapper />
<!-- add lib/ prefix -->
<globmapper from="*" to="lib/*" />
</chainedmapper>
</mapper>
</pathconvert>
<jar destfile="${build.dir}/${name}-${version}.${build.number}.jar"
basedir="${build.dir}/main/classes">
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
<attribute name="SplashScreen-Image" value="${splash.image}"/>
</manifest>
</jar>
</target>
<target name="-build-modular"
depends="-build-modular-lib,-build-modular-executable"/>
<target name="-build-packed-libs"
depends="compile,increment-build-number,resources">

View File

@ -1,6 +1,8 @@
#Sun, 25 Dec 2011 21:56:17 -0600
#Sun, 25 Dec 2011 23:07:02 -0600
name=jlp
version=1.0
build.number=0
version=1.1
build.number=6
lib.local=true
release.dir=release
main.class=com.jdblabs.jlp.JLPMain
executable.jar=true

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] }