1use crate::{2 binding, bool_val, context_creator, function_default, function_rhs, future_wrapper, lazy_val,3 Binding, Context, ContextCreator, FuncDesc, ObjMember, ObjValue, Val,4};5use closure::closure;6use jsonnet_parser::{7 ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, Member, ObjBody, ParamsDesc,8 UnaryOpType, Visibility,9};10use std::{11 collections::{BTreeMap, HashMap},12 rc::Rc,13};1415pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (String, Binding) {16 let b = b.clone();17 if let Some(args) = &b.params {18 let args = args.clone();19 (20 b.name.clone(),21 binding!(move |this, super_obj| Val::Lazy(lazy_val!(22 closure!(clone b, clone args, clone context_creator, || evaluate_method(23 context_creator.0(this.clone(), super_obj.clone()),24 &b.value,25 args.clone()26 ))27 ))),28 )29 } else {30 (31 b.name.clone(),32 binding!(move |this, super_obj| {33 Val::Lazy(lazy_val!(34 closure!(clone context_creator, clone b, || evaluate(35 context_creator.0(this.clone(), super_obj.clone()),36 &b.value37 ))38 ))39 }),40 )41 }42}4344pub fn evaluate_method(ctx: Context, expr: &Expr, arg_spec: ParamsDesc) -> Val {45 Val::Func(FuncDesc {46 ctx,47 params: arg_spec,48 eval_rhs: function_rhs!(closure!(clone expr, |ctx| evaluate(ctx, &expr))),49 eval_default: function_default!(|ctx, default| evaluate(ctx, &default)),50 })51}5253pub fn evaluate_field_name(context: Context, field_name: &jsonnet_parser::FieldName) -> String {54 match field_name {55 jsonnet_parser::FieldName::Fixed(n) => n.clone(),56 jsonnet_parser::FieldName::Dyn(expr) => {57 let name = evaluate(context, expr).unwrap_if_lazy();58 match name {59 Val::Str(n) => n,60 _ => panic!(61 "dynamic field name can be only evaluated to 'string', got: {:?}",62 name63 ),64 }65 }66 }67}6869pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Val {70 match (op, b) {71 (o, Val::Lazy(l)) => evaluate_unary_op(o, &l.0()),72 (UnaryOpType::Not, Val::Literal(LiteralType::True)) => Val::Literal(LiteralType::False),73 (UnaryOpType::Not, Val::Literal(LiteralType::False)) => Val::Literal(LiteralType::True),74 (op, o) => panic!("unary op not implemented: {:?} {:?}", op, o),75 }76}7778pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {79 match (a, op, b) {80 (Val::Lazy(a), o, b) => evaluate_binary_op(&a.0(), o, b),81 (a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.0()),8283 (Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),84 (Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => bool_val(v1 == v2),85 (Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => bool_val(v1 != v2),8687 (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)),8990 (Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),9192 (Val::Arr(a), BinaryOpType::Add, Val::Arr(b)) => Val::Arr([&a[..], &b[..]].concat()),9394 (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),95 (Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => Val::Num(v1 / v2),96 (Val::Num(v1), BinaryOpType::Mod, Val::Num(v2)) => Val::Num(v1 % v2),9798 (Val::Num(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Num(v1 + v2),99 (Val::Num(v1), BinaryOpType::Sub, Val::Num(v2)) => Val::Num(v1 - v2),100101 (Val::Num(v1), BinaryOpType::Lhs, Val::Num(v2)) => {102 Val::Num(((*v1 as i32) << (*v2 as i32)) as f64)103 }104 (Val::Num(v1), BinaryOpType::Rhs, Val::Num(v2)) => {105 Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64)106 }107108 (Val::Num(v1), BinaryOpType::Lt, Val::Num(v2)) => bool_val(v1 < v2),109 (Val::Num(v1), BinaryOpType::Gt, Val::Num(v2)) => bool_val(v1 > v2),110 (Val::Num(v1), BinaryOpType::Lte, Val::Num(v2)) => bool_val(v1 <= v2),111 (Val::Num(v1), BinaryOpType::Gte, Val::Num(v2)) => bool_val(v1 >= v2),112113 (Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => bool_val((v1 - v2).abs() < f64::EPSILON),114 (Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => bool_val((v1 - v2).abs() > f64::EPSILON),115116 (Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => {117 Val::Num(((*v1 as i32) & (*v2 as i32)) as f64)118 }119 (Val::Num(v1), BinaryOpType::BitOr, Val::Num(v2)) => {120 Val::Num(((*v1 as i32) | (*v2 as i32)) as f64)121 }122 (Val::Num(v1), BinaryOpType::BitXor, Val::Num(v2)) => {123 Val::Num(((*v1 as i32) ^ (*v2 as i32)) as f64)124 }125 _ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b),126 }127}128129future_wrapper!(HashMap<String, Binding>, FutureNewBindings);130future_wrapper!(ObjValue, FutureObjValue);131132133pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {134 match object {135 ObjBody::MemberList(members) => {136 let future_bindings = FutureNewBindings::new();137 let future_this = FutureObjValue::new();138 let context_creator = context_creator!(139 closure!(clone context, clone future_bindings, clone future_this, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {140 context.clone().extend(141 future_bindings.clone().unwrap(),142 context.clone().dollar().clone().or_else(||this.clone()),143 Some(future_this.clone().unwrap()),144 super_obj145 )146 })147 );148 let mut bindings: HashMap<String, Binding> = HashMap::new();149 for (n, b) in members150 .iter()151 .filter_map(|m| match m {152 Member::BindStmt(b) => Some(b.clone()),153 _ => None,154 })155 .map(|b| evaluate_binding(&b, context_creator.clone()))156 {157 bindings.insert(n, b);158 }159 future_bindings.fill(bindings);160161 let mut new_members = BTreeMap::new();162 for member in members.into_iter() {163 match member {164 Member::Field(FieldMember {165 name,166 plus,167 params: None,168 visibility,169 value,170 }) => {171 let name = evaluate_field_name(context.clone(), &name);172 new_members.insert(173 name,174 ObjMember {175 add: plus,176 visibility: visibility.clone(),177 invoke: binding!(178 closure!(clone value, clone context_creator, |this, super_obj| {179 180 evaluate(181 context_creator.0(this, super_obj),182 &value,183 )184 })185 ),186 },187 );188 }189 Member::Field(FieldMember {190 name,191 params: Some(params),192 value,193 ..194 }) => {195 let name = evaluate_field_name(context.clone(), &name);196 new_members.insert(197 name,198 ObjMember {199 add: false,200 visibility: Visibility::Hidden,201 invoke: binding!(202 closure!(clone value, clone context_creator, |this, super_obj| {203 204 evaluate_method(205 context_creator.0(this, super_obj),206 &value.clone(),207 params.clone(),208 )209 })210 ),211 },212 );213 }214 Member::BindStmt(_) => {}215 Member::AssertStmt(_) => {}216 }217 }218 future_this.fill(ObjValue::new(None, Rc::new(new_members)))219 }220 _ => todo!(),221 }222}223224pub fn evaluate(context: Context, expr: &Expr) -> Val {225 use Expr::*;226 match &*expr {227 Literal(LiteralType::This) => Val::Obj(228 context229 .this()230 .clone()231 .unwrap_or_else(|| panic!("this not found")),232 ),233 Literal(LiteralType::Super) => Val::Obj(234 context235 .super_obj()236 .clone()237 .unwrap_or_else(|| panic!("super not found")),238 ),239 Literal(t) => Val::Literal(t.clone()),240 Parened(e) => evaluate(context, e),241 Str(v) => Val::Str(v.clone()),242 Num(v) => Val::Num(*v),243 BinaryOp(v1, o, v2) => {244 evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))245 }246 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)),247 Var(name) => {248 let variable = context.binding(&name);249 variable.0(None, None).unwrap_if_lazy()250 }251 Index(box value, box index) => {252 match (253 evaluate(context.clone(), value).unwrap_if_lazy(),254 evaluate(context, index),255 ) {256 (Val::Obj(v), Val::Str(s)) => v257 .get(&s)258 .unwrap_or_else(|| panic!("{} not found in {:?}", s, v)),259 (Val::Arr(v), Val::Num(n)) => v260 .get(n as usize)261 .unwrap_or_else(|| panic!("out of bounds"))262 .clone(),263 (v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),264 }265 }266 LocalExpr(bindings, returned) => {267 let mut new_bindings: HashMap<String, Binding> = HashMap::new();268 let future_context = Context::new_future();269270 let context_creator = context_creator!(271 closure!(clone future_context, |_, _| future_context.clone().unwrap())272 );273274 for (k, v) in bindings275 .iter()276 .map(move |b| evaluate_binding(b, context_creator.clone()))277 {278 new_bindings.insert(k, v);279 }280281 let context = context282 .extend(new_bindings, None, None, None)283 .into_future(future_context);284 evaluate(context, &*returned.clone())285 }286 Obj(body) => Val::Obj(evaluate_object(context, body.clone())),287 Apply(box value, ArgsDesc(args)) => {288 let value = evaluate(context.clone(), value).unwrap_if_lazy();289 match value {290 Val::Func(f) => f.evaluate(291 args.clone()292 .into_iter()293 .map(|a| {294 (295 a.clone().0,296 Val::Lazy(lazy_val!(297 closure!(clone context, clone a, || evaluate(context.clone(), &a.clone().1))298 )),299 )300 })301 .collect(),302 ),303 _ => panic!("{:?} is not a function", value),304 }305 }306 Function(params, body) => evaluate_method(context, body, params.clone()),307 Error(e) => panic!("error: {}", evaluate(context, e)),308 IfElse {309 cond,310 cond_then,311 cond_else,312 } => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {313 Val::Literal(LiteralType::True) => evaluate(context, cond_then),314 Val::Literal(LiteralType::False) => match cond_else {315 Some(v) => evaluate(context, v),316 None => Val::Literal(LiteralType::False),317 },318 v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),319 },320 _ => panic!("evaluation not implemented: {:?}", expr),321 }322}