First part of ES5 strict mode.
- var eval | arguments - catch (eval | arguments) - 'with' is disabled - function can't be named eval or arguments - function parameter name cannot be eval or arguments - no duplicate parameter names allowed Add FLAG_strict_mode git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6369 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
80b7a0e164
commit
b4c88d5de4
@ -1675,7 +1675,8 @@ class FunctionLiteral: public Expression {
|
|||||||
int start_position,
|
int start_position,
|
||||||
int end_position,
|
int end_position,
|
||||||
bool is_expression,
|
bool is_expression,
|
||||||
bool contains_loops)
|
bool contains_loops,
|
||||||
|
bool strict_mode)
|
||||||
: name_(name),
|
: name_(name),
|
||||||
scope_(scope),
|
scope_(scope),
|
||||||
body_(body),
|
body_(body),
|
||||||
@ -1689,6 +1690,7 @@ class FunctionLiteral: public Expression {
|
|||||||
end_position_(end_position),
|
end_position_(end_position),
|
||||||
is_expression_(is_expression),
|
is_expression_(is_expression),
|
||||||
contains_loops_(contains_loops),
|
contains_loops_(contains_loops),
|
||||||
|
strict_mode_(strict_mode),
|
||||||
function_token_position_(RelocInfo::kNoPosition),
|
function_token_position_(RelocInfo::kNoPosition),
|
||||||
inferred_name_(Heap::empty_string()),
|
inferred_name_(Heap::empty_string()),
|
||||||
try_full_codegen_(false),
|
try_full_codegen_(false),
|
||||||
@ -1705,6 +1707,7 @@ class FunctionLiteral: public Expression {
|
|||||||
int end_position() const { return end_position_; }
|
int end_position() const { return end_position_; }
|
||||||
bool is_expression() const { return is_expression_; }
|
bool is_expression() const { return is_expression_; }
|
||||||
bool contains_loops() const { return contains_loops_; }
|
bool contains_loops() const { return contains_loops_; }
|
||||||
|
bool strict_mode() const { return strict_mode_; }
|
||||||
|
|
||||||
int materialized_literal_count() { return materialized_literal_count_; }
|
int materialized_literal_count() { return materialized_literal_count_; }
|
||||||
int expected_property_count() { return expected_property_count_; }
|
int expected_property_count() { return expected_property_count_; }
|
||||||
@ -1747,6 +1750,7 @@ class FunctionLiteral: public Expression {
|
|||||||
int end_position_;
|
int end_position_;
|
||||||
bool is_expression_;
|
bool is_expression_;
|
||||||
bool contains_loops_;
|
bool contains_loops_;
|
||||||
|
bool strict_mode_;
|
||||||
int function_token_position_;
|
int function_token_position_;
|
||||||
Handle<String> inferred_name_;
|
Handle<String> inferred_name_;
|
||||||
bool try_full_codegen_;
|
bool try_full_codegen_;
|
||||||
|
@ -301,6 +301,7 @@ DEFINE_bool(use_verbose_printer, true, "allows verbose printing")
|
|||||||
|
|
||||||
// parser.cc
|
// parser.cc
|
||||||
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
|
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
|
||||||
|
DEFINE_bool(strict_mode, true, "allow strict mode directives")
|
||||||
|
|
||||||
// rewriter.cc
|
// rewriter.cc
|
||||||
DEFINE_bool(optimize_ast, true, "optimize the ast")
|
DEFINE_bool(optimize_ast, true, "optimize the ast")
|
||||||
|
@ -203,7 +203,8 @@ namespace internal {
|
|||||||
V(zero_symbol, "0") \
|
V(zero_symbol, "0") \
|
||||||
V(global_eval_symbol, "GlobalEval") \
|
V(global_eval_symbol, "GlobalEval") \
|
||||||
V(identity_hash_symbol, "v8::IdentityHash") \
|
V(identity_hash_symbol, "v8::IdentityHash") \
|
||||||
V(closure_symbol, "(closure)")
|
V(closure_symbol, "(closure)") \
|
||||||
|
V(use_strict, "use strict")
|
||||||
|
|
||||||
|
|
||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
|
@ -202,7 +202,13 @@ function FormatMessage(message) {
|
|||||||
array_indexof_not_defined: "Array.getIndexOf: Argument undefined",
|
array_indexof_not_defined: "Array.getIndexOf: Argument undefined",
|
||||||
object_not_extensible: "Can't add property %0, object is not extensible",
|
object_not_extensible: "Can't add property %0, object is not extensible",
|
||||||
illegal_access: "Illegal access",
|
illegal_access: "Illegal access",
|
||||||
invalid_preparser_data: "Invalid preparser data for function %0"
|
invalid_preparser_data: "Invalid preparser data for function %0",
|
||||||
|
strict_mode_with: "Strict mode code may not include a with statement",
|
||||||
|
strict_catch_variable: "Catch variable may not be eval or arguments in strict mode",
|
||||||
|
strict_param_name: "Parameter name eval or arguments is not allowed in strict mode",
|
||||||
|
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",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var format = kMessages[message.type];
|
var format = kMessages[message.type];
|
||||||
|
127
src/parser.cc
127
src/parser.cc
@ -283,6 +283,11 @@ class TemporaryScope BASE_EMBEDDED {
|
|||||||
void AddLoop() { loop_count_++; }
|
void AddLoop() { loop_count_++; }
|
||||||
bool ContainsLoops() const { return loop_count_ > 0; }
|
bool ContainsLoops() const { return loop_count_ > 0; }
|
||||||
|
|
||||||
|
bool StrictMode() { return strict_mode_; }
|
||||||
|
void EnableStrictMode() {
|
||||||
|
strict_mode_ = FLAG_strict_mode;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Captures the number of literals that need materialization in the
|
// Captures the number of literals that need materialization in the
|
||||||
// function. Includes regexp literals, and boilerplate for object
|
// function. Includes regexp literals, and boilerplate for object
|
||||||
@ -300,6 +305,9 @@ class TemporaryScope BASE_EMBEDDED {
|
|||||||
// Captures the number of loops inside the scope.
|
// Captures the number of loops inside the scope.
|
||||||
int loop_count_;
|
int loop_count_;
|
||||||
|
|
||||||
|
// Parsing strict mode code.
|
||||||
|
bool strict_mode_;
|
||||||
|
|
||||||
// Bookkeeping
|
// Bookkeeping
|
||||||
TemporaryScope** variable_;
|
TemporaryScope** variable_;
|
||||||
TemporaryScope* parent_;
|
TemporaryScope* parent_;
|
||||||
@ -314,6 +322,8 @@ TemporaryScope::TemporaryScope(TemporaryScope** variable)
|
|||||||
loop_count_(0),
|
loop_count_(0),
|
||||||
variable_(variable),
|
variable_(variable),
|
||||||
parent_(*variable) {
|
parent_(*variable) {
|
||||||
|
// Inherit the strict mode from the parent scope.
|
||||||
|
strict_mode_ = (parent_ != NULL) && parent_->strict_mode_;
|
||||||
*variable = this;
|
*variable = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,7 +571,6 @@ class LexicalScope BASE_EMBEDDED {
|
|||||||
int prev_level_;
|
int prev_level_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// The CHECK_OK macro is a convenient macro to enforce error
|
// The CHECK_OK macro is a convenient macro to enforce error
|
||||||
// handling for functions that may fail (by returning !*ok).
|
// handling for functions that may fail (by returning !*ok).
|
||||||
@ -669,7 +678,8 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
|
|||||||
0,
|
0,
|
||||||
source->length(),
|
source->length(),
|
||||||
false,
|
false,
|
||||||
temp_scope.ContainsLoops());
|
temp_scope.ContainsLoops(),
|
||||||
|
temp_scope.StrictMode());
|
||||||
} else if (stack_overflow_) {
|
} else if (stack_overflow_) {
|
||||||
Top::StackOverflow();
|
Top::StackOverflow();
|
||||||
}
|
}
|
||||||
@ -1075,9 +1085,46 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
|||||||
ASSERT(processor != NULL);
|
ASSERT(processor != NULL);
|
||||||
InitializationBlockFinder block_finder;
|
InitializationBlockFinder block_finder;
|
||||||
ThisNamedPropertyAssigmentFinder this_property_assignment_finder;
|
ThisNamedPropertyAssigmentFinder this_property_assignment_finder;
|
||||||
|
bool directive_prologue = true; // Parsing directive prologue.
|
||||||
|
|
||||||
while (peek() != end_token) {
|
while (peek() != end_token) {
|
||||||
|
if (directive_prologue && peek() != Token::STRING) {
|
||||||
|
directive_prologue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scanner::Location token_loc = scanner().peek_location();
|
||||||
Statement* stat = ParseStatement(NULL, CHECK_OK);
|
Statement* stat = ParseStatement(NULL, CHECK_OK);
|
||||||
if (stat == NULL || stat->IsEmpty()) continue;
|
|
||||||
|
if (stat == NULL || stat->IsEmpty()) {
|
||||||
|
directive_prologue = false; // End of directive prologue.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directive_prologue) {
|
||||||
|
// A shot at a directive.
|
||||||
|
ExpressionStatement *e_stat;
|
||||||
|
Literal *literal;
|
||||||
|
// Still processing directive prologue?
|
||||||
|
if ((e_stat = stat->AsExpressionStatement()) != NULL &&
|
||||||
|
(literal = e_stat->expression()->AsLiteral()) != NULL &&
|
||||||
|
literal->handle()->IsString()) {
|
||||||
|
Handle<String> directive = Handle<String>::cast(literal->handle());
|
||||||
|
|
||||||
|
// Check "use strict" directive (ES5 14.1).
|
||||||
|
if (!temp_scope_->StrictMode() &&
|
||||||
|
directive->Equals(Heap::use_strict()) &&
|
||||||
|
token_loc.end_pos - token_loc.beg_pos ==
|
||||||
|
Heap::use_strict()->length() + 2) {
|
||||||
|
temp_scope_->EnableStrictMode();
|
||||||
|
// "use strict" is the only directive for now.
|
||||||
|
directive_prologue = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// End of the directive prologue.
|
||||||
|
directive_prologue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We find and mark the initialization blocks on top level code only.
|
// We find and mark the initialization blocks on top level code only.
|
||||||
// This is because the optimization prevents reuse of the map transitions,
|
// This is because the optimization prevents reuse of the map transitions,
|
||||||
// so it should be used only for code that will only be run once.
|
// so it should be used only for code that will only be run once.
|
||||||
@ -1431,6 +1478,10 @@ Block* Parser::ParseVariableStatement(bool* ok) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsEvalOrArguments(Handle<String> string) {
|
||||||
|
return string.is_identical_to(Factory::eval_symbol()) ||
|
||||||
|
string.is_identical_to(Factory::arguments_symbol());
|
||||||
|
}
|
||||||
|
|
||||||
// If the variable declaration declares exactly one non-const
|
// If the variable declaration declares exactly one non-const
|
||||||
// variable, then *var is set to that variable. In all other cases,
|
// variable, then *var is set to that variable. In all other cases,
|
||||||
@ -1479,6 +1530,13 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
|
|||||||
Handle<String> name = ParseIdentifier(CHECK_OK);
|
Handle<String> name = ParseIdentifier(CHECK_OK);
|
||||||
if (fni_ != NULL) fni_->PushVariableName(name);
|
if (fni_ != NULL) fni_->PushVariableName(name);
|
||||||
|
|
||||||
|
// Strict mode variables may not be named eval or arguments
|
||||||
|
if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) {
|
||||||
|
ReportMessage("strict_var_name", Vector<const char*>::empty());
|
||||||
|
*ok = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Declare variable.
|
// Declare variable.
|
||||||
// Note that we *always* must treat the initial value via a separate init
|
// Note that we *always* must treat the initial value via a separate init
|
||||||
// assignment for variables and constants because the value must be assigned
|
// assignment for variables and constants because the value must be assigned
|
||||||
@ -1839,6 +1897,13 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
|
|||||||
// 'with' '(' Expression ')' Statement
|
// 'with' '(' Expression ')' Statement
|
||||||
|
|
||||||
Expect(Token::WITH, CHECK_OK);
|
Expect(Token::WITH, CHECK_OK);
|
||||||
|
|
||||||
|
if (temp_scope_->StrictMode()) {
|
||||||
|
ReportMessage("strict_mode_with", Vector<const char*>::empty());
|
||||||
|
*ok = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Expect(Token::LPAREN, CHECK_OK);
|
Expect(Token::LPAREN, CHECK_OK);
|
||||||
Expression* expr = ParseExpression(true, CHECK_OK);
|
Expression* expr = ParseExpression(true, CHECK_OK);
|
||||||
Expect(Token::RPAREN, CHECK_OK);
|
Expect(Token::RPAREN, CHECK_OK);
|
||||||
@ -1971,6 +2036,13 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
|||||||
|
|
||||||
Expect(Token::LPAREN, CHECK_OK);
|
Expect(Token::LPAREN, CHECK_OK);
|
||||||
Handle<String> name = ParseIdentifier(CHECK_OK);
|
Handle<String> name = ParseIdentifier(CHECK_OK);
|
||||||
|
|
||||||
|
if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) {
|
||||||
|
ReportMessage("strict_catch_variable", Vector<const char*>::empty());
|
||||||
|
*ok = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Expect(Token::RPAREN, CHECK_OK);
|
Expect(Token::RPAREN, CHECK_OK);
|
||||||
|
|
||||||
if (peek() == Token::LBRACE) {
|
if (peek() == Token::LBRACE) {
|
||||||
@ -3224,11 +3296,27 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
|
|||||||
// '(' (Identifier)*[','] ')'
|
// '(' (Identifier)*[','] ')'
|
||||||
Expect(Token::LPAREN, CHECK_OK);
|
Expect(Token::LPAREN, CHECK_OK);
|
||||||
int start_pos = scanner().location().beg_pos;
|
int start_pos = scanner().location().beg_pos;
|
||||||
|
Scanner::Location eval_loc(RelocInfo::kNoPosition, RelocInfo::kNoPosition);
|
||||||
|
Scanner::Location dupe_loc(RelocInfo::kNoPosition, RelocInfo::kNoPosition);
|
||||||
|
|
||||||
bool done = (peek() == Token::RPAREN);
|
bool done = (peek() == Token::RPAREN);
|
||||||
while (!done) {
|
while (!done) {
|
||||||
Handle<String> param_name = ParseIdentifier(CHECK_OK);
|
Handle<String> param_name = ParseIdentifier(CHECK_OK);
|
||||||
top_scope_->AddParameter(top_scope_->DeclareLocal(param_name,
|
Variable* parameter = top_scope_->DeclareLocal(param_name, Variable::VAR);
|
||||||
Variable::VAR));
|
|
||||||
|
// Store locations for possible future error reports.
|
||||||
|
if (eval_loc.beg_pos == RelocInfo::kNoPosition &&
|
||||||
|
IsEvalOrArguments(param_name)) {
|
||||||
|
// Store location for later
|
||||||
|
eval_loc = scanner().location();
|
||||||
|
}
|
||||||
|
if (dupe_loc.beg_pos == RelocInfo::kNoPosition &&
|
||||||
|
top_scope_->IsParameterDeclared(param_name)) {
|
||||||
|
// Store location for later
|
||||||
|
dupe_loc = scanner().location();
|
||||||
|
}
|
||||||
|
|
||||||
|
top_scope_->AddParameter(parameter);
|
||||||
num_parameters++;
|
num_parameters++;
|
||||||
done = (peek() == Token::RPAREN);
|
done = (peek() == Token::RPAREN);
|
||||||
if (!done) Expect(Token::COMMA, CHECK_OK);
|
if (!done) Expect(Token::COMMA, CHECK_OK);
|
||||||
@ -3300,6 +3388,32 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
|
|||||||
end_pos = scanner().location().end_pos;
|
end_pos = scanner().location().end_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate strict mode.
|
||||||
|
if (temp_scope_->StrictMode()) {
|
||||||
|
if (IsEvalOrArguments(name)) {
|
||||||
|
int position = function_token_position != RelocInfo::kNoPosition
|
||||||
|
? function_token_position
|
||||||
|
: (start_pos > 0 ? start_pos - 1 : start_pos);
|
||||||
|
ReportMessageAt(Scanner::Location(position, start_pos),
|
||||||
|
"strict_function_name", Vector<const char*>::empty());
|
||||||
|
*ok = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (eval_loc.beg_pos != RelocInfo::kNoPosition) {
|
||||||
|
ReportMessageAt(eval_loc, "strict_param_name",
|
||||||
|
Vector<const char*>::empty());
|
||||||
|
*ok = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (dupe_loc.beg_pos != RelocInfo::kNoPosition) {
|
||||||
|
ReportMessageAt(dupe_loc, "strict_param_dupe",
|
||||||
|
Vector<const char*>::empty());
|
||||||
|
*ok = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// TODO(mmaly): Check for octal escape sequence here.
|
||||||
|
}
|
||||||
|
|
||||||
FunctionLiteral* function_literal =
|
FunctionLiteral* function_literal =
|
||||||
new FunctionLiteral(name,
|
new FunctionLiteral(name,
|
||||||
top_scope_,
|
top_scope_,
|
||||||
@ -3312,7 +3426,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
|
|||||||
start_pos,
|
start_pos,
|
||||||
end_pos,
|
end_pos,
|
||||||
function_name->length() > 0,
|
function_name->length() > 0,
|
||||||
temp_scope.ContainsLoops());
|
temp_scope.ContainsLoops(),
|
||||||
|
temp_scope.StrictMode());
|
||||||
function_literal->set_function_token_position(function_token_position);
|
function_literal->set_function_token_position(function_token_position);
|
||||||
|
|
||||||
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
|
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
|
||||||
|
@ -445,6 +445,18 @@ int Scope::ContextChainLength(Scope* scope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Scope::IsParameterDeclared(Handle<String> name) {
|
||||||
|
ASSERT(name->IsSymbol());
|
||||||
|
for (int i = 0, length = num_parameters(); i < length; i ++) {
|
||||||
|
ASSERT(parameter(i)->name()->IsSymbol());
|
||||||
|
if (name.is_identical_to(parameter(i)->name())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static const char* Header(Scope::Type type) {
|
static const char* Header(Scope::Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -288,6 +288,10 @@ class Scope: public ZoneObject {
|
|||||||
// The number of contexts between this and scope; zero if this == scope.
|
// The number of contexts between this and scope; zero if this == scope.
|
||||||
int ContextChainLength(Scope* scope);
|
int ContextChainLength(Scope* scope);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Strict mode support.
|
||||||
|
bool IsParameterDeclared(Handle<String> name);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Debugging.
|
// Debugging.
|
||||||
|
|
||||||
|
117
test/mjsunit/strict-mode.js
Normal file
117
test/mjsunit/strict-mode.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
function CheckStrictMode(code, exception) {
|
||||||
|
assertDoesNotThrow(code);
|
||||||
|
assertThrows("'use strict';\n" + code, exception);
|
||||||
|
assertThrows('"use strict";\n' + code, exception);
|
||||||
|
assertDoesNotThrow("\
|
||||||
|
function outer() {\
|
||||||
|
function inner() {\n"
|
||||||
|
+ code +
|
||||||
|
"\n}\
|
||||||
|
}");
|
||||||
|
assertThrows("\
|
||||||
|
function outer() {\
|
||||||
|
'use strict';\
|
||||||
|
function inner() {\n"
|
||||||
|
+ code +
|
||||||
|
"\n}\
|
||||||
|
}", exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incorrect 'use strict' directive.
|
||||||
|
function UseStrictEscape() {
|
||||||
|
"use\\x20strict";
|
||||||
|
with ({}) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'use strict' in non-directive position.
|
||||||
|
function UseStrictNonDirective() {
|
||||||
|
void(0);
|
||||||
|
"use strict";
|
||||||
|
with ({}) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple directives, including "use strict".
|
||||||
|
assertThrows('\
|
||||||
|
"directive 1";\
|
||||||
|
"another directive";\
|
||||||
|
"use strict";\
|
||||||
|
"directive after strict";\
|
||||||
|
"and one more";\
|
||||||
|
with({}) {}', SyntaxError);
|
||||||
|
|
||||||
|
// 'with' disallowed in strict mode.
|
||||||
|
CheckStrictMode("with({}) {}", SyntaxError);
|
||||||
|
|
||||||
|
// Function named 'eval'.
|
||||||
|
CheckStrictMode("function eval() {}", SyntaxError)
|
||||||
|
|
||||||
|
// Function named 'arguments'.
|
||||||
|
CheckStrictMode("function arguments() {}", SyntaxError)
|
||||||
|
|
||||||
|
// Function parameter named 'eval'.
|
||||||
|
CheckStrictMode("function foo(a, b, eval, c, d) {}", SyntaxError)
|
||||||
|
|
||||||
|
// Function parameter named 'arguments'.
|
||||||
|
CheckStrictMode("function foo(a, b, arguments, c, d) {}", SyntaxError)
|
||||||
|
|
||||||
|
// Property accessor parameter named 'eval'.
|
||||||
|
CheckStrictMode("var o = { set foo(eval) {} }", SyntaxError)
|
||||||
|
|
||||||
|
// Property accessor parameter named 'arguments'.
|
||||||
|
CheckStrictMode("var o = { set foo(arguments) {} }", SyntaxError)
|
||||||
|
|
||||||
|
// Duplicate function parameter name.
|
||||||
|
CheckStrictMode("function foo(a, b, c, d, b) {}", SyntaxError)
|
||||||
|
|
||||||
|
// catch(eval)
|
||||||
|
CheckStrictMode("try{}catch(eval){};", SyntaxError)
|
||||||
|
|
||||||
|
// catch(arguments)
|
||||||
|
CheckStrictMode("try{}catch(arguments){};", SyntaxError)
|
||||||
|
|
||||||
|
// var eval
|
||||||
|
CheckStrictMode("var eval;", SyntaxError)
|
||||||
|
|
||||||
|
// var arguments
|
||||||
|
CheckStrictMode("var arguments;", SyntaxError)
|
||||||
|
|
||||||
|
// Strict mode applies to the function in which the directive is used..
|
||||||
|
assertThrows('\
|
||||||
|
function foo(eval) {\
|
||||||
|
"use strict";\
|
||||||
|
}', SyntaxError);
|
||||||
|
|
||||||
|
// Strict mode doesn't affect the outer stop of strict code.
|
||||||
|
function NotStrict(eval) {
|
||||||
|
function Strict() {
|
||||||
|
"use strict";
|
||||||
|
}
|
||||||
|
with ({}) {};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user