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

View File

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

View File

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

View File

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

View File

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

View File

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