From d3242484fc5967d26362cc6c2ec6a4bf52a41dbd Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Fri, 16 Jul 2021 18:56:45 -0500 Subject: [PATCH] Make integer coercion infallible --- src/interpret.rs | 11 +++++------ src/variables.rs | 43 +++++++++++++++++++------------------------ 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/interpret.rs b/src/interpret.rs index cc4b10ef..82473750 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -143,8 +143,8 @@ impl ExecEnv { match kind { // Arithmetic operators. Add | Subtract | Multiply | Divide => { - let lhs = lhs.try_into_i32(&expr.span)?; - let rhs = rhs.try_into_i32(&expr.span)?; + let lhs = lhs.into_i32(); + let rhs = rhs.into_i32(); let res = match kind { Add => lhs.checked_add(rhs), @@ -159,8 +159,8 @@ impl ExecEnv { // Numeric comparisons. Less | Greater => { - let lhs = lhs.try_into_i32(&expr.span)?; - let rhs = rhs.try_into_i32(&expr.span)?; + let lhs = lhs.into_i32(); + let rhs = rhs.into_i32(); let res = match kind { Less => lhs < rhs, @@ -241,8 +241,7 @@ impl ExecEnv { .as_ref() .map(|tape_len| { self.eval_expr(tape_len) - .and_then(|v| v.try_into_i32(&stmt.span)) - .map(|len| len as usize) + .map(|v| v.into_i32() as usize) }) .unwrap_or(Ok(crate::brian::DEFAULT_TAPE_SIZE_LIMIT))?, }), diff --git a/src/variables.rs b/src/variables.rs index db8d53cc..d9bc7bd9 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -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 crate::{ - ast::Stmt, - error::{Error, ErrorKind}, -}; +use crate::{ast::Stmt, consts}; #[derive(Debug, Clone, PartialEq)] pub enum Abool { @@ -119,35 +116,33 @@ impl Value { .expect("Failed to write to Brainfuck input"); } - /// Attempt to coerce a Value to an integer. If the conversion - /// fails, the generated error message is associated with the - /// given span. - pub fn try_into_i32(self, span: &Range) -> Result { + /// Coerce a value to an integer. + pub fn into_i32(self) -> i32 { match self { - Value::Int(i) => Ok(i), - _ => Err(Error { - kind: ErrorKind::TypeError(format!("expected int, got {}", self)), - span: span.clone(), - }), + Value::Abool(a) => a as _, + Value::Bool(b) => b as _, + Value::Functio(func) => match func { + 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. pub fn into_bool(self) -> bool { match self { - // Booleans and abooleans have a trivial conversion. - Value::Bool(b) => b, Value::Abool(b) => b.into(), - // The empty string is falsey, other strings are truthy. - Value::Str(s) => !s.is_empty(), - // 0 is falsey, nonzero is truthy. - Value::Int(x) => x != 0, - // Functios are always truthy. + Value::Bool(b) => b, Value::Functio(_) => true, - // And nul is truthy as a symbol of the fact that the - // deep, fundamental truth of this world is nothing but - // the eternal void. + Value::Int(x) => x != 0, Value::Nul => true, + Value::Str(s) => !s.is_empty(), } } }