Skip to content

Commit

Permalink
surface errors when forcing closures
Browse files Browse the repository at this point in the history
  • Loading branch information
dgkf committed Oct 11, 2023
1 parent 539a088 commit 9081360
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 30 deletions.
10 changes: 8 additions & 2 deletions src/callable/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,20 @@ impl TryFrom<&str> for Box<dyn Builtin> {
}
}

pub fn force_closures(vals: List, stack: &mut CallStack) -> Vec<(Option<String>, Obj)> {
pub fn force_closures(
vals: List,
stack: &mut CallStack,
) -> Result<Vec<(Option<String>, Obj)>, Signal> {
// Force any closures that were created during call. This helps with using
// variables as argument for sep and collapse parameters.
vals.values
.borrow_mut()
.clone()
.into_iter()
.map(|(k, v)| (k, v.clone().force(stack).unwrap_or(Obj::Null))) // TODO: raise this error
.map(|(k, v)| match (k, v.force(stack)) {
(k, Ok(v)) => Ok((k, v)),
(_, Err(e)) => Err(e),
})
.collect()
}

Expand Down
39 changes: 17 additions & 22 deletions src/callable/primitive/paste.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use r_derive::*;

use crate::callable::core::*;
use crate::context::Context;
use crate::error::*;
use crate::lang::*;
use crate::object::*;
Expand All @@ -10,35 +9,31 @@ use crate::object::*;
#[builtin(sym = "paste")]
pub struct PrimitivePaste;
impl Callable for PrimitivePaste {
fn formals(&self) -> ExprList {
ExprList::from(vec![
(None, Expr::Ellipsis(None)),
(Some(String::from("sep")), Expr::String(" ".to_string())),
(Some(String::from("collapse")), Expr::Null),
])
}

fn call(&self, args: ExprList, stack: &mut CallStack) -> EvalResult {
let Obj::List(vals) = stack.parent_frame().eval_list_lazy(args)? else {
unreachable!()
};
let (args, ellipsis) = self.match_arg_exprs(args, stack)?;

let mut vals = force_closures(vals, stack);
let ellipsis = force_closures(ellipsis, stack)?;
let args = force_closures(args, stack)?;

let mut sep = String::from(" ");
let mut should_collapse = false;
let mut collapse = String::new();

// find non-ellipsis arg indices
let named_indices: Vec<usize> = vals
.iter()
.enumerate()
.filter(|(_, (k, _))| {
*k == Some("collapse".to_string()) || *k == Some("sep".to_string())
})
.map(|(i, _)| i)
.collect();

// remove named sep and collapse args from our arguments and populate values
for i in named_indices.iter().rev() {
let (Some(k), v) = vals.remove(*i) else {
continue;
};
for (k, v) in args.iter().rev() {
let Some(k) = k else { continue };

match (k.as_str(), v) {
("sep", Obj::Vector(v)) => {
sep = v.into();
sep = (*v).clone().into();
}
("sep", _) => {
return Err(Signal::Error(Error::Other(
Expand All @@ -48,7 +43,7 @@ impl Callable for PrimitivePaste {
("collapse", Obj::Null) => continue,
("collapse", Obj::Vector(v)) => {
should_collapse = true;
collapse = v.into();
collapse = (*v).clone().into();
}
("collapse", _) => {
return Err(Signal::Error(Error::WithCallStack(
Expand All @@ -63,7 +58,7 @@ impl Callable for PrimitivePaste {
}

// coerce all of our remaining arguments into vectors of strings
let vec_s_vec: Vec<Vec<String>> = vals
let vec_s_vec: Vec<Vec<String>> = ellipsis
.into_iter()
.map(|(_, v)| -> Result<Vec<String>, Signal> {
match v.as_character()? {
Expand Down
2 changes: 1 addition & 1 deletion src/callable/primitive/rnorm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Callable for PrimitiveRnorm {
fn call(&self, args: ExprList, stack: &mut CallStack) -> EvalResult {
use Error::ArgumentInvalid;
let (vals, _) = self.match_arg_exprs(args, stack)?;
let vals = force_closures(vals, stack);
let vals = force_closures(vals, stack)?;
let mut vals = Obj::List(List::from(vals));

let n: i32 = vals.try_get_named("n")?.try_into()?;
Expand Down
2 changes: 1 addition & 1 deletion src/callable/primitive/runif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl Callable for PrimitiveRunif {
use Error::ArgumentInvalid;

let (vals, _) = self.match_arg_exprs(args, stack)?;
let vals = force_closures(vals, stack);
let vals = force_closures(vals, stack)?;
let mut vals = Obj::List(List::from(vals));

let n: i32 = vals.try_get_named("n")?.try_into()?;
Expand Down
8 changes: 6 additions & 2 deletions src/context/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ pub trait Context: std::fmt::Debug + std::fmt::Display {

fn env(&self) -> Rc<Environment>;

fn eval_call(&mut self, expr: Expr) -> EvalResult {
self.eval(expr)
fn eval_call_in(&mut self, expr: Expr, env: Rc<Environment>) -> EvalResult {
self.eval_in(expr, env)
}

fn eval_in(&mut self, expr: Expr, env: Rc<Environment>) -> EvalResult {
env.clone().eval(expr)
}

fn eval(&mut self, expr: Expr) -> EvalResult {
Expand Down
14 changes: 12 additions & 2 deletions src/lang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ impl Context for CallStack {
self.last_frame().env().clone()
}

fn eval_call(&mut self, expr: Expr) -> EvalResult {
fn eval_call_in(&mut self, expr: Expr, _env: Rc<Environment>) -> EvalResult {
let Expr::Call(what, args) = expr.clone() else {
return internal_err!();
};
Expand Down Expand Up @@ -768,12 +768,22 @@ impl Context for CallStack {
}
}

fn eval_in(&mut self, expr: Expr, env: Rc<Environment>) -> EvalResult {
use Expr::*;
match expr {
List(x) => self.eval_list_lazy(x),
Symbol(s) => env.clone().get(s),
Call(..) => self.eval_call_in(expr, env),
_ => self.last_frame().eval(expr),
}
}

fn eval(&mut self, expr: Expr) -> EvalResult {
use Expr::*;
match expr {
List(x) => self.eval_list_lazy(x),
Symbol(s) => self.get(s),
Call(..) => self.eval_call(expr),
Call(..) => self.eval_call_in(expr, self.env()),
_ => self.last_frame().eval(expr),
}
}
Expand Down

0 comments on commit 9081360

Please sign in to comment.