Optimize Fn construct.

This commit is contained in:
Stephen Chung 2021-04-06 12:26:38 +08:00
parent d3cfb3c605
commit 131147c65d
2 changed files with 38 additions and 15 deletions

View File

@ -13,8 +13,8 @@ use crate::stdlib::{
}; };
use crate::token::is_valid_identifier; use crate::token::is_valid_identifier;
use crate::{ use crate::{
calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ImmutableString, Module, Position, calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, ImmutableString, Module,
RhaiResult, StaticVec, Position, RhaiResult, StaticVec,
}; };
/// Trait that maps to `Send + Sync` only under the `sync` feature. /// 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 /// A general function pointer, which may carry additional (i.e. curried) argument values
/// to be passed onto a function during a call. /// to be passed onto a function during a call.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FnPtr(ImmutableString, StaticVec<Dynamic>); pub struct FnPtr(Identifier, StaticVec<Dynamic>);
impl FnPtr { impl FnPtr {
/// Create a new function pointer. /// Create a new function pointer.
#[inline(always)] #[inline(always)]
pub fn new(name: impl Into<ImmutableString>) -> Result<Self, Box<EvalAltResult>> { pub fn new(name: impl Into<Identifier>) -> Result<Self, Box<EvalAltResult>> {
name.into().try_into() name.into().try_into()
} }
/// Create a new function pointer without checking its parameters. /// Create a new function pointer without checking its parameters.
#[inline(always)] #[inline(always)]
pub(crate) fn new_unchecked( pub(crate) fn new_unchecked(name: impl Into<Identifier>, curry: StaticVec<Dynamic>) -> Self {
name: impl Into<ImmutableString>,
curry: StaticVec<Dynamic>,
) -> Self {
Self(name.into(), curry) Self(name.into(), curry)
} }
/// Get the name of the function. /// Get the name of the function.
@ -275,12 +272,12 @@ impl FnPtr {
} }
/// Get the name of the function. /// Get the name of the function.
#[inline(always)] #[inline(always)]
pub(crate) fn get_fn_name(&self) -> &ImmutableString { pub(crate) fn get_fn_name(&self) -> &Identifier {
&self.0 &self.0
} }
/// Get the underlying data of the function pointer. /// Get the underlying data of the function pointer.
#[inline(always)] #[inline(always)]
pub(crate) fn take_data(self) -> (ImmutableString, StaticVec<Dynamic>) { pub(crate) fn take_data(self) -> (Identifier, StaticVec<Dynamic>) {
(self.0, self.1) (self.0, self.1)
} }
/// Get the curried arguments. /// Get the curried arguments.
@ -362,11 +359,11 @@ impl fmt::Display for FnPtr {
} }
} }
impl TryFrom<ImmutableString> for FnPtr { impl TryFrom<Identifier> for FnPtr {
type Error = Box<EvalAltResult>; type Error = Box<EvalAltResult>;
#[inline(always)] #[inline(always)]
fn try_from(value: ImmutableString) -> Result<Self, Self::Error> { fn try_from(value: Identifier) -> Result<Self, Self::Error> {
if is_valid_identifier(value.chars()) { if is_valid_identifier(value.chars()) {
Ok(Self(value, Default::default())) Ok(Self(value, Default::default()))
} else { } else {
@ -375,12 +372,22 @@ impl TryFrom<ImmutableString> for FnPtr {
} }
} }
impl TryFrom<ImmutableString> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: ImmutableString) -> Result<Self, Self::Error> {
let s: Identifier = value.into();
Self::try_from(s)
}
}
impl TryFrom<String> for FnPtr { impl TryFrom<String> for FnPtr {
type Error = Box<EvalAltResult>; type Error = Box<EvalAltResult>;
#[inline(always)] #[inline(always)]
fn try_from(value: String) -> Result<Self, Self::Error> { fn try_from(value: String) -> Result<Self, Self::Error> {
let s: ImmutableString = value.into(); let s: Identifier = value.into();
Self::try_from(s) Self::try_from(s)
} }
} }
@ -390,7 +397,7 @@ impl TryFrom<&str> for FnPtr {
#[inline(always)] #[inline(always)]
fn try_from(value: &str) -> Result<Self, Self::Error> { fn try_from(value: &str) -> Result<Self, Self::Error> {
let s: ImmutableString = value.into(); let s: Identifier = value.into();
Self::try_from(s) Self::try_from(s)
} }
} }

View File

@ -2,7 +2,7 @@
use crate::ast::{Expr, Stmt, StmtBlock}; use crate::ast::{Expr, Stmt, StmtBlock};
use crate::dynamic::AccessMode; 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::fn_builtin::get_builtin_binary_op_fn;
use crate::parser::map_dynamic_to_expr; use crate::parser::map_dynamic_to_expr;
use crate::stdlib::{ use crate::stdlib::{
@ -794,6 +794,22 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
Expr::FnCall(x, _) if x.name == KEYWORD_EVAL => { Expr::FnCall(x, _) if x.name == KEYWORD_EVAL => {
state.propagate_constants = false; 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 // Do not call some special keywords
Expr::FnCall(x, _) if DONT_EVAL_KEYWORDS.contains(&x.name.as_ref()) => { Expr::FnCall(x, _) if DONT_EVAL_KEYWORDS.contains(&x.name.as_ref()) => {
x.args.iter_mut().for_each(|a| optimize_expr(a, state)); x.args.iter_mut().for_each(|a| optimize_expr(a, state));