Skip to content

Commit 31c60ec

Browse files
WIP Try new parsing system
1 parent 3100295 commit 31c60ec

File tree

11 files changed

+153
-202
lines changed

11 files changed

+153
-202
lines changed

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

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,13 @@ 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,
22+
/// Indicates that this attribute is required
23+
Required,
2924
}
3025

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

4944
impl<'a> ParsedAttributes {
5045
/// 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
46+
/// Will error if an attribute which is not in the allowed list is found, or attribute is used incorrectly
5247
pub fn require_attributes(
5348
mut attrs: Vec<Attribute>,
54-
allowed: &'a [&str],
49+
allowed: &'a [(AttributeConstraint, &str)],
5550
) -> Result<ParsedAttributes> {
5651
let mut output = BTreeMap::<String, Vec<Attribute>>::default();
5752
for attr in attrs.drain(..) {
58-
let index = allowed
59-
.iter()
60-
.position(|string| path_compare_str(attr.meta.path(), &parser::split_path(string)));
53+
let index = allowed.iter().position(|(_, string)| {
54+
path_compare_str(attr.meta.path(), &parser::split_path(string))
55+
});
6156
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]);
57+
match allowed[index].0 {
58+
AttributeConstraint::Unique => {
59+
match output.entry(allowed[index].1.into()) {
60+
Entry::Occupied(_) => return Err(Error::new_spanned(
61+
attr,
62+
"There must be at most one of this attribute on this given item",
63+
)),
64+
Entry::Vacant(entry) => {
65+
entry.insert(vec![attr]);
66+
}
67+
}
6968
}
69+
AttributeConstraint::Duplicate => match output.entry(allowed[index].1.into()) {
70+
Entry::Occupied(mut entry) => {
71+
entry.get_mut().push(attr);
72+
}
73+
Entry::Vacant(entry) => {
74+
entry.insert(vec![attr]);
75+
}
76+
},
77+
AttributeConstraint::Required => {}
7078
}
7179
} else {
7280
return Err(Error::new(
7381
attr.span(),
7482
format!(
7583
"Unsupported attribute! The only attributes allowed on this item are\n{}",
76-
allowed.join(", ")
84+
allowed
85+
.iter()
86+
.map(|(_, string)| *string)
87+
.collect::<Vec<_>>()
88+
.join(", ")
7789
),
7890
));
7991
}
@@ -122,18 +134,6 @@ impl<'a> ParsedAttributes {
122134
self.cxx_qt_attrs.get(key)?.first()
123135
}
124136

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-
137137
/// Check if CXX-Qt or passthrough attributes contains a particular key
138138
pub fn contains_key(&self, key: &str) -> bool {
139139
self.cxx_qt_attrs.contains_key(key) // TODO: Check in passthrough too

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

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
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},
@@ -37,30 +37,19 @@ impl ParsedExternCxxQt {
3737
// TODO: support cfg on foreign mod blocks
3838
let attrs = ParsedAttributes::require_attributes(
3939
foreign_mod.attrs,
40-
&["namespace", "auto_cxx_name", "auto_rust_name"],
40+
&[
41+
(AttributeConstraint::Unique, "namespace"),
42+
(AttributeConstraint::Unique, "auto_cxx_name"),
43+
(AttributeConstraint::Unique, "auto_rust_name"),
44+
],
4145
)?;
4246

4347
let auto_case = CaseConversion::from_attrs(&attrs)?;
4448

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-
};
49+
let namespace = attrs
50+
.get_one("namespace")
51+
.map(|attr| expr_to_string(&attr.meta.require_name_value()?.value))
52+
.transpose()?;
6453

6554
let mut extern_cxx_block = ParsedExternCxxQt {
6655
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: 11 additions & 27 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;
@@ -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)