git.delta.rocks / jrsonnet / refs/commits / e53349155ac3

difftreelog

fix range was one element short

Yaroslav Bolyukin2022-04-21parent: #1111100.patch.diff
in: master

1 file changed

modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/val.rs
1use std::{cell::RefCell, fmt::Debug, rc::Rc};23use gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;5use jrsonnet_parser::{LocExpr, ParamsDesc};6use jrsonnet_types::ValType;78use crate::{9	builtin::manifest::{10		manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions,11	},12	cc_ptr_eq,13	error::{Error::*, LocError},14	evaluate,15	function::{16		parse_default_function_call, parse_function_call, ArgsLike, Builtin, CallLocation,17		StaticBuiltin,18	},19	gc::TraceBox,20	throw, Context, ObjValue, Result,21};2223pub trait LazyValValue: Trace {24	fn get(self: Box<Self>) -> Result<Val>;25}2627#[derive(Trace)]28enum LazyValInternals {29	Computed(Val),30	Errored(LocError),31	Waiting(TraceBox<dyn LazyValValue>),32	Pending,33}3435#[derive(Clone, Trace)]36pub struct LazyVal(Cc<RefCell<LazyValInternals>>);37impl LazyVal {38	pub fn new(f: TraceBox<dyn LazyValValue>) -> Self {39		Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f))))40	}41	pub fn new_resolved(val: Val) -> Self {42		Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))43	}44	pub fn force(&self) -> Result<()> {45		self.evaluate()?;46		Ok(())47	}48	pub fn evaluate(&self) -> Result<Val> {49		match &*self.0.borrow() {50			LazyValInternals::Computed(v) => return Ok(v.clone()),51			LazyValInternals::Errored(e) => return Err(e.clone()),52			LazyValInternals::Pending => return Err(InfiniteRecursionDetected.into()),53			_ => (),54		};55		let value = if let LazyValInternals::Waiting(value) =56			std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)57		{58			value59		} else {60			unreachable!()61		};62		let new_value = match value.0.get() {63			Ok(v) => v,64			Err(e) => {65				*self.0.borrow_mut() = LazyValInternals::Errored(e.clone());66				return Err(e);67			}68		};69		*self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());70		Ok(new_value)71	}72}7374impl Debug for LazyVal {75	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {76		write!(f, "Lazy")77	}78}79impl PartialEq for LazyVal {80	fn eq(&self, other: &Self) -> bool {81		cc_ptr_eq(&self.0, &other.0)82	}83}8485#[derive(Debug, PartialEq, Trace)]86pub struct FuncDesc {87	pub name: IStr,88	pub ctx: Context,89	pub params: ParamsDesc,90	pub body: LocExpr,91}92impl FuncDesc {93	/// Create body context, but fill arguments without defaults with lazy error94	pub fn default_body_context(&self) -> Context {95		parse_default_function_call(self.ctx.clone(), &self.params)96	}9798	/// Create context, with which body code will run99	pub fn call_body_context(100		&self,101		call_ctx: Context,102		args: &dyn ArgsLike,103		tailstrict: bool,104	) -> Result<Context> {105		parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)106	}107}108109#[derive(Trace, Clone)]110pub enum FuncVal {111	/// Plain function implemented in jsonnet112	Normal(Cc<FuncDesc>),113	/// Standard library function114	StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),115	/// User-provided function116	Builtin(Cc<TraceBox<dyn Builtin>>),117}118119impl Debug for FuncVal {120	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {121		match self {122			Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),123			Self::StaticBuiltin(arg0) => {124				f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()125			}126			Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),127		}128	}129}130131impl FuncVal {132	pub fn args_len(&self) -> usize {133		match self {134			Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),135			Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),136			Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),137		}138	}139	pub fn name(&self) -> IStr {140		match self {141			Self::Normal(normal) => normal.name.clone(),142			Self::StaticBuiltin(builtin) => builtin.name().into(),143			Self::Builtin(builtin) => builtin.name().into(),144		}145	}146	pub fn evaluate(147		&self,148		call_ctx: Context,149		loc: CallLocation,150		args: &dyn ArgsLike,151		tailstrict: bool,152	) -> Result<Val> {153		match self {154			Self::Normal(func) => {155				let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;156				evaluate(body_ctx, &func.body)157			}158			Self::StaticBuiltin(b) => b.call(call_ctx, loc, args),159			Self::Builtin(b) => b.call(call_ctx, loc, args),160		}161	}162	pub fn evaluate_simple(&self, args: &dyn ArgsLike) -> Result<Val> {163		self.evaluate(Context::default(), CallLocation::native(), args, true)164	}165}166167#[derive(Clone)]168pub enum ManifestFormat {169	YamlStream(Box<ManifestFormat>),170	Yaml {171		padding: usize,172		#[cfg(feature = "exp-preserve-order")]173		preserve_order: bool,174	},175	Json {176		padding: usize,177		#[cfg(feature = "exp-preserve-order")]178		preserve_order: bool,179	},180	ToString,181	String,182}183impl ManifestFormat {184	#[cfg(feature = "exp-preserve-order")]185	fn preserve_order(&self) -> bool {186		match self {187			ManifestFormat::YamlStream(s) => s.preserve_order(),188			ManifestFormat::Yaml { preserve_order, .. } => *preserve_order,189			ManifestFormat::Json { preserve_order, .. } => *preserve_order,190			ManifestFormat::ToString => false,191			ManifestFormat::String => false,192		}193	}194}195196#[derive(Debug, Clone, Trace)]197pub struct Slice {198	pub(crate) inner: ArrValue,199	pub(crate) from: u32,200	pub(crate) to: u32,201	pub(crate) step: u32,202}203impl Slice {204	const fn from(&self) -> usize {205		self.from as usize206	}207	const fn to(&self) -> usize {208		self.to as usize209	}210	const fn step(&self) -> usize {211		self.step as usize212	}213	const fn len(&self) -> usize {214		// TODO: use div_ceil215		let diff = self.to() - self.from();216		let rem = diff % self.step();217		let div = diff / self.step();218219		if rem != 0 {220			div + 1221		} else {222			div223		}224	}225}226227#[derive(Debug, Clone, Trace)]228#[force_tracking]229pub enum ArrValue {230	Bytes(#[skip_trace] Rc<[u8]>),231	Lazy(Cc<Vec<LazyVal>>),232	Eager(Cc<Vec<Val>>),233	Extended(Box<(Self, Self)>),234	Range(i32, i32),235	Slice(Box<Slice>),236	Reversed(Box<Self>),237}238impl ArrValue {239	pub fn new_eager() -> Self {240		Self::Eager(Cc::new(Vec::new()))241	}242	pub fn new_range(a: i32, b: i32) -> Self {243		assert!(a <= b);244		Self::Range(a, b)245	}246247	pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {248		let len = self.len();249		let from = from.unwrap_or(0);250		let to = to.unwrap_or(len).min(len);251		let step = step.unwrap_or(1);252		assert!(from < to);253		assert!(step > 0);254255		Self::Slice(Box::new(Slice {256			inner: self,257			from: from as u32,258			to: to as u32,259			step: step as u32,260		}))261	}262263	pub fn len(&self) -> usize {264		match self {265			Self::Bytes(i) => i.len(),266			Self::Lazy(l) => l.len(),267			Self::Eager(e) => e.len(),268			Self::Extended(v) => v.0.len() + v.1.len(),269			Self::Range(a, b) => a.abs_diff(*b) as usize,270			Self::Reversed(i) => i.len(),271			Self::Slice(s) => s.len(),272		}273	}274275	pub fn is_empty(&self) -> bool {276		self.len() == 0277	}278279	pub fn get(&self, index: usize) -> Result<Option<Val>> {280		match self {281			Self::Bytes(i) => i282				.get(index)283				.map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),284			Self::Lazy(vec) => {285				if let Some(v) = vec.get(index) {286					Ok(Some(v.evaluate()?))287				} else {288					Ok(None)289				}290			}291			Self::Eager(vec) => Ok(vec.get(index).cloned()),292			Self::Extended(v) => {293				let a_len = v.0.len();294				if a_len > index {295					v.0.get(index)296				} else {297					v.1.get(index - a_len)298				}299			}300			Self::Range(a, _) => {301				if index >= self.len() {302					return Ok(None);303				}304				Ok(Some(Val::Num(((*a as isize) + index as isize) as f64)))305			}306			Self::Reversed(v) => {307				let len = v.len();308				if index >= len {309					return Ok(None);310				}311				v.get(len - index - 1)312			}313			Self::Slice(s) => {314				let index = s.from() + index * s.step();315				if index >= s.to() {316					return Ok(None);317				}318				s.inner.get(index as usize)319			}320		}321	}322323	pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {324		match self {325			Self::Bytes(i) => i326				.get(index)327				.map(|b| LazyVal::new_resolved(Val::Num(*b as f64))),328			Self::Lazy(vec) => vec.get(index).cloned(),329			Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),330			Self::Extended(v) => {331				let a_len = v.0.len();332				if a_len > index {333					v.0.get_lazy(index)334				} else {335					v.1.get_lazy(index - a_len)336				}337			}338			Self::Range(a, _) => {339				if index >= self.len() {340					return None;341				}342				Some(LazyVal::new_resolved(Val::Num(343					((*a as isize) + index as isize) as f64,344				)))345			}346			Self::Reversed(v) => {347				let len = v.len();348				if index >= len {349					return None;350				}351				v.get_lazy(len - index - 1)352			}353			Self::Slice(s) => {354				let index = s.from() + index * s.step();355				if index >= s.to() {356					return None;357				}358				s.inner.get_lazy(index as usize)359			}360		}361	}362363	pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {364		Ok(match self {365			Self::Bytes(i) => {366				let mut out = Vec::with_capacity(i.len());367				for v in i.iter() {368					out.push(Val::Num(*v as f64));369				}370				Cc::new(out)371			}372			Self::Lazy(vec) => {373				let mut out = Vec::with_capacity(vec.len());374				for item in vec.iter() {375					out.push(item.evaluate()?);376				}377				Cc::new(out)378			}379			Self::Eager(vec) => vec.clone(),380			Self::Extended(_v) => {381				let mut out = Vec::with_capacity(self.len());382				for item in self.iter() {383					out.push(item?);384				}385				Cc::new(out)386			}387			Self::Range(a, b) => {388				let mut out = Vec::with_capacity(self.len());389				for i in *a..*b {390					out.push(Val::Num(i as f64));391				}392				Cc::new(out)393			}394			Self::Reversed(r) => {395				let mut r = r.evaluated()?;396				Cc::update_with(&mut r, |v| v.reverse());397				r398			}399			Self::Slice(v) => {400				let mut out = Vec::with_capacity(v.inner.len());401				for v in v402					.inner403					.iter_lazy()404					.skip(v.from())405					.take(v.to() - v.from())406					.step_by(v.step())407				{408					out.push(v.evaluate()?)409				}410				Cc::new(out)411			}412		})413	}414415	pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {416		(0..self.len()).map(move |idx| match self {417			Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),418			Self::Lazy(l) => l[idx].evaluate(),419			Self::Eager(e) => Ok(e[idx].clone()),420			Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),421			Self::Range(..) => self.get(idx).map(|e| e.unwrap()),422			Self::Reversed(..) => self.get(idx).map(|e| e.unwrap()),423			Self::Slice(..) => self.get(idx).map(|e| e.unwrap()),424		})425	}426427	pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {428		(0..self.len()).map(move |idx| match self {429			Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),430			Self::Lazy(l) => l[idx].clone(),431			Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),432			Self::Extended(_) => self.get_lazy(idx).unwrap(),433			Self::Range(..) => self.get_lazy(idx).unwrap(),434			Self::Reversed(..) => self.get_lazy(idx).unwrap(),435			Self::Slice(..) => self.get_lazy(idx).unwrap(),436		})437	}438439	pub fn reversed(self) -> Self {440		Self::Reversed(Box::new(self))441	}442443	pub fn map(self, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {444		let mut out = Vec::with_capacity(self.len());445446		for value in self.iter() {447			out.push(mapper(value?)?);448		}449450		Ok(Self::Eager(Cc::new(out)))451	}452453	pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {454		let mut out = Vec::with_capacity(self.len());455456		for value in self.iter() {457			let value = value?;458			if filter(&value)? {459				out.push(value);460			}461		}462463		Ok(Self::Eager(Cc::new(out)))464	}465466	pub fn ptr_eq(a: &Self, b: &Self) -> bool {467		match (a, b) {468			(Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b),469			(Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b),470			_ => false,471		}472	}473}474475impl From<Vec<LazyVal>> for ArrValue {476	fn from(v: Vec<LazyVal>) -> Self {477		Self::Lazy(Cc::new(v))478	}479}480481impl From<Vec<Val>> for ArrValue {482	fn from(v: Vec<Val>) -> Self {483		Self::Eager(Cc::new(v))484	}485}486487pub enum IndexableVal {488	Str(IStr),489	Arr(ArrValue),490}491492#[derive(Debug, Clone, Trace)]493pub enum Val {494	Bool(bool),495	Null,496	Str(IStr),497	Num(f64),498	Arr(ArrValue),499	Obj(ObjValue),500	Func(FuncVal),501}502503impl Val {504	pub const fn as_bool(&self) -> Option<bool> {505		match self {506			Val::Bool(v) => Some(*v),507			_ => None,508		}509	}510	pub const fn as_null(&self) -> Option<()> {511		match self {512			Val::Null => Some(()),513			_ => None,514		}515	}516	pub fn as_str(&self) -> Option<IStr> {517		match self {518			Val::Str(s) => Some(s.clone()),519			_ => None,520		}521	}522	pub const fn as_num(&self) -> Option<f64> {523		match self {524			Val::Num(n) => Some(*n),525			_ => None,526		}527	}528	pub fn as_arr(&self) -> Option<ArrValue> {529		match self {530			Val::Arr(a) => Some(a.clone()),531			_ => None,532		}533	}534	pub fn as_obj(&self) -> Option<ObjValue> {535		match self {536			Val::Obj(o) => Some(o.clone()),537			_ => None,538		}539	}540	pub fn as_func(&self) -> Option<FuncVal> {541		match self {542			Val::Func(f) => Some(f.clone()),543			_ => None,544		}545	}546547	/// Creates `Val::Num` after checking for numeric overflow.548	/// As numbers are `f64`, we can just check for their finity.549	pub fn new_checked_num(num: f64) -> Result<Self> {550		if num.is_finite() {551			Ok(Self::Num(num))552		} else {553			throw!(RuntimeError("overflow".into()))554		}555	}556557	pub const fn value_type(&self) -> ValType {558		match self {559			Self::Str(..) => ValType::Str,560			Self::Num(..) => ValType::Num,561			Self::Arr(..) => ValType::Arr,562			Self::Obj(..) => ValType::Obj,563			Self::Bool(_) => ValType::Bool,564			Self::Null => ValType::Null,565			Self::Func(..) => ValType::Func,566		}567	}568569	pub fn to_string(&self) -> Result<IStr> {570		Ok(match self {571			Self::Bool(true) => "true".into(),572			Self::Bool(false) => "false".into(),573			Self::Null => "null".into(),574			Self::Str(s) => s.clone(),575			v => manifest_json_ex(576				v,577				&ManifestJsonOptions {578					padding: "",579					mtype: ManifestType::ToString,580					newline: "\n",581					key_val_sep: ": ",582					#[cfg(feature = "exp-preserve-order")]583					preserve_order: false,584				},585			)?586			.into(),587		})588	}589590	/// Expects value to be object, outputs (key, manifested value) pairs591	pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {592		let obj = match self {593			Self::Obj(obj) => obj,594			_ => throw!(MultiManifestOutputIsNotAObject),595		};596		let keys = obj.fields(597			#[cfg(feature = "exp-preserve-order")]598			ty.preserve_order(),599		);600		let mut out = Vec::with_capacity(keys.len());601		for key in keys {602			let value = obj603				.get(key.clone())?604				.expect("item in object")605				.manifest(ty)?;606			out.push((key, value));607		}608		Ok(out)609	}610611	/// Expects value to be array, outputs manifested values612	pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<IStr>> {613		let arr = match self {614			Self::Arr(a) => a,615			_ => throw!(StreamManifestOutputIsNotAArray),616		};617		let mut out = Vec::with_capacity(arr.len());618		for i in arr.iter() {619			out.push(i?.manifest(ty)?);620		}621		Ok(out)622	}623624	pub fn manifest(&self, ty: &ManifestFormat) -> Result<IStr> {625		Ok(match ty {626			ManifestFormat::YamlStream(format) => {627				let arr = match self {628					Self::Arr(a) => a,629					_ => throw!(StreamManifestOutputIsNotAArray),630				};631				let mut out = String::new();632633				match format as &ManifestFormat {634					ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed),635					ManifestFormat::String => throw!(StreamManifestCannotNestString),636					_ => {}637				};638639				if !arr.is_empty() {640					for v in arr.iter() {641						out.push_str("---\n");642						out.push_str(&v?.manifest(format)?);643						out.push('\n');644					}645					out.push_str("...");646				}647648				out.into()649			}650			ManifestFormat::Yaml {651				padding,652				#[cfg(feature = "exp-preserve-order")]653				preserve_order,654			} => self.to_yaml(655				*padding,656				#[cfg(feature = "exp-preserve-order")]657				*preserve_order,658			)?,659			ManifestFormat::Json {660				padding,661				#[cfg(feature = "exp-preserve-order")]662				preserve_order,663			} => self.to_json(664				*padding,665				#[cfg(feature = "exp-preserve-order")]666				*preserve_order,667			)?,668			ManifestFormat::ToString => self.to_string()?,669			ManifestFormat::String => match self {670				Self::Str(s) => s.clone(),671				_ => throw!(StringManifestOutputIsNotAString),672			},673		})674	}675676	/// For manifestification677	pub fn to_json(678		&self,679		padding: usize,680		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,681	) -> Result<IStr> {682		manifest_json_ex(683			self,684			&ManifestJsonOptions {685				padding: &" ".repeat(padding),686				mtype: if padding == 0 {687					ManifestType::Minify688				} else {689					ManifestType::Manifest690				},691				newline: "\n",692				key_val_sep: ": ",693				#[cfg(feature = "exp-preserve-order")]694				preserve_order,695			},696		)697		.map(|s| s.into())698	}699700	/// Calls `std.manifestJson`701	pub fn to_std_json(702		&self,703		padding: usize,704		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,705	) -> Result<Rc<str>> {706		manifest_json_ex(707			self,708			&ManifestJsonOptions {709				padding: &" ".repeat(padding),710				mtype: ManifestType::Std,711				newline: "\n",712				key_val_sep: ": ",713				#[cfg(feature = "exp-preserve-order")]714				preserve_order,715			},716		)717		.map(|s| s.into())718	}719720	pub fn to_yaml(721		&self,722		padding: usize,723		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,724	) -> Result<IStr> {725		let padding = &" ".repeat(padding);726		manifest_yaml_ex(727			self,728			&ManifestYamlOptions {729				padding,730				arr_element_padding: padding,731				quote_keys: false,732				#[cfg(feature = "exp-preserve-order")]733				preserve_order,734			},735		)736		.map(|s| s.into())737	}738	pub fn into_indexable(self) -> Result<IndexableVal> {739		Ok(match self {740			Val::Str(s) => IndexableVal::Str(s),741			Val::Arr(arr) => IndexableVal::Arr(arr),742			_ => throw!(ValueIsNotIndexable(self.value_type())),743		})744	}745}746747const fn is_function_like(val: &Val) -> bool {748	matches!(val, Val::Func(_))749}750751/// Native implementation of `std.primitiveEquals`752pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {753	Ok(match (val_a, val_b) {754		(Val::Bool(a), Val::Bool(b)) => a == b,755		(Val::Null, Val::Null) => true,756		(Val::Str(a), Val::Str(b)) => a == b,757		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,758		(Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(759			"primitiveEquals operates on primitive types, got array".into(),760		)),761		(Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(762			"primitiveEquals operates on primitive types, got object".into(),763		)),764		(a, b) if is_function_like(a) && is_function_like(b) => {765			throw!(RuntimeError("cannot test equality of functions".into()))766		}767		(_, _) => false,768	})769}770771/// Native implementation of `std.equals`772pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {773	if val_a.value_type() != val_b.value_type() {774		return Ok(false);775	}776	match (val_a, val_b) {777		(Val::Arr(a), Val::Arr(b)) => {778			if ArrValue::ptr_eq(a, b) {779				return Ok(true);780			}781			if a.len() != b.len() {782				return Ok(false);783			}784			for (a, b) in a.iter().zip(b.iter()) {785				if !equals(&a?, &b?)? {786					return Ok(false);787				}788			}789			Ok(true)790		}791		(Val::Obj(a), Val::Obj(b)) => {792			if ObjValue::ptr_eq(a, b) {793				return Ok(true);794			}795			let fields = a.fields(796				#[cfg(feature = "exp-preserve-order")]797				false,798			);799			if fields800				!= b.fields(801					#[cfg(feature = "exp-preserve-order")]802					false,803				) {804				return Ok(false);805			}806			for field in fields {807				if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {808					return Ok(false);809				}810			}811			Ok(true)812		}813		(a, b) => Ok(primitive_equals(a, b)?),814	}815}
after · crates/jrsonnet-evaluator/src/val.rs
1use std::{cell::RefCell, fmt::Debug, rc::Rc};23use gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;5use jrsonnet_parser::{LocExpr, ParamsDesc};6use jrsonnet_types::ValType;78use crate::{9	builtin::manifest::{10		manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions,11	},12	cc_ptr_eq,13	error::{Error::*, LocError},14	evaluate,15	function::{16		parse_default_function_call, parse_function_call, ArgsLike, Builtin, CallLocation,17		StaticBuiltin,18	},19	gc::TraceBox,20	throw, Context, ObjValue, Result,21};2223pub trait LazyValValue: Trace {24	fn get(self: Box<Self>) -> Result<Val>;25}2627#[derive(Trace)]28enum LazyValInternals {29	Computed(Val),30	Errored(LocError),31	Waiting(TraceBox<dyn LazyValValue>),32	Pending,33}3435#[derive(Clone, Trace)]36pub struct LazyVal(Cc<RefCell<LazyValInternals>>);37impl LazyVal {38	pub fn new(f: TraceBox<dyn LazyValValue>) -> Self {39		Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f))))40	}41	pub fn new_resolved(val: Val) -> Self {42		Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))43	}44	pub fn force(&self) -> Result<()> {45		self.evaluate()?;46		Ok(())47	}48	pub fn evaluate(&self) -> Result<Val> {49		match &*self.0.borrow() {50			LazyValInternals::Computed(v) => return Ok(v.clone()),51			LazyValInternals::Errored(e) => return Err(e.clone()),52			LazyValInternals::Pending => return Err(InfiniteRecursionDetected.into()),53			_ => (),54		};55		let value = if let LazyValInternals::Waiting(value) =56			std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)57		{58			value59		} else {60			unreachable!()61		};62		let new_value = match value.0.get() {63			Ok(v) => v,64			Err(e) => {65				*self.0.borrow_mut() = LazyValInternals::Errored(e.clone());66				return Err(e);67			}68		};69		*self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());70		Ok(new_value)71	}72}7374impl Debug for LazyVal {75	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {76		write!(f, "Lazy")77	}78}79impl PartialEq for LazyVal {80	fn eq(&self, other: &Self) -> bool {81		cc_ptr_eq(&self.0, &other.0)82	}83}8485#[derive(Debug, PartialEq, Trace)]86pub struct FuncDesc {87	pub name: IStr,88	pub ctx: Context,89	pub params: ParamsDesc,90	pub body: LocExpr,91}92impl FuncDesc {93	/// Create body context, but fill arguments without defaults with lazy error94	pub fn default_body_context(&self) -> Context {95		parse_default_function_call(self.ctx.clone(), &self.params)96	}9798	/// Create context, with which body code will run99	pub fn call_body_context(100		&self,101		call_ctx: Context,102		args: &dyn ArgsLike,103		tailstrict: bool,104	) -> Result<Context> {105		parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)106	}107}108109#[derive(Trace, Clone)]110pub enum FuncVal {111	/// Plain function implemented in jsonnet112	Normal(Cc<FuncDesc>),113	/// Standard library function114	StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),115	/// User-provided function116	Builtin(Cc<TraceBox<dyn Builtin>>),117}118119impl Debug for FuncVal {120	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {121		match self {122			Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),123			Self::StaticBuiltin(arg0) => {124				f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()125			}126			Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),127		}128	}129}130131impl FuncVal {132	pub fn args_len(&self) -> usize {133		match self {134			Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),135			Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),136			Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),137		}138	}139	pub fn name(&self) -> IStr {140		match self {141			Self::Normal(normal) => normal.name.clone(),142			Self::StaticBuiltin(builtin) => builtin.name().into(),143			Self::Builtin(builtin) => builtin.name().into(),144		}145	}146	pub fn evaluate(147		&self,148		call_ctx: Context,149		loc: CallLocation,150		args: &dyn ArgsLike,151		tailstrict: bool,152	) -> Result<Val> {153		match self {154			Self::Normal(func) => {155				let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;156				evaluate(body_ctx, &func.body)157			}158			Self::StaticBuiltin(b) => b.call(call_ctx, loc, args),159			Self::Builtin(b) => b.call(call_ctx, loc, args),160		}161	}162	pub fn evaluate_simple(&self, args: &dyn ArgsLike) -> Result<Val> {163		self.evaluate(Context::default(), CallLocation::native(), args, true)164	}165}166167#[derive(Clone)]168pub enum ManifestFormat {169	YamlStream(Box<ManifestFormat>),170	Yaml {171		padding: usize,172		#[cfg(feature = "exp-preserve-order")]173		preserve_order: bool,174	},175	Json {176		padding: usize,177		#[cfg(feature = "exp-preserve-order")]178		preserve_order: bool,179	},180	ToString,181	String,182}183impl ManifestFormat {184	#[cfg(feature = "exp-preserve-order")]185	fn preserve_order(&self) -> bool {186		match self {187			ManifestFormat::YamlStream(s) => s.preserve_order(),188			ManifestFormat::Yaml { preserve_order, .. } => *preserve_order,189			ManifestFormat::Json { preserve_order, .. } => *preserve_order,190			ManifestFormat::ToString => false,191			ManifestFormat::String => false,192		}193	}194}195196#[derive(Debug, Clone, Trace)]197pub struct Slice {198	pub(crate) inner: ArrValue,199	pub(crate) from: u32,200	pub(crate) to: u32,201	pub(crate) step: u32,202}203impl Slice {204	const fn from(&self) -> usize {205		self.from as usize206	}207	const fn to(&self) -> usize {208		self.to as usize209	}210	const fn step(&self) -> usize {211		self.step as usize212	}213	const fn len(&self) -> usize {214		// TODO: use div_ceil215		let diff = self.to() - self.from();216		let rem = diff % self.step();217		let div = diff / self.step();218219		if rem != 0 {220			div + 1221		} else {222			div223		}224	}225}226227#[derive(Debug, Clone, Trace)]228#[force_tracking]229pub enum ArrValue {230	Bytes(#[skip_trace] Rc<[u8]>),231	Lazy(Cc<Vec<LazyVal>>),232	Eager(Cc<Vec<Val>>),233	Extended(Box<(Self, Self)>),234	Range(i32, i32),235	Slice(Box<Slice>),236	Reversed(Box<Self>),237}238impl ArrValue {239	pub fn new_eager() -> Self {240		Self::Eager(Cc::new(Vec::new()))241	}242	pub fn new_range(a: i32, b: i32) -> Self {243		assert!(a <= b);244		Self::Range(a, b)245	}246247	pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {248		let len = self.len();249		let from = from.unwrap_or(0);250		let to = to.unwrap_or(len).min(len);251		let step = step.unwrap_or(1);252		assert!(from < to);253		assert!(step > 0);254255		Self::Slice(Box::new(Slice {256			inner: self,257			from: from as u32,258			to: to as u32,259			step: step as u32,260		}))261	}262263	pub fn len(&self) -> usize {264		match self {265			Self::Bytes(i) => i.len(),266			Self::Lazy(l) => l.len(),267			Self::Eager(e) => e.len(),268			Self::Extended(v) => v.0.len() + v.1.len(),269			Self::Range(a, b) => a.abs_diff(*b) as usize + 1,270			Self::Reversed(i) => i.len(),271			Self::Slice(s) => s.len(),272		}273	}274275	pub fn is_empty(&self) -> bool {276		self.len() == 0277	}278279	pub fn get(&self, index: usize) -> Result<Option<Val>> {280		match self {281			Self::Bytes(i) => i282				.get(index)283				.map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),284			Self::Lazy(vec) => {285				if let Some(v) = vec.get(index) {286					Ok(Some(v.evaluate()?))287				} else {288					Ok(None)289				}290			}291			Self::Eager(vec) => Ok(vec.get(index).cloned()),292			Self::Extended(v) => {293				let a_len = v.0.len();294				if a_len > index {295					v.0.get(index)296				} else {297					v.1.get(index - a_len)298				}299			}300			Self::Range(a, _) => {301				if index >= self.len() {302					return Ok(None);303				}304				Ok(Some(Val::Num(((*a as isize) + index as isize) as f64)))305			}306			Self::Reversed(v) => {307				let len = v.len();308				if index >= len {309					return Ok(None);310				}311				v.get(len - index - 1)312			}313			Self::Slice(s) => {314				let index = s.from() + index * s.step();315				if index >= s.to() {316					return Ok(None);317				}318				s.inner.get(index as usize)319			}320		}321	}322323	pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {324		match self {325			Self::Bytes(i) => i326				.get(index)327				.map(|b| LazyVal::new_resolved(Val::Num(*b as f64))),328			Self::Lazy(vec) => vec.get(index).cloned(),329			Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),330			Self::Extended(v) => {331				let a_len = v.0.len();332				if a_len > index {333					v.0.get_lazy(index)334				} else {335					v.1.get_lazy(index - a_len)336				}337			}338			Self::Range(a, _) => {339				if index >= self.len() {340					return None;341				}342				Some(LazyVal::new_resolved(Val::Num(343					((*a as isize) + index as isize) as f64,344				)))345			}346			Self::Reversed(v) => {347				let len = v.len();348				if index >= len {349					return None;350				}351				v.get_lazy(len - index - 1)352			}353			Self::Slice(s) => {354				let index = s.from() + index * s.step();355				if index >= s.to() {356					return None;357				}358				s.inner.get_lazy(index as usize)359			}360		}361	}362363	pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {364		Ok(match self {365			Self::Bytes(i) => {366				let mut out = Vec::with_capacity(i.len());367				for v in i.iter() {368					out.push(Val::Num(*v as f64));369				}370				Cc::new(out)371			}372			Self::Lazy(vec) => {373				let mut out = Vec::with_capacity(vec.len());374				for item in vec.iter() {375					out.push(item.evaluate()?);376				}377				Cc::new(out)378			}379			Self::Eager(vec) => vec.clone(),380			Self::Extended(_v) => {381				let mut out = Vec::with_capacity(self.len());382				for item in self.iter() {383					out.push(item?);384				}385				Cc::new(out)386			}387			Self::Range(a, b) => {388				let mut out = Vec::with_capacity(self.len());389				for i in *a..*b {390					out.push(Val::Num(i as f64));391				}392				Cc::new(out)393			}394			Self::Reversed(r) => {395				let mut r = r.evaluated()?;396				Cc::update_with(&mut r, |v| v.reverse());397				r398			}399			Self::Slice(v) => {400				let mut out = Vec::with_capacity(v.inner.len());401				for v in v402					.inner403					.iter_lazy()404					.skip(v.from())405					.take(v.to() - v.from())406					.step_by(v.step())407				{408					out.push(v.evaluate()?)409				}410				Cc::new(out)411			}412		})413	}414415	pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {416		(0..self.len()).map(move |idx| match self {417			Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),418			Self::Lazy(l) => l[idx].evaluate(),419			Self::Eager(e) => Ok(e[idx].clone()),420			Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),421			Self::Range(..) => self.get(idx).map(|e| e.unwrap()),422			Self::Reversed(..) => self.get(idx).map(|e| e.unwrap()),423			Self::Slice(..) => self.get(idx).map(|e| e.unwrap()),424		})425	}426427	pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {428		(0..self.len()).map(move |idx| match self {429			Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),430			Self::Lazy(l) => l[idx].clone(),431			Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),432			Self::Extended(_) => self.get_lazy(idx).unwrap(),433			Self::Range(..) => self.get_lazy(idx).unwrap(),434			Self::Reversed(..) => self.get_lazy(idx).unwrap(),435			Self::Slice(..) => self.get_lazy(idx).unwrap(),436		})437	}438439	pub fn reversed(self) -> Self {440		Self::Reversed(Box::new(self))441	}442443	pub fn map(self, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {444		let mut out = Vec::with_capacity(self.len());445446		for value in self.iter() {447			out.push(mapper(value?)?);448		}449450		Ok(Self::Eager(Cc::new(out)))451	}452453	pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {454		let mut out = Vec::with_capacity(self.len());455456		for value in self.iter() {457			let value = value?;458			if filter(&value)? {459				out.push(value);460			}461		}462463		Ok(Self::Eager(Cc::new(out)))464	}465466	pub fn ptr_eq(a: &Self, b: &Self) -> bool {467		match (a, b) {468			(Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b),469			(Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b),470			_ => false,471		}472	}473}474475impl From<Vec<LazyVal>> for ArrValue {476	fn from(v: Vec<LazyVal>) -> Self {477		Self::Lazy(Cc::new(v))478	}479}480481impl From<Vec<Val>> for ArrValue {482	fn from(v: Vec<Val>) -> Self {483		Self::Eager(Cc::new(v))484	}485}486487pub enum IndexableVal {488	Str(IStr),489	Arr(ArrValue),490}491492#[derive(Debug, Clone, Trace)]493pub enum Val {494	Bool(bool),495	Null,496	Str(IStr),497	Num(f64),498	Arr(ArrValue),499	Obj(ObjValue),500	Func(FuncVal),501}502503impl Val {504	pub const fn as_bool(&self) -> Option<bool> {505		match self {506			Val::Bool(v) => Some(*v),507			_ => None,508		}509	}510	pub const fn as_null(&self) -> Option<()> {511		match self {512			Val::Null => Some(()),513			_ => None,514		}515	}516	pub fn as_str(&self) -> Option<IStr> {517		match self {518			Val::Str(s) => Some(s.clone()),519			_ => None,520		}521	}522	pub const fn as_num(&self) -> Option<f64> {523		match self {524			Val::Num(n) => Some(*n),525			_ => None,526		}527	}528	pub fn as_arr(&self) -> Option<ArrValue> {529		match self {530			Val::Arr(a) => Some(a.clone()),531			_ => None,532		}533	}534	pub fn as_obj(&self) -> Option<ObjValue> {535		match self {536			Val::Obj(o) => Some(o.clone()),537			_ => None,538		}539	}540	pub fn as_func(&self) -> Option<FuncVal> {541		match self {542			Val::Func(f) => Some(f.clone()),543			_ => None,544		}545	}546547	/// Creates `Val::Num` after checking for numeric overflow.548	/// As numbers are `f64`, we can just check for their finity.549	pub fn new_checked_num(num: f64) -> Result<Self> {550		if num.is_finite() {551			Ok(Self::Num(num))552		} else {553			throw!(RuntimeError("overflow".into()))554		}555	}556557	pub const fn value_type(&self) -> ValType {558		match self {559			Self::Str(..) => ValType::Str,560			Self::Num(..) => ValType::Num,561			Self::Arr(..) => ValType::Arr,562			Self::Obj(..) => ValType::Obj,563			Self::Bool(_) => ValType::Bool,564			Self::Null => ValType::Null,565			Self::Func(..) => ValType::Func,566		}567	}568569	pub fn to_string(&self) -> Result<IStr> {570		Ok(match self {571			Self::Bool(true) => "true".into(),572			Self::Bool(false) => "false".into(),573			Self::Null => "null".into(),574			Self::Str(s) => s.clone(),575			v => manifest_json_ex(576				v,577				&ManifestJsonOptions {578					padding: "",579					mtype: ManifestType::ToString,580					newline: "\n",581					key_val_sep: ": ",582					#[cfg(feature = "exp-preserve-order")]583					preserve_order: false,584				},585			)?586			.into(),587		})588	}589590	/// Expects value to be object, outputs (key, manifested value) pairs591	pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {592		let obj = match self {593			Self::Obj(obj) => obj,594			_ => throw!(MultiManifestOutputIsNotAObject),595		};596		let keys = obj.fields(597			#[cfg(feature = "exp-preserve-order")]598			ty.preserve_order(),599		);600		let mut out = Vec::with_capacity(keys.len());601		for key in keys {602			let value = obj603				.get(key.clone())?604				.expect("item in object")605				.manifest(ty)?;606			out.push((key, value));607		}608		Ok(out)609	}610611	/// Expects value to be array, outputs manifested values612	pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<IStr>> {613		let arr = match self {614			Self::Arr(a) => a,615			_ => throw!(StreamManifestOutputIsNotAArray),616		};617		let mut out = Vec::with_capacity(arr.len());618		for i in arr.iter() {619			out.push(i?.manifest(ty)?);620		}621		Ok(out)622	}623624	pub fn manifest(&self, ty: &ManifestFormat) -> Result<IStr> {625		Ok(match ty {626			ManifestFormat::YamlStream(format) => {627				let arr = match self {628					Self::Arr(a) => a,629					_ => throw!(StreamManifestOutputIsNotAArray),630				};631				let mut out = String::new();632633				match format as &ManifestFormat {634					ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed),635					ManifestFormat::String => throw!(StreamManifestCannotNestString),636					_ => {}637				};638639				if !arr.is_empty() {640					for v in arr.iter() {641						out.push_str("---\n");642						out.push_str(&v?.manifest(format)?);643						out.push('\n');644					}645					out.push_str("...");646				}647648				out.into()649			}650			ManifestFormat::Yaml {651				padding,652				#[cfg(feature = "exp-preserve-order")]653				preserve_order,654			} => self.to_yaml(655				*padding,656				#[cfg(feature = "exp-preserve-order")]657				*preserve_order,658			)?,659			ManifestFormat::Json {660				padding,661				#[cfg(feature = "exp-preserve-order")]662				preserve_order,663			} => self.to_json(664				*padding,665				#[cfg(feature = "exp-preserve-order")]666				*preserve_order,667			)?,668			ManifestFormat::ToString => self.to_string()?,669			ManifestFormat::String => match self {670				Self::Str(s) => s.clone(),671				_ => throw!(StringManifestOutputIsNotAString),672			},673		})674	}675676	/// For manifestification677	pub fn to_json(678		&self,679		padding: usize,680		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,681	) -> Result<IStr> {682		manifest_json_ex(683			self,684			&ManifestJsonOptions {685				padding: &" ".repeat(padding),686				mtype: if padding == 0 {687					ManifestType::Minify688				} else {689					ManifestType::Manifest690				},691				newline: "\n",692				key_val_sep: ": ",693				#[cfg(feature = "exp-preserve-order")]694				preserve_order,695			},696		)697		.map(|s| s.into())698	}699700	/// Calls `std.manifestJson`701	pub fn to_std_json(702		&self,703		padding: usize,704		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,705	) -> Result<Rc<str>> {706		manifest_json_ex(707			self,708			&ManifestJsonOptions {709				padding: &" ".repeat(padding),710				mtype: ManifestType::Std,711				newline: "\n",712				key_val_sep: ": ",713				#[cfg(feature = "exp-preserve-order")]714				preserve_order,715			},716		)717		.map(|s| s.into())718	}719720	pub fn to_yaml(721		&self,722		padding: usize,723		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,724	) -> Result<IStr> {725		let padding = &" ".repeat(padding);726		manifest_yaml_ex(727			self,728			&ManifestYamlOptions {729				padding,730				arr_element_padding: padding,731				quote_keys: false,732				#[cfg(feature = "exp-preserve-order")]733				preserve_order,734			},735		)736		.map(|s| s.into())737	}738	pub fn into_indexable(self) -> Result<IndexableVal> {739		Ok(match self {740			Val::Str(s) => IndexableVal::Str(s),741			Val::Arr(arr) => IndexableVal::Arr(arr),742			_ => throw!(ValueIsNotIndexable(self.value_type())),743		})744	}745}746747const fn is_function_like(val: &Val) -> bool {748	matches!(val, Val::Func(_))749}750751/// Native implementation of `std.primitiveEquals`752pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {753	Ok(match (val_a, val_b) {754		(Val::Bool(a), Val::Bool(b)) => a == b,755		(Val::Null, Val::Null) => true,756		(Val::Str(a), Val::Str(b)) => a == b,757		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,758		(Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(759			"primitiveEquals operates on primitive types, got array".into(),760		)),761		(Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(762			"primitiveEquals operates on primitive types, got object".into(),763		)),764		(a, b) if is_function_like(a) && is_function_like(b) => {765			throw!(RuntimeError("cannot test equality of functions".into()))766		}767		(_, _) => false,768	})769}770771/// Native implementation of `std.equals`772pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {773	if val_a.value_type() != val_b.value_type() {774		return Ok(false);775	}776	match (val_a, val_b) {777		(Val::Arr(a), Val::Arr(b)) => {778			if ArrValue::ptr_eq(a, b) {779				return Ok(true);780			}781			if a.len() != b.len() {782				return Ok(false);783			}784			for (a, b) in a.iter().zip(b.iter()) {785				if !equals(&a?, &b?)? {786					return Ok(false);787				}788			}789			Ok(true)790		}791		(Val::Obj(a), Val::Obj(b)) => {792			if ObjValue::ptr_eq(a, b) {793				return Ok(true);794			}795			let fields = a.fields(796				#[cfg(feature = "exp-preserve-order")]797				false,798			);799			if fields800				!= b.fields(801					#[cfg(feature = "exp-preserve-order")]802					false,803				) {804				return Ok(false);805			}806			for field in fields {807				if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {808					return Ok(false);809				}810			}811			Ok(true)812		}813		(a, b) => Ok(primitive_equals(a, b)?),814	}815}