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}