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 /// Null literal: `null`
157 Null {
158 /// Source position
159 position: Position,
160 },
161
162 /// Variable reference: `x`
163 Identifier {
164 /// The variable name
165 name: String,
166 /// Source position
167 position: Position,
168 },
169
170 /// Binary operation: `a + b`
171 Binary {
172 /// Left operand
173 left: Box<Expression>,
174 /// The binary operator
175 operator: BinaryOp,
176 /// Right operand
177 right: Box<Expression>,
178 /// Source position
179 position: Position,
180 },
181
182 /// Unary operation: `-x` or `!x`
183 Unary {
184 /// The unary operator
185 operator: UnaryOp,
186 /// The operand expression
187 operand: Box<Expression>,
188 /// Source position
189 position: Position,
190 },
191
192 /// Assignment: `x = value`
193 Assignment {
194 /// The variable name being assigned
195 name: String,
196 /// The value expression
197 value: Box<Expression>,
198 /// Source position
199 position: Position,
200 },
201
202 /// Function call: `foo(args)`
203 Call {
204 /// The function name
205 function: String,
206 /// The argument expressions
207 arguments: Vec<Expression>,
208 /// Source position
209 position: Position,
210 },
211
212 /// Method call: `expr.method(args)`
213 MethodCall {
214 /// The receiver expression (object the method is called on)
215 receiver: Box<Expression>,
216 /// The method name
217 method: String,
218 /// The argument expressions
219 arguments: Vec<Expression>,
220 /// Source position
221 position: Position,
222 },
223
224 /// Grouped expression: `(expr)`
225 Grouped {
226 /// The inner expression
227 expression: Box<Expression>,
228 /// Source position
229 position: Position,
230 },
231
232 /// Array literal: `[1, 2, 3]`
233 ArrayLiteral {
234 /// The array element expressions
235 elements: Vec<Expression>,
236 /// Source position
237 position: Position,
238 },
239
240 /// Dictionary literal: `{"key": value, "another": 42}`
241 DictionaryLiteral {
242 /// Key-value pairs where keys are string expressions
243 pairs: Vec<(Expression, Expression)>,
244 /// Source position
245 position: Position,
246 },
247}
248
249impl Expression {
250 /// Get the position of this expression.
251 pub fn position(&self) -> Position {
252 match self {
253 Expression::Integer { position, .. }
254 | Expression::Float { position, .. }
255 | Expression::String { position, .. }
256 | Expression::Boolean { position, .. }
257 | Expression::Null { position }
258 | Expression::Identifier { position, .. }
259 | Expression::Binary { position, .. }
260 | Expression::Unary { position, .. }
261 | Expression::Assignment { position, .. }
262 | Expression::Call { position, .. }
263 | Expression::MethodCall { position, .. }
264 | Expression::Grouped { position, .. }
265 | Expression::ArrayLiteral { position, .. }
266 | Expression::DictionaryLiteral { position, .. } => *position,
267 }
268 }
269}
270
271/// Binary operators.
272#[derive(Debug, Clone, Copy, PartialEq, Eq)]
273pub enum BinaryOp {
274 /// Addition: `+`
275 Add,
276 /// Subtraction: `-`
277 Subtract,
278 /// Multiplication: `*`
279 Multiply,
280 /// Division: `/`
281 Divide,
282 /// Modulo: `%`
283 Modulo,
284 /// Equality: `==`
285 Equal,
286 /// Inequality: `!=`
287 NotEqual,
288 /// Less than: `<`
289 LessThan,
290 /// Less than or equal: `<=`
291 LessEqual,
292 /// Greater than: `>`
293 GreaterThan,
294 /// Greater than or equal: `>=`
295 GreaterEqual,
296 /// Logical and: `&&`
297 And,
298 /// Logical or: `||`
299 Or,
300}
301
302impl std::fmt::Display for BinaryOp {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 let s = match self {
305 BinaryOp::Add => "+",
306 BinaryOp::Subtract => "-",
307 BinaryOp::Multiply => "*",
308 BinaryOp::Divide => "/",
309 BinaryOp::Modulo => "%",
310 BinaryOp::Equal => "==",
311 BinaryOp::NotEqual => "!=",
312 BinaryOp::LessThan => "<",
313 BinaryOp::LessEqual => "<=",
314 BinaryOp::GreaterThan => ">",
315 BinaryOp::GreaterEqual => ">=",
316 BinaryOp::And => "&&",
317 BinaryOp::Or => "||",
318 };
319 write!(f, "{}", s)
320 }
321}
322
323/// Unary operators.
324#[derive(Debug, Clone, Copy, PartialEq, Eq)]
325pub enum UnaryOp {
326 /// Logical negation: `!`
327 Not,
328 /// Arithmetic negation: `-`
329 Negate,
330}
331
332impl std::fmt::Display for UnaryOp {
333 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
334 let s = match self {
335 UnaryOp::Not => "!",
336 UnaryOp::Negate => "-",
337 };
338 write!(f, "{}", s)
339 }
340}
341
342#[cfg(test)]
343mod tests {
344 use super::*;
345
346 #[test]
347 fn test_program_creation() {
348 let program = Program::new(vec![]);
349 assert!(program.statements.is_empty());
350 }
351
352 #[test]
353 fn test_binary_op_display() {
354 assert_eq!(BinaryOp::Add.to_string(), "+");
355 assert_eq!(BinaryOp::Equal.to_string(), "==");
356 assert_eq!(BinaryOp::And.to_string(), "&&");
357 }
358
359 #[test]
360 fn test_unary_op_display() {
361 assert_eq!(UnaryOp::Not.to_string(), "!");
362 assert_eq!(UnaryOp::Negate.to_string(), "-");
363 }
364
365 #[test]
366 fn test_expression_position() {
367 let pos = Position::new(1, 1, 0);
368 let expr = Expression::Integer {
369 value: 42,
370 position: pos,
371 };
372 assert_eq!(expr.position(), pos);
373 }
374}