some nashorn testing/ jrunscript patch
Andreas Rieber
rieberandreas at gmail.com
Thu Jan 10 11:45:21 PST 2013
Hi Jim,
please find attached the jrunscript patch(es). The small Nashorn patch
took me a while to find out... The jdk8 patch is hg export -g like
expected on openjdk.java.net contributing page. I also updated the jtreg
test.
The patch for jdk8 has a new file for the formatting. Tricky part for
printf/sprintf was to do the type conversion of the javascript types.
The init.js file will now work with Nashorn and Rhino.
nashorn> printf("%5d %f %s %B %c %<d %n", 1, 2, "3", true, "a");
1 2.000000 3 TRUE a 97
nashorn> printf("java.util.Date(): %1$tm %1$te, %1$tY%n", new
java.util.Date());
java.util.Date(): 01 10, 2013
nashorn> printf("javascript Date(): %1$tm %1$te, %1$tY%n", new Date());
javascript Date(): 01 10, 2013
nashorn> printf("%c %c %c %d %d%n", 'a', "b", 65, -1, "Hello");
a b A -1 72
nashorn>
The jdk8 patch works also for jdk7u as that's where i started.
I will see if i get scriptpad sample also working.
- Andreas
On 08.01.13 19:12, Jim Laskey (Oracle) wrote:
> On 2013-01-08, at 1:22 PM, Andreas Rieber <rieberandreas at gmail.com> wrote:
>
>> Hi,
>>
>> i tested Nashorn with a project i am currently working on (scripting
>> java). The first thing i spotted is that Rhino comes with print() and
>> println() as default functions in:
>>
>> jdk8/jdk/src/share/classes/com/sun/script/javascript/RhinoScriptEngine.java
>>
>> while Nashorn has only a print():
>>
>> jdk8/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
>> jdk8/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js
>>
>> Will this be changed or is that a migration issue?
> We opted for print because we were primarily using V8 performance tests and v8 only supports print. Standalone rhino does not support println either. We did have a switch for turning on println, but it fell out of favour to be consistent with other VMs.
>
> You can duplicate the behaviour with;
>
> function print(s) { java.lang.System.out.print("" + s); }
> function println(s) { java.lang.System.out.println("" + s); }
>
>
>> importClass works only with: load("nashorn:mozilla_compat.js");
>> What is with importPackage (also used in jrunscript)?
>>
> importClass is being phased out since it duplicates the builtin behaviour of Packages and JavaClass.
>
> importPackage(java.awt);
> importClass(java.awt.Frame);
>
> is just
>
> var awt = java.awt;
> var Frame = java.awt.Frame;
>
>
>> Next problem i had was related to java array creation. Here the sample
>> from JSE 7 Documentation "Java Scripting Programmer's Guide":
>>
>> // create Java String array of 5 elements
>> var a = java.lang.reflect.Array.newInstance(java.lang.String, 5);
>>
>> // Accessing elements and length access is by usual Java syntax
>> a[0] = "scripting is great!";
>> print(a.length);
>>
>> It works with Rhino but fails with Nashorn:
>>
>> Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodException: None of the fixed arity signatures [(java.lang.Class, int[]), (java.lang.Class, int)] or the variable arity signatures [(java.lang.Class, int...)] of the method java.lang.reflect.Array.newInstance match the argument types [org.dynalang.dynalink.beans.StaticClass, java.lang.Integer]
>>
>> The default number type for Rhino in vararg functions is double while
>> Nashorn has also integer (nice), might be a migration issue.
>
> We are pushing the Java syntax here to eliminate confusion between the java class and the JavaClass javascript object. This eliminates the confusion when accessing members of the (String) class when a javascript object and members of the class itself when a java object.
>
> jjs> java.lang.String
> [JavaClass java.lang.String]
> jjs> java.lang.String.class
> class java.lang.String
>
> so
>
> var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5);
>
>> Is jrunscript and the scriptpad sample application
>> (jdk8/jdk/src/share/sample/scripting/scriptpad) now also developed
>> under Nashorn project? I would like to contribute a patch for
>> jrunscript (printf never worked and i added also a sprintf), the
>> scriptpad needed only a few fixes to work with Rhino. I signed the OCA
>> recently.
> Contributions welcome.
>
> I just see Attila answered differently, but both forms work.
>
>
>> best regards
>> Andreas
>>
-------------- next part --------------
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -485,12 +485,6 @@
try {
final Object val = ctxt.getAttribute(ScriptEngine.FILENAME);
final String fileName = (val != null) ? val.toString() : "<eval>";
-
- // !!HACK!! do not evaluate "init.js" from jrunscript tool!!
- if ("<system-init>".equals(fileName)) {
- return null;
- }
-
final Source source = new Source(fileName, buf);
if (globalChanged) {
setNashornGlobal(global);
-------------- next part --------------
# HG changeset patch
# User arieber
# Date 1357845438 -3600
# Node ID 99350545e3f5ecb0fe11fb9cce86f36664a375e9
# Parent 32a57e645e012a1f0665c075969ca598e0dbb948
fixed jrunscript for Nashorn+Rhino, added sprintf and got printf working.
diff --git a/src/share/classes/com/sun/tools/script/shell/Formatter.java b/src/share/classes/com/sun/tools/script/shell/Formatter.java
new file mode 100644
--- /dev/null
+++ b/src/share/classes/com/sun/tools/script/shell/Formatter.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.script.shell;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Formatter is a class to get the type conversion between javascript types and
+ * java types for the format (sprintf) method working.
+ *
+ * <p>In javascript the type for numbers can be different from the format type
+ * specifier. For format type '%d', '%o', '%x', '%X' double need to be
+ * converted to integer. For format type 'e', 'E', 'f', 'g', 'G', 'a', 'A'
+ * integer needs to be converted to double.
+ *
+ * <p>Format type "%c" and javascript string needs special handling.
+ *
+ * <p>The javascript date objects can be handled if they are type double (the
+ * related javascript code will convert with Date.getTime() to double). So
+ * double date types are converted to long.
+ *
+ * <p>Pattern and the logic for parameter position: java.util.Formatter
+ *
+ * @author Andreas Rieber
+ * @since 1.8
+ */
+public class Formatter {
+
+ /**
+ * Method which converts javascript types to java types for the
+ * String.format method (jrunscript function sprintf).
+ *
+ * @param format a format string
+ * @param args arguments referenced by the format specifiers in format
+ * @return a formatted string
+ */
+ public static String format(String format, Object[] args) {
+ Matcher m = fsPattern.matcher(format);
+ int positionalParameter = 1;
+
+ while (m.find()) {
+ int index = index(m.group(1));
+ boolean previous = isPreviousArgument(m.group(2));
+ char conversion = m.group(6).charAt(0);
+
+ // skip over some formats
+ if (index < 0 || previous
+ || conversion == 'n' || conversion == '%') {
+ continue;
+ }
+
+ // index 0 here means take a positional parameter
+ if (index == 0) {
+ index = positionalParameter++;
+ }
+
+ // out of index, String.format will handle
+ if (index > args.length) {
+ continue;
+ }
+
+ // current argument
+ Object arg = args[index - 1];
+
+ // for date we convert double to long
+ if (m.group(5) != null) {
+ // convert double to long
+ if (arg instanceof Double) {
+ args[index - 1] = ((Double) arg).longValue();
+ }
+ } else {
+ // we have to convert some types
+ switch (conversion) {
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (arg instanceof Double) {
+ // convert double to long
+ args[index - 1] = ((Double) arg).longValue();
+ } else if (arg instanceof String
+ && ((String) arg).length() > 0) {
+ // convert string (first character) to int
+ args[index - 1] = (int) ((String) arg).charAt(0);
+ }
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ if (arg instanceof Integer) {
+ // convert integer to double
+ args[index - 1] = ((Integer) arg).doubleValue();
+ }
+ break;
+ case 'c':
+ if (arg instanceof Double) {
+ // convert double to integer
+ args[index - 1] = ((Double) arg).intValue();
+ } else if (arg instanceof String
+ && ((String) arg).length() > 0) {
+ // get the first character from string
+ args[index - 1] = (int) ((String) arg).charAt(0);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return String.format(format, args);
+ }
+
+ /**
+ * Method to parse the integer of the argument index.
+ *
+ * @param s
+ * @return -1 if parsing failed, 0 if string is null, > 0 integer
+ */
+ private static int index(String s) {
+ int index = -1;
+
+ if (s != null) {
+ try {
+ index = Integer.parseInt(s.substring(0, s.length() - 1));
+ } catch (NumberFormatException e) { }
+ } else {
+ index = 0;
+ }
+
+ return index;
+ }
+
+ /**
+ * Method to check if a string contains '<'. This is used to find out if
+ * previous parameter is used.
+ *
+ * @param s
+ * @return true if '<' is in the string, else false
+ */
+ private static boolean isPreviousArgument(String s) {
+ return (s != null && s.indexOf('<') >= 0) ? true : false;
+ }
+
+ // %[argument_index$][flags][width][.precision][t]conversion
+ private static final String formatSpecifier =
+ "%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";
+ // compiled format string
+ private static Pattern fsPattern;
+
+ static {
+ fsPattern = Pattern.compile(formatSpecifier);
+ }
+}
diff --git a/src/share/classes/com/sun/tools/script/shell/init.js b/src/share/classes/com/sun/tools/script/shell/init.js
--- a/src/share/classes/com/sun/tools/script/shell/init.js
+++ b/src/share/classes/com/sun/tools/script/shell/init.js
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,7 @@
__get__ : function(name) {
return function() {
return obj.invoke(name, arguments);
- }
+ };
}
});
}
@@ -200,8 +200,18 @@
var inp = java.lang.System["in"];
// useful imports for often used io, net classes
-importPackage(java.io);
-importPackage(java.net);
+var BufferedInputStream = java.io.BufferedInputStream;
+var BufferedOutputStream = java.io.BufferedOutputStream;
+var BufferedReader = java.io.BufferedReader;
+var DataInputStream = java.io.DataInputStream;
+var File = java.io.File;
+var FileInputStream = java.io.FileInputStream;
+var FileOutputStream = java.io.FileOutputStream;
+var InputStream = java.io.InputStream;
+var InputStreamReader = java.io.InputStreamReader;
+var OutputStream = java.io.OutputStream;
+var Reader = java.io.Reader;
+var URL = java.net.URL;
/**
* Generic any object to input stream mapper
@@ -302,18 +312,20 @@
*
* @param str input from which script is loaded and evaluated
*/
-function load(str) {
- var stream = inStream(str);
- var bstream = new BufferedInputStream(stream);
- var reader = new BufferedReader(new InputStreamReader(bstream));
- var oldFilename = engine.get(engine.FILENAME);
- engine.put(engine.FILENAME, str);
- try {
- engine.eval(reader);
- } finally {
- engine.put(engine.FILENAME, oldFilename);
+if (load === undefined) {
+ var load = function load(str) {
+ var stream = inStream(str);
+ var bstream = new BufferedInputStream(stream);
+ var reader = new BufferedReader(new InputStreamReader(bstream));
+ var oldFilename = engine.get(engine.FILENAME);
+ engine.put(engine.FILENAME, str);
+ try {
+ engine.eval(reader);
+ } finally {
+ engine.put(engine.FILENAME, oldFilename);
streamClose(stream);
- }
+ }
+ };
}
// file system utilities
@@ -458,7 +470,7 @@
* @param dir name of the new directory
*/
function mkdir(dir) {
- var dir = pathToFile(dir);
+ dir = pathToFile(dir);
println(dir.mkdir()? "created" : "can not create dir");
}
@@ -469,7 +481,7 @@
* @param dir input path name
*/
function mkdirs(dir) {
- var dir = pathToFile(dir);
+ dir = pathToFile(dir);
println(dir.mkdirs()? "created" : "can not create dirs");
}
@@ -479,7 +491,7 @@
* @param pathname name of the file
*/
function rm(pathname) {
- file = pathToFile(pathname);
+ var file = pathToFile(pathname);
if (!file.exists()) {
println("file not found: " + pathname);
return false;
@@ -586,7 +598,7 @@
for (var i in files) {
var f = files[i];
if (filter) {
- if(!f.getName().match(filter)) {
+ if (!f.getName().match(filter)) {
continue;
}
}
@@ -776,7 +788,7 @@
}
var factory = javax.xml.transform.TransformerFactory.newInstance();
- var tranformer;
+ var transformer;
if (style) {
transformer = factory.newTransformer(XMLSource(style));
} else {
@@ -840,18 +852,42 @@
}
/**
- * This is C-like printf
+ * This is C-like printf
*
* @param format string to format the rest of the print items
* @param args variadic argument list
*/
-function printf(format, args/*, more args*/) {
- var array = java.lang.reflect.Array.newInstance(java.lang.Object,
- arguments.length - 1);
- for (var i = 0; i < array.length; i++) {
- array[i] = arguments[i+1];
+function printf(format, args/*, more args*/) {
+ print(sprintf.apply(this, arguments));
+}
+
+/**
+ * This is C-like sprintf
+ *
+ * @param format string to format the rest of the print items
+ * @param args variadic argument list
+ */
+function sprintf(format, args/*, more args*/) {
+ var len = arguments.length - 1;
+ var array = [];
+
+ if (len < 0) {
+ return "";
}
- return java.lang.System.out.printf(format, array);
+
+ for (var i = 0; i < len; i++) {
+ if (arguments[i+1] instanceof Date) {
+ array[i] = arguments[i+1].getTime();
+ } else {
+ array[i] = arguments[i+1];
+ }
+ }
+
+ if( typeof Java !== "undefined") {
+ array = Java.toJavaArray(array);
+ }
+
+ return Packages.com.sun.tools.script.shell.Formatter.format(format, array);
}
/**
@@ -882,3 +918,23 @@
return reader.readLine();
}
}
+
+// Nashorn has only print, so we define it here
+if (println === undefined) {
+ var print = function print(str, newline) {
+ if (typeof(str) == 'undefined') {
+ str = 'undefined';
+ } else if (str == null) {
+ str = 'null';
+ }
+ if (!(out instanceof java.io.PrintWriter))
+ out = new java.io.PrintWriter(out);
+ out.print(String(str));
+ if (newline) out.print('\n');
+ out.flush();
+ };
+
+ var println = function println(str) {
+ print(str, true);
+ };
+}
diff --git a/test/sun/tools/jrunscript/jrunscriptTest.sh b/test/sun/tools/jrunscript/jrunscriptTest.sh
--- a/test/sun/tools/jrunscript/jrunscriptTest.sh
+++ b/test/sun/tools/jrunscript/jrunscriptTest.sh
@@ -46,6 +46,7 @@
v = v + " is the value";
if (v != 0) { println('yes v != 0'); }
java.lang.System.out.println('hello world from script');
+printf("%3d\n",1);
new java.lang.Runnable() { run: function() { println('I am runnable'); }}.run();
EOF
@@ -64,6 +65,7 @@
v = v + " is the value";
if (v != 0) { println('yes v != 0'); }
java.lang.System.out.println('hello world from script');
+printf("%3d\n",1);
new java.lang.Runnable() { run: function() { println('I am runnable'); }}.run();
EOF
diff --git a/test/sun/tools/jrunscript/repl.out b/test/sun/tools/jrunscript/repl.out
--- a/test/sun/tools/jrunscript/repl.out
+++ b/test/sun/tools/jrunscript/repl.out
@@ -3,5 +3,6 @@
js> 35 is the value
js> yes v != 0
js> hello world from script
+js> 1
js> I am runnable
js>
\ No newline at end of file
More information about the nashorn-dev
mailing list