From 53e6f31f19530bce11c7481101f99954d0c0fe64 Mon Sep 17 00:00:00 2001 From: dude Date: Sun, 29 Oct 2017 18:42:40 +0300 Subject: [PATCH 01/15] Some part of work --- .../java/ru/dude/simplepeg/Executable.java | 15 ++ .../java/ru/dude/simplepeg/HelloWorld.java | 10 -- .../dude/simplepeg/ParseInputException.java | 11 ++ src/main/java/ru/dude/simplepeg/RdParser.java | 155 ++++++++++++++++++ .../java/ru/dude/simplepeg/SpegParser.java | 101 ++++++++++++ src/main/java/ru/dude/simplepeg/Starter.java | 37 +++++ .../ru/dude/simplepeg/entity/PegNode.java | 135 +++++++++++++++ .../ru/dude/simplepeg/entity/SpegTypes.java | 15 ++ .../java/ru/dude/simplepeg/entity/State.java | 69 ++++++++ 9 files changed, 538 insertions(+), 10 deletions(-) create mode 100644 src/main/java/ru/dude/simplepeg/Executable.java delete mode 100644 src/main/java/ru/dude/simplepeg/HelloWorld.java create mode 100644 src/main/java/ru/dude/simplepeg/ParseInputException.java create mode 100644 src/main/java/ru/dude/simplepeg/RdParser.java create mode 100644 src/main/java/ru/dude/simplepeg/SpegParser.java create mode 100644 src/main/java/ru/dude/simplepeg/Starter.java create mode 100644 src/main/java/ru/dude/simplepeg/entity/PegNode.java create mode 100644 src/main/java/ru/dude/simplepeg/entity/SpegTypes.java create mode 100644 src/main/java/ru/dude/simplepeg/entity/State.java diff --git a/src/main/java/ru/dude/simplepeg/Executable.java b/src/main/java/ru/dude/simplepeg/Executable.java new file mode 100644 index 0000000..35adc3e --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/Executable.java @@ -0,0 +1,15 @@ +package ru.dude.simplepeg; + +/** + * For implements in PEG expression + * Created by dude on 29.10.2017. + */ +public interface Executable { + + /** + * Execute PEG expression + * @return + * @throws ParseInputException + */ + boolean exec()throws ParseInputException; +} diff --git a/src/main/java/ru/dude/simplepeg/HelloWorld.java b/src/main/java/ru/dude/simplepeg/HelloWorld.java deleted file mode 100644 index cdf57c0..0000000 --- a/src/main/java/ru/dude/simplepeg/HelloWorld.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.dude.simplepeg; - -/** - * Created by dude on 29.10.2017. - */ -public class HelloWorld { - public static void main(String[]args){ - System.out.println("HelloWorld"); - } -} diff --git a/src/main/java/ru/dude/simplepeg/ParseInputException.java b/src/main/java/ru/dude/simplepeg/ParseInputException.java new file mode 100644 index 0000000..2eeeb31 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/ParseInputException.java @@ -0,0 +1,11 @@ +package ru.dude.simplepeg; + +/** + * Exception for errors + * + * Created by dude on 29.10.2017. + */ +public class ParseInputException extends Exception { + public ParseInputException(String message) { + } +} diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java new file mode 100644 index 0000000..36a16d9 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -0,0 +1,155 @@ +package ru.dude.simplepeg; + +import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.SpegTypes; +import ru.dude.simplepeg.entity.State; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Parser for PEG business expressions + * + * Created by dude on 29.10.2017. + */ +public class RdParser { + + /** + * Object with processing data + */ + State state; + + public RdParser(State state) { + this.state = state; + } + + public PegNode parseString(final String str) { + + return new PegNode() { + @Override + public boolean exec() throws ParseInputException { + + int endPos = state.getPosition() + str.length(); + if (endPos <= state.getTextData().length() && + state.getTextData().substring(state.getPosition(),endPos).equals(str)) { + setType(SpegTypes.STRING); + addMatch(str); + setStartPosition(state.getPosition()); + setEndPosition(state.appendPosition(str.length())); + return true; + } else { + System.err.println(" parseString " + str + " lastPos = " + state.getPosition()); + return false; + //throw new ParseInputException(" parseString " + str + " lastPos = " + state.getPosition()); + } + } + }; + } + + public PegNode parseRegexp(final String regexp) { + return new PegNode() { + @Override + public boolean exec() throws ParseInputException { + + Pattern pattern = Pattern.compile(regexp); + Matcher matcher = pattern.matcher(state.getTextData()); + if (matcher.find(state.getPosition()) && state.getPosition() == matcher.start()) { + //нашли и у места , где каретка + String founded = matcher.group(); + setType(SpegTypes.REGEXP); + addMatch(founded); + setStartPosition(matcher.start()); + setEndPosition(state.appendPosition(founded.length())); + return true; + } else { + System.err.println(" parseRegexp " + regexp + " lastPos = " + state.getPosition()); + return false; + } + } + }; + } + + public PegNode sequence(final PegNode... nodes) { + return new PegNode() { + + @Override + public boolean exec() throws ParseInputException { + setType(SpegTypes.SEQUENCE); + + for (PegNode pegNode : nodes) { + if (pegNode.exec()) { + appendChild(pegNode); + } else { + return false; + } + } + return true; + } + }; + + } + + public PegNode orderedChoise(final PegNode... nodes) { + return new PegNode() { + + @Override + public boolean exec() throws ParseInputException { + setType(SpegTypes.ORDERED_CHOICE); + + for (PegNode pegNode : nodes) { + if (pegNode.exec()) { + appendChild(pegNode); + return true; + } + } + return false; + } + }; + + } + + public PegNode oneOrMore(PegNode node) { + return oneOrZeroOrMore(false, node); + + } + + public PegNode zeroOrMore(PegNode node) { + return oneOrZeroOrMore(true, node); + + } + + private PegNode oneOrZeroOrMore(final boolean canZero, final PegNode node) { + return new PegNode() { + + @Override + public boolean exec() throws ParseInputException { + setType(canZero ? SpegTypes.ZERO_OR_MORE : SpegTypes.ONE_OR_MORE); + while (node.exec()) { + appendChild(node.copyTruncate()); + } + return canZero || getChildrens().size() > 0; + } + }; + + } + + public PegNode parseEndOfFile(){ + return new PegNode() { + + @Override + public boolean exec() throws ParseInputException { + + if (state.getPosition()>=state.getTextData().length()){ + setType(SpegTypes.END_OF_FILE); + setStartPosition(state.getPosition()); + setEndPosition(state.getPosition()); + return true; + } else { + System.err.println(" parseEndOfFile " + " lastPos = " + state.getPosition()); + return false; + } + } + }; + } + +} diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java new file mode 100644 index 0000000..7c01b1c --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -0,0 +1,101 @@ +package ru.dude.simplepeg; + +import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.State; + +/** + * Parser for SimplePEG constructions + *

+ * Created by dude on 29.10.2017. + */ +public class SpegParser { + + State state; + RdParser rdParser; + + + SpegParser(State state) { + this.state = state; + rdParser = new RdParser(state); + } + + /** + * All SPEG + * @return + */ + public PegNode peg() { + + return rdParser.sequence( + rdParser.zeroOrMore(spacesBreaks()), + parsingHeader(), + rdParser.oneOrMore(spacesBreaks()), + parsingBody(), + rdParser.parseEndOfFile() + ); + } + + /** + * HEADER only + * @return + */ + public PegNode parsingHeader() { + return rdParser.sequence( + rdParser.parseString("GRAMMAR"), + rdParser.oneOrMore(spacesBreaks()), + rdParser.oneOrMore(ruleName()) + ); + } + + + /** + * BODy only + * @return + */ + public PegNode parsingBody() { + return rdParser.oneOrMore( + rdParser.orderedChoise( + parsingRule(), + rdParser.oneOrMore(spacesBreaks()) + ) + ); + } + + /** + * Space symbols filter + * @return + */ + private PegNode spacesBreaks() { + return rdParser.parseRegexp("[\\s]"); + } + + /** + * Parce rule name + * @return + */ + private PegNode ruleName() { + return rdParser.sequence( + rdParser.parseRegexp("[a-zA-Z_]"), + rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) + ); + } + + + /** + * Parce rule + * + * TODO: (not ready) + * @return + */ + private PegNode parsingRule() { + return rdParser.sequence( + rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")), + rdParser.zeroOrMore(spacesBreaks()), + rdParser.parseString("->"), + rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) + + ); + } + + +} 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..d15bc19 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -0,0 +1,37 @@ +package ru.dude.simplepeg; + +import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.State; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by dude on 29.10.2017. + */ +public class Starter { + + public static void main(String [] args)throws Exception{ + + File f = new File("input.txt"); + + State state = new State(); + state.loadByStream(new FileInputStream(f)); + + SpegParser spegParser = new SpegParser(state); + PegNode res = spegParser.peg(); + res.exec(); + + printTree(res); + } + + public static void printTree(PegNode node){ + StringBuilder sb = new StringBuilder(); + node.toJson(sb,0); + System.out.println(sb); + } +} 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..d3f12b2 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/entity/PegNode.java @@ -0,0 +1,135 @@ +package ru.dude.simplepeg.entity; + +import ru.dude.simplepeg.Executable; +import ru.dude.simplepeg.ParseInputException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree object with result data + * + * Created by dude on 29.10.2017. + */ +public abstract class PegNode implements Executable { + SpegTypes type; + StringBuilder match = new StringBuilder(); + Integer startPosition; + Integer endPosition; + + List childrens = new ArrayList<>(); + + protected void appendChild(PegNode child) { + childrens.add(child); + match.append(child.match); + + if (startPosition == null || getStartPosition() > child.getStartPosition()) { + startPosition = child.getStartPosition(); + } + + if (endPosition == null || endPosition < child.getEndPosition()) { + endPosition =child.getEndPosition(); + } + } + + + + public void toJson(StringBuilder sb,int level){ + + addtabs(sb,level).append("{\n"); + addtabs(sb,level+1).append("\"type\" :\"").append(type).append("\",\n"); + addtabs(sb,level+1).append("\"match\" :\"").append(match).append("\",\n"); + addtabs(sb,level+1).append("\"startPosition\" :").append(startPosition).append(",\n"); + addtabs(sb,level+1).append("\"endPosition\" :").append(endPosition).append(",\n"); + + if (childrens.size()>0) { + addtabs(sb, level + 1).append("\"childrens\":[\n"); + for (PegNode children : childrens) { + children.toJson(sb, level + 1); + } + addtabs(sb, level + 1).append("]\n"); + } + addtabs(sb,level).append("}\n"); + } + + private StringBuilder addtabs(StringBuilder sb,int level){ + for (int i=0;i getChildrens() { + return childrens; + } + + public void setChildrens(List childrens) { + this.childrens = childrens; + } + + + public PegNode copyTruncate(){ + PegNode copy = new PegNode() { + @Override + public boolean exec() throws ParseInputException { + return false; + } + }; + + copy.type = this.type; + copy.match = this.match; + copy.startPosition = this.startPosition; + copy.endPosition = this.endPosition; + copy.setChildrens(this.childrens); + + this.match = new StringBuilder(); + this.startPosition = null; + this.endPosition = null; + this.childrens = new ArrayList<>(); + return copy; + } +} diff --git a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java new file mode 100644 index 0000000..476c734 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java @@ -0,0 +1,15 @@ +package ru.dude.simplepeg.entity; + +/** + * PEG operation types + * Created by dude on 29.10.2017. + */ +public enum SpegTypes { + SEQUENCE, + ORDERED_CHOICE, + ONE_OR_MORE, + ZERO_OR_MORE, + REGEXP, + STRING, + END_OF_FILE, +} diff --git a/src/main/java/ru/dude/simplepeg/entity/State.java b/src/main/java/ru/dude/simplepeg/entity/State.java new file mode 100644 index 0000000..091fa11 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/entity/State.java @@ -0,0 +1,69 @@ +package ru.dude.simplepeg.entity; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Store and processing input data + * Created by dude on 29.10.2017. + */ +public class State { + + /** + * Input data + */ + StringBuilder textData; + + /** + * current position (slide) + */ + int position; + + public State(){ + textData = new StringBuilder(); + position = 0; + } + + /** + * Load data from input stream + * @param is + */ + public void loadByStream(InputStream is){ + textData = new StringBuilder(); + + try (Reader r = new InputStreamReader(is, "UTF-8")){ + int c = 0; + while ((c = r.read()) != -1) { + textData.append((char) c); + } + r.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + position = 0; + } + + + public int getPosition() { + return position; + } + + public StringBuilder getTextData() { + return textData; + } + + /** + * increase slide + * @param len + * @return + */ + public int appendPosition(int len){ + position+=len; + return position; + } + +} From a7145a6bb7760993cf18377e006f74cf5283a679 Mon Sep 17 00:00:00 2001 From: dude Date: Sun, 29 Oct 2017 23:51:40 +0300 Subject: [PATCH 02/15] -2 bags, +2 bags --- src/main/java/ru/dude/simplepeg/RdParser.java | 54 +++++++++++-------- .../java/ru/dude/simplepeg/SpegParser.java | 15 ++++-- src/main/java/ru/dude/simplepeg/Starter.java | 2 + .../ru/dude/simplepeg/entity/PegNode.java | 21 ++++++-- 4 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index 36a16d9..6ef1387 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -28,7 +28,7 @@ public PegNode parseString(final String str) { return new PegNode() { @Override public boolean exec() throws ParseInputException { - + clearNode(); int endPos = state.getPosition() + str.length(); if (endPos <= state.getTextData().length() && state.getTextData().substring(state.getPosition(),endPos).equals(str)) { @@ -50,7 +50,7 @@ public PegNode parseRegexp(final String regexp) { return new PegNode() { @Override public boolean exec() throws ParseInputException { - + clearNode(); Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(state.getTextData()); if (matcher.find(state.getPosition()) && state.getPosition() == matcher.start()) { @@ -74,11 +74,11 @@ public PegNode sequence(final PegNode... nodes) { @Override public boolean exec() throws ParseInputException { + clearNode(); setType(SpegTypes.SEQUENCE); - - for (PegNode pegNode : nodes) { - if (pegNode.exec()) { - appendChild(pegNode); + for (PegNode node : nodes) { + if (node.exec() && node.isResExist()){ + appendChild(node); } else { return false; } @@ -94,11 +94,12 @@ public PegNode orderedChoise(final PegNode... nodes) { @Override public boolean exec() throws ParseInputException { + clearNode(); setType(SpegTypes.ORDERED_CHOICE); - for (PegNode pegNode : nodes) { - if (pegNode.exec()) { - appendChild(pegNode); + for (PegNode node : nodes) { + if (node.exec() && node.isResExist()) { + appendChild(node); return true; } } @@ -108,26 +109,36 @@ public boolean exec() throws ParseInputException { } - public PegNode oneOrMore(PegNode node) { - return oneOrZeroOrMore(false, node); - - } - - public PegNode zeroOrMore(PegNode node) { - return oneOrZeroOrMore(true, node); + public PegNode oneOrMore(final PegNode node) { + return new PegNode() { + @Override + public boolean exec() throws ParseInputException { + clearNode(); + setType(SpegTypes.ONE_OR_MORE); + while (node.exec() && node.isResExist()) { + PegNode truncateNode = node.copyTruncate(); + appendChild(truncateNode); + } + return getChildrens().size() > 0; + } + }; } - private PegNode oneOrZeroOrMore(final boolean canZero, final PegNode node) { + public PegNode zeroOrMore(final PegNode node) { return new PegNode() { @Override public boolean exec() throws ParseInputException { - setType(canZero ? SpegTypes.ZERO_OR_MORE : SpegTypes.ONE_OR_MORE); - while (node.exec()) { - appendChild(node.copyTruncate()); + clearNode(); + setType(SpegTypes.ZERO_OR_MORE); + while (node.exec() && node.isResExist()) { + PegNode truncateNode = node.copyTruncate(); + appendChild(truncateNode); + } - return canZero || getChildrens().size() > 0; + setResExist(getChildrens().size()>0); + return true; } }; @@ -139,6 +150,7 @@ public PegNode parseEndOfFile(){ @Override public boolean exec() throws ParseInputException { + clearNode(); if (state.getPosition()>=state.getTextData().length()){ setType(SpegTypes.END_OF_FILE); setStartPosition(state.getPosition()); diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 7c01b1c..2129140 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -25,13 +25,15 @@ public class SpegParser { */ public PegNode peg() { + return parsingBody(); +/* return rdParser.sequence( rdParser.zeroOrMore(spacesBreaks()), parsingHeader(), rdParser.oneOrMore(spacesBreaks()), parsingBody(), rdParser.parseEndOfFile() - ); + );*/ } /** @@ -88,11 +90,14 @@ private PegNode ruleName() { */ private PegNode parsingRule() { return rdParser.sequence( - rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")), - rdParser.zeroOrMore(spacesBreaks()), + + rdParser.zeroOrMore(rdParser.parseString("URL")), + //rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")), + //rdParser.zeroOrMore(spacesBreaks()), rdParser.parseString("->"), - rdParser.zeroOrMore(spacesBreaks()), - rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) + //rdParser.zeroOrMore(spacesBreaks()), + //rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) + rdParser.zeroOrMore(rdParser.parseString("KARL")) ); } diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java index d15bc19..f80b5c3 100644 --- a/src/main/java/ru/dude/simplepeg/Starter.java +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -22,6 +22,8 @@ public static void main(String [] args)throws Exception{ State state = new State(); state.loadByStream(new FileInputStream(f)); + System.out.println(state.getTextData()); + SpegParser spegParser = new SpegParser(state); PegNode res = spegParser.peg(); res.exec(); diff --git a/src/main/java/ru/dude/simplepeg/entity/PegNode.java b/src/main/java/ru/dude/simplepeg/entity/PegNode.java index d3f12b2..b3792d9 100644 --- a/src/main/java/ru/dude/simplepeg/entity/PegNode.java +++ b/src/main/java/ru/dude/simplepeg/entity/PegNode.java @@ -17,6 +17,8 @@ public abstract class PegNode implements Executable { Integer startPosition; Integer endPosition; + boolean resExist = true; + List childrens = new ArrayList<>(); protected void appendChild(PegNode child) { @@ -111,6 +113,20 @@ public void setChildrens(List childrens) { this.childrens = childrens; } + public boolean isResExist() { + return resExist; + } + + public void setResExist(boolean resExist) { + this.resExist = resExist; + } + + public void clearNode(){ + this.match = new StringBuilder(); + this.startPosition = null; + this.endPosition = null; + this.childrens = new ArrayList<>(); + } public PegNode copyTruncate(){ PegNode copy = new PegNode() { @@ -126,10 +142,7 @@ public boolean exec() throws ParseInputException { copy.endPosition = this.endPosition; copy.setChildrens(this.childrens); - this.match = new StringBuilder(); - this.startPosition = null; - this.endPosition = null; - this.childrens = new ArrayList<>(); + clearNode(); return copy; } } From 38df66d6d95b3f013f3715f663a25a3183036c2c Mon Sep 17 00:00:00 2001 From: dude Date: Mon, 30 Oct 2017 21:30:22 +0300 Subject: [PATCH 03/15] Restruct by Executor --- .../java/ru/dude/simplepeg/Executable.java | 4 +- src/main/java/ru/dude/simplepeg/RdParser.java | 194 +++++++++++------- .../java/ru/dude/simplepeg/SpegParser.java | 30 +-- src/main/java/ru/dude/simplepeg/Starter.java | 6 +- .../ru/dude/simplepeg/entity/PegNode.java | 48 ++--- .../ru/dude/simplepeg/entity/ResultType.java | 11 + .../java/ru/dude/simplepeg/entity/State.java | 6 + src/test/java/Tests.java | 6 +- 8 files changed, 181 insertions(+), 124 deletions(-) create mode 100644 src/main/java/ru/dude/simplepeg/entity/ResultType.java diff --git a/src/main/java/ru/dude/simplepeg/Executable.java b/src/main/java/ru/dude/simplepeg/Executable.java index 35adc3e..17f2fb7 100644 --- a/src/main/java/ru/dude/simplepeg/Executable.java +++ b/src/main/java/ru/dude/simplepeg/Executable.java @@ -1,5 +1,7 @@ package ru.dude.simplepeg; +import ru.dude.simplepeg.entity.PegNode; + /** * For implements in PEG expression * Created by dude on 29.10.2017. @@ -11,5 +13,5 @@ public interface Executable { * @return * @throws ParseInputException */ - boolean exec()throws ParseInputException; + PegNode exec(); } diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index 6ef1387..e6b68ee 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -1,6 +1,7 @@ package ru.dude.simplepeg; import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.ResultType; import ru.dude.simplepeg.entity.SpegTypes; import ru.dude.simplepeg.entity.State; @@ -23,143 +24,188 @@ public RdParser(State state) { this.state = state; } - public PegNode parseString(final String str) { + public Executable parseString(final String str) { - return new PegNode() { + return new Executable() { @Override - public boolean exec() throws ParseInputException { - clearNode(); + public PegNode exec(){ + PegNode res = new PegNode(); + res.setType(SpegTypes.STRING); + int endPos = state.getPosition() + str.length(); if (endPos <= state.getTextData().length() && state.getTextData().substring(state.getPosition(),endPos).equals(str)) { - setType(SpegTypes.STRING); - addMatch(str); - setStartPosition(state.getPosition()); - setEndPosition(state.appendPosition(str.length())); - return true; + + res.addMatch(str); + res.setStartPosition(state.getPosition()); + res.setEndPosition(state.appendPosition(str.length())); + res.setResultType(ResultType.OK); } else { - System.err.println(" parseString " + str + " lastPos = " + state.getPosition()); - return false; - //throw new ParseInputException(" parseString " + str + " lastPos = " + state.getPosition()); + res.setResultType(ResultType.ERROR); + res.setError(" parseString " + str + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); } + return res; } }; } - public PegNode parseRegexp(final String regexp) { - return new PegNode() { + public Executable parseRegexp(final String regexp) { + return new Executable() { @Override - public boolean exec() throws ParseInputException { - clearNode(); + public PegNode exec(){ + + 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(); - setType(SpegTypes.REGEXP); - addMatch(founded); - setStartPosition(matcher.start()); - setEndPosition(state.appendPosition(founded.length())); - return true; + + res.addMatch(founded); + res.setStartPosition(matcher.start()); + res.setEndPosition(state.appendPosition(founded.length())); + res.setResultType(ResultType.OK); } else { - System.err.println(" parseRegexp " + regexp + " lastPos = " + state.getPosition()); - return false; + res.setResultType(ResultType.ERROR); + res.setError(" parseRegexp " + regexp + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); } + return res; } }; } - public PegNode sequence(final PegNode... nodes) { - return new PegNode() { + public Executable sequence(final Executable... execs) { + return new Executable() { @Override - public boolean exec() throws ParseInputException { - clearNode(); - setType(SpegTypes.SEQUENCE); - for (PegNode node : nodes) { - if (node.exec() && node.isResExist()){ - appendChild(node); - } else { - return false; + public PegNode exec(){ + PegNode res = new PegNode(); + res.setType(SpegTypes.SEQUENCE); + + for (Executable exec : execs) { + PegNode pegNode = exec.exec(); + + switch (pegNode.getResultType()){ + case OK: + res.appendChild(pegNode); + res.setResultType(ResultType.OK); + break; + case ERROR: + res.setResultType(ResultType.ERROR); + res.setError(" sequence " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); + return res; } } - return true; + + if (res.getChildrens().size() == 0){ + res.setResultType(ResultType.EMPTY); + } + return res; } }; } - public PegNode orderedChoise(final PegNode... nodes) { - return new PegNode() { + public Executable orderedChoise(final Executable... execs) { + return new Executable() { @Override - public boolean exec() throws ParseInputException { - clearNode(); - setType(SpegTypes.ORDERED_CHOICE); - - for (PegNode node : nodes) { - if (node.exec() && node.isResExist()) { - appendChild(node); - return true; + public PegNode exec() { + PegNode res = new PegNode(); + res.setType(SpegTypes.ORDERED_CHOICE); + + for (Executable exec : execs) { + PegNode pegNode = exec.exec(); + + switch (pegNode.getResultType()){ + case OK: + res.appendChild(pegNode); + res.setResultType(ResultType.OK); + res.setError(""); + return res; + case EMPTY: + res.setResultType(ResultType.EMPTY); + res.setError(""); + return res; + case ERROR: + res.setResultType(ResultType.ERROR); + res.setError(" orderedChoise " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); + } } - return false; + return res; } }; } - public PegNode oneOrMore(final PegNode node) { - return new PegNode() { + public Executable oneOrMore(final Executable exec) { + return new Executable() { @Override - public boolean exec() throws ParseInputException { - clearNode(); - setType(SpegTypes.ONE_OR_MORE); - while (node.exec() && node.isResExist()) { - PegNode truncateNode = node.copyTruncate(); - appendChild(truncateNode); + public PegNode exec(){ + PegNode res = new PegNode(); + res.setType(SpegTypes.ONE_OR_MORE); + + PegNode pegNode; + while ((pegNode = exec.exec()).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 getChildrens().size() > 0; + return res; } }; } - public PegNode zeroOrMore(final PegNode node) { - return new PegNode() { + public Executable zeroOrMore(final Executable exec) { + return new Executable() { @Override - public boolean exec() throws ParseInputException { - clearNode(); - setType(SpegTypes.ZERO_OR_MORE); - while (node.exec() && node.isResExist()) { - PegNode truncateNode = node.copyTruncate(); - appendChild(truncateNode); + public PegNode exec(){ + PegNode res = new PegNode(); + res.setType(SpegTypes.ZERO_OR_MORE); + PegNode pegNode; + while ((pegNode = exec.exec()).getResultType().equals(ResultType.OK)) { + res.appendChild(pegNode); } - setResExist(getChildrens().size()>0); - return true; + + if (res.getChildrens().size() == 0){ + res.setResultType(ResultType.EMPTY); + } else { + res.setResultType(ResultType.OK); + } + return res; } }; } - public PegNode parseEndOfFile(){ - return new PegNode() { + public Executable parseEndOfFile(){ + return new Executable() { @Override - public boolean exec() throws ParseInputException { + public PegNode exec(){ - clearNode(); + PegNode res = new PegNode(); + res.setType(SpegTypes.END_OF_FILE); if (state.getPosition()>=state.getTextData().length()){ - setType(SpegTypes.END_OF_FILE); - setStartPosition(state.getPosition()); - setEndPosition(state.getPosition()); - return true; + + res.setStartPosition(state.getPosition()); + res.setEndPosition(state.getPosition()); } else { - System.err.println(" parseEndOfFile " + " lastPos = " + state.getPosition()); - return false; + res.setResultType(ResultType.ERROR); + res.setError(" parseEndOfFile " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); } + return res; } }; } diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 2129140..40ff387 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -23,24 +23,26 @@ public class SpegParser { * All SPEG * @return */ - public PegNode peg() { + public Executable peg() { + + + + - return parsingBody(); -/* return rdParser.sequence( rdParser.zeroOrMore(spacesBreaks()), parsingHeader(), rdParser.oneOrMore(spacesBreaks()), parsingBody(), rdParser.parseEndOfFile() - );*/ + ); } /** * HEADER only * @return */ - public PegNode parsingHeader() { + public Executable parsingHeader() { return rdParser.sequence( rdParser.parseString("GRAMMAR"), rdParser.oneOrMore(spacesBreaks()), @@ -53,7 +55,7 @@ public PegNode parsingHeader() { * BODy only * @return */ - public PegNode parsingBody() { + public Executable parsingBody() { return rdParser.oneOrMore( rdParser.orderedChoise( parsingRule(), @@ -66,7 +68,7 @@ public PegNode parsingBody() { * Space symbols filter * @return */ - private PegNode spacesBreaks() { + private Executable spacesBreaks() { return rdParser.parseRegexp("[\\s]"); } @@ -74,7 +76,7 @@ private PegNode spacesBreaks() { * Parce rule name * @return */ - private PegNode ruleName() { + private Executable ruleName() { return rdParser.sequence( rdParser.parseRegexp("[a-zA-Z_]"), rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) @@ -88,16 +90,14 @@ private PegNode ruleName() { * TODO: (not ready) * @return */ - private PegNode parsingRule() { + private Executable parsingRule() { return rdParser.sequence( - rdParser.zeroOrMore(rdParser.parseString("URL")), - //rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")), - //rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")), + rdParser.zeroOrMore(spacesBreaks()), rdParser.parseString("->"), - //rdParser.zeroOrMore(spacesBreaks()), - //rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) - rdParser.zeroOrMore(rdParser.parseString("KARL")) + rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) ); } diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java index f80b5c3..f4312fc 100644 --- a/src/main/java/ru/dude/simplepeg/Starter.java +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -25,13 +25,15 @@ public static void main(String [] args)throws Exception{ System.out.println(state.getTextData()); SpegParser spegParser = new SpegParser(state); - PegNode res = spegParser.peg(); - res.exec(); + PegNode res = spegParser.peg().exec(); printTree(res); } public static void printTree(PegNode node){ + System.out.println(node.getResultType()); + System.out.println(node.getError()); + StringBuilder sb = new StringBuilder(); node.toJson(sb,0); System.out.println(sb); diff --git a/src/main/java/ru/dude/simplepeg/entity/PegNode.java b/src/main/java/ru/dude/simplepeg/entity/PegNode.java index b3792d9..face9e8 100644 --- a/src/main/java/ru/dude/simplepeg/entity/PegNode.java +++ b/src/main/java/ru/dude/simplepeg/entity/PegNode.java @@ -11,17 +11,18 @@ * * Created by dude on 29.10.2017. */ -public abstract class PegNode implements Executable { +public class PegNode{ SpegTypes type; StringBuilder match = new StringBuilder(); Integer startPosition; Integer endPosition; - boolean resExist = true; - List childrens = new ArrayList<>(); - protected void appendChild(PegNode child) { + ResultType resultType = ResultType.NONE; + String error; + + public void appendChild(PegNode child) { childrens.add(child); match.append(child.match); @@ -47,11 +48,11 @@ public void toJson(StringBuilder sb,int level){ if (childrens.size()>0) { addtabs(sb, level + 1).append("\"childrens\":[\n"); for (PegNode children : childrens) { - children.toJson(sb, level + 1); + children.toJson(sb, level + 2); } addtabs(sb, level + 1).append("]\n"); } - addtabs(sb,level).append("}\n"); + addtabs(sb,level).append("},\n"); } private StringBuilder addtabs(StringBuilder sb,int level){ @@ -113,36 +114,21 @@ public void setChildrens(List childrens) { this.childrens = childrens; } - public boolean isResExist() { - return resExist; - } - public void setResExist(boolean resExist) { - this.resExist = resExist; + public ResultType getResultType() { + return resultType; } - public void clearNode(){ - this.match = new StringBuilder(); - this.startPosition = null; - this.endPosition = null; - this.childrens = new ArrayList<>(); + public void setResultType(ResultType resultType) { + this.resultType = resultType; } - public PegNode copyTruncate(){ - PegNode copy = new PegNode() { - @Override - public boolean exec() throws ParseInputException { - return false; - } - }; - - copy.type = this.type; - copy.match = this.match; - copy.startPosition = this.startPosition; - copy.endPosition = this.endPosition; - copy.setChildrens(this.childrens); + public String getError() { + return error; + } - clearNode(); - return copy; + public void setError(String error) { + this.error = error; } + } diff --git a/src/main/java/ru/dude/simplepeg/entity/ResultType.java b/src/main/java/ru/dude/simplepeg/entity/ResultType.java new file mode 100644 index 0000000..e50d2a4 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/entity/ResultType.java @@ -0,0 +1,11 @@ +package ru.dude.simplepeg.entity; + +/** + * Created by dude on 30.10.2017. + */ +public enum ResultType { + NONE, + OK, + ERROR, + EMPTY +} diff --git a/src/main/java/ru/dude/simplepeg/entity/State.java b/src/main/java/ru/dude/simplepeg/entity/State.java index 091fa11..b567877 100644 --- a/src/main/java/ru/dude/simplepeg/entity/State.java +++ b/src/main/java/ru/dude/simplepeg/entity/State.java @@ -66,4 +66,10 @@ public int appendPosition(int len){ return position; } + public String atPos() { + if (position Date: Mon, 6 Nov 2017 15:14:39 +0300 Subject: [PATCH 04/15] All blind implementation --- src/main/java/ru/dude/simplepeg/RdParser.java | 72 +++-- .../java/ru/dude/simplepeg/SpegParser.java | 248 +++++++++++++++++- .../ru/dude/simplepeg/entity/SpegTypes.java | 1 + src/test/java/Tests.java | 22 +- 4 files changed, 316 insertions(+), 27 deletions(-) diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index e6b68ee..b64004e 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -10,7 +10,7 @@ /** * Parser for PEG business expressions - * + *

* Created by dude on 29.10.2017. */ public class RdParser { @@ -28,13 +28,13 @@ public Executable parseString(final String str) { return new Executable() { @Override - public PegNode exec(){ + public PegNode exec() { PegNode res = new PegNode(); res.setType(SpegTypes.STRING); int endPos = state.getPosition() + str.length(); if (endPos <= state.getTextData().length() && - state.getTextData().substring(state.getPosition(),endPos).equals(str)) { + state.getTextData().substring(state.getPosition(), endPos).equals(str)) { res.addMatch(str); res.setStartPosition(state.getPosition()); @@ -52,7 +52,7 @@ public PegNode exec(){ public Executable parseRegexp(final String regexp) { return new Executable() { @Override - public PegNode exec(){ + public PegNode exec() { PegNode res = new PegNode(); res.setType(SpegTypes.REGEXP); @@ -80,14 +80,14 @@ public Executable sequence(final Executable... execs) { return new Executable() { @Override - public PegNode exec(){ + public PegNode exec() { PegNode res = new PegNode(); res.setType(SpegTypes.SEQUENCE); for (Executable exec : execs) { PegNode pegNode = exec.exec(); - switch (pegNode.getResultType()){ + switch (pegNode.getResultType()) { case OK: res.appendChild(pegNode); res.setResultType(ResultType.OK); @@ -99,7 +99,7 @@ public PegNode exec(){ } } - if (res.getChildrens().size() == 0){ + if (res.getChildrens().size() == 0) { res.setResultType(ResultType.EMPTY); } return res; @@ -119,7 +119,7 @@ public PegNode exec() { for (Executable exec : execs) { PegNode pegNode = exec.exec(); - switch (pegNode.getResultType()){ + switch (pegNode.getResultType()) { case OK: res.appendChild(pegNode); res.setResultType(ResultType.OK); @@ -145,7 +145,7 @@ public Executable oneOrMore(final Executable exec) { return new Executable() { @Override - public PegNode exec(){ + public PegNode exec() { PegNode res = new PegNode(); res.setType(SpegTypes.ONE_OR_MORE); @@ -154,9 +154,9 @@ public PegNode exec(){ res.appendChild(pegNode); } - if ( res.getChildrens().size()>0){ + if (res.getChildrens().size() > 0) { res.setResultType(ResultType.OK); - }else { + } else { res.setResultType(ResultType.ERROR); res.setError(" oneOrMore " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); } @@ -169,7 +169,7 @@ public Executable zeroOrMore(final Executable exec) { return new Executable() { @Override - public PegNode exec(){ + public PegNode exec() { PegNode res = new PegNode(); res.setType(SpegTypes.ZERO_OR_MORE); @@ -178,7 +178,7 @@ public PegNode exec(){ res.appendChild(pegNode); } - if (res.getChildrens().size() == 0){ + if (res.getChildrens().size() == 0) { res.setResultType(ResultType.EMPTY); } else { res.setResultType(ResultType.OK); @@ -189,15 +189,37 @@ public PegNode exec(){ } - public Executable parseEndOfFile(){ + public Executable optional(final Executable exec) { + return new Executable() { + + @Override + public PegNode exec() { + PegNode res = new PegNode(); + res.setType(SpegTypes.OPTIONAL); + + PegNode pegNode = exec.exec(); + if (pegNode.getResultType().equals(ResultType.OK)) { + res.setResultType(ResultType.OK); + res.appendChild(pegNode); + } else { + res.setResultType(ResultType.EMPTY); + } + + return res; + } + }; + + } + + public Executable parseEndOfFile() { return new Executable() { @Override - public PegNode exec(){ + public PegNode exec() { PegNode res = new PegNode(); res.setType(SpegTypes.END_OF_FILE); - if (state.getPosition()>=state.getTextData().length()){ + if (state.getPosition() >= state.getTextData().length()) { res.setStartPosition(state.getPosition()); res.setEndPosition(state.getPosition()); @@ -210,4 +232,22 @@ public PegNode exec(){ }; } + /** + * Not Supported yet + * @param exec + * @return + */ + public Executable rec(final Executable exec) { + return new Executable() { + + @Override + public PegNode exec() { + + throw new UnsupportedOperationException("Not suppordet yet"); + } + }; + } + + + } diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 40ff387..301207c 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -25,17 +25,39 @@ public class SpegParser { */ public Executable peg() { + return rdParser.orderedChoise( + rdParser.parseString("A"), + rdParser.parseString("11"), + rdParser.parseString("AMO") + ); +/* + return rdParser.orderedChoise( + parsingOptional(), + parsingAtomicExpression() + ); +*/ +/* + rdParser.orderedChoise( + parsingNot(), + parsingAnd(), + parsingOptional(), + parsingOneOrMore(), + parsingZeroOrMore(), + parsingGroup(), + parsingAtomicExpression() + ); + */ - +/* return rdParser.sequence( rdParser.zeroOrMore(spacesBreaks()), parsingHeader(), rdParser.oneOrMore(spacesBreaks()), parsingBody(), rdParser.parseEndOfFile() - ); + );*/ } /** @@ -72,8 +94,34 @@ private Executable spacesBreaks() { return rdParser.parseRegexp("[\\s]"); } + + + + /** + * Parce rule + * + * TODO: (not ready) + * @return + */ + private Executable parsingRule() { + return rdParser.sequence( + + ruleName(), + rdParser.zeroOrMore(spacesBreaks()), + rdParser.parseString("->"), + rdParser.zeroOrMore(spacesBreaks()), + ruleExpression(), + rdParser.zeroOrMore(spacesBreaks()), + rdParser.parseString(";"), + rdParser.zeroOrMore(spacesBreaks()) + + ); + } + /** - * Parce rule name + * Parse rule name + * + * js parsing_rule_name * @return */ private Executable ruleName() { @@ -83,24 +131,204 @@ private Executable ruleName() { ); } - /** - * Parce rule + * Parse rule Expression * - * TODO: (not ready) + * js parsing_expression * @return */ - private Executable parsingRule() { + private Executable ruleExpression() { + return rdParser.orderedChoise( + parsingSequence(), + parsingOrderedChoice(), + parsingSubExpression() + ); + } + + + + private Executable parsingSequence() { + + return rdParser.sequence( + rdParser.orderedChoise( + parsingOrderedChoice(), + parsingSubExpression() + ), + rdParser.oneOrMore( + rdParser.sequence( + rdParser.oneOrMore(spacesBreaks()), + rdParser.orderedChoise( + parsingOrderedChoice(), + parsingSubExpression() + ) + ) + ) + ); + } + + private Executable parsingOrderedChoice() { + return rdParser.sequence( + parsingSubExpression(), + rdParser.oneOrMore( + rdParser.sequence( + rdParser.oneOrMore(spacesBreaks()), + rdParser.parseString("/"), + rdParser.oneOrMore(spacesBreaks()), + parsingSubExpression() + ) + ) + ); + } + + private Executable parsingSubExpression() { + return rdParser.orderedChoise( + parsingNot(), + parsingAnd(), + parsingOptional(), + parsingAtomicExpression(), + parsingOneOrMore(), + parsingZeroOrMore(), + parsingGroup() + + ); + +/* + return rdParser.sequence( + + rdParser.zeroOrMore(rdParser.sequence( + tag(), + rdParser.parseString(":") + + )), + rdParser.orderedChoise( + parsingNot(), + parsingAnd(), + parsingOptional(), + parsingOneOrMore(), + parsingZeroOrMore(), + parsingGroup(), + parsingAtomicExpression() + ) + + ); + */ + } + + + private Executable tag() { return rdParser.sequence( + rdParser.parseRegexp("[a-zA-Z_]"), + rdParser.zeroOrMore( rdParser.parseRegexp("[a-zA-Z0-9_]")) + ); + } + - rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")), + private Executable parsingGroup() { + return rdParser.sequence( + rdParser.parseString("("), rdParser.zeroOrMore(spacesBreaks()), - rdParser.parseString("->"), + // rdParser.rec(ruleExpression()), rdParser.zeroOrMore(spacesBreaks()), - rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) + rdParser.parseString(")") + ); + } + private Executable parsingAtomicExpression() { + return rdParser.orderedChoise( + parseString(), + parseRegex(), + rdParser.parseEndOfFile(), + parsingRuleCall() ); } + /** + * js parsing_rule_call() + * @return + */ + private Executable parsingRuleCall() { + return ruleName(); + } + + private Executable parseString() { + return rdParser.sequence( + rdParser.parseString("\""), + rdParser.oneOrMore(rdParser.orderedChoise( + rdParser.parseString("\\\\"), + rdParser.parseString("\\\""), + rdParser.parseRegexp("[^\"]") + )), + rdParser.parseString("\"") + ); + } + + private Executable parseRegex() { + return rdParser.orderedChoise( + rdParser.sequence( + rdParser.parseString("["), + rdParser.optional(rdParser.parseString("^")), + rdParser.oneOrMore(rdParser.orderedChoise( + rdParser.parseString("\\]"), + rdParser.parseString("\\["), + rdParser.parseRegexp("[^\\]]") + )), + rdParser.parseString("]") + ), + rdParser.parseString(".") + ); + } + + + private Executable parsingNot(){ + return rdParser.sequence( + rdParser.parseString("!"), + rdParser.orderedChoise( + parsingGroup(), + parsingAtomicExpression() + ) + ); + } + + private Executable parsingAnd(){ + return rdParser.sequence( + rdParser.parseString("&"), + rdParser.orderedChoise( + parsingGroup(), + parsingAtomicExpression() + ) + ); + } + + private Executable parsingOneOrMore(){ + return rdParser.sequence( + rdParser.orderedChoise( + parsingGroup(), + parsingAtomicExpression() + ), + rdParser.parseString("+") + ); + } + + + private Executable parsingZeroOrMore(){ + return rdParser.sequence( + rdParser.orderedChoise( + parsingGroup(), + parsingAtomicExpression() + ), + rdParser.parseString("*") + ); + } + + private Executable parsingOptional(){ + return rdParser.sequence( + rdParser.orderedChoise( + parsingGroup(), + parsingAtomicExpression() + ), + rdParser.parseString("?") + ); + } + } diff --git a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java index 476c734..d71d10b 100644 --- a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java +++ b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java @@ -11,5 +11,6 @@ public enum SpegTypes { ZERO_OR_MORE, REGEXP, STRING, + OPTIONAL, END_OF_FILE, } diff --git a/src/test/java/Tests.java b/src/test/java/Tests.java index 293ff98..a895c70 100644 --- a/src/test/java/Tests.java +++ b/src/test/java/Tests.java @@ -1,9 +1,29 @@ -import junit.framework.Assert; +import org.junit.Assert; +import org.junit.Test; /** * Created by dude on 29.10.2017. */ public class Tests extends Assert{ + @Test + public void all(){ + one(); + two(); + } + + + @Test + public void one(){ + assertEquals(2, 2); + } + + @Test + public void two(){ + assertEquals(3, 3); + } + + + } From 6542e3916a8b4a07f50dcdc10fa86facd927a500 Mon Sep 17 00:00:00 2001 From: dude Date: Mon, 6 Nov 2017 17:32:15 +0300 Subject: [PATCH 05/15] Url work without tags --- .../java/ru/dude/simplepeg/Executable.java | 3 +- src/main/java/ru/dude/simplepeg/RdParser.java | 48 +++++++++---------- .../java/ru/dude/simplepeg/SpegParser.java | 39 +++------------ src/main/java/ru/dude/simplepeg/Starter.java | 2 +- .../java/ru/dude/simplepeg/entity/State.java | 12 +++++ 5 files changed, 45 insertions(+), 59 deletions(-) diff --git a/src/main/java/ru/dude/simplepeg/Executable.java b/src/main/java/ru/dude/simplepeg/Executable.java index 17f2fb7..437c672 100644 --- a/src/main/java/ru/dude/simplepeg/Executable.java +++ b/src/main/java/ru/dude/simplepeg/Executable.java @@ -1,6 +1,7 @@ package ru.dude.simplepeg; import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.State; /** * For implements in PEG expression @@ -13,5 +14,5 @@ public interface Executable { * @return * @throws ParseInputException */ - PegNode exec(); + PegNode exec(State state); } diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index b64004e..9b98382 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -15,20 +15,16 @@ */ public class RdParser { - /** - * Object with processing data - */ - State state; - public RdParser(State state) { - this.state = state; + public RdParser() { + } public Executable parseString(final String str) { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.STRING); @@ -52,7 +48,7 @@ public PegNode exec() { public Executable parseRegexp(final String regexp) { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.REGEXP); @@ -80,12 +76,12 @@ public Executable sequence(final Executable... execs) { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.SEQUENCE); for (Executable exec : execs) { - PegNode pegNode = exec.exec(); + PegNode pegNode = exec.exec(state); switch (pegNode.getResultType()) { case OK: @@ -112,18 +108,20 @@ public Executable orderedChoise(final Executable... execs) { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.ORDERED_CHOICE); for (Executable exec : execs) { - PegNode pegNode = exec.exec(); + 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); @@ -145,12 +143,12 @@ public Executable oneOrMore(final Executable exec) { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.ONE_OR_MORE); PegNode pegNode; - while ((pegNode = exec.exec()).getResultType().equals(ResultType.OK)) { + while ((pegNode = exec.exec(state)).getResultType().equals(ResultType.OK)) { res.appendChild(pegNode); } @@ -169,12 +167,12 @@ public Executable zeroOrMore(final Executable exec) { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.ZERO_OR_MORE); PegNode pegNode; - while ((pegNode = exec.exec()).getResultType().equals(ResultType.OK)) { + while ((pegNode = exec.exec(state)).getResultType().equals(ResultType.OK)) { res.appendChild(pegNode); } @@ -193,11 +191,11 @@ public Executable optional(final Executable exec) { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.OPTIONAL); - PegNode pegNode = exec.exec(); + PegNode pegNode = exec.exec(state); if (pegNode.getResultType().equals(ResultType.OK)) { res.setResultType(ResultType.OK); res.appendChild(pegNode); @@ -215,7 +213,7 @@ public Executable parseEndOfFile() { return new Executable() { @Override - public PegNode exec() { + public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.END_OF_FILE); @@ -233,17 +231,17 @@ public PegNode exec() { } /** - * Not Supported yet - * @param exec + * + * @param spParser * @return */ - public Executable rec(final Executable exec) { + public Executable rec(final SpegParser spParser) { return new Executable() { @Override - public PegNode exec() { - - throw new UnsupportedOperationException("Not suppordet yet"); + public PegNode exec(State state) { + Executable recExec = spParser.ruleExpression(); + return recExec.exec(state); } }; } diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 301207c..1a9a9a3 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -16,7 +16,7 @@ public class SpegParser { SpegParser(State state) { this.state = state; - rdParser = new RdParser(state); + rdParser = new RdParser(); } /** @@ -25,39 +25,14 @@ public class SpegParser { */ public Executable peg() { - return rdParser.orderedChoise( - rdParser.parseString("A"), - rdParser.parseString("11"), - rdParser.parseString("AMO") - ); - -/* - return rdParser.orderedChoise( - parsingOptional(), - parsingAtomicExpression() - ); -*/ -/* - rdParser.orderedChoise( - parsingNot(), - parsingAnd(), - parsingOptional(), - parsingOneOrMore(), - parsingZeroOrMore(), - parsingGroup(), - parsingAtomicExpression() - ); - */ - - -/* return rdParser.sequence( rdParser.zeroOrMore(spacesBreaks()), parsingHeader(), rdParser.oneOrMore(spacesBreaks()), parsingBody(), rdParser.parseEndOfFile() - );*/ + ); + } /** @@ -137,7 +112,7 @@ private Executable ruleName() { * js parsing_expression * @return */ - private Executable ruleExpression() { + public Executable ruleExpression() { return rdParser.orderedChoise( parsingSequence(), parsingOrderedChoice(), @@ -185,10 +160,10 @@ private Executable parsingSubExpression() { parsingNot(), parsingAnd(), parsingOptional(), - parsingAtomicExpression(), parsingOneOrMore(), parsingZeroOrMore(), - parsingGroup() + parsingGroup(), + parsingAtomicExpression() ); @@ -227,7 +202,7 @@ private Executable parsingGroup() { return rdParser.sequence( rdParser.parseString("("), rdParser.zeroOrMore(spacesBreaks()), - // rdParser.rec(ruleExpression()), + rdParser.rec(this), rdParser.zeroOrMore(spacesBreaks()), rdParser.parseString(")") ); diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java index f4312fc..23fffaf 100644 --- a/src/main/java/ru/dude/simplepeg/Starter.java +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -25,7 +25,7 @@ public static void main(String [] args)throws Exception{ System.out.println(state.getTextData()); SpegParser spegParser = new SpegParser(state); - PegNode res = spegParser.peg().exec(); + PegNode res = spegParser.peg().exec(state); printTree(res); } diff --git a/src/main/java/ru/dude/simplepeg/entity/State.java b/src/main/java/ru/dude/simplepeg/entity/State.java index b567877..ff26958 100644 --- a/src/main/java/ru/dude/simplepeg/entity/State.java +++ b/src/main/java/ru/dude/simplepeg/entity/State.java @@ -72,4 +72,16 @@ public String atPos() { } return null; } + + public State copy(){ + State state = new State(); + state.textData = textData; + state.position = position; + return state; + } + + + public void setPosition(int position) { + this.position = position; + } } From 02cfa1a2e1b480c283fdbfebe21576bbbac9e744 Mon Sep 17 00:00:00 2001 From: dude Date: Sun, 27 May 2018 11:27:15 +0300 Subject: [PATCH 06/15] Many fixes and debug info --- input.txt | 11 +++ src/main/java/ru/dude/simplepeg/RdParser.java | 18 ++++- .../java/ru/dude/simplepeg/SpegParser.java | 80 ++++++++----------- src/main/java/ru/dude/simplepeg/Starter.java | 16 ++-- .../ru/dude/simplepeg/entity/PegNode.java | 9 +++ 5 files changed, 77 insertions(+), 57 deletions(-) create mode 100644 input.txt diff --git a/input.txt b/input.txt new file mode 100644 index 0000000..b5fcc92 --- /dev/null +++ b/input.txt @@ -0,0 +1,11 @@ +GRAMMAR url + +url -> scheme "://" host pathname search hash?; +scheme -> "http" "s"?; +host -> hostname port?; +hostname -> segment ("." segment)*; +segment -> [a-z0-9-]+; +port -> ":" [0-9]+; +pathname -> "/" [^ ?]*; +search -> ("?" [^ #]*)?; +hash -> "#" [^ ]*; diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index 9b98382..61f2374 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -27,6 +27,7 @@ public Executable parseString(final String str) { 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() && @@ -72,25 +73,32 @@ public PegNode exec(State state) { }; } - public Executable sequence(final Executable... execs) { + 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) { - PegNode pegNode = exec.exec(state); + 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 " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); + res.setError(" sequence "+execName + " lastPos = " + stateCp.getPosition() + " unexpected " + stateCp.atPos()); + state.setPosition(stateCp.getPosition()); return res; } } @@ -112,6 +120,7 @@ public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.ORDERED_CHOICE); + for (Executable exec : execs) { State statecp = state.copy(); PegNode pegNode = exec.exec(statecp); @@ -139,13 +148,14 @@ public PegNode exec(State state) { } - public Executable oneOrMore(final Executable exec) { + 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)) { diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 1a9a9a3..88c4ee1 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -1,6 +1,5 @@ package ru.dude.simplepeg; -import ru.dude.simplepeg.entity.PegNode; import ru.dude.simplepeg.entity.State; /** @@ -25,14 +24,17 @@ public class SpegParser { */ public Executable peg() { - return rdParser.sequence( + //return parsingBody(); + + return rdParser.sequence("peg_parser", rdParser.zeroOrMore(spacesBreaks()), parsingHeader(), - rdParser.oneOrMore(spacesBreaks()), + rdParser.oneOrMore("spaces",spacesBreaks()), parsingBody(), rdParser.parseEndOfFile() ); + } /** @@ -40,10 +42,10 @@ public Executable peg() { * @return */ public Executable parsingHeader() { - return rdParser.sequence( + return rdParser.sequence("header", rdParser.parseString("GRAMMAR"), - rdParser.oneOrMore(spacesBreaks()), - rdParser.oneOrMore(ruleName()) + rdParser.oneOrMore("spaces",spacesBreaks()), + rdParser.oneOrMore("rulenames",ruleName()) ); } @@ -53,10 +55,10 @@ public Executable parsingHeader() { * @return */ public Executable parsingBody() { - return rdParser.oneOrMore( + return rdParser.oneOrMore("body", rdParser.orderedChoise( parsingRule(), - rdParser.oneOrMore(spacesBreaks()) + rdParser.oneOrMore("spaces",spacesBreaks()) ) ); } @@ -79,7 +81,7 @@ private Executable spacesBreaks() { * @return */ private Executable parsingRule() { - return rdParser.sequence( + return rdParser.sequence("rule", ruleName(), rdParser.zeroOrMore(spacesBreaks()), @@ -100,7 +102,7 @@ private Executable parsingRule() { * @return */ private Executable ruleName() { - return rdParser.sequence( + return rdParser.sequence("rule_name", rdParser.parseRegexp("[a-zA-Z_]"), rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) ); @@ -124,14 +126,14 @@ public Executable ruleExpression() { private Executable parsingSequence() { - return rdParser.sequence( + return rdParser.sequence("sequence", rdParser.orderedChoise( parsingOrderedChoice(), parsingSubExpression() ), - rdParser.oneOrMore( - rdParser.sequence( - rdParser.oneOrMore(spacesBreaks()), + rdParser.oneOrMore("sequence_args", + rdParser.sequence("sequence_arg", + rdParser.oneOrMore("spaces",spacesBreaks()), rdParser.orderedChoise( parsingOrderedChoice(), parsingSubExpression() @@ -142,13 +144,13 @@ private Executable parsingSequence() { } private Executable parsingOrderedChoice() { - return rdParser.sequence( + return rdParser.sequence("ordered_choise", parsingSubExpression(), - rdParser.oneOrMore( - rdParser.sequence( - rdParser.oneOrMore(spacesBreaks()), + rdParser.oneOrMore("ordered_choise_args", + rdParser.sequence("ordered_choise_arg", + rdParser.oneOrMore("spaces",spacesBreaks()), rdParser.parseString("/"), - rdParser.oneOrMore(spacesBreaks()), + rdParser.oneOrMore("spaces",spacesBreaks()), parsingSubExpression() ) ) @@ -156,21 +158,9 @@ private Executable parsingOrderedChoice() { } private Executable parsingSubExpression() { - return rdParser.orderedChoise( - parsingNot(), - parsingAnd(), - parsingOptional(), - parsingOneOrMore(), - parsingZeroOrMore(), - parsingGroup(), - parsingAtomicExpression() + return rdParser.sequence("sub_expression", - ); - -/* - return rdParser.sequence( - - rdParser.zeroOrMore(rdParser.sequence( + rdParser.zeroOrMore(rdParser.sequence("tags", tag(), rdParser.parseString(":") @@ -186,12 +176,12 @@ private Executable parsingSubExpression() { ) ); - */ + } private Executable tag() { - return rdParser.sequence( + return rdParser.sequence("tag_name", rdParser.parseRegexp("[a-zA-Z_]"), rdParser.zeroOrMore( rdParser.parseRegexp("[a-zA-Z0-9_]")) ); @@ -199,7 +189,7 @@ private Executable tag() { private Executable parsingGroup() { - return rdParser.sequence( + return rdParser.sequence("group", rdParser.parseString("("), rdParser.zeroOrMore(spacesBreaks()), rdParser.rec(this), @@ -227,9 +217,9 @@ private Executable parsingRuleCall() { } private Executable parseString() { - return rdParser.sequence( + return rdParser.sequence("string", rdParser.parseString("\""), - rdParser.oneOrMore(rdParser.orderedChoise( + rdParser.oneOrMore("string",rdParser.orderedChoise( rdParser.parseString("\\\\"), rdParser.parseString("\\\""), rdParser.parseRegexp("[^\"]") @@ -240,10 +230,10 @@ private Executable parseString() { private Executable parseRegex() { return rdParser.orderedChoise( - rdParser.sequence( + rdParser.sequence("regex", rdParser.parseString("["), rdParser.optional(rdParser.parseString("^")), - rdParser.oneOrMore(rdParser.orderedChoise( + rdParser.oneOrMore("regex[]",rdParser.orderedChoise( rdParser.parseString("\\]"), rdParser.parseString("\\["), rdParser.parseRegexp("[^\\]]") @@ -256,7 +246,7 @@ private Executable parseRegex() { private Executable parsingNot(){ - return rdParser.sequence( + return rdParser.sequence("not", rdParser.parseString("!"), rdParser.orderedChoise( parsingGroup(), @@ -266,7 +256,7 @@ private Executable parsingNot(){ } private Executable parsingAnd(){ - return rdParser.sequence( + return rdParser.sequence("and", rdParser.parseString("&"), rdParser.orderedChoise( parsingGroup(), @@ -276,7 +266,7 @@ private Executable parsingAnd(){ } private Executable parsingOneOrMore(){ - return rdParser.sequence( + return rdParser.sequence("one_or_more", rdParser.orderedChoise( parsingGroup(), parsingAtomicExpression() @@ -287,7 +277,7 @@ private Executable parsingOneOrMore(){ private Executable parsingZeroOrMore(){ - return rdParser.sequence( + return rdParser.sequence("zero_or_more", rdParser.orderedChoise( parsingGroup(), parsingAtomicExpression() @@ -297,7 +287,7 @@ private Executable parsingZeroOrMore(){ } private Executable parsingOptional(){ - return rdParser.sequence( + return rdParser.sequence("optional", rdParser.orderedChoise( parsingGroup(), parsingAtomicExpression() diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java index 23fffaf..6322b09 100644 --- a/src/main/java/ru/dude/simplepeg/Starter.java +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -3,10 +3,7 @@ import ru.dude.simplepeg.entity.PegNode; import ru.dude.simplepeg.entity.State; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; +import java.io.*; import java.util.ArrayList; import java.util.List; @@ -15,7 +12,7 @@ */ public class Starter { - public static void main(String [] args)throws Exception{ + public static void main(String[] args) throws Exception { File f = new File("input.txt"); @@ -30,12 +27,15 @@ public static void main(String [] args)throws Exception{ printTree(res); } - public static void printTree(PegNode node){ + 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); - System.out.println(sb); + 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/PegNode.java b/src/main/java/ru/dude/simplepeg/entity/PegNode.java index face9e8..6e1fc40 100644 --- a/src/main/java/ru/dude/simplepeg/entity/PegNode.java +++ b/src/main/java/ru/dude/simplepeg/entity/PegNode.java @@ -21,6 +21,7 @@ public class PegNode{ ResultType resultType = ResultType.NONE; String error; + private String execName; public void appendChild(PegNode child) { childrens.add(child); @@ -40,6 +41,7 @@ public void appendChild(PegNode child) { public void toJson(StringBuilder sb,int level){ addtabs(sb,level).append("{\n"); + addtabs(sb,level+1).append("\"execName\" :\"").append(execName).append("\",\n"); addtabs(sb,level+1).append("\"type\" :\"").append(type).append("\",\n"); addtabs(sb,level+1).append("\"match\" :\"").append(match).append("\",\n"); addtabs(sb,level+1).append("\"startPosition\" :").append(startPosition).append(",\n"); @@ -131,4 +133,11 @@ public void setError(String error) { this.error = error; } + public void setExecName(String execName) { + this.execName = execName; + } + + public String getExecName() { + return execName; + } } From 166c60cfbcd4ade1ba9a665dc28e8c66e2c53fc4 Mon Sep 17 00:00:00 2001 From: dude Date: Sun, 27 May 2018 12:07:16 +0300 Subject: [PATCH 07/15] tests --- .../java/ru/dude/simplepeg/SpegParser.java | 11 ++ src/test/java/Tests.java | 101 ++++++++++++++++-- 2 files changed, 105 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 88c4ee1..ef58883 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -1,7 +1,10 @@ package ru.dude.simplepeg; +import ru.dude.simplepeg.entity.PegNode; import ru.dude.simplepeg.entity.State; +import java.io.InputStream; + /** * Parser for SimplePEG constructions *

@@ -18,6 +21,14 @@ public class SpegParser { rdParser = new RdParser(); } + public static PegNode createAndExec(InputStream grammarData){ + State state = new State(); + state.loadByStream(grammarData); + + SpegParser spegParser = new SpegParser(state); + return spegParser.peg().exec(state); + } + /** * All SPEG * @return diff --git a/src/test/java/Tests.java b/src/test/java/Tests.java index a895c70..881d402 100644 --- a/src/test/java/Tests.java +++ b/src/test/java/Tests.java @@ -1,29 +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 extends Assert{ - @Test + private void assertProcess(String input,ResultType expected,PegNode result){ + String message = "INPUT:\n"+input+"\nERROR:"+result.getError(); + assertEquals(message,expected,result.getResultType()); + } + + // @Test public void all(){ - one(); - two(); + headerAndSimpleRule(); + noRuleError(); + noLastSemicolonError(); + + oneRuleStrings(); + oneRuleRegexp(); + twoRulesSimple(); + twoRulesRegexp(); + manyRulesRegexp(); + + complicateTest_URL(); + } + + @Test + public void headerAndSimpleRule(){ + String input = "GRAMMAR simple rule-> \"aaaa\";"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.OK,res); + } + + @Test + public void noRuleError(){ + String input = "GRAMMAR simple;"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.ERROR,res); + } + + @Test + public void noLastSemicolonError(){ + String input = "GRAMMAR simple rule-> \"aaaa\""; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.ERROR,res); } + @Test + public void oneRuleStrings(){ + String input = "GRAMMAR one rule-> \"aaaa\" \"bb\" \"cccc\" \"zz\";"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.OK,res); + } @Test - public void one(){ - assertEquals(2, 2); + public void oneRuleRegexp(){ + String input = "GRAMMAR one rule-> \"XX\" [a-zA-Z0-9-]+ [^ #]*;"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.OK,res); } + @Test - public void two(){ - assertEquals(3, 3); + public void twoRulesSimple(){ + String input = "GRAMMAR duo rule_one-> \"XX\" rule_two; rule_two-> \"YY\";"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.OK,res); } + @Test + public void twoRulesRegexp(){ + String input = "GRAMMAR duo rule_one-> \"XX\" rule_two [^ #]*; rule_two-> \"YY\" [a-zA-Z0-9-]+;"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.OK,res); + } + + @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-]+;"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.OK,res); + } + //TODO: test for SEQUENCE, ONE_OR_MANY and others + + @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 -> \"#\" [^ ]*;"; + PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + assertProcess(input,ResultType.OK,res); + } } From 5aeaea90a46b6845d56f790dc4b1bf8a1715c72f Mon Sep 17 00:00:00 2001 From: dude Date: Sun, 27 May 2018 14:33:21 +0300 Subject: [PATCH 08/15] more tests --- src/main/java/ru/dude/simplepeg/RdParser.java | 47 ++++- .../java/ru/dude/simplepeg/SpegParser.java | 33 ++- src/main/java/ru/dude/simplepeg/Starter.java | 3 +- .../java/ru/dude/simplepeg/entity/State.java | 15 +- src/test/java/RdComplexTest.java | 54 +++++ src/test/java/RdParserTest.java | 197 ++++++++++++++++++ src/test/java/Tests.java | 30 +-- 7 files changed, 337 insertions(+), 42 deletions(-) create mode 100644 src/test/java/RdComplexTest.java create mode 100644 src/test/java/RdParserTest.java diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index 61f2374..2d0e392 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -73,6 +73,15 @@ public PegNode exec(State state) { }; } + /** + * Последовательно выполняет все 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() { @@ -112,7 +121,14 @@ public PegNode exec(State state) { } - public Executable orderedChoise(final Executable... execs) { + /** + * Последовательное выполнение. Первая, полнившаяся OK возвращается как результат. + * Если вернулись все пустые: возвращает EMPTY + * Если в результатах каждого exec был ERROR - возвращает ERROR + * @param execs + * @return + */ + public Executable orderedChoice(final Executable... execs) { return new Executable() { @Override @@ -138,7 +154,7 @@ public PegNode exec(State state) { return res; case ERROR: res.setResultType(ResultType.ERROR); - res.setError(" orderedChoise " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); + res.setError(" orderedChoice " + " lastPos = " + state.getPosition() + " unexpected " + state.atPos()); } } @@ -148,6 +164,13 @@ public PegNode exec(State state) { } + /** + * Выплняет exec, добавляя OK руезльутаты в child + * Возвращает OK если добавленых child > 0 иначе ERROR + * @param execName + * @param exec + * @return + */ public Executable oneOrMore(final String execName, final Executable exec) { return new Executable() { @@ -173,6 +196,12 @@ public PegNode exec(State state) { }; } + /** + * Выплняет exec, добавляя OK руезльутаты в child + * Возвращает OK если добавленых child > 0, EMPTY если child = 0 + * @param exec + * @return + */ public Executable zeroOrMore(final Executable exec) { return new Executable() { @@ -197,6 +226,11 @@ public PegNode exec(State state) { } + /** + * Возвращает OK если результат exec, иначе EMPTY + * @param exec + * @return + */ public Executable optional(final Executable exec) { return new Executable() { @@ -205,6 +239,10 @@ public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.OPTIONAL); +//TODO: ВОЗМОЖНА ОШИБКА: состояние изменится, при опионале ERROR и следующее правило не считается +//TODO:!!!!! state.copy() !!!! + + // state.copy(); PegNode pegNode = exec.exec(state); if (pegNode.getResultType().equals(ResultType.OK)) { res.setResultType(ResultType.OK); @@ -219,6 +257,10 @@ public PegNode exec(State state) { } + /** + * OK если достигнут конец строки данных + * @return + */ public Executable parseEndOfFile() { return new Executable() { @@ -229,6 +271,7 @@ public PegNode exec(State state) { 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 { diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index ef58883..30ff3d0 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -21,9 +21,8 @@ public class SpegParser { rdParser = new RdParser(); } - public static PegNode createAndExec(InputStream grammarData){ - State state = new State(); - state.loadByStream(grammarData); + public static PegNode createAndExec(InputStream grammarIS){ + State state = new State(grammarIS); SpegParser spegParser = new SpegParser(state); return spegParser.peg().exec(state); @@ -67,7 +66,7 @@ public Executable parsingHeader() { */ public Executable parsingBody() { return rdParser.oneOrMore("body", - rdParser.orderedChoise( + rdParser.orderedChoice( parsingRule(), rdParser.oneOrMore("spaces",spacesBreaks()) ) @@ -126,7 +125,7 @@ private Executable ruleName() { * @return */ public Executable ruleExpression() { - return rdParser.orderedChoise( + return rdParser.orderedChoice( parsingSequence(), parsingOrderedChoice(), parsingSubExpression() @@ -138,14 +137,14 @@ public Executable ruleExpression() { private Executable parsingSequence() { return rdParser.sequence("sequence", - rdParser.orderedChoise( + rdParser.orderedChoice( parsingOrderedChoice(), parsingSubExpression() ), rdParser.oneOrMore("sequence_args", rdParser.sequence("sequence_arg", rdParser.oneOrMore("spaces",spacesBreaks()), - rdParser.orderedChoise( + rdParser.orderedChoice( parsingOrderedChoice(), parsingSubExpression() ) @@ -176,7 +175,7 @@ private Executable parsingSubExpression() { rdParser.parseString(":") )), - rdParser.orderedChoise( + rdParser.orderedChoice( parsingNot(), parsingAnd(), parsingOptional(), @@ -210,7 +209,7 @@ private Executable parsingGroup() { } private Executable parsingAtomicExpression() { - return rdParser.orderedChoise( + return rdParser.orderedChoice( parseString(), parseRegex(), rdParser.parseEndOfFile(), @@ -230,7 +229,7 @@ private Executable parsingRuleCall() { private Executable parseString() { return rdParser.sequence("string", rdParser.parseString("\""), - rdParser.oneOrMore("string",rdParser.orderedChoise( + rdParser.oneOrMore("string",rdParser.orderedChoice( rdParser.parseString("\\\\"), rdParser.parseString("\\\""), rdParser.parseRegexp("[^\"]") @@ -240,11 +239,11 @@ private Executable parseString() { } private Executable parseRegex() { - return rdParser.orderedChoise( + return rdParser.orderedChoice( rdParser.sequence("regex", rdParser.parseString("["), rdParser.optional(rdParser.parseString("^")), - rdParser.oneOrMore("regex[]",rdParser.orderedChoise( + rdParser.oneOrMore("regex[]",rdParser.orderedChoice( rdParser.parseString("\\]"), rdParser.parseString("\\["), rdParser.parseRegexp("[^\\]]") @@ -259,7 +258,7 @@ private Executable parseRegex() { private Executable parsingNot(){ return rdParser.sequence("not", rdParser.parseString("!"), - rdParser.orderedChoise( + rdParser.orderedChoice( parsingGroup(), parsingAtomicExpression() ) @@ -269,7 +268,7 @@ private Executable parsingNot(){ private Executable parsingAnd(){ return rdParser.sequence("and", rdParser.parseString("&"), - rdParser.orderedChoise( + rdParser.orderedChoice( parsingGroup(), parsingAtomicExpression() ) @@ -278,7 +277,7 @@ private Executable parsingAnd(){ private Executable parsingOneOrMore(){ return rdParser.sequence("one_or_more", - rdParser.orderedChoise( + rdParser.orderedChoice( parsingGroup(), parsingAtomicExpression() ), @@ -289,7 +288,7 @@ private Executable parsingOneOrMore(){ private Executable parsingZeroOrMore(){ return rdParser.sequence("zero_or_more", - rdParser.orderedChoise( + rdParser.orderedChoice( parsingGroup(), parsingAtomicExpression() ), @@ -299,7 +298,7 @@ private Executable parsingZeroOrMore(){ private Executable parsingOptional(){ return rdParser.sequence("optional", - rdParser.orderedChoise( + rdParser.orderedChoice( parsingGroup(), parsingAtomicExpression() ), diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java index 6322b09..3d9712b 100644 --- a/src/main/java/ru/dude/simplepeg/Starter.java +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -16,8 +16,7 @@ public static void main(String[] args) throws Exception { File f = new File("input.txt"); - State state = new State(); - state.loadByStream(new FileInputStream(f)); + State state = new State(new FileInputStream(f)); System.out.println(state.getTextData()); diff --git a/src/main/java/ru/dude/simplepeg/entity/State.java b/src/main/java/ru/dude/simplepeg/entity/State.java index ff26958..4e389af 100644 --- a/src/main/java/ru/dude/simplepeg/entity/State.java +++ b/src/main/java/ru/dude/simplepeg/entity/State.java @@ -22,16 +22,27 @@ public class State { */ int position; - public State(){ + private State(){ textData = new StringBuilder(); position = 0; } + public State(InputStream is){ + textData = new StringBuilder(); + position = 0; + loadByStream(is); + } + + public State(String grammar){ + textData = new StringBuilder(grammar); + position = 0; + } + /** * Load data from input stream * @param is */ - public void loadByStream(InputStream is){ + private void loadByStream(InputStream is){ textData = new StringBuilder(); try (Reader r = new InputStreamReader(is, "UTF-8")){ diff --git a/src/test/java/RdComplexTest.java b/src/test/java/RdComplexTest.java new file mode 100644 index 0000000..43ef3b8 --- /dev/null +++ b/src/test/java/RdComplexTest.java @@ -0,0 +1,54 @@ +import org.junit.Assert; +import org.junit.Test; +import ru.dude.simplepeg.Executable; +import ru.dude.simplepeg.RdParser; +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. + * + * Сложные тесты для RdParser + */ +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(){ + RdParser rd = new RdParser(); + 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(){ + RdParser rd = new RdParser(); + 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); + } + + +} diff --git a/src/test/java/RdParserTest.java b/src/test/java/RdParserTest.java new file mode 100644 index 0000000..3a0a2fd --- /dev/null +++ b/src/test/java/RdParserTest.java @@ -0,0 +1,197 @@ +import org.junit.Assert; +import org.junit.Test; +import ru.dude.simplepeg.Executable; +import ru.dude.simplepeg.RdParser; +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 RdParserTest 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 RdParser().parseString(input); + assertProcess(grammar,input,executable,ResultType.OK); + } + + + @Test + public void simpleRegexp(){ + String grammar = "aaaazz;"; + String input = "[a-z]+"; + Executable executable = new RdParser().parseRegexp(input); + assertProcess(grammar,input,executable,ResultType.OK); + } + + @Test + public void eofTest(){ + String grammar = ""; + String input = "[___ANY___]"; + Executable executable = new RdParser().parseEndOfFile(); + assertProcess(grammar,input,executable,ResultType.OK); + } + + @Test + public void simpleSequenceOk(){ + String grammar = "aaaazzxxXx"; + String s1 = "aaaa"; + String s2 = "zz"; + String r3 = "[xX]+"; + RdParser rd = new RdParser(); + 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]+"; + RdParser rd = new RdParser(); + 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]+"; + RdParser rd = new RdParser(); + 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]+"; + RdParser rd = new RdParser(); + 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]+"; + RdParser rd = new RdParser(); + 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]+"; + RdParser rd = new RdParser(); + 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"; + RdParser rd = new RdParser(); + Executable executable = rd.oneOrMore("simpleOneOrMoreOK_test", + rd.parseString(s1) + ); + assertProcess("aaaazzxxXx_",s1,executable,ResultType.OK); + } + + @Test + public void simpleOneOrMoreError(){ + String s1 = "a"; + RdParser rd = new RdParser(); + Executable executable = rd.oneOrMore("simpleOneOrMoreError_test", + rd.parseString(s1) + ); + assertProcess("bbaaaazzxxXx_",s1,executable,ResultType.ERROR); + } + + @Test + public void simplZeroOrMoreOk(){ + String s1 = "a"; + RdParser rd = new RdParser(); + Executable executable = rd.zeroOrMore( + rd.parseString(s1) + ); + assertProcess("aaaazzxxXx_",s1,executable,ResultType.OK); + } + + @Test + public void simpleZeroOrMoreEmpty(){ + String s1 = "a"; + RdParser rd = new RdParser(); + Executable executable = rd.zeroOrMore( + rd.parseString(s1) + ); + assertProcess("bbaaaazzxxXx_",s1,executable,ResultType.EMPTY); + } + + @Test + public void simpleOptionalOk(){ + String s1 = "a"; + RdParser rd = new RdParser(); + Executable executable = rd.optional( + rd.parseString(s1) + ); + assertProcess("aaaazzxxXx_",s1,executable,ResultType.OK); + } + + @Test + public void simpleOptionalEmpty(){ + String s1 = "a"; + RdParser rd = new RdParser(); + Executable executable = rd.optional( + rd.parseString(s1) + ); + assertProcess("bbaaaazzxxXx_",s1,executable,ResultType.EMPTY); + } +} diff --git a/src/test/java/Tests.java b/src/test/java/Tests.java index 881d402..29ddf32 100644 --- a/src/test/java/Tests.java +++ b/src/test/java/Tests.java @@ -11,7 +11,8 @@ */ public class Tests extends Assert{ - private void assertProcess(String input,ResultType expected,PegNode result){ + private void assertProcess(String input,ResultType expected){ + PegNode result = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); String message = "INPUT:\n"+input+"\nERROR:"+result.getError(); assertEquals(message,expected,result.getResultType()); } @@ -34,51 +35,44 @@ public void all(){ @Test public void headerAndSimpleRule(){ String input = "GRAMMAR simple rule-> \"aaaa\";"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.OK,res); + assertProcess(input,ResultType.OK); } @Test public void noRuleError(){ String input = "GRAMMAR simple;"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.ERROR,res); + assertProcess(input,ResultType.ERROR); } @Test public void noLastSemicolonError(){ String input = "GRAMMAR simple rule-> \"aaaa\""; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.ERROR,res); + assertProcess(input,ResultType.ERROR); } @Test public void oneRuleStrings(){ String input = "GRAMMAR one rule-> \"aaaa\" \"bb\" \"cccc\" \"zz\";"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.OK,res); + assertProcess(input,ResultType.OK); } @Test public void oneRuleRegexp(){ String input = "GRAMMAR one rule-> \"XX\" [a-zA-Z0-9-]+ [^ #]*;"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.OK,res); + assertProcess(input,ResultType.OK); } @Test public void twoRulesSimple(){ String input = "GRAMMAR duo rule_one-> \"XX\" rule_two; rule_two-> \"YY\";"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.OK,res); + assertProcess(input,ResultType.OK); } @Test public void twoRulesRegexp(){ String input = "GRAMMAR duo rule_one-> \"XX\" rule_two [^ #]*; rule_two-> \"YY\" [a-zA-Z0-9-]+;"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.OK,res); + assertProcess(input,ResultType.OK); } @Test @@ -89,8 +83,7 @@ public void manyRulesRegexp(){ "r_two-> [^ #]*;\n" + "r_three-> \"YY\";\n" + "r_four-> \"ZZ\" [a-zA-Z0-9-]+;"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.OK,res); + assertProcess(input,ResultType.OK); } @@ -110,7 +103,6 @@ public void complicateTest_URL(){ "pathname -> \"/\" [^ ?]*;\n" + "search -> (\"?\" [^ #]*)?;\n" + "hash -> \"#\" [^ ]*;"; - PegNode res = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); - assertProcess(input,ResultType.OK,res); + assertProcess(input,ResultType.OK); } } From 5364992d25d62e3bd869a1ff0aa057c3804b0d22 Mon Sep 17 00:00:00 2001 From: dude Date: Sun, 27 May 2018 16:16:06 +0300 Subject: [PATCH 09/15] more tests and fixes --- src/main/java/ru/dude/simplepeg/RdParser.java | 27 +++++--- src/test/java/RdComplexTest.java | 67 ++++++++++++++----- src/test/java/Tests.java | 4 -- 3 files changed, 69 insertions(+), 29 deletions(-) diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index 2d0e392..f4dc913 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -124,7 +124,7 @@ public PegNode exec(State state) { /** * Последовательное выполнение. Первая, полнившаяся OK возвращается как результат. * Если вернулись все пустые: возвращает EMPTY - * Если в результатах каждого exec был ERROR - возвращает ERROR + * Если в результатах exec были ERROR или EMPTY - возвращает ERROR * @param execs * @return */ @@ -136,6 +136,8 @@ public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.ORDERED_CHOICE); + boolean hasEmpty = false; + boolean hasError = false; for (Executable exec : execs) { State statecp = state.copy(); @@ -150,12 +152,23 @@ public PegNode exec(State state) { return res; case EMPTY: res.setResultType(ResultType.EMPTY); - res.setError(""); - return res; + 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; @@ -239,14 +252,12 @@ public PegNode exec(State state) { PegNode res = new PegNode(); res.setType(SpegTypes.OPTIONAL); -//TODO: ВОЗМОЖНА ОШИБКА: состояние изменится, при опионале ERROR и следующее правило не считается -//TODO:!!!!! state.copy() !!!! - - // state.copy(); - PegNode pegNode = exec.exec(state); + 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); } diff --git a/src/test/java/RdComplexTest.java b/src/test/java/RdComplexTest.java index 43ef3b8..9a28afb 100644 --- a/src/test/java/RdComplexTest.java +++ b/src/test/java/RdComplexTest.java @@ -8,46 +8,79 @@ /** * Created by dude on 27.05.2018. - * + *

* Сложные тесты для RdParser */ public class RdComplexTest extends Assert { - private void assertProcess(String grammar, String input, Executable executable, ResultType resultType){ + 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()); + String message = "GRAMMAR:\n" + grammar + "\nINPUT:\n" + input + "\nERROR:" + result.getError(); + assertEquals(message, resultType, result.getResultType()); } @Test - public void sequencesAndOneZeroMore(){ + public void sequencesAndOneZeroMore() { RdParser rd = new RdParser(); - Executable executable = rd.sequence("test_sequence", - rd.oneOrMore("",rd.parseString("a")), - rd.oneOrMore("",rd.parseString("b")), + 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")) + rd.oneOrMore("", rd.parseString("e")) ); - assertProcess("aabbccddee","abcdXde",executable,ResultType.OK); - assertProcess("aabbccccddee","abcdXde",executable,ResultType.OK); - assertProcess("aabbcccddee","abcdXde",executable,ResultType.ERROR); + assertProcess("aabbccddee", "abcdXde", executable, ResultType.OK); + assertProcess("aabbccccddee", "abcdXde", executable, ResultType.OK); + assertProcess("aabbcccddee", "abcdXde", executable, ResultType.ERROR); } @Test - public void sequencesAndOptional(){ + public void sequencesAndOptional() { RdParser rd = new RdParser(); - Executable executable = rd.sequence("test_sequence", + 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); + assertProcess("aaaabbbbcccc", "aaaabbbbXcccc", executable, ResultType.OK); + assertProcess("aaaacccc", "aaaabbbbXcccc", executable, ResultType.OK); + assertProcess("aaaabbbXcccc", "aaaabbbbXcccc", executable, ResultType.OK); + } + + @Test + public void oneOrManyAndOptional() { + RdParser rd = new RdParser(); + 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() { + RdParser rd = new RdParser(); + 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/Tests.java b/src/test/java/Tests.java index 29ddf32..13c8c15 100644 --- a/src/test/java/Tests.java +++ b/src/test/java/Tests.java @@ -86,10 +86,6 @@ public void manyRulesRegexp(){ assertProcess(input,ResultType.OK); } - - //TODO: test for SEQUENCE, ONE_OR_MANY and others - - @Test public void complicateTest_URL(){ String input = "GRAMMAR url\n" + From a479efc987dae404edc43705baae40e18a580d57 Mon Sep 17 00:00:00 2001 From: dude Date: Sun, 27 May 2018 22:50:43 +0300 Subject: [PATCH 10/15] first try to check text --- src/main/java/ru/dude/simplepeg/RdParser.java | 10 ++- .../java/ru/dude/simplepeg/RuleProcessor.java | 63 +++++++++++++++ .../java/ru/dude/simplepeg/SpegParser.java | 77 +++++++++++++------ .../ru/dude/simplepeg/entity/CheckResult.java | 34 ++++++++ .../ru/dude/simplepeg/entity/PegNode.java | 21 ++++- src/test/java/RdComplexTest.java | 8 +- src/test/java/RdParserTest.java | 10 +-- src/test/java/RuleTest.java | 28 +++++++ src/test/java/Tests.java | 2 +- 9 files changed, 213 insertions(+), 40 deletions(-) create mode 100644 src/main/java/ru/dude/simplepeg/RuleProcessor.java create mode 100644 src/main/java/ru/dude/simplepeg/entity/CheckResult.java create mode 100644 src/test/java/RuleTest.java diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index f4dc913..3f8cf28 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -128,13 +128,14 @@ public PegNode exec(State state) { * @param execs * @return */ - public Executable orderedChoice(final Executable... execs) { + 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; @@ -212,16 +213,19 @@ public PegNode exec(State state) { /** * Выплняет exec, добавляя OK руезльутаты в child * Возвращает OK если добавленых child > 0, EMPTY если child = 0 + * + * @param execName * @param exec * @return */ - public Executable zeroOrMore(final Executable exec) { + 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)) { @@ -312,4 +316,6 @@ public PegNode exec(State 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..7e29ee7 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/RuleProcessor.java @@ -0,0 +1,63 @@ +package ru.dude.simplepeg; + +import ru.dude.simplepeg.entity.CheckResult; +import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.State; + +import java.util.HashMap; +import java.util.Map; + +public class RuleProcessor { + + Map rules; + + PegNode firstRule; + + RdParser rdParser; + + public RuleProcessor(PegNode grammarTree) { + rdParser = new RdParser(); + selectRules(grammarTree); + } + + private void selectRules(PegNode grammarTree) { + rules = new HashMap<>(); + firstRule = null; + + PegNode lines = grammarTree.child("body").child("rule_lines"); + for (PegNode ch : lines.getChildrens()) { + if (ch.getExecName().equals("rule")){ + String ruleName = ch.child("rule_name").getMatch().toString(); + PegNode ruleExpression = ch.child("rule_expression"); + if (firstRule == null){ + firstRule = ruleExpression; + } + rules.put(ruleName,ruleExpression); + } + } + } + + public CheckResult check(String text) { + if (firstRule == null || rules == null || rules.size() == 0) { + return CheckResult.error("rules init failure"); + } + + State textState = new State(text); + + executeRule(firstRule,textState); + + + return null; + + } + + private PegNode executeRule(PegNode rule, State state){ + + SpegParser spegParser = new SpegParser(state); + + Executable exec = spegParser.execRule(rule); + PegNode res = exec.exec(state); + return res; + } + +} diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 30ff3d0..3138848 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -21,6 +21,14 @@ public class SpegParser { rdParser = new RdParser(); } + + public static PegNode createAndExec(String grammar){ + State state = new State(grammar); + + SpegParser spegParser = new SpegParser(state); + return spegParser.peg().exec(state); + } + public static PegNode createAndExec(InputStream grammarIS){ State state = new State(grammarIS); @@ -37,7 +45,7 @@ public Executable peg() { //return parsingBody(); return rdParser.sequence("peg_parser", - rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), parsingHeader(), rdParser.oneOrMore("spaces",spacesBreaks()), parsingBody(), @@ -66,7 +74,7 @@ public Executable parsingHeader() { */ public Executable parsingBody() { return rdParser.oneOrMore("body", - rdParser.orderedChoice( + rdParser.orderedChoice("rule_lines", parsingRule(), rdParser.oneOrMore("spaces",spacesBreaks()) ) @@ -94,13 +102,13 @@ private Executable parsingRule() { return rdParser.sequence("rule", ruleName(), - rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore("spaces",spacesBreaks()), rdParser.parseString("->"), - rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), ruleExpression(), - rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), rdParser.parseString(";"), - rdParser.zeroOrMore(spacesBreaks()) + rdParser.zeroOrMore("spaces", spacesBreaks()) ); } @@ -114,7 +122,7 @@ private Executable parsingRule() { private Executable ruleName() { return rdParser.sequence("rule_name", rdParser.parseRegexp("[a-zA-Z_]"), - rdParser.zeroOrMore(rdParser.parseRegexp("[a-zA-Z0-9_]")) + rdParser.zeroOrMore("", rdParser.parseRegexp("[a-zA-Z0-9_]")) ); } @@ -125,7 +133,7 @@ private Executable ruleName() { * @return */ public Executable ruleExpression() { - return rdParser.orderedChoice( + return rdParser.orderedChoice("rule_expression", parsingSequence(), parsingOrderedChoice(), parsingSubExpression() @@ -138,14 +146,14 @@ private Executable parsingSequence() { return rdParser.sequence("sequence", rdParser.orderedChoice( - parsingOrderedChoice(), + "", parsingOrderedChoice(), parsingSubExpression() ), rdParser.oneOrMore("sequence_args", rdParser.sequence("sequence_arg", rdParser.oneOrMore("spaces",spacesBreaks()), rdParser.orderedChoice( - parsingOrderedChoice(), + "", parsingOrderedChoice(), parsingSubExpression() ) ) @@ -170,13 +178,13 @@ private Executable parsingOrderedChoice() { private Executable parsingSubExpression() { return rdParser.sequence("sub_expression", - rdParser.zeroOrMore(rdParser.sequence("tags", + rdParser.zeroOrMore("", rdParser.sequence("tags", tag(), rdParser.parseString(":") )), rdParser.orderedChoice( - parsingNot(), + "", parsingNot(), parsingAnd(), parsingOptional(), parsingOneOrMore(), @@ -193,7 +201,7 @@ private Executable parsingSubExpression() { private Executable tag() { return rdParser.sequence("tag_name", rdParser.parseRegexp("[a-zA-Z_]"), - rdParser.zeroOrMore( rdParser.parseRegexp("[a-zA-Z0-9_]")) + rdParser.zeroOrMore("", rdParser.parseRegexp("[a-zA-Z0-9_]")) ); } @@ -201,16 +209,16 @@ private Executable tag() { private Executable parsingGroup() { return rdParser.sequence("group", rdParser.parseString("("), - rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), rdParser.rec(this), - rdParser.zeroOrMore(spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), rdParser.parseString(")") ); } private Executable parsingAtomicExpression() { return rdParser.orderedChoice( - parseString(), + "", parseString(), parseRegex(), rdParser.parseEndOfFile(), parsingRuleCall() @@ -230,7 +238,7 @@ private Executable parseString() { return rdParser.sequence("string", rdParser.parseString("\""), rdParser.oneOrMore("string",rdParser.orderedChoice( - rdParser.parseString("\\\\"), + "", rdParser.parseString("\\\\"), rdParser.parseString("\\\""), rdParser.parseRegexp("[^\"]") )), @@ -240,11 +248,11 @@ private Executable parseString() { private Executable parseRegex() { return rdParser.orderedChoice( - rdParser.sequence("regex", + "", rdParser.sequence("regex", rdParser.parseString("["), rdParser.optional(rdParser.parseString("^")), rdParser.oneOrMore("regex[]",rdParser.orderedChoice( - rdParser.parseString("\\]"), + "", rdParser.parseString("\\]"), rdParser.parseString("\\["), rdParser.parseRegexp("[^\\]]") )), @@ -259,7 +267,7 @@ private Executable parsingNot(){ return rdParser.sequence("not", rdParser.parseString("!"), rdParser.orderedChoice( - parsingGroup(), + "", parsingGroup(), parsingAtomicExpression() ) ); @@ -269,7 +277,7 @@ private Executable parsingAnd(){ return rdParser.sequence("and", rdParser.parseString("&"), rdParser.orderedChoice( - parsingGroup(), + "", parsingGroup(), parsingAtomicExpression() ) ); @@ -278,18 +286,18 @@ private Executable parsingAnd(){ private Executable parsingOneOrMore(){ return rdParser.sequence("one_or_more", rdParser.orderedChoice( - parsingGroup(), + "", parsingGroup(), parsingAtomicExpression() ), rdParser.parseString("+") ); - } + } private Executable parsingZeroOrMore(){ return rdParser.sequence("zero_or_more", rdParser.orderedChoice( - parsingGroup(), + "", parsingGroup(), parsingAtomicExpression() ), rdParser.parseString("*") @@ -299,11 +307,30 @@ private Executable parsingZeroOrMore(){ private Executable parsingOptional(){ return rdParser.sequence("optional", rdParser.orderedChoice( - parsingGroup(), + "", parsingGroup(), parsingAtomicExpression() ), rdParser.parseString("?") ); } + + public Executable execRule(final PegNode rule) { + return new Executable() { + + @Override + public PegNode exec(State state) { + + + switch (rule.getType()) { + case STRING: return parseString().exec(state); + case REGEXP: return parseRegex().exec(state); + case ORDERED_CHOICE: return parsingOrderedChoice().exec(state); + + } + + return null; + } + }; + } } 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..2b306f2 --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/entity/CheckResult.java @@ -0,0 +1,34 @@ +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; + } + +} diff --git a/src/main/java/ru/dude/simplepeg/entity/PegNode.java b/src/main/java/ru/dude/simplepeg/entity/PegNode.java index 6e1fc40..c998b72 100644 --- a/src/main/java/ru/dude/simplepeg/entity/PegNode.java +++ b/src/main/java/ru/dude/simplepeg/entity/PegNode.java @@ -1,8 +1,5 @@ package ru.dude.simplepeg.entity; -import ru.dude.simplepeg.Executable; -import ru.dude.simplepeg.ParseInputException; - import java.util.ArrayList; import java.util.List; @@ -12,6 +9,10 @@ * 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; @@ -23,6 +24,10 @@ public class PegNode{ String error; private String execName; + public PegNode(){ + id = nextId++; + } + public void appendChild(PegNode child) { childrens.add(child); match.append(child.match); @@ -41,6 +46,7 @@ public void appendChild(PegNode child) { public void toJson(StringBuilder sb,int level){ addtabs(sb,level).append("{\n"); + addtabs(sb,level+1).append("\"id\" :\"").append(id).append("\",\n"); addtabs(sb,level+1).append("\"execName\" :\"").append(execName).append("\",\n"); addtabs(sb,level+1).append("\"type\" :\"").append(type).append("\",\n"); addtabs(sb,level+1).append("\"match\" :\"").append(match).append("\",\n"); @@ -64,6 +70,15 @@ private StringBuilder addtabs(StringBuilder sb,int level){ return sb; } + public PegNode child(String execName){ + + for (PegNode ch : childrens) { + if (ch.getExecName().equals(execName)){ + return ch; + } + } + return null; + } public SpegTypes getType() { diff --git a/src/test/java/RdComplexTest.java b/src/test/java/RdComplexTest.java index 9a28afb..a1c764d 100644 --- a/src/test/java/RdComplexTest.java +++ b/src/test/java/RdComplexTest.java @@ -26,9 +26,9 @@ public void sequencesAndOneZeroMore() { 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.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); @@ -55,7 +55,7 @@ public void oneOrManyAndOptional() { RdParser rd = new RdParser(); Executable executable = rd.oneOrMore("test_oneOrMany", rd.orderedChoice( - rd.optional(rd.parseString("bxy")), + "", rd.optional(rd.parseString("bxy")), rd.optional(rd.parseString("bxz")) ) ); diff --git a/src/test/java/RdParserTest.java b/src/test/java/RdParserTest.java index 3a0a2fd..204d190 100644 --- a/src/test/java/RdParserTest.java +++ b/src/test/java/RdParserTest.java @@ -98,7 +98,7 @@ public void simpleOrderedChoiceOk(){ String r3 = "[xX]+"; RdParser rd = new RdParser(); Executable executable = rd.orderedChoice( - rd.parseString(s1), + "", rd.parseString(s1), rd.parseString(s2), rd.parseRegexp(r3) ); @@ -114,7 +114,7 @@ public void simpleOrderedChoiceEmpty(){ String r3 = "[0-9]+"; RdParser rd = new RdParser(); Executable executable = rd.orderedChoice( - rd.optional(rd.parseString(s1)), + "", rd.optional(rd.parseString(s1)), rd.optional(rd.parseString(s2)), rd.optional(rd.parseRegexp(r3)) ); @@ -128,7 +128,7 @@ public void simpleOrderedChoiceError(){ String r3 = "[0-9]+"; RdParser rd = new RdParser(); Executable executable = rd.orderedChoice( - rd.parseString(s1), + "", rd.parseString(s1), rd.parseString(s2), rd.parseRegexp(r3) ); @@ -160,7 +160,7 @@ public void simplZeroOrMoreOk(){ String s1 = "a"; RdParser rd = new RdParser(); Executable executable = rd.zeroOrMore( - rd.parseString(s1) + "", rd.parseString(s1) ); assertProcess("aaaazzxxXx_",s1,executable,ResultType.OK); } @@ -170,7 +170,7 @@ public void simpleZeroOrMoreEmpty(){ String s1 = "a"; RdParser rd = new RdParser(); Executable executable = rd.zeroOrMore( - rd.parseString(s1) + "", 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..7434d4e --- /dev/null +++ b/src/test/java/RuleTest.java @@ -0,0 +1,28 @@ +import org.junit.Assert; +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 simpleRule(){ + 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); + } + +} diff --git a/src/test/java/Tests.java b/src/test/java/Tests.java index 13c8c15..3c49120 100644 --- a/src/test/java/Tests.java +++ b/src/test/java/Tests.java @@ -12,7 +12,7 @@ public class Tests extends Assert{ private void assertProcess(String input,ResultType expected){ - PegNode result = SpegParser.createAndExec(new ByteArrayInputStream(input.getBytes())); + PegNode result = SpegParser.createAndExec(input); String message = "INPUT:\n"+input+"\nERROR:"+result.getError(); assertEquals(message,expected,result.getResultType()); } From 9d78b6a4a684daf48d279f6ad8e46f3f813dbc08 Mon Sep 17 00:00:00 2001 From: dude Date: Thu, 9 Aug 2018 20:14:41 +0300 Subject: [PATCH 11/15] worker 1 --- pom.xml | 32 ++ src/main/java/ru/dude/simplepeg/RdParser.java | 50 ++- .../java/ru/dude/simplepeg/RuleProcessor.java | 28 +- .../java/ru/dude/simplepeg/SpegParser.java | 130 +++++-- .../ru/dude/simplepeg/entity/SpegTypes.java | 2 +- src/test/java/RuleTest.java | 359 +++++++++++++++++- src/test/java/Tests.java | 12 + 7 files changed, 564 insertions(+), 49 deletions(-) create mode 100644 pom.xml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..804eda0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + ru.dude + SimplePEG-Java + 1.0-SNAPSHOT + + + + junit + junit + RELEASE + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.7 + 1.7 + + + + + \ No newline at end of file diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdParser.java index 3f8cf28..481bb19 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdParser.java @@ -78,6 +78,7 @@ public PegNode exec(State state) { * Возвращает ERROR, если вернулся хотя бы один ERROR * EMPTY - если все exec вернули EMPTY * OK - если все exec вернули OK(минимум один) или EMPTY + * * @param execName * @param execs * @return @@ -106,7 +107,7 @@ public PegNode exec(State state) { break; case ERROR: res.setResultType(ResultType.ERROR); - res.setError(" sequence "+execName + " lastPos = " + stateCp.getPosition() + " unexpected " + stateCp.atPos()); + res.setError(" sequence " + execName + " lastPos = " + stateCp.getPosition() + " unexpected " + stateCp.atPos()); state.setPosition(stateCp.getPosition()); return res; } @@ -125,6 +126,7 @@ public PegNode exec(State state) { * Последовательное выполнение. Первая, полнившаяся OK возвращается как результат. * Если вернулись все пустые: возвращает EMPTY * Если в результатах exec были ERROR или EMPTY - возвращает ERROR + * * @param execs * @return */ @@ -165,7 +167,7 @@ public PegNode exec(State state) { } } - if (hasError){ + if (hasError) { res.setResultType(ResultType.ERROR); } else { if (hasEmpty) { @@ -181,6 +183,7 @@ public PegNode exec(State state) { /** * Выплняет exec, добавляя OK руезльутаты в child * Возвращает OK если добавленых child > 0 иначе ERROR + * * @param execName * @param exec * @return @@ -245,6 +248,7 @@ public PegNode exec(State state) { /** * Возвращает OK если результат exec, иначе EMPTY + * * @param exec * @return */ @@ -272,8 +276,46 @@ public PegNode exec(State state) { } + /** + * Предикат 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() { @@ -299,7 +341,6 @@ public PegNode exec(State state) { } /** - * * @param spParser * @return */ @@ -315,7 +356,4 @@ public PegNode exec(State state) { } - - - } diff --git a/src/main/java/ru/dude/simplepeg/RuleProcessor.java b/src/main/java/ru/dude/simplepeg/RuleProcessor.java index 7e29ee7..b46e7f1 100644 --- a/src/main/java/ru/dude/simplepeg/RuleProcessor.java +++ b/src/main/java/ru/dude/simplepeg/RuleProcessor.java @@ -2,6 +2,7 @@ import ru.dude.simplepeg.entity.CheckResult; import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.ResultType; import ru.dude.simplepeg.entity.State; import java.util.HashMap; @@ -24,11 +25,12 @@ private void selectRules(PegNode grammarTree) { rules = new HashMap<>(); firstRule = null; - PegNode lines = grammarTree.child("body").child("rule_lines"); + PegNode lines = grammarTree.child("body"); for (PegNode ch : lines.getChildrens()) { - if (ch.getExecName().equals("rule")){ - String ruleName = ch.child("rule_name").getMatch().toString(); - PegNode ruleExpression = ch.child("rule_expression"); + if (ch.getExecName().equals("rule_lines")){ + PegNode rule = ch.child("rule"); + String ruleName = rule.child("rule_name").getMatch().toString(); + PegNode ruleExpression = rule.child("rule_expression"); if (firstRule == null){ firstRule = ruleExpression; } @@ -44,20 +46,28 @@ public CheckResult check(String text) { State textState = new State(text); - executeRule(firstRule,textState); + PegNode resultExec = executeRule(firstRule, textState); + if (resultExec.getResultType() == ResultType.OK){ + return CheckResult.ok(); + } - return null; - + return CheckResult.error(resultExec.getError()); } private PegNode executeRule(PegNode rule, State state){ - SpegParser spegParser = new SpegParser(state); + SpegParser spegParser = new SpegParser(state,rules); + + - Executable exec = spegParser.execRule(rule); + Executable exec = spegParser.applyRule(rule); PegNode res = exec.exec(state); return res; } + + + + } diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 3138848..777f07b 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -1,9 +1,14 @@ package ru.dude.simplepeg; import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.ResultType; +import ru.dude.simplepeg.entity.SpegTypes; import ru.dude.simplepeg.entity.State; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * Parser for SimplePEG constructions @@ -12,24 +17,30 @@ */ public class SpegParser { + private Map rules; State state; RdParser rdParser; - SpegParser(State state) { + public SpegParser(State state) { this.state = state; - rdParser = new RdParser(); + this.rdParser = new RdParser(); + } + + public SpegParser(State state, Map rules) { + this(state); + this.rules = rules; } - public static PegNode createAndExec(String grammar){ + public static PegNode createAndExec(String grammar) { State state = new State(grammar); SpegParser spegParser = new SpegParser(state); return spegParser.peg().exec(state); } - public static PegNode createAndExec(InputStream grammarIS){ + public static PegNode createAndExec(InputStream grammarIS) { State state = new State(grammarIS); SpegParser spegParser = new SpegParser(state); @@ -38,6 +49,7 @@ public static PegNode createAndExec(InputStream grammarIS){ /** * All SPEG + * * @return */ public Executable peg() { @@ -47,7 +59,7 @@ public Executable peg() { return rdParser.sequence("peg_parser", rdParser.zeroOrMore("spaces", spacesBreaks()), parsingHeader(), - rdParser.oneOrMore("spaces",spacesBreaks()), + rdParser.oneOrMore("spaces", spacesBreaks()), parsingBody(), rdParser.parseEndOfFile() ); @@ -57,32 +69,35 @@ public Executable peg() { /** * HEADER only + * * @return */ public Executable parsingHeader() { return rdParser.sequence("header", rdParser.parseString("GRAMMAR"), - rdParser.oneOrMore("spaces",spacesBreaks()), - rdParser.oneOrMore("rulenames",ruleName()) + rdParser.oneOrMore("spaces", spacesBreaks()), + rdParser.oneOrMore("rulenames", ruleName()) ); } /** * BODy only + * * @return */ public Executable parsingBody() { return rdParser.oneOrMore("body", rdParser.orderedChoice("rule_lines", parsingRule(), - rdParser.oneOrMore("spaces",spacesBreaks()) + rdParser.oneOrMore("spaces", spacesBreaks()) ) ); } /** * Space symbols filter + * * @return */ private Executable spacesBreaks() { @@ -90,19 +105,18 @@ private Executable spacesBreaks() { } - - /** * Parce rule - * + *

* TODO: (not ready) + * * @return */ private Executable parsingRule() { return rdParser.sequence("rule", ruleName(), - rdParser.zeroOrMore("spaces",spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), rdParser.parseString("->"), rdParser.zeroOrMore("spaces", spacesBreaks()), ruleExpression(), @@ -115,8 +129,9 @@ private Executable parsingRule() { /** * Parse rule name - * + *

* js parsing_rule_name + * * @return */ private Executable ruleName() { @@ -128,8 +143,9 @@ private Executable ruleName() { /** * Parse rule Expression - * + *

* js parsing_expression + * * @return */ public Executable ruleExpression() { @@ -141,7 +157,6 @@ public Executable ruleExpression() { } - private Executable parsingSequence() { return rdParser.sequence("sequence", @@ -151,7 +166,7 @@ private Executable parsingSequence() { ), rdParser.oneOrMore("sequence_args", rdParser.sequence("sequence_arg", - rdParser.oneOrMore("spaces",spacesBreaks()), + rdParser.oneOrMore("spaces", spacesBreaks()), rdParser.orderedChoice( "", parsingOrderedChoice(), parsingSubExpression() @@ -166,9 +181,9 @@ private Executable parsingOrderedChoice() { parsingSubExpression(), rdParser.oneOrMore("ordered_choise_args", rdParser.sequence("ordered_choise_arg", - rdParser.oneOrMore("spaces",spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), rdParser.parseString("/"), - rdParser.oneOrMore("spaces",spacesBreaks()), + rdParser.zeroOrMore("spaces", spacesBreaks()), parsingSubExpression() ) ) @@ -228,6 +243,7 @@ private Executable parsingAtomicExpression() { /** * js parsing_rule_call() + * * @return */ private Executable parsingRuleCall() { @@ -237,7 +253,7 @@ private Executable parsingRuleCall() { private Executable parseString() { return rdParser.sequence("string", rdParser.parseString("\""), - rdParser.oneOrMore("string",rdParser.orderedChoice( + rdParser.oneOrMore("string", rdParser.orderedChoice( "", rdParser.parseString("\\\\"), rdParser.parseString("\\\""), rdParser.parseRegexp("[^\"]") @@ -251,7 +267,7 @@ private Executable parseRegex() { "", rdParser.sequence("regex", rdParser.parseString("["), rdParser.optional(rdParser.parseString("^")), - rdParser.oneOrMore("regex[]",rdParser.orderedChoice( + rdParser.oneOrMore("regex[]", rdParser.orderedChoice( "", rdParser.parseString("\\]"), rdParser.parseString("\\["), rdParser.parseRegexp("[^\\]]") @@ -263,7 +279,7 @@ private Executable parseRegex() { } - private Executable parsingNot(){ + private Executable parsingNot() { return rdParser.sequence("not", rdParser.parseString("!"), rdParser.orderedChoice( @@ -273,7 +289,7 @@ private Executable parsingNot(){ ); } - private Executable parsingAnd(){ + private Executable parsingAnd() { return rdParser.sequence("and", rdParser.parseString("&"), rdParser.orderedChoice( @@ -283,7 +299,7 @@ private Executable parsingAnd(){ ); } - private Executable parsingOneOrMore(){ + private Executable parsingOneOrMore() { return rdParser.sequence("one_or_more", rdParser.orderedChoice( "", parsingGroup(), @@ -291,10 +307,10 @@ private Executable parsingOneOrMore(){ ), rdParser.parseString("+") ); - } + } - private Executable parsingZeroOrMore(){ + private Executable parsingZeroOrMore() { return rdParser.sequence("zero_or_more", rdParser.orderedChoice( "", parsingGroup(), @@ -304,7 +320,7 @@ private Executable parsingZeroOrMore(){ ); } - private Executable parsingOptional(){ + private Executable parsingOptional() { return rdParser.sequence("optional", rdParser.orderedChoice( "", parsingGroup(), @@ -315,21 +331,71 @@ private Executable parsingOptional(){ } - public Executable execRule(final PegNode rule) { + public Executable applyRule(final PegNode rule) { return new Executable() { @Override public PegNode exec(State state) { - switch (rule.getType()) { - case STRING: return parseString().exec(state); - case REGEXP: return parseRegex().exec(state); - case ORDERED_CHOICE: return parsingOrderedChoice().exec(state); + Executable[] childExecs = null; + if (rule.getChildrens() != null) { + List childExecsList = new ArrayList<>(); + for (PegNode childNode : rule.getChildrens()) { + childExecsList.add(applyRule(childNode)); + } + childExecs = childExecsList.toArray(new Executable[0]); } - return null; + String fullStr = rule.getMatch().toString(); + String unQuotedStr = fullStr; + if (fullStr.length() > 1) { + unQuotedStr = fullStr.substring(1, fullStr.length() - 1); + } + + PegNode emptyRes = new PegNode(); + emptyRes.setResultType(ResultType.EMPTY); + + if (rule.getExecName() == null) { + return emptyRes; + } + + switch (rule.getExecName()) { + case "string": + return rdParser.parseString(unQuotedStr).exec(state); + case "regex": + return rdParser.parseRegexp(fullStr).exec(state); + case "sequence": + return rdParser.sequence("applySequence", childExecs).exec(state); + case "ordered_choise": + return rdParser.orderedChoice("applyOrderedChoise", childExecs).exec(state); + case "one_or_more": + return rdParser.oneOrMore("applyOneOrMore", childExecs[0]).exec(state); + case "zero_or_more": + return rdParser.zeroOrMore("applyZeroOrMore", childExecs[0]).exec(state); + case "not": + return rdParser.not(childExecs[1]).exec(state); + //case "and": //return rdParser.(childExecs[1]).exec(state); + case "optional": + return rdParser.optional(childExecs[0]).exec(state); + case "rule_expression": + default: + if (rules.containsKey(fullStr)) { + return applyRule(rules.get(fullStr)).exec(state); + } + + + if (childExecs.length == 0) { + return emptyRes; + } + + if (childExecs.length == 1) { + return childExecs[0].exec(state); + } + + return rdParser.sequence("deafultSequence", childExecs).exec(state); + } } }; } diff --git a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java index d71d10b..6cdfe63 100644 --- a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java +++ b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java @@ -12,5 +12,5 @@ public enum SpegTypes { REGEXP, STRING, OPTIONAL, - END_OF_FILE, + END_OF_FILE, NOT, } diff --git a/src/test/java/RuleTest.java b/src/test/java/RuleTest.java index 7434d4e..a2e4f2f 100644 --- a/src/test/java/RuleTest.java +++ b/src/test/java/RuleTest.java @@ -1,4 +1,5 @@ import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import ru.dude.simplepeg.RuleProcessor; import ru.dude.simplepeg.SpegParser; @@ -14,7 +15,7 @@ public class RuleTest extends Assert { @Test - public void simpleRule(){ + public void ruleString(){ String grammar = "GRAMMAR simple url-> \"aaaa\";"; String text = "aaaa"; @@ -25,4 +26,360 @@ public void simpleRule(){ 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 3c49120..4681d81 100644 --- a/src/test/java/Tests.java +++ b/src/test/java/Tests.java @@ -38,6 +38,18 @@ public void headerAndSimpleRule(){ 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;"; From fe0823cc7968690cf06d47aa23a41b4505743f5a Mon Sep 17 00:00:00 2001 From: dude Date: Sat, 11 Aug 2018 13:22:42 +0300 Subject: [PATCH 12/15] refactor1 --- .../java/ru/dude/simplepeg/Executable.java | 1 - .../dude/simplepeg/ParseInputException.java | 11 - .../{RdParser.java => RdExecutor.java} | 4 +- .../java/ru/dude/simplepeg/RuleProcessor.java | 88 ++++++- .../java/ru/dude/simplepeg/SpegParser.java | 237 +++++++----------- src/main/java/ru/dude/simplepeg/Starter.java | 28 ++- .../ru/dude/simplepeg/entity/CheckResult.java | 11 + .../ru/dude/simplepeg/entity/ResultType.java | 1 + .../ru/dude/simplepeg/entity/SpegTypes.java | 3 +- src/test/java/RdComplexTest.java | 12 +- ...{RdParserTest.java => RdExecutorTest.java} | 34 +-- 11 files changed, 224 insertions(+), 206 deletions(-) delete mode 100644 src/main/java/ru/dude/simplepeg/ParseInputException.java rename src/main/java/ru/dude/simplepeg/{RdParser.java => RdExecutor.java} (99%) rename src/test/java/{RdParserTest.java => RdExecutorTest.java} (87%) diff --git a/src/main/java/ru/dude/simplepeg/Executable.java b/src/main/java/ru/dude/simplepeg/Executable.java index 437c672..24bc966 100644 --- a/src/main/java/ru/dude/simplepeg/Executable.java +++ b/src/main/java/ru/dude/simplepeg/Executable.java @@ -12,7 +12,6 @@ public interface Executable { /** * Execute PEG expression * @return - * @throws ParseInputException */ PegNode exec(State state); } diff --git a/src/main/java/ru/dude/simplepeg/ParseInputException.java b/src/main/java/ru/dude/simplepeg/ParseInputException.java deleted file mode 100644 index 2eeeb31..0000000 --- a/src/main/java/ru/dude/simplepeg/ParseInputException.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.dude.simplepeg; - -/** - * Exception for errors - * - * Created by dude on 29.10.2017. - */ -public class ParseInputException extends Exception { - public ParseInputException(String message) { - } -} diff --git a/src/main/java/ru/dude/simplepeg/RdParser.java b/src/main/java/ru/dude/simplepeg/RdExecutor.java similarity index 99% rename from src/main/java/ru/dude/simplepeg/RdParser.java rename to src/main/java/ru/dude/simplepeg/RdExecutor.java index 481bb19..79fb53c 100644 --- a/src/main/java/ru/dude/simplepeg/RdParser.java +++ b/src/main/java/ru/dude/simplepeg/RdExecutor.java @@ -13,10 +13,10 @@ *

* Created by dude on 29.10.2017. */ -public class RdParser { +public class RdExecutor { - public RdParser() { + public RdExecutor() { } diff --git a/src/main/java/ru/dude/simplepeg/RuleProcessor.java b/src/main/java/ru/dude/simplepeg/RuleProcessor.java index b46e7f1..8d3aac9 100644 --- a/src/main/java/ru/dude/simplepeg/RuleProcessor.java +++ b/src/main/java/ru/dude/simplepeg/RuleProcessor.java @@ -5,19 +5,30 @@ import ru.dude.simplepeg.entity.ResultType; import ru.dude.simplepeg.entity.State; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +/** + * For text checking + */ public class RuleProcessor { + /** + * Разобранные правила + */ Map rules; + /** + * Первое правило + */ PegNode firstRule; - RdParser rdParser; + RdExecutor rdExecutor; public RuleProcessor(PegNode grammarTree) { - rdParser = new RdParser(); + rdExecutor = new RdExecutor(); selectRules(grammarTree); } @@ -57,13 +68,78 @@ public CheckResult check(String text) { private PegNode executeRule(PegNode rule, State state){ - SpegParser spegParser = new SpegParser(state,rules); + Executable exec = applyRule(rule); + PegNode res = exec.exec(state); + return res; + } + public Executable applyRule(final PegNode rule) { + return new Executable() { - Executable exec = spegParser.applyRule(rule); - PegNode res = exec.exec(state); - return res; + @Override + public PegNode exec(State state) { + + Executable[] childExecs = null; + + if (rule.getChildrens() != null) { + List childExecsList = new ArrayList<>(); + for (PegNode childNode : rule.getChildrens()) { + childExecsList.add(applyRule(childNode)); + } + childExecs = childExecsList.toArray(new Executable[0]); + } + + String fullStr = rule.getMatch().toString(); + String unQuotedStr = fullStr; + if (fullStr.length() > 1) { + unQuotedStr = fullStr.substring(1, fullStr.length() - 1); + } + + PegNode emptyRes = new PegNode(); + emptyRes.setResultType(ResultType.EMPTY); + + if (rule.getExecName() == null) { + return emptyRes; + } + + switch (rule.getExecName()) { + case "string": + return rdExecutor.parseString(unQuotedStr).exec(state); + case "regex": + return rdExecutor.parseRegexp(fullStr).exec(state); + case "sequence": + return rdExecutor.sequence("applySequence", childExecs).exec(state); + case "ordered_choise": + return rdExecutor.orderedChoice("applyOrderedChoise", childExecs).exec(state); + case "one_or_more": + return rdExecutor.oneOrMore("applyOneOrMore", childExecs[0]).exec(state); + case "zero_or_more": + return rdExecutor.zeroOrMore("applyZeroOrMore", childExecs[0]).exec(state); + case "not": + return rdExecutor.not(childExecs[1]).exec(state); + //case "and": //return rdExecutor.(childExecs[1]).exec(state); + case "optional": + return rdExecutor.optional(childExecs[0]).exec(state); + case "rule_expression": + default: + if (rules.containsKey(fullStr)) { + return applyRule(rules.get(fullStr)).exec(state); + } + + + if (childExecs.length == 0) { + return emptyRes; + } + + if (childExecs.length == 1) { + return childExecs[0].exec(state); + } + + return rdExecutor.sequence("deafultSequence", childExecs).exec(state); + } + } + }; } diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 777f07b..0d32894 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -2,7 +2,6 @@ import ru.dude.simplepeg.entity.PegNode; import ru.dude.simplepeg.entity.ResultType; -import ru.dude.simplepeg.entity.SpegTypes; import ru.dude.simplepeg.entity.State; import java.io.InputStream; @@ -19,12 +18,12 @@ public class SpegParser { private Map rules; State state; - RdParser rdParser; + RdExecutor rdExecutor; public SpegParser(State state) { this.state = state; - this.rdParser = new RdParser(); + this.rdExecutor = new RdExecutor(); } public SpegParser(State state, Map rules) { @@ -56,12 +55,12 @@ public Executable peg() { //return parsingBody(); - return rdParser.sequence("peg_parser", - rdParser.zeroOrMore("spaces", spacesBreaks()), + return rdExecutor.sequence("peg_parser", + rdExecutor.zeroOrMore("spaces", spacesBreaks()), parsingHeader(), - rdParser.oneOrMore("spaces", spacesBreaks()), + rdExecutor.oneOrMore("spaces", spacesBreaks()), parsingBody(), - rdParser.parseEndOfFile() + rdExecutor.parseEndOfFile() ); @@ -73,10 +72,10 @@ public Executable peg() { * @return */ public Executable parsingHeader() { - return rdParser.sequence("header", - rdParser.parseString("GRAMMAR"), - rdParser.oneOrMore("spaces", spacesBreaks()), - rdParser.oneOrMore("rulenames", ruleName()) + return rdExecutor.sequence("header", + rdExecutor.parseString("GRAMMAR"), + rdExecutor.oneOrMore("spaces", spacesBreaks()), + rdExecutor.oneOrMore("rulenames", ruleName()) ); } @@ -87,10 +86,10 @@ public Executable parsingHeader() { * @return */ public Executable parsingBody() { - return rdParser.oneOrMore("body", - rdParser.orderedChoice("rule_lines", + return rdExecutor.oneOrMore("body", + rdExecutor.orderedChoice("rule_lines", parsingRule(), - rdParser.oneOrMore("spaces", spacesBreaks()) + rdExecutor.oneOrMore("spaces", spacesBreaks()) ) ); } @@ -101,7 +100,7 @@ public Executable parsingBody() { * @return */ private Executable spacesBreaks() { - return rdParser.parseRegexp("[\\s]"); + return rdExecutor.parseRegexp("[\\s]"); } @@ -113,16 +112,16 @@ private Executable spacesBreaks() { * @return */ private Executable parsingRule() { - return rdParser.sequence("rule", + return rdExecutor.sequence("rule", ruleName(), - rdParser.zeroOrMore("spaces", spacesBreaks()), - rdParser.parseString("->"), - rdParser.zeroOrMore("spaces", spacesBreaks()), + rdExecutor.zeroOrMore("spaces", spacesBreaks()), + rdExecutor.parseString("->"), + rdExecutor.zeroOrMore("spaces", spacesBreaks()), ruleExpression(), - rdParser.zeroOrMore("spaces", spacesBreaks()), - rdParser.parseString(";"), - rdParser.zeroOrMore("spaces", spacesBreaks()) + rdExecutor.zeroOrMore("spaces", spacesBreaks()), + rdExecutor.parseString(";"), + rdExecutor.zeroOrMore("spaces", spacesBreaks()) ); } @@ -135,9 +134,9 @@ private Executable parsingRule() { * @return */ private Executable ruleName() { - return rdParser.sequence("rule_name", - rdParser.parseRegexp("[a-zA-Z_]"), - rdParser.zeroOrMore("", rdParser.parseRegexp("[a-zA-Z0-9_]")) + return rdExecutor.sequence("rule_name", + rdExecutor.parseRegexp("[a-zA-Z_]"), + rdExecutor.zeroOrMore("", rdExecutor.parseRegexp("[a-zA-Z0-9_]")) ); } @@ -149,7 +148,7 @@ private Executable ruleName() { * @return */ public Executable ruleExpression() { - return rdParser.orderedChoice("rule_expression", + return rdExecutor.orderedChoice("rule_expression", parsingSequence(), parsingOrderedChoice(), parsingSubExpression() @@ -159,15 +158,15 @@ public Executable ruleExpression() { private Executable parsingSequence() { - return rdParser.sequence("sequence", - rdParser.orderedChoice( + return rdExecutor.sequence("sequence", + rdExecutor.orderedChoice( "", parsingOrderedChoice(), parsingSubExpression() ), - rdParser.oneOrMore("sequence_args", - rdParser.sequence("sequence_arg", - rdParser.oneOrMore("spaces", spacesBreaks()), - rdParser.orderedChoice( + rdExecutor.oneOrMore("sequence_args", + rdExecutor.sequence("sequence_arg", + rdExecutor.oneOrMore("spaces", spacesBreaks()), + rdExecutor.orderedChoice( "", parsingOrderedChoice(), parsingSubExpression() ) @@ -177,13 +176,13 @@ private Executable parsingSequence() { } private Executable parsingOrderedChoice() { - return rdParser.sequence("ordered_choise", + return rdExecutor.sequence("ordered_choise", parsingSubExpression(), - rdParser.oneOrMore("ordered_choise_args", - rdParser.sequence("ordered_choise_arg", - rdParser.zeroOrMore("spaces", spacesBreaks()), - rdParser.parseString("/"), - rdParser.zeroOrMore("spaces", spacesBreaks()), + rdExecutor.oneOrMore("ordered_choise_args", + rdExecutor.sequence("ordered_choise_arg", + rdExecutor.zeroOrMore("spaces", spacesBreaks()), + rdExecutor.parseString("/"), + rdExecutor.zeroOrMore("spaces", spacesBreaks()), parsingSubExpression() ) ) @@ -191,14 +190,14 @@ private Executable parsingOrderedChoice() { } private Executable parsingSubExpression() { - return rdParser.sequence("sub_expression", + return rdExecutor.sequence("sub_expression", - rdParser.zeroOrMore("", rdParser.sequence("tags", + rdExecutor.zeroOrMore("", rdExecutor.sequence("tags", tag(), - rdParser.parseString(":") + rdExecutor.parseString(":") )), - rdParser.orderedChoice( + rdExecutor.orderedChoice( "", parsingNot(), parsingAnd(), parsingOptional(), @@ -214,28 +213,28 @@ private Executable parsingSubExpression() { private Executable tag() { - return rdParser.sequence("tag_name", - rdParser.parseRegexp("[a-zA-Z_]"), - rdParser.zeroOrMore("", rdParser.parseRegexp("[a-zA-Z0-9_]")) + return rdExecutor.sequence("tag_name", + rdExecutor.parseRegexp("[a-zA-Z_]"), + rdExecutor.zeroOrMore("", rdExecutor.parseRegexp("[a-zA-Z0-9_]")) ); } private Executable parsingGroup() { - return rdParser.sequence("group", - rdParser.parseString("("), - rdParser.zeroOrMore("spaces", spacesBreaks()), - rdParser.rec(this), - rdParser.zeroOrMore("spaces", spacesBreaks()), - rdParser.parseString(")") + return rdExecutor.sequence("group", + rdExecutor.parseString("("), + rdExecutor.zeroOrMore("spaces", spacesBreaks()), + rdExecutor.rec(this), + rdExecutor.zeroOrMore("spaces", spacesBreaks()), + rdExecutor.parseString(")") ); } private Executable parsingAtomicExpression() { - return rdParser.orderedChoice( + return rdExecutor.orderedChoice( "", parseString(), parseRegex(), - rdParser.parseEndOfFile(), + rdExecutor.parseEndOfFile(), parsingRuleCall() ); } @@ -251,38 +250,38 @@ private Executable parsingRuleCall() { } private Executable parseString() { - return rdParser.sequence("string", - rdParser.parseString("\""), - rdParser.oneOrMore("string", rdParser.orderedChoice( - "", rdParser.parseString("\\\\"), - rdParser.parseString("\\\""), - rdParser.parseRegexp("[^\"]") + return rdExecutor.sequence("string", + rdExecutor.parseString("\""), + rdExecutor.oneOrMore("string", rdExecutor.orderedChoice( + "", rdExecutor.parseString("\\\\"), + rdExecutor.parseString("\\\""), + rdExecutor.parseRegexp("[^\"]") )), - rdParser.parseString("\"") + rdExecutor.parseString("\"") ); } private Executable parseRegex() { - return rdParser.orderedChoice( - "", rdParser.sequence("regex", - rdParser.parseString("["), - rdParser.optional(rdParser.parseString("^")), - rdParser.oneOrMore("regex[]", rdParser.orderedChoice( - "", rdParser.parseString("\\]"), - rdParser.parseString("\\["), - rdParser.parseRegexp("[^\\]]") + return rdExecutor.orderedChoice( + "", rdExecutor.sequence("regex", + rdExecutor.parseString("["), + rdExecutor.optional(rdExecutor.parseString("^")), + rdExecutor.oneOrMore("regex[]", rdExecutor.orderedChoice( + "", rdExecutor.parseString("\\]"), + rdExecutor.parseString("\\["), + rdExecutor.parseRegexp("[^\\]]") )), - rdParser.parseString("]") + rdExecutor.parseString("]") ), - rdParser.parseString(".") + rdExecutor.parseString(".") ); } private Executable parsingNot() { - return rdParser.sequence("not", - rdParser.parseString("!"), - rdParser.orderedChoice( + return rdExecutor.sequence("not", + rdExecutor.parseString("!"), + rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() ) @@ -290,9 +289,9 @@ private Executable parsingNot() { } private Executable parsingAnd() { - return rdParser.sequence("and", - rdParser.parseString("&"), - rdParser.orderedChoice( + return rdExecutor.sequence("and", + rdExecutor.parseString("&"), + rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() ) @@ -300,103 +299,35 @@ private Executable parsingAnd() { } private Executable parsingOneOrMore() { - return rdParser.sequence("one_or_more", - rdParser.orderedChoice( + return rdExecutor.sequence("one_or_more", + rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() ), - rdParser.parseString("+") + rdExecutor.parseString("+") ); } private Executable parsingZeroOrMore() { - return rdParser.sequence("zero_or_more", - rdParser.orderedChoice( + return rdExecutor.sequence("zero_or_more", + rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() ), - rdParser.parseString("*") + rdExecutor.parseString("*") ); } private Executable parsingOptional() { - return rdParser.sequence("optional", - rdParser.orderedChoice( + return rdExecutor.sequence("optional", + rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() ), - rdParser.parseString("?") + rdExecutor.parseString("?") ); } - public Executable applyRule(final PegNode rule) { - return new Executable() { - - @Override - public PegNode exec(State state) { - - - Executable[] childExecs = null; - - if (rule.getChildrens() != null) { - List childExecsList = new ArrayList<>(); - for (PegNode childNode : rule.getChildrens()) { - childExecsList.add(applyRule(childNode)); - } - childExecs = childExecsList.toArray(new Executable[0]); - } - - String fullStr = rule.getMatch().toString(); - String unQuotedStr = fullStr; - if (fullStr.length() > 1) { - unQuotedStr = fullStr.substring(1, fullStr.length() - 1); - } - - PegNode emptyRes = new PegNode(); - emptyRes.setResultType(ResultType.EMPTY); - - if (rule.getExecName() == null) { - return emptyRes; - } - - switch (rule.getExecName()) { - case "string": - return rdParser.parseString(unQuotedStr).exec(state); - case "regex": - return rdParser.parseRegexp(fullStr).exec(state); - case "sequence": - return rdParser.sequence("applySequence", childExecs).exec(state); - case "ordered_choise": - return rdParser.orderedChoice("applyOrderedChoise", childExecs).exec(state); - case "one_or_more": - return rdParser.oneOrMore("applyOneOrMore", childExecs[0]).exec(state); - case "zero_or_more": - return rdParser.zeroOrMore("applyZeroOrMore", childExecs[0]).exec(state); - case "not": - return rdParser.not(childExecs[1]).exec(state); - //case "and": //return rdParser.(childExecs[1]).exec(state); - case "optional": - return rdParser.optional(childExecs[0]).exec(state); - case "rule_expression": - default: - if (rules.containsKey(fullStr)) { - return applyRule(rules.get(fullStr)).exec(state); - } - - - if (childExecs.length == 0) { - return emptyRes; - } - - if (childExecs.length == 1) { - return childExecs[0].exec(state); - } - - return rdParser.sequence("deafultSequence", childExecs).exec(state); - } - } - }; - } } diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java index 3d9712b..d3462b8 100644 --- a/src/main/java/ru/dude/simplepeg/Starter.java +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -14,16 +14,26 @@ public class Starter { public static void main(String[] args) throws Exception { - File f = new File("input.txt"); + 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)); + + String check1 = "https://simplepeg.github.io/"; + + 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/")); - State state = new State(new FileInputStream(f)); - - System.out.println(state.getTextData()); - - SpegParser spegParser = new SpegParser(state); - PegNode res = spegParser.peg().exec(state); - - printTree(res); } public static void printTree(PegNode node) throws IOException { diff --git a/src/main/java/ru/dude/simplepeg/entity/CheckResult.java b/src/main/java/ru/dude/simplepeg/entity/CheckResult.java index 2b306f2..04d22a4 100644 --- a/src/main/java/ru/dude/simplepeg/entity/CheckResult.java +++ b/src/main/java/ru/dude/simplepeg/entity/CheckResult.java @@ -1,5 +1,8 @@ package ru.dude.simplepeg.entity; +/** + * Результат проверки + */ public class CheckResult { private ResultType resultType; @@ -31,4 +34,12 @@ 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/ResultType.java b/src/main/java/ru/dude/simplepeg/entity/ResultType.java index e50d2a4..785e8c4 100644 --- a/src/main/java/ru/dude/simplepeg/entity/ResultType.java +++ b/src/main/java/ru/dude/simplepeg/entity/ResultType.java @@ -1,6 +1,7 @@ package ru.dude.simplepeg.entity; /** + * Тип результата * Created by dude on 30.10.2017. */ public enum ResultType { diff --git a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java index 6cdfe63..f3da466 100644 --- a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java +++ b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java @@ -12,5 +12,6 @@ public enum SpegTypes { REGEXP, STRING, OPTIONAL, - END_OF_FILE, NOT, + END_OF_FILE, + NOT, } diff --git a/src/test/java/RdComplexTest.java b/src/test/java/RdComplexTest.java index a1c764d..329014d 100644 --- a/src/test/java/RdComplexTest.java +++ b/src/test/java/RdComplexTest.java @@ -1,7 +1,7 @@ import org.junit.Assert; import org.junit.Test; import ru.dude.simplepeg.Executable; -import ru.dude.simplepeg.RdParser; +import ru.dude.simplepeg.RdExecutor; import ru.dude.simplepeg.entity.PegNode; import ru.dude.simplepeg.entity.ResultType; import ru.dude.simplepeg.entity.State; @@ -9,7 +9,7 @@ /** * Created by dude on 27.05.2018. *

- * Сложные тесты для RdParser + * Сложные тесты для RdExecutor */ public class RdComplexTest extends Assert { @@ -22,7 +22,7 @@ private void assertProcess(String grammar, String input, Executable executable, @Test public void sequencesAndOneZeroMore() { - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.sequence("test_sequence", rd.oneOrMore("", rd.parseString("a")), rd.oneOrMore("", rd.parseString("b")), @@ -38,7 +38,7 @@ public void sequencesAndOneZeroMore() { @Test public void sequencesAndOptional() { - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.sequence("test_sequence", rd.parseString("aaaa"), rd.optional(rd.parseString("bbbb")), @@ -52,7 +52,7 @@ public void sequencesAndOptional() { @Test public void oneOrManyAndOptional() { - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.oneOrMore("test_oneOrMany", rd.orderedChoice( "", rd.optional(rd.parseString("bxy")), @@ -65,7 +65,7 @@ public void oneOrManyAndOptional() { @Test public void sequenceAndOneOrManyAndOptional() { - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.sequence("", rd.oneOrMore("test_oneOrMany", diff --git a/src/test/java/RdParserTest.java b/src/test/java/RdExecutorTest.java similarity index 87% rename from src/test/java/RdParserTest.java rename to src/test/java/RdExecutorTest.java index 204d190..be0edb0 100644 --- a/src/test/java/RdParserTest.java +++ b/src/test/java/RdExecutorTest.java @@ -1,7 +1,7 @@ import org.junit.Assert; import org.junit.Test; import ru.dude.simplepeg.Executable; -import ru.dude.simplepeg.RdParser; +import ru.dude.simplepeg.RdExecutor; import ru.dude.simplepeg.entity.PegNode; import ru.dude.simplepeg.entity.ResultType; import ru.dude.simplepeg.entity.State; @@ -12,7 +12,7 @@ * * Тесты конструкций PEG */ -public class RdParserTest extends Assert { +public class RdExecutorTest extends Assert { private void assertProcess(String grammar,String input,Executable executable,ResultType resultType){ @@ -25,7 +25,7 @@ private void assertProcess(String grammar,String input,Executable executable,Res public void simpleString(){ String grammar = "aaaazz;"; String input = "aaaazz"; - Executable executable = new RdParser().parseString(input); + Executable executable = new RdExecutor().parseString(input); assertProcess(grammar,input,executable,ResultType.OK); } @@ -34,7 +34,7 @@ public void simpleString(){ public void simpleRegexp(){ String grammar = "aaaazz;"; String input = "[a-z]+"; - Executable executable = new RdParser().parseRegexp(input); + Executable executable = new RdExecutor().parseRegexp(input); assertProcess(grammar,input,executable,ResultType.OK); } @@ -42,7 +42,7 @@ public void simpleRegexp(){ public void eofTest(){ String grammar = ""; String input = "[___ANY___]"; - Executable executable = new RdParser().parseEndOfFile(); + Executable executable = new RdExecutor().parseEndOfFile(); assertProcess(grammar,input,executable,ResultType.OK); } @@ -52,7 +52,7 @@ public void simpleSequenceOk(){ String s1 = "aaaa"; String s2 = "zz"; String r3 = "[xX]+"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.sequence("test_sequence", rd.parseString(s1), rd.parseString(s2), @@ -67,7 +67,7 @@ public void simpleSequenceEmpty(){ String s1 = "aaaa"; String s2 = "zz"; String r3 = "[0-9]+"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.sequence("test_sequence", rd.optional(rd.parseString(s1)), rd.optional(rd.parseString(s2)), @@ -82,7 +82,7 @@ public void simpleSequenceError(){ String s1 = "aaaa"; String s2 = "zz"; String r3 = "[0-9]+"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.sequence("test_sequence", rd.parseString(s1), rd.parseString(s2), @@ -96,7 +96,7 @@ public void simpleOrderedChoiceOk(){ String s1 = "aaaa"; String s2 = "zz"; String r3 = "[xX]+"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.orderedChoice( "", rd.parseString(s1), rd.parseString(s2), @@ -112,7 +112,7 @@ public void simpleOrderedChoiceEmpty(){ String s1 = "aaaa"; String s2 = "zz"; String r3 = "[0-9]+"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.orderedChoice( "", rd.optional(rd.parseString(s1)), rd.optional(rd.parseString(s2)), @@ -126,7 +126,7 @@ public void simpleOrderedChoiceError(){ String s1 = "aaaa"; String s2 = "zz"; String r3 = "[0-9]+"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.orderedChoice( "", rd.parseString(s1), rd.parseString(s2), @@ -138,7 +138,7 @@ public void simpleOrderedChoiceError(){ @Test public void simpleOneOrMoreOk(){ String s1 = "a"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.oneOrMore("simpleOneOrMoreOK_test", rd.parseString(s1) ); @@ -148,7 +148,7 @@ public void simpleOneOrMoreOk(){ @Test public void simpleOneOrMoreError(){ String s1 = "a"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.oneOrMore("simpleOneOrMoreError_test", rd.parseString(s1) ); @@ -158,7 +158,7 @@ public void simpleOneOrMoreError(){ @Test public void simplZeroOrMoreOk(){ String s1 = "a"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.zeroOrMore( "", rd.parseString(s1) ); @@ -168,7 +168,7 @@ public void simplZeroOrMoreOk(){ @Test public void simpleZeroOrMoreEmpty(){ String s1 = "a"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.zeroOrMore( "", rd.parseString(s1) ); @@ -178,7 +178,7 @@ public void simpleZeroOrMoreEmpty(){ @Test public void simpleOptionalOk(){ String s1 = "a"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.optional( rd.parseString(s1) ); @@ -188,7 +188,7 @@ public void simpleOptionalOk(){ @Test public void simpleOptionalEmpty(){ String s1 = "a"; - RdParser rd = new RdParser(); + RdExecutor rd = new RdExecutor(); Executable executable = rd.optional( rd.parseString(s1) ); From 5877fca962d23f22b84f5354abc9357a2aec3eaa Mon Sep 17 00:00:00 2001 From: dude Date: Mon, 13 Aug 2018 22:48:12 +0300 Subject: [PATCH 13/15] refactor2 --- .../java/ru/dude/simplepeg/Executable.java | 1 + .../java/ru/dude/simplepeg/RdExecutor.java | 1 + .../java/ru/dude/simplepeg/RuleProcessor.java | 15 +++----- .../java/ru/dude/simplepeg/SpegParser.java | 6 --- src/main/java/ru/dude/simplepeg/Starter.java | 15 +++----- .../ru/dude/simplepeg/entity/CheckResult.java | 10 ++--- .../ru/dude/simplepeg/entity/PegNode.java | 37 +++++++++---------- .../java/ru/dude/simplepeg/entity/State.java | 31 ++++++++-------- 8 files changed, 53 insertions(+), 63 deletions(-) diff --git a/src/main/java/ru/dude/simplepeg/Executable.java b/src/main/java/ru/dude/simplepeg/Executable.java index 24bc966..ab15b2e 100644 --- a/src/main/java/ru/dude/simplepeg/Executable.java +++ b/src/main/java/ru/dude/simplepeg/Executable.java @@ -11,6 +11,7 @@ public interface Executable { /** * Execute PEG expression + * * @return */ PegNode exec(State state); diff --git a/src/main/java/ru/dude/simplepeg/RdExecutor.java b/src/main/java/ru/dude/simplepeg/RdExecutor.java index 79fb53c..2db81a4 100644 --- a/src/main/java/ru/dude/simplepeg/RdExecutor.java +++ b/src/main/java/ru/dude/simplepeg/RdExecutor.java @@ -279,6 +279,7 @@ public PegNode exec(State state) { /** * Предикат not. * По хорошему, внутри он должен двигать position... оставлю пока так + * * @param exec * @return */ diff --git a/src/main/java/ru/dude/simplepeg/RuleProcessor.java b/src/main/java/ru/dude/simplepeg/RuleProcessor.java index 8d3aac9..2195830 100644 --- a/src/main/java/ru/dude/simplepeg/RuleProcessor.java +++ b/src/main/java/ru/dude/simplepeg/RuleProcessor.java @@ -38,14 +38,14 @@ private void selectRules(PegNode grammarTree) { PegNode lines = grammarTree.child("body"); for (PegNode ch : lines.getChildrens()) { - if (ch.getExecName().equals("rule_lines")){ + if (ch.getExecName().equals("rule_lines")) { PegNode rule = ch.child("rule"); String ruleName = rule.child("rule_name").getMatch().toString(); PegNode ruleExpression = rule.child("rule_expression"); - if (firstRule == null){ + if (firstRule == null) { firstRule = ruleExpression; } - rules.put(ruleName,ruleExpression); + rules.put(ruleName, ruleExpression); } } } @@ -59,14 +59,14 @@ public CheckResult check(String text) { PegNode resultExec = executeRule(firstRule, textState); - if (resultExec.getResultType() == ResultType.OK){ + if (resultExec.getResultType() == ResultType.OK) { return CheckResult.ok(); } return CheckResult.error(resultExec.getError()); } - private PegNode executeRule(PegNode rule, State state){ + private PegNode executeRule(PegNode rule, State state) { Executable exec = applyRule(rule); PegNode res = exec.exec(state); @@ -113,7 +113,7 @@ public PegNode exec(State state) { case "ordered_choise": return rdExecutor.orderedChoice("applyOrderedChoise", childExecs).exec(state); case "one_or_more": - return rdExecutor.oneOrMore("applyOneOrMore", childExecs[0]).exec(state); + return rdExecutor.oneOrMore("applyOneOrMore", childExecs[0]).exec(state); case "zero_or_more": return rdExecutor.zeroOrMore("applyZeroOrMore", childExecs[0]).exec(state); case "not": @@ -143,7 +143,4 @@ public PegNode exec(State state) { } - - - } diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 0d32894..1327b22 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -1,12 +1,9 @@ package ru.dude.simplepeg; import ru.dude.simplepeg.entity.PegNode; -import ru.dude.simplepeg.entity.ResultType; import ru.dude.simplepeg.entity.State; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; import java.util.Map; /** @@ -53,8 +50,6 @@ public static PegNode createAndExec(InputStream grammarIS) { */ public Executable peg() { - //return parsingBody(); - return rdExecutor.sequence("peg_parser", rdExecutor.zeroOrMore("spaces", spacesBreaks()), parsingHeader(), @@ -107,7 +102,6 @@ private Executable spacesBreaks() { /** * Parce rule *

- * TODO: (not ready) * * @return */ diff --git a/src/main/java/ru/dude/simplepeg/Starter.java b/src/main/java/ru/dude/simplepeg/Starter.java index d3462b8..a29977c 100644 --- a/src/main/java/ru/dude/simplepeg/Starter.java +++ b/src/main/java/ru/dude/simplepeg/Starter.java @@ -1,11 +1,10 @@ package ru.dude.simplepeg; import ru.dude.simplepeg.entity.PegNode; -import ru.dude.simplepeg.entity.State; -import java.io.*; -import java.util.ArrayList; -import java.util.List; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; /** * Created by dude on 29.10.2017. @@ -28,11 +27,9 @@ public static void main(String[] args) throws Exception { RuleProcessor rp = new RuleProcessor(SpegParser.createAndExec(grammar)); - String check1 = "https://simplepeg.github.io/"; - - 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/")); + 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/")); } diff --git a/src/main/java/ru/dude/simplepeg/entity/CheckResult.java b/src/main/java/ru/dude/simplepeg/entity/CheckResult.java index 04d22a4..6f67b5a 100644 --- a/src/main/java/ru/dude/simplepeg/entity/CheckResult.java +++ b/src/main/java/ru/dude/simplepeg/entity/CheckResult.java @@ -8,18 +8,18 @@ public class CheckResult { private ResultType resultType; private String errorText; - private CheckResult(){ + private CheckResult() { } - public static CheckResult error(String errorText){ + public static CheckResult error(String errorText) { CheckResult r = new CheckResult(); r.resultType = ResultType.ERROR; r.errorText = errorText; return r; } - public static CheckResult ok(){ + public static CheckResult ok() { CheckResult r = new CheckResult(); r.resultType = ResultType.OK; r.errorText = ""; @@ -36,10 +36,10 @@ public String getErrorText() { @Override public String toString() { - if (ResultType.OK.equals(resultType)){ + if (ResultType.OK.equals(resultType)) { return ResultType.OK.toString(); } else { - return resultType +"["+ errorText + ']'; + 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 index c998b72..95df1c6 100644 --- a/src/main/java/ru/dude/simplepeg/entity/PegNode.java +++ b/src/main/java/ru/dude/simplepeg/entity/PegNode.java @@ -5,10 +5,10 @@ /** * Tree object with result data - * + *

* Created by dude on 29.10.2017. */ -public class PegNode{ +public class PegNode { private static Integer nextId = 0; @@ -24,7 +24,7 @@ public class PegNode{ String error; private String execName; - public PegNode(){ + public PegNode() { id = nextId++; } @@ -37,43 +37,42 @@ public void appendChild(PegNode child) { } if (endPosition == null || endPosition < child.getEndPosition()) { - endPosition =child.getEndPosition(); + endPosition = child.getEndPosition(); } } + public void toJson(StringBuilder sb, int level) { - public void toJson(StringBuilder sb,int level){ + addtabs(sb, level).append("{\n"); + addtabs(sb, level + 1).append("\"id\" :\"").append(id).append("\",\n"); + addtabs(sb, level + 1).append("\"execName\" :\"").append(execName).append("\",\n"); + addtabs(sb, level + 1).append("\"type\" :\"").append(type).append("\",\n"); + addtabs(sb, level + 1).append("\"match\" :\"").append(match).append("\",\n"); + addtabs(sb, level + 1).append("\"startPosition\" :").append(startPosition).append(",\n"); + addtabs(sb, level + 1).append("\"endPosition\" :").append(endPosition).append(",\n"); - addtabs(sb,level).append("{\n"); - addtabs(sb,level+1).append("\"id\" :\"").append(id).append("\",\n"); - addtabs(sb,level+1).append("\"execName\" :\"").append(execName).append("\",\n"); - addtabs(sb,level+1).append("\"type\" :\"").append(type).append("\",\n"); - addtabs(sb,level+1).append("\"match\" :\"").append(match).append("\",\n"); - addtabs(sb,level+1).append("\"startPosition\" :").append(startPosition).append(",\n"); - addtabs(sb,level+1).append("\"endPosition\" :").append(endPosition).append(",\n"); - - if (childrens.size()>0) { + if (childrens.size() > 0) { addtabs(sb, level + 1).append("\"childrens\":[\n"); for (PegNode children : childrens) { children.toJson(sb, level + 2); } addtabs(sb, level + 1).append("]\n"); } - addtabs(sb,level).append("},\n"); + addtabs(sb, level).append("},\n"); } - private StringBuilder addtabs(StringBuilder sb,int level){ - for (int i=0;i Date: Mon, 13 Aug 2018 23:13:52 +0300 Subject: [PATCH 14/15] refactor3 --- README.md | 21 ++++++++++ .../java/ru/dude/simplepeg/RuleProcessor.java | 32 +++++++------- .../java/ru/dude/simplepeg/SpegParser.java | 32 +++++++------- .../ru/dude/simplepeg/entity/SpegNames.java | 42 +++++++++++++++++++ .../ru/dude/simplepeg/entity/SpegTypes.java | 2 + 5 files changed, 98 insertions(+), 31 deletions(-) create mode 100644 src/main/java/ru/dude/simplepeg/entity/SpegNames.java 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/src/main/java/ru/dude/simplepeg/RuleProcessor.java b/src/main/java/ru/dude/simplepeg/RuleProcessor.java index 2195830..bc0aa6d 100644 --- a/src/main/java/ru/dude/simplepeg/RuleProcessor.java +++ b/src/main/java/ru/dude/simplepeg/RuleProcessor.java @@ -1,15 +1,13 @@ package ru.dude.simplepeg; -import ru.dude.simplepeg.entity.CheckResult; -import ru.dude.simplepeg.entity.PegNode; -import ru.dude.simplepeg.entity.ResultType; -import ru.dude.simplepeg.entity.State; +import ru.dude.simplepeg.entity.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; + /** * For text checking */ @@ -103,25 +101,27 @@ public PegNode exec(State state) { return emptyRes; } - switch (rule.getExecName()) { - case "string": + SpegNames spegName = SpegNames.bySpegName(rule.getExecName()); + + switch (spegName) { + case NAME_STRING: return rdExecutor.parseString(unQuotedStr).exec(state); - case "regex": + case NAME_REGEX: return rdExecutor.parseRegexp(fullStr).exec(state); - case "sequence": + case NAME_SEQUENCE: return rdExecutor.sequence("applySequence", childExecs).exec(state); - case "ordered_choise": - return rdExecutor.orderedChoice("applyOrderedChoise", childExecs).exec(state); - case "one_or_more": + case NAME_ORDERED_CHOCE: + return rdExecutor.orderedChoice("applyOrderedChoice", childExecs).exec(state); + case NAME_ONE_OR_MORE: return rdExecutor.oneOrMore("applyOneOrMore", childExecs[0]).exec(state); - case "zero_or_more": + case NAME_ZERO_OR_MORE: return rdExecutor.zeroOrMore("applyZeroOrMore", childExecs[0]).exec(state); - case "not": + case NAME_NOT: return rdExecutor.not(childExecs[1]).exec(state); - //case "and": //return rdExecutor.(childExecs[1]).exec(state); - case "optional": + //case NAME_AND: //return rdExecutor.(childExecs[1]).exec(state); + case NAME_OPTIONAL: return rdExecutor.optional(childExecs[0]).exec(state); - case "rule_expression": + case NAME_RULE_EXPRESSION: default: if (rules.containsKey(fullStr)) { return applyRule(rules.get(fullStr)).exec(state); diff --git a/src/main/java/ru/dude/simplepeg/SpegParser.java b/src/main/java/ru/dude/simplepeg/SpegParser.java index 1327b22..4eb0daa 100644 --- a/src/main/java/ru/dude/simplepeg/SpegParser.java +++ b/src/main/java/ru/dude/simplepeg/SpegParser.java @@ -1,6 +1,7 @@ package ru.dude.simplepeg; import ru.dude.simplepeg.entity.PegNode; +import ru.dude.simplepeg.entity.SpegNames; import ru.dude.simplepeg.entity.State; import java.io.InputStream; @@ -170,10 +171,10 @@ private Executable parsingSequence() { } private Executable parsingOrderedChoice() { - return rdExecutor.sequence("ordered_choise", + return rdExecutor.sequence("ordered_choice", parsingSubExpression(), - rdExecutor.oneOrMore("ordered_choise_args", - rdExecutor.sequence("ordered_choise_arg", + rdExecutor.oneOrMore("ordered_choice_args", + rdExecutor.sequence("ordered_choice_arg", rdExecutor.zeroOrMore("spaces", spacesBreaks()), rdExecutor.parseString("/"), rdExecutor.zeroOrMore("spaces", spacesBreaks()), @@ -244,20 +245,21 @@ private Executable parsingRuleCall() { } private Executable parseString() { - return rdExecutor.sequence("string", + return rdExecutor.sequence(SpegNames.NAME_STRING.getSpegName(), rdExecutor.parseString("\""), - rdExecutor.oneOrMore("string", rdExecutor.orderedChoice( - "", rdExecutor.parseString("\\\\"), - rdExecutor.parseString("\\\""), - rdExecutor.parseRegexp("[^\"]") - )), + rdExecutor.oneOrMore(SpegNames.NAME_STRING.getSpegName(), + rdExecutor.orderedChoice( + "", rdExecutor.parseString("\\\\"), + rdExecutor.parseString("\\\""), + rdExecutor.parseRegexp("[^\"]") + )), rdExecutor.parseString("\"") ); } private Executable parseRegex() { return rdExecutor.orderedChoice( - "", rdExecutor.sequence("regex", + "", rdExecutor.sequence(SpegNames.NAME_REGEX.getSpegName(), rdExecutor.parseString("["), rdExecutor.optional(rdExecutor.parseString("^")), rdExecutor.oneOrMore("regex[]", rdExecutor.orderedChoice( @@ -273,7 +275,7 @@ private Executable parseRegex() { private Executable parsingNot() { - return rdExecutor.sequence("not", + return rdExecutor.sequence(SpegNames.NAME_NOT.getSpegName(), rdExecutor.parseString("!"), rdExecutor.orderedChoice( "", parsingGroup(), @@ -283,7 +285,7 @@ private Executable parsingNot() { } private Executable parsingAnd() { - return rdExecutor.sequence("and", + return rdExecutor.sequence(SpegNames.NAME_AND.getSpegName(), rdExecutor.parseString("&"), rdExecutor.orderedChoice( "", parsingGroup(), @@ -293,7 +295,7 @@ private Executable parsingAnd() { } private Executable parsingOneOrMore() { - return rdExecutor.sequence("one_or_more", + return rdExecutor.sequence(SpegNames.NAME_ONE_OR_MORE.getSpegName(), rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() @@ -304,7 +306,7 @@ private Executable parsingOneOrMore() { private Executable parsingZeroOrMore() { - return rdExecutor.sequence("zero_or_more", + return rdExecutor.sequence(SpegNames.NAME_ZERO_OR_MORE.getSpegName(), rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() @@ -314,7 +316,7 @@ private Executable parsingZeroOrMore() { } private Executable parsingOptional() { - return rdExecutor.sequence("optional", + return rdExecutor.sequence(SpegNames.NAME_OPTIONAL.getSpegName(), rdExecutor.orderedChoice( "", parsingGroup(), parsingAtomicExpression() diff --git a/src/main/java/ru/dude/simplepeg/entity/SpegNames.java b/src/main/java/ru/dude/simplepeg/entity/SpegNames.java new file mode 100644 index 0000000..85fe28e --- /dev/null +++ b/src/main/java/ru/dude/simplepeg/entity/SpegNames.java @@ -0,0 +1,42 @@ +package ru.dude.simplepeg.entity; + +/** + * SPEG names. + * + * Имя узла может нести семантическое значение узла (например header или only_letter_rule). + * Здесь собраны имена узлов, определяемых при парсинге грамматики, и используемые для валидации по грамматике. + */ +public enum SpegNames { + NAME_OTHER(""), + NAME_STRING("string"), + NAME_REGEX("regex"), + NAME_SEQUENCE("sequence"), + NAME_ORDERED_CHOCE("ordered_choice"), + NAME_ONE_OR_MORE("one_or_more"), + NAME_ZERO_OR_MORE("zero_or_more"), + NAME_NOT("not"), + NAME_AND("and"), + NAME_OPTIONAL("optional"), + NAME_RULE_EXPRESSION("rule_expression"), + ; + + private String spegName; + + SpegNames(String spegName) { + + this.spegName = spegName; + } + + public String getSpegName() { + return spegName; + } + + public static SpegNames bySpegName(String spegName) { + for (SpegNames sn : values()) { + if (sn.getSpegName().equals(spegName)) { + return sn; + } + } + return NAME_OTHER; + } +} diff --git a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java index f3da466..1a49fd9 100644 --- a/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java +++ b/src/main/java/ru/dude/simplepeg/entity/SpegTypes.java @@ -2,6 +2,8 @@ /** * PEG operation types + * + * Типы операций в peg-грамматике. Фиксированный набор. * Created by dude on 29.10.2017. */ public enum SpegTypes { From 646965f92862aea9c574e57ea19fa91ec5bbb3c6 Mon Sep 17 00:00:00 2001 From: dude Date: Mon, 13 Aug 2018 23:16:19 +0300 Subject: [PATCH 15/15] refactor4 --- input.txt | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 input.txt diff --git a/input.txt b/input.txt deleted file mode 100644 index b5fcc92..0000000 --- a/input.txt +++ /dev/null @@ -1,11 +0,0 @@ -GRAMMAR url - -url -> scheme "://" host pathname search hash?; -scheme -> "http" "s"?; -host -> hostname port?; -hostname -> segment ("." segment)*; -segment -> [a-z0-9-]+; -port -> ":" [0-9]+; -pathname -> "/" [^ ?]*; -search -> ("?" [^ #]*)?; -hash -> "#" [^ ]*;