1use crate::{2 builtin::{3 call_builtin,4 manifest::{manifest_json_ex, ManifestJsonOptions, ManifestType},5 },6 error::Error::*,7 evaluate,8 function::{parse_function_call, parse_function_call_map, place_args},9 native::NativeCallback,10 throw, with_state, Context, ObjValue, Result,11};12use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, ExprLocation, LiteralType, LocExpr, ParamsDesc};13use jrsonnet_types::ValType;14use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};1516enum LazyValInternals {17 Computed(Val),18 Waiting(Box<dyn Fn() -> Result<Val>>),19}20#[derive(Clone)]21pub struct LazyVal(Rc<RefCell<LazyValInternals>>);22impl LazyVal {23 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {24 Self(Rc::new(RefCell::new(LazyValInternals::Waiting(f))))25 }26 pub fn new_resolved(val: Val) -> Self {27 Self(Rc::new(RefCell::new(LazyValInternals::Computed(val))))28 }29 pub fn evaluate(&self) -> Result<Val> {30 let new_value = match &*self.0.borrow() {31 LazyValInternals::Computed(v) => return Ok(v.clone()),32 LazyValInternals::Waiting(f) => f()?,33 };34 *self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());35 Ok(new_value)36 }37}3839#[macro_export]40macro_rules! lazy_val {41 ($f: expr) => {42 $crate::LazyVal::new(Box::new($f))43 };44}45#[macro_export]46macro_rules! resolved_lazy_val {47 ($f: expr) => {48 $crate::LazyVal::new_resolved($f)49 };50}51impl Debug for LazyVal {52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {53 write!(f, "Lazy")54 }55}56impl PartialEq for LazyVal {57 fn eq(&self, other: &Self) -> bool {58 Rc::ptr_eq(&self.0, &other.0)59 }60}6162#[derive(Debug, PartialEq)]63pub struct FuncDesc {64 pub name: Rc<str>,65 pub ctx: Context,66 pub params: ParamsDesc,67 pub body: LocExpr,68}6970#[derive(Debug)]71pub enum FuncVal {72 73 Normal(FuncDesc),74 75 Intrinsic(Rc<str>),76 77 NativeExt(Rc<str>, Rc<NativeCallback>),78}7980impl PartialEq for FuncVal {81 fn eq(&self, other: &Self) -> bool {82 match (self, other) {83 (Self::Normal(a), Self::Normal(b)) => a == b,84 (Self::Intrinsic(an), Self::Intrinsic(bn)) => an == bn,85 (Self::NativeExt(an, _), Self::NativeExt(bn, _)) => an == bn,86 (..) => false,87 }88 }89}90impl FuncVal {91 pub fn is_ident(&self) -> bool {92 matches!(&self, Self::Intrinsic(n) if n as &str == "id")93 }94 pub fn name(&self) -> Rc<str> {95 match self {96 Self::Normal(normal) => normal.name.clone(),97 Self::Intrinsic(name) => format!("std.{}", name).into(),98 Self::NativeExt(n, _) => format!("native.{}", n).into(),99 }100 }101 pub fn evaluate(102 &self,103 call_ctx: Context,104 loc: &Option<ExprLocation>,105 args: &ArgsDesc,106 tailstrict: bool,107 ) -> Result<Val> {108 match self {109 Self::Normal(func) => {110 let ctx = parse_function_call(111 call_ctx,112 Some(func.ctx.clone()),113 &func.params,114 args,115 tailstrict,116 )?;117 evaluate(ctx, &func.body)118 }119 Self::Intrinsic(name) => call_builtin(call_ctx, loc, name, args),120 Self::NativeExt(_name, handler) => {121 let args = parse_function_call(call_ctx, None, &handler.params, args, true)?;122 let mut out_args = Vec::with_capacity(handler.params.len());123 for p in handler.params.0.iter() {124 out_args.push(args.binding(p.0.clone())?.evaluate()?);125 }126 Ok(handler.call(&out_args)?)127 }128 }129 }130131 pub fn evaluate_map(132 &self,133 call_ctx: Context,134 args: &HashMap<Rc<str>, Val>,135 tailstrict: bool,136 ) -> Result<Val> {137 match self {138 Self::Normal(func) => {139 let ctx = parse_function_call_map(140 call_ctx,141 Some(func.ctx.clone()),142 &func.params,143 args,144 tailstrict,145 )?;146 evaluate(ctx, &func.body)147 }148 Self::Intrinsic(_) => todo!(),149 Self::NativeExt(_, _) => todo!(),150 }151 }152153 pub fn evaluate_values(&self, call_ctx: Context, args: &[Val]) -> Result<Val> {154 match self {155 Self::Normal(func) => {156 let ctx = place_args(call_ctx, Some(func.ctx.clone()), &func.params, args)?;157 evaluate(ctx, &func.body)158 }159 Self::Intrinsic(_) => todo!(),160 Self::NativeExt(_, _) => todo!(),161 }162 }163}164165#[derive(Clone)]166pub enum ManifestFormat {167 YamlStream(Box<ManifestFormat>),168 Yaml(usize),169 Json(usize),170 ToString,171 String,172}173174#[derive(Debug, Clone)]175pub enum ArrValue {176 Lazy(Rc<Vec<LazyVal>>),177 Eager(Rc<Vec<Val>>),178}179impl ArrValue {180 pub fn len(&self) -> usize {181 match self {182 ArrValue::Lazy(l) => l.len(),183 ArrValue::Eager(e) => e.len(),184 }185 }186187 pub fn is_empty(&self) -> bool {188 self.len() == 0189 }190191 pub fn get(&self, index: usize) -> Result<Option<Val>> {192 match self {193 ArrValue::Lazy(vec) => {194 if let Some(v) = vec.get(index) {195 Ok(Some(v.evaluate()?))196 } else {197 Ok(None)198 }199 }200 ArrValue::Eager(vec) => Ok(vec.get(index).cloned()),201 }202 }203204 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {205 match self {206 ArrValue::Lazy(vec) => vec.get(index).cloned(),207 ArrValue::Eager(vec) => vec208 .get(index)209 .cloned()210 .map(|val| LazyVal::new_resolved(val)),211 }212 }213214 pub fn evaluated(&self) -> Result<Rc<Vec<Val>>> {215 Ok(match self {216 ArrValue::Lazy(vec) => {217 let mut out = Vec::with_capacity(vec.len());218 for item in vec.iter() {219 out.push(item.evaluate()?);220 }221 Rc::new(out)222 }223 ArrValue::Eager(vec) => vec.clone(),224 })225 }226227 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {228 (0..self.len()).map(move |idx| match self {229 ArrValue::Lazy(l) => l[idx].evaluate(),230 ArrValue::Eager(e) => Ok(e[idx].clone()),231 })232 }233234 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {235 (0..self.len()).map(move |idx| match self {236 ArrValue::Lazy(l) => l[idx].clone(),237 ArrValue::Eager(e) => LazyVal::new_resolved(e[idx].clone()),238 })239 }240241 pub fn reversed(self) -> Self {242 match self {243 ArrValue::Lazy(vec) => {244 let mut out = (&vec as &Vec<_>).clone();245 out.reverse();246 Self::Lazy(Rc::new(out))247 }248 ArrValue::Eager(vec) => {249 let mut out = (&vec as &Vec<_>).clone();250 out.reverse();251 Self::Eager(Rc::new(out))252 }253 }254 }255}256257impl From<Vec<LazyVal>> for ArrValue {258 fn from(v: Vec<LazyVal>) -> Self {259 Self::Lazy(Rc::new(v))260 }261}262263impl From<Vec<Val>> for ArrValue {264 fn from(v: Vec<Val>) -> Self {265 Self::Eager(Rc::new(v))266 }267}268269#[derive(Debug, Clone)]270pub enum Val {271 Bool(bool),272 Null,273 Str(Rc<str>),274 Num(f64),275 Arr(ArrValue),276 Obj(ObjValue),277 Func(Rc<FuncVal>),278}279280macro_rules! matches_unwrap {281 ($e: expr, $p: pat, $r: expr) => {282 match $e {283 $p => $r,284 _ => panic!("no match"),285 }286 };287}288impl Val {289 290 291 pub fn new_checked_num(num: f64) -> Result<Self> {292 if num.is_finite() {293 Ok(Self::Num(num))294 } else {295 throw!(RuntimeError("overflow".into()))296 }297 }298299 pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> {300 let this_type = self.value_type();301 if this_type != val_type {302 throw!(TypeMismatch(context, vec![val_type], this_type))303 } else {304 Ok(())305 }306 }307 pub fn unwrap_num(self) -> Result<f64> {308 Ok(matches_unwrap!(self, Self::Num(v), v))309 }310 pub fn unwrap_func(self) -> Result<Rc<FuncVal>> {311 Ok(matches_unwrap!(self, Self::Func(v), v))312 }313 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {314 self.assert_type(context, ValType::Bool)?;315 Ok(matches_unwrap!(self, Self::Bool(v), v))316 }317 pub fn try_cast_str(self, context: &'static str) -> Result<Rc<str>> {318 self.assert_type(context, ValType::Str)?;319 Ok(matches_unwrap!(self, Self::Str(v), v))320 }321 pub fn try_cast_num(self, context: &'static str) -> Result<f64> {322 self.assert_type(context, ValType::Num)?;323 self.unwrap_num()324 }325 pub fn value_type(&self) -> ValType {326 match self {327 Self::Str(..) => ValType::Str,328 Self::Num(..) => ValType::Num,329 Self::Arr(..) => ValType::Arr,330 Self::Obj(..) => ValType::Obj,331 Self::Bool(_) => ValType::Bool,332 Self::Null => ValType::Null,333 Self::Func(..) => ValType::Func,334 }335 }336337 pub fn to_string(&self) -> Result<Rc<str>> {338 Ok(match self {339 Self::Bool(true) => "true".into(),340 Self::Bool(false) => "false".into(),341 Self::Null => "null".into(),342 Self::Str(s) => s.clone(),343 v => manifest_json_ex(344 &v,345 &ManifestJsonOptions {346 padding: "",347 mtype: ManifestType::ToString,348 },349 )?350 .into(),351 })352 }353354 355 pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(Rc<str>, Rc<str>)>> {356 let obj = match self {357 Self::Obj(obj) => obj,358 _ => throw!(MultiManifestOutputIsNotAObject),359 };360 let keys = obj.visible_fields();361 let mut out = Vec::with_capacity(keys.len());362 for key in keys {363 let value = obj364 .get(key.clone())?365 .expect("item in object")366 .manifest(ty)?;367 out.push((key, value));368 }369 Ok(out)370 }371372 373 pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<Rc<str>>> {374 let arr = match self {375 Self::Arr(a) => a,376 _ => throw!(StreamManifestOutputIsNotAArray),377 };378 let mut out = Vec::with_capacity(arr.len());379 for i in arr.iter() {380 out.push(i?.manifest(ty)?);381 }382 Ok(out)383 }384385 pub fn manifest(&self, ty: &ManifestFormat) -> Result<Rc<str>> {386 Ok(match ty {387 ManifestFormat::YamlStream(format) => {388 let arr = match self {389 Self::Arr(a) => a,390 _ => throw!(StreamManifestOutputIsNotAArray),391 };392 let mut out = String::new();393394 match format as &ManifestFormat {395 ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed),396 ManifestFormat::String => throw!(StreamManifestCannotNestString),397 _ => {}398 };399400 if !arr.is_empty() {401 for v in arr.iter() {402 out.push_str("---\n");403 out.push_str(&v?.manifest(format)?);404 out.push('\n');405 }406 out.push_str("...");407 }408409 out.into()410 }411 ManifestFormat::Yaml(padding) => self.to_yaml(*padding)?,412 ManifestFormat::Json(padding) => self.to_json(*padding)?,413 ManifestFormat::ToString => self.to_string()?,414 ManifestFormat::String => match self {415 Self::Str(s) => s.clone(),416 _ => throw!(StringManifestOutputIsNotAString),417 },418 })419 }420421 422 pub fn to_json(&self, padding: usize) -> Result<Rc<str>> {423 manifest_json_ex(424 self,425 &ManifestJsonOptions {426 padding: &" ".repeat(padding),427 mtype: if padding == 0 {428 ManifestType::Minify429 } else {430 ManifestType::Manifest431 },432 },433 )434 .map(|s| s.into())435 }436437 438 #[cfg(feature = "faster")]439 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {440 manifest_json_ex(441 self,442 &ManifestJsonOptions {443 padding: &" ".repeat(padding),444 mtype: ManifestType::Std,445 },446 )447 .map(|s| s.into())448 }449450 451 #[cfg(not(feature = "faster"))]452 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {453 with_state(|s| {454 let ctx = s455 .create_default_context()?456 .with_var("__tmp__to_json__".into(), self.clone())?;457 Ok(evaluate(458 ctx,459 &el!(Expr::Apply(460 el!(Expr::Index(461 el!(Expr::Var("std".into())),462 el!(Expr::Str("manifestJsonEx".into()))463 )),464 ArgsDesc(vec![465 Arg(None, el!(Expr::Var("__tmp__to_json__".into()))),466 Arg(None, el!(Expr::Str(" ".repeat(padding).into())))467 ]),468 false469 )),470 )?471 .try_cast_str("to json")?)472 })473 }474 pub fn to_yaml(&self, padding: usize) -> Result<Rc<str>> {475 with_state(|s| {476 let ctx = s477 .create_default_context()?478 .with_var("__tmp__to_json__".into(), self.clone());479 Ok(evaluate(480 ctx,481 &el!(Expr::Apply(482 el!(Expr::Index(483 el!(Expr::Var("std".into())),484 el!(Expr::Str("manifestYamlDoc".into()))485 )),486 ArgsDesc(vec![487 Arg(None, el!(Expr::Var("__tmp__to_json__".into()))),488 Arg(489 None,490 el!(Expr::Literal(if padding != 0 {491 LiteralType::True492 } else {493 LiteralType::False494 }))495 )496 ]),497 false498 )),499 )?500 .try_cast_str("to json")?)501 })502 }503}504505const fn is_function_like(val: &Val) -> bool {506 matches!(val, Val::Func(_))507}508509510pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {511 Ok(match (val_a, val_b) {512 (Val::Bool(a), Val::Bool(b)) => a == b,513 (Val::Null, Val::Null) => true,514 (Val::Str(a), Val::Str(b)) => a == b,515 (Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,516 (Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(517 "primitiveEquals operates on primitive types, got array".into(),518 )),519 (Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(520 "primitiveEquals operates on primitive types, got object".into(),521 )),522 (a, b) if is_function_like(&a) && is_function_like(&b) => {523 throw!(RuntimeError("cannot test equality of functions".into()))524 }525 (_, _) => false,526 })527}528529530pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {531 if val_a.value_type() != val_b.value_type() {532 return Ok(false);533 }534 match (val_a, val_b) {535 536 (Val::Arr(a), Val::Arr(b)) => {537 if a.len() != b.len() {538 return Ok(false);539 }540 for (a, b) in a.iter().zip(b.iter()) {541 if !equals(&a?, &b?)? {542 return Ok(false);543 }544 }545 Ok(true)546 }547 (Val::Obj(a), Val::Obj(b)) => {548 let fields = a.visible_fields();549 if fields != b.visible_fields() {550 return Ok(false);551 }552 for field in fields {553 if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {554 return Ok(false);555 }556 }557 Ok(true)558 }559 (a, b) => Ok(primitive_equals(&a, &b)?),560 }561}