Skip to main content

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