--- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -5,7 +5,7 @@ use jsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParserSettings}; use location::{offset_to_location, CodeLocation}; use std::env::current_dir; -use std::{collections::HashMap, path::PathBuf, str::FromStr}; +use std::{collections::HashMap, path::PathBuf, str::FromStr, rc::Rc}; enum Format { None, @@ -128,10 +128,10 @@ evaluator.with_stdlib(); } for ExtStr { name, value } in opts.ext_str.iter().cloned() { - evaluator.add_ext_var(name, Val::Str(value)); + evaluator.add_ext_var(name.into(), Val::Str(value.into())); } for ExtStr { name, value } in opts.ext_code.iter().cloned() { - evaluator.add_ext_var(name, evaluator.parse_evaluate_raw(&value).unwrap()); + evaluator.add_ext_var(name.into(), evaluator.parse_evaluate_raw(&value).unwrap()); } let mut input = current_dir().unwrap(); input.push(opts.input.clone()); @@ -147,7 +147,7 @@ Val::Func(f) => { let mut desc_map = HashMap::new(); for ExtStr { name, value } in opts.tla_str.iter().cloned() { - desc_map.insert(name, el!(Expr::Str(value))); + desc_map.insert(name, el!(Expr::Str(value.into()))); } for ExtStr { name, value } in opts.tla_code.iter().cloned() { desc_map.insert( @@ -155,17 +155,17 @@ jsonnet_parser::parse( &value, &ParserSettings { - file_name: PathBuf::new(), + file_name: Rc::new(PathBuf::new()), loc_data: false, }, ) .unwrap(), ); } - evaluator.add_global("__tmp__tlf__".to_owned(), Val::Func(f)); + evaluator.add_global("__tmp__tlf__".into(), Val::Func(f)); evaluator .evaluate_raw(el!(Expr::Apply( - el!(Expr::Var("__tmp__tlf__".to_owned())), + el!(Expr::Var("__tmp__tlf__".into())), ArgsDesc(desc_map.into_iter().map(|(k, v)| Arg(Some(k), v)).collect()), false, ))) @@ -178,7 +178,7 @@ if opts.no_stdlib { evaluator.with_stdlib(); } - evaluator.add_global("__tmp__to_json__".to_owned(), v); + evaluator.add_global("__tmp__to_json__".into(), v); let v = evaluator.parse_evaluate_raw(&format!( "std.manifestJsonEx(__tmp__to_json__, \"{}\")", " ".repeat(opts.line_padding), @@ -195,7 +195,7 @@ if opts.no_stdlib { evaluator.with_stdlib(); } - evaluator.add_global("__tmp__to_yaml__".to_owned(), v); + evaluator.add_global("__tmp__to_yaml__".into(), v); let v = evaluator .parse_evaluate_raw("std.manifestYamlDoc(__tmp__to_yaml__, \" \")"); match v { --- a/crates/jsonnet-evaluator/build.rs +++ b/crates/jsonnet-evaluator/build.rs @@ -34,7 +34,7 @@ Member::Field(FieldMember { name: FieldName::Fixed(name), .. - }) if name == "join" + }) if **name == *"join" ) }) .collect(), --- a/crates/jsonnet-evaluator/src/ctx.rs +++ b/crates/jsonnet-evaluator/src/ctx.rs @@ -16,7 +16,7 @@ dollar: Option, this: Option, super_obj: Option, - bindings: LayeredHashMap, + bindings: LayeredHashMap, LazyVal>, } pub struct Context(Rc); impl Debug for Context { @@ -53,9 +53,9 @@ })) } - pub fn binding(&self, name: &str) -> Result { - self.0.bindings.get(name).cloned().ok_or_else(|| { - create_error::<()>(Error::UnknownVariable(name.to_owned())) + pub fn binding(&self, name: Rc) -> Result { + self.0.bindings.get(&name).cloned().ok_or_else(|| { + create_error::<()>(Error::UnknownVariable(name)) .err() .unwrap() }) @@ -67,7 +67,7 @@ ctx.unwrap() } - pub fn with_var(&self, name: String, value: Val) -> Result { + pub fn with_var(&self, name: Rc, value: Val) -> Result { let mut new_bindings = HashMap::with_capacity(1); new_bindings.insert(name, resolved_lazy_val!(value)); self.extend(new_bindings, None, None, None) @@ -75,7 +75,7 @@ pub fn extend( &self, - new_bindings: HashMap, + new_bindings: HashMap, LazyVal>, new_dollar: Option, new_this: Option, new_super_obj: Option, @@ -97,7 +97,7 @@ } pub fn extend_unbound( &self, - new_bindings: HashMap, + new_bindings: HashMap, LazyBinding>, new_dollar: Option, new_this: Option, new_super_obj: Option, --- a/crates/jsonnet-evaluator/src/error.rs +++ b/crates/jsonnet-evaluator/src/error.rs @@ -6,20 +6,20 @@ pub enum Error { VariableIsNotDefined(String), TypeMismatch(&'static str, Vec, ValType), - NoSuchField(String), + NoSuchField(Rc), - UnknownVariable(String), + UnknownVariable(Rc), UnknownFunctionParameter(String), - BindingParameterASecondTime(String), + BindingParameterASecondTime(Rc), TooManyArgsFunctionHas(usize), - FunctionParameterNotBoundInCall(String), + FunctionParameterNotBoundInCall(Rc), - UndefinedExternalVariable(String), + UndefinedExternalVariable(Rc), FieldMustBeStringGot(ValType), - AttemptedIndexAnArrayWithString(String), + AttemptedIndexAnArrayWithString(Rc), ValueIndexMustBeTypeGot(ValType, ValType, ValType), CantIndexInto(ValType), @@ -31,7 +31,7 @@ ImportNotSupported(PathBuf, PathBuf), ImportSyntaxError(jsonnet_parser::ParseError), - RuntimeError(String), + RuntimeError(Rc), StackOverflow, FractionalIndex, DivisionByZero, --- a/crates/jsonnet-evaluator/src/evaluate.rs +++ b/crates/jsonnet-evaluator/src/evaluate.rs @@ -14,7 +14,7 @@ rc::Rc, }; -pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (String, LazyBinding) { +pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (Rc, LazyBinding) { let b = b.clone(); if let Some(params) = &b.params { let params = params.clone(); @@ -54,11 +54,12 @@ pub fn evaluate_field_name( context: Context, field_name: &jsonnet_parser::FieldName, -) -> Result> { +) -> Result>> { Ok(match field_name { jsonnet_parser::FieldName::Fixed(n) => Some(n.clone()), jsonnet_parser::FieldName::Dyn(expr) => { - let value = evaluate(context, expr)?.unwrap_if_lazy()?; + let lazy = evaluate(context, expr)?; + let value = lazy.unwrap_if_lazy()?; if matches!(value, Val::Null) { None } else { @@ -80,17 +81,17 @@ pub(crate) fn evaluate_add_op(a: &Val, b: &Val) -> Result { Ok(match (a, b) { - (Val::Str(v1), Val::Str(v2)) => Val::Str(v1.to_owned() + &v2), + (Val::Str(v1), Val::Str(v2)) => Val::Str(((**v1).to_owned() + &v2).into()), // Can't use generic json serialization way, because it depends on number to string concatenation (std.jsonnet:890) - (Val::Num(n), Val::Str(o)) => Val::Str(format!("{}{}", n, o)), - (Val::Str(o), Val::Num(n)) => Val::Str(format!("{}{}", o, n)), + (Val::Num(n), Val::Str(o)) => Val::Str(format!("{}{}", n, o).into()), + (Val::Str(o), Val::Num(n)) => Val::Str(format!("{}{}", o, n).into()), - (Val::Str(s), o) => Val::Str(format!("{}{}", s, o.clone().into_json(0)?)), - (o, Val::Str(s)) => Val::Str(format!("{}{}", o.clone().into_json(0)?, s)), + (Val::Str(s), o) => Val::Str(format!("{}{}", s, o.clone().into_json(0)?).into()), + (o, Val::Str(s)) => Val::Str(format!("{}{}", o.clone().into_json(0)?, s).into()), (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())), - (Val::Arr(a), Val::Arr(b)) => Val::Arr([&a[..], &b[..]].concat()), + (Val::Arr(a), Val::Arr(b)) => Val::Arr(Rc::new([&a[..], &b[..]].concat())), (Val::Num(v1), Val::Num(v2)) => Val::Num(v1 + v2), _ => panic!("can't add: {:?} and {:?}", a, b), }) @@ -117,7 +118,7 @@ Ok(match (a, op, b) { (a, BinaryOpType::Add, b) => evaluate_add_op(a, b)?, - (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)), + (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize).into()), // Bool X Bool (Val::Bool(a), BinaryOpType::And, Val::Bool(b)) => Val::Bool(*a && *b), @@ -165,7 +166,7 @@ }) } -future_wrapper!(HashMap, FutureNewBindings); +future_wrapper!(HashMap, LazyBinding>, FutureNewBindings); future_wrapper!(ObjValue, FutureObjValue); pub fn evaluate_comp( @@ -186,10 +187,10 @@ match evaluate(context.clone(), &expr)?.unwrap_if_lazy()? { Val::Arr(list) => { let mut out = Vec::new(); - for item in list { - let item = item.clone().unwrap_if_lazy()?; + for item in list.iter() { + let item = item.unwrap_if_lazy()?; out.push(evaluate_comp( - context.with_var(var.clone(), item)?, + context.with_var(var.clone(), item.clone())?, value, &specs[1..], )?); @@ -202,113 +203,108 @@ }) } -// TODO: Asserts -pub fn evaluate_object(context: Context, object: ObjBody) -> Result { - Ok(match object { - ObjBody::MemberList(members) => { - let new_bindings = FutureNewBindings::new(); - let future_this = FutureObjValue::new(); - let context_creator = context_creator!( - closure!(clone context, clone new_bindings, |this: Option, super_obj: Option| { - Ok(context.extend_unbound( - new_bindings.clone().unwrap(), - context.dollar().clone().or_else(||this.clone()), - Some(this.unwrap()), - super_obj - )?) - }) - ); - { - let mut bindings: HashMap = HashMap::new(); - for (n, b) in members - .iter() - .filter_map(|m| match m { - Member::BindStmt(b) => Some(b.clone()), - _ => None, - }) - .map(|b| evaluate_binding(&b, context_creator.clone())) - { - bindings.insert(n, b); +pub fn evaluate_member_list_object(context: Context, members: &Vec) -> Result { + let new_bindings = FutureNewBindings::new(); + let future_this = FutureObjValue::new(); + let context_creator = context_creator!( + closure!(clone context, clone new_bindings, |this: Option, super_obj: Option| { + Ok(context.extend_unbound( + new_bindings.clone().unwrap(), + context.dollar().clone().or_else(||this.clone()), + Some(this.unwrap()), + super_obj + )?) + }) + ); + { + let mut bindings: HashMap, LazyBinding> = HashMap::new(); + for (n, b) in members + .iter() + .filter_map(|m| match m { + Member::BindStmt(b) => Some(b.clone()), + _ => None, + }) + .map(|b| evaluate_binding(&b, context_creator.clone())) + { + bindings.insert(n, b); + } + new_bindings.fill(bindings); + } + + let mut new_members = BTreeMap::new(); + for member in members.iter() { + match member { + Member::Field(FieldMember { + name, + plus, + params: None, + visibility, + value, + }) => { + let name = evaluate_field_name(context.clone(), &name)?; + if name.is_none() { + continue; } - new_bindings.fill(bindings); + let name = name.unwrap(); + new_members.insert( + name.clone(), + ObjMember { + add: *plus, + visibility: *visibility, + invoke: LazyBinding::Bindable(Rc::new( + closure!(clone name, clone value, clone context_creator, |this, super_obj| { + Ok(LazyVal::new_resolved(push(&value.1, "object field", ||{ + let context = context_creator.0(this, super_obj)?; + evaluate( + context, + &value, + ) + })?)) + }), + )), + }, + ); } - - let mut new_members = BTreeMap::new(); - for member in members.into_iter() { - match member { - Member::Field(FieldMember { - name, - plus, - params: None, - visibility, - value, - }) => { - let name = evaluate_field_name(context.clone(), &name)?; - if name.is_none() { - continue; - } - let name = name.unwrap(); - new_members.insert( - name.clone(), - ObjMember { - add: plus, - visibility: visibility.clone(), - invoke: LazyBinding::Bindable(Rc::new( - closure!(clone name, clone value, clone context_creator, |this, super_obj| { - Ok(LazyVal::new_resolved(push(&value.1, "object field", ||{ - let context = context_creator.0(this, super_obj)?; - evaluate( - context, - &value, - )?.unwrap_if_lazy() - })?)) - }), - )), - }, - ); - } - Member::Field(FieldMember { - name, - params: Some(params), - value, - .. - }) => { - let name = evaluate_field_name(context.clone(), &name)?; - if name.is_none() { - continue; - } - let name = name.unwrap(); - new_members.insert( - name, - ObjMember { - add: false, - visibility: Visibility::Hidden, - invoke: LazyBinding::Bindable(Rc::new( - closure!(clone value, clone context_creator, |this, super_obj| { - // TODO: Assert - Ok(LazyVal::new_resolved(evaluate_method( - context_creator.0(this, super_obj)?, - params.clone(), - value.clone(), - ))) - }), - )), - }, - ); - } - Member::BindStmt(_) => {} - Member::AssertStmt(_) => {} + Member::Field(FieldMember { + name, + params: Some(params), + value, + .. + }) => { + let name = evaluate_field_name(context.clone(), &name)?; + if name.is_none() { + continue; } + let name = name.unwrap(); + new_members.insert( + name, + ObjMember { + add: false, + visibility: Visibility::Hidden, + invoke: LazyBinding::Bindable(Rc::new( + closure!(clone value, clone context_creator, clone params, |this, super_obj| { + // TODO: Assert + Ok(LazyVal::new_resolved(evaluate_method( + context_creator.0(this, super_obj)?, + params.clone(), + value.clone(), + ))) + }), + )), + }, + ); } - future_this.fill(ObjValue::new(None, Rc::new(new_members))) + Member::BindStmt(_) => {} + Member::AssertStmt(_) => {} } - ObjBody::ObjComp { - pre_locals, - key, - value, - post_locals, - compspecs, - } => { + } + Ok(future_this.fill(ObjValue::new(None, Rc::new(new_members)))) +} + +pub fn evaluate_object(context: Context, object: &ObjBody) -> Result { + Ok(match object { + ObjBody::MemberList(members) => evaluate_member_list_object(context, &members)?, + ObjBody::ObjComp(obj) => { let future_this = FutureObjValue::new(); let mut new_members = BTreeMap::new(); for (k, v) in evaluate_comp( @@ -325,26 +321,27 @@ )?) }) ); - let mut bindings: HashMap = HashMap::new(); - for (n, b) in pre_locals + let mut bindings: HashMap, LazyBinding> = HashMap::new(); + for (n, b) in obj + .pre_locals .iter() - .chain(post_locals.iter()) + .chain(obj.post_locals.iter()) .map(|b| evaluate_binding(b, context_creator.clone())) { bindings.insert(n, b); } let bindings = new_bindings.fill(bindings); let ctx = ctx.extend_unbound(bindings, None, None, None)?; - let key = evaluate(ctx.clone(), &key)?; + let key = evaluate(ctx.clone(), &obj.key)?; let value = LazyBinding::Bindable(Rc::new( - closure!(clone ctx, clone value, |this, _super_obj| { + closure!(clone ctx, clone obj.value, |this, _super_obj| { Ok(LazyVal::new_resolved(evaluate(ctx.extend(HashMap::new(), None, this, None)?, &value)?)) }), )); Ok((key, value)) }, - &compspecs, + &obj.compspecs, )? .unwrap() { @@ -394,7 +391,7 @@ BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?, UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?, Var(name) => push(loc, "var", || { - Val::Lazy(context.binding(&name)?).unwrap_if_lazy() + Ok(Val::Lazy(context.binding(name.clone())?).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")?; @@ -411,9 +408,9 @@ evaluate(context, index)?, ) { (Val::Obj(v), Val::Str(s)) => { - if let Some(v) = v.get(&s)? { + if let Some(v) = v.get(s.clone())? { v.unwrap_if_lazy()? - } else if let Some(Val::Str(n)) = v.get("__intristic_namespace__")? { + } else if let Some(Val::Str(n)) = v.get("__intristic_namespace__".into())? { Val::Intristic(n, s) } else { create_error(crate::Error::NoSuchField(s))? @@ -443,9 +440,13 @@ n.value_type()?, ))?, - (Val::Str(s), Val::Num(n)) => { - Val::Str(s.chars().skip(n as usize).take(1).collect()) - } + (Val::Str(s), Val::Num(n)) => Val::Str( + s.chars() + .skip(n as usize) + .take(1) + .collect::() + .into(), + ), (Val::Str(_), n) => create_error(crate::Error::ValueIndexMustBeTypeGot( ValType::Str, ValType::Num, @@ -456,7 +457,7 @@ } } LocalExpr(bindings, returned) => { - let mut new_bindings: HashMap = HashMap::new(); + let mut new_bindings: HashMap, LazyBinding> = HashMap::new(); let future_context = Context::new_future(); let context_creator = context_creator!( @@ -484,19 +485,20 @@ }) ))); } - Val::Arr(out) + Val::Arr(Rc::new(out)) } ArrComp(expr, compspecs) => Val::Arr( // First compspec should be forspec, so no "None" possible here - evaluate_comp(context, &|ctx| evaluate(ctx, expr), compspecs)?.unwrap(), + Rc::new(evaluate_comp(context, &|ctx| evaluate(ctx, expr), compspecs)?.unwrap()), ), - Obj(body) => Val::Obj(evaluate_object(context, body.clone())?), + Obj(body) => Val::Obj(evaluate_object(context, body)?), ObjExtend(s, t) => evaluate_add_op( &evaluate(context.clone(), s)?, - &Val::Obj(evaluate_object(context, t.clone())?), + &Val::Obj(evaluate_object(context, t)?), )?, Apply(value, args, tailstrict) => { - let value = evaluate(context.clone(), value)?.unwrap_if_lazy()?; + let lazy = evaluate(context.clone(), value)?; + let value = lazy.unwrap_if_lazy()?; match value { Val::Intristic(ns, name) => match (&ns as &str, &name as &str) { // arr/string/function @@ -519,7 +521,7 @@ ("std", "type") => { assert_eq!(args.len(), 1); let expr = &args.get(0).unwrap().1; - Val::Str(evaluate(context, expr)?.value_type()?.name().to_owned()) + Val::Str(evaluate(context, expr)?.value_type()?.name().into()) } // length, idx=>any ("std", "makeArray") => { @@ -532,14 +534,14 @@ let mut out = Vec::with_capacity(v as usize); for i in 0..v as usize { let call_ctx = - Context::new().with_var("v".to_owned(), Val::Num(i as f64))?; + Context::new().with_var("v".into(), Val::Num(i as f64))?; out.push(d.evaluate( call_ctx, - &ArgsDesc(vec![Arg(None, el!(Expr::Var("v".to_owned())))]), + &ArgsDesc(vec![Arg(None, el!(Expr::Var("v".into())))]), true, )?) } - Val::Arr(out) + Val::Arr(Rc::new(out)) } else { panic!("bad makeArray call"); } @@ -564,13 +566,13 @@ evaluate(context.clone(), &args[0].1)?, evaluate(context, &args[1].1)?, ) { - Val::Arr( + Val::Arr(Rc::new( body.fields_visibility() .into_iter() .filter(|(_k, v)| *v || include_hidden) .map(|(k, _v)| Val::Str(k)) .collect(), - ) + )) } else { panic!("bad objectFieldsEx call"); } @@ -587,7 +589,7 @@ body.fields_visibility() .into_iter() .filter(|(_k, v)| *v || include_hidden) - .any(|(k, _v)| k == name), + .any(|(k, _v)| *k == *name), ) } else { panic!("bad objectHasEx call"); @@ -664,8 +666,8 @@ evaluate(context.clone(), &args[0].1)?, evaluate(context.clone(), &args[1].1)?, ) { - Val::Arr( - arr.into_iter() + Val::Arr(Rc::new( + arr.iter() .filter(|e| { predicate .evaluate_values(context.clone(), &[e.clone()]) @@ -673,8 +675,9 @@ .try_cast_bool("filter predicate") .unwrap() }) + .cloned() .collect(), - ) + )) } else { panic!("bad filter call"); } @@ -682,33 +685,35 @@ // faster ("std", "join") => { assert_eq!(args.len(), 2); - let joiner = evaluate(context.clone(), &args[0].1)?.unwrap_if_lazy()?; - let items = evaluate(context, &args[1].1)?.unwrap_if_lazy()?; - match (joiner, items) { + let joiner = evaluate(context.clone(), &args[0].1)?; + let items = evaluate(context, &args[1].1)?; + match (joiner.unwrap_if_lazy()?, items.unwrap_if_lazy()?) { (Val::Arr(joiner_items), Val::Arr(items)) => { // TODO: Minimal size should be known let mut out = Vec::new(); let mut first = true; - for item in items { + for item in items.iter().cloned() { if let Val::Arr(items) = item.unwrap_if_lazy()? { if !first { + out.reserve(joiner_items.len()); out.extend(joiner_items.iter().cloned()); } first = false; - out.extend(items); + out.reserve(items.len()); + out.extend(items.iter().cloned()); } else { panic!("all array items should be arrays") } } - Val::Arr(out) + Val::Arr(Rc::new(out)) } (Val::Str(joiner), Val::Arr(items)) => { let mut out = String::new(); let mut first = true; - for item in items { + for item in items.iter().cloned() { if let Val::Str(item) = item.unwrap_if_lazy()? { if !first { out += &joiner; @@ -720,7 +725,7 @@ } } - Val::Str(out) + Val::Str(out.into()) } (joiner, items) => panic!("bad join call: {:?} {:?}", joiner, items), } @@ -776,20 +781,20 @@ } } Import(path) => { - let mut import_location = loc + let mut tmp = loc .clone() .expect("imports can't be used without loc_data") - .0 - .clone(); + .0; + let import_location = Rc::make_mut(&mut tmp); import_location.pop(); with_state(|s| s.import_file(&import_location, path))? } ImportStr(path) => { - let mut import_location = loc + let mut tmp = loc .clone() .expect("imports can't be used without loc_data") - .0 - .clone(); + .0; + let import_location = Rc::make_mut(&mut tmp); import_location.pop(); Val::Str(with_state(|s| s.import_file_str(&import_location, path))?) } --- a/crates/jsonnet-evaluator/src/function.rs +++ b/crates/jsonnet-evaluator/src/function.rs @@ -35,7 +35,7 @@ let mut positioned_args = vec![None; params.0.len()]; for (id, arg) in args.iter().enumerate() { let idx = if let Some(name) = &arg.0 { - params.iter().position(|p| &p.0 == name).ok_or_else(|| { + params.iter().position(|p| *p.0 == *name).ok_or_else(|| { create_error::<()>(Error::UnknownFunctionParameter(name.clone())) .err() .unwrap() --- a/crates/jsonnet-evaluator/src/lib.rs +++ b/crates/jsonnet-evaluator/src/lib.rs @@ -65,11 +65,11 @@ /// Contains file source codes and evaluated results for imports and pretty /// printing stacktraces files: RefCell>, - str_files: RefCell>, - globals: RefCell>, + str_files: RefCell>>, + globals: RefCell, Val>>, /// Values to use with std.extVar - ext_vars: RefCell>, + ext_vars: RefCell, Val>>, settings: EvaluationSettings, import_resolver: Box, @@ -87,7 +87,7 @@ with_state(|s| s.error(err)) } pub(crate) fn push( - e: &Option>, + e: &Option, comment: &str, f: impl FnOnce() -> Result, ) -> Result { @@ -185,11 +185,14 @@ })?; self.evaluate_file(&file_path) } - pub(crate) fn import_file_str(&self, from: &PathBuf, path: &PathBuf) -> Result { + pub(crate) fn import_file_str(&self, from: &PathBuf, path: &PathBuf) -> Result> { let path = self.0.import_resolver.resolve_file(from, path)?; if !self.0.str_files.borrow().contains_key(&path) { let file_str = self.0.import_resolver.load_file_contents(&path)?; - self.0.str_files.borrow_mut().insert(path.clone(), file_str); + self.0 + .str_files + .borrow_mut() + .insert(path.clone(), file_str.into()); } Ok(self.0.str_files.borrow().get(&path).cloned().unwrap()) } @@ -210,10 +213,10 @@ self.run_in_state(|| evaluate(self.create_default_context()?, &code)) } - pub fn add_global(&self, name: String, value: Val) { + pub fn add_global(&self, name: Rc, value: Val) { self.0.globals.borrow_mut().insert(name, value); } - pub fn add_ext_var(&self, name: String, value: Val) { + pub fn add_ext_var(&self, name: Rc, value: Val) { self.0.ext_vars.borrow_mut().insert(name, value); } @@ -236,14 +239,14 @@ .unwrap(); } let val = self.evaluate_file(&PathBuf::from("std.jsonnet")).unwrap(); - self.add_global("std".to_owned(), val); + self.add_global("std".into(), val); }); self } pub fn create_default_context(&self) -> Result { let globals = self.0.globals.borrow(); - let mut new_bindings: HashMap = HashMap::new(); + let mut new_bindings: HashMap, LazyBinding> = HashMap::new(); for (name, value) in globals.iter() { new_bindings.insert( name.clone(), @@ -255,7 +258,7 @@ pub fn push( &self, - e: Rc, + e: ExprLocation, comment: String, f: impl FnOnce() -> Result, ) -> Result { @@ -362,7 +365,7 @@ let evaluator = EvaluationState::default(); evaluator.with_stdlib(); let val = evaluator.parse_evaluate_raw($str).unwrap(); - evaluator.add_global("__tmp__to_yaml__".to_owned(), val); + evaluator.add_global("__tmp__to_yaml__".into(), val); evaluator .parse_evaluate_raw("std.manifestJsonEx(__tmp__to_yaml__, \"\")") .unwrap() --- a/crates/jsonnet-evaluator/src/obj.rs +++ b/crates/jsonnet-evaluator/src/obj.rs @@ -18,9 +18,10 @@ #[derive(Debug)] pub struct ObjValueInternals { super_obj: Option, - this_entries: Rc>, - value_cache: RefCell>, + this_entries: Rc, ObjMember>>, + value_cache: RefCell, Val>>, } +#[derive(Clone)] pub struct ObjValue(pub(crate) Rc); impl Debug for ObjValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -43,7 +44,7 @@ impl ObjValue { pub fn new( super_obj: Option, - this_entries: Rc>, + this_entries: Rc, ObjMember>>, ) -> ObjValue { ObjValue(Rc::new(ObjValueInternals { super_obj, @@ -57,7 +58,7 @@ Some(v) => ObjValue::new(Some(v.with_super(super_obj)), self.0.this_entries.clone()), } } - pub fn enum_fields(&self, handler: &impl Fn(&str, &Visibility)) { + pub fn enum_fields(&self, handler: &impl Fn(&Rc, &Visibility)) { if let Some(s) = &self.0.super_obj { s.enum_fields(handler); } @@ -65,7 +66,7 @@ handler(&name, &member.visibility); } } - pub fn fields_visibility(&self) -> IndexMap { + pub fn fields_visibility(&self) -> IndexMap, bool> { let out = Rc::new(RefCell::new(IndexMap::new())); self.enum_fields(&|name, visibility| { let mut out = out.borrow_mut(); @@ -85,16 +86,20 @@ }); Rc::try_unwrap(out).unwrap().into_inner() } - pub fn get(&self, key: &str) -> Result> { - if let Some(v) = self.0.value_cache.borrow().get(key) { + pub fn visible_fields(&self) -> Vec> { + self.fields_visibility() + .into_iter() + .filter(|(_k, v)| *v) + .map(|(k, _)| k) + .collect() + } + pub fn get(&self, key: Rc) -> Result> { + if let Some(v) = self.0.value_cache.borrow().get(&key) { return Ok(Some(v.clone())); } - if let Some(v) = self.get_raw(key, self)? { + if let Some(v) = self.get_raw(&key, self)? { let v = v.unwrap_if_lazy()?; - self.0 - .value_cache - .borrow_mut() - .insert(key.to_owned(), v.clone()); + self.0.value_cache.borrow_mut().insert(key, v.clone()); Ok(Some(v)) } else { Ok(None) @@ -108,10 +113,10 @@ .evaluate()?, )), (Some(k), Some(s)) => { - let our = k + let lazy = k .invoke - .evaluate(Some(real_this.clone()), self.0.super_obj.clone())? - .evaluate()?; + .evaluate(Some(real_this.clone()), self.0.super_obj.clone())?; + let our = lazy.evaluate()?; if k.add { s.get_raw(key, real_this)? .map_or(Ok(Some(our.clone())), |v| { @@ -124,11 +129,6 @@ (None, Some(s)) => s.get_raw(key, real_this), (None, None) => Ok(None), } - } -} -impl Clone for ObjValue { - fn clone(&self) -> Self { - ObjValue(self.0.clone()) } } impl PartialEq for ObjValue { --- a/crates/jsonnet-evaluator/src/val.rs +++ b/crates/jsonnet-evaluator/src/val.rs @@ -81,7 +81,7 @@ } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum ValType { Bool, Null, @@ -115,42 +115,46 @@ pub enum Val { Bool(bool), Null, - Str(String), + Str(Rc), Num(f64), Lazy(LazyVal), - Arr(Vec), + Arr(Rc>), Obj(ObjValue), Func(FuncDesc), // Library functions implemented in native - Intristic(String, String), + Intristic(Rc, Rc), +} +macro_rules! matches_unwrap { + ($e: expr, $p: pat, $r: expr) => { + match $e { + $p => $r, + _ => panic!("no match"), + } + }; } impl Val { + pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> { + let this_type = self.value_type()?; + if this_type != val_type { + create_error(Error::TypeMismatch(context, vec![val_type], this_type)) + } else { + Ok(()) + } + } pub fn try_cast_bool(self, context: &'static str) -> Result { - match self.unwrap_if_lazy()? { - Val::Bool(v) => Ok(v), - v => create_error(Error::TypeMismatch( - context, - vec![ValType::Bool], - v.value_type()?, - )), - } + self.assert_type(context, ValType::Bool)?; + Ok(matches_unwrap!(self.unwrap_if_lazy()?, Val::Bool(v), v)) } - pub fn try_cast_str(self, context: &'static str) -> Result { - match self.unwrap_if_lazy()? { - Val::Str(v) => Ok(v), - v => create_error(Error::TypeMismatch( - context, - vec![ValType::Str], - v.value_type()?, - )), - } + pub fn try_cast_str(self, context: &'static str) -> Result> { + self.assert_type(context, ValType::Str)?; + Ok(matches_unwrap!(self.unwrap_if_lazy()?, Val::Str(v), v)) } - pub fn unwrap_if_lazy(self) -> Result { + pub fn unwrap_if_lazy(&self) -> Result { Ok(if let Val::Lazy(v) = self { v.evaluate()?.unwrap_if_lazy()? } else { - self + self.clone() }) } pub fn value_type(&self) -> Result { @@ -166,26 +170,30 @@ Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?, }) } - pub fn into_json(self, padding: usize) -> Result { + pub fn into_json(self, padding: usize) -> Result> { with_state(|s| { let ctx = s .create_default_context()? - .with_var("__tmp__to_json__".to_owned(), self)?; - if let Val::Str(result) = evaluate( + .with_var("__tmp__to_json__".into(), self)?; + Ok(evaluate( ctx, &el!(Expr::Apply( el!(Expr::Index( - el!(Expr::Var("std".to_owned())), - el!(Expr::Str("manifestJsonEx".to_owned())) + el!(Expr::Var("std".into())), + el!(Expr::Str("manifestJsonEx".into())) )), ArgsDesc(vec![ - Arg(None, el!(Expr::Var("__tmp__to_json__".to_owned()))), - Arg(None, el!(Expr::Str(" ".repeat(padding)))) + Arg(None, el!(Expr::Var("__tmp__to_json__".into()))), + Arg(None, el!(Expr::Str(" ".repeat(padding).into()))) ]), false )), - )? { - Ok(result) + )? + .try_cast_str("to json")?) + }) + } +} + } else { unreachable!() } --- a/crates/jsonnet-parser/src/expr.rs +++ b/crates/jsonnet-parser/src/expr.rs @@ -1,15 +1,15 @@ use serde::{Deserialize, Serialize}; use std::{fmt::Debug, ops::Deref, path::PathBuf, rc::Rc}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum FieldName { /// {fixed: 2} - Fixed(String), + Fixed(Rc), /// {["dyn"+"amic"]: 3} Dyn(LocExpr), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum Visibility { /// : Normal, @@ -19,10 +19,10 @@ Unhide, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct AssertStmt(pub LocExpr, pub Option); -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct FieldMember { pub name: FieldName, pub plus: bool, @@ -31,7 +31,7 @@ pub value: LocExpr, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum Member { Field(FieldMember), BindStmt(BindSpec), @@ -71,11 +71,11 @@ } /// name, default value -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Param(pub String, pub Option); +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Param(pub Rc, pub Option); /// Defined function parameters #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ParamsDesc(pub Vec); +pub struct ParamsDesc(pub Rc>); impl Deref for ParamsDesc { type Target = Vec; fn deref(&self) -> &Self::Target { @@ -83,9 +83,9 @@ } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Arg(pub Option, pub LocExpr); -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct ArgsDesc(pub Vec); impl Deref for ArgsDesc { type Target = Vec; @@ -96,35 +96,38 @@ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct BindSpec { - pub name: String, + pub name: Rc, pub params: Option, pub value: LocExpr, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct IfSpecData(pub LocExpr); -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ForSpecData(pub String, pub LocExpr); +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct ForSpecData(pub Rc, pub LocExpr); -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum CompSpec { IfSpec(IfSpecData), ForSpec(ForSpecData), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct ObjComp { + pub pre_locals: Vec, + pub key: LocExpr, + pub value: LocExpr, + pub post_locals: Vec, + pub compspecs: Vec, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum ObjBody { MemberList(Vec), - ObjComp { - pre_locals: Vec, - key: LocExpr, - value: LocExpr, - post_locals: Vec, - compspecs: Vec, - }, + ObjComp(ObjComp), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)] pub enum LiteralType { This, Super, @@ -134,7 +137,7 @@ False, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct SliceDesc { pub start: Option, pub end: Option, @@ -142,16 +145,16 @@ } /// Syntax base -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum Expr { Literal(LiteralType), /// String value: "hello" - Str(String), + Str(Rc), /// Number: 1, 2.0, 2e+20 Num(f64), /// Variable name: test - Var(String), + Var(Rc), /// Array of expressions: [1, 2, "Hello"] Arr(Vec), --- a/crates/jsonnet-parser/src/lib.rs +++ b/crates/jsonnet-parser/src/lib.rs @@ -39,7 +39,7 @@ /// Reserved word followed by any non-alphanumberic rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident() - rule id() -> String = quiet!{ !reserved() s:$(alpha() (alpha() / digit())*) {s.to_owned()}} / expected!("") + rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("") rule keyword(id: &'static str) = ##parse_string_literal(id) end_of_ident() @@ -47,7 +47,7 @@ rule l(s: &ParserSettings, x: rule) -> LocExpr = start:position!() v:x() end:position!() {loc_expr!(v, s.loc_data, (s.file_name.clone(), start, end))} - pub rule param(s: &ParserSettings) -> expr::Param = name:id() expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) } + pub rule param(s: &ParserSettings) -> expr::Param = name:$(id()) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name.into(), expr) } pub rule params(s: &ParserSettings) -> expr::ParamsDesc = params:(param(s) ** comma()) { let mut defaults_started = false; @@ -55,12 +55,12 @@ defaults_started = defaults_started || param.1.is_some(); assert_eq!(defaults_started, param.1.is_some(), "defauld parameters should be used after all positionals"); } - expr::ParamsDesc(params) + expr::ParamsDesc(Rc::new(params)) } - / { expr::ParamsDesc(Vec::new()) } + / { expr::ParamsDesc(Rc::new(Vec::new())) } pub rule arg(s: &ParserSettings) -> expr::Arg - = name:id() _ "=" _ expr:expr(s) {expr::Arg(Some(name), expr)} + = name:$(id()) _ "=" _ expr:expr(s) {expr::Arg(Some(name.into()), expr)} / expr:expr(s) {expr::Arg(None, expr)} pub rule args(s: &ParserSettings) -> expr::ArgsDesc = args:arg(s) ** comma() comma()? { @@ -74,8 +74,8 @@ / { expr::ArgsDesc(Vec::new()) } pub rule bind(s: &ParserSettings) -> expr::BindSpec - = name:id() _ "=" _ expr:expr(s) {expr::BindSpec{name, params: None, value: expr}} - / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec{name, params: Some(params), value: expr}} + = name:$(id()) _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: None, value: expr}} + / name:$(id()) _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: Some(params), value: expr}} pub rule assertion(s: &ParserSettings) -> expr::AssertStmt = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) } @@ -95,8 +95,8 @@ / string_block() pub rule field_name(s: &ParserSettings) -> expr::FieldName - = name:id() {expr::FieldName::Fixed(name)} - / name:string() {expr::FieldName::Fixed(name)} + = name:$(id()) {expr::FieldName::Fixed(name.into())} + / name:string() {expr::FieldName::Fixed(name.into())} / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)} pub rule visibility() -> expr::Visibility = ":::" {expr::Visibility::Unhide} @@ -125,35 +125,41 @@ / field:field(s) {expr::Member::Field(field)} pub rule objinside(s: &ParserSettings) -> expr::ObjBody = pre_locals:(b: obj_local(s) comma() {b})* "[" _ key:expr(s) _ "]" _ ":" _ value:expr(s) post_locals:(comma() b:obj_local(s) {b})* _ forspec:forspec(s) others:(_ rest:compspec(s) {rest})? { - expr::ObjBody::ObjComp { + let mut compspecs = vec![CompSpec::ForSpec(forspec)]; + compspecs.extend(others.unwrap_or_default()); + expr::ObjBody::ObjComp(expr::ObjComp{ pre_locals, key, value, post_locals, - compspecs: [vec![CompSpec::ForSpec(forspec)], others.unwrap_or_default()].concat(), - } + compspecs, + }) } / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)} pub rule ifspec(s: &ParserSettings) -> IfSpecData = keyword("if") _ expr:expr(s) {IfSpecData(expr)} pub rule forspec(s: &ParserSettings) -> ForSpecData - = keyword("for") _ id:id() _ keyword("in") _ cond:expr(s) {ForSpecData(id, cond)} + = keyword("for") _ id:$(id()) _ keyword("in") _ cond:expr(s) {ForSpecData(id.into(), cond)} pub rule compspec(s: &ParserSettings) -> Vec = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s} pub rule local_expr(s: &ParserSettings) -> LocExpr = l(s,) pub rule string_expr(s: &ParserSettings) -> LocExpr - = l(s, ) + = l(s, ) pub rule obj_expr(s: &ParserSettings) -> LocExpr = l(s,<"{" _ body:objinside(s) _ "}" {Expr::Obj(body)}>) pub rule array_expr(s: &ParserSettings) -> LocExpr = l(s,<"[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}>) pub rule array_comp_expr(s: &ParserSettings) -> LocExpr - = l(s,<"[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {Expr::ArrComp(expr, [vec![CompSpec::ForSpec(forspec)], others.unwrap_or_default()].concat())}>) + = l(s,<"[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" { + let mut specs = vec![CompSpec::ForSpec(forspec)]; + specs.extend(others.unwrap_or_default()); + Expr::ArrComp(expr, specs) + }>) pub rule number_expr(s: &ParserSettings) -> LocExpr = l(s,) pub rule var_expr(s: &ParserSettings) -> LocExpr - = l(s,) + = l(s,) pub rule if_then_else_expr(s: &ParserSettings) -> LocExpr = l(s,=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gte, b))} a:(@) _ keyword("in") _ b:@ {loc_expr_todo!(Expr::Apply( el!(Expr::Index( - el!(Expr::Var("std".to_owned())), - el!(Expr::Str("objectHasEx".to_owned())) + el!(Expr::Var("std".into())), + el!(Expr::Str("objectHasEx".into())) )), ArgsDesc(vec![Arg(None, b), Arg(None, a), Arg(None, el!(Expr::Literal(LiteralType::True)))]), true ))} @@ -256,8 +262,8 @@ a:(@) _ "/" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Div, b))} a:(@) _ "%" _ b:@ {loc_expr_todo!(Expr::Apply( el!(Expr::Index( - el!(Expr::Var("std".to_owned())), - el!(Expr::Str("mod".to_owned())) + el!(Expr::Var("std".into())), + el!(Expr::Str("mod".into())) )), ArgsDesc(vec![Arg(None, a), Arg(None, b)]), true ))} @@ -268,8 +274,8 @@ -- a:(@) _ "[" _ s:slice_desc(s) _ "]" {loc_expr_todo!(Expr::Apply( el!(Expr::Index( - el!(Expr::Var("std".to_owned())), - el!(Expr::Str("slice".to_owned())), + el!(Expr::Var("std".into())), + el!(Expr::Str("slice".into())), )), ArgsDesc(vec![ Arg(None, a), @@ -279,7 +285,7 @@ ]), true, ))} - a:(@) _ "." _ s:id() {loc_expr_todo!(Expr::Index(a, el!(Expr::Str(s))))} + a:(@) _ "." _ s:$(id()) {loc_expr_todo!(Expr::Index(a, el!(Expr::Str(s.into()))))} a:(@) _ "[" _ s:expr(s) _ "]" {loc_expr_todo!(Expr::Index(a, s))} a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {loc_expr_todo!(Expr::Apply(a, args, ts.is_some()))} a:(@) _ "{" _ body:objinside(s) _ "}" {loc_expr_todo!(Expr::ObjExtend(a, body))} @@ -352,7 +358,7 @@ fn multiline_string() { assert_eq!( parse!("|||\n Hello world!\n a\n|||"), - el!(Expr::Str("Hello world!\n a\n".to_owned())), + el!(Expr::Str("Hello world!\n a\n".into())), ) } @@ -369,20 +375,20 @@ fn string_escaping() { assert_eq!( parse!(r#""Hello, \"world\"!""#), - el!(Expr::Str(r#"Hello, "world"!"#.to_owned())), + el!(Expr::Str(r#"Hello, "world"!"#.into())), ); assert_eq!( parse!(r#"'Hello \'world\'!'"#), - el!(Expr::Str("Hello 'world'!".to_owned())), + el!(Expr::Str("Hello 'world'!".into())), ); - assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".to_owned())),); + assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".into())),); } #[test] fn string_unescaping() { assert_eq!( parse!(r#""Hello\nWorld""#), - el!(Expr::Str("Hello\nWorld".to_owned())), + el!(Expr::Str("Hello\nWorld".into())), ); } @@ -390,7 +396,7 @@ fn string_verbantim() { assert_eq!( parse!(r#"@"Hello\n""World""""#), - el!(Expr::Str("Hello\\n\"World\"".to_owned())), + el!(Expr::Str("Hello\\n\"World\"".into())), ); } @@ -489,16 +495,13 @@ parse!("[std.deepJoin(x) for x in arr]"), el!(ArrComp( el!(Apply( - el!(Index( - el!(Var("std".to_owned())), - el!(Str("deepJoin".to_owned())) - )), - ArgsDesc(vec![Arg(None, el!(Var("x".to_owned())))]), + el!(Index(el!(Var("std".into())), el!(Str("deepJoin".into())))), + ArgsDesc(vec![Arg(None, el!(Var("x".into())))]), false, )), vec![CompSpec::ForSpec(ForSpecData( - "x".to_owned(), - el!(Var("arr".to_owned())) + "x".into(), + el!(Var("arr".into())) ))] )), ) @@ -508,7 +511,7 @@ fn reserved() { use Expr::*; assert_eq!(parse!("null"), el!(Literal(LiteralType::Null))); - assert_eq!(parse!("nulla"), el!(Var("nulla".to_owned()))); + assert_eq!(parse!("nulla"), el!(Var("nulla".into()))); } #[test] @@ -522,9 +525,9 @@ assert_eq!( parse!("!a && !b"), el!(BinaryOp( - el!(UnaryOp(UnaryOpType::Not, el!(Var("a".to_owned())))), + el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))), BinaryOpType::And, - el!(UnaryOp(UnaryOpType::Not, el!(Var("b".to_owned())))) + el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into())))) )) ); } @@ -535,9 +538,9 @@ assert_eq!( parse!("!a / !b"), el!(BinaryOp( - el!(UnaryOp(UnaryOpType::Not, el!(Var("a".to_owned())))), + el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))), BinaryOpType::Div, - el!(UnaryOp(UnaryOpType::Not, el!(Var("b".to_owned())))) + el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into())))) )) ); } @@ -549,7 +552,7 @@ parse!("!!a"), el!(UnaryOp( UnaryOpType::Not, - el!(UnaryOp(UnaryOpType::Not, el!(Var("a".to_owned())))) + el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))) )) ) }