Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ path = "src/bin/tulisp.rs"
name = "tulisp"
path = "src/lib.rs"

[profile.release]
lto = true

[features]
sync = []
big_functions = []
38 changes: 19 additions & 19 deletions src/builtin/functions/conditionals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down Expand Up @@ -55,34 +56,33 @@ pub(crate) fn add(ctx: &mut TulispContext) {
fn and(ctx: &mut TulispContext, args: &TulispObject) -> Result<TulispObject, Error> {
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)
}
ctx.add_special_form("and", and);

fn or(ctx: &mut TulispContext, args: &TulispObject) -> Result<TulispObject, Error> {
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())
Expand Down
14 changes: 4 additions & 10 deletions src/cons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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
}
Expand Down
12 changes: 9 additions & 3 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,16 @@ impl TulispContext {
#[inline(always)]
pub fn eval_progn(&mut self, seq: &TulispObject) -> Result<TulispObject, Error> {
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))
}
Expand Down
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
125 changes: 52 additions & 73 deletions src/eval.rs
Original file line number Diff line number Diff line change
@@ -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<TulispObject>,
) -> Result<(), Error>;
value: &'a TulispObject,
) -> Result<Cow<'a, TulispObject>, Error>;
}

pub(crate) struct Eval;
impl Evaluator for Eval {
fn eval(
fn eval<'a>(
ctx: &mut TulispContext,
value: &TulispObject,
result: &mut Option<TulispObject>,
) -> Result<(), Error> {
eval_basic(ctx, value, result)
value: &'a TulispObject,
) -> Result<Cow<'a, TulispObject>, 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<TulispObject>,
) -> Result<(), Error> {
Ok(())
value: &'a TulispObject,
) -> Result<Cow<'a, TulispObject>, Error> {
Ok(Cow::Borrowed(value))
}
}

Expand All @@ -38,26 +37,29 @@ fn zip_function_args<E: Evaluator>(
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()));
};
Expand Down Expand Up @@ -204,24 +206,12 @@ fn eval_back_quote(ctx: &mut TulispContext, mut vv: TulispObject) -> Result<Tuli

#[inline(always)]
pub(crate) fn eval(ctx: &mut TulispContext, expr: &TulispObject) -> Result<TulispObject, Error> {
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<bool, Error> {
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)]
Expand All @@ -230,33 +220,30 @@ pub(crate) fn eval_and_then<T>(
expr: &TulispObject,
func: impl FnOnce(&mut TulispContext, &TulispObject) -> Result<T, Error>,
) -> Result<T, Error> {
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<TulispObject>,
) -> Result<(), Error> {
) -> Result<Cow<'a, TulispObject>, Error> {
match &*expr.inner_ref() {
TulispValue::List { .. } => {
*result = Some(eval_form::<Eval>(ctx, expr).map_err(|e| e.with_trace(expr.clone()))?);
}
TulispValue::List { .. } => Ok(Cow::Owned(
eval_form::<Eval>(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 { .. }
Expand All @@ -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<TulispObject, Error> {
Expand Down