rue_compiler/compile/expr/
binary.rs

1use std::collections::HashMap;
2
3use log::debug;
4use rue_ast::{AstBinaryExpr, AstNode};
5use rue_diagnostic::DiagnosticKind;
6use rue_hir::{BinaryOp, Hir, Mappings, Value, merge_mappings};
7use rue_parser::T;
8
9use crate::{Compiler, compile_expr};
10
11pub fn compile_binary_expr(ctx: &mut Compiler, binary: &AstBinaryExpr) -> Value {
12    let left = |ctx: &mut Compiler| {
13        if let Some(left) = binary.left() {
14            compile_expr(ctx, &left, None)
15        } else {
16            debug!("Unresolved lhs in binary expr");
17            ctx.builtins().unresolved.clone()
18        }
19    };
20
21    let right = |ctx: &mut Compiler, mappings: Option<Mappings>| {
22        if let Some(right) = binary.right() {
23            if let Some(mappings) = mappings {
24                let range = right.syntax().text_range();
25                let index = ctx.push_mappings(mappings, range.start());
26                let value = compile_expr(ctx, &right, None);
27                ctx.revert_mappings(index, range.end());
28                value
29            } else {
30                compile_expr(ctx, &right, None)
31            }
32        } else {
33            debug!("Unresolved rhs in binary expr");
34            ctx.builtins().unresolved.clone()
35        }
36    };
37
38    let Some(op) = binary.op() else {
39        debug!("Unresolved op in binary expr");
40        return ctx.builtins().unresolved.clone();
41    };
42
43    let (left, right) = match op.kind() {
44        T![+] => {
45            let left = left(ctx);
46            let right = right(ctx, None);
47
48            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
49                debug!("Unresolved binary expr operands");
50                return ctx.builtins().unresolved.clone();
51            }
52
53            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
54                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
55                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Add, left.hir, right.hir));
56                return Value::new(hir, ctx.builtins().types.int);
57            }
58
59            if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
60                ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
61                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Concat, left.hir, right.hir));
62                return Value::new(hir, ctx.builtins().types.bytes);
63            }
64
65            if ctx.is_assignable(left.ty, ctx.builtins().types.public_key) {
66                ctx.assign_type(&op, right.ty, ctx.builtins().types.public_key);
67                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::G1Add, left.hir, right.hir));
68                return Value::new(hir, ctx.builtins().types.public_key);
69            }
70
71            if ctx.is_assignable(left.ty, ctx.builtins().types.signature) {
72                ctx.assign_type(&op, right.ty, ctx.builtins().types.signature);
73                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::G2Add, left.hir, right.hir));
74                return Value::new(hir, ctx.builtins().types.signature);
75            }
76
77            (left, right)
78        }
79        T![-] => {
80            let left = left(ctx);
81            let right = right(ctx, None);
82
83            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
84                debug!("Unresolved binary expr operands");
85                return ctx.builtins().unresolved.clone();
86            }
87
88            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
89                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
90                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Sub, left.hir, right.hir));
91                return Value::new(hir, ctx.builtins().types.int);
92            }
93
94            if ctx.is_assignable(left.ty, ctx.builtins().types.public_key) {
95                ctx.assign_type(&op, right.ty, ctx.builtins().types.public_key);
96                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::G1Subtract, left.hir, right.hir));
97                return Value::new(hir, ctx.builtins().types.public_key);
98            }
99
100            if ctx.is_assignable(left.ty, ctx.builtins().types.signature) {
101                ctx.assign_type(&op, right.ty, ctx.builtins().types.signature);
102                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::G2Subtract, left.hir, right.hir));
103                return Value::new(hir, ctx.builtins().types.signature);
104            }
105
106            (left, right)
107        }
108        T![*] => {
109            let left = left(ctx);
110            let right = right(ctx, None);
111
112            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
113                debug!("Unresolved binary expr operands");
114                return ctx.builtins().unresolved.clone();
115            }
116
117            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
118                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
119                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Mul, left.hir, right.hir));
120                return Value::new(hir, ctx.builtins().types.int);
121            }
122
123            if ctx.is_assignable(left.ty, ctx.builtins().types.public_key) {
124                ctx.assign_type(&op, right.ty, ctx.builtins().types.public_key);
125                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::G1Multiply, left.hir, right.hir));
126                return Value::new(hir, ctx.builtins().types.public_key);
127            }
128
129            if ctx.is_assignable(left.ty, ctx.builtins().types.signature) {
130                ctx.assign_type(&op, right.ty, ctx.builtins().types.signature);
131                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::G2Multiply, left.hir, right.hir));
132                return Value::new(hir, ctx.builtins().types.signature);
133            }
134
135            (left, right)
136        }
137        T![/] => {
138            let left = left(ctx);
139            let right = right(ctx, None);
140
141            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
142                debug!("Unresolved binary expr operands");
143                return ctx.builtins().unresolved.clone();
144            }
145
146            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
147                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
148                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Div, left.hir, right.hir));
149                return Value::new(hir, ctx.builtins().types.int);
150            }
151
152            (left, right)
153        }
154        T![%] => {
155            let left = left(ctx);
156            let right = right(ctx, None);
157
158            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
159                debug!("Unresolved binary expr operands");
160                return ctx.builtins().unresolved.clone();
161            }
162
163            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
164                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
165                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Mod, left.hir, right.hir));
166                return Value::new(hir, ctx.builtins().types.int);
167            }
168
169            (left, right)
170        }
171        T![<<] => {
172            let left = left(ctx);
173            let right = right(ctx, None);
174
175            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
176                debug!("Unresolved binary expr operands");
177                return ctx.builtins().unresolved.clone();
178            }
179
180            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
181                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
182                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::LeftShift, left.hir, right.hir));
183                return Value::new(hir, ctx.builtins().types.int);
184            }
185
186            (left, right)
187        }
188        T![>>] => {
189            let left = left(ctx);
190            let right = right(ctx, None);
191
192            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
193                debug!("Unresolved binary expr operands");
194                return ctx.builtins().unresolved.clone();
195            }
196
197            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
198                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
199                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::RightShift, left.hir, right.hir));
200                return Value::new(hir, ctx.builtins().types.int);
201            }
202
203            (left, right)
204        }
205        T![>] => {
206            let left = left(ctx);
207            let right = right(ctx, None);
208
209            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
210                debug!("Unresolved binary expr operands");
211                return ctx.builtins().unresolved.clone();
212            }
213
214            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
215                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
216                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Gt, left.hir, right.hir));
217                return Value::new(hir, ctx.builtins().types.bool);
218            }
219
220            if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
221                ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
222                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::GtBytes, left.hir, right.hir));
223                return Value::new(hir, ctx.builtins().types.bool);
224            }
225
226            (left, right)
227        }
228        T![<] => {
229            let left = left(ctx);
230            let right = right(ctx, None);
231
232            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
233                debug!("Unresolved binary expr operands");
234                return ctx.builtins().unresolved.clone();
235            }
236
237            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
238                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
239                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Lt, left.hir, right.hir));
240                return Value::new(hir, ctx.builtins().types.bool);
241            }
242
243            if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
244                ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
245                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::LtBytes, left.hir, right.hir));
246                return Value::new(hir, ctx.builtins().types.bool);
247            }
248
249            (left, right)
250        }
251        T![>=] => {
252            let left = left(ctx);
253            let right = right(ctx, None);
254
255            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
256                debug!("Unresolved binary expr operands");
257                return ctx.builtins().unresolved.clone();
258            }
259
260            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
261                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
262                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Gte, left.hir, right.hir));
263                return Value::new(hir, ctx.builtins().types.bool);
264            }
265
266            if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
267                ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
268                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::GteBytes, left.hir, right.hir));
269                return Value::new(hir, ctx.builtins().types.bool);
270            }
271
272            (left, right)
273        }
274        T![<=] => {
275            let left = left(ctx);
276            let right = right(ctx, None);
277
278            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
279                debug!("Unresolved binary expr operands");
280                return ctx.builtins().unresolved.clone();
281            }
282
283            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
284                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
285                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Lte, left.hir, right.hir));
286                return Value::new(hir, ctx.builtins().types.bool);
287            }
288
289            if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
290                ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
291                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::LteBytes, left.hir, right.hir));
292                return Value::new(hir, ctx.builtins().types.bool);
293            }
294
295            (left, right)
296        }
297        T![&&] => {
298            let left = left(ctx);
299            let right = right(ctx, Some(left.then_map.clone()));
300
301            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
302                debug!("Unresolved binary expr operands");
303                return ctx.builtins().unresolved.clone();
304            }
305
306            if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
307                ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
308                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::And, left.hir, right.hir));
309                return Value::new(hir, ctx.builtins().types.bool).with_mappings(
310                    merge_mappings(&left.then_map, &right.then_map),
311                    HashMap::new(),
312                );
313            }
314
315            (left, right)
316        }
317        T![||] => {
318            let left = left(ctx);
319            let right = right(ctx, Some(left.else_map.clone()));
320
321            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
322                debug!("Unresolved binary expr operands");
323                return ctx.builtins().unresolved.clone();
324            }
325
326            if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
327                ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
328                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Or, left.hir, right.hir));
329                return Value::new(hir, ctx.builtins().types.bool).with_mappings(
330                    HashMap::new(),
331                    merge_mappings(&left.else_map, &right.else_map),
332                );
333            }
334
335            (left, right)
336        }
337        T![&] => {
338            let left = left(ctx);
339            let right = right(ctx, None);
340
341            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
342                debug!("Unresolved binary expr operands");
343                return ctx.builtins().unresolved.clone();
344            }
345
346            if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
347                ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
348                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::All, left.hir, right.hir));
349                return Value::new(hir, ctx.builtins().types.bool).with_mappings(
350                    merge_mappings(&left.then_map, &right.then_map),
351                    HashMap::new(),
352                );
353            }
354
355            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
356                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
357                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::BitwiseAnd, left.hir, right.hir));
358                return Value::new(hir, ctx.builtins().types.int);
359            }
360
361            (left, right)
362        }
363        T![|] => {
364            let left = left(ctx);
365            let right = right(ctx, None);
366
367            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
368                debug!("Unresolved binary expr operands");
369                return ctx.builtins().unresolved.clone();
370            }
371
372            if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
373                ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
374                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Any, left.hir, right.hir));
375                return Value::new(hir, ctx.builtins().types.bool).with_mappings(
376                    HashMap::new(),
377                    merge_mappings(&left.then_map, &right.then_map),
378                );
379            }
380
381            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
382                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
383                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::BitwiseOr, left.hir, right.hir));
384                return Value::new(hir, ctx.builtins().types.int);
385            }
386
387            (left, right)
388        }
389        T![^] => {
390            let left = left(ctx);
391            let right = right(ctx, None);
392
393            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
394                debug!("Unresolved binary expr operands");
395                return ctx.builtins().unresolved.clone();
396            }
397
398            if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
399                ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
400                let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::BitwiseXor, left.hir, right.hir));
401                return Value::new(hir, ctx.builtins().types.int);
402            }
403
404            (left, right)
405        }
406        T![==] | T![!=] => {
407            // TODO: Guard?
408
409            let left = left(ctx);
410            let right = right(ctx, None);
411
412            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
413                debug!("Unresolved binary expr operands");
414                return ctx.builtins().unresolved.clone();
415            }
416
417            let types = [
418                ctx.builtins().types.bool,
419                ctx.builtins().types.int,
420                ctx.builtins().types.bytes,
421                ctx.builtins().types.public_key,
422                ctx.builtins().types.signature,
423            ];
424
425            if types
426                .iter()
427                .any(|ty| ctx.is_assignable(left.ty, *ty) && ctx.is_assignable(right.ty, *ty))
428            {
429                let hir = if op.kind() == T![==] {
430                    ctx.alloc_hir(Hir::Binary(BinaryOp::Eq, left.hir, right.hir))
431                } else {
432                    ctx.alloc_hir(Hir::Binary(BinaryOp::Ne, left.hir, right.hir))
433                };
434
435                let mut value = Value::new(hir, ctx.builtins().types.bool);
436
437                if op.kind() == T![!=] {
438                    value = value.flip_mappings();
439                }
440
441                return value;
442            }
443
444            (left, right)
445        }
446        _ => {
447            let left = left(ctx);
448            let right = right(ctx, None);
449
450            if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
451                debug!("Unresolved binary expr operands");
452                return ctx.builtins().unresolved.clone();
453            }
454
455            (left, right)
456        }
457    };
458
459    let left_name = ctx.type_name(left.ty);
460    let right_name = ctx.type_name(right.ty);
461
462    debug!("Unresolved binary expr");
463
464    ctx.diagnostic(
465        binary.syntax(),
466        DiagnosticKind::IncompatibleBinaryOp(op.text().to_string(), left_name, right_name),
467    );
468    ctx.builtins().unresolved.clone()
469}