ripper.y: fix word list events

* parse.y (parser_skip_words_sep): QWORDS_BEG should not include
  the first separators in ripper.

* parse.y (parser_parse_string): WORDS_SEP should not include
  the closing parentheses of a word list in ripper, should include
  spaces at beginning of lines.  [ruby-core:83864] [Bug #14126]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60883 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2017-11-23 04:30:23 +00:00
parent 717b7fd9c4
commit dee6a91002
2 changed files with 64 additions and 33 deletions

70
parse.y
View File

@ -5819,6 +5819,26 @@ parser_str_new(const char *p, long n, rb_encoding *enc, int func, rb_encoding *e
#define peekc() peekc_n(0) #define peekc() peekc_n(0)
#define peekc_n(n) (lex_p+(n) < lex_pend ? (unsigned char)lex_p[n] : -1) #define peekc_n(n) (lex_p+(n) < lex_pend ? (unsigned char)lex_p[n] : -1)
#ifdef RIPPER
static void
parser_add_delayed_token(struct parser_params *parser, const char *tok, const char *end)
{
if (tok < end) {
if (!has_delayed_token()) {
parser->delayed = rb_str_buf_new(1024);
rb_enc_associate(parser->delayed, current_enc);
parser->delayed_line = ruby_sourceline;
parser->delayed_col = (int)(tok - lex_pbeg);
}
rb_str_buf_cat(parser->delayed, tok, end - tok);
parser->tokp = end;
}
}
#define add_delayed_token(tok, end) parser_add_delayed_token(parser, (tok), (end))
#else
#define add_delayed_token(tok, end) ((void)(tok), (void)(end))
#endif
static int static int
parser_nextline(struct parser_params *parser) parser_nextline(struct parser_params *parser)
{ {
@ -5835,22 +5855,7 @@ parser_nextline(struct parser_params *parser)
} }
parser->cr_seen = FALSE; parser->cr_seen = FALSE;
} }
#ifdef RIPPER add_delayed_token(parser->tokp, lex_pend);
if (parser->tokp < lex_pend) {
if (!has_delayed_token()) {
parser->delayed = rb_str_buf_new(1024);
rb_enc_associate(parser->delayed, current_enc);
rb_str_buf_cat(parser->delayed,
parser->tokp, lex_pend - parser->tokp);
parser->delayed_line = ruby_sourceline;
parser->delayed_col = (int)(parser->tokp - lex_pbeg);
}
else {
rb_str_buf_cat(parser->delayed,
parser->tokp, lex_pend - parser->tokp);
}
}
#endif
if (heredoc_end > 0) { if (heredoc_end > 0) {
ruby_sourceline = heredoc_end; ruby_sourceline = heredoc_end;
heredoc_end = 0; heredoc_end = 0;
@ -6597,6 +6602,9 @@ parser_parse_string(struct parser_params *parser, rb_strterm_literal_t *quote)
VALUE lit; VALUE lit;
if (func & STR_FUNC_TERM) { if (func & STR_FUNC_TERM) {
#ifdef RIPPER
if (func & STR_FUNC_QWORDS) nextc(); /* delayed term */
#endif
SET_LEX_STATE(EXPR_END|EXPR_ENDARG); SET_LEX_STATE(EXPR_END|EXPR_ENDARG);
lex_strterm = 0; lex_strterm = 0;
return func & STR_FUNC_REGEXP ? tREGEXP_END : tSTRING_END; return func & STR_FUNC_REGEXP ? tREGEXP_END : tSTRING_END;
@ -6609,12 +6617,17 @@ parser_parse_string(struct parser_params *parser, rb_strterm_literal_t *quote)
if (c == term && !quote->u0.nest) { if (c == term && !quote->u0.nest) {
if (func & STR_FUNC_QWORDS) { if (func & STR_FUNC_QWORDS) {
quote->u1.func |= STR_FUNC_TERM; quote->u1.func |= STR_FUNC_TERM;
#ifdef RIPPER
pushback(c); /* dispatch the term at tSTRING_END */
#endif
add_delayed_token(parser->tokp, lex_p);
return ' '; return ' ';
} }
return parser_string_term(parser, func); return parser_string_term(parser, func);
} }
if (space) { if (space) {
pushback(c); pushback(c);
add_delayed_token(parser->tokp, lex_p);
return ' '; return ' ';
} }
newtok(); newtok();
@ -7853,6 +7866,19 @@ parse_qmark(struct parser_params *parser, int space_seen)
return tCHAR; return tCHAR;
} }
#ifndef RIPPER
static void
parser_skip_words_sep(struct parser_params *parser)
{
int c;
do {c = nextc();} while (ISSPACE(c));
pushback(c);
}
#define skip_words_sep() parser_skip_words_sep(parser)
#else
#define skip_words_sep() ((void)0)
#endif
static enum yytokentype static enum yytokentype
parse_percent(struct parser_params *parser, const int space_seen, const enum lex_state_e last_state) parse_percent(struct parser_params *parser, const int space_seen, const enum lex_state_e last_state)
{ {
@ -7897,26 +7923,22 @@ parse_percent(struct parser_params *parser, const int space_seen, const enum lex
case 'W': case 'W':
lex_strterm = NEW_STRTERM(str_dword, term, paren); lex_strterm = NEW_STRTERM(str_dword, term, paren);
do {c = nextc();} while (ISSPACE(c)); skip_words_sep();
pushback(c);
return tWORDS_BEG; return tWORDS_BEG;
case 'w': case 'w':
lex_strterm = NEW_STRTERM(str_sword, term, paren); lex_strterm = NEW_STRTERM(str_sword, term, paren);
do {c = nextc();} while (ISSPACE(c)); skip_words_sep();
pushback(c);
return tQWORDS_BEG; return tQWORDS_BEG;
case 'I': case 'I':
lex_strterm = NEW_STRTERM(str_dword, term, paren); lex_strterm = NEW_STRTERM(str_dword, term, paren);
do {c = nextc();} while (ISSPACE(c)); skip_words_sep();
pushback(c);
return tSYMBOLS_BEG; return tSYMBOLS_BEG;
case 'i': case 'i':
lex_strterm = NEW_STRTERM(str_sword, term, paren); lex_strterm = NEW_STRTERM(str_sword, term, paren);
do {c = nextc();} while (ISSPACE(c)); skip_words_sep();
pushback(c);
return tQSYMBOLS_BEG; return tQSYMBOLS_BEG;
case 'x': case 'x':

View File

@ -637,8 +637,10 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
scan('words_beg', '%W()') scan('words_beg', '%W()')
assert_equal ['%W('], assert_equal ['%W('],
scan('words_beg', '%W(w w w)') scan('words_beg', '%W(w w w)')
assert_equal ['%W( '], assert_equal ['%W('],
scan('words_beg', '%W( w w w )') scan('words_beg', '%W( w w w )')
assert_equal ['%W('],
scan('words_beg', "%W(\nw)")
end end
def test_qwords_beg def test_qwords_beg
@ -648,8 +650,10 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
scan('qwords_beg', '%w()') scan('qwords_beg', '%w()')
assert_equal ['%w('], assert_equal ['%w('],
scan('qwords_beg', '%w(w w w)') scan('qwords_beg', '%w(w w w)')
assert_equal ['%w( '], assert_equal ['%w('],
scan('qwords_beg', '%w( w w w )') scan('qwords_beg', '%w( w w w )')
assert_equal ['%w('],
scan('qwords_beg', "%w(\nw)")
end end
def test_qsymbols_beg def test_qsymbols_beg
@ -659,8 +663,10 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
scan('qsymbols_beg', '%i()') scan('qsymbols_beg', '%i()')
assert_equal ['%i('], assert_equal ['%i('],
scan('qsymbols_beg', '%i(w w w)') scan('qsymbols_beg', '%i(w w w)')
assert_equal ['%i( '], assert_equal ['%i('],
scan('qsymbols_beg', '%i( w w w )') scan('qsymbols_beg', '%i( w w w )')
assert_equal ['%i('],
scan('qsymbols_beg', "%i(\nw)")
end end
def test_symbols_beg def test_symbols_beg
@ -670,22 +676,25 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
scan('symbols_beg', '%I()') scan('symbols_beg', '%I()')
assert_equal ['%I('], assert_equal ['%I('],
scan('symbols_beg', '%I(w w w)') scan('symbols_beg', '%I(w w w)')
assert_equal ['%I( '], assert_equal ['%I('],
scan('symbols_beg', '%I( w w w )') scan('symbols_beg', '%I( w w w )')
assert_equal ['%I('],
scan('symbols_beg', "%I(\nw)")
end end
# FIXME: Close paren must not present (`words_end' scanner event?).
def test_words_sep def test_words_sep
assert_equal [], assert_equal [],
scan('words_sep', '') scan('words_sep', '')
assert_equal [')'], assert_equal [],
scan('words_sep', '%w()') scan('words_sep', '%w()')
assert_equal [' ', ' ', ')'], assert_equal [' ', ' '],
scan('words_sep', '%w(w w w)') scan('words_sep', '%w(w w w)')
assert_equal [' ', ' ', ' )'], assert_equal [' ', ' ', ' ', ' '],
scan('words_sep', '%w( w w w )') scan('words_sep', '%w( w w w )')
assert_equal ["\n", ' ', ' )'], assert_equal [' ', "\n", ' ', ' '],
scan('words_sep', "%w( w\nw w )") scan('words_sep', "%w( w\nw w )")
assert_equal ["\n\n", "\n ", ' ', ' '],
scan('words_sep', "%w(\n\nw\n w w )")
end end
def test_heredoc_beg def test_heredoc_beg