Skip to main content

mago_syntax/ast/ast/loop/
for.rs

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