diff options
-rw-r--r-- | C-IF | 63 | ||||
-rw-r--r-- | ChangeLog | 314 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | Makefile.in | 27 | ||||
-rw-r--r-- | ToDo | 2 | ||||
-rw-r--r-- | array.c | 122 | ||||
-rw-r--r-- | bignum.c | 4 | ||||
-rw-r--r-- | class.c | 28 | ||||
-rw-r--r-- | compar.c | 48 | ||||
-rw-r--r-- | configure.in | 12 | ||||
-rw-r--r-- | dbm.c | 46 | ||||
-rw-r--r-- | defines.h | 2 | ||||
-rw-r--r-- | dict.c | 81 | ||||
-rw-r--r-- | dir.c | 21 | ||||
-rw-r--r-- | dln.c | 14 | ||||
-rw-r--r-- | dln.h | 4 | ||||
-rw-r--r-- | enum.c | 2 | ||||
-rw-r--r-- | env.h | 13 | ||||
-rw-r--r-- | error.c | 9 | ||||
-rw-r--r-- | etc.c | 20 | ||||
-rw-r--r-- | eval.c | 881 | ||||
-rw-r--r-- | file.c | 219 | ||||
-rw-r--r-- | fnmatch.c | 189 | ||||
-rw-r--r-- | fnmatch.h | 36 | ||||
-rw-r--r-- | gc.c | 23 | ||||
-rw-r--r-- | glob.c | 177 | ||||
-rw-r--r-- | gnuglob.c | 572 | ||||
-rw-r--r-- | ident.h | 4 | ||||
-rw-r--r-- | inits.c | 3 | ||||
-rw-r--r-- | io.c | 180 | ||||
-rw-r--r-- | io.h | 10 | ||||
-rw-r--r-- | main.c | 17 | ||||
-rw-r--r-- | math.c | 20 | ||||
-rw-r--r-- | methods.c | 152 | ||||
-rw-r--r-- | methods.h | 6 | ||||
-rw-r--r-- | missing.c | 2 | ||||
-rw-r--r-- | missing/strstr.c | 2 | ||||
-rw-r--r-- | node.h | 20 | ||||
-rw-r--r-- | numeric.c | 163 | ||||
-rw-r--r-- | object.c | 53 | ||||
-rw-r--r-- | pack.c | 11 | ||||
-rw-r--r-- | parse.y | 1341 | ||||
-rw-r--r-- | process.c | 100 | ||||
-rw-r--r-- | random.c | 2 | ||||
-rw-r--r-- | range.c | 60 | ||||
-rw-r--r-- | re.c | 11 | ||||
-rw-r--r-- | re.h | 4 | ||||
-rw-r--r-- | ruby.1 | 121 | ||||
-rw-r--r-- | ruby.c | 161 | ||||
-rw-r--r-- | ruby.h | 17 | ||||
-rw-r--r-- | sample/biorhythm.rb | 4 | ||||
-rw-r--r-- | sample/cat2.rb | 4 | ||||
-rw-r--r-- | sample/getopts.rb | 2 | ||||
-rw-r--r-- | sample/io.rb | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | sample/newver.rb (renamed from newver.rb) | 7 | ||||
-rw-r--r-- | sample/rcs.rb | 10 | ||||
-rw-r--r-- | sample/ruby-mode.el | 139 | ||||
-rw-r--r-- | sample/sieve.rb | 16 | ||||
-rw-r--r-- | sample/t2.rb | 7 | ||||
-rw-r--r-- | sample/trojan.rb | 12 | ||||
-rw-r--r-- | sample/tt.rb | 19 | ||||
-rw-r--r-- | socket.c | 25 | ||||
-rw-r--r-- | spec | 1459 | ||||
-rw-r--r-- | sprintf.c | 8 | ||||
-rw-r--r-- | st.c | 2 | ||||
-rw-r--r-- | string.c | 189 | ||||
-rw-r--r-- | struct.c | 2 | ||||
-rw-r--r-- | time.c | 10 | ||||
-rw-r--r-- | variable.c | 13 | ||||
-rw-r--r-- | version.c | 12 | ||||
-rw-r--r-- | version.h | 4 |
71 files changed, 4887 insertions, 2454 deletions
@@ -21,8 +21,19 @@ Ruby-C インターフェース 変数: 現在のselfオブジェクトの値. 一般にメソッドにはselfを指す引数 が与えられるので, この変数にアクセスする必要はない. この変数の値を - 変更する時は以後のselfの値そのものが変わってしまうので, 慎重に行な - うこと. + 変更する時は以後のselfの値そのものが変わってしまうので, 特別な事情 + がない限り代入してはならない. + + 注意: ヘッダファイル"env.h"をインクルードしていないファイルでは, + Qselfは定数であり, 代入は文法エラーとなる. + + TRUE + + 定数: tオブジェクト(真のデフォルト値) + + FALSE + + 定数: nilオブジェクト クラス・モジュール定義 @@ -54,8 +65,8 @@ Ruby-C インターフェース void rb_global_variable(VALUE *var) - GCにRubyからはアクセスされないが, Rubyオブジェクトを含む大域変数を - マークする. + GCのためRubyからはアクセスされないが, Rubyオブジェクトを含む大域変 + 数をマークする. void rb_read_only_hook() @@ -72,9 +83,10 @@ Ruby-C インターフェース rb_define_method(VALUE class, char *name, VALUE (*func)(), int argc) - メソッドを定義する. argcはselfを除く引数の数. argcが-1の時, 引数は - argc, argv形式で与えられる. argcが-2の時, 引数はself, args(argsは - 引数を含むrubyの配列)という形式で与えられる. + メソッドを定義する. argcはselfを除く引数の数. argcが-1の時, 関数に + は引数の数(selfを含まない)を第1引数, 引数の配列を第2引数とする形式 + で与えられる. argcが-2の時, 引数はself, args(argsは引数を含むrubyの + 配列)という形式で与えられる. rb_define_single_method(VALUE class, char *name, VALUE (*func)(), int argc) @@ -83,10 +95,10 @@ Ruby-C インターフェース rb_scan_args(VALUE args, char *fmt, ...) args形式で与えられた引数を分解する. fmtは必須引数の数, 付加引数の数, - 残りの引数があるかを指定する文字列で, "数字数字*"という形式である. - 2 番目の数字と"*"は省略可能である. 第3引数以降は変数へのポインタで, - 該当する要素がその変数に格納される. 付加引数が与えられない場合は変 - 数に Qnilが代入される. + 残りの引数があるかを指定する文字列で, "数字数字*"という形式である. + 2 番目の数字と"*"はそれぞれ省略可能である. 第3引数以降は変数へのポ + インタで, 該当する要素がその変数に格納される. 付加引数に対応する引 + 数が与えられていない場合は変数にQnilが代入される. Rubyメソッド呼び出し @@ -109,6 +121,11 @@ Rubyメソッド呼び出し IDに対応する文字列を返す(デバッグ用). + char *rb_class2name(VALUE class) + + classの名前を返す(デバッグ用). classが名前を持たない時には, 一番近 + い名前を持つクラスの名前を返す. + インスタンス変数 VALUE rb_iv_get(VALUE obj, char *name) @@ -125,8 +142,8 @@ Rubyメソッド呼び出し VALUE rb_iterate(VALUE (*func1)(), char *arg1, VALUE (*func2)(), char *arg2) func2をブロックとして設定し, func1をイテレータとして呼ぶ. func1に - は arg1が引数として渡され, func2には第1引数にイテレータとして与えら - れた値, 第2引数にarg2が渡される. + は arg1が引数として渡され, func2には第1引数にイテレータから与えられ + た値, 第2引数にarg2が渡される. VALUE rb_yield(VALUE val) @@ -142,10 +159,14 @@ Rubyメソッド呼び出し 関数func1をarg1を引数として実行し, 実行終了後(たとえ例外が発生して も) func2をarg2を引数として実行する. 戻り値はfunc1の戻り値である(例 - 外が発生した時はnil). + 外が発生した時は戻らない). 例外・エラー + void Warning(char *fmt, ...) + + 標準エラー出力に警告情報を表示する. 引数はprintf()と同じ. + void Fail(char *fmt, ...) 例外を発生させる. 引数はprintf()と同じ. @@ -161,6 +182,20 @@ Rubyメソッド呼び出し 呼ぶ. インタープリタはコアダンプし直ちに終了する. 例外処理は一切行 なわれない. +rubyの初期化・実行 + + void ruby_init(int argc, char **argv, char **envp) + + rubyインタプリタの初期化を行なう. + + void ruby_run() + + rubyインタプリタを実行する. + + void ruby_script(char *name) + + rubyのスクリプト名($0)を設定する. + /* * Local variables: * fill-column: 70 @@ -1,3 +1,286 @@ +Thu Oct 13 12:13:48 1994 Yukihiro Matsumoto (matz@ix-02) + + * eval.c(SETUP_ARGS): 付加演算子が配列でない時には配列に変換する. + + * parse.y: 括弧なしのメソッド呼び出しでも`*'による付加引数が使える + ようにした. ただし, 通常引数が一つもない場合は乗算演算子と区別が + つかないので, 必ず括弧が必要. + +Wed Oct 12 10:09:07 1994 Yukihiro Matsumoto (matz@ix-02) + + * eval.c(rb_call): キャッシュの計算をinline化. キャッシュミスがあ + れば関数呼び出しでメソッドを検索する. methods.cはなくなった. + + * eval.c(rb_eval): ローカル変数用の領域をalloca()するように変更. + サイズの変更が必要になれば改めてmalloc()するように. + + * parse.y: error recoveryの際にlex_stateを更新しておくように. + +Tue Oct 11 17:10:46 1994 Yukihiro Matsumoto (matz@ix-02) + + * socket.c(for_fd): ファイル記述子(Fixnum)からソケットインスタンス + を得るメソッド. たとえばinetdから起動されたサーバで標準入出力に + ソケット操作を行なうために使う. つまりSocket.for_fd($stdin)で標 + 準入力に対応するソケットオブジェクトが得られる. + + * io.c(to_i): IOクラスのインスタンスを整数に変換するとそのファイル + 記述子を返すように. + + * numeric.c(num2int): to_iメソッドを使って, できる限り整数に変換す + る. 以前はnum2fixだけが全てのオブジェクトに対してto_iメソッドを + 適用していた. + + * sprintf.c(Fsprintf): 整数表示の際, オブジェクトをできる限り整数 + に変換するように(to_iメソッドを使う). + +Fri Oct 7 14:06:32 1994 Yukihiro Matsumoto (matz@ix-02) + + * eval.c(Fcaller): 必要性がよく分からないのでドキュメントから削除. + 将来デバッガを作る時に復活させよう. + + * eval.c(rb_call): Cで記述されたメソッド呼び出しでは環境をスタック + にセーブしないことによって高速化. + +Wed Oct 5 15:00:58 1994 Yukihiro Matsumoto (matz@ix-02) + + * ruby.h: 一時env.hに移動してたQselfの定義を復活. ただし今回は関数 + として実現(env.hでは変数として再定義してある). + + * ruby.h: TRUEでsyntax errorにならないよう#undefを追加. + + * eval.c(rb_eval): thread化に挑戦したが, 失敗(速くならなかった). + が, Scopingなどの無駄なコードの削除とメソッド呼び出しの引数セッ + トのinline化で若干の高速化を実現した. 副作用として, argc, argv形 + 式の関数呼び出しの仕様が変化した(argvにselfを含まなくなった). + + * eval.c(rb_call): メソッド呼び出しの高速化. + +Tue Oct 4 11:40:53 1994 Yukihiro Matsumoto (matz@ix-02) + + * ruby-mode.el: 修飾子に対応した. + + * parse.y: 多重代入にrestをつけた. この機能を使えばoptional引数の + 解析が簡単にできる(はず). + + * pack.c(unpack): uuencode形式のdecodeの際に文字列の長さが間違って + いた. + +Mon Oct 3 15:58:41 1994 Yukihiro Matsumoto (matz@ix-02) + + * file.c(type): ファイルタイプを文字列で返すメソッド. + +Fri Sep 30 11:36:07 1994 Yukihiro Matsumoto (matz@ix-02) + + * object.c: デフォルトの真の値である%TRUEの値を1(Fixnum)からtに変 + 更した. to_sで文字列に変換した時にも`t'と表示される. 更に踏み込 + んで`t'を予約語にしてlispのようにしようかとも思ったが, そこまで + は決心できなかった. 一文字のローカル変数はかなり使いそうな気がす + るので…. + + * array.c,dict.c: equalを再定義しているクラスで, hashを正しく定義 + した. + +Wed Sep 28 23:30:28 1994 Yukihiro Matsumoto (matz@dyna) + + * eval.c(Ffail): 今までfailはカーネルクラスのメソッドであったが, + 構文に組み込んだ. この変更によって, 1)`fail'は予約語となり, ロー + カル変数に用いることができなくなった. 2)`fail'単体で例外を発生す + るようになった. 3)failはメソッドではなくなったので再定義される可 + 能性がなくなった. + + * dic.c, dbm.c(indexes): Arrayのindexesと同様の機能を持つメソッド + を追加. + + * array.c(indexes): 引数をインデックスとする要素の配列を返す. 整数 + の配列を引数とする時には引数の要素をインデックスとする要素の配列 + を返す. + +Mon Sep 19 13:42:31 1994 Yukihiro Matsumoto (matz@ix-02) + + * array.c(aset): 部分配列に対する代入で配列以外のオブジェクトが指 + 定された場合に多重代入と同じルールで配列化するようにした. + + * io.c(print): 引数として与えられた各オブジェクトにprint_onメッセー + ジを与えるように. 実行速度は落ちるが柔軟性は増す. + +Fri Sep 16 14:59:18 1994 Yukihiro Matsumoto (matz@ix-02) + + * glob.c: ワイルドカードの導入. bashに使われているGNUのglobルーチ + ンを流用した. + +Mon Sep 12 18:36:58 1994 Yukihiro Matsumoto (matz@ix-02) + + * parse.y(value_expr): 式がnilの時に対応. + + * class.c: ICLASSのclassが必ずClass/Moduleを指すように. + +Tue Sep 6 16:23:28 1994 Yukihiro Matsumoto (matz@ix-02) + + * re.c: 正規表現内で「\数字」形式が指定できるように. + + * parse.y:「do expr using var ... end」形式はなくなった. 寂しい気 + もする. *BACKWARD INCOMPATIBILITY* + +Mon Sep 5 10:59:01 1994 Yukihiro Matsumoto (matz@ix-02) + + * numeric.c(next): Numericクラスにもnextを提供. + + * string.c(upto): uptoを提供. + + * range.c(each): nextを使ったインタフェースからuptoを使うように変 + 更した. この方が一つのメソッドで処理をまとめで行なうことができる. + +Fri Sep 2 15:25:39 1994 Yukihiro Matsumoto (matz@ix-02) + + * dict.c(each): 戻り値を[key, value]のペアに変更. 今までのeachは + each_valueとして残る. *BACKWARD INCOMPATIBILITY* + +Thu Sep 1 10:49:04 1994 Yukihiro Matsumoto (matz@ix-02) + + * 成功した(特別な戻り値を持たない)システムコールは`0'を返すように. + +Wed Aug 31 00:26:51 1994 Yukihiro Matsumoto (matz@dyna) + + * string.c: チェックサムを得るメソッド`sum'を作った. + + * class.c(include_class_new): ICLASSのclassをもとのクラスにした. + gcの際に元クラスをマークする必要があるのが, フィールドを増やす余 + 地が無いので, classフィールドを流用した. 私の見積りが間違ってい + て, ICLASSのインスタンスにメッセージを送る事があれば, おかしな動 + 作をするだろう. + + * eval.c(masign): 式(a,b = nil)の値を[nil]からnilに変更した. + +Mon Aug 29 11:56:09 1994 Yukihiro Matsumoto (matz@ix-02) + + * class.c: rb_define_mfuncを無くして, メタクラスにモジュールをイン + クルードするようにした. + + * error.c(yyerror): 同じ行で複数のsyntax errorをリポートしないよう + にした. + + * file.c: FileTestモジュールにファイルテストメソッドを分離した. + + * parse.y: 演算子を指定する時のlex_stateを正しく設定した. + +Sat Aug 27 01:23:34 1994 Yukihiro Matsumoto (matz@dyna) + + * parse.y: if/whileなどの複合式をprimaryに移動した. これによって例 + えば「if cond then a else b end.message()」のような式が書けるよ + うになった. + +Fri Aug 26 10:46:30 1994 Yukihiro Matsumoto (matz@ix-02) + + * spec: 整理された文法にしたがって書き直した. + + * parse.y: ここ数日で混乱していた文法を整理した. 括弧を省略したメ + ソッド呼び出しができるようになったこと, modifierが付けられるよう + になったこと, returnにリストが渡せるようになったことが主な変更点 + である. + + * process周りが怪しいがとにかくSolaris 2.3で動くように. + + * parse.y: 曖昧性がない場合にはメソッド呼び出しの引数の括弧を省略 + できるように. 省略できるメソッド呼び出しの条件は, 1)かならず1個 + 以上の引数を必要とすること, 2)第1引数が`+', `-', `(', `[', `{', + `/'など, 式の始まりに置かれた時と途中に現れた時とで解釈が違う記 + 号で始まらないこと, である. + +Thu Aug 25 13:54:58 1994 Yukihiro Matsumoto (matz@ix-02) + + * parse.y(cond): 条件式の展開部にbugがあった. + +Wed Aug 24 00:01:15 1994 Yukihiro Matsumoto (matz@dyna) + + * parse.y: returnはコンマで区切ったリストも受け取るように. つまり, + return a, b, cはreturn [a, b, c]と同じ意味になる. + + * parse.y: yield以外の大域脱出制御式をexprからexpr0に移した. よっ + てメソッドの引数に制御式を使えなくなる(これで困る人はいないはず). + + * parse.y: `+'の定数展開の際に演算子の優先順位を忘れていた. + + * eval.c: untilの戻り値はnilになった. + + * parse.y: modifierとしてのif/unless/while/untilを追加. + + * parse.y: 文法からendの後ろにつけるキーワードを削除. ほとんど使わ + なかった上に, emacsではruby-modeがあれば対応のチェックが機械的に + 出来るため. + +Tue Aug 23 18:08:33 1994 Yukihiro Matsumoto (matz@ix-02) + + * eval.c: スクリプト実行開始前に例外が発生した時にcore dumpした. + 組み込み用にコードを変更した時にenbugしてしまった. + +Tue Aug 23 00:07:17 1994 Yukihiro Matsumoto (matz@dyna) + + * eval.c: doの戻り値がいつもnilになっていた. + + * parse.y: loop制御変数の多重代入化にbugがあった. + + * parse.y(expand_op): 文字列も畳み込みの対象に. + +Mon Aug 22 10:50:01 1994 Yukihiro Matsumoto (matz@ix-02) + + * parse.y(expand_op): `+'に関しては結合則を使って, より多く定数畳 + み込みを行なうように. + + * ruby.c(proc_options): argcが0の時にも対応. + + * parse.y: forなどの制御変数に多重代入も使えるように. + +Sat Aug 20 00:59:40 1994 Yukihiro Matsumoto (matz@dyna) + + * parse.y(call_op): 演算子`~'の取り扱いをルール部へ移動. + +Fri Aug 19 11:44:13 1994 Yukihiro Matsumoto (matz@ix-02) + + * main.c: rubyをほかのプログラムに組み込めるようにmain()を分割した. + それにともない, プログラムの呼び出し構造を修正した. + + * parse.y: 条件式の定義を変更. ifなどの条件式の中でだけ`&&'や`||' + および`!'の引数が条件式になるように. この変更により条件式以外の + 場所での `&&', `||', `!'演算子の動作が直観に一致する. + + * parse.y: 実引数の`*'の後に続く引数はexprに制限した. 今までは全て + の文が有効であったが, ここで定義文があってもしょうがない. + +Thu Aug 18 10:21:45 1994 Yukihiro Matsumoto (matz@ix-02) + + * re.c: 正規表現ルーチンの初期化部分を削除してしまっていた. これで + はemacsの正規表現になってしまう. + + * version.c: copyright表示を追加. + + * version.c: バージョン表示をstderrに. + + * configure.in: gccがない場合testに失敗していた. + +Fri Aug 12 14:12:23 1994 Yukihiro Matsumoto (matz@ix-02) + + * array.c(astore): 配列の拡大する時にある程度の大きさをまとめて拡 + 大するように. + + * io.c(Fprint): 配列に対しては一度文字列に変換することなく, 直接内 + 容を出力するように. + + * string.c(str_new): memmoveからmemcpyへ置き換えた. これでもかなり + 速度が違う. + + * ruby.h: データメンバの取り出しで名前を文字列からIDで指定するよう + にした. かなりの高速化になる. + + * io.c: $ARGFという変数で引数列からなる仮想ファイルをオブジェクト + として扱えるようにした. 今まではトップレベルのgets()などを使って + アクセスしていたが, どうもオブジェクト指向的ではなかった. + +Thu Aug 11 11:43:15 1994 Yukihiro Matsumoto (matz@ix-02) + + * gc.c: mark_location()の間違った呼び出し方の行が残っていた. + + * method.c: プロトタイプ宣言が足りなかった. + Wed Aug 10 15:54:46 1994 Yukihiro Matsumoto (matz@ix-02) * variable.c: -vオプションが指定されている時は初期化されていない, @@ -15,7 +298,7 @@ Tue Aug 9 11:50:48 1994 Yukihiro Matsumoto (matz@ix-02) * array.c(Fary_aref): 引数が1つでFixnumの時, Range checkを行なわな いように修正. - * eval.c: 引数の数をコンパイル時に計算して若干の高速化. + * eval.c: メソッドの引数の数をコンパイル時に計算して若干の高速化. Mon Aug 8 13:06:24 1994 Yukihiro Matsumoto (matz@ix-02) @@ -105,23 +388,6 @@ Mon Jul 18 10:19:15 1994 Yukihiro Matsumoto (matz@ix-02) * dbm.c, dict.c(clear): メソッド追加. -Mon Jul 18 10:19:15 1994 Yukihiro Matsumoto (matz@ix-02) - - * parse.y: 多重代入を処理するルールにバグがあって, 3要素以上の多重 - 代入に失敗していた. - - * eval.c(rb_eval): 多重代入で, 右辺が配列でない時には`to_a'メソッ - ドで配列に変換して代入するようにした. 今までの仕様だと右辺値が第 - 1要素にそのまま代入されていたが, structなど配列に変換できるもの - は変換した方が嬉しい気がする. - - * dbm.c,dict.c(delete_if): メソッド追加. - - * process.c(wait,waitpid): システムコールwaitpidまたはwait4がある - 時はそちらを使うように. configureもそれらをチェックするように変更. - - * dbm.c, dict.c(clear): メソッド追加. - Fri Jul 15 10:54:45 1994 Yukihiro Matsumoto (matz@ix-02) * array.c(Fary_fill,Fary_clear): メソッドを追加. @@ -141,10 +407,6 @@ Fri Jul 15 10:54:45 1994 Yukihiro Matsumoto (matz@ix-02) Thu Jul 14 11:18:07 1994 Yukihiro Matsumoto (matz@ix-02) - * eval.c: メソッドが存在しない時にはKernel:_undefined(id)が呼ばれ - るように. しかし, rubyでは個々のメソッド毎の処理よりも, クラス - 単位の処理が必要な気もするなあ. - * autoexec.c: 削除. autoload関係の機能は今後検討しよう. * dict.c: 辞書クラスの正式名称をDictに変更した. 別名としてHashを用 @@ -408,8 +670,8 @@ Wed Jun 15 10:18:27 1994 Yukihiro Matsumoto (matz@ix-02) Tue Jun 14 16:08:42 1994 Yukihiro Matsumoto (matz@ix-02) - * gc.c: Bignumを追加するのを忘れていた. 組み込み型を追加した時には - 必ずmark()とsweep()にその型に関する処理を追加する必要がある. + * gc.c: Bignum型を追加するのを忘れていた. 組み込み型を追加した時に + は必ずmark()とsweep()にその型に関する処理を追加する必要がある. * bignum: 割算も動いたような気がする. アルゴリズムを理解していない ので, 自信がない. @@ -422,7 +684,7 @@ Mon Jun 13 14:36:55 1994 Yukihiro Matsumoto (matz@ix-02) Fri Jun 10 17:26:42 1994 Yukihiro Matsumoto (matz@ix-02) * Comparable: 基礎となるメソッドを`=='と`>'から`<=>'に変更した. 今 - 後Comparableのサブクラスは`<=>'だけを定義する必要がある. + 後Comparableのサブクラスは`<=>'だけを再定義する必要がある. Wed Jun 8 13:12:18 1994 Yukihiro Matsumoto (matz@ix-02) @@ -569,7 +831,7 @@ Mon May 30 10:07:42 1994 Yukihiro Matsumoto (matz@ix-02) は混乱を避けることができると思う. * autoconfを使って, 自動的にMakefile, config.hを生成するようにした. - これで, 大抵のマシンでは`configure'を実行した後, `make'一発でコ + これで, 多くのマシンでは`configure'を実行した後, `make'一発でコ ンパイルできると思う. * clone: サブクラスに対して用いられた場合, 元のオブジェクトと同じ diff --git a/Makefile b/Makefile deleted file mode 100644 index 0908d49776..0000000000 --- a/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile - -# -# created at: Wed Aug 10 15:21:29 JST 1994 - -all:; @echo "You must run configure first." diff --git a/Makefile.in b/Makefile.in index 66b3689260..7cb2829dce 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,11 +53,14 @@ SRCS = array.c \ etc.c \ eval.c \ file.c \ + fnmatch.c \ gc.c \ + glob.c \ + gnuglob.c \ inits.c \ io.c \ + main.c \ math.c \ - methods.c \ missing.c \ numeric.c \ object.c \ @@ -91,11 +94,14 @@ OBJS = array.o \ etc.o \ eval.o \ file.o \ + fnmatch.o \ gc.o \ + glob.o \ + gnuglob.o \ inits.o \ io.o \ + main.o \ math.o \ - methods.o \ missing.o \ numeric.o \ object.o \ @@ -128,9 +134,11 @@ $(PROGRAM): $(OBJS) @rm -f $(PROGRAM) $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) -install: $(PROGMAM) +$(bindir)/$(PROGRAM): $(PROGRAM) $(INSTALL_PROGRAM) $(PROGRAM) $(bindir)/$(PROGRAM) +install: $(bindir)/$(PROGRAM) + clean:; @rm -f $(OBJS) realclean:; @rm -f $(OBJS) @@ -142,7 +150,7 @@ dbm.o:dbm.c # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: ### -parse.o : parse.y ruby.h defines.h env.h ident.h node.h st.h regex.h +parse.o : parse.y ruby.h defines.h env.h node.h st.h ident.h regex.h ### array.o : array.c ruby.h defines.h bignum.o : bignum.c ruby.h defines.h @@ -155,24 +163,27 @@ dln.o : dln.c defines.h dln.h enum.o : enum.c ruby.h defines.h error.o : error.c ruby.h defines.h env.h etc.o : etc.c ruby.h defines.h -eval.o : eval.c ruby.h defines.h env.h node.h ident.h st.h +eval.o : eval.c ruby.h defines.h ident.h env.h node.h methods.h st.h file.o : file.c ruby.h defines.h io.h +fnmatch.o : fnmatch.c fnmatch.h gc.o : gc.c ruby.h defines.h env.h st.h +glob.o : glob.c ruby.h defines.h fnmatch.h +gnuglob.o : gnuglob.c fnmatch.h inits.o : inits.c ruby.h defines.h io.o : io.c ruby.h defines.h io.h +main.o : main.c math.o : math.c ruby.h defines.h -methods.o : methods.c ruby.h defines.h ident.h env.h node.h methods.h missing.o : missing.c ruby.h defines.h missing/memmove.c missing/strerror.c \ missing/strtoul.c missing/strftime.c missing/strstr.c missing/getopt.h missing/getopt.c \ missing/getopt1.c missing/mkdir.c -numeric.o : numeric.c ruby.h defines.h env.h +numeric.o : numeric.c ruby.h defines.h object.o : object.c ruby.h defines.h env.h node.h st.h pack.o : pack.c ruby.h defines.h process.o : process.c ruby.h defines.h st.h random.o : random.c ruby.h defines.h range.o : range.c ruby.h defines.h re.o : re.c ruby.h defines.h re.h regex.h -regex.o : regex.c regex.h +regex.o : regex.c defines.h regex.h ruby.o : ruby.c ruby.h defines.h re.h regex.h missing/getopt.h socket.o : socket.c ruby.h defines.h sprintf.o : sprintf.c ruby.h defines.h @@ -1,3 +1,5 @@ +* 適切なsignal handling +* dlnのCOFF対応 * rubyで定義する変数hookの実現 * write debugger for ruby * re-write regex code for speeding @@ -3,7 +3,7 @@ array.c - $Author: matz $ - $Date: 1994/06/27 15:48:20 $ + $Date: 1994/08/12 11:06:34 $ created at: Fri Aug 6 09:46:12 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -16,6 +16,8 @@ VALUE C_Array; static ID eq; +VALUE rb_to_a(); + #define ARY_DEFAULT_SIZE 16 VALUE @@ -111,19 +113,16 @@ astore(ary, idx, val) int idx; VALUE val; { - int max; - if (idx < 0) { Fail("negative index for array"); } - max = idx + 1; if (idx >= ary->capa) { - ary->capa = max; - REALLOC_N(ary->ptr, VALUE, max); + ary->capa = idx + ary->capa/5; + REALLOC_N(ary->ptr, VALUE, ary->capa); } if (idx >= ary->len) { - bzero(ary->ptr+ary->len, sizeof(VALUE)*(max-ary->len)); + memset(ary->ptr+ary->len, 0, sizeof(VALUE)*(idx-ary->len+1)); } if (idx >= ary->len) { @@ -305,6 +304,42 @@ Fary_aref(ary, args) } static VALUE +Fary_index(ary, val) + struct RArray *ary; + VALUE val; +{ + int i; + + for (i=0; i<ary->len; i++) { + if (rb_funcall(ary->ptr[i], eq, 1, val)) + return INT2FIX(i); + } + return Qnil; +} + +static VALUE +Fary_indexes(ary, args) + struct RArray *ary, *args; +{ + VALUE *p, *pend; + VALUE new; + int i = 0; + + if (!args || args->len == 1) { + args = (struct RArray*)rb_to_a(args->ptr[0]); + } + + new = ary_new2(args->len); + + p = args->ptr; pend = p + args->len; + while (p < pend) { + astore(new, i++, ary_entry(ary, NUM2INT(*p))); + p++; + } + return new; +} + +static VALUE Fary_aset(ary, args) struct RArray *ary; VALUE args; @@ -317,7 +352,9 @@ Fary_aset(ary, args) int beg, len; beg = NUM2INT(arg1); - Check_Type(arg3, T_ARRAY); + if (TYPE(arg3) != T_ARRAY) { + arg3 = (struct RArray*)rb_to_a(arg3); + } if (beg < 0) { beg = ary->len + beg; if (beg < 0) { @@ -330,7 +367,7 @@ Fary_aset(ary, args) ary->capa=len; REALLOC_N(ary->ptr, VALUE, ary->capa); } - bzero(ary->ptr+ary->len, sizeof(VALUE)*(beg-ary->len)); + memset(ary->ptr+ary->len, 0, sizeof(VALUE)*(beg-ary->len)); memcpy(ary->ptr+beg, arg3->ptr, sizeof(VALUE)*arg3->len); ary->len = len; } @@ -371,7 +408,7 @@ Fary_aset(ary, args) ary->capa=len; REALLOC_N(ary->ptr, VALUE, ary->capa); } - bzero(ary->ptr+ary->len, sizeof(VALUE)*(beg-ary->len)); + memset(ary->ptr+ary->len, 0, sizeof(VALUE)*(beg-ary->len)); memcpy(ary->ptr+beg, RARRAY(arg2)->ptr, sizeof(VALUE)*RARRAY(arg2)->len); ary->len = len; @@ -500,6 +537,24 @@ Fary_to_s(ary) } static VALUE +Fary_print_on(ary, port) + struct RArray *ary; + VALUE port; +{ + int i; + + for (i=0; i<ary->len; i++) { + if (OFS && i>1) { + Fio_write(port, OFS); + } + Fio_write(port, ary->ptr[i]); + } + return port; +} + +#define INSPECT_MAX 10 + +static VALUE Fary_inspect(ary) struct RArray *ary; { @@ -511,6 +566,7 @@ Fary_inspect(ary) len = ary->len; for (i=0; i<len; i++) { + if (i > INSPECT_MAX) break; ary->ptr[i] = rb_funcall(ary->ptr[i], rb_intern("_inspect"), 0, Qnil); } @@ -518,11 +574,18 @@ Fary_inspect(ary) str = ary_join(ary, str); if (str == Qnil) return str_new2("[]"); len = RSTRING(str)->len; - str_grow(str, len+2); + if (ary->len > INSPECT_MAX) + str_grow(str, len+5); + else + str_grow(str, len+2); + p = RSTRING(str)->ptr; memmove(p+1, p, len); p[0] = '['; - p[len+1] = ']'; + if (ary->len > INSPECT_MAX) + strcpy(p+len, "...]"); + else + p[len+1] = ']'; return str; } @@ -534,6 +597,18 @@ Fary_to_a(ary) return ary; } +VALUE +rb_to_a(obj) + VALUE obj; +{ + if (TYPE(obj) == T_ARRAY) return obj; + obj = rb_funcall(obj, rb_intern("to_a"), 0); + if (TYPE(obj) != T_ARRAY) { + Bug("`to_a' did not return Array"); + } + return obj; +} + static VALUE Fary_reverse(ary) struct RArray *ary; @@ -653,7 +728,7 @@ Fary_fill(ary, args) REALLOC_N(ary->ptr, VALUE, ary->capa); } if (beg > ary->len) { - bzero(ary->ptr+ary->len, sizeof(VALUE)*(end-ary->len)); + memset(ary->ptr+ary->len, 0, sizeof(VALUE)*(end-ary->len)); } ary->len = end; } @@ -755,6 +830,21 @@ Fary_equal(ary1, ary2) return TRUE; } +static VALUE +Fary_hash(ary) + struct RArray *ary; +{ + int i, h; + ID hash = rb_intern("hash"); + + h = 0; + for (i=0; i<ary->len; i++) { + h += rb_funcall(ary->ptr[i], hash, 0); + } + h += ary->len; + return INT2FIX(h); +} + extern VALUE C_Kernel; extern VALUE M_Enumerable; @@ -768,7 +858,10 @@ Init_Array() rb_define_method(C_Array, "_inspect", Fary_inspect, 0); rb_define_method(C_Array, "to_a", Fary_to_a, 0); + rb_define_method(C_Array, "print_on", Fary_print_on, 1); + rb_define_method(C_Array, "==", Fary_equal, 1); + rb_define_method(C_Array, "hash", Fary_hash, 0); rb_define_method(C_Array, "[]", Fary_aref, -2); rb_define_method(C_Array, "[]=", Fary_aset, -2); rb_define_method(C_Array, "<<", Fary_append, 1); @@ -778,6 +871,9 @@ Init_Array() rb_define_method(C_Array, "unshift", Fary_unshift, 1); rb_define_method(C_Array, "each", Fary_each, 0); rb_define_method(C_Array, "length", Fary_length, 0); + rb_define_alias(C_Array, "size", "length"); + rb_define_method(C_Array, "index", Fary_index, 1); + rb_define_method(C_Array, "indexes", Fary_indexes, -2); rb_define_method(C_Array, "clone", Fary_clone, 0); rb_define_method(C_Array, "join", Fary_join, -2); rb_define_method(C_Array, "reverse", Fary_reverse, 0); @@ -3,7 +3,7 @@ bignum.c - $Author: matz $ - $Date: 1994/06/27 15:48:21 $ + $Date: 1994/08/12 04:47:06 $ created at: Fri Jun 10 00:48:55 JST 1994 ************************************************/ @@ -58,7 +58,7 @@ Fbig_clone(x) { VALUE z = bignew_1(CLASS_OF(x), x->len, x->sign); - bcopy(BDIGITS(x), BDIGITS(z), x->len*sizeof(USHORT)); + memcpy(BDIGITS(z), BDIGITS(x), x->len*sizeof(USHORT)); return (VALUE)z; } @@ -3,7 +3,7 @@ class.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 11:06:35 $ created at: Tue Aug 10 15:05:44 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -131,6 +131,12 @@ include_class_new(module, super) cls->m_tbl = module->m_tbl; cls->c_tbl = module->c_tbl; cls->super = super; + if (TYPE(module) == T_ICLASS) { + RBASIC(cls)->class = RBASIC(module)->class; + } + else { + RBASIC(cls)->class = (VALUE)module; + } return cls; } @@ -243,17 +249,6 @@ rb_define_single_method(obj, name, func, argc) } void -rb_define_mfunc(class, name, func, argc) - struct RClass *class; - char *name; - VALUE (*func)(); - int argc; -{ - rb_define_method(class, name, func, argc); - rb_define_single_method(class, name, func, argc); -} - -void rb_define_alias(class, name1, name2) struct RClass *class; char *name1, *name2; @@ -276,11 +271,11 @@ rb_define_attr(class, name, pub) attreq = rb_intern(buf); sprintf(buf, "@%s", name); attriv = rb_intern(buf); - if (rb_get_method_body(class, attr, 0) == Qnil) { - rb_add_method(class, attr, NEW_IVAR(attriv), TRUE); + if (rb_method_boundp(class, attr) == Qnil) { + rb_add_method(class, attr, NEW_IVAR(attriv), FALSE); } - if (pub && rb_get_method_body(class, attreq, 0) == Qnil) { - rb_add_method(class, attreq, NEW_ATTRSET(attriv), TRUE); + if (pub && rb_method_boundp(class, attreq) == Qnil) { + rb_add_method(class, attreq, NEW_ATTRSET(attriv), FALSE); } } @@ -309,6 +304,7 @@ rb_scan_args(args, fmt, va_alist) if (NIL_P(args)) { len = 0; + args = ary_new(); } else { Check_Type(args, T_ARRAY); @@ -3,7 +3,7 @@ compar.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 04:47:09 $ created at: Thu Aug 26 14:39:48 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -17,10 +17,10 @@ VALUE M_Comparable; static ID cmp; static VALUE -Fcmp_eq(this, other) - VALUE this, other; +Fcmp_eq(x, y) + VALUE x, y; { - VALUE c = rb_funcall(this, cmp, 1, other); + VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); if (t == 0) return TRUE; @@ -28,58 +28,58 @@ Fcmp_eq(this, other) } static VALUE -Fcmp_gt(this, other) - VALUE this, other; +Fcmp_gt(x, y) + VALUE x, y; { - VALUE c = rb_funcall(this, cmp, 1, other); + VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t > 0) return other; + if (t > 0) return y; return FALSE; } static VALUE -Fcmp_ge(this, other) - VALUE this, other; +Fcmp_ge(x, y) + VALUE x, y; { - VALUE c = rb_funcall(this, cmp, 1, other); + VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t >= 0) return other; + if (t >= 0) return y; return FALSE; } static VALUE -Fcmp_lt(this, other) - VALUE this, other; +Fcmp_lt(x, y) + VALUE x, y; { - VALUE c = rb_funcall(this, cmp, 1, other); + VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t < 0) return other; + if (t < 0) return y; return FALSE; } static VALUE -Fcmp_le(this, other) - VALUE this, other; +Fcmp_le(x, y) + VALUE x, y; { - VALUE c = rb_funcall(this, cmp, 1, other); + VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t <= 0) return other; + if (t <= 0) return y; return FALSE; } static VALUE -Fcmp_between(this, min, max) - VALUE this, min, max; +Fcmp_between(x, min, max) + VALUE x, min, max; { - VALUE c = rb_funcall(this, cmp, 1, min); + VALUE c = rb_funcall(x, cmp, 1, min); int t = NUM2INT(c); if (t < 0) return FALSE; - c = rb_funcall(this, cmp, 1, min); + c = rb_funcall(x, cmp, 1, min); t = NUM2INT(c); if (t > 0) return FALSE; return TRUE; diff --git a/configure.in b/configure.in index 041018e0d2..bd841c434c 100644 --- a/configure.in +++ b/configure.in @@ -1,16 +1,15 @@ - dnl Process this file with autoconf to produce a configure script. AC_INIT(ruby.h) PROGS="ruby" AC_SUBST(PROGS)dnl AC_PROG_CC AC_GCC_TRADITIONAL -if test $GCC -eq 1 ; then +if test "$GCC" = 1 ; then DBM=-fpcc-struct-return fi AC_SUBST(DBM)dnl if test "$HOSTTYPE" = sparc; then - if test $GCC -eq 1 ; then + if test "$GCC" = 1 ; then STATIC=-static else STATIC=-Bstatic @@ -27,7 +26,8 @@ AC_GETGROUPS_T AC_RETSIGTYPE AC_HAVE_FUNCS(getopt_long memmove strerror strtoul strdup strstr) AC_HAVE_FUNCS(setenv fmod killpg mkdir strftime socket random) -AC_HAVE_FUNCS(wait4 waitpid syscall) +AC_HAVE_FUNCS(wait4 waitpid syscall getcwd) +AC_HAVE_FUNCS(getpriority sigprocmask) if echo $DEFS | grep "HAVE_SETENV" 2>&1 > /dev/null; then : else @@ -38,13 +38,15 @@ if echo $DEFS | grep "HAVE_STRFTIME" 2>&1 > /dev/null; then else AC_TIMEZONE AC_COMPILE_CHECK([daylight], [], - [extern int daylight; int i; i = daylight;], AC_DEFINE(HAVE_DAYLIGHT)) + [extern int daylight; int i = daylight;], AC_DEFINE(HAVE_DAYLIGHT)) fi AC_ALLOCA AC_WORDS_BIGENDIAN AC_ST_BLKSIZE AC_ST_BLOCKS AC_ST_RDEV +AC_COMPILE_CHECK([std stdio], [#include <stdio.h>], +[stdin->_cnt > 0;], AC_DEFINE(STDSTDIO)) AC_COMPILE_CHECK([pw_change in struct passwd], [#include <pwd.h>], [struct passwd pw; pw.pw_change;], AC_DEFINE(PW_CHANGE)) AC_COMPILE_CHECK([pw_quota in struct passwd], [#include <pwd.h>], @@ -3,7 +3,7 @@ dbm.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 11:06:37 $ created at: Mon Jan 24 15:59:52 JST 1994 Copyright (C) 1994 Yukihiro Matsumoto @@ -15,10 +15,11 @@ #ifdef USE_DBM #include <ndbm.h> -#include <sys/file.h> +#include <sys/fcntl.h> #include <errno.h> VALUE C_DBM; +static ID id_dbm; extern VALUE M_Enumerable; @@ -30,7 +31,7 @@ closeddbm() #define GetDBM(obj, dbmp) {\ DBM **_dbm;\ - Get_Data_Struct(obj, "dbm", DBM*, _dbm);\ + Get_Data_Struct(obj, id_dbm, DBM*, _dbm);\ dbmp = *_dbm;\ if (dbmp == Qnil) closeddbm();\ } @@ -44,7 +45,7 @@ free_dbm(dbmp) #define MakeDBM(obj, dp) {\ DBM **_dbm;\ - Make_Data_Struct(obj,"dbm",DBM*,Qnil,free_dbm,_dbm);\ + Make_Data_Struct(obj,id_dbm,DBM*,Qnil,free_dbm,_dbm);\ *_dbm=dp;\ } @@ -93,7 +94,7 @@ Fdbm_close(obj) { DBM **dbmp; - Get_Data_Struct(obj, "dbm", DBM*, dbmp); + Get_Data_Struct(obj, id_dbm, DBM*, dbmp); if (*dbmp == Qnil) Fail("already closed DBM file"); dbm_close(*dbmp); *dbmp = Qnil; @@ -121,6 +122,29 @@ Fdbm_fetch(obj, keystr) } static VALUE +Fdbm_indexes(obj, args) + VALUE obj; + struct RArray *args; +{ + VALUE *p, *pend; + struct RArray *new; + int i = 0; + + if (!args || args->len == 1 && TYPE(args->ptr) != T_ARRAY) { + args = (struct RArray*)rb_to_a(args->ptr[0]); + } + + new = (struct RArray*)ary_new2(args->len); + + p = args->ptr; pend = p + args->len; + while (p < pend) { + new->ptr[i++] = Fdbm_fetch(obj, *p++); + new->len = i; + } + return (VALUE)new; +} + +static VALUE Fdbm_delete(obj, keystr) VALUE obj, keystr; { @@ -133,7 +157,7 @@ Fdbm_delete(obj, keystr) GetDBM(obj, dbm); if (dbm_delete(dbm, key)) { - Fail("DBM delete failed"); + Fail("dbm_delete failed"); } return obj; } @@ -153,7 +177,7 @@ Fdbm_delete_if(obj) valstr = str_new(val.dptr, val.dsize); if (rb_yield(assoc_new(keystr, valstr)) && dbm_delete(dbm, key)) { - Fail("DBM delete failed"); + Fail("dbm_delete failed"); } } return obj; @@ -169,7 +193,7 @@ Fdbm_clear(obj) GetDBM(obj, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { if (dbm_delete(dbm, key)) { - Fail("DBM delete failed"); + Fail("dbm_delete failed"); } } return obj; @@ -198,7 +222,7 @@ Fdbm_store(obj, keystr, valstr) if (dbm_store(dbm, key, val, DBM_REPLACE)) { dbm_clearerr(dbm); if (errno == EPERM) rb_sys_fail(Qnil); - Fail("DBM store failed"); + Fail("dbm_store failed"); } return valstr; } @@ -369,7 +393,9 @@ Init_DBM() rb_define_method(C_DBM, "close", Fdbm_close, 0); rb_define_method(C_DBM, "[]", Fdbm_fetch, 1); rb_define_method(C_DBM, "[]=", Fdbm_store, 2); + rb_define_method(C_DBM, "indexes", Fdbm_indexes, -2); rb_define_method(C_DBM, "length", Fdbm_length, 0); + rb_define_alias(C_DBM, "size", "length"); rb_define_method(C_DBM, "each", Fdbm_each, 0); rb_define_method(C_DBM, "each_value", Fdbm_each, 0); rb_define_method(C_DBM, "each_key", Fdbm_each_key, 0); @@ -384,5 +410,7 @@ Init_DBM() rb_define_method(C_DBM, "has_value", Fdbm_has_value, 1); rb_define_method(C_DBM, "to_a", Fdbm_to_a, 0); + + id_dbm = rb_intern("dbm"); } #endif /* USE_DBM */ @@ -3,7 +3,7 @@ defines.h - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 04:47:11 $ created at: Wed May 18 00:21:44 JST 1994 ************************************************/ @@ -3,7 +3,7 @@ dict.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 04:47:13 $ created at: Mon Nov 22 18:51:18 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -74,6 +74,29 @@ Fdic_aref(dic, key) } static VALUE +Fdic_indexes(dic, args) + struct RDict *dic; + struct RArray *args; +{ + VALUE *p, *pend; + struct RArray *new; + int i = 0; + + if (!args || args->len == 1 && TYPE(args->ptr) != T_ARRAY) { + args = (struct RArray*)rb_to_a(args->ptr[0]); + } + + new = (struct RArray*)ary_new2(args->len); + + p = args->ptr; pend = p + args->len; + while (p < pend) { + new->ptr[i++] = Fdic_aref(dic, *p++); + } + new->len = i; + return (VALUE)new; +} + +static VALUE Fdic_delete(dic, key) struct RDict *dic; VALUE key; @@ -140,7 +163,7 @@ Fdic_length(dic) } static -dic_each(key, value) +dic_each_value(key, value) VALUE key, value; { rb_yield(value); @@ -148,10 +171,10 @@ dic_each(key, value) } static VALUE -Fdic_each(dic) +Fdic_each_value(dic) struct RDict *dic; { - st_foreach(dic->tbl, dic_each); + st_foreach(dic->tbl, dic_each_value); return (VALUE)dic; } @@ -304,14 +327,12 @@ Fdic_has_key(dic, key) return FALSE; } -static VALUE value_found; - static int -dic_search_value(key, value, arg) - VALUE key, value, arg; +dic_search_value(key, value, data) + VALUE key, value, *data; { - if (rb_funcall(value, eq, 1, arg)) { - value_found = TRUE; + if (rb_funcall(value, eq, 1, data[1])) { + data[0] = TRUE; return ST_STOP; } return ST_CONTINUE; @@ -322,9 +343,12 @@ Fdic_has_value(dic, val) struct RDict *dic; VALUE val; { - value_found = FALSE; - st_foreach(dic->tbl, dic_search_value, val); - return value_found; + VALUE data[2]; + + data[0] = FALSE; + data[1] = val; + st_foreach(dic->tbl, dic_search_value, data); + return data[0]; } struct equal_data { @@ -367,7 +391,27 @@ Fdic_equal(dic1, dic2) return data.result; } -char *index(); +static int +dic_hash(key, val, data) + VALUE key, val; + int *data; +{ + *data ^= rb_funcall(key, hash, 0); + *data ^= rb_funcall(val, hash, 0); + return ST_CONTINUE; +} + +static VALUE +Fdic_hash(dic) + struct RDict *dic; +{ + int h; + + st_foreach(dic->tbl, dic_hash, &h); + return INT2FIX(h); +} + +char *strchr(); extern VALUE rb_readonly_hook(); extern char **environ; @@ -381,7 +425,7 @@ Fenv_each(dic) env = environ; while (*env) { VALUE var, val; - char *s = index(*env, '='); + char *s = strchr(*env, '='); var = str_new(*env, s-*env); val = str_new2(s+1); @@ -500,11 +544,14 @@ Init_Dict() rb_define_method(C_Dict,"_inspect", Fdic_inspect, 0); rb_define_method(C_Dict,"==", Fdic_equal, 1); + rb_define_method(C_Dict,"hash", Fdic_hash, 0); rb_define_method(C_Dict,"[]", Fdic_aref, 1); rb_define_method(C_Dict,"[]=", Fdic_aset, 2); + rb_define_method(C_Dict,"indexes", Fdic_indexes, -2); rb_define_method(C_Dict,"length", Fdic_length, 0); - rb_define_method(C_Dict,"each", Fdic_each, 0); - rb_define_method(C_Dict,"each_value", Fdic_each, 0); + rb_define_alias(C_Dict, "size", "length"); + rb_define_method(C_Dict,"each", Fdic_each_pair, 0); + rb_define_method(C_Dict,"each_value", Fdic_each_value, 0); rb_define_method(C_Dict,"each_key", Fdic_each_key, 0); rb_define_method(C_Dict,"each_pair", Fdic_each_pair, 0); @@ -3,7 +3,7 @@ dir.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 11:06:38 $ created at: Wed Jan 5 09:51:01 JST 1994 Copyright (C) 1994 Yukihiro Matsumoto @@ -37,6 +37,7 @@ #endif /* not (DIRENT or _POSIX_VERSION) */ static VALUE C_Dir; +static ID id_dir; static void free_dir(dir) @@ -59,7 +60,7 @@ Fdir_open(dir_class, dirname) if (dirp == NULL) Fail("Can't open directory %s", dirname->ptr); obj = obj_alloc(dir_class); - Make_Data_Struct(obj, "dir", DIR*, Qnil, free_dir, d); + Make_Data_Struct(obj, id_dir, DIR*, Qnil, free_dir, d); *d = dirp; return obj; @@ -73,7 +74,7 @@ closeddir() #define GetDIR(obj, dirp) {\ DIR **_dp;\ - Get_Data_Struct(obj, "dir", DIR*, _dp);\ + Get_Data_Struct(obj, id_dir, DIR*, _dp);\ dirp = *_dp;\ if (dirp == NULL) closeddir();\ } @@ -134,7 +135,7 @@ Fdir_close(dir) { DIR **dirpp; - Get_Data_Struct(dir, "dir", DIR*, dirpp); + Get_Data_Struct(dir, id_dir, DIR*, dirpp); if (*dirpp == NULL) Fail("already closed directory"); closedir(*dirpp); *dirpp = NULL; @@ -166,7 +167,7 @@ Fdir_chdir(obj, args) if (chdir(dist) < 0) rb_sys_fail(Qnil); - return Qnil; + return INT2FIX(0); } static VALUE @@ -176,7 +177,11 @@ Fdir_getwd(dir) extern char *getwd(); char path[MAXPATHLEN]; +#ifdef HAVE_GETCWD + if (getcwd(path, sizeof(path)) == 0) Fail(path); +#else if (getwd(path) == 0) Fail(path); +#endif return str_new2(path); } @@ -190,7 +195,7 @@ Fdir_chroot(dir, path) if (chroot(RSTRING(path)->ptr) == -1) rb_sys_fail(Qnil); - return Qnil; + return INT2FIX(0); } static VALUE @@ -211,7 +216,7 @@ Fdir_mkdir(obj, args) if (mkdir(RSTRING(path)->ptr, mode) == -1) rb_sys_fail(RSTRING(path)->ptr); - return Qnil; + return INT2FIX(0); } static VALUE @@ -251,4 +256,6 @@ Init_Dir() rb_define_single_method(C_Dir,"rmdir", Fdir_rmdir, 1); rb_define_single_method(C_Dir,"delete", Fdir_rmdir, 1); rb_define_single_method(C_Dir,"unlink", Fdir_rmdir, 1); + + id_dir = rb_intern("dir"); } @@ -3,7 +3,7 @@ dln.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 04:47:16 $ created at: Tue Jan 18 17:05:06 JST 1994 Copyright (C) 1994 Yukihiro Matsumoto @@ -32,7 +32,7 @@ static int dln_init_p = 0; static char fbuf[MAXPATHLEN]; static char *dln_find_1(); char *getenv(); -char *index(); +char *strchr(); int strcmp(); char * @@ -74,7 +74,7 @@ dln_find_1(fname, path, exe_flag) int fspace; /* extract a component */ - ep = index(dp, ':'); + ep = strchr(dp, ':'); if (ep == NULL) ep = dp+strlen(dp); @@ -420,18 +420,18 @@ dln_load_text_data(fd, hdrp, bss, disp) } if (bss == -1) { - bzero(addr + hdrp->a_text + hdrp->a_data, hdrp->a_bss); + memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss); } else if (bss > 0) { - bzero(addr + hdrp->a_text + hdrp->a_data, bss ); + memset(addr + hdrp->a_text + hdrp->a_data, 0, bss); } return (long)addr; } static int -undef_print(key, value, arg) - char *key; +undef_print(key, value) + char *key, *value; { fprintf(stderr, " %s\n", key); return ST_CONTINUE; @@ -3,8 +3,8 @@ dln.h - $Author: matz $ - $Revision: 1.1.1.1 $ - $Date: 1994/06/17 14:23:49 $ + $Revision: 1.2 $ + $Date: 1994/08/12 04:47:17 $ created at: Wed Jan 19 16:53:09 JST 1994 ************************************************/ @@ -3,7 +3,7 @@ enum.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 04:47:18 $ created at: Fri Oct 1 15:15:19 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -2,9 +2,9 @@ env.h - - $Author$ - $Revision$ - $Date$ + $Author: matz $ + $Revision: 1.3 $ + $Date: 1994/08/12 11:06:39 $ created at: Mon Jul 11 11:53:03 JST 1994 ************************************************/ @@ -17,8 +17,10 @@ extern struct ENVIRON { VALUE *argv; struct RClass *current_module; struct RClass *last_class; +#ifdef USE_CALLER char *file; int line; +#endif ID last_func; ID *local_tbl; VALUE *local_vars; @@ -29,12 +31,15 @@ extern struct ENVIRON { struct ENVIRON *prev; } *the_env; -#define ITERATOR_P() (the_env->iterator > 0 && the_env->iterator < 3) +#define ITERATOR_P() (the_env->iterator == 1 || the_env->iterator == 2) + +#undef Qself #define Qself the_env->self #define the_class the_env->current_module #define DURING_ITERATE 1 #define DURING_RESQUE 2 #define DURING_CALL 4 +#define VARS_MALLOCED 8 #endif /* ENV_H */ @@ -3,7 +3,7 @@ error.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/12 04:47:21 $ created at: Mon Aug 9 16:11:34 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -53,9 +53,16 @@ err_print(fmt, args) } } +void yyerror(msg) char *msg; { + static char *f; + static int line; + + if (line == sourceline && strcmp(f, sourcefile) == 0) + return; + f = sourcefile; line = sourceline; Error("%s", msg); } @@ -3,7 +3,7 @@ etc.c - $Author: matz $ - $Date: 1994/06/17 14:23:49 $ + $Date: 1994/08/24 09:25:27 $ created at: Tue Mar 22 18:39:19 JST 1994 ************************************************/ @@ -21,7 +21,7 @@ Fetc_getlogin(obj) char *login = getlogin(); if (login) - return str_new2(getlogin()); + return str_new2(login); return Qnil; } @@ -178,13 +178,15 @@ Init_Etc() { M_Etc = rb_define_module("Etc"); - rb_define_mfunc(M_Etc, "getlogin", Fetc_getlogin, 0); + rb_define_method(M_Etc, "getlogin", Fetc_getlogin, 0); - rb_define_mfunc(M_Etc, "getpwuid", Fetc_getpwuid, -2); - rb_define_mfunc(M_Etc, "getpwnam", Fetc_getpwnam, 1); - rb_define_mfunc(M_Etc, "passwd", Fetc_passwd, 0); + rb_define_method(M_Etc, "getpwuid", Fetc_getpwuid, -2); + rb_define_method(M_Etc, "getpwnam", Fetc_getpwnam, 1); + rb_define_method(M_Etc, "passwd", Fetc_passwd, 0); - rb_define_mfunc(M_Etc, "getgrgid", Fetc_getgrgid, 1); - rb_define_mfunc(M_Etc, "getgrnam", Fetc_getgrnam, 1); - rb_define_mfunc(M_Etc, "group", Fetc_group, 0); + rb_define_method(M_Etc, "getgrgid", Fetc_getgrgid, 1); + rb_define_method(M_Etc, "getgrnam", Fetc_getgrnam, 1); + rb_define_method(M_Etc, "group", Fetc_group, 0); + + rb_include_module(CLASS_OF(M_Etc), M_Etc); } @@ -3,7 +3,7 @@ eval.c - $Author: matz $ - $Date: 1994/06/27 15:48:23 $ + $Date: 1994/08/24 09:25:28 $ created at: Thu Jun 10 14:22:17 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -11,23 +11,183 @@ ************************************************/ #include "ruby.h" +#include "ident.h" #include "env.h" #include "node.h" -#include "ident.h" +#include "methods.h" + #include <stdio.h> #include <setjmp.h> #include "st.h" +void method_free(); +void rb_clear_cache(); + +/* #define TEST /* prints cache miss */ +#ifdef TEST +#include <stdio.h> +#endif + +#if 1 +#define CACHE_SIZE 0x200 +#define CACHE_MASK 0x1ff +#define EXPR1(c,m) ((((int)(c)>>3)^(m))&CACHE_MASK) + +#else + +#define CACHE_SIZE 577 +#define EXPR1(c,m) (((int)(c)^(m))%CACHE_SIZE) +#endif + +struct cache_entry { /* method hash table. */ + ID mid; /* method's id */ + struct RClass *class; /* receiver's class */ + struct RClass *origin; /* where method defined */ + struct SMethod *method; + int undef; +}; + +static struct cache_entry cache[CACHE_SIZE]; + +static struct SMethod* +search_method(class, id, origin) + struct RClass *class, **origin; + ID id; +{ + struct SMethod *body; + NODE *list; + + while (!st_lookup(class->m_tbl, id, &body)) { + class = class->super; + if (class == Qnil) return Qnil; + } + + if (body->origin) + *origin = body->origin; + else + *origin = class; + return body; +} + +static NODE* +rb_get_method_body(classp, idp) + struct RClass **classp; + ID *idp; +{ + int pos, i; + ID id = *idp; + struct RClass *class = *classp; + struct SMethod *method; + struct SMethod *body; + struct RClass *origin; + struct cache_entry *ent; + + if ((body = search_method(class, id, &origin)) == Qnil) { + return Qnil; + } + + ent = cache + EXPR1(class, id); +#ifdef TEST + if (ent->mid != 0) { + fprintf(stderr, "0x%x 0x%x %x\n", class, id, EXPR1(class, id)); + } +#endif + /* store in cache */ + ent->mid = id; + ent->class = class; + ent->origin = origin; + ent->method = body; + ent->undef = body->undef; + + if (ent->undef) return Qnil; + *idp = ent->method->id; + *classp = ent->origin; + return ent->method->node; +} + +VALUE +rb_method_boundp(class, id) + struct RClass *class; + ID id; +{ + if (rb_get_method_body(&class, &id)) + return TRUE; + return FALSE; +} + +void +rb_alias(class, name, def) + struct RClass *class; + ID name, def; +{ + struct SMethod *body; + + if (st_lookup(class->m_tbl, name, &body)) { + if (verbose) { + Warning("redefine %s", rb_id2name(name)); + } + rb_clear_cache(body); + method_free(body); + } + body = search_method(class, def, &body); + body->count++; + st_insert(class->m_tbl, name, body); +} + +void +rb_clear_cache(body) + struct SMethod *body; +{ + struct cache_entry *ent, *end; + + ent = cache; end = ent + CACHE_SIZE; + while (ent < end) { + if (ent->method == body) { + ent->class = Qnil; + ent->mid = Qnil; + } + ent++; + } +} + +void +rb_clear_cache2(class) + struct RClass *class; +{ + struct cache_entry *ent, *end; + + ent = cache; end = ent + CACHE_SIZE; + while (ent < end) { + if (ent->origin == class) { + ent->class = Qnil; + ent->mid = Qnil; + } + ent++; + } +} + +void +method_free(body) + struct SMethod *body; +{ + body->count--; + if (body->count == 0) { + freenode(body->node); + free(body); + } +} + static ID match, each; VALUE errstr, errat; extern NODE *eval_tree; +extern int nerrs; extern VALUE TopSelf; struct ENVIRON *the_env, *top_env; #define PUSH_ENV() {\ struct ENVIRON _this;\ - if (the_env) _this = *the_env; else bzero(&_this, sizeof(_this));\ + _this = *the_env;\ _this.prev = the_env;\ _this.flags = 0;\ the_env = &_this;\ @@ -51,6 +211,8 @@ static struct tag { jmp_buf buf; struct gc_list *gclist; struct ENVIRON *env; + VALUE self; + int ilevel; } *prot_tag; #define PUSH_TAG() {\ @@ -59,6 +221,8 @@ static struct tag { &_oldtag;\ _this.level= ++tag_level;\ _this.env= the_env;\ + _this.self= Qself;\ + _this.ilevel= the_env->iterator;\ prot_tag = &_this;\ #define POP_TAG() \ @@ -69,6 +233,8 @@ static struct tag { #define EXEC_TAG() (setjmp(prot_tag->buf)) #define JUMP_TAG(val) {\ the_env = prot_tag->env;\ + the_env->iterator = prot_tag->ilevel;\ + Qself = prot_tag->self;\ longjmp(prot_tag->buf,(val));\ } @@ -85,11 +251,12 @@ static struct tag { static VALUE rb_eval(); VALUE Feval(); -VALUE Argv; static VALUE rb_call(); VALUE rb_apply(); VALUE rb_xstring(); +void rb_fail(); +static VALUE masign(); static void asign(); static VALUE last_val; @@ -99,6 +266,12 @@ extern VALUE rb_stderr; extern int sourceline; extern char *sourcefile; +VALUE +rb_self() +{ + return Qself; +} + static ID last_func; static void error_print() @@ -123,71 +296,36 @@ error_print() exit(1); } -static int origargc; -static char **origargv; - -main(argc, argv) +void +ruby_init(argc, argv, envp) int argc; - char *argv[]; + char **argv, **envp; { int state; + static struct ENVIRON top_env; + the_env = &top_env; - origargc = argc; origargv = argv; - Init_stack(); - PUSH_ENV(); - top_env = the_env; PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { - rb_main(argc, argv); + ruby_init0(argc, argv, envp); } POP_TAG(); - - switch (state) { - case 0: - break; - case TAG_RETURN: - Fatal("unexpected return"); - break; - case TAG_CONTINUE: - Fatal("unexpected continue"); - break; - case TAG_BREAK: - Fatal("unexpected break"); - break; - case TAG_REDO: - Fatal("unexpected redo"); - break; - case TAG_RETRY: - Fatal("retry outside of protect clause"); - break; - case TAG_FAIL: - PUSH_TAG() + if (state) { + PUSH_TAG(); error_print(); POP_TAG(); - break; - case TAG_EXIT: - rb_trap_exit(); - exit(FIX2UINT(last_val)); - break; - default: - Bug("Unknown longjmp status %d", state); - break; } - POP_ENV(); - exit(0); } VALUE rb_readonly_hook(); -static VALUE Progname; - static VALUE Eval(toplevel) int toplevel; { VALUE result; NODE *tree; - int state; + int state; if (match == Qnil) match = rb_intern("=~"); if (each == Qnil) each = rb_intern("each"); @@ -199,79 +337,72 @@ Eval(toplevel) result = rb_eval(tree); } POP_TAG(); +/* #define PURIFY_D /* define when purify'ing */ +#ifdef PURIFY_D + freenode(tree); +#else /* you don't have to free at toplevel */ if (!toplevel) freenode(tree); +#endif if (state) JUMP_TAG(state); return result; } -static VALUE -set_arg0(val, id) - VALUE val; - ID id; -{ - char *s; - int i; - static int len; - - Check_Type(val, T_STRING); - if (len == 0) { - s = origargv[0]; - s += strlen(s); - /* See if all the arguments are contiguous in memory */ - for (i = 1; i < origargc; i++) { - if (origargv[i] == s + 1) - s += strlen(++s); /* this one is ok too */ - } - len = s - origargv[0]; - } - s = RSTRING(val)->ptr; - i = RSTRING(val)->len; - if (i > len) { - memcpy(origargv[0], s, len); - origargv[0][len] = '\0'; - } - else { - memcpy(origargv[0], s, i); - s = origargv[0]+i; - *s++ = '\0'; - while (++i < len) - *s++ = ' '; - } - Progname = str_new2(origargv[0]); - - return val; -} - -VALUE -TopLevel(script, argc, argv) - char *script; - int argc; - char **argv; +ruby_run() { - int i; + int state; - the_class = (struct RClass*)C_Object; + if (nerrs > 0) exit(nerrs); + Init_stack(); rb_define_variable("$!", &errstr, Qnil, Qnil); errat = Qnil; /* clear for execution */ - Progname = str_new2(script); - rb_define_variable("$0", &Progname, Qnil, set_arg0); + PUSH_ENV(); + top_env = the_env; + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + int i; - rb_define_variable("$ARGV", &Argv, Qnil, Qnil); - rb_define_variable("$*", &Argv, Qnil, Qnil); - Argv = ary_new2(argc); - for (i=0; i < argc; i++) { - Fary_push(Argv, str_new2(argv[i])); + the_class = (struct RClass*)C_Object; + Eval(1); } -#define PURIFY_D -#ifdef PURIFY_D - return Eval(0); -#else - return Eval(1); -#endif + POP_TAG(); + + switch (state) { + case 0: + break; + case TAG_RETURN: + Fatal("unexpected return"); + break; + case TAG_CONTINUE: + Fatal("unexpected continue"); + break; + case TAG_BREAK: + Fatal("unexpected break"); + break; + case TAG_REDO: + Fatal("unexpected redo"); + break; + case TAG_RETRY: + Fatal("retry outside of protect clause"); + break; + case TAG_FAIL: + PUSH_TAG(); + error_print(); + POP_TAG(); + break; + case TAG_EXIT: + rb_trap_exit(); + exit(FIX2UINT(last_val)); + break; + default: + Bug("Unknown longjmp status %d", state); + break; + } + POP_ENV(); + exit(0); } void @@ -289,61 +420,38 @@ rb_trap_eval(cmd) POP_ENV(); } -static int -setup_arg_1(node, args) - NODE *node; - VALUE *args; -{ - int argc; - - if (node->type == NODE_ARRAY) { - for (argc=0; node; node=node->nd_next) argc++; - argc++; - } - else { - *args = rb_eval(node); - if (TYPE(*args) != T_ARRAY) - Fail("*`argument' must be array"); - argc = RARRAY(*args)->len + 1; - } - return argc; -} - -static void -setup_arg_2(node, args, argc, argv) - NODE *node; - VALUE args; - int argc; - VALUE *argv; -{ - int i; - - bzero(argv, sizeof(VALUE)*argc); - if (node->type == NODE_ARRAY) { - for (i=1;node;node=node->nd_next) { - argv[i++] = rb_eval(node->nd_head); - } - } - else { - for (i=1;i<argc;i++) { - argv[i] = RARRAY(args)->ptr[i-1]; - } - } -} - #define SETUP_ARGS {\ - VALUE args = Qnil;\ - argc = setup_arg_1(node->nd_args, &args);\ - argv = (VALUE*)alloca(sizeof(VALUE)*argc);\ - setup_arg_2(node->nd_args, args, argc, argv);\ + NODE *n = node->nd_args;\ + if (!n) {\ + argc = 0;\ + argv = Qnil;\ + }\ + else if (n->type == NODE_ARRAY) {\ + int i;\ + for (argc=0; n; n=n->nd_next) argc++;\ + if (argc > 0) {\ + n = node->nd_args;\ + argv = (VALUE*)alloca(sizeof(VALUE)*argc);\ + for (i=0;n;n=n->nd_next) {\ + argv[i++] = rb_eval(n->nd_head);\ + }\ + }\ + }\ + else {\ + args = rb_eval(n);\ + if (TYPE(args) != T_ARRAY)\ + args = rb_to_a(args);\ + argc = RARRAY(args)->len;\ + argv = RARRAY(args)->ptr;\ + }\ } static VALUE rb_eval(node) register NODE *node; { - int state; - int go_out = 0; + int state; + int go_out = 0; VALUE result; &go_out; @@ -388,34 +496,6 @@ rb_eval(node) if (node) goto again; return Qnil; - case NODE_UNLESS: - { - VALUE res; - - PUSH_TAG(); - if ((state = EXEC_TAG()) == 0) { - res = rb_eval(node->nd_cond); - } - POP_TAG(); - if (state == 0) - ; - else if (state == TAG_FAIL) { - res = Qnil; - } - else { - JUMP_TAG(state); - } - - if (res == Qnil) { - node = node->nd_body; - } - else { - node = node->nd_else; - } - if (node) goto again; - return res; - } - case NODE_CASE: { VALUE val; @@ -441,6 +521,29 @@ rb_eval(node) } return Qnil; + case NODE_EXNOT: + { + VALUE res; + + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + res = rb_eval(node->nd_cond); + break; + + case TAG_FAIL: + res = Qnil; + break; + + default: + go_out++; + } + POP_TAG(); + if (go_out) JUMP_TAG(state); + if (res) return FALSE; + return TRUE; + } + case NODE_WHILE: PUSH_TAG(); switch (state = EXEC_TAG()) { @@ -465,47 +568,29 @@ rb_eval(node) if (go_out) JUMP_TAG(state); return Qnil; - case NODE_UNTIL: - for (;;) { - VALUE res; - - PUSH_TAG(); - switch (state = EXEC_TAG()) { - case 0: - res = rb_eval(node->nd_cond); - break; - - case TAG_FAIL: - res = Qnil; - break; - - default: - go_out++; - } - POP_TAG(); - if (go_out) JUMP_TAG(state); - if (res) return res; - - PUSH_TAG(); - switch (state = EXEC_TAG()) { - case 0: - until_redo: + case NODE_WHILE2: + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + while2_cont: + do { + while2_redo: rb_eval(node->nd_body); - break; - case TAG_REDO: - goto until_redo; - case TAG_CONTINUE: - break; - case TAG_BREAK: - goto until_break; - default: - go_out++; - } - POP_TAG(); - if (go_out) JUMP_TAG(state); + } while (rb_eval(node->nd_cond)); + break; + case TAG_REDO: + goto while2_redo; + case TAG_CONTINUE: + goto while2_cont; + default: + go_out++; + case TAG_BREAK: + break; } - until_break: - break; + while2_out: + POP_TAG(); + if (go_out) JUMP_TAG(state); + return Qnil; case NODE_DO: case NODE_FOR: @@ -520,14 +605,14 @@ rb_eval(node) if (state == 0) { if (node->type == NODE_DO) { the_env->iterator = 1; - rb_eval(node->nd_iter); + result = rb_eval(node->nd_iter); } else { VALUE recv; recv = rb_eval(node->nd_iter); the_env->iterator = 1; - result = rb_call(CLASS_OF(recv), recv, each, 1, Qnil, 0); + result = rb_call(CLASS_OF(recv), recv, each, 0, Qnil); } } POP_TAG(); @@ -552,6 +637,14 @@ rb_eval(node) } return result; + case NODE_FAIL: + { + VALUE mesg = rb_eval(node->nd_stts); + if (mesg) Check_Type(mesg, T_STRING); + rb_fail(mesg); + return Qnil; /* not reached */ + } + case NODE_YIELD: { VALUE val; @@ -634,6 +727,10 @@ rb_eval(node) JUMP_TAG(TAG_CONTINUE); break; + case NODE_REDO: + JUMP_TAG(TAG_REDO); + break; + case NODE_RETRY: JUMP_TAG(TAG_RETRY); break; @@ -648,17 +745,12 @@ rb_eval(node) { VALUE recv, *argv; int argc, last_iter; + VALUE args = Qnil; /* used in SETUP_ARGS */ last_iter = the_env->iterator; the_env->iterator = 0; /* recv & args are not iter. */ recv = node->nd_recv?rb_eval(node->nd_recv):Qself; - if (node->nd_args) { - SETUP_ARGS; - } - else { - argc = 1; - argv = &recv; - } + SETUP_ARGS; the_env->iterator = last_iter; /* restore iter. level */ return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv); @@ -671,20 +763,17 @@ rb_eval(node) int last_iter; int i, argc; VALUE *argv; + VALUE args = Qnil; /* used in SETUP_ARGS */ last_iter = the_env->iterator; /* recv & args are not iter. */ the_env->iterator = 0; - if (node->nd_args) { - SETUP_ARGS; - } - else if (node->type == NODE_ZSUPER) { + if (node->type == NODE_ZSUPER) { argc = the_env->argc; argv = the_env->argv; } else { - argc = 1; - argv = Qnil; + SETUP_ARGS; } /* restore iter. level */ @@ -707,23 +796,23 @@ rb_eval(node) { VALUE result; - PUSH_ENV(); PUSH_TAG(); if (node->nd_cnt > 0) { - the_env->local_vars = ALLOC_N(VALUE, node->nd_cnt); - bzero(the_env->local_vars, sizeof(VALUE)*node->nd_cnt); + the_env->local_vars = alloca(sizeof(VALUE)*node->nd_cnt); + memset(the_env->local_vars, 0, sizeof(VALUE)*node->nd_cnt); the_env->local_tbl = node->nd_tbl; } else { the_env->local_vars = Qnil; - the_env->local_tbl = Qnil; + the_env->local_tbl = Qnil; } if ((state = EXEC_TAG()) == 0) { result = rb_eval(node->nd_body); } POP_TAG(); - if (the_env->local_vars) free(the_env->local_vars); - POP_ENV(); + if (the_env->local_vars && (the_env->flags&VARS_MALLOCED)) + free(the_env->local_vars); + the_env->local_vars = Qnil; if (state != 0) JUMP_TAG(state); return result; @@ -732,25 +821,7 @@ rb_eval(node) case NODE_MASGN: { VALUE val = rb_eval(node->nd_value); - NODE *list = node->nd_head; - int i, len; - - if (TYPE(val) != T_ARRAY) { - val = rb_funcall(val, rb_intern("to_a"), 0, Qnil); - if (TYPE(val) != T_ARRAY) { - Bug("to_a did not return Array"); - } - } - len = RARRAY(val)->len; - for (i=0; list && i<len; i++) { - asign(list->nd_head, RARRAY(val)->ptr[i]); - list = list->nd_next; - } - while (list) { - asign(list->nd_head, Qnil); - list = list->nd_next; - } - return val; + return masign(node, val); } case NODE_LASGN: @@ -856,6 +927,7 @@ rb_eval(node) case NODE_STR2: case NODE_XSTR2: case NODE_DREGX: + case NODE_DGLOB: { VALUE str, str2; NODE *list = node->nd_next; @@ -877,9 +949,12 @@ rb_eval(node) if (node->type == NODE_DREGX) { return regexp_new(RSTRING(str)->ptr, RSTRING(str)->len); } - else if (node->type == NODE_XSTR2) { + if (node->type == NODE_XSTR2) { return rb_xstring(str); } + if (node->type == NODE_DGLOB) { + return glob_new(str); + } return str; } @@ -890,9 +965,9 @@ rb_eval(node) return node->nd_lit; case NODE_ATTRSET: - if (the_env->argc != 2) - Fail("Wrong # of arguments(%d for 1)", the_env->argc - 1); - return rb_ivar_set(node->nd_vid, the_env->argv[1]); + 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]); case NODE_ARGS: { @@ -900,7 +975,7 @@ rb_eval(node) int i, len; i = node->nd_cnt; - len = the_env->argc - 1; + len = the_env->argc; if (i > len || (node->nd_rest == -1 && i < len)) Fail("Wrong # of arguments(%d for %d)", len, i); @@ -909,15 +984,15 @@ rb_eval(node) Bug("unexpected local variable asignment"); for (i=1;local;i++) { - the_env->local_vars[(int)local->nd_head] = the_env->argv[i]; + the_env->local_vars[(int)local->nd_head] = the_env->argv[i-1]; local = local->nd_next; } if (node->nd_rest >= 0) { - if (the_env->argc == 1) + if (the_env->argc == 0) the_env->local_vars[node->nd_rest] = ary_new(); else the_env->local_vars[node->nd_rest] = - ary_new4(the_env->argc-i, the_env->argv+i); + ary_new4(the_env->argc-i+1, the_env->argv+i-1); } } return Qnil; @@ -1053,7 +1128,7 @@ obj_responds_to(obj, msg) id = rb_intern(msg->ptr); } - if (rb_get_method_body(CLASS_OF(obj), id, 0)) { + if (rb_method_boundp(CLASS_OF(obj), id)) { return TRUE; } return FALSE; @@ -1147,19 +1222,6 @@ rb_fail(mesg) } VALUE -Ffail(self, args) - VALUE self, args; -{ - VALUE mesg; - - rb_scan_args(args, "01", &mesg); - - if (mesg) Check_Type(mesg, T_STRING); - rb_fail(mesg); - - return Qnil; /* not reached */ -} - iterator_p() { return ITERATOR_P(); @@ -1170,10 +1232,10 @@ rb_yield(val) VALUE val; { struct BLOCK *block; - int state; - int go_out; + int state; + int go_out; VALUE result; - int cnt; + int cnt; &go_out; block = the_env->block; @@ -1186,7 +1248,10 @@ rb_yield(val) the_env = &(block->env); the_env->flags = the_env->prev->flags; if (block->var) { - asign(block->var, val); + if (block->var->type == NODE_MASGN) + masign(block->var, val); + else + asign(block->var, val); } go_out = 0; @@ -1221,6 +1286,44 @@ rb_yield(val) return result; } +static VALUE +masign(node, val) + NODE *node; + VALUE val; +{ + NODE *list; + int i, len; + + list = node->nd_head; + + if (val) { + if (TYPE(val) != T_ARRAY) { + val = rb_to_a(val); + } + len = RARRAY(val)->len; + for (i=0; list && i<len; i++) { + asign(list->nd_head, RARRAY(val)->ptr[i]); + list = list->nd_next; + } + if (node->nd_args) { + if (!list && i<len) { + asign(node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i)); + } + else { + asign(node->nd_args, ary_new()); + } + } + } + else if (node->nd_args) { + asign(node->nd_args, ary_new()); + } + while (list) { + asign(list->nd_head, Qnil); + list = list->nd_next; + } + return val; +} + static void asign(lhs, val) NODE *lhs; @@ -1275,7 +1378,7 @@ rb_iterate(it_proc, data1, bl_proc, data2) VALUE (*it_proc)(), (*bl_proc)(); char *data1, *data2; { - int state; + int state; VALUE retval; NODE *node = NEW_CFUNC(bl_proc, data2); struct BLOCK block; @@ -1324,8 +1427,8 @@ rb_resque(b_proc, data1, r_proc, data2) VALUE (*b_proc)(), (*r_proc)(); char *data1, *data2; { - int state; - int go_out; + int state; + int go_out; VALUE result; &go_out; @@ -1375,7 +1478,7 @@ rb_ensure(b_proc, data1, e_proc, data2) VALUE (*b_proc)(), (*e_proc)(); char *data1, *data2; { - int state; + int state; VALUE result; PUSH_TAG(); @@ -1396,7 +1499,7 @@ struct st_table *new_idhash(); static void rb_undefined(obj, id) VALUE obj; - ID id; + ID id; { VALUE desc = obj_as_string(obj); @@ -1413,126 +1516,133 @@ static VALUE rb_call(class, recv, mid, argc, argv) struct RClass *class; VALUE recv, *argv; - int argc; - ID mid; + int argc; + ID mid; { - int state; - int go_out = 0; - int c = argc - 1; - NODE *body; - VALUE result; + int state, go_out; + NODE *body; + VALUE result; + VALUE saved_self = Qself; + int saved_ilevel = the_env->iterator; + struct cache_entry *ent; + ID id; - &go_out; - PUSH_ENV(); - the_env->flags |= DURING_CALL; - the_env->argc = argc; - the_env->argv = argv; Qself = recv; - if (argv) argv[0] = recv; if (the_env->iterator != 0) the_env->iterator++; - if ((body = rb_get_method_body(class, mid, 1)) == Qnil) { - rb_undefined(recv, mid); + /* is it in the method cache? */ + ent = cache + EXPR1(class, mid); + if (ent->class == class && ent->mid == mid) { + if (ent->undef) rb_undefined(recv, mid); + class = ent->origin; + id = ent->method->id; + body = ent->method->node; + } + else { + id = mid; + if ((body = rb_get_method_body(&class, &id)) == Qnil) { + rb_undefined(recv, mid); + } } if (body->type == NODE_CFUNC) { int len = body->nd_argc; - if (len >= 0 && c != len) { - Fail("Wrong # of arguments for(%d for %d)", c, body->nd_argc); + if (len >= 0 && argc != len) { + Fail("Wrong # of arguments for(%d for %d)", argc, body->nd_argc); } if (len == -2) { - result = (*body->nd_cfnc)(recv, ary_new4(argc-1, argv+1)); + result = (*body->nd_cfnc)(recv, ary_new4(argc, argv)); } else if (len == -1) { result = (*body->nd_cfnc)(argc, argv); } else if (len >= 0) { - switch (c) { + switch (argc) { case 0: result = (*body->nd_cfnc)(recv); break; case 1: - result = (*body->nd_cfnc)(recv, argv[1]); + result = (*body->nd_cfnc)(recv, argv[0]); break; case 2: - result = (*body->nd_cfnc)(recv, argv[1], argv[2]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1]); break; case 3: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2]); break; case 4: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3]); break; case 5: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4]); break; case 6: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); break; case 7: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6]); break; case 8: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7]); break; case 9: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8]); break; case 10: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9]); break; case 11: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10]); break; case 12: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11]); break; case 13: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12], - argv[13]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11], + argv[12]); break; case 14: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12], - argv[13], argv[14]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11], + argv[12], argv[13]); break; case 15: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12], - argv[13], argv[14], argv[15]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14]); break; default: Fail("too many arguments(%d)", len); @@ -1545,15 +1655,25 @@ rb_call(class, recv, mid, argc, argv) } } else { - the_env->file = sourcefile; - the_env->line = sourceline; + PUSH_ENV(); + the_env->local_vars = Qnil; the_env->local_tbl = Qnil; + the_env->flags |= DURING_CALL; + the_env->argc = argc; + the_env->argv = argv; + the_env->last_class = class; + the_env->last_func = id; +#ifdef USE_CALLER + the_env->file = sourcefile; + the_env->line = sourceline; +#endif PUSH_TAG(); switch (state = EXEC_TAG()) { case 0: result = rb_eval(body); + go_out=0; break; case TAG_CONTINUE: Fatal("unexpected continue"); @@ -1571,14 +1691,14 @@ rb_call(class, recv, mid, argc, argv) result = last_val; break; default: - go_out++; + go_out=1; } POP_TAG(); + POP_ENV(); + if (go_out) JUMP_TAG(state); } - - POP_ENV(); - - if (go_out) JUMP_TAG(state); + Qself = saved_self; + the_env->iterator = saved_ilevel; return result; } @@ -1627,30 +1747,27 @@ rb_funcall(recv, mid, n, va_alist) va_dcl { va_list ar; - int argc; VALUE *argv; if (n > 0) { int i; - argc = n + 1; - argv = (VALUE*)alloca(sizeof(VALUE)*argc); + argv = (VALUE*)alloca(sizeof(VALUE)*n); va_start(ar); - for (i=1;i<argc;i++) { + for (i=0;i<n;i++) { argv[i] = va_arg(ar, VALUE); } - argv[0] = Qnil; va_end(ar); } else { - argc = 1; argv = Qnil; } - return rb_call(CLASS_OF(recv), recv, mid, argc, argv); + return rb_call(CLASS_OF(recv), recv, mid, n, argv); } +#ifdef USE_CALLER VALUE Fcaller(obj, args) VALUE obj, args; @@ -1679,15 +1796,15 @@ Fcaller(obj, args) if (e->file == Qnil) Fail("initial frame"); file = str_new2(e->file); - ary = e->argv?ary_new4(e->argc, e->argv):ary_new3(1, Qself); - res = ary_new3(4, file, INT2FIX(e->line), - str_new2(rb_id2name(e->last_func)), ary); + ary = e->argv?ary_new4(e->argc, e->argv):ary_new2(0); + res = ary_new3(5, file, INT2FIX(e->line), + str_new2(rb_id2name(e->last_func)), Qself, ary); return res; } +#endif int in_eval = 0; -extern int nerrs; VALUE Feval(obj, src) @@ -1855,7 +1972,7 @@ Frequire(obj, fname) } char *getenv(); -char *index(); +char *strchr(); #ifndef RUBY_LIB #define RUBY_LIB "/usr/local/lib/ruby:." @@ -1874,7 +1991,7 @@ addpath(path) p = s = path; while (*p) { while (*p == RUBY_LIB_SEP) p++; - if (s = index(p, RUBY_LIB_SEP)) { + if (s = strchr(p, RUBY_LIB_SEP)) { Fary_push(rb_load_path, str_new(p, (int)(s-p))); p = s + 1; } @@ -4,7 +4,7 @@ file.c - $Author: matz $ - $Date: 1994/06/27 15:48:26 $ + $Date: 1994/08/18 07:06:21 $ created at: Mon Nov 15 12:24:34 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -23,6 +23,7 @@ char *strdup(); extern VALUE C_IO; VALUE C_File; +VALUE M_FileTest; VALUE time_new(); @@ -76,8 +77,6 @@ Ffile_seek(obj, offset, ptrname) OpenFile *fptr; long pos; - Check_Type(ptrname, T_FIXNUM); - GetOpenFile(obj, fptr); pos = fseek(fptr->f, NUM2INT(offset), NUM2INT(ptrname)); @@ -88,6 +87,21 @@ Ffile_seek(obj, offset, ptrname) } static VALUE +Ffile_set_pos(obj, offset) + VALUE obj, offset; +{ + OpenFile *fptr; + long pos; + + GetOpenFile(obj, fptr); + pos = fseek(fptr->f, NUM2INT(offset), 0); + if (pos != 0) rb_sys_fail(Qnil); + clearerr(fptr->f); + + return obj; +} + +static VALUE Ffile_rewind(obj) VALUE obj; { @@ -310,7 +324,7 @@ eaccess(path, mode) } static VALUE -Ffile_d(obj, fname) +Ftest_d(obj, fname) VALUE obj; struct RString *fname; { @@ -327,7 +341,7 @@ Ffile_d(obj, fname) } static VALUE -Ffile_p(obj, fname) +Ftest_p(obj, fname) VALUE obj; struct RString *fname; { @@ -347,7 +361,7 @@ Ffile_p(obj, fname) } static VALUE -Ffile_l(obj, fname) +Ftest_l(obj, fname) VALUE obj; struct RString *fname; { @@ -376,7 +390,7 @@ Ffile_l(obj, fname) return FALSE; } -Ffile_S(obj, fname) +Ftest_S(obj, fname) VALUE obj; struct RString *fname; { @@ -406,7 +420,7 @@ Ffile_S(obj, fname) } static VALUE -Ffile_b(obj, fname) +Ftest_b(obj, fname) VALUE obj; struct RString *fname; { @@ -428,7 +442,7 @@ Ffile_b(obj, fname) } static VALUE -Ffile_c(obj, fname) +Ftest_c(obj, fname) VALUE obj; struct RString *fname; { @@ -446,7 +460,7 @@ Ffile_c(obj, fname) } static VALUE -Ffile_e(obj, fname) +Ftest_e(obj, fname) VALUE obj; struct RString *fname; { @@ -458,7 +472,7 @@ Ffile_e(obj, fname) } static VALUE -Ffile_r(obj, fname) +Ftest_r(obj, fname) VALUE obj; struct RString *fname; { @@ -468,7 +482,7 @@ Ffile_r(obj, fname) } static VALUE -Ffile_R(obj, fname) +Ftest_R(obj, fname) VALUE obj; struct RString *fname; { @@ -478,7 +492,7 @@ Ffile_R(obj, fname) } static VALUE -Ffile_w(obj, fname) +Ftest_w(obj, fname) VALUE obj; struct RString *fname; { @@ -488,7 +502,7 @@ Ffile_w(obj, fname) } static VALUE -Ffile_W(obj, fname) +Ftest_W(obj, fname) VALUE obj; struct RString *fname; { @@ -498,7 +512,7 @@ Ffile_W(obj, fname) } static VALUE -Ffile_x(obj, fname) +Ftest_x(obj, fname) VALUE obj; struct RString *fname; { @@ -508,7 +522,7 @@ Ffile_x(obj, fname) } static VALUE -Ffile_X(obj, fname) +Ftest_X(obj, fname) VALUE obj; struct RString *fname; { @@ -518,7 +532,7 @@ Ffile_X(obj, fname) } static VALUE -Ffile_f(obj, fname) +Ftest_f(obj, fname) VALUE obj; struct RString *fname; { @@ -531,7 +545,7 @@ Ffile_f(obj, fname) } static VALUE -Ffile_z(obj, fname) +Ftest_z(obj, fname) VALUE obj; struct RString *fname; { @@ -544,7 +558,7 @@ Ffile_z(obj, fname) } static VALUE -Ffile_s(obj, fname) +Ftest_s(obj, fname) VALUE obj; struct RString *fname; { @@ -557,7 +571,7 @@ Ffile_s(obj, fname) } static VALUE -Ffile_owned(obj, fname) +Ftest_owned(obj, fname) VALUE obj; struct RString *fname; { @@ -570,7 +584,7 @@ Ffile_owned(obj, fname) } static VALUE -Ffile_grpowned(obj, fname) +Ftest_grpowned(obj, fname) VALUE obj; struct RString *fname; { @@ -597,7 +611,7 @@ check3rdbyte(file, mode) #endif static VALUE -Ffile_suid(obj, fname) +Ftest_suid(obj, fname) VALUE obj; struct RString *fname; { @@ -610,7 +624,7 @@ Ffile_suid(obj, fname) } static VALUE -Ffile_sgid(obj, fname) +Ftest_sgid(obj, fname) VALUE obj; struct RString *fname; { @@ -623,7 +637,7 @@ Ffile_sgid(obj, fname) } static VALUE -Ffile_sticky(obj, fname) +Ftest_sticky(obj, fname) VALUE obj; struct RString *fname; { @@ -636,6 +650,51 @@ Ffile_sticky(obj, fname) } static VALUE +Ffile_type(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + char *t; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr); + + if (S_ISREG(st.st_mode)) { + t = "file"; + } else if (S_ISDIR(st.st_mode)) { + t = "directory"; + } else if (S_ISCHR(st.st_mode)) { + t = "characterSpecial"; + } +#ifdef S_ISBLK + else if (S_ISBLK(st.st_mode)) { + t = "blockSpecial"; + } +#endif +#ifndef S_ISFIFO + else if (S_ISFIFO(st.st_mode)) { + t = "fifo"; + } +#endif +#ifdef S_ISLNK + else if (S_ISLNK(st.st_mode)) { + t = "link"; + } +#endif +#ifdef S_ISSOCK + else if (S_ISSOCK(st.st_mode)) { + t = "socket"; + } +#endif + else { + t = "unknown"; + } + + return str_new2(t); +} + +static VALUE Ffile_atime(obj, fname) VALUE obj; struct RString *fname; @@ -733,7 +792,7 @@ Ffile_chmod(obj, args) rb_sys_fail(RSTRING(path)->ptr); } - return Qnil; + return INT2FIX(i); } static VALUE @@ -749,7 +808,7 @@ Ffile_chmod2(obj, vmode) if (fchmod(fileno(fptr->f), mode) == -1) rb_sys_fail(fptr->path); - return obj; + return INT2FIX(0); } static VALUE @@ -797,7 +856,7 @@ Ffile_chown2(obj, owner, group) if (fchown(fileno(fptr->f), NUM2INT(owner), NUM2INT(group)) == -1) rb_sys_fail(fptr->path); - return obj; + return INT2FIX(0); } struct timeval *time_timeval(); @@ -838,7 +897,7 @@ Ffile_link(obj, from, to) if (link(from->ptr, to->ptr) < 0) rb_sys_fail(from->ptr); - return TRUE; + return INT2FIX(0); } static VALUE @@ -899,7 +958,7 @@ Ffile_rename(obj, from, to) if (rename(from->ptr, to->ptr) == -1) rb_sys_fail(from->ptr); - return TRUE; + return INT2FIX(0); } static VALUE @@ -910,11 +969,11 @@ Ffile_umask(argc, argv) VALUE mask; int omask; - if (argc == 1) { + if (argc == 0) { int omask = umask(0); umask(omask); } - else if (argc == 2) { + else if (argc == 1) { omask = umask(NUM2INT(argv[1])); } else { @@ -962,64 +1021,69 @@ Ffile_fcntl(obj, req, arg) Init_File() { + M_FileTest = rb_define_module("FileTest"); + + rb_define_method(M_FileTest, "d", Ftest_d, 1); + rb_define_method(M_FileTest, "isdirectory", Ftest_d, 1); + rb_define_method(M_FileTest, "a", Ftest_e, 1); + rb_define_method(M_FileTest, "e", Ftest_e, 1); + rb_define_method(M_FileTest, "exists", Ftest_e, 1); + rb_define_method(M_FileTest, "r", Ftest_r, 1); + rb_define_method(M_FileTest, "readable", Ftest_r, 1); + rb_define_method(M_FileTest, "R", Ftest_R, 1); + rb_define_method(M_FileTest, "w", Ftest_w, 1); + rb_define_method(M_FileTest, "writable", Ftest_w, 1); + rb_define_method(M_FileTest, "W", Ftest_W, 1); + rb_define_method(M_FileTest, "x", Ftest_x, 1); + rb_define_method(M_FileTest, "executable", Ftest_x, 1); + rb_define_method(M_FileTest, "X", Ftest_X, 1); + rb_define_method(M_FileTest, "f", Ftest_f, 1); + rb_define_method(M_FileTest, "isfile", Ftest_f, 1); + rb_define_method(M_FileTest, "z", Ftest_z, 1); + rb_define_method(M_FileTest, "s", Ftest_s, 1); + rb_define_method(M_FileTest, "size", Ftest_s, 1); + rb_define_method(M_FileTest, "O", Ftest_owned, 1); + rb_define_method(M_FileTest, "owned", Ftest_owned, 1); + rb_define_method(M_FileTest, "G", Ftest_grpowned, 1); + + rb_define_method(M_FileTest, "p", Ftest_p, 1); + rb_define_method(M_FileTest, "ispipe", Ftest_p, 1); + rb_define_method(M_FileTest, "l", Ftest_l, 1); + rb_define_method(M_FileTest, "issymlink", Ftest_l, 1); + rb_define_method(M_FileTest, "S", Ftest_S, 1); + rb_define_method(M_FileTest, "issocket", Ftest_S, 1); + + rb_define_method(M_FileTest, "b", Ftest_b, 1); + rb_define_method(M_FileTest, "c", Ftest_c, 1); + + rb_define_method(M_FileTest, "u", Ftest_suid, 1); + rb_define_method(M_FileTest, "setuid", Ftest_suid, 1); + rb_define_method(M_FileTest, "g", Ftest_sgid, 1); + rb_define_method(M_FileTest, "setgid", Ftest_sgid, 1); + rb_define_method(M_FileTest, "k", Ftest_sticky, 1); + C_File = rb_define_class("File", C_IO); + rb_include_module(CLASS_OF(C_File), M_FileTest); + rb_define_single_method(C_File, "stat", Ffile_stat, 1); - rb_define_single_method(C_File, "lstat", Ffile_lstat, 1); - - rb_define_single_method(C_File, "d", Ffile_d, 1); - rb_define_single_method(C_File, "isdirectory", Ffile_d, 1); - rb_define_single_method(C_File, "a", Ffile_e, 1); - rb_define_single_method(C_File, "e", Ffile_e, 1); - rb_define_single_method(C_File, "exists", Ffile_e, 1); - rb_define_single_method(C_File, "r", Ffile_r, 1); - rb_define_single_method(C_File, "readable", Ffile_r, 1); - rb_define_single_method(C_File, "R", Ffile_R, 1); - rb_define_single_method(C_File, "w", Ffile_w, 1); - rb_define_single_method(C_File, "writable", Ffile_w, 1); - rb_define_single_method(C_File, "W", Ffile_W, 1); - rb_define_single_method(C_File, "x", Ffile_x, 1); - rb_define_single_method(C_File, "executable", Ffile_x, 1); - rb_define_single_method(C_File, "X", Ffile_X, 1); - rb_define_single_method(C_File, "f", Ffile_f, 1); - rb_define_single_method(C_File, "isfile", Ffile_f, 1); - rb_define_single_method(C_File, "z", Ffile_z, 1); - rb_define_single_method(C_File, "s", Ffile_s, 1); - rb_define_single_method(C_File, "size", Ffile_s, 1); - rb_define_single_method(C_File, "O", Ffile_owned, 1); - rb_define_single_method(C_File, "owned", Ffile_owned, 1); - rb_define_single_method(C_File, "G", Ffile_grpowned, 1); - - rb_define_single_method(C_File, "p", Ffile_p, 1); - rb_define_single_method(C_File, "ispipe", Ffile_p, 1); - rb_define_single_method(C_File, "l", Ffile_l, 1); - rb_define_single_method(C_File, "issymlink", Ffile_l, 1); - rb_define_single_method(C_File, "S", Ffile_S, 1); - rb_define_single_method(C_File, "issocket", Ffile_S, 1); - - rb_define_single_method(C_File, "b", Ffile_b, 1); - rb_define_single_method(C_File, "c", Ffile_c, 1); - - rb_define_single_method(C_File, "u", Ffile_suid, 1); - rb_define_single_method(C_File, "setuid", Ffile_suid, 1); - rb_define_single_method(C_File, "g", Ffile_sgid, 1); - rb_define_single_method(C_File, "setgid", Ffile_sgid, 1); - rb_define_single_method(C_File, "k", Ffile_sticky, 1); + rb_define_single_method(C_File, "lstat", Ffile_lstat, 1); + rb_define_single_method(C_File, "type", Ffile_type, 1); rb_define_single_method(C_File, "atime", Ffile_atime, 1); rb_define_single_method(C_File, "mtime", Ffile_mtime, 1); rb_define_single_method(C_File, "ctime", Ffile_ctime, 1); - rb_define_single_method(C_File, "utime", Ffile_utime, -1); + rb_define_single_method(C_File, "utime", Ffile_utime, -2); rb_define_single_method(C_File, "chmod", Ffile_chmod, -2); - rb_define_single_method(C_File, "chown", Ffile_chown, -1); + rb_define_single_method(C_File, "chown", Ffile_chown, -2); rb_define_single_method(C_File, "link", Ffile_link, 2); rb_define_single_method(C_File, "symlink", Ffile_symlink, 2); rb_define_single_method(C_File, "readlink", Ffile_readlink, 1); - rb_define_single_method(C_File, "unlink", Ffile_unlink, -1); - rb_define_single_method(C_File, "delete", Ffile_unlink, -1); + rb_define_single_method(C_File, "unlink", Ffile_unlink, -2); + rb_define_single_method(C_File, "delete", Ffile_unlink, -2); rb_define_single_method(C_File, "rename", Ffile_rename, 2); rb_define_single_method(C_File, "umask", Ffile_umask, -1); rb_define_single_method(C_File, "truncate", Ffile_truncate, 2); @@ -1037,6 +1101,11 @@ Init_File() rb_define_method(C_File, "tell", Ffile_tell, 0); rb_define_method(C_File, "seek", Ffile_seek, 2); + + + rb_define_method(C_File, "pos", Ffile_tell, 0); + rb_define_method(C_File, "pos=", Ffile_set_pos, 1); + rb_define_method(C_File, "rewind", Ffile_rewind, 0); rb_define_method(C_File, "isatty", Ffile_isatty, 0); rb_define_method(C_File, "eof", Ffile_eof, 0); diff --git a/fnmatch.c b/fnmatch.c new file mode 100644 index 0000000000..6a8b574902 --- /dev/null +++ b/fnmatch.c @@ -0,0 +1,189 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include "fnmatch.h" + +#if !defined (__GNU_LIBRARY__) && !defined (STDC_HEADERS) +# if !defined (errno) +extern int errno; +# endif /* !errno */ +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, FNM_NOMATCH if not. */ +int +fnmatch (pattern, string, flags) + char *pattern; + char *string; + int flags; +{ + register char *p = pattern, *n = string; + register char c; + + if ((flags & ~__FNM_FLAGS) != 0) + { + errno = EINVAL; + return (-1); + } + + while ((c = *p++) != '\0') + { + switch (c) + { + case '?': + if (*n == '\0') + return (FNM_NOMATCH); + else if ((flags & FNM_PATHNAME) && *n == '/') + return (FNM_NOMATCH); + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return (FNM_NOMATCH); + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + c = *p++; + if (*n != c) + return (FNM_NOMATCH); + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return (FNM_NOMATCH); + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_PATHNAME) && *n == '/') || + (c == '?' && *n == '\0')) + return (FNM_NOMATCH); + + if (c == '\0') + return (0); + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + for (--p; *n != '\0'; ++n) + if ((c == '[' || *n == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return (0); + return (FNM_NOMATCH); + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return (FNM_NOMATCH); + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return (FNM_NOMATCH); + + /* Make sure there is a closing `]'. If there isn't, the `[' + is just a character to be matched. */ + { + register char *np; + + for (np = p; np && *np && *np != ']'; np++); + + if (np && !*np) + { + if (*n != '[') + return (FNM_NOMATCH); + goto next_char; + } + } + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + if (c == '\0') + /* [ (unterminated) loses. */ + return (FNM_NOMATCH); + + c = *p++; + + if ((flags & FNM_PATHNAME) && c == '/') + /* [/] can never match. */ + return (FNM_NOMATCH); + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return (FNM_NOMATCH); + c = *p++; + } + + if (*n >= cstart && *n <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return (FNM_NOMATCH); + + next_char: + break; + + matched: + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return (FNM_NOMATCH); + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* 1003.2d11 is unclear if this is right. %%% */ + ++p; + } + if (not) + return (FNM_NOMATCH); + } + break; + + default: + if (c != *n) + return (FNM_NOMATCH); + } + + ++n; + } + + if (*n == '\0') + return (0); + + return (FNM_NOMATCH); +} diff --git a/fnmatch.h b/fnmatch.h new file mode 100644 index 0000000000..62c8c8fa02 --- /dev/null +++ b/fnmatch.h @@ -0,0 +1,36 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ +#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch(); + +#endif /* fnmatch.h */ @@ -3,7 +3,7 @@ gc.c - $Author: matz $ - $Date: 1994/06/27 15:48:27 $ + $Date: 1994/08/12 04:47:27 $ created at: Tue Oct 5 09:44:46 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -48,7 +48,7 @@ xcalloc(n, size) void *mem; mem = xmalloc(n * size); - bzero(mem, n * size); + memset(mem, 0, n * size); return mem; } @@ -318,12 +318,13 @@ mark_locations_array(x, n) { int j; VALUE p; - for(j=0;j<n;++j) - {p = x[j]; - if (looks_pointerp(p)) { - gc_mark(p); - } - } + + for(j=0;j<n;++j) { + p = x[j]; + if (looks_pointerp(p)) { + gc_mark(p); + } + } } static void @@ -590,12 +591,10 @@ gc() setjmp(save_regs_gc_mark); mark_locations((VALUE*)save_regs_gc_mark, (VALUE*)(((char*)save_regs_gc_mark)+sizeof(save_regs_gc_mark))); - mark_locations((VALUE*)save_regs_gc_mark, - sizeof save_regs_gc_mark/sizeof(VALUE)); mark_locations(stack_start_ptr, (VALUE*) &stack_end); #if defined(THINK_C) - mark_locations(((char*)stack_start_ptr + 2), - ((char*)&stack_end + 2)); + mark_locations((VALUE*)((char*)stack_start_ptr + 2), + (VALUE*)((char*)&stack_end + 2)); #endif /* mark protected global variables */ diff --git a/glob.c b/glob.c new file mode 100644 index 0000000000..1c21d25f14 --- /dev/null +++ b/glob.c @@ -0,0 +1,177 @@ +/************************************************ + + glob.c - + + $Author$ + $Date$ + created at: Mon Sep 12 18:56:43 JST 1994 + +************************************************/ + +#include "ruby.h" +#include "fnmatch.h" +#include <sys/param.h> + +char *strdup(); + +VALUE C_Glob; + +struct glob_data { + char **globs; +}; + +static ID id_data; + +static void +glob_free(data) + struct glob_data *data; +{ + char **globs = data->globs; + while (*globs) { + free(*globs); + globs++; + } + free(data->globs); +} + +#define isdelim(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\0') + +char *strchr(); +char *strdup(); + +static int +expand_brace(s, data, len) + char *s; + struct glob_data *data; + int len; +{ + char org[MAXPATHLEN], path[MAXPATHLEN]; + char *pre, *post, *head, *p, *t; + + strcpy(org, s); + pre = strchr(org, '{'); + if (pre) post = strchr(pre, '}'); + if (!pre || !post) { + data->globs[len++] = strdup(s); + REALLOC_N(data->globs, char*, len+1); + return len; + } + + memcpy(path, org, pre - org); + p = org + (pre - org) + 1; + head = path + (pre - org); + + while (p < post) { + t = p; + while (t < post) { + if (*t == ',') break; + t++; + } + memcpy(head, p, t-p); + strcpy(head+(t-p), post+1); + len = expand_brace(path, data, len); + p = t + 1; + } + return len; +} + +static VALUE +glob_new0(class, str) + VALUE class; + struct RString *str; +{ + VALUE new; + struct glob_data *data; + char *p1, *p2, *pend, *s; + int len = 0; + + new = obj_alloc(class); + Make_Data_Struct(new, id_data, struct glob_data, Qnil, glob_free, data); + data->globs = ALLOC_N(char*, 1); + + p1 = p2 = str->ptr; + pend = p1 + str->len; + while (p1 < pend) { + char s[MAXPATHLEN]; + int d; + + while (isdelim(*p1)) p1++; + p2 = p1; + while (!isdelim(*p2)) p2++; + d = p2 - p1; + memcpy(s, p1, d); + s[d] = '\0'; + len = expand_brace(s, data, len); + p1 = p2; + } + data->globs[len] = Qnil; + + return new; +} + +VALUE +glob_new(str) + char *str; +{ + return glob_new0(C_Glob, str); +} + +char **glob_filename(); + +static VALUE +Fglob_each(glob) + VALUE glob; +{ + struct glob_data *data; + char **patv, **fnames, **ff; + + Get_Data_Struct(glob, id_data, struct glob_data, data); + for (patv = data->globs; *patv; patv++) { + if (!glob_pattern_p(*patv)) { + rb_yield(str_new2(*patv)); + continue; + } + fnames = ff = glob_filename(*patv); + while (*ff) { + rb_yield(str_new2(*ff)); + free(*ff); + ff++; + } + free(fnames); + } + return Qnil; +} + +VALUE +Fglob_match(glob, str) + VALUE glob; + struct RString *str; +{ + struct glob_data *data; + char **patv; + + Check_Type(str, T_STRING); + Get_Data_Struct(glob, id_data, struct glob_data, data); + patv = data->globs; + while (*patv) { + if (fnmatch(*patv, str->ptr, 0) != FNM_NOMATCH) + return TRUE; + patv++; + } + return FALSE; +} + +extern VALUE M_Enumerable; + +Init_Glob() +{ + C_Glob = rb_define_class("Glob", C_Object); + rb_include_module(C_Glob, M_Enumerable); + + rb_define_single_method(C_Glob, "new", glob_new0, 1); + + rb_define_method(C_Glob, "each", Fglob_each, 0); + rb_define_method(C_Glob, "=~", Fglob_match, 1); + + id_data = rb_intern("data"); +} diff --git a/gnuglob.c b/gnuglob.c new file mode 100644 index 0000000000..e5eecc1a79 --- /dev/null +++ b/gnuglob.c @@ -0,0 +1,572 @@ +/* File-name wildcard pattern matching for GNU. + Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* To whomever it may concern: I have never seen the code which most + Unix programs use to perform this function. I wrote this from scratch + based on specifications for the pattern matching. --RMS. */ + +#if defined (SHELL) +# if defined (HAVE_STDLIB_H) +# include <stdlib.h> +# else +# include "ansi_stdlib.h" +# endif /* HAVE_STDLIB_H */ +# include <config.h> +#endif + +#include <sys/types.h> + +#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3)) +# if !defined (HAVE_DIRENT_H) +# define HAVE_DIRENT_H +# endif /* !HAVE_DIRENT_H */ +#endif /* !SHELL && (_POSIX_VERSION || USGr3) */ + +#if defined (HAVE_DIRENT_H) +# include <dirent.h> +# if !defined (direct) +# define direct dirent +# endif /* !direct */ +# define D_NAMLEN(d) strlen ((d)->d_name) +#else /* !HAVE_DIRENT_H */ +# define D_NAMLEN(d) ((d)->d_namlen) +# if defined (USG) +# if defined (Xenix) +# include <sys/ndir.h> +# else /* !Xenix (but USG...) */ +# include "ndir.h" +# endif /* !Xenix */ +# else /* !USG */ +# include <sys/dir.h> +# endif /* !USG */ +#endif /* !HAVE_DIRENT_H */ + +#if defined (_POSIX_SOURCE) +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +#else +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +#endif /* _POSIX_SOURCE */ + +#if defined (USG) || defined (NeXT) +# if !defined (HAVE_STRING_H) +# define HAVE_STRING_H +# endif /* !HAVE_STRING_H */ +#endif /* USG || NeXT */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (USG) +# if !defined (isc386) +# include <memory.h> +# endif /* !isc386 */ +# if defined (RISC6000) +extern void bcopy (); +# else /* !RISC6000 */ +# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) +# endif /* !RISC6000 */ +#endif /* USG */ + +#include "fnmatch.h" + +/* If the opendir () on your system lets you open non-directory files, + then we consider that not robust. Define OPENDIR_NOT_ROBUST in the + SYSDEP_CFLAGS for your machines entry in machines.h. */ +#if defined (OPENDIR_NOT_ROBUST) +# if defined (SHELL) +# include "posixstat.h" +# else /* !SHELL */ +# include <sys/stat.h> +# endif /* !SHELL */ +#endif /* OPENDIR_NOT_ROBUST */ + +#if !defined (HAVE_STDLIB_H) +extern char *malloc (), *realloc (); +extern void free (); +#endif /* !HAVE_STDLIB_H */ + +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *) 0) +# else +# define NULL 0x0 +# endif /* __STDC__ */ +#endif /* !NULL */ + +#if defined (SHELL) +extern int interrupt_state; +#endif /* SHELL */ + +/* Global variable which controls whether or not * matches .*. + Non-zero means don't match .*. */ +int noglob_dot_filenames = 1; + +/* Global variable to return to signify an error in globbing. */ +char *glob_error_return; + + +/* Return nonzero if PATTERN has any special globbing chars in it. */ +int +glob_pattern_p (pattern) + char *pattern; +{ + register char *p = pattern; + register char c; + int open = 0; + + while ((c = *p++) != '\0') + switch (c) + { + case '?': + case '*': + return (1); + + case '[': /* Only accept an open brace if there is a close */ + open++; /* brace to match it. Bracket expressions must be */ + continue; /* complete, according to Posix.2 */ + case ']': + if (open) + return (1); + continue; + + case '\\': + if (*p++ == '\0') + return (0); + } + + return (0); +} + +/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */ +static void +dequote_pathname (pathname) + char *pathname; +{ + register int i, j; + + for (i = j = 0; pathname && pathname[i]; ) + { + if (pathname[i] == '\\') + i++; + + pathname[j++] = pathname[i++]; + + if (!pathname[i - 1]) + break; + } + pathname[j] = '\0'; +} + + +/* Return a vector of names of files in directory DIR + whose names match glob pattern PAT. + The names are not in any particular order. + Wildcards at the beginning of PAT do not match an initial period. + + The vector is terminated by an element that is a null pointer. + + To free the space allocated, first free the vector's elements, + then free the vector. + + Return 0 if cannot get enough memory to hold the pointer + and the names. + + Return -1 if cannot access directory DIR. + Look in errno for more information. */ + +char ** +glob_vector (pat, dir) + char *pat; + char *dir; +{ + struct globval + { + struct globval *next; + char *name; + }; + + DIR *d; + register struct direct *dp; + struct globval *lastlink; + register struct globval *nextlink; + register char *nextname; + unsigned int count; + int lose, skip; + register char **name_vector; + register unsigned int i; +#if defined (OPENDIR_NOT_ROBUST) + struct stat finfo; + + if (stat (dir, &finfo) < 0) + return ((char **) &glob_error_return); + + if (!S_ISDIR (finfo.st_mode)) + return ((char **) &glob_error_return); +#endif /* OPENDIR_NOT_ROBUST */ + + d = opendir (dir); + if (d == NULL) + return ((char **) &glob_error_return); + + lastlink = 0; + count = 0; + lose = 0; + skip = 0; + + /* If PAT is empty, skip the loop, but return one (empty) filename. */ + if (!pat || !*pat) + { + nextlink = (struct globval *)alloca (sizeof (struct globval)); + nextlink->next = lastlink; + nextname = (char *) malloc (1); + if (!nextname) + lose = 1; + else + { + lastlink = nextlink; + nextlink->name = nextname; + nextname[0] = '\0'; + count++; + } + skip = 1; + } + + /* Scan the directory, finding all names that match. + For each name that matches, allocate a struct globval + on the stack and store the name in it. + Chain those structs together; lastlink is the front of the chain. */ + while (!skip) + { + int flags; /* Flags passed to fnmatch (). */ +#if defined (SHELL) + /* Make globbing interruptible in the bash shell. */ + if (interrupt_state) + { + closedir (d); + lose = 1; + goto lost; + } +#endif /* SHELL */ + + dp = readdir (d); + if (dp == NULL) + break; + + /* If this directory entry is not to be used, try again. */ + if (!REAL_DIR_ENTRY (dp)) + continue; + + /* If a dot must be explicity matched, check to see if they do. */ + if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.') + continue; + + flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME; + + if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH) + { + nextlink = (struct globval *) alloca (sizeof (struct globval)); + nextlink->next = lastlink; + nextname = (char *) malloc (D_NAMLEN (dp) + 1); + if (nextname == NULL) + { + lose = 1; + break; + } + lastlink = nextlink; + nextlink->name = nextname; + bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1); + ++count; + } + } + (void) closedir (d); + + if (!lose) + { + name_vector = (char **) malloc ((count + 1) * sizeof (char *)); + lose |= name_vector == NULL; + } + + /* Have we run out of memory? */ + lost: + if (lose) + { + /* Here free the strings we have got. */ + while (lastlink) + { + free (lastlink->name); + lastlink = lastlink->next; + } +#if defined (SHELL) + if (interrupt_state) + throw_to_top_level (); +#endif /* SHELL */ + return (NULL); + } + + /* Copy the name pointers from the linked list into the vector. */ + for (i = 0; i < count; ++i) + { + name_vector[i] = lastlink->name; + lastlink = lastlink->next; + } + + name_vector[count] = NULL; + return (name_vector); +} + +/* Return a new array which is the concatenation of each string in ARRAY + to DIR. This function expects you to pass in an allocated ARRAY, and + it takes care of free()ing that array. Thus, you might think of this + function as side-effecting ARRAY. */ +static char ** +glob_dir_to_array (dir, array) + char *dir, **array; +{ + register unsigned int i, l; + int add_slash; + char **result; + + l = strlen (dir); + if (l == 0) + return (array); + + add_slash = dir[l - 1] != '/'; + + i = 0; + while (array[i] != NULL) + ++i; + + result = (char **) malloc ((i + 1) * sizeof (char *)); + if (result == NULL) + return (NULL); + + for (i = 0; array[i] != NULL; i++) + { + result[i] = (char *) malloc (l + (add_slash ? 1 : 0) + + strlen (array[i]) + 1); + if (result[i] == NULL) + return (NULL); + sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); + } + result[i] = NULL; + + /* Free the input array. */ + for (i = 0; array[i] != NULL; i++) + free (array[i]); + free ((char *) array); + + return (result); +} + +/* Do globbing on PATHNAME. Return an array of pathnames that match, + marking the end of the array with a null-pointer as an element. + If no pathnames match, then the array is empty (first element is null). + If there isn't enough memory, then return NULL. + If a file system error occurs, return -1; `errno' has the error code. */ +char ** +glob_filename (pathname) + char *pathname; +{ + char *strrchr(); + + char **result; + unsigned int result_size; + char *directory_name, *filename; + unsigned int directory_len; + + result = (char **) malloc (sizeof (char *)); + result_size = 1; + if (result == NULL) + return (NULL); + + result[0] = NULL; + + /* Find the filename. */ + filename = strrchr (pathname, '/'); + if (filename == NULL) + { + filename = pathname; + directory_name = ""; + directory_len = 0; + } + else + { + directory_len = (filename - pathname) + 1; + directory_name = (char *) alloca (directory_len + 1); + + bcopy (pathname, directory_name, directory_len); + directory_name[directory_len] = '\0'; + ++filename; + } + + /* If directory_name contains globbing characters, then we + have to expand the previous levels. Just recurse. */ + if (glob_pattern_p (directory_name)) + { + char **directories; + register unsigned int i; + + if (directory_name[directory_len - 1] == '/') + directory_name[directory_len - 1] = '\0'; + + directories = glob_filename (directory_name); + + if (directories == NULL) + goto memory_error; + else if (directories == (char **)&glob_error_return) + return ((char **) &glob_error_return); + else if (*directories == NULL) + { + free ((char *) directories); + return ((char **) &glob_error_return); + } + + /* We have successfully globbed the preceding directory name. + For each name in DIRECTORIES, call glob_vector on it and + FILENAME. Concatenate the results together. */ + for (i = 0; directories[i] != NULL; ++i) + { + char **temp_results; + + /* Scan directory even on a NULL pathname. That way, `*h/' + returns only directories ending in `h', instead of all + files ending in `h' with a `/' appended. */ + temp_results = glob_vector (filename, directories[i]); + + /* Handle error cases. */ + if (temp_results == NULL) + goto memory_error; + else if (temp_results == (char **)&glob_error_return) + /* This filename is probably not a directory. Ignore it. */ + ; + else + { + char **array; + register unsigned int l; + + array = glob_dir_to_array (directories[i], temp_results); + l = 0; + while (array[l] != NULL) + ++l; + + result = + (char **)realloc (result, (result_size + l) * sizeof (char *)); + + if (result == NULL) + goto memory_error; + + for (l = 0; array[l] != NULL; ++l) + result[result_size++ - 1] = array[l]; + + result[result_size - 1] = NULL; + + /* Note that the elements of ARRAY are not freed. */ + free ((char *) array); + } + } + /* Free the directories. */ + for (i = 0; directories[i]; i++) + free (directories[i]); + + free ((char *) directories); + + return (result); + } + + /* If there is only a directory name, return it. */ + if (*filename == '\0') + { + result = (char **) realloc ((char *) result, 2 * sizeof (char *)); + if (result == NULL) + return (NULL); + result[0] = (char *) malloc (directory_len + 1); + if (result[0] == NULL) + goto memory_error; + bcopy (directory_name, result[0], directory_len + 1); + result[1] = NULL; + return (result); + } + else + { + char **temp_results; + + /* There are no unquoted globbing characters in DIRECTORY_NAME. + Dequote it before we try to open the directory since there may + be quoted globbing characters which should be treated verbatim. */ + if (directory_len > 0) + dequote_pathname (directory_name); + + /* We allocated a small array called RESULT, which we won't be using. + Free that memory now. */ + free (result); + + /* Just return what glob_vector () returns appended to the + directory name. */ + temp_results = + glob_vector (filename, (directory_len == 0 ? "." : directory_name)); + + if (temp_results == NULL || temp_results == (char **)&glob_error_return) + return (temp_results); + + return (glob_dir_to_array (directory_name, temp_results)); + } + + /* We get to memory_error if the program has run out of memory, or + if this is the shell, and we have been interrupted. */ + memory_error: + if (result != NULL) + { + register unsigned int i; + for (i = 0; result[i] != NULL; ++i) + free (result[i]); + free ((char *) result); + } +#if defined (SHELL) + if (interrupt_state) + throw_to_top_level (); +#endif /* SHELL */ + return (NULL); +} + +#if defined (TEST) + +main (argc, argv) + int argc; + char **argv; +{ + unsigned int i; + + for (i = 1; i < argc; ++i) + { + char **value = glob_filename (argv[i]); + if (value == NULL) + puts ("Out of memory."); + else if (value == &glob_error_return) + perror (argv[i]); + else + for (i = 0; value[i] != NULL; i++) + puts (value[i]); + } + + exit (0); +} +#endif /* TEST. */ @@ -3,8 +3,8 @@ ident.h - $Author: matz $ - $Revision: 1.1.1.1 $ - $Date: 1994/06/17 14:23:49 $ + $Revision: 1.2 $ + $Date: 1994/08/12 04:47:29 $ created at: Mon Jan 31 16:23:19 JST 1994 Copyright (C) 1994 Yukihiro Matsumoto @@ -3,7 +3,7 @@ inits.c - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/19 09:32:02 $ created at: Tue Dec 28 16:01:58 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -27,6 +27,7 @@ rb_call_inits() Init_Struct(); Init_String(); Init_Regexp(); + Init_Glob(); Init_pack(); Init_Range(); Init_IO(); @@ -3,7 +3,7 @@ io.c - $Author: matz $ - $Date: 1994/06/27 15:48:29 $ + $Date: 1994/08/12 11:06:40 $ created at: Fri Oct 15 18:08:59 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -21,7 +21,7 @@ VALUE rb_ad_string(); -VALUE C_IO; +VALUE C_IO, C_ARGFILE; extern VALUE C_File; VALUE rb_stdin, rb_stdout, rb_stderr, rb_defout; @@ -29,12 +29,12 @@ VALUE rb_stdin, rb_stdout, rb_stderr, rb_defout; VALUE FS, OFS; VALUE RS, ORS; -ID id_write; +ID id_write, id_fd, id_print_on; extern char *inplace; /* writing functions */ -static VALUE +VALUE Fio_write(obj, str) VALUE obj; struct RString *str; @@ -151,11 +151,11 @@ Fio_fileno(obj) VALUE obj; { OpenFile *fptr; - int f; + int fd; GetOpenFile(obj, fptr); - f = fileno(fptr->f); - return INT2FIX(f); + fd = fileno(fptr->f); + return INT2FIX(fd); } /* reading functions */ @@ -178,7 +178,7 @@ read_all(port) for (;;) { n = fread(buf, 1, BUFSIZ, fptr->f); if (n == 0) { - if (feof(fptr->f)) break; + if (feof(fptr->f)) return Qnil; rb_sys_fail(Qnil); } str_cat(str, buf, n); @@ -219,15 +219,6 @@ Fio_read(obj, args) return str; } -static void -io_gets(str) - VALUE str; -{ - rb_break(); -} - -void rb_each(); - VALUE rb_lastline; static VALUE lineno; @@ -660,12 +651,12 @@ Fprintf(argc, argv) { VALUE out; - if (argc == 1) return Qnil; - if (TYPE(argv[1]) == T_STRING) { + if (argc == 0) return Qnil; + if (TYPE(argv[0]) == T_STRING) { out = rb_defout; } - else if (obj_responds_to(argv[1], INT2FIX(id_write))) { - out = argv[1]; + else if (obj_responds_to(argv[0], INT2FIX(id_write))) { + out = argv[0]; argv++; argc--; } @@ -678,15 +669,6 @@ Fprintf(argc, argv) return Qnil; } -static void -obj_print(obj) - VALUE obj; -{ - int i; - - Fio_write(rb_defout, obj); -} - static VALUE Fprint(argc, argv) int argc; @@ -695,25 +677,32 @@ Fprint(argc, argv) int i; /* if no argument given, print recv */ - if (argc == 1) { - obj_print(argv[0]); + if (argc == 0) { + rb_funcall(Qself, id_print_on, 1, rb_defout); } else { - for (i=1; i<argc; i++) { - obj_print(argv[i]); - if (OFS && i>1) { - obj_print(OFS); + for (i=0; i<argc; i++) { + if (OFS && i>0) { + Fio_write(rb_defout, OFS); } + rb_funcall(argv[i], id_print_on, 1, rb_defout); } } if (ORS) { - obj_print(ORS); + Fio_write(rb_defout, ORS); } return Qnil; } static VALUE +Fprint_on(obj, port) + VALUE obj, port; +{ + return Fio_write(port, obj); +} + +static VALUE prep_stdio(f, mode) FILE *f; int mode; @@ -806,8 +795,7 @@ next_argv() } static VALUE -Fgets(obj) - VALUE obj; +Fgets() { VALUE line; @@ -827,8 +815,7 @@ Fgets(obj) } static VALUE -Feof(obj) - VALUE obj; +Feof() { if (init_p == 0 && !next_argv()) return TRUE; @@ -840,8 +827,7 @@ Feof(obj) } static VALUE -Fgetc(obj) - VALUE obj; +Fgetc() { return Fio_getc(rb_stdin); } @@ -1120,14 +1106,14 @@ Fsyscall(argc, argv) unsigned long arg[8]; #endif int retval = -1; - int i = 1; - int items = argc - 2; + int i = 0; + int items = argc - 1; /* This probably won't work on machines where sizeof(long) != sizeof(int) * or where sizeof(long) != sizeof(char*). But such machines will * not likely have syscall implemented either, so who cares? */ - argv++; /* skip SELF */ + arg[0] = NUM2INT(argv[0]); argv++; while (items--) { if (FIXNUM_P(*argv)) { @@ -1140,7 +1126,7 @@ Fsyscall(argc, argv) } i++; } - switch (argc-1) { + switch (argc) { case 0: Fail("Too few args to syscall"); case 1: @@ -1196,12 +1182,80 @@ Fsyscall(argc, argv) #endif /* atarist */ } if (retval == -1) rb_sys_fail(0); - return Qnil; + return INT2FIX(0); #else Fail("syscall() unimplemented"); #endif } +static VALUE +Farg_read(obj) + VALUE obj; +{ + VALUE str, str2; + + str = str_new(0, 0); + for (;;) { + retry: + if (!next_argv()) return Qnil; + str2 = Fio_read(file, Qnil); + if (str2 == Qnil && next_p != -1) { + Fio_close(file); + next_p = 1; + goto retry; + } + if (str2 == Qnil) break; + str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + } + + return str; +} + +static VALUE +Farg_getc() +{ + VALUE byte; + + retry: + if (!next_argv()) return Qnil; + byte = Fio_getc(file); + if (byte == Qnil && next_p != -1) { + Fio_close(file); + next_p = 1; + goto retry; + } + + return byte; +} + +static VALUE +Farg_each() +{ + VALUE str; + + while (str = Fgets()) { + rb_yield(str); + } + return Qnil; +} + +static VALUE +Farg_each_byte() +{ + VALUE byte; + + while (byte = Farg_getc()) { + rb_yield(byte); + } + return Qnil; +} + +static VALUE +Farg_to_s() +{ + return str_new2("$ARGF"); +} + extern VALUE M_Enumerable; VALUE rb_readonly_hook(); @@ -1209,19 +1263,25 @@ Init_IO() { extern VALUE C_Kernel; + id_write = rb_intern("write"); + id_fd = rb_intern("fd"); + id_print_on = rb_intern("print_on"); + rb_define_method(C_Kernel, "syscall", Fsyscall, -1); rb_define_method(C_Kernel, "open", Fopen, -2); rb_define_method(C_Kernel, "printf", Fprintf, -1); rb_define_method(C_Kernel, "print", Fprint, -1); rb_define_method(C_Kernel, "gets", Fgets, 0); - rb_define_method(C_Kernel, "eof", Feof, 0); rb_define_alias(C_Kernel,"readline", "gets"); + rb_define_method(C_Kernel, "eof", Feof, 0); rb_define_method(C_Kernel, "getc", Fgetc, 0); rb_define_method(C_Kernel, "select", Fselect, -2); rb_define_method(C_Kernel, "readlines", Freadlines, 0); + rb_define_method(C_Kernel, "print_on", Fprint_on, 1); + C_IO = rb_define_class("IO", C_Object); rb_include_module(C_IO, M_Enumerable); @@ -1245,7 +1305,9 @@ Init_IO() rb_define_method(C_IO, "sysread", Fio_sysread, 1); rb_define_method(C_IO, "fileno", Fio_fileno, 0); - rb_define_method(C_IO, "sync", Fio_sync, 0); + rb_define_alias(C_IO, "to_i", "fileno"); + + rb_define_method(C_IO, "sync", Fio_sync, 0); rb_define_method(C_IO, "sync=", Fio_set_sync, 1); rb_define_alias(C_IO, "readlines", "to_a"); @@ -1278,6 +1340,22 @@ Init_IO() rb_define_single_method(C_IO, "default", Fio_defget, 0); rb_define_single_method(C_IO, "default=", Fio_defset, 1); - id_write = rb_intern("write"); + C_ARGFILE = rb_define_class("ARGFILE", C_Object); + rb_include_module(C_ARGFILE, M_Enumerable); + + rb_define_variable("$ARGF", &C_ARGFILE, Qnil, rb_readonly_hook); + + rb_define_single_method(C_ARGFILE, "each", Farg_each, 0); + rb_define_single_method(C_ARGFILE, "each_byte", Farg_each_byte, 0); + + rb_define_single_method(C_ARGFILE, "read", Farg_read, 0); + rb_define_single_method(C_ARGFILE, "readlines", Freadlines, 0); + rb_define_single_method(C_ARGFILE, "gets", Fgets, 0); + rb_define_single_method(C_ARGFILE, "realine", Fgets, 0); + rb_define_single_method(C_ARGFILE, "getc", Farg_getc, 0); + rb_define_single_method(C_ARGFILE, "eof", Feof, 0); + + rb_define_single_method(C_ARGFILE, "to_s", Farg_to_s, 0); + Init_File(); } @@ -3,8 +3,8 @@ io.h - $Author: matz $ - $Revision: 1.1.1.1 $ - $Date: 1994/06/17 14:23:50 $ + $Revision: 1.3 $ + $Date: 1994/08/12 11:06:42 $ created at: Fri Nov 12 16:47:09 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -31,12 +31,14 @@ typedef struct { #define FMODE_READWRITE 3 #define FMODE_SYNC 4 -#define GetOpenFile(obj,fp) Get_Data_Struct(obj, "fd", OpenFile, fp) +extern ID id_fd; + +#define GetOpenFile(obj,fp) Get_Data_Struct(obj, id_fd, OpenFile, fp) void io_free_OpenFile(); #define MakeOpenFile(obj, fp) {\ - Make_Data_Struct(obj, "fd", OpenFile, Qnil, io_free_OpenFile, fp);\ + Make_Data_Struct(obj, id_fd, OpenFile, Qnil, io_free_OpenFile, fp);\ fp->f = fp->f2 = NULL;\ fp->mode = 0;\ fp->pid = 0;\ diff --git a/main.c b/main.c new file mode 100644 index 0000000000..0dee01c269 --- /dev/null +++ b/main.c @@ -0,0 +1,17 @@ +/************************************************ + + main.c - + + $Author: matz $ + $Date: 1994/08/19 09:32:03 $ + created at: Fri Aug 19 13:19:58 JST 1994 + +************************************************/ + +main(argc, argv, envp) + int argc; + char **argv, **envp; +{ + ruby_init(argc, argv, envp); + ruby_run(); +} @@ -3,7 +3,7 @@ math.c - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/12 04:47:35 $ created at: Tue Jan 25 14:12:56 JST 1994 Copyright (C) 1994 Yukihiro Matsumoto @@ -110,13 +110,15 @@ Init_Math() { M_Math = rb_define_module("Math"); - rb_define_mfunc(M_Math, "atan2", Fmath_atan2, 2); - rb_define_mfunc(M_Math, "cos", Fmath_cos, 1); - rb_define_mfunc(M_Math, "sin", Fmath_sin, 1); - rb_define_mfunc(M_Math, "tan", Fmath_tan, 1); + rb_define_method(M_Math, "atan2", Fmath_atan2, 2); + rb_define_method(M_Math, "cos", Fmath_cos, 1); + rb_define_method(M_Math, "sin", Fmath_sin, 1); + rb_define_method(M_Math, "tan", Fmath_tan, 1); - rb_define_mfunc(M_Math, "exp", Fmath_exp, 1); - rb_define_mfunc(M_Math, "log", Fmath_log, 1); - rb_define_mfunc(M_Math, "log10", Fmath_log10, 1); - rb_define_mfunc(M_Math, "sqrt", Fmath_sqrt, 1); + rb_define_method(M_Math, "exp", Fmath_exp, 1); + rb_define_method(M_Math, "log", Fmath_log, 1); + rb_define_method(M_Math, "log10", Fmath_log10, 1); + rb_define_method(M_Math, "sqrt", Fmath_sqrt, 1); + + rb_include_module(CLASS_OF(M_Math), M_Math); } diff --git a/methods.c b/methods.c deleted file mode 100644 index b085799a45..0000000000 --- a/methods.c +++ /dev/null @@ -1,152 +0,0 @@ -/************************************************ - - methods.c - - - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ - created at: Fri Oct 1 17:25:07 JST 1993 - - Copyright (C) 1994 Yukihiro Matsumoto - -************************************************/ - -#include "ruby.h" -#include "ident.h" -#include "env.h" -#include "node.h" -#include "methods.h" - -void method_free(); - -#define CACHE_SIZE 577 -#if 0 -#define EXPR1(c,m) (((int)(c)*(m))>>0) -#else -#define EXPR1(c,m) ((int)(c)^(m)) -#endif - -#define TRIAL 3 - -struct hash_entry { /* method hash table. */ - ID mid; /* method's id */ - struct RClass *class; /* receiver's class */ - struct RClass *origin; /* where method defined */ - struct SMethod *method; - int undef; -}; - -static struct hash_entry cache[CACHE_SIZE]; - -static struct SMethod* -search_method(class, id, origin) - struct RClass *class, **origin; - ID id; -{ - struct SMethod *body; - NODE *list; - - while (!st_lookup(class->m_tbl, id, &body)) { - class = class->super; - if (class == Qnil) return Qnil; - } - - if (body->origin) - *origin = body->origin; - else - *origin = class; - return body; -} - -NODE* -rb_get_method_body(class, id, envset) - struct RClass *class; - ID id; - int envset; -{ - int pos, i; - struct SMethod *method; - - /* is it in the method cache? */ - pos = EXPR1(class, id) % CACHE_SIZE; - if (cache[pos].class != class || cache[pos].mid != id) { - /* not in the cache */ - struct SMethod *body; - struct RClass *origin; - - if ((body = search_method(class, id, &origin)) == Qnil) { - return Qnil; - } - /* store in cache */ - cache[pos].mid = id; - cache[pos].class = class; - cache[pos].origin = origin; - cache[pos].method = body; - cache[pos].undef = body->undef; - } - - method = cache[pos].method; - if (cache[pos].undef) return Qnil; - if (envset) { - the_env->last_func = method->id; - the_env->last_class = cache[pos].origin; - } - return method->node; -} - -void -rb_alias(class, name, def) - struct RClass *class; - ID name, def; -{ - struct SMethod *body; - - if (st_lookup(class->m_tbl, name, &body)) { - if (verbose) { - Warning("redefine %s", rb_id2name(name)); - } - rb_clear_cache(body); - method_free(body); - } - body = search_method(class, def, &body); - body->count++; - st_insert(class->m_tbl, name, body); -} - -void -rb_clear_cache(body) - struct SMethod *body; -{ - int i; - - for (i = 0; i< CACHE_SIZE; i++ ) { - if (cache[i].method == body) { - cache[i].class = Qnil; - cache[i].mid = Qnil; - } - } -} - -void -rb_clear_cache2(class) - struct RClass *class; -{ - int i; - - for (i = 0; i< CACHE_SIZE; i++ ) { - if (cache[i].origin == class) { - cache[i].class = Qnil; - cache[i].mid = Qnil; - } - } -} - -void -method_free(body) - struct SMethod *body; -{ - body->count--; - if (body->count == 0) { - freenode(body->node); - free(body); - } -} @@ -2,9 +2,9 @@ methods.h - - $Author$ - $Revision$ - $Date$ + $Author: matz $ + $Revision: 1.2 $ + $Date: 1994/08/12 04:47:38 $ created at: Fri Jul 29 14:43:03 JST 1994 ************************************************/ @@ -60,7 +60,7 @@ strdup(str) tmp = xmalloc(len); if (tmp == NULL) return NULL; - bcopy(str, tmp, len); + memcpy(tmp, str, len); return tmp; } diff --git a/missing/strstr.c b/missing/strstr.c index ff28ebffd6..68f40f8260 100644 --- a/missing/strstr.c +++ b/missing/strstr.c @@ -14,7 +14,7 @@ */ #ifndef lint -static char rcsid[] = "$Header: /work/cvsroot/ruby/missing/strstr.c,v 1.1 1994/06/27 15:49:21 matz Exp $ SPRITE (Berkeley)"; +static char rcsid[] = "$Header: /usr/ext/cvsroot/ruby/missing/strstr.c,v 1.2 1994/08/12 04:48:34 matz Exp $ SPRITE (Berkeley)"; #endif /* not lint */ /* @@ -3,7 +3,7 @@ node.h - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/24 09:25:29 $ created at: Fri May 28 15:14:02 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -20,9 +20,9 @@ enum node_type { NODE_IF, NODE_CASE, NODE_WHEN, - NODE_UNLESS, NODE_WHILE, - NODE_UNTIL, + NODE_WHILE2, + NODE_EXNOT, NODE_DO, NODE_FOR, NODE_PROT, @@ -46,6 +46,7 @@ enum node_type { NODE_CONTINUE, NODE_RETURN, NODE_RETRY, + NODE_FAIL, NODE_YIELD, NODE_LVAR, NODE_GVAR, @@ -59,6 +60,7 @@ enum node_type { NODE_XSTR, NODE_XSTR2, NODE_DREGX, + NODE_DGLOB, NODE_ARGS, NODE_DEFN, NODE_DEFS, @@ -165,11 +167,14 @@ typedef struct node { #define NEW_SCOPE(b) newnode(NODE_SCOPE, local_tbl(),(b),local_cnt(0)) #define NEW_BLOCK(a) newnode(NODE_BLOCK,a,Qnil,Qnil) #define NEW_IF(c,t,e) newnode(NODE_IF,c,t,e) -#define NEW_UNLESS(c,t,e) newnode(NODE_UNLESS,c,t,e) +#define NEW_EXNOT(c) newnode(NODE_EXNOT,c,Qnil,Qnil) +#define NEW_UNLESS(c,t,e) newnode(NODE_IF,NEW_EXNOT(c),t,e) #define NEW_CASE(h,b) newnode(NODE_CASE,h,b,Qnil) #define NEW_WHEN(c,t,e) newnode(NODE_WHEN,c,t,e) #define NEW_WHILE(c,b) newnode(NODE_WHILE,c,b,Qnil) -#define NEW_UNTIL(c,b) newnode(NODE_UNTIL,c,b,Qnil) +#define NEW_UNTIL(c,b) newnode(NODE_WHILE,NEW_EXNOT(c),b,Qnil) +#define NEW_WHILE2(c,b) newnode(NODE_WHILE2,c,b,Qnil) +#define NEW_UNTIL2(c,b) newnode(NODE_WHILE2,NEW_EXNOT(c),b,Qnil) #define NEW_FOR(v,i,b) newnode(NODE_FOR,v,b,i) #define NEW_DO(v,i,b) newnode(NODE_DO,v,b,i) #define NEW_PROT(b,ex,en) newnode(NODE_PROT,b,ex,en) @@ -178,6 +183,7 @@ typedef struct node { #define NEW_CONT() newnode(NODE_CONTINUE,Qnil,Qnil,Qnil) #define NEW_RETRY() newnode(NODE_RETRY,Qnil,Qnil,Qnil) #define NEW_RET(s) newnode(NODE_RETURN,s,Qnil,Qnil) +#define NEW_FAIL(s) newnode(NODE_FAIL,s,Qnil,Qnil) #define NEW_YIELD(a) newnode(NODE_YIELD,a,Qnil,Qnil) #define NEW_LIST(a) NEW_ARRAY(a) #define NEW_QLIST(a) newnode(NODE_QLIST,a,Qnil,Qnil) @@ -186,7 +192,7 @@ typedef struct node { #define NEW_HASH(a) newnode(NODE_HASH,a,Qnil,Qnil) #define NEW_AND(a,b) newnode(NODE_AND,a,b,Qnil) #define NEW_OR(a,b) newnode(NODE_OR,a,b,Qnil) -#define NEW_MASGN(l,val) newnode(NODE_MASGN,l,val,Qnil) +#define NEW_MASGN(l,r) newnode(NODE_MASGN,l,r,Qnil) #define NEW_GASGN(v,val) newnode(NODE_GASGN,v,val,rb_global_entry(v)) #define NEW_LASGN(v,val) newnode(NODE_LASGN,v,val,local_cnt(v)) #define NEW_IASGN(v,val) newnode(NODE_IASGN,v,val,Qnil) @@ -217,7 +223,7 @@ typedef struct node { #define NEW_NIL() newnode(NODE_NIL,Qnil,Qnil,Qnil) NODE *newnode(); -NODE *rb_get_method_body(); +VALUE rb_method_booundp(); void freenode(); #endif @@ -3,7 +3,7 @@ numeric.c - $Author: matz $ - $Date: 1994/06/27 15:48:32 $ + $Date: 1994/08/12 04:47:41 $ created at: Fri Aug 13 18:33:09 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -11,7 +11,6 @@ ************************************************/ #include "ruby.h" -#include "env.h" #include <math.h> static ID coerce; @@ -25,12 +24,23 @@ VALUE C_Fixnum; extern VALUE C_Range; double big2dbl(); +VALUE +float_new(d) + double d; +{ + NEWOBJ(flt, struct RFloat); + OBJSETUP(flt, C_Float, T_FLOAT); + + flt->value = d; + return (VALUE)flt; +} + static -num_coerce_bin(this, other) - VALUE this, other; +num_coerce_bin(x, mid, y) + VALUE x, y; + ID mid; { - return rb_funcall(rb_funcall(other, coerce, 1, this), - the_env->last_func, 1, other); + return rb_funcall(rb_funcall(y, coerce, 1, x), mid, 1, y); } static VALUE @@ -57,6 +67,14 @@ Fnum_dot2(left, right) } static VALUE +Fnum_next(num) + VALUE num; +{ + num = rb_funcall(num, rb_intern("to_i"), 0); + return rb_funcall(num, '+', 1, INT2FIX(1)); +} + +VALUE Fnum_upto(from, to) VALUE from, to; { @@ -128,8 +146,15 @@ Fnum_divmod(x, y) { VALUE div, mod; - div = rb_funcall(x, '/', 1, y); - mod = rb_funcall(x, '%', 1, y); + div = rb_funcall(x, '/', 1, y); + if (TYPE(div) == T_FLOAT) { + double d = floor(RFLOAT(div)->value); + + if (RFLOAT(div)->value > d) { + div = float_new(d); + } + } + mod = rb_funcall(x, '%', 1, y); return assoc_new(div, mod); } @@ -140,28 +165,17 @@ Fnum_is_int(num) return FALSE; } -VALUE -float_new(flt) - double flt; -{ - NEWOBJ(flo, struct RFloat); - OBJSETUP(flo, C_Float, T_FLOAT); - - flo->value = flt; - return (VALUE)flo; -} - static VALUE -Fflo_new(flo) - struct RFloat *flo; +Fflo_new(flt) + struct RFloat *flt; { - Check_Type(flo, T_FLOAT); + Check_Type(flt, T_FLOAT); { - NEWOBJ(flo2, struct RFloat); - CLONESETUP(flo2, flo); + NEWOBJ(flt2, struct RFloat); + CLONESETUP(flt2, flt); - flo2->value = flo->value; - return (VALUE)flo2; + flt2->value = flt->value; + return (VALUE)flt2; } } @@ -177,18 +191,18 @@ Fflo_to_s(flt) } static VALUE -Fflo_coerce(this, other) - VALUE this, other; +Fflo_coerce(x, y) + VALUE x, y; { - switch (TYPE(other)) { + switch (TYPE(y)) { case T_FIXNUM: - return float_new((double)FIX2INT(other)); + return float_new((double)FIX2INT(y)); case T_FLOAT: - return other; + return y; case T_BIGNUM: - return Fbig_to_f(other); + return Fbig_to_f(y); default: - Fail("can't coerce %s to Float", rb_class2name(CLASS_OF(other))); + Fail("can't coerce %s to Float", rb_class2name(CLASS_OF(y))); } /* not reached */ return Qnil; @@ -215,7 +229,7 @@ Fflo_plus(x, y) case T_STRING: return Fstr_plus(obj_as_string(x), y); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '+', y); } } @@ -231,7 +245,7 @@ Fflo_minus(x, y) case T_FLOAT: return float_new(x->value - y->value); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '-', y); } } @@ -249,7 +263,7 @@ Fflo_mul(x, y) case T_STRING: return Fstr_times(y, INT2FIX((int)x->value)); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '*', y); } } @@ -273,7 +287,7 @@ Fflo_div(x, y) if (y->value == 0.0) Fail("devided by 0"); return float_new(x->value / y->value); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '/', y); } } @@ -294,7 +308,7 @@ Fflo_mod(x, y) value = y->value; break; default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '%', y); } #ifdef HAVE_FMOD { @@ -324,7 +338,7 @@ Fflo_pow(x, y) case T_FLOAT: return float_new(pow(x->value, y->value)); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, rb_intern("**"), y); } } @@ -343,7 +357,7 @@ Fflo_eq(x, y) case T_FLOAT: return (x->value == y->value)?TRUE:FALSE; default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, rb_intern("=="), y); } } @@ -385,7 +399,7 @@ Fflo_cmp(x, y) break; default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, rb_intern("<=>"), y); } if (a == b) return INT2FIX(0); if (a > b) return INT2FIX(1); @@ -430,6 +444,20 @@ Fflo_abs(flt) return float_new(val); } +static VALUE +to_integer(val) + VALUE val; +{ + return rb_funcall(val, to_i, 0); +} + +static VALUE +fail_to_integer(val) + VALUE val; +{ + Fail("failed to convert %s into integer", rb_class2name(CLASS_OF(val))); +} + int num2int(val) VALUE val; @@ -444,7 +472,7 @@ num2int(val) case T_FLOAT: if (RFLOAT(val)->value <= (double) LONG_MAX && RFLOAT(val)->value >= (double) LONG_MIN) { - return (int)RFLOAT(val)->value; + return (int)(RFLOAT(val)->value); } else { Fail("float %g out of rang of integer", RFLOAT(val)->value); @@ -455,25 +483,11 @@ num2int(val) return big2int(val); default: - Fail("failed to convert %s into int", rb_class2name(CLASS_OF(val))); - break; + val = rb_resque(to_integer, val, fail_to_integer, val); + return NUM2INT(val); } } -static VALUE -to_fixnum(val) - VALUE val; -{ - return rb_funcall(val, to_i, 0); -} - -static VALUE -fail_to_fixnum(val) - VALUE val; -{ - Fail("failed to convert %s into fixnum", rb_class2name(CLASS_OF(val))); -} - VALUE num2fix(val) VALUE val; @@ -487,13 +501,11 @@ num2fix(val) case T_FLOAT: case T_BIGNUM: + default: v = num2int(val); if (!FIXABLE(v)) Fail("integer %d out of rang of Fixnum", v); return INT2FIX(v); - - default: - return rb_resque(to_fixnum, val, fail_to_fixnum, val); } } @@ -579,7 +591,7 @@ Ffix_plus(x, y) case T_FLOAT: return float_new((double)FIX2INT(x) + y->value); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '+', y); } } @@ -607,7 +619,7 @@ Ffix_minus(x, y) case T_FLOAT: return float_new((double)FIX2INT(x) - y->value); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '-', y); } } @@ -631,7 +643,7 @@ Ffix_mul(x, y) case T_FLOAT: return float_new((double)FIX2INT(x) * y->value); default: - return num_coerce_bin(x, y); + return num_coerce_bin(x, '*', y); } } @@ -648,7 +660,7 @@ Ffix_div(x, y) i = FIX2INT(x)/i; return INT2FIX(i); } - return num_coerce_bin(x, y); + return num_coerce_bin(x, '/', y); } static VALUE @@ -663,7 +675,7 @@ Ffix_mod(x, y) i = FIX2INT(x)%i; return INT2FIX(i); } - return num_coerce_bin(x, y); + return num_coerce_bin(x, '%', y); } static VALUE @@ -686,7 +698,7 @@ Ffix_pow(x, y) else if (NIL_P(y)) { return INT2FIX(1); } - return num_coerce_bin(x, y); + return num_coerce_bin(x, rb_intern("**"), y); } static VALUE @@ -700,7 +712,7 @@ Ffix_equal(x, y) return Qnil; } else { - return num_coerce_bin(x, y); + return num_coerce_bin(x, rb_intern("=="), y); } } @@ -716,7 +728,7 @@ Ffix_cmp(x, y) return INT2FIX(-1); } else { - return num_coerce_bin(x, y); + return num_coerce_bin(x, rb_intern("<=>"), y); } } @@ -861,6 +873,15 @@ Ffix_id2name(fix) return Qnil; } +static VALUE +Ffix_next(fix) + VALUE fix; +{ + int i = FIX2INT(fix) + 1; + + return int2inum(i); +} + extern VALUE M_Comparable; extern Fkrn_inspect(); @@ -874,7 +895,9 @@ Init_Numeric() rb_define_method(C_Numeric, "+@", Fnum_uplus, 0); rb_define_method(C_Numeric, "-@", Fnum_uminus, 0); rb_define_method(C_Numeric, "..", Fnum_dot2, 1); + rb_define_method(C_Numeric, "divmod", Fnum_divmod, 1); + rb_define_method(C_Numeric, "next", Fnum_next, 0); rb_define_method(C_Numeric, "upto", Fnum_upto, 1); rb_define_method(C_Numeric, "downto", Fnum_downto, 1); rb_define_method(C_Numeric, "step", Fnum_step, 2); @@ -919,6 +942,8 @@ Init_Numeric() rb_define_method(C_Fixnum, "to_i", Ffix_to_i, 0); rb_define_method(C_Fixnum, "to_f", Ffix_to_f, 0); + rb_define_method(C_Fixnum, "next", Ffix_next, 0); + C_Float = rb_define_class("Float", C_Numeric); rb_define_single_method(C_Float, "new", Fflo_new, 1); rb_define_method(C_Float, "clone", Fflo_clone, 0); @@ -3,7 +3,7 @@ object.c - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/12 04:47:42 $ created at: Thu Jul 15 12:01:24 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -27,7 +27,6 @@ VALUE C_Method; struct st_table *new_idhash(); VALUE Fsprintf(); -VALUE Ffail(); VALUE Fexit(); VALUE Feval(); VALUE Fapply(); @@ -274,6 +273,13 @@ Fmain_to_s(obj) return str_new2("main"); } +static VALUE +Ftrue_to_s(obj) + VALUE obj; +{ + return str_new2("t"); +} + VALUE obj_alloc(class) VALUE class; @@ -335,6 +341,7 @@ static VALUE boot_defclass(name, super) } VALUE TopSelf; +VALUE TRUE = 1; Init_Object() { @@ -351,31 +358,33 @@ Init_Object() metaclass = RBASIC(C_Class)->class = single_class_new(metaclass); /* + * Ruby's Class Hierarchy Chart + * * +-------nil +---------------------+ * | ^ | | * | | | | * | Kernel----->(Kernel) | * | ^ ^ ^ ^ | * | | | | | | - * | +---+ +-----+ | +---+ | - * | | +------|---+ | | - * | | | | | | + * | +---+ +----+ | +---+ | + * | | +-----|----+ | | + * | | | | | | * +->Nil->(Nil) Object---->(Object) | - * ^ ^ ^ ^ | - * | | | | | - * | | +-------+ | | - * | | | | | - * | +---------+ +------+ | - * | | | | | - * +--------+ | Module--->(Module) | + * ^ ^ ^ ^ | + * | | | | | + * | | +-------+ | | + * | | | | | + * | +---------+ +------+ | + * | | | | | + * +---------+ | Module--->(Module) | * | | ^ ^ | * OtherClass-->(OtherClass) | | | * Class---->(Class) | - * ^ | - * | | - * +-----+ + * ^ | + * | | + * +----------------+ * - * + all metaclasses are instance of class Class + * + All metaclasses are instances of the class `Class'. */ rb_define_method(C_Kernel, "is_nil", P_false, 0); @@ -393,8 +402,9 @@ Init_Object() rb_define_method(C_Kernel, "to_s", Fkrn_to_s, 0); rb_define_method(C_Kernel, "_inspect", Fkrn_inspect, 0); +#ifdef USE_CALLER rb_define_method(C_Kernel, "caller", Fcaller, -2); - rb_define_method(C_Kernel, "fail", Ffail, -2); +#endif rb_define_method(C_Kernel, "exit", Fexit, -2); rb_define_method(C_Kernel, "eval", Feval, 1); rb_define_method(C_Kernel, "defined", Fdefined, 1); @@ -404,9 +414,6 @@ Init_Object() rb_define_method(C_Kernel, "apply", Fapply, -2); - rb_define_const(C_Kernel, "%TRUE", TRUE); - rb_define_const(C_Kernel, "%FALSE", FALSE); - rb_define_method(C_Object, "_inspect", Fobj_inspect, 0); rb_define_method(C_Object, "responds_to", obj_responds_to, 1); @@ -443,4 +450,10 @@ Init_Object() Qself = TopSelf = obj_alloc(C_Object); rb_define_single_method(TopSelf, "to_s", Fmain_to_s, 0); + + TRUE = obj_alloc(C_Object); + rb_define_single_method(TRUE, "to_s", Ftrue_to_s, 0); + rb_define_const(C_Kernel, "%TRUE", TRUE); + rb_define_const(C_Kernel, "%FALSE", FALSE); } + @@ -3,7 +3,7 @@ pack.c - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/12 04:47:44 $ created at: Thu Feb 10 15:17:05 JST 1994 Copyright (C) 1994 Yukihiro Matsumoto @@ -76,7 +76,7 @@ Fpck_pack(ary, fmt) type = *p++; /* get data type */ if (*p == '*') { /* set data length */ - len = index("@Xxu", type) ? 0 : items; + len = strchr("@Xxu", type) ? 0 : items; p++; } else if (isdigit(*p)) { @@ -773,13 +773,15 @@ Fpck_unpack(str, fmt) { VALUE str = str_new(0, (send - s)*3/4); char *ptr = RSTRING(str)->ptr; + int total = 0; while (s < send && *s > ' ' && *s < 'a') { - int a,b,c,d; + long a,b,c,d; char hunk[4]; hunk[3] = '\0'; len = (*s++ - ' ') & 077; + total += len; while (len > 0) { if (s < send && *s >= ' ') a = (*s++ - ' ') & 077; @@ -804,11 +806,12 @@ Fpck_unpack(str, fmt) ptr += 3; len -= 3; } - if (s[0] == '\n') + if (*s == '\n') s++; else if (s[1] == '\n') /* possible checksum byte */ s += 2; } + RSTRING(str)->len = total; Fary_push(ary, str); } break; @@ -3,7 +3,7 @@ parse.y - $Author: matz $ - $Date: 1994/06/27 15:48:34 $ + $Date: 1994/08/25 09:21:07 $ created at: Fri May 28 18:02:42 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -34,19 +34,18 @@ struct op_tbl { }; NODE *eval_tree = Qnil; -static int in_regexp; char *sourcefile; /* current source file */ int sourceline; /* current line no. */ -enum { - KEEP_STATE = 0, /* don't change lex_state. */ +static int yylex(); + +static enum lex_state { EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_MID, /* newline significant, +/- is a sign. */ - EXPR_END, /* +/- is a operator. newline significant */ -}; - -static int lex_state; + EXPR_END, /* newline significant, +/- is a operator. */ + EXPR_FNAME, /* ignore newline, +/- is a operator. */ +} lex_state; static ID cur_class = Qnil, cur_mid = Qnil; static int in_module, in_single; @@ -59,6 +58,7 @@ static NODE *block_append(); static NODE *list_append(); static NODE *list_concat(); static NODE *list_copy(); +static NODE *expand_op(); static NODE *call_op(); static NODE *gettable(); @@ -100,8 +100,6 @@ static void setup_top_local(); WHILE FOR IN - DO - USING PROTECT RESQUE ENSURE @@ -110,6 +108,7 @@ static void setup_top_local(); BREAK CONTINUE RETURN + FAIL YIELD SUPER RETRY @@ -117,20 +116,24 @@ static void setup_top_local(); NIL _FILE_ _LINE_ + IF_MOD + UNLESS_MOD + WHILE_MOD + UNTIL_MOD %token <id> IDENTIFIER GVAR IVAR CONSTANT -%token <val> INTEGER FLOAT STRING XSTRING REGEXP -%token <node> STRING2 XSTRING2 DREGEXP +%token <val> INTEGER FLOAT STRING XSTRING REGEXP GLOB +%token <node> STRING2 XSTRING2 DREGEXP DGLOB %type <node> singleton inc_list %type <val> literal numeric -%type <node> compexpr exprs expr expr2 primary var_ref -%type <node> if_tail opt_else cases resque ensure opt_using -%type <node> call_args opt_args args f_arglist f_args f_arg -%type <node> assoc_list assocs assoc regexp -%type <node> mlhs mlhs_head mlhs_tail lhs +%type <node> compstmts stmts stmt stmt0 expr expr0 var_ref +%type <node> if_tail opt_else cases resque ensure +%type <node> call_args call_args0 opt_args args args2 +%type <node> f_arglist f_args f_arg assoc_list assocs assoc +%type <node> mlhs mlhs_head mlhs_tail lhs iter_var opt_iter_var %type <id> superclass variable symbol -%type <id> fname fname0 op rest_arg end_mark +%type <id> fname fname0 op rest_arg %token UPLUS /* unary+ */ %token UMINUS /* unary- */ @@ -148,12 +151,13 @@ static void setup_top_local(); %token COLON2 /* :: */ %token <id> SELF_ASGN /* +=, -= etc. */ %token ASSOC /* => */ +%token LPAREN LBRACK LBRACE /* * precedence table */ -%left YIELD RETURN +%left YIELD RETURN FAIL %right '=' SELF_ASGN %right COLON2 %nonassoc DOT2 DOT3 @@ -176,42 +180,43 @@ program : { lex_state = EXPR_BEG; init_top_local(); } - compexpr + compstmts { eval_tree = block_append(eval_tree, $2); setup_top_local(); } -compexpr : exprs opt_term +compstmts : stmts opt_term -exprs : /* none */ +stmts : /* none */ { $$ = Qnil; } - | expr - | exprs term expr + | stmt + | stmts term stmt { $$ = block_append($1, $3); } - | exprs error expr + | stmts error + { + lex_state = EXPR_BEG; + } + stmt { yyerrok; - $$ = $1; + $$ = block_append($1, $4); } -expr : CLASS IDENTIFIER superclass +stmt : CLASS IDENTIFIER superclass { if (cur_class || cur_mid || in_single) Error("nested class definition"); cur_class = $2; push_local(); } - compexpr - END end_mark + compstmts + END { - if ($7 && $7 != CLASS) { - Error("unmatched end keyword(expected `class')"); - } $$ = NEW_CLASS($2, $5, $3); pop_local(); cur_class = Qnil; @@ -224,12 +229,9 @@ expr : CLASS IDENTIFIER superclass in_module = 1; push_local(); } - compexpr - END end_mark + compstmts + END { - if ($6 && $6 != MODULE) { - Error("unmatched end keyword(expected `module')"); - } $$ = NEW_MODULE($2, $4); pop_local(); cur_class = Qnil; @@ -242,12 +244,9 @@ expr : CLASS IDENTIFIER superclass cur_mid = $2; push_local(); } - f_arglist compexpr - END end_mark + f_arglist compstmts + END { - if ($7 && $7 != DEF) { - Error("unmatched end keyword(expected `def')"); - } $$ = NEW_DEFN($2, NEW_RFUNC($4, $5)); pop_local(); cur_mid = Qnil; @@ -259,12 +258,9 @@ expr : CLASS IDENTIFIER superclass push_local(); } f_arglist - compexpr - END end_mark + compstmts + END { - if ($9 && $9 != DEF) { - Error("unmatched end keyword(expected `def')"); - } $$ = NEW_DEFS($2, $4, NEW_RFUNC($6, $7)); pop_local(); in_single--; @@ -283,40 +279,113 @@ expr : CLASS IDENTIFIER superclass Error("include appeared in method definition"); $$ = $2; } - | mlhs '=' args + | stmt0 IF_MOD stmt0 { - NODE *rhs; - - if ($3->nd_next == Qnil) { - rhs = $3->nd_head; - free($3); - } - else { - rhs = $3; - } - - $$ = NEW_MASGN($1, rhs); + $$ = NEW_IF(cond($3), $1, Qnil); + } + | stmt0 UNLESS_MOD stmt0 + { + $$ = NEW_UNLESS(cond($3), $1, Qnil); } - | expr2 + | stmt0 WHILE_MOD stmt0 + { + $$ = NEW_WHILE2(cond($3), $1); + } + | stmt0 UNTIL_MOD stmt0 + { + $$ = NEW_UNTIL2(cond($3), $1); + } + | stmt0 +stmt0 : mlhs '=' args2 + { + $1->nd_value = $3; + $$ = $1; + } + | REDO + { + $$ = NEW_REDO(); + } + | BREAK + { + $$ = NEW_BREAK(); + } + | CONTINUE + { + $$ = NEW_CONT(); + } + | RETRY + { + $$ = NEW_RETRY(); + } + | RETURN args2 + { + value_expr($2); + if (!cur_mid && !in_single) + Error("return appeared outside of method"); + $$ = NEW_RET($2); + } + | RETURN + { + if (!cur_mid && !in_single) + Error("return appeared outside of method"); + $$ = NEW_RET(Qnil); + } + | FAIL args2 + { + value_expr($2); + $$ = NEW_FAIL($2); + } + | YIELD args2 + { + value_expr($2); + $$ = NEW_YIELD($2); + } + | IDENTIFIER call_args0 + { + $$ = NEW_CALL(Qnil, $1, $2); + } + | expr0 '.' IDENTIFIER call_args0 + { + value_expr($1); + $$ = NEW_CALL($1, $3, $4); + } + | SUPER call_args0 + { + if (!cur_mid && !in_single) + Error("super called outside of method"); + $$ = NEW_SUPER($2); + } + | expr mlhs : mlhs_head + { + $$ = NEW_MASGN(NEW_LIST($1),Qnil); + } + | mlhs_head '*' lhs + { + $$ = NEW_MASGN(NEW_LIST($1),$3); + } | mlhs_head mlhs_tail { - $$ = list_concat($1, $2); + $$ = NEW_MASGN(list_concat(NEW_LIST($1),$2),Qnil); + } + | mlhs_head mlhs_tail comma '*' lhs + { + $$ = NEW_MASGN(list_concat(NEW_LIST($1),$2),$5); } mlhs_head : variable comma { - $$ = NEW_LIST(asignable($1, Qnil)); + $$ = asignable($1, Qnil); } - | primary '[' args rbracket comma + | expr0 '[' args rbracket comma { - $$ = NEW_LIST(aryset($1, $3, Qnil)); + $$ = aryset($1, $3, Qnil); } - | primary '.' IDENTIFIER comma + | expr0 '.' IDENTIFIER comma { - $$ = NEW_LIST(attrset($1, $3, Qnil)); + $$ = attrset($1, $3, Qnil); } mlhs_tail : lhs @@ -332,11 +401,11 @@ lhs : variable { $$ = asignable($1, Qnil); } - | primary '[' args rbracket + | expr0 '[' args rbracket { $$ = aryset($1, $3, Qnil); } - | primary '.' IDENTIFIER + | expr0 '.' IDENTIFIER { $$ = attrset($1, $3, Qnil); } @@ -360,23 +429,24 @@ inc_list : IDENTIFIER } | error { + lex_state = EXPR_BEG; $$ = Qnil; } | inc_list comma error + { + lex_state = EXPR_BEG; + $$ = $1; + } fname : fname0 | IVAR fname0 : IDENTIFIER - | IDENTIFIER '=' + | op { - ID id = $1; - - id &= ~ID_SCOPE_MASK; - id |= ID_ATTRSET; - $$ = id; + lex_state = EXPR_END; + $$ = $1; } - | op op : COLON2 { $$ = COLON2; } | DOT2 { $$ = DOT2; } @@ -402,12 +472,10 @@ op : COLON2 { $$ = COLON2; } | POW { $$ = POW; } | '!' { $$ = '!'; } | '~' { $$ = '~'; } - | '!' '@' { $$ = '!'; } - | '~' '@' { $$ = '~'; } - | '-' '@' { $$ = UMINUS; } - | '+' '@' { $$ = UPLUS; } - | '[' ']' { $$ = AREF; } - | '[' ']' '=' { $$ = ASET; } + | UPLUS { $$ = UMINUS; } + | UMINUS { $$ = UPLUS; } + | AREF { $$ = AREF; } + | ASET { $$ = ASET; } f_arglist : '(' f_args rparen { @@ -444,10 +512,12 @@ f_args : /* no arg */ } | f_arg error { + lex_state = EXPR_BEG; $$ = NEW_ARGS($1, -1); } | error { + lex_state = EXPR_BEG; $$ = Qnil; } @@ -485,7 +555,7 @@ singleton : var_ref $$ = $1; } } - | '(' compexpr rparen + | LPAREN compstmts rparen { switch ($2->type) { case NODE_STR: @@ -499,130 +569,22 @@ singleton : var_ref $$ = $2; } -expr2 : IF expr2 then - compexpr - if_tail - END end_mark - { - if ($7 && $7 != IF) { - Error("unmatched end keyword(expected `if')"); - } - $$ = NEW_IF(cond($2), $4, $5); - } - | UNLESS expr2 then - compexpr opt_else END end_mark - { - if ($7 && $7 != UNLESS) { - Error("unmatched end keyword(expected `if')"); - } - $$ = NEW_UNLESS(cond($2), $4, $5); - } - | CASE expr2 opt_term - cases - END end_mark - { - if ($6 && $6 != CASE) { - Error("unmatched end keyword(expected `case')"); - } - value_expr($2); - $$ = NEW_CASE($2, $4); - } - | WHILE expr2 term compexpr END end_mark - { - if ($6 && $6 != WHILE) { - Error("unmatched end keyword(expected `while')"); - } - $$ = NEW_WHILE(cond($2), $4); - } - | UNTIL expr2 term compexpr END end_mark - { - if ($6 && $6 != UNTIL) { - Error("unmatched end keyword(expected `until')"); - } - $$ = NEW_UNTIL(cond($2), $4); - } - | FOR lhs IN expr2 term - compexpr - END end_mark - { - if ($8 && $8 != FOR) { - Error("unmatched end keyword(expected `for')"); - } - value_expr($4); - $$ = NEW_FOR($2, $4, $6); - } - | DO expr2 opt_using - compexpr - END end_mark - { - if ($6 && $6 != DO) { - Error("unmatched end keyword(expected `do')"); - } - value_expr($2); - $$ = NEW_DO($3, $2, $4); - } - | PROTECT - compexpr - resque - ensure - END end_mark - { - if ($6 && $6 != PROTECT) { - Error("unmatched end keyword(expected `protect')"); - } - if ($3 == Qnil && $4 == Qnil) { - Warning("useless protect clause"); - $$ = $2; - } - else { - $$ = NEW_PROT($2, $3, $4); - } - } - | REDO - { - $$ = NEW_REDO(); - } - | BREAK - { - $$ = NEW_BREAK(); - } - | CONTINUE - { - $$ = NEW_CONT(); - } - | RETRY - { - $$ = NEW_RETRY(); - } - | RETURN expr2 - { - value_expr($2); - if (!cur_mid && !in_single) - Error("return appeared outside of method"); - $$ = NEW_RET($2); - } - | RETURN - { - if (!cur_mid && !in_single) - Error("return appeared outside of method"); - $$ = NEW_RET(Qnil); - } - | variable '=' expr2 +expr : variable '=' expr { value_expr($3); $$ = asignable($1, $3); } - | primary '[' args rbracket '=' expr2 + | expr0 '[' args rbracket '=' expr { value_expr($6); $$ = aryset($1, $3, $6); } - | primary '.' IDENTIFIER '=' expr2 + | expr0 '.' IDENTIFIER '=' expr { value_expr($5); $$ = attrset($1, $3, $5); } - | variable SELF_ASGN expr2 + | variable SELF_ASGN expr { NODE *val; @@ -641,7 +603,7 @@ expr2 : IF expr2 then } $$ = asignable($1, call_op(val, $2, 1, $3)); } - | primary '[' args rbracket SELF_ASGN expr2 + | expr0 '[' args rbracket SELF_ASGN expr { NODE *rval, *args; value_expr($1); @@ -653,7 +615,7 @@ expr2 : IF expr2 then args = list_append($3, call_op(rval, $5, 1, $6)); $$ = NEW_CALL($1, ASET, args); } - | primary '.' IDENTIFIER SELF_ASGN expr2 + | expr0 '.' IDENTIFIER SELF_ASGN expr { ID id = $3; NODE *rval; @@ -667,202 +629,163 @@ expr2 : IF expr2 then rval = call_op(NEW_CALL2($1, $3, Qnil), $4, 1, $5); $$ = NEW_CALL($1, id, NEW_LIST(rval)); } - | YIELD expr2 - { - value_expr($2); - $$ = NEW_YIELD($2); - } - | expr2 DOT2 expr2 + | expr DOT2 expr { $$ = call_op($1, DOT2, 1, $3); } - | expr2 DOT3 expr2 + | expr DOT3 expr { $$ = NEW_DOT3(cond2($1), cond2($3)); } - | expr2 '+' expr2 + | expr '+' expr { - $$ = call_op($1, '+', 1, $3); + $$ = Qnil; + if ($1 && $3 + && ($3->type == NODE_LIT || $3->type == NODE_STR) + && $1->type == NODE_CALL && $1->nd_mid == '+') { + if ($1->nd_args->nd_head == Qnil) + Bug("bad operand for `+'"); + if ($1->nd_args->nd_head->type == NODE_LIT + || $1->nd_args->nd_head->type == NODE_STR) { + $1->nd_args->nd_head = + expand_op($1->nd_args->nd_head, '+', $3); + $$ = $1; + } + } + if ($$ == Qnil) { + $$ = call_op($1, '+', 1, $3); + } } - | expr2 '-' expr2 + | expr '-' expr { $$ = call_op($1, '-', 1, $3); } - | expr2 '*' expr2 + | expr '*' expr { $$ = call_op($1, '*', 1, $3); } - | expr2 '/' expr2 + | expr '/' expr { $$ = call_op($1, '/', 1, $3); } - | expr2 '%' expr2 + | expr '%' expr { $$ = call_op($1, '%', 1, $3); } - | expr2 POW expr2 + | expr POW expr { $$ = call_op($1, POW, 1, $3); } - | '+' expr2 %prec UPLUS + | UPLUS expr { $$ = call_op($2, UPLUS, 0); - } - | '-' expr2 %prec UMINUS + | UMINUS expr { $$ = call_op($2, UMINUS, 0); } - | expr2 '|' expr2 + | expr '|' expr { $$ = call_op($1, '|', 1, $3); } - | expr2 '^' expr2 + | expr '^' expr { $$ = call_op($1, '^', 1, $3); } - | expr2 '&' expr2 + | expr '&' expr { $$ = call_op($1, '&', 1, $3); } - | expr2 CMP expr2 + | expr CMP expr { $$ = call_op($1, CMP, 1, $3); } - | expr2 '>' expr2 + | expr '>' expr { $$ = call_op($1, '>', 1, $3); } - | expr2 GEQ expr2 + | expr GEQ expr { $$ = call_op($1, GEQ, 1, $3); } - | expr2 '<' expr2 + | expr '<' expr { $$ = call_op($1, '<', 1, $3); } - | expr2 LEQ expr2 + | expr LEQ expr { $$ = call_op($1, LEQ, 1, $3); } - | expr2 EQ expr2 + | expr EQ expr { $$ = call_op($1, EQ, 1, $3); } - | expr2 NEQ expr2 + | expr NEQ expr { $$ = call_op($1, NEQ, 1, $3); } - | expr2 MATCH expr2 + | expr MATCH expr { $$ = call_op($1, MATCH, 1, $3); } - | expr2 NMATCH expr2 + | expr NMATCH expr { $$ = call_op($1, NMATCH, 1, $3); } - | '!' expr2 + | '!' expr { - $$ = call_op(cond($2), '!', 0); + $$ = call_op($2, '!', 0); } - | '~' expr2 + | '~' expr { - $$ = call_op($2, '~', 0); + if ($2 + && ($2->type == NODE_STR + || ($2->type == NODE_LIT + && (TYPE($2->nd_lit) == T_REGEXP + || TYPE($2->nd_lit) == T_STRING)))) { + $$ = NEW_CALL($2, '~', Qnil); + } + else { + $$ = call_op($2, '~', 0); + } } - | expr2 LSHFT expr2 + | expr LSHFT expr { $$ = call_op($1, LSHFT, 1, $3); } - | expr2 RSHFT expr2 + | expr RSHFT expr { $$ = call_op($1, RSHFT, 1, $3); } - | expr2 COLON2 expr2 + | expr COLON2 expr { $$ = call_op($1, COLON2, 1, $3); } - | expr2 AND expr2 + | expr AND expr { - $$ = NEW_AND(cond($1), cond($3)); + $$ = NEW_AND($1, $3); } - | expr2 OR expr2 + | expr OR expr { - $$ = NEW_OR(cond($1), cond($3)); + $$ = NEW_OR($1, $3); } - |primary + |expr0 { $$ = $1; } -then : term - | THEN - | term THEN - -if_tail : opt_else - | ELSIF expr2 then - compexpr - if_tail - { - $$ = NEW_IF(cond($2), $4, $5); - } - -opt_else : /* none */ - { - $$ = Qnil; - } - | ELSE compexpr - { - $$ = $2; - } - -opt_using : term - { - $$ = Qnil; - } - | opt_term USING lhs term - { - $$ = $3; - } - -cases : opt_else - | WHEN args term - compexpr - cases - { - $$ = NEW_WHEN($2, $4, $5); - } - -resque : /* none */ - { - $$ = Qnil; - } - | RESQUE compexpr - { - if ($2 == Qnil) - $$ = (NODE*)1; - else - $$ = $2; - } - -ensure : /* none */ - { - $$ = Qnil; - } - | ENSURE compexpr - { - $$ = $2; - } - call_args : /* none */ { $$ = Qnil; } - | args - | '*' exprs + | call_args0 + | '*' expr { $$ = $2; } - | args comma '*' exprs + +call_args0 : args + | args comma '*' expr { $$ = call_op($1, '+', 1, $4); } @@ -873,19 +796,31 @@ opt_args : /* none */ } | args -args : expr2 +args : expr { value_expr($1); $$ = NEW_LIST($1); } - | args comma expr2 + | args comma expr { value_expr($3); $$ = list_append($1, $3); } -primary : var_ref - | literal +args2 : args + { + NODE *rhs; + + if ($1 && $1->nd_next == Qnil) { + $$ = $1->nd_head; + free($1); + } + else { + $$ = $1; + } + } + +expr0 : literal { literalize($1); $$ = NEW_LIT($1); @@ -902,16 +837,36 @@ primary : var_ref $$ = NEW_XSTR($1); } | XSTRING2 - | '/' {in_regexp = 1;} regexp + | DREGEXP + | DGLOB + | var_ref + | IDENTIFIER '(' call_args rparen + { + $$ = NEW_CALL(Qnil, $1, $3); + } + | IVAR '(' call_args rparen + { + $$ = NEW_CALL(Qnil, $1, $3); + } + | SUPER '(' call_args rparen + { + if (!cur_mid && !in_single) + Error("super called outside of method"); + $$ = NEW_SUPER($3); + } + | SUPER { - $$ = $3; + if (!cur_mid && !in_single) + Error("super called outside of method"); + $$ = NEW_ZSUPER(); } - | primary '[' args rbracket + + | expr0 '[' args rbracket { value_expr($1); $$ = NEW_CALL($1, AREF, $3); } - | '[' opt_args rbracket + | LBRACK opt_args rbracket { if ($2 == Qnil) $$ = NEW_ZARRAY(); /* zero length array*/ @@ -919,41 +874,158 @@ primary : var_ref $$ = $2; } } - | lbrace assoc_list rbrace + | LBRACE assoc_list rbrace { $$ = NEW_HASH($2); } - | primary '.' IDENTIFIER '(' call_args rparen + | FAIL '(' args2 ')' + { + value_expr($3); + $$ = NEW_FAIL($3); + } + | FAIL '(' ')' + { + $$ = NEW_FAIL(Qnil); + } + | FAIL + { + $$ = NEW_FAIL(Qnil); + } + | YIELD '(' args2 ')' + { + value_expr($3); + $$ = NEW_YIELD($3); + } + | YIELD '(' ')' + { + $$ = NEW_YIELD(Qnil); + } + | YIELD + { + $$ = NEW_YIELD(Qnil); + } + | expr0 lbrace opt_iter_var '|' compstmts rbrace + { + $$ = NEW_DO($3, $1, $5); + } + | expr0 '.' IDENTIFIER '(' call_args rparen { value_expr($1); $$ = NEW_CALL($1, $3, $5); } - | primary '.' IDENTIFIER + | expr0 '.' IDENTIFIER { value_expr($1); $$ = NEW_CALL($1, $3, Qnil); } - | IDENTIFIER '(' call_args rparen + | IF stmt0 then + compstmts + if_tail + END { - $$ = NEW_CALL(Qnil, $1, $3); + $$ = NEW_IF(cond($2), $4, $5); } - | IVAR '(' call_args rparen + | UNLESS stmt0 then + compstmts opt_else END { - $$ = NEW_CALL(Qnil, $1, $3); + $$ = NEW_UNLESS(cond($2), $4, $5); } - | SUPER '(' call_args rparen + | WHILE stmt0 term compstmts END { - if (!cur_mid && !in_single) - Error("super called outside of method"); - $$ = NEW_SUPER($3); + $$ = NEW_WHILE(cond($2), $4); } - | SUPER + | UNTIL stmt0 term compstmts END { - if (!cur_mid && !in_single) - Error("super called outside of method"); - $$ = NEW_ZSUPER(); + $$ = NEW_UNTIL(cond($2), $4); + } + | CASE stmt0 opt_term + cases + END + { + value_expr($2); + $$ = NEW_CASE($2, $4); + } + | FOR iter_var IN stmt0 term + compstmts + END + { + value_expr($4); + $$ = NEW_FOR($2, $4, $6); + } + | PROTECT + compstmts + resque + ensure + END + { + if ($3 == Qnil && $4 == Qnil) { + Warning("useless protect clause"); + $$ = $2; + } + else { + $$ = NEW_PROT($2, $3, $4); + } } - | '(' compexpr rparen + | LPAREN compstmts rparen + { + $$ = $2; + } + +then : term + | THEN + | term THEN + +if_tail : opt_else + | ELSIF stmt0 then + compstmts + if_tail + { + $$ = NEW_IF(cond($2), $4, $5); + } + +opt_else : /* none */ + { + $$ = Qnil; + } + | ELSE compstmts + { + $$ = $2; + } + +iter_var : lhs + | mlhs + +opt_iter_var : /* none */ + { + $$ = Qnil; + } + | iter_var + +cases : opt_else + | WHEN args term + compstmts + cases + { + $$ = NEW_WHEN($2, $4, $5); + } + +resque : /* none */ + { + $$ = Qnil; + } + | RESQUE compstmts + { + if ($2 == Qnil) + $$ = (NODE*)1; + else + $$ = $2; + } + +ensure : /* none */ + { + $$ = Qnil; + } + | ENSURE compstmts { $$ = $2; } @@ -963,13 +1035,9 @@ literal : numeric { $$ = INT2FIX($2); } + | REGEXP + | GLOB -regexp : REGEXP - { - literalize($1); - $$ = NEW_LIT($1); - } - | DREGEXP symbol : fname0 | IVAR @@ -1009,24 +1077,12 @@ assocs : assoc $$ = list_concat($1, $3); } -assoc : expr2 ASSOC expr2 +assoc : expr ASSOC expr { $$ = NEW_LIST($1); $$ = list_append($$, $3); } -end_mark : CLASS { $$ = CLASS; } - | MODULE { $$ = MODULE; } - | DEF { $$ = DEF; } - | IF { $$ = IF; } - | UNLESS { $$ = UNLESS; } - | CASE { $$ = CASE; } - | WHILE { $$ = WHILE; } - | UNTIL { $$ = UNTIL; } - | FOR { $$ = FOR; } - | DO { $$ = DO; } - | PROTECT { $$ = PROTECT; } - | { $$ = Qnil;} opt_term : /* none */ | term @@ -1039,7 +1095,7 @@ nl : '\n' { yyerrok; } rparen : ')' { yyerrok; } rbracket : ']' { yyerrok; } -lbrace : '{' { yyerrok; } +lbrace : '{' rbrace : '}' { yyerrok; } comma : ',' { yyerrok; } %% @@ -1053,8 +1109,6 @@ comma : ',' { yyerrok; } static char *tokenbuf = NULL; static int tokidx, toksiz = 0; -char *xmalloc(); -char *xrealloc(); VALUE newregexp(); VALUE newstring(); VALUE newfloat(); @@ -1070,6 +1124,7 @@ static void read_escape(); static char *lex_p; static int lex_len; +void lex_setsrc(src, ptr, len) char *src; char *ptr; @@ -1115,33 +1170,182 @@ tokadd(c) tokenbuf[tokidx++] = c; } +static int +parse_regx() +{ + register int c; + int in_brack = 0; + int re_start = sourceline; + NODE *list = Qnil; + + newtok(); + while (c = nextc()) { + switch (c) { + case '[': + in_brack = 1; + break; + case ']': + in_brack = 0; + break; + + case '#': + list = var_extend(list, '/'); + if (list == (NODE*)-1) return 0; + continue; + + case '\\': + if ((c = nextc()) == -1) { + sourceline = re_start; + Error("unterminated regexp meets end of file"); + return 0; + } + else if (c == '\n') { + sourceline++; + } + else if (in_brack && c == 'b') { + tokadd('\b'); + } + else if (isdigit(c)) { + tokadd('\\'); + tokadd(c); + } + else { + pushback(); + read_escape(LEAVE_BS); + } + continue; + + case '/': /* end of the regexp */ + if (in_brack) + break; + + tokfix(); + lex_state = EXPR_END; + if (list) { + if (toklen() > 0) { + VALUE ss = str_new(tok(), toklen()); + literalize(ss); + list_append(list, NEW_STR(ss)); + } + list->type = NODE_DREGX; + yylval.node = list; + return DREGEXP; + } + else { + yylval.val = regexp_new(tok(), toklen()); + return REGEXP; + } + case -1: + Error("unterminated regexp"); + return 0; + + default: + if (ismbchar(c)) { + tokadd(c); + c = nextc(); + } + break; + } + tokadd(c); + } +} + +static int +parse_string(term) + int term; +{ + int c; + NODE *list = Qnil; + ID id; + int strstart; + + strstart = sourceline; + newtok(); + while ((c = nextc()) != term) { + if (c == -1) { + unterm_str: + sourceline = strstart; + Error("unterminated string meets end of file"); + return 0; + } + if (ismbchar(c)) { + tokadd(c); + c = nextc(); + } + else if (c == '\n') { + sourceline++; + } + else if (c == '#') { + list = var_extend(list, term); + if (list == (NODE*)-1) goto unterm_str; + continue; + } + else if (c == '\\') { + c = nextc(); + if (c == '\n') { + sourceline++; + } + else if (c == term) { + tokadd(c); + } + else { + pushback(); + read_escape(LEAVE_BS | EXPAND_B); + } + continue; + } + tokadd(c); + } + tokfix(); + lex_state = EXPR_END; + if (list == Qnil) { + yylval.val = str_new(tok(), toklen()); + return (term == '`') ? XSTRING : STRING; + } + else { + if (toklen() > 0) { + VALUE ss = str_new(tok(), toklen()); + literalize(ss); + list_append(list, NEW_STR(ss)); + } + yylval.node = list; + if (term == '`') { + list->type = NODE_XSTR2; + return XSTRING2; + } + else { + return STRING2; + } + } +} + #define LAST(v) ((v)-1 + sizeof(v)/sizeof(v[0])) static struct kwtable { char *name; int id; - int state; + enum lex_state state; } kwtable [] = { - "__END__", 0, KEEP_STATE, + "__END__", 0, EXPR_BEG, "__FILE__", _FILE_, EXPR_END, "__LINE__", _LINE_, EXPR_END, "break", BREAK, EXPR_END, - "case", CASE, KEEP_STATE, - "class", CLASS, KEEP_STATE, + "case", CASE, EXPR_BEG, + "class", CLASS, EXPR_BEG, "continue", CONTINUE, EXPR_END, - "def", DEF, KEEP_STATE, - "do", DO, KEEP_STATE, + "def", DEF, EXPR_FNAME, "else", ELSE, EXPR_BEG, "elsif", ELSIF, EXPR_BEG, "end", END, EXPR_END, "ensure", ENSURE, EXPR_BEG, - "for", FOR, KEEP_STATE, - "if", IF, KEEP_STATE, + "fail", FAIL, EXPR_END, + "for", FOR, EXPR_BEG, + "if", IF, EXPR_BEG, "in", IN, EXPR_BEG, "include", INCLUDE, EXPR_BEG, - "module", MODULE, KEEP_STATE, + "module", MODULE, EXPR_BEG, "nil", NIL, EXPR_END, - "protect", PROTECT, KEEP_STATE, + "protect", PROTECT, EXPR_BEG, "redo", REDO, EXPR_END, "resque", RESQUE, EXPR_BEG, "retry", RETRY, EXPR_END, @@ -1152,95 +1356,18 @@ static struct kwtable { "undef", UNDEF, EXPR_BEG, "unless", UNLESS, EXPR_BEG, "until", UNTIL, EXPR_BEG, - "using", USING, KEEP_STATE, "when", WHEN, EXPR_BEG, - "while", WHILE, KEEP_STATE, - "yield", YIELD, EXPR_BEG, + "while", WHILE, EXPR_BEG, + "yield", YIELD, EXPR_END, }; -static int strstart; - +static int yylex() { register int c; struct kwtable *low = kwtable, *mid, *high = LAST(kwtable); int last; - if (in_regexp) { - int in_brack = 0; - int re_start = sourceline; - NODE *list = Qnil; - - in_regexp = 0; - newtok(); - while (c = nextc()) { - switch (c) { - case '[': - in_brack = 1; - break; - case ']': - in_brack = 0; - break; - - case '#': - list = var_extend(list, '/'); - if (list == (NODE*)-1) return 0; - continue; - - case '\\': - if ((c = nextc()) == -1) { - sourceline = re_start; - Error("unterminated regexp meets end of file"); - return 0; - } - else if (c == '\n') { - sourceline++; - } - else if (in_brack && c == 'b') { - tokadd('\b'); - } - else { - pushback(); - read_escape(LEAVE_BS); - } - continue; - - case '/': /* end of the regexp */ - if (in_brack) - break; - - tokfix(); - lex_state = EXPR_END; - if (list) { - if (toklen() > 0) { - VALUE ss = str_new(tok(), toklen()); - literalize(ss); - list_append(list, NEW_STR(ss)); - } - list->type = NODE_DREGX; - yylval.node = list; - return DREGEXP; - } - else { - yylval.val = regexp_new(tok(), toklen()); - return REGEXP; - } - - case -1: - Error("unterminated regexp"); - return 0; - - default: - if (ismbchar(c)) { - tokadd(c); - c = nextc(); - } - break; - } - tokadd(c); - } - } - retry: switch (c = nextc()) { case '\0': @@ -1251,6 +1378,7 @@ retry: /* white spaces */ case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ goto retry; case '#': /* it's a comment */ @@ -1261,7 +1389,8 @@ retry: /* fall through */ case '\n': sourceline++; - if (lex_state == EXPR_BEG) goto retry; + if (lex_state == EXPR_BEG || lex_state == EXPR_FNAME) + goto retry; lex_state = EXPR_BEG; return '\n'; @@ -1283,6 +1412,13 @@ retry: return '*'; case '!': + if (lex_state == EXPR_FNAME) { + if ((c = nextc()) == '@') { + lex_state = EXPR_BEG; + return '!'; + } + pushback(); + } lex_state = EXPR_BEG; if ((c = nextc()) == '=') { return NEQ; @@ -1308,6 +1444,14 @@ retry: return '='; case '<': + if (lex_state == EXPR_BEG) { + if (parse_string('>') == STRING) { + yylval.val = glob_new(yylval.val); + return GLOB; + } + yylval.node->type = NODE_DGLOB; + return DGLOB; + } lex_state = EXPR_BEG; if ((c = nextc()) == '=') { if ((c = nextc()) == '>') { @@ -1345,16 +1489,16 @@ retry: case '"': case '`': + return parse_string(c); + + case '\'': { - char term = c; - NODE *list = Qnil; - ID id; + int strstart; strstart = sourceline; newtok(); - while ((c = nextc()) != term) { - if (c == -1) { - unterm_str: + while ((c = nextc()) != '\'') { + if (c == -1) { sourceline = strstart; Error("unterminated string meets end of file"); return 0; @@ -1366,63 +1510,6 @@ retry: else if (c == '\n') { sourceline++; } - else if (c == '#') { - list = var_extend(list, term); - if (list == (NODE*)-1) return 0; - continue; - } - else if (c == '\\') { - c = nextc(); - if (c == '\n') { - sourceline++; - } - else if (c == term) { - tokadd(c); - } - else { - pushback(); - read_escape(LEAVE_BS | EXPAND_B); - } - continue; - } - tokadd(c); - } - tokfix(); - lex_state = EXPR_END; - if (list == Qnil) { - yylval.val = str_new(tok(), toklen()); - return (term == '"') ? STRING : XSTRING; - } - else { - if (toklen() > 0) { - VALUE ss = str_new(tok(), toklen()); - literalize(ss); - list_append(list, NEW_STR(ss)); - } - yylval.node = list; - if (term == '"') { - return STRING2; - } - else { - list->type = NODE_XSTR2; - return XSTRING2; - } - } - } - - case '\'': - { - strstart = sourceline; - newtok(); - while ((c = nextc()) != '\'') { - if (c == -1) goto unterm_str; - if (ismbchar(c)) { - tokadd(c); - c = nextc(); - } - else if (c == '\n') { - sourceline++; - } else if (c == '\\') { c = nextc(); switch (c) { @@ -1491,6 +1578,15 @@ retry: if (isdigit(c)) { goto start_num; } + lex_state = EXPR_BEG; + return UPLUS; + } + else if (lex_state == EXPR_FNAME) { + if ((c = nextc()) == '@') { + return UPLUS; + } + pushback(); + return '+'; } lex_state = EXPR_BEG; if ((c = nextc()) == '=') { @@ -1508,6 +1604,15 @@ retry: c = '-'; goto start_num; } + lex_state = EXPR_BEG; + return UMINUS; + } + else if (lex_state == EXPR_FNAME) { + if ((c = nextc()) == '@') { + return UMINUS; + } + pushback(); + return '-'; } lex_state = EXPR_BEG; if ((c = nextc()) == '=') { @@ -1518,17 +1623,16 @@ retry: return '-'; case '.': + lex_state = EXPR_BEG; if ((c = nextc()) == '.') { if ((c = nextc()) == '.') { return DOT3; } pushback(); - lex_state = EXPR_BEG; return DOT2; } pushback(); if (!isdigit(c)) { - lex_state = EXPR_BEG; return '.'; } c = '.'; @@ -1563,11 +1667,7 @@ retry: } while (c >= '0' && c <= '9'); pushback(); tokfix(); -#if 0 - yylval.val = INT2FIX(strtoul(tok(), Qnil, 8)); -#else yylval.val = str2inum(tok(), 8); -#endif return INTEGER; } } @@ -1651,6 +1751,9 @@ retry: return ':'; case '/': + if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + return parse_regx(); + } lex_state = EXPR_BEG; if (nextc() == '=') { yylval.id = '/'; @@ -1670,17 +1773,52 @@ retry: case ',': case ';': - case '[': + lex_state = EXPR_BEG; + return c; + + case '~': + if (lex_state == EXPR_FNAME) { + if ((c = nextc()) != '@') { + pushback(); + } + } + lex_state = EXPR_BEG; + return c; + case '(': + if (lex_state != EXPR_END) + c = LPAREN; + 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 ((c = nextc()) == ']') { + if ((c = nextc()) == '=') { + return ASET; + } + pushback(); + return AREF; + } + pushback(); + return '['; + } + lex_state = EXPR_BEG; + return c; + case '{': - case '~': + if (lex_state != EXPR_END) + c = LBRACE; lex_state = EXPR_BEG; return c; case '\\': c = nextc(); if (c == '\n') goto retry; /* skip \\n */ - lex_state = EXPR_BEG; + lex_state = EXPR_FNAME; pushback(); return '\\'; @@ -1767,8 +1905,13 @@ retry: while (low <= high) { mid = low + (high - low)/2; if (( c = strcmp(mid->name, tok())) == 0) { - if (mid->state != KEEP_STATE) { - lex_state = mid->state; + enum lex_state state = lex_state; + lex_state = mid->state; + if (state != EXPR_BEG) { + if (mid->id == IF) return IF_MOD; + if (mid->id == UNLESS) return UNLESS_MOD; + if (mid->id == WHILE) return WHILE_MOD; + if (mid->id == UNTIL) return UNTIL_MOD; } return mid->id; } @@ -1781,17 +1924,30 @@ retry: } id_fetch: - lex_state = EXPR_END; - yylval.id = rb_intern(tok()); - switch (tok()[0]) { - case '%': - return CONSTANT; - case '$': - return GVAR; - case '@': - return IVAR; - default: - return IDENTIFIER; + { + enum lex_state state = lex_state; + + lex_state = EXPR_END; + yylval.id = rb_intern(tok()); + switch (tok()[0]) { + case '%': + return CONSTANT; + case '$': + return GVAR; + case '@': + return IVAR; + default: + if (state == EXPR_FNAME) { + if ((c = nextc()) == '=') { + yylval.id &= ~ID_SCOPE_MASK; + yylval.id |= ID_ATTRSET; + } + else { + pushback(); + } + } + return IDENTIFIER; + } } } @@ -1836,9 +1992,6 @@ var_extend(list, term) if (c == '{') { while ((c = nextc()) != '}') { if (c == -1) { - unterm_str: - sourceline = strstart; - Error("unterminated string meets end of file"); return (NODE*)-1; } if (isspace(c)) { @@ -1858,7 +2011,7 @@ var_extend(list, term) case '$': tokadd(c); c = nextc(); - if (c == -1) goto unterm_str; + if (c == -1) return (NODE*)-1; if (!is_identchar(c)) { tokadd(c); goto fetch_id; @@ -1994,7 +2147,7 @@ read_escape(flag) i *= 16; i += c - '0'; } - else if ((int)index("abcdefABCDEF", (c = nextc()))) { + else if ((int)strchr("abcdefABCDEF", (c = nextc()))) { i *= 16; i += toupper(c) - 'A' + 10; } @@ -2139,14 +2292,17 @@ void freenode(node) case NODE_STR2: case NODE_XSTR2: case NODE_DREGX: + case NODE_DGLOB: case NODE_QLIST: freenode(node->nd_next); break; case NODE_HASH: freenode(node->nd_head); break; + case NODE_EXNOT: + freenode(node->nd_cond); + break; case NODE_IF: - case NODE_UNLESS: case NODE_WHEN: case NODE_PROT: freenode(node->nd_cond); @@ -2155,7 +2311,7 @@ void freenode(node) break; case NODE_CASE: case NODE_WHILE: - case NODE_UNTIL: + case NODE_WHILE2: case NODE_AND: case NODE_OR: freenode(node->nd_head); @@ -2176,6 +2332,7 @@ void freenode(node) case NODE_MASGN: freenode(node->nd_value); freenode(node->nd_head); + freenode(node->nd_args); break; case NODE_CALL: case NODE_SUPER: @@ -2199,6 +2356,7 @@ void freenode(node) break; case NODE_RETURN: case NODE_YIELD: + case NODE_FAIL: freenode(node->nd_stts); break; case NODE_STR: @@ -2221,9 +2379,11 @@ void freenode(node) case NODE_MODULE: freenode(node->nd_body); break; + case NODE_CONST: + unliteralize(node->nd_cval); + break; case NODE_ATTRSET: case NODE_CVAR: - case NODE_CONST: case NODE_ZSUPER: case NODE_ZARRAY: case NODE_CFUNC: @@ -2272,44 +2432,49 @@ except_lit() } 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); + } + + freenode(recv); + if (arg) freenode(arg); + return result; +} + +static NODE * call_op(recv, id, narg, arg1) NODE *recv; ID id; int narg; NODE *arg1; { - NODE *args; - value_expr(recv); - if (narg == 1) + if (narg == 1) { value_expr(arg1); - - if (recv->type != NODE_LIT || recv->type != NODE_STR - || (narg == 0 && id == '~' - && (TYPE(recv->nd_lit)==T_REGEXP || TYPE(recv->nd_lit)==T_STRING)) - || arg1->type == NODE_LIT || arg1->type == NODE_STR) { - if (narg > 0) { - args = NEW_ARRAY(arg1); - args->nd_argc = 1; - } - else { - args = Qnil; - } - return NEW_CALL(recv, id, args); } - else { - struct call_arg arg_data; - NODE *result; - - arg_data.recv = recv->nd_lit; - arg_data.id = id; - arg_data.narg = narg; - if (narg == 1) arg_data.arg = arg1->nd_lit; - result = NEW_LIT(rb_resque(call_lit, &arg_data, except_lit, Qnil)); - freenode(recv); - if (narg == 1) freenode(arg1); - return result; + + if ((recv->type == NODE_LIT || recv->type == NODE_STR) + && (narg == 0 || (arg1->type == NODE_LIT || arg1->type == NODE_STR))) { + return expand_op(recv, id, (narg == 1)?arg1:Qnil); } + return NEW_CALL(recv, id, narg==1?NEW_LIST(arg1):Qnil); } static NODE* @@ -2390,8 +2555,6 @@ static NODE * aryset(recv, idx, val) NODE *recv, *idx, *val; { - NODE *args; - value_expr(recv); return NEW_CALL(recv, ASET, list_append(idx, val)); } @@ -2413,18 +2576,25 @@ static void value_expr(node) NODE *node; { + if (node == Qnil) return; + switch (node->type) { case NODE_RETURN: case NODE_CONTINUE: case NODE_BREAK: case NODE_REDO: case NODE_RETRY: + case NODE_WHILE: + case NODE_WHILE2: + case NODE_INC: + case NODE_CLASS: + case NODE_MODULE: Error("void value expression"); break; case NODE_BLOCK: if (node->nd_last) - return value_expr(node->nd_last->nd_head); + value_expr(node->nd_last->nd_head); break; default: @@ -2433,28 +2603,49 @@ value_expr(node) } static NODE* -cond(node) +cond0(node) NODE *node; { - value_expr(node); - if (node->type == NODE_STR) { + enum node_type type = node->type; + + if (type == NODE_STR || type == NODE_STR2 || type == NODE_DREGX) { return call_op(NEW_GVAR(rb_intern("$_")),MATCH,1,node); } - else if (node->type == NODE_LIT && TYPE(node->nd_lit) == T_REGEXP) { + else if (type == NODE_LIT && TYPE(node->nd_lit) == T_REGEXP) { return call_op(node,MATCH,1,NEW_GVAR(rb_intern("$_"))); } return node; } static NODE* +cond(node) + NODE *node; +{ + enum node_type type = node->type; + + value_expr(node); + + node = cond0(node); + if (type == NODE_AND || type == NODE_OR) { + node->nd_1st = cond(node->nd_1st); + node->nd_2nd = cond(node->nd_2nd); + } + else if (type == NODE_CALL && node->nd_mid == '!') { + if (node->nd_args || node->nd_recv == Qnil) { + Bug("method `!' called with wrong # of operand"); + } + node->nd_recv = cond0(node->nd_recv); + } + return node; +} + +static NODE* cond2(node) NODE *node; { node = cond(node); - if (node->type == NODE_LIT) { - if (FIXNUM_P(node->nd_lit)) { - return call_op(node,EQ,1,NEW_GVAR(rb_intern("$."))); - } + if (node->type == NODE_LIT && FIXNUM_P(node->nd_lit)) { + return call_op(node,EQ,1,NEW_GVAR(rb_intern("$."))); } return node; } @@ -2550,15 +2741,21 @@ setup_top_local() if (lvtbl->cnt > 0) { if (the_env->local_vars == Qnil) { the_env->local_vars = ALLOC_N(VALUE, lvtbl->cnt); - bzero(the_env->local_vars, lvtbl->cnt * sizeof(VALUE)); + memset(the_env->local_vars, 0, lvtbl->cnt * sizeof(VALUE)); } else if (lvtbl->tbl[0] < lvtbl->cnt) { int i; - REALLOC_N(the_env->local_vars, VALUE, lvtbl->cnt); - for (i=lvtbl->tbl[0]; i<lvtbl->cnt; i++) { - the_env->local_vars[i] = Qnil; + if (the_env->flags&VARS_MALLOCED) { + REALLOC_N(the_env->local_vars, VALUE, lvtbl->cnt); + } + else { + VALUE *vars = the_env->local_vars; + the_env->local_vars = ALLOC_N(VALUE, lvtbl->cnt); + memcpy(the_env->local_vars, vars, sizeof(VALUE)*lvtbl->cnt); + the_env->flags |= VARS_MALLOCED; } + memset(the_env->local_vars+i, 0, lvtbl->cnt-i); } lvtbl->tbl[0] = lvtbl->cnt; the_env->local_tbl = lvtbl->tbl; @@ -3,7 +3,7 @@ process.c - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/12 04:47:47 $ created at: Tue Aug 10 14:30:50 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -84,6 +84,8 @@ static int wait_status; static wait_each(key, value) int key, value; { + if (wait_status != -1) return ST_STOP; + wait_pid = key; wait_status = value; return ST_DELETE; @@ -135,7 +137,7 @@ rb_proc_exec(str) char **argv, **a; for (s=str; *s; s++) { - if (*s != ' ' && !isalpha(*s) && index("*?{}[]<>()~&|\\$;'`\"\n",*s)) { + if (*s != ' ' && !isalpha(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { execl("/bin/sh", "sh", "-c", str, (char *)NULL); return -1; } @@ -173,10 +175,10 @@ Ffork(obj) switch (pid = fork()) { case 0: - return Qnil; + return INT2FIX(0); case -1: - rb_sys_fail(Qnil); + rb_sys_fail("fork(2)"); break; default: @@ -410,18 +412,18 @@ Fkill(argc, argv) int sig; int i; - if (argc < 3) + if (argc < 2) Fail("wrong # of arguments -- kill(sig, pid...)"); - switch (TYPE(argv[1])) { + switch (TYPE(argv[0])) { case T_FIXNUM: - sig = FIX2UINT(argv[1]); + sig = FIX2UINT(argv[0]); break; case T_STRING: { int negative = 0; - char *s = RSTRING(argv[1])->ptr; + char *s = RSTRING(argv[0])->ptr; if (*s == '-') { negative++; s++; @@ -437,13 +439,13 @@ Fkill(argc, argv) break; default: - Fail("bad signal type %s", rb_class2name(CLASS_OF(argv[1]))); + Fail("bad signal type %s", rb_class2name(CLASS_OF(argv[0]))); break; } if (sig < 0) { sig = -sig; - for (i=2; i<argc; i++) { + for (i=1; i<argc; i++) { int pid = NUM2INT(argv[i]); #ifdef HAS_KILLPG if (killpg(pid, sig) < 0) @@ -454,13 +456,13 @@ Fkill(argc, argv) } } else { - for (i=2; i<argc; i++) { + for (i=1; i<argc; i++) { Check_Type(argv[i], T_FIXNUM); if (kill(FIX2UINT(argv[i]), sig) < 0) rb_sys_fail(Qnil); } } - return INT2FIX(i-2); + return INT2FIX(i-1); } static VALUE trap_list[NSIG]; @@ -601,39 +603,48 @@ Ftrap(argc, argv) RETSIGTYPE (*func)(); VALUE command; int i, sig; +#ifdef HAVE_SIGPROCMASK + sigset_t mask; +#else int mask; +#endif - if (argc < 3) + if (argc < 2) Fail("wrong # of arguments -- kill(cmd, sig...)"); /* disable interrupt */ +#ifdef HAVE_SIGPROCMASK + sigfillset(&mask); + sigprocmask(SIG_BLOCK, &mask, &mask); +#else mask = sigblock(~0); +#endif func = sighandle; - if (argv[1] == Qnil) { + if (argv[0] == Qnil) { func = SIG_IGN; command = Qnil; } else { - Check_Type(argv[1], T_STRING); - command = argv[1]; - if (RSTRING(argv[1])->len == 0) { + Check_Type(argv[0], T_STRING); + command = argv[0]; + if (RSTRING(argv[0])->len == 0) { func = SIG_IGN; } - else if (RSTRING(argv[1])->len == 7) { - if (strncmp(RSTRING(argv[1])->ptr, "SIG_IGN", 7) == 0) { + else if (RSTRING(argv[0])->len == 7) { + if (strncmp(RSTRING(argv[0])->ptr, "SIG_IGN", 7) == 0) { func = SIG_IGN; } - else if (strncmp(RSTRING(argv[1])->ptr, "SIG_DFL", 7) == 0) { + else if (strncmp(RSTRING(argv[0])->ptr, "SIG_DFL", 7) == 0) { func = SIG_DFL; } - else if (strncmp(RSTRING(argv[1])->ptr, "DEFAULT", 7) == 0) { + else if (strncmp(RSTRING(argv[0])->ptr, "DEFAULT", 7) == 0) { func = SIG_DFL; } } - else if (RSTRING(argv[1])->len == 6) { - if (strncmp(RSTRING(argv[1])->ptr, "IGNORE", 6) == 0) { + else if (RSTRING(argv[0])->len == 6) { + if (strncmp(RSTRING(argv[0])->ptr, "IGNORE", 6) == 0) { func = SIG_IGN; } } @@ -641,7 +652,7 @@ Ftrap(argc, argv) if (func == SIG_IGN || func == SIG_DFL) command = Qnil; - for (i=2; i<argc; i++) { + for (i=1; i<argc; i++) { if (TYPE(argv[i]) == T_STRING) { char *s = RSTRING(argv[i])->ptr; @@ -654,15 +665,24 @@ Ftrap(argc, argv) else { sig = NUM2INT(argv[i]); } - if (i < 0 || i > NSIG) + if (sig < 0 || sig > NSIG) Fail("Invalid signal no %d", sig); signal(sig, sighandle); trap_list[sig] = command; /* enable at least specified signal. */ +#ifdef HAVE_SIGPROCMASK + sigdelset(&mask, sig); +#else mask &= ~sigmask(sig); +#endif } + /* disable interrupt */ +#ifdef HAVE_SIGPROCMASK + sigprocmask(SIG_SETMASK, &mask, NULL); +#else sigsetmask(mask); +#endif return Qnil; } @@ -676,8 +696,8 @@ Fsleep(argc, argv) if (argc == 1) { sleep((32767<<16)+32767); } - else if (argc == 2) { - sleep(NUM2INT(argv[1])); + else if (argc == 1) { + sleep(NUM2INT(argv[0])); } else { Fail("wrong # of arguments"); @@ -718,13 +738,14 @@ Fproc_setpgrp(obj, pid, pgrp) if (getpgrp(ipid, ipgrp) == -1) rb_sys_fail(Qnil); - return Qnil; + return INT2FIX(0); } static VALUE Fproc_getpriority(obj, which, who) VALUE obj, which, who; { +#ifdef HAVE_GETPRIORITY int prio, iwhich, iwho; iwhich = NUM2INT(which); @@ -733,12 +754,16 @@ Fproc_getpriority(obj, which, who) prio = getpriority(iwhich, iwho); if (prio == -1) rb_sys_fail(Qnil); return INT2FIX(prio); +#else + Fail("The getpriority() function is unimplemented on this machine"); +#endif } static VALUE Fproc_setpriority(obj, which, who, prio) VALUE obj, which, who, prio; { +#ifdef HAVE_GETPRIORITY int iwhich, iwho, iprio; iwhich = NUM2INT(which); @@ -747,7 +772,10 @@ Fproc_setpriority(obj, which, who, prio) if (setpriority(iwhich, iwho, iprio) == -1) rb_sys_fail(Qnil); - return Qnil; + return INT2FIX(0); +#else + Fail("The setpriority() function is unimplemented on this machine"); +#endif } static VALUE @@ -826,14 +854,14 @@ Init_process() rb_define_single_method(M_Process, "waitpid", Fwaitpid, 2); rb_define_single_method(M_Process, "kill", Fkill, -1); - rb_define_mfunc(M_Process, "pid", get_pid, 0); - rb_define_mfunc(M_Process, "ppid", get_ppid, 0); + rb_define_method(M_Process, "pid", get_pid, 0); + rb_define_method(M_Process, "ppid", get_ppid, 0); - rb_define_mfunc(M_Process, "getpgrp", Fproc_getpgrp, -2); - rb_define_mfunc(M_Process, "setpgrp", Fproc_setpgrp, 2); + rb_define_method(M_Process, "getpgrp", Fproc_getpgrp, -2); + rb_define_method(M_Process, "setpgrp", Fproc_setpgrp, 2); - rb_define_mfunc(M_Process, "getpriority", Fproc_getpriority, 2); - rb_define_mfunc(M_Process, "setpriority", Fproc_setpriority, 3); + rb_define_method(M_Process, "getpriority", Fproc_getpriority, 2); + rb_define_method(M_Process, "setpriority", Fproc_setpriority, 3); rb_define_const(M_Process, "%PRIO_PROCESS", INT2FIX(PRIO_PROCESS)); rb_define_const(M_Process, "%PRIO_PGRP", INT2FIX(PRIO_PGRP)); @@ -847,4 +875,6 @@ Init_process() rb_define_method(M_Process, "euid", Fproc_geteuid, 0); rb_define_single_method(M_Process, "euid=", Fproc_seteuid, 1); rb_define_method(M_Process, "euid=", Fproc_seteuid, 1); + + rb_include_module(CLASS_OF(M_Process), M_Process); } @@ -3,7 +3,7 @@ random.c - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/12 04:47:48 $ created at: Fri Dec 24 16:39:21 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -3,7 +3,7 @@ range.c - $Author: matz $ - $Date: 1994/06/17 14:23:50 $ + $Date: 1994/08/12 04:47:49 $ created at: Thu Aug 19 17:46:47 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -59,6 +59,24 @@ Frng_match(rng, obj) } } +struct upto_data { + VALUE beg; + VALUE end; +}; + +static rng_upto(data) + struct upto_data *data; +{ + return rb_funcall(data->beg, rb_intern("upto"), 1, data->end); +} + +static rng_upto_yield(v) + VALUE v; +{ + rb_yield(v); + return Qnil; +} + static VALUE Frng_each(obj) VALUE obj; @@ -69,22 +87,18 @@ Frng_each(obj) e = rb_iv_get(obj, "end"); if (FIXNUM_P(b)) { /* fixnum is a special case(for performance) */ - int beg, end, i; - - beg = FIX2INT(b); - end = FIX2INT(e); - - for (i=beg; i<=end; i++) { - rb_yield(INT2FIX(i)); - } + Fnum_upto(b, e); + } + else if (TYPE(b) == T_STRING) { + Fstr_upto(b, e); } else { - current = b; - for (;;) { - rb_yield(current); - if (rb_funcall(current, eq, 1, e)) break; - current = rb_funcall(current, next, 0); - } + struct upto_data data; + + data.beg = b; + data.end = e; + + rb_iterate(rng_upto, &data, rng_upto_yield, Qnil); } return Qnil; @@ -114,18 +128,12 @@ static VALUE Frng_to_s(obj) VALUE obj; { - int beg, end; - VALUE fmt, str, args[4]; - - - beg = rb_iv_get(obj, "start"); - end = rb_iv_get(obj, "end"); - - fmt = str_new2("%d..%d"); - args[0] = obj; args[1] = fmt; args[2]= beg; args[3] = end; - str = Fsprintf(4, args); + VALUE args[4]; - return str; + args[0] = str_new2("%d..%d"); + args[1] = rb_iv_get(obj, "start"); + args[2] = rb_iv_get(obj, "end"); + return Fsprintf(3, args); } extern VALUE M_Enumerable; @@ -3,7 +3,7 @@ re.c - $Author: matz $ - $Date: 1994/06/27 15:48:36 $ + $Date: 1994/08/18 07:06:23 $ created at: Mon Aug 9 18:24:49 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -101,7 +101,7 @@ int len; */ rp = ALLOC(Regexp); - bzero((char *)rp, sizeof(Regexp)); + memset((char *)rp, 0, sizeof(Regexp)); rp->pat.buffer = ALLOC_N(char, 16); rp->pat.allocated = 16; rp->pat.fastmap = ALLOC_N(char, 256); @@ -153,7 +153,7 @@ research(reg, str, start, ignorecase) OBJSETUP(obj, C_Data, T_DATA); obj->dfree = free_match; data = (struct match*)DATA_PTR(obj); - bzero(data, sizeof(struct match)); + memset(data, 0, sizeof(struct match)); beg = reg->ptr->regs.start[0]; data->len = reg->ptr->regs.end[0] - beg; data->ptr = ALLOC_N(char, data->len+1); @@ -410,6 +410,11 @@ VALUE rb_readonly_hook(); void Init_Regexp() { + obscure_syntax = RE_NO_BK_PARENS | RE_NO_BK_VBAR + | RE_CONTEXT_INDEP_OPS | RE_INTERVALS + | RE_NO_BK_CURLY_BRACES + | RE_MBCTYPE_EUC; + rb_define_variable("$~", last_match_data, Qnil, store_match_data); rb_define_variable("$&", Qnil, re_last_match, rb_readonly_hook); @@ -3,8 +3,8 @@ re.h - $Author: matz $ - $Revision: 1.1.1.1 $ - $Date: 1994/06/17 14:23:50 $ + $Revision: 1.2 $ + $Date: 1994/08/12 04:47:52 $ created at: Thu Sep 30 14:18:32 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -1,26 +1,26 @@ .\"ruby.1 - -*- Nroff -*- -.\" $Author$ -.\" $Date$ -.\" created at: Tue Apr 12 01:45:04 GMT 1994 +.\" $Author: matz $ +.\" $Date: 1994/08/18 07:06:25 $ +.\" created at: Tue Apr 12 01:45:04 JST 1994 .TH RUBY 1 "\*(RP" .UC -.SH "NAME 名称" +.SH NAME ruby \- オブジェクト指向スクリプト言語 -.SH "SYNOPSIS 形式" +.SH SYNOPSIS .B ruby [ .B options ] filename args .SH DESCRIPTION -.IB Ruby +.B Ruby は, 手軽なオブジェクト指向プログラミングを実現するための種々 -の機能を持つオブジェクト指向スクリプト言語である. その設計の +の機能を持つオブジェクト指向スクリプト言語である.その設計の 基本原則は, 以下の通りである. .IP 機能性 オブジェクト指向プログラミングとスクリプトプログラミングのた めに必要な機能を十分に備える. 特にテキスト処理関係の機能を豊 -富に持つ. また, 純粋なオブジェクト指向言語でありながら, 必要 +富に持つ。また, 純粋なオブジェクト指向言語でありながら, 必要 であれば手続き型プログラミングも可能である. .IP 拡張性 必要に応じて容易に機能を拡張できる. クラスを自由に追加できる @@ -28,33 +28,57 @@ ruby \- オブジェクト指向スクリプト言語 る機能を追加できる. さらにプラットフォームによっては, 動的に オブジェクトコードをリンクする機能も提供する. .IP 一貫性 -少数の原則が全体に適用されるような一貫性のある言語仕様を持つ. -これによって「パズルの楽しさ」は減少したかも知れない. ただし, +少数の原則が全体に適用されるような一貫性のある言語仕様を持つ. +これによって「パズルの楽しさ」は減少したかも知れない. ただし, 一貫性のため使いやすさを犠牲にすることはない. .PP -.IB Ruby -はshやperlを知っている人にとっての常識にできる限り従ったので, +.B Ruby +はshやperlを知っている人にとっての常識にできる限り従ったので, それらの言語に精通している人にとっては習得が(多分)容易だろう. -.SH "OPTIONS オプション" -.IB ruby -は以下の引数を受け付ける. +.SH OPTIONS +.B ruby +インタプリタは以下の引数を受け付ける. .TP 5 .B \-a `\-n'や`\-p'とともに用いて, オートスプリットモードをONにする. -オートスプリットモードでは各ループの先頭で, +オートスプリットモードでは各ループの先頭で, .nf .ne 2 $F = $_.split .fi -が実行される. `\-n'か`\-p'オプションが指定されない限り, この -オプションは意味を持たない. +が実行される. `\-n'か`\-p'オプションが同時に指定されない限り, +このオプションは意味を持たない. .TP 5 .B \-c スクリプトの内部形式へのコンパイルのみを行い, 実行しない. コ ンパイル終了後, 文法エラーが無ければ, "Syntax OK"と出力する. .TP 5 +.B \-C " code" +.B ruby +の処理する漢字コードを指定する. +.B ruby +は指定した文字列が `E'または`e'から始まる場合は文字列やアク +セスするファイルがEUCで記述されていると仮定する. 同様に`S'ま +たは`s'の場合はSJISとして処理する. `N'は漢字を処理しない. デ +フォルトはEUC. +.nf +.ne 2 + + ruby -C EUC -e 'print "テスト"' + ruby -Ceuc -e 'print "テスト"' + ruby -C 'Shift JIS' -e 'print "テスト"' + ruby -CN 'print "テスト"' + +.fi +このオプションは将来文字コードの自動判別機能が追加された場合 +等には変更される. +.TP 5 +.B \-d, \-\-debug +デバッグモードをonにする. このフラグがセットされるとシステム +変数$DEBUGがセットされる. +.TP 5 .B \-e " script" コマンドラインからスクリプトを指定する. \-eオプションを付け た時には引数からスクリプトファイル名を取らない. @@ -84,13 +108,9 @@ ruby \- オブジェクト指向スクリプト言語 .B \-I " directory" ファイルをロードするパスを指定(追加)する. 指定されたディレク トリは -.IB ruby +.B ruby の配列変数$LOAD_PATHに追加される. .TP 5 -.B \-d, \--debug -デバッグモードをonにする. このフラグがセットされるとシステム -変数$DEBUGがセットされる. -.TP 5 .B \-l `$\\'を`$/'と同じ値に設定し, print()での出力時に改行を付加す る. また, \-nまたは\-pとともに用いられると, 入力された各行の @@ -109,12 +129,12 @@ ruby \- オブジェクト指向スクリプト言語 で囲まれているように動作する. .TP 5 .B \-p -\-nフラグと同じだが, 各ループの最後に変数`$_'の値を出力する. +`\-n'フラグと同じだが, 各ループの最後に変数`$_'の値を出力する. .nf 例: .ne 2 - % echo matz | ruby \-p \-e '$_.tr("a-z", "A-Z")' + % echo matz | ruby \-p \-e '$_\.tr("a-z", "A-Z")' MATZ .fi @@ -136,28 +156,32 @@ ruby \- オブジェクト指向スクリプト言語 例: .ne 2 - #! /usr/local/ruby -s - # -xyzオプションが与えられると"true"を表示する. - if $xyz then print("true\n") end + #! /usr/local/bin/ruby \-s + # \-xyzオプションが与えられると"true"を表示する. + if $xyz then print("true\\n") end .fi .TP 5 -.B \-v, \--verbose +.B \-S +スクリプト名が`/'で始まっていない場合, 環境変数`PATH'の値を +使ってスクリプトを探す. +.TP 5 +.B \-v, \-\-verbose 冗長モード. 起動時にバージョン番号の表示を行い, システム変数 $VERBOSEをセットする. この変数がセットされている時, いくつか のメソッドは実行時に冗長なメッセージを出力する. \-v オプショ -ンだけが指定されており, オプション以外の引数がない時にはバー -ジョンを表示した後, 実行を終了する(標準入力からのスクリプト -を待たない). +ンが指定されてq, オプション以外の引数がない時にはバージョン +を表示した後, 実行を終了する(標準入力からのスクリプトを待た +ない). .TP 5 -.B \--version -.IB ruby +.B \-\-version +.B ruby のバージョンを表示する. .nf 表示例: .ne 2 - ruby - version 0.50 (29 Jul 94) + ruby - version 0.51 (05 Sep 94) .fi .TP 5 @@ -170,39 +194,34 @@ $VERBOSEをセットする. この変数がセットされている時, いくつか .B \-X " directory" スクリプト実行前に指定されたディレクトリに移る. .TP 5 -.B \-y, \--yydebug +.B \-y, \-\-yydebug コンパイラデバッグモード. コンパイル時の構文解析の過程を表示 する. この表示は非常に冗長なので, コンパイラそのものをデバッ グする人以外は表示させない方が良いと思う. -.TP 5 -.B \-N, \-E, \-S -.IB ruby -の処理する漢字コードを指定する. Nは漢字を処理しない. EはEUC, -SはSJISを表す. デフォルトは漢字非対応. -.SH "BUG バグ(あるいは欠点)" +.SH BUGS .PP -遅い. 単純な処理の場合perlやawkなどの2,3倍の実行時間がかかる. -他の言語と異なり, その提供する機能のほとんどがメソッド呼び出 -しを介することが原因だが, 他の言語でも関数呼び出しが多くなる -ような処理ではメソッドキャッシュの分だけ -.IB ruby +遅い. 単純な処理の場合perlやawkなどの2,3倍の実行時間がかかる. +これらの言語と異なり, その提供する機能のほとんどがメソッド呼 +び出しを介することが原因だが, 他の言語でも関数呼び出しが多く +なるような処理ではメソッドキャッシュの分だけ +.B ruby が有利になるし, データ構造が複雑になれば, オブジェクト指向の メリットが活かせるので, まあ許せるかも知れない. .PP perlより記述量が多い. これは -.IB ruby +.B ruby が一貫性を追求した結果である. だが, その結果, -.IB ruby +.B ruby スクリプトはperlより読みやすいはずで, 若干の記述量を犠牲に理 解しやすさと可読性を得ていると思って欲しい. .PP ドキュメントが不十分. 必要な情報を得るためにはソースを読んで 欲しい. .PP -テストが不十分. バグにつき当たったら, できれば自分で直して, +テストが不十分. バグにつき当たったら, できれば自分で直して, こっそり私に教えて欲しい. 無理ならば, せめてバグが再現する条 件を明確にしてレポートして欲しい. -.SH "AUTHOR 作者" +.SH AUTHOR 松本 行弘 (matz@caelum.co.jp) @@ -3,7 +3,7 @@ ruby.c - $Author: matz $ - $Date: 1994/06/27 15:48:37 $ + $Date: 1994/08/24 09:25:34 $ created at: Tue Aug 10 12:47:31 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -13,7 +13,7 @@ #include "ruby.h" #include "re.h" #include <stdio.h> -#include <sys/file.h> +#include <sys/fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <signal.h> @@ -24,12 +24,15 @@ #include "missing/getopt.h" #endif +static int version, copyright; + static struct option long_options[] = { {"debug", 0, 0, 'd'}, {"yydebug", 0, 0, 'y'}, {"verbose", 0, 0, 'v'}, - {"version", 0, 0, 0}, + {"version", 0, &version, 1}, + {"copyright", 0, ©right, 1}, {0, 0, 0, 0} }; @@ -40,7 +43,8 @@ static int sflag = FALSE; char *inplace = Qnil; char *strdup(); char *strstr(); -char *index(); +char *strchr(); +char *dln_find_file(); extern int yydebug; extern int nerrs; @@ -58,7 +62,9 @@ static int do_loop = FALSE, do_print = FALSE; static int do_check = FALSE, do_line = FALSE; static int do_split = FALSE; -static char* +static char *script; + +static void proc_options(argcp, argvp) int *argcp; char ***argvp; @@ -68,26 +74,20 @@ proc_options(argcp, argvp) extern VALUE rb_load_path; extern char *optarg; extern int optind; - int c, i, j, script_given, version, opt_index; + int c, i, j, script_given, do_search, opt_index; extern VALUE RS, ORS, FS; - char *script; char *src; + if (argc == 0) return; + version = FALSE; script_given = FALSE; - script = Qnil; + do_search = FALSE; optind = 0; - while ((c = getopt_long(argc, argv, "+acde:F:i:I:lnpR:svxX:yNES", + while ((c = getopt_long(argc, argv, "+acC:de:F:i:I:lnpR:svxX:yS", long_options, &opt_index)) != EOF) { switch (c) { - case 0: /* long options */ - if (strcmp(long_options[opt_index].name, "version") == 0) { - version = TRUE; - show_version(); - } - break; - case 'p': do_print = TRUE; /* through */ @@ -104,7 +104,7 @@ proc_options(argcp, argvp) break; case 'v': - version = verbose = TRUE; + verbose = TRUE; show_version(); break; @@ -175,19 +175,29 @@ proc_options(argcp, argvp) do_split = TRUE; break; - case 'N': - obscure_syntax &= ~RE_MBCTYPE_MASK; - re_set_syntax(obscure_syntax); - break; - case 'E': - obscure_syntax &= ~RE_MBCTYPE_MASK; - obscure_syntax |= RE_MBCTYPE_EUC; + case 'C': + switch (optarg[0]) { + case 'E': + case 'e': + obscure_syntax &= ~RE_MBCTYPE_MASK; + obscure_syntax |= RE_MBCTYPE_EUC; + break; + case 'S': + case 's': + obscure_syntax &= ~RE_MBCTYPE_MASK; + obscure_syntax |= RE_MBCTYPE_SJIS; + break; + default: + case 'N': + case 'n': + obscure_syntax &= ~RE_MBCTYPE_MASK; + break; + } re_set_syntax(obscure_syntax); break; + case 'S': - obscure_syntax &= ~RE_MBCTYPE_MASK; - obscure_syntax |= RE_MBCTYPE_SJIS; - re_set_syntax(obscure_syntax); + do_search = TRUE; break; case 'I': @@ -199,17 +209,29 @@ proc_options(argcp, argvp) } } - if (argv[0] == Qnil) return Qnil; + if (version) { + show_version(); + exit(0); + } + if (copyright) { + show_copyright(); + } + + if (argv[0] == Qnil) return; if (script_given == 0) { if (argc == optind) { /* no more args */ - if (version == TRUE) exit(0); + if (verbose) exit(0); script = "-"; load_stdin(); } else { script = argv[optind]; - rb_load_file(argv[optind]); + if (do_search) { + script = dln_find_file(script, getenv("PATH")); + if (!script) script = argv[optind]; + } + rb_load_file(script); optind++; } } @@ -228,7 +250,7 @@ proc_options(argcp, argvp) break; } argv[0][0] = '$'; - if (s = index(argv[0], '=')) { + if (s = strchr(argv[0], '=')) { *s++ = '\0'; rb_gvar_set2((*argvp)[0], str_new2(s)); } @@ -238,8 +260,6 @@ proc_options(argcp, argvp) } *argcp = argc; *argvp = argv; } - - return script; } static void @@ -331,13 +351,68 @@ load_stdin() readin(fd, "-"); } +static VALUE Progname; +VALUE Argv; + +static int origargc; +static char **origargv, **origenvp; + +static VALUE +set_arg0(val, id) + VALUE val; + ID id; +{ + char *s; + int i; + static int len; + + Check_Type(val, T_STRING); + if (len == 0) { + s = origargv[0]; + s += strlen(s); + /* See if all the arguments are contiguous in memory */ + for (i = 1; i < origargc; i++) { + if (origargv[i] == s + 1) + s += strlen(++s); /* this one is ok too */ + } + len = s - origargv[0]; + } + s = RSTRING(val)->ptr; + i = RSTRING(val)->len; + if (i > len) { + memcpy(origargv[0], s, len); + origargv[0][len] = '\0'; + } + else { + memcpy(origargv[0], s, i); + s = origargv[0]+i; + *s++ = '\0'; + while (++i < len) + *s++ = ' '; + } + Progname = str_new2(origargv[0]); + + return val; +} + void -rb_main(argc, argv) /* real main() is in eval.c */ +ruby_script(name) + char *name; +{ + if (name) { + Progname = str_new2(name); + } +} + +void +ruby_init0(argc, argv, envp) int argc; - char **argv; + char **argv, **envp; { - char *script; extern VALUE errat; + int i; + + origargc = argc; origargv = argv; origenvp = envp; rb_call_inits(); @@ -350,7 +425,7 @@ rb_main(argc, argv) /* real main() is in eval.c */ rb_dln_argv0 = argv[0]; #endif - script = proc_options(&argc, &argv); + proc_options(&argc, &argv); if (do_check && nerrs == 0) { printf("Syntax OK\n"); exit(0); @@ -362,9 +437,13 @@ rb_main(argc, argv) /* real main() is in eval.c */ yywhole_loop(do_line, do_split); } - if (nerrs == 0) { - TopLevel(script, argc, argv); - } + rb_define_variable("$0", &Progname, Qnil, set_arg0); + ruby_script(script); - exit(nerrs); + rb_define_variable("$ARGV", &Argv, Qnil, Qnil); + rb_define_variable("$*", &Argv, Qnil, Qnil); + Argv = ary_new2(argc); + for (i=0; i < argc; i++) { + Fary_push(Argv, str_new2(argv[i])); + } } @@ -3,7 +3,7 @@ ruby.h - $Author: matz $ - $Date: 1994/06/27 15:48:38 $ + $Date: 1994/08/12 11:06:43 $ created at: Thu Jun 10 14:26:32 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -70,7 +70,8 @@ typedef unsigned short USHORT; #define POINTER(p) (p) #define NIL_P(p) ((p) == Qnil) -#define TRUE INT2FIX(1) +#undef TRUE +extern VALUE TRUE; #define FALSE Qnil extern VALUE C_Object; @@ -179,9 +180,12 @@ struct RData { #define DATA_PTR(dta) (RDATA(dta)->data) +VALUE rb_ivar_get_1(); +VALUE rb_ivar_set_1(); + #define Get_Data_Struct(obj, iv, type, sval) {\ VALUE _data_;\ - _data_ = rb_iv_get(obj, iv);\ + _data_ = rb_ivar_get_1(obj, iv);\ Check_Type(_data_, T_DATA);\ sval = (type*)DATA_PTR(_data_);\ } @@ -192,8 +196,8 @@ struct RData { _new_->dmark = (void (*)())(mark);\ _new_->dfree = (void (*)())(free);\ sval = (type*)DATA_PTR(_new_);\ - bzero(sval, sizeof(type));\ - rb_iv_set(obj, iv, _new_);\ + memset(sval, 0, sizeof(type));\ + rb_ivar_set_1(obj, iv, _new_);\ } struct RStruct { @@ -226,6 +230,8 @@ struct RBignum { #define RSTRUCT(obj) (R_CAST(RStruct)(obj)) #define RBIGNUM(obj) (R_CAST(RBignum)(obj)) +extern VALUE rb_self(); +#define Qself rb_self() #define Qnil (VALUE)0 #define ALLOC_N(type,n) (type*)xmalloc(sizeof(type)*(n)) @@ -240,7 +246,6 @@ void rb_define_const(); void rb_define_method(); void rb_define_single_method(); -void rb_define_mfunc(); void rb_undef_method(); void rb_define_alias(); void rb_define_attr(); diff --git a/sample/biorhythm.rb b/sample/biorhythm.rb index 3261c4377f..eb14ca7365 100644 --- a/sample/biorhythm.rb +++ b/sample/biorhythm.rb @@ -41,7 +41,7 @@ def leapyear(y) return ta end -def bcalc(t, m, j) +def bcalc(tt, m, j) ta = 0 if (m <= 2) ta = (m - 1) * 31 @@ -51,7 +51,7 @@ def bcalc(t, m, j) end ta = ta + (j - 1) * 365 + ((j - 1) / 4.0).to_i ta = ta - ((j - 1) / 100) + ((j - 1) / 400.0).to_i - ta = ta + t + ta = ta + tt return ta end diff --git a/sample/cat2.rb b/sample/cat2.rb new file mode 100644 index 0000000000..f979dc53cb --- /dev/null +++ b/sample/cat2.rb @@ -0,0 +1,4 @@ +while gets() + if 1 ... /^\*/; print("--") end + printf("%5d: %s", $., $_) +end diff --git a/sample/getopts.rb b/sample/getopts.rb index 57a7db424f..01eddcea98 100644 --- a/sample/getopts.rb +++ b/sample/getopts.rb @@ -55,7 +55,7 @@ def getopts(single_opts, *opts) while ($ARGV.length != 0) compare = nil case $ARGV[0] - when /^-*$/ + when /^--?$/ $ARGV.shift break when /^--.*/ diff --git a/sample/io.rb b/sample/io.rb index 45d50d653a..b5591af7e4 100644 --- a/sample/io.rb +++ b/sample/io.rb @@ -13,7 +13,7 @@ end printf("%s:(%d)%s\n", $0, $ARGV.length, $ARGV[0]) passwd = open($ARGV[0], "r") -#printf("%s", do passwd.find using i; i =~ /\*/ end) +#printf("%s", passwd.find{i|i =~ /\*/}) n = 1 for i in passwd #.grep(/^\*/) diff --git a/newver.rb b/sample/newver.rb index bee3853c25..bbf03aebc2 100755..100644 --- a/newver.rb +++ b/sample/newver.rb @@ -1,14 +1,13 @@ #! /usr/local/bin/ruby + f = open("version.h", "r") f.gets() f.close -if $_ =~ /"(\d+)\.(\d+)"/; +if $_ =~ /"(\d)\.(\d+)"/; f = open("version.h", "w") i = $2.to_i + 1 - date = Time.now.strftime("%d %b %y") - printf("ruby version %d.%0d (%s)\n", $1, i, date) + printf("ruby version %d.%0d\n", $1, i) printf(f, "#define RUBY_VERSION \"%d.%0d\"\n", $1, i) - printf(f, "#define VERSION_DATE \"%s\"\n", date) f.close end diff --git a/sample/rcs.rb b/sample/rcs.rb index 6d7f10c6bc..0ed4a36c1e 100644 --- a/sample/rcs.rb +++ b/sample/rcs.rb @@ -14,12 +14,16 @@ while gets() while xr < hdw x = xr * (1 + y) - y * w / 2 i = (x / (1 + h) + sw /2) - c = if (1 < i && i < $_.length); $_[i, 1].to_i else 0 end + if (1 < i && i < $_.length); + c = $_[i, 1].to_i + else + c = 0 + end y = h - d * c xl = xr - w * y / (1 + y); if xl < -hdw || xl >= hdw || xl <= maxxl - t = rand(ss.length) - c = ss[t, 1] + tt = rand(ss.length) + c = ss[tt, 1] else c = s[xl + hdw, 1] maxxl = xl diff --git a/sample/ruby-mode.el b/sample/ruby-mode.el index 96915bdc5a..8f864d3846 100644 --- a/sample/ruby-mode.el +++ b/sample/ruby-mode.el @@ -8,22 +8,23 @@ ;;; (defconst ruby-block-beg-re - "class\\|module\\|def\\|if\\|case\\|while\\|do\\|for\\|protect" + "class\\|module\\|def\\|if\\|unless\\|case\\|while\\|until\\|for\\|protect" ) (defconst ruby-block-mid-re - "else\\|elsif\\|when\\|using\\|resque\\|ensure" + "else\\|elsif\\|when\\|resque\\|ensure" ) -(defconst ruby-block-end-re - (concat "\\(end\\([ \t]+\\(" ruby-block-beg-re "\\)\\)?\\)") - ) +(defconst ruby-block-end-re "end") (defconst ruby-delimiter - (concat "(\\|)\\|\\{\\|\\}\\|\"\\|\'\\|\\b\\(" ruby-block-beg-re "\\|" ruby-block-end-re "\\)\\b\\|#") + (concat "[/<(){}#\"'`]\\|\\[\\|\\]\\|\\b\\(" + ruby-block-beg-re "\\|" ruby-block-end-re "\\)\\b") ) + (defconst ruby-negative - (concat "^[ \t]*\\b\\(\\(" ruby-block-mid-re "\\)\\|\\(" ruby-block-end-re "\\)\\)\\b") + (concat "^[ \t]*\\(\\b\\(" ruby-block-mid-re "\\)\\|\\(" + ruby-block-end-re "\\)\\b\\|\\}\\|\\]\\)") ) (defvar ruby-mode-abbrev-table nil @@ -51,9 +52,10 @@ (setq ruby-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?\' "\"" ruby-mode-syntax-table) (modify-syntax-entry ?\" "\"" ruby-mode-syntax-table) - (modify-syntax-entry ?\n "> " ruby-mode-syntax-table) - (modify-syntax-entry ?\f "> " ruby-mode-syntax-table) - (modify-syntax-entry ?# "< " ruby-mode-syntax-table) +;;(modify-syntax-entry ?\n ">" ruby-mode-syntax-table) +;;(modify-syntax-entry ?\f ">" ruby-mode-syntax-table) + (modify-syntax-entry ?# "<" ruby-mode-syntax-table) + (modify-syntax-entry ?\\ "'" ruby-mode-syntax-table) (modify-syntax-entry ?_ "w" ruby-mode-syntax-table) (modify-syntax-entry ?< "." ruby-mode-syntax-table) (modify-syntax-entry ?> "." ruby-mode-syntax-table) @@ -68,9 +70,9 @@ (modify-syntax-entry ?- "." ruby-mode-syntax-table) (modify-syntax-entry ?\; "." ruby-mode-syntax-table) (modify-syntax-entry ?\( "()" ruby-mode-syntax-table) - (modify-syntax-entry ?) ")(" ruby-mode-syntax-table) - (modify-syntax-entry ?{ "(}" ruby-mode-syntax-table) - (modify-syntax-entry ?} "){" ruby-mode-syntax-table) + (modify-syntax-entry ?\) ")(" ruby-mode-syntax-table) + (modify-syntax-entry ?\{ "(}" ruby-mode-syntax-table) + (modify-syntax-entry ?\} "){" ruby-mode-syntax-table) (modify-syntax-entry ?\[ "(]" ruby-mode-syntax-table) (modify-syntax-entry ?\] ")[" ruby-mode-syntax-table) ) @@ -78,23 +80,6 @@ (defvar ruby-indent-level 2 "*Indentation of ruby statements.") -(defun ruby-mode-variables () - (setq local-abbrev-table ruby-mode-abbrev-table) - (make-local-variable 'indent-line-function) - (setq indent-line-function 'ruby-indent-line) - (make-local-variable 'require-final-newline) - (setq require-final-newline t) - (make-variable-buffer-local 'comment-start) - (setq comment-start "# ") - (make-variable-buffer-local 'comment-end) - (setq comment-end "") - (make-variable-buffer-local 'comment-column) - (setq comment-column 32) - (make-variable-buffer-local 'comment-start-skip) - (setq comment-start-skip "#+ *") - (make-local-variable 'parse-sexp-ignore-comments) - (setq parse-sexp-ignore-comments t)) - (defun ruby-mode () "Major mode for editing ruby scripts. \\[ruby-indent-command] properly indents subexpressions of multi-line @@ -109,7 +94,21 @@ The variable ruby-indent-level controls the amount of indentation. (setq mode-name "ruby") (setq major-mode 'ruby-mode) (set-syntax-table ruby-mode-syntax-table) - (ruby-mode-variables) + (setq local-abbrev-table ruby-mode-abbrev-table) + (make-local-variable 'indent-line-function) + (setq indent-line-function 'ruby-indent-line) + (make-local-variable 'require-final-newline) + (setq require-final-newline t) + (make-variable-buffer-local 'comment-start) + (setq comment-start "# ") + (make-variable-buffer-local 'comment-end) + (setq comment-end "") + (make-variable-buffer-local 'comment-column) + (setq comment-column 32) + (make-variable-buffer-local 'comment-start-skip) + (setq comment-start-skip "#+ *") + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments t) (run-hooks 'ruby-mode-hook)) (defun ruby-current-indentation () @@ -131,10 +130,8 @@ The variable ruby-indent-level controls the amount of indentation. (defun ruby-indent-line (&optional flag) "Correct indentation of the current ruby line." - (let - ((x (ruby-calculate-indent))) - (ruby-indent-to x))) - + (ruby-indent-to (ruby-calculate-indent))) + (defun ruby-indent-command () (interactive) (ruby-indent-line t)) @@ -166,14 +163,36 @@ The variable ruby-indent-level controls the amount of indentation. (ruby-beginning-of-defun)) (while (and (> indent-point (point)) (re-search-forward ruby-delimiter indent-point t)) - (let ((w (buffer-substring (match-beginning 0) (match-end 0)))) + (let ((w (buffer-substring (match-beginning 0) (match-end 0))) + (pnt (match-beginning 0))) (cond ((or (string= "\"" w) ;skip string - (string= "\'" w)) + (string= "'" w) + (string= "`" w)) (if (search-forward w indent-point t) nil (goto-char indent-point) (setq in-string t))) + ((or (string= "/" w) + (string= "<" w)) + (if (string= "<" w) (setq w ">")) + (let (c) + (save-excursion + (goto-char pnt) + (skip-chars-backward " \t") + (setq c (char-after (1- (point)))) + (if c + (setq c (char-syntax c)))) + (cond + ((or (eq c ?.) + (and (eq c ?w) + (save-excursion + (forward-word -1) + (looking-at ruby-block-beg-re)))) + (if (search-forward w indent-point t) + nil + (goto-char indent-point) + (setq in-string t)))))) ((string= "#" w) ;skip comment (forward-line 1)) ((string= "(" w) ;skip to matching paren @@ -189,7 +208,21 @@ The variable ruby-indent-level controls the amount of indentation. (t (setq nest (cdr nest)) (setq depth (1- depth))))) - (if (> depth orig) (setq in-paren t)))) + (if (> depth orig) (setq in-paren ?\()))) + ((string= "[" w) ;skip to matching paren + (let ((orig depth)) + (setq nest (cons (point) nest)) + (setq depth (1+ depth)) + (while (and (/= depth orig) + (re-search-forward "\\[\\|\\]" indent-point t)) + (cond + ((= (char-after (match-beginning 0)) ?\[ ) + (setq nest (cons (point) nest)) + (setq depth (1+ depth))) + (t + (setq nest (cdr nest)) + (setq depth (1- depth))))) + (if (> depth orig) (setq in-paren ?\[)))) ((string= "{" w) ;skip to matching paren (let ((orig depth)) (setq nest (cons (point) nest)) @@ -197,22 +230,28 @@ The variable ruby-indent-level controls the amount of indentation. (while (and (/= depth orig) (re-search-forward "[{}]" indent-point t)) (cond - ((= (char-after (match-beginning 0)) ?\{ ) + ((= (char-after (match-beginning 0)) ?{ ) (setq nest (cons (point) nest)) (setq depth (1+ depth))) (t (setq nest (cdr nest)) (setq depth (1- depth))))) - (if (> depth orig) (setq in-paren t)))) - ((string-match "^end" w) + (if (> depth orig) (setq in-paren ?{)))) + ((string-match ruby-block-end-re w) (setq nest (cdr nest)) (setq depth (1- depth))) ((string-match ruby-block-beg-re w) - (setq nest (cons (point) nest)) - (setq depth (1+ depth))) + (let (c) + (save-excursion + (goto-char pnt) + (skip-chars-backward " \t") + (setq c (char-after (1- (point))))) + (if (or (null c) (= c ?\n) (= c ?\;)) + (progn + (setq nest (cons (point) nest)) + (setq depth (1+ depth)))))) (t (error (format "bad string %s" w))))))) - (if in-paren (message "in-paren")) (list in-string in-paren (car nest) depth))) (defun ruby-calculate-indent (&optional parse-start) @@ -224,7 +263,7 @@ The variable ruby-indent-level controls the amount of indentation. (indent 0)) (if parse-start (goto-char parse-start) - (beginning-of-defun) + (ruby-beginning-of-defun) (setq parse-start (point))) (setq state (ruby-parse-region parse-start indent-point)) (cond @@ -234,9 +273,9 @@ The variable ruby-indent-level controls the amount of indentation. ((nth 1 state) ; in paren (goto-char (nth 2 state)) (setq indent - (if (looking-at "$") - (+ (current-indentation) ruby-indent-level) - (current-column)))) + (if (and (eq (nth 1 state) ?\( ) (not (looking-at "$"))) + (current-column) + (+ (current-indentation) ruby-indent-level)))) ((> (nth 3 state) 0) ; in nest (goto-char (nth 2 state)) @@ -258,7 +297,7 @@ The variable ruby-indent-level controls the amount of indentation. With argument, do this that many times. Returns t unless search stops due to end of buffer." (interactive "p") - (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)") + (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)\\b") nil 'move (or arg 1)) (progn (beginning-of-line) t))) @@ -266,7 +305,7 @@ Returns t unless search stops due to end of buffer." "Move forward to next end of defun. An end of a defun is found by moving forward from the beginning of one." (interactive "p") - (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)") + (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\b") nil 'move (or arg 1)) (progn (beginning-of-line) t)) (forward-line 1)) diff --git a/sample/sieve.rb b/sample/sieve.rb new file mode 100644 index 0000000000..0228243fda --- /dev/null +++ b/sample/sieve.rb @@ -0,0 +1,16 @@ +sieve = [] +unless max = $ARGV.shift; max = 100; end +max = max.to_i + +print "1" +for i in 2 .. max + protect + for d in sieve + fail if i % d == 0 + end + print ", " + print i + sieve.push(i) + resque + end +end diff --git a/sample/t2.rb b/sample/t2.rb index 7f5b9df480..a34c171837 100644 --- a/sample/t2.rb +++ b/sample/t2.rb @@ -7,7 +7,7 @@ def println(*args) print(a) end print("\n") -end def +end def tt for i in 1..10 @@ -16,9 +16,8 @@ def tt end end -test = -do tt() using i +test = tt{i| if i == 3; break end println("ttt: ", i); -end +} #exit() diff --git a/sample/trojan.rb b/sample/trojan.rb index bd49d44357..b42fd166a8 100644 --- a/sample/trojan.rb +++ b/sample/trojan.rb @@ -2,11 +2,13 @@ path = $ENV['PATH'].split(/:/) for dir in path - for f in d = Dir.open(dir) - fpath = dir+"/"+f - if File.f(fpath) && (File.stat(fpath).mode & 022) != 0 - printf("file %s is writable from other users\n", fpath) + if File.d(dir) + for f in d = Dir.open(dir) + fpath = dir+"/"+f + if File.f(fpath) && (File.stat(fpath).mode & 022) != 0 + printf("file %s is writable from other users\n", fpath) + end end + d.close end - d.close end diff --git a/sample/tt.rb b/sample/tt.rb index cb863e3527..c53ec39d68 100644 --- a/sample/tt.rb +++ b/sample/tt.rb @@ -5,13 +5,13 @@ module Print print(a) end print("\n") - end def + end def println2(*args) print(*args) print("\n") - end def -end module + end +end module Print2 def println(*args) @@ -52,20 +52,20 @@ class Fib:Object if args; println(*args) end args = args.grep(/^c/) super(*args) - end def + end def init println("in Fib.init"); - end def + end def fib(n) a =0; b = 1 while b <= n c = a; a = b; b = c+b - end while + end return b - end def + end end def Object.test(*args) @@ -96,8 +96,5 @@ def tt end end -test = do tt() using i - if i == 2; break end -end - +test = tt() {i|break if i == 2} println([1,2,3,4].join(":")) @@ -3,7 +3,7 @@ socket.c - $Author: matz $ - $Date: 1994/06/17 14:23:51 $ + $Date: 1994/08/12 04:47:56 $ created at: Thu Mar 31 12:21:29 JST 1994 ************************************************/ @@ -65,7 +65,8 @@ Fbsock_shutdown(sock, args) GetOpenFile(sock, fptr); if (shutdown(fileno(fptr->f), how) == -1) rb_sys_fail(Qnil); - return sock; + + return INT2FIX(0); } static VALUE @@ -84,7 +85,8 @@ Fbsock_setopt(sock, lev, optname, val) GetOpenFile(sock, fptr); if (setsockopt(fileno(fptr->f), level, option, val->ptr, val->len) < 0) rb_sys_fail(fptr->path); - return sock; + + return INT2FIX(0); } static VALUE @@ -533,6 +535,13 @@ Fsock_open(class, domain, type, protocol) } static VALUE +Fsock_for_fd(class, fd) + VALUE class, fd; +{ + return sock_new(class, NUM2INT(fd)); +} + +static VALUE Fsock_socketpair(class, domain, type, protocol) VALUE class, domain, type, protocol; { @@ -559,7 +568,8 @@ Fsock_connect(sock, addr) GetOpenFile(sock, fptr); if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) rb_sys_fail("connect(2)"); - return sock; + + return INT2FIX(0); } static VALUE @@ -575,7 +585,8 @@ Fsock_bind(sock, addr) GetOpenFile(sock, fptr); if (bind(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) rb_sys_fail("bind(2)"); - return sock; + + return INT2FIX(0); } static VALUE @@ -587,7 +598,8 @@ Fsock_listen(sock, log) GetOpenFile(sock, fptr); if (listen(fileno(fptr->f), NUM2INT(log)) < 0) rb_sys_fail("listen(2)"); - return sock; + + return INT2FIX(0); } static VALUE @@ -695,6 +707,7 @@ Init_Socket () C_Socket = rb_define_class("Socket", C_BasicSocket); rb_define_single_method(C_Socket, "open", Fsock_open, 3); rb_define_single_method(C_Socket, "new", Fsock_open, 3); + rb_define_single_method(C_Socket, "for_fd", Fsock_for_fd, 1); rb_define_method(C_Socket, "connect", Fsock_connect, 1); rb_define_method(C_Socket, "bind", Fsock_bind, 1); @@ -42,10 +42,10 @@ Rubyのオブジェクト指向機能について学べば, より強力なこともできるように イルをリンクできるし, そうでなくてもRubyを再コンパイルして組み込みクラ スを追加するのは容易である(Perlなどよりもはるかに容易である). -* Rubyの基本 +* Rubyの文法 -Rubyの基本的な部分は非常に小さく, 文法に例外が少ないので身につけるのは -さほど難しくないだろう. +ここではRuby言語の文法を解説する. Rubyの基本的な部分は非常に小さく, 文 +法に例外が少ないので身につけるのはさほど難しくないだろう. ** コメント @@ -54,214 +54,193 @@ Rubyの基本的な部分は非常に小さく, 文法に例外が少ないので身につけるのは ** 区切り記号 -空白文字(タブとスペース)および改行(\n)が区切り記号となる. ただし, +空白文字(タブとスペース)および改行(\n)が区切り記号となる. 更に +改行は a + b -のように行が式(文)の途中で終り, 次の行に続くことが明白な場合以外は改行 -は文の区切りとして認識される. - -** 識別子 - -アルファベットか`_'で始まり, アルファベット, 数字, `_'の任意の並びは識 -別子である. 識別子の長さに制限はない. +のように行が式(文)の途中で終り, 次の行に続くことが明白な場合以外は文の +区切りとしても認識される. ** 予約語 予約語は以下の通りである - break elsif module self when - case end nil super while - class ensure protect then yield - continue for redo undef __END__ - def if resque unless __FILE__ - do in retry until __LINE__ - else include return using + break end module self while + case ensure nil super yield + class fail protect then __END__ + continue for redo undef __FILE__ + def if resque unless __LINE__ + else in retry until + elsif include return when 予約語はクラス名, メソッド名, 変数名などに用いることはできない. -** グルーピング - -式は括弧によってグルーピングすることができる. 更に括弧内には式の並びも -書ける. 式の並びを記述する場合, 式と式の区切りには改行か ';' を用いる. -式の並びの値は最後に評価した式の値である. つまり - - (式; 式; ...) - -の値は最後に評価した式の値になる. - -** リテラル - -以下のリテラルがある これらは式である. +** 式 - 文字列リテラル +Rubyプログラムを構成する要素は式と文である. まず, 式から解説する. - "..." # バックスラッシュの解釈と変数展開あり - '...' # バックスラッシュの解釈なし(\\と\'は解釈する) +*** リテラル - バックスラッシュ記法 +プログラム中に直接記述できるオブジェクトをリテラルと呼ぶ. Rubyのリテラ +ルには文字列, 正規表現, 数値というリテラルがある. - \t タブ(0x09) - \n 改行文字(0x0a) - \r 復帰文字(0x0d) - \f 改ページ文字(0x0c) - \b バックスペース(0x08) - \a ベル(0x07) - \e エスケープ(0x1b) - \# 文字`#'そのもの - \nnn 8進数表記(nは0-7) - \xnn 16進数表記(nは0-9,a-f) - \^c コントロール文字(cはASCII文字) - \C-c コントロール文字(同上) - \M-c メタ文字(c|0x80) +**** 文字列リテラル - 正規表現リテラル + "..." # バックスラッシュの解釈と変数展開あり + '...' # バックスラッシュの解釈なし(\\と\'は解釈する) - /.../ +**** バックスラッシュ記法 - 正規表現 + \t タブ(0x09) + \n 改行文字(0x0a) + \r 復帰文字(0x0d) + \f 改ページ文字(0x0c) + \b バックスペース(0x08) + \a ベル(0x07) + \e エスケープ(0x1b) + \# 文字`#'そのもの + \nnn 8進数表記(nは0-7) + \xnn 16進数表記(nは0-9,a-f) + \^c コントロール文字(cはASCII文字) + \C-c コントロール文字(同上) + \M-c メタ文字(c|0x80) - ^ 行頭 - $ 行末 - . 任意の1文字 - \w 英数字. [0-9A-Za-z_]と同じ - \W 非英数字 - \s 空白文字. [ \t\n\r\f]と同じ - \S 非空白文字 - \d 数字. [0-9] と同じ - \D 非数字 - \b 語境界文字(文字クラス外) - \B 非語境界文字 - \b 後退(0x08)(文字クラス内) - [ ] 文字クラス指定 - * 直前の表現の0回以上の繰り返し - + 直前の表現の1回以上の繰り返し - {m,n} m回からn回の繰り返し - ? 0または1回 - | 選択 - ( ) 正規表現をまとめる - - その他に文字列と同じバックスラッシュ記法も有効である. - - 数値リテラル - - 123 整数 - -123 整数(符合つき数) - 1_234 整数(10進数は`_'を含むことができる) - 123.45 浮動小数点数 - 1.2e-3 浮動小数点数 - 0xffff 16進整数 - 0377 8進整数 - ?a 文字`a'のコード(97) - ?\C-a コントロールaのコード(1) - ?\M-a メタaのコード(225) - ?\M-\C-a メタ-コントロールaのコード(129) - - ?表現では全てのバックスラッシュ記法が有効である. - -*** 変数展開 +**** 変数展開 ダブルクォート(`"')で囲まれた文字列と正規表現の中では `#{変数名}'とい う形式で変数の内容を展開することができる. 変数が変数記号(`$',`@',`%') を持つ場合には`#変数名'という形式でも展開できる. 文字`#'に続く文字が -`{'でないか, 変数でなければ, そのまま`#'として解釈される. - -** コマンドの出力 - -``で囲まれた文字列は, ダブルクォートと同様に展開された後, シェルと同じ -ようにコマンドとして実行され, その実行結果が文字列として与えられる. コ -マンドは評価されるたびに実行される. +`{',`$',`@',`%'でなければ, そのまま`#'として解釈される. -** 配列式 +**** 正規表現リテラル -配列式は以下の形式である. + /.../ - [ 式, ... ] + ^ 行頭 + $ 行末 + . 任意の1文字 + \w 英数字. [0-9A-Za-z_]と同じ + \W 非英数字 + \s 空白文字. [ \t\n\r\f]と同じ + \S 非空白文字 + \d 数字. [0-9] と同じ + \D 非数字 + \b 語境界文字(文字クラス外) + \B 非語境界文字 + \b 後退(0x08)(文字クラス内) + [ ] 文字クラス指定 + * 直前の表現の0回以上の繰り返し + + 直前の表現の1回以上の繰り返し + {m,n} m回からn回の繰り返し + ? 0または1回 + | 選択 + ( ) 正規表現をまとめる -それぞれの式を評価した結果を含む配列を返す. 要素が0の配列を生成するた -めには空の配列式 +その他に文字列と同じバックスラッシュ記法も有効である. - [] +**** ワイルドカードリテラル -を用いる. + <...> -** 連想配列式 + * 任意の文字列(空文字列を含む)と一致 + ? 任意の1文字と一致 + [ ] []内のいずれか1文字と一致 + {..} {}内のいずれかの文字列と一致 -連想配列とは任意のオブジェクトをキー(添字)として持てる配列である. Ruby -では連想配列はSmalltalkの用語を借りてDict(辞書)とも呼ばれる. 詳細はク -ラスDictの項を参照されたい. 連想配列を生成する連想配列式は以下の形式で -ある. +**** 数値リテラル - { 式=>式, ... } + 123 整数 + -123 整数(符合つき数) + 1_234 整数(10進数は`_'を含むことができる) + 123.45 浮動小数点数 + 1.2e-3 浮動小数点数 + 0xffff 16進整数 + 0377 8進整数 + ?a 文字`a'のコード(97) + ?\C-a コントロールaのコード(1) + ?\M-a メタaのコード(225) + ?\M-\C-a メタ-コントロールaのコード(129) -それぞれの式を評価した結果をキーと値とする連想配列オブジェクトを返す. -要素が0の連想配列を生成するためには空の連想配列式 + \シンボル 識別子/変数名と一対一対応する整数. applyなどでメソッ + ドを指定するのに使う. - {} +?表現では全てのバックスラッシュ記法が有効である. -を用いる. +*** コマンドの出力 -** 変数参照 +Rubyではshのようにコマンドの実行結果を文字列リテラルのように使うことが +できる. ``で囲まれた文字列は, ダブルクォートと同様にバックスラッシュ記 +法の解釈と変数展開が行なわれた後, コマンドとして実行され, その実行結果 +が文字列として与えられる. コマンドは評価されるたびに実行される. -変数には4種類あって, その種類は変数名の最初の一文字で決定される. 代入 -されていない変数を参照した時の値はnilである. +*** 変数参照 - クラス変数(定数) +Rubyの変数はスコープ(有効範囲)と寿命(有効期限)によって4種類に分類され, +その種類は変数名の最初の一文字で決定される. 通常の変数の2文字目以降は +英数時または`_'であるが, システム変数の一部は「`$'+1文字の記号」という +変数がある. 変数名の長さに関して特別な制限はない. - `%'で始まる変数はクラス変数であり, そのクラスと全てのサブクラスの - インスタンスから参照できる. この変数への代入はトップレベル, すなわ - ちメソッドが定義できるレベルでのみ可能である. この変数はクラス間で - 値が共有され, 一度代入するとメソッドからは値を変更することができな - いので,定数として用いられる. +変数のスコープに関わらず, 初期化されていない変数を参照した時の値はnil +である. - インスタンス変数 +**** グローバル変数 - `@'で始まる変数はインスタンス変数であり, そのクラスまたはサブクラ - スのメソッドから参照できる. その寿命はオブジェクトの寿命に等しい. +`$'で始まる変数のスコープはグローバルであり, プログラムのどこからでも +参照できる. その寿命はプログラムの寿命と等しい. - グローバル変数 +**** インスタンス変数 - `$'で始まる変数のスコープはグローバルであり, その寿命はプログラム - の寿命と等しい. +`@'で始まる変数はインスタンス変数であり, そのクラスまたはサブクラスの +メソッドから参照できる. スコープはメソッド内であり, その寿命はオブジェ +クトの寿命に等しい. - クラス名/モジュール名/ローカル変数 +**** クラス名/モジュール名/ローカル変数 - アルファベットまたは`_'で始まる変数は識別子とも呼ばれ, ローカ - ル変数, クラス名またはモジュール名である. +アルファベットまたは`_'で始まる変数は識別子とも呼ばれ, ローカル変数, +クラス名またはモジュール名である. - 初期状態では識別子はクラス/モジュール名とみなされるが(該当するクラ - スが存在しない場合の値はnil), 代入式の左辺に現れた識別子は,そのス - コープ内ではローカル変数として見なされ, 同名のクラスやモジュールは - 隠される. この意味で識別子への代入は宣言としての働きも持つ. +初期状態では識別子はクラス/モジュール名とみなされるが(該当するクラスが +存在しない場合の値はnil), 代入式の左辺に現れた識別子は,そのスコープ内 +ではローカル変数として見なされ, 同名のクラスやモジュールは隠される. こ +の意味で識別子への代入は宣言としての働きも持つ. Array # 配列クラス Array Array = 15 # 代入. 以後Arrayはローカル変数 - print(Array, "\n") # `15'が出力される + print Array, "\n" # `15'が出力される - この宣言はコンパイル時に解釈されるため, 識別子への代入式が実際に実 - 行されても, されなくても, 以降のスコープ内ではその識別子はローカル - 変数とみなされる. +この宣言としての代入の解釈はコンパイル時に行なわれるため, 識別子への代 +入式が実際に実行されてもされなくても, 以降のスコープ内ではその識別子は +ローカル変数とみなされる. Array # 配列クラス Array if %FALSE Array = 15 # このコードは実行されないが, # 以降Arrayはローカル変数とみなされる. end - print(Array, "\n") # `nil'が出力される + print Array, "\n" # `nil'が出力される + +このルールは一見複雑だが, クラス/モジュール名とローカル変数名が重複し +ない限り, 未初期化のローカル変数の値はnilであると考えても差し支えはな +い. Rubyの組み込みクラスは大文字のアルファベットで始まる名前がついて +おり, ユーザもクラス/モジュール名には大文字で始まる識別子を, ローカル +変数名には小文字または`_'で始まる識別子を使うことを強く推奨する. - このルールは一見複雑だが, クラス/モジュール名とローカル変数名が重 - 複しない限り, 未初期化のローカル変数の値はnilであると考えても差し - 支えはない. +ローカル変数のスコープも寿命もそのブロックの終りまで(トップレベルのロー +カル変数はプログラムの終了まで)である. - Rubyの組み込みクラスは大文字のアルファベットで始まる名前がついてお - り, ユーザもクラス/モジュール名には大文字で始まる識別子を, ローカ - ル変数名には小文字または`_'で始まる識別子を使うことを強く推奨する. +**** クラス変数(定数) - ローカル変数の寿命はそのメソッドが終了するまで(トップレベルのロー - カル変数はプログラムの終了まで)である. +`%'で始まる変数はクラス変数であり, そのクラスと全てのサブクラスのイン +スタンスから参照できる. この変数への代入はトップレベル, すなわちメソッ +ドが定義できるレベルでのみ可能である. この変数はクラス間で値が共有され, +一度代入するとメソッドからは値を変更することができないので,定数として +用いられる. -更に疑似変数と呼ばれる特殊な変数が4つある. +**** 疑似変数 + +通常の変数以外に疑似変数と呼ばれる特殊な変数が4つある. self | 現在のメソッドの実行主体 nil | Nilクラスの唯一のインスタンス(偽を表す) @@ -271,52 +250,99 @@ Rubyの基本的な部分は非常に小さく, 文法に例外が少ないので身につけるのは これらの疑似変数は代入によってその値を変更することはできない. これらの 変数への代入は例外を発生させる. -** メッセージ式 +*** メッセージ式 オブジェクトにメッセージを送る基本的な構文がメッセージ式であり, その基 本形式は以下の通りである. - 式1.メソッド名(引数...) + 式1 '.' メソッド名 '(' 引数1... [',' '*' 引数n ]')' - 式1を評価して得られるオブジェクトの, 識別子で指定されるメソッ - ドを呼び出す. 一番最後の引数が'*'に続く(単一の)式である場合, - その式を評価した結果(配列である必要がある)を展開して, 引数とし - て追加する. +式1を評価して得られるオブジェクトの, 識別子で指定されるメソッドを呼び +出す. 一番最後の引数が'*'に続く(単一の)式である場合, その式を評価した +結果(配列である必要がある)を展開して, 引数として追加する. - 引数が一つもない時には括弧を省略できる. +引数が一つもない時には括弧を省略できる. メソッド名としては任意の識別子を用いることができる. 変数名とは識別子の 名前空間が違うので重複しても構わない. -** 関数式 - メッセージ式で, レシーバがselfの場合, レシーバを省略して通常のプログラ ミング言語における関数のような形式でメソッドを呼び出すことができる. こ の場合引数が1つもない時でも括弧の省略はできない. 関数形式では`@'で始まる名前を持つメソッドを呼び出すことができる. `@'で 始まるメソッドは関数形式でしか呼び出すことができないため, 該当するクラ -スまたは, そのサブクラスからしか呼ばれないので, プライベートメソッドと -呼ばれる. プライベートメソッドはC++におけるprotected member functionに -該当する. +スまたはそのサブクラスからしか呼ばれないので, プライベートメソッドと呼 +ばれる. プライベートメソッドはC++におけるprotected member functionに該 +当する. -** スーパークラスのメソッド呼び出し +*** スーパークラスのメソッド呼び出し メッセージ式の特殊なケースとしてスーパークラスのメソッドの呼び出しがあ る. この形式はメソッドを再定義した時にスーパークラスの定義を利用するた めに使う. - super + super + +現在のメソッドに与えられた引数のままスーパクラスの同名のメソッドを呼び +出す. + + super'(' 引数... ')' + +引数とともにスーパークラスの同名のメソッドを呼び出す. 一番最後の引数が +`*'に続く場合は通常のメソッド呼び出しと同様に渡される. - 現在のメソッドに与えられた引数のままスーパクラスの同名のメソッ - ドを呼び出す. +*** 配列式/連想配列式 - super(引数...) +配列のオブジェクトを生成する式の形式は以下の形式である. - 引数とともにスーパークラスの同名のメソッドを呼び出す. 一番最後 - の引数が`*'に続く場合は通常のメソッド呼び出しと同様に渡される. + '[' 式, ... ']' -** 演算式 +それぞれの式を評価した結果を含む配列を返す. 要素数が0の空配列を生成す +るためには空の配列式 + + '[' ']' + +を用いる. + +** 連想配列式 + +連想配列とは任意のオブジェクトをキー(添字)として持てる配列である. Ruby +では連想配列はSmalltalkの用語を借りてDict(辞書)とも呼ばれる. 詳細はク +ラスDictの項を参照されたい. 連想配列を生成する連想配列式は以下の形式で +ある. + + '{' 式 '=>' 式... '}' + +それぞれの式を評価した結果をキーと値とする連想配列オブジェクトを返す. +要素数が0の連想配列を生成するためには空の連想配列式 + + '{' '}' + +を用いる. + +*** 配列参照, 配列代入 + +配列(連想配列を含む)の要素の参照は以下の形式で行なう. + + 式1 '[' 式2... ']' + +この形式は内部的に, 式1に"[]"というメッセージを送ると解釈される. この +動作を疑似的なコードで記述すれば以下のようになる. + + 式1"[]="(式2) + +一方, 配列要素の代入は + + 式1 '[' 式2... ']' '=' 式n + +という形式で行なわれ, + + 式1."[]="(式2..) + +という形式として解釈される. + +*** 演算子形式 プログラミングの利便のために一部のメソッド呼び出しと制御構造は演算子形 式をとる. Rubyには以下にあげる演算子がある. 上のものほど結合順位が強く, @@ -335,68 +361,33 @@ Rubyの基本的な部分は非常に小さく, 文法に例外が少ないので身につけるのは || .. ... :: - =(代入) 自己代入(+=, -=, ..) - 弱 yield + 弱 =(代入) 自己代入(+=, -=, ..) ほとんどの演算式にはメソッド呼び出しとして解釈される(クラス毎に再定義 できる)が, 一部再定義できない特殊なものがある. 再定義できない特殊演算 子は &&(論理積), ||(論理和), =(代入), ...(範囲指定), - yield(ブロック呼び出し) -の5つである. +の4つである. 上であげた特殊演算子以外の演算子形式はメソッド呼び出しと見なされる. 単項演算子(+, -, !, ~)は - 式1."演算子"() - -という形式に, 2項演算子は + 式1."演算子"() - 式1."演算子"(式2) +という形式に, それ以外の2項演算子は -に解釈される. 多項演算子(配列の参照の[])は演算子形式の特別な形として + 式1."演算子"(式2) - recv[arg..] - -が, - - recv."[]"(arg..) - -と解釈される. 配列要素への代入も同様に - - recv[arg0..] = argn - -が, - - recv."[]="(arg0.., argn) - -と解釈される. - -** 条件式 - -if, unless, while, untilの条件判断部の式, および特殊演算子`&&', `||', -`...'の両辺の式, 通常演算子`!'の右辺は条件式と呼ばれる. 条件式では文字 -列と正規表現リテラルは式「$_=~リテラル」の省略であるとみなされる. 更に -演算子`...'の両辺では整数定数が「$.==定数」の省略と解釈される. - -注意: 演算子`!'は特殊演算子ではないので, 再定義を行なう場合に気をつけ -ること. - - ! 文字列リテラル - ! 正規表現リテラル - -の形で呼び出されるメソッドの引数は, リテラルの表すオブジェクトではなく, -上記の比較の結果が与えられる. このため, 原則的に`!'メソッドは再定義し -ない方が良いと思う. +に解釈される. ** 代入 代入には変数に対する代入(真の代入)と, プログラムを簡単にするためのシン タックスシュガーとしての代入がある. 真の代入は以下の形式である. - 変数 = 式 + 変数 '=' 式 これは式を評価し, 変数の値として代入する. クラスやモジュールや疑似変数 には代入できない. クラスやモジュールの定義を変更するためにはclass文, @@ -405,171 +396,207 @@ module文を用いる. 代入式は演算子形式をとっているが, メソッドではないの シンタックスシュガーとしての代入式は以下のものがある. - 配列要素への代入 +配列要素への代入 - 式1[式2,..] = 式n + 式1'[' 式2... ' ]' '=' 式n - 式1を評価して得られるオブジェクトに, 式2から式nまでを引数とし - て, "[]="というメソッドを呼び出す. +式1を評価して得られるオブジェクトに, 式2から式nまでを引数として, "[]=" +というメソッドを呼び出す. - 属性代入 +属性代入 - 式1.識別子 = 式2 + 式1 '.' 識別子 '=' 式2 - 式1を評価して得られるオブジェクトに対して"識別子="というメソッ - ドを, 式2を引数として呼び出す. +式1を評価して得られるオブジェクトに対して"識別子="というメソッドを, 式 +2を引数として呼び出す. - 自己代入 +自己代入 - 式1 op= 式2 # 式1は代入可能でなければならない. + 式1 op= 式2 # 式1は代入可能でなければならない. - この形式は内部的に「式1 = 式1 op 式2」と展開され, 実行される. その - ため式1は2回評価されるので, 副作用がある場合は予想しない結果を呼ぶ - 可能性がある. 自己代入形式はプログラマのタイプ数を減らす目的のため - に存在する形式である. opとして使える演算子は +この形式は内部的に「式1 = 式1 op 式2」と展開され, 実行される. そのため +式1は2回評価されるので, 副作用がある場合は予想しない結果を呼ぶ可能性が +ある. 自己代入形式はプログラマのタイプ数を減らす目的のために存在する形 +式である. opとして使える演算子は +, -, *, /, %, **, &, |, ^, <<, >> - の11種類である. 演算子と`='の間にスペースを空けてはいけない. - -*** 多重代入 - -同時に複数の変数に代入を行なうことができる. その形式は以下の通りである. +の11種類である. 演算子と`='の間にスペースを空けてはいけない. - 変数, [変数,...] = 式 [, 式] +*** 条件分岐式 -右辺の式が一つしかない場合は, その値を配列として(必要ならばto_aメソッ -ドで配列に変換して), 要素をそれぞれ変数に代入する. それ以外の場合には, -それぞれの式の値が変数に代入される. 左辺の変数の数と右辺の要素の数が合 -わない時には足りない変数には nilが代入され, 余った要素は無視される. +式の値によって分岐する式は以下に示すif式, unless式, case式の複合文型が +3種類と演算子型が3種類ある. Rubyではnilが偽, それ以外が真と評価される. +CやPerlなどとは異なり, 0や ""(空文字列)は偽とは評価されないので気をつ +けること. - foo, bar = [1, 2] # foo = 1; bar = 2 - foo, bar = 1, 2 # foo = 1; bar = 2 - foo, bar = 1 # foo = 1; bar = nil - - foo, bar, baz = 1, 2 # foo = 1; bar = 2; baz = nil - foo, bar = 1, 2, 3 # foo = 1; bar = 2 - -** 条件分岐 +if式 if 式1 [then] 文1 - [ elsif 式2 [then] + [elsif 式2 [then] 文2 ]... - [ else + [else 文n ] - end [ if ] + end - 条件判断文. else if でもelifでもなくelsifでifの連続を行なうことに - 注意すること. +条件判断式. 式1が真の場合に文1を評価する. それ以外の場合は文2を評価す +る. Rubyのif式はelse ifでもelifでもなくelsifでifの連続を行なうことに注 +意すること. + +unless式 unless 式1 [then] - 文1 - [ else + 文1 + [else 文2 ] - end [ unless ] - - 式1が偽(nil)を返すか, 式2の評価中に例外が発生した場合に文1を評価 - する. - - 式1 && 式2 - - 式1を評価し, その値が真(nil以外)であれば, 式2を評価する. - - 式1 || 式2 - - 式1を評価し, その値が偽であれば, 式2を評価する. + end - 式1 ... 式2 +式1が偽(nil)を返すか, 式2の評価中に例外が発生した場合に文1を評価する. +それ以外の場合は文2を評価する. - 式1が真になるまでは偽を返し, その後は式2が真を返すまでは真を返す. - 式2が真になれば状態は偽に戻る +case式 case 式0 - [ when 式1 [, 式2]... + [when 式1 [, 式2]... 文1 ]... - [ else + [else 文n ] - end [ case ] + end - 条件分岐, CのswitchよりもPascalのcaseに似ている. breakで脱出するこ - とも後ろの文に継続することもないので注意. +条件分岐, CのswitchよりもPascalのcaseに似ている. breakで脱出することも +後ろの文に継続することもないので注意. - 条件の一致は「式n =~ 式0]で行なわれる. つまり, +条件の一致は「式n =~ 式0]で行なわれる. つまり, - case expr0 - when expr1, expr2 - stmt1 - when expr3, expr4 + case expr0 + when expr1, expr2 + stmt1 + when expr3, expr4 + stmt2 + else + stmt3 + end + +は以下のif文と等価である. + + _tmp = expr0 + if expr1 =~ _tmp || expr2 =~ _tmp + stmt1 + elsif expr3 =~ _tmp || expr4 =~ _tmp stmt2 - else + else stmt3 - end + end + +演算子型 + + 式1 '&&' 式2 + +式1を評価し, その値が真(nil以外)であれば, 式2を評価する. + + 式1 '||' 式2 - は以下のif文と等価である. +式1を評価し, その値が偽であれば, 式2を評価する. - _tmp = expr0 - if expr1 =~ _tmp || expr2 =~ _tmp - stmt1 - elsif expr3 =~ _tmp || expr4 =~ _tmp - stmt2 - else - stmt3 - end + 式1 '...' 式2 -** 繰り返し +式1が真になるまでは偽を返し, その後は式2が真を返すまでは真を返す. 式2 +が真になれば状態は偽に戻る + +*** 繰り返し式(単純型) + +ループを構成する式. これらの式の値は常にnilである. オブジェクトに合わ +せたループを行なうためには次に述べるイテレータを用いる. + +while式 while 式 文 - end [ while ] + end + +条件が真の間, 文を繰り返し実行する. - 条件が真の間, 文を繰り返し実行する. +until式 until 式 文 - end [ until ] + end 式1 until 式2 - 式が偽(nil)を返すか, 式の評価中に例外が発生する間, 文を繰り返し実 - 行する. +式が偽(nil)を返すか, 式の評価中に例外が発生する間, 文を繰り返し実行す +る. + +*** 条件式について + +if, unless, while, untilの条件判断部の式, および特殊演算子`...'の両辺 +の式は条件式と呼ばれる. 条件式では文字列と正規表現リテラルは式「$_=~リ +テラル」の省略であるとみなされる. 更に演算子`...'の両辺では整数定数が +「$.==定数」の省略と解釈される. 条件式に現れる演算子 `&&', `||', `!'の +右辺の式も条件式とみなされる. + +注意: 演算子`!'は特殊演算子ではないので, 再定義を行なう場合に気をつけ +ること. 条件式の中で + + ! 文字列リテラル + ! 正規表現リテラル + +の形で呼び出されるメソッドの引数は, リテラルの表すオブジェクトではなく, +上記の比較の結果が与えられる. このため, 原則的に`!'メソッドは再定義し +ない方が良い. + +*** イテレータ(繰り返し子) ** イテレータ イテレータとは制御構造(特にループ)の抽象化のために用いられるメソッドの +一種である. コードの断片(ブロックと呼ばれる)を指定してイテレータを呼び +出すと, イテレータは適当な値をセットしてブロックを評価する(おそらくは +複数回). イテレータからのブロックの呼び出しはyield式を用いる(後述). + +イテレータの呼び出しは以下の構文で行なわれる. + +イテレータとは制御構造(特にループ)の抽象化のために用いられるメソッドの 一種である. イテレータの呼び出しは以下の構文で行なわれる. - do - 文1 - using 変数 - 文2 - end [ do ] - - 「文2」をブロックとして設定し, 文1のメソッドをイテレータとして評価 - する. 文1のトップレベルのメソッドだけがイテレータとして呼び出され, - レシーバを表す式や, 引数の式はイテレータとしては呼び出されない. 文 - 1に複数の式があれば各々がイテレータとして順に呼ばれる. - -イテレータ内でyield valueが実行されると, その値がdo文で指定された変数 -に代入されブロックが実行される. ブロックの実行が終了するとその値は -yield式の値として返される. あるメソッドがイテレータとして呼び出された -かどうかは関数iterator_p()で知ることができる. 中にはEnumerableモジュー -ルのgrepメソッドのようにイテレータとして呼ばれた時と普通のメソッドとし -て呼ばれた時とで動作が異なるメソッドもある. - - for 変数 in 式 + 式 '{' 変数... '|' 文 '}' + +「文」をブロックとして設定し, 「式」のメソッドをイテレータとして評価す +る. 「式」のトップレベルのメソッドだけがイテレータとして呼び出され, +レシーバを表す式や, 引数の式はイテレータとしては呼び出されない. 「式」 +が複数の式を含む時, 各々がイテレータとして順に呼ばれる. + +イテレータ内でyield文が実行されると, そこで指定された値がdo文で指定さ +れた変数に代入され, ブロックが実行される. ブロックの実行が終了するとそ +の値は yield文の値として返される. あるメソッドがイテレータとして呼び出 +されたかどうかはメソッドiterator_p()の戻り値で知ることができる. 中には +Enumerableモジュールのgrepメソッドのようにイテレータとして呼ばれた時と +普通のメソッドとして呼ばれた時とで動作が異なるメソッドもある. + +オブジェクトの各要素に対して操作を行なうための形式も提供されている. 形 +式は以下の通り. + + for 変数.. in 式 文 - end [ for ] + end - 式の各要素に対し文を実行する. これは以下のdo文と等価である. +式の各要素に対し文を実行する. これは以下の式と等価である. - do (式).each using 変数 - 文 - end + 式 '{' 変数 '|' 文 '}' + +よって式の値のオブジェクトがメソッドeachを持たない場合, forを実行する +と例外が発生する. + +*** イテレータの中でのブロック呼び出し + + yield '(' [式 [',' 式...]]) + yield - よって式の値のオブジェクトがメソッドeachを持たない場合, forを実行 - すると例外が発生する. +イテレータの中でブロックの呼び出しを行なう. yieldを実行したメソッドが +イテレータとして呼び出されていない時には例外が発生する. yield の値はブ +ロックの戻り値である. -** 例外処理 +*** 例外処理 処理中に予期しない事態が発生した時には例外が発生する. Rubyでは例外を途 中で捕捉して, 再試行したり, 後処理を行なったりすることができる. @@ -580,116 +607,212 @@ yield式の値として返される. あるメソッドがイテレータとして呼び出された 文2 ] [ ensure 文3 ] - end [ protect ] + end + +文1を実行し, その実行中に例外が発生すればresque節で指定された文2を実行 +する. 更にensure節が存在する時はprotect文を終了する前に必ず(正常終了時 +だけでなく, 例外, return, break, continue, redoなどによる脱出でも)文3 +を実行する. + +unless文, until文は条件を評価する時に例外が発生した場合, 評価結果が偽 +であると見なすので, 暗黙の例外処理を行なっていることになる. + +*** グルーピング + +式は括弧によってグルーピングすることができる. + + '(' 式 ')' + +更に括弧を用いて, 文(または文の並び)を式にすることもできる. + + '(' 文 ';' 文... ')' + +文の並びの値は最後に評価した式の値である. つまりの値は最後に評価した文 +の値になる. + +** 文 + +Rubyプログラムを構成するもう一つの要素は文である. 文には単純文, 制御文, +宣言文がある. 一般に文の値を用いることはないが, 式として用いられる場合 +もあるので, 値を持つ. 通常は文の値はnilである. + +*** 式 + +式は単純文である. + +*** 多重代入 + +同時に複数の変数に代入を行なうことができる. その形式は以下の通りである. + + 変数 ',' [変数 ',' ...] ['*' 変数]= 式 [, 式...] + +右辺の式が一つしかない場合は, その値を配列として(必要ならばto_aメソッ +ドで配列に変換して), 要素をそれぞれ変数に代入する. それ以外の場合には, +それぞれの式の値が変数に代入される. 左辺の変数の数と右辺の要素の数が合 +わない時には足りない変数には nilが代入され, 余った要素は無視される. 多 +重代入の最後の要素の前に`*'がある場合, 残りの全て引数が配列として代入 +される. + + foo, bar = [1, 2] # foo = 1; bar = 2 + foo, bar = 1, 2 # foo = 1; bar = 2 + foo, bar = 1 # foo = 1; bar = nil + + foo, bar, baz = 1, 2 # foo = 1; bar = 2; baz = nil + foo, bar = 1, 2, 3 # foo = 1; bar = 2 + foo,*bar = 1, 2, 3 # foo = 1; bar = [2, 3] + +多重代入は単純文である. その値は(配列に変換された)右辺である. - 文1を実行し, その実行中に例外が発生すればresque節で指定された文2を - 実行する. 更にensure節が存在する時はprotect文を終了する前に必ず(正 - 常終了時だけでなく, 例外, return, break, continue, redoなどによる - 脱出でも)文3を実行する. +*** 制御文 -protect以外に, unless演算子, until演算子は右辺の値を求める時に例外が発 -生した場合, 右辺の値として偽を与えられたと見なすので, 暗黙の例外処理を -行なっていることになる. +制御の流れを変更する以下の文がある. これらは単純文である. -** 大域脱出 +return文 - return [式] + return [式[, 式...]] - メソッドの実行を終了する. +式の値を戻り値としてメソッドの実行を終了する. 式が2つ以上与えられた時 +には, それらを要素とする配列をメソッドの戻り値とする. 式が一つもない場 +合には nil が戻り値となる. + +ループ制御文 continue redo break - 上記3つはループ中で使う. +上記3つはループ中で使う. + +continueはもっとも内側のループの次の繰り返しを始める. redoはループ条件 +のチェックを行なわず, 現在の繰り返しをやり直す. break はループを脱出す +る. Cと違い, breakはもっとも内側のループを脱出する作用だけを持ち, case +を抜ける作用は持たない. - continueはもっとも内側のループの次の繰り返しを始める. redoはループ - のループ条件のチェックを行なわず, 現在の繰り返しをやり直す. break - はループを脱出する. Cと違い, breakはもっとも内側のループを脱出する - 作用だけを持ち, caseを抜ける作用は持たない. +retry文 retry - protect文のresque節で使い, protect文を始めから実行する. 例外処理を - 行なってから再試行するのに使う. +protect文のresque節で使い, protect文を始めから実行する. 例外処理を行なっ +てから再試行するのに使う. resque節以外でretryが用いられた場合例外が発 +生する. + +fail文 + + fail '(' [メッセージ] ')' + fail [メッセージ] + +例外を発生させる. メッセージが与えられた場合には発生したソースファイル +名, 行番号をシステム変数`$@'に, メッセージを`$!'にセットする. + +yield文 + + yield 式 [',' 式...] + +文としてyieldを用いることもできる. この場合は式を括弧で括る必要はない. + +*** メソッド呼び出し文 + +1つ以上引数を持つメソッドを文として呼び出す場合には引数を括弧で括る必 +要はない. その形式は以下の通りである. + + 式 '.' メソッド名 引数1 ',' [ 引数2... ][ '*' 引数n ] + メソッド名 引数1 ',' [ 引数2... ][ '*' 引数n ] + super 引数1 ',' [ 引数2... ][ '*' 引数n ] + +構文解析時に, 式のように解釈できる場合は式としての解釈が優先される. + + foo bar+baz # メソッド呼び出しfoo(bar+baz) + foo (bar)+baz # メソッド呼び出しfoo(bar) + bar + foo 1 # メソッド呼び出しfoo(1) + foo -1 # ローカル変数foo - 1 + +メソッド呼び出し文は単純文である. - fail([メッセージ]) * これはKernelクラスのメソッドである. +*** 制御修飾子 - 例外を発生させる. メッセージが与えられた場合には発生したソースファ - イル名, 行番号を$@にメッセージを$!にセットする. +単純文に制御修飾子を付加したものは文である(単純文ではない). 修飾子は以 +下の4種類である. -** イテレータの中でのブロック呼び出し + 単純文 if 式 + 単純文 unless 式 + 単純文 while 式 + 単純文 until 式 - yield 式 +条件修飾子(if/unless)の式は先行する文に先だって評価される. 動作も対応 +する条件分岐式と同様である. - イテレータの中でブロックの呼び出しを行なう. yieldを実行したメソッ - ドがイテレータとして呼び出されていない時には例外が発生する. +繰り返し修飾子(while/until)はまず先行する文を評価してから条件式を評価 +するので, 最低一度は文を実行することになる. -** クラス定義 +*** クラス宣言文 クラスを定義する構文は以下の通りである. - class クラス名 [ : スーパークラス名 ] + class クラス名 [':' スーパークラス名 ] 定義実体 - end [ class ] + end -値はnil. クラス名は大文字で始まる識別子である. クラス定義のネストはで -きないので他の定義文内ではクラスを定義できない. +クラス名は任意の識別子である(大文字で始めることを推奨する). クラス定義 +のネストはできないので他の定義文内ではクラスを定義できない. -** モジュール定義 +*** モジュール定義文 モジュールを定義する構文は以下の通りである. module クラス名 定義実体 - end [ module ] + end モジュール名は大文字で始まる識別子である. クラス同様, モジュール定義も ネストできない. -** インクルード +*** インクルード文 -クラスにモジュールをインクルードする構文は以下の通りである. +モジュールをインクルードすることによって, クラスまたはモジュールに機能 +を追加できる. モジュールをインクルードした場合, そのモジュール(および +そのモジュールが更にインクルードしているモジュール)の全てのメソッドを +受け継ぐ. 別のいい方をすればインクルードは限定された多重継承といえる. - include モジュール名 [, モジュール名...] +他のモジュールをインクルードする構文は以下の通りである. -現在の定義中のクラスまたはモジュール(トップレベルではObject)に指定した -モジュールをインクルードする. これによって多重継承をエミュレートできる. + include モジュール名 [',' モジュール名...] -** メソッド定義 +現在の定義中のクラスまたはモジュール(トップレベルではObjectクラス)に指 +定したモジュールをインクルードする. + +*** メソッド定義文 通常(特異メソッドでない)メソッド定義の形式は以下の通りである. 通常メソッ ド定義はネストできないので, メソッド定義文中ではメソッド定義文を再び呼 び出せない. - def メソッド名 [ ( 引数 [, 引数...][, *引数 ] ) ] + def メソッド名 [ '(' 引数 [',' 引数...][',' '*'引数 ] ')' ] 定義実体 - end [ def ] + end メソッド名は識別子または文字列である. 演算子の再定義をする時には文字列 で指定する. 仮引数並びの最後に`*'がある場合, 仮引数より多く与えられた 実引数は, 最後の引数に配列として与えられる(足りない時にはエラー). -** 特異メソッド定義 +** 特異メソッド定義文 -メソッド定義にはもう一つ特異メソッドの定義がある. 形式は以下の通りであ -る. +メソッド定義にはもう一つ特異メソッドの定義がある. 特異メソッドとはある +特定のオブジェクトに固有のメソッドである. 形式は以下の通りである. - def 式.メソッド名 [ ( 引数 [, 引数...][, *引数 ] ) ] + def 式 '.' メソッド名 [ '(' 引数 [',' 引数...][',' '*'引数 ] ')' ] 定義実体 - end [ def ] + end -この形式は式の値であるオブジェクトに特異メソッドを定義する. 式の値は +この形式は式の値であるオブジェクトに特異メソッドを定義する. 式の値は (ビルトインクラスでない)通常オブジェクトか, クラスまたはモジュールであ -る必要がある. 通常メソッド定義とは異なり, こちらはメソッド本体内でもネ -ストして呼び出すことができる. +る必要がある. 通常メソッド定義とは異なり, 特異メソッドはメソッド本体内 +でもネストして定義することができる. -特異メソッドは特定のオブジェクトにだけ属するメソッドである. よって通常 -は継承しえないが, 例外としてクラスの特異メソッドはそのサブクラスにも継 -承される. 言い替えればクラスの特異メソッドは他のオブジェクト指向システ -ムにおけるクラスメソッドの働きをする. +特異メソッドは通常は継承しえないが, 例外としてクラスの特異メソッドはそ +のサブクラスにも継承される. 言い替えればクラスの特異メソッドは他のオブ +ジェクト指向システムにおけるクラスメソッドの働きをする. -** メソッドの別名定義 +*** メソッドの別名定義文 以下の形式でメソッドに別名をつけることができる. @@ -699,7 +822,7 @@ protect以外に, unless演算子, until演算子は右辺の値を求める時に例外が発 ソッドが再定義されても, 古いメソッドが呼び出されたのと全く同じ働きをす る. -** メソッド定義取り消し +*** メソッド定義取り消し文 メソッドの定義を取り消すためにはundefを用いる. @@ -708,10 +831,11 @@ protect以外に, unless演算子, until演算子は右辺の値を求める時に例外が発 識別子または文字列で指定したメソッドの定義を取り消す. defによる別名定義とundefによる定義取り消しを使うとクラスのインタフェー -スをスーパクラスと独立に変更することができる. ただし, 自分自身にメッセー -ジを送っている場合に注意しないと既存のメソッドが動作しなくなる可能性が -ある. - +スをスーパークラスと独立に変更することができる. ただし, メソッドがself +にメッセージを送っている場合にはよく注意しないと既存のメソッドが動作し +なくなる可能性がある. + +------------------------------------------------------- * Rubyの組み込み機能 Rubyプログラミングの基本はクラス, モジュールとそのメソッドの習得である. @@ -719,8 +843,6 @@ Rubyには処理系そのものに以下の機能が組み込まれている. ライブラリをロー ドすることによって機能は増えるが, それらに関してはそれぞれのライブラリ のドキュメントを参照してもらいたい. -右端に`+'記号のついたメソッドは関数メソッドである. - ** 関数 Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク @@ -728,50 +850,38 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク れるメソッドを以下にあげる. これらのメソッドを再定義する際には互換性を 考えて行なうべきである. - _exit(status) + + _exit(status) プログラムの実行を終了する. 整数statusを終了ステータスとする. exit()とは違って, 例外処理などは一切行なわない. fork()の後, 子 プロセスを終了させる時などに用いる. - caller + - caller(level) + - - スタックフレームから情報を得て, メソッドの呼び出し元のファイル - 名, 行番号, 引数を要素とする配列を返す. levelが与えられた場合 - は現在のスタックフレームよりlevel段上の情報を返す. - - eof() + + eof() コマンドラインからの入力がEOFに到達している場合, 真を返す. - eval(expr) + + eval(expr) exprとして与えられた文字列をrubyプログラムとして解釈,実行する. - exec(command) + + exec(command) 現在実行しているプロセスを終了して, command文字列で指定される 別プロセスを起動する. - exit([status]) + + exit([status]) プログラムの実行を終了する. statusとして整数が与えられた場合, その値をRubyコマンドの終了ステータスとする. デフォルトは0. - fail([message]) + - - 例外を発生させる. メッセージが与えられた場合にはそれをシステム - 変数`$!'にセットし, 発生した位置をシステム変数`$@'にセットする. - - fork() + + fork() forkシステムコールを実行し, 子プロセスを生成する. 詳細は fork(2)を参照のこと. 親プロセス側では子プロセスのプロセスidを 返し, 子プロセス側ではnilを返す. 何らかの原因で子プロセスの生 成に失敗した時には例外が発生する. - format(format, ...) + + format(format, ...) フォーマットとして与えられた文字列をC言語のsprintfと同じように 解釈し, 引数を展開した文字列を返す. メソッドsprintf()の別名. @@ -779,46 +889,47 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク Rubyにおけるformat指定子の拡張についてはsprintf()の項を参照の こと. - getc() + + getc() 標準入力から一文字取り出す. 戻り値は読み込んだ文字の文字コード (ASCII)を表すFixnumである. - getenv(name) + + getenv(name) - nameに該当する環境変数を取り出す. + nameに該当する環境変数を取り出す. $ENV[name]と同義. - gets(pattern, replace) + + gets() - 引数として与えられたファイル(なければ標準入力)から一行読み込ん - で, 読み込みに成功した時にはその文字列を返す. ファイルの終りに - 到達した時にはnilを返す. 行の区切りはシステム変数`$/'によって - 変更できる. 読み込んだ文字列はシステム変数`$_'にもセットされる. + 引数として与えられたファイル(なければ標準入力)で構成される仮想 + 的なファイル($ARGFでアクセスできる)から一行読み込んで, 読み込 + みに成功した時にはその文字列を返す. ファイルの終りに到達した時 + にはnilを返す. 行の区切りはシステム変数`$/'によって変更できる. + 読み込んだ文字列はシステム変数`$_'にもセットされる. - gsub() + + gsub(pattern, replace) システム変数`$_'の指す文字列に対して置換を行なう. 文字列内で patternにマッチする部分を全てreplaceに置き換える. Stringクラス のgsubメソッドの解説を参照のこと. - iterator_p() + + iterator_p() メソッドがイテレータとして呼び出された時に真, そうでない時に偽 を返す述語. - kill(signal, pid...) + + kill(signal, pid...) pidで指定されたプロセスにシグナルを送る. シグナルはシグナル番 号か名前で指定する. 負の値を持つシグナル(あるいはシグナル名の 前に`-')を与えるとプロセスではなくプロセスグループにシグナルを 送る. - load(file) + + load(file) fileをロードする. fileをロードするパスはシステム変数$LOAD_PATH で決定される. - open(file[, mode]) + + open(file[, mode]) fileをオープンして, Fileオブジェクトを返す. ファイル名はオープ ンするファイルを示す. ファイル名が`|'で始まる時には続く文字列 @@ -860,7 +971,7 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク 変数`$\'(出力フィールドセパレータ)にnil でない値がセットされて いる時には, 最後にそれを出力する. - printf([port, ]format, arg1, ..., argn) + + printf([port, ]format, arg1, ..., argn) C言語のprintf()と同じformatに従い引数を文字列に変換し, 出力す る. 第1引数がIOのサブクラスのインスタンスであった場合はそのオ @@ -869,7 +980,7 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク Rubyにおけるformat指定子の拡張についてはsprintf()の項を参照の こと. - rand(max) + + rand(max) 0からmaxを越えない範囲の整数の乱数を発生する. 戻り値はFixnum. @@ -880,7 +991,7 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク イルは再ロードしない点である. 実際にロードした時には%TRUE, 既 にロードされている時には%FALSEを返す. - select(reads[, writes[, execpts[, timeout]]]) + + select(reads[, writes[, execpts[, timeout]]]) select(2)を実行する. reads/writes/execptsにはIO(またはそのサブ クラス)のインスタンスの配列を与える. timeoutはFixnum / Float @@ -888,17 +999,18 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク nil, そうでないときは3要素の配列を返し, その各要素が入力/出力/ 例外待ちのオブジェクトを要素として持つ. - setenv(name, value) + + setenv(name, value) - nameで指定される環境変数をvalueにセットする. + nameで指定される環境変数をvalueにセットする. $ENV[name]=value + と同じ働きをする. - sleep([sec]) + + sleep([sec]) sec秒だけプログラムの実行を停止する. secが省略された場合, プロ セスにSIGALRMが送られない限り, 永久にスリープする. 実際にスリー プした秒数を返す. - sprintf(format, ...) + + sprintf(format, ...) format文字列をC言語のsprintfと同じように解釈し, 引数を展開した 文字列を返す. メソッドformat()の別名. @@ -910,40 +1022,40 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク 8 進, 16進数の表示を行なうが, 負の数の処理の際に2の補数表現で はなく, その絶対値表記の先頭に`-'をつけたものを表示する. - srand([初期値]) + + srand([初期値]) 乱数の初期値を設定し, 古い初期値を返す. 初期値が省略された時に はtime(3)の返す値をデフォルトとする. - sub() + + sub(pattern, replace) システム変数`$_'の指す文字列に対して置換を行なう. 文字列内で最 初にpatternにマッチする部分をreplaceに置き換える. Stringクラス のsubメソッドの解説を参照のこと. - syscall(num, arg...) + + syscall(num, arg...) numで指定された番号のシステムコールを実行する. 第2引数以降をシ ステムコールの引数として渡す. 引数は文字列または整数でなければ ならない. - system(command) + + system(command) コマンドを実行し, その終了ステータスを返す. - trap(command, signal...) + + trap(command, signal...) signalの割り込みがかかった時にcommandを実行する. signalはシグ - ナル名かシグナルの番号. commandとしてSIG_IGNまたはIGNOREを指定 - した時にはそのシグナルを無視する(可能ならば). SIG_DFLまたは - DEFAULTを指定した時はデフォルトの動作を行なう. + ナル名かシグナルの番号. commandとして"SIG_IGN"または"IGNORE"を + 指定した時にはそのシグナルを無視する(可能ならば). "SIG_DFL"ま + たは"DEFAULT"を指定した時はデフォルトの動作を行なう. - wait() + + wait() 子プロセスが終了するのを待ち, 終了した子プロセスのpidを返す. 子プロセスが一つもなければnilを返す. - waitpid(pid, flags) + + waitpid(pid, flags) 特定の子プロセスの終了を待ち, そのプロセスが終了した時に真を返 す. 子プロセスが存在しないか, ノンブロッキングモードで子プロセ @@ -953,7 +1065,7 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク ** システム変数 - $! エラーメッセージ. fail()で設定する. + $! エラーメッセージ. failで設定する. $@ エラーが発生した時点のファイル名と行番号が @@ -1007,7 +1119,8 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク $ENV 環境変数にアクセスする連想配列(EnvDict). この変数に対 して `for'を行なうと変数名と値のペアを与える. - $FILENAME 関数gets()で現在読み込み中のファイル名. + $FILENAME 仮想ファイル$ARGFで現在読み込み中のファイル名. メソッ + ドgets()が今読んでいるファイル名. $DEBUG `-d'フラグの状態(真偽値) @@ -1020,28 +1133,97 @@ Rubyには厳密な意味では関数はないがKernelクラスのメソッドの一部は(全ク $stdout 標準出力 $stderr 標準エラー出力 + $ARGF 引数(なければ標準入力)で構成される仮想ファイル. つまり + gets()は$ARGF.gets()と同じ意味である. + $VERBOSE `-v'フラグの状態(真偽値) $VERSION rubyのバージョンを示す文字列 ** システム定数 - %TRUE 1(Fixnum) + %TRUE t %FALSE nil それぞれ真偽値を表す. 条件判断はnilを偽, それ以外の全ての値を - 真として判断するため, 真偽値を返すメソッドで%TRUE以外の値を返 - すものが存在するので, 比較に用いるのは適切でないことに注意すべ - きである. 例えば次の式は真にならない. + 真として判断するため, %TRUEの値は代表的な真の値という以上の意 + 味を持たない. よって, あるメソッドの返値が真であるということと, + それが%TRUEを返すということは厳密には同じではない(述語的に用い + られるメソッドは大抵真の値として%TRUEを返すようにはなっている + が). つまり + + if some.method() then .. else .. end - (2 < 3) == %TRUE + と - メソッド"<"は真の時右辺値を返すので, この場合の値は3であり, 定 - 数%TRUEの値1とは異なる. %FALSEに関しては, このような問題は生じ + if some.method() == %TRUE then .. else .. end + + は完全には同義ではない. %FALSEに関しては, このような問題は生じ ない. ** クラス/モジュール +*** ARGFILE(クラス) + +引数で指定されたファイル(引数が与えられていない時には標準入力)で構成さ +れる仮想ファイルをアクセスするためのクラス. ただしこのクラスは特異メソッ +ドしか持たず, モジュール的な使い方をされる. クラス名だけでなくシステム +変数$ARGFでも参照できる. + + while gets() + ... + end + +と + + for $_ in $ARGF + ... + end + +は全く同じ意味だが, 後者の方がより美しく, 理解しやすく, そしてブロック +生成のコストのため若干遅い. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + each + + 各行毎に繰り返すイテレータ + + each_byte + + 各文字毎に繰り返すイテレータ + + eof + + 現在読み込んでいるファイル(仮想ファイル全体ではない)が終りに到 + 達した時に真を返す. + + getc + + 仮想ファイルから1文字読み込む. 戻り値は文字コードを表す整数で + ある. ファイルの終りに到達した時にはnilを返す. このメソッドで + 読み込んだ場合, システム変数`$.'は変化しない. + + gets + readline + + 仮想ファイルから一行読み込んで, 読み込みに成功した時にはその文 + 字列を返す. ファイルの終りに到達した時にはnilを返す. 行の区切 + りはシステム変数`$/'によって変更できる. 読み込んだ文字列はシス + テム変数`$_'にもセットされる. + + read + + 仮想ファイルの内容を全て文字列として読み込む. + + readlines + + 仮想ファイルを全て読み込んで, 各行を要素として持つ配列を返す. + *** Array(クラス) 数字を添字とした配列のクラスである. 生成は一般的には配列式``[...]''で @@ -1101,9 +1283,9 @@ Methods: 配列の大きさを0にする. - delete(item) + delete(val) - itemと一致する要素を削除する. + valと一致する要素を削除する. delete_if @@ -1122,6 +1304,18 @@ Methods: lengthが省略された時は配列の終りまでの長さをとる. 指定された部 分配列が元の配列の範囲を越える時は自動的に拡張される. + index(val) + + valと等しい最初の要素のインデックスを返す. 該当する要素が存在 + しない場合はnilを返す. + + indexes(ary) + indexes(index-1, ..., index-n) + + 1番目の形式では整数の配列を引数として受けて, その要素をインデッ + クスとする要素を含む配列を返す. 2番目の形式では各引数の値をイ + ンデックスとする要素を含む配列を返す. + join([sep]) 配列の要素を連結した文字列を返す. 各要素は文字列に変換され, 間 @@ -1129,6 +1323,7 @@ Methods: の値が用いられる. length + size 配列の長さ(要素数)を返す. @@ -1241,7 +1436,9 @@ Methods: クラスのクラス. より厳密に説明するとクラスは特異メソッドを継承するため に, それぞれメタクラスと呼ばれる名前のないクラスをクラスとして持ち, Classはそのメタクラスのクラスである(分かったかな?). が, この解説が理解 -できなくても, Rubyを使うことに何の支障もない. +できなくても, Rubyを使うことに何の支障もない. クラスには特異メソッドを +定義できる事と, スーパークラスで定義された特異メソッドはそのサブクラス +でも有効である事を知れば十分である. SuperClass: Module @@ -1260,12 +1457,16 @@ Methods: *** Comparable(モジュール) - 比較演算を許すクラスのためのMixin. このモジュールをインクルードするこ - とによって, `<=>'を定義するだけで他の演算子はその定義を利用して派生で - きる. +比較演算を許すクラスのためのMixin. このモジュールをインクルードするこ +とによって, `<=>'演算子を定義するだけで他の演算子はその定義を利用して +派生できる. Methods: + self == other + + selfがotherと等しい時真を返す. + self > other selfがotherより大きい時真を返す. @@ -1291,7 +1492,7 @@ Methods: NDBMファイルをアクセスするクラス. キー, データともに文字列でなければな らないという制限と, データがファイルに保存されるという点を除いては Dictクラスと全く同様に扱うことができる. NDBMを備えていないシステムでは -このクラスへのアクセスは例外を発生させる. +このクラスは定義されない. SuperClass: Object @@ -1326,6 +1527,10 @@ Methods: クを評価した値が真の時, 該当する項目を削除する. each + each_pair + + [key, value]なる配列を与えるイテレータ. + each_value 全てのvalueに対して繰り返すイテレータ. @@ -1334,12 +1539,8 @@ Methods: 全てのkeyに対して繰り返すイテレータ. - each_pair - - [key, value]なる配列を与えるイテレータ. - - includes(key) has_key(key) + includes(key) keyがデータベース中に存在する時, 真を返す @@ -1348,11 +1549,19 @@ Methods: valueを値とする組がデータベース中に存在する時, 真を 返す + indexes(ary) + indexes(key-1, ..., key-n) + + 1番目の形式では文字列の配列を引数として受けて, その要素をキー + とする要素を含む配列を返す. 2番目の形式では各引数の値をキーと + する要素を含む配列を返す. + keys データベース中に存在するキー全てを含む配列を返す. length + size データベース中の要素の数を返す. (注意:現在の実現では要素数を数 えるためにデータベースを全部検索するので, 結構コストが高い. 気 @@ -1422,8 +1631,8 @@ Methods: [key, value]なる配列を与えるイテレータ. - includes(key) has_key(key) + includes(key) keyが辞書中に存在する時, 真を返す @@ -1431,11 +1640,19 @@ Methods: valueを値とする組が辞書中に存在する時, 真を返す + indexes(ary) + indexes(key-1, ..., key-n) + + 1番目の形式では配列を引数として受けて, その要素をキーとする要 + 素を含む配列を返す. 2番目の形式では各引数の値をキーとする要素 + を含む配列を返す. + keys 辞書中に存在するキー全てを含む配列を返す. length + size 辞書中の要素の数を返す. @@ -1539,7 +1756,7 @@ Methods: grep(pattern) - 「pattern =~ 要素」が成立する全ての要素を含む配列を返す. イテ + 「要素 =~ pattern」が成立する全ての要素を含む配列を返す. イテ レータとして用いられた時は上記の条件の成立した要素に対してブロッ クを実行する. @@ -1555,13 +1772,13 @@ Methods: min - 最小の要素を返す. 各要素が`<=>'メソッドを持つことを暗黙のうち - に仮定している. + 最小の要素を返す. 全ての要素がお互いに`<=>'メソッドで比較でき + ることを仮定している. max - 最大の要素を返す. 各要素が`<=>'メソッドを持つことを暗黙のうち - に仮定している. + 最大の要素を返す. 各要素が`<=>'メソッドで比較できることを仮定 + している. reverse @@ -1626,7 +1843,7 @@ Single Methods: gecos # gecosフィールド(文字列) dir # ホームディレクトリ(文字列) shell # ログインシェル(文字列) - # 以降のメンバはシステムによってはないものもある + # 以降のメンバはシステムによっては提供されない. change # パスワード変更時間(整数) quota # クォータ(整数) age # エージ(整数) @@ -1673,9 +1890,9 @@ Single Methods: *** File(クラス) -ファイルアクセスのためのクラス. 関数メソッドopen()で生成される. また, -このクラスの特異メソッドとしてtestのファイルテスト演算子相当のメソッド -が定義されている. +ファイルアクセスのためのクラス. メソッドopen()で生成される. また, この +クラスの特異メソッドとしてtestのファイルテスト演算子相当のメソッドが定 +義されている(FileTestモジュールのメソッド郡). SuperClass: IO @@ -1693,7 +1910,7 @@ Methods: ファイルのパーミッションを変更する(cf chmod(2)). - chmod(owner, group) + chown(owner, group) ファイルの所有者とグループを変更する(cf chown(2)). nilか-1を 指定することによって所有者やグループを現在のまま変えないでおく @@ -1707,7 +1924,7 @@ Methods: ファイルに関するStat構造体を返す. lstatはファイルがシンボリッ クリンクであればリンクそのものに関するStat構造体を返す. 構造体 - の内容についてはstat を参照のこと. + の内容についてはstatを参照のこと. mtime @@ -1727,7 +1944,7 @@ Methods: 0, 1, 2のいずれかであって, それぞれファイルの先頭, 現在位置, ファイルの終端のうちのいずれかからの相対を示す. - stat() + stat ファイルに関するStat構造体を返す(Struct を参照). @@ -1765,29 +1982,85 @@ Single Methods: filenameの最終アクセス時刻を返す. - b(filename) - - filenameのファイルがブロックスペシャルファイルである時, 真を返 - す. - - c(filename) - - filenameのファイルがキャラクタスペシャルファイルである時, 真を - 返す. - ctime(filename) filenameの最終ステータス変更時刻を返す. chmod(mode, path, file...) - ファイルのパーミッションを変更する(cf chmod(2)). + ファイルのパーミッションを変更する(cf chmod(2)). 変更したファ + イル数を返す. chown(owner, group, file...) ファイルの所有者とグループを変更する(cf chown(2)). nilか-1を指 定することによって所有者やグループを現在のまま変えないでおくこ - とができる. + とができる. 変更したファイル数を返す. + + link(old, new) + + oldへのハードリンクnewを生成する. link(2)と同じ制限がある. + + mtime(filename) + + filenameの最終修正時刻を返す. + + readlink(path) + + シンボリックリンクpathの内容を文字列として返す. + + rename(from, to) + + ファイル名fromをtoに変更する. rename(2)参照. 既にtoという名前 + のファイルが存在する時にはまずそのファイルが削除される. + + stat(filename) + + filenameのファイルのStat構造体を返す. + + symlink(old, new) + + oldへのシンボリックリンクnewを生成する. + + truncate(path, length) + + pathで指定されたファイルを切り捨てて最大lengthバイトにする. + + type(filename) + + filenameのファイルのタイプを表す文字列を返す. 文字列は"file", + "directory", "characterSpecial", "blockSpecial", "fifo", + "link", "socket"のうちのいずれか一つである. + + unlink(file...) + + ファイルを削除する. ディレクトリの削除にはDir.rmdirを使うこと. + + utime(atime, mtime, file...) + + ファイルのアクセス時刻をatimeに, 修正時刻をmtimeに設定する. + atime, mtimeは数またはTimeクラスのインスタンスでなければならな + い. + + これ以外にFileTestモジュールのメソッドも特異メソッドとして持つ. + +*** FileTest(モジュール) + +ファイルテスト用メソッドを集めたモジュール. インクルードして用いること +もできる. + +Methods: +Single Methods: + + b(filename) + + filenameのファイルがブロックスペシャルファイルである時, 真を返 + す. + + c(filename) + + filenameのファイルがキャラクタスペシャルファイルである時, 真を + 返す. executable(filename) x(filename) @@ -1829,14 +2102,6 @@ Single Methods: filenameのファイルがソケットである時, 真を返す. - link(old, new) - - oldへのハードリンクnewを生成する. link(2)と同じ制限がある. - - mtime(filename) - - filenameの最終修正時刻を返す. - owned(filename) O(filename) @@ -1847,15 +2112,6 @@ Single Methods: filenameのファイルを読みとり可能の時, 真を返す. - readlink(path) - - シンボリックリンクpathの内容を文字列として返す. - - rename(from, to) - - ファイル名fromをtoに変更する. rename(2)参照. 既にtoという名前 - のファイルが存在する時にはまずそのファイルが削除される. - R(filename) filenameのファイルを実uid/gidで読みとり可能の時, 真を返す. @@ -1881,24 +2137,6 @@ Single Methods: filenameのファイルのstickyビットがセットされている時, 真を返す. - symlink(old, new) - - oldへのシンボリックリンクnewを生成する. - - truncate(path, length) - - pathで指定されたファイルを切り捨てて最大lengthバイトにする. - - unlink(file...) - - ファイルを削除する. ディレクトリの削除にはDir.rmdirを使うこと. - - utime(atime, mtime, file...) - - ファイルのアクセス時刻をatimeに, 修正時刻をmtimeに設定する. - atime, mtimeは数またはTimeクラスのインスタンスでなければならな - い. - writable(filename) w(filename) @@ -2002,7 +2240,7 @@ Methods: coerce(num) numをfloatに変換する. ただし現時点でFloatが理解できる他の数は - Fixnumだけである. + FixnumとBignumだけである. to_f @@ -2010,7 +2248,7 @@ Methods: to_i - floatを整数に変換した結果を返す. + selfを整数に変換した結果を返す. Single Methods: @@ -2024,13 +2262,9 @@ Ruby組み込みのgarbage collectorの制御を行なうためのモジュール. このモ ジュールのメソッドをを用いることによって, 一時的にGCを止めたり, GCの起 きるタイミングを制御したりできる. -更にgcは始まる時にこのモジュールのstart_hookメソッドを, 終った時には -end_hookメソッドを呼び出すため, これらメソッドを定義することによって -hookをかけることができる. - Methods: - garbage_collect + + garbage_collect GCを開始する. 「GC.start」と同義. @@ -2048,6 +2282,33 @@ Single Methods: GCを開始する. +*** Glob(クラス) + +ワイルドカードのクラス. ワイルドカードのリテラルは<...>という形式であ +る. 正規表現とほぼ同じように使えるが, こちらは機能が少ない. ただし, ワ +イルドカードの展開機能がある. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self =~ string + + ワイルドカードが文字列にマッチした場合には真を, しない場合は + nilを返す. + + each + + ワイルドカードにマッチするファイル名を返すイテレータ. + +Single Methods: + + new(string) + + 文字列をワイルドカードに変換したオブジェクトを返す. + *** Integer(クラス) 整数クラス. 実際はその大きさによってFixnumとBignumいう二つのサブクラス @@ -2096,7 +2357,7 @@ Methods: 例: - $stdout << 1 << " is a " << Fixnum + $stdout << 1 << " is a " << Fixnum << "\n" close @@ -2115,6 +2376,7 @@ Methods: すFixnumである. fileno + to_i IOオブジェクトが使っているファイルディスクリプタ(Fixnum)を返す. @@ -2125,7 +2387,7 @@ Methods: getc 一行読み込んで, 読み込みに成功した時にはその文字列を返す. ファ - イルの終りに到達した時にはnilを返す. 関数的メソッドのgetc()は + イルの終りに到達した時にはnilを返す. カーネルメソッドgetc()は $stdin.getcと同じ意味である. gets @@ -2146,6 +2408,10 @@ Methods: lengthバイト読み込んで, その文字列を返す. lengthが省略された時 には, 全てのデータを読み込む. + readlines + + ファイルを全て読み込んで各行を要素としてもつ配列を返す. + sync 現在の出力同期モードを真偽値で返す. 同期モードが真の時は出力関 @@ -2158,16 +2424,17 @@ Methods: sysread(length) stdioを経由せずにread(2)を用いて入力を行なう. 入力されたデータ - を含む文字列を返す. ファイルの終りに到達した時にはnilを返す. + を含む文字列を返す. ファイルの終りに到達した時にはnilを返す. read(2)の性質により必ずlengthバイトの文字列が読み込まれるわけ ではない. gets()やgetc()などstdioを経由するメソッドと混用する - ことはバッファリングの不整合などで, 思わぬ動作をすることがある. + ことはバッファリングの不整合などで思わぬ動作をすることがある. syswrite(str) - stdioを経由せずに, wirte(2)を用いて出力を行なう. このメソッド - はバッファリングなどstdioがしてくれることは一切行なわない. - print()やprintf()とsyswrite()を混用するのは推奨できない. + stdioを経由せずに, write(2)を用いて出力を行なう. このメソッド + はバッファリングなどstdioがしてくれることは一切行なわない. + syswriteは実際に書き込んだバイト数を返す. print()やprintf()と + syswrite()を混用するのは推奨できない. write(str) @@ -2179,14 +2446,14 @@ Single Methods: printやprintfのデフォルトの出力先を返す. 初期値は$stdout. - default= + default=(io) デフォルトの出力先を指定する. *** Kernel(クラス) -全てのクラスの基底クラス. Ruby組み込みの全ての関数的メソッドはこのク -ラスで定義されている. +全てのクラスの基底クラス. Ruby組み込みの全ての関数的に呼ばれるメソッド +はこのクラスで定義されている. SuperClass: なし @@ -2197,8 +2464,8 @@ Methods: 否定. Non-nilのオブジェクトの場合常に偽(nil)を返す. このメソッ ドはNilクラスでは再定義され真を返す. - equal(other) self == other + equal(other) オブジェクトの一致判定. レシーバと引数の引数が一致する時, 真を 返す. Kernelクラスの定義では双方のオブジェクトが同一の時真を返 @@ -2217,13 +2484,13 @@ Methods: self =~ other - マッチ. デフォルトは"=="と同じである. "=~"はcaseの比較にも用い - られる. + マッチ. デフォルトの動作は"=="と同じである. "=~"はcaseの比較に + も用いられる. !~ - "=~"の否定. 内部で"=~"メソッドを呼び出しているので, 再定義する - 必要はない. + "=~"の否定. 内部で"=~"メソッドを呼び出しているので, こちらは再 + 定義する必要はない. self :: other @@ -2254,7 +2521,7 @@ Methods: オブジェクトのハッシュ値(Fixnum)を返す. Dictクラスでキーとなる オブジェクトを格納するのに用いられている.「A == B」が成立する 時は必ず「A.hash == B.hash」が成立する必要があるので, "=="を再 - 定義した時にはこちらもそれに合わせて再定義すること. + 定義した時には必ずこちらもそれに合わせて再定義すること. *** Math(モジュール) @@ -2309,7 +2576,7 @@ SuperClass: Object Methods: - attr(name[, public]) + + attr(name[, public]) そのモジュールをインクルードしたクラスのインスタンスに対して nameで指定される属性を付加し, 属性に対するアクセスメソッドを定 @@ -2390,6 +2657,10 @@ Methods: 商と剰余の2要素の配列を返す. + next + + 次の数を返す. 次の数とはその数を越える最小の整数である. + *** Object(クラス) 全ての通常クラスのスーパクラス. このクラスのサブクラスでないクラスは @@ -2410,9 +2681,9 @@ Methods: clone - オブジェクトの複製を作る. Fixnum以外のクラスの場合, 恐らくは - 「obj.eqaul(obj.clone)」は偽であるが, 多くの場合「obj == - obj.clone」は真である. + オブジェクトの複製を作る. インスタンスが即値であるFixnumクラス + 以外のクラスの場合,「obj.equal(obj.clone)」は偽であるが, 多く + の場合「obj == obj.clone」は真である. to_s @@ -2587,7 +2858,7 @@ Single Methods: 正規表現のクラス. 正規表現のリテラルは/.../という形式で表すが, 動的に 生成するためには - Regexp.compile(文字列) + Regexp.new(文字列) とする. ただし, Stringクラスの`=~'を始めとして多くのメソッドは正規表現 の替わりに文字列が与えられた時には内部的に正規表現を生成するので, 生成 @@ -2598,7 +2869,6 @@ SuperClass: Object Methods: - self =~ string 正規表現が文字列にマッチした場合, マッチした位置を返す. マッチ @@ -2611,6 +2881,7 @@ Methods: Single Methods: complie(string) + new(string) 文字列を正規表現に変換したオブジェクトを返す. @@ -2646,7 +2917,7 @@ Methods: ソケットの以降の接続を終了させる. howが0である時, 以降の受信が, howが1である時は, 以降の送信が拒否される. howが2の時には, それ - 以降の送信, 受信ともに拒否される. + 以降の送信, 受信ともに拒否される. shutdown(2)を参照. *** String(クラス) @@ -2758,47 +3029,28 @@ Methods: 変換する. length + size 文字列の長さ(バイト数)を返す. next - 「次の」文字列を返す. 次の文字列とは数字は数字として,英文字は - 英文字として増加し, 桁上がりの処理が行なわれた者である. - - "aa".next == "ab" - "99".next == "100" - "a9".next == "b0" - - このメソッドはRange:eachで用いられているので, 以下のような処理 - が可能である. - - for i in "a" .. "ba" - print(i, "\n"); - end - - これはa, b, c, .. aa, .. az, baまでを各行に出力する. - - - 気を付けなければいけないのは, この終了判定は大小関係ではなく - `=='で判定されているため, `..'演算子の左辺の値に続く文字列に右 - 辺の文字列が含まれていない, 以下の例のような場合は無限ループに - 陥ってしまう. - - for i in "0" .. "1a" - print(i, "\n"); - end + selfからendまで「次の」文字列を返す. 次の文字列とは数字は数字 + として,英文字は英文字として増加し, 桁上がりの処理が行なわれた + ものである. - 作者はこう書くことによって責任を逃れてようとしていると考える人 - もいるかもしれない. その推測は正しい. + "aa".next => "ab" + "99".next => "100" + "a9".next => "b0" oct 文字列を8進数を表す文字列と解釈して, 整数に変換する. 8進数の - 定義は/[0-7]+/であり, この定義に当てはまらない文字列に対しては - 0を返す. perlとは違って文字列が0xから始まっているからといって - 16進数だと見なしてくれたりはしない. それらは8進数ではないので0 - を返す. + 定義は/[0-7]+/であり, 文字列の先頭からこのパターンにマッチする + 部分を整数に変換する. この定義に全く当てはまらない文字列に対し + ては0を返す. perlとは違って文字列が0xから始まっているからといっ + て 16進数だと見なしてくれたりはしない. それらは先頭の0が8進数 + と認識され, 0を返す. reverse @@ -2844,6 +3096,16 @@ Methods: の内容に置き換えられる. sub()はgsub()と異なり, 最初のマッチだ けを置換する. + sum([bits]) + + 文字列のbitsビットのチェックサムを得る. 省略値は16である. ruby + では以下のコードでSystem Vの`sum'プログラムと同じ値を得られる. + + while gets() + sum += $_.sum + end + sum %= 65536 + to_f 文字列をFloatに変換する. @@ -2918,6 +3180,36 @@ Methods: X 1バイト後退 @ 絶対位置への移動 + rubyのunpackはperlと違ってチェックサムの計算機能がないことに注 + 意すること. + + upto(end) + + selfから始まって, endまで「次の」文字列を順に与えるイテレータ. + 次の文字列とはstr.nextで与えられる文字列である. + + このメソッドはRange:eachで用いられているので, 以下のような処理 + が可能である. + + for i in "a" .. "ba" + print(i, "\n"); + end + + これはa, b, c, .. aa, .. az, baまでを各行に出力する. + + + 気を付けなければいけないのは, この終了判定は大小関係ではなく + `=='で判定されているため, `..'演算子の左辺の値に続く文字列に右 + 辺の文字列が含まれていない, 以下の例のような場合は無限ループに + 陥ってしまう. + + for i in "0" .. "1a" + print(i, "\n"); + end + + 作者はこう書くことによって責任を逃れてようとしていると考える人 + もいるかもしれない. その推測は正しい. + Single Methods: new(string) @@ -2930,20 +3222,24 @@ Single Methods: データをまとめる時には配列クラスが用いられることもあるが(例: select), 構造体を使うべき時は以下のような場合である. - (1) 要素の数が多い + (1) 要素の数が固定 + + 要素の数が変動するものは構造体を使うのには向かない. + + (2) 要素の数が多い 人間が一度に容易に扱える概念の数は7つまでであるという仮説がある. - この仮説に従えば, データが4つ以上の場合は配列を用いた場合, 要素 - 数*2(つまりオフセットとその意味)が7を越える. よって, そのような - 場合には構造体を使った方が理解しやすいと思われる. + この仮説に従えば, 要素が4つ以上あるデータの場合は配列を用いた場 + 合, 要素数*2(つまりオフセットとその意味)が7を越える. よって, そ + のような場合には構造体を使った方が理解しやすいと思われる. - (2) 同時に大量に生成されない + (3) 同時に大量に生成されない - 構造体は配列よりも若干生成コストが高いので, 速度が問題になる場合 - には, (同時に大量に生成される場合など)は構造体の使用が適切でない + 構造体は配列よりも若干生成コストが高いので, 速度が問題になる場合 + (例えば同時に大量に生成される場合など)は構造体の使用が適切でない 可能性がある. -各構造体にはメンバ名と同名の引数のないメソッドが定義されている. +各構造体にはメンバ名と同名の引数のないメソッドが定義される. 本ドキュメント内で, 構造体を表現するためには以下の形式を使う. @@ -3079,8 +3375,7 @@ Included Modules: Comparable Methods: - self == other - self > other + self <=> other otherはTimeのインスタンスか整数. 整数が与えられた場 合には1970年 1月 1日 00:00:00 GMTからの秒数であると @@ -3107,7 +3402,7 @@ Methods: localtime タイムゾーンの修正を行なった時刻を得る(デフォルト). localtime - も自分自身を返す. + は自分自身を返す. to_i tv_sec @@ -3,7 +3,7 @@ sprintf.c - $Author: matz $ - $Date: 1994/06/27 15:48:40 $ + $Date: 1994/08/12 04:47:57 $ created at: Fri Oct 15 10:39:26 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -51,7 +51,7 @@ Fsprintf(argc, argv) } #define GETARG() \ - ((argc == 1)?Fail("too few argument."):(argc--, argv++, argv[0])) + ((argc == 0)?Fail("too few argument."):(argc--, (argv++)[0])) fmt = (struct RString*)GETARG(); Check_Type(fmt, T_STRING); @@ -314,8 +314,8 @@ Fsprintf(argc, argv) bignum = 1; break; default: - WrongType(val, T_FIXNUM); - break; + val = num2fix(val); + goto int_retry; } if (bignum) { @@ -2,7 +2,7 @@ static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; #ifndef lint -static char *rcsid = "$Header: /work/cvsroot/ruby/st.c,v 1.2 1994/06/27 15:48:41 matz Exp $"; +static char *rcsid = "$Header: /usr/ext/cvsroot/ruby/st.c,v 1.2 1994/08/12 04:47:59 matz Exp $"; #endif #include <stdio.h> @@ -3,7 +3,7 @@ string.c - $Author: matz $ - $Date: 1994/06/27 15:48:44 $ + $Date: 1994/08/12 11:06:44 $ created at: Mon Aug 9 17:12:58 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -31,7 +31,7 @@ str_new(ptr, len) str->len = len; str->ptr = ALLOC_N(char,len+1); if (ptr) { - memmove(str->ptr, ptr, len); + memcpy(str->ptr, ptr, len); } str->ptr[len] = '\0'; str->orig = Qnil; @@ -285,61 +285,6 @@ Fstr_concat(str1, str2) return (VALUE)str1; } -static char -str_next(s) - char *s; -{ - char c = *s; - - /* control code */ - if (c < ' ') return 0; - - /* numerics */ - if ('0' <= c && c < '9') (*s)++; - else if (c == '9') { - *s = '0'; - return '1'; - } - /* small alphabets */ - else if ('a' <= c && c < 'z') (*s)++; - else if (c == 'z') { - return *s = 'a'; - } - /* capital alphabets */ - else if ('A' <= c && c < 'Z') (*s)++; - else if (c == 'Z') { - return *s = 'A'; - } - return 0; -} - -static VALUE -Fstr_next(orig) - struct RString *orig; -{ - struct RString *str, *str2; - char *sbeg, *s; - char c = -1; - - str = (struct RString*)str_new(orig->ptr, orig->len); - - sbeg = str->ptr; s = sbeg + str->len - 1; - - while (sbeg <= s) { - if (isalnum(*s) && (c = str_next(s)) == Qnil) break; - s--; - } - if (s < sbeg && c != -1) { - str2 = (struct RString*)str_new(0, str->len+1); - str2->ptr[0] = c; - memmove(str2->ptr+1, str->ptr, str->len); - obj_free(str); - str = str2; - } - - return (VALUE)str; -} - static str_hash(str) struct RString *str; @@ -418,24 +363,29 @@ Fstr_cmp(str1, str2) Regexp * make_regexp(); VALUE Freg_match(); +extern VALUE C_Glob; + static VALUE -Fstr_match(this, other) - struct RString *this, *other; +Fstr_match(x, y) + struct RString *x, *y; { VALUE reg; int start; - switch (TYPE(other)) { + switch (TYPE(y)) { case T_REGEXP: - return Freg_match(other, this); + return Freg_match(y, x); case T_STRING: - reg = re_regcomp(other); - start = research(reg, this, 0, ignorecase); + reg = re_regcomp(y); + start = research(reg, x, 0, ignorecase); if (start == -1) { return FALSE; } return INT2FIX(start); default: + if (obj_is_kind_of(y, C_Glob)) { + return Fglob_match(y, x); + } Fail("type mismatch"); break; } @@ -547,6 +497,74 @@ Fstr_rindex(str, args) return Qnil; } +static char +str_next(s) + char *s; +{ + char c = *s; + + /* numerics */ + if ('0' <= c && c < '9') (*s)++; + else if (c == '9') { + *s = '0'; + return '1'; + } + /* small alphabets */ + else if ('a' <= c && c < 'z') (*s)++; + else if (c == 'z') { + return *s = 'a'; + } + /* capital alphabets */ + else if ('A' <= c && c < 'Z') (*s)++; + else if (c == 'Z') { + return *s = 'A'; + } + return 0; +} + +static VALUE +Fstr_next(orig) + struct RString *orig; +{ + struct RString *str, *str2; + char *sbeg, *s; + char c = -1; + + str = (struct RString*)str_new(orig->ptr, orig->len); + + sbeg = str->ptr; s = sbeg + str->len - 1; + + while (sbeg <= s) { + if (isalnum(*s) && (c = str_next(s)) == Qnil) break; + s--; + } + if (s < sbeg && c != -1) { + str2 = (struct RString*)str_new(0, str->len+1); + str2->ptr[0] = c; + memmove(str2->ptr+1, str->ptr, str->len); + obj_free(str); + str = str2; + } + + return (VALUE)str; +} + +VALUE +Fstr_upto(beg, end) + VALUE beg, end; +{ + VALUE current; + + current = beg; + for (;;) { + rb_yield(current); + if (Fstr_equal(current, end)) break; + current = Fstr_next(current); + } + + return Qnil; +} + static VALUE Fstr_aref_internal(str, indx) struct RString *str; @@ -1474,6 +1492,47 @@ Fstr_intern(str) return rb_intern(str->ptr)|FIXNUM_FLAG; } +static VALUE +Fstr_sum(str, args) + struct RString *str; + VALUE args; +{ + VALUE vbits; + int bits; + char *p, *pend; + + rb_scan_args(args, "01", &vbits); + if (vbits == Qnil) bits = 16; + else bits = NUM2INT(vbits); + + p = str->ptr; pend = p + str->len; + if (bits > 32) { + VALUE res = INT2FIX(0); + VALUE mod; + + mod = rb_funcall(INT2FIX(1), rb_intern("<<"), 1, INT2FIX(bits)); + mod = rb_funcall(mod, '-', 1, INT2FIX(1)); + + while (p < pend) { + res = rb_funcall(res, '+', 1, INT2FIX((UINT)*p)); + res = rb_funcall(res, '%', 1, mod); + p++; + } + return res; + } + else { + UINT res = 0; + UINT mod = (1<<bits)-1; + + while (p < pend) { + res += (UINT)*p; + res %= mod; + p++; + } + return int2inum(res); + } +} + extern VALUE C_Kernel; extern VALUE M_Comparable; extern VALUE M_Enumerable; @@ -1494,9 +1553,11 @@ Init_String() rb_define_method(C_String, "[]", Fstr_aref, -2); rb_define_method(C_String, "[]=", Fstr_aset, -2); rb_define_method(C_String, "length", Fstr_length, 0); + rb_define_alias(C_String, "size", "length"); rb_define_method(C_String, "=~", Fstr_match, 1); rb_define_method(C_String, "~", Fstr_match2, 0); rb_define_method(C_String, "next", Fstr_next, 0); + rb_define_method(C_String, "upto", Fstr_next, 1); rb_define_method(C_String, "index", Fstr_index, -2); rb_define_method(C_String, "rindex", Fstr_rindex, -2); @@ -1532,6 +1593,8 @@ Init_String() rb_define_method(C_String, "each", Fstr_each, 0); rb_define_method(C_String, "each_byte", Fstr_each_byte, 0); + rb_define_method(C_String, "sum", Fstr_sum, -2); + rb_define_method(C_Kernel, "sub", Fsub, 2); rb_define_method(C_Kernel, "gsub", Fgsub, 2); @@ -3,7 +3,7 @@ struct.c - $Author: matz $ - $Date: 1994/06/17 14:23:51 $ + $Date: 1994/08/12 04:48:01 $ created at: Tue Mar 22 18:44:30 JST 1994 ************************************************/ @@ -3,7 +3,7 @@ time.c - $Author: matz $ - $Date: 1994/06/17 14:23:51 $ + $Date: 1994/08/12 11:06:46 $ created at: Tue Dec 28 14:31:59 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -28,10 +28,12 @@ struct time_object { int tm_got; }; +static ID id_tv; + #define GetTimeval(obj, tobj) \ - Get_Data_Struct(obj, "tv", struct time_object, tobj) + Get_Data_Struct(obj, id_tv, struct time_object, tobj) #define MakeTimeval(obj,tobj) {\ - Make_Data_Struct(obj, "tv", struct time_object, Qnil, Qnil, tobj);\ + Make_Data_Struct(obj, id_tv, struct time_object, Qnil, Qnil, tobj);\ tobj->tm_got=0;\ } @@ -543,4 +545,6 @@ Init_Time() rb_define_method(C_Time, "usec", Ftime_usec, 0); rb_define_method(C_Time, "strftime", Ftime_strftime, 1); + + id_tv = rb_intern("tv"); } diff --git a/variable.c b/variable.c index 5bddd9cc1d..70aa959acd 100644 --- a/variable.c +++ b/variable.c @@ -3,7 +3,7 @@ variable.c - $Author: matz $ - $Date: 1994/06/17 14:23:51 $ + $Date: 1994/08/19 09:32:10 $ created at: Tue Apr 19 23:55:15 JST 1994 ************************************************/ @@ -200,6 +200,7 @@ rb_gvar_get(entry) return Qnil; } +VALUE rb_ivar_get_1(obj, id) struct RBasic *obj; ID id; @@ -285,6 +286,7 @@ rb_gvar_set2(name, val) return val; } +VALUE rb_ivar_set_1(obj, id, val) struct RBasic *obj; ID id; @@ -304,11 +306,10 @@ rb_ivar_set(id, val) } static VALUE -const_bound(id) +const_bound(class, id) + struct RClass *class; ID id; { - struct RClass *class = (struct RClass*)CLASS_OF(Qself); - while (class) { if (class->c_tbl && st_lookup(class->c_tbl, id, Qnil)) { return TRUE; @@ -324,7 +325,7 @@ rb_const_set_1(class, id, val) ID id; VALUE val; { - if (const_bound(id)) + if (const_bound(class, id)) Fail("already initialized constnant"); if (class->c_tbl == Qnil) @@ -402,7 +403,7 @@ Fdefined(obj, name) break; case ID_CONST: - return const_bound(id); + return const_bound(CLASS_OF(Qself), id); break; default: @@ -3,8 +3,8 @@ version.c - $Author: matz $ - $Revision: 1.1.1.1 $ - $Date: 1994/06/17 14:23:51 $ + $Revision: 1.3 $ + $Date: 1994/08/18 07:06:32 $ created at: Thu Sep 30 20:08:01 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -27,5 +27,11 @@ Init_version() show_version() { - printf("ruby - version %s (%s)\n", RUBY_VERSION, VERSION_DATE); + fprintf(stderr, "ruby - version %s (%s)\n", RUBY_VERSION, VERSION_DATE); +} + +show_copyright() +{ + fprintf(stderr, "ruby - Copyright (C) 1994 Yukihiro Matsumoto\n"); + exit(0); } @@ -1,2 +1,2 @@ -#define RUBY_VERSION "0.50" -#define VERSION_DATE "10 Aug 94" +#define RUBY_VERSION "0.51" +#define VERSION_DATE "13 Oct 94" |