-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
101 changed files
with
812 additions
and
483 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[package] | ||
name = "rune-alloc-macros" | ||
version = "0.12.3" | ||
authors = ["John-John Tedro <[email protected]>"] | ||
edition = "2021" | ||
rust-version = "1.70" | ||
description = "Macros for the Rune Language, an embeddable dynamic programming language for Rust." | ||
documentation = "https://docs.rs/rune" | ||
readme = "README.md" | ||
homepage = "https://github.com/rune-rs/rune" | ||
repository = "https://github.com/rune-rs/rune" | ||
license = "MIT OR Apache-2.0" | ||
keywords = ["language", "scripting", "scripting-language"] | ||
categories = ["parser-implementations"] | ||
|
||
[dependencies] | ||
syn = { version = "2.0.16", features = ["full"] } | ||
quote = "1.0.27" | ||
proc-macro2 = "1.0.56" | ||
|
||
[lib] | ||
proc-macro = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
use std::cell::RefCell; | ||
|
||
use proc_macro2::Span; | ||
use syn::punctuated::Punctuated; | ||
use syn::spanned::Spanned as _; | ||
|
||
#[derive(Default)] | ||
pub(crate) struct Context { | ||
pub(crate) errors: RefCell<Vec<syn::Error>>, | ||
pub(crate) module: Option<syn::Path>, | ||
} | ||
|
||
impl Context { | ||
/// Construct a new context. | ||
pub(crate) fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
/// Register an error. | ||
pub(crate) fn error(&self, error: syn::Error) { | ||
self.errors.borrow_mut().push(error) | ||
} | ||
|
||
/// Test if context has any errors. | ||
pub(crate) fn has_errors(&self) -> bool { | ||
!self.errors.borrow().is_empty() | ||
} | ||
|
||
/// Convert into errors. | ||
pub(crate) fn into_errors(self) -> Vec<syn::Error> { | ||
self.errors.into_inner() | ||
} | ||
|
||
pub(crate) fn tokens_with_module(&self, module: Option<&syn::Path>) -> Tokens { | ||
let mut default_module; | ||
|
||
let m = match module { | ||
Some(module) => module, | ||
None => match &self.module { | ||
Some(module) => module, | ||
None => { | ||
default_module = syn::Path { | ||
leading_colon: None, | ||
segments: Punctuated::default(), | ||
}; | ||
default_module | ||
.segments | ||
.push(syn::PathSegment::from(syn::Ident::new( | ||
"rune", | ||
Span::call_site(), | ||
))); | ||
&default_module | ||
} | ||
}, | ||
}; | ||
|
||
Tokens { | ||
try_clone: path(m, ["alloc", "clone", "TryClone"]), | ||
alloc: path(m, ["alloc"]), | ||
} | ||
} | ||
} | ||
|
||
fn path<const N: usize>(base: &syn::Path, path: [&'static str; N]) -> syn::Path { | ||
let mut base = base.clone(); | ||
|
||
for s in path { | ||
let ident = syn::Ident::new(s, base.span()); | ||
base.segments.push(syn::PathSegment::from(ident)); | ||
} | ||
|
||
base | ||
} | ||
|
||
pub(crate) struct Tokens { | ||
pub(crate) try_clone: syn::Path, | ||
pub(crate) alloc: syn::Path, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
//! <img alt="rune logo" src="https://raw.githubusercontent.com/rune-rs/rune/main/assets/icon.png" /> | ||
//! <br> | ||
//! <a href="https://github.com/rune-rs/rune"><img alt="github" src="https://img.shields.io/badge/github-rune--rs/rune-8da0cb?style=for-the-badge&logo=github" height="20"></a> | ||
//! <a href="https://crates.io/crates/rune-macros"><img alt="crates.io" src="https://img.shields.io/crates/v/rune-macros.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20"></a> | ||
//! <a href="https://docs.rs/rune-macros"><img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-rune--macros-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20"></a> | ||
//! <a href="https://discord.gg/v5AeNkT"><img alt="chat on discord" src="https://img.shields.io/discord/558644981137670144.svg?logo=discord&style=flat-square" height="20"></a> | ||
//! <br> | ||
//! Minimum support: Rust <b>1.70+</b>. | ||
//! <br> | ||
//! <br> | ||
//! <a href="https://rune-rs.github.io"><b>Visit the site 🌐</b></a> | ||
//! — | ||
//! <a href="https://rune-rs.github.io/book/"><b>Read the book 📖</b></a> | ||
//! <br> | ||
//! <br> | ||
//! | ||
//! Macros for the Rune Language, an embeddable dynamic programming language for Rust. | ||
//! | ||
//! <br> | ||
//! | ||
//! ## Usage | ||
//! | ||
//! This is part of the [Rune Language](https://rune-rs.github.io). | ||
#![allow(clippy::manual_map)] | ||
|
||
extern crate proc_macro; | ||
|
||
mod context; | ||
mod try_clone; | ||
|
||
#[proc_macro_derive(TryClone, attributes(try_clone))] | ||
pub fn try_clone(input: proc_macro::TokenStream) -> proc_macro::TokenStream { | ||
let input = syn::parse_macro_input!(input as syn::DeriveInput); | ||
|
||
try_clone::expand(input) | ||
.unwrap_or_else(to_compile_errors) | ||
.into() | ||
} | ||
|
||
fn to_compile_errors<I>(errors: I) -> proc_macro2::TokenStream | ||
where | ||
I: IntoIterator<Item = syn::Error>, | ||
{ | ||
let compile_errors = errors.into_iter().map(syn::Error::into_compile_error); | ||
::quote::quote!(#(#compile_errors)*) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
use proc_macro2::TokenStream; | ||
use quote::quote; | ||
use syn::parse::Parse; | ||
|
||
use crate::context::{Context, Tokens}; | ||
|
||
pub(super) fn expand(mut input: syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> { | ||
let cx = Context::new(); | ||
let tokens = cx.tokens_with_module(None); | ||
|
||
for a in input.attrs { | ||
if !a.path().is_ident("try_clone") { | ||
continue; | ||
} | ||
|
||
let result = a.parse_nested_meta(|parser| { | ||
if parser.path.is_ident("bound") { | ||
parser.input.parse::<syn::Token![=]>()?; | ||
let content; | ||
syn::braced!(content in parser.input); | ||
let extra = content.parse_terminated(syn::WherePredicate::parse, syn::Token![,])?; | ||
input.generics.make_where_clause().predicates.extend(extra); | ||
return Ok(()); | ||
} | ||
|
||
Err(syn::Error::new( | ||
parser.input.span(), | ||
"unsupported attribute", | ||
)) | ||
}); | ||
|
||
if let Err(error) = result { | ||
cx.error(error); | ||
} | ||
} | ||
|
||
let Tokens { | ||
try_clone, alloc, .. | ||
} = &tokens; | ||
|
||
let implementation = match input.data { | ||
syn::Data::Struct(st) => { | ||
let fields = st.fields.into_iter().enumerate().map(|(index, f)| { | ||
let member = match &f.ident { | ||
Some(ident) => syn::Member::Named(ident.clone()), | ||
None => syn::Member::Unnamed(syn::Index::from(index)), | ||
}; | ||
|
||
let expr = syn::Expr::Verbatim(quote! { #try_clone::try_clone(&self.#member)? }); | ||
|
||
syn::FieldValue { | ||
attrs: Vec::new(), | ||
member, | ||
colon_token: Some(<syn::Token![:]>::default()), | ||
expr, | ||
} | ||
}); | ||
|
||
let name = input.ident; | ||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); | ||
|
||
quote! { | ||
impl #impl_generics #try_clone for #name #ty_generics #where_clause { | ||
fn try_clone(&self) -> #alloc::Result<Self> { | ||
Ok(Self { #(#fields),* }) | ||
} | ||
} | ||
} | ||
} | ||
syn::Data::Enum(en) => { | ||
let name = input.ident; | ||
|
||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); | ||
|
||
let variants = en.variants.into_iter().map(|v| { | ||
let name = v.ident; | ||
|
||
let members = v | ||
.fields | ||
.iter() | ||
.enumerate() | ||
.map(|(index, f)| match &f.ident { | ||
Some(ident) => ( | ||
syn::Member::Named(ident.clone()), | ||
quote::format_ident!("{}", ident), | ||
), | ||
None => ( | ||
syn::Member::Unnamed(syn::Index::from(index)), | ||
quote::format_ident!("_{}", index), | ||
), | ||
}); | ||
|
||
let assigns = members.clone().map(|(member, var)| { | ||
let expr = syn::Expr::Path(syn::ExprPath { | ||
attrs: Vec::new(), | ||
qself: None, | ||
path: syn::Path::from(var), | ||
}); | ||
|
||
syn::FieldValue { | ||
attrs: Vec::new(), | ||
member, | ||
colon_token: Some(<syn::Token![:]>::default()), | ||
expr, | ||
} | ||
}); | ||
|
||
let fields = members.clone().map(|(member, var)| { | ||
let expr = syn::Expr::Verbatim(quote! { #try_clone::try_clone(#var)? }); | ||
|
||
syn::FieldValue { | ||
attrs: Vec::new(), | ||
member, | ||
colon_token: Some(<syn::Token![:]>::default()), | ||
expr, | ||
} | ||
}); | ||
|
||
quote! { | ||
Self::#name { #(#assigns),* } => { | ||
Self::#name { #(#fields),* } | ||
} | ||
} | ||
}); | ||
|
||
quote! { | ||
impl #impl_generics #try_clone for #name #ty_generics #where_clause { | ||
fn try_clone(&self) -> #alloc::Result<Self> { | ||
Ok(match self { | ||
#(#variants),* | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
syn::Data::Union(_) => todo!(), | ||
}; | ||
|
||
if !cx.has_errors() { | ||
return Err(cx.into_errors()); | ||
} | ||
|
||
Ok(implementation) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.