aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-02-23 20:48:50 +0000
committerMichael Williamson <mike@zwobble.org>2016-02-23 20:48:50 +0000
commitce3d0cb6b5349787d26f4a2d7201b3d04b8e5085 (patch)
treeef055c3449b4b8511dbc474b45241fd19b3927e1
parent14a07f679a1ad1726445f363fee484e3b2d52884 (diff)
Add parsing for paragraph matchers
-rw-r--r--src/main/java/org/zwobble/mammoth/styles/StyleMapParser.java7
-rw-r--r--src/main/java/org/zwobble/mammoth/styles/parsing/HtmlPathParser.java68
-rw-r--r--src/main/java/org/zwobble/mammoth/styles/parsing/Parsing.java4
-rw-r--r--src/main/java/org/zwobble/mammoth/styles/parsing/StyleMapParser.java17
-rw-r--r--src/main/java/org/zwobble/mammoth/styles/parsing/StyleMappingParser.java128
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/styles/DocumentMatcherParsingTests.java53
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/styles/HtmlPathParsingTests.java7
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/styles/StyleMapParserTests.java20
8 files changed, 224 insertions, 80 deletions
diff --git a/src/main/java/org/zwobble/mammoth/styles/StyleMapParser.java b/src/main/java/org/zwobble/mammoth/styles/StyleMapParser.java
deleted file mode 100644
index 1092353..0000000
--- a/src/main/java/org/zwobble/mammoth/styles/StyleMapParser.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.zwobble.mammoth.styles;
-
-import org.parboiled.BaseParser;
-
-public class StyleMapParser extends BaseParser<HtmlPath> {
-
-}
diff --git a/src/main/java/org/zwobble/mammoth/styles/parsing/HtmlPathParser.java b/src/main/java/org/zwobble/mammoth/styles/parsing/HtmlPathParser.java
deleted file mode 100644
index 18e1107..0000000
--- a/src/main/java/org/zwobble/mammoth/styles/parsing/HtmlPathParser.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.zwobble.mammoth.styles.parsing;
-
-import org.parboiled.BaseParser;
-import org.parboiled.Rule;
-import org.parboiled.support.Var;
-import org.zwobble.mammoth.styles.HtmlPath;
-import org.zwobble.mammoth.styles.HtmlPathElement;
-
-import static org.zwobble.mammoth.util.MammothMaps.map;
-
-public class HtmlPathParser extends BaseParser<HtmlPath> {
- public Rule HtmlPath() {
- ListVar<HtmlPathElement> elements = new ListVar<>();
- return Sequence(Optional(HtmlPathElements(elements)), EOI, push(new HtmlPath(elements.build())));
- }
-
- Rule HtmlPathElements(ListVar<HtmlPathElement> elements) {
- Var<HtmlPathElement> element = new Var<>();
- return Sequence(
- HtmlPathElement(element),
- elements.append(element),
- ZeroOrMore(Sequence(Whitespace(), Ch('>'), Whitespace(), HtmlPathElement(element), elements.append(element))));
- }
-
- Rule HtmlPathElement(Var<HtmlPathElement> element) {
- ListVar<String> tagNames = new ListVar<>();
- ListVar<String> classNames = new ListVar<>();
- Var<Boolean> fresh = new Var<>();
- return Sequence(
- TagNames(tagNames),
- ClassNames(classNames),
- Fresh(fresh),
- element.set(new HtmlPathElement(
- tagNames.build(),
- classNames.isEmpty() ? map() : map("class", String.join(" ", classNames.build())),
- !fresh.get())));
- }
-
- Rule TagNames(ListVar<String> tagNames) {
- return Sequence(
- Identifier(),
- tagNames.append(match()),
- ZeroOrMore(Sequence("|", Identifier(), tagNames.append(match()))));
- }
-
- Rule ClassNames(ListVar<String> classNames) {
- Var<String> className = new Var<>();
- return ZeroOrMore(Sequence(ClassName(className), classNames.append(className)));
- }
-
- Rule ClassName(Var<String> className) {
- return Sequence(".", Identifier(), className.set(match()));
- }
-
- Rule Fresh(Var<Boolean> fresh) {
- return Sequence(fresh.set(false), Optional(":fresh", fresh.set(true)));
- }
-
- Rule Identifier() {
- return Sequence(
- FirstOf(CharRange('a', 'z'), CharRange('A', 'Z')),
- ZeroOrMore(FirstOf(CharRange('a', 'z'), CharRange('A', 'Z'), CharRange('0', '9'), Ch('-'), Ch('_'))));
- }
-
- Rule Whitespace() {
- return ZeroOrMore(AnyOf(" \t"));
- }
-}
diff --git a/src/main/java/org/zwobble/mammoth/styles/parsing/Parsing.java b/src/main/java/org/zwobble/mammoth/styles/parsing/Parsing.java
index 761e7b8..8971f8a 100644
--- a/src/main/java/org/zwobble/mammoth/styles/parsing/Parsing.java
+++ b/src/main/java/org/zwobble/mammoth/styles/parsing/Parsing.java
@@ -9,15 +9,13 @@ import org.parboiled.support.ParsingResult;
import java.util.function.Function;
public class Parsing {
- public static <T, U extends BaseParser<T>> T parse(Class<U> parserType, Function<U, Rule> rule, String value) {
+ public static <T, U extends BaseParser<T>, V> void parse(Class<U> parserType, Function<U, Rule> rule, String value) {
U parser = Parboiled.createParser(parserType);
ReportingParseRunner<T> runner = new ReportingParseRunner<>(rule.apply(parser));
ParsingResult<T> result = runner.run(value);
if (result.hasErrors()) {
// TODO: wrap in result
throw new RuntimeException("Parse error");
- } else {
- return result.valueStack.peek();
}
}
}
diff --git a/src/main/java/org/zwobble/mammoth/styles/parsing/StyleMapParser.java b/src/main/java/org/zwobble/mammoth/styles/parsing/StyleMapParser.java
new file mode 100644
index 0000000..618c00b
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/styles/parsing/StyleMapParser.java
@@ -0,0 +1,17 @@
+package org.zwobble.mammoth.styles.parsing;
+
+import org.parboiled.support.Var;
+import org.zwobble.mammoth.styles.StyleMap;
+import org.zwobble.mammoth.styles.StyleMapBuilder;
+
+public class StyleMapParser {
+ public static StyleMap parse(String input) {
+ if (input.isEmpty()) {
+ return StyleMap.EMPTY;
+ } else {
+ Var<StyleMapBuilder> styleMap = new Var<>(StyleMap.builder());
+ Parsing.parse(StyleMappingParser.class, parser -> parser.StyleMapping(styleMap), input);
+ return styleMap.get().build();
+ }
+ }
+}
diff --git a/src/main/java/org/zwobble/mammoth/styles/parsing/StyleMappingParser.java b/src/main/java/org/zwobble/mammoth/styles/parsing/StyleMappingParser.java
new file mode 100644
index 0000000..3053666
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/styles/parsing/StyleMappingParser.java
@@ -0,0 +1,128 @@
+package org.zwobble.mammoth.styles.parsing;
+
+import org.parboiled.BaseParser;
+import org.parboiled.Rule;
+import org.parboiled.support.Var;
+import org.zwobble.mammoth.documents.NumberingLevel;
+import org.zwobble.mammoth.styles.HtmlPath;
+import org.zwobble.mammoth.styles.HtmlPathElement;
+import org.zwobble.mammoth.styles.ParagraphMatcher;
+import org.zwobble.mammoth.styles.StyleMapBuilder;
+
+import java.math.BigInteger;
+import java.util.Optional;
+
+import static org.zwobble.mammoth.util.MammothMaps.map;
+
+public class StyleMappingParser extends BaseParser<StyleMapBuilder> {
+ Rule StyleMapping(Var<StyleMapBuilder> styleMap) {
+ Var<ParagraphMatcher> paragraphMatcher = new Var<>();
+ Var<HtmlPath> path = new Var<>();
+ return Sequence(
+ ParagraphMatcher(paragraphMatcher), Whitespace(), "=>", Whitespace(), HtmlPath(path), EOI,
+ styleMap.set(styleMap.get().mapParagraph(ParagraphMatcher.ANY, HtmlPath.EMPTY)));
+ }
+
+ public Rule ParagraphMatcher(Var<ParagraphMatcher> matcher) {
+ Var<Optional<String>> styleId = new Var<>();
+ Var<Optional<String>> styleName = new Var<>();
+ Var<Optional<NumberingLevel>> numbering = new Var<>();
+ return Sequence(
+ "p", StyleId(styleId), StyleName(styleName), Numbering(numbering),
+ matcher.set(new ParagraphMatcher(styleId.get(), styleName.get(), numbering.get())));
+ }
+
+ Rule StyleId(Var<Optional<String>> styleId) {
+ return Sequence(styleId.set(Optional.empty()), Optional(".", Identifier(), styleId.set(Optional.of(match()))));
+ }
+
+ Rule StyleName(Var<Optional<String>> styleName) {
+ Var<String> value = new Var<>();
+ return Sequence(
+ styleName.set(Optional.empty()),
+ Optional("[style-name=", SingleQuotedString(value), "]", styleName.set(Optional.of(value.get()))));
+ }
+
+ Rule Numbering(Var<Optional<NumberingLevel>> numbering) {
+ Var<Boolean> isOrdered = new Var<>();
+ Var<BigInteger> level = new Var<>();
+ return Sequence(
+ numbering.set(Optional.empty()),
+ Optional(Sequence(
+ ":", NumberingType(isOrdered), "(", Number(level), ")",
+ numbering.set(Optional.of(new NumberingLevel(level.get().subtract(BigInteger.ONE).toString(), isOrdered.get()))))));
+ }
+
+ Rule NumberingType(Var<Boolean> isOrdered) {
+ return FirstOf(
+ Sequence("ordered-list", isOrdered.set(true)),
+ Sequence("unordered-list", isOrdered.set(false)));
+ }
+
+ Rule Number(Var<BigInteger> level) {
+ return Sequence(
+ OneOrMore(CharRange('0', '9')),
+ level.set(new BigInteger(match())));
+ }
+
+ public Rule HtmlPath(Var<HtmlPath> htmlPath) {
+ ListVar<HtmlPathElement> elements = new ListVar<>();
+ return Sequence(Optional(HtmlPathElements(elements)), htmlPath.set(new HtmlPath(elements.build())));
+ }
+
+ Rule HtmlPathElements(ListVar<HtmlPathElement> elements) {
+ Var<HtmlPathElement> element = new Var<>();
+ return Sequence(
+ HtmlPathElement(element),
+ elements.append(element),
+ ZeroOrMore(Sequence(Whitespace(), Ch('>'), Whitespace(), HtmlPathElement(element), elements.append(element))));
+ }
+
+ Rule HtmlPathElement(Var<HtmlPathElement> element) {
+ ListVar<String> tagNames = new ListVar<>();
+ ListVar<String> classNames = new ListVar<>();
+ Var<Boolean> fresh = new Var<>();
+ return Sequence(
+ TagNames(tagNames),
+ ClassNames(classNames),
+ Fresh(fresh),
+ element.set(new HtmlPathElement(
+ tagNames.build(),
+ classNames.isEmpty() ? map() : map("class", String.join(" ", classNames.build())),
+ !fresh.get())));
+ }
+
+ Rule TagNames(ListVar<String> tagNames) {
+ return Sequence(
+ Identifier(),
+ tagNames.append(match()),
+ ZeroOrMore(Sequence("|", Identifier(), tagNames.append(match()))));
+ }
+
+ Rule ClassNames(ListVar<String> classNames) {
+ Var<String> className = new Var<>();
+ return ZeroOrMore(Sequence(ClassName(className), classNames.append(className)));
+ }
+
+ Rule ClassName(Var<String> className) {
+ return Sequence(".", Identifier(), className.set(match()));
+ }
+
+ Rule Fresh(Var<Boolean> fresh) {
+ return Sequence(fresh.set(false), Optional(":fresh", fresh.set(true)));
+ }
+
+ Rule SingleQuotedString(Var<String> value) {
+ return Sequence("'", ZeroOrMore(NoneOf("\'")), value.set(match()), "'");
+ }
+
+ Rule Identifier() {
+ return Sequence(
+ FirstOf(CharRange('a', 'z'), CharRange('A', 'Z')),
+ ZeroOrMore(FirstOf(CharRange('a', 'z'), CharRange('A', 'Z'), CharRange('0', '9'), Ch('-'), Ch('_'))));
+ }
+
+ Rule Whitespace() {
+ return ZeroOrMore(AnyOf(" \t"));
+ }
+}
diff --git a/src/test/java/org/zwobble/mammoth/tests/styles/DocumentMatcherParsingTests.java b/src/test/java/org/zwobble/mammoth/tests/styles/DocumentMatcherParsingTests.java
new file mode 100644
index 0000000..dc87945
--- /dev/null
+++ b/src/test/java/org/zwobble/mammoth/tests/styles/DocumentMatcherParsingTests.java
@@ -0,0 +1,53 @@
+package org.zwobble.mammoth.tests.styles;
+
+import org.junit.Test;
+import org.parboiled.support.Var;
+import org.zwobble.mammoth.styles.ParagraphMatcher;
+import org.zwobble.mammoth.styles.parsing.Parsing;
+import org.zwobble.mammoth.styles.parsing.StyleMappingParser;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.zwobble.mammoth.tests.DeepReflectionMatcher.deepEquals;
+
+public class DocumentMatcherParsingTests {
+ @Test
+ public void canReadPlainParagraph() {
+ assertThat(
+ parseParagraphMatcher("p"),
+ deepEquals(ParagraphMatcher.ANY));
+ }
+
+ @Test
+ public void readsParagraphWithStyleId() {
+ assertThat(
+ parseParagraphMatcher("p.Heading1"),
+ deepEquals(ParagraphMatcher.styleId("Heading1")));
+ }
+
+ @Test
+ public void readsParagraphWithStyleName() {
+ assertThat(
+ parseParagraphMatcher("p[style-name='Heading 1']"),
+ deepEquals(ParagraphMatcher.styleName("Heading 1")));
+ }
+
+ @Test
+ public void readsParagraphOrderedList() {
+ assertThat(
+ parseParagraphMatcher("p:ordered-list(2)"),
+ deepEquals(ParagraphMatcher.orderedList("1")));
+ }
+
+ @Test
+ public void readsParagraphUnorderedList() {
+ assertThat(
+ parseParagraphMatcher("p:unordered-list(2)"),
+ deepEquals(ParagraphMatcher.unorderedList("1")));
+ }
+
+ private ParagraphMatcher parseParagraphMatcher(String input) {
+ Var<ParagraphMatcher> matcher = new Var<>();
+ Parsing.parse(StyleMappingParser.class, parser -> parser.ParagraphMatcher(matcher), input);
+ return matcher.get();
+ }
+}
diff --git a/src/test/java/org/zwobble/mammoth/tests/styles/HtmlPathParsingTests.java b/src/test/java/org/zwobble/mammoth/tests/styles/HtmlPathParsingTests.java
index c6d0cb1..04317b6 100644
--- a/src/test/java/org/zwobble/mammoth/tests/styles/HtmlPathParsingTests.java
+++ b/src/test/java/org/zwobble/mammoth/tests/styles/HtmlPathParsingTests.java
@@ -1,10 +1,11 @@
package org.zwobble.mammoth.tests.styles;
import org.junit.Test;
+import org.parboiled.support.Var;
import org.zwobble.mammoth.styles.HtmlPath;
import org.zwobble.mammoth.styles.HtmlPathElement;
-import org.zwobble.mammoth.styles.parsing.HtmlPathParser;
import org.zwobble.mammoth.styles.parsing.Parsing;
+import org.zwobble.mammoth.styles.parsing.StyleMappingParser;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.zwobble.mammoth.tests.DeepReflectionMatcher.deepEquals;
@@ -66,6 +67,8 @@ public class HtmlPathParsingTests {
}
private HtmlPath parseHtmlPath(String input) {
- return Parsing.parse(HtmlPathParser.class, HtmlPathParser::HtmlPath, input);
+ Var<HtmlPath> path = new Var<>();
+ Parsing.parse(StyleMappingParser.class, parser -> parser.HtmlPath(path), input);
+ return path.get();
}
}
diff --git a/src/test/java/org/zwobble/mammoth/tests/styles/StyleMapParserTests.java b/src/test/java/org/zwobble/mammoth/tests/styles/StyleMapParserTests.java
index 09f0806..ae2ef2b 100644
--- a/src/test/java/org/zwobble/mammoth/tests/styles/StyleMapParserTests.java
+++ b/src/test/java/org/zwobble/mammoth/tests/styles/StyleMapParserTests.java
@@ -1,4 +1,24 @@
package org.zwobble.mammoth.tests.styles;
+import org.junit.Test;
+import org.zwobble.mammoth.styles.HtmlPath;
+import org.zwobble.mammoth.styles.ParagraphMatcher;
+import org.zwobble.mammoth.styles.StyleMap;
+import org.zwobble.mammoth.styles.parsing.StyleMapParser;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.zwobble.mammoth.tests.DeepReflectionMatcher.deepEquals;
+
public class StyleMapParserTests {
+ @Test
+ public void emptyStringIsParsedAsEmptyStyleMap() {
+ StyleMap styleMap = StyleMapParser.parse("");
+ assertThat(styleMap, deepEquals(StyleMap.builder().build()));
+ }
+
+ @Test
+ public void canMapParagraphs() {
+ StyleMap styleMap = StyleMapParser.parse("p => p");
+ assertThat(styleMap, deepEquals(StyleMap.builder().mapParagraph(ParagraphMatcher.ANY, HtmlPath.EMPTY).build()));
+ }
}