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<TypeParameterAnnotation>,
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<TypeParameterAnnotation>,
482 extends: Vec<TypeAnnotation>,
483 members: Vec<InterfaceMember>,
484 doc: Option<DocComment>,
485 },
486 ClassDecl {
490 name: Ident,
491 generics: Vec<TypeParameterAnnotation>,
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<TypeParameterAnnotation>,
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 TypeParameterAnnotation {
538 pub ident: Ident,
539 pub constraint: Option<TypeAnnotation>,
540}
541
542impl std::ops::Deref for TypeParameterAnnotation {
543 type Target = Ident;
544
545 fn deref(&self) -> &Ident {
546 &self.ident
547 }
548}
549
550impl From<Ident> for TypeParameterAnnotation {
551 fn from(ident: Ident) -> Self {
552 Self {
553 ident,
554 constraint: None,
555 }
556 }
557}
558
559#[derive(Clone, Debug, PartialEq)]
560pub struct ImportSpecifier {
561 pub imported_name: Ident,
562 pub local_name: Ident,
563}
564
565#[derive(Clone, Debug, PartialEq)]
566pub enum InterfaceMember {
567 IndexSignature(IndexSignatureAnnotation),
568 Method {
569 name: Ident,
570 optional: bool,
571 generics: Vec<TypeParameterAnnotation>,
572 params: Vec<ParamDecl>,
573 return_type: TypeAnnotation,
574 span: Span,
575 doc: Option<DocComment>,
576 },
577 Property {
580 name: Ident,
581 ty: TypeAnnotation,
582 optional: bool,
583 readonly: bool,
584 span: Span,
585 doc: Option<DocComment>,
586 },
587}
588
589#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
591pub enum Visibility {
592 #[default]
593 Public,
594 Private,
595}
596
597impl Visibility {
598 pub fn is_public(&self) -> bool {
599 *self == Visibility::Public
600 }
601}
602
603#[derive(Clone, Debug, PartialEq)]
606pub struct ClassModifiers {
607 pub visibility: Visibility,
608 pub visibility_span: Option<Span>,
609 pub readonly: Option<Span>,
610 pub static_span: Option<Span>,
611}
612
613#[derive(Clone, Debug, PartialEq)]
614pub enum ClassMember {
615 Field {
616 name: Ident,
617 modifiers: ClassModifiers,
618 optional: bool,
620 method_signature: bool,
623 ty: TypeAnnotation,
624 initializer: Option<ExprId>,
626 span: Span,
627 doc: Option<DocComment>,
628 },
629 Method {
630 name: Ident,
631 optional: bool,
632 modifiers: ClassModifiers,
633 generics: Vec<TypeParameterAnnotation>,
634 params: Vec<ParamDecl>,
635 return_type: TypeAnnotation,
636 body: StmtId,
637 span: Span,
638 doc: Option<DocComment>,
639 },
640 Constructor {
641 visibility: Visibility,
644 params: Vec<ParamDecl>,
645 body: StmtId,
646 span: Span,
647 doc: Option<DocComment>,
648 },
649 Accessor {
652 name: Ident,
653 modifiers: ClassModifiers,
654 kind: AccessorKind,
655 param: Option<Box<ParamDecl>>,
658 return_type: Option<TypeAnnotation>,
660 body: StmtId,
661 span: Span,
662 doc: Option<DocComment>,
663 },
664}
665
666#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
667pub enum AccessorKind {
668 Get,
669 Set,
670}
671
672#[derive(Clone, Debug, PartialEq)]
673pub struct EnumMember {
674 pub name: Ident,
675 pub value: Option<EnumInitializer>,
676 pub span: Span,
677 pub doc: Option<DocComment>,
678}
679
680#[derive(Clone, Debug, PartialEq)]
682pub enum EnumInitializer {
683 Number {
685 value: f64,
686 span: Span,
687 },
688 String {
689 value: String,
690 span: Span,
691 },
692}
693
694impl EnumInitializer {
695 pub fn span(&self) -> Span {
696 match self {
697 EnumInitializer::Number { span, .. } => *span,
698 EnumInitializer::String { span, .. } => *span,
699 }
700 }
701}
702
703#[derive(Clone, Debug, PartialEq)]
705pub struct SwitchCase {
706 pub values: Vec<ExprId>,
707 pub body: StmtId,
708 pub span: Span,
709}
710
711#[derive(Clone, Debug, PartialEq)]
713pub struct SwitchDefault {
714 pub body: StmtId,
715 pub span: Span,
716}
717
718#[derive(Clone, Debug, PartialEq)]
722pub struct CatchClause {
723 pub binding: Ident,
724 pub ty: Option<TypeAnnotation>,
725 pub body: StmtId,
726 pub span: Span,
727}
728
729#[derive(Clone, Debug, PartialEq)]
731pub struct ParamDecl {
732 pub name: Ident,
733 pub ty: Option<TypeAnnotation>,
734 pub default: Option<ExprId>,
735 pub optional: bool,
738 pub pattern: Option<Binding>,
740 pub rest: bool,
741 pub modifiers: Option<ClassModifiers>,
744}
745
746impl ParamDecl {
747 pub fn is_omittable(&self) -> bool {
749 self.optional || self.default.is_some()
750 }
751}
752
753#[derive(Clone, Debug, PartialEq)]
755pub enum Binding {
756 Object {
757 fields: Vec<ObjectPatternField>,
758 rest: Option<Ident>,
759 span: Span,
760 },
761 Array {
762 elems: Vec<Option<Ident>>,
764 defaults: Vec<Option<ExprId>>,
766 rest: Option<Ident>,
767 span: Span,
768 },
769}
770
771impl Binding {
772 pub fn span(&self) -> Span {
773 match self {
774 Binding::Object { span, .. } | Binding::Array { span, .. } => *span,
775 }
776 }
777}
778
779#[derive(Clone, Debug, PartialEq)]
781pub struct ObjectPatternField {
782 pub source: Ident,
783 pub local: Ident,
784 pub default: Option<ExprId>,
785 pub span: Span,
786}
787
788#[derive(Clone, Debug, PartialEq)]
789pub struct TypeAnnotation {
790 pub kind: TypeAnnotationKind,
791 pub span: Span,
792}
793
794#[derive(Clone, Debug, PartialEq)]
796pub struct TypePredicateAnnotation {
797 pub param: Ident,
798 pub asserted: TypeAnnotation,
799 pub span: Span,
800}
801
802#[derive(Clone, Debug, PartialEq)]
803pub enum TypeAnnotationKind {
804 Name {
806 name: Ident,
807 args: Vec<TypeAnnotation>,
808 },
809 Qualified {
811 path: Vec<Ident>,
812 args: Vec<TypeAnnotation>,
813 },
814 StringLiteral(String),
815 TemplateLiteral {
816 parts: Vec<String>,
817 substitutions: Vec<TypeAnnotation>,
818 },
819 NumberLiteral(crate::types::LiteralF64),
821 BigIntLiteral(String),
823 BooleanLiteral(bool),
824 Array(Box<TypeAnnotation>),
825 Tuple(Vec<TypeAnnotation>),
828 Optional(Box<TypeAnnotation>),
830 Readonly(Box<TypeAnnotation>),
833 Object {
834 fields: Vec<TypeAnnotationField>,
835 index: Option<Box<IndexSignatureAnnotation>>,
836 },
837 Function {
839 params: Vec<TypeAnnotationField>,
840 return_type: Box<TypeAnnotation>,
841 },
842 Union(Vec<TypeAnnotation>),
844 KeyOf(Box<TypeAnnotation>),
846 IndexedAccess {
848 object: Box<TypeAnnotation>,
849 index: Box<TypeAnnotation>,
850 },
851 TypeOf {
855 path: Vec<Ident>,
856 },
857}
858
859#[derive(Clone, Debug, PartialEq)]
863pub struct TypeAnnotationField {
864 pub name: Ident,
865 pub ty: TypeAnnotation,
866 pub optional: bool,
867 pub readonly: bool,
868 pub rest: bool,
869 pub method: bool,
871}
872
873#[derive(Clone, Debug, PartialEq, Eq)]
875pub struct BindingDefault {
876 pub saved: Ident,
878 pub default: ExprId,
880 pub annotated: bool,
883}
884
885#[derive(Clone, Debug, PartialEq, Eq)]
887pub struct PatternOrigin {
888 pub pattern_span: Span,
889 pub slot_arity: usize,
890 pub defaulted: bool,
893}
894
895#[derive(Clone, Debug)]
900pub struct ExportedDecl {
901 pub stmt: StmtId,
902 pub export_span: Span,
904}
905
906#[derive(Default, Clone, Debug)]
907pub struct Ast {
908 exprs: Vec<Expr>,
909 stmts: Vec<Stmt>,
910 pub top_level: Vec<StmtId>,
911 pub call_spread_args: std::collections::BTreeSet<ExprId>,
913 pub pattern_origins: std::collections::BTreeMap<ExprId, PatternOrigin>,
919 pub tuple_pattern_sources: std::collections::BTreeSet<ExprId>,
924 pub tuple_pattern_pad_defaults: std::collections::BTreeMap<ExprId, Vec<Option<ExprId>>>,
929 pub object_pattern_pad_defaults: std::collections::BTreeMap<ExprId, Vec<(String, ExprId)>>,
934 pub object_pattern_sources:
941 std::collections::BTreeMap<ExprId, std::collections::BTreeMap<String, Option<ExprId>>>,
942 pub tuple_pattern_defaults:
945 std::collections::BTreeMap<ExprId, std::collections::BTreeMap<usize, ExprId>>,
946 pub const_pattern_sources: std::collections::BTreeSet<ExprId>,
949 pub parameter_bindings: std::collections::HashMap<Span, Vec<StmtId>>,
951 pub for_of_pattern_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
953 pub for_pattern_init_bindings: std::collections::BTreeMap<StmtId, Vec<Ident>>,
957 pub exported_decls: Vec<ExportedDecl>,
959 pub implicit_initializers: std::collections::BTreeSet<ExprId>,
961 pub synthetic_undefined: std::collections::BTreeSet<ExprId>,
965 pub binding_defaults: std::collections::BTreeMap<ExprId, BindingDefault>,
967 pub unparsed_main: bool,
970 pub lowered_local_types: Option<LoweredLocalTypes>,
975}
976
977#[derive(Default, Clone, Debug)]
979pub struct LoweredLocalTypes {
980 pub diagnostics: Vec<crate::Diagnostic>,
983 pub scopes: std::collections::BTreeMap<String, Span>,
986}
987
988impl Ast {
989 pub(crate) fn source_expressions(&self) -> &[Expr] {
990 &self.exprs
991 }
992 pub(crate) fn source_statements(&self) -> &[Stmt] {
993 &self.stmts
994 }
995
996 pub fn validate_source(
997 &self,
998 source: &str,
999 file: crate::FileId,
1000 ) -> Result<(), crate::source::SourceError> {
1001 crate::source_validation::validate(self, source, file)
1002 }
1003
1004 pub fn new() -> Self {
1005 Self::default()
1006 }
1007
1008 pub fn try_push_expr(&mut self, expr: Expr) -> Result<ExprId, ArenaError> {
1010 arena::push(&mut self.exprs, expr, ArenaKind::Expressions).map(ExprId)
1011 }
1012
1013 pub fn try_push_stmt(&mut self, stmt: Stmt) -> Result<StmtId, ArenaError> {
1015 arena::push(&mut self.stmts, stmt, ArenaKind::Statements).map(StmtId)
1016 }
1017
1018 pub fn try_expr(&self, id: ExprId) -> Result<&Expr, ArenaError> {
1019 arena::get(&self.exprs, id.0, ArenaKind::Expressions)
1020 }
1021
1022 pub fn exprs_within(&self, span: Span) -> impl Iterator<Item = &Expr> {
1025 self.exprs
1026 .iter()
1027 .filter(move |expr| span.encloses(expr.span))
1028 }
1029
1030 pub fn try_peel_parens(&self, mut id: ExprId) -> Result<ExprId, ArenaError> {
1032 while let ExprKind::Paren(inner) = &self.try_expr(id)?.kind {
1033 id = *inner;
1034 }
1035 Ok(id)
1036 }
1037
1038 pub fn try_stmt(&self, id: StmtId) -> Result<&Stmt, ArenaError> {
1039 arena::get(&self.stmts, id.0, ArenaKind::Statements)
1040 }
1041
1042 pub fn try_expr_mut(&mut self, id: ExprId) -> Result<&mut Expr, ArenaError> {
1043 arena::get_mut(&mut self.exprs, id.0, ArenaKind::Expressions)
1044 }
1045
1046 pub fn try_stmt_mut(&mut self, id: StmtId) -> Result<&mut Stmt, ArenaError> {
1047 arena::get_mut(&mut self.stmts, id.0, ArenaKind::Statements)
1048 }
1049
1050 pub fn expr_ids(&self) -> Result<impl DoubleEndedIterator<Item = ExprId> + use<>, ArenaError> {
1052 Ok(arena::ids(self.exprs.len(), ArenaKind::Expressions)?.map(ExprId))
1053 }
1054
1055 pub fn stmt_ids(&self) -> Result<impl DoubleEndedIterator<Item = StmtId> + use<>, ArenaError> {
1057 Ok(arena::ids(self.stmts.len(), ArenaKind::Statements)?.map(StmtId))
1058 }
1059
1060 pub fn exprs_len(&self) -> usize {
1061 self.exprs.len()
1062 }
1063
1064 pub fn stmts_len(&self) -> usize {
1065 self.stmts.len()
1066 }
1067}
1068
1069#[cfg(test)]
1070mod tests {
1071 use super::{Ast, BinOp, Expr, ExprKind, Stmt, StmtKind, UnOp};
1072 use crate::Span;
1073
1074 #[test]
1075 fn arena_round_trip_for_exprs() {
1076 let mut ast = Ast::new();
1077 let id = ast
1078 .try_push_expr(Expr {
1079 kind: ExprKind::Number(42.0),
1080 span: Span::new(crate::FileId(0), 0, 2).unwrap(),
1081 })
1082 .unwrap();
1083 assert_eq!(id.0, 0);
1084 assert_eq!(ast.try_expr(id).unwrap().kind, ExprKind::Number(42.0));
1085 assert_eq!(
1086 ast.try_expr(id).unwrap().span,
1087 Span::new(crate::FileId(0), 0, 2).unwrap()
1088 );
1089 }
1090
1091 #[test]
1092 fn arena_round_trip_for_stmts() {
1093 let mut ast = Ast::new();
1094 let expr_id = ast
1095 .try_push_expr(Expr {
1096 kind: ExprKind::Null,
1097 span: Span::new(crate::FileId(0), 0, 4).unwrap(),
1098 })
1099 .unwrap();
1100 let stmt_id = ast
1101 .try_push_stmt(Stmt {
1102 kind: StmtKind::Expr(expr_id),
1103 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1104 })
1105 .unwrap();
1106 assert_eq!(stmt_id.0, 0);
1107 assert_eq!(
1108 ast.try_stmt(stmt_id).unwrap().span,
1109 Span::new(crate::FileId(0), 0, 5).unwrap()
1110 );
1111 assert!(matches!(
1112 ast.try_stmt(stmt_id).unwrap().kind,
1113 StmtKind::Expr(_)
1114 ));
1115 }
1116
1117 #[test]
1118 fn build_binary_expression_tree() {
1119 let mut ast = Ast::new();
1120 let lhs = ast
1121 .try_push_expr(Expr {
1122 kind: ExprKind::Number(1.0),
1123 span: Span::new(crate::FileId(0), 0, 1).unwrap(),
1124 })
1125 .unwrap();
1126 let rhs = ast
1127 .try_push_expr(Expr {
1128 kind: ExprKind::Number(2.0),
1129 span: Span::new(crate::FileId(0), 4, 5).unwrap(),
1130 })
1131 .unwrap();
1132 let sum = ast
1133 .try_push_expr(Expr {
1134 kind: ExprKind::Binary {
1135 op: BinOp::Add,
1136 lhs,
1137 rhs,
1138 },
1139 span: Span::new(crate::FileId(0), 0, 5).unwrap(),
1140 })
1141 .unwrap();
1142 let stmt_id = ast
1143 .try_push_stmt(Stmt {
1144 kind: StmtKind::Expr(sum),
1145 span: Span::new(crate::FileId(0), 0, 6).unwrap(),
1146 })
1147 .unwrap();
1148 ast.top_level.push(stmt_id);
1149
1150 let top = ast.try_stmt(stmt_id).unwrap();
1151 let StmtKind::Expr(sum_id) = top.kind else {
1152 panic!("expected expression statement")
1153 };
1154 let sum_expr = ast.try_expr(sum_id).unwrap();
1155 let ExprKind::Binary { op, lhs, rhs } = sum_expr.kind else {
1156 panic!("expected binary expression")
1157 };
1158 assert_eq!(op, BinOp::Add);
1159 assert_eq!(ast.try_expr(lhs).unwrap().kind, ExprKind::Number(1.0));
1160 assert_eq!(ast.try_expr(rhs).unwrap().kind, ExprKind::Number(2.0));
1161 }
1162
1163 #[test]
1164 fn clone_and_equality() {
1165 let kind = ExprKind::Unary {
1166 op: UnOp::Neg,
1167 operand: super::ExprId(0),
1168 };
1169 assert_eq!(kind.clone(), kind);
1170 assert_eq!(BinOp::Eq, BinOp::Eq);
1171 assert_ne!(BinOp::Eq, BinOp::NotEq);
1172 }
1173
1174 #[test]
1175 fn new_ast_is_empty() {
1176 let ast = Ast::new();
1177 assert!(ast.top_level.is_empty());
1178 }
1179}
1180
1181#[derive(Clone, Debug, PartialEq)]
1183pub struct IndexSignatureAnnotation {
1184 pub key: TypeAnnotation,
1185 pub value: TypeAnnotation,
1186 pub readonly: bool,
1187 pub span: Span,
1188}