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