difftreelog
fix(evaluator) indirect_self bug
in: master
4 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,9 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "closure"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6173fd61b610d15a7566dd7b7620775627441c4ab9dac8906e17cb93a24b782"
+
+[[package]]
name = "jsonnet-evaluator"
version = "0.1.0"
dependencies = [
+ "closure",
"jsonnet-parser",
"jsonnet-stdlib",
]
crates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/ctx.rs
+++ b/crates/jsonnet-evaluator/src/ctx.rs
@@ -74,7 +74,6 @@
new_this: Option<ObjValue>,
new_super_obj: Option<ObjValue>,
) -> Context {
- println!("Extend with {:?} {:?}", new_dollar, new_this);
let dollar = new_dollar.or_else(|| self.0.dollar.clone());
let this = new_this.or_else(|| self.0.this.clone());
let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -29,9 +29,8 @@
} else {
(
b.name.clone(),
- binding!(move |this, super_obj| {
- println!("Evaluating binding");
- Val::Lazy(lazy_val!(
+ binding!(move |this, super_obj| {
+ Val::Lazy(lazy_val!(
closure!(clone context_creator, clone b, || evaluate(
context_creator.0(this.clone(), super_obj.clone()),
&b.value
@@ -137,12 +136,11 @@
let future_bindings = FutureNewBindings::new();
let future_this = FutureObjValue::new();
let context_creator = context_creator!(
- closure!(clone context, clone future_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
- println!("Context created");
+ closure!(clone context, clone future_bindings, clone future_this, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
context.clone().extend(
future_bindings.clone().unwrap(),
context.clone().dollar().clone().or_else(||this.clone()),
- this,
+ Some(future_this.clone().unwrap()),
super_obj
)
})
@@ -154,15 +152,12 @@
Member::BindStmt(b) => Some(b.clone()),
_ => None,
})
- .map(|b| {
- evaluate_binding(&b, context_creator.clone())
- })
+ .map(|b| evaluate_binding(&b, context_creator.clone()))
{
bindings.insert(n, b);
}
future_bindings.fill(bindings);
- println!("Bindings filled");
let mut new_members = BTreeMap::new();
for member in members.into_iter() {
match member {
@@ -180,8 +175,7 @@
add: plus,
visibility: visibility.clone(),
invoke: binding!(
- closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {
- // FIXME: I should take "this" instead of "future_this" there?
+ closure!(clone value, clone context_creator, |this, super_obj| {
// TODO: Assert
evaluate(
context_creator.0(this, super_obj),
@@ -205,8 +199,7 @@
add: false,
visibility: Visibility::Hidden,
invoke: binding!(
- closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {
- // FIXME: I should take "this" instead of "future_this" there?
+ closure!(clone value, clone context_creator, |this, super_obj| {
// TODO: Assert
evaluate_method(
context_creator.0(this, super_obj),
@@ -231,15 +224,12 @@
pub fn evaluate(context: Context, expr: &Expr) -> Val {
use Expr::*;
match &*expr {
- Literal(LiteralType::This) => {
- println!("{:?}", context.this());
- Val::Obj(
- context
- .this()
- .clone()
- .unwrap_or_else(|| panic!("this not found")),
- )
- }
+ Literal(LiteralType::This) => Val::Obj(
+ context
+ .this()
+ .clone()
+ .unwrap_or_else(|| panic!("this not found")),
+ ),
Literal(LiteralType::Super) => Val::Obj(
context
.super_obj()
crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]4#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]5mod ctx;6mod dynamic;7mod evaluate;8mod obj;9mod val;1011pub use ctx::*;12pub use dynamic::*;13pub use evaluate::*;14use jsonnet_parser::*;15pub use obj::*;16pub use val::*;1718rc_fn_helper!(19 Binding,20 binding,21 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val22);23rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);24rc_fn_helper!(25 FunctionDefault,26 function_default,27 dyn Fn(Context, Expr) -> Val28);2930#[cfg(test)]31pub mod tests {32 use super::{evaluate, Context, Val};33 use jsonnet_parser::*;3435 macro_rules! eval {36 ($str: expr) => {37 evaluate(Context::new(), &parse($str).unwrap())38 };39 }4041 macro_rules! eval_stdlib {42 ($str: expr) => {43 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";44 evaluate(Context::new(), &parse(&(std + $str)).unwrap())45 };46 }4748 macro_rules! assert_eval {49 ($str: expr) => {50 assert_eq!(51 evaluate(Context::new(), &parse($str).unwrap()),52 Val::Literal(LiteralType::True)53 )54 };55 }56 macro_rules! assert_json {57 ($str: expr, $out: expr) => {58 assert_eq!(59 format!("{}", evaluate(Context::new(), &parse($str).unwrap())),60 $out61 )62 };63 }64 macro_rules! assert_eval_neg {65 ($str: expr) => {66 assert_eq!(67 evaluate(Context::new(), &parse($str).unwrap()),68 Val::Literal(LiteralType::False)69 )70 };71 }7273 /// Sanity checking, before trusting to another tests74 #[test]75 fn equality_operator() {76 assert_eval!("2 == 2");77 assert_eval_neg!("2 != 2");78 assert_eval!("2 != 3");79 assert_eval_neg!("2 == 3");80 assert_eval!("'Hello' == 'Hello'");81 assert_eval_neg!("'Hello' != 'Hello'");82 assert_eval!("'Hello' != 'World'");83 assert_eval_neg!("'Hello' == 'World'");84 }8586 #[test]87 fn math_evaluation() {88 assert_eval!("2 + 2 * 2 == 6");89 assert_eval!("3 + (2 + 2 * 2) == 9");90 }9192 #[test]93 fn string_concat() {94 assert_eval!("'Hello' + 'World' == 'HelloWorld'");95 assert_eval!("'Hello' * 3 == 'HelloHelloHello'");96 assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");97 }9899 #[test]100 fn local() {101 assert_eval!("local a = 2; local b = 3; a + b == 5");102 assert_eval!("local a = 1, b = a + 1; a + b == 3");103 assert_eval!("local a = 1; local a = 2; a == 2");104 }105106 #[test]107 fn object_lazyness() {108 assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);109 }110111 #[test]112 fn object_inheritance() {113 assert_json!("{a:self.b} + {b:3}", r#"{"a":3,"b":3}"#);114 }115116 #[test]117 fn test_object() {118 assert_json!("{a:2}", r#"{"a":2}"#);119 assert_json!("{a:2+2}", r#"{"a":4}"#);120 assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);121 assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);122 assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);123 assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);124 assert_json!(125 r#"126 {127 name: "Alice",128 welcome: "Hello " + self.name + "!",129 }130 "#,131 r#"{"name":"Alice","welcome":"Hello Alice!"}"#132 );133 assert_json!(134 r#"135 {136 name: "Alice",137 welcome: "Hello " + self.name + "!",138 } + {139 name: "Bob"140 }141 "#,142 r#"{"name":"Bob","welcome":"Hello Bob!"}"#143 );144 }145146 #[test]147 fn functions() {148 assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");149 assert_json!(150 r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,151 r#""HelloDearWorld""#152 );153 }154155 #[test]156 fn local_methods() {157 assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");158 assert_json!(159 r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,160 r#""HelloDearWorld""#161 );162 }163164 #[test]165 fn object_locals() {166 assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);167 assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);168 assert_json!(169 r#"{local a = function (b) {[b]:4}, test: a("test")}"#,170 r#"{"test":{"test":4}}"#171 );172 }173174 #[test]175 fn direct_self() {176 println!(177 "{:#?}",178 eval!(179 r#"180 {181 local me = self,182 a: 3,183 b(): me.a,184 }185 "#186 )187 );188 }189190 #[test]191 fn indirect_self() {192 // `self` assigned to `me` was lost when being193 // referenced from field194 eval_stdlib!(195 r#"{196 local me = std.trace("test", self),197 b: me,198 }.b"#199 );200 }201202 // We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly203 #[test]204 fn std_assert_ok() {205 eval_stdlib!("std.assertEqual(4.5 << 2, 16)");206 }207208 #[test]209 #[should_panic]210 fn std_assert_failure() {211 eval_stdlib!("std.assertEqual(4.5 << 2, 15)");212 }213214 #[test]215 fn base64_works() {216 eval_stdlib!(r#"std.base64("test")"#);217 }218}