Refactoring: make Grammar an abstract class

This commit is contained in:
Alberto Venturini 2021-07-03 15:42:28 +02:00
parent c9c1454f90
commit 301eaaf98d
18 changed files with 395 additions and 163 deletions

View file

@ -1,89 +1,18 @@
package com.albertoventurini.parsley.grammar;
import com.albertoventurini.parsley.grammar.rules.AnyCharacter;
import com.albertoventurini.parsley.grammar.rules.MatchCharacter;
import com.albertoventurini.parsley.grammar.rules.MatchString;
import com.albertoventurini.parsley.grammar.rules.OneOf;
import com.albertoventurini.parsley.grammar.rules.OneOrMore;
import com.albertoventurini.parsley.grammar.rules.Rule;
import com.albertoventurini.parsley.grammar.rules.Sequence;
import com.albertoventurini.parsley.grammar.rules.TakeWhileCharacter;
import com.albertoventurini.parsley.grammar.rules.UntilString;
import com.albertoventurini.parsley.grammar.rules.Wrapper;
import com.albertoventurini.parsley.grammar.rules.ZeroOrMore;
import com.albertoventurini.parsley.grammar.rules.ZeroOrOne;
import java.util.Optional;
import java.util.function.Predicate;
public class Grammar {
public abstract class Grammar {
private final Rule startRule;
protected abstract Rule startRule();
private final Rule commentRule;
public Grammar(
final Rule startRule,
final Rule commentRule) {
this.startRule = startRule;
this.commentRule = commentRule;
// TODO: better than this
if (commentRule != null) {
commentRule.setComment(true);
}
}
protected abstract Rule commentRule();
public Optional<ParseTree> parse(final String text) {
final var ctx = new GrammarContext(text, commentRule);
return startRule.apply(ctx);
final var ctx = new GrammarContext(text, commentRule());
return startRule().apply(ctx);
}
public static MatchCharacter character(final char c) {
return new MatchCharacter(c);
}
public static AnyCharacter anyChar() {
return new AnyCharacter();
}
public static MatchString string(final String s) {
return new MatchString(s);
}
public static TakeWhileCharacter token() {
return new TakeWhileCharacter();
}
public static TakeWhileCharacter takeWhile(final Predicate<Character> characterPredicate) {
return new TakeWhileCharacter(characterPredicate);
}
public static UntilString until(final String s) {
return new UntilString(s);
}
public static Sequence sequence(final Rule... rules) {
return new Sequence(rules);
}
public static OneOf oneOf(final Rule... rules) {
return new OneOf(rules);
}
public static ZeroOrMore zeroOrMore(final Rule childRule) {
return new ZeroOrMore(childRule);
}
public static ZeroOrOne zeroOrOne(final Rule childRule) {
return new ZeroOrOne(childRule);
}
public static OneOrMore oneOrMore(final Rule childRule) {
return new OneOrMore(childRule);
}
public static Wrapper wrapper() {
return new Wrapper();
}
}

View file

@ -0,0 +1,27 @@
package com.albertoventurini.parsley.grammar;
import com.albertoventurini.parsley.grammar.rules.Rule;
public class GrammarFactory {
public static Grammar newGrammar(final Rule startRule, final Rule commentRule) {
// TODO: better than this
if (commentRule != null) {
commentRule.setComment(true);
}
return new Grammar() {
@Override
protected Rule startRule() {
return startRule;
}
@Override
protected Rule commentRule() {
return commentRule;
}
};
}
}

View file

@ -2,7 +2,7 @@ package com.albertoventurini.parsley.grammar;
import java.util.Arrays;
public class ParseContext {
class ParseContext {
private final char[] charArr;
private int cursor;

View file

@ -4,7 +4,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
public class ParseTree {
public abstract class ParseTree {
private final String text;

View file

@ -10,7 +10,6 @@ public final class MatchCharacter extends Rule {
public MatchCharacter(final char c) {
this.c = c;
discard = true;
}

View file

@ -42,7 +42,8 @@ public abstract class Rule {
public abstract Optional<ParseTree> tryApply(final GrammarContext ctx);
public void setComment(final boolean comment) {
public Rule setComment(final boolean comment) {
isComment = comment;
return this;
}
}

View file

@ -0,0 +1,54 @@
package com.albertoventurini.parsley.grammar.rules;
import java.util.function.Predicate;
public class Rules {
public static MatchCharacter character(final char c) {
return new MatchCharacter(c);
}
public static AnyCharacter anyChar() {
return new AnyCharacter();
}
public static MatchString string(final String s) {
return new MatchString(s);
}
public static TakeWhileCharacter token() {
return new TakeWhileCharacter();
}
public static TakeWhileCharacter takeWhile(final Predicate<Character> characterPredicate) {
return new TakeWhileCharacter(characterPredicate);
}
public static UntilString until(final String s) {
return new UntilString(s);
}
public static Sequence sequence(final Rule... rules) {
return new Sequence(rules);
}
public static OneOf oneOf(final Rule... rules) {
return new OneOf(rules);
}
public static ZeroOrMore zeroOrMore(final Rule childRule) {
return new ZeroOrMore(childRule);
}
public static ZeroOrOne zeroOrOne(final Rule childRule) {
return new ZeroOrOne(childRule);
}
public static OneOrMore oneOrMore(final Rule childRule) {
return new OneOrMore(childRule);
}
public static Wrapper wrapper() {
return new Wrapper();
}
}

View file

@ -20,7 +20,7 @@ public final class Sequence extends Rule {
final int start = ctx.getCursor();
final List<ParseTree> children = new ArrayList<>(rules.length);
for (final com.albertoventurini.parsley.grammar.rules.Rule rule : rules) {
for (final Rule rule : rules) {
if (!ctx.hasNext()) {
ctx.setCursor(start);
return Optional.empty();

View file

@ -5,13 +5,7 @@ import org.junit.jupiter.api.Test;
import java.util.function.Function;
import static com.albertoventurini.parsley.grammar.Grammar.character;
import static com.albertoventurini.parsley.grammar.Grammar.oneOf;
import static com.albertoventurini.parsley.grammar.Grammar.sequence;
import static com.albertoventurini.parsley.grammar.Grammar.string;
import static com.albertoventurini.parsley.grammar.Grammar.takeWhile;
import static com.albertoventurini.parsley.grammar.Grammar.token;
import static com.albertoventurini.parsley.grammar.Grammar.zeroOrMore;
import static com.albertoventurini.parsley.grammar.rules.Rules.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -24,7 +18,7 @@ public class GrammarTest {
takeWhile(Character::isLetterOrDigit),
oneOf(string("/>"), character('>')));
final Grammar grammar = new Grammar(tag, null);
final Grammar grammar = GrammarFactory.newGrammar(tag, null);
final var parseTree1 = grammar.parse("<tag1>");
@ -49,7 +43,7 @@ public class GrammarTest {
zeroOrMore(attribute),
oneOf(string("/>"), character('>')));
final Grammar grammar = new Grammar(tag, null);
final Grammar grammar = GrammarFactory.newGrammar(tag, null);
assertTrue(grammar.parse("<tag1>").isPresent());
@ -111,7 +105,7 @@ public class GrammarTest {
zeroOrMore(attribute),
oneOf(string("/>"), character('>')));
final Grammar grammar = new Grammar(tag, null);
final Grammar grammar = GrammarFactory.newGrammar(tag, null);
assertTrue(grammar.parse("<graphml xmlns='http://graphml.graphdrawing.org/xmlns'>").isPresent());
}
@ -140,7 +134,7 @@ public class GrammarTest {
tagFunc.apply("key"),
closingTagFunc.apply("key"));
final Grammar grammar = new Grammar(key, null);
final Grammar grammar = GrammarFactory.newGrammar(key, null);
assertTrue(grammar.parse("<key id='type' for='node' attr.name='type' attr.type='string'></key>").isPresent());
}