Reduce cloning.

This commit is contained in:
Stephen Chung 2020-04-05 17:44:48 +08:00
parent 94313ca095
commit 44d6a5e466
7 changed files with 44 additions and 48 deletions

View File

@ -141,18 +141,18 @@ fn main() {
.compile_with_scope(&scope, &script) .compile_with_scope(&scope, &script)
.map_err(EvalAltResult::ErrorParsing) .map_err(EvalAltResult::ErrorParsing)
.and_then(|r| { .and_then(|r| {
ast_u = r; ast_u = r.clone();
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
{ {
engine.set_optimization_level(OptimizationLevel::Full); engine.set_optimization_level(OptimizationLevel::Full);
ast = engine.optimize_ast(&scope, &ast_u); ast = engine.optimize_ast(&scope, r);
engine.set_optimization_level(OptimizationLevel::None); engine.set_optimization_level(OptimizationLevel::None);
} }
#[cfg(feature = "no_optimize")] #[cfg(feature = "no_optimize")]
{ {
ast = ast_u.clone(); ast = r;
} }
// Merge the AST into the main // Merge the AST into the main

View File

@ -125,7 +125,7 @@ impl fmt::Debug for Variant {
impl Clone for Dynamic { impl Clone for Dynamic {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Any::into_dynamic(self.as_ref()) self.as_ref().into_dynamic()
} }
} }

View File

@ -986,7 +986,7 @@ impl<'e> Engine<'e> {
} }
/// Optimize the `AST` with constants defined in an external Scope. /// Optimize the `AST` with constants defined in an external Scope.
/// An optimized copy of the `AST` is returned while the original `AST` is untouched. /// An optimized copy of the `AST` is returned while the original `AST` is consumed.
/// ///
/// Although optimization is performed by default during compilation, sometimes it is necessary to /// Although optimization is performed by default during compilation, sometimes it is necessary to
/// _re_-optimize an AST. For example, when working with constants that are passed in via an /// _re_-optimize an AST. For example, when working with constants that are passed in via an
@ -997,11 +997,11 @@ impl<'e> Engine<'e> {
/// compiled just once. Before evaluation, constants are passed into the `Engine` via an external scope /// compiled just once. Before evaluation, constants are passed into the `Engine` via an external scope
/// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running. /// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running.
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
pub fn optimize_ast(&self, scope: &Scope, ast: &AST) -> AST { pub fn optimize_ast(&self, scope: &Scope, ast: AST) -> AST {
optimize_into_ast( optimize_into_ast(
self, self,
scope, scope,
ast.0.clone(), ast.0,
ast.1.iter().map(|fn_def| fn_def.as_ref().clone()).collect(), ast.1.iter().map(|fn_def| fn_def.as_ref().clone()).collect(),
) )
} }

View File

@ -452,10 +452,11 @@ impl Engine<'_> {
scope.extend( scope.extend(
// Put arguments into scope as variables - variable name is copied // Put arguments into scope as variables - variable name is copied
// TODO - avoid copying variable name
fn_def fn_def
.params .params
.iter() .iter()
.zip(args.iter().map(|x| (*x).into_dynamic())) .zip(args.into_iter().map(|x| (*x).into_dynamic()))
.map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)), .map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)),
); );
@ -481,7 +482,7 @@ impl Engine<'_> {
fn_def fn_def
.params .params
.iter() .iter()
.zip(args.iter().map(|x| (*x).into_dynamic())) .zip(args.into_iter().map(|x| (*x).into_dynamic()))
.map(|(name, value)| (name, ScopeEntryType::Normal, value)), .map(|(name, value)| (name, ScopeEntryType::Normal, value)),
); );
@ -1227,6 +1228,7 @@ impl Engine<'_> {
*scope.get_mut(entry) = rhs_val.clone(); *scope.get_mut(entry) = rhs_val.clone();
Ok(rhs_val) Ok(rhs_val)
} }
ScopeSource { ScopeSource {
typ: ScopeEntryType::Constant, typ: ScopeEntryType::Constant,
.. ..
@ -1560,6 +1562,7 @@ impl Engine<'_> {
if let Some(type_iterators) = &self.type_iterators { if let Some(type_iterators) = &self.type_iterators {
if let Some(iter_fn) = type_iterators.get(&tid) { if let Some(iter_fn) = type_iterators.get(&tid) {
// Add the loop variable - variable name is copied // Add the loop variable - variable name is copied
// TODO - avoid copying variable name
scope.push(name.clone(), ()); scope.push(name.clone(), ());
let entry = ScopeSource { let entry = ScopeSource {
@ -1622,11 +1625,13 @@ impl Engine<'_> {
// Let statement // Let statement
Stmt::Let(name, Some(expr), _) => { Stmt::Let(name, Some(expr), _) => {
let val = self.eval_expr(scope, expr, level)?; let val = self.eval_expr(scope, expr, level)?;
// TODO - avoid copying variable name in inner block?
scope.push_dynamic_value(name.clone(), ScopeEntryType::Normal, val, false); scope.push_dynamic_value(name.clone(), ScopeEntryType::Normal, val, false);
Ok(().into_dynamic()) Ok(().into_dynamic())
} }
Stmt::Let(name, None, _) => { Stmt::Let(name, None, _) => {
// TODO - avoid copying variable name in inner block?
scope.push(name.clone(), ()); scope.push(name.clone(), ());
Ok(().into_dynamic()) Ok(().into_dynamic())
} }
@ -1634,6 +1639,7 @@ impl Engine<'_> {
// Const statement // Const statement
Stmt::Const(name, expr, _) if expr.is_constant() => { Stmt::Const(name, expr, _) if expr.is_constant() => {
let val = self.eval_expr(scope, expr, level)?; let val = self.eval_expr(scope, expr, level)?;
// TODO - avoid copying variable name in inner block?
scope.push_dynamic_value(name.clone(), ScopeEntryType::Constant, val, true); scope.push_dynamic_value(name.clone(), ScopeEntryType::Constant, val, true);
Ok(().into_dynamic()) Ok(().into_dynamic())
} }

View File

@ -480,7 +480,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
// Otherwise use the default value, if any // Otherwise use the default value, if any
def_value.clone() def_value.clone()
} }
}).and_then(|result| map_dynamic_to_expr(result, pos).0) }).and_then(|result| map_dynamic_to_expr(result, pos))
.map(|expr| { .map(|expr| {
state.set_dirty(); state.set_dirty();
expr expr

View File

@ -221,15 +221,15 @@ impl AST {
/// # } /// # }
/// ``` /// ```
pub fn merge(&self, other: &Self) -> Self { pub fn merge(&self, other: &Self) -> Self {
let Self(ast, functions) = self; let Self(statements, functions) = self;
let ast = match (ast.is_empty(), other.0.is_empty()) { let ast = match (statements.is_empty(), other.0.is_empty()) {
(false, false) => { (false, false) => {
let mut ast = ast.clone(); let mut statements = statements.clone();
ast.extend(other.0.iter().cloned()); statements.extend(other.0.iter().cloned());
ast statements
} }
(false, true) => ast.clone(), (false, true) => statements.clone(),
(true, false) => other.0.clone(), (true, false) => other.0.clone(),
(true, true) => vec![], (true, true) => vec![],
}; };
@ -1733,8 +1733,8 @@ fn parse_map_literal<'a>(
PERR::MissingToken("}".into(), "to end this object map literal".into()) PERR::MissingToken("}".into(), "to end this object map literal".into())
.into_err_eof() .into_err_eof()
})? { })? {
(Token::Identifier(s), pos) => (s.clone(), pos), (Token::Identifier(s), pos) => (s, pos),
(Token::StringConst(s), pos) => (s.clone(), pos), (Token::StringConst(s), pos) => (s, pos),
(_, pos) if map.is_empty() => { (_, pos) if map.is_empty() => {
return Err(PERR::MissingToken( return Err(PERR::MissingToken(
"}".into(), "}".into(),
@ -2727,35 +2727,27 @@ pub fn parse<'a, 'e>(
/// Map a `Dynamic` value to an expression. /// Map a `Dynamic` value to an expression.
/// ///
/// Returns Some(expression) if conversion is successful. Otherwise None. /// Returns Some(expression) if conversion is successful. Otherwise None.
pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> (Option<Expr>, Dynamic) { pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option<Expr> {
if value.is::<INT>() { if value.is::<INT>() {
let value2 = value.clone(); Some(Expr::IntegerConstant(value.cast(), pos))
(Some(Expr::IntegerConstant(value.cast(), pos)), value2)
} else if value.is::<char>() { } else if value.is::<char>() {
let value2 = value.clone(); Some(Expr::CharConstant(value.cast(), pos))
(Some(Expr::CharConstant(value.cast(), pos)), value2)
} else if value.is::<String>() { } else if value.is::<String>() {
let value2 = value.clone(); Some(Expr::StringConstant(value.cast(), pos))
(Some(Expr::StringConstant(value.cast(), pos)), value2)
} else if value.is::<bool>() { } else if value.is::<bool>() {
let value2 = value.clone();
(
Some(if value.cast::<bool>() { Some(if value.cast::<bool>() {
Expr::True(pos) Expr::True(pos)
} else { } else {
Expr::False(pos) Expr::False(pos)
}), })
value2,
)
} else { } else {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
{ {
if value.is::<FLOAT>() { if value.is::<FLOAT>() {
let value2 = value.clone(); return Some(Expr::FloatConstant(value.cast(), pos));
return (Some(Expr::FloatConstant(value.cast(), pos)), value2);
} }
} }
(None, value) None
} }
} }

View File

@ -126,17 +126,15 @@ impl<'a> Scope<'a> {
value: Dynamic, value: Dynamic,
map_expr: bool, map_expr: bool,
) { ) {
let (expr, value) = if map_expr {
map_dynamic_to_expr(value, Position::none())
} else {
(None, value)
};
self.0.push(Entry { self.0.push(Entry {
name: name.into(), name: name.into(),
typ: entry_type, typ: entry_type,
value, value: value.clone(),
expr, expr: if map_expr {
map_dynamic_to_expr(value, Position::none())
} else {
None
},
}); });
} }
@ -163,15 +161,15 @@ impl<'a> Scope<'a> {
.find(|(_, Entry { name, .. })| name == key) .find(|(_, Entry { name, .. })| name == key)
.map( .map(
|( |(
i, index,
Entry { Entry {
name, typ, value, .. name, typ, value, ..
}, },
)| { )| {
( (
EntryRef { EntryRef {
name: name.as_ref(), name,
index: i, index,
typ: *typ, typ: *typ,
}, },
value.clone(), value.clone(),