difftreelog
refactor(stdlib) split more builtins into own files
in: master
3 files changed
crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth39pub use manifest::*;39pub use manifest::*;40mod parse;40mod parse;41pub use parse::*;41pub use parse::*;42mod strings;43pub use strings::*;44mod misc;45pub use misc::*;424643pub fn stdlib_uncached(s: State, settings: Rc<RefCell<Settings>>) -> ObjValue {47pub fn stdlib_uncached(s: State, settings: Rc<RefCell<Settings>>) -> ObjValue {44 let mut builder = ObjValueBuilder::new();48 let mut builder = ObjValueBuilder::new();52 builder.with_super(eval);56 builder.with_super(eval);535754 for (name, builtin) in [58 for (name, builtin) in [55 ("length", builtin_length::INST),56 // Types59 // Types57 ("type", builtin_type::INST),60 ("type", builtin_type::INST),58 ("isString", builtin_is_string::INST),61 ("isString", builtin_is_string::INST),117 // Parsing120 // Parsing118 ("parseJson", builtin_parse_json::INST),121 ("parseJson", builtin_parse_json::INST),119 ("parseYaml", builtin_parse_yaml::INST),122 ("parseYaml", builtin_parse_yaml::INST),120 // Misc123 // Strings121 ("codepoint", builtin_codepoint::INST),124 ("codepoint", builtin_codepoint::INST),122 ("substr", builtin_substr::INST),125 ("substr", builtin_substr::INST),123 ("char", builtin_char::INST),126 ("char", builtin_char::INST),126 ("asciiUpper", builtin_ascii_upper::INST),129 ("asciiUpper", builtin_ascii_upper::INST),127 ("asciiLower", builtin_ascii_lower::INST),130 ("asciiLower", builtin_ascii_lower::INST),128 ("findSubstr", builtin_find_substr::INST),131 ("findSubstr", builtin_find_substr::INST),132 // Misc133 ("length", builtin_length::INST),129 ("startsWith", builtin_starts_with::INST),134 ("startsWith", builtin_starts_with::INST),130 ("endsWith", builtin_ends_with::INST),135 ("endsWith", builtin_ends_with::INST),131 ]136 ]345 }350 }346}351}347348#[builtin]349fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> Result<usize> {350 use Either4::*;351 Ok(match x {352 A(x) => x.chars().count(),353 B(x) => x.len(),354 C(x) => x.len(),355 D(f) => f.params_len(),356 })357}358359#[builtin]360const fn builtin_codepoint(str: char) -> Result<u32> {361 Ok(str as u32)362}363364#[builtin]365fn builtin_substr(str: IStr, from: usize, len: usize) -> Result<String> {366 Ok(str.chars().skip(from).take(len).collect())367}368369#[builtin(fields(370 settings: Rc<RefCell<Settings>>,371))]372fn builtin_ext_var(this: &builtin_ext_var, s: State, x: IStr) -> Result<Any> {373 let ctx = s.create_default_context(extvar_source(&x, ""));374 Ok(Any(this375 .settings376 .borrow()377 .ext_vars378 .get(&x)379 .cloned()380 .ok_or_else(|| UndefinedExternalVariable(x))?381 .evaluate_arg(s.clone(), ctx, true)?382 .evaluate(s)?))383}384385#[builtin(fields(386 settings: Rc<RefCell<Settings>>,387))]388fn builtin_native(this: &builtin_native, name: IStr) -> Result<Any> {389 Ok(Any(this390 .settings391 .borrow()392 .ext_natives393 .get(&name)394 .cloned()395 .map_or(Val::Null, |v| {396 Val::Func(FuncVal::Builtin(v.clone()))397 })))398}399400#[builtin]401fn builtin_char(n: u32) -> Result<char> {402 Ok(std::char::from_u32(n).ok_or_else(|| InvalidUnicodeCodepointGot(n))?)403}404405#[builtin(fields(406 settings: Rc<RefCell<Settings>>,407))]408fn builtin_trace(409 this: &builtin_trace,410 s: State,411 loc: CallLocation,412 str: IStr,413 rest: Thunk<Val>,414) -> Result<Any> {415 this.settings416 .borrow()417 .trace_printer418 .print_trace(s.clone(), loc, str);419 Ok(Any(rest.evaluate(s)?))420}421422#[builtin]423fn builtin_str_replace(str: String, from: IStr, to: IStr) -> Result<String> {424 Ok(str.replace(&from as &str, &to as &str))425}426427#[builtin]428fn builtin_splitlimit(str: IStr, c: IStr, maxsplits: Either![usize, M1]) -> Result<VecVal> {429 use Either2::*;430 Ok(VecVal(Cc::new(match maxsplits {431 A(n) => str432 .splitn(n + 1, &c as &str)433 .map(|s| Val::Str(s.into()))434 .collect(),435 B(_) => str.split(&c as &str).map(|s| Val::Str(s.into())).collect(),436 })))437}438439#[builtin]440fn builtin_ascii_upper(str: IStr) -> Result<String> {441 Ok(str.to_ascii_uppercase())442}443444#[builtin]445fn builtin_ascii_lower(str: IStr) -> Result<String> {446 Ok(str.to_ascii_lowercase())447}448449#[builtin]450fn builtin_find_substr(pat: IStr, str: IStr) -> Result<ArrValue> {451 if pat.is_empty() || str.is_empty() || pat.len() > str.len() {452 return Ok(ArrValue::empty());453 }454455 let str = str.as_str();456 let pat = pat.as_bytes();457 let strb = str.as_bytes();458459 let max_pos = str.len() - pat.len();460461 let mut out: Vec<Val> = Vec::new();462 for (ch_idx, (i, _)) in str463 .char_indices()464 .take_while(|(i, _)| i <= &max_pos)465 .enumerate()466 {467 if &strb[i..i + pat.len()] == pat {468 out.push(Val::Num(ch_idx as f64))469 }470 }471 Ok(out.into())472}473474#[allow(clippy::comparison_chain)]475#[builtin]476fn builtin_starts_with(477 s: State,478 a: Either![IStr, ArrValue],479 b: Either![IStr, ArrValue],480) -> Result<bool> {481 Ok(match (a, b) {482 (Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),483 (Either2::B(a), Either2::B(b)) => {484 if b.len() > a.len() {485 return Ok(false);486 } else if b.len() == a.len() {487 return equals(s, &Val::Arr(a), &Val::Arr(b));488 } else {489 for (a, b) in a490 .slice(None, Some(b.len()), None)491 .iter(s.clone())492 .zip(b.iter(s.clone()))493 {494 let a = a?;495 let b = b?;496 if !equals(s.clone(), &a, &b)? {497 return Ok(false);498 }499 }500 true501 }502 }503 _ => throw!("both arguments should be of the same type"),504 })505}506507#[allow(clippy::comparison_chain)]508#[builtin]509fn builtin_ends_with(510 s: State,511 a: Either![IStr, ArrValue],512 b: Either![IStr, ArrValue],513) -> Result<bool> {514 Ok(match (a, b) {515 (Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),516 (Either2::B(a), Either2::B(b)) => {517 if b.len() > a.len() {518 return Ok(false);519 } else if b.len() == a.len() {520 return equals(s, &Val::Arr(a), &Val::Arr(b));521 } else {522 let a_len = a.len();523 for (a, b) in a524 .slice(Some(a_len - b.len()), None, None)525 .iter(s.clone())526 .zip(b.iter(s.clone()))527 {528 let a = a?;529 let b = b?;530 if !equals(s.clone(), &a, &b)? {531 return Ok(false);532 }533 }534 true535 }536 }537 _ => throw!("both arguments should be of the same type"),538 })539}540352541pub trait StateExt {353pub trait StateExt {542 /// This method was previously implemented in jrsonnet-evaluator itself354 /// This method was previously implemented in jrsonnet-evaluator itselfcrates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -0,0 +1,138 @@
+use std::{cell::RefCell, rc::Rc};
+
+use jrsonnet_evaluator::{
+ error::{Error::*, Result},
+ function::{builtin, ArgLike, CallLocation, FuncVal},
+ throw,
+ typed::{Any, Either2, Either4},
+ val::{equals, ArrValue},
+ Either, IStr, ObjValue, State, Thunk, Val,
+};
+
+use crate::{extvar_source, Settings};
+
+#[builtin]
+pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> Result<usize> {
+ use Either4::*;
+ Ok(match x {
+ A(x) => x.chars().count(),
+ B(x) => x.len(),
+ C(x) => x.len(),
+ D(f) => f.params_len(),
+ })
+}
+
+#[builtin(fields(
+ settings: Rc<RefCell<Settings>>,
+))]
+pub fn builtin_ext_var(this: &builtin_ext_var, s: State, x: IStr) -> Result<Any> {
+ let ctx = s.create_default_context(extvar_source(&x, ""));
+ Ok(Any(this
+ .settings
+ .borrow()
+ .ext_vars
+ .get(&x)
+ .cloned()
+ .ok_or_else(|| UndefinedExternalVariable(x))?
+ .evaluate_arg(s.clone(), ctx, true)?
+ .evaluate(s)?))
+}
+
+#[builtin(fields(
+ settings: Rc<RefCell<Settings>>,
+))]
+pub fn builtin_native(this: &builtin_native, name: IStr) -> Result<Any> {
+ Ok(Any(this
+ .settings
+ .borrow()
+ .ext_natives
+ .get(&name)
+ .cloned()
+ .map_or(Val::Null, |v| {
+ Val::Func(FuncVal::Builtin(v.clone()))
+ })))
+}
+
+#[builtin(fields(
+ settings: Rc<RefCell<Settings>>,
+))]
+pub fn builtin_trace(
+ this: &builtin_trace,
+ s: State,
+ loc: CallLocation,
+ str: IStr,
+ rest: Thunk<Val>,
+) -> Result<Any> {
+ this.settings
+ .borrow()
+ .trace_printer
+ .print_trace(s.clone(), loc, str);
+ Ok(Any(rest.evaluate(s)?))
+}
+
+#[allow(clippy::comparison_chain)]
+#[builtin]
+pub fn builtin_starts_with(
+ s: State,
+ a: Either![IStr, ArrValue],
+ b: Either![IStr, ArrValue],
+) -> Result<bool> {
+ Ok(match (a, b) {
+ (Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),
+ (Either2::B(a), Either2::B(b)) => {
+ if b.len() > a.len() {
+ return Ok(false);
+ } else if b.len() == a.len() {
+ return equals(s, &Val::Arr(a), &Val::Arr(b));
+ } else {
+ for (a, b) in a
+ .slice(None, Some(b.len()), None)
+ .iter(s.clone())
+ .zip(b.iter(s.clone()))
+ {
+ let a = a?;
+ let b = b?;
+ if !equals(s.clone(), &a, &b)? {
+ return Ok(false);
+ }
+ }
+ true
+ }
+ }
+ _ => throw!("both arguments should be of the same type"),
+ })
+}
+
+#[allow(clippy::comparison_chain)]
+#[builtin]
+pub fn builtin_ends_with(
+ s: State,
+ a: Either![IStr, ArrValue],
+ b: Either![IStr, ArrValue],
+) -> Result<bool> {
+ Ok(match (a, b) {
+ (Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),
+ (Either2::B(a), Either2::B(b)) => {
+ if b.len() > a.len() {
+ return Ok(false);
+ } else if b.len() == a.len() {
+ return equals(s, &Val::Arr(a), &Val::Arr(b));
+ } else {
+ let a_len = a.len();
+ for (a, b) in a
+ .slice(Some(a_len - b.len()), None, None)
+ .iter(s.clone())
+ .zip(b.iter(s.clone()))
+ {
+ let a = a?;
+ let b = b?;
+ if !equals(s.clone(), &a, &b)? {
+ return Ok(false);
+ }
+ }
+ true
+ }
+ }
+ _ => throw!("both arguments should be of the same type"),
+ })
+}
crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -0,0 +1,75 @@
+use jrsonnet_evaluator::{
+ error::{Error::*, Result},
+ function::builtin,
+ typed::{Either2, VecVal, M1},
+ val::ArrValue,
+ Either, IStr, Val,
+};
+use jrsonnet_gcmodule::Cc;
+
+#[builtin]
+pub const fn builtin_codepoint(str: char) -> Result<u32> {
+ Ok(str as u32)
+}
+
+#[builtin]
+pub fn builtin_substr(str: IStr, from: usize, len: usize) -> Result<String> {
+ Ok(str.chars().skip(from).take(len).collect())
+}
+
+#[builtin]
+pub fn builtin_char(n: u32) -> Result<char> {
+ Ok(std::char::from_u32(n).ok_or_else(|| InvalidUnicodeCodepointGot(n))?)
+}
+
+#[builtin]
+pub fn builtin_str_replace(str: String, from: IStr, to: IStr) -> Result<String> {
+ Ok(str.replace(&from as &str, &to as &str))
+}
+
+#[builtin]
+pub fn builtin_splitlimit(str: IStr, c: IStr, maxsplits: Either![usize, M1]) -> Result<VecVal> {
+ use Either2::*;
+ Ok(VecVal(Cc::new(match maxsplits {
+ A(n) => str
+ .splitn(n + 1, &c as &str)
+ .map(|s| Val::Str(s.into()))
+ .collect(),
+ B(_) => str.split(&c as &str).map(|s| Val::Str(s.into())).collect(),
+ })))
+}
+
+#[builtin]
+pub fn builtin_ascii_upper(str: IStr) -> Result<String> {
+ Ok(str.to_ascii_uppercase())
+}
+
+#[builtin]
+pub fn builtin_ascii_lower(str: IStr) -> Result<String> {
+ Ok(str.to_ascii_lowercase())
+}
+
+#[builtin]
+pub fn builtin_find_substr(pat: IStr, str: IStr) -> Result<ArrValue> {
+ if pat.is_empty() || str.is_empty() || pat.len() > str.len() {
+ return Ok(ArrValue::empty());
+ }
+
+ let str = str.as_str();
+ let pat = pat.as_bytes();
+ let strb = str.as_bytes();
+
+ let max_pos = str.len() - pat.len();
+
+ let mut out: Vec<Val> = Vec::new();
+ for (ch_idx, (i, _)) in str
+ .char_indices()
+ .take_while(|(i, _)| i <= &max_pos)
+ .enumerate()
+ {
+ if &strb[i..i + pat.len()] == pat {
+ out.push(Val::Num(ch_idx as f64))
+ }
+ }
+ Ok(out.into())
+}