rue_compiler/compile/expr/
prefix.rs1use std::borrow::Cow;
2
3use log::debug;
4use rue_ast::{AstNode, AstPrefixExpr};
5use rue_diagnostic::DiagnosticKind;
6use rue_hir::{Hir, UnaryOp, Value};
7use rue_lir::{atom_bigint, bigint_atom};
8use rue_parser::T;
9use rue_types::{Atom, AtomRestriction, AtomSemantic, Atoms, Type};
10
11use crate::{Compiler, compile_expr};
12
13pub fn compile_prefix_expr(ctx: &mut Compiler, prefix: &AstPrefixExpr) -> Value {
14 let Some(expr) = prefix.expr() else {
15 debug!("Unresolved prefix expr");
16 return ctx.builtins().unresolved.clone();
17 };
18
19 let value = compile_expr(ctx, &expr, None);
20
21 if ctx.is_unresolved(value.ty) {
22 debug!("Unresolved prefix expr");
23 return ctx.builtins().unresolved.clone();
24 }
25
26 let Some(op) = prefix.op() else {
27 return value;
28 };
29
30 match op.kind() {
31 T![!] => {
32 if ctx.is_assignable(value.ty, ctx.builtins().types.bool) {
33 let is_true = ctx.is_assignable(value.ty, ctx.builtins().types.bool_true);
34 let is_false = ctx.is_assignable(value.ty, ctx.builtins().types.bool_false);
35
36 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::Not, value.hir));
37
38 return value.flip_mappings().with_hir(hir).with_type(if is_true {
39 ctx.builtins().types.bool_false
40 } else if is_false {
41 ctx.builtins().types.bool_true
42 } else {
43 ctx.builtins().types.bool
44 });
45 }
46 }
47 T![+] => {
48 if ctx.is_assignable(value.ty, ctx.builtins().types.int) {
49 ctx.diagnostic(prefix.syntax(), DiagnosticKind::UnnecessaryPlus);
50 return Value::new(value.hir, ctx.builtins().types.int);
51 }
52 }
53 T![-] => {
54 if ctx.is_assignable(value.ty, ctx.builtins().types.int) {
55 let ty = if let Some(Atoms::Restricted(restrictions)) =
56 rue_types::extract_atoms(ctx.types_mut(), value.ty, true)
57 && restrictions.len() == 1
58 && let Some(AtomRestriction::Value(value)) = restrictions.iter().next()
59 {
60 ctx.alloc_type(Type::Atom(Atom::new(
61 AtomSemantic::Int,
62 Some(AtomRestriction::Value(Cow::Owned(bigint_atom(
63 -atom_bigint(value),
64 )))),
65 )))
66 } else {
67 ctx.builtins().types.int
68 };
69
70 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::Neg, value.hir));
71 return Value::new(hir, ty);
72 }
73
74 if ctx.is_assignable(value.ty, ctx.builtins().types.public_key) {
75 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::G1Negate, value.hir));
76 return Value::new(hir, ctx.builtins().types.public_key);
77 }
78
79 if ctx.is_assignable(value.ty, ctx.builtins().types.signature) {
80 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::G2Negate, value.hir));
81 return Value::new(hir, ctx.builtins().types.signature);
82 }
83 }
84 T![~] => {
85 if ctx.is_assignable(value.ty, ctx.builtins().types.int) {
86 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::BitwiseNot, value.hir));
87 return Value::new(hir, ctx.builtins().types.int);
88 }
89 }
90 _ => {}
91 }
92
93 debug!("Unresolved prefix expr due to incompatible op");
94
95 let type_name = ctx.type_name(value.ty);
96 ctx.diagnostic(
97 prefix.syntax(),
98 DiagnosticKind::IncompatibleUnaryOp(op.text().to_string(), type_name),
99 );
100 ctx.builtins().unresolved.clone()
101}