From 5d828b25d4ae30a000c054a724ac248dadbb97b3 Mon Sep 17 00:00:00 2001 From: Yukihiro Matsumoto Date: Tue, 10 Jan 1995 00:58:20 +0900 Subject: version 0.64 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.64.tar.gz Tue Jan 10 00:58:20 1995 Yukihiro Matsumoto (matz@dyna) * eval.c: レシーバと引数は常にiterではない. * cons.c(aref,aset): negative offset対応. Mon Jan 9 14:40:39 1995 Yukihiro Matsumoto (matz@ix-02) * parse.y: foo{..}の形式において,fooをローカル変数やクラス名では なく,引数なしの関数型メソッド呼び出しとみなすようにした. * list.c -> cons.c: 名称変更(クラス名も). * list.c: a::b::c::nilをリスト(a b c)とみなすlisp形式から,a::b::c をリスト(a b c)とみなすruby形式に変更.[], []=, eachもそれに会わ せた仕様とする. * list.c: consペアとしての機能を強調.仕様変更. Sat Jan 7 01:26:26 1995 Yukihiro Matsumoto (matz@dyna) * eval.c: 自己代入の不具合修正. * eval.c(masign): 多重代入が配列もリストもとれるようにした. * list.c: assocを2要素の配列からList(CONSペア)に変更した. Fri Jan 6 13:42:12 1995 Yukihiro Matsumoto (matz@ix-02) * parse.y: a[b]+=cやa.b+=cなどの自己代入形式で,aやbを2度評価しな くなった. * eval.c: iterator設定のバグフィックス. * list.c: Listクラスを新設. Thu Jan 5 13:55:00 1995 Yukihiro Matsumoto (matz@ix-02) * parse.y: SCOPEのメモリリークをなくした. * eval.c: built-inメソッドへの引数の引き渡し方を変更して,配列の生 成数を減らした. * re.c: match-dataを毎回生成することをやめた.`$~'をアクセスした時 にon-demandで生成する. * string.c etc: 不必要なmemmoveをmemcpyに置換. * parse.y: =~, !~は副作用があるのでコンパイル時に展開できない. Tue Jan 3 02:04:36 1995 Yukihiro Matsumoto (matz@dyna) * eval.c: rest引数のbug fix. * eval.c,gc.c: scopeをオブジェクトにした. * eval.c: envとscopeの扱いを変更した. Wed Dec 28 09:46:57 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y: evalでローカル変数が追加された場合に対応した. * parse.y: 演算子を含むaliasのbug fix. Tue Dec 27 16:45:20 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y: def A Bをalias A Bに変更. * eval.c: alias関係のbug修正.nodeをオブジェクト化した時にenbugし たようだ. * signal.c: システムコールの再定義を止めた. * io.c(select): write/exceptのフラグ設定にバグ. * Makefile.in: static link用オプションをMake変数として独立させた. --- eval.c | 785 +++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 446 insertions(+), 339 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index 952d8c2f7d..c54fa14e5e 100644 --- a/eval.c +++ b/eval.c @@ -3,7 +3,7 @@ eval.c - $Author: matz $ - $Date: 1994/12/20 05:07:05 $ + $Date: 1995/01/10 10:42:34 $ created at: Thu Jun 10 14:22:17 JST 1993 Copyright (C) 1994 Yukihiro Matsumoto @@ -26,17 +26,10 @@ void rb_clear_cache(); #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 */ @@ -79,6 +72,7 @@ rb_get_method_body(classp, idp, noexp) if ((body = search_method(class, id, &origin)) == Qnil) { return Qnil; } + if (body->nd_body == Qnil) return Qnil; ent = cache + EXPR1(class, id); #ifdef TEST @@ -87,19 +81,20 @@ rb_get_method_body(classp, idp, noexp) } #endif /* store in cache */ - ent->mid = id; ent->class = class; - ent->origin = origin; - ent->method = body->nd_body; ent->noex = body->nd_noex; body = body->nd_body; - - if (body == Qnil) return Qnil; if (nd_type(body) == NODE_FBODY) { - *idp = body->nd_mid; - body = body->nd_head; + *classp = ent->origin = (struct RClass*)body->nd_orig; + *idp = ent->mid = body->nd_mid; + body = ent->method = body->nd_head; } - *classp = origin; + else { + *classp = ent->origin = origin; + ent->mid = id; + ent->method = body; + } + if (noexp) *noexp = ent->noex; return body; } @@ -114,7 +109,7 @@ rb_alias(class, name, def) if (name == def) return; body = search_method(class, def, &origin); - if (body == Qnil) { + if (body == Qnil || body->nd_body == Qnil) { Fail("undefined method `%s' for class `%s'", rb_id2name(def), rb_class2name(class)); } @@ -126,8 +121,9 @@ rb_alias(class, name, def) rb_clear_cache(old->nd_body); } - st_insert(class->m_tbl, name, NEW_METHOD(NEW_FBODY(body->nd_body, name), - body->nd_noex)); + st_insert(class->m_tbl, name, + NEW_METHOD(NEW_FBODY(body->nd_body, def, origin), + body->nd_noex)); } void @@ -196,7 +192,7 @@ rb_clear_cache2(class) } } -static ID match, each; +static ID match, each, aref, aset; VALUE errstr, errat; extern NODE *eval_tree; extern int nerrs; @@ -214,18 +210,18 @@ struct ENVIRON *the_env, *top_env; struct SCOPE *the_scope, *top_scope; #define PUSH_ENV() { \ - struct ENVIRON _this; \ - _this.prev = the_env; \ - the_env = &_this; \ + struct ENVIRON _env; \ + _env.prev = the_env; \ + the_env = &_env; \ -#define POP_ENV() the_env = the_env->prev; } +#define POP_ENV() the_env = _env.prev; } struct BLOCK { NODE *var; NODE *body; VALUE self; struct ENVIRON env; - struct SCOPE scope; + struct SCOPE *scope; int level; VALUE block; int iter; @@ -233,16 +229,16 @@ struct BLOCK { } *the_block; #define PUSH_BLOCK(v,b) { \ - struct BLOCK _this; \ - _this.level = tag_level; \ - _this.var=v; \ - _this.body = b; \ - _this.self = Qself; \ - _this.env = *the_env; \ - _this.scope = *the_scope; \ - _this.block = Qnil; \ - _this.prev = the_block; \ - the_block = &_this; \ + struct BLOCK _block; \ + _block.level = tag_level; \ + _block.var=v; \ + _block.body = b; \ + _block.self = Qself; \ + _block.env = *the_env; \ + _block.scope = the_scope; \ + _block.block = Qnil; \ + _block.prev = the_block; \ + the_block = &_block; \ #define PUSH_BLOCK2(b) { \ b->prev = the_block; \ @@ -255,14 +251,18 @@ static struct iter { struct iter *prev; } *iter; -#define PUSH_ITER(i) {\ - struct iter __iter__;\ - __iter__.prev = iter;\ - __iter__.iter = (i);\ - iter = &__iter__;\ +#define ITER_NOT 0 +#define ITER_PRE 1 +#define ITER_CUR 2 + +#define PUSH_ITER(i) { \ + struct iter _iter; \ + _iter.prev = iter; \ + _iter.iter = (i); \ + iter = &_iter; \ -#define POP_ITER() \ - iter = iter->prev;\ +#define POP_ITER() \ + iter = _iter.prev; \ } static int tag_level, target_level; @@ -277,13 +277,13 @@ static struct tag { } *prot_tag; #define PUSH_TAG() { \ - struct tag _this; \ - _this.level= ++tag_level; \ - _this.self = Qself; \ - _this.env = the_env; \ - _this.iter = iter; \ - _this.prev = prot_tag; \ - prot_tag = &_this; \ + struct tag _tag; \ + _tag.level= ++tag_level; \ + _tag.self = Qself; \ + _tag.env = the_env; \ + _tag.iter = iter; \ + _tag.prev = prot_tag; \ + prot_tag = &_tag; \ #define EXEC_TAG() (setjmp(prot_tag->buf)) #define JUMP_TAG(val) { \ @@ -294,7 +294,7 @@ static struct tag { #define POP_TAG() \ tag_level--; \ - prot_tag = prot_tag->prev; \ + prot_tag = _tag.prev; \ } #define TAG_RETURN 1 @@ -321,15 +321,16 @@ struct class_link { #define POP_CLASS() \ the_class = class_link->class; \ - class_link = class_link->prev; } + class_link = _link.prev; } #define PUSH_SCOPE() { \ - struct SCOPE _scope; \ - _scope = *the_scope; \ - _scope.prev = the_scope; \ - the_scope = &_scope; \ + struct SCOPE *_old; \ + NEWOBJ(_scope, struct SCOPE); \ + OBJSETUP(_scope, Qnil, T_SCOPE); \ + _old = the_scope; \ + the_scope = _scope; \ -#define POP_SCOPE() the_scope = the_scope->prev; } +#define POP_SCOPE() the_scope = _old; } static VALUE rb_eval(); static VALUE Feval(); @@ -386,15 +387,23 @@ ruby_init(argc, argv, envp) { int state; static struct ENVIRON env; - static struct SCOPE scope; the_env = top_env = &env; - the_scope = top_scope = &scope; - + + PUSH_SCOPE(); + the_scope->local_vars = Qnil; + the_scope->local_tbl = Qnil; + top_scope = the_scope; + PUSH_TAG(); + PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { ruby_init0(argc, argv, envp); } + POP_ITER(); POP_TAG(); + POP_SCOPE(); + the_scope = top_scope; + if (state) { PUSH_TAG(); error_print(); @@ -412,9 +421,6 @@ Eval(toplevel) NODE *tree; int state; - if (match == Qnil) match = rb_intern("=~"); - if (each == Qnil) each = rb_intern("each"); - tree = eval_tree; eval_tree = Qnil; sourcefile = tree->file; @@ -440,10 +446,12 @@ ruby_run() errat = Qnil; /* clear for execution */ PUSH_TAG(); + PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { the_class = (struct RClass*)C_Object; Eval(1); } + POP_ITER(); POP_TAG(); switch (state) { @@ -484,29 +492,51 @@ void rb_trap_eval(cmd) VALUE cmd; { - int state, go_out; + int state; + struct SCOPE *saved_scope; PUSH_SELF(TopSelf); PUSH_CLASS(); PUSH_TAG(); - PUSH_SCOPE(); - if ((state = EXEC_TAG()) == 0) { - the_class = (struct RClass*)C_Object; - the_scope->local_vars = top_scope->local_vars; - the_scope->local_tbl = top_scope->local_tbl; + saved_scope = the_scope; + the_scope = top_scope; + + the_class = (struct RClass*)C_Object; + if ((state = EXEC_TAG()) == 0) { Feval(Qself, cmd); - go_out = 0; } - else { - go_out = 1; - } - POP_SCOPE(); + + the_scope = saved_scope; POP_TAG(); POP_CLASS(); POP_SELF(); - if (go_out) JUMP_TAG(state); + 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; + default: +#ifdef SAFE_SIGHANDLE + trap_immediate = 0; +#endif + JUMP_TAG(state); + break; + } } #define SETUP_ARGS {\ @@ -515,12 +545,12 @@ rb_trap_eval(cmd) argc = 0;\ argv = Qnil;\ }\ - else if (nd_type(n) == NODE_ARRAY) {\ + else if (/*nd_type(n) == NODE_LIST ||*/ nd_type(n) == NODE_ARRAY) {\ argc=n->nd_alen;\ if (argc > 0) {\ int i;\ n = node->nd_args;\ - argv = (VALUE*)alloca(sizeof(VALUE)*argc);\ + argv = ALLOCA_N(VALUE,argc);\ for (i=0;ind_head);\ n=n->nd_next;\ @@ -528,10 +558,12 @@ rb_trap_eval(cmd) }\ }\ else {\ - argc = -2;\ - argv = (VALUE*)rb_eval(n);\ - if (TYPE(argv) != T_ARRAY)\ - argv = (VALUE*)rb_to_a(argv);\ + VALUE args = rb_eval(n);\ + if (TYPE(args) != T_ARRAY)\ + args = rb_to_a(args);\ + argc = RARRAY(args)->len;\ + argv = ALLOCA_N(VALUE, argc);\ + MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\ }\ } @@ -694,13 +726,17 @@ rb_eval(node) state = EXEC_TAG(); if (state == 0) { if (nd_type(node) == NODE_ITER) { + PUSH_ITER(ITER_PRE); result = rb_eval(node->nd_iter); + POP_ITER(); } else { VALUE recv; recv = rb_eval(node->nd_iter); - result = rb_call(CLASS_OF(recv),recv,each,0,Qnil,0,1); + PUSH_ITER(ITER_PRE); + result = rb_call(CLASS_OF(recv),recv,each,0,Qnil,0); + POP_ITER(); } } POP_TAG(); @@ -743,17 +779,6 @@ rb_eval(node) } return result; - case NODE_IYIELD: - { - VALUE val; - - val = rb_eval(node->nd_stts); - PUSH_ITER(1); - result = rb_yield(val); - POP_ITER(); - } - return result; - case NODE_PROT: PUSH_TAG(); switch (state = EXEC_TAG()) { @@ -841,16 +866,16 @@ rb_eval(node) break; case NODE_CALL: - case NODE_ICALL: { VALUE recv; int argc; VALUE *argv; /* used in SETUP_ARGS */ - VALUE buf[3]; + PUSH_ITER(ITER_NOT); recv = node->nd_recv?rb_eval(node->nd_recv):Qself; SETUP_ARGS; + POP_ITER(); return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv, - node->nd_recv?0:1, nd_type(node)==NODE_ICALL); + node->nd_recv?0:1); } break; @@ -865,11 +890,15 @@ rb_eval(node) argv = the_env->argv; } else { + PUSH_ITER(ITER_NOT); SETUP_ARGS; + POP_ITER(); } + PUSH_ITER(iter->iter?ITER_PRE:ITER_NOT); result = rb_call(the_env->last_class->super, Qself, - the_env->last_func, argc, argv, 1, iter->iter); + the_env->last_func, argc, argv, 1); + POP_ITER(); } return result; @@ -880,9 +909,8 @@ rb_eval(node) PUSH_SCOPE(); PUSH_TAG(); if (node->nd_cnt > 0) { - the_scope->local_vars = (VALUE*) - alloca(sizeof(VALUE)*node->nd_cnt); - memset(the_scope->local_vars, 0, sizeof(VALUE)*node->nd_cnt); + the_scope->local_vars = ALLOCA_N(VALUE, node->nd_cnt); + MEMZERO(the_scope->local_vars, VALUE, node->nd_cnt); the_scope->local_tbl = node->nd_tbl; } else { @@ -893,12 +921,45 @@ rb_eval(node) result = rb_eval(node->nd_body); } POP_TAG(); + if (!(the_scope->flags & SCOPE_MALLOCED)) { + the_scope->local_vars = Qnil; + the_scope->local_tbl = Qnil; + } POP_SCOPE(); if (state != 0) JUMP_TAG(state); return result; } + case NODE_OP_ASGN1: + { + VALUE recv, args, val; + NODE *rval; + + recv = rb_eval(node->nd_recv); + rval = node->nd_args->nd_head; + + args = rb_eval(node->nd_args->nd_next); + 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); + } + + case NODE_OP_ASGN2: + { + ID id = node->nd_aid; + VALUE recv, val; + + recv = rb_funcall(rb_eval(node->nd_recv), id, 0); + + id &= ~ID_SCOPE_MASK; + id |= ID_ATTRSET; + + val = rb_eval(node->nd_value); + return rb_funcall(recv, id, 1, val); + } + case NODE_MASGN: { VALUE val = rb_eval(node->nd_value); @@ -946,6 +1007,18 @@ rb_eval(node) case NODE_IVAR: return rb_ivar_get(node->nd_vid); case NODE_MVAR: + if (the_scope->flags & SCOPE_MALLOCED) { + ID id = node->nd_vid, *tbl = the_scope->local_tbl; + int i, len = tbl[0]; + + tbl++; + for (i=0; ilocal_vars[i]; + } + } return rb_mvar_get(node->nd_vid); case NODE_CVAR: @@ -1193,12 +1266,14 @@ rb_exit(status) } static VALUE -Fexit(obj, args) - VALUE obj, args; +Fexit(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; { VALUE status; - if (rb_scan_args(args, "01", &status) == 1) { + if (rb_scan_args(argc, argv, "01", &status) == 1) { Need_Fixnum(status); } else { @@ -1270,25 +1345,26 @@ Fiterator_p() return FALSE; } - VALUE rb_yield(val) VALUE val; { struct BLOCK *block; NODE *node; - int state, go_out; + int state; VALUE result; + struct ENVIRON *old_env; + struct SCOPE *old_scope; if (!iterator_p()) { Fail("yield called out of iterator"); } block = the_block; - block->env.prev = the_env; + old_env = the_env; the_env = &(block->env); - block->scope.prev = the_scope; - the_scope = &(block->scope); + old_scope = the_scope; + the_scope = block->scope; the_block = block->prev; if (block->var) { if (nd_type(block->var) == NODE_MASGN) @@ -1298,6 +1374,7 @@ rb_yield(val) } PUSH_ITER(block->iter); + PUSH_SELF(block->self); PUSH_TAG(); node = block->body; switch (state = EXEC_TAG()) { @@ -1309,28 +1386,26 @@ rb_yield(val) else { result = rb_eval(node); } - go_out = 0; break; case TAG_REDO: goto redo; case TAG_CONTINUE: - go_out = 0; + state = 0; break; case TAG_RETRY: case TAG_BREAK: case TAG_RETURN: target_level = block->level; state = IN_BLOCK|state; - default: - go_out = 1; break; } POP_TAG(); + POP_SELF(); POP_ITER(); the_block = block; - the_env = the_env->prev; - the_scope = the_scope->prev; - if (go_out) JUMP_TAG(state); + the_env = old_env; + the_scope = old_scope; + if (state) JUMP_TAG(state); return result; } @@ -1359,12 +1434,12 @@ masign(node, val) asign(node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i)); } else { - asign(node->nd_args, ary_new()); + asign(node->nd_args, Qnil); } } } else if (node->nd_args) { - asign(node->nd_args, ary_new()); + asign(node->nd_args, Qnil); } while (list) { asign(list->nd_head, Qnil); @@ -1432,7 +1507,7 @@ rb_iterate(it_proc, data1, bl_proc, data2) NODE *node = NEW_CFUNC(bl_proc, data2); struct BLOCK block; - PUSH_ITER(1); + PUSH_ITER(ITER_PRE); PUSH_BLOCK(Qnil, node); PUSH_TAG(); @@ -1564,23 +1639,24 @@ rb_undefined(obj, id, noex) } static VALUE -rb_call(class, recv, mid, argc, argv, func, itr) +rb_call(class, recv, mid, argc, argv, func) struct RClass *class; VALUE recv; ID mid; int argc; VALUE *argv; - int func, itr; + int func; { NODE *body; int noex; VALUE result; struct cache_entry *ent; + int itr; /* is it in the method cache? */ ent = cache + EXPR1(class, mid); - if (ent->class == class && ent->mid == mid) { - if (ent->method == Qnil) rb_undefined(recv, mid, 0); + 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; @@ -1597,206 +1673,224 @@ rb_call(class, recv, mid, argc, argv, func, itr) if (!func && noex) rb_undefined(recv, mid, 1); + switch (iter->iter) { + case ITER_PRE: + itr = ITER_CUR; + break; + case ITER_CUR: + default: + itr = ITER_NOT; + break; + } PUSH_ITER(itr); PUSH_SELF(recv); PUSH_ENV(); the_env->last_func = mid; the_env->last_class = class; - - if (argc < 0) { - the_env->arg_ary = (VALUE)argv; - argc = RARRAY(argv)->len; - argv = RARRAY(argv)->ptr; - } - else { - the_env->arg_ary = Qnil; - } the_env->argc = argc; the_env->argv = argv; - if (nd_type(body) == NODE_CFUNC) { - int len = body->nd_argc; + switch (nd_type(body)) { + case NODE_CFUNC: + { + int len = body->nd_argc; - if (len >= 0 && argc != len) { - Fail("Wrong # of arguments(%d for %d)", argc, body->nd_argc); - } + if (len >= 0 && argc != len) { + Fail("Wrong # of arguments(%d for %d)", argc, len); + } - switch (len) { - case -2: - result = (*body->nd_cfnc)(recv, ary_new4(argc, argv)); - break; - case -1: - result = (*body->nd_cfnc)(argc, argv); - break; - case 0: + switch (len) { + case -2: + result = (*body->nd_cfnc)(recv, ary_new4(argc, argv)); + break; + case -1: + result = (*body->nd_cfnc)(argc, argv, recv); + break; + case 0: result = (*body->nd_cfnc)(recv); - break; - case 1: - result = (*body->nd_cfnc)(recv, argv[0]); - break; - case 2: - result = (*body->nd_cfnc)(recv, argv[0], argv[1]); - break; - case 3: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2]); - break; - case 4: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3]); - break; - case 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[0], argv[1], argv[2], - argv[3], argv[4], argv[5]); - break; - case 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[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7]); - break; - case 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[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[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[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[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[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[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: - if (len < 0) { - Bug("bad argc(%d) specified for `%s(%s)'", - len, rb_class2name(class), rb_id2name(mid)); - } - else { - Fail("too many arguments(%d)", len); + break; + case 1: + result = (*body->nd_cfnc)(recv, argv[0]); + break; + case 2: + result = (*body->nd_cfnc)(recv, argv[0], argv[1]); + break; + case 3: + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2]); + break; + case 4: + result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], + argv[3]); + break; + case 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[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); + break; + case 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[0], argv[1], argv[2], + argv[3], argv[4], argv[5], + argv[6], argv[7]); + break; + case 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[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[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[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[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[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[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: + if (len < 0) { + Bug("bad argc(%d) specified for `%s(%s)'", + len, rb_class2name(class), rb_id2name(mid)); + } + else { + Fail("too many arguments(%d)", len); + } + break; } - break; } - } - else { - int state; - VALUE *local_vars; + break; - sourcefile = body->file; - PUSH_SCOPE(); - PUSH_TAG(); - if (body->nd_cnt > 0) { - local_vars = (VALUE*)alloca(sizeof(VALUE)*body->nd_cnt); - memset(local_vars, 0, sizeof(VALUE)*body->nd_cnt); - the_scope->local_tbl = body->nd_tbl; - the_scope->local_vars = local_vars; - } - else { - local_vars = the_scope->local_vars = Qnil; - the_scope->local_tbl = Qnil; - } - body = body->nd_body; - if (nd_type(body) == NODE_BLOCK) { - NODE *node = body->nd_head; - NODE *local; - int i; + /* for attr get/set */ + case NODE_ATTRSET: + case NODE_IVAR: + return rb_eval(body); - if (nd_type(node) != NODE_ARGS) { - Bug("no argument-node"); + default: + { + int state; + VALUE *local_vars; + + sourcefile = body->file; + PUSH_SCOPE(); + PUSH_TAG(); + + if (body->nd_cnt > 0) { + local_vars = ALLOCA_N(VALUE, body->nd_cnt); + MEMZERO(local_vars, VALUE, body->nd_cnt); + the_scope->local_tbl = body->nd_tbl; + the_scope->local_vars = local_vars; } + else { + local_vars = the_scope->local_vars = Qnil; + the_scope->local_tbl = Qnil; + } + body = body->nd_body; + + if (nd_type(body) == NODE_BLOCK) { + NODE *node = body->nd_head; + NODE *local; + int i; + + if (nd_type(node) != NODE_ARGS) { + Bug("no argument-node"); + } - body = body->nd_next; - i = node->nd_cnt; - if (i > argc || (node->nd_rest == -1 && i < argc)) - Fail("Wrong # of arguments(%d for %d)", argc, i); - - if (local_vars) { - memcpy(local_vars, argv, argc*sizeof(VALUE)); - if (node->nd_rest >= 0) { - if (argc == 0) - local_vars[node->nd_rest] = ary_new(); - else - local_vars[node->nd_rest] = ary_new4(argc-i, argv+i); + body = body->nd_next; + i = node->nd_cnt; + if (i > argc || (node->nd_rest == -1 && i < argc)) + Fail("Wrong # of arguments(%d for %d)", argc, i); + + if (local_vars) { + if (i > 0) { + MEMCPY(local_vars, argv, VALUE, i); + } + if (node->nd_rest >= 0) { + if (argc == 0) + local_vars[node->nd_rest] = ary_new(); + else + local_vars[node->nd_rest] = ary_new4(argc-i, argv+i); + } } } - } - state = EXEC_TAG(); - if (state == 0) { - result = rb_eval(body); - } - POP_TAG(); - POP_SCOPE(); - switch (state) { - case 0: - 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_RETURN: - result = last_val; - break; - default: - JUMP_TAG(state); + state = EXEC_TAG(); + if (state == 0) { + result = rb_eval(body); + } + POP_TAG(); + if (!(the_scope->flags & SCOPE_MALLOCED)) { + the_scope->local_vars = Qnil; + the_scope->local_tbl = Qnil; + } + POP_SCOPE(); + switch (state) { + case 0: + 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_RETURN: + result = last_val; + break; + default: + JUMP_TAG(state); + } } } POP_ENV(); POP_SELF(); POP_ITER(); - return result; } @@ -1806,17 +1900,25 @@ rb_apply(recv, mid, args) struct RArray *args; ID mid; { - return rb_call(CLASS_OF(recv), recv, mid, -2, (VALUE*)args, 1, 0); + int argc; + VALUE *argv; + + argc = RARRAY(args)->len; + argv = ALLOCA_N(VALUE, argc); + MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc); + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1); } static VALUE -Fapply(recv, args) - VALUE recv, args; +Fapply(argc, argv, recv) + int argc; + VALUE *argv; + VALUE recv; { VALUE vid, rest; ID mid; - rb_scan_args(args, "1*", &vid, &rest); + rb_scan_args(argc, argv, "1*", &vid, &rest); if (TYPE(vid) == T_STRING) { mid = rb_intern(RSTRING(vid)->ptr); } @@ -1841,7 +1943,7 @@ rb_funcall(recv, mid, n, va_alist) if (n > 0) { int i; - argv = (VALUE*)alloca(sizeof(VALUE)*n); + argv = ALLOCA_N(VALUE, n); va_start(ar); for (i=0;iptr); @@ -1953,15 +2055,15 @@ Fload(obj, fname) static int rb_dln_init = 0; extern char *rb_dln_argv0; int len = strlen(file); - + if (len > 2 && file[len-1] == 'o' && file[len-2] == '.') { if (rb_dln_init == 0 && dln_init(rb_dln_argv0) == -1) { Fail("%s: %s", rb_dln_argv0, dln_strerror()); } - + if (dln_load(file) == -1) Fail(dln_strerror()); - + return TRUE; } } @@ -2069,11 +2171,37 @@ Init_load() 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, -2); + 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, -2); + rb_define_method(C_Kernel, "apply", Fapply, -1); +} + +void +scope_dup(scope) + struct SCOPE *scope; +{ + ID *tbl; + VALUE *vars; + + if (scope->flags & SCOPE_MALLOCED) return; + if (!scope->local_tbl) return; + + tbl = scope->local_tbl; + scope->local_tbl = ALLOC_N(ID, tbl[0]+1); + MEMCPY(scope->local_tbl, tbl, ID, tbl[0]+1); + vars = scope->local_vars; + scope->local_vars = ALLOC_N(VALUE, tbl[0]); + MEMCPY(scope->local_vars, vars, VALUE, tbl[0]); + scope->flags |= SCOPE_MALLOCED; } VALUE C_Block; @@ -2083,8 +2211,8 @@ static void blk_mark(data) struct BLOCK *data; { - gc_mark_scope(&data->scope); - gc_mark(data->env.arg_ary); + gc_mark_env(&data->env); + gc_mark(data->scope); gc_mark(data->var); gc_mark(data->body); gc_mark(data->self); @@ -2094,8 +2222,7 @@ static void blk_free(data) struct BLOCK *data; { - free(data->scope.local_tbl); - free(data->scope.local_vars); + free(data->env.argv); } static VALUE @@ -2104,8 +2231,6 @@ Sblk_new(class) VALUE blk; struct BLOCK *data; struct SCOPE *scope; - ID *tbl; - int len; if (!iterator_p() && !Fiterator_p()) { Fail("tryed to create Block out of iterator"); @@ -2115,30 +2240,12 @@ Sblk_new(class) blk = obj_alloc(class); Make_Data_Struct(blk, blkdata, struct BLOCK, Qnil, blk_free, data); - memcpy(data, the_block, sizeof(struct BLOCK)); - scope = the_scope; - tbl = data->scope.local_tbl; - len = tbl ? tbl[0] : 0; - - while (scope && scope->local_tbl != tbl) - scope = scope->prev; + MEMCPY(data, the_block, struct BLOCK, 1); - if (!scope) { - Bug("non-existing scope"); - } - if (scope->var_ary == Qnil) { - scope->var_ary = ary_new4(len, scope->local_vars); - scope->local_vars = RARRAY(scope->var_ary)->ptr; - } - data->scope.local_vars = scope->local_vars; - data->scope.var_ary = scope->var_ary; + data->env.argv = ALLOC_N(VALUE, data->env.argc); + MEMCPY(data->env.argv, the_block->env.argv, VALUE, data->env.argc); - if (len > 0) { - len++; - tbl = ALLOC_N(ID, len); - memcpy(tbl, data->scope.local_tbl, sizeof(ID)*len); - data->scope.local_tbl = tbl; - } + scope_dup(data->scope); the_block->block = blk; return blk; @@ -2171,7 +2278,7 @@ Fblk_do(blk, args) /* PUSH BLOCK from data */ PUSH_BLOCK2(data); - PUSH_ITER(1); + PUSH_ITER(ITER_CUR); PUSH_TAG(); state = EXEC_TAG(); -- cgit v1.2.3