/**
* 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.parameter;
import static org.objectweb.fractal.adl.NodeUtil.cloneTree;
import static org.ow2.mind.adl.parameter.ast.ParameterASTHelper.turnsToArgumentContainer;
import static org.ow2.mind.adl.parameter.ast.ParameterASTHelper.turnsToParamContainer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.objectweb.fractal.adl.ADLException;
import org.objectweb.fractal.adl.CompilerError;
import org.objectweb.fractal.adl.Definition;
import org.objectweb.fractal.adl.NodeFactory;
import org.objectweb.fractal.adl.error.GenericErrors;
import org.objectweb.fractal.adl.merger.NodeMerger;
import org.ow2.mind.adl.DefinitionReferenceResolver;
import org.ow2.mind.adl.ast.DefinitionReference;
import org.ow2.mind.adl.generic.TemplateInstantiator;
import org.ow2.mind.adl.generic.TemplateInstantiator.AbstractDelegatingTemplateInstantiator;
import org.ow2.mind.adl.generic.ast.FormalTypeParameter;
import org.ow2.mind.adl.generic.ast.FormalTypeParameterContainer;
import org.ow2.mind.adl.generic.ast.TypeArgument;
import org.ow2.mind.adl.parameter.ast.Argument;
import org.ow2.mind.adl.parameter.ast.ArgumentContainer;
import org.ow2.mind.adl.parameter.ast.FormalParameter;
import org.ow2.mind.adl.parameter.ast.FormalParameterContainer;
import org.ow2.mind.value.ast.Reference;
import com.google.inject.Inject;
/**
* This delegating {@link TemplateInstantiator} adds {@link FormalParameter
* formal parameters} contained by the definitions designated by type arguments
* to the instantiated template.
*/
public class ParametricTemplateInstantiator
extends
AbstractDelegatingTemplateInstantiator {
@Inject
protected DefinitionReferenceResolver definitionReferenceResolverItf;
@Inject
protected NodeFactory nodeFactoryItf;
@Inject
protected NodeMerger nodeMergerItf;
// ---------------------------------------------------------------------------
// Implementation of the TemplateInstantiator interface
// ---------------------------------------------------------------------------
public Definition instantiateTemplate(final Definition genericDefinition,
final Map<String, Object> typeArgumentValues,
final Map<Object, Object> context) throws ADLException {
// the list of FormalParameter to be added on the instantiated template.
final List<FormalParameter> toBeAddedParameters = new ArrayList<FormalParameter>();
// for each formal type parameter of the generic definition
for (final FormalTypeParameter formalTypeParameter : ((FormalTypeParameterContainer) genericDefinition)
.getFormalTypeParameters()) {
final String formalTypeParameterName = formalTypeParameter.getName();
// get the given type argument value
final Object typeArgumentValue = typeArgumentValues
.get(formalTypeParameterName);
assert typeArgumentValue != null;
// if the type argument value is not a DefinitionReference, pass it.
if (!(typeArgumentValue instanceof TypeArgument)) continue;
final DefinitionReference typeArgumentDefRef = ((TypeArgument) typeArgumentValue)
.getDefinitionReference();
if (typeArgumentDefRef == null) continue;
final Definition typeArgumentDef = definitionReferenceResolverItf
.resolve(typeArgumentDefRef, null, context);
assert typeArgumentDef != null;
// if the type argument value do not contains formal parameter, pass.
if (!(typeArgumentDef instanceof FormalParameterContainer)) continue;
final FormalParameter[] formalParameters = ((FormalParameterContainer) typeArgumentDef)
.getFormalParameters();
// if the type argument value do not contains formal parameter, pass.
if (formalParameters.length == 0) continue;
// The type argument value must be modified: an argument sub-node must be
// added for each formal parameter. To avoid modification of given
// DefinitionReference, clone it and ensure that it implements
// ArgumentContainer.
final TypeArgument clonedTypeArgument = cloneTree((TypeArgument) typeArgumentValue);
final ArgumentContainer argumentContainer = turnsToArgumentContainer(
clonedTypeArgument.getDefinitionReference(), nodeFactoryItf,
nodeMergerItf);
if (argumentContainer != clonedTypeArgument.getDefinitionReference())
clonedTypeArgument
.setDefinitionReference((DefinitionReference) argumentContainer);
// replace the type argument value in given typeArgumentValues Map.
typeArgumentValues.put(formalTypeParameterName, clonedTypeArgument);
// remove present argument values (if any).
for (final Argument argument : argumentContainer.getArguments())
argumentContainer.removeArgument(argument);
// add new arguments that reference the added formal parameters
// for each formal parameter of the type argument.
for (final FormalParameter formalParameter : formalParameters) {
final String paramName = formalTypeParameterName + "$"
+ formalParameter.getName();
// create a new formal parameter that will be added to the instantiated
// template.
final FormalParameter newFormalParameter = cloneTree(formalParameter);
newFormalParameter.setName(paramName);
toBeAddedParameters.add(newFormalParameter);
// create a new argument that references the newly created formal
// parameter.
final Argument newArgument = newArgumentNode();
newArgument.setName(formalParameter.getName());
final Reference newReference = newReferenceNode();
newReference.setRef(paramName);
newArgument.setValue(newReference);
argumentContainer.addArgument(newArgument);
}
}
// Instantiate template
Definition templateInstance = clientInstantiatorItf.instantiateTemplate(
genericDefinition, typeArgumentValues, context);
// add the formal parameters (if any).
if (!toBeAddedParameters.isEmpty()) {
final FormalParameterContainer formalParameterContainer = turnsToParamContainer(
templateInstance, nodeFactoryItf, nodeMergerItf);
if (templateInstance != formalParameterContainer)
templateInstance = (Definition) formalParameterContainer;
for (final FormalParameter formalParameter : toBeAddedParameters)
formalParameterContainer.addFormalParameter(formalParameter);
}
return templateInstance;
}
protected Argument newArgumentNode() {
try {
return (Argument) nodeFactoryItf.newNode("argument",
Argument.class.getName());
} catch (final ClassNotFoundException e) {
throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
"Node factory error");
}
}
protected Reference newReferenceNode() {
try {
return (Reference) nodeFactoryItf.newNode("value",
Reference.class.getName());
} catch (final ClassNotFoundException e) {
throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
"Node factory error");
}
}
}