Example #1
0
  /**
   * The read-eval-print loop, which can take input from a console, command line expression or a
   * file. There are two ways the repl can terminate:
   *
   * <ol>
   *   <li>A {@code quit} command is executed successfully, which case the system exits from the
   *       {@link Quit} {@code .Internal} .
   *   <li>EOF on the input.
   * </ol>
   *
   * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before exiting.
   * So,in either case, we never return.
   */
  static int readEvalPrint(PolyglotEngine vm) {
    int lastStatus = 0;
    ContextInfo contextInfo = ContextInfo.getContextInfo(vm);
    ConsoleHandler consoleHandler = contextInfo.getConsoleHandler();
    try {
      // console.println("initialize time: " + (System.currentTimeMillis() - start));
      REPL:
      for (; ; ) {
        boolean doEcho = doEcho(vm);
        consoleHandler.setPrompt(doEcho ? "> " : null);
        try {
          String input = consoleHandler.readLine();
          if (input == null) {
            throw new EOFException();
          }
          String trInput = input.trim();
          if (trInput.equals("") || trInput.charAt(0) == '#') {
            // nothing to parse
            continue;
          }

          String continuePrompt = getContinuePrompt();
          StringBuffer sb = new StringBuffer(input);
          Source source = RSource.fromTextInternal(sb.toString(), RSource.Internal.SHELL_INPUT);
          while (true) {
            lastStatus = 0;
            try {
              try {
                vm.eval(source);
                // checked exceptions are wrapped in RuntimeExceptions
              } catch (RuntimeException e) {
                if (e.getCause() instanceof com.oracle.truffle.api.vm.IncompleteSourceException) {
                  throw e.getCause().getCause();
                }
                throw e;
              }
            } catch (IncompleteSourceException e) {
              // read another line of input
              consoleHandler.setPrompt(doEcho ? continuePrompt : null);
              String additionalInput = consoleHandler.readLine();
              if (additionalInput == null) {
                throw new EOFException();
              }
              sb.append(additionalInput);
              source = RSource.fromTextInternal(sb.toString(), RSource.Internal.SHELL_INPUT);
              // The only continuation in the while loop
              continue;
            } catch (ParseException e) {
              e.report(consoleHandler);
              lastStatus = 1;
            } catch (RError e) {
              // drop through to continue REPL and remember last eval was an error
              lastStatus = 1;
            } catch (JumpToTopLevelException e) {
              // drop through to continue REPL
            } catch (DebugExitException e) {
              throw (RuntimeException) e.getCause();
            } catch (ExitException e) {
              // usually from quit
              int status = e.getStatus();
              if (contextInfo.getParent() == null) {
                vm.dispose();
                Utils.systemExit(status);
              } else {
                return status;
              }
            } catch (Throwable e) {
              RInternalError.reportErrorAndConsoleLog(e, consoleHandler, 0);
              // We continue the repl even though the system may be broken
              lastStatus = 1;
            }
            continue REPL;
          }
        } catch (UserInterruptException e) {
          // interrupted by ctrl-c
        }
      }
    } catch (JumpToTopLevelException | EOFException ex) {
      // JumpToTopLevelException can happen if user profile invokes browser (unlikely but
      // possible)
      try {
        vm.eval(QUIT_EOF);
      } catch (JumpToTopLevelException e) {
        Utils.systemExit(0);
      } catch (ExitException e) {
        // normal quit, but with exit code based on lastStatus
        if (contextInfo.getParent() == null) {
          Utils.systemExit(lastStatus);
        } else {
          return lastStatus;
        }
      } catch (Throwable e) {
        throw RInternalError.shouldNotReachHere(e);
      }
    } finally {
      vm.dispose();
    }
    return 0;
  }
