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

Reply via email to