[Nashorn] "${expr}"で様々な計算式を文字列に埋め込む

投稿日: 2015/12/13 14:00:53

jjsに-scriptingオプションを指定すると、文字列の中に${expr}という形式でexprの部分に変数名や計算式を埋め込むことができます。コンストラクタや代入を埋め込むこともできます。

${expr}はexprの部分をそのままeval()に渡しているのかと思ったのですが、バイトコードを見た限りではeval()は使用されておらず、例えば"A${x+9}Z"は("A"+(x+9)+"Z")に相当する処理に変換されるようです。

1-1. 実行するスクリプト(stringInterpolation.js)

var s = "A";
var n = 10;
print("s+1=${s+1}, n+1=${n+2}, s.aaa=${s.aaa}, [3,4]=[${[3,4]}]");
print("new java.awt.Point(5,6)=${new java.awt.Point(5,6)}");
print("(function(x)x*7)(8)=${(function(x)x*7)(8)}");
var t = null;
print("(t=s)=${t=s}=(t)=${s}");

1-2. jjsで実行する

>jjs -scripting -fullversion stringInterpolation.js
nashorn full version 1.8.0_66-b18
s+1=A1, n+1=12, s.aaa=undefined, [3,4]=[3,4]
new java.awt.Point(5,6)=java.awt.Point[x=5,y=6]
(function(x)x*7)(8)=56
(t=s)=A=(t)=A

2-1. バイトコードを確認するためのスクリプト(stringInterpolationByteCode.js)

var x = "s";
print("A${x+9}Z");

2-2. jjsに-pc(--print-code)オプションを付けてバイトコードを確認する(抜粋)

>jjs -scripting -fullversion -co=true -pc stringInterpolationByteCode.js
nashorn full version 1.8.0_66-b18
class: jdk/nashorn/internal/scripts/JO1P0
// class version 51.0 (51)
// access flags 0x21
...
L3 [bci=29]
<line 2>
  29    aload 2
  30    invokedynamic dyn:getMethod|getProp|getElem:print(Object;)Object;      [static 'bootstrap' fastscope]
  35    getstatic ScriptRuntime.UNDEFINED : Undefined;
  38    ldc "A"
  40    aload 2
  41    invokedynamic dyn:getProp|getElem|getMethod:x(Object;)Object;          [static 'bootstrap' fastscope]
  46    bipush 9
  48    invokestatic Integer.valueOf(I)Integer;
  51    invokestatic ScriptRuntime.ADD(Object;Object;)Object;
  54    invokestatic ScriptRuntime.ADD(Object;Object;)Object;
  57    ldc "Z"
  59    invokestatic ScriptRuntime.ADD(Object;Object;)Object;
  62    invokedynamic dyn:call(Object;Undefined;Object;)Object;                [static 'bootstrap' fastscope]