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 --- parse.y | 963 ++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 574 insertions(+), 389 deletions(-) (limited to 'parse.y') diff --git a/parse.y b/parse.y index 9ea1fb1622..cdecb958bc 100644 --- a/parse.y +++ b/parse.y @@ -24,21 +24,27 @@ # undef const #endif -#include "ident.h" +#define ID_SCOPE_SHIFT 3 +#define ID_SCOPE_MASK 0x07 +#define ID_LOCAL 0x00 +#define ID_INSTANCE 0x01 +#define ID_GLOBAL 0x02 +#define ID_ATTRSET 0x03 +#define ID_CONST 0x04 + #define is_id_nonop(id) ((id)>LAST_TOKEN) #define is_local_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) #define is_global_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL) #define is_instance_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) #define is_attrset_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) #define is_const_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) -#define is_nthref_id(id) (((id)&ID_SCOPE_MASK)==ID_NTHREF) struct op_tbl { ID token; char *name; }; -NODE *eval_tree = Qnil; +NODE *eval_tree = 0; char *sourcefile; /* current source file */ int sourceline; /* current line no. */ @@ -49,16 +55,16 @@ static enum lex_state { EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_MID, /* newline significant, +/- is a sign. */ EXPR_END, /* newline significant, +/- is a operator. */ + EXPR_ARG, /* newline significant, +/- is a sign(meybe). */ EXPR_FNAME, /* ignore newline, +/- is a operator. */ } lex_state; static int class_nest = 0; static int in_single = 0; -static ID cur_mid = Qnil; +static ID cur_mid = 0; static int value_expr(); static NODE *cond(); -static NODE *cond2(); static NODE *block_append(); static NODE *list_append(); @@ -66,11 +72,13 @@ static NODE *list_concat(); static NODE *list_copy(); static NODE *expand_op(); static NODE *call_op(); +static int in_defined = 0; static NODE *gettable(); static NODE *asignable(); static NODE *aryset(); static NODE *attrset(); +static void backref_error(); static void local_push(); static void local_pop(); @@ -78,12 +86,17 @@ static int local_cnt(); static int local_id(); static ID *local_tbl(); +static struct RVarmap *dyna_push(); +static void dyna_pop(); +static int dyna_in_block(); + +VALUE dyna_var_ref(); +#define dyna_id(id) dyna_var_ref(id) + #define cref_push() NEW_CREF(0) static void cref_pop(); static NODE *cref_list; -struct global_entry* rb_global_entry(); - static void top_local_init(); static void top_local_setup(); %} @@ -93,6 +106,7 @@ static void top_local_setup(); VALUE val; ID id; int num; + struct RVarmap *vars; } %token CLASS @@ -100,7 +114,7 @@ static void top_local_setup(); DEF UNDEF BEGIN - RESQUE + RESCUE ENSURE END IF @@ -124,24 +138,27 @@ static void top_local_setup(); NIL AND OR + NOT _FILE_ _LINE_ IF_MOD WHILE_MOD ALIAS + DEFINED -%token IDENTIFIER GVAR IVAR CONSTANT NTH_REF +%token IDENTIFIER FID GVAR IVAR CONSTANT %token INTEGER FLOAT STRING XSTRING REGEXP -%token STRING2 XSTRING2 DREGEXP +%token STRING2 XSTRING2 DREGEXP NTH_REF BACK_REF %type singleton %type literal numeric %type compexpr exprs expr arg primary var_ref -%type if_tail opt_else case_body cases resque ensure +%type if_tail opt_else case_body cases rescue ensure %type call_args call_args0 args args2 opt_args -%type f_arglist f_args array assoc_list assocs assoc -%type mlhs mlhs_head mlhs_tail lhs iter_var opt_iter_var -%type superclass variable symbol +%type superclass f_arglist f_args f_optarg f_opt +%type array assoc_list assocs assoc undef_list +%type mlhs mlhs_head mlhs_tail lhs iter_var opt_iter_var backref +%type variable symbol operation %type cname fname op rest_arg %type f_arg %token UPLUS /* unary+ */ @@ -160,7 +177,10 @@ static void top_local_setup(); %token COLON2 /* :: */ %token OP_ASGN /* +=, -= etc. */ %token ASSOC /* => */ -%token LPAREN LBRACK LBRACE +%token LPAREN /* ( */ +%token LBRACK /* [ */ +%token LBRACE /* { */ +%token STAR /* * */ %token SYMBEG /* @@ -168,10 +188,9 @@ static void top_local_setup(); */ %left IF_MOD WHILE_MOD +%right NOT %left OR AND -%left YIELD RETURN FAIL %right '=' OP_ASGN -%right COLON2 %nonassoc DOT2 DOT3 %left OROP %left ANDOP @@ -184,6 +203,7 @@ static void top_local_setup(); %left '*' '/' '%' %right '!' '~' UPLUS UMINUS %right POW +%left COLON2 %token LAST_TOKEN @@ -246,24 +266,29 @@ expr : mlhs '=' args2 value_expr($2); $$ = NEW_YIELD($2); } - | IDENTIFIER call_args0 + | DEFINED {in_defined = 1;} arg + { + in_defined = 0; + $$ = NEW_DEFINED($3); + } + | operation call_args0 { $$ = NEW_FCALL($1, $2); } - | primary '.' IDENTIFIER call_args0 + | primary '.' operation call_args0 { value_expr($1); $$ = NEW_CALL($1, $3, $4); } | SUPER call_args0 { - if (!cur_mid && !in_single) + if (!cur_mid && !in_single && !in_defined) Error("super called outside of method"); $$ = NEW_SUPER($2); } - | UNDEF fname + | UNDEF undef_list { - $$ = NEW_UNDEF($2); + $$ = $2; } | ALIAS fname {lex_state = EXPR_FNAME;} fname { @@ -271,27 +296,41 @@ expr : mlhs '=' args2 } | expr IF_MOD expr { + value_expr($3); $$ = NEW_IF(cond($3), $1, Qnil); } | expr WHILE_MOD expr { - $$ = NEW_WHILE2(cond($3), $1); + value_expr($3); + if (nd_type($1) == NODE_BEGIN) { + $$ = NEW_WHILE2(cond($3), $1); + } + else { + $$ = NEW_WHILE(cond($3), $1); + } } | expr AND expr { + value_expr($1); $$ = NEW_AND(cond($1), cond($3)); } | expr OR expr { + value_expr($1); $$ = NEW_OR(cond($1), cond($3)); } + | NOT expr + { + value_expr($2); + $$ = NEW_NOT(cond($2)); + } | arg mlhs : mlhs_head { $$ = NEW_MASGN(NEW_LIST($1), Qnil); } - | mlhs_head '*' lhs + | mlhs_head STAR lhs { $$ = NEW_MASGN(NEW_LIST($1), $3); } @@ -299,7 +338,7 @@ mlhs : mlhs_head { $$ = NEW_MASGN(list_concat(NEW_LIST($1),$2),Qnil); } - | mlhs_head mlhs_tail comma '*' lhs + | mlhs_head mlhs_tail comma STAR lhs { $$ = NEW_MASGN(list_concat(NEW_LIST($1),$2),$5); } @@ -327,6 +366,11 @@ lhs : variable { $$ = attrset($1, $3, Qnil); } + | backref + { + backref_error($1); + $$ = Qnil; + } cname : IDENTIFIER { @@ -335,6 +379,7 @@ cname : IDENTIFIER | CONSTANT fname : IDENTIFIER + | FID | CONSTANT | op { @@ -342,8 +387,16 @@ fname : IDENTIFIER $$ = $1; } -op : COLON2 { $$ = COLON2; } - | DOT2 { $$ = DOT2; } +undef_list : fname + { + $$ = NEW_UNDEF($1); + } + | undef_list ',' fname + { + $$ = block_append($1, NEW_UNDEF($3)); + } + +op : DOT2 { $$ = DOT2; } | '|' { $$ = '|'; } | '^' { $$ = '^'; } | '&' { $$ = '&'; } @@ -359,6 +412,7 @@ op : COLON2 { $$ = COLON2; } | '+' { $$ = '+'; } | '-' { $$ = '-'; } | '*' { $$ = '*'; } + | STAR { $$ = '*'; } | '/' { $$ = '/'; } | '%' { $$ = '%'; } | POW { $$ = POW; } @@ -381,13 +435,20 @@ arg : variable '=' arg { $$ = attrset($1, $3, $5); } + | backref '=' arg + { + value_expr($3); + backref_error($1); + $$ = Qnil; + } | variable OP_ASGN arg { NODE *val; value_expr($3); if (is_local_id($1)) { - val = NEW_LVAR($1); + if (local_id($1)) val = NEW_LVAR($1); + else val = NEW_DVAR($1); } else if (is_global_id($1)) { val = NEW_GVAR($1); @@ -411,33 +472,22 @@ arg : variable '=' arg { $$ = NEW_OP_ASGN2($1, $4, $5); } + | backref OP_ASGN arg + { + backref_error($1); + $$ = Qnil; + } | arg DOT2 arg { - $$ = call_op($1, DOT2, 1, $3); + $$ = NEW_DOT2($1, $3); } | arg DOT3 arg { - $$ = NEW_DOT3(cond2($1), cond2($3)); + $$ = NEW_DOT3($1, $3); } | arg '+' arg { - $$ = Qnil; - if ($1 && $3 - && (nd_type($3) == NODE_LIT - || nd_type($3) == NODE_STR) - && nd_type($1) == NODE_CALL && $1->nd_mid == '+') { - if ($1->nd_args->nd_head == Qnil) - Bug("bad operand for `+'"); - if (nd_type($1->nd_args->nd_head) == NODE_LIT - || nd_type($1->nd_args->nd_head) == NODE_STR) { - $1->nd_args->nd_head = - expand_op($1->nd_args->nd_head, '+', $3); - $$ = $1; - } - } - if ($$ == Qnil) { - $$ = call_op($1, '+', 1, $3); - } + $$ = call_op($1, '+', 1, $3); } | arg '-' arg { @@ -517,20 +567,12 @@ arg : variable '=' arg } | '!' arg { + value_expr($2); $$ = NEW_NOT(cond($2)); } | '~' arg { - if ($2 - && (nd_type($2) == NODE_STR - || (nd_type($2) == NODE_LIT - && (TYPE($2->nd_lit) == T_REGEXP - || TYPE($2->nd_lit) == T_STRING)))) { - $$ = NEW_CALL($2, '~', Qnil); - } - else { - $$ = call_op($2, '~', 0); - } + $$ = call_op($2, '~', 0); } | arg LSHFT arg { @@ -540,16 +582,18 @@ arg : variable '=' arg { $$ = call_op($1, RSHFT, 1, $3); } - | arg COLON2 arg + | arg COLON2 cname { - $$ = call_op($1, COLON2, 1, $3); + $$ = NEW_COLON2($1, $3); } | arg ANDOP arg { + value_expr($1); $$ = NEW_AND(cond($1), cond($3)); } | arg OROP arg { + value_expr($1); $$ = NEW_OR(cond($1), cond($3)); } | primary @@ -562,10 +606,6 @@ call_args : /* none */ $$ = Qnil; } | call_args0 opt_nl - | '*' arg opt_nl - { - $$ = $2; - } call_args0 : args | assocs @@ -576,10 +616,19 @@ call_args0 : args { $$ = list_append($1, NEW_HASH($3)); } - | args comma '*' arg + | args comma assocs comma STAR arg + { + $$ = list_append($1, NEW_HASH($3)); + $$ = call_op($$, '+', 1, $6); + } + | args comma STAR arg { $$ = call_op($1, '+', 1, $4); } + | STAR arg + { + $$ = $2; + } opt_args : /* none */ { @@ -630,15 +679,16 @@ primary : literal | XSTRING2 | DREGEXP | var_ref + | backref | SUPER '(' call_args rparen { - if (!cur_mid && !in_single) + if (!cur_mid && !in_single && !in_defined) Error("super called outside of method"); $$ = NEW_SUPER($3); } | SUPER { - if (!cur_mid && !in_single) + if (!cur_mid && !in_single && !in_defined) Error("super called outside of method"); $$ = NEW_ZSUPER(); } @@ -710,25 +760,39 @@ primary : literal { $$ = NEW_YIELD(Qnil); } - | primary '{' opt_iter_var compexpr rbrace + | DEFINED '(' {in_defined = 1;} arg ')' + { + in_defined = 0; + $$ = NEW_DEFINED($4); + } + | primary '{' + { + $$ = dyna_push(); + } + opt_iter_var + compexpr rbrace { if (nd_type($1) == NODE_LVAR - || nd_type($1) == NODE_LVAR2 || nd_type($1) == NODE_CVAR) { $1 = NEW_FCALL($1->nd_vid, Qnil); } - $$ = NEW_ITER($3, $1, $4); + $$ = NEW_ITER($4, $1, $5); + dyna_pop($3); + } + | FID + { + $$ = NEW_FCALL($1, Qnil); } - | IDENTIFIER '(' call_args rparen + | operation '(' call_args rparen { $$ = NEW_FCALL($1, $3); } - | primary '.' IDENTIFIER '(' call_args rparen + | primary '.' operation '(' call_args rparen { value_expr($1); $$ = NEW_CALL($1, $3, $5); } - | primary '.' IDENTIFIER + | primary '.' operation { value_expr($1); $$ = NEW_CALL($1, $3, Qnil); @@ -738,10 +802,12 @@ primary : literal if_tail END { + value_expr($2); $$ = NEW_IF(cond($2), $4, $5); } | WHILE expr term compexpr END { + value_expr($2); $$ = NEW_WHILE(cond($2), $4); } | CASE compexpr @@ -751,29 +817,20 @@ primary : literal value_expr($2); $$ = NEW_CASE($2, $3); } - | FOR iter_var IN expr term - compexpr - END + | FOR iter_var IN expr term compexpr END { - value_expr($4); + value_expr($2); $$ = NEW_FOR($2, $4, $6); } | BEGIN compexpr - resque + rescue ensure END { - if ($3 == Qnil && $4 == Qnil) { - $$ = $2; - } - else { - $$ = NEW_BEGIN($2, $3, $4); - } + $$ = NEW_BEGIN($2, $3, $4); } - | LPAREN expr - opt_nl - rparen + | LPAREN exprs opt_nl rparen { $$ = $2; } @@ -823,13 +880,14 @@ primary : literal { $$ = NEW_DEFN($2, $4, $5, class_nest?0:1); local_pop(); - cur_mid = Qnil; + cur_mid = 0; } | DEF singleton '.' fname { value_expr($2); in_single++; local_push(); + lex_state = EXPR_END; /* force for args */ } f_arglist compexpr @@ -849,6 +907,7 @@ if_tail : opt_else compexpr if_tail { + value_expr($2); $$ = NEW_IF(cond($2), $4, $5); } @@ -864,7 +923,11 @@ opt_else : /* none */ iter_var : lhs | mlhs -opt_iter_var : '|' /* none */ '|' +opt_iter_var : /* node */ + { + $$ = Qnil; + } + | '|' /* none */ '|' { $$ = Qnil; } @@ -887,11 +950,11 @@ case_body : WHEN args then cases : opt_else | case_body -resque : /* none */ +rescue : /* none */ { $$ = Qnil; } - | RESQUE compexpr + | RESCUE compexpr { if ($2 == Qnil) $$ = (NODE*)1; @@ -926,7 +989,6 @@ variable : IDENTIFIER | IVAR | GVAR | CONSTANT - | NTH_REF | NIL { $$ = NIL; @@ -941,6 +1003,9 @@ var_ref : variable $$ = gettable($1); } +backref : NTH_REF + | BACK_REF + superclass : term { $$ = Qnil; @@ -949,7 +1014,7 @@ superclass : term { lex_state = EXPR_BEG; } - CONSTANT + expr term { $$ = $3; } @@ -958,36 +1023,47 @@ f_arglist : '(' f_args rparen { $$ = $2; } - | term + | f_args term { - $$ = NEW_ARGS(0, -1); + $$ = $1; } f_args : /* no arg */ { - $$ = NEW_ARGS(0, -1); + $$ = NEW_ARGS(0, 0, -1); } | f_arg { - $$ = NEW_ARGS($1, -1); + $$ = NEW_ARGS($1, 0, -1); } | f_arg comma rest_arg { - $$ = NEW_ARGS($1, $3); + $$ = NEW_ARGS($1, 0, $3); } - | rest_arg + | f_arg comma f_optarg { - $$ = NEW_ARGS(Qnil, $1); + $$ = NEW_ARGS($1, $3, -1); } - | f_arg error + | f_arg comma f_optarg comma rest_arg { - lex_state = EXPR_BEG; - $$ = NEW_ARGS($1, -1); + $$ = NEW_ARGS($1, $3, $5); + } + | f_optarg + { + $$ = NEW_ARGS(0, $1, -1); + } + | f_optarg comma rest_arg + { + $$ = NEW_ARGS(0, $1, $3); + } + | rest_arg + { + $$ = NEW_ARGS(0, 0, $1); } | error { lex_state = EXPR_BEG; - $$ = NEW_ARGS(0, -1); + $$ = NEW_ARGS(0, 0, -1); } f_arg : IDENTIFIER @@ -1005,7 +1081,23 @@ f_arg : IDENTIFIER $$ += 1; } -rest_arg : '*' IDENTIFIER +f_opt : IDENTIFIER '=' arg + { + if (!is_local_id($1)) + Error("formal argument must be local variable"); + $$ = asignable($1, $3); + } + +f_optarg : f_opt + { + $$ = NEW_BLOCK($1); + } + | f_optarg comma f_opt + { + $$ = block_append($1, $3); + } + +rest_arg : STAR IDENTIFIER { if (!is_local_id($2)) Error("rest argument must be local variable"); @@ -1025,7 +1117,7 @@ singleton : var_ref $$ = $1; } } - | LPAREN compexpr rparen + | LPAREN expr opt_nl rparen { switch (nd_type($2)) { case NODE_STR: @@ -1048,6 +1140,9 @@ assoc_list : /* none */ $$ = Qnil; } | assocs trailer + { + $$ = $1; + } | args trailer { if ($1->nd_alen%2 != 0) { @@ -1067,6 +1162,9 @@ assoc : arg ASSOC arg $$ = list_append(NEW_LIST($1), $3); } +operation : IDENTIFIER + | FID + opt_term : /* none */ | term @@ -1109,7 +1207,6 @@ VALUE newinteger(); char *strdup(); static NODE *var_extend(); -static void read_escape(); #define LEAVE_BS 1 @@ -1122,7 +1219,7 @@ lex_setsrc(src, ptr, len) char *ptr; int len; { - sourcefile = (char*)strdup(src); + sourcefile = strdup(src); sourceline = 1; lex_p = ptr; @@ -1151,7 +1248,7 @@ do { \ #define tokfix() (tokenbuf[tokidx]='\0') #define tok() tokenbuf #define toklen() tokidx -#define toknow() &toknbuf[tokidx] +#define toklast() (tokidx>0?tokenbuf[tokidx-1]:0) char * newtok() @@ -1178,6 +1275,88 @@ tokadd(c) tokenbuf[tokidx++] = c; } +static int +read_escape() +{ + int c; + + switch (c = nextc()) { + case '\\': /* Backslash */ + return c; + + case 'n': /* newline */ + return '\n'; + + case 't': /* horizontal tab */ + return '\t'; + + case 'r': /* carriage-return */ + return '\r'; + + case 'f': /* form-feed */ + return '\f'; + + case 'v': /* vertical tab */ + return '\13'; + + case 'a': /* alarm(bell) */ + return '\007'; + + case 'e': /* escape */ + return 033; + + case '0': case '1': case '2': case '3': /* octal constant */ + case '4': case '5': case '6': case '7': + pushback(); + SCAN_OCT(c); + return c; + + case 'x': /* hex constant */ + SCAN_HEX(c); + return c; + + case 'b': /* backspace */ + return '\b'; + + case 'M': + if ((c = nextc()) != '-') { + Error("Invalid escape character syntax"); + return '\0'; + } + if ((c = nextc()) == '\\') { + return read_escape() | 0x80; + } + else if (c == -1) goto eof; + else { + return ((c & 0xff) | 0x80); + } + + case 'C': + if ((c = nextc()) != '-') { + Error("Invalid escape character syntax"); + return '\0'; + } + case 'c': + case '^': + if ((c = nextc())== '\\') { + c = read_escape(); + } + else if (c == '?') + return 0177; + else if (c == -1) goto eof; + return c & 0x9f; + + eof: + case -1: + Error("Invalid escape character syntax"); + pushback(); + return '\0'; + + default: + return c; + } +} + static int parse_regx() { @@ -1188,7 +1367,7 @@ parse_regx() NODE *list = Qnil; newtok(); - while (c = nextc()) { + while ((c = nextc()) != -1) { switch (c) { case '[': in_brack = 1; @@ -1235,7 +1414,8 @@ parse_regx() /* fall through */ default: pushback(); - read_escape(LEAVE_BS); + tokadd('\\'); + tokadd(read_escape()); } continue; @@ -1247,6 +1427,7 @@ parse_regx() casefold = 1; } else { + casefold = 0; pushback(); } @@ -1263,7 +1444,7 @@ parse_regx() return DREGEXP; } else { - yylval.val = regexp_new(tok(), toklen(), casefold); + yylval.val = reg_new(tok(), toklen(), casefold); return REGEXP; } case -1: @@ -1279,6 +1460,8 @@ parse_regx() } tokadd(c); } + Error("unterminated regexp"); + return 0; } static int @@ -1287,7 +1470,6 @@ parse_string(term) { int c; NODE *list = Qnil; - ID id; int strstart; strstart = sourceline; @@ -1320,10 +1502,9 @@ parse_string(term) tokadd(c); } else { - int flags = 0; - if (term != '"') flags = LEAVE_BS; pushback(); - read_escape(flags); + if (term != '"') tokadd('\\'); + tokadd(read_escape()); } continue; } @@ -1369,6 +1550,7 @@ static struct kwtable { "class", CLASS, EXPR_BEG, "continue", CONTINUE, EXPR_END, "def", DEF, EXPR_FNAME, + "defined?", DEFINED, EXPR_END, "else", ELSE, EXPR_BEG, "elsif", ELSIF, EXPR_BEG, "end", END, EXPR_END, @@ -1379,9 +1561,10 @@ static struct kwtable { "in", IN, EXPR_BEG, "module", MODULE, EXPR_BEG, "nil", NIL, EXPR_END, + "not", NOT, EXPR_BEG, "or", OR, EXPR_BEG, "redo", REDO, EXPR_END, - "resque", RESQUE, EXPR_BEG, + "rescue", RESCUE, EXPR_BEG, "retry", RETRY, EXPR_END, "return", RETURN, EXPR_MID, "self", SELF, EXPR_END, @@ -1393,10 +1576,17 @@ static struct kwtable { "yield", YIELD, EXPR_END, }; +static void +arg_ambiguous() +{ + Warning("ambiguous first argument; make sure"); +} + static int yylex() { register int c; + int space_seen = 0; struct kwtable *low = kwtable, *mid, *high = LAST(kwtable); retry: @@ -1410,6 +1600,7 @@ retry: /* white spaces */ case ' ': case '\t': case '\f': case '\r': case '\13': /* '\v' */ + space_seen = 1; goto retry; case '#': /* it's a comment */ @@ -1424,14 +1615,15 @@ retry: /* fall through */ case '\n': sourceline++; - if (lex_state == EXPR_BEG || lex_state == EXPR_FNAME) + if (lex_state == EXPR_BEG + || lex_state == EXPR_FNAME) goto retry; lex_state = EXPR_BEG; return '\n'; case '*': - lex_state = EXPR_BEG; if ((c = nextc()) == '*') { + lex_state = EXPR_BEG; if (nextc() == '=') { yylval.id = POW; return OP_ASGN; @@ -1439,11 +1631,21 @@ retry: pushback(); return POW; } - else if (c == '=') { + if (c == '=') { yylval.id = '*'; + lex_state = EXPR_BEG; return OP_ASGN; } pushback(); + if (lex_state == EXPR_ARG && space_seen && !isspace(c)){ + arg_ambiguous(); + lex_state = EXPR_BEG; + return STAR; + } + if (lex_state == EXPR_BEG) { + return STAR; + } + lex_state = EXPR_BEG; return '*'; case '!': @@ -1558,9 +1760,7 @@ retry: case '?': if ((c = nextc()) == '\\') { - newtok(); - read_escape(0); - c = tok()[0]; + c = read_escape(); } c &= 0xff; yylval.val = INT2FIX(c); @@ -1592,21 +1792,27 @@ retry: return '|'; case '+': + c = nextc(); if (lex_state == EXPR_FNAME) { - if ((c = nextc()) == '@') { + if (c == '@') { return UPLUS; } pushback(); return '+'; } - c = nextc(); + if (lex_state == EXPR_ARG) { + if (!space_seen || c == '=' || isspace(c)) { + arg_ambiguous(); + lex_state = EXPR_END; + } + } if (lex_state != EXPR_END) { pushback(); if (isdigit(c)) { goto start_num; } lex_state = EXPR_BEG; - return UMINUS; + return UPLUS; } lex_state = EXPR_BEG; if (c == '=') { @@ -1617,21 +1823,28 @@ retry: return '+'; case '-': + c = nextc(); if (lex_state == EXPR_FNAME) { - if ((c = nextc()) == '@') { + if (c == '@') { return UMINUS; } pushback(); return '-'; } - c = nextc(); + if (lex_state == EXPR_ARG) { + if (!space_seen || c == '=' || isspace(c)) { + arg_ambiguous(); + lex_state = EXPR_END; + } + } if (lex_state != EXPR_END) { - pushback(); if (isdigit(c)) { + pushback(); c = '-'; goto start_num; } lex_state = EXPR_BEG; + pushback(); return UMINUS; } lex_state = EXPR_BEG; @@ -1774,16 +1987,25 @@ retry: return SYMBEG; case '/': - if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + if (lex_state == EXPR_BEG + || lex_state == EXPR_MID) { return parse_regx(); } + c = nextc(); + if (lex_state == EXPR_ARG) { + if (space_seen && c != '=' && !isspace(c)) { + pushback(); + arg_ambiguous(); + return parse_regx(); + } + } lex_state = EXPR_BEG; - if (nextc() == '=') { + if (c == '=') { yylval.id = '/'; return OP_ASGN; } pushback(); - return c; + return '/'; case '^': lex_state = EXPR_BEG; @@ -1795,6 +2017,9 @@ retry: return c; case ',': + lex_state = EXPR_BEG; + return c; + case ';': lex_state = EXPR_BEG; return c; @@ -1809,15 +2034,23 @@ retry: return c; case '(': - if (lex_state != EXPR_END) + if (lex_state == EXPR_BEG + || lex_state == EXPR_MID) { c = LPAREN; - lex_state = EXPR_BEG; + lex_state = EXPR_BEG; + } + else if (lex_state == EXPR_ARG && space_seen) { + arg_ambiguous(); + c = LPAREN; + lex_state = EXPR_BEG; + } + else { + lex_state = EXPR_BEG; + } return c; case '[': - if (lex_state == EXPR_BEG || lex_state == EXPR_MID) - c = LBRACK; - else if (lex_state == EXPR_FNAME) { + if (lex_state == EXPR_FNAME) { if ((c = nextc()) == ']') { if ((c = nextc()) == '=') { return ASET; @@ -1828,11 +2061,19 @@ retry: pushback(); return '['; } + else if (lex_state == EXPR_BEG + || lex_state == EXPR_MID) { + c = LBRACK; + } + else if (lex_state == EXPR_ARG && space_seen) { + arg_ambiguous(); + c = LBRACK; + } lex_state = EXPR_BEG; return c; case '{': - if (lex_state != EXPR_END) + if (lex_state != EXPR_END && lex_state != EXPR_ARG) c = LBRACE; lex_state = EXPR_BEG; return c; @@ -1841,6 +2082,7 @@ retry: c = nextc(); if (c == '\n') { sourceline++; + space_seen = 1; goto retry; /* skip \\n */ } pushback(); @@ -1860,6 +2102,9 @@ retry: newtok(); c = nextc(); switch (c) { + case '~': /* $~: match-data */ + local_cnt('~'); + /* fall through */ case '*': /* $*: argv */ case '$': /* $$: pid */ case '?': /* $?: last status */ @@ -1870,51 +2115,42 @@ retry: case ',': /* $,: output field separator */ case '.': /* $.: last read line number */ case '_': /* $_: last read line string */ - case '&': /* $&: last match */ - case '`': /* $&: string before last match */ - case '\'': /* $&: string after last match */ - case '+': /* $&: string matches last paren. */ - case '~': /* $~: match-data */ case '=': /* $=: ignorecase */ case ':': /* $:: load path */ case '<': /* $<: reading filename */ case '>': /* $>: default output handle */ - case '"': /* $": already loaded files */ + case '\"': /* $": already loaded files */ tokadd('$'); tokadd(c); tokfix(); yylval.id = rb_intern(tok()); return GVAR; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': + case '&': /* $&: last match */ + case '`': /* $`: string before last match */ + case '\'': /* $': string after last match */ + case '+': /* $+: string matches last paren. */ + yylval.node = NEW_BACK_REF(c); + return BACK_REF; + + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': while (isdigit(c)) { tokadd(c); c = nextc(); } pushback(); tokfix(); - { - ID id = atoi(tok()); - id <<= ID_SCOPE_SHIFT; - id |= ID_NTHREF; - yylval.id = id; - return NTH_REF; - } + yylval.node = NEW_NTH_REF(atoi(tok())); + return NTH_REF; - case '0': default: if (!is_identchar(c)) { pushback(); return '$'; } + case '0': tokadd('$'); } break; @@ -1947,7 +2183,12 @@ retry: } c = nextc(); } - pushback(); + if (c == '!' || c == '?') { + tokadd(c); + } + else { + pushback(); + } tokfix(); { @@ -1955,9 +2196,11 @@ retry: switch (tok()[0]) { case '$': + lex_state = EXPR_END; result = GVAR; break; case '@': + lex_state = EXPR_END; result = IVAR; break; default: @@ -1967,7 +2210,8 @@ retry: if (( c = strcmp(mid->name, tok())) == 0) { enum lex_state state = lex_state; lex_state = mid->state; - if (state != EXPR_BEG) { + if (state != EXPR_BEG + && state != EXPR_BEG) { if (mid->id == IF) return IF_MOD; if (mid->id == WHILE) return WHILE_MOD; } @@ -1982,6 +2226,7 @@ retry: } if (lex_state == EXPR_FNAME) { + lex_state = EXPR_END; if ((c = nextc()) == '=') { tokadd(c); } @@ -1989,14 +2234,21 @@ retry: pushback(); } } + else if (lex_state == EXPR_BEG){ + lex_state = EXPR_ARG; + } + else { + lex_state = EXPR_END; + } if (isupper(tok()[0])) { result = CONSTANT; } - else { + else if (toklast() == '!' || toklast() == '?') { + result = FID; + } else { result = IDENTIFIER; } } - lex_state = EXPR_END; yylval.id = rb_intern(tok()); return result; } @@ -2007,16 +2259,16 @@ var_extend(list, term) NODE *list; char term; { - int c, t; + int c, t, brace; VALUE ss; + NODE *node; ID id; c = nextc(); switch (c) { - default: - tokadd('#'); - pushback(); - return list; + case '$': + case '{': + break; case '@': t = nextc(); pushback(); @@ -2025,9 +2277,10 @@ var_extend(list, term) tokadd(c); return list; } - case '$': - case '{': - break; + default: + tokadd('#'); + pushback(); + return list; } ss = str_new(tok(), toklen()); @@ -2038,49 +2291,64 @@ var_extend(list, term) list_append(list, NEW_STR(ss)); } newtok(); - if (c == '{') { - while ((c = nextc()) != '}') { - if (c == -1) { - return (NODE*)-1; - } - if (isspace(c)) { - Error("Invalid variable name in string"); - break; - } - if (c == term) { - Error("Inmature variable name in string"); - pushback(); - return list; - } - tokadd(c); - } + if (c == '{') { + brace = 1; + c = nextc(); } else { + brace = 0; + } + + switch (c) { + case '$': + c = nextc(); + if (c == -1) return (NODE*)-1; switch (c) { - case '$': - tokadd(c); + case '&': + case '`': + case '\'': + case '+': + node = NEW_BACK_REF(c); c = nextc(); - if (c == -1) return (NODE*)-1; - if (!is_identchar(c)) { + goto append_node; + + case '~': + local_cnt('~'); + id = '~'; + goto id_node; + + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + while (isdigit(c)) { tokadd(c); - goto fetch_id; + c = nextc(); } - /* through */ - case '@': - tokadd(c); - c = nextc(); - break; + tokfix(); + node = NEW_NTH_REF(atoi(tok())); + goto append_node; } - while (is_identchar(c)) { + + tokadd('$'); + if (!is_identchar(c)) { tokadd(c); - if (ismbchar(c)) { - c = nextc(); - tokadd(c); - } + goto fetch_id; + } + /* through */ + case '@': + tokadd(c); + c = nextc(); + break; + } + while (is_identchar(c)) { + tokadd(c); + if (ismbchar(c)) { c = nextc(); + tokadd(c); } - pushback(); + c = nextc(); } + fetch_id: tokfix(); if (strcmp("__LINE__", tok()) == 0) @@ -2089,90 +2357,21 @@ var_extend(list, term) id = _FILE_; else id = rb_intern(tok()); - list_append(list, gettable(id)); + id_node: + node = gettable(id); + + append_node: + if (brace) { + if (c != '}') + Error("Invalid variable name in string"); + } + else pushback(); + + list_append(list, node); newtok(); return list; } -static void -read_escape(flag) - int flag; -{ - char c; - - switch (c = nextc()) { - case '\\': /* Backslash */ - tokadd('\\'); - break; - - case 'n': /* newline */ - tokadd('\n'); - break; - - case 't': /* horizontal tab */ - tokadd('\t'); - break; - - case 'r': /* carriage-return */ - tokadd('\r'); - break; - - case 'f': /* form-feed */ - tokadd('\f'); - break; - - case 'v': /* vertical tab */ - tokadd('\13'); - break; - - case 'a': /* alarm(bell) */ - tokadd('\007'); - break; - - case 'e': /* escape */ - tokadd(033); - break; - - case 'c': - if ((c = nextc()) == '?') - tokadd(0177); - else { - if (islower(c)) - c = toupper(c); - c = c - '@'; - tokadd(c); - } - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - { /* octal constant */ - pushback(); - SCAN_OCT(c); - tokadd(c); - } - break; - - case 'x': /* hex constant */ - { - SCAN_HEX(c); - tokadd(c); - } - break; - - case 'b': /* backspace */ - tokadd('\b'); - return; - - default: - if (flag & LEAVE_BS) { - tokadd('\\'); - } - case '#': - tokadd(c); - break; - } -} NODE* newnode(type, a0, a1, a2) @@ -2282,72 +2481,6 @@ list_concat(head, tail) return head; } -static NODE* -list_copy(list) - NODE *list; -{ - NODE *tmp; - - if (list == Qnil) return Qnil; - - tmp = Qnil; - while(list) { - tmp = list_append(tmp, list->nd_head); - list = list->nd_next; - } - return tmp; -} - -struct call_arg { - ID id; - VALUE recv; - int narg; - VALUE arg; -}; - -static VALUE -call_lit(arg) - struct call_arg *arg; -{ - return rb_funcall(arg->recv, arg->id, arg->narg, arg->arg); -} - -static VALUE -except_lit() -{ - extern VALUE errstr; - - Error("%s", RSTRING(errstr)->ptr); - return Qnil; -} - -static NODE * -expand_op(recv, id, arg) - NODE *recv, *arg; - ID id; -{ - struct call_arg arg_data; - VALUE val; - NODE *result; - - arg_data.recv = recv->nd_lit; - arg_data.id = id; - arg_data.narg = arg?1:0; - arg_data.arg = arg->nd_lit; - - val = rb_resque(call_lit, &arg_data, except_lit, Qnil); - if (TYPE(val) == T_STRING) { - result = NEW_STR(val); - } - else { - result = NEW_LIT(val); - } - - return result; -} - -#define NODE_IS_CONST(n) (nd_type(n) == NODE_LIT || nd_type(n) == NODE_STR) - static NODE * call_op(recv, id, narg, arg1) NODE *recv; @@ -2360,9 +2493,6 @@ call_op(recv, id, narg, arg1) value_expr(arg1); } - if (NODE_IS_CONST(recv) && (narg == 0 || NODE_IS_CONST(arg1))) { - return expand_op(recv, id, (narg == 1)?arg1:Qnil); - } return NEW_CALL(recv, id, narg==1?NEW_LIST(arg1):Qnil); } @@ -2385,10 +2515,10 @@ gettable(id) return NEW_STR(s); } else if (is_local_id(id)) { - if (local_id(id)) - return NEW_LVAR(id); - else - return NEW_LVAR2(id); + if (local_id(id)) return NEW_LVAR(id); + if (dyna_id(id)) return NEW_DVAR(id); + /* method call without arguments */ + return NEW_FCALL(id, Qnil); } else if (is_global_id(id)) { return NEW_GVAR(id); @@ -2399,9 +2529,8 @@ gettable(id) else if (is_const_id(id)) { return NEW_CVAR(id); } - else if (is_nthref_id(id)) { - return NEW_NTH_REF(id>>ID_SCOPE_SHIFT); - } + Bug("invalid id for gettable"); + return Qnil; } static NODE* @@ -2409,6 +2538,7 @@ asignable(id, val) ID id; NODE *val; { + extern VALUE dyna_var_asgn(); NODE *lhs = Qnil; if (id == SELF) { @@ -2421,7 +2551,12 @@ asignable(id, val) Error("Can't asign to special identifier"); } else if (is_local_id(id)) { - lhs = NEW_LASGN(id, val); + if (local_id(id) || !dyna_in_block()) + lhs = NEW_LASGN(id, val); + else{ + dyna_var_asgn(id, TRUE); + lhs = NEW_DASGN(id, val); + } } else if (is_global_id(id)) { lhs = NEW_GASGN(id, val); @@ -2434,9 +2569,6 @@ asignable(id, val) Error("class constant asigned in method body"); lhs = NEW_CASGN(id, val); } - else if (is_nthref_id(id)) { - Error("Can't set variable $%d", id>>ID_SCOPE_SHIFT); - } else { Bug("bad id for variable"); } @@ -2452,6 +2584,15 @@ aryset(recv, idx, val) return NEW_CALL(recv, ASET, list_append(idx, val)); } +ID +id_attrset(id) + ID id; +{ + id &= ~ID_SCOPE_MASK; + id |= ID_ATTRSET; + return id; +} + static NODE * attrset(recv, id, val) NODE *recv, *val; @@ -2460,12 +2601,26 @@ attrset(recv, id, val) value_expr(recv); value_expr(val); - id &= ~ID_SCOPE_MASK; + id &= ~ID_SCOPE_MASK; id |= ID_ATTRSET; return NEW_CALL(recv, id, NEW_LIST(val)); } +static void +backref_error(node) + NODE *node; +{ + switch (nd_type(node)) { + case NODE_NTH_REF: + Error("Can't set variable $%d", node->nd_nth); + break; + case NODE_BACK_REF: + Error("Can't set variable $%c", node->nd_nth); + break; + } +} + static int value_expr(node) NODE *node; @@ -2503,6 +2658,8 @@ value_expr(node) } } +static NODE *cond2(); + static NODE* cond0(node) NODE *node; @@ -2515,6 +2672,12 @@ cond0(node) else if (type == NODE_LIT && TYPE(node->nd_lit) == T_REGEXP) { return call_op(node,MATCH,1,NEW_GVAR(rb_intern("$_"))); } + else if (type == NODE_DOT2 || type == NODE_DOT3) { + node->nd_beg = cond2(node->nd_beg); + node->nd_end = cond2(node->nd_end); + if (type == NODE_DOT2) nd_set_type(node,NODE_FLIP2); + else if (type == NODE_DOT3) nd_set_type(node, NODE_FLIP3); + } return node; } @@ -2524,10 +2687,10 @@ cond(node) { enum node_type type = nd_type(node); - value_expr(node); switch (type) { case NODE_MASGN: case NODE_LASGN: + case NODE_DASGN: case NODE_GASGN: case NODE_IASGN: case NODE_CASGN: @@ -2561,6 +2724,7 @@ st_table *new_idhash(); static struct local_vars { ID *tbl; int cnt; + int dlev; struct local_vars *prev; } *lvtbl; @@ -2572,7 +2736,8 @@ local_push() local = ALLOC(struct local_vars); local->prev = lvtbl; local->cnt = 0; - local->tbl = Qnil; + local->tbl = 0; + local->dlev = 0; lvtbl = local; } @@ -2600,11 +2765,11 @@ local_cnt(id) if (id == 0) return lvtbl->cnt; - for (cnt=0, max=lvtbl->cnt; cnttbl[cnt+1] == id) return cnt; + for (cnt=1, max=lvtbl->cnt+1; cnttbl[cnt] == id) return cnt-1; } - if (lvtbl->tbl == Qnil) { + if (lvtbl->tbl == 0) { lvtbl->tbl = ALLOC_N(ID, 2); lvtbl->tbl[0] = 0; } @@ -2622,7 +2787,7 @@ local_id(id) { int i, max; - if (lvtbl == Qnil) return FALSE; + if (lvtbl == 0) return FALSE; for (i=1, max=lvtbl->cnt+1; itbl[i] == id) return TRUE; } @@ -2632,7 +2797,7 @@ local_id(id) static void top_local_init() { - if (lvtbl == Qnil) { + if (lvtbl == 0) { local_push(); } else if (the_scope->local_tbl) { @@ -2643,12 +2808,13 @@ top_local_init() } if (lvtbl->cnt > 0) { lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt+1); - MEMCPY(lvtbl->tbl, the_scope->local_tbl, ID, lvtbl->cnt); + MEMCPY(lvtbl->tbl, the_scope->local_tbl, ID, lvtbl->cnt+1); } else { - lvtbl->tbl = Qnil; + lvtbl->tbl = 0; } NEW_CREF0(); /* initialize constant c-ref */ + lvtbl->dlev = (the_dyna_vars?1:0); } static void @@ -2661,14 +2827,7 @@ top_local_setup() i = lvtbl->tbl[0]; if (i < len) { - if (the_scope->flags & SCOPE_MALLOCED) { - VALUE *vars = the_scope->local_vars; - - REALLOC_N(the_scope->local_vars, VALUE, len); - MEMZERO(the_scope->local_vars+i, VALUE, len-i); - free(the_scope->local_tbl); - } - else { + if (the_scope->flag == SCOPE_ALLOCA) { VALUE *vars = the_scope->local_vars; the_scope->local_vars = ALLOC_N(VALUE, len); if (vars) { @@ -2678,10 +2837,15 @@ top_local_setup() else { MEMZERO(the_scope->local_vars, VALUE, len); } + the_scope->flag = SCOPE_MALLOC; + } + else { + REALLOC_N(the_scope->local_vars, VALUE, len); + MEMZERO(the_scope->local_vars+i, VALUE, len-i); + free(the_scope->local_tbl); } lvtbl->tbl[0] = len; the_scope->local_tbl = lvtbl->tbl; - the_scope->flags |= SCOPE_MALLOCED; } else if (lvtbl->tbl) { free(lvtbl->tbl); @@ -2690,6 +2854,27 @@ top_local_setup() cref_list = Qnil; } +static struct RVarmap* +dyna_push() +{ + lvtbl->dlev++; + return the_dyna_vars; +} + +static void +dyna_pop(vars) + struct RVarmap* vars; +{ + lvtbl->dlev--; + the_dyna_vars = vars; +} + +static int +dyna_in_block() +{ + return (lvtbl->dlev > 0); +} + static void cref_pop() { @@ -2721,7 +2906,7 @@ yywhole_loop(chop, split) if (chop) { eval_tree = block_append(NEW_CALL(NEW_GVAR(rb_intern("$_")), - rb_intern("chop"), Qnil), eval_tree); + rb_intern("chop!"), Qnil), eval_tree); } eval_tree = NEW_WHILE(NEW_FCALL(rb_intern("gets"),0),eval_tree); } @@ -2808,14 +2993,14 @@ rb_intern(name) /* operator */ int i; - id = Qnil; + id = 0; for (i=0; rb_op_tbl[i].token; i++) { if (strcmp(rb_op_tbl[i].name, name) == 0) { id = rb_op_tbl[i].token; break; } } - if (id == Qnil) Bug("Unknown operator `%s'", name); + if (id == 0) Bug("Unknown operator `%s'", name); break; } @@ -2844,7 +3029,7 @@ rb_intern(name) static char *find_ok; -static +static int id_find(name, id1, id2) char *name; ID id1, id2; @@ -2860,7 +3045,7 @@ char * rb_id2name(id) ID id; { - find_ok = Qnil; + find_ok = 0; if (id < LAST_TOKEN) { int i = 0; @@ -2897,7 +3082,7 @@ const_check(id, val, class) VALUE val; struct RClass *class; { - if (is_const_id(id) && rb_const_bound(class, id)) { + if (is_const_id(id) && rb_const_defined(class, id)) { Warning("constant redefined for %s", rb_class2name(class)); return ST_STOP; } -- cgit v1.2.3