tests for expression parsing

main
Ziyang Hu 2 years ago
parent 2f4368fd9b
commit 57937b6f56

@ -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;

@ -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::<Vec<_>>().join(" ")),
args.iter()
.map(|v| format!("{:?}", v))
.collect::<Vec<_>>()
.join(" ")
),
Expr::ApplyAgg(op, a_args, args) => write!(
f, "[|{} {} | {}|]",
f,
"[|{} {} | {}|]",
op.name(),
a_args.iter().map(|v| format!("{:?}", v)).collect::<Vec<_>>().join(" "),
args.iter().map(|v| format!("{:?}", v)).collect::<Vec<_>>().join(" ")),
a_args
.iter()
.map(|v| format!("{:?}", v))
.collect::<Vec<_>>()
.join(" "),
args.iter()
.map(|v| format!("{:?}", v))
.collect::<Vec<_>>()
.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<Value<'a>> 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::<Result<Vec<_>>>()?))
Ok(Expr::List(
l.into_iter()
.map(Expr::try_from)
.collect::<Result<Vec<_>>>()?,
))
}
"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::<Result<BTreeMap<_, _>>>()?))
}
v => return Err(ExprError::ConversionFailure(Value::Dict(BTreeMap::from([(k, v)])).to_static()))
})
.collect::<Result<BTreeMap<_, _>>>()?,
)),
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<Value<'a>> 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::<Result<Vec<_>>>()?;
let args = l
.into_iter()
.map(Expr::try_from)
.collect::<Result<Vec<_>>>()?;
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::<Result<Vec<_>>>()?;
let a_args = l
.into_iter()
.map(Expr::try_from)
.collect::<Result<Vec<_>>>()?;
let l = extract_list_from_value(ll.next().unwrap(), 0)?;
let args = l.into_iter().map(Expr::try_from).collect::<Result<Vec<_>>>()?;
let args = l
.into_iter()
.map(Expr::try_from)
.collect::<Result<Vec<_>>>()?;
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<Value<'a>> 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<Expr<'a>> 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<Expr<'a>> 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<Expr<'a>> for Value<'a> {
Value::from(op.name().to_string()),
args.into_iter().map(Value::from).collect::<Vec<_>>().into(),
]
.into(),
.into(),
),
Expr::ApplyAgg(op, a_args, args) => build_tagged_value(
"ApplyAgg",
@ -267,7 +305,7 @@ impl<'a> From<Expr<'a>> for Value<'a> {
.into(),
args.into_iter().map(Value::from).collect::<Vec<_>>().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<Expr<'a>> for Value<'a> {
}
}
fn build_tagged_value<'a>(tag: &'static str, val: Value<'a>) -> Value<'a> {
Value::Dict(BTreeMap::from([(tag.into(), val)]))
}

@ -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<Rule>) -> Result<Expr> {
Ok(Expr::Apply(op, vec![term]))
}
Rule::pos_int => Ok(Expr::Const(Value::Int(pair.as_str().replace('_', "").parse::<i64>()?))),
Rule::pos_int => Ok(Expr::Const(Value::Int(
pair.as_str().replace('_', "").parse::<i64>()?,
))),
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<Rule>) -> Result<Expr> {
}
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<Rule>) -> Result<Expr> {
}
}
fn build_expr_infix<'a>(
lhs: Result<Expr<'a>>,
op: Pair<Rule>,
@ -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<Expr> {
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]

@ -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"
}
}
}

@ -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
)
}
}
}

@ -212,7 +212,6 @@ impl TryFrom<Pair<'_, Rule>> for Typing {
}
}
#[cfg(test)]
mod tests {
use super::*;

Loading…
Cancel
Save