compose_library/foundations/
support.rs1use compose_error_codes::E0012_PREDICATE_MUST_RETURN_BOOLEAN;
2use compose_library::diag::{SourceResult, bail, error};
3use compose_library::{Args, Func, Value, Vm};
4use std::iter;
5
6pub fn eval_predicate(
7 vm: &mut dyn Vm,
8 predicate: &Func,
9 value: Value,
10 callee: &str,
11) -> SourceResult<bool> {
12 let span = predicate.span;
13 let args = Args::new(span, iter::once(value));
14 match predicate.call(vm, args)? {
15 Value::Bool(b) => Ok(b),
16 other => {
17 let mut err = error!(
18 span, "predicate must return a boolean";
19 label_message: "this function should return a boolean, but returned type `{}` instead", other.ty();
20 note: "a predicate function passed to `{callee}` must return either `true` or `false`";
21 code: &E0012_PREDICATE_MUST_RETURN_BOOLEAN;
22 );
23
24 if let Some(hint) = predicate_hint(&other) {
25 err.hint(hint);
26 }
27
28 bail!(err);
29 }
30 }
31}
32
33pub fn eval_func(vm: &mut dyn Vm, func: &Func, args: impl IntoIterator<Item = Value>) -> SourceResult<Value> {
34 func.call(vm, Args::new(func.span, args))
35}
36
37fn predicate_hint(value: &Value) -> Option<&'static str> {
38 match value {
39 Value::Int(_) => Some("did you mean to write a comparison like `x == 1` or `x > 1`?"),
40 Value::Str(_) => Some("did you mean to compare it, like `x == \"hello\"`?"),
41 Value::Array(_) => {
42 Some("did you mean to check the contents, e.g., `x.contains(...)` or `x.len() > 0`?")
43 }
44 _ => None,
45 }
46}