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:
parent
ce02aebd91
commit
528de718dc
121
src/interpret.rs
121
src/interpret.rs
|
@ -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(),
|
||||||
|
|
Loading…
Reference in a new issue