Nashorn's javax.script.ScriptEngineFactory produces wrong code
Edmond Kemokai
ekemokai at gmail.com
Fri Jan 6 15:07:20 UTC 2017
Hi Rony,
I am the developer of HiveMind, it is a web app platform that relies
entirely on scripting engines via JSR-223.
You can access a demo instance: http://demo.crudzilla.com:7000/
Login with: developer/developer
I have created a test file in: /com/crudzilla/cloudTest/web/rony-groovy.ste
Put your code (the original one you pasted) in there and save, I'll take a
look to see what might be missing.
On Fri, Jan 6, 2017 at 9:07 AM, Rony G. Flatscher <Rony.Flatscher at wu.ac.at>
wrote:
> Besides Java 1.8.0_111 the problem exists in 9ea-+134 (engine version:
> "9ea", language version:
> "ECMA 262 - Edition 5.1" ) as well: Nashorn's javax.script factory is used
> to get an output
> statement and then it is used to execute it:
>
> ---> language [ECMAScript]: ---------------------------------------->
>
> 1) output statement to process: hello world, this is
> "ECMAScript" speaking!
>
> --> testing getOutputStatement(String), produced the following
> [ECMAScript] output statement
>
> print(hello world, this is "ECMAScript" speaking! )
>
> ... now running "eval(code)" using the scripting engine
> [ECMAScript]:
>
>
> javax.script.ScriptException: <eval>:1:12 Expected , but found world
> print(hello world, this is "ECMAScript" speaking! )
> ^ in <eval> at line number 1 at column number 12 while
> eval() the code: print(hello
> world, this is "ECMAScript" speaking! )
>
> This time trying to not format the Java code, so hopefully the mailer will
> not render it illegible:
>
> ... cut ...
>
> // create an output statement and execute output statement with the
> script engine
> static void testEngine(String name, ScriptEngineFactory sef,
> ScriptEngine se)
> {
> System.out.println("---> language ["+name+"]:
> ---------------------------------------->\n");
> String text="hello world, this is \""+name+"\" speaking! ";
> String code=sef.getOutputStatement(text);
> System.out.println("\t1) output statement to process:
> "+text+"\n");
>
> System.out.print("\t--> testing getOutputStatement(String)");
> System.out.println(", produced the following ["+name+"] output
> statement \n\n"+code+"\n");
> System.out.println("\t... now running \"eval(code)\" using the
> scripting engine
> ["+name+"]: \n\n");
> try
> {
> se.eval(code);
> System.out.println("\n");
> }
> catch (ScriptException sexc)
> {
> System.err.println(sexc+" while eval() the code:
> "+code+"\n");
> }
>
> System.out.print("\t2) testing getMethodCallSyntax(obj, meth,
> arg...)");
> String methCode=sef.getMethodCallSyntax("object", "method",
> "arg1", "arg2");
> System.out.println(", produced the following ["+name+"] method
> call statement:
> \n\n"+methCode+"\n");
>
> System.out.print("\t3) testing getProgram(String...)");
> String programCode=sef.getProgram(code, methCode);
> System.out.println(" produced the following ["+name+"]
> program: \n\n"+programCode+"\n");
>
> System.out.println("<--- end of testing language ["+name+"].
> <----------------------------------------\n");
> }
>
> ... cut ...
>
> If I should file a bug then please advise where and how.
>
> ---rony
>
>
> On 08.12.2016 16:17, Rony G. Flatscher wrote:
> > Unfortunately, the mailing list seems to behave as if it was running in
> the 1970's such that the
> > formatted text (indented, partially colorized and formatted to preformat
> and Courier) has turned to
> > become illegible, unfortunately (using the Thunderbird e-Mail client)!
> > :(
> >
> > The meat is right in the first two paragraphs and the last paragraph
> before the signature. Should
> > anyone be interested in the Java-utility, please drop me a personal
> e-mail and I will send that Java
> > program as an attachment to you.
> >
> > ---rony
> >
> >
> >
> > On 08.12.2016 16:05, Rony G. Flatscher wrote:
> >> Hi there, was directed to this list to report an error with Nashorn's
> implementation of
> >> javax.script.ScriptEngineFactory.getOutputStatement(String toDisplay).
> >>
> >> The test is simple: one supplies a string, containing double quotes,
> and immediately use the Nashort
> >> script engine to carry out the output statement produced by its
> factory, yielding a runtime error.
> >> In order for you to reproduce, I list the Java utility (it lists all
> available javax.script engines
> >> and tests them with the -t switch and is a little example of how one
> can take advantage of
> >> javax.script very easily) after my signature below to study the code
> and run it to double-check:
> >>
> >> F:\work\svn\bsf4oorexx\trunk\samples\Java\jsr223>java RunScript -t
> ---> language [ECMAScript]:
> >> ----------------------------------------> 1) output statement to
> process: hello world, this is
> >> "ECMAScript" speaking! --> testing getOutputStatement(String),
> produced the following
> >> [ECMAScript] output statement *print(hello world, this is
> "ECMAScript" speaking! )* ... now
> >> running "eval(code)" using the scripting engine [ECMAScript]:
> *javax.script.ScriptException:
> >> <eval>:1:12 Expected , but found world print(hello world, this is
> "ECMAScript" speaking! ) ^ in
> >> <eval> at line number 1 at column number 12 while eval() the code:
> print(hello world, this is
> >> "ECMAScript" speaking! )* 2) testing getMethodCallSyntax(obj, meth,
> arg...), produced the
> >> following [ECMAScript] method call statement:
> object.method(arg1,arg2) 3) testing
> >> getProgram(String...) produced the following [ECMAScript] program:
> print(hello world, this is
> >> "ECMAScript" speaking! );object.method(arg1,arg2); <--- end of
> testing language [ECMAScript].
> >> <---------------------------------------- ---> language [ooRexx]:
> >> ----------------------------------------> ... cut ...
> >>
> >> The specification for javax.script created by the Java specification
> request group 223 (a.k.a.
> >> JSR-223) can be consulted. BTW, "jrunscript[.exe]" (from the JDK) seems
> to be broken, it only is be
> >> able to execute the Nashorn script engine, despite switches that allow
> other script engines to be
> >> employed.
> >>
> >> ---rony
> >>
> >> Code of "RunScript.java" (little utility to list the currently
> available javax.script languages, run
> >> any javax.script program, give helpful information about each
> javax.script engine and test each one
> >> using its own factory means): just compile it and run it with "java
> RunScript -t":
> >>
> >> ------------------ cut here ------------------
> >> import java.io.File; import java.io.FileReader; import
> java.util.ArrayList; import java.util.Arrays;
> >> import java.util.List; import java.util.HashMap; import
> java.util.SortedSet; import
> >> java.util.TreeSet; import javax.script.Bindings; import
> javax.script.ScriptContext; import
> >> javax.script.ScriptEngine; import javax.script.ScriptEngineFactory;
> import
> >> javax.script.ScriptEngineManager; import javax.script.ScriptException;
> import
> >> javax.script.SimpleScriptContext; /* ------------------------ Apache
> Version 2.0 license
> >> ------------------------- Copyright 2015-2016 Rony G. Flatscher
> Licensed under the Apache License,
> >> Version 2.0 (the "License"); you may not use this file except in
> compliance with the License. You
> >> may obtain a copy of the License at http://www.apache.org/
> licenses/LICENSE-2.0 Unless required by
> >> applicable law or agreed to in writing, software distributed under the
> License is distributed on an
> >> "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
> express or implied. See the
> >> License for the specific language governing permissions and limitations
> under the License.
> >> -----------------------------------------------------------------------------
> changed: 2016-12-06,
> >> rgf: if no argument is given, show the help after the list of currently
> available javax.script
> >> engines */ /** A command line Java utility to query, test and evaluate
> {@link javax.script}
> >> scripting engines that * gets distributed via the beta BSF4ooRexx
> package from Sourceforge. * *
> >> <p>Usage: <code>java RunScript [{-i | -t | -e enginename filename
> [args...] | filename
> >> [args...]}]</code> * <br> * <ul> * <li> ... no arguments: lists the
> currently available
> >> <code>javax.script</code> engines * * <li> <code>-h</code> ... 'help',
> lists and briefly explains
> >> the command line options * * <li> <code>-i</code> ... lists the
> available <code>javax.script</code>
> >> engines and informs about their properties * * <li> <code>-t</code> ...
> lists the available
> >> <code>javax.script</code> engines and tests evaluating their factory's
> >> <code>"getOutputStatement(String)"</code> method * * <li>
> <code>-e enginename filename
> >> [args...]</code> ... uses <code>"enginename"</code> to
> evaluate
> >> <code>"filename"</code> supplying the arguments
> <code>"args..."</code> * * <li>
> >> <code>filename [args...]</code> ... the <code>"filename"</code>
> extension determines the
> >> script engine to evaluate it, supplying the arguments
> <code>"args..."</code> * </ul> * * *
> >> @author Rony G. Flatscher * @since 2015-05-20 */ public class RunScript
> { public static void
> >> main(String args[]) { ScriptEngineManager manager = new
> ScriptEngineManager();
> >> List<ScriptEngineFactory> factories = manager.getEngineFactories();
> >> HashMap<String,ScriptEngineFactory> n2sef=new HashMap<String,ScriptEngineFactory>
> ();
> >> HashMap<String,ScriptEngine> n2se =new HashMap<String,ScriptEngine> ();
> // create the Maps for
> >> (ScriptEngineFactory factory : factories) { String
> name=factory.getLanguageName(); // String
> >> name=factory.getEngineName(); n2sef.put(name, factory); n2se .put(name,
> factory.getScriptEngine());
> >> } // create a sorted set of key names SortedSet<String> keys = new
> TreeSet<String>(n2sef.keySet());
> >> int argsStartAt=-1; // arguments - if any - for filenmae to execute
> start at this position
> >> ScriptEngine scriptEngineToUse=null; String filename=null; if
> (args.length==0) // list all available
> >> javax.script engines { System.out.println("The following javax.script
> engines are currently
> >> available:\n"); for (String key : keys) { System.out.println('\t'+key);
> } System.out.println();
> >> showHelp(); return; } else // process the first argument to decide what
> we need to do { String
> >> firstWord=args[0]; // get first value if (firstWord.startsWith("-")==true)
> // a switch at hand! { if
> >> (firstWord.length()!=2) // oops an error, we need excactly two chars
> (-i, -t, -e) { throw new
> >> IllegalArgumentException("switch '-' must be followed by one of the
> letters 'i', 't', or 'e'"); }
> >> String uSwitch=firstWord.substring(1).toUpperCase(); // get switch in
> uppercase if
> >> (uSwitch.equals("I")) // list all engines, list all their standard
> properties { for (String key :
> >> keys) // list all engines in order{ { showEngineProperties(key,
> n2sef.get(key)); } return; } else if
> >> (uSwitch.equals("T")) // list all engines, test them { for (String key
> : keys) // list all engines
> >> in order{ { testEngine(key, n2sef.get(key), n2se.get(key)); } return; }
> else if
> >> (uSwitch.equals("H")) // -h ... help text { showHelp(); return; } else
> if (uSwitch.equals("E")) //
> >> -e engineName fileName [arg... ] { if (args.length<3) { throw new
> IllegalArgumentException("too few
> >> command line arguments ("+args.length+"), minimum needed is 3: \"-e
> enginename filename\""); } //
> >> check whether engine is available, if so, then load it
> filename=args[2]; // assign filename String
> >> errMsg="no \""+args[1]+"\" javax.script engine available"; try {
> >> scriptEngineToUse=manager.getEngineByName(args[1]); // fetch script
> engine } catch (Exception exc) {
> >> throw new IllegalArgumentException(errMsg); } if
> (scriptEngineToUse==null) { throw new
> >> IllegalArgumentException(errMsg); } argsStartAt=3; // fourth argument!
> } else // unknown switch {
> >> throw new IllegalArgumentException("unknown switch '"+firstWord+"',
> must be followed by one of '-h',
> >> '-i', '-t', or '-e'"); } } else // a filename in hand, check whether we
> have a suitable engine
> >> available { // - check whether suitable engine is available, if not
> raise an exception
> >> filename=args[0]; // assign filename int lastIdx=filename.lastIndexOf('.');
> if (lastIdx==0) { throw
> >> new IllegalArgumentException("filename \"filename\" does not have an
> extension, cannot determine
> >> scripting engine"); } String errMsg="cannot determine scripting engine
> from the filename extension
> >> in \""+filename+"\""; try { String extension=filename.substring(lastIdx+1);
> // get extension
> >> scriptEngineToUse=manager.getEngineByExtension(extension); // fetch
> script engine } catch (Exception
> >> exc) // if substring() causes an exception { throw new
> IllegalArgumentException(errMsg); } if
> >> (scriptEngineToUse==null) // no scripting engine found { throw new
> IllegalArgumentException(errMsg);
> >> } argsStartAt=1; // second argument! } } // now setup the remainder and
> eval() the "filename" with
> >> the script engine // - check whether file exists, if not raise an
> exception File f=null; try { f=new
> >> File (filename); } catch (Exception exc) { throw new
> IllegalArgumentException(exc); } if
> >> (f.exists()==false) { throw new IllegalArgumentException("filename
> \""+filename+"\" does not
> >> exist"); } // - supply filename ScriptContext sc=scriptEngineToUse.getContext();
> // get the default
> >> context sc.setAttribute(ScriptEngine.FILENAME, filename,
> ScriptContext.ENGINE_SCOPE); // - if
> >> arguments, setup ARGV in ENGINE_SCOPE if (args.length>argsStartAt) //
> do we have command line
> >> arguments to supply? { String argArr []=new String
> [args.length-argsStartAt]; // determine array
> >> size int k=0; for (int i=argsStartAt; i<args.length; i++, k++) {
> argArr[k]=args[i]; }
> >> sc.setAttribute(ScriptEngine.ARGV, argArr,
> ScriptContext.ENGINE_SCOPE); } // - eval the script try {
> >> scriptEngineToUse.eval(new FileReader(f)); } catch (Exception exc) {
> throw new
> >> IllegalArgumentException(exc); } } // show information about the script
> engine static void
> >> showEngineProperties(String name, ScriptEngineFactory sef) {
> System.out.println(name);
> >> System.out.print ("\tgetEngineName() : "); try { System.out.println(sef.getEngineName()
> ); } catch
> >> (Exception e) { System.out.println("--> FAILED!"); } System.out.print
> ("\tgetEngineVersion() : ");
> >> try { System.out.println(sef.getEngineVersion() ); } catch (Exception
> e) { System.out.println("-->
> >> FAILED!"); } System.out.print ("\tgetExtensions() : "); try {
> System.out.println(sef.getExtensions
> >> ()); } catch (Exception e) { System.out.println("--> FAILED!"); }
> System.out.print
> >> ("\tgetLanguageName() : "); try { System.out.println(sef.getLanguageName
> () ); } catch (Exception e)
> >> { System.out.println("--> FAILED!"); } System.out.print
> ("\tgetLanguageVersion() : "); try {
> >> System.out.println(sef.getLanguageVersion()); } catch (Exception e) {
> System.out.println("-->
> >> FAILED!"); } System.out.print ("\tgetMimeTypes() : "); try {
> System.out.println(sef.getMimeTypes
> >> ()); } catch (Exception e) { System.out.println("--> FAILED!"); }
> System.out.print ("\tgetNames() :
> >> "); try { System.out.println(sef.getNames() ); } catch (Exception e) {
> System.out.println("-->
> >> FAILED!"); } System.out.print ("\tgetParameter(\"THREADING\"): "); try
> {
> >> System.out.println(sef.getParameter("THREADING")); } catch (Exception
> e) { System.out.println("-->
> >> FAILED!"); } } // create an output statement and execute output
> statement for each available script
> >> engine static void testEngine(String name, ScriptEngineFactory sef,
> ScriptEngine se) {
> >> System.out.println("---> language ["+name+"]:
> ---------------------------------------->\n"); String
> >> text="hello world, this is \""+name+"\" speaking! "; String
> code=sef.getOutputStatement(text);
> >> System.out.println("\t1) output statement to process: "+text+"\n");
> System.out.print("\t--> testing
> >> getOutputStatement(String)"); System.out.println(", produced the
> following ["+name+"] output
> >> statement \n\n"+code+"\n"); System.out.println("\t... now running
> \"eval(code)\" using the scripting
> >> engine ["+name+"]: \n\n"); try { se.eval(code);
> System.out.println("\n"); } catch (ScriptException
> >> sexc) { System.err.println(sexc+" while eval() the code: "+code+"\n");
> } System.out.print("\t2)
> >> testing getMethodCallSyntax(obj, meth, arg...)"); String methCode=sef.
> getMethodCallSyntax("object",
> >> "method", "arg1", "arg2"); System.out.println(", produced the following
> ["+name+"] method call
> >> statement: \n\n"+methCode+"\n"); System.out.print("\t3) testing
> getProgram(String...)"); String
> >> programCode=sef.getProgram(code, methCode); System.out.println("
> produced the following ["+name+"]
> >> program: \n\n"+programCode+"\n"); System.out.println("<--- end of
> testing language ["+name+"].
> >> <----------------------------------------\n"); } // allow us to call
> this from different parts
> >> static void showHelp() { System.out.println("usage: java RunScript [{-i
> | -t | -e enginename
> >> filename [args...] | filename [args...]}]\n"); System.out.println(" ...
> no arguments lists the
> >> available javax.script engines"); System.out.println(" -h ... 'help',
> gives this usage text");
> >> System.out.println(" -i ... lists the available javax.script engines
> and informs about their
> >> properties"); System.out.println(" -t ... lists the available
> javax.script engines and tests
> >> evaluating their \"getOutputStatement(String)\" method");
> System.out.println(" -e enginename
> >> filename [args...] ... uses \"enginename\" to evaluate \"filename\"
> supplying the arguments
> >> \"args...\""); System.out.println(" filename [args...] ... the
> \"filename\" extension determines the
> >> script engine to evaluate it, supplying the arguments \"args...\"");
> return; } } ------------------
> >> cut here ------------------
> >>
> >>
>
>
More information about the nashorn-dev
mailing list