Skip to main content

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}