プログラマメモ2 - programmer no memo2

jsr-223 - 追記中 2017/01/09
2021/03/14

jsr-223です。


javaからJVM言語をスクリプト実行したいです。
主観ですが、メジャーな言語と思えるものを調べてみました。
かなりおおざっぱです。

対象
 clojure,groovy,scala,jruby,jython,kotlin, javascript


言語 engine name(shortName) Factoryクラス JAR 特記
Clojure Clojure clojure.contrib.jsr223.ClojureScriptEngineFactory clojure-jsr223-1.2.jar  
Groovy Groovy org.codehaus.groovy.jsr223.GroovyScriptEngineFactory groovy-jsr223-2.4.7.jar  
Scala scala scala.tools.nsc.interpreter.IMain$Factory scala-compiler-2.11.8.jar -Dscala.usejavacp=true
Kotlin kotlin org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory kotlin-jsr223-local-example-1.1-M04-eap-14.jar  
JRuby jruby org.jruby.embed.jsr223.JRubyEngineFactory jruby-complete-9.1.6.0.jar -Dpython.import.site=FALSE
Jython jython org.python.jsr223.PyScriptEngineFactory jython-2.7.0.jar  
javascript javascript com.sun.script.javascript.RhinoScriptEngineFactory#java7 resources.jar java8はNashorn


jsr-223って、もともとサーバーサイドで各種スクリプト言語の実行を目指したもののようですね。

こうやってみてみるとJVM言語っていろいろありますね。かなり貪欲というか。

呼び出し方は、ScriptEngineManagerにたいして、エンジン名を指定して、ScriptEngineを取得します。取得できない場合は、nullが返ってくるようです。

ちなみに、各ScriptEngineFactoryはプログラムの起動時に行われるようです。ScriptEngineFactoryの定義は、各ライブラリ(jar)のMETA-INF/services/javax.script.ScriptEngineFactory ファイルに記述されています。
ですので、このファイルを探せばよいというのがわかります。ただし、このファイルに記述されているのに実際のクラスがない場合、不幸なことにプログラム全体が起動しません。
# 遅延ロードでできないのかしら?

参考 clojure


以下、呼び出しソース

