/**
* 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.Collection;
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.Variable;
import org.whole.lang.commons.reflect.CommonsFeatureDescriptorEnum;
import org.whole.lang.iterators.AbstractPatternFilterIterator;
import org.whole.lang.iterators.IteratorFactory;
import org.whole.lang.model.IEntity;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.reflect.EntityKinds;
import org.whole.lang.reflect.FeatureDescriptor;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.visitors.GenericTraversalFactory;
import org.whole.lang.visitors.ITraversalFilter;
import org.whole.lang.visitors.IVisitor;
import org.whole.lang.visitors.TraverseAllFilter;
import org.whole.lang.visitors.VisitException;
/**
* @author Riccardo Solmi
*/
public class Matcher {
public static IEntity find(EntityKinds kind, IEntity model, boolean includeAdjacents) {
GenericMatcherFactory mf = GenericMatcherFactory.instance;
return find(mf.hasKindMatcher(kind), model, includeAdjacents);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E find(EntityDescriptor<E> descriptor, IEntity model, boolean includeAdjacents) {
GenericMatcherFactory mf = GenericMatcherFactory.instance;
return (E) find(mf.hasTypeMatcher(descriptor), model, includeAdjacents);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E find(E pattern, IEntity model, boolean includeAdjacents) {
GenericMatcherFactory mf = GenericMatcherFactory.instance;
return (E) find(mf.match(pattern), model, includeAdjacents);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E find(E pattern, IEntity model, IBindingManager bindings, boolean includeAdjacents) {
GenericMatcherFactory mf = GenericMatcherFactory.instance;
IVisitor mv = mf.matchInScope(pattern);
mv.setBindings(bindings);
return (E) find(mv, model, includeAdjacents);
}
public static IEntity find(IVisitor matcherVisitor, IEntity model, boolean includeAdjacents) {
GenericTraversalFactory tf = GenericTraversalFactory.instance;
Set<IEntity> c = new HashSet<IEntity>();
try {
tf.onceTopDown(tf.collect(matcherVisitor, c), includeAdjacents).visit(model);
} catch (VisitException e) {
}
if (c.isEmpty())
return null;
else
return c.iterator().next();
}
public static IEntity findAncestor(EntityKinds kind, IEntity model) {
return findAncestor(GenericMatcherFactory.instance.hasKindMatcher(kind), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findAncestor(EntityDescriptor<E> descriptor, IEntity model) {
return (E) findAncestor(GenericMatcherFactory.instance.hasTypeMatcher(descriptor), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findAncestor(E pattern, IEntity model) {
return (E) findAncestor(GenericMatcherFactory.instance.match(pattern), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findAncestor(E pattern, IEntity model, IBindingManager bindings) {
IVisitor mv = GenericMatcherFactory.instance.matchInScope(pattern);
mv.setBindings(bindings);
return (E) findAncestor(mv, model);
}
public static IEntity findAncestor(IVisitor matcherVisitor, IEntity model) {
AbstractPatternFilterIterator<IEntity> i = IteratorFactory.ancestorMatcherIterator().withPattern(matcherVisitor);
i.reset(model);
for (IEntity e : i)
return e;
return null;
}
public static IEntity findAncestorOrSelf(EntityKinds kind, IEntity model) {
return findAncestorOrSelf(GenericMatcherFactory.instance.hasKindMatcher(kind), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findAncestorOrSelf(EntityDescriptor<E> descriptor, IEntity model) {
return (E) findAncestorOrSelf(GenericMatcherFactory.instance.hasTypeMatcher(descriptor), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findAncestorOrSelf(E pattern, IEntity model) {
return (E) findAncestorOrSelf(GenericMatcherFactory.instance.match(pattern), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findAncestorOrSelf(E pattern, IEntity model, IBindingManager bindings) {
IVisitor mv = GenericMatcherFactory.instance.matchInScope(pattern);
mv.setBindings(bindings);
return (E) findAncestorOrSelf(mv, model);
}
public static IEntity findAncestorOrSelf(IVisitor matcherVisitor, IEntity model) {
AbstractPatternFilterIterator<IEntity> i = IteratorFactory.ancestorOrSelfMatcherIterator().withPattern(matcherVisitor);
i.reset(model);
for (IEntity e : i)
return e;
return null;
}
public static IEntity findChild(EntityKinds kind, IEntity model) {
return findChild(GenericMatcherFactory.instance.hasKindMatcher(kind), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findChild(EntityDescriptor<E> descriptor, IEntity model) {
return (E) findChild(GenericMatcherFactory.instance.hasTypeMatcher(descriptor), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findChild(E pattern, IEntity model) {
return (E) findChild(GenericMatcherFactory.instance.match(pattern), model);
}
@SuppressWarnings("unchecked")
public static <E extends IEntity> E findChild(E pattern, IEntity model, IBindingManager bindings) {
IVisitor mv = GenericMatcherFactory.instance.matchInScope(pattern);
mv.setBindings(bindings);
return (E) findChild(mv, model);
}
public static IEntity findChild(IVisitor matcherVisitor, IEntity model) {
AbstractPatternFilterIterator<IEntity> i = IteratorFactory.childMatcherIterator().withPattern(matcherVisitor);
i.reset(model);
for (IEntity e : i)
return e;
return null;
}
public static <E extends IEntity> Collection<E> findAll(EntityDescriptor<E> descriptor, IEntity model, boolean includeAdjacents) {
GenericMatcherFactory mf = GenericMatcherFactory.instance;
return findAll(mf.hasTypeMatcher(descriptor), model, new HashSet<E>(), includeAdjacents);
}
public static <E extends IEntity> Collection<E> findAll(IEntity pattern, IEntity model, boolean includeAdjacents) {
GenericMatcherFactory mf = GenericMatcherFactory.instance;
return findAll(mf.match(pattern), model, new HashSet<E>(), includeAdjacents);
}
public static <E extends IEntity> Collection<E> findAll(IVisitor matcherVisitor, IEntity model, Collection<E> result, boolean includeAdjacents) {
GenericTraversalFactory tf = GenericTraversalFactory.instance;
tf.topDownUntil(tf.collect(matcherVisitor, result), includeAdjacents).visit(model);
return result;
}
public static int indexOf(IEntity pattern, IEntity model) {
GenericMatcherFactory mf = GenericMatcherFactory.instance;
return indexOf(mf.match(pattern), model);
}
public static int indexOf(IVisitor matcherVisitor, IEntity model) {
GenericTraversalFactory tf = GenericTraversalFactory.instance;
try {
Set<IEntity> c = new HashSet<IEntity>();
tf.traverseOne(tf.collect(matcherVisitor, c), true).visit(model);
return model.wIndexOf(c.iterator().next());
} catch (VisitException e) {
return -1;
}
}
public static boolean match(EntityKinds kind, IEntity model) {
return model.wGetEntityKind().equals(kind);
}
public static boolean match(EntityKinds kind, IEntity model, IBindingScope bindings, String name) {
if (match(kind, model)) {
bindings.wDef(name, model);
return true;
}
return false;
}
public static boolean matchAny(IEntity model, EntityDescriptor<?>... descriptors) {
EntityDescriptor<?> ed = model.wGetEntityDescriptor();
for (EntityDescriptor<?> descriptor : descriptors) {
if (ed.equals(descriptor))
return true;
}
return false;
}
public static boolean matchAnyImpl(IEntity model, EntityDescriptor<?>... descriptors) {
return matchAny(model.wGetAdaptee(true), descriptors);
}
public static boolean matchImpl(EntityDescriptor<?> descriptor, IEntity model) {
return match(descriptor, model.wGetAdaptee(true));
}
public static boolean matchAtFeature(FeatureDescriptor fd, IEntity model) {
return EntityUtils.hasParent(model) && fd.equals(model.wGetParent().wGetFeatureDescriptor(model));
}
public static boolean matchAtEntityFeature(FeatureDescriptor efd, IEntity model) {
return matchAtEntityFeature(efd.getParentEntityDescriptor(), efd, model);
}
public static boolean matchAtEntityFeature(EntityDescriptor<?> ed, FeatureDescriptor fd, IEntity model) {
IEntity parent = model.wGetParent();
return !EntityUtils.isNull(parent) && isAssignableAsIsFrom(ed, parent) && fd.equals(parent.wGetFeatureDescriptor(model));
}
public static boolean isAssignableAsIsFrom(EntityDescriptor<?> descriptor, IEntity model) {
return descriptor.isLanguageSupertypeOf(model.wGetEntityDescriptor());
}
public static boolean isAssignableFrom(EntityDescriptor<?> descriptor, IEntity model) {
return descriptor.isPlatformSupertypeOf(model.wGetEntityDescriptor());
}
public static boolean match(EntityDescriptor<?> descriptor, IEntity model) {
return model.wGetEntityDescriptor().equals(descriptor);
}
public static boolean matchImplAndBind(EntityDescriptor<?> descriptor, IEntity model, IBindingScope bindings, String name) {
if (matchImpl(descriptor, model)) {
bindings.wDef(name, model);
return true;
}
return false;
}
public static boolean forceMatch(IEntity pattern, IEntity model) {
return Matcher.forceMatch(pattern, model, TraverseAllFilter.instance);
}
public static boolean forceMatch(IEntity pattern, IEntity model, ITraversalFilter traversalFilter) {
try {
pattern.wAccept(new GenericResolverForcedMatcher(BindingManagerFactory.instance.createBindingManager(), traversalFilter), model);
return true;
} catch (MatchException e) {
return false;
} catch (VisitException e) {
return false;
}
}
public static boolean forceMatchUsingVariables(IEntity pattern, IEntity model) {
return Matcher.forceMatchUsingVariables(pattern, model, TraverseAllFilter.instance);
}
public static boolean forceMatchUsingVariables(IEntity pattern, IEntity model, ITraversalFilter traversalFilter) {
try {
IBindingManager bm = BindingManagerFactory.instance.createBindingManager();
final Set<String> boundNames = new HashSet<String>();
bm.wDefValue("boundNames", boundNames);
model.wAccept(new AbstractGenericForcedMatcher(bm, traversalFilter) {
public void matchEntityVariable(IEntity pattern, IEntity model) {
if (EntityUtils.isVariable(model)) {
IEntity varName = pattern.wGet(CommonsFeatureDescriptorEnum.varName);
IEntity varType = pattern.wGet(CommonsFeatureDescriptorEnum.varType);
if (varName.wEquals(model.wGet(CommonsFeatureDescriptorEnum.varName)) &&
varType.wEquals(model.wGet(CommonsFeatureDescriptorEnum.varType)))
boundNames.add(varName.wStringValue());
}
}
}, pattern);
pattern.wAccept(new GenericVariableForcedMatcher(bm, traversalFilter), model);
return true;
} catch (MatchException e) {
return false;
} catch (VisitException e) {
return false;
}
}
public static boolean match(IEntity pattern, IEntity model) {
return Matcher.match(pattern, model, TraverseAllFilter.instance);
}
public static boolean match(IEntity pattern, IEntity model, ITraversalFilter traversalFilter) {
try {
pattern.wAccept(new GenericMatcher(BindingManagerFactory.instance.createBindingManager(), traversalFilter), model);
return true;
} catch (MatchException e) {
return false;
} catch (VisitException e) {
return false;
}
}
public static boolean match(IEntity pattern, IEntity model, IBindingManager bindings) {
boolean mergeScope = true;
try {
bindings.wEnterScope();
pattern.wAccept(new GenericMatcher(bindings), model);
} catch (MatchException e) {
mergeScope = false;
} catch (VisitException e) {
mergeScope = false;
} finally {
bindings.wExitScope(mergeScope);
}
return mergeScope;
}
public static boolean match(IVisitor matcherVisitor, IEntity model) {
try {
matcherVisitor.visit(model);
return true;
} catch (MatchException e) {
return false;
} catch (VisitException e) {
return false;
}
}
public static boolean containsMatch(IEntity pattern, IEntity model) {
try {
pattern.wAccept(new GenericPatternMatcher(), model);
return true;
} catch (MatchException e) {
return false;
} catch (VisitException e) {
return false;
}
}
public static boolean containsMatch(IEntity pattern, IEntity model, IBindingManager bindings) {
boolean mergeScope = true;
try {
bindings.wEnterScope();
pattern.wAccept(new GenericPatternMatcher(bindings), model);
} catch (MatchException e) {
mergeScope = false;
} catch (VisitException e) {
mergeScope = false;
} finally {
bindings.wExitScope(mergeScope);
}
return mergeScope;
}
public static boolean learnMatch(IEntity pattern, IEntity model) {
try {
pattern.wAccept(new GenericLearningPatternMatcher(), model);
return true;
} catch (MatchException e) {
return false;
} catch (VisitException e) {
return false;
}
}
public static boolean learnMatch(IEntity pattern, IEntity model, IBindingManager bindings) {
boolean mergeScope = true;
try {
bindings.wEnterScope();
pattern.wAccept(new GenericLearningPatternMatcher(bindings), model);
} catch (MatchException e) {
mergeScope = false;
} catch (VisitException e) {
mergeScope = false;
} finally {
bindings.wExitScope(mergeScope);
}
return mergeScope;
}
public static void rename(IEntity pattern, final Map<String, String> nameMap, boolean includeAdjacents) {
GenericTraversalFactory.instance.topDown(
GenericMatcherFactory.instance.rename(nameMap), includeAdjacents).visit(pattern);
}
public static void rename(IEntity pattern, final String oldName, final String newName, boolean includeAdjacents) {
GenericTraversalFactory.instance.topDown(
GenericMatcherFactory.instance.rename(oldName, newName), includeAdjacents).visit(pattern);
}
public static void substitute(IEntity pattern, final IBindingScope bindings, boolean includeAdjacents) {
GenericTraversalFactory.instance.topDown(
GenericMatcherFactory.instance.substitute(bindings), includeAdjacents).visit(pattern);
}
public static void substitute(IEntity pattern, final IBindingScope inBindings, final IBindingScope outBindings, boolean includeAdjacents) {
GenericTraversalFactory.instance.topDown(
GenericMatcherFactory.instance.substitute(inBindings, outBindings), includeAdjacents).visit(pattern);
}
public static boolean removeVars(IEntity pattern, boolean force) {
boolean allVarsAreOptional = true;
AbstractPatternFilterIterator<IEntity> variableIterator = IteratorFactory.descendantOrSelfMatcherIterator()
.withPattern(GenericMatcherFactory.instance.isVariableMatcher());
variableIterator.reset(pattern);
for (IEntity variableAdapter : variableIterator) {
Variable variable = (Variable) variableAdapter.wGetAdaptee(false);
boolean isOptional = variable.getQuantifier().getValue().isOptional();
allVarsAreOptional &= isOptional;
if (force || isOptional)
variableIterator.remove();
}
return allVarsAreOptional;
}
public static boolean removeVars(IEntity pattern, final Set<String> names, boolean useNamesComplement) {
if (names.isEmpty() && !useNamesComplement)
return true;
boolean allVarsAreOptional = true;
AbstractPatternFilterIterator<IEntity> variableIterator = IteratorFactory.descendantOrSelfMatcherIterator()
.withPattern(GenericMatcherFactory.instance.isVariableMatcher());
variableIterator.reset(pattern);
for (IEntity variableAdapter : variableIterator) {
Variable variable = (Variable) variableAdapter.wGetAdaptee(false);
if (names.contains(variable.getVarName().getValue()) ^ useNamesComplement) {
boolean isOptional = variable.getQuantifier().getValue().isOptional();
allVarsAreOptional &= isOptional;
if (isOptional)
variableIterator.remove();
}
}
return allVarsAreOptional;
}
public static Set<String> vars(IEntity pattern, boolean includeOptionals) {
Set<String> names = new HashSet<String>();
AbstractPatternFilterIterator<IEntity> variableIterator = IteratorFactory.descendantOrSelfMatcherIterator()
.withPattern(GenericMatcherFactory.instance.isVariableMatcher());
variableIterator.reset(pattern);
for (IEntity variableAdapter : variableIterator) {
Variable variable = (Variable) variableAdapter.wGetAdaptee(false);
if (includeOptionals || !variable.getQuantifier().getValue().isOptional())
names.add(variable.getVarName().getValue());
}
return names;
}
}