/**
* Copyright (C) 2010 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.attribute;
import static org.ow2.mind.adl.parameter.ast.ParameterASTHelper.getInferredParameterType;
import static org.ow2.mind.adl.parameter.ast.ParameterASTHelper.setInferredParameterType;
import static org.ow2.mind.adl.parameter.ast.ParameterASTHelper.setUsedFormalParameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.fractal.adl.ADLException;
import org.objectweb.fractal.adl.Definition;
import org.objectweb.fractal.adl.NodeFactory;
import org.ow2.mind.adl.ADLErrors;
import org.ow2.mind.adl.AbstractDelegatingLoader;
import org.ow2.mind.adl.ast.Attribute;
import org.ow2.mind.adl.ast.AttributeContainer;
import org.ow2.mind.adl.parameter.ast.FormalParameter;
import org.ow2.mind.adl.parameter.ast.FormalParameterContainer;
import org.ow2.mind.adl.parameter.ast.ParameterASTHelper.ParameterType;
import org.ow2.mind.error.ErrorManager;
import org.ow2.mind.idl.IncludeResolver;
import org.ow2.mind.idl.ast.IDL;
import org.ow2.mind.idl.ast.IDLASTHelper;
import org.ow2.mind.idl.ast.IDLASTHelper.IncludeDelimiter;
import org.ow2.mind.idl.ast.Include;
import org.ow2.mind.value.ValueKindDecorator;
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 AttributeCheckerLoader extends AbstractDelegatingLoader {
@Inject
protected ErrorManager errorManagerItf;
@Inject
protected NodeFactory nodeFactoryItf;
@Inject
protected IncludeResolver includeResolverItf;
@Inject
protected ValueKindDecorator valueKindDecoratorItf;
// ---------------------------------------------------------------------------
// Implementation of the Loader interface
// ---------------------------------------------------------------------------
public Definition load(final String name, final Map<Object, Object> context)
throws ADLException {
final Definition d = clientLoader.load(name, context);
if (d instanceof AttributeContainer)
checkAttributes((AttributeContainer) d, context);
return d;
}
protected void checkAttributes(final AttributeContainer container,
final Map<Object, Object> context) throws ADLException {
final Map<String, FormalParameter> formalParameters = new HashMap<String, FormalParameter>();
if (container instanceof FormalParameterContainer) {
for (final FormalParameter parameter : ((FormalParameterContainer) container)
.getFormalParameters()) {
formalParameters.put(parameter.getName(), parameter);
}
}
final List<Attribute> uninitializedAttributes = new ArrayList<Attribute>();
for (final Attribute attr : container.getAttributes()) {
final String idtPath = attr.getIdt();
if (idtPath != null) {
// check idt path
// create an include node to use the IncludeResolver
final Include includeNode = IDLASTHelper.newIncludeNode(nodeFactoryItf,
idtPath, IncludeDelimiter.QUOTE);
// copy source info for error reporting
includeNode.astSetSource(attr.astGetSource());
final IDL idtFile = includeResolverItf.resolve(includeNode, null,
((Definition) container).getName(), context);
attr.setIdt(idtFile.getName());
}
final ParameterType type = ParameterType.fromCType(idtPath,
attr.getType());
final Value value = attr.getValue();
if (value != null) {
valueKindDecoratorItf.setValueKind(value, context);
if (value instanceof NumberLiteral) {
if (!type.isCompatible(value))
errorManagerItf.logError(
ADLErrors.INVALID_ATTRIBUTE_VALUE_INCOMPATIBLE_TYPE, value);
if (type.isIntegerType() && type.getCType().startsWith("u")
&& ((NumberLiteral) value).getValue().startsWith("-")) {
errorManagerItf.logWarning(
ADLErrors.WARNING_ATTRIBUTE_UNSIGNED_ASSIGNED_TO_NEGATIVE,
value);
}
} else if (value instanceof StringLiteral
|| value instanceof NullLiteral || value instanceof CompoundValue) {
if (!type.isCompatible(value))
errorManagerItf.logError(
ADLErrors.INVALID_ATTRIBUTE_VALUE_INCOMPATIBLE_TYPE, value);
if (value instanceof CompoundValue) {
checkCompoundValue((CompoundValue) value, formalParameters);
}
} else {
assert value instanceof Reference;
final String refParamName = ((Reference) value).getRef();
final FormalParameter refParam = formalParameters.get(refParamName);
if (refParam == null) {
errorManagerItf.logError(ADLErrors.UNDEFINED_PARAMETER, value,
refParamName);
} else {
setUsedFormalParameter(refParam);
final ParameterType referencedType = getInferredParameterType(refParam);
if (referencedType == null) {
setInferredParameterType(refParam, type);
} else if (type != null && !type.isCompatible(referencedType)) {
errorManagerItf.logError(ADLErrors.INCOMPATIBLE_ARGUMENT_TYPE,
value, refParamName);
}
}
}
} else {
// value is null, move attribute at end of list
uninitializedAttributes.add(attr);
container.removeAttribute(attr);
}
}
// re-add uninitialized attribute at end of container.
for (final Attribute uninitializedAttr : uninitializedAttributes) {
container.addAttribute(uninitializedAttr);
}
}
private void checkCompoundValue(final CompoundValue value,
final Map<String, FormalParameter> formalParameters) throws ADLException {
for (final CompoundValueField field : value.getCompoundValueFields()) {
final Value subValue = field.getValue();
if (subValue instanceof Reference) {
final String refParamName = ((Reference) subValue).getRef();
final FormalParameter refParam = formalParameters.get(refParamName);
if (refParam == null) {
errorManagerItf.logError(ADLErrors.UNDEFINED_PARAMETER, value,
refParamName);
} else {
setUsedFormalParameter(refParam);
}
} else if (subValue instanceof CompoundValue) {
checkCompoundValue((CompoundValue) subValue, formalParameters);
}
}
}
}