From 57937b6f56e9cfe076ba5995d3c11ad24acb832f Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Sun, 15 May 2022 20:04:37 +0800 Subject: [PATCH] tests for expression parsing --- src/data.rs | 2 +- src/data/expr.rs | 117 ++++++++++++++++++++++++++-------------- src/data/expr_parser.rs | 109 +++++++++++++++++++++---------------- src/data/op.rs | 13 +---- src/data/tuple_set.rs | 11 ++-- src/data/typing.rs | 1 - 6 files changed, 151 insertions(+), 102 deletions(-) diff --git a/src/data.rs b/src/data.rs index 3054cfa6..e49b109b 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,7 +1,7 @@ pub(crate) mod expr; +pub(crate) mod expr_parser; pub(crate) mod op; pub(crate) mod tuple; pub(crate) mod tuple_set; pub(crate) mod typing; pub(crate) mod value; -pub(crate) mod expr_parser; diff --git a/src/data/expr.rs b/src/data/expr.rs index 959ef08e..0ecb9267 100644 --- a/src/data/expr.rs +++ b/src/data/expr.rs @@ -2,7 +2,7 @@ use crate::data::op::{AggOp, Op, UnresolvedOp}; use crate::data::tuple_set::{ColId, TableId, TupleSetIdx}; use crate::data::value::{StaticValue, Value}; use std::collections::BTreeMap; -use std::fmt::{Debug, format, Formatter, write}; +use std::fmt::{format, write, Debug, Formatter}; use std::result; use std::sync::Arc; @@ -46,10 +46,12 @@ impl<'a> PartialEq for Expr<'a> { (TableCol(lt, lc), TableCol(rt, rc)) => (lt == rt) && (lc == rc), (TupleSetIdx(l), TupleSetIdx(r)) => l == r, (Apply(lo, la), Apply(ro, ra)) => (lo.name() == ro.name()) && (la == ra), - (ApplyAgg(lo, laa, la), ApplyAgg(ro, raa, ra)) => (lo.name() == ro.name()) && (laa == raa) && (la == ra), + (ApplyAgg(lo, laa, la), ApplyAgg(ro, raa, ra)) => { + (lo.name() == ro.name()) && (laa == raa) && (la == ra) + } (FieldAcc(lf, la), FieldAcc(rf, ra)) => (lf == rf) && (la == ra), (IdxAcc(li, la), IdxAcc(ri, ra)) => (li == ri) && (la == ra), - _ => false + _ => false, } } } @@ -64,16 +66,30 @@ impl<'a> Debug for Expr<'a> { Expr::TableCol(tid, cid) => write!(f, "{:?}{:?}", tid, cid), Expr::TupleSetIdx(sid) => write!(f, "{:?}", sid), Expr::Apply(op, args) => write!( - f, "({} {})", + f, + "({} {})", op.name(), - args.iter().map(|v| format!("{:?}", v)).collect::>().join(" ")), + args.iter() + .map(|v| format!("{:?}", v)) + .collect::>() + .join(" ") + ), Expr::ApplyAgg(op, a_args, args) => write!( - f, "[|{} {} | {}|]", + f, + "[|{} {} | {}|]", op.name(), - a_args.iter().map(|v| format!("{:?}", v)).collect::>().join(" "), - args.iter().map(|v| format!("{:?}", v)).collect::>().join(" ")), + a_args + .iter() + .map(|v| format!("{:?}", v)) + .collect::>() + .join(" "), + args.iter() + .map(|v| format!("{:?}", v)) + .collect::>() + .join(" ") + ), Expr::FieldAcc(field, arg) => write!(f, "(.{} {:?})", field, arg), - Expr::IdxAcc(i, arg) => write!(f, "(.{} {:?})", i, arg) + Expr::IdxAcc(i, arg) => write!(f, "(.{} {:?})", i, arg), } } } @@ -104,58 +120,71 @@ impl<'a> TryFrom> for Expr<'a> { "Const" => Ok(Expr::Const(v)), "List" => { let l = extract_list_from_value(v, 0)?; - Ok(Expr::List(l.into_iter().map(Expr::try_from).collect::>>()?)) + Ok(Expr::List( + l.into_iter() + .map(Expr::try_from) + .collect::>>()?, + )) } - "Dict" => { - match v { - Value::Dict(d) => { - Ok(Expr::Dict(d.into_iter().map(|(k, v)| -> Result<(String, Expr)> { + "Dict" => match v { + Value::Dict(d) => Ok(Expr::Dict( + d.into_iter() + .map(|(k, v)| -> Result<(String, Expr)> { Ok((k.to_string(), Expr::try_from(v)?)) - }).collect::>>()?)) - } - v => return Err(ExprError::ConversionFailure(Value::Dict(BTreeMap::from([(k, v)])).to_static())) + }) + .collect::>>()?, + )), + v => { + return Err(ExprError::ConversionFailure( + Value::Dict(BTreeMap::from([(k, v)])).to_static(), + )) } - } + }, "Variable" => { if let Value::Text(t) = v { Ok(Expr::Variable(t.to_string())) } else { - return Err(ExprError::ConversionFailure(Value::Dict(BTreeMap::from([(k, v)])).to_static())); + return Err(ExprError::ConversionFailure( + Value::Dict(BTreeMap::from([(k, v)])).to_static(), + )); } } "TableCol" => { let mut l = extract_list_from_value(v, 4)?.into_iter(); let in_root = match l.next().unwrap() { Value::Bool(b) => b, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let tid = match l.next().unwrap() { Value::Int(i) => i, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let is_key = match l.next().unwrap() { Value::Bool(b) => b, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let cid = match l.next().unwrap() { Value::Int(i) => i, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; - Ok(Expr::TableCol((in_root, tid as u32).into(), (is_key, cid as usize).into())) + Ok(Expr::TableCol( + (in_root, tid as u32).into(), + (is_key, cid as usize).into(), + )) } "TupleSetIdx" => { let mut l = extract_list_from_value(v, 3)?.into_iter(); let is_key = match l.next().unwrap() { Value::Bool(b) => b, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let tid = match l.next().unwrap() { Value::Int(i) => i, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let cid = match l.next().unwrap() { Value::Int(i) => i, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; Ok(Expr::TupleSetIdx(TupleSetIdx { is_key, @@ -167,31 +196,40 @@ impl<'a> TryFrom> for Expr<'a> { let mut ll = extract_list_from_value(v, 2)?.into_iter(); let name = match ll.next().unwrap() { Value::Text(t) => t, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let op = Arc::new(UnresolvedOp(name.to_string())); let l = extract_list_from_value(ll.next().unwrap(), 0)?; - let args = l.into_iter().map(Expr::try_from).collect::>>()?; + let args = l + .into_iter() + .map(Expr::try_from) + .collect::>>()?; Ok(Expr::Apply(op, args)) } "ApplyAgg" => { let mut ll = extract_list_from_value(v, 3)?.into_iter(); let name = match ll.next().unwrap() { Value::Text(t) => t, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let op = Arc::new(UnresolvedOp(name.to_string())); let l = extract_list_from_value(ll.next().unwrap(), 0)?; - let a_args = l.into_iter().map(Expr::try_from).collect::>>()?; + let a_args = l + .into_iter() + .map(Expr::try_from) + .collect::>>()?; let l = extract_list_from_value(ll.next().unwrap(), 0)?; - let args = l.into_iter().map(Expr::try_from).collect::>>()?; + let args = l + .into_iter() + .map(Expr::try_from) + .collect::>>()?; Ok(Expr::ApplyAgg(op, a_args, args)) } "FieldAcc" => { let mut ll = extract_list_from_value(v, 2)?.into_iter(); let field = match ll.next().unwrap() { Value::Text(t) => t, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let arg = Expr::try_from(ll.next().unwrap())?; Ok(Expr::FieldAcc(field.to_string(), arg.into())) @@ -200,12 +238,12 @@ impl<'a> TryFrom> for Expr<'a> { let mut ll = extract_list_from_value(v, 2)?.into_iter(); let idx = match ll.next().unwrap() { Value::Int(i) => i as usize, - v => return Err(ExprError::ConversionFailure(v.to_static())) + v => return Err(ExprError::ConversionFailure(v.to_static())), }; let arg = Expr::try_from(ll.next().unwrap())?; Ok(Expr::IdxAcc(idx, arg.into())) } - k => Err(ExprError::UnknownExprTag(k.to_string())) + k => Err(ExprError::UnknownExprTag(k.to_string())), } } else { Err(ExprError::ConversionFailure(value.to_static())) @@ -237,7 +275,7 @@ impl<'a> From> for Value<'a> { cid.is_key.into(), Value::from(cid.id as i64), ] - .into(), + .into(), ), Expr::TupleSetIdx(sid) => build_tagged_value( "TupleSetIdx", @@ -246,7 +284,7 @@ impl<'a> From> for Value<'a> { Value::from(sid.t_set as i64), Value::from(sid.col_idx as i64), ] - .into(), + .into(), ), Expr::Apply(op, args) => build_tagged_value( "Apply", @@ -254,7 +292,7 @@ impl<'a> From> for Value<'a> { Value::from(op.name().to_string()), args.into_iter().map(Value::from).collect::>().into(), ] - .into(), + .into(), ), Expr::ApplyAgg(op, a_args, args) => build_tagged_value( "ApplyAgg", @@ -267,7 +305,7 @@ impl<'a> From> for Value<'a> { .into(), args.into_iter().map(Value::from).collect::>().into(), ] - .into(), + .into(), ), Expr::FieldAcc(f, v) => { build_tagged_value("FieldAcc", vec![f.into(), Value::from(*v)].into()) @@ -279,7 +317,6 @@ impl<'a> From> for Value<'a> { } } - fn build_tagged_value<'a>(tag: &'static str, val: Value<'a>) -> Value<'a> { Value::Dict(BTreeMap::from([(tag.into(), val)])) } diff --git a/src/data/expr_parser.rs b/src/data/expr_parser.rs index 4e645a29..a61e50d6 100644 --- a/src/data/expr_parser.rs +++ b/src/data/expr_parser.rs @@ -1,16 +1,19 @@ -use std::borrow::Cow; -use std::collections::BTreeMap; -use pest::prec_climber::{Assoc, Operator, PrecClimber}; -use std::result; -use std::sync::Arc; -use lazy_static::lazy_static; -use pest::iterators::Pair; use crate::data::expr::{Expr, ExprError}; -use crate::data::op::{Op, OpAdd, OpAnd, OpCoalesce, OpConcat, OpDiv, OpEq, OpGe, OpGt, OpLe, OpLt, OpMerge, OpMinus, OpMod, OpMul, OpNe, OpNegate, OpOr, OpPow, OpStrCat, OpSub, UnresolvedOp}; +use crate::data::op::{ + Op, OpAdd, OpAnd, OpCoalesce, OpConcat, OpDiv, OpEq, OpGe, OpGt, OpLe, OpLt, OpMerge, OpMinus, + OpMod, OpMul, OpNe, OpNegate, OpOr, OpPow, OpStrCat, OpSub, UnresolvedOp, +}; use crate::data::value::Value; use crate::parser::number::parse_int; +use crate::parser::text_identifier::parse_string; use crate::parser::Rule; -use crate::parser::text_identifier::{parse_string}; +use lazy_static::lazy_static; +use pest::iterators::Pair; +use pest::prec_climber::{Assoc, Operator, PrecClimber}; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::result; +use std::sync::Arc; #[derive(thiserror::Error, Debug)] pub(crate) enum ExprParseError { @@ -106,7 +109,9 @@ fn build_expr_primary(pair: Pair) -> Result { Ok(Expr::Apply(op, vec![term])) } - Rule::pos_int => Ok(Expr::Const(Value::Int(pair.as_str().replace('_', "").parse::()?))), + Rule::pos_int => Ok(Expr::Const(Value::Int( + pair.as_str().replace('_', "").parse::()?, + ))), Rule::hex_pos_int => Ok(Expr::Const(Value::Int(parse_int(pair.as_str(), 16)))), Rule::octo_pos_int => Ok(Expr::Const(Value::Int(parse_int(pair.as_str(), 8)))), Rule::bin_pos_int => Ok(Expr::Const(Value::Int(parse_int(pair.as_str(), 2)))), @@ -167,10 +172,8 @@ fn build_expr_primary(pair: Pair) -> Result { } Rule::scoped_accessor => { let name = parse_string(p.into_inner().next().unwrap())?; - let val = Expr::FieldAcc( - name.clone().into(), - Expr::Variable("_".into()).into(), - ); + let val = + Expr::FieldAcc(name.clone().into(), Expr::Variable("_".into()).into()); collected.insert(name.into(), val); } Rule::spreading => { @@ -214,7 +217,6 @@ fn build_expr_primary(pair: Pair) -> Result { } } - fn build_expr_infix<'a>( lhs: Result>, op: Pair, @@ -244,13 +246,12 @@ fn build_expr_infix<'a>( Ok(Expr::Apply(op, vec![lhs, rhs])) } - #[cfg(test)] mod tests { use super::*; + use crate::data::expr::StaticExpr; use crate::parser::CozoParser; use pest::Parser; - use crate::data::expr::StaticExpr; fn parse_expr_from_str(s: &str) -> Result { let pair = CozoParser::parse(Rule::expr, s.as_ref()) @@ -272,58 +273,76 @@ mod tests { #[test] fn parse_literals() { - assert_eq!(parse_expr_from_str("1").unwrap(), Expr::Const(Value::Int(1))); - assert_eq!(parse_expr_from_str("12_3").unwrap(), Expr::Const(Value::Int(123))); - assert_eq!(parse_expr_from_str("0xaf").unwrap(), Expr::Const(Value::Int(0xaf))); + assert_eq!( + parse_expr_from_str("1").unwrap(), + Expr::Const(Value::Int(1)) + ); + assert_eq!( + parse_expr_from_str("12_3").unwrap(), + Expr::Const(Value::Int(123)) + ); + assert_eq!( + parse_expr_from_str("0xaf").unwrap(), + Expr::Const(Value::Int(0xaf)) + ); assert_eq!( parse_expr_from_str("0xafcE_f").unwrap(), - Expr::Const(Value::Int(0xafcef) - )); + Expr::Const(Value::Int(0xafcef)) + ); assert_eq!( parse_expr_from_str("0o1234_567").unwrap(), - Expr::Const(Value::Int(0o1234567) - )); + Expr::Const(Value::Int(0o1234567)) + ); assert_eq!( parse_expr_from_str("0o0001234_567").unwrap(), - Expr::Const(Value::Int(0o1234567) - )); + Expr::Const(Value::Int(0o1234567)) + ); assert_eq!( parse_expr_from_str("0b101010").unwrap(), - Expr::Const(Value::Int(0b101010) - )); + Expr::Const(Value::Int(0b101010)) + ); assert_eq!( parse_expr_from_str("0.0").unwrap(), - Expr::Const(Value::Float((0.).into()) - )); + Expr::Const(Value::Float((0.).into())) + ); assert_eq!( parse_expr_from_str("10.022_3").unwrap(), - Expr::Const(Value::Float(10.0223.into()) - )); + Expr::Const(Value::Float(10.0223.into())) + ); assert_eq!( parse_expr_from_str("10.022_3e-100").unwrap(), - Expr::Const(Value::Float(10.0223e-100.into()) - )); + Expr::Const(Value::Float(10.0223e-100.into())) + ); - assert_eq!(parse_expr_from_str("null").unwrap(), Expr::Const(Value::Null)); - assert_eq!(parse_expr_from_str("true").unwrap(), Expr::Const(Value::Bool(true))); - assert_eq!(parse_expr_from_str("false").unwrap(), Expr::Const(Value::Bool(false))); + assert_eq!( + parse_expr_from_str("null").unwrap(), + Expr::Const(Value::Null) + ); + assert_eq!( + parse_expr_from_str("true").unwrap(), + Expr::Const(Value::Bool(true)) + ); + assert_eq!( + parse_expr_from_str("false").unwrap(), + Expr::Const(Value::Bool(false)) + ); assert_eq!( parse_expr_from_str(r#""x \n \ty \"""#).unwrap(), - Expr::Const(Value::Text(Cow::Borrowed("x \n \ty \"")) - )); + Expr::Const(Value::Text(Cow::Borrowed("x \n \ty \""))) + ); assert_eq!( parse_expr_from_str(r#""x'""#).unwrap(), - Expr::Const(Value::Text("x'".into()) - )); + Expr::Const(Value::Text("x'".into())) + ); assert_eq!( parse_expr_from_str(r#"'"x"'"#).unwrap(), - Expr::Const(Value::Text(r##""x""##.into()) - )); + Expr::Const(Value::Text(r##""x""##.into())) + ); assert_eq!( parse_expr_from_str(r#####"r###"x"yz"###"#####).unwrap(), - (Expr::Const(Value::Text(r##"x"yz"##.into())) - )); + (Expr::Const(Value::Text(r##"x"yz"##.into()))) + ); } #[test] diff --git a/src/data/op.rs b/src/data/op.rs index 101e9e9a..c2636e1a 100644 --- a/src/data/op.rs +++ b/src/data/op.rs @@ -56,7 +56,6 @@ impl Op for OpSub { } } - pub(crate) struct OpMul; impl Op for OpMul { @@ -69,7 +68,6 @@ impl Op for OpMul { } } - pub(crate) struct OpDiv; impl Op for OpDiv { @@ -82,7 +80,6 @@ impl Op for OpDiv { } } - pub(crate) struct OpStrCat; impl Op for OpStrCat { @@ -95,7 +92,6 @@ impl Op for OpStrCat { } } - pub(crate) struct OpEq; impl Op for OpEq { @@ -108,7 +104,6 @@ impl Op for OpEq { } } - pub(crate) struct OpNe; impl Op for OpNe { @@ -121,7 +116,6 @@ impl Op for OpNe { } } - pub(crate) struct OpOr; impl Op for OpOr { @@ -134,8 +128,6 @@ impl Op for OpOr { } } - - pub(crate) struct OpAnd; impl Op for OpAnd { @@ -172,7 +164,6 @@ impl Op for OpGt { } } - pub(crate) struct OpGe; impl Op for OpGe { @@ -245,7 +236,6 @@ impl Op for OpNegate { } } - pub(crate) struct OpMinus; impl Op for OpMinus { @@ -294,7 +284,6 @@ impl Op for OpConcat { } } - pub(crate) struct OpMerge; impl Op for OpMerge { @@ -305,4 +294,4 @@ impl Op for OpMerge { fn name(&self) -> &str { "merge" } -} \ No newline at end of file +} diff --git a/src/data/tuple_set.rs b/src/data/tuple_set.rs index d768ab04..e076f47b 100644 --- a/src/data/tuple_set.rs +++ b/src/data/tuple_set.rs @@ -67,9 +67,14 @@ pub(crate) struct TupleSetIdx { pub(crate) col_idx: usize, } - impl Debug for TupleSetIdx { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "@{}{}{}", self.t_set, if self.is_key { 'K' } else { 'D' }, self.col_idx) + write!( + f, + "@{}{}{}", + self.t_set, + if self.is_key { 'K' } else { 'D' }, + self.col_idx + ) } -} \ No newline at end of file +} diff --git a/src/data/typing.rs b/src/data/typing.rs index 000b0fe3..567ae6a1 100644 --- a/src/data/typing.rs +++ b/src/data/typing.rs @@ -212,7 +212,6 @@ impl TryFrom> for Typing { } } - #[cfg(test)] mod tests { use super::*;