Reduce cloning.
This commit is contained in:
parent
94313ca095
commit
44d6a5e466
@ -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
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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>() {
|
||||||
(
|
Expr::True(pos)
|
||||||
Some(if value.cast::<bool>() {
|
} else {
|
||||||
Expr::True(pos)
|
Expr::False(pos)
|
||||||
} else {
|
})
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
src/scope.rs
20
src/scope.rs
@ -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(),
|
||||||
|
Loading…
Reference in New Issue
Block a user