1use proc_macro::TokenStream;
2use unsynn::{
3 AndAnd, DelimitedVec, Either, Equal, Ident, LeftAssocExpr, Literal, NotEqual, OrOr, Parse,
4 ToTokenIter, TrailingDelimiter::Forbidden, quote, unsynn,
5};
6use unsynn::{Colon, Cons, Dollar, LiteralString, ToTokens};
7
8unsynn! {
9 keyword Field = "field";
10 keyword Current = "current";
11 struct ComparisonOp(Either<Equal, NotEqual>);
12 type ComparisonExpr = DelimitedVec<Either<Cons<Dollar, Current>, Cons<Field, Colon, LiteralString>, Literal, Ident>, ComparisonOp, Forbidden, 2, 2>;
13
14 struct CompositeOp(Either<AndAnd, OrOr>);
15 type CompositeExpr = LeftAssocExpr<ComparisonExpr, CompositeOp>;
16
17 type Expr = CompositeExpr;
18}
19
20#[proc_macro]
21pub fn expression(token_stream: TokenStream) -> TokenStream {
22 let expr = Expr::parse(&mut unsynn::TokenStream::from(token_stream).to_token_iter())
23 .unwrap()
24 .0;
25
26 expr.iter().rfold(unsynn::TokenStream::new(), |temp, component| {
27 let ts = component_to_token_stream(&component.value);
28 if let Some(delimiter) = &component.delimiter {
29 let operator = match delimiter.0 {
30 Either::First(_) => quote! {And},
31 Either::Second(_) => quote! {Or},
32 _ => unreachable!(),
33 };
34 quote! {::scalar_expr::Expression::#operator {lhs: Box::new(#ts), rhs: Box::new(#temp)}}
36 } else {
37 ts
38 }
39 }).into()
40}
41
42fn component_to_token_stream(component: &ComparisonExpr) -> unsynn::TokenStream {
43 let operator = match component[0]
44 .delimiter
45 .as_ref()
46 .expect("expected an operator")
47 .0
48 {
49 Either::First(_) => quote! {Equals},
50 Either::Second(_) => quote! {NotEquals},
51 _ => unreachable!(),
52 };
53 let lhs = match &component[0].value {
54 Either::First(_) => quote! {::scalar_expr::Value::CurrentField},
55 Either::Second(Cons { third, .. }) => {
56 quote! {::scalar_expr::Value::Ident(#third)}
57 }
58 Either::Third(val) => {
59 quote! {::scalar_expr::Value::Value(::scalar_expr::to_value(#val).unwrap())}
60 }
61 Either::Fourth(val) => {
62 quote! {::scalar_expr::Value::Value(::scalar_expr::to_value(#val).unwrap())}
63 }
64 };
65 let rhs = match &component[1].value {
66 Either::First(_) => quote! {::scalar_expr::Value::CurrentField},
67 Either::Second(Cons { third, .. }) => {
68 quote! {::scalar_expr::Value::Ident(#third)}
69 }
70 Either::Third(val) => {
71 quote! {::scalar_expr::Value::Value(::scalar_expr::to_value(#val).unwrap())}
72 }
73 Either::Fourth(val) => {
74 quote! {::scalar_expr::Value::Value(::scalar_expr::to_value(#val).unwrap())}
75 }
76 };
77 quote! {::scalar_expr::Expression::#operator {lhs: #lhs, rhs: #rhs}}
78}