All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.objectweb.fractal.mind.adl.parameter.ParametricDefinitionReferenceResolver Maven / Gradle / Ivy

The newest version!
/**
 * 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 .
 *
 * Contact: [email protected]
 *
 * Authors: Matthieu Leclercq
 * Contributors: 
 */

package org.objectweb.fractal.mind.adl.parameter;

import static org.objectweb.fractal.mind.adl.parameter.ast.ParameterASTHelper.getInferredParameterType;
import static org.objectweb.fractal.mind.adl.parameter.ast.ParameterASTHelper.setInferredParameterType;
import static org.objectweb.fractal.mind.adl.parameter.ast.ParameterASTHelper.setUsedFormalParameter;

import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

import org.objectweb.fractal.adl.ADLException;
import org.objectweb.fractal.adl.CompilerError;
import org.objectweb.fractal.adl.ContextLocal;
import org.objectweb.fractal.adl.Definition;
import org.objectweb.fractal.adl.Node;
import org.objectweb.fractal.adl.error.GenericErrors;
import org.objectweb.fractal.adl.error.NodeErrorLocator;
import org.objectweb.fractal.mind.adl.AbstractDefinitionReferenceResolver;
import org.objectweb.fractal.mind.adl.DefinitionReferenceResolver;
import org.objectweb.fractal.mind.adl.ADLErrors;
import org.objectweb.fractal.mind.adl.ast.DefinitionReference;
import org.objectweb.fractal.mind.adl.parameter.ast.Argument;
import org.objectweb.fractal.mind.adl.parameter.ast.ArgumentContainer;
import org.objectweb.fractal.mind.adl.parameter.ast.FormalParameter;
import org.objectweb.fractal.mind.adl.parameter.ast.FormalParameterContainer;
import org.objectweb.fractal.mind.adl.parameter.ast.ParameterASTHelper.ParameterType;
import org.objectweb.fractal.mind.value.ast.NumberLiteral;
import org.objectweb.fractal.mind.value.ast.Reference;
import org.objectweb.fractal.mind.value.ast.StringLiteral;
import org.objectweb.fractal.mind.value.ast.Value;

/**
 * This delegating {@link DefinitionReferenceResolver} checks that
 * {@link Argument} nodes contained by the {@link DefinitionReference} to
 * resolve, match {@link FormalParameter} contained by the resolved
 * {@link Definition}.
 */
