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            is_method: false,
337        })
338    }
339
340    /// Parse a `class` (the `class` keyword is current). `_decl` distinguishes a
341    /// declaration (name required in strict mode, but we accept optional) from an
342    /// expression.
343    fn parse_class(&mut self, _decl: bool) -> Result<ClassNode, String> {
344        self.advance(); // class
345        let name = if let Tok::Ident(n) = self.tok() {
346            if !is_keyword(n) && n != "extends" {
347                let n = n.clone();
348                self.advance();
349                Some(n)
350            } else {
351                None
352            }
353        } else {
354            None
355        };
356        let parent = if self.eat_kw("extends") {
357            // The superclass is a left-hand-side expression (`extends Base`,
358            // `extends foo.Bar`).
359            Some(Box::new(self.parse_call_member()?))
360        } else {
361            None
362        };
363        self.expect_punct("{")?;
364        let mut members = Vec::new();
365        while !self.is_punct("}") && !self.at_eof() {
366            if self.eat_punct(";") {
367                continue; // stray semicolons between members
368            }
369            members.push(self.parse_class_member()?);
370        }
371        self.expect_punct("}")?;
372        Ok(ClassNode {
373            name,
374            parent,
375            members,
376        })
377    }
378
379    /// Parse one class member: `[static] [get|set|async|*] name(params){…}` or a
380    /// `[static] name [= init];` field.
381    fn parse_class_member(&mut self) -> Result<ClassMember, String> {
382        let is_static = self.is_kw("static") && !self.peek_is_member_punct(1) && {
383            self.advance();
384            true
385        };
386        // `static { … }` — a class static initialization block (ES2022). A brace
387        // where a member key would be is unambiguous: no member name can start
388        // with `{`, so this is checked before the key parse (which otherwise
389        // rejects it as `bad member key Punct("{")`).
390        if is_static && self.is_punct("{") {
391            self.advance();
392            // Its own function context: `yield`/`await` are plain identifiers
393            // inside a static block, whatever encloses the class.
394            let body = self.parse_fn_body_block(false, false)?;
395            return Ok(ClassMember {
396                key: Expr::Str(String::new()),
397                computed: false,
398                kind: MemberKind::StaticBlock,
399                is_static: true,
400                is_generator: false,
401                is_async: false,
402                params: Vec::new(),
403                body,
404                field_init: None,
405            });
406        }
407        // Accessor / async / generator prefixes (each contextual: only a prefix
408        // when followed by another member name, not itself the member name).
409        let mut kind = MemberKind::Method;
410        let mut is_async = false;
411        let mut is_generator = false;
412        if self.is_kw("get") && !self.peek_is_member_punct(1) {
413            self.advance();
414            kind = MemberKind::Get;
415        } else if self.is_kw("set") && !self.peek_is_member_punct(1) {
416            self.advance();
417            kind = MemberKind::Set;
418        } else {
419            if self.is_kw("async") && !self.peek_is_member_punct(1) && !self.peek_newline(1) {
420                self.advance();
421                is_async = true;
422            }
423            if self.eat_punct("*") {
424                is_generator = true;
425            }
426        }
427        // The member key (computed `[expr]`, string, number, or identifier).
428        let (key, computed) = self.parse_property_key()?;
429        // A field (no parentheses) vs a method.
430        if kind == MemberKind::Method && !self.is_punct("(") {
431            let field_init = if self.eat_punct("=") {
432                Some(self.parse_assign()?)
433            } else {
434                None
435            };
436            self.semicolon()?;
437            return Ok(ClassMember {
438                key,
439                computed,
440                kind: MemberKind::Field,
441                is_static,
442                is_generator: false,
443                is_async: false,
444                params: Vec::new(),
445                body: Vec::new(),
446                field_init,
447            });
448        }
449        // A method / accessor / constructor.
450        let is_ctor = !is_static
451            && !computed
452            && matches!(&key, Expr::Str(s) if s == "constructor")
453            && kind == MemberKind::Method;
454        let params = self.parse_params()?;
455        self.expect_punct("{")?;
456        let body = self.parse_fn_body_block(is_generator, is_async)?;
457        Ok(ClassMember {
458            key,
459            computed,
460            kind: if is_ctor {
461                MemberKind::Constructor
462            } else {
463                kind
464            },
465            is_static,
466            is_generator,
467            is_async,
468            params,
469            body,
470            field_init: None,
471        })
472    }
473
474    /// Whether the token `n` ahead is `(`, `=`, `;`, `}`, or a newline-boundary —
475    /// i.e. the current word is itself the member name, not a modifier prefix.
476    fn peek_is_member_punct(&self, n: usize) -> bool {
477        matches!(
478            self.toks.get(self.pos + n).map(|t| &t.tok),
479            Some(Tok::Punct(p)) if p == "(" || p == "=" || p == ";" || p == "}"
480        )
481    }
482
483    /// Parse a property key for a class member / object method: `[expr]` (computed),
484    /// a string, a number, or an identifier (returned as an `Expr::Str`).
485    fn parse_property_key(&mut self) -> Result<(Expr, bool), String> {
486        if self.is_punct("[") {
487            self.advance();
488            let k = self.parse_assign()?;
489            self.expect_punct("]")?;
490            Ok((k, true))
491        } else {
492            match self.tok().clone() {
493                Tok::Str(s) => {
494                    self.advance();
495                    Ok((Expr::Str(s), false))
496                }
497                Tok::Num(n) => {
498                    self.advance();
499                    Ok((Expr::Str(crate::host::fmt_number(n)), false))
500                }
501                Tok::Ident(s) => {
502                    self.advance();
503                    Ok((Expr::Str(s), false))
504                }
505                other => Err(format!(
506                    "SyntaxError: bad member key {other:?} (line {})",
507                    self.line()
508                )),
509            }
510        }
511    }
512
513    /// An optional non-newline label after break/continue.
514    fn opt_label(&mut self) -> Option<String> {
515        if self.newline_before() {
516            return None;
517        }
518        if let Tok::Ident(s) = self.tok() {
519            if !is_keyword(s) {
520                let s = s.clone();
521                self.advance();
522                return Some(s);
523            }
524        }
525        None
526    }
527
528    /// Parse statements up to (and consuming) the closing `}`.
529    fn parse_block_body(&mut self) -> Result<Vec<Stmt>, String> {
530        let mut out = Vec::new();
531        while !self.is_punct("}") && !self.at_eof() {
532            out.push(self.parse_stmt()?);
533        }
534        self.expect_punct("}")?;
535        Ok(out)
536    }
537
538    fn parse_decl_kind(&mut self) -> DeclKind {
539        let k = match self.tok() {
540            Tok::Ident(s) if s == "let" => DeclKind::Let,
541            Tok::Ident(s) if s == "const" => DeclKind::Const,
542            _ => DeclKind::Var,
543        };
544        self.advance();
545        k
546    }
547
548    fn parse_declarators(&mut self) -> Result<Vec<Declarator>, String> {
549        let mut decls = Vec::new();
550        loop {
551            let target = self.parse_binding_target()?;
552            let init = if self.eat_punct("=") {
553                Some(self.parse_assign()?)
554            } else {
555                None
556            };
557            decls.push(Declarator { target, init });
558            if !self.eat_punct(",") {
559                break;
560            }
561        }
562        Ok(decls)
563    }
564
565    /// A binding target: identifier or array/object destructuring pattern.
566    fn parse_binding_target(&mut self) -> Result<Expr, String> {
567        if self.is_punct("[") {
568            self.parse_array_literal()
569        } else if self.is_punct("{") {
570            self.parse_object_literal()
571        } else {
572            Ok(Expr::Ident(self.ident_name()?))
573        }
574    }
575
576    fn parse_if(&mut self) -> Result<StmtKind, String> {
577        self.advance(); // if
578        self.expect_punct("(")?;
579        let test = self.parse_expr()?;
580        self.expect_punct(")")?;
581        let cons = Box::new(self.parse_stmt()?);
582        let alt = if self.eat_kw("else") {
583            Some(Box::new(self.parse_stmt()?))
584        } else {
585            None
586        };
587        Ok(StmtKind::If { test, cons, alt })
588    }
589
590    fn parse_while(&mut self) -> Result<StmtKind, String> {
591        self.advance();
592        self.expect_punct("(")?;
593        let test = self.parse_expr()?;
594        self.expect_punct(")")?;
595        let body = Box::new(self.parse_stmt()?);
596        Ok(StmtKind::While { test, body })
597    }
598
599    fn parse_do_while(&mut self) -> Result<StmtKind, String> {
600        self.advance();
601        let body = Box::new(self.parse_stmt()?);
602        if !self.eat_kw("while") {
603            return Err(format!(
604                "SyntaxError: expected 'while' (line {})",
605                self.line()
606            ));
607        }
608        self.expect_punct("(")?;
609        let test = self.parse_expr()?;
610        self.expect_punct(")")?;
611        self.semicolon()?;
612        Ok(StmtKind::DoWhile { body, test })
613    }
614
615    fn parse_for(&mut self) -> Result<StmtKind, String> {
616        self.advance();
617        // `for await (… of …)` — the async-iteration form (valid in an async body).
618        let is_await = self.eat_kw("await");
619        self.expect_punct("(")?;
620        // Optional declaration or expression init.
621        let decl_kind = match self.tok() {
622            Tok::Ident(s) if s == "var" || s == "let" || s == "const" => {
623                Some(self.parse_decl_kind())
624            }
625            _ => None,
626        };
627        // Empty init: `for (;;)`.
628        if decl_kind.is_none() && self.is_punct(";") {
629            return self.parse_c_for(None);
630        }
631        // Parse the first binding/expression, then decide of/in vs C-style.
632        let first_target = if decl_kind.is_some() {
633            self.parse_binding_target()?
634        } else {
635            self.parse_expr_no_in()?
636        };
637        if self.eat_kw("of") {
638            let iter = self.parse_assign()?;
639            self.expect_punct(")")?;
640            let body = Box::new(self.parse_stmt()?);
641            return Ok(StmtKind::ForOf {
642                decl_kind,
643                target: first_target,
644                iter,
645                body,
646                is_await,
647            });
648        }
649        if self.eat_kw("in") {
650            let object = self.parse_assign()?;
651            self.expect_punct(")")?;
652            let body = Box::new(self.parse_stmt()?);
653            return Ok(StmtKind::ForIn {
654                decl_kind,
655                target: first_target,
656                object,
657                body,
658            });
659        }
660        // C-style: reconstruct the init statement.
661        let init_stmt = if let Some(k) = decl_kind {
662            let init = if self.eat_punct("=") {
663                Some(self.parse_assign()?)
664            } else {
665                None
666            };
667            let mut decls = vec![Declarator {
668                target: first_target,
669                init,
670            }];
671            while self.eat_punct(",") {
672                let target = self.parse_binding_target()?;
673                let init = if self.eat_punct("=") {
674                    Some(self.parse_assign()?)
675                } else {
676                    None
677                };
678                decls.push(Declarator { target, init });
679            }
680            StmtKind::Decl { kind: k, decls }
681        } else {
682            // A non-declaration C-style init may be a comma sequence
683            // (`for (i = 0, n = a.length; …)`) — extend past the first assignment.
684            let init = if self.is_punct(",") {
685                let mut items = vec![first_target];
686                while self.eat_punct(",") {
687                    items.push(self.parse_expr_no_in()?);
688                }
689                Expr::Sequence(items)
690            } else {
691                first_target
692            };
693            StmtKind::Expr(init)
694        };
695        self.parse_c_for(Some(Stmt::from(init_stmt)))
696    }
697
698    fn parse_c_for(&mut self, init: Option<Stmt>) -> Result<StmtKind, String> {
699        self.expect_punct(";")?;
700        let test = if self.is_punct(";") {
701            None
702        } else {
703            Some(self.parse_expr()?)
704        };
705        self.expect_punct(";")?;
706        let update = if self.is_punct(")") {
707            None
708        } else {
709            Some(self.parse_expr()?)
710        };
711        self.expect_punct(")")?;
712        let body = Box::new(self.parse_stmt()?);
713        Ok(StmtKind::For {
714            init: init.map(Box::new),
715            test,
716            update,
717            body,
718        })
719    }
720
721    fn parse_switch(&mut self) -> Result<StmtKind, String> {
722        self.advance();
723        self.expect_punct("(")?;
724        let disc = self.parse_expr()?;
725        self.expect_punct(")")?;
726        self.expect_punct("{")?;
727        let mut cases = Vec::new();
728        while !self.is_punct("}") && !self.at_eof() {
729            let test = if self.eat_kw("case") {
730                let e = self.parse_expr()?;
731                Some(e)
732            } else if self.eat_kw("default") {
733                None
734            } else {
735                return Err(format!(
736                    "SyntaxError: expected 'case' or 'default' (line {})",
737                    self.line()
738                ));
739            };
740            self.expect_punct(":")?;
741            let mut body = Vec::new();
742            while !self.is_punct("}")
743                && !self.is_kw("case")
744                && !self.is_kw("default")
745                && !self.at_eof()
746            {
747                body.push(self.parse_stmt()?);
748            }
749            cases.push(SwitchCase { test, body });
750        }
751        self.expect_punct("}")?;
752        Ok(StmtKind::Switch { disc, cases })
753    }
754
755    fn parse_try(&mut self) -> Result<StmtKind, String> {
756        self.advance();
757        self.expect_punct("{")?;
758        let block = self.parse_block_body()?;
759        let handler = if self.eat_kw("catch") {
760            let param = if self.eat_punct("(") {
761                let p = self.parse_binding_target()?;
762                self.expect_punct(")")?;
763                Some(p)
764            } else {
765                None
766            };
767            self.expect_punct("{")?;
768            let body = self.parse_block_body()?;
769            Some((param, body))
770        } else {
771            None
772        };
773        let finalizer = if self.eat_kw("finally") {
774            self.expect_punct("{")?;
775            Some(self.parse_block_body()?)
776        } else {
777            None
778        };
779        Ok(StmtKind::Try {
780            block,
781            handler,
782            finalizer,
783        })
784    }
785
786    // ── expressions ──────────────────────────────────────────────────────
787    /// Full expression, including the comma sequence operator.
788    fn parse_expr(&mut self) -> Result<Expr, String> {
789        let first = self.parse_assign()?;
790        if self.is_punct(",") {
791            let mut items = vec![first];
792            while self.eat_punct(",") {
793                items.push(self.parse_assign()?);
794            }
795            Ok(Expr::Sequence(items))
796        } else {
797            Ok(first)
798        }
799    }
800
801    /// Like `parse_expr` but stops before `in` (used in `for` init position).
802    fn parse_expr_no_in(&mut self) -> Result<Expr, String> {
803        // For simplicity the no-in variant only parses an assignment/LHS chain,
804        // which is sufficient for `for (x in ...)` / `for (x of ...)` heads.
805        let saved = self.no_in;
806        self.no_in = true;
807        let r = self.parse_assign();
808        self.no_in = saved;
809        r
810    }
811
812    /// Run `f` with `in` re-enabled (inside a parenthesised/bracketed sub-
813    /// expression of a `for` LHS, where the no-in restriction does not apply).
814    fn allow_in<T>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, String>) -> Result<T, String> {
815        let saved = self.no_in;
816        self.no_in = false;
817        let r = f(self);
818        self.no_in = saved;
819        r
820    }
821
822    fn parse_assign(&mut self) -> Result<Expr, String> {
823        // Arrow function detection.
824        if let Some(arrow) = self.try_parse_arrow()? {
825            return Ok(arrow);
826        }
827        let left = self.parse_conditional()?;
828        // Assignment operators (right-associative).
829        let op = match self.tok() {
830            Tok::Punct(p) => p.clone(),
831            _ => return Ok(left),
832        };
833        let compound = match op.as_str() {
834            "=" => None,
835            "+=" => Some(BinOp::Add),
836            "-=" => Some(BinOp::Sub),
837            "*=" => Some(BinOp::Mul),
838            "/=" => Some(BinOp::Div),
839            "%=" => Some(BinOp::Mod),
840            "**=" => Some(BinOp::Pow),
841            "&=" => Some(BinOp::BitAnd),
842            "|=" => Some(BinOp::BitOr),
843            "^=" => Some(BinOp::BitXor),
844            "<<=" => Some(BinOp::Shl),
845            ">>=" => Some(BinOp::Shr),
846            ">>>=" => Some(BinOp::UShr),
847            "&&=" | "||=" | "??=" => {
848                // Logical assignment.
849                self.advance();
850                let value = self.parse_assign()?;
851                let lop = match op.as_str() {
852                    "&&=" => LogicalOp::And,
853                    "||=" => LogicalOp::Or,
854                    _ => LogicalOp::Nullish,
855                };
856                return Ok(Expr::Assign {
857                    target: Box::new(left.clone()),
858                    value: Box::new(Expr::Logical(lop, Box::new(left), Box::new(value))),
859                });
860            }
861            _ => return Ok(left),
862        };
863        self.advance();
864        let value = self.parse_assign()?;
865        let value = match compound {
866            None => value,
867            Some(b) => Expr::Binary(b, Box::new(left.clone()), Box::new(value)),
868        };
869        Ok(Expr::Assign {
870            target: Box::new(left),
871            value: Box::new(value),
872        })
873    }
874
875    fn parse_conditional(&mut self) -> Result<Expr, String> {
876        let test = self.parse_binary(0)?;
877        if self.eat_punct("?") {
878            let cons = self.parse_assign()?;
879            self.expect_punct(":")?;
880            let alt = self.parse_assign()?;
881            Ok(Expr::Conditional {
882                test: Box::new(test),
883                cons: Box::new(cons),
884                alt: Box::new(alt),
885            })
886        } else {
887            Ok(test)
888        }
889    }
890
891    /// Precedence-climbing binary parser. Handles `&& || ??` as logical nodes.
892    fn parse_binary(&mut self, min_prec: u8) -> Result<Expr, String> {
893        let mut left = self.parse_unary()?;
894        while let Some((prec, right_assoc, logical, bin)) = self.bin_info() {
895            if prec < min_prec {
896                break;
897            }
898            self.advance();
899            let next_min = if right_assoc { prec } else { prec + 1 };
900            let right = self.parse_binary(next_min)?;
901            left = if let Some(lop) = logical {
902                Expr::Logical(lop, Box::new(left), Box::new(right))
903            } else {
904                Expr::Binary(bin.unwrap(), Box::new(left), Box::new(right))
905            };
906        }
907        Ok(left)
908    }
909
910    /// `(precedence, right_assoc, logical_op, bin_op)` for the current token.
911    fn bin_info(&self) -> Option<(u8, bool, Option<LogicalOp>, Option<BinOp>)> {
912        let p = match self.tok() {
913            Tok::Punct(p) => p.as_str(),
914            // In a `for` LHS (no-in) context, `in` is the loop separator, not a
915            // relational operator.
916            Tok::Ident(s) if s == "in" => {
917                if self.no_in {
918                    return None;
919                }
920                "in"
921            }
922            Tok::Ident(s) if s == "instanceof" => "instanceof",
923            _ => return None,
924        };
925        let (prec, ra, log, bin) = match p {
926            "??" => (1, false, Some(LogicalOp::Nullish), None),
927            "||" => (2, false, Some(LogicalOp::Or), None),
928            "&&" => (3, false, Some(LogicalOp::And), None),
929            "|" => (4, false, None, Some(BinOp::BitOr)),
930            "^" => (5, false, None, Some(BinOp::BitXor)),
931            "&" => (6, false, None, Some(BinOp::BitAnd)),
932            "==" => (7, false, None, Some(BinOp::EqEq)),
933            "!=" => (7, false, None, Some(BinOp::NeEq)),
934            "===" => (7, false, None, Some(BinOp::EqEqEq)),
935            "!==" => (7, false, None, Some(BinOp::NeEqEq)),
936            "<" => (8, false, None, Some(BinOp::Lt)),
937            "<=" => (8, false, None, Some(BinOp::Le)),
938            ">" => (8, false, None, Some(BinOp::Gt)),
939            ">=" => (8, false, None, Some(BinOp::Ge)),
940            "in" => (8, false, None, Some(BinOp::In)),
941            "instanceof" => (8, false, None, Some(BinOp::InstanceOf)),
942            "<<" => (9, false, None, Some(BinOp::Shl)),
943            ">>" => (9, false, None, Some(BinOp::Shr)),
944            ">>>" => (9, false, None, Some(BinOp::UShr)),
945            "+" => (10, false, None, Some(BinOp::Add)),
946            "-" => (10, false, None, Some(BinOp::Sub)),
947            "*" => (11, false, None, Some(BinOp::Mul)),
948            "/" => (11, false, None, Some(BinOp::Div)),
949            "%" => (11, false, None, Some(BinOp::Mod)),
950            "**" => (12, true, None, Some(BinOp::Pow)),
951            _ => return None,
952        };
953        Some((prec, ra, log, bin))
954    }
955
956    /// Reject a `**` directly after a just-parsed UnaryExpression. JS only
957    /// allows an UpdateExpression there (`x++ ** y` and `++x ** y` are fine),
958    /// so an unparenthesized `-x ** y` / `typeof x ** y` / `await x ** y` is a
959    /// SyntaxError rather than a silently-reassociated `-(x ** y)`.
960    fn reject_unary_before_pow(&mut self) -> Result<(), String> {
961        if self.is_punct("**") {
962            return Err(format!(
963                "SyntaxError: Unary operator used immediately before exponentiation \
964                 expression. Parenthesis must be used to disambiguate operator \
965                 precedence (line {})",
966                self.line()
967            ));
968        }
969        Ok(())
970    }
971
972    fn parse_unary(&mut self) -> Result<Expr, String> {
973        let op = match self.tok() {
974            Tok::Punct(p) if p == "!" => Some(UnOp::Not),
975            Tok::Punct(p) if p == "~" => Some(UnOp::BitNot),
976            Tok::Punct(p) if p == "+" => Some(UnOp::Pos),
977            Tok::Punct(p) if p == "-" => Some(UnOp::Neg),
978            Tok::Ident(s) if s == "typeof" => Some(UnOp::TypeOf),
979            Tok::Ident(s) if s == "void" => Some(UnOp::Void),
980            Tok::Ident(s) if s == "delete" => Some(UnOp::Delete),
981            _ => None,
982        };
983        if let Some(op) = op {
984            self.advance();
985            let e = self.parse_unary()?;
986            // `ExponentiationExpression : UpdateExpression ** …` — a
987            // UnaryExpression on the left of `**` is a SyntaxError, so
988            // `-x ** y` must be written `(-x) ** y` or `-(x ** y)`.
989            self.reject_unary_before_pow()?;
990            return Ok(Expr::Unary(op, Box::new(e)));
991        }
992        // Prefix ++/--.
993        if self.is_punct("++") || self.is_punct("--") {
994            let op = if self.is_punct("++") {
995                UpdateOp::Inc
996            } else {
997                UpdateOp::Dec
998            };
999            self.advance();
1000            let e = self.parse_unary()?;
1001            return Ok(Expr::Update {
1002                op,
1003                prefix: true,
1004                target: Box::new(e),
1005            });
1006        }
1007        self.parse_postfix()
1008    }
1009
1010    fn parse_postfix(&mut self) -> Result<Expr, String> {
1011        let mut e = self.parse_call_member()?;
1012        // Postfix ++/-- (no line break before).
1013        if (self.is_punct("++") || self.is_punct("--")) && !self.newline_before() {
1014            let op = if self.is_punct("++") {
1015                UpdateOp::Inc
1016            } else {
1017                UpdateOp::Dec
1018            };
1019            self.advance();
1020            e = Expr::Update {
1021                op,
1022                prefix: false,
1023                target: Box::new(e),
1024            };
1025        }
1026        Ok(e)
1027    }
1028
1029    fn parse_call_member(&mut self) -> Result<Expr, String> {
1030        let mut e = if self.eat_kw("new") {
1031            // `new.target` meta-property.
1032            if self.is_punct(".") {
1033                self.advance();
1034                let prop = self.ident_name()?;
1035                if prop != "target" {
1036                    return Err(format!(
1037                        "SyntaxError: expected 'target' (line {})",
1038                        self.line()
1039                    ));
1040                }
1041                Expr::NewTarget
1042            } else {
1043                let callee = self.parse_call_member_no_call()?;
1044                let args = if self.is_punct("(") {
1045                    self.parse_args()?
1046                } else {
1047                    Vec::new()
1048                };
1049                Expr::New {
1050                    callee: Box::new(callee),
1051                    args,
1052                }
1053            }
1054        } else {
1055            self.parse_primary()?
1056        };
1057        loop {
1058            if self.eat_punct(".") {
1059                let property = self.ident_name()?;
1060                e = Expr::Member {
1061                    object: Box::new(e),
1062                    property,
1063                    optional: false,
1064                };
1065            } else if self.eat_punct("?.") {
1066                if self.is_punct("(") {
1067                    let args = self.parse_args()?;
1068                    e = Expr::Call {
1069                        func: Box::new(e),
1070                        args,
1071                        optional: true,
1072                    };
1073                } else if self.is_punct("[") {
1074                    self.advance();
1075                    let index = self.allow_in(|p| p.parse_expr())?;
1076                    self.expect_punct("]")?;
1077                    e = Expr::Index {
1078                        object: Box::new(e),
1079                        index: Box::new(index),
1080                        optional: true,
1081                    };
1082                } else {
1083                    let property = self.ident_name()?;
1084                    e = Expr::Member {
1085                        object: Box::new(e),
1086                        property,
1087                        optional: true,
1088                    };
1089                }
1090            } else if self.is_punct("[") {
1091                self.advance();
1092                let index = self.allow_in(|p| p.parse_expr())?;
1093                self.expect_punct("]")?;
1094                e = Expr::Index {
1095                    object: Box::new(e),
1096                    index: Box::new(index),
1097                    optional: false,
1098                };
1099            } else if self.is_punct("(") {
1100                let args = self.parse_args()?;
1101                e = Expr::Call {
1102                    func: Box::new(e),
1103                    args,
1104                    optional: false,
1105                };
1106            } else if matches!(self.tok(), Tok::Template { .. }) {
1107                // A template literal immediately after a callee is a *tagged*
1108                // template: `` tag`...` `` → `tag(strings, ...values)`.
1109                e = self.parse_tagged_template(e)?;
1110            } else {
1111                break;
1112            }
1113        }
1114        Ok(e)
1115    }
1116
1117    /// Parse `` tag`a${x}b` `` into a `TaggedTemplate` node (the tag expression is
1118    /// already parsed as `tag`, and the current token is the template).
1119    fn parse_tagged_template(&mut self, tag: Expr) -> Result<Expr, String> {
1120        let (quasis, raws, exprs_src) = match self.tok().clone() {
1121            Tok::Template {
1122                quasis,
1123                raws,
1124                exprs,
1125            } => (quasis, raws, exprs),
1126            _ => unreachable!(),
1127        };
1128        self.advance();
1129        let mut exprs = Vec::new();
1130        for src in &exprs_src {
1131            exprs.push(parse_expr_source(src)?);
1132        }
1133        Ok(Expr::TaggedTemplate {
1134            tag: Box::new(tag),
1135            quasis,
1136            raws,
1137            exprs,
1138        })
1139    }
1140
1141    /// Member chain without a trailing call — the `new X.Y` callee grammar.
1142    fn parse_call_member_no_call(&mut self) -> Result<Expr, String> {
1143        let mut e = self.parse_primary()?;
1144        loop {
1145            if self.eat_punct(".") {
1146                let property = self.ident_name()?;
1147                e = Expr::Member {
1148                    object: Box::new(e),
1149                    property,
1150                    optional: false,
1151                };
1152            } else if self.is_punct("[") {
1153                self.advance();
1154                let index = self.allow_in(|p| p.parse_expr())?;
1155                self.expect_punct("]")?;
1156                e = Expr::Index {
1157                    object: Box::new(e),
1158                    index: Box::new(index),
1159                    optional: false,
1160                };
1161            } else {
1162                break;
1163            }
1164        }
1165        Ok(e)
1166    }
1167
1168    fn parse_args(&mut self) -> Result<Vec<Expr>, String> {
1169        self.expect_punct("(")?;
1170        // Inside a call-argument list `in` is always a relational operator, even
1171        // in a `for` LHS.
1172        let args = self.allow_in(|p| {
1173            let mut args = Vec::new();
1174            while !p.is_punct(")") {
1175                if p.eat_punct("...") {
1176                    let e = p.parse_assign()?;
1177                    args.push(Expr::Spread(Box::new(e)));
1178                } else {
1179                    args.push(p.parse_assign()?);
1180                }
1181                if !p.eat_punct(",") {
1182                    break;
1183                }
1184            }
1185            Ok(args)
1186        })?;
1187        self.expect_punct(")")?;
1188        Ok(args)
1189    }
1190
1191    fn parse_primary(&mut self) -> Result<Expr, String> {
1192        match self.tok().clone() {
1193            Tok::Num(n) => {
1194                self.advance();
1195                Ok(Expr::Number(n))
1196            }
1197            Tok::BigInt(s) => {
1198                self.advance();
1199                Ok(Expr::BigInt(s))
1200            }
1201            Tok::Regex(pat, flags) => {
1202                self.advance();
1203                Ok(Expr::Regex(pat, flags))
1204            }
1205            Tok::Str(s) => {
1206                self.advance();
1207                Ok(Expr::Str(s))
1208            }
1209            Tok::Template {
1210                quasis,
1211                raws: _,
1212                exprs,
1213            } => {
1214                self.advance();
1215                let mut parsed = Vec::new();
1216                for src in &exprs {
1217                    parsed.push(parse_expr_source(src)?);
1218                }
1219                Ok(Expr::Template {
1220                    quasis,
1221                    exprs: parsed,
1222                })
1223            }
1224            Tok::Punct(p) if p == "(" => {
1225                self.advance();
1226                let e = self.parse_expr()?;
1227                self.expect_punct(")")?;
1228                Ok(e)
1229            }
1230            Tok::Punct(p) if p == "[" => self.parse_array_literal(),
1231            Tok::Punct(p) if p == "{" => self.parse_object_literal(),
1232            Tok::Ident(s) => {
1233                match s.as_str() {
1234                    "true" => {
1235                        self.advance();
1236                        Ok(Expr::True)
1237                    }
1238                    "false" => {
1239                        self.advance();
1240                        Ok(Expr::False)
1241                    }
1242                    "null" => {
1243                        self.advance();
1244                        Ok(Expr::Null)
1245                    }
1246                    "this" => {
1247                        self.advance();
1248                        Ok(Expr::This)
1249                    }
1250                    "super" => {
1251                        self.advance();
1252                        Ok(Expr::Super)
1253                    }
1254                    "class" => Ok(Expr::Class(Box::new(self.parse_class(false)?))),
1255                    "function" => self.parse_function_expr(false),
1256                    "async" if self.peek_kw(1, "function") && !self.peek_newline(1) => {
1257                        self.advance(); // async
1258                        self.parse_function_expr(true)
1259                    }
1260                    "yield" if self.in_generator => {
1261                        self.advance();
1262                        let delegate = self.eat_punct("*");
1263                        // `yield` with no argument (before `)`, `]`, `}`, `,`, `;`,
1264                        // newline, or EOF).
1265                        let arg = if delegate
1266                            || !(self.is_punct(")")
1267                                || self.is_punct("]")
1268                                || self.is_punct("}")
1269                                || self.is_punct(",")
1270                                || self.is_punct(";")
1271                                || self.is_punct(":")
1272                                || self.newline_before()
1273                                || self.at_eof())
1274                        {
1275                            Some(Box::new(self.parse_assign()?))
1276                        } else {
1277                            None
1278                        };
1279                        Ok(Expr::Yield { arg, delegate })
1280                    }
1281                    "await" if self.in_async => {
1282                        self.advance();
1283                        let e = self.parse_unary()?;
1284                        // An AwaitExpression is a UnaryExpression, so it too
1285                        // cannot sit directly left of `**`.
1286                        self.reject_unary_before_pow()?;
1287                        Ok(Expr::Await(Box::new(e)))
1288                    }
1289                    _ if is_keyword(&s) => Err(format!(
1290                        "SyntaxError: unexpected keyword '{s}' (line {})",
1291                        self.line()
1292                    )),
1293                    _ => {
1294                        self.advance();
1295                        Ok(Expr::Ident(s))
1296                    }
1297                }
1298            }
1299            other => Err(format!(
1300                "SyntaxError: unexpected token {other:?} (line {})",
1301                self.line()
1302            )),
1303        }
1304    }
1305
1306    fn parse_array_literal(&mut self) -> Result<Expr, String> {
1307        self.expect_punct("[")?;
1308        let mut items = Vec::new();
1309        while !self.is_punct("]") {
1310            if self.is_punct(",") {
1311                // Elision: the element is a HOLE, not a stored `undefined`.
1312                items.push(Expr::Hole);
1313                self.advance();
1314                continue;
1315            }
1316            if self.eat_punct("...") {
1317                let e = self.parse_assign()?;
1318                items.push(Expr::Spread(Box::new(e)));
1319            } else {
1320                items.push(self.parse_assign()?);
1321            }
1322            if !self.eat_punct(",") {
1323                break;
1324            }
1325        }
1326        self.expect_punct("]")?;
1327        Ok(Expr::Array(items))
1328    }
1329
1330    fn parse_object_literal(&mut self) -> Result<Expr, String> {
1331        self.expect_punct("{")?;
1332        let mut props = Vec::new();
1333        while !self.is_punct("}") {
1334            if self.eat_punct("...") {
1335                let e = self.parse_assign()?;
1336                props.push(Prop::Spread(e));
1337                if !self.eat_punct(",") {
1338                    break;
1339                }
1340                continue;
1341            }
1342            // `get key() {}` / `set key(v) {}` accessor (contextual: `get`/`set`
1343            // is a modifier only when followed by another key, not `:`/`(`/`,`).
1344            if (self.is_kw("get") || self.is_kw("set"))
1345                && !self.peek_is_member_punct(1)
1346                && !matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":" || p == ",")
1347            {
1348                let is_getter = self.is_kw("get");
1349                self.advance();
1350                let (key, computed) = self.parse_property_key()?;
1351                let params = self.parse_params()?;
1352                self.expect_punct("{")?;
1353                let body = self.parse_block_body()?;
1354                let func = Expr::Function {
1355                    params,
1356                    body: FnBody::Block(body),
1357                    is_arrow: false,
1358                    name: None,
1359                    is_generator: false,
1360                    is_async: false,
1361                    is_method: true,
1362                };
1363                props.push(Prop::Accessor {
1364                    key,
1365                    computed,
1366                    is_getter,
1367                    func,
1368                });
1369                if !self.eat_punct(",") {
1370                    break;
1371                }
1372                continue;
1373            }
1374            // Concise-method modifiers: `async` and/or `*` before the key.
1375            let mut m_async = false;
1376            let mut m_gen = false;
1377            if self.is_kw("async")
1378                && !self.peek_is_member_punct(1)
1379                && !self.peek_newline(1)
1380                && !matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":" || p == ",")
1381            {
1382                self.advance();
1383                m_async = true;
1384            }
1385            if self.is_punct("*") {
1386                self.advance();
1387                m_gen = true;
1388            }
1389            let (key, computed) = self.parse_property_key()?;
1390            // Method shorthand `key(params) { }` (incl. `*gen(){}`, `async m(){}`).
1391            if self.is_punct("(") {
1392                let params = self.parse_params()?;
1393                self.expect_punct("{")?;
1394                let body = self.parse_fn_body_block(m_gen, m_async)?;
1395                let f = Expr::Function {
1396                    params,
1397                    body: FnBody::Block(body),
1398                    is_arrow: false,
1399                    name: None,
1400                    is_generator: m_gen,
1401                    is_async: m_async,
1402                    is_method: true,
1403                };
1404                props.push(Prop::KeyValue {
1405                    key,
1406                    value: f,
1407                    computed,
1408                });
1409            } else if self.eat_punct(":") {
1410                let value = self.parse_assign()?;
1411                props.push(Prop::KeyValue {
1412                    key,
1413                    value,
1414                    computed,
1415                });
1416            } else {
1417                // Shorthand `{ x }` -> key "x", value ident x. Or with default
1418                // in a destructuring pattern: `{ x = 1 }`.
1419                let name = match &key {
1420                    Expr::Str(s) => s.clone(),
1421                    _ => return Err(format!("SyntaxError: bad shorthand (line {})", self.line())),
1422                };
1423                let value = if self.eat_punct("=") {
1424                    // Pattern default; represent as Assign so destructuring reads it.
1425                    let d = self.parse_assign()?;
1426                    Expr::Assign {
1427                        target: Box::new(Expr::Ident(name.clone())),
1428                        value: Box::new(d),
1429                    }
1430                } else {
1431                    Expr::Ident(name)
1432                };
1433                props.push(Prop::KeyValue {
1434                    key,
1435                    value,
1436                    computed,
1437                });
1438            }
1439            if !self.eat_punct(",") {
1440                break;
1441            }
1442        }
1443        self.expect_punct("}")?;
1444        Ok(Expr::Object(props))
1445    }
1446
1447    // ── functions / arrows ───────────────────────────────────────────────
1448    fn parse_params(&mut self) -> Result<Vec<Param>, String> {
1449        self.expect_punct("(")?;
1450        let mut params = Vec::new();
1451        while !self.is_punct(")") {
1452            let rest = self.eat_punct("...");
1453            let pattern = self.parse_binding_target()?;
1454            let default = if !rest && self.eat_punct("=") {
1455                Some(self.parse_assign()?)
1456            } else {
1457                None
1458            };
1459            params.push(Param {
1460                pattern,
1461                default,
1462                rest,
1463            });
1464            if !self.eat_punct(",") {
1465                break;
1466            }
1467        }
1468        self.expect_punct(")")?;
1469        Ok(params)
1470    }
1471
1472    /// Try to parse an arrow function starting at the current position. Returns
1473    /// `None` (without consuming) if the head is not an arrow.
1474    fn try_parse_arrow(&mut self) -> Result<Option<Expr>, String> {
1475        // `async` prefix on an arrow (`async x => …` / `async (…) => …`), only
1476        // when `async` is not itself the parameter and no newline intervenes.
1477        let mut is_async = false;
1478        let mut base = self.pos;
1479        if self.is_kw("async") && !self.peek_newline(1) {
1480            let next = self.toks.get(self.pos + 1).map(|t| &t.tok);
1481            let looks_async_arrow = matches!(next, Some(Tok::Punct(p)) if p == "(")
1482                || matches!(next, Some(Tok::Ident(n)) if !is_keyword(n) && self.peek_is_arrow_after(2));
1483            if looks_async_arrow {
1484                is_async = true;
1485                base += 1;
1486            }
1487        }
1488        // `ident => ...`
1489        if let Some(Tok::Ident(name)) = self.toks.get(base).map(|t| &t.tok) {
1490            if !is_keyword(name)
1491                && matches!(self.toks.get(base + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1492            {
1493                let name = name.clone();
1494                if is_async {
1495                    self.advance(); // async
1496                }
1497                self.advance(); // ident
1498                self.advance(); // =>
1499                let body = self.parse_arrow_body(is_async)?;
1500                return Ok(Some(Expr::Function {
1501                    params: vec![Param {
1502                        pattern: Expr::Ident(name),
1503                        default: None,
1504                        rest: false,
1505                    }],
1506                    body,
1507                    is_arrow: true,
1508                    name: None,
1509                    is_generator: false,
1510                    is_async,
1511                    is_method: false,
1512                }));
1513            }
1514        }
1515        // `( ... ) => ...`
1516        if matches!(self.toks.get(base).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "(") {
1517            if let Some(close) = self.matching_paren(base) {
1518                let after = close + 1;
1519                if matches!(self.toks.get(after).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1520                {
1521                    if is_async {
1522                        self.advance(); // async
1523                    }
1524                    let params = self.parse_params()?;
1525                    self.expect_punct("=>")?;
1526                    let body = self.parse_arrow_body(is_async)?;
1527                    return Ok(Some(Expr::Function {
1528                        params,
1529                        body,
1530                        is_arrow: true,
1531                        name: None,
1532                        is_generator: false,
1533                        is_async,
1534                        is_method: false,
1535                    }));
1536                }
1537            }
1538        }
1539        Ok(None)
1540    }
1541
1542    fn parse_arrow_body(&mut self, is_async: bool) -> Result<FnBody, String> {
1543        let (pg, pa) = (self.in_generator, self.in_async);
1544        self.in_generator = false;
1545        self.in_async = is_async;
1546        let r = if self.is_punct("{") {
1547            self.advance();
1548            self.parse_block_body().map(FnBody::Block)
1549        } else {
1550            self.parse_assign().map(|e| FnBody::Expr(Box::new(e)))
1551        };
1552        self.in_generator = pg;
1553        self.in_async = pa;
1554        r
1555    }
1556
1557    /// Whether the token `n` positions ahead is `=>`.
1558    fn peek_is_arrow_after(&self, n: usize) -> bool {
1559        matches!(self.toks.get(self.pos + n).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1560    }
1561
1562    /// Index of the `)` matching the `(` at `open`, skipping nested brackets.
1563    fn matching_paren(&self, open: usize) -> Option<usize> {
1564        let mut depth = 0i32;
1565        let mut i = open;
1566        while i < self.toks.len() {
1567            match &self.toks[i].tok {
1568                Tok::Punct(p) if p == "(" || p == "[" || p == "{" => depth += 1,
1569                Tok::Punct(p) if p == ")" || p == "]" || p == "}" => {
1570                    depth -= 1;
1571                    if depth == 0 {
1572                        return Some(i);
1573                    }
1574                }
1575                Tok::Eof => return None,
1576                _ => {}
1577            }
1578            i += 1;
1579        }
1580        None
1581    }
1582}
1583
1584/// Parse a template-literal `${...}` field's raw source into an expression.
1585fn parse_expr_source(src: &str) -> Result<Expr, String> {
1586    let toks = lex(src)?;
1587    let mut p = Parser {
1588        toks,
1589        pos: 0,
1590        in_generator: false,
1591        in_async: false,
1592        no_in: false,
1593    };
1594    let e = p.parse_expr()?;
1595    Ok(e)
1596}