Follow the spec in disallowing function declarations without a name. We
authorager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Oct 2009 12:47:15 +0000 (12:47 +0000)
committerager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Oct 2009 12:47:15 +0000 (12:47 +0000)
used to allow these for compatibility, but both Safari and Firefox now
disallow them.
Review URL: http://codereview.chromium.org/242124

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3009 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/debug-delay.js
src/parser.cc
src/runtime.cc
test/cctest/test-debug.cc
test/mjsunit/class-of-builtins.js
test/mjsunit/debug-compile-event.js
test/mjsunit/invalid-source-element.js [new file with mode: 0644]
test/mjsunit/mirror-script.js
test/mjsunit/regress/regress-220.js
test/mjsunit/switch.js

index 189279b..cb789be 100644 (file)
@@ -348,7 +348,7 @@ ScriptBreakPoint.prototype.set = function (script) {
     if (!script.sourceColumnStart_) {
       script.sourceColumnStart_ = new Array(script.lineCount());
     }
-    
+
     // Fill cache if needed and get column where the actual source starts.
     if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
       script.sourceColumnStart_[line] =
@@ -359,11 +359,11 @@ ScriptBreakPoint.prototype.set = function (script) {
 
   // Convert the line and column into an absolute position within the script.
   var pos = Debug.findScriptSourcePosition(script, this.line(), column);
-  
+
   // If the position is not found in the script (the script might be shorter
   // than it used to be) just ignore it.
   if (pos === null) return;
-  
+
   // Create a break point object and set the break point.
   break_point = MakeBreakPoint(pos, this.line(), this.column(), this);
   break_point.setIgnoreCount(this.ignoreCount());
@@ -490,7 +490,7 @@ Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
 // Returns the character position in a script based on a line number and an
 // optional position within that line.
 Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
-  var location = script.locationFromLine(opt_line, opt_column);  
+  var location = script.locationFromLine(opt_line, opt_column);
   return location ? location.position : null;
 }
 
@@ -942,7 +942,7 @@ ExceptionEvent.prototype.toJSONProtocol = function() {
   o.body = { uncaught: this.uncaught_,
              exception: MakeMirror(this.exception_)
            };
-           
+
   // Exceptions might happen whithout any JavaScript frames.
   if (this.exec_state_.frameCount() > 0) {
     o.body.sourceLine = this.sourceLine();
@@ -1095,7 +1095,7 @@ DebugCommandProcessor.prototype.processDebugRequest = function (request) {
 function ProtocolMessage(request) {
   // Update sequence number.
   this.seq = next_response_seq++;
-  
+
   if (request) {
     // If message is based on a request this is a response. Fill the initial
     // response from the request.
@@ -1485,7 +1485,7 @@ DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(request,
     response.failed('Missing argument "groupId"');
     return;
   }
-  
+
   var cleared_break_points = [];
   var new_script_break_points = [];
   for (var i = 0; i < script_break_points.length; i++) {
@@ -1601,7 +1601,7 @@ DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
     if (index < 0 || this.exec_state_.frameCount() <= index) {
       return response.failed('Invalid frame number');
     }
-    
+
     this.exec_state_.setSelectedFrame(request.arguments.number);
   }
   response.body = this.exec_state_.frame();
@@ -1631,7 +1631,7 @@ DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
 
   // Get the frame for which the scopes are requested.
   var frame = this.frameForScopeRequest_(request);
-  
+
   // Fill all scopes for this frame.
   var total_scopes = frame.scopeCount();
   var scopes = [];
@@ -1748,7 +1748,7 @@ DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
     includeSource = %ToBoolean(request.arguments.includeSource);
     response.setOption('includeSource', includeSource);
   }
-  
+
   // Lookup handles.
   var mirrors = {};
   for (var i = 0; i < handles.length; i++) {
index 4dbd472..3b24687 100644 (file)
@@ -1924,31 +1924,20 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
 
 
 Statement* Parser::ParseFunctionDeclaration(bool* ok) {
-  // Parse a function literal. We may or may not have a function name.
-  // If we have a name we use it as the variable name for the function
-  // (a function declaration) and not as the function name of a function
-  // expression.
-
+  // FunctionDeclaration ::
+  //   'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
   Expect(Token::FUNCTION, CHECK_OK);
   int function_token_position = scanner().location().beg_pos;
-
-  Handle<String> name;
-  if (peek() == Token::IDENTIFIER) name = ParseIdentifier(CHECK_OK);
-  FunctionLiteral* fun = ParseFunctionLiteral(name, function_token_position,
-                                              DECLARATION, CHECK_OK);
-
-  if (name.is_null()) {
-    // We don't have a name - it is always an anonymous function
-    // expression.
-    return NEW(ExpressionStatement(fun));
-  } else {
-    // We have a name so even if we're not at the top-level of the
-    // global or a function scope, we treat is as such and introduce
-    // the function with it's initial value upon entering the
-    // corresponding scope.
-    Declare(name, Variable::VAR, fun, true, CHECK_OK);
-    return factory()->EmptyStatement();
-  }
+  Handle<String> name = ParseIdentifier(CHECK_OK);
+  FunctionLiteral* fun = ParseFunctionLiteral(name,
+                                              function_token_position,
+                                              DECLARATION,
+                                              CHECK_OK);
+  // Even if we're not at the top-level of the global or a function
+  // scope, we treat is as such and introduce the function with it's
+  // initial value upon entering the corresponding scope.
+  Declare(name, Variable::VAR, fun, true, CHECK_OK);
+  return factory()->EmptyStatement();
 }
 
 
index 06b61e7..8a803b3 100644 (file)
@@ -7148,7 +7148,7 @@ static Object* Runtime_DebugEvaluate(Arguments args) {
   // the function being debugged.
   // function(arguments,__source__) {return eval(__source__);}
   static const char* source_str =
-      "function(arguments,__source__){return eval(__source__);}";
+      "(function(arguments,__source__){return eval(__source__);})";
   static const int source_str_length = strlen(source_str);
   Handle<String> function_source =
       Factory::NewStringFromAscii(Vector<const char>(source_str,
index e724375..1da363c 100644 (file)
@@ -4096,11 +4096,11 @@ v8::Handle<v8::Function> debugger_call_with_data;
 // passed it throws an exception.
 static const char* debugger_call_with_closure_source =
     "var x = 3;"
-    "function (exec_state) {"
+    "(function (exec_state) {"
     "  if (exec_state.y) return x - 1;"
     "  exec_state.y = x;"
     "  return exec_state.y"
-    "}";
+    "})";
 v8::Handle<v8::Function> debugger_call_with_closure;
 
 // Function to retrieve the number of JavaScript frames by calling a JavaScript
index 40c958c..59fefff 100644 (file)
@@ -35,7 +35,7 @@ var funs = {
   Boolean:  [ Boolean ],
   Number:   [ Number ],
   Date:     [ Date ],
-  RegExp:   [ RegExp ],  
+  RegExp:   [ RegExp ],
   Error:    [ Error, TypeError, RangeError, SyntaxError, ReferenceError, EvalError, URIError ]
 }
 for (f in funs) {
index c346f76..4804ac7 100644 (file)
@@ -102,10 +102,10 @@ Debug.setListener(listener);
 
 // Compile different sources.
 compileSource('a=1');
-compileSource('function(){}');
+compileSource('(function(){})');
 compileSource('eval("a=2")');
 source_count++;  // Using eval causes additional compilation event.
-compileSource('eval("eval(\'function(){return a;}\')")');
+compileSource('eval("eval(\'(function(){return a;})\')")');
 source_count += 2;  // Using eval causes additional compilation event.
 compileSource('JSON.parse("{a:1,b:2}")');
 source_count++;  // Using JSON.parse causes additional compilation event.
diff --git a/test/mjsunit/invalid-source-element.js b/test/mjsunit/invalid-source-element.js
new file mode 100644 (file)
index 0000000..fb012e2
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// A function expression with no parenthesis around it is not a valid
+// expression statement.
+assertThrows("eval('function() {}')");
index 9b67b9b..3208f16 100644 (file)
@@ -85,16 +85,16 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type,
 // Test the script mirror for different functions.
 testScriptMirror(function(){}, 'mirror-script.js', 100, 2, 0);
 testScriptMirror(Math.sin, 'native math.js', -1, 0, 0);
-testScriptMirror(eval('function(){}'), null, 1, 2, 1, 'function(){}', 87);
-testScriptMirror(eval('function(){\n  }'), null, 2, 2, 1, 'function(){\n  }', 88);
+testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87);
+testScriptMirror(eval('(function(){\n  })'), null, 2, 2, 1, '(function(){\n  })', 88);
 testScriptMirror(%CompileString("({a:1,b:2})", true), null, 1, 2, 2, '({a:1,b:2})');
 testScriptMirror(%CompileString("({a:1,\n  b:2})", true), null, 2, 2, 2, '({a:1,\n  b:2})');
 
 // Test taking slices of source.
-var mirror = debug.MakeMirror(eval('function(){\n  1;\n}')).script();
-assertEquals('function(){\n', mirror.sourceSlice(0, 1).sourceText());
+var mirror = debug.MakeMirror(eval('(function(){\n  1;\n})')).script();
+assertEquals('(function(){\n', mirror.sourceSlice(0, 1).sourceText());
 assertEquals('  1;\n', mirror.sourceSlice(1, 2).sourceText());
-assertEquals('}', mirror.sourceSlice(2, 3).sourceText());
-assertEquals('function(){\n  1;\n', mirror.sourceSlice(0, 2).sourceText());
-assertEquals('  1;\n}', mirror.sourceSlice(1, 3).sourceText());
-assertEquals('function(){\n  1;\n}', mirror.sourceSlice(0, 3).sourceText());
+assertEquals('})', mirror.sourceSlice(2, 3).sourceText());
+assertEquals('(function(){\n  1;\n', mirror.sourceSlice(0, 2).sourceText());
+assertEquals('  1;\n})', mirror.sourceSlice(1, 3).sourceText());
+assertEquals('(function(){\n  1;\n})', mirror.sourceSlice(0, 3).sourceText());
index 416aa41..32c6471 100644 (file)
@@ -28,4 +28,4 @@
 function foo(f) { eval(f); }
 
 // Ensure that compiling a declaration of a function does not crash.
-foo("function (x) { with ({x: []}) function x(){} }");
+foo("(function (x) { with ({x: []}) function x(){} })");
index 4044490..180f994 100644 (file)
@@ -269,7 +269,7 @@ assertEquals("A", f7((170/16)-(170%16/16)), "0-1-switch.heapnum");
 
 
 function makeVeryLong(length) {
-  var res = "function() {\n" +
+  var res = "(function () {\n" +
             "  var res = 0;\n" +
             "  for (var i = 0; i <= " + length + "; i++) {\n" +
             "    switch(i) {\n";
@@ -280,7 +280,7 @@ function makeVeryLong(length) {
          "    }\n" +
          "  }\n" +
          "  return res;\n" +
-         "}";
+         "})";
   return eval(res);
 }
 var verylong_size = 1000;