difftreelog
fix(parser) desugar == to std.equals
in: master
4 files changed
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -5,9 +5,8 @@
};
use closure::closure;
use jsonnet_parser::{
- el, Arg, ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember,
- ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType,
- Visibility,
+ ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, ForSpecData,
+ IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType, Visibility,
};
use std::{
collections::{BTreeMap, HashMap},
@@ -102,55 +101,20 @@
match (evaluate(context.clone(), &a)?.unwrap_if_lazy()?, op, b) {
(Val::Bool(true), BinaryOpType::Or, _o) => Val::Bool(true),
(Val::Bool(false), BinaryOpType::And, _o) => Val::Bool(false),
- (a, op, eb) => evaluate_binary_op_normal(
- context.clone(),
- &a,
- op,
- &evaluate(context, eb)?.unwrap_if_lazy()?,
- )?,
+ (a, op, eb) => {
+ evaluate_binary_op_normal(&a, op, &evaluate(context, eb)?.unwrap_if_lazy()?)?
+ }
},
)
}
-pub fn evaluate_binary_op_normal(
- context: Context,
- a: &Val,
- op: BinaryOpType,
- b: &Val,
-) -> Result<Val> {
+pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {
Ok(match (a, op, b) {
(a, BinaryOpType::Add, b) => evaluate_add_op(a, b)?,
-
- (Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => Val::Bool(v1 == v2),
- (Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => Val::Bool(v1 != v2),
(Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),
- (Val::Str(format), BinaryOpType::Mod, args) => evaluate(
- context
- .with_var("__tmp__format__".to_owned(), Val::Str(format.to_owned()))?
- .with_var(
- "__tmp__args__".to_owned(),
- match args {
- Val::Arr(v) => Val::Arr(v.clone()),
- v => Val::Arr(vec![v.clone()]),
- },
- )?,
- &el!(Expr::Apply(
- el!(Expr::Index(
- el!(Expr::Var("std".to_owned())),
- el!(Expr::Str("format".to_owned()))
- )),
- ArgsDesc(vec![
- Arg(None, el!(Expr::Var("__tmp__format__".to_owned()))),
- Arg(None, el!(Expr::Var("__tmp__args__".to_owned())))
- ])
- )),
- )?,
// Bool X Bool
- (Val::Bool(a), BinaryOpType::Eq, Val::Bool(b)) => Val::Bool(a == b),
- (Val::Bool(a), BinaryOpType::Ne, Val::Bool(b)) => Val::Bool(a != b),
-
(Val::Bool(a), BinaryOpType::And, Val::Bool(b)) => Val::Bool(*a && *b),
(Val::Bool(a), BinaryOpType::Or, Val::Bool(b)) => Val::Bool(*a || *b),
@@ -163,7 +127,6 @@
// Num X Num
(Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),
(Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => Val::Num(v1 / v2),
- (Val::Num(v1), BinaryOpType::Mod, Val::Num(v2)) => Val::Num(v1 % v2),
(Val::Num(v1), BinaryOpType::Sub, Val::Num(v2)) => Val::Num(v1 - v2),
@@ -171,9 +134,6 @@
(Val::Num(v1), BinaryOpType::Gt, Val::Num(v2)) => Val::Bool(v1 > v2),
(Val::Num(v1), BinaryOpType::Lte, Val::Num(v2)) => Val::Bool(v1 <= v2),
(Val::Num(v1), BinaryOpType::Gte, Val::Num(v2)) => Val::Bool(v1 >= v2),
-
- (Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => Val::Bool((v1 - v2).abs() < f64::EPSILON),
- (Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => Val::Bool((v1 - v2).abs() > f64::EPSILON),
(Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => {
Val::Num(((*v1 as i32) & (*v2 as i32)) as f64)
@@ -191,28 +151,6 @@
Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64)
}
- // Arr X Arr
- (Val::Arr(a), BinaryOpType::Eq, Val::Arr(b)) => {
- if a.len() != b.len() {
- Val::Bool(false)
- } else {
- for i in 0..a.len() {
- if let Val::Bool(v) = evaluate_binary_op_normal(
- context.clone(),
- &a[i].clone().unwrap_if_lazy()?,
- op,
- &b[i].clone().unwrap_if_lazy()?,
- )? {
- if !v {
- return Ok(Val::Bool(false));
- }
- } else {
- unreachable!()
- }
- }
- return Ok(Val::Bool(true));
- }
- }
_ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b),
})
}
@@ -385,7 +323,7 @@
Index(value, index) => {
match (
evaluate(context.clone(), value)?.unwrap_if_lazy()?,
- evaluate(context.clone(), index)?,
+ evaluate(context, index)?,
) {
(Val::Obj(v), Val::Str(s)) => {
if let Some(v) = v.get(&s)? {
@@ -506,9 +444,17 @@
panic!("bad objectFieldsEx call");
}
}
+ ("std", "primitiveEquals") => {
+ assert_eq!(args.len(), 2);
+ let (a, b) = (
+ evaluate(context.clone(), &args[0].1)?,
+ evaluate(context, &args[1].1)?,
+ );
+ Val::Bool(a == b)
+ }
(ns, name) => panic!("Intristic not found: {}.{}", ns, name),
},
- Val::Func(f) => push(locexpr.clone(), "function call".to_owned(), || {
+ Val::Func(f) => push(locexpr, "function call".to_owned(), || {
f.evaluate(
args.clone()
.into_iter()
@@ -528,10 +474,11 @@
}
Function(params, body) => evaluate_method(context, body, params.clone()),
AssertExpr(AssertStmt(value, msg), returned) => {
- if push(value.clone(), "assertion condition".to_owned(), || {
+ let assertion_result = push(value.clone(), "assertion condition".to_owned(), || {
evaluate(context.clone(), &value)?
.try_cast_bool("assertion condition should be boolean")
- })? {
+ })?;
+ if assertion_result {
push(
returned.clone(),
"assert 'return' branch".to_owned(),
@@ -555,9 +502,10 @@
cond_then,
cond_else,
} => {
- if push(cond.0.clone(), "if condition".to_owned(), || {
+ let condition_result = push(cond.0.clone(), "if condition".to_owned(), || {
evaluate(context.clone(), &cond.0)?.try_cast_bool("if condition should be boolean")
- })? {
+ })?;
+ if condition_result {
push(
cond_then.clone(),
"if condition 'then' branch".to_owned(),
crates/jsonnet-parser/Cargo.tomldiffbeforeafterboth--- a/crates/jsonnet-parser/Cargo.toml
+++ b/crates/jsonnet-parser/Cargo.toml
@@ -7,7 +7,7 @@
[features]
default = []
# Trace peg token parsing
-trace = ["peg/trace"]
+# trace = ["peg/trace"]
# TODO:
# serialize = ["serde"]
crates/jsonnet-parser/src/expr.rsdiffbeforeafterboth1use serde::{Deserialize, Serialize};2use std::{fmt::Debug, rc::Rc};34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]5pub enum FieldName {6 /// {fixed: 2}7 Fixed(String),8 /// {["dyn"+"amic"]: 3}9 Dyn(LocExpr),10}1112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]13pub enum Visibility {14 /// :15 Normal,16 /// ::17 Hidden,18 /// :::19 Unhide,20}2122#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]23pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);2425#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]26pub struct FieldMember {27 pub name: FieldName,28 pub plus: bool,29 pub params: Option<ParamsDesc>,30 pub visibility: Visibility,31 pub value: LocExpr,32}3334#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]35pub enum Member {36 Field(FieldMember),37 BindStmt(BindSpec),38 AssertStmt(AssertStmt),39}4041#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]42pub enum UnaryOpType {43 Plus,44 Minus,45 BitNot,46 Not,47}4849#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]50pub enum BinaryOpType {51 Mul,52 Div,53 // Mod is desugared to stdlib54 // Mod,55 Add,56 Sub,5758 Lhs,59 Rhs,6061 Lt,62 Gt,63 Lte,64 Gte,6566 In,6768 Eq,69 Ne,7071 BitAnd,72 BitOr,73 BitXor,7475 And,76 Or,77}7879/// name, default value80#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]81pub struct Param(pub String, pub Option<LocExpr>);82/// Defined function parameters83#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]84pub struct ParamsDesc(pub Vec<Param>);85impl ParamsDesc {86 pub fn with_defaults(&self) -> Vec<Param> {87 self.0.iter().filter(|e| e.1.is_some()).cloned().collect()88 }89}9091#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]92pub struct Arg(pub Option<String>, pub LocExpr);93#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]94pub struct ArgsDesc(pub Vec<Arg>);9596#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]97pub struct BindSpec {98 pub name: String,99 pub params: Option<ParamsDesc>,100 pub value: LocExpr,101}102103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]104pub struct IfSpecData(pub LocExpr);105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]106pub struct ForSpecData(pub String, pub LocExpr);107108#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]109pub enum CompSpec {110 IfSpec(IfSpecData),111 ForSpec(ForSpecData),112}113114#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]115pub enum ObjBody {116 MemberList(Vec<Member>),117 ObjComp {118 pre_locals: Vec<BindSpec>,119 key: LocExpr,120 value: LocExpr,121 post_locals: Vec<BindSpec>,122 first: ForSpecData,123 rest: Vec<CompSpec>,124 },125}126127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]128pub enum LiteralType {129 This,130 Super,131 Dollar,132 Null,133 True,134 False,135}136137#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]138pub struct SliceDesc {139 pub start: Option<LocExpr>,140 pub end: Option<LocExpr>,141 pub step: Option<LocExpr>,142}143144/// Syntax base145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]146pub enum Expr {147 Literal(LiteralType),148149 /// String value: "hello"150 Str(String),151 /// Number: 1, 2.0, 2e+20152 Num(f64),153 /// Variable name: test154 Var(String),155156 /// Array of expressions: [1, 2, "Hello"]157 Arr(Vec<LocExpr>),158 /// Array comprehension:159 /// ```jsonnet160 /// ingredients: [161 /// { kind: kind, qty: 4 / 3 }162 /// for kind in [163 /// 'Honey Syrup',164 /// 'Lemon Juice',165 /// 'Farmers Gin',166 /// ]167 /// ],168 /// ```169 ArrComp(LocExpr, Vec<CompSpec>),170171 /// Object: {a: 2}172 Obj(ObjBody),173 /// Object extension: var1 {b: 2}174 ObjExtend(LocExpr, ObjBody),175176 /// (obj)177 Parened(LocExpr),178179 /// Params in function definition180 /// hello, world, test = 2181 Params(ParamsDesc),182 /// Args in function call183 /// 2 + 2, 3, named = 6184 Args(ArgsDesc),185186 /// -2187 UnaryOp(UnaryOpType, LocExpr),188 /// 2 - 2189 BinaryOp(LocExpr, BinaryOpType, LocExpr),190 /// assert 2 == 2 : "Math is broken"191 AssertExpr(AssertStmt, LocExpr),192 /// local a = 2; { b: a }193 LocalExpr(Vec<BindSpec>, LocExpr),194195 /// a = 3196 Bind(BindSpec),197 /// import "hello"198 Import(String),199 /// importStr "file.txt"200 ImportStr(String),201 /// error "I'm broken"202 Error(LocExpr),203 /// a(b, c)204 Apply(LocExpr, ArgsDesc),205 ///206 Select(LocExpr, String),207 /// a[b]208 Index(LocExpr, LocExpr),209 /// a[1::2]210 Slice(LocExpr, SliceDesc),211 /// function(x) x212 Function(ParamsDesc, LocExpr),213 /// if true == false then 1 else 2214 IfElse {215 cond: IfSpecData,216 cond_then: LocExpr,217 cond_else: Option<LocExpr>,218 },219 /// if 2 = 3220 IfSpec(IfSpecData),221 /// for elem in array222 ForSpec(ForSpecData),223}224225/// file, begin offset, end offset226#[derive(Clone, PartialEq, Serialize, Deserialize)]227pub struct ExprLocation(pub String, pub usize, pub usize);228impl Debug for ExprLocation {229 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {230 write!(f, "{}:{:?}-{:?}", self.0, self.1, self.2)231 }232}233234/// Holds AST expression and its location in source file+235#[derive(Clone, PartialEq, Serialize, Deserialize)]236pub struct LocExpr(pub Rc<Expr>, pub Option<Rc<ExprLocation>>);237impl Debug for LocExpr {238 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {239 write!(f, "{:?} from {:?}", self.0, self.1)240 }241}242243/// Creates LocExpr from Expr and ExprLocation components244#[macro_export]245macro_rules! loc_expr {246 ($expr:expr, $need_loc:expr,($name:expr, $start:expr, $end:expr)) => {247 LocExpr(248 std::rc::Rc::new($expr),249 if $need_loc {250 Some(std::rc::Rc::new(ExprLocation(251 $name.to_owned(),252 $start,253 $end,254 )))255 } else {256 None257 },258 )259 };260}261262/// Creates LocExpr without location info263#[macro_export]264macro_rules! loc_expr_todo {265 ($expr:expr) => {266 LocExpr(Rc::new($expr), None)267 };268}1use serde::{Deserialize, Serialize};2use std::{fmt::Debug, rc::Rc};34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]5pub enum FieldName {6 /// {fixed: 2}7 Fixed(String),8 /// {["dyn"+"amic"]: 3}9 Dyn(LocExpr),10}1112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]13pub enum Visibility {14 /// :15 Normal,16 /// ::17 Hidden,18 /// :::19 Unhide,20}2122#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]23pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);2425#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]26pub struct FieldMember {27 pub name: FieldName,28 pub plus: bool,29 pub params: Option<ParamsDesc>,30 pub visibility: Visibility,31 pub value: LocExpr,32}3334#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]35pub enum Member {36 Field(FieldMember),37 BindStmt(BindSpec),38 AssertStmt(AssertStmt),39}4041#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]42pub enum UnaryOpType {43 Plus,44 Minus,45 BitNot,46 Not,47}4849#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]50pub enum BinaryOpType {51 Mul,52 Div,53 // Mod is desugared to std.mod54 // Mod,55 Add,56 Sub,5758 Lhs,59 Rhs,6061 Lt,62 Gt,63 Lte,64 Gte,6566 In,6768 // Eq/Ne is desugared to std.equals69 // Eq,70 // Ne,7172 BitAnd,73 BitOr,74 BitXor,7576 And,77 Or,78}7980/// name, default value81#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]82pub struct Param(pub String, pub Option<LocExpr>);83/// Defined function parameters84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]85pub struct ParamsDesc(pub Vec<Param>);86impl ParamsDesc {87 pub fn with_defaults(&self) -> Vec<Param> {88 self.0.iter().filter(|e| e.1.is_some()).cloned().collect()89 }90}9192#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]93pub struct Arg(pub Option<String>, pub LocExpr);94#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]95pub struct ArgsDesc(pub Vec<Arg>);9697#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]98pub struct BindSpec {99 pub name: String,100 pub params: Option<ParamsDesc>,101 pub value: LocExpr,102}103104#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]105pub struct IfSpecData(pub LocExpr);106#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]107pub struct ForSpecData(pub String, pub LocExpr);108109#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]110pub enum CompSpec {111 IfSpec(IfSpecData),112 ForSpec(ForSpecData),113}114115#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]116pub enum ObjBody {117 MemberList(Vec<Member>),118 ObjComp {119 pre_locals: Vec<BindSpec>,120 key: LocExpr,121 value: LocExpr,122 post_locals: Vec<BindSpec>,123 first: ForSpecData,124 rest: Vec<CompSpec>,125 },126}127128#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]129pub enum LiteralType {130 This,131 Super,132 Dollar,133 Null,134 True,135 False,136}137138#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]139pub struct SliceDesc {140 pub start: Option<LocExpr>,141 pub end: Option<LocExpr>,142 pub step: Option<LocExpr>,143}144145/// Syntax base146#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]147pub enum Expr {148 Literal(LiteralType),149150 /// String value: "hello"151 Str(String),152 /// Number: 1, 2.0, 2e+20153 Num(f64),154 /// Variable name: test155 Var(String),156157 /// Array of expressions: [1, 2, "Hello"]158 Arr(Vec<LocExpr>),159 /// Array comprehension:160 /// ```jsonnet161 /// ingredients: [162 /// { kind: kind, qty: 4 / 3 }163 /// for kind in [164 /// 'Honey Syrup',165 /// 'Lemon Juice',166 /// 'Farmers Gin',167 /// ]168 /// ],169 /// ```170 ArrComp(LocExpr, Vec<CompSpec>),171172 /// Object: {a: 2}173 Obj(ObjBody),174 /// Object extension: var1 {b: 2}175 ObjExtend(LocExpr, ObjBody),176177 /// (obj)178 Parened(LocExpr),179180 /// Params in function definition181 /// hello, world, test = 2182 Params(ParamsDesc),183 /// Args in function call184 /// 2 + 2, 3, named = 6185 Args(ArgsDesc),186187 /// -2188 UnaryOp(UnaryOpType, LocExpr),189 /// 2 - 2190 BinaryOp(LocExpr, BinaryOpType, LocExpr),191 /// assert 2 == 2 : "Math is broken"192 AssertExpr(AssertStmt, LocExpr),193 /// local a = 2; { b: a }194 LocalExpr(Vec<BindSpec>, LocExpr),195196 /// a = 3197 Bind(BindSpec),198 /// import "hello"199 Import(String),200 /// importStr "file.txt"201 ImportStr(String),202 /// error "I'm broken"203 Error(LocExpr),204 /// a(b, c)205 Apply(LocExpr, ArgsDesc),206 ///207 Select(LocExpr, String),208 /// a[b]209 Index(LocExpr, LocExpr),210 /// a[1::2]211 Slice(LocExpr, SliceDesc),212 /// function(x) x213 Function(ParamsDesc, LocExpr),214 /// if true == false then 1 else 2215 IfElse {216 cond: IfSpecData,217 cond_then: LocExpr,218 cond_else: Option<LocExpr>,219 },220 /// if 2 = 3221 IfSpec(IfSpecData),222 /// for elem in array223 ForSpec(ForSpecData),224}225226/// file, begin offset, end offset227#[derive(Clone, PartialEq, Serialize, Deserialize)]228pub struct ExprLocation(pub String, pub usize, pub usize);229impl Debug for ExprLocation {230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {231 write!(f, "{}:{:?}-{:?}", self.0, self.1, self.2)232 }233}234235/// Holds AST expression and its location in source file+236#[derive(Clone, PartialEq, Serialize, Deserialize)]237pub struct LocExpr(pub Rc<Expr>, pub Option<Rc<ExprLocation>>);238impl Debug for LocExpr {239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {240 write!(f, "{:?} from {:?}", self.0, self.1)241 }242}243244/// Creates LocExpr from Expr and ExprLocation components245#[macro_export]246macro_rules! loc_expr {247 ($expr:expr, $need_loc:expr,($name:expr, $start:expr, $end:expr)) => {248 LocExpr(249 std::rc::Rc::new($expr),250 if $need_loc {251 Some(std::rc::Rc::new(ExprLocation(252 $name.to_owned(),253 $start,254 $end,255 )))256 } else {257 None258 },259 )260 };261}262263/// Creates LocExpr without location info264#[macro_export]265macro_rules! loc_expr_todo {266 ($expr:expr) => {267 LocExpr(Rc::new($expr), None)268 };269}crates/jsonnet-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jsonnet-parser/src/lib.rs
+++ b/crates/jsonnet-parser/src/lib.rs
@@ -230,8 +230,18 @@
--
a:(@) _ "&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitAnd, b))}
--
- a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Eq, b))}
- a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Ne, b))}
+ a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::Apply(
+ el!(Expr::Index(
+ el!(Expr::Var("std".to_owned())),
+ el!(Expr::Str("equals".to_owned()))
+ )), ArgsDesc(vec![Arg(None, a), Arg(None, b)])
+ ))}
+ a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Not, el!(Expr::Apply(
+ el!(Expr::Index(
+ el!(Expr::Var("std".to_owned())),
+ el!(Expr::Str("equals".to_owned()))
+ )), ArgsDesc(vec![Arg(None, a), Arg(None, b)])
+ ))))}
--
a:(@) _ "<" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lt, b))}
a:(@) _ ">" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gt, b))}
@@ -385,25 +395,6 @@
el!(Expr::Num(2.0)),
BinaryOpType::Sub,
el!(Expr::Num(22.0))
- ))
- );
- }
-
- #[test]
- fn suffix_comparsion() {
- use Expr::*;
- assert_eq!(
- parse!("std.type(a) == \"string\""),
- el!(BinaryOp(
- el!(Apply(
- el!(Index(
- el!(Var("std".to_owned())),
- el!(Str("type".to_owned()))
- )),
- ArgsDesc(vec![Arg(None, el!(Var("a".to_owned())))])
- )),
- BinaryOpType::Eq,
- el!(Str("string".to_owned()))
))
);
}
@@ -427,37 +418,6 @@
))]
)),
)
- }
-
- #[test]
- fn array_comp_with_ifs() {
- use Expr::*;
- assert_eq!(
- parse!("[k for k in std.objectFields(patch) if patch[k] == null]"),
- el!(ArrComp(
- el!(Var("k".to_owned())),
- vec![
- CompSpec::ForSpec(ForSpecData(
- "k".to_owned(),
- el!(Apply(
- el!(Index(
- el!(Var("std".to_owned())),
- el!(Str("objectFields".to_owned()))
- )),
- ArgsDesc(vec![Arg(None, el!(Var("patch".to_owned())))])
- ))
- )),
- CompSpec::IfSpec(IfSpecData(el!(BinaryOp(
- el!(Index(
- el!(Var("patch".to_owned())),
- el!(Var("k".to_owned()))
- )),
- BinaryOpType::Eq,
- el!(Literal(LiteralType::Null))
- ))))
- ]
- ))
- );
}
#[test]