difftreelog
refactor prefer builtins over natives
in: master
8 files changed
bindings/jsonnet/src/native.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/native.rs
+++ b/bindings/jsonnet/src/native.rs
@@ -1,11 +1,11 @@
use gcmodule::Cc;
use jrsonnet_evaluator::{
error::{Error, LocError},
+ function::BuiltinParam,
gc::TraceBox,
native::{NativeCallback, NativeCallbackHandler},
EvaluationState, IStr, Val,
};
-use jrsonnet_parser::{Param, ParamsDesc};
use std::{
convert::TryFrom,
ffi::{c_void, CStr},
@@ -28,7 +28,7 @@
cb: JsonnetNativeCallback,
}
impl NativeCallbackHandler for JsonnetNativeCallbackHandler {
- fn call(&self, _from: Rc<Path>, args: &[Val]) -> Result<Val, LocError> {
+ fn call(&self, _from: Option<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {
let mut n_args = Vec::new();
for a in args {
n_args.push(Some(Box::new(a.clone())));
@@ -68,16 +68,19 @@
break;
}
let param = CStr::from_ptr(*raw_params).to_str().expect("not utf8");
- params.push(Param(param.into(), None));
+ params.push(BuiltinParam {
+ name: param.into(),
+ has_default: false,
+ });
raw_params = raw_params.offset(1);
}
- let params = ParamsDesc(Rc::new(params));
vm.add_native(
name,
- Cc::new(NativeCallback::new(
+ #[allow(deprecated)]
+ Cc::new(TraceBox(Box::new(NativeCallback::new(
params,
TraceBox(Box::new(JsonnetNativeCallbackHandler { ctx, cb })),
- )),
+ )))),
)
}
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth1use crate::function::StaticBuiltin;2use crate::typed::{Any, PositiveF64, VecVal, M1};3use crate::{4 builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},5 equals,6 error::{Error::*, Result},7 operator::evaluate_mod_op,8 primitive_equals, push_frame, throw,9 typed::{Either2, Either4},10 with_state, ArrValue, Context, FuncVal, IndexableVal, Val,11};12use crate::{Either, ObjValue};13use format::{format_arr, format_obj};14use gcmodule::Cc;15use jrsonnet_interner::IStr;16use jrsonnet_parser::ExprLocation;17use serde::Deserialize;18use serde_yaml::DeserializingQuirks;19use std::collections::HashMap;20use std::convert::{TryFrom, TryInto};2122pub mod stdlib;23pub use stdlib::*;2425use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};2627pub mod format;28pub mod manifest;29pub mod sort;3031pub fn std_format(str: IStr, vals: Val) -> Result<String> {32 push_frame(33 None,34 || format!("std.format of {}", str),35 || {36 Ok(match vals {37 Val::Arr(vals) => format_arr(&str, &vals.evaluated()?)?,38 Val::Obj(obj) => format_obj(&str, &obj)?,39 o => format_arr(&str, &[o])?,40 })41 },42 )43}4445pub fn std_slice(46 indexable: IndexableVal,47 index: Option<usize>,48 end: Option<usize>,49 step: Option<usize>,50) -> Result<Val> {51 let index = index.unwrap_or(0);52 let end = end.unwrap_or_else(|| match &indexable {53 IndexableVal::Str(_) => usize::MAX,54 IndexableVal::Arr(v) => v.len(),55 });56 let step = step.unwrap_or(1);57 match &indexable {58 IndexableVal::Str(s) => Ok(Val::Str(59 (s.chars()60 .skip(index)61 .take(end - index)62 .step_by(step)63 .collect::<String>())64 .into(),65 )),66 IndexableVal::Arr(arr) => Ok(Val::Arr(67 (arr.iter()68 .skip(index)69 .take(end - index)70 .step_by(step)71 .collect::<Result<Vec<Val>>>()?)72 .into(),73 )),74 }75}7677type BuiltinsType = HashMap<IStr, &'static dyn StaticBuiltin>;7879thread_local! {80 pub static BUILTINS: BuiltinsType = {81 [82 ("length".into(), builtin_length::INST),83 ("type".into(), builtin_type::INST),84 ("makeArray".into(), builtin_make_array::INST),85 ("codepoint".into(), builtin_codepoint::INST),86 ("objectFieldsEx".into(), builtin_object_fields_ex::INST),87 ("objectHasEx".into(), builtin_object_has_ex::INST),88 ("slice".into(), builtin_slice::INST),89 ("substr".into(), builtin_substr::INST),90 ("primitiveEquals".into(), builtin_primitive_equals::INST),91 ("equals".into(), builtin_equals::INST),92 ("modulo".into(), builtin_modulo::INST),93 ("mod".into(), builtin_mod::INST),94 ("floor".into(), builtin_floor::INST),95 ("ceil".into(), builtin_ceil::INST),96 ("log".into(), builtin_log::INST),97 ("pow".into(), builtin_pow::INST),98 ("sqrt".into(), builtin_sqrt::INST),99 ("sin".into(), builtin_sin::INST),100 ("cos".into(), builtin_cos::INST),101 ("tan".into(), builtin_tan::INST),102 ("asin".into(), builtin_asin::INST),103 ("acos".into(), builtin_acos::INST),104 ("atan".into(), builtin_atan::INST),105 ("exp".into(), builtin_exp::INST),106 ("mantissa".into(), builtin_mantissa::INST),107 ("exponent".into(), builtin_exponent::INST),108 ("extVar".into(), builtin_ext_var::INST),109 ("native".into(), builtin_native::INST),110 ("filter".into(), builtin_filter::INST),111 ("map".into(), builtin_map::INST),112 ("flatMap".into(), builtin_flatmap::INST),113 ("foldl".into(), builtin_foldl::INST),114 ("foldr".into(), builtin_foldr::INST),115 ("sort".into(), builtin_sort::INST),116 ("format".into(), builtin_format::INST),117 ("range".into(), builtin_range::INST),118 ("char".into(), builtin_char::INST),119 ("encodeUTF8".into(), builtin_encode_utf8::INST),120 ("decodeUTF8".into(), builtin_decode_utf8::INST),121 ("md5".into(), builtin_md5::INST),122 ("base64".into(), builtin_base64::INST),123 ("base64DecodeBytes".into(), builtin_base64_decode_bytes::INST),124 ("base64Decode".into(), builtin_base64_decode::INST),125 ("trace".into(), builtin_trace::INST),126 ("join".into(), builtin_join::INST),127 ("escapeStringJson".into(), builtin_escape_string_json::INST),128 ("manifestJsonEx".into(), builtin_manifest_json_ex::INST),129 ("manifestYamlDoc".into(), builtin_manifest_yaml_doc::INST),130 ("reverse".into(), builtin_reverse::INST),131 ("id".into(), builtin_id::INST),132 ("strReplace".into(), builtin_str_replace::INST),133 ("splitLimit".into(), builtin_splitlimit::INST),134 ("parseJson".into(), builtin_parse_json::INST),135 ("parseYaml".into(), builtin_parse_yaml::INST),136 ("asciiUpper".into(), builtin_ascii_upper::INST),137 ("asciiLower".into(), builtin_ascii_lower::INST),138 ("member".into(), builtin_member::INST),139 ("count".into(), builtin_count::INST),140 ].iter().cloned().collect()141 };142}143144#[jrsonnet_macros::builtin]145fn builtin_length(x: Either![IStr, VecVal, ObjValue, Cc<FuncVal>]) -> Result<usize> {146 use Either4::*;147 Ok(match x {148 A(x) => x.chars().count(),149 B(x) => x.0.len(),150 C(x) => x151 .fields_visibility()152 .into_iter()153 .filter(|(_k, v)| *v)154 .count(),155 D(f) => f.args_len(),156 })157}158159#[jrsonnet_macros::builtin]160fn builtin_type(x: Any) -> Result<IStr> {161 Ok(x.0.value_type().name().into())162}163164#[jrsonnet_macros::builtin]165fn builtin_make_array(sz: usize, func: Cc<FuncVal>) -> Result<VecVal> {166 let mut out = Vec::with_capacity(sz);167 for i in 0..sz {168 out.push(func.evaluate_simple(&[i as f64].as_slice())?)169 }170 Ok(VecVal(out))171}172173#[jrsonnet_macros::builtin]174const fn builtin_codepoint(str: char) -> Result<u32> {175 Ok(str as u32)176}177178#[jrsonnet_macros::builtin]179fn builtin_object_fields_ex(obj: ObjValue, inc_hidden: bool) -> Result<VecVal> {180 let out = obj.fields_ex(inc_hidden);181 Ok(VecVal(out.into_iter().map(Val::Str).collect::<Vec<_>>()))182}183184#[jrsonnet_macros::builtin]185fn builtin_object_has_ex(obj: ObjValue, f: IStr, inc_hidden: bool) -> Result<bool> {186 Ok(obj.has_field_ex(f, inc_hidden))187}188189#[jrsonnet_macros::builtin]190fn builtin_parse_json(s: IStr) -> Result<Any> {191 let value: serde_json::Value = serde_json::from_str(&s)192 .map_err(|e| RuntimeError(format!("failed to parse json: {}", e).into()))?;193 Ok(Any(Val::try_from(&value)?))194}195196#[jrsonnet_macros::builtin]197fn builtin_parse_yaml(s: IStr) -> Result<Any> {198 let value = serde_yaml::Deserializer::from_str_with_quirks(199 &s,200 DeserializingQuirks { old_octals: true },201 );202 let mut out = vec![];203 for item in value {204 let value = serde_json::Value::deserialize(item)205 .map_err(|e| RuntimeError(format!("failed to parse yaml: {}", e).into()))?;206 let val = Val::try_from(&value)?;207 out.push(val);208 }209 Ok(Any(if out.is_empty() {210 Val::Null211 } else if out.len() == 1 {212 out.into_iter().next().unwrap()213 } else {214 Val::Arr(out.into())215 }))216}217218#[jrsonnet_macros::builtin]219fn builtin_slice(220 indexable: IndexableVal,221 index: Option<usize>,222 end: Option<usize>,223 step: Option<usize>,224) -> Result<Any> {225 std_slice(indexable, index, end, step).map(Any)226}227228#[jrsonnet_macros::builtin]229fn builtin_substr(str: IStr, from: usize, len: usize) -> Result<String> {230 Ok(str.chars().skip(from as usize).take(len as usize).collect())231}232233#[jrsonnet_macros::builtin]234fn builtin_primitive_equals(a: Any, b: Any) -> Result<bool> {235 primitive_equals(&a.0, &b.0)236}237238#[jrsonnet_macros::builtin]239fn builtin_equals(a: Any, b: Any) -> Result<bool> {240 equals(&a.0, &b.0)241}242243#[jrsonnet_macros::builtin]244fn builtin_modulo(a: f64, b: f64) -> Result<f64> {245 Ok(a % b)246}247248#[jrsonnet_macros::builtin]249fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result<Any> {250 use Either2::*;251 Ok(Any(evaluate_mod_op(252 &match a {253 A(v) => Val::Num(v),254 B(s) => Val::Str(s),255 },256 &b.0,257 )?))258}259260#[jrsonnet_macros::builtin]261fn builtin_floor(x: f64) -> Result<f64> {262 Ok(x.floor())263}264265#[jrsonnet_macros::builtin]266fn builtin_ceil(x: f64) -> Result<f64> {267 Ok(x.ceil())268}269270#[jrsonnet_macros::builtin]271fn builtin_log(n: f64) -> Result<f64> {272 Ok(n.ln())273}274275#[jrsonnet_macros::builtin]276fn builtin_pow(x: f64, n: f64) -> Result<f64> {277 Ok(x.powf(n))278}279280#[jrsonnet_macros::builtin]281fn builtin_sqrt(x: PositiveF64) -> Result<f64> {282 Ok(x.0.sqrt())283}284285#[jrsonnet_macros::builtin]286fn builtin_sin(x: f64) -> Result<f64> {287 Ok(x.sin())288}289290#[jrsonnet_macros::builtin]291fn builtin_cos(x: f64) -> Result<f64> {292 Ok(x.cos())293}294295#[jrsonnet_macros::builtin]296fn builtin_tan(x: f64) -> Result<f64> {297 Ok(x.tan())298}299300#[jrsonnet_macros::builtin]301fn builtin_asin(x: f64) -> Result<f64> {302 Ok(x.asin())303}304305#[jrsonnet_macros::builtin]306fn builtin_acos(x: f64) -> Result<f64> {307 Ok(x.acos())308}309310#[jrsonnet_macros::builtin]311fn builtin_atan(x: f64) -> Result<f64> {312 Ok(x.atan())313}314315#[jrsonnet_macros::builtin]316fn builtin_exp(x: f64) -> Result<f64> {317 Ok(x.exp())318}319320fn frexp(s: f64) -> (f64, i16) {321 if 0.0 == s {322 (s, 0)323 } else {324 let lg = s.abs().log2();325 let x = (lg - lg.floor() - 1.0).exp2();326 let exp = lg.floor() + 1.0;327 (s.signum() * x, exp as i16)328 }329}330331#[jrsonnet_macros::builtin]332fn builtin_mantissa(x: f64) -> Result<f64> {333 Ok(frexp(x).0)334}335336#[jrsonnet_macros::builtin]337fn builtin_exponent(x: f64) -> Result<i16> {338 Ok(frexp(x).1)339}340341#[jrsonnet_macros::builtin]342fn builtin_ext_var(x: IStr) -> Result<Any> {343 Ok(Any(with_state(|s| s.settings().ext_vars.get(&x).cloned())344 .ok_or(UndefinedExternalVariable(x))?))345}346347#[jrsonnet_macros::builtin]348fn builtin_native(name: IStr) -> Result<Cc<FuncVal>> {349 Ok(with_state(|s| s.settings().ext_natives.get(&name).cloned())350 .map(|v| Cc::new(FuncVal::NativeExt(name.clone(), v)))351 .ok_or(UndefinedExternalFunction(name))?)352}353354#[jrsonnet_macros::builtin]355fn builtin_filter(func: Cc<FuncVal>, arr: ArrValue) -> Result<ArrValue> {356 arr.filter(|val| bool::try_from(func.evaluate_simple(&[Any(val.clone())].as_slice())?))357}358359#[jrsonnet_macros::builtin]360fn builtin_map(func: Cc<FuncVal>, arr: ArrValue) -> Result<ArrValue> {361 arr.map(|val| func.evaluate_simple(&[Any(val)].as_slice()))362}363364#[jrsonnet_macros::builtin]365fn builtin_flatmap(func: Cc<FuncVal>, arr: IndexableVal) -> Result<IndexableVal> {366 match arr {367 IndexableVal::Str(s) => {368 let mut out = String::new();369 for c in s.chars() {370 match func.evaluate_simple(&[c.to_string()].as_slice())? {371 Val::Str(o) => out.push_str(&o),372 _ => throw!(RuntimeError(373 "in std.join all items should be strings".into()374 )),375 };376 }377 Ok(IndexableVal::Str(out.into()))378 }379 IndexableVal::Arr(a) => {380 let mut out = Vec::new();381 for el in a.iter() {382 let el = el?;383 match func.evaluate_simple(&[Any(el)].as_slice())? {384 Val::Arr(o) => {385 for oe in o.iter() {386 out.push(oe?)387 }388 }389 _ => throw!(RuntimeError(390 "in std.join all items should be arrays".into()391 )),392 };393 }394 Ok(IndexableVal::Arr(out.into()))395 }396 }397}398399#[jrsonnet_macros::builtin]400fn builtin_foldl(func: Cc<FuncVal>, arr: ArrValue, init: Any) -> Result<Any> {401 let mut acc = init.0;402 for i in arr.iter() {403 acc = func.evaluate_simple(&[Any(acc), Any(i?)].as_slice())?;404 }405 Ok(Any(acc))406}407408#[jrsonnet_macros::builtin]409fn builtin_foldr(func: Cc<FuncVal>, arr: ArrValue, init: Any) -> Result<Any> {410 let mut acc = init.0;411 for i in arr.iter().rev() {412 acc = func.evaluate_simple(&[Any(i?), Any(acc)].as_slice())?;413 }414 Ok(Any(acc))415}416417#[jrsonnet_macros::builtin]418#[allow(non_snake_case)]419fn builtin_sort(arr: ArrValue, keyF: Option<Cc<FuncVal>>) -> Result<ArrValue> {420 if arr.len() <= 1 {421 return Ok(arr);422 }423 Ok(ArrValue::Eager(sort::sort(424 arr.evaluated()?,425 keyF.as_deref(),426 )?))427}428429#[jrsonnet_macros::builtin]430fn builtin_format(str: IStr, vals: Any) -> Result<String> {431 std_format(str, vals.0)432}433434#[jrsonnet_macros::builtin]435fn builtin_range(from: i32, to: i32) -> Result<VecVal> {436 if to < from {437 return Ok(VecVal(Vec::new()));438 }439 let mut out = Vec::with_capacity((1 + to as usize - from as usize).max(0));440 for i in from as usize..=to as usize {441 out.push(Val::Num(i as f64));442 }443 Ok(VecVal(out))444}445446#[jrsonnet_macros::builtin]447fn builtin_char(n: u32) -> Result<char> {448 Ok(std::char::from_u32(n as u32).ok_or(InvalidUnicodeCodepointGot(n as u32))?)449}450451#[jrsonnet_macros::builtin]452fn builtin_encode_utf8(str: IStr) -> Result<VecVal> {453 Ok(VecVal(454 str.bytes()455 .map(|b| Val::Num(b as f64))456 .collect::<Vec<Val>>(),457 ))458}459460#[jrsonnet_macros::builtin]461fn builtin_decode_utf8(arr: Vec<u8>) -> Result<String> {462 Ok(String::from_utf8(arr).map_err(|_| RuntimeError("bad utf8".into()))?)463}464465#[jrsonnet_macros::builtin]466fn builtin_md5(str: IStr) -> Result<String> {467 Ok(format!("{:x}", md5::compute(&str.as_bytes())))468}469470#[jrsonnet_macros::builtin]471fn builtin_trace(#[location] loc: Option<&ExprLocation>, str: IStr, rest: Any) -> Result<Any> {472 eprint!("TRACE:");473 if let Some(loc) = loc {474 with_state(|s| {475 let locs = s.map_source_locations(&loc.0, &[loc.1]);476 eprint!(477 " {}:{}",478 loc.0.file_name().unwrap().to_str().unwrap(),479 locs[0].line480 );481 });482 }483 eprintln!(" {}", str);484 Ok(rest) as Result<Any>485}486487#[jrsonnet_macros::builtin]488fn builtin_base64(input: Either![Vec<u8>, IStr]) -> Result<String> {489 use Either2::*;490 Ok(match input {491 A(a) => base64::encode(a),492 B(l) => base64::encode(l.bytes().collect::<Vec<_>>()),493 })494}495496#[jrsonnet_macros::builtin]497fn builtin_base64_decode_bytes(input: IStr) -> Result<Vec<u8>> {498 Ok(base64::decode(&input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?)499}500501#[jrsonnet_macros::builtin]502fn builtin_base64_decode(input: IStr) -> Result<String> {503 let bytes = base64::decode(&input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?;504 Ok(String::from_utf8(bytes).map_err(|_| RuntimeError("bad utf8".into()))?)505}506507#[jrsonnet_macros::builtin]508fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {509 Ok(match sep {510 IndexableVal::Arr(joiner_items) => {511 let mut out = Vec::new();512513 let mut first = true;514 for item in arr.iter() {515 let item = item?.clone();516 if let Val::Arr(items) = item {517 if !first {518 out.reserve(joiner_items.len());519 // TODO: extend520 for item in joiner_items.iter() {521 out.push(item?);522 }523 }524 first = false;525 out.reserve(items.len());526 // TODO: extend527 for item in items.iter() {528 out.push(item?);529 }530 } else {531 throw!(RuntimeError(532 "in std.join all items should be arrays".into()533 ));534 }535 }536537 IndexableVal::Arr(out.into())538 }539 IndexableVal::Str(sep) => {540 let mut out = String::new();541542 let mut first = true;543 for item in arr.iter() {544 let item = item?.clone();545 if let Val::Str(item) = item {546 if !first {547 out += &sep;548 }549 first = false;550 out += &item;551 } else {552 throw!(RuntimeError(553 "in std.join all items should be strings".into()554 ));555 }556 }557558 IndexableVal::Str(out.into())559 }560 })561}562563#[jrsonnet_macros::builtin]564fn builtin_escape_string_json(str_: IStr) -> Result<String> {565 Ok(escape_string_json(&str_))566}567568#[jrsonnet_macros::builtin]569fn builtin_manifest_json_ex(570 value: Any,571 indent: IStr,572 newline: Option<IStr>,573 key_val_sep: Option<IStr>,574) -> Result<String> {575 let newline = newline.as_deref().unwrap_or("\n");576 let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");577 manifest_json_ex(578 &value.0,579 &ManifestJsonOptions {580 padding: &indent,581 mtype: ManifestType::Std,582 newline,583 key_val_sep,584 },585 )586}587588#[jrsonnet_macros::builtin]589fn builtin_manifest_yaml_doc(590 value: Any,591 indent_array_in_object: Option<bool>,592 quote_keys: Option<bool>,593) -> Result<String> {594 manifest_yaml_ex(595 &value.0,596 &ManifestYamlOptions {597 padding: " ",598 arr_element_padding: if indent_array_in_object.unwrap_or(false) {599 " "600 } else {601 ""602 },603 quote_keys: quote_keys.unwrap_or(true),604 },605 )606}607608#[jrsonnet_macros::builtin]609fn builtin_reverse(value: ArrValue) -> Result<ArrValue> {610 Ok(value.reversed())611}612613#[jrsonnet_macros::builtin]614const fn builtin_id(v: Any) -> Result<Any> {615 Ok(v)616}617618#[jrsonnet_macros::builtin]619fn builtin_str_replace(str: String, from: IStr, to: IStr) -> Result<String> {620 Ok(str.replace(&from as &str, &to as &str))621}622623#[jrsonnet_macros::builtin]624fn builtin_splitlimit(str: IStr, c: char, maxsplits: Either![usize, M1]) -> Result<VecVal> {625 use Either2::*;626 Ok(VecVal(match maxsplits {627 A(n) => str.splitn(n + 1, c).map(|s| Val::Str(s.into())).collect(),628 B(_) => str.split(c).map(|s| Val::Str(s.into())).collect(),629 }))630}631632#[jrsonnet_macros::builtin]633fn builtin_ascii_upper(str: IStr) -> Result<String> {634 Ok(str.to_ascii_uppercase())635}636637#[jrsonnet_macros::builtin]638fn builtin_ascii_lower(str: IStr) -> Result<String> {639 Ok(str.to_ascii_lowercase())640}641642#[jrsonnet_macros::builtin]643fn builtin_member(arr: IndexableVal, x: Any) -> Result<bool> {644 match arr {645 IndexableVal::Str(s) => {646 let x: IStr = IStr::try_from(x.0)?;647 Ok(!x.is_empty() && s.contains(&*x))648 }649 IndexableVal::Arr(a) => {650 for item in a.iter() {651 let item = item?;652 if equals(&item, &x.0)? {653 return Ok(true);654 }655 }656 Ok(false)657 }658 }659}660661#[jrsonnet_macros::builtin]662fn builtin_count(arr: Vec<Any>, v: Any) -> Result<usize> {663 let mut count = 0;664 for item in arr.iter() {665 if equals(&item.0, &v.0)? {666 count += 1;667 }668 }669 Ok(count)670}1use crate::function::StaticBuiltin;2use crate::typed::{Any, PositiveF64, VecVal, M1};3use crate::{4 builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},5 equals,6 error::{Error::*, Result},7 operator::evaluate_mod_op,8 primitive_equals, push_frame, throw,9 typed::{Either2, Either4},10 with_state, ArrValue, Context, FuncVal, IndexableVal, Val,11};12use crate::{Either, ObjValue};13use format::{format_arr, format_obj};14use jrsonnet_interner::IStr;15use jrsonnet_parser::ExprLocation;16use serde::Deserialize;17use serde_yaml::DeserializingQuirks;18use std::collections::HashMap;19use std::convert::{TryFrom, TryInto};2021pub mod stdlib;22pub use stdlib::*;2324use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};2526pub mod format;27pub mod manifest;28pub mod sort;2930pub fn std_format(str: IStr, vals: Val) -> Result<String> {31 push_frame(32 None,33 || format!("std.format of {}", str),34 || {35 Ok(match vals {36 Val::Arr(vals) => format_arr(&str, &vals.evaluated()?)?,37 Val::Obj(obj) => format_obj(&str, &obj)?,38 o => format_arr(&str, &[o])?,39 })40 },41 )42}4344pub fn std_slice(45 indexable: IndexableVal,46 index: Option<usize>,47 end: Option<usize>,48 step: Option<usize>,49) -> Result<Val> {50 let index = index.unwrap_or(0);51 let end = end.unwrap_or_else(|| match &indexable {52 IndexableVal::Str(_) => usize::MAX,53 IndexableVal::Arr(v) => v.len(),54 });55 let step = step.unwrap_or(1);56 match &indexable {57 IndexableVal::Str(s) => Ok(Val::Str(58 (s.chars()59 .skip(index)60 .take(end - index)61 .step_by(step)62 .collect::<String>())63 .into(),64 )),65 IndexableVal::Arr(arr) => Ok(Val::Arr(66 (arr.iter()67 .skip(index)68 .take(end - index)69 .step_by(step)70 .collect::<Result<Vec<Val>>>()?)71 .into(),72 )),73 }74}7576type BuiltinsType = HashMap<IStr, &'static dyn StaticBuiltin>;7778thread_local! {79 pub static BUILTINS: BuiltinsType = {80 [81 ("length".into(), builtin_length::INST),82 ("type".into(), builtin_type::INST),83 ("makeArray".into(), builtin_make_array::INST),84 ("codepoint".into(), builtin_codepoint::INST),85 ("objectFieldsEx".into(), builtin_object_fields_ex::INST),86 ("objectHasEx".into(), builtin_object_has_ex::INST),87 ("slice".into(), builtin_slice::INST),88 ("substr".into(), builtin_substr::INST),89 ("primitiveEquals".into(), builtin_primitive_equals::INST),90 ("equals".into(), builtin_equals::INST),91 ("modulo".into(), builtin_modulo::INST),92 ("mod".into(), builtin_mod::INST),93 ("floor".into(), builtin_floor::INST),94 ("ceil".into(), builtin_ceil::INST),95 ("log".into(), builtin_log::INST),96 ("pow".into(), builtin_pow::INST),97 ("sqrt".into(), builtin_sqrt::INST),98 ("sin".into(), builtin_sin::INST),99 ("cos".into(), builtin_cos::INST),100 ("tan".into(), builtin_tan::INST),101 ("asin".into(), builtin_asin::INST),102 ("acos".into(), builtin_acos::INST),103 ("atan".into(), builtin_atan::INST),104 ("exp".into(), builtin_exp::INST),105 ("mantissa".into(), builtin_mantissa::INST),106 ("exponent".into(), builtin_exponent::INST),107 ("extVar".into(), builtin_ext_var::INST),108 ("native".into(), builtin_native::INST),109 ("filter".into(), builtin_filter::INST),110 ("map".into(), builtin_map::INST),111 ("flatMap".into(), builtin_flatmap::INST),112 ("foldl".into(), builtin_foldl::INST),113 ("foldr".into(), builtin_foldr::INST),114 ("sort".into(), builtin_sort::INST),115 ("format".into(), builtin_format::INST),116 ("range".into(), builtin_range::INST),117 ("char".into(), builtin_char::INST),118 ("encodeUTF8".into(), builtin_encode_utf8::INST),119 ("decodeUTF8".into(), builtin_decode_utf8::INST),120 ("md5".into(), builtin_md5::INST),121 ("base64".into(), builtin_base64::INST),122 ("base64DecodeBytes".into(), builtin_base64_decode_bytes::INST),123 ("base64Decode".into(), builtin_base64_decode::INST),124 ("trace".into(), builtin_trace::INST),125 ("join".into(), builtin_join::INST),126 ("escapeStringJson".into(), builtin_escape_string_json::INST),127 ("manifestJsonEx".into(), builtin_manifest_json_ex::INST),128 ("manifestYamlDoc".into(), builtin_manifest_yaml_doc::INST),129 ("reverse".into(), builtin_reverse::INST),130 ("id".into(), builtin_id::INST),131 ("strReplace".into(), builtin_str_replace::INST),132 ("splitLimit".into(), builtin_splitlimit::INST),133 ("parseJson".into(), builtin_parse_json::INST),134 ("parseYaml".into(), builtin_parse_yaml::INST),135 ("asciiUpper".into(), builtin_ascii_upper::INST),136 ("asciiLower".into(), builtin_ascii_lower::INST),137 ("member".into(), builtin_member::INST),138 ("count".into(), builtin_count::INST),139 ].iter().cloned().collect()140 };141}142143#[jrsonnet_macros::builtin]144fn builtin_length(x: Either![IStr, VecVal, ObjValue, FuncVal]) -> Result<usize> {145 use Either4::*;146 Ok(match x {147 A(x) => x.chars().count(),148 B(x) => x.0.len(),149 C(x) => x150 .fields_visibility()151 .into_iter()152 .filter(|(_k, v)| *v)153 .count(),154 D(f) => f.args_len(),155 })156}157158#[jrsonnet_macros::builtin]159fn builtin_type(x: Any) -> Result<IStr> {160 Ok(x.0.value_type().name().into())161}162163#[jrsonnet_macros::builtin]164fn builtin_make_array(sz: usize, func: FuncVal) -> Result<VecVal> {165 let mut out = Vec::with_capacity(sz);166 for i in 0..sz {167 out.push(func.evaluate_simple(&[i as f64].as_slice())?)168 }169 Ok(VecVal(out))170}171172#[jrsonnet_macros::builtin]173const fn builtin_codepoint(str: char) -> Result<u32> {174 Ok(str as u32)175}176177#[jrsonnet_macros::builtin]178fn builtin_object_fields_ex(obj: ObjValue, inc_hidden: bool) -> Result<VecVal> {179 let out = obj.fields_ex(inc_hidden);180 Ok(VecVal(out.into_iter().map(Val::Str).collect::<Vec<_>>()))181}182183#[jrsonnet_macros::builtin]184fn builtin_object_has_ex(obj: ObjValue, f: IStr, inc_hidden: bool) -> Result<bool> {185 Ok(obj.has_field_ex(f, inc_hidden))186}187188#[jrsonnet_macros::builtin]189fn builtin_parse_json(s: IStr) -> Result<Any> {190 let value: serde_json::Value = serde_json::from_str(&s)191 .map_err(|e| RuntimeError(format!("failed to parse json: {}", e).into()))?;192 Ok(Any(Val::try_from(&value)?))193}194195#[jrsonnet_macros::builtin]196fn builtin_parse_yaml(s: IStr) -> Result<Any> {197 let value = serde_yaml::Deserializer::from_str_with_quirks(198 &s,199 DeserializingQuirks { old_octals: true },200 );201 let mut out = vec![];202 for item in value {203 let value = serde_json::Value::deserialize(item)204 .map_err(|e| RuntimeError(format!("failed to parse yaml: {}", e).into()))?;205 let val = Val::try_from(&value)?;206 out.push(val);207 }208 Ok(Any(if out.is_empty() {209 Val::Null210 } else if out.len() == 1 {211 out.into_iter().next().unwrap()212 } else {213 Val::Arr(out.into())214 }))215}216217#[jrsonnet_macros::builtin]218fn builtin_slice(219 indexable: IndexableVal,220 index: Option<usize>,221 end: Option<usize>,222 step: Option<usize>,223) -> Result<Any> {224 std_slice(indexable, index, end, step).map(Any)225}226227#[jrsonnet_macros::builtin]228fn builtin_substr(str: IStr, from: usize, len: usize) -> Result<String> {229 Ok(str.chars().skip(from as usize).take(len as usize).collect())230}231232#[jrsonnet_macros::builtin]233fn builtin_primitive_equals(a: Any, b: Any) -> Result<bool> {234 primitive_equals(&a.0, &b.0)235}236237#[jrsonnet_macros::builtin]238fn builtin_equals(a: Any, b: Any) -> Result<bool> {239 equals(&a.0, &b.0)240}241242#[jrsonnet_macros::builtin]243fn builtin_modulo(a: f64, b: f64) -> Result<f64> {244 Ok(a % b)245}246247#[jrsonnet_macros::builtin]248fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result<Any> {249 use Either2::*;250 Ok(Any(evaluate_mod_op(251 &match a {252 A(v) => Val::Num(v),253 B(s) => Val::Str(s),254 },255 &b.0,256 )?))257}258259#[jrsonnet_macros::builtin]260fn builtin_floor(x: f64) -> Result<f64> {261 Ok(x.floor())262}263264#[jrsonnet_macros::builtin]265fn builtin_ceil(x: f64) -> Result<f64> {266 Ok(x.ceil())267}268269#[jrsonnet_macros::builtin]270fn builtin_log(n: f64) -> Result<f64> {271 Ok(n.ln())272}273274#[jrsonnet_macros::builtin]275fn builtin_pow(x: f64, n: f64) -> Result<f64> {276 Ok(x.powf(n))277}278279#[jrsonnet_macros::builtin]280fn builtin_sqrt(x: PositiveF64) -> Result<f64> {281 Ok(x.0.sqrt())282}283284#[jrsonnet_macros::builtin]285fn builtin_sin(x: f64) -> Result<f64> {286 Ok(x.sin())287}288289#[jrsonnet_macros::builtin]290fn builtin_cos(x: f64) -> Result<f64> {291 Ok(x.cos())292}293294#[jrsonnet_macros::builtin]295fn builtin_tan(x: f64) -> Result<f64> {296 Ok(x.tan())297}298299#[jrsonnet_macros::builtin]300fn builtin_asin(x: f64) -> Result<f64> {301 Ok(x.asin())302}303304#[jrsonnet_macros::builtin]305fn builtin_acos(x: f64) -> Result<f64> {306 Ok(x.acos())307}308309#[jrsonnet_macros::builtin]310fn builtin_atan(x: f64) -> Result<f64> {311 Ok(x.atan())312}313314#[jrsonnet_macros::builtin]315fn builtin_exp(x: f64) -> Result<f64> {316 Ok(x.exp())317}318319fn frexp(s: f64) -> (f64, i16) {320 if 0.0 == s {321 (s, 0)322 } else {323 let lg = s.abs().log2();324 let x = (lg - lg.floor() - 1.0).exp2();325 let exp = lg.floor() + 1.0;326 (s.signum() * x, exp as i16)327 }328}329330#[jrsonnet_macros::builtin]331fn builtin_mantissa(x: f64) -> Result<f64> {332 Ok(frexp(x).0)333}334335#[jrsonnet_macros::builtin]336fn builtin_exponent(x: f64) -> Result<i16> {337 Ok(frexp(x).1)338}339340#[jrsonnet_macros::builtin]341fn builtin_ext_var(x: IStr) -> Result<Any> {342 Ok(Any(with_state(|s| s.settings().ext_vars.get(&x).cloned())343 .ok_or(UndefinedExternalVariable(x))?))344}345346#[jrsonnet_macros::builtin]347fn builtin_native(name: IStr) -> Result<FuncVal> {348 Ok(with_state(|s| s.settings().ext_natives.get(&name).cloned())349 .map(|v| FuncVal::Builtin(v.clone()))350 .ok_or(UndefinedExternalFunction(name))?)351}352353#[jrsonnet_macros::builtin]354fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {355 arr.filter(|val| bool::try_from(func.evaluate_simple(&[Any(val.clone())].as_slice())?))356}357358#[jrsonnet_macros::builtin]359fn builtin_map(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {360 arr.map(|val| func.evaluate_simple(&[Any(val)].as_slice()))361}362363#[jrsonnet_macros::builtin]364fn builtin_flatmap(func: FuncVal, arr: IndexableVal) -> Result<IndexableVal> {365 match arr {366 IndexableVal::Str(s) => {367 let mut out = String::new();368 for c in s.chars() {369 match func.evaluate_simple(&[c.to_string()].as_slice())? {370 Val::Str(o) => out.push_str(&o),371 _ => throw!(RuntimeError(372 "in std.join all items should be strings".into()373 )),374 };375 }376 Ok(IndexableVal::Str(out.into()))377 }378 IndexableVal::Arr(a) => {379 let mut out = Vec::new();380 for el in a.iter() {381 let el = el?;382 match func.evaluate_simple(&[Any(el)].as_slice())? {383 Val::Arr(o) => {384 for oe in o.iter() {385 out.push(oe?)386 }387 }388 _ => throw!(RuntimeError(389 "in std.join all items should be arrays".into()390 )),391 };392 }393 Ok(IndexableVal::Arr(out.into()))394 }395 }396}397398#[jrsonnet_macros::builtin]399fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {400 let mut acc = init.0;401 for i in arr.iter() {402 acc = func.evaluate_simple(&[Any(acc), Any(i?)].as_slice())?;403 }404 Ok(Any(acc))405}406407#[jrsonnet_macros::builtin]408fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {409 let mut acc = init.0;410 for i in arr.iter().rev() {411 acc = func.evaluate_simple(&[Any(i?), Any(acc)].as_slice())?;412 }413 Ok(Any(acc))414}415416#[jrsonnet_macros::builtin]417#[allow(non_snake_case)]418fn builtin_sort(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {419 if arr.len() <= 1 {420 return Ok(arr);421 }422 Ok(ArrValue::Eager(sort::sort(423 arr.evaluated()?,424 keyF.as_ref(),425 )?))426}427428#[jrsonnet_macros::builtin]429fn builtin_format(str: IStr, vals: Any) -> Result<String> {430 std_format(str, vals.0)431}432433#[jrsonnet_macros::builtin]434fn builtin_range(from: i32, to: i32) -> Result<VecVal> {435 if to < from {436 return Ok(VecVal(Vec::new()));437 }438 let mut out = Vec::with_capacity((1 + to as usize - from as usize).max(0));439 for i in from as usize..=to as usize {440 out.push(Val::Num(i as f64));441 }442 Ok(VecVal(out))443}444445#[jrsonnet_macros::builtin]446fn builtin_char(n: u32) -> Result<char> {447 Ok(std::char::from_u32(n as u32).ok_or(InvalidUnicodeCodepointGot(n as u32))?)448}449450#[jrsonnet_macros::builtin]451fn builtin_encode_utf8(str: IStr) -> Result<VecVal> {452 Ok(VecVal(453 str.bytes()454 .map(|b| Val::Num(b as f64))455 .collect::<Vec<Val>>(),456 ))457}458459#[jrsonnet_macros::builtin]460fn builtin_decode_utf8(arr: Vec<u8>) -> Result<String> {461 Ok(String::from_utf8(arr).map_err(|_| RuntimeError("bad utf8".into()))?)462}463464#[jrsonnet_macros::builtin]465fn builtin_md5(str: IStr) -> Result<String> {466 Ok(format!("{:x}", md5::compute(&str.as_bytes())))467}468469#[jrsonnet_macros::builtin]470fn builtin_trace(#[location] loc: Option<&ExprLocation>, str: IStr, rest: Any) -> Result<Any> {471 eprint!("TRACE:");472 if let Some(loc) = loc {473 with_state(|s| {474 let locs = s.map_source_locations(&loc.0, &[loc.1]);475 eprint!(476 " {}:{}",477 loc.0.file_name().unwrap().to_str().unwrap(),478 locs[0].line479 );480 });481 }482 eprintln!(" {}", str);483 Ok(rest) as Result<Any>484}485486#[jrsonnet_macros::builtin]487fn builtin_base64(input: Either![Vec<u8>, IStr]) -> Result<String> {488 use Either2::*;489 Ok(match input {490 A(a) => base64::encode(a),491 B(l) => base64::encode(l.bytes().collect::<Vec<_>>()),492 })493}494495#[jrsonnet_macros::builtin]496fn builtin_base64_decode_bytes(input: IStr) -> Result<Vec<u8>> {497 Ok(base64::decode(&input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?)498}499500#[jrsonnet_macros::builtin]501fn builtin_base64_decode(input: IStr) -> Result<String> {502 let bytes = base64::decode(&input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?;503 Ok(String::from_utf8(bytes).map_err(|_| RuntimeError("bad utf8".into()))?)504}505506#[jrsonnet_macros::builtin]507fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {508 Ok(match sep {509 IndexableVal::Arr(joiner_items) => {510 let mut out = Vec::new();511512 let mut first = true;513 for item in arr.iter() {514 let item = item?.clone();515 if let Val::Arr(items) = item {516 if !first {517 out.reserve(joiner_items.len());518 // TODO: extend519 for item in joiner_items.iter() {520 out.push(item?);521 }522 }523 first = false;524 out.reserve(items.len());525 // TODO: extend526 for item in items.iter() {527 out.push(item?);528 }529 } else {530 throw!(RuntimeError(531 "in std.join all items should be arrays".into()532 ));533 }534 }535536 IndexableVal::Arr(out.into())537 }538 IndexableVal::Str(sep) => {539 let mut out = String::new();540541 let mut first = true;542 for item in arr.iter() {543 let item = item?.clone();544 if let Val::Str(item) = item {545 if !first {546 out += &sep;547 }548 first = false;549 out += &item;550 } else {551 throw!(RuntimeError(552 "in std.join all items should be strings".into()553 ));554 }555 }556557 IndexableVal::Str(out.into())558 }559 })560}561562#[jrsonnet_macros::builtin]563fn builtin_escape_string_json(str_: IStr) -> Result<String> {564 Ok(escape_string_json(&str_))565}566567#[jrsonnet_macros::builtin]568fn builtin_manifest_json_ex(569 value: Any,570 indent: IStr,571 newline: Option<IStr>,572 key_val_sep: Option<IStr>,573) -> Result<String> {574 let newline = newline.as_deref().unwrap_or("\n");575 let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");576 manifest_json_ex(577 &value.0,578 &ManifestJsonOptions {579 padding: &indent,580 mtype: ManifestType::Std,581 newline,582 key_val_sep,583 },584 )585}586587#[jrsonnet_macros::builtin]588fn builtin_manifest_yaml_doc(589 value: Any,590 indent_array_in_object: Option<bool>,591 quote_keys: Option<bool>,592) -> Result<String> {593 manifest_yaml_ex(594 &value.0,595 &ManifestYamlOptions {596 padding: " ",597 arr_element_padding: if indent_array_in_object.unwrap_or(false) {598 " "599 } else {600 ""601 },602 quote_keys: quote_keys.unwrap_or(true),603 },604 )605}606607#[jrsonnet_macros::builtin]608fn builtin_reverse(value: ArrValue) -> Result<ArrValue> {609 Ok(value.reversed())610}611612#[jrsonnet_macros::builtin]613const fn builtin_id(v: Any) -> Result<Any> {614 Ok(v)615}616617#[jrsonnet_macros::builtin]618fn builtin_str_replace(str: String, from: IStr, to: IStr) -> Result<String> {619 Ok(str.replace(&from as &str, &to as &str))620}621622#[jrsonnet_macros::builtin]623fn builtin_splitlimit(str: IStr, c: char, maxsplits: Either![usize, M1]) -> Result<VecVal> {624 use Either2::*;625 Ok(VecVal(match maxsplits {626 A(n) => str.splitn(n + 1, c).map(|s| Val::Str(s.into())).collect(),627 B(_) => str.split(c).map(|s| Val::Str(s.into())).collect(),628 }))629}630631#[jrsonnet_macros::builtin]632fn builtin_ascii_upper(str: IStr) -> Result<String> {633 Ok(str.to_ascii_uppercase())634}635636#[jrsonnet_macros::builtin]637fn builtin_ascii_lower(str: IStr) -> Result<String> {638 Ok(str.to_ascii_lowercase())639}640641#[jrsonnet_macros::builtin]642fn builtin_member(arr: IndexableVal, x: Any) -> Result<bool> {643 match arr {644 IndexableVal::Str(s) => {645 let x: IStr = IStr::try_from(x.0)?;646 Ok(!x.is_empty() && s.contains(&*x))647 }648 IndexableVal::Arr(a) => {649 for item in a.iter() {650 let item = item?;651 if equals(&item, &x.0)? {652 return Ok(true);653 }654 }655 Ok(false)656 }657 }658}659660#[jrsonnet_macros::builtin]661fn builtin_count(arr: Vec<Any>, v: Any) -> Result<usize> {662 let mut count = 0;663 for item in arr.iter() {664 if equals(&item.0, &v.0)? {665 count += 1;666 }667 }668 Ok(count)669}crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -177,7 +177,7 @@
}
pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {
- Val::Func(Cc::new(FuncVal::Normal(FuncDesc {
+ Val::Func(FuncVal::Normal(Cc::new(FuncDesc {
name,
ctx,
params,
@@ -630,11 +630,11 @@
Function(params, body) => {
evaluate_method(context, "anonymous".into(), params.clone(), body.clone())
}
- Intrinsic(name) => Val::Func(Cc::new(FuncVal::StaticBuiltin(
+ Intrinsic(name) => Val::Func(FuncVal::StaticBuiltin(
BUILTINS
.with(|b| b.get(name).copied())
.ok_or_else(|| IntrinsicNotFound(name.clone()))?,
- ))),
+ )),
AssertExpr(assert, returned) => {
evaluate_assert(context.clone(), assert)?;
evaluate(context, returned)?
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -371,7 +371,7 @@
type BuiltinParamName = Cow<'static, str>;
-#[derive(Clone)]
+#[derive(Clone, Trace)]
pub struct BuiltinParam {
pub name: BuiltinParamName,
pub has_default: bool,
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -13,7 +13,7 @@
mod dynamic;
pub mod error;
mod evaluate;
-mod function;
+pub mod function;
mod import;
mod integrations;
mod map;
@@ -27,14 +27,12 @@
pub use dynamic::*;
use error::{Error::*, LocError, Result, StackTraceElement};
pub use evaluate::*;
-pub use function::parse_function_call;
-use function::TlaArg;
+use function::{Builtin, TlaArg};
use gc::{GcHashMap, TraceBox};
use gcmodule::{Cc, Trace};
pub use import::*;
pub use jrsonnet_interner::IStr;
use jrsonnet_parser::*;
-use native::NativeCallback;
pub use obj::*;
use std::{
cell::{Ref, RefCell, RefMut},
@@ -79,7 +77,7 @@
/// Used for s`td.extVar`
pub ext_vars: HashMap<IStr, Val>,
/// Used for ext.native
- pub ext_natives: HashMap<IStr, Cc<NativeCallback>>,
+ pub ext_natives: HashMap<IStr, Cc<TraceBox<dyn Builtin>>>,
/// TLA vars
pub tla_vars: HashMap<IStr, TlaArg>,
/// Global variables are inserted in default context
@@ -614,7 +612,7 @@
self.settings_mut().import_resolver = resolver;
}
- pub fn add_native(&self, name: IStr, cb: Cc<NativeCallback>) {
+ pub fn add_native(&self, name: IStr, cb: Cc<TraceBox<dyn Builtin>>) {
self.settings_mut().ext_natives.insert(name, cb);
}
@@ -657,8 +655,8 @@
pub mod tests {
use super::Val;
use crate::{
- error::Error::*, gc::TraceBox, native::NativeCallbackHandler, primitive_equals,
- EvaluationState,
+ error::Error::*, function::BuiltinParam, gc::TraceBox, native::NativeCallbackHandler,
+ primitive_equals, EvaluationState,
};
use gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
@@ -1096,8 +1094,11 @@
#[derive(Trace)]
struct NativeAdd;
impl NativeCallbackHandler for NativeAdd {
- fn call(&self, from: Rc<Path>, args: &[Val]) -> crate::error::Result<Val> {
- assert_eq!(&from as &Path, &PathBuf::from("native_caller.jsonnet"));
+ fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> crate::error::Result<Val> {
+ assert_eq!(
+ &from.unwrap() as &Path,
+ &PathBuf::from("native_caller.jsonnet")
+ );
match (&args[0], &args[1]) {
(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a + b)),
(_, _) => unreachable!(),
@@ -1106,13 +1107,20 @@
}
evaluator.settings_mut().ext_natives.insert(
"native_add".into(),
- Cc::new(NativeCallback::new(
- ParamsDesc(Rc::new(vec![
- Param("a".into(), None),
- Param("b".into(), None),
- ])),
+ #[allow(deprecated)]
+ Cc::new(TraceBox(Box::new(NativeCallback::new(
+ vec![
+ BuiltinParam {
+ name: "a".into(),
+ has_default: false,
+ },
+ BuiltinParam {
+ name: "b".into(),
+ has_default: false,
+ },
+ ],
TraceBox(Box::new(NativeAdd)),
- )),
+ )))),
);
evaluator.evaluate_snippet_raw(
PathBuf::from("native_caller.jsonnet").into(),
crates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/native.rs
+++ b/crates/jrsonnet-evaluator/src/native.rs
@@ -1,33 +1,52 @@
#![allow(clippy::type_complexity)]
+use crate::function::{parse_builtin_call, ArgsLike, Builtin, BuiltinParam};
use crate::gc::TraceBox;
+use crate::Context;
use crate::{error::Result, Val};
use gcmodule::Trace;
-use jrsonnet_parser::ParamsDesc;
-use std::fmt::Debug;
+use jrsonnet_parser::ExprLocation;
use std::path::Path;
use std::rc::Rc;
-#[deprecated(note = "Use builtins instead")]
-pub trait NativeCallbackHandler: Trace {
- fn call(&self, from: Rc<Path>, args: &[Val]) -> Result<Val>;
-}
-
#[derive(Trace)]
pub struct NativeCallback {
- pub params: ParamsDesc,
+ pub(crate) params: Vec<BuiltinParam>,
handler: TraceBox<dyn NativeCallbackHandler>,
}
impl NativeCallback {
- pub fn new(params: ParamsDesc, handler: TraceBox<dyn NativeCallbackHandler>) -> Self {
+ #[deprecated = "prefer using builtins directly, use this interface only for bindings"]
+ pub fn new(params: Vec<BuiltinParam>, handler: TraceBox<dyn NativeCallbackHandler>) -> Self {
Self { params, handler }
- }
- pub fn call(&self, caller: Rc<Path>, args: &[Val]) -> Result<Val> {
- self.handler.call(caller, args)
}
}
-impl Debug for NativeCallback {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("NativeCallback").finish()
+
+impl Builtin for NativeCallback {
+ fn name(&self) -> &str {
+ // TODO: standard natives gets their names from definition
+ // But builitins should already have them
+ "<native>"
+ }
+
+ fn params(&self) -> &[BuiltinParam] {
+ &self.params
+ }
+
+ fn call(
+ &self,
+ context: Context,
+ loc: Option<&ExprLocation>,
+ args: &dyn ArgsLike,
+ ) -> Result<Val> {
+ let args = parse_builtin_call(context, &self.params, args, true)?;
+ let mut out_args = Vec::with_capacity(self.params.len());
+ for p in self.params.iter() {
+ out_args.push(args[&p.name].evaluate()?);
+ }
+ self.handler.call(loc.map(|l| l.0.clone()), &out_args)
}
}
+
+pub trait NativeCallbackHandler: Trace {
+ fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> Result<Val>;
+}
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -1,6 +1,5 @@
use std::convert::{TryFrom, TryInto};
-use gcmodule::Cc;
use jrsonnet_interner::IStr;
use jrsonnet_types::{ComplexValType, ValType};
@@ -400,10 +399,10 @@
}
}
-impl Typed for Cc<FuncVal> {
+impl Typed for FuncVal {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
}
-impl TryFrom<Val> for Cc<FuncVal> {
+impl TryFrom<Val> for FuncVal {
type Error = LocError;
fn try_from(value: Val) -> Result<Self> {
@@ -414,10 +413,10 @@
}
}
}
-impl TryFrom<Cc<FuncVal>> for Val {
+impl TryFrom<FuncVal> for Val {
type Error = LocError;
- fn try_from(value: Cc<FuncVal>) -> Result<Self> {
+ fn try_from(value: FuncVal) -> Result<Self> {
Ok(Self::Func(value))
}
}
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -7,7 +7,6 @@
evaluate,
function::{parse_function_call, ArgsLike, Builtin, StaticBuiltin},
gc::TraceBox,
- native::NativeCallback,
throw, Context, ObjValue, Result,
};
use gcmodule::{Cc, Trace};
@@ -86,16 +85,14 @@
pub body: LocExpr,
}
-#[derive(Trace)]
+#[derive(Trace, Clone)]
pub enum FuncVal {
/// Plain function implemented in jsonnet
- Normal(FuncDesc),
+ Normal(Cc<FuncDesc>),
/// Standard library function
StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),
- Builtin(TraceBox<dyn Builtin>),
- /// Library functions implemented in native
- NativeExt(IStr, Cc<NativeCallback>),
+ Builtin(Cc<TraceBox<dyn Builtin>>),
}
impl Debug for FuncVal {
@@ -104,9 +101,6 @@
Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),
Self::StaticBuiltin(arg0) => f.debug_tuple("Intrinsic").field(&arg0.name()).finish(),
Self::Builtin(arg0) => f.debug_tuple("Intrinsic").field(&arg0.name()).finish(),
- Self::NativeExt(arg0, arg1) => {
- f.debug_tuple("NativeExt").field(arg0).field(arg1).finish()
- }
}
}
}
@@ -116,7 +110,6 @@
match (self, other) {
(Self::Normal(a), Self::Normal(b)) => a == b,
(Self::StaticBuiltin(an), Self::StaticBuiltin(bn)) => std::ptr::eq(*an, *bn),
- (Self::NativeExt(an, _), Self::NativeExt(bn, _)) => an == bn,
(..) => false,
}
}
@@ -127,7 +120,6 @@
Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),
Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),
Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),
- Self::NativeExt(_, n) => n.params.iter().filter(|p| p.1.is_none()).count(),
}
}
pub fn name(&self) -> IStr {
@@ -135,7 +127,6 @@
Self::Normal(normal) => normal.name.clone(),
Self::StaticBuiltin(builtin) => builtin.name().into(),
Self::Builtin(builtin) => builtin.name().into(),
- Self::NativeExt(n, _) => format!("native.{}", n).into(),
}
}
pub fn evaluate(
@@ -158,15 +149,6 @@
}
Self::StaticBuiltin(name) => name.call(call_ctx, loc, args),
Self::Builtin(b) => b.call(call_ctx, loc, args),
- Self::NativeExt(_name, handler) => {
- let args =
- parse_function_call(call_ctx, Context::new(), &handler.params, args, true)?;
- let mut out_args = Vec::with_capacity(handler.params.len());
- for p in handler.params.0.iter() {
- out_args.push(args.binding(p.0.clone())?.evaluate()?);
- }
- Ok(handler.call(loc.expect("todo").0.clone(), &out_args)?)
- }
}
}
pub fn evaluate_simple(&self, args: &dyn ArgsLike) -> Result<Val> {
@@ -352,7 +334,7 @@
Num(f64),
Arr(ArrValue),
Obj(ObjValue),
- Func(Cc<FuncVal>),
+ Func(FuncVal),
}
impl Val {