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 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}