package jsr223; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class TestMain { public static void main(String[] args) throws ScriptException { a(); } static void a() throws ScriptException { // まとめて実行するとjava.lang.OutOfMemoryErrorする.... jsr223_noengine(); jsr223_Clojure(); jsr223_Groovy(); jsr223_Scala(); jsr223_JRuby(); jsr223_Jython(); jsr223_Javascript(); jsr223_Kotlin(); } static void jsr223_noengine() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "xxxx";// 存在しないものを指定 final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); if (scriptEngine == null) { System.out.println("*** 存在しないものを指定した場合は、script engineはnullになります。"); } else { scriptEngine.eval(""); } } static void jsr223_Clojure() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "Clojure"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("(println \"clojure \")"); } static void jsr223_Groovy() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "Groovy"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println \"groovy \""); } static void jsr223_Scala() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "scala"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println(\"scala \")"); } static void jsr223_JRuby() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "jruby"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("printf \"jruby \n\""); } static void jsr223_Jython() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "jython"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("print 'jython'"); } static void jsr223_Javascript() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "javascript"; // java7 Rhino java8 Nashorn final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("print('javascript')"); } static void jsr223_Kotlin() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "kotlin"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println(\"Kotlin\")"); } }


 参考

uberjarでjava sourceをコンパイルして含める 2015/11/07

uberjarでjava sourceをコンパイルして含めるです。

悩みました。

参考
Leiningen で Clojure と Java の混在プロジェクト - tnoda-clojure

project.cljに

:java-source-paths ["src"]
を含めるでした。


herokuでclojureのメモ1 2014/10/19

herokuでclojureのメモ
いいチュートリアルがあるので、あまり困らないなと。
 あと、eclipse + Counterclockwise の組み合わせで開発試してしているので、
cloneしてきたclojure-getting-startedをどう、
eclipseのプロジェクトに取り込むのだろうと思ったけど、とても簡単で、フォルダをドラッグアンドドロップするととりこめた。
 
 
 まあベースがあると実験しやすいなと
 
で、ローカルでサーバー起動させるやりかただけど、ベストな解はわかってないのだけど、
 
 
REPLを起動して、命令すると動きだした。
 
 
 

javaから実行その7コンパイルして、invokeしてeval実行 - Clojure 2014/02/08

clojureです。
そろそろ行き詰まってきた感があります。

evalを試してみました。
まずevalを内部で実行する関数を用意して、それにlistを渡してあげるというイメージです。

参考


実行結果

#'clojure.core/m
class clojure.lang.Var
hello



package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.PersistentList; import clojure.lang.Var; public class ExtClojure07 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); {// // evalする関数を定義 String str = "(defn m[s](eval s))"; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); // listを生成 Object o2 = Compiler.load(new StringReader( "(list (symbol (str \"print\" \"ln\")) \"hello\")")); Var v = (Var) o; v.invoke(o2); } } }

javaから実行その6コンパイル エラー - Clojure 2014/02/08

clojureです。
どう使っていこうかというアイデアを練っている最中です。

ロード時にエラーです。

適当なコードをloadすると

Exception in thread "main" java.lang.RuntimeException: EOF while reading, starting at line 1, compiling:(null:1:1) at clojure.lang.Compiler.load(Compiler.java:7071) at clojure.lang.Compiler.load(Compiler.java:7029) at jp.deiji.ext.ExtClojure06.a(ExtClojure06.java:18) at jp.deiji.ext.ExtClojure06.main(ExtClojure06.java:11) Caused by: java.lang.RuntimeException: EOF while reading, starting at line 1 at clojure.lang.Util.runtimeException(Util.java:219) at clojure.lang.LispReader.readDelimitedList(LispReader.java:1139) at clojure.lang.LispReader$ListReader.invoke(LispReader.java:982) at clojure.lang.LispReader.read(LispReader.java:185) at clojure.lang.Compiler.load(Compiler.java:7059) ... 3 more

package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.Var; public class ExtClojure06 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); {// エラー String str = "(defppppp"; Object o = Compiler.load(new StringReader(str)); } } }

javaから実行その5コンパイルして、invokeする - Clojure 2014/02/02

clojureです。
javaから実行その5コンパイルして、invokeするです。
ふたつdefnで関数が定義されている場合、varのinvokeを呼ぶと最後に定義されたものが呼ばれるようにみえます。
ふたつdefnで関数定義されていてひつと前に定義されていたものを呼ぶことができました。

package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.Var; public class ExtClojure05 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); {// 二つdefnで定義されていた場合どちらを呼ぶか実験 String str = "(defn p1[](println \"その1\" )) (defn p2[](println \"その2\")) "; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; v.invoke(); } {// 二つdefnで定義されており、呼ばれた関数から定義済みのものを呼び出す String str = "(defn p1[](println \"その1\" )) (defn p2[](p1)) "; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; v.invoke(); } } }

結果
#'clojure.core/p2
class clojure.lang.Var
その2
#'clojure.core/p2
class clojure.lang.Var
その1


javaから実行その4 コンパイルして、invokeから引数を渡して、その引数(オブジェクト)のメソッドを呼ぶ - Clojure 2014/01/26

少しずつみえてきました。
Clojureです。

javaから実行その4 コンパイルして、invokeから引数を渡して、その引数(オブジェクト)のメソッドを呼ぶです。

package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.Var; public class ExtClojure04 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); {// (1) 引数でわたされたオブジェクトのメソッドを呼ぶ String str = "(defn p[o](println (. o toString)))"; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; v.invoke("ok"); } {// (2) 引数でわたされたオブジェクトのメソッドに引数を渡す String str = "(defn append[o](. o append \"ok\"))"; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; StringBuilder builder = new StringBuilder(); v.invoke(builder); System.out.println(builder); } } }


結果

#'clojure.core/p
class clojure.lang.Var
ok
#'clojure.core/append
class clojure.lang.Var
ok

javaから実行その3 コンパイルして、invokeから引数を渡す - Clojure 2014/01/26

clojureです。
javaから文字列を渡してコンパイルして、できあがったオブジェクトを実行してみます。
その際に、ivokeするときに引数を渡して実行します。

package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.Var; public class ExtClojure03 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); String str = " (defn hello [name] (println (str \"hello \" name)))"; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; v.invoke("ugo"); } }


実行結果

#'clojure.core/hello
class clojure.lang.Var
hello ugo

javaから実行その2 - Clojure 2014/01/25

clojureです。
javaから文字列を渡してコンパイルして、できあがったオブジェクトを実行してみます。

コンパイルするコストが小さければ、実行させたいときにコンパイルして実行したいなと。


package jp.deiji.ext; import java.io.StringReader; import clojure.lang.Compiler; import clojure.lang.Var; public class ExtClojure02 { public static void main(String[] args) { a(); } static void a() { new clojure.lang.RT(); String str = "(def hello (fn [] (println \"Hello world\")))"; Object o = Compiler.load(new StringReader(str)); System.out.println(o); System.out.println(o.getClass()); Var v = (Var) o; v.call(); v.invoke(); } }


実行結果です。

#'clojure.core/hello
class clojure.lang.Var
Hello world
Hello world
 

javaから実行その1 - Clojure 2014/01/19

ここんとこ、いろいろ自分の中で新しいもののにとりくんでたりしてます。
いつかは、LISPやってみたいなーと思ってたのですが、そのとっかかりとしてClojure。

javaで動作する言語は、とりかかりやすいかなと思えます。

そういうわけで、はじめの一歩として、java上からまずは実行。ファイルを読み込ませてではなく、直接、プログラムを文字列として渡して実行です。
バージョンは、1.5.1です。


package jp.deiji.ext; import java.io.StringReader; public class ExtClojure01 { public static void main(String[] args) { a(); } static void a() { // この一行ないと java.lang.ExceptionInInitializerErrorがでる new clojure.lang.RT(); String str = "(print \"Hello World \")(flush)"; clojure.lang.Compiler.load(new StringReader(str)); System.out.println(); } }


はじめは、
clojure.lang.Compiler.load(new StringReader(str));を呼ぶだけで実行できるかなと試してたのですが、実行時例外がでてしまって、調べたら、new clojure.lang.RT();をやっとけみたいなのがあったのでとりあえず。



表現力がそんなに高いのでしょうかClojureは

普通のやつらの上をいけるのでしょうか。