rawk_core/
ast.rs

1use std::fmt;
2
3use crate::token::Token;
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct Program<'a> {
7    items: Vec<Item<'a>>,
8}
9
10impl<'a> Program<'a> {
11    pub fn new() -> Self {
12        Program { items: vec![] }
13    }
14
15    pub fn len(&self) -> usize {
16        self.items.len()
17    }
18
19    pub fn is_empty(&self) -> bool {
20        self.items.is_empty()
21    }
22
23    pub fn add_item(&mut self, item: Item<'a>) {
24        self.items.push(item);
25    }
26
27    pub fn iter(&self) -> std::slice::Iter<'_, Item<'a>> {
28        self.items.iter()
29    }
30}
31
32impl<'a> Default for Program<'a> {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl<'a> fmt::Display for Program<'a> {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(
41            f,
42            "{}",
43            self.items
44                .iter()
45                .map(|item| item.to_string())
46                .collect::<Vec<String>>()
47                .join("")
48        )
49    }
50}
51
52#[derive(Debug, Clone, PartialEq)]
53pub enum Statement<'a> {
54    Print(Vec<Expression<'a>>),
55}
56
57#[derive(Debug, Clone, PartialEq)]
58pub struct Action<'a> {
59    pub statements: Vec<Statement<'a>>,
60}
61
62#[derive(Debug, Clone, PartialEq)]
63pub enum Item<'a> {
64    Action(Action<'a>),
65    PatternAction {
66        pattern: Option<Expression<'a>>,
67        action: Option<Action<'a>>,
68    },
69}
70
71impl<'a> fmt::Display for Item<'a> {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        match self {
74            Item::Action(action) => write!(f, "{}", action),
75            Item::PatternAction { pattern, action } => match (pattern, action) {
76                (Some(expr), Some(action)) => write!(f, "{} {}", expr, action),
77                (Some(expr), None) => write!(f, "{}", expr),
78                (None, Some(action)) => write!(f, "{}", action),
79                (None, None) => write!(f, ""),
80            },
81        }
82    }
83}
84
85impl<'a> fmt::Display for Action<'a> {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        if self.statements.is_empty() {
88            write!(f, "{{}}")
89        } else {
90            write!(
91                f,
92                "{{ {} }}",
93                self.statements
94                    .iter()
95                    .map(|stmt| stmt.to_string())
96                    .collect::<Vec<String>>()
97                    .join("; ")
98            )
99        }
100    }
101}
102
103impl<'a> fmt::Display for Statement<'a> {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        match self {
106            Statement::Print(expressions) => {
107                if expressions.is_empty() {
108                    write!(f, "print")
109                } else {
110                    write!(
111                        f,
112                        "print {}",
113                        expressions
114                            .iter()
115                            .map(|expr| expr.to_string())
116                            .collect::<Vec<String>>()
117                            .join(", ")
118                    )
119                }
120            }
121        }
122    }
123}
124
125#[derive(Debug, Clone, PartialEq)]
126pub enum Expression<'a> {
127    Number(f64),
128    Field(Box<Expression<'a>>),
129    // non_unary_expr
130    Infix {
131        left: Box<Expression<'a>>,
132        operator: Token<'a>,
133        right: Box<Expression<'a>>,
134    },
135}
136
137impl<'a> fmt::Display for Expression<'a> {
138    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139        match self {
140            Expression::Number(n) => write!(f, "{}", n),
141            Expression::Field(expr) => write!(f, "${}", expr),
142            Expression::Infix {
143                left,
144                operator,
145                right,
146            } => {
147                write!(f, "{} {} {}", left, operator.literal, right)
148            }
149        }
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156    use crate::token::TokenKind;
157
158    #[test]
159    fn test_empty_program_creation() {
160        let program = Program::default();
161
162        assert!(program.is_empty());
163    }
164
165    #[test]
166    fn test_add_item_to_program() {
167        let mut program = Program::new();
168
169        let item = Item::Action(Action {
170            statements: vec![Statement::Print(vec![])],
171        });
172        program.add_item(item);
173
174        assert_eq!(program.len(), 1);
175    }
176
177    #[test]
178    fn test_program_creation() {
179        let expected_string = "$3 > 5";
180        let program = Program {
181            items: vec![Item::PatternAction {
182                pattern: Some(Expression::Infix {
183                    left: Box::new(Expression::Field(Box::new(Expression::Number(3.0)))),
184                    operator: Token {
185                        kind: TokenKind::GreaterThan,
186                        literal: ">",
187                    },
188                    right: Box::new(Expression::Number(5.0)),
189                }),
190                action: None,
191            }],
192        };
193
194        assert_eq!(expected_string, program.to_string());
195    }
196
197    #[test]
198    fn test_action_without_pattern_program_creation() {
199        let expected_string = "{ print }";
200        let program = Program {
201            items: vec![Item::PatternAction {
202                pattern: None,
203                action: Some(Action {
204                    statements: vec![Statement::Print(vec![])],
205                }),
206            }],
207        };
208
209        assert_eq!(expected_string, program.to_string());
210    }
211}