php_parser/ast/
mod.rs

1use crate::lexer::token::Token;
2use crate::span::{LineInfo, Span};
3use serde::Serialize;
4
5pub mod locator;
6pub mod sexpr;
7pub mod symbol_table;
8pub mod visitor;
9
10pub type ExprId<'ast> = &'ast Expr<'ast>;
11pub type StmtId<'ast> = &'ast Stmt<'ast>;
12
13#[derive(Debug, Clone, Copy, Serialize)]
14pub struct ParseError {
15    pub span: Span,
16    pub message: &'static str,
17}
18
19impl ParseError {
20    pub fn to_human_readable(&self, source: &[u8]) -> String {
21        self.to_human_readable_with_path(source, None)
22    }
23
24    pub fn to_human_readable_with_path(&self, source: &[u8], path: Option<&str>) -> String {
25        let Some(LineInfo {
26            line,
27            column,
28            line_text,
29        }) = self.span.line_info(source)
30        else {
31            return format!("error: {}", self.message);
32        };
33
34        let line_str = String::from_utf8_lossy(line_text);
35        let gutter_width = line.to_string().len();
36        let padding = std::cmp::min(line_text.len(), column.saturating_sub(1));
37        let highlight_len = std::cmp::max(
38            1,
39            std::cmp::min(self.span.len(), line_text.len().saturating_sub(padding)),
40        );
41
42        let mut marker = String::new();
43        marker.push_str(&" ".repeat(padding));
44        marker.push_str(&"^".repeat(highlight_len));
45
46        let location = match path {
47            Some(path) => format!("{path}:{line}:{column}"),
48            None => format!("line {line}, column {column}"),
49        };
50
51        format!(
52            "error: {}\n --> {}\n{gutter}|\n{line_no:>width$} | {line_src}\n{gutter}| {marker}",
53            self.message,
54            location,
55            gutter = " ".repeat(gutter_width + 1),
56            line_no = line,
57            width = gutter_width,
58            line_src = line_str,
59            marker = marker,
60        )
61    }
62}
63
64#[derive(Debug, Serialize)]
65pub struct Program<'ast> {
66    pub statements: &'ast [StmtId<'ast>],
67    pub errors: &'ast [ParseError],
68    pub span: Span,
69}
70
71#[derive(Debug, Serialize)]
72pub enum Stmt<'ast> {
73    Echo {
74        exprs: &'ast [ExprId<'ast>],
75        span: Span,
76    },
77    Return {
78        expr: Option<ExprId<'ast>>,
79        span: Span,
80    },
81    If {
82        condition: ExprId<'ast>,
83        then_block: &'ast [StmtId<'ast>],
84        else_block: Option<&'ast [StmtId<'ast>]>, // Simplified: else block is just statements for now
85        span: Span,
86    },
87    While {
88        condition: ExprId<'ast>,
89        body: &'ast [StmtId<'ast>],
90        span: Span,
91    },
92    DoWhile {
93        body: &'ast [StmtId<'ast>],
94        condition: ExprId<'ast>,
95        span: Span,
96    },
97    For {
98        init: &'ast [ExprId<'ast>],
99        condition: &'ast [ExprId<'ast>], // Can be multiple expressions separated by comma, but usually one. PHP allows empty.
100        loop_expr: &'ast [ExprId<'ast>],
101        body: &'ast [StmtId<'ast>],
102        span: Span,
103    },
104    Foreach {
105        expr: ExprId<'ast>,
106        key_var: Option<ExprId<'ast>>,
107        value_var: ExprId<'ast>,
108        body: &'ast [StmtId<'ast>],
109        span: Span,
110    },
111    Block {
112        statements: &'ast [StmtId<'ast>],
113        span: Span,
114    },
115    Function {
116        attributes: &'ast [AttributeGroup<'ast>],
117        name: &'ast Token,
118        by_ref: bool,
119        params: &'ast [Param<'ast>],
120        return_type: Option<&'ast Type<'ast>>,
121        body: &'ast [StmtId<'ast>],
122        doc_comment: Option<Span>,
123        span: Span,
124    },
125    Class {
126        attributes: &'ast [AttributeGroup<'ast>],
127        modifiers: &'ast [Token],
128        name: &'ast Token,
129        extends: Option<Name<'ast>>,
130        implements: &'ast [Name<'ast>],
131        members: &'ast [ClassMember<'ast>],
132        doc_comment: Option<Span>,
133        span: Span,
134    },
135    Interface {
136        attributes: &'ast [AttributeGroup<'ast>],
137        name: &'ast Token,
138        extends: &'ast [Name<'ast>],
139        members: &'ast [ClassMember<'ast>],
140        doc_comment: Option<Span>,
141        span: Span,
142    },
143    Trait {
144        attributes: &'ast [AttributeGroup<'ast>],
145        name: &'ast Token,
146        members: &'ast [ClassMember<'ast>],
147        doc_comment: Option<Span>,
148        span: Span,
149    },
150    Enum {
151        attributes: &'ast [AttributeGroup<'ast>],
152        name: &'ast Token,
153        backed_type: Option<&'ast Type<'ast>>,
154        implements: &'ast [Name<'ast>],
155        members: &'ast [ClassMember<'ast>],
156        doc_comment: Option<Span>,
157        span: Span,
158    },
159    Namespace {
160        name: Option<Name<'ast>>,
161        body: Option<&'ast [StmtId<'ast>]>,
162        span: Span,
163    },
164    Use {
165        uses: &'ast [UseItem<'ast>],
166        kind: UseKind,
167        span: Span,
168    },
169    Switch {
170        condition: ExprId<'ast>,
171        cases: &'ast [Case<'ast>],
172        span: Span,
173    },
174    Try {
175        body: &'ast [StmtId<'ast>],
176        catches: &'ast [Catch<'ast>],
177        finally: Option<&'ast [StmtId<'ast>]>,
178        span: Span,
179    },
180    Throw {
181        expr: ExprId<'ast>,
182        span: Span,
183    },
184    Const {
185        attributes: &'ast [AttributeGroup<'ast>],
186        consts: &'ast [ClassConst<'ast>],
187        doc_comment: Option<Span>,
188        span: Span,
189    },
190    Break {
191        level: Option<ExprId<'ast>>,
192        span: Span,
193    },
194    Continue {
195        level: Option<ExprId<'ast>>,
196        span: Span,
197    },
198    Global {
199        vars: &'ast [ExprId<'ast>],
200        span: Span,
201    },
202    Static {
203        vars: &'ast [StaticVar<'ast>],
204        span: Span,
205    },
206    Unset {
207        vars: &'ast [ExprId<'ast>],
208        span: Span,
209    },
210    Expression {
211        expr: ExprId<'ast>,
212        span: Span,
213    },
214    InlineHtml {
215        value: &'ast [u8],
216        span: Span,
217    },
218    Nop {
219        span: Span,
220    },
221    Label {
222        name: &'ast Token,
223        span: Span,
224    },
225    Goto {
226        label: &'ast Token,
227        span: Span,
228    },
229    Error {
230        span: Span,
231    },
232    Declare {
233        declares: &'ast [DeclareItem<'ast>],
234        body: &'ast [StmtId<'ast>],
235        span: Span,
236    },
237    HaltCompiler {
238        span: Span,
239    },
240}
241
242#[derive(Debug, Clone, Copy, Serialize)]
243pub struct StaticVar<'ast> {
244    pub var: ExprId<'ast>,
245    pub default: Option<ExprId<'ast>>,
246    pub span: Span,
247}
248
249#[derive(Debug, Clone, Copy, Serialize)]
250pub struct Param<'ast> {
251    pub attributes: &'ast [AttributeGroup<'ast>],
252    pub modifiers: &'ast [Token],
253    pub name: &'ast Token,
254    pub ty: Option<&'ast Type<'ast>>,
255    pub default: Option<ExprId<'ast>>,
256    pub by_ref: bool,
257    pub variadic: bool,
258    pub hooks: Option<&'ast [PropertyHook<'ast>]>,
259    pub span: Span,
260}
261
262#[derive(Debug, Serialize)]
263pub enum Expr<'ast> {
264    Assign {
265        var: ExprId<'ast>,
266        expr: ExprId<'ast>,
267        span: Span,
268    },
269    AssignRef {
270        var: ExprId<'ast>,
271        expr: ExprId<'ast>,
272        span: Span,
273    },
274    AssignOp {
275        var: ExprId<'ast>,
276        op: AssignOp,
277        expr: ExprId<'ast>,
278        span: Span,
279    },
280    Binary {
281        left: ExprId<'ast>,
282        op: BinaryOp,
283        right: ExprId<'ast>,
284        span: Span,
285    },
286    Unary {
287        op: UnaryOp,
288        expr: ExprId<'ast>,
289        span: Span,
290    },
291    Call {
292        func: ExprId<'ast>,
293        args: &'ast [Arg<'ast>],
294        span: Span,
295    },
296    Array {
297        items: &'ast [ArrayItem<'ast>],
298        span: Span,
299    },
300    ArrayDimFetch {
301        array: ExprId<'ast>,
302        dim: Option<ExprId<'ast>>, // None for $a[]
303        span: Span,
304    },
305    PropertyFetch {
306        target: ExprId<'ast>,
307        property: ExprId<'ast>, // Usually Identifier or Variable
308        span: Span,
309    },
310    MethodCall {
311        target: ExprId<'ast>,
312        method: ExprId<'ast>,
313        args: &'ast [Arg<'ast>],
314        span: Span,
315    },
316    StaticCall {
317        class: ExprId<'ast>,
318        method: ExprId<'ast>,
319        args: &'ast [Arg<'ast>],
320        span: Span,
321    },
322    ClassConstFetch {
323        class: ExprId<'ast>,
324        constant: ExprId<'ast>,
325        span: Span,
326    },
327    New {
328        class: ExprId<'ast>,
329        args: &'ast [Arg<'ast>],
330        span: Span,
331    },
332    Variable {
333        name: Span,
334        span: Span,
335    },
336    IndirectVariable {
337        name: ExprId<'ast>,
338        span: Span,
339    },
340    Integer {
341        value: &'ast [u8],
342        span: Span,
343    },
344    Float {
345        value: &'ast [u8],
346        span: Span,
347    },
348    Boolean {
349        value: bool,
350        span: Span,
351    },
352    Null {
353        span: Span,
354    },
355    String {
356        value: &'ast [u8],
357        span: Span,
358    },
359    InterpolatedString {
360        parts: &'ast [ExprId<'ast>],
361        span: Span,
362    },
363    ShellExec {
364        parts: &'ast [ExprId<'ast>],
365        span: Span,
366    },
367    Include {
368        kind: IncludeKind,
369        expr: ExprId<'ast>,
370        span: Span,
371    },
372    MagicConst {
373        kind: MagicConstKind,
374        span: Span,
375    },
376    PostInc {
377        var: ExprId<'ast>,
378        span: Span,
379    },
380    PostDec {
381        var: ExprId<'ast>,
382        span: Span,
383    },
384    Ternary {
385        condition: ExprId<'ast>,
386        if_true: Option<ExprId<'ast>>,
387        if_false: ExprId<'ast>,
388        span: Span,
389    },
390    Match {
391        condition: ExprId<'ast>,
392        arms: &'ast [MatchArm<'ast>],
393        span: Span,
394    },
395    AnonymousClass {
396        attributes: &'ast [AttributeGroup<'ast>],
397        modifiers: &'ast [Token],
398        args: &'ast [Arg<'ast>],
399        extends: Option<Name<'ast>>,
400        implements: &'ast [Name<'ast>],
401        members: &'ast [ClassMember<'ast>],
402        span: Span,
403    },
404    Print {
405        expr: ExprId<'ast>,
406        span: Span,
407    },
408    Yield {
409        key: Option<ExprId<'ast>>,
410        value: Option<ExprId<'ast>>,
411        from: bool,
412        span: Span,
413    },
414    Cast {
415        kind: CastKind,
416        expr: ExprId<'ast>,
417        span: Span,
418    },
419    Empty {
420        expr: ExprId<'ast>,
421        span: Span,
422    },
423    Isset {
424        vars: &'ast [ExprId<'ast>],
425        span: Span,
426    },
427    Eval {
428        expr: ExprId<'ast>,
429        span: Span,
430    },
431    Die {
432        expr: Option<ExprId<'ast>>,
433        span: Span,
434    },
435    Exit {
436        expr: Option<ExprId<'ast>>,
437        span: Span,
438    },
439    Closure {
440        attributes: &'ast [AttributeGroup<'ast>],
441        is_static: bool,
442        by_ref: bool,
443        params: &'ast [Param<'ast>],
444        uses: &'ast [ClosureUse<'ast>],
445        return_type: Option<&'ast Type<'ast>>,
446        body: &'ast [StmtId<'ast>],
447        span: Span,
448    },
449    ArrowFunction {
450        attributes: &'ast [AttributeGroup<'ast>],
451        is_static: bool,
452        by_ref: bool,
453        params: &'ast [Param<'ast>],
454        return_type: Option<&'ast Type<'ast>>,
455        expr: ExprId<'ast>,
456        span: Span,
457    },
458    Clone {
459        expr: ExprId<'ast>,
460        span: Span,
461    },
462    NullsafePropertyFetch {
463        target: ExprId<'ast>,
464        property: ExprId<'ast>,
465        span: Span,
466    },
467    NullsafeMethodCall {
468        target: ExprId<'ast>,
469        method: ExprId<'ast>,
470        args: &'ast [Arg<'ast>],
471        span: Span,
472    },
473    VariadicPlaceholder {
474        span: Span,
475    },
476    Error {
477        span: Span,
478    },
479}
480
481#[derive(Debug, Clone, Copy, Serialize)]
482pub struct ClosureUse<'ast> {
483    pub var: &'ast Token,
484    pub by_ref: bool,
485    pub span: Span,
486}
487
488#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
489pub enum CastKind {
490    Int,
491    Bool,
492    Float,
493    String,
494    Array,
495    Object,
496    Unset,
497    Void,
498}
499
500#[derive(Debug, Clone, Copy, Serialize)]
501pub struct MatchArm<'ast> {
502    pub conditions: Option<&'ast [ExprId<'ast>]>, // None for default
503    pub body: ExprId<'ast>,
504    pub span: Span,
505}
506
507#[derive(Debug, Clone, Copy, Serialize)]
508pub struct AnonymousClass<'ast> {
509    pub args: &'ast [Arg<'ast>],
510    pub extends: Option<Name<'ast>>,
511    pub implements: &'ast [Name<'ast>],
512    pub members: &'ast [ClassMember<'ast>],
513    pub span: Span,
514}
515
516#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
517pub enum UnaryOp {
518    Plus,
519    Minus,
520    Not,
521    BitNot,
522    PreInc,
523    PreDec,
524    ErrorSuppress,
525    Reference,
526}
527
528impl<'ast> Expr<'ast> {
529    pub fn span(&self) -> Span {
530        match self {
531            Expr::Assign { span, .. } => *span,
532            Expr::AssignRef { span, .. } => *span,
533            Expr::AssignOp { span, .. } => *span,
534            Expr::Binary { span, .. } => *span,
535            Expr::Unary { span, .. } => *span,
536            Expr::Call { span, .. } => *span,
537            Expr::Array { span, .. } => *span,
538            Expr::ArrayDimFetch { span, .. } => *span,
539            Expr::PropertyFetch { span, .. } => *span,
540            Expr::MethodCall { span, .. } => *span,
541            Expr::StaticCall { span, .. } => *span,
542            Expr::ClassConstFetch { span, .. } => *span,
543            Expr::New { span, .. } => *span,
544            Expr::Variable { span, .. } => *span,
545            Expr::Integer { span, .. } => *span,
546            Expr::Float { span, .. } => *span,
547            Expr::Boolean { span, .. } => *span,
548            Expr::Null { span, .. } => *span,
549            Expr::String { span, .. } => *span,
550            Expr::InterpolatedString { span, .. } => *span,
551            Expr::ShellExec { span, .. } => *span,
552            Expr::Include { span, .. } => *span,
553            Expr::MagicConst { span, .. } => *span,
554            Expr::PostInc { span, .. } => *span,
555            Expr::PostDec { span, .. } => *span,
556            Expr::Ternary { span, .. } => *span,
557            Expr::Match { span, .. } => *span,
558            Expr::AnonymousClass { span, .. } => *span,
559            Expr::Yield { span, .. } => *span,
560            Expr::Cast { span, .. } => *span,
561            Expr::Empty { span, .. } => *span,
562            Expr::Isset { span, .. } => *span,
563            Expr::Eval { span, .. } => *span,
564            Expr::Die { span, .. } => *span,
565            Expr::Exit { span, .. } => *span,
566            Expr::Closure { span, .. } => *span,
567            Expr::ArrowFunction { span, .. } => *span,
568            Expr::Clone { span, .. } => *span,
569            Expr::Print { span, .. } => *span,
570            Expr::NullsafePropertyFetch { span, .. } => *span,
571            Expr::NullsafeMethodCall { span, .. } => *span,
572            Expr::VariadicPlaceholder { span } => *span,
573            Expr::Error { span } => *span,
574            Expr::IndirectVariable { span, .. } => *span,
575        }
576    }
577}
578
579impl<'ast> Stmt<'ast> {
580    pub fn span(&self) -> Span {
581        match self {
582            Stmt::Echo { span, .. } => *span,
583            Stmt::Return { span, .. } => *span,
584            Stmt::If { span, .. } => *span,
585            Stmt::While { span, .. } => *span,
586            Stmt::DoWhile { span, .. } => *span,
587            Stmt::For { span, .. } => *span,
588            Stmt::Foreach { span, .. } => *span,
589            Stmt::Block { span, .. } => *span,
590            Stmt::Function { span, .. } => *span,
591            Stmt::Class { span, .. } => *span,
592            Stmt::Interface { span, .. } => *span,
593            Stmt::Trait { span, .. } => *span,
594            Stmt::Enum { span, .. } => *span,
595            Stmt::Namespace { span, .. } => *span,
596            Stmt::Use { span, .. } => *span,
597            Stmt::Switch { span, .. } => *span,
598            Stmt::Try { span, .. } => *span,
599            Stmt::Throw { span, .. } => *span,
600            Stmt::Const { span, .. } => *span,
601            Stmt::Break { span, .. } => *span,
602            Stmt::Continue { span, .. } => *span,
603            Stmt::Global { span, .. } => *span,
604            Stmt::Static { span, .. } => *span,
605            Stmt::Unset { span, .. } => *span,
606            Stmt::Expression { span, .. } => *span,
607            Stmt::InlineHtml { span, .. } => *span,
608            Stmt::Declare { span, .. } => *span,
609            Stmt::HaltCompiler { span } => *span,
610            Stmt::Label { span, .. } => *span,
611            Stmt::Goto { span, .. } => *span,
612            Stmt::Error { span } => *span,
613            Stmt::Nop { span } => *span,
614        }
615    }
616}
617
618#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
619pub enum BinaryOp {
620    Plus,
621    Minus,
622    Mul,
623    Div,
624    Mod,
625    Concat, // .
626    Eq,
627    EqEq,
628    EqEqEq,
629    NotEq,
630    NotEqEq,
631    Lt,
632    LtEq,
633    Gt,
634    GtEq,
635    And,
636    Or,
637    BitAnd,
638    BitOr,
639    BitXor,
640    Coalesce,
641    Spaceship,
642    Pow,
643    ShiftLeft,
644    ShiftRight,
645    LogicalAnd,
646    LogicalOr,
647    LogicalXor,
648    Instanceof,
649}
650
651#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
652pub enum AssignOp {
653    Plus,       // +=
654    Minus,      // -=
655    Mul,        // *=
656    Div,        // /=
657    Mod,        // %=
658    Concat,     // .=
659    BitAnd,     // &=
660    BitOr,      // |=
661    BitXor,     // ^=
662    ShiftLeft,  // <<=
663    ShiftRight, // >>=
664    Pow,        // **=
665    Coalesce,   // ??=
666}
667
668#[derive(Debug, Clone, Copy, Serialize)]
669pub struct Arg<'ast> {
670    pub name: Option<&'ast Token>,
671    pub value: ExprId<'ast>,
672    pub unpack: bool,
673    pub span: Span,
674}
675
676#[derive(Debug, Clone, Copy, Serialize)]
677pub struct ArrayItem<'ast> {
678    pub key: Option<ExprId<'ast>>,
679    pub value: ExprId<'ast>,
680    pub by_ref: bool,
681    pub unpack: bool,
682    pub span: Span,
683}
684
685#[derive(Debug, Clone, Copy, Serialize)]
686pub struct PropertyEntry<'ast> {
687    pub name: &'ast Token,
688    pub default: Option<ExprId<'ast>>,
689    pub span: Span,
690}
691
692#[derive(Debug, Clone, Copy, Serialize)]
693pub enum ClassMember<'ast> {
694    Property {
695        attributes: &'ast [AttributeGroup<'ast>],
696        modifiers: &'ast [Token],
697        ty: Option<&'ast Type<'ast>>,
698        entries: &'ast [PropertyEntry<'ast>],
699        doc_comment: Option<Span>,
700        span: Span,
701    },
702    PropertyHook {
703        attributes: &'ast [AttributeGroup<'ast>],
704        modifiers: &'ast [Token],
705        ty: Option<&'ast Type<'ast>>,
706        name: &'ast Token,
707        default: Option<ExprId<'ast>>,
708        hooks: &'ast [PropertyHook<'ast>],
709        doc_comment: Option<Span>,
710        span: Span,
711    },
712    Method {
713        attributes: &'ast [AttributeGroup<'ast>],
714        modifiers: &'ast [Token],
715        name: &'ast Token,
716        params: &'ast [Param<'ast>],
717        return_type: Option<&'ast Type<'ast>>,
718        body: &'ast [StmtId<'ast>],
719        doc_comment: Option<Span>,
720        span: Span,
721    },
722    Const {
723        attributes: &'ast [AttributeGroup<'ast>],
724        modifiers: &'ast [Token],
725        ty: Option<&'ast Type<'ast>>,
726        consts: &'ast [ClassConst<'ast>],
727        doc_comment: Option<Span>,
728        span: Span,
729    },
730    TraitUse {
731        attributes: &'ast [AttributeGroup<'ast>],
732        traits: &'ast [Name<'ast>],
733        adaptations: &'ast [TraitAdaptation<'ast>],
734        doc_comment: Option<Span>,
735        span: Span,
736    },
737    Case {
738        attributes: &'ast [AttributeGroup<'ast>],
739        name: &'ast Token,
740        value: Option<ExprId<'ast>>,
741        doc_comment: Option<Span>,
742        span: Span,
743    },
744}
745
746#[derive(Debug, Clone, Copy, Serialize)]
747pub struct Case<'ast> {
748    pub condition: Option<ExprId<'ast>>, // None for default
749    pub body: &'ast [StmtId<'ast>],
750    pub span: Span,
751}
752
753#[derive(Debug, Clone, Copy, Serialize)]
754pub struct ClassConst<'ast> {
755    pub name: &'ast Token,
756    pub value: ExprId<'ast>,
757    pub span: Span,
758}
759
760#[derive(Debug, Clone, Copy, Serialize)]
761pub enum PropertyHookBody<'ast> {
762    None,
763    Statements(&'ast [StmtId<'ast>]),
764    Expr(ExprId<'ast>),
765}
766
767#[derive(Debug, Clone, Copy, Serialize)]
768pub struct PropertyHook<'ast> {
769    pub attributes: &'ast [AttributeGroup<'ast>],
770    pub modifiers: &'ast [Token],
771    pub name: &'ast Token,
772    pub params: &'ast [Param<'ast>],
773    pub by_ref: bool,
774    pub body: PropertyHookBody<'ast>,
775    pub span: Span,
776}
777
778#[derive(Debug, Clone, Copy, Serialize)]
779pub struct TraitMethodRef<'ast> {
780    pub trait_name: Option<Name<'ast>>,
781    pub method: &'ast Token,
782    pub span: Span,
783}
784
785#[derive(Debug, Clone, Copy, Serialize)]
786pub enum TraitAdaptation<'ast> {
787    Precedence {
788        method: TraitMethodRef<'ast>,
789        insteadof: &'ast [Name<'ast>],
790        span: Span,
791    },
792    Alias {
793        method: TraitMethodRef<'ast>,
794        alias: Option<&'ast Token>,
795        visibility: Option<&'ast Token>,
796        span: Span,
797    },
798}
799
800#[derive(Debug, Clone, Copy, Serialize)]
801pub struct Catch<'ast> {
802    pub types: &'ast [Name<'ast>], // Multi-catch: TryCatch|Exception
803    pub var: Option<&'ast Token>,  // Variable may be omitted in PHP 8+
804    pub body: &'ast [StmtId<'ast>],
805    pub span: Span,
806}
807
808#[derive(Debug, Clone, Copy, Serialize)]
809pub struct Name<'ast> {
810    pub parts: &'ast [Token],
811    pub span: Span,
812}
813
814#[derive(Debug, Clone, Copy, Serialize)]
815pub struct UseItem<'ast> {
816    pub name: Name<'ast>,
817    pub alias: Option<&'ast Token>,
818    pub kind: UseKind,
819    pub span: Span,
820}
821
822#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
823pub enum UseKind {
824    Normal,
825    Function,
826    Const,
827}
828
829#[derive(Debug, Clone, Copy, Serialize)]
830pub struct Attribute<'ast> {
831    pub name: Name<'ast>,
832    pub args: &'ast [Arg<'ast>],
833    pub span: Span,
834}
835
836#[derive(Debug, Clone, Copy, Serialize)]
837pub struct AttributeGroup<'ast> {
838    pub attributes: &'ast [Attribute<'ast>],
839    pub span: Span,
840}
841
842#[derive(Debug, Clone, Copy, Serialize)]
843pub enum Type<'ast> {
844    Simple(&'ast Token),
845    Name(Name<'ast>),
846    Union(&'ast [Type<'ast>]),
847    Intersection(&'ast [Type<'ast>]),
848    Nullable(&'ast Type<'ast>),
849}
850
851#[derive(Debug, Clone, Copy, Serialize)]
852pub struct DeclareItem<'ast> {
853    pub key: &'ast Token,
854    pub value: ExprId<'ast>,
855    pub span: Span,
856}
857
858#[derive(Debug, Clone, Copy, Serialize)]
859pub enum IncludeKind {
860    Include,
861    IncludeOnce,
862    Require,
863    RequireOnce,
864}
865
866#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
867pub enum MagicConstKind {
868    Dir,
869    File,
870    Line,
871    Function,
872    Class,
873    Trait,
874    Method,
875    Namespace,
876    Property,
877}