From fca49a8a69a0f6bb4feae74c6cd0e93d7fac8b36 Mon Sep 17 00:00:00 2001 From: Yukihiro Matsumoto Date: Thu, 21 Dec 1995 00:56:57 +0900 Subject: version 0.95 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://cache.ruby-lang.org/pub/ruby/1.0/ruby-0.95.tar.gz Thu Dec 21 00:56:57 1995 Yukihiro Matsumoto * version 0.95 - fj.sourcesに * eval.c (rb_eval): rescueのロジックをrb_rescue()に一元化. Wed Dec 20 19:30:58 1995 Yukihiro Matsumoto * Makefile.in: 不要なコンパイルの回避(より完全に). * class.c (singleton_class_new): `single'->`singleton' Tue Dec 19 07:14:33 1995 Yukihiro Matsumoto * io.c (closed?): IOがcloseされているかどうかを知る述語. * parse.y (primary): 特異メソッドの引数のlex_stateが不適切. * lib/tk.rb: tcl->rubyの変換関数の用意. * ext/extmk.rb.in (install): installの2重コンパイルの回避. * array.c (range_beg_len): range指定の不適切なエラーを訂正. * string.c (str_aref): range指定のバグを削除. * lib/tk.rb (tk_split_list): Tclのリストに対応. Mon Dec 18 09:58:12 1995 Yukihiro Matsumoto * version 0.94 * dln.c (dln_load): HP対応(未確認) * eval.c (Init_Proc): BlockをProcに改名. Sat Dec 16 13:46:14 1995 Yukihiro Matsumoto * eval.c (rb_eval): retryでイテレータの再実行ができるように. Fri Dec 15 17:14:30 1995 Yukihiro Matsumoto * eval.c: proc:lambdaの親しみやすい別名 Thu Dec 14 17:21:55 1995 Yukihiro Matsumoto * eval.c (dyna_var_asgn): イテレータブロック内で最初に初期化された ローカル変数の有効範囲をそのブロック内に限定.これでlambdaと呼べ ないことはない. Wed Dec 13 02:30:58 1995 Yukihiro Matsumoto * gc.c: autoloadのマークミス. * lib/tk.rb: wishからの複数行の戻り値に対応 * lib/tkcomposite.rb: 複合widget * variable.c (rb_class2path): ICLASSに対応してなかった. * eval.c (ruby_run): exit(0)のバグ Sat Dec 9 01:21:24 1995 Yukihiro Matsumoto * ext/marshal/marshal.c (dumps|load): 文字列に対する入出力を可能に した(ただし実はファイル経由なのだ). Fri Dec 8 18:29:11 1995 Yukihiro Matsumoto * ext/marshal/marshal.c: シンボルを一度だけ初期化する. Thu Dec 7 07:58:50 1995 Yukihiro Matsumoto * parse.y (yylex): 第1引数の正規表現の認識にエラーがあった.同時に 状態数を減らした. * string.c (str_sub): 置換でスキップ幅が大きすぎた. Wed Dec 6 15:14:23 1995 Yukihiro Matsumoto * string.c (str_sub_method): sub/gsub(!なし)は置換が行なわれなかっ た時,置換前の文字列を返す. Tue Dec 5 00:55:15 1995 Yukihiro Matsumoto * parse.y (yylex): 括弧を省略した時の引数展開の`*'に対応. * eval.c (ruby_run): EXITハンドラ内での例外に対応. * bignum.c (big_cmp): BignumとFixnumの比較で落ちる. Mon Dec 4 14:21:18 1995 Yukihiro Matsumoto * parse.y (call_op): コンパイル時の定数式の展開をやめた.労多くし て益少ないと判断したので. Thu Nov 30 01:35:15 1995 Yukihiro Matsumoto * lib/tk.rb: {Radio,Check}Buttonのvariableの実装. * eval.c (rb_yield_0): Block.callがネストした時のバグ. * io.c (f_select): 常に配列3つをふくむ配列を返すように * lib/tk.rb: fileeventをruby側で実装. Wed Nov 29 17:53:23 1995 Yukihiro Matsumoto * variable.c (rb_ivar_get): selfを常に指定するように. Tue Nov 14 00:07:29 1995 Yukihiro Matsumoto * lib/tk.rb: Tk4.0対応 Mon Nov 13 16:23:32 1995 Yukihiro Matsumoto * version 0.93 Thu Nov 9 23:26:01 1995 Yukihiro Matsumoto * gc.c (gc_mark): モジュールのMixinのマーク忘れ. * parse.y (f_arglist): メソッド定義の引数を括弧で括らなくても良い ようにした. Wed Nov 8 00:17:51 1995 Yukihiro Matsumoto * eval.c (rb_yield_0): 未初期化のローカル変数があった. * eval.c (rb_eval): pendig signalのチェックをeval実行後に行うよう にした.でないとシグナルの発生と検出が遠く離れてしまう事がある. * parse.y: class文のsuperclass部を定数から式に拡張した. * lib/tk.rb: Tkのほぼ全ウィンドウクラスに対応.キャンバスとテキス ト上のオブジェクトが残っている. Tue Nov 7 08:18:37 1995 Yukihiro Matsumoto * signal.c (trap): ブロックを指定できるように. Mon Nov 6 16:44:00 1995 Yukihiro Matsumoto * eval.c (f_caller): 呼出元の情報を得る. * ext/tkutil/tkutil.c: wishのstderr出力を監視することで,エラー処 理を行う. * ext/tkutil/tkutil.c: wishとの通信部をCで記述. Sat Nov 4 01:12:59 1995 Yukihiro Matsumoto * sample/ruby-mode.el (ruby-calculate-indent): インデントの計算を もう少しスマートにした(正規表現のチェック,継続行のチェック). * eval.c (rb_call): 無限再帰を避けるため,関数のネストレベルの制限 を行なう. * lib/tk.rb: Tkインターフェース.まだ不完全だが. * eval.c (rb_yield_0): 空のBlockのバグ. * sample/ruby-mode.el (ruby-calculate-indent): 行末の演算子による 行継続に対応. Fri Nov 3 12:56:21 1995 Yukihiro Matsumoto * eval.c (rb_call): 本体が空の関数の実行にバグ. * parse.y (var_extend): 文字列の末尾の変数展開のバグ. * variable.c (rb_gvar_set): traceの評価時にに変数値を与えるように. * eval.c (f_require): ruby scriptのrequireにbug. * variable.c (rb_const_get): モジュールのinclude対策. Thu Oct 19 13:56:06 1995 Yukihiro Matsumoto * dln.c (dln_load): HP対応でのtypo. Wed Oct 18 17:39:39 1995 Yukihiro Matsumoto * version 0.92 * object.c (krn_type): オブジェクトの動的な型を返すメソッド. Tue Oct 17 00:48:18 1995 Yukihiro Matsumoto * ruby.c (proc_options): -X オプション.chdirだけを行う. * re.c (reg_search): 漢字コードを途中で変更できるように.コンパイ ル時のコードが変更された時にはマッチの直前に正規表現の再コンパイ ルを行う.定数KCODEから変数$KCODEへ. * parse.y: ()のなかにcompexprを許す. * re.c (reg_search): メモリリークを直した. Fri Oct 13 13:19:19 1995 Yukihiro Matsumoto * string.c (str_sub): 文字列置換にバグ. * string.c (str_strip_bang): 文字列の後ろの長さの調整が行われてい なかった. * re.c (reg_search): $&, $1...のはローカルに束縛するようになった. 呼び出したメソッドでのマッチは現スコープの$&などの値に影響しない. マッチの情報をスコープ外で得たいときには$~を使って束縛情報を持ち 出す必要がある. Thu Oct 12 00:33:33 1995 Yukihiro Matsumoto * re.c (reg_search): String:split, String:indexでは$&, $1...が変化 しないようにした. * io.c (rb_str_setter): setterの仕様が変更になっていた. * variable.c (f_trace_var): 第2引数を省略してイテレータとして呼べ るように. Wed Oct 11 11:50:59 1995 Yukihiro Matsumoto * version 0.91 * variable.c (var_setter): 引数が間違っていた.致命的バグ. * io.c (pipe_open): $stderrの値が変更されている時にはそちらを 子プロセスのstderrに設定する. Mon Oct 9 13:06:33 1995 Yukihiro Matsumoto * object.c (mod_to_s): モジュール内のモジュールは`::'を使った表現 で表示されるように. * variable.c (rb_gvar_set): 代入によるループが発生しないように, trace内での代入ではtraceを評価しない. * struct.c (struct_equal): structのequal判定にクラスの一致を含めた. Sat Oct 7 00:18:32 1995 Yukihiro Matsumoto * eval.c (rb_eval): defined?の機能を拡張(yieldのチェック,superの 存在など). Fri Oct 6 12:06:47 1995 Yukihiro Matsumoto * version 0.90 * st.c (st_foreach): 要素を削除した時に要素数が変化していなかった. * hash.c (hash_values): バグ修正.keysを返していた…. * parse.y (call_op): defined? の引数では定数の畳み込みを行わない (チェックする前にコンパイルエラーになっては困る). * スコープ生成の一部見直し. Thu Oct 5 00:29:43 1995 Yukihiro Matsumoto * 関数とクラスの命名規則を変更した.関数名,変数名の全面書き換え. * gc.c (looks_pointerp): ヒープチェックの高速化. * struct.c (Fstruct_aset): 構造体に対する`[]='. (struct_set): 構造体メンバに対する代入. Wed Oct 4 09:54:07 1995 Yukihiro Matsumoto * version 0.89 * eval.c (Frequire): ダイナミックロードのエラーチェックを厳しく. * struct.c: structの構造を完全に書き換えた.以前は順序付きの id->valueの連想配列であったが,今度は構造体毎に新しいクラスを生 成するようにした. * parse.y: `::'の意味をAssocの生成からクラス(モジュール)内の定数ア クセスへ変更. * assoc.c: なくす. Tue Oct 3 13:31:08 1995 Yukihiro Matsumoto * variable.c (Ftrace_var): trace_var, 大域変数への書き込みhookを設 定する. * variable.c: global_entryの構成を書き換えた.これでtrace_varを実 装できる. * file.c (Ffile_stat): "&"で直前のfstatの結果も参照できるように. Fri Sep 29 14:15:13 1995 Yukihiro Matsumoto * version 0.88 * dln.c (dln_load): AIXとHPに対応したコードを入れた(動作は未確認). * ext/extmk.rb.in: 必要に応じて,定数EXTLIBを定義するように. * dln.c (dln_load): dln独立に書き換える.将来の拡張用. (load_1): dln_a_outにおいてソースコードでライブラリを明示的にロー ドする必要がないように変更した. Thu Sep 28 13:31:37 1995 Yukihiro Matsumoto * sample/ruby-mode.el: もっとましなhilit19対応(正規表現). Wed Sep 27 04:12:44 1995 Takahasi Mamoru * sample/test.rb: echoで-nを使わないように(SysV対策). * ext/extmk.rb.in: sub -> sub! Tue Sep 26 19:12:42 1995 Yasuo OHBA * dln.c (dln_find_1): `.', `..'から始まるパスに対応した. Mon Sep 25 12:33:03 1995 Yukihiro Matsumoto * version 0.87 Sat Sep 23 10:00:18 1995 Yukihiro Matsumoto * eval.c (Fmod_modfunc): メソッドをprivateにし,同時に特異メソッド も定義するメソッド.パッケージ的使い方のモジュール用. Fri Sep 22 11:02:44 1995 Yukihiro Matsumoto * lib/find.rb: findを提供するライブラリ * variable.c (rb_define_variable): hookの設定を分離. (add_hook): 1変数に対して複数のhookを設定できるように. Thu Sep 21 00:22:11 1995 Yukihiro Matsumoto * string.c (Fstr_frozen): 文字列が更新不可かどうかをチェックする述 語メソッド. * hash.c (Fhash_aset): keyが文字列の時,キーの内容が変化しないよう に,dupしてfreezeする. Wed Sep 20 16:12:44 1995 Yukihiro Matsumoto * version 0.86 * ext/extmk.rb.in (have_header): キャッシュにバグ. * ext/extmk.rb.in (have_library): 引数の順序が変わった. Thu Sep 14 18:00:59 1995 Yukihiro Matsumoto * object.c (obj_is_instance_of): is_member_ofから名称変更. Wed Sep 13 15:44:35 1995 Yukihiro Matsumoto * string.c (Fstr_tr_bang): 範囲外の文字に対する変換バグ. Tue Sep 12 14:27:58 1995 Yukihiro Matsumoto * file.c (Sfile_expand_path): expand_file_name -> expand_pathに名 称変更. * enum.c (Fenum_member): includes? -> member? に名称変更. * string.c (Fstr_each_byte): StringはByteArrayであるという基本に戻っ て,eachの定義をeach_byteに変更した.今までのeachはeach_lineでア クセスできる. Mon Sep 11 18:31:17 1995 Yukihiro Matsumoto * file.c (cache_stat): ファイル名として"&"を指定すると直前の stat(2)の結果を再利用するように. Fri Sep 8 14:18:51 1995 Yukihiro Matsumoto * ruby.texi: `!', `?'に対応してアップデート. * parse.y: defined -> defined? * file.c: FileOpの一文字メソッドをなくす.一文字テストはtestメソッ ドにまかせる. * parse.y (yylex): 変数名の後ろに`?'も許す.述語メソッドの後ろに `?'を追加する. Thu Sep 7 20:01:33 1995 Yukihiro Matsumoto * string.c: 文字列の中身を更新するメソッドの名前の終りに`!'を付加. `!'の無いバージョンも用意した. * parse.y: 変数名の後ろに`!'を許す. Wed Sep 6 14:12:19 1995 Yukihiro Matsumoto * version 0.85 * string.c (Fstr_dup): 文字列の複製を作る (Fstr_freeze): 文字列の更新不可属性を設定できるように. (Fsub/Fgsub): $_の内容をdupしてから置換を行うように. * ruby.h (CLONESETUP): flagsの状態もコピー Tue Sep 5 01:27:50 1995 Yukihiro Matsumoto * sample/test.rb: 失敗の検出を厳しく. Fri Aug 25 14:31:02 1995 Yukihiro Matsumoto * process.c (Ffork): イテレータとしても動作するように. * version 0.84 * signal.c (sig_beg): ハンドラが設定されている時には再設定しない. * ext/extmk.rb.in (create_makefile): shared objectのリンクの際に `-l'オプションを指定するように. * signal.c (trap): `EXIT'で終了処理を行う設定が出来る. Wed Aug 16 00:13:22 1995 Yukihiro Matsumoto * signal.c (sig_beg): デフォルトではbegin節の中でだけSIGINTを捕捉 するように変更. * io.c (io_ctl): fcntlを持たないシステムにも対応. * 各ディレクトリに分散していたMANIFESTをまとめた.拡張モジュール毎 には必要. * string.c (Sstr_new,str_sub,Fstr_crypt): 引数を自動的に文字列に変 換するように. Sat Aug 12 00:44:02 1995 Yukihiro Matsumoto * string.c (Fstr_crypt): PD cryptを用意した. Fri Aug 11 14:37:03 1995 Yukihiro Matsumoto * assoc.c (Fassoc_clone): assocもcloneできるように. * io.c: マクロREAD_DATA_PENDINGの定義を変更(Linux対応) * io.c (io_fptr_finalize): ftprの開放時の処理を指定できるように. Wed Aug 9 16:52:41 1995 Yukihiro Matsumoto * eval.c (rb_provided): 複数のfeatureをロードすると無限ループに落 ちるという単純な(しかし凶悪な)ミス. * ext/extmk.rb.in (install): dlopen対応を行った.今までdlnにしか十 分に対応していなかった. Tue Aug 8 14:17:06 1995 Yukihiro Matsumoto * version 0.83 Mon Aug 7 12:47:41 1995 Yukihiro Matsumoto * parse.y: resque -> rescue.恥ずかしいがtypoを残しておくわけには いかないよなあ.なんで今まで気がつかなかったのか…. Thu Aug 3 18:18:05 1995 Yukihiro Matsumoto * missing/nt.c: NT移植用の関数群をまとめた. * variable.c (rb_const_get): また例外を発生するようにした.defined がある以上例外を発生させない理由がないので(例外が発生した方がタ イプミスの検出などの点で有利). * variable.c (Fautoload): autoloadを実装.今度は使えるか. Mon Jul 31 15:44:21 1995 Yukihiro Matsumoto * parse.y (arg_ambiguous): 第1引数のあいまいさを警告(-vオプション で有効). * eval.c (rb_eval): `-v'オプションをつけて`def'が呼ばれると不必要 なエラーメッセージが出た. * parse.y (yylex): メソッドの第1引数の判定をもうちょっと賢くした. Fri Jul 28 19:04:43 1995 Yukihiro Matsumoto * parse.y (yylex): `+/-/['の直前に空白が来るかどうかで動作を変更し た(混乱のもとか?) Wed Jul 26 09:21:23 1995 Yukihiro Matsumoto * version 0.82a * sprintf.c (Fsprintf): `%s'で'\0'を含む文字列に対応. * pack.c (Fpck_pack): packの要素確保のバグ. * eval.c (Floop): 無限ループのイテレータ. * io.c (next_argv): 存在しないファイル名が指定された時のエラー処理 が行われていなかった. Mon Jul 24 17:37:34 1995 Yukihiro Matsumoto * version 0.82 * ext/extmk.rb.in (install): 拡張モジュールをstatic linkする場合は そのモジュールが既にrequireされたのと同じようにfeatureを設定する. これで拡張モジュールの機能が必要な時には(static linkされているか どうかにかかわらず)requireすればよくなる. * eval.c (Frequire): `$"'に格納する文字列をフルパスでなくフィーチャ 名とする.rubyスクリプトをロードした時には`.rb',オブジェクトを ロードした時には`.o'をフィーチャ名に付加する.lispのrequireと provideの働きに(少し)近い. Thu Jul 20 12:50:05 1995 Yukihiro Matsumoto * Makefile.in (test): make testができるように. * struct.c (struct_new): typo. * eval.c (rb_eval): `defined'を追加.メソッド/変数/定数の定義状態 を知る事が出来る. Wed Jul 19 18:04:01 1995 Yukihiro Matsumoto * version 0.81 Mon Jul 17 14:53:51 1995 Yukihiro Matsumoto * variable.c (rb_const_get): 未初期化のCONSTANTの値をnilにした.し かし,今後また例外に戻す可能性はある.要はoptionalなクラス/モジュー ルが存在するかチェックしたいだけなんだな. * st.c (int): grow_factorを固定にした(大嶋さんのマシンに対応). Fri Jul 14 00:48:40 1995 Yukihiro Matsumoto * ext/extmk.rb.in: キャッシュのバグを修正. * parse.y (var_extend): #{$数字}に対応した. * dln.c (dln_load_1): `Init_FILENAME'だけを有効に.`init_*'は今後 実行しない. * ext/etc/etc.c : Etcモジュールを拡張モジュールとして分離.実はNT 対応への布石だったりするかもしれない. Tue Jul 11 17:12:48 1995 Yukihiro Matsumoto * gcc -Wallで出たwarningを元にソースを変更. * signal.c (trap): typo. Fri Jul 7 10:08:51 1995 Yukihiro Matsumoto * version 0.80 * ruby.texi: texinfo documentを提供.specとruby.1は無くなった. * signal.c (Ftrap): 割込み禁止中の例外発生に対応. * eval.c (Flambda): Blockオブジェクトを返す.Block.newと同義. Thu Jul 6 00:35:03 1995 Yukihiro Matsumoto * signal.c (Ftrap): SIG_DFLの処理を変更.SIGINTへのデフォルトハン ドラを用意(例外を発生する). * file.c (Sfile_expand_fname): パス名を絶対パスに展開するメソッド. (Sfile_basename): basenameを得るメソッド.拡張子も外せる. (Sfile_dirname): basenameの反対. * eval.c (rb_call): argument評価中の例外発生に対応. * file.c (Ftest): `M', `A', `C'を追加. Tue Jul 4 12:36:33 1995 Yukihiro Matsumoto * file.c (Ftest): ファイルテスト用メソッド. * ruby.c (proc_options): `-r'オプションを追加. * parse.y (f_args): デフォルト引数を追加. * eval.c (rb_call): 該当する引数が無い時,rest引数の値をnilに. * numeric.c (num_equal): 数値以外との比較で例外が発生していた. FALSEを返すように. * eval.c (masign): 多重代入のrest部の動作がおかしかった. Sat Jun 17 01:03:16 1995 Yukihiro Matsumoto * parse.y (gettable): 未初期化のローカル変数の参照(独立した識別子) は正式にメソッド呼び出しとした. * parse.y (read_escape): tokenbufを使わないように修正.それにとも ない,`\C-x',`\M-x'などのエスケープ表現を復活.これでドキュメン トと実際の処理系が一致した. Thu Jun 15 15:42:00 1995 Yukihiro Matsumoto * re.c (re_regcomp): cacheのチェックを改善. Mon Jun 12 18:50:51 1995 Yukihiro Matsumoto * version 0.79 Sat Jun 10 00:25:01 1995 Yukihiro Matsumoto * re.c (re_regcomp): cache判定に`$='の値も反映させた. * sample/test.rb: test suite作成. Fri Jun 9 15:58:34 1995 Yukihiro Matsumoto * re.c (re_regcomp): cacheの判定が間違っていた. Fri Jun 9 00:01:35 1995 Yukihiro Matsumoto (matz@dyna) * eval.c (rb_yield): block構造体に初期化していないメンバ(iter)があっ たのでイテレータのネストが正しく動作しなかった. Thu Jun 8 00:59:03 1995 Yukihiro Matsumoto (matz@dyna) * re.c (=~): String以外との比較がFALSEを返すように(例外を発生して いた). * extmk.rb.in: 判定した値をファイルにキャッシュするようにした. * assoc.c (to_a): to_aメソッドが再定義されていなかった. * eval.c (rb_eval): 初期化されていないローカル変数へのアクセスを引 数の無いメソッド呼び出しと解釈する.ただし,(現状では)メソッドが 定義されていない場合,エラーにせず変数未初期化のwaringを出して nilを返している.「ruby -pe print」などが実行できるという意味で はありがたいこの仕様は,しかし今後の検討が必要である.-- メソッ ド呼び出しとするのを止めるか(以前の仕様),いつもメソッド呼び出し とする(未定義ならばエラー)か,今の仕様で行くか. * eval.c (rb_eval): 初期化されていないローカル変数へのアクセスで (evalなどで)初期化された事が分かった時には以後初期化されたローカ ル変数とみなす. Wed Jun 7 11:58:12 1995 Yukihiro Matsumoto * eval.c (rb_fail): 例外処理後も`$!'をクリアしないように. (rb_fail): `$!'変数に最後に改行を追加しない. * io.c (Fprint): privateメソッドに変更.引数を取らない時の動作を変 更(`$_'を出力する). (Fio_print): 出力先指定のprintメソッド. (Fio_printf): 出力先指定のprintfメソッド. * parse.y: not演算子の追加.優先順位の低い`!'演算子. Mon Jun 5 19:00:55 1995 Yukihiro Matsumoto * version 0.78 Fri Jun 2 17:52:03 1995 Yukihiro Matsumoto * ruby.c (proc_options): -Iオプションで`$:'への追加される順番を修 正した. Fri Jun 2 00:36:34 1995 Yukihiro Matsumoto (matz@dyna) * parse.y: while修飾子の動作を通常のwhileと同じにした.ただし, begin式へのwhile修飾子だけはdo..while型のループとなる. Wed May 31 18:36:30 1995 Yukihiro Matsumoto * version 0.77 Mon May 29 18:39:37 1995 Yukihiro Matsumoto * ext/extmk.rb.in (install): 拡張モジュールもインストールできるよ うに. Fri May 26 14:43:01 1995 Yukihiro Matsumoto * process.c (Fsystem): 戻り値をサブプロセスの失敗/成功を表す真偽値 にした.終了ステータスは`$?'で得る. Tue May 23 10:58:11 1995 Yukihiro Matsumoto * string.c (Fstr_upto): 無限ループに陥らないように. * parse.y (cond): `||'などの右辺に制御式が書けるように,条件式がか ならずしも値を持たなくても良いようにした. * ext/marshal/marshal.c: オブジェクトの読み書きをメソッドの再定義 でコントロールできるように.インスタンスが`_dump_to'というメソッ ドを定義している時はそちらを使うように. * ext/extmk.rb.in: static linkも設定できるような仕様にした. ext/Setupというファイルにディレクトリ名を記述するとそのディレク トリに存在するモジュールはstatic linkされる(はず). * eval.c (rb_eval): `..'を文法に組み込み,`..'と`...'の動作をperl に合わせた. Sat May 20 01:22:48 1995 Yukihiro Matsumoto (matz@dyna) * io.c (select): timeout時と割込み時の動作の明確化. Co-authored-by: Takahasi Mamoru Co-authored-by: Yasuo OHBA --- eval.c | 1537 ++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 1001 insertions(+), 536 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index a96e84ef3c..c1363a6840 100644 --- a/eval.c +++ b/eval.c @@ -11,9 +11,9 @@ ************************************************/ #include "ruby.h" -#include "ident.h" #include "env.h" #include "node.h" +#include "sig.h" #include #include @@ -24,13 +24,11 @@ # include #else char *strchr(); +char *strrchr(); #endif -#ifdef HAVE_STDLIB_H -#include -#else -char *getenv(); -#endif +VALUE cProc; +static VALUE proc_call(); static void rb_clear_cache_body(); static void rb_clear_cache_entry(); @@ -48,6 +46,7 @@ struct cache_entry { /* method hash table. */ ID mid; /* method's id */ struct RClass *class; /* receiver's class */ struct RClass *origin; /* where method defined */ + int nargs; /* # of args */ NODE *method; int noex; }; @@ -63,7 +62,7 @@ rb_add_method(class, mid, node, noex) { NODE *body; - if (class == Qnil) class = (struct RClass*)C_Object; + if (class == Qnil) class = (struct RClass*)cObject; if (st_lookup(class->m_tbl, mid, &body)) { Warning("redefine %s", rb_id2name(mid)); rb_clear_cache_body(body); @@ -97,14 +96,13 @@ rb_get_method_body(classp, idp, noexp) ID *idp; int *noexp; { - int pos, i; ID id = *idp; struct RClass *class = *classp; NODE *body; struct RClass *origin; struct cache_entry *ent; - if ((body = search_method(class, id, &origin)) == Qnil) { + if ((body = search_method(class, id, &origin)) == FALSE) { return Qnil; } if (body->nd_body == Qnil) return Qnil; @@ -186,16 +184,30 @@ rb_export_method(class, name, noex) } } -VALUE -rb_method_boundp(class, id) +static VALUE +method_boundp(class, id, ex) struct RClass *class; ID id; + int ex; { - if (rb_get_method_body(&class, &id, 0)) + int noex; + + if (rb_get_method_body(&class, &id, &noex)) { + if (ex && noex == NOEX_PRIVATE) + return FALSE; return TRUE; + } return FALSE; } +VALUE +rb_method_boundp(class, id) + struct RClass *class; + ID id; +{ + return method_boundp(class, id, 0); +} + static void rb_clear_cache_body(body) NODE *body; @@ -251,44 +263,51 @@ extern int nerrs; extern VALUE TopSelf; VALUE Qself; -#define PUSH_SELF(s) { \ - VALUE __saved_self__ = Qself; \ - Qself = s; \ +#define PUSH_SELF(s) { \ + VALUE __saved_self__ = Qself; \ + Qself = s; \ #define POP_SELF() Qself = __saved_self__; } -struct ENVIRON *the_env, *top_env; -struct SCOPE *the_scope, *top_scope; +struct FRAME *the_frame; +struct SCOPE *the_scope; +static struct FRAME *top_frame; +static struct SCOPE *top_scope; -#define PUSH_ENV() { \ - struct ENVIRON _env; \ - _env.prev = the_env; \ - the_env = &_env; \ +#define PUSH_FRAME() { \ + struct FRAME _frame; \ + _frame.prev = the_frame; \ + _frame.file = sourcefile; \ + _frame.line = sourceline; \ + the_frame = &_frame; \ -#define POP_ENV() the_env = _env.prev; } +#define POP_FRAME() the_frame = _frame.prev; } struct BLOCK { NODE *var; NODE *body; VALUE self; - struct ENVIRON env; + struct FRAME frame; struct SCOPE *scope; int level; - VALUE block; int iter; + struct RVarmap *d_vars; struct BLOCK *prev; } *the_block; #define PUSH_BLOCK(v,b) { \ struct BLOCK _block; \ _block.level = tag_level; \ - _block.var=v; \ + _block.var = v; \ _block.body = b; \ _block.self = Qself; \ - _block.env = *the_env; \ + _block.frame = *the_frame; \ + _block.frame.file = sourcefile; \ + _block.frame.line = sourceline; \ _block.scope = the_scope; \ - _block.block = Qnil; \ + _block.d_vars = the_dyna_vars; \ _block.prev = the_block; \ + _block.iter = iter->iter; \ the_block = &_block; \ #define PUSH_BLOCK2(b) { \ @@ -297,6 +316,51 @@ struct BLOCK { #define POP_BLOCK() the_block = the_block->prev; } +struct RVarmap *the_dyna_vars; +#define PUSH_VARS() { \ + struct RVarmap *_old; \ + _old = the_dyna_vars; + +#define POP_VARS() the_dyna_vars = _old; } + +VALUE +dyna_var_ref(id) + ID id; +{ + struct RVarmap *vars = the_dyna_vars; + + while (vars) { + if (vars->id == id) return vars->val; + vars = vars->next; + } + return Qnil; +} + +VALUE +dyna_var_asgn(id, value) + ID id; + VALUE value; +{ + struct RVarmap *vars = the_dyna_vars; + + while (vars) { + if (vars->id == id) { + vars->val = value; + return; + } + vars = vars->next; + } + { + NEWOBJ(_vars, struct RVarmap); + OBJSETUP(_vars, Qnil, T_VARMAP); + _vars->id = id; + _vars->val = value; + _vars->next = the_dyna_vars; + the_dyna_vars = _vars; + } + return value; +} + static struct iter { int iter; struct iter *prev; @@ -322,7 +386,7 @@ static struct tag { jmp_buf buf; struct gc_list *gclist; VALUE self; - struct ENVIRON *env; + struct FRAME *frame; struct iter *iter; struct tag *prev; } *prot_tag; @@ -331,15 +395,16 @@ static struct tag { struct tag _tag; \ _tag.level= ++tag_level; \ _tag.self = Qself; \ - _tag.env = the_env; \ + _tag.frame = the_frame; \ _tag.iter = iter; \ _tag.prev = prot_tag; \ prot_tag = &_tag; \ #define EXEC_TAG() (setjmp(prot_tag->buf)) + #define JUMP_TAG(val) { \ Qself = prot_tag->self; \ - the_env = prot_tag->env; \ + the_frame = prot_tag->frame; \ iter = prot_tag->iter; \ longjmp(prot_tag->buf,(val)); \ } @@ -372,8 +437,8 @@ struct class_link { class_link = &_link \ #define POP_CLASS() \ - the_class = class_link->class; \ - class_link = _link.prev; } + the_class = class_link->class; \ + class_link = _link.prev; } #define PUSH_SCOPE() { \ struct SCOPE *_old; \ @@ -382,16 +447,24 @@ struct class_link { _old = the_scope; \ the_scope = _scope; \ -#define POP_SCOPE() the_scope = _old; } +#define POP_SCOPE() \ + if (the_scope->flag == SCOPE_ALLOCA) {\ + the_scope->local_vars = 0;\ + the_scope->local_tbl = 0;\ + }\ + the_scope = _old;\ +} static VALUE rb_eval(); -static VALUE Feval(); +static VALUE f_eval(); static VALUE rb_call(); VALUE rb_apply(); VALUE rb_xstring(); void rb_fail(); +VALUE rb_rescue(); + static void module_setup(); static VALUE masign(); @@ -404,20 +477,15 @@ extern VALUE rb_stderr; extern int sourceline; extern char *sourcefile; -VALUE -rb_self() -{ - return Qself; -} - static ID last_func; static void -error_print() +error_print(last_func) + ID last_func; { if (errat) { fwrite(RSTRING(errat)->ptr, 1, RSTRING(errat)->len, stderr); if (last_func) { - fprintf(stderr, ":in method `%s': ", rb_id2name(last_func)); + fprintf(stderr, ":in `%s': ", rb_id2name(last_func)); } else { fprintf(stderr, ": "); @@ -426,34 +494,43 @@ error_print() if (errstr) { fwrite(RSTRING(errstr)->ptr, 1, RSTRING(errstr)->len, stderr); + if (RSTRING(errstr)->ptr[RSTRING(errstr)->len - 1] != '\n') { + putc('\n', stderr); + } } else { fprintf(stderr, "unhandled failure.\n"); } - rb_trap_exit(); - exit(1); } +extern char **environ; +char **origenviron; + void ruby_init(argc, argv, envp) int argc; char **argv, **envp; { int state; - static struct ENVIRON env; - the_env = top_env = &env; + static struct FRAME frame; + the_frame = top_frame = &frame; + + origenviron = environ; +#ifdef NT + NtInitialize(&argc, &argv); +#endif init_heap(); PUSH_SCOPE(); - the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; + the_scope->local_vars = 0; + the_scope->local_tbl = 0; top_scope = the_scope; PUSH_TAG(); PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { rb_call_inits(); - the_class = (struct RClass*)C_Object; + the_class = (struct RClass*)cObject; ruby_options(argc, argv, envp); } POP_ITER(); @@ -466,37 +543,27 @@ ruby_init(argc, argv, envp) exit(FIX2UINT(last_val)); } if (state) { - PUSH_TAG(); - error_print(); - POP_TAG(); + error_print(last_func); } } -VALUE rb_readonly_hook(); - static VALUE Eval() { - VALUE result; + VALUE result = Qnil; NODE *tree; int state; if (!eval_tree) return Qnil; tree = eval_tree; - eval_tree = Qnil; - sourcefile = tree->file; - - PUSH_TAG(); - if ((state = EXEC_TAG()) == 0) { - result = rb_eval(tree); - } - POP_TAG(); - if (state) JUMP_TAG(state); + eval_tree = 0; + result = rb_eval(tree); return result; } +void ruby_run() { int state; @@ -504,13 +571,14 @@ ruby_run() if (nerrs > 0) exit(nerrs); init_stack(); - rb_define_variable("$!", &errstr, Qnil, Qnil, 0); + rb_define_variable("$!", &errstr); errat = Qnil; /* clear for execution */ PUSH_TAG(); PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { Eval(); + rb_trap_exit(); } POP_ITER(); POP_TAG(); @@ -534,12 +602,10 @@ ruby_run() Fatal("retry outside of protect clause"); break; case TAG_FAIL: - PUSH_TAG(); - error_print(); - POP_TAG(); + error_print(last_func); + exit(1); break; case TAG_EXIT: - rb_trap_exit(); exit(FIX2UINT(last_val)); break; default: @@ -566,11 +632,12 @@ rb_eval_string(str) char *str; { char *oldsrc = sourcefile; - VALUE result; lex_setsrc("(eval)", str, strlen(str)); - eval_tree = Qnil; + eval_tree = 0; + PUSH_VARS(); yyparse(); + POP_VARS(); sourcefile = oldsrc; if (nerrs == 0) { return Eval(); @@ -582,22 +649,30 @@ rb_eval_string(str) } void -rb_trap_eval(cmd) - VALUE cmd; +rb_eval_cmd(cmd, arg) + VALUE cmd, arg; { int state; struct SCOPE *saved_scope; + if (TYPE(cmd) != T_STRING) { + if (TYPE(cmd) == T_OBJECT + && obj_is_kind_of(cmd, cProc)) { + proc_call(cmd, arg); + return; + } + } + PUSH_SELF(TopSelf); PUSH_CLASS(); PUSH_TAG(); saved_scope = the_scope; the_scope = top_scope; - the_class = (struct RClass*)C_Object; + the_class = (struct RClass*)cObject; if ((state = EXEC_TAG()) == 0) { - Feval(Qself, cmd); + f_eval(Qself, cmd); } the_scope = saved_scope; @@ -624,21 +699,40 @@ rb_trap_eval(cmd) Fatal("retry outside of protect clause"); break; default: + JUMP_TAG(state); + break; + } +} + +void +rb_trap_eval(cmd, sig) + VALUE cmd; + int sig; +{ #ifdef SAFE_SIGHANDLE + int state; + + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + rb_eval_cmd(cmd, ary_new3(1, INT2FIX(sig))); + } + POP_TAG(); + if (state) { trap_immediate = 0; -#endif JUMP_TAG(state); - break; } +#else + rb_eval_cmd(cmd, ary_new3(1, INT2FIX(sig))); +#endif } -#define SETUP_ARGS do {\ +#define SETUP_ARGS {\ NODE *n = node->nd_args;\ if (!n) {\ argc = 0;\ - argv = Qnil;\ + argv = 0;\ }\ - else if (/*nd_type(n) == NODE_LIST ||*/ nd_type(n) == NODE_ARRAY) {\ + else if (nd_type(n) == NODE_ARRAY) {\ argc=n->nd_alen;\ if (argc > 0) {\ int i;\ @@ -649,6 +743,10 @@ rb_trap_eval(cmd) n=n->nd_next;\ }\ }\ + else {\ + argc = 0;\ + argv = 0;\ + }\ }\ else {\ VALUE args = rb_eval(n);\ @@ -658,45 +756,36 @@ rb_trap_eval(cmd) argv = ALLOCA_N(VALUE, argc);\ MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\ }\ -} while (0) +} + +#define RETURN(v) do { result = (v); goto finish; } while (0) static VALUE rb_eval(node) register NODE *node; { int state; - int go_out; - VALUE result; + VALUE result = Qnil; again: - if (node == Qnil) return Qnil; + if (node == Qnil) RETURN(Qnil); sourceline = node->line; - -#ifdef SAFE_SIGHANDLE - { - extern int trap_pending; - - if (trap_pending) { - rb_trap_exec(); - } - } -#endif + sourcefile = node->file; switch (nd_type(node)) { case NODE_BLOCK: - while (node->nd_next) { - rb_eval(node->nd_head); + while (node) { + result = rb_eval(node->nd_head); node = node->nd_next; } - node = node->nd_head; - goto again; + break; case NODE_SELF: - return Qself; + RETURN(Qself); case NODE_NIL: - return Qnil; + RETURN(Qnil); case NODE_IF: if (rb_eval(node->nd_cond)) { @@ -706,7 +795,7 @@ rb_eval(node) node = node->nd_else; } if (node) goto again; - return Qnil; + RETURN(Qnil); case NODE_CASE: { @@ -720,18 +809,18 @@ rb_eval(node) while (tag) { if (rb_funcall(rb_eval(tag->nd_head), match, 1, val)){ - return rb_eval(node->nd_body); + RETURN(rb_eval(node->nd_body)); } tag = tag->nd_next; } } else { - return rb_eval(node); + RETURN(rb_eval(node)); } node = node->nd_next; } } - return Qnil; + RETURN(Qnil); case NODE_WHILE: PUSH_TAG(); @@ -742,23 +831,26 @@ rb_eval(node) while_redo: rb_eval(node->nd_body); } - go_out = 0; break; case TAG_REDO: + state = 0; goto while_redo; case TAG_CONTINUE: + state = 0; goto while_cont; default: - go_out = 1; break; + } + POP_TAG(); + switch (state) { + case 0: case TAG_BREAK: - go_out = 0; + break; + default: + JUMP_TAG(state); break; } - while_out: - POP_TAG(); - if (go_out) JUMP_TAG(state); - return Qnil; + RETURN(Qnil); case NODE_WHILE2: PUSH_TAG(); @@ -769,25 +861,31 @@ rb_eval(node) while2_redo: rb_eval(node->nd_body); } while (rb_eval(node->nd_cond)); - go_out = 0; break; case TAG_REDO: + state = 0; goto while2_redo; case TAG_CONTINUE: + state = 0; goto while2_cont; default: - go_out = 1; case TAG_BREAK: break; } - while2_out: POP_TAG(); - if (go_out) JUMP_TAG(state); - return Qnil; + switch (state) { + case 0: + case TAG_BREAK: + break; + default: + JUMP_TAG(state); + } + RETURN(Qnil); case NODE_ITER: case NODE_FOR: { + iter_retry: PUSH_BLOCK(node->nd_var, node->nd_body); PUSH_TAG(); @@ -803,7 +901,7 @@ rb_eval(node) recv = rb_eval(node->nd_iter); PUSH_ITER(ITER_PRE); - result = rb_call(CLASS_OF(recv),recv,each,0,Qnil,0); + result = rb_call(CLASS_OF(recv),recv,each,0,0,0); POP_ITER(); } } @@ -812,13 +910,16 @@ rb_eval(node) switch (state) { case 0: break; + + case TAG_RETRY: + goto iter_retry; + case IN_BLOCK|TAG_BREAK: if (target_level != tag_level) { JUMP_TAG(state); } result = Qnil; break; - case IN_BLOCK|TAG_RETRY: case IN_BLOCK|TAG_RETURN: if (target_level == tag_level) { state &= ~IN_BLOCK; @@ -828,91 +929,100 @@ rb_eval(node) JUMP_TAG(state); } } - return result; + break; case NODE_FAIL: { VALUE mesg = rb_eval(node->nd_stts); if (mesg) Check_Type(mesg, T_STRING); rb_fail(mesg); - return Qnil; /* not reached */ } + break; case NODE_YIELD: - { - VALUE val; - - val = rb_eval(node->nd_stts); - result = rb_yield(val); - } - return result; + result = rb_yield(rb_eval(node->nd_stts)); + break; case NODE_BEGIN: - PUSH_TAG(); - switch (state = EXEC_TAG()) { - case 0: - retry_entry: - result = rb_eval(node->nd_head); - break; + if (node->nd_resq == Qnil && node->nd_ensr == Qnil) { + node = node->nd_head; + goto again; + } + else { + VALUE (*r_proc)(); - case TAG_FAIL: - if (node->nd_resq) { - if (node->nd_resq == (NODE*)1) { - state = 0; - } - else { - PUSH_TAG(); - state = EXEC_TAG(); - if (state == 0) result = rb_eval(node->nd_resq); - POP_TAG(); - if (state == TAG_RETRY) { - goto retry_entry; - } + if (node->nd_resq == (NODE*)1) { + r_proc = 0; + } + else { + r_proc = rb_eval; + } + if (node->nd_ensr) { + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + result = rb_rescue(rb_eval, node->nd_head, r_proc, node->nd_resq); } - if (state == 0) { - errstr = errat = Qnil; - last_func = 0; + POP_TAG(); + /* ensure clause */ + rb_eval(node->nd_ensr); + if (state) { + JUMP_TAG(state); } } - break; - } - POP_TAG(); - - /* ensure clause */ - rb_eval(node->nd_ensr); - - if (state != 0) { - JUMP_TAG(state); + else { + result = rb_rescue(rb_eval, node->nd_head, r_proc, node->nd_resq); + } } - return result; + break; case NODE_AND: - if ((result = rb_eval(node->nd_1st)) == Qnil) return result; + if ((result = rb_eval(node->nd_1st)) == FALSE) RETURN(result); node = node->nd_2nd; goto again; case NODE_OR: - if ((result = rb_eval(node->nd_1st)) != Qnil) return result; + if ((result = rb_eval(node->nd_1st)) != FALSE) RETURN(result); node = node->nd_2nd; goto again; case NODE_NOT: - if (rb_eval(node->nd_body)) return FALSE; - return TRUE; + if (rb_eval(node->nd_body)) result = FALSE; + else result = TRUE; + break; + case NODE_DOT2: case NODE_DOT3: + RETURN(range_new(rb_eval(node->nd_beg), rb_eval(node->nd_end))); + + case NODE_FLIP2: /* like AWK */ + if (node->nd_state == 0) { + if (rb_eval(node->nd_beg)) { + node->nd_state = rb_eval(node->nd_end)?0:1; + result = TRUE; + } + result = FALSE; + } + else { + if (rb_eval(node->nd_end)) { + node->nd_state = 0; + } + result = TRUE; + } + break; + + case NODE_FLIP3: /* like SED */ if (node->nd_state == 0) { if (rb_eval(node->nd_beg)) { node->nd_state = 1; - return TRUE; + result = TRUE; } - return FALSE; + result = FALSE; } else { if (rb_eval(node->nd_end)) { node->nd_state = 0; } - return TRUE; + result = TRUE; } break; @@ -946,7 +1056,7 @@ rb_eval(node) recv = rb_eval(node->nd_recv); SETUP_ARGS; POP_ITER(); - return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0); + result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0); } break; @@ -957,19 +1067,18 @@ rb_eval(node) PUSH_ITER(ITER_NOT); SETUP_ARGS; POP_ITER(); - return rb_call(CLASS_OF(Qself),Qself,node->nd_mid,argc,argv,1); + result = rb_call(CLASS_OF(Qself),Qself,node->nd_mid,argc,argv,1); } break; case NODE_SUPER: case NODE_ZSUPER: { - int i; int argc; VALUE *argv; /* used in SETUP_ARGS */ if (nd_type(node) == NODE_ZSUPER) { - argc = the_env->argc; - argv = the_env->argv; + argc = the_frame->argc; + argv = the_frame->argv; } else { PUSH_ITER(ITER_NOT); @@ -978,16 +1087,14 @@ rb_eval(node) } PUSH_ITER(iter->iter?ITER_PRE:ITER_NOT); - result = rb_call(the_env->last_class->super, Qself, - the_env->last_func, argc, argv, 1); + result = rb_call(the_frame->last_class->super, Qself, + the_frame->last_func, argc, argv, 1); POP_ITER(); } - return result; + break; case NODE_SCOPE: { - VALUE result; - PUSH_SCOPE(); PUSH_TAG(); if (node->nd_cnt > 0) { @@ -996,22 +1103,17 @@ rb_eval(node) the_scope->local_tbl = node->nd_tbl; } else { - the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; + the_scope->local_vars = 0; + the_scope->local_tbl = 0; } if ((state = EXEC_TAG()) == 0) { result = rb_eval(node->nd_body); } POP_TAG(); - if (!(the_scope->flags & SCOPE_MALLOCED)) { - the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; - } POP_SCOPE(); if (state != 0) JUMP_TAG(state); - - return result; } + break; case NODE_OP_ASGN1: { @@ -1026,8 +1128,9 @@ rb_eval(node) val = rb_funcall(val, node->nd_mid, 1, rb_eval(rval)); ary_push(args, val); rb_apply(recv, aset, args); - return val; + result = val; } + break; case NODE_OP_ASGN2: { @@ -1036,24 +1139,27 @@ rb_eval(node) recv = rb_funcall(rb_eval(node->nd_recv), id, 0); - id &= ~ID_SCOPE_MASK; - id |= ID_ATTRSET; + id = id_attrset(id); val = rb_eval(node->nd_value); rb_funcall(recv, id, 1, val); - return val; + result = val; } + break; case NODE_MASGN: - { - VALUE val = rb_eval(node->nd_value); - return masign(node, val); - } + result = masign(node, rb_eval(node->nd_value)); + break; case NODE_LASGN: - if (the_scope->local_vars == Qnil) + if (the_scope->local_vars == 0) Bug("unexpected local variable asignment"); - return the_scope->local_vars[node->nd_cnt] = rb_eval(node->nd_value); + result = the_scope->local_vars[node->nd_cnt] = rb_eval(node->nd_value); + break; + + case NODE_DASGN: + result = dyna_var_asgn(node->nd_vid, rb_eval(node->nd_value)); + break; case NODE_GASGN: { @@ -1061,51 +1167,47 @@ rb_eval(node) val = rb_eval(node->nd_value); rb_gvar_set(node->nd_entry, val); - return val; + result = val; } + break; + case NODE_IASGN: { VALUE val; val = rb_eval(node->nd_value); - rb_ivar_set(node->nd_vid, val); - return val; + rb_ivar_set(Qself, node->nd_vid, val); + result = val; } + break; + case NODE_CASGN: { VALUE val; val = rb_eval(node->nd_value); rb_const_set(the_class, node->nd_vid, val); - return val; + result = val; } break; case NODE_LVAR: - if (the_scope->local_vars == Qnil) + if (the_scope->local_vars == 0) Bug("unexpected local variable"); - return the_scope->local_vars[node->nd_cnt]; - - case NODE_LVAR2: - if (the_scope->flags & SCOPE_MALLOCED) { - ID id = node->nd_vid, *tbl = the_scope->local_tbl; - int i, len = tbl[0]; + result = the_scope->local_vars[node->nd_cnt]; + break; - tbl++; - for (i=0; ilocal_vars[i]; - } - } - Warning("local var %s not initialized", rb_id2name(node->nd_vid)); - return Qnil; + case NODE_DVAR: + result = dyna_var_ref(node->nd_vid); + break; case NODE_GVAR: - return rb_gvar_get(node->nd_entry); + result = rb_gvar_get(node->nd_entry); + break; + case NODE_IVAR: - return rb_ivar_get(node->nd_vid); + result = rb_ivar_get(Qself, node->nd_vid); + break; case NODE_CVAR: { @@ -1114,14 +1216,54 @@ rb_eval(node) val = rb_const_get(node->nd_rval->nd_clss, node->nd_vid); nd_set_type(node, NODE_CONST); node->nd_cval = val; - return val; + result = val; } + break; case NODE_CONST: - return node->nd_cval; + result = node->nd_cval; + break; + + case NODE_COLON2: + { + VALUE cls; + + cls = rb_eval(node->nd_head); + switch (TYPE(cls)) { + case T_CLASS: + case T_MODULE: + break; + default: + Check_Type(cls, T_CLASS); + break; + } + result = rb_const_get(cls, node->nd_mid); + } + break; +#define MATCH_DATA the_scope->local_vars[node->nd_cnt] case NODE_NTH_REF: - return re_nth_match(node->nd_nth); + result = reg_nth_match(node->nd_nth, MATCH_DATA); + break; + + case NODE_BACK_REF: + switch (node->nd_nth) { + case '&': + result = reg_last_match(MATCH_DATA); + break; + case '`': + result = reg_match_pre(MATCH_DATA); + break; + case '\'': + result = reg_match_post(MATCH_DATA); + break; + case '+': + result = reg_match_last(MATCH_DATA); + break; + default: + Bug("unexpected back-ref"); + } + break; case NODE_HASH: { @@ -1133,24 +1275,24 @@ rb_eval(node) while (list) { key = rb_eval(list->nd_head); list = list->nd_next; - if (list == Qnil) + if (list == 0) Bug("odd number list for Hash"); val = rb_eval(list->nd_head); list = list->nd_next; - Fhash_aset(hash, key, val); + hash_aset(hash, key, val); } - return hash; + result = hash; } break; case NODE_ZARRAY: /* zero length list */ - return ary_new(); + result = ary_new(); + break; case NODE_ARRAY: { VALUE ary; int i; - NODE *list; i = node->nd_alen; ary = ary_new2(i); @@ -1159,12 +1301,13 @@ rb_eval(node) RARRAY(ary)->len = i; } - return ary; + result = ary; } break; case NODE_STR: - return str_new3(node->nd_lit); + result = str_new3(node->nd_lit); + break; case NODE_STR2: case NODE_XSTR2: @@ -1188,26 +1331,32 @@ rb_eval(node) list = list->nd_next; } if (nd_type(node) == NODE_DREGX) { - VALUE re = regexp_new(RSTRING(str)->ptr, RSTRING(str)->len, - node->nd_cflag); - return re; + VALUE re = reg_new(RSTRING(str)->ptr, RSTRING(str)->len, + node->nd_cflag); + result = re; + } + else if (nd_type(node) == NODE_XSTR2) { + result = rb_xstring(str); } - if (nd_type(node) == NODE_XSTR2) { - return rb_xstring(str); + else { + result = str; } - return str; } + break; case NODE_XSTR: - return rb_xstring(node->nd_lit); + result = rb_xstring(node->nd_lit); + break; case NODE_LIT: - return node->nd_lit; + result = node->nd_lit; + break; case NODE_ATTRSET: - if (the_env->argc != 1) - Fail("Wrong # of arguments(%d for 1)", the_env->argc); - return rb_ivar_set(node->nd_vid, the_env->argv[0]); + if (the_frame->argc != 1) + Fail("Wrong # of arguments(%d for 1)", the_frame->argc); + result = rb_ivar_set(Qself, node->nd_vid, the_frame->argv[0]); + break; case NODE_DEFN: if (node->nd_defn) { @@ -1216,7 +1365,7 @@ rb_eval(node) int noex; body = search_method(the_class, node->nd_mid, &origin); - if (verbose && origin != (VALUE)the_class + if (body && verbose && origin != (VALUE)the_class && body->nd_noex != node->nd_noex) { Warning("change method %s's scope", rb_id2name(node->nd_mid)); } @@ -1225,8 +1374,9 @@ rb_eval(node) else noex = node->nd_noex; /* default(1 for toplevel) */ rb_add_method(the_class, node->nd_mid, node->nd_defn, noex); + result = Qnil; } - return Qnil; + break; case NODE_DEFS: if (node->nd_defn) { @@ -1236,20 +1386,23 @@ rb_eval(node) Fail("Can't define method \"%s\" for nil", rb_id2name(node->nd_mid)); } - rb_funcall(recv, rb_intern("single_method_added"), + rb_funcall(recv, rb_intern("singleton_method_added"), 1, INT2FIX(node->nd_mid)); - rb_add_method(rb_single_class(recv),node->nd_mid,node->nd_defn, + rb_add_method(rb_singleton_class(recv),node->nd_mid,node->nd_defn, NOEX_PUBLIC); + result = Qnil; } - return Qnil; + break; case NODE_UNDEF: rb_add_method(the_class, node->nd_mid, Qnil, NOEX_PUBLIC); - return Qnil; + result = Qnil; + break; case NODE_ALIAS: rb_alias(the_class, node->nd_new, node->nd_old); - return Qnil; + result = Qnil; + break; case NODE_CLASS: { @@ -1257,17 +1410,16 @@ rb_eval(node) struct RClass *tmp; if (node->nd_super) { - super = rb_const_get(the_class, node->nd_super); - if (super == Qnil) { - Fail("undefined superclass %s", - rb_id2name(node->nd_super)); + super = rb_eval(node->nd_super); + if (super == Qnil || TYPE(super) != T_CLASS) { + Fail("superclass undefined"); } } else { super = Qnil; } - if (rb_const_bound(the_class, node->nd_cname)) { + if (rb_const_defined(the_class, node->nd_cname)) { class = rb_const_get(the_class, node->nd_cname); if (super) { if (TYPE(class) != T_CLASS) @@ -1280,27 +1432,28 @@ rb_eval(node) tmp = RCLASS(tmp)->super; } if (tmp != RCLASS(super)) - Fail("%s's superclass differs", + Fail("superclass mismatch for %s", rb_id2name(node->nd_cname)); } Warning("extending class %s", rb_id2name(node->nd_cname)); } else { - if (super == Qnil) super = C_Object; + if (super == Qnil) super = cObject; class = rb_define_class_id(node->nd_cname, super); rb_const_set(the_class, node->nd_cname, class); rb_set_class_path(class,the_class,rb_id2name(node->nd_cname)); } module_setup(class, node->nd_body); - return class; + result = class; } + break; case NODE_MODULE: { VALUE module; - if (rb_const_bound(the_class, node->nd_cname)) { + if (rb_const_defined(the_class, node->nd_cname)) { module = rb_const_get(the_class, node->nd_cname); if (TYPE(module) != T_MODULE) Fail("%s is not a module", rb_id2name(node->nd_cname)); @@ -1313,13 +1466,141 @@ rb_eval(node) } module_setup(module, node->nd_body); - return module; + result = module; } + break; + + case NODE_DEFINED: + { + VALUE obj; + + node = node->nd_head; + switch (nd_type(node)) { + case NODE_SUPER: + case NODE_ZSUPER: + if (the_frame->last_func == 0) result = FALSE; + else { + result = method_boundp(the_frame->last_class->super, + the_frame->last_func, 1); + } + break; + + case NODE_FCALL: + obj = CLASS_OF(Qself); + goto check_bound; + + case NODE_CALL: + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + obj = rb_eval(node->nd_recv); + } + POP_TAG(); + if (state == TAG_FAIL) { + result = FALSE; + break; + } + else { + if (state) JUMP_TAG(state); + obj = CLASS_OF(obj); + check_bound: + if (method_boundp(obj, node->nd_mid, + nd_type(node)== NODE_CALL)) { + result = TRUE; + } + else result = FALSE; + } + break; + + case NODE_YIELD: + result = iterator_p(); + break; + + case NODE_BREAK: + case NODE_CONTINUE: + case NODE_REDO: + case NODE_RETRY: + + case NODE_SELF: + case NODE_NIL: + case NODE_FAIL: + case NODE_ATTRSET: + case NODE_DEFINED: + + case NODE_OP_ASGN1: + case NODE_OP_ASGN2: + case NODE_MASGN: + case NODE_LASGN: + case NODE_DASGN: + case NODE_GASGN: + case NODE_IASGN: + case NODE_CASGN: + case NODE_LVAR: + case NODE_DVAR: + result = TRUE; + break; + + case NODE_GVAR: + result = rb_gvar_defined(node->nd_entry); + break; + + case NODE_IVAR: + result = rb_ivar_defined(node->nd_vid); + break; + + case NODE_CVAR: + result = rb_const_defined(node->nd_rval->nd_clss, node->nd_vid); + break; + + case NODE_CONST: + result = TRUE; + break; + + case NODE_COLON2: + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + obj = rb_eval(node->nd_head); + } + POP_TAG(); + if (state == TAG_FAIL) result = FALSE; + else { + if (state) JUMP_TAG(state); + result = rb_const_defined(obj, node->nd_mid); + } + break; + + case NODE_NTH_REF: + result = reg_nth_defined(node->nd_nth, MATCH_DATA); + break; + + case NODE_BACK_REF: + result = reg_nth_defined(0, MATCH_DATA); + break; + + default: + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + rb_eval(node); + } + POP_TAG(); + if (state == TAG_FAIL) result = FALSE; + else { + if (state) JUMP_TAG(state); + result = TRUE; + } + } + } + break; default: Bug("unknown node type %d", nd_type(node)); } - return Qnil; /* not reached */ + finish: +#ifdef SAFE_SIGHANDLE + if (trap_pending) { + rb_trap_exec(); + } +#endif + return result; /* not reached */ } static void @@ -1337,7 +1618,6 @@ module_setup(module, node) the_class = (struct RClass*)module; PUSH_SELF((VALUE)the_class); PUSH_SCOPE(); - PUSH_TAG(); if (node->nd_cnt > 0) { the_scope->local_vars = ALLOCA_N(VALUE, node->nd_cnt); @@ -1345,20 +1625,15 @@ module_setup(module, node) the_scope->local_tbl = node->nd_tbl; } else { - the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; + the_scope->local_vars = 0; + the_scope->local_tbl = 0; } + PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { rb_eval(node->nd_body); } - POP_TAG(); - if (!(the_scope->flags & SCOPE_MALLOCED)) { - the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; - } - if (state != 0) JUMP_TAG(state); POP_SCOPE(); POP_SELF(); POP_CLASS(); @@ -1366,20 +1641,10 @@ module_setup(module, node) } VALUE -obj_responds_to(obj, msg) +rb_responds_to(obj, id) VALUE obj; - struct RString *msg; -{ ID id; - - if (FIXNUM_P(msg)) { - id = FIX2INT(msg); - } - else { - Check_Type(msg, T_STRING); - id = rb_intern(msg->ptr); - } - +{ if (rb_method_boundp(CLASS_OF(obj), id)) { return TRUE; } @@ -1393,11 +1658,12 @@ rb_exit(status) last_val = INT2FIX(status); if (prot_tag) JUMP_TAG(TAG_EXIT); + rb_trap_exit(); exit(FIX2UINT(last_val)); } static VALUE -Fexit(argc, argv, obj) +f_exit(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -1440,25 +1706,22 @@ rb_fail(mesg) { char buf[BUFSIZ]; - if (errat == Qnil || sourcefile) { - if (the_env->last_func) { - last_func = the_env->last_func; + if (errat == Qnil && mesg == Qnil) { + errstr = Qnil; + } + + if (errat == Qnil && sourcefile) { + if (the_frame->last_func) { + last_func = the_frame->last_func; } sprintf(buf, "%s:%d", sourcefile, sourceline); errat = str_new2(buf); } if (mesg) { - if (RSTRING(mesg)->ptr[RSTRING(mesg)->len - 1] == '\n') { - errstr = mesg; - } - else { - errstr = str_clone(mesg); - str_cat(errstr, "\n", 1); - } + errstr = mesg; } - - if (prot_tag->level == 0) error_print(); + if (prot_tag->level == 0) error_print(last_func); JUMP_TAG(TAG_FAIL); } @@ -1470,48 +1733,54 @@ iterator_p() } static VALUE -Fiterator_p() +f_iterator_p() { if (iter->prev && iter->prev->iter) return TRUE; return FALSE; } VALUE -rb_yield(val) - VALUE val; +rb_yield_0(val, self) + VALUE val, self; { struct BLOCK *block; NODE *node; int state; - VALUE result; - struct ENVIRON *old_env; - struct SCOPE *old_scope; + VALUE result = Qnil; + struct SCOPE *old_scope; + struct FRAME frame; if (!iterator_p()) { Fail("yield called out of iterator"); } + PUSH_VARS(); block = the_block; - old_env = the_env; - the_env = &(block->env); + frame = block->frame; + frame.prev = the_frame; + the_frame = &(frame); old_scope = the_scope; the_scope = block->scope; the_block = block->prev; + the_dyna_vars = block->d_vars; if (block->var) { if (nd_type(block->var) == NODE_MASGN) masign(block->var, val); else asign(block->var, val); } + node = block->body; PUSH_ITER(block->iter); - PUSH_SELF(block->self); + PUSH_SELF(self?self:block->self); PUSH_TAG(); - node = block->body; switch (state = EXEC_TAG()) { redo: case 0: - if (nd_type(node) == NODE_CFUNC) { + if (!node) { + result = Qnil; + } + else if (nd_type(node) == NODE_CFUNC) { result = (*node->nd_cfnc)(val,node->nd_argc); } else { @@ -1523,24 +1792,40 @@ rb_yield(val) case TAG_CONTINUE: state = 0; break; - case TAG_RETRY: case TAG_BREAK: case TAG_RETURN: target_level = block->level; state = IN_BLOCK|state; break; + default: + break; } POP_TAG(); POP_SELF(); POP_ITER(); + POP_VARS(); the_block = block; - the_env = old_env; + the_frame = the_frame->prev; the_scope = old_scope; if (state) JUMP_TAG(state); return result; } +VALUE +rb_yield(val) + VALUE val; +{ + return rb_yield_0(val, 0); +} + +static VALUE +f_loop() +{ + for (;;) { rb_yield(Qnil); } + return Qnil; +} + static VALUE masign(node, val) NODE *node; @@ -1590,15 +1875,19 @@ asign(lhs, val) break; case NODE_IASGN: - rb_ivar_set(lhs->nd_vid, val); + rb_ivar_set(Qself, lhs->nd_vid, val); break; case NODE_LASGN: - if (the_scope->local_vars == Qnil) + if (the_scope->local_vars == 0) Bug("unexpected iterator variable asignment"); the_scope->local_vars[lhs->nd_cnt] = val; break; + case NODE_DASGN: + dyna_var_asgn(lhs->nd_vid, val); + break; + case NODE_CASGN: rb_const_set(the_class, lhs->nd_vid, val); break; @@ -1631,13 +1920,13 @@ asign(lhs, val) VALUE rb_iterate(it_proc, data1, bl_proc, data2) VALUE (*it_proc)(), (*bl_proc)(); - char *data1, *data2; + void *data1, *data2; { int state; - VALUE retval; + VALUE retval = Qnil; NODE *node = NEW_CFUNC(bl_proc, data2); - struct BLOCK block; + iter_retry: PUSH_ITER(ITER_PRE); PUSH_BLOCK(Qnil, node); PUSH_TAG(); @@ -1654,13 +1943,17 @@ rb_iterate(it_proc, data1, bl_proc, data2) switch (state) { case 0: break; + + case TAG_RETRY: + goto iter_retry; + case IN_BLOCK|TAG_BREAK: if (target_level != tag_level) { JUMP_TAG(state); } retval = Qnil; break; - case IN_BLOCK|TAG_RETRY: + case IN_BLOCK|TAG_RETURN: if (target_level == tag_level) { state &= ~IN_BLOCK; @@ -1674,23 +1967,24 @@ rb_iterate(it_proc, data1, bl_proc, data2) } VALUE -rb_resque(b_proc, data1, r_proc, data2) +rb_rescue(b_proc, data1, r_proc, data2) VALUE (*b_proc)(), (*r_proc)(); - char *data1, *data2; + void *data1, *data2; { int state; - int go_out; - VALUE result; + VALUE result = Qnil; + volatile SIGHANDLE handle; PUSH_TAG(); switch (state = EXEC_TAG()) { case 0: + handle = sig_beg(); retry_entry: result = (*b_proc)(data1); - go_out = 0; break; case TAG_FAIL: + sig_end(handle); if (r_proc) { PUSH_TAG(); state = EXEC_TAG(); @@ -1698,28 +1992,25 @@ rb_resque(b_proc, data1, r_proc, data2) result = (*r_proc)(data2); } POP_TAG(); - switch (state) { - case TAG_RETRY: + if (state == TAG_RETRY) { goto retry_entry; - case 0: - go_out = 0; - break; - default: - go_out = 1; - break; } } + else { + state = 0; + } if (state == 0) { - errstr = errat = Qnil; + errat = Qnil; + last_func = 0; } break; default: - go_out = 1; + sig_end(handle); break; } POP_TAG(); - if (go_out) JUMP_TAG(state); + if (state) JUMP_TAG(state); return result; } @@ -1727,10 +2018,10 @@ rb_resque(b_proc, data1, r_proc, data2) VALUE rb_ensure(b_proc, data1, e_proc, data2) VALUE (*b_proc)(), (*e_proc)(); - char *data1, *data2; + void *data1, *data2; { int state; - VALUE result; + VALUE result = Qnil; PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { @@ -1748,7 +2039,7 @@ rb_ensure(b_proc, data1, e_proc, data2) static int last_noex; static VALUE -Fmissing(argc, argv, obj) +f_missing(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -1756,31 +2047,33 @@ Fmissing(argc, argv, obj) VALUE desc; ID id; char *format; - struct ENVIRON *env; + struct FRAME *frame; id = FIX2INT(argv[0]); argc--; argv++; - desc = obj_as_string(obj); - if (RSTRING(desc)->len > 160) { - desc = Fkrn_to_s(obj); + if (TYPE(obj) == T_STRING) { + desc = krn_inspect(obj); + } + else { + desc = obj_as_string(obj); } if (last_noex) - format = "method `%s' not available for \"%s\"(%s)"; + format = "method `%s' not available for %s(%s)"; else - format = "undefined method `%s' for \"%s\"(%s)"; + format = "undefined method `%s' for %s(%s)"; - /* fake environment */ - PUSH_ENV(); - env = the_env->prev; - MEMCPY(the_env, env->prev, struct ENVIRON, 1); - the_env->prev = env; + /* fake frame */ + PUSH_FRAME(); + frame = the_frame->prev; + *the_frame = *frame->prev; + the_frame->prev = frame; Fail(format, rb_id2name(id), RSTRING(desc)->ptr, rb_class2name(CLASS_OF(obj))); - POP_ENV(); + POP_FRAME(); } static VALUE @@ -1793,7 +2086,6 @@ rb_undefined(obj, id, argc, argv, noex) { VALUE *nargv; - argc; nargv = ALLOCA_N(VALUE, argc+1); nargv[0] = INT2FIX(id); MEMCPY(nargv+1, argv, VALUE, argc); @@ -1803,6 +2095,9 @@ rb_undefined(obj, id, argc, argv, noex) return rb_funcall2(obj, rb_intern("method_missing"), argc+1, nargv); } +#define STACK_LEVEL_MAX 10000 +static int stack_level; + static VALUE rb_call(class, recv, mid, argc, argv, scope) struct RClass *class; @@ -1814,7 +2109,7 @@ rb_call(class, recv, mid, argc, argv, scope) { NODE *body; int noex; - VALUE result; + VALUE result = Qnil; struct cache_entry *ent; int itr; enum node_type type; @@ -1830,7 +2125,7 @@ rb_call(class, recv, mid, argc, argv, scope) else { ID id = mid; - if ((body = rb_get_method_body(&class, &id, &noex)) == Qnil) { + if ((body = rb_get_method_body(&class, &id, &noex)) == FALSE) { return rb_undefined(recv, mid, argc, argv, 0); } mid = id; @@ -1861,13 +2156,16 @@ rb_call(class, recv, mid, argc, argv, scope) return rb_call(class->super, recv, mid, argc, argv, scope?scope:1); } + if (stack_level++ > STACK_LEVEL_MAX) + Fail("stack level too deep"); + PUSH_ITER(itr); PUSH_SELF(recv); - PUSH_ENV(); - the_env->last_func = mid; - the_env->last_class = class; - the_env->argc = argc; - the_env->argv = argv; + PUSH_FRAME(); + the_frame->last_func = mid; + the_frame->last_class = class; + the_frame->argc = argc; + the_frame->argv = argv; switch (type) { case NODE_CFUNC: @@ -1985,14 +2283,14 @@ rb_call(class, recv, mid, argc, argv, scope) /* for attr get/set */ case NODE_ATTRSET: case NODE_IVAR: - return rb_eval(body); + result = rb_eval(body); + break; default: { int state; VALUE *local_vars; - sourcefile = body->file; PUSH_SCOPE(); if (body->nd_cnt > 0) { @@ -2002,47 +2300,59 @@ rb_call(class, recv, mid, argc, argv, scope) the_scope->local_vars = local_vars; } else { - local_vars = the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; + local_vars = the_scope->local_vars = 0; + the_scope->local_tbl = 0; } body = body->nd_body; - if (nd_type(body) == NODE_BLOCK) { - NODE *node = body->nd_head; - NODE *local; - int i; - - if (nd_type(node) != NODE_ARGS) { - Bug("no argument-node"); - } + PUSH_TAG(); + state = EXEC_TAG(); + if (state == 0) { + if (nd_type(body) == NODE_BLOCK) { + NODE *node = body->nd_head; + int i; - body = body->nd_next; - i = node->nd_cnt; - if (i > argc || (node->nd_rest == -1 && i < argc)) - Fail("Wrong # of arguments(%d for %d)", argc, i); + if (nd_type(node) != NODE_ARGS) { + Bug("no argument-node"); + } - if (local_vars) { - if (i > 0) { - MEMCPY(local_vars, argv, VALUE, i); + body = body->nd_next; + i = node->nd_cnt; + if (i > argc + || (node->nd_rest == -1 + && i+(node->nd_opt?node->nd_opt->nd_alen:0)nd_rest >= 0) { - if (argc == 0) - local_vars[node->nd_rest] = ary_new(); - else - local_vars[node->nd_rest] = ary_new4(argc-i, argv+i); + + if (local_vars) { + if (i > 0) { + MEMCPY(local_vars, argv, VALUE, i); + } + argv += i; argc -= i; + if (node->nd_opt) { + NODE *opt = node->nd_opt; + + while (opt && argc) { + asign(opt->nd_head, *argv); + argv++; argc--; + opt = opt->nd_next; + } + rb_eval(opt); + } + if (node->nd_rest >= 0) { + if (argc > 0) + local_vars[node->nd_rest]=ary_new4(argc,argv); + else + local_vars[node->nd_rest] = ary_new2(0); + } } } - } - PUSH_TAG(); - state = EXEC_TAG(); - if (state == 0) { + else if (nd_type(body) == NODE_ARGS) { + body = 0; + } result = rb_eval(body); } POP_TAG(); - if (!(the_scope->flags & SCOPE_MALLOCED)) { - the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; - } POP_SCOPE(); switch (state) { case 0: @@ -2056,20 +2366,23 @@ rb_call(class, recv, mid, argc, argv, scope) case TAG_REDO: Fatal("unexpected redo"); break; - case TAG_RETRY: - Fatal("retry outside of resque clause"); - break; case TAG_RETURN: result = last_val; break; + case TAG_RETRY: + if (!iterator_p()) { + Fatal("retry outside of rescue clause"); + } default: + stack_level--; JUMP_TAG(state); } } } - POP_ENV(); + POP_FRAME(); POP_SELF(); POP_ITER(); + stack_level--; return result; } @@ -2089,7 +2402,7 @@ rb_apply(recv, mid, args) } static VALUE -Fapply(argc, argv, recv) +f_send(argc, argv, recv) int argc; VALUE *argv; VALUE recv; @@ -2133,7 +2446,7 @@ rb_funcall(recv, mid, n, va_alist) va_end(ar); } else { - argv = Qnil; + argv = 0; } return rb_call(CLASS_OF(recv), recv, mid, n, argv, 1); @@ -2149,17 +2462,69 @@ rb_funcall2(recv, mid, argc, argv) return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1); } +static VALUE +f_caller(argc, argv) + int argc; + VALUE *argv; +{ + VALUE level; + struct FRAME *frame = the_frame; + int lev, n; + char buf[BUFSIZ]; + + rb_scan_args(argc, argv, "01", &level); + if (level == Qnil) lev = 1; + else lev = NUM2INT(level); + n = lev; + if (n < 0) Fail("negative level(%d)", n); + else { + while (n-- > 0) { + frame = frame->prev; + if (!frame) return Qnil; + } + if (!frame->file) return Qnil; + if (frame->prev && frame->prev->last_func) { + sprintf(buf, "%s:%d:in `%s'", + frame->file, frame->line, + rb_id2name(frame->prev->last_func)); + } + else { + sprintf(buf, "%s:%d", frame->file, frame->line); + } + } + return str_new2(buf); +} + +void +rb_backtrace() +{ + VALUE c, lev; + int n = 0; + + lev = INT2FIX(n); + while (c = f_caller(1, &lev)) { + printf("%s\n", RSTRING(c)->ptr); + n++; + lev = INT2FIX(n); + } +} + +ID +rb_frame_last_func() +{ + return the_frame->last_func; +} + int rb_in_eval = 0; static VALUE -Feval(obj, src) +f_eval(obj, src) VALUE obj; struct RString *src; { - VALUE result; + VALUE result = Qnil; int state; NODE *node; - char *oldsrc = sourcefile; Check_Type(src, T_STRING); PUSH_TAG(); @@ -2173,11 +2538,12 @@ Feval(obj, src) if ((state = EXEC_TAG()) == 0) { lex_setsrc("(eval)", src->ptr, src->len); - eval_tree = Qnil; + eval_tree = 0; + PUSH_VARS(); yyparse(); - sourcefile = oldsrc; + POP_VARS(); if (nerrs == 0) { - result = Eval(0); + result = Eval(); } } eval_tree = node; @@ -2221,22 +2587,22 @@ find_file(file) } VALUE -Fload(obj, fname) +f_load(obj, fname) VALUE obj; struct RString *fname; { int state, in_eval = rb_in_eval; - NODE *node; - char *file; + char *file, *src; Check_Type(fname, T_STRING); file = find_file(fname->ptr); - if (!file) Fail("No such file to load -- %s", file); + if (!file) Fail("No such file to load -- %s", fname->ptr); PUSH_SELF(TopSelf); PUSH_TAG(); PUSH_CLASS(); - the_class = (struct RClass*)C_Object; + the_class = (struct RClass*)cObject; + PUSH_SCOPE(); the_scope->local_vars = top_scope->local_vars; the_scope->local_tbl = top_scope->local_tbl; rb_in_eval = 1; @@ -2244,9 +2610,11 @@ Fload(obj, fname) if (state == 0) { rb_load_file(file); if (nerrs == 0) { - Eval(0); + Eval(); } } + top_scope->flag = the_scope->flag; + POP_SCOPE(); POP_CLASS(); POP_TAG(); POP_SELF(); @@ -2259,98 +2627,175 @@ Fload(obj, fname) return TRUE; } -static VALUE rb_loadfiles; +static VALUE rb_features; -Frequire(obj, fname) - VALUE obj; - struct RString *fname; +static VALUE +rb_provided(feature) + char *feature; { - char *file; VALUE *p, *pend; + char *f; + int len; - Check_Type(fname, T_STRING); - file = find_file(fname->ptr); - if (!file) { - char *buf = ALLOCA_N(char, strlen(fname->ptr) + 4); - sprintf(buf, "%s.rb", fname->ptr); - file = find_file(buf); -#ifdef USE_DL - if (!file) { - sprintf(buf, "%s%s", fname->ptr, DLEXT); - file = find_file(buf); - } -#endif - if (!file) Fail("No such file to load -- %s", file); - } - - p = RARRAY(rb_loadfiles)->ptr; - pend = p + RARRAY(rb_loadfiles)->len; + p = RARRAY(rb_features)->ptr; + pend = p + RARRAY(rb_features)->len; while (p < pend) { Check_Type(*p, T_STRING); - if (strcmp(RSTRING(*p)->ptr, file) == 0) return FALSE; + f = RSTRING(*p)->ptr; + if (strcmp(f, feature) == 0) return TRUE; + len = strlen(feature); + if (strncmp(f, feature, len) == 0 + && (strcmp(f+len, ".rb") == 0 ||strcmp(f+len, ".o") == 0)) { + return TRUE; + } + p++; } - fname = (struct RString*)str_new2(file); - ary_push(rb_loadfiles, fname); - file = fname->ptr; + return FALSE; +} -#ifdef USE_DL - { - int len = strlen(file), extsiz = sizeof(DLEXT); +void +rb_provide(feature) + char *feature; +{ + if (!rb_provided(feature)) + ary_push(rb_features, str_new2(feature)); +} - if (len > extsiz) { - int i; - for (i=1;iptr)) return FALSE; + + ext = strrchr(fname->ptr, '.'); + if (ext) { + if (strcmp(".rb", ext) == 0) { + feature = file = fname->ptr; + file = find_file(file); + if (file) goto rb_load; + } + else if (strcmp(".o", ext) == 0) { + feature = fname->ptr; + if (strcmp(".o", DLEXT) != 0) { + buf = ALLOCA_N(char, strlen(fname->ptr) + 3); + strcpy(buf, feature); + ext = strrchr(buf, '.'); + strcpy(ext, DLEXT); + file = find_file(buf); } - if (i==extsiz) { - static int rb_dln_init = 0; - extern char *rb_dln_argv0; + if (file) goto dyna_load; + } + else if (strcmp(DLEXT, ext) == 0) { + feature = fname->ptr; + file = find_file(feature); + if (file) goto dyna_load; + } + } + buf = ALLOCA_N(char, strlen(fname->ptr) + 4); + sprintf(buf, "%s.rb", fname->ptr); + file = find_file(buf); + if (file) { + fname = (struct RString*)str_new2(file); + feature = buf; + goto rb_load; + } + sprintf(buf, "%s%s", fname->ptr, DLEXT); + file = find_file(buf); + if (file) { + feature = buf; + goto dyna_load; + } + Fail("No such file to load -- %s", fname->ptr); + + dyna_load: + load = str_new2(file); + file = RSTRING(load)->ptr; + dln_load(file); + rb_provide(feature); + return TRUE; - if (rb_dln_init == 0 && dln_init(rb_dln_argv0) == -1) { - Fail("%s: %s", rb_dln_argv0, dln_strerror()); - } + rb_load: + f_load(obj, fname); + rb_provide(feature); + return TRUE; +} - if (dln_load(file) == -1) - Fail(dln_strerror()); +static void +set_method_visibility(argc, argv, ex) + int argc; + VALUE *argv; + int ex; +{ + VALUE self = Qself; + int i; + ID id; - return TRUE; - } + for (i=0; iptr); + } + rb_export_method(self, id, ex); } -#endif - return Fload(obj, fname); } -#ifndef RUBY_LIB -#define RUBY_LIB "/usr/local/lib/ruby:." -#endif - -#define RUBY_LIB_SEP ':' +static VALUE +mod_public(argc, argv) + int argc; + VALUE *argv; +{ + set_method_visibility(argc, argv, NOEX_PUBLIC); + return Qnil; +} -static void -addpath(path) - char *path; +static VALUE +mod_private(argc, argv) + int argc; + VALUE *argv; { - char *p, *s; + set_method_visibility(argc, argv, NOEX_PRIVATE); + return Qnil; +} - if (path == Qnil) return; +static VALUE +mod_modfunc(argc, argv, module) + int argc; + VALUE *argv; + VALUE module; +{ + int i; + ID id; + NODE *body, *old; - p = s = path; - while (*p) { - while (*p == RUBY_LIB_SEP) p++; - if (s = strchr(p, RUBY_LIB_SEP)) { - ary_push(rb_load_path, str_new(p, (int)(s-p))); - p = s + 1; + set_method_visibility(argc, argv, NOEX_PRIVATE); + for (i=0; iptr); } + body = search_method(module, id, 0); + if (body == 0 || body->nd_body == 0) { + Fail("undefined method `%s' for module `%s'", + rb_id2name(id), rb_class2name(module)); + } + rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC); } + return Qnil; } static VALUE -Fmod_include(argc, argv, module) +mod_include(argc, argv, module) int argc; VALUE *argv; struct RClass *module; @@ -2358,33 +2803,43 @@ Fmod_include(argc, argv, module) int i; for (i=0; iflags & SCOPE_MALLOCED) return; - if (!scope->local_tbl) return; + if (scope->flag == SCOPE_MALLOC) return; - tbl = scope->local_tbl; - scope->local_tbl = ALLOC_N(ID, tbl[0]+1); - MEMCPY(scope->local_tbl, tbl, ID, tbl[0]+1); - vars = scope->local_vars; - scope->local_vars = ALLOC_N(VALUE, tbl[0]); - MEMCPY(scope->local_vars, vars, VALUE, tbl[0]); - scope->flags |= SCOPE_MALLOCED; + if (scope->local_tbl) { + tbl = scope->local_tbl; + scope->local_tbl = ALLOC_N(ID, tbl[0]+1); + MEMCPY(scope->local_tbl, tbl, ID, tbl[0]+1); + vars = scope->local_vars; + scope->local_vars = ALLOC_N(VALUE, tbl[0]); + MEMCPY(scope->local_vars, vars, VALUE, tbl[0]); + scope->flag = SCOPE_MALLOC; + } } -VALUE C_Block; static ID blkdata; static void blk_mark(data) struct BLOCK *data; { - gc_mark_env(&data->env); + gc_mark_frame(&data->frame); gc_mark(data->scope); gc_mark(data->var); gc_mark(data->body); gc_mark(data->self); + gc_mark(data->d_vars); } static void blk_free(data) struct BLOCK *data; { - free(data->env.argv); + free(data->frame.argv); } static VALUE -Sblk_new(class) +proc_s_new(class) + VALUE class; { - VALUE blk; + VALUE proc; struct BLOCK *data; - struct SCOPE *scope; - if (!iterator_p() && !Fiterator_p()) { - Fail("tryed to create Block out of iterator"); + if (!iterator_p() && !f_iterator_p()) { + Fail("tryed to create Procedure-Object out of iterator"); } - if (the_block->block) return the_block->block; - blk = obj_alloc(class); + proc = obj_alloc(class); if (!blkdata) blkdata = rb_intern("blk"); - Make_Data_Struct(blk, blkdata, struct BLOCK, Qnil, blk_free, data); + Make_Data_Struct(proc, blkdata, struct BLOCK, blk_mark, blk_free, data); MEMCPY(data, the_block, struct BLOCK, 1); - data->env.argv = ALLOC_N(VALUE, data->env.argc); - MEMCPY(data->env.argv, the_block->env.argv, VALUE, data->env.argc); + data->frame.argv = ALLOC_N(VALUE, data->frame.argc); + MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc); scope_dup(data->scope); - the_block->block = blk; - return blk; + return proc; } VALUE -block_new() +f_lambda() { - return Sblk_new(C_Block); + return proc_s_new(cProc); } static VALUE -Fblk_call(blk, args) - VALUE blk, args; +proc_call(proc, args) + VALUE proc, args; { struct BLOCK *data; - VALUE result; + VALUE result = Qnil; int state; - switch (RARRAY(args)->len) { - case 0: - args = Qnil; - break; - case 1: - args = RARRAY(args)->ptr[0]; - break; + if (TYPE(args) == T_ARRAY) { + switch (RARRAY(args)->len) { + case 0: + args = 0; + break; + case 1: + args = RARRAY(args)->ptr[0]; + break; + } } - Get_Data_Struct(blk, blkdata, struct BLOCK, data); + Get_Data_Struct(proc, blkdata, struct BLOCK, data); /* PUSH BLOCK from data */ PUSH_BLOCK2(data); @@ -2525,18 +2991,14 @@ Fblk_call(blk, args) if (state == 0) { result = rb_yield(args); } - POP_TAG(); + POP_ITER(); POP_BLOCK(); switch (state) { case 0: break; - case TAG_RETRY: - case IN_BLOCK|TAG_RETRY: - Fail("retry from block-closure"); - break; case TAG_BREAK: case IN_BLOCK|TAG_BREAK: Fail("break from block-closure"); @@ -2552,11 +3014,14 @@ Fblk_call(blk, args) return result; } -Init_Block() +void +Init_Proc() { - C_Block = rb_define_class("Block", C_Object); + cProc = rb_define_class("Proc", cObject); - rb_define_single_method(C_Block, "new", Sblk_new, 0); + rb_define_singleton_method(cProc, "new", proc_s_new, 0); - rb_define_method(C_Block, "call", Fblk_call, -2); + rb_define_method(cProc, "call", proc_call, -2); + rb_define_private_method(cKernel, "lambda", f_lambda, 0); + rb_define_private_method(cKernel, "proc", f_lambda, 0); } -- cgit v1.2.3