/**
* 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 org.whole.lang.bindings.BindingManagerFactory;
import org.whole.lang.bindings.IBindingManager;
import org.whole.lang.commons.reflect.CommonsEntityDescriptorEnum;
import org.whole.lang.commons.reflect.CommonsFeatureDescriptorEnum;
import org.whole.lang.commons.reflect.CommonsLanguageKit;
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.ITraversalFilter;
import org.whole.lang.visitors.TraverseAllFilter;
/**
* @author Riccardo Solmi
*/
public class GenericMatcher {
protected IBindingManager bindings;
protected ITraversalFilter traversalFilter;
public GenericMatcher() {
this(BindingManagerFactory.instance.createBindingManager());
}
public GenericMatcher(IBindingManager bindings) {
this(bindings, TraverseAllFilter.instance);
}
public GenericMatcher(IBindingManager bindings, ITraversalFilter traversalFilter) {
this.bindings = bindings;
this.traversalFilter = traversalFilter;
}
public void match(IEntity pattern, IEntity model) {
IEntity patternAdaptee = pattern.wGetAdaptee(false);
if (patternAdaptee.wGetLanguageKit().getURI().equals(CommonsLanguageKit.URI)) {
switch (patternAdaptee.wGetEntityDescriptor().getOrdinal()) {
case CommonsEntityDescriptorEnum.Resolver_ord:
matchEntityResolver(pattern, model);
return;
case CommonsEntityDescriptorEnum.Variable_ord:
case CommonsEntityDescriptorEnum.InlineVariable_ord:
matchEntityVariable(pattern, model);
return;
case CommonsEntityDescriptorEnum.SameStageFragment_ord:
matchAdapterFragmentEntity(pattern, model);
return;
case CommonsEntityDescriptorEnum.RootFragment_ord:
case CommonsEntityDescriptorEnum.StageDownFragment_ord:
matchBaseFragmentEntity(pattern, model);
return;
case CommonsEntityDescriptorEnum.StageUpFragment_ord:
matchMetaFragmentEntity(pattern, model);
return;
}
}
switch(pattern.wGetEntityKind()) {
case SIMPLE:
matchSimpleEntity(pattern, model);
break;
case COMPOSITE:
matchCompositeEntity(pattern, model);
break;
case DATA:
matchDataEntity(pattern, model);
break;
}
}
public void matchAdapterFragmentEntity(IEntity pattern, IEntity model) {
matchSimpleEntity(pattern, model);
}
public void matchBaseFragmentEntity(IEntity pattern, IEntity model) {
matchSimpleEntity(pattern, model);
}
public void matchMetaFragmentEntity(IEntity pattern, IEntity model) {
matchSimpleEntity(pattern, model);
}
public void matchSimpleEntity(IEntity pattern, IEntity model) {
if (!pattern.wGetEntityDescriptor().equals(model.wGetEntityDescriptor()) ||
model.wSize() < pattern.wSize())
throw new MatchException(pattern, model, bindings);
for (int i=0, size=pattern.wSize(); i<size; i++)
if (traversalFilter.include(model, i))
pattern.wGet(i).wAccept(this, model.wGet(i));
}
public void matchCompositeEntity(IEntity pattern, IEntity model) {
if ((!pattern.wGetEntityDescriptor().equals(model.wGetEntityDescriptor())
&& !EntityUtils.isResolver(model) //TODO workaround for resolvers
) || (pattern.wSize() != model.wSize() && !(pattern.wIsEmpty() && model.wIsEmpty())) )
throw new MatchException(pattern, model, bindings);
if (!pattern.wIsEmpty())
for (int i=0, size=pattern.wSize(); i<size; i++)
if (traversalFilter.include(model, i))
pattern.wGet(i).wAccept(this, model.wGet(i));
}
public void matchDataEntity(IEntity pattern, IEntity model) {
if (!EntityUtils.isData(model) ||
!pattern.wGetEntityDescriptor().equals(model.wGetEntityDescriptor()))
throw new MatchException(pattern, model, bindings);
Object patternValue = pattern.wGetValue();
Object modelValue = model.wGetValue();
if (patternValue != modelValue && (patternValue == null || !patternValue.equals(modelValue)))
throw new MatchException(pattern, model, bindings);
}
public void matchEntityResolver(IEntity pattern, IEntity model) {
if (pattern.wSize() != model.wSize() || model.wGetEntityKind().equals(EntityKinds.DATA))
throw new MatchException(pattern, model, bindings);
for (FeatureDescriptor fd : pattern.wGetEntityDescriptor().getEntityFeatureDescriptors()) {
if (pattern.wContains(fd))
if (model.wContains(fd))
pattern.wGet(fd).wAccept(this, model.wGet(fd));
else
throw new MatchException(pattern, model, bindings);
}
}
public void matchEntityVariable(IEntity pattern, IEntity model) {
EntityDescriptor<?> type = (EntityDescriptor<?>) pattern.wGet(CommonsFeatureDescriptorEnum.varType).wGetValue();
String name = pattern.wGet(CommonsFeatureDescriptorEnum.varName).wStringValue();
if (bindings.wIsSet(name)) {
IEntity value = bindings.wGet(name);
if (EntityUtils.isVariable(value)) {
if (!EntityUtils.isVariable(model) ||
!value.wGet(CommonsFeatureDescriptorEnum.varType).wGetValue().equals(model.wGet(CommonsFeatureDescriptorEnum.varType).wGetValue()) ||
!value.wGet(CommonsFeatureDescriptorEnum.varName).wStringValue().equals(model.wGet(CommonsFeatureDescriptorEnum.varName).wStringValue()))
throw new MatchException(pattern, model, bindings);
} else {
if (type.isPlatformSupertypeOf(value.wGetEntityDescriptor()))//was AsIsFrom(
value.wAccept(this, model);
else
throw new MatchException(pattern, model, bindings);
}
} else {
if (type.isPlatformSupertypeOf(//was AsIsFrom(
EntityUtils.isVariable(model) ?
(EntityDescriptor<?>) model.wGet(CommonsFeatureDescriptorEnum.varType).wGetValue()
: model.wGetEntityDescriptor()))
bindings.wDef(name, model);
else if (EntityUtils.isResolver(model)) //TODO workaround waiting for a dynamic entity descriptor for resolvers
bindings.wDef(name, model);
else
throw new MatchException(pattern, model, bindings);
}
}
}