215 lines
5.4 KiB
Rust
215 lines
5.4 KiB
Rust
#![recursion_limit = "128"]
|
|
|
|
extern crate proc_macro;
|
|
|
|
use crate::proc_macro::TokenStream;
|
|
use quote::quote;
|
|
use syn::Data::{Enum, Struct};
|
|
use syn::{self, DeriveInput};
|
|
|
|
#[proc_macro_derive(Node)]
|
|
pub fn node_derive(input: TokenStream) -> TokenStream {
|
|
let ast = syn::parse(input).unwrap();
|
|
impl_node(&ast)
|
|
}
|
|
|
|
fn impl_node(ast: &DeriveInput) -> TokenStream {
|
|
let name = &ast.ident;
|
|
|
|
let next = match ast.data {
|
|
Enum(ref data) => {
|
|
let mut items = quote! {};
|
|
for v in &data.variants {
|
|
let ident = &v.ident;
|
|
let item = quote! {
|
|
#name::#ident(x) => { x.into() },
|
|
};
|
|
items = quote! {
|
|
#items
|
|
#item
|
|
};
|
|
}
|
|
|
|
quote! {
|
|
match self {
|
|
#items
|
|
}
|
|
}
|
|
}
|
|
Struct(_) => {
|
|
quote! {
|
|
(&(self.nodes)).into()
|
|
}
|
|
}
|
|
_ => {
|
|
quote! {
|
|
vec![].into()
|
|
}
|
|
}
|
|
};
|
|
|
|
let gen = quote! {
|
|
impl<'a> Node<'a> for #name {
|
|
fn next(&'a self) -> RefNodes<'a> {
|
|
#next
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a #name> for RefNodes<'a> {
|
|
fn from(x: &'a #name) -> Self {
|
|
vec![RefNode::#name(x)].into()
|
|
}
|
|
}
|
|
|
|
impl From<#name> for AnyNode {
|
|
fn from(x: #name) -> Self {
|
|
AnyNode::#name(x)
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a #name> for RefNode<'a> {
|
|
fn from(x: &'a #name) -> Self {
|
|
RefNode::#name(x)
|
|
}
|
|
}
|
|
|
|
impl core::convert::TryFrom<#name> for Locate {
|
|
type Error = ();
|
|
fn try_from(x: #name) -> Result<Self, Self::Error> {
|
|
Self::try_from(&x)
|
|
}
|
|
}
|
|
|
|
impl<'a> core::convert::TryFrom<&'a #name> for Locate {
|
|
type Error = ();
|
|
fn try_from(x: &'a #name) -> Result<Self, Self::Error> {
|
|
let mut locate: Option<Locate> = None;
|
|
for x in x {
|
|
match x {
|
|
RefNode::Locate(x) => if let Some(loc) = locate {
|
|
assert_eq!(x.offset, loc.offset + loc.len);
|
|
locate = Some(Locate { offset: loc.offset, line: loc.line, len: loc.len + x.len });
|
|
} else {
|
|
locate = Some(*x);
|
|
},
|
|
_ => (),
|
|
}
|
|
}
|
|
locate.ok_or(())
|
|
}
|
|
}
|
|
|
|
impl<'a> IntoIterator for &'a #name {
|
|
type Item = RefNode<'a>;
|
|
type IntoIter = Iter<'a>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
let mut nodes: RefNodes = self.into();
|
|
nodes.0.reverse();
|
|
Iter { next: nodes }
|
|
}
|
|
}
|
|
};
|
|
gen.into()
|
|
}
|
|
|
|
#[proc_macro_derive(AnyNode)]
|
|
pub fn any_node_derive(input: TokenStream) -> TokenStream {
|
|
let ast = syn::parse(input).unwrap();
|
|
impl_any_node(&ast)
|
|
}
|
|
|
|
fn impl_any_node(ast: &DeriveInput) -> TokenStream {
|
|
let ref data = match ast.data {
|
|
Enum(ref data) => data,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let mut try_froms = quote! {};
|
|
let mut from_items = quote! {};
|
|
for v in &data.variants {
|
|
let ident = &v.ident;
|
|
|
|
try_froms = quote! {
|
|
#try_froms
|
|
impl TryFrom<AnyNode> for #ident {
|
|
type Error = ();
|
|
fn try_from(x: AnyNode) -> Result<Self, Self::Error> {
|
|
match x {
|
|
AnyNode::#ident(x) => Ok(x),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
from_items = quote! {
|
|
#from_items
|
|
AnyNode::#ident(x) => RefNode::#ident(&x),
|
|
};
|
|
}
|
|
|
|
let gen = quote! {
|
|
#try_froms
|
|
|
|
impl<'a> From<&'a AnyNode> for RefNode<'a> {
|
|
fn from(x: &'a AnyNode) -> Self {
|
|
match x {
|
|
#from_items
|
|
}
|
|
}
|
|
}
|
|
};
|
|
gen.into()
|
|
}
|
|
|
|
#[proc_macro_derive(RefNode)]
|
|
pub fn ref_node_derive(input: TokenStream) -> TokenStream {
|
|
let ast = syn::parse(input).unwrap();
|
|
impl_ref_node(&ast)
|
|
}
|
|
|
|
fn impl_ref_node(ast: &DeriveInput) -> TokenStream {
|
|
let ref data = match ast.data {
|
|
Enum(ref data) => data,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let mut next_items = quote! {};
|
|
let mut into_iter_items = quote! {};
|
|
for v in &data.variants {
|
|
let ident = &v.ident;
|
|
next_items = quote! {
|
|
#next_items
|
|
RefNode::#ident(x) => x.next(),
|
|
};
|
|
into_iter_items = quote! {
|
|
#into_iter_items
|
|
RefNode::#ident(x) => x.into_iter(),
|
|
};
|
|
}
|
|
|
|
let name = &ast.ident;
|
|
let gen = quote! {
|
|
impl<'a> #name<'a> {
|
|
fn next(&self) -> RefNodes<'a> {
|
|
match self {
|
|
#next_items
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> IntoIterator for #name<'a> {
|
|
type Item = RefNode<'a>;
|
|
type IntoIter = Iter<'a>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
match self {
|
|
#into_iter_items
|
|
}
|
|
}
|
|
}
|
|
};
|
|
gen.into()
|
|
}
|