Yukihiro Matsumotoさんの <983199207.503414.26928.nullmailer / ev.netlab.zetabits.com>から > |そういえば、クラス定義で class に続くものを式にも出来ないで > |しょうか。無名クラス Foo(n) に対して「class Foo(n) … end」 > |のように書きたいことがしばしばあります。 > > うーん、気持ちは分からないでもないですが... > だれか実装してみない? まつもとさんが、文法に関わることを 他人にまかされるとは珍しい。 二度とないかもしれない、大チャンスですね。 以下のようなことができればよいのでしょうか? def Foo(obj) obj end class Foo(String) def bar(*args); printf("bar: %s\n", args); end end String.new("abc").bar(1, 2, 3) class Foo_2934; end def foo(n) eval("Foo_" + n.to_s) end class foo(2934) def bar; puts "bar success !"; end end Foo_2934.new.bar 実装してみました。 上記のスクリプトと make testしかチェックしていません。 --- parse.y Mon Feb 26 14:29:00 2001 +++ /home/kosako/ruby/parse.y Tue Feb 27 14:31:31 2001 @@ -86,6 +86,7 @@ #define CMDARG_P() (cmdarg_stack && (cmdarg_stack&1)) static int class_nest = 0; +static int in_class_head = 0; static int in_single = 0; static int in_def = 0; static int compile_for_eval = 0; @@ -214,6 +215,7 @@ %type <id> fitem variable sym symbol operation operation2 operation3 %type <id> cname fname op f_rest_arg %type <num> f_norm_arg f_arg +%token tRELSUPER /* < */ %token tUPLUS /* unary+ */ %token tUMINUS /* unary- */ %token tPOW /* ** */ @@ -1253,8 +1255,9 @@ $$ = NEW_FOR($2, $5, $8); fixpos($$, $2); } - | kCLASS cname superclass + | class_start expr superclass { + in_class_head = 0; if (in_def || in_single) yyerror("class definition in method body"); class_nest++; @@ -1271,7 +1274,11 @@ cref_pop(); class_nest--; } - | kCLASS tLSHFT expr + | class_start tLSHFT + { + in_class_head = 0; + } + expr { $<num>$ = in_def; in_def = 0; @@ -1287,13 +1294,13 @@ compstmt kEND { - $$ = NEW_SCLASS($3, $7); - fixpos($$, $3); + $$ = NEW_SCLASS($4, $8); + fixpos($$, $4); local_pop(); cref_pop(); class_nest--; - in_def = $<num>4; - in_single = $<num>6; + in_def = $<num>5; + in_single = $<num>7; } | kMODULE cname { @@ -1377,6 +1384,11 @@ $$ = NEW_RETRY(); } +class_start : kCLASS + { + in_class_head = 1; + } + then : term | kTHEN | term kTHEN @@ -1638,7 +1650,7 @@ { $$ = 0; } - | '<' + | tRELSUPER { lex_state = EXPR_BEG; } @@ -1984,6 +1996,7 @@ cond_nest = 0; cond_stack = 0; class_nest = 0; + in_class_head = 0; in_single = 0; in_def = 0; cur_mid = 0; @@ -2964,6 +2977,8 @@ return tLSHFT; } pushback(c); + if (in_class_head) + return tRELSUPER; return '<'; case '>': @@ -3373,7 +3388,8 @@ if (cond_nest > 0) { cond_stack = (cond_stack<<1)|0; } - if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + if (lex_state == EXPR_BEG || lex_state == EXPR_MID || + lex_state == EXPR_CLASS) { c = tLPAREN; } else if (lex_state == EXPR_ARG && space_seen) { --- eval.c Mon Feb 26 14:29:00 2001 +++ /home/kosako/ruby/eval.c Tue Feb 27 17:18:03 2001 @@ -3047,6 +3047,7 @@ case NODE_CLASS: { VALUE super, klass, tmp; + ID cname = 0; if (NIL_P(ruby_class)) { rb_raise(rb_eTypeError, "no outer class/module"); @@ -3059,16 +3060,28 @@ } klass = 0; - if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) { - rb_autoload_load(node->nd_cname); + if (nd_type(node->nd_cname) == NODE_CONST) { + cname = ((NODE* )(node->nd_cname))->nd_vid; } - if (rb_const_defined_at(ruby_class, node->nd_cname)) { - klass = rb_const_get(ruby_class, node->nd_cname); + else { + klass = rb_eval(self, (NODE* )(node->nd_cname)); + if (! klass || TYPE(klass) != T_CLASS) { + rb_raise(rb_eTypeError, "class name value is not a class object"); + } + } + + if (cname) { + if ((ruby_class == rb_cObject) && rb_autoload_defined(cname)) { + rb_autoload_load(cname); + } + if (rb_const_defined_at(ruby_class, cname)) { + klass = rb_const_get(ruby_class, cname); + } } if (klass) { if (TYPE(klass) != T_CLASS) { rb_raise(rb_eTypeError, "%s is not a class", - rb_id2name(node->nd_cname)); + (cname ? rb_id2name(cname) : "class name object")); } if (super) { tmp = RCLASS(klass)->super; @@ -3091,9 +3104,14 @@ else { override_class: if (!super) super = rb_cObject; - klass = rb_define_class_id(node->nd_cname, super); - rb_const_set(ruby_class, node->nd_cname, klass); - rb_set_class_path(klass,ruby_class,rb_id2name(node->nd_cname)); + if (cname) { + klass = rb_define_class_id(cname, super); + rb_const_set(ruby_class, cname, klass); + rb_set_class_path(klass,ruby_class,rb_id2name(cname)); + } + else { + klass = rb_define_class("(anonymous)", super); + } } if (ruby_wrapper) { rb_extend_object(klass, ruby_wrapper); ---- 小迫@ソフネック 渋谷区恵比寿1-15-1