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}
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    // non_unary_expr
172    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}