Tuesday Feb 12, 2013

ClojureScript REPL - If you build it, they will come!

Together with Attila Szegedi, also from the Java language team, I attended the very successful JFokus conference in Stockholm last week. I gave a talk about Nashorn and on implementing dynamic languages on the JVM in general. It seemed well received by the audience.

We also bumped into Bodil Stokke, of Catnip fame, there. Normally, as a Clojure open source developer, you just don't walk into the Oracle office, but we invited her over anyway and told the infrastructure orcs to stay under their desks. After depositing the ring she brought with her inside the big red volcano, we discussed Nashorn and other things for a bit.

A couple of days later, Bodil has made available an awesome ClojureScript REPL for Nashorn. Standard Clojure doesn't rely on invokedynamic for its implementation, but now can we can play with a ClojureScript that does. Neat.

 The javax.scripting API indeed enables some pretty powerful stuff.

Friday Feb 08, 2013

CSI: Nashorn - Shell Scripting in JavaScript, WAT?

I was reading the article in The Register with the heading GNOME project picks JavaScript as sole app dev language, when I remembered that we haven't said much about shell scripting using Nashorn.

This may seem sacrilegious to both JavaScripters and shell scripters, but think about it. The features that make JavaScript good for browser support are similar to what is needed for shell scripting. Plus you have access to all those Java libraries, and JavaFX, wink, wink, nudge, nudge (think visualization.)

There is an option (-scripting) in the Nashorn engine that extends the JavaScript language with features that make JavaScript very useful for writing shell scripts (even shebang scripts.) These features include;
  • function $EXEC("command args", "input"); that executes a command string as a separate process with handling of stdin, stdout $OUT, stderr $ERR and exit code $EXIT,
  • an exec string `command args` syntax for simple execution,
  • edit strings for embedding expressions in a double quote or exec strings, single quote strings are always unedited,
  • here strings, with editing for multi-line strings, <<TAG…TAG for include end of line and <<<TAG…TAG for exclude end of line,
  • environment variable $ENV for access to shell variables,
  • access to command line arguments with $ARG,
  • exit(code) and quit() for terminating the script,
  • and, # style comments
I will submit more scripting examples in the future, but let's start off with the following teaser.

Fingerprinting Source Code 

Often enough, when we are working on Nashorn, we run across some source that is unfamiliar and we would like to discuss the code with the original author. This is sometimes called blaming, but really, it's just about getting up to speed on the code without a lot of pain and suffering.  Nashorn is stored in a Mercurial repository on openjdk.java.net. Mercurial already supports basic change set annotation of source, but sometimes you just want to cut to the chase and get the full details of a specific source line.

The following shell script, suspect, takes a root source file name and a line number, and then displays the change set information associated with the source line.

# This script hunts down the change set associated with a
# source file and a line number.

// Report proper command usage.
function usage() {
usage: suspect javaFileName lineNumber
    javaFileName - name of file in local mercurial repository
    lineNumber   - file line number

// Report on stderr.
function error(message) {

// Provide meaningful names for arguments.
var fileName   = $ARG[0];
var lineNumber = $ARG[1];

// If arguments are missing, report proper usage.
if (!fileName || !lineNumber) {

// Add .java if not present.
if (!fileName.endsWith(".java")) {
    fileName += ".java";

// Search for matching files and convert the result to an array of paths.
var where = `find . -name ${fileName}`.trim().split("\n");

// If not found
if (where == "") {
    error("File ${fileName} is not in the current repository.\n");
} else if (where.length != 1) {
    error("File ${fileName} found in multiple locations\n${where.join('\n')}\n");

// Get the source annotated with change set number.
var annotated = `hg annotate -c ${where}`.split("\n");

// Get the target source line.
var line = annotated[lineNumber];

// Make sure the line exists.
if (!line) {
    error("File ${fileName} does not contain line number ${lineNumber}\n");

// Extract the revision number.
var revision = line.substring(0, 12);

// Report the change set information from the revision number.
print(`hg log -r ${revision}`);

If I wanted to find out about the changed set for line 63 of SpillProperty.java,

>> suspect SpillProperty 63
changeset:   2:da1e581c933b
user:        jlaskey
date:        Fri Dec 21 16:36:24 2012 -0400
summary:     8005403: Open-source Nashorn

This is just the beginning.


Technical discussions and status of the Nashorn JavaScript Project.


« February 2013 »