Skip to main content

mago_syntax/cst/cst/loop/
for.rs

1use strum::Display;
2
3use mago_span::HasSpan;
4use mago_span::Span;
5
6use crate::cst::cst::expression::Expression;
7use crate::cst::cst::keyword::Keyword;
8use crate::cst::cst::statement::Statement;
9use crate::cst::cst::terminator::Terminator;
10use crate::cst::sequence::Sequence;
11use crate::cst::sequence::TokenSeparatedSequence;
12
13/// Represents a for statement in PHP.
14///
15/// Example:
16///
17/// ```php
18/// <?php
19///
20/// for ($i = 0; $i < 10; $i++) {
21///   echo $i;
22/// }
23/// ```
24#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize))]
26pub struct For<'arena> {
27    pub r#for: Keyword<'arena>,
28    pub left_parenthesis: Span,
29    pub initializations: TokenSeparatedSequence<'arena, &'arena Expression<'arena>>,
30    pub initializations_semicolon: Span,
31    pub conditions: TokenSeparatedSequence<'arena, &'arena Expression<'arena>>,
32    pub conditions_semicolon: Span,
33    pub increments: TokenSeparatedSequence<'arena, &'arena Expression<'arena>>,
34    pub right_parenthesis: Span,
35    pub body: ForBody<'arena>,
36}
37
38/// Represents the body of a for statement.
39#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Display)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize))]
41#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
42pub enum ForBody<'arena> {
43    Statement(&'arena Statement<'arena>),
44    ColonDelimited(ForColonDelimitedBody<'arena>),
45}
46
47/// Represents a colon-delimited for statement body.
48///
49/// Example:
50///
51/// ```php
52/// <?php
53///
54/// for ($i = 0; $i < 10; $i++):
55///   echo $i;
56/// endfor;
57/// ```
58#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize))]
60pub struct ForColonDelimitedBody<'arena> {
61    pub colon: Span,
62    pub statements: Sequence<'arena, Statement<'arena>>,
63    pub end_for: Keyword<'arena>,
64    pub terminator: Terminator<'arena>,
65}
66
67impl<'arena> ForBody<'arena> {
68    #[inline]
69    #[must_use]
70    pub fn statements(&self) -> &[Statement<'arena>] {
71        match self {
72            ForBody::Statement(statement) => std::slice::from_ref(statement),
73            ForBody::ColonDelimited(body) => body.statements.as_slice(),
74        }
75    }
76}
77
78impl HasSpan for For<'_> {
79    fn span(&self) -> Span {
80        self.r#for.span().join(self.body.span())
81    }
82}
83
84impl HasSpan for ForBody<'_> {
85    fn span(&self) -> Span {
86        match self {
87            ForBody::Statement(statement) => statement.span(),
88            ForBody::ColonDelimited(body) => body.span(),
89        }
90    }
91}
92
93impl HasSpan for ForColonDelimitedBody<'_> {
94    fn span(&self) -> Span {
95        self.colon.join(self.terminator.span())
96    }
97}