1pub mod default_module_type_provider;
2pub mod dominator;
3pub mod environment;
4pub mod environment_config;
5pub mod globals;
6pub mod object_shape;
7pub mod print;
8pub mod reactive;
9pub mod type_config;
10pub mod visitors;
11
12use indexmap::IndexMap;
13use indexmap::IndexSet;
14pub use react_compiler_diagnostics::CompilerDiagnostic;
15pub use react_compiler_diagnostics::ErrorCategory;
16pub use react_compiler_diagnostics::GENERATED_SOURCE;
17pub use react_compiler_diagnostics::Position;
18pub use react_compiler_diagnostics::SourceLocation;
19pub use reactive::*;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
26pub struct BlockId(pub u32);
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
29pub struct IdentifierId(pub u32);
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
33pub struct InstructionId(pub u32);
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
38pub struct EvaluationOrder(pub u32);
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
41pub struct DeclarationId(pub u32);
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
44pub struct ScopeId(pub u32);
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
47pub struct TypeId(pub u32);
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
50pub struct FunctionId(pub u32);
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub struct MutableRangeId(pub u32);
54
55#[derive(Debug, Clone, Copy)]
62pub struct FloatValue(u64);
63
64impl FloatValue {
65 pub fn new(value: f64) -> Self {
66 FloatValue(value.to_bits())
67 }
68
69 pub fn value(self) -> f64 {
70 f64::from_bits(self.0)
71 }
72}
73
74impl From<f64> for FloatValue {
75 fn from(value: f64) -> Self {
76 FloatValue::new(value)
77 }
78}
79
80impl From<FloatValue> for f64 {
81 fn from(value: FloatValue) -> Self {
82 value.value()
83 }
84}
85
86impl PartialEq for FloatValue {
87 fn eq(&self, other: &Self) -> bool {
88 self.0 == other.0
89 }
90}
91
92impl Eq for FloatValue {}
93
94impl std::hash::Hash for FloatValue {
95 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
96 self.0.hash(state);
97 }
98}
99
100impl std::fmt::Display for FloatValue {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 write!(f, "{}", format_js_number(self.value()))
103 }
104}
105
106pub fn format_js_number(n: f64) -> String {
114 if n.is_nan() {
115 return "NaN".to_string();
116 }
117 if n.is_infinite() {
118 return if n > 0.0 {
119 "Infinity".to_string()
120 } else {
121 "-Infinity".to_string()
122 };
123 }
124 if n == 0.0 {
125 return "0".to_string();
126 }
127
128 let abs = n.abs();
129 let sign = if n < 0.0 { "-" } else { "" };
130
131 if abs >= 1e21 || (abs > 0.0 && abs < 1e-6) {
132 let formatted = format!("{:e}", abs);
135 let (coeff, exp_str) = formatted.split_once('e').unwrap();
137 let exp: i32 = exp_str.parse().unwrap();
138 if exp >= 0 {
140 format!("{}{}e+{}", sign, coeff, exp)
141 } else {
142 format!("{}{}e-{}", sign, coeff, exp.unsigned_abs())
143 }
144 } else if abs.fract() == 0.0 && abs < (i64::MAX as f64) {
145 format!("{}{}", sign, abs as i64)
147 } else {
148 format!("{}", n)
150 }
151}
152
153#[derive(Debug, Clone)]
159pub struct HirFunction {
160 pub loc: Option<SourceLocation>,
161 pub id: Option<String>,
162 pub name_hint: Option<String>,
163 pub fn_type: ReactFunctionType,
164 pub params: Vec<ParamPattern>,
165 pub return_type_annotation: Option<String>,
166 pub returns: Place,
167 pub context: Vec<Place>,
168 pub body: HIR,
169 pub instructions: Vec<Instruction>,
170 pub generator: bool,
171 pub is_async: bool,
172 pub directives: Vec<String>,
173 pub aliasing_effects: Option<Vec<AliasingEffect>>,
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub enum ReactFunctionType {
178 Component,
179 Hook,
180 Other,
181}
182
183#[derive(Debug, Clone)]
184pub enum ParamPattern {
185 Place(Place),
186 Spread(SpreadPattern),
187}
188
189#[derive(Debug, Clone)]
191pub struct HIR {
192 pub entry: BlockId,
193 pub blocks: IndexMap<BlockId, BasicBlock>,
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum BlockKind {
199 Block,
200 Value,
201 Loop,
202 Sequence,
203 Catch,
204}
205
206impl std::fmt::Display for BlockKind {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 match self {
209 BlockKind::Block => write!(f, "block"),
210 BlockKind::Value => write!(f, "value"),
211 BlockKind::Loop => write!(f, "loop"),
212 BlockKind::Sequence => write!(f, "sequence"),
213 BlockKind::Catch => write!(f, "catch"),
214 }
215 }
216}
217
218#[derive(Debug, Clone)]
220pub struct BasicBlock {
221 pub kind: BlockKind,
222 pub id: BlockId,
223 pub instructions: Vec<InstructionId>,
224 pub terminal: Terminal,
225 pub preds: IndexSet<BlockId>,
226 pub phis: Vec<Phi>,
227}
228
229#[derive(Debug, Clone)]
231pub struct Phi {
232 pub place: Place,
233 pub operands: IndexMap<BlockId, Place>,
234}
235
236#[derive(Debug, Clone)]
241pub enum Terminal {
242 Unsupported {
243 id: EvaluationOrder,
244 loc: Option<SourceLocation>,
245 },
246 Unreachable {
247 id: EvaluationOrder,
248 loc: Option<SourceLocation>,
249 },
250 Throw {
251 value: Place,
252 id: EvaluationOrder,
253 loc: Option<SourceLocation>,
254 },
255 Return {
256 value: Place,
257 return_variant: ReturnVariant,
258 id: EvaluationOrder,
259 loc: Option<SourceLocation>,
260 effects: Option<Vec<AliasingEffect>>,
261 },
262 Goto {
263 block: BlockId,
264 variant: GotoVariant,
265 id: EvaluationOrder,
266 loc: Option<SourceLocation>,
267 },
268 If {
269 test: Place,
270 consequent: BlockId,
271 alternate: BlockId,
272 fallthrough: BlockId,
273 id: EvaluationOrder,
274 loc: Option<SourceLocation>,
275 },
276 Branch {
277 test: Place,
278 consequent: BlockId,
279 alternate: BlockId,
280 fallthrough: BlockId,
281 id: EvaluationOrder,
282 loc: Option<SourceLocation>,
283 },
284 Switch {
285 test: Place,
286 cases: Vec<Case>,
287 fallthrough: BlockId,
288 id: EvaluationOrder,
289 loc: Option<SourceLocation>,
290 },
291 DoWhile {
292 loop_block: BlockId,
293 test: BlockId,
294 fallthrough: BlockId,
295 id: EvaluationOrder,
296 loc: Option<SourceLocation>,
297 },
298 While {
299 test: BlockId,
300 loop_block: BlockId,
301 fallthrough: BlockId,
302 id: EvaluationOrder,
303 loc: Option<SourceLocation>,
304 },
305 For {
306 init: BlockId,
307 test: BlockId,
308 update: Option<BlockId>,
309 loop_block: BlockId,
310 fallthrough: BlockId,
311 id: EvaluationOrder,
312 loc: Option<SourceLocation>,
313 },
314 ForOf {
315 init: BlockId,
316 test: BlockId,
317 loop_block: BlockId,
318 fallthrough: BlockId,
319 id: EvaluationOrder,
320 loc: Option<SourceLocation>,
321 },
322 ForIn {
323 init: BlockId,
324 loop_block: BlockId,
325 fallthrough: BlockId,
326 id: EvaluationOrder,
327 loc: Option<SourceLocation>,
328 },
329 Logical {
330 operator: LogicalOperator,
331 test: BlockId,
332 fallthrough: BlockId,
333 id: EvaluationOrder,
334 loc: Option<SourceLocation>,
335 },
336 Ternary {
337 test: BlockId,
338 fallthrough: BlockId,
339 id: EvaluationOrder,
340 loc: Option<SourceLocation>,
341 },
342 Optional {
343 optional: bool,
344 test: BlockId,
345 fallthrough: BlockId,
346 id: EvaluationOrder,
347 loc: Option<SourceLocation>,
348 },
349 Label {
350 block: BlockId,
351 fallthrough: BlockId,
352 id: EvaluationOrder,
353 loc: Option<SourceLocation>,
354 },
355 Sequence {
356 block: BlockId,
357 fallthrough: BlockId,
358 id: EvaluationOrder,
359 loc: Option<SourceLocation>,
360 },
361 MaybeThrow {
362 continuation: BlockId,
363 handler: Option<BlockId>,
364 id: EvaluationOrder,
365 loc: Option<SourceLocation>,
366 effects: Option<Vec<AliasingEffect>>,
367 },
368 Try {
369 block: BlockId,
370 handler_binding: Option<Place>,
371 handler: BlockId,
372 fallthrough: BlockId,
373 id: EvaluationOrder,
374 loc: Option<SourceLocation>,
375 },
376 Scope {
377 fallthrough: BlockId,
378 block: BlockId,
379 scope: ScopeId,
380 id: EvaluationOrder,
381 loc: Option<SourceLocation>,
382 },
383 PrunedScope {
384 fallthrough: BlockId,
385 block: BlockId,
386 scope: ScopeId,
387 id: EvaluationOrder,
388 loc: Option<SourceLocation>,
389 },
390}
391
392impl Terminal {
393 pub fn evaluation_order(&self) -> EvaluationOrder {
395 match self {
396 Terminal::Unsupported { id, .. }
397 | Terminal::Unreachable { id, .. }
398 | Terminal::Throw { id, .. }
399 | Terminal::Return { id, .. }
400 | Terminal::Goto { id, .. }
401 | Terminal::If { id, .. }
402 | Terminal::Branch { id, .. }
403 | Terminal::Switch { id, .. }
404 | Terminal::DoWhile { id, .. }
405 | Terminal::While { id, .. }
406 | Terminal::For { id, .. }
407 | Terminal::ForOf { id, .. }
408 | Terminal::ForIn { id, .. }
409 | Terminal::Logical { id, .. }
410 | Terminal::Ternary { id, .. }
411 | Terminal::Optional { id, .. }
412 | Terminal::Label { id, .. }
413 | Terminal::Sequence { id, .. }
414 | Terminal::MaybeThrow { id, .. }
415 | Terminal::Try { id, .. }
416 | Terminal::Scope { id, .. }
417 | Terminal::PrunedScope { id, .. } => *id,
418 }
419 }
420
421 pub fn loc(&self) -> Option<&SourceLocation> {
423 match self {
424 Terminal::Unsupported { loc, .. }
425 | Terminal::Unreachable { loc, .. }
426 | Terminal::Throw { loc, .. }
427 | Terminal::Return { loc, .. }
428 | Terminal::Goto { loc, .. }
429 | Terminal::If { loc, .. }
430 | Terminal::Branch { loc, .. }
431 | Terminal::Switch { loc, .. }
432 | Terminal::DoWhile { loc, .. }
433 | Terminal::While { loc, .. }
434 | Terminal::For { loc, .. }
435 | Terminal::ForOf { loc, .. }
436 | Terminal::ForIn { loc, .. }
437 | Terminal::Logical { loc, .. }
438 | Terminal::Ternary { loc, .. }
439 | Terminal::Optional { loc, .. }
440 | Terminal::Label { loc, .. }
441 | Terminal::Sequence { loc, .. }
442 | Terminal::MaybeThrow { loc, .. }
443 | Terminal::Try { loc, .. }
444 | Terminal::Scope { loc, .. }
445 | Terminal::PrunedScope { loc, .. } => loc.as_ref(),
446 }
447 }
448
449 pub fn set_evaluation_order(&mut self, new_id: EvaluationOrder) {
451 match self {
452 Terminal::Unsupported { id, .. }
453 | Terminal::Unreachable { id, .. }
454 | Terminal::Throw { id, .. }
455 | Terminal::Return { id, .. }
456 | Terminal::Goto { id, .. }
457 | Terminal::If { id, .. }
458 | Terminal::Branch { id, .. }
459 | Terminal::Switch { id, .. }
460 | Terminal::DoWhile { id, .. }
461 | Terminal::While { id, .. }
462 | Terminal::For { id, .. }
463 | Terminal::ForOf { id, .. }
464 | Terminal::ForIn { id, .. }
465 | Terminal::Logical { id, .. }
466 | Terminal::Ternary { id, .. }
467 | Terminal::Optional { id, .. }
468 | Terminal::Label { id, .. }
469 | Terminal::Sequence { id, .. }
470 | Terminal::MaybeThrow { id, .. }
471 | Terminal::Try { id, .. }
472 | Terminal::Scope { id, .. }
473 | Terminal::PrunedScope { id, .. } => *id = new_id,
474 }
475 }
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq)]
479pub enum ReturnVariant {
480 Void,
481 Implicit,
482 Explicit,
483}
484
485#[derive(Debug, Clone, Copy, PartialEq, Eq)]
486pub enum GotoVariant {
487 Break,
488 Continue,
489 Try,
490}
491
492#[derive(Debug, Clone)]
493pub struct Case {
494 pub test: Option<Place>,
495 pub block: BlockId,
496}
497
498#[derive(Debug, Clone, Copy, PartialEq, Eq)]
499pub enum LogicalOperator {
500 And,
501 Or,
502 NullishCoalescing,
503}
504
505impl std::fmt::Display for LogicalOperator {
506 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507 match self {
508 LogicalOperator::And => write!(f, "&&"),
509 LogicalOperator::Or => write!(f, "||"),
510 LogicalOperator::NullishCoalescing => write!(f, "??"),
511 }
512 }
513}
514
515#[derive(Debug, Clone)]
520pub struct Instruction {
521 pub id: EvaluationOrder,
522 pub lvalue: Place,
523 pub value: InstructionValue,
524 pub loc: Option<SourceLocation>,
525 pub effects: Option<Vec<AliasingEffect>>,
526}
527
528#[derive(Debug, Clone, Copy, PartialEq, Eq)]
529pub enum InstructionKind {
530 Const,
531 Let,
532 Reassign,
533 Catch,
534 HoistedConst,
535 HoistedLet,
536 HoistedFunction,
537 Function,
538}
539
540#[derive(Debug, Clone)]
541pub struct LValue {
542 pub place: Place,
543 pub kind: InstructionKind,
544}
545
546#[derive(Debug, Clone)]
547pub struct LValuePattern {
548 pub pattern: Pattern,
549 pub kind: InstructionKind,
550}
551
552#[derive(Debug, Clone)]
553pub enum Pattern {
554 Array(ArrayPattern),
555 Object(ObjectPattern),
556}
557
558#[derive(Debug, Clone)]
563pub enum InstructionValue {
564 LoadLocal {
565 place: Place,
566 loc: Option<SourceLocation>,
567 },
568 LoadContext {
569 place: Place,
570 loc: Option<SourceLocation>,
571 },
572 DeclareLocal {
573 lvalue: LValue,
574 type_annotation: Option<String>,
575 loc: Option<SourceLocation>,
576 },
577 DeclareContext {
578 lvalue: LValue,
579 loc: Option<SourceLocation>,
580 },
581 StoreLocal {
582 lvalue: LValue,
583 value: Place,
584 type_annotation: Option<String>,
585 loc: Option<SourceLocation>,
586 },
587 StoreContext {
588 lvalue: LValue,
589 value: Place,
590 loc: Option<SourceLocation>,
591 },
592 Destructure {
593 lvalue: LValuePattern,
594 value: Place,
595 loc: Option<SourceLocation>,
596 },
597 Primitive {
598 value: PrimitiveValue,
599 loc: Option<SourceLocation>,
600 },
601 JSXText {
602 value: String,
603 loc: Option<SourceLocation>,
604 },
605 BinaryExpression {
606 operator: BinaryOperator,
607 left: Place,
608 right: Place,
609 loc: Option<SourceLocation>,
610 },
611 NewExpression {
612 callee: Place,
613 args: Vec<PlaceOrSpread>,
614 loc: Option<SourceLocation>,
615 },
616 CallExpression {
617 callee: Place,
618 args: Vec<PlaceOrSpread>,
619 loc: Option<SourceLocation>,
620 },
621 MethodCall {
622 receiver: Place,
623 property: Place,
624 args: Vec<PlaceOrSpread>,
625 loc: Option<SourceLocation>,
626 },
627 UnaryExpression {
628 operator: UnaryOperator,
629 value: Place,
630 loc: Option<SourceLocation>,
631 },
632 TypeCastExpression {
633 value: Place,
634 type_: Type,
635 type_annotation_name: Option<String>,
636 type_annotation_kind: Option<String>,
637 type_annotation: Option<Box<serde_json::Value>>,
641 loc: Option<SourceLocation>,
642 },
643 JsxExpression {
644 tag: JsxTag,
645 props: Vec<JsxAttribute>,
646 children: Option<Vec<Place>>,
647 loc: Option<SourceLocation>,
648 opening_loc: Option<SourceLocation>,
649 closing_loc: Option<SourceLocation>,
650 },
651 ObjectExpression {
652 properties: Vec<ObjectPropertyOrSpread>,
653 loc: Option<SourceLocation>,
654 },
655 ObjectMethod {
656 loc: Option<SourceLocation>,
657 lowered_func: LoweredFunction,
658 },
659 ArrayExpression {
660 elements: Vec<ArrayElement>,
661 loc: Option<SourceLocation>,
662 },
663 JsxFragment {
664 children: Vec<Place>,
665 loc: Option<SourceLocation>,
666 },
667 RegExpLiteral {
668 pattern: String,
669 flags: String,
670 loc: Option<SourceLocation>,
671 },
672 MetaProperty {
673 meta: String,
674 property: String,
675 loc: Option<SourceLocation>,
676 },
677 PropertyStore {
678 object: Place,
679 property: PropertyLiteral,
680 value: Place,
681 loc: Option<SourceLocation>,
682 },
683 PropertyLoad {
684 object: Place,
685 property: PropertyLiteral,
686 loc: Option<SourceLocation>,
687 },
688 PropertyDelete {
689 object: Place,
690 property: PropertyLiteral,
691 loc: Option<SourceLocation>,
692 },
693 ComputedStore {
694 object: Place,
695 property: Place,
696 value: Place,
697 loc: Option<SourceLocation>,
698 },
699 ComputedLoad {
700 object: Place,
701 property: Place,
702 loc: Option<SourceLocation>,
703 },
704 ComputedDelete {
705 object: Place,
706 property: Place,
707 loc: Option<SourceLocation>,
708 },
709 LoadGlobal {
710 binding: NonLocalBinding,
711 loc: Option<SourceLocation>,
712 },
713 StoreGlobal {
714 name: String,
715 value: Place,
716 loc: Option<SourceLocation>,
717 },
718 FunctionExpression {
719 name: Option<String>,
720 name_hint: Option<String>,
721 lowered_func: LoweredFunction,
722 expr_type: FunctionExpressionType,
723 loc: Option<SourceLocation>,
724 },
725 TaggedTemplateExpression {
726 tag: Place,
727 value: TemplateQuasi,
728 loc: Option<SourceLocation>,
729 },
730 TemplateLiteral {
731 subexprs: Vec<Place>,
732 quasis: Vec<TemplateQuasi>,
733 loc: Option<SourceLocation>,
734 },
735 Await {
736 value: Place,
737 loc: Option<SourceLocation>,
738 },
739 GetIterator {
740 collection: Place,
741 loc: Option<SourceLocation>,
742 },
743 IteratorNext {
744 iterator: Place,
745 collection: Place,
746 loc: Option<SourceLocation>,
747 },
748 NextPropertyOf {
749 value: Place,
750 loc: Option<SourceLocation>,
751 },
752 PrefixUpdate {
753 lvalue: Place,
754 operation: UpdateOperator,
755 value: Place,
756 loc: Option<SourceLocation>,
757 },
758 PostfixUpdate {
759 lvalue: Place,
760 operation: UpdateOperator,
761 value: Place,
762 loc: Option<SourceLocation>,
763 },
764 Debugger {
765 loc: Option<SourceLocation>,
766 },
767 StartMemoize {
768 manual_memo_id: u32,
769 deps: Option<Vec<ManualMemoDependency>>,
770 deps_loc: Option<Option<SourceLocation>>,
771 has_invalid_deps: bool,
772 loc: Option<SourceLocation>,
773 },
774 FinishMemoize {
775 manual_memo_id: u32,
776 decl: Place,
777 pruned: bool,
778 loc: Option<SourceLocation>,
779 },
780 UnsupportedNode {
781 node_type: Option<String>,
782 original_node: Option<serde_json::Value>,
784 loc: Option<SourceLocation>,
785 },
786}
787
788impl InstructionValue {
789 pub fn loc(&self) -> Option<&SourceLocation> {
790 match self {
791 InstructionValue::LoadLocal { loc, .. }
792 | InstructionValue::LoadContext { loc, .. }
793 | InstructionValue::DeclareLocal { loc, .. }
794 | InstructionValue::DeclareContext { loc, .. }
795 | InstructionValue::StoreLocal { loc, .. }
796 | InstructionValue::StoreContext { loc, .. }
797 | InstructionValue::Destructure { loc, .. }
798 | InstructionValue::Primitive { loc, .. }
799 | InstructionValue::JSXText { loc, .. }
800 | InstructionValue::BinaryExpression { loc, .. }
801 | InstructionValue::NewExpression { loc, .. }
802 | InstructionValue::CallExpression { loc, .. }
803 | InstructionValue::MethodCall { loc, .. }
804 | InstructionValue::UnaryExpression { loc, .. }
805 | InstructionValue::TypeCastExpression { loc, .. }
806 | InstructionValue::JsxExpression { loc, .. }
807 | InstructionValue::ObjectExpression { loc, .. }
808 | InstructionValue::ObjectMethod { loc, .. }
809 | InstructionValue::ArrayExpression { loc, .. }
810 | InstructionValue::JsxFragment { loc, .. }
811 | InstructionValue::RegExpLiteral { loc, .. }
812 | InstructionValue::MetaProperty { loc, .. }
813 | InstructionValue::PropertyStore { loc, .. }
814 | InstructionValue::PropertyLoad { loc, .. }
815 | InstructionValue::PropertyDelete { loc, .. }
816 | InstructionValue::ComputedStore { loc, .. }
817 | InstructionValue::ComputedLoad { loc, .. }
818 | InstructionValue::ComputedDelete { loc, .. }
819 | InstructionValue::LoadGlobal { loc, .. }
820 | InstructionValue::StoreGlobal { loc, .. }
821 | InstructionValue::FunctionExpression { loc, .. }
822 | InstructionValue::TaggedTemplateExpression { loc, .. }
823 | InstructionValue::TemplateLiteral { loc, .. }
824 | InstructionValue::Await { loc, .. }
825 | InstructionValue::GetIterator { loc, .. }
826 | InstructionValue::IteratorNext { loc, .. }
827 | InstructionValue::NextPropertyOf { loc, .. }
828 | InstructionValue::PrefixUpdate { loc, .. }
829 | InstructionValue::PostfixUpdate { loc, .. }
830 | InstructionValue::Debugger { loc, .. }
831 | InstructionValue::StartMemoize { loc, .. }
832 | InstructionValue::FinishMemoize { loc, .. }
833 | InstructionValue::UnsupportedNode { loc, .. } => loc.as_ref(),
834 }
835 }
836}
837
838#[derive(Debug, Clone, PartialEq, Eq, Hash)]
843pub enum PrimitiveValue {
844 Null,
845 Undefined,
846 Boolean(bool),
847 Number(FloatValue),
848 String(String),
849}
850
851#[derive(Debug, Clone, Copy, PartialEq, Eq)]
852pub enum BinaryOperator {
853 Equal,
854 NotEqual,
855 StrictEqual,
856 StrictNotEqual,
857 LessThan,
858 LessEqual,
859 GreaterThan,
860 GreaterEqual,
861 ShiftLeft,
862 ShiftRight,
863 UnsignedShiftRight,
864 Add,
865 Subtract,
866 Multiply,
867 Divide,
868 Modulo,
869 Exponent,
870 BitwiseOr,
871 BitwiseXor,
872 BitwiseAnd,
873 In,
874 InstanceOf,
875}
876
877impl std::fmt::Display for BinaryOperator {
878 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
879 match self {
880 BinaryOperator::Equal => write!(f, "=="),
881 BinaryOperator::NotEqual => write!(f, "!="),
882 BinaryOperator::StrictEqual => write!(f, "==="),
883 BinaryOperator::StrictNotEqual => write!(f, "!=="),
884 BinaryOperator::LessThan => write!(f, "<"),
885 BinaryOperator::LessEqual => write!(f, "<="),
886 BinaryOperator::GreaterThan => write!(f, ">"),
887 BinaryOperator::GreaterEqual => write!(f, ">="),
888 BinaryOperator::ShiftLeft => write!(f, "<<"),
889 BinaryOperator::ShiftRight => write!(f, ">>"),
890 BinaryOperator::UnsignedShiftRight => write!(f, ">>>"),
891 BinaryOperator::Add => write!(f, "+"),
892 BinaryOperator::Subtract => write!(f, "-"),
893 BinaryOperator::Multiply => write!(f, "*"),
894 BinaryOperator::Divide => write!(f, "/"),
895 BinaryOperator::Modulo => write!(f, "%"),
896 BinaryOperator::Exponent => write!(f, "**"),
897 BinaryOperator::BitwiseOr => write!(f, "|"),
898 BinaryOperator::BitwiseXor => write!(f, "^"),
899 BinaryOperator::BitwiseAnd => write!(f, "&"),
900 BinaryOperator::In => write!(f, "in"),
901 BinaryOperator::InstanceOf => write!(f, "instanceof"),
902 }
903 }
904}
905
906#[derive(Debug, Clone, Copy, PartialEq, Eq)]
907pub enum UnaryOperator {
908 Minus,
909 Plus,
910 Not,
911 BitwiseNot,
912 TypeOf,
913 Void,
914}
915
916impl std::fmt::Display for UnaryOperator {
917 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
918 match self {
919 UnaryOperator::Minus => write!(f, "-"),
920 UnaryOperator::Plus => write!(f, "+"),
921 UnaryOperator::Not => write!(f, "!"),
922 UnaryOperator::BitwiseNot => write!(f, "~"),
923 UnaryOperator::TypeOf => write!(f, "typeof"),
924 UnaryOperator::Void => write!(f, "void"),
925 }
926 }
927}
928
929#[derive(Debug, Clone, Copy, PartialEq, Eq)]
930pub enum UpdateOperator {
931 Increment,
932 Decrement,
933}
934
935impl std::fmt::Display for UpdateOperator {
936 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
937 match self {
938 UpdateOperator::Increment => write!(f, "++"),
939 UpdateOperator::Decrement => write!(f, "--"),
940 }
941 }
942}
943
944#[derive(Debug, Clone, Copy, PartialEq, Eq)]
945pub enum FunctionExpressionType {
946 ArrowFunctionExpression,
947 FunctionExpression,
948 FunctionDeclaration,
949}
950
951#[derive(Debug, Clone)]
952pub struct TemplateQuasi {
953 pub raw: String,
954 pub cooked: Option<String>,
955}
956
957#[derive(Debug, Clone)]
958pub struct ManualMemoDependency {
959 pub root: ManualMemoDependencyRoot,
960 pub path: Vec<DependencyPathEntry>,
961 pub loc: Option<SourceLocation>,
962}
963
964#[derive(Debug, Clone)]
965pub enum ManualMemoDependencyRoot {
966 NamedLocal { value: Place, constant: bool },
967 Global { identifier_name: String },
968}
969
970#[derive(Debug, Clone, PartialEq, Eq)]
971pub struct DependencyPathEntry {
972 pub property: PropertyLiteral,
973 pub optional: bool,
974 pub loc: Option<SourceLocation>,
975}
976
977#[derive(Debug, Clone)]
982pub struct Place {
983 pub identifier: IdentifierId,
984 pub effect: Effect,
985 pub reactive: bool,
986 pub loc: Option<SourceLocation>,
987}
988
989#[derive(Debug, Clone)]
990pub struct Identifier {
991 pub id: IdentifierId,
992 pub declaration_id: DeclarationId,
993 pub name: Option<IdentifierName>,
994 pub mutable_range: MutableRange,
995 pub scope: Option<ScopeId>,
996 pub type_: TypeId,
997 pub loc: Option<SourceLocation>,
998}
999
1000#[derive(Debug, Clone)]
1001pub struct MutableRange {
1002 pub id: MutableRangeId,
1006 pub start: EvaluationOrder,
1007 pub end: EvaluationOrder,
1008}
1009
1010impl MutableRange {
1011 pub fn contains(&self, eval_order: EvaluationOrder) -> bool {
1014 eval_order >= self.start && eval_order < self.end
1015 }
1016
1017 pub fn same_range(&self, other: &MutableRange) -> bool {
1021 self.id == other.id
1022 }
1023}
1024
1025#[derive(Debug, Clone)]
1026pub enum IdentifierName {
1027 Named(String),
1028 Promoted(String),
1029}
1030
1031impl IdentifierName {
1032 pub fn value(&self) -> &str {
1033 match self {
1034 IdentifierName::Named(v) | IdentifierName::Promoted(v) => v,
1035 }
1036 }
1037}
1038
1039#[derive(
1040 Debug,
1041 Clone,
1042 Copy,
1043 PartialEq,
1044 Eq,
1045 serde::Serialize,
1046 serde::Deserialize
1047)]
1048pub enum Effect {
1049 #[serde(rename = "<unknown>")]
1050 Unknown,
1051 #[serde(rename = "freeze")]
1052 Freeze,
1053 #[serde(rename = "read")]
1054 Read,
1055 #[serde(rename = "capture")]
1056 Capture,
1057 #[serde(rename = "mutate-iterator?")]
1058 ConditionallyMutateIterator,
1059 #[serde(rename = "mutate?")]
1060 ConditionallyMutate,
1061 #[serde(rename = "mutate")]
1062 Mutate,
1063 #[serde(rename = "store")]
1064 Store,
1065}
1066
1067impl Effect {
1068 pub fn is_mutable(&self) -> bool {
1072 matches!(
1073 self,
1074 Effect::Capture
1075 | Effect::Store
1076 | Effect::ConditionallyMutate
1077 | Effect::ConditionallyMutateIterator
1078 | Effect::Mutate
1079 )
1080 }
1081}
1082
1083impl std::fmt::Display for Effect {
1084 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1085 match self {
1086 Effect::Unknown => write!(f, "<unknown>"),
1087 Effect::Freeze => write!(f, "freeze"),
1088 Effect::Read => write!(f, "read"),
1089 Effect::Capture => write!(f, "capture"),
1090 Effect::ConditionallyMutateIterator => write!(f, "mutate-iterator?"),
1091 Effect::ConditionallyMutate => write!(f, "mutate?"),
1092 Effect::Mutate => write!(f, "mutate"),
1093 Effect::Store => write!(f, "store"),
1094 }
1095 }
1096}
1097
1098#[derive(Debug, Clone)]
1099pub struct SpreadPattern {
1100 pub place: Place,
1101}
1102
1103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1104pub enum Hole {
1105 Hole,
1106}
1107
1108#[derive(Debug, Clone)]
1109pub struct ArrayPattern {
1110 pub items: Vec<ArrayPatternElement>,
1111 pub loc: Option<SourceLocation>,
1112}
1113
1114#[derive(Debug, Clone)]
1115pub enum ArrayPatternElement {
1116 Place(Place),
1117 Spread(SpreadPattern),
1118 Hole,
1119}
1120
1121#[derive(Debug, Clone)]
1122pub struct ObjectPattern {
1123 pub properties: Vec<ObjectPropertyOrSpread>,
1124 pub loc: Option<SourceLocation>,
1125}
1126
1127#[derive(Debug, Clone)]
1128pub enum ObjectPropertyOrSpread {
1129 Property(ObjectProperty),
1130 Spread(SpreadPattern),
1131}
1132
1133#[derive(Debug, Clone)]
1134pub struct ObjectProperty {
1135 pub key: ObjectPropertyKey,
1136 pub property_type: ObjectPropertyType,
1137 pub place: Place,
1138}
1139
1140#[derive(Debug, Clone)]
1141pub enum ObjectPropertyKey {
1142 String { name: String },
1143 Identifier { name: String },
1144 Computed { name: Place },
1145 Number { name: FloatValue },
1146}
1147
1148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1149pub enum ObjectPropertyType {
1150 Property,
1151 Method,
1152}
1153
1154impl std::fmt::Display for ObjectPropertyType {
1155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1156 match self {
1157 ObjectPropertyType::Property => write!(f, "property"),
1158 ObjectPropertyType::Method => write!(f, "method"),
1159 }
1160 }
1161}
1162
1163#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1164pub enum PropertyLiteral {
1165 String(String),
1166 Number(FloatValue),
1167}
1168
1169impl std::fmt::Display for PropertyLiteral {
1170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1171 match self {
1172 PropertyLiteral::String(s) => write!(f, "{}", s),
1173 PropertyLiteral::Number(n) => write!(f, "{}", n),
1174 }
1175 }
1176}
1177
1178#[derive(Debug, Clone)]
1179pub enum PlaceOrSpread {
1180 Place(Place),
1181 Spread(SpreadPattern),
1182}
1183
1184#[derive(Debug, Clone)]
1185pub enum ArrayElement {
1186 Place(Place),
1187 Spread(SpreadPattern),
1188 Hole,
1189}
1190
1191#[derive(Debug, Clone)]
1192pub struct LoweredFunction {
1193 pub func: FunctionId,
1194}
1195
1196#[derive(Debug, Clone)]
1197pub struct BuiltinTag {
1198 pub name: String,
1199 pub loc: Option<SourceLocation>,
1200}
1201
1202#[derive(Debug, Clone)]
1203pub enum JsxTag {
1204 Place(Place),
1205 Builtin(BuiltinTag),
1206}
1207
1208#[derive(Debug, Clone)]
1209pub enum JsxAttribute {
1210 SpreadAttribute { argument: Place },
1211 Attribute { name: String, place: Place },
1212}
1213
1214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1219pub enum BindingKind {
1220 Var,
1221 Let,
1222 Const,
1223 Param,
1224 Module,
1225 Hoisted,
1226 Local,
1227 Unknown,
1228}
1229
1230#[derive(Debug, Clone)]
1231pub enum VariableBinding {
1232 Identifier {
1233 identifier: IdentifierId,
1234 binding_kind: BindingKind,
1235 },
1236 Global {
1237 name: String,
1238 },
1239 ImportDefault {
1240 name: String,
1241 module: String,
1242 },
1243 ImportSpecifier {
1244 name: String,
1245 module: String,
1246 imported: String,
1247 },
1248 ImportNamespace {
1249 name: String,
1250 module: String,
1251 },
1252 ModuleLocal {
1253 name: String,
1254 },
1255}
1256
1257#[derive(Debug, Clone)]
1258pub enum NonLocalBinding {
1259 ImportDefault {
1260 name: String,
1261 module: String,
1262 },
1263 ImportSpecifier {
1264 name: String,
1265 module: String,
1266 imported: String,
1267 },
1268 ImportNamespace {
1269 name: String,
1270 module: String,
1271 },
1272 ModuleLocal {
1273 name: String,
1274 },
1275 Global {
1276 name: String,
1277 },
1278}
1279
1280impl NonLocalBinding {
1281 pub fn name(&self) -> &str {
1283 match self {
1284 NonLocalBinding::ImportDefault { name, .. }
1285 | NonLocalBinding::ImportSpecifier { name, .. }
1286 | NonLocalBinding::ImportNamespace { name, .. }
1287 | NonLocalBinding::ModuleLocal { name, .. }
1288 | NonLocalBinding::Global { name, .. } => name,
1289 }
1290 }
1291}
1292
1293#[derive(Debug, Clone)]
1298pub enum Type {
1299 Primitive,
1300 Function {
1301 shape_id: Option<String>,
1302 return_type: Box<Type>,
1303 is_constructor: bool,
1304 },
1305 Object {
1306 shape_id: Option<String>,
1307 },
1308 TypeVar {
1309 id: TypeId,
1310 },
1311 Poly,
1312 Phi {
1313 operands: Vec<Type>,
1314 },
1315 Property {
1316 object_type: Box<Type>,
1317 object_name: String,
1318 property_name: PropertyNameKind,
1319 },
1320 ObjectMethod,
1321}
1322
1323#[derive(Debug, Clone)]
1324pub enum PropertyNameKind {
1325 Literal { value: PropertyLiteral },
1326 Computed { value: Box<Type> },
1327}
1328
1329#[derive(Debug, Clone)]
1334pub struct ReactiveScope {
1335 pub id: ScopeId,
1336 pub range: MutableRange,
1337
1338 pub dependencies: Vec<ReactiveScopeDependency>,
1340
1341 pub declarations: Vec<(IdentifierId, ReactiveScopeDeclaration)>,
1343
1344 pub reassignments: Vec<IdentifierId>,
1346
1347 pub early_return_value: Option<ReactiveScopeEarlyReturn>,
1349
1350 pub merged: Vec<ScopeId>,
1352
1353 pub loc: Option<SourceLocation>,
1355}
1356
1357#[derive(Debug, Clone)]
1359pub struct ReactiveScopeDependency {
1360 pub identifier: IdentifierId,
1361 pub reactive: bool,
1362 pub path: Vec<DependencyPathEntry>,
1363 pub loc: Option<SourceLocation>,
1364}
1365
1366#[derive(Debug, Clone)]
1368pub struct ReactiveScopeDeclaration {
1369 pub identifier: IdentifierId,
1370 pub scope: ScopeId,
1371}
1372
1373#[derive(Debug, Clone)]
1375pub struct ReactiveScopeEarlyReturn {
1376 pub value: IdentifierId,
1377 pub loc: Option<SourceLocation>,
1378 pub label: BlockId,
1379}
1380
1381use crate::object_shape::FunctionSignature;
1386use crate::type_config::ValueKind;
1387use crate::type_config::ValueReason;
1388
1389#[derive(Debug, Clone, PartialEq, Eq)]
1391pub enum MutationReason {
1392 AssignCurrentProperty,
1393}
1394
1395#[derive(Debug, Clone)]
1398pub enum AliasingEffect {
1399 Freeze { value: Place, reason: ValueReason },
1401 Mutate {
1403 value: Place,
1404 reason: Option<MutationReason>,
1405 },
1406 MutateConditionally { value: Place },
1408 MutateTransitive { value: Place },
1410 MutateTransitiveConditionally { value: Place },
1412 Capture { from: Place, into: Place },
1414 Alias { from: Place, into: Place },
1416 MaybeAlias { from: Place, into: Place },
1418 Assign { from: Place, into: Place },
1420 Create {
1422 into: Place,
1423 value: ValueKind,
1424 reason: ValueReason,
1425 },
1426 CreateFrom { from: Place, into: Place },
1428 ImmutableCapture { from: Place, into: Place },
1430 Apply {
1432 receiver: Place,
1433 function: Place,
1434 mutates_function: bool,
1435 args: Vec<PlaceOrSpreadOrHole>,
1436 into: Place,
1437 signature: Option<FunctionSignature>,
1438 loc: Option<SourceLocation>,
1439 },
1440 CreateFunction {
1442 captures: Vec<Place>,
1443 function_id: FunctionId,
1444 into: Place,
1445 },
1446 MutateFrozen {
1448 place: Place,
1449 error: CompilerDiagnostic,
1450 },
1451 MutateGlobal {
1453 place: Place,
1454 error: CompilerDiagnostic,
1455 },
1456 Impure {
1458 place: Place,
1459 error: CompilerDiagnostic,
1460 },
1461 Render { place: Place },
1463}
1464
1465#[derive(Debug, Clone)]
1467pub enum PlaceOrSpreadOrHole {
1468 Place(Place),
1469 Spread(SpreadPattern),
1470 Hole,
1471}
1472
1473#[derive(Debug, Clone)]
1476pub struct AliasingSignature {
1477 pub receiver: IdentifierId,
1478 pub params: Vec<IdentifierId>,
1479 pub rest: Option<IdentifierId>,
1480 pub returns: IdentifierId,
1481 pub effects: Vec<AliasingEffect>,
1482 pub temporaries: Vec<Place>,
1483}
1484
1485use crate::object_shape::BUILT_IN_ARRAY_ID;
1490use crate::object_shape::BUILT_IN_JSX_ID;
1491use crate::object_shape::BUILT_IN_MAP_ID;
1492use crate::object_shape::BUILT_IN_PROPS_ID;
1493use crate::object_shape::BUILT_IN_REF_VALUE_ID;
1494use crate::object_shape::BUILT_IN_SET_ID;
1495use crate::object_shape::BUILT_IN_USE_OPERATOR_ID;
1496use crate::object_shape::BUILT_IN_USE_REF_ID;
1497
1498pub fn is_primitive_type(ty: &Type) -> bool {
1500 matches!(ty, Type::Primitive)
1501}
1502
1503pub fn is_props_type(ty: &Type) -> bool {
1505 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_PROPS_ID)
1506}
1507
1508pub fn is_array_type(ty: &Type) -> bool {
1510 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_ARRAY_ID)
1511}
1512
1513pub fn is_set_type(ty: &Type) -> bool {
1515 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_SET_ID)
1516}
1517
1518pub fn is_map_type(ty: &Type) -> bool {
1520 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_MAP_ID)
1521}
1522
1523pub fn is_jsx_type(ty: &Type) -> bool {
1525 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_JSX_ID)
1526}
1527
1528pub fn is_ref_value_type(ty: &Type) -> bool {
1530 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_REF_VALUE_ID)
1531}
1532
1533pub fn is_use_ref_type(ty: &Type) -> bool {
1535 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_USE_REF_ID)
1536}
1537
1538pub fn is_ref_or_ref_value(ty: &Type) -> bool {
1540 is_use_ref_type(ty) || is_ref_value_type(ty)
1541}
1542
1543pub fn is_use_state_type(ty: &Type) -> bool {
1545 matches!(ty, Type::Object { shape_id: Some(id) } if id == object_shape::BUILT_IN_USE_STATE_ID)
1546}
1547
1548pub fn is_set_state_type(ty: &Type) -> bool {
1550 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_SET_STATE_ID)
1551}
1552
1553pub fn is_use_effect_hook_type(ty: &Type) -> bool {
1555 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_EFFECT_HOOK_ID)
1556}
1557
1558pub fn is_use_layout_effect_hook_type(ty: &Type) -> bool {
1560 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_LAYOUT_EFFECT_HOOK_ID)
1561}
1562
1563pub fn is_use_insertion_effect_hook_type(ty: &Type) -> bool {
1565 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_INSERTION_EFFECT_HOOK_ID)
1566}
1567
1568pub fn is_use_effect_event_type(ty: &Type) -> bool {
1570 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_EFFECT_EVENT_ID)
1571}
1572
1573pub fn is_ref_or_ref_like_mutable_type(ty: &Type) -> bool {
1575 matches!(ty, Type::Object { shape_id: Some(id) }
1576 if id == object_shape::BUILT_IN_USE_REF_ID || id == object_shape::REANIMATED_SHARED_VALUE_ID)
1577}
1578
1579pub fn is_use_operator_type(ty: &Type) -> bool {
1581 matches!(
1582 ty,
1583 Type::Function { shape_id: Some(id), .. }
1584 if id == BUILT_IN_USE_OPERATOR_ID
1585 )
1586}
1587
1588pub fn is_plain_object_type(ty: &Type) -> bool {
1590 matches!(ty, Type::Object { shape_id: Some(id) } if id == object_shape::BUILT_IN_OBJECT_ID)
1591}
1592
1593pub fn is_start_transition_type(ty: &Type) -> bool {
1595 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_START_TRANSITION_ID)
1596}
1597
1598#[cfg(test)]
1599mod tests {
1600 use super::*;
1601
1602 #[test]
1603 fn test_format_js_number() {
1604 assert_eq!(format_js_number(1e21), "1e+21");
1606 assert_eq!(format_js_number(1.5e21), "1.5e+21");
1607 assert_eq!(
1608 format_js_number(2.18739127891275e22),
1609 "2.18739127891275e+22"
1610 );
1611 assert_eq!(format_js_number(1e100), "1e+100");
1612 assert_eq!(format_js_number(-1e21), "-1e+21");
1613 assert_eq!(format_js_number(-1e100), "-1e+100");
1614
1615 assert_eq!(format_js_number(1e-7), "1e-7");
1617 assert_eq!(format_js_number(5e-7), "5e-7");
1618 assert_eq!(format_js_number(1.5e-8), "1.5e-8");
1619 assert_eq!(format_js_number(-1.5e-8), "-1.5e-8");
1620
1621 assert_eq!(format_js_number(1e20), "100000000000000000000");
1623 assert_eq!(format_js_number(1e-6), "0.000001");
1624
1625 assert_eq!(format_js_number(0.0), "0");
1627 assert_eq!(format_js_number(-0.0), "0");
1628 assert_eq!(format_js_number(1.0), "1");
1629 assert_eq!(format_js_number(100.0), "100");
1630
1631 assert_eq!(format_js_number(1.5), "1.5");
1633 assert_eq!(format_js_number(0.5), "0.5");
1634 assert_eq!(format_js_number(0.1), "0.1");
1635
1636 assert_eq!(format_js_number(f64::NAN), "NaN");
1638 assert_eq!(format_js_number(f64::INFINITY), "Infinity");
1639 assert_eq!(format_js_number(f64::NEG_INFINITY), "-Infinity");
1640 }
1641}