Skip to content

Commit b17558a

Browse files
committed
adds default parameters parsing
1 parent e1073bc commit b17558a

File tree

5 files changed

+75
-4
lines changed

5 files changed

+75
-4
lines changed

godot-core/src/registry/method.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,11 @@ impl ClassMethodInfo {
5959
ptrcall_func: sys::GDExtensionClassMethodPtrCall,
6060
method_flags: MethodFlags,
6161
param_names: &[&str],
62-
// default_arguments: Vec<Variant>, - not yet implemented
62+
default_arguments: Vec<Variant>,
6363
) -> Self {
6464
let return_value = Ret::Via::return_info();
6565
let arguments = Signature::<Params, Ret>::param_names(param_names);
6666

67-
let default_arguments = vec![]; // not yet implemented.
6867
assert!(
6968
default_arguments.len() <= arguments.len(),
7069
"cannot have more default arguments than arguments"

godot-macros/src/class/data_models/func.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
use crate::class::RpcAttr;
99
use crate::util::{bail_fn, ident, safe_ident};
10-
use crate::{util, ParseResult};
10+
use crate::{bail, util, ParseResult};
1111
use proc_macro2::{Group, Ident, TokenStream, TokenTree};
1212
use quote::{format_ident, quote};
1313

@@ -126,6 +126,8 @@ pub fn make_method_registration(
126126
.iter()
127127
.map(|ident| ident.to_string());
128128

129+
let default_parameters =
130+
validate_default_parameters(&func_definition.signature_info.default_parameters)?;
129131
// Transport #[cfg] attrs to the FFI glue to ensure functions which were conditionally
130132
// removed from compilation don't cause errors.
131133
let cfg_attrs = util::extract_cfg_attrs(&func_definition.external_attributes)
@@ -158,6 +160,9 @@ pub fn make_method_registration(
158160
&[
159161
#( #param_ident_strs ),*
160162
],
163+
vec![
164+
#( <#default_parameters as ::godot::meta::AsArg>.to_variant() ),*
165+
]
161166
)
162167
};
163168

@@ -175,6 +180,32 @@ pub fn make_method_registration(
175180
Ok(registration)
176181
}
177182

183+
fn validate_default_parameters(
184+
default_parameters: &[Option<TokenStream>],
185+
) -> ParseResult<Vec<TokenStream>> {
186+
let mut res = vec![];
187+
let mut allowed = true;
188+
for param in default_parameters.iter().rev() {
189+
match (param, allowed) {
190+
(Some(tk), true) => {
191+
res.push(tk.clone()); // toreview: if we really care about it, we can use &mut sig_info and mem::take() as we don't use this later
192+
}
193+
(None, true) => {
194+
allowed = false;
195+
}
196+
(None, false) => {}
197+
(Some(tk), false) => {
198+
return bail!(
199+
tk,
200+
"opt arguments are only allowed at the end of the argument list."
201+
);
202+
}
203+
}
204+
}
205+
res.reverse();
206+
Ok(res)
207+
}
208+
178209
// ----------------------------------------------------------------------------------------------------------------------------------------------
179210
// Implementation
180211

@@ -199,6 +230,8 @@ pub struct SignatureInfo {
199230
///
200231
/// Index points into original venial tokens (i.e. takes into account potential receiver params).
201232
pub modified_param_types: Vec<(usize, venial::TypeExpr)>,
233+
/// Contains expressions of the default values of parameters.
234+
pub default_parameters: Vec<Option<TokenStream>>,
202235
}
203236

204237
impl SignatureInfo {
@@ -210,6 +243,7 @@ impl SignatureInfo {
210243
param_types: vec![],
211244
return_type: quote! { () },
212245
modified_param_types: vec![],
246+
default_parameters: vec![],
213247
}
214248
}
215249

@@ -412,6 +446,7 @@ pub(crate) fn into_signature_info(
412446
param_types,
413447
return_type: ret_type,
414448
modified_param_types,
449+
default_parameters: vec![],
415450
}
416451
}
417452

godot-macros/src/class/data_models/inherent_impl.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,10 @@ fn process_godot_fns(
304304
};
305305

306306
// Clone might not strictly be necessary, but the 2 other callers of into_signature_info() are better off with pass-by-value.
307-
let signature_info =
307+
let mut signature_info =
308308
into_signature_info(signature.clone(), class_name, gd_self_parameter.is_some());
309309

310+
signature_info.default_parameters = parse_default_parameters(&mut function.params)?;
310311
// For virtual methods, rename/mangle existing user method and create a new method with the original name,
311312
// which performs a dynamic dispatch.
312313
let registered_name = if func.is_virtual {
@@ -688,6 +689,24 @@ fn parse_constant_attr(
688689
Ok(AttrParseResult::Constant(attr.value.clone()))
689690
}
690691

692+
fn parse_default_parameters(
693+
params: &mut venial::Punctuated<venial::FnParam>,
694+
) -> ParseResult<Vec<Option<TokenStream>>> {
695+
let mut res = vec![];
696+
for param in params.iter_mut() {
697+
let typed_param = match &mut param.0 {
698+
venial::FnParam::Receiver(_) => continue,
699+
venial::FnParam::Typed(fn_typed_param) => fn_typed_param,
700+
};
701+
let default = match KvParser::parse_remove(&mut typed_param.attributes, "opt")? {
702+
None => None,
703+
Some(mut parser) => Some(parser.handle_expr_required("default")?),
704+
};
705+
res.push(default);
706+
}
707+
Ok(res)
708+
}
709+
691710
fn bail_attr<R>(attr_name: &Ident, msg: &str, method_name: &Ident) -> ParseResult<R> {
692711
bail!(method_name, "#[{attr_name}]: {msg}")
693712
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use godot::prelude::*;
2+
3+
#[derive(GodotClass)]
4+
#[class(no_init)]
5+
struct HasDefaultParameters {}
6+
7+
#[godot_api]
8+
impl HasDefaultParameters {
9+
#[func]
10+
fn function_with_default_params(
11+
required: i32,
12+
#[opt(default = "test")] string: GString,
13+
// #[opt(default = 123)] integer: i32,
14+
// #[opt(default=None)] object: Option<Gd<Node>>,
15+
) {
16+
}
17+
}

itest/rust/src/register_tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
mod constant_test;
99
mod conversion_test;
10+
mod default_parameters_test;
1011
mod derive_godotconvert_test;
1112
mod func_test;
1213
mod gdscript_ffi_test;

0 commit comments

Comments
 (0)