Make integer coercion infallible
This commit is contained in:
parent
f6e6f8cea1
commit
56623de96a
|
@ -143,8 +143,8 @@ impl ExecEnv {
|
||||||
match kind {
|
match kind {
|
||||||
// Arithmetic operators.
|
// Arithmetic operators.
|
||||||
Add | Subtract | Multiply | Divide => {
|
Add | Subtract | Multiply | Divide => {
|
||||||
let lhs = lhs.try_into_i32(&expr.span)?;
|
let lhs = lhs.into_i32();
|
||||||
let rhs = rhs.try_into_i32(&expr.span)?;
|
let rhs = rhs.into_i32();
|
||||||
|
|
||||||
let res = match kind {
|
let res = match kind {
|
||||||
Add => lhs.checked_add(rhs),
|
Add => lhs.checked_add(rhs),
|
||||||
|
@ -159,8 +159,8 @@ impl ExecEnv {
|
||||||
|
|
||||||
// Numeric comparisons.
|
// Numeric comparisons.
|
||||||
Less | Greater => {
|
Less | Greater => {
|
||||||
let lhs = lhs.try_into_i32(&expr.span)?;
|
let lhs = lhs.into_i32();
|
||||||
let rhs = rhs.try_into_i32(&expr.span)?;
|
let rhs = rhs.into_i32();
|
||||||
|
|
||||||
let res = match kind {
|
let res = match kind {
|
||||||
Less => lhs < rhs,
|
Less => lhs < rhs,
|
||||||
|
@ -241,8 +241,7 @@ impl ExecEnv {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|tape_len| {
|
.map(|tape_len| {
|
||||||
self.eval_expr(tape_len)
|
self.eval_expr(tape_len)
|
||||||
.and_then(|v| v.try_into_i32(&stmt.span))
|
.map(|v| v.into_i32() as usize)
|
||||||
.map(|len| len as usize)
|
|
||||||
})
|
})
|
||||||
.unwrap_or(Ok(crate::brian::DEFAULT_TAPE_SIZE_LIMIT))?,
|
.unwrap_or(Ok(crate::brian::DEFAULT_TAPE_SIZE_LIMIT))?,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use std::{cell::RefCell, fmt::Display, io::Write, ops::Range, rc::Rc};
|
use std::{cell::RefCell, fmt::Display, io::Write, rc::Rc};
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::{
|
use crate::{ast::Stmt, consts};
|
||||||
ast::Stmt,
|
|
||||||
error::{Error, ErrorKind},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Abool {
|
pub enum Abool {
|
||||||
|
@ -119,35 +116,33 @@ impl Value {
|
||||||
.expect("Failed to write to Brainfuck input");
|
.expect("Failed to write to Brainfuck input");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to coerce a Value to an integer. If the conversion
|
/// Coerce a value to an integer.
|
||||||
/// fails, the generated error message is associated with the
|
pub fn into_i32(self) -> i32 {
|
||||||
/// given span.
|
|
||||||
pub fn try_into_i32(self, span: &Range<usize>) -> Result<i32, Error> {
|
|
||||||
match self {
|
match self {
|
||||||
Value::Int(i) => Ok(i),
|
Value::Abool(a) => a as _,
|
||||||
_ => Err(Error {
|
Value::Bool(b) => b as _,
|
||||||
kind: ErrorKind::TypeError(format!("expected int, got {}", self)),
|
Value::Functio(func) => match func {
|
||||||
span: span.clone(),
|
Functio::BfFunctio {
|
||||||
}),
|
instructions,
|
||||||
|
tape_len,
|
||||||
|
} => (instructions.len() + tape_len) as _,
|
||||||
|
Functio::AbleFunctio { params, body } => (params.len() + body.len()) as _,
|
||||||
|
},
|
||||||
|
Value::Int(i) => i,
|
||||||
|
Value::Nul => consts::ANSWER,
|
||||||
|
Value::Str(text) => text.parse().unwrap_or(consts::ANSWER),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Coerce a Value to a boolean. The conversion cannot fail.
|
/// Coerce a Value to a boolean. The conversion cannot fail.
|
||||||
pub fn into_bool(self) -> bool {
|
pub fn into_bool(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
// Booleans and abooleans have a trivial conversion.
|
|
||||||
Value::Bool(b) => b,
|
|
||||||
Value::Abool(b) => b.into(),
|
Value::Abool(b) => b.into(),
|
||||||
// The empty string is falsey, other strings are truthy.
|
Value::Bool(b) => b,
|
||||||
Value::Str(s) => !s.is_empty(),
|
|
||||||
// 0 is falsey, nonzero is truthy.
|
|
||||||
Value::Int(x) => x != 0,
|
|
||||||
// Functios are always truthy.
|
|
||||||
Value::Functio(_) => true,
|
Value::Functio(_) => true,
|
||||||
// And nul is truthy as a symbol of the fact that the
|
Value::Int(x) => x != 0,
|
||||||
// deep, fundamental truth of this world is nothing but
|
|
||||||
// the eternal void.
|
|
||||||
Value::Nul => true,
|
Value::Nul => true,
|
||||||
|
Value::Str(s) => !s.is_empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue