difftreelog
fix make jsonnet tests partially pass
in: master
3 files changed
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -54,11 +54,16 @@
pub fn evaluate_field_name(
context: Context,
field_name: &jsonnet_parser::FieldName,
-) -> Result<String> {
+) -> Result<Option<String>> {
Ok(match field_name {
- jsonnet_parser::FieldName::Fixed(n) => n.clone(),
+ jsonnet_parser::FieldName::Fixed(n) => Some(n.clone()),
jsonnet_parser::FieldName::Dyn(expr) => {
- evaluate(context, expr)?.try_cast_str("dynamic field name")?
+ let value = evaluate(context, expr)?.unwrap_if_lazy()?;
+ if matches!(value, Val::Null) {
+ None
+ } else {
+ Some(value.try_cast_str("dynamic field name")?)
+ }
}
})
}
@@ -234,6 +239,10 @@
value,
}) => {
let name = evaluate_field_name(context.clone(), &name)?;
+ if name.is_none() {
+ continue;
+ }
+ let name = name.unwrap();
new_members.insert(
name.clone(),
ObjMember {
@@ -260,6 +269,10 @@
..
}) => {
let name = evaluate_field_name(context.clone(), &name)?;
+ if name.is_none() {
+ continue;
+ }
+ let name = name.unwrap();
new_members.insert(
name,
ObjMember {
@@ -299,12 +312,6 @@
.clone()
.unwrap_or_else(|| panic!("this not found")),
),
- Literal(LiteralType::Super) => Val::Obj(
- context
- .super_obj()
- .clone()
- .unwrap_or_else(|| panic!("super not found")),
- ),
Literal(LiteralType::Dollar) => Val::Obj(
context
.dollar()
@@ -320,6 +327,15 @@
BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?,
UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
Var(name) => Val::Lazy(context.binding(&name)).unwrap_if_lazy()?,
+ Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {
+ let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;
+ context
+ .super_obj()
+ .clone()
+ .expect("no super found")
+ .get_raw(&name, &context.this().clone().expect("no this found"))?
+ .expect("value not found")
+ }
Index(value, index) => {
match (
evaluate(context.clone(), value)?.unwrap_if_lazy()?,
@@ -381,6 +397,10 @@
evaluate_comp(context, expr, compspecs)?.unwrap(),
),
Obj(body) => Val::Obj(evaluate_object(context, body.clone())?),
+ ObjExtend(s, t) => evaluate_add_op(
+ &evaluate(context.clone(), s)?,
+ &Val::Obj(evaluate_object(context, t.clone())?),
+ )?,
Apply(value, ArgsDesc(args)) => {
let value = evaluate(context.clone(), value)?.unwrap_if_lazy()?;
match value {
@@ -408,7 +428,7 @@
evaluate(context.clone(), &args[0].1)?,
evaluate(context, &args[1].1)?,
) {
- assert!(v > 0.0);
+ assert!(v >= 0.0);
let mut out = Vec::with_capacity(v as usize);
for i in 0..v as usize {
out.push(d.evaluate(vec![(None, Val::Num(i as f64))])?)
@@ -452,6 +472,25 @@
);
Val::Bool(a == b)
}
+ ("std", "modulo") => {
+ assert_eq!(args.len(), 2);
+ if let (Val::Num(a), Val::Num(b)) = (
+ evaluate(context.clone(), &args[0].1)?,
+ evaluate(context, &args[1].1)?,
+ ) {
+ Val::Num(a % b)
+ } else {
+ panic!("bad modulo call");
+ }
+ }
+ ("std", "floor") => {
+ assert_eq!(args.len(), 1);
+ if let Val::Num(a) = evaluate(context, &args[0].1)? {
+ Val::Num(a.floor())
+ } else {
+ panic!("bad floor call");
+ }
+ }
(ns, name) => panic!("Intristic not found: {}.{}", ns, name),
},
Val::Func(f) => push(locexpr, "function call".to_owned(), || {
@@ -516,7 +555,7 @@
Some(v) => push(v.clone(), "if condition 'else' branch".to_owned(), || {
evaluate(context, v)
})?,
- None => Val::Bool(false),
+ None => Val::Null,
}
}
}
crates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/obj.rs
+++ b/crates/jsonnet-evaluator/src/obj.rs
@@ -83,7 +83,7 @@
Ok(None)
}
}
- fn get_raw(&self, key: &str, real_this: &ObjValue) -> Result<Option<Val>> {
+ pub(crate) fn get_raw(&self, key: &str, real_this: &ObjValue) -> Result<Option<Val>> {
match (self.0.this_entries.get(key), &self.0.super_obj) {
(Some(k), None) => Ok(Some(k.invoke.0(
Some(real_this.clone()),
crates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth1use crate::{2 create_error, lazy_binding, Context, Error, FunctionDefault, FunctionRhs, LazyBinding,3 ObjValue, Result,4};5use closure::closure;6use jsonnet_parser::ParamsDesc;7use std::{8 cell::RefCell,9 collections::HashMap,10 fmt::{Debug, Display},11 rc::Rc,12};1314struct LazyValInternals {15 pub f: Box<dyn Fn() -> Result<Val>>,16 pub cached: RefCell<Option<Val>>,17}18#[derive(Clone)]19pub struct LazyVal(Rc<LazyValInternals>);20impl LazyVal {21 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {22 LazyVal(Rc::new(LazyValInternals {23 f,24 cached: RefCell::new(None),25 }))26 }27 pub fn evaluate(&self) -> Result<Val> {28 {29 let cached = self.0.cached.borrow();30 if cached.is_some() {31 return Ok(cached.clone().unwrap());32 }33 }34 let result = (self.0.f)()?;35 self.0.cached.borrow_mut().replace(result.clone());36 Ok(result)37 }38}39#[macro_export]40macro_rules! lazy_val {41 ($f: expr) => {42 $crate::LazyVal::new(Box::new($f))43 };44}45impl Debug for LazyVal {46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {47 if self.0.cached.borrow().is_some() {48 write!(f, "{:?}", self.0.cached.borrow().clone().unwrap())49 } else {50 write!(f, "Lazy")51 }52 }53}54impl PartialEq for LazyVal {55 fn eq(&self, other: &Self) -> bool {56 Rc::ptr_eq(&self.0, &other.0)57 }58}5960#[derive(Debug, PartialEq, Clone)]61pub struct FuncDesc {62 pub ctx: Context,63 pub params: ParamsDesc,64 pub eval_rhs: FunctionRhs,65 pub eval_default: FunctionDefault,66}67impl FuncDesc {68 // TODO: Check for unset variables69 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Result<Val> {70 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();71 let future_ctx = Context::new_future();7273 // self.params74 // .with_defaults()75 // .into_iter()76 // .for_each(|Param(name, default)| {77 // let default = Rc::new(*default.unwrap());78 // new_bindings.insert(79 // name,80 // binding!(move |_, _| Val::Lazy(lazy_val!(|| self81 // .eval_default82 // .083 // .default(future_ctx.unwrap(), *default.clone())))),84 // );85 // });86 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {87 new_bindings.insert(88 name.as_ref().unwrap().clone(),89 lazy_binding!(90 closure!(clone val, |_, _| Ok(lazy_val!(closure!(clone val, || Ok(val.clone())))))91 ),92 );93 }94 for (i, param) in self.params.0.iter().enumerate() {95 if let Some((None, val)) = args.get(i) {96 new_bindings.insert(97 param.0.clone(),98 lazy_binding!(99 closure!(clone val, |_, _| Ok(lazy_val!(closure!(clone val, || Ok(val.clone())))))100 ),101 );102 }103 }104 let ctx = self105 .ctx106 .extend(new_bindings, None, None, None)?107 .into_future(future_ctx);108 self.eval_rhs.0(ctx)109 }110}111112#[derive(Debug)]113pub enum ValType {114 Bool,115 Null,116 Str,117 Num,118 Arr,119 Obj,120 Func,121}122impl ValType {123 pub fn name(&self) -> &'static str {124 use ValType::*;125 match self {126 Bool => "boolean",127 Null => "null",128 Str => "string",129 Num => "number",130 Arr => "array",131 Obj => "object",132 Func => "function",133 }134 }135}136impl Display for ValType {137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {138 write!(f, "{}", self.name())139 }140}141142#[derive(Debug, PartialEq, Clone)]143pub enum Val {144 Bool(bool),145 Null,146 Str(String),147 Num(f64),148 Lazy(LazyVal),149 Arr(Vec<Val>),150 Obj(ObjValue),151 Func(FuncDesc),152153 // Library functions implemented in native154 Intristic(String, String),155}156impl Val {157 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {158 match self.unwrap_if_lazy()? {159 Val::Bool(v) => Ok(v),160 v => create_error(Error::TypeMismatch(161 context,162 vec![ValType::Bool],163 v.value_type()?,164 )),165 }166 }167 pub fn try_cast_str(self, context: &'static str) -> Result<String> {168 match self.unwrap_if_lazy()? {169 Val::Str(v) => Ok(v),170 v => create_error(Error::TypeMismatch(171 context,172 vec![ValType::Str],173 v.value_type()?,174 )),175 }176 }177 pub fn unwrap_if_lazy(self) -> Result<Self> {178 Ok(if let Val::Lazy(v) = self {179 v.evaluate()?.unwrap_if_lazy()?180 } else {181 self182 })183 }184 pub fn value_type(&self) -> Result<ValType> {185 Ok(match self {186 Val::Str(..) => ValType::Str,187 Val::Num(..) => ValType::Num,188 Val::Arr(..) => ValType::Arr,189 Val::Obj(..) => ValType::Obj,190 Val::Func(..) => ValType::Func,191 Val::Bool(_) => ValType::Bool,192 Val::Null => ValType::Null,193 Val::Intristic(_, _) => ValType::Func,194 Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,195 })196 }197}1use crate::{2 create_error, lazy_binding, Context, Error, FunctionDefault, FunctionRhs, LazyBinding,3 ObjValue, Result,4};5use closure::closure;6use jsonnet_parser::{Param, ParamsDesc};7use std::{8 cell::RefCell,9 collections::HashMap,10 fmt::{Debug, Display},11 rc::Rc,12};1314struct LazyValInternals {15 pub f: Box<dyn Fn() -> Result<Val>>,16 pub cached: RefCell<Option<Val>>,17}18#[derive(Clone)]19pub struct LazyVal(Rc<LazyValInternals>);20impl LazyVal {21 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {22 LazyVal(Rc::new(LazyValInternals {23 f,24 cached: RefCell::new(None),25 }))26 }27 pub fn evaluate(&self) -> Result<Val> {28 {29 let cached = self.0.cached.borrow();30 if cached.is_some() {31 return Ok(cached.clone().unwrap());32 }33 }34 let result = (self.0.f)()?;35 self.0.cached.borrow_mut().replace(result.clone());36 Ok(result)37 }38}39#[macro_export]40macro_rules! lazy_val {41 ($f: expr) => {42 $crate::LazyVal::new(Box::new($f))43 };44}45impl Debug for LazyVal {46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {47 if self.0.cached.borrow().is_some() {48 write!(f, "{:?}", self.0.cached.borrow().clone().unwrap())49 } else {50 write!(f, "Lazy")51 }52 }53}54impl PartialEq for LazyVal {55 fn eq(&self, other: &Self) -> bool {56 Rc::ptr_eq(&self.0, &other.0)57 }58}5960#[derive(Debug, PartialEq, Clone)]61pub struct FuncDesc {62 pub ctx: Context,63 pub params: ParamsDesc,64 pub eval_rhs: FunctionRhs,65 pub eval_default: FunctionDefault,66}67impl FuncDesc {68 // TODO: Check for unset variables69 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Result<Val> {70 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();71 let future_ctx = Context::new_future();7273 for Param(name, default) in self.params.with_defaults() {74 let default = default.unwrap();75 let eval_default = self.eval_default.clone();76 new_bindings.insert(77 name,78 lazy_binding!(closure!(clone future_ctx, clone default, clone eval_default, |_, _| Ok(lazy_val!(closure!(clone future_ctx, clone eval_default, clone default, || (eval_default.clone()).079 (future_ctx.clone().unwrap(), default.clone())))))),80 );81 }82 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {83 new_bindings.insert(84 name.as_ref().unwrap().clone(),85 lazy_binding!(86 closure!(clone val, |_, _| Ok(lazy_val!(closure!(clone val, || Ok(val.clone())))))87 ),88 );89 }90 for (i, param) in self.params.0.iter().enumerate() {91 if let Some((None, val)) = args.get(i) {92 new_bindings.insert(93 param.0.clone(),94 lazy_binding!(95 closure!(clone val, |_, _| Ok(lazy_val!(closure!(clone val, || Ok(val.clone())))))96 ),97 );98 }99 }100 let ctx = self101 .ctx102 .extend(new_bindings, None, None, None)?103 .into_future(future_ctx);104 self.eval_rhs.0(ctx)105 }106}107108#[derive(Debug)]109pub enum ValType {110 Bool,111 Null,112 Str,113 Num,114 Arr,115 Obj,116 Func,117}118impl ValType {119 pub fn name(&self) -> &'static str {120 use ValType::*;121 match self {122 Bool => "boolean",123 Null => "null",124 Str => "string",125 Num => "number",126 Arr => "array",127 Obj => "object",128 Func => "function",129 }130 }131}132impl Display for ValType {133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {134 write!(f, "{}", self.name())135 }136}137138#[derive(Debug, PartialEq, Clone)]139pub enum Val {140 Bool(bool),141 Null,142 Str(String),143 Num(f64),144 Lazy(LazyVal),145 Arr(Vec<Val>),146 Obj(ObjValue),147 Func(FuncDesc),148149 // Library functions implemented in native150 Intristic(String, String),151}152impl Val {153 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {154 match self.unwrap_if_lazy()? {155 Val::Bool(v) => Ok(v),156 v => create_error(Error::TypeMismatch(157 context,158 vec![ValType::Bool],159 v.value_type()?,160 )),161 }162 }163 pub fn try_cast_str(self, context: &'static str) -> Result<String> {164 match self.unwrap_if_lazy()? {165 Val::Str(v) => Ok(v),166 v => create_error(Error::TypeMismatch(167 context,168 vec![ValType::Str],169 v.value_type()?,170 )),171 }172 }173 pub fn unwrap_if_lazy(self) -> Result<Self> {174 Ok(if let Val::Lazy(v) = self {175 v.evaluate()?.unwrap_if_lazy()?176 } else {177 self178 })179 }180 pub fn value_type(&self) -> Result<ValType> {181 Ok(match self {182 Val::Str(..) => ValType::Str,183 Val::Num(..) => ValType::Num,184 Val::Arr(..) => ValType::Arr,185 Val::Obj(..) => ValType::Obj,186 Val::Func(..) => ValType::Func,187 Val::Bool(_) => ValType::Bool,188 Val::Null => ValType::Null,189 Val::Intristic(_, _) => ValType::Func,190 Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,191 })192 }193}