Worked on documentation, parser.
* Added planning documentation regrding the process. * Updated grammer. * Refactored the test code a bit. * Added sample input file from vbs-suite * Refactored the AST node structure created by the parser.
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
package com.jdblabs.jlp
|
||||
|
||||
import com.jdblabs.jlp.ast.ASTNode
|
||||
import org.parboiled.Parboiled
|
||||
import org.parboiled.parserunners.ReportingParseRunner
|
||||
|
||||
@ -31,8 +32,10 @@ public class JLPMain {
|
||||
def files = filenames.collect { new File(it) }
|
||||
|
||||
// -------- parse input -------- //
|
||||
Map parsed = files.inject([:]) { docContext, file ->
|
||||
inst.parse(new File(file), docContext) }
|
||||
Map parsedFiles = files.inject([:]) { acc, file ->
|
||||
def parsed = inst.parse(new File(file))
|
||||
acc[file.canonicalPath] = parsed
|
||||
return acc }
|
||||
|
||||
// -------- generate output -------- //
|
||||
}
|
||||
@ -41,11 +44,14 @@ public class JLPMain {
|
||||
parser = Parboiled.createParser(JLPPegParser.class)
|
||||
}
|
||||
|
||||
public Map parse(File inputFile, Map docCtx) {
|
||||
public Map parse(File inputFile) {
|
||||
def parseRunner = new ReportingParseRunner(parser.SourceFile())
|
||||
|
||||
// parse the file
|
||||
def firstPass = parseRunner.run(inputFile)
|
||||
return parseRunner.run(inputFile).resultValue
|
||||
}
|
||||
|
||||
public def generate(def emitter, List<ASTNode> blocks) {
|
||||
// second pass, semantics
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import org.parboiled.Rule;
|
||||
import org.parboiled.annotations.*;
|
||||
|
||||
import static com.jdblabs.jlp.ast.TextBlock.makeCodeBlock;
|
||||
import static com.jdblabs.jlp.ast.TextBlock.makeMarkdownBlock;
|
||||
import static com.jdblabs.jlp.ast.TextBlock.makeTextBlock;
|
||||
|
||||
@BuildParseTree
|
||||
public class JLPPegParser extends BaseParser<Object> {
|
||||
@ -20,7 +20,7 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
public Rule SourceFile() {
|
||||
return Sequence(
|
||||
clearLineCount(),
|
||||
push(new ArrayList<Object>()),
|
||||
push(new ArrayList<ASTNode>()),
|
||||
ZeroOrMore(Sequence(
|
||||
FirstOf(
|
||||
DocBlock(),
|
||||
@ -29,22 +29,19 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
|
||||
/**
|
||||
* Parses the rule:
|
||||
* DocBlock = DirectiveBlock / MarkdownBlock
|
||||
* DocBlock = (DirectiveBlock / DocTextBlock)+
|
||||
*
|
||||
* Pushes a DocBlock object onto the stack.
|
||||
*/
|
||||
Rule DocBlock() {
|
||||
return Sequence(
|
||||
push(new ArrayList<ASTNode>()),
|
||||
OneOrMore(Sequence(
|
||||
push(new DocBlock(curLineNum)),
|
||||
OneOrMore(
|
||||
FirstOf(
|
||||
DirectiveBlock(),
|
||||
MarkdownBlock()),
|
||||
|
||||
// stack is now: [List<ASTNode>, BlockValue *top*]
|
||||
// pop the Block, then List, pass to helper to add the
|
||||
// Block to the list, then push the List back on
|
||||
push(addToList((ASTNode)pop(), (List<ASTNode>)pop()))))); }
|
||||
Sequence(DirectiveBlock(),
|
||||
push(addDirectiveBlock((Directive) pop(), (DocBlock) pop()))),
|
||||
Sequence(DocTextBlock(),
|
||||
push(addTextBlock((TextBlock) pop(), (DocBlock) pop())))))); }
|
||||
|
||||
/**
|
||||
* Parses the rule:
|
||||
@ -55,13 +52,15 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
Rule CodeBlock() {
|
||||
return Sequence(
|
||||
push(curLineNum),
|
||||
TestNot(DOC_START), RemainingLine(), push(match()),
|
||||
ZeroOrMore(Sequence(
|
||||
TestNot(DOC_START), RemainingLine(),
|
||||
push(popAsString() + match()))),
|
||||
push(""),
|
||||
OneOrMore(FirstOf(
|
||||
Sequence(
|
||||
TestNot(DOC_START), RemainingLine(),
|
||||
push(popAsString() + match())),
|
||||
Sequence(EmptyLine(),
|
||||
push(popAsString() + match())))),
|
||||
push(makeCodeBlock(popAsString(),popAsInt()))); }
|
||||
|
||||
push(makeCodeBlock(popAsString(), popAsInt()))); }
|
||||
|
||||
/**
|
||||
* Parses the rule:
|
||||
* DirectiveBlock =
|
||||
@ -77,7 +76,7 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
/**
|
||||
* Parses the rule:
|
||||
* LongDirective =
|
||||
* (AUTHOR_DIR / DOC_DIR / EXAMPLE_DIR) RemainingLine MarkdownBlock?
|
||||
* (AUTHOR_DIR / DOC_DIR / EXAMPLE_DIR) RemainingLine DocTextBlock?
|
||||
*
|
||||
* Pushes a Directive object onto the value stack.
|
||||
*/
|
||||
@ -87,7 +86,7 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
FirstOf(AUTHOR_DIR, DOC_DIR, EXAMPLE_DIR), push(match()),
|
||||
RemainingLine(), push(match()),
|
||||
Optional(Sequence(
|
||||
MarkdownBlock(), // pushes block
|
||||
DocTextBlock(), // pushes block
|
||||
swap(),
|
||||
push(popAsString() + ((TextBlock) pop()).value))),
|
||||
|
||||
@ -112,29 +111,29 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
|
||||
/**
|
||||
* Parses the rule:
|
||||
* MarkdownBlock = MarkdownLine+
|
||||
* DocTextBlock = DocTextLine+
|
||||
*
|
||||
* Pushes a MarkdownBlock onto the stack as a string.
|
||||
* Pushes a DocTextBlock onto the stack as a string.
|
||||
*/
|
||||
Rule MarkdownBlock() {
|
||||
Rule DocTextBlock() {
|
||||
return Sequence(
|
||||
push(curLineNum),
|
||||
MarkdownLine(), // pushes the value onto the stack
|
||||
DocTextLine(), // pushes the value onto the stack
|
||||
ZeroOrMore(Sequence(
|
||||
MarkdownLine(),
|
||||
DocTextLine(),
|
||||
swap(),
|
||||
push(popAsString() + popAsString()))),
|
||||
|
||||
push(makeMarkdownBlock(popAsString(), popAsInt()))); }
|
||||
push(makeTextBlock(popAsString(), popAsInt()))); }
|
||||
|
||||
/**
|
||||
* Parses the rule:
|
||||
* MarkdownLine =
|
||||
* DocTextLine =
|
||||
* DOC_START !DIRECTIVE_START RemainingLine
|
||||
*
|
||||
* Pushes the line value (not including the DOC_START) onto the stack.
|
||||
*/
|
||||
Rule MarkdownLine() {
|
||||
Rule DocTextLine() {
|
||||
return Sequence(
|
||||
DOC_START, TestNot(DIRECTIVE_START),
|
||||
RemainingLine(), push(match())); }
|
||||
@ -145,13 +144,17 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
*/
|
||||
@SuppressSubnodes
|
||||
Rule RemainingLine() {
|
||||
return Sequence(OneOrMore(NOT_EOL), EOL, incLineCount()); }
|
||||
return Sequence(OneOrMore(NOT_EOL), FirstOf(EOL, EOI), incLineCount()); }
|
||||
|
||||
Rule EmptyLine() {
|
||||
return Sequence(EOL, incLineCount()); }
|
||||
|
||||
Rule DOC_START = String("%% ");
|
||||
Rule EOL = FirstOf(Ch('\n'), EOI);
|
||||
Rule EOL = Ch('\n');
|
||||
Rule NOT_EOL = Sequence(TestNot(EOL), ANY);
|
||||
Rule DIRECTIVE_START= Ch('@');
|
||||
Rule SLASH = Ch('/');
|
||||
Rule SPACE = AnyOf(" \t");
|
||||
|
||||
// directive terminals
|
||||
Rule AUTHOR_DIR = IgnoreCase("author");
|
||||
@ -175,4 +178,12 @@ public class JLPPegParser extends BaseParser<Object> {
|
||||
boolean clearLineCount() { curLineNum = 1; return true; }
|
||||
|
||||
boolean incLineCount() { curLineNum++; return true; }
|
||||
|
||||
boolean echo(String msg) { System.out.println(msg); return true; }
|
||||
|
||||
static DocBlock addDirectiveBlock(Directive dir, DocBlock docBlock) {
|
||||
docBlock.directives.add(dir); return docBlock; }
|
||||
|
||||
static DocBlock addTextBlock(TextBlock tb, DocBlock docBlock) {
|
||||
docBlock.textBlocks.add(tb); return docBlock; }
|
||||
}
|
||||
|
18
src/main/com/jdblabs/jlp/ast/DocBlock.groovy
Normal file
18
src/main/com/jdblabs/jlp/ast/DocBlock.groovy
Normal file
@ -0,0 +1,18 @@
|
||||
package com.jdblabs.jlp.ast
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.List
|
||||
|
||||
public class DocBlock implements ASTNode {
|
||||
|
||||
public final int lineNumber
|
||||
public List<Directive> directives = new ArrayList<Directive>()
|
||||
public List<TextBlock> textBlocks = new ArrayList<TextBlock>()
|
||||
|
||||
public DocBlock(int lineNumber) { this.lineNumber = lineNumber }
|
||||
|
||||
public int getLineNumber() { lineNumber }
|
||||
|
||||
public String toString() {
|
||||
"[DocBlock: Directives ${directives}, TextBlocks ${textBlocks}]" }
|
||||
}
|
@ -2,7 +2,7 @@ package com.jdblabs.jlp.ast
|
||||
|
||||
public class TextBlock implements ASTNode {
|
||||
|
||||
public static enum TextBlockType { MarkdownBlock, CodeBlock }
|
||||
public static enum TextBlockType { TextBlock, CodeBlock }
|
||||
|
||||
public final TextBlockType type
|
||||
public final String value
|
||||
@ -17,8 +17,8 @@ public class TextBlock implements ASTNode {
|
||||
|
||||
public String toString() { return "[${type}(${lineNumber}): ${value}]" }
|
||||
|
||||
public static TextBlock makeMarkdownBlock(String value, int lineNumber) {
|
||||
return new TextBlock(TextBlockType.MarkdownBlock, value, lineNumber) }
|
||||
public static TextBlock makeTextBlock(String value, int lineNumber) {
|
||||
return new TextBlock(TextBlockType.TextBlock, value, lineNumber) }
|
||||
|
||||
public static TextBlock makeCodeBlock(String value, int lineNumber) {
|
||||
return new TextBlock(TextBlockType.CodeBlock, value, lineNumber) }
|
||||
|
Reference in New Issue
Block a user