use meta item rather than parent name

This commit is contained in:
Jeong YunWon committed 2020-08-23 18:24:46 +09:00
1 parent 9d025b0e4e
commit 8d46a96068
3 files changed
+90 -67

No files matched your search

+32 -24
View File
@@ -90,35 +90,38 @@ impl Class {
}
fn extract_method(
ident: &Ident,
nested: PunctuatedNestedMeta,
item: &Ident,
(meta, nested): (&Ident, PunctuatedNestedMeta),
) -> Result<ClassItem, Diagnostic> {
let item_meta = MethodItemMeta::from_nested("pymethod", &ident, nested.into_iter())?;
let item_meta =
MethodItemMeta::from_nested(item.clone(), meta.clone(), nested.into_iter())?;
Ok(ClassItem::Method {
item_ident: ident.clone(),
item_ident: item.clone(),
py_name: item_meta.method_name()?,
})
}
fn extract_classmethod(
ident: &Ident,
nested: PunctuatedNestedMeta,
item: &Ident,
(meta, nested): (&Ident, PunctuatedNestedMeta),
) -> Result<ClassItem, Diagnostic> {
let item_meta = MethodItemMeta::from_nested("pyclassmethod", &ident, nested.into_iter())?;
let item_meta =
MethodItemMeta::from_nested(item.clone(), meta.clone(), nested.into_iter())?;
Ok(ClassItem::ClassMethod {
item_ident: ident.clone(),
item_ident: item.clone(),
py_name: item_meta.method_name()?,
})
}
fn extract_property(
ident: &Ident,
nested: PunctuatedNestedMeta,
item: &Ident,
(meta, nested): (&Ident, PunctuatedNestedMeta),
) -> Result<ClassItem, Diagnostic> {
let item_meta = PropertyItemMeta::from_nested("pyproperty", &ident, nested.into_iter())?;
let item_meta =
PropertyItemMeta::from_nested(item.clone(), meta.clone(), nested.into_iter())?;
Ok(ClassItem::Property {
item_ident: item.clone(),
py_name: item_meta.property_name()?,
item_ident: ident.clone(),
setter: item_meta.setter()?,
})
}
@@ -159,9 +162,13 @@ impl Class {
};
let item = match name.to_string().as_str() {
"pymethod" => Self::extract_method(item.ident, attr.promoted_nested()?)?,
"pyclassmethod" => Self::extract_classmethod(item.ident, attr.promoted_nested()?)?,
"pyproperty" => Self::extract_property(item.ident, attr.promoted_nested()?)?,
"pymethod" => Self::extract_method(item.ident, attr.ident_and_promoted_nested()?)?,
"pyclassmethod" => {
Self::extract_classmethod(item.ident, attr.ident_and_promoted_nested()?)?
}
"pyproperty" => {
Self::extract_property(item.ident, attr.ident_and_promoted_nested()?)?
}
"pyslot" => Self::extract_slot(item.ident, attr.promoted_nested()?)?,
_ => {
continue;
@@ -208,7 +215,7 @@ impl MethodItemMeta {
Ok(if let Some(name) = name {
name
} else {
let name = inner.ident.to_string();
let name = inner.item_name();
if magic {
format!("__{}__", name)
} else {
@@ -241,24 +248,24 @@ impl PropertyItemMeta {
Ok(if let Some(name) = name {
name
} else {
let sig_name = inner.ident.to_string();
let sig_name = inner.item_name();
let name = if setter {
if let Some(name) = sig_name.strip_prefix("set_") {
if name.is_empty() {
bail_span!(
&inner.ident,
&inner.meta_ident,
"A #[{}(setter)] fn with a set_* name must \
have something after \"set_\"",
inner.parent_type
inner.meta_name()
)
}
name.to_string()
} else {
bail_span!(
&inner.ident,
&inner.meta_ident,
"A #[{}(setter)] fn must either have a `name` \
parameter or a fn name along the lines of \"set_*\"",
inner.parent_type
inner.meta_name()
)
}
} else {
@@ -572,7 +579,8 @@ pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
),
};
let class_meta = ClassItemMeta::from_nested("pyclass", ident, attr.into_iter())?;
let fake_ident = Ident::new("pyclass", item.span());
let class_meta = ClassItemMeta::from_nested(ident.clone(), fake_ident, attr.into_iter())?;
let class_name = class_meta.class_name()?;
let module_name = class_meta.module()?;
let class_def = generate_class_def(&ident, &class_name, module_name.as_deref(), &attrs)?;
@@ -593,8 +601,8 @@ pub fn impl_pystruct_sequence(attr: AttributeArgs, item: Item) -> Result<TokenSt
"#[pystruct_sequence] can only be on a struct declaration"
)
};
let class_meta =
ClassItemMeta::from_nested("pystruct_sequence", &struc.ident, attr.into_iter())?;
let fake_ident = Ident::new("pystruct_sequence", struc.span());
let class_meta = ClassItemMeta::from_nested(struc.ident.clone(), fake_ident, attr.into_iter())?;
let class_name = class_meta.class_name()?;
let module_name = class_meta.mandatory_module()?;
+16 -14
View File
@@ -21,8 +21,9 @@ pub fn impl_pymodule(
Item::Mod(m) => m,
other => bail_span!(other, "#[pymodule] can only be on a module declaration"),
};
let fake_ident = Ident::new("pymodule", module_item.span());
let module_meta =
SimpleItemMeta::from_nested("pymodule", &module_item.ident, attr.into_iter())?;
SimpleItemMeta::from_nested(module_item.ident.clone(), fake_ident, attr.into_iter())?;
let mut module_context = Module {
name: module_meta.simple_name()?,
items: ItemNursery::default(),
@@ -260,8 +261,8 @@ impl ModuleItem for FunctionItem {
};
let item_attr = attrs.remove(self.index());
let item_meta = SimpleItemMeta::from_nested(
"pyfunction",
&args.ident,
args.ident.clone(),
item_attr.get_ident().unwrap().clone(),
item_attr.promoted_nested()?.into_iter(),
)?;
@@ -309,14 +310,10 @@ impl ModuleItem for ClassItem {
));
}
}
let static_name = match self.attr_name() {
"pyclass" => "pyclass",
"pystruct_sequence" => "pystruct_sequence",
_ => unreachable!(),
};
let class_meta = ClassItemMeta::from_nested(
static_name,
&args.ident,
args.ident.clone(),
class_attr.get_ident().unwrap().clone(),
class_attr.promoted_nested()?.into_iter(),
)?;
let module_name = args.module.name.clone();
@@ -328,8 +325,12 @@ impl ModuleItem for ClassItem {
};
for attr_index in self.pyattrs.iter().rev() {
let attr_attr = attrs.remove(*attr_index);
let nested = attr_attr.promoted_nested()?;
let item_meta = SimpleItemMeta::from_nested("pyattr", &args.ident, nested.into_iter())?;
let (meta_ident, nested) = attr_attr.ident_and_promoted_nested()?;
let item_meta = SimpleItemMeta::from_nested(
args.ident.clone(),
meta_ident.clone(),
nested.into_iter(),
)?;
let py_name = item_meta
.optional_name()
@@ -356,8 +357,9 @@ impl ModuleItem for AttributeItem {
fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()> {
let ident = &args.ident;
let get_py_name = |attrs: &mut Vec<Attribute>| -> Result<_> {
let nested = attrs[self.inner.index].promoted_nested()?;
let item_meta = SimpleItemMeta::from_nested("pyattr", &ident, nested.into_iter())?;
let (meta_ident, nested) = attrs[self.inner.index].ident_and_promoted_nested()?;
let item_meta =
SimpleItemMeta::from_nested(ident.clone(), meta_ident.clone(), nested.into_iter())?;
let py_name = item_meta.simple_name()?;
Ok(py_name)
};
+42 -29
View File
@@ -68,22 +68,22 @@ pub(crate) trait ContentItem {
}
pub(crate) struct ItemMetaInner {
pub ident: Ident,
pub parent_type: &'static str,
pub meta: HashMap<String, (usize, Meta)>,
pub item_ident: Ident,
pub meta_ident: Ident,
pub meta_map: HashMap<String, (usize, Meta)>,
}
impl ItemMetaInner {
pub fn from_nested<I>(
parent_type: &'static str,
ident: &Ident,
item_ident: Ident,
meta_ident: Ident,
nested: I,
allowed_names: &[&'static str],
) -> Result<Self>
where
I: std::iter::Iterator<Item = NestedMeta>,
{
let (named_map, lits) = nested.into_unique_map_and_lits(|path| {
let (meta_map, lits) = nested.into_unique_map_and_lits(|path| {
if let Some(ident) = path.get_ident() {
let name = ident.to_string();
if allowed_names.contains(&name.as_str()) {
@@ -93,7 +93,7 @@ impl ItemMetaInner {
ident,
format!(
"#[{}({})] is not one of allowed attributes {}",
parent_type,
meta_ident.to_string(),
name,
allowed_names.join(", ")
),
@@ -105,20 +105,28 @@ impl ItemMetaInner {
})?;
if !lits.is_empty() {
return Err(syn::Error::new_spanned(
ident,
format!("#[{}(..)] cannot contain literal", parent_type),
&meta_ident,
format!("#[{}(..)] cannot contain literal", meta_ident.to_string()),
));
}
Ok(Self {
ident: ident.clone(),
parent_type,
meta: named_map,
item_ident,
meta_ident,
meta_map,
})
}
pub fn item_name(&self) -> String {
self.item_ident.to_string()
}
pub fn meta_name(&self) -> String {
self.meta_ident.to_string()
}
pub fn _optional_str(&self, key: &str) -> Result<Option<String>> {
let value = if let Some((_, meta)) = self.meta.get(key) {
let value = if let Some((_, meta)) = self.meta_map.get(key) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(lit),
@@ -129,7 +137,8 @@ impl ItemMetaInner {
other,
format!(
"#[{}({} = ...)] must exist as a string",
self.parent_type, key
self.meta_name(),
key
),
));
}
@@ -141,7 +150,7 @@ impl ItemMetaInner {
}
pub fn _bool(&self, key: &str) -> Result<bool> {
let value = if let Some((_, meta)) = self.meta.get(key) {
let value = if let Some((_, meta)) = self.meta_map.get(key) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Bool(lit),
@@ -151,7 +160,7 @@ impl ItemMetaInner {
other => {
return Err(syn::Error::new_spanned(
other,
format!("#[{}({})] is expected", self.parent_type, key),
format!("#[{}({})] is expected", self.meta_name(), key),
))
}
}
@@ -165,13 +174,13 @@ impl ItemMetaInner {
pub(crate) trait ItemMeta: Sized {
const ALLOWED_NAMES: &'static [&'static str];
fn from_nested<I>(parent_type: &'static str, ident: &Ident, nested: I) -> Result<Self>
fn from_nested<I>(item_ident: Ident, meta_ident: Ident, nested: I) -> Result<Self>
where
I: std::iter::Iterator<Item = NestedMeta>,
{
Ok(Self::from_inner(ItemMetaInner::from_nested(
parent_type,
ident,
item_ident,
meta_ident,
nested,
Self::ALLOWED_NAMES,
)?))
@@ -184,7 +193,7 @@ pub(crate) trait ItemMeta: Sized {
let inner = self.inner();
Ok(inner
._optional_str("name")?
.unwrap_or_else(|| inner.ident.to_string()))
.unwrap_or_else(|| inner.item_name()))
}
fn optional_name(&self) -> Option<String> {
@@ -221,22 +230,22 @@ impl ClassItemMeta {
pub fn class_name(&self) -> Result<String> {
const KEY: &str = "name";
let inner = self.inner();
let value = if let Some((_, meta)) = inner.meta.get(KEY) {
let value = if let Some((_, meta)) = inner.meta_map.get(KEY) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(lit),
..
}) => Some(lit.value()),
Meta::Path(_) => Some(inner.ident.to_string()),
Meta::Path(_) => Some(inner.item_name()),
_ => None,
}
} else {
None
}.ok_or_else(|| syn::Error::new_spanned(
&inner.ident,
&inner.meta_ident,
format!(
"#[{attr_name}(name = ...)] must exist as a string. Try #[{attr_name}(name)] to use rust type name.",
attr_name=inner.parent_type
attr_name=inner.meta_name()
),
))?;
Ok(value)
@@ -245,7 +254,7 @@ impl ClassItemMeta {
pub fn module(&self) -> Result<Option<String>> {
const KEY: &str = "module";
let inner = self.inner();
let value = if let Some((_, meta)) = inner.meta.get(KEY) {
let value = if let Some((_, meta)) = inner.meta_map.get(KEY) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(lit),
@@ -262,12 +271,12 @@ impl ClassItemMeta {
other => Err(other.span()),
}
} else {
Err(inner.ident.span())
Err(inner.item_ident.span())
}.map_err(|span| syn::Error::new(
span,
format!(
"#[{attr_name}(module = ...)] must exist as a string or false. Try #[{attr_name}(module=false)] for built-in types.",
attr_name=inner.parent_type
attr_name=inner.meta_name()
),
))?;
Ok(value)
@@ -277,10 +286,10 @@ impl ClassItemMeta {
let inner = self.inner();
let value = self.module().ok().flatten().
ok_or_else(|| syn::Error::new_spanned(
&inner.ident,
&inner.meta_ident,
format!(
"#[{attr_name}(module = ...)] must exist as a string. Built-in module is not allowed here.",
attr_name=inner.parent_type
attr_name=inner.meta_name()
),
))?;
Ok(value)
@@ -293,6 +302,7 @@ pub(crate) fn path_eq(path: &Path, s: &str) -> bool {
pub(crate) trait AttributeExt: SynAttributeExt {
fn promoted_nested(&self) -> Result<PunctuatedNestedMeta>;
fn ident_and_promoted_nested(&self) -> Result<(&Ident, PunctuatedNestedMeta)>;
fn try_remove_name(&mut self, name: &str) -> Result<Option<syn::NestedMeta>>;
fn fill_nested_meta<F>(&mut self, name: &str, new_item: F) -> Result<()>
where
@@ -315,6 +325,9 @@ impl AttributeExt for Attribute {
})?;
Ok(list.nested)
}
fn ident_and_promoted_nested(&self) -> Result<(&Ident, PunctuatedNestedMeta)> {
Ok((self.get_ident().unwrap(), self.promoted_nested()?))
}
fn try_remove_name(&mut self, item_name: &str) -> Result<Option<syn::NestedMeta>> {
self.try_meta_mut(|meta| {