From 7b99a65518a38d1bd9dc59890be615e99d27343f Mon Sep 17 00:00:00 2001
From: Shugo Maeda <shugo@ruby-lang.org>
Date: Sun, 17 Oct 2010 11:41:21 +0900
Subject: [PATCH 24/51] added a new keyword classbox.

---
 class.c               |   21 ++++++
 compile.c             |   15 ++++
 defs/keywords         |    1 +
 defs/lex.c.src        |    1 +
 gc.c                  |    1 +
 include/ruby/intern.h |    2 +
 include/ruby/ruby.h   |    1 +
 insns.def             |   21 ++++++
 lex.c.blt             |  173 +++++++++++++++++++++++++------------------------
 lib/classbox.rb       |   18 ++---
 node.c                |    9 +++
 node.h                |    3 +
 object.c              |    5 ++
 parse.y               |   31 +++++++++-
 14 files changed, 205 insertions(+), 97 deletions(-)

diff --git a/class.c b/class.c
index 5c7835b..9a36efb 100644
--- a/class.c
+++ b/class.c
@@ -1532,6 +1532,27 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
 		 argc, n_mand, f_var ? "+" : "");
 }
 
+VALUE
+rb_classbox_new(void)
+{
+    VALUE mdl = class_alloc(T_MODULE, rb_cClassbox);
+
+    RCLASS_M_TBL(mdl) = st_init_numtable();
+
+    return (VALUE)mdl;
+}
+
+VALUE
+rb_define_classbox_id(ID id)
+{
+    VALUE mdl;
+
+    mdl = rb_classbox_new();
+    rb_name_class(mdl, id);
+
+    return mdl;
+}
+
 /*!
  * \}
  */
diff --git a/compile.c b/compile.c
index 8875e57..e04d5f8 100644
--- a/compile.c
+++ b/compile.c
@@ -4686,6 +4686,21 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 	}
 	break;
       }
+      case NODE_CLASSBOX:{
+	VALUE iseqval = NEW_CHILD_ISEQVAL(
+	    node->nd_body,
+	    rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
+	    ISEQ_TYPE_CLASS, nd_line(node));
+
+	compile_cpath(ret, iseq, node->nd_cpath);
+	ADD_INSN (ret, nd_line(node), putnil); /* dummy */
+	ADD_INSN3(ret, nd_line(node), defineclass,
+		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(3));
+	if (poped) {
+	    ADD_INSN(ret, nd_line(node), pop);
+	}
+	break;
+      }
       case NODE_COLON2:{
 	if (rb_is_const_id(node->nd_mid)) {
 	    /* constant */
diff --git a/defs/keywords b/defs/keywords
index 1b5719a..acd3dc6 100644
--- a/defs/keywords
+++ b/defs/keywords
@@ -19,6 +19,7 @@ begin, {keyword_begin, keyword_begin}, EXPR_BEG
 break, {keyword_break, keyword_break}, EXPR_MID
 case, {keyword_case, keyword_case}, EXPR_VALUE
 class, {keyword_class, keyword_class}, EXPR_CLASS
+classbox, {keyword_classbox, keyword_classbox}, EXPR_VALUE
 def, {keyword_def, keyword_def}, EXPR_FNAME
 defined?, {keyword_defined, keyword_defined}, EXPR_ARG
 do, {keyword_do, keyword_do}, EXPR_BEG
diff --git a/defs/lex.c.src b/defs/lex.c.src
index 1b5719a..acd3dc6 100644
--- a/defs/lex.c.src
+++ b/defs/lex.c.src
@@ -19,6 +19,7 @@ begin, {keyword_begin, keyword_begin}, EXPR_BEG
 break, {keyword_break, keyword_break}, EXPR_MID
 case, {keyword_case, keyword_case}, EXPR_VALUE
 class, {keyword_class, keyword_class}, EXPR_CLASS
+classbox, {keyword_classbox, keyword_classbox}, EXPR_VALUE
 def, {keyword_def, keyword_def}, EXPR_FNAME
 defined?, {keyword_defined, keyword_defined}, EXPR_ARG
 do, {keyword_do, keyword_do}, EXPR_BEG
diff --git a/gc.c b/gc.c
index c3309ee..b7805a7 100644
--- a/gc.c
+++ b/gc.c
@@ -1615,6 +1615,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
 	  case NODE_OP_ASGN_OR:
 	  case NODE_OP_ASGN_AND:
 	  case NODE_MODULE:
+	  case NODE_CLASSBOX:
 	  case NODE_ALIAS:
 	  case NODE_VALIAS:
 	  case NODE_ARGSCAT:
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 100c026..e417feb 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -185,6 +185,8 @@ void rb_define_protected_method(VALUE, const char*, VALUE (*)(ANYARGS), int);
 void rb_define_private_method(VALUE, const char*, VALUE (*)(ANYARGS), int);
 void rb_define_singleton_method(VALUE, const char*, VALUE(*)(ANYARGS), int);
 VALUE rb_singleton_class(VALUE);
+VALUE rb_classbox_new(void);
+VALUE rb_define_classbox_id(ID);
 /* compar.c */
 int rb_cmpint(VALUE, VALUE, VALUE);
 NORETURN(void rb_cmperr(VALUE, VALUE));
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index def9d3c..c364476 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -1221,6 +1221,7 @@ RUBY_EXTERN VALUE rb_cArray;
 RUBY_EXTERN VALUE rb_cBignum;
 RUBY_EXTERN VALUE rb_cBinding;
 RUBY_EXTERN VALUE rb_cClass;
+RUBY_EXTERN VALUE rb_cClassbox;
 RUBY_EXTERN VALUE rb_cCont;
 RUBY_EXTERN VALUE rb_cDir;
 RUBY_EXTERN VALUE rb_cData;
diff --git a/insns.def b/insns.def
index 3179a70..00a9566 100644
--- a/insns.def
+++ b/insns.def
@@ -956,6 +956,27 @@ defineclass
 	    rb_const_set(cbase, id, klass);
 	}
 	break;
+      case 3:
+	/* val is dummy.  classdef returns class scope value */
+	/* super is dummy */
+
+	vm_check_if_namespace(cbase);
+
+	/* find klass */
+#if 0
+	if (rb_const_defined_at(cbase, id)) {
+	    klass = rb_const_get_at(cbase, id);
+	    rb_raise(rb_eNameError, "%s is not a module", rb_id2name(id));
+	}
+	else
+#endif
+	{
+	    /* new module declaration */
+	    klass = rb_define_classbox_id(id);
+	    rb_set_class_path_string(klass, cbase, rb_id2str(id));
+	    rb_const_set(cbase, id, klass);
+	}
+	break;
       default:
 	rb_bug("unknown defineclass type: %d", (int)define_type);
     }
