Pre-calculate property getter/setter function names.
This commit is contained in:
parent
d6fd5416b0
commit
996a54279c
@ -884,9 +884,10 @@ impl Engine {
|
|||||||
// {xxx:map}.id = ???
|
// {xxx:map}.id = ???
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(x) if obj.is::<Map>() && new_val.is_some() => {
|
Expr::Property(x) if obj.is::<Map>() && new_val.is_some() => {
|
||||||
let index = x.0.clone().into();
|
let ((prop, _, _), pos) = x.as_ref();
|
||||||
|
let index = prop.clone().into();
|
||||||
let mut val =
|
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())?;
|
val.set_value(new_val.unwrap(), rhs.position())?;
|
||||||
Ok((Default::default(), true))
|
Ok((Default::default(), true))
|
||||||
@ -894,24 +895,25 @@ impl Engine {
|
|||||||
// {xxx:map}.id
|
// {xxx:map}.id
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(x) if obj.is::<Map>() => {
|
Expr::Property(x) if obj.is::<Map>() => {
|
||||||
let index = x.0.clone().into();
|
let ((prop, _, _), pos) = x.as_ref();
|
||||||
|
let index = prop.clone().into();
|
||||||
let val =
|
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))
|
Ok((val.clone_into_dynamic(), false))
|
||||||
}
|
}
|
||||||
// xxx.id = ???
|
// xxx.id = ???
|
||||||
Expr::Property(x) if new_val.is_some() => {
|
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()];
|
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))
|
.map(|(v, _)| (v, true))
|
||||||
}
|
}
|
||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(x) => {
|
Expr::Property(x) => {
|
||||||
let fn_name = make_getter(&x.0);
|
let ((_, getter, _), pos) = x.as_ref();
|
||||||
let mut args = [obj];
|
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))
|
.map(|(v, _)| (v, false))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -920,7 +922,8 @@ impl Engine {
|
|||||||
let is_idx = matches!(rhs, Expr::Index(_));
|
let is_idx = matches!(rhs, Expr::Index(_));
|
||||||
|
|
||||||
let val = if let Expr::Property(p) = &x.0 {
|
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)?
|
self.get_indexed_mut(state, obj, is_ref, index, x.2, op_pos, false)?
|
||||||
} else {
|
} else {
|
||||||
// Syntax error
|
// Syntax error
|
||||||
@ -940,8 +943,8 @@ impl Engine {
|
|||||||
let args = &mut [obj, &mut Default::default()];
|
let args = &mut [obj, &mut Default::default()];
|
||||||
|
|
||||||
let (mut val, updated) = if let Expr::Property(p) = &x.0 {
|
let (mut val, updated) = if let Expr::Property(p) = &x.0 {
|
||||||
let fn_name = make_getter(&p.0);
|
let ((_, getter, _), _) = p.as_ref();
|
||||||
self.exec_fn_call(state, &fn_name, 0, &mut args[..1], is_ref, None, x.2, 0)?
|
self.exec_fn_call(state, getter, 0, &mut args[..1], is_ref, None, x.2, 0)?
|
||||||
} else {
|
} else {
|
||||||
// Syntax error
|
// Syntax error
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
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
|
// Feed the value back via a setter just in case it has been updated
|
||||||
if updated || may_be_changed {
|
if updated || may_be_changed {
|
||||||
if let Expr::Property(p) = &x.0 {
|
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
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
args[1] = val;
|
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 {
|
.or_else(|err| match *err {
|
||||||
// If there is no setter, no need to feed it back because the property is read-only
|
// If there is no setter, no need to feed it back because the property is read-only
|
||||||
EvalAltResult::ErrorDotExpr(_, _) => Ok(Default::default()),
|
EvalAltResult::ErrorDotExpr(_, _) => Ok(Default::default()),
|
||||||
|
@ -392,11 +392,12 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
Expr::Dot(x) => match (x.0, x.1) {
|
Expr::Dot(x) => match (x.0, x.1) {
|
||||||
// map.string
|
// map.string
|
||||||
(Expr::Map(m), Expr::Property(p)) if m.0.iter().all(|(_, x)| x.is_pure()) => {
|
(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.
|
// Map literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let pos = m.1;
|
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))
|
.map(|(_, expr)| expr.set_position(pos))
|
||||||
.unwrap_or_else(|| Expr::Unit(pos))
|
.unwrap_or_else(|| Expr::Unit(pos))
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::calc_fn_hash;
|
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::error::{LexError, ParseError, ParseErrorType};
|
||||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
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 access - ((variable name, position), optional modules, hash, optional index)
|
||||||
Variable(Box<((String, Position), MRef, u64, Option<NonZeroUsize>)>),
|
Variable(Box<((String, Position), MRef, u64, Option<NonZeroUsize>)>),
|
||||||
/// Property access.
|
/// Property access.
|
||||||
Property(Box<(String, Position)>),
|
Property(Box<((String, String, String), Position)>),
|
||||||
/// { stmt }
|
/// { stmt }
|
||||||
Stmt(Box<(Stmt, Position)>),
|
Stmt(Box<(Stmt, Position)>),
|
||||||
/// func(expr, ... ) - ((function name, position), optional modules, hash, arguments, optional default value)
|
/// func(expr, ... ) - ((function name, position), optional modules, hash, arguments, optional default value)
|
||||||
@ -641,7 +641,9 @@ impl Expr {
|
|||||||
match self {
|
match self {
|
||||||
Self::Variable(x) if x.1.is_none() => {
|
Self::Variable(x) if x.1.is_none() => {
|
||||||
let (name, pos) = x.0;
|
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,
|
_ => self,
|
||||||
}
|
}
|
||||||
@ -1431,8 +1433,13 @@ fn make_dot_expr(
|
|||||||
}
|
}
|
||||||
// lhs.id
|
// lhs.id
|
||||||
(lhs, Expr::Variable(x)) if x.1.is_none() => {
|
(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 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)))
|
Expr::Dot(Box::new((lhs, rhs, op_pos)))
|
||||||
}
|
}
|
||||||
(lhs, Expr::Property(x)) => {
|
(lhs, Expr::Property(x)) => {
|
||||||
|
@ -17,6 +17,7 @@ use crate::stdlib::collections::hash_map::DefaultHasher;
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use ahash::AHasher;
|
use ahash::AHasher;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn EMPTY_TYPE_ID() -> TypeId {
|
pub fn EMPTY_TYPE_ID() -> TypeId {
|
||||||
TypeId::of::<()>()
|
TypeId::of::<()>()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user