Example #2
0
  static PolyglotEngine createPolyglotEngineFromCommandLine(
      RCmdOptions options,
      boolean embedded,
      boolean initial,
      InputStream inStream,
      OutputStream outStream,
      String[] env) {
    RStartParams rsp = new RStartParams(options, embedded);

    String fileArg = options.getString(FILE);
    if (fileArg != null) {
      if (options.getStringList(EXPR) != null) {
        Utils.rSuicide("cannot use -e with -f or --file");
      }
      if (!rsp.getSlave()) {
        rsp.setSaveAction(SA_TYPE.NOSAVE);
      }
      if (fileArg.equals("-")) {
        // means stdin, but still implies NO_SAVE
        fileArg = null;
      } else {
        fileArg = unescapeSpace(fileArg);
      }
      // cf GNU R
      rsp.setInteractive(false);
    }

    /*
     * Outputting the welcome message here has the virtue that the VM initialization delay
     * occurs later. However, it does not work in embedded mode as console redirects have not
     * been installed at this point. So we do it later in REmbedded.
     */
    if (!rsp.getQuiet() && !embedded) {
      System.out.println(RRuntime.WELCOME_MESSAGE);
    }
    /*
     * Whether the input is from stdin, a file (-f), or an expression on the command line (-e)
     * it goes through the console. N.B. -f and -e can't be used together and this is already
     * checked.
     */
    ConsoleHandler consoleHandler;
    if (fileArg != null) {
      List<String> lines;
      String filePath;
      try {
        /*
         * If initial==false, ~ expansion will not have been done and the open will fail.
         * It's harmless to always do it.
         */
        File file = new File(Utils.tildeExpand(fileArg));
        lines = Files.readAllLines(file.toPath());
        filePath = file.getCanonicalPath();
      } catch (IOException e) {
        if (initial) {
          throw Utils.rSuicide(String.format(RError.Message.NO_SUCH_FILE.message, fileArg));
        } else {
          throw RError.error(RError.NO_CALLER, RError.Message.NO_SUCH_FILE, fileArg);
        }
      }
      consoleHandler = new StringConsoleHandler(lines, outStream, filePath);
    } else if (options.getStringList(EXPR) != null) {
      List<String> exprs = options.getStringList(EXPR);
      for (int i = 0; i < exprs.size(); i++) {
        exprs.set(i, unescapeSpace(exprs.get(i)));
      }
      if (!rsp.getSlave()) {
        rsp.setSaveAction(SA_TYPE.NOSAVE);
      }
      // cf GNU R
      rsp.setInteractive(false);
      consoleHandler =
          new StringConsoleHandler(exprs, outStream, RSource.Internal.EXPRESSION_INPUT.string);
    } else {
      /*
       * GnuR behavior differs from the manual entry for {@code interactive} in that {@code
       * --interactive} never applies to {@code -e/-f}, only to console input that has been
       * redirected from a pipe/file etc.
       *
       * If we are in embedded mode, the creation of ConsoleReader and the ConsoleHandler
       * should be lazy, as these may not be necessary and can cause hangs if stdin has been
       * redirected.
       */
      Console sysConsole = System.console(); // TODO fix for context sessions
      boolean isInteractive = options.getBoolean(INTERACTIVE) || sysConsole != null;
      if (!isInteractive
          && rsp.getSaveAction() != SA_TYPE.SAVE
          && rsp.getSaveAction() != SA_TYPE.NOSAVE) {
        String msg = "you must specify '--save', '--no-save' or '--vanilla'";
        if (initial) {
          throw Utils.rSuicide(msg);
        } else {
          throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, msg);
        }
      }
      if (embedded) {
        consoleHandler = new EmbeddedConsoleHandler(rsp);
      } else {
        boolean useReadLine = !rsp.getNoReadline();
        if (useReadLine) {
          consoleHandler = new JLineConsoleHandler(rsp, inStream, outStream);
        } else {
          consoleHandler = new DefaultConsoleHandler(inStream, outStream);
        }
      }
    }
    return ContextInfo.create(
            rsp,
            env,
            ContextKind.SHARE_NOTHING,
            initial ? null : RContext.getInstance(),
            consoleHandler)
        .createVM();
  }
Example #3
0
  @TruffleBoundary
  static void printNoDimList(RAbstractContainer s, PrintContext printCtx) throws IOException {
    final PrintParameters pp = printCtx.parameters();
    final PrintWriter out = printCtx.output();

    final StringBuilder tagbuf = printCtx.getOrCreateTagBuffer();
    // save the original length so that we can restore the original value
    int taglen = tagbuf.length();

    int ns = s.getLength();

    RAbstractStringVector names;
    names = Utils.castTo(RRuntime.asAbstractVector(s.getNames(dummyAttrProfiles)));

    if (ns > 0) {
      int npr = (ns <= pp.getMax() + 1) ? ns : pp.getMax();
      /* '...max +1' ==> will omit at least 2 ==> plural in msg below */
      for (int i = 0; i < npr; i++) {
        if (i > 0) {
          out.println();
        }
        String ss = names == null ? null : Utils.<String>getDataAt(names, i);
        if (ss != null && !ss.isEmpty()) {
          /*
           * Bug for L <- list(`a\\b` = 1, `a\\c` = 2) : const char *ss =
           * translateChar(STRING_ELT(names, i));
           */
          if (taglen + ss.length() > TAGBUFLEN) {
            if (taglen <= TAGBUFLEN) {
              tagbuf.append("$...");
            }
          } else {
            /*
             * we need to distinguish character NA from "NA", which is a valid (if
             * non-syntactic) name
             */
            if (ss == RRuntime.STRING_NA) {
              tagbuf.append("$<NA>");
            } else if (RDeparse.isValidName(ss)) {
              tagbuf.append(String.format("$%s", ss));
            } else {
              tagbuf.append(String.format("$`%s`", ss));
            }
          }

        } else {
          if (taglen + indexWidth(i) > TAGBUFLEN) {
            if (taglen <= TAGBUFLEN) {
              tagbuf.append("$...");
            }
          } else {
            tagbuf.append(String.format("[[%d]]", i + 1));
          }
        }

        out.println(tagbuf);
        Object si = s.getDataAtAsObject(i);
        if (si instanceof RAttributable && ((RAttributable) si).isObject()) {
          RContext.getEngine().printResult(si);
        } else {
          ValuePrinters.INSTANCE.print(si, printCtx);
          ValuePrinters.printNewLine(printCtx);
        }
        tagbuf.setLength(taglen); // reset tag buffer to the original value
      }

      if (npr < ns) {
        out.printf("\n [ reached getOption(\"max.print\") -- omitted %d entries ]", ns - npr);
      }

    } else {
      /* ns = length(s) == 0 */

      /* Formal classes are represented as empty lists */
      String className = null;
      if (printCtx.printerNode().isObject(s) && printCtx.printerNode().isMethodDispatchOn()) {
        RAbstractStringVector klass =
            Utils.castTo(RRuntime.asAbstractVector(s.getAttr(RRuntime.CLASS_ATTR_KEY)));
        if (klass != null && klass.getLength() == 1) {
          String ss = klass.getDataAt(0);
          String str = snprintf(200, ".__C__%s", ss);
          Frame frame = com.oracle.truffle.r.runtime.Utils.getActualCurrentFrame();
          if (ReadVariableNode.lookupAny(str, frame, false) != null) {
            className = ss;
          }
        }
      }
      if (className != null) {
        out.printf("An object of class \"%s\"", className);
      } else {
        if (names != null) {
          out.print("named ");
        }
        out.print("list()");
      }
    }
  }