Feature #14973 ยป hash_expand.patch
ext/ripper/eventids2.c | ||
---|---|---|
ID ripper_id_words_beg;
|
||
ID ripper_id_qwords_beg;
|
||
ID ripper_id_qsymbols_beg;
|
||
ID ripper_id_hashexpand_beg;
|
||
ID ripper_id_symbols_beg;
|
||
ID ripper_id_words_sep;
|
||
ID ripper_id_rational;
|
||
... | ... | |
set_id2(words_beg);
|
||
set_id2(qwords_beg);
|
||
set_id2(qsymbols_beg);
|
||
set_id2(hashexpand_beg);
|
||
set_id2(symbols_beg);
|
||
set_id2(words_sep);
|
||
set_id2(rational);
|
||
... | ... | |
{tPOW, O(op)},
|
||
{tQWORDS_BEG, O(qwords_beg)},
|
||
{tQSYMBOLS_BEG, O(qsymbols_beg)},
|
||
{tHASHEXPAND_BEG, O(hashexpand_beg)},
|
||
{tSYMBOLS_BEG, O(symbols_beg)},
|
||
{tRATIONAL, O(rational)},
|
||
{tREGEXP_BEG, O(regexp_beg)},
|
parse.y | ||
---|---|---|
%type <node> singleton strings string string1 xstring regexp
|
||
%type <node> string_contents xstring_contents regexp_contents string_content
|
||
%type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word
|
||
%type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word hashexpand hashexpand_list
|
||
%type <node> literal numeric simple_numeric dsym cpath
|
||
%type <node> top_compstmt top_stmts top_stmt begin_block
|
||
%type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
|
||
... | ... | |
%token tDSTAR "**arg"
|
||
%token tAMPER "&"
|
||
%token tLAMBDA "->"
|
||
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG
|
||
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG tHASHEXPAND_BEG
|
||
%token tSTRING_DBEG tSTRING_DEND tSTRING_DVAR tSTRING_END tLAMBEG tLABEL_END
|
||
/*
|
||
... | ... | |
| qwords
|
||
| symbols
|
||
| qsymbols
|
||
| hashexpand
|
||
| var_ref
|
||
| backref
|
||
| tFID
|
||
... | ... | |
| qwords
|
||
| symbols
|
||
| qsymbols
|
||
| hashexpand
|
||
| keyword_variable
|
||
{
|
||
/*%%%*/
|
||
... | ... | |
}
|
||
;
|
||
hashexpand : tHASHEXPAND_BEG ' ' hashexpand_list tSTRING_END
|
||
{
|
||
/*%%%*/
|
||
$$ = new_hash(p, $3, &@$);
|
||
/*% %*/
|
||
/*% ripper: hash!($3) %*/
|
||
}
|
||
;
|
||
hashexpand_list : /* none */
|
||
{
|
||
/*%%%*/
|
||
$$ = 0;
|
||
/*% %*/
|
||
/*% ripper: hashexpand_new! %*/
|
||
}
|
||
| hashexpand_list string_content ' '
|
||
{
|
||
/*%%%*/
|
||
NODE *key, *val, *estr;
|
||
estr = evstr2dstr(p, $2);
|
||
estr = $2;
|
||
key = NEW_CALL(estr, rb_intern("to_sym"), 0, &@$);
|
||
val = NEW_FCALL(rb_intern("eval"), NEW_LIST(estr, &@$), &@$);
|
||
$$ = list_append(p, list_append(p, $1, key), val);
|
||
/*% %*/
|
||
/*% ripper: hashexpand_add!($1, $2) %*/
|
||
}
|
||
;
|
||
string_contents : /* none */
|
||
{
|
||
/*%%%*/
|
||
... | ... | |
SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);
|
||
return tSYMBEG;
|
||
case 'h':
|
||
p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
|
||
return tHASHEXPAND_BEG;
|
||
default:
|
||
yyerror0("unknown type of %string");
|
||
return 0;
|
test/ripper/dummyparser.rb | ||
---|---|---|
symbols.push Node::Sym.new(symbol)
|
||
end
|
||
def on_hashexpand_new
|
||
# NodeList.new
|
||
Node.new('assoc')
|
||
end
|
||
def on_hashexpand_add(hashexpand, str)
|
||
pp hashexpand
|
||
# hashexpand.push Node::Sym.new(str)
|
||
# hashexpand.push str
|
||
end
|
||
def on_mlhs_new
|
||
NodeList.new
|
||
end
|
test/ripper/test_parser_events.rb | ||
---|---|---|
assert_equal '[array([:a])]', tree
|
||
end
|
||
def test_hashexpand_add
|
||
thru_hasexpand_add = false
|
||
a = 1
|
||
b = 2
|
||
tree = parse('%h[a,b]', :on_hashexpand_add) {thru_hasexpand_add = true}
|
||
pp tree
|
||
# assert_equal true, thru_hasexpand_add
|
||
# assert_equal '[hash([:a,a,:b,b])]', tree
|
||
end
|
||
def test_qwords_new
|
||
thru_qwords_new = false
|
||
parse('%w[]', :on_qwords_new) {thru_qwords_new = true}
|
||
... | ... | |
assert_equal true, thru_symbols_new
|
||
end
|
||
def test_hashexpand_new
|
||
thru_hashexpand_new = false
|
||
parse('%h[]', :on_hashexpand_new) {thru_hashexpand_new = true}
|
||
assert_equal true, thru_hashexpand_new
|
||
end
|
||
def test_redo
|
||
thru_redo = false
|
||
parse('redo', :on_redo) {thru_redo = true}
|
test/ripper/test_scanner_events.rb | ||
---|---|---|
scan('symbols_beg', "%I(\nw)")
|
||
end
|
||
def test_hashexpand_beg
|
||
assert_equal [],
|
||
scan('hashexpand_beg', '')
|
||
assert_equal ['%h('],
|
||
scan('hashexpand_beg', '%h()')
|
||
assert_equal ['%h('],
|
||
scan('hashexpand_beg', '%h(w w w)')
|
||
assert_equal ['%h('],
|
||
scan('hashexpand_beg', '%h( w w w )')
|
||
assert_equal ['%h('],
|
||
scan('hashexpand_beg', "%h(\nw)")
|
||
end
|
||
def test_words_sep
|
||
assert_equal [],
|
||
scan('words_sep', '')
|
test/ruby/test_parse.rb | ||
---|---|---|
assert_valid_syntax('let () { m(a) do; end }')
|
||
end
|
||
def test_hashexpand_meth
|
||
"test_hashexpand_meth"
|
||
end
|
||
def test_hashexpand
|
||
hoge = 1
|
||
foo = "str"
|
||
bar = nil
|
||
@test_hashexpand_value = { a: 1 }
|
||
@@test_hashexpand_value = [1, 2]
|
||
hash = %h(hoge foo bar @test_hashexpand_value @@test_hashexpand_value test_hashexpand_meth)
|
||
assert_equal(
|
||
hash,
|
||
{ hoge: 1, foo: "str", bar: nil, "@test_hashexpand_value": { a: 1}, "@@test_hashexpand_value": [1, 2], test_hashexpand_meth: "test_hashexpand_meth" }
|
||
)
|
||
assert_equal(
|
||
hash.keys,
|
||
%i(hoge foo bar @test_hashexpand_value @@test_hashexpand_value test_hashexpand_meth)
|
||
)
|
||
str = 42
|
||
pp %h(#{foo})
|
||
assert_equal(%h(#{foo}), { str: 42 })
|
||
assert_operator(Hash, :===, hash)
|
||
proc { |value|
|
||
hoge = -1
|
||
assert_equal(%h(hoge foo value), { hoge: -1, foo: "str", value: 42 })
|
||
}.call 42
|
||
assert_equal(%h(hoge foo hoge), { hoge: hoge, foo: foo })
|
||
assert_equal(%h(hoge foo hoge).keys, %i(hoge foo))
|
||
assert_raise(NameError) do
|
||
%h(not_found)
|
||
end
|
||
end
|
||
=begin
|
||
def test_past_scope_variable
|
||
assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}}
|