зеркало из https://github.com/github/ruby.git
* parse.y (assoc, parser_yylex): add syntax to splat keyword hash.
[ruby-core:44591][Feature #6353] * compile.c (compile_array_): generate keyword splat insns. * vm.c (m_core_hash_merge_kwd): merge keyword hash into intermediate hash. leftward argument is prior currently. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35489 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
82fa2995b5
Коммит
3380974143
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
Sun Apr 29 06:12:02 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* parse.y (assoc, parser_yylex): add syntax to splat keyword hash.
|
||||
[ruby-core:44591][Feature #6353]
|
||||
|
||||
* compile.c (compile_array_): generate keyword splat insns.
|
||||
|
||||
* vm.c (m_core_hash_merge_kwd): merge keyword hash into intermediate
|
||||
hash. leftward argument is prior currently.
|
||||
|
||||
Sat Apr 28 18:39:40 2012 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* vm_core.h (rb_thread_t#yielding): add a field.
|
||||
|
|
19
compile.c
19
compile.c
|
@ -2296,21 +2296,28 @@ compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
|
|||
|
||||
while (node) {
|
||||
NODE *start_node = node, *end_node;
|
||||
NODE *kw = 0;
|
||||
const int max = 0x100;
|
||||
DECL_ANCHOR(anchor);
|
||||
INIT_ANCHOR(anchor);
|
||||
|
||||
for (i=0; i<max && node; i++, len++) {
|
||||
for (i=0; i<max && node; i++, len++, node = node->nd_next) {
|
||||
if (CPDEBUG > 0 && nd_type(node) != NODE_ARRAY) {
|
||||
rb_bug("compile_array: This node is not NODE_ARRAY, but %s", ruby_node_name(nd_type(node)));
|
||||
}
|
||||
|
||||
if (type == COMPILE_ARRAY_TYPE_HASH && !node->nd_head) {
|
||||
opt_p = 0;
|
||||
kw = node->nd_next;
|
||||
node = kw->nd_next;
|
||||
kw = kw->nd_head;
|
||||
break;
|
||||
}
|
||||
if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
|
||||
opt_p = 0;
|
||||
}
|
||||
|
||||
COMPILE_(anchor, "array element", node->nd_head, poped);
|
||||
node = node->nd_next;
|
||||
}
|
||||
|
||||
if (opt_p && type != COMPILE_ARRAY_TYPE_ARGS) {
|
||||
|
@ -2378,12 +2385,18 @@ compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
|
|||
ADD_INSN1(anchor, line, newhash, INT2FIX(i));
|
||||
APPEND_LIST(ret, anchor);
|
||||
}
|
||||
else {
|
||||
else if (i > 0) {
|
||||
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
|
||||
ADD_INSN(ret, line, swap);
|
||||
APPEND_LIST(ret, anchor);
|
||||
ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_ptr), INT2FIX(i + 1));
|
||||
}
|
||||
if (kw) {
|
||||
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
|
||||
ADD_INSN(ret, line, swap);
|
||||
COMPILE(ret, "keyword splat", kw);
|
||||
ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_kwd), INT2FIX(2));
|
||||
}
|
||||
break;
|
||||
case COMPILE_ARRAY_TYPE_ARGS:
|
||||
APPEND_LIST(ret, anchor);
|
||||
|
|
|
@ -233,6 +233,7 @@ static const struct token_assoc {
|
|||
{tRPAREN, &ripper_id_rparen},
|
||||
{tRSHFT, &ripper_id_op},
|
||||
{tSTAR, &ripper_id_op},
|
||||
{tDSTAR, &ripper_id_op},
|
||||
{tSTRING_BEG, &ripper_id_tstring_beg},
|
||||
{tSTRING_CONTENT, &ripper_id_tstring_content},
|
||||
{tSTRING_DBEG, &ripper_id_embexpr_beg},
|
||||
|
|
1
id.c
1
id.c
|
@ -34,6 +34,7 @@ Init_id(void)
|
|||
REGISTER_SYMID(id_core_hash_from_ary, "core#hash_from_ary");
|
||||
REGISTER_SYMID(id_core_hash_merge_ary, "core#hash_merge_ary");
|
||||
REGISTER_SYMID(id_core_hash_merge_ptr, "core#hash_merge_ptr");
|
||||
REGISTER_SYMID(id_core_hash_merge_kwd, "core#hash_merge_kwd");
|
||||
|
||||
REGISTER_SYMID(idEach, "each");
|
||||
REGISTER_SYMID(idLength, "length");
|
||||
|
|
32
parse.y
32
parse.y
|
@ -759,6 +759,7 @@ static void token_info_pop(struct parser_params*, const char *token);
|
|||
%token tLBRACE /* { */
|
||||
%token tLBRACE_ARG /* { */
|
||||
%token tSTAR /* * */
|
||||
%token tDSTAR /* ** */
|
||||
%token tAMPER /* & */
|
||||
%token tLAMBDA /* -> */
|
||||
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG
|
||||
|
@ -805,6 +806,7 @@ static void token_info_pop(struct parser_params*, const char *token);
|
|||
%nonassoc id_core_hash_from_ary
|
||||
%nonassoc id_core_hash_merge_ary
|
||||
%nonassoc id_core_hash_merge_ptr
|
||||
%nonassoc id_core_hash_merge_kwd
|
||||
|
||||
%token tLAST_TOKEN
|
||||
|
||||
|
@ -1918,6 +1920,7 @@ op : '|' { ifndef_ripper($$ = '|'); }
|
|||
| '/' { ifndef_ripper($$ = '/'); }
|
||||
| '%' { ifndef_ripper($$ = '%'); }
|
||||
| tPOW { ifndef_ripper($$ = tPOW); }
|
||||
| tDSTAR { ifndef_ripper($$ = tDSTAR); }
|
||||
| '!' { ifndef_ripper($$ = '!'); }
|
||||
| '~' { ifndef_ripper($$ = '~'); }
|
||||
| tUPLUS { ifndef_ripper($$ = tUPLUS); }
|
||||
|
@ -4699,7 +4702,11 @@ f_kwarg : f_kw
|
|||
}
|
||||
;
|
||||
|
||||
f_kwrest : tPOW tIDENTIFIER
|
||||
kwrest_mark : tPOW
|
||||
| tDSTAR
|
||||
;
|
||||
|
||||
f_kwrest : kwrest_mark tIDENTIFIER
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
|
@ -4923,6 +4930,16 @@ assoc : arg_value tASSOC arg_value
|
|||
$$ = dispatch2(assoc_new, $1, $2);
|
||||
%*/
|
||||
}
|
||||
| tDSTAR arg_value
|
||||
{
|
||||
/*%%%*/
|
||||
$$ = list_append(NEW_LIST(0), $2);
|
||||
/*%
|
||||
$$ = dispatch1(assoc_splat, $2);
|
||||
%*/
|
||||
}
|
||||
;
|
||||
|
||||
;
|
||||
|
||||
operation : tIDENTIFIER
|
||||
|
@ -6890,7 +6907,17 @@ parser_yylex(struct parser_params *parser)
|
|||
return tOP_ASGN;
|
||||
}
|
||||
pushback(c);
|
||||
c = tPOW;
|
||||
if (IS_SPCARG(c)) {
|
||||
rb_warning0("`**' interpreted as argument prefix");
|
||||
c = tDSTAR;
|
||||
}
|
||||
else if (IS_BEG()) {
|
||||
c = tDSTAR;
|
||||
}
|
||||
else {
|
||||
warn_balanced("**", "argument prefix");
|
||||
c = tPOW;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c == '=') {
|
||||
|
@ -9701,6 +9728,7 @@ static const struct {
|
|||
{'+', "+(binary)"},
|
||||
{'-', "-(binary)"},
|
||||
{tPOW, "**"},
|
||||
{tDSTAR, "**"},
|
||||
{tUPLUS, "+@"},
|
||||
{tUMINUS, "-@"},
|
||||
{tCMP, "<=>"},
|
||||
|
|
|
@ -146,6 +146,12 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
|||
assert_equal true, thru_assoc_new
|
||||
end
|
||||
|
||||
def test_assoc_splat
|
||||
thru_assoc_splat = false
|
||||
parse('m(**h)', :on_assoc_splat) {thru_assoc_splat = true}
|
||||
assert_equal true, thru_assoc_splat
|
||||
end
|
||||
|
||||
def test_aref_field
|
||||
assert_equal '[assign(aref_field(vcall(a),[1]),2)]', parse('a[1]=2')
|
||||
end
|
||||
|
|
|
@ -90,6 +90,21 @@ class TestSyntax < Test::Unit::TestCase
|
|||
assert_equal({foo: 1, bar: 2}, o.kw(foo: 1, bar: 2), bug5989)
|
||||
end
|
||||
|
||||
def test_keyword_splat
|
||||
assert_valid_syntax("foo(**h)", __FILE__)
|
||||
o = Object.new
|
||||
def o.kw(k1: 1, k2: 2) [k1, k2] end
|
||||
h = {k1: 11, k2: 12}
|
||||
assert_equal([11, 12], o.kw(**h))
|
||||
assert_equal([11, 22], o.kw(k2: 22, **h))
|
||||
assert_equal([11, 12], o.kw(**h, **{k2: 22}))
|
||||
assert_equal([11, 22], o.kw(**{k2: 22}, **h))
|
||||
h = {k3: 31}
|
||||
assert_raise(ArgumentError) {o.kw(**h)}
|
||||
h = {"k1"=>11, k2: 12}
|
||||
assert_raise(TypeError) {o.kw(**h)}
|
||||
end
|
||||
|
||||
def test_warn_grouped_expression
|
||||
assert_warn("test:2: warning: (...) interpreted as grouped expression\n") do
|
||||
assert_valid_syntax("foo \\\n(\n true)", "test") {$VERBOSE = true}
|
||||
|
|
25
vm.c
25
vm.c
|
@ -2068,6 +2068,30 @@ m_core_hash_merge_ptr(int argc, VALUE *argv, VALUE recv)
|
|||
return hash;
|
||||
}
|
||||
|
||||
static int
|
||||
kwmerge_ii(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
|
||||
{
|
||||
if (existing) return ST_STOP;
|
||||
*value = arg;
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
kwmerge_i(VALUE key, VALUE value, VALUE hash)
|
||||
{
|
||||
if (!SYMBOL_P(key)) Check_Type(key, T_SYMBOL);
|
||||
st_update(RHASH_TBL(hash), key, kwmerge_ii, (st_data_t)value);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
m_core_hash_merge_kwd(VALUE recv, VALUE hash, VALUE kw)
|
||||
{
|
||||
kw = rb_convert_type(kw, T_HASH, "Hash", "to_hash");
|
||||
rb_hash_foreach(kw, kwmerge_i, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
extern VALUE *rb_gc_stack_start;
|
||||
extern size_t rb_gc_stack_maxsize;
|
||||
#ifdef __ia64
|
||||
|
@ -2134,6 +2158,7 @@ Init_VM(void)
|
|||
rb_define_method_id(klass, id_core_hash_from_ary, m_core_hash_from_ary, 1);
|
||||
rb_define_method_id(klass, id_core_hash_merge_ary, m_core_hash_merge_ary, 2);
|
||||
rb_define_method_id(klass, id_core_hash_merge_ptr, m_core_hash_merge_ptr, -1);
|
||||
rb_define_method_id(klass, id_core_hash_merge_kwd, m_core_hash_merge_kwd, 2);
|
||||
rb_obj_freeze(fcore);
|
||||
rb_gc_register_mark_object(fcore);
|
||||
rb_mRubyVMFrozenCore = fcore;
|
||||
|
|
Загрузка…
Ссылка в новой задаче