Skip to content
This repository was archived by the owner on Jan 25, 2024. It is now read-only.

Commit a40d0e0

Browse files
committed
use macro for binops
1 parent fd068a8 commit a40d0e0

File tree

1 file changed

+46
-58
lines changed

1 file changed

+46
-58
lines changed

src/eval.rs

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -103,78 +103,66 @@ impl Tree {
103103
right.as_ref()?.eval()
104104
}
105105
}
106+
107+
#[allow(clippy::enum_glob_use)]
108+
#[allow(clippy::float_cmp)] // We want to match the Nix reference implementation
106109
TreeSource::BinOp { op, left, right } => {
107110
use BinOpKind::*;
108111
use NixValue::*;
109-
let tmp1 = left.as_ref()?.eval()?;
110-
let tmp2 = right.as_ref()?.eval()?;
111-
let left = tmp1.borrow();
112-
let right = tmp2.borrow();
113-
let out = match (op, left, right) {
114-
(Add, Integer(x), Integer(y)) => Integer(x + y),
115-
(Add, Float(x), Float(y)) => Float(x + y),
116-
(Add, Integer(x), Float(y)) => Float(*x as f64 + y),
117-
(Add, Float(x), Integer(y)) => Float(x + *y as f64),
118-
119-
(Sub, Integer(x), Integer(y)) => Integer(x - y),
120-
(Sub, Float(x), Float(y)) => Float(x - y),
121-
(Sub, Integer(x), Float(y)) => Float(*x as f64 - y),
122-
(Sub, Float(x), Integer(y)) => Float(x - *y as f64),
123-
124-
(Mul, Integer(x), Integer(y)) => Integer(x * y),
125-
(Mul, Float(x), Float(y)) => Float(x * y),
126-
(Mul, Integer(x), Float(y)) => Float(*x as f64 * y),
127-
(Mul, Float(x), Integer(y)) => Float(x * *y as f64),
128-
129-
(Div, Integer(x), Integer(y)) => Integer(
130-
x.checked_div(*y)
131-
.ok_or_else(|| EvalError::Unexpected("division by zero".to_string()))?,
132-
),
133-
(Div, Float(x), Float(y)) => Float(x / y),
134-
(Div, Integer(x), Float(y)) => Float(*x as f64 / y),
135-
(Div, Float(x), Integer(y)) => Float(x / *y as f64),
136-
137-
// It seems like the Nix reference implementation compares floats exactly
138-
// https://github.com/NixOS/nix/blob/4a5aa1dbf6/src/libutil/comparator.hh#L26
139-
(Equal, Integer(x), Integer(y)) => Bool(x == y),
140-
(Equal, Float(x), Float(y)) => Bool(x == y),
141-
(Equal, Integer(x), Float(y)) => Bool(*x as f64 == *y),
142-
(Equal, Float(x), Integer(y)) => Bool(*x == *y as f64),
143-
(Equal, Bool(x), Bool(y)) => Bool(x == y),
144112

145-
(NotEqual, Integer(x), Integer(y)) => Bool(x != y),
146-
(NotEqual, Float(x), Float(y)) => Bool(x != y),
147-
(NotEqual, Integer(x), Float(y)) => Bool(*x as f64 != *y),
148-
(NotEqual, Float(x), Integer(y)) => Bool(*x != *y as f64),
149-
(NotEqual, Bool(x), Bool(y)) => Bool(x != y),
113+
// Workaround for "temporary value dropped while borrowed"
114+
// https://doc.rust-lang.org/error-index.html#E0716
115+
let left_tmp = left.as_ref()?.eval()?;
116+
let left_val = left_tmp.borrow();
117+
let right_tmp = right.as_ref()?.eval()?;
118+
let right_val = right_tmp.borrow();
150119

151-
(Less, Integer(x), Integer(y)) => Bool(x < y),
152-
(Less, Float(x), Float(y)) => Bool(x < y),
153-
(Less, Integer(x), Float(y)) => Bool((*x as f64) < *y),
154-
(Less, Float(x), Integer(y)) => Bool(*x < *y as f64),
155-
156-
(LessOrEq, Integer(x), Integer(y)) => Bool(x <= y),
157-
(LessOrEq, Float(x), Float(y)) => Bool(x <= y),
158-
(LessOrEq, Integer(x), Float(y)) => Bool(*x as f64 <= *y),
159-
(LessOrEq, Float(x), Integer(y)) => Bool(*x <= *y as f64),
160-
161-
(Greater, Integer(x), Integer(y)) => Bool(x > y),
162-
(Greater, Float(x), Float(y)) => Bool(x > y),
163-
(Greater, Integer(x), Float(y)) => Bool(*x as f64 > *y),
164-
(Greater, Float(x), Integer(y)) => Bool(*x > (*y as f64)),
120+
// Specially handle integer division by zero
121+
if let (Div, Integer(_), Integer(0)) = (op, left_val, right_val) {
122+
return Err(EvalError::Unexpected("division by zero".to_string()));
123+
}
165124

166-
(GreaterOrEq, Integer(x), Integer(y)) => Bool(x >= y),
167-
(GreaterOrEq, Float(x), Float(y)) => Bool(x >= y),
168-
(GreaterOrEq, Integer(x), Float(y)) => Bool(*x as f64 >= *y),
169-
(GreaterOrEq, Float(x), Integer(y)) => Bool(*x >= (*y as f64)),
125+
macro_rules! match_binops {
126+
( arithmetic [ $( $arith_kind:pat => $arith_oper:tt, )+ ],
127+
comparisons [ $( $comp_kind:pat => $comp_oper:tt, )+ ],
128+
$( $pattern:pat => $expr:expr ),* ) => {
129+
match (op, left_val, right_val) {
130+
$(
131+
($arith_kind, Integer(x), Integer(y)) => Integer(x $arith_oper y),
132+
($arith_kind, Float(x), Float(y)) => Float(x $arith_oper y),
133+
($arith_kind, Integer(x), Float(y)) => Float((*x as f64) $arith_oper y),
134+
($arith_kind, Float(x), Integer(y)) => Float(x $arith_oper (*y as f64)),
135+
)*
136+
$(
137+
($comp_kind, Integer(x), Integer(y)) => Bool(x $comp_oper y),
138+
($comp_kind, Float(x), Float(y)) => Bool(x $comp_oper y),
139+
($comp_kind, Integer(x), Float(y)) => Bool((*x as f64) $comp_oper *y),
140+
($comp_kind, Float(x), Integer(y)) => Bool(*x $comp_oper (*y as f64)),
141+
)*
142+
$(
143+
$pattern => $expr,
144+
)*
145+
}
146+
};
147+
}
170148

149+
let out = match_binops! {
150+
arithmetic [
151+
Add => +, Sub => -, Mul => *, Div => /,
152+
],
153+
comparisons [
154+
Equal => ==, NotEqual => !=,
155+
Greater => >, GreaterOrEq => >=,
156+
Less => <, LessOrEq => <=,
157+
],
171158
_ => {
172159
return Err(EvalError::Unexpected(format!(
173160
"{:?} {:?} {:?} unsupported",
174161
left, op, right
175162
)))
176163
}
177164
};
165+
178166
Ok(Gc::new(out))
179167
}
180168
TreeSource::UnaryInvert { value } => {

0 commit comments

Comments
 (0)