1use alloc::boxed::Box;
8use alloc::rc::Rc;
9use core::cell::RefCell;
10use alloc::string::String;
11use alloc::vec::Vec;
12
13#[derive(Debug, Clone, PartialEq)]
14pub enum BinaryOp {
15 Add,
16 Sub,
17 Mul,
18 Div,
19 Mod,
20 Pow,
21 Eq,
22 NotEq,
23 StrictEq,
24 StrictNotEq,
25 Lt,
26 Gt,
27 LtEq,
28 GtEq,
29 BitAnd,
30 BitOr,
31 BitXor,
32 Shl,
33 Shr,
34 UShr,
35 InstanceOf,
36 In,
37}
38
39#[derive(Debug, Clone, PartialEq)]
40pub enum LogicalOp {
41 And, Or, Nullish, }
45
46#[derive(Debug, Clone, PartialEq)]
47pub enum UnaryOp {
48 Neg, Pos, Not, BitNot, TypeOf, Void, Delete, }
56
57#[derive(Debug, Clone, PartialEq)]
59pub struct Property {
60 pub key: String,
61 pub value: Expression,
62 pub computed: Option<Expression>,
64 pub accessor: Option<bool>,
67}
68
69pub const OBJECT_SPREAD_KEY: &str = "\u{0}spread";
71
72#[derive(Debug, Clone, PartialEq)]
73pub enum Expression {
74 Number(f64),
75 BigIntLit(String),
77 Str(String),
78 Bool(bool),
79 Null,
80 Undefined,
81 Identifier(String),
82 This,
83 TemplateLiteral {
84 quasis: Vec<String>,
86 exprs: Vec<Expression>,
87 },
88 TaggedTemplate {
92 tag: Box<Expression>,
93 quasis: Vec<String>,
94 raw: Vec<String>,
95 exprs: Vec<Expression>,
96 },
97 Array(Vec<Expression>),
98 Object(Vec<Property>),
99 Function {
103 name: Option<String>,
104 params: Rc<Vec<Param>>,
105 body: Rc<FnBody>,
106 is_arrow: bool,
107 is_async: bool,
108 is_generator: bool,
109 },
110 Await(Box<Expression>),
112 Yield {
114 argument: Option<Box<Expression>>,
115 delegate: bool,
116 },
117 Unary {
118 op: UnaryOp,
119 expr: Box<Expression>,
120 },
121 Update {
122 op: String, prefix: bool,
124 target: Box<Expression>,
125 },
126 Binary {
127 op: BinaryOp,
128 left: Box<Expression>,
129 right: Box<Expression>,
130 },
131 Logical {
132 op: LogicalOp,
133 left: Box<Expression>,
134 right: Box<Expression>,
135 },
136 Assign {
137 op: String, target: Box<Expression>,
139 value: Box<Expression>,
140 },
141 Conditional {
142 test: Box<Expression>,
143 consequent: Box<Expression>,
144 alternate: Box<Expression>,
145 },
146 Member {
147 object: Box<Expression>,
148 property: String,
149 optional: bool, },
151 Index {
152 object: Box<Expression>,
153 index: Box<Expression>,
154 optional: bool, },
156 Call {
157 callee: Box<Expression>,
158 arguments: Vec<Expression>,
159 optional: bool, },
161 New {
162 callee: Box<Expression>,
163 arguments: Vec<Expression>,
164 },
165 Spread(Box<Expression>),
167 Class {
169 name: Option<String>,
170 superclass: Option<Box<Expression>>,
171 members: Vec<ClassMember>,
172 },
173 Super,
175 Sequence(Vec<Expression>),
178 NewTarget,
181 Regex(String, String),
183}
184
185#[derive(Debug, Clone, PartialEq)]
187pub enum MethodKind {
188 Method,
189 Constructor,
190 Field,
193 Getter,
195 Setter,
197 StaticBlock,
200}
201
202#[derive(Debug, Clone, PartialEq)]
204pub struct ClassMember {
205 pub key: String,
206 pub computed_key: Option<Expression>,
209 pub kind: MethodKind,
210 pub params: Rc<Vec<Param>>,
211 pub body: Rc<FnBody>,
212 pub is_static: bool,
213 pub field_init: Option<Expression>,
215 pub is_async: bool,
217 pub is_generator: bool,
219}
220
221#[derive(Debug, Clone, PartialEq)]
222pub enum VarKind {
223 Var,
224 Let,
225 Const,
226 Using,
229 AwaitUsing,
231}
232
233#[derive(Debug, Clone, PartialEq)]
235pub enum Pattern {
236 Identifier(String),
237 Object(Vec<ObjPatProp>),
239 Array(Vec<ArrPatElem>),
241 Expr(Box<Expression>),
244}
245
246#[derive(Debug, Clone, PartialEq)]
248pub struct ObjPatProp {
249 pub key: String,
252 pub computed_key: Option<Expression>,
254 pub value: Pattern,
256 pub default: Option<Expression>,
257 pub is_rest: bool,
258}
259
260#[derive(Debug, Clone, PartialEq)]
262pub struct ArrPatElem {
263 pub pattern: Option<Pattern>,
265 pub default: Option<Expression>,
266 pub is_rest: bool,
267}
268
269#[derive(Debug, Clone, PartialEq)]
271pub struct Param {
272 pub pattern: Pattern,
273 pub default: Option<Expression>,
274 pub is_rest: bool,
275}
276
277#[derive(Debug, Clone, PartialEq)]
278pub enum Statement {
279 Expression(Expression),
280 VarDeclaration {
281 kind: VarKind,
282 decls: Vec<(Pattern, Option<Expression>)>,
284 },
285 Block(Vec<Statement>),
286 If {
287 test: Expression,
288 consequent: Box<Statement>,
289 alternate: Option<Box<Statement>>,
290 },
291 While {
292 test: Expression,
293 body: Box<Statement>,
294 },
295 DoWhile {
296 body: Box<Statement>,
297 test: Expression,
298 },
299 For {
300 init: Option<Box<Statement>>,
301 test: Option<Expression>,
302 update: Option<Expression>,
303 body: Box<Statement>,
304 },
305 ForIn {
306 decl_kind: Option<VarKind>,
307 pattern: Pattern,
308 object: Expression,
309 body: Box<Statement>,
310 of: bool, is_await: bool,
314 },
315 FunctionDeclaration {
316 name: String,
317 params: Rc<Vec<Param>>,
318 body: Rc<FnBody>,
319 is_async: bool,
320 is_generator: bool,
321 },
322 Return(Option<Expression>),
323 Break(Option<String>),
325 Continue(Option<String>),
327 Labeled(String, Box<Statement>),
330 Throw(Expression),
331 Switch {
332 discriminant: Expression,
333 cases: Vec<SwitchCase>,
334 },
335 Try {
336 block: Vec<Statement>,
337 catch_param: Option<Pattern>,
339 catch_block: Option<Vec<Statement>>,
340 finally_block: Option<Vec<Statement>>,
341 },
342 Import {
345 source: String,
347 default: Option<String>,
349 namespace: Option<String>,
351 named: Vec<(String, String)>,
353 side_effect_only: bool,
355 },
356 ExportNamed {
358 specifiers: Vec<(String, String)>,
360 source: Option<String>,
362 },
363 ExportDefault(Expression),
365 ExportDecl {
368 declaration: Box<Statement>,
369 names: Vec<String>,
370 },
371 ExportAll {
373 source: String,
374 },
375 Empty,
376}
377
378#[derive(Debug, Clone, PartialEq)]
380pub struct SwitchCase {
381 pub test: Option<Expression>,
382 pub body: Vec<Statement>,
383}
384
385#[derive(Debug, Clone, PartialEq)]
386pub struct Program {
387 pub body: Vec<Statement>,
388}
389
390pub struct FnBody {
397 state: RefCell<FnBodyState>,
398 pub strict: bool,
401 uses_args: core::cell::Cell<u8>,
403}
404
405enum FnBodyState {
406 Parsed(Rc<Vec<Statement>>),
407 Source { src: Rc<String>, calls: u8 },
408}
409
410impl FnBody {
411 pub fn parsed(stmts: Vec<Statement>) -> Rc<Self> {
412 Self::parsed_with(stmts, false)
413 }
414
415 pub fn parsed_with(stmts: Vec<Statement>, strict: bool) -> Rc<Self> {
416 Rc::new(Self {
417 state: RefCell::new(FnBodyState::Parsed(Rc::new(stmts))),
418 strict,
419 uses_args: core::cell::Cell::new(0),
420 })
421 }
422
423 pub fn from_rc(stmts: Rc<Vec<Statement>>) -> Rc<Self> {
424 Rc::new(Self {
425 state: RefCell::new(FnBodyState::Parsed(stmts)),
426 strict: false,
427 uses_args: core::cell::Cell::new(0),
428 })
429 }
430
431 pub fn lazy(source: String, strict: bool) -> Rc<Self> {
432 Rc::new(Self {
433 state: RefCell::new(FnBodyState::Source {
434 src: Rc::new(source),
435 calls: 0,
436 }),
437 strict,
438 uses_args: core::cell::Cell::new(0),
439 })
440 }
441
442 pub fn is_lazy(&self) -> bool {
444 matches!(&*self.state.borrow(), FnBodyState::Source { .. })
445 }
446
447 pub fn stmts(&self) -> Rc<Vec<Statement>> {
457 enum Action {
458 Cached(Rc<Vec<Statement>>),
459 ParseOnce(Rc<String>),
460 ParseAndDrop(Rc<String>),
461 ParseAndCache(Rc<String>),
462 }
463 let action = {
464 let mut b = self.state.borrow_mut();
465 match &mut *b {
466 FnBodyState::Parsed(s) => Action::Cached(s.clone()),
467 FnBodyState::Source { src, calls } => {
468 if src.len() >= 65_536 {
469 let s = src.clone();
470 *b = FnBodyState::Parsed(Rc::new(Vec::new()));
471 Action::ParseAndDrop(s)
472 } else if *calls == 0 {
473 *calls = 1;
474 Action::ParseOnce(src.clone())
475 } else {
476 let s = src.clone();
477 *b = FnBodyState::Parsed(Rc::new(Vec::new()));
478 Action::ParseAndCache(s)
479 }
480 }
481 }
482 };
483 match action {
484 Action::Cached(s) => s,
485 Action::ParseOnce(src) => {
486 Rc::new(super::parser::parse_function_body_source(&src, self.strict))
487 }
488 Action::ParseAndDrop(src) => {
489 let parsed = Rc::new(super::parser::parse_function_body_source(&src, self.strict));
490 drop(src);
491 parsed
492 }
493 Action::ParseAndCache(src) => {
494 let parsed = Rc::new(super::parser::parse_function_body_source(&src, self.strict));
495 drop(src);
496 *self.state.borrow_mut() = FnBodyState::Parsed(parsed.clone());
497 parsed
498 }
499 }
500 }
501
502 pub fn uses_arguments(&self, stmts: &[Statement]) -> bool {
504 match self.uses_args.get() {
505 1 => false,
506 2 => true,
507 _ => {
508 let u = stmts_use_arguments(stmts);
509 self.uses_args.set(if u { 2 } else { 1 });
510 u
511 }
512 }
513 }
514
515 fn raw_might_use_arguments(&self) -> bool {
516 match self.uses_args.get() {
517 1 => false,
518 2 => true,
519 _ => match &*self.state.borrow() {
520 FnBodyState::Source { src, .. } => {
521 src.contains("arguments") || src.contains("eval")
522 }
523 FnBodyState::Parsed(s) => {
524 let u = stmts_use_arguments(s);
525 self.uses_args.set(if u { 2 } else { 1 });
526 u
527 }
528 },
529 }
530 }
531}
532
533fn stmts_use_arguments(stmts: &[Statement]) -> bool {
534 stmts.iter().any(stmt_uses_arguments)
535}
536
537fn stmt_uses_arguments(stmt: &Statement) -> bool {
538 match stmt {
539 Statement::Expression(e)
540 | Statement::Return(Some(e))
541 | Statement::Throw(e)
542 | Statement::ExportDefault(e) => expr_uses_arguments(e),
543 Statement::VarDeclaration { decls, .. } => decls
544 .iter()
545 .any(|(p, init)| pat_uses_arguments(p) || init.as_ref().is_some_and(expr_uses_arguments)),
546 Statement::Block(b) => stmts_use_arguments(b),
547 Statement::If {
548 test,
549 consequent,
550 alternate,
551 } => {
552 expr_uses_arguments(test)
553 || stmt_uses_arguments(consequent)
554 || alternate.as_deref().is_some_and(stmt_uses_arguments)
555 }
556 Statement::While { test, body } | Statement::DoWhile { body, test } => {
557 expr_uses_arguments(test) || stmt_uses_arguments(body)
558 }
559 Statement::For {
560 init,
561 test,
562 update,
563 body,
564 } => {
565 init.as_deref().is_some_and(stmt_uses_arguments)
566 || test.as_ref().is_some_and(expr_uses_arguments)
567 || update.as_ref().is_some_and(expr_uses_arguments)
568 || stmt_uses_arguments(body)
569 }
570 Statement::ForIn {
571 pattern,
572 object,
573 body,
574 ..
575 } => {
576 pat_uses_arguments(pattern)
577 || expr_uses_arguments(object)
578 || stmt_uses_arguments(body)
579 }
580 Statement::Labeled(_, s) | Statement::ExportDecl { declaration: s, .. } => {
581 stmt_uses_arguments(s)
582 }
583 Statement::Switch {
584 discriminant,
585 cases,
586 } => {
587 expr_uses_arguments(discriminant)
588 || cases.iter().any(|c| {
589 c.test.as_ref().is_some_and(expr_uses_arguments)
590 || stmts_use_arguments(&c.body)
591 })
592 }
593 Statement::Try {
594 block,
595 catch_param,
596 catch_block,
597 finally_block,
598 } => {
599 stmts_use_arguments(block)
600 || catch_param.as_ref().is_some_and(pat_uses_arguments)
601 || catch_block.as_deref().is_some_and(stmts_use_arguments)
602 || finally_block.as_deref().is_some_and(stmts_use_arguments)
603 }
604 Statement::FunctionDeclaration { .. }
606 | Statement::Return(None)
607 | Statement::Break(_)
608 | Statement::Continue(_)
609 | Statement::Import { .. }
610 | Statement::ExportNamed { .. }
611 | Statement::ExportAll { .. }
612 | Statement::Empty => false,
613 }
614}
615
616fn pat_uses_arguments(pat: &Pattern) -> bool {
617 match pat {
618 Pattern::Identifier(n) => n == "arguments" || n == "eval",
619 Pattern::Object(props) => props.iter().any(|p| {
620 p.computed_key.as_ref().is_some_and(expr_uses_arguments)
621 || pat_uses_arguments(&p.value)
622 || p.default.as_ref().is_some_and(expr_uses_arguments)
623 }),
624 Pattern::Array(elems) => elems.iter().any(|e| {
625 e.pattern.as_ref().is_some_and(pat_uses_arguments)
626 || e.default.as_ref().is_some_and(expr_uses_arguments)
627 }),
628 Pattern::Expr(e) => expr_uses_arguments(e),
629 }
630}
631
632fn expr_uses_arguments(expr: &Expression) -> bool {
633 match expr {
634 Expression::Identifier(n) => n == "arguments" || n == "eval",
635 Expression::TemplateLiteral { exprs, .. } | Expression::Array(exprs) | Expression::Sequence(exprs) => {
636 exprs.iter().any(expr_uses_arguments)
637 }
638 Expression::TaggedTemplate { tag, exprs, .. } => {
639 expr_uses_arguments(tag) || exprs.iter().any(expr_uses_arguments)
640 }
641 Expression::Object(props) => props.iter().any(|p| {
642 p.computed.as_ref().is_some_and(expr_uses_arguments) || expr_uses_arguments(&p.value)
643 }),
644 Expression::Function {
645 params,
646 body,
647 is_arrow,
648 ..
649 } => {
650 if !*is_arrow {
651 false
652 } else {
653 params.iter().any(|p| {
654 pat_uses_arguments(&p.pattern)
655 || p.default.as_ref().is_some_and(expr_uses_arguments)
656 }) || body.raw_might_use_arguments()
657 }
658 }
659 Expression::Await(e)
660 | Expression::Unary { expr: e, .. }
661 | Expression::Update { target: e, .. }
662 | Expression::Spread(e)
663 | Expression::Member { object: e, .. } => expr_uses_arguments(e),
664 Expression::Yield { argument, .. } => argument.as_deref().is_some_and(expr_uses_arguments),
665 Expression::Binary { left, right, .. }
666 | Expression::Logical { left, right, .. }
667 | Expression::Assign {
668 target: left,
669 value: right,
670 ..
671 }
672 | Expression::Index {
673 object: left,
674 index: right,
675 ..
676 } => expr_uses_arguments(left) || expr_uses_arguments(right),
677 Expression::Conditional {
678 test,
679 consequent,
680 alternate,
681 } => {
682 expr_uses_arguments(test)
683 || expr_uses_arguments(consequent)
684 || expr_uses_arguments(alternate)
685 }
686 Expression::Call {
687 callee, arguments, ..
688 }
689 | Expression::New { callee, arguments } => {
690 expr_uses_arguments(callee) || arguments.iter().any(expr_uses_arguments)
691 }
692 Expression::Class {
693 superclass,
694 members,
695 ..
696 } => {
697 superclass.as_deref().is_some_and(expr_uses_arguments)
698 || members.iter().any(|m| {
699 m.computed_key.as_ref().is_some_and(expr_uses_arguments)
700 || m.field_init.as_ref().is_some_and(expr_uses_arguments)
701 })
702 }
703 Expression::Number(_)
704 | Expression::BigIntLit(_)
705 | Expression::Str(_)
706 | Expression::Bool(_)
707 | Expression::Null
708 | Expression::Undefined
709 | Expression::This
710 | Expression::Super
711 | Expression::NewTarget
712 | Expression::Regex(..) => false,
713 }
714}
715
716impl core::fmt::Debug for FnBody {
717 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
718 match &*self.state.borrow() {
719 FnBodyState::Parsed(s) => write!(f, "FnBody({} stmts)", s.len()),
720 FnBodyState::Source { src, .. } => write!(f, "FnBody(lazy {} chars)", src.len()),
721 }
722 }
723}
724
725impl PartialEq for FnBody {
727 fn eq(&self, other: &Self) -> bool {
728 core::ptr::eq(self, other)
729 }
730}