Compare commits

...

9 Commits

47 changed files with 86 additions and 303 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.gradle/
docs/jlp-docs/ docs/jlp-docs/
build/ build/
.*.sw? .*.sw?

View File

@ -1,5 +1,8 @@
# J Literate Programming # J Literate Programming
* [Source](https://git.jdb-labs.com/jdb-labs/jlp)
* [Annotated Source and Documentation](https://doc.jdb-labs.com/jlp/current/)
## Overview ## Overview
*Jonathan's Literate Programming* is my take on literate programming. *Jonathan's Literate Programming* is my take on literate programming.
This project grew out of a desire for a documentation system that: This project grew out of a desire for a documentation system that:
@ -57,14 +60,19 @@ This project is in its infancy and some of the larger goals are still unmet:
## Project Architecture ## Project Architecture
JLP processes it's own documentation. The latest documentation is available at
https://doc.jdb-labs.com/jlp/current/
Below are some starting points.
### Control and Flow ### Control and Flow
* [JLPMain](https://jdbernard.github.io/jlp/doc/src/com/jdblabs/jlp/JLPMain.groovy.html) * [JLPMain](https://doc.jdb-labs.com/jlp/current/src/main/groovy/com/jdblabs/jlp/JLPMain.groovy.html)
The entry point to the JLP executable. Parses the command line input and The entry point to the JLP executable. Parses the command line input and
sets up the processor. sets up the processor.
* [Processor](https://jdbernard.github.io/jlp/doc/src/com/jdblabs/jlp/Processor) * [Processor](https://doc.jdb-labs.com/jlp/current/src/main/groovy/com/jdblabs/jlp/Processor.groovy.html)
The Processor processes one batch of input files to create a set of output files. The Processor processes one batch of input files to create a set of output files.
It holds the intermediate state needed by the generators and coordinates the It holds the intermediate state needed by the generators and coordinates the
@ -72,14 +80,14 @@ This project is in its infancy and some of the larger goals are still unmet:
processor only generates HTML documentation and will likely be renamed in processor only generates HTML documentation and will likely be renamed in
the future to reflect this. the future to reflect this.
* [JLPBaseGenerator](https://jdbernard.github.io/jlp/doc/src/com/jdblabs/jlp/JLPBaseGenerator) * [JLPBaseGenerator](https://doc.jdb-labs.com/jlp/current/src/main/groovy/com/jdblabs/jlp/JLPBaseGenerator.groovy.html)
The Generator processes one input file. It parses the AST for the input file The Generator processes one input file. It parses the AST for the input file
and emits the final documentation for the file. JLPBaseGenerator and emits the final documentation for the file. JLPBaseGenerator
implementations are expected to be tightly coupled to Processor implementations are expected to be tightly coupled to Processor
implementations. implementations.
* [LiterateMarkdownGenerator](https://jdbernard.github.io/jlp/doc/src/com/jdblabs/jlp/LiterateMarkdownGenerator) * [LiterateMarkdownGenerator](https://doc.jdb-labs.com/jlp/current/src/main/groovy/com/jdblabs/jlp/LiterateMarkdownGenerator.groovy.html)
This implemetation of JLPBaseGenerator generates literate-style This implemetation of JLPBaseGenerator generates literate-style
documentation (as opposed to API-style), using documentation (as opposed to API-style), using
@ -88,11 +96,11 @@ This project is in its infancy and some of the larger goals are still unmet:
### Parsing ### Parsing
* [JLPParser](https://jdbernard.github.io/jlp/doc/src/com/jdblabs/jlp/JLPParser) * [JLPParser](https://doc.jdb-labs.com/jlp/current/src/main/groovy/com/jdblabs/jlp/JLPParser.groovy.html)
A very simple interface for parsing JLP input. A very simple interface for parsing JLP input.
* [JLPPegParser](https://jdbernard.github.io/jlp/doc/src/com/jdblabs/jlp/JLPPegParser) * [JLPPegParser](https://doc.jdb-labs.com/jlp/current/src/main/groovy/com/jdblabs/jlp/JLPPegParser.groovy.html)
A [PEG parser](http://en.wikipedia.org/wiki/Parsing_expression_grammar) A [PEG parser](http://en.wikipedia.org/wiki/Parsing_expression_grammar)
implemented using the [parboiled](http://www.parboiled.org) library. This implemented using the [parboiled](http://www.parboiled.org) library. This
@ -102,6 +110,6 @@ This project is in its infancy and some of the larger goals are still unmet:
### Abstract Syntax Tree ### Abstract Syntax Tree
* [SourceFile](https://jdbernard.github.io/jlp/doc/src/com/jdblabs/jlp/JLPPegParserSourceFile) * [SourceFile](https://doc.jdb-labs.com/jlp/current/src/main/groovy/com/jdblabs/jlp/JLPPegParserSourceFile.groovy.html)
The top-level AST element. This represents a source file. The top-level AST element. This represents a source file.

27
build.gradle Normal file
View File

@ -0,0 +1,27 @@
apply plugin: "groovy"
apply plugin: "maven"
group = "com.jdblabs"
version = "1.9"
repositories {
mavenLocal()
mavenCentral() }
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.6'
compile 'org.pegdown:pegdown:1.4.2'
compile 'org.slf4j:slf4j-api:1.7.10'
compile 'ch.qos.logback:logback-core:1.1.2'
compile 'ch.qos.logback:logback-classic:1.1.2'
compile 'commons-cli:commons-cli:1.2'
compile 'org.apache.commons:commons-lang3:3.3.2'
compile 'com.jdbernard:jdb-util:3.4'
compile 'org.pegdown:pegdown:1.4.2'
}
jar {
manifest {
attributes("Main-Class": "com.jdbernard.remindme.DailyAgenda")
}
}

View File

@ -1,20 +0,0 @@
<project name="Jonathan's Literate Programming" basedir="." default="release">
<import file="jdb-build-1.10.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 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,248 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<project name="Jonathan Bernard Build Common"
xmlns:ivy="antlib:org.apache.ivy.ant">
<property environment="env"/>
<!--======== INIT TARGETS ========-->
<target name="-init" depends="-common-init,init"/>
<target name="-common-init">
<!-- Set default values for some key properties. Since properties are
write once, any value set before this point takes precedence. -->
<property name="versioning.file" value="project.properties"/>
<property name="src.dir" value="${basedir}/src"/>
<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">
<fileset dir="${env.GROOVY_HOME}/lib">
<include name="*.jar"/>
</fileset>
</path>
<path id="groovy.embeddable">
<fileset dir="${env.GROOVY_HOME}/embeddable">
<include name="*.jar"/>
</fileset>
</path>
<path id="compile-libs">
<fileset dir="${build.dir}/lib/compile/jar">
<include name="*.jar"/>
</fileset>
</path>
<path id="runtime-libs">
<fileset dir="${build.dir}/lib/runtime/jar">
<include name="*.jar"/>
</fileset>
</path>
</target>
<target name="-init-groovy">
<taskdef name="groovyc" classpathref="groovy.classpath"
classname="org.codehaus.groovy.ant.Groovyc"/>
<taskdef name="groovy" classpathref="groovy.classpath"
classname="org.codehaus.groovy.ant.Groovy"/>
</target>
<target name="init"/>
<target name="clean" depends="-init">
<delete dir="${build.dir}"/>
</target>
<!--======== LIBRARY TARGETS ========-->
<target name="-lib" depends="-lib-local,-lib-ivy,lib"/>
<target name="lib"/>
<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."/>
<mkdir dir="${build.dir}/lib/compile/jar"/>
<mkdir dir="${build.dir}/lib/runtime/jar"/>
<copy todir="${build.dir}/lib/compile/jar" failonerror="false">
<fileset dir="${lib.dir}/compile/jar"/>
</copy>
<copy todir="${build.dir}/lib/runtime/jar" failonerror="false">
<fileset dir="${lib.dir}/runtime/jar"/>
</copy>
</target>
<!--======== VERSIONING TARGETS ========-->
<target name="increment-build-number" depends="-init">
<propertyfile file="${versioning.file}">
<entry key="build.number" default="0" type="int" value="1"
operation="+"/>
</propertyfile>
</target>
<target name="set-version" depends="-init">
<input
message="The current version is ${version}. Enter a new version: "
addproperty="new-version"/>
<propertyfile file="${versioning.file}">
<entry key="version" value="${new-version}" operation="="
type="string"/>
<entry key="build.number" value="0" type="int" operation="="/>
</propertyfile>
</target>
<!--======== COMPILATION TARGETS ========-->
<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" fork="true">
<classpath>
<path refid="groovy.classpath"/>
<path refid="compile-libs"/>
</classpath>
<javac/>
</groovyc>
</target>
<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"/>
</target>
<target name="compile" depends="-compile-groovy"/>
<!--======== JUNIT TARGETS ========-->
<target name="-compile-tests-groovy" depends="-init,compile">
<mkdir dir="${build.dir}/test/classes"/>
<groovyc srcdir="${src.dir}/test" destdir="${build.dir}/test/classes"
includeAntRuntime="false" fork="true">
<classpath>
<path refid="groovy.classpath"/>
<path refid="compile-libs"/>
<path location="${build.dir}/main/classes"/>
</classpath>
</groovyc>
</target>
<target name="-compile-tests-java" depends="-init,compile">
<mkdir dir="${build.dir}/test/classes"/>
<javac srcdir="${src.dir}/test" destdir="${build.dir}/test/classes"
includeAntRuntime="false">
<classpath>
<path refid="compile-libs"/>
<path location="${build.dir}/main/classes"/>
</classpath>
</javac>
</target>
<target name="compile-tests" depends="-compile-tests-groovy"/>
<target name="run-tests" depends="compile-tests,resources-test">
<junit printsummary="true">
<classpath>
<path refid="groovy.classpath"/>
<path refid="compile-libs"/>
<path location="${build.dir}/main/classes"/>
<path location="${build.dir}/test/classes"/>
</classpath>
<formatter type="plain" usefile="false"/>
<batchtest>
<fileset dir="${build.dir}/test/classes">
<include name="**/*"/>
</fileset>
</batchtest>
</junit>
</target>
<!--======== RESOURCES TARGETS ========-->
<target name="resources" depends="-init">
<mkdir dir="${build.dir}/main/classes"/>
<copy todir="${build.dir}/main/classes" failonerror="false">
<fileset dir="${resources.dir}/main/"/>
</copy>
</target>
<target name="resources-test" depends="-init">
<mkdir dir="${build.dir}/test/classes"/>
<copy todir="${build.dir}/test/classes" failonerror="false">
<fileset dir="${resources.dir}/test/"/>
</copy>
</target>
<!--======== BUILD TARGETS ========-->
<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">
<unjar destdir="${build.dir}/main/classes">
<fileset dir="${build.dir}/lib/runtime/jar"/>
</unjar>
<jar destfile="${build.dir}/${name}-${version}.${build.number}.jar"
basedir="${build.dir}/main/classes"/>
</target>
<target name="build" depends="-build-modular"/>
</project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +0,0 @@
#Tue, 13 Aug 2013 08:48:43 -0500
name=jlp
version=1.7
build.number=25
lib.local=true
release.dir=release
main.class=com.jdblabs.jlp.JLPMain
executable.jar=true

View File

@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory
*/ */
public class JLPMain { public class JLPMain {
public static final String VERSION = "1.7" public static final String VERSION = "1.9"
private static Logger log = LoggerFactory.getLogger(JLPMain.class) private static Logger log = LoggerFactory.getLogger(JLPMain.class)

View File

@ -13,7 +13,7 @@ import com.jdblabs.jlp.ast.SourceFile;
* be an abstract class implementing methods that take additional input for * be an abstract class implementing methods that take additional input for
* convenience. * convenience.
* *
* [`SourceFile`]: jlp://jlp.jdb-labs.com/SourceFile * [`SourceFile`]: jlp://jlp.jdb-labs.com/ast/SourceFile
* *
* @org jlp.jdb-labs.com/JLPParser * @org jlp.jdb-labs.com/JLPParser
*/ */

View File

@ -40,8 +40,8 @@ public class JLPPegParser extends BaseParser<Object> implements JLPParser {
*/ */
/** /**
* #### Full constructor * #### Full constructor.
* This allows the caller to specific all four of the comment delimiters * This allows the caller to specify all four of the comment delimiters
* recognized by the parser. * recognized by the parser.
*/ */
public JLPPegParser(String mdocStart, String mdocEnd, public JLPPegParser(String mdocStart, String mdocEnd,
@ -52,6 +52,20 @@ public class JLPPegParser extends BaseParser<Object> implements JLPParser {
SDOC_START = String(sdocStart).label("SDOC_START"); SDOC_START = String(sdocStart).label("SDOC_START");
MDOC_LINE_START = AnyOf(mdocLineStart).label("MDOC_LINE_START"); } MDOC_LINE_START = AnyOf(mdocLineStart).label("MDOC_LINE_START"); }
/**
* #### Full constructor supporting multiple comment types.
* This allows the caller to specify all four of the comment delimiters
* recognized by the parser, supplying multiple types of comment
* delimiters.
*/
public JLPPegParser(List mdocStarts, List mdocEnds,
String mdocLineStarts, List sdocStart) {
MDOC_START = FirstOf(mdocStarts.toArray()).label("MDOC_START");
MDOC_END = FirstOf(mdocEnds.toArray()).label("MDOC_END");
SDOC_START = FirstOf(mdocStarts.toArray()).label("SDOC_START");
MDOC_LINE_START = AnyOf(mdocLineStarts).label("MDOC_LINE_START"); }
/** /**
* #### Single-line comments only constructor. * #### Single-line comments only constructor.
* This allows the caller to easily set up the parser to only recognize * This allows the caller to easily set up the parser to only recognize
@ -292,7 +306,7 @@ public class JLPPegParser extends BaseParser<Object> implements JLPParser {
* Parses the rule: * Parses the rule:
* *
* SLongDirective = * SLongDirective =
* (API_DIR / EXAMPLE_DIR) RemainingSDocLine SDocText? * (API_DIR / EXAMPLE_DIR / PARAM_DIR) RemainingSDocLine SDocText?
* *
* Pushes a [`Directive`] node onto the stack. * Pushes a [`Directive`] node onto the stack.
* *
@ -302,7 +316,7 @@ public class JLPPegParser extends BaseParser<Object> implements JLPParser {
return Sequence( return Sequence(
push(curLineNum), push(curLineNum),
FirstOf(API_DIR, EXAMPLE_DIR), push(match()), FirstOf(API_DIR, EXAMPLE_DIR, PARAM_DIR), push(match()),
RemainingSDocLine(), push(match()), RemainingSDocLine(), push(match()),
Optional(Sequence( Optional(Sequence(
@ -318,7 +332,7 @@ public class JLPPegParser extends BaseParser<Object> implements JLPParser {
* Parses the rule: * Parses the rule:
* *
* MLongDirective = * MLongDirective =
* (API_DIR / EXAMPLE_DIR) RemainingMDocLine MDocText? * (API_DIR / EXAMPLE_DIR / PARAM_DIR) RemainingMDocLine MDocText?
* *
* Pushes a [`Directive`] node onto the stack. * Pushes a [`Directive`] node onto the stack.
* *
@ -328,7 +342,7 @@ public class JLPPegParser extends BaseParser<Object> implements JLPParser {
return Sequence( return Sequence(
push(curLineNum), push(curLineNum),
FirstOf(API_DIR, EXAMPLE_DIR), push(match()), FirstOf(API_DIR, EXAMPLE_DIR, PARAM_DIR), push(match()),
RemainingMDocLine(), push(match()), RemainingMDocLine(), push(match()),
Optional(Sequence( Optional(Sequence(
@ -497,6 +511,7 @@ public class JLPPegParser extends BaseParser<Object> implements JLPParser {
Rule EXAMPLE_DIR = IgnoreCase("example"); Rule EXAMPLE_DIR = IgnoreCase("example");
Rule INCLUDE_DIR = IgnoreCase("include"); Rule INCLUDE_DIR = IgnoreCase("include");
Rule ORG_DIR = IgnoreCase("org"); Rule ORG_DIR = IgnoreCase("org");
Rule PARAM_DIR = IgnoreCase("param");
/// #### Hard-coded terminals. /// #### Hard-coded terminals.
Rule AT = Ch('@').label("AT"); Rule AT = Ch('@').label("AT");

View File

@ -217,7 +217,7 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
/// Close the table row. /// Close the table row.
sb.append('</tr>') } sb.append('</tr>') }
/** @api Emit a [`DocBlock`](jlp://jlp/jdb-labs.com/ast/DocBlock). */ /** @api Emit a [`DocBlock`](jlp://jlp.jdb-labs.com/ast/DocBlock). */
protected String emit(DocBlock docBlock) { protected String emit(DocBlock docBlock) {
/// Create a queue for the doc block elements, we are going to /// Create a queue for the doc block elements, we are going to
/// sort them by type and line number /// sort them by type and line number
@ -248,7 +248,7 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
[lineNumber, line] } [lineNumber, line] }
/// Sort by line number. /// Sort by line number.
codeLines.sort({ i1, i2 -> i1[0] - i2[0] } as Comparator) codeLines.sort { i1, i2 -> i1[0] <=> i2[0] }
codeLines = codeLines.collect { arr -> arr[1] } codeLines = codeLines.collect { arr -> arr[1] }
@ -281,6 +281,9 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
case DirectiveType.Example: case DirectiveType.Example:
return directive.value return directive.value
case DirectiveType.Param:
return "" // TODO: can we do better here, even though we're
// not understanding the source yet?
// TODO: // TODO:
// case DirectiveType.Include: // case DirectiveType.Include:

View File

@ -128,7 +128,7 @@ public class Processor {
// Get the relative path as path elements. // Get the relative path as path elements.
def relPath = getRelativeFilepath(inputRoot, file) def relPath = getRelativeFilepath(inputRoot, file)
def pathParts = relPath.split('/') as List def pathParts = relPath.split('/|\\\\') as List
// We will skip binary files and files we know nothing about. // We will skip binary files and files we know nothing about.
def fileType = sourceTypeForFile(file) def fileType = sourceTypeForFile(file)
@ -304,8 +304,8 @@ public class Processor {
if (!root.isDirectory()) root= root.parentFile if (!root.isDirectory()) root= root.parentFile
/// Split both paths into their individual parts. /// Split both paths into their individual parts.
def rootPath = root.canonicalPath.split('/') def rootPath = root.canonicalPath.split('/|\\\\')
def filePath = file.canonicalPath.split('/') def filePath = file.canonicalPath.split('/|\\\\')
def relativePath = [] def relativePath = []
@ -331,8 +331,8 @@ public class Processor {
* @org jlp.jdb-labs.com/Processor/getCommonParent * @org jlp.jdb-labs.com/Processor/getCommonParent
*/ */
public static File getCommonParent(File file1, File file2) { public static File getCommonParent(File file1, File file2) {
def path1 = file1.canonicalPath.split('/') def path1 = file1.canonicalPath.split('/|\\\\')
def path2 = file2.canonicalPath.split('/') def path2 = file2.canonicalPath.split('/|\\\\')
def newPath = [] def newPath = []
// build new commonPath based on matching paths so far // build new commonPath based on matching paths so far
@ -438,8 +438,8 @@ public class Processor {
break break
case 'html': case 'xml': case 'html': case 'xml':
parsers[sourceType] = Parboiled.createParser( parsers[sourceType] = Parboiled.createParser(
JLPPegParser, '<!--', '-->', JLPPegParser, '<!--!', '-->',
'#$%^&*()_-+=|;:\'",<>?~`', '<<?') '!#$%^&*()_-+=|;:\'",<>?~`', '<<?')
break break
case 'sql': case 'sql':
parsers[sourceType] = Parboiled.createParser(JLPPegParser, parsers[sourceType] = Parboiled.createParser(JLPPegParser,

View File

@ -50,10 +50,15 @@ public class Directive extends ASTNode {
* the [`LinkAnchor`] documentation for more information about link * the [`LinkAnchor`] documentation for more information about link
* anchors. * anchors.
* *
* Param
* : Used to document a parameter to a function, method, or subroutine.
* This is typically used in API documentation, but no generator
* currently knows how to do anything intelligent with this directive.
*
* [`LinkAnchor`]: jlp://jlp.jdb-labs.com/LinkAnchor * [`LinkAnchor`]: jlp://jlp.jdb-labs.com/LinkAnchor
*/ */
public static enum DirectiveType { public static enum DirectiveType {
Api, Author, Copyright, Example, Include, Org; Api, Author, Copyright, Example, Include, Org, Param;
public static DirectiveType parse(String typeString) { public static DirectiveType parse(String typeString) {
valueOf(typeString.toLowerCase().capitalize()) } } valueOf(typeString.toLowerCase().capitalize()) } }