/** * Copyright 2004-2016 Riccardo Solmi. All rights reserved. * This file is part of the Whole Platform. * * The Whole Platform is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Whole Platform is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>. */ package org.whole.lang.matchers; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.whole.lang.bindings.BindingManagerFactory; import org.whole.lang.bindings.IBindingManager; import org.whole.lang.bindings.IBindingScope; import org.whole.lang.commons.model.QuantifierEnum; import org.whole.lang.commons.model.Variable; import org.whole.lang.commons.parsers.CommonsDataTypePersistenceParser; import org.whole.lang.iterators.FilterByIndexRangeIterator; import org.whole.lang.iterators.IEntityIterator; import org.whole.lang.model.IEntity; import org.whole.lang.operations.ICloneContext; import org.whole.lang.reflect.DataKinds; import org.whole.lang.reflect.EntityDescriptor; import org.whole.lang.reflect.EntityKinds; import org.whole.lang.reflect.FeatureDescriptor; import org.whole.lang.util.BehaviorUtils; import org.whole.lang.util.BindingUtils; import org.whole.lang.util.DataTypeUtils; import org.whole.lang.util.EntityUtils; import org.whole.lang.util.ResourceUtils; import org.whole.lang.visitors.AbstractVisitor; import org.whole.lang.visitors.IVisitor; import org.whole.lang.visitors.VisitException; /** * @author Riccardo Solmi */ public class GenericMatcherFactory { public static final GenericMatcherFactory instance = new GenericMatcherFactory(); protected GenericMatcherFactory() { } public IVisitor isPlatformSubtypeOfMatcher(String edUri) { return new AbstractEntityDescriptorBasedMatcher(edUri) { public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !otherEd.isPlatformSupertypeOf(ed)) throw new VisitException(); } protected String predicateName() { return "isPlatformSubtypeOf"; } }; } public IVisitor isExtendedLanguageSubtypeOfMatcher(String edUri) { return new AbstractEntityDescriptorBasedMatcher(edUri) { public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !otherEd.isExtendedLanguageSupertypeOf(ed)) throw new VisitException(); } protected String predicateName() { return "isExtendedLanguageSubtypeOf"; } }; } public IVisitor isLanguageSubtypeOfMatcher(String edUri) { return new IsLanguageSubtypeOfMatcher(edUri); } public IVisitor isLanguageSubtypeOfMatcher(EntityDescriptor<?> ed) { return new IsLanguageSubtypeOfMatcher(ed); } public static class IsLanguageSubtypeOfMatcher extends AbstractEntityDescriptorBasedMatcher { public IsLanguageSubtypeOfMatcher(String edUri) { super(edUri); } public IsLanguageSubtypeOfMatcher(EntityDescriptor<?> ed) { super(ed); } public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !otherEd.isLanguageSupertypeOf(ed)) throw new VisitException(); } protected String predicateName() { return "isLanguageSubtypeOf"; } } public IVisitor isPlatformSupertypeOfMatcher(String edUri) { return new AbstractEntityDescriptorBasedMatcher(edUri) { public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !ed.isPlatformSupertypeOf(otherEd)) throw new VisitException(); } protected String predicateName() { return "isPlatformSupertypeOf"; } }; } public IVisitor isExtendedLanguageSupertypeOfMatcher(String edUri) { return new AbstractEntityDescriptorBasedMatcher(edUri) { public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !ed.isExtendedLanguageSupertypeOf(otherEd)) throw new VisitException(); } protected String predicateName() { return "isExtendedLanguageSupertypeOf"; } }; } public IVisitor isLanguageSupertypeOfMatcher(String edUri) { return new AbstractEntityDescriptorBasedMatcher(edUri) { public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !ed.isLanguageSupertypeOf(otherEd)) throw new VisitException(); } protected String predicateName() { return "isLanguageSupertypeOf"; } }; } public IVisitor hasTypeMatcher(String edUri) { return new HasTypeMatcher(edUri); } public IVisitor hasTypeMatcher(EntityDescriptor<?> ed) { return new HasTypeMatcher(ed); } public static class HasTypeMatcher extends AbstractEntityDescriptorBasedMatcher { public HasTypeMatcher(String edUri) { super(edUri); } public HasTypeMatcher(EntityDescriptor<?> ed) { super(ed); } public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetEntityDescriptor(); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !ed.equals(otherEd)) throw new VisitException(); } protected String predicateName() { return "hasType"; } } public IVisitor atTypeMatcher(String edUri) { return new AbstractEntityDescriptorBasedMatcher(edUri) { public void visit(IEntity entity) { EntityDescriptor<?> ed = entity.wGetParent().wGetEntityDescriptor(entity); EntityDescriptor<?> otherEd = getOtherEntityDescriptor(ed); if (otherEd == null || !ed.equals(otherEd)) throw new VisitException(); } protected String predicateName() { return "atType"; } }; } public IVisitor atFeatureMatcher(String fdUri) { return new AtFeatureMatcher(fdUri); } public IVisitor atFeatureMatcher(FeatureDescriptor fd) { return new AtFeatureMatcher(fd); } public static class AtFeatureMatcher extends AbstractFeatureDescriptorBasedMatcher { public AtFeatureMatcher(String fdUri) { super(fdUri); } public AtFeatureMatcher(FeatureDescriptor fd) { super(fd); } public void visit(IEntity entity) { try { FeatureDescriptor fd = entity.wGetParent().wGetFeatureDescriptor(entity); FeatureDescriptor otherFd = getOtherFeatureDescriptor(fd); if (otherFd != null && fd.equals(otherFd)) return; } catch (RuntimeException e) { } throw new VisitException(); } protected String predicateName() { return "atFeature"; } } public static abstract class AbstractEntityDescriptorBasedMatcher extends AbstractVisitor { public final String edUri; protected EntityDescriptor<?> ed; public AbstractEntityDescriptorBasedMatcher(String edUri) { this.edUri = edUri; } public AbstractEntityDescriptorBasedMatcher(EntityDescriptor<?> ed) { this(ed.getURI()); this.ed = ed; } protected EntityDescriptor<?> getOtherEntityDescriptor(EntityDescriptor<?> selfEd) { if (ed == null) { if (!ResourceUtils.hasFragmentPart(edUri)) return selfEd.getEntityDescriptorEnum().valueOf(edUri); String contextUri = getBindings().wIsSet("contextURI") ? getBindings().wStringValue("contextURI") : null; ed = CommonsDataTypePersistenceParser.getEntityDescriptor(edUri, true, contextUri); } return ed; } public void toString(StringBuilder sb) { sb.append(predicateName()); sb.append("("); sb.append(edUri); sb.append(")"); } protected abstract String predicateName(); } public static abstract class AbstractFeatureDescriptorBasedMatcher extends AbstractVisitor { public final String fdUri; protected FeatureDescriptor fd; public AbstractFeatureDescriptorBasedMatcher(String edUri) { this.fdUri = edUri; } public AbstractFeatureDescriptorBasedMatcher(FeatureDescriptor fd) { this(fd.getURI()); this.fd = fd; } protected FeatureDescriptor getOtherFeatureDescriptor(FeatureDescriptor selfFd) { if (fd == null) { if (!ResourceUtils.hasFragmentPart(fdUri)) return selfFd.getFeatureDescriptorEnum().valueOf(fdUri); String contextUri = getBindings().wIsSet("contextURI") ? getBindings().wStringValue("contextURI") : null; fd = CommonsDataTypePersistenceParser.getFeatureDescriptor(fdUri, true, contextUri); } return fd; } public void toString(StringBuilder sb) { sb.append(predicateName()); sb.append("("); sb.append(fdUri); sb.append(")"); } protected abstract String predicateName(); } public IVisitor isLanguageMatcher(final String languageURI) { return new AbstractVisitor() { public void visit(IEntity entity) { if (!languageURI.equals(entity.wGetLanguageKit().getURI())) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("isLanguage("); sb.append(languageURI); sb.append(")"); } }; } public IVisitor hasKindMatcher(final EntityKinds kind) { return new AbstractVisitor() { public void visit(IEntity entity) { if (!kind.equals(entity.wGetEntityKind())) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("hasKind("); sb.append(kind); sb.append(")"); } }; } private static IVisitor matchImplVisitor; public IVisitor isImplMatcher() { if (matchImplVisitor == null) matchImplVisitor = new AbstractVisitor() { public void visit(IEntity entity) { if (!EntityUtils.isNotResolver(entity)) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("isImpl()"); } }; return matchImplVisitor; } private static IVisitor matchResolverVisitor; public IVisitor isResolverMatcher() { if (matchResolverVisitor == null) matchResolverVisitor = new AbstractVisitor() { public void visit(IEntity entity) { if (!EntityUtils.isResolver(entity)) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("isResolver()"); } }; return matchResolverVisitor; } private static IVisitor matchVariableVisitor; public IVisitor isVariableMatcher() { if (matchVariableVisitor == null) matchVariableVisitor = new AbstractVisitor() { public void visit(IEntity entity) { if (!EntityUtils.isVariable(entity)) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("isVariable()"); } }; return matchVariableVisitor; } private static IVisitor matchFragmentVisitor; public IVisitor isFragmentMatcher() { if (matchFragmentVisitor == null) matchFragmentVisitor = new AbstractVisitor() { public void visit(IEntity entity) { if (!EntityUtils.isFragment(entity)) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("isFragment()"); } }; return matchFragmentVisitor; } public IVisitor atHostStageMatcher() { return new AbstractVisitor() { public void visit(IEntity entity) { if (getOperation().getStage() > 0) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("atHostStage()"); } }; } public IVisitor atTemplateStageMatcher() { return new AbstractVisitor() { public void visit(IEntity entity) { if (getOperation().getStage() <= 0) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("atTemplateStage()"); } }; } public IVisitor atStageMatcher(final int stage) { return new AbstractVisitor() { public void visit(IEntity entity) { if (getOperation().getStage() != stage) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("atStage("); sb.append(stage); sb.append(")"); } }; } public IVisitor atStageVariableMatcher(final String name) { if (BindingUtils.hasEnvironmentPart(name)) return new AbstractVisitor() { public void visit(IEntity entity) { final IBindingManager bm = BindingUtils.getEnvironment(getBindings(), name); final String varName = BindingUtils.getVariableName(name); if (bm.wIsSet(varName)) { IEntity value = bm.wGet(name); DataKinds dataKind = DataTypeUtils.getDataKind(value); if (!dataKind.isInt() || value.wIntValue() != getOperation().getStage()) throw new VisitException(); } else bm.wDef(varName, entity); } public void toString(StringBuilder sb) { sb.append("atStageVariable("); sb.append(name); sb.append(")"); } }; else return new AbstractVisitor() { public void visit(IEntity entity) { final IBindingManager bm = getBindings(); if (bm.wIsSet(name)) { IEntity value = bm.wGet(name); DataKinds dataKind = DataTypeUtils.getDataKind(value); if (!dataKind.isInt() || value.wIntValue() != getOperation().getStage()) throw new VisitException(); } else bm.wDef(name, entity); } public void toString(StringBuilder sb) { sb.append("atStageVariable("); sb.append(name); sb.append(")"); } }; } public IVisitor asVariableMatcher(final String name) { if (BindingUtils.hasEnvironmentPart(name)) return new AbstractVisitor() { public void visit(IEntity entity) { final IBindingManager bm = BindingUtils.getEnvironment(getBindings(), name); final String varName = BindingUtils.getVariableName(name); if (bm.wIsSet(varName)) { if (!Matcher.match(bm.wGet(varName), entity)) throw new VisitException(); } else bm.wDef(varName, entity); } public void toString(StringBuilder sb) { sb.append("asVariable("); sb.append(name); sb.append(")"); } }; else return new AbstractVisitor() { public void visit(IEntity entity) { final IBindingManager bm = getBindings(); if (bm.wIsSet(name)) { if (!Matcher.match(bm.wGet(name), entity)) throw new VisitException(); } else bm.wDef(name, entity); } public void toString(StringBuilder sb) { sb.append("asVariable("); sb.append(name); sb.append(")"); } }; } public IVisitor defineVariableMatcher(final String name) { if (BindingUtils.hasEnvironmentPart(name)) return new AbstractVisitor() { public void visit(IEntity entity) { BindingUtils.wDef(getBindings(), name, entity); } public void toString(StringBuilder sb) { sb.append("defineVariable("); sb.append(name); sb.append(")"); } }; else return new AbstractVisitor() { public void visit(IEntity entity) { getBindings().wDef(name, entity); } public void toString(StringBuilder sb) { sb.append("defineVariable("); sb.append(name); sb.append(")"); } }; } public IVisitor atIndexMatcher(final int index) { return new AbstractVisitor() { public void visit(IEntity entity) { try { IEntity parent = entity.wGetParent(); int indexOf = parent.wIndexOf(entity); if (index < 0) indexOf -= parent.wSize(); if (indexOf == index) return; } catch (RuntimeException e) { } throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("atIndex("); if (index < 0) sb.append("size"); sb.append(index); sb.append(")"); } }; } public IVisitor matchIteratorIndexVariable(FilterByIndexRangeIterator<?> iterator, String name) { if (BindingUtils.hasEnvironmentPart(name)) return new MatchIteratorIndexLocalVariableVisitor(iterator, name); else return new MatchIteratorIndexVariableVisitor(iterator, name); } public static class MatchIteratorIndexLocalVariableVisitor extends AbstractVisitor { protected FilterByIndexRangeIterator<?> iterator; protected String name; public MatchIteratorIndexLocalVariableVisitor(FilterByIndexRangeIterator<?> iterator, String name) { this.iterator = iterator; this.name = name; } public IVisitor clone(ICloneContext cc) { MatchIteratorIndexVariableVisitor visitor = (MatchIteratorIndexVariableVisitor) super.clone(cc); visitor.iterator = cc.clone(iterator); return visitor; } @Override public void setBindings(IBindingManager bm) { super.setBindings(bm); iterator.setBindings(bm); } public void visit(IEntity entity) { int predicateIndex = iterator.predicateIndex(this); final IBindingManager bm = getBindings(); if (bm.wIsSet(name)) { IEntity value = bm.wGet(name); DataKinds dataKind = DataTypeUtils.getDataKind(value); if (!dataKind.isInt() || value.wIntValue() != predicateIndex) throw new VisitException(); } else bm.wDef(name, BindingManagerFactory.instance.createValue(predicateIndex)); } public void toString(StringBuilder sb) { sb.append("matchIteratorIndexVariable(index as"); sb.append(name); sb.append(")"); } }; public static class MatchIteratorIndexVariableVisitor extends MatchIteratorIndexLocalVariableVisitor { public MatchIteratorIndexVariableVisitor(FilterByIndexRangeIterator<?> iterator, String name) { super(iterator, name); } public void visit(IEntity entity) { int predicateIndex = iterator.predicateIndex(this); final IBindingManager bm = BindingUtils.getEnvironment(getBindings(), name); final String varName = BindingUtils.getVariableName(name); if (bm.wIsSet(varName)) { IEntity value = bm.wGet(varName); DataKinds dataKind = DataTypeUtils.getDataKind(value); if (!dataKind.isInt() || value.wIntValue() != predicateIndex) throw new VisitException(); } else bm.wDef(varName, BindingManagerFactory.instance.createValue(predicateIndex)); } }; public IVisitor matchIteratorIndex(FilterByIndexRangeIterator<?> iterator, int index) { return new MatchIteratorIndexVisitor(iterator, index); } public static class MatchIteratorIndexVisitor extends AbstractVisitor { private FilterByIndexRangeIterator<?> iterator; private int index; public MatchIteratorIndexVisitor(FilterByIndexRangeIterator<?> iterator, int index) { this.iterator = iterator; this.index = index; } public IVisitor clone(ICloneContext cc) { MatchIteratorIndexVisitor visitor = (MatchIteratorIndexVisitor) super.clone(cc); visitor.iterator = cc.clone(iterator); return visitor; } @Override public void setBindings(IBindingManager bm) { super.setBindings(bm); iterator.setBindings(bm); } public void visit(IEntity entity) { if (iterator.predicateIndex(this) == index) return; else throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("matchIteratorIndex("); sb.append(index); sb.append(")"); } } public IVisitor matchIteratorIndexRange(FilterByIndexRangeIterator<?> iterator, int startIndex, int endIndex) { return new MatchIteratorIndexRangeVisitor(iterator, startIndex, endIndex); } public static class MatchIteratorIndexRangeVisitor extends AbstractVisitor { private FilterByIndexRangeIterator<?> iterator; private int startIndex, endIndex; public MatchIteratorIndexRangeVisitor(FilterByIndexRangeIterator<?> iterator, int startIndex, int endIndex) { this.iterator = iterator; this.startIndex = startIndex; this.endIndex = endIndex; } public IVisitor clone(ICloneContext cc) { MatchIteratorIndexRangeVisitor visitor = (MatchIteratorIndexRangeVisitor) super.clone(cc); visitor.iterator = cc.clone(iterator); return visitor; } @Override public void setBindings(IBindingManager bm) { super.setBindings(bm); iterator.setBindings(bm); } public void visit(IEntity entity) { int index = iterator.predicateIndex(this); if (startIndex <= index && index <= endIndex) return; else throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("matchIteratorIndexRange("); sb.append(startIndex); sb.append(".."); sb.append(endIndex == Integer.MAX_VALUE ? "*" : String.valueOf(endIndex)); sb.append(")"); } }; public static IVisitor evalTrue(final IEntity program) { return new AbstractVisitor() { public void visit(IEntity entity) { IBindingManager bm = getBindings(); IEntity selfEntity = bm.wGet("self"); if (selfEntity != entity) bm.wDef("self", entity); IEntity result = BehaviorUtils.evaluate(program, 0, bm); if (selfEntity != entity ) { if (selfEntity != null) bm.wDef("self", selfEntity); else bm.wUnset("self"); } if (result == null || !DataTypeUtils.getDataKind(result).isBoolean() || !result.wBooleanValue()) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("evalTrue("); sb.append(program);//TODO startOf sb.append(")"); } }; } public IVisitor match(final IEntity pattern) { return new AbstractVisitor() { public void visit(IEntity entity) { if (!Matcher.match(pattern, entity)) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("match("); sb.append(pattern); //TODO startOf sb.append(")"); } }; } public IVisitor matchInScope(final IEntity pattern) { return new AbstractVisitor() { public void visit(IEntity entity) { if (!Matcher.match(pattern, entity, getBindings())) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("match("); sb.append(pattern); //TODO startOf sb.append(")"); } }; } public IVisitor containsMatch(final IEntity pattern) { return new AbstractVisitor() { public void visit(IEntity entity) { if (!Matcher.containsMatch(pattern, entity)) throw new VisitException(); } public void toString(StringBuilder sb) { sb.append("containsMatch("); sb.append(pattern); //TODO startOf sb.append(")"); } }; } public IVisitor match(final IEntityIterator<?> iterator) { return new MatchVisitor(iterator); } public static class MatchVisitor extends AbstractVisitor { private IEntityIterator<?> iterator; public MatchVisitor(IEntityIterator<?> iterator) { this.iterator = iterator; } public IVisitor clone(ICloneContext cc) { MatchVisitor visitor = (MatchVisitor) super.clone(cc); visitor.iterator = cc.clone(iterator); return visitor; } public void visit(IEntity entity) { iterator.reset(entity); if (!iterator.hasNext()) throw new VisitException(); iterator.next(); // merge lookahead bindings } @Override public void setBindings(IBindingManager bm) { super.setBindings(bm); iterator.setBindings(bm); } public void toString(StringBuilder sb) { sb.append("match("); sb.append(iterator); sb.append(")"); } } public IVisitor rename(final Map<String, String> nameMap) { return new AbstractVariableVisitor() { public void visitVariable(Variable variable) { String oldName = variable.getVarName().getValue(); String newName = nameMap.get(oldName); if (newName != null) variable.getVarName().setValue(newName); } }; } public IVisitor rename(final String oldName, final String newName) { return new AbstractVariableVisitor() { public void visitVariable(Variable variable) { if (variable.getVarName().getValue().equals(oldName)) variable.getVarName().setValue(newName); } }; } // NB substitute a copy of the binding values public IVisitor substitute(final IBindingScope bindings) { return substitute(bindings, BindingManagerFactory.instance.createVoidScope()); } // NB substitute a copy of the binding values public IVisitor substitute(final IBindingScope inBindings, final IBindingScope outBindings) { return new AbstractVariableVisitor() { private Set<Variable> vars = new HashSet<Variable>(); public void visitVariable(Variable variable) { if (!EntityUtils.hasParent(variable) || !vars.add(variable)) return; String varName = variable.getVarName().getValue(); IEntity value = inBindings.wGet(varName); if (value != null && !BindingManagerFactory.instance.isVoid(value)) { boolean isInline = EntityUtils.isInlineVariable(variable); EntityDescriptor<?> varType = variable.getVarType().getValue(); if (!isInline) value = EntityUtils.convertCloneIfParented(value, varType);//TODO convertCloneIfReparenting variable reference outBindings.wDef(varName, value); //TODO if has not a parent and has only one inverseAdjacent use it and use convertCloneIfReparenting IEntity parentEntity = variable.wGetParent(); int variableIndex = parentEntity.wIndexOf(variable); QuantifierEnum.Value quantifierValue = variable.getQuantifier().getValue(); boolean isCompositeVar = quantifierValue.isComposite(); if (isCompositeVar) variable.getQuantifier().setValue(quantifierValue.toOptional()); //TODO ? use EntityUtils.convert(value, varType?) instead of cloneIfParented if (isInline) { if (!isCompositeVar) parentEntity.wRemove(variableIndex); for (int i=0, size=value.wSize(); i<size; i++) parentEntity.wAdd(variableIndex+i, EntityUtils.clone(value.wGet(i))); } else if (isCompositeVar) parentEntity.wAdd(variableIndex, value); else parentEntity.wSet(variableIndex, value); } } }; } public IVisitor rewrite(final IEntity oldPattern, final IEntity newPattern, final boolean includeAdjacents) { return new AbstractVisitor() { public void visit(IEntity entity) { IBindingManager bindings = BindingManagerFactory.instance.createBindingManager(); if (!Matcher.match(oldPattern, entity, bindings)) throw new VisitException(); IEntity rewritePattern = EntityUtils.clone(newPattern); if (!entity.wGetParent().wSet(entity, rewritePattern)) throw new VisitException(); Matcher.substitute(rewritePattern, bindings, includeAdjacents); } }; } public static abstract class AbstractVariableVisitor extends AbstractVisitor { public void visit(IEntity entity) { IEntity adaptee = entity.wGetAdaptee(false); if (EntityUtils.isVariable(adaptee.wGetEntityDescriptor())) visitVariable((Variable) adaptee); } public abstract void visitVariable(Variable entity); } }