summaryrefslogtreecommitdiff
path: root/deps/v8/src/parser.cc
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2015-03-27 12:04:12 +0100
committerChris Dickinson <christopher.s.dickinson@gmail.com>2015-04-28 14:38:16 -0700
commit36cd5fb9d27b830320e57213f5b8829ffbb93324 (patch)
treebbab4215d26f8597019135206426fccf27a3089e /deps/v8/src/parser.cc
parentb57cc51d8d3f4ad279591ae8fa6584ee22773b97 (diff)
downloadnode-new-36cd5fb9d27b830320e57213f5b8829ffbb93324.tar.gz
deps: upgrade v8 to 4.2.77.13
This commit applies some secondary changes in order to make `make test` pass cleanly: * disable broken postmortem debugging in common.gypi * drop obsolete strict mode test in parallel/test-repl * drop obsolete test parallel/test-v8-features PR-URL: https://github.com/iojs/io.js/pull/1232 Reviewed-By: Fedor Indutny <fedor@indutny.com>
Diffstat (limited to 'deps/v8/src/parser.cc')
-rw-r--r--deps/v8/src/parser.cc1680
1 files changed, 915 insertions, 765 deletions
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc
index bfdeaa3276..985a90f8dc 100644
--- a/deps/v8/src/parser.cc
+++ b/deps/v8/src/parser.cc
@@ -251,27 +251,18 @@ int ParseData::FunctionsSize() {
}
-void Parser::SetCachedData() {
- if (compile_options() == ScriptCompiler::kNoCompileOptions) {
+void Parser::SetCachedData(CompilationInfo* info) {
+ if (compile_options_ == ScriptCompiler::kNoCompileOptions) {
cached_parse_data_ = NULL;
} else {
- DCHECK(info_->cached_data() != NULL);
- if (compile_options() == ScriptCompiler::kConsumeParserCache) {
- cached_parse_data_ = ParseData::FromCachedData(*info_->cached_data());
+ DCHECK(info->cached_data() != NULL);
+ if (compile_options_ == ScriptCompiler::kConsumeParserCache) {
+ cached_parse_data_ = ParseData::FromCachedData(*info->cached_data());
}
}
}
-Scope* Parser::NewScope(Scope* parent, ScopeType scope_type) {
- DCHECK(ast_value_factory());
- Scope* result =
- new (zone()) Scope(parent, scope_type, ast_value_factory(), zone());
- result->Initialize();
- return result;
-}
-
-
FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
int pos, int end_pos) {
int materialized_literal_count = -1;
@@ -280,8 +271,12 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
int parameter_count = 0;
const AstRawString* name = ast_value_factory()->empty_string();
- Scope* function_scope = NewScope(scope, FUNCTION_SCOPE);
- function_scope->SetStrictMode(STRICT);
+
+ FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor
+ : FunctionKind::kDefaultBaseConstructor;
+ Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind);
+ function_scope->SetLanguageMode(
+ static_cast<LanguageMode>(scope->language_mode() | STRICT_BIT));
// Set start and end position to the same value
function_scope->set_start_position(pos);
function_scope->set_end_position(pos);
@@ -290,18 +285,18 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
{
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, function_scope,
- &function_factory);
+ kind, &function_factory);
- body = new (zone()) ZoneList<Statement*>(1, zone());
+ body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone());
+ AddAssertIsConstruct(body, pos);
if (call_super) {
ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(0, zone());
CallRuntime* call = factory()->NewCallRuntime(
ast_value_factory()->empty_string(),
- Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args,
- pos);
- body->Add(factory()->NewExpressionStatement(call, pos), zone());
- function_scope->RecordSuperConstructorCallUsage();
+ Runtime::FunctionForId(Runtime::kInlineDefaultConstructorCallSuper),
+ args, pos);
+ body->Add(factory()->NewReturnStatement(call, pos), zone());
}
materialized_literal_count = function_state.materialized_literal_count();
@@ -314,8 +309,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
materialized_literal_count, expected_property_count, handler_count,
parameter_count, FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction,
- FunctionLiteral::kNotParenthesized, FunctionKind::kDefaultConstructor,
- pos);
+ FunctionLiteral::kNotParenthesized, kind, pos);
return function_literal;
}
@@ -329,8 +323,8 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
class Target BASE_EMBEDDED {
public:
- Target(Target** variable, AstNode* node)
- : variable_(variable), node_(node), previous_(*variable) {
+ Target(Target** variable, BreakableStatement* statement)
+ : variable_(variable), statement_(statement), previous_(*variable) {
*variable = this;
}
@@ -339,11 +333,11 @@ class Target BASE_EMBEDDED {
}
Target* previous() { return previous_; }
- AstNode* node() { return node_; }
+ BreakableStatement* statement() { return statement_; }
private:
Target** variable_;
- AstNode* node_;
+ BreakableStatement* statement_;
Target* previous_;
};
@@ -388,9 +382,18 @@ class TargetScope BASE_EMBEDDED {
// ----------------------------------------------------------------------------
// Implementation of Parser
+bool ParserTraits::IsEval(const AstRawString* identifier) const {
+ return identifier == parser_->ast_value_factory()->eval_string();
+}
+
+
+bool ParserTraits::IsArguments(const AstRawString* identifier) const {
+ return identifier == parser_->ast_value_factory()->arguments_string();
+}
+
+
bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const {
- return identifier == parser_->ast_value_factory()->eval_string() ||
- identifier == parser_->ast_value_factory()->arguments_string();
+ return IsEval(identifier) || IsArguments(identifier);
}
@@ -407,9 +410,8 @@ bool ParserTraits::IsConstructor(const AstRawString* identifier) const {
bool ParserTraits::IsThisProperty(Expression* expression) {
DCHECK(expression != NULL);
Property* property = expression->AsProperty();
- return property != NULL &&
- property->obj()->AsVariableProxy() != NULL &&
- property->obj()->AsVariableProxy()->is_this();
+ return property != NULL && property->obj()->IsVariableProxy() &&
+ property->obj()->AsVariableProxy()->is_this();
}
@@ -433,8 +435,7 @@ void ParserTraits::PushPropertyName(FuncNameInferrer* fni,
void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
Expression* right) {
DCHECK(left != NULL);
- if (left->AsProperty() != NULL &&
- right->AsFunctionLiteral() != NULL) {
+ if (left->IsProperty() && right->IsFunctionLiteral()) {
right->AsFunctionLiteral()->set_pretenure();
}
}
@@ -665,7 +666,7 @@ const AstRawString* ParserTraits::GetNumberAsSymbol(Scanner* scanner) {
char array[100];
const char* string =
DoubleToCString(double_value, Vector<char>(array, arraysize(array)));
- return ast_value_factory()->GetOneByteString(string);
+ return parser_->ast_value_factory()->GetOneByteString(string);
}
@@ -718,13 +719,14 @@ Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
int pos, Scope* scope,
AstNodeFactory* factory) {
if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
- // The name may refer to a module instance object, so its type is unknown.
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Variable %.*s ", name->length(), name->raw_data());
-#endif
- Interface* interface = Interface::NewUnknown(parser_->zone());
- return scope->NewUnresolved(factory, name, interface, pos);
+
+ // Arrow function parameters are parsed as an expression. When
+ // parsing lazily, it is enough to create a VariableProxy in order
+ // for Traits::DeclareArrowParametersFromExpression() to be able to
+ // pick the names of the parameters.
+ return parser_->parsing_lazy_arrow_parameters_
+ ? factory->NewVariableProxy(name, false, pos)
+ : scope->NewUnresolved(factory, name, pos);
}
@@ -779,22 +781,29 @@ ClassLiteral* ParserTraits::ParseClassLiteral(
}
-Parser::Parser(CompilationInfo* info, ParseInfo* parse_info)
- : ParserBase<ParserTraits>(&scanner_, parse_info->stack_limit,
- info->extension(), NULL, info->zone(), this),
- scanner_(parse_info->unicode_cache),
+Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed,
+ UnicodeCache* unicode_cache)
+ : ParserBase<ParserTraits>(info->zone(), &scanner_, stack_limit,
+ info->extension(), info->ast_value_factory(),
+ NULL, this),
+ scanner_(unicode_cache),
reusable_preparser_(NULL),
original_scope_(NULL),
target_stack_(NULL),
+ compile_options_(info->compile_options()),
cached_parse_data_(NULL),
- info_(info),
+ parsing_lazy_arrow_parameters_(false),
has_pending_error_(false),
pending_error_message_(NULL),
pending_error_arg_(NULL),
pending_error_char_arg_(NULL),
total_preparse_skipped_(0),
- pre_parse_timer_(NULL) {
- DCHECK(!script().is_null() || info->source_stream() != NULL);
+ pre_parse_timer_(NULL),
+ parsing_on_main_thread_(true) {
+ // Even though we were passed CompilationInfo, we should not store it in
+ // Parser - this makes sure that Isolate is not accidentally accessed via
+ // CompilationInfo during background parsing.
+ DCHECK(!info->script().is_null() || info->source_stream() != NULL);
set_allow_lazy(false); // Must be explicitly enabled.
set_allow_natives(FLAG_allow_natives_syntax || info->is_native());
set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping);
@@ -806,27 +815,34 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info)
set_allow_harmony_templates(FLAG_harmony_templates);
set_allow_harmony_sloppy(FLAG_harmony_sloppy);
set_allow_harmony_unicode(FLAG_harmony_unicode);
+ set_allow_harmony_computed_property_names(
+ FLAG_harmony_computed_property_names);
+ set_allow_harmony_rest_params(FLAG_harmony_rest_parameters);
+ set_allow_strong_mode(FLAG_strong_mode);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
}
if (info->ast_value_factory() == NULL) {
// info takes ownership of AstValueFactory.
- info->SetAstValueFactory(
- new AstValueFactory(zone(), parse_info->hash_seed));
+ info->SetAstValueFactory(new AstValueFactory(zone(), hash_seed));
+ ast_value_factory_ = info->ast_value_factory();
}
}
-FunctionLiteral* Parser::ParseProgram() {
+FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
// TODO(bmeurer): We temporarily need to pass allow_nesting = true here,
// see comment for HistogramTimerScope class.
- // It's OK to use the counters here, since this function is only called in
- // the main thread.
- HistogramTimerScope timer_scope(isolate()->counters()->parse(), true);
- Handle<String> source(String::cast(script()->source()));
- isolate()->counters()->total_parse_size()->Increment(source->length());
+ // It's OK to use the Isolate & counters here, since this function is only
+ // called in the main thread.
+ DCHECK(parsing_on_main_thread_);
+
+ Isolate* isolate = info->isolate();
+ HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
+ Handle<String> source(String::cast(info->script()->source()));
+ isolate->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
if (FLAG_trace_parse) {
timer.Start();
@@ -854,24 +870,24 @@ FunctionLiteral* Parser::ParseProgram() {
ExternalTwoByteStringUtf16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
scanner_.Initialize(&stream);
- result = DoParseProgram(info(), &top_scope, &eval_scope);
+ result = DoParseProgram(info, &top_scope, &eval_scope);
} else {
GenericStringUtf16CharacterStream stream(source, 0, source->length());
scanner_.Initialize(&stream);
- result = DoParseProgram(info(), &top_scope, &eval_scope);
+ result = DoParseProgram(info, &top_scope, &eval_scope);
}
top_scope->set_end_position(source->length());
if (eval_scope != NULL) {
eval_scope->set_end_position(source->length());
}
- HandleSourceURLComments();
+ HandleSourceURLComments(info);
if (FLAG_trace_parse && result != NULL) {
double ms = timer.Elapsed().InMillisecondsF();
- if (info()->is_eval()) {
+ if (info->is_eval()) {
PrintF("[parsing eval");
- } else if (info()->script()->name()->IsString()) {
- String* name = String::cast(info()->script()->name());
+ } else if (info->script()->name()->IsString()) {
+ String* name = String::cast(info->script()->name());
SmartArrayPointer<char> name_chars = name->ToCString();
PrintF("[parsing script: %s", name_chars.get());
} else {
@@ -880,7 +896,7 @@ FunctionLiteral* Parser::ParseProgram() {
PrintF(" - took %0.3f ms]\n", ms);
}
if (produce_cached_parse_data()) {
- if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
+ if (result != NULL) *info->cached_data() = recorder.GetScriptData();
log_ = NULL;
}
return result;
@@ -889,6 +905,9 @@ FunctionLiteral* Parser::ParseProgram() {
FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
Scope** eval_scope) {
+ // Note that this function can be called from the main thread or from a
+ // background thread. We should not access anything Isolate / heap dependent
+ // via CompilationInfo, and also not pass it forward.
DCHECK(scope_ == NULL);
DCHECK(target_stack_ == NULL);
@@ -897,16 +916,18 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
*scope = NewScope(scope_, SCRIPT_SCOPE);
info->SetScriptScope(*scope);
if (!info->context().is_null() && !info->context()->IsNativeContext()) {
- *scope = Scope::DeserializeScopeChain(*info->context(), *scope, zone());
+ *scope = Scope::DeserializeScopeChain(info->isolate(), zone(),
+ *info->context(), *scope);
// The Scope is backed up by ScopeInfo (which is in the V8 heap); this
// means the Parser cannot operate independent of the V8 heap. Tell the
// string table to internalize strings and values right after they're
- // created.
- ast_value_factory()->Internalize(isolate());
+ // created. This kind of parsing can only be done in the main thread.
+ DCHECK(parsing_on_main_thread_);
+ ast_value_factory()->Internalize(info->isolate());
}
original_scope_ = *scope;
if (info->is_eval()) {
- if (!(*scope)->is_script_scope() || info->strict_mode() == STRICT) {
+ if (!(*scope)->is_script_scope() || is_strict(info->language_mode())) {
*scope = NewScope(*scope, EVAL_SCOPE);
}
} else if (info->is_global()) {
@@ -926,20 +947,27 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
// Enters 'scope'.
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, *scope,
- &function_factory);
+ kNormalFunction, &function_factory);
- scope_->SetStrictMode(info->strict_mode());
+ scope_->SetLanguageMode(info->language_mode());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
bool ok = true;
int beg_pos = scanner()->location().beg_pos;
- ParseSourceElements(body, Token::EOS, info->is_eval(), true, eval_scope,
- &ok);
+ if (info->is_module()) {
+ DCHECK(allow_harmony_modules());
+ Statement* stmt = ParseModule(&ok);
+ if (ok) {
+ body->Add(stmt, zone());
+ }
+ } else {
+ ParseStatementList(body, Token::EOS, info->is_eval(), eval_scope, &ok);
+ }
- if (ok && strict_mode() == STRICT) {
+ if (ok && is_strict(language_mode())) {
CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
}
- if (ok && allow_harmony_scoping() && strict_mode() == STRICT) {
+ if (ok && allow_harmony_scoping() && is_strict(language_mode())) {
CheckConflictingVarDeclarations(scope_, &ok);
}
@@ -972,17 +1000,18 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
}
-FunctionLiteral* Parser::ParseLazy() {
- // It's OK to use the counters here, since this function is only called in
- // the main thread.
- HistogramTimerScope timer_scope(isolate()->counters()->parse_lazy());
- Handle<String> source(String::cast(script()->source()));
- isolate()->counters()->total_parse_size()->Increment(source->length());
+FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
+ // It's OK to use the Isolate & counters here, since this function is only
+ // called in the main thread.
+ DCHECK(parsing_on_main_thread_);
+ HistogramTimerScope timer_scope(info->isolate()->counters()->parse_lazy());
+ Handle<String> source(String::cast(info->script()->source()));
+ info->isolate()->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
if (FLAG_trace_parse) {
timer.Start();
}
- Handle<SharedFunctionInfo> shared_info = info()->shared_info();
+ Handle<SharedFunctionInfo> shared_info = info->shared_info();
// Initialize parser state.
source = String::Flatten(source);
@@ -992,12 +1021,12 @@ FunctionLiteral* Parser::ParseLazy() {
Handle<ExternalTwoByteString>::cast(source),
shared_info->start_position(),
shared_info->end_position());
- result = ParseLazy(&stream);
+ result = ParseLazy(info, &stream);
} else {
GenericStringUtf16CharacterStream stream(source,
shared_info->start_position(),
shared_info->end_position());
- result = ParseLazy(&stream);
+ result = ParseLazy(info, &stream);
}
if (FLAG_trace_parse && result != NULL) {
@@ -1009,8 +1038,9 @@ FunctionLiteral* Parser::ParseLazy() {
}
-FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
- Handle<SharedFunctionInfo> shared_info = info()->shared_info();
+FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
+ Utf16CharacterStream* source) {
+ Handle<SharedFunctionInfo> shared_info = info->shared_info();
scanner_.Initialize(source);
DCHECK(scope_ == NULL);
DCHECK(target_stack_ == NULL);
@@ -1029,18 +1059,22 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
{
// Parse the function literal.
Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
- info()->SetScriptScope(scope);
- if (!info()->closure().is_null()) {
- scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
- zone());
+ info->SetScriptScope(scope);
+ if (!info->closure().is_null()) {
+ // Ok to use Isolate here, since lazy function parsing is only done in the
+ // main thread.
+ DCHECK(parsing_on_main_thread_);
+ scope = Scope::DeserializeScopeChain(info->isolate(), zone(),
+ info->closure()->context(), scope);
}
original_scope_ = scope;
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, scope,
- &function_factory);
- DCHECK(scope->strict_mode() == SLOPPY || info()->strict_mode() == STRICT);
- DCHECK(info()->strict_mode() == shared_info->strict_mode());
- scope->SetStrictMode(shared_info->strict_mode());
+ shared_info->kind(), &function_factory);
+ DCHECK(is_sloppy(scope->language_mode()) ||
+ is_strict(info->language_mode()));
+ DCHECK(info->language_mode() == shared_info->language_mode());
+ scope->SetLanguageMode(shared_info->language_mode());
FunctionLiteral::FunctionType function_type = shared_info->is_expression()
? (shared_info->is_anonymous()
? FunctionLiteral::ANONYMOUS_EXPRESSION
@@ -1049,11 +1083,15 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
bool ok = true;
if (shared_info->is_arrow()) {
+ // The first expression being parsed is the parameter list of the arrow
+ // function. Setting this avoids prevents ExpressionFromIdentifier()
+ // from creating unresolved variables in already-resolved scopes.
+ parsing_lazy_arrow_parameters_ = true;
Expression* expression = ParseExpression(false, &ok);
DCHECK(expression->IsFunctionLiteral());
result = expression->AsFunctionLiteral();
} else if (shared_info->is_default_constructor()) {
- result = DefaultConstructor(shared_info->uses_super_constructor_call(),
+ result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()),
scope, shared_info->start_position(),
shared_info->end_position());
} else {
@@ -1078,11 +1116,10 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
}
-void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
- int end_token, bool is_eval, bool is_global,
- Scope** eval_scope, bool* ok) {
- // SourceElements ::
- // (ModuleElement)* <end_token>
+void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
+ bool is_eval, Scope** eval_scope, bool* ok) {
+ // StatementList ::
+ // (StatementListItem)* <end_token>
// Allocate a target stack to use for this set of source
// elements. This way, all scripts and functions get their own
@@ -1090,7 +1127,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
// functions.
TargetScope scope(&this->target_stack_);
- DCHECK(processor != NULL);
+ DCHECK(body != NULL);
bool directive_prologue = true; // Parsing directive prologue.
while (peek() != end_token) {
@@ -1099,12 +1136,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
}
Scanner::Location token_loc = scanner()->peek_location();
- Statement* stat;
- if (is_global && !is_eval) {
- stat = ParseModuleElement(NULL, CHECK_OK);
- } else {
- stat = ParseBlockElement(NULL, CHECK_OK);
- }
+ Statement* stat = ParseStatementListItem(CHECK_OK);
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
@@ -1118,33 +1150,48 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
if ((e_stat = stat->AsExpressionStatement()) != NULL &&
(literal = e_stat->expression()->AsLiteral()) != NULL &&
literal->raw_value()->IsString()) {
- // Check "use strict" directive (ES5 14.1) and "use asm" directive. Only
- // one can be present.
- if (strict_mode() == SLOPPY &&
+ // Check "use strict" directive (ES5 14.1), "use asm" directive, and
+ // "use strong" directive (experimental).
+ bool use_strict_found =
literal->raw_value()->AsString() ==
ast_value_factory()->use_strict_string() &&
token_loc.end_pos - token_loc.beg_pos ==
- ast_value_factory()->use_strict_string()->length() + 2) {
- // TODO(mstarzinger): Global strict eval calls, need their own scope
- // as specified in ES5 10.4.2(3). The correct fix would be to always
- // add this scope in DoParseProgram(), but that requires adaptations
- // all over the code base, so we go with a quick-fix for now.
- // In the same manner, we have to patch the parsing mode.
- if (is_eval && !scope_->is_eval_scope()) {
- DCHECK(scope_->is_script_scope());
- Scope* scope = NewScope(scope_, EVAL_SCOPE);
- scope->set_start_position(scope_->start_position());
- scope->set_end_position(scope_->end_position());
- scope_ = scope;
- if (eval_scope != NULL) {
- // Caller will correct the positions of the ad hoc eval scope.
- *eval_scope = scope;
+ ast_value_factory()->use_strict_string()->length() + 2;
+ bool use_strong_found =
+ allow_strong_mode() &&
+ literal->raw_value()->AsString() ==
+ ast_value_factory()->use_strong_string() &&
+ token_loc.end_pos - token_loc.beg_pos ==
+ ast_value_factory()->use_strong_string()->length() + 2;
+ if (use_strict_found || use_strong_found) {
+ // Strong mode implies strict mode. If there are several "use strict"
+ // / "use strong" directives, do the strict mode changes only once.
+ if (is_sloppy(scope_->language_mode())) {
+ // TODO(mstarzinger): Global strict eval calls, need their own scope
+ // as specified in ES5 10.4.2(3). The correct fix would be to always
+ // add this scope in DoParseProgram(), but that requires adaptations
+ // all over the code base, so we go with a quick-fix for now.
+ // In the same manner, we have to patch the parsing mode.
+ if (is_eval && !scope_->is_eval_scope()) {
+ DCHECK(scope_->is_script_scope());
+ Scope* scope = NewScope(scope_, EVAL_SCOPE);
+ scope->set_start_position(scope_->start_position());
+ scope->set_end_position(scope_->end_position());
+ scope_ = scope;
+ if (eval_scope != NULL) {
+ // Caller will correct the positions of the ad hoc eval scope.
+ *eval_scope = scope;
+ }
+ mode_ = PARSE_EAGERLY;
}
- mode_ = PARSE_EAGERLY;
+ scope_->SetLanguageMode(static_cast<LanguageMode>(
+ scope_->language_mode() | STRICT_BIT));
+ }
+
+ if (use_strong_found) {
+ scope_->SetLanguageMode(static_cast<LanguageMode>(
+ scope_->language_mode() | STRONG_BIT));
}
- scope_->SetStrictMode(STRICT);
- // "use strict" is the only directive for now.
- directive_prologue = false;
} else if (literal->raw_value()->AsString() ==
ast_value_factory()->use_asm_string() &&
token_loc.end_pos - token_loc.beg_pos ==
@@ -1160,169 +1207,89 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
}
}
- processor->Add(stat, zone());
+ body->Add(stat, zone());
}
return 0;
}
-Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels,
- bool* ok) {
- // (Ecma 262 5th Edition, clause 14):
- // SourceElement:
+Statement* Parser::ParseStatementListItem(bool* ok) {
+ // (Ecma 262 6th Edition, 13.1):
+ // StatementListItem:
// Statement
- // FunctionDeclaration
- //
- // In harmony mode we allow additionally the following productions
- // ModuleElement:
- // LetDeclaration
- // ConstDeclaration
- // ModuleDeclaration
- // ImportDeclaration
- // ExportDeclaration
- // GeneratorDeclaration
+ // Declaration
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
case Token::CLASS:
return ParseClassDeclaration(NULL, ok);
- case Token::IMPORT:
- return ParseImportDeclaration(ok);
- case Token::EXPORT:
- return ParseExportDeclaration(ok);
case Token::CONST:
- return ParseVariableStatement(kModuleElement, NULL, ok);
+ case Token::VAR:
+ return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::LET:
DCHECK(allow_harmony_scoping());
- if (strict_mode() == STRICT) {
- return ParseVariableStatement(kModuleElement, NULL, ok);
+ if (is_strict(language_mode())) {
+ return ParseVariableStatement(kStatementListItem, NULL, ok);
}
// Fall through.
- default: {
- Statement* stmt = ParseStatement(labels, CHECK_OK);
- // Handle 'module' as a context-sensitive keyword.
- if (FLAG_harmony_modules &&
- peek() == Token::IDENTIFIER &&
- !scanner()->HasAnyLineTerminatorBeforeNext() &&
- stmt != NULL) {
- ExpressionStatement* estmt = stmt->AsExpressionStatement();
- if (estmt != NULL && estmt->expression()->AsVariableProxy() != NULL &&
- estmt->expression()->AsVariableProxy()->raw_name() ==
- ast_value_factory()->module_string() &&
- !scanner()->literal_contains_escapes()) {
- return ParseModuleDeclaration(NULL, ok);
- }
- }
- return stmt;
- }
- }
-}
-
-
-Statement* Parser::ParseModuleDeclaration(ZoneList<const AstRawString*>* names,
- bool* ok) {
- // ModuleDeclaration:
- // 'module' Identifier Module
-
- int pos = peek_position();
- const AstRawString* name =
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
-
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Module %.*s ", name->length(), name->raw_data());
-#endif
-
- Module* module = ParseModule(CHECK_OK);
- VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface());
- Declaration* declaration =
- factory()->NewModuleDeclaration(proxy, module, scope_, pos);
- Declare(declaration, true, CHECK_OK);
-
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Module %.*s ", name->length(), name->raw_data());
- if (FLAG_print_interfaces) {
- PrintF("module %.*s: ", name->length(), name->raw_data());
- module->interface()->Print();
+ default:
+ return ParseStatement(NULL, ok);
}
-#endif
-
- if (names) names->Add(name, zone());
- if (module->body() == NULL)
- return factory()->NewEmptyStatement(pos);
- else
- return factory()->NewModuleStatement(proxy, module->body(), pos);
}
-Module* Parser::ParseModule(bool* ok) {
- // Module:
- // '{' ModuleElement '}'
- // '=' ModulePath ';'
- // 'at' String ';'
+Statement* Parser::ParseModuleItem(bool* ok) {
+ // (Ecma 262 6th Edition, 15.2):
+ // ModuleItem :
+ // ImportDeclaration
+ // ExportDeclaration
+ // StatementListItem
switch (peek()) {
- case Token::LBRACE:
- return ParseModuleLiteral(ok);
-
- case Token::ASSIGN: {
- Expect(Token::ASSIGN, CHECK_OK);
- Module* result = ParseModulePath(CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return result;
- }
-
- default: {
- ExpectContextualKeyword(CStrVector("at"), CHECK_OK);
- Module* result = ParseModuleUrl(CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return result;
- }
+ case Token::IMPORT:
+ return ParseImportDeclaration(ok);
+ case Token::EXPORT:
+ return ParseExportDeclaration(ok);
+ default:
+ return ParseStatementListItem(ok);
}
}
-Module* Parser::ParseModuleLiteral(bool* ok) {
- // Module:
- // '{' ModuleElement '}'
+Statement* Parser::ParseModule(bool* ok) {
+ // (Ecma 262 6th Edition, 15.2):
+ // Module :
+ // ModuleBody?
+ //
+ // ModuleBody :
+ // ModuleItem*
- int pos = peek_position();
- // Construct block expecting 16 statements.
Block* body = factory()->NewBlock(NULL, 16, false, RelocInfo::kNoPosition);
-#ifdef DEBUG
- if (FLAG_print_interface_details) PrintF("# Literal ");
-#endif
Scope* scope = NewScope(scope_, MODULE_SCOPE);
-
- Expect(Token::LBRACE, CHECK_OK);
scope->set_start_position(scanner()->location().beg_pos);
- scope->SetStrictMode(STRICT);
+ scope->SetLanguageMode(
+ static_cast<LanguageMode>(scope->language_mode() | STRICT_BIT));
{
BlockState block_state(&scope_, scope);
- TargetCollector collector(zone());
- Target target(&this->target_stack_, &collector);
- Target target_body(&this->target_stack_, body);
- while (peek() != Token::RBRACE) {
- Statement* stat = ParseModuleElement(NULL, CHECK_OK);
+ while (peek() != Token::EOS) {
+ Statement* stat = ParseModuleItem(CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat, zone());
}
}
}
- Expect(Token::RBRACE, CHECK_OK);
scope->set_end_position(scanner()->location().end_pos);
body->set_scope(scope);
// Check that all exports are bound.
- Interface* interface = scope->interface();
- for (Interface::Iterator it = interface->iterator();
- !it.done(); it.Advance()) {
+ ModuleDescriptor* descriptor = scope->module();
+ for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
+ it.Advance()) {
if (scope->LookupLocal(it.name()) == NULL) {
ParserTraits::ReportMessage("module_export_undefined", it.name());
*ok = false;
@@ -1330,196 +1297,284 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
}
}
- interface->MakeModule(ok);
- DCHECK(*ok);
- interface->Freeze(ok);
- DCHECK(*ok);
- return factory()->NewModuleLiteral(body, interface, pos);
+ scope->module()->Freeze();
+ return body;
}
-Module* Parser::ParseModulePath(bool* ok) {
- // ModulePath:
- // Identifier
- // ModulePath '.' Identifier
+Literal* Parser::ParseModuleSpecifier(bool* ok) {
+ // ModuleSpecifier :
+ // StringLiteral
int pos = peek_position();
- Module* result = ParseModuleVariable(CHECK_OK);
- while (Check(Token::PERIOD)) {
- const AstRawString* name = ParseIdentifierName(CHECK_OK);
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Path .%.*s ", name->length(), name->raw_data());
-#endif
- Module* member = factory()->NewModulePath(result, name, pos);
- result->interface()->Add(name, member->interface(), zone(), ok);
- if (!*ok) {
-#ifdef DEBUG
- if (FLAG_print_interfaces) {
- PrintF("PATH TYPE ERROR at '%.*s'\n", name->length(), name->raw_data());
- PrintF("result: ");
- result->interface()->Print();
- PrintF("member: ");
- member->interface()->Print();
- }
-#endif
- ParserTraits::ReportMessage("invalid_module_path", name);
- return NULL;
- }
- result = member;
- }
-
- return result;
+ Expect(Token::STRING, CHECK_OK);
+ return factory()->NewStringLiteral(GetSymbol(scanner()), pos);
}
-Module* Parser::ParseModuleVariable(bool* ok) {
- // ModulePath:
- // Identifier
-
- int pos = peek_position();
- const AstRawString* name =
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Module variable %.*s ", name->length(), name->raw_data());
-#endif
- VariableProxy* proxy = scope_->NewUnresolved(
- factory(), name, Interface::NewModule(zone()),
- scanner()->location().beg_pos);
+void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names,
+ Scanner::Location* reserved_loc, bool* ok) {
+ // ExportClause :
+ // '{' '}'
+ // '{' ExportsList '}'
+ // '{' ExportsList ',' '}'
+ //
+ // ExportsList :
+ // ExportSpecifier
+ // ExportsList ',' ExportSpecifier
+ //
+ // ExportSpecifier :
+ // IdentifierName
+ // IdentifierName 'as' IdentifierName
- return factory()->NewModuleVariable(proxy, pos);
-}
+ Expect(Token::LBRACE, CHECK_OK);
+ Token::Value name_tok;
+ while ((name_tok = peek()) != Token::RBRACE) {
+ // Keep track of the first reserved word encountered in case our
+ // caller needs to report an error.
+ if (!reserved_loc->IsValid() &&
+ !Token::IsIdentifier(name_tok, STRICT, false)) {
+ *reserved_loc = scanner()->location();
+ }
+ const AstRawString* name = ParseIdentifierName(CHECK_OK);
+ names->Add(name, zone());
+ const AstRawString* export_name = NULL;
+ if (CheckContextualKeyword(CStrVector("as"))) {
+ export_name = ParseIdentifierName(CHECK_OK);
+ }
+ // TODO(ES6): Return the export_name as well as the name.
+ USE(export_name);
+ if (peek() == Token::RBRACE) break;
+ Expect(Token::COMMA, CHECK_OK);
+ }
-Module* Parser::ParseModuleUrl(bool* ok) {
- // Module:
- // String
+ Expect(Token::RBRACE, CHECK_OK);
- int pos = peek_position();
- Expect(Token::STRING, CHECK_OK);
- const AstRawString* symbol = GetSymbol(scanner());
+ return 0;
+}
- // TODO(ES6): Request JS resource from environment...
-#ifdef DEBUG
- if (FLAG_print_interface_details) PrintF("# Url ");
-#endif
+void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* names,
+ bool* ok) {
+ // NamedImports :
+ // '{' '}'
+ // '{' ImportsList '}'
+ // '{' ImportsList ',' '}'
+ //
+ // ImportsList :
+ // ImportSpecifier
+ // ImportsList ',' ImportSpecifier
+ //
+ // ImportSpecifier :
+ // BindingIdentifier
+ // IdentifierName 'as' BindingIdentifier
- // Create an empty literal as long as the feature isn't finished.
- USE(symbol);
- Scope* scope = NewScope(scope_, MODULE_SCOPE);
- Block* body = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
- body->set_scope(scope);
- Interface* interface = scope->interface();
- Module* result = factory()->NewModuleLiteral(body, interface, pos);
- interface->Freeze(ok);
- DCHECK(*ok);
- interface->Unify(scope->interface(), zone(), ok);
- DCHECK(*ok);
- return result;
-}
+ Expect(Token::LBRACE, CHECK_OK);
+ Token::Value name_tok;
+ while ((name_tok = peek()) != Token::RBRACE) {
+ const AstRawString* name = ParseIdentifierName(CHECK_OK);
+ const AstRawString* import_name = NULL;
+ // In the presence of 'as', the left-side of the 'as' can
+ // be any IdentifierName. But without 'as', it must be a valid
+ // BindingIdentiifer.
+ if (CheckContextualKeyword(CStrVector("as"))) {
+ import_name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ } else if (!Token::IsIdentifier(name_tok, STRICT, false)) {
+ *ok = false;
+ ReportMessageAt(scanner()->location(), "unexpected_reserved");
+ return NULL;
+ } else if (IsEvalOrArguments(name)) {
+ *ok = false;
+ ReportMessageAt(scanner()->location(), "strict_eval_arguments");
+ return NULL;
+ }
+ // TODO(ES6): Return the import_name as well as the name.
+ names->Add(name, zone());
+ USE(import_name);
+ if (peek() == Token::RBRACE) break;
+ Expect(Token::COMMA, CHECK_OK);
+ }
-Module* Parser::ParseModuleSpecifier(bool* ok) {
- // ModuleSpecifier:
- // String
- // ModulePath
+ Expect(Token::RBRACE, CHECK_OK);
- if (peek() == Token::STRING) {
- return ParseModuleUrl(ok);
- } else {
- return ParseModulePath(ok);
- }
+ return NULL;
}
-Block* Parser::ParseImportDeclaration(bool* ok) {
- // ImportDeclaration:
- // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
+Statement* Parser::ParseImportDeclaration(bool* ok) {
+ // ImportDeclaration :
+ // 'import' ImportClause 'from' ModuleSpecifier ';'
+ // 'import' ModuleSpecifier ';'
+ //
+ // ImportClause :
+ // NameSpaceImport
+ // NamedImports
+ // ImportedDefaultBinding
+ // ImportedDefaultBinding ',' NameSpaceImport
+ // ImportedDefaultBinding ',' NamedImports
//
- // TODO(ES6): implement destructuring ImportSpecifiers
+ // NameSpaceImport :
+ // '*' 'as' ImportedBinding
int pos = peek_position();
Expect(Token::IMPORT, CHECK_OK);
+
+ Token::Value tok = peek();
+
+ // 'import' ModuleSpecifier ';'
+ if (tok == Token::STRING) {
+ ParseModuleSpecifier(CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return factory()->NewEmptyStatement(pos);
+ }
+
+ // Parse ImportedDefaultBinding if present.
+ const AstRawString* imported_default_binding = NULL;
+ if (tok != Token::MUL && tok != Token::LBRACE) {
+ imported_default_binding =
+ ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ }
+
+ const AstRawString* module_instance_binding = NULL;
ZoneList<const AstRawString*> names(1, zone());
+ if (imported_default_binding == NULL || Check(Token::COMMA)) {
+ switch (peek()) {
+ case Token::MUL: {
+ Consume(Token::MUL);
+ ExpectContextualKeyword(CStrVector("as"), CHECK_OK);
+ module_instance_binding =
+ ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ break;
+ }
- const AstRawString* name = ParseIdentifierName(CHECK_OK);
- names.Add(name, zone());
- while (peek() == Token::COMMA) {
- Consume(Token::COMMA);
- name = ParseIdentifierName(CHECK_OK);
- names.Add(name, zone());
+ case Token::LBRACE:
+ ParseNamedImports(&names, CHECK_OK);
+ break;
+
+ default:
+ *ok = false;
+ ReportUnexpectedToken(scanner()->current_token());
+ return NULL;
+ }
}
ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
- Module* module = ParseModuleSpecifier(CHECK_OK);
+ Literal* module = ParseModuleSpecifier(CHECK_OK);
+ USE(module);
+
ExpectSemicolon(CHECK_OK);
- // Generate a separate declaration for each identifier.
- // TODO(ES6): once we implement destructuring, make that one declaration.
- Block* block = factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+ if (module_instance_binding != NULL) {
+ // TODO(ES6): Bind name to the Module Instance Object of module.
+ }
+
+ if (imported_default_binding != NULL) {
+ // TODO(ES6): Add an appropriate declaration.
+ }
+
for (int i = 0; i < names.length(); ++i) {
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Import %.*s ", name->length(), name->raw_data());
-#endif
- Interface* interface = Interface::NewUnknown(zone());
- module->interface()->Add(names[i], interface, zone(), ok);
- if (!*ok) {
-#ifdef DEBUG
- if (FLAG_print_interfaces) {
- PrintF("IMPORT TYPE ERROR at '%.*s'\n", name->length(),
- name->raw_data());
- PrintF("module: ");
- module->interface()->Print();
- }
-#endif
- ParserTraits::ReportMessage("invalid_module_path", name);
- return NULL;
+ // TODO(ES6): Add an appropriate declaration for each name
+ }
+
+ return factory()->NewEmptyStatement(pos);
+}
+
+
+Statement* Parser::ParseExportDefault(bool* ok) {
+ // Supports the following productions, starting after the 'default' token:
+ // 'export' 'default' FunctionDeclaration
+ // 'export' 'default' ClassDeclaration
+ // 'export' 'default' AssignmentExpression[In] ';'
+
+ Statement* result = NULL;
+ switch (peek()) {
+ case Token::FUNCTION:
+ // TODO(ES6): Support parsing anonymous function declarations here.
+ result = ParseFunctionDeclaration(NULL, CHECK_OK);
+ break;
+
+ case Token::CLASS:
+ // TODO(ES6): Support parsing anonymous class declarations here.
+ result = ParseClassDeclaration(NULL, CHECK_OK);
+ break;
+
+ default: {
+ int pos = peek_position();
+ Expression* expr = ParseAssignmentExpression(true, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ result = factory()->NewExpressionStatement(expr, pos);
+ break;
}
- VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
- Declaration* declaration =
- factory()->NewImportDeclaration(proxy, module, scope_, pos);
- Declare(declaration, true, CHECK_OK);
}
- return block;
+ // TODO(ES6): Add default export to scope_->module()
+
+ return result;
}
Statement* Parser::ParseExportDeclaration(bool* ok) {
// ExportDeclaration:
- // 'export' Identifier (',' Identifier)* ';'
- // 'export' VariableDeclaration
- // 'export' FunctionDeclaration
- // 'export' GeneratorDeclaration
- // 'export' ModuleDeclaration
- //
- // TODO(ES6): implement structuring ExportSpecifiers
+ // 'export' '*' 'from' ModuleSpecifier ';'
+ // 'export' ExportClause ('from' ModuleSpecifier)? ';'
+ // 'export' VariableStatement
+ // 'export' Declaration
+ // 'export' 'default' ... (handled in ParseExportDefault)
+ int pos = peek_position();
Expect(Token::EXPORT, CHECK_OK);
Statement* result = NULL;
ZoneList<const AstRawString*> names(1, zone());
+ bool is_export_from = false;
switch (peek()) {
- case Token::IDENTIFIER: {
- int pos = position();
- const AstRawString* name =
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
- // Handle 'module' as a context-sensitive keyword.
- if (name != ast_value_factory()->module_string()) {
- names.Add(name, zone());
- while (peek() == Token::COMMA) {
- Consume(Token::COMMA);
- name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
- names.Add(name, zone());
- }
- ExpectSemicolon(CHECK_OK);
- result = factory()->NewEmptyStatement(pos);
- } else {
- result = ParseModuleDeclaration(&names, CHECK_OK);
+ case Token::DEFAULT:
+ Consume(Token::DEFAULT);
+ return ParseExportDefault(ok);
+
+ case Token::MUL: {
+ Consume(Token::MUL);
+ ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
+ Literal* module = ParseModuleSpecifier(CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ // TODO(ES6): Do something with the return value
+ // of ParseModuleSpecifier.
+ USE(module);
+ is_export_from = true;
+ result = factory()->NewEmptyStatement(pos);
+ break;
+ }
+
+ case Token::LBRACE: {
+ // There are two cases here:
+ //
+ // 'export' ExportClause ';'
+ // and
+ // 'export' ExportClause FromClause ';'
+ //
+ // In the first case, the exported identifiers in ExportClause must
+ // not be reserved words, while in the latter they may be. We
+ // pass in a location that gets filled with the first reserved word
+ // encountered, and then throw a SyntaxError if we are in the
+ // non-FromClause case.
+ Scanner::Location reserved_loc = Scanner::Location::invalid();
+ ParseExportClause(&names, &reserved_loc, CHECK_OK);
+ if (CheckContextualKeyword(CStrVector("from"))) {
+ Literal* module = ParseModuleSpecifier(CHECK_OK);
+ // TODO(ES6): Do something with the return value
+ // of ParseModuleSpecifier.
+ USE(module);
+ is_export_from = true;
+ } else if (reserved_loc.IsValid()) {
+ // No FromClause, so reserved words are invalid in ExportClause.
+ *ok = false;
+ ReportMessageAt(reserved_loc, "unexpected_reserved");
+ return NULL;
}
+ ExpectSemicolon(CHECK_OK);
+ result = factory()->NewEmptyStatement(pos);
break;
}
@@ -1534,7 +1589,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
case Token::VAR:
case Token::LET:
case Token::CONST:
- result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
+ result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
break;
default:
@@ -1556,24 +1611,21 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
}
}
- // Extract declared names into export declarations and interface.
- Interface* interface = scope_->interface();
- for (int i = 0; i < names.length(); ++i) {
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Export %.*s ", names[i]->length(), names[i]->raw_data());
-#endif
- Interface* inner = Interface::NewUnknown(zone());
- interface->Add(names[i], inner, zone(), CHECK_OK);
- if (!*ok)
- return NULL;
- VariableProxy* proxy = NewUnresolved(names[i], LET, inner);
- USE(proxy);
- // TODO(rossberg): Rethink whether we actually need to store export
- // declarations (for compilation?).
- // ExportDeclaration* declaration =
- // factory()->NewExportDeclaration(proxy, scope_, position);
- // scope_->AddDeclaration(declaration);
+ // TODO(ES6): Handle 'export from' once imports are properly implemented.
+ // For now we just drop such exports on the floor.
+ if (!is_export_from) {
+ // Extract declared names into export declarations and module descriptor.
+ ModuleDescriptor* descriptor = scope_->module();
+ for (int i = 0; i < names.length(); ++i) {
+ // TODO(adamk): Make early errors here provide the right error message
+ // (duplicate exported names).
+ descriptor->Add(names[i], zone(), CHECK_OK);
+ // TODO(rossberg): Rethink whether we actually need to store export
+ // declarations (for compilation?).
+ // ExportDeclaration* declaration =
+ // factory()->NewExportDeclaration(proxy, scope_, position);
+ // scope_->AddDeclaration(declaration);
+ }
}
DCHECK(result != NULL);
@@ -1581,41 +1633,22 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
}
-Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels,
- bool* ok) {
- // (Ecma 262 5th Edition, clause 14):
- // SourceElement:
- // Statement
- // FunctionDeclaration
- //
- // In harmony mode we allow additionally the following productions
- // BlockElement (aka SourceElement):
- // LetDeclaration
- // ConstDeclaration
- // GeneratorDeclaration
- // ClassDeclaration
+Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok) {
+ // Statement ::
+ // EmptyStatement
+ // ...
- switch (peek()) {
- case Token::FUNCTION:
- return ParseFunctionDeclaration(NULL, ok);
- case Token::CLASS:
- return ParseClassDeclaration(NULL, ok);
- case Token::CONST:
- return ParseVariableStatement(kModuleElement, NULL, ok);
- case Token::LET:
- DCHECK(allow_harmony_scoping());
- if (strict_mode() == STRICT) {
- return ParseVariableStatement(kModuleElement, NULL, ok);
- }
- // Fall through.
- default:
- return ParseStatement(labels, ok);
+ if (peek() == Token::SEMICOLON) {
+ Next();
+ return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
}
+ return ParseSubStatement(labels, ok);
}
-Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
- bool* ok) {
+Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok) {
// Statement ::
// Block
// VariableStatement
@@ -1644,6 +1677,11 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
return ParseBlock(labels, ok);
case Token::SEMICOLON:
+ if (is_strong(language_mode())) {
+ ReportMessageAt(scanner()->peek_location(), "strong_empty");
+ *ok = false;
+ return NULL;
+ }
Next();
return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
@@ -1703,7 +1741,7 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
// In Harmony mode, this case also handles the extension:
// Statement:
// GeneratorDeclaration
- if (strict_mode() == STRICT) {
+ if (is_strict(language_mode())) {
ReportMessageAt(scanner()->peek_location(), "strict_function");
*ok = false;
return NULL;
@@ -1711,22 +1749,21 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
return ParseFunctionDeclaration(NULL, ok);
}
- case Token::CLASS:
- return ParseClassDeclaration(NULL, ok);
-
case Token::DEBUGGER:
return ParseDebuggerStatement(ok);
case Token::VAR:
- case Token::CONST:
return ParseVariableStatement(kStatement, NULL, ok);
- case Token::LET:
- DCHECK(allow_harmony_scoping());
- if (strict_mode() == STRICT) {
+ case Token::CONST:
+ // In ES6 CONST is not allowed as a Statement, only as a
+ // LexicalDeclaration, however we continue to allow it in sloppy mode for
+ // backwards compatibility.
+ if (is_sloppy(language_mode())) {
return ParseVariableStatement(kStatement, NULL, ok);
}
- // Fall through.
+
+ // Fall through.
default:
return ParseExpressionOrLabelledStatement(labels, ok);
}
@@ -1734,14 +1771,13 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
VariableProxy* Parser::NewUnresolved(const AstRawString* name,
- VariableMode mode, Interface* interface) {
+ VariableMode mode) {
// If we are inside a function, a declaration of a var/const variable is a
// truly local variable, and the scope of the variable is always the function
// scope.
// Let/const variables in harmony mode are always added to the immediately
// enclosing scope.
- return DeclarationScope(mode)->NewUnresolved(
- factory(), name, interface, position());
+ return DeclarationScope(mode)->NewUnresolved(factory(), name, position());
}
@@ -1770,9 +1806,8 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
var = declaration_scope->LookupLocal(name);
if (var == NULL) {
// Declare the name.
- var = declaration_scope->DeclareLocal(name, mode,
- declaration->initialization(),
- kNotAssigned, proxy->interface());
+ var = declaration_scope->DeclareLocal(
+ name, mode, declaration->initialization(), kNotAssigned);
} else if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())
|| ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
!declaration_scope->is_script_scope())) {
@@ -1790,7 +1825,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
// because the var declaration is hoisted to the function scope where 'x'
// is already bound.
DCHECK(IsDeclaredVariableMode(var->mode()));
- if (allow_harmony_scoping() && strict_mode() == STRICT) {
+ if (allow_harmony_scoping() && is_strict(language_mode())) {
// In harmony we treat re-declarations as early errors. See
// ES5 16 for a definition of early errors.
ParserTraits::ReportMessage("var_redeclaration", name);
@@ -1827,19 +1862,17 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
// For global const variables we bind the proxy to a variable.
DCHECK(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL;
- var = new (zone())
- Variable(declaration_scope, name, mode, true, kind,
- kNeedsInitialization, kNotAssigned, proxy->interface());
+ var = new (zone()) Variable(declaration_scope, name, mode, true, kind,
+ kNeedsInitialization, kNotAssigned);
} else if (declaration_scope->is_eval_scope() &&
- declaration_scope->strict_mode() == SLOPPY) {
+ is_sloppy(declaration_scope->language_mode())) {
// For variable declarations in a sloppy eval scope the proxy is bound
// to a lookup variable to force a dynamic declaration using the
// DeclareLookupSlot runtime function.
Variable::Kind kind = Variable::NORMAL;
// TODO(sigurds) figure out if kNotAssigned is OK here
var = new (zone()) Variable(declaration_scope, name, mode, true, kind,
- declaration->initialization(), kNotAssigned,
- proxy->interface());
+ declaration->initialization(), kNotAssigned);
var->AllocateTo(Variable::LOOKUP, -1);
resolve = true;
}
@@ -1870,29 +1903,6 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
// runtime needs to provide both.
if (resolve && var != NULL) {
proxy->BindTo(var);
-
- if (FLAG_harmony_modules) {
- bool ok;
-#ifdef DEBUG
- if (FLAG_print_interface_details) {
- PrintF("# Declare %.*s ", var->raw_name()->length(),
- var->raw_name()->raw_data());
- }
-#endif
- proxy->interface()->Unify(var->interface(), zone(), &ok);
- if (!ok) {
-#ifdef DEBUG
- if (FLAG_print_interfaces) {
- PrintF("DECLARE TYPE ERROR\n");
- PrintF("proxy: ");
- proxy->interface()->Print();
- PrintF("var: ");
- var->interface()->Print();
- }
-#endif
- ParserTraits::ReportMessage("module_type_error", name);
- }
- }
}
}
@@ -1927,7 +1937,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
// TODO(1240846): It's weird that native function declarations are
// introduced dynamically when we meet their declarations, whereas
// other functions are set up when entering the surrounding scope.
- VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue());
+ VariableProxy* proxy = NewUnresolved(name, VAR);
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, VAR, scope_, pos);
Declare(declaration, true, CHECK_OK);
@@ -1965,10 +1975,13 @@ Statement* Parser::ParseFunctionDeclaration(
// In ES6, a function behaves as a lexical binding, except in
// a script scope, or the initial scope of eval or another function.
VariableMode mode =
- allow_harmony_scoping() && strict_mode() == STRICT &&
- !(scope_->is_script_scope() || scope_->is_eval_scope() ||
- scope_->is_function_scope()) ? LET : VAR;
- VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
+ is_strong(language_mode()) ? CONST :
+ allow_harmony_scoping() && is_strict(language_mode()) &&
+ !(scope_->is_script_scope() || scope_->is_eval_scope() ||
+ scope_->is_function_scope())
+ ? LET
+ : VAR;
+ VariableProxy* proxy = NewUnresolved(name, mode);
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos);
Declare(declaration, true, CHECK_OK);
@@ -1993,7 +2006,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
// so rewrite it as such.
Expect(Token::CLASS, CHECK_OK);
- if (!allow_harmony_sloppy() && strict_mode() == SLOPPY) {
+ if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
ReportMessage("sloppy_lexical");
*ok = false;
return NULL;
@@ -2006,13 +2019,15 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
ClassLiteral* value = ParseClassLiteral(name, scanner()->location(),
is_strict_reserved, pos, CHECK_OK);
- VariableProxy* proxy = NewUnresolved(name, LET, Interface::NewValue());
+ VariableMode mode = is_strong(language_mode()) ? CONST : LET;
+ VariableProxy* proxy = NewUnresolved(name, mode);
Declaration* declaration =
- factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
+ factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
Declare(declaration, true, CHECK_OK);
proxy->var()->set_initializer_position(pos);
- Token::Value init_op = Token::INIT_LET;
+ Token::Value init_op =
+ is_strong(language_mode()) ? Token::INIT_CONST : Token::INIT_LET;
Assignment* assignment = factory()->NewAssignment(init_op, proxy, value, pos);
Statement* assignment_statement =
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
@@ -2022,7 +2037,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
- if (allow_harmony_scoping() && strict_mode() == STRICT) {
+ if (allow_harmony_scoping() && is_strict(language_mode())) {
return ParseScopedBlock(labels, ok);
}
@@ -2053,7 +2068,7 @@ Block* Parser::ParseScopedBlock(ZoneList<const AstRawString*>* labels,
// The harmony mode uses block elements instead of statements.
//
// Block ::
- // '{' BlockElement* '}'
+ // '{' StatementList '}'
// Construct block expecting 16 statements.
Block* body =
@@ -2064,12 +2079,10 @@ Block* Parser::ParseScopedBlock(ZoneList<const AstRawString*>* labels,
Expect(Token::LBRACE, CHECK_OK);
block_scope->set_start_position(scanner()->location().beg_pos);
{ BlockState block_state(&scope_, block_scope);
- TargetCollector collector(zone());
- Target target(&this->target_stack_, &collector);
- Target target_body(&this->target_stack_, body);
+ Target target(&this->target_stack_, body);
while (peek() != Token::RBRACE) {
- Statement* stat = ParseBlockElement(NULL, CHECK_OK);
+ Statement* stat = ParseStatementListItem(CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat, zone());
}
@@ -2132,52 +2145,35 @@ Block* Parser::ParseVariableDeclarations(
bool is_const = false;
Token::Value init_op = Token::INIT_VAR;
if (peek() == Token::VAR) {
+ if (is_strong(language_mode())) {
+ Scanner::Location location = scanner()->peek_location();
+ ReportMessageAt(location, "strong_var");
+ *ok = false;
+ return NULL;
+ }
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
- // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
- //
- // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
- //
- // * It is a Syntax Error if the code that matches this production is not
- // contained in extended code.
- //
- // However disallowing const in sloppy mode will break compatibility with
- // existing pages. Therefore we keep allowing const with the old
- // non-harmony semantics in sloppy mode.
Consume(Token::CONST);
- switch (strict_mode()) {
- case SLOPPY:
- mode = CONST_LEGACY;
- init_op = Token::INIT_CONST_LEGACY;
- break;
- case STRICT:
- if (allow_harmony_scoping()) {
- if (var_context == kStatement) {
- // In strict mode 'const' declarations are only allowed in source
- // element positions.
- ReportMessage("unprotected_const");
- *ok = false;
- return NULL;
- }
- mode = CONST;
- init_op = Token::INIT_CONST;
- } else {
- ReportMessage("strict_const");
- *ok = false;
- return NULL;
- }
+ if (is_sloppy(language_mode())) {
+ mode = CONST_LEGACY;
+ init_op = Token::INIT_CONST_LEGACY;
+ } else {
+ DCHECK(var_context != kStatement);
+ // In ES5 const is not allowed in strict mode.
+ if (!allow_harmony_scoping()) {
+ ReportMessage("strict_const");
+ *ok = false;
+ return NULL;
+ }
+ mode = CONST;
+ init_op = Token::INIT_CONST;
}
is_const = true;
needs_init = true;
- } else if (peek() == Token::LET && strict_mode() == STRICT) {
+ } else if (peek() == Token::LET && is_strict(language_mode())) {
DCHECK(allow_harmony_scoping());
Consume(Token::LET);
- if (var_context == kStatement) {
- // Let declarations are only allowed in source element positions.
- ReportMessage("unprotected_let");
- *ok = false;
- return NULL;
- }
+ DCHECK(var_context != kStatement);
mode = LET;
needs_init = true;
init_op = Token::INIT_LET;
@@ -2234,9 +2230,7 @@ Block* Parser::ParseVariableDeclarations(
needs_init = false;
}
- Interface* interface =
- is_const ? Interface::NewConst() : Interface::NewValue();
- VariableProxy* proxy = NewUnresolved(name, mode, interface);
+ VariableProxy* proxy = NewUnresolved(name, mode);
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
Declare(declaration, mode != VAR, CHECK_OK);
@@ -2345,10 +2339,10 @@ Block* Parser::ParseVariableDeclarations(
Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
pos);
} else {
- // Add strict mode.
+ // Add language mode.
// We may want to pass singleton to avoid Literal allocations.
- StrictMode strict_mode = initialization_scope->strict_mode();
- arguments->Add(factory()->NewNumberLiteral(strict_mode, pos), zone());
+ LanguageMode language_mode = initialization_scope->language_mode();
+ arguments->Add(factory()->NewNumberLiteral(language_mode, pos), zone());
// Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not
@@ -2400,7 +2394,7 @@ Block* Parser::ParseVariableDeclarations(
// if they are inside a 'with' statement - they may change a 'with' object
// property).
VariableProxy* proxy =
- initialization_scope->NewUnresolved(factory(), name, interface);
+ initialization_scope->NewUnresolved(factory(), name);
Assignment* assignment =
factory()->NewAssignment(init_op, proxy, value, pos);
block->AddStatement(
@@ -2440,6 +2434,26 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
// ExpressionStatement | LabelledStatement ::
// Expression ';'
// Identifier ':' Statement
+ //
+ // ExpressionStatement[Yield] :
+ // [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ;
+
+ switch (peek()) {
+ case Token::FUNCTION:
+ case Token::LBRACE:
+ UNREACHABLE(); // Always handled by the callers.
+ case Token::CLASS:
+ ReportUnexpectedToken(Next());
+ *ok = false;
+ return nullptr;
+
+ // TODO(arv): Handle `let [`
+ // https://code.google.com/p/v8/issues/detail?id=3847
+
+ default:
+ break;
+ }
+
int pos = peek_position();
bool starts_with_idenfifier = peek_any_identifier();
Expression* expr = ParseExpression(true, CHECK_OK);
@@ -2484,24 +2498,16 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
return ParseNativeDeclaration(ok);
}
- // Parsed expression statement, or the context-sensitive 'module' keyword.
- // Only expect semicolon in the former case.
- // Also detect attempts at 'let' declarations in sloppy mode.
- if (!FLAG_harmony_modules || peek() != Token::IDENTIFIER ||
- scanner()->HasAnyLineTerminatorBeforeNext() ||
- expr->AsVariableProxy() == NULL ||
- expr->AsVariableProxy()->raw_name() !=
- ast_value_factory()->module_string() ||
- scanner()->literal_contains_escapes()) {
- if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
- expr->AsVariableProxy()->raw_name() ==
- ast_value_factory()->let_string()) {
- ReportMessage("sloppy_lexical", NULL);
- *ok = false;
- return NULL;
- }
- ExpectSemicolon(CHECK_OK);
+ // Parsed expression statement, followed by semicolon.
+ // Detect attempts at 'let' declarations in sloppy mode.
+ if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
+ expr->AsVariableProxy()->raw_name() ==
+ ast_value_factory()->let_string()) {
+ ReportMessage("sloppy_lexical", NULL);
+ *ok = false;
+ return NULL;
}
+ ExpectSemicolon(CHECK_OK);
return factory()->NewExpressionStatement(expr, pos);
}
@@ -2516,11 +2522,11 @@ IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::LPAREN, CHECK_OK);
Expression* condition = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- Statement* then_statement = ParseStatement(labels, CHECK_OK);
+ Statement* then_statement = ParseSubStatement(labels, CHECK_OK);
Statement* else_statement = NULL;
if (peek() == Token::ELSE) {
Next();
- else_statement = ParseStatement(labels, CHECK_OK);
+ else_statement = ParseSubStatement(labels, CHECK_OK);
} else {
else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
}
@@ -2612,11 +2618,16 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
tok == Token::SEMICOLON ||
tok == Token::RBRACE ||
tok == Token::EOS) {
- return_value = GetLiteralUndefined(position());
+ if (IsSubclassConstructor(function_state_->kind())) {
+ return_value = ThisExpression(scope_, factory(), loc.beg_pos);
+ } else {
+ return_value = GetLiteralUndefined(position());
+ }
} else {
return_value = ParseExpression(true, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
+
if (is_generator()) {
Expression* generator = factory()->NewVariableProxy(
function_state_->generator_object_variable());
@@ -2645,7 +2656,7 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::WITH, CHECK_OK);
int pos = position();
- if (strict_mode() == STRICT) {
+ if (is_strict(language_mode())) {
ReportMessage("strict_mode_with");
*ok = false;
return NULL;
@@ -2660,7 +2671,7 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
Statement* stmt;
{ BlockState block_state(&scope_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos);
- stmt = ParseStatement(labels, CHECK_OK);
+ stmt = ParseSubStatement(labels, CHECK_OK);
with_scope->set_end_position(scanner()->location().end_pos);
}
return factory()->NewWithStatement(with_scope, expr, stmt, pos);
@@ -2762,12 +2773,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::TRY, CHECK_OK);
int pos = position();
- TargetCollector try_collector(zone());
- Block* try_block;
-
- { Target target(&this->target_stack_, &try_collector);
- try_block = ParseBlock(NULL, CHECK_OK);
- }
+ Block* try_block = ParseBlock(NULL, CHECK_OK);
Token::Value tok = peek();
if (tok != Token::CATCH && tok != Token::FINALLY) {
@@ -2776,11 +2782,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
return NULL;
}
- // If we can break out from the catch block and there is a finally block,
- // then we will need to collect escaping targets from the catch
- // block. Since we don't know yet if there will be a finally block, we
- // always collect the targets.
- TargetCollector catch_collector(zone());
Scope* catch_scope = NULL;
Variable* catch_variable = NULL;
Block* catch_block = NULL;
@@ -2795,7 +2796,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::RPAREN, CHECK_OK);
- Target target(&this->target_stack_, &catch_collector);
catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized);
BlockState block_state(&scope_, catch_scope);
catch_block = ParseBlock(NULL, CHECK_OK);
@@ -2823,7 +2823,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
TryCatchStatement* statement = factory()->NewTryCatchStatement(
index, try_block, catch_scope, catch_variable, catch_block,
RelocInfo::kNoPosition);
- statement->set_escaping_targets(try_collector.targets());
try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
try_block->AddStatement(statement, zone());
catch_block = NULL; // Clear to indicate it's been handled.
@@ -2841,11 +2840,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
int index = function_state_->NextHandlerIndex();
result = factory()->NewTryFinallyStatement(
index, try_block, finally_block, pos);
- // Combine the jump targets of the try block and the possible catch block.
- try_collector.targets()->AddAll(*catch_collector.targets(), zone());
}
- result->set_escaping_targets(try_collector.targets());
return result;
}
@@ -2860,7 +2856,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(
Target target(&this->target_stack_, loop);
Expect(Token::DO, CHECK_OK);
- Statement* body = ParseStatement(NULL, CHECK_OK);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
@@ -2890,26 +2886,13 @@ WhileStatement* Parser::ParseWhileStatement(
Expect(Token::LPAREN, CHECK_OK);
Expression* cond = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- Statement* body = ParseStatement(NULL, CHECK_OK);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
if (loop != NULL) loop->Initialize(cond, body);
return loop;
}
-bool Parser::CheckInOrOf(bool accept_OF,
- ForEachStatement::VisitMode* visit_mode) {
- if (Check(Token::IN)) {
- *visit_mode = ForEachStatement::ENUMERATE;
- return true;
- } else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) {
- *visit_mode = ForEachStatement::ITERATE;
- return true;
- }
- return false;
-}
-
-
void Parser::InitializeForEachStatement(ForEachStatement* stmt,
Expression* each,
Expression* subject,
@@ -3034,8 +3017,7 @@ Statement* Parser::DesugarLetBindingsInForStatement(
// For each let variable x:
// make statement: temp_x = x.
for (int i = 0; i < names->length(); i++) {
- VariableProxy* proxy =
- NewUnresolved(names->at(i), LET, Interface::NewValue());
+ VariableProxy* proxy = NewUnresolved(names->at(i), LET);
Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
Assignment* assignment = factory()->NewAssignment(
@@ -3079,8 +3061,7 @@ Statement* Parser::DesugarLetBindingsInForStatement(
// For each let variable x:
// make statement: let x = temp_x.
for (int i = 0; i < names->length(); i++) {
- VariableProxy* proxy =
- NewUnresolved(names->at(i), LET, Interface::NewValue());
+ VariableProxy* proxy = NewUnresolved(names->at(i), LET);
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
Declare(declaration, true, CHECK_OK);
@@ -3230,8 +3211,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
bool is_let_identifier_expression = false;
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR ||
- (peek() == Token::CONST && strict_mode() == SLOPPY)) {
- bool is_const = peek() == Token::CONST;
+ (peek() == Token::CONST && is_sloppy(language_mode()))) {
const AstRawString* name = NULL;
VariableDeclarationProperties decl_props = kHasNoInitializers;
Block* variable_statement =
@@ -3241,9 +3221,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
ForEachStatement::VisitMode mode;
int each_pos = position();
- if (name != NULL && CheckInOrOf(accept_OF, &mode)) {
- Interface* interface =
- is_const ? Interface::NewConst() : Interface::NewValue();
+ if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) {
+ if (!*ok) return nullptr;
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop);
@@ -3251,9 +3230,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expression* enumerable = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- VariableProxy* each =
- scope_->NewUnresolved(factory(), name, interface, each_pos);
- Statement* body = ParseStatement(NULL, CHECK_OK);
+ VariableProxy* each = scope_->NewUnresolved(factory(), name, each_pos);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
InitializeForEachStatement(loop, each, enumerable, body);
Block* result =
factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
@@ -3269,7 +3247,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
init = variable_statement;
}
} else if ((peek() == Token::LET || peek() == Token::CONST) &&
- strict_mode() == STRICT) {
+ is_strict(language_mode())) {
bool is_const = peek() == Token::CONST;
const AstRawString* name = NULL;
VariableDeclarationProperties decl_props = kHasNoInitializers;
@@ -3281,7 +3259,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
ForEachStatement::VisitMode mode;
int each_pos = position();
- if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
+ if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
+ if (!*ok) return nullptr;
+
// Rewrite a for-in statement of the form
//
// for (let/const x in e) b
@@ -3310,9 +3290,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
scope_ = for_scope;
Expect(Token::RPAREN, CHECK_OK);
- VariableProxy* each = scope_->NewUnresolved(
- factory(), name, Interface::NewValue(), each_pos);
- Statement* body = ParseStatement(NULL, CHECK_OK);
+ VariableProxy* each = scope_->NewUnresolved(factory(), name, each_pos);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
Block* body_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN;
@@ -3344,7 +3323,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
expression->AsVariableProxy()->raw_name() ==
ast_value_factory()->let_string();
- if (CheckInOrOf(accept_OF, &mode)) {
+ if (CheckInOrOf(accept_OF, &mode, ok)) {
+ if (!*ok) return nullptr;
expression = this->CheckAndRewriteReferenceExpression(
expression, lhs_location, "invalid_lhs_in_for", CHECK_OK);
@@ -3355,7 +3335,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expression* enumerable = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- Statement* body = ParseStatement(NULL, CHECK_OK);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
InitializeForEachStatement(loop, expression, enumerable, body);
scope_ = saved_scope;
for_scope->set_end_position(scanner()->location().end_pos);
@@ -3376,7 +3356,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// Parsed initializer at this point.
// Detect attempts at 'let' declarations in sloppy mode.
- if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY &&
+ if (peek() == Token::IDENTIFIER && is_sloppy(language_mode()) &&
is_let_identifier_expression) {
ReportMessage("sloppy_lexical", NULL);
*ok = false;
@@ -3407,7 +3387,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
}
Expect(Token::RPAREN, CHECK_OK);
- Statement* body = ParseStatement(NULL, CHECK_OK);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
Statement* result = NULL;
if (let_bindings.length() > 0) {
@@ -3560,6 +3540,10 @@ int ParserTraits::DeclareArrowParametersFromExpression(
Expression* expression, Scope* scope, Scanner::Location* dupe_loc,
bool* ok) {
int num_params = 0;
+ // Always reset the flag: It only needs to be set for the first expression
+ // parsed as arrow function parameter list, becauseonly top-level functions
+ // are parsed lazily.
+ parser_->parsing_lazy_arrow_parameters_ = false;
*ok = CheckAndDeclareArrowParameter(this, expression, scope, &num_params,
dupe_loc);
return num_params;
@@ -3627,11 +3611,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Scope* original_declaration_scope = original_scope_->DeclarationScope();
Scope* scope =
function_type == FunctionLiteral::DECLARATION &&
- (!allow_harmony_scoping() || strict_mode() == SLOPPY) &&
- (original_scope_ == original_declaration_scope ||
- declaration_scope != original_declaration_scope)
- ? NewScope(declaration_scope, FUNCTION_SCOPE)
- : NewScope(scope_, FUNCTION_SCOPE);
+ (!allow_harmony_scoping() || is_sloppy(language_mode())) &&
+ (original_scope_ == original_declaration_scope ||
+ declaration_scope != original_declaration_scope)
+ ? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
+ : NewScope(scope_, FUNCTION_SCOPE, kind);
ZoneList<Statement*>* body = NULL;
int materialized_literal_count = -1;
int expected_property_count = -1;
@@ -3644,7 +3628,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Parse function body.
{
AstNodeFactory function_factory(ast_value_factory());
- FunctionState function_state(&function_state_, &scope_, scope,
+ FunctionState function_state(&function_state_, &scope_, scope, kind,
&function_factory);
scope_->SetScopeName(function_name);
@@ -3670,32 +3654,39 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// We don't yet know if the function will be strict, so we cannot yet
// produce errors for parameter names or duplicates. However, we remember
// the locations of these errors if they occur and produce the errors later.
- Scanner::Location eval_args_error_log = Scanner::Location::invalid();
+ Scanner::Location eval_args_error_loc = Scanner::Location::invalid();
Scanner::Location dupe_error_loc = Scanner::Location::invalid();
- Scanner::Location reserved_loc = Scanner::Location::invalid();
+ Scanner::Location reserved_error_loc = Scanner::Location::invalid();
+ bool is_rest = false;
bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
(peek() == Token::RPAREN &&
arity_restriction != FunctionLiteral::SETTER_ARITY);
while (!done) {
bool is_strict_reserved = false;
+ is_rest = peek() == Token::ELLIPSIS && allow_harmony_rest_params();
+ if (is_rest) {
+ Consume(Token::ELLIPSIS);
+ }
+
const AstRawString* param_name =
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
// Store locations for possible future error reports.
- if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name)) {
- eval_args_error_log = scanner()->location();
+ if (!eval_args_error_loc.IsValid() && IsEvalOrArguments(param_name)) {
+ eval_args_error_loc = scanner()->location();
}
- if (!reserved_loc.IsValid() && is_strict_reserved) {
- reserved_loc = scanner()->location();
+ if (!reserved_error_loc.IsValid() && is_strict_reserved) {
+ reserved_error_loc = scanner()->location();
}
- if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) {
+ if (!dupe_error_loc.IsValid() &&
+ scope_->IsDeclaredParameter(param_name)) {
duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
dupe_error_loc = scanner()->location();
}
- Variable* var = scope_->DeclareParameter(param_name, VAR);
- if (scope->strict_mode() == SLOPPY) {
+ Variable* var = scope_->DeclareParameter(param_name, VAR, is_rest);
+ if (is_sloppy(scope->language_mode())) {
// TODO(sigurds) Mark every parameter as maybe assigned. This is a
// conservative approximation necessary to account for parameters
// that are assigned via the arguments array.
@@ -3710,7 +3701,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
if (arity_restriction == FunctionLiteral::SETTER_ARITY) break;
done = (peek() == Token::RPAREN);
- if (!done) Expect(Token::COMMA, CHECK_OK);
+ if (!done) {
+ if (is_rest) {
+ ReportMessageAt(scanner()->peek_location(), "param_after_rest");
+ *ok = false;
+ return NULL;
+ }
+ Expect(Token::COMMA, CHECK_OK);
+ }
}
Expect(Token::RPAREN, CHECK_OK);
@@ -3725,17 +3723,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Variable* fvar = NULL;
Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
- if (allow_harmony_scoping() && strict_mode() == STRICT) {
+ if (allow_harmony_scoping() && is_strict(language_mode())) {
fvar_init_op = Token::INIT_CONST;
}
VariableMode fvar_mode =
- allow_harmony_scoping() && strict_mode() == STRICT
- ? CONST : CONST_LEGACY;
+ allow_harmony_scoping() && is_strict(language_mode()) ? CONST
+ : CONST_LEGACY;
DCHECK(function_name != NULL);
fvar = new (zone())
Variable(scope_, function_name, fvar_mode, true /* is valid LHS */,
- Variable::NORMAL, kCreatedInitialized, kNotAssigned,
- Interface::NewConst());
+ Variable::NORMAL, kCreatedInitialized, kNotAssigned);
VariableProxy* proxy = factory()->NewVariableProxy(fvar);
VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
@@ -3785,28 +3782,27 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
&expected_property_count, CHECK_OK);
} else {
body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
- is_generator, CHECK_OK);
+ kind, CHECK_OK);
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
handler_count = function_state.handler_count();
}
- // Validate strict mode.
- // Concise methods use StrictFormalParameters.
- if (strict_mode() == STRICT || IsConciseMethod(kind)) {
- CheckStrictFunctionNameAndParameters(function_name,
- name_is_strict_reserved,
- function_name_location,
- eval_args_error_log,
- dupe_error_loc,
- reserved_loc,
- CHECK_OK);
- }
- if (strict_mode() == STRICT) {
+ // Validate name and parameter names. We can do this only after parsing the
+ // function, since the function can declare itself strict.
+ CheckFunctionName(language_mode(), kind, function_name,
+ name_is_strict_reserved, function_name_location,
+ CHECK_OK);
+ const bool use_strict_params = is_rest || IsConciseMethod(kind);
+ CheckFunctionParameterNames(language_mode(), use_strict_params,
+ eval_args_error_loc, dupe_error_loc,
+ reserved_error_loc, CHECK_OK);
+
+ if (is_strict(language_mode())) {
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
CHECK_OK);
}
- if (allow_harmony_scoping() && strict_mode() == STRICT) {
+ if (allow_harmony_scoping() && is_strict(language_mode())) {
CheckConflictingVarDeclarations(scope, CHECK_OK);
}
}
@@ -3818,6 +3814,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
FunctionLiteral::kIsFunction, parenthesized, kind, pos);
function_literal->set_function_token_position(function_token_pos);
+ if (scope->has_rest_parameter()) {
+ // TODO(caitp): enable optimization of functions with rest params
+ function_literal->set_dont_optimize_reason(kRestParameter);
+ }
+
if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
return function_literal;
}
@@ -3849,7 +3850,8 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
total_preparse_skipped_ += scope_->end_position() - function_block_pos;
*materialized_literal_count = entry.literal_count();
*expected_property_count = entry.property_count();
- scope_->SetStrictMode(entry.strict_mode());
+ scope_->SetLanguageMode(entry.language_mode());
+ if (entry.uses_super_property()) scope_->RecordSuperPropertyUsage();
return;
}
cached_parse_data_->Reject();
@@ -3880,27 +3882,48 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
total_preparse_skipped_ += scope_->end_position() - function_block_pos;
*materialized_literal_count = logger.literals();
*expected_property_count = logger.properties();
- scope_->SetStrictMode(logger.strict_mode());
+ scope_->SetLanguageMode(logger.language_mode());
+ if (logger.scope_uses_super_property()) {
+ scope_->RecordSuperPropertyUsage();
+ }
if (produce_cached_parse_data()) {
DCHECK(log_);
// Position right after terminal '}'.
int body_end = scanner()->location().end_pos;
log_->LogFunction(function_block_pos, body_end, *materialized_literal_count,
- *expected_property_count, scope_->strict_mode());
+ *expected_property_count, scope_->language_mode(),
+ scope_->uses_super_property());
}
}
+void Parser::AddAssertIsConstruct(ZoneList<Statement*>* body, int pos) {
+ ZoneList<Expression*>* arguments =
+ new (zone()) ZoneList<Expression*>(0, zone());
+ CallRuntime* construct_check = factory()->NewCallRuntime(
+ ast_value_factory()->is_construct_call_string(),
+ Runtime::FunctionForId(Runtime::kInlineIsConstructCall), arguments, pos);
+ CallRuntime* non_callable_error = factory()->NewCallRuntime(
+ ast_value_factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kThrowConstructorNonCallableError),
+ arguments, pos);
+ IfStatement* if_statement = factory()->NewIfStatement(
+ factory()->NewUnaryOperation(Token::NOT, construct_check, pos),
+ factory()->NewReturnStatement(non_callable_error, pos),
+ factory()->NewEmptyStatement(pos), pos);
+ body->Add(if_statement, zone());
+}
+
+
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
const AstRawString* function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, bool is_generator, bool* ok) {
+ Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
// Everything inside an eagerly parsed function will be parsed eagerly
// (see comment above).
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8, zone());
if (fvar != NULL) {
- VariableProxy* fproxy = scope_->NewUnresolved(
- factory(), function_name, Interface::NewConst());
+ VariableProxy* fproxy = scope_->NewUnresolved(factory(), function_name);
fproxy->BindTo(fvar);
body->Add(factory()->NewExpressionStatement(
factory()->NewAssignment(fvar_init_op,
@@ -3910,8 +3933,15 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
RelocInfo::kNoPosition), zone());
}
+
+ // For concise constructors, check that they are constructed,
+ // not called.
+ if (i::IsConstructor(kind)) {
+ AddAssertIsConstruct(body, pos);
+ }
+
// For generators, allocate and yield an iterator on function entry.
- if (is_generator) {
+ if (IsGeneratorFunction(kind)) {
ZoneList<Expression*>* arguments =
new(zone()) ZoneList<Expression*>(0, zone());
CallRuntime* allocation = factory()->NewCallRuntime(
@@ -3930,9 +3960,9 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
yield, RelocInfo::kNoPosition), zone());
}
- ParseSourceElements(body, Token::RBRACE, false, false, NULL, CHECK_OK);
+ ParseStatementList(body, Token::RBRACE, false, NULL, CHECK_OK);
- if (is_generator) {
+ if (IsGeneratorFunction(kind)) {
VariableProxy* get_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
Expression* undefined =
@@ -3943,6 +3973,14 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
yield, RelocInfo::kNoPosition), zone());
}
+ if (IsSubclassConstructor(kind)) {
+ body->Add(
+ factory()->NewReturnStatement(
+ this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition),
+ zone());
+ }
+
Expect(Token::RBRACE, CHECK_OK);
scope_->set_end_position(scanner()->location().end_pos);
@@ -3960,7 +3998,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
if (reusable_preparser_ == NULL) {
- reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit_);
+ reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(),
+ NULL, stack_limit_);
reusable_preparser_->set_allow_lazy(true);
reusable_preparser_->set_allow_natives(allow_natives());
reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
@@ -3975,11 +4014,14 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
reusable_preparser_->set_allow_harmony_templates(allow_harmony_templates());
reusable_preparser_->set_allow_harmony_sloppy(allow_harmony_sloppy());
reusable_preparser_->set_allow_harmony_unicode(allow_harmony_unicode());
- }
- PreParser::PreParseResult result =
- reusable_preparser_->PreParseLazyFunction(strict_mode(),
- is_generator(),
- logger);
+ reusable_preparser_->set_allow_harmony_computed_property_names(
+ allow_harmony_computed_property_names());
+ reusable_preparser_->set_allow_harmony_rest_params(
+ allow_harmony_rest_params());
+ reusable_preparser_->set_allow_strong_mode(allow_strong_mode());
+ }
+ PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
+ language_mode(), function_state_->kind(), logger);
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Stop();
}
@@ -4005,12 +4047,13 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
BlockState block_state(&scope_, block_scope);
- scope_->SetStrictMode(STRICT);
+ scope_->SetLanguageMode(
+ static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
scope_->SetScopeName(name);
VariableProxy* proxy = NULL;
if (name != NULL) {
- proxy = NewUnresolved(name, CONST, Interface::NewConst());
+ proxy = NewUnresolved(name, CONST);
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
Declare(declaration, true, CHECK_OK);
@@ -4024,21 +4067,28 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
block_scope->set_start_position(scanner()->location().end_pos);
}
+
+ ClassLiteralChecker checker(this);
ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone());
- Expression* constructor = NULL;
+ FunctionLiteral* constructor = NULL;
bool has_seen_constructor = false;
Expect(Token::LBRACE, CHECK_OK);
+ const bool has_extends = extends != nullptr;
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
if (fni_ != NULL) fni_->Enter();
const bool in_class = true;
const bool is_static = false;
+ bool is_computed_name = false; // Classes do not care about computed
+ // property names here.
ObjectLiteral::Property* property = ParsePropertyDefinition(
- NULL, in_class, is_static, &has_seen_constructor, CHECK_OK);
+ &checker, in_class, has_extends, is_static, &is_computed_name,
+ &has_seen_constructor, CHECK_OK);
if (has_seen_constructor && constructor == NULL) {
- constructor = GetPropertyValue(property);
+ constructor = GetPropertyValue(property)->AsFunctionLiteral();
+ DCHECK_NOT_NULL(constructor);
} else {
properties->Add(property, zone());
}
@@ -4153,9 +4203,7 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
bool Parser::TargetStackContainsLabel(const AstRawString* label) {
for (Target* t = target_stack_; t != NULL; t = t->previous()) {
- BreakableStatement* stat = t->node()->AsBreakableStatement();
- if (stat != NULL && ContainsLabel(stat->labels(), label))
- return true;
+ if (ContainsLabel(t->statement()->labels(), label)) return true;
}
return false;
}
@@ -4165,11 +4213,9 @@ BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label,
bool* ok) {
bool anonymous = label == NULL;
for (Target* t = target_stack_; t != NULL; t = t->previous()) {
- BreakableStatement* stat = t->node()->AsBreakableStatement();
- if (stat == NULL) continue;
+ BreakableStatement* stat = t->statement();
if ((anonymous && stat->is_target_for_anonymous()) ||
(!anonymous && ContainsLabel(stat->labels(), label))) {
- RegisterTargetUse(stat->break_target(), t->previous());
return stat;
}
}
@@ -4181,12 +4227,11 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
bool* ok) {
bool anonymous = label == NULL;
for (Target* t = target_stack_; t != NULL; t = t->previous()) {
- IterationStatement* stat = t->node()->AsIterationStatement();
+ IterationStatement* stat = t->statement()->AsIterationStatement();
if (stat == NULL) continue;
DCHECK(stat->is_target_for_anonymous());
if (anonymous || ContainsLabel(stat->labels(), label)) {
- RegisterTargetUse(stat->continue_target(), t->previous());
return stat;
}
}
@@ -4194,36 +4239,26 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
}
-void Parser::RegisterTargetUse(Label* target, Target* stop) {
- // Register that a break target found at the given stop in the
- // target stack has been used from the top of the target stack. Add
- // the break target to any TargetCollectors passed on the stack.
- for (Target* t = target_stack_; t != stop; t = t->previous()) {
- TargetCollector* collector = t->node()->AsTargetCollector();
- if (collector != NULL) collector->AddTarget(target, zone());
- }
-}
-
-
-void Parser::HandleSourceURLComments() {
+void Parser::HandleSourceURLComments(CompilationInfo* info) {
if (scanner_.source_url()->length() > 0) {
- Handle<String> source_url = scanner_.source_url()->Internalize(isolate());
- info_->script()->set_source_url(*source_url);
+ Handle<String> source_url =
+ scanner_.source_url()->Internalize(info->isolate());
+ info->script()->set_source_url(*source_url);
}
if (scanner_.source_mapping_url()->length() > 0) {
Handle<String> source_mapping_url =
- scanner_.source_mapping_url()->Internalize(isolate());
- info_->script()->set_source_mapping_url(*source_mapping_url);
+ scanner_.source_mapping_url()->Internalize(info->isolate());
+ info->script()->set_source_mapping_url(*source_mapping_url);
}
}
-void Parser::ThrowPendingError() {
+void Parser::ThrowPendingError(Isolate* isolate, Handle<Script> script) {
DCHECK(ast_value_factory()->IsInternalized());
if (has_pending_error_) {
- MessageLocation location(script(), pending_error_location_.beg_pos,
+ MessageLocation location(script, pending_error_location_.beg_pos,
pending_error_location_.end_pos);
- Factory* factory = isolate()->factory();
+ Factory* factory = isolate->factory();
bool has_arg =
pending_error_arg_ != NULL || pending_error_char_arg_ != NULL;
Handle<FixedArray> elements = factory->NewFixedArray(has_arg ? 1 : 0);
@@ -4236,7 +4271,7 @@ void Parser::ThrowPendingError() {
.ToHandleChecked();
elements->set(0, *arg_string);
}
- isolate()->debug()->OnCompileError(script());
+ isolate->debug()->OnCompileError(script);
Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
Handle<Object> error;
@@ -4244,21 +4279,39 @@ void Parser::ThrowPendingError() {
pending_error_is_reference_error_
? factory->NewReferenceError(pending_error_message_, array)
: factory->NewSyntaxError(pending_error_message_, array);
- if (maybe_error.ToHandle(&error)) isolate()->Throw(*error, &location);
+
+ if (maybe_error.ToHandle(&error)) {
+ Handle<JSObject> jserror = Handle<JSObject>::cast(error);
+
+ Handle<Name> key_start_pos = factory->error_start_pos_symbol();
+ JSObject::SetProperty(jserror, key_start_pos,
+ handle(Smi::FromInt(location.start_pos()), isolate),
+ SLOPPY).Check();
+
+ Handle<Name> key_end_pos = factory->error_end_pos_symbol();
+ JSObject::SetProperty(jserror, key_end_pos,
+ handle(Smi::FromInt(location.end_pos()), isolate),
+ SLOPPY).Check();
+
+ Handle<Name> key_script = factory->error_script_symbol();
+ JSObject::SetProperty(jserror, key_script, script, SLOPPY).Check();
+
+ isolate->Throw(*error, &location);
+ }
}
}
-void Parser::Internalize() {
+void Parser::Internalize(CompilationInfo* info) {
// Internalize strings.
- ast_value_factory()->Internalize(isolate());
+ ast_value_factory()->Internalize(info->isolate());
// Error processing.
- if (info()->function() == NULL) {
+ if (info->function() == NULL) {
if (stack_overflow()) {
- isolate()->StackOverflow();
+ info->isolate()->StackOverflow();
} else {
- ThrowPendingError();
+ ThrowPendingError(info->isolate(), info->script());
}
}
@@ -4266,10 +4319,10 @@ void Parser::Internalize() {
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
for (int i = 0; i < use_counts_[feature]; ++i) {
- isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature));
+ info->isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature));
}
}
- isolate()->counters()->total_preparse_skipped()->Increment(
+ info->isolate()->counters()->total_preparse_skipped()->Increment(
total_preparse_skipped_);
}
@@ -4278,11 +4331,10 @@ void Parser::Internalize() {
// Regular expressions
-RegExpParser::RegExpParser(FlatStringReader* in,
- Handle<String>* error,
- bool multiline,
+RegExpParser::RegExpParser(FlatStringReader* in, Handle<String>* error,
+ bool multiline, bool unicode, Isolate* isolate,
Zone* zone)
- : isolate_(zone->isolate()),
+ : isolate_(isolate),
zone_(zone),
error_(error),
captures_(NULL),
@@ -4292,6 +4344,7 @@ RegExpParser::RegExpParser(FlatStringReader* in,
capture_count_(0),
has_more_(true),
multiline_(multiline),
+ unicode_(unicode),
simple_(false),
contains_anchor_(false),
is_scanned_for_captures_(false),
@@ -4348,6 +4401,13 @@ bool RegExpParser::simple() {
}
+bool RegExpParser::IsSyntaxCharacter(uc32 c) {
+ return c == '^' || c == '$' || c == '\\' || c == '.' || c == '*' ||
+ c == '+' || c == '?' || c == '(' || c == ')' || c == '[' || c == ']' ||
+ c == '{' || c == '}' || c == '|';
+}
+
+
RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
failed_ = true;
*error_ = isolate()->factory()->NewStringFromAscii(message).ToHandleChecked();
@@ -4564,9 +4624,15 @@ RegExpTree* RegExpParser::ParseDisjunction() {
}
uc32 first_digit = Next();
if (first_digit == '8' || first_digit == '9') {
- // Treat as identity escape
- builder->AddCharacter(first_digit);
- Advance(2);
+ // If the 'u' flag is present, only syntax characters can be escaped,
+ // no other identity escapes are allowed. If the 'u' flag is not
+ // present, all identity escapes are allowed.
+ if (!FLAG_harmony_unicode_regexps || !unicode_) {
+ builder->AddCharacter(first_digit);
+ Advance(2);
+ } else {
+ return ReportError(CStrVector("Invalid escape"));
+ }
break;
}
}
@@ -4622,25 +4688,41 @@ RegExpTree* RegExpParser::ParseDisjunction() {
uc32 value;
if (ParseHexEscape(2, &value)) {
builder->AddCharacter(value);
- } else {
+ } else if (!FLAG_harmony_unicode_regexps || !unicode_) {
builder->AddCharacter('x');
+ } else {
+ // If the 'u' flag is present, invalid escapes are not treated as
+ // identity escapes.
+ return ReportError(CStrVector("Invalid escape"));
}
break;
}
case 'u': {
Advance(2);
uc32 value;
- if (ParseHexEscape(4, &value)) {
+ if (ParseUnicodeEscape(&value)) {
builder->AddCharacter(value);
- } else {
+ } else if (!FLAG_harmony_unicode_regexps || !unicode_) {
builder->AddCharacter('u');
+ } else {
+ // If the 'u' flag is present, invalid escapes are not treated as
+ // identity escapes.
+ return ReportError(CStrVector("Invalid unicode escape"));
}
break;
}
default:
- // Identity escape.
- builder->AddCharacter(Next());
- Advance(2);
+ Advance();
+ // If the 'u' flag is present, only syntax characters can be escaped, no
+ // other identity escapes are allowed. If the 'u' flag is not present,
+ // all identity escapes are allowed.
+ if (!FLAG_harmony_unicode_regexps || !unicode_ ||
+ IsSyntaxCharacter(current())) {
+ builder->AddCharacter(current());
+ Advance();
+ } else {
+ return ReportError(CStrVector("Invalid escape"));
+ }
break;
}
break;
@@ -4883,11 +4965,10 @@ uc32 RegExpParser::ParseOctalLiteral() {
}
-bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
+bool RegExpParser::ParseHexEscape(int length, uc32* value) {
int start = position();
uc32 val = 0;
- bool done = false;
- for (int i = 0; !done; i++) {
+ for (int i = 0; i < length; ++i) {
uc32 c = current();
int d = HexValue(c);
if (d < 0) {
@@ -4896,15 +4977,52 @@ bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
}
val = val * 16 + d;
Advance();
- if (i == length - 1) {
- done = true;
- }
}
*value = val;
return true;
}
+bool RegExpParser::ParseUnicodeEscape(uc32* value) {
+ // Accept both \uxxxx and \u{xxxxxx} (if harmony unicode escapes are
+ // allowed). In the latter case, the number of hex digits between { } is
+ // arbitrary. \ and u have already been read.
+ if (current() == '{' && FLAG_harmony_unicode_regexps && unicode_) {
+ int start = position();
+ Advance();
+ if (ParseUnlimitedLengthHexNumber(0x10ffff, value)) {
+ if (current() == '}') {
+ Advance();
+ return true;
+ }
+ }
+ Reset(start);
+ return false;
+ }
+ // \u but no {, or \u{...} escapes not allowed.
+ return ParseHexEscape(4, value);
+}
+
+
+bool RegExpParser::ParseUnlimitedLengthHexNumber(int max_value, uc32* value) {
+ uc32 x = 0;
+ int d = HexValue(current());
+ if (d < 0) {
+ return false;
+ }
+ while (d >= 0) {
+ x = x * 16 + d;
+ if (x > max_value) {
+ return false;
+ }
+ Advance();
+ d = HexValue(current());
+ }
+ *value = x;
+ return true;
+}
+
+
uc32 RegExpParser::ParseClassCharacterEscape() {
DCHECK(current() == '\\');
DCHECK(has_next() && !IsSpecialClassEscape(Next()));
@@ -4959,27 +5077,42 @@ uc32 RegExpParser::ParseClassCharacterEscape() {
if (ParseHexEscape(2, &value)) {
return value;
}
- // If \x is not followed by a two-digit hexadecimal, treat it
- // as an identity escape.
- return 'x';
+ if (!FLAG_harmony_unicode_regexps || !unicode_) {
+ // If \x is not followed by a two-digit hexadecimal, treat it
+ // as an identity escape.
+ return 'x';
+ }
+ // If the 'u' flag is present, invalid escapes are not treated as
+ // identity escapes.
+ ReportError(CStrVector("Invalid escape"));
+ return 0;
}
case 'u': {
Advance();
uc32 value;
- if (ParseHexEscape(4, &value)) {
+ if (ParseUnicodeEscape(&value)) {
return value;
}
- // If \u is not followed by a four-digit hexadecimal, treat it
- // as an identity escape.
- return 'u';
+ if (!FLAG_harmony_unicode_regexps || !unicode_) {
+ return 'u';
+ }
+ // If the 'u' flag is present, invalid escapes are not treated as
+ // identity escapes.
+ ReportError(CStrVector("Invalid unicode escape"));
+ return 0;
}
default: {
- // Extended identity escape. We accept any character that hasn't
- // been matched by a more specific case, not just the subset required
- // by the ECMAScript specification.
uc32 result = current();
- Advance();
- return result;
+ // If the 'u' flag is present, only syntax characters can be escaped, no
+ // other identity escapes are allowed. If the 'u' flag is not present, all
+ // identity escapes are allowed.
+ if (!FLAG_harmony_unicode_regexps || !unicode_ ||
+ IsSyntaxCharacter(result)) {
+ Advance();
+ return result;
+ }
+ ReportError(CStrVector("Invalid escape"));
+ return 0;
}
}
return 0;
@@ -5085,12 +5218,11 @@ RegExpTree* RegExpParser::ParseCharacterClass() {
// ----------------------------------------------------------------------------
// The Parser interface.
-bool RegExpParser::ParseRegExp(FlatStringReader* input,
- bool multiline,
- RegExpCompileData* result,
- Zone* zone) {
+bool RegExpParser::ParseRegExp(Isolate* isolate, Zone* zone,
+ FlatStringReader* input, bool multiline,
+ bool unicode, RegExpCompileData* result) {
DCHECK(result != NULL);
- RegExpParser parser(input, &result->error, multiline, zone);
+ RegExpParser parser(input, &result->error, multiline, unicode, isolate, zone);
RegExpTree* tree = parser.ParsePattern();
if (parser.failed()) {
DCHECK(tree == NULL);
@@ -5108,49 +5240,67 @@ bool RegExpParser::ParseRegExp(FlatStringReader* input,
}
-bool Parser::Parse() {
- DCHECK(info()->function() == NULL);
+bool Parser::ParseStatic(CompilationInfo* info, bool allow_lazy) {
+ Parser parser(info, info->isolate()->stack_guard()->real_climit(),
+ info->isolate()->heap()->HashSeed(),
+ info->isolate()->unicode_cache());
+ parser.set_allow_lazy(allow_lazy);
+ if (parser.Parse(info)) {
+ info->SetLanguageMode(info->function()->language_mode());
+ return true;
+ }
+ return false;
+}
+
+
+bool Parser::Parse(CompilationInfo* info) {
+ DCHECK(info->function() == NULL);
FunctionLiteral* result = NULL;
- pre_parse_timer_ = isolate()->counters()->pre_parse();
+ // Ok to use Isolate here; this function is only called in the main thread.
+ DCHECK(parsing_on_main_thread_);
+ Isolate* isolate = info->isolate();
+ pre_parse_timer_ = isolate->counters()->pre_parse();
if (FLAG_trace_parse || allow_natives() || extension_ != NULL) {
// If intrinsics are allowed, the Parser cannot operate independent of the
// V8 heap because of Runtime. Tell the string table to internalize strings
// and values right after they're created.
- ast_value_factory()->Internalize(isolate());
+ ast_value_factory()->Internalize(isolate);
}
- if (info()->is_lazy()) {
- DCHECK(!info()->is_eval());
- if (info()->shared_info()->is_function()) {
- result = ParseLazy();
+ if (info->is_lazy()) {
+ DCHECK(!info->is_eval());
+ if (info->shared_info()->is_function()) {
+ result = ParseLazy(info);
} else {
- result = ParseProgram();
+ result = ParseProgram(info);
}
} else {
- SetCachedData();
- result = ParseProgram();
+ SetCachedData(info);
+ result = ParseProgram(info);
}
- info()->SetFunction(result);
+ info->SetFunction(result);
- Internalize();
+ Internalize(info);
DCHECK(ast_value_factory()->IsInternalized());
return (result != NULL);
}
-void Parser::ParseOnBackground() {
- DCHECK(info()->function() == NULL);
+void Parser::ParseOnBackground(CompilationInfo* info) {
+ parsing_on_main_thread_ = false;
+
+ DCHECK(info->function() == NULL);
FunctionLiteral* result = NULL;
fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
CompleteParserRecorder recorder;
if (produce_cached_parse_data()) log_ = &recorder;
- DCHECK(info()->source_stream() != NULL);
- ExternalStreamingStream stream(info()->source_stream(),
- info()->source_stream_encoding());
+ DCHECK(info->source_stream() != NULL);
+ ExternalStreamingStream stream(info->source_stream(),
+ info->source_stream_encoding());
scanner_.Initialize(&stream);
- DCHECK(info()->context().is_null() || info()->context()->IsNativeContext());
+ DCHECK(info->context().is_null() || info->context()->IsNativeContext());
// When streaming, we don't know the length of the source until we have parsed
// it. The raw data can be UTF-8, so we wouldn't know the source length until
@@ -5160,20 +5310,20 @@ void Parser::ParseOnBackground() {
// scopes) and set their end position after we know the script length.
Scope* top_scope = NULL;
Scope* eval_scope = NULL;
- result = DoParseProgram(info(), &top_scope, &eval_scope);
+ result = DoParseProgram(info, &top_scope, &eval_scope);
top_scope->set_end_position(scanner()->location().end_pos);
if (eval_scope != NULL) {
eval_scope->set_end_position(scanner()->location().end_pos);
}
- info()->SetFunction(result);
+ info->SetFunction(result);
// We cannot internalize on a background thread; a foreground task will take
// care of calling Parser::Internalize just before compilation.
if (produce_cached_parse_data()) {
- if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
+ if (result != NULL) *info->cached_data() = recorder.GetScriptData();
log_ = NULL;
}
}