fiddler_script/ast.rs
1//! Abstract Syntax Tree (AST) definitions for FiddlerScript.
2//!
3//! This module contains all the node types that make up the parsed representation
4//! of a FiddlerScript program.
5
6use crate::error::Position;
7
8/// A complete FiddlerScript program.
9#[derive(Debug, Clone, PartialEq)]
10pub struct Program {
11 /// The statements that make up the program
12 pub statements: Vec<Statement>,
13}
14
15impl Program {
16 /// Create a new program with the given statements.
17 pub fn new(statements: Vec<Statement>) -> Self {
18 Self { statements }
19 }
20}
21
22/// A statement in FiddlerScript.
23#[derive(Debug, Clone, PartialEq)]
24pub enum Statement {
25 /// Variable declaration: `let x = expr;`
26 Let {
27 /// The variable name being declared
28 name: String,
29 /// The initial value expression
30 value: Expression,
31 /// Source position of the let keyword
32 position: Position,
33 },
34
35 /// If statement: `if (condition) { ... } else { ... }`
36 If {
37 /// The condition expression to evaluate
38 condition: Expression,
39 /// The block to execute if condition is true
40 then_block: Block,
41 /// Optional else clause (block or else-if)
42 else_block: Option<ElseClause>,
43 /// Source position of the if keyword
44 position: Position,
45 },
46
47 /// For loop: `for (init; condition; update) { ... }`
48 For {
49 /// Optional initialization statement
50 init: Option<Box<Statement>>,
51 /// Optional loop condition expression
52 condition: Option<Expression>,
53 /// Optional update expression
54 update: Option<Expression>,
55 /// The loop body
56 body: Block,
57 /// Source position of the for keyword
58 position: Position,
59 },
60
61 /// Return statement: `return expr;`
62 Return {
63 /// Optional return value expression
64 value: Option<Expression>,
65 /// Source position of the return keyword
66 position: Position,
67 },
68
69 /// Function definition: `fn name(params) { ... }`
70 Function {
71 /// The function name
72 name: String,
73 /// Parameter names
74 params: Vec<String>,
75 /// The function body
76 body: Block,
77 /// Source position of the fn keyword
78 position: Position,
79 },
80
81 /// Expression statement: `expr;`
82 Expression {
83 /// The expression to evaluate
84 expression: Expression,
85 /// Source position of the expression start
86 position: Position,
87 },
88
89 /// Block statement: `{ ... }`
90 Block(Block),
91}
92
93/// An else clause can be either a block or an else-if chain.
94#[derive(Debug, Clone, PartialEq)]
95pub enum ElseClause {
96 /// else { ... }
97 Block(Block),
98 /// else if (...) { ... }
99 ElseIf(Box<Statement>),
100}
101
102/// A block of statements.
103#[derive(Debug, Clone, PartialEq)]
104pub struct Block {
105 /// The statements in the block
106 pub statements: Vec<Statement>,
107 /// Position of the opening brace
108 pub position: Position,
109}
110
111impl Block {
112 /// Create a new block with the given statements.
113 pub fn new(statements: Vec<Statement>, position: Position) -> Self {
114 Self {
115 statements,
116 position,
117 }
118 }
119}
120
121/// An expression in FiddlerScript.
122#[derive(Debug, Clone, PartialEq)]
123pub enum Expression {
124 /// Integer literal: `42`
125 Integer {
126 /// The integer value
127 value: i64,
128 /// Source position
129 position: Position,
130 },
131
132 /// Float literal: `3.14`
133 Float {
134 /// The float value
135 value: f64,
136 /// Source position
137 position: Position,
138 },
139
140 /// String literal: `"hello"`
141 String {
142 /// The string value
143 value: String,
144 /// Source position
145 position: Position,
146 },
147
148 /// Boolean literal: `true` or `false`
149 Boolean {
150 /// The boolean value
151 value: bool,
152 /// Source position
153 position: Position,
154 },
155
156 /// Variable reference: `x`
157 Identifier {
158 /// The variable name
159 name: String,
160 /// Source position
161 position: Position,
162 },
163
164 /// Binary operation: `a + b`
165 Binary {
166 /// Left operand
167 left: Box<Expression>,
168 /// The binary operator
169 operator: BinaryOp,
170 /// Right operand
171 right: Box<Expression>,
172 /// Source position
173 position: Position,
174 },
175
176 /// Unary operation: `-x` or `!x`
177 Unary {
178 /// The unary operator
179 operator: UnaryOp,
180 /// The operand expression
181 operand: Box<Expression>,
182 /// Source position
183 position: Position,
184 },
185
186 /// Assignment: `x = value`
187 Assignment {
188 /// The variable name being assigned
189 name: String,
190 /// The value expression
191 value: Box<Expression>,
192 /// Source position
193 position: Position,
194 },
195
196 /// Function call: `foo(args)`
197 Call {
198 /// The function name
199 function: String,
200 /// The argument expressions
201 arguments: Vec<Expression>,
202 /// Source position
203 position: Position,
204 },
205
206 /// Method call: `expr.method(args)`
207 MethodCall {
208 /// The receiver expression (object the method is called on)
209 receiver: Box<Expression>,
210 /// The method name
211 method: String,
212 /// The argument expressions
213 arguments: Vec<Expression>,
214 /// Source position
215 position: Position,
216 },
217
218 /// Grouped expression: `(expr)`
219 Grouped {
220 /// The inner expression
221 expression: Box<Expression>,
222 /// Source position
223 position: Position,
224 },
225
226 /// Array literal: `[1, 2, 3]`
227 ArrayLiteral {
228 /// The array element expressions
229 elements: Vec<Expression>,
230 /// Source position
231 position: Position,
232 },
233
234 /// Dictionary literal: `{"key": value, "another": 42}`
235 DictionaryLiteral {
236 /// Key-value pairs where keys are string expressions
237 pairs: Vec<(Expression, Expression)>,
238 /// Source position
239 position: Position,
240 },
241}
242
243impl Expression {
244 /// Get the position of this expression.
245 pub fn position(&self) -> Position {
246 match self {
247 Expression::Integer { position, .. }
248 | Expression::Float { position, .. }
249 | Expression::String { position, .. }
250 | Expression::Boolean { position, .. }
251 | Expression::Identifier { position, .. }
252 | Expression::Binary { position, .. }
253 | Expression::Unary { position, .. }
254 | Expression::Assignment { position, .. }
255 | Expression::Call { position, .. }
256 | Expression::MethodCall { position, .. }
257 | Expression::Grouped { position, .. }
258 | Expression::ArrayLiteral { position, .. }
259 | Expression::DictionaryLiteral { position, .. } => *position,
260 }
261 }
262}
263
264/// Binary operators.
265#[derive(Debug, Clone, Copy, PartialEq, Eq)]
266pub enum BinaryOp {
267 /// Addition: `+`
268 Add,
269 /// Subtraction: `-`
270 Subtract,
271 /// Multiplication: `*`
272 Multiply,
273 /// Division: `/`
274 Divide,
275 /// Modulo: `%`
276 Modulo,
277 /// Equality: `==`
278 Equal,
279 /// Inequality: `!=`
280 NotEqual,
281 /// Less than: `<`
282 LessThan,
283 /// Less than or equal: `<=`
284 LessEqual,
285 /// Greater than: `>`
286 GreaterThan,
287 /// Greater than or equal: `>=`
288 GreaterEqual,
289 /// Logical and: `&&`
290 And,
291 /// Logical or: `||`
292 Or,
293}
294
295impl std::fmt::Display for BinaryOp {
296 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
297 let s = match self {
298 BinaryOp::Add => "+",
299 BinaryOp::Subtract => "-",
300 BinaryOp::Multiply => "*",
301 BinaryOp::Divide => "/",
302 BinaryOp::Modulo => "%",
303 BinaryOp::Equal => "==",
304 BinaryOp::NotEqual => "!=",
305 BinaryOp::LessThan => "<",
306 BinaryOp::LessEqual => "<=",
307 BinaryOp::GreaterThan => ">",
308 BinaryOp::GreaterEqual => ">=",
309 BinaryOp::And => "&&",
310 BinaryOp::Or => "||",
311 };
312 write!(f, "{}", s)
313 }
314}
315
316/// Unary operators.
317#[derive(Debug, Clone, Copy, PartialEq, Eq)]
318pub enum UnaryOp {
319 /// Logical negation: `!`
320 Not,
321 /// Arithmetic negation: `-`
322 Negate,
323}
324
325impl std::fmt::Display for UnaryOp {
326 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327 let s = match self {
328 UnaryOp::Not => "!",
329 UnaryOp::Negate => "-",
330 };
331 write!(f, "{}", s)
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338
339 #[test]
340 fn test_program_creation() {
341 let program = Program::new(vec![]);
342 assert!(program.statements.is_empty());
343 }
344
345 #[test]
346 fn test_binary_op_display() {
347 assert_eq!(BinaryOp::Add.to_string(), "+");
348 assert_eq!(BinaryOp::Equal.to_string(), "==");
349 assert_eq!(BinaryOp::And.to_string(), "&&");
350 }
351
352 #[test]
353 fn test_unary_op_display() {
354 assert_eq!(UnaryOp::Not.to_string(), "!");
355 assert_eq!(UnaryOp::Negate.to_string(), "-");
356 }
357
358 #[test]
359 fn test_expression_position() {
360 let pos = Position::new(1, 1, 0);
361 let expr = Expression::Integer {
362 value: 42,
363 position: pos,
364 };
365 assert_eq!(expr.position(), pos);
366 }
367}