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 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}