001/*
002 * Copyright (C) 2009-2011 Mathias Doenitz
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.parboiled.support;
018
019import org.parboiled.Context;
020import org.parboiled.Node;
021import org.parboiled.Rule;
022import org.parboiled.common.Predicate;
023import org.parboiled.common.Predicates;
024import org.parboiled.common.Tuple2;
025import org.parboiled.matchers.Matcher;
026import org.parboiled.matchers.MatcherUtils;
027import org.parboiled.parserunners.TracingParseRunner;
028
029import java.util.HashSet;
030import java.util.Set;
031
032import static org.parboiled.trees.GraphUtils.hasChildren;
033
034public class Filters {
035
036    /**
037     * A predicate for Node tree printing, suppresses printing of parse tree nodes for Optional rules that
038     * do not have sub nodes.
039     */
040    public static final Predicate<Node<Object>> SKIP_EMPTY_OPTS = new Predicate<Node<Object>>() {
041        public boolean apply(Node<Object> node) {
042            return hasChildren(node) || node.getEndIndex() != node.getStartIndex() ||
043                    !"Optional".equals(node.getLabel());
044        }
045    };
046
047    /**
048     * A predicate for Node tree printing, suppresses printing of parse tree nodes for ZeroOrMore rules that
049     * do not have sub nodes.
050     */
051    public static final Predicate<Node<Object>> SKIP_EMPTY_ZOMS = new Predicate<Node<Object>>() {
052        public boolean apply(Node<Object> node) {
053            return hasChildren(node) || node.getEndIndex() != node.getStartIndex() ||
054                    !"ZeroOrMore".equals(node.getLabel());
055        }
056    };
057
058    /**
059     * A predicate for Node tree printing, suppresses printing of parse tree nodes for Optional and ZeroOrMore rules
060     * that do not have sub nodes.
061     */
062    public static final Predicate<Node<Object>> SKIP_EMPTY_OPTS_AND_ZOMS =
063            Predicates.and(SKIP_EMPTY_OPTS, SKIP_EMPTY_ZOMS);
064
065    /**
066     * A predicate for rule tree printing. Prevents SOEs by detecting and suppressing loops in the rule tree.
067     *
068     * @return a predicate
069     */
070    public static Predicate<Matcher> preventLoops() {
071        return new Predicate<Matcher>() {
072            private final Set<Matcher> visited = new HashSet<Matcher>();
073
074            public boolean apply(Matcher node) {
075                node = MatcherUtils.unwrap(node);
076                if (visited.contains(node)) {
077                    return false;
078                }
079                visited.add(node);
080                return true;
081            }
082        };
083    }
084
085    /**
086     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
087     * Enables printing of rule tracing log messages for all input in the given range of input lines.
088     *
089     * @param firstLine the number of the first input line to generate tracing message for
090     * @param lastLine  the number of the last input line to generate tracing message for
091     * @return a predicate
092     */
093    public static Predicate<Tuple2<Context<?>, Boolean>> lines(final int firstLine, final int lastLine) {
094        return new Predicate<Tuple2<Context<?>, Boolean>>() {
095            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
096                int line = tuple.a.getInputBuffer().getPosition(tuple.a.getCurrentIndex()).line;
097                return firstLine <= line && line <= lastLine;
098            }
099        };
100    }
101
102    /**
103     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
104     * Enables printing of rule tracing log messages for all input in the given range of input lines.
105     *
106     * @param firstLine the number of the first input line to generate tracing message for
107     * @return a predicate
108     */
109    public static Predicate<Tuple2<Context<?>, Boolean>> fromLine(final int firstLine) {
110        return new Predicate<Tuple2<Context<?>, Boolean>>() {
111            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
112                return tuple.a.getInputBuffer().getPosition(tuple.a.getCurrentIndex()).line >= firstLine;
113            }
114        };
115    }
116
117    /**
118     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
119     * Enables printing of rule tracing log messages for all input in the given range of input lines.
120     *
121     * @param lastLine  the number of the last input line to generate tracing message for
122     * @return a predicate
123     */
124    public static Predicate<Tuple2<Context<?>, Boolean>> untilLine(final int lastLine) {
125        return new Predicate<Tuple2<Context<?>, Boolean>>() {
126            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
127                return tuple.a.getInputBuffer().getPosition(tuple.a.getCurrentIndex()).line <= lastLine;
128            }
129        };
130    }
131
132    /**
133     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
134     * Enables printing of rule tracing log messages for all given rules and their sub rules.
135     *
136     * @param rules the rules to generate tracing message for
137     * @return a predicate
138     */
139    public static Predicate<Tuple2<Context<?>, Boolean>> rules(final Rule... rules) {
140        return new Predicate<Tuple2<Context<?>, Boolean>>() {
141            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
142                MatcherPath path = tuple.a.getPath();
143                for (Rule rule : rules) if (path.contains((Matcher) rule)) return true;
144                return false;
145            }
146        };
147    }
148
149    /**
150     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
151     * Enables printing of rule tracing log messages for all given rules (without their sub rules).
152     *
153     * @param rules the rules to generate tracing message for
154     * @return a predicate
155     */
156    public static Predicate<Tuple2<Context<?>, Boolean>> onlyRules(final Rule... rules) {
157        return new Predicate<Tuple2<Context<?>, Boolean>>() {
158            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
159                for (Rule rule : rules) if (tuple.a.getMatcher() == rule) return true;
160                return false;
161            }
162        };
163    }
164
165    /**
166     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
167     * Enables printing of rule tracing log messages for all sub rules of the given rules.
168     *
169     * @param rules the rules whose sub rules to generate tracing message for
170     * @return a predicate
171     */
172    public static Predicate<Tuple2<Context<?>, Boolean>> rulesBelow(final Rule... rules) {
173        return new Predicate<Tuple2<Context<?>, Boolean>>() {
174            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
175                MatcherPath path = tuple.a.getPath();
176                for (Rule rule : rules) {
177                    Matcher matcher = (Matcher) rule;
178                    if (tuple.a.getMatcher() != matcher && path.contains(matcher)) return true;
179                }
180                return false;
181            }
182        };
183    }
184
185    /**
186     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
187     * Enables printing of rule tracing log messages for all matched rules.
188     *
189     * @return a predicate
190     */
191    public static Predicate<Tuple2<Context<?>, Boolean>> onlyMatches() {
192        return new Predicate<Tuple2<Context<?>, Boolean>>() {
193            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
194                return tuple.b;
195            }
196        };
197    }
198
199    /**
200     * A predicate usable as a filter (element) of a {@link TracingParseRunner}.
201     * Enables printing of rule tracing log messages for all mismatched rules.
202     *
203     * @return a predicate
204     */
205    public static Predicate<Tuple2<Context<?>, Boolean>> onlyMismatches() {
206        return new Predicate<Tuple2<Context<?>, Boolean>>() {
207            public boolean apply(Tuple2<Context<?>, Boolean> tuple) {
208                return !tuple.b;
209            }
210        };
211    }
212
213}