mago_ast/ast/
variable.rs

1use serde::Deserialize;
2use serde::Serialize;
3use strum::Display;
4
5use mago_interner::StringIdentifier;
6use mago_span::HasSpan;
7use mago_span::Span;
8
9use crate::ast::expression::Expression;
10
11/// Represents a variable.
12///
13/// # Examples
14///
15/// ```php
16/// $foo
17/// ${foo}
18/// $$foo
19/// ```
20#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
21#[serde(tag = "type", content = "value")]
22#[repr(C, u8)]
23pub enum Variable {
24    Direct(DirectVariable),
25    Indirect(IndirectVariable),
26    Nested(NestedVariable),
27}
28
29/// Represents a direct variable.
30///
31/// A direct variable is a variable that is directly referenced by its name.
32///
33/// # Examples
34///
35/// ```php
36/// $foo
37/// ```
38#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
39#[repr(C)]
40pub struct DirectVariable {
41    pub span: Span,
42    pub name: StringIdentifier,
43}
44
45/// Represents an indirect variable.
46///
47/// An indirect variable is a variable whose name is determined by evaluating an expression at runtime.
48///
49/// The expression is enclosed in curly braces `{}` following a dollar sign `$`.
50///
51/// # Examples
52///
53/// ```php
54/// ${foo}
55/// ```
56#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
57#[repr(C)]
58pub struct IndirectVariable {
59    pub dollar_left_brace: Span,
60    pub expression: Box<Expression>,
61    pub right_brace: Span,
62}
63
64/// Represents a nested variable.
65///
66/// A nested variable is a variable that is nested inside another variable, commonly known as a variable variable.
67///
68/// # Examples
69///
70/// ```php
71/// $$foo
72/// $${foo}
73/// $$$foo
74/// ```
75#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
76#[repr(C)]
77pub struct NestedVariable {
78    pub dollar: Span,
79    pub variable: Box<Variable>,
80}
81
82impl HasSpan for Variable {
83    fn span(&self) -> Span {
84        match self {
85            Variable::Direct(node) => node.span(),
86            Variable::Indirect(node) => node.span(),
87            Variable::Nested(node) => node.span(),
88        }
89    }
90}
91
92impl HasSpan for DirectVariable {
93    fn span(&self) -> Span {
94        self.span
95    }
96}
97
98impl HasSpan for IndirectVariable {
99    fn span(&self) -> Span {
100        Span::between(self.dollar_left_brace, self.right_brace)
101    }
102}
103
104impl HasSpan for NestedVariable {
105    fn span(&self) -> Span {
106        Span::between(self.dollar, self.variable.span())
107    }
108}