1#[macro_export]
8macro_rules! arithmetic_op {
9 ( $self:ident, $op:tt ) => {{ let b = $self.pop();
11 let a = $self.pop();
12 let result = fallible!($self, arithmetic_op!(&a, &b, $op));
13 $self.push(result);
14 }};
15
16 ( $a:expr, $b:expr, $op:tt ) => {{
17 match ($a, $b) {
18 (Value::Integer(i1), Value::Integer(i2)) => Ok(Value::Integer(i1 $op i2)),
19 (Value::Float(f1), Value::Float(f2)) => Ok(Value::Float(f1 $op f2)),
20 (Value::Integer(i1), Value::Float(f2)) => Ok(Value::Float(*i1 as f64 $op f2)),
21 (Value::Float(f1), Value::Integer(i2)) => Ok(Value::Float(f1 $op *i2 as f64)),
22
23 (v1, v2) => Err(ErrorKind::TypeError {
24 expected: "number (either int or float)",
25 actual: if v1.is_number() {
26 v2.type_of()
27 } else {
28 v1.type_of()
29 },
30 }),
31 }
32 }};
33}
34
35#[macro_export]
37macro_rules! cmp_op {
38 ( $vm:ident, $frame:ident, $span:ident, $op:tt ) => {{
39 lifted_pop! {
40 $vm(b, a) => {
41 async fn compare(a: Value, b: Value, co: GenCo) -> Result<Value, ErrorKind> {
42 let a = generators::request_force(&co, a).await;
43 let b = generators::request_force(&co, b).await;
44 let span = generators::request_span(&co).await;
45 let ordering = a.nix_cmp_ordering(b, co, span).await?;
46 match ordering {
47 Err(cek) => Ok(Value::from(cek)),
48 Ok(ordering) => Ok(Value::Bool(cmp_op!(@order $op ordering))),
49 }
50 }
51
52 let gen_span = $frame.current_span();
53 $vm.push_call_frame($span, $frame);
54 $vm.enqueue_generator("compare", gen_span, |co| compare(a, b, co));
55 return Ok(false);
56 }
57 }
58 }};
59
60 (@order < $ordering:expr) => {
61 $ordering == Ordering::Less
62 };
63
64 (@order > $ordering:expr) => {
65 $ordering == Ordering::Greater
66 };
67
68 (@order <= $ordering:expr) => {
69 matches!($ordering, Ordering::Equal | Ordering::Less)
70 };
71
72 (@order >= $ordering:expr) => {
73 matches!($ordering, Ordering::Equal | Ordering::Greater)
74 };
75}
76
77#[macro_export]
78macro_rules! lifted_pop {
79 ($vm:ident ($($bind:ident),+) => $body:expr) => {
80 {
81 $(
82 let $bind = $vm.stack_pop();
83 )+
84 $(
85 if $bind.is_catchable() {
86 $vm.stack.push($bind);
87 continue;
88 }
89 )+
90 $body
91 }
92 }
93}