Skip to main content

normalize_surface_syntax/ir/
expr.rs

1//! Expression types for the IR.
2
3use serde::{Deserialize, Serialize};
4
5/// An expression that produces a value.
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub enum Expr {
8    /// Literal value.
9    Literal(Literal),
10
11    /// Variable reference.
12    Ident(String),
13
14    /// Binary operation: `left op right`.
15    Binary {
16        left: Box<Expr>,
17        op: BinaryOp,
18        right: Box<Expr>,
19    },
20
21    /// Unary operation: `op expr`.
22    Unary { op: UnaryOp, expr: Box<Expr> },
23
24    /// Function call: `callee(args...)`.
25    Call { callee: Box<Expr>, args: Vec<Expr> },
26
27    /// Member access: `object.property` or `object[property]`.
28    Member {
29        object: Box<Expr>,
30        property: Box<Expr>,
31        /// True for `obj[expr]`, false for `obj.ident`.
32        computed: bool,
33    },
34
35    /// Array literal: `[a, b, c]`.
36    Array(Vec<Expr>),
37
38    /// Object literal: `{ key: value, ... }`.
39    Object(Vec<(String, Expr)>),
40
41    /// Anonymous function: `function(params) { body }`.
42    Function(Box<crate::Function>),
43
44    /// Ternary/conditional: `cond ? then : else`.
45    Conditional {
46        test: Box<Expr>,
47        consequent: Box<Expr>,
48        alternate: Box<Expr>,
49    },
50
51    /// Assignment: `target = value`.
52    Assign { target: Box<Expr>, value: Box<Expr> },
53}
54
55/// Literal values.
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
57pub enum Literal {
58    Null,
59    Bool(bool),
60    Number(f64),
61    String(String),
62}
63
64/// Binary operators.
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
66pub enum BinaryOp {
67    // Arithmetic
68    Add,
69    Sub,
70    Mul,
71    Div,
72    Mod,
73
74    // Comparison
75    Eq,
76    Ne,
77    Lt,
78    Le,
79    Gt,
80    Ge,
81
82    // Logical
83    And,
84    Or,
85
86    // String
87    Concat,
88}
89
90/// Unary operators.
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
92pub enum UnaryOp {
93    Neg,
94    Not,
95}
96
97// Builder methods for expressions
98impl Expr {
99    pub fn null() -> Self {
100        Expr::Literal(Literal::Null)
101    }
102
103    pub fn bool(v: bool) -> Self {
104        Expr::Literal(Literal::Bool(v))
105    }
106
107    pub fn number(v: impl Into<f64>) -> Self {
108        Expr::Literal(Literal::Number(v.into()))
109    }
110
111    pub fn string(v: impl Into<String>) -> Self {
112        Expr::Literal(Literal::String(v.into()))
113    }
114
115    pub fn ident(name: impl Into<String>) -> Self {
116        Expr::Ident(name.into())
117    }
118
119    pub fn binary(left: Expr, op: BinaryOp, right: Expr) -> Self {
120        Expr::Binary {
121            left: Box::new(left),
122            op,
123            right: Box::new(right),
124        }
125    }
126
127    pub fn unary(op: UnaryOp, expr: Expr) -> Self {
128        Expr::Unary {
129            op,
130            expr: Box::new(expr),
131        }
132    }
133
134    pub fn call(callee: Expr, args: Vec<Expr>) -> Self {
135        Expr::Call {
136            callee: Box::new(callee),
137            args,
138        }
139    }
140
141    pub fn member(object: Expr, property: impl Into<String>) -> Self {
142        Expr::Member {
143            object: Box::new(object),
144            property: Box::new(Expr::string(property)),
145            computed: false,
146        }
147    }
148
149    pub fn index(object: Expr, index: Expr) -> Self {
150        Expr::Member {
151            object: Box::new(object),
152            property: Box::new(index),
153            computed: true,
154        }
155    }
156
157    pub fn array(items: Vec<Expr>) -> Self {
158        Expr::Array(items)
159    }
160
161    pub fn object(pairs: Vec<(String, Expr)>) -> Self {
162        Expr::Object(pairs)
163    }
164
165    pub fn conditional(test: Expr, consequent: Expr, alternate: Expr) -> Self {
166        Expr::Conditional {
167            test: Box::new(test),
168            consequent: Box::new(consequent),
169            alternate: Box::new(alternate),
170        }
171    }
172
173    pub fn assign(target: Expr, value: Expr) -> Self {
174        Expr::Assign {
175            target: Box::new(target),
176            value: Box::new(value),
177        }
178    }
179}