Skip to content

Commit c1c2d60

Browse files
bors[bot]ttencate
andauthored
Merge #203
203: Make `get` and `set` arguments take identifiers instead of strings r=Bromeon a=ttencate Refactors `KvParser` to accept some expressions, as long as they don't contain a comma at the top level outside any pair of `[]`, `()` or `{}`. Also tightens up spans in error messages quite a bit. Prelude for #199. Co-authored-by: Thomas ten Cate <[email protected]>
2 parents afa2e59 + 1b32155 commit c1c2d60

File tree

4 files changed

+331
-258
lines changed

4 files changed

+331
-258
lines changed

godot-macros/src/derive_godot_class.rs

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
55
*/
66

7-
use crate::util::{bail, ident, string_lit_contents, KvParser, KvValue};
7+
use crate::util::{bail, ident, KvParser};
88
use crate::ParseResult;
99
use proc_macro2::{Ident, Punct, TokenStream};
1010
use quote::{format_ident, quote};
@@ -185,45 +185,36 @@ enum GetterSetter {
185185
Omitted,
186186
/// Trivial getter/setter should be autogenerated.
187187
Generated,
188-
/// Getter/setter is hand-written by the user, and here is its name.
189-
Custom(String),
188+
/// Getter/setter is hand-written by the user, and here is its identifier.
189+
Custom(Ident),
190190
}
191191

192192
impl GetterSetter {
193193
fn parse(parser: &mut KvParser, key: &str) -> ParseResult<Self> {
194194
Ok(match parser.handle_any(key) {
195195
// No `get` argument
196196
None => GetterSetter::Omitted,
197-
// `get` without value
198-
Some(KvValue::None) => GetterSetter::Generated,
199-
// `get = literal`
200-
Some(KvValue::Lit(name_lit)) => {
201-
let Some(name) = string_lit_contents(&name_lit) else {
202-
return bail(format!("argument to {key} must be a string literal, got: {name_lit}"), parser.span());
203-
};
204-
GetterSetter::Custom(name)
205-
}
206-
Some(KvValue::Ident(ident)) => {
207-
return bail(
208-
format!("argument to {key} must be a string, got: {ident}"),
209-
parser.span(),
210-
);
211-
}
197+
Some(value) => match value {
198+
// `get` without value
199+
None => GetterSetter::Generated,
200+
// `get = expr`
201+
Some(value) => GetterSetter::Custom(value.ident()?),
202+
},
212203
})
213204
}
214205
}
215206

216207
#[derive(Clone)]
217208
struct ExportHint {
218209
hint_type: Ident,
219-
description: String,
210+
description: TokenStream,
220211
}
221212

222213
impl ExportHint {
223214
fn none() -> Self {
224215
Self {
225216
hint_type: ident("PROPERTY_HINT_NONE"),
226-
description: "".to_string(),
217+
description: quote!(""),
227218
}
228219
}
229220
}
@@ -242,7 +233,7 @@ impl ExportedField {
242233
.map(|hint_type| {
243234
Ok(ExportHint {
244235
hint_type,
245-
description: parser.handle_lit_required("hint_desc")?,
236+
description: parser.handle_expr_required("hint_desc")?,
246237
})
247238
})
248239
.transpose()?;
@@ -316,9 +307,6 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
316307
description,
317308
} = exported_field.hint.clone().unwrap_or_else(ExportHint::none);
318309

319-
// trims '"' and '\' from both ends of the hint description.
320-
let description = description.trim_matches(|c| c == '\\' || c == '"');
321-
322310
let getter_name;
323311
match &exported_field.getter {
324312
GetterSetter::Omitted => {
@@ -339,10 +327,9 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
339327
::godot::private::gdext_register_method!(#class_name, #signature);
340328
});
341329
}
342-
GetterSetter::Custom(name) => {
343-
getter_name = name.clone();
344-
let getter_ident = ident(&getter_name);
345-
export_tokens.push(make_existence_check(&getter_ident));
330+
GetterSetter::Custom(getter_ident) => {
331+
getter_name = getter_ident.to_string();
332+
export_tokens.push(make_existence_check(getter_ident));
346333
}
347334
}
348335

@@ -366,10 +353,9 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
366353
::godot::private::gdext_register_method!(#class_name, #signature);
367354
});
368355
}
369-
GetterSetter::Custom(name) => {
370-
setter_name = name.clone();
371-
let setter_ident = ident(&setter_name);
372-
export_tokens.push(make_existence_check(&setter_ident));
356+
GetterSetter::Custom(setter_ident) => {
357+
setter_name = setter_ident.to_string();
358+
export_tokens.push(make_existence_check(setter_ident));
373359
}
374360
};
375361

godot-macros/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,14 @@ mod util;
171171
///
172172
/// If you want to implement your own getter and/or setter, write those as a function on your Rust
173173
/// type, expose it using `#[func]`, and annotate the field with
174-
/// `#[export(get = "...", set = "...")]`:
174+
/// `#[export(get = ..., set = ...)]`:
175175
///
176176
/// ```
177177
/// use godot::prelude::*;
178178
///
179179
/// #[derive(GodotClass)]
180180
/// struct MyStruct {
181-
/// #[export(get = "get_my_field", set = "set_my_field")]
181+
/// #[export(get = get_my_field, set = set_my_field)]
182182
/// my_field: i64,
183183
/// }
184184
///
@@ -206,7 +206,7 @@ mod util;
206206
/// #[derive(GodotClass)]
207207
/// struct MyStruct {
208208
/// // Default getter, custom setter.
209-
/// #[export(get, set = "set_my_field")]
209+
/// #[export(get, set = set_my_field)]
210210
/// my_field: i64,
211211
/// }
212212
///

0 commit comments

Comments
 (0)