public class ParametricDefinitionReferenceResolver
    extends
      AbstractDefinitionReferenceResolver {

  protected final ContextLocal>> contextualParameters = new ContextLocal>>();

  // ---------------------------------------------------------------------------
  // Implementation of the DefinitionReferenceResolver interface
  // ---------------------------------------------------------------------------

  public Definition resolve(final DefinitionReference reference,
      final Definition encapsulatingDefinition,
      final Map context) throws ADLException {

    return resolve(reference, encapsulatingDefinition, getParameters(
        encapsulatingDefinition, context), context);
  }

  // ---------------------------------------------------------------------------
  // Utility methods
  // ---------------------------------------------------------------------------

  protected Definition resolve(final DefinitionReference reference,
      final Definition encapsulatingDefinition,
      final Map formalParameters,
      final Map context) throws ADLException {

    final Definition d = clientResolverItf.resolve(reference,
        encapsulatingDefinition, context);

    final Argument[] argumentValues = (reference instanceof ArgumentContainer)
        ? ((ArgumentContainer) reference).getArguments()
        : null;
    final FormalParameter[] refFormalParameters = (d instanceof FormalParameterContainer)
        ? ((FormalParameterContainer) d).getFormalParameters()
        : null;

    // Map argument values to formal parameters.
    // argumentMap associates formal parameter names to actual arguments;
    final Map argumentMap = mapArguments(refFormalParameters,
        argumentValues, reference);

    if (argumentMap != null) {
      // referenced definition has formal parameters.

      // Check argument values
      for (final FormalParameter parameter : refFormalParameters) {
        final ParameterType type = getInferredParameterType(parameter);
        final Argument argumentValue = argumentMap.get(parameter.getName());
        final Value value = argumentValue.getValue();

        if (value instanceof Reference) {
          // the argument references a formal parameter
          final String ref = ((Reference) value).getRef();
          final FormalParameter referencedParameter = formalParameters.get(ref);
          if (referencedParameter == null) {
            throw new ADLException(ADLErrors.UNDEFINED_PARAMETER, value, ref);
          }
          setUsedFormalParameter(referencedParameter);

          final ParameterType referencedType = getInferredParameterType(referencedParameter);
          if (referencedType == null) {
            setInferredParameterType(referencedParameter, type);
          } else if (type != null && type != referencedType) {
            throw new ADLException(ADLErrors.INCOMPATIBLE_ARGUMENT_TYPE, value,
                ref);
          }
        } else if (value instanceof StringLiteral) {
          if (type != null && type != ParameterType.STRING) {
            throw new ADLException(ADLErrors.INCOMPATIBLE_ARGUMENT_VALUE,
                value, parameter.getName());
          }
        } else if (value instanceof NumberLiteral) {
          if (type != null && type != ParameterType.INTEGER) {
            throw new ADLException(ADLErrors.INCOMPATIBLE_ARGUMENT_VALUE,
                value, parameter.getName());
          }
        }
      }
    }

    return d;
  }

  protected Map mapArguments(
      final FormalParameter[] parameters, final Argument[] arguments,
      final Node location) throws ADLException {
    if (parameters == null || parameters.length == 0) {
      if (arguments != null && arguments.length > 0) {
        throw new ADLException(ADLErrors.INVALID_REFERENCE_NO_PARAMETER,
            location);
      } else {
        return null;
      }

    } else {
      // there are parameters
      if (arguments == null || arguments.length == 0)
        throw new ADLException(ADLErrors.INVALID_REFERENCE_MISSING_ARGUMENT,
            location);

      if (arguments.length > 0 && arguments[0].getName() == null) {
        // argument values are specified by ordinal position.

        if (parameters.length > arguments.length) {
          // missing template values
          throw new ADLException(ADLErrors.INVALID_REFERENCE_MISSING_ARGUMENT,
              location);
        }

        if (parameters.length < arguments.length) {
          throw new ADLException(ADLErrors.INVALID_REFERENCE_TOO_MANY_ARGUMENT,
              location);
        }

        final Map result = new HashMap(
            parameters.length);

        for (int i = 0; i < parameters.length; i++) {
          final Argument value = arguments[i];
          // sanity check.
          if (value.getName() != null) {
            throw new CompilerError(GenericErrors.INTERNAL_ERROR,
                new NodeErrorLocator(value),
                "Cannot mix ordinal and name-based template values.");
          }

          final String varName = parameters[i].getName();

          value.setName(varName);
          result.put(varName, value);
        }

        return result;

      } else {
        // template values are specified by name

        final Map valuesByName = new HashMap(
            arguments.length);
        for (final Argument value : arguments) {
          // sanity check.
          if (value.getName() == null) {
            throw new CompilerError(GenericErrors.INTERNAL_ERROR,
                new NodeErrorLocator(value),
                "Cannot mix ordinal and name-based argument values.");
          }

          valuesByName.put(value.getName(), value);
        }

        final Map result = new HashMap();
        for (final FormalParameter variable : parameters) {
          final Argument value = valuesByName.remove(variable.getName());
          if (value == null) {
            // missing template values
            throw new ADLException(
                ADLErrors.INVALID_REFERENCE_MISSING_ARGUMENT, location,
                variable.getName());
          }
          result.put(variable.getName(), value);
        }
        if (!valuesByName.isEmpty()) {
          // too many template values

          // get the first one
          final Map.Entry value = valuesByName.entrySet()
              .iterator().next();

          throw new ADLException(ADLErrors.INVALID_REFERENCE_NO_SUCH_PARAMETER,
              value.getValue(), value.getKey());
        }

        return result;
      }
    }
  }

  protected Map getParameters(final Definition d,
      final Map context) throws ADLException {
    Map> parameters = contextualParameters
        .get(context);
    if (parameters == null) {
      parameters = new IdentityHashMap>();
      contextualParameters.set(context, parameters);
    }

    Map result = parameters.get(d);

    if (result == null) {
      if (d instanceof FormalParameterContainer) {
        final FormalParameter[] formalParameters = ((FormalParameterContainer) d)
            .getFormalParameters();
        if (formalParameters.length > 0) {

          result = new HashMap(formalParameters.length);
          for (final FormalParameter parameter : formalParameters) {
            if (result.put(parameter.getName(), parameter) != null) {
              throw new ADLException(
                  ADLErrors.DUPLICATED_TEMPALTE_VARIABLE_NAME, parameter,
                  parameter.getName());
            }
          }
        }
      }
      parameters.put(d, result);
    }

    return result;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy