@@ -72,6 +72,49 @@ pp.isAsyncFunction = function() {
72
72
! ( isIdentifierChar ( after = this . input . charCodeAt ( next + 8 ) ) || after > 0xd7ff && after < 0xdc00 ) )
73
73
}
74
74
75
+ pp . isUsingKeyword = function ( isAwaitUsing , isFor ) {
76
+ if ( this . options . ecmaVersion < 17 || ! this . isContextual ( isAwaitUsing ? "await" : "using" ) )
77
+ return false
78
+
79
+ skipWhiteSpace . lastIndex = this . pos
80
+ let skip = skipWhiteSpace . exec ( this . input )
81
+ let next = this . pos + skip [ 0 ] . length
82
+
83
+ if ( lineBreak . test ( this . input . slice ( this . pos , next ) ) ) return false
84
+
85
+ if ( isAwaitUsing ) {
86
+ let awaitEndPos = next + 5 /* await */ , after
87
+ if ( this . input . slice ( next , awaitEndPos ) !== "using" ||
88
+ awaitEndPos === this . input . length ||
89
+ isIdentifierChar ( after = this . input . charCodeAt ( awaitEndPos ) ) ||
90
+ ( after > 0xd7ff && after < 0xdc00 )
91
+ ) return false
92
+
93
+ skipWhiteSpace . lastIndex = awaitEndPos
94
+ let skipAfterUsing = skipWhiteSpace . exec ( this . input )
95
+ if ( skipAfterUsing && lineBreak . test ( this . input . slice ( awaitEndPos , awaitEndPos + skipAfterUsing [ 0 ] . length ) ) ) return false
96
+ }
97
+
98
+ if ( isFor ) {
99
+ let ofEndPos = next + 2 /* of */ , after
100
+ if ( this . input . slice ( next , ofEndPos ) === "of" ) {
101
+ if ( ofEndPos === this . input . length ||
102
+ ( ! isIdentifierChar ( after = this . input . charCodeAt ( ofEndPos ) ) && ! ( after > 0xd7ff && after < 0xdc00 ) ) ) return false
103
+ }
104
+ }
105
+
106
+ let ch = this . input . charCodeAt ( next )
107
+ return isIdentifierStart ( ch , true ) || ch === 92 // '\'
108
+ }
109
+
110
+ pp . isAwaitUsing = function ( isFor ) {
111
+ return this . isUsingKeyword ( true , isFor )
112
+ }
113
+
114
+ pp . isUsing = function ( isFor ) {
115
+ return this . isUsingKeyword ( false , isFor )
116
+ }
117
+
75
118
// Parse a single statement.
76
119
//
77
120
// If expecting a statement and finding a slash operator, parse a
@@ -148,6 +191,23 @@ pp.parseStatement = function(context, topLevel, exports) {
148
191
return this . parseFunctionStatement ( node , true , ! context )
149
192
}
150
193
194
+ let usingKind = this . isAwaitUsing ( false ) ? "await using" : this . isUsing ( false ) ? "using" : null
195
+ if ( usingKind ) {
196
+ if ( topLevel && this . options . sourceType === "script" ) {
197
+ this . raise ( this . start , "Using declaration cannot appear in the top level when source type is `script`" )
198
+ }
199
+ if ( usingKind === "await using" ) {
200
+ if ( ! this . canAwait ) {
201
+ this . raise ( this . start , "Await using cannot appear outside of async function" )
202
+ }
203
+ this . next ( )
204
+ }
205
+ this . next ( )
206
+ this . parseVar ( node , false , usingKind )
207
+ this . semicolon ( )
208
+ return this . finishNode ( node , "VariableDeclaration" )
209
+ }
210
+
151
211
let maybeName = this . value , expr = this . parseExpression ( )
152
212
if ( starttype === tt . name && expr . type === "Identifier" && this . eat ( tt . colon ) )
153
213
return this . parseLabeledStatement ( node , maybeName , expr , context )
@@ -223,18 +283,19 @@ pp.parseForStatement = function(node) {
223
283
this . next ( )
224
284
this . parseVar ( init , true , kind )
225
285
this . finishNode ( init , "VariableDeclaration" )
226
- if ( ( this . type === tt . _in || ( this . options . ecmaVersion >= 6 && this . isContextual ( "of" ) ) ) && init . declarations . length === 1 ) {
227
- if ( this . options . ecmaVersion >= 9 ) {
228
- if ( this . type === tt . _in ) {
229
- if ( awaitAt > - 1 ) this . unexpected ( awaitAt )
230
- } else node . await = awaitAt > - 1
231
- }
232
- return this . parseForIn ( node , init )
233
- }
234
- if ( awaitAt > - 1 ) this . unexpected ( awaitAt )
235
- return this . parseFor ( node , init )
286
+ return this . parseForAfterInit ( node , init , awaitAt )
236
287
}
237
288
let startsWithLet = this . isContextual ( "let" ) , isForOf = false
289
+
290
+ let usingKind = this . isUsing ( true ) ? "using" : this . isAwaitUsing ( true ) ? "await using" : null
291
+ if ( usingKind ) {
292
+ let init = this . startNode ( )
293
+ this . next ( )
294
+ if ( usingKind === "await using" ) this . next ( )
295
+ this . parseVar ( init , true , usingKind )
296
+ this . finishNode ( init , "VariableDeclaration" )
297
+ return this . parseForAfterInit ( node , init , awaitAt )
298
+ }
238
299
let containsEsc = this . containsEsc
239
300
let refDestructuringErrors = new DestructuringErrors
240
301
let initPos = this . start
@@ -260,6 +321,20 @@ pp.parseForStatement = function(node) {
260
321
return this . parseFor ( node , init )
261
322
}
262
323
324
+ // Helper method to parse for loop after variable initialization
325
+ pp . parseForAfterInit = function ( node , init , awaitAt ) {
326
+ if ( ( this . type === tt . _in || ( this . options . ecmaVersion >= 6 && this . isContextual ( "of" ) ) ) && init . declarations . length === 1 ) {
327
+ if ( this . options . ecmaVersion >= 9 ) {
328
+ if ( this . type === tt . _in ) {
329
+ if ( awaitAt > - 1 ) this . unexpected ( awaitAt )
330
+ } else node . await = awaitAt > - 1
331
+ }
332
+ return this . parseForIn ( node , init )
333
+ }
334
+ if ( awaitAt > - 1 ) this . unexpected ( awaitAt )
335
+ return this . parseFor ( node , init )
336
+ }
337
+
263
338
pp . parseFunctionStatement = function ( node , isAsync , declarationPosition ) {
264
339
this . next ( )
265
340
return this . parseFunction ( node , FUNC_STATEMENT | ( declarationPosition ? 0 : FUNC_HANGING_STATEMENT ) , false , isAsync )
@@ -511,6 +586,8 @@ pp.parseVar = function(node, isFor, kind, allowMissingInitializer) {
511
586
decl . init = this . parseMaybeAssign ( isFor )
512
587
} else if ( ! allowMissingInitializer && kind === "const" && ! ( this . type === tt . _in || ( this . options . ecmaVersion >= 6 && this . isContextual ( "of" ) ) ) ) {
513
588
this . unexpected ( )
589
+ } else if ( ! allowMissingInitializer && ( kind === "using" || kind === "await using" ) && this . options . ecmaVersion >= 17 && this . type !== tt . _in && ! this . isContextual ( "of" ) ) {
590
+ this . raise ( this . lastTokEnd , `Missing initializer in ${ kind } declaration` )
514
591
} else if ( ! allowMissingInitializer && decl . id . type !== "Identifier" && ! ( isFor && ( this . type === tt . _in || this . isContextual ( "of" ) ) ) ) {
515
592
this . raise ( this . lastTokEnd , "Complex binding patterns require an initialization value" )
516
593
} else {
@@ -523,7 +600,10 @@ pp.parseVar = function(node, isFor, kind, allowMissingInitializer) {
523
600
}
524
601
525
602
pp . parseVarId = function ( decl , kind ) {
526
- decl . id = this . parseBindingAtom ( )
603
+ decl . id = kind === "using" || kind === "await using"
604
+ ? this . parseIdent ( )
605
+ : this . parseBindingAtom ( )
606
+
527
607
this . checkLValPattern ( decl . id , kind === "var" ? BIND_VAR : BIND_LEXICAL , false )
528
608
}
529
609
0 commit comments