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<Item<'a>>,
8    items: Vec<Item<'a>>,
9}
10
11impl<'a> Program<'a> {
12    pub fn new() -> Self {
13        Program {
14            begin_blocks: vec![],
15            items: vec![],
16        }
17    }
18
19    pub fn len(&self) -> usize {
20        self.items.len() + self.begin_blocks.len()
21    }
22
23    pub fn is_empty(&self) -> bool {
24        self.items.is_empty()
25    }
26
27    pub fn add_begin_block(&mut self, item: Item<'a>) {
28        self.begin_blocks.push(item);
29    }
30
31    pub fn add_item(&mut self, item: Item<'a>) {
32        self.items.push(item);
33    }
34
35    pub fn iter(&self) -> std::slice::Iter<'_, Item<'a>> {
36        self.items.iter()
37    }
38}
39
40impl<'a> Default for Program<'a> {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46impl<'a> fmt::Display for Program<'a> {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        for item in &self.begin_blocks {
49            write!(f, "{item}")?;
50        }
51
52        // Add space between begin blocks and main items if both exist
53        if !self.begin_blocks.is_empty() && !self.items.is_empty() {
54            write!(f, " ")?;
55        }
56
57        for item in &self.items {
58            write!(f, "{item}")?;
59        }
60        Ok(())
61    }
62}
63
64#[derive(Debug, Clone, PartialEq)]
65pub enum Statement<'a> {
66    Print(Vec<Expression<'a>>),
67}
68
69#[derive(Debug, Clone, PartialEq)]
70pub struct Action<'a> {
71    pub statements: Vec<Statement<'a>>,
72}
73
74#[derive(Debug, Clone, PartialEq)]
75pub enum Item<'a> {
76    Begin(Action<'a>),
77    Action(Action<'a>),
78    PatternAction {
79        pattern: Option<Expression<'a>>,
80        action: Option<Action<'a>>,
81    },
82}
83
84impl<'a> fmt::Display for Item<'a> {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        match self {
87            Item::Begin(action) => write!(f, "BEGIN {}", action),
88            Item::Action(action) => write!(f, "{}", action),
89            Item::PatternAction { pattern, action } => match (pattern, action) {
90                (Some(expr), Some(action)) => write!(f, "{} {}", expr, action),
91                (Some(expr), None) => write!(f, "{}", expr),
92                (None, Some(action)) => write!(f, "{}", action),
93                (None, None) => write!(f, ""),
94            },
95        }
96    }
97}
98
99impl<'a> fmt::Display for Action<'a> {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        if self.statements.is_empty() {
102            write!(f, "{{}}")
103        } else {
104            write!(
105                f,
106                "{{ {} }}",
107                self.statements
108                    .iter()
109                    .map(|stmt| stmt.to_string())
110                    .collect::<Vec<String>>()
111                    .join("; ")
112            )
113        }
114    }
115}
116
117impl<'a> fmt::Display for Statement<'a> {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        match self {
120            Statement::Print(expressions) => {
121                if expressions.is_empty() {
122                    write!(f, "print")
123                } else {
124                    write!(
125                        f,
126                        "print {}",
127                        expressions
128                            .iter()
129                            .map(|expr| expr.to_string())
130                            .collect::<Vec<String>>()
131                            .join(", ")
132                    )
133                }
134            }
135        }
136    }
137}
138
139#[derive(Debug, Clone, PartialEq)]
140pub enum Expression<'a> {
141    Number(f64),
142    Field(Box<Expression<'a>>),
143    // non_unary_expr
144    Infix {
145        left: Box<Expression<'a>>,
146        operator: Token<'a>,
147        right: Box<Expression<'a>>,
148    },
149}
150
151impl<'a> fmt::Display for Expression<'a> {
152    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153        match self {
154            Expression::Number(n) => write!(f, "{}", n),
155            Expression::Field(expr) => write!(f, "${}", expr),
156            Expression::Infix {
157                left,
158                operator,
159                right,
160            } => {
161                write!(f, "{} {} {}", left, operator.literal, right)
162            }
163        }
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170    use crate::token::TokenKind;
171
172    #[test]
173    fn test_empty_program_creation() {
174        let program = Program::default();
175
176        assert!(program.is_empty());
177    }
178
179    #[test]
180    fn test_add_block_to_program() {
181        let mut program = Program::new();
182
183        let item = Item::Action(Action {
184            statements: vec![Statement::Print(vec![])],
185        });
186        program.add_begin_block(item);
187
188        assert_eq!(program.begin_blocks.len(), 1);
189    }
190
191    #[test]
192    fn test_add_item_to_program() {
193        let mut program = Program::new();
194
195        let item = Item::Action(Action {
196            statements: vec![Statement::Print(vec![])],
197        });
198        program.add_item(item);
199
200        assert_eq!(program.len(), 1);
201    }
202
203    #[test]
204    fn test_program_creation() {
205        let expected_string = "$3 > 5";
206        let program = Program {
207            begin_blocks: vec![],
208            items: vec![Item::PatternAction {
209                pattern: Some(Expression::Infix {
210                    left: Box::new(Expression::Field(Box::new(Expression::Number(3.0)))),
211                    operator: Token::new(TokenKind::GreaterThan, ">", 3),
212                    right: Box::new(Expression::Number(5.0)),
213                }),
214                action: None,
215            }],
216        };
217
218        assert_eq!(expected_string, program.to_string());
219    }
220
221    #[test]
222    fn test_begin_block_program_creation() {
223        let expected_string = "BEGIN { print }";
224        let program = Program {
225            begin_blocks: vec![Item::Begin(Action {
226                statements: vec![Statement::Print(vec![])],
227            })],
228            items: vec![],
229        };
230
231        assert_eq!(expected_string, program.to_string());
232    }
233
234    #[test]
235    fn test_action_without_pattern_program_creation() {
236        let expected_string = "{ print }";
237        let program = Program {
238            begin_blocks: vec![],
239            items: vec![Item::PatternAction {
240                pattern: None,
241                action: Some(Action {
242                    statements: vec![Statement::Print(vec![])],
243                }),
244            }],
245        };
246
247        assert_eq!(expected_string, program.to_string());
248    }
249
250    #[test]
251    fn test_program_with_begin_and_body() {
252        let expected_string = "BEGIN { print } $1 == 42 { print $2 }";
253        let program = Program {
254            begin_blocks: vec![Item::Begin(Action {
255                statements: vec![Statement::Print(vec![])],
256            })],
257            items: vec![Item::PatternAction {
258                pattern: Some(Expression::Infix {
259                    left: Box::new(Expression::Field(Box::new(Expression::Number(1.0)))),
260                    operator: Token::new(TokenKind::Equal, "==", 7),
261                    right: Box::new(Expression::Number(42.0)),
262                }),
263                action: Some(Action {
264                    statements: vec![Statement::Print(vec![Expression::Field(Box::new(
265                        Expression::Number(2.0),
266                    ))])],
267                }),
268            }],
269        };
270
271        assert_eq!(expected_string, program.to_string());
272    }
273}