Reviewers: Lasse Reichstein, Mads Ager,
Description:
Strict mode octal literals.
BUG=
TEST=test/mjsunit/strict-mode.js
Please review this at http://codereview.chromium.org/6248013/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge
Affected files:
M src/messages.js
M src/parser.h
M src/parser.cc
M src/scanner-base.h
M src/scanner-base.cc
M test/mjsunit/strict-mode.js
Index: src/messages.js
diff --git a/src/messages.js b/src/messages.js
index
e62f06fcf884857e18fca7c768833bf3ad82269e..7ca3d0c8b3c43d43b6987d084b381e19b35f892f
100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -209,6 +209,7 @@ function FormatMessage(message) {
strict_param_dupe: "Strict mode function may not have
duplicate parameter names",
strict_var_name: "Variable name may not be eval or
arguments in strict mode",
strict_function_name: "Function name may not be eval or
arguments in strict mode",
+ strict_octal_literal: "Octal literals are not allowed in
strict mode.",
};
}
var format = kMessages[message.type];
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index
2637281f080ed9f7f32fba93701c4da068a4f34e..fae83209a85267eb6afef921359295c7df1174db
100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -664,7 +664,11 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String>
source,
TemporaryScope temp_scope(&this->temp_scope_);
ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
bool ok = true;
+ int beg_loc = scanner().location().beg_pos;
ParseSourceElements(body, Token::EOS, &ok);
+ if (ok && temp_scope_->StrictMode()) {
+ CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
+ }
if (ok) {
result = new FunctionLiteral(
no_name,
@@ -3384,7 +3388,7 @@ FunctionLiteral*
Parser::ParseFunctionLiteral(Handle<String> var_name,
*ok = false;
return NULL;
}
- // TODO(mmaly): Check for octal escape sequence here.
+ CheckOctalLiteral(start_pos, end_pos, CHECK_OK);
}
FunctionLiteral* function_literal =
@@ -3530,6 +3534,20 @@ Handle<String> Parser::ParseIdentifierName(bool* ok)
{
return GetSymbol(ok);
}
+// Checks whether octal literal last seen is between beg_pos and end_pos.
+// If so, reports an error.
+void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+ Scanner::Location octal = scanner().octal_location();
+ if (octal.beg_pos >= beg_pos &&
+ octal.end_pos <= end_pos &&
+ octal.beg_pos < octal.end_pos) {
+ ReportMessageAt(octal, "strict_octal_literal",
+ Vector<const char*>::empty());
+ scanner().clear_octal_location();
+ *ok = false;
+ }
+}
+
// This function reads an identifier and determines whether or not it
// is 'get' or 'set'. The reason for not using ParseIdentifier and
Index: src/parser.h
diff --git a/src/parser.h b/src/parser.h
index
0613a8de99c4aad758ebc825201515aa0f56ca43..916f9ed102ad25bfc3310624a8c22f939371021b
100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -613,6 +613,9 @@ class Parser {
bool* is_set,
bool* ok);
+ // Strict mode octal literal validation.
+ void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
+
// Parser support
VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
FunctionLiteral* fun,
Index: src/scanner-base.cc
diff --git a/src/scanner-base.cc b/src/scanner-base.cc
index
997fb312fc8e589ce64fa4a3601565dbe4a59ad5..1c8090ceae9213d9ae57b947ca899940305e9d17
100644
--- a/src/scanner-base.cc
+++ b/src/scanner-base.cc
@@ -98,6 +98,7 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) {
// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
// ECMA-262. Other JS VMs support them.
uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
+ octal_loc_.beg_pos = source_pos() - 1; // Already advanced
uc32 x = c - '0';
for (int i = 0; i < length; i++) {
int d = c0_ - '0';
@@ -107,6 +108,7 @@ uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
x = nx;
Advance();
}
+ octal_loc_.end_pos = source_pos();
return x;
}
@@ -597,11 +599,17 @@ Token::Value JavaScriptScanner::ScanNumber(bool
seen_period) {
// (possible) octal number
kind = OCTAL;
while (true) {
+ // TODO(mmaly): Do we want to keep the auto-upgrade to decimal?
if (c0_ == '8' || c0_ == '9') {
kind = DECIMAL;
break;
}
- if (c0_ < '0' || '7' < c0_) break;
+ if (c0_ < '0' || '7' < c0_) {
+ // Octal literal finished.
+ octal_loc_.beg_pos = next_.location.beg_pos;
+ octal_loc_.end_pos = source_pos();
+ break;
+ }
AddLiteralCharAdvance();
}
}
Index: src/scanner-base.h
diff --git a/src/scanner-base.h b/src/scanner-base.h
index
1024ad18582e3c078793d2295fe3cb8a92d23b18..0cbca9975b2e1e30cc7ccff9baeb3f81b870783c
100644
--- a/src/scanner-base.h
+++ b/src/scanner-base.h
@@ -280,6 +280,10 @@ class Scanner {
Location location() const { return current_.location; }
Location peek_location() const { return next_.location; }
+ // Returns the location of the last seen octal literal
+ Location octal_location() const { return octal_loc_; }
+ void clear_octal_location() { octal_loc_ = Location(); }
+
// Returns the literal string, if any, for the current token (the
// token returned by Next()). The string is 0-terminated and in
// UTF-8 format; they may contain 0-characters. Literal strings are
@@ -410,6 +414,8 @@ class Scanner {
// Input stream. Must be initialized to an UC16CharacterStream.
UC16CharacterStream* source_;
+ // Location of the octal literal last seen
+ Location octal_loc_;
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
uc32 c0_;
Index: test/mjsunit/strict-mode.js
diff --git a/test/mjsunit/strict-mode.js b/test/mjsunit/strict-mode.js
index
924b34f936c274684e0e3cc2921b2563fb76aa05..83a22cc1f661cb1abb0426f991b46f40deb8331d
100644
--- a/test/mjsunit/strict-mode.js
+++ b/test/mjsunit/strict-mode.js
@@ -115,3 +115,17 @@ function NotStrict(eval) {
}
with ({}) {};
}
+
+// Octal literal
+CheckStrictMode("var x = 012");
+CheckStrictMode("012");
+CheckStrictMode("'Hello octal\\032'");
+CheckStrictMode("function octal() { return 012; }");
+CheckStrictMode("function octal() { return '\\032'; }");
+
+// Octal before "use strict"
+assertThrows('\
+ function strict() {\
+ "octal\\032directive";\
+ "use strict";\
+ }', SyntaxError);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev