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 let Some(op) = prefix.op() else {
22 return value;
23 };
24
25 match op.kind() {
26 T![!] => {
27 if ctx.is_assignable(value.ty, ctx.builtins().types.bool) {
28 let is_true = ctx.is_assignable(value.ty, ctx.builtins().types.bool_true);
29 let is_false = ctx.is_assignable(value.ty, ctx.builtins().types.bool_false);
30
31 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::Not, value.hir));
32
33 return value.flip_mappings().with_hir(hir).with_type(if is_true {
34 ctx.builtins().types.bool_false
35 } else if is_false {
36 ctx.builtins().types.bool_true
37 } else {
38 ctx.builtins().types.bool
39 });
40 }
41 }
42 T![+] => {
43 if ctx.is_assignable(value.ty, ctx.builtins().types.int) {
44 ctx.diagnostic(prefix.syntax(), DiagnosticKind::UnnecessaryPlus);
45 return Value::new(value.hir, ctx.builtins().types.int);
46 }
47 }
48 T![-] => {
49 if ctx.is_assignable(value.ty, ctx.builtins().types.int) {
50 let ty = if let Some(Atoms::Restricted(restrictions)) =
51 rue_types::extract_atoms(ctx.types_mut(), value.ty, true)
52 && restrictions.len() == 1
53 && let Some(AtomRestriction::Value(value)) = restrictions.iter().next()
54 {
55 ctx.alloc_type(Type::Atom(Atom::new(
56 AtomSemantic::Int,
57 Some(AtomRestriction::Value(Cow::Owned(bigint_atom(
58 -atom_bigint(value),
59 )))),
60 )))
61 } else {
62 ctx.builtins().types.int
63 };
64
65 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::Neg, value.hir));
66 return Value::new(hir, ty);
67 }
68
69 if ctx.is_assignable(value.ty, ctx.builtins().types.public_key) {
70 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::G1Negate, value.hir));
71 return Value::new(hir, ctx.builtins().types.public_key);
72 }
73
74 if ctx.is_assignable(value.ty, ctx.builtins().types.signature) {
75 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::G2Negate, value.hir));
76 return Value::new(hir, ctx.builtins().types.signature);
77 }
78 }
79 T![~] => {
80 if ctx.is_assignable(value.ty, ctx.builtins().types.int) {
81 let hir = ctx.alloc_hir(Hir::Unary(UnaryOp::BitwiseNot, value.hir));
82 return Value::new(hir, ctx.builtins().types.int);
83 }
84 }
85 _ => {}
86 }
87
88 debug!("Unresolved prefix expr due to incompatible op");
89
90 let type_name = ctx.type_name(value.ty);
91 ctx.diagnostic(
92 prefix.syntax(),
93 DiagnosticKind::IncompatibleUnaryOp(op.text().to_string(), type_name),
94 );
95 ctx.builtins().unresolved.clone()
96}