Skip to content

Commit fe80b76

Browse files
tuchidaGregory Brail
authored andcommitted
Implement ES.next for-of
When ant junit-all, yield is syntax error.
1 parent bb60a60 commit fe80b76

15 files changed

Lines changed: 534 additions & 131 deletions

src/org/mozilla/javascript/CodeGenerator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ private void visitStatement(Node node, int initialStackDepth)
475475
case Token.ENUM_INIT_KEYS:
476476
case Token.ENUM_INIT_VALUES:
477477
case Token.ENUM_INIT_ARRAY:
478+
case Token.ENUM_INIT_VALUES_IN_ORDER:
478479
visitExpression(child, 0);
479480
addIndexOp(type, getLocalBlockRef(node));
480481
stackChange(-1);

src/org/mozilla/javascript/IRFactory.java

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,11 @@ private Node arrayCompTransformHelper(ArrayComprehension node,
270270
defineSymbol(Token.LET, name, false);
271271
iterators[i] = init;
272272

273-
decompiler.addToken(Token.IN);
273+
if (acl.isForOf()) {
274+
decompiler.addName("of ");
275+
} else {
276+
decompiler.addToken(Token.IN);
277+
}
274278
iteratedObjs[i] = transform(acl.getIteratedObject());
275279
decompiler.addToken(Token.RP);
276280
}
@@ -305,7 +309,8 @@ private Node arrayCompTransformHelper(ArrayComprehension node,
305309
iterators[i],
306310
iteratedObjs[i],
307311
body,
308-
acl.isForEach());
312+
acl.isForEach(),
313+
acl.isForOf());
309314
}
310315
} finally {
311316
for (int i = 0; i < pushed; i++) {
@@ -468,14 +473,18 @@ private Node transformForInLoop(ForInLoop loop) {
468473
declType = ((VariableDeclaration)iter).getType();
469474
}
470475
Node lhs = transform(iter);
471-
decompiler.addToken(Token.IN);
476+
if (loop.isForOf()) {
477+
decompiler.addName("of ");
478+
} else {
479+
decompiler.addToken(Token.IN);
480+
}
472481
Node obj = transform(loop.getIteratedObject());
473482
decompiler.addToken(Token.RP);
474483
decompiler.addEOL(Token.LC);
475484
Node body = transform(loop.getBody());
476485
decompiler.addEOL(Token.RC);
477486
return createForIn(declType, loop, lhs, obj, body,
478-
loop.isForEach());
487+
loop.isForEach(), loop.isForOf());
479488
} finally {
480489
popScope();
481490
}
@@ -671,7 +680,11 @@ private Node genExprTransformHelper(GeneratorExpression node) {
671680
defineSymbol(Token.LET, name, false);
672681
iterators[i] = init;
673682

674-
decompiler.addToken(Token.IN);
683+
if (acl.isForOf()) {
684+
decompiler.addName("of ");
685+
} else {
686+
decompiler.addToken(Token.IN);
687+
}
675688
iteratedObjs[i] = transform(acl.getIteratedObject());
676689
decompiler.addToken(Token.RP);
677690
}
@@ -703,7 +716,8 @@ private Node genExprTransformHelper(GeneratorExpression node) {
703716
iterators[i],
704717
iteratedObjs[i],
705718
body,
706-
acl.isForEach());
719+
acl.isForEach(),
720+
acl.isForOf());
707721
}
708722
} finally {
709723
for (int i = 0; i < pushed; i++) {
@@ -1510,7 +1524,7 @@ private Node createLoop(Jump loop, int loopType, Node body,
15101524
* Generate IR for a for..in loop.
15111525
*/
15121526
private Node createForIn(int declType, Node loop, Node lhs,
1513-
Node obj, Node body, boolean isForEach)
1527+
Node obj, Node body, boolean isForEach, boolean isForOf)
15141528
{
15151529
int destructuring = -1;
15161530
int destructuringLen = 0;
@@ -1548,6 +1562,7 @@ private Node createForIn(int declType, Node loop, Node lhs,
15481562

15491563
Node localBlock = new Node(Token.LOCAL_BLOCK);
15501564
int initType = isForEach ? Token.ENUM_INIT_VALUES
1565+
: isForOf ? Token.ENUM_INIT_VALUES_IN_ORDER
15511566
: (destructuring != -1
15521567
? Token.ENUM_INIT_ARRAY
15531568
: Token.ENUM_INIT_KEYS);
@@ -1562,8 +1577,9 @@ private Node createForIn(int declType, Node loop, Node lhs,
15621577
Node assign;
15631578
if (destructuring != -1) {
15641579
assign = createDestructuringAssignment(declType, lvalue, id);
1565-
if (!isForEach && (destructuring == Token.OBJECTLIT ||
1566-
destructuringLen != 2))
1580+
if (!isForEach && !isForOf &&
1581+
(destructuring == Token.OBJECTLIT ||
1582+
destructuringLen != 2))
15671583
{
15681584
// destructuring assignment is only allowed in for..each or
15691585
// with an array type of length 2 (to hold key and value)

src/org/mozilla/javascript/Interpreter.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,8 @@ private static Object interpretLoop(Context cx, CallFrame frame,
16481648
}
16491649
case Token.ENUM_INIT_KEYS :
16501650
case Token.ENUM_INIT_VALUES :
1651-
case Token.ENUM_INIT_ARRAY : {
1651+
case Token.ENUM_INIT_ARRAY :
1652+
case Token.ENUM_INIT_VALUES_IN_ORDER : {
16521653
Object lhs = stack[stackTop];
16531654
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
16541655
--stackTop;
@@ -1657,6 +1658,8 @@ private static Object interpretLoop(Context cx, CallFrame frame,
16571658
? ScriptRuntime.ENUMERATE_KEYS :
16581659
op == Token.ENUM_INIT_VALUES
16591660
? ScriptRuntime.ENUMERATE_VALUES :
1661+
op == Token.ENUM_INIT_VALUES_IN_ORDER
1662+
? ScriptRuntime.ENUMERATE_VALUES_IN_ORDER :
16601663
ScriptRuntime.ENUMERATE_ARRAY;
16611664
stack[indexReg] = ScriptRuntime.enumInit(lhs, cx, frame.scope, enumType);
16621665
continue Loop;

src/org/mozilla/javascript/NativeArray.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ protected void initPrototypeId(int id)
214214
case Id_findIndex: arity=1; s="findIndex"; break;
215215
case Id_reduce: arity=1; s="reduce"; break;
216216
case Id_reduceRight: arity=1; s="reduceRight"; break;
217+
case Id_iterator: arity=0; s="iterator"; break;
217218
default: throw new IllegalArgumentException(String.valueOf(id));
218219
}
219220
initPrototypeMethod(ARRAY_TAG, id, s, arity);
@@ -331,6 +332,9 @@ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
331332
case Id_reduce:
332333
case Id_reduceRight:
333334
return reduceMethod(cx, id, scope, thisObj, args);
335+
336+
case Id_iterator:
337+
return new NativeElementIterator(scope, thisObj);
334338
}
335339
throw new IllegalArgumentException(String.valueOf(id));
336340
}
@@ -1980,6 +1984,7 @@ protected int findPrototypeId(String s)
19801984
case 8: c=s.charAt(3);
19811985
if (c=='o') { X="toSource";id=Id_toSource; }
19821986
else if (c=='t') { X="toString";id=Id_toString; }
1987+
else if (c=='r') { X="iterator";id=Id_iterator; }
19831988
break L;
19841989
case 9: X="findIndex";id=Id_findIndex; break L;
19851990
case 11: c=s.charAt(0);
@@ -2022,9 +2027,9 @@ protected int findPrototypeId(String s)
20222027
Id_findIndex = 23,
20232028
Id_reduce = 24,
20242029
Id_reduceRight = 25,
2030+
Id_iterator = 26,
20252031

2026-
2027-
MAX_PROTOTYPE_ID = 25;
2032+
MAX_PROTOTYPE_ID = 26;
20282033

20292034
// #/string_id_map#
20302035

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2+
*
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
package org.mozilla.javascript;
8+
9+
import java.util.Iterator;
10+
11+
/**
12+
* This class implements ArrayIterator and StringIterator objects. See
13+
* http://wiki.ecmascript.org/doku.php?id=harmony:iterators
14+
*/
15+
public final class NativeElementIterator extends IdScriptableObject {
16+
private static final long serialVersionUID = 1L;
17+
private static final Object ELEMENT_ITERATOR_TAG = "ElementIterator";
18+
19+
static void init(ScriptableObject scope, boolean sealed) {
20+
// NativeElementIterator
21+
// Can't use "NativeElementIterator().exportAsJSClass" since we don't want
22+
// to define "NativeElementIterator" as a constructor in the top-level scope.
23+
NativeElementIterator prototype = new NativeElementIterator();
24+
if (scope != null) {
25+
prototype.setParentScope(scope);
26+
prototype.setPrototype(getObjectPrototype(scope));
27+
}
28+
prototype.activatePrototypeMap(MAX_PROTOTYPE_ID);
29+
if (sealed) {
30+
prototype.sealObject();
31+
}
32+
33+
// Need to access Iterator prototype when constructing
34+
// Iterator instances, but don't have a iterator constructor
35+
// to use to find the prototype. Use the "associateValue"
36+
// approach instead.
37+
if (scope != null) {
38+
scope.associateValue(ELEMENT_ITERATOR_TAG, prototype);
39+
}
40+
}
41+
42+
/**
43+
* Only for constructing the prototype object.
44+
*/
45+
private NativeElementIterator() {
46+
}
47+
48+
NativeElementIterator(Scriptable scope, Scriptable arrayLike) {
49+
this.arrayLike = arrayLike;
50+
this.index = 0;
51+
// Set parent and prototype properties. Since we don't have a
52+
// "Iterator" constructor in the top scope, we stash the
53+
// prototype in the top scope's associated value.
54+
Scriptable top = ScriptableObject.getTopLevelScope(scope);
55+
this.setParentScope(top);
56+
NativeElementIterator prototype = (NativeElementIterator)
57+
ScriptableObject.getTopScopeValue(top, ELEMENT_ITERATOR_TAG);
58+
setPrototype(prototype);
59+
}
60+
61+
@Override
62+
public String getClassName() {
63+
return "Iterator";
64+
}
65+
66+
@Override
67+
protected void initPrototypeId(int id)
68+
{
69+
String s;
70+
int arity;
71+
switch (id) {
72+
case Id_next: arity=0; s="next"; break;
73+
default: throw new IllegalArgumentException(String.valueOf(id));
74+
}
75+
initPrototypeMethod(ELEMENT_ITERATOR_TAG, id, s, arity);
76+
}
77+
78+
@Override
79+
public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
80+
Scriptable thisObj, Object[] args)
81+
{
82+
if (!f.hasTag(ELEMENT_ITERATOR_TAG)) {
83+
return super.execIdCall(f, cx, scope, thisObj, args);
84+
}
85+
int id = f.methodId();
86+
87+
if (!(thisObj instanceof NativeElementIterator))
88+
throw incompatibleCallError(f);
89+
90+
NativeElementIterator iterator = (NativeElementIterator) thisObj;
91+
92+
switch (id) {
93+
case Id_next:
94+
return iterator.next(cx, scope);
95+
default:
96+
throw new IllegalArgumentException(String.valueOf(id));
97+
}
98+
}
99+
100+
@Override
101+
protected int findPrototypeId(String s)
102+
{
103+
if (s.equals("next")) {
104+
return Id_next;
105+
}
106+
return 0;
107+
}
108+
109+
private Object next(Context cx, Scriptable scope) {
110+
if (index >= NativeArray.getLengthProperty(cx, arrayLike)) {
111+
// Out of values. Throw StopIteration.
112+
throw new JavaScriptException(
113+
NativeIterator.getStopIterationObject(scope), null, 0);
114+
}
115+
return arrayLike.get(index++, arrayLike);
116+
}
117+
118+
public static final String ITERATOR_FUNCTION_NAME = "iterator";
119+
120+
private Scriptable arrayLike;
121+
private int index;
122+
123+
private static final int
124+
Id_next = 1,
125+
MAX_PROTOTYPE_ID = 1;
126+
}

src/org/mozilla/javascript/NativeString.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ protected void initPrototypeId(int id)
175175
case Id_normalize: arity=0; s="normalize"; break;
176176
case Id_repeat: arity=1; s="repeat"; break;
177177
case Id_codePointAt: arity=1; s="codePointAt"; break;
178+
case Id_iterator: arity=0; s="iterator"; break;
178179
default: throw new IllegalArgumentException(String.valueOf(id));
179180
}
180181
initPrototypeMethod(STRING_TAG, id, s, arity);
@@ -447,6 +448,7 @@ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
447448

448449
return str.substring(start, end);
449450
}
451+
450452
case Id_normalize: {
451453
String formStr = ScriptRuntime.toString(args, 0);
452454

@@ -498,6 +500,10 @@ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
498500
? Undefined.instance
499501
: str.codePointAt((int) cnt);
500502
}
503+
504+
case Id_iterator:
505+
return new NativeElementIterator(scope, thisObj);
506+
501507
}
502508
throw new IllegalArgumentException("String.prototype has no method: " + f.getFunctionName());
503509
}
@@ -793,6 +799,7 @@ protected int findPrototypeId(String s)
793799
case 'n': X="toString";id=Id_toString; break L;
794800
case 't': X="endsWith";id=Id_endsWith; break L;
795801
case 'z': X="fontsize";id=Id_fontsize; break L;
802+
case 'o': X="iterator";id=Id_iterator; break L;
796803
} break L;
797804
case 9: switch (s.charAt(0)) {
798805
case 'f': X="fontcolor";id=Id_fontcolor; break L;
@@ -873,7 +880,8 @@ protected int findPrototypeId(String s)
873880
Id_normalize = 43,
874881
Id_repeat = 44,
875882
Id_codePointAt = 45,
876-
MAX_PROTOTYPE_ID = Id_codePointAt;
883+
Id_iterator = 46,
884+
MAX_PROTOTYPE_ID = Id_iterator;
877885

878886
// #/string_id_map#
879887

0 commit comments

Comments
 (0)