/** * 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.graph; import java.util.HashMap; 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.error.GenericErrors; import org.ow2.mind.adl.ADLErrors; import org.ow2.mind.adl.ast.Attribute; import org.ow2.mind.adl.ast.AttributeContainer; 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.graph.Instantiator.AbstractDelegatingInstantiator; import org.ow2.mind.adl.parameter.ast.Argument; import org.ow2.mind.adl.parameter.ast.ArgumentContainer; import org.ow2.mind.adl.parameter.ast.FormalParameterContainer; import org.ow2.mind.error.ErrorManager; import org.ow2.mind.value.ast.CompoundValue; import org.ow2.mind.value.ast.CompoundValueField; import org.ow2.mind.value.ast.NullLiteral; import org.ow2.mind.value.ast.NumberLiteral; import org.ow2.mind.value.ast.Reference; import org.ow2.mind.value.ast.StringLiteral; import org.ow2.mind.value.ast.Value; import com.google.inject.Inject; public class AttributeInstantiator extends AbstractDelegatingInstantiator { private static final Map<String, ValueContext> EMPTY_NAME_VALUE_MAP = new HashMap<String, ValueContext>(); @Inject protected ErrorManager errorManagerItf; // --------------------------------------------------------------------------- // Implementation of the Instantiator interface // --------------------------------------------------------------------------- public ComponentGraph instantiate(final Definition definition, final Map<Object, Object> context) throws ADLException { if (definition instanceof FormalParameterContainer) { if (((FormalParameterContainer) definition).getFormalParameters().length > 0) { errorManagerItf.logError(ADLErrors.INSTANTIATE_ARGUMENT_DEFINIITON, definition, definition.getName()); } } final ComponentGraph graph = clientInstantiatorItf.instantiate(definition, context); initAttributes(graph, EMPTY_NAME_VALUE_MAP, context); return graph; } protected void initAttributes(final ComponentGraph graph, final Map<String, ValueContext> argumentValues, final Map<Object, Object> context) { // Initialize map of attribute values. if (graph.getDefinition() instanceof AttributeContainer) { final Attribute[] attributes = ((AttributeContainer) graph .getDefinition()).getAttributes(); if (attributes.length > 0) { final Map<String, String> attributeValues = new HashMap<String, String>(); for (final Attribute attribute : attributes) { final Value valueNode = attribute.getValue(); if (valueNode == null) continue; String valueString; valueString = toValueString(valueNode, argumentValues); attributeValues.put(attribute.getName(), valueString); } graph.setDecoration("attribute-values", attributeValues); } } // Init attribute of sub components if (graph.getDefinition() instanceof ComponentContainer) { for (final Component subComponent : ((ComponentContainer) graph .getDefinition()).getComponents()) { final ComponentGraph subGraph = graph.getSubComponent(subComponent .getName()); if (subComponent.getDefinitionReference() != null) { // sub component is defined by a definition reference, map its // argument values final DefinitionReference subCompDefRef = subComponent .getDefinitionReference(); final Map<String, ValueContext> refValues; final Argument[] refArguments = (subCompDefRef instanceof ArgumentContainer) ? ((ArgumentContainer) subCompDefRef).getArguments() : null; if (refArguments != null && refArguments.length > 0) { assert subGraph.getDefinition() instanceof FormalParameterContainer; assert ((FormalParameterContainer) subGraph.getDefinition()) .getFormalParameters().length == refArguments.length; refValues = new HashMap<String, ValueContext>(); for (final Argument refArgument : refArguments) { assert refArgument.getName() != null; // final Value refValue = refArgument.getValue(); // if (refValue instanceof Reference) { // final Value value = argumentValues.get(((Reference) refValue) // .getRef()); // assert value != null; // refValues.put(refArgument.getName(), value); // } else { // refValues.put(refArgument.getName(), refValue); // } // when the definition is anonymous, there are no written // arguments, only inferred ones and we've got only their name, // no value... so we try to get the value from the parent context if (subGraph.getDefinition().astGetType() .equals("anonymousDefinition")) { final ValueContext parentValueContextByArgName = argumentValues .get(refArgument.getName()); if (parentValueContextByArgName != null) refArgument.setValue(parentValueContextByArgName.value); } refValues.put(refArgument.getName(), new ValueContext(refArgument.getValue(), argumentValues)); } } else { refValues = EMPTY_NAME_VALUE_MAP; } initAttributes(subGraph, refValues, context); } } } } private String toValueString(final Value valueNode, final Map<String, ValueContext> referenceValues) throws CompilerError { if (valueNode instanceof Reference) { final ValueContext ctx = referenceValues.get(((Reference) valueNode) .getRef()); assert ctx != null; return toValueString(ctx.value, ctx.referenceValues); } else if (valueNode instanceof StringLiteral) { return ((StringLiteral) valueNode).getValue(); } else if (valueNode instanceof NumberLiteral) { return ((NumberLiteral) valueNode).getValue(); } else if (valueNode instanceof NullLiteral) { return "((void *) 0)"; } else if (valueNode instanceof CompoundValue) { final StringBuilder sb = new StringBuilder(); sb.append("{"); final CompoundValueField[] fields = ((CompoundValue) valueNode) .getCompoundValueFields(); for (int i = 0; i < fields.length; i++) { final CompoundValueField field = fields[i]; if (field.getName() != null) { sb.append(".").append(field.getName()).append("="); } sb.append(toValueString(field.getValue(), referenceValues)); if (i < fields.length - 1) { sb.append(", "); } } sb.append("}"); return sb.toString(); } else { throw new CompilerError(GenericErrors.INTERNAL_ERROR, "Unexpected value"); } } protected static class ValueContext { final protected Value value; final protected Map<String, ValueContext> referenceValues; protected ValueContext(final Value value, final Map<String, ValueContext> referenceValues) { this.value = value; this.referenceValues = referenceValues; } } }