1use std::fmt;
2
3use crate::token::Token;
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct Program<'a> {
7 begin_blocks: Vec<Rule<'a>>,
8 rules: Vec<Rule<'a>>,
9 end_blocks: Vec<Rule<'a>>,
10}
11
12impl<'a> Program<'a> {
13 pub fn new() -> Self {
14 Program {
15 begin_blocks: vec![],
16 rules: vec![],
17 end_blocks: vec![],
18 }
19 }
20
21 pub fn len(&self) -> usize {
22 self.rules.len() + self.begin_blocks.len() + self.end_blocks.len()
23 }
24
25 pub fn is_empty(&self) -> bool {
26 self.rules.is_empty()
27 }
28
29 pub fn add_begin_block(&mut self, rule: Rule<'a>) {
30 self.begin_blocks.push(rule);
31 }
32
33 pub fn add_end_block(&mut self, rule: Rule<'a>) {
34 self.end_blocks.push(rule);
35 }
36
37 pub fn add_rule(&mut self, rule: Rule<'a>) {
38 self.rules.push(rule);
39 }
40
41 pub fn begin_blocks_iter(&self) -> std::slice::Iter<'_, Rule<'a>> {
42 self.begin_blocks.iter()
43 }
44
45 pub fn end_blocks_iter(&self) -> std::slice::Iter<'_, Rule<'a>> {
46 self.end_blocks.iter()
47 }
48
49 pub fn rules_iter(&self) -> std::slice::Iter<'_, Rule<'a>> {
50 self.rules.iter()
51 }
52}
53
54impl<'a> Default for Program<'a> {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60impl<'a> fmt::Display for Program<'a> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 for rule in &self.begin_blocks {
63 write!(f, "{rule}")?;
64 }
65
66 if !self.begin_blocks.is_empty() && !self.rules.is_empty() {
68 write!(f, " ")?;
69 }
70
71 for rule in &self.rules {
72 write!(f, "{rule}")?;
73 }
74
75 if !self.rules.is_empty() && !self.end_blocks.is_empty() {
77 write!(f, " ")?;
78 }
79
80 for rule in &self.end_blocks {
81 write!(f, "{rule}")?;
82 }
83
84 Ok(())
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
89pub enum Statement<'a> {
90 Print(Vec<Expression<'a>>),
91}
92
93#[derive(Debug, Clone, PartialEq)]
94pub struct Action<'a> {
95 pub statements: Vec<Statement<'a>>,
96}
97
98#[derive(Debug, Clone, PartialEq)]
99pub enum Rule<'a> {
100 Begin(Action<'a>),
101 Action(Action<'a>),
102 PatternAction {
103 pattern: Option<Expression<'a>>,
104 action: Option<Action<'a>>,
105 },
106 End(Action<'a>),
107}
108
109impl<'a> fmt::Display for Rule<'a> {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 match self {
112 Rule::Begin(action) => write!(f, "BEGIN {}", action),
113 Rule::Action(action) => write!(f, "{}", action),
114 Rule::PatternAction { pattern, action } => match (pattern, action) {
115 (Some(expr), Some(action)) => write!(f, "{} {}", expr, action),
116 (Some(expr), None) => write!(f, "{}", expr),
117 (None, Some(action)) => write!(f, "{}", action),
118 (None, None) => write!(f, ""),
119 },
120 Rule::End(action) => write!(f, "END {}", action),
121 }
122 }
123}
124
125impl<'a> fmt::Display for Action<'a> {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 if self.statements.is_empty() {
128 write!(f, "{{}}")
129 } else {
130 write!(
131 f,
132 "{{ {} }}",
133 self.statements
134 .iter()
135 .map(|stmt| stmt.to_string())
136 .collect::<Vec<String>>()
137 .join("; ")
138 )
139 }
140 }
141}
142
143impl<'a> fmt::Display for Statement<'a> {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 match self {
146 Statement::Print(expressions) => {
147 if expressions.is_empty() {
148 write!(f, "print")
149 } else {
150 write!(
151 f,
152 "print {}",
153 expressions
154 .iter()
155 .map(|expr| expr.to_string())
156 .collect::<Vec<String>>()
157 .join(", ")
158 )
159 }
160 }
161 }
162 }
163}
164
165#[derive(Debug, Clone, PartialEq)]
166pub enum Expression<'a> {
167 Number(f64),
168 String(&'a str),
169 Regex(&'a str),
170 Field(Box<Expression<'a>>),
171 Infix {
173 left: Box<Expression<'a>>,
174 operator: Token<'a>,
175 right: Box<Expression<'a>>,
176 },
177}
178
179impl<'a> fmt::Display for Expression<'a> {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 match self {
182 Expression::Number(n) => write!(f, "{}", n),
183 Expression::String(value) => write!(f, "\"{}\"", value),
184 Expression::Regex(value) => write!(f, "/{}/", value),
185 Expression::Field(expr) => write!(f, "${}", expr),
186 Expression::Infix {
187 left,
188 operator,
189 right,
190 } => {
191 write!(f, "{} {} {}", left, operator.literal, right)
192 }
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use crate::token::TokenKind;
201
202 #[test]
203 fn test_empty_program_creation() {
204 let program = Program::default();
205
206 assert!(program.is_empty());
207 }
208
209 #[test]
210 fn test_add_block_to_program() {
211 let mut program = Program::new();
212
213 let rule = Rule::Action(Action {
214 statements: vec![Statement::Print(vec![])],
215 });
216 program.add_begin_block(rule);
217
218 assert_eq!(program.begin_blocks.len(), 1);
219 }
220
221 #[test]
222 fn test_add_rule_to_program() {
223 let mut program = Program::new();
224
225 let rule = Rule::Action(Action {
226 statements: vec![Statement::Print(vec![])],
227 });
228 program.add_rule(rule);
229
230 assert_eq!(program.len(), 1);
231 }
232
233 #[test]
234 fn test_program_creation() {
235 let expected_string = "$3 > 5";
236 let program = Program {
237 begin_blocks: vec![],
238 rules: vec![Rule::PatternAction {
239 pattern: Some(Expression::Infix {
240 left: Box::new(Expression::Field(Box::new(Expression::Number(3.0)))),
241 operator: Token::new(TokenKind::GreaterThan, ">", 3),
242 right: Box::new(Expression::Number(5.0)),
243 }),
244 action: None,
245 }],
246 end_blocks: vec![],
247 };
248
249 assert_eq!(expected_string, program.to_string());
250 }
251
252 #[test]
253 fn test_begin_block_program_creation() {
254 let expected_string = "BEGIN { print }";
255 let program = Program {
256 begin_blocks: vec![Rule::Begin(Action {
257 statements: vec![Statement::Print(vec![])],
258 })],
259 rules: vec![],
260 end_blocks: vec![],
261 };
262
263 assert!(program.len() == 1);
264 assert_eq!(expected_string, program.to_string());
265 }
266
267 #[test]
268 fn test_end_block_program_creation() {
269 let expected_string = "END { print }";
270 let program = Program {
271 begin_blocks: vec![],
272 rules: vec![],
273 end_blocks: vec![Rule::End(Action {
274 statements: vec![Statement::Print(vec![])],
275 })],
276 };
277
278 assert!(program.len() == 1);
279 assert_eq!(expected_string, program.to_string());
280 }
281
282 #[test]
283 fn test_action_without_pattern_program_creation() {
284 let expected_string = "{ print }";
285 let program = Program {
286 begin_blocks: vec![],
287 rules: vec![Rule::PatternAction {
288 pattern: None,
289 action: Some(Action {
290 statements: vec![Statement::Print(vec![])],
291 }),
292 }],
293 end_blocks: vec![],
294 };
295
296 assert!(program.len() == 1);
297 assert_eq!(expected_string, program.to_string());
298 }
299
300 #[test]
301 fn test_program_with_begin_body_and_end_blocks() {
302 let expected_string = "BEGIN { print } $1 == 42 { print $2 } END { print \"hello\" }";
303 let program = Program {
304 begin_blocks: vec![Rule::Begin(Action {
305 statements: vec![Statement::Print(vec![])],
306 })],
307 rules: vec![Rule::PatternAction {
308 pattern: Some(Expression::Infix {
309 left: Box::new(Expression::Field(Box::new(Expression::Number(1.0)))),
310 operator: Token::new(TokenKind::Equal, "==", 7),
311 right: Box::new(Expression::Number(42.0)),
312 }),
313 action: Some(Action {
314 statements: vec![Statement::Print(vec![Expression::Field(Box::new(
315 Expression::Number(2.0),
316 ))])],
317 }),
318 }],
319 end_blocks: vec![Rule::End(Action {
320 statements: vec![Statement::Print(vec![Expression::String("hello".into())])],
321 })],
322 };
323
324 assert_eq!(expected_string, program.to_string());
325 }
326
327 #[test]
328 fn test_print_regex_expression() {
329 let expr = Expression::Regex("^[a-z]+$");
330
331 assert_eq!("/^[a-z]+$/", expr.to_string());
332 }
333}