git.delta.rocks / jrsonnet / refs/commits / 26c294dc66fa

difftreelog

fix(evaluator) instristics

Лач2020-05-31parent: #30ac0c8.patch.diff
in: master

6 files changed

addedcrates/jsonnet-evaluator/README.mddiffbeforeafterboth

no changes

modifiedcrates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
1use crate::{future_wrapper, rc_fn_helper, Binding, ObjValue};1use crate::{future_wrapper, rc_fn_helper, LazyBinding, ObjValue, LazyVal, Val};
2use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};2use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
33
4rc_fn_helper!(4rc_fn_helper!(
14 dollar: Option<ObjValue>,14 dollar: Option<ObjValue>,
15 this: Option<ObjValue>,15 this: Option<ObjValue>,
16 super_obj: Option<ObjValue>,16 super_obj: Option<ObjValue>,
17 bindings: Rc<RefCell<HashMap<String, Binding>>>,17 bindings: Rc<HashMap<String, LazyVal>>,
18}18}
19pub struct Context(Rc<ContextInternals>);19pub struct Context(Rc<ContextInternals>);
20impl Debug for Context {20impl Debug for Context {
46 dollar: None,46 dollar: None,
47 this: None,47 this: None,
48 super_obj: None,48 super_obj: None,
49 bindings: Rc::new(RefCell::new(HashMap::new())),49 bindings: Rc::new(HashMap::new()),
50 }))50 }))
51 }51 }
5252
53 pub fn binding(&self, name: &str) -> Binding {53 pub fn binding(&self, name: &str) -> LazyVal {
54 self.054 self.0
55 .bindings55 .bindings
56 .borrow()
57 .get(name)56 .get(name)
58 .cloned()57 .cloned()
59 .unwrap_or_else(|| {58 .unwrap_or_else(|| {
6968
70 pub fn extend(69 pub fn extend(
71 &self,70 &self,
72 new_bindings: HashMap<String, Binding>,71 new_bindings: HashMap<String, LazyBinding>,
73 new_dollar: Option<ObjValue>,72 new_dollar: Option<ObjValue>,
74 new_this: Option<ObjValue>,73 new_this: Option<ObjValue>,
75 new_super_obj: Option<ObjValue>,74 new_super_obj: Option<ObjValue>,
80 let bindings = if new_bindings.is_empty() {79 let bindings = if new_bindings.is_empty() {
81 self.0.bindings.clone()80 self.0.bindings.clone()
82 } else {81 } else {
82 let mut new = HashMap::new(); // = self.0.bindings.clone();
83 let new = self.0.bindings.clone();83 for (k, v) in self.0.bindings.iter() {
84 new.insert(k.clone(), v.clone());
85 }
84 for (k, v) in new_bindings.into_iter() {86 for (k, v) in new_bindings.into_iter() {
85 new.borrow_mut().insert(k, v);87 new.insert(k, v.0(this.clone(), super_obj.clone()));
86 }88 }
87 new89 Rc::new(new)
88 };90 };
89 Context(Rc::new(ContextInternals {91 Context(Rc::new(ContextInternals {
90 dollar,92 dollar,
modifiedcrates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 binding, bool_val, context_creator, function_default, function_rhs, future_wrapper, lazy_val,2 binding, bool_val, context_creator, function_default, function_rhs, future_wrapper,
3 Binding, Context, ContextCreator, FuncDesc, ObjMember, ObjValue, Val,3 lazy_binding, lazy_val, Binding, Context, ContextCreator, FuncDesc, LazyBinding, ObjMember,
4 ObjValue, Val,
4};5};
5use closure::closure;6use closure::closure;
12 rc::Rc,13 rc::Rc,
13};14};
1415
15pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (String, Binding) {16pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (String, LazyBinding) {
16 let b = b.clone();17 let b = b.clone();
17 if let Some(args) = &b.params {18 if let Some(args) = &b.params {
18 let args = args.clone();19 let args = args.clone();
19 (20 (
20 b.name.clone(),21 b.name.clone(),
21 binding!(move |this, super_obj| Val::Lazy(lazy_val!(22 lazy_binding!(move |this, super_obj| lazy_val!(
22 closure!(clone b, clone args, clone context_creator, || evaluate_method(23 closure!(clone b, clone args, clone context_creator, || evaluate_method(
23 context_creator.0(this.clone(), super_obj.clone()),24 context_creator.0(this.clone(), super_obj.clone()),
24 &b.value,25 &b.value,
25 args.clone()26 args.clone()
26 ))27 ))
27 ))),28 )),
28 )29 )
29 } else {30 } else {
30 (31 (
31 b.name.clone(),32 b.name.clone(),
32 binding!(move |this, super_obj| {33 lazy_binding!(move |this, super_obj| {
33 Val::Lazy(lazy_val!(34 lazy_val!(closure!(clone context_creator, clone b, || evaluate(
34 closure!(clone context_creator, clone b, || evaluate(
35 context_creator.0(this.clone(), super_obj.clone()),35 context_creator.0(this.clone(), super_obj.clone()),
36 &b.value36 &b.value
37 ))37 )))
38 ))
39 }),38 }),
40 )39 )
41 }40 }
87 (Val::Str(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Str(format!("{}{}", v1, v2)),86 (Val::Str(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Str(format!("{}{}", v1, v2)),
88 (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),87 (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),
88
89 (Val::Literal(LiteralType::False), BinaryOpType::And, Val::Literal(LiteralType::False)) => {
90 bool_val(false)
91 }
92 (Val::Literal(LiteralType::False), BinaryOpType::And, Val::Literal(LiteralType::True)) => {
93 bool_val(false)
94 }
95 (Val::Literal(LiteralType::True), BinaryOpType::And, Val::Literal(LiteralType::False)) => {
96 bool_val(false)
97 }
98 (Val::Literal(LiteralType::True), BinaryOpType::And, Val::Literal(LiteralType::True)) => {
99 bool_val(true)
100 }
89101
90 (Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),102 (Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),
91103
126 }138 }
127}139}
128140
129future_wrapper!(HashMap<String, Binding>, FutureNewBindings);141future_wrapper!(HashMap<String, LazyBinding>, FutureNewBindings);
130future_wrapper!(ObjValue, FutureObjValue);142future_wrapper!(ObjValue, FutureObjValue);
131143
132// TODO: Asserts144// TODO: Asserts
133pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {145pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {
134 match object {146 match object {
135 ObjBody::MemberList(members) => {147 ObjBody::MemberList(members) => {
136 let future_bindings = FutureNewBindings::new();148 let new_bindings = FutureNewBindings::new();
137 let future_this = FutureObjValue::new();149 let future_this = FutureObjValue::new();
138 let context_creator = context_creator!(150 let context_creator = context_creator!(
139 closure!(clone context, clone future_bindings, clone future_this, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {151 closure!(clone context, clone new_bindings, clone future_this, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
140 context.clone().extend(152 context.clone().extend(
141 future_bindings.clone().unwrap(),153 new_bindings.clone().unwrap(),
142 context.clone().dollar().clone().or_else(||this.clone()),154 context.clone().dollar().clone().or_else(||this.clone()),
143 Some(future_this.clone().unwrap()),155 Some(this.clone().unwrap()),
144 super_obj156 super_obj
145 )157 )
146 })158 })
147 );159 );
160 {
148 let mut bindings: HashMap<String, Binding> = HashMap::new();161 let mut bindings: HashMap<String, LazyBinding> = HashMap::new();
149 for (n, b) in members162 for (n, b) in members
150 .iter()163 .iter()
151 .filter_map(|m| match m {164 .filter_map(|m| match m {
156 {169 {
157 bindings.insert(n, b);170 bindings.insert(n, b);
158 }171 }
159 future_bindings.fill(bindings);172 new_bindings.fill(bindings);
173 }
160174
161 let mut new_members = BTreeMap::new();175 let mut new_members = BTreeMap::new();
162 for member in members.into_iter() {176 for member in members.into_iter() {
176 visibility: visibility.clone(),190 visibility: visibility.clone(),
177 invoke: binding!(191 invoke: binding!(
178 closure!(clone value, clone context_creator, |this, super_obj| {192 closure!(clone value, clone context_creator, |this, super_obj| {
179 // TODO: Assert
180 evaluate(
181 context_creator.0(this, super_obj),193 let context = context_creator.0(this, super_obj);
194 // TODO: Assert
195 evaluate(
196 context,
182 &value,197 &value,
183 )198 ).unwrap_if_lazy()
184 })199 })
185 ),200 ),
186 },201 },
244 evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))259 evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))
245 }260 }
246 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)),261 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)),
247 Var(name) => {262 Var(name) => Val::Lazy(context.binding(&name)).unwrap_if_lazy(),
248 let variable = context.binding(&name);
249 variable.0(None, None).unwrap_if_lazy()
250 }
251 Index(box value, box index) => {263 Index(box value, box index) => {
252 match (264 match (
253 evaluate(context.clone(), value).unwrap_if_lazy(),265 evaluate(context.clone(), value).unwrap_if_lazy(),
254 evaluate(context, index),266 evaluate(context.clone(), index),
255 ) {267 ) {
256 (Val::Obj(v), Val::Str(s)) => v268 (Val::Obj(v), Val::Str(s)) => v
257 .get(&s)269 .get(&s)
258 .unwrap_or_else(|| panic!("{} not found in {:?}", s, v)),270 .unwrap_or_else(closure!(clone context, || {
271 if let Some(n) = v.get("__intristic_namespace__") {
272 if let Val::Str(n) = n.unwrap_if_lazy() {
273 Val::Intristic(n, s)
274 } else {
275 panic!("__intristic_namespace__ should be string");
276 }
277 } else {
278 panic!("{} not found in {:?}", s, v)
279 }
280 }))
281 .unwrap_if_lazy(),
259 (Val::Arr(v), Val::Num(n)) => v282 (Val::Arr(v), Val::Num(n)) => v
260 .get(n as usize)283 .get(n as usize)
261 .unwrap_or_else(|| panic!("out of bounds"))284 .unwrap_or_else(|| panic!("out of bounds"))
262 .clone(),285 .clone(),
286 (Val::Str(s), Val::Num(n)) => {
287 // FIXME: Only works for ASCII
288 Val::Str(String::from_utf8(vec![s.as_bytes()[n as usize]]).unwrap())
289 }
263 (v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),290 (v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),
264 }291 }
265 }292 }
266 LocalExpr(bindings, returned) => {293 LocalExpr(bindings, returned) => {
267 let mut new_bindings: HashMap<String, Binding> = HashMap::new();294 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();
268 let future_context = Context::new_future();295 let future_context = Context::new_future();
269296
270 let context_creator = context_creator!(297 let context_creator = context_creator!(
287 Apply(box value, ArgsDesc(args)) => {314 Apply(box value, ArgsDesc(args)) => {
288 let value = evaluate(context.clone(), value).unwrap_if_lazy();315 let value = evaluate(context.clone(), value).unwrap_if_lazy();
289 match value {316 match value {
317 // TODO: Capture context of application
318 Val::Intristic(ns, name) => match (&ns as &str, &name as &str) {
319 ("std", "length") => {
320 assert_eq!(args.len(), 1);
321 let expr = &args.get(0).unwrap().1;
322 match evaluate(context, expr) {
323 Val::Str(n) => Val::Num(n.len() as f64),
324 Val::Arr(i) => Val::Num(i.len() as f64),
325 v => panic!("can't get length of {:?}", v),
326 }
327 }
328 ("std", "type") => {
329 assert_eq!(args.len(), 1);
330 let expr = &args.get(0).unwrap().1;
331 Val::Str(evaluate(context, expr).type_of().to_owned())
332 }
333 ("std", "makeArray") => {
334 assert_eq!(args.len(), 2);
335 if let (Val::Num(v), Val::Func(d)) = (
336 evaluate(context.clone(), &args[0].1),
337 evaluate(context, &args[1].1),
338 ) {
339 assert!(v > 0.0);
340 let mut out = Vec::with_capacity(v as usize);
341 for i in 0..v as usize {
342 out.push(d.evaluate(vec![(None, Val::Num(i as f64))]))
343 }
344 Val::Arr(out)
345 } else {
346 panic!("bad makeArray call");
347 }
348 }
349 ("std", "codepoint") => {
350 assert_eq!(args.len(), 1);
351 if let Val::Str(s) = evaluate(context.clone(), &args[0].1) {
352 // FIXME: this is not a codepoint
353 Val::Num(s.as_bytes()[0] as f64)
354 } else {
355 panic!("bad codepoint call");
356 }
357 }
358 (ns, name) => panic!("Intristic not found: {}.{}", ns, name),
359 },
290 Val::Func(f) => f.evaluate(360 Val::Func(f) => f.evaluate(
291 args.clone()361 args.clone()
292 .into_iter()362 .into_iter()
modifiedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
20 binding,20 binding,
21 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val21 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val
22);22);
23rc_fn_helper!(
24 LazyBinding,
25 lazy_binding,
26 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> LazyVal
27);
23rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);28rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);
24rc_fn_helper!(29rc_fn_helper!(
25 FunctionDefault,30 FunctionDefault,
39 }44 }
4045
41 macro_rules! eval_stdlib {46 macro_rules! eval_stdlib {
42 ($str: expr) => {47 ($str: expr) => {{
43 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";48 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";
44 evaluate(Context::new(), &parse(&(std + $str)).unwrap())49 evaluate(Context::new(), &parse(&(std + $str)).unwrap())
45 };50 }};
46 }51 }
4752
48 macro_rules! assert_eval {53 macro_rules! assert_eval {
61 )66 )
62 };67 };
63 }68 }
69 macro_rules! assert_json_stdlib {
70 ($str: expr, $out: expr) => {
71 assert_eq!(
72 format!("{}", eval_stdlib!($str)),
73 $out
74 )
75 };
76 }
64 macro_rules! assert_eval_neg {77 macro_rules! assert_eval_neg {
65 ($str: expr) => {78 ($str: expr) => {
66 assert_eq!(79 assert_eq!(
110123
111 #[test]124 #[test]
112 fn object_inheritance() {125 fn object_inheritance() {
113 assert_json!("{a:self.b} + {b:3}", r#"{"a":3,"b":3}"#);126 assert_json!("{a: self.b} + {b:3}", r#"{"a":3,"b":3}"#);
114 }127 }
115128
116 #[test]129 #[test]
192 // `self` assigned to `me` was lost when being205 // `self` assigned to `me` was lost when being
193 // referenced from field206 // referenced from field
194 eval_stdlib!(207 eval_stdlib!(
195 r#"{208 r#"{
196 local me = self,209 local me = self,
197 b: me,210 a: 3,
211 b: me.a,
198 }.b"#212 }.b"#
199 );213 );
200 }214 }
201215
211 eval_stdlib!("std.assertEqual(4.5 << 2, 15)");225 eval_stdlib!("std.assertEqual(4.5 << 2, 15)");
212 }226 }
227
228 #[test]
229 fn string_is_string() {
230 assert_eq!(
231 eval_stdlib!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),
232 Val::Literal(LiteralType::False)
233 );
234 }
213235
214 #[test]236 #[test]
215 fn base64_works() {237 fn base64_works() {
216 eval_stdlib!(r#"std.base64("test")"#);238 assert_json_stdlib!(r#"std.base64("test")"#, r#""dGVzdA==""#);
217 }239 }
218}240}
219241
modifiedcrates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth
70 }70 }
71 pub fn get(&self, key: &str) -> Option<Val> {71 pub fn get(&self, key: &str) -> Option<Val> {
72 // TODO: Cache get_raw result72 // TODO: Cache get_raw result
73 self.get_raw(key, Some(self))73 self.get_raw(key, self)
74 }74 }
75 fn get_raw(&self, key: &str, real_this: Option<&ObjValue>) -> Option<Val> {75 fn get_raw(&self, key: &str, real_this: &ObjValue) -> Option<Val> {
76 match (self.0.this_entries.get(key), &self.0.super_obj) {76 match (self.0.this_entries.get(key), &self.0.super_obj) {
77 (Some(k), None) => Some(k.invoke.0(77 (Some(k), None) => Some(k.invoke.0(
78 real_this.as_ref().map(|e| (*e).clone()),78 Some(real_this.clone()),
79 self.0.super_obj.clone(),79 self.0.super_obj.clone(),
80 )),80 )),
81 (Some(k), Some(s)) => {81 (Some(k), Some(s)) => {
82 let our = k.invoke.0(82 let our = k.invoke.0(
83 real_this.as_ref().map(|e| (*e).clone()),83 Some(real_this.clone()),
84 self.0.super_obj.clone(),84 self.0.super_obj.clone(),
85 );85 );
86 if k.add {86 if k.add {
modifiedcrates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth
1use crate::{binding, rc_fn_helper, Binding, Context, FunctionDefault, FunctionRhs, ObjValue};1use crate::{
2 lazy_binding, rc_fn_helper, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue,
3};
2use closure::closure;4use closure::closure;
3use jsonnet_parser::{LiteralType, ParamsDesc};5use jsonnet_parser::{LiteralType, ParamsDesc};
18impl FuncDesc {20impl FuncDesc {
19 // TODO: Check for unset variables21 // TODO: Check for unset variables
20 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {22 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {
21 let mut new_bindings: HashMap<String, Binding> = HashMap::new();23 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();
22 let future_ctx = Context::new_future();24 let future_ctx = Context::new_future();
2325
24 // self.params26 // self.params
37 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {39 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {
38 new_bindings.insert(40 new_bindings.insert(
39 name.as_ref().unwrap().clone(),41 name.as_ref().unwrap().clone(),
40 binding!(42 lazy_binding!(
41 closure!(clone val, |_, _| Val::Lazy(lazy_val!(closure!(clone val, || val.clone()))))43 closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))
42 ),44 ),
43 );45 );
44 }46 }
45 for (i, param) in self.params.0.iter().enumerate() {47 for (i, param) in self.params.0.iter().enumerate() {
46 if let Some((None, val)) = args.get(i) {48 if let Some((None, val)) = args.get(i) {
47 new_bindings.insert(49 new_bindings.insert(
48 param.0.clone(),50 param.0.clone(),
49 binding!(51 lazy_binding!(
50 closure!(clone val, |_, _| Val::Lazy(lazy_val!(closure!(clone val, || val.clone()))))52 closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))
51 ),53 ),
52 );54 );
53 }55 }