Skip to main content

luau_syntax/ast/
statement.rs

1use super::*;
2use crate::allocator::AstArena;
3use crate::location::Position;
4use std::fmt;
5use std::marker::PhantomData;
6use std::ptr::NonNull;
7
8#[repr(u8)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum StatementTag {
11    Block,
12    Assign,
13    CompoundAssign,
14    Break,
15    Continue,
16    Class,
17    Expression,
18    NumericFor,
19    GenericFor,
20    FunctionDeclaration,
21    If,
22    LocalFunction,
23    Local,
24    TypeAlias,
25    TypeFunction,
26    DeclareGlobal,
27    DeclareFunction,
28    DeclareExternType,
29    Repeat,
30    Return,
31    While,
32    Error,
33}
34
35#[repr(C)]
36#[derive(Debug, PartialEq)]
37pub struct StatementHeader<'ast> {
38    pub tag: StatementTag,
39    pub location: Location,
40    pub has_semicolon: bool,
41    _marker: PhantomData<&'ast ()>,
42}
43
44#[derive(Clone, Copy)]
45pub struct Statement<'ast> {
46    ptr: NonNull<StatementHeader<'ast>>,
47    _marker: PhantomData<&'ast StatementHeader<'ast>>,
48}
49
50impl<'ast> std::ops::Deref for Statement<'ast> {
51    type Target = StatementHeader<'ast>;
52
53    fn deref(&self) -> &Self::Target {
54        self.header()
55    }
56}
57
58impl fmt::Debug for Statement<'_> {
59    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
60        match self.tag {
61            StatementTag::Block => fmt::Debug::fmt(&self.as_block_unchecked(), formatter),
62            StatementTag::Assign => fmt::Debug::fmt(self.as_assign_unchecked(), formatter),
63            StatementTag::CompoundAssign => {
64                fmt::Debug::fmt(self.as_compound_assign_unchecked(), formatter)
65            }
66            StatementTag::Break | StatementTag::Continue => formatter
67                .debug_struct("StatementUnit")
68                .field("tag", &self.tag)
69                .field("location", &self.location)
70                .field("has_semicolon", &self.has_semicolon)
71                .finish(),
72            StatementTag::Class => fmt::Debug::fmt(self.as_class_unchecked(), formatter),
73            StatementTag::Expression => fmt::Debug::fmt(self.as_expression_unchecked(), formatter),
74            StatementTag::NumericFor => fmt::Debug::fmt(self.as_numeric_for_unchecked(), formatter),
75            StatementTag::GenericFor => fmt::Debug::fmt(self.as_generic_for_unchecked(), formatter),
76            StatementTag::FunctionDeclaration => {
77                fmt::Debug::fmt(self.as_function_declaration_unchecked(), formatter)
78            }
79            StatementTag::If => fmt::Debug::fmt(self.as_if_unchecked(), formatter),
80            StatementTag::LocalFunction => {
81                fmt::Debug::fmt(self.as_local_function_unchecked(), formatter)
82            }
83            StatementTag::Local => fmt::Debug::fmt(self.as_local_unchecked(), formatter),
84            StatementTag::TypeAlias => fmt::Debug::fmt(self.as_type_alias_unchecked(), formatter),
85            StatementTag::TypeFunction => {
86                fmt::Debug::fmt(self.as_type_function_unchecked(), formatter)
87            }
88            StatementTag::DeclareGlobal => {
89                fmt::Debug::fmt(self.as_declare_global_unchecked(), formatter)
90            }
91            StatementTag::DeclareFunction => {
92                fmt::Debug::fmt(self.as_declare_function_unchecked(), formatter)
93            }
94            StatementTag::DeclareExternType => {
95                fmt::Debug::fmt(self.as_declare_extern_type_unchecked(), formatter)
96            }
97            StatementTag::Repeat => fmt::Debug::fmt(self.as_repeat_unchecked(), formatter),
98            StatementTag::Return => fmt::Debug::fmt(self.as_return_unchecked(), formatter),
99            StatementTag::While => fmt::Debug::fmt(self.as_while_unchecked(), formatter),
100            StatementTag::Error => fmt::Debug::fmt(self.as_error_unchecked(), formatter),
101        }
102    }
103}
104
105impl PartialEq for Statement<'_> {
106    fn eq(&self, other: &Self) -> bool {
107        match (self.tag, other.tag) {
108            (StatementTag::Block, StatementTag::Block) => self.as_block() == other.as_block(),
109            (StatementTag::Assign, StatementTag::Assign) => self.as_assign() == other.as_assign(),
110            (StatementTag::CompoundAssign, StatementTag::CompoundAssign) => {
111                self.as_compound_assign() == other.as_compound_assign()
112            }
113            (StatementTag::Break, StatementTag::Break)
114            | (StatementTag::Continue, StatementTag::Continue) => {
115                self.location == other.location && self.has_semicolon == other.has_semicolon
116            }
117            (StatementTag::Class, StatementTag::Class) => self.as_class() == other.as_class(),
118            (StatementTag::Expression, StatementTag::Expression) => {
119                self.as_expression() == other.as_expression()
120            }
121            (StatementTag::NumericFor, StatementTag::NumericFor) => {
122                self.as_numeric_for() == other.as_numeric_for()
123            }
124            (StatementTag::GenericFor, StatementTag::GenericFor) => {
125                self.as_generic_for() == other.as_generic_for()
126            }
127            (StatementTag::FunctionDeclaration, StatementTag::FunctionDeclaration) => {
128                self.as_function_declaration() == other.as_function_declaration()
129            }
130            (StatementTag::If, StatementTag::If) => self.as_if() == other.as_if(),
131            (StatementTag::LocalFunction, StatementTag::LocalFunction) => {
132                self.as_local_function() == other.as_local_function()
133            }
134            (StatementTag::Local, StatementTag::Local) => self.as_local() == other.as_local(),
135            (StatementTag::TypeAlias, StatementTag::TypeAlias) => {
136                self.as_type_alias() == other.as_type_alias()
137            }
138            (StatementTag::TypeFunction, StatementTag::TypeFunction) => {
139                self.as_type_function() == other.as_type_function()
140            }
141            (StatementTag::DeclareGlobal, StatementTag::DeclareGlobal) => {
142                self.as_declare_global() == other.as_declare_global()
143            }
144            (StatementTag::DeclareFunction, StatementTag::DeclareFunction) => {
145                self.as_declare_function() == other.as_declare_function()
146            }
147            (StatementTag::DeclareExternType, StatementTag::DeclareExternType) => {
148                self.as_declare_extern_type() == other.as_declare_extern_type()
149            }
150            (StatementTag::Repeat, StatementTag::Repeat) => self.as_repeat() == other.as_repeat(),
151            (StatementTag::Return, StatementTag::Return) => self.as_return() == other.as_return(),
152            (StatementTag::While, StatementTag::While) => self.as_while() == other.as_while(),
153            (StatementTag::Error, StatementTag::Error) => self.as_error() == other.as_error(),
154            _ => false,
155        }
156    }
157}
158
159#[repr(C)]
160pub(crate) struct BlockNode<'ast> {
161    pub base: StatementHeader<'ast>,
162    pub statements: &'ast [Statement<'ast>],
163    pub has_end: bool,
164}
165
166#[derive(Clone, Copy)]
167pub struct Block<'ast> {
168    ptr: NonNull<BlockNode<'ast>>,
169    _marker: PhantomData<&'ast BlockNode<'ast>>,
170}
171
172impl fmt::Debug for Block<'_> {
173    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
174        formatter
175            .debug_struct("Block")
176            .field("location", &self.location())
177            .field("has_semicolon", &self.has_semicolon())
178            .field("has_end", &self.has_end())
179            .field("statements", &self.as_slice())
180            .finish()
181    }
182}
183
184impl PartialEq for Block<'_> {
185    fn eq(&self, other: &Self) -> bool {
186        self.location() == other.location()
187            && self.has_semicolon() == other.has_semicolon()
188            && self.has_end() == other.has_end()
189            && self.as_slice() == other.as_slice()
190    }
191}
192
193impl<'ast> Block<'ast> {
194    pub(crate) fn from_node(node: &'ast mut BlockNode<'ast>) -> Self {
195        Self {
196            ptr: NonNull::from(node),
197            _marker: PhantomData,
198        }
199    }
200
201    #[inline(always)]
202    fn node(&self) -> &BlockNode<'ast> {
203        unsafe { self.ptr.as_ref() }
204    }
205
206    pub fn as_statement(self) -> Statement<'ast> {
207        Statement {
208            ptr: self.ptr.cast(),
209            _marker: PhantomData,
210        }
211    }
212
213    pub fn location(self) -> Location {
214        self.node().base.location
215    }
216
217    pub fn has_semicolon(self) -> bool {
218        self.node().base.has_semicolon
219    }
220
221    pub fn has_end(self) -> bool {
222        self.node().has_end
223    }
224
225    pub fn as_slice(self) -> &'ast [Statement<'ast>] {
226        self.node().statements
227    }
228
229    pub fn len(self) -> usize {
230        self.as_slice().len()
231    }
232
233    pub fn is_empty(self) -> bool {
234        self.as_slice().is_empty()
235    }
236
237    pub fn first(self) -> Option<Statement<'ast>> {
238        self.as_slice().first().copied()
239    }
240
241    pub fn visit<V: AstVisitor>(self, visitor: &mut V) {
242        if !visitor.visit_block(self) {
243            return;
244        }
245
246        visit_statements(self.as_slice(), visitor);
247    }
248}
249
250impl<'ast> BlockNode<'ast> {
251    pub(crate) fn new(
252        statements: &'ast [Statement<'ast>],
253        has_end: bool,
254        location: Location,
255    ) -> Self {
256        Self {
257            base: Statement::new_header(StatementTag::Block, location, false),
258            statements,
259            has_end,
260        }
261    }
262}
263
264impl<'ast> std::ops::Index<usize> for Block<'ast> {
265    type Output = Statement<'ast>;
266
267    fn index(&self, index: usize) -> &Self::Output {
268        &self.node().statements[index]
269    }
270}
271
272impl<'a, 'ast> IntoIterator for &'a Block<'ast> {
273    type Item = Statement<'ast>;
274    type IntoIter = std::iter::Copied<std::slice::Iter<'a, Statement<'ast>>>;
275
276    fn into_iter(self) -> Self::IntoIter {
277        self.as_slice().iter().copied()
278    }
279}
280
281macro_rules! stmt_node {
282    ($name:ident { $($field:ident : $ty:ty),* $(,)? }, $tag:ident) => {
283        #[repr(C)]
284        pub struct $name<'ast> {
285            pub base: StatementHeader<'ast>,
286            $(pub $field: $ty),*
287        }
288
289        impl fmt::Debug for $name<'_> {
290            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
291                let mut debug = formatter.debug_struct(stringify!($name));
292                debug
293                    .field("location", &self.location())
294                    .field("has_semicolon", &self.has_semicolon());
295                $(debug.field(stringify!($field), &self.$field);)*
296                debug.finish()
297            }
298        }
299
300        impl PartialEq for $name<'_> {
301            fn eq(&self, other: &Self) -> bool {
302                self.location() == other.location()
303                    && self.has_semicolon() == other.has_semicolon()
304                    $(&& self.$field == other.$field)*
305            }
306        }
307
308        impl<'ast> $name<'ast> {
309            // AST node constructors mirror the concrete node fields; grouping
310            // those fields would hide the source-shaped node layout.
311            #[allow(clippy::too_many_arguments)]
312            pub fn new(location: Location, has_semicolon: bool, $($field: $ty),*) -> Self {
313                Self {
314                    base: Statement::new_header(StatementTag::$tag, location, has_semicolon),
315                    $($field),*
316                }
317            }
318
319            pub fn location(&self) -> Location {
320                self.base.location
321            }
322
323            pub fn has_semicolon(&self) -> bool {
324                self.base.has_semicolon
325            }
326        }
327    };
328}
329
330#[repr(C)]
331pub struct StatementUnit<'ast> {
332    pub base: StatementHeader<'ast>,
333}
334
335impl<'ast> StatementUnit<'ast> {
336    pub fn new(tag: StatementTag, location: Location, has_semicolon: bool) -> Self {
337        Self {
338            base: Statement::new_header(tag, location, has_semicolon),
339        }
340    }
341}
342
343impl fmt::Debug for StatementUnit<'_> {
344    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
345        formatter
346            .debug_struct("StatementUnit")
347            .field("tag", &self.base.tag)
348            .field("location", &self.base.location)
349            .field("has_semicolon", &self.base.has_semicolon)
350            .finish()
351    }
352}
353
354impl PartialEq for StatementUnit<'_> {
355    fn eq(&self, other: &Self) -> bool {
356        self.base.tag == other.base.tag
357            && self.base.location == other.base.location
358            && self.base.has_semicolon == other.base.has_semicolon
359    }
360}
361
362stmt_node!(StatementAssign {
363    vars: &'ast [Expression<'ast>],
364    values: &'ast [Expression<'ast>]
365}, Assign);
366stmt_node!(StatementCompoundAssign {
367    var: Expression<'ast>,
368    op: BinaryOp,
369    value: Expression<'ast>
370}, CompoundAssign);
371stmt_node!(StatementClass {
372    name: &'ast Local<'ast>,
373    super_class: Option<Expression<'ast>>,
374    members: &'ast [ClassMember<'ast>],
375    exported: bool
376}, Class);
377stmt_node!(StatementExpression {
378    expr: Expression<'ast>
379}, Expression);
380stmt_node!(StatementNumericFor {
381    name: &'ast Local<'ast>,
382    start: Expression<'ast>,
383    limit: Expression<'ast>,
384    step: Option<Expression<'ast>>,
385    body: Block<'ast>,
386    has_do: bool,
387    do_location: Location
388}, NumericFor);
389stmt_node!(StatementGenericFor {
390    names: &'ast [&'ast Local<'ast>],
391    values: &'ast [Expression<'ast>],
392    body: Block<'ast>,
393    has_in: bool,
394    in_location: Location,
395    has_do: bool,
396    do_location: Location
397}, GenericFor);
398stmt_node!(StatementFunctionDeclaration {
399    name: Expression<'ast>,
400    function: &'ast Function<'ast>
401}, FunctionDeclaration);
402stmt_node!(StatementIf {
403    condition: Expression<'ast>,
404    then_body: Block<'ast>,
405    else_body: Option<Statement<'ast>>,
406    then_location: Option<Location>,
407    else_location: Option<Location>
408}, If);
409stmt_node!(StatementLocalFunction {
410    name: &'ast Local<'ast>,
411    function: &'ast Function<'ast>,
412    is_const: bool,
413    const_keyword_begin: Position
414}, LocalFunction);
415stmt_node!(StatementLocal {
416    bindings: &'ast [&'ast Local<'ast>],
417    values: &'ast [Expression<'ast>],
418    keyword_location: Option<Location>,
419    equals_sign_location: Option<Location>,
420    is_const: bool,
421    is_exported: bool
422}, Local);
423stmt_node!(StatementTypeAlias {
424    name: AstName<'ast>,
425    name_location: Location,
426    generics: &'ast [&'ast GenericType<'ast>],
427    generic_packs: &'ast [&'ast GenericTypePack<'ast>],
428    exported: bool,
429    ty: Type<'ast>
430}, TypeAlias);
431stmt_node!(StatementTypeFunction {
432    name: AstName<'ast>,
433    name_location: Location,
434    exported: bool,
435    body: &'ast Function<'ast>,
436    has_errors: bool
437}, TypeFunction);
438stmt_node!(StatementDeclareGlobal {
439    name: AstName<'ast>,
440    name_location: Location,
441    ty: Type<'ast>
442}, DeclareGlobal);
443stmt_node!(StatementDeclareFunction {
444    name: AstName<'ast>,
445    name_location: Location,
446    params: TypeList<'ast>,
447    param_names: &'ast [ArgumentName<'ast>],
448    variadic: bool,
449    vararg_location: Location,
450    generics: &'ast [&'ast GenericType<'ast>],
451    generic_packs: &'ast [&'ast GenericTypePack<'ast>],
452    return_types: TypePack<'ast>,
453    attributes: &'ast [&'ast Attribute<'ast>]
454}, DeclareFunction);
455stmt_node!(StatementDeclareExternType {
456    name: AstName<'ast>,
457    super_name: Option<AstName<'ast>>,
458    props: &'ast [DeclaredExternTypeProperty<'ast>],
459    indexer: Option<&'ast TableTypeIndexer<'ast>>
460}, DeclareExternType);
461stmt_node!(StatementRepeat {
462    body: Block<'ast>,
463    condition: Expression<'ast>
464}, Repeat);
465stmt_node!(StatementReturn {
466    expressions: &'ast [Expression<'ast>]
467}, Return);
468stmt_node!(StatementWhile {
469    condition: Expression<'ast>,
470    body: Block<'ast>,
471    has_do: bool,
472    do_location: Location
473}, While);
474stmt_node!(StatementError {
475    expressions: &'ast [Expression<'ast>],
476    statements: &'ast [Statement<'ast>],
477    message_index: usize
478}, Error);
479
480impl<'ast> Statement<'ast> {
481    pub const fn new_header(
482        tag: StatementTag,
483        location: Location,
484        has_semicolon: bool,
485    ) -> StatementHeader<'ast> {
486        StatementHeader {
487            tag,
488            location,
489            has_semicolon,
490            _marker: PhantomData,
491        }
492    }
493
494    pub(crate) fn from_node<T>(node: &'ast mut T) -> Self {
495        Self {
496            ptr: NonNull::from(node).cast(),
497            _marker: PhantomData,
498        }
499    }
500
501    pub fn as_ptr(self) -> *const () {
502        self.ptr.as_ptr().cast()
503    }
504
505    #[inline(always)]
506    fn header(&self) -> &StatementHeader<'ast> {
507        unsafe { self.ptr.as_ref() }
508    }
509
510    #[inline(always)]
511    fn header_mut(&mut self) -> &mut StatementHeader<'ast> {
512        unsafe { self.ptr.as_mut() }
513    }
514
515    #[inline(always)]
516    pub fn location(self) -> Location {
517        self.header().location
518    }
519
520    #[inline(always)]
521    pub fn has_semicolon(self) -> bool {
522        self.header().has_semicolon
523    }
524
525    pub fn is_checked_declare_function(&self) -> bool {
526        self.has_declare_function_attribute(AttributeKind::Checked)
527    }
528
529    pub fn has_declare_function_attribute(&self, kind: AttributeKind) -> bool {
530        self.get_declare_function_attribute(kind).is_some()
531    }
532
533    pub fn get_declare_function_attribute(&self, kind: AttributeKind) -> Option<&Attribute<'ast>> {
534        self.as_declare_function()
535            .and_then(|statement| find_attribute(statement.attributes, kind))
536    }
537
538    pub fn as_block(self) -> Option<Block<'ast>> {
539        (self.tag == StatementTag::Block).then(|| Block {
540            ptr: self.ptr.cast(),
541            _marker: PhantomData,
542        })
543    }
544
545    #[inline(always)]
546    pub(crate) fn as_block_unchecked(self) -> Block<'ast> {
547        debug_assert_eq!(self.tag, StatementTag::Block);
548        Block {
549            ptr: self.ptr.cast(),
550            _marker: PhantomData,
551        }
552    }
553
554    pub(crate) fn set_semicolon(mut self, location: Location) {
555        let header = self.header_mut();
556        header.has_semicolon = true;
557        header.location.end = location.end;
558    }
559
560    pub fn visit<V: AstVisitor>(self, visitor: &mut V) {
561        match self.tag {
562            StatementTag::Block => self.as_block_unchecked().visit(visitor),
563            StatementTag::Assign => {
564                let node = self.as_assign_unchecked();
565                if !visitor.visit_assign_statement(self) {
566                    return;
567                }
568                visit_expressions(node.vars, visitor);
569                visit_expressions(node.values, visitor);
570            }
571            StatementTag::CompoundAssign => {
572                let node = self.as_compound_assign_unchecked();
573                if !visitor.visit_compound_assign_statement(self) {
574                    return;
575                }
576                node.var.visit(visitor);
577                node.value.visit(visitor);
578            }
579            StatementTag::Break => {
580                let _ = visitor.visit_break_statement(self);
581            }
582            StatementTag::Continue => {
583                let _ = visitor.visit_continue_statement(self);
584            }
585            StatementTag::Class => {
586                let node = self.as_class_unchecked();
587                if !visitor.visit_class_statement(self) {
588                    return;
589                }
590                if let Some(super_class) = node.super_class {
591                    super_class.visit(visitor);
592                }
593                for member in node.members {
594                    member.visit(visitor);
595                }
596            }
597            StatementTag::Expression => {
598                let node = self.as_expression_unchecked();
599                if !visitor.visit_expression_statement(self) {
600                    return;
601                }
602                node.expr.visit(visitor);
603            }
604            StatementTag::NumericFor => {
605                let node = self.as_numeric_for_unchecked();
606                if !visitor.visit_numeric_for_statement(self) {
607                    return;
608                }
609                node.name.visit(visitor);
610                node.start.visit(visitor);
611                node.limit.visit(visitor);
612                if let Some(step) = node.step {
613                    step.visit(visitor);
614                }
615                node.body.visit(visitor);
616            }
617            StatementTag::GenericFor => {
618                let node = self.as_generic_for_unchecked();
619                if !visitor.visit_generic_for_statement(self) {
620                    return;
621                }
622                for name in node.names {
623                    name.visit(visitor);
624                }
625                visit_expressions(node.values, visitor);
626                node.body.visit(visitor);
627            }
628            StatementTag::FunctionDeclaration => {
629                let node = self.as_function_declaration_unchecked();
630                if !visitor.visit_function_declaration_statement(self) {
631                    return;
632                }
633                node.name.visit(visitor);
634                node.function.visit(visitor);
635            }
636            StatementTag::If => {
637                let node = self.as_if_unchecked();
638                if !visitor.visit_if_statement(self) {
639                    return;
640                }
641                node.condition.visit(visitor);
642                node.then_body.visit(visitor);
643                if let Some(else_body) = node.else_body {
644                    else_body.visit(visitor);
645                }
646            }
647            StatementTag::LocalFunction => {
648                let node = self.as_local_function_unchecked();
649                if !visitor.visit_local_function_statement(self) {
650                    return;
651                }
652                node.function.visit(visitor);
653            }
654            StatementTag::TypeFunction => {
655                let node = self.as_type_function_unchecked();
656                if !visitor.visit_type_function_statement(self) {
657                    return;
658                }
659                node.body.visit(visitor);
660            }
661            StatementTag::Local => {
662                let node = self.as_local_unchecked();
663                if !visitor.visit_local_statement(self) {
664                    return;
665                }
666                for binding in node.bindings {
667                    binding.visit(visitor);
668                }
669                visit_expressions(node.values, visitor);
670            }
671            StatementTag::TypeAlias => {
672                let node = self.as_type_alias_unchecked();
673                if !visitor.visit_type_alias_statement(self) {
674                    return;
675                }
676                for generic in node.generics {
677                    generic.visit(visitor);
678                }
679                for generic_pack in node.generic_packs {
680                    generic_pack.visit(visitor);
681                }
682                node.ty.visit(visitor);
683            }
684            StatementTag::DeclareGlobal => {
685                let node = self.as_declare_global_unchecked();
686                if !visitor.visit_declare_global_statement(self) {
687                    return;
688                }
689                node.ty.visit(visitor);
690            }
691            StatementTag::DeclareFunction => {
692                let node = self.as_declare_function_unchecked();
693                if !visitor.visit_declare_function_statement(self) {
694                    return;
695                }
696                node.params.visit(visitor);
697                node.return_types.visit(visitor);
698            }
699            StatementTag::DeclareExternType => {
700                let node = self.as_declare_extern_type_unchecked();
701                if !visitor.visit_declare_extern_type_statement(self) {
702                    return;
703                }
704                for prop in node.props {
705                    prop.ty.visit(visitor);
706                }
707                if let Some(indexer) = node.indexer {
708                    indexer.index_type.visit(visitor);
709                    indexer.result_type.visit(visitor);
710                }
711            }
712            StatementTag::Repeat => {
713                let node = self.as_repeat_unchecked();
714                if !visitor.visit_repeat_statement(self) {
715                    return;
716                }
717                node.body.visit(visitor);
718                node.condition.visit(visitor);
719            }
720            StatementTag::Return => {
721                let node = self.as_return_unchecked();
722                if !visitor.visit_return_statement(self) {
723                    return;
724                }
725                visit_expressions(node.expressions, visitor);
726            }
727            StatementTag::While => {
728                let node = self.as_while_unchecked();
729                if !visitor.visit_while_statement(self) {
730                    return;
731                }
732                node.condition.visit(visitor);
733                node.body.visit(visitor);
734            }
735            StatementTag::Error => {
736                let node = self.as_error_unchecked();
737                if !visitor.visit_error_statement(self) {
738                    return;
739                }
740                visit_expressions(node.expressions, visitor);
741                visit_statements(node.statements, visitor);
742            }
743        }
744    }
745
746    #[inline(always)]
747    fn cast_ref<T>(self) -> &'ast T {
748        unsafe { self.ptr.cast::<T>().as_ref() }
749    }
750
751    #[inline(always)]
752    fn cast_if_tag<T>(self, tag: StatementTag) -> Option<&'ast T> {
753        (self.tag == tag).then(|| self.cast_ref())
754    }
755
756    #[inline(always)]
757    fn cast_unchecked<T>(self, tag: StatementTag) -> &'ast T {
758        debug_assert_eq!(self.tag, tag);
759        self.cast_ref()
760    }
761
762    #[inline(always)]
763    pub fn as_assign(self) -> Option<&'ast StatementAssign<'ast>> {
764        self.cast_if_tag(StatementTag::Assign)
765    }
766
767    #[inline(always)]
768    pub(crate) fn as_assign_unchecked(self) -> &'ast StatementAssign<'ast> {
769        self.cast_unchecked(StatementTag::Assign)
770    }
771
772    #[inline(always)]
773    pub fn as_compound_assign(self) -> Option<&'ast StatementCompoundAssign<'ast>> {
774        self.cast_if_tag(StatementTag::CompoundAssign)
775    }
776
777    #[inline(always)]
778    pub(crate) fn as_compound_assign_unchecked(self) -> &'ast StatementCompoundAssign<'ast> {
779        self.cast_unchecked(StatementTag::CompoundAssign)
780    }
781
782    #[inline(always)]
783    pub fn as_class(self) -> Option<&'ast StatementClass<'ast>> {
784        self.cast_if_tag(StatementTag::Class)
785    }
786
787    #[inline(always)]
788    pub(crate) fn as_class_unchecked(self) -> &'ast StatementClass<'ast> {
789        self.cast_unchecked(StatementTag::Class)
790    }
791
792    #[inline(always)]
793    pub fn as_expression(self) -> Option<&'ast StatementExpression<'ast>> {
794        self.cast_if_tag(StatementTag::Expression)
795    }
796
797    #[inline(always)]
798    pub(crate) fn as_expression_unchecked(self) -> &'ast StatementExpression<'ast> {
799        self.cast_unchecked(StatementTag::Expression)
800    }
801
802    #[inline(always)]
803    pub fn as_numeric_for(self) -> Option<&'ast StatementNumericFor<'ast>> {
804        self.cast_if_tag(StatementTag::NumericFor)
805    }
806
807    #[inline(always)]
808    pub(crate) fn as_numeric_for_unchecked(self) -> &'ast StatementNumericFor<'ast> {
809        self.cast_unchecked(StatementTag::NumericFor)
810    }
811
812    #[inline(always)]
813    pub fn as_generic_for(self) -> Option<&'ast StatementGenericFor<'ast>> {
814        self.cast_if_tag(StatementTag::GenericFor)
815    }
816
817    #[inline(always)]
818    pub(crate) fn as_generic_for_unchecked(self) -> &'ast StatementGenericFor<'ast> {
819        self.cast_unchecked(StatementTag::GenericFor)
820    }
821
822    #[inline(always)]
823    pub fn as_function_declaration(self) -> Option<&'ast StatementFunctionDeclaration<'ast>> {
824        self.cast_if_tag(StatementTag::FunctionDeclaration)
825    }
826
827    #[inline(always)]
828    pub(crate) fn as_function_declaration_unchecked(
829        self,
830    ) -> &'ast StatementFunctionDeclaration<'ast> {
831        self.cast_unchecked(StatementTag::FunctionDeclaration)
832    }
833
834    #[inline(always)]
835    pub fn as_if(self) -> Option<&'ast StatementIf<'ast>> {
836        self.cast_if_tag(StatementTag::If)
837    }
838
839    #[inline(always)]
840    pub(crate) fn as_if_unchecked(self) -> &'ast StatementIf<'ast> {
841        self.cast_unchecked(StatementTag::If)
842    }
843
844    #[inline(always)]
845    pub fn as_local_function(self) -> Option<&'ast StatementLocalFunction<'ast>> {
846        self.cast_if_tag(StatementTag::LocalFunction)
847    }
848
849    #[inline(always)]
850    pub(crate) fn as_local_function_unchecked(self) -> &'ast StatementLocalFunction<'ast> {
851        self.cast_unchecked(StatementTag::LocalFunction)
852    }
853
854    #[inline(always)]
855    pub fn as_local(self) -> Option<&'ast StatementLocal<'ast>> {
856        self.cast_if_tag(StatementTag::Local)
857    }
858
859    #[inline(always)]
860    pub(crate) fn as_local_unchecked(self) -> &'ast StatementLocal<'ast> {
861        self.cast_unchecked(StatementTag::Local)
862    }
863
864    #[inline(always)]
865    pub fn as_type_alias(self) -> Option<&'ast StatementTypeAlias<'ast>> {
866        self.cast_if_tag(StatementTag::TypeAlias)
867    }
868
869    #[inline(always)]
870    pub(crate) fn as_type_alias_unchecked(self) -> &'ast StatementTypeAlias<'ast> {
871        self.cast_unchecked(StatementTag::TypeAlias)
872    }
873
874    #[inline(always)]
875    pub fn as_type_function(self) -> Option<&'ast StatementTypeFunction<'ast>> {
876        self.cast_if_tag(StatementTag::TypeFunction)
877    }
878
879    #[inline(always)]
880    pub(crate) fn as_type_function_unchecked(self) -> &'ast StatementTypeFunction<'ast> {
881        self.cast_unchecked(StatementTag::TypeFunction)
882    }
883
884    #[inline(always)]
885    pub fn as_declare_global(self) -> Option<&'ast StatementDeclareGlobal<'ast>> {
886        self.cast_if_tag(StatementTag::DeclareGlobal)
887    }
888
889    #[inline(always)]
890    pub(crate) fn as_declare_global_unchecked(self) -> &'ast StatementDeclareGlobal<'ast> {
891        self.cast_unchecked(StatementTag::DeclareGlobal)
892    }
893
894    #[inline(always)]
895    pub fn as_declare_function(self) -> Option<&'ast StatementDeclareFunction<'ast>> {
896        self.cast_if_tag(StatementTag::DeclareFunction)
897    }
898
899    #[inline(always)]
900    pub(crate) fn as_declare_function_unchecked(self) -> &'ast StatementDeclareFunction<'ast> {
901        self.cast_unchecked(StatementTag::DeclareFunction)
902    }
903
904    #[inline(always)]
905    pub fn as_declare_extern_type(self) -> Option<&'ast StatementDeclareExternType<'ast>> {
906        self.cast_if_tag(StatementTag::DeclareExternType)
907    }
908
909    #[inline(always)]
910    pub(crate) fn as_declare_extern_type_unchecked(self) -> &'ast StatementDeclareExternType<'ast> {
911        self.cast_unchecked(StatementTag::DeclareExternType)
912    }
913
914    #[inline(always)]
915    pub fn as_repeat(self) -> Option<&'ast StatementRepeat<'ast>> {
916        self.cast_if_tag(StatementTag::Repeat)
917    }
918
919    #[inline(always)]
920    pub(crate) fn as_repeat_unchecked(self) -> &'ast StatementRepeat<'ast> {
921        self.cast_unchecked(StatementTag::Repeat)
922    }
923
924    #[inline(always)]
925    pub fn as_return(self) -> Option<&'ast StatementReturn<'ast>> {
926        self.cast_if_tag(StatementTag::Return)
927    }
928
929    #[inline(always)]
930    pub(crate) fn as_return_unchecked(self) -> &'ast StatementReturn<'ast> {
931        self.cast_unchecked(StatementTag::Return)
932    }
933
934    #[inline(always)]
935    pub fn as_while(self) -> Option<&'ast StatementWhile<'ast>> {
936        self.cast_if_tag(StatementTag::While)
937    }
938
939    #[inline(always)]
940    pub(crate) fn as_while_unchecked(self) -> &'ast StatementWhile<'ast> {
941        self.cast_unchecked(StatementTag::While)
942    }
943
944    #[inline(always)]
945    pub fn as_error(self) -> Option<&'ast StatementError<'ast>> {
946        self.cast_if_tag(StatementTag::Error)
947    }
948
949    #[inline(always)]
950    pub(crate) fn as_error_unchecked(self) -> &'ast StatementError<'ast> {
951        self.cast_unchecked(StatementTag::Error)
952    }
953}
954
955#[derive(Debug, Clone, Copy, PartialEq)]
956pub enum ClassMember<'ast> {
957    Property {
958        qualifier_location: Location,
959        name: AstName<'ast>,
960        name_location: Location,
961        type_colon_location: Option<Location>,
962        ty: Option<Type<'ast>>,
963    },
964    Method {
965        qualifier_location: Option<Location>,
966        keyword_location: Location,
967        function_name: AstName<'ast>,
968        name_location: Location,
969        function: &'ast Function<'ast>,
970    },
971}
972
973impl ClassMember<'_> {
974    pub fn name(&self) -> AstName<'_> {
975        match self {
976            Self::Property { name, .. } => *name,
977            Self::Method { function_name, .. } => *function_name,
978        }
979    }
980
981    pub fn visit<V: AstVisitor>(&self, visitor: &mut V) {
982        match self {
983            Self::Property { ty, .. } => {
984                if let Some(annotation) = ty {
985                    annotation.visit(visitor);
986                }
987            }
988            Self::Method { function, .. } => function.visit(visitor),
989        }
990    }
991}
992
993impl AstArena {
994    pub(crate) fn alloc_block_node<'ast>(&'ast self, node: BlockNode<'ast>) -> Block<'ast> {
995        Block::from_node(self.alloc(node))
996    }
997
998    pub(crate) fn alloc_statement_node<'ast, T: 'ast>(&'ast self, node: T) -> Statement<'ast> {
999        Statement::from_node(self.alloc(node))
1000    }
1001}