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 method_signature: bool,
598 ty: TypeAnnotation,
599 initializer: Option<ExprId>,
601 span: Span,
602 doc: Option<DocComment>,
603 },
604 Method {
605 name: Ident,
606 optional: bool,
607 modifiers: ClassModifiers,
608 generics: Vec<Ident>,
609 params: Vec<ParamDecl>,
610 return_type: TypeAnnotation,
611 body: StmtId,
612 span: Span,
613 doc: Option<DocComment>,
614 },
615 Constructor {
616 visibility: Visibility,
619 params: Vec<ParamDecl>,
620 body: StmtId,
621 span: Span,
622 doc: Option<DocComment>,
623 },
624 Accessor {
627 name: Ident,
628 modifiers: ClassModifiers,
629 kind: AccessorKind,
630 param: Option<Box<ParamDecl>>,
633 return_type: Option<TypeAnnotation>,
635 body: StmtId,
636 span: Span,
637 doc: Option<DocComment>,
638 },
639}
640
641#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
642pub enum AccessorKind {
643 Get,
644 Set,
645}
646
647#[derive(Clone, Debug, PartialEq)]
648pub struct EnumMember {
649 pub name: Ident,
650 pub value: Option<EnumInitializer>,
651 pub span: Span,
652 pub doc: Option<DocComment>,
653}
654
655#[derive(Clone, Debug, PartialEq)]
657pub enum EnumInitializer {
658 Number {
660 value: f64,
661 span: Span,
662 },
663 String {
664 value: String,
665 span: Span,
666 },
667}
668
669impl EnumInitializer {
670 pub fn span(&self) -> Span {
671 match self {
672 EnumInitializer::Number { span, .. } => *span,
673 EnumInitializer::String { span, .. } => *span,
674 }
675 }
676}
677
678#[derive(Clone, Debug, PartialEq)]
680pub struct SwitchCase {
681 pub values: Vec<ExprId>,
682 pub body: StmtId,
683 pub span: Span,
684}
685
686#[derive(Clone, Debug, PartialEq)]
688pub struct SwitchDefault {
689 pub body: StmtId,
690 pub span: Span,
691}
692
693#[derive(Clone, Debug, PartialEq)]
697pub struct CatchClause {
698 pub binding: Ident,
699 pub ty: Option<TypeAnnotation>,
700 pub body: StmtId,
701 pub span: Span,
702}
703
704#[derive(Clone, Debug, PartialEq)]
706pub struct ParamDecl {
707 pub name: Ident,
708 pub ty: Option<TypeAnnotation>,
709 pub default: Option<ExprId>,
710 pub optional: bool,
713 pub pattern: Option<Binding>,
715 pub rest: bool,
716 pub modifiers: Option<ClassModifiers>,
719}
720
721impl ParamDecl {
722 pub fn is_omittable(&self) -> bool {
724 self.optional || self.default.is_some()
725 }
726}
727
728#[derive(Clone, Debug, PartialEq)]
730pub enum Binding {
731 Object {
732 fields: Vec<ObjectPatternField>,
733 rest: Option<Ident>,
734 span: Span,
735 },
736 Array {
737 elems: Vec<Option<Ident>>,
739 defaults: Vec<Option<ExprId>>,
741 rest: Option<Ident>,
742 span: Span,
743 },
744}
745
746impl Binding {
747 pub fn span(&self) -> Span {
748 match self {
749 Binding::Object { span, .. } | Binding::Array { span, .. } => *span,
750 }
751 }
752}
753
754#[derive(Clone, Debug, PartialEq)]
756pub struct ObjectPatternField {
757 pub source: Ident,
758 pub local: Ident,
759 pub default: Option<ExprId>,
760 pub span: Span,
761}
762
763#[derive(Clone, Debug, PartialEq)]
764pub struct TypeAnnotation {
765 pub kind: TypeAnnotationKind,
766 pub span: Span,
767}
768
769#[derive(Clone, Debug, PartialEq)]
771pub struct TypePredicateAnnotation {
772 pub param: Ident,
773 pub asserted: TypeAnnotation,
774 pub span: Span,
775}
776
777#[derive(Clone, Debug, PartialEq)]
778pub enum TypeAnnotationKind {
779 Name {
781 name: Ident,
782 args: Vec<TypeAnnotation>,
783 },
784 Qualified {
786 path: Vec<Ident>,
787 args: Vec<TypeAnnotation>,
788 },
789 StringLiteral(String),
790 NumberLiteral(crate::types::LiteralF64),
792 BigIntLiteral(String),
794 BooleanLiteral(bool),
795 Array(Box<TypeAnnotation>),
796 Tuple(Vec<TypeAnnotation>),
799 Optional(Box<TypeAnnotation>),
801 Readonly(Box<TypeAnnotation>),
804 Object {
805 fields: Vec<TypeAnnotationField>,
806 index: Option<Box<IndexSignatureAnnotation>>,
807 },
808 Function {
810 params: Vec<TypeAnnotationField>,
811 return_type: Box<TypeAnnotation>,
812 },
813 Union(Vec<TypeAnnotation>),
815 KeyOf(Box<TypeAnnotation>),
818 TypeOf {
822 path: Vec<Ident>,
823 },
824}
825
826#[derive(Clone, Debug, PartialEq)]
830pub struct TypeAnnotationField {
831 pub name: Ident,
832 pub ty: TypeAnnotation,
833 pub optional: bool,
834 pub readonly: bool,
835 pub rest: bool,
836 pub method: bool,
838}
839
840#[derive(Clone, Debug, PartialEq, Eq)]
842pub struct BindingDefault {
843 pub saved: Ident,
845 pub default: ExprId,
847 pub annotated: bool,
850}
851
852#[derive(Clone, Debug, PartialEq, Eq)]
854pub struct PatternOrigin {
855 pub pattern_span: Span,
856 pub slot_arity: usize,
857 pub defaulted: bool,
860}
861
862#[derive(Clone, Debug)]
867pub struct ExportedDecl {
868 pub stmt: StmtId,
869 pub export_span: Span,
871}
872
873#[derive(Default, Clone, Debug)]
874pub struct Ast {
875 exprs: Vec<Expr>,
876 stmts: Vec<Stmt>,
877 pub top_level: Vec<StmtId>,
878 pub pattern_origins: std::collections::BTreeMap<ExprId, PatternOrigin>,
884 pub tuple_pattern_sources: std::collections::BTreeSet<ExprId>,
889 pub tuple_pattern_pad_defaults: std::collections::BTreeMap<ExprId, Vec<Option<ExprId>>>,
894 pub object_pattern_pad_defaults: std::collections::BTreeMap<ExprId, Vec<(String, ExprId)>>,
899 pub object_pattern_sources:
906 std::collections::BTreeMap<ExprId, std::collections::BTreeMap<String, Option<ExprId>>>,
907 pub tuple_pattern_defaults:
910 std::collections::BTreeMap<ExprId, std::collections::BTreeMap<usize, ExprId>>,
911 pub const_pattern_sources: std::collections::BTreeSet<ExprId>,
914 pub parameter_bindings: std::collections::HashMap<Span, Vec<StmtId>>,
916 pub for_of_pattern_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
918 pub for_pattern_init_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
922 pub exported_decls: Vec<ExportedDecl>,
924 pub implicit_initializers: std::collections::BTreeSet<ExprId>,
926 pub synthetic_undefined: std::collections::BTreeSet<ExprId>,
930 pub binding_defaults: std::collections::BTreeMap<ExprId, BindingDefault>,
932 pub unparsed_main: bool,
935}
936
937impl Ast {
938 pub(crate) fn source_expressions(&self) -> &[Expr] {
939 &self.exprs
940 }
941 pub(crate) fn source_statements(&self) -> &[Stmt] {
942 &self.stmts
943 }
944
945 pub fn validate_source(
946 &self,
947 source: &str,
948 file: crate::FileId,
949 ) -> Result<(), crate::source::SourceError> {
950 crate::source_validation::validate(self, source, file)
951 }
952
953 pub fn new() -> Self {
954 Self::default()
955 }
956
957 pub fn try_push_expr(&mut self, expr: Expr) -> Result<ExprId, ArenaError> {
959 arena::push(&mut self.exprs, expr, ArenaKind::Expressions).map(ExprId)
960 }
961
962 pub fn try_push_stmt(&mut self, stmt: Stmt) -> Result<StmtId, ArenaError> {
964 arena::push(&mut self.stmts, stmt, ArenaKind::Statements).map(StmtId)
965 }
966
967 pub fn try_expr(&self, id: ExprId) -> Result<&Expr, ArenaError> {
968 arena::get(&self.exprs, id.0, ArenaKind::Expressions)
969 }
970
971 pub fn exprs_within(&self, span: Span) -> impl Iterator<Item = &Expr> {
974 self.exprs
975 .iter()
976 .filter(move |expr| span.encloses(expr.span))
977 }
978
979 pub fn try_peel_parens(&self, mut id: ExprId) -> Result<ExprId, ArenaError> {
981 while let ExprKind::Paren(inner) = &self.try_expr(id)?.kind {
982 id = *inner;
983 }
984 Ok(id)
985 }
986
987 pub fn try_stmt(&self, id: StmtId) -> Result<&Stmt, ArenaError> {
988 arena::get(&self.stmts, id.0, ArenaKind::Statements)
989 }
990
991 pub fn try_expr_mut(&mut self, id: ExprId) -> Result<&mut Expr, ArenaError> {
992 arena::get_mut(&mut self.exprs, id.0, ArenaKind::Expressions)
993 }
994
995 pub fn try_stmt_mut(&mut self, id: StmtId) -> Result<&mut Stmt, ArenaError> {
996 arena::get_mut(&mut self.stmts, id.0, ArenaKind::Statements)
997 }
998
999 pub fn expr_ids(&self) -> Result<impl DoubleEndedIterator<Item = ExprId> + use<>, ArenaError> {
1001 Ok(arena::ids(self.exprs.len(), ArenaKind::Expressions)?.map(ExprId))
1002 }
1003
1004 pub fn stmt_ids(&self) -> Result<impl DoubleEndedIterator<Item = StmtId> + use<>, ArenaError> {
1006 Ok(arena::ids(self.stmts.len(), ArenaKind::Statements)?.map(StmtId))
1007 }
1008
1009 pub fn exprs_len(&self) -> usize {
1010 self.exprs.len()
1011 }
1012
1013 pub fn stmts_len(&self) -> usize {
1014 self.stmts.len()
1015 }
1016}
1017
1018#[cfg(test)]
1019mod tests {
1020 use super::{Ast, BinOp, Expr, ExprKind, Stmt, StmtKind, UnOp};
1021 use crate::Span;
1022
1023 #[test]
1024 fn arena_round_trip_for_exprs() {
1025 let mut ast = Ast::new();
1026 let id = ast
1027 .try_push_expr(Expr {
1028 kind: ExprKind::Number(42.0),
1029 span: Span::new(crate::FileId(0), 0, 2).unwrap(),
1030 })
1031 .unwrap();
1032 assert_eq!(id.0, 0);
1033 assert_eq!(ast.try_expr(id).unwrap().kind, ExprKind::Number(42.0));
1034 assert_eq!(
1035 ast.try_expr(id).unwrap().span,
1036 Span::new(crate::FileId(0), 0, 2).unwrap()
1037 );
1038 }
1039
1040 #[test]
1041 fn arena_round_trip_for_stmts() {
1042 let mut ast = Ast::new();
1043 let expr_id = ast
1044 .try_push_expr(Expr {
1045 kind: ExprKind::Null,
1046 span: Span::new(crate::FileId(0), 0, 4).unwrap(),
1047 })
1048 .unwrap();
1049 let stmt_id = ast
1050 .try_push_stmt(Stmt {
1051 kind: StmtKind::Expr(expr_id),
1052 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1053 })
1054 .unwrap();
1055 assert_eq!(stmt_id.0, 0);
1056 assert_eq!(
1057 ast.try_stmt(stmt_id).unwrap().span,
1058 Span::new(crate::FileId(0), 0, 5).unwrap()
1059 );
1060 assert!(matches!(
1061 ast.try_stmt(stmt_id).unwrap().kind,
1062 StmtKind::Expr(_)
1063 ));
1064 }
1065
1066 #[test]
1067 fn build_binary_expression_tree() {
1068 let mut ast = Ast::new();
1069 let lhs = ast
1070 .try_push_expr(Expr {
1071 kind: ExprKind::Number(1.0),
1072 span: Span::new(crate::FileId(0), 0, 1).unwrap(),
1073 })
1074 .unwrap();
1075 let rhs = ast
1076 .try_push_expr(Expr {
1077 kind: ExprKind::Number(2.0),
1078 span: Span::new(crate::FileId(0), 4, 5).unwrap(),
1079 })
1080 .unwrap();
1081 let sum = ast
1082 .try_push_expr(Expr {
1083 kind: ExprKind::Binary {
1084 op: BinOp::Add,
1085 lhs,
1086 rhs,
1087 },
1088 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1089 })
1090 .unwrap();
1091 let stmt_id = ast
1092 .try_push_stmt(Stmt {
1093 kind: StmtKind::Expr(sum),
1094 span: Span::new(crate::FileId(0), 0, 6).unwrap(),
1095 })
1096 .unwrap();
1097 ast.top_level.push(stmt_id);
1098
1099 let top = ast.try_stmt(stmt_id).unwrap();
1100 let StmtKind::Expr(sum_id) = top.kind else {
1101 panic!("expected expression statement")
1102 };
1103 let sum_expr = ast.try_expr(sum_id).unwrap();
1104 let ExprKind::Binary { op, lhs, rhs } = sum_expr.kind else {
1105 panic!("expected binary expression")
1106 };
1107 assert_eq!(op, BinOp::Add);
1108 assert_eq!(ast.try_expr(lhs).unwrap().kind, ExprKind::Number(1.0));
1109 assert_eq!(ast.try_expr(rhs).unwrap().kind, ExprKind::Number(2.0));
1110 }
1111
1112 #[test]
1113 fn clone_and_equality() {
1114 let kind = ExprKind::Unary {
1115 op: UnOp::Neg,
1116 operand: super::ExprId(0),
1117 };
1118 assert_eq!(kind.clone(), kind);
1119 assert_eq!(BinOp::Eq, BinOp::Eq);
1120 assert_ne!(BinOp::Eq, BinOp::NotEq);
1121 }
1122
1123 #[test]
1124 fn new_ast_is_empty() {
1125 let ast = Ast::new();
1126 assert!(ast.top_level.is_empty());
1127 }
1128}
1129
1130#[derive(Clone, Debug, PartialEq)]
1132pub struct IndexSignatureAnnotation {
1133 pub value: TypeAnnotation,
1134 pub readonly: bool,
1135 pub span: Span,
1136}