feat: EvalState::new_value_apply
(cherry picked from commit f8143ae4ed7b62b86cb232f8d73e53bae30d632c)
This commit is contained in:
parent
8fcc645c5d
commit
78435d4ed7
1 changed files with 84 additions and 0 deletions
|
|
@ -293,6 +293,8 @@ impl EvalState {
|
|||
}
|
||||
|
||||
/// Eagerly apply a function to an argument.
|
||||
///
|
||||
/// For a lazy version, see [`new_value_apply`][`EvalState::new_value_apply`].
|
||||
pub fn call(&self, f: Value, a: Value) -> Result<Value> {
|
||||
let v = unsafe {
|
||||
let value = self.new_value_uninitialized();
|
||||
|
|
@ -309,6 +311,23 @@ impl EvalState {
|
|||
Ok(v)
|
||||
}
|
||||
|
||||
/// Apply a function to an argument, but don't evaluate the result just yet.
|
||||
///
|
||||
/// For an eager version, see [`call`][`EvalState::call`].
|
||||
pub fn new_value_apply(&self, f: &Value, a: &Value) -> Result<Value> {
|
||||
let value = self.new_value_uninitialized();
|
||||
unsafe {
|
||||
raw::init_apply(
|
||||
self.context.ptr(),
|
||||
value.raw_ptr(),
|
||||
f.raw_ptr(),
|
||||
a.raw_ptr(),
|
||||
);
|
||||
};
|
||||
self.context.check_err()?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn new_value_uninitialized(&self) -> Value {
|
||||
let value = unsafe { raw::alloc_value(self.context.ptr(), self.raw_ptr()) };
|
||||
Value::new(value)
|
||||
|
|
@ -847,6 +866,23 @@ mod tests {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_apply() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto").unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
// This is a function that takes two arguments.
|
||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("2", "<test>").unwrap();
|
||||
let v = es.new_value_apply(&f, &a).unwrap();
|
||||
assert!(es.value_is_thunk(&v));
|
||||
es.force(&v).unwrap();
|
||||
let i = es.require_int(&v).unwrap();
|
||||
assert!(i == 3);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_call_fail_body() {
|
||||
gc_registering_current_thread(|| {
|
||||
|
|
@ -868,6 +904,30 @@ mod tests {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_apply_fail_body() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto").unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("true", "<test>").unwrap();
|
||||
// Lazy => no error
|
||||
let r = es.new_value_apply(&f, &a).unwrap();
|
||||
// Force it => error
|
||||
let res = es.force(&r);
|
||||
match res {
|
||||
Ok(_) => panic!("expected an error"),
|
||||
Err(e) => {
|
||||
if !e.to_string().contains("cannot coerce") {
|
||||
eprintln!("{}", e);
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_call_fail_args() {
|
||||
gc_registering_current_thread(|| {
|
||||
|
|
@ -888,4 +948,28 @@ mod tests {
|
|||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_apply_fail_args() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto").unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("{x}: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("{}", "<test>").unwrap();
|
||||
// Lazy => no error
|
||||
let r = es.new_value_apply(&f, &a).unwrap();
|
||||
// Force it => error
|
||||
let res = es.force(&r);
|
||||
match res {
|
||||
Ok(_) => panic!("expected an error"),
|
||||
Err(e) => {
|
||||
if !e.to_string().contains("called without required argument") {
|
||||
eprintln!("{}", e);
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue