Add ScriptFnMetadata.

This commit is contained in:
Stephen Chung 2020-12-12 18:44:28 +08:00
parent 1087c338bd
commit 26449a9f1c
6 changed files with 57 additions and 29 deletions

View File

@ -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
------------

View File

@ -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::<Vec<_>>()
.join(", ")
)
});
main_ast.iter_functions().for_each(|f| println!("{}", f));
println!();
continue;

View File

@ -83,6 +83,8 @@ pub struct ScriptFnDef {
/// Access to external variables.
#[cfg(not(feature = "no_closure"))]
pub externals: Vec<ImmutableString>,
/// Comment block for function.
pub fn_comments: Vec<String>,
}
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<String>,
pub access: FnAccess,
pub fn_name: ImmutableString,
pub params: Vec<ImmutableString>,
}
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::<Vec<_>>()
.join(", ")
)
}
}
impl Into<ScriptFnMetadata> 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<Item = (FnNamespace, FnAccess, &str, usize, &[ImmutableString])> + 'a {
pub fn iter_functions<'a>(&'a self) -> impl Iterator<Item = ScriptFnMetadata> + '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"))]

View File

@ -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};

View File

@ -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);

View File

@ -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<ImmutableString, Position>,
/// Latest global comments block.
comments: Vec<String>,
/// 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<String>,
) -> Result<ScriptFnDef, ParseError> {
#[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);