Skip to content

Commit

Permalink
add alternative syntax for manual property registration
Browse files Browse the repository at this point in the history
  • Loading branch information
you-win committed Sep 8, 2023
1 parent 52709eb commit 46afcc7
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 4 deletions.
38 changes: 38 additions & 0 deletions godot-macros/src/class/derive_godot_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,44 @@ fn parse_struct_attributes(class: &Struct) -> ParseResult<ClassAttributes> {
is_tool = true;
}

if let Some(mut list_parser) = parser.handle_array("properties")? {
while let Some(inner_list_parser) = list_parser.try_next_list(Delimiter::Parenthesis)? {
let mut parser =
KvParser::parse_from_list_parser(inner_list_parser, Delimiter::Parenthesis)?;

let name = parser.handle_expr_required("name")?.to_string();
let ty = parser.handle_expr_required("type")?;

let field_var = FieldVar::new_from_kv(&mut parser)?;
if field_var.getter.is_omitted() && field_var.setter.is_omitted() {
bail!(
parser.span(),
"#[properties] item must define at least 1 getter or setter"
)?;
}
if field_var.getter.is_generated() || field_var.setter.is_generated() {
bail!(
parser.span(),
"#[properties] item does not support generated getters and setters"
)?;
}

let mut field = Field::new(
ident(name.as_str()),
venial::TyExpr {
tokens: vec![TokenTree::Group(Group::new(Delimiter::None, ty))],
},
);
field.var = Some(field_var);

standlone_properties.push(field);

parser.finish()?;
}

list_parser.finish()?;
}

parser.finish()?;
}

Expand Down
30 changes: 28 additions & 2 deletions godot-macros/src/util/kv_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

use crate::ParseResult;
use proc_macro2::{Delimiter, Ident, Spacing, Span, TokenStream, TokenTree};
use proc_macro2::{Delimiter, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::collections::HashMap;
use venial::Attribute;
Expand Down Expand Up @@ -77,6 +77,28 @@ impl KvParser {
Ok(found_attrs)
}

pub fn parse_from_list_parser(parser: ListParser, delimiter: Delimiter) -> ParseResult<Self> {
let span = parser.span_close;
let tokens = parser
.lists
.into_iter()
.flat_map(|v| {
let mut tokens = v.into_tokens();
tokens.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));

tokens
})
.collect::<Vec<TokenTree>>();

Ok(Self {
span,
map: ParserState::parse(
"nested list".to_string(),
&venial::AttributeValue::Group(venial::GroupSpan { delimiter, span }, tokens),
)?,
})
}

pub fn span(&self) -> Span {
self.span
}
Expand Down Expand Up @@ -333,7 +355,11 @@ impl<'a> ParserState<'a> {
} else {
"".to_owned()
};
return bail!(cur, "expected identifier{parens_hint}");
let attr_name = self.attr_name;
let tokens = self.tokens;
let prev = self.prev;
let cur = self.cur;
return bail!(cur, "expected identifier{parens_hint} attr {attr_name} tokens {tokens:?} prev {prev:?} cur {cur:?}");
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions godot-macros/src/util/list_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use crate::ParseResult;
/// Parses a list of tokens as an ordered list of values. Unlike [`KvParser`] which treats the tokens as a
/// set of values.
pub struct ListParser {
lists: VecDeque<KvValue>,
pub(super) lists: VecDeque<KvValue>,
/// The last span of the list, usually a closing parenthesis.
span_close: Span,
pub(super) span_close: Span,
}

impl ListParser {
Expand Down Expand Up @@ -194,6 +194,18 @@ impl ListParser {
}
}

/// Takes the next list element of the list.
///
/// # Example
/// `((name = foo), (name = boo))` will yield `(name = foo)`
pub(crate) fn try_next_list(&mut self, delimiter: Delimiter) -> ParseResult<Option<Self>> {
let Some(kv) = self.pop_next() else {
return Ok(None);
};

Ok(Some(ListParser::new_from_tree(kv.single()?, delimiter)?))
}

/// Ensure all values have been consumed.
pub fn finish(&mut self) -> ParseResult<()> {
if let Some(kv) = self.pop_next() {
Expand Down
3 changes: 3 additions & 0 deletions itest/godot/ManualFfiTests.gd
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,6 @@ func test_standalone_property():
assert_eq(standalone_property.my_int, 10)
assert_eq(standalone_property.readonly_int, 10)
assert_eq(standalone_property.int_array, [10])

assert_eq(standalone_property.first_int, 10)
assert_eq(standalone_property.second_int, 10)
6 changes: 6 additions & 0 deletions itest/rust/src/object_tests/property_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,12 @@ fn derive_export() {
}

#[derive(GodotClass)]
#[class(
properties = [
(name = first_int, type = i32, get = get_integer),
(name = second_int, type = i32, get = get_integer)
]
)]
#[property(name = my_int, type = i32, get = get_integer, set = set_integer)]
#[property(name = readonly_int, type = i32, get = get_integer)]
#[property(name = int_array, type = Array<i32>, get = get_integer_as_array, set = set_integer_from_array_front)]
Expand Down

0 comments on commit 46afcc7

Please sign in to comment.