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:
caitpotter88 2014-12-18 14:01:25 -08:00 committed by Commit bot
parent b494f5cdb8
commit 233f2d2bf1
6 changed files with 41 additions and 36 deletions

View File

@ -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"],

View File

@ -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) {

View File

@ -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();

View File

@ -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);
}

View File

@ -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

View File

@ -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`);
})();