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)"],
|
too_many_variables: ["Too many variables declared (only 4194303 allowed)"],
|
||||||
strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
|
strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
|
||||||
strict_octal_literal: ["Octal literals are not allowed in strict mode."],
|
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"],
|
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_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"],
|
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);
|
&ok);
|
||||||
|
|
||||||
if (ok && strict_mode() == STRICT) {
|
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) {
|
if (ok && allow_harmony_scoping() && strict_mode() == STRICT) {
|
||||||
@ -3803,9 +3803,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
CHECK_OK);
|
CHECK_OK);
|
||||||
}
|
}
|
||||||
if (strict_mode() == STRICT) {
|
if (strict_mode() == STRICT) {
|
||||||
CheckOctalLiteral(scope->start_position(),
|
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
|
||||||
scope->end_position(),
|
CHECK_OK);
|
||||||
CHECK_OK);
|
|
||||||
}
|
}
|
||||||
if (allow_harmony_scoping() && strict_mode() == STRICT) {
|
if (allow_harmony_scoping() && strict_mode() == STRICT) {
|
||||||
CheckConflictingVarDeclarations(scope, CHECK_OK);
|
CheckConflictingVarDeclarations(scope, CHECK_OK);
|
||||||
|
@ -125,7 +125,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
|||||||
DCHECK_EQ(Token::RBRACE, scanner()->peek());
|
DCHECK_EQ(Token::RBRACE, scanner()->peek());
|
||||||
if (scope_->strict_mode() == STRICT) {
|
if (scope_->strict_mode() == STRICT) {
|
||||||
int end_pos = scanner()->location().end_pos;
|
int end_pos = scanner()->location().end_pos;
|
||||||
CheckOctalLiteral(start_position, end_pos, &ok);
|
CheckStrictOctalLiteral(start_position, end_pos, &ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return kPreParseSuccess;
|
return kPreParseSuccess;
|
||||||
@ -937,7 +937,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int end_position = scanner()->location().end_pos;
|
int end_position = scanner()->location().end_pos;
|
||||||
CheckOctalLiteral(start_position, end_position, CHECK_OK);
|
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Expression::Default();
|
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.
|
// Checks whether an octal literal was last seen between beg_pos and end_pos.
|
||||||
// If so, reports an error. Only called for strict mode.
|
// If so, reports an error. Only called for strict mode and template strings.
|
||||||
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
void CheckOctalLiteral(int beg_pos, int end_pos, const char* error,
|
||||||
|
bool* ok) {
|
||||||
Scanner::Location octal = scanner()->octal_position();
|
Scanner::Location octal = scanner()->octal_position();
|
||||||
if (octal.IsValid() && beg_pos <= octal.beg_pos &&
|
if (octal.IsValid() && beg_pos <= octal.beg_pos &&
|
||||||
octal.end_pos <= end_pos) {
|
octal.end_pos <= end_pos) {
|
||||||
ReportMessageAt(octal, "strict_octal_literal");
|
ReportMessageAt(octal, error);
|
||||||
scanner()->clear_octal_position();
|
scanner()->clear_octal_position();
|
||||||
*ok = false;
|
*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
|
// Validates strict mode for function parameter lists. This has to be
|
||||||
// done after parsing the function, since the function can declare
|
// done after parsing the function, since the function can declare
|
||||||
// itself strict.
|
// itself strict.
|
||||||
@ -1489,7 +1498,8 @@ class PreParser : public ParserBase<PreParserTraits> {
|
|||||||
if (!ok) {
|
if (!ok) {
|
||||||
ReportUnexpectedToken(scanner()->current_token());
|
ReportUnexpectedToken(scanner()->current_token());
|
||||||
} else if (scope_->strict_mode() == STRICT) {
|
} 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) {
|
if (materialized_literals) {
|
||||||
*materialized_literals = function_state_->materialized_literal_count();
|
*materialized_literals = function_state_->materialized_literal_count();
|
||||||
@ -2802,7 +2812,8 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
|
|||||||
|
|
||||||
// Validate strict mode.
|
// Validate strict mode.
|
||||||
if (strict_mode() == STRICT) {
|
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)
|
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) {
|
if (peek() == Token::TEMPLATE_TAIL) {
|
||||||
Consume(Token::TEMPLATE_TAIL);
|
Consume(Token::TEMPLATE_TAIL);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
|
CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
|
||||||
typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
|
typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
|
||||||
Traits::AddTemplateSpan(&ts, true);
|
Traits::AddTemplateSpan(&ts, true);
|
||||||
return Traits::CloseTemplateLiteral(&ts, start, tag);
|
return Traits::CloseTemplateLiteral(&ts, start, tag);
|
||||||
@ -2897,6 +2909,7 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) {
|
|||||||
} while (next == Token::TEMPLATE_SPAN);
|
} while (next == Token::TEMPLATE_SPAN);
|
||||||
|
|
||||||
DCHECK_EQ(next, Token::TEMPLATE_TAIL);
|
DCHECK_EQ(next, Token::TEMPLATE_TAIL);
|
||||||
|
CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
|
||||||
// Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
|
// Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
|
||||||
return Traits::CloseTemplateLiteral(&ts, start, tag);
|
return Traits::CloseTemplateLiteral(&ts, start, tag);
|
||||||
}
|
}
|
||||||
|
@ -733,21 +733,7 @@ bool Scanner::ScanEscape() {
|
|||||||
if (c < 0) return false;
|
if (c < 0) return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '0':
|
case '0': // Fall through.
|
||||||
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 '1': // fall through
|
case '1': // fall through
|
||||||
case '2': // fall through
|
case '2': // fall through
|
||||||
case '3': // fall through
|
case '3': // fall through
|
||||||
@ -755,14 +741,8 @@ bool Scanner::ScanEscape() {
|
|||||||
case '5': // fall through
|
case '5': // fall through
|
||||||
case '6': // fall through
|
case '6': // fall through
|
||||||
case '7':
|
case '7':
|
||||||
if (!in_template_literal) {
|
c = ScanOctalEscape<capture_raw>(c, 2);
|
||||||
c = ScanOctalEscape<capture_raw>(c, 2);
|
break;
|
||||||
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
|
// According to ECMA-262, section 7.8.4, characters not covered by the
|
||||||
|
@ -476,9 +476,11 @@ var obj = {
|
|||||||
(function testLegacyOctal() {
|
(function testLegacyOctal() {
|
||||||
assertEquals('\u0000', `\0`);
|
assertEquals('\u0000', `\0`);
|
||||||
assertEquals('\u0000a', `\0a`);
|
assertEquals('\u0000a', `\0a`);
|
||||||
for (var i = 0; i < 10; i++) {
|
for (var i = 0; i < 8; i++) {
|
||||||
var code = "`\\0" + i + "`";
|
var code = "`\\0" + i + "`";
|
||||||
assertThrows(code, SyntaxError);
|
assertThrows(code, SyntaxError);
|
||||||
|
code = "(function(){})" + code;
|
||||||
|
assertThrows(code, SyntaxError);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals('\\0', String.raw`\0`);
|
assertEquals('\\0', String.raw`\0`);
|
||||||
@ -488,8 +490,18 @@ var obj = {
|
|||||||
(function testSyntaxErrorsNonEscapeCharacter() {
|
(function testSyntaxErrorsNonEscapeCharacter() {
|
||||||
assertThrows("`\\x`", SyntaxError);
|
assertThrows("`\\x`", SyntaxError);
|
||||||
assertThrows("`\\u`", SyntaxError);
|
assertThrows("`\\u`", SyntaxError);
|
||||||
for (var i = 1; i < 10; i++) {
|
for (var i = 1; i < 8; i++) {
|
||||||
var code = "`\\" + i + "`";
|
var code = "`\\" + i + "`";
|
||||||
assertThrows(code, SyntaxError);
|
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