Skip to main content

normalize_surface_syntax/ir/
stmt.rs

1//! Statement types for the IR.
2
3use crate::Expr;
4use serde::{Deserialize, Serialize};
5
6/// A statement (doesn't produce a value directly).
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub enum Stmt {
9    /// Expression statement: `expr;`.
10    Expr(Expr),
11
12    /// Variable declaration: `let name = init` or `const name = init`.
13    Let {
14        name: String,
15        init: Option<Expr>,
16        mutable: bool,
17    },
18
19    /// Block: `{ stmts... }`.
20    Block(Vec<Stmt>),
21
22    /// If statement: `if (test) consequent else alternate`.
23    If {
24        test: Expr,
25        consequent: Box<Stmt>,
26        alternate: Option<Box<Stmt>>,
27    },
28
29    /// While loop: `while (test) body`.
30    While { test: Expr, body: Box<Stmt> },
31
32    /// For loop: `for (init; test; update) body`.
33    For {
34        init: Option<Box<Stmt>>,
35        test: Option<Expr>,
36        update: Option<Expr>,
37        body: Box<Stmt>,
38    },
39
40    /// For-in/for-of loop: `for (variable in/of iterable) body`.
41    ForIn {
42        variable: String,
43        iterable: Expr,
44        body: Box<Stmt>,
45    },
46
47    /// Return statement: `return expr`.
48    Return(Option<Expr>),
49
50    /// Break statement.
51    Break,
52
53    /// Continue statement.
54    Continue,
55
56    /// Try/catch/finally statement.
57    TryCatch {
58        body: Box<Stmt>,
59        catch_param: Option<String>,
60        catch_body: Option<Box<Stmt>>,
61        finally_body: Option<Box<Stmt>>,
62    },
63
64    /// Function declaration.
65    Function(crate::Function),
66}
67
68// Builder methods for statements
69impl Stmt {
70    pub fn expr(e: Expr) -> Self {
71        Stmt::Expr(e)
72    }
73
74    pub fn let_decl(name: impl Into<String>, init: Option<Expr>) -> Self {
75        Stmt::Let {
76            name: name.into(),
77            init,
78            mutable: true,
79        }
80    }
81
82    pub fn const_decl(name: impl Into<String>, init: Expr) -> Self {
83        Stmt::Let {
84            name: name.into(),
85            init: Some(init),
86            mutable: false,
87        }
88    }
89
90    pub fn block(stmts: Vec<Stmt>) -> Self {
91        Stmt::Block(stmts)
92    }
93
94    pub fn if_stmt(test: Expr, consequent: Stmt, alternate: Option<Stmt>) -> Self {
95        Stmt::If {
96            test,
97            consequent: Box::new(consequent),
98            alternate: alternate.map(Box::new),
99        }
100    }
101
102    pub fn while_loop(test: Expr, body: Stmt) -> Self {
103        Stmt::While {
104            test,
105            body: Box::new(body),
106        }
107    }
108
109    pub fn for_loop(
110        init: Option<Stmt>,
111        test: Option<Expr>,
112        update: Option<Expr>,
113        body: Stmt,
114    ) -> Self {
115        Stmt::For {
116            init: init.map(Box::new),
117            test,
118            update,
119            body: Box::new(body),
120        }
121    }
122
123    pub fn for_in(variable: impl Into<String>, iterable: Expr, body: Stmt) -> Self {
124        Stmt::ForIn {
125            variable: variable.into(),
126            iterable,
127            body: Box::new(body),
128        }
129    }
130
131    pub fn return_stmt(expr: Option<Expr>) -> Self {
132        Stmt::Return(expr)
133    }
134
135    pub fn break_stmt() -> Self {
136        Stmt::Break
137    }
138
139    pub fn continue_stmt() -> Self {
140        Stmt::Continue
141    }
142
143    pub fn try_catch(
144        body: Stmt,
145        catch_param: Option<String>,
146        catch_body: Option<Stmt>,
147        finally_body: Option<Stmt>,
148    ) -> Self {
149        Stmt::TryCatch {
150            body: Box::new(body),
151            catch_param,
152            catch_body: catch_body.map(Box::new),
153            finally_body: finally_body.map(Box::new),
154        }
155    }
156
157    pub fn function(f: crate::Function) -> Self {
158        Stmt::Function(f)
159    }
160}