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