mirror of
https://github.com/ruby/ruby.git
synced 2025-09-16 00:54:01 +02:00
* 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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@44911 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0d2b4a6dd8
commit
b64a3e4120
6 changed files with 154 additions and 40 deletions
32
ChangeLog
32
ChangeLog
|
@ -1,3 +1,35 @@
|
||||||
|
Tue Feb 11 23:21:02 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
Tue Feb 11 00:26:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* file.c (GetLastError): already defined in windows.h on nowadays
|
* file.c (GetLastError): already defined in windows.h on nowadays
|
||||||
|
|
|
@ -27,8 +27,17 @@ bug_sym_##type##_p(VALUE self, VALUE name) \
|
||||||
|
|
||||||
FOREACH_ID_TYPES(define_symbol_type_p)
|
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
|
void
|
||||||
Init_type(VALUE klass)
|
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);
|
||||||
}
|
}
|
||||||
|
|
111
parse.y
111
parse.y
|
@ -8678,9 +8678,41 @@ block_dup_check_gen(struct parser_params *parser, NODE *node1, NODE *node2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char id_type_names[][9] = {
|
||||||
|
"LOCAL",
|
||||||
|
"INSTANCE",
|
||||||
|
"", /* INSTANCE2 */
|
||||||
|
"GLOBAL",
|
||||||
|
"ATTRSET",
|
||||||
|
"CONST",
|
||||||
|
"CLASS",
|
||||||
|
"JUNK",
|
||||||
|
};
|
||||||
|
|
||||||
ID
|
ID
|
||||||
rb_id_attrset(ID 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_SCOPE_MASK;
|
||||||
id |= ID_ATTRSET;
|
id |= ID_ATTRSET;
|
||||||
return id;
|
return id;
|
||||||
|
@ -10062,8 +10094,11 @@ rb_enc_symname_p(const char *name, rb_encoding *enc)
|
||||||
return rb_enc_symname2_p(name, strlen(name), enc);
|
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
|
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 *m = name;
|
||||||
const char *e = m + len;
|
const char *e = m + len;
|
||||||
|
@ -10148,7 +10183,7 @@ rb_enc_symname_type(const char *name, long len, rb_encoding *enc)
|
||||||
++m;
|
++m;
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (type != ID_CONST && type != ID_LOCAL) return -1;
|
if (!(allowed_atttset & (1U << type))) return -1;
|
||||||
type = ID_ATTRSET;
|
type = ID_ATTRSET;
|
||||||
++m;
|
++m;
|
||||||
break;
|
break;
|
||||||
|
@ -10161,15 +10196,15 @@ rb_enc_symname_type(const char *name, long len, rb_encoding *enc)
|
||||||
int
|
int
|
||||||
rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
|
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
|
static int
|
||||||
rb_str_symname_type(VALUE name)
|
rb_str_symname_type(VALUE name, unsigned int allowed_atttset)
|
||||||
{
|
{
|
||||||
const char *ptr = StringValuePtr(name);
|
const char *ptr = StringValuePtr(name);
|
||||||
long len = RSTRING_LEN(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);
|
RB_GC_GUARD(name);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -10294,26 +10329,27 @@ intern_str(VALUE str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
if (m[last] == '=') {
|
}
|
||||||
/* attribute assignment */
|
if (name[last] == '=') {
|
||||||
if (!rb_enc_symname2_p(name, last, enc))
|
/* attribute assignment */
|
||||||
goto junk;
|
if (last > 1 && name[last-1] == '=')
|
||||||
id = rb_intern3(name, last, enc);
|
goto junk;
|
||||||
if (id > tLAST_OP_ID && !is_attrset_id(id)) {
|
id = rb_intern3(name, last, enc);
|
||||||
enc = rb_enc_get(rb_id2str(id));
|
if (id > tLAST_OP_ID && !is_attrset_id(id)) {
|
||||||
id = rb_id_attrset(id);
|
enc = rb_enc_get(rb_id2str(id));
|
||||||
goto id_register;
|
id = rb_id_attrset(id);
|
||||||
}
|
goto id_register;
|
||||||
id = ID_ATTRSET;
|
|
||||||
}
|
}
|
||||||
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;
|
id = ID_CONST;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
id = ID_LOCAL;
|
id = ID_LOCAL;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!rb_enc_isdigit(*m, enc)) {
|
if (!rb_enc_isdigit(*m, enc)) {
|
||||||
while (m <= name + last && is_identchar(m, e, enc)) {
|
while (m <= name + last && is_identchar(m, e, enc)) {
|
||||||
|
@ -10325,7 +10361,7 @@ intern_str(VALUE str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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();
|
if (sym_check_asciionly(str)) symenc = rb_usascii_encoding();
|
||||||
new_id:
|
new_id:
|
||||||
if (symenc != enc) rb_enc_associate(str, symenc);
|
if (symenc != enc) rb_enc_associate(str, symenc);
|
||||||
|
@ -10408,16 +10444,21 @@ rb_id2str(ID id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_attrset_id(id)) {
|
if (is_attrset_id(id)) {
|
||||||
ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL;
|
ID id_stem = (id & ~ID_SCOPE_MASK);
|
||||||
VALUE str;
|
VALUE str;
|
||||||
|
|
||||||
while (!(str = rb_id2str(id2))) {
|
do {
|
||||||
if (!is_local_id(id2)) return 0;
|
if (!!(str = rb_id2str(id_stem | ID_LOCAL))) break;
|
||||||
id2 = (id & ~ID_SCOPE_MASK) | ID_CONST;
|
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);
|
str = rb_str_dup(str);
|
||||||
rb_str_cat(str, "=", 1);
|
rb_str_cat(str, "=", 1);
|
||||||
rb_intern_str(str);
|
register_symid_str(id, str);
|
||||||
if (st_lookup(global_symbols.id_str, id, &data)) {
|
if (st_lookup(global_symbols.id_str, id, &data)) {
|
||||||
VALUE str = (VALUE)data;
|
VALUE str = (VALUE)data;
|
||||||
if (RBASIC(str)->klass == 0)
|
if (RBASIC(str)->klass == 0)
|
||||||
|
@ -10600,43 +10641,43 @@ rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
|
||||||
int
|
int
|
||||||
rb_is_const_name(VALUE name)
|
rb_is_const_name(VALUE name)
|
||||||
{
|
{
|
||||||
return rb_str_symname_type(name) == ID_CONST;
|
return rb_str_symname_type(name, 0) == ID_CONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_is_class_name(VALUE name)
|
rb_is_class_name(VALUE name)
|
||||||
{
|
{
|
||||||
return rb_str_symname_type(name) == ID_CLASS;
|
return rb_str_symname_type(name, 0) == ID_CLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_is_global_name(VALUE name)
|
rb_is_global_name(VALUE name)
|
||||||
{
|
{
|
||||||
return rb_str_symname_type(name) == ID_GLOBAL;
|
return rb_str_symname_type(name, 0) == ID_GLOBAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_is_instance_name(VALUE name)
|
rb_is_instance_name(VALUE name)
|
||||||
{
|
{
|
||||||
return rb_str_symname_type(name) == ID_INSTANCE;
|
return rb_str_symname_type(name, 0) == ID_INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_is_attrset_name(VALUE name)
|
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
|
int
|
||||||
rb_is_local_name(VALUE name)
|
rb_is_local_name(VALUE name)
|
||||||
{
|
{
|
||||||
return rb_str_symname_type(name) == ID_LOCAL;
|
return rb_str_symname_type(name, 0) == ID_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_is_method_name(VALUE name)
|
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:
|
case ID_LOCAL: case ID_ATTRSET: case ID_JUNK:
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -10646,7 +10687,7 @@ rb_is_method_name(VALUE name)
|
||||||
int
|
int
|
||||||
rb_is_junk_name(VALUE name)
|
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 */
|
#endif /* !RIPPER */
|
||||||
|
|
|
@ -82,15 +82,29 @@ module Test_Symbol
|
||||||
assert_symtype("@foo=", :attrset?)
|
assert_symtype("@foo=", :attrset?)
|
||||||
assert_symtype("@@foo=", :attrset?)
|
assert_symtype("@@foo=", :attrset?)
|
||||||
assert_symtype("$foo=", :attrset?)
|
assert_symtype("$foo=", :attrset?)
|
||||||
assert_not_symtype("0=", :attrset?)
|
assert_symtype("0=", :attrset?)
|
||||||
assert_not_symtype("@=", :attrset?)
|
assert_symtype("@=", :attrset?)
|
||||||
assert_not_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_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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -142,7 +142,19 @@ class TestStruct < Test::Unit::TestCase
|
||||||
|
|
||||||
klass = Struct.new(:@a)
|
klass = Struct.new(:@a)
|
||||||
o = klass.new(1)
|
o = klass.new(1)
|
||||||
|
assert_equal(1, o.__send__(:@a))
|
||||||
assert_equal("#<struct :@a=1>", o.inspect)
|
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
|
end
|
||||||
|
|
||||||
def test_init_copy
|
def test_init_copy
|
||||||
|
@ -281,4 +293,10 @@ class TestStruct < Test::Unit::TestCase
|
||||||
o = klass.new(1, 2, 3, 4, 5, 6)
|
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)
|
assert_equal({a:1, b:2, c:3, d:4, e:5, f:6}, o.to_h)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_struct_question_mark
|
||||||
|
bug9248 = '[ruby-core:59095]'
|
||||||
|
klass = Struct.new(:a?)
|
||||||
|
assert_include(klass.new.methods.inspect, ':a?', bug9248)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#define RUBY_VERSION "2.0.0"
|
#define RUBY_VERSION "2.0.0"
|
||||||
#define RUBY_RELEASE_DATE "2014-02-11"
|
#define RUBY_RELEASE_DATE "2014-02-11"
|
||||||
#define RUBY_PATCHLEVEL 401
|
#define RUBY_PATCHLEVEL 402
|
||||||
|
|
||||||
#define RUBY_RELEASE_YEAR 2014
|
#define RUBY_RELEASE_YEAR 2014
|
||||||
#define RUBY_RELEASE_MONTH 2
|
#define RUBY_RELEASE_MONTH 2
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue