1use crate::{2 builtin::{3 call_builtin,4 manifest::{5 manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType,6 ManifestYamlOptions,7 },8 },9 cc_ptr_eq,10 error::{Error::*, LocError},11 evaluate,12 function::{parse_function_call, parse_function_call_map, place_args},13 gc::TraceBox,14 native::NativeCallback,15 throw, Context, ObjValue, Result,16};17use gcmodule::{Cc, Trace};18use jrsonnet_interner::IStr;19use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};20use jrsonnet_types::ValType;21use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};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 evaluate(&self) -> Result<Val> {45 match &*self.0.borrow() {46 LazyValInternals::Computed(v) => return Ok(v.clone()),47 LazyValInternals::Errored(e) => return Err(e.clone()),48 LazyValInternals::Pending => return Err(RecursiveLazyValueEvaluation.into()),49 _ => (),50 };51 let value = if let LazyValInternals::Waiting(value) =52 std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)53 {54 value55 } else {56 unreachable!()57 };58 let new_value = match value.0.get() {59 Ok(v) => v,60 Err(e) => {61 *self.0.borrow_mut() = LazyValInternals::Errored(e.clone());62 return Err(e);63 }64 };65 *self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());66 Ok(new_value)67 }68}6970impl Debug for LazyVal {71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {72 write!(f, "Lazy")73 }74}75impl PartialEq for LazyVal {76 fn eq(&self, other: &Self) -> bool {77 cc_ptr_eq(&self.0, &other.0)78 }79}8081#[derive(Debug, PartialEq, Trace)]82pub struct FuncDesc {83 pub name: IStr,84 pub ctx: Context,85 pub params: ParamsDesc,86 pub body: LocExpr,87}8889#[derive(Debug, Trace)]90pub enum FuncVal {91 92 Normal(FuncDesc),93 94 Intrinsic(IStr),95 96 NativeExt(IStr, Cc<NativeCallback>),97}9899impl PartialEq for FuncVal {100 fn eq(&self, other: &Self) -> bool {101 match (self, other) {102 (Self::Normal(a), Self::Normal(b)) => a == b,103 (Self::Intrinsic(an), Self::Intrinsic(bn)) => an == bn,104 (Self::NativeExt(an, _), Self::NativeExt(bn, _)) => an == bn,105 (..) => false,106 }107 }108}109impl FuncVal {110 pub fn is_ident(&self) -> bool {111 matches!(&self, Self::Intrinsic(n) if n as &str == "id")112 }113 pub fn name(&self) -> IStr {114 match self {115 Self::Normal(normal) => normal.name.clone(),116 Self::Intrinsic(name) => format!("std.{}", name).into(),117 Self::NativeExt(n, _) => format!("native.{}", n).into(),118 }119 }120 pub fn evaluate(121 &self,122 call_ctx: Context,123 loc: &ExprLocation,124 args: &ArgsDesc,125 tailstrict: bool,126 ) -> Result<Val> {127 match self {128 Self::Normal(func) => {129 let ctx = parse_function_call(130 call_ctx,131 func.ctx.clone(),132 &func.params,133 args,134 tailstrict,135 )?;136 evaluate(ctx, &func.body)137 }138 Self::Intrinsic(name) => call_builtin(call_ctx, loc, name, args),139 Self::NativeExt(_name, handler) => {140 let args =141 parse_function_call(call_ctx, Context::new(), &handler.params, args, true)?;142 let mut out_args = Vec::with_capacity(handler.params.len());143 for p in handler.params.0.iter() {144 out_args.push(args.binding(p.0.clone())?.evaluate()?);145 }146 Ok(handler.call(loc.0.clone(), &out_args)?)147 }148 }149 }150151 pub fn evaluate_map(152 &self,153 call_ctx: Context,154 args: &HashMap<IStr, Val>,155 tailstrict: bool,156 ) -> Result<Val> {157 match self {158 Self::Normal(func) => {159 let ctx = parse_function_call_map(160 call_ctx,161 Some(func.ctx.clone()),162 &func.params,163 args,164 tailstrict,165 )?;166 evaluate(ctx, &func.body)167 }168 Self::Intrinsic(_) => todo!(),169 Self::NativeExt(_, _) => todo!(),170 }171 }172173 pub fn evaluate_values(&self, args: &[Val]) -> Result<Val> {174 match self {175 Self::Normal(func) => {176 let ctx = place_args(func.ctx.clone(), &func.params, args)?;177 evaluate(ctx, &func.body)178 }179 Self::Intrinsic(_) => todo!(),180 Self::NativeExt(_, _) => todo!(),181 }182 }183}184185#[derive(Clone)]186pub enum ManifestFormat {187 YamlStream(Box<ManifestFormat>),188 Yaml(usize),189 Json(usize),190 ToString,191 String,192}193194#[derive(Debug, Clone, Trace)]195#[force_tracking]196pub enum ArrValue {197 Lazy(Cc<Vec<LazyVal>>),198 Eager(Cc<Vec<Val>>),199 Extended(Box<(Self, Self)>),200}201impl ArrValue {202 pub fn new_eager() -> Self {203 Self::Eager(Cc::new(Vec::new()))204 }205206 pub fn len(&self) -> usize {207 match self {208 Self::Lazy(l) => l.len(),209 Self::Eager(e) => e.len(),210 Self::Extended(v) => v.0.len() + v.1.len(),211 }212 }213214 pub fn is_empty(&self) -> bool {215 self.len() == 0216 }217218 pub fn get(&self, index: usize) -> Result<Option<Val>> {219 match self {220 Self::Lazy(vec) => {221 if let Some(v) = vec.get(index) {222 Ok(Some(v.evaluate()?))223 } else {224 Ok(None)225 }226 }227 Self::Eager(vec) => Ok(vec.get(index).cloned()),228 Self::Extended(v) => {229 let a_len = v.0.len();230 if a_len > index {231 v.0.get(index)232 } else {233 v.1.get(index - a_len)234 }235 }236 }237 }238239 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {240 match self {241 Self::Lazy(vec) => vec.get(index).cloned(),242 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),243 Self::Extended(v) => {244 let a_len = v.0.len();245 if a_len > index {246 v.0.get_lazy(index)247 } else {248 v.1.get_lazy(index - a_len)249 }250 }251 }252 }253254 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {255 Ok(match self {256 Self::Lazy(vec) => {257 let mut out = Vec::with_capacity(vec.len());258 for item in vec.iter() {259 out.push(item.evaluate()?);260 }261 Cc::new(out)262 }263 Self::Eager(vec) => vec.clone(),264 Self::Extended(_v) => {265 let mut out = Vec::with_capacity(self.len());266 for item in self.iter() {267 out.push(item?);268 }269 Cc::new(out)270 }271 })272 }273274 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {275 (0..self.len()).map(move |idx| match self {276 Self::Lazy(l) => l[idx].evaluate(),277 Self::Eager(e) => Ok(e[idx].clone()),278 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),279 })280 }281282 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {283 (0..self.len()).map(move |idx| match self {284 Self::Lazy(l) => l[idx].clone(),285 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),286 Self::Extended(_) => self.get_lazy(idx).unwrap(),287 })288 }289290 pub fn reversed(self) -> Self {291 match self {292 Self::Lazy(vec) => {293 let mut out = (&vec as &Vec<_>).clone();294 out.reverse();295 Self::Lazy(Cc::new(out))296 }297 Self::Eager(vec) => {298 let mut out = (&vec as &Vec<_>).clone();299 out.reverse();300 Self::Eager(Cc::new(out))301 }302 Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))),303 }304 }305306 pub fn map(self, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {307 let mut out = Vec::with_capacity(self.len());308309 for value in self.iter() {310 out.push(mapper(value?)?);311 }312313 Ok(Self::Eager(Cc::new(out)))314 }315316 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {317 let mut out = Vec::with_capacity(self.len());318319 for value in self.iter() {320 let value = value?;321 if filter(&value)? {322 out.push(value);323 }324 }325326 Ok(Self::Eager(Cc::new(out)))327 }328329 pub fn ptr_eq(a: &Self, b: &Self) -> bool {330 match (a, b) {331 (Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b),332 (Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b),333 _ => false,334 }335 }336}337338impl From<Vec<LazyVal>> for ArrValue {339 fn from(v: Vec<LazyVal>) -> Self {340 Self::Lazy(Cc::new(v))341 }342}343344impl From<Vec<Val>> for ArrValue {345 fn from(v: Vec<Val>) -> Self {346 Self::Eager(Cc::new(v))347 }348}349350pub enum IndexableVal {351 Str(IStr),352 Arr(ArrValue),353}354355#[derive(Debug, Clone, Trace)]356pub enum Val {357 Bool(bool),358 Null,359 Str(IStr),360 Num(f64),361 Arr(ArrValue),362 Obj(ObjValue),363 Func(Cc<FuncVal>),364}365366impl Val {367 368 369 pub fn new_checked_num(num: f64) -> Result<Self> {370 if num.is_finite() {371 Ok(Self::Num(num))372 } else {373 throw!(RuntimeError("overflow".into()))374 }375 }376377 pub fn try_cast_nullable_num(self, context: &'static str) -> Result<Option<f64>> {378 Ok(match self {379 Val::Null => None,380 Val::Num(num) => Some(num),381 _ => throw!(TypeMismatch(382 context,383 vec![ValType::Null, ValType::Num],384 self.value_type()385 )),386 })387 }388 pub const fn value_type(&self) -> ValType {389 match self {390 Self::Str(..) => ValType::Str,391 Self::Num(..) => ValType::Num,392 Self::Arr(..) => ValType::Arr,393 Self::Obj(..) => ValType::Obj,394 Self::Bool(_) => ValType::Bool,395 Self::Null => ValType::Null,396 Self::Func(..) => ValType::Func,397 }398 }399400 pub fn to_string(&self) -> Result<IStr> {401 Ok(match self {402 Self::Bool(true) => "true".into(),403 Self::Bool(false) => "false".into(),404 Self::Null => "null".into(),405 Self::Str(s) => s.clone(),406 v => manifest_json_ex(407 v,408 &ManifestJsonOptions {409 padding: "",410 mtype: ManifestType::ToString,411 },412 )?413 .into(),414 })415 }416417 418 pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {419 let obj = match self {420 Self::Obj(obj) => obj,421 _ => throw!(MultiManifestOutputIsNotAObject),422 };423 let keys = obj.fields();424 let mut out = Vec::with_capacity(keys.len());425 for key in keys {426 let value = obj427 .get(key.clone())?428 .expect("item in object")429 .manifest(ty)?;430 out.push((key, value));431 }432 Ok(out)433 }434435 436 pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<IStr>> {437 let arr = match self {438 Self::Arr(a) => a,439 _ => throw!(StreamManifestOutputIsNotAArray),440 };441 let mut out = Vec::with_capacity(arr.len());442 for i in arr.iter() {443 out.push(i?.manifest(ty)?);444 }445 Ok(out)446 }447448 pub fn manifest(&self, ty: &ManifestFormat) -> Result<IStr> {449 Ok(match ty {450 ManifestFormat::YamlStream(format) => {451 let arr = match self {452 Self::Arr(a) => a,453 _ => throw!(StreamManifestOutputIsNotAArray),454 };455 let mut out = String::new();456457 match format as &ManifestFormat {458 ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed),459 ManifestFormat::String => throw!(StreamManifestCannotNestString),460 _ => {}461 };462463 if !arr.is_empty() {464 for v in arr.iter() {465 out.push_str("---\n");466 out.push_str(&v?.manifest(format)?);467 out.push('\n');468 }469 out.push_str("...");470 }471472 out.into()473 }474 ManifestFormat::Yaml(padding) => self.to_yaml(*padding)?,475 ManifestFormat::Json(padding) => self.to_json(*padding)?,476 ManifestFormat::ToString => self.to_string()?,477 ManifestFormat::String => match self {478 Self::Str(s) => s.clone(),479 _ => throw!(StringManifestOutputIsNotAString),480 },481 })482 }483484 485 pub fn to_json(&self, padding: usize) -> Result<IStr> {486 manifest_json_ex(487 self,488 &ManifestJsonOptions {489 padding: &" ".repeat(padding),490 mtype: if padding == 0 {491 ManifestType::Minify492 } else {493 ManifestType::Manifest494 },495 },496 )497 .map(|s| s.into())498 }499500 501 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {502 manifest_json_ex(503 self,504 &ManifestJsonOptions {505 padding: &" ".repeat(padding),506 mtype: ManifestType::Std,507 },508 )509 .map(|s| s.into())510 }511512 pub fn to_yaml(&self, padding: usize) -> Result<IStr> {513 let padding = &" ".repeat(padding);514 manifest_yaml_ex(515 self,516 &ManifestYamlOptions {517 padding,518 arr_element_padding: padding,519 quote_keys: false,520 },521 )522 .map(|s| s.into())523 }524 pub fn into_indexable(self) -> Result<IndexableVal> {525 Ok(match self {526 Val::Str(s) => IndexableVal::Str(s),527 Val::Arr(arr) => IndexableVal::Arr(arr),528 _ => throw!(ValueIsNotIndexable(self.value_type())),529 })530 }531}532533const fn is_function_like(val: &Val) -> bool {534 matches!(val, Val::Func(_))535}536537538pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {539 Ok(match (val_a, val_b) {540 (Val::Bool(a), Val::Bool(b)) => a == b,541 (Val::Null, Val::Null) => true,542 (Val::Str(a), Val::Str(b)) => a == b,543 (Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,544 (Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(545 "primitiveEquals operates on primitive types, got array".into(),546 )),547 (Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(548 "primitiveEquals operates on primitive types, got object".into(),549 )),550 (a, b) if is_function_like(a) && is_function_like(b) => {551 throw!(RuntimeError("cannot test equality of functions".into()))552 }553 (_, _) => false,554 })555}556557558pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {559 if val_a.value_type() != val_b.value_type() {560 return Ok(false);561 }562 match (val_a, val_b) {563 (Val::Arr(a), Val::Arr(b)) => {564 if ArrValue::ptr_eq(a, b) {565 return Ok(true);566 }567 if a.len() != b.len() {568 return Ok(false);569 }570 for (a, b) in a.iter().zip(b.iter()) {571 if !equals(&a?, &b?)? {572 return Ok(false);573 }574 }575 Ok(true)576 }577 (Val::Obj(a), Val::Obj(b)) => {578 if ObjValue::ptr_eq(a, b) {579 return Ok(true);580 }581 let fields = a.fields();582 if fields != b.fields() {583 return Ok(false);584 }585 for field in fields {586 if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {587 return Ok(false);588 }589 }590 Ok(true)591 }592 (a, b) => Ok(primitive_equals(a, b)?),593 }594}