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.matchers; 018 019import org.parboiled.MatcherContext; 020import org.parboiled.Rule; 021import org.parboiled.matchervisitors.MatcherVisitor; 022import org.parboiled.support.Var; 023import org.parboiled.support.Var; 024 025import java.util.List; 026 027import static org.parboiled.common.Preconditions.checkArgNotNull; 028 029/** 030 * Special wrapping matcher that manages the creation and destruction of execution frames for a number of action vars. 031 */ 032public class VarFramingMatcher implements Matcher { 033 private final Matcher inner; 034 private final Var[] variables; 035 036 public VarFramingMatcher(Rule inner, Var[] variables) { 037 this.inner = checkArgNotNull((Matcher)inner, "inner"); 038 this.variables = checkArgNotNull(variables, "variables"); 039 } 040 041 public <V> boolean match(MatcherContext<V> context) { 042 for (Var var : variables) { 043 var.enterFrame(); 044 } 045 046 boolean matched = inner.match(context); 047 048 for (Var var : variables) { 049 var.exitFrame(); 050 } 051 052 return matched; 053 } 054 055 // GraphNode 056 057 public List<Matcher> getChildren() { 058 return inner.getChildren(); 059 } 060 061 // Rule 062 063 public Rule label(String label) { 064 return new VarFramingMatcher(inner.label(label), variables); 065 } 066 067 public Rule suppressNode() { 068 return new VarFramingMatcher(inner.suppressNode(), variables); 069 } 070 071 public Rule suppressSubnodes() { 072 return new VarFramingMatcher(inner.suppressSubnodes(), variables); 073 } 074 075 public Rule skipNode() { 076 return new VarFramingMatcher(inner.skipNode(), variables); 077 } 078 079 public Rule memoMismatches() { 080 return new VarFramingMatcher(inner.memoMismatches(), variables); 081 } 082 083 // Matcher 084 085 public String getLabel() {return inner.getLabel();} 086 087 public boolean hasCustomLabel() {return inner.hasCustomLabel();} 088 089 public boolean isNodeSuppressed() {return inner.isNodeSuppressed();} 090 091 public boolean areSubnodesSuppressed() {return inner.areSubnodesSuppressed();} 092 093 public boolean isNodeSkipped() {return inner.isNodeSkipped();} 094 095 public boolean areMismatchesMemoed() { return inner.areMismatchesMemoed(); } 096 097 public void setTag(Object tagObject) { inner.setTag(tagObject); } 098 099 public Object getTag() { return inner.getTag(); } 100 101 public MatcherContext getSubContext(MatcherContext context) { 102 MatcherContext subContext = inner.getSubContext(context); 103 subContext.setMatcher(this); // we need to inject ourselves here otherwise we get cut out 104 return subContext; 105 } 106 107 public <R> R accept(MatcherVisitor<R> visitor) { 108 checkArgNotNull(visitor, "visitor"); 109 return inner.accept(visitor); 110 } 111 112 @Override 113 public String toString() { return inner.toString(); } 114 115 /** 116 * Retrieves the innermost Matcher that is not a VarFramingMatcher. 117 * 118 * @param matcher the matcher to unwrap 119 * @return the given instance if it is not a VarFramingMatcher, otherwise the innermost Matcher 120 */ 121 public static Matcher unwrap(Matcher matcher) { 122 if (matcher instanceof VarFramingMatcher) { 123 VarFramingMatcher varFramingMatcher = (VarFramingMatcher) matcher; 124 return unwrap(varFramingMatcher.inner); 125 } 126 return matcher; 127 } 128 129}