Simplify codegen.

This commit is contained in:
Stephen Chung 2020-12-24 21:28:40 +08:00
parent 363085efc3
commit 809b813def
7 changed files with 77 additions and 73 deletions

View File

@ -3,7 +3,7 @@ use syn::{
spanned::Spanned, spanned::Spanned,
}; };
#[derive(Debug)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum ExportScope { pub enum ExportScope {
PubOnly, PubOnly,
Prefix(String), Prefix(String),
@ -22,12 +22,14 @@ pub trait ExportedParams: Sized {
fn from_info(info: ExportInfo) -> syn::Result<Self>; fn from_info(info: ExportInfo) -> syn::Result<Self>;
} }
#[derive(Debug, Clone)]
pub struct AttrItem { pub struct AttrItem {
pub key: proc_macro2::Ident, pub key: proc_macro2::Ident,
pub value: Option<syn::LitStr>, pub value: Option<syn::LitStr>,
pub span: proc_macro2::Span, pub span: proc_macro2::Span,
} }
#[derive(Debug, Clone)]
pub struct ExportInfo { pub struct ExportInfo {
pub item_span: proc_macro2::Span, pub item_span: proc_macro2::Span,
pub items: Vec<AttrItem>, pub items: Vec<AttrItem>,

View File

@ -22,23 +22,30 @@ use crate::attrs::{ExportInfo, ExportScope, ExportedParams};
#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)] #[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)]
pub enum FnNamespaceAccess { pub enum FnNamespaceAccess {
Unset,
Global, Global,
Internal, Internal,
} }
#[derive(Clone, Debug, Eq, PartialEq)] impl Default for FnNamespaceAccess {
fn default() -> Self {
Self::Unset
}
}
#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)]
pub enum Index { pub enum Index {
Get, Get,
Set, Set,
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Property { pub enum Property {
Get(syn::Ident), Get(syn::Ident),
Set(syn::Ident), Set(syn::Ident),
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum FnSpecialAccess { pub enum FnSpecialAccess {
None, None,
Index(Index), Index(Index),
@ -101,7 +108,7 @@ pub(crate) struct ExportedFnParams {
pub return_raw: bool, pub return_raw: bool,
pub skip: bool, pub skip: bool,
pub special: FnSpecialAccess, pub special: FnSpecialAccess,
pub namespace: Option<FnNamespaceAccess>, pub namespace: FnNamespaceAccess,
pub span: Option<proc_macro2::Span>, pub span: Option<proc_macro2::Span>,
} }
@ -138,7 +145,7 @@ impl ExportedParams for ExportedFnParams {
let mut name = Vec::new(); let mut name = Vec::new();
let mut return_raw = false; let mut return_raw = false;
let mut skip = false; let mut skip = false;
let mut namespace = None; let mut namespace = FnNamespaceAccess::Unset;
let mut special = FnSpecialAccess::None; let mut special = FnSpecialAccess::None;
for attr in attrs { for attr in attrs {
let crate::attrs::AttrItem { let crate::attrs::AttrItem {
@ -226,22 +233,16 @@ impl ExportedParams for ExportedFnParams {
("global", Some(s)) | ("internal", Some(s)) => { ("global", Some(s)) | ("internal", Some(s)) => {
return Err(syn::Error::new(s.span(), "extraneous value")) return Err(syn::Error::new(s.span(), "extraneous value"))
} }
("global", None) => { ("global", None) => match namespace {
if let Some(ns) = namespace { FnNamespaceAccess::Unset => namespace = FnNamespaceAccess::Global,
if ns != FnNamespaceAccess::Global { FnNamespaceAccess::Global => (),
return Err(syn::Error::new(key.span(), "conflicting namespace")); _ => return Err(syn::Error::new(key.span(), "conflicting namespace")),
} },
} ("internal", None) => match namespace {
namespace = Some(FnNamespaceAccess::Global); FnNamespaceAccess::Unset => namespace = FnNamespaceAccess::Internal,
} FnNamespaceAccess::Internal => (),
("internal", None) => { _ => return Err(syn::Error::new(key.span(), "conflicting namespace")),
if let Some(ns) = namespace { },
if ns != FnNamespaceAccess::Internal {
return Err(syn::Error::new(key.span(), "conflicting namespace"));
}
}
namespace = Some(FnNamespaceAccess::Internal);
}
(attr, _) => { (attr, _) => {
return Err(syn::Error::new( return Err(syn::Error::new(
key.span(), key.span(),

View File

@ -19,9 +19,9 @@ use std::borrow::Cow;
use crate::attrs::{AttrItem, ExportInfo, ExportScope, ExportedParams}; use crate::attrs::{AttrItem, ExportInfo, ExportScope, ExportedParams};
use crate::function::ExportedFnParams; use crate::function::ExportedFnParams;
#[derive(Debug, Default)] #[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
pub(crate) struct ExportedModParams { pub(crate) struct ExportedModParams {
pub name: Option<String>, pub name: String,
skip: bool, skip: bool,
pub scope: ExportScope, pub scope: ExportScope,
} }
@ -49,21 +49,32 @@ impl ExportedParams for ExportedModParams {
fn from_info(info: ExportInfo) -> syn::Result<Self> { fn from_info(info: ExportInfo) -> syn::Result<Self> {
let ExportInfo { items: attrs, .. } = info; let ExportInfo { items: attrs, .. } = info;
let mut name = None; let mut name = Default::default();
let mut skip = false; let mut skip = false;
let mut scope = ExportScope::default(); let mut scope = None;
for attr in attrs { for attr in attrs {
let AttrItem { key, value, .. } = attr; let AttrItem { key, value, .. } = attr;
match (key.to_string().as_ref(), value) { match (key.to_string().as_ref(), value) {
("name", Some(s)) => name = Some(s.value()), ("name", Some(s)) => {
let new_name = s.value();
if name == new_name {
return Err(syn::Error::new(key.span(), "conflicting name"));
}
name = new_name;
}
("name", None) => return Err(syn::Error::new(key.span(), "requires value")), ("name", None) => return Err(syn::Error::new(key.span(), "requires value")),
("skip", None) => skip = true, ("skip", None) => skip = true,
("skip", Some(s)) => return Err(syn::Error::new(s.span(), "extraneous value")), ("skip", Some(s)) => return Err(syn::Error::new(s.span(), "extraneous value")),
("export_prefix", Some(s)) => scope = ExportScope::Prefix(s.value()),
("export_prefix", Some(_)) | ("export_all", None) if scope.is_some() => {
return Err(syn::Error::new(key.span(), "duplicate export scope"));
}
("export_prefix", Some(s)) => scope = Some(ExportScope::Prefix(s.value())),
("export_prefix", None) => { ("export_prefix", None) => {
return Err(syn::Error::new(key.span(), "requires value")) return Err(syn::Error::new(key.span(), "requires value"))
} }
("export_all", None) => scope = ExportScope::All, ("export_all", None) => scope = Some(ExportScope::All),
("export_all", Some(s)) => { ("export_all", Some(s)) => {
return Err(syn::Error::new(s.span(), "extraneous value")) return Err(syn::Error::new(s.span(), "extraneous value"))
} }
@ -79,7 +90,7 @@ impl ExportedParams for ExportedModParams {
Ok(ExportedModParams { Ok(ExportedModParams {
name, name,
skip, skip,
scope, scope: scope.unwrap_or_default(),
..Default::default() ..Default::default()
}) })
} }
@ -87,7 +98,7 @@ impl ExportedParams for ExportedModParams {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Module { pub(crate) struct Module {
mod_all: Option<syn::ItemMod>, mod_all: syn::ItemMod,
fns: Vec<ExportedFn>, fns: Vec<ExportedFn>,
consts: Vec<ExportedConst>, consts: Vec<ExportedConst>,
submodules: Vec<Module>, submodules: Vec<Module>,
@ -183,7 +194,7 @@ impl Parse for Module {
fns = new_vec![]; fns = new_vec![];
} }
Ok(Module { Ok(Module {
mod_all: Some(mod_all), mod_all,
fns, fns,
consts, consts,
submodules, submodules,
@ -194,39 +205,27 @@ impl Parse for Module {
#[allow(dead_code)] #[allow(dead_code)]
impl Module { impl Module {
pub fn attrs(&self) -> Option<&Vec<syn::Attribute>> { pub fn attrs(&self) -> &Vec<syn::Attribute> {
self.mod_all.as_ref().map(|m| &m.attrs) &self.mod_all.attrs
} }
pub fn module_name(&self) -> Option<&syn::Ident> { pub fn module_name(&self) -> &syn::Ident {
self.mod_all.as_ref().map(|m| &m.ident) &self.mod_all.ident
} }
pub fn exported_name(&self) -> Option<Cow<str>> { pub fn exported_name(&self) -> Cow<str> {
if let Some(ref s) = self.params.name { if !self.params.name.is_empty() {
Some(s.into()) self.params.name.as_str().into()
} else { } else {
self.module_name().map(|m| m.to_string().into()) self.module_name().to_string().into()
} }
} }
pub fn update_scope(&mut self, parent_scope: &ExportScope) { pub fn update_scope(&mut self, parent_scope: &ExportScope) {
let keep = match (self.params.skip, parent_scope) { let keep = match (self.params.skip, parent_scope) {
(true, _) => false, (true, _) => false,
(_, ExportScope::PubOnly) => { (_, ExportScope::PubOnly) => matches!(self.mod_all.vis, syn::Visibility::Public(_)),
if let Some(ref mod_all) = self.mod_all { (_, ExportScope::Prefix(s)) => self.mod_all.ident.to_string().starts_with(s),
matches!(mod_all.vis, syn::Visibility::Public(_))
} else {
false
}
}
(_, ExportScope::Prefix(s)) => {
if let Some(ref mod_all) = self.mod_all {
mod_all.ident.to_string().starts_with(s)
} else {
false
}
}
(_, ExportScope::All) => true, (_, ExportScope::All) => true,
}; };
self.params.skip = !keep; self.params.skip = !keep;
@ -249,14 +248,13 @@ impl Module {
// Extract the current structure of the module. // Extract the current structure of the module.
let Module { let Module {
mod_all, mut mod_all,
mut fns, mut fns,
consts, consts,
mut submodules, mut submodules,
params, params,
.. ..
} = self; } = self;
let mut mod_all = mod_all.unwrap();
let mod_name = mod_all.ident.clone(); let mod_name = mod_all.ident.clone();
let (_, orig_content) = mod_all.content.take().unwrap(); let (_, orig_content) = mod_all.content.take().unwrap();
let mod_attrs = mem::take(&mut mod_all.attrs); let mod_attrs = mem::take(&mut mod_all.attrs);
@ -299,8 +297,8 @@ impl Module {
} }
} }
pub fn name(&self) -> Option<&syn::Ident> { pub fn name(&self) -> &syn::Ident {
self.mod_all.as_ref().map(|m| &m.ident) &self.mod_all.ident
} }
pub fn consts(&self) -> &[ExportedConst] { pub fn consts(&self) -> &[ExportedConst] {
@ -317,10 +315,10 @@ impl Module {
pub fn content(&self) -> Option<&Vec<syn::Item>> { pub fn content(&self) -> Option<&Vec<syn::Item>> {
match self.mod_all { match self.mod_all {
Some(syn::ItemMod { syn::ItemMod {
content: Some((_, ref vec)), content: Some((_, ref vec)),
.. ..
}) => Some(vec), } => Some(vec),
_ => None, _ => None,
} }
} }

View File

@ -18,6 +18,7 @@ pub(crate) fn generated_module_path(
} }
type RegisterMacroInput = (syn::Expr, proc_macro2::TokenStream, syn::Path); type RegisterMacroInput = (syn::Expr, proc_macro2::TokenStream, syn::Path);
pub fn parse_register_macro( pub fn parse_register_macro(
args: proc_macro::TokenStream, args: proc_macro::TokenStream,
) -> Result<RegisterMacroInput, syn::Error> { ) -> Result<RegisterMacroInput, syn::Error> {

View File

@ -40,15 +40,13 @@ pub(crate) fn generate_body(
if itemmod.skipped() { if itemmod.skipped() {
continue; continue;
} }
let module_name = itemmod.module_name().unwrap(); let module_name = itemmod.module_name();
let exported_name: syn::LitStr = if let Some(name) = itemmod.exported_name() { let exported_name: syn::LitStr = syn::LitStr::new(
syn::LitStr::new(&name, proc_macro2::Span::call_site()) itemmod.exported_name().as_ref(),
} else { proc_macro2::Span::call_site(),
syn::LitStr::new(&module_name.to_string(), proc_macro2::Span::call_site()) );
};
let cfg_attrs: Vec<&syn::Attribute> = itemmod let cfg_attrs: Vec<&syn::Attribute> = itemmod
.attrs() .attrs()
.unwrap()
.iter() .iter()
.filter(|&a| a.path.get_ident().map(|i| *i == "cfg").unwrap_or(false)) .filter(|&a| a.path.get_ident().map(|i| *i == "cfg").unwrap_or(false))
.collect(); .collect();
@ -158,12 +156,14 @@ pub(crate) fn generate_body(
} }
} }
if let Some(ns) = function.params().namespace { match function.params().namespace {
namespace = ns; FnNamespaceAccess::Unset => (),
ns => namespace = ns,
} }
let ns_str = syn::Ident::new( let ns_str = syn::Ident::new(
match namespace { match namespace {
FnNamespaceAccess::Unset => unreachable!(),
FnNamespaceAccess::Global => "Global", FnNamespaceAccess::Global => "Global",
FnNamespaceAccess::Internal => "Internal", FnNamespaceAccess::Internal => "Internal",
}, },
@ -256,11 +256,11 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
} }
for (name, fn_name) in names { for (name, fn_name) in names {
let current_span = itemfn.params().span.as_ref().unwrap(); let current_span = itemfn.params().span.unwrap();
let key = make_key(&name, itemfn); let key = make_key(&name, itemfn);
if let Some(other_span) = renames.insert(key, *current_span) { if let Some(other_span) = renames.insert(key, current_span) {
let mut err = syn::Error::new( let mut err = syn::Error::new(
*current_span, current_span,
format!("duplicate Rhai signature for '{}'", &fn_name), format!("duplicate Rhai signature for '{}'", &fn_name),
); );
err.combine(syn::Error::new( err.combine(syn::Error::new(

View File

@ -291,6 +291,7 @@ fn multiple_fn_rename_test() -> Result<(), Box<EvalAltResult>> {
mod export_by_prefix { mod export_by_prefix {
use rhai::plugin::*; use rhai::plugin::*;
#[export_module(export_prefix = "foo_")] #[export_module(export_prefix = "foo_")]
pub mod my_adds { pub mod my_adds {
use rhai::{FLOAT, INT}; use rhai::{FLOAT, INT};
@ -373,6 +374,7 @@ fn export_by_prefix_test() -> Result<(), Box<EvalAltResult>> {
mod export_all { mod export_all {
use rhai::plugin::*; use rhai::plugin::*;
#[export_module(export_all)] #[export_module(export_all)]
pub mod my_adds { pub mod my_adds {
use rhai::{FLOAT, INT}; use rhai::{FLOAT, INT};

View File

@ -73,8 +73,8 @@ fn one_fn_submodule_nested_attr_test() -> Result<(), Box<EvalAltResult>> {
mod export_nested_by_prefix { mod export_nested_by_prefix {
use rhai::plugin::*; use rhai::plugin::*;
#[export_module(export_prefix = "foo_")]
#[export_module(export_prefix = "foo_")]
pub mod my_adds { pub mod my_adds {
pub mod foo_first_adders { pub mod foo_first_adders {
use rhai::{FLOAT, INT}; use rhai::{FLOAT, INT};