diff --git a/RELEASES.md b/RELEASES.md index 7a5b65db..8d2baddb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -15,7 +15,7 @@ Breaking changes * `Engine::on_progress` now takes `u64` instead of `&u64`. * The closure for `Engine::on_debug` now takes an additional `Position` parameter. -* `AST::iter_functions` returns a slice of parameter names instead of the internal `ScriptFnDef`. +* `AST::iter_functions` now returns `ScriptFnMetadata`. Enhancements ------------ diff --git a/examples/repl.rs b/examples/repl.rs index a2e48709..7d42cfac 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -142,20 +142,7 @@ fn main() { .for_each(|f| println!("{}", f)); #[cfg(not(feature = "no_function"))] - main_ast - .iter_functions() - .for_each(|(_, access, name, _, params)| { - println!( - "{}{}({}) -> Dynamic", - if access.is_private() { "private " } else { "" }, - name, - params - .iter() - .map(|s| s.as_str()) - .collect::>() - .join(", ") - ) - }); + main_ast.iter_functions().for_each(|f| println!("{}", f)); println!(); continue; diff --git a/src/ast.rs b/src/ast.rs index be07e0f7..0ecf5e76 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -83,6 +83,8 @@ pub struct ScriptFnDef { /// Access to external variables. #[cfg(not(feature = "no_closure"))] pub externals: Vec, + /// Comment block for function. + pub fn_comments: Vec, } impl fmt::Display for ScriptFnDef { @@ -105,6 +107,46 @@ impl fmt::Display for ScriptFnDef { } } +/// A type containing a script-defined function's metadata. +#[derive(Debug, Clone, Hash)] +pub struct ScriptFnMetadata { + pub comments: Vec, + pub access: FnAccess, + pub fn_name: ImmutableString, + pub params: Vec, +} + +impl fmt::Display for ScriptFnMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}{}({}) -> Dynamic", + if self.access.is_private() { + "private " + } else { + "" + }, + self.fn_name, + self.params + .iter() + .map(|p| p.as_str()) + .collect::>() + .join(", ") + ) + } +} + +impl Into for &ScriptFnDef { + fn into(self) -> ScriptFnMetadata { + ScriptFnMetadata { + comments: self.fn_comments.clone(), + access: self.access, + fn_name: self.name.clone(), + params: self.params.iter().cloned().collect(), + } + } +} + /// Compiled AST (abstract syntax tree) of a Rhai script. /// /// # Thread Safety @@ -499,20 +541,10 @@ impl AST { /// Iterate through all functions #[cfg(not(feature = "no_function"))] #[inline(always)] - pub fn iter_functions<'a>( - &'a self, - ) -> impl Iterator + 'a { + pub fn iter_functions<'a>(&'a self) -> impl Iterator + 'a { self.functions .iter_script_fn() - .map(|(namespace, access, name, num_params, fn_def)| { - ( - namespace, - access, - name, - num_params, - fn_def.params.as_slice(), - ) - }) + .map(|(_, _, _, _, fn_def)| fn_def.into()) } /// Clear all function definitions in the [`AST`]. #[cfg(not(feature = "no_function"))] diff --git a/src/lib.rs b/src/lib.rs index 4e492c30..f19553d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,7 +115,7 @@ pub type FLOAT = f64; #[cfg(feature = "f32_float")] pub type FLOAT = f32; -pub use ast::{FnAccess, AST}; +pub use ast::{FnAccess, ScriptFnMetadata, AST}; pub use dynamic::Dynamic; pub use engine::{Engine, EvalContext}; pub use fn_native::{FnPtr, NativeCallContext, Shared}; diff --git a/src/optimize.rs b/src/optimize.rs index 4727dff4..2ef94938 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -868,6 +868,7 @@ pub fn optimize_into_ast( lib: None, #[cfg(not(feature = "no_module"))] mods: Default::default(), + fn_comments: Default::default(), }) .for_each(|fn_def| { lib2.set_script_fn(fn_def); diff --git a/src/parser.rs b/src/parser.rs index 479c2778..af501e00 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -54,6 +54,8 @@ struct ParseState<'e> { /// Tracks a list of external variables (variables that are not explicitly declared in the scope). #[cfg(not(feature = "no_closure"))] externals: HashMap, + /// Latest global comments block. + comments: Vec, /// An indicator that disables variable capturing into externals one single time /// up until the nearest consumed Identifier token. /// If set to false the next call to `access_var` will not capture the variable. @@ -98,6 +100,7 @@ impl<'e> ParseState<'e> { strings: HashMap::with_capacity(64), stack: Vec::with_capacity(16), entry_stack_len: 0, + comments: Default::default(), #[cfg(not(feature = "no_module"))] modules: Default::default(), } @@ -2449,7 +2452,9 @@ fn parse_stmt( pos: pos, }; - let func = parse_fn(input, &mut new_state, lib, access, settings)?; + let fn_comments = state.comments.clone(); + + let func = parse_fn(input, &mut new_state, lib, access, settings, fn_comments)?; // Qualifiers (none) + function name + number of arguments. let hash = calc_script_fn_hash(empty(), &func.name, func.params.len()); @@ -2608,6 +2613,7 @@ fn parse_fn( lib: &mut FunctionsLib, access: FnAccess, mut settings: ParseSettings, + fn_comments: Vec, ) -> Result { #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; @@ -2693,6 +2699,7 @@ fn parse_fn( lib: None, #[cfg(not(feature = "no_module"))] mods: Default::default(), + fn_comments, }) } @@ -2849,6 +2856,7 @@ fn parse_anon_fn( lib: None, #[cfg(not(feature = "no_module"))] mods: Default::default(), + fn_comments: Default::default(), }; let expr = Expr::FnPointer(fn_name, settings.pos);