From 996a54279cc60f2fadfcaa55a37dc48f3c047fff Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 13 May 2020 10:19:18 +0800 Subject: [PATCH] Pre-calculate property getter/setter function names. --- src/engine.rs | 29 ++++++++++++++++------------- src/optimize.rs | 3 ++- src/parser.rs | 15 +++++++++++---- src/utils.rs | 1 + 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 6245d1cc..05a97502 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -884,9 +884,10 @@ impl Engine { // {xxx:map}.id = ??? #[cfg(not(feature = "no_object"))] Expr::Property(x) if obj.is::() && new_val.is_some() => { - let index = x.0.clone().into(); + let ((prop, _, _), pos) = x.as_ref(); + let index = prop.clone().into(); let mut val = - self.get_indexed_mut(state, obj, is_ref, index, x.1, op_pos, true)?; + self.get_indexed_mut(state, obj, is_ref, index, *pos, op_pos, true)?; val.set_value(new_val.unwrap(), rhs.position())?; Ok((Default::default(), true)) @@ -894,24 +895,25 @@ impl Engine { // {xxx:map}.id #[cfg(not(feature = "no_object"))] Expr::Property(x) if obj.is::() => { - let index = x.0.clone().into(); + let ((prop, _, _), pos) = x.as_ref(); + let index = prop.clone().into(); let val = - self.get_indexed_mut(state, obj, is_ref, index, x.1, op_pos, false)?; + self.get_indexed_mut(state, obj, is_ref, index, *pos, op_pos, false)?; Ok((val.clone_into_dynamic(), false)) } // xxx.id = ??? Expr::Property(x) if new_val.is_some() => { - let fn_name = make_setter(&x.0); + let ((_, _, setter), pos) = x.as_ref(); let mut args = [obj, new_val.as_mut().unwrap()]; - self.exec_fn_call(state, &fn_name, 0, &mut args, is_ref, None, x.1, 0) + self.exec_fn_call(state, setter, 0, &mut args, is_ref, None, *pos, 0) .map(|(v, _)| (v, true)) } // xxx.id Expr::Property(x) => { - let fn_name = make_getter(&x.0); + let ((_, getter, _), pos) = x.as_ref(); let mut args = [obj]; - self.exec_fn_call(state, &fn_name, 0, &mut args, is_ref, None, x.1, 0) + self.exec_fn_call(state, getter, 0, &mut args, is_ref, None, *pos, 0) .map(|(v, _)| (v, false)) } #[cfg(not(feature = "no_object"))] @@ -920,7 +922,8 @@ impl Engine { let is_idx = matches!(rhs, Expr::Index(_)); let val = if let Expr::Property(p) = &x.0 { - let index = p.0.clone().into(); + let ((prop, _, _), _) = p.as_ref(); + let index = prop.clone().into(); self.get_indexed_mut(state, obj, is_ref, index, x.2, op_pos, false)? } else { // Syntax error @@ -940,8 +943,8 @@ impl Engine { let args = &mut [obj, &mut Default::default()]; let (mut val, updated) = if let Expr::Property(p) = &x.0 { - let fn_name = make_getter(&p.0); - self.exec_fn_call(state, &fn_name, 0, &mut args[..1], is_ref, None, x.2, 0)? + let ((_, getter, _), _) = p.as_ref(); + self.exec_fn_call(state, getter, 0, &mut args[..1], is_ref, None, x.2, 0)? } else { // Syntax error return Err(Box::new(EvalAltResult::ErrorDotExpr( @@ -965,10 +968,10 @@ impl Engine { // Feed the value back via a setter just in case it has been updated if updated || may_be_changed { if let Expr::Property(p) = &x.0 { - let fn_name = make_setter(&p.0); + let ((_, _, setter), _) = p.as_ref(); // Re-use args because the first &mut parameter will not be consumed args[1] = val; - self.exec_fn_call(state, &fn_name, 0, args, is_ref, None, x.2, 0) + self.exec_fn_call(state, setter, 0, args, is_ref, None, x.2, 0) .or_else(|err| match *err { // If there is no setter, no need to feed it back because the property is read-only EvalAltResult::ErrorDotExpr(_, _) => Ok(Default::default()), diff --git a/src/optimize.rs b/src/optimize.rs index 0f83a703..9670f288 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -392,11 +392,12 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr { Expr::Dot(x) => match (x.0, x.1) { // map.string (Expr::Map(m), Expr::Property(p)) if m.0.iter().all(|(_, x)| x.is_pure()) => { + let ((prop, _, _), _) = p.as_ref(); // Map literal where everything is pure - promote the indexed item. // All other items can be thrown away. state.set_dirty(); let pos = m.1; - m.0.into_iter().find(|((name, _), _)| name == &p.0) + m.0.into_iter().find(|((name, _), _)| name == prop) .map(|(_, expr)| expr.set_position(pos)) .unwrap_or_else(|| Expr::Unit(pos)) } diff --git a/src/parser.rs b/src/parser.rs index 8264da56..42f8a5a5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,7 +2,7 @@ use crate::any::{Dynamic, Union}; use crate::calc_fn_hash; -use crate::engine::{Engine, FunctionsLib}; +use crate::engine::{make_getter, make_setter, Engine, FunctionsLib}; use crate::error::{LexError, ParseError, ParseErrorType}; use crate::optimize::{optimize_into_ast, OptimizationLevel}; use crate::scope::{EntryType as ScopeEntryType, Scope}; @@ -395,7 +395,7 @@ pub enum Expr { /// Variable access - ((variable name, position), optional modules, hash, optional index) Variable(Box<((String, Position), MRef, u64, Option)>), /// Property access. - Property(Box<(String, Position)>), + Property(Box<((String, String, String), Position)>), /// { stmt } Stmt(Box<(Stmt, Position)>), /// func(expr, ... ) - ((function name, position), optional modules, hash, arguments, optional default value) @@ -641,7 +641,9 @@ impl Expr { match self { Self::Variable(x) if x.1.is_none() => { let (name, pos) = x.0; - Self::Property(Box::new((name.clone(), pos))) + let getter = make_getter(&name); + let setter = make_setter(&name); + Self::Property(Box::new(((name.clone(), getter, setter), pos))) } _ => self, } @@ -1431,8 +1433,13 @@ fn make_dot_expr( } // lhs.id (lhs, Expr::Variable(x)) if x.1.is_none() => { + let (name, pos) = x.0; let lhs = if is_index { lhs.into_property() } else { lhs }; - let rhs = Expr::Property(Box::new(x.0)); + + let getter = make_getter(&name); + let setter = make_setter(&name); + let rhs = Expr::Property(Box::new(((name, getter, setter), pos))); + Expr::Dot(Box::new((lhs, rhs, op_pos))) } (lhs, Expr::Property(x)) => { diff --git a/src/utils.rs b/src/utils.rs index 4694fce4..381ab1a0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -17,6 +17,7 @@ use crate::stdlib::collections::hash_map::DefaultHasher; #[cfg(feature = "no_std")] use ahash::AHasher; +#[inline(always)] pub fn EMPTY_TYPE_ID() -> TypeId { TypeId::of::<()>() }