Skip to content

Commit c72712f

Browse files
WIP Try new parsing system
1 parent 3100295 commit c72712f

File tree

11 files changed

+152
-205
lines changed

11 files changed

+152
-205
lines changed

crates/cxx-qt-gen/src/parser/attribute.rs

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,11 @@ pub struct ParsedAttributes {
1414
pub passthrough_attrs: Vec<Attribute>,
1515
}
1616

17-
// TODO: ATTR could this instead be used as Result<ParsedAttribute> to encapsulate error states
18-
pub enum ParsedAttribute<'a> {
19-
/// A single attribute was found
20-
Single(&'a Attribute),
21-
/// An attribute was not found, but this is ok
22-
Absent,
23-
/// An attribute was not found, and this is an error
24-
AbsentRequired,
25-
/// Multiple attributes were found, but this is ok
26-
Multiple(Vec<&'a Attribute>),
27-
/// Multiple attributes were found, but this is an error
28-
MultipleDisallowed(Vec<&'a Attribute>),
17+
pub enum AttributeConstraint {
18+
/// Indicates that there must be only one of this attribute
19+
Unique,
20+
/// Indicates there can be multiple of this attribute
21+
Duplicate,
2922
}
3023

3124
/// Iterate the attributes of the method to extract cfg attributes
@@ -48,32 +41,49 @@ pub fn extract_docs(attrs: &[Attribute]) -> Vec<Attribute> {
4841

4942
impl<'a> ParsedAttributes {
5043
/// Collects a Map of all attributes found from the allowed list
51-
/// Will error if an attribute which is not in the allowed list is found
44+
/// Will error if an attribute which is not in the allowed list is found, or attribute is used incorrectly
5245
pub fn require_attributes(
5346
mut attrs: Vec<Attribute>,
54-
allowed: &'a [&str],
47+
allowed: &'a [(AttributeConstraint, &str)],
5548
) -> Result<ParsedAttributes> {
5649
let mut output = BTreeMap::<String, Vec<Attribute>>::default();
50+
// Iterate all attributes found
5751
for attr in attrs.drain(..) {
58-
let index = allowed
59-
.iter()
60-
.position(|string| path_compare_str(attr.meta.path(), &parser::split_path(string)));
52+
let index = allowed.iter().position(|(_, string)| {
53+
path_compare_str(attr.meta.path(), &parser::split_path(string))
54+
});
6155
if let Some(index) = index {
62-
// TODO: ATTR Doesn't error on duplicates / distinguish allowed and disallowed duplicates
63-
match output.entry(allowed[index].into()) {
64-
Entry::Occupied(mut entry) => {
65-
entry.get_mut().push(attr);
66-
}
67-
Entry::Vacant(entry) => {
68-
entry.insert(vec![attr]);
56+
match allowed[index].0 {
57+
AttributeConstraint::Unique => {
58+
match output.entry(allowed[index].1.into()) {
59+
Entry::Occupied(_) => return Err(Error::new_spanned(
60+
attr,
61+
"There must be at most one of this attribute on this given item",
62+
)),
63+
Entry::Vacant(entry) => {
64+
entry.insert(vec![attr]);
65+
}
66+
}
6967
}
68+
AttributeConstraint::Duplicate => match output.entry(allowed[index].1.into()) {
69+
Entry::Occupied(mut entry) => {
70+
entry.get_mut().push(attr);
71+
}
72+
Entry::Vacant(entry) => {
73+
entry.insert(vec![attr]);
74+
}
75+
},
7076
}
7177
} else {
7278
return Err(Error::new(
7379
attr.span(),
7480
format!(
7581
"Unsupported attribute! The only attributes allowed on this item are\n{}",
76-
allowed.join(", ")
82+
allowed
83+
.iter()
84+
.map(|(_, string)| *string)
85+
.collect::<Vec<_>>()
86+
.join(", ")
7787
),
7888
));
7989
}
@@ -122,18 +132,6 @@ impl<'a> ParsedAttributes {
122132
self.cxx_qt_attrs.get(key)?.first()
123133
}
124134

125-
pub fn require_one(&self, key: &str) -> ParsedAttribute {
126-
if let Some(attrs) = self.cxx_qt_attrs.get(key) {
127-
if attrs.len() != 1 {
128-
ParsedAttribute::MultipleDisallowed(attrs.iter().by_ref().collect())
129-
} else {
130-
ParsedAttribute::Single(attrs.first().expect("Expected at least one attribute"))
131-
}
132-
} else {
133-
ParsedAttribute::Absent
134-
}
135-
}
136-
137135
/// Check if CXX-Qt or passthrough attributes contains a particular key
138136
pub fn contains_key(&self, key: &str) -> bool {
139137
self.cxx_qt_attrs.contains_key(key) // TODO: Check in passthrough too

crates/cxx-qt-gen/src/parser/externcxxqt.rs

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

6-
use crate::parser::attribute::{ParsedAttribute, ParsedAttributes};
6+
use crate::parser::attribute::{AttributeConstraint, ParsedAttributes};
77
use crate::{
88
parser::{externqobject::ParsedExternQObject, signals::ParsedSignal, CaseConversion},
99
syntax::{attribute::attribute_get_path, expr::expr_to_string},
1010
};
11-
use proc_macro2::Span;
1211
use syn::{
1312
spanned::Spanned, Error, ForeignItem, ForeignItemFn, Ident, ItemForeignMod, Result, Token,
1413
};
@@ -37,30 +36,19 @@ impl ParsedExternCxxQt {
3736
// TODO: support cfg on foreign mod blocks
3837
let attrs = ParsedAttributes::require_attributes(
3938
foreign_mod.attrs,
40-
&["namespace", "auto_cxx_name", "auto_rust_name"],
39+
&[
40+
(AttributeConstraint::Unique, "namespace"),
41+
(AttributeConstraint::Unique, "auto_cxx_name"),
42+
(AttributeConstraint::Unique, "auto_rust_name"),
43+
],
4144
)?;
4245

4346
let auto_case = CaseConversion::from_attrs(&attrs)?;
4447

45-
let namespace = match attrs.require_one("namespace") {
46-
ParsedAttribute::Single(attr) => {
47-
expr_to_string(&attr.meta.require_name_value()?.value).ok()
48-
}
49-
ParsedAttribute::Absent => None,
50-
ParsedAttribute::MultipleDisallowed(_) => {
51-
Err(Error::new(
52-
Span::call_site(),
53-
"There must be at most one namespace attribute",
54-
))? // TODO: ATTR use real span
55-
}
56-
_ => {
57-
// CODECOV_EXCLUDE_START
58-
unreachable!(
59-
"Namepsace is not an allowed duplicate, nor required so this block should be unreachable"
60-
)
61-
// CODECOV_EXCLUDE_STOP
62-
}
63-
};
48+
let namespace = attrs
49+
.get_one("namespace")
50+
.map(|attr| expr_to_string(&attr.meta.require_name_value()?.value))
51+
.transpose()?;
6452

6553
let mut extern_cxx_block = ParsedExternCxxQt {
6654
namespace,

crates/cxx-qt-gen/src/parser/externqobject.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55
use crate::naming::Name;
6-
use crate::parser::attribute::ParsedAttributes;
6+
use crate::parser::attribute::{AttributeConstraint, ParsedAttributes};
77
use crate::parser::{parse_base_type, CaseConversion};
88
use syn::{ForeignItemType, Ident, Result};
99

@@ -18,14 +18,14 @@ pub struct ParsedExternQObject {
1818
}
1919

2020
impl ParsedExternQObject {
21-
const ALLOWED_ATTRS: [&'static str; 7] = [
22-
"cxx_name",
23-
"rust_name",
24-
"namespace",
25-
"cfg",
26-
"doc",
27-
"qobject",
28-
"base",
21+
const ALLOWED_ATTRS: [(AttributeConstraint, &'static str); 7] = [
22+
(AttributeConstraint::Unique, "cxx_name"),
23+
(AttributeConstraint::Unique, "rust_name"),
24+
(AttributeConstraint::Unique, "namespace"),
25+
(AttributeConstraint::Duplicate, "cfg"),
26+
(AttributeConstraint::Duplicate, "doc"),
27+
(AttributeConstraint::Unique, "qobject"),
28+
(AttributeConstraint::Unique, "base"),
2929
];
3030

3131
pub fn parse(

crates/cxx-qt-gen/src/parser/externrustqt.rs

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

66
use crate::naming::cpp::err_unsupported_item;
7-
use crate::parser::attribute::{ParsedAttribute, ParsedAttributes};
7+
use crate::parser::attribute::{AttributeConstraint, ParsedAttributes};
88
use crate::parser::inherit::ParsedInheritedMethod;
99
use crate::parser::method::ParsedMethod;
1010
use crate::parser::qobject::ParsedQObject;
@@ -13,7 +13,7 @@ use crate::parser::CaseConversion;
1313
use crate::syntax::attribute::attribute_get_path;
1414
use crate::syntax::expr::expr_to_string;
1515
use crate::syntax::foreignmod::ForeignTypeIdentAlias;
16-
use proc_macro2::{Ident, Span};
16+
use proc_macro2::Ident;
1717
use syn::spanned::Spanned;
1818
use syn::{Error, ForeignItem, ForeignItemFn, ItemForeignMod, Result, Token};
1919

@@ -41,7 +41,11 @@ impl ParsedExternRustQt {
4141
// TODO: support cfg on foreign mod blocks
4242
let attrs = ParsedAttributes::require_attributes(
4343
foreign_mod.attrs,
44-
&["namespace", "auto_cxx_name", "auto_rust_name"],
44+
&[
45+
(AttributeConstraint::Unique, "namespace"),
46+
(AttributeConstraint::Unique, "auto_cxx_name"),
47+
(AttributeConstraint::Unique, "auto_rust_name"),
48+
],
4549
)?;
4650

4751
let auto_case = CaseConversion::from_attrs(&attrs)?;
@@ -51,31 +55,11 @@ impl ParsedExternRustQt {
5155
..Default::default()
5256
};
5357

54-
// let namespace = attrs
55-
// .get_one("namespace")
56-
// .map(|attr| expr_to_string(&attr.meta.require_name_value()?.value))
57-
// .transpose()?
58-
// .or_else(|| parent_namespace.map(String::from));
59-
60-
let namespace = match attrs.require_one("namespace") {
61-
ParsedAttribute::Single(attr) => {
62-
expr_to_string(&attr.meta.require_name_value()?.value).ok()
63-
}
64-
ParsedAttribute::Absent => None,
65-
ParsedAttribute::MultipleDisallowed(_) => {
66-
Err(Error::new(
67-
Span::call_site(),
68-
"There must be at most one namespace attribute",
69-
))? // TODO: ATTR use real span
70-
}
71-
_ => {
72-
// CODECOV_EXCLUDE_START
73-
unreachable!(
74-
"Namepsace is not an allowed duplicate, nor required so this block should be unreachable"
75-
)
76-
// CODECOV_EXCLUDE_STOP
77-
}
78-
}.or_else(|| parent_namespace.map(String::from));
58+
let namespace = attrs
59+
.get_one("namespace")
60+
.map(|attr| expr_to_string(&attr.meta.require_name_value()?.value))
61+
.transpose()?
62+
.or_else(|| parent_namespace.map(String::from));
7963

8064
for item in foreign_mod.items.drain(..) {
8165
match item {

crates/cxx-qt-gen/src/parser/inherit.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

6+
use crate::parser::attribute::AttributeConstraint;
67
use crate::parser::{method::MethodFields, CaseConversion};
78
use core::ops::Deref;
89
use quote::format_ident;
@@ -20,13 +21,13 @@ pub struct ParsedInheritedMethod {
2021
}
2122

2223
impl ParsedInheritedMethod {
23-
const ALLOWED_ATTRS: [&'static str; 6] = [
24-
"cxx_name",
25-
"rust_name",
26-
"qinvokable",
27-
"doc",
28-
"inherit",
29-
"cfg",
24+
const ALLOWED_ATTRS: [(AttributeConstraint, &'static str); 6] = [
25+
(AttributeConstraint::Unique, "cxx_name"),
26+
(AttributeConstraint::Unique, "rust_name"),
27+
(AttributeConstraint::Unique, "qinvokable"),
28+
(AttributeConstraint::Duplicate, "doc"),
29+
(AttributeConstraint::Unique, "inherit"),
30+
(AttributeConstraint::Duplicate, "cfg"),
3031
];
3132

3233
pub fn parse(method: ForeignItemFn, auto_case: CaseConversion) -> Result<Self> {

crates/cxx-qt-gen/src/parser/method.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
5-
use crate::parser::attribute::{extract_cfgs, ParsedAttributes};
5+
use crate::parser::attribute::{extract_cfgs, AttributeConstraint, ParsedAttributes};
66
use crate::parser::CaseConversion;
77
use crate::{
88
naming::Name,
@@ -69,16 +69,16 @@ pub struct ParsedMethod {
6969
}
7070

7171
impl ParsedMethod {
72-
const ALLOWED_ATTRS: [&'static str; 9] = [
73-
"cxx_name",
74-
"rust_name",
75-
"qinvokable",
76-
"cxx_final",
77-
"cxx_override",
78-
"cxx_virtual",
79-
"cxx_pure",
80-
"doc",
81-
"cfg",
72+
const ALLOWED_ATTRS: [(AttributeConstraint, &'static str); 9] = [
73+
(AttributeConstraint::Unique, "cxx_name"),
74+
(AttributeConstraint::Unique, "rust_name"),
75+
(AttributeConstraint::Unique, "qinvokable"),
76+
(AttributeConstraint::Unique, "cxx_final"),
77+
(AttributeConstraint::Unique, "cxx_override"),
78+
(AttributeConstraint::Unique, "cxx_virtual"),
79+
(AttributeConstraint::Unique, "cxx_pure"),
80+
(AttributeConstraint::Duplicate, "doc"),
81+
(AttributeConstraint::Duplicate, "cfg"),
8282
];
8383

8484
#[cfg(test)]
@@ -172,7 +172,7 @@ impl MethodFields {
172172
pub fn parse(
173173
method: ForeignItemFn,
174174
auto_case: CaseConversion,
175-
allowed: &[&str],
175+
allowed: &[(AttributeConstraint, &str)],
176176
) -> Result<Self> {
177177
// TODO: Remove this clone?
178178
let attrs = ParsedAttributes::require_attributes(method.attrs.clone(), allowed)?;

0 commit comments

Comments
 (0)