diff --git a/lex.c.blt b/lex.c.blt
index 1ae8099..58bb02d 100644
--- a/lex.c.blt
+++ b/lex.c.blt
@@ -1,5 +1,5 @@
-/* C code produced by gperf version 3.0.4 */
-/* Command-line: gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' defs/keywords  */
+/* C code produced by gperf version 3.0.3 */
+/* Command-line: gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' ../defs/keywords  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -28,22 +28,22 @@
 error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
 #endif
 
-#line 1 "defs/keywords"
+#line 1 "../defs/keywords"
 
 struct kwtable {const char *name; int id[2]; enum lex_state_e state;};
 const struct kwtable *rb_reserved_word(const char *, unsigned int);
 #ifndef RIPPER
 static const struct kwtable *reserved_word(const char *, unsigned int);
 #define rb_reserved_word(str, len) reserved_word(str, len)
-#line 9 "defs/keywords"
+#line 9 "../defs/keywords"
 struct kwtable;
 
-#define TOTAL_KEYWORDS 41
+#define TOTAL_KEYWORDS 42
 #define MIN_WORD_LENGTH 2
 #define MAX_WORD_LENGTH 12
 #define MIN_HASH_VALUE 8
-#define MAX_HASH_VALUE 50
-/* maximum key range = 43, duplicates = 0 */
+#define MAX_HASH_VALUE 59
+/* maximum key range = 52, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -59,32 +59,32 @@ hash (str, len)
 {
   static const unsigned char asso_values[] =
     {
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 26, 51, 51, 14, 51, 16,  8,
-      11, 13, 51, 51, 51, 51, 10, 51, 13, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 11, 51, 13,  1, 26,
-       4,  1,  8, 28, 51, 23, 51,  1,  1, 27,
-       5, 19, 21, 51,  8,  3,  3, 11, 51, 21,
-      24, 16, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
-      51, 51, 51, 51, 51, 51
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 27, 60, 60, 14, 60, 17,  9,
+      12, 13, 60, 60, 60, 60, 11, 60, 13, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 11, 60, 13,  1, 18,
+       4,  1,  8, 29, 60, 23, 60,  1,  1, 27,
+       5, 19, 20, 60,  8,  3,  3, 11, 60, 24,
+      20, 21, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60
     };
   register int hval = len;
 
@@ -103,7 +103,7 @@ hash (str, len)
 
 #ifdef __GNUC__
 __inline
-#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+#ifdef __GNUC_STDC_INLINE__
 __attribute__ ((__gnu_inline__))
 #endif
 #endif
@@ -115,89 +115,92 @@ rb_reserved_word (str, len)
   static const struct kwtable wordlist[] =
     {
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 19 "defs/keywords"
+#line 19 "../defs/keywords"
       {"break", {keyword_break, keyword_break}, EXPR_MID},
-#line 25 "defs/keywords"
+#line 26 "../defs/keywords"
       {"else", {keyword_else, keyword_else}, EXPR_BEG},
-#line 35 "defs/keywords"
+#line 36 "../defs/keywords"
       {"nil", {keyword_nil, keyword_nil}, EXPR_END},
-#line 28 "defs/keywords"
+#line 29 "../defs/keywords"
       {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG},
-#line 27 "defs/keywords"
+#line 28 "../defs/keywords"
       {"end", {keyword_end, keyword_end}, EXPR_END},
-#line 44 "defs/keywords"
+#line 45 "../defs/keywords"
       {"then", {keyword_then, keyword_then}, EXPR_BEG},
-#line 36 "defs/keywords"
+#line 37 "../defs/keywords"
       {"not", {keyword_not, keyword_not}, EXPR_ARG},
-#line 29 "defs/keywords"
+#line 30 "../defs/keywords"
       {"false", {keyword_false, keyword_false}, EXPR_END},
-#line 42 "defs/keywords"
+#line 43 "../defs/keywords"
       {"self", {keyword_self, keyword_self}, EXPR_END},
-#line 26 "defs/keywords"
+#line 27 "../defs/keywords"
       {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE},
-#line 39 "defs/keywords"
+#line 40 "../defs/keywords"
       {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID},
-#line 45 "defs/keywords"
+#line 46 "../defs/keywords"
       {"true", {keyword_true, keyword_true}, EXPR_END},
-#line 48 "defs/keywords"
+#line 49 "../defs/keywords"
       {"until", {keyword_until, modifier_until}, EXPR_VALUE},
-#line 47 "defs/keywords"
+#line 48 "../defs/keywords"
       {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE},
-#line 41 "defs/keywords"
+#line 42 "../defs/keywords"
       {"return", {keyword_return, keyword_return}, EXPR_MID},
-#line 22 "defs/keywords"
+#line 23 "../defs/keywords"
       {"def", {keyword_def, keyword_def}, EXPR_FNAME},
-#line 17 "defs/keywords"
+#line 17 "../defs/keywords"
       {"and", {keyword_and, keyword_and}, EXPR_VALUE},
-#line 24 "defs/keywords"
+#line 25 "../defs/keywords"
       {"do", {keyword_do, keyword_do}, EXPR_BEG},
-#line 51 "defs/keywords"
-      {"yield", {keyword_yield, keyword_yield}, EXPR_ARG},
-#line 30 "defs/keywords"
+#line 20 "../defs/keywords"
+      {"case", {keyword_case, keyword_case}, EXPR_VALUE},
+#line 31 "../defs/keywords"
       {"for", {keyword_for, keyword_for}, EXPR_VALUE},
-#line 46 "defs/keywords"
+#line 47 "../defs/keywords"
       {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME},
-#line 37 "defs/keywords"
+#line 38 "../defs/keywords"
       {"or", {keyword_or, keyword_or}, EXPR_VALUE},
-#line 32 "defs/keywords"
+#line 33 "../defs/keywords"
       {"in", {keyword_in, keyword_in}, EXPR_VALUE},
-#line 49 "defs/keywords"
-      {"when", {keyword_when, keyword_when}, EXPR_VALUE},
-#line 40 "defs/keywords"
-      {"retry", {keyword_retry, keyword_retry}, EXPR_END},
-#line 31 "defs/keywords"
+#line 52 "../defs/keywords"
+      {"yield", {keyword_yield, keyword_yield}, EXPR_ARG},
+#line 35 "../defs/keywords"
+      {"next", {keyword_next, keyword_next}, EXPR_MID},
+#line 32 "../defs/keywords"
       {"if", {keyword_if, modifier_if}, EXPR_VALUE},
-#line 20 "defs/keywords"
-      {"case", {keyword_case, keyword_case}, EXPR_VALUE},
-#line 38 "defs/keywords"
+#line 50 "../defs/keywords"
+      {"when", {keyword_when, keyword_when}, EXPR_VALUE},
+#line 39 "../defs/keywords"
       {"redo", {keyword_redo, keyword_redo}, EXPR_END},
-#line 34 "defs/keywords"
-      {"next", {keyword_next, keyword_next}, EXPR_MID},
-#line 43 "defs/keywords"
+#line 44 "../defs/keywords"
       {"super", {keyword_super, keyword_super}, EXPR_ARG},
-#line 33 "defs/keywords"
+#line 41 "../defs/keywords"
+      {"retry", {keyword_retry, keyword_retry}, EXPR_END},
+#line 34 "../defs/keywords"
       {"module", {keyword_module, keyword_module}, EXPR_VALUE},
-#line 18 "defs/keywords"
+#line 21 "../defs/keywords"
+      {"class", {keyword_class, keyword_class}, EXPR_CLASS},
+#line 18 "../defs/keywords"
       {"begin", {keyword_begin, keyword_begin}, EXPR_BEG},
-#line 12 "defs/keywords"
+#line 12 "../defs/keywords"
       {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END},
-#line 13 "defs/keywords"
+#line 13 "../defs/keywords"
       {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END},
-#line 11 "defs/keywords"
+#line 11 "../defs/keywords"
       {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
-#line 15 "defs/keywords"
-      {"END", {keyword_END, keyword_END}, EXPR_END},
-#line 16 "defs/keywords"
+#line 16 "../defs/keywords"
       {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME},
-#line 14 "defs/keywords"
+#line 14 "../defs/keywords"
       {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END},
-#line 23 "defs/keywords"
+#line 15 "../defs/keywords"
+      {"END", {keyword_END, keyword_END}, EXPR_END},
+#line 24 "../defs/keywords"
       {"defined?", {keyword_defined, keyword_defined}, EXPR_ARG},
-#line 21 "defs/keywords"
-      {"class", {keyword_class, keyword_class}, EXPR_CLASS},
-      {""}, {""},
-#line 50 "defs/keywords"
-      {"while", {keyword_while, modifier_while}, EXPR_VALUE}
+      {""}, {""}, {""}, {""}, {""},
+#line 51 "../defs/keywords"
+      {"while", {keyword_while, modifier_while}, EXPR_VALUE},
+      {""}, {""}, {""}, {""}, {""},
+#line 22 "../defs/keywords"
+      {"classbox", {keyword_classbox, keyword_classbox}, EXPR_VALUE}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -214,6 +217,6 @@ rb_reserved_word (str, len)
     }
   return 0;
 }
-#line 52 "defs/keywords"
+#line 53 "../defs/keywords"
 
 #endif
diff --git a/lib/classbox.rb b/lib/classbox.rb
index 91e9ab9..09879be 100644
--- a/lib/classbox.rb
+++ b/lib/classbox.rb
@@ -1,4 +1,4 @@
-class Classbox < Module
+class Classbox
   def import_to(binding)
     @__overlayed_modules__.each do |klass, modules|
       modules.each do |mod|
@@ -9,17 +9,13 @@ class Classbox < Module
 
   private
 
-  def initialize
-    super
-    @__overlayed_modules__ = {}
-  end
-
   @@__optimized_methods__ = [
     :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=, :>, :>=, :!, :!=,
     :length, :size, :succ
   ]
 
   def refine(klass, &block)
+    @__overlayed_modules__ ||= {}
     mod = Module.new
     modules = @__overlayed_modules__[klass] ||= []
     modules.push(mod)
@@ -37,11 +33,11 @@ class Classbox < Module
 end
 
 def classbox(name, &block)
-  classbox = Classbox.new
-  Object.const_set(name, classbox)
-  classbox.module_eval(&block)
+  klassbox = Classbox.new
+  Object.const_set(name, klassbox)
+  klassbox.module_eval(&block)
 end
 
-def import_classbox(classbox)
-  classbox.import_to(binding(1))
+def import_classbox(klassbox)
+  klassbox.import_to(binding(1))
 end
diff --git a/node.c b/node.c
index 65bc541..e761d72 100644
--- a/node.c
+++ b/node.c
@@ -696,6 +696,15 @@ dump_node(VALUE buf, VALUE indent, int comment, NODE *node)
 	F_NODE(nd_body, "singleton class definition");
 	break;
 
+      case NODE_CLASSBOX:
+	ANN("classbox definition");
+	ANN("format: classbox [nd_cpath]; [nd_body]; end");
+	ANN("example: classbox M; ..; end");
+	F_NODE(nd_cpath, "classbox path");
+	LAST_NODE;
+	F_NODE(nd_body, "classbox definition");
+	break;
+
       case NODE_COLON2:
 	ANN("scoped constant reference");
 	ANN("format: [nd_head]::[nd_mid]");
diff --git a/node.h b/node.h
index 405a469..89d424c 100644
--- a/node.h
+++ b/node.h
@@ -184,6 +184,8 @@ enum node_type {
 #define NODE_MODULE      NODE_MODULE
     NODE_SCLASS,
 #define NODE_SCLASS      NODE_SCLASS
+    NODE_CLASSBOX,
+#define NODE_CLASSBOX    NODE_CLASSBOX
     NODE_COLON2,
 #define NODE_COLON2      NODE_COLON2
     NODE_COLON3,
@@ -441,6 +443,7 @@ typedef struct RNode {
 #define NEW_CLASS(n,b,s) NEW_NODE(NODE_CLASS,n,NEW_SCOPE(0,b),(s))
 #define NEW_SCLASS(r,b) NEW_NODE(NODE_SCLASS,r,NEW_SCOPE(0,b),0)
 #define NEW_MODULE(n,b) NEW_NODE(NODE_MODULE,n,NEW_SCOPE(0,b),0)
+#define NEW_CLASSBOX(n,b) NEW_NODE(NODE_CLASSBOX,n,NEW_SCOPE(0,b),0)
 #define NEW_COLON2(c,i) NEW_NODE(NODE_COLON2,c,i,0)
 #define NEW_COLON3(i) NEW_NODE(NODE_COLON3,0,i,0)
 #define NEW_CREF(a) NEW_NODE(NODE_CREF,a,0,0)
diff --git a/object.c b/object.c
index 75192c1..e2ed9e8 100644
--- a/object.c
+++ b/object.c
@@ -26,6 +26,7 @@ VALUE rb_mKernel;
 VALUE rb_cObject;
 VALUE rb_cModule;
 VALUE rb_cClass;
+VALUE rb_cClassbox;
 VALUE rb_cData;
 
 VALUE rb_cNilClass;
@@ -2660,6 +2661,10 @@ Init_Object(void)
     rb_undef_method(rb_cClass, "extend_object");
     rb_undef_method(rb_cClass, "append_features");
 
+    rb_cClassbox = rb_define_class("Classbox", rb_cModule);
+    rb_undef_method(rb_cClassbox, "extend_object");
+    rb_undef_method(rb_cClassbox, "append_features");
+
     rb_cData = rb_define_class("Data", rb_cObject);
     rb_undef_alloc_func(rb_cData);
 
diff --git a/parse.y b/parse.y
index 67ca1f1..670d921 100644
--- a/parse.y
+++ b/parse.y
@@ -627,6 +627,7 @@ static void token_info_pop(struct parser_params*, const char *token);
 %*/
 	keyword_class
 	keyword_module
+	keyword_classbox
 	keyword_def
 	keyword_undef
 	keyword_begin
@@ -1864,7 +1865,8 @@ op		: '|'		{ ifndef_ripper($$ = '|'); }
 reswords	: keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
 		| keyword_BEGIN | keyword_END
 		| keyword_alias | keyword_and | keyword_begin
-		| keyword_break | keyword_case | keyword_class | keyword_def
+		| keyword_break | keyword_case
+		| keyword_class | keyword_classbox | keyword_def
 		| keyword_defined | keyword_do | keyword_else | keyword_elsif
 		| keyword_end | keyword_ensure | keyword_false
 		| keyword_for | keyword_in | keyword_module | keyword_next
@@ -2951,6 +2953,27 @@ primary		: literal
 		    %*/
 			local_pop();
 		    }
+		| k_classbox cpath
+		    {
+			if (in_def || in_single)
+			    yyerror("module definition in method body");
+			local_push(0);
+		    /*%%%*/
+			$<num>$ = ruby_sourceline;
+		    /*%
+		    %*/
+		    }
+		  bodystmt
+		  k_end
+		    {
+		    /*%%%*/
+			$$ = NEW_CLASSBOX($2, $4);
+			nd_set_line($$, $<num>3);
+		    /*%
+			$$ = dispatch2(module, $2, $4);
+		    %*/
+			local_pop();
+		    }
 		| k_def fname
 		    {
 			$<id>$ = cur_mid;
@@ -3097,6 +3120,12 @@ k_module	: keyword_module
 		    }
 		;
 
+k_classbox	: keyword_classbox
+		    {
+			token_info_push("classbox");
+		    }
+		;
+
 k_def		: keyword_def
 		    {
 			token_info_push("def");
-- 
1.7.0.4

