Skip to content

Commit 64683f6

Browse files
JS: Support async generator methods (class { async * generator () { ... })
Additional bugfix: async methods were potentially not correctly recognized, leading to parser failures when encountering async-only constructs. Closes: #8397
1 parent 882d1a7 commit 64683f6

File tree

5 files changed

+267
-2
lines changed

5 files changed

+267
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
class Demo {
2+
* generator1() {
3+
yield 1;
4+
yield 1 + 10;
5+
}
6+
7+
* generator2(i) {
8+
yield i;
9+
yield i + 10;
10+
}
11+
12+
async * generator3() {
13+
yield 1;
14+
yield 1 + 10;
15+
}
16+
17+
async * generator4(i) {
18+
yield i;
19+
yield i + 10;
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
<!--
2+
3+
Licensed to the Apache Software Foundation (ASF) under one
4+
or more contributor license agreements. See the NOTICE file
5+
distributed with this work for additional information
6+
regarding copyright ownership. The ASF licenses this file
7+
to you under the Apache License, Version 2.0 (the
8+
"License"); you may not use this file except in compliance
9+
with the License. You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing,
14+
software distributed under the License is distributed on an
15+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
KIND, either express or implied. See the License for the
17+
specific language governing permissions and limitations
18+
under the License.
19+
20+
-->
21+
22+
<FunctionNode name=':program' kind='SCRIPT' start='0' end='295'>
23+
<isProgram/>
24+
<!-- FunctionNode Parameters -->
25+
<!-- FunctionNode Body -->
26+
<Block start='0' end='295'>
27+
<isFunctionBody/>
28+
<isSynthetic/>
29+
<!-- Block Statements -->
30+
<VarNode name='Demo' start='0' end='10'>
31+
<hasInit/>
32+
<isAssignment/>
33+
<isBlockScoped/>
34+
<isConst/>
35+
<!-- VarNode Assignment Dest -->
36+
<IdentNode start='6' end='10'>
37+
<name>Demo</name>
38+
<isInitializedHere/>
39+
</IdentNode>
40+
<!-- VarNode Init -->
41+
<ClassNode ident='Demo' start='0' end='295'>
42+
<!-- ClassNode Constructor -->
43+
<ClassElement name='Demo' start='0' end='295'>
44+
<!-- ClassElement Key -->
45+
<IdentNode start='6' end='10'>
46+
<name>Demo</name>
47+
</IdentNode>
48+
<!-- ClassElement Value -->
49+
<FunctionNode name='Demo' kind='NORMAL' start='0' end='295'>
50+
<isClassConstructor/>
51+
<isMethod/>
52+
<isNamedFunctionExpression/>
53+
<!-- FunctionNode Parameters -->
54+
<!-- FunctionNode Body -->
55+
<Block start='0' end='295'>
56+
<isFunctionBody/>
57+
<!-- Block Statements -->
58+
</Block>
59+
</FunctionNode>
60+
<!-- ClassElement Decorators -->
61+
</ClassElement>
62+
<!-- ClassNode Elements -->
63+
<ClassElement name='generator1' start='19' end='78'>
64+
<!-- ClassElement Key -->
65+
<IdentNode start='19' end='29'>
66+
<name>generator1</name>
67+
<isPropertyName/>
68+
</IdentNode>
69+
<!-- ClassElement Value -->
70+
<FunctionNode name='generator1' kind='GENERATOR' start='19' end='78'>
71+
<isMethod/>
72+
<isNamedFunctionExpression/>
73+
<!-- FunctionNode Parameters -->
74+
<!-- FunctionNode Body -->
75+
<Block start='32' end='72'>
76+
<isFunctionBody/>
77+
<!-- Block Statements -->
78+
<ExpressionStatement start='42' end='50'>
79+
<UnaryNode type='YIELD' start='42' end='49'>
80+
<!-- UnaryNode Expression -->
81+
<NumberLiteralNode value='1' start='48' end='49'/>
82+
</UnaryNode>
83+
</ExpressionStatement>
84+
<ExpressionStatement start='59' end='72'>
85+
<UnaryNode type='YIELD' start='59' end='71'>
86+
<!-- UnaryNode Expression -->
87+
<BinaryNode type='ADD' start='65' end='71'>
88+
<!-- BinaryNode lhs -->
89+
<NumberLiteralNode value='1' start='65' end='66'/>
90+
<!-- BinaryNode rhs -->
91+
<NumberLiteralNode value='10' start='69' end='71'/>
92+
</BinaryNode>
93+
</UnaryNode>
94+
</ExpressionStatement>
95+
</Block>
96+
</FunctionNode>
97+
<!-- ClassElement Decorators -->
98+
</ClassElement>
99+
<ClassElement name='generator2' start='86' end='146'>
100+
<!-- ClassElement Key -->
101+
<IdentNode start='86' end='96'>
102+
<name>generator2</name>
103+
<isPropertyName/>
104+
</IdentNode>
105+
<!-- ClassElement Value -->
106+
<FunctionNode name='generator2' kind='GENERATOR' start='86' end='146'>
107+
<isMethod/>
108+
<isNamedFunctionExpression/>
109+
<!-- FunctionNode Parameters -->
110+
<IdentNode start='97' end='98'>
111+
<name>i</name>
112+
</IdentNode>
113+
<!-- FunctionNode Body -->
114+
<Block start='100' end='140'>
115+
<isFunctionBody/>
116+
<!-- Block Statements -->
117+
<ExpressionStatement start='110' end='118'>
118+
<UnaryNode type='YIELD' start='110' end='117'>
119+
<!-- UnaryNode Expression -->
120+
<IdentNode start='116' end='117'>
121+
<name>i</name>
122+
</IdentNode>
123+
</UnaryNode>
124+
</ExpressionStatement>
125+
<ExpressionStatement start='127' end='140'>
126+
<UnaryNode type='YIELD' start='127' end='139'>
127+
<!-- UnaryNode Expression -->
128+
<BinaryNode type='ADD' start='133' end='139'>
129+
<!-- BinaryNode lhs -->
130+
<IdentNode start='133' end='134'>
131+
<name>i</name>
132+
</IdentNode>
133+
<!-- BinaryNode rhs -->
134+
<NumberLiteralNode value='10' start='137' end='139'/>
135+
</BinaryNode>
136+
</UnaryNode>
137+
</ExpressionStatement>
138+
</Block>
139+
</FunctionNode>
140+
<!-- ClassElement Decorators -->
141+
</ClassElement>
142+
<ClassElement name='generator3' start='160' end='219'>
143+
<!-- ClassElement Key -->
144+
<IdentNode start='160' end='170'>
145+
<name>generator3</name>
146+
<isPropertyName/>
147+
</IdentNode>
148+
<!-- ClassElement Value -->
149+
<FunctionNode name='generator3' kind='GENERATOR' start='160' end='219'>
150+
<isMethod/>
151+
<isNamedFunctionExpression/>
152+
<isAsync/>
153+
<!-- FunctionNode Parameters -->
154+
<!-- FunctionNode Body -->
155+
<Block start='173' end='213'>
156+
<isFunctionBody/>
157+
<!-- Block Statements -->
158+
<ExpressionStatement start='183' end='191'>
159+
<UnaryNode type='YIELD' start='183' end='190'>
160+
<!-- UnaryNode Expression -->
161+
<NumberLiteralNode value='1' start='189' end='190'/>
162+
</UnaryNode>
163+
</ExpressionStatement>
164+
<ExpressionStatement start='200' end='213'>
165+
<UnaryNode type='YIELD' start='200' end='212'>
166+
<!-- UnaryNode Expression -->
167+
<BinaryNode type='ADD' start='206' end='212'>
168+
<!-- BinaryNode lhs -->
169+
<NumberLiteralNode value='1' start='206' end='207'/>
170+
<!-- BinaryNode rhs -->
171+
<NumberLiteralNode value='10' start='210' end='212'/>
172+
</BinaryNode>
173+
</UnaryNode>
174+
</ExpressionStatement>
175+
</Block>
176+
</FunctionNode>
177+
<!-- ClassElement Decorators -->
178+
</ClassElement>
179+
<ClassElement name='generator4' start='233' end='293'>
180+
<!-- ClassElement Key -->
181+
<IdentNode start='233' end='243'>
182+
<name>generator4</name>
183+
<isPropertyName/>
184+
</IdentNode>
185+
<!-- ClassElement Value -->
186+
<FunctionNode name='generator4' kind='GENERATOR' start='233' end='293'>
187+
<isMethod/>
188+
<isNamedFunctionExpression/>
189+
<isAsync/>
190+
<!-- FunctionNode Parameters -->
191+
<IdentNode start='244' end='245'>
192+
<name>i</name>
193+
</IdentNode>
194+
<!-- FunctionNode Body -->
195+
<Block start='247' end='287'>
196+
<isFunctionBody/>
197+
<!-- Block Statements -->
198+
<ExpressionStatement start='257' end='265'>
199+
<UnaryNode type='YIELD' start='257' end='264'>
200+
<!-- UnaryNode Expression -->
201+
<IdentNode start='263' end='264'>
202+
<name>i</name>
203+
</IdentNode>
204+
</UnaryNode>
205+
</ExpressionStatement>
206+
<ExpressionStatement start='274' end='287'>
207+
<UnaryNode type='YIELD' start='274' end='286'>
208+
<!-- UnaryNode Expression -->
209+
<BinaryNode type='ADD' start='280' end='286'>
210+
<!-- BinaryNode lhs -->
211+
<IdentNode start='280' end='281'>
212+
<name>i</name>
213+
</IdentNode>
214+
<!-- BinaryNode rhs -->
215+
<NumberLiteralNode value='10' start='284' end='286'/>
216+
</BinaryNode>
217+
</UnaryNode>
218+
</ExpressionStatement>
219+
</Block>
220+
</FunctionNode>
221+
<!-- ClassElement Decorators -->
222+
</ClassElement>
223+
<!-- ClassNode Decorators -->
224+
</ClassNode>
225+
</VarNode>
226+
</Block>
227+
</FunctionNode>

webcommon/javascript2.editor/test/unit/src/org/netbeans/modules/javascript2/editor/parser/AstTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,6 +2054,10 @@ public void testStaticGeneratorMethod() throws Exception {
20542054
checkAstResult("testfiles/ecmascript6/parser/ES6/generator/static-generator-method.js");
20552055
}
20562056

2057+
public void testGeneratorClassMethod() throws Exception {
2058+
checkAstResult("testfiles/ecmascript6/parser/ES6/generator/generator-class-method.js");
2059+
}
2060+
20572061
public void testDakutenHandakuten() throws Exception {
20582062
checkAstResult("testfiles/ecmascript6/parser/ES6/identifier/dakuten_handakuten.js");
20592063
}

webcommon/libs.nashorn/src/com/oracle/js/parser/Parser.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,7 +1329,7 @@ && lookaheadIsAsyncFunction(true)) {
13291329
next();
13301330
}
13311331
boolean generator = false;
1332-
if (!async && type == MUL && isAtLeastES6()) {
1332+
if (type == MUL && isAtLeastES6() && ((!async) || isAtLeastES9())) {
13331333
generator = true;
13341334
next();
13351335
}
@@ -1480,7 +1480,7 @@ private ClassElement classElement(boolean isStatic, boolean subclass, boolean ge
14801480
endOfLine();
14811481
return ClassElement.createField(methodToken, finish, propertyName, assignment, decorators, isStatic, computed);
14821482
}
1483-
PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, false, flags, computed);
1483+
PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, async, flags, computed);
14841484
if((flags & FunctionNode.IS_CLASS_CONSTRUCTOR) == FunctionNode.IS_CLASS_CONSTRUCTOR) {
14851485
return ClassElement.createDefaultConstructor(methodToken, finish, methodDefinition.key, methodDefinition.functionNode);
14861486
} else {
@@ -6180,6 +6180,8 @@ private boolean lookaheadIsAsyncFunction(boolean method) {
61806180
long token = getToken(k + i);
61816181
TokenType t = Token.descType(token);
61826182
switch (t) {
6183+
case MUL:
6184+
continue;
61836185
case COMMENT:
61846186
continue;
61856187
case FUNCTION:

webcommon/libs.nashorn/test/unit/src/com/oracle/js/parser/ParserTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,17 @@ public void testTopLevelAwait() {
346346
assertParses(12, false, true, "function dummy() {await Promise.resolve(1);}");
347347
}
348348

349+
@Test
350+
public void testAsyncGenerator() {
351+
assertParsesNot(8, "class Demo {\nasync * generator() {\nyield i;\nyield i + 10;\n}\n}");
352+
assertParses("class Demo {\nasync * generator() {\nyield 1;\nyield 1 + 10;\n}\n}");
353+
assertParses("class Demo {\nasync * generator(i) {\nyield i;\nyield i + 10;\n}\n}");
354+
assertParsesNot(8, "class Demo {\nasync * [Symbol.asyncIterator]() {\nyield i;\nyield i + 10;\n}\n}");
355+
assertParses("class Demo {\nasync * [Symbol.asyncIterator]() {\nyield 1;\nyield 1 + 10;\n}\n}");
356+
assertParses("class Demo {\nasync * [Symbol.asyncIterator](i) {\nyield i;\nyield i + 10;\n}\n}");
357+
assertParses("class Demo {\nasync * [Symbol.asyncIterator]() {\nyield await this.next();\n}\n}");
358+
}
359+
349360
private Predicate<Node> functionNodeWithName(String name) {
350361
return n -> n instanceof FunctionNode && name.equals(((FunctionNode) n).getName());
351362
}

0 commit comments

Comments
 (0)