1use crate::{2 builtin::manifest::{3 manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions,4 },5 cc_ptr_eq,6 error::{Error::*, LocError},7 evaluate,8 function::{9 parse_default_function_call, parse_function_call, ArgsLike, Builtin, CallLocation,10 StaticBuiltin,11 },12 gc::TraceBox,13 throw, Context, ObjValue, Result,14};15use gcmodule::{Cc, Trace};16use jrsonnet_interner::IStr;17use jrsonnet_parser::{LocExpr, ParamsDesc};18use jrsonnet_types::ValType;19use std::{cell::RefCell, fmt::Debug, rc::Rc};2021pub trait LazyValValue: Trace {22 fn get(self: Box<Self>) -> Result<Val>;23}2425#[derive(Trace)]26enum LazyValInternals {27 Computed(Val),28 Errored(LocError),29 Waiting(TraceBox<dyn LazyValValue>),30 Pending,31}3233#[derive(Clone, Trace)]34pub struct LazyVal(Cc<RefCell<LazyValInternals>>);35impl LazyVal {36 pub fn new(f: TraceBox<dyn LazyValValue>) -> Self {37 Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f))))38 }39 pub fn new_resolved(val: Val) -> Self {40 Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))41 }42 pub fn force(&self) -> Result<()> {43 self.evaluate()?;44 Ok(())45 }46 pub fn evaluate(&self) -> Result<Val> {47 match &*self.0.borrow() {48 LazyValInternals::Computed(v) => return Ok(v.clone()),49 LazyValInternals::Errored(e) => return Err(e.clone()),50 LazyValInternals::Pending => return Err(RecursiveLazyValueEvaluation.into()),51 _ => (),52 };53 let value = if let LazyValInternals::Waiting(value) =54 std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)55 {56 value57 } else {58 unreachable!()59 };60 let new_value = match value.0.get() {61 Ok(v) => v,62 Err(e) => {63 *self.0.borrow_mut() = LazyValInternals::Errored(e.clone());64 return Err(e);65 }66 };67 *self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());68 Ok(new_value)69 }70}7172impl Debug for LazyVal {73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {74 write!(f, "Lazy")75 }76}77impl PartialEq for LazyVal {78 fn eq(&self, other: &Self) -> bool {79 cc_ptr_eq(&self.0, &other.0)80 }81}8283#[derive(Debug, PartialEq, Trace)]84pub struct FuncDesc {85 pub name: IStr,86 pub ctx: Context,87 pub params: ParamsDesc,88 pub body: LocExpr,89}90impl FuncDesc {91 92 pub fn default_body_context(&self) -> Context {93 parse_default_function_call(self.ctx.clone(), &self.params)94 }9596 97 pub fn call_body_context(98 &self,99 call_ctx: Context,100 args: &dyn ArgsLike,101 tailstrict: bool,102 ) -> Result<Context> {103 parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)104 }105}106107#[derive(Trace, Clone)]108pub enum FuncVal {109 110 Normal(Cc<FuncDesc>),111 112 StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),113 114 Builtin(Cc<TraceBox<dyn Builtin>>),115}116117impl Debug for FuncVal {118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {119 match self {120 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),121 Self::StaticBuiltin(arg0) => {122 f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()123 }124 Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),125 }126 }127}128129impl PartialEq for FuncVal {130 fn eq(&self, other: &Self) -> bool {131 match (self, other) {132 (Self::Normal(a), Self::Normal(b)) => a == b,133 (Self::StaticBuiltin(an), Self::StaticBuiltin(bn)) => std::ptr::eq(*an, *bn),134 (..) => false,135 }136 }137}138impl FuncVal {139 pub fn args_len(&self) -> usize {140 match self {141 Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),142 Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),143 Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),144 }145 }146 pub fn name(&self) -> IStr {147 match self {148 Self::Normal(normal) => normal.name.clone(),149 Self::StaticBuiltin(builtin) => builtin.name().into(),150 Self::Builtin(builtin) => builtin.name().into(),151 }152 }153 pub fn evaluate(154 &self,155 call_ctx: Context,156 loc: CallLocation,157 args: &dyn ArgsLike,158 tailstrict: bool,159 ) -> Result<Val> {160 match self {161 Self::Normal(func) => {162 let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;163 evaluate(body_ctx, &func.body)164 }165 Self::StaticBuiltin(b) => b.call(call_ctx, loc, args),166 Self::Builtin(b) => b.call(call_ctx, loc, args),167 }168 }169 pub fn evaluate_simple(&self, args: &dyn ArgsLike) -> Result<Val> {170 self.evaluate(Context::default(), CallLocation::native(), args, true)171 }172}173174#[derive(Clone)]175pub enum ManifestFormat {176 YamlStream(Box<ManifestFormat>),177 Yaml(usize),178 Json(usize),179 ToString,180 String,181}182183#[derive(Debug, Clone, Trace)]184#[force_tracking]185pub enum ArrValue {186 Lazy(Cc<Vec<LazyVal>>),187 Eager(Cc<Vec<Val>>),188 Extended(Box<(Self, Self)>),189}190impl ArrValue {191 pub fn new_eager() -> Self {192 Self::Eager(Cc::new(Vec::new()))193 }194195 pub fn len(&self) -> usize {196 match self {197 Self::Lazy(l) => l.len(),198 Self::Eager(e) => e.len(),199 Self::Extended(v) => v.0.len() + v.1.len(),200 }201 }202203 pub fn is_empty(&self) -> bool {204 self.len() == 0205 }206207 pub fn get(&self, index: usize) -> Result<Option<Val>> {208 match self {209 Self::Lazy(vec) => {210 if let Some(v) = vec.get(index) {211 Ok(Some(v.evaluate()?))212 } else {213 Ok(None)214 }215 }216 Self::Eager(vec) => Ok(vec.get(index).cloned()),217 Self::Extended(v) => {218 let a_len = v.0.len();219 if a_len > index {220 v.0.get(index)221 } else {222 v.1.get(index - a_len)223 }224 }225 }226 }227228 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {229 match self {230 Self::Lazy(vec) => vec.get(index).cloned(),231 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),232 Self::Extended(v) => {233 let a_len = v.0.len();234 if a_len > index {235 v.0.get_lazy(index)236 } else {237 v.1.get_lazy(index - a_len)238 }239 }240 }241 }242243 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {244 Ok(match self {245 Self::Lazy(vec) => {246 let mut out = Vec::with_capacity(vec.len());247 for item in vec.iter() {248 out.push(item.evaluate()?);249 }250 Cc::new(out)251 }252 Self::Eager(vec) => vec.clone(),253 Self::Extended(_v) => {254 let mut out = Vec::with_capacity(self.len());255 for item in self.iter() {256 out.push(item?);257 }258 Cc::new(out)259 }260 })261 }262263 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {264 (0..self.len()).map(move |idx| match self {265 Self::Lazy(l) => l[idx].evaluate(),266 Self::Eager(e) => Ok(e[idx].clone()),267 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),268 })269 }270271 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {272 (0..self.len()).map(move |idx| match self {273 Self::Lazy(l) => l[idx].clone(),274 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),275 Self::Extended(_) => self.get_lazy(idx).unwrap(),276 })277 }278279 pub fn reversed(self) -> Self {280 match self {281 Self::Lazy(vec) => {282 let mut out = (&vec as &Vec<_>).clone();283 out.reverse();284 Self::Lazy(Cc::new(out))285 }286 Self::Eager(vec) => {287 let mut out = (&vec as &Vec<_>).clone();288 out.reverse();289 Self::Eager(Cc::new(out))290 }291 Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))),292 }293 }294295 pub fn map(self, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {296 let mut out = Vec::with_capacity(self.len());297298 for value in self.iter() {299 out.push(mapper(value?)?);300 }301302 Ok(Self::Eager(Cc::new(out)))303 }304305 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {306 let mut out = Vec::with_capacity(self.len());307308 for value in self.iter() {309 let value = value?;310 if filter(&value)? {311 out.push(value);312 }313 }314315 Ok(Self::Eager(Cc::new(out)))316 }317318 pub fn ptr_eq(a: &Self, b: &Self) -> bool {319 match (a, b) {320 (Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b),321 (Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b),322 _ => false,323 }324 }325}326327impl From<Vec<LazyVal>> for ArrValue {328 fn from(v: Vec<LazyVal>) -> Self {329 Self::Lazy(Cc::new(v))330 }331}332333impl From<Vec<Val>> for ArrValue {334 fn from(v: Vec<Val>) -> Self {335 Self::Eager(Cc::new(v))336 }337}338339pub enum IndexableVal {340 Str(IStr),341 Arr(ArrValue),342}343344#[derive(Debug, Clone, Trace)]345pub enum Val {346 Bool(bool),347 Null,348 Str(IStr),349 Num(f64),350 Arr(ArrValue),351 Obj(ObjValue),352 Func(FuncVal),353}354355impl Val {356 pub fn as_bool(&self) -> Option<bool> {357 match self {358 Val::Bool(v) => Some(*v),359 _ => None,360 }361 }362 pub fn as_null(&self) -> Option<()> {363 match self {364 Val::Null => Some(()),365 _ => None,366 }367 }368 pub fn as_str(&self) -> Option<IStr> {369 match self {370 Val::Str(s) => Some(s.clone()),371 _ => None,372 }373 }374 pub fn as_num(&self) -> Option<f64> {375 match self {376 Val::Num(n) => Some(*n),377 _ => None,378 }379 }380 pub fn as_arr(&self) -> Option<ArrValue> {381 match self {382 Val::Arr(a) => Some(a.clone()),383 _ => None,384 }385 }386 pub fn as_obj(&self) -> Option<ObjValue> {387 match self {388 Val::Obj(o) => Some(o.clone()),389 _ => None,390 }391 }392 pub fn as_func(&self) -> Option<FuncVal> {393 match self {394 Val::Func(f) => Some(f.clone()),395 _ => None,396 }397 }398399 400 401 pub fn new_checked_num(num: f64) -> Result<Self> {402 if num.is_finite() {403 Ok(Self::Num(num))404 } else {405 throw!(RuntimeError("overflow".into()))406 }407 }408409 pub fn try_cast_nullable_num(self, context: &'static str) -> Result<Option<f64>> {410 Ok(match self {411 Val::Null => None,412 Val::Num(num) => Some(num),413 _ => throw!(TypeMismatch(414 context,415 vec![ValType::Null, ValType::Num],416 self.value_type()417 )),418 })419 }420 pub const fn value_type(&self) -> ValType {421 match self {422 Self::Str(..) => ValType::Str,423 Self::Num(..) => ValType::Num,424 Self::Arr(..) => ValType::Arr,425 Self::Obj(..) => ValType::Obj,426 Self::Bool(_) => ValType::Bool,427 Self::Null => ValType::Null,428 Self::Func(..) => ValType::Func,429 }430 }431432 pub fn to_string(&self) -> Result<IStr> {433 Ok(match self {434 Self::Bool(true) => "true".into(),435 Self::Bool(false) => "false".into(),436 Self::Null => "null".into(),437 Self::Str(s) => s.clone(),438 v => manifest_json_ex(439 v,440 &ManifestJsonOptions {441 padding: "",442 mtype: ManifestType::ToString,443 newline: "\n",444 key_val_sep: ": ",445 },446 )?447 .into(),448 })449 }450451 452 pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {453 let obj = match self {454 Self::Obj(obj) => obj,455 _ => throw!(MultiManifestOutputIsNotAObject),456 };457 let keys = obj.fields();458 let mut out = Vec::with_capacity(keys.len());459 for key in keys {460 let value = obj461 .get(key.clone())?462 .expect("item in object")463 .manifest(ty)?;464 out.push((key, value));465 }466 Ok(out)467 }468469 470 pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<IStr>> {471 let arr = match self {472 Self::Arr(a) => a,473 _ => throw!(StreamManifestOutputIsNotAArray),474 };475 let mut out = Vec::with_capacity(arr.len());476 for i in arr.iter() {477 out.push(i?.manifest(ty)?);478 }479 Ok(out)480 }481482 pub fn manifest(&self, ty: &ManifestFormat) -> Result<IStr> {483 Ok(match ty {484 ManifestFormat::YamlStream(format) => {485 let arr = match self {486 Self::Arr(a) => a,487 _ => throw!(StreamManifestOutputIsNotAArray),488 };489 let mut out = String::new();490491 match format as &ManifestFormat {492 ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed),493 ManifestFormat::String => throw!(StreamManifestCannotNestString),494 _ => {}495 };496497 if !arr.is_empty() {498 for v in arr.iter() {499 out.push_str("---\n");500 out.push_str(&v?.manifest(format)?);501 out.push('\n');502 }503 out.push_str("...");504 }505506 out.into()507 }508 ManifestFormat::Yaml(padding) => self.to_yaml(*padding)?,509 ManifestFormat::Json(padding) => self.to_json(*padding)?,510 ManifestFormat::ToString => self.to_string()?,511 ManifestFormat::String => match self {512 Self::Str(s) => s.clone(),513 _ => throw!(StringManifestOutputIsNotAString),514 },515 })516 }517518 519 pub fn to_json(&self, padding: usize) -> Result<IStr> {520 manifest_json_ex(521 self,522 &ManifestJsonOptions {523 padding: &" ".repeat(padding),524 mtype: if padding == 0 {525 ManifestType::Minify526 } else {527 ManifestType::Manifest528 },529 newline: "\n",530 key_val_sep: ": ",531 },532 )533 .map(|s| s.into())534 }535536 537 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {538 manifest_json_ex(539 self,540 &ManifestJsonOptions {541 padding: &" ".repeat(padding),542 mtype: ManifestType::Std,543 newline: "\n",544 key_val_sep: ": ",545 },546 )547 .map(|s| s.into())548 }549550 pub fn to_yaml(&self, padding: usize) -> Result<IStr> {551 let padding = &" ".repeat(padding);552 manifest_yaml_ex(553 self,554 &ManifestYamlOptions {555 padding,556 arr_element_padding: padding,557 quote_keys: false,558 },559 )560 .map(|s| s.into())561 }562 pub fn into_indexable(self) -> Result<IndexableVal> {563 Ok(match self {564 Val::Str(s) => IndexableVal::Str(s),565 Val::Arr(arr) => IndexableVal::Arr(arr),566 _ => throw!(ValueIsNotIndexable(self.value_type())),567 })568 }569}570571const fn is_function_like(val: &Val) -> bool {572 matches!(val, Val::Func(_))573}574575576pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {577 Ok(match (val_a, val_b) {578 (Val::Bool(a), Val::Bool(b)) => a == b,579 (Val::Null, Val::Null) => true,580 (Val::Str(a), Val::Str(b)) => a == b,581 (Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,582 (Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(583 "primitiveEquals operates on primitive types, got array".into(),584 )),585 (Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(586 "primitiveEquals operates on primitive types, got object".into(),587 )),588 (a, b) if is_function_like(a) && is_function_like(b) => {589 throw!(RuntimeError("cannot test equality of functions".into()))590 }591 (_, _) => false,592 })593}594595596pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {597 if val_a.value_type() != val_b.value_type() {598 return Ok(false);599 }600 match (val_a, val_b) {601 (Val::Arr(a), Val::Arr(b)) => {602 if ArrValue::ptr_eq(a, b) {603 return Ok(true);604 }605 if a.len() != b.len() {606 return Ok(false);607 }608 for (a, b) in a.iter().zip(b.iter()) {609 if !equals(&a?, &b?)? {610 return Ok(false);611 }612 }613 Ok(true)614 }615 (Val::Obj(a), Val::Obj(b)) => {616 if ObjValue::ptr_eq(a, b) {617 return Ok(true);618 }619 let fields = a.fields();620 if fields != b.fields() {621 return Ok(false);622 }623 for field in fields {624 if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {625 return Ok(false);626 }627 }628 Ok(true)629 }630 (a, b) => Ok(primitive_equals(a, b)?),631 }632}