feat!(core): Use new AST structure
Derive Expr methods using a derive proc-macro. These macros are present in the `argus-derive` crate, but the traits are defined in `argus-core`
This commit is contained in:
parent
70c5a50d22
commit
1c79847a77
22 changed files with 958 additions and 702 deletions
5
argus-derive/src/expr.rs
Normal file
5
argus-derive/src/expr.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod bool_expr;
|
||||
mod num_expr;
|
||||
|
||||
pub use bool_expr::*;
|
||||
pub use num_expr::*;
|
||||
93
argus-derive/src/expr/bool_expr.rs
Normal file
93
argus-derive/src/expr/bool_expr.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use proc_macro::{self, TokenStream};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::DeriveInput;
|
||||
|
||||
/// Implement [`IsBoolExpr`](argus_core::expr::traits::IsBoolExpr) and other Boolean
|
||||
/// operations (`Not`, `BitOr`, and `BitAnd`) for the input identifier.
|
||||
pub fn bool_expr_impl(input: DeriveInput) -> TokenStream {
|
||||
let ident = &input.ident;
|
||||
let marker_impl = quote! {
|
||||
impl ::argus_core::expr::traits::IsBoolExpr for #ident {}
|
||||
};
|
||||
|
||||
let not_impl = impl_bool_not(&input);
|
||||
let or_impl = impl_bool_and_or(&input, BoolOp::Or);
|
||||
let and_impl = impl_bool_and_or(&input, BoolOp::And);
|
||||
|
||||
let output = quote! {
|
||||
#marker_impl
|
||||
#not_impl
|
||||
#or_impl
|
||||
#and_impl
|
||||
};
|
||||
|
||||
output.into()
|
||||
}
|
||||
|
||||
fn impl_bool_not(input: &DeriveInput) -> impl ToTokens {
|
||||
let ident = &input.ident;
|
||||
quote! {
|
||||
impl ::core::ops::Not for #ident {
|
||||
type Output = ::argus_core::expr::BoolExpr;
|
||||
|
||||
#[inline]
|
||||
fn not(self) -> Self::Output {
|
||||
(::argus_core::expr::Not { arg: Box::new(self.into()) }).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum BoolOp {
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
fn impl_bool_and_or(input: &DeriveInput, op: BoolOp) -> impl ToTokens {
|
||||
let ident = &input.ident;
|
||||
let (trait_fn, trait_name, enum_id) = match op {
|
||||
BoolOp::And => {
|
||||
let trait_name = Ident::new("BitAnd", Span::call_site());
|
||||
let trait_fn = Ident::new("bitand", Span::call_site());
|
||||
let enum_id = Ident::new("And", Span::call_site());
|
||||
(trait_fn, trait_name, enum_id)
|
||||
}
|
||||
BoolOp::Or => {
|
||||
let trait_name = Ident::new("BitOr", Span::call_site());
|
||||
let trait_fn = Ident::new("bitor", Span::call_site());
|
||||
let enum_id = Ident::new("Or", Span::call_site());
|
||||
(trait_fn, trait_name, enum_id)
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
impl ::core::ops::#trait_name for #ident {
|
||||
type Output = ::argus_core::expr::BoolExpr;
|
||||
|
||||
#[inline]
|
||||
fn #trait_fn(self, other: Self) -> Self::Output {
|
||||
use ::argus_core::expr::BoolExpr;
|
||||
use ::argus_core::expr::#enum_id;
|
||||
let lhs: BoolExpr = self.into();
|
||||
let rhs: BoolExpr = other.into();
|
||||
|
||||
let expr = match (lhs, rhs) {
|
||||
(BoolExpr::#enum_id(#enum_id { args: mut left }), BoolExpr::#enum_id(#enum_id { args: mut right })) => {
|
||||
left.append(&mut right);
|
||||
#enum_id { args: left }
|
||||
}
|
||||
(BoolExpr::#enum_id(#enum_id { mut args }), other) | (other, BoolExpr::#enum_id(#enum_id { mut args })) => {
|
||||
args.push(other);
|
||||
#enum_id { args }
|
||||
}
|
||||
(left, right) => {
|
||||
let args = vec![left, right];
|
||||
#enum_id { args }
|
||||
}
|
||||
};
|
||||
expr.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
156
argus-derive/src/expr/num_expr.rs
Normal file
156
argus-derive/src/expr/num_expr.rs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
use proc_macro::{self, TokenStream};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::DeriveInput;
|
||||
|
||||
/// Implement [`IsNumExpr`](argus_core::expr::traits::IsNumExpr) and other Numean
|
||||
/// operations (`Neg`, `Add`, `Mul`, `Sub`, and `Div`) for the input identifier.
|
||||
pub fn num_expr_impl(input: DeriveInput) -> TokenStream {
|
||||
let ident = &input.ident;
|
||||
let marker_impl = quote! {
|
||||
impl ::argus_core::expr::traits::IsNumExpr for #ident {}
|
||||
};
|
||||
|
||||
let neg_impl = impl_num_neg(&input);
|
||||
let mul_impl = impl_nary_op(&input, NumOp::Mul);
|
||||
let add_impl = impl_nary_op(&input, NumOp::Add);
|
||||
let sub_impl = impl_sub(&input);
|
||||
let div_impl = impl_div(&input);
|
||||
|
||||
let output = quote! {
|
||||
#marker_impl
|
||||
#neg_impl
|
||||
#mul_impl
|
||||
#add_impl
|
||||
#sub_impl
|
||||
#div_impl
|
||||
};
|
||||
|
||||
output.into()
|
||||
}
|
||||
|
||||
fn impl_num_neg(input: &DeriveInput) -> impl ToTokens {
|
||||
let ident = &input.ident;
|
||||
quote! {
|
||||
impl ::core::ops::Neg for #ident {
|
||||
type Output = ::argus_core::expr::NumExpr;
|
||||
|
||||
#[inline]
|
||||
fn neg(self) -> Self::Output {
|
||||
(::argus_core::expr::Neg { arg: Box::new(self.into()) }).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum NumOp {
|
||||
Add,
|
||||
Mul,
|
||||
}
|
||||
|
||||
impl NumOp {
|
||||
fn get_trait_name(self) -> Ident {
|
||||
match self {
|
||||
NumOp::Add => Ident::new("Add", Span::call_site()),
|
||||
NumOp::Mul => Ident::new("Mul", Span::call_site()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_trait_fn(self) -> Ident {
|
||||
match self {
|
||||
NumOp::Add => Ident::new("add", Span::call_site()),
|
||||
NumOp::Mul => Ident::new("mul", Span::call_site()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_expr_name(self) -> Ident {
|
||||
match self {
|
||||
NumOp::Add => Ident::new("Add", Span::call_site()),
|
||||
NumOp::Mul => Ident::new("Mul", Span::call_site()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_nary_op(input: &DeriveInput, op: NumOp) -> impl ToTokens {
|
||||
let ident = &input.ident;
|
||||
let trait_name = op.get_trait_name();
|
||||
let trait_fn = op.get_trait_fn();
|
||||
let node_name = op.get_expr_name();
|
||||
quote! {
|
||||
impl<T> ::core::ops::#trait_name<T> for #ident
|
||||
where
|
||||
T: ::core::convert::Into<::argus_core::expr::NumExpr>
|
||||
{
|
||||
type Output = ::argus_core::expr::NumExpr;
|
||||
|
||||
#[inline]
|
||||
fn #trait_fn(self, other: T) -> Self::Output {
|
||||
use ::argus_core::expr::NumExpr;
|
||||
use ::argus_core::expr::#node_name;
|
||||
let lhs: NumExpr = self.into();
|
||||
let rhs: NumExpr = other.into();
|
||||
|
||||
let expr = match (lhs, rhs) {
|
||||
(NumExpr::#node_name(#node_name { args: mut left }), NumExpr::#node_name(#node_name { args: mut right })) => {
|
||||
left.append(&mut right);
|
||||
#node_name { args: left }
|
||||
}
|
||||
(NumExpr::#node_name(#node_name { mut args }), other) | (other, NumExpr::#node_name(#node_name { mut args })) => {
|
||||
args.push(other);
|
||||
#node_name { args }
|
||||
}
|
||||
(left, right) => {
|
||||
let args = vec![left, right];
|
||||
#node_name { args }
|
||||
}
|
||||
};
|
||||
expr.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_sub(input: &DeriveInput) -> impl ToTokens {
|
||||
let ident = &input.ident;
|
||||
quote! {
|
||||
impl<T> ::core::ops::Sub<T> for #ident
|
||||
where
|
||||
T: ::core::convert::Into<::argus_core::expr::NumExpr>
|
||||
{
|
||||
type Output = ::argus_core::expr::NumExpr;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, other: T) -> Self::Output {
|
||||
use ::argus_core::expr::Sub;
|
||||
let expr = Sub {
|
||||
lhs: Box::new(self.into()),
|
||||
rhs: Box::new(other.into())
|
||||
};
|
||||
expr.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_div(input: &DeriveInput) -> impl ToTokens {
|
||||
let ident = &input.ident;
|
||||
quote! {
|
||||
impl<T> ::core::ops::Div<T> for #ident
|
||||
where
|
||||
T: ::core::convert::Into<::argus_core::expr::NumExpr>
|
||||
{
|
||||
type Output = ::argus_core::expr::NumExpr;
|
||||
|
||||
#[inline]
|
||||
fn div(self, other: T) -> Self::Output {
|
||||
use ::argus_core::expr::Div;
|
||||
let expr = Div {
|
||||
dividend: Box::new(self.into()),
|
||||
divisor: Box::new(other.into())
|
||||
};
|
||||
expr.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
argus-derive/src/lib.rs
Normal file
18
argus-derive/src/lib.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use proc_macro::{self, TokenStream};
|
||||
use syn::parse_macro_input;
|
||||
|
||||
mod expr;
|
||||
|
||||
use expr::{bool_expr_impl, num_expr_impl};
|
||||
|
||||
#[proc_macro_derive(BoolExpr)]
|
||||
pub fn bool_expr(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input);
|
||||
bool_expr_impl(input)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(NumExpr)]
|
||||
pub fn num_expr(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input);
|
||||
num_expr_impl(input)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue