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