summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-07-17 00:11:38 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-07-17 00:11:38 +0000
commit28695a8fff7c04224a58cdb9cb1adeb5810b719c (patch)
tree9509af81484fa953240e12d88fc527b8f6d8e56d
parentb17efb6874345c2dc8dc41f76226463b9a785123 (diff)
parse.y: refine literal error messages
* parse.y (parser_yyerror): strip newline in error source which will not be printed, when lex_p has passed it. * parse.y (parser_tokadd_utf8): unterminated Unicode escape even after invalid Unicode escape. * parse.y (parser_parse_string): show the error source line when unterminated literal at end of file. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59349 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--parse.y36
-rw-r--r--test/ruby/test_parse.rb18
2 files changed, 37 insertions, 17 deletions
diff --git a/parse.y b/parse.y
index ceb8cc8..3a58d2e 100644
--- a/parse.y
+++ b/parse.y
@@ -5042,15 +5042,15 @@ parser_yyerror(struct parser_params *parser, const char *msg)
long len;
int i;
- p = lex_p;
- lim = p - lex_pbeg > max_line_margin ? p - max_line_margin : lex_pbeg;
- while ((lim < p) && (*(p-1) != '\n')) p--;
-
pend = lex_pend;
if (pend > lex_pbeg && pend[-1] == '\n') {
if (--pend > lex_pbeg && pend[-1] == '\r') --pend;
}
- pe = lex_p;
+
+ p = pe = lex_p < pend ? lex_p : pend;
+ lim = p - lex_pbeg > max_line_margin ? p - max_line_margin : lex_pbeg;
+ while ((lim < p) && (*(p-1) != '\n')) p--;
+
lim = pend - pe > max_line_margin ? pe + max_line_margin : pend;
while ((pe < lim) && (*pe != '\n')) pe++;
@@ -5067,20 +5067,22 @@ parser_yyerror(struct parser_params *parser, const char *msg)
if (pe < pend) post = "...";
}
len = pe - p;
- i = (int)(lex_p - p);
+ lim = lex_p < pend ? lex_p : pend;
+ i = (int)(lim - p);
buf = ALLOCA_N(char, i+2);
code = p;
caret = p2 = buf;
- if (p <= parser->tokp) {
- while (p < parser->tokp) {
+ pe = (parser->tokp < lim ? parser->tokp : lim);
+ if (p <= pe) {
+ while (p < pe) {
*p2++ = *p++ == '\t' ? '\t' : ' ';
}
*p2++ = '^';
p++;
}
- if (lex_p > p) {
- memset(p2, '~', (lex_p - p));
- p2 += (lex_p - p);
+ if (lim > p) {
+ memset(p2, '~', (lim - p));
+ p2 += (lim - p);
}
*p2 = '\0';
newline = "\n";
@@ -5711,7 +5713,7 @@ parser_tokadd_utf8(struct parser_params *parser, rb_encoding **encp,
while (!string_literal || c != close_brace) {
if (regexp_literal) tokadd(last);
if (!parser_tokadd_codepoint(parser, encp, regexp_literal, TRUE)) {
- return 0;
+ break;
}
while (ISSPACE(c = *lex_p)) {
if (++lex_p >= lex_pend) goto unterminated;
@@ -6282,11 +6284,17 @@ parser_parse_string(struct parser_params *parser, NODE *quote)
if (tokadd_string(func, term, paren, &quote->nd_nest,
&enc) == -1) {
if (parser->eofp) {
+#ifndef RIPPER
+# define unterminated_literal(mesg) yyerror(mesg)
+#else
+# define unterminated_literal(mesg) compile_error(PARSER_ARG mesg)
+#endif
+ literal_flush(lex_p);
if (func & STR_FUNC_REGEXP) {
- compile_error(PARSER_ARG "unterminated regexp meets end of file");
+ unterminated_literal("unterminated regexp meets end of file");
}
else {
- compile_error(PARSER_ARG "unterminated string meets end of file");
+ unterminated_literal("unterminated string meets end of file");
}
quote->nd_func |= STR_FUNC_TERM;
}
diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb
index 7ce2366..982f91d 100644
--- a/test/ruby/test_parse.rb
+++ b/test/ruby/test_parse.rb
@@ -489,11 +489,23 @@ class TestParse < Test::Unit::TestCase
e = assert_syntax_error('"\xg1"', /hex escape/)
assert_equal(' ^', e.message.lines.last, mesg)
- e = assert_syntax_error('"\u{1234"', 'Unicode escape')
- assert_match(' ^', e.message.lines.last, mesg)
+ e = assert_syntax_error('"\u{1234"', 'unterminated Unicode escape')
+ assert_equal(' ^', e.message.lines.last, mesg)
e = assert_syntax_error('"\u{xxxx}"', 'invalid Unicode escape')
- assert_match(' ^', e.message.lines.last, mesg)
+ assert_equal(' ^', e.message.lines.last, mesg)
+
+ e = assert_syntax_error('"\u{xxxx', 'Unicode escape')
+ assert_pattern_list([
+ /.*: invalid Unicode escape\n.*\n/,
+ / \^/,
+ /\n/,
+ /.*: unterminated Unicode escape\n.*\n/,
+ / \^/,
+ /\n/,
+ /.*: unterminated string.*\n.*\n/,
+ / \^/,
+ ], e.message)
e = assert_syntax_error('"\M1"', /escape character syntax/)
assert_equal(' ^~~', e.message.lines.last, mesg)