Simplify scanner and generate better error message for legacy octals in templates
LOG=N BUG= R=arv@chromium.org, dslomov@chromium.org Review URL: https://codereview.chromium.org/812163003 Cr-Commit-Position: refs/heads/master@{#25895}
This commit is contained in:
parent
b494f5cdb8
commit
233f2d2bf1
@ -154,6 +154,7 @@ var kMessages = {
|
||||
too_many_variables: ["Too many variables declared (only 4194303 allowed)"],
|
||||
strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
|
||||
strict_octal_literal: ["Octal literals are not allowed in strict mode."],
|
||||
template_octal_literal: ["Octal literals are not allowed in template strings."],
|
||||
strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"],
|
||||
accessor_data_property: ["Object literal may not have data and accessor property with the same name"],
|
||||
accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"],
|
||||
|
@ -936,7 +936,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
|
||||
&ok);
|
||||
|
||||
if (ok && strict_mode() == STRICT) {
|
||||
CheckOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
|
||||
CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
|
||||
}
|
||||
|
||||
if (ok && allow_harmony_scoping() && strict_mode() == STRICT) {
|
||||
@ -3803,8 +3803,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
CHECK_OK);
|
||||
}
|
||||
if (strict_mode() == STRICT) {
|
||||
CheckOctalLiteral(scope->start_position(),
|
||||
scope->end_position(),
|
||||
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
|
||||
CHECK_OK);
|
||||
}
|
||||
if (allow_harmony_scoping() && strict_mode() == STRICT) {
|
||||
|
@ -125,7 +125,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
||||
DCHECK_EQ(Token::RBRACE, scanner()->peek());
|
||||
if (scope_->strict_mode() == STRICT) {
|
||||
int end_pos = scanner()->location().end_pos;
|
||||
CheckOctalLiteral(start_position, end_pos, &ok);
|
||||
CheckStrictOctalLiteral(start_position, end_pos, &ok);
|
||||
}
|
||||
}
|
||||
return kPreParseSuccess;
|
||||
@ -937,7 +937,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
}
|
||||
|
||||
int end_position = scanner()->location().end_pos;
|
||||
CheckOctalLiteral(start_position, end_position, CHECK_OK);
|
||||
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
|
||||
}
|
||||
|
||||
return Expression::Default();
|
||||
|
@ -385,17 +385,26 @@ class ParserBase : public Traits {
|
||||
}
|
||||
|
||||
// Checks whether an octal literal was last seen between beg_pos and end_pos.
|
||||
// If so, reports an error. Only called for strict mode.
|
||||
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
||||
// If so, reports an error. Only called for strict mode and template strings.
|
||||
void CheckOctalLiteral(int beg_pos, int end_pos, const char* error,
|
||||
bool* ok) {
|
||||
Scanner::Location octal = scanner()->octal_position();
|
||||
if (octal.IsValid() && beg_pos <= octal.beg_pos &&
|
||||
octal.end_pos <= end_pos) {
|
||||
ReportMessageAt(octal, "strict_octal_literal");
|
||||
ReportMessageAt(octal, error);
|
||||
scanner()->clear_octal_position();
|
||||
*ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
||||
CheckOctalLiteral(beg_pos, end_pos, "strict_octal_literal", ok);
|
||||
}
|
||||
|
||||
inline void CheckTemplateOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
||||
CheckOctalLiteral(beg_pos, end_pos, "template_octal_literal", ok);
|
||||
}
|
||||
|
||||
// Validates strict mode for function parameter lists. This has to be
|
||||
// done after parsing the function, since the function can declare
|
||||
// itself strict.
|
||||
@ -1489,7 +1498,8 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
if (!ok) {
|
||||
ReportUnexpectedToken(scanner()->current_token());
|
||||
} else if (scope_->strict_mode() == STRICT) {
|
||||
CheckOctalLiteral(start_position, scanner()->location().end_pos, &ok);
|
||||
CheckStrictOctalLiteral(start_position, scanner()->location().end_pos,
|
||||
&ok);
|
||||
}
|
||||
if (materialized_literals) {
|
||||
*materialized_literals = function_state_->materialized_literal_count();
|
||||
@ -2802,7 +2812,8 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
|
||||
|
||||
// Validate strict mode.
|
||||
if (strict_mode() == STRICT) {
|
||||
CheckOctalLiteral(start_pos, scanner()->location().end_pos, CHECK_OK);
|
||||
CheckStrictOctalLiteral(start_pos, scanner()->location().end_pos,
|
||||
CHECK_OK);
|
||||
}
|
||||
|
||||
if (allow_harmony_scoping() && strict_mode() == STRICT)
|
||||
@ -2846,6 +2857,7 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) {
|
||||
if (peek() == Token::TEMPLATE_TAIL) {
|
||||
Consume(Token::TEMPLATE_TAIL);
|
||||
int pos = position();
|
||||
CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
|
||||
typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
|
||||
Traits::AddTemplateSpan(&ts, true);
|
||||
return Traits::CloseTemplateLiteral(&ts, start, tag);
|
||||
@ -2897,6 +2909,7 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) {
|
||||
} while (next == Token::TEMPLATE_SPAN);
|
||||
|
||||
DCHECK_EQ(next, Token::TEMPLATE_TAIL);
|
||||
CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
|
||||
// Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
|
||||
return Traits::CloseTemplateLiteral(&ts, start, tag);
|
||||
}
|
||||
|
@ -733,21 +733,7 @@ bool Scanner::ScanEscape() {
|
||||
if (c < 0) return false;
|
||||
break;
|
||||
}
|
||||
case '0':
|
||||
if (in_template_literal) {
|
||||
// \ 0 DecimalDigit is never allowed in templates.
|
||||
if (IsDecimalDigit(c0_)) {
|
||||
Advance<capture_raw>(); // Advance to include the problematic char.
|
||||
return false;
|
||||
}
|
||||
|
||||
// The TV of TemplateCharacter :: \ EscapeSequence is the CV of
|
||||
// EscapeSequence.
|
||||
// The CV of EscapeSequence :: 0 is the code unit value 0.
|
||||
c = 0;
|
||||
break;
|
||||
}
|
||||
// Fall through.
|
||||
case '0': // Fall through.
|
||||
case '1': // fall through
|
||||
case '2': // fall through
|
||||
case '3': // fall through
|
||||
@ -755,15 +741,9 @@ bool Scanner::ScanEscape() {
|
||||
case '5': // fall through
|
||||
case '6': // fall through
|
||||
case '7':
|
||||
if (!in_template_literal) {
|
||||
c = ScanOctalEscape<capture_raw>(c, 2);
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
case '8':
|
||||
case '9':
|
||||
if (in_template_literal) return false;
|
||||
}
|
||||
|
||||
// According to ECMA-262, section 7.8.4, characters not covered by the
|
||||
// above cases should be illegal, but they are commonly handled as
|
||||
|
@ -476,9 +476,11 @@ var obj = {
|
||||
(function testLegacyOctal() {
|
||||
assertEquals('\u0000', `\0`);
|
||||
assertEquals('\u0000a', `\0a`);
|
||||
for (var i = 0; i < 10; i++) {
|
||||
for (var i = 0; i < 8; i++) {
|
||||
var code = "`\\0" + i + "`";
|
||||
assertThrows(code, SyntaxError);
|
||||
code = "(function(){})" + code;
|
||||
assertThrows(code, SyntaxError);
|
||||
}
|
||||
|
||||
assertEquals('\\0', String.raw`\0`);
|
||||
@ -488,8 +490,18 @@ var obj = {
|
||||
(function testSyntaxErrorsNonEscapeCharacter() {
|
||||
assertThrows("`\\x`", SyntaxError);
|
||||
assertThrows("`\\u`", SyntaxError);
|
||||
for (var i = 1; i < 10; i++) {
|
||||
for (var i = 1; i < 8; i++) {
|
||||
var code = "`\\" + i + "`";
|
||||
assertThrows(code, SyntaxError);
|
||||
code = "(function(){})" + code;
|
||||
assertThrows(code, SyntaxError);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
(function testValidNumericEscapes() {
|
||||
assertEquals("8", `\8`);
|
||||
assertEquals("9", `\9`);
|
||||
assertEquals("\u00008", `\08`);
|
||||
assertEquals("\u00009", `\09`);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user