Package org.renjin.primitives

Source Code of org.renjin.primitives.Contexts

/*
* 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.primitives;

import org.renjin.eval.Context;
import org.renjin.eval.Context.Type;
import org.renjin.eval.EvalException;
import org.renjin.invoke.annotations.Builtin;
import org.renjin.invoke.annotations.Current;
import org.renjin.invoke.annotations.Internal;
import org.renjin.sexp.Closure;
import org.renjin.sexp.Environment;
import org.renjin.sexp.Function;
import org.renjin.sexp.FunctionCall;


/**
* Functions that provide access to the call Context stack.
*/
public class Contexts {

  private Contexts() {}

  /**
   * Returns the index of the current frame.
   *
   * .GlobalEnv is given number 0 in the list of frames.
   * Each subsequent function evaluation increases the frame stack by 1.
   *
   * @param context the current {@code Context}
   * @return the index of the current frame.
   */
  @Internal("sys.nframe")
  public static int sysFrameCount(@Current Context context) {
    return findStartingContext(context).getFrameDepth();
  }

  /**
   * @param context the current call context
   * @param n generations to ascend the call tree (1=parent, 2=grandparent, etc)
   * @return the Environment of the parent environment
   *
   */
  @Internal("parent.frame")
  public static Environment parentFrame(@Current Context context,  int n) {
    if(n < 1) {
      throw new EvalException("invalid 'n' value");
    }

    // note that we actually climb n+1 parents in order to
    // skip the closure that makes the .Internal(parent.frame()) call

    Context cptr = context;
    Environment t = cptr.getCallingEnvironment();
    while (!cptr.isTopLevel()){
      if (cptr.getType() == Type.FUNCTION ) {
        if (cptr.getEnvironment() == t) {
          if (n == 1) {
            return cptr.getCallingEnvironment();
          }
          n--;
          t = cptr.getCallingEnvironment();
        }
      }
      cptr = cptr.getParent();
    }
    return context.getGlobalEnvironment();
  }

 
  /** Find the environment that can be returned by sys.frame
    * (so it needs to be on the cloenv pointer of a context) that matches
    * the environment where the closure arguments are to be evaluated.
    * It would be much simpler if sysparent just returned cptr->sysparent
    * but then we wouldn't be compatible with S.
    **/
  private static int R_sysparent(int n, Context cptr) {
    int j;
    if(n <= 0) {
      throw new EvalException("only positive values of 'n' are allowed");
    }
    while (!cptr.isTopLevel() && n > 1) {
      if (cptr.getType() == Type.FUNCTION ) {
        n--;
      }
      cptr = cptr.getParent();
    }
    /* make sure we're looking at a return context */
    while (!cptr.isTopLevel()  && cptr.getType() != Type.FUNCTION)  {
      cptr = cptr.getParent();
    }

    Environment s = cptr.getCallingEnvironment();

    if(s == cptr.getGlobalEnvironment()) {
      return 0;
    }
    j = 0;
    while (true ) {
      if (cptr.getType() == Type.FUNCTION) {
        j++;
        if( cptr.getEnvironment() == s )
          n=j;
      }
      if(cptr.isTopLevel()) {
        break;
      }
      cptr = cptr.getParent();
    }
    n = j - n + 1;
    if (n < 0) {
      n = 0;
    }
    return n;
  }
 
  public static Closure R_sysfunction(int n, Context cptr) {
    if (n > 0) {
      n = cptr.getFrameDepth() - n;
    } else {
      n = - n;
    }
    if (n < 0) {
      throw new EvalException("not that many frames on the stack");
    }
    while (!cptr.isTopLevel()) {
      if (cptr.getType() == Type.FUNCTION ) {
        if (n == 0)
          return cptr.getClosure();
        else
          n--;
      }
      cptr = cptr.getParent();
    }
    if (n == 0 && cptr.isTopLevel()) {
      return cptr.getClosure();
    }
    throw new EvalException("not that many frames on the stack");
  }
 

/* R_sysframe - look back up the context stack until the */
/* nth closure context and return that cloenv. */
/* R_sysframe(0) means the R_GlobalEnv environment */
/* negative n counts back from the current frame */
/* positive n counts up from the globalEnv */

  private static Environment R_sysframe(int n, Context cptr) {
    if (n == 0) {
      return cptr.getGlobalEnvironment();
    }

    if (n > 0) {
      n = cptr.getFrameDepth() - n;
    else {
      n = -n;
    }

    if(n < 0) {
      throw new EvalException("not that many frames on the stack");
    }

    while (!cptr.isTopLevel()) {
      if (cptr.getType() == Type.FUNCTION ) {
        if (n == 0) {  /* we need to detach the enclosing env */
          return cptr.getEnvironment();
        } else {
          n--;
        }
      }
      cptr = cptr.getParent();
    }
    if(n == 0 && cptr.isTopLevel()) {
      return cptr.getGlobalEnvironment();
    }
    throw new EvalException("not that many frames on the stack");
  }


  private static FunctionCall R_syscall(int n, Context cptr) {
    /* negative n counts back from the current frame */
    /* positive n counts up from the globalEnv */
 
    if (n > 0)
      n = cptr.getFrameDepth() - n;
    else
      n = - n;
    if(n < 0) {
      throw new EvalException("not that many frames on the stack");
    }
    while (!cptr.isTopLevel() ) {
      if (cptr.getType() == Type.FUNCTION) {
        if (n == 0) {
          return cptr.getCall();
        } else {
          n--;
        }
      }
      cptr = cptr.getParent();
    }
    if (n == 0 && cptr.isTopLevel()) {
      return cptr.getCall();
    }
    throw new EvalException("not that many frames on the stack");
  }



 
  @Internal("sys.parent")
  public static int sysParent(@Current Context context, int n) {
   
    Context cptr = findStartingContext(context);
   
    int i, nframe;
    i = nframe = cptr.getFrameDepth();
    /* This is a pretty awful kludge, but the alternative would be
       a major redesign of everything... -pd */
    while (n-- > 0)
        i = R_sysparent(nframe - i + 1, cptr);
    return i;
 
  }

  public static Context findStartingContext(Context context) {
    /* first find the context that sys.xxx needs to be evaluated in */
    Context cptr = context;
    Environment t = cptr.getCallingEnvironment();
    while (!cptr.isTopLevel()) {
      if(cptr.getType() == Type.FUNCTION) {
        if(cptr.getEnvironment() == t) {
          break;
        }
      }
      cptr = cptr.getParent();
    }
    return cptr;
  }


  @Internal("sys.frame")
  public static Environment sysFrame(@Current Context context, int which) {
    return R_sysframe(which, findStartingContext(context));
  }

  @Internal("sys.call")
  public static FunctionCall sysCall(@Current Context context, int which) {
    return R_syscall(which, findStartingContext(context));
  }

  @Internal("sys.function")
  public static Function sysFunction(@Current Context context, int which) {
    return R_sysfunction(which, findStartingContext(context));
  }


}
TOP

Related Classes of org.renjin.primitives.Contexts

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.