diff --git a/C-IF b/C-IF index 05f6edb638ad3b..5c66a20ddc95fd 100644 --- a/C-IF +++ b/C-IF @@ -24,9 +24,6 @@ Ruby-C 変更する時は以後のselfの値そのものが変わってしまうので, 特別な事情 がない限り代入してはならない. - 注意: ヘッダファイル"env.h"をインクルードしていないファイルでは, - Qselfは定数であり, 代入は文法エラーとなる. - TRUE 定数: tオブジェクト(真のデフォルト値) @@ -43,7 +40,7 @@ Ruby-C VALUE rb_define_module(char *name) - Rubyモジュールを定義する. + 新しいRubyモジュールを定義する. void rb_include_module(VALUE class, VALUE module) @@ -67,8 +64,8 @@ Ruby-C void rb_global_variable(VALUE *var) - GCのためRubyからはアクセスされないが, Rubyオブジェクトを含む大域変 - 数をマークする. + GCのため,Rubyプログラムからはアクセスされないが, Rubyオブジェクト + を含む大域変数をマークする. void rb_read_only_hook() @@ -87,20 +84,21 @@ Ruby-C メソッドを定義する. argcはselfを除く引数の数. argcが-1の時, 関数に は引数の数(selfを含まない)を第1引数, 引数の配列を第2引数とする形式 - で与えられる. argcが-2の時, 引数はself, args(argsは引数を含むrubyの - 配列)という形式で与えられる. + で与えられる(第3引数はself). argcが-2の時, 引数はself, args(argsは + 引数を含むrubyの配列)という形式で与えられる. rb_define_single_method(VALUE class, char *name, VALUE (*func)(), int argc) 特異メソッドを定義する. 引数はrb_define_method()と同じ. - rb_scan_args(VALUE args, char *fmt, ...) + rb_scan_args(int atgc, VALUE *argv, char *fmt, ...) - args形式で与えられた引数を分解する. fmtは必須引数の数, 付加引数の数, - 残りの引数があるかを指定する文字列で, "数字数字*"という形式である. - 2 番目の数字と"*"はそれぞれ省略可能である. 第3引数以降は変数へのポ - インタで, 該当する要素がその変数に格納される. 付加引数に対応する引 - 数が与えられていない場合は変数にQnilが代入される. + argc,argv形式で与えられた引数を分解する. fmtは必須引数の数, 付加引 + 数の数, 残りの引数があるかを指定する文字列で, "数字数字*"という形式 + である. 2 番目の数字と"*"はそれぞれ省略可能である. 必須引数が一つ + もない場合は0を指定する.第3引数以降は変数へのポインタで, 該当する + 要素がその変数に格納される. 付加引数に対応する引数が与えられていな + い場合は変数にQnilが代入される. Rubyメソッド呼び出し @@ -108,12 +106,13 @@ Ruby メソッド呼び出し. 文字列からmidを得るためにはrb_intern()を使う. - rb_call_super(VALUE args) + VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) + + メソッド呼び出し. 引数をargc,argv形式で渡す. - スーパークラスのメソッドを呼び出す. argsは引数リストとなる配列. - args がQnilの時は現在のメソッドの引数をそのまま引き継ぐ. + VALUE rb_eval_string(char *str) -文字列 <-> ID変換 + 文字列をrubyとスクリプトしてコンパイル・実行する. ID rb_intern(char *name) diff --git a/ChangeLog b/ChangeLog index f6246f3a0db8cf..35d02ea51e13d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,91 @@ +Wed Feb 1 19:48:24 1995 Yukihiro Matsumoto (matz@ix-02) + + * string.c(str_replace): 置き換える文字列の長さが等しい時メモリコ + ピーをしない. + + * string.c(rindex): バグ修正. + +Mon Jan 30 11:23:05 1995 Yukihiro Matsumoto (matz@ix-02) + + * parse.y(value_expr): ifのチェックを追加. + + * gc.c(gc_mark): free cellの扱いにバグ. + + * parse.y: 文法の変更(よりシンプルに).例外を減らした. + +Thu Jan 26 00:52:55 1995 Yukihiro Matsumoto (matz@dyna) + + * parse.y: 引数として連想配列を置くことができるように.この場合, + 連想配列リテラルが最終引数となる. + + * parse.y: 配列参照の`[]'内が空でもよいことにした. + +Tue Jan 24 14:45:15 1995 Yukihiro Matsumoto (matz@ix-02) + + * class.c(rb_include_module): `-v'を指定した時にはincludeしたモジュー + ルとクラス定数が衝突していないかチェックする. + +Mon Jan 23 10:42:09 1995 Yukihiro Matsumoto (matz@ix-02) + + * parse.y(rb_class2name): メタクラスに関するbug fix. + + * dict.c: Dict[..]で辞書の生成が出来るように. + + * array.c: Array[..]で配列の生成が出来るように. + + * parse.y: 辞書の表現として{a,b,..}という形式も許すように. + +Fri Jan 20 10:28:38 1995 Yukihiro Matsumoto (matz@ix-02) + + * re.c(Regexp.quote): 正規表現をエスケープするメソッド. + + * 無駄なrb_intern()を減らした. + + * parse.y: `!', `!=', `!~'を特殊演算子にする.よってこれらは再定義 + できなくなった. + +Wed Jan 18 13:20:41 1995 Yukihiro Matsumoto (matz@ix-02) + + * parse.y: 文法の整理(unless,untilをなくした). + +Tue Jan 17 11:11:27 1995 Yukihiro Matsumoto (matz@ix-02) + + * eval.c: defでメソッド再定義時にはスーパークラスのメソッドの可視 + 性を継承する.最初の定義の時は今までと同じデフォルト(トップレベ + ルで関数的,クラス定義内で通常メソッド). + + * object.c(Class::new): オブジェクトの生成時に関数的メ + ソッドinit_objectが必ず呼ばれるように変更. + + * eval.c: 未定義のメソッドに対してunknownメソッドが呼ばれるように + なった.エラー表示が今までと同じになるようにenvを調節している. + +Fri Jan 13 14:40:30 1995 Yukihiro Matsumoto (matz@ix-02) + + * gc.c: gcを若干書き換えて整理した.が,あまり変化はなかったようだ. + + * parse.y(yylex): symbolを\symから:symに変更した. + +Thu Jan 12 01:39:28 1995 Yukihiro Matsumoto (matz@dyna) + + * eval.c: 新規関数 rb_eval_string(). + + * gc.c: gc_mark()を一部非再帰化. + + * variable.c(rb_ivar_{get,set}): インスタンス変数のアクセス周りで + チェックが足りなかった. + + * variable.c: クラス定数とインスタンス変数でハッシュテーブルを共有 + するようにした. + + * ruby.h: iv_tblをRBasicからRObjectとRClassへ移動した.これにより, + ObjectとClass,Moduleしかインスタンス変数を持てなくなる.が,メモ + リ効率は若干向上する. + Tue Jan 10 00:58:20 1995 Yukihiro Matsumoto (matz@dyna) + * 0.64 released + * eval.c: レシーバと引数は常にiterではない. * cons.c(aref,aset): negative offset対応. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 00000000000000..429e9210747620 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,67 @@ +C-IF +ChangeLog +FAQ +MANIFEST +Makefile.in +README +ToDo +array.c +bignum.c +class.c +compar.c +configure +configure.in +cons.c +dbm.c +defines.h +dict.c +dir.c +dln.c +dln.h +enum.c +env.h +error.c +etc.c +eval.c +file.c +fnmatch.c +fnmatch.h +gc.c +getopt.c +getopt.h +getopt1.c +glob.c +gnuglob.c +ident.h +inits.c +io.c +io.h +main.c +math.c +node.h +numeric.c +object.c +pack.c +parse.y +process.c +random.c +range.c +re.c +re.h +regex.c +regex.h +ruby.1 +ruby.c +ruby.h +signal.c +socket.c +spec +sprintf.c +st.c +st.h +string.c +struct.c +time.c +variable.c +version.c +version.h diff --git a/Makefile.in b/Makefile.in index 477b4fdbd25072..b0c6eb5ea93eec 100644 --- a/Makefile.in +++ b/Makefile.in @@ -160,7 +160,7 @@ io.o: io.c ruby.h config.h defines.h io.h main.o: main.c math.o: math.c ruby.h config.h defines.h numeric.o: numeric.c ruby.h config.h defines.h env.h -object.o: object.c ruby.h config.h defines.h env.h node.h st.h +object.o: object.c ruby.h config.h defines.h env.h st.h pack.o: pack.c ruby.h config.h defines.h process.o: process.c ruby.h config.h defines.h st.h random.o: random.c ruby.h config.h defines.h @@ -174,5 +174,5 @@ st.o: st.c st.h string.o: string.c ruby.h config.h defines.h re.h regex.h struct.o: struct.c ruby.h config.h defines.h env.h time.o: time.c ruby.h config.h defines.h -variable.o: variable.c ruby.h config.h defines.h env.h node.h ident.h st.h +variable.o: variable.c ruby.h config.h defines.h env.h ident.h st.h version.o: version.c ruby.h config.h defines.h version.h diff --git a/ToDo b/ToDo index 5422040f450ece..5dcb005f524ed9 100644 --- a/ToDo +++ b/ToDo @@ -1,10 +1,12 @@ +* Process Class +* クラスライブラリの見直し(UNIX依存を減らす) * format機能 * here document * perlのようなsetuid check * trからBSDコードを取り除く(またはcopyrightをはっきりさせる) * 適切なsignal handling -* dlnのCOFF対応 +* dlnのCOFF対応(またはdlopen対応) * rubyで定義する変数hookの実現 * write debugger for ruby -* re-write regex code for speeding +* re-write regex code for speed * byte code interpretor diff --git a/array.c b/array.c index 5a8f040723c59f..28d755b73f28fe 100644 --- a/array.c +++ b/array.c @@ -77,32 +77,33 @@ ary_new4(n, elts) return (VALUE)ary; } -#if 0 -VALUE -assoc_new(elm1, elm2) - VALUE elm1, elm2; +static VALUE +Sary_new(class) + VALUE class; { - struct RArray *ary; + NEWOBJ(ary, struct RArray); + OBJSETUP(ary, class, T_ARRAY); - ary = (struct RArray*)ary_new2(2); - ary->ptr[0] = elm1; - ary->ptr[1] = elm2; - ary->len = 2; + ary->len = 0; + ary->capa = ARY_DEFAULT_SIZE; + ary->ptr = ALLOC_N(VALUE, ARY_DEFAULT_SIZE); return (VALUE)ary; } -#endif static VALUE -Sary_new(class) +Sary_create(argc, argv, class) + int argc; + VALUE *argv; VALUE class; { NEWOBJ(ary, struct RArray); OBJSETUP(ary, class, T_ARRAY); - ary->len = 0; - ary->capa = ARY_DEFAULT_SIZE; - ary->ptr = ALLOC_N(VALUE, ARY_DEFAULT_SIZE); + ary->len = argc; + ary->capa = argc; + ary->ptr = ALLOC_N(VALUE, argc); + MEMCPY(ary->ptr, argv, VALUE, argc); return (VALUE)ary; } @@ -648,7 +649,10 @@ static int sort_2(a, b) VALUE *a, *b; { - VALUE retval = rb_funcall(*a, cmp, 1, *b); + VALUE retval; + + if (!cmp) cmp = rb_intern("<=>"); + retval = rb_funcall(*a, cmp, 1, *b); return NUM2INT(retval); } @@ -936,6 +940,7 @@ Init_Array() rb_include_module(C_Array, M_Enumerable); rb_define_single_method(C_Array, "new", Sary_new, 0); + rb_define_single_method(C_Array, "[]", Sary_create, -1); rb_define_method(C_Array, "to_s", Fary_to_s, 0); rb_define_method(C_Array, "_inspect", Fary_inspect, 0); rb_define_method(C_Array, "to_a", Fary_to_a, 0); @@ -976,6 +981,4 @@ Init_Array() rb_define_method(C_Array, "-", Fary_diff, 1); rb_define_method(C_Array, "&", Fary_and, 1); rb_define_method(C_Array, "|", Fary_or, 1); - - cmp = rb_intern("<=>"); } diff --git a/bignum.c b/bignum.c index 59667faaca383a..ef76fc532d5416 100644 --- a/bignum.c +++ b/bignum.c @@ -88,7 +88,7 @@ bignorm(x) while (len-- && !ds[len]) ; x->len = ++len; - + if (len*sizeof(USHORT) < sizeof(VALUE) || (len*sizeof(USHORT) == sizeof(VALUE) && ds[sizeof(VALUE)/sizeof(USHORT)-1] <= 0x3fff)) { diff --git a/class.c b/class.c index ba056a628383b4..6c790b79ee9fbe 100644 --- a/class.c +++ b/class.c @@ -3,7 +3,7 @@ class.c - $Author: matz $ - $Date: 1995/01/10 10:42:21 $ + $Date: 1995/01/12 08:54:44 $ created at: Tue Aug 10 15:05:44 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -29,7 +29,6 @@ class_new(super) cls->super = super; cls->m_tbl = new_idhash(); - cls->c_tbl = Qnil; return (VALUE)cls; } @@ -69,13 +68,12 @@ single_class_clone(class) clone->super = class->super; clone->m_tbl = new_idhash(); st_foreach(class->m_tbl, clone_method, clone->m_tbl); - clone->c_tbl = Qnil; FL_SET(clone, FL_SINGLE); return (VALUE)clone; } } -VALUE +VALUE rb_define_class_id(id, super) ID id; struct RBasic *super; @@ -90,7 +88,7 @@ rb_define_class_id(id, super) return (VALUE)cls; } -VALUE +VALUE rb_define_class(name, super) char *name; VALUE super; @@ -106,12 +104,11 @@ module_new() mdl->super = Qnil; mdl->m_tbl = new_idhash(); - mdl->c_tbl = Qnil; return (VALUE)mdl; } -VALUE +VALUE rb_define_module_id(id) ID id; { @@ -121,7 +118,7 @@ rb_define_module_id(id) return (VALUE)mdl; } -VALUE +VALUE rb_define_module(name) char *name; { @@ -138,7 +135,7 @@ include_class_new(module, super) OBJSETUP(cls, C_Class, T_ICLASS); cls->m_tbl = module->m_tbl; - cls->c_tbl = module->c_tbl; + cls->iv_tbl = module->iv_tbl; cls->super = super; if (TYPE(module) == T_ICLASS) { RBASIC(cls)->class = RBASIC(module)->class; @@ -155,26 +152,30 @@ rb_include_module(class, module) struct RClass *class, *module; { struct RClass *p; - int added = FALSE; + + if (!module) return; Check_Type(module, T_MODULE); + if (BUILTIN_TYPE(class) == T_CLASS) { + rb_clear_cache2(class); + } + while (module) { - /* ignore if module included already in superclasses */ + /* ignore if the module included already in superclasses */ for (p = class->super; p; p = p->super) { if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == module->m_tbl) - goto ignore_module; + return; + } + + if (verbose) { + rb_const_check(class, module); } class->super = include_class_new(module, class->super); - added = TRUE; class = class->super; - ignore_module: module = module->super; } - if (added) { - rb_clear_cache2(class); - } } void diff --git a/cons.c b/cons.c index ac562814ca0af2..bf755865c98f20 100644 --- a/cons.c +++ b/cons.c @@ -3,7 +3,7 @@ cons.c - $Author: matz $ - $Date: 1995/01/10 10:22:24 $ + $Date: 1995/01/10 10:30:37 $ created at: Fri Jan 6 10:10:36 JST 1995 Copyright (C) 1994 Yukihiro Matsumoto @@ -178,6 +178,7 @@ Fcons_hash(cons) { int key; + if (!hash) hash = rb_intern("hash"); key = rb_funcall(cons->car, hash, 0, 0); key ^= rb_funcall(cons->cdr, hash, 0, 0); return INT2FIX(key); @@ -253,7 +254,6 @@ Init_Cons() rb_define_method(C_Cons, "==", Fcons_equal, 1); rb_define_method(C_Cons, "hash", Fcons_hash, 0); - hash = rb_intern("hash"); rb_define_method(C_Cons, "length", Fcons_length, 0); rb_define_method(C_Cons, "to_s", Fcons_to_s, 0); diff --git a/dbm.c b/dbm.c index c0fd514e59757c..ed605614a04bb3 100644 --- a/dbm.c +++ b/dbm.c @@ -31,6 +31,7 @@ closeddbm() #define GetDBM(obj, dbmp) {\ DBM **_dbm;\ + if (!id_dbm) id_dbm = rb_intern("dbm");\ Get_Data_Struct(obj, id_dbm, DBM*, _dbm);\ dbmp = *_dbm;\ if (dbmp == Qnil) closeddbm();\ @@ -156,7 +157,7 @@ Fdbm_delete(obj, keystr) Check_Type(keystr, T_STRING); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; - + GetDBM(obj, dbm); if (dbm_delete(dbm, key)) { Fail("dbm_delete failed"); @@ -338,7 +339,7 @@ Fdbm_has_key(obj, keystr) Check_Type(keystr, T_STRING); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; - + GetDBM(obj, dbm); val = dbm_fetch(dbm, key); if (val.dptr) return TRUE; @@ -355,7 +356,7 @@ Fdbm_has_value(obj, valstr) Check_Type(valstr, T_STRING); val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; - + GetDBM(obj, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); @@ -412,7 +413,5 @@ 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 */ diff --git a/dict.c b/dict.c index d6ccbca56e7eb9..fa4ffc04e3914e 100644 --- a/dict.c +++ b/dict.c @@ -41,7 +41,6 @@ static VALUE Sdic_new(class) VALUE class; { - int i, max; NEWOBJ(dic, struct RDict); OBJSETUP(dic, class, T_DICT); @@ -50,6 +49,40 @@ Sdic_new(class) return (VALUE)dic; } +static VALUE Fdic_clone(); + +static VALUE +Sdic_create(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + struct RDict *dic; + int i; + + if (argc == 1 && TYPE(argv[0]) == T_DICT) { + if (class == CLASS_OF(argv[0])) return argv[0]; + else { + NEWOBJ(dic, struct RDict); + OBJSETUP(dic, class, T_DICT); + dic->tbl = (st_table*)st_copy(RDICT(argv[0])->tbl); + + return (VALUE)dic; + } + } + + if (argc % 2 != 0) { + Fail("odd number args for Dict"); + } + dic = (struct RDict*)Sdic_new(class); + + for (i=0; itbl, argv[i], argv[i+1]); + } + + return (VALUE)dic; +} + VALUE dic_new() { @@ -551,6 +584,7 @@ Init_Dict() rb_include_module(C_Dict, M_Enumerable); rb_define_single_method(C_Dict, "new", Sdic_new, 0); + rb_define_single_method(C_Dict, "[]", Sdic_create, -1); rb_define_method(C_Dict,"clone", Fdic_clone, 0); diff --git a/dir.c b/dir.c index 0baa13fdd107f8..755290fa0c78d1 100644 --- a/dir.c +++ b/dir.c @@ -55,11 +55,12 @@ Sdir_open(dir_class, dirname) DIR *dirp, **d; Check_Type(dirname, T_STRING); - + dirp = opendir(dirname->ptr); if (dirp == NULL) Fail("Can't open directory %s", dirname->ptr); obj = obj_alloc(dir_class); + if (!id_dir) id_dir = rb_intern("dir"); Make_Data_Struct(obj, id_dir, DIR*, Qnil, free_dir, d); *d = dirp; @@ -74,6 +75,7 @@ closeddir() #define GetDIR(obj, dirp) {\ DIR **_dp;\ + if (!id_dir) id_dir = rb_intern("dir");\ Get_Data_Struct(obj, id_dir, DIR*, _dp);\ dirp = *_dp;\ if (dirp == NULL) closeddir();\ @@ -260,6 +262,4 @@ Init_Dir() rb_define_single_method(C_Dir,"rmdir", Sdir_rmdir, 1); rb_define_single_method(C_Dir,"delete", Sdir_rmdir, 1); rb_define_single_method(C_Dir,"unlink", Sdir_rmdir, 1); - - id_dir = rb_intern("dir"); } diff --git a/dln.c b/dln.c index 44179ec3e976b9..2e1ff5aed5cf3e 100644 --- a/dln.c +++ b/dln.c @@ -238,7 +238,7 @@ dln_load_reloc(fd, hdrp, disp) int size; lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); - + size = hdrp->a_trsize + hdrp->a_drsize; reloc = (struct relocation_info*)xmalloc(size); if (reloc == NULL) { @@ -251,7 +251,7 @@ dln_load_reloc(fd, hdrp, disp) free(reloc); return NULL; } - + return reloc; } @@ -681,7 +681,7 @@ static int dln_load_1(fd, disp, need_init) */ { struct relocation_info * rel = reloc; - struct relocation_info * rel_beg = reloc + + struct relocation_info * rel_beg = reloc + (hdr.a_trsize/sizeof(struct relocation_info)); struct relocation_info * rel_end = reloc + (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); @@ -772,7 +772,7 @@ static int dln_load_1(fd, disp, need_init) while (sym < end) { char *name = sym->n_un.n_name; if (name[0] == '_' && sym->n_value >= block - && ((bcmp (name, "_Init_", 6) == 0 + && ((bcmp (name, "_Init_", 6) == 0 || bcmp (name, "_init_", 6) == 0) && name[6] != '_')) { init_p = 1; ((int (*)())sym->n_value)(); diff --git a/enum.c b/enum.c index 5eaef855f1c745..a27c9860d2c7ec 100644 --- a/enum.c +++ b/enum.c @@ -19,6 +19,7 @@ void rb_each(obj) VALUE obj; { + if (!id_each) id_each = rb_intern("each"); rb_funcall(obj, id_each, 0, Qnil); } @@ -26,6 +27,7 @@ static void enum_grep(i, arg) VALUE i, *arg; { + if (!id_match) id_match = rb_intern("=~"); if (rb_funcall(arg[0], id_match, 1, i)) { ary_push(arg[1], i); } @@ -35,6 +37,7 @@ static void enum_grep2(i, pat) VALUE i, pat; { + if (!id_match) id_match = rb_intern("=~"); if (rb_funcall(pat, id_match, 1, i)) { rb_yield(i); } @@ -150,7 +153,7 @@ enum_all(i, ary) { ary_push(ary, i); } - + static VALUE Fenum_to_a(obj) VALUE obj; @@ -183,6 +186,7 @@ enum_min(i, min) if (*min == Qnil) *min = i; else { + if (!id_cmp) id_cmp = rb_intern("<=>"); cmp = rb_funcall(i, id_cmp, 1, *min); if (FIX2INT(cmp) < 0) *min = i; @@ -208,6 +212,7 @@ enum_max(i, max) if (*max == Qnil) *max = i; else { + if (!id_cmp) id_cmp = rb_intern("<=>"); cmp = rb_funcall(i, id_cmp, 1, *max); if (FIX2INT(cmp) > 0) *max = i; @@ -316,8 +321,4 @@ Init_Enumerable() rb_define_method(M_Enumerable,"index", Fenum_index, 1); rb_define_method(M_Enumerable,"includes", Fenum_includes, 1); rb_define_method(M_Enumerable,"length", Fenum_length, 0); - - id_each = rb_intern("each"); - id_match = rb_intern("=~"); - id_cmp = rb_intern("<=>"); } diff --git a/error.c b/error.c index 437d0baef381ac..e9626165fb0626 100644 --- a/error.c +++ b/error.c @@ -82,7 +82,7 @@ Warning(fmt, va_alist) char *fmt; va_dcl { - char buf[BUFSIZ]; + char buf[BUFSIZ]; va_list args; sprintf(buf, "warning: %s", fmt); @@ -108,7 +108,7 @@ Bug(fmt, va_alist) char *fmt; va_dcl { - char buf[BUFSIZ]; + char buf[BUFSIZ]; va_list args; sprintf(buf, "[BUG] %s", fmt); @@ -124,7 +124,7 @@ Fail(fmt, va_alist) va_dcl { va_list args; - char buf[BUFSIZ]; + char buf[BUFSIZ]; va_start(args); vsprintf(buf, fmt, args); @@ -132,7 +132,7 @@ Fail(fmt, va_alist) rb_fail(str_new2(buf)); } - + rb_sys_fail(mesg) char *mesg; { @@ -164,8 +164,6 @@ static char *builtin_types[] = { "Method", "Struct", "Bignum", - "Node", - "Scope", "Cons", "Data", }; diff --git a/eval.c b/eval.c index c54fa14e5e8386..1e00de909c9587 100644 --- a/eval.c +++ b/eval.c @@ -3,7 +3,7 @@ eval.c - $Author: matz $ - $Date: 1995/01/10 10:42:34 $ + $Date: 1995/01/12 08:54:45 $ created at: Thu Jun 10 14:22:17 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -52,7 +52,7 @@ search_method(class, id, origin) if (class == Qnil) return Qnil; } - *origin = class; + if (origin) *origin = class; return body; } @@ -389,6 +389,7 @@ ruby_init(argc, argv, envp) static struct ENVIRON env; the_env = top_env = &env; + init_heap(); PUSH_SCOPE(); the_scope->local_vars = Qnil; the_scope->local_tbl = Qnil; @@ -414,13 +415,14 @@ ruby_init(argc, argv, envp) VALUE rb_readonly_hook(); static VALUE -Eval(toplevel) - int toplevel; +Eval() { VALUE result; NODE *tree; int state; + if (!eval_tree) return Qnil; + tree = eval_tree; eval_tree = Qnil; sourcefile = tree->file; @@ -441,7 +443,7 @@ ruby_run() if (nerrs > 0) exit(nerrs); - Init_stack(); + init_stack(); rb_define_variable("$!", &errstr, Qnil, Qnil, 0); errat = Qnil; /* clear for execution */ @@ -449,7 +451,7 @@ ruby_run() PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { the_class = (struct RClass*)C_Object; - Eval(1); + Eval(); } POP_ITER(); POP_TAG(); @@ -488,6 +490,38 @@ ruby_run() exit(0); } +static void +syntax_error() +{ + VALUE mesg; + + mesg = errstr; + nerrs = 0; + errstr = str_new2("syntax error in eval():\n"); + str_cat(errstr, RSTRING(mesg)->ptr, RSTRING(mesg)->len); + rb_fail(errstr); +} + +VALUE +rb_eval_string(str) + char *str; +{ + char *oldsrc = sourcefile; + VALUE result; + + lex_setsrc("(eval)", str, strlen(str)); + eval_tree = Qnil; + yyparse(); + sourcefile = oldsrc; + if (nerrs == 0) { + return Eval(); + } + else { + syntax_error(); + } + return Qnil; /* not reached */ +} + void rb_trap_eval(cmd) VALUE cmd; @@ -636,34 +670,9 @@ rb_eval(node) return rb_eval(node); } node = node->nd_next; - } - } - return Qnil; - - case NODE_EXNOT: - { - VALUE res; - - PUSH_TAG(); - switch (state = EXEC_TAG()) { - case 0: - res = rb_eval(node->nd_cond); - go_out = 0; - break; - - case TAG_FAIL: - res = Qnil; - go_out = 0; - break; - - default: - go_out = 1; } - POP_TAG(); - if (go_out) JUMP_TAG(state); - if (res) return FALSE; - return TRUE; } + return Qnil; case NODE_WHILE: PUSH_TAG(); @@ -828,6 +837,10 @@ rb_eval(node) node = node->nd_2nd; goto again; + case NODE_NOT: + if (rb_eval(node->nd_body)) return FALSE; + return TRUE; + case NODE_DOT3: if (node->nd_state == 0) { if (rb_eval(node->nd_beg)) { @@ -943,7 +956,8 @@ rb_eval(node) val = rb_apply(recv, aref, args); val = rb_funcall(val, node->nd_mid, 1, rb_eval(rval)); ary_push(args, val); - return rb_apply(recv, aset, args); + rb_apply(recv, aset, args); + return val; } case NODE_OP_ASGN2: @@ -957,7 +971,8 @@ rb_eval(node) id |= ID_ATTRSET; val = rb_eval(node->nd_value); - return rb_funcall(recv, id, 1, val); + rb_funcall(recv, id, 1, val); + return val; } case NODE_MASGN: @@ -1044,7 +1059,7 @@ rb_eval(node) key = rb_eval(list->nd_head); list = list->nd_next; if (list == Qnil) - Bug("odd number list for hash"); + Bug("odd number list for Dict"); val = rb_eval(list->nd_head); list = list->nd_next; Fdic_aset(hash, key, val); @@ -1122,39 +1137,42 @@ rb_eval(node) return rb_ivar_set(node->nd_vid, the_env->argv[0]); case NODE_DEFN: - { - if (node->nd_defn) { - rb_add_method(the_class,node->nd_mid,node->nd_defn, - node->nd_noex); + if (node->nd_defn) { + NODE *body; + VALUE origin; + int noex; + + body = search_method(the_class, node->nd_mid, &origin); + if (verbose && origin != (VALUE)the_class + && body->nd_noex != node->nd_noex) { + Warning("change method %s's scope", rb_id2name(node->nd_mid)); } + + if (body) noex = body->nd_noex; + else noex = node->nd_noex; /* default(1 for toplevel) */ + + rb_add_method(the_class, node->nd_mid, node->nd_defn, noex); } return Qnil; case NODE_DEFS: - { - if (node->nd_defn) { - VALUE recv = rb_eval(node->nd_recv); + if (node->nd_defn) { + VALUE recv = rb_eval(node->nd_recv); - if (recv == Qnil) { - Fail("Can't define method \"%s\" for nil", - rb_id2name(node->nd_mid)); - } - rb_add_method(rb_single_class(recv), - node->nd_mid, node->nd_defn, 0); + if (recv == Qnil) { + Fail("Can't define method \"%s\" for nil", + rb_id2name(node->nd_mid)); } + rb_add_method(rb_single_class(recv),node->nd_mid,node->nd_defn,0); } return Qnil; case NODE_UNDEF: - { - rb_add_method(the_class, node->nd_mid, Qnil, 0); - } + rb_add_method(the_class, node->nd_mid, Qnil, 0); return Qnil; case NODE_ALIAS: - { - rb_alias(the_class, node->nd_new, node->nd_old); - } + rb_alias(the_class, node->nd_new, node->nd_old); return Qnil; case NODE_CLASS: @@ -1492,7 +1510,7 @@ asign(lhs, val) break; default: - Bug("bug in iterator variable asignment"); + Bug("bug in variable asignment"); break; } } @@ -1614,28 +1632,62 @@ rb_ensure(b_proc, data1, e_proc, data2) return result; } -struct st_table *new_idhash(); +static int last_noex; -static void -rb_undefined(obj, id, noex) +static VALUE +Funknown(argc, argv, obj) + int argc; + VALUE *argv; VALUE obj; - ID id; - int noex; { - VALUE desc = obj_as_string(obj); + VALUE desc; + ID id; char *format; + struct ENVIRON *env; + + id = FIX2INT(argv[0]); + argc--; argv++; + desc = obj_as_string(obj); if (RSTRING(desc)->len > 160) { desc = Fkrn_to_s(obj); } - if (noex) + if (last_noex) format = "method `%s' not available for \"%s\"(%s)"; else format = "undefined method `%s' for \"%s\"(%s)"; + + /* fake environment */ + PUSH_ENV(); + env = the_env->prev; + MEMCPY(the_env, the_env->prev->prev, struct ENVIRON, 1); + the_env->prev = env; + Fail(format, rb_id2name(id), RSTRING(desc)->ptr, rb_class2name(CLASS_OF(obj))); + POP_ENV(); +} + +static VALUE +rb_undefined(obj, id, argc, argv, noex) + VALUE obj; + ID id; + int argc; + VALUE*argv; + int noex; +{ + VALUE *nargv; + + argc; + nargv = ALLOCA_N(VALUE, argc+1); + nargv[0] = INT2FIX(id); + MEMCPY(nargv+1, argv, VALUE, argc); + + last_noex = noex; + + return rb_funcall2(obj, rb_intern("unknown"), argc+1, nargv); } static VALUE @@ -1656,7 +1708,6 @@ rb_call(class, recv, mid, argc, argv, func) /* is it in the method cache? */ ent = cache + EXPR1(class, mid); if (ent->mid == mid && ent->class == class) { - /* if (ent->method == Qnil) rb_undefined(recv, mid, 0); */ class = ent->origin; mid = ent->mid; body = ent->method; @@ -1666,12 +1717,14 @@ rb_call(class, recv, mid, argc, argv, func) ID id = mid; if ((body = rb_get_method_body(&class, &id, &noex)) == Qnil) { - rb_undefined(recv, mid, 0); + return rb_undefined(recv, mid, argc, argv, 0); } mid = id; } - if (!func && noex) rb_undefined(recv, mid, 1); + if (!func && noex) { + return rb_undefined(recv, mid, argc, argv, 1); + } switch (iter->iter) { case ITER_PRE: @@ -1691,7 +1744,7 @@ rb_call(class, recv, mid, argc, argv, func) the_env->argv = argv; switch (nd_type(body)) { - case NODE_CFUNC: + case NODE_CFUNC: { int len = body->nd_argc; @@ -1806,6 +1859,8 @@ rb_call(class, recv, mid, argc, argv, func) /* for attr get/set */ case NODE_ATTRSET: case NODE_IVAR: + /* for exported method */ + case NODE_ZSUPER: return rb_eval(body); default: @@ -1915,17 +1970,19 @@ Fapply(argc, argv, recv) VALUE *argv; VALUE recv; { - VALUE vid, rest; + VALUE vid; ID mid; - rb_scan_args(argc, argv, "1*", &vid, &rest); + if (argc == 0) Fail("no method name given"); + + vid = argv[0]; argc--; argv++; if (TYPE(vid) == T_STRING) { mid = rb_intern(RSTRING(vid)->ptr); } else { mid = NUM2INT(vid); } - return rb_apply(recv, mid, rest); + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1); } #include @@ -1958,6 +2015,16 @@ rb_funcall(recv, mid, n, va_alist) return rb_call(CLASS_OF(recv), recv, mid, n, argv, 1); } +VALUE +rb_funcall2(recv, mid, argc, argv) + VALUE recv; + ID mid; + int argc; + VALUE *argv; +{ + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1); +} + int rb_in_eval = 0; static VALUE @@ -1995,13 +2062,7 @@ Feval(obj, src) if (state) JUMP_TAG(state); if (nerrs > 0) { - VALUE mesg; - - mesg = errstr; - nerrs = 0; - errstr = str_new2("syntax error in eval():\n"); - str_cat(errstr, RSTRING(mesg)->ptr, RSTRING(mesg)->len); - rb_fail(errstr); + syntax_error(); } return result; @@ -2151,6 +2212,24 @@ addpath(path) extern VALUE C_Kernel; + +Init_eval() +{ + match = rb_intern("=~"); + each = rb_intern("each"); + + aref = rb_intern("[]"); + aset = rb_intern("[]="); + + rb_global_variable(&top_scope); + rb_global_variable(&eval_tree); + rb_define_private_method(C_Kernel, "exit", Fexit, -1); + rb_define_private_method(C_Kernel, "eval", Feval, 1); + rb_define_private_method(C_Kernel, "iterator_p", Fiterator_p, 0); + rb_define_method(C_Kernel, "apply", Fapply, -1); + rb_define_method(C_Kernel, "unknown", Funknown, -1); +} + Init_load() { char *path; @@ -2169,22 +2248,6 @@ Init_load() rb_define_private_method(C_Kernel, "require", Frequire, 1); } -Init_eval() -{ - match = rb_intern("=~"); - each = rb_intern("each"); - - aref = rb_intern("[]"); - aset = rb_intern("[]="); - - rb_global_variable(&top_scope); - rb_global_variable(&eval_tree); - rb_define_private_method(C_Kernel, "exit", Fexit, -1); - rb_define_private_method(C_Kernel, "eval", Feval, 1); - rb_define_private_method(C_Kernel, "iterator_p", Fiterator_p, 0); - rb_define_method(C_Kernel, "apply", Fapply, -1); -} - void scope_dup(scope) struct SCOPE *scope; @@ -2239,11 +2302,12 @@ Sblk_new(class) if (the_block->block) return the_block->block; blk = obj_alloc(class); + if (!blkdata) blkdata = rb_intern("blk"); Make_Data_Struct(blk, blkdata, struct BLOCK, Qnil, blk_free, data); MEMCPY(data, the_block, struct BLOCK, 1); data->env.argv = ALLOC_N(VALUE, data->env.argc); - MEMCPY(data->env.argv, the_block->env.argv, VALUE, data->env.argc); + MEMCPY(data->env.argv, the_block->env.argv, VALUE, data->env.argc); scope_dup(data->scope); @@ -2252,13 +2316,13 @@ Sblk_new(class) } VALUE -blk_new() +block_new() { return Sblk_new(C_Block); } static VALUE -Fblk_do(blk, args) +Fblk_call(blk, args) VALUE blk, args; { struct BLOCK *data; @@ -2318,6 +2382,5 @@ Init_Block() rb_define_single_method(C_Block, "new", Sblk_new, 0); - rb_define_method(C_Block, "do", Fblk_do, -2); - blkdata = rb_intern("blk"); + rb_define_method(C_Block, "call", Fblk_call, -2); } diff --git a/file.c b/file.c index bae2c3140b13d9..6f10099c332bf4 100644 --- a/file.c +++ b/file.c @@ -225,7 +225,7 @@ stat_new(st) "blksize", INT2FIX(0), #endif #ifdef HAVE_ST_BLOCKS - "blocks", INT2FIX((int)st->st_blocks), + "blocks", INT2FIX((int)st->st_blocks), #else "blocks", INT2FIX(0), #endif @@ -721,7 +721,7 @@ Sfile_type(obj, fname) t = "directory"; } else if (S_ISCHR(st.st_mode)) { t = "characterSpecial"; - } + } #ifdef S_ISBLK else if (S_ISBLK(st.st_mode)) { t = "blockSpecial"; @@ -730,7 +730,7 @@ Sfile_type(obj, fname) #ifndef S_ISFIFO else if (S_ISFIFO(st.st_mode)) { t = "fifo"; - } + } #endif #ifdef S_ISLNK else if (S_ISLNK(st.st_mode)) { diff --git a/gc.c b/gc.c index af6741f6cae2d2..ec07c0fa95b176 100644 --- a/gc.c +++ b/gc.c @@ -3,7 +3,7 @@ gc.c - $Author: matz $ - $Date: 1995/01/10 10:42:37 $ + $Date: 1995/01/12 08:54:47 $ created at: Tue Oct 5 09:44:46 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -164,7 +164,7 @@ rb_global_variable(var) Global_List = tmp; } -struct RVALUE { +typedef struct RVALUE { union { struct { UINT flag; /* always 0 for freed obj */ @@ -185,50 +185,53 @@ struct RVALUE { struct RCons cons; struct SCOPE scope; } as; -} *freelist = Qnil; +} RVALUE; -struct heap_block { - struct heap_block *next; - struct RVALUE *beg; - struct RVALUE *end; - struct RVALUE body[1]; -} *heap_link = Qnil; +RVALUE *freelist = Qnil; -#define SEG_SLOTS 10000 -#define SEG_SIZE (SEG_SLOTS*sizeof(struct RVALUE)) +#define HEAPS_INCREMENT 10 +static RVALUE **heaps; +static int heaps_length = 0; +static int heaps_used = 0; + +#define HEAP_SLOTS 10000 #define FREE_MIN 512 static void add_heap() { - struct heap_block *block; - struct RVALUE *p, *pend; - - block = (struct heap_block*)malloc(sizeof(*block) + SEG_SIZE); - if (block == Qnil) Fatal("can't alloc memory"); - block->next = heap_link; - block->beg = &block->body[0]; - block->end = block->beg + SEG_SLOTS; - p = block->beg; pend = block->end; + RVALUE *p, *pend; + + if (heaps_used == heaps_length) { + /* Realloc heaps */ + heaps_length += HEAPS_INCREMENT; + heaps = (heaps_used)? + (RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE)): + (RVALUE**)malloc(heaps_length*sizeof(RVALUE)); + if (heaps == Qnil) Fatal("can't alloc memory"); + } + + p = heaps[heaps_used++] = (RVALUE*)malloc(sizeof(RVALUE)*HEAP_SLOTS); + if (p == Qnil) Fatal("can't alloc memory"); + pend = p + HEAP_SLOTS; + while (p < pend) { p->as.free.flag = 0; p->as.free.next = freelist; freelist = p; p++; } - heap_link = block; } struct RBasic * newobj() { struct RBasic *obj; - if (heap_link == Qnil) add_heap(); if (freelist) { retry: obj = (struct RBasic*)freelist; freelist = freelist->as.free.next; - memset(obj, 0, sizeof(struct RVALUE)); + memset(obj, 0, sizeof(RVALUE)); return obj; } if (dont_gc) add_heap(); @@ -259,16 +262,17 @@ static VALUE *stack_start_ptr; static long looks_pointerp(p) - struct RVALUE *p; + register RVALUE *p; { - struct heap_block *heap = heap_link; - - if (FIXNUM_P(p)) return FALSE; - while (heap) { - if (heap->beg <= p && p < heap->end - && ((((char*)p)-((char*)heap->beg))%sizeof(struct RVALUE)) == 0) + register RVALUE *heap_org; + register long i, j, n; + + /* if p looks as a SCM pointer mark location */ + for (i=0; i < heaps_used; i++) { + heap_org = heaps[i]; + if (heap_org <= p && p < heap_org + HEAP_SLOTS + && ((((char*)p)-((char*)heap_org))%sizeof(RVALUE)) == 0) return TRUE; - heap = heap->next; } return FALSE; } @@ -349,11 +353,13 @@ gc_mark_maybe(obj) void gc_mark(obj) - register struct RVALUE *obj; + register RVALUE *obj; { - if (obj == Qnil) return; - if (FIXNUM_P(obj)) return; - if (obj->as.basic.flags & FL_MARK) return; + Top: + if (obj == Qnil) return; /* nil not marked */ + if (FIXNUM_P(obj)) return; /* fixnum not marked */ + if (obj->as.basic.flags == 0) return; /* free cell */ + if (obj->as.basic.flags & FL_MARK) return; /* marked */ obj->as.basic.flags |= FL_MARK; @@ -362,21 +368,34 @@ gc_mark(obj) case T_FIXNUM: Bug("gc_mark() called for broken object"); break; + + case T_NODE: + if (looks_pointerp(obj->as.node.u1.node)) { + gc_mark(obj->as.node.u1.node); + } + if (looks_pointerp(obj->as.node.u2.node)) { + gc_mark(obj->as.node.u2.node); + } + if (looks_pointerp(obj->as.node.u3.node)) { + obj = (RVALUE*)obj->as.node.u3.node; + goto Top; + } + return; /* no need to mark class. */ } + gc_mark(obj->as.basic.class); switch (obj->as.basic.flags & T_MASK) { case T_ICLASS: gc_mark(obj->as.class.super); - if (obj->as.class.c_tbl) mark_tbl(obj->as.class.c_tbl); + if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl); mark_tbl(obj->as.class.m_tbl); break; case T_CLASS: gc_mark(obj->as.class.super); case T_MODULE: - if (obj->as.class.c_tbl) mark_tbl(obj->as.class.c_tbl); mark_tbl(obj->as.class.m_tbl); - gc_mark(obj->as.basic.class); + if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl); break; case T_ARRAY: @@ -402,6 +421,9 @@ gc_mark(obj) break; case T_OBJECT: + if (obj->as.object.iv_tbl) mark_tbl(obj->as.object.iv_tbl); + break; + case T_REGEXP: case T_FLOAT: case T_BIGNUM: @@ -427,20 +449,12 @@ gc_mark(obj) case T_CONS: gc_mark(obj->as.cons.car); - gc_mark(obj->as.cons.cdr); - break; - - case T_NODE: - gc_mark_maybe(obj->as.node.u1.node); - gc_mark_maybe(obj->as.node.u2.node); - gc_mark_maybe(obj->as.node.u3.node); - return; /* no need to mark class & tbl */ + obj = (RVALUE*)obj->as.cons.cdr; + goto Top; default: Bug("gc_mark(): unknown data type %d", obj->as.basic.flags & T_MASK); } - if (obj->as.basic.iv_tbl) mark_tbl(obj->as.basic.iv_tbl); - gc_mark(obj->as.basic.class); } #define MIN_FREE_OBJ 512 @@ -450,19 +464,19 @@ static void obj_free(); static void gc_sweep() { - struct heap_block *heap = heap_link; int freed = 0; + int i; freelist = Qnil; - while (heap) { - struct RVALUE *p, *pend; - struct RVALUE *nfreelist; + for (i = 0; i < heaps_used; i++) { + RVALUE *p, *pend; + RVALUE *nfreelist; int n = 0; nfreelist = freelist; - p = heap->beg; pend = heap->end; + p = heaps[i]; pend = p + HEAP_SLOTS; + while (p < pend) { - if (!(p->as.basic.flags & FL_MARK)) { if (p->as.basic.flags) obj_free(p); p->as.free.flag = 0; @@ -470,31 +484,12 @@ gc_sweep() nfreelist = p; n++; } - RBASIC(p)->flags &= ~FL_MARK; + else + RBASIC(p)->flags &= ~FL_MARK; p++; } - if (n == SEG_SLOTS) { - struct heap_block *link = heap_link; - if (heap != link) { - while (link) { - if (link->next && link->next == heap) { - link->next = heap->next; - break; - } - link = link->next; - } - if (link == Qnil) { - Bug("non-existing heap at 0x%x", heap); - } - } - free(heap); - heap = link; - } - else { - freed += n; - freelist = nfreelist; - } - heap = heap->next; + freed += n; + freelist = nfreelist; } if (freed < FREE_MIN) { add_heap(); @@ -503,7 +498,7 @@ gc_sweep() static void obj_free(obj) - struct RVALUE *obj; + RVALUE *obj; { switch (obj->as.basic.flags & T_MASK) { case T_NIL: @@ -514,13 +509,13 @@ obj_free(obj) switch (obj->as.basic.flags & T_MASK) { case T_OBJECT: + if (obj->as.object.iv_tbl) st_free_table(obj->as.object.iv_tbl); break; case T_MODULE: case T_CLASS: rb_clear_cache2(obj); st_free_table(obj->as.class.m_tbl); - if (obj->as.class.c_tbl) - st_free_table(obj->as.class.c_tbl); + if (obj->as.object.iv_tbl) st_free_table(obj->as.object.iv_tbl); break; case T_STRING: if (obj->as.string.orig == Qnil) free(obj->as.string.ptr); @@ -570,7 +565,6 @@ obj_free(obj) default: Bug("gc_sweep(): unknown data type %d", obj->as.basic.flags & T_MASK); } - if (obj->as.basic.iv_tbl) st_free_table(obj->as.basic.iv_tbl); } void @@ -626,13 +620,21 @@ gc() dont_gc--; } -Init_stack() +void +init_stack() { VALUE start; stack_start_ptr = &start; } +void +init_heap() +{ + init_stack(); + add_heap(); +} + Init_GC() { M_GC = rb_define_module("GC"); diff --git a/getopt1.c b/getopt1.c index 7f824232d75a05..7a2bbae34486fe 100644 --- a/getopt1.c +++ b/getopt1.c @@ -56,7 +56,7 @@ getopt_long (argc, argv, options, long_options, opt_index) but does match a short option, it is parsed as a short option instead. */ -int +int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; diff --git a/io.c b/io.c index c0f246b60cbc12..288e86d4d90787 100644 --- a/io.c +++ b/io.c @@ -802,7 +802,7 @@ next_argv() next_p = 0; if (RARRAY(Argv)->len > 0) { filename = ary_shift(Argv); - fn = RSTRING(filename)->ptr; + fn = RSTRING(filename)->ptr; if (RSTRING(filename)->len == 1 && fn[0] == '-') { file = rb_stdin; if (inplace) { @@ -938,12 +938,12 @@ struct timeval *time_timeval(); #ifdef STDSTDIO # define READ_PENDING(fp) ((fp)->_cnt != 0) -#else +#else # ifdef __SLBF # define READ_PENDING(fp) ((fp)->_r > 0) # else # ifdef __linux__ -# ifdef _other_gbase +# ifdef _other_gbase # define READ_PENDING(fp) ((fp)->_IO_read_ptr < (fp)->_IO_read_end) # else # define READ_PENDING(fp) ((fp)->_gptr < (fp)->_egptr) @@ -1009,7 +1009,7 @@ Fselect(argc, argv, obj) FD_SET(fileno(fptr->f), wp); if (max > fileno(fptr->f)) max = fileno(fptr->f); if (fptr->f2) { - FD_SET(fileno(fptr->f2), wp); + FD_SET(fileno(fptr->f2), wp); if (max < fileno(fptr->f2)) max = fileno(fptr->f2); } } @@ -1026,7 +1026,7 @@ Fselect(argc, argv, obj) FD_SET(fileno(fptr->f), ep); if (max < fileno(fptr->f)) max = fileno(fptr->f); if (fptr->f2) { - FD_SET(fileno(fptr->f2), ep); + FD_SET(fileno(fptr->f2), ep); if (max > fileno(fptr->f2)) max = fileno(fptr->f2); } } diff --git a/missing/MANIFEST b/missing/MANIFEST new file mode 100644 index 00000000000000..52640c2720f8df --- /dev/null +++ b/missing/MANIFEST @@ -0,0 +1,10 @@ +MANIFEST +alloca.c +memmove.c +mkdir.c +strdup.c +strerror.c +strftime.c +strstr.c +strtol.c +strtoul.c diff --git a/node.h b/node.h index 9322417fa2eb68..8137995d7157a2 100644 --- a/node.h +++ b/node.h @@ -24,12 +24,12 @@ enum node_type { NODE_WHEN, NODE_WHILE, NODE_WHILE2, - NODE_EXNOT, NODE_ITER, NODE_FOR, NODE_PROT, NODE_AND, NODE_OR, + NODE_NOT, NODE_MASGN, NODE_LASGN, NODE_GASGN, @@ -181,13 +181,10 @@ typedef struct RNode { #define NEW_BLOCK(a) newnode(NODE_BLOCK,a,1,Qnil) #define NEW_IF(c,t,e) newnode(NODE_IF,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_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_ITER(v,i,b) newnode(NODE_ITER,v,b,i) #define NEW_PROT(b,ex,en) newnode(NODE_PROT,b,ex,en) @@ -204,6 +201,7 @@ typedef struct RNode { #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_NOT(a) newnode(NODE_NOT,Qnil,a,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)) diff --git a/numeric.c b/numeric.c index 5b88a354544958..cab3c69db394c0 100644 --- a/numeric.c +++ b/numeric.c @@ -332,7 +332,7 @@ static VALUE Fflo_eq(x, y) struct RFloat *x, *y; { - switch (TYPE(y)) { + switch (TYPE(y)) { case T_NIL: return Qnil; case T_FIXNUM: @@ -676,7 +676,7 @@ Ffix_equal(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - return (FIX2INT(x) == FIX2INT(y))?TRUE:FALSE; + return (FIX2INT(x) == FIX2INT(y))?TRUE:FALSE; } else if (NIL_P(y)) { return Qnil; @@ -692,7 +692,7 @@ Ffix_cmp(x, y) { if (FIXNUM_P(y)) { int a = FIX2INT(x), b = FIX2INT(y); - + if (a == b) return INT2FIX(0); if (a > b) return INT2FIX(1); return INT2FIX(-1); @@ -708,7 +708,7 @@ Ffix_gt(x, y) { if (FIXNUM_P(y)) { int a = FIX2INT(x), b = FIX2INT(y); - + if (a > b) return TRUE; return FALSE; } @@ -723,7 +723,7 @@ Ffix_ge(x, y) { if (FIXNUM_P(y)) { int a = FIX2INT(x), b = FIX2INT(y); - + if (a >= b) return TRUE; return FALSE; } @@ -738,7 +738,7 @@ Ffix_lt(x, y) { if (FIXNUM_P(y)) { int a = FIX2INT(x), b = FIX2INT(y); - + if (a < b) return TRUE; return FALSE; } @@ -753,7 +753,7 @@ Ffix_le(x, y) { if (FIXNUM_P(y)) { int a = FIX2INT(x), b = FIX2INT(y); - + if (a <= b) return TRUE; return FALSE; } diff --git a/object.c b/object.c index e71043fdde43f2..a35e683cdd4c3a 100644 --- a/object.c +++ b/object.c @@ -3,7 +3,7 @@ object.c - $Author: matz $ - $Date: 1995/01/10 10:42:44 $ + $Date: 1995/01/12 08:54:49 $ created at: Thu Jul 15 12:01:24 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -12,7 +12,6 @@ #include "ruby.h" #include "env.h" -#include "node.h" #include "st.h" #include @@ -31,6 +30,7 @@ VALUE obj_responds_to(); VALUE obj_alloc(); static ID eq, match; +static ID init_object; static VALUE P_true(obj) @@ -75,26 +75,6 @@ Fkrn_id(obj) return obj | FIXNUM_FLAG; } -static VALUE -Fkrn_noteq(obj, other) - VALUE obj, other; -{ - if (rb_equal(obj, other)) { - return FALSE; - } - return TRUE; -} - -static VALUE -Fkrn_nmatch(obj, other) - VALUE obj, other; -{ - if (rb_funcall(obj, match, 1, other)) { - return FALSE; - } - return TRUE; -} - static VALUE Fkrn_class(obj) struct RBasic *obj; @@ -145,7 +125,7 @@ obj_inspect(id, value, str) static VALUE Fobj_inspect(obj) - struct RBasic *obj; + struct RObject *obj; { VALUE str; char buf[256]; @@ -212,14 +192,21 @@ Fobj_clone(obj) Check_Type(obj, T_OBJECT); clone = obj_alloc(RBASIC(obj)->class); - if (RBASIC(obj)->iv_tbl) { - RBASIC(clone)->iv_tbl = st_copy(RBASIC(obj)->iv_tbl); + if (ROBJECT(obj)->iv_tbl) { + ROBJECT(clone)->iv_tbl = st_copy(ROBJECT(obj)->iv_tbl); } RBASIC(clone)->class = single_class_clone(RBASIC(obj)->class); return clone; } +static VALUE +Fobj_init_object(obj) + VALUE obj; +{ + return Qnil; +} + static VALUE Fnil_to_s(obj) VALUE obj; @@ -282,7 +269,10 @@ Fcls_new(argc, argv, class) VALUE *argv; VALUE class; { - return obj_alloc(class); + VALUE obj = obj_alloc(class); + + rb_funcall2(obj, init_object, argc, argv); + return obj; } static VALUE @@ -377,6 +367,13 @@ Fdo() return rb_yield(Qnil); } +Fforever() +{ + for (;;) { + rb_yield(Qnil); + } +} + VALUE TopSelf; VALUE TRUE = 1; @@ -424,16 +421,14 @@ Init_Object() * + All metaclasses are instances of the class `Class'. */ + rb_define_method(C_Kernel, "is_nil", P_false, 0); - rb_define_method(C_Kernel, "!", P_false, 0); rb_define_method(C_Kernel, "==", Fkrn_equal, 1); rb_define_alias(C_Kernel, "equal", "=="); rb_define_method(C_Kernel, "hash", Fkrn_id, 0); rb_define_method(C_Kernel, "id", Fkrn_id, 0); rb_define_method(C_Kernel, "class", Fkrn_class, 0); - rb_define_method(C_Kernel, "!=", Fkrn_noteq, 1); rb_define_alias(C_Kernel, "=~", "=="); - rb_define_method(C_Kernel, "!~", Fkrn_nmatch, 1); rb_define_method(C_Kernel, "to_a", Fkrn_to_a, 0); rb_define_method(C_Kernel, "to_s", Fkrn_to_s, 0); @@ -443,8 +438,11 @@ Init_Object() rb_define_alias(C_Kernel, "format", "sprintf"); rb_define_private_method(C_Kernel, "do", Fdo, 0); + rb_define_private_method(C_Kernel, "forever", Fforever, 0); - rb_define_method(C_Object, "_inspect", Fobj_inspect, 0); + rb_define_private_method(C_Object, "init_object", Fobj_init_object, -1); + + rb_define_method(C_Object, "clone", Fobj_clone, 0); rb_define_method(C_Object, "responds_to", obj_responds_to, 1); rb_define_method(C_Object, "is_member_of", obj_is_member_of, 1); @@ -465,7 +463,6 @@ Init_Object() rb_define_method(C_Nil, "class", Fnil_class, 0); rb_define_method(C_Nil, "is_nil", P_true, 0); - rb_define_method(C_Nil, "!", P_true, 0); /* default addition */ rb_define_method(C_Nil, "+", Fnil_plus, 1); @@ -475,7 +472,6 @@ Init_Object() rb_define_method(C_Data, "class", Fdata_class, 0); eq = rb_intern("=="); - match = rb_intern("=~"); Qself = TopSelf = obj_alloc(C_Object); rb_define_single_method(TopSelf, "to_s", Fmain_to_s, 0); @@ -484,5 +480,6 @@ Init_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); -} + init_object = rb_intern("init_object"); +} diff --git a/parse.y b/parse.y index c4148d88d3130f..7c84221c8c670a 100644 --- a/parse.y +++ b/parse.y @@ -3,7 +3,7 @@ parse.y - $Author: matz $ - $Date: 1995/01/10 10:42:45 $ + $Date: 1995/01/12 08:54:50 $ created at: Fri May 28 18:02:42 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -50,7 +50,7 @@ static enum lex_state { static ID cur_class = Qnil, cur_mid = Qnil; static int in_module, in_single; -static void value_expr(); +static int value_expr(); static NODE *cond(); static NODE *cond2(); @@ -96,8 +96,6 @@ static void setup_top_local(); ELSE CASE WHEN - UNLESS - UNTIL WHILE FOR IN @@ -120,9 +118,7 @@ static void setup_top_local(); _FILE_ _LINE_ IF_MOD - UNLESS_MOD WHILE_MOD - UNTIL_MOD ALIAS %token IDENTIFIER GVAR IVAR CONSTANT @@ -131,14 +127,14 @@ static void setup_top_local(); %type singleton inc_list %type literal numeric -%type compstmts stmts stmt stmt0 expr expr0 var_ref +%type compexpr exprs expr arg primary var_ref %type if_tail opt_else case_body cases resque ensure -%type call_args call_args0 args args2 array +%type call_args call_args0 args args2 opt_args %type f_arglist f_args assoc_list assocs assoc %type mlhs mlhs_head mlhs_tail lhs iter_var opt_iter_var %type superclass variable symbol %type fname op rest_arg -%type f_arg +%type f_arg %token UPLUS /* unary+ */ %token UMINUS /* unary- */ %token POW /* ** */ @@ -156,11 +152,13 @@ static void setup_top_local(); %token OP_ASGN /* +=, -= etc. */ %token ASSOC /* => */ %token LPAREN LBRACK LBRACE +%token SYMBEG /* * precedence table */ +%left IF_MOD WHILE_MOD %left OR %left AND %left YIELD RETURN FAIL @@ -186,91 +184,74 @@ program : { lex_state = EXPR_BEG; init_top_local(); } - compstmts + compexpr { eval_tree = block_append(eval_tree, $2); setup_top_local(); } -compstmts : stmts opt_term +compexpr : exprs opt_term -stmts : /* none */ +exprs : /* none */ { $$ = Qnil; } - | stmt - | stmts term stmt + | expr + | exprs term expr { $$ = block_append($1, $3); } - | stmts error + | exprs error { lex_state = EXPR_BEG; } - stmt + expr { yyerrok; $$ = block_append($1, $4); } -stmt : CLASS IDENTIFIER superclass +expr : mlhs '=' args2 { - if (cur_class || cur_mid || in_single) - Error("nested class definition"); - cur_class = $2; - push_local(); + value_expr($3); + $1->nd_value = $3; + $$ = $1; } - compstmts - END + | assocs { - $$ = NEW_CLASS($2, $5, $3); - pop_local(); - cur_class = Qnil; + $$ = NEW_HASH($1); } - | MODULE IDENTIFIER + | RETURN args2 { - if (cur_class != Qnil) - Error("nested module definition"); - cur_class = $2; - in_module = 1; - push_local(); + value_expr($2); + if (!cur_mid && !in_single) + Error("return appeared outside of method"); + $$ = NEW_RET($2); } - compstmts - END + | FAIL args2 { - $$ = NEW_MODULE($2, $4); - pop_local(); - cur_class = Qnil; - in_module = 0; + value_expr($2); + $$ = NEW_FAIL($2); } - | DEF fname + | YIELD args2 { - if (cur_mid || in_single) - Error("nested method definition"); - cur_mid = $2; - push_local(); + value_expr($2); + $$ = NEW_YIELD($2); } - f_arglist - compstmts - END + | IDENTIFIER call_args0 { - $$ = NEW_DEFN($2, NEW_RFUNC($4, $5), cur_class?0:1); - pop_local(); - cur_mid = Qnil; + $$ = NEW_CALL(Qnil, $1, $2); } - | DEF singleton '.' fname + | primary '.' IDENTIFIER call_args0 { - value_expr($2); - in_single++; - push_local(); + value_expr($1); + $$ = NEW_CALL($1, $3, $4); } - f_arglist - compstmts - END + | SUPER call_args0 { - $$ = NEW_DEFS($2, $4, NEW_RFUNC($6, $7)); - pop_local(); - in_single--; + if (!cur_mid && !in_single) + Error("super called outside of method"); + $$ = NEW_SUPER($2); } | UNDEF fname { @@ -286,100 +267,31 @@ stmt : CLASS IDENTIFIER superclass Error("include appeared in method definition"); $$ = $2; } - | stmt0 IF_MOD stmt0 + | expr IF_MOD expr { $$ = NEW_IF(cond($3), $1, Qnil); } - | stmt0 UNLESS_MOD stmt0 - { - $$ = NEW_UNLESS(cond($3), $1, Qnil); - } - | stmt0 WHILE_MOD stmt0 + | expr WHILE_MOD expr { $$ = NEW_WHILE2(cond($3), $1); } - | stmt0 UNTIL_MOD stmt0 - { - $$ = NEW_UNTIL2(cond($3), $1); - } - | stmt AND stmt + | expr AND expr { $$ = NEW_AND(cond($1), cond($3)); } - | stmt OR stmt + | expr OR expr { $$ = NEW_OR(cond($1), cond($3)); } - | 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 + | arg mlhs : mlhs_head { - $$ = NEW_MASGN(NEW_LIST($1),Qnil); + $$ = NEW_MASGN(NEW_LIST($1), Qnil); } | mlhs_head '*' lhs { - $$ = NEW_MASGN(NEW_LIST($1),$3); + $$ = NEW_MASGN(NEW_LIST($1), $3); } | mlhs_head mlhs_tail { @@ -390,18 +302,7 @@ mlhs : mlhs_head $$ = NEW_MASGN(list_concat(NEW_LIST($1),$2),$5); } -mlhs_head : variable comma - { - $$ = asignable($1, Qnil); - } - | expr0 '[' args rbracket comma - { - $$ = aryset($1, $3, Qnil); - } - | expr0 '.' IDENTIFIER comma - { - $$ = attrset($1, $3, Qnil); - } +mlhs_head : lhs comma mlhs_tail : lhs { @@ -416,24 +317,15 @@ lhs : variable { $$ = asignable($1, Qnil); } - | expr0 '[' args rbracket + | primary '[' opt_args rbracket { $$ = aryset($1, $3, Qnil); } - | expr0 '.' IDENTIFIER + | primary '.' IDENTIFIER { $$ = attrset($1, $3, Qnil); } -superclass : /* none */ - { - $$ = Qnil; - } - | ':' IDENTIFIER - { - $$ = $2; - } - inc_list : IDENTIFIER { $$ = NEW_INC($1); @@ -467,9 +359,7 @@ op : COLON2 { $$ = COLON2; } | '&' { $$ = '&'; } | CMP { $$ = CMP; } | EQ { $$ = EQ; } - | NEQ { $$ = NEQ; } | MATCH { $$ = MATCH; } - | NMATCH { $$ = NMATCH; } | '>' { $$ = '>'; } | GEQ { $$ = GEQ; } | '<' { $$ = '<'; } @@ -482,119 +372,26 @@ op : COLON2 { $$ = COLON2; } | '/' { $$ = '/'; } | '%' { $$ = '%'; } | POW { $$ = POW; } - | '!' { $$ = '!'; } | '~' { $$ = '~'; } | UPLUS { $$ = UMINUS; } | UMINUS { $$ = UPLUS; } | AREF { $$ = AREF; } | ASET { $$ = ASET; } -f_arglist : '(' f_args rparen - { - $$ = $2; - } - | term - { - $$ = NEW_ARGS(0, -1); - } - -f_args : /* no arg */ - { - $$ = NEW_ARGS(0, -1); - } - | f_arg - { - $$ = NEW_ARGS($1, -1); - } - | f_arg comma rest_arg - { - $$ = NEW_ARGS($1, $3); - } - | rest_arg - { - $$ = NEW_ARGS(Qnil, $1); - } - | f_arg error - { - lex_state = EXPR_BEG; - $$ = NEW_ARGS($1, -1); - } - | error - { - lex_state = EXPR_BEG; - $$ = NEW_ARGS(0, -1); - } - -f_arg : IDENTIFIER - { - if (!is_local_id($1)) - Error("formal argument must be local variable"); - local_cnt($1); - $$ = 1; - } - | f_arg comma IDENTIFIER - { - if (!is_local_id($3)) - Error("formal argument must be local variable"); - local_cnt($3); - $$ += 1; - } - -rest_arg : '*' IDENTIFIER - { - if (!is_local_id($2)) - Error("rest argument must be local variable"); - $$ = local_cnt($2); - } - -singleton : var_ref - { - if (nd_type($1) == NODE_SELF) { - $$ = NEW_SELF(); - } - else if (nd_type($1) == NODE_NIL) { - Error("Can't define single method for nil."); - $$ = Qnil; - } - else { - $$ = $1; - } - } - | LPAREN compstmts rparen - { - switch (nd_type($2)) { - case NODE_STR: - case NODE_STR2: - case NODE_XSTR: - case NODE_XSTR2: - case NODE_DREGX: - case NODE_DGLOB: - case NODE_LIT: - case NODE_ARRAY: - case NODE_ZARRAY: - Error("Can't define single method for literals."); - default: - break; - } - $$ = $2; - } - -expr : variable '=' expr +arg : variable '=' arg { value_expr($3); $$ = asignable($1, $3); } - | expr0 '[' args rbracket '=' expr + | primary '[' opt_args rbracket '=' arg { - value_expr($6); $$ = aryset($1, $3, $6); } - | expr0 '.' IDENTIFIER '=' expr + | primary '.' IDENTIFIER '=' arg { - value_expr($5); $$ = attrset($1, $3, $5); } - | variable OP_ASGN expr + | variable OP_ASGN arg { NODE *val; @@ -613,27 +410,31 @@ expr : variable '=' expr } $$ = asignable($1, call_op(val, $2, 1, $3)); } - | expr0 '[' args rbracket OP_ASGN expr + | primary '[' opt_args rbracket OP_ASGN arg { - $$ = NEW_OP_ASGN1($1,$5,list_concat(NEW_LIST($6),$3)); + NODE *args = NEW_LIST($6); + + if ($3) list_concat(args, $3); + $$ = NEW_OP_ASGN1($1, $5, args); } - | expr0 '.' IDENTIFIER OP_ASGN expr + | primary '.' IDENTIFIER OP_ASGN arg { $$ = NEW_OP_ASGN2($1, $4, $5); } - | expr DOT2 expr + | arg DOT2 arg { $$ = call_op($1, DOT2, 1, $3); } - | expr DOT3 expr + | arg DOT3 arg { $$ = NEW_DOT3(cond2($1), cond2($3)); } - | expr '+' expr + | arg '+' arg { $$ = Qnil; if ($1 && $3 - && (nd_type($3) == NODE_LIT || nd_type($3) == NODE_STR) + && (nd_type($3) == NODE_LIT + || nd_type($3) == NODE_STR) && nd_type($1) == NODE_CALL && $1->nd_mid == '+') { if ($1->nd_args->nd_head == Qnil) Bug("bad operand for `+'"); @@ -648,87 +449,87 @@ expr : variable '=' expr $$ = call_op($1, '+', 1, $3); } } - | expr '-' expr + | arg '-' arg { $$ = call_op($1, '-', 1, $3); } - | expr '*' expr + | arg '*' arg { $$ = call_op($1, '*', 1, $3); } - | expr '/' expr + | arg '/' arg { $$ = call_op($1, '/', 1, $3); } - | expr '%' expr + | arg '%' arg { $$ = call_op($1, '%', 1, $3); } - | expr POW expr + | arg POW arg { $$ = call_op($1, POW, 1, $3); } - | UPLUS expr + | UPLUS arg { $$ = call_op($2, UPLUS, 0); } - | UMINUS expr + | UMINUS arg { $$ = call_op($2, UMINUS, 0); } - | expr '|' expr + | arg '|' arg { $$ = call_op($1, '|', 1, $3); } - | expr '^' expr + | arg '^' arg { $$ = call_op($1, '^', 1, $3); } - | expr '&' expr + | arg '&' arg { $$ = call_op($1, '&', 1, $3); } - | expr CMP expr + | arg CMP arg { $$ = call_op($1, CMP, 1, $3); } - | expr '>' expr + | arg '>' arg { $$ = call_op($1, '>', 1, $3); } - | expr GEQ expr + | arg GEQ arg { $$ = call_op($1, GEQ, 1, $3); } - | expr '<' expr + | arg '<' arg { $$ = call_op($1, '<', 1, $3); } - | expr LEQ expr + | arg LEQ arg { $$ = call_op($1, LEQ, 1, $3); } - | expr EQ expr + | arg EQ arg { $$ = call_op($1, EQ, 1, $3); } - | expr NEQ expr + | arg NEQ arg { - $$ = call_op($1, NEQ, 1, $3); + $$ = NEW_NOT(call_op($1, EQ, 1, $3)); } - | expr MATCH expr + | arg MATCH arg { $$ = NEW_CALL($1, MATCH, NEW_LIST($3)); } - | expr NMATCH expr + | arg NMATCH arg { - $$ = NEW_CALL($1, NMATCH, NEW_LIST($3)); + $$ = NEW_NOT(NEW_CALL($1, MATCH, NEW_LIST($3))); } - | '!' expr + | '!' arg { - $$ = call_op($2, '!', 0); + $$ = NEW_NOT(cond($2)); } - | '~' expr + | '~' arg { if ($2 && (nd_type($2) == NODE_STR @@ -741,27 +542,27 @@ expr : variable '=' expr $$ = call_op($2, '~', 0); } } - | expr LSHFT expr + | arg LSHFT arg { $$ = call_op($1, LSHFT, 1, $3); } - | expr RSHFT expr + | arg RSHFT arg { $$ = call_op($1, RSHFT, 1, $3); } - | expr COLON2 expr + | arg COLON2 arg { $$ = call_op($1, COLON2, 1, $3); } - | expr ANDOP expr + | arg ANDOP arg { $$ = NEW_AND(cond($1), cond($3)); } - | expr OROP expr + | arg OROP arg { $$ = NEW_OR(cond($1), cond($3)); } - |expr0 + | primary { $$ = $1; } @@ -771,23 +572,37 @@ call_args : /* none */ $$ = Qnil; } | call_args0 - | '*' expr + | '*' arg { $$ = $2; } call_args0 : args - | args comma '*' expr + | assocs + { + $$ = NEW_LIST(NEW_HASH($1)); + } + | args comma assocs + { + $$ = list_append($1, NEW_HASH($3)); + } + | args comma '*' arg { $$ = call_op($1, '+', 1, $4); } -args : expr +opt_args : /* none */ + { + $$ = Qnil; + } + | args + +args : arg { value_expr($1); $$ = NEW_LIST($1); } - | args comma expr + | args comma arg { value_expr($3); $$ = list_append($1, $3); @@ -803,7 +618,7 @@ args2 : args } } -expr0 : literal +primary : literal { $$ = NEW_LIT($1); } @@ -820,10 +635,6 @@ expr0 : literal | DREGEXP | DGLOB | var_ref - | IDENTIFIER '(' call_args rparen - { - $$ = NEW_CALL(Qnil, $1, $3); - } | SUPER '(' call_args rparen { if (!cur_mid && !in_single) @@ -836,13 +647,12 @@ expr0 : literal Error("super called outside of method"); $$ = NEW_ZSUPER(); } - - | expr0 '[' args rbracket + | primary '[' opt_args rbracket { value_expr($1); $$ = NEW_CALL($1, AREF, $3); } - | LBRACK array rbracket + | LBRACK opt_args rbracket { if ($2 == Qnil) $$ = NEW_ZARRAY(); /* zero length array*/ @@ -854,8 +664,33 @@ expr0 : literal { $$ = NEW_HASH($2); } + | REDO + { + $$ = NEW_REDO(); + } + | BREAK + { + $$ = NEW_BREAK(); + } + | CONTINUE + { + $$ = NEW_CONT(); + } + | RETRY + { + $$ = NEW_RETRY(); + } + | RETURN + { + if (!cur_mid && !in_single) + Error("return appeared outside of method"); + $$ = NEW_RET(Qnil); + } | FAIL '(' args2 ')' { + if (nd_type($3) == NODE_ARRAY) { + Error("wrong number of argument to fail(0 or 1)"); + } value_expr($3); $$ = NEW_FAIL($3); } @@ -880,7 +715,7 @@ expr0 : literal { $$ = NEW_YIELD(Qnil); } - | expr0 '{' opt_iter_var '|' compstmts rbrace + | primary '{' opt_iter_var '|' compexpr rbrace { if (nd_type($1) == NODE_LVAR || nd_type($1) == NODE_MVAR) { @@ -888,52 +723,47 @@ expr0 : literal } $$ = NEW_ITER($3, $1, $5); } - | expr0 '.' IDENTIFIER '(' call_args rparen + | IDENTIFIER '(' call_args rparen + { + $$ = NEW_CALL(Qnil, $1, $3); + } + | primary '.' IDENTIFIER '(' call_args rparen { value_expr($1); $$ = NEW_CALL($1, $3, $5); } - | expr0 '.' IDENTIFIER + | primary '.' IDENTIFIER { value_expr($1); $$ = NEW_CALL($1, $3, Qnil); } - | IF stmt0 then - compstmts + | IF expr then + compexpr if_tail END { $$ = NEW_IF(cond($2), $4, $5); } - | UNLESS stmt0 then - compstmts opt_else END - { - $$ = NEW_UNLESS(cond($2), $4, $5); - } - | WHILE stmt0 term compstmts END + | WHILE expr term compexpr END { $$ = NEW_WHILE(cond($2), $4); } - | UNTIL stmt0 term compstmts END - { - $$ = NEW_UNTIL(cond($2), $4); - } - | CASE compstmts + | CASE compexpr case_body END { value_expr($2); $$ = NEW_CASE($2, $3); } - | FOR iter_var IN stmt0 term - compstmts + | FOR iter_var IN expr term + compexpr END { value_expr($4); $$ = NEW_FOR($2, $4, $6); } | PROTECT - compstmts + compexpr resque ensure END @@ -946,18 +776,77 @@ expr0 : literal $$ = NEW_PROT($2, $3, $4); } } - | LPAREN compstmts rparen + | LPAREN compexpr rparen { $$ = $2; } + | CLASS IDENTIFIER superclass + { + if (cur_class || cur_mid || in_single) + Error("nested class definition"); + cur_class = $2; + push_local(); + } + compexpr + END + { + $$ = NEW_CLASS($2, $5, $3); + pop_local(); + cur_class = Qnil; + } + | MODULE IDENTIFIER + { + if (cur_class != Qnil) + Error("nested module definition"); + cur_class = $2; + in_module = 1; + push_local(); + } + compexpr + END + { + $$ = NEW_MODULE($2, $4); + pop_local(); + cur_class = Qnil; + in_module = 0; + } + | DEF fname + { + if (cur_mid || in_single) + Error("nested method definition"); + cur_mid = $2; + push_local(); + } + f_arglist + compexpr + END + { + $$ = NEW_DEFN($2, NEW_RFUNC($4, $5), cur_class?0:1); + pop_local(); + cur_mid = Qnil; + } + | DEF singleton '.' fname + { + value_expr($2); + in_single++; + push_local(); + } + f_arglist + compexpr + END + { + $$ = NEW_DEFS($2, $4, NEW_RFUNC($6, $7)); + pop_local(); + in_single--; + } then : term | THEN | term THEN if_tail : opt_else - | ELSIF stmt0 then - compstmts + | ELSIF expr then + compexpr if_tail { $$ = NEW_IF(cond($2), $4, $5); @@ -967,7 +856,7 @@ opt_else : /* none */ { $$ = Qnil; } - | ELSE compstmts + | ELSE compexpr { $$ = $2; } @@ -982,7 +871,7 @@ opt_iter_var : /* none */ | iter_var case_body : WHEN args then - compstmts + compexpr cases { $$ = NEW_WHEN($2, $4, $5); @@ -990,7 +879,7 @@ case_body : WHEN args then cases : opt_else | WHEN args then - compstmts + compexpr cases { $$ = NEW_WHEN($2, $4, $5); @@ -1000,7 +889,7 @@ resque : /* none */ { $$ = Qnil; } - | RESQUE compstmts + | RESQUE compexpr { if ($2 == Qnil) $$ = (NODE*)1; @@ -1012,26 +901,19 @@ ensure : /* none */ { $$ = Qnil; } - | ENSURE compstmts + | ENSURE compexpr { $$ = $2; } -array : /* none */ - { - $$ = Qnil; - } - | args - literal : numeric - | '\\' symbol + | SYMBEG symbol { $$ = INT2FIX($2); } | REGEXP | GLOB - symbol : fname | IVAR | GVAR @@ -1058,11 +940,121 @@ var_ref : variable $$ = gettable($1); } +superclass : term + { + $$ = Qnil; + } + | colon + { + lex_state = EXPR_BEG; + } + IDENTIFIER + { + $$ = $3; + } + +f_arglist : '(' f_args rparen + { + $$ = $2; + } + | term + { + $$ = NEW_ARGS(0, -1); + } + +f_args : /* no arg */ + { + $$ = NEW_ARGS(0, -1); + } + | f_arg + { + $$ = NEW_ARGS($1, -1); + } + | f_arg comma rest_arg + { + $$ = NEW_ARGS($1, $3); + } + | rest_arg + { + $$ = NEW_ARGS(Qnil, $1); + } + | f_arg error + { + lex_state = EXPR_BEG; + $$ = NEW_ARGS($1, -1); + } + | error + { + lex_state = EXPR_BEG; + $$ = NEW_ARGS(0, -1); + } + +f_arg : IDENTIFIER + { + if (!is_local_id($1)) + Error("formal argument must be local variable"); + local_cnt($1); + $$ = 1; + } + | f_arg comma IDENTIFIER + { + if (!is_local_id($3)) + Error("formal argument must be local variable"); + local_cnt($3); + $$ += 1; + } + +rest_arg : '*' IDENTIFIER + { + if (!is_local_id($2)) + Error("rest argument must be local variable"); + $$ = local_cnt($2); + } + +singleton : var_ref + { + if (nd_type($1) == NODE_SELF) { + $$ = NEW_SELF(); + } + else if (nd_type($1) == NODE_NIL) { + Error("Can't define single method for nil."); + $$ = Qnil; + } + else { + $$ = $1; + } + } + | LPAREN compexpr rparen + { + switch (nd_type($2)) { + case NODE_STR: + case NODE_STR2: + case NODE_XSTR: + case NODE_XSTR2: + case NODE_DREGX: + case NODE_DGLOB: + case NODE_LIT: + case NODE_ARRAY: + case NODE_ZARRAY: + Error("Can't define single method for literals."); + default: + break; + } + $$ = $2; + } + assoc_list : /* none */ { $$ = Qnil; } | assocs + | args + { + if ($1->nd_alen%2 != 0) { + Error("odd number list for Dict"); + } + $$ = $1; + } assocs : assoc | assocs comma assoc @@ -1070,12 +1062,11 @@ assocs : assoc $$ = list_concat($1, $3); } -assoc : expr ASSOC expr +assoc : arg ASSOC arg { $$ = list_append(NEW_LIST($1), $3); } - opt_term : /* none */ | term @@ -1085,6 +1076,9 @@ term : sc sc : ';' { yyerrok; } nl : '\n' { yyerrok; } +colon : ':' + | SYMBEG + rparen : ')' { yyerrok; } rbracket : ']' { yyerrok; } rbrace : '}' { yyerrok; } @@ -1196,10 +1190,6 @@ parse_regx() else if (in_brack && c == 'b') { tokadd('\b'); } - else if (isdigit(c)) { - tokadd('\\'); - tokadd(c); - } else { pushback(); read_escape(LEAVE_BS); @@ -1348,8 +1338,6 @@ static struct kwtable { "super", SUPER, EXPR_END, "then", THEN, EXPR_BEG, "undef", UNDEF, EXPR_FNAME, - "unless", UNLESS, EXPR_BEG, - "until", UNTIL, EXPR_BEG, "when", WHEN, EXPR_BEG, "while", WHILE, EXPR_BEG, "yield", YIELD, EXPR_END, @@ -1406,13 +1394,6 @@ 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; @@ -1737,12 +1718,15 @@ retry: return c; case ':': - lex_state = EXPR_BEG; - if (nextc() == ':') { + c = nextc(); + if (c == ':') { + lex_state = EXPR_BEG; return COLON2; } pushback(); - return ':'; + if (isspace(c)) + return ':'; + return SYMBEG; case '/': if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { @@ -1786,7 +1770,6 @@ retry: return c; case '[': - if (lex_state == EXPR_BEG || lex_state == EXPR_MID) c = LBRACK; else if (lex_state == EXPR_FNAME) { @@ -1811,8 +1794,10 @@ retry: case '\\': c = nextc(); - if (c == '\n') goto retry; /* skip \\n */ - lex_state = EXPR_FNAME; + if (c == '\n') { + sourceline++; + goto retry; /* skip \\n */ + } pushback(); return '\\'; @@ -1910,9 +1895,7 @@ retry: 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; } @@ -2444,6 +2427,7 @@ aryset(recv, idx, val) NODE *recv, *idx, *val; { value_expr(recv); + value_expr(val); return NEW_CALL(recv, ASET, list_append(idx, val)); } @@ -2453,18 +2437,19 @@ attrset(recv, id, val) ID id; { value_expr(recv); + value_expr(val); id &= ~ID_SCOPE_MASK; id |= ID_ATTRSET; - return NEW_CALL(recv, id, NEW_ARRAY(val)); + return NEW_CALL(recv, id, NEW_LIST(val)); } -static void +static int value_expr(node) NODE *node; { - if (node == Qnil) return; + if (node == Qnil) return TRUE; switch (nd_type(node)) { case NODE_RETURN: @@ -2472,25 +2457,29 @@ value_expr(node) case NODE_BREAK: case NODE_REDO: case NODE_RETRY: + case NODE_FAIL: case NODE_WHILE: case NODE_WHILE2: case NODE_INC: case NODE_CLASS: case NODE_MODULE: + case NODE_DEFN: + case NODE_DEFS: Error("void value expression"); + return FALSE; break; case NODE_BLOCK: while (node->nd_next) { node = node->nd_next; } - if (node) { - value_expr(node->nd_head); - } - break; + return value_expr(node->nd_head); + + case NODE_IF: + return value_expr(node->nd_body) && value_expr(node->nd_else); default: - break; + return TRUE; } } @@ -2635,8 +2624,8 @@ init_top_local() lvtbl->cnt = 0; } if (lvtbl->cnt > 0) { - lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt); - MEMCPY(lvtbl->tbl, the_scope->local_tbl, VALUE, lvtbl->cnt); + lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt+1); + MEMCPY(lvtbl->tbl, the_scope->local_tbl, ID, lvtbl->cnt); } else { lvtbl->tbl = Qnil; @@ -2892,7 +2881,7 @@ rb_class2name(class) Fail("0x%x is not a class/module", class); } - if (FL_TEST(class, FL_SINGLE)) { + while (FL_TEST(class, FL_SINGLE)) { class = (struct RClass*)class->super; } @@ -2906,3 +2895,23 @@ rb_class2name(class) } Bug("class 0x%x not named", class); } + +static int +const_check(id, val, class) + ID id; + VALUE val; + struct RClass *class; +{ + if (is_const_id(id) && rb_const_bound(class, id)) { + Warning("constant redefined for %s", rb_class2name(class)); + return ST_STOP; + } + return ST_CONTINUE; +} + +void +rb_const_check(class, module) + struct RClass *class, *module; +{ + st_foreach(module->iv_tbl, const_check, class); +} diff --git a/process.c b/process.c index f6de89d8553aca..e8bcaaa3a6df1a 100644 --- a/process.c +++ b/process.c @@ -507,7 +507,7 @@ Init_process() rb_define_module_function(M_Process, "getpriority", Fproc_getpriority, 2); rb_define_module_function(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)); rb_define_const(M_Process, "%PRIO_USER", INT2FIX(PRIO_USER)); diff --git a/range.c b/range.c index 6274170522ca90..97e68bdf803dde 100644 --- a/range.c +++ b/range.c @@ -15,7 +15,7 @@ VALUE M_Comparable; VALUE C_Range; -static ID next, eq; +static ID next; static VALUE Srng_new(class, start, end) @@ -156,6 +156,5 @@ Init_Range() rb_define_method(C_Range, "end", Frng_end, 0); rb_define_method(C_Range, "to_s", Frng_to_s, 0); - eq = rb_intern("=="); next = rb_intern("next"); } diff --git a/re.c b/re.c index cdff895aa2e013..d631d0c165c91b 100644 --- a/re.c +++ b/re.c @@ -76,7 +76,7 @@ str_cicmp(str1, str2) len = min(str1->len, str2->len); p1 = str1->ptr; p2 = str2->ptr; - + for (i = 0; i < len; i++, p1++, p2++) { if (casetable[*p1] != casetable[*p2]) return casetable[*p1] - casetable[*p2]; @@ -97,7 +97,7 @@ int len; /* Build a copy of the string (in dest) with the escaped characters translated, and generate the regex - from that. + from that. */ rp = ALLOC(Regexp); @@ -194,7 +194,7 @@ re_match_post() struct match *match; if (last_match.regs.start[0] == -1) return Qnil; - return str_new(last_match.ptr+last_match.regs.end[0], + return str_new(last_match.ptr+last_match.regs.end[0], last_match.len-last_match.regs.end[0]); } @@ -400,6 +400,36 @@ Sreg_new(argc, argv, self) return Qnil; } +static VALUE +Sreg_quote(re, str) + VALUE re; + struct RString *str; +{ + char *s, *send, *t; + char *tmp; + + Check_Type(str, T_STRING); + + tmp = ALLOCA_N(char, str->len*2); + + s = str->ptr; send = s + str->len; + t = tmp; + + for (; s != send; s++) { + if (*s == '[' || *s == ']' + || *s == '{' || *s == '}' + || *s == '(' || *s == ')' + || *s == '*' || *s == '.' || *s == '\\' + || *s == '?' || *s == '+' + || *s == '^' || *s == '$') { + *t++ = '\\'; + } + *t++ = *s; + } + + return str_new(tmp, t - tmp); +} + static VALUE Freg_clone(re) struct RRegexp *re; @@ -549,6 +579,7 @@ Init_Regexp() C_Regexp = rb_define_class("Regexp", C_Object); rb_define_single_method(C_Regexp, "new", Sreg_new, -1); rb_define_single_method(C_Regexp, "compile", Sreg_new, -1); + rb_define_single_method(C_Regexp, "quote", Sreg_quote, 1); rb_define_method(C_Regexp, "=~", Freg_match, 1); rb_define_method(C_Regexp, "~", Freg_match2, 0); diff --git a/ruby.c b/ruby.c index e22f0b15ce0171..8029a3e026d94c 100644 --- a/ruby.c +++ b/ruby.c @@ -262,7 +262,7 @@ readin(fd, fname) if (xflag) { char *s = p; - *pend = '\0'; + *pend = '\0'; xflag = FALSE; while (p < pend) { while (s < pend && *s != '\n') s++; diff --git a/ruby.h b/ruby.h index 086c112084fbec..b52bd3c46d1e1c 100644 --- a/ruby.h +++ b/ruby.h @@ -1,13 +1,13 @@ /************************************************ - + ruby.h - - + $Author: matz $ - $Date: 1995/01/10 10:42:52 $ + $Date: 1995/01/12 08:54:52 $ created at: Thu Jun 10 14:26:32 JST 1993 - + Copyright (C) 1994 Yukihiro Matsumoto - + *************************************************/ #ifndef RUBY_H @@ -100,13 +100,12 @@ extern VALUE C_Data; #define T_DICT 0x0a #define T_STRUCT 0x0b #define T_BIGNUM 0x0c - -#define T_NODE 0x0d -#define T_SCOPE 0x0e #define T_CONS 0x0f - #define T_DATA 0x10 +#define T_SCOPE 0xfe +#define T_NODE 0xff + #define T_MASK 0xff #define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK) @@ -128,17 +127,17 @@ int num2int(); struct RBasic { UINT flags; VALUE class; - struct st_table *iv_tbl; }; struct RObject { struct RBasic basic; + struct st_table *iv_tbl; }; struct RClass { struct RBasic basic; + struct st_table *iv_tbl; struct st_table *m_tbl; - struct st_table *c_tbl; struct RClass *super; }; @@ -181,7 +180,7 @@ struct RData { #define DATA_PTR(dta) (RDATA(dta)->data) -VALUE data_new(); +VALUE data_new(); VALUE rb_ivar_get_1(); VALUE rb_ivar_set_1(); @@ -222,6 +221,9 @@ struct RCons { VALUE car, cdr; }; +#define CAR(c) (RCONS(c)->car) +#define CDR(c) (RCONS(c)->cdr) + #define R_CAST(st) (struct st*) #define RBASIC(obj) (R_CAST(RBasic)(obj)) #define ROBJECT(obj) (R_CAST(RObject)(obj)) @@ -291,7 +293,9 @@ void rb_define_attr(); ID rb_intern(); char *rb_id2name(); +VALUE rb_eval_string(); VALUE rb_funcall(); +VALUE rb_funcall2(); int rb_scan_args(); VALUE rb_yield(); diff --git a/sample/Artistic b/sample/Artistic new file mode 100644 index 00000000000000..fbf798977589c2 --- /dev/null +++ b/sample/Artistic @@ -0,0 +1,117 @@ + + + + + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard executables + non-standard names, and clearly documenting the differences in manual + pages (or equivalent), together with instructions on where to get + the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this Package. +You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whomever generated +them, and may be sold commercially, and may be aggregated with this +Package. + +7. C subroutines supplied by you and linked into this Package in order +to emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End diff --git a/sample/MANIFEST b/sample/MANIFEST new file mode 100644 index 00000000000000..c54adf31ef592a --- /dev/null +++ b/sample/MANIFEST @@ -0,0 +1,63 @@ +MANIFEST +Artistic +aset.rb +attr.rb +biorhythm.rb +blk.rb +case.rb +cat.rb +cat2.rb +cbreak.rb +clnt.rb +clone.rb +const.rb +dbm.rb +dir.rb +evaldef.rb +export.rb +exyacc.rb +fib.awk +fib.pl +fib.rb +fib.scm +freq.rb +fullpath.pl +fullpath.rb +gctest.rb +gctest2.rb +getopts.rb +getopts.test +hash.rb +io.rb +less.rb +list.rb +list2.rb +list3.rb +math.rb +mpart.rb +occur.pl +occur.rb +occur2.rb +opt_s.rb +opt_x.rb +parsearg.rb +rcs.awk +rcs.dat +rcs.rb +ruby-mode.el +samp.rb +sieve.rb +split.rb +struct.rb +svr.rb +system.rb +t1.rb +t2.rb +test.rb +time.rb +trap.pl +trap.rb +trojan.pl +trojan.rb +tt.rb +uumerge.rb diff --git a/sample/biorhythm.rb b/sample/biorhythm.rb new file mode 100644 index 00000000000000..eb14ca736544bb --- /dev/null +++ b/sample/biorhythm.rb @@ -0,0 +1,201 @@ +#!/mp/free/bin/ruby +# +# biorhythm.rb - +# $Release Version: $ +# $Revision: 1.6 $ +# $Date: 1994/02/24 10:23:34 $ +# by Yasuo OHBA(STAFS Development Room) +# +# -- +# +# +# + +$RCS_ID="$Header: /var/ohba/RCS/biorhythm.rb,v 1.6 1994/02/24 10:23:34 ohba Exp ohba $" + +include Math +load("parsearg.rb") + +$wochentag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ] +monatstag1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] +monatstag2 = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + +def usage() + print("Usage:\n") + print("biorhythm.rb [options]\n") + print(" options...\n") + print(" -D YYYYMMDD(birthday) : すべて default 値を使う. \n") + print(" --sdate | --date YYYYMMDD : system date もしくは指定した日付を使う.\n") + print(" --birthday YYYYMMDD : 誕生日の指定をする. \n") + print(" -v | -g : Values or Graph の指定. \n") + print(" --days DAYS : 期間の指定をする(Graph の時のみ有効). \n") + print(" --help : help\n") +end +$USAGE = 'usage' + +def leapyear(y) + ta = 0 + if ((y % 4.0) == 0); ta = 1; end + if ((y % 100.0) == 0); ta = 0; end + if ((y % 400.0) == 0); ta = 1; end + return ta +end + +def bcalc(tt, m, j) + ta = 0 + if (m <= 2) + ta = (m - 1) * 31 + else + ta = leapyear(j) + ta = ta + ((306 * m - 324) / 10.0).to_i + 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 + tt + return ta +end + +def printHeader(tg, mg, jg, gtag, tage) + print("\n") + print(" Biorhythm\n") + print(" =========\n") + print("\n") + printf("The birthday %04d.%02d.%02d is a %s\n", jg, mg, tg, $wochentag[gtag]) + printf("Age in days: [%d]\n", tage) +end + +def getPosition(z) + pi = 3.14159265 + $phys = (50.0 * (1.0 + sin((z / 23.0 - (z / 23)) * 360.0 * pi / 180.0))).to_i + $emot = (50.0 * (1.0 + sin((z / 28.0 - (z / 28)) * 360.0 * pi / 180.0))).to_i + $geist =(50.0 * (1.0 + sin((z / 33.0 - (z / 33)) * 360.0 * pi / 180.0))).to_i +end + +# +# main program +# +parseArgs(0, nil, "vg", "D:", "sdate", "date:", "birthday:", "days:") + +printf($stderr, "\n") +printf($stderr, "Biorhythm (c) 1987-1994 V3.0\n") +printf($stderr, "\n") +if ($OPT_D) + dtmp = Time.now.strftime("%Y%m%d") + jh = dtmp[0,4].to_i + mh = dtmp[4,2].to_i + th = dtmp[6,2].to_i + dtmp = $OPT_D + jg = dtmp[0,4].to_i + mg = dtmp[4,2].to_i + tg = dtmp[6,2].to_i + gtag = bcalc(tg, mg, jg) % 7 + ausgabeart = "g" +else + if ($OPT_birthday) + dtmp = $OPT_birthday + else + printf($stderr, "Birthday (YYYYMMDD) : ") + dtmp = $stdin.gets.chop + end + if (dtmp.length != 8) + printf($stderr, "BAD Input Birthday!!\n") + exit() + end + jg = dtmp[0,4].to_i + mg = dtmp[4,2].to_i + tg = dtmp[6,2].to_i + + gtag = bcalc(tg, mg, jg) % 7 + + if ($OPT_sdate) + dtmp = Time.now.strftime("%Y%m%d") + elsif ($OPT_date) + dtmp = $OPT_date + else + printf($stderr, "Date [ for Systemdate] (YYYYMMDD) : ") + dtmp = $stdin.gets.chop + end + if (dtmp.length != 8) + dtmp = Time.now.strftime("%Y%m%d") + end + jh = dtmp[0,4].to_i + mh = dtmp[4,2].to_i + th = dtmp[6,2].to_i + + if ($OPT_v) + ausgabeart = "v" + elsif ($OPT_g) + ausgabeart = "g" + else + printf($stderr, "Values for today or Graph (v/g) [default g] : ") + ausgabeart = $stdin.gets.chop + end +end +if (ausgabeart == "v") + tag = bcalc(tg, mg, jg) + tah = bcalc(th, mh, jh) + tage = tah - tag + printHeader(tg, mg, jg, gtag, tage) + print("\n") + + getPosition(tage) + printf("Biorhythm: %04d.%02d.%02d\n", jh, mh, th) + printf("Physical: %d%%\n", $phys) + printf("Emotional: %d%%\n", $emot) + printf("Mental: %d%%\n", $geist) + print("\n") +else + if ($OPT_days) + ktage = $OPT_days.to_i + else + if ($OPT_D) + ktage = 9 + else + printf($stderr, "Graph for how many days [default 10] : ") + ktage = $stdin.gets.chop + if (ktage == "") + ktage = 9 + else + ktage = ktage.to_i - 1 + end + end + end + tag = bcalc(tg, mg, jg) + tah = bcalc(th, mh, jh) + tage = tah - tag + printHeader(tg, mg, jg, gtag, tage) + print(" P=physical, E=emotional, M=mental\n") + print(" -------------------------+-------------------------\n") + print(" Bad Condition | Good Condition\n") + print(" -------------------------+-------------------------\n") + + for z in tage..(tage + ktage) + getPosition(z) + + printf("%04d.%02d.%02d : ", jh, mh, th) + p = ($phys / 2.0 + 0.5).to_i + e = ($emot / 2.0 + 0.5).to_i + g = ($geist / 2.0 + 0.5).to_i + graph = "." * 51 + graph[25] = ?| + graph[p] = ?P + graph[e] = ?E + graph[g] = ?M + print(graph, "\n") + th = th + 1 + if (leapyear(jh) == 0) + $MONATSTAG = monatstag1 + else + $MONATSTAG = monatstag2 + end + if (th > $MONATSTAG[mh - 1]) + mh = mh + 1 + th = 1 + end + if (mh > 12) + jh = jh + 1 + mh = 1 + end + end + print(" -------------------------+-------------------------\n\n") +end diff --git a/sample/blk.rb b/sample/blk.rb index 4e618bce2d2943..12d1038fd09c70 100644 --- a/sample/blk.rb +++ b/sample/blk.rb @@ -2,8 +2,8 @@ def foo() $block = Block.new end -foo(){i | print "i = ", i, "\n"} -$block.do(2) +foo(){i| print "i = ", i, "\n"} +$block.call(2) -foo(){i | print "i*2 = ", i*2, "\n"} -$block.do(2) +foo(){i| print "i*2 = ", i*2, "\n"} +$block.call(2) diff --git a/sample/clone.rb b/sample/clone.rb index 69d2f1d52b82f4..e7d6b00a314982 100644 --- a/sample/clone.rb +++ b/sample/clone.rb @@ -3,7 +3,7 @@ # test2 # test # test -# clone.rb:13: undefined method `test2' for "#"(Object) +# clone.rb:18: undefined method `test2' for "#"(Object) foo = Object.new def foo.test print("test\n") diff --git a/sample/dir.rb b/sample/dir.rb index f269c568bab0f8..3349dc7b6d457c 100644 --- a/sample/dir.rb +++ b/sample/dir.rb @@ -3,7 +3,7 @@ dirp = Dir.open(".") dirp.rewind for f in dirp - unless (~/^\./ || ~/~$/ || ~/\.o/) + if !(~/^\./ || ~/~$/ || ~/\.o/) print f, "\n" end end diff --git a/sample/evaldef.rb b/sample/evaldef.rb index 021f65800a3f1e..1d77a3c0080a3e 100644 --- a/sample/evaldef.rb +++ b/sample/evaldef.rb @@ -1,7 +1,7 @@ # method definition by eval() # output: # bar -# (eval):21: method `baz' not available for "#"(foo) +# (eval):26: method `baz' not available for "#"(foo) class foo def foo diff --git a/sample/export.rb b/sample/export.rb index be7b6bc797e756..03b9492e5a68db 100644 --- a/sample/export.rb +++ b/sample/export.rb @@ -4,7 +4,7 @@ # foo class foo - export(\printf) + export :printf end def foobar @@ -12,7 +12,7 @@ def foobar end f = foo.new -#foo.unexport(\printf) -foo.export(\foobar) +#foo.unexport :printf +foo.export :foobar f.foobar f.printf "%s\n", foo diff --git a/sample/exyacc.rb b/sample/exyacc.rb new file mode 100644 index 00000000000000..ad6191c03d0835 --- /dev/null +++ b/sample/exyacc.rb @@ -0,0 +1,22 @@ +#! /usr/local/bin/ruby -Cn +# usage: exyacc.rb [yaccfiles] +# this is coverted from exyacc.pl in the camel book + +$/ = nil + +while gets() + sbeg = $_.index("\n%%") + 1 + send = $_.rindex("\n%%") + 1 + $_ = $_[sbeg, send-sbeg] + sub(/.*\n/, "") + gsub(/'{'/, "'\001'") + gsub(/'}'/, "'\002'") + gsub('\*/', "\003\003") + gsub("/\\*[^\003]*\003\003", '') + while gsub(/{[^}{]*}/, ''); end + gsub(/'\001'/, "'{'") + gsub(/'\002'/, "'}'") + while gsub(/^[ \t]*\n(\s)/, '\1'); end + gsub(/([:|])[ \t\n]+(\w)/, '\1 \2') + print $_ +end diff --git a/sample/gctest2.rb b/sample/gctest2.rb new file mode 100644 index 00000000000000..851d14f217750b --- /dev/null +++ b/sample/gctest2.rb @@ -0,0 +1,71 @@ +# GC stress test +def cons(car, cdr) + car::cdr +end + +def car(x) + x.car +end + +def cdr(x) + x.cdr +end + +def reverse1(x, y) + if x == nil then + y + else + reverse1(cdr(x), cons(car(x), y)) + end +end + +def reverse(x) + reverse1(x, nil) +end + +def ints(low, up) + if low > up + nil + else + cons(low, ints(low+1, up)) + end +end + +def print_int_list(x) + if x == nil + print("NIL\n") + else + print(car(x)) + if cdr(x) + print(", ") + print_int_list(cdr(x)) + else + print("\n") + end + end +end + +print("start\n") + +a = ints(1, 100) +print_int_list(a) +b = ints(1, 50) +print_int_list(b) +print_int_list(reverse(a)) +print_int_list(reverse(b)) +for i in 1 .. 100 + b = reverse(reverse(b)) +# print(i, ": ") +# print_int_list(b) +end +print("a: ") +print_int_list(a) +print("b: ") +print_int_list(b) +print("reverse(a): ") +print_int_list(reverse(a)) +print("reverse(b): ") +print_int_list(reverse(b)) +a = b = nil +print("finish\n") +GC.start() diff --git a/sample/list.rb b/sample/list.rb index 1a20c954d0db28..fa145f4627783a 100644 --- a/sample/list.rb +++ b/sample/list.rb @@ -1,19 +1,10 @@ # Linked list example class MyElem - #クラスメソッド(相当)の定義 - def MyElem.new(item) - # スーパークラスのメソッドの呼び出し(この場合はクラスClass) - elm = super # 変数宣言は要らない - #elmに対するメソッドの呼び出し - elm.init(item) - end - - # 通常のメソッド定義 - def init(item) + # オブジェクト生成時に自動的に呼ばれるメソッド + def init_object(item) # @変数はインスタンス変数(宣言は要らない) @data = item @next = nil - self end def data @@ -63,11 +54,7 @@ def to_s end class Point - def Point.new(x, y) - super.init(x, y) - end - - def init(x, y) + def init_object(x, y) @x = x; @y = y self end diff --git a/sample/list2.rb b/sample/list2.rb index fef9d35a841370..1c2ca08150edca 100644 --- a/sample/list2.rb +++ b/sample/list2.rb @@ -1,10 +1,6 @@ # Linked list example -- short version class Point - def Point.new(x, y) - super.init(x, y) - end - - def init(x, y) + def init_object(x, y) @x = x; @y = y self end diff --git a/sample/list3.rb b/sample/list3.rb index c6278574bf9843..6bedc6ced98795 100644 --- a/sample/list3.rb +++ b/sample/list3.rb @@ -2,11 +2,7 @@ # using _inspect class Point - def Point.new(x, y) - super.init(x, y) - end - - def init(x, y) + def init_object(x, y) @x = x; @y = y self end diff --git a/sample/rcs.awk b/sample/rcs.awk new file mode 100644 index 00000000000000..08979285c92984 --- /dev/null +++ b/sample/rcs.awk @@ -0,0 +1,33 @@ +BEGIN { + sw = 40.0; + dw = 78.0; + hdw = dw / 2.0; + w = 20.0; + h =1.0; + d = 0.2; + ss="abcdefghijklmnopqrstuvwxyz0123456789!#$%^&*()-=\\[];'`,./"; + rnd = srand(); +} + +{ + xr = -hdw; y = h * 1.0; maxxl = -999; + s = ""; + while (xr < hdw) { + x = xr * (1 + y) - y * w / 2; + i = (x / (1 + h) + sw /2); + c = (0 < i && i < length($0)) ? substr($0, i, 1) : "0"; + y = h - d * c; + xl = xr - w * y / (1 + y); + if (xl < -hdw || xl >= hdw || xl <= maxxl) { + t = rand() * length(ss); + c = substr(ss, t, 1); + } + else { + c = substr(s, xl + hdw, 1); + maxxl = xl; + } + s = s c; + xr = xr + 1; + } + print s; +} diff --git a/sample/rcs.dat b/sample/rcs.dat new file mode 100644 index 00000000000000..61c88bff89378a --- /dev/null +++ b/sample/rcs.dat @@ -0,0 +1,17 @@ +0000000000000000220000000000000000 +0000000000000111221110000000000000 +0000000000111112222111110000000000 +0000000111111112222111111110000000 +0000111111111122222211111111110000 +0111111111111222222221111111111110 +2222222222222222222222222222222222 +1122222222222222222222222222222211 +0111122222222222222222222222211110 +0011111122222222222222222211111100 +0001111111222222222222221111111000 +0000111112222222222222222111110000 +0000011122222222112222222211100000 +0000001122222221111222222211000000 +0000000122221111111111222210000000 +0000000221111111111111111220000000 +0000000000000000000000000000000000 diff --git a/sample/rcs.rb b/sample/rcs.rb new file mode 100644 index 00000000000000..faa4606788058a --- /dev/null +++ b/sample/rcs.rb @@ -0,0 +1,49 @@ +# random dot steraogram +# usage: rcs.rb rcs.dat + +sw = 40.0 # p^[ +dw = 78.0 # Random Character Streogram +hdw = dw / 2.0 +w = 20.0 # +h =1.0 # +d = 0.2 # P +ss="abcdefghijklmnopqrstuvwxyz0123456789!#$%^&*()-=\\[];'`,./" +rnd = srand() + +while gets() +# print($_) + xr = -hdw; y = h * 1.0; maxxl = -999 + s = ""; + while xr < hdw + x = xr * (1 + y) - y * w / 2 + i = (x / (1 + h) + sw /2) + 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 + tt = rand(ss.length) + c = ss[tt, 1] + else + c = s[xl + hdw, 1] + maxxl = xl + end + s += c + xr += 1 + end + print(s, "\n") +end + + + + + + + + + + + diff --git a/sample/sieve.rb b/sample/sieve.rb index 192a5865d8ab96..eaf4e33e2cd034 100644 --- a/sample/sieve.rb +++ b/sample/sieve.rb @@ -1,6 +1,6 @@ # sieve of Eratosthenes sieve = [] -unless max = $ARGV.shift; max = 100; end +if ! max = $ARGV.shift; max = 100; end max = max.to_i print "1" @@ -15,3 +15,4 @@ resque end end +print "\n" diff --git a/sample/uumerge.rb b/sample/uumerge.rb index 420a3924b67ea9..d0bd016036af43 100755 --- a/sample/uumerge.rb +++ b/sample/uumerge.rb @@ -8,7 +8,7 @@ end end -fail "missing begin" unless $sawbegin; +fail "missing begin" if !$sawbegin; OUT = open($file, "w") if $file != ""; while gets() @@ -18,10 +18,10 @@ end sub(/[a-z]+$/, ""); # handle stupid trailing lowercase letters continue if /[a-z]/ - continue unless ((($_[0] - 32) & 077) + 2) / 3 == $_.length / 4 + continue if !(((($_[0] - 32) & 077) + 2) / 3 == $_.length / 4) OUT << $_.unpack("u"); end -fail "missing end" unless $sawend; +fail "missing end" if ! $sawend; File.chmod $mode.oct, $file; exit 0; diff --git a/signal.c b/signal.c index f711436f1cb31c..c0173d8e1c848e 100644 --- a/signal.c +++ b/signal.c @@ -168,23 +168,30 @@ Fkill(argc, argv) { int sig; int i; + char *s; if (argc < 2) Fail("wrong # of arguments -- kill(sig, pid...)"); switch (TYPE(argv[0])) { case T_FIXNUM: sig = FIX2UINT(argv[0]); + if (sig >= NSIG) { + s = rb_id2name(sig); + if (!s) Fail("Bad signal"); + goto str_signal; + } break; case T_STRING: { int negative = 0; - char *s = RSTRING(argv[0])->ptr; - if (*s == '-') { + s = RSTRING(argv[0])->ptr; + if (s[0] == '-') { negative++; s++; } + str_signal: if (strncmp("SIG", s, 3) == 0) s += 3; if((sig = signm2signo(s)) == 0) diff --git a/socket.c b/socket.c index b691e7e1c8befe..58a2a8e9e7e051 100644 --- a/socket.c +++ b/socket.c @@ -82,7 +82,6 @@ Fbsock_setopt(sock, lev, optname, val) level = NUM2INT(lev); option = NUM2INT(optname); Check_Type(val, T_STRING); - GetOpenFile(sock, fptr); if (setsockopt(fileno(fptr->f), level, option, val->ptr, val->len) < 0) @@ -104,7 +103,7 @@ Fbsock_getopt(sock, lev, optname) len = 256; val = (struct RString*)str_new(0, len); Check_Type(val, T_STRING); - + GetOpenFile(sock, fptr); if (getsockopt(fileno(fptr->f), level, option, val->ptr, &len) < 0) rb_sys_fail(fptr->path); @@ -163,7 +162,7 @@ open_inet(class, h, serv, server) if (hostent == NULL) { hostaddr = inet_addr(host); if (hostaddr == -1) { - if (server && !strlen(host)) + if (server && !strlen(host)) hostaddr = INADDR_ANY; else rb_sys_fail(host); @@ -193,9 +192,9 @@ open_inet(class, h, serv, server) } protoent = getprotobyname(servent->s_proto); if (protoent == NULL) Fail("no such proto %s", servent->s_proto); - + fd = socket(PF_INET, SOCK_STREAM, protoent->p_proto); - + sockaddr.sin_family = AF_INET; if (h == Qnil) { sockaddr.sin_addr.s_addr = INADDR_ANY; @@ -293,7 +292,7 @@ open_unix(class, path, server) char *syscall; VALUE sock; OpenFile *fptr; - + Check_Type(path, T_STRING); fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) rb_sys_fail("socket(2)"); @@ -361,7 +360,7 @@ Ftcp_addr(sock) int len = sizeof addr; GetOpenFile(sock, fptr); - + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getsockname(2)"); return tcp_addr(&addr); @@ -376,7 +375,7 @@ Ftcp_peeraddr(sock) int len = sizeof addr; GetOpenFile(sock, fptr); - + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getsockname(2)"); return tcp_addr(&addr); @@ -443,7 +442,7 @@ Funix_addr(sock) int len = sizeof addr; GetOpenFile(sock, fptr); - + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getsockname(2)"); return unix_addr(&addr); @@ -458,7 +457,7 @@ Funix_peeraddr(sock) int len = sizeof addr; GetOpenFile(sock, fptr); - + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getsockname(2)"); return unix_addr(&addr); @@ -642,7 +641,7 @@ Fsock_send(argc, argv, sock) fd = fileno(f); if (to) { Check_Type(to, T_STRING); - n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags), + n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags), (struct sockaddr*)to->ptr, to->len); } else { @@ -678,7 +677,7 @@ sock_recv(sock, argc, argv, from) GetOpenFile(sock, fptr); fd = fileno(fptr->f); - if ((str->len = recvfrom(fd, str->ptr, str->len, flags, + if ((str->len = recvfrom(fd, str->ptr, str->len, flags, (struct sockaddr*)buf, &alen)) < 0) { rb_sys_fail("recvfrom(2)"); } diff --git a/spec b/spec index 75bd5e806594dd..b7c374db6423b5 100644 --- a/spec +++ b/spec @@ -1,6 +1,6 @@ .\" spec - -*- Indented-Text -*- created at: Tue May 25 15:18:26 JST 1993 -* はじめに(なぜRubyか?) +* はじめに Rubyは「UNIXで手軽にオブジェクト指向プログラミング」をしたいという望み を実現するために生まれた.そのために必要だと思われた性質は: @@ -41,57 +41,75 @@ Ruby イルをリンクできるし,そうでなくてもRubyを再コンパイルして組み込みクラ スを追加するのは容易である(Perlなどよりもはるかに容易である). -* Rubyの文法 +* Lexical structure -ここではRuby言語の文法を解説する.Rubyの基本的な部分は小さく,文法に例 -外が少ないので身につけるのはさほど難しくないだろう. +現在のrubyの実装はキャラクタセットとしてASCIIを用いる.rubyは大文字と +小文字を区別する.識別子の途中でなければ任意のところに空白文字をおくこ +とが出来る.空白文字はスペース(space),タブ(tab),垂直タブ(vertical +tab), CR(carriage return),改頁(form feed)である.改行(newline)は明ら +かに式が継続する場合には空白文字として,それ以外では文の区切りとして解 +釈される. + +識別子は英文字("_"を含む)から始まり,英数字が続いたものである.rubyの +識別子の長さに制限はない.現在の実装は識別子としてマルチバイトコード +(EUC,SJIS)も通すが勧められない. + +グローバル変数名は"$"に続く識別子または記号1文字,インスタンス変数は +"@"に続く識別子,クラス定数は"%"に続く識別子である.メソッド名,ローカ +ル変数名とクラス名は単なる識別子を用いる. ** コメント -スクリプト言語の習慣にならい,文字列中以外の'#'から行末まではコメント -と見なす. +スクリプト言語の習慣にならい,文字列中や文字表現(?#)以外の`#'から行末 +まではコメントと見なす. + +** 予約語 + +予約語は以下の通りである + + alias else in resque when + and elsif include retry while + break end module return yield + case ensure nil self __END__ + class fail or super __FILE__ + continue for protect then __LINE__ + def if redo undef -** 区切り記号 +予約語はクラス名,メソッド名,変数名などに用いることはできない. -空白文字(タブとスペース)および改行(\n)が区切り記号となる.更に -改行は +** 区切り文字 + +文字列などのリテラルの内部以外の場所の空白文字(タブとスペース)および改 +行(\n)が区切り記号となる.更に改行は a + b -のように行が式(文)の途中で終り,次の行に続くことが明白な場合以外は文の -区切りとしても認識される. +のように行が式の途中で終り,次の行に続くことが明白な場合を除き,式の区 +切りとしても認識される. -** 予約語 +* プログラム -予約語は以下の通りである +例: - alias elsif module self yield - and end nil super __END__ - break ensure or then __FILE__ - case fail protect undef __LINE__ - class for redo unless - continue if resque until - def in retry when - else include return while + print "hello world!\n" -予約語はクラス名,メソッド名,変数名などに用いることはできない. +プログラムは式を並べたものである.式と式の間はセミコロン(`;')または改 +行で区切られる(※). -** 式 +※ 式が次の行に継続することが明白な時には改行は式の区切りにならない. -Rubyプログラムを構成する要素は式と文である.まず,式から解説する. +* 式 -*** リテラル +Rubyではnilが偽,それ以外が真と評価される.CやPerl などとは異なり,0や +""(空文字列)は偽とは評価されないので気をつけること. -プログラム中に直接記述できるオブジェクトをリテラルと呼ぶ.Rubyのリテラ -ルには文字列,正規表現,数値というリテラルがある. - -**** 文字列リテラル +** 文字列式 "..." # バックスラッシュの解釈と変数展開あり '...' # バックスラッシュの解釈なし(\\と\'は解釈する) -**** バックスラッシュ記法 +バックスラッシュ記法 \t タブ(0x09) \n 改行文字(0x0a) @@ -108,14 +126,21 @@ Ruby \M-c メタ文字(c|0x80) \それ以外 文字そのもの -**** 変数展開 +変数展開 ダブルクォート(`"')で囲まれた文字列と正規表現の中では `#{変数名}'とい う形式で変数の内容を展開することができる.変数が変数記号(`$',`@',`%') で始まる場合には`#変数名'という形式でも展開できる.文字`#'に続く文字 が `{',`$',`@',`%'でなければ,そのまま`#'として解釈される. -**** 正規表現リテラル +** コマンド出力 + +Rubyではshのようにコマンドの実行結果を文字列リテラルのように使うことが +できる.``で囲まれた文字列は,ダブルクォートと同様にバックスラッシュ記 +法の解釈と変数展開が行なわれた後,コマンドとして実行され,その実行結果 +が文字列として与えられる.コマンドは評価されるたびに実行される. + +** 正規表現式 /.../ @@ -139,18 +164,20 @@ Ruby | 選択 ( ) 正規表現をまとめる -その他に文字列と同じバックスラッシュ記法も有効である. +その他に文字列と同じバックスラッシュ記法や変数展開も有効である. -**** ワイルドカードリテラル +** ワイルドカード式 <...> * 任意の文字列(空文字列を含む)と一致 ? 任意の1文字と一致 [ ] []内のいずれか1文字と一致 - {..} {}内のいずれかの文字列と一致 + {..} {}内の(コンマで区切られた)いずれかの文字列と一致 + +その他に文字列と同じバックスラッシュ記法や変数展開も有効である. -**** 数値リテラル +** 数値リテラル 123 整数 -123 整数(符合つき数) @@ -164,19 +191,12 @@ Ruby ?\M-a メタaのコード(225) ?\M-\C-a メタ-コントロールaのコード(129) - \シンボル 識別子/変数名と一対一対応する整数.applyなどでメソッ - ドを指定するのに使う. + :シンボル 識別子/変数名/演算子と一対一対応する整数.applyなど + でメソッドを指定する時などに使う. ?表現では全てのバックスラッシュ記法が有効である. -*** コマンドの出力 - -Rubyではshのようにコマンドの実行結果を文字列リテラルのように使うことが -できる.``で囲まれた文字列は,ダブルクォートと同様にバックスラッシュ記 -法の解釈と変数展開が行なわれた後,コマンドとして実行され,その実行結果 -が文字列として与えられる.コマンドは評価されるたびに実行される. - -*** 変数参照 +** 変数と定数 Rubyの変数はスコープ(有効範囲)と寿命(有効期限)によって4種類に分類され, その種類は変数名の最初の一文字で決定される.通常の変数の2文字目以降は @@ -184,20 +204,35 @@ Ruby 変数がある.変数名の長さに関して特別な制限はない. 変数のスコープに関わらず,初期化されていない変数を参照した時の値はnil -である. +である.いずれの種類の変数も宣言は必要ない. -**** グローバル変数 +*** グローバル変数 + +例: + + $foobar + $/ `$'で始まる変数のスコープはグローバルであり,プログラムのどこからでも 参照できる.その寿命はプログラムの寿命と等しい. -**** インスタンス変数 +*** インスタンス変数 + +例: + + @foobar `@'で始まる変数はインスタンス変数であり,そのクラスまたはサブクラスの メソッドから参照できる.スコープはメソッド内であり,その寿命はオブジェ クトの寿命に等しい. -**** クラス名/モジュール名/ローカル変数 +*** クラス名/モジュール名/ローカル変数 + +例: + + Array + Math + foobar アルファベットまたは`_'で始まる変数は識別子とも呼ばれ,ローカル変数, クラス名またはモジュール名である. @@ -231,15 +266,18 @@ Ruby ローカル変数のスコープも寿命もそのブロックの終りまで(トップレベルのロー カル変数はプログラムの終了まで)である. -**** クラス変数(定数) +*** クラス定数 -`%'で始まる変数はクラス変数であり,そのクラスと全てのサブクラスのイン -スタンスから参照できる.この変数への代入はトップレベル,すなわちメソッ -ドが定義できるレベルでのみ可能である.この変数はクラス間で値が共有され, -一度代入するとメソッドからは値を変更することができないので,定数として -用いられる. +例: + + %foobar + +`%'で始まる変数はクラス定数であり,そのクラスと全てのサブクラスのイン +スタンスから参照できる.この定数へはトップレベル,すなわちメソッドが定 +義できるレベルでのみ代入可能である.この変数はクラス間で値が共有され, +一度代入すると値を変更することができない. -**** 疑似変数 +*** 疑似変数 通常の変数以外に疑似変数と呼ばれる特殊な変数が4つある. @@ -251,31 +289,109 @@ Ruby これらの疑似変数は代入によってその値を変更することはできない.これらの 変数への代入は例外を発生させる. -*** メッセージ式 +** 括弧によるグルーピング + +例: + + (1+2)*3 + (foo();bar()) + +式は括弧によってグルーピングすることができる. + + `(' 式 `)' + +括弧の中には単なる式だけではなく,式の並び(=プログラム)を置くことが出 +来る. + + `(' 式 `;' 式... `)' + +式の並びの値は最後に評価した式の値である.つまりの値は最後に評価した式 +の値になる. + +** 配列式 + +例: + + [1, 2, 3] + +配列はArrayクラスのインスタンスである.配列を生成する式は以下の形式で +ある. + + `[' 式, ... `]' + +それぞれの式を評価した結果を含む配列を返す.要素数が0の空配列を生成す +るためには空の配列式 + + `[' `]' + +を用いる. + +** 連想配列式 + +例: + + {1=>2, 2=>4, 3=>6} + +連想配列とは任意のオブジェクトをキー(添字)として持つ配列である.Ruby +の連想配列はDict(辞書)クラスのインスタンスである.詳細はクラスDictの項 +を参照されたい.連想配列を生成する連想配列式は以下の形式である. + + `{' 式 `=>' 式... `}' + +それぞれの式を評価した結果をキーと値とする連想配列オブジェクトを返す. +要素数が0の連想配列を生成するためには空の連想配列式 + + `{' `}' + +を用いる.要素が1つ以上ある場合,曖昧でなければ`{', `}'は省略できる. + +** メソッド呼出式 + +例: + + foo.bar() + foo.bar + bar() オブジェクトにメッセージを送る基本的な構文がメッセージ式であり,その基 本形式は以下の通りである. - 式1 '.' メソッド名 '(' 引数1... [',' '*' 引数n ]')' + 式1 `.' メソッド名 `(' 引数1... [`,' `*' 引数n ]`)' 式1を評価して得られるオブジェクトの,識別子で指定されるメソッドを呼び -出す.一番最後の引数が'*'に続く(単一の)式である場合,その式を評価した -結果(配列である必要がある)を展開して,引数として追加する. +出す.一番最後の引数が`*'に続く(単一の)式である場合,その式を評価した +結果(配列でなければ変換される)を展開して,引数として追加する. + +メッセージ式で,レシーバがselfの場合,レシーバを省略して通常のプログラ +ミング言語における関数のような形式でメソッドを呼び出すことができる. -引数が一つもない時には括弧を省略できる. +メソッド呼び出しでは曖昧さがない時には括弧を省略できる.曖昧さがある時 +とは第一引数が以下の文字または予約語で始まる場合である. + + (, [, {, <, /, %, +, -, if, while + +例: + foo bar+baz # メソッド呼び出しfoo(bar+baz) + foo (1+2)*5 # メソッド呼び出し(foo(1+2)) * 5 + foo 1 # メソッド呼び出しfoo(1) + foo -1 # ローカル変数foo - 1 + +レシーバを指定したメソッド呼び出しではの場合引数が1つもない時にも括弧 +を省略できる. メソッド名としては任意の識別子を用いることができる.変数名とは識別子の 名前空間が違うので重複しても構わない. -メッセージ式で,レシーバがselfの場合,レシーバを省略して通常のプログラ -ミング言語における関数のような形式でメソッドを呼び出すことができる.こ -の場合引数が1つもない時でも括弧の省略はできない. - -クラス定義文の外で指定されたメソッドとクラスModuleのnoexportメソッドで +クラス定義文の外で指定されたメソッドとクラスModuleのunexportメソッドで 指定されたメソッドは関数的メソッドと呼ばれ,関数形式でしか呼び出すこと -ができない. +ができない(DEF参照). + +** SUPER -*** スーパークラスのメソッド呼び出し +例: + + super + super(1,2,3) メッセージ式の特殊なケースとしてスーパークラスのメソッドの呼び出しがあ る.この形式はメソッドを再定義した時にスーパークラスの定義を利用するた @@ -284,70 +400,106 @@ Ruby super 現在のメソッドに与えられた引数のままスーパクラスの同名のメソッドを呼び -出す. +出す.引数として与えられた変数の値を変更しても,渡されるのは元の引数の +値である. - super'(' 引数... ')' + super`(' 引数... `)' 引数とともにスーパークラスの同名のメソッドを呼び出す.一番最後の引数が -`*'に続く場合は通常のメソッド呼び出しと同様に渡される. +`*'に続く場合は通常のメソッド呼び出しと同様に展開して渡される. -*** 配列式/連想配列式 +** 代入 -配列のオブジェクトを生成する式の形式は以下の形式である. +例: - '[' 式, ... ']' + foo = bar + foo[0] = bar + foo.bar = baz -それぞれの式を評価した結果を含む配列を返す.要素数が0の空配列を生成す -るためには空の配列式 +代入には変数に対する代入(真の代入)と,プログラムを簡単にするためのシン +タックスシュガーとしての代入がある.真の代入は以下の形式である. - '[' ']' + 変数 `=' 式 -を用いる. +これは式を評価し,変数の値として代入する.クラスやモジュールや疑似変数 +には代入できない.クラスやモジュールの定義を変更するためにはclass式, +module式を用いる.代入式は演算子形式をとっているが,メソッドではないの +で再定義することはできない. -** 連想配列式 +シンタックスシュガーとしての代入式は以下のものがある. -連想配列とは任意のオブジェクトをキー(添字)として持てる配列である.Ruby -では連想配列はSmalltalkの用語を借りてDict(辞書)とも呼ばれる.詳細はク -ラスDictの項を参照されたい.連想配列を生成する連想配列式は以下の形式で -ある. +配列要素への代入 - '{' 式 '=>' 式... '}' + 式1`[' 式2... `]' `=' 式n -それぞれの式を評価した結果をキーと値とする連想配列オブジェクトを返す. -要素数が0の連想配列を生成するためには空の連想配列式 +式1を評価して得られるオブジェクトに,式2から式nまでを引数として,"[]=" +というメソッドを呼び出す. - '{' '}' +属性代入 -を用いる. + 式1 `.' 識別子 `=' 式2 + +式1を評価して得られるオブジェクト(レシーバが省略された場合は`self')に +対して,"識別子="というメソッドを式 2を引数として呼び出す. + +** 自己代入 + +例: + + foo += 12 + +式の値そのものに演算を加えるために自己代入形式がある. + + 式1 op= 式2 # 式1は代入可能でなければならない. + +この形式は内部的に「式1 = 式1 op 式2」と同様に評価される.ただし,式1 +は1回しか評価されないので,式1に副作用がある場合は,「式1 = 式1 op 式2」 +とは動作が異なる結果となる.opとして使える演算子は + + +, -, *, /, %, **, &, |, ^, <<, >> + +の11種類である.演算子と`='の間にスペースを空けてはいけない. -*** 配列参照,配列代入 +** 多重代入 -配列(連想配列を含む)の要素の参照は以下の形式で行なう. +例: - 式1 '[' 式2... ']' + foo, bar, baz = 1, 2, 3 + foo, = list() + foo, *rest = list2() -この形式は内部的に,式1に"[]"というメッセージを送ると解釈される.この -動作を疑似的なコードで記述すれば以下のようになる. +同時に複数の変数に代入を行なうことができる.その形式は以下の通りである. - 式1"[]"(式2...) + 左辺 `,' [左辺 `,' ...] [`*' 左辺]= 式 [, 式...] -一方,配列要素の代入は +右辺の式が一つしかない場合は,その値を配列として(必要ならばto_aメソッ +ドで配列に変換して),要素をそれぞれ左辺に代入する.それ以外の場合には, +それぞれの式の値が左辺に代入される.左辺の数と右辺の要素の数が合わない +時には足りない変数には nilが代入され,余った要素は無視される.多重代入 +の最後の要素の前に`*'がある場合,残りの全て引数が配列として代入される. - 式1 '[' 式2... ']' '=' 式n + 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."[]="(式2...) +** 演算子式 -という形式として解釈される. +例: -*** 演算子形式 + 1+2*3/4 プログラミングの利便のために一部のメソッド呼び出しと制御構造は演算子形 式をとる.Rubyには以下にあげる演算子がある.上のものほど結合順位が強く, 同じ列の演算子の結合順位は同じである. - 強 -(unary) +(unary) ! ~ + 強 [](配列参照), []=(配列代入) + -(unary) +(unary) ! ~ ** * / % + - @@ -362,110 +514,77 @@ Ruby :: =(代入) 自己代入(+=, -=, ..) and - 弱 or + or + 弱 if修飾子 while修飾子 ほとんどの演算式にはメソッド呼び出しとして解釈される(クラス毎に再定義 できる)が,一部再定義できない特殊なものがある.再定義できない特殊演算 子は - &&(論理積), ||(論理和), =(代入), ...(範囲指定), and, or + =(代入), ...(範囲), !(否定), &&(論理積), and, |(論理和), or, + if修飾子, while修飾子 -の6つである. +の9つの演算子とこれらとの組み合わせになる !=, !~ および自己代入演算子 +である. -上であげた特殊演算子以外の演算子形式はメソッド呼び出しと見なされる. -単項演算子(+, -, !, ~)は - - 式1."演算子"() - -という形式に,それ以外の2項演算子は - - 式1."演算子"(式2) - -に解釈される. - -** 代入 +上であげた特殊演算子以外の演算子形式は以下のようなメソッド呼び出しと見 +なされる. -代入には変数に対する代入(真の代入)と,プログラムを簡単にするためのシン -タックスシュガーとしての代入がある.真の代入は以下の形式である. - - 変数 '=' 式 +単項演算子(+, -, ~) -これは式を評価し,変数の値として代入する.クラスやモジュールや疑似変数 -には代入できない.クラスやモジュールの定義を変更するためにはclass文, -module文を用いる.代入式は演算子形式をとっているが,メソッドではないの -で再定義することはできない. + 式1. 演算子 () -シンタックスシュガーとしての代入式は以下のものがある. +配列(連想配列を含む)の要素の参照(式1 `[' 式2... `]') -配列要素への代入 + 式1. `[]' (式2...) - 式1'[' 式2... ' ]' '=' 式n +配列要素の代入( 式1 `[' 式2... `]' `=' 式n) -式1を評価して得られるオブジェクトに,式2から式nまでを引数として,"[]=" -というメソッドを呼び出す. + 式1. `[]=' (式2...) -属性代入 +それ以外の2項演算子(式 演算子 式) - 式1 '.' 識別子 '=' 式2 + 式1. 演算子 (式2) -式1を評価して得られるオブジェクトに対して"識別子="というメソッドを,式 -2を引数として呼び出す. +これはあくまでもそういう形式のメソッド呼び出しとして解釈されるというだ +けで,rubyプログラムでこういう記述が許されるというわけではない. -自己代入 - - 式1 op= 式2 # 式1は代入可能でなければならない. - -この形式は内部的に「式1 = 式1 op 式2」と同様に評価される.ただし,式1 -は1回しか評価されないので,式1に副作用がある場合は,「式1 = 式1 op 式2」 -とは動作が異なる結果となる.opとして使える演算子は - - +, -, *, /, %, **, &, |, ^, <<, >> - -の11種類である.演算子と`='の間にスペースを空けてはいけない. - -*** 条件分岐式 - -式の値によって分岐する式は以下に示すif式,unless式,case式の複合文型が -3種類と演算子型が3種類ある.Rubyではnilが偽,それ以外が真と評価される. -CやPerlなどとは異なり,0や ""(空文字列)は偽とは評価されないので気をつ -けること. - -if式 +** IF if 式1 [then] - 文1 + 式1 [elsif 式2 [then] - 文2 ]... + 式2 ]... [else - 文n ] + 式n ] end -条件判断式.式1が真の場合に文1を評価する.それ以外の場合は文2を評価す +条件判断式.式1が真の場合に式1を評価する.それ以外の場合は式2を評価す る.Rubyのif式はelse ifでもelifでもなくelsifでifの連続を行なうことに注 意すること. -unless式 +ifの条件判断部の式では文字列と正規表現リテラルは式「$_=~ リテラル」の +省略であるとみなされる. - unless 式1 [then] - 文1 - [else - 文2 ] - end +** IF修飾子 + + 式 if 式 -式1が偽(nil)を返すか,式2の評価中に例外が発生した場合に文1を評価する. -それ以外の場合は文2を評価する. +条件修飾子(if)の式は先行する式に先だって評価される.動作も対応するif式 +と同様である.if修飾子のついた式の値は条件が成立した場合には式の値,不 +成立の場合にはnilである. -case式 +** CASE case 式0 [when 式1 [, 式2]... [then] - 文1 ]... + 式1 ]... [else - 文n ] + 式n ] end 条件分岐,CのswitchよりもPascalのcaseに似ている.breakで脱出することも -後ろの文に継続することもないので注意. +後ろの式に継続することもないので注意. 条件の一致は「式n =~ 式0]で行なわれる.つまり, @@ -478,7 +597,7 @@ case stmt3 end -は以下のif文とほぼ等価である. +は以下のif式とほぼ等価である. _tmp = expr0 if expr1 =~ _tmp || expr2 =~ _tmp @@ -489,67 +608,77 @@ case stmt3 end -演算子型 +** AND 式 - 式1 '&&' 式2 - 式1 'and' 式2 + 式1 `&&' 式2 + 式1 `and' 式2 式1を評価し,その値が真(nil以外)であれば,式2を評価する.`and'は優先順 位が低い別名である. - 式1 '||' 式2 +andの両辺の式では文字列と正規表現リテラルは式「$_=~ リテラル」の省略で +あるとみなされる. + +** OR 式 + + 式1 `||' 式2 式1 'or 式2 式1を評価し,その値が偽であれば,式2を評価する.`or'は優先順位が低い別 名である. - 式1 '...' 式2 +orの両辺の式では文字列と正規表現リテラルは式「$_=~ リテラル」の省略で +あるとみなされる. -式1が真になるまでは偽を返し,その後は式2が真を返すまでは真を返す.式2 -が真になれば状態は偽に戻る +** 範囲指定式 -*** 繰り返し式(単純型) + 式1 `...' 式2 -ループを構成する式.これらの式の値は常にnilである.オブジェクトに合わ -せたループを行なうためには次に述べるイテレータを用いる. +式1が真になるまでは偽を返し,その後は式2が真を返すまでは真を返す.式2 +が真になれば状態は偽に戻る. -while式 +演算子`...'の両辺は条件式であり,更に `...'の両辺の式では文字列と正規 +表現リテラルは式「$_=~ リテラル」の省略,整数定数が「$.==定数」の省略 +と解釈される. - while 式 - 文 - end +** NOT 式 -条件が真の間,文を繰り返し実行する. + `!' 式 -until式 +式が真であれば偽,偽であれば真を返す. - until 式 - 文 - end - 式1 until 式2 +`!'式では文字列と正規表現リテラルは式「$_=~ リテラル」の省略であるとみ +なされる. -式が偽(nil)を返すか,式の評価中に例外が発生する間,文を繰り返し実行す -る. -*** 条件式について + 式1 `!=' 式2 + +「!(式1 == 式2)」の省略形 -if,unless,while,untilの条件判断部の式,および特殊演算子`&&', `||', -`...'の両辺の式は条件式と呼ばれる.条件式では文字列と正規表現リテラル -は式「$_=~リテラル」の省略であるとみなされる.更に演算子`...'の両辺で -は整数定数が「$.==定数」の省略と解釈される.条件式に現れる`!'演算子の -オペランドも条件式とみなされる. + 式1 `!~' 式2 -注意: 演算子`!'は特殊演算子ではないので,再定義を行なう場合に気をつけ -ること.条件式の中で +「!(式1 ~= 式2)」の省略形 + +** WHILE + + while 式 + 式 + end - ! 文字列リテラル - ! 正規表現リテラル +式を評価した値が真の間,式を繰り返し実行する.while式の値はnilである. -の形で呼び出されるメソッドの引数は,リテラルの表すオブジェクトではなく, -上記の比較の結果が与えられる.このため,原則的に`!'メソッドは再定義し -ない方が良い. +whileの条件判断部の式では文字列と正規表現リテラルは式「$_=~ リテラル」 +の省略であるとみなされる. -*** イテレータ(繰り返し子) +** WHILE 修飾子 + + 単純式 while 式 + +繰り返し修飾子(while)はまず先行する式を評価してから条件式を評価するの +で,最低一度は式を実行することになる.while修飾子のついた式の値はnilで +ある. + +** イテレータ(繰り返し子) イテレータとは制御構造(特にループ)の抽象化のために用いられるメソッドの 一種である.コードの断片(ブロックと呼ばれる)を指定してイテレータを呼び @@ -561,205 +690,122 @@ if イテレータとは制御構造(特にループ)の抽象化のために用いられるメソッドの 一種である.イテレータの呼び出しは以下の構文で行なわれる. - 式 '{' 変数... '|' 文... '}' + 式 `{' 変数... `|' 式... `}' -「文」をブロックとして設定し,「式」のメソッドをイテレータとして評価す +「式」をブロックとして設定し,「式」のメソッドをイテレータとして評価す る.「式」のトップレベルのメソッドだけがイテレータとして呼び出され, レシーバを表す式や,引数の式はイテレータとしては呼び出されない.「式」 が複数の式を含む時,各々がイテレータとして順に呼ばれる. -イテレータ内でyield文が実行されると,そこで指定された値がdo文で指定さ +イテレータ内でyield式が実行されると,そこで指定された値がdo式で指定さ れた変数に代入され,ブロックが実行される.ブロックの実行が終了するとそ -の値は yield文の値として返される.あるメソッドがイテレータとして呼び出 +の値は yield式の値として返される.あるメソッドがイテレータとして呼び出 されたかどうかはメソッドiterator_p()の戻り値で知ることができる.中には Enumerableモジュールのgrepメソッドのようにイテレータとして呼ばれた時と 普通のメソッドとして呼ばれた時とで動作が異なるメソッドもある. +** FOR + オブジェクトの各要素に対して操作を行なうための形式も提供されている.形 式は以下の通り. for 変数.. in 式 - 文 + 式 end -式の各要素に対し文を実行する.これは以下の式と等価である. +式の各要素に対し式を実行する.これは以下の式と等価である. - (式).each '{' 変数.. '|' 文 '}' + (式).each `{' 変数.. `|' 式 `}' よって式の値のオブジェクトがメソッドeachを持たない場合,forを実行する と例外が発生する. -*** イテレータの中でのブロック呼び出し +** YIELD - yield '(' [式 [',' 式...]]) + yield `(' [式 [`,' 式...]]) yield イテレータの中でブロックの呼び出しを行なう.yieldを実行したメソッドが イテレータとして呼び出されていない時には例外が発生する.yield の値はブ ロックの戻り値である. -*** 例外処理 +yieldの引数の括弧は曖昧でない限り省略できる. + +** FAIL + + fail `(' [メッセージ] `)' + +例外を発生させる.メッセージが与えられた場合には発生したソースファイル +名,行番号をシステム変数`$@'に,メッセージを`$!'にセットする. + +failの引数の括弧は曖昧でない限り省略できる. + +** PROTECT 処理中に予期しない事態が発生した時には例外が発生する.Rubyでは例外を途 中で捕捉して,再試行したり,後処理を行なったりすることができる. protect - 文1 + 式1 [resque - 文2 ] + 式2 ] [ensure - 文3] + 式3] end -文1を実行し,その実行中に例外が発生すればresque節で指定された文2を実行 -する.更にensure節が存在する時はprotect文を終了する前に必ず(正常終了時 -だけでなく,例外, return, break, continue, redoなどによる脱出でも)文3 +式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] - -多重代入は単純文である.その値は(配列に変換された)右辺である. - -*** 制御文 - -制御の流れを変更する以下の文がある.これらは単純文である. +** RETURN -return文 - - return [式[',' 式...]] + return [式[`,' 式...]] 式の値を戻り値としてメソッドの実行を終了する.式が2つ以上与えられた時 には,それらを要素とする配列をメソッドの戻り値とする.式が一つもない場 合には nil が戻り値となる. -ループ制御文 +** BREAK - continue - redo break -上記3つはループ中で使う. - -continueはもっとも内側のループの次の繰り返しを始める.redoはループ条件 -のチェックを行なわず,現在の繰り返しをやり直す.break はループを脱出す -る.Cと違い,breakはもっとも内側のループを脱出する作用だけを持ち,case -を抜ける作用は持たない. - -retry文 +break はループを脱出する.Cと違い,breakはもっとも内側のループを脱出す +る作用だけを持ち,case を抜ける作用は持たない. - retry - -protect文のresque節で使い,protect文を始めから実行する.例外処理を行なっ -てから再試行するのに使う.resque節以外でretryが用いられた場合例外が発 -生する. - -fail文 - - fail '(' [メッセージ] ')' - fail [メッセージ] - -例外を発生させる.メッセージが与えられた場合には発生したソースファイル -名,行番号をシステム変数`$@'に,メッセージを`$!'にセットする. - -yield文 - - yield 式 [',' 式...] - -文としてyieldを用いることもできる.この場合は式を括弧で括る必要はない. - -*** メソッド呼び出し文 - -1つ以上の引数を持つメソッド呼び出す場合には曖昧さがなければ,引数を括 -弧で括る必要はない.その形式は以下の通りである. - - 式 '.' メソッド名 引数1 ',' [引数2...]['*' 引数n] - メソッド名 引数1 ',' [引数2...]['*' 引数n] - super 引数1 ',' [引数2... ]['*' 引数n] - -構文解析時に,式のように解釈できる場合は式としての解釈が優先される. +** CONTINUE + continue - foo bar+baz # メソッド呼び出しfoo(bar+baz) - foo (bar)+baz # メソッド呼び出しfoo(bar) + bar - foo 1 # メソッド呼び出しfoo(1) - foo -1 # ローカル変数foo - 1 +continueはもっとも内側のループの次の繰り返しを始める. -括弧のないメソッド呼び出し文は単純文である. +** REDO -*** 制御修飾子 + redo -単純文に制御修飾子を付加したものは文である(単純文ではない).修飾子は以 -下の4種類である. +redoはループ条件のチェックを行なわず,現在の繰り返しをやり直す. - 単純文 if 式 - 単純文 unless 式 - 単純文 while 式 - 単純文 until 式 +** RETRY -条件修飾子(if/unless)の式は先行する文に先だって評価される.動作も対応 -する条件分岐式と同様である. + retry -繰り返し修飾子(while/until)はまず先行する文を評価してから条件式を評価 -するので,最低一度は文を実行することになる. +protect式のresque節で使い,protect式を始めから実行する.例外処理を行なっ +てから再試行するのに使う.resque節以外でretryが用いられた場合例外が発 +生する. -*** クラス宣言文 +** クラス定義 -クラスを定義する構文は以下の通りである. +クラスを定義する構式は以下の通りである. - class クラス名 [':' スーパークラス名 ] + class クラス名 [`:' スーパークラス名 ] 定義実体 end クラス名は任意の識別子である(大文字で始めることを推奨する).クラス定義 -のネストはできないので他の定義文内ではクラスを定義できない. +のネストはできないので他の定義式内ではクラスを定義できない. -*** モジュール定義文 +** モジュール定義 -モジュールを定義する構文は以下の通りである. +モジュールを定義する構式は以下の通りである. module クラス名 定義実体 @@ -768,27 +814,13 @@ yield文 モジュール名は大文字で始まる識別子である.クラス同様,モジュール定義も ネストできない. -*** インクルード文 - -モジュールをインクルードすることによって,クラスまたはモジュールに機能 -を追加できる.モジュールをインクルードした場合,そのモジュール(および -そのモジュールが更にインクルードしているモジュール)の全てのメソッドを -受け継ぐ.別のいい方をすればインクルードは限定された多重継承といえる. - -他のモジュールをインクルードする構文は以下の通りである. - - include モジュール名 [',' モジュール名...] - -現在の定義中のクラスまたはモジュール(トップレベルではObjectクラス)に指 -定したモジュールをインクルードする. - -*** メソッド定義文 +** メソッド定義 通常(特異メソッドでない)メソッド定義の形式は以下の通りである.通常メソッ -ド定義はネストできないので,メソッド定義文中ではメソッド定義文を再び呼 +ド定義はネストできないので,メソッド定義式中ではメソッド定義式を再び呼 び出せない. - def メソッド名 ['(' 引数 [',' 引数...][',' '*'引数 ] ')'] + def メソッド名 [`(' 引数 [`,' 引数...][`,' `*'引数 ] `)'] 定義実体 end @@ -798,17 +830,22 @@ yield文 メソッドには関数的メソッドと通常メソッドがある.関数的メソッドは関数形 式でしか呼び出すことができず,よって該当するクラスとそのサブクラスのメ -ソッドからしか呼び出すことができない.クラス定義文の外にあるdef文は関 -数的メソッドを定義し,クラス定義文の中にあるdef文は通常のメソッドを定 -義する.メソッドの可視性はModuleクラスのexport/noexportメソッドを使っ -て変更する. +ソッドからしか呼び出すことができない. + +新規にメソッドを定義する場合,クラス定義式の外にあるdef式は関数的メソッ +ドを定義し,クラス定義式の中にあるdef式は通常のメソッドを定義する.スー +パークラスのメソッドを再定義する場合には定義されるメソッドの可視性はスー +パークラスのメソッドのものを受け継ぐ. -** 特異メソッド定義文 +メソッドの可視性を変更する場合にはModuleクラスのexport/unexportメソッ +ドを用いる. + +** 特異メソッド定義 メソッド定義にはもう一つ特異メソッドの定義がある.特異メソッドとはある 特定のオブジェクトに固有のメソッドである.形式は以下の通りである. - def 式 '.' メソッド名 ['(' 引数 [',' 引数...][',' '*'引数 ] ')'] + def 式 `.' メソッド名 [`(' 引数 [`,' 引数...][`,' `*'引数 ] `)'] 定義実体 end @@ -821,7 +858,21 @@ yield文 のサブクラスにも継承される.言い替えればクラスの特異メソッドは他のオブ ジェクト指向システムにおけるクラスメソッドの働きをする. -*** メソッドの別名定義文 +** INCLUDE + +モジュールをインクルードすることによって,クラスまたはモジュールに機能 +を追加できる.モジュールをインクルードした場合,そのモジュール(および +そのモジュールが更にインクルードしているモジュール)の全てのメソッドを +受け継ぐ.別のいい方をすればインクルードは限定された多重継承といえる. + +他のモジュールをインクルードする構式は以下の通りである. + + include モジュール名 [`,' モジュール名...] + +現在の定義中のクラスまたはモジュール(トップレベルではObjectクラス)に指 +定したモジュールをインクルードする. + +** ALIAS 以下の形式でメソッドに別名をつけることができる. @@ -831,28 +882,20 @@ yield文 ソッドが再定義されても,古いメソッドが呼び出されたのと全く同じ働きをす る. -*** メソッド定義取り消し文 +** UNDEF メソッドの定義を取り消すためにはundefを用いる. undef メソッド名 -識別子または文字列で指定したメソッドの定義を取り消す. +指定したメソッドの定義を取り消す. defによる別名定義とundefによる定義取り消しを使うとクラスのインタフェー -スをスーパークラスと独立に変更することができる.ただし,メソッドがself -にメッセージを送っている場合にはよく注意しないと既存のメソッドが動作し -なくなる可能性がある. - -------------------------------------------------------- -* Rubyの組み込み機能 +スをスーパークラスと独立に変更することができる.ただし,メソッドがself +にメッセージを送っている場合もあるので,よく注意しないと既存のメソッド +が動作しなくなる可能性がある. -Rubyプログラミングの基本はクラス,モジュールとそのメソッドの習得である. -Rubyには処理系そのものに以下の機能が組み込まれている.ライブラリをロー -ドすることによって機能は増えるが,それらに関してはそれぞれのライブラリ -のドキュメントを参照してもらいたい. - -** 関数 +* 組み込み関数 Rubyには厳密な意味では関数はないがKernelクラスの関数メソッドは(全ての 通常クラスから関数形式で呼び出せるので),関数的に用いられる.関数的に @@ -1081,7 +1124,7 @@ Ruby 実装されていないマシンではflagsはいつもnilまたは0でなければな らない. -** システム変数 +* 組み込み変数と定数 $! エラーメッセージ.failで設定する. @@ -1180,7 +1223,6 @@ Ruby $VERSION rubyのバージョンを示す文字列 -** システム定数 %TRUE t %FALSE nil @@ -1201,9 +1243,9 @@ Ruby は完全には同義ではない.%FALSEに関しては,このような問題は生じ ない. -** クラス/モジュール +* 組み込みクラスとモジュール -*** Array(クラス) +** Array(クラス) 数字を添字とした配列のクラスである.生成は一般的には配列式``[...]''で 行なわれる. @@ -1385,7 +1427,13 @@ Methods: objを配列の先頭に追加する. -*** Bignum(クラス) +Single Methods: + + Array[item...] + + 引数を要素とする配列を生成する. + +** Bignum(クラス) 無限多倍長整数のクラス.演算の結果がこのFixnumの範囲内である場合には自 動的にクラスはFixnumに変換される.一般的にRubyプログラムではFixnumと @@ -1425,7 +1473,7 @@ Methods: 商と剰余の2要素の配列を返す. -*** Block(クラス) +** Block(クラス) イテレータに渡される手続きをまとめたオブジェクト.実行するコードだけで なくコンテキスト(ローカル変数)なども保存する. @@ -1434,7 +1482,7 @@ SuperClass: Object Methods: - do(arg[, ...]) + call(arg[, ...]) ブロックを実行する. @@ -1446,7 +1494,7 @@ Single Methods: が呼ばれると,その時点で実行されるべきコードを包み込んだオブジェ クト(Block)を生成する. -*** Class(クラス) +** Class(クラス) クラスのクラス.より厳密に説明するとクラスは特異メソッドを継承するため に,それぞれメタクラスと呼ばれる名前のないクラスをクラスとして持ち, @@ -1472,7 +1520,7 @@ Methods: ラスの特異メソッドによってオーバーライドされ,クラスによって引 数が異なる. -*** Comparable(モジュール) +** Comparable(モジュール) 比較演算を許すクラスのためのMixin.このモジュールをインクルードするこ とによって,`<=>'演算子を定義するだけで他の演算子はその定義を利用して @@ -1504,7 +1552,7 @@ Methods: selfがminとmaxの範囲内にある時真を返す. -*** Cons(クラス) +** Cons(クラス) データの組(ペア)を表現するクラス.通常,生成は`::'演算子を用いて行なわ れる.LispのCONSペアと同様にListを構成する形で用いられることもある. @@ -1561,7 +1609,7 @@ Methods: CONSペアからなるリストの各要素を与えるイテレータ. -*** DBM(クラス) +** DBM(クラス) NDBMファイルをアクセスするクラス.キー,データともに文字列でなければな らないという制限と,データがファイルに保存されるという点を除いては @@ -1657,7 +1705,7 @@ Single Methods: る.modeの省略値は0666である.modeとしてnilを指定するとデータ ベースが既に存在しない時には新たにオープンせず,nilを返す. -*** Dict(クラス) +** Dict(クラス) 辞書あるいは連想配列.任意のオブジェクトを添字とできる配列のクラスであ る.Hashという名前でもアクセスできる.連想配列オブジェクトの生成は一般 @@ -1740,11 +1788,15 @@ Methods: Single Methods: + Dict[key, value...] + + 奇数番目の引数をkey,偶数番目の引数をvalueとする辞書を生成する. + new 新しい(空の)辞書オブジェクトを返す. -*** Directory(クラス) +** Directory(クラス) ディレクトリ内の要素を順に返すディレクトリストリーム操作のためのクラス. Dirという名前でもアクセスできる. @@ -1808,7 +1860,7 @@ Single Methods: pathで指定されたディレクトリを削除する.ディレクトリは空である 必要がある. -*** Enumerable(モジュール) +** Enumerable(モジュール) 要素に対する繰り返しを行なうクラスのためのMixin.このモジュールをイン クルードするためには,メソッド`each'を定義する必要がある. @@ -1866,7 +1918,7 @@ Methods: 全ての要素をソートした配列を返す. -*** Etc(モジュール) +** Etc(モジュール) /etcディレクトリ以下の情報を得るためのモジュール.クラスにインクルード して使うこともできる. @@ -1938,7 +1990,7 @@ Single Methods: 全てのpasswdエントリを順にアクセスするためのイテレータ. -*** File(クラス) +** File(クラス) ファイルアクセスのためのクラス.メソッドopen()で生成される.また,この クラスの特異メソッドとしてtestのファイルテスト演算子相当のメソッドが定 @@ -2097,7 +2149,7 @@ Single Methods: これ以外にFileTestモジュールのメソッドも特異メソッドとして持つ. -*** FileTest(モジュール) +** FileTest(モジュール) ファイルテスト用メソッドを集めたモジュール.インクルードして用いること もできる. @@ -2203,7 +2255,7 @@ Single Methods: filenameのファイルが存在し,大きさが0である時,真を返す. -*** Fixnum(クラス) +** Fixnum(クラス) 31bit(マシンのlongの長さ-1 bit)整数のクラス.builtin classである.この クラスはpointer内の即値であるためcall by valueで呼び出される点が特徴的 @@ -2268,7 +2320,7 @@ Methods: イテレータ.selfからmaxまで繰り返す. -*** Float(クラス) +** Float(クラス) 浮動小数点数のクラス. @@ -2309,7 +2361,7 @@ Single Methods: floatと同じ値を持つ新しいFloatオブジェクトを返す. -*** GC(モジュール) +** GC(モジュール) Ruby組み込みのgarbage collectorの制御を行なうためのモジュール.このモ ジュールのメソッドをを用いることによって,一時的にGCを止めたり,GCの起 @@ -2335,7 +2387,7 @@ Single Methods: GCを開始する. -*** Glob(クラス) +** Glob(クラス) ワイルドカードのクラス.ワイルドカードのリテラルは<...>という形式であ る.正規表現とほぼ同じように使えるが,こちらは機能が少ない.ただし,ワ @@ -2362,7 +2414,7 @@ Single Methods: 文字列をワイルドカードに変換したオブジェクトを返す. -*** Integer(クラス) +** Integer(クラス) 整数クラス.実際はその大きさによってFixnumとBignumいう二つのサブクラス で実現されている.Integerはそれらのスーパークラスとなる抽象クラスであ @@ -2392,7 +2444,7 @@ Methods: いつも真を返す. -*** IO(クラス) +** IO(クラス) 入出力のための基本クラス. @@ -2493,7 +2545,7 @@ Methods: strを出力する.出力したバイト数を返す. -*** Kernel(クラス) +** Kernel(クラス) 全てのクラスの基底クラス.Ruby組み込みの全ての関数メソッドはこのクラス で定義されている.関数メソッドについては「関数」の項目を参照のこと. @@ -2565,7 +2617,7 @@ Methods: 定義した時には必ずこちらもそれに合わせて再定義すること. -*** Math(モジュール) +** Math(モジュール) 浮動小数点演算をサポートするクラス.Mathモジュールは同じ定義のメソッド と特異メソッドとの両方が定義されているので,特異メソッドを呼び出して使 @@ -2610,7 +2662,7 @@ Single Methods: xの立方根を返す. -*** Module(クラス) +** Module(クラス) モジュールのクラス. @@ -2665,7 +2717,7 @@ Methods: nameで指定されたメソッドを関数形式でだけ呼び出し可能にする.す でに関数メソッドである場合には何もしない. -*** Nil(クラス) +** Nil(クラス) 偽を表すオブジェクトnilのクラス.偽変数(の値)nilはNilクラスの唯一のイ ンスタンスである. @@ -2686,7 +2738,7 @@ Methods: 常に真を返す. -*** Numeric(クラス) +** Numeric(クラス) 数一般の性質を表す抽象クラス. @@ -2717,7 +2769,7 @@ Methods: 次の数を返す.次の数とはその数を越える最小の整数である. -*** Object(クラス) +** Object(クラス) 全ての通常クラスのスーパクラス.通常クラスのインスタンスの一般的な振舞 いを定義している.このクラスのサブクラスでないクラスはKernelとNilと, @@ -2727,6 +2779,9 @@ SuperClass: Builtin Methods: + init_object + + is_member_of(class) オブジェクトselfがクラスclassのインスタンスである時,真を返す. @@ -2752,7 +2807,7 @@ Methods: オブジェクトを配列に変換する.カーネルクラスで定義されているデ フォルトは,そのオブジェクト自身を含む1要素の配列を返す. -*** Process(モジュール) +** Process(モジュール) プロセスに関する操作を行なうためのモジュール.Mathモジュールと同様に全 てのメソッドは特異メソッドとしても通常のメソッドとしても使える. @@ -2827,7 +2882,7 @@ Single Methods: プロセスの現在の実UIDをuidにセットする. -*** Range(クラス) +** Range(クラス) 範囲オブジェクトのクラス.範囲オブジェクトは`..'演算子によって生成され, 一般的には以下のような使い方をする @@ -2855,7 +2910,7 @@ Methods: self =~ other selfがotherと同じクラスに対する範囲オブジェクトで,その範囲内 - にotherがある時(start <= other <= end),真を返す.これはcase文 + にotherがある時(start <= other <= end),真を返す.これはcase式 で範囲指定する時に便利である.例えば case i @@ -2867,7 +2922,7 @@ Methods: each - 範囲内に存在するオブジェクトを与えるイテレータ.主にfor文のた + 範囲内に存在するオブジェクトを与えるイテレータ.主にfor式のた めに用いられる. end @@ -2878,7 +2933,7 @@ Methods: 範囲の始点を返す. -*** Socket(クラス) +** Socket(クラス) SuperClass: BasicSocket @@ -2938,7 +2993,8 @@ Single Methods: ソケットのペアを返す.引数の指定は openと同じである. -*** Regexp(クラス) + +** Regexp(クラス) 正規表現のクラス.正規表現のリテラルは/.../という形式で表すが,動的に 生成するためには @@ -2974,7 +3030,12 @@ Single Methods: 区別する.設定されない場合はマッチを行なった時点のシステム変数 `$='の値によって区別するかしないかが決定される. -*** BasicSocket(クラス) + quote(str) + + 文字列の中の正規表現で意味を持つ文字をエスケープする.新しい文 + 字列を返す. + +** BasicSocket(クラス) ソケットを表す抽象クラス.具体的なソケット操作はサブクラスで定義される. 例えばインターネットドメインの場合はTCPsocketを用いる. @@ -3008,7 +3069,7 @@ Methods: howが1である時は,以降の送信が拒否される.howが2の時には,それ 以降の送信,受信ともに拒否される.shutdown(2)を参照. -*** String(クラス) +** String(クラス) 文字列クラス.Rubyの文字列はヌルターミネートではないので,バイナリデー タも扱える.従ってどちらかというと単なる文字列というよりバイト列である. @@ -3323,7 +3384,7 @@ Single Methods: stringと同じ内容を持つ新しい文字列を返す. -*** Struct(クラス) +** Struct(クラス) 構造体クラス.複数のデータをまとめる時に用いられる(例: Time::times). データをまとめる時には配列クラスが用いられることもあるが(例: select), @@ -3386,7 +3447,7 @@ Single Methods: バで指定された名前の特異メソッドが定義されていて,そのメソッド によってメンバの内容を得ることができる. -*** TCPserver(クラス) +** TCPserver(クラス) TCP/IPストリーム型接続のサーバ側のソケットのクラス.このクラスによって 簡単にソケットを利用したサーバのプログラミングができる.例えばechoサー @@ -3432,7 +3493,7 @@ Single Methods: 続だけを受け付ける.省略時は全てのホストからの接続要求を受け付 ける. -*** TCPsocket +** TCPsocket インターネットドメインのストリーム型ソケットのクラス.通常のIOクラスの サブクラスと同様の入出力ができる.このクラスによってソケットを用いたク @@ -3470,7 +3531,7 @@ Single Methods: 字列,serviceは/etc/services(またはNIS)に登録されているサービ ス名かポート番号である. -*** Time(クラス) +** Time(クラス) 時間を表すクラス.大小比較などができる.Time.nowで現在の時間を得ること ができる.またファイルのタイムスタンプを得るメソッドの戻り値もこのクラ @@ -3593,7 +3654,7 @@ Single Methods: 時間の単位は秒であり,浮動小数点数で与えられる.詳細は times(3)を参照のこと. -*** UNIXserver +** UNIXserver UNIXストリーム型接続のサーバ側のソケットのクラス. @@ -3606,7 +3667,7 @@ Methods: クライアントからの接続要求を受け付け,接続したUNIXsocketのイン スタンスを返す. -*** UNIXsocket +** UNIXsocket UNIXドメインのストリーム型ソケットのクラス.通常のIOクラスのサブクラス と同様の入出力ができる. @@ -3636,6 +3697,210 @@ Single Methods: pathで指定したパス名を用いて接続したソケットを返す. +* C言語とのインタフェース + +rubyはC言語とのインターフェースを提供し,C言語からのクラス,モジュール +の定義,C言語で記述したメソッドの定義,rubyのメソッドの呼び出し,イテ +レータの呼び出し,例外処理などを行なうことが出来る.また,OSが許せば実 +行時にCで書かれたモジュールをロードすることも出来る. + +具体的なインタフェースに関しては,別ドキュメント(添付ファイル C-IF)を +参照のこと. + +* 文法 + +以下は疑似BNFで記述したrubyの文法である.より正確な記述はparse.yを参照 +されたい. + +PROGRAM : COMPEXPR + +COMPEXPR : EXPR (TERM EXPR)* [TERM] + +EXPR : MLHS `=' ARGS + | ASSOCS + | return ARGS + | fail ARGS + | yield ARGS + | identifier CALL_ARGS + | PRIMARY `.' identifier CALL_ARGS + | super CALL_ARGS + | undef FNAME + | alias FNAME FNAME + | include identifier (`,' identifier)* + | EXPR if EXPR + | EXPR while EXPR + | EXPR and EXPR + | EXPR or EXPR + | ARG + +ARG : LHS `=' ARG + | LHS OP_ASGN ARG + | ARG `..' ARG + | ARG `...' ARG + | ARG `+' ARG + | ARG `-' ARG + | ARG `*' ARG + | ARG `/' ARG + | ARG `%' ARG + | ARG `**' ARG + | `+' ARG + | `-' ARG + | ARG `|' ARG + | ARG `^' ARG + | ARG `&' ARG + | ARG `<=>' ARG + | ARG `>' ARG + | ARG `>=' ARG + | ARG `<' ARG + | ARG `<=' ARG + | ARG `==' ARG + | ARG `!=' ARG + | ARG `=~' ARG + | ARG `!~' ARG + | `!' ARG + | `~' ARG + | ARG `<<' ARG + | ARG `>>' ARG + | ARG `::' ARG + | ARG `&&' ARG + | ARG `||' ARG + | PRIMARY + +PRIMARY : LITERAL + | VARIABLE + | super `(' [CALL_ARGS] `)' + | super + | PRIMARY `[' [ARGS] `]' + | `[' [ARGS] `]' + | `{' ARGS `}' + | `{' ASSOCS `}' + | redo + | break + | continue + | retry + | return + | fail `(' ARGS `)' + | fail `(' `)' + | fail + | yield `(' ARGS `)' + | yield `(' `)' + | yield + | PRIMARY `{' [ITER_VAR] `|' COMPEXPR `}' + | identifier `(' [CALL_ARGS] `)' + | PRIMARY `.' identifier `(' [CALL_ARGS] `)' + | PRIMARY `.' identifier + | if EXPR THEN + COMPEXPR + (elsif EXPR THEN COMPEXPR)* + [else COMPEXPR] + end + | while EXPR TERM COMPEXPR end + | case COMPEXPR + (when ARGS THEN)+ + [else COMPEXPR] + end + | for ITER_VAR in EXPR TERM + COMPEXPR + end + | protect + COMPEXPR + [resque COMPEXPR] + [ensure COMPEXPR] + end + | `(' COMPEXPR `)' + | class identifier `:' identifier + COMPEXPR + end + | module identifier + COMPEXPR + end + | def FNAME ARGLIST + COMPEXPR + end + | def SINGLETON `.' FNAME ARGLIST + COMPEXPR + end + +THEN : TERM + | then + | TERM then + +ITER_VAR : LHS + | MLHS + +MLHS : LHS `,' [LHS (`,' LHS)*] [`*' LHS] + +LHS : VARIABLE + | PRIMARY `[' [ARGS] `]' + | PRIMARY `.' identifier + +CALL_ARGS : ARGS + | ASSOCS + | ARGS `,' ASSOCS + | ARGS `,' `*' ARG + +ARGS : ARG + | ARGS `,' ARG + +ARGLIST : `('[identifier(`,'identifier)*][`*'identifier]`)' + | TERM + +SINGLETON : VARIABLE + | `(' COMPEXPR `)' + +ASSOCS : ASSOC (`,' ASSOC)* + +ASSOC : ARG `=>' ARG + +VARIABLE : identifier + | VARNAME + | nil + | self + | `__FILE__' + | `__LINE__' + +LITERAL : numeric + | SYMBOL + | STRING + | REGEXP + | GLOB + +TERM : `;' + | `\n' + +ここより下は字句解析部で認識される. + +SYMBOL : `:'FNAME + | `:'VARNAME + +FNAME : identifier | `::' | `..' | `|' | `^' | `&' + | `<=>' | `==' | `=~' | `>' | `>=' | `<' | `<=' + | `<<' | `>>' | `+' | `-' | `*' | `/' | `%' | `**' + | `~' | `+@' | `-@' | `[]' | `[]=' + +VARNAME : GLOBAL + | `@'identifier + | `%'identifier + +GLOBAL : `$'identifier + | `$'any_char + +STRING : `"' any_char* `"' + | `'' any_char* `'' + | ``' any_char* ``' + +REGEXP : `/' any_char* `/' + +GLOB : `<' any_char* `>' + +* 謝辞 + +Rubyの言語仕様はC, Perl, Eiffelの各言語にこの順に影響を受けている. そ +の他に影響を受けた言語としてはtcl, AWK, bourne shell, CLU, Sather, +Icon, Smalltalk, Emacs Lispなどがある. またrubyの言語仕様を決定するた +めに協力して下さった方々を以下にあげる(敬称略): 石塚圭樹,大庭康生,伊 +藤純一郎,中村@NEC.関根@日本DEC,たなか@赤坂.富士通. + ------------------------------------------------------- Local variables: fill-column: 70 diff --git a/sprintf.c b/sprintf.c index 278b16607c11a0..c74ec080ff7592 100644 --- a/sprintf.c +++ b/sprintf.c @@ -282,7 +282,7 @@ Fsprintf(argc, argv) blen += strlen(&buf[blen]); } break; - + case 'd': case 'D': case 'O': diff --git a/st.c b/st.c index 80f08e9fb6deb5..eb3ad92871fe50 100644 --- a/st.c +++ b/st.c @@ -58,7 +58,7 @@ int reorder_flag; tbl->grow_factor = grow_factor; tbl->reorder_flag = reorder_flag; tbl->num_bins = size; - tbl->bins = + tbl->bins = (st_table_entry **) Calloc((unsigned)size, sizeof(st_table_entry *)); return tbl; } @@ -122,11 +122,11 @@ char **value; hash_val = do_hash(key, table); FIND_ENTRY(table, ptr, hash_val); - + if (ptr == nil(st_table_entry)) { return 0; } else { - if (value != nil(char *)) *value = ptr->record; + if (value != nil(char *)) *value = ptr->record; return 1; } } @@ -176,7 +176,7 @@ char *value; { int hash_val; st_table_entry *tbl; - + hash_val = do_hash(key, table); ADD_DIRECT(table, key, value, hash_val, tbl); } @@ -210,13 +210,13 @@ register st_table *table; int i, old_num_bins = table->num_bins, hash_val; table->num_bins = table->grow_factor*old_num_bins; - + if (table->num_bins%2 == 0) { table->num_bins += 1; } - + table->num_entries = 0; - table->bins = + table->bins = (st_table_entry **) Calloc((unsigned) table->num_bins, sizeof(st_table_entry *)); @@ -245,9 +245,9 @@ st_table *old_table; if (new_table == nil(st_table)) { return nil(st_table); } - + *new_table = *old_table; - new_table->bins = + new_table->bins = (st_table_entry **) Calloc((unsigned) num_bins, sizeof(st_table_entry *)); @@ -357,7 +357,7 @@ int modulus; { register int val = 0; register int c; - + while ((c = *string++) != '\0') { val = val*997 + c; } diff --git a/string.c b/string.c index 3861f71d32354a..aacc6f621cadf3 100644 --- a/string.c +++ b/string.c @@ -489,7 +489,7 @@ Fstr_rindex(argc, argv, str) Check_Type(sub, T_STRING); if (pos > str->len) return Qnil; /* substring longer than string */ - sbeg = str->ptr; s = s + pos - sub->len; + sbeg = str->ptr; s = sbeg + pos - sub->len; t = sub->ptr; len = sub->len; while (sbeg <= s) { @@ -535,7 +535,7 @@ Fstr_next(orig) char c = -1; str = (struct RString*)str_new(orig->ptr, orig->len); - + sbeg = str->ptr; s = sbeg + str->len - 1; while (sbeg <= s) { @@ -642,7 +642,9 @@ str_replace(str, beg, len, val) REALLOC_N(str->ptr, char, str->len+val->len-len+1); } - memmove(str->ptr+beg+val->len, str->ptr+beg+len, str->len-(beg+len)); + if (len != val->len) { + memmove(str->ptr+beg+val->len, str->ptr+beg+len, str->len-(beg+len)); + } memcpy(str->ptr+beg, val->ptr, val->len); str->len += val->len - len; str->ptr[str->len] = '\0'; @@ -830,7 +832,7 @@ Fsub(obj, pat, val) Check_Type(rb_lastline, T_STRING); return Fstr_sub_internal(rb_lastline, pat, val, 1); } - + static VALUE Fgsub(obj, pat, val) VALUE obj, pat, val; diff --git a/struct.c b/struct.c index 819b3526dad9f7..a368605965b490 100644 --- a/struct.c +++ b/struct.c @@ -167,7 +167,7 @@ Fstruct_aref(s, idx) if (TYPE(idx) == T_STRING) return struct_find(rb_intern(RSTRING(idx)->ptr)); - + i = NUM2INT(idx); if (s->len <= i) Fail("offset %d too large for struct(size:%d)", i, s->len); diff --git a/time.c b/time.c index b6c1bd26cb7eae..73f3837ec51833 100644 --- a/time.c +++ b/time.c @@ -30,9 +30,13 @@ struct time_object { static ID id_tv; -#define GetTimeval(obj, tobj) \ - Get_Data_Struct(obj, id_tv, struct time_object, tobj) +#define GetTimeval(obj, tobj) {\ + if (!id_tv) id_tv = rb_intern("tv");\ + Get_Data_Struct(obj, id_tv, struct time_object, tobj);\ +} + #define MakeTimeval(obj,tobj) {\ + if (!id_tv) id_tv = rb_intern("tv");\ Make_Data_Struct(obj, id_tv, struct time_object, Qnil, Qnil, tobj);\ tobj->tm_got=0;\ } @@ -118,7 +122,7 @@ time_timeval(time) static VALUE Stime_at(class, time) VALUE class, time; -{ +{ VALUE obj; int sec, usec; struct time_object *tobj; @@ -557,6 +561,4 @@ 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 88a306841f626c..bdfca0a2cf6842 100644 --- a/variable.c +++ b/variable.c @@ -3,14 +3,13 @@ variable.c - $Author: matz $ - $Date: 1995/01/10 10:43:03 $ + $Date: 1995/01/12 08:54:53 $ created at: Tue Apr 19 23:55:15 JST 1994 ************************************************/ #include "ruby.h" #include "env.h" -#include "node.h" #include "ident.h" #include "st.h" @@ -209,58 +208,6 @@ rb_gvar_get(entry) return Qnil; } -VALUE -rb_ivar_get_1(obj, id) - struct RBasic *obj; - ID id; -{ - VALUE val; - - if (obj->iv_tbl == Qnil) - return Qnil; - if (st_lookup(obj->iv_tbl, id, &val)) - return val; - if (verbose) - Warning("instance var %s not initialized", rb_id2name(id)); - return Qnil; -} - -VALUE -rb_ivar_get(id) - ID id; -{ - return rb_ivar_get_1(Qself, id); -} - -VALUE -rb_mvar_get(id) - ID id; -{ - VALUE val; - - if (st_lookup(class_tbl, id, &val)) return val; - if (verbose) - Warning("local var %s not initialized", rb_id2name(id)); - return Qnil; -} - -VALUE -rb_const_get(id) - ID id; -{ - struct RClass *class = (struct RClass*)CLASS_OF(Qself); - VALUE value; - - while (class) { - if (class->c_tbl && st_lookup(class->c_tbl, id, &value)) { - return value; - } - class = class->super; - } - Fail("Uninitialized constant %s", rb_id2name(id)); - /* not reached */ -} - VALUE rb_gvar_set(entry, val) struct global_entry *entry; @@ -300,14 +247,68 @@ rb_gvar_set2(name, val) return val; } +VALUE +rb_mvar_get(id) + ID id; +{ + VALUE val; + + if (st_lookup(class_tbl, id, &val)) return val; + if (verbose) + Warning("local var %s not initialized", rb_id2name(id)); + return Qnil; +} + +VALUE +rb_ivar_get_1(obj, id) + struct RObject *obj; + ID id; +{ + VALUE val; + + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (obj->iv_tbl && st_lookup(obj->iv_tbl, id, &val)) + return val; + return Qnil; + default: + Fail("class %s can not have instance variables", + rb_class2name(CLASS_OF(obj))); + break; + } + if (verbose) { + Warning("instance var %s not initialized", rb_id2name(id)); + } + return Qnil; +} + +VALUE +rb_ivar_get(id) + ID id; +{ + return rb_ivar_get_1(Qself, id); +} + VALUE rb_ivar_set_1(obj, id, val) - struct RBasic *obj; + struct RObject *obj; ID id; VALUE val; { - if (obj->iv_tbl == Qnil) obj->iv_tbl = new_idhash(); - st_insert(obj->iv_tbl, id, val); + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (obj->iv_tbl == Qnil) obj->iv_tbl = new_idhash(); + st_insert(obj->iv_tbl, id, val); + break; + default: + Fail("class %s can not have instance variables", + rb_class2name(CLASS_OF(obj))); + break; + } return val; } @@ -319,13 +320,30 @@ rb_ivar_set(id, val) return rb_ivar_set_1(Qself, id, val); } -static VALUE -const_bound(class, id) +VALUE +rb_const_get(id) + ID id; +{ + struct RClass *class = (struct RClass*)CLASS_OF(Qself); + VALUE value; + + while (class) { + if (class->iv_tbl && st_lookup(class->iv_tbl, id, &value)) { + return value; + } + class = class->super; + } + Fail("Uninitialized constant %s", rb_id2name(id)); + /* not reached */ +} + +VALUE +rb_const_bound(class, id) struct RClass *class; ID id; { while (class) { - if (class->c_tbl && st_lookup(class->c_tbl, id, Qnil)) { + if (class->iv_tbl && st_lookup(class->iv_tbl, id, Qnil)) { return TRUE; } class = class->super; @@ -339,13 +357,11 @@ rb_const_set(class, id, val) ID id; VALUE val; { - if (const_bound(class, id)) + if (rb_const_bound(class, id)) Fail("already initialized constnant"); - if (class->c_tbl == Qnil) - class->c_tbl = new_idhash(); - - st_insert(class->c_tbl, id, val); + if (class->iv_tbl == Qnil) class->iv_tbl = new_idhash(); + st_insert(class->iv_tbl, id, val); } void diff --git a/version.c b/version.c index aa9028b0e41fc8..27a3182f9cb750 100644 --- a/version.c +++ b/version.c @@ -3,8 +3,8 @@ version.c - $Author: matz $ - $Revision: 1.4 $ - $Date: 1994/12/19 08:30:17 $ + $Revision: 1.5 $ + $Date: 1995/01/12 08:54:54 $ created at: Thu Sep 30 20:08:01 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto diff --git a/version.h b/version.h index ef005b1692cacf..d24ad99a31fd19 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RUBY_VERSION "0.64" -#define VERSION_DATE "95/01/10" +#define RUBY_VERSION "0.65" +#define VERSION_DATE "95/02/08"