solverforge_core/wasm/expression/
mod.rs

1mod builder;
2mod substitution;
3#[cfg(test)]
4mod tests;
5
6pub use builder::{Expr, FieldAccessExt};
7
8use serde::{Deserialize, Serialize};
9
10/// WASM type for field access expressions.
11///
12/// This enum represents the WASM type that a field access will produce.
13/// Used for type inference to select correct operation variants (e.g., Add vs Add64).
14#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
15pub enum WasmFieldType {
16    /// 32-bit integer (default for int fields)
17    I32,
18    /// 64-bit integer (for datetime, timedelta fields)
19    I64,
20    /// 64-bit float
21    F64,
22    /// Boolean (represented as i32 in WASM)
23    Bool,
24    /// String (represented as handle in WASM)
25    String,
26    /// Object reference (represented as handle in WASM)
27    #[default]
28    Object,
29}
30
31/// Rich expression tree for constraint predicates
32///
33/// This enum represents a complete expression language for building constraint predicates.
34/// Expressions are serializable (via serde) for use across FFI boundaries.
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36#[serde(tag = "kind")]
37pub enum Expression {
38    // ===== Literals =====
39    /// Integer literal (i64) - compiles to i32 in WASM
40    IntLiteral { value: i64 },
41
42    /// 64-bit integer literal - compiles directly to i64 in WASM
43    Int64Literal { value: i64 },
44
45    /// Float literal (f64)
46    FloatLiteral { value: f64 },
47
48    /// String literal
49    StringLiteral { value: String },
50
51    /// Boolean literal
52    BoolLiteral { value: bool },
53
54    /// Null value
55    Null,
56
57    // ===== Parameter Access =====
58    /// Access a function parameter by index
59    Param { index: u32 },
60
61    // ===== Field Access =====
62    /// Access a field on an object
63    FieldAccess {
64        object: Box<Expression>,
65        class_name: String,
66        field_name: String,
67        /// WASM type of the field for type inference.
68        /// Defaults to Object for unknown types.
69        #[serde(default)]
70        field_type: WasmFieldType,
71    },
72
73    // ===== Comparisons =====
74    /// Equal comparison (==)
75    Eq {
76        left: Box<Expression>,
77        right: Box<Expression>,
78    },
79
80    /// Not equal comparison (!=)
81    Ne {
82        left: Box<Expression>,
83        right: Box<Expression>,
84    },
85
86    /// Less than comparison (<)
87    Lt {
88        left: Box<Expression>,
89        right: Box<Expression>,
90    },
91
92    /// Less than or equal comparison (<=)
93    Le {
94        left: Box<Expression>,
95        right: Box<Expression>,
96    },
97
98    /// Greater than comparison (>)
99    Gt {
100        left: Box<Expression>,
101        right: Box<Expression>,
102    },
103
104    /// Greater than or equal comparison (>=)
105    Ge {
106        left: Box<Expression>,
107        right: Box<Expression>,
108    },
109
110    // ===== i64 Comparisons =====
111    /// Equal comparison for i64
112    Eq64 {
113        left: Box<Expression>,
114        right: Box<Expression>,
115    },
116
117    /// Not equal comparison for i64
118    Ne64 {
119        left: Box<Expression>,
120        right: Box<Expression>,
121    },
122
123    /// Less than comparison for i64
124    Lt64 {
125        left: Box<Expression>,
126        right: Box<Expression>,
127    },
128
129    /// Less than or equal comparison for i64
130    Le64 {
131        left: Box<Expression>,
132        right: Box<Expression>,
133    },
134
135    /// Greater than comparison for i64
136    Gt64 {
137        left: Box<Expression>,
138        right: Box<Expression>,
139    },
140
141    /// Greater than or equal comparison for i64
142    Ge64 {
143        left: Box<Expression>,
144        right: Box<Expression>,
145    },
146
147    // ===== Logical Operations =====
148    /// Logical AND (&&)
149    And {
150        left: Box<Expression>,
151        right: Box<Expression>,
152    },
153
154    /// Logical OR (||)
155    Or {
156        left: Box<Expression>,
157        right: Box<Expression>,
158    },
159
160    /// Logical NOT (!)
161    Not { operand: Box<Expression> },
162
163    /// Null check (is null) - for i32 operands
164    IsNull { operand: Box<Expression> },
165
166    /// Not-null check (is not null) - for i32 operands
167    IsNotNull { operand: Box<Expression> },
168
169    /// Null check (is null) - for i64 operands
170    IsNull64 { operand: Box<Expression> },
171
172    /// Not-null check (is not null) - for i64 operands
173    IsNotNull64 { operand: Box<Expression> },
174
175    // ===== Arithmetic Operations =====
176    /// Addition (+)
177    Add {
178        left: Box<Expression>,
179        right: Box<Expression>,
180    },
181
182    /// Subtraction (-)
183    Sub {
184        left: Box<Expression>,
185        right: Box<Expression>,
186    },
187
188    /// Multiplication (*)
189    Mul {
190        left: Box<Expression>,
191        right: Box<Expression>,
192    },
193
194    /// Division (/)
195    Div {
196        left: Box<Expression>,
197        right: Box<Expression>,
198    },
199
200    // ===== i64 Arithmetic Operations =====
201    /// Addition for i64
202    Add64 {
203        left: Box<Expression>,
204        right: Box<Expression>,
205    },
206
207    /// Subtraction for i64
208    Sub64 {
209        left: Box<Expression>,
210        right: Box<Expression>,
211    },
212
213    /// Multiplication for i64
214    Mul64 {
215        left: Box<Expression>,
216        right: Box<Expression>,
217    },
218
219    /// Division for i64
220    Div64 {
221        left: Box<Expression>,
222        right: Box<Expression>,
223    },
224
225    // ===== Float Arithmetic Operations =====
226    /// Float addition (f64)
227    FloatAdd {
228        left: Box<Expression>,
229        right: Box<Expression>,
230    },
231
232    /// Float subtraction (f64)
233    FloatSub {
234        left: Box<Expression>,
235        right: Box<Expression>,
236    },
237
238    /// Float multiplication (f64)
239    FloatMul {
240        left: Box<Expression>,
241        right: Box<Expression>,
242    },
243
244    /// Float division (f64)
245    FloatDiv {
246        left: Box<Expression>,
247        right: Box<Expression>,
248    },
249
250    // ===== Math Functions =====
251    /// Square root (WASM f64.sqrt intrinsic)
252    Sqrt { operand: Box<Expression> },
253
254    /// Absolute value for floats (WASM f64.abs intrinsic)
255    FloatAbs { operand: Box<Expression> },
256
257    /// Round to nearest integer (WASM f64.nearest intrinsic)
258    Round { operand: Box<Expression> },
259
260    /// Floor (WASM f64.floor intrinsic)
261    Floor { operand: Box<Expression> },
262
263    /// Ceiling (WASM f64.ceil intrinsic)
264    Ceil { operand: Box<Expression> },
265
266    /// Sine (host call)
267    Sin { operand: Box<Expression> },
268
269    /// Cosine (host call)
270    Cos { operand: Box<Expression> },
271
272    /// Arc sine (host call)
273    Asin { operand: Box<Expression> },
274
275    /// Arc cosine (host call)
276    Acos { operand: Box<Expression> },
277
278    /// Arc tangent (host call)
279    Atan { operand: Box<Expression> },
280
281    /// Arc tangent of y/x (host call)
282    Atan2 {
283        y: Box<Expression>,
284        x: Box<Expression>,
285    },
286
287    /// Convert degrees to radians
288    Radians { operand: Box<Expression> },
289
290    /// Convert int to float
291    IntToFloat { operand: Box<Expression> },
292
293    /// Convert float to int (truncating)
294    FloatToInt { operand: Box<Expression> },
295
296    // ===== List Operations =====
297    /// Check if a list contains an element
298    ListContains {
299        list: Box<Expression>,
300        element: Box<Expression>,
301    },
302
303    /// Get the length of a collection
304    Length { collection: Box<Expression> },
305
306    /// Sum of field values over a collection
307    Sum {
308        collection: Box<Expression>,
309        item_var_name: String,
310        item_param_index: u32,
311        item_class_name: String,
312        accumulator_expr: Box<Expression>,
313    },
314
315    /// Access the last element of a collection
316    LastElement {
317        collection: Box<Expression>,
318        item_class_name: String,
319    },
320
321    // ===== Host Function Calls =====
322    /// Call a host-provided function
323    HostCall {
324        function_name: String,
325        args: Vec<Expression>,
326    },
327
328    // ===== Conditional =====
329    /// If-then-else conditional expression (produces i32)
330    IfThenElse {
331        condition: Box<Expression>,
332        then_branch: Box<Expression>,
333        else_branch: Box<Expression>,
334    },
335
336    /// If-then-else conditional expression (produces i64)
337    IfThenElse64 {
338        condition: Box<Expression>,
339        then_branch: Box<Expression>,
340        else_branch: Box<Expression>,
341    },
342
343    // ===== Type Conversions =====
344    /// Wrap i64 to i32 (truncate)
345    I64ToI32 { operand: Box<Expression> },
346
347    /// Extend i32 to i64 (signed)
348    I32ToI64 { operand: Box<Expression> },
349}