git.delta.rocks / jrsonnet / refs/commits / 067b138a5c9b

difftreelog

chore(evaluator) partial interpreter implementation

Лач2020-05-29parent: #45767d3.patch.diff
in: master

8 files changed

modifiedcrates/jsonnet-evaluator/Cargo.tomldiffbeforeafterboth
9[dependencies]9[dependencies]
10jsonnet-parser = { path = "../jsonnet-parser" }10jsonnet-parser = { path = "../jsonnet-parser" }
11
12[dev-dependencies]
13jsonnet-stdlib = { version = "0.1.0", path = "../jsonnet-stdlib" }
1114
addedcrates/jsonnet-evaluator/src/binding.rsdiffbeforeafterboth

no changes

addedcrates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth

no changes

addedcrates/jsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth

no changes

addedcrates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth

no changes

modifiedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
1#![feature(box_syntax, box_patterns)]1#![feature(box_syntax, box_patterns)]
22#![feature(type_alias_impl_trait)]
3use jsonnet_parser::*;
4
5#[derive(Debug, Clone, PartialEq)]3#![feature(debug_non_exhaustive)]
6pub enum Val {4
7 Str(String),5mod binding;
8 Num(f64),6mod ctx;
9}7mod dynamic;
10
11pub fn evaluate(expr: &Expr) -> Val {8mod evaluate;
9mod obj;
10mod val;
11
12pub use binding::*;
12 use Expr::*;13pub use ctx::*;
13 match expr {14pub use dynamic::*;
14 Parened(e) => evaluate(e),15pub use evaluate::*;
15 Str(v) => Val::Str(v.clone()),16use jsonnet_parser::*;
16 Num(v) => Val::Num(*v),17pub use obj::*;
17 BinaryOp(v1, o, v2) => match (evaluate(v1), o, evaluate(v2)) {18use std::fmt::Debug;
19use std::rc::Rc;
18 (Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1 + &v2),20pub use val::*;
21
22pub trait FunctionRhs: Debug {
19 (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => {23 fn evaluate(&self, ctx: Context) -> Val;
20 Val::Str(v1.repeat(v2 as usize))24}
21 },
22 (Val::Num(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Num(v1 + v2),25dynamic_wrapper!(FunctionRhs, BoxedFunctionRhs);
26
27pub trait FunctionDefault: Debug {
23 (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),28 fn default(&self, ctx: Context, expr: Expr) -> Val;
24 _ => panic!("Can't evaluate binary op: {:?} {:?} {:?}", v1, o, v2),29}
25 },
26 _ => panic!("Can't evaluate: {:?}", expr),30dynamic_wrapper!(FunctionDefault, BoxedFunctionDefault);
27 }
28}
2931
30#[cfg(test)]32#[cfg(test)]
31pub mod tests {33pub mod tests {
32 use super::{evaluate, Val};34 use super::{evaluate, Context, Val};
33 use jsonnet_parser::parse;35 use jsonnet_parser::*;
34 #[test]36
37 // macro_rules! eval {
38 // ($str: expr) => {
39 // evaluate(Context::new(), &parse($str).unwrap())
40 // };
41 // }
35 fn math_evaluation() {42 macro_rules! assert_eval {
43 ($str: expr) => {
36 assert_eq!(evaluate(&parse("2+2*2").unwrap()), Val::Num(6.0));44 assert_eq!(
45 evaluate(Context::new(), &parse($str).unwrap()),
46 Val::Literal(LiteralType::True)
47 )
48 };
37 }49 }
3850 macro_rules! assert_json {
39 #[test]51 ($str: expr, $out: expr) => {
52 assert_eq!(
53 format!("{}", evaluate(Context::new(), &parse($str).unwrap())),
54 $out
55 )
56 };
57 }
40 fn math_evaluation_with_parened() {58 macro_rules! assert_eval_neg {
59 ($str: expr) => {
41 assert_eq!(evaluate(&parse("3+(2+2*2)").unwrap()), Val::Num(9.0));60 assert_eq!(
61 evaluate(Context::new(), &parse($str).unwrap()),
62 Val::Literal(LiteralType::False)
63 )
64 };
42 }65 }
66
67 /// Sanity checking, before trusting to another tests
68 #[test]
69 fn equality_operator() {
70 assert_eval!("2 == 2");
71 assert_eval_neg!("2 != 2");
72 assert_eval!("2 != 3");
73 assert_eval_neg!("2 == 3");
74 assert_eval!("'Hello' == 'Hello'");
75 assert_eval_neg!("'Hello' != 'Hello'");
76 assert_eval!("'Hello' != 'World'");
77 assert_eval_neg!("'Hello' == 'World'");
78 }
4379
44 #[test]80 #[test]
45 fn string_concat() {81 fn math_evaluation() {
46 assert_eq!(82 assert_eval!("2 + 2 * 2 == 6");
83 assert_eval!("3 + (2 + 2 * 2) == 9");
84 }
85
86 #[test]
87 fn string_concat() {
88 assert_eval!("'Hello' + 'World' == 'HelloWorld'");
89 assert_eval!("'Hello' * 3 == 'HelloHelloHello'");
90 assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");
91 }
92
93 #[test]
94 fn local() {
95 assert_eval!("local a = 2; local b = 3; a + b == 5");
96 assert_eval!("local a = 1, b = a + 1; a + b == 3");
97 assert_eval!("local a = 1; local a = 2; a == 2");
98 }
99
100 #[test]
101 fn object_lazyness() {
102 assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);
103 }
104
105 #[test]
106 fn object_inheritance() {
107 assert_json!("{a:self.b} + {b:3}", r#"{"a":3,"b":3}"#);
108 }
109
110 #[test]
111 fn test_object() {
112 assert_json!("{a:2}", r#"{"a":2}"#);
113 assert_json!("{a:2+2}", r#"{"a":4}"#);
114 assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);
115 assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);
116 assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);
117 assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);
118 assert_json!(
119 r#"
120 {
121 name: "Alice",
122 welcome: "Hello " + self.name + "!",
123 }
124 "#,
125 r#"{"name":"Alice","welcome":"Hello Alice!"}"#
126 );
127 assert_json!(
128 r#"
129 {
130 name: "Alice",
131 welcome: "Hello " + self.name + "!",
132 } + {
133 name: "Bob"
134 }
135 "#,
136 r#"{"name":"Bob","welcome":"Hello Bob!"}"#
137 );
138 }
139
140 #[test]
141 fn functions() {
142 assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");
143 assert_json!(
144 r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,
145 r#""HelloDearWorld""#
146 );
147 }
148
149 #[test]
150 fn local_methods() {
151 assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");
152 assert_json!(
153 r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,
154 r#""HelloDearWorld""#
155 );
156 }
157
158 #[test]
159 fn object_locals() {
160 assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);
161 assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);
162 assert_json!(
163 r#"{local a = function (b) {[b]:4}, test: a("test")}"#,
164 r#"{"test":{"test":4}}"#
165 );
166 }
167
168 // We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly
169 #[test]
170 fn std_assert_ok() {
171 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";
47 evaluate(&parse("\"Hello\"+\"World\"").unwrap()),172 evaluate(
48 Val::Str("HelloWorld".to_owned()),173 Context::new(),
174 &parse(&(std + "std.assertEqual(4.5 << 2, 16,)")).unwrap(),
49 );175 );
50 }176 }
51177
52 #[test]178 #[test]
179 #[should_panic]
53 fn string_repeat() {180 fn std_assert_failure() {
54 assert_eq!(181 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";
55 evaluate(&parse("\"Hello\"*3").unwrap()),182 evaluate(
56 Val::Str("HelloHelloHello".to_owned()),183 Context::new(),
184 &parse(&(std + "std.assertEqual(4.5 << 2, 15,)")).unwrap(),
57 );185 );
58 }186 }
59}187}
60188
addedcrates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth

no changes

addedcrates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth

no changes