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 Printf(Vec<Expression<'a>>),
92 Assignment {
93 identifier: &'a str,
94 value: Expression<'a>,
95 },
96}
97
98#[derive(Debug, Clone, PartialEq)]
99pub struct Action<'a> {
100 pub statements: Vec<Statement<'a>>,
101}
102
103#[derive(Debug, Clone, PartialEq)]
104pub enum Rule<'a> {
105 Begin(Action<'a>),
106 Action(Action<'a>),
107 PatternAction {
108 pattern: Option<Expression<'a>>,
109 action: Option<Action<'a>>,
110 },
111 End(Action<'a>),
112}
113
114impl<'a> fmt::Display for Rule<'a> {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 match self {
117 Rule::Begin(action) => write!(f, "BEGIN {}", action),
118 Rule::Action(action) => write!(f, "{}", action),
119 Rule::PatternAction { pattern, action } => match (pattern, action) {
120 (Some(expr), Some(action)) => write!(f, "{} {}", expr, action),
121 (Some(expr), None) => write!(f, "{}", expr),
122 (None, Some(action)) => write!(f, "{}", action),
123 (None, None) => write!(f, ""),
124 },
125 Rule::End(action) => write!(f, "END {}", action),
126 }
127 }
128}
129
130impl<'a> fmt::Display for Action<'a> {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 if self.statements.is_empty() {
133 write!(f, "{{}}")
134 } else {
135 write!(
136 f,
137 "{{ {} }}",
138 self.statements
139 .iter()
140 .map(|stmt| stmt.to_string())
141 .collect::<Vec<String>>()
142 .join("; ")
143 )
144 }
145 }
146}
147
148impl<'a> fmt::Display for Statement<'a> {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 match self {
151 Statement::Print(expressions) => {
152 if expressions.is_empty() {
153 write!(f, "print")
154 } else {
155 write!(
156 f,
157 "print {}",
158 expressions
159 .iter()
160 .filter(|expr| *expr != &Expression::String(" "))
161 .map(|expr| expr.to_string())
162 .collect::<Vec<String>>()
163 .join(", ")
164 )
165 }
166 }
167 Statement::Printf(expressions) => {
168 if expressions.is_empty() {
169 write!(f, "printf")
170 } else {
171 write!(
172 f,
173 "printf {}",
174 expressions
175 .iter()
176 .map(|expr| expr.to_string())
177 .collect::<Vec<String>>()
178 .join(", ")
179 )
180 }
181 }
182 Statement::Assignment { identifier, value } => write!(f, "{identifier} = {value}"),
183 }
184 }
185}
186
187#[derive(Debug, Clone, PartialEq)]
188pub enum Expression<'a> {
189 Number(f64),
190 String(&'a str),
191 Regex(&'a str),
192 Field(Box<Expression<'a>>),
193 Identifier(&'a str),
194 Infix {
196 left: Box<Expression<'a>>,
197 operator: Token<'a>,
198 right: Box<Expression<'a>>,
199 },
200}
201
202impl<'a> fmt::Display for Expression<'a> {
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 match self {
205 Expression::Number(n) => write!(f, "{}", n),
206 Expression::String(value) => write!(f, "\"{}\"", value),
207 Expression::Regex(value) => write!(f, "/{}/", value),
208 Expression::Field(expr) => write!(f, "${}", expr),
209 Expression::Identifier(ident) => write!(f, "{}", ident),
210 Expression::Infix {
211 left,
212 operator,
213 right,
214 } => {
215 write!(f, "{} {} {}", left, operator.literal, right)
216 }
217 }
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224 use crate::token::TokenKind;
225
226 #[test]
227 fn test_empty_program_creation() {
228 let program = Program::default();
229
230 assert!(program.is_empty());
231 }
232
233 #[test]
234 fn test_add_block_to_program() {
235 let mut program = Program::new();
236
237 let rule = Rule::Action(Action {
238 statements: vec![Statement::Print(vec![])],
239 });
240 program.add_begin_block(rule);
241
242 assert_eq!(program.begin_blocks.len(), 1);
243 }
244
245 #[test]
246 fn test_add_rule_to_program() {
247 let mut program = Program::new();
248
249 let rule = Rule::Action(Action {
250 statements: vec![Statement::Print(vec![])],
251 });
252 program.add_rule(rule);
253
254 assert_eq!(program.len(), 1);
255 }
256
257 #[test]
258 fn test_program_creation() {
259 let expected_string = "$3 > 5";
260 let program = Program {
261 begin_blocks: vec![],
262 rules: vec![Rule::PatternAction {
263 pattern: Some(Expression::Infix {
264 left: Box::new(Expression::Field(Box::new(Expression::Number(3.0)))),
265 operator: Token::new(TokenKind::GreaterThan, ">", 3),
266 right: Box::new(Expression::Number(5.0)),
267 }),
268 action: None,
269 }],
270 end_blocks: vec![],
271 };
272
273 assert_eq!(expected_string, program.to_string());
274 }
275
276 #[test]
277 fn test_begin_block_program_creation() {
278 let expected_string = "BEGIN { print }";
279 let program = Program {
280 begin_blocks: vec![Rule::Begin(Action {
281 statements: vec![Statement::Print(vec![])],
282 })],
283 rules: vec![],
284 end_blocks: vec![],
285 };
286
287 assert!(program.len() == 1);
288 assert_eq!(expected_string, program.to_string());
289 }
290
291 #[test]
292 fn test_end_block_program_creation() {
293 let expected_string = "END { print }";
294 let program = Program {
295 begin_blocks: vec![],
296 rules: vec![],
297 end_blocks: vec![Rule::End(Action {
298 statements: vec![Statement::Print(vec![])],
299 })],
300 };
301
302 assert!(program.len() == 1);
303 assert_eq!(expected_string, program.to_string());
304 }
305
306 #[test]
307 fn test_action_without_pattern_program_creation() {
308 let expected_string = "{ print }";
309 let program = Program {
310 begin_blocks: vec![],
311 rules: vec![Rule::PatternAction {
312 pattern: None,
313 action: Some(Action {
314 statements: vec![Statement::Print(vec![])],
315 }),
316 }],
317 end_blocks: vec![],
318 };
319
320 assert!(program.len() == 1);
321 assert_eq!(expected_string, program.to_string());
322 }
323
324 #[test]
325 fn test_program_with_begin_body_and_end_blocks() {
326 let expected_string =
327 "BEGIN { print } $1 == 42 { print NF, $2, $3 } END { print \"hello\" }";
328 let program = Program {
329 begin_blocks: vec![Rule::Begin(Action {
330 statements: vec![Statement::Print(vec![])],
331 })],
332 rules: vec![Rule::PatternAction {
333 pattern: Some(Expression::Infix {
334 left: Box::new(Expression::Field(Box::new(Expression::Number(1.0)))),
335 operator: Token::new(TokenKind::Equal, "==", 7),
336 right: Box::new(Expression::Number(42.0)),
337 }),
338 action: Some(Action {
339 statements: vec![Statement::Print(vec![
340 Expression::Identifier("NF"),
341 Expression::String(" "),
342 Expression::Field(Box::new(Expression::Number(2.0))),
343 Expression::String(" "),
344 Expression::Field(Box::new(Expression::Number(3.0))),
345 ])],
346 }),
347 }],
348 end_blocks: vec![Rule::End(Action {
349 statements: vec![Statement::Print(vec![Expression::String("hello".into())])],
350 })],
351 };
352
353 assert_eq!(expected_string, program.to_string());
354 }
355
356 #[test]
357 fn test_print_regex_expression() {
358 let expr = Expression::Regex("^[a-z]+$");
359
360 assert_eq!("/^[a-z]+$/", expr.to_string());
361 }
362}