src.org.python.util.InteractiveInterpreter Maven / Gradle / Ivy
Show all versions of jython-standalone Show documentation
// Copyright (c) Corporation for National Research Initiatives
package org.python.util;
import org.python.core.*;
/**
* This class provides the interface for compiling and running code that supports an interactive
* interpreter.
*/
// Based on CPython-1.5.2's code module
public class InteractiveInterpreter extends PythonInterpreter {
/**
* Construct an InteractiveInterpreter with all default characteristics: default state (from
* {@link Py#getSystemState()}), and a new empty dictionary of local variables.
* */
public InteractiveInterpreter() {
this(null);
}
/**
* Construct an InteractiveInterpreter with state (from {@link Py#getSystemState()}), and the
* specified dictionary of local variables.
*
* @param locals dictionary to use, or if null
, a new empty one will be created
*/
public InteractiveInterpreter(PyObject locals) {
this(locals, null);
}
/**
* Construct an InteractiveInterpreter with, and system state the specified dictionary of local
* variables.
*
* @param locals dictionary to use, or if null
, a new empty one will be created
* @param systemState interpreter state, or if null
use {@link Py#getSystemState()}
*/
public InteractiveInterpreter(PyObject locals, PySystemState systemState) {
super(locals, systemState);
}
/**
* Compile and run some source in the interpreter, in the mode {@link CompileMode#single} which
* is used for incremental compilation at the interactive console, known as "".
*
* @param source Python code
* @return true
to indicate a partial statement was entered
*/
public boolean runsource(String source) {
return runsource(source, "", CompileMode.single);
}
/**
* Compile and run some source in the interpreter, in the mode {@link CompileMode#single} which
* is used for incremental compilation at the interactive console.
*
* @param source Python code
* @param filename name with which to label this console input (e.g. in error messages).
* @return true
to indicate a partial statement was entered
*/
public boolean runsource(String source, String filename) {
return runsource(source, filename, CompileMode.single);
}
/**
* Compile and run some source in the interpreter, according to the {@link CompileMode} given.
* This method supports incremental compilation and interpretation through the return value,
* where true
signifies that more input is expected in order to complete the Python
* statement. An interpreter can use this to decide whether to use sys.ps1
("
* >>>
") or sys.ps2
("...
") to prompt the next line.
* The arguments are the same as the mandatory ones in the Python compile()
* command.
*
* One the following can happen:
*
* - The input is incorrect; compilation raised an exception (SyntaxError or OverflowError). A
* syntax traceback will be printed by calling {@link #showexception(PyException)}. Return is
*
false
.
*
* - The input is incomplete, and more input is required; compilation returned no code.
* Nothing happens. Return is
true
.
*
* - The input is complete; compilation returned a code object. The code is executed by
* calling {@link #runcode(PyObject)} (which also handles run-time exceptions, except for
* SystemExit). Return is
false
.
*
*
* @param source Python code
* @param filename name with which to label this console input (e.g. in error messages).
* @param kind of compilation required: {@link CompileMode#eval}, {@link CompileMode#exec} or
* {@link CompileMode#single}
* @return true
to indicate a partial statement was provided
*/
public boolean runsource(String source, String filename, CompileMode kind) {
PyObject code;
try {
code = Py.compile_command_flags(source, filename, kind, cflags, true);
} catch (PyException exc) {
if (exc.match(Py.SyntaxError)) {
// Case 1
showexception(exc);
return false;
} else if (exc.match(Py.ValueError) || exc.match(Py.OverflowError)) {
// Should not print the stack trace, just the error.
showexception(exc);
return false;
} else {
throw exc;
}
}
// Case 2
if (code == Py.None) {
return true;
}
// Case 3
runcode(code);
return false;
}
/**
* Execute a code object. When an exception occurs, {@link #showexception(PyException)} is
* called to display a stack trace, except in the case of SystemExit, which is re-raised.
*
* A note about KeyboardInterrupt: this exception may occur elsewhere in this code, and may not
* always be caught. The caller should be prepared to deal with it.
**/
// Make this run in another thread somehow????
public void runcode(PyObject code) {
try {
exec(code);
} catch (PyException exc) {
if (exc.match(Py.SystemExit)) {
throw exc;
}
showexception(exc);
}
}
public void showexception(PyException exc) {
// Should probably add code to handle skipping top stack frames
// somehow...
Py.printException(exc);
}
public void write(String data) {
Py.stderr.write(data);
}
public StringBuilder buffer = new StringBuilder();
public String filename = "";
public void resetbuffer() {
buffer.setLength(0);
}
/**
* Pause the current code, sneak an exception raiser into sys.trace_func, and then continue the
* code hoping that Jython will get control to do the break;
**/
public void interrupt(ThreadState ts) {
TraceFunction breaker = new BreakTraceFunction();
TraceFunction oldTrace = ts.tracefunc;
ts.tracefunc = breaker;
if (ts.frame != null) {
ts.frame.tracefunc = breaker;
}
ts.tracefunc = oldTrace;
// ts.thread.join();
}
}
class BreakTraceFunction extends TraceFunction {
private void doBreak() {
throw new Error("Python interrupt");
// Thread.currentThread().interrupt();
}
@Override
public TraceFunction traceCall(PyFrame frame) {
doBreak();
return null;
}
@Override
public TraceFunction traceReturn(PyFrame frame, PyObject ret) {
doBreak();
return null;
}
@Override
public TraceFunction traceLine(PyFrame frame, int line) {
doBreak();
return null;
}
@Override
public TraceFunction traceException(PyFrame frame, PyException exc) {
doBreak();
return null;
}
}