Package org.renjin.script

Source Code of org.renjin.script.RenjinScriptEngine$FunctionCallBuilder

package org.renjin.script;

import com.google.common.io.CharSource;
import org.renjin.eval.Context;
import org.renjin.eval.EvalException;
import org.renjin.eval.Session;
import org.renjin.invoke.reflection.converters.Converters;
import org.renjin.invoke.reflection.converters.RuntimeConverter;
import org.renjin.parser.RParser;
import org.renjin.primitives.Warning;
import org.renjin.primitives.special.BreakException;
import org.renjin.primitives.special.NextException;
import org.renjin.sexp.*;

import javax.script.*;
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class RenjinScriptEngine implements ScriptEngine, Invocable {

  private final RenjinScriptEngineFactory factory;
  private final Context topLevelContext;
 
  RenjinScriptEngine(RenjinScriptEngineFactory factory, Session session) {
    super();
    this.factory = factory;
    this.topLevelContext = session.getTopLevelContext();
  }

  public Session getSession() {
    return topLevelContext.getSession();
  }
 
  public Context getTopLevelContext() {
    return topLevelContext;
  }
 
  @Override
  public Bindings createBindings() {
    return new RenjinBindings(new HashFrame());
  }
 
  @Override
  public Object get(String key) {
    return topLevelContext.getEnvironment().getVariable(Symbol.get(key));
  }

  @Override
  public Bindings getBindings(int scope) {
    switch(scope) {
      case ScriptContext.ENGINE_SCOPE:
        return new RenjinBindings(topLevelContext.getEnvironment().getFrame());

      default:
      case ScriptContext.GLOBAL_SCOPE:
        throw new UnsupportedOperationException();

    }
  }

  @Override
  public ScriptContext getContext() {
    return new RenjinScriptContext(topLevelContext);
  }

  @Override
  public void put(String key, Object value) {
    topLevelContext.getEnvironment().setVariable(Symbol.get(key),
        Converters.get(value.getClass()).convertToR(value));
  }

  @Override
  public void setBindings(Bindings bindings, int scope) {

  }

  @Override
  public void setContext(ScriptContext context) {
    throw new UnsupportedOperationException("Cannot set the context");
  }


  @Override
  public Object eval(Reader reader, Bindings n) throws ScriptException {
    throw new UnsupportedOperationException();
  }

  @Override
  public Object eval(String script, Bindings n) throws ScriptException {
    throw new UnsupportedOperationException("nyi");
  }

  @Override
  public Object eval(String script) throws ScriptException {
    return eval(topLevelContext, RParser.parseSource(script + "\n"));
  }
 
  @Override
  public Object eval(String script, ScriptContext scriptContext)
      throws ScriptException {
    SEXP source = RParser.parseSource(script + "\n");
    return eval(unwrapContext(scriptContext), source);
  }

  @Override
  public Object eval(Reader reader) throws ScriptException {
    return eval(reader, topLevelContext);
  }
 
  @Override
  public Object eval(final Reader reader, ScriptContext scriptContext)
      throws ScriptException {
    return eval(reader, unwrapContext(scriptContext));
  }

  private Object eval(Reader reader, Context context) throws ScriptException {
    SEXP source;
    try {
      // terminate with '\n'
      CharSource terminated = CharSource.concat(
          newReaderSupplier(reader),
         CharSource.wrap("\n"));
      source = RParser.parseSource(terminated);
    } catch (IOException e) {
      throw new ScriptException(e);
    }
    return eval(context, source);
  }
 
  private Object eval(Context context, SEXP source) {
    try {
      return context.evaluate( source, context.getEnvironment());
    } catch(BreakException e) {
      throw new EvalException("no loop for break");
    } catch(NextException e) {
      throw new EvalException("no loop for next");

    }
  }

  public void eval(File file) throws IOException, ScriptException {
    InputStreamReader reader = new InputStreamReader(
        new FileInputStream(file));
    eval(reader);
    reader.close();
  }
 
  private CharSource newReaderSupplier(final Reader reader) {
    return new CharSource() {
      @Override
      public Reader openStream() throws IOException {
        return reader;
      }     
    };
  }

  private Context unwrapContext(ScriptContext scriptContext) {
    return ((RenjinScriptContext)scriptContext).getContext();
  }

  @Override
  public ScriptEngineFactory getFactory() {
    return factory;
  }

  @Override
  @SuppressWarnings("unchecked")
  public <T> T getInterface(Class<T> clasz) {
    return (T)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {clasz}, new InvocationHandler() {
     
      @Override
      public Object invoke(Object instance, Method method, Object[] arguments) throws Exception {
     
        SEXP result = invokeFunction(method.getName(), arguments);
        return Converters.get(method.getReturnType()).convertToJava(result);
     
      }
    });
  }

  @Override
  @SuppressWarnings("unchecked")
  public <T> T getInterface(final Object thiz, Class<T> clasz) {
    return (T)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {clasz}, new InvocationHandler() {
     
      @Override
      public Object invoke(Object instance, Method method, Object[] arguments) throws Exception {
        SEXP result = invokeMethod(thiz, method.getName(), arguments);
        return Converters.get(method.getReturnType()).convertToJava(result);
      }
    });   
  }

  @Override
  public SEXP invokeFunction(String name, Object... arguments)
      throws ScriptException, NoSuchMethodException {

    if(name == null) {
      throw new NullPointerException("name");
    }
  
    Function function = topLevelContext.getEnvironment().findFunction(topLevelContext, Symbol.get(name));
    if(function == null) {
      throw new NoSuchMethodException(name);
    }

    return invoke(function, arguments);
  }
 
  @Override
  public SEXP invokeMethod(Object thiz, String name, Object... arguments)
      throws ScriptException, NoSuchMethodException {
  
    SEXP element;
    if(thiz instanceof Environment) {
      element = ((Environment)thiz).getVariable(name);
    } else if(thiz instanceof ListVector) {
      element = ((ListVector)thiz).get(name);
    } else {
      throw new NoSuchMethodException(name);
    }
    if(!(element instanceof Function)) {
      throw new NoSuchMethodException(name);
    }
    Function method = (Function)element;
   
    return invoke(method, arguments);
  }
 
  private SEXP invoke(Function function, Object... arguments) {
    PairList.Builder argList = new PairList.Builder();
    for(Object argument : arguments) {
      argList.add(RuntimeConverter.INSTANCE.convertToR(argument));
    }
  
    FunctionCall call = new FunctionCall(function, argList.build());
 
    return topLevelContext.evaluate(call);
  }
 
  public FunctionCallBuilder invoke(String functionName) {
    return new FunctionCallBuilder(functionName);
  }

  public void printWarnings() {
    SEXP warnings = topLevelContext.getEnvironment().getBaseEnvironment().getVariable(Warning.LAST_WARNING);
    if(warnings != Symbol.UNBOUND_VALUE) {
      topLevelContext.evaluate( FunctionCall.newCall(Symbol.get("print.warnings"), warnings),
        topLevelContext.getEnvironment().getBaseEnvironment());
    }

    topLevelContext.getEnvironment().getBaseEnvironment().remove(Warning.LAST_WARNING);
  }
 
  public class FunctionCallBuilder {
   
    private Symbol function;
    private PairList.Builder arguments = new PairList.Builder();
   
    private FunctionCallBuilder(String functionName) {
      this.function = Symbol.get(functionName);
    }
   
    public FunctionCallBuilder withArgument(Object argument) {
      arguments.add(RuntimeConverter.INSTANCE.convertToR(argument));
      return this;
    }
   
    public FunctionCallBuilder withNamedArgument(String name, Object argument) {
      arguments.add(name, RuntimeConverter.INSTANCE.convertToR(argument));
      return this;
    }
   
    public <S extends SEXP> S apply() {
      FunctionCall call = new FunctionCall(function, arguments.build());
      return (S)topLevelContext.evaluate(call);
    }
  }

  public Context getRuntimeContext() {
    return topLevelContext;
  }

}
TOP

Related Classes of org.renjin.script.RenjinScriptEngine$FunctionCallBuilder

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.