diff --git a/README.md b/README.md
index 4048583..a6c90f0 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,23 @@
# Java
Java version of SimplePEG
+
+Using example:
+
+ String grammar = "GRAMMAR url\n" +
+ "\n" +
+ "url -> scheme \"://\" host pathname search hash?;\n" +
+ "scheme -> \"http\" \"s\"?;\n" +
+ "host -> hostname port?;\n" +
+ "hostname -> segment (\".\" segment)*;\n" +
+ "segment -> [a-z0-9-]+;\n" +
+ "port -> \":\" [0-9]+;\n" +
+ "pathname -> \"/\" [^ ?]*;\n" +
+ "search -> (\"?\" [^ #]*)?;\n" +
+ "hash -> \"#\" [^ ]*;";
+
+ RuleProcessor rp = new RuleProcessor(SpegParser.createAndExec(grammar));
+
+ System.out.println(rp.check("https://simplepeg.github.io/"));
+ System.out.println(rp.check("https://google.com/"));
+ System.out.println(rp.check("https://abcdssss.....com/"));
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..804eda0
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,32 @@
+
+
+ * Created by dude on 29.10.2017.
+ */
+public class RdExecutor {
+
+
+ public RdExecutor() {
+
+ }
+
+ public Executable parseString(final String str) {
+
+ return new Executable() {
+ @Override
+ public PegNode exec(State state) {
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.STRING);
+ res.setExecName(str);
+
+ int endPos = state.getPosition() + str.length();
+ if (endPos <= state.getTextData().length() &&
+ state.getTextData().substring(state.getPosition(), endPos).equals(str)) {
+
+ res.addMatch(str);
+ res.setStartPosition(state.getPosition());
+ res.setEndPosition(state.appendPosition(str.length()));
+ res.setResultType(ResultType.OK);
+ } else {
+ res.setResultType(ResultType.ERROR);
+ res.setError(" parseString " + str + " lastPos = " + state.getPosition() + " unexpected " + state.atPos());
+ }
+ return res;
+ }
+ };
+ }
+
+ public Executable parseRegexp(final String regexp) {
+ return new Executable() {
+ @Override
+ public PegNode exec(State state) {
+
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.REGEXP);
+
+ Pattern pattern = Pattern.compile(regexp);
+ Matcher matcher = pattern.matcher(state.getTextData());
+ if (matcher.find(state.getPosition()) && state.getPosition() == matcher.start()) {
+ //нашли и у места , где каретка
+ String founded = matcher.group();
+
+ res.addMatch(founded);
+ res.setStartPosition(matcher.start());
+ res.setEndPosition(state.appendPosition(founded.length()));
+ res.setResultType(ResultType.OK);
+ } else {
+ res.setResultType(ResultType.ERROR);
+ res.setError(" parseRegexp " + regexp + " lastPos = " + state.getPosition() + " unexpected " + state.atPos());
+ }
+ return res;
+ }
+ };
+ }
+
+ /**
+ * Последовательно выполняет все exec.
+ * Возвращает ERROR, если вернулся хотя бы один ERROR
+ * EMPTY - если все exec вернули EMPTY
+ * OK - если все exec вернули OK(минимум один) или EMPTY
+ *
+ * @param execName
+ * @param execs
+ * @return
+ */
+ public Executable sequence(final String execName, final Executable... execs) {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.SEQUENCE);
+ res.setExecName(execName);
+
+ for (Executable exec : execs) {
+ State stateCp = state.copy();
+ PegNode pegNode = exec.exec(stateCp);
+
+ switch (pegNode.getResultType()) {
+ case OK:
+ res.appendChild(pegNode);
+ res.setResultType(ResultType.OK);
+ state.setPosition(stateCp.getPosition());
+ break;
+ case EMPTY:
+
+ break;
+ case ERROR:
+ res.setResultType(ResultType.ERROR);
+ res.setError(" sequence " + execName + " lastPos = " + stateCp.getPosition() + " unexpected " + stateCp.atPos());
+ state.setPosition(stateCp.getPosition());
+ return res;
+ }
+ }
+
+ if (res.getChildrens().size() == 0) {
+ res.setResultType(ResultType.EMPTY);
+ }
+ return res;
+ }
+ };
+
+ }
+
+ /**
+ * Последовательное выполнение. Первая, полнившаяся OK возвращается как результат.
+ * Если вернулись все пустые: возвращает EMPTY
+ * Если в результатах exec были ERROR или EMPTY - возвращает ERROR
+ *
+ * @param execs
+ * @return
+ */
+ public Executable orderedChoice(final String execName, final Executable... execs) {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.ORDERED_CHOICE);
+ res.setExecName(execName);
+
+ boolean hasEmpty = false;
+ boolean hasError = false;
+
+ for (Executable exec : execs) {
+ State statecp = state.copy();
+ PegNode pegNode = exec.exec(statecp);
+
+ switch (pegNode.getResultType()) {
+ case OK:
+ res.appendChild(pegNode);
+ res.setResultType(ResultType.OK);
+ res.setError("");
+ state.setPosition(statecp.getPosition());
+ return res;
+ case EMPTY:
+ res.setResultType(ResultType.EMPTY);
+ hasEmpty = true;
+ //return res;
+ break;
+ case ERROR:
+ res.setResultType(ResultType.ERROR);
+ res.setError(" orderedChoice " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos());
+ hasError = true;
+ break;
+
+ }
+ }
+
+ if (hasError) {
+ res.setResultType(ResultType.ERROR);
+ } else {
+ if (hasEmpty) {
+ res.setResultType(ResultType.EMPTY);
+ }
+ }
+ return res;
+ }
+ };
+
+ }
+
+ /**
+ * Выплняет exec, добавляя OK руезльутаты в child
+ * Возвращает OK если добавленых child > 0 иначе ERROR
+ *
+ * @param execName
+ * @param exec
+ * @return
+ */
+ public Executable oneOrMore(final String execName, final Executable exec) {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.ONE_OR_MORE);
+ res.setExecName(execName);
+
+ PegNode pegNode;
+ while ((pegNode = exec.exec(state)).getResultType().equals(ResultType.OK)) {
+ res.appendChild(pegNode);
+ }
+
+ if (res.getChildrens().size() > 0) {
+ res.setResultType(ResultType.OK);
+ } else {
+ res.setResultType(ResultType.ERROR);
+ res.setError(" oneOrMore " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos());
+ }
+ return res;
+ }
+ };
+ }
+
+ /**
+ * Выплняет exec, добавляя OK руезльутаты в child
+ * Возвращает OK если добавленых child > 0, EMPTY если child = 0
+ *
+ * @param execName
+ * @param exec
+ * @return
+ */
+ public Executable zeroOrMore(final String execName, final Executable exec) {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.ZERO_OR_MORE);
+ res.setExecName(execName);
+
+ PegNode pegNode;
+ while ((pegNode = exec.exec(state)).getResultType().equals(ResultType.OK)) {
+ res.appendChild(pegNode);
+ }
+
+ if (res.getChildrens().size() == 0) {
+ res.setResultType(ResultType.EMPTY);
+ } else {
+ res.setResultType(ResultType.OK);
+ }
+ return res;
+ }
+ };
+
+ }
+
+ /**
+ * Возвращает OK если результат exec, иначе EMPTY
+ *
+ * @param exec
+ * @return
+ */
+ public Executable optional(final Executable exec) {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.OPTIONAL);
+
+ State statecp = state.copy();
+ PegNode pegNode = exec.exec(statecp);
+ if (pegNode.getResultType().equals(ResultType.OK)) {
+ res.setResultType(ResultType.OK);
+ res.appendChild(pegNode);
+ state.setPosition(statecp.getPosition());
+ } else {
+ res.setResultType(ResultType.EMPTY);
+ }
+
+ return res;
+ }
+ };
+
+ }
+
+ /**
+ * Предикат not.
+ * По хорошему, внутри он должен двигать position... оставлю пока так
+ *
+ * @param exec
+ * @return
+ */
+ public Executable not(final Executable exec) {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.NOT);
+
+ State statecp = state.copy();
+ PegNode pegNode = exec.exec(statecp);
+
+ switch (pegNode.getResultType()) {
+ case OK:
+
+ res.setResultType(ResultType.ERROR);
+ res.setError(" not " + " lastPos = " + statecp.getPosition() + " unexpected " + statecp.atPos());
+
+ break;
+ case ERROR:
+ default:
+ res.setResultType(ResultType.OK);
+ res.appendChild(pegNode);
+ state.setPosition(statecp.getPosition());
+ break;
+ }
+ return res;
+ }
+ };
+
+ }
+
+ /**
+ * OK если достигнут конец строки данных
+ *
+ * @return
+ */
+ public Executable parseEndOfFile() {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+
+ PegNode res = new PegNode();
+ res.setType(SpegTypes.END_OF_FILE);
+ if (state.getPosition() >= state.getTextData().length()) {
+
+ res.setResultType(ResultType.OK);
+ res.setStartPosition(state.getPosition());
+ res.setEndPosition(state.getPosition());
+ } else {
+ res.setResultType(ResultType.ERROR);
+ res.setError(" parseEndOfFile " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos());
+ }
+ return res;
+ }
+ };
+ }
+
+ /**
+ * @param spParser
+ * @return
+ */
+ public Executable rec(final SpegParser spParser) {
+ return new Executable() {
+
+ @Override
+ public PegNode exec(State state) {
+ Executable recExec = spParser.ruleExpression();
+ return recExec.exec(state);
+ }
+ };
+ }
+
+
+}
diff --git a/src/main/java/ru/dude/simplepeg/RuleProcessor.java b/src/main/java/ru/dude/simplepeg/RuleProcessor.java
new file mode 100644
index 0000000..bc0aa6d
--- /dev/null
+++ b/src/main/java/ru/dude/simplepeg/RuleProcessor.java
@@ -0,0 +1,146 @@
+package ru.dude.simplepeg;
+
+import ru.dude.simplepeg.entity.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * For text checking
+ */
+public class RuleProcessor {
+
+ /**
+ * Разобранные правила
+ */
+ Map
+ * Created by dude on 29.10.2017.
+ */
+public class SpegParser {
+
+ private Map
+ *
+ * @return
+ */
+ private Executable parsingRule() {
+ return rdExecutor.sequence("rule",
+
+ ruleName(),
+ rdExecutor.zeroOrMore("spaces", spacesBreaks()),
+ rdExecutor.parseString("->"),
+ rdExecutor.zeroOrMore("spaces", spacesBreaks()),
+ ruleExpression(),
+ rdExecutor.zeroOrMore("spaces", spacesBreaks()),
+ rdExecutor.parseString(";"),
+ rdExecutor.zeroOrMore("spaces", spacesBreaks())
+
+ );
+ }
+
+ /**
+ * Parse rule name
+ *
+ * js parsing_rule_name
+ *
+ * @return
+ */
+ private Executable ruleName() {
+ return rdExecutor.sequence("rule_name",
+ rdExecutor.parseRegexp("[a-zA-Z_]"),
+ rdExecutor.zeroOrMore("", rdExecutor.parseRegexp("[a-zA-Z0-9_]"))
+ );
+ }
+
+ /**
+ * Parse rule Expression
+ *
+ * js parsing_expression
+ *
+ * @return
+ */
+ public Executable ruleExpression() {
+ return rdExecutor.orderedChoice("rule_expression",
+ parsingSequence(),
+ parsingOrderedChoice(),
+ parsingSubExpression()
+ );
+ }
+
+
+ private Executable parsingSequence() {
+
+ return rdExecutor.sequence("sequence",
+ rdExecutor.orderedChoice(
+ "", parsingOrderedChoice(),
+ parsingSubExpression()
+ ),
+ rdExecutor.oneOrMore("sequence_args",
+ rdExecutor.sequence("sequence_arg",
+ rdExecutor.oneOrMore("spaces", spacesBreaks()),
+ rdExecutor.orderedChoice(
+ "", parsingOrderedChoice(),
+ parsingSubExpression()
+ )
+ )
+ )
+ );
+ }
+
+ private Executable parsingOrderedChoice() {
+ return rdExecutor.sequence("ordered_choice",
+ parsingSubExpression(),
+ rdExecutor.oneOrMore("ordered_choice_args",
+ rdExecutor.sequence("ordered_choice_arg",
+ rdExecutor.zeroOrMore("spaces", spacesBreaks()),
+ rdExecutor.parseString("/"),
+ rdExecutor.zeroOrMore("spaces", spacesBreaks()),
+ parsingSubExpression()
+ )
+ )
+ );
+ }
+
+ private Executable parsingSubExpression() {
+ return rdExecutor.sequence("sub_expression",
+
+ rdExecutor.zeroOrMore("", rdExecutor.sequence("tags",
+ tag(),
+ rdExecutor.parseString(":")
+
+ )),
+ rdExecutor.orderedChoice(
+ "", parsingNot(),
+ parsingAnd(),
+ parsingOptional(),
+ parsingOneOrMore(),
+ parsingZeroOrMore(),
+ parsingGroup(),
+ parsingAtomicExpression()
+ )
+
+ );
+
+ }
+
+
+ private Executable tag() {
+ return rdExecutor.sequence("tag_name",
+ rdExecutor.parseRegexp("[a-zA-Z_]"),
+ rdExecutor.zeroOrMore("", rdExecutor.parseRegexp("[a-zA-Z0-9_]"))
+ );
+ }
+
+
+ private Executable parsingGroup() {
+ return rdExecutor.sequence("group",
+ rdExecutor.parseString("("),
+ rdExecutor.zeroOrMore("spaces", spacesBreaks()),
+ rdExecutor.rec(this),
+ rdExecutor.zeroOrMore("spaces", spacesBreaks()),
+ rdExecutor.parseString(")")
+ );
+ }
+
+ private Executable parsingAtomicExpression() {
+ return rdExecutor.orderedChoice(
+ "", parseString(),
+ parseRegex(),
+ rdExecutor.parseEndOfFile(),
+ parsingRuleCall()
+ );
+ }
+
+
+ /**
+ * js parsing_rule_call()
+ *
+ * @return
+ */
+ private Executable parsingRuleCall() {
+ return ruleName();
+ }
+
+ private Executable parseString() {
+ return rdExecutor.sequence(SpegNames.NAME_STRING.getSpegName(),
+ rdExecutor.parseString("\""),
+ rdExecutor.oneOrMore(SpegNames.NAME_STRING.getSpegName(),
+ rdExecutor.orderedChoice(
+ "", rdExecutor.parseString("\\\\"),
+ rdExecutor.parseString("\\\""),
+ rdExecutor.parseRegexp("[^\"]")
+ )),
+ rdExecutor.parseString("\"")
+ );
+ }
+
+ private Executable parseRegex() {
+ return rdExecutor.orderedChoice(
+ "", rdExecutor.sequence(SpegNames.NAME_REGEX.getSpegName(),
+ rdExecutor.parseString("["),
+ rdExecutor.optional(rdExecutor.parseString("^")),
+ rdExecutor.oneOrMore("regex[]", rdExecutor.orderedChoice(
+ "", rdExecutor.parseString("\\]"),
+ rdExecutor.parseString("\\["),
+ rdExecutor.parseRegexp("[^\\]]")
+ )),
+ rdExecutor.parseString("]")
+ ),
+ rdExecutor.parseString(".")
+ );
+ }
+
+
+ private Executable parsingNot() {
+ return rdExecutor.sequence(SpegNames.NAME_NOT.getSpegName(),
+ rdExecutor.parseString("!"),
+ rdExecutor.orderedChoice(
+ "", parsingGroup(),
+ parsingAtomicExpression()
+ )
+ );
+ }
+
+ private Executable parsingAnd() {
+ return rdExecutor.sequence(SpegNames.NAME_AND.getSpegName(),
+ rdExecutor.parseString("&"),
+ rdExecutor.orderedChoice(
+ "", parsingGroup(),
+ parsingAtomicExpression()
+ )
+ );
+ }
+
+ private Executable parsingOneOrMore() {
+ return rdExecutor.sequence(SpegNames.NAME_ONE_OR_MORE.getSpegName(),
+ rdExecutor.orderedChoice(
+ "", parsingGroup(),
+ parsingAtomicExpression()
+ ),
+ rdExecutor.parseString("+")
+ );
+ }
+
+
+ private Executable parsingZeroOrMore() {
+ return rdExecutor.sequence(SpegNames.NAME_ZERO_OR_MORE.getSpegName(),
+ rdExecutor.orderedChoice(
+ "", parsingGroup(),
+ parsingAtomicExpression()
+ ),
+ rdExecutor.parseString("*")
+ );
+ }
+
+ private Executable parsingOptional() {
+ return rdExecutor.sequence(SpegNames.NAME_OPTIONAL.getSpegName(),
+ rdExecutor.orderedChoice(
+ "", parsingGroup(),
+ parsingAtomicExpression()
+ ),
+ rdExecutor.parseString("?")
+ );
+ }
+
+
+}
diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java
new file mode 100644
index 0000000..a29977c
--- /dev/null
+++ b/src/main/java/ru/dude/simplepeg/Starter.java
@@ -0,0 +1,47 @@
+package ru.dude.simplepeg;
+
+import ru.dude.simplepeg.entity.PegNode;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * Created by dude on 29.10.2017.
+ */
+public class Starter {
+
+ public static void main(String[] args) throws Exception {
+
+ String grammar = "GRAMMAR url\n" +
+ "\n" +
+ "url -> scheme \"://\" host pathname search hash?;\n" +
+ "scheme -> \"http\" \"s\"?;\n" +
+ "host -> hostname port?;\n" +
+ "hostname -> segment (\".\" segment)*;\n" +
+ "segment -> [a-z0-9-]+;\n" +
+ "port -> \":\" [0-9]+;\n" +
+ "pathname -> \"/\" [^ ?]*;\n" +
+ "search -> (\"?\" [^ #]*)?;\n" +
+ "hash -> \"#\" [^ ]*;";
+
+ RuleProcessor rp = new RuleProcessor(SpegParser.createAndExec(grammar));
+
+ System.out.println(rp.check("https://simplepeg.github.io/"));
+ System.out.println(rp.check("https://google.com/"));
+ System.out.println(rp.check("https://abcdssss.....com/"));
+
+ }
+
+ public static void printTree(PegNode node) throws IOException {
+ System.out.println(node.getResultType());
+ System.out.println(node.getError());
+
+ StringBuilder sb = new StringBuilder();
+ node.toJson(sb, 0);
+ BufferedWriter bw = new BufferedWriter(new FileWriter("tree.json"));
+
+ bw.write(sb.toString());
+ bw.close();
+ }
+}
diff --git a/src/main/java/ru/dude/simplepeg/entity/CheckResult.java b/src/main/java/ru/dude/simplepeg/entity/CheckResult.java
new file mode 100644
index 0000000..6f67b5a
--- /dev/null
+++ b/src/main/java/ru/dude/simplepeg/entity/CheckResult.java
@@ -0,0 +1,45 @@
+package ru.dude.simplepeg.entity;
+
+/**
+ * Результат проверки
+ */
+public class CheckResult {
+
+ private ResultType resultType;
+ private String errorText;
+
+ private CheckResult() {
+
+ }
+
+ public static CheckResult error(String errorText) {
+ CheckResult r = new CheckResult();
+ r.resultType = ResultType.ERROR;
+ r.errorText = errorText;
+ return r;
+ }
+
+ public static CheckResult ok() {
+ CheckResult r = new CheckResult();
+ r.resultType = ResultType.OK;
+ r.errorText = "";
+ return r;
+ }
+
+ public ResultType getResultType() {
+ return resultType;
+ }
+
+ public String getErrorText() {
+ return errorText;
+ }
+
+ @Override
+ public String toString() {
+ if (ResultType.OK.equals(resultType)) {
+ return ResultType.OK.toString();
+ } else {
+ return resultType + "[" + errorText + ']';
+ }
+ }
+}
diff --git a/src/main/java/ru/dude/simplepeg/entity/PegNode.java b/src/main/java/ru/dude/simplepeg/entity/PegNode.java
new file mode 100644
index 0000000..95df1c6
--- /dev/null
+++ b/src/main/java/ru/dude/simplepeg/entity/PegNode.java
@@ -0,0 +1,157 @@
+package ru.dude.simplepeg.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree object with result data
+ *
+ * Created by dude on 29.10.2017.
+ */
+public class PegNode {
+
+ private static Integer nextId = 0;
+
+ Integer id;
+ SpegTypes type;
+ StringBuilder match = new StringBuilder();
+ Integer startPosition;
+ Integer endPosition;
+
+ List
+ * Сложные тесты для RdExecutor
+ */
+public class RdComplexTest extends Assert {
+
+ private void assertProcess(String grammar, String input, Executable executable, ResultType resultType) {
+ PegNode result = executable.exec(new State(grammar));
+ String message = "GRAMMAR:\n" + grammar + "\nINPUT:\n" + input + "\nERROR:" + result.getError();
+ assertEquals(message, resultType, result.getResultType());
+ }
+
+
+ @Test
+ public void sequencesAndOneZeroMore() {
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.sequence("test_sequence",
+ rd.oneOrMore("", rd.parseString("a")),
+ rd.oneOrMore("", rd.parseString("b")),
+ rd.zeroOrMore("", rd.parseString("cc")),
+ rd.zeroOrMore("", rd.parseString("X")),
+ rd.zeroOrMore("", rd.parseString("d")),
+ rd.oneOrMore("", rd.parseString("e"))
+ );
+ assertProcess("aabbccddee", "abcdXde", executable, ResultType.OK);
+ assertProcess("aabbccccddee", "abcdXde", executable, ResultType.OK);
+ assertProcess("aabbcccddee", "abcdXde", executable, ResultType.ERROR);
+ }
+
+ @Test
+ public void sequencesAndOptional() {
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.sequence("test_sequence",
+ rd.parseString("aaaa"),
+ rd.optional(rd.parseString("bbbb")),
+ rd.optional(rd.parseString("bbbX")),
+ rd.parseString("cccc")
+ );
+ assertProcess("aaaabbbbcccc", "aaaabbbbXcccc", executable, ResultType.OK);
+ assertProcess("aaaacccc", "aaaabbbbXcccc", executable, ResultType.OK);
+ assertProcess("aaaabbbXcccc", "aaaabbbbXcccc", executable, ResultType.OK);
+ }
+
+ @Test
+ public void oneOrManyAndOptional() {
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.oneOrMore("test_oneOrMany",
+ rd.orderedChoice(
+ "", rd.optional(rd.parseString("bxy")),
+ rd.optional(rd.parseString("bxz"))
+ )
+ );
+ assertProcess("bxz", "bxy/bxz", executable, ResultType.OK);
+
+ }
+
+ @Test
+ public void sequenceAndOneOrManyAndOptional() {
+ RdExecutor rd = new RdExecutor();
+ Executable executable =
+ rd.sequence("",
+ rd.oneOrMore("test_oneOrMany",
+ rd.optional(
+ rd.sequence("",
+ rd.parseString("a"),
+ rd.parseString("b"),
+ rd.parseString("c")
+ )
+ )
+ ),
+ rd.parseString("abx")
+ );
+ assertProcess("abcabcabx", "abcabcabx", executable, ResultType.OK);
+
+ }
+
+
+}
diff --git a/src/test/java/RdExecutorTest.java b/src/test/java/RdExecutorTest.java
new file mode 100644
index 0000000..be0edb0
--- /dev/null
+++ b/src/test/java/RdExecutorTest.java
@@ -0,0 +1,197 @@
+import org.junit.Assert;
+import org.junit.Test;
+import ru.dude.simplepeg.Executable;
+import ru.dude.simplepeg.RdExecutor;
+import ru.dude.simplepeg.entity.PegNode;
+import ru.dude.simplepeg.entity.ResultType;
+import ru.dude.simplepeg.entity.State;
+
+
+/**
+ * Created by dude on 27.05.2018.
+ *
+ * Тесты конструкций PEG
+ */
+public class RdExecutorTest extends Assert {
+
+
+ private void assertProcess(String grammar,String input,Executable executable,ResultType resultType){
+ PegNode result = executable.exec(new State(grammar));
+ String message = "GRAMMAR:\n" + grammar + "\nINPUT:\n"+input+"\nERROR:"+result.getError();
+ assertEquals(message, resultType,result.getResultType());
+ }
+
+ @Test
+ public void simpleString(){
+ String grammar = "aaaazz;";
+ String input = "aaaazz";
+ Executable executable = new RdExecutor().parseString(input);
+ assertProcess(grammar,input,executable,ResultType.OK);
+ }
+
+
+ @Test
+ public void simpleRegexp(){
+ String grammar = "aaaazz;";
+ String input = "[a-z]+";
+ Executable executable = new RdExecutor().parseRegexp(input);
+ assertProcess(grammar,input,executable,ResultType.OK);
+ }
+
+ @Test
+ public void eofTest(){
+ String grammar = "";
+ String input = "[___ANY___]";
+ Executable executable = new RdExecutor().parseEndOfFile();
+ assertProcess(grammar,input,executable,ResultType.OK);
+ }
+
+ @Test
+ public void simpleSequenceOk(){
+ String grammar = "aaaazzxxXx";
+ String s1 = "aaaa";
+ String s2 = "zz";
+ String r3 = "[xX]+";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.sequence("test_sequence",
+ rd.parseString(s1),
+ rd.parseString(s2),
+ rd.parseRegexp(r3)
+ );
+ assertProcess(grammar,s1+","+s2+","+r3,executable,ResultType.OK);
+ }
+
+ @Test
+ public void simpleSequenceEmpty(){
+ String grammar = "_____XXXX___";
+ String s1 = "aaaa";
+ String s2 = "zz";
+ String r3 = "[0-9]+";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.sequence("test_sequence",
+ rd.optional(rd.parseString(s1)),
+ rd.optional(rd.parseString(s2)),
+ rd.optional(rd.parseRegexp(r3))
+ );
+ assertProcess(grammar,s1+","+s2+","+r3,executable,ResultType.EMPTY);
+ }
+
+ @Test
+ public void simpleSequenceError(){
+ String grammar = "aaaazzxxXx";
+ String s1 = "aaaa";
+ String s2 = "zz";
+ String r3 = "[0-9]+";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.sequence("test_sequence",
+ rd.parseString(s1),
+ rd.parseString(s2),
+ rd.parseRegexp(r3)
+ );
+ assertProcess(grammar,s1+","+s2+","+r3,executable,ResultType.ERROR);
+ }
+
+ @Test
+ public void simpleOrderedChoiceOk(){
+ String s1 = "aaaa";
+ String s2 = "zz";
+ String r3 = "[xX]+";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.orderedChoice(
+ "", rd.parseString(s1),
+ rd.parseString(s2),
+ rd.parseRegexp(r3)
+ );
+ assertProcess("aaaazzxxXx_",s1+","+s2+","+r3,executable,ResultType.OK);
+ assertProcess("zz____xxXx_",s1+","+s2+","+r3,executable,ResultType.OK);
+ assertProcess("xxXx_______",s1+","+s2+","+r3,executable,ResultType.OK);
+ }
+
+ @Test
+ public void simpleOrderedChoiceEmpty(){
+ String s1 = "aaaa";
+ String s2 = "zz";
+ String r3 = "[0-9]+";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.orderedChoice(
+ "", rd.optional(rd.parseString(s1)),
+ rd.optional(rd.parseString(s2)),
+ rd.optional(rd.parseRegexp(r3))
+ );
+ assertProcess("xxXx_______",s1+","+s2+","+r3,executable,ResultType.EMPTY);
+ }
+
+ @Test
+ public void simpleOrderedChoiceError(){
+ String s1 = "aaaa";
+ String s2 = "zz";
+ String r3 = "[0-9]+";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.orderedChoice(
+ "", rd.parseString(s1),
+ rd.parseString(s2),
+ rd.parseRegexp(r3)
+ );
+ assertProcess("xxXx_______",s1+","+s2+","+r3,executable,ResultType.ERROR);
+ }
+
+ @Test
+ public void simpleOneOrMoreOk(){
+ String s1 = "a";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.oneOrMore("simpleOneOrMoreOK_test",
+ rd.parseString(s1)
+ );
+ assertProcess("aaaazzxxXx_",s1,executable,ResultType.OK);
+ }
+
+ @Test
+ public void simpleOneOrMoreError(){
+ String s1 = "a";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.oneOrMore("simpleOneOrMoreError_test",
+ rd.parseString(s1)
+ );
+ assertProcess("bbaaaazzxxXx_",s1,executable,ResultType.ERROR);
+ }
+
+ @Test
+ public void simplZeroOrMoreOk(){
+ String s1 = "a";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.zeroOrMore(
+ "", rd.parseString(s1)
+ );
+ assertProcess("aaaazzxxXx_",s1,executable,ResultType.OK);
+ }
+
+ @Test
+ public void simpleZeroOrMoreEmpty(){
+ String s1 = "a";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.zeroOrMore(
+ "", rd.parseString(s1)
+ );
+ assertProcess("bbaaaazzxxXx_",s1,executable,ResultType.EMPTY);
+ }
+
+ @Test
+ public void simpleOptionalOk(){
+ String s1 = "a";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.optional(
+ rd.parseString(s1)
+ );
+ assertProcess("aaaazzxxXx_",s1,executable,ResultType.OK);
+ }
+
+ @Test
+ public void simpleOptionalEmpty(){
+ String s1 = "a";
+ RdExecutor rd = new RdExecutor();
+ Executable executable = rd.optional(
+ rd.parseString(s1)
+ );
+ assertProcess("bbaaaazzxxXx_",s1,executable,ResultType.EMPTY);
+ }
+}
diff --git a/src/test/java/RuleTest.java b/src/test/java/RuleTest.java
new file mode 100644
index 0000000..a2e4f2f
--- /dev/null
+++ b/src/test/java/RuleTest.java
@@ -0,0 +1,385 @@
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import ru.dude.simplepeg.RuleProcessor;
+import ru.dude.simplepeg.SpegParser;
+import ru.dude.simplepeg.entity.CheckResult;
+import ru.dude.simplepeg.entity.PegNode;
+import ru.dude.simplepeg.entity.ResultType;
+
+/**
+ * Created by dude on 27.05.2018.
+ *
+ * Тесты выполнения rule
+ */
+public class RuleTest extends Assert {
+
+ @Test
+ public void ruleString(){
+ String grammar = "GRAMMAR simple url-> \"aaaa\";";
+ String text = "aaaa";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+
+ @Test
+ public void ruleStringError(){
+ String grammar = "GRAMMAR simple url-> \"aaaa\";";
+ String text = "aabb";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+ @Test
+ public void ruleStringMany(){
+ String grammar = "GRAMMAR simple url-> \"aaaa\" \"bb\" \"cc\" \"dd\" \"ee\";";
+ String text = "aaaabbccddee";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+
+ @Test
+ public void ruleRegex(){
+ String grammar = "GRAMMAR simple url-> [a-z];";
+ String text = "a";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+
+ @Test
+ public void ruleRegexMany(){
+ String grammar = "GRAMMAR simple url-> [a-z] [A-Z] [0-9];";
+ String text = "aZ2";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+
+ @Test
+ public void ruleRegexError(){
+ String grammar = "GRAMMAR simple url-> [a-z];";
+ String text = "X";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+
+ @Test
+ public void ruleOneOrMore(){
+ String grammar = "GRAMMAR simple url-> \"a\"+;";
+ String text = "aaa";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleOneOrMore2(){
+ String grammar = "GRAMMAR simple url-> \"ab\"+;";
+ String text = "ababab";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleOneOrMoreError(){
+ String grammar = "GRAMMAR simple url-> \"abc\"+;";
+ String text = "ababab";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+ @Test
+ public void ruleZeroOrMore(){
+ String grammar = "GRAMMAR simple url-> \"a\"*;";
+ String text = "aaa";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleZeroOrMore2(){
+ String grammar = "GRAMMAR simple url-> \"ab\"*;";
+ String text = "ababX";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleOrderedChoise(){
+ String grammar = "GRAMMAR simple url-> \"a\"/\"b\";";
+ String text = "b";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleOrderedChoiseError(){
+ String grammar = "GRAMMAR simple url-> \"a\"/\"b\";";
+ String text = "c";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+
+ @Test
+ public void ruleGroup(){
+ String grammar = "GRAMMAR simple url-> (\"a\"/\"b\")+;";
+ String text = "ab";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleGroupError(){
+ String grammar = "GRAMMAR simple url-> (\"a\"/\"b\");";
+ String text = "c";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+
+ @Test
+ public void ruleNot(){
+ String grammar = "GRAMMAR simple url-> !\"a\";";
+ String text = "b";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleNotError(){
+ String grammar = "GRAMMAR simple url-> !\"a\";";
+ String text = "a";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+ /**
+ * осатвлю пока также как в js версии.
+ * по моему то неправильное поведение предиката not
+ */
+ @Test
+ public void ruleNot2(){
+ String grammar = "GRAMMAR simple url-> (!\"a\") \"v\";";
+ String text = "v";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+
+ @Test
+ @Ignore
+ public void ruleAnd(){
+
+ /*
+ ???????
+
+ не понятно что это
+
+ String grammar = "GRAMMAR simple url-> (!\"a\") \"v\";";
+ String text = "v";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ */
+ }
+
+ @Test
+ public void ruleOptional(){
+ String grammar = "GRAMMAR simple url-> \"a\"? \"b\";";
+ String text = "ab";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleOptional2(){
+ String grammar = "GRAMMAR simple url-> \"a\"? \"b\";";
+ String text = "b";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleOptionalError(){
+ String grammar = "GRAMMAR simple url-> \"a\"? \"b\";";
+ String text = "xb";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+
+ @Test
+ public void ruleSubExpression(){
+ String grammar = "GRAMMAR url url -> shema; shema -> \"ab\";";
+ String text = "ab";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void ruleSubExpressionError(){
+ String grammar = "GRAMMAR url url -> shema; shema -> \"ab\";";
+ String text = "ac";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+ @Test
+ public void ruleCError(){
+ String grammar = "GRAMMAR url url -> shema; shema -> \"ab\";";
+ String text = "ac";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+
+ @Test
+ public void complicateTest_URL(){
+ String grammar = "GRAMMAR url\n" +
+ "\n" +
+ "url -> scheme \"://\" host pathname search hash?;\n" +
+ "scheme -> \"http\" \"s\"?;\n" +
+ "host -> hostname port?;\n" +
+ "hostname -> segment (\".\" segment)*;\n" +
+ "segment -> [a-z0-9-]+;\n" +
+ "port -> \":\" [0-9]+;\n" +
+ "pathname -> \"/\" [^ ?]*;\n" +
+ "search -> (\"?\" [^ #]*)?;\n" +
+ "hash -> \"#\" [^ ]*;";
+
+ String text = "https://simplepeg.github.io/";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.OK);
+ }
+
+ @Test
+ public void complicateTest_URL_Error(){
+ String grammar = "GRAMMAR url\n" +
+ "\n" +
+ "url -> scheme \"://\" host pathname search hash?;\n" +
+ "scheme -> \"http\" \"s\"?;\n" +
+ "host -> hostname port?;\n" +
+ "hostname -> segment (\".\" segment)*;\n" +
+ "segment -> [a-z0-9-]+;\n" +
+ "port -> \":\" [0-9]+;\n" +
+ "pathname -> \"/\" [^ ?]*;\n" +
+ "search -> (\"?\" [^ #]*)?;\n" +
+ "hash -> \"#\" [^ ]*;";
+
+ String text = "https://////simplepeg.github.io/";
+
+ PegNode grammarTree = SpegParser.createAndExec(grammar);
+ RuleProcessor rp = new RuleProcessor(grammarTree);
+ CheckResult cr = rp.check(text);
+
+ assertEquals(cr.getErrorText(), cr.getResultType(), ResultType.ERROR);
+ }
+
+}
diff --git a/src/test/java/Tests.java b/src/test/java/Tests.java
index a695a8c..4681d81 100644
--- a/src/test/java/Tests.java
+++ b/src/test/java/Tests.java
@@ -1,5 +1,116 @@
+import org.junit.Assert;
+import org.junit.Test;
+import ru.dude.simplepeg.SpegParser;
+import ru.dude.simplepeg.entity.PegNode;
+import ru.dude.simplepeg.entity.ResultType;
+
+import java.io.ByteArrayInputStream;
+
/**
* Created by dude on 29.10.2017.
*/
-public class Tests {
+public class Tests extends Assert{
+
+ private void assertProcess(String input,ResultType expected){
+ PegNode result = SpegParser.createAndExec(input);
+ String message = "INPUT:\n"+input+"\nERROR:"+result.getError();
+ assertEquals(message,expected,result.getResultType());
+ }
+
+ // @Test
+ public void all(){
+ headerAndSimpleRule();
+ noRuleError();
+ noLastSemicolonError();
+
+ oneRuleStrings();
+ oneRuleRegexp();
+ twoRulesSimple();
+ twoRulesRegexp();
+ manyRulesRegexp();
+
+ complicateTest_URL();
+ }
+
+ @Test
+ public void headerAndSimpleRule(){
+ String input = "GRAMMAR simple rule-> \"aaaa\";";
+ assertProcess(input,ResultType.OK);
+ }
+
+ @Test
+ public void orderedGrammar(){
+ String input = "GRAMMAR simple rule-> \"a\"/\"b\";";
+ assertProcess(input,ResultType.OK);
+ }
+
+ @Test
+ public void groupGrammar(){
+ String input = "GRAMMAR simple rule-> (\"a\"/\"b\")+;";
+ assertProcess(input,ResultType.OK);
+ }
+
+ @Test
+ public void noRuleError(){
+ String input = "GRAMMAR simple;";
+ assertProcess(input,ResultType.ERROR);
+ }
+
+ @Test
+ public void noLastSemicolonError(){
+ String input = "GRAMMAR simple rule-> \"aaaa\"";
+ assertProcess(input,ResultType.ERROR);
+ }
+
+ @Test
+ public void oneRuleStrings(){
+ String input = "GRAMMAR one rule-> \"aaaa\" \"bb\" \"cccc\" \"zz\";";
+ assertProcess(input,ResultType.OK);
+ }
+
+ @Test
+ public void oneRuleRegexp(){
+ String input = "GRAMMAR one rule-> \"XX\" [a-zA-Z0-9-]+ [^ #]*;";
+ assertProcess(input,ResultType.OK);
+ }
+
+
+ @Test
+ public void twoRulesSimple(){
+ String input = "GRAMMAR duo rule_one-> \"XX\" rule_two; rule_two-> \"YY\";";
+ assertProcess(input,ResultType.OK);
+ }
+
+ @Test
+ public void twoRulesRegexp(){
+ String input = "GRAMMAR duo rule_one-> \"XX\" rule_two [^ #]*; rule_two-> \"YY\" [a-zA-Z0-9-]+;";
+ assertProcess(input,ResultType.OK);
+ }
+
+ @Test
+ public void manyRulesRegexp(){
+ String input = "GRAMMAR many\n" +
+ "rule-> r_one r_two r_three r_four; \n" +
+ "r_one-> \"XX\";\n" +
+ "r_two-> [^ #]*;\n" +
+ "r_three-> \"YY\";\n" +
+ "r_four-> \"ZZ\" [a-zA-Z0-9-]+;";
+ assertProcess(input,ResultType.OK);
+ }
+
+ @Test
+ public void complicateTest_URL(){
+ String input = "GRAMMAR url\n" +
+ "\n" +
+ "url -> scheme \"://\" host pathname search hash?;\n" +
+ "scheme -> \"http\" \"s\"?;\n" +
+ "host -> hostname port?;\n" +
+ "hostname -> segment (\".\" segment)*;\n" +
+ "segment -> [a-z0-9-]+;\n" +
+ "port -> \":\" [0-9]+;\n" +
+ "pathname -> \"/\" [^ ?]*;\n" +
+ "search -> (\"?\" [^ #]*)?;\n" +
+ "hash -> \"#\" [^ ]*;";
+ assertProcess(input,ResultType.OK);
+ }
}