mago_syntax/ast/ast/loop/
while.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;
12
13/// Represents a while statement in PHP.
14///
15/// Example:
16///
17/// ```php
18/// <?php
19///
20/// $i = 0;
21/// while ($i < 10) {
22///   echo $i;
23///   $i++;
24/// }
25/// ```
26#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
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, Serialize, PartialOrd, Ord, Display)]
37#[serde(tag = "type", content = "value")]
38#[repr(u8)]
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, Serialize, PartialOrd, Ord)]
58pub struct WhileColonDelimitedBody<'arena> {
59    pub colon: Span,
60    pub statements: Sequence<'arena, Statement<'arena>>,
61    pub end_while: Keyword<'arena>,
62    pub terminator: Terminator<'arena>,
63}
64
65impl<'arena> WhileBody<'arena> {
66    #[inline]
67    #[must_use]
68    pub fn statements(&self) -> &[Statement<'arena>] {
69        match self {
70            WhileBody::Statement(statement) => std::slice::from_ref(statement),
71            WhileBody::ColonDelimited(body) => body.statements.as_slice(),
72        }
73    }
74}
75
76impl HasSpan for While<'_> {
77    fn span(&self) -> Span {
78        self.r#while.span().join(self.body.span())
79    }
80}
81
82impl HasSpan for WhileBody<'_> {
83    fn span(&self) -> Span {
84        match self {
85            WhileBody::Statement(statement) => statement.span(),
86            WhileBody::ColonDelimited(body) => body.span(),
87        }
88    }
89}
90
91impl HasSpan for WhileColonDelimitedBody<'_> {
92    fn span(&self) -> Span {
93        self.colon.join(self.terminator.span())
94    }
95}