static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptyStringRootIndex = 162;
+ static const int kEmptyStringRootIndex = 163;
// The external allocation limit should be below 256 MB on all architectures
// to avoid that resource-constrained embedders run low on memory.
Iteration loop_statement(this, stmt);
increment_loop_depth();
- // var iterator = iterable[@@iterator]()
- VisitForAccumulatorValue(stmt->assign_iterator());
+ // var iterable = subject
+ VisitForAccumulatorValue(stmt->assign_iterable());
// As with for-in, skip the loop if the iterator is null or undefined.
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
__ CompareRoot(r0, Heap::kNullValueRootIndex);
__ b(eq, loop_statement.break_label());
- // Convert the iterator to a JS object.
- Label convert, done_convert;
- __ JumpIfSmi(r0, &convert);
- __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
- __ b(ge, &done_convert);
- __ bind(&convert);
- __ push(r0);
- __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
- __ bind(&done_convert);
- __ push(r0);
+ // var iterator = iterable[Symbol.iterator]();
+ VisitForEffect(stmt->assign_iterator());
// Loop entry.
__ bind(loop_statement.continue_label());
Iteration loop_statement(this, stmt);
increment_loop_depth();
- // var iterator = iterable[@@iterator]()
- VisitForAccumulatorValue(stmt->assign_iterator());
+ // var iterable = subject
+ VisitForAccumulatorValue(stmt->assign_iterable());
// As with for-in, skip the loop if the iterator is null or undefined.
Register iterator = x0;
__ JumpIfRoot(iterator, Heap::kNullValueRootIndex,
loop_statement.break_label());
- // Convert the iterator to a JS object.
- Label convert, done_convert;
- __ JumpIfSmi(iterator, &convert);
- __ CompareObjectType(iterator, x1, x1, FIRST_SPEC_OBJECT_TYPE);
- __ B(ge, &done_convert);
- __ Bind(&convert);
- __ Push(iterator);
- __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
- __ Bind(&done_convert);
- __ Push(iterator);
+ // var iterator = iterable[Symbol.iterator]();
+ VisitForEffect(stmt->assign_iterator());
// Loop entry.
__ Bind(loop_statement.continue_label());
function ArrayIterator() {}
+// TODO(wingo): Update section numbers when ES6 has stabilized. The
+// section numbers below are already out of date as of the May 2014
+// draft.
+
+
// 15.4.5.1 CreateArrayIterator Abstract Operation
function CreateArrayIterator(array, kind) {
var object = ToObject(array);
}
+// 22.1.5.2.2 %ArrayIteratorPrototype%[@@iterator]
+function ArrayIteratorIterator() {
+ return this;
+}
+
+
// 15.4.5.2.2 ArrayIterator.prototype.next( )
function ArrayIteratorNext() {
var iterator = ToObject(this);
InstallFunctions(ArrayIterator.prototype, DONT_ENUM, $Array(
'next', ArrayIteratorNext
));
+ %FunctionSetName(ArrayIteratorIterator, '[Symbol.iterator]');
+ %SetProperty(ArrayIterator.prototype, symbolIterator, ArrayIteratorIterator,
+ DONT_ENUM | DONT_DELETE | READ_ONLY);
}
SetUpArrayIterator();
void Initialize(Expression* each,
Expression* subject,
Statement* body,
+ Expression* assign_iterable,
Expression* assign_iterator,
Expression* next_result,
Expression* result_done,
Expression* assign_each) {
ForEachStatement::Initialize(each, subject, body);
+ assign_iterable_ = assign_iterable;
assign_iterator_ = assign_iterator;
next_result_ = next_result;
result_done_ = result_done;
return subject();
}
- // var iterator = iterable;
+ // var iterable = subject;
+ Expression* assign_iterable() const {
+ return assign_iterable_;
+ }
+
+ // var iterator = iterable[Symbol.iterator]();
Expression* assign_iterator() const {
return assign_iterator_;
}
back_edge_id_(GetNextId(zone)) {
}
+ Expression* assign_iterable_;
Expression* assign_iterator_;
Expression* next_result_;
Expression* result_done_;
INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
}
+
+ if (FLAG_harmony_symbols) {
+ INSTALL_NATIVE(Symbol, "symbolIterator", iterator_symbol);
+ }
}
#undef INSTALL_NATIVE
generator_object_prototype_map) \
V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map) \
V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \
- V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map)
+ V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map) \
+ V(ITERATOR_SYMBOL_INDEX, Symbol, iterator_symbol)
// JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and
ITERATOR_RESULT_MAP_INDEX,
MAP_ITERATOR_MAP_INDEX,
SET_ITERATOR_MAP_INDEX,
+ ITERATOR_SYMBOL_INDEX,
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.
DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_collections, harmony_symbols)
DEFINE_implication(harmony_generators, harmony_symbols)
+DEFINE_implication(harmony_iteration, harmony_symbols)
DEFINE_implication(harmony, es_staging)
DEFINE_implication(es_staging, harmony_maths)
DONT_ENUM | DONT_DELETE | READ_ONLY,
["next", GeneratorObjectNext,
"throw", GeneratorObjectThrow]);
+ %FunctionSetName(GeneratorObjectIterator, '[Symbol.iterator]');
%SetProperty(GeneratorObjectPrototype, symbolIterator, GeneratorObjectIterator,
DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetProperty(GeneratorObjectPrototype, "constructor",
V(constructor_string, "constructor") \
V(dot_result_string, ".result") \
V(dot_for_string, ".for.") \
+ V(dot_iterable_string, ".iterable") \
V(dot_iterator_string, ".iterator") \
V(dot_generator_object_string, ".generator_object") \
V(eval_string, "eval") \
Iteration loop_statement(this, stmt);
increment_loop_depth();
- // var iterator = iterable[@@iterator]()
- VisitForAccumulatorValue(stmt->assign_iterator());
+ // var iterable = subject
+ VisitForAccumulatorValue(stmt->assign_iterable());
// As with for-in, skip the loop if the iterator is null or undefined.
__ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
__ CompareRoot(eax, Heap::kNullValueRootIndex);
__ j(equal, loop_statement.break_label());
- // Convert the iterator to a JS object.
- Label convert, done_convert;
- __ JumpIfSmi(eax, &convert);
- __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
- __ j(above_equal, &done_convert);
- __ bind(&convert);
- __ push(eax);
- __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
- __ bind(&done_convert);
+ // var iterator = iterable[Symbol.iterator]();
+ VisitForEffect(stmt->assign_iterator());
// Loop entry.
__ bind(loop_statement.continue_label());
Iteration loop_statement(this, stmt);
increment_loop_depth();
- // var iterator = iterable[@@iterator]()
- VisitForAccumulatorValue(stmt->assign_iterator());
+ // var iterable = subject
+ VisitForAccumulatorValue(stmt->assign_iterable());
__ mov(a0, v0);
// As with for-in, skip the loop if the iterator is null or undefined.
__ LoadRoot(at, Heap::kNullValueRootIndex);
__ Branch(loop_statement.break_label(), eq, a0, Operand(at));
- // Convert the iterator to a JS object.
- Label convert, done_convert;
- __ JumpIfSmi(a0, &convert);
- __ GetObjectType(a0, a1, a1);
- __ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
- __ bind(&convert);
- __ push(a0);
- __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
- __ mov(a0, v0);
- __ bind(&done_convert);
- __ push(a0);
+ // var iterator = iterable[Symbol.iterator]();
+ VisitForEffect(stmt->assign_iterator());
// Loop entry.
__ bind(loop_statement.continue_label());
if (for_of != NULL) {
Factory* heap_factory = isolate()->factory();
+ Variable* iterable = scope_->DeclarationScope()->NewTemporary(
+ heap_factory->dot_iterable_string());
Variable* iterator = scope_->DeclarationScope()->NewTemporary(
heap_factory->dot_iterator_string());
Variable* result = scope_->DeclarationScope()->NewTemporary(
heap_factory->dot_result_string());
+ Expression* assign_iterable;
Expression* assign_iterator;
Expression* next_result;
Expression* result_done;
Expression* assign_each;
- // var iterator = iterable;
+ // var iterable = subject;
{
+ Expression* iterable_proxy = factory()->NewVariableProxy(iterable);
+ assign_iterable = factory()->NewAssignment(
+ Token::ASSIGN, iterable_proxy, subject, subject->position());
+ }
+
+ // var iterator = iterable[Symbol.iterator]();
+ {
+ Expression* iterable_proxy = factory()->NewVariableProxy(iterable);
+ Handle<Symbol> iterator_symbol(
+ isolate()->native_context()->iterator_symbol(), isolate());
+ Expression* iterator_symbol_literal = factory()->NewLiteral(
+ iterator_symbol, RelocInfo::kNoPosition);
+ // FIXME(wingo): Unhappily, it will be a common error that the RHS of a
+ // for-of doesn't have a Symbol.iterator property. We should do better
+ // than informing the user that "undefined is not a function".
+ int pos = subject->position();
+ Expression* iterator_property = factory()->NewProperty(
+ iterable_proxy, iterator_symbol_literal, pos);
+ ZoneList<Expression*>* iterator_arguments =
+ new(zone()) ZoneList<Expression*>(0, zone());
+ Expression* iterator_call = factory()->NewCall(
+ iterator_property, iterator_arguments, pos);
Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
assign_iterator = factory()->NewAssignment(
- Token::ASSIGN, iterator_proxy, subject, RelocInfo::kNoPosition);
+ Token::ASSIGN, iterator_proxy, iterator_call, RelocInfo::kNoPosition);
}
// var result = iterator.next();
}
for_of->Initialize(each, subject, body,
- assign_iterator, next_result, result_done, assign_each);
+ assign_iterable,
+ assign_iterator,
+ next_result,
+ result_done,
+ assign_each);
} else {
stmt->Initialize(each, subject, body);
}
Iteration loop_statement(this, stmt);
increment_loop_depth();
- // var iterator = iterable[@@iterator]()
- VisitForAccumulatorValue(stmt->assign_iterator());
+ // var iterable = subject
+ VisitForAccumulatorValue(stmt->assign_iterable());
- // As with for-in, skip the loop if the iterator is null or undefined.
+ // As with for-in, skip the loop if the iterable is null or undefined.
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(equal, loop_statement.break_label());
__ CompareRoot(rax, Heap::kNullValueRootIndex);
__ j(equal, loop_statement.break_label());
- // Convert the iterator to a JS object.
- Label convert, done_convert;
- __ JumpIfSmi(rax, &convert);
- __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
- __ j(above_equal, &done_convert);
- __ bind(&convert);
- __ Push(rax);
- __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
- __ bind(&done_convert);
+ // var iterator = iterable[Symbol.iterator]();
+ VisitForEffect(stmt->assign_iterator());
// Loop entry.
__ bind(loop_statement.continue_label());
Iteration loop_statement(this, stmt);
increment_loop_depth();
- // var iterator = iterable[@@iterator]()
- VisitForAccumulatorValue(stmt->assign_iterator());
+ // var iterable = subject
+ VisitForAccumulatorValue(stmt->assign_iterable());
// As with for-in, skip the loop if the iterator is null or undefined.
__ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
__ CompareRoot(eax, Heap::kNullValueRootIndex);
__ j(equal, loop_statement.break_label());
- // Convert the iterator to a JS object.
- Label convert, done_convert;
- __ JumpIfSmi(eax, &convert);
- __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
- __ j(above_equal, &done_convert);
- __ bind(&convert);
- __ push(eax);
- __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
- __ bind(&done_convert);
+ // var iterator = iterable[Symbol.iterator]();
+ VisitForEffect(stmt->assign_iterator());
// Loop entry.
__ bind(loop_statement.continue_label());
// Flags: --harmony-iteration
// Flags: --harmony-generators --harmony-scoping --harmony-proxies
+// Flags: --harmony-symbols
// Test for-of semantics.
}
}
+function wrap_iterator(iterator) {
+ var iterable = {};
+ iterable[Symbol.iterator] = function() { return iterator; };
+ return iterable;
+}
+
function integers_until(max) {
function next() {
var ret = { value: this.n, done: this.n == max };
this.n++;
return ret;
}
- return { next: next, n: 0 }
+ return wrap_iterator({ next: next, n: 0 });
}
function results(results) {
function next() {
return results[i++];
}
- return { next: next }
+ return wrap_iterator({ next: next });
}
function* integers_from(n) {
return x + tail;
}
-function fold(cons, seed, iter) {
- for (var x of iter) {
+function fold(cons, seed, iterable) {
+ for (var x of iterable) {
seed = cons(x, seed);
}
return seed;
}
-function* take(iter, n) {
+function* take(iterable, n) {
if (n == 0) return;
- for (let x of iter) {
+ for (let x of iterable) {
yield x;
if (--n == 0) break;
}
}
-function nth(iter, n) {
- for (let x of iter) {
+function nth(iterable, n) {
+ for (let x of iterable) {
if (n-- == 0) return x;
}
throw "unreachable";
}
-function* skip_every(iter, n) {
+function* skip_every(iterable, n) {
var i = 0;
- for (let x of iter) {
+ for (let x of iterable) {
if (++i % n == 0) continue;
yield x;
}
}
-function* iter_map(iter, f) {
- for (var x of iter) {
+function* iter_map(iterable, f) {
+ for (var x of iterable) {
yield f(x);
}
}
-function nested_fold(cons, seed, iter) {
+function nested_fold(cons, seed, iterable) {
var visited = []
- for (let x of iter) {
+ for (let x of iterable) {
for (let y of x) {
seed = cons(y, seed);
}
return seed;
}
-function* unreachable(iter) {
- for (let x of iter) {
+function* unreachable(iterable) {
+ for (let x of iterable) {
throw "not reached";
}
}
return o;
}
-function remove_next_after(iter, n) {
+function remove_next_after(iterable, n) {
+ var iterator = iterable[Symbol.iterator]();
function next() {
if (n-- == 0) delete this.next;
- return iter.next();
+ return iterator.next();
}
- return { next: next }
+ return wrap_iterator({ next: next });
}
-function poison_next_after(iter, n) {
+function poison_next_after(iterable, n) {
+ var iterator = iterable[Symbol.iterator]();
function next() {
- return iter.next();
+ return iterator.next();
}
function next_getter() {
if (n-- < 0)
}
var o = {};
Object.defineProperty(o, 'next', { get: next_getter });
- return o;
+ return wrap_iterator(o);
}
// Now, the tests.
assertEquals(45,
fold(sum, 0, poison_next_after(integers_until(10), 10)));
-function labelled_continue(iter) {
+function labelled_continue(iterable) {
var n = 0;
outer:
while (true) {
n++;
- for (var x of iter) continue outer;
+ for (var x of iterable) continue outer;
break;
}
return n;
}
assertEquals(11, labelled_continue(integers_until(10)));
-function labelled_break(iter) {
+function labelled_break(iterable) {
var n = 0;
outer:
while (true) {
n++;
- for (var x of iter) break outer;
+ for (var x of iterable) break outer;
}
return n;
}
assertEquals(1, labelled_break(integers_until(10)));
// Test continue/break in catch.
-function catch_control(iter, k) {
+function catch_control(iterable, k) {
var n = 0;
- for (var x of iter) {
+ for (var x of iterable) {
try {
return k(x);
} catch (e) {
}));
// Test continue/break in try.
-function try_control(iter, k) {
+function try_control(iterable, k) {
var n = 0;
- for (var x of iter) {
+ for (var x of iterable) {
try {
var e = k(x);
if (e == "continue") continue;
.map(transparent_proxy))));
// Proxy iterators.
-function poison_proxy_after(x, n) {
- return Proxy.create({
+function poison_proxy_after(iterable, n) {
+ var iterator = iterable[Symbol.iterator]();
+ return wrap_iterator(Proxy.create({
get: function(receiver, name) {
if (name == 'next' && n-- < 0) throw "unreachable";
- return x[name];
+ return iterator[name];
},
// Needed for integers_until(10)'s this.n++.
set: function(receiver, name, val) {
- return x[name] = val;
+ return iterator[name] = val;
}
- });
+ }));
}
assertEquals(45, fold(sum, 0, poison_proxy_after(integers_until(10), 10)));
EXPECTED_FUZZABLE_COUNT = 325
EXPECTED_CCTEST_COUNT = 6
EXPECTED_UNKNOWN_COUNT = 5
-EXPECTED_BUILTINS_COUNT = 797
+EXPECTED_BUILTINS_COUNT = 798
# Don't call these at all.