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.
|
/// 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> {
|
pub fn call(&self, f: Value, a: Value) -> Result<Value> {
|
||||||
let v = unsafe {
|
let v = unsafe {
|
||||||
let value = self.new_value_uninitialized();
|
let value = self.new_value_uninitialized();
|
||||||
|
|
@ -309,6 +311,23 @@ impl EvalState {
|
||||||
Ok(v)
|
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 {
|
fn new_value_uninitialized(&self) -> Value {
|
||||||
let value = unsafe { raw::alloc_value(self.context.ptr(), self.raw_ptr()) };
|
let value = unsafe { raw::alloc_value(self.context.ptr(), self.raw_ptr()) };
|
||||||
Value::new(value)
|
Value::new(value)
|
||||||
|
|
@ -847,6 +866,23 @@ mod tests {
|
||||||
.unwrap();
|
.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]
|
#[test]
|
||||||
fn eval_state_call_fail_body() {
|
fn eval_state_call_fail_body() {
|
||||||
gc_registering_current_thread(|| {
|
gc_registering_current_thread(|| {
|
||||||
|
|
@ -868,6 +904,30 @@ mod tests {
|
||||||
.unwrap();
|
.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]
|
#[test]
|
||||||
fn eval_state_call_fail_args() {
|
fn eval_state_call_fail_args() {
|
||||||
gc_registering_current_thread(|| {
|
gc_registering_current_thread(|| {
|
||||||
|
|
@ -888,4 +948,28 @@ mod tests {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.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