diff --git a/src/fn_native.rs b/src/fn_native.rs index 3625cd08..8ff22a05 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -13,8 +13,8 @@ use crate::stdlib::{ }; use crate::token::is_valid_identifier; use crate::{ - calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ImmutableString, Module, Position, - RhaiResult, StaticVec, + calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, ImmutableString, Module, + Position, RhaiResult, StaticVec, }; /// Trait that maps to `Send + Sync` only under the `sync` feature. @@ -252,20 +252,17 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic]; /// A general function pointer, which may carry additional (i.e. curried) argument values /// to be passed onto a function during a call. #[derive(Debug, Clone)] -pub struct FnPtr(ImmutableString, StaticVec); +pub struct FnPtr(Identifier, StaticVec); impl FnPtr { /// Create a new function pointer. #[inline(always)] - pub fn new(name: impl Into) -> Result> { + pub fn new(name: impl Into) -> Result> { name.into().try_into() } /// Create a new function pointer without checking its parameters. #[inline(always)] - pub(crate) fn new_unchecked( - name: impl Into, - curry: StaticVec, - ) -> Self { + pub(crate) fn new_unchecked(name: impl Into, curry: StaticVec) -> Self { Self(name.into(), curry) } /// Get the name of the function. @@ -275,12 +272,12 @@ impl FnPtr { } /// Get the name of the function. #[inline(always)] - pub(crate) fn get_fn_name(&self) -> &ImmutableString { + pub(crate) fn get_fn_name(&self) -> &Identifier { &self.0 } /// Get the underlying data of the function pointer. #[inline(always)] - pub(crate) fn take_data(self) -> (ImmutableString, StaticVec) { + pub(crate) fn take_data(self) -> (Identifier, StaticVec) { (self.0, self.1) } /// Get the curried arguments. @@ -362,11 +359,11 @@ impl fmt::Display for FnPtr { } } -impl TryFrom for FnPtr { +impl TryFrom for FnPtr { type Error = Box; #[inline(always)] - fn try_from(value: ImmutableString) -> Result { + fn try_from(value: Identifier) -> Result { if is_valid_identifier(value.chars()) { Ok(Self(value, Default::default())) } else { @@ -375,12 +372,22 @@ impl TryFrom for FnPtr { } } +impl TryFrom for FnPtr { + type Error = Box; + + #[inline(always)] + fn try_from(value: ImmutableString) -> Result { + let s: Identifier = value.into(); + Self::try_from(s) + } +} + impl TryFrom for FnPtr { type Error = Box; #[inline(always)] fn try_from(value: String) -> Result { - let s: ImmutableString = value.into(); + let s: Identifier = value.into(); Self::try_from(s) } } @@ -390,7 +397,7 @@ impl TryFrom<&str> for FnPtr { #[inline(always)] fn try_from(value: &str) -> Result { - let s: ImmutableString = value.into(); + let s: Identifier = value.into(); Self::try_from(s) } } diff --git a/src/optimize.rs b/src/optimize.rs index de82a8f9..22eb64e6 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -2,7 +2,7 @@ use crate::ast::{Expr, Stmt, StmtBlock}; use crate::dynamic::AccessMode; -use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF}; +use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF}; use crate::fn_builtin::get_builtin_binary_op_fn; use crate::parser::map_dynamic_to_expr; use crate::stdlib::{ @@ -794,6 +794,22 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { Expr::FnCall(x, _) if x.name == KEYWORD_EVAL => { state.propagate_constants = false; } + // Fn + Expr::FnCall(x, pos) + if x.namespace.is_none() // Non-qualified + && state.optimization_level == OptimizationLevel::Simple // simple optimizations + && x.num_args() == 1 + && matches!(x.args[0], Expr::StringConstant(_, _)) + && x.name == KEYWORD_FN_PTR + => { + if let Expr::StringConstant(s, _) = mem::take(&mut x.args[0]) { + state.set_dirty(); + *expr = Expr::FnPointer(s, *pos); + } else { + unreachable!(); + } + } + // Do not call some special keywords Expr::FnCall(x, _) if DONT_EVAL_KEYWORDS.contains(&x.name.as_ref()) => { x.args.iter_mut().for_each(|a| optimize_expr(a, state));