001: // Copyright (c) Corporation for National Research Initiatives
002: package org.lateralnz.common.util;
003:
004: import org.python.core.*;
005: import org.python.util.*;
006:
007: // Based on CPython-1.5.2's code module
008:
009: // JRB 13/08/2004 : can't pass a new state into this so temporarily reproduced this class here
010:
011: public class InteractiveInterpreter extends PythonInterpreter {
012: private InteractiveInterpreter() {
013: }
014:
015: public InteractiveInterpreter(PyObject locals,
016: PySystemState systemState) {
017: super (locals, systemState);
018: cflags = new CompilerFlags();
019: }
020:
021: /**
022: * Compile and run some source in the interpreter.
023: *
024: * Arguments are as for compile_command().
025: *
026: * One several things can happen:
027: *
028: * 1) The input is incorrect; compile_command() raised an exception
029: * (SyntaxError or OverflowError). A syntax traceback will be printed
030: * by calling the showsyntaxerror() method.
031: *
032: * 2) The input is incomplete, and more input is required;
033: * compile_command() returned None. Nothing happens.
034: *
035: * 3) The input is complete; compile_command() returned a code object.
036: * The code is executed by calling self.runcode() (which also handles
037: * run-time exceptions, except for SystemExit).
038: *
039: * The return value is 1 in case 2, 0 in the other cases (unless an
040: * exception is raised). The return value can be used to decide
041: * whether to use sys.ps1 or sys.ps2 to prompt the next line.
042: **/
043: public boolean runsource(String source) {
044: return runsource(source, "<input>", "single");
045: }
046:
047: public boolean runsource(String source, String filename) {
048: return runsource(source, filename, "single");
049: }
050:
051: public boolean runsource(String source, String filename,
052: String symbol) {
053: PyObject code;
054: try {
055: code = org.python.modules.codeop.compile_command_flags(
056: source, filename, symbol, cflags);
057: } catch (PyException exc) {
058: if (Py.matchException(exc, Py.SyntaxError)) {
059: // Case 1
060: showexception(exc);
061: return false;
062: } else if (Py.matchException(exc, Py.ValueError)
063: || Py.matchException(exc, Py.OverflowError)) {
064: // Should not print the stack trace, just the error.
065: showexception(exc);
066: return false;
067: } else {
068: throw exc;
069: }
070: }
071: // Case 2
072: if (code == Py.None)
073: return true;
074: // Case 3
075: runcode(code);
076: return false;
077: }
078:
079: /**
080: * execute a code object.
081: *
082: * When an exception occurs, self.showtraceback() is called to display
083: * a traceback. All exceptions are caught except SystemExit, which is
084: * reraised.
085: *
086: * A note about KeyboardInterrupt: this exception may occur elsewhere
087: * in this code, and may not always be caught. The caller should be
088: * prepared to deal with it.
089: **/
090:
091: // Make this run in another thread somehow????
092: public void runcode(PyObject code) {
093: try {
094: exec(code);
095: } catch (PyException exc) {
096: if (Py.matchException(exc, Py.SystemExit))
097: throw exc;
098: showexception(exc);
099: }
100: }
101:
102: public void showexception(PyException exc) {
103: // Should probably add code to handle skipping top stack frames
104: // somehow...
105: write(exc.toString());
106: }
107:
108: public void write(String data) {
109: Py.stderr.write(data);
110: }
111:
112: public StringBuffer buffer = new StringBuffer();
113: public String filename = "<stdin>";
114:
115: public void resetbuffer() {
116: buffer.setLength(0);
117: }
118:
119: /** Pause the current code, sneak an exception raiser into
120: * sys.trace_func, and then continue the code hoping that JPython will
121: * get control to do the break;
122: **/
123: public void interrupt(ThreadState ts) {
124: TraceFunction breaker = new BreakTraceFunction();
125: TraceFunction oldTrace = ts.systemState.tracefunc;
126: ts.systemState.tracefunc = breaker;
127: if (ts.frame != null)
128: ts.frame.tracefunc = breaker;
129: ts.systemState.tracefunc = oldTrace;
130: //ts.thread.join();
131: }
132: }
133:
134: class BreakTraceFunction extends TraceFunction {
135: private void doBreak() {
136: throw new Error("Python interrupt");
137: //Thread.currentThread().interrupt();
138: }
139:
140: public TraceFunction traceCall(PyFrame frame) {
141: doBreak();
142: return null;
143: }
144:
145: public TraceFunction traceReturn(PyFrame frame, PyObject ret) {
146: doBreak();
147: return null;
148: }
149:
150: public TraceFunction traceLine(PyFrame frame, int line) {
151: doBreak();
152: return null;
153: }
154:
155: public TraceFunction traceException(PyFrame frame, PyException exc) {
156: doBreak();
157: return null;
158: }
159: }
|