diff --git a/Cargo.toml b/Cargo.toml index ccdc20f..7ff3685 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,9 @@ path = "src/bin/tulisp.rs" name = "tulisp" path = "src/lib.rs" +[profile.release] +lto = true + [features] sync = [] big_functions = [] diff --git a/src/builtin/functions/conditionals.rs b/src/builtin/functions/conditionals.rs index d2dc8ea..5d18176 100644 --- a/src/builtin/functions/conditionals.rs +++ b/src/builtin/functions/conditionals.rs @@ -4,6 +4,7 @@ use crate::{ list, lists::{last, length}, }; +use std::borrow::Cow; pub(crate) fn add(ctx: &mut TulispContext) { ctx.add_special_form("if", |ctx, args| { @@ -55,19 +56,14 @@ pub(crate) fn add(ctx: &mut TulispContext) { fn and(ctx: &mut TulispContext, args: &TulispObject) -> Result { let mut ret = TulispObject::nil(); for item in args.base_iter() { - let mut result = None; - eval_basic(ctx, &item, &mut result)?; - if let Some(result) = result { - if result.null() { - return Ok(result); - } - ret = result; - } else { - if item.null() { - return Ok(item); - } - ret = item; + let result = eval_basic(ctx, &item)?; + if result.null() { + return Ok(result.into_owned()); } + ret = match result { + Cow::Borrowed(_) => item, + Cow::Owned(o) => o, + }; } Ok(ret) } @@ -75,14 +71,18 @@ pub(crate) fn add(ctx: &mut TulispContext) { fn or(ctx: &mut TulispContext, args: &TulispObject) -> Result { for item in args.base_iter() { - let mut result = None; - eval_basic(ctx, &item, &mut result)?; - if let Some(result) = result { - if !result.null() { - return Ok(result); + let result = eval_basic(ctx, &item)?; + match result { + Cow::Borrowed(_) => { + if !item.null() { + return Ok(item); + } + } + Cow::Owned(o) => { + if !o.null() { + return Ok(o); + } } - } else if !item.null() { - return Ok(item); } } Ok(TulispObject::nil()) diff --git a/src/cons.rs b/src/cons.rs index 2948c9a..84d7de1 100644 --- a/src/cons.rs +++ b/src/cons.rs @@ -4,7 +4,6 @@ use crate::TulispContext; use crate::TulispObject; use crate::TulispValue; use crate::error::Error; -use crate::eval::eval_basic; use crate::object::Span; #[derive(Debug, Clone)] @@ -137,19 +136,14 @@ impl BaseIter { if let Some(ref next) = self.next { let Cons { car, cdr } = next; let new_car = { - let mut result = None; - if let Err(e) = eval_basic(ctx, car, &mut result) { - return Some(Err(e)); - }; - if let Some(result) = result { - Ok(result) - } else { - Ok(next.car.clone()) + match ctx.eval(car) { + Ok(v) => v, + Err(e) => return Some(Err(e)), } }; self.next = cdr.as_list_cons(); - Some(new_car) + Some(Ok(new_car)) } else { None } diff --git a/src/context.rs b/src/context.rs index fc1d463..cb3e2fd 100644 --- a/src/context.rs +++ b/src/context.rs @@ -210,10 +210,16 @@ impl TulispContext { #[inline(always)] pub fn eval_progn(&mut self, seq: &TulispObject) -> Result { let mut ret = None; - let mut result = None; + for val in seq.base_iter() { - eval_basic(self, &val, &mut result)?; - ret = Some(result.take().unwrap_or(val)) + match eval_basic(self, &val)? { + std::borrow::Cow::Borrowed(_) => { + ret = Some(val); + } + std::borrow::Cow::Owned(o) => { + ret = Some(o); + } + }; } Ok(ret.unwrap_or_else(TulispObject::nil)) } diff --git a/src/error.rs b/src/error.rs index d3a13f5..19f0431 100644 --- a/src/error.rs +++ b/src/error.rs @@ -136,7 +136,7 @@ impl Error { impl Error { /// Adds a trace span to the error's backtrace. pub fn with_trace(mut self, span: TulispObject) -> Self { - if self.backtrace.last().map_or(false, |last| last.eq(&span)) { + if self.backtrace.last().is_some_and(|last| last.eq(&span)) { return self; } self.backtrace.push(span); diff --git a/src/eval.rs b/src/eval.rs index eb4a68d..e8bc079 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,34 +1,33 @@ +use std::borrow::Cow; + use crate::{ TulispObject, TulispValue, context::TulispContext, error::Error, list, value::DefunParams, }; pub(crate) trait Evaluator { - fn eval( + fn eval<'a>( ctx: &mut TulispContext, - value: &TulispObject, - result: &mut Option, - ) -> Result<(), Error>; + value: &'a TulispObject, + ) -> Result, Error>; } pub(crate) struct Eval; impl Evaluator for Eval { - fn eval( + fn eval<'a>( ctx: &mut TulispContext, - value: &TulispObject, - result: &mut Option, - ) -> Result<(), Error> { - eval_basic(ctx, value, result) + value: &'a TulispObject, + ) -> Result, Error> { + eval_basic(ctx, value) } } pub(crate) struct DummyEval; impl Evaluator for DummyEval { - fn eval( + fn eval<'a>( _ctx: &mut TulispContext, - _value: &TulispObject, - _result: &mut Option, - ) -> Result<(), Error> { - Ok(()) + value: &'a TulispObject, + ) -> Result, Error> { + Ok(Cow::Borrowed(value)) } } @@ -38,26 +37,29 @@ fn zip_function_args( args: &TulispObject, ) -> Result<(), Error> { let mut args_iter = args.base_iter(); - let mut eval_result = None; for param in params.iter() { let val = if param.is_optional { match args_iter.next() { - Some(vv) => { - E::eval(ctx, &vv, &mut eval_result)?; - eval_result.take().unwrap_or(vv) - } + Some(vv) => match E::eval(ctx, &vv)? { + Cow::Borrowed(_) => vv, + Cow::Owned(o) => o, + }, None => TulispObject::nil(), } } else if param.is_rest { let ret = TulispObject::nil(); for arg in args_iter.by_ref() { - E::eval(ctx, &arg, &mut eval_result)?; - ret.push(eval_result.take().unwrap_or(arg))?; + ret.push(match E::eval(ctx, &arg)? { + Cow::Borrowed(_) => arg, + Cow::Owned(o) => o, + })?; } ret } else if let Some(vv) = args_iter.next() { - E::eval(ctx, &vv, &mut eval_result)?; - eval_result.take().unwrap_or(vv) + match E::eval(ctx, &vv)? { + Cow::Borrowed(_) => vv, + Cow::Owned(o) => o, + } } else { return Err(Error::type_mismatch("Too few arguments".to_string())); }; @@ -204,24 +206,12 @@ fn eval_back_quote(ctx: &mut TulispContext, mut vv: TulispObject) -> Result Result { - let mut result = None; - eval_basic(ctx, expr, &mut result)?; - if let Some(result) = result { - Ok(result) - } else { - Ok(expr.clone()) - } + eval_basic(ctx, expr).map(|x| x.into_owned()) } #[inline(always)] pub(crate) fn eval_check_null(ctx: &mut TulispContext, expr: &TulispObject) -> Result { - let result = &mut None; - eval_basic(ctx, expr, result)?; - if let Some(result) = result { - Ok(result.null()) - } else { - Ok(expr.null()) - } + eval_basic(ctx, expr).map(|x| x.null()) } #[inline(always)] @@ -230,33 +220,30 @@ pub(crate) fn eval_and_then( expr: &TulispObject, func: impl FnOnce(&mut TulispContext, &TulispObject) -> Result, ) -> Result { - let result = &mut None; - eval_basic(ctx, expr, result)?; - if let Some(result) = result { - func(ctx, result) - } else { - func(ctx, expr) - } + let val = eval_basic(ctx, expr)?; + func(ctx, &val) } +#[inline(always)] pub(crate) fn eval_basic<'a>( ctx: &mut TulispContext, expr: &'a TulispObject, - result: &'a mut Option, -) -> Result<(), Error> { +) -> Result, Error> { match &*expr.inner_ref() { - TulispValue::List { .. } => { - *result = Some(eval_form::(ctx, expr).map_err(|e| e.with_trace(expr.clone()))?); - } + TulispValue::List { .. } => Ok(Cow::Owned( + eval_form::(ctx, expr).map_err(|e| e.with_trace(expr.clone()))?, + )), TulispValue::Symbol { value, .. } => { if value.is_constant() { - return Ok(()); + return Ok(Cow::Borrowed(expr)); } - *result = Some(value.get().map_err(|e| e.with_trace(expr.clone()))?); - } - TulispValue::LexicalBinding { value, .. } => { - *result = Some(value.get().map_err(|e| e.with_trace(expr.clone()))?); + Ok(Cow::Owned( + value.get().map_err(|e| e.with_trace(expr.clone()))?, + )) } + TulispValue::LexicalBinding { value, .. } => Ok(Cow::Owned( + value.get().map_err(|e| e.with_trace(expr.clone()))?, + )), TulispValue::Int { .. } | TulispValue::Float { .. } | TulispValue::String { .. } @@ -267,27 +254,19 @@ pub(crate) fn eval_basic<'a>( | TulispValue::Any(_) | TulispValue::Bounce | TulispValue::Nil - | TulispValue::T => {} - TulispValue::Quote { value, .. } => { - *result = Some(value.clone()); - } - TulispValue::Backquote { value } => { - *result = - Some(eval_back_quote(ctx, value.clone()).map_err(|e| e.with_trace(expr.clone()))?); - } - TulispValue::Unquote { .. } => { - return Err(Error::type_mismatch( - "Unquote without backquote".to_string(), - )); - } + | TulispValue::T => Ok(Cow::Borrowed(expr)), + TulispValue::Quote { value, .. } => Ok(Cow::Owned(value.clone())), + TulispValue::Backquote { value } => Ok(Cow::Owned( + eval_back_quote(ctx, value.clone()).map_err(|e| e.with_trace(expr.clone()))?, + )), + TulispValue::Unquote { .. } => Err(Error::type_mismatch( + "Unquote without backquote".to_string(), + )), TulispValue::Splice { .. } => { - return Err(Error::type_mismatch("Splice without backquote".to_string())); + Err(Error::type_mismatch("Splice without backquote".to_string())) } - TulispValue::Sharpquote { value, .. } => { - *result = Some(value.clone()); - } - }; - Ok(()) + TulispValue::Sharpquote { value, .. } => Ok(Cow::Owned(value.clone())), + } } pub fn macroexpand(ctx: &mut TulispContext, inp: TulispObject) -> Result {