001/**
002 *
003 * Copyright 2019 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jxmpp.strings.testframework;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.parboiled.Rule;
023import org.parboiled.parserunners.ParseRunner;
024import org.parboiled.parserunners.ReportingParseRunner;
025import org.parboiled.parserunners.TracingParseRunner;
026import org.parboiled.support.ParsingResult;
027
028public abstract class JidCorpusParser<J> {
029
030        public static final char ASCII_LINE_FEED_UNICODE_END_OF_LINE = '\n';
031        public static final char ASCII_RECORD_SEPARATOR_UNICODE_INFORMATION_SEPARATOR_TWO = '\u001E';
032        public static final char ASCII_UNIT_SEPARATOR_UNICODE_INFORMATION_SEPARATOR_ONE = '\u001F';
033        public static final String END_OF_RECORD;
034
035        static {
036                char[] endOfRecordChars = {ASCII_RECORD_SEPARATOR_UNICODE_INFORMATION_SEPARATOR_TWO,
037                                ASCII_LINE_FEED_UNICODE_END_OF_LINE};
038                END_OF_RECORD = new String(endOfRecordChars);
039        }
040
041        protected static final char[] CONTROL_CHARACTERS = new char[] {
042                        ASCII_RECORD_SEPARATOR_UNICODE_INFORMATION_SEPARATOR_TWO,
043                        ASCII_UNIT_SEPARATOR_UNICODE_INFORMATION_SEPARATOR_ONE,
044        };
045
046        protected static final char[] CONTROL_CHARACTERS_AND_NEWLINE;
047
048        static {
049                CONTROL_CHARACTERS_AND_NEWLINE = new char[CONTROL_CHARACTERS.length + 1];
050                System.arraycopy(CONTROL_CHARACTERS, 0, CONTROL_CHARACTERS_AND_NEWLINE, 0, CONTROL_CHARACTERS.length);
051                CONTROL_CHARACTERS_AND_NEWLINE[CONTROL_CHARACTERS_AND_NEWLINE.length - 1] = '\n';
052        }
053
054        private final String input;
055        private final boolean enableParserTracing;
056
057        ParsingResult<J> parsingResult;
058        private List<J> parsedJids;
059
060        /**
061         * Construct a new valid JID corpus parser.
062         *
063         * @param input the string to parse.
064         */
065        protected JidCorpusParser(String input) {
066                this(input, false);
067        }
068
069        /**
070         * Construct a new valid JID corpus parser.
071         *
072         * @param input the string to parse.
073         * @param tracing if tracing of the parser should be enabled.
074         */
075        protected JidCorpusParser(String input, boolean tracing) {
076                this.input = input;
077                this.enableParserTracing = tracing;
078        }
079
080        /**
081         * Parse the input.
082         *
083         * @return a list of parsed {@link ValidJid}s.
084         */
085        public List<J> parse() {
086                final ParseRunner<J> runner;
087                if (enableParserTracing) {
088                        runner = getTracingParseRunner();
089                } else {
090                        runner = getReportingParserRunner();
091                }
092
093                parsingResult = runner.run(input);
094                parsedJids = getValidJidsFrom(parsingResult);
095                return parsedJids;
096        }
097
098        protected abstract Rule getParserRootRule();
099
100        private ReportingParseRunner<J> getReportingParserRunner() {
101                Rule parserRootRule = getParserRootRule();
102                ReportingParseRunner<J> runner = new ReportingParseRunner<>(parserRootRule);
103                return runner;
104        }
105
106        private TracingParseRunner<J> getTracingParseRunner() {
107                Rule parserRootRule = getParserRootRule();
108                TracingParseRunner<J> runner = new TracingParseRunner<>(parserRootRule);
109                return runner;
110        }
111
112        private static <J> List<J> getValidJidsFrom(ParsingResult<J> parsingResult) {
113                final List<J> result = new ArrayList<>(parsingResult.valueStack.size());
114                parsingResult.valueStack.forEach(e -> result.add(e));
115                return result;
116        }
117
118}