@@ -270,6 +270,212 @@ fn parse_for_statement(t: &[TokenData], index: &mut usize) -> Result<Statement,
270270 * index += 1 ;
271271 }
272272
273+ // Check for `using` or `await using` in the for-head
274+ // `for (using x = expr; ...; ...)` or `for (using x of iterable)` or
275+ // `for (await using x of iterable)` or `for (await using x = expr; ...; ...)`
276+ {
277+ // Detect `await using` inside the parens: `for (await using ...)`
278+ // In this case, `await` is NOT the `for await` syntax but an `await using` declaration.
279+ let is_await_using_in_parens = matches ! ( t[ * index] . token, Token :: Await ) && {
280+ let mut pk = * index + 1 ;
281+ while pk < t. len ( ) && matches ! ( t[ pk] . token, Token :: LineTerminator ) {
282+ pk += 1 ;
283+ }
284+ matches ! ( & t[ pk] . token, Token :: Identifier ( n) if n == "using" )
285+ } ;
286+ if is_await_using_in_parens {
287+ // Consume `await`; the `using` handling below will pick up the rest.
288+ // Mark this as an await-using declaration context.
289+ * index += 1 ;
290+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
291+ * index += 1 ;
292+ }
293+ is_for_await = true ;
294+ }
295+
296+ let is_using_kw = matches ! ( & t[ * index] . token, Token :: Identifier ( n) if n == "using" ) ;
297+ if is_using_kw {
298+ // Peek ahead: `using` followed by an identifier means a using declaration
299+ let mut peek = * index + 1 ;
300+ while peek < t. len ( ) && matches ! ( t[ peek] . token, Token :: LineTerminator ) {
301+ peek += 1 ;
302+ }
303+ let next_is_ident = peek < t. len ( ) && matches ! ( & t[ peek] . token, Token :: Identifier ( _) ) ;
304+
305+ // Special case: `for (using of ...` where `of` is the identifier after `using`.
306+ // Per spec, `using of` is only a using-declaration if followed by `=`
307+ // (i.e., `for (using of = expr; ...; ...)`). Otherwise, `using` is just
308+ // an identifier and `of` is the for-of keyword.
309+ let is_using_of = next_is_ident && matches ! ( & t[ peek] . token, Token :: Identifier ( n) if n == "of" ) ;
310+ let using_of_is_decl = if is_using_of {
311+ let mut peek2 = peek + 1 ;
312+ while peek2 < t. len ( ) && matches ! ( t[ peek2] . token, Token :: LineTerminator ) {
313+ peek2 += 1 ;
314+ }
315+ peek2 < t. len ( ) && matches ! ( t[ peek2] . token, Token :: Assign )
316+ } else {
317+ false
318+ } ;
319+
320+ let enter_using_path = next_is_ident && ( is_await_using_in_parens || !is_using_of || using_of_is_decl) ;
321+
322+ if enter_using_path {
323+ * index += 1 ; // consume `using`
324+ // Skip line terminators
325+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
326+ * index += 1 ;
327+ }
328+ // Parse the first binding name
329+ let first_name = match & t[ * index] . token {
330+ Token :: Identifier ( n) => n. clone ( ) ,
331+ _ => return Err ( raise_parse_error_at ! ( t. get( * index) ) ) ,
332+ } ;
333+ * index += 1 ;
334+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
335+ * index += 1 ;
336+ }
337+
338+ // Check if followed by `of` (for-of/for-await-of with using)
339+ if * index < t. len ( ) && matches ! ( & t[ * index] . token, Token :: Identifier ( n) if n == "of" ) {
340+ * index += 1 ; // consume `of`
341+ let iterable = parse_assignment ( t, index) ?;
342+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
343+ * index += 1 ;
344+ }
345+ if !matches ! ( t[ * index] . token, Token :: RParen ) {
346+ return Err ( raise_parse_error_at ! ( t. get( * index) ) ) ;
347+ }
348+ * index += 1 ; // consume )
349+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
350+ * index += 1 ;
351+ }
352+ let body = parse_statement_item ( t, index) ?;
353+ let body_stmts = match * body. kind {
354+ StatementKind :: Block ( b) => b,
355+ _ => vec ! [ body] ,
356+ } ;
357+ let kind = if is_for_await {
358+ StatementKind :: ForAwaitOf ( Some ( crate :: core:: VarDeclKind :: AwaitUsing ) , first_name, iterable, body_stmts)
359+ } else {
360+ StatementKind :: ForOf ( Some ( crate :: core:: VarDeclKind :: Using ) , first_name, iterable, body_stmts)
361+ } ;
362+ return Ok ( Statement {
363+ kind : Box :: new ( kind) ,
364+ line,
365+ column,
366+ } ) ;
367+ }
368+
369+ // C-style for with using: `for (using x = expr, ...; test; update) body`
370+ if !matches ! ( t[ * index] . token, Token :: Assign ) {
371+ return Err ( raise_parse_error ! ( "using declarations must have an initializer" , line, column) ) ;
372+ }
373+ * index += 1 ; // consume `=`
374+ let first_init = parse_assignment ( t, index) ?;
375+ let mut using_decls = vec ! [ ( first_name, first_init) ] ;
376+
377+ // Check for comma-separated additional declarations
378+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: Comma ) {
379+ * index += 1 ;
380+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
381+ * index += 1 ;
382+ }
383+ let next_name = match & t[ * index] . token {
384+ Token :: Identifier ( n) => n. clone ( ) ,
385+ _ => return Err ( raise_parse_error_at ! ( t. get( * index) ) ) ,
386+ } ;
387+ * index += 1 ;
388+ if !matches ! ( t[ * index] . token, Token :: Assign ) {
389+ return Err ( raise_parse_error ! ( "using declarations must have an initializer" , line, column) ) ;
390+ }
391+ * index += 1 ; // consume `=`
392+ let next_init = parse_assignment ( t, index) ?;
393+ using_decls. push ( ( next_name, next_init) ) ;
394+ }
395+
396+ // Skip line terminators before the first semicolon
397+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
398+ * index += 1 ;
399+ }
400+ if !matches ! ( t[ * index] . token, Token :: Semicolon ) {
401+ return Err ( raise_parse_error_at ! ( t. get( * index) ) ) ;
402+ }
403+ * index += 1 ; // consume ;
404+
405+ // Parse test expression
406+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
407+ * index += 1 ;
408+ }
409+ let test = if !matches ! ( t[ * index] . token, Token :: Semicolon ) {
410+ Some ( parse_expression ( t, index) ?)
411+ } else {
412+ None
413+ } ;
414+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
415+ * index += 1 ;
416+ }
417+ if !matches ! ( t[ * index] . token, Token :: Semicolon ) {
418+ return Err ( raise_parse_error_at ! ( t. get( * index) ) ) ;
419+ }
420+ * index += 1 ; // consume ;
421+
422+ // Parse update expression
423+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
424+ * index += 1 ;
425+ }
426+ let update = if !matches ! ( t[ * index] . token, Token :: RParen ) {
427+ Some ( parse_expression ( t, index) ?)
428+ } else {
429+ None
430+ } ;
431+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
432+ * index += 1 ;
433+ }
434+ if !matches ! ( t[ * index] . token, Token :: RParen ) {
435+ return Err ( raise_parse_error_at ! ( t. get( * index) ) ) ;
436+ }
437+ * index += 1 ; // consume )
438+
439+ while * index < t. len ( ) && matches ! ( t[ * index] . token, Token :: LineTerminator ) {
440+ * index += 1 ;
441+ }
442+ let body = parse_statement_item ( t, index) ?;
443+ let body_stmts = match * body. kind {
444+ StatementKind :: Block ( b) => b,
445+ _ => vec ! [ body] ,
446+ } ;
447+
448+ let init_stmt = Some ( Box :: new ( Statement {
449+ kind : Box :: new ( if is_for_await {
450+ StatementKind :: AwaitUsing ( using_decls)
451+ } else {
452+ StatementKind :: Using ( using_decls)
453+ } ) ,
454+ line,
455+ column,
456+ } ) ) ;
457+ let update_stmt = update. map ( |e| {
458+ Box :: new ( Statement {
459+ kind : Box :: new ( StatementKind :: Expr ( e) ) ,
460+ line,
461+ column,
462+ } )
463+ } ) ;
464+
465+ return Ok ( Statement {
466+ kind : Box :: new ( StatementKind :: For ( Box :: new ( ForStatement {
467+ init : init_stmt,
468+ test,
469+ update : update_stmt,
470+ body : body_stmts,
471+ } ) ) ) ,
472+ line,
473+ column,
474+ } ) ;
475+ }
476+ }
477+ }
478+
273479 // Check for declaration
274480 let is_decl = matches ! ( t[ * index] . token, Token :: Var | Token :: Let | Token :: Const ) ;
275481 log:: trace!( "parse_for_statement: is_decl={} token={:?}" , is_decl, t. get( * index) ) ;
0 commit comments