From eed5c920dd5429bac6075e9bc98d82360392b424 Mon Sep 17 00:00:00 2001 From: Yukihiro Matsumoto Date: Thu, 13 Oct 1994 12:13:48 +0900 Subject: version 0.51 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://cache.ruby-lang.org/pub/ruby/1.0/ruby-0.51.tar.gz Thu Oct 13 12:13:48 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c(SETUP_ARGS): 付加演算子が配列でない時には配列に変換する. * parse.y: 括弧なしのメソッド呼び出しでも`*'による付加引数が使える ようにした. ただし, 通常引数が一つもない場合は乗算演算子と区別が つかないので, 必ず括弧が必要. Wed Oct 12 10:09:07 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c(rb_call): キャッシュの計算をinline化. キャッシュミスがあ れば関数呼び出しでメソッドを検索する. methods.cはなくなった. * eval.c(rb_eval): ローカル変数用の領域をalloca()するように変更. サイズの変更が必要になれば改めてmalloc()するように. * parse.y: error recoveryの際にlex_stateを更新しておくように. Tue Oct 11 17:10:46 1994 Yukihiro Matsumoto (matz@ix-02) * socket.c(for_fd): ファイル記述子(Fixnum)からソケットインスタンス を得るメソッド. たとえばinetdから起動されたサーバで標準入出力に ソケット操作を行なうために使う. つまりSocket.for_fd($stdin)で標 準入力に対応するソケットオブジェクトが得られる. * io.c(to_i): IOクラスのインスタンスを整数に変換するとそのファイル 記述子を返すように. * numeric.c(num2int): to_iメソッドを使って, できる限り整数に変換す る. 以前はnum2fixだけが全てのオブジェクトに対してto_iメソッドを 適用していた. * sprintf.c(Fsprintf): 整数表示の際, オブジェクトをできる限り整数 に変換するように(to_iメソッドを使う). Fri Oct 7 14:06:32 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c(Fcaller): 必要性がよく分からないのでドキュメントから削除. 将来デバッガを作る時に復活させよう. * eval.c(rb_call): Cで記述されたメソッド呼び出しでは環境をスタック にセーブしないことによって高速化. Wed Oct 5 15:00:58 1994 Yukihiro Matsumoto (matz@ix-02) * ruby.h: 一時env.hに移動してたQselfの定義を復活. ただし今回は関数 として実現(env.hでは変数として再定義してある). * ruby.h: TRUEでsyntax errorにならないよう#undefを追加. * eval.c(rb_eval): thread化に挑戦したが, 失敗(速くならなかった). が, Scopingなどの無駄なコードの削除とメソッド呼び出しの引数セッ トのinline化で若干の高速化を実現した. 副作用として, argc, argv形 式の関数呼び出しの仕様が変化した(argvにselfを含まなくなった). * eval.c(rb_call): メソッド呼び出しの高速化. Tue Oct 4 11:40:53 1994 Yukihiro Matsumoto (matz@ix-02) * ruby-mode.el: 修飾子に対応した. * parse.y: 多重代入にrestをつけた. この機能を使えばoptional引数の 解析が簡単にできる(はず). * pack.c(unpack): uuencode形式のdecodeの際に文字列の長さが間違って いた. Mon Oct 3 15:58:41 1994 Yukihiro Matsumoto (matz@ix-02) * file.c(type): ファイルタイプを文字列で返すメソッド. Fri Sep 30 11:36:07 1994 Yukihiro Matsumoto (matz@ix-02) * object.c: デフォルトの真の値である%TRUEの値を1(Fixnum)からtに変 更した. to_sで文字列に変換した時にも`t'と表示される. 更に踏み込 んで`t'を予約語にしてlispのようにしようかとも思ったが, そこまで は決心できなかった. 一文字のローカル変数はかなり使いそうな気がす るので…. * array.c,dict.c: equalを再定義しているクラスで, hashを正しく定義 した. Wed Sep 28 23:30:28 1994 Yukihiro Matsumoto (matz@dyna) * eval.c(Ffail): 今までfailはカーネルクラスのメソッドであったが, 構文に組み込んだ. この変更によって, 1)`fail'は予約語となり, ロー カル変数に用いることができなくなった. 2)`fail'単体で例外を発生す るようになった. 3)failはメソッドではなくなったので再定義される可 能性がなくなった. * dic.c, dbm.c(indexes): Arrayのindexesと同様の機能を持つメソッド を追加. * array.c(indexes): 引数をインデックスとする要素の配列を返す. 整数 の配列を引数とする時には引数の要素をインデックスとする要素の配列 を返す. Mon Sep 19 13:42:31 1994 Yukihiro Matsumoto (matz@ix-02) * array.c(aset): 部分配列に対する代入で配列以外のオブジェクトが指 定された場合に多重代入と同じルールで配列化するようにした. * io.c(print): 引数として与えられた各オブジェクトにprint_onメッセー ジを与えるように. 実行速度は落ちるが柔軟性は増す. Fri Sep 16 14:59:18 1994 Yukihiro Matsumoto (matz@ix-02) * glob.c: ワイルドカードの導入. bashに使われているGNUのglobルーチ ンを流用した. Mon Sep 12 18:36:58 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y(value_expr): 式がnilの時に対応. * class.c: ICLASSのclassが必ずClass/Moduleを指すように. Tue Sep 6 16:23:28 1994 Yukihiro Matsumoto (matz@ix-02) * re.c: 正規表現内で「\数字」形式が指定できるように. * parse.y:「do expr using var ... end」形式はなくなった. 寂しい気 もする. *BACKWARD INCOMPATIBILITY* Mon Sep 5 10:59:01 1994 Yukihiro Matsumoto (matz@ix-02) * numeric.c(next): Numericクラスにもnextを提供. * string.c(upto): uptoを提供. * range.c(each): nextを使ったインタフェースからuptoを使うように変 更した. この方が一つのメソッドで処理をまとめで行なうことができる. Fri Sep 2 15:25:39 1994 Yukihiro Matsumoto (matz@ix-02) * dict.c(each): 戻り値を[key, value]のペアに変更. 今までのeachは each_valueとして残る. *BACKWARD INCOMPATIBILITY* Thu Sep 1 10:49:04 1994 Yukihiro Matsumoto (matz@ix-02) * 成功した(特別な戻り値を持たない)システムコールは`0'を返すように. Wed Aug 31 00:26:51 1994 Yukihiro Matsumoto (matz@dyna) * string.c: チェックサムを得るメソッド`sum'を作った. * class.c(include_class_new): ICLASSのclassをもとのクラスにした. gcの際に元クラスをマークする必要があるのが, フィールドを増やす余 地が無いので, classフィールドを流用した. 私の見積りが間違ってい て, ICLASSのインスタンスにメッセージを送る事があれば, おかしな動 作をするだろう. * eval.c(masign): 式(a,b = nil)の値を[nil]からnilに変更した. Mon Aug 29 11:56:09 1994 Yukihiro Matsumoto (matz@ix-02) * class.c: rb_define_mfuncを無くして, メタクラスにモジュールをイン クルードするようにした. * error.c(yyerror): 同じ行で複数のsyntax errorをリポートしないよう にした. * file.c: FileTestモジュールにファイルテストメソッドを分離した. * parse.y: 演算子を指定する時のlex_stateを正しく設定した. Sat Aug 27 01:23:34 1994 Yukihiro Matsumoto (matz@dyna) * parse.y: if/whileなどの複合式をprimaryに移動した. これによって例 えば「if cond then a else b end.message()」のような式が書けるよ うになった. Fri Aug 26 10:46:30 1994 Yukihiro Matsumoto (matz@ix-02) * spec: 整理された文法にしたがって書き直した. * parse.y: ここ数日で混乱していた文法を整理した. 括弧を省略したメ ソッド呼び出しができるようになったこと, modifierが付けられるよう になったこと, returnにリストが渡せるようになったことが主な変更点 である. * process周りが怪しいがとにかくSolaris 2.3で動くように. * parse.y: 曖昧性がない場合にはメソッド呼び出しの引数の括弧を省略 できるように. 省略できるメソッド呼び出しの条件は, 1)かならず1個 以上の引数を必要とすること, 2)第1引数が`+', `-', `(', `[', `{', `/'など, 式の始まりに置かれた時と途中に現れた時とで解釈が違う記 号で始まらないこと, である. Thu Aug 25 13:54:58 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y(cond): 条件式の展開部にbugがあった. Wed Aug 24 00:01:15 1994 Yukihiro Matsumoto (matz@dyna) * parse.y: returnはコンマで区切ったリストも受け取るように. つまり, return a, b, cはreturn [a, b, c]と同じ意味になる. * parse.y: yield以外の大域脱出制御式をexprからexpr0に移した. よっ てメソッドの引数に制御式を使えなくなる(これで困る人はいないはず). * parse.y: `+'の定数展開の際に演算子の優先順位を忘れていた. * eval.c: untilの戻り値はnilになった. * parse.y: modifierとしてのif/unless/while/untilを追加. * parse.y: 文法からendの後ろにつけるキーワードを削除. ほとんど使わ なかった上に, emacsではruby-modeがあれば対応のチェックが機械的に 出来るため. Tue Aug 23 18:08:33 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c: スクリプト実行開始前に例外が発生した時にcore dumpした. 組み込み用にコードを変更した時にenbugしてしまった. Tue Aug 23 00:07:17 1994 Yukihiro Matsumoto (matz@dyna) * eval.c: doの戻り値がいつもnilになっていた. * parse.y: loop制御変数の多重代入化にbugがあった. * parse.y(expand_op): 文字列も畳み込みの対象に. Mon Aug 22 10:50:01 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y(expand_op): `+'に関しては結合則を使って, より多く定数畳 み込みを行なうように. * ruby.c(proc_options): argcが0の時にも対応. * parse.y: forなどの制御変数に多重代入も使えるように. Sat Aug 20 00:59:40 1994 Yukihiro Matsumoto (matz@dyna) * parse.y(call_op): 演算子`~'の取り扱いをルール部へ移動. Fri Aug 19 11:44:13 1994 Yukihiro Matsumoto (matz@ix-02) * main.c: rubyをほかのプログラムに組み込めるようにmain()を分割した. それにともない, プログラムの呼び出し構造を修正した. * parse.y: 条件式の定義を変更. ifなどの条件式の中でだけ`&&'や`||' および`!'の引数が条件式になるように. この変更により条件式以外の 場所での `&&', `||', `!'演算子の動作が直観に一致する. * parse.y: 実引数の`*'の後に続く引数はexprに制限した. 今までは全て の文が有効であったが, ここで定義文があってもしょうがない. Thu Aug 18 10:21:45 1994 Yukihiro Matsumoto (matz@ix-02) * re.c: 正規表現ルーチンの初期化部分を削除してしまっていた. これで はemacsの正規表現になってしまう. * version.c: copyright表示を追加. * version.c: バージョン表示をstderrに. * configure.in: gccがない場合testに失敗していた. Fri Aug 12 14:12:23 1994 Yukihiro Matsumoto (matz@ix-02) * array.c(astore): 配列の拡大する時にある程度の大きさをまとめて拡 大するように. * io.c(Fprint): 配列に対しては一度文字列に変換することなく, 直接内 容を出力するように. * string.c(str_new): memmoveからmemcpyへ置き換えた. これでもかなり 速度が違う. * ruby.h: データメンバの取り出しで名前を文字列からIDで指定するよう にした. かなりの高速化になる. * io.c: $ARGFという変数で引数列からなる仮想ファイルをオブジェクト として扱えるようにした. 今まではトップレベルのgets()などを使って アクセスしていたが, どうもオブジェクト指向的ではなかった. Thu Aug 11 11:43:15 1994 Yukihiro Matsumoto (matz@ix-02) * gc.c: mark_location()の間違った呼び出し方の行が残っていた. * method.c: プロトタイプ宣言が足りなかった. --- eval.c | 881 +++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 499 insertions(+), 382 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index 7a69a22a75..4a7241e7f7 100644 --- a/eval.c +++ b/eval.c @@ -3,7 +3,7 @@ eval.c - $Author: matz $ - $Date: 1994/06/27 15:48:23 $ + $Date: 1994/08/24 09:25:28 $ created at: Thu Jun 10 14:22:17 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -11,23 +11,183 @@ ************************************************/ #include "ruby.h" +#include "ident.h" #include "env.h" #include "node.h" -#include "ident.h" +#include "methods.h" + #include #include #include "st.h" +void method_free(); +void rb_clear_cache(); + +/* #define TEST /* prints cache miss */ +#ifdef TEST +#include +#endif + +#if 1 +#define CACHE_SIZE 0x200 +#define CACHE_MASK 0x1ff +#define EXPR1(c,m) ((((int)(c)>>3)^(m))&CACHE_MASK) + +#else + +#define CACHE_SIZE 577 +#define EXPR1(c,m) (((int)(c)^(m))%CACHE_SIZE) +#endif + +struct cache_entry { /* method hash table. */ + ID mid; /* method's id */ + struct RClass *class; /* receiver's class */ + struct RClass *origin; /* where method defined */ + struct SMethod *method; + int undef; +}; + +static struct cache_entry cache[CACHE_SIZE]; + +static struct SMethod* +search_method(class, id, origin) + struct RClass *class, **origin; + ID id; +{ + struct SMethod *body; + NODE *list; + + while (!st_lookup(class->m_tbl, id, &body)) { + class = class->super; + if (class == Qnil) return Qnil; + } + + if (body->origin) + *origin = body->origin; + else + *origin = class; + return body; +} + +static NODE* +rb_get_method_body(classp, idp) + struct RClass **classp; + ID *idp; +{ + int pos, i; + ID id = *idp; + struct RClass *class = *classp; + struct SMethod *method; + struct SMethod *body; + struct RClass *origin; + struct cache_entry *ent; + + if ((body = search_method(class, id, &origin)) == Qnil) { + return Qnil; + } + + ent = cache + EXPR1(class, id); +#ifdef TEST + if (ent->mid != 0) { + fprintf(stderr, "0x%x 0x%x %x\n", class, id, EXPR1(class, id)); + } +#endif + /* store in cache */ + ent->mid = id; + ent->class = class; + ent->origin = origin; + ent->method = body; + ent->undef = body->undef; + + if (ent->undef) return Qnil; + *idp = ent->method->id; + *classp = ent->origin; + return ent->method->node; +} + +VALUE +rb_method_boundp(class, id) + struct RClass *class; + ID id; +{ + if (rb_get_method_body(&class, &id)) + return TRUE; + return FALSE; +} + +void +rb_alias(class, name, def) + struct RClass *class; + ID name, def; +{ + struct SMethod *body; + + if (st_lookup(class->m_tbl, name, &body)) { + if (verbose) { + Warning("redefine %s", rb_id2name(name)); + } + rb_clear_cache(body); + method_free(body); + } + body = search_method(class, def, &body); + body->count++; + st_insert(class->m_tbl, name, body); +} + +void +rb_clear_cache(body) + struct SMethod *body; +{ + struct cache_entry *ent, *end; + + ent = cache; end = ent + CACHE_SIZE; + while (ent < end) { + if (ent->method == body) { + ent->class = Qnil; + ent->mid = Qnil; + } + ent++; + } +} + +void +rb_clear_cache2(class) + struct RClass *class; +{ + struct cache_entry *ent, *end; + + ent = cache; end = ent + CACHE_SIZE; + while (ent < end) { + if (ent->origin == class) { + ent->class = Qnil; + ent->mid = Qnil; + } + ent++; + } +} + +void +method_free(body) + struct SMethod *body; +{ + body->count--; + if (body->count == 0) { + freenode(body->node); + free(body); + } +} + static ID match, each; VALUE errstr, errat; extern NODE *eval_tree; +extern int nerrs; extern VALUE TopSelf; struct ENVIRON *the_env, *top_env; #define PUSH_ENV() {\ struct ENVIRON _this;\ - if (the_env) _this = *the_env; else bzero(&_this, sizeof(_this));\ + _this = *the_env;\ _this.prev = the_env;\ _this.flags = 0;\ the_env = &_this;\ @@ -51,6 +211,8 @@ static struct tag { jmp_buf buf; struct gc_list *gclist; struct ENVIRON *env; + VALUE self; + int ilevel; } *prot_tag; #define PUSH_TAG() {\ @@ -59,6 +221,8 @@ static struct tag { &_oldtag;\ _this.level= ++tag_level;\ _this.env= the_env;\ + _this.self= Qself;\ + _this.ilevel= the_env->iterator;\ prot_tag = &_this;\ #define POP_TAG() \ @@ -69,6 +233,8 @@ static struct tag { #define EXEC_TAG() (setjmp(prot_tag->buf)) #define JUMP_TAG(val) {\ the_env = prot_tag->env;\ + the_env->iterator = prot_tag->ilevel;\ + Qself = prot_tag->self;\ longjmp(prot_tag->buf,(val));\ } @@ -85,11 +251,12 @@ static struct tag { static VALUE rb_eval(); VALUE Feval(); -VALUE Argv; static VALUE rb_call(); VALUE rb_apply(); VALUE rb_xstring(); +void rb_fail(); +static VALUE masign(); static void asign(); static VALUE last_val; @@ -99,6 +266,12 @@ extern VALUE rb_stderr; extern int sourceline; extern char *sourcefile; +VALUE +rb_self() +{ + return Qself; +} + static ID last_func; static void error_print() @@ -123,71 +296,36 @@ error_print() exit(1); } -static int origargc; -static char **origargv; - -main(argc, argv) +void +ruby_init(argc, argv, envp) int argc; - char *argv[]; + char **argv, **envp; { int state; + static struct ENVIRON top_env; + the_env = &top_env; - origargc = argc; origargv = argv; - Init_stack(); - PUSH_ENV(); - top_env = the_env; PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { - rb_main(argc, argv); + ruby_init0(argc, argv, envp); } POP_TAG(); - - switch (state) { - case 0: - break; - case TAG_RETURN: - Fatal("unexpected return"); - break; - case TAG_CONTINUE: - Fatal("unexpected continue"); - break; - case TAG_BREAK: - Fatal("unexpected break"); - break; - case TAG_REDO: - Fatal("unexpected redo"); - break; - case TAG_RETRY: - Fatal("retry outside of protect clause"); - break; - case TAG_FAIL: - PUSH_TAG() + if (state) { + PUSH_TAG(); error_print(); POP_TAG(); - break; - case TAG_EXIT: - rb_trap_exit(); - exit(FIX2UINT(last_val)); - break; - default: - Bug("Unknown longjmp status %d", state); - break; } - POP_ENV(); - exit(0); } VALUE rb_readonly_hook(); -static VALUE Progname; - static VALUE Eval(toplevel) int toplevel; { VALUE result; NODE *tree; - int state; + int state; if (match == Qnil) match = rb_intern("=~"); if (each == Qnil) each = rb_intern("each"); @@ -199,79 +337,72 @@ Eval(toplevel) result = rb_eval(tree); } POP_TAG(); +/* #define PURIFY_D /* define when purify'ing */ +#ifdef PURIFY_D + freenode(tree); +#else /* you don't have to free at toplevel */ if (!toplevel) freenode(tree); +#endif if (state) JUMP_TAG(state); return result; } -static VALUE -set_arg0(val, id) - VALUE val; - ID id; -{ - char *s; - int i; - static int len; - - Check_Type(val, T_STRING); - if (len == 0) { - s = origargv[0]; - s += strlen(s); - /* See if all the arguments are contiguous in memory */ - for (i = 1; i < origargc; i++) { - if (origargv[i] == s + 1) - s += strlen(++s); /* this one is ok too */ - } - len = s - origargv[0]; - } - s = RSTRING(val)->ptr; - i = RSTRING(val)->len; - if (i > len) { - memcpy(origargv[0], s, len); - origargv[0][len] = '\0'; - } - else { - memcpy(origargv[0], s, i); - s = origargv[0]+i; - *s++ = '\0'; - while (++i < len) - *s++ = ' '; - } - Progname = str_new2(origargv[0]); - - return val; -} - -VALUE -TopLevel(script, argc, argv) - char *script; - int argc; - char **argv; +ruby_run() { - int i; + int state; - the_class = (struct RClass*)C_Object; + if (nerrs > 0) exit(nerrs); + Init_stack(); rb_define_variable("$!", &errstr, Qnil, Qnil); errat = Qnil; /* clear for execution */ - Progname = str_new2(script); - rb_define_variable("$0", &Progname, Qnil, set_arg0); + PUSH_ENV(); + top_env = the_env; + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + int i; - rb_define_variable("$ARGV", &Argv, Qnil, Qnil); - rb_define_variable("$*", &Argv, Qnil, Qnil); - Argv = ary_new2(argc); - for (i=0; i < argc; i++) { - Fary_push(Argv, str_new2(argv[i])); + the_class = (struct RClass*)C_Object; + Eval(1); } -#define PURIFY_D -#ifdef PURIFY_D - return Eval(0); -#else - return Eval(1); -#endif + POP_TAG(); + + switch (state) { + case 0: + break; + case TAG_RETURN: + Fatal("unexpected return"); + break; + case TAG_CONTINUE: + Fatal("unexpected continue"); + break; + case TAG_BREAK: + Fatal("unexpected break"); + break; + case TAG_REDO: + Fatal("unexpected redo"); + break; + case TAG_RETRY: + Fatal("retry outside of protect clause"); + break; + case TAG_FAIL: + PUSH_TAG(); + error_print(); + POP_TAG(); + break; + case TAG_EXIT: + rb_trap_exit(); + exit(FIX2UINT(last_val)); + break; + default: + Bug("Unknown longjmp status %d", state); + break; + } + POP_ENV(); + exit(0); } void @@ -289,61 +420,38 @@ rb_trap_eval(cmd) POP_ENV(); } -static int -setup_arg_1(node, args) - NODE *node; - VALUE *args; -{ - int argc; - - if (node->type == NODE_ARRAY) { - for (argc=0; node; node=node->nd_next) argc++; - argc++; - } - else { - *args = rb_eval(node); - if (TYPE(*args) != T_ARRAY) - Fail("*`argument' must be array"); - argc = RARRAY(*args)->len + 1; - } - return argc; -} - -static void -setup_arg_2(node, args, argc, argv) - NODE *node; - VALUE args; - int argc; - VALUE *argv; -{ - int i; - - bzero(argv, sizeof(VALUE)*argc); - if (node->type == NODE_ARRAY) { - for (i=1;node;node=node->nd_next) { - argv[i++] = rb_eval(node->nd_head); - } - } - else { - for (i=1;iptr[i-1]; - } - } -} - #define SETUP_ARGS {\ - VALUE args = Qnil;\ - argc = setup_arg_1(node->nd_args, &args);\ - argv = (VALUE*)alloca(sizeof(VALUE)*argc);\ - setup_arg_2(node->nd_args, args, argc, argv);\ + NODE *n = node->nd_args;\ + if (!n) {\ + argc = 0;\ + argv = Qnil;\ + }\ + else if (n->type == NODE_ARRAY) {\ + int i;\ + for (argc=0; n; n=n->nd_next) argc++;\ + if (argc > 0) {\ + n = node->nd_args;\ + argv = (VALUE*)alloca(sizeof(VALUE)*argc);\ + for (i=0;n;n=n->nd_next) {\ + argv[i++] = rb_eval(n->nd_head);\ + }\ + }\ + }\ + else {\ + args = rb_eval(n);\ + if (TYPE(args) != T_ARRAY)\ + args = rb_to_a(args);\ + argc = RARRAY(args)->len;\ + argv = RARRAY(args)->ptr;\ + }\ } static VALUE rb_eval(node) register NODE *node; { - int state; - int go_out = 0; + int state; + int go_out = 0; VALUE result; &go_out; @@ -388,34 +496,6 @@ rb_eval(node) if (node) goto again; return Qnil; - case NODE_UNLESS: - { - VALUE res; - - PUSH_TAG(); - if ((state = EXEC_TAG()) == 0) { - res = rb_eval(node->nd_cond); - } - POP_TAG(); - if (state == 0) - ; - else if (state == TAG_FAIL) { - res = Qnil; - } - else { - JUMP_TAG(state); - } - - if (res == Qnil) { - node = node->nd_body; - } - else { - node = node->nd_else; - } - if (node) goto again; - return res; - } - case NODE_CASE: { VALUE val; @@ -441,6 +521,29 @@ rb_eval(node) } return Qnil; + case NODE_EXNOT: + { + VALUE res; + + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + res = rb_eval(node->nd_cond); + break; + + case TAG_FAIL: + res = Qnil; + break; + + default: + go_out++; + } + POP_TAG(); + if (go_out) JUMP_TAG(state); + if (res) return FALSE; + return TRUE; + } + case NODE_WHILE: PUSH_TAG(); switch (state = EXEC_TAG()) { @@ -465,47 +568,29 @@ rb_eval(node) if (go_out) JUMP_TAG(state); return Qnil; - case NODE_UNTIL: - for (;;) { - VALUE res; - - PUSH_TAG(); - switch (state = EXEC_TAG()) { - case 0: - res = rb_eval(node->nd_cond); - break; - - case TAG_FAIL: - res = Qnil; - break; - - default: - go_out++; - } - POP_TAG(); - if (go_out) JUMP_TAG(state); - if (res) return res; - - PUSH_TAG(); - switch (state = EXEC_TAG()) { - case 0: - until_redo: + case NODE_WHILE2: + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + while2_cont: + do { + while2_redo: rb_eval(node->nd_body); - break; - case TAG_REDO: - goto until_redo; - case TAG_CONTINUE: - break; - case TAG_BREAK: - goto until_break; - default: - go_out++; - } - POP_TAG(); - if (go_out) JUMP_TAG(state); + } while (rb_eval(node->nd_cond)); + break; + case TAG_REDO: + goto while2_redo; + case TAG_CONTINUE: + goto while2_cont; + default: + go_out++; + case TAG_BREAK: + break; } - until_break: - break; + while2_out: + POP_TAG(); + if (go_out) JUMP_TAG(state); + return Qnil; case NODE_DO: case NODE_FOR: @@ -520,14 +605,14 @@ rb_eval(node) if (state == 0) { if (node->type == NODE_DO) { the_env->iterator = 1; - rb_eval(node->nd_iter); + result = rb_eval(node->nd_iter); } else { VALUE recv; recv = rb_eval(node->nd_iter); the_env->iterator = 1; - result = rb_call(CLASS_OF(recv), recv, each, 1, Qnil, 0); + result = rb_call(CLASS_OF(recv), recv, each, 0, Qnil); } } POP_TAG(); @@ -552,6 +637,14 @@ rb_eval(node) } return result; + case NODE_FAIL: + { + VALUE mesg = rb_eval(node->nd_stts); + if (mesg) Check_Type(mesg, T_STRING); + rb_fail(mesg); + return Qnil; /* not reached */ + } + case NODE_YIELD: { VALUE val; @@ -634,6 +727,10 @@ rb_eval(node) JUMP_TAG(TAG_CONTINUE); break; + case NODE_REDO: + JUMP_TAG(TAG_REDO); + break; + case NODE_RETRY: JUMP_TAG(TAG_RETRY); break; @@ -648,17 +745,12 @@ rb_eval(node) { VALUE recv, *argv; int argc, last_iter; + VALUE args = Qnil; /* used in SETUP_ARGS */ last_iter = the_env->iterator; the_env->iterator = 0; /* recv & args are not iter. */ recv = node->nd_recv?rb_eval(node->nd_recv):Qself; - if (node->nd_args) { - SETUP_ARGS; - } - else { - argc = 1; - argv = &recv; - } + SETUP_ARGS; the_env->iterator = last_iter; /* restore iter. level */ return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv); @@ -671,20 +763,17 @@ rb_eval(node) int last_iter; int i, argc; VALUE *argv; + VALUE args = Qnil; /* used in SETUP_ARGS */ last_iter = the_env->iterator; /* recv & args are not iter. */ the_env->iterator = 0; - if (node->nd_args) { - SETUP_ARGS; - } - else if (node->type == NODE_ZSUPER) { + if (node->type == NODE_ZSUPER) { argc = the_env->argc; argv = the_env->argv; } else { - argc = 1; - argv = Qnil; + SETUP_ARGS; } /* restore iter. level */ @@ -707,23 +796,23 @@ rb_eval(node) { VALUE result; - PUSH_ENV(); PUSH_TAG(); if (node->nd_cnt > 0) { - the_env->local_vars = ALLOC_N(VALUE, node->nd_cnt); - bzero(the_env->local_vars, sizeof(VALUE)*node->nd_cnt); + the_env->local_vars = alloca(sizeof(VALUE)*node->nd_cnt); + memset(the_env->local_vars, 0, sizeof(VALUE)*node->nd_cnt); the_env->local_tbl = node->nd_tbl; } else { the_env->local_vars = Qnil; - the_env->local_tbl = Qnil; + the_env->local_tbl = Qnil; } if ((state = EXEC_TAG()) == 0) { result = rb_eval(node->nd_body); } POP_TAG(); - if (the_env->local_vars) free(the_env->local_vars); - POP_ENV(); + if (the_env->local_vars && (the_env->flags&VARS_MALLOCED)) + free(the_env->local_vars); + the_env->local_vars = Qnil; if (state != 0) JUMP_TAG(state); return result; @@ -732,25 +821,7 @@ rb_eval(node) case NODE_MASGN: { VALUE val = rb_eval(node->nd_value); - NODE *list = node->nd_head; - int i, len; - - if (TYPE(val) != T_ARRAY) { - val = rb_funcall(val, rb_intern("to_a"), 0, Qnil); - if (TYPE(val) != T_ARRAY) { - Bug("to_a did not return Array"); - } - } - len = RARRAY(val)->len; - for (i=0; list && ind_head, RARRAY(val)->ptr[i]); - list = list->nd_next; - } - while (list) { - asign(list->nd_head, Qnil); - list = list->nd_next; - } - return val; + return masign(node, val); } case NODE_LASGN: @@ -856,6 +927,7 @@ rb_eval(node) case NODE_STR2: case NODE_XSTR2: case NODE_DREGX: + case NODE_DGLOB: { VALUE str, str2; NODE *list = node->nd_next; @@ -877,9 +949,12 @@ rb_eval(node) if (node->type == NODE_DREGX) { return regexp_new(RSTRING(str)->ptr, RSTRING(str)->len); } - else if (node->type == NODE_XSTR2) { + if (node->type == NODE_XSTR2) { return rb_xstring(str); } + if (node->type == NODE_DGLOB) { + return glob_new(str); + } return str; } @@ -890,9 +965,9 @@ rb_eval(node) return node->nd_lit; case NODE_ATTRSET: - if (the_env->argc != 2) - Fail("Wrong # of arguments(%d for 1)", the_env->argc - 1); - return rb_ivar_set(node->nd_vid, the_env->argv[1]); + if (the_env->argc != 1) + Fail("Wrong # of arguments(%d for 1)", the_env->argc); + return rb_ivar_set(node->nd_vid, the_env->argv[0]); case NODE_ARGS: { @@ -900,7 +975,7 @@ rb_eval(node) int i, len; i = node->nd_cnt; - len = the_env->argc - 1; + len = the_env->argc; if (i > len || (node->nd_rest == -1 && i < len)) Fail("Wrong # of arguments(%d for %d)", len, i); @@ -909,15 +984,15 @@ rb_eval(node) Bug("unexpected local variable asignment"); for (i=1;local;i++) { - the_env->local_vars[(int)local->nd_head] = the_env->argv[i]; + the_env->local_vars[(int)local->nd_head] = the_env->argv[i-1]; local = local->nd_next; } if (node->nd_rest >= 0) { - if (the_env->argc == 1) + if (the_env->argc == 0) the_env->local_vars[node->nd_rest] = ary_new(); else the_env->local_vars[node->nd_rest] = - ary_new4(the_env->argc-i, the_env->argv+i); + ary_new4(the_env->argc-i+1, the_env->argv+i-1); } } return Qnil; @@ -1053,7 +1128,7 @@ obj_responds_to(obj, msg) id = rb_intern(msg->ptr); } - if (rb_get_method_body(CLASS_OF(obj), id, 0)) { + if (rb_method_boundp(CLASS_OF(obj), id)) { return TRUE; } return FALSE; @@ -1147,19 +1222,6 @@ rb_fail(mesg) } VALUE -Ffail(self, args) - VALUE self, args; -{ - VALUE mesg; - - rb_scan_args(args, "01", &mesg); - - if (mesg) Check_Type(mesg, T_STRING); - rb_fail(mesg); - - return Qnil; /* not reached */ -} - iterator_p() { return ITERATOR_P(); @@ -1170,10 +1232,10 @@ rb_yield(val) VALUE val; { struct BLOCK *block; - int state; - int go_out; + int state; + int go_out; VALUE result; - int cnt; + int cnt; &go_out; block = the_env->block; @@ -1186,7 +1248,10 @@ rb_yield(val) the_env = &(block->env); the_env->flags = the_env->prev->flags; if (block->var) { - asign(block->var, val); + if (block->var->type == NODE_MASGN) + masign(block->var, val); + else + asign(block->var, val); } go_out = 0; @@ -1221,6 +1286,44 @@ rb_yield(val) return result; } +static VALUE +masign(node, val) + NODE *node; + VALUE val; +{ + NODE *list; + int i, len; + + list = node->nd_head; + + if (val) { + if (TYPE(val) != T_ARRAY) { + val = rb_to_a(val); + } + len = RARRAY(val)->len; + for (i=0; list && ind_head, RARRAY(val)->ptr[i]); + list = list->nd_next; + } + if (node->nd_args) { + if (!list && ind_args, ary_new4(len-i, RARRAY(val)->ptr+i)); + } + else { + asign(node->nd_args, ary_new()); + } + } + } + else if (node->nd_args) { + asign(node->nd_args, ary_new()); + } + while (list) { + asign(list->nd_head, Qnil); + list = list->nd_next; + } + return val; +} + static void asign(lhs, val) NODE *lhs; @@ -1275,7 +1378,7 @@ rb_iterate(it_proc, data1, bl_proc, data2) VALUE (*it_proc)(), (*bl_proc)(); char *data1, *data2; { - int state; + int state; VALUE retval; NODE *node = NEW_CFUNC(bl_proc, data2); struct BLOCK block; @@ -1324,8 +1427,8 @@ rb_resque(b_proc, data1, r_proc, data2) VALUE (*b_proc)(), (*r_proc)(); char *data1, *data2; { - int state; - int go_out; + int state; + int go_out; VALUE result; &go_out; @@ -1375,7 +1478,7 @@ rb_ensure(b_proc, data1, e_proc, data2) VALUE (*b_proc)(), (*e_proc)(); char *data1, *data2; { - int state; + int state; VALUE result; PUSH_TAG(); @@ -1396,7 +1499,7 @@ struct st_table *new_idhash(); static void rb_undefined(obj, id) VALUE obj; - ID id; + ID id; { VALUE desc = obj_as_string(obj); @@ -1413,126 +1516,133 @@ static VALUE rb_call(class, recv, mid, argc, argv) struct RClass *class; VALUE recv, *argv; - int argc; - ID mid; + int argc; + ID mid; { - int state; - int go_out = 0; - int c = argc - 1; - NODE *body; - VALUE result; + int state, go_out; + NODE *body; + VALUE result; + VALUE saved_self = Qself; + int saved_ilevel = the_env->iterator; + struct cache_entry *ent; + ID id; - &go_out; - PUSH_ENV(); - the_env->flags |= DURING_CALL; - the_env->argc = argc; - the_env->argv = argv; Qself = recv; - if (argv) argv[0] = recv; if (the_env->iterator != 0) the_env->iterator++; - if ((body = rb_get_method_body(class, mid, 1)) == Qnil) { - rb_undefined(recv, mid); + /* is it in the method cache? */ + ent = cache + EXPR1(class, mid); + if (ent->class == class && ent->mid == mid) { + if (ent->undef) rb_undefined(recv, mid); + class = ent->origin; + id = ent->method->id; + body = ent->method->node; + } + else { + id = mid; + if ((body = rb_get_method_body(&class, &id)) == Qnil) { + rb_undefined(recv, mid); + } } if (body->type == NODE_CFUNC) { int len = body->nd_argc; - if (len >= 0 && c != len) { - Fail("Wrong # of arguments for(%d for %d)", c, body->nd_argc); + if (len >= 0 && argc != len) { + Fail("Wrong # of arguments for(%d for %d)", argc, body->nd_argc); } if (len == -2) { - result = (*body->nd_cfnc)(recv, ary_new4(argc-1, argv+1)); + result = (*body->nd_cfnc)(recv, ary_new4(argc, argv)); } else if (len == -1) { result = (*body->nd_cfnc)(argc, argv); } else if (len >= 0) { - switch (c) { + switch (argc) { case 0: result = (*body->nd_cfnc)(recv); break; case 1: - result = (*body->nd_cfnc)(recv, argv[1]); + result = (*body->nd_cfnc)(recv, argv[0]); break; case 2: - result = (*body->nd_cfnc)(recv, argv[1], argv[2]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1]); break; case 3: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2]); break; case 4: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3]); break; case 5: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4]); break; case 6: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); break; case 7: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6]); break; case 8: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7]); break; case 9: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8]); break; case 10: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9]); break; case 11: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10]); break; case 12: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11]); break; case 13: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12], - argv[13]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11], + argv[12]); break; case 14: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12], - argv[13], argv[14]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11], + argv[12], argv[13]); break; case 15: - result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], - argv[4], argv[5], argv[6], - argv[7], argv[8], argv[9], - argv[7], argv[8], argv[9], - argv[10], argv[11], argv[12], - argv[13], argv[14], argv[15]); + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], + argv[6], argv[7], argv[8], + argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14]); break; default: Fail("too many arguments(%d)", len); @@ -1545,15 +1655,25 @@ rb_call(class, recv, mid, argc, argv) } } else { - the_env->file = sourcefile; - the_env->line = sourceline; + PUSH_ENV(); + the_env->local_vars = Qnil; the_env->local_tbl = Qnil; + the_env->flags |= DURING_CALL; + the_env->argc = argc; + the_env->argv = argv; + the_env->last_class = class; + the_env->last_func = id; +#ifdef USE_CALLER + the_env->file = sourcefile; + the_env->line = sourceline; +#endif PUSH_TAG(); switch (state = EXEC_TAG()) { case 0: result = rb_eval(body); + go_out=0; break; case TAG_CONTINUE: Fatal("unexpected continue"); @@ -1571,14 +1691,14 @@ rb_call(class, recv, mid, argc, argv) result = last_val; break; default: - go_out++; + go_out=1; } POP_TAG(); + POP_ENV(); + if (go_out) JUMP_TAG(state); } - - POP_ENV(); - - if (go_out) JUMP_TAG(state); + Qself = saved_self; + the_env->iterator = saved_ilevel; return result; } @@ -1627,30 +1747,27 @@ rb_funcall(recv, mid, n, va_alist) va_dcl { va_list ar; - int argc; VALUE *argv; if (n > 0) { int i; - argc = n + 1; - argv = (VALUE*)alloca(sizeof(VALUE)*argc); + argv = (VALUE*)alloca(sizeof(VALUE)*n); va_start(ar); - for (i=1;ifile == Qnil) Fail("initial frame"); file = str_new2(e->file); - ary = e->argv?ary_new4(e->argc, e->argv):ary_new3(1, Qself); - res = ary_new3(4, file, INT2FIX(e->line), - str_new2(rb_id2name(e->last_func)), ary); + ary = e->argv?ary_new4(e->argc, e->argv):ary_new2(0); + res = ary_new3(5, file, INT2FIX(e->line), + str_new2(rb_id2name(e->last_func)), Qself, ary); return res; } +#endif int in_eval = 0; -extern int nerrs; VALUE Feval(obj, src) @@ -1855,7 +1972,7 @@ Frequire(obj, fname) } char *getenv(); -char *index(); +char *strchr(); #ifndef RUBY_LIB #define RUBY_LIB "/usr/local/lib/ruby:." @@ -1874,7 +1991,7 @@ addpath(path) p = s = path; while (*p) { while (*p == RUBY_LIB_SEP) p++; - if (s = index(p, RUBY_LIB_SEP)) { + if (s = strchr(p, RUBY_LIB_SEP)) { Fary_push(rb_load_path, str_new(p, (int)(s-p))); p = s + 1; } -- cgit v1.2.3