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: Vec<StmtId>,
394 condition: Option<ExprId>,
395 update: Option<StmtId>,
396 body: StmtId,
398 },
399 ForOf {
400 binding_kind: BindingKind,
401 name: Ident,
402 ty: Option<TypeAnnotation>,
403 iter: ExprId,
404 body: StmtId,
406 },
407 ForOfPattern {
409 binding_kind: BindingKind,
410 binding: Binding,
411 ty: Option<TypeAnnotation>,
412 iter: ExprId,
413 body: StmtId,
415 },
416 DoWhile {
417 body: StmtId,
419 condition: ExprId,
420 },
421 Switch {
423 discriminant: ExprId,
424 cases: Vec<SwitchCase>,
425 default: Option<SwitchDefault>,
426 },
427 Break,
428 Continue,
429 Return(Option<ExprId>),
430 Throw {
431 value: ExprId,
432 },
433 Try {
437 body: StmtId,
438 catches: Vec<CatchClause>,
439 finally: Option<StmtId>,
440 },
441 Expr(ExprId),
442 Block(Vec<StmtId>),
443 Assign {
444 target: Ident,
445 value: ExprId,
446 },
447 AssignField {
448 receiver: ExprId,
449 field_name: Ident,
450 value: ExprId,
451 },
452 AssignIndex {
453 receiver: ExprId,
454 index: ExprId,
455 value: ExprId,
456 },
457 CompoundAssign {
459 target: Ident,
460 op: BinOp,
461 op_span: Span,
462 value: ExprId,
463 },
464 CompoundAssignField {
465 receiver: ExprId,
466 field_name: Ident,
467 op: BinOp,
468 op_span: Span,
469 value: ExprId,
470 },
471 CompoundAssignIndex {
472 receiver: ExprId,
473 index: ExprId,
474 op: BinOp,
475 op_span: Span,
476 value: ExprId,
477 },
478 InterfaceDecl {
480 name: Ident,
481 generics: Vec<Ident>,
482 extends: Vec<TypeAnnotation>,
483 members: Vec<InterfaceMember>,
484 doc: Option<DocComment>,
485 },
486 ClassDecl {
490 name: Ident,
491 generics: Vec<Ident>,
492 extends: Option<TypeAnnotation>,
493 implements: Vec<TypeAnnotation>,
494 members: Vec<ClassMember>,
495 doc: Option<DocComment>,
496 },
497 EnumDecl {
499 name: Ident,
500 members: Vec<EnumMember>,
501 doc: Option<DocComment>,
502 },
503 TypeAliasDecl {
504 name: Ident,
505 generics: Vec<Ident>,
506 ty: TypeAnnotation,
507 doc: Option<DocComment>,
508 },
509 Import {
511 module: String,
512 module_span: Span,
513 kind: ImportKind,
514 doc: Option<DocComment>,
515 },
516 ExportFrom {
521 specs: Vec<ImportSpecifier>,
522 source: Option<(String, Span)>,
523 doc: Option<DocComment>,
524 },
525}
526
527#[derive(Clone, Debug, PartialEq)]
528pub enum ImportKind {
529 Named(Vec<ImportSpecifier>),
530 Namespace {
532 local_name: Ident,
533 },
534}
535
536#[derive(Clone, Debug, PartialEq)]
537pub struct ImportSpecifier {
538 pub imported_name: Ident,
539 pub local_name: Ident,
540}
541
542#[derive(Clone, Debug, PartialEq)]
543pub enum InterfaceMember {
544 IndexSignature(IndexSignatureAnnotation),
545 Method {
546 name: Ident,
547 optional: bool,
548 generics: Vec<Ident>,
549 params: Vec<ParamDecl>,
550 return_type: TypeAnnotation,
551 span: Span,
552 doc: Option<DocComment>,
553 },
554 Property {
557 name: Ident,
558 ty: TypeAnnotation,
559 optional: bool,
560 readonly: bool,
561 span: Span,
562 doc: Option<DocComment>,
563 },
564}
565
566#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
568pub enum Visibility {
569 #[default]
570 Public,
571 Private,
572}
573
574impl Visibility {
575 pub fn is_public(&self) -> bool {
576 *self == Visibility::Public
577 }
578}
579
580#[derive(Clone, Debug, PartialEq)]
583pub struct ClassModifiers {
584 pub visibility: Visibility,
585 pub visibility_span: Option<Span>,
586 pub readonly: Option<Span>,
587 pub static_span: Option<Span>,
588}
589
590#[derive(Clone, Debug, PartialEq)]
591pub enum ClassMember {
592 Field {
593 name: Ident,
594 modifiers: ClassModifiers,
595 optional: bool,
597 method_signature: bool,
600 ty: TypeAnnotation,
601 initializer: Option<ExprId>,
603 span: Span,
604 doc: Option<DocComment>,
605 },
606 Method {
607 name: Ident,
608 optional: bool,
609 modifiers: ClassModifiers,
610 generics: Vec<Ident>,
611 params: Vec<ParamDecl>,
612 return_type: TypeAnnotation,
613 body: StmtId,
614 span: Span,
615 doc: Option<DocComment>,
616 },
617 Constructor {
618 visibility: Visibility,
621 params: Vec<ParamDecl>,
622 body: StmtId,
623 span: Span,
624 doc: Option<DocComment>,
625 },
626 Accessor {
629 name: Ident,
630 modifiers: ClassModifiers,
631 kind: AccessorKind,
632 param: Option<Box<ParamDecl>>,
635 return_type: Option<TypeAnnotation>,
637 body: StmtId,
638 span: Span,
639 doc: Option<DocComment>,
640 },
641}
642
643#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
644pub enum AccessorKind {
645 Get,
646 Set,
647}
648
649#[derive(Clone, Debug, PartialEq)]
650pub struct EnumMember {
651 pub name: Ident,
652 pub value: Option<EnumInitializer>,
653 pub span: Span,
654 pub doc: Option<DocComment>,
655}
656
657#[derive(Clone, Debug, PartialEq)]
659pub enum EnumInitializer {
660 Number {
662 value: f64,
663 span: Span,
664 },
665 String {
666 value: String,
667 span: Span,
668 },
669}
670
671impl EnumInitializer {
672 pub fn span(&self) -> Span {
673 match self {
674 EnumInitializer::Number { span, .. } => *span,
675 EnumInitializer::String { span, .. } => *span,
676 }
677 }
678}
679
680#[derive(Clone, Debug, PartialEq)]
682pub struct SwitchCase {
683 pub values: Vec<ExprId>,
684 pub body: StmtId,
685 pub span: Span,
686}
687
688#[derive(Clone, Debug, PartialEq)]
690pub struct SwitchDefault {
691 pub body: StmtId,
692 pub span: Span,
693}
694
695#[derive(Clone, Debug, PartialEq)]
699pub struct CatchClause {
700 pub binding: Ident,
701 pub ty: Option<TypeAnnotation>,
702 pub body: StmtId,
703 pub span: Span,
704}
705
706#[derive(Clone, Debug, PartialEq)]
708pub struct ParamDecl {
709 pub name: Ident,
710 pub ty: Option<TypeAnnotation>,
711 pub default: Option<ExprId>,
712 pub optional: bool,
715 pub pattern: Option<Binding>,
717 pub rest: bool,
718 pub modifiers: Option<ClassModifiers>,
721}
722
723impl ParamDecl {
724 pub fn is_omittable(&self) -> bool {
726 self.optional || self.default.is_some()
727 }
728}
729
730#[derive(Clone, Debug, PartialEq)]
732pub enum Binding {
733 Object {
734 fields: Vec<ObjectPatternField>,
735 rest: Option<Ident>,
736 span: Span,
737 },
738 Array {
739 elems: Vec<Option<Ident>>,
741 defaults: Vec<Option<ExprId>>,
743 rest: Option<Ident>,
744 span: Span,
745 },
746}
747
748impl Binding {
749 pub fn span(&self) -> Span {
750 match self {
751 Binding::Object { span, .. } | Binding::Array { span, .. } => *span,
752 }
753 }
754}
755
756#[derive(Clone, Debug, PartialEq)]
758pub struct ObjectPatternField {
759 pub source: Ident,
760 pub local: Ident,
761 pub default: Option<ExprId>,
762 pub span: Span,
763}
764
765#[derive(Clone, Debug, PartialEq)]
766pub struct TypeAnnotation {
767 pub kind: TypeAnnotationKind,
768 pub span: Span,
769}
770
771#[derive(Clone, Debug, PartialEq)]
773pub struct TypePredicateAnnotation {
774 pub param: Ident,
775 pub asserted: TypeAnnotation,
776 pub span: Span,
777}
778
779#[derive(Clone, Debug, PartialEq)]
780pub enum TypeAnnotationKind {
781 Name {
783 name: Ident,
784 args: Vec<TypeAnnotation>,
785 },
786 Qualified {
788 path: Vec<Ident>,
789 args: Vec<TypeAnnotation>,
790 },
791 StringLiteral(String),
792 NumberLiteral(crate::types::LiteralF64),
794 BigIntLiteral(String),
796 BooleanLiteral(bool),
797 Array(Box<TypeAnnotation>),
798 Tuple(Vec<TypeAnnotation>),
801 Optional(Box<TypeAnnotation>),
803 Readonly(Box<TypeAnnotation>),
806 Object {
807 fields: Vec<TypeAnnotationField>,
808 index: Option<Box<IndexSignatureAnnotation>>,
809 },
810 Function {
812 params: Vec<TypeAnnotationField>,
813 return_type: Box<TypeAnnotation>,
814 },
815 Union(Vec<TypeAnnotation>),
817 KeyOf(Box<TypeAnnotation>),
820 TypeOf {
824 path: Vec<Ident>,
825 },
826}
827
828#[derive(Clone, Debug, PartialEq)]
832pub struct TypeAnnotationField {
833 pub name: Ident,
834 pub ty: TypeAnnotation,
835 pub optional: bool,
836 pub readonly: bool,
837 pub rest: bool,
838 pub method: bool,
840}
841
842#[derive(Clone, Debug, PartialEq, Eq)]
844pub struct BindingDefault {
845 pub saved: Ident,
847 pub default: ExprId,
849 pub annotated: bool,
852}
853
854#[derive(Clone, Debug, PartialEq, Eq)]
856pub struct PatternOrigin {
857 pub pattern_span: Span,
858 pub slot_arity: usize,
859 pub defaulted: bool,
862}
863
864#[derive(Clone, Debug)]
869pub struct ExportedDecl {
870 pub stmt: StmtId,
871 pub export_span: Span,
873}
874
875#[derive(Default, Clone, Debug)]
876pub struct Ast {
877 exprs: Vec<Expr>,
878 stmts: Vec<Stmt>,
879 pub top_level: Vec<StmtId>,
880 pub pattern_origins: std::collections::BTreeMap<ExprId, PatternOrigin>,
886 pub tuple_pattern_sources: std::collections::BTreeSet<ExprId>,
891 pub tuple_pattern_pad_defaults: std::collections::BTreeMap<ExprId, Vec<Option<ExprId>>>,
896 pub object_pattern_pad_defaults: std::collections::BTreeMap<ExprId, Vec<(String, ExprId)>>,
901 pub object_pattern_sources:
908 std::collections::BTreeMap<ExprId, std::collections::BTreeMap<String, Option<ExprId>>>,
909 pub tuple_pattern_defaults:
912 std::collections::BTreeMap<ExprId, std::collections::BTreeMap<usize, ExprId>>,
913 pub const_pattern_sources: std::collections::BTreeSet<ExprId>,
916 pub parameter_bindings: std::collections::HashMap<Span, Vec<StmtId>>,
918 pub for_of_pattern_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
920 pub for_pattern_init_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
924 pub exported_decls: Vec<ExportedDecl>,
926 pub implicit_initializers: std::collections::BTreeSet<ExprId>,
928 pub synthetic_undefined: std::collections::BTreeSet<ExprId>,
932 pub binding_defaults: std::collections::BTreeMap<ExprId, BindingDefault>,
934 pub unparsed_main: bool,
937}
938
939impl Ast {
940 pub(crate) fn source_expressions(&self) -> &[Expr] {
941 &self.exprs
942 }
943 pub(crate) fn source_statements(&self) -> &[Stmt] {
944 &self.stmts
945 }
946
947 pub fn validate_source(
948 &self,
949 source: &str,
950 file: crate::FileId,
951 ) -> Result<(), crate::source::SourceError> {
952 crate::source_validation::validate(self, source, file)
953 }
954
955 pub fn new() -> Self {
956 Self::default()
957 }
958
959 pub fn try_push_expr(&mut self, expr: Expr) -> Result<ExprId, ArenaError> {
961 arena::push(&mut self.exprs, expr, ArenaKind::Expressions).map(ExprId)
962 }
963
964 pub fn try_push_stmt(&mut self, stmt: Stmt) -> Result<StmtId, ArenaError> {
966 arena::push(&mut self.stmts, stmt, ArenaKind::Statements).map(StmtId)
967 }
968
969 pub fn try_expr(&self, id: ExprId) -> Result<&Expr, ArenaError> {
970 arena::get(&self.exprs, id.0, ArenaKind::Expressions)
971 }
972
973 pub fn exprs_within(&self, span: Span) -> impl Iterator<Item = &Expr> {
976 self.exprs
977 .iter()
978 .filter(move |expr| span.encloses(expr.span))
979 }
980
981 pub fn try_peel_parens(&self, mut id: ExprId) -> Result<ExprId, ArenaError> {
983 while let ExprKind::Paren(inner) = &self.try_expr(id)?.kind {
984 id = *inner;
985 }
986 Ok(id)
987 }
988
989 pub fn try_stmt(&self, id: StmtId) -> Result<&Stmt, ArenaError> {
990 arena::get(&self.stmts, id.0, ArenaKind::Statements)
991 }
992
993 pub fn try_expr_mut(&mut self, id: ExprId) -> Result<&mut Expr, ArenaError> {
994 arena::get_mut(&mut self.exprs, id.0, ArenaKind::Expressions)
995 }
996
997 pub fn try_stmt_mut(&mut self, id: StmtId) -> Result<&mut Stmt, ArenaError> {
998 arena::get_mut(&mut self.stmts, id.0, ArenaKind::Statements)
999 }
1000
1001 pub fn expr_ids(&self) -> Result<impl DoubleEndedIterator<Item = ExprId> + use<>, ArenaError> {
1003 Ok(arena::ids(self.exprs.len(), ArenaKind::Expressions)?.map(ExprId))
1004 }
1005
1006 pub fn stmt_ids(&self) -> Result<impl DoubleEndedIterator<Item = StmtId> + use<>, ArenaError> {
1008 Ok(arena::ids(self.stmts.len(), ArenaKind::Statements)?.map(StmtId))
1009 }
1010
1011 pub fn exprs_len(&self) -> usize {
1012 self.exprs.len()
1013 }
1014
1015 pub fn stmts_len(&self) -> usize {
1016 self.stmts.len()
1017 }
1018}
1019
1020#[cfg(test)]
1021mod tests {
1022 use super::{Ast, BinOp, Expr, ExprKind, Stmt, StmtKind, UnOp};
1023 use crate::Span;
1024
1025 #[test]
1026 fn arena_round_trip_for_exprs() {
1027 let mut ast = Ast::new();
1028 let id = ast
1029 .try_push_expr(Expr {
1030 kind: ExprKind::Number(42.0),
1031 span: Span::new(crate::FileId(0), 0, 2).unwrap(),
1032 })
1033 .unwrap();
1034 assert_eq!(id.0, 0);
1035 assert_eq!(ast.try_expr(id).unwrap().kind, ExprKind::Number(42.0));
1036 assert_eq!(
1037 ast.try_expr(id).unwrap().span,
1038 Span::new(crate::FileId(0), 0, 2).unwrap()
1039 );
1040 }
1041
1042 #[test]
1043 fn arena_round_trip_for_stmts() {
1044 let mut ast = Ast::new();
1045 let expr_id = ast
1046 .try_push_expr(Expr {
1047 kind: ExprKind::Null,
1048 span: Span::new(crate::FileId(0), 0, 4).unwrap(),
1049 })
1050 .unwrap();
1051 let stmt_id = ast
1052 .try_push_stmt(Stmt {
1053 kind: StmtKind::Expr(expr_id),
1054 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1055 })
1056 .unwrap();
1057 assert_eq!(stmt_id.0, 0);
1058 assert_eq!(
1059 ast.try_stmt(stmt_id).unwrap().span,
1060 Span::new(crate::FileId(0), 0, 5).unwrap()
1061 );
1062 assert!(matches!(
1063 ast.try_stmt(stmt_id).unwrap().kind,
1064 StmtKind::Expr(_)
1065 ));
1066 }
1067
1068 #[test]
1069 fn build_binary_expression_tree() {
1070 let mut ast = Ast::new();
1071 let lhs = ast
1072 .try_push_expr(Expr {
1073 kind: ExprKind::Number(1.0),
1074 span: Span::new(crate::FileId(0), 0, 1).unwrap(),
1075 })
1076 .unwrap();
1077 let rhs = ast
1078 .try_push_expr(Expr {
1079 kind: ExprKind::Number(2.0),
1080 span: Span::new(crate::FileId(0), 4, 5).unwrap(),
1081 })
1082 .unwrap();
1083 let sum = ast
1084 .try_push_expr(Expr {
1085 kind: ExprKind::Binary {
1086 op: BinOp::Add,
1087 lhs,
1088 rhs,
1089 },
1090 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1091 })
1092 .unwrap();
1093 let stmt_id = ast
1094 .try_push_stmt(Stmt {
1095 kind: StmtKind::Expr(sum),
1096 span: Span::new(crate::FileId(0), 0, 6).unwrap(),
1097 })
1098 .unwrap();
1099 ast.top_level.push(stmt_id);
1100
1101 let top = ast.try_stmt(stmt_id).unwrap();
1102 let StmtKind::Expr(sum_id) = top.kind else {
1103 panic!("expected expression statement")
1104 };
1105 let sum_expr = ast.try_expr(sum_id).unwrap();
1106 let ExprKind::Binary { op, lhs, rhs } = sum_expr.kind else {
1107 panic!("expected binary expression")
1108 };
1109 assert_eq!(op, BinOp::Add);
1110 assert_eq!(ast.try_expr(lhs).unwrap().kind, ExprKind::Number(1.0));
1111 assert_eq!(ast.try_expr(rhs).unwrap().kind, ExprKind::Number(2.0));
1112 }
1113
1114 #[test]
1115 fn clone_and_equality() {
1116 let kind = ExprKind::Unary {
1117 op: UnOp::Neg,
1118 operand: super::ExprId(0),
1119 };
1120 assert_eq!(kind.clone(), kind);
1121 assert_eq!(BinOp::Eq, BinOp::Eq);
1122 assert_ne!(BinOp::Eq, BinOp::NotEq);
1123 }
1124
1125 #[test]
1126 fn new_ast_is_empty() {
1127 let ast = Ast::new();
1128 assert!(ast.top_level.is_empty());
1129 }
1130}
1131
1132#[derive(Clone, Debug, PartialEq)]
1134pub struct IndexSignatureAnnotation {
1135 pub value: TypeAnnotation,
1136 pub readonly: bool,
1137 pub span: Span,
1138}