compose_eval/expression/
unary.rs

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