Package org.parboiled.parserunners

Source Code of org.parboiled.parserunners.ReportingParseRunner$Handler

/*
* Copyright (C) 2009-2010 Mathias Doenitz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.parboiled.parserunners;

import org.jetbrains.annotations.NotNull;
import org.parboiled.MatchHandler;
import org.parboiled.MatcherContext;
import org.parboiled.Rule;
import org.parboiled.errors.InvalidInputError;
import org.parboiled.matchervisitors.IsSingleCharMatcherVisitor;
import org.parboiled.support.*;

import java.util.ArrayList;
import java.util.List;

/**
* A {@link ParseRunner} implementation that properly reports the first {@link InvalidInputError} if the input
* does not conform to the rule grammar.
* It performs exactly as the {@link BasicParseRunner} on valid input, however, on invalid input two more parsing
* runs are initiated: one for recording the first parse error and one for collecting the error report information.
*/
public class ReportingParseRunner<V> extends BasicParseRunner<V> {

    /**
     * Create a new ReportingParseRunner instance with the given rule and input text and returns the result of
     * its {@link #run(String)} method invocation.
     *
     * @param rule  the parser rule to run
     * @param input the input text to run on
     * @return the ParsingResult for the parsing run
     */
    public static <V> ParsingResult<V> run(@NotNull Rule rule, @NotNull String input) {
        return new ReportingParseRunner<V>(rule).run(input);
    }

    /**
     * Creates a new ReportingParseRunner instance for the given rule.
     *
     * @param rule  the parser rule
     */
    public ReportingParseRunner(@NotNull Rule rule) {
        super(rule);
    }

    /**
     * Creates a new ReportingParseRunner instance for the given rule using the given ValueStack instance.
     *
     * @param rule  the parser rule
     * @param valueStack  the value stack
     */
    public ReportingParseRunner(@NotNull Rule rule, @NotNull ValueStack<V> valueStack) {
        super(rule, valueStack);
    }

    @SuppressWarnings({"SimplifiableIfStatement"})
    @Override
    protected boolean runRootContext() {
        // run a basic match
        if (super.runRootContext()) {
            return true;
        }

        // ok, we have a parse error, so run again without fast string matching and with our recording handler
        RecordingParseRunner.Handler recordingHandler = new RecordingParseRunner.Handler();
        if (runRootContext(recordingHandler, false)) {
            throw new IllegalStateException(); // we failed before so we should really be failing again
        }

        // finally perform a third, reporting run (now that we know the error location)
        Handler reportingHandler = new Handler(recordingHandler.getErrorIndex());
        if (runRootContext(reportingHandler, false)) {
            throw new IllegalStateException(); // we failed before so we should really be failing again
        }

        return false;
    }

    /**
     * A {@link org.parboiled.MatchHandler} implementation that reports the {@link InvalidInputError} at a given error index.
     * For the actual matching this handler relies on another, inner {@link org.parboiled.MatchHandler} instance it delegates to.
     */
    public static class Handler implements MatchHandler {
        private final IsSingleCharMatcherVisitor isSingleCharMatcherVisitor = new IsSingleCharMatcherVisitor();
        private final int errorIndex;
        private final MatchHandler inner;
        private final List<MatcherPath> failedMatchers = new ArrayList<MatcherPath>();
        private InvalidInputError parseError;
        private boolean seeking;

        /**
         * Create a new handler that can report the {@link InvalidInputError} at the given error index.
         * It relies on a new {@link BasicParseRunner.Handler} instance for the actual matching.
         *
         * @param errorIndex the InputLocation of the error to be reported
         */
        public Handler(int errorIndex) {
            this(errorIndex, new BasicParseRunner.Handler());
        }

        /**
         * Create a new handler that can report the {@link InvalidInputError} at the given error index.
         * It relies on the given {@link MatchHandler} instance for the actual matching.
         *
         * @param errorIndex the InputLocation of the error to be reported
         * @param inner      the inner MatchHandler to use
         */
        public Handler(int errorIndex, @NotNull MatchHandler inner) {
            this.errorIndex = errorIndex;
            this.inner = inner;
        }

        /**
         * Returns the {@link InvalidInputError} instance that was created during the reporting run.
         *
         * @return the InvalidInputError
         */
        public InvalidInputError getParseError() {
            return parseError;
        }

        public boolean matchRoot(MatcherContext<?> rootContext) {
            failedMatchers.clear();
            seeking = errorIndex > 0;
            inner.matchRoot(rootContext);

            parseError = new InvalidInputError(rootContext.getInputBuffer(), errorIndex, failedMatchers, null);
            rootContext.getParseErrors().add(parseError);
            return false;
        }

        public boolean match(MatcherContext<?> context) {
            boolean matched = inner.match(context);
            if (context.getCurrentIndex() == errorIndex) {
                if (matched && seeking) {
                    seeking = false;
                }
                if (!matched && !seeking && context.getMatcher().accept(isSingleCharMatcherVisitor)) {
                    failedMatchers.add(context.getPath());
                }
            }
            return matched;
        }

    }

}
TOP

Related Classes of org.parboiled.parserunners.ReportingParseRunner$Handler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.