cas_parser/parser/ast/
loop_expr.rs1use crate::parser::{
2 ast::expr::Expr,
3 error::{kind::{BreakOutsideLoop, ContinueOutsideLoop}, Error},
4 fmt::Latex,
5 keyword::{Break as BreakToken, Continue as ContinueToken, Loop as LoopToken},
6 Parse,
7 Parser,
8};
9use std::{fmt, ops::Range};
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, PartialEq)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub struct Loop {
19 pub body: Box<Expr>,
21
22 pub span: Range<usize>,
24
25 pub loop_span: Range<usize>,
27}
28
29impl Loop {
30 pub fn span(&self) -> Range<usize> {
32 self.span.clone()
33 }
34}
35
36impl<'source> Parse<'source> for Loop {
37 fn std_parse(
38 input: &mut Parser<'source>,
39 recoverable_errors: &mut Vec<Error>
40 ) -> Result<Self, Vec<Error>> {
41 let loop_token = input.try_parse::<LoopToken>().forward_errors(recoverable_errors)?;
42
43 let body = input.try_parse_with_state::<_, Expr>(|state| {
44 state.allow_loop_control = true;
45 }).forward_errors(recoverable_errors)?;
46 let span = loop_token.span.start..body.span().end;
47
48 Ok(Self {
49 body: Box::new(body),
50 span,
51 loop_span: loop_token.span,
52 })
53 }
54}
55
56impl std::fmt::Display for Loop {
57 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
58 write!(f, "loop {}", self.body)
59 }
60}
61
62impl Latex for Loop {
63 fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 write!(f, "\\text{{loop }}")?;
65 self.body.fmt_latex(f)?;
66 Ok(())
67 }
68}
69
70#[derive(Debug, Clone, PartialEq)]
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
73pub struct Break {
74 pub value: Option<Box<Expr>>,
76
77 pub span: Range<usize>,
79
80 pub break_span: Range<usize>,
82}
83
84impl Break {
85 pub fn span(&self) -> Range<usize> {
87 self.span.clone()
88 }
89}
90
91impl<'source> Parse<'source> for Break {
92 fn std_parse(
93 input: &mut Parser<'source>,
94 recoverable_errors: &mut Vec<Error>
95 ) -> Result<Self, Vec<Error>> {
96 let break_token = input.try_parse::<BreakToken>().forward_errors(recoverable_errors)?;
97 let value = if let Ok(value) = input.try_parse::<Expr>().forward_errors(recoverable_errors) {
98 Some(value)
99 } else {
100 None
101 };
102 let span = if let Some(value) = &value {
103 break_token.span.start..value.span().end
104 } else {
105 break_token.span.clone()
106 };
107
108 if !input.state.allow_loop_control {
110 recoverable_errors.push(Error::new(
111 vec![break_token.span.clone()],
112 BreakOutsideLoop,
113 ));
114 }
115
116 Ok(Self {
117 value: value.map(Box::new),
118 span,
119 break_span: break_token.span,
120 })
121 }
122}
123
124impl std::fmt::Display for Break {
125 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
126 write!(f, "break")?;
127 if let Some(value) = &self.value {
128 write!(f, " {}", value)?;
129 }
130 Ok(())
131 }
132}
133
134impl Latex for Break {
135 fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
136 write!(f, "\\text{{break }}")?;
137 if let Some(value) = &self.value {
138 value.fmt_latex(f)?;
139 }
140 Ok(())
141 }
142}
143
144#[derive(Debug, Clone, PartialEq)]
146#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
147pub struct Continue {
148 pub span: Range<usize>,
150}
151
152impl Continue {
153 pub fn span(&self) -> Range<usize> {
155 self.span.clone()
156 }
157}
158
159impl<'source> Parse<'source> for Continue {
160 fn std_parse(
161 input: &mut Parser<'source>,
162 recoverable_errors: &mut Vec<Error>
163 ) -> Result<Self, Vec<Error>> {
164 let continue_token = input.try_parse::<ContinueToken>()
165 .forward_errors(recoverable_errors)?;
166
167 if !input.state.allow_loop_control {
169 recoverable_errors.push(Error::new(
170 vec![continue_token.span.clone()],
171 ContinueOutsideLoop,
172 ));
173 }
174
175 Ok(Self {
176 span: continue_token.span,
177 })
178 }
179}
180
181impl std::fmt::Display for Continue {
182 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
183 write!(f, "continue")
184 }
185}
186
187impl Latex for Continue {
188 fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
189 write!(f, "\\text{{continue}}")
190 }
191}