Permalink
Browse files

* parse.y: added symbols and qsymbols productions for %i and %I

  support. %i{ .. } returns a list of symbols without interpolation,
  %I{ .. } returns a list of symbols with interpolation.  Thanks to
  Josh Susser for inspiration of this feature. [Feature #4985]

* ext/ripper/eventids2.c: added ripper events for %i and %I.

* test/ripper/test_parser_events.rb: ripper tests

* test/ripper/test_scanner_events.rb: ditto

* test/ruby/test_array.rb: test for %i and %I behavior

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36524 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information...
tenderlove
tenderlove committed Jul 24, 2012
1 parent 1a5773a commit 91bd6e711db3418baa287e936d4b0fac99927711
Showing with 177 additions and 2 deletions.
  1. +15 −0 ChangeLog
  2. +3 −0 NEWS
  3. +6 −0 ext/ripper/eventids2.c
  4. +96 −2 parse.y
  5. +24 −0 test/ripper/test_parser_events.rb
  6. +22 −0 test/ripper/test_scanner_events.rb
  7. +11 −0 test/ruby/test_array.rb
View
@@ -1,3 +1,18 @@
+Wed Jul 25 03:05:06 2012 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * parse.y: added symbols and qsymbols productions for %i and %I
+ support. %i{ .. } returns a list of symbols without interpolation,
+ %I{ .. } returns a list of symbols with interpolation. Thanks to
+ Josh Susser for inspiration of this feature. [Feature #4985]
+
+ * ext/ripper/eventids2.c: added ripper events for %i and %I.
+
+ * test/ripper/test_parser_events.rb: ripper tests
+
+ * test/ripper/test_scanner_events.rb: ditto
+
+ * test/ruby/test_array.rb: test for %i and %I behavior
+
Tue Jul 24 23:34:43 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com>
* include/ruby/win32.h (rb_w32_pow): add new function.
View
3 NEWS
@@ -169,6 +169,9 @@ with all sufficient information, see the ChangeLog file.
long.
=== Language changes
+
+ * Added %i and %I for symbol list creation (similar to %w and %W).
+
=== Compatibility issues (excluding feature bug fixes)
* Signal.trap
View
@@ -38,6 +38,8 @@ static ID ripper_id_tstring_content;
static ID ripper_id_tstring_end;
static ID ripper_id_words_beg;
static ID ripper_id_qwords_beg;
+static ID ripper_id_qsymbols_beg;
+static ID ripper_id_symbols_beg;
static ID ripper_id_words_sep;
static ID ripper_id_regexp_beg;
static ID ripper_id_regexp_end;
@@ -91,6 +93,8 @@ ripper_init_eventids2(void)
ripper_id_tstring_end = rb_intern_const("on_tstring_end");
ripper_id_words_beg = rb_intern_const("on_words_beg");
ripper_id_qwords_beg = rb_intern_const("on_qwords_beg");
+ ripper_id_qsymbols_beg = rb_intern_const("on_qsymbols_beg");
+ ripper_id_symbols_beg = rb_intern_const("on_symbols_beg");
ripper_id_words_sep = rb_intern_const("on_words_sep");
ripper_id_regexp_beg = rb_intern_const("on_regexp_beg");
ripper_id_regexp_end = rb_intern_const("on_regexp_end");
@@ -228,6 +232,8 @@ static const struct token_assoc {
{tOROP, &ripper_id_op},
{tPOW, &ripper_id_op},
{tQWORDS_BEG, &ripper_id_qwords_beg},
+ {tQSYMBOLS_BEG, &ripper_id_qsymbols_beg},
+ {tSYMBOLS_BEG, &ripper_id_symbols_beg},
{tREGEXP_BEG, &ripper_id_regexp_beg},
{tREGEXP_END, &ripper_id_regexp_end},
{tRPAREN, &ripper_id_rparen},
View
98 parse.y
@@ -715,7 +715,7 @@ static void token_info_pop(struct parser_params*, const char *token);
%type <node> singleton strings string string1 xstring regexp
%type <node> string_contents xstring_contents regexp_contents string_content
-%type <node> words qwords word_list qword_list word
+%type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word
%type <node> literal numeric dsym cpath
%type <node> top_compstmt top_stmts top_stmt
%type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
@@ -769,7 +769,7 @@ static void token_info_pop(struct parser_params*, const char *token);
%token tDSTAR /* ** */
%token tAMPER /* & */
%token tLAMBDA /* -> */
-%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG
+%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG
%token tSTRING_DBEG tSTRING_DEND tSTRING_DVAR tSTRING_END tLAMBEG
/*
@@ -2672,6 +2672,8 @@ primary : literal
| regexp
| words
| qwords
+ | symbols
+ | qsymbols
| var_ref
| backref
| tFID
@@ -4105,6 +4107,45 @@ word : string_content
}
;
+symbols : tSYMBOLS_BEG ' ' tSTRING_END
+ {
+ /*%%%*/
+ $$ = NEW_ZARRAY();
+ /*%
+ $$ = dispatch0(symbols_new);
+ $$ = dispatch1(array, $$);
+ %*/
+ }
+ | tSYMBOLS_BEG symbol_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = $2;
+ /*%
+ $$ = dispatch1(array, $2);
+ %*/
+ }
+ ;
+
+symbol_list : /* none */
+ {
+ /*%%%*/
+ $$ = 0;
+ /*%
+ $$ = dispatch0(symbols_new);
+ %*/
+ }
+ | symbol_list word ' '
+ {
+ /*%%%*/
+ $2 = evstr2dstr($2);
+ nd_set_type($2, NODE_DSYM);
+ $$ = list_append($1, $2);
+ /*%
+ $$ = dispatch2(symbols_add, $1, $2);
+ %*/
+ }
+ ;
+
qwords : tQWORDS_BEG ' ' tSTRING_END
{
/*%%%*/
@@ -4124,6 +4165,25 @@ qwords : tQWORDS_BEG ' ' tSTRING_END
}
;
+qsymbols : tQSYMBOLS_BEG ' ' tSTRING_END
+ {
+ /*%%%*/
+ $$ = NEW_ZARRAY();
+ /*%
+ $$ = dispatch0(qsymbols_new);
+ $$ = dispatch1(array, $$);
+ %*/
+ }
+ | tQSYMBOLS_BEG qsym_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = $2;
+ /*%
+ $$ = dispatch1(array, $2);
+ %*/
+ }
+ ;
+
qword_list : /* none */
{
/*%%%*/
@@ -4142,6 +4202,28 @@ qword_list : /* none */
}
;
+qsym_list : /* none */
+ {
+ /*%%%*/
+ $$ = 0;
+ /*%
+ $$ = dispatch0(qsymbols_new);
+ %*/
+ }
+ | qsym_list tSTRING_CONTENT ' '
+ {
+ /*%%%*/
+ VALUE lit;
+ lit = $2->nd_lit;
+ $2->nd_lit = ID2SYM(rb_intern_str(lit));
+ nd_set_type($2, NODE_LIT);
+ $$ = list_append($1, $2);
+ /*%
+ $$ = dispatch2(qsymbols_add, $1, $2);
+ %*/
+ }
+ ;
+
string_contents : /* none */
{
/*%%%*/
@@ -7796,6 +7878,18 @@ parser_yylex(struct parser_params *parser)
pushback(c);
return tQWORDS_BEG;
+ case 'I':
+ lex_strterm = NEW_STRTERM(str_dword, term, paren);
+ do {c = nextc();} while (ISSPACE(c));
+ pushback(c);
+ return tSYMBOLS_BEG;
+
+ case 'i':
+ lex_strterm = NEW_STRTERM(str_sword, term, paren);
+ do {c = nextc();} while (ISSPACE(c));
+ pushback(c);
+ return tQSYMBOLS_BEG;
+
case 'x':
lex_strterm = NEW_STRTERM(str_xquote, term, paren);
return tXSTRING_BEG;
@@ -755,12 +755,36 @@ def test_qwords_add
assert_equal true, thru_qwords_add
end
+ def test_qsymbols_add
+ thru_qsymbols_add = false
+ parse('%i[a]', :on_qsymbols_add) {thru_qsymbols_add = true}
+ assert_equal true, thru_qsymbols_add
+ end
+
+ def test_symbols_add
+ thru_symbols_add = false
+ parse('%I[a]', :on_symbols_add) {thru_symbols_add = true}
+ assert_equal true, thru_symbols_add
+ end
+
def test_qwords_new
thru_qwords_new = false
parse('%w[]', :on_qwords_new) {thru_qwords_new = true}
assert_equal true, thru_qwords_new
end
+ def test_qsymbols_new
+ thru_qsymbols_new = false
+ parse('%i[]', :on_qsymbols_new) {thru_qsymbols_new = true}
+ assert_equal true, thru_qsymbols_new
+ end
+
+ def test_symbols_new
+ thru_symbols_new = false
+ parse('%I[]', :on_symbols_new) {thru_symbols_new = true}
+ assert_equal true, thru_symbols_new
+ end
+
def test_redo
thru_redo = false
parse('redo', :on_redo) {thru_redo = true}
@@ -608,6 +608,28 @@ def test_qwords_beg
scan('qwords_beg', '%w( w w w )')
end
+ def test_qsymbols_beg
+ assert_equal [],
+ scan('qsymbols_beg', '')
+ assert_equal ['%i('],
+ scan('qsymbols_beg', '%i()')
+ assert_equal ['%i('],
+ scan('qsymbols_beg', '%i(w w w)')
+ assert_equal ['%i( '],
+ scan('qsymbols_beg', '%i( w w w )')
+ end
+
+ def test_symbols_beg
+ assert_equal [],
+ scan('symbols_beg', '')
+ assert_equal ['%I('],
+ scan('symbols_beg', '%I()')
+ assert_equal ['%I('],
+ scan('symbols_beg', '%I(w w w)')
+ assert_equal ['%I( '],
+ scan('symbols_beg', '%I( w w w )')
+ end
+
# FIXME: Close paren must not present (`words_end' scanner event?).
def test_words_sep
assert_equal [],
View
@@ -12,6 +12,17 @@ def teardown
$VERBOSE = @verbose
end
+ def test_percent_i
+ assert_equal([:foo, :bar], %i[foo bar])
+ assert_equal([:"\"foo"], %i["foo])
+ end
+
+ def test_percent_I
+ x = 10
+ assert_equal([:foo, :b10], %I[foo b#{x}])
+ assert_equal([:"\"foo10"], %I["foo#{x}])
+ end
+
def test_0_literal
assert_equal([1, 2, 3, 4], [1, 2] + [3, 4])
assert_equal([1, 2, 1, 2], [1, 2] * 2)

14 comments on commit 91bd6e7

@jassa

This comment has been minimized.

Show comment
Hide comment
@jassa

jassa Jul 26, 2012

nice feature! 👍

nice feature! 👍

@saks

This comment has been minimized.

Show comment
Hide comment
@saks

saks Jul 26, 2012

+1 for that!

saks replied Jul 26, 2012

+1 for that!

@justbaker

This comment has been minimized.

Show comment
Hide comment
@justbaker

justbaker Jul 26, 2012

+1 pure winning.

+1 pure winning.

@flori

This comment has been minimized.

Show comment
Hide comment
@flori

flori Jul 26, 2012

Just discussed this in the team last week as a nice to have, and soon we have. Thx!

Just discussed this in the team last week as a nice to have, and soon we have. Thx!

@skalnik

This comment has been minimized.

Show comment
Hide comment
@skalnik

skalnik Jul 26, 2012

👍. I've had this on my "Things To Do" list for a while. Guess I'll delete that now.

👍. I've had this on my "Things To Do" list for a while. Guess I'll delete that now.

@edzhelyov

This comment has been minimized.

Show comment
Hide comment
@edzhelyov

edzhelyov Jul 27, 2012

Come on guys, you just complicated the language and forced every other implementation to implement that for having a syntax sugar for clearing list of symbols ....

Come on guys, you just complicated the language and forced every other implementation to implement that for having a syntax sugar for clearing list of symbols ....

@EinLama

This comment has been minimized.

Show comment
Hide comment
@EinLama

EinLama Jul 28, 2012

You should not bother about other implementations having a hard time to adapt - instead care about making life easier for people who actually write code using the language :)

+1 from me!

You should not bother about other implementations having a hard time to adapt - instead care about making life easier for people who actually write code using the language :)

+1 from me!

@edzhelyov

This comment has been minimized.

Show comment
Hide comment
@edzhelyov

edzhelyov Jul 28, 2012

Having a syntax sugar for writing arrays of symbols will not make your life easier as programmer, reducing the accidental and unneeded complexity will make it easier ... and Ruby is already cluttered and complex enough.

Having a syntax sugar for writing arrays of symbols will not make your life easier as programmer, reducing the accidental and unneeded complexity will make it easier ... and Ruby is already cluttered and complex enough.

@jmonteiro

This comment has been minimized.

Show comment
Hide comment
@jmonteiro

jmonteiro Aug 21, 2012

🆒 that's a nice feature. That might not make the life easier for everybody, but it does for me.

🆒 that's a nice feature. That might not make the life easier for everybody, but it does for me.

@edzhelyov

This comment has been minimized.

Show comment
Hide comment
@edzhelyov

edzhelyov Aug 21, 2012

I will refer to the Rich Hickey talk - "Simple made easy" (http://www.infoq.com/presentations/Simple-Made-Easy).

Our job is to avoid the unnecessary complexity and provide simplistic, good solutions.
I urge the people behind big communities like Ruby, to acknowledge this and serve as role models for better and stop introducing needless complexity for the sake of "easier" life.

I will refer to the Rich Hickey talk - "Simple made easy" (http://www.infoq.com/presentations/Simple-Made-Easy).

Our job is to avoid the unnecessary complexity and provide simplistic, good solutions.
I urge the people behind big communities like Ruby, to acknowledge this and serve as role models for better and stop introducing needless complexity for the sake of "easier" life.

@drbrain

This comment has been minimized.

Show comment
Hide comment
@drbrain

drbrain Aug 21, 2012

Member

My only regret is that I will not be able to use this new syntax for a long time because ruby 1.9 does not support it… I can't wait!

Member

drbrain replied Aug 21, 2012

My only regret is that I will not be able to use this new syntax for a long time because ruby 1.9 does not support it… I can't wait!

@flori

This comment has been minimized.

Show comment
Hide comment
@flori

flori Aug 21, 2012

From my experience, simplicity is not a primary goal.
Seeking simplicity in language design does not help much, I think.

Because things too simple are difficult.
Because things too complex are difficult too.
Because human thoughts are not simple.
Because programs are essentially complex.
Because combination of simple concepts can be complex very easily.

-- Yukihiro Matsumoto, http://www.rubyist.net/~matz/slides/oscon2003/mgp00047.html

From my experience, simplicity is not a primary goal.
Seeking simplicity in language design does not help much, I think.

Because things too simple are difficult.
Because things too complex are difficult too.
Because human thoughts are not simple.
Because programs are essentially complex.
Because combination of simple concepts can be complex very easily.

-- Yukihiro Matsumoto, http://www.rubyist.net/~matz/slides/oscon2003/mgp00047.html

@dexterous

This comment has been minimized.

Show comment
Hide comment
@dexterous

dexterous Sep 7, 2012

I'm curious though, what would be a real world use case of this feature?

I'm curious though, what would be a real world use case of this feature?

@elight

This comment has been minimized.

Show comment
Hide comment
@elight

elight Sep 8, 2012

Good one, Josh!

Good one, Josh!

Please sign in to comment.