Clean up eval_expr some more

I keep going back and forth on how I want this block to look :P
Anyway, this is *probably* its final-ish form, until the parser gets
re-written.
This commit is contained in:
Alex Bethel 2021-06-02 18:41:20 -05:00
parent d80f47716d
commit 98b2fae6f3

View file

@ -113,55 +113,86 @@ impl ExecEnv {
use Expr::*; use Expr::*;
use Value::*; use Value::*;
// NOTE(Alex): This is really quite horrible. I think the only // NOTE(Alex): This block will get a whole lot cleaner once
// real way to clean it up would be to re-engineer the AST's // Ondra's parser stuff gets merged (specifically 97fb19e).
// representation to be more hierarchical: rather than having // For now, though, we've got a bunch of manually-checked
// e.g. "Expr::Add" and "Expr::Subtract" each with a "left" // unreachable!()s in here which makes me sad...
// and "right" struct member, have something like
// "Expr::Binary { oper: BinOp, left: Box<Expr>, right:
// Box<Expr> }". That way we could factor out a whole bunch of
// common code here.
//
// That work should probably wait for Ondra's new parser to
// come in, however.
Ok(match expr { Ok(match expr {
Add { left, right } => Int(i32::try_from(self.eval_expr(left)?)? // Binary expressions.
.checked_add(i32::try_from(self.eval_expr(right)?)?) Add { left, right }
.ok_or(Error { | Subtract { left, right }
kind: ErrorKind::ArithmeticError, | Multiply { left, right }
position: 0..0, | Divide { left, right }
})?), | Lt { left, right }
Subtract { left, right } => Int(i32::try_from(self.eval_expr(left)?)? | Gt { left, right }
.checked_sub(i32::try_from(self.eval_expr(right)?)?) | Eq { left, right }
.ok_or(Error { | Neq { left, right }
kind: ErrorKind::ArithmeticError, | And { left, right }
position: 0..0, | Or { left, right } => {
})?), let left = self.eval_expr(left)?;
Multiply { left, right } => Int(i32::try_from(self.eval_expr(left)?)? let right = self.eval_expr(right)?;
.checked_mul(i32::try_from(self.eval_expr(right)?)?)
.ok_or(Error { match expr {
kind: ErrorKind::ArithmeticError, // Arithmetic operators.
position: 0..0, Add { .. }
})?), | Subtract { .. }
Divide { left, right } => Int(i32::try_from(self.eval_expr(left)?)? | Multiply { .. }
.checked_div(i32::try_from(self.eval_expr(right)?)?) | Divide { .. } => {
.ok_or(Error { let left = i32::try_from(left)?;
kind: ErrorKind::ArithmeticError, let right = i32::try_from(right)?;
position: 0..0,
})?), let res = match expr {
Lt { left, right } => { Add { .. } => left.checked_add(right),
Bool(i32::try_from(self.eval_expr(left)?)? < i32::try_from(self.eval_expr(right)?)?) Subtract { .. } => left.checked_sub(right),
Multiply { .. } => left.checked_mul(right),
Divide { .. } => left.checked_div(right),
_ => unreachable!(),
} }
Gt { left, right } => { .ok_or(Error {
Bool(i32::try_from(self.eval_expr(left)?)? > i32::try_from(self.eval_expr(right)?)?) kind: ErrorKind::ArithmeticError,
position: 0..0,
})?;
Int(res)
} }
Eq { left, right } => Bool(self.eval_expr(left)? == self.eval_expr(right)?),
Neq { left, right } => Bool(self.eval_expr(left)? != self.eval_expr(right)?), // Numeric comparisons.
And { left, right } => { Lt { .. } | Gt { .. } => {
Bool(bool::from(self.eval_expr(left)?) && bool::from(self.eval_expr(right)?)) let left = i32::try_from(left)?;
let right = i32::try_from(right)?;
let res = match expr {
Lt { .. } => left < right,
Gt { .. } => left > right,
_ => unreachable!(),
};
Bool(res)
}
// General comparisons.
Eq { .. } | Neq { .. } => {
let res = match expr {
Eq { .. } => left == right,
Neq { .. } => left != right,
_ => unreachable!(),
};
Bool(res)
}
// Logical connectives.
And { .. } | Or { .. } => {
let left = bool::from(left);
let right = bool::from(right);
let res = match expr {
And { .. } => left && right,
Or { .. } => left || right,
_ => unreachable!(),
};
Bool(res)
}
// That's all the binary operations.
_ => unreachable!(),
} }
Or { left, right } => {
Bool(bool::from(self.eval_expr(left)?) || bool::from(self.eval_expr(right)?))
} }
Not(expr) => Bool(!bool::from(self.eval_expr(expr)?)), Not(expr) => Bool(!bool::from(self.eval_expr(expr)?)),
Literal(value) => value.clone(), Literal(value) => value.clone(),