refactor(tvix/eval): Generalize propagation of catchable values
Rather than explicitly checking for Value::Catchable in all builtins, make the #[builtin] proc macro insert this for all strict arguments by default, with support for a #[catch] attribute on the argument to disable this behavior. That attribute hasn't actually been *used* anywhere here, primarily because the tests pass without it, even for those builtins which weren't previously checking for Value::Catchable - if some time passes without this being used I might get rid of support for it entirely. There's also a `try_value` macro in builtins directly for the places where builtins were eg forcing something, then explicitly propagating a catchable value. Change-Id: Ie22037b9d3e305e3bdb682d105fe467bd90d53e9 Reviewed-on: https://cl.tvl.fyi/c/depot/+/10732 Tested-by: BuildkiteCI Reviewed-by: raitobezarius <tvl@lahfa.xyz>
This commit is contained in:
parent
4e040e8bc4
commit
780b47193a
2 changed files with 44 additions and 183 deletions
|
@ -22,6 +22,10 @@ struct BuiltinArgument {
|
||||||
/// function is called.
|
/// function is called.
|
||||||
strict: bool,
|
strict: bool,
|
||||||
|
|
||||||
|
/// Propagate catchable values as values to the function, rather than short-circuit returning
|
||||||
|
/// them if encountered
|
||||||
|
catch: bool,
|
||||||
|
|
||||||
/// Span at which the argument was defined.
|
/// Span at which the argument was defined.
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
@ -205,6 +209,7 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
let span = arg.span();
|
let span = arg.span();
|
||||||
let mut strict = true;
|
let mut strict = true;
|
||||||
|
let mut catch = false;
|
||||||
let (name, ty) = match arg {
|
let (name, ty) = match arg {
|
||||||
FnArg::Receiver(_) => {
|
FnArg::Receiver(_) => {
|
||||||
return Err(quote_spanned!(span => {
|
return Err(quote_spanned!(span => {
|
||||||
|
@ -219,6 +224,9 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
if id == "lazy" {
|
if id == "lazy" {
|
||||||
strict = false;
|
strict = false;
|
||||||
false
|
false
|
||||||
|
} else if id == "catch" {
|
||||||
|
catch = true;
|
||||||
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -233,8 +241,15 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if catch && !strict {
|
||||||
|
return Err(quote_spanned!(span => {
|
||||||
|
compile_error!("Cannot mix both lazy and catch on the same argument")
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(BuiltinArgument {
|
Ok(BuiltinArgument {
|
||||||
strict,
|
strict,
|
||||||
|
catch,
|
||||||
span,
|
span,
|
||||||
name,
|
name,
|
||||||
ty,
|
ty,
|
||||||
|
@ -267,12 +282,22 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let ident = &arg.name;
|
let ident = &arg.name;
|
||||||
|
|
||||||
if arg.strict {
|
if arg.strict {
|
||||||
|
if arg.catch {
|
||||||
f.block = Box::new(parse_quote_spanned! {arg.span=> {
|
f.block = Box::new(parse_quote_spanned! {arg.span=> {
|
||||||
let #ident: #ty = tvix_eval::generators::request_force(&co, values.pop()
|
let #ident: #ty = tvix_eval::generators::request_force(&co, values.pop()
|
||||||
.expect("Tvix bug: builtin called with incorrect number of arguments")).await;
|
.expect("Tvix bug: builtin called with incorrect number of arguments")).await;
|
||||||
|
|
||||||
#block
|
#block
|
||||||
}});
|
}});
|
||||||
|
} else {
|
||||||
|
f.block = Box::new(parse_quote_spanned! {arg.span=> {
|
||||||
|
let #ident: #ty = tvix_eval::generators::request_force(&co, values.pop()
|
||||||
|
.expect("Tvix bug: builtin called with incorrect number of arguments")).await;
|
||||||
|
if #ident.is_catchable() {
|
||||||
|
return Ok(#ident);
|
||||||
|
}
|
||||||
|
#block
|
||||||
|
}});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
f.block = Box::new(parse_quote_spanned! {arg.span=> {
|
f.block = Box::new(parse_quote_spanned! {arg.span=> {
|
||||||
let #ident: #ty = values.pop()
|
let #ident: #ty = values.pop()
|
||||||
|
|
|
@ -91,6 +91,16 @@ mod pure_builtins {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
macro_rules! try_value {
|
||||||
|
($value:expr) => {{
|
||||||
|
let val = $value;
|
||||||
|
if val.is_catchable() {
|
||||||
|
return Ok(val);
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
#[builtin("abort")]
|
#[builtin("abort")]
|
||||||
async fn builtin_abort(co: GenCo, message: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_abort(co: GenCo, message: Value) -> Result<Value, ErrorKind> {
|
||||||
// TODO(sterni): coerces to string
|
// TODO(sterni): coerces to string
|
||||||
|
@ -108,21 +118,9 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("all")]
|
#[builtin("all")]
|
||||||
async fn builtin_all(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_all(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pred.is_catchable() {
|
|
||||||
return Ok(pred);
|
|
||||||
}
|
|
||||||
|
|
||||||
for value in list.to_list()?.into_iter() {
|
for value in list.to_list()?.into_iter() {
|
||||||
let pred_result = generators::request_call_with(&co, pred.clone(), [value]).await;
|
let pred_result = generators::request_call_with(&co, pred.clone(), [value]).await;
|
||||||
let pred_result = generators::request_force(&co, pred_result).await;
|
let pred_result = try_value!(generators::request_force(&co, pred_result).await);
|
||||||
|
|
||||||
if pred_result.is_catchable() {
|
|
||||||
return Ok(pred_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !pred_result.as_bool()? {
|
if !pred_result.as_bool()? {
|
||||||
return Ok(Value::Bool(false));
|
return Ok(Value::Bool(false));
|
||||||
|
@ -134,21 +132,9 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("any")]
|
#[builtin("any")]
|
||||||
async fn builtin_any(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_any(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pred.is_catchable() {
|
|
||||||
return Ok(pred);
|
|
||||||
}
|
|
||||||
|
|
||||||
for value in list.to_list()?.into_iter() {
|
for value in list.to_list()?.into_iter() {
|
||||||
let pred_result = generators::request_call_with(&co, pred.clone(), [value]).await;
|
let pred_result = generators::request_call_with(&co, pred.clone(), [value]).await;
|
||||||
let pred_result = generators::request_force(&co, pred_result).await;
|
let pred_result = try_value!(generators::request_force(&co, pred_result).await);
|
||||||
|
|
||||||
if pred_result.is_catchable() {
|
|
||||||
return Ok(pred_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pred_result.as_bool()? {
|
if pred_result.as_bool()? {
|
||||||
return Ok(Value::Bool(true));
|
return Ok(Value::Bool(true));
|
||||||
|
@ -160,9 +146,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("attrNames")]
|
#[builtin("attrNames")]
|
||||||
async fn builtin_attr_names(co: GenCo, set: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_attr_names(co: GenCo, set: Value) -> Result<Value, ErrorKind> {
|
||||||
if set.is_catchable() {
|
|
||||||
return Ok(set);
|
|
||||||
}
|
|
||||||
let xs = set.to_attrs()?;
|
let xs = set.to_attrs()?;
|
||||||
let mut output = Vec::with_capacity(xs.len());
|
let mut output = Vec::with_capacity(xs.len());
|
||||||
|
|
||||||
|
@ -175,10 +158,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("attrValues")]
|
#[builtin("attrValues")]
|
||||||
async fn builtin_attr_values(co: GenCo, set: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_attr_values(co: GenCo, set: Value) -> Result<Value, ErrorKind> {
|
||||||
if set.is_catchable() {
|
|
||||||
return Ok(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
let xs = set.to_attrs()?;
|
let xs = set.to_attrs()?;
|
||||||
let mut output = Vec::with_capacity(xs.len());
|
let mut output = Vec::with_capacity(xs.len());
|
||||||
|
|
||||||
|
@ -231,14 +210,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("catAttrs")]
|
#[builtin("catAttrs")]
|
||||||
async fn builtin_cat_attrs(co: GenCo, key: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_cat_attrs(co: GenCo, key: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if key.is_catchable() {
|
|
||||||
return Ok(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
let key = key.to_str()?;
|
let key = key.to_str()?;
|
||||||
let list = list.to_list()?;
|
let list = list.to_list()?;
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
@ -275,10 +246,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("concatLists")]
|
#[builtin("concatLists")]
|
||||||
async fn builtin_concat_lists(co: GenCo, lists: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_concat_lists(co: GenCo, lists: Value) -> Result<Value, ErrorKind> {
|
||||||
if lists.is_catchable() {
|
|
||||||
return Ok(lists);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut out = imbl::Vector::new();
|
let mut out = imbl::Vector::new();
|
||||||
|
|
||||||
for value in lists.to_list()? {
|
for value in lists.to_list()? {
|
||||||
|
@ -291,14 +258,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("concatMap")]
|
#[builtin("concatMap")]
|
||||||
async fn builtin_concat_map(co: GenCo, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_concat_map(co: GenCo, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.is_catchable() {
|
|
||||||
return Ok(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
let list = list.to_list()?;
|
let list = list.to_list()?;
|
||||||
let mut res = imbl::Vector::new();
|
let mut res = imbl::Vector::new();
|
||||||
for val in list {
|
for val in list {
|
||||||
|
@ -315,14 +274,6 @@ mod pure_builtins {
|
||||||
separator: Value,
|
separator: Value,
|
||||||
list: Value,
|
list: Value,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if separator.is_catchable() {
|
|
||||||
return Ok(separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut separator = separator.to_contextful_str()?;
|
let mut separator = separator.to_contextful_str()?;
|
||||||
let mut context = NixContext::new();
|
let mut context = NixContext::new();
|
||||||
if let Some(sep_context) = separator.context_mut() {
|
if let Some(sep_context) = separator.context_mut() {
|
||||||
|
@ -413,10 +364,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("elem")]
|
#[builtin("elem")]
|
||||||
async fn builtin_elem(co: GenCo, x: Value, xs: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_elem(co: GenCo, x: Value, xs: Value) -> Result<Value, ErrorKind> {
|
||||||
if xs.is_catchable() {
|
|
||||||
return Ok(xs);
|
|
||||||
}
|
|
||||||
|
|
||||||
for val in xs.to_list()? {
|
for val in xs.to_list()? {
|
||||||
match generators::check_equality(&co, x.clone(), val, PointerEquality::AllowAll).await?
|
match generators::check_equality(&co, x.clone(), val, PointerEquality::AllowAll).await?
|
||||||
{
|
{
|
||||||
|
@ -430,12 +377,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("elemAt")]
|
#[builtin("elemAt")]
|
||||||
async fn builtin_elem_at(co: GenCo, xs: Value, i: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_elem_at(co: GenCo, xs: Value, i: Value) -> Result<Value, ErrorKind> {
|
||||||
if xs.is_catchable() {
|
|
||||||
return Ok(xs);
|
|
||||||
}
|
|
||||||
if i.is_catchable() {
|
|
||||||
return Ok(i);
|
|
||||||
}
|
|
||||||
let xs = xs.to_list()?;
|
let xs = xs.to_list()?;
|
||||||
let i = i.as_int()?;
|
let i = i.as_int()?;
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
|
@ -450,23 +391,12 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("filter")]
|
#[builtin("filter")]
|
||||||
async fn builtin_filter(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_filter(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if pred.is_catchable() {
|
|
||||||
return Ok(pred);
|
|
||||||
}
|
|
||||||
|
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
let list: NixList = list.to_list()?;
|
let list: NixList = list.to_list()?;
|
||||||
let mut out = imbl::Vector::new();
|
let mut out = imbl::Vector::new();
|
||||||
|
|
||||||
for value in list {
|
for value in list {
|
||||||
let result = generators::request_call_with(&co, pred.clone(), [value.clone()]).await;
|
let result = generators::request_call_with(&co, pred.clone(), [value.clone()]).await;
|
||||||
let verdict = generators::request_force(&co, result).await;
|
let verdict = try_value!(generators::request_force(&co, result).await);
|
||||||
if verdict.is_catchable() {
|
|
||||||
return Ok(verdict);
|
|
||||||
}
|
|
||||||
if verdict.as_bool()? {
|
if verdict.as_bool()? {
|
||||||
out.push_back(value);
|
out.push_back(value);
|
||||||
}
|
}
|
||||||
|
@ -487,10 +417,6 @@ mod pure_builtins {
|
||||||
#[lazy] nul: Value,
|
#[lazy] nul: Value,
|
||||||
list: Value,
|
list: Value,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut nul = nul;
|
let mut nul = nul;
|
||||||
let list = list.to_list()?;
|
let list = list.to_list()?;
|
||||||
for val in list {
|
for val in list {
|
||||||
|
@ -509,10 +435,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("functionArgs")]
|
#[builtin("functionArgs")]
|
||||||
async fn builtin_function_args(co: GenCo, f: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_function_args(co: GenCo, f: Value) -> Result<Value, ErrorKind> {
|
||||||
if f.is_catchable() {
|
|
||||||
return Ok(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
let lambda = &f.as_closure()?.lambda();
|
let lambda = &f.as_closure()?.lambda();
|
||||||
let formals = if let Some(formals) = &lambda.formals {
|
let formals = if let Some(formals) = &lambda.formals {
|
||||||
formals
|
formals
|
||||||
|
@ -526,10 +448,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("fromJSON")]
|
#[builtin("fromJSON")]
|
||||||
async fn builtin_from_json(co: GenCo, json: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_from_json(co: GenCo, json: Value) -> Result<Value, ErrorKind> {
|
||||||
if json.is_catchable() {
|
|
||||||
return Ok(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
let json_str = json.to_str()?;
|
let json_str = json.to_str()?;
|
||||||
|
|
||||||
serde_json::from_slice(&json_str).map_err(|err| err.into())
|
serde_json::from_slice(&json_str).map_err(|err| err.into())
|
||||||
|
@ -564,10 +482,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("genericClosure")]
|
#[builtin("genericClosure")]
|
||||||
async fn builtin_generic_closure(co: GenCo, input: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_generic_closure(co: GenCo, input: Value) -> Result<Value, ErrorKind> {
|
||||||
if input.is_catchable() {
|
|
||||||
return Ok(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
let attrs = input.to_attrs()?;
|
let attrs = input.to_attrs()?;
|
||||||
|
|
||||||
// The work set is maintained as a VecDeque because new items
|
// The work set is maintained as a VecDeque because new items
|
||||||
|
@ -613,10 +527,6 @@ mod pure_builtins {
|
||||||
generator: Value,
|
generator: Value,
|
||||||
length: Value,
|
length: Value,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
if length.is_catchable() {
|
|
||||||
return Ok(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut out = imbl::Vector::<Value>::new();
|
let mut out = imbl::Vector::<Value>::new();
|
||||||
let len = length.as_int()?;
|
let len = length.as_int()?;
|
||||||
// the best span we can get…
|
// the best span we can get…
|
||||||
|
@ -636,12 +546,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("getAttr")]
|
#[builtin("getAttr")]
|
||||||
async fn builtin_get_attr(co: GenCo, key: Value, set: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_get_attr(co: GenCo, key: Value, set: Value) -> Result<Value, ErrorKind> {
|
||||||
if key.is_catchable() {
|
|
||||||
return Ok(key);
|
|
||||||
}
|
|
||||||
if set.is_catchable() {
|
|
||||||
return Ok(set);
|
|
||||||
}
|
|
||||||
let k = key.to_str()?;
|
let k = key.to_str()?;
|
||||||
let xs = set.to_attrs()?;
|
let xs = set.to_attrs()?;
|
||||||
|
|
||||||
|
@ -655,14 +559,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("groupBy")]
|
#[builtin("groupBy")]
|
||||||
async fn builtin_group_by(co: GenCo, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_group_by(co: GenCo, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.is_catchable() {
|
|
||||||
return Ok(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut res: BTreeMap<NixString, imbl::Vector<Value>> = BTreeMap::new();
|
let mut res: BTreeMap<NixString, imbl::Vector<Value>> = BTreeMap::new();
|
||||||
for val in list.to_list()? {
|
for val in list.to_list()? {
|
||||||
let key = generators::request_force(
|
let key = generators::request_force(
|
||||||
|
@ -682,14 +578,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("hasAttr")]
|
#[builtin("hasAttr")]
|
||||||
async fn builtin_has_attr(co: GenCo, key: Value, set: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_has_attr(co: GenCo, key: Value, set: Value) -> Result<Value, ErrorKind> {
|
||||||
if set.is_catchable() {
|
|
||||||
return Ok(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if key.is_catchable() {
|
|
||||||
return Ok(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
let k = key.to_str()?;
|
let k = key.to_str()?;
|
||||||
let xs = set.to_attrs()?;
|
let xs = set.to_attrs()?;
|
||||||
|
|
||||||
|
@ -1007,10 +895,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("listToAttrs")]
|
#[builtin("listToAttrs")]
|
||||||
async fn builtin_list_to_attrs(co: GenCo, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_list_to_attrs(co: GenCo, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
let list = list.to_list()?;
|
let list = list.to_list()?;
|
||||||
let mut map = BTreeMap::new();
|
let mut map = BTreeMap::new();
|
||||||
for val in list {
|
for val in list {
|
||||||
|
@ -1027,14 +911,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("map")]
|
#[builtin("map")]
|
||||||
async fn builtin_map(co: GenCo, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_map(co: GenCo, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.is_catchable() {
|
|
||||||
return Ok(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut out = imbl::Vector::<Value>::new();
|
let mut out = imbl::Vector::<Value>::new();
|
||||||
|
|
||||||
// the best span we can get…
|
// the best span we can get…
|
||||||
|
@ -1140,14 +1016,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("partition")]
|
#[builtin("partition")]
|
||||||
async fn builtin_partition(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_partition(co: GenCo, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pred.is_catchable() {
|
|
||||||
return Ok(pred);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut right: imbl::Vector<Value> = Default::default();
|
let mut right: imbl::Vector<Value> = Default::default();
|
||||||
let mut wrong: imbl::Vector<Value> = Default::default();
|
let mut wrong: imbl::Vector<Value> = Default::default();
|
||||||
|
|
||||||
|
@ -1176,14 +1044,6 @@ mod pure_builtins {
|
||||||
attrs: Value,
|
attrs: Value,
|
||||||
keys: Value,
|
keys: Value,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
if attrs.is_catchable() {
|
|
||||||
return Ok(attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if keys.is_catchable() {
|
|
||||||
return Ok(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
let attrs = attrs.to_attrs()?;
|
let attrs = attrs.to_attrs()?;
|
||||||
let keys = keys
|
let keys = keys
|
||||||
.to_list()?
|
.to_list()?
|
||||||
|
@ -1207,18 +1067,6 @@ mod pure_builtins {
|
||||||
to: Value,
|
to: Value,
|
||||||
s: Value,
|
s: Value,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
if s.is_catchable() {
|
|
||||||
return Ok(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if to.is_catchable() {
|
|
||||||
return Ok(to);
|
|
||||||
}
|
|
||||||
|
|
||||||
if from.is_catchable() {
|
|
||||||
return Ok(from);
|
|
||||||
}
|
|
||||||
|
|
||||||
let from = from.to_list()?;
|
let from = from.to_list()?;
|
||||||
for val in &from {
|
for val in &from {
|
||||||
generators::request_force(&co, val.clone()).await;
|
generators::request_force(&co, val.clone()).await;
|
||||||
|
@ -1372,14 +1220,6 @@ mod pure_builtins {
|
||||||
|
|
||||||
#[builtin("sort")]
|
#[builtin("sort")]
|
||||||
async fn builtin_sort(co: GenCo, comparator: Value, list: Value) -> Result<Value, ErrorKind> {
|
async fn builtin_sort(co: GenCo, comparator: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||||
if list.is_catchable() {
|
|
||||||
return Ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if comparator.is_catchable() {
|
|
||||||
return Ok(comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
let list = list.to_list()?;
|
let list = list.to_list()?;
|
||||||
let sorted = list.sort_by(&co, comparator).await?;
|
let sorted = list.sort_by(&co, comparator).await?;
|
||||||
Ok(Value::List(sorted))
|
Ok(Value::List(sorted))
|
||||||
|
@ -1664,10 +1504,6 @@ mod placeholder_builtins {
|
||||||
co: GenCo,
|
co: GenCo,
|
||||||
s: Value,
|
s: Value,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
if s.is_catchable() {
|
|
||||||
return Ok(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
let span = generators::request_span(&co).await;
|
let span = generators::request_span(&co).await;
|
||||||
let mut v = s
|
let mut v = s
|
||||||
.coerce_to_string(
|
.coerce_to_string(
|
||||||
|
|
Loading…
Reference in a new issue