1use std::{cell::RefCell, rc::Rc};23use jrsonnet_evaluator::{4 error::{Error::*, Result},5 function::{builtin, ArgLike, CallLocation, FuncVal},6 throw,7 typed::{Any, Either2, Either4},8 val::{equals, ArrValue},9 Either, IStr, ObjValue, State, Thunk, Val,10};1112use crate::{extvar_source, Settings};1314#[builtin]15pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> Result<usize> {16 use Either4::*;17 Ok(match x {18 A(x) => x.chars().count(),19 B(x) => x.len(),20 C(x) => x.len(),21 D(f) => f.params_len(),22 })23}2425#[builtin(fields(26 settings: Rc<RefCell<Settings>>,27))]28pub fn builtin_ext_var(this: &builtin_ext_var, s: State, x: IStr) -> Result<Any> {29 let ctx = s.create_default_context(extvar_source(&x, ""));30 Ok(Any(this31 .settings32 .borrow()33 .ext_vars34 .get(&x)35 .cloned()36 .ok_or_else(|| UndefinedExternalVariable(x))?37 .evaluate_arg(s.clone(), ctx, true)?38 .evaluate(s)?))39}4041#[builtin(fields(42 settings: Rc<RefCell<Settings>>,43))]44pub fn builtin_native(this: &builtin_native, name: IStr) -> Result<Any> {45 Ok(Any(this46 .settings47 .borrow()48 .ext_natives49 .get(&name)50 .cloned()51 .map_or(Val::Null, |v| {52 Val::Func(FuncVal::Builtin(v.clone()))53 })))54}5556#[builtin(fields(57 settings: Rc<RefCell<Settings>>,58))]59pub fn builtin_trace(60 this: &builtin_trace,61 s: State,62 loc: CallLocation,63 str: IStr,64 rest: Thunk<Val>,65) -> Result<Any> {66 this.settings67 .borrow()68 .trace_printer69 .print_trace(s.clone(), loc, str);70 Ok(Any(rest.evaluate(s)?))71}7273#[allow(clippy::comparison_chain)]74#[builtin]75pub fn builtin_starts_with(76 s: State,77 a: Either![IStr, ArrValue],78 b: Either![IStr, ArrValue],79) -> Result<bool> {80 Ok(match (a, b) {81 (Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),82 (Either2::B(a), Either2::B(b)) => {83 if b.len() > a.len() {84 return Ok(false);85 } else if b.len() == a.len() {86 return equals(s, &Val::Arr(a), &Val::Arr(b));87 } else {88 for (a, b) in a89 .slice(None, Some(b.len()), None)90 .iter(s.clone())91 .zip(b.iter(s.clone()))92 {93 let a = a?;94 let b = b?;95 if !equals(s.clone(), &a, &b)? {96 return Ok(false);97 }98 }99 true100 }101 }102 _ => throw!("both arguments should be of the same type"),103 })104}105106#[allow(clippy::comparison_chain)]107#[builtin]108pub fn builtin_ends_with(109 s: State,110 a: Either![IStr, ArrValue],111 b: Either![IStr, ArrValue],112) -> Result<bool> {113 Ok(match (a, b) {114 (Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),115 (Either2::B(a), Either2::B(b)) => {116 if b.len() > a.len() {117 return Ok(false);118 } else if b.len() == a.len() {119 return equals(s, &Val::Arr(a), &Val::Arr(b));120 } else {121 let a_len = a.len();122 for (a, b) in a123 .slice(Some(a_len - b.len()), None, None)124 .iter(s.clone())125 .zip(b.iter(s.clone()))126 {127 let a = a?;128 let b = b?;129 if !equals(s.clone(), &a, &b)? {130 return Ok(false);131 }132 }133 true134 }135 }136 _ => throw!("both arguments should be of the same type"),137 })138}