Skip to main content

nodejs/
parser.rs

1//! JavaScript parser: token stream → AST.
2//!
3//! Recursive descent with precedence climbing for binary operators. Automatic
4//! Semicolon Insertion is applied at statement boundaries using the
5//! `newline_before` flag the lexer records on every token. Arrow functions are
6//! detected at assignment level by looking ahead for `=>` after a parameter
7//! list. Template-literal `${...}` fields are re-parsed here from the raw source
8//! the lexer captured.
9
10use crate::ast::*;
11use crate::lexer::{lex, Tok, Token};
12
13const KEYWORDS: &[&str] = &[
14    "var",
15    "let",
16    "const",
17    "function",
18    "return",
19    "if",
20    "else",
21    "while",
22    "do",
23    "for",
24    "of",
25    "in",
26    "switch",
27    "case",
28    "default",
29    "break",
30    "continue",
31    "true",
32    "false",
33    "null",
34    "this",
35    "new",
36    "typeof",
37    "void",
38    "delete",
39    "instanceof",
40    "throw",
41    "try",
42    "catch",
43    "finally",
44];
45
46fn is_keyword(s: &str) -> bool {
47    KEYWORDS.contains(&s)
48}
49
50struct Parser {
51    toks: Vec<Token>,
52    pos: usize,
53    /// True while parsing a generator body — enables `yield` as an operator.
54    in_generator: bool,
55    /// True while parsing an async body — enables `await` as an operator.
56    in_async: bool,
57    /// True while parsing a `for` init in LHS position — suppresses `in` as a
58    /// relational operator so `for (x in obj)` (no declaration keyword) parses
59    /// the `in` as the loop separator, not a binary expression. Cleared inside
60    /// any parenthesised/bracketed sub-expression, where `in` is legal again.
61    no_in: bool,
62}
63
64/// Parse a complete JS program into a statement list. Inline `rust { ... }` FFI
65/// blocks are desugared to `__rust_compile(...)` calls before lexing.
66pub fn parse(src: &str) -> Result<Vec<Stmt>, String> {
67    let src = crate::rust_ffi::desugar(src);
68    let toks = lex(&src)?;
69    let mut p = Parser {
70        toks,
71        pos: 0,
72        in_generator: false,
73        in_async: false,
74        no_in: false,
75    };
76    let mut out = Vec::new();
77    while !p.at_eof() {
78        out.push(p.parse_stmt()?);
79    }
80    Ok(out)
81}
82
83impl Parser {
84    // ── token helpers ────────────────────────────────────────────────────
85    fn cur(&self) -> &Token {
86        &self.toks[self.pos]
87    }
88    fn tok(&self) -> &Tok {
89        &self.toks[self.pos].tok
90    }
91    fn line(&self) -> u32 {
92        self.toks[self.pos].line
93    }
94    fn at_eof(&self) -> bool {
95        matches!(self.tok(), Tok::Eof)
96    }
97    fn newline_before(&self) -> bool {
98        self.cur().newline_before
99    }
100    fn advance(&mut self) -> Tok {
101        let t = self.toks[self.pos].tok.clone();
102        if self.pos + 1 < self.toks.len() {
103            self.pos += 1;
104        }
105        t
106    }
107
108    /// True if the current token is the punctuation `s`.
109    fn is_punct(&self, s: &str) -> bool {
110        matches!(self.tok(), Tok::Punct(p) if p == s)
111    }
112    /// True if the current token is the identifier/keyword `s`.
113    fn is_kw(&self, s: &str) -> bool {
114        matches!(self.tok(), Tok::Ident(i) if i == s)
115    }
116    /// Consume the punctuation `s` if present.
117    fn eat_punct(&mut self, s: &str) -> bool {
118        if self.is_punct(s) {
119            self.advance();
120            true
121        } else {
122            false
123        }
124    }
125    fn eat_kw(&mut self, s: &str) -> bool {
126        if self.is_kw(s) {
127            self.advance();
128            true
129        } else {
130            false
131        }
132    }
133    fn expect_punct(&mut self, s: &str) -> Result<(), String> {
134        if self.eat_punct(s) {
135            Ok(())
136        } else {
137            Err(format!(
138                "SyntaxError: expected '{s}' but found {:?} (line {})",
139                self.tok(),
140                self.line()
141            ))
142        }
143    }
144
145    /// Consume an identifier name (any non-punct ident, including keywords used
146    /// as property names when `allow_kw`).
147    fn ident_name(&mut self) -> Result<String, String> {
148        match self.tok().clone() {
149            Tok::Ident(s) => {
150                self.advance();
151                Ok(s)
152            }
153            other => Err(format!(
154                "SyntaxError: expected identifier but found {other:?} (line {})",
155                self.line()
156            )),
157        }
158    }
159
160    /// Apply ASI: consume an explicit `;`, or accept a newline / `}` / EOF.
161    fn semicolon(&mut self) -> Result<(), String> {
162        if self.eat_punct(";") {
163            return Ok(());
164        }
165        if self.newline_before() || self.is_punct("}") || self.at_eof() {
166            return Ok(());
167        }
168        Err(format!(
169            "SyntaxError: expected ';' but found {:?} (line {})",
170            self.tok(),
171            self.line()
172        ))
173    }
174
175    // ── statements ───────────────────────────────────────────────────────
176    fn parse_stmt(&mut self) -> Result<Stmt, String> {
177        let line = self.line();
178        let kind = match self.tok().clone() {
179            Tok::Punct(p) if p == "{" => {
180                self.advance();
181                StmtKind::Block(self.parse_block_body()?)
182            }
183            Tok::Punct(p) if p == ";" => {
184                self.advance();
185                StmtKind::Empty
186            }
187            Tok::Ident(kw) if kw == "var" || kw == "let" || kw == "const" => {
188                let k = self.parse_decl_kind();
189                let decls = self.parse_declarators()?;
190                self.semicolon()?;
191                StmtKind::Decl { kind: k, decls }
192            }
193            Tok::Ident(kw) if kw == "function" => self.parse_func_decl(false)?,
194            // `async function …` (declaration). `async` stays a plain identifier
195            // anywhere else (contextual keyword).
196            Tok::Ident(kw)
197                if kw == "async" && self.peek_kw(1, "function") && !self.peek_newline(1) =>
198            {
199                self.advance(); // async
200                self.parse_func_decl(true)?
201            }
202            Tok::Ident(kw) if kw == "class" => {
203                let node = self.parse_class(true)?;
204                StmtKind::ClassDecl(node)
205            }
206            Tok::Ident(kw) if kw == "if" => self.parse_if()?,
207            Tok::Ident(kw) if kw == "while" => self.parse_while()?,
208            Tok::Ident(kw) if kw == "do" => self.parse_do_while()?,
209            Tok::Ident(kw) if kw == "for" => self.parse_for()?,
210            Tok::Ident(kw) if kw == "switch" => self.parse_switch()?,
211            Tok::Ident(kw) if kw == "return" => {
212                self.advance();
213                let arg = if self.is_punct(";")
214                    || self.is_punct("}")
215                    || self.newline_before()
216                    || self.at_eof()
217                {
218                    None
219                } else {
220                    Some(self.parse_expr()?)
221                };
222                self.semicolon()?;
223                StmtKind::Return(arg)
224            }
225            Tok::Ident(kw) if kw == "break" => {
226                self.advance();
227                let label = self.opt_label();
228                self.semicolon()?;
229                StmtKind::Break(label)
230            }
231            Tok::Ident(kw) if kw == "continue" => {
232                self.advance();
233                let label = self.opt_label();
234                self.semicolon()?;
235                StmtKind::Continue(label)
236            }
237            Tok::Ident(kw) if kw == "throw" => {
238                self.advance();
239                let e = self.parse_expr()?;
240                self.semicolon()?;
241                StmtKind::Throw(e)
242            }
243            Tok::Ident(kw) if kw == "try" => self.parse_try()?,
244            // `label: stmt` — a bare identifier immediately followed by `:` at
245            // statement position is a label (never an expression; the reserved
246            // control keywords are all matched above, and switch `case`/`default`
247            // labels are parsed inside `parse_switch`).
248            Tok::Ident(name) if matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":") =>
249            {
250                self.advance(); // the label identifier
251                self.advance(); // the ':'
252                let body = Box::new(self.parse_stmt()?);
253                StmtKind::Labeled { label: name, body }
254            }
255            _ => {
256                let e = self.parse_expr()?;
257                self.semicolon()?;
258                StmtKind::Expr(e)
259            }
260        };
261        Ok(Stmt::new(kind, line))
262    }
263
264    /// Whether the token `n` ahead is the identifier `kw`.
265    fn peek_kw(&self, n: usize, kw: &str) -> bool {
266        matches!(self.toks.get(self.pos + n).map(|t| &t.tok), Some(Tok::Ident(s)) if s == kw)
267    }
268    /// Whether the token `n` ahead has a newline before it.
269    fn peek_newline(&self, n: usize) -> bool {
270        self.toks
271            .get(self.pos + n)
272            .map(|t| t.newline_before)
273            .unwrap_or(false)
274    }
275
276    /// Parse a `function` declaration (the `function`/`async function` keyword is
277    /// current). `is_async` is true when a preceding `async` was consumed.
278    fn parse_func_decl(&mut self, is_async: bool) -> Result<StmtKind, String> {
279        self.advance(); // function
280        let is_generator = self.eat_punct("*");
281        let name = self.ident_name()?;
282        let params = self.parse_params()?;
283        self.expect_punct("{")?;
284        let body = self.parse_fn_body_block(is_generator, is_async)?;
285        Ok(StmtKind::FuncDecl {
286            name,
287            params,
288            body,
289            is_generator,
290            is_async,
291        })
292    }
293
294    /// Parse a brace-delimited function body under the given generator/async
295    /// context (so `yield`/`await` inside are operators, not identifiers).
296    fn parse_fn_body_block(
297        &mut self,
298        is_generator: bool,
299        is_async: bool,
300    ) -> Result<Vec<Stmt>, String> {
301        let (pg, pa) = (self.in_generator, self.in_async);
302        self.in_generator = is_generator;
303        self.in_async = is_async;
304        let body = self.parse_block_body();
305        self.in_generator = pg;
306        self.in_async = pa;
307        body
308    }
309
310    /// Parse a function *expression* (`function`/`async function`, keyword
311    /// current). Supports `function*` generators.
312    fn parse_function_expr(&mut self, is_async: bool) -> Result<Expr, String> {
313        self.advance(); // function
314        let is_generator = self.eat_punct("*");
315        let name = if let Tok::Ident(n) = self.tok() {
316            if !is_keyword(n) {
317                let n = n.clone();
318                self.advance();
319                Some(n)
320            } else {
321                None
322            }
323        } else {
324            None
325        };
326        let params = self.parse_params()?;
327        self.expect_punct("{")?;
328        let body = self.parse_fn_body_block(is_generator, is_async)?;
329        Ok(Expr::Function {
330            params,
331            body: FnBody::Block(body),
332            is_arrow: false,
333            name,
334            is_generator,
335            is_async,
336        })
337    }
338
339    /// Parse a `class` (the `class` keyword is current). `_decl` distinguishes a
340    /// declaration (name required in strict mode, but we accept optional) from an
341    /// expression.
342    fn parse_class(&mut self, _decl: bool) -> Result<ClassNode, String> {
343        self.advance(); // class
344        let name = if let Tok::Ident(n) = self.tok() {
345            if !is_keyword(n) && n != "extends" {
346                let n = n.clone();
347                self.advance();
348                Some(n)
349            } else {
350                None
351            }
352        } else {
353            None
354        };
355        let parent = if self.eat_kw("extends") {
356            // The superclass is a left-hand-side expression (`extends Base`,
357            // `extends foo.Bar`).
358            Some(Box::new(self.parse_call_member()?))
359        } else {
360            None
361        };
362        self.expect_punct("{")?;
363        let mut members = Vec::new();
364        while !self.is_punct("}") && !self.at_eof() {
365            if self.eat_punct(";") {
366                continue; // stray semicolons between members
367            }
368            members.push(self.parse_class_member()?);
369        }
370        self.expect_punct("}")?;
371        Ok(ClassNode {
372            name,
373            parent,
374            members,
375        })
376    }
377
378    /// Parse one class member: `[static] [get|set|async|*] name(params){…}` or a
379    /// `[static] name [= init];` field.
380    fn parse_class_member(&mut self) -> Result<ClassMember, String> {
381        let is_static = self.is_kw("static") && !self.peek_is_member_punct(1) && {
382            self.advance();
383            true
384        };
385        // Accessor / async / generator prefixes (each contextual: only a prefix
386        // when followed by another member name, not itself the member name).
387        let mut kind = MemberKind::Method;
388        let mut is_async = false;
389        let mut is_generator = false;
390        if self.is_kw("get") && !self.peek_is_member_punct(1) {
391            self.advance();
392            kind = MemberKind::Get;
393        } else if self.is_kw("set") && !self.peek_is_member_punct(1) {
394            self.advance();
395            kind = MemberKind::Set;
396        } else {
397            if self.is_kw("async") && !self.peek_is_member_punct(1) && !self.peek_newline(1) {
398                self.advance();
399                is_async = true;
400            }
401            if self.eat_punct("*") {
402                is_generator = true;
403            }
404        }
405        // The member key (computed `[expr]`, string, number, or identifier).
406        let (key, computed) = self.parse_property_key()?;
407        // A field (no parentheses) vs a method.
408        if kind == MemberKind::Method && !self.is_punct("(") {
409            let field_init = if self.eat_punct("=") {
410                Some(self.parse_assign()?)
411            } else {
412                None
413            };
414            self.semicolon()?;
415            return Ok(ClassMember {
416                key,
417                computed,
418                kind: MemberKind::Field,
419                is_static,
420                is_generator: false,
421                is_async: false,
422                params: Vec::new(),
423                body: Vec::new(),
424                field_init,
425            });
426        }
427        // A method / accessor / constructor.
428        let is_ctor = !is_static
429            && !computed
430            && matches!(&key, Expr::Str(s) if s == "constructor")
431            && kind == MemberKind::Method;
432        let params = self.parse_params()?;
433        self.expect_punct("{")?;
434        let body = self.parse_fn_body_block(is_generator, is_async)?;
435        Ok(ClassMember {
436            key,
437            computed,
438            kind: if is_ctor {
439                MemberKind::Constructor
440            } else {
441                kind
442            },
443            is_static,
444            is_generator,
445            is_async,
446            params,
447            body,
448            field_init: None,
449        })
450    }
451
452    /// Whether the token `n` ahead is `(`, `=`, `;`, `}`, or a newline-boundary —
453    /// i.e. the current word is itself the member name, not a modifier prefix.
454    fn peek_is_member_punct(&self, n: usize) -> bool {
455        matches!(
456            self.toks.get(self.pos + n).map(|t| &t.tok),
457            Some(Tok::Punct(p)) if p == "(" || p == "=" || p == ";" || p == "}"
458        )
459    }
460
461    /// Parse a property key for a class member / object method: `[expr]` (computed),
462    /// a string, a number, or an identifier (returned as an `Expr::Str`).
463    fn parse_property_key(&mut self) -> Result<(Expr, bool), String> {
464        if self.is_punct("[") {
465            self.advance();
466            let k = self.parse_assign()?;
467            self.expect_punct("]")?;
468            Ok((k, true))
469        } else {
470            match self.tok().clone() {
471                Tok::Str(s) => {
472                    self.advance();
473                    Ok((Expr::Str(s), false))
474                }
475                Tok::Num(n) => {
476                    self.advance();
477                    Ok((Expr::Str(crate::host::fmt_number(n)), false))
478                }
479                Tok::Ident(s) => {
480                    self.advance();
481                    Ok((Expr::Str(s), false))
482                }
483                other => Err(format!(
484                    "SyntaxError: bad member key {other:?} (line {})",
485                    self.line()
486                )),
487            }
488        }
489    }
490
491    /// An optional non-newline label after break/continue.
492    fn opt_label(&mut self) -> Option<String> {
493        if self.newline_before() {
494            return None;
495        }
496        if let Tok::Ident(s) = self.tok() {
497            if !is_keyword(s) {
498                let s = s.clone();
499                self.advance();
500                return Some(s);
501            }
502        }
503        None
504    }
505
506    /// Parse statements up to (and consuming) the closing `}`.
507    fn parse_block_body(&mut self) -> Result<Vec<Stmt>, String> {
508        let mut out = Vec::new();
509        while !self.is_punct("}") && !self.at_eof() {
510            out.push(self.parse_stmt()?);
511        }
512        self.expect_punct("}")?;
513        Ok(out)
514    }
515
516    fn parse_decl_kind(&mut self) -> DeclKind {
517        let k = match self.tok() {
518            Tok::Ident(s) if s == "let" => DeclKind::Let,
519            Tok::Ident(s) if s == "const" => DeclKind::Const,
520            _ => DeclKind::Var,
521        };
522        self.advance();
523        k
524    }
525
526    fn parse_declarators(&mut self) -> Result<Vec<Declarator>, String> {
527        let mut decls = Vec::new();
528        loop {
529            let target = self.parse_binding_target()?;
530            let init = if self.eat_punct("=") {
531                Some(self.parse_assign()?)
532            } else {
533                None
534            };
535            decls.push(Declarator { target, init });
536            if !self.eat_punct(",") {
537                break;
538            }
539        }
540        Ok(decls)
541    }
542
543    /// A binding target: identifier or array/object destructuring pattern.
544    fn parse_binding_target(&mut self) -> Result<Expr, String> {
545        if self.is_punct("[") {
546            self.parse_array_literal()
547        } else if self.is_punct("{") {
548            self.parse_object_literal()
549        } else {
550            Ok(Expr::Ident(self.ident_name()?))
551        }
552    }
553
554    fn parse_if(&mut self) -> Result<StmtKind, String> {
555        self.advance(); // if
556        self.expect_punct("(")?;
557        let test = self.parse_expr()?;
558        self.expect_punct(")")?;
559        let cons = Box::new(self.parse_stmt()?);
560        let alt = if self.eat_kw("else") {
561            Some(Box::new(self.parse_stmt()?))
562        } else {
563            None
564        };
565        Ok(StmtKind::If { test, cons, alt })
566    }
567
568    fn parse_while(&mut self) -> Result<StmtKind, String> {
569        self.advance();
570        self.expect_punct("(")?;
571        let test = self.parse_expr()?;
572        self.expect_punct(")")?;
573        let body = Box::new(self.parse_stmt()?);
574        Ok(StmtKind::While { test, body })
575    }
576
577    fn parse_do_while(&mut self) -> Result<StmtKind, String> {
578        self.advance();
579        let body = Box::new(self.parse_stmt()?);
580        if !self.eat_kw("while") {
581            return Err(format!(
582                "SyntaxError: expected 'while' (line {})",
583                self.line()
584            ));
585        }
586        self.expect_punct("(")?;
587        let test = self.parse_expr()?;
588        self.expect_punct(")")?;
589        self.semicolon()?;
590        Ok(StmtKind::DoWhile { body, test })
591    }
592
593    fn parse_for(&mut self) -> Result<StmtKind, String> {
594        self.advance();
595        // `for await (… of …)` — the async-iteration form (valid in an async body).
596        let is_await = self.eat_kw("await");
597        self.expect_punct("(")?;
598        // Optional declaration or expression init.
599        let decl_kind = match self.tok() {
600            Tok::Ident(s) if s == "var" || s == "let" || s == "const" => {
601                Some(self.parse_decl_kind())
602            }
603            _ => None,
604        };
605        // Empty init: `for (;;)`.
606        if decl_kind.is_none() && self.is_punct(";") {
607            return self.parse_c_for(None);
608        }
609        // Parse the first binding/expression, then decide of/in vs C-style.
610        let first_target = if decl_kind.is_some() {
611            self.parse_binding_target()?
612        } else {
613            self.parse_expr_no_in()?
614        };
615        if self.eat_kw("of") {
616            let iter = self.parse_assign()?;
617            self.expect_punct(")")?;
618            let body = Box::new(self.parse_stmt()?);
619            return Ok(StmtKind::ForOf {
620                decl_kind,
621                target: first_target,
622                iter,
623                body,
624                is_await,
625            });
626        }
627        if self.eat_kw("in") {
628            let object = self.parse_assign()?;
629            self.expect_punct(")")?;
630            let body = Box::new(self.parse_stmt()?);
631            return Ok(StmtKind::ForIn {
632                decl_kind,
633                target: first_target,
634                object,
635                body,
636            });
637        }
638        // C-style: reconstruct the init statement.
639        let init_stmt = if let Some(k) = decl_kind {
640            let init = if self.eat_punct("=") {
641                Some(self.parse_assign()?)
642            } else {
643                None
644            };
645            let mut decls = vec![Declarator {
646                target: first_target,
647                init,
648            }];
649            while self.eat_punct(",") {
650                let target = self.parse_binding_target()?;
651                let init = if self.eat_punct("=") {
652                    Some(self.parse_assign()?)
653                } else {
654                    None
655                };
656                decls.push(Declarator { target, init });
657            }
658            StmtKind::Decl { kind: k, decls }
659        } else {
660            // A non-declaration C-style init may be a comma sequence
661            // (`for (i = 0, n = a.length; …)`) — extend past the first assignment.
662            let init = if self.is_punct(",") {
663                let mut items = vec![first_target];
664                while self.eat_punct(",") {
665                    items.push(self.parse_expr_no_in()?);
666                }
667                Expr::Sequence(items)
668            } else {
669                first_target
670            };
671            StmtKind::Expr(init)
672        };
673        self.parse_c_for(Some(Stmt::from(init_stmt)))
674    }
675
676    fn parse_c_for(&mut self, init: Option<Stmt>) -> Result<StmtKind, String> {
677        self.expect_punct(";")?;
678        let test = if self.is_punct(";") {
679            None
680        } else {
681            Some(self.parse_expr()?)
682        };
683        self.expect_punct(";")?;
684        let update = if self.is_punct(")") {
685            None
686        } else {
687            Some(self.parse_expr()?)
688        };
689        self.expect_punct(")")?;
690        let body = Box::new(self.parse_stmt()?);
691        Ok(StmtKind::For {
692            init: init.map(Box::new),
693            test,
694            update,
695            body,
696        })
697    }
698
699    fn parse_switch(&mut self) -> Result<StmtKind, String> {
700        self.advance();
701        self.expect_punct("(")?;
702        let disc = self.parse_expr()?;
703        self.expect_punct(")")?;
704        self.expect_punct("{")?;
705        let mut cases = Vec::new();
706        while !self.is_punct("}") && !self.at_eof() {
707            let test = if self.eat_kw("case") {
708                let e = self.parse_expr()?;
709                Some(e)
710            } else if self.eat_kw("default") {
711                None
712            } else {
713                return Err(format!(
714                    "SyntaxError: expected 'case' or 'default' (line {})",
715                    self.line()
716                ));
717            };
718            self.expect_punct(":")?;
719            let mut body = Vec::new();
720            while !self.is_punct("}")
721                && !self.is_kw("case")
722                && !self.is_kw("default")
723                && !self.at_eof()
724            {
725                body.push(self.parse_stmt()?);
726            }
727            cases.push(SwitchCase { test, body });
728        }
729        self.expect_punct("}")?;
730        Ok(StmtKind::Switch { disc, cases })
731    }
732
733    fn parse_try(&mut self) -> Result<StmtKind, String> {
734        self.advance();
735        self.expect_punct("{")?;
736        let block = self.parse_block_body()?;
737        let handler = if self.eat_kw("catch") {
738            let param = if self.eat_punct("(") {
739                let p = self.parse_binding_target()?;
740                self.expect_punct(")")?;
741                Some(p)
742            } else {
743                None
744            };
745            self.expect_punct("{")?;
746            let body = self.parse_block_body()?;
747            Some((param, body))
748        } else {
749            None
750        };
751        let finalizer = if self.eat_kw("finally") {
752            self.expect_punct("{")?;
753            Some(self.parse_block_body()?)
754        } else {
755            None
756        };
757        Ok(StmtKind::Try {
758            block,
759            handler,
760            finalizer,
761        })
762    }
763
764    // ── expressions ──────────────────────────────────────────────────────
765    /// Full expression, including the comma sequence operator.
766    fn parse_expr(&mut self) -> Result<Expr, String> {
767        let first = self.parse_assign()?;
768        if self.is_punct(",") {
769            let mut items = vec![first];
770            while self.eat_punct(",") {
771                items.push(self.parse_assign()?);
772            }
773            Ok(Expr::Sequence(items))
774        } else {
775            Ok(first)
776        }
777    }
778
779    /// Like `parse_expr` but stops before `in` (used in `for` init position).
780    fn parse_expr_no_in(&mut self) -> Result<Expr, String> {
781        // For simplicity the no-in variant only parses an assignment/LHS chain,
782        // which is sufficient for `for (x in ...)` / `for (x of ...)` heads.
783        let saved = self.no_in;
784        self.no_in = true;
785        let r = self.parse_assign();
786        self.no_in = saved;
787        r
788    }
789
790    /// Run `f` with `in` re-enabled (inside a parenthesised/bracketed sub-
791    /// expression of a `for` LHS, where the no-in restriction does not apply).
792    fn allow_in<T>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, String>) -> Result<T, String> {
793        let saved = self.no_in;
794        self.no_in = false;
795        let r = f(self);
796        self.no_in = saved;
797        r
798    }
799
800    fn parse_assign(&mut self) -> Result<Expr, String> {
801        // Arrow function detection.
802        if let Some(arrow) = self.try_parse_arrow()? {
803            return Ok(arrow);
804        }
805        let left = self.parse_conditional()?;
806        // Assignment operators (right-associative).
807        let op = match self.tok() {
808            Tok::Punct(p) => p.clone(),
809            _ => return Ok(left),
810        };
811        let compound = match op.as_str() {
812            "=" => None,
813            "+=" => Some(BinOp::Add),
814            "-=" => Some(BinOp::Sub),
815            "*=" => Some(BinOp::Mul),
816            "/=" => Some(BinOp::Div),
817            "%=" => Some(BinOp::Mod),
818            "**=" => Some(BinOp::Pow),
819            "&=" => Some(BinOp::BitAnd),
820            "|=" => Some(BinOp::BitOr),
821            "^=" => Some(BinOp::BitXor),
822            "<<=" => Some(BinOp::Shl),
823            ">>=" => Some(BinOp::Shr),
824            ">>>=" => Some(BinOp::UShr),
825            "&&=" | "||=" | "??=" => {
826                // Logical assignment.
827                self.advance();
828                let value = self.parse_assign()?;
829                let lop = match op.as_str() {
830                    "&&=" => LogicalOp::And,
831                    "||=" => LogicalOp::Or,
832                    _ => LogicalOp::Nullish,
833                };
834                return Ok(Expr::Assign {
835                    target: Box::new(left.clone()),
836                    value: Box::new(Expr::Logical(lop, Box::new(left), Box::new(value))),
837                });
838            }
839            _ => return Ok(left),
840        };
841        self.advance();
842        let value = self.parse_assign()?;
843        let value = match compound {
844            None => value,
845            Some(b) => Expr::Binary(b, Box::new(left.clone()), Box::new(value)),
846        };
847        Ok(Expr::Assign {
848            target: Box::new(left),
849            value: Box::new(value),
850        })
851    }
852
853    fn parse_conditional(&mut self) -> Result<Expr, String> {
854        let test = self.parse_binary(0)?;
855        if self.eat_punct("?") {
856            let cons = self.parse_assign()?;
857            self.expect_punct(":")?;
858            let alt = self.parse_assign()?;
859            Ok(Expr::Conditional {
860                test: Box::new(test),
861                cons: Box::new(cons),
862                alt: Box::new(alt),
863            })
864        } else {
865            Ok(test)
866        }
867    }
868
869    /// Precedence-climbing binary parser. Handles `&& || ??` as logical nodes.
870    fn parse_binary(&mut self, min_prec: u8) -> Result<Expr, String> {
871        let mut left = self.parse_unary()?;
872        while let Some((prec, right_assoc, logical, bin)) = self.bin_info() {
873            if prec < min_prec {
874                break;
875            }
876            self.advance();
877            let next_min = if right_assoc { prec } else { prec + 1 };
878            let right = self.parse_binary(next_min)?;
879            left = if let Some(lop) = logical {
880                Expr::Logical(lop, Box::new(left), Box::new(right))
881            } else {
882                Expr::Binary(bin.unwrap(), Box::new(left), Box::new(right))
883            };
884        }
885        Ok(left)
886    }
887
888    /// `(precedence, right_assoc, logical_op, bin_op)` for the current token.
889    fn bin_info(&self) -> Option<(u8, bool, Option<LogicalOp>, Option<BinOp>)> {
890        let p = match self.tok() {
891            Tok::Punct(p) => p.as_str(),
892            // In a `for` LHS (no-in) context, `in` is the loop separator, not a
893            // relational operator.
894            Tok::Ident(s) if s == "in" => {
895                if self.no_in {
896                    return None;
897                }
898                "in"
899            }
900            Tok::Ident(s) if s == "instanceof" => "instanceof",
901            _ => return None,
902        };
903        let (prec, ra, log, bin) = match p {
904            "??" => (1, false, Some(LogicalOp::Nullish), None),
905            "||" => (2, false, Some(LogicalOp::Or), None),
906            "&&" => (3, false, Some(LogicalOp::And), None),
907            "|" => (4, false, None, Some(BinOp::BitOr)),
908            "^" => (5, false, None, Some(BinOp::BitXor)),
909            "&" => (6, false, None, Some(BinOp::BitAnd)),
910            "==" => (7, false, None, Some(BinOp::EqEq)),
911            "!=" => (7, false, None, Some(BinOp::NeEq)),
912            "===" => (7, false, None, Some(BinOp::EqEqEq)),
913            "!==" => (7, false, None, Some(BinOp::NeEqEq)),
914            "<" => (8, false, None, Some(BinOp::Lt)),
915            "<=" => (8, false, None, Some(BinOp::Le)),
916            ">" => (8, false, None, Some(BinOp::Gt)),
917            ">=" => (8, false, None, Some(BinOp::Ge)),
918            "in" => (8, false, None, Some(BinOp::In)),
919            "instanceof" => (8, false, None, Some(BinOp::InstanceOf)),
920            "<<" => (9, false, None, Some(BinOp::Shl)),
921            ">>" => (9, false, None, Some(BinOp::Shr)),
922            ">>>" => (9, false, None, Some(BinOp::UShr)),
923            "+" => (10, false, None, Some(BinOp::Add)),
924            "-" => (10, false, None, Some(BinOp::Sub)),
925            "*" => (11, false, None, Some(BinOp::Mul)),
926            "/" => (11, false, None, Some(BinOp::Div)),
927            "%" => (11, false, None, Some(BinOp::Mod)),
928            "**" => (12, true, None, Some(BinOp::Pow)),
929            _ => return None,
930        };
931        Some((prec, ra, log, bin))
932    }
933
934    fn parse_unary(&mut self) -> Result<Expr, String> {
935        let op = match self.tok() {
936            Tok::Punct(p) if p == "!" => Some(UnOp::Not),
937            Tok::Punct(p) if p == "~" => Some(UnOp::BitNot),
938            Tok::Punct(p) if p == "+" => Some(UnOp::Pos),
939            Tok::Punct(p) if p == "-" => Some(UnOp::Neg),
940            Tok::Ident(s) if s == "typeof" => Some(UnOp::TypeOf),
941            Tok::Ident(s) if s == "void" => Some(UnOp::Void),
942            Tok::Ident(s) if s == "delete" => Some(UnOp::Delete),
943            _ => None,
944        };
945        if let Some(op) = op {
946            self.advance();
947            let e = self.parse_unary()?;
948            return Ok(Expr::Unary(op, Box::new(e)));
949        }
950        // Prefix ++/--.
951        if self.is_punct("++") || self.is_punct("--") {
952            let op = if self.is_punct("++") {
953                UpdateOp::Inc
954            } else {
955                UpdateOp::Dec
956            };
957            self.advance();
958            let e = self.parse_unary()?;
959            return Ok(Expr::Update {
960                op,
961                prefix: true,
962                target: Box::new(e),
963            });
964        }
965        self.parse_postfix()
966    }
967
968    fn parse_postfix(&mut self) -> Result<Expr, String> {
969        let mut e = self.parse_call_member()?;
970        // Postfix ++/-- (no line break before).
971        if (self.is_punct("++") || self.is_punct("--")) && !self.newline_before() {
972            let op = if self.is_punct("++") {
973                UpdateOp::Inc
974            } else {
975                UpdateOp::Dec
976            };
977            self.advance();
978            e = Expr::Update {
979                op,
980                prefix: false,
981                target: Box::new(e),
982            };
983        }
984        Ok(e)
985    }
986
987    fn parse_call_member(&mut self) -> Result<Expr, String> {
988        let mut e = if self.eat_kw("new") {
989            // `new.target` meta-property.
990            if self.is_punct(".") {
991                self.advance();
992                let prop = self.ident_name()?;
993                if prop != "target" {
994                    return Err(format!(
995                        "SyntaxError: expected 'target' (line {})",
996                        self.line()
997                    ));
998                }
999                Expr::NewTarget
1000            } else {
1001                let callee = self.parse_call_member_no_call()?;
1002                let args = if self.is_punct("(") {
1003                    self.parse_args()?
1004                } else {
1005                    Vec::new()
1006                };
1007                Expr::New {
1008                    callee: Box::new(callee),
1009                    args,
1010                }
1011            }
1012        } else {
1013            self.parse_primary()?
1014        };
1015        loop {
1016            if self.eat_punct(".") {
1017                let property = self.ident_name()?;
1018                e = Expr::Member {
1019                    object: Box::new(e),
1020                    property,
1021                    optional: false,
1022                };
1023            } else if self.eat_punct("?.") {
1024                if self.is_punct("(") {
1025                    let args = self.parse_args()?;
1026                    e = Expr::Call {
1027                        func: Box::new(e),
1028                        args,
1029                        optional: true,
1030                    };
1031                } else if self.is_punct("[") {
1032                    self.advance();
1033                    let index = self.allow_in(|p| p.parse_expr())?;
1034                    self.expect_punct("]")?;
1035                    e = Expr::Index {
1036                        object: Box::new(e),
1037                        index: Box::new(index),
1038                        optional: true,
1039                    };
1040                } else {
1041                    let property = self.ident_name()?;
1042                    e = Expr::Member {
1043                        object: Box::new(e),
1044                        property,
1045                        optional: true,
1046                    };
1047                }
1048            } else if self.is_punct("[") {
1049                self.advance();
1050                let index = self.allow_in(|p| p.parse_expr())?;
1051                self.expect_punct("]")?;
1052                e = Expr::Index {
1053                    object: Box::new(e),
1054                    index: Box::new(index),
1055                    optional: false,
1056                };
1057            } else if self.is_punct("(") {
1058                let args = self.parse_args()?;
1059                e = Expr::Call {
1060                    func: Box::new(e),
1061                    args,
1062                    optional: false,
1063                };
1064            } else if matches!(self.tok(), Tok::Template { .. }) {
1065                // A template literal immediately after a callee is a *tagged*
1066                // template: `` tag`...` `` → `tag(strings, ...values)`.
1067                e = self.parse_tagged_template(e)?;
1068            } else {
1069                break;
1070            }
1071        }
1072        Ok(e)
1073    }
1074
1075    /// Parse `` tag`a${x}b` `` into a `TaggedTemplate` node (the tag expression is
1076    /// already parsed as `tag`, and the current token is the template).
1077    fn parse_tagged_template(&mut self, tag: Expr) -> Result<Expr, String> {
1078        let (quasis, raws, exprs_src) = match self.tok().clone() {
1079            Tok::Template {
1080                quasis,
1081                raws,
1082                exprs,
1083            } => (quasis, raws, exprs),
1084            _ => unreachable!(),
1085        };
1086        self.advance();
1087        let mut exprs = Vec::new();
1088        for src in &exprs_src {
1089            exprs.push(parse_expr_source(src)?);
1090        }
1091        Ok(Expr::TaggedTemplate {
1092            tag: Box::new(tag),
1093            quasis,
1094            raws,
1095            exprs,
1096        })
1097    }
1098
1099    /// Member chain without a trailing call — the `new X.Y` callee grammar.
1100    fn parse_call_member_no_call(&mut self) -> Result<Expr, String> {
1101        let mut e = self.parse_primary()?;
1102        loop {
1103            if self.eat_punct(".") {
1104                let property = self.ident_name()?;
1105                e = Expr::Member {
1106                    object: Box::new(e),
1107                    property,
1108                    optional: false,
1109                };
1110            } else if self.is_punct("[") {
1111                self.advance();
1112                let index = self.allow_in(|p| p.parse_expr())?;
1113                self.expect_punct("]")?;
1114                e = Expr::Index {
1115                    object: Box::new(e),
1116                    index: Box::new(index),
1117                    optional: false,
1118                };
1119            } else {
1120                break;
1121            }
1122        }
1123        Ok(e)
1124    }
1125
1126    fn parse_args(&mut self) -> Result<Vec<Expr>, String> {
1127        self.expect_punct("(")?;
1128        // Inside a call-argument list `in` is always a relational operator, even
1129        // in a `for` LHS.
1130        let args = self.allow_in(|p| {
1131            let mut args = Vec::new();
1132            while !p.is_punct(")") {
1133                if p.eat_punct("...") {
1134                    let e = p.parse_assign()?;
1135                    args.push(Expr::Spread(Box::new(e)));
1136                } else {
1137                    args.push(p.parse_assign()?);
1138                }
1139                if !p.eat_punct(",") {
1140                    break;
1141                }
1142            }
1143            Ok(args)
1144        })?;
1145        self.expect_punct(")")?;
1146        Ok(args)
1147    }
1148
1149    fn parse_primary(&mut self) -> Result<Expr, String> {
1150        match self.tok().clone() {
1151            Tok::Num(n) => {
1152                self.advance();
1153                Ok(Expr::Number(n))
1154            }
1155            Tok::BigInt(s) => {
1156                self.advance();
1157                Ok(Expr::BigInt(s))
1158            }
1159            Tok::Regex(pat, flags) => {
1160                self.advance();
1161                Ok(Expr::Regex(pat, flags))
1162            }
1163            Tok::Str(s) => {
1164                self.advance();
1165                Ok(Expr::Str(s))
1166            }
1167            Tok::Template {
1168                quasis,
1169                raws: _,
1170                exprs,
1171            } => {
1172                self.advance();
1173                let mut parsed = Vec::new();
1174                for src in &exprs {
1175                    parsed.push(parse_expr_source(src)?);
1176                }
1177                Ok(Expr::Template {
1178                    quasis,
1179                    exprs: parsed,
1180                })
1181            }
1182            Tok::Punct(p) if p == "(" => {
1183                self.advance();
1184                let e = self.parse_expr()?;
1185                self.expect_punct(")")?;
1186                Ok(e)
1187            }
1188            Tok::Punct(p) if p == "[" => self.parse_array_literal(),
1189            Tok::Punct(p) if p == "{" => self.parse_object_literal(),
1190            Tok::Ident(s) => {
1191                match s.as_str() {
1192                    "true" => {
1193                        self.advance();
1194                        Ok(Expr::True)
1195                    }
1196                    "false" => {
1197                        self.advance();
1198                        Ok(Expr::False)
1199                    }
1200                    "null" => {
1201                        self.advance();
1202                        Ok(Expr::Null)
1203                    }
1204                    "this" => {
1205                        self.advance();
1206                        Ok(Expr::This)
1207                    }
1208                    "super" => {
1209                        self.advance();
1210                        Ok(Expr::Super)
1211                    }
1212                    "class" => Ok(Expr::Class(Box::new(self.parse_class(false)?))),
1213                    "function" => self.parse_function_expr(false),
1214                    "async" if self.peek_kw(1, "function") && !self.peek_newline(1) => {
1215                        self.advance(); // async
1216                        self.parse_function_expr(true)
1217                    }
1218                    "yield" if self.in_generator => {
1219                        self.advance();
1220                        let delegate = self.eat_punct("*");
1221                        // `yield` with no argument (before `)`, `]`, `}`, `,`, `;`,
1222                        // newline, or EOF).
1223                        let arg = if delegate
1224                            || !(self.is_punct(")")
1225                                || self.is_punct("]")
1226                                || self.is_punct("}")
1227                                || self.is_punct(",")
1228                                || self.is_punct(";")
1229                                || self.is_punct(":")
1230                                || self.newline_before()
1231                                || self.at_eof())
1232                        {
1233                            Some(Box::new(self.parse_assign()?))
1234                        } else {
1235                            None
1236                        };
1237                        Ok(Expr::Yield { arg, delegate })
1238                    }
1239                    "await" if self.in_async => {
1240                        self.advance();
1241                        let e = self.parse_unary()?;
1242                        Ok(Expr::Await(Box::new(e)))
1243                    }
1244                    _ if is_keyword(&s) => Err(format!(
1245                        "SyntaxError: unexpected keyword '{s}' (line {})",
1246                        self.line()
1247                    )),
1248                    _ => {
1249                        self.advance();
1250                        Ok(Expr::Ident(s))
1251                    }
1252                }
1253            }
1254            other => Err(format!(
1255                "SyntaxError: unexpected token {other:?} (line {})",
1256                self.line()
1257            )),
1258        }
1259    }
1260
1261    fn parse_array_literal(&mut self) -> Result<Expr, String> {
1262        self.expect_punct("[")?;
1263        let mut items = Vec::new();
1264        while !self.is_punct("]") {
1265            if self.is_punct(",") {
1266                // Elision (hole) — represent as undefined.
1267                items.push(Expr::Undefined);
1268                self.advance();
1269                continue;
1270            }
1271            if self.eat_punct("...") {
1272                let e = self.parse_assign()?;
1273                items.push(Expr::Spread(Box::new(e)));
1274            } else {
1275                items.push(self.parse_assign()?);
1276            }
1277            if !self.eat_punct(",") {
1278                break;
1279            }
1280        }
1281        self.expect_punct("]")?;
1282        Ok(Expr::Array(items))
1283    }
1284
1285    fn parse_object_literal(&mut self) -> Result<Expr, String> {
1286        self.expect_punct("{")?;
1287        let mut props = Vec::new();
1288        while !self.is_punct("}") {
1289            if self.eat_punct("...") {
1290                let e = self.parse_assign()?;
1291                props.push(Prop::Spread(e));
1292                if !self.eat_punct(",") {
1293                    break;
1294                }
1295                continue;
1296            }
1297            // `get key() {}` / `set key(v) {}` accessor (contextual: `get`/`set`
1298            // is a modifier only when followed by another key, not `:`/`(`/`,`).
1299            if (self.is_kw("get") || self.is_kw("set"))
1300                && !self.peek_is_member_punct(1)
1301                && !matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":" || p == ",")
1302            {
1303                let is_getter = self.is_kw("get");
1304                self.advance();
1305                let (key, computed) = self.parse_property_key()?;
1306                let params = self.parse_params()?;
1307                self.expect_punct("{")?;
1308                let body = self.parse_block_body()?;
1309                let func = Expr::Function {
1310                    params,
1311                    body: FnBody::Block(body),
1312                    is_arrow: false,
1313                    name: None,
1314                    is_generator: false,
1315                    is_async: false,
1316                };
1317                props.push(Prop::Accessor {
1318                    key,
1319                    computed,
1320                    is_getter,
1321                    func,
1322                });
1323                if !self.eat_punct(",") {
1324                    break;
1325                }
1326                continue;
1327            }
1328            // Concise-method modifiers: `async` and/or `*` before the key.
1329            let mut m_async = false;
1330            let mut m_gen = false;
1331            if self.is_kw("async")
1332                && !self.peek_is_member_punct(1)
1333                && !self.peek_newline(1)
1334                && !matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":" || p == ",")
1335            {
1336                self.advance();
1337                m_async = true;
1338            }
1339            if self.is_punct("*") {
1340                self.advance();
1341                m_gen = true;
1342            }
1343            let (key, computed) = self.parse_property_key()?;
1344            // Method shorthand `key(params) { }` (incl. `*gen(){}`, `async m(){}`).
1345            if self.is_punct("(") {
1346                let params = self.parse_params()?;
1347                self.expect_punct("{")?;
1348                let body = self.parse_fn_body_block(m_gen, m_async)?;
1349                let f = Expr::Function {
1350                    params,
1351                    body: FnBody::Block(body),
1352                    is_arrow: false,
1353                    name: None,
1354                    is_generator: m_gen,
1355                    is_async: m_async,
1356                };
1357                props.push(Prop::KeyValue {
1358                    key,
1359                    value: f,
1360                    computed,
1361                });
1362            } else if self.eat_punct(":") {
1363                let value = self.parse_assign()?;
1364                props.push(Prop::KeyValue {
1365                    key,
1366                    value,
1367                    computed,
1368                });
1369            } else {
1370                // Shorthand `{ x }` -> key "x", value ident x. Or with default
1371                // in a destructuring pattern: `{ x = 1 }`.
1372                let name = match &key {
1373                    Expr::Str(s) => s.clone(),
1374                    _ => return Err(format!("SyntaxError: bad shorthand (line {})", self.line())),
1375                };
1376                let value = if self.eat_punct("=") {
1377                    // Pattern default; represent as Assign so destructuring reads it.
1378                    let d = self.parse_assign()?;
1379                    Expr::Assign {
1380                        target: Box::new(Expr::Ident(name.clone())),
1381                        value: Box::new(d),
1382                    }
1383                } else {
1384                    Expr::Ident(name)
1385                };
1386                props.push(Prop::KeyValue {
1387                    key,
1388                    value,
1389                    computed,
1390                });
1391            }
1392            if !self.eat_punct(",") {
1393                break;
1394            }
1395        }
1396        self.expect_punct("}")?;
1397        Ok(Expr::Object(props))
1398    }
1399
1400    // ── functions / arrows ───────────────────────────────────────────────
1401    fn parse_params(&mut self) -> Result<Vec<Param>, String> {
1402        self.expect_punct("(")?;
1403        let mut params = Vec::new();
1404        while !self.is_punct(")") {
1405            let rest = self.eat_punct("...");
1406            let pattern = self.parse_binding_target()?;
1407            let default = if !rest && self.eat_punct("=") {
1408                Some(self.parse_assign()?)
1409            } else {
1410                None
1411            };
1412            params.push(Param {
1413                pattern,
1414                default,
1415                rest,
1416            });
1417            if !self.eat_punct(",") {
1418                break;
1419            }
1420        }
1421        self.expect_punct(")")?;
1422        Ok(params)
1423    }
1424
1425    /// Try to parse an arrow function starting at the current position. Returns
1426    /// `None` (without consuming) if the head is not an arrow.
1427    fn try_parse_arrow(&mut self) -> Result<Option<Expr>, String> {
1428        // `async` prefix on an arrow (`async x => …` / `async (…) => …`), only
1429        // when `async` is not itself the parameter and no newline intervenes.
1430        let mut is_async = false;
1431        let mut base = self.pos;
1432        if self.is_kw("async") && !self.peek_newline(1) {
1433            let next = self.toks.get(self.pos + 1).map(|t| &t.tok);
1434            let looks_async_arrow = matches!(next, Some(Tok::Punct(p)) if p == "(")
1435                || matches!(next, Some(Tok::Ident(n)) if !is_keyword(n) && self.peek_is_arrow_after(2));
1436            if looks_async_arrow {
1437                is_async = true;
1438                base += 1;
1439            }
1440        }
1441        // `ident => ...`
1442        if let Some(Tok::Ident(name)) = self.toks.get(base).map(|t| &t.tok) {
1443            if !is_keyword(name)
1444                && matches!(self.toks.get(base + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1445            {
1446                let name = name.clone();
1447                if is_async {
1448                    self.advance(); // async
1449                }
1450                self.advance(); // ident
1451                self.advance(); // =>
1452                let body = self.parse_arrow_body(is_async)?;
1453                return Ok(Some(Expr::Function {
1454                    params: vec![Param {
1455                        pattern: Expr::Ident(name),
1456                        default: None,
1457                        rest: false,
1458                    }],
1459                    body,
1460                    is_arrow: true,
1461                    name: None,
1462                    is_generator: false,
1463                    is_async,
1464                }));
1465            }
1466        }
1467        // `( ... ) => ...`
1468        if matches!(self.toks.get(base).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "(") {
1469            if let Some(close) = self.matching_paren(base) {
1470                let after = close + 1;
1471                if matches!(self.toks.get(after).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1472                {
1473                    if is_async {
1474                        self.advance(); // async
1475                    }
1476                    let params = self.parse_params()?;
1477                    self.expect_punct("=>")?;
1478                    let body = self.parse_arrow_body(is_async)?;
1479                    return Ok(Some(Expr::Function {
1480                        params,
1481                        body,
1482                        is_arrow: true,
1483                        name: None,
1484                        is_generator: false,
1485                        is_async,
1486                    }));
1487                }
1488            }
1489        }
1490        Ok(None)
1491    }
1492
1493    fn parse_arrow_body(&mut self, is_async: bool) -> Result<FnBody, String> {
1494        let (pg, pa) = (self.in_generator, self.in_async);
1495        self.in_generator = false;
1496        self.in_async = is_async;
1497        let r = if self.is_punct("{") {
1498            self.advance();
1499            self.parse_block_body().map(FnBody::Block)
1500        } else {
1501            self.parse_assign().map(|e| FnBody::Expr(Box::new(e)))
1502        };
1503        self.in_generator = pg;
1504        self.in_async = pa;
1505        r
1506    }
1507
1508    /// Whether the token `n` positions ahead is `=>`.
1509    fn peek_is_arrow_after(&self, n: usize) -> bool {
1510        matches!(self.toks.get(self.pos + n).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1511    }
1512
1513    /// Index of the `)` matching the `(` at `open`, skipping nested brackets.
1514    fn matching_paren(&self, open: usize) -> Option<usize> {
1515        let mut depth = 0i32;
1516        let mut i = open;
1517        while i < self.toks.len() {
1518            match &self.toks[i].tok {
1519                Tok::Punct(p) if p == "(" || p == "[" || p == "{" => depth += 1,
1520                Tok::Punct(p) if p == ")" || p == "]" || p == "}" => {
1521                    depth -= 1;
1522                    if depth == 0 {
1523                        return Some(i);
1524                    }
1525                }
1526                Tok::Eof => return None,
1527                _ => {}
1528            }
1529            i += 1;
1530        }
1531        None
1532    }
1533}
1534
1535/// Parse a template-literal `${...}` field's raw source into an expression.
1536fn parse_expr_source(src: &str) -> Result<Expr, String> {
1537    let toks = lex(src)?;
1538    let mut p = Parser {
1539        toks,
1540        pos: 0,
1541        in_generator: false,
1542        in_async: false,
1543        no_in: false,
1544    };
1545    let e = p.parse_expr()?;
1546    Ok(e)
1547}