Skip to content

Commit fe9e7a6

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

File tree

5 files changed

+77
-4
lines changed

5 files changed

+77
-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: 38 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,10 @@ 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)?;
131+
132+
let default_parameter_types = ();
129133
// Transport #[cfg] attrs to the FFI glue to ensure functions which were conditionally
130134
// removed from compilation don't cause errors.
131135
let cfg_attrs = util::extract_cfg_attrs(&func_definition.external_attributes)
@@ -158,6 +162,9 @@ pub fn make_method_registration(
158162
&[
159163
#( #param_ident_strs ),*
160164
],
165+
vec![
166+
#(::godot::builtin::Variant::from(#default_parameters)),*
167+
]
161168
)
162169
};
163170

@@ -175,6 +182,32 @@ pub fn make_method_registration(
175182
Ok(registration)
176183
}
177184

185+
fn validate_default_parameters(
186+
default_parameters: &[Option<TokenStream>],
187+
) -> ParseResult<Vec<TokenStream>> {
188+
let mut res = vec![];
189+
let mut allowed = true;
190+
for param in default_parameters.iter().rev() {
191+
match (param, allowed) {
192+
(Some(tk), true) => {
193+
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
194+
}
195+
(None, true) => {
196+
allowed = false;
197+
}
198+
(None, false) => {}
199+
(Some(tk), false) => {
200+
return bail!(
201+
tk,
202+
"opt arguments are only allowed at the end of the argument list."
203+
);
204+
}
205+
}
206+
}
207+
res.reverse();
208+
Ok(res)
209+
}
210+
178211
// ----------------------------------------------------------------------------------------------------------------------------------------------
179212
// Implementation
180213

@@ -199,6 +232,8 @@ pub struct SignatureInfo {
199232
///
200233
/// Index points into original venial tokens (i.e. takes into account potential receiver params).
201234
pub modified_param_types: Vec<(usize, venial::TypeExpr)>,
235+
/// Contains expressions of the default values of parameters.
236+
pub default_parameters: Vec<Option<TokenStream>>,
202237
}
203238

204239
impl SignatureInfo {
@@ -210,6 +245,7 @@ impl SignatureInfo {
210245
param_types: vec![],
211246
return_type: quote! { () },
212247
modified_param_types: vec![],
248+
default_parameters: vec![],
213249
}
214250
}
215251

@@ -412,6 +448,7 @@ pub(crate) fn into_signature_info(
412448
param_types,
413449
return_type: ret_type,
414450
modified_param_types,
451+
default_parameters: vec![],
415452
}
416453
}
417454

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)