ruby-changes:32835
From: nagachika <ko1@a...>
Date: Wed, 12 Feb 2014 03:31:00 +0900 (JST)
Subject: [ruby-changes:32835] nagachika:r44911 (ruby_2_0_0): merge revision(s) r42479, r42490, r42509, r43083, r43084, r43085: [Backport #8756] [Backport #9248]
nagachika 2014-02-11 23:55:00 +0900 (Tue, 11 Feb 2014) New Revision: 44911 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=44911 Log: merge revision(s) r42479,r42490,r42509,r43083,r43084,r43085: [Backport #8756] [Backport #9248] * parse.y (rb_enc_symname_type): allow ID_ATTRSET for ID_INSTANCE, ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756] * parse.y (rb_id_attrset): fix inconsistency with literals, allow ID_ATTRSET and return it itself, but ID_JUNK cannot make ID_ATTRSET. and raise a NameError instead of rb_bug() for invalid argument. * parse.y (rb_id_attrset, intern_str): allow junk attrset ID for Struct. * parse.y (rb_id_attrset): check if the argument is valid type as an attribute. * parse.y (rb_id_attrset): allow other than ID_ATTRSET. * parse.y (intern_str): ditto. try stem ID for ID_INSTANCE, ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756] Modified directories: branches/ruby_2_0_0/ Modified files: branches/ruby_2_0_0/ChangeLog branches/ruby_2_0_0/ext/-test-/symbol/type.c branches/ruby_2_0_0/parse.y branches/ruby_2_0_0/test/-ext-/symbol/test_type.rb branches/ruby_2_0_0/test/ruby/test_struct.rb branches/ruby_2_0_0/version.h Index: ruby_2_0_0/ChangeLog =================================================================== --- ruby_2_0_0/ChangeLog (revision 44910) +++ ruby_2_0_0/ChangeLog (revision 44911) @@ -1,3 +1,35 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/ChangeLog#L1 +Tue Feb 11 23:21:02 2014 CHIKANAGA Tomoyuki <nagachika@r...> + + * test/ruby/test_struct.rb (test_struct_question_mark): add a testcase + for Struct attribute with question mark. the patch was originally + written by Eric Wong [ruby-core:59095] [Backport #9248] + +Tue Feb 11 23:21:02 2014 Nobuyoshi Nakada <nobu@r...> + + * parse.y (rb_id_attrset, intern_str): allow junk attrset ID for + Struct. + + * parse.y (rb_id_attrset): fix inconsistency with literals, allow + ID_ATTRSET and return it itself, but ID_JUNK cannot make ID_ATTRSET. + and raise a NameError instead of rb_bug() for invalid argument. + +Tue Feb 11 23:21:02 2014 Nobuyoshi Nakada <nobu@r...> + + * parse.y (rb_enc_symname_type): allow ID_ATTRSET for ID_INSTANCE, + ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756] + +Tue Feb 11 23:21:02 2014 Nobuyoshi Nakada <nobu@r...> + + * parse.y (rb_id_attrset): allow other than ID_ATTRSET. + + * parse.y (intern_str): ditto. try stem ID for ID_INSTANCE, + ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756] + +Tue Feb 11 23:21:02 2014 Nobuyoshi Nakada <nobu@r...> + + * parse.y (rb_id_attrset): check if the argument is valid type as an + attribute. + Tue Feb 11 00:26:19 2014 Nobuyoshi Nakada <nobu@r...> * file.c (GetLastError): already defined in windows.h on nowadays Index: ruby_2_0_0/parse.y =================================================================== --- ruby_2_0_0/parse.y (revision 44910) +++ ruby_2_0_0/parse.y (revision 44911) @@ -8678,9 +8678,41 @@ block_dup_check_gen(struct parser_params https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L8678 } } +static const char id_type_names[][9] = { + "LOCAL", + "INSTANCE", + "", /* INSTANCE2 */ + "GLOBAL", + "ATTRSET", + "CONST", + "CLASS", + "JUNK", +}; + ID rb_id_attrset(ID id) { + if (!is_notop_id(id)) { + switch (id) { + case tAREF: case tASET: + return tASET; /* only exception */ + } + rb_name_error(id, "cannot make operator ID :%s attrset", rb_id2name(id)); + } + else { + int scope = (int)(id & ID_SCOPE_MASK); + switch (scope) { + case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL: + case ID_CONST: case ID_CLASS: case ID_JUNK: + break; + case ID_ATTRSET: + return id; + default: + rb_name_error(id, "cannot make %s ID %+"PRIsVALUE" attrset", + id_type_names[scope], ID2SYM(id)); + + } + } id &= ~ID_SCOPE_MASK; id |= ID_ATTRSET; return id; @@ -10062,8 +10094,11 @@ rb_enc_symname_p(const char *name, rb_en https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10094 return rb_enc_symname2_p(name, strlen(name), enc); } +#define IDSET_ATTRSET_FOR_SYNTAX ((1U<<ID_LOCAL)|(1U<<ID_CONST)) +#define IDSET_ATTRSET_FOR_INTERN (~(~0U<<ID_SCOPE_MASK) & ~(1U<<ID_ATTRSET)) + static int -rb_enc_symname_type(const char *name, long len, rb_encoding *enc) +rb_enc_symname_type(const char *name, long len, rb_encoding *enc, unsigned int allowed_atttset) { const char *m = name; const char *e = m + len; @@ -10148,7 +10183,7 @@ rb_enc_symname_type(const char *name, lo https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10183 ++m; break; case '=': - if (type != ID_CONST && type != ID_LOCAL) return -1; + if (!(allowed_atttset & (1U << type))) return -1; type = ID_ATTRSET; ++m; break; @@ -10161,15 +10196,15 @@ rb_enc_symname_type(const char *name, lo https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10196 int rb_enc_symname2_p(const char *name, long len, rb_encoding *enc) { - return rb_enc_symname_type(name, len, enc) != -1; + return rb_enc_symname_type(name, len, enc, IDSET_ATTRSET_FOR_SYNTAX) != -1; } static int -rb_str_symname_type(VALUE name) +rb_str_symname_type(VALUE name, unsigned int allowed_atttset) { const char *ptr = StringValuePtr(name); long len = RSTRING_LEN(name); - int type = rb_enc_symname_type(ptr, len, rb_enc_get(name)); + int type = rb_enc_symname_type(ptr, len, rb_enc_get(name), allowed_atttset); RB_GC_GUARD(name); return type; } @@ -10294,26 +10329,27 @@ intern_str(VALUE str) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10329 } } } - - if (m[last] == '=') { - /* attribute assignment */ - if (!rb_enc_symname2_p(name, last, enc)) - goto junk; - id = rb_intern3(name, last, enc); - if (id > tLAST_OP_ID && !is_attrset_id(id)) { - enc = rb_enc_get(rb_id2str(id)); - id = rb_id_attrset(id); - goto id_register; - } - id = ID_ATTRSET; + break; + } + if (name[last] == '=') { + /* attribute assignment */ + if (last > 1 && name[last-1] == '=') + goto junk; + id = rb_intern3(name, last, enc); + if (id > tLAST_OP_ID && !is_attrset_id(id)) { + enc = rb_enc_get(rb_id2str(id)); + id = rb_id_attrset(id); + goto id_register; } - else if (rb_enc_isupper(m[0], enc)) { + id = ID_ATTRSET; + } + else if (id == 0) { + if (rb_enc_isupper(m[0], enc)) { id = ID_CONST; - } + } else { id = ID_LOCAL; } - break; } if (!rb_enc_isdigit(*m, enc)) { while (m <= name + last && is_identchar(m, e, enc)) { @@ -10325,7 +10361,7 @@ intern_str(VALUE str) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10361 } } } - if (m - name < len) id = ID_JUNK; + if (id != ID_ATTRSET && m - name < len) id = ID_JUNK; if (sym_check_asciionly(str)) symenc = rb_usascii_encoding(); new_id: if (symenc != enc) rb_enc_associate(str, symenc); @@ -10408,16 +10444,21 @@ rb_id2str(ID id) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10444 } if (is_attrset_id(id)) { - ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL; + ID id_stem = (id & ~ID_SCOPE_MASK); VALUE str; - while (!(str = rb_id2str(id2))) { - if (!is_local_id(id2)) return 0; - id2 = (id & ~ID_SCOPE_MASK) | ID_CONST; - } + do { + if (!!(str = rb_id2str(id_stem | ID_LOCAL))) break; + if (!!(str = rb_id2str(id_stem | ID_CONST))) break; + if (!!(str = rb_id2str(id_stem | ID_INSTANCE))) break; + if (!!(str = rb_id2str(id_stem | ID_GLOBAL))) break; + if (!!(str = rb_id2str(id_stem | ID_CLASS))) break; + if (!!(str = rb_id2str(id_stem | ID_JUNK))) break; + return 0; + } while (0); str = rb_str_dup(str); rb_str_cat(str, "=", 1); - rb_intern_str(str); + register_symid_str(id, str); if (st_lookup(global_symbols.id_str, id, &data)) { VALUE str = (VALUE)data; if (RBASIC(str)->klass == 0) @@ -10600,43 +10641,43 @@ rb_check_id_cstr(const char *ptr, long l https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10641 int rb_is_const_name(VALUE name) { - return rb_str_symname_type(name) == ID_CONST; + return rb_str_symname_type(name, 0) == ID_CONST; } int rb_is_class_name(VALUE name) { - return rb_str_symname_type(name) == ID_CLASS; + return rb_str_symname_type(name, 0) == ID_CLASS; } int rb_is_global_name(VALUE name) { - return rb_str_symname_type(name) == ID_GLOBAL; + return rb_str_symname_type(name, 0) == ID_GLOBAL; } int rb_is_instance_name(VALUE name) { - return rb_str_symname_type(name) == ID_INSTANCE; + return rb_str_symname_type(name, 0) == ID_INSTANCE; } int rb_is_attrset_name(VALUE name) { - return rb_str_symname_type(name) == ID_ATTRSET; + return rb_str_symname_type(name, IDSET_ATTRSET_FOR_INTERN) == ID_ATTRSET; } int rb_is_local_name(VALUE name) { - return rb_str_symname_type(name) == ID_LOCAL; + return rb_str_symname_type(name, 0) == ID_LOCAL; } int rb_is_method_name(VALUE name) { - switch (rb_str_symname_type(name)) { + switch (rb_str_symname_type(name, 0)) { case ID_LOCAL: case ID_ATTRSET: case ID_JUNK: return TRUE; } @@ -10646,7 +10687,7 @@ rb_is_method_name(VALUE name) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/parse.y#L10687 int rb_is_junk_name(VALUE name) { - return rb_str_symname_type(name) == -1; + return rb_str_symname_type(name, IDSET_ATTRSET_FOR_SYNTAX) == -1; } #endif /* !RIPPER */ Index: ruby_2_0_0/ext/-test-/symbol/type.c =================================================================== --- ruby_2_0_0/ext/-test-/symbol/type.c (revision 44910) +++ ruby_2_0_0/ext/-test-/symbol/type.c (revision 44911) @@ -27,8 +27,17 @@ bug_sym_##type##_p(VALUE self, VALUE nam https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/ext/-test-/symbol/type.c#L27 FOREACH_ID_TYPES(define_symbol_type_p) +static VALUE +bug_sym_attrset(VALUE self, VALUE name) +{ + ID id = rb_to_id(name); + id = rb_id_attrset(id); + return ID2SYM(id); +} + void Init_type(VALUE klass) { - FOREACH_ID_TYPES(declare_symbol_type_p) + FOREACH_ID_TYPES(declare_symbol_type_p); + rb_define_singleton_method(klass, "attrset", bug_sym_attrset, 1); } Index: ruby_2_0_0/version.h =================================================================== --- ruby_2_0_0/version.h (revision 44910) +++ ruby_2_0_0/version.h (revision 44911) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/version.h#L1 #define RUBY_VERSION "2.0.0" #define RUBY_RELEASE_DATE "2014-02-11" -#define RUBY_PATCHLEVEL 401 +#define RUBY_PATCHLEVEL 402 #define RUBY_RELEASE_YEAR 2014 #define RUBY_RELEASE_MONTH 2 Index: ruby_2_0_0/test/ruby/test_struct.rb =================================================================== --- ruby_2_0_0/test/ruby/test_struct.rb (revision 44910) +++ ruby_2_0_0/test/ruby/test_struct.rb (revision 44911) @@ -142,7 +142,19 @@ class TestStruct < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/test/ruby/test_struct.rb#L142 klass = Struct.new(:@a) o = klass.new(1) + assert_equal(1, o.__send__(:@a)) assert_equal("#<struct :@a=1>", o.inspect) + o.__send__(:"@a=", 2) + assert_equal(2, o.__send__(:@a)) + assert_equal("#<struct :@a=2>", o.inspect) + o.__send__("@a=", 3) + assert_equal(3, o.__send__(:@a)) + assert_equal("#<struct :@a=3>", o.inspect) + + methods = klass.instance_methods(false) + assert_equal([:@a, :"@a="].inspect, methods.inspect, '[Bug #8756]') + assert_include(methods, :@a) + assert_include(methods, :"@a=") end def test_init_copy @@ -281,4 +293,10 @@ class TestStruct < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/test/ruby/test_struct.rb#L293 o = klass.new(1, 2, 3, 4, 5, 6) assert_equal({a:1, b:2, c:3, d:4, e:5, f:6}, o.to_h) end + + def test_struct_question_mark + bug9248 = '[ruby-core:59095]' + klass = Struct.new(:a?) + assert_include(klass.new.methods.inspect, ':a?', bug9248) + end end Index: ruby_2_0_0/test/-ext-/symbol/test_type.rb =================================================================== --- ruby_2_0_0/test/-ext-/symbol/test_type.rb (revision 44910) +++ ruby_2_0_0/test/-ext-/symbol/test_type.rb (revision 44911) @@ -82,15 +82,29 @@ module Test_Symbol https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/test/-ext-/symbol/test_type.rb#L82 assert_symtype("@foo=", :attrset?) assert_symtype("@@foo=", :attrset?) assert_symtype("$foo=", :attrset?) - assert_not_symtype("0=", :attrset?) - assert_not_symtype("@=", :attrset?) - assert_not_symtype("@@=", :attrset?) + assert_symtype("0=", :attrset?) + assert_symtype("@=", :attrset?) + assert_symtype("@@=", :attrset?) assert_not_symtype("foo", :attrset?) assert_not_symtype("Foo", :attrset?) assert_not_symtype("@foo", :attrset?) assert_not_symtype("@@foo", :attrset?) assert_not_symtype("$foo", :attrset?) assert_not_symtype("[foo]", :attrset?) + assert_symtype("[foo]=", :attrset?) + assert_equal(:"foo=", Bug::Symbol.attrset("foo")) + assert_symtype(Bug::Symbol.attrset("foo"), :attrset?) + assert_equal(:"Foo=", Bug::Symbol.attrset("Foo")) + assert_symtype(Bug::Symbol.attrset("Foo"), :attrset?) + assert_equal(:"@foo=", Bug::Symbol.attrset("@foo")) + assert_symtype(Bug::Symbol.attrset("@foo"), :attrset?) + assert_equal(:"@@foo=", Bug::Symbol.attrset("@@foo")) + assert_symtype(Bug::Symbol.attrset("@@foo"), :attrset?) + assert_equal(:"$foo=", Bug::Symbol.attrset("$foo")) + assert_symtype(Bug::Symbol.attrset("$foo"), :attrset?) + assert_equal(:"[foo]=", Bug::Symbol.attrset("[foo]")) + assert_symtype(Bug::Symbol.attrset("[foo]"), :attrset?) + assert_equal(:[]=, Bug::Symbol.attrset(:[])) end end end Property changes on: ruby_2_0_0 ___________________________________________________________________ Modified: svn:mergeinfo Merged /trunk:r42479,42490,42509,43083-43085 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/