mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
parse.y: warn escaped whitespace
* parse.y (warn_space_char_code): warn whitespace characters escaped with meta/control prefix.
This commit is contained in:
parent
fb568fe724
commit
c730c25354
3 changed files with 91 additions and 22 deletions
86
parse.y
86
parse.y
|
@ -6138,6 +6138,36 @@ tok_hex(struct parser_params *p, size_t *numlen)
|
||||||
|
|
||||||
#define tokcopy(p, n) memcpy(tokspace(p, n), (p)->lex.pcur - (n), (n))
|
#define tokcopy(p, n) memcpy(tokspace(p, n), (p)->lex.pcur - (n), (n))
|
||||||
|
|
||||||
|
static int
|
||||||
|
escaped_control_code(int c)
|
||||||
|
{
|
||||||
|
int c2 = 0;
|
||||||
|
switch (c) {
|
||||||
|
case ' ':
|
||||||
|
c2 = 's';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
c2 = 'n';
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
c2 = 't';
|
||||||
|
break;
|
||||||
|
case '\v':
|
||||||
|
c2 = 'v';
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
c2 = 'r';
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
c2 = 'f';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return c2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WARN_SPACE_CHAR(c, prefix) \
|
||||||
|
rb_warn1("invalid character syntax; use "prefix"\\%c", WARN_I(c2))
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tokadd_codepoint(struct parser_params *p, rb_encoding **encp,
|
tokadd_codepoint(struct parser_params *p, rb_encoding **encp,
|
||||||
int regexp_literal, int wide)
|
int regexp_literal, int wide)
|
||||||
|
@ -6290,6 +6320,16 @@ read_escape(struct parser_params *p, int flags, rb_encoding **encp)
|
||||||
}
|
}
|
||||||
else if (c == -1 || !ISASCII(c)) goto eof;
|
else if (c == -1 || !ISASCII(c)) goto eof;
|
||||||
else {
|
else {
|
||||||
|
int c2 = escaped_control_code(c);
|
||||||
|
if (c2) {
|
||||||
|
if (ISCNTRL(c) || !(flags & ESCAPE_CONTROL)) {
|
||||||
|
WARN_SPACE_CHAR(c2, "\\M-");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WARN_SPACE_CHAR(c2, "\\C-\\M-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ISCNTRL(c)) goto eof;
|
||||||
return ((c & 0xff) | 0x80);
|
return ((c & 0xff) | 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6306,6 +6346,28 @@ read_escape(struct parser_params *p, int flags, rb_encoding **encp)
|
||||||
else if (c == '?')
|
else if (c == '?')
|
||||||
return 0177;
|
return 0177;
|
||||||
else if (c == -1 || !ISASCII(c)) goto eof;
|
else if (c == -1 || !ISASCII(c)) goto eof;
|
||||||
|
else {
|
||||||
|
int c2 = escaped_control_code(c);
|
||||||
|
if (c2) {
|
||||||
|
if (ISCNTRL(c)) {
|
||||||
|
if (flags & ESCAPE_META) {
|
||||||
|
WARN_SPACE_CHAR(c2, "\\M-");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WARN_SPACE_CHAR(c2, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (flags & ESCAPE_META) {
|
||||||
|
WARN_SPACE_CHAR(c2, "\\M-\\C-");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WARN_SPACE_CHAR(c2, "\\C-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ISCNTRL(c)) goto eof;
|
||||||
|
}
|
||||||
return c & 0x9f;
|
return c & 0x9f;
|
||||||
|
|
||||||
eof:
|
eof:
|
||||||
|
@ -8009,29 +8071,9 @@ parse_qmark(struct parser_params *p, int space_seen)
|
||||||
}
|
}
|
||||||
if (rb_enc_isspace(c, p->enc)) {
|
if (rb_enc_isspace(c, p->enc)) {
|
||||||
if (!IS_ARG()) {
|
if (!IS_ARG()) {
|
||||||
int c2 = 0;
|
int c2 = escaped_control_code(c);
|
||||||
switch (c) {
|
|
||||||
case ' ':
|
|
||||||
c2 = 's';
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
c2 = 'n';
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
c2 = 't';
|
|
||||||
break;
|
|
||||||
case '\v':
|
|
||||||
c2 = 'v';
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
c2 = 'r';
|
|
||||||
break;
|
|
||||||
case '\f':
|
|
||||||
c2 = 'f';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c2) {
|
if (c2) {
|
||||||
rb_warn1("invalid character syntax; use ?\\%c", WARN_I(c2));
|
WARN_SPACE_CHAR(c2, "?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ternary:
|
ternary:
|
||||||
|
|
|
@ -45,6 +45,7 @@ class TestRubyLiteral < Test::Unit::TestCase
|
||||||
assert_equal "A", ?A
|
assert_equal "A", ?A
|
||||||
assert_instance_of String, ?\n
|
assert_instance_of String, ?\n
|
||||||
assert_equal "\n", ?\n
|
assert_equal "\n", ?\n
|
||||||
|
assert_equal " ", ?\s
|
||||||
assert_equal " ", ?\ # space
|
assert_equal " ", ?\ # space
|
||||||
assert_equal '', ''
|
assert_equal '', ''
|
||||||
assert_equal 'string', 'string'
|
assert_equal 'string', 'string'
|
||||||
|
|
|
@ -548,6 +548,19 @@ class TestParse < Test::Unit::TestCase
|
||||||
|
|
||||||
assert_equal("\x81", eval('"\C-\M-a"'))
|
assert_equal("\x81", eval('"\C-\M-a"'))
|
||||||
assert_equal("\177", eval('"\c?"'))
|
assert_equal("\177", eval('"\c?"'))
|
||||||
|
|
||||||
|
assert_warning(/use \\C-\\s/) {assert_equal("\x00", eval('"\C- "'))}
|
||||||
|
assert_warning(/use \\M-\\s/) {assert_equal("\xa0", eval('"\M- "'))}
|
||||||
|
assert_warning(/use \\M-\\C-\\s/) {assert_equal("\x80", eval('"\M-\C- "'))}
|
||||||
|
assert_warning(/use \\C-\\M-\\s/) {assert_equal("\x80", eval('"\C-\M- "'))}
|
||||||
|
assert_warning(/use \\t/) {assert_equal("\x09", eval("\"\\C-\t\""))}
|
||||||
|
assert_warning(/use \\M-\\t/) {assert_equal("\x89", eval("\"\\M-\t\""))}
|
||||||
|
assert_warning(/use \\M-\\t/) {assert_equal("\x89", eval("\"\\M-\\C-\t\""))}
|
||||||
|
assert_warning(/use \\M-\\t/) {assert_equal("\x89", eval("\"\\C-\\M-\t\""))}
|
||||||
|
assert_syntax_error("\"\\C-\x01\"", 'Invalid escape character syntax')
|
||||||
|
assert_syntax_error("\"\\M-\x01\"", 'Invalid escape character syntax')
|
||||||
|
assert_syntax_error("\"\\M-\\C-\x01\"", 'Invalid escape character syntax')
|
||||||
|
assert_syntax_error("\"\\C-\\M-\x01\"", 'Invalid escape character syntax')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_question
|
def test_question
|
||||||
|
@ -565,6 +578,19 @@ class TestParse < Test::Unit::TestCase
|
||||||
assert_equal("\u{1234}", eval('?\u1234'))
|
assert_equal("\u{1234}", eval('?\u1234'))
|
||||||
e = assert_syntax_error('"#{?\u123}"', 'invalid Unicode escape')
|
e = assert_syntax_error('"#{?\u123}"', 'invalid Unicode escape')
|
||||||
assert_not_match(/end-of-input/, e.message)
|
assert_not_match(/end-of-input/, e.message)
|
||||||
|
|
||||||
|
assert_warning(/use ?\\C-\\s/) {assert_equal("\x00", eval('?\C- '))}
|
||||||
|
assert_warning(/use ?\\M-\\s/) {assert_equal("\xa0", eval('?\M- '))}
|
||||||
|
assert_warning(/use ?\\M-\\C-\\s/) {assert_equal("\x80", eval('?\M-\C- '))}
|
||||||
|
assert_warning(/use ?\\C-\\M-\\s/) {assert_equal("\x80", eval('?\C-\M- '))}
|
||||||
|
assert_warning(/use ?\\t/) {assert_equal("\x09", eval("?\\C-\t"))}
|
||||||
|
assert_warning(/use ?\\M-\\t/) {assert_equal("\x89", eval("?\\M-\t"))}
|
||||||
|
assert_warning(/use ?\\M-\\t/) {assert_equal("\x89", eval("?\\M-\\C-\t"))}
|
||||||
|
assert_warning(/use ?\\M-\\t/) {assert_equal("\x89", eval("?\\C-\\M-\t"))}
|
||||||
|
assert_syntax_error("?\\C-\x01", 'Invalid escape character syntax')
|
||||||
|
assert_syntax_error("?\\M-\x01", 'Invalid escape character syntax')
|
||||||
|
assert_syntax_error("?\\M-\\C-\x01", 'Invalid escape character syntax')
|
||||||
|
assert_syntax_error("?\\C-\\M-\x01", 'Invalid escape character syntax')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_percent
|
def test_percent
|
||||||
|
|
Loading…
Reference in a new issue