/**
* Copyright (C) 2009 STMicroelectronics
*
* This file is part of "Mind Compiler" 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: mind@ow2.org
*
* Authors: Matthieu Leclercq
* Contributors:
*/
package org.ow2.mind.adl.generic;
import static org.objectweb.fractal.adl.NodeUtil.cloneTree;
import static org.ow2.mind.adl.generic.ast.GenericASTHelper.setTemplateName;
import java.util.HashMap;
import java.util.Map;
import org.objectweb.fractal.adl.ADLException;
import org.objectweb.fractal.adl.Definition;
import org.objectweb.fractal.adl.NodeUtil;
import org.ow2.mind.adl.DefinitionReferenceResolver;
import org.ow2.mind.adl.DefinitionReferenceResolver.AbstractDelegatingDefinitionReferenceResolver;
import org.ow2.mind.adl.ExtendsLoader;
import org.ow2.mind.adl.SubComponentResolverLoader;
import org.ow2.mind.adl.ast.Component;
import org.ow2.mind.adl.ast.ComponentContainer;
import org.ow2.mind.adl.ast.DefinitionReference;
import org.ow2.mind.adl.generic.ast.FormalTypeParameter;
import org.ow2.mind.adl.generic.ast.FormalTypeParameterContainer;
import org.ow2.mind.adl.generic.ast.FormalTypeParameterReference;
import org.ow2.mind.adl.generic.ast.TypeArgument;
import org.ow2.mind.adl.generic.ast.TypeArgumentContainer;
/**
* This delegating {@link DefinitionReferenceResolver} replaces, in the resolved
* definition, every type parameter occurrences by its corresponding value. This
* <code>DefinitionReferenceResolver</code> should be used only by
* {@link ExtendsLoader} and should not be used by
* {@link SubComponentResolverLoader}.
*/
public class ExtendsGenericDefinitionReferenceResolver
extends
AbstractDelegatingDefinitionReferenceResolver {
public Definition resolve(final DefinitionReference reference,
final Definition encapsulatingDefinition,
final Map<Object, Object> context) throws ADLException {
Definition d = clientResolverItf.resolve(reference,
encapsulatingDefinition, context);
if (d instanceof FormalTypeParameterContainer) {
final FormalTypeParameter[] formalTypeParameters = ((FormalTypeParameterContainer) d)
.getFormalTypeParameters();
if (formalTypeParameters.length > 0) {
assert reference instanceof TypeArgumentContainer;
d = NodeUtil.cloneGraph(d);
setTemplateName(d, null);
final Map<String, TypeArgument> typeParameterMapping = new HashMap<String, TypeArgument>();
for (final TypeArgument typeArgument : ((TypeArgumentContainer) reference)
.getTypeArguments()) {
assert typeArgument.getTypeParameterName() != null;
typeParameterMapping.put(typeArgument.getTypeParameterName(),
typeArgument);
}
// replace type argument occurrences that references a formal type
// parameter of the encapsulating definition.
if (d instanceof ComponentContainer) {
for (final Component subComp : ((ComponentContainer) d)
.getComponents()) {
if ((subComp instanceof FormalTypeParameterReference)
&& ((FormalTypeParameterReference) subComp)
.getTypeParameterReference() != null) {
final FormalTypeParameterReference typeParamRef = (FormalTypeParameterReference) subComp;
final TypeArgument typeArgument = typeParameterMapping
.get(typeParamRef.getTypeParameterReference());
assert typeArgument != null;
if (typeArgument.getTypeParameterReference() != null) {
typeParamRef.setTypeParameterReference(typeArgument
.getTypeParameterReference());
} else {
typeParamRef.setTypeParameterReference(null);
final DefinitionReference defRef = typeArgument
.getDefinitionReference();
if (defRef != null) {
subComp.setDefinitionReference(cloneTree(defRef));
}
}
} else {
replaceTypeparameterReferences(subComp.getDefinitionReference(),
typeParameterMapping);
}
}
}
}
}
return d;
}
protected void replaceTypeparameterReferences(
final DefinitionReference defRef,
final Map<String, TypeArgument> typeParameterMapping) {
if (defRef instanceof TypeArgumentContainer) {
for (final TypeArgument typeArgument : ((TypeArgumentContainer) defRef)
.getTypeArguments()) {
if (typeArgument.getTypeParameterReference() != null) {
final TypeArgument referencedTypeArgument = typeParameterMapping
.get(typeArgument.getTypeParameterReference());
assert referencedTypeArgument != null;
if (referencedTypeArgument.getTypeParameterReference() != null) {
typeArgument.setTypeParameterReference(referencedTypeArgument
.getTypeParameterReference());
} else {
typeArgument.setTypeParameterReference(null);
typeArgument.setDefinitionReference(typeArgument
.getDefinitionReference());
}
} else if (typeArgument.getDefinitionReference() != null) {
replaceTypeparameterReferences(typeArgument.getDefinitionReference(),
typeParameterMapping);
}
}
}
}
}