Skip to main content

rawk_core/
ast.rs

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        // Add space between begin blocks and rules if both exist
67        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        // Add space between rules and end blocks if both exist
76        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    // non_unary_expr
195    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}