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(
183 BinaryOp::LeftArithmeticShift,
184 left.hir,
185 right.hir,
186 ));
187 return Value::new(hir, ctx.builtins().types.int);
188 }
189
190 (left, right)
191 }
192 T![>>] => {
193 let left = left(ctx);
194 let right = right(ctx, None);
195
196 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
197 debug!("Unresolved binary expr operands");
198 return ctx.builtins().unresolved.clone();
199 }
200
201 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
202 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
203 let hir = ctx.alloc_hir(Hir::Binary(
204 BinaryOp::RightArithmeticShift,
205 left.hir,
206 right.hir,
207 ));
208 return Value::new(hir, ctx.builtins().types.int);
209 }
210
211 (left, right)
212 }
213 T![>>>] => {
214 let left = left(ctx);
215 let right = right(ctx, None);
216
217 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
218 debug!("Unresolved binary expr operands");
219 return ctx.builtins().unresolved.clone();
220 }
221
222 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
223 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
224 let hir = ctx.alloc_hir(Hir::Binary(
225 BinaryOp::RightLogicalShift,
226 left.hir,
227 right.hir,
228 ));
229 return Value::new(hir, ctx.builtins().types.int);
230 }
231
232 (left, right)
233 }
234 T![>] => {
235 let left = left(ctx);
236 let right = right(ctx, None);
237
238 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
239 debug!("Unresolved binary expr operands");
240 return ctx.builtins().unresolved.clone();
241 }
242
243 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
244 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
245 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Gt, left.hir, right.hir));
246 return Value::new(hir, ctx.builtins().types.bool);
247 }
248
249 if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
250 ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
251 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::GtBytes, left.hir, right.hir));
252 return Value::new(hir, ctx.builtins().types.bool);
253 }
254
255 (left, right)
256 }
257 T![<] => {
258 let left = left(ctx);
259 let right = right(ctx, None);
260
261 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
262 debug!("Unresolved binary expr operands");
263 return ctx.builtins().unresolved.clone();
264 }
265
266 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
267 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
268 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Lt, left.hir, right.hir));
269 return Value::new(hir, ctx.builtins().types.bool);
270 }
271
272 if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
273 ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
274 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::LtBytes, left.hir, right.hir));
275 return Value::new(hir, ctx.builtins().types.bool);
276 }
277
278 (left, right)
279 }
280 T![>=] => {
281 let left = left(ctx);
282 let right = right(ctx, None);
283
284 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
285 debug!("Unresolved binary expr operands");
286 return ctx.builtins().unresolved.clone();
287 }
288
289 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
290 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
291 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Gte, left.hir, right.hir));
292 return Value::new(hir, ctx.builtins().types.bool);
293 }
294
295 if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
296 ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
297 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::GteBytes, left.hir, right.hir));
298 return Value::new(hir, ctx.builtins().types.bool);
299 }
300
301 (left, right)
302 }
303 T![<=] => {
304 let left = left(ctx);
305 let right = right(ctx, None);
306
307 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
308 debug!("Unresolved binary expr operands");
309 return ctx.builtins().unresolved.clone();
310 }
311
312 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
313 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
314 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Lte, left.hir, right.hir));
315 return Value::new(hir, ctx.builtins().types.bool);
316 }
317
318 if ctx.is_assignable(left.ty, ctx.builtins().types.bytes) {
319 ctx.assign_type(&op, right.ty, ctx.builtins().types.bytes);
320 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::LteBytes, left.hir, right.hir));
321 return Value::new(hir, ctx.builtins().types.bool);
322 }
323
324 (left, right)
325 }
326 T![&&] => {
327 let left = left(ctx);
328 let right = right(ctx, Some(left.then_map.clone()));
329
330 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
331 debug!("Unresolved binary expr operands");
332 return ctx.builtins().unresolved.clone();
333 }
334
335 if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
336 ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
337 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::And, left.hir, right.hir));
338 return Value::new(hir, ctx.builtins().types.bool).with_mappings(
339 merge_mappings(&left.then_map, &right.then_map),
340 HashMap::new(),
341 );
342 }
343
344 (left, right)
345 }
346 T![||] => {
347 let left = left(ctx);
348 let right = right(ctx, Some(left.else_map.clone()));
349
350 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
351 debug!("Unresolved binary expr operands");
352 return ctx.builtins().unresolved.clone();
353 }
354
355 if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
356 ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
357 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Or, left.hir, right.hir));
358 return Value::new(hir, ctx.builtins().types.bool).with_mappings(
359 HashMap::new(),
360 merge_mappings(&left.else_map, &right.else_map),
361 );
362 }
363
364 (left, right)
365 }
366 T![&] => {
367 let left = left(ctx);
368 let right = right(ctx, None);
369
370 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
371 debug!("Unresolved binary expr operands");
372 return ctx.builtins().unresolved.clone();
373 }
374
375 if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
376 ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
377 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::All, left.hir, right.hir));
378 return Value::new(hir, ctx.builtins().types.bool).with_mappings(
379 merge_mappings(&left.then_map, &right.then_map),
380 HashMap::new(),
381 );
382 }
383
384 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
385 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
386 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::BitwiseAnd, left.hir, right.hir));
387 return Value::new(hir, ctx.builtins().types.int);
388 }
389
390 (left, right)
391 }
392 T![|] => {
393 let left = left(ctx);
394 let right = right(ctx, None);
395
396 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
397 debug!("Unresolved binary expr operands");
398 return ctx.builtins().unresolved.clone();
399 }
400
401 if ctx.is_assignable(left.ty, ctx.builtins().types.bool) {
402 ctx.assign_type(&op, right.ty, ctx.builtins().types.bool);
403 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::Any, left.hir, right.hir));
404 return Value::new(hir, ctx.builtins().types.bool).with_mappings(
405 HashMap::new(),
406 merge_mappings(&left.then_map, &right.then_map),
407 );
408 }
409
410 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
411 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
412 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::BitwiseOr, left.hir, right.hir));
413 return Value::new(hir, ctx.builtins().types.int);
414 }
415
416 (left, right)
417 }
418 T![^] => {
419 let left = left(ctx);
420 let right = right(ctx, None);
421
422 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
423 debug!("Unresolved binary expr operands");
424 return ctx.builtins().unresolved.clone();
425 }
426
427 if ctx.is_assignable(left.ty, ctx.builtins().types.int) {
428 ctx.assign_type(&op, right.ty, ctx.builtins().types.int);
429 let hir = ctx.alloc_hir(Hir::Binary(BinaryOp::BitwiseXor, left.hir, right.hir));
430 return Value::new(hir, ctx.builtins().types.int);
431 }
432
433 (left, right)
434 }
435 T![==] | T![!=] => {
436 let left = left(ctx);
439 let right = right(ctx, None);
440
441 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
442 debug!("Unresolved binary expr operands");
443 return ctx.builtins().unresolved.clone();
444 }
445
446 let types = [
447 ctx.builtins().types.bool,
448 ctx.builtins().types.int,
449 ctx.builtins().types.bytes,
450 ctx.builtins().types.public_key,
451 ctx.builtins().types.signature,
452 ];
453
454 if types
455 .iter()
456 .any(|ty| ctx.is_assignable(left.ty, *ty) && ctx.is_assignable(right.ty, *ty))
457 {
458 let hir = if op.kind() == T![==] {
459 ctx.alloc_hir(Hir::Binary(BinaryOp::Eq, left.hir, right.hir))
460 } else {
461 ctx.alloc_hir(Hir::Binary(BinaryOp::Ne, left.hir, right.hir))
462 };
463
464 let mut value = Value::new(hir, ctx.builtins().types.bool);
465
466 if op.kind() == T![!=] {
467 value = value.flip_mappings();
468 }
469
470 return value;
471 }
472
473 (left, right)
474 }
475 _ => {
476 let left = left(ctx);
477 let right = right(ctx, None);
478
479 if ctx.is_unresolved(left.ty) || ctx.is_unresolved(right.ty) {
480 debug!("Unresolved binary expr operands");
481 return ctx.builtins().unresolved.clone();
482 }
483
484 (left, right)
485 }
486 };
487
488 let left_name = ctx.type_name(left.ty);
489 let right_name = ctx.type_name(right.ty);
490
491 debug!("Unresolved binary expr");
492
493 ctx.diagnostic(
494 binary.syntax(),
495 DiagnosticKind::IncompatibleBinaryOp(op.text().to_string(), left_name, right_name),
496 );
497 ctx.builtins().unresolved.clone()
498}