Package org.rascalmpl.interpreter.result

Source Code of org.rascalmpl.interpreter.result.AbstractPatternDispatchedFunction

/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:

*   * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
*   * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
*   * Anya Helene Bagge - anya@ii.uib.no
*   * Anastasia Izmaylova - A.Izmaylova@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.interpreter.result;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.IExternalValue;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.type.Type;
import org.eclipse.imp.pdb.facts.type.TypeFactory;
import org.eclipse.imp.pdb.facts.visitors.IValueVisitor;
import org.rascalmpl.ast.KeywordFormal;
import org.rascalmpl.interpreter.IEvaluator;
import org.rascalmpl.interpreter.control_exceptions.Failure;
import org.rascalmpl.interpreter.control_exceptions.MatchFailed;
import org.rascalmpl.interpreter.env.Environment;
import org.rascalmpl.interpreter.types.FunctionType;
import org.rascalmpl.interpreter.types.RascalTypeFactory;

public class AbstractPatternDispatchedFunction extends AbstractFunction {
  private final Map<String, List<AbstractFunction>> alternatives;
  private final Type type;
  private final int arity;
  private final boolean isStatic;
  private final String name;

  public AbstractPatternDispatchedFunction(IEvaluator<Result<IValue>> eval, String name, Type type, Map<String, List<AbstractFunction>> alternatives) {
    super(null, eval
        , (FunctionType) RascalTypeFactory.getInstance().functionType(TypeFactory.getInstance().voidType()
            , TypeFactory.getInstance().voidType(), TF.voidType())
            , Collections.<KeywordFormal>emptyList() // can we get away with this?
            , checkVarArgs(alternatives), null);
    this.type = type;
    this.alternatives = alternatives;
    this.arity = minArity(alternatives);
    this.isStatic = checkStatic(alternatives);
    this.name = name;
  }
 
  @Override
  public AbstractPatternDispatchedFunction cloneInto(Environment env) {
    Map<String, List<AbstractFunction>> newAlts = new HashMap<>();
    for (String name: alternatives.keySet()) {
      List<AbstractFunction> alts = new ArrayList<>();
      for (AbstractFunction alt: newAlts.get(name)) {
        alts.add((AbstractFunction) alt.cloneInto(env));
      }
      newAlts.put(name, alts);
    }
    return new AbstractPatternDispatchedFunction(getEval(), name, type, newAlts);
  }
 
  @Override
  public boolean isPublic() {
    throw new UnsupportedOperationException();
  }
 
  public Map<String,List<AbstractFunction>> getMap() {
    return alternatives;
  }

  @Override
  public boolean isPatternDispatched() {
    return true;
  }

  /**
   * We check if the different alternatives for this function have different arities here as well.
   */
  private static boolean checkVarArgs(Map<String, List<AbstractFunction>> alts) {
    int arity = -1;
    for (List<AbstractFunction> l : alts.values()) {
      for (AbstractFunction f : l) {
        if (arity != -1) {
          if (arity != f.getArity()) {
            return true;
          }
        }
        else {
          arity = f.getArity();
        }
       
        if (f.hasVarArgs()) {
          return true;
        }
      }
    }
    return false;
  }
 
  private static int minArity(Map<String, List<AbstractFunction>> alts) {
    int min = Integer.MAX_VALUE;
    for (List<AbstractFunction> l : alts.values()) {
      for (AbstractFunction f : l) {
        if (f.getArity() < min) {
          min = f.getArity();
        }
      }
    }
    return min;
  }

  @Override
  public Type getType() {
    return type;
  }
 
  /*
   * The super getFunctionType() uses unsafe downcast in its body: (FunctionType) getType();
   * @see org.rascalmpl.interpreter.result.AbstractFunction#getFunctionType()
   */
  @Override
  public FunctionType getFunctionType() {
    return (FunctionType) super.getType();
  }

  @Override
  public <T, E extends Throwable> T accept(IValueVisitor<T,E> v) throws E {
    return v.visitExternal((IExternalValue) this);
  }

  @Override
  public boolean isEqual(IValue other) {
    return equals(other);
  }
 
  @Override
  public boolean equals(Object arg0) {
    if(arg0 == null)
      return false;
    if (arg0.getClass() == getClass()) {
      AbstractPatternDispatchedFunction other = (AbstractPatternDispatchedFunction) arg0;
      return other.alternatives.equals(alternatives);
    }
    return false;
  }

  @Override
  /**
   * In this case we produce the minimum arity of the overloaded alternatives
   */
  public int getArity() {
    return arity;
  }

  @Override
  public Result<IValue> call(Type[] argTypes, IValue[] argValues, Map<String, IValue> keyArgValues) {
    String label = null;
   
    if (argTypes.length == 0) {
      throw new MatchFailed();
    }
   
    if (argTypes[0].isAbstractData() || argTypes[0].isConstructor()) {
      label = ((IConstructor) argValues[0]).getConstructorType().getName();
      List<AbstractFunction> funcs = alternatives.get(label);
     
      if (funcs != null) {
        for (AbstractFunction candidate : funcs) {
          if ((candidate.hasVarArgs() && argValues.length >= candidate.getArity() - 1)
              || candidate.getArity() == argValues.length) {
            try {
              return candidate.call(argTypes, argValues, keyArgValues);
            }
            catch (MatchFailed m) {
              // could happen if pattern dispatched
            }
            catch (Failure e) {
              // could happen if function body throws fail
            }
          }
        }

        throw new MatchFailed();
      }
    }
   
    throw new MatchFailed();
  }

  @Override
  public boolean isStatic() {
    return isStatic;
  }
 
  private static boolean checkStatic(Map<String, List<AbstractFunction>> m) {
    for(List<AbstractFunction> l : m.values()) {
      for(AbstractFunction f : l)
        if(!f.isStatic())
          return false;
    }
    return true;
  }

  @Override
  public boolean isDefault() {
    return false;
  }
 
  @Override
  public String getName() {
    return this.name;
  }
 
  @Override
  public String toString() {
    StringBuilder b = new StringBuilder();
    for (List<AbstractFunction> l : alternatives.values()) {
      for(AbstractFunction f : l)
        b.append(f.toString() + " (abstract pattern); ");
        b.append(' ');
    }
    return b.toString();
  }
 
}
TOP

Related Classes of org.rascalmpl.interpreter.result.AbstractPatternDispatchedFunction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.