1use 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
50#[derive(Default)]
52struct PrivateScope {
53 declared: Vec<String>,
54 used: Vec<String>,
55}
56
57fn private_not_declared(name: &str) -> String {
58 format!("SyntaxError: Private field '{name}' must be declared in an enclosing class")
59}
60
61struct Parser {
62 toks: Vec<Token>,
63 pos: usize,
64 in_generator: bool,
66 in_async: bool,
68 no_in: bool,
73 class_scopes: Vec<PrivateScope>,
79}
80
81pub fn parse(src: &str) -> Result<Vec<Stmt>, String> {
84 let src = crate::rust_ffi::desugar(src);
85 let toks = lex(&src)?;
86 let mut p = Parser {
87 toks,
88 pos: 0,
89 in_generator: false,
90 in_async: false,
91 no_in: false,
92 class_scopes: Vec::new(),
93 };
94 let mut out = Vec::new();
95 while !p.at_eof() {
96 out.push(p.parse_stmt()?);
97 }
98 Ok(out)
99}
100
101impl Parser {
102 fn cur(&self) -> &Token {
104 &self.toks[self.pos]
105 }
106 fn tok(&self) -> &Tok {
107 &self.toks[self.pos].tok
108 }
109 fn line(&self) -> u32 {
110 self.toks[self.pos].line
111 }
112 fn at_eof(&self) -> bool {
113 matches!(self.tok(), Tok::Eof)
114 }
115 fn newline_before(&self) -> bool {
116 self.cur().newline_before
117 }
118 fn advance(&mut self) -> Tok {
119 let t = self.toks[self.pos].tok.clone();
120 if self.pos + 1 < self.toks.len() {
121 self.pos += 1;
122 }
123 t
124 }
125
126 fn is_punct(&self, s: &str) -> bool {
128 matches!(self.tok(), Tok::Punct(p) if p == s)
129 }
130 fn is_kw(&self, s: &str) -> bool {
132 matches!(self.tok(), Tok::Ident(i) if i == s)
133 }
134 fn eat_punct(&mut self, s: &str) -> bool {
136 if self.is_punct(s) {
137 self.advance();
138 true
139 } else {
140 false
141 }
142 }
143 fn eat_kw(&mut self, s: &str) -> bool {
144 if self.is_kw(s) {
145 self.advance();
146 true
147 } else {
148 false
149 }
150 }
151 fn expect_punct(&mut self, s: &str) -> Result<(), String> {
152 if self.eat_punct(s) {
153 Ok(())
154 } else {
155 Err(format!(
156 "SyntaxError: expected '{s}' but found {:?} (line {})",
157 self.tok(),
158 self.line()
159 ))
160 }
161 }
162
163 fn ident_name(&mut self) -> Result<String, String> {
166 match self.tok().clone() {
167 Tok::Ident(s) => {
168 self.advance();
169 Ok(s)
170 }
171 other => Err(format!(
172 "SyntaxError: expected identifier but found {other:?} (line {})",
173 self.line()
174 )),
175 }
176 }
177
178 fn semicolon(&mut self) -> Result<(), String> {
180 if self.eat_punct(";") {
181 return Ok(());
182 }
183 if self.newline_before() || self.is_punct("}") || self.at_eof() {
184 return Ok(());
185 }
186 Err(format!(
187 "SyntaxError: expected ';' but found {:?} (line {})",
188 self.tok(),
189 self.line()
190 ))
191 }
192
193 fn parse_stmt(&mut self) -> Result<Stmt, String> {
195 let line = self.line();
196 let kind = match self.tok().clone() {
197 Tok::Punct(p) if p == "{" => {
198 self.advance();
199 StmtKind::Block(self.parse_block_body()?)
200 }
201 Tok::Punct(p) if p == ";" => {
202 self.advance();
203 StmtKind::Empty
204 }
205 Tok::Ident(kw) if kw == "var" || kw == "let" || kw == "const" => {
206 let k = self.parse_decl_kind();
207 let decls = self.parse_declarators()?;
208 self.semicolon()?;
209 StmtKind::Decl { kind: k, decls }
210 }
211 Tok::Ident(kw) if kw == "function" => self.parse_func_decl(false)?,
212 Tok::Ident(kw)
215 if kw == "async" && self.peek_kw(1, "function") && !self.peek_newline(1) =>
216 {
217 self.advance(); self.parse_func_decl(true)?
219 }
220 Tok::Ident(kw) if kw == "class" => {
221 let node = self.parse_class(true)?;
222 StmtKind::ClassDecl(node)
223 }
224 Tok::Ident(kw) if kw == "if" => self.parse_if()?,
225 Tok::Ident(kw) if kw == "while" => self.parse_while()?,
226 Tok::Ident(kw) if kw == "do" => self.parse_do_while()?,
227 Tok::Ident(kw) if kw == "for" => self.parse_for()?,
228 Tok::Ident(kw) if kw == "switch" => self.parse_switch()?,
229 Tok::Ident(kw) if kw == "return" => {
230 self.advance();
231 let arg = if self.is_punct(";")
232 || self.is_punct("}")
233 || self.newline_before()
234 || self.at_eof()
235 {
236 None
237 } else {
238 Some(self.parse_expr()?)
239 };
240 self.semicolon()?;
241 StmtKind::Return(arg)
242 }
243 Tok::Ident(kw) if kw == "break" => {
244 self.advance();
245 let label = self.opt_label();
246 self.semicolon()?;
247 StmtKind::Break(label)
248 }
249 Tok::Ident(kw) if kw == "continue" => {
250 self.advance();
251 let label = self.opt_label();
252 self.semicolon()?;
253 StmtKind::Continue(label)
254 }
255 Tok::Ident(kw) if kw == "throw" => {
256 self.advance();
257 let e = self.parse_expr()?;
258 self.semicolon()?;
259 StmtKind::Throw(e)
260 }
261 Tok::Ident(kw) if kw == "try" => self.parse_try()?,
262 Tok::Ident(name) if matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":") =>
267 {
268 self.advance(); self.advance(); let body = Box::new(self.parse_stmt()?);
271 StmtKind::Labeled { label: name, body }
272 }
273 _ => {
274 let e = self.parse_expr()?;
275 self.semicolon()?;
276 StmtKind::Expr(e)
277 }
278 };
279 Ok(Stmt::new(kind, line))
280 }
281
282 fn peek_kw(&self, n: usize, kw: &str) -> bool {
284 matches!(self.toks.get(self.pos + n).map(|t| &t.tok), Some(Tok::Ident(s)) if s == kw)
285 }
286 fn peek_newline(&self, n: usize) -> bool {
288 self.toks
289 .get(self.pos + n)
290 .map(|t| t.newline_before)
291 .unwrap_or(false)
292 }
293
294 fn parse_func_decl(&mut self, is_async: bool) -> Result<StmtKind, String> {
297 self.advance(); let is_generator = self.eat_punct("*");
299 let name = self.ident_name()?;
300 let params = self.parse_params()?;
301 self.expect_punct("{")?;
302 let body = self.parse_fn_body_block(is_generator, is_async)?;
303 Ok(StmtKind::FuncDecl {
304 name,
305 params,
306 body,
307 is_generator,
308 is_async,
309 })
310 }
311
312 fn parse_fn_body_block(
315 &mut self,
316 is_generator: bool,
317 is_async: bool,
318 ) -> Result<Vec<Stmt>, String> {
319 let (pg, pa) = (self.in_generator, self.in_async);
320 self.in_generator = is_generator;
321 self.in_async = is_async;
322 let body = self.parse_block_body();
323 self.in_generator = pg;
324 self.in_async = pa;
325 body
326 }
327
328 fn parse_function_expr(&mut self, is_async: bool) -> Result<Expr, String> {
331 self.advance(); let is_generator = self.eat_punct("*");
333 let name = if let Tok::Ident(n) = self.tok() {
334 if !is_keyword(n) {
335 let n = n.clone();
336 self.advance();
337 Some(n)
338 } else {
339 None
340 }
341 } else {
342 None
343 };
344 let params = self.parse_params()?;
345 self.expect_punct("{")?;
346 let body = self.parse_fn_body_block(is_generator, is_async)?;
347 Ok(Expr::Function {
348 params,
349 body: FnBody::Block(body),
350 is_arrow: false,
351 name,
352 is_generator,
353 is_async,
354 is_method: false,
355 })
356 }
357
358 fn check_private_in_scope(&mut self, property: &str) -> Result<(), String> {
366 if !property.starts_with('#') {
367 return Ok(());
368 }
369 match self.class_scopes.last_mut() {
370 Some(scope) => scope.used.push(property.to_string()),
373 None => return Err(private_not_declared(property)),
374 }
375 Ok(())
376 }
377
378 fn parse_class(&mut self, _decl: bool) -> Result<ClassNode, String> {
379 self.class_scopes.push(PrivateScope::default());
380 let out = self.parse_class_inner();
381 let scope = self.class_scopes.pop().unwrap_or_default();
382 let out = out?;
383 for name in &scope.used {
384 if scope.declared.contains(name) {
385 continue;
386 }
387 match self.class_scopes.last_mut() {
390 Some(outer) => outer.used.push(name.clone()),
391 None => return Err(private_not_declared(name)),
392 }
393 }
394 Ok(out)
395 }
396
397 fn parse_class_inner(&mut self) -> Result<ClassNode, String> {
398 self.advance(); let name = if let Tok::Ident(n) = self.tok() {
400 if !is_keyword(n) && n != "extends" {
401 let n = n.clone();
402 self.advance();
403 Some(n)
404 } else {
405 None
406 }
407 } else {
408 None
409 };
410 let parent = if self.eat_kw("extends") {
411 Some(Box::new(self.parse_call_member()?))
414 } else {
415 None
416 };
417 self.expect_punct("{")?;
418 let mut members = Vec::new();
419 while !self.is_punct("}") && !self.at_eof() {
420 if self.eat_punct(";") {
421 continue; }
423 let member = self.parse_class_member()?;
424 if let Expr::Str(k) = &member.key {
425 if k.starts_with('#') {
426 if let Some(scope) = self.class_scopes.last_mut() {
427 scope.declared.push(k.clone());
428 }
429 }
430 }
431 members.push(member);
432 }
433 self.expect_punct("}")?;
434 Ok(ClassNode {
435 name,
436 parent,
437 members,
438 })
439 }
440
441 fn parse_class_member(&mut self) -> Result<ClassMember, String> {
444 let is_static = self.is_kw("static") && !self.peek_is_member_punct(1) && {
445 self.advance();
446 true
447 };
448 if is_static && self.is_punct("{") {
453 self.advance();
454 let body = self.parse_fn_body_block(false, false)?;
457 return Ok(ClassMember {
458 key: Expr::Str(String::new()),
459 computed: false,
460 kind: MemberKind::StaticBlock,
461 is_static: true,
462 is_generator: false,
463 is_async: false,
464 params: Vec::new(),
465 body,
466 field_init: None,
467 });
468 }
469 let mut kind = MemberKind::Method;
472 let mut is_async = false;
473 let mut is_generator = false;
474 if self.is_kw("get") && !self.peek_is_member_punct(1) {
475 self.advance();
476 kind = MemberKind::Get;
477 } else if self.is_kw("set") && !self.peek_is_member_punct(1) {
478 self.advance();
479 kind = MemberKind::Set;
480 } else {
481 if self.is_kw("async") && !self.peek_is_member_punct(1) && !self.peek_newline(1) {
482 self.advance();
483 is_async = true;
484 }
485 if self.eat_punct("*") {
486 is_generator = true;
487 }
488 }
489 let (key, computed) = self.parse_property_key()?;
491 if kind == MemberKind::Method && !self.is_punct("(") {
493 let field_init = if self.eat_punct("=") {
494 Some(self.parse_assign()?)
495 } else {
496 None
497 };
498 self.semicolon()?;
499 return Ok(ClassMember {
500 key,
501 computed,
502 kind: MemberKind::Field,
503 is_static,
504 is_generator: false,
505 is_async: false,
506 params: Vec::new(),
507 body: Vec::new(),
508 field_init,
509 });
510 }
511 let is_ctor = !is_static
513 && !computed
514 && matches!(&key, Expr::Str(s) if s == "constructor")
515 && kind == MemberKind::Method;
516 let params = self.parse_params()?;
517 self.expect_punct("{")?;
518 let body = self.parse_fn_body_block(is_generator, is_async)?;
519 Ok(ClassMember {
520 key,
521 computed,
522 kind: if is_ctor {
523 MemberKind::Constructor
524 } else {
525 kind
526 },
527 is_static,
528 is_generator,
529 is_async,
530 params,
531 body,
532 field_init: None,
533 })
534 }
535
536 fn peek_is_member_punct(&self, n: usize) -> bool {
539 matches!(
540 self.toks.get(self.pos + n).map(|t| &t.tok),
541 Some(Tok::Punct(p)) if p == "(" || p == "=" || p == ";" || p == "}"
542 )
543 }
544
545 fn parse_property_key(&mut self) -> Result<(Expr, bool), String> {
548 if self.is_punct("[") {
549 self.advance();
550 let k = self.parse_assign()?;
551 self.expect_punct("]")?;
552 Ok((k, true))
553 } else {
554 match self.tok().clone() {
555 Tok::Str(s) => {
556 self.advance();
557 Ok((Expr::Str(s), false))
558 }
559 Tok::Num(n) => {
560 self.advance();
561 Ok((Expr::Str(crate::host::fmt_number(n)), false))
562 }
563 Tok::Ident(s) => {
564 self.advance();
565 Ok((Expr::Str(s), false))
566 }
567 other => Err(format!(
568 "SyntaxError: bad member key {other:?} (line {})",
569 self.line()
570 )),
571 }
572 }
573 }
574
575 fn opt_label(&mut self) -> Option<String> {
577 if self.newline_before() {
578 return None;
579 }
580 if let Tok::Ident(s) = self.tok() {
581 if !is_keyword(s) {
582 let s = s.clone();
583 self.advance();
584 return Some(s);
585 }
586 }
587 None
588 }
589
590 fn parse_block_body(&mut self) -> Result<Vec<Stmt>, String> {
592 let mut out = Vec::new();
593 while !self.is_punct("}") && !self.at_eof() {
594 out.push(self.parse_stmt()?);
595 }
596 self.expect_punct("}")?;
597 Ok(out)
598 }
599
600 fn parse_decl_kind(&mut self) -> DeclKind {
601 let k = match self.tok() {
602 Tok::Ident(s) if s == "let" => DeclKind::Let,
603 Tok::Ident(s) if s == "const" => DeclKind::Const,
604 _ => DeclKind::Var,
605 };
606 self.advance();
607 k
608 }
609
610 fn parse_declarators(&mut self) -> Result<Vec<Declarator>, String> {
611 let mut decls = Vec::new();
612 loop {
613 let target = self.parse_binding_target()?;
614 let init = if self.eat_punct("=") {
615 Some(self.parse_assign()?)
616 } else {
617 None
618 };
619 decls.push(Declarator { target, init });
620 if !self.eat_punct(",") {
621 break;
622 }
623 }
624 Ok(decls)
625 }
626
627 fn parse_binding_target(&mut self) -> Result<Expr, String> {
629 if self.is_punct("[") {
630 self.parse_array_literal()
631 } else if self.is_punct("{") {
632 self.parse_object_literal()
633 } else {
634 Ok(Expr::Ident(self.ident_name()?))
635 }
636 }
637
638 fn parse_if(&mut self) -> Result<StmtKind, String> {
639 self.advance(); self.expect_punct("(")?;
641 let test = self.parse_expr()?;
642 self.expect_punct(")")?;
643 let cons = Box::new(self.parse_stmt()?);
644 let alt = if self.eat_kw("else") {
645 Some(Box::new(self.parse_stmt()?))
646 } else {
647 None
648 };
649 Ok(StmtKind::If { test, cons, alt })
650 }
651
652 fn parse_while(&mut self) -> Result<StmtKind, String> {
653 self.advance();
654 self.expect_punct("(")?;
655 let test = self.parse_expr()?;
656 self.expect_punct(")")?;
657 let body = Box::new(self.parse_stmt()?);
658 Ok(StmtKind::While { test, body })
659 }
660
661 fn parse_do_while(&mut self) -> Result<StmtKind, String> {
662 self.advance();
663 let body = Box::new(self.parse_stmt()?);
664 if !self.eat_kw("while") {
665 return Err(format!(
666 "SyntaxError: expected 'while' (line {})",
667 self.line()
668 ));
669 }
670 self.expect_punct("(")?;
671 let test = self.parse_expr()?;
672 self.expect_punct(")")?;
673 self.semicolon()?;
674 Ok(StmtKind::DoWhile { body, test })
675 }
676
677 fn parse_for(&mut self) -> Result<StmtKind, String> {
678 self.advance();
679 let is_await = self.eat_kw("await");
681 self.expect_punct("(")?;
682 let decl_kind = match self.tok() {
684 Tok::Ident(s) if s == "var" || s == "let" || s == "const" => {
685 Some(self.parse_decl_kind())
686 }
687 _ => None,
688 };
689 if decl_kind.is_none() && self.is_punct(";") {
691 return self.parse_c_for(None);
692 }
693 let first_target = if decl_kind.is_some() {
695 self.parse_binding_target()?
696 } else {
697 self.parse_expr_no_in()?
698 };
699 if self.eat_kw("of") {
700 let iter = self.parse_assign()?;
701 self.expect_punct(")")?;
702 let body = Box::new(self.parse_stmt()?);
703 return Ok(StmtKind::ForOf {
704 decl_kind,
705 target: first_target,
706 iter,
707 body,
708 is_await,
709 });
710 }
711 if self.eat_kw("in") {
712 let object = self.parse_assign()?;
713 self.expect_punct(")")?;
714 let body = Box::new(self.parse_stmt()?);
715 return Ok(StmtKind::ForIn {
716 decl_kind,
717 target: first_target,
718 object,
719 body,
720 });
721 }
722 let init_stmt = if let Some(k) = decl_kind {
724 let init = if self.eat_punct("=") {
725 Some(self.parse_assign()?)
726 } else {
727 None
728 };
729 let mut decls = vec![Declarator {
730 target: first_target,
731 init,
732 }];
733 while self.eat_punct(",") {
734 let target = self.parse_binding_target()?;
735 let init = if self.eat_punct("=") {
736 Some(self.parse_assign()?)
737 } else {
738 None
739 };
740 decls.push(Declarator { target, init });
741 }
742 StmtKind::Decl { kind: k, decls }
743 } else {
744 let init = if self.is_punct(",") {
747 let mut items = vec![first_target];
748 while self.eat_punct(",") {
749 items.push(self.parse_expr_no_in()?);
750 }
751 Expr::Sequence(items)
752 } else {
753 first_target
754 };
755 StmtKind::Expr(init)
756 };
757 self.parse_c_for(Some(Stmt::from(init_stmt)))
758 }
759
760 fn parse_c_for(&mut self, init: Option<Stmt>) -> Result<StmtKind, String> {
761 self.expect_punct(";")?;
762 let test = if self.is_punct(";") {
763 None
764 } else {
765 Some(self.parse_expr()?)
766 };
767 self.expect_punct(";")?;
768 let update = if self.is_punct(")") {
769 None
770 } else {
771 Some(self.parse_expr()?)
772 };
773 self.expect_punct(")")?;
774 let body = Box::new(self.parse_stmt()?);
775 Ok(StmtKind::For {
776 init: init.map(Box::new),
777 test,
778 update,
779 body,
780 })
781 }
782
783 fn parse_switch(&mut self) -> Result<StmtKind, String> {
784 self.advance();
785 self.expect_punct("(")?;
786 let disc = self.parse_expr()?;
787 self.expect_punct(")")?;
788 self.expect_punct("{")?;
789 let mut cases = Vec::new();
790 while !self.is_punct("}") && !self.at_eof() {
791 let test = if self.eat_kw("case") {
792 let e = self.parse_expr()?;
793 Some(e)
794 } else if self.eat_kw("default") {
795 None
796 } else {
797 return Err(format!(
798 "SyntaxError: expected 'case' or 'default' (line {})",
799 self.line()
800 ));
801 };
802 self.expect_punct(":")?;
803 let mut body = Vec::new();
804 while !self.is_punct("}")
805 && !self.is_kw("case")
806 && !self.is_kw("default")
807 && !self.at_eof()
808 {
809 body.push(self.parse_stmt()?);
810 }
811 cases.push(SwitchCase { test, body });
812 }
813 self.expect_punct("}")?;
814 Ok(StmtKind::Switch { disc, cases })
815 }
816
817 fn parse_try(&mut self) -> Result<StmtKind, String> {
818 self.advance();
819 self.expect_punct("{")?;
820 let block = self.parse_block_body()?;
821 let handler = if self.eat_kw("catch") {
822 let param = if self.eat_punct("(") {
823 let p = self.parse_binding_target()?;
824 self.expect_punct(")")?;
825 Some(p)
826 } else {
827 None
828 };
829 self.expect_punct("{")?;
830 let body = self.parse_block_body()?;
831 Some((param, body))
832 } else {
833 None
834 };
835 let finalizer = if self.eat_kw("finally") {
836 self.expect_punct("{")?;
837 Some(self.parse_block_body()?)
838 } else {
839 None
840 };
841 Ok(StmtKind::Try {
842 block,
843 handler,
844 finalizer,
845 })
846 }
847
848 fn parse_expr(&mut self) -> Result<Expr, String> {
851 let first = self.parse_assign()?;
852 if self.is_punct(",") {
853 let mut items = vec![first];
854 while self.eat_punct(",") {
855 items.push(self.parse_assign()?);
856 }
857 Ok(Expr::Sequence(items))
858 } else {
859 Ok(first)
860 }
861 }
862
863 fn parse_expr_no_in(&mut self) -> Result<Expr, String> {
865 let saved = self.no_in;
868 self.no_in = true;
869 let r = self.parse_assign();
870 self.no_in = saved;
871 r
872 }
873
874 fn has_optional_link(e: &Expr) -> bool {
878 match e {
879 Expr::Member {
880 object, optional, ..
881 } => *optional || Self::has_optional_link(object),
882 Expr::Index {
883 object, optional, ..
884 } => *optional || Self::has_optional_link(object),
885 Expr::Call { func, optional, .. } => *optional || Self::has_optional_link(func),
886 _ => false,
887 }
888 }
889
890 fn allow_in<T>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, String>) -> Result<T, String> {
893 let saved = self.no_in;
894 self.no_in = false;
895 let r = f(self);
896 self.no_in = saved;
897 r
898 }
899
900 fn parse_assign(&mut self) -> Result<Expr, String> {
901 if let Some(arrow) = self.try_parse_arrow()? {
903 return Ok(arrow);
904 }
905 let left = self.parse_conditional()?;
906 let op = match self.tok() {
908 Tok::Punct(p) => p.clone(),
909 _ => return Ok(left),
910 };
911 let compound = match op.as_str() {
912 "=" => None,
913 "+=" => Some(BinOp::Add),
914 "-=" => Some(BinOp::Sub),
915 "*=" => Some(BinOp::Mul),
916 "/=" => Some(BinOp::Div),
917 "%=" => Some(BinOp::Mod),
918 "**=" => Some(BinOp::Pow),
919 "&=" => Some(BinOp::BitAnd),
920 "|=" => Some(BinOp::BitOr),
921 "^=" => Some(BinOp::BitXor),
922 "<<=" => Some(BinOp::Shl),
923 ">>=" => Some(BinOp::Shr),
924 ">>>=" => Some(BinOp::UShr),
925 "&&=" | "||=" | "??=" => {
926 self.advance();
932 let value = self.parse_assign()?;
933 let lop = match op.as_str() {
934 "&&=" => LogicalOp::And,
935 "||=" => LogicalOp::Or,
936 _ => LogicalOp::Nullish,
937 };
938 return Ok(Expr::Assign {
939 target: Box::new(left),
940 op: Some(AssignOp::Logical(lop)),
941 value: Box::new(value),
942 });
943 }
944 _ => return Ok(left),
945 };
946 self.advance();
947 let value = self.parse_assign()?;
948 Ok(Expr::Assign {
949 target: Box::new(left),
950 op: compound.map(AssignOp::Binary),
951 value: Box::new(value),
952 })
953 }
954
955 fn parse_conditional(&mut self) -> Result<Expr, String> {
956 let test = self.parse_binary(0)?;
957 if self.eat_punct("?") {
958 let cons = self.parse_assign()?;
959 self.expect_punct(":")?;
960 let alt = self.parse_assign()?;
961 Ok(Expr::Conditional {
962 test: Box::new(test),
963 cons: Box::new(cons),
964 alt: Box::new(alt),
965 })
966 } else {
967 Ok(test)
968 }
969 }
970
971 fn parse_binary(&mut self, min_prec: u8) -> Result<Expr, String> {
973 let mut left = self.parse_unary()?;
974 while let Some((prec, right_assoc, logical, bin)) = self.bin_info() {
975 if prec < min_prec {
976 break;
977 }
978 self.advance();
979 let next_min = if right_assoc { prec } else { prec + 1 };
980 let right = self.parse_binary(next_min)?;
981 left = if let Some(lop) = logical {
982 Expr::Logical(lop, Box::new(left), Box::new(right))
983 } else {
984 Expr::Binary(bin.unwrap(), Box::new(left), Box::new(right))
985 };
986 }
987 Ok(left)
988 }
989
990 fn bin_info(&self) -> Option<(u8, bool, Option<LogicalOp>, Option<BinOp>)> {
992 let p = match self.tok() {
993 Tok::Punct(p) => p.as_str(),
994 Tok::Ident(s) if s == "in" => {
997 if self.no_in {
998 return None;
999 }
1000 "in"
1001 }
1002 Tok::Ident(s) if s == "instanceof" => "instanceof",
1003 _ => return None,
1004 };
1005 let (prec, ra, log, bin) = match p {
1006 "??" => (1, false, Some(LogicalOp::Nullish), None),
1007 "||" => (2, false, Some(LogicalOp::Or), None),
1008 "&&" => (3, false, Some(LogicalOp::And), None),
1009 "|" => (4, false, None, Some(BinOp::BitOr)),
1010 "^" => (5, false, None, Some(BinOp::BitXor)),
1011 "&" => (6, false, None, Some(BinOp::BitAnd)),
1012 "==" => (7, false, None, Some(BinOp::EqEq)),
1013 "!=" => (7, false, None, Some(BinOp::NeEq)),
1014 "===" => (7, false, None, Some(BinOp::EqEqEq)),
1015 "!==" => (7, false, None, Some(BinOp::NeEqEq)),
1016 "<" => (8, false, None, Some(BinOp::Lt)),
1017 "<=" => (8, false, None, Some(BinOp::Le)),
1018 ">" => (8, false, None, Some(BinOp::Gt)),
1019 ">=" => (8, false, None, Some(BinOp::Ge)),
1020 "in" => (8, false, None, Some(BinOp::In)),
1021 "instanceof" => (8, false, None, Some(BinOp::InstanceOf)),
1022 "<<" => (9, false, None, Some(BinOp::Shl)),
1023 ">>" => (9, false, None, Some(BinOp::Shr)),
1024 ">>>" => (9, false, None, Some(BinOp::UShr)),
1025 "+" => (10, false, None, Some(BinOp::Add)),
1026 "-" => (10, false, None, Some(BinOp::Sub)),
1027 "*" => (11, false, None, Some(BinOp::Mul)),
1028 "/" => (11, false, None, Some(BinOp::Div)),
1029 "%" => (11, false, None, Some(BinOp::Mod)),
1030 "**" => (12, true, None, Some(BinOp::Pow)),
1031 _ => return None,
1032 };
1033 Some((prec, ra, log, bin))
1034 }
1035
1036 fn reject_unary_before_pow(&mut self) -> Result<(), String> {
1041 if self.is_punct("**") {
1042 return Err(format!(
1043 "SyntaxError: Unary operator used immediately before exponentiation \
1044 expression. Parenthesis must be used to disambiguate operator \
1045 precedence (line {})",
1046 self.line()
1047 ));
1048 }
1049 Ok(())
1050 }
1051
1052 fn parse_unary(&mut self) -> Result<Expr, String> {
1053 let op = match self.tok() {
1054 Tok::Punct(p) if p == "!" => Some(UnOp::Not),
1055 Tok::Punct(p) if p == "~" => Some(UnOp::BitNot),
1056 Tok::Punct(p) if p == "+" => Some(UnOp::Pos),
1057 Tok::Punct(p) if p == "-" => Some(UnOp::Neg),
1058 Tok::Ident(s) if s == "typeof" => Some(UnOp::TypeOf),
1059 Tok::Ident(s) if s == "void" => Some(UnOp::Void),
1060 Tok::Ident(s) if s == "delete" => Some(UnOp::Delete),
1061 _ => None,
1062 };
1063 if let Some(op) = op {
1064 self.advance();
1065 let e = self.parse_unary()?;
1066 self.reject_unary_before_pow()?;
1070 return Ok(Expr::Unary(op, Box::new(e)));
1071 }
1072 if self.is_punct("++") || self.is_punct("--") {
1074 let op = if self.is_punct("++") {
1075 UpdateOp::Inc
1076 } else {
1077 UpdateOp::Dec
1078 };
1079 self.advance();
1080 let e = self.parse_unary()?;
1081 return Ok(Expr::Update {
1082 op,
1083 prefix: true,
1084 target: Box::new(e),
1085 });
1086 }
1087 self.parse_postfix()
1088 }
1089
1090 fn parse_postfix(&mut self) -> Result<Expr, String> {
1091 let mut e = self.parse_call_member()?;
1092 if (self.is_punct("++") || self.is_punct("--")) && !self.newline_before() {
1094 let op = if self.is_punct("++") {
1095 UpdateOp::Inc
1096 } else {
1097 UpdateOp::Dec
1098 };
1099 self.advance();
1100 e = Expr::Update {
1101 op,
1102 prefix: false,
1103 target: Box::new(e),
1104 };
1105 }
1106 Ok(e)
1107 }
1108
1109 fn parse_call_member(&mut self) -> Result<Expr, String> {
1110 let mut e = if self.eat_kw("new") {
1111 if self.is_punct(".") {
1113 self.advance();
1114 let prop = self.ident_name()?;
1115 if prop != "target" {
1116 return Err(format!(
1117 "SyntaxError: expected 'target' (line {})",
1118 self.line()
1119 ));
1120 }
1121 Expr::NewTarget
1122 } else {
1123 let callee = self.parse_call_member_no_call()?;
1124 if Self::has_optional_link(&callee) || self.is_punct("?.") {
1130 return Err(
1131 "SyntaxError: Invalid optional chain from new expression".to_string()
1132 );
1133 }
1134 let args = if self.is_punct("(") {
1135 self.parse_args()?
1136 } else {
1137 Vec::new()
1138 };
1139 Expr::New {
1140 callee: Box::new(callee),
1141 args,
1142 }
1143 }
1144 } else {
1145 self.parse_primary()?
1146 };
1147 loop {
1148 if self.eat_punct(".") {
1149 let property = self.ident_name()?;
1150 self.check_private_in_scope(&property)?;
1151 e = Expr::Member {
1152 object: Box::new(e),
1153 property,
1154 optional: false,
1155 };
1156 } else if self.eat_punct("?.") {
1157 if self.is_punct("(") {
1158 let args = self.parse_args()?;
1159 e = Expr::Call {
1160 func: Box::new(e),
1161 args,
1162 optional: true,
1163 };
1164 } else if self.is_punct("[") {
1165 self.advance();
1166 let index = self.allow_in(|p| p.parse_expr())?;
1167 self.expect_punct("]")?;
1168 e = Expr::Index {
1169 object: Box::new(e),
1170 index: Box::new(index),
1171 optional: true,
1172 };
1173 } else {
1174 let property = self.ident_name()?;
1175 e = Expr::Member {
1176 object: Box::new(e),
1177 property,
1178 optional: true,
1179 };
1180 }
1181 } else if self.is_punct("[") {
1182 self.advance();
1183 let index = self.allow_in(|p| p.parse_expr())?;
1184 self.expect_punct("]")?;
1185 e = Expr::Index {
1186 object: Box::new(e),
1187 index: Box::new(index),
1188 optional: false,
1189 };
1190 } else if self.is_punct("(") {
1191 let args = self.parse_args()?;
1192 e = Expr::Call {
1193 func: Box::new(e),
1194 args,
1195 optional: false,
1196 };
1197 } else if matches!(self.tok(), Tok::Template { .. }) {
1198 if Self::has_optional_link(&e) {
1204 return Err(
1205 "SyntaxError: Invalid tagged template on optional chain".to_string()
1206 );
1207 }
1208 e = self.parse_tagged_template(e)?;
1209 } else {
1210 break;
1211 }
1212 }
1213 Ok(e)
1214 }
1215
1216 fn parse_tagged_template(&mut self, tag: Expr) -> Result<Expr, String> {
1219 let (quasis, raws, exprs_src) = match self.tok().clone() {
1220 Tok::Template {
1221 quasis,
1222 raws,
1223 exprs,
1224 } => (quasis, raws, exprs),
1225 _ => unreachable!(),
1226 };
1227 self.advance();
1228 let mut exprs = Vec::new();
1229 for src in &exprs_src {
1230 exprs.push(parse_expr_source(src)?);
1231 }
1232 Ok(Expr::TaggedTemplate {
1233 tag: Box::new(tag),
1234 quasis,
1235 raws,
1236 exprs,
1237 })
1238 }
1239
1240 fn parse_call_member_no_call(&mut self) -> Result<Expr, String> {
1242 let mut e = self.parse_primary()?;
1243 loop {
1244 if self.eat_punct(".") {
1245 let property = self.ident_name()?;
1246 self.check_private_in_scope(&property)?;
1247 e = Expr::Member {
1248 object: Box::new(e),
1249 property,
1250 optional: false,
1251 };
1252 } else if self.is_punct("[") {
1253 self.advance();
1254 let index = self.allow_in(|p| p.parse_expr())?;
1255 self.expect_punct("]")?;
1256 e = Expr::Index {
1257 object: Box::new(e),
1258 index: Box::new(index),
1259 optional: false,
1260 };
1261 } else {
1262 break;
1263 }
1264 }
1265 Ok(e)
1266 }
1267
1268 fn parse_args(&mut self) -> Result<Vec<Expr>, String> {
1269 self.expect_punct("(")?;
1270 let args = self.allow_in(|p| {
1273 let mut args = Vec::new();
1274 while !p.is_punct(")") {
1275 if p.eat_punct("...") {
1276 let e = p.parse_assign()?;
1277 args.push(Expr::Spread(Box::new(e)));
1278 } else {
1279 args.push(p.parse_assign()?);
1280 }
1281 if !p.eat_punct(",") {
1282 break;
1283 }
1284 }
1285 Ok(args)
1286 })?;
1287 self.expect_punct(")")?;
1288 Ok(args)
1289 }
1290
1291 fn parse_primary(&mut self) -> Result<Expr, String> {
1292 match self.tok().clone() {
1293 Tok::Num(n) => {
1294 self.advance();
1295 Ok(Expr::Number(n))
1296 }
1297 Tok::BigInt(s) => {
1298 self.advance();
1299 Ok(Expr::BigInt(s))
1300 }
1301 Tok::Regex(pat, flags) => {
1302 self.advance();
1303 Ok(Expr::Regex(pat, flags))
1304 }
1305 Tok::Str(s) => {
1306 self.advance();
1307 Ok(Expr::Str(s))
1308 }
1309 Tok::Template {
1310 quasis,
1311 raws: _,
1312 exprs,
1313 } => {
1314 self.advance();
1315 let mut parsed = Vec::new();
1316 for src in &exprs {
1317 parsed.push(parse_expr_source(src)?);
1318 }
1319 Ok(Expr::Template {
1320 quasis,
1321 exprs: parsed,
1322 })
1323 }
1324 Tok::Punct(p) if p == "(" => {
1325 self.advance();
1326 let e = self.parse_expr()?;
1327 self.expect_punct(")")?;
1328 if Self::has_optional_link(&e) {
1344 return Ok(Expr::Sequence(vec![e]));
1345 }
1346 Ok(e)
1347 }
1348 Tok::Punct(p) if p == "[" => self.parse_array_literal(),
1349 Tok::Punct(p) if p == "{" => self.parse_object_literal(),
1350 Tok::Ident(s) => {
1351 match s.as_str() {
1352 "true" => {
1353 self.advance();
1354 Ok(Expr::True)
1355 }
1356 "false" => {
1357 self.advance();
1358 Ok(Expr::False)
1359 }
1360 "null" => {
1361 self.advance();
1362 Ok(Expr::Null)
1363 }
1364 "this" => {
1365 self.advance();
1366 Ok(Expr::This)
1367 }
1368 "super" => {
1369 self.advance();
1370 Ok(Expr::Super)
1371 }
1372 "class" => Ok(Expr::Class(Box::new(self.parse_class(false)?))),
1373 "function" => self.parse_function_expr(false),
1374 "async" if self.peek_kw(1, "function") && !self.peek_newline(1) => {
1375 self.advance(); self.parse_function_expr(true)
1377 }
1378 "yield" if self.in_generator => {
1379 self.advance();
1380 let delegate = self.eat_punct("*");
1381 let arg = if delegate
1384 || !(self.is_punct(")")
1385 || self.is_punct("]")
1386 || self.is_punct("}")
1387 || self.is_punct(",")
1388 || self.is_punct(";")
1389 || self.is_punct(":")
1390 || self.newline_before()
1391 || self.at_eof())
1392 {
1393 Some(Box::new(self.parse_assign()?))
1394 } else {
1395 None
1396 };
1397 Ok(Expr::Yield { arg, delegate })
1398 }
1399 "await" if self.in_async => {
1400 self.advance();
1401 let e = self.parse_unary()?;
1402 self.reject_unary_before_pow()?;
1405 Ok(Expr::Await(Box::new(e)))
1406 }
1407 _ if is_keyword(&s) => Err(format!(
1408 "SyntaxError: unexpected keyword '{s}' (line {})",
1409 self.line()
1410 )),
1411 _ => {
1412 self.advance();
1413 Ok(Expr::Ident(s))
1414 }
1415 }
1416 }
1417 other => Err(format!(
1418 "SyntaxError: unexpected token {other:?} (line {})",
1419 self.line()
1420 )),
1421 }
1422 }
1423
1424 fn parse_array_literal(&mut self) -> Result<Expr, String> {
1425 self.expect_punct("[")?;
1426 let mut items = Vec::new();
1427 while !self.is_punct("]") {
1428 if self.is_punct(",") {
1429 items.push(Expr::Hole);
1431 self.advance();
1432 continue;
1433 }
1434 if self.eat_punct("...") {
1435 let e = self.parse_assign()?;
1436 items.push(Expr::Spread(Box::new(e)));
1437 } else {
1438 items.push(self.parse_assign()?);
1439 }
1440 if !self.eat_punct(",") {
1441 break;
1442 }
1443 }
1444 self.expect_punct("]")?;
1445 Ok(Expr::Array(items))
1446 }
1447
1448 fn parse_object_literal(&mut self) -> Result<Expr, String> {
1449 self.expect_punct("{")?;
1450 let mut props = Vec::new();
1451 while !self.is_punct("}") {
1452 if self.eat_punct("...") {
1453 let e = self.parse_assign()?;
1454 props.push(Prop::Spread(e));
1455 if !self.eat_punct(",") {
1456 break;
1457 }
1458 continue;
1459 }
1460 if (self.is_kw("get") || self.is_kw("set"))
1463 && !self.peek_is_member_punct(1)
1464 && !matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":" || p == ",")
1465 {
1466 let is_getter = self.is_kw("get");
1467 self.advance();
1468 let (key, computed) = self.parse_property_key()?;
1469 let params = self.parse_params()?;
1470 self.expect_punct("{")?;
1471 let body = self.parse_block_body()?;
1472 let func = Expr::Function {
1473 params,
1474 body: FnBody::Block(body),
1475 is_arrow: false,
1476 name: None,
1477 is_generator: false,
1478 is_async: false,
1479 is_method: true,
1480 };
1481 props.push(Prop::Accessor {
1482 key,
1483 computed,
1484 is_getter,
1485 func,
1486 });
1487 if !self.eat_punct(",") {
1488 break;
1489 }
1490 continue;
1491 }
1492 let mut m_async = false;
1494 let mut m_gen = false;
1495 if self.is_kw("async")
1496 && !self.peek_is_member_punct(1)
1497 && !self.peek_newline(1)
1498 && !matches!(self.toks.get(self.pos + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == ":" || p == ",")
1499 {
1500 self.advance();
1501 m_async = true;
1502 }
1503 if self.is_punct("*") {
1504 self.advance();
1505 m_gen = true;
1506 }
1507 let (key, computed) = self.parse_property_key()?;
1508 if self.is_punct("(") {
1510 let params = self.parse_params()?;
1511 self.expect_punct("{")?;
1512 let body = self.parse_fn_body_block(m_gen, m_async)?;
1513 let f = Expr::Function {
1514 params,
1515 body: FnBody::Block(body),
1516 is_arrow: false,
1517 name: None,
1518 is_generator: m_gen,
1519 is_async: m_async,
1520 is_method: true,
1521 };
1522 props.push(Prop::KeyValue {
1523 key,
1524 value: f,
1525 computed,
1526 });
1527 } else if self.eat_punct(":") {
1528 let value = self.parse_assign()?;
1529 props.push(Prop::KeyValue {
1530 key,
1531 value,
1532 computed,
1533 });
1534 } else {
1535 let name = match &key {
1538 Expr::Str(s) => s.clone(),
1539 _ => return Err(format!("SyntaxError: bad shorthand (line {})", self.line())),
1540 };
1541 let value = if self.eat_punct("=") {
1542 let d = self.parse_assign()?;
1544 Expr::Assign {
1545 target: Box::new(Expr::Ident(name.clone())),
1546 op: None,
1547 value: Box::new(d),
1548 }
1549 } else {
1550 Expr::Ident(name)
1551 };
1552 props.push(Prop::KeyValue {
1553 key,
1554 value,
1555 computed,
1556 });
1557 }
1558 if !self.eat_punct(",") {
1559 break;
1560 }
1561 }
1562 self.expect_punct("}")?;
1563 Ok(Expr::Object(props))
1564 }
1565
1566 fn parse_params(&mut self) -> Result<Vec<Param>, String> {
1568 self.expect_punct("(")?;
1569 let mut params = Vec::new();
1570 while !self.is_punct(")") {
1571 let rest = self.eat_punct("...");
1572 let pattern = self.parse_binding_target()?;
1573 let default = if !rest && self.eat_punct("=") {
1574 Some(self.parse_assign()?)
1575 } else {
1576 None
1577 };
1578 params.push(Param {
1579 pattern,
1580 default,
1581 rest,
1582 });
1583 if !self.eat_punct(",") {
1584 break;
1585 }
1586 }
1587 self.expect_punct(")")?;
1588 Ok(params)
1589 }
1590
1591 fn try_parse_arrow(&mut self) -> Result<Option<Expr>, String> {
1594 let mut is_async = false;
1597 let mut base = self.pos;
1598 if self.is_kw("async") && !self.peek_newline(1) {
1599 let next = self.toks.get(self.pos + 1).map(|t| &t.tok);
1600 let looks_async_arrow = matches!(next, Some(Tok::Punct(p)) if p == "(")
1601 || matches!(next, Some(Tok::Ident(n)) if !is_keyword(n) && self.peek_is_arrow_after(2));
1602 if looks_async_arrow {
1603 is_async = true;
1604 base += 1;
1605 }
1606 }
1607 if let Some(Tok::Ident(name)) = self.toks.get(base).map(|t| &t.tok) {
1609 if !is_keyword(name)
1610 && matches!(self.toks.get(base + 1).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1611 {
1612 let name = name.clone();
1613 if is_async {
1614 self.advance(); }
1616 self.advance(); self.advance(); let body = self.parse_arrow_body(is_async)?;
1619 return Ok(Some(Expr::Function {
1620 params: vec![Param {
1621 pattern: Expr::Ident(name),
1622 default: None,
1623 rest: false,
1624 }],
1625 body,
1626 is_arrow: true,
1627 name: None,
1628 is_generator: false,
1629 is_async,
1630 is_method: false,
1631 }));
1632 }
1633 }
1634 if matches!(self.toks.get(base).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "(") {
1636 if let Some(close) = self.matching_paren(base) {
1637 let after = close + 1;
1638 if matches!(self.toks.get(after).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1639 {
1640 if is_async {
1641 self.advance(); }
1643 let params = self.parse_params()?;
1644 self.expect_punct("=>")?;
1645 let body = self.parse_arrow_body(is_async)?;
1646 return Ok(Some(Expr::Function {
1647 params,
1648 body,
1649 is_arrow: true,
1650 name: None,
1651 is_generator: false,
1652 is_async,
1653 is_method: false,
1654 }));
1655 }
1656 }
1657 }
1658 Ok(None)
1659 }
1660
1661 fn parse_arrow_body(&mut self, is_async: bool) -> Result<FnBody, String> {
1662 let (pg, pa) = (self.in_generator, self.in_async);
1663 self.in_generator = false;
1664 self.in_async = is_async;
1665 let r = if self.is_punct("{") {
1666 self.advance();
1667 self.parse_block_body().map(FnBody::Block)
1668 } else {
1669 self.parse_assign().map(|e| FnBody::Expr(Box::new(e)))
1670 };
1671 self.in_generator = pg;
1672 self.in_async = pa;
1673 r
1674 }
1675
1676 fn peek_is_arrow_after(&self, n: usize) -> bool {
1678 matches!(self.toks.get(self.pos + n).map(|t| &t.tok), Some(Tok::Punct(p)) if p == "=>")
1679 }
1680
1681 fn matching_paren(&self, open: usize) -> Option<usize> {
1683 let mut depth = 0i32;
1684 let mut i = open;
1685 while i < self.toks.len() {
1686 match &self.toks[i].tok {
1687 Tok::Punct(p) if p == "(" || p == "[" || p == "{" => depth += 1,
1688 Tok::Punct(p) if p == ")" || p == "]" || p == "}" => {
1689 depth -= 1;
1690 if depth == 0 {
1691 return Some(i);
1692 }
1693 }
1694 Tok::Eof => return None,
1695 _ => {}
1696 }
1697 i += 1;
1698 }
1699 None
1700 }
1701}
1702
1703fn parse_expr_source(src: &str) -> Result<Expr, String> {
1705 let toks = lex(src)?;
1706 let mut p = Parser {
1707 toks,
1708 pos: 0,
1709 in_generator: false,
1710 in_async: false,
1711 no_in: false,
1712 class_scopes: Vec::new(),
1713 };
1714 let e = p.parse_expr()?;
1715 Ok(e)
1716}