compose_eval/expression/
unary.rs1use crate::access::Access;
2use crate::{Eval, Evaluated, Machine};
3use compose_library::diag::{At, SourceResult, StrResult, bail};
4use compose_library::{Heap, Value, ops};
5use compose_syntax::ast::{AstNode, UnOp, Unary};
6
7impl Eval for Unary<'_> {
8 fn eval(self, vm: &mut Machine) -> SourceResult<Evaluated> {
9 let rhs = self.expr().eval(vm)?;
10
11 match self.op() {
12 UnOp::Plus => ops::unary_plus(rhs.value).map(Evaluated::mutable),
13 UnOp::Minus => ops::unary_minus(rhs.value).map(Evaluated::mutable),
14 UnOp::Bang => ops::unary_not(rhs.value).map(Evaluated::mutable),
15 UnOp::Tilde => ops::unary_bitwise_not(rhs.value).map(Evaluated::mutable),
16 UnOp::Star => deref(rhs, &vm.heap),
17 }
18 .at(self.span())
19 }
20}
21
22fn deref(rhs: Evaluated, heap: &Heap) -> StrResult<Evaluated> {
23 match rhs.value {
24 Value::Box(b) => match b.get(heap) {
25 Some(value) => Ok(Evaluated::new(value.clone(), rhs.mutable)),
26 None => bail!("Use after free. This is a bug"),
27 },
28 _ => bail!(
29 "only boxed values can be dereferenced. got a {}",
30 rhs.value.ty()
31 ),
32 }
33}
34
35impl Access for Unary<'_> {
36 fn access<'a>(self, vm: &'a mut Machine) -> SourceResult<&'a mut Value> {
37 match self.op() {
38 UnOp::Star => access_deref(self, vm),
39 _ => bail!(
40 self.span(),
41 "cannot access unary expression with operator {:?}",
42 self.op();
43 note: "only dereferencing with `*` is supported"
44 ),
45 }
46 }
47}
48
49fn access_deref<'a>(unary: Unary, vm: &'a mut Machine) -> SourceResult<&'a mut Value> {
50 let span = unary.span();
51 let expr = unary.expr();
52 let value_ref = expr.access(vm)?;
53
54 if let Value::Box(box_value) = value_ref {
55 let heap_ref = box_value.clone();
56 match heap_ref.get_mut(&mut vm.heap) {
57 Some(v) => Ok(v),
58 None => bail!(span, "use after free. this is a bug"),
59 }
60 } else {
61 bail!(span, "cannot deref non-box value");
62 }
63}