< :前の番号
^ :番号順リスト
> :次の番号
P :前の記事(自分と同じ返事先を持つ)
N :次の記事
|<:スレッドの先頭
>|:次のスレッド
^ :返事先
_:自分への返事
>:同じ返事先を持つ記事(前)
<:同じ返事先を持つ記事(後)
---:分割してスレッド表示、再表示
| :分割して(縦)スレッド表示、再表示
~ :スレッドのフレーム消去
.:インデックス
..:インデックスのインデックス
2012/6/19 SASADA Koichi <ko1 / atdot.net>:
> ささだです.
>
> (2012/06/15 22:02), Yugui wrote:
>> コンパイルコストが本当に必要になるケースがはっきりしてくるまでは、まずはそれで良いかもしれません。
>> じゃ、ruby_compile_main_from_string と ruby_eval_main は削除しましょう。
>>
>> ここで案が2つあります。
>> 1. toplevel_binding と rb_f_evalを公開する
>> 2. さらに両者を合わせてruby_eval_in_main みたいなのを作る。
>>
>> どっちが良いと思います?
>> ちなみに、いずれにしてもさらにファイル版は必要だと思います。というのはマジックコメントとか読んで
>> 適切なエンコーディングを付けたりってのは結構面倒なので。
>> で、そのエンコーディングを付ける話を始めるとまたencdet話に跳んでしまうので、
>> * rb_eval_string_in_main
>> * rb_eval_file_in_main
>> を作るのが現実的かなと思ってます。
>
> 返事が遅くなってすみません.長いメールになりましたが,ちゃんと議論しよ
> うとすると,こういうふうにまとめないといかんと思って,それで面倒がって遅
> れておりました.すみません.
>
> 中田さんに協力してもらって,現在,Ruby を組み込んだアプリから Ruby プ
> ログラムを実行する方法をまとめました.下記に示すように意外とある,という
> か,あまり一貫性がなく追加しているので,あまり良くないなぁと,思っている
> というのがありまして,なので慎重になっている次第です.
>
>
> プログラムを組み込んだアプリから指定して実行する,という時,気にしない
> といけない点がいくつかあるかと思います.次の 5 項目としてまとめました.
>
> (a) プログラムの文字列はどうやって渡すか?
> (b) トップレベルの self はどうなるか?
> (c) 実行バインディングはどうなるか?
> (d) __FILE__ はどうなるか?
> (e) エンコーディングはどうなるか?
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
>
> (1) ruby_options() を利用(-r,-e,ファイル名を指定,標準入力から入力)
>
> ruby(1) と同じ利用感が得られます.
>
> -e は,エンコーディングは下記のようになるようです.
>
> http://jp.rubyist.net/magazine/?0025-Ruby19_m17n
>> なお、標準入力から読み込んだスクリプトや、コマンドラインオプション -e
> で与えたスクリプトの場合は、magic comment がなかった場合、ロケールが
> script encoding として用いられます。このため、1 行スクリプトを書く場合に
> までいちいち magic comment を書く必要はありません。
>
> プログラムの __FILE__ を好き勝手に指定する方法はありません(勝手に決ま
> ります).-r,ファイル名指定では,それぞれ読み込んだファイルの名前,-e
> では,"-e" になります.
>
> まとめますと,
>
> (a) プログラムの文字列はどうやって渡すか?
>
> -r:ファイル名でファイルを指定(ファイルの中身がプログラム)
> -e:実行する文字列を C 文字列で指定
> ファイル名:ファイル名でファイルを指定(ファイルの中身がプログラム)
> 標準入力から:標準入力から読む
>
> (b) トップレベルの self はどうなるか?
>
> main になる(ruby -e self で得られるオブジェクトを,ここでは main と呼
> ぶことにします).
>
> (c) 実行バインディングはどうなるか?
>
> -r:新しいバインディングを作って実行します.
> 例えば,ruby -rfoo -e 'p a' とあって,foo.rb に a=1 とあったとして
> も,-r と -e は別々の環境を指しているので -e で a が見つからないというエ
> ラーになります.
>
> それ以外:
>
> TOPLEVEL_BINDING になります.
>
> 例えば,ruby -e 'a=1' -e 'p a' とすると,プログラムが 2 回実行されます
> が,同じバインディングを共有しているため,問題無く2回目の実行で 1 が出力
> されます.
>
> (d) __FILE__ はどうなるか?
>
> 下記に固定されます.
>
> -r:指定されたファイル名
> -e:"-e"
> ファイル名:ファイル名
> 標準入力から:"-"
>
> (e) エンコーディングはどうなるか?
>
> マジックコメントを見て判断.ただし,下記の例外があり.
>
> http://jp.rubyist.net/magazine/?0025-Ruby19_m17n
>> なお、標準入力から読み込んだスクリプトや、コマンドラインオプション -e
> で与えたスクリプトの場合は、magic comment がなかった場合、ロケールが
> script encoding として用いられます。このため、1 行スクリプトを書く場合に
> までいちいち magic comment を書く必要はありません。
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
> 構文エラー,実行時エラー,ともにエラーが起きたらバックトレースを標準エ
> ラー出力に表示して終了します.
>
>
> (2) VALUE rb_eval_string(const char *str)
> VALUE rb_eval_string_protect(const char *str, int *state)
> VALUE rb_eval_string_wrap(const char *str, int *state)
>
> eval という名前ですが,意に反して,実は Kernel.eval ではありません.判
> りづらいですね.これがまさに,Ruby を組み込んだアプリから使うことを意識
> して作ったインターフェースです.多分.
>
> str で指定された C 文字列を実行します.-e に似ています.ただし,実行コ
> ンテキストは TOPLEVEL_BINDING ではありません.self は main です.これ
> は,require された時のコンテキストと同じです.
>
> __FILE__ は "(eval)" 固定です.
>
> protect は,例外が起きたとき,外に例外が伝搬しません.state にどういう
> 実行状態で止まったか,ということが入ります.
>
> wrap は,protect の機能に加えて,load で第2引数を true にしたときに
> toplevel に匿名 module が指定されますが,それと同じ挙動を行います.
>
> 実は,yugui さんが欲しいのは,__FILE__ が指定出来ない,という点以外は
> これなんじゃないかと思うのですが,どうでしょうか.TOPLEVEL_BINDING で実
> 行したい,というのは,本当に必要な要件なんでしょうか.
なるほど。当面__FILE__の問題だけなんとかなれば要件としては十分そうです。
IRCでも話したように、これまでの議論と笹田さんの案から、
* ruby_opaque_t を void*に戻す
* ruby_compile_main_from_file
* ruby_compile_main_from_string
* ruby_eval_main
を削除
* rb_eval_string_with_filename(VALUE string, VALUE fname);
* rb_eval_string_with_filename_protect(VALUE string, VALUE fname, int* state);
を追加、
という提案をします。異論が無ければあとでコミットしますが、特に追加する関数の名前について何かご意見(もっと良い名前)は無いでしょうか。
>
>
> まとめます.
>
> (a) プログラムの文字列はどうやって渡すか?
>
> C 文字列で渡します.
>
> (b) トップレベルの self はどうなるか?
>
> main になります.
>
> (c) 実行バインディングはどうなるか?
>
> 新しい binding を作って実行します.require で新しく作られるバインディ
> ングと同じです.
>
> rb_eval_string_wrap() の場合,定数のトップレベルが匿名モジュールになり
> ます.
>
> (d) __FILE__ はどうなるか?
>
> "(eval)" になります.
>
> (e) エンコーディングはどうなるか?
>
> マジックコメントを見ます.
> (無いとどうなんだろう...)
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
> VALUE rb_eval_string(const char *str)
> 外側に伝搬します.アプリ側でトラップ出来るようにしておかないと死にます.
>
> VALUE rb_eval_string_protect(const char *str, int *state)
> VALUE rb_eval_string_wrap(const char *str, int *state)
> エラーが起きたら state に 0 以外の値が入っています.
>
>
> (3) void rb_load(VALUE fname, int wrap)
> void rb_load_protect(VALUE fname, int wrap, int *state)
>
> ファイル名を String で渡す,ということ以外は (2) と変わりません.
>
> (a) プログラムの文字列はどうやって渡すか?
>
> ファイル名でファイルを指定(ファイルの中身がプログラム).
>
> (b) トップレベルの self はどうなるか?
>
> main になります.wrap が !0 の場合,定数のトップレベルが匿名モジュール
> になります.
>
> (c) 実行バインディングはどうなるか?
>
> 新しい binding を作って実行します.require で新しく作られるバインディ
> ングと同じです.
>
> (d) __FILE__ はどうなるか?
>
> 渡されたファイル名と同じになります(多分).
>
> (e) エンコーディングはどうなるか?
>
> マジックコメントを見ます.
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
> void rb_load(VALUE fname, int wrap)
> 外側に伝搬します.設定していないと死にます(多分).
>
> void rb_load_protect(VALUE fname, int wrap, int *state)
> ここで食い止めます.state を見るとエラーの有無をチェック出来ます.
>
>
> (4) その他
>
> その他,Kernel.eval,Kernel.instance_eval,Kernel.class_eval などを用
> いる,という手段もありますが,どちらかというと拡張ライブラリから呼び出す
> ような手段であり,設定も面倒なので省略します.いや,それらで済むのなら,
> それでいいのですが.
>
> ruby.h などで非公開の関数ですが rb_iseq_compile() + rb_iseq_eval() と
> いうのもあるかと思ったんですが,よくよく調べてみると,これらをきちんと使
> うのは準備が大変だということがわかりました.
>
> なお,上記で「準備しないと死ぬ」とあるのは,例外の伝搬先が設定されてい
> ないと死ぬ,という感じです.普通に組込み用途でカジュアルに使わない方がい
> いですね.
>
>
> とりあえず,現状認識はこの通りです.
>
>
> では,yugui さんご提案のインターフェースを見てます.
>
>> * rb_eval_string_in_main
>> * rb_eval_file_in_main
>
> (a) プログラムの文字列はどうやって渡すか?
>
> 不明.C 文字列だろうか.
>
> (b) トップレベルの self はどうなるか?
>
> main です.
>
> (c) 実行バインディングはどうなるか?
>
> TOPLEVEL_BINDING です.
>
> (d) __FILE__ はどうなるか?
>
> 不明.引数で渡すんだろうか.
>
> (e) エンコーディングはどうなるか?
>
> 多分,プログラム文字列に書いてあるのを読むんじゃないかと思う.
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
> 不明.
>
>
>
> ちなみに,組込みで有名な mruby さんのインターフェースを調べてみます.
>
> int mrb_compile_file(mrb_state*,FILE*);
> int mrb_compile_string(mrb_state*,char*);
> int mrb_compile_nstring(mrb_state*,char*,size_t);
>
> ぱっと見た感じ,ファイルや C 文字列を渡すと,これらの関数は返値 n を返
> し,コンパイル結果が mrb_state->ipre[n] に格納されます.
>
> mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value);
>
> そして,mrb_run で,格納されたコンパイル結果を実行しています(多分).
> 第二引数に,コンパイル結果 mrb_state->irep[n] を mrb_proc_new() に渡して
> Proc オブジェクトを作って(多分),第三引数にその Proc の初期値を渡して
> 実行,という感じでしょうか.多分.違ってたらすみません.
>
> まとめます.
>
> (a) プログラムの文字列はどうやって渡すか?
>
> C 文字列や FILE*.
>
> (b) トップレベルの self はどうなるか?
>
> どうなんだろう,これ.サンプル見ても判らなかったんだけど,main が勝手
> に入るのかなぁ.
>
> (c) 実行バインディングはどうなるか?
>
> そもそも binding が存在しません.
>
> (d) __FILE__ はどうなるか?
>
> どうなるんでしょうか? そもそもあるの?
>
> $ bin/mruby -e 'p __FILE__'
> "(null)"
> $ bin/mruby t.rb # t.rb には p __FILE__ と書いてある
> "t.rb"
>
> あるようでした.いつの間に設定されてたんだろう.mrb_compile_* だと,何が
> 入るんだろう.
>
> (e) エンコーディングはどうなるか?
>
> エンコーディングが存在しません(多分.あったらすみません)
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
> どうなるんでしょう? mrb_run() の外まで伝搬するのかなぁ.
>
> これでサーベイを終わります.JRuby とかも調べ出すといいんでしょうが,
> ちょっとしんどくなってきました.
>
>
>
> こう見ると,VALUE rb_eval_string_protect(const char *str, int *state)
> が,__FILE__ を指定出来ない(そして名前が Kernel.eval を想起させる悪い名
> 前である),という点以外はいけてるんじゃないかと思うのですが,どうでしょ
> うか.
>
> アプリケーション組込みアプリが,TOPLEVEL_BINDING 上で動作する,という
> のは,実は想定していませんでした(なので無かった).require 相当が動けば
> いいと思っていました.
>
> やりたいときは,
>
> $exec_string にプログラムをセットしてから,
> rb_eval_string_protected("eval($exec_string, TOPLEVEL_BINDING)"...);
>
> なんて手もあるかもしれません,がそれはあんまりかな.
>
> --
> // SASADA Koichi at atdot dot net
>
--
Yuki Sonoda (Yugui)
yugui / yugui.jp
http://yugui.jp