Package org.renjin.repl

Source Code of org.renjin.repl.JlineRepl

package org.renjin.repl;

import java.io.IOException;
import java.io.PrintWriter;

import jline.UnsupportedTerminal;
import jline.console.ConsoleReader;

import org.renjin.eval.Context;
import org.renjin.eval.EvalException;
import org.renjin.eval.Session;
import org.renjin.eval.SessionBuilder;
import org.renjin.parser.ParseOptions;
import org.renjin.parser.ParseState;
import org.renjin.parser.RLexer;
import org.renjin.parser.RParser;
import org.renjin.parser.RParser.StatusResult;
import org.renjin.primitives.Warning;
import org.renjin.sexp.FunctionCall;
import org.renjin.sexp.Promise;
import org.renjin.sexp.SEXP;
import org.renjin.sexp.Symbol;
import org.renjin.RenjinVersion;

import com.google.common.base.Strings;

/**
* A Read-Eval-Print Loop that uses Jline for
* reading lines
*/
public class JlineRepl {

  /**
   * Echo lines to standard out.
   */
  private boolean echo;

  /**
   * Whether to abort evaluation if an error is encountered
   */
  private boolean stopOnError;

  public static void main(String[] args) throws Exception {
    JlineRepl repl = new JlineRepl(SessionBuilder.buildDefault());
    repl.run();
  }
 
  private Context topLevelContext;
  private ConsoleReader reader;

  public JlineRepl(Session session) throws Exception {
   
    if(Strings.nullToEmpty(System.getProperty("os.name")).startsWith("Windows")) {
      // AnsiWindowsTerminal does not work properly in WIndows 7
      // so disabling across the board for now
      reader = new ConsoleReader(System.in, System.out, new UnsupportedTerminal());
    } else {
      reader = new ConsoleReader();
    }

    // disable events triggered by ! (this is valid R !!)
    reader.setExpandEvents(false);

    session.setSessionController(new JlineSessionController(reader.getTerminal()));
    this.topLevelContext = session.getTopLevelContext();

  }

  public JlineRepl(Session session, ConsoleReader reader) throws IOException {
    session.setSessionController(new JlineSessionController(reader.getTerminal()));
    this.topLevelContext = session.getTopLevelContext();
    this.reader = reader;
  }


  public void setEcho(boolean echo) {
    this.echo = echo;
  }

  public boolean isEcho() {
    return echo;
  }

  public boolean isStopOnError() {
    return stopOnError;
  }

  public void setStopOnError(boolean stopOnError) {
    this.stopOnError = stopOnError;
  }

  public void run() throws Exception {

    reader.getTerminal().init();

    printGreeting();

    try {
      while(readExpression()) { }

    } finally {
      reader.getTerminal().restore();
    }
  }

  private void printGreeting() throws Exception {

    try {
      RenjinVersion renjin = new RenjinVersion();
      reader.println("Renjin " + renjin.getVersionName());
    } catch (IOException e) {
      reader.println("Renjin");
    }

    reader.println("Copyright (C) 2013 The R Foundation for Statistical Computing");
    reader.println("Copyright (C) 2014 BeDataDriven");

  }

  private boolean readExpression() throws Exception {

    reader.setPrompt("> ");

    ParseOptions options = new ParseOptions();
    ParseState parseState = new ParseState();
    JlineReader lineReader = new JlineReader(reader);
    lineReader.setEcho(echo);
    lineReader.setEchoOut(reader.getOutput());

    RLexer lexer = new RLexer(options, parseState, lineReader);
    if(lexer.isEof()) {
      return false;
    }

    RParser parser = new RParser(options, parseState, lexer);
    while(!parser.parse()) {
      if(lexer.errorEncountered()) {
        String errorMessage = "Syntax error at " + lexer.getErrorLocation() + ": " + lexer.getErrorMessage();
        reader.getOutput().append(errorMessage + "\n");
        if(stopOnError) {
          throw new RuntimeException(errorMessage);
        }
      }
    }


    SEXP exp = parser.getResult();
    if(parser.getResultStatus() == StatusResult.EOF) {
      return true;
    } else if(exp == null) {
      return true;
    }
   
    // clean up last warnings from any previous run
    clearWarnings();

    try {
      SEXP result = topLevelContext.evaluate(exp, topLevelContext.getGlobalEnvironment());

      if(!topLevelContext.getSession().isInvisible()) {
        topLevelContext.evaluate(FunctionCall.newCall(Symbol.get("print"), Promise.repromise(result)));
      }

      printWarnings();
    } catch(EvalException e) {
      printEvalException(e);
      if(stopOnError) {
        throw e;
      }
    } catch(QuitException e) {
      return false;
    } catch(Exception e) {
      printException(e);
      if(stopOnError) {
        throw e;
      }
    }
    return true;
  }


  private void printException(Exception e) throws IOException {
    reader.getOutput().append("ERROR: " + e.getMessage());
    PrintWriter printWriter = new PrintWriter(reader.getOutput());
    e.printStackTrace(printWriter);
    printWriter.flush();
    reader.getOutput().flush();
  }

  private void printEvalException(EvalException e) throws IOException {
    reader.getOutput().append("ERROR: ").append(e.getMessage()).append("\n");
    e.printRStackTrace(reader.getOutput());   
    reader.getOutput().flush();
  }

  private 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());
    }
  }

  private void clearWarnings() {
    topLevelContext.getEnvironment().getBaseEnvironment().remove(Warning.LAST_WARNING);
  }

}
TOP

Related Classes of org.renjin.repl.JlineRepl

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.