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}