@@ -72,6 +72,49 @@ pp.isAsyncFunction = function() {
7272 ! ( isIdentifierChar ( after = this . input . charCodeAt ( next + 8 ) ) || after > 0xd7ff && after < 0xdc00 ) )
7373}
7474
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+
75118// Parse a single statement.
76119//
77120// If expecting a statement and finding a slash operator, parse a
@@ -148,6 +191,23 @@ pp.parseStatement = function(context, topLevel, exports) {
148191 return this . parseFunctionStatement ( node , true , ! context )
149192 }
150193
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+
151211 let maybeName = this . value , expr = this . parseExpression ( )
152212 if ( starttype === tt . name && expr . type === "Identifier" && this . eat ( tt . colon ) )
153213 return this . parseLabeledStatement ( node , maybeName , expr , context )
@@ -223,18 +283,19 @@ pp.parseForStatement = function(node) {
223283 this . next ( )
224284 this . parseVar ( init , true , kind )
225285 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 )
236287 }
237288 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+ }
238299 let containsEsc = this . containsEsc
239300 let refDestructuringErrors = new DestructuringErrors
240301 let initPos = this . start
@@ -260,6 +321,20 @@ pp.parseForStatement = function(node) {
260321 return this . parseFor ( node , init )
261322}
262323
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+
263338pp . parseFunctionStatement = function ( node , isAsync , declarationPosition ) {
264339 this . next ( )
265340 return this . parseFunction ( node , FUNC_STATEMENT | ( declarationPosition ? 0 : FUNC_HANGING_STATEMENT ) , false , isAsync )
@@ -511,6 +586,8 @@ pp.parseVar = function(node, isFor, kind, allowMissingInitializer) {
511586 decl . init = this . parseMaybeAssign ( isFor )
512587 } else if ( ! allowMissingInitializer && kind === "const" && ! ( this . type === tt . _in || ( this . options . ecmaVersion >= 6 && this . isContextual ( "of" ) ) ) ) {
513588 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` )
514591 } else if ( ! allowMissingInitializer && decl . id . type !== "Identifier" && ! ( isFor && ( this . type === tt . _in || this . isContextual ( "of" ) ) ) ) {
515592 this . raise ( this . lastTokEnd , "Complex binding patterns require an initialization value" )
516593 } else {
@@ -523,7 +600,10 @@ pp.parseVar = function(node, isFor, kind, allowMissingInitializer) {
523600}
524601
525602pp . parseVarId = function ( decl , kind ) {
526- decl . id = this . parseBindingAtom ( )
603+ decl . id = kind === "using" || kind === "await using"
604+ ? this . parseIdent ( )
605+ : this . parseBindingAtom ( )
606+
527607 this . checkLValPattern ( decl . id , kind === "var" ? BIND_VAR : BIND_LEXICAL , false )
528608}
529609
0 commit comments