Commit cb0d1468 authored by wingo@igalia.com's avatar wingo@igalia.com

Add initial parser support for harmony iteration

This commit adds initial parser support for harmony iteration.
Specifically, it will parse:

  for (x of y) {}
  for (let x of y) {}
  for (var x of y) {}

The semantics are still unimplemented.

TEST=mjsunit/harmony/for-of-syntax
BUG=v8:2214
R=rossberg@chromium.org

Review URL: https://codereview.chromium.org/15300018

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14984 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1b4cb2aa
...@@ -1156,6 +1156,7 @@ DONT_SELFOPTIMIZE_NODE(DoWhileStatement) ...@@ -1156,6 +1156,7 @@ DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
DONT_SELFOPTIMIZE_NODE(WhileStatement) DONT_SELFOPTIMIZE_NODE(WhileStatement)
DONT_SELFOPTIMIZE_NODE(ForStatement) DONT_SELFOPTIMIZE_NODE(ForStatement)
DONT_SELFOPTIMIZE_NODE(ForInStatement) DONT_SELFOPTIMIZE_NODE(ForInStatement)
DONT_SELFOPTIMIZE_NODE(ForOfStatement)
DONT_CACHE_NODE(ModuleLiteral) DONT_CACHE_NODE(ModuleLiteral)
......
...@@ -90,6 +90,7 @@ namespace internal { ...@@ -90,6 +90,7 @@ namespace internal {
V(WhileStatement) \ V(WhileStatement) \
V(ForStatement) \ V(ForStatement) \
V(ForInStatement) \ V(ForInStatement) \
V(ForOfStatement) \
V(TryCatchStatement) \ V(TryCatchStatement) \
V(TryFinallyStatement) \ V(TryFinallyStatement) \
V(DebuggerStatement) V(DebuggerStatement)
...@@ -874,47 +875,79 @@ class ForStatement: public IterationStatement { ...@@ -874,47 +875,79 @@ class ForStatement: public IterationStatement {
}; };
class ForInStatement: public IterationStatement { class ForEachStatement: public IterationStatement {
public: public:
DECLARE_NODE_TYPE(ForInStatement) enum VisitMode {
ENUMERATE, // for (each in subject) body;
ITERATE // for (each of subject) body;
};
void Initialize(Expression* each, Expression* enumerable, Statement* body) { void Initialize(Expression* each, Expression* subject, Statement* body) {
IterationStatement::Initialize(body); IterationStatement::Initialize(body);
each_ = each; each_ = each;
enumerable_ = enumerable; subject_ = subject;
for_in_type_ = SLOW_FOR_IN;
} }
Expression* each() const { return each_; } Expression* each() const { return each_; }
Expression* enumerable() const { return enumerable_; } Expression* subject() const { return subject_; }
virtual BailoutId ContinueId() const { return EntryId(); } virtual BailoutId ContinueId() const { return EntryId(); }
virtual BailoutId StackCheckId() const { return body_id_; } virtual BailoutId StackCheckId() const { return body_id_; }
BailoutId BodyId() const { return body_id_; } BailoutId BodyId() const { return body_id_; }
BailoutId PrepareId() const { return prepare_id_; } BailoutId PrepareId() const { return prepare_id_; }
TypeFeedbackId ForInFeedbackId() const { return reuse(PrepareId()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
enum ForInType { FAST_FOR_IN, SLOW_FOR_IN };
ForInType for_in_type() const { return for_in_type_; }
protected: protected:
ForInStatement(Isolate* isolate, ZoneStringList* labels) ForEachStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(isolate, labels), : IterationStatement(isolate, labels),
each_(NULL), each_(NULL),
enumerable_(NULL), subject_(NULL),
body_id_(GetNextId(isolate)), body_id_(GetNextId(isolate)),
prepare_id_(GetNextId(isolate)) { prepare_id_(GetNextId(isolate)) {
} }
private: private:
Expression* each_; Expression* each_;
Expression* enumerable_; Expression* subject_;
const BailoutId body_id_;
const BailoutId prepare_id_;
};
class ForInStatement: public ForEachStatement {
public:
DECLARE_NODE_TYPE(ForInStatement)
Expression* enumerable() const {
return subject();
}
TypeFeedbackId ForInFeedbackId() const { return reuse(PrepareId()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
enum ForInType { FAST_FOR_IN, SLOW_FOR_IN };
ForInType for_in_type() const { return for_in_type_; }
protected:
ForInStatement(Isolate* isolate, ZoneStringList* labels)
: ForEachStatement(isolate, labels),
for_in_type_(SLOW_FOR_IN) {
}
ForInType for_in_type_; ForInType for_in_type_;
};
const BailoutId body_id_;
const BailoutId prepare_id_; class ForOfStatement: public ForEachStatement {
public:
DECLARE_NODE_TYPE(ForOfStatement)
Expression* iterable() const {
return subject();
}
protected:
ForOfStatement(Isolate* isolate, ZoneStringList* labels)
: ForEachStatement(isolate, labels) {
}
}; };
...@@ -2853,10 +2886,25 @@ class AstNodeFactory BASE_EMBEDDED { ...@@ -2853,10 +2886,25 @@ class AstNodeFactory BASE_EMBEDDED {
STATEMENT_WITH_LABELS(DoWhileStatement) STATEMENT_WITH_LABELS(DoWhileStatement)
STATEMENT_WITH_LABELS(WhileStatement) STATEMENT_WITH_LABELS(WhileStatement)
STATEMENT_WITH_LABELS(ForStatement) STATEMENT_WITH_LABELS(ForStatement)
STATEMENT_WITH_LABELS(ForInStatement)
STATEMENT_WITH_LABELS(SwitchStatement) STATEMENT_WITH_LABELS(SwitchStatement)
#undef STATEMENT_WITH_LABELS #undef STATEMENT_WITH_LABELS
ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode,
ZoneStringList* labels) {
switch (visit_mode) {
case ForEachStatement::ENUMERATE: {
ForInStatement* stmt = new(zone_) ForInStatement(isolate_, labels);
VISIT_AND_RETURN(ForInStatement, stmt);
}
case ForEachStatement::ITERATE: {
ForOfStatement* stmt = new(zone_) ForOfStatement(isolate_, labels);
VISIT_AND_RETURN(ForOfStatement, stmt);
}
}
UNREACHABLE();
return NULL;
}
ModuleStatement* NewModuleStatement(VariableProxy* proxy, Block* body) { ModuleStatement* NewModuleStatement(VariableProxy* proxy, Block* body) {
ModuleStatement* stmt = new(zone_) ModuleStatement(proxy, body); ModuleStatement* stmt = new(zone_) ModuleStatement(proxy, body);
VISIT_AND_RETURN(ModuleStatement, stmt) VISIT_AND_RETURN(ModuleStatement, stmt)
......
...@@ -170,6 +170,7 @@ DEFINE_bool(harmony_array_buffer, false, ...@@ -170,6 +170,7 @@ DEFINE_bool(harmony_array_buffer, false,
"enable harmony array buffer") "enable harmony array buffer")
DEFINE_implication(harmony_typed_arrays, harmony_array_buffer) DEFINE_implication(harmony_typed_arrays, harmony_array_buffer)
DEFINE_bool(harmony_generators, false, "enable harmony generators") DEFINE_bool(harmony_generators, false, "enable harmony generators")
DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)")
DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_bool(harmony, false, "enable all harmony features (except typeof)")
DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_scoping)
DEFINE_implication(harmony, harmony_modules) DEFINE_implication(harmony, harmony_modules)
...@@ -178,6 +179,7 @@ DEFINE_implication(harmony, harmony_proxies) ...@@ -178,6 +179,7 @@ DEFINE_implication(harmony, harmony_proxies)
DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony, harmony_collections)
DEFINE_implication(harmony, harmony_observation) DEFINE_implication(harmony, harmony_observation)
DEFINE_implication(harmony, harmony_generators) DEFINE_implication(harmony, harmony_generators)
DEFINE_implication(harmony, harmony_iteration)
DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_observation, harmony_collections) DEFINE_implication(harmony_observation, harmony_collections)
// TODO[dslomov] add harmony => harmony_typed_arrays // TODO[dslomov] add harmony => harmony_typed_arrays
......
...@@ -163,6 +163,12 @@ void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) { ...@@ -163,6 +163,12 @@ void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
} }
void BreakableStatementChecker::VisitForOfStatement(ForOfStatement* stmt) {
// Mark for in statements breakable if the iterable expression is.
Visit(stmt->iterable());
}
void BreakableStatementChecker::VisitTryCatchStatement( void BreakableStatementChecker::VisitTryCatchStatement(
TryCatchStatement* stmt) { TryCatchStatement* stmt) {
// Mark try catch as breakable to avoid adding a break slot in front of it. // Mark try catch as breakable to avoid adding a break slot in front of it.
...@@ -1383,6 +1389,11 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { ...@@ -1383,6 +1389,11 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
} }
void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
// TODO(wingo): Implement.
}
void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
Comment cmnt(masm_, "[ TryCatchStatement"); Comment cmnt(masm_, "[ TryCatchStatement");
SetStatementPosition(stmt); SetStatementPosition(stmt);
......
...@@ -5447,6 +5447,14 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { ...@@ -5447,6 +5447,14 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
} }
void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
return Bailout("ForOfStatement");
}
void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
......
...@@ -549,6 +549,7 @@ Parser::Parser(CompilationInfo* info) ...@@ -549,6 +549,7 @@ Parser::Parser(CompilationInfo* info)
allow_natives_syntax_(false), allow_natives_syntax_(false),
allow_lazy_(false), allow_lazy_(false),
allow_generators_(false), allow_generators_(false),
allow_for_of_(false),
stack_overflow_(false), stack_overflow_(false),
parenthesized_function_(false), parenthesized_function_(false),
zone_(info->zone()), zone_(info->zone()),
...@@ -560,6 +561,7 @@ Parser::Parser(CompilationInfo* info) ...@@ -560,6 +561,7 @@ Parser::Parser(CompilationInfo* info)
set_allow_natives_syntax(FLAG_allow_natives_syntax || info->is_native()); set_allow_natives_syntax(FLAG_allow_natives_syntax || info->is_native());
set_allow_lazy(false); // Must be explicitly enabled. set_allow_lazy(false); // Must be explicitly enabled.
set_allow_generators(FLAG_harmony_generators); set_allow_generators(FLAG_harmony_generators);
set_allow_for_of(FLAG_harmony_iteration);
} }
...@@ -1028,7 +1030,7 @@ Module* Parser::ParseModule(bool* ok) { ...@@ -1028,7 +1030,7 @@ Module* Parser::ParseModule(bool* ok) {
} }
default: { default: {
ExpectContextualKeyword("at", CHECK_OK); ExpectContextualKeyword(CStrVector("at"), CHECK_OK);
Module* result = ParseModuleUrl(CHECK_OK); Module* result = ParseModuleUrl(CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return result; return result;
...@@ -1200,7 +1202,7 @@ Block* Parser::ParseImportDeclaration(bool* ok) { ...@@ -1200,7 +1202,7 @@ Block* Parser::ParseImportDeclaration(bool* ok) {
names.Add(name, zone()); names.Add(name, zone());
} }
ExpectContextualKeyword("from", CHECK_OK); ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
Module* module = ParseModuleSpecifier(CHECK_OK); Module* module = ParseModuleSpecifier(CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
...@@ -2622,6 +2624,18 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { ...@@ -2622,6 +2624,18 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
} }
bool Parser::CheckInOrOf(ForEachStatement::VisitMode* visit_mode) {
if (Check(Token::IN)) {
*visit_mode = ForEachStatement::ENUMERATE;
return true;
} else if (allow_for_of() && CheckContextualKeyword(CStrVector("of"))) {
*visit_mode = ForEachStatement::ITERATE;
return true;
}
return false;
}
Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
// ForStatement :: // ForStatement ::
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
...@@ -2642,14 +2656,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2642,14 +2656,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Handle<String> name; Handle<String> name;
Block* variable_statement = Block* variable_statement =
ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK); ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK);
ForEachStatement::VisitMode mode;
if (peek() == Token::IN && !name.is_null()) { if (!name.is_null() && CheckInOrOf(&mode)) {
Interface* interface = Interface* interface =
is_const ? Interface::NewConst() : Interface::NewValue(); is_const ? Interface::NewConst() : Interface::NewValue();
ForInStatement* loop = factory()->NewForInStatement(labels); ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
Expect(Token::IN, CHECK_OK);
Expression* enumerable = ParseExpression(true, CHECK_OK); Expression* enumerable = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
...@@ -2676,7 +2690,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2676,7 +2690,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
CHECK_OK); CHECK_OK);
bool accept_IN = !name.is_null() && decl_props != kHasInitializers; bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
if (peek() == Token::IN && accept_IN) { ForEachStatement::VisitMode mode;
if (accept_IN && CheckInOrOf(&mode)) {
// Rewrite a for-in statement of the form // Rewrite a for-in statement of the form
// //
// for (let x in e) b // for (let x in e) b
...@@ -2698,11 +2714,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2698,11 +2714,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Handle<String> tempname = heap_factory->InternalizeString(tempstr); Handle<String> tempname = heap_factory->InternalizeString(tempstr);
Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname); Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
ForInStatement* loop = factory()->NewForInStatement(labels); ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
// The expression does not see the loop variable. // The expression does not see the loop variable.
Expect(Token::IN, CHECK_OK);
top_scope_ = saved_scope; top_scope_ = saved_scope;
Expression* enumerable = ParseExpression(true, CHECK_OK); Expression* enumerable = ParseExpression(true, CHECK_OK);
top_scope_ = for_scope; top_scope_ = for_scope;
...@@ -2732,7 +2747,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2732,7 +2747,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
} }
} else { } else {
Expression* expression = ParseExpression(false, CHECK_OK); Expression* expression = ParseExpression(false, CHECK_OK);
if (peek() == Token::IN) { ForEachStatement::VisitMode mode;
if (CheckInOrOf(&mode)) {
// Signal a reference error if the expression is an invalid // Signal a reference error if the expression is an invalid
// left-hand side expression. We could report this as a syntax // left-hand side expression. We could report this as a syntax
// error here but for compatibility with JSC we choose to report // error here but for compatibility with JSC we choose to report
...@@ -2742,15 +2759,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2742,15 +2759,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
isolate()->factory()->invalid_lhs_in_for_in_string(); isolate()->factory()->invalid_lhs_in_for_in_string();
expression = NewThrowReferenceError(message); expression = NewThrowReferenceError(message);
} }
ForInStatement* loop = factory()->NewForInStatement(labels); ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
Expect(Token::IN, CHECK_OK);
Expression* enumerable = ParseExpression(true, CHECK_OK); Expression* enumerable = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseStatement(NULL, CHECK_OK);
if (loop) loop->Initialize(expression, enumerable, body); loop->Initialize(expression, enumerable, body);
top_scope_ = saved_scope; top_scope_ = saved_scope;
for_scope->set_end_position(scanner().location().end_pos); for_scope->set_end_position(scanner().location().end_pos);
for_scope = for_scope->FinalizeBlockScope(); for_scope = for_scope->FinalizeBlockScope();
...@@ -2804,10 +2820,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2804,10 +2820,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
result->AddStatement(init, zone()); result->AddStatement(init, zone());
result->AddStatement(loop, zone()); result->AddStatement(loop, zone());
result->set_scope(for_scope); result->set_scope(for_scope);
if (loop) loop->Initialize(NULL, cond, next, body); loop->Initialize(NULL, cond, next, body);
return result; return result;
} else { } else {
if (loop) loop->Initialize(init, cond, next, body); loop->Initialize(init, cond, next, body);
return loop; return loop;
} }
} }
...@@ -4511,6 +4527,7 @@ preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral( ...@@ -4511,6 +4527,7 @@ preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax()); reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
reusable_preparser_->set_allow_lazy(true); reusable_preparser_->set_allow_lazy(true);
reusable_preparser_->set_allow_generators(allow_generators()); reusable_preparser_->set_allow_generators(allow_generators());
reusable_preparser_->set_allow_for_of(allow_for_of());
} }
preparser::PreParser::PreParseResult result = preparser::PreParser::PreParseResult result =
reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(), reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
...@@ -4608,6 +4625,16 @@ bool Parser::Check(Token::Value token) { ...@@ -4608,6 +4625,16 @@ bool Parser::Check(Token::Value token) {
} }
bool Parser::CheckContextualKeyword(Vector<const char> keyword) {
if (peek() == Token::IDENTIFIER &&
scanner().is_next_contextual_keyword(keyword)) {
Consume(Token::IDENTIFIER);
return true;
}
return false;
}
void Parser::ExpectSemicolon(bool* ok) { void Parser::ExpectSemicolon(bool* ok) {
// Check for automatic semicolon insertion according to // Check for automatic semicolon insertion according to
// the rules given in ECMA-262, section 7.9, page 21. // the rules given in ECMA-262, section 7.9, page 21.
...@@ -4625,12 +4652,10 @@ void Parser::ExpectSemicolon(bool* ok) { ...@@ -4625,12 +4652,10 @@ void Parser::ExpectSemicolon(bool* ok) {
} }
void Parser::ExpectContextualKeyword(const char* keyword, bool* ok) { void Parser::ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
Expect(Token::IDENTIFIER, ok); Expect(Token::IDENTIFIER, ok);
if (!*ok) return; if (!*ok) return;
Handle<String> symbol = GetSymbol(); if (!scanner().is_literal_contextual_keyword(keyword)) {
if (!*ok) return;
if (!symbol->IsUtf8EqualTo(CStrVector(keyword))) {
*ok = false; *ok = false;
ReportUnexpectedToken(scanner().current_token()); ReportUnexpectedToken(scanner().current_token());
} }
...@@ -5768,6 +5793,7 @@ ScriptDataImpl* PreParserApi::PreParse(Utf16CharacterStream* source) { ...@@ -5768,6 +5793,7 @@ ScriptDataImpl* PreParserApi::PreParse(Utf16CharacterStream* source) {
preparser::PreParser preparser(&scanner, &recorder, stack_limit); preparser::PreParser preparser(&scanner, &recorder, stack_limit);
preparser.set_allow_lazy(true); preparser.set_allow_lazy(true);
preparser.set_allow_generators(FLAG_harmony_generators); preparser.set_allow_generators(FLAG_harmony_generators);
preparser.set_allow_for_of(FLAG_harmony_iteration);
preparser.set_allow_harmony_scoping(FLAG_harmony_scoping); preparser.set_allow_harmony_scoping(FLAG_harmony_scoping);
scanner.Initialize(source); scanner.Initialize(source);
preparser::PreParser::PreParseResult result = preparser.PreParseProgram(); preparser::PreParser::PreParseResult result = preparser.PreParseProgram();
......
...@@ -437,6 +437,7 @@ class Parser BASE_EMBEDDED { ...@@ -437,6 +437,7 @@ class Parser BASE_EMBEDDED {
bool allow_modules() { return scanner().HarmonyModules(); } bool allow_modules() { return scanner().HarmonyModules(); }
bool allow_harmony_scoping() { return scanner().HarmonyScoping(); } bool allow_harmony_scoping() { return scanner().HarmonyScoping(); }
bool allow_generators() const { return allow_generators_; } bool allow_generators() const { return allow_generators_; }
bool allow_for_of() const { return allow_for_of_; }
void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; } void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
void set_allow_lazy(bool allow) { allow_lazy_ = allow; } void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
...@@ -445,6 +446,7 @@ class Parser BASE_EMBEDDED { ...@@ -445,6 +446,7 @@ class Parser BASE_EMBEDDED {
scanner().SetHarmonyScoping(allow); scanner().SetHarmonyScoping(allow);
} }
void set_allow_generators(bool allow) { allow_generators_ = allow; } void set_allow_generators(bool allow) { allow_generators_ = allow; }
void set_allow_for_of(bool allow) { allow_for_of_ = allow; }
// Parses the source code represented by the compilation info and sets its // Parses the source code represented by the compilation info and sets its
// function literal. Returns false (and deallocates any allocated AST // function literal. Returns false (and deallocates any allocated AST
...@@ -721,13 +723,16 @@ class Parser BASE_EMBEDDED { ...@@ -721,13 +723,16 @@ class Parser BASE_EMBEDDED {
bool is_generator() const { return current_function_state_->is_generator(); } bool is_generator() const { return current_function_state_->is_generator(); }
bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode);
bool peek_any_identifier(); bool peek_any_identifier();
INLINE(void Consume(Token::Value token)); INLINE(void Consume(Token::Value token));
void Expect(Token::Value token, bool* ok); void Expect(Token::Value token, bool* ok);
bool Check(Token::Value token); bool Check(Token::Value token);
void ExpectSemicolon(bool* ok); void ExpectSemicolon(bool* ok);
void ExpectContextualKeyword(const char* keyword, bool* ok); bool CheckContextualKeyword(Vector<const char> keyword);
void ExpectContextualKeyword(Vector<const char> keyword, bool* ok);
Handle<String> LiteralString(PretenureFlag tenured) { Handle<String> LiteralString(PretenureFlag tenured) {
if (scanner().is_literal_ascii()) { if (scanner().is_literal_ascii()) {
...@@ -850,6 +855,7 @@ class Parser BASE_EMBEDDED { ...@@ -850,6 +855,7 @@ class Parser BASE_EMBEDDED {
bool allow_natives_syntax_; bool allow_natives_syntax_;
bool allow_lazy_; bool allow_lazy_;
bool allow_generators_; bool allow_generators_;
bool allow_for_of_;
bool stack_overflow_; bool stack_overflow_;
// If true, the next (and immediately following) function literal is // If true, the next (and immediately following) function literal is
// preceded by a parenthesis. // preceded by a parenthesis.
......
...@@ -659,6 +659,17 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) { ...@@ -659,6 +659,17 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
} }
bool PreParser::CheckInOrOf() {
if (peek() == i::Token::IN ||
(allow_for_of() &&
scanner_->is_next_contextual_keyword(v8::internal::CStrVector("of")))) {
Next();
return true;
}
return false;
}
PreParser::Statement PreParser::ParseForStatement(bool* ok) { PreParser::Statement PreParser::ParseForStatement(bool* ok) {
// ForStatement :: // ForStatement ::
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
...@@ -675,8 +686,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -675,8 +686,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
kForStatement, &decl_props, &decl_count, CHECK_OK); kForStatement, &decl_props, &decl_count, CHECK_OK);
bool accept_IN = decl_count == 1 && bool accept_IN = decl_count == 1 &&
!(is_let && decl_props == kHasInitializers); !(is_let && decl_props == kHasInitializers);
if (peek() == i::Token::IN && accept_IN) { if (accept_IN && CheckInOrOf()) {
Expect(i::Token::IN, CHECK_OK);
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK); Expect(i::Token::RPAREN, CHECK_OK);
...@@ -685,8 +695,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -685,8 +695,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
} }
} else { } else {
ParseExpression(false, CHECK_OK); ParseExpression(false, CHECK_OK);
if (peek() == i::Token::IN) { if (CheckInOrOf()) {
Expect(i::Token::IN, CHECK_OK);
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK); Expect(i::Token::RPAREN, CHECK_OK);
......
...@@ -130,6 +130,7 @@ class PreParser { ...@@ -130,6 +130,7 @@ class PreParser {
allow_lazy_(false), allow_lazy_(false),
allow_natives_syntax_(false), allow_natives_syntax_(false),
allow_generators_(false), allow_generators_(false),
allow_for_of_(false),
parenthesized_function_(false) { } parenthesized_function_(false) { }
~PreParser() {} ~PreParser() {}
...@@ -139,6 +140,7 @@ class PreParser { ...@@ -139,6 +140,7 @@ class PreParser {
bool allow_modules() const { return scanner_->HarmonyModules(); } bool allow_modules() const { return scanner_->HarmonyModules(); }
bool allow_harmony_scoping() const { return scanner_->HarmonyScoping(); } bool allow_harmony_scoping() const { return scanner_->HarmonyScoping(); }
bool allow_generators() const { return allow_generators_; } bool allow_generators() const { return allow_generators_; }
bool allow_for_of() const { return allow_for_of_; }
void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; } void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
void set_allow_lazy(bool allow) { allow_lazy_ = allow; } void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
...@@ -147,6 +149,7 @@ class PreParser { ...@@ -147,6 +149,7 @@ class PreParser {
scanner_->SetHarmonyScoping(allow); scanner_->SetHarmonyScoping(allow);
} }
void set_allow_generators(bool allow) { allow_generators_ = allow; } void set_allow_generators(bool allow) { allow_generators_ = allow; }
void set_allow_for_of(bool allow) { allow_for_of_ = allow; }
// Pre-parse the program from the character stream; returns true on // Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully // success (even if parsing failed, the pre-parse data successfully
...@@ -655,6 +658,8 @@ class PreParser { ...@@ -655,6 +658,8 @@ class PreParser {
} }
void ExpectSemicolon(bool* ok); void ExpectSemicolon(bool* ok);
bool CheckInOrOf();
static int Precedence(i::Token::Value tok, bool accept_IN); static int Precedence(i::Token::Value tok, bool accept_IN);
void SetStrictModeViolation(i::Scanner::Location, void SetStrictModeViolation(i::Scanner::Location,
...@@ -678,6 +683,7 @@ class PreParser { ...@@ -678,6 +683,7 @@ class PreParser {
bool allow_lazy_; bool allow_lazy_;
bool allow_natives_syntax_; bool allow_natives_syntax_;
bool allow_generators_; bool allow_generators_;
bool allow_for_of_;
bool parenthesized_function_; bool parenthesized_function_;
}; };
} } // v8::preparser } } // v8::preparser
......
...@@ -255,6 +255,17 @@ void PrettyPrinter::VisitForInStatement(ForInStatement* node) { ...@@ -255,6 +255,17 @@ void PrettyPrinter::VisitForInStatement(ForInStatement* node) {
} }
void PrettyPrinter::VisitForOfStatement(ForOfStatement* node) {
PrintLabels(node->labels());
Print("for (");
Visit(node->each());
Print(" of ");
Visit(node->iterable());
Print(") ");
Visit(node->body());
}
void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) { void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
Print("try "); Print("try ");
Visit(node->try_block()); Visit(node->try_block());
...@@ -929,6 +940,14 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) { ...@@ -929,6 +940,14 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) {
} }
void AstPrinter::VisitForOfStatement(ForOfStatement* node) {
IndentedScope indent(this, "FOR OF");
PrintIndentedVisit("FOR", node->each());
PrintIndentedVisit("OF", node->iterable());
PrintIndentedVisit("BODY", node->body());
}
void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
IndentedScope indent(this, "TRY CATCH"); IndentedScope indent(this, "TRY CATCH");
PrintIndentedVisit("TRY", node->try_block()); PrintIndentedVisit("TRY", node->try_block());
......
...@@ -168,6 +168,11 @@ void Processor::VisitForInStatement(ForInStatement* node) { ...@@ -168,6 +168,11 @@ void Processor::VisitForInStatement(ForInStatement* node) {
} }
void Processor::VisitForOfStatement(ForOfStatement* node) {
VisitIterationStatement(node);
}
void Processor::VisitTryCatchStatement(TryCatchStatement* node) { void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
// Rewrite both try and catch blocks (reversed order). // Rewrite both try and catch blocks (reversed order).
bool set_after_catch = is_set_; bool set_after_catch = is_set_;
......
...@@ -178,6 +178,11 @@ class LiteralBuffer { ...@@ -178,6 +178,11 @@ class LiteralBuffer {
bool is_ascii() { return is_ascii_; } bool is_ascii() { return is_ascii_; }
bool is_contextual_keyword(Vector<const char> keyword) {
return is_ascii() && keyword.length() == position_ &&
(memcmp(keyword.start(), backing_store_.start(), position_) == 0);
}
Vector<const uc16> utf16_literal() { Vector<const uc16> utf16_literal() {
ASSERT(!is_ascii_); ASSERT(!is_ascii_);
ASSERT((position_ & 0x1) == 0); ASSERT((position_ & 0x1) == 0);
...@@ -325,6 +330,10 @@ class Scanner { ...@@ -325,6 +330,10 @@ class Scanner {
ASSERT_NOT_NULL(current_.literal_chars); ASSERT_NOT_NULL(current_.literal_chars);
return current_.literal_chars->is_ascii(); return current_.literal_chars->is_ascii();
} }
bool is_literal_contextual_keyword(Vector<const char> keyword) {
ASSERT_NOT_NULL(next_.literal_chars);
return current_.literal_chars->is_contextual_keyword(keyword);
}
int literal_length() const { int literal_length() const {
ASSERT_NOT_NULL(current_.literal_chars); ASSERT_NOT_NULL(current_.literal_chars);
return current_.literal_chars->length(); return current_.literal_chars->length();
...@@ -361,6 +370,10 @@ class Scanner { ...@@ -361,6 +370,10 @@ class Scanner {
ASSERT_NOT_NULL(next_.literal_chars); ASSERT_NOT_NULL(next_.literal_chars);
return next_.literal_chars->is_ascii(); return next_.literal_chars->is_ascii();
} }
bool is_next_contextual_keyword(Vector<const char> keyword) {
ASSERT_NOT_NULL(next_.literal_chars);
return next_.literal_chars->is_contextual_keyword(keyword);
}
int next_literal_length() const { int next_literal_length() const {
ASSERT_NOT_NULL(next_.literal_chars); ASSERT_NOT_NULL(next_.literal_chars);
return next_.literal_chars->length(); return next_.literal_chars->length();
......
...@@ -224,6 +224,13 @@ void AstTyper::VisitForInStatement(ForInStatement* stmt) { ...@@ -224,6 +224,13 @@ void AstTyper::VisitForInStatement(ForInStatement* stmt) {
} }
void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
ASSERT(!HasStackOverflow());
CHECK_ALIVE(Visit(stmt->iterable()));
CHECK_ALIVE(Visit(stmt->body()));
}
void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) { void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
CHECK_ALIVE(Visit(stmt->try_block())); CHECK_ALIVE(Visit(stmt->try_block()));
......
...@@ -1078,6 +1078,7 @@ enum ParserFlag { ...@@ -1078,6 +1078,7 @@ enum ParserFlag {
kAllowHarmonyScoping, kAllowHarmonyScoping,
kAllowModules, kAllowModules,
kAllowGenerators, kAllowGenerators,
kAllowForOf,
kParserFlagCount kParserFlagCount
}; };
...@@ -1094,7 +1095,8 @@ static bool checkParserFlag(unsigned flags, ParserFlag flag) { ...@@ -1094,7 +1095,8 @@ static bool checkParserFlag(unsigned flags, ParserFlag flag) {
parser.set_allow_harmony_scoping(checkParserFlag(flags, \ parser.set_allow_harmony_scoping(checkParserFlag(flags, \
kAllowHarmonyScoping)); \ kAllowHarmonyScoping)); \
parser.set_allow_modules(checkParserFlag(flags, kAllowModules)); \ parser.set_allow_modules(checkParserFlag(flags, kAllowModules)); \
parser.set_allow_generators(checkParserFlag(flags, kAllowGenerators)); parser.set_allow_generators(checkParserFlag(flags, kAllowGenerators)); \
parser.set_allow_for_of(checkParserFlag(flags, kAllowForOf));
void TestParserSyncWithFlags(i::Handle<i::String> source, unsigned flags) { void TestParserSyncWithFlags(i::Handle<i::String> source, unsigned flags) {
i::Isolate* isolate = i::Isolate::Current(); i::Isolate* isolate = i::Isolate::Current();
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --harmony-iteration --harmony-scoping
// Test for-of syntax.
"use strict";
function f() { for (x of y) { } }
function f() { for (var x of y) { } }
function f() { for (let x of y) { } }
assertThrows("function f() { for (x of) { } }", SyntaxError);
assertThrows("function f() { for (x of y z) { } }", SyntaxError);
assertThrows("function f() { for (x of y;) { } }", SyntaxError);
assertThrows("function f() { for (var x of) { } }", SyntaxError);
assertThrows("function f() { for (var x of y z) { } }", SyntaxError);
assertThrows("function f() { for (var x of y;) { } }", SyntaxError);
assertThrows("function f() { for (let x of) { } }", SyntaxError);
assertThrows("function f() { for (let x of y z) { } }", SyntaxError);
assertThrows("function f() { for (let x of y;) { } }", SyntaxError);
assertThrows("function f() { for (of y) { } }", SyntaxError);
assertThrows("function f() { for (of of) { } }", SyntaxError);
assertThrows("function f() { for (var of y) { } }", SyntaxError);
assertThrows("function f() { for (var of of) { } }", SyntaxError);
assertThrows("function f() { for (let of y) { } }", SyntaxError);
assertThrows("function f() { for (let of of) { } }", SyntaxError);
// Alack, this appears to be valid.
function f() { for (of of y) { } }
function f() { for (let of of y) { } }
function f() { for (var of of y) { } }
// This too, of course.
function f() { for (of in y) { } }
function f() { for (var of in y) { } }
function f() { for (let of in y) { } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment