Package org.renjin.sexp

Source Code of org.renjin.sexp.Closure

/*
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
* Copyright (C) 1997--2008  The R Development Core Team
* Copyright (C) 2003, 2004  The R Foundation
* Copyright (C) 2010 bedatadriven
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.renjin.sexp;

import com.google.common.base.Objects;
import org.renjin.eval.ClosureDispatcher;
import org.renjin.eval.Context;
import org.renjin.eval.EvalException;
import org.renjin.primitives.special.ReturnException;


/**
* The function closure data type.
*
* <p>
* In R functions are objects and can be manipulated in much the same way as any other object.
* Functions (or more precisely, function closures) have three basic components:
*  a formal argument list, a body and an environment.
*
*/
public class Closure extends AbstractSEXP implements Function {

  public static final String TYPE_NAME = "closure";
  private Environment enclosingEnvironment;
  private SEXP body;
  private PairList formals;

  public Closure(Environment enclosingEnvironment, PairList formals, SEXP body, AttributeMap attributes) {
    super(attributes);
    this.enclosingEnvironment = enclosingEnvironment;
    this.body = body;
    this.formals = formals;
  }
  public Closure(Environment environment, PairList formals, SEXP body) {
    this(environment, formals, body, AttributeMap.EMPTY);
  }

  @Override
  public String getTypeName() {
    return TYPE_NAME;
  }
 

  @Override
  protected SEXP cloneWithNewAttributes(AttributeMap newAttributes) {
    return new Closure(this.enclosingEnvironment, this.formals, this.body, newAttributes);
  }

  @Override
  public String getImplicitClass() {
    return Function.IMPLICIT_CLASS;
  }

  @Override
  public void accept(SexpVisitor visitor) {
    visitor.visit(this);
  }

  @Override
  public SEXP apply(Context context, Environment rho, FunctionCall call, PairList args) {
    ClosureDispatcher dispatcher = new ClosureDispatcher(context, rho, call);
    return dispatcher.applyClosure(this, args);
  }
 

  public SEXP matchAndApply(Context callingContext, Environment callingEnvironment, FunctionCall call,
      PairList promisedArgs) {
    Context functionContext = callingContext.beginFunction(callingEnvironment, call, this, promisedArgs);
    Environment functionEnvironment = functionContext.getEnvironment();   

    ClosureDispatcher.matchArgumentsInto(getFormals(), promisedArgs, functionContext, functionEnvironment);

    SEXP result;
    try {
      result = doApply(functionContext);
    } catch(ReturnException e) {
      if(functionEnvironment != e.getEnvironment()) {
        throw e;
      }
      result = e.getValue();
    } finally {
      functionContext.exit();
    }
    return result;
  }

  public SEXP doApply(Context functionContext) {
    return functionContext.evaluate(body);
  }
  

  /**
   * A function's <strong> evaluation environment</strong> is the environment
   * that was active at the time that the
   * function was created. Any symbols bound in that environment are
   * captured and available to the function. This combination of the code of the
   * function and the bindings in its environment is called a `function closure', a
   * term from functional programming theory.
   *
   */
  public Environment getEnclosingEnvironment() {
    return enclosingEnvironment;
  }

  /**
   * Creates a copy of this Closure with the new enclosing environment.
   * @param env the new enclosing environment.
   * @return
   */
  public Closure setEnclosingEnvironment(Environment env) {
    return new Closure(env, formals, body, attributes);
  }

  /**
   * The body is a parsed R statement.
   * It is usually a collection of statements in braces but it
   * can be a single statement, a symbol or even a constant.
   */
  public SEXP getBody() {
    return body;
  }

  /**
   * The formal argument list is a a pair list of arguments.
   * An argument can be a symbol, or a ‘symbol = default’ construct, or
   * the special argument ‘...’.
   *
   * <p> The second form of argument is
   *  used to specify a default value for an argument.
   * This value will be used if the function is called
   *  without any value specified for that argument.
   * The ‘...’ argument is special and can contain any number of arguments.
   * It is generally used if the number of arguments
   * is unknown or in cases where the arguments will
   * be passed on to another function.
   */
  public PairList getFormals() {
    return formals;
  }


  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("function(");
    if(getFormals() instanceof PairList.Node) {
      ((PairList.Node) getFormals()).appendValuesTo(sb);
    }
    return sb.append(")").toString();
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((body == null) ? 0 : body.hashCode());
    result = prime
        * result
        + ((enclosingEnvironment == null) ? 0 : enclosingEnvironment.hashCode());
    result = prime * result + ((formals == null) ? 0 : formals.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (!(obj instanceof Closure))
      return false;
    Closure other = (Closure) obj;
    if(!Objects.equal(body, other.body)) {
      return false;
    }
    if(!Objects.equal(enclosingEnvironment, other.enclosingEnvironment)) {
      return false;
    }
    if(!Objects.equal(formals, other.formals)) {
      return false;
    }
    return true;
  }

}
TOP

Related Classes of org.renjin.sexp.Closure

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.