PythonJS development has moved to Rusthon https://github.com/rusthon/Rusthon
とありましたので、きっとRusthonもPythonJSみたいに使えるんだろう。 と思い、早速ドキュメントを読んでみました。
仕方ないので実行pythonスクリプトをバッチ的に使います。
Tagの0.9.8からrusthonが現れ、それ以前はPythonJSです。 0.9.8のコミットが2015年1月17日ですが、現在(2016/1/23)に至るまでドキュメントが日本語はおろか公式にしか見つからないので、ちょっと試行錯誤してみました。
結論から言うと、簡単なpython -> javascript翻訳機として使えそうです。
Expand
ざっとドキュメントを読んだ簡単な理解をまとめます。
Python, C++, javascript, Go, rustの相互変換ができるかもしれません。 coffee script、rapydscriptの出力もできるとか。
基本的にmarkdownドキュメント中にプログラムを引用の形で記載し、本体のpythonプログラムrusthon.pyに渡してやれば変換、コンパイル、実行をやってくれるみたいです。
また、渡したファイルがmarkdownではなくpythonであれば、単純に他の言語への変換器としても動くようです。
なんかpythonに関してはpypyより速いみたいな記事を見た気がする。
git clone https://github.com/rusthon/Rusthon.git
C++11が使えるmingwを用意し、パスを通しておきます。 適当なコマンドプロンプトからg++ -vと打って、4.8とか4.9とか出ればいいかと思います。
これのために、例えば僕はいつの間にかインストールしていたgcc490のmingwのパスを通し、前のバージョンのMinGWとHaskell platformに同梱されるgccのパスを消しました。
早速pythonのクラスと配列を操作するサンプルをC++に変換して試してみます。
cd \Path\to\Rusthon\examples python ../rusthon.py array_genetics.md
d:/MinGW/gcc490/mingw32/bin/../lib/gcc/i686-w64-mingw32/4.9.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -ldl collect2.exe: error: ld returned 1 exit status Traceback (most recent call last): File "../rusthon.py", line 1951, in <module> main() File "../rusthon.py", line 1725, in main package = build(modules, base_path, datadirs=datadirs ) File "../rusthon.py", line 1398, in build subprocess.check_call( cmd ) File "c:\Python27\lib\subprocess.py", line 540, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['g++', '-O3', '-fprofile-generate', '-march=native', '-mtune=native', '-Ic:\\users\\xxxx\\appdata\\local\\temp', '-Wl,-rpath,/usr/local/lib/', '-Wl,-rpath,./', 'c:\\users\\xxxx\\appdata\\local\\temp/rusthon-c++-build.cpp', '-o', 'c:\\users\\xxxx\\appdata\\local\\temp\\rusthon-test-bin', '-pthread', '-std=c++11', '-ldl']' returned non-zero exit status 1
rusthon.pyの1371行目をコメントアウト。
## always link to libdl, external libraries may require dl_open, etc. # cmd.append('-ldl')
1330行目に/usr/local/libを加えるオプションがありますが、残しておいて大丈夫です。 するとこれでようやく、
> python ../rusthon.py array_generics.md ========== g++ : compile main ========== g++ -O3 -fprofile-generate -march=native -mtune=native -Ic:\users\xxxx\appdata\local\temp -Wl,-rpath,/usr/local/lib/ -Wl,-rpath,./ c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp -o c:\users\xxxx\appdata\local\temp\rusthon-test-bin -pthread -std=c++11 c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp: In function 'std::string* __pointer__(std::string)': c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp:54:38: warning: address of local variable 'ob' returned [-Wreturn-local-addr] std::string* __pointer__(std::string ob) { ^ running: c:\users\xxxx\appdata\local\temp/rusthon-test-bin 1 200 220 3000 hi from C
中間コードも見れます。一時作業ファイル置き場に置かれています。
Linuxだと/tmp/、Windowsには環境変数TEMPに設定されています。僕の窓10では %USERPROFILE%\AppData\Local\Temp でした。
けどいちいち見に行くのはめんどくさいので、rusthon.pyのtarを吐き出すオプションを利用します。
> python ../rusthon.py array_generics.md test.tar ========== g++ : compile main ========== g++ -O3 -fprofile-generate -march=native -mtune=native -Ic:\users\xxxx\appdata\local\temp -Wl,-rpath,/usr/local/lib/ -Wl,-rpath,./ c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp -o c:\users\xxxx\appdata\local\temp\rusthon-test-bin -pthread -std=c++11 c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp: In function 'std::string* __pointer__(std::string)': c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp:54:38: warning: address of local variable 'ob' returned [-Wreturn-local-addr] std::string* __pointer__(std::string ob) { ^ Traceback (most recent call last): File "../rusthon.py", line 1951, in <module> main() File "../rusthon.py", line 1820, in main save_tar( package, output_tar ) File "../rusthon.py", line 1505, in save_tar s.write(open(info['binary'],'rb').read()) IOError: [Errno 2] No such file or directory: 'c:\\users\\xxxx\\appdata\\local\\temp/rusthon-test-bin'
これは、コンパイル時g++にはrusthon-test-binを出力するようなオプションを渡しているのに、Windows(のg++)が勝手に.exeを付けたのでファイルを見つけられなくなっているのが原因です。
なので、rusthon.pyの1505行目に次のように追記します。
elif 'binary' in info: info['binary'] = info['binary'] + '.exe' s.write(open(info['binary'],'rb').read())
> python ../rusthon.py array_generics.md test.tar ========== g++ : compile main ========== g++ -O3 -fprofile-generate -march=native -mtune=native -Ic:\users\xxxx\appdata\local\temp -Wl,-rpath,/usr/local/lib/ -Wl,-rpath,./ c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp -o c:\users\xxxx\appdata\local\temp\rusthon-test-bin -pthread -std=c++11 c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp: In function 'std::string* __pointer__(std::string)': c:\users\xxxx\appdata\local\temp/rusthon-c++-build.cpp:54:38: warning: address of local variable 'ob' returned [-Wreturn-local-addr] std::string* __pointer__(std::string ob) { ^ saved build to: test.tar
これでできたtarファイルをほどきますと、中にrusthon-test-bin-source.cppとコンパイルされたrusthon-test-bin (.exeなし)があります。
cppは300行近いのでここには載せません。ご自身の目で確かめてみよう
> python ../rusthon.py hello_javascript.md ../rusthon.py:940: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal 'staticlib' : nuitka_compile( nsrc, nuitka_module_name ),
すると突然ブラウザが立ち上がりました。そしてclickmeと書かれたボタンが。 押すと"hi"とだけ書かれたアラートが出ました。
> python ../rusthon.py helloworld.py --javascript hello world > python ../rusthon.py helloworld.py --c++ hello world > python ../rusthon.py helloworld.py --go WARNING: could not find go compiler only a single translation pass was performed (the generated code may not compile) > python ../rusthon.py helloworld.py --rust Traceback (most recent call last): File "../rusthon.py", line 1951, in <module> main() File "../rusthon.py", line 1725, in main package = build(modules, base_path, datadirs=datadirs ) File "../rusthon.py", line 830, in build rustcode = translate_to_rust( pyjs ) File "<string>", line 14220, in translate_to_rust RuntimeError: rustc not found in /usr/local/bin
Goとrustはインストールしてないので、エラーが出ました。
pythonの要ともいえる標準モジュールですが、ctypesはjavascript実行時にエラー、randomは
RuntimeError: can not find rapydscript stdlib source: /lib/node_modules/rapydscript/src/lib/random.pyj
やはりinstall-dev.shを使ってのインストールをしたLinuxでないと使いこなすのは難しいようです。
おとなしくjavascriptをそのまま書くか、coffeescriptを使おうと思いました。
for i in range(1, 101): print (((i%3 == 0)and "fizz" or "") + ((i%5 == 0) and "buzz" or "")) or i
python /path/to/rusthon.py fizzbuzz_oneline.py fizzbuzz_oneline.tar
として生成されたjavascriptの中身を見ると、
var __$UID$__=0; /*for var in range*/; var i; i = (1 - 1); while (++i < 101) { console.log(((((((i % 3)) === 0 && "fizz") || "") + ((((i % 5)) === 0 && "buzz") || "")) || i)); }
for i in [f(x) for x in range(100)]: print i
みたいなことをすると、中のrange用のループ変数がバグってx = 0の時しか評価されませんでした。