diff --git a/crates/jrsonnet-evaluator/src/arr/mod.rs b/crates/jrsonnet-evaluator/src/arr/mod.rs index 7aefaa48..05e929a0 100644 --- a/crates/jrsonnet-evaluator/src/arr/mod.rs +++ b/crates/jrsonnet-evaluator/src/arr/mod.rs @@ -14,7 +14,7 @@ pub use spec::{ArrayLike, *}; /// Represents a Jsonnet array value. #[derive(Debug, Clone, Trace)] -// may contrain other ArrValue +// may contain other ArrValue #[trace(tracking(force))] pub struct ArrValue(Cc>); diff --git a/crates/jrsonnet-evaluator/src/val.rs b/crates/jrsonnet-evaluator/src/val.rs index d0a42cc1..28810a96 100644 --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -220,6 +220,13 @@ pub enum IndexableVal { Arr(ArrValue), } impl IndexableVal { + pub fn empty(&self) -> bool { + match self { + Self::Str(s) => s.is_empty(), + Self::Arr(s) => s.is_empty(), + } + } + pub fn to_array(self) -> ArrValue { match self { Self::Str(s) => ArrValue::chars(s.chars()), diff --git a/crates/jrsonnet-stdlib/src/lib.rs b/crates/jrsonnet-stdlib/src/lib.rs index 99333fc3..a608c037 100644 --- a/crates/jrsonnet-stdlib/src/lib.rs +++ b/crates/jrsonnet-stdlib/src/lib.rs @@ -201,6 +201,9 @@ pub fn stdlib_uncached(settings: Rc>) -> ObjValue { ("parseOctal", builtin_parse_octal::INST), ("parseHex", builtin_parse_hex::INST), ("stringChars", builtin_string_chars::INST), + ("lstripChars", builtin_lstrip_chars::INST), + ("rstripChars", builtin_rstrip_chars::INST), + ("stripChars", builtin_strip_chars::INST), // Misc ("length", builtin_length::INST), ("get", builtin_get::INST), diff --git a/crates/jrsonnet-stdlib/src/std.jsonnet b/crates/jrsonnet-stdlib/src/std.jsonnet index 6f793848..020b69b2 100644 --- a/crates/jrsonnet-stdlib/src/std.jsonnet +++ b/crates/jrsonnet-stdlib/src/std.jsonnet @@ -3,22 +3,6 @@ thisFile:: error 'std.thisFile is deprecated, to enable its support in jrsonnet - recompile it with "legacy-this-file" support.\nThis will slow down stdlib caching a bit, though', - lstripChars(str, chars):: - if std.length(str) > 0 && std.member(chars, str[0]) then - std.lstripChars(str[1:], chars) - else - str, - - rstripChars(str, chars):: - local len = std.length(str); - if len > 0 && std.member(chars, str[len - 1]) then - std.rstripChars(str[:len - 1], chars) - else - str, - - stripChars(str, chars):: - std.lstripChars(std.rstripChars(str, chars), chars), - mapWithIndex(func, arr):: if !std.isFunction(func) then error ('std.mapWithIndex first param must be function, got ' + std.type(func)) diff --git a/crates/jrsonnet-stdlib/src/strings.rs b/crates/jrsonnet-stdlib/src/strings.rs index 39a2281b..c9ec5b1c 100644 --- a/crates/jrsonnet-stdlib/src/strings.rs +++ b/crates/jrsonnet-stdlib/src/strings.rs @@ -1,9 +1,11 @@ +use std::{collections::BTreeSet, str::pattern::Pattern}; + use jrsonnet_evaluator::{ bail, error::{ErrorKind::*, Result}, function::builtin, typed::{Either2, M1}, - val::ArrValue, + val::{ArrValue, IndexableVal}, Either, IStr, Val, }; @@ -215,6 +217,53 @@ pub fn builtin_bigint(v: Either![f64, IStr]) -> Result { }) } +#[builtin] +pub fn builtin_string_chars(str: IStr) -> ArrValue { + ArrValue::chars(str.chars()) +} + +#[builtin] +pub fn builtin_lstrip_chars(str: IStr, chars: IndexableVal) -> Result { + if str.is_empty() || chars.empty() { + return str; + } + + let pattern = new_trim_pattern(chars)?; + str.as_str().trim_start_matches(pattern).into() +} + +#[builtin] +pub fn builtin_rstrip_chars(str: IStr, chars: IndexableVal) -> Result { + if str.is_empty() || chars.empty() { + return str; + } + + let pattern = new_trim_pattern(chars)?; + str.as_str().trim_start_matches(pattern).into() +} + +#[builtin] +pub fn builtin_strip_chars(str: IStr, chars: IndexableVal) -> Result { + if str.is_empty() || chars.empty() { + return str; + } + + let pattern = new_trim_pattern(chars)?; + str.as_str().trim_start_matches(pattern).into() +} + +fn new_trim_pattern(chars: IndexableVal) -> Result bool> { + let chars: BTreeSet = match chars { + IndexableVal::Str(chars) => chars.chars().collect(), + IndexableVal::Arr(chars) => chars + .iter() + .filter_map(|it| it.map(|it| it.as_str()).transpose()) + .collect()?, + }; + + Ok(|char| chars.contains(&char)) +} + #[cfg(test)] mod tests { use super::*; @@ -243,8 +292,3 @@ mod tests { assert_eq!(parse_nat::<16>("BbC").unwrap(), 0xBBC as f64); } } - -#[builtin] -pub fn builtin_string_chars(str: IStr) -> ArrValue { - ArrValue::chars(str.chars()) -}