1use crate::arena::{self, ArenaError, ArenaKind};
2use crate::{DocComment, Span};
3
4#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
5pub struct ExprId(pub u32);
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
8pub struct StmtId(pub u32);
9
10#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11pub struct Ident {
12 pub name: String,
13 pub span: Span,
14}
15
16#[derive(Clone, Debug, PartialEq)]
17pub struct Expr {
18 pub kind: ExprKind,
19 pub span: Span,
20}
21
22#[derive(Clone, Debug, PartialEq)]
23pub enum ExprKind {
24 Number(f64),
25 BigInt(String),
27 String(String),
28 Boolean(bool),
29 Null,
30 Identifier(Ident),
31 Binary {
32 op: BinOp,
33 lhs: ExprId,
34 rhs: ExprId,
35 },
36 Unary {
37 op: UnOp,
38 operand: ExprId,
39 },
40 Call {
41 callee: ExprId,
42 type_args: Option<Vec<TypeAnnotation>>,
43 args: Vec<ExprId>,
44 },
45 Paren(ExprId),
46 ObjectLiteral {
47 members: Vec<ObjectLiteralMember>,
48 },
49 ArrayLiteral {
50 elements: Vec<ArrayLiteralElement>,
51 },
52 FieldAccess {
53 receiver: ExprId,
54 name: Ident,
55 },
56 IndexAccess {
57 receiver: ExprId,
58 index: ExprId,
59 },
60 FunctionExpression {
61 name: Option<Ident>,
62 this_type: Option<TypeAnnotation>,
63 function: ExprId,
64 },
65 Arrow {
66 params: Vec<ParamDecl>,
67 return_type: Option<TypeAnnotation>,
68 type_predicate: Option<TypePredicateAnnotation>,
69 body: ArrowBody,
70 },
71 Void {
73 operand: ExprId,
74 },
75 Typeof {
77 operand: ExprId,
78 },
79 Delete {
82 operand: ExprId,
83 },
84 New {
86 callee: ExprId,
87 type_args: Option<Vec<TypeAnnotation>>,
88 args: Vec<ExprId>,
89 },
90 This,
93 ThisOutsideReceiver,
96 Super,
98 TemplateLiteral {
100 parts: Vec<String>,
101 exprs: Vec<ExprId>,
102 substitution_spans: Vec<Span>,
104 },
105 Ternary {
106 cond: ExprId,
107 then_: ExprId,
108 else_: ExprId,
109 },
110 OptionalChain {
111 base: ExprId,
112 parts: Vec<ChainPart>,
113 },
114 PostfixUnary {
115 op: PostfixOp,
116 operand: ExprId,
117 },
118 Assign {
123 target: ExprId,
124 op: Option<BinOp>,
125 op_span: Span,
126 value: ExprId,
127 },
128 As {
130 expr: ExprId,
131 ty: TypeAnnotation,
132 },
133 InstanceOf {
137 value: ExprId,
138 ty: TypeAnnotation,
139 },
140 Regex {
142 source: String,
143 flags: String,
144 },
145}
146
147#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
149pub enum PostfixOp {
150 Inc,
151 Dec,
152 NonNullAssert,
153}
154
155#[derive(Clone, Debug, PartialEq)]
156pub enum ChainPart {
157 Field {
158 name: Ident,
159 optional: bool,
160 span: Span,
161 },
162 Index {
163 idx: ExprId,
164 optional: bool,
165 span: Span,
166 },
167 Call {
168 args: Vec<ExprId>,
169 type_args: Option<Vec<TypeAnnotation>>,
170 optional: bool,
171 span: Span,
172 },
173 NonNull { span: Span },
176}
177
178impl ChainPart {
179 pub fn is_optional(&self) -> bool {
180 match self {
181 ChainPart::Field { optional, .. }
182 | ChainPart::Index { optional, .. }
183 | ChainPart::Call { optional, .. } => *optional,
184 ChainPart::NonNull { .. } => false,
185 }
186 }
187
188 pub fn as_plain_step(mut self) -> Self {
190 match &mut self {
191 ChainPart::Field { optional, .. }
192 | ChainPart::Index { optional, .. }
193 | ChainPart::Call { optional, .. } => *optional = false,
194 ChainPart::NonNull { .. } => {}
195 }
196 self
197 }
198
199 pub fn span(&self) -> Span {
200 match self {
201 ChainPart::Field { span, .. }
202 | ChainPart::Index { span, .. }
203 | ChainPart::Call { span, .. }
204 | ChainPart::NonNull { span } => *span,
205 }
206 }
207}
208
209#[derive(Clone, Copy, Debug, PartialEq)]
210pub enum ArrowBody {
211 Expr(ExprId),
212 Block(StmtId),
213}
214
215#[derive(Clone, Debug, PartialEq)]
216pub struct ObjectLiteralField {
217 pub name: Ident,
218 pub value: ExprId,
219}
220
221#[derive(Clone, Debug, PartialEq)]
222pub enum ObjectLiteralMember {
223 Computed {
224 key: ExprId,
225 value: ExprId,
226 },
227 Field(ObjectLiteralField),
228 Spread {
229 value: ExprId,
230 span: Span,
232 },
233}
234
235impl ObjectLiteralMember {
236 pub fn expressions(&self) -> impl Iterator<Item = ExprId> {
237 let key = match self {
238 Self::Computed { key, .. } => Some(*key),
239 _ => None,
240 };
241 key.into_iter().chain(std::iter::once(self.value()))
242 }
243
244 pub fn value(&self) -> ExprId {
245 match self {
246 ObjectLiteralMember::Field(f) => f.value,
247 ObjectLiteralMember::Spread { value, .. }
248 | ObjectLiteralMember::Computed { value, .. } => *value,
249 }
250 }
251}
252
253#[derive(Clone, Debug, PartialEq)]
254pub enum ArrayLiteralElement {
255 Value(ExprId),
256 Spread {
257 value: ExprId,
258 span: Span,
260 },
261}
262
263impl ArrayLiteralElement {
264 pub fn value(&self) -> ExprId {
265 match self {
266 ArrayLiteralElement::Value(id) => *id,
267 ArrayLiteralElement::Spread { value, .. } => *value,
268 }
269 }
270}
271
272#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
273pub enum BinOp {
274 Add,
275 Sub,
276 Mul,
277 Div,
278 Rem,
279 Pow,
281 BitAnd,
282 BitOr,
283 BitXor,
284 Shl,
285 Shr,
286 UnsignedShr,
287 Eq,
288 NotEq,
289 Lt,
290 Gt,
291 Le,
292 Ge,
293 And,
294 Or,
295 In,
296 NullishCoalesce,
298}
299
300#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
301pub enum UnOp {
302 Not,
303 BitNot,
304 Neg,
305 Pos,
306}
307
308impl BinOp {
309 pub(crate) fn bitwise_name(self) -> Option<&'static str> {
310 match self {
311 Self::BitAnd => Some("bitand"),
312 Self::BitOr => Some("bitor"),
313 Self::BitXor => Some("bitxor"),
314 Self::Shl => Some("shl"),
315 Self::Shr => Some("shr"),
316 Self::UnsignedShr => Some("ushr"),
317 _ => None,
318 }
319 }
320}
321
322#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
323pub enum BindingKind {
324 Let,
325 Const,
326}
327
328#[derive(Clone, Debug, PartialEq)]
329pub struct Stmt {
330 pub kind: StmtKind,
331 pub span: Span,
332}
333
334#[derive(Clone, Debug, PartialEq)]
335pub enum StmtKind {
336 Let {
337 name: Ident,
338 ty: Option<TypeAnnotation>,
339 value: ExprId,
340 doc: Option<DocComment>,
341 },
342 Const {
343 name: Ident,
344 ty: Option<TypeAnnotation>,
345 value: ExprId,
346 doc: Option<DocComment>,
347 },
348 LetPattern {
350 binding: Binding,
351 ty: Option<TypeAnnotation>,
352 value: ExprId,
353 doc: Option<DocComment>,
354 },
355 ConstPattern {
356 binding: Binding,
357 ty: Option<TypeAnnotation>,
358 value: ExprId,
359 doc: Option<DocComment>,
360 },
361 ObjectRest {
363 is_const: bool,
364 name: Ident,
365 source: ExprId,
366 exclude: Vec<Ident>,
367 ty: Option<TypeAnnotation>,
368 doc: Option<DocComment>,
369 },
370 Function {
371 name: Ident,
372 generics: Vec<Ident>,
373 params: Vec<ParamDecl>,
374 return_type: Option<TypeAnnotation>,
376 type_predicate: Option<TypePredicateAnnotation>,
377 body: StmtId,
378 doc: Option<DocComment>,
379 },
380 If {
381 condition: ExprId,
382 then_block: StmtId,
383 else_block: Option<StmtId>,
384 },
385 While {
386 condition: ExprId,
387 body: StmtId,
388 },
389 For {
391 init: Option<StmtId>,
392 condition: Option<ExprId>,
393 update: Option<StmtId>,
394 body: StmtId,
396 },
397 ForOf {
398 binding_kind: BindingKind,
399 name: Ident,
400 ty: Option<TypeAnnotation>,
401 iter: ExprId,
402 body: StmtId,
404 },
405 ForOfPattern {
407 binding_kind: BindingKind,
408 binding: Binding,
409 ty: Option<TypeAnnotation>,
410 iter: ExprId,
411 body: StmtId,
413 },
414 DoWhile {
415 body: StmtId,
417 condition: ExprId,
418 },
419 Switch {
421 discriminant: ExprId,
422 cases: Vec<SwitchCase>,
423 default: Option<SwitchDefault>,
424 },
425 Break,
426 Continue,
427 Return(Option<ExprId>),
428 Throw {
429 value: ExprId,
430 },
431 Try {
435 body: StmtId,
436 catches: Vec<CatchClause>,
437 finally: Option<StmtId>,
438 },
439 Expr(ExprId),
440 Block(Vec<StmtId>),
441 Assign {
442 target: Ident,
443 value: ExprId,
444 },
445 AssignField {
446 receiver: ExprId,
447 field_name: Ident,
448 value: ExprId,
449 },
450 AssignIndex {
451 receiver: ExprId,
452 index: ExprId,
453 value: ExprId,
454 },
455 CompoundAssign {
457 target: Ident,
458 op: BinOp,
459 op_span: Span,
460 value: ExprId,
461 },
462 CompoundAssignField {
463 receiver: ExprId,
464 field_name: Ident,
465 op: BinOp,
466 op_span: Span,
467 value: ExprId,
468 },
469 CompoundAssignIndex {
470 receiver: ExprId,
471 index: ExprId,
472 op: BinOp,
473 op_span: Span,
474 value: ExprId,
475 },
476 InterfaceDecl {
478 name: Ident,
479 generics: Vec<Ident>,
480 extends: Vec<TypeAnnotation>,
481 members: Vec<InterfaceMember>,
482 doc: Option<DocComment>,
483 },
484 ClassDecl {
488 name: Ident,
489 generics: Vec<Ident>,
490 extends: Option<TypeAnnotation>,
491 implements: Vec<TypeAnnotation>,
492 members: Vec<ClassMember>,
493 doc: Option<DocComment>,
494 },
495 EnumDecl {
497 name: Ident,
498 members: Vec<EnumMember>,
499 doc: Option<DocComment>,
500 },
501 TypeAliasDecl {
502 name: Ident,
503 generics: Vec<Ident>,
504 ty: TypeAnnotation,
505 doc: Option<DocComment>,
506 },
507 Import {
509 module: String,
510 module_span: Span,
511 kind: ImportKind,
512 doc: Option<DocComment>,
513 },
514 ExportFrom {
519 specs: Vec<ImportSpecifier>,
520 source: Option<(String, Span)>,
521 doc: Option<DocComment>,
522 },
523}
524
525#[derive(Clone, Debug, PartialEq)]
526pub enum ImportKind {
527 Named(Vec<ImportSpecifier>),
528 Namespace {
530 local_name: Ident,
531 },
532}
533
534#[derive(Clone, Debug, PartialEq)]
535pub struct ImportSpecifier {
536 pub imported_name: Ident,
537 pub local_name: Ident,
538}
539
540#[derive(Clone, Debug, PartialEq)]
541pub enum InterfaceMember {
542 IndexSignature(IndexSignatureAnnotation),
543 Method {
544 name: Ident,
545 optional: bool,
546 generics: Vec<Ident>,
547 params: Vec<ParamDecl>,
548 return_type: TypeAnnotation,
549 span: Span,
550 doc: Option<DocComment>,
551 },
552 Property {
555 name: Ident,
556 ty: TypeAnnotation,
557 optional: bool,
558 readonly: bool,
559 span: Span,
560 doc: Option<DocComment>,
561 },
562}
563
564#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
566pub enum Visibility {
567 #[default]
568 Public,
569 Private,
570}
571
572impl Visibility {
573 pub fn is_public(&self) -> bool {
574 *self == Visibility::Public
575 }
576}
577
578#[derive(Clone, Debug, PartialEq)]
581pub struct ClassModifiers {
582 pub visibility: Visibility,
583 pub visibility_span: Option<Span>,
584 pub readonly: Option<Span>,
585 pub static_span: Option<Span>,
586}
587
588#[derive(Clone, Debug, PartialEq)]
589pub enum ClassMember {
590 Field {
591 name: Ident,
592 modifiers: ClassModifiers,
593 optional: bool,
595 ty: TypeAnnotation,
596 initializer: Option<ExprId>,
598 span: Span,
599 doc: Option<DocComment>,
600 },
601 Method {
602 name: Ident,
603 optional: bool,
604 modifiers: ClassModifiers,
605 generics: Vec<Ident>,
606 params: Vec<ParamDecl>,
607 return_type: TypeAnnotation,
608 body: StmtId,
609 span: Span,
610 doc: Option<DocComment>,
611 },
612 Constructor {
613 visibility: Visibility,
616 params: Vec<ParamDecl>,
617 body: StmtId,
618 span: Span,
619 doc: Option<DocComment>,
620 },
621 Accessor {
624 name: Ident,
625 modifiers: ClassModifiers,
626 kind: AccessorKind,
627 param: Option<Box<ParamDecl>>,
630 return_type: Option<TypeAnnotation>,
632 body: StmtId,
633 span: Span,
634 doc: Option<DocComment>,
635 },
636}
637
638#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
639pub enum AccessorKind {
640 Get,
641 Set,
642}
643
644#[derive(Clone, Debug, PartialEq)]
645pub struct EnumMember {
646 pub name: Ident,
647 pub value: Option<EnumInitializer>,
648 pub span: Span,
649 pub doc: Option<DocComment>,
650}
651
652#[derive(Clone, Debug, PartialEq)]
654pub enum EnumInitializer {
655 Number {
657 value: f64,
658 span: Span,
659 },
660 String {
661 value: String,
662 span: Span,
663 },
664}
665
666impl EnumInitializer {
667 pub fn span(&self) -> Span {
668 match self {
669 EnumInitializer::Number { span, .. } => *span,
670 EnumInitializer::String { span, .. } => *span,
671 }
672 }
673}
674
675#[derive(Clone, Debug, PartialEq)]
677pub struct SwitchCase {
678 pub values: Vec<ExprId>,
679 pub body: StmtId,
680 pub span: Span,
681}
682
683#[derive(Clone, Debug, PartialEq)]
685pub struct SwitchDefault {
686 pub body: StmtId,
687 pub span: Span,
688}
689
690#[derive(Clone, Debug, PartialEq)]
694pub struct CatchClause {
695 pub binding: Ident,
696 pub ty: Option<TypeAnnotation>,
697 pub body: StmtId,
698 pub span: Span,
699}
700
701#[derive(Clone, Debug, PartialEq)]
703pub struct ParamDecl {
704 pub name: Ident,
705 pub ty: Option<TypeAnnotation>,
706 pub default: Option<ExprId>,
707 pub optional: bool,
710 pub pattern: Option<Binding>,
712 pub rest: bool,
713 pub modifiers: Option<ClassModifiers>,
716}
717
718impl ParamDecl {
719 pub fn is_omittable(&self) -> bool {
721 self.optional || self.default.is_some()
722 }
723}
724
725#[derive(Clone, Debug, PartialEq)]
727pub enum Binding {
728 Object {
729 fields: Vec<ObjectPatternField>,
730 rest: Option<Ident>,
731 span: Span,
732 },
733 Array {
734 elems: Vec<Option<Ident>>,
736 defaults: Vec<Option<ExprId>>,
738 rest: Option<Ident>,
739 span: Span,
740 },
741}
742
743impl Binding {
744 pub fn span(&self) -> Span {
745 match self {
746 Binding::Object { span, .. } | Binding::Array { span, .. } => *span,
747 }
748 }
749}
750
751#[derive(Clone, Debug, PartialEq)]
753pub struct ObjectPatternField {
754 pub source: Ident,
755 pub local: Ident,
756 pub default: Option<ExprId>,
757 pub span: Span,
758}
759
760#[derive(Clone, Debug, PartialEq)]
761pub struct TypeAnnotation {
762 pub kind: TypeAnnotationKind,
763 pub span: Span,
764}
765
766#[derive(Clone, Debug, PartialEq)]
768pub struct TypePredicateAnnotation {
769 pub param: Ident,
770 pub asserted: TypeAnnotation,
771 pub span: Span,
772}
773
774#[derive(Clone, Debug, PartialEq)]
775pub enum TypeAnnotationKind {
776 Name {
778 name: Ident,
779 args: Vec<TypeAnnotation>,
780 },
781 Qualified {
783 path: Vec<Ident>,
784 args: Vec<TypeAnnotation>,
785 },
786 StringLiteral(String),
787 NumberLiteral(crate::types::LiteralF64),
789 BigIntLiteral(String),
791 BooleanLiteral(bool),
792 Array(Box<TypeAnnotation>),
793 Tuple(Vec<TypeAnnotation>),
796 Optional(Box<TypeAnnotation>),
798 Readonly(Box<TypeAnnotation>),
801 Object {
802 fields: Vec<TypeAnnotationField>,
803 index: Option<Box<IndexSignatureAnnotation>>,
804 },
805 Function {
807 params: Vec<TypeAnnotationField>,
808 return_type: Box<TypeAnnotation>,
809 },
810 Union(Vec<TypeAnnotation>),
812 KeyOf(Box<TypeAnnotation>),
815 TypeOf {
819 path: Vec<Ident>,
820 },
821}
822
823#[derive(Clone, Debug, PartialEq)]
827pub struct TypeAnnotationField {
828 pub name: Ident,
829 pub ty: TypeAnnotation,
830 pub optional: bool,
831 pub readonly: bool,
832 pub rest: bool,
833 pub method: bool,
835}
836
837#[derive(Clone, Debug, PartialEq, Eq)]
839pub struct BindingDefault {
840 pub saved: Ident,
842 pub default: ExprId,
844 pub annotated: bool,
847}
848
849#[derive(Clone, Debug, PartialEq, Eq)]
851pub struct PatternOrigin {
852 pub pattern_span: Span,
853 pub slot_arity: usize,
854}
855
856#[derive(Clone, Debug)]
861pub struct ExportedDecl {
862 pub stmt: StmtId,
863 pub export_span: Span,
865}
866
867#[derive(Default, Clone, Debug)]
868pub struct Ast {
869 exprs: Vec<Expr>,
870 stmts: Vec<Stmt>,
871 pub top_level: Vec<StmtId>,
872 pub pattern_origins: std::collections::BTreeMap<ExprId, PatternOrigin>,
878 pub tuple_pattern_sources: std::collections::BTreeSet<ExprId>,
883 pub parameter_bindings: std::collections::HashMap<Span, Vec<StmtId>>,
885 pub for_of_pattern_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
887 pub for_pattern_init_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
891 pub exported_decls: Vec<ExportedDecl>,
893 pub implicit_initializers: std::collections::BTreeSet<ExprId>,
895 pub synthetic_undefined: std::collections::BTreeSet<ExprId>,
899 pub binding_defaults: std::collections::BTreeMap<ExprId, BindingDefault>,
901}
902
903impl Ast {
904 pub(crate) fn source_expressions(&self) -> &[Expr] {
905 &self.exprs
906 }
907 pub(crate) fn source_statements(&self) -> &[Stmt] {
908 &self.stmts
909 }
910
911 pub fn validate_source(
912 &self,
913 source: &str,
914 file: crate::FileId,
915 ) -> Result<(), crate::source::SourceError> {
916 crate::source_validation::validate(self, source, file)
917 }
918
919 pub fn new() -> Self {
920 Self::default()
921 }
922
923 pub fn try_push_expr(&mut self, expr: Expr) -> Result<ExprId, ArenaError> {
925 arena::push(&mut self.exprs, expr, ArenaKind::Expressions).map(ExprId)
926 }
927
928 pub fn try_push_stmt(&mut self, stmt: Stmt) -> Result<StmtId, ArenaError> {
930 arena::push(&mut self.stmts, stmt, ArenaKind::Statements).map(StmtId)
931 }
932
933 pub fn try_expr(&self, id: ExprId) -> Result<&Expr, ArenaError> {
934 arena::get(&self.exprs, id.0, ArenaKind::Expressions)
935 }
936
937 pub fn try_stmt(&self, id: StmtId) -> Result<&Stmt, ArenaError> {
938 arena::get(&self.stmts, id.0, ArenaKind::Statements)
939 }
940
941 pub fn try_expr_mut(&mut self, id: ExprId) -> Result<&mut Expr, ArenaError> {
942 arena::get_mut(&mut self.exprs, id.0, ArenaKind::Expressions)
943 }
944
945 pub fn try_stmt_mut(&mut self, id: StmtId) -> Result<&mut Stmt, ArenaError> {
946 arena::get_mut(&mut self.stmts, id.0, ArenaKind::Statements)
947 }
948
949 pub fn expr_ids(&self) -> Result<impl DoubleEndedIterator<Item = ExprId> + use<>, ArenaError> {
951 Ok(arena::ids(self.exprs.len(), ArenaKind::Expressions)?.map(ExprId))
952 }
953
954 pub fn stmt_ids(&self) -> Result<impl DoubleEndedIterator<Item = StmtId> + use<>, ArenaError> {
956 Ok(arena::ids(self.stmts.len(), ArenaKind::Statements)?.map(StmtId))
957 }
958
959 pub fn exprs_len(&self) -> usize {
960 self.exprs.len()
961 }
962
963 pub fn stmts_len(&self) -> usize {
964 self.stmts.len()
965 }
966}
967
968#[cfg(test)]
969mod tests {
970 use super::{Ast, BinOp, Expr, ExprKind, Stmt, StmtKind, UnOp};
971 use crate::Span;
972
973 #[test]
974 fn arena_round_trip_for_exprs() {
975 let mut ast = Ast::new();
976 let id = ast
977 .try_push_expr(Expr {
978 kind: ExprKind::Number(42.0),
979 span: Span::new(crate::FileId(0), 0, 2).unwrap(),
980 })
981 .unwrap();
982 assert_eq!(id.0, 0);
983 assert_eq!(ast.try_expr(id).unwrap().kind, ExprKind::Number(42.0));
984 assert_eq!(
985 ast.try_expr(id).unwrap().span,
986 Span::new(crate::FileId(0), 0, 2).unwrap()
987 );
988 }
989
990 #[test]
991 fn arena_round_trip_for_stmts() {
992 let mut ast = Ast::new();
993 let expr_id = ast
994 .try_push_expr(Expr {
995 kind: ExprKind::Null,
996 span: Span::new(crate::FileId(0), 0, 4).unwrap(),
997 })
998 .unwrap();
999 let stmt_id = ast
1000 .try_push_stmt(Stmt {
1001 kind: StmtKind::Expr(expr_id),
1002 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1003 })
1004 .unwrap();
1005 assert_eq!(stmt_id.0, 0);
1006 assert_eq!(
1007 ast.try_stmt(stmt_id).unwrap().span,
1008 Span::new(crate::FileId(0), 0, 5).unwrap()
1009 );
1010 assert!(matches!(
1011 ast.try_stmt(stmt_id).unwrap().kind,
1012 StmtKind::Expr(_)
1013 ));
1014 }
1015
1016 #[test]
1017 fn build_binary_expression_tree() {
1018 let mut ast = Ast::new();
1019 let lhs = ast
1020 .try_push_expr(Expr {
1021 kind: ExprKind::Number(1.0),
1022 span: Span::new(crate::FileId(0), 0, 1).unwrap(),
1023 })
1024 .unwrap();
1025 let rhs = ast
1026 .try_push_expr(Expr {
1027 kind: ExprKind::Number(2.0),
1028 span: Span::new(crate::FileId(0), 4, 5).unwrap(),
1029 })
1030 .unwrap();
1031 let sum = ast
1032 .try_push_expr(Expr {
1033 kind: ExprKind::Binary {
1034 op: BinOp::Add,
1035 lhs,
1036 rhs,
1037 },
1038 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1039 })
1040 .unwrap();
1041 let stmt_id = ast
1042 .try_push_stmt(Stmt {
1043 kind: StmtKind::Expr(sum),
1044 span: Span::new(crate::FileId(0), 0, 6).unwrap(),
1045 })
1046 .unwrap();
1047 ast.top_level.push(stmt_id);
1048
1049 let top = ast.try_stmt(stmt_id).unwrap();
1050 let StmtKind::Expr(sum_id) = top.kind else {
1051 panic!("expected expression statement")
1052 };
1053 let sum_expr = ast.try_expr(sum_id).unwrap();
1054 let ExprKind::Binary { op, lhs, rhs } = sum_expr.kind else {
1055 panic!("expected binary expression")
1056 };
1057 assert_eq!(op, BinOp::Add);
1058 assert_eq!(ast.try_expr(lhs).unwrap().kind, ExprKind::Number(1.0));
1059 assert_eq!(ast.try_expr(rhs).unwrap().kind, ExprKind::Number(2.0));
1060 }
1061
1062 #[test]
1063 fn clone_and_equality() {
1064 let kind = ExprKind::Unary {
1065 op: UnOp::Neg,
1066 operand: super::ExprId(0),
1067 };
1068 assert_eq!(kind.clone(), kind);
1069 assert_eq!(BinOp::Eq, BinOp::Eq);
1070 assert_ne!(BinOp::Eq, BinOp::NotEq);
1071 }
1072
1073 #[test]
1074 fn new_ast_is_empty() {
1075 let ast = Ast::new();
1076 assert!(ast.top_level.is_empty());
1077 }
1078}
1079
1080#[derive(Clone, Debug, PartialEq)]
1082pub struct IndexSignatureAnnotation {
1083 pub value: TypeAnnotation,
1084 pub readonly: bool,
1085 pub span: Span,
1086}