From: <nr...@us...> - 2009-07-17 05:27:55
|
Revision: 6541 http://jython.svn.sourceforge.net/jython/?rev=6541&view=rev Author: nriley Date: 2009-07-17 05:27:51 +0000 (Fri, 17 Jul 2009) Log Message: ----------- JSR 223 support for compile and eval of Strings. Modified Paths: -------------- branches/jsr223/build.xml branches/jsr223/src/org/python/core/Py.java branches/jsr223/src/org/python/core/PyFinalizableInstance.java branches/jsr223/src/org/python/jsr223/PyScriptEngine.java branches/jsr223/src/org/python/util/PythonInterpreter.java Added Paths: ----------- branches/jsr223/src/META-INF/ branches/jsr223/src/META-INF/services/ branches/jsr223/src/META-INF/services/javax.script.ScriptEngineFactory branches/jsr223/tests/java/org/python/jsr223/ branches/jsr223/tests/java/org/python/jsr223/ScriptEngineTest.java Modified: branches/jsr223/build.xml =================================================================== --- branches/jsr223/build.xml 2009-07-17 04:28:55 UTC (rev 6540) +++ branches/jsr223/build.xml 2009-07-17 05:27:51 UTC (rev 6541) @@ -503,6 +503,10 @@ </copy> <!-- grammar must now be up to date --> <property name="antlr.notneeded" value="true" /> + + <copy todir="${compile.dir}/META-INF/services"> + <fileset dir="${source.dir}/META-INF/services" /> + </copy> </target> <!-- Added: branches/jsr223/src/META-INF/services/javax.script.ScriptEngineFactory =================================================================== --- branches/jsr223/src/META-INF/services/javax.script.ScriptEngineFactory (rev 0) +++ branches/jsr223/src/META-INF/services/javax.script.ScriptEngineFactory 2009-07-17 05:27:51 UTC (rev 6541) @@ -0,0 +1 @@ +org.python.jsr223.PyScriptEngineFactory Modified: branches/jsr223/src/org/python/core/Py.java =================================================================== --- branches/jsr223/src/org/python/core/Py.java 2009-07-17 04:28:55 UTC (rev 6540) +++ branches/jsr223/src/org/python/core/Py.java 2009-07-17 05:27:51 UTC (rev 6541) @@ -1021,7 +1021,7 @@ stderr.println(getStackTrace((Throwable) javaError)); } } - stderr.println(formatException(type, value, tb)); + stderr.println(formatException(type, value)); } /** @@ -1074,7 +1074,7 @@ out.print("^\n"); } - static String formatException(PyObject type, PyObject value, PyObject tb) { + public static String formatException(PyObject type, PyObject value) { StringBuilder buf = new StringBuilder(); if (PyException.isExceptionClass(type)) { @@ -1100,7 +1100,7 @@ } else { buf.append(type.__str__()); } - if (value != Py.None) { + if (value != null && value != Py.None) { // only print colon if the str() of the object is not the empty string PyObject s = value.__str__(); if (!(s instanceof PyString) || s.__len__() != 0) { Modified: branches/jsr223/src/org/python/core/PyFinalizableInstance.java =================================================================== --- branches/jsr223/src/org/python/core/PyFinalizableInstance.java 2009-07-17 04:28:55 UTC (rev 6540) +++ branches/jsr223/src/org/python/core/PyFinalizableInstance.java 2009-07-17 05:27:51 UTC (rev 6541) @@ -31,7 +31,7 @@ } catch (PyException e) { ; } Py.stderr.println("Exception " + - Py.formatException(exc.type, exc.value, exc.traceback) + + Py.formatException(exc.type, exc.value) + " in " + method + " ignored"); } Modified: branches/jsr223/src/org/python/jsr223/PyScriptEngine.java =================================================================== --- branches/jsr223/src/org/python/jsr223/PyScriptEngine.java 2009-07-17 04:28:55 UTC (rev 6540) +++ branches/jsr223/src/org/python/jsr223/PyScriptEngine.java 2009-07-17 05:27:51 UTC (rev 6541) @@ -1,5 +1,6 @@ package org.python.jsr223; +import org.python.core.*; import java.io.Reader; import javax.script.AbstractScriptEngine; import javax.script.Bindings; @@ -10,9 +11,6 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptException; -import org.python.core.Py; -import org.python.core.PyException; -import org.python.core.PyObject; import org.python.util.PythonInterpreter; public class PyScriptEngine extends AbstractScriptEngine implements Compilable, Invocable { @@ -26,9 +24,17 @@ } public Object eval(String script, ScriptContext context) throws ScriptException { - throw new UnsupportedOperationException("Not supported yet."); + return eval(compileScript(script, context)); } + private Object eval(PyCode code) throws ScriptException { + try { + return interp.eval(code).__tojava__(Object.class); + } catch (PyException e) { + throw scriptException(e); + } + } + // it would be nice if we supported a Reader interface in Py.compileFlags, instead of having // to create a string here public Object eval(Reader reader, ScriptContext context) throws ScriptException { @@ -43,15 +49,26 @@ return factory; } - // i assume this should simply return a PyModule object or something public CompiledScript compile(String script) throws ScriptException { - throw new UnsupportedOperationException("Not supported yet."); + return new PyCompiledScript(compileScript(script, context)); } public CompiledScript compile(Reader script) throws ScriptException { throw new UnsupportedOperationException("Not supported yet."); } + private PyCode compileScript(String script, ScriptContext context) throws ScriptException { + try { + String filename = (String) context.getAttribute(ScriptEngine.FILENAME); + if (filename == null) + return interp.compileExpressionOrModule(script); + else + return interp.compileExpressionOrModule(script, filename); + } catch (PyException e) { + throw scriptException(e); + } + } + public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptException, NoSuchMethodException { try { if (thiz instanceof PyObject) { @@ -85,6 +102,48 @@ throw new UnsupportedOperationException("Not supported yet."); } + private static ScriptException scriptException(PyException e) { + ScriptException se = null; + try { + e.normalize(); + + PyObject type = e.type; + PyObject value = e.value; + PyTraceback tb = e.traceback; + + if (__builtin__.isinstance(value, Py.SyntaxError)) { + PyObject filename = value.__findattr__("filename"); + PyObject lineno = value.__findattr__("lineno"); + PyObject offset = value.__findattr__("offset"); + value = value.__findattr__("msg"); + + se = new ScriptException( + Py.formatException(type, value), + filename == null ? "<script>" : filename.toString(), + lineno == null ? 0 : lineno.asInt(), + offset == null ? 0 : offset.asInt()); + } else if (tb != null) { + String filename; + if (tb.tb_frame == null || tb.tb_frame.f_code == null) + filename = null; + else + filename = tb.tb_frame.f_code.co_filename; + + se = new ScriptException( + Py.formatException(type, value), + filename, + tb.tb_lineno); + } else { + se = new ScriptException(Py.formatException(type, value)); + } + se.initCause(e); + return se; + } catch (Exception ee) { + se = new ScriptException(e); + } + return se; + } + private static PyObject[] java2py(Object[] args) { PyObject wrapped[] = new PyObject[args.length]; for (int i = 0; i < args.length; i++) { @@ -93,18 +152,20 @@ return wrapped; } - // wraps a PyCode object - private static class PyCompiledScript extends CompiledScript { + private class PyCompiledScript extends CompiledScript { + private PyCode code; - @Override - public Object eval(ScriptContext arg0) throws ScriptException { - throw new UnsupportedOperationException("Not supported yet."); + PyCompiledScript(PyCode code) { + this.code = code; } - @Override public ScriptEngine getEngine() { - throw new UnsupportedOperationException("Not supported yet."); + return PyScriptEngine.this; } + public Object eval(ScriptContext ctx) throws ScriptException { + // can't read filename from context at this point + return PyScriptEngine.this.eval(code); + } } } Modified: branches/jsr223/src/org/python/util/PythonInterpreter.java =================================================================== --- branches/jsr223/src/org/python/util/PythonInterpreter.java 2009-07-17 04:28:55 UTC (rev 6540) +++ branches/jsr223/src/org/python/util/PythonInterpreter.java 2009-07-17 05:27:51 UTC (rev 6541) @@ -2,8 +2,10 @@ import java.util.Properties; +import org.python.antlr.base.mod; import org.python.core.CompileMode; import org.python.core.CompilerFlags; +import org.python.core.ParserFacade; import org.python.core.Py; import org.python.core.PyCode; import org.python.core.PyException; @@ -13,6 +15,7 @@ import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; +import org.python.core.PySyntaxError; import org.python.core.PySystemState; import org.python.core.__builtin__; @@ -130,6 +133,14 @@ } /** + * Evaluate a Python code object and return the result + */ + public PyObject eval(PyObject code) { + setState(); + return __builtin__.eval(code, locals, locals); + } + + /** * Execute a string of Python source in the local namespace */ public void exec(String s) { @@ -166,6 +177,34 @@ Py.flushLine(); } + /** + * Compile a string of Python source as either an expression (if possible) or module. + * + * Designed for use by a JSR 223 implementation: "the Scripting API does not distinguish + * between scripts which return values and those which do not, nor do they make the + * corresponding distinction between evaluating or executing objects." (SCR.4.2.1) + */ + public PyCode compileExpressionOrModule(String script) { + return compileExpressionOrModule(script, "<script>"); + } + + public PyCode compileExpressionOrModule(String script, String filename) { + mod node; + try { + // first, try parsing as an expression + node = ParserFacade.parse(script, CompileMode.eval, filename, cflags); + } catch (PySyntaxError e) { + try { + // then, try parsing as a module + node = ParserFacade.parse(script, CompileMode.exec, filename, cflags); + } catch (PySyntaxError ee) { + throw ee; + } + } + return Py.compile_flags(node, filename, CompileMode.eval, cflags); + } + + public PyObject getLocals() { return locals; } Added: branches/jsr223/tests/java/org/python/jsr223/ScriptEngineTest.java =================================================================== --- branches/jsr223/tests/java/org/python/jsr223/ScriptEngineTest.java (rev 0) +++ branches/jsr223/tests/java/org/python/jsr223/ScriptEngineTest.java 2009-07-17 05:27:51 UTC (rev 6541) @@ -0,0 +1,58 @@ +package org.python.jsr223; + +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import javax.script.SimpleScriptContext; +import junit.framework.TestCase; + +public class ScriptEngineTest extends TestCase { + + public void testEvalString() throws ScriptException { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine pythonEngine = manager.getEngineByName("python"); + + assertNull(pythonEngine.eval("x = 5")); + assertEquals(Integer.valueOf(5), pythonEngine.eval("x")); + } + + public void testSyntaxError() { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine pythonEngine = manager.getEngineByName("python"); + + try { + pythonEngine.eval("5q"); + } catch (ScriptException e) { + assertEquals(e.getColumnNumber(), 1); + assertEquals(e.getLineNumber(), 1); + assertTrue(e.getMessage().startsWith("SyntaxError: ")); + return; + } + assertTrue("Expected a ScriptException", false); + } + + public void testScriptFilename() { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine pythonEngine = manager.getEngineByName("python"); + SimpleScriptContext scriptContext = new SimpleScriptContext(); + scriptContext.setAttribute(ScriptEngine.FILENAME, "sample.py", ScriptContext.ENGINE_SCOPE); + try { + pythonEngine.eval("foo", scriptContext); + } catch (ScriptException e) { + assertEquals("sample.py", e.getFileName()); + return; + } + assertTrue("Expected a ScriptException", false); + } + + public void testCompileEvalString() throws ScriptException { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine pythonEngine = manager.getEngineByName("python"); + + CompiledScript five = ((Compilable)pythonEngine).compile("5"); + assertEquals(Integer.valueOf(5), five.eval()); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |