Streamine StmtBlock.
This commit is contained in:
parent
980a13ca42
commit
1f987ec61a
41
src/ast.rs
41
src/ast.rs
@ -10,7 +10,7 @@ use crate::stdlib::{
|
|||||||
hash::Hash,
|
hash::Hash,
|
||||||
iter::empty,
|
iter::empty,
|
||||||
num::{NonZeroU8, NonZeroUsize},
|
num::{NonZeroU8, NonZeroUsize},
|
||||||
ops::{Add, AddAssign},
|
ops::{Add, AddAssign, Deref, DerefMut},
|
||||||
vec,
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
@ -247,7 +247,7 @@ impl AST {
|
|||||||
#[deprecated = "this method is volatile and may change"]
|
#[deprecated = "this method is volatile and may change"]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn statements(&self) -> &[Stmt] {
|
pub fn statements(&self) -> &[Stmt] {
|
||||||
&self.body.statements
|
&self.body.0
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the statements.
|
/// Get a mutable reference to the statements.
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
@ -718,7 +718,7 @@ impl AST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
for stmt in self.iter_fn_def().flat_map(|f| f.body.statements.iter()) {
|
for stmt in self.iter_fn_def().flat_map(|f| f.body.0.iter()) {
|
||||||
if !stmt.walk(path, on_node) {
|
if !stmt.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -824,9 +824,13 @@ impl<'a> From<&'a Expr> for ASTNode<'a> {
|
|||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Clone, Hash, Default)]
|
#[derive(Clone, Hash, Default)]
|
||||||
pub struct StmtBlock(pub StaticVec<Stmt>, pub Position);
|
pub struct StmtBlock(StaticVec<Stmt>, Position);
|
||||||
|
|
||||||
impl StmtBlock {
|
impl StmtBlock {
|
||||||
|
/// Create a new [`StmtBlock`].
|
||||||
|
pub fn new(statements: impl Into<StaticVec<Stmt>>, pos: Position) -> Self {
|
||||||
|
Self(statements.into(), pos)
|
||||||
|
}
|
||||||
/// Is this statements block empty?
|
/// Is this statements block empty?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
@ -837,6 +841,28 @@ impl StmtBlock {
|
|||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
/// Get the position of this statements block.
|
||||||
|
pub fn position(&self) -> Position {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
/// Get the statements of this statements block.
|
||||||
|
pub fn statements(&mut self) -> &mut StaticVec<Stmt> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for StmtBlock {
|
||||||
|
type Target = StaticVec<Stmt>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for StmtBlock {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for StmtBlock {
|
impl fmt::Debug for StmtBlock {
|
||||||
@ -850,6 +876,13 @@ impl fmt::Debug for StmtBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<StmtBlock> for Stmt {
|
||||||
|
fn from(block: StmtBlock) -> Self {
|
||||||
|
let block_pos = block.position();
|
||||||
|
Self::Block(block.0.into_vec(), block_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ A statement.
|
/// _(INTERNALS)_ A statement.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Main module defining the script evaluation [`Engine`].
|
//! Main module defining the script evaluation [`Engine`].
|
||||||
|
|
||||||
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt, StmtBlock};
|
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt};
|
||||||
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
||||||
use crate::fn_native::{
|
use crate::fn_native::{
|
||||||
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnProgressCallback,
|
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnProgressCallback,
|
||||||
@ -1733,7 +1733,7 @@ impl Engine {
|
|||||||
// Statement block
|
// Statement block
|
||||||
Expr::Stmt(x) if x.is_empty() => Ok(Dynamic::UNIT),
|
Expr::Stmt(x) if x.is_empty() => Ok(Dynamic::UNIT),
|
||||||
Expr::Stmt(x) => {
|
Expr::Stmt(x) => {
|
||||||
self.eval_stmt_block(scope, mods, state, lib, this_ptr, &x.0, true, level)
|
self.eval_stmt_block(scope, mods, state, lib, this_ptr, x, true, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// lhs[idx_expr]
|
// lhs[idx_expr]
|
||||||
@ -2133,31 +2133,29 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If statement
|
// If statement
|
||||||
Stmt::If(expr, x, _) => {
|
Stmt::If(expr, x, _) => self
|
||||||
let (StmtBlock(if_stmt, _), StmtBlock(else_stmt, _)) = x.as_ref();
|
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))
|
||||||
.and_then(|guard_val| {
|
.and_then(|guard_val| {
|
||||||
if guard_val {
|
if guard_val {
|
||||||
if !if_stmt.is_empty() {
|
if !x.0.is_empty() {
|
||||||
self.eval_stmt_block(
|
self.eval_stmt_block(
|
||||||
scope, mods, state, lib, this_ptr, if_stmt, true, level,
|
scope, mods, state, lib, this_ptr, &x.0, true, level,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !else_stmt.is_empty() {
|
if !x.1.is_empty() {
|
||||||
self.eval_stmt_block(
|
self.eval_stmt_block(
|
||||||
scope, mods, state, lib, this_ptr, else_stmt, true, level,
|
scope, mods, state, lib, this_ptr, &x.1, true, level,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
|
|
||||||
// Switch statement
|
// Switch statement
|
||||||
Stmt::Switch(match_expr, x, _) => {
|
Stmt::Switch(match_expr, x, _) => {
|
||||||
@ -2188,7 +2186,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let statements = &(t.1).0;
|
let statements = &t.1;
|
||||||
|
|
||||||
Some(if !statements.is_empty() {
|
Some(if !statements.is_empty() {
|
||||||
self.eval_stmt_block(
|
self.eval_stmt_block(
|
||||||
@ -2204,7 +2202,6 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
// Default match clause
|
// Default match clause
|
||||||
let def_stmt = &def_stmt.0;
|
|
||||||
if !def_stmt.is_empty() {
|
if !def_stmt.is_empty() {
|
||||||
self.eval_stmt_block(
|
self.eval_stmt_block(
|
||||||
scope, mods, state, lib, this_ptr, def_stmt, true, level,
|
scope, mods, state, lib, this_ptr, def_stmt, true, level,
|
||||||
@ -2216,15 +2213,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// While loop
|
// While loop
|
||||||
Stmt::While(expr, body, _) => {
|
Stmt::While(expr, body, _) => loop {
|
||||||
let body = &body.0;
|
|
||||||
loop {
|
|
||||||
let condition = if !expr.is_unit() {
|
let condition = if !expr.is_unit() {
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.map_err(|err| {
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))?
|
||||||
self.make_type_mismatch_err::<bool>(err, expr.position())
|
|
||||||
})?
|
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
@ -2236,8 +2229,7 @@ impl Engine {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.eval_stmt_block(scope, mods, state, lib, this_ptr, body, true, level)
|
match self.eval_stmt_block(scope, mods, state, lib, this_ptr, body, true, level) {
|
||||||
{
|
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
EvalAltResult::LoopBreak(false, _) => (),
|
EvalAltResult::LoopBreak(false, _) => (),
|
||||||
@ -2245,17 +2237,12 @@ impl Engine {
|
|||||||
_ => return Err(err),
|
_ => return Err(err),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
// Do loop
|
// Do loop
|
||||||
Stmt::Do(body, expr, is_while, _) => {
|
Stmt::Do(body, expr, is_while, _) => loop {
|
||||||
let body = &body.0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if !body.is_empty() {
|
if !body.is_empty() {
|
||||||
match self
|
match self.eval_stmt_block(scope, mods, state, lib, this_ptr, body, true, level)
|
||||||
.eval_stmt_block(scope, mods, state, lib, this_ptr, body, true, level)
|
|
||||||
{
|
{
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
@ -2279,12 +2266,12 @@ impl Engine {
|
|||||||
return Ok(Dynamic::UNIT);
|
return Ok(Dynamic::UNIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
// For loop
|
// For loop
|
||||||
Stmt::For(expr, x, _) => {
|
Stmt::For(expr, x, _) => {
|
||||||
let (Ident { name, .. }, StmtBlock(statements, pos)) = x.as_ref();
|
let (Ident { name, .. }, statements) = x.as_ref();
|
||||||
|
let pos = statements.position();
|
||||||
let iter_obj = self
|
let iter_obj = self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.flatten();
|
.flatten();
|
||||||
@ -2333,7 +2320,7 @@ impl Engine {
|
|||||||
*loop_var = value;
|
*loop_var = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inc_operations(state, *pos)?;
|
self.inc_operations(state, pos)?;
|
||||||
|
|
||||||
if statements.is_empty() {
|
if statements.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@ -2367,10 +2354,10 @@ impl Engine {
|
|||||||
|
|
||||||
// Try/Catch statement
|
// Try/Catch statement
|
||||||
Stmt::TryCatch(x, _, _) => {
|
Stmt::TryCatch(x, _, _) => {
|
||||||
let (StmtBlock(try_body, _), err_var, StmtBlock(catch_body, _)) = x.as_ref();
|
let (try_stmt, err_var, catch_stmt) = x.as_ref();
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.eval_stmt_block(scope, mods, state, lib, this_ptr, try_body, true, level)
|
.eval_stmt_block(scope, mods, state, lib, this_ptr, try_stmt, true, level)
|
||||||
.map(|_| Dynamic::UNIT);
|
.map(|_| Dynamic::UNIT);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
@ -2430,7 +2417,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let result = self.eval_stmt_block(
|
let result = self.eval_stmt_block(
|
||||||
scope, mods, state, lib, this_ptr, catch_body, true, level,
|
scope, mods, state, lib, this_ptr, catch_stmt, true, level,
|
||||||
);
|
);
|
||||||
|
|
||||||
state.scope_level -= 1;
|
state.scope_level -= 1;
|
||||||
|
@ -540,7 +540,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate the function
|
// Evaluate the function
|
||||||
let body = &fn_def.body.0;
|
let body = &fn_def.body;
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.eval_stmt_block(scope, mods, state, unified_lib, this_ptr, body, true, level)
|
.eval_stmt_block(scope, mods, state, unified_lib, this_ptr, body, true, level)
|
||||||
|
112
src/optimize.rs
112
src/optimize.rs
@ -1,6 +1,6 @@
|
|||||||
//! Module implementing the [`AST`] optimizer.
|
//! Module implementing the [`AST`] optimizer.
|
||||||
|
|
||||||
use crate::ast::{Expr, Stmt, StmtBlock};
|
use crate::ast::{Expr, Stmt};
|
||||||
use crate::dynamic::AccessMode;
|
use crate::dynamic::AccessMode;
|
||||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, 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;
|
||||||
@ -416,28 +416,30 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
// if false { if_block } else { else_block } -> else_block
|
// if false { if_block } else { else_block } -> else_block
|
||||||
Stmt::If(Expr::BoolConstant(false, _), x, _) => {
|
Stmt::If(Expr::BoolConstant(false, _), x, _) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let else_block = mem::take(&mut (x.1).0).into_vec();
|
let else_block = mem::take(&mut *x.1).into_vec();
|
||||||
*stmt = match optimize_stmt_block(else_block, state, preserve_result, true, false) {
|
*stmt = match optimize_stmt_block(else_block, state, preserve_result, true, false) {
|
||||||
statements if statements.is_empty() => Stmt::Noop((x.1).1),
|
statements if statements.is_empty() => Stmt::Noop(x.1.position()),
|
||||||
statements => Stmt::Block(statements, (x.1).1),
|
statements => Stmt::Block(statements, x.1.position()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if true { if_block } else { else_block } -> if_block
|
// if true { if_block } else { else_block } -> if_block
|
||||||
Stmt::If(Expr::BoolConstant(true, _), x, _) => {
|
Stmt::If(Expr::BoolConstant(true, _), x, _) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let if_block = mem::take(&mut (x.0).0).into_vec();
|
let if_block = mem::take(&mut *x.0).into_vec();
|
||||||
*stmt = match optimize_stmt_block(if_block, state, preserve_result, true, false) {
|
*stmt = match optimize_stmt_block(if_block, state, preserve_result, true, false) {
|
||||||
statements if statements.is_empty() => Stmt::Noop((x.0).1),
|
statements if statements.is_empty() => Stmt::Noop(x.0.position()),
|
||||||
statements => Stmt::Block(statements, (x.0).1),
|
statements => Stmt::Block(statements, x.0.position()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if expr { if_block } else { else_block }
|
// if expr { if_block } else { else_block }
|
||||||
Stmt::If(condition, x, _) => {
|
Stmt::If(condition, x, _) => {
|
||||||
optimize_expr(condition, state);
|
optimize_expr(condition, state);
|
||||||
let if_block = mem::take(&mut (x.0).0).into_vec();
|
let if_block = mem::take(x.0.statements()).into_vec();
|
||||||
(x.0).0 = optimize_stmt_block(if_block, state, preserve_result, true, false).into();
|
*x.0.statements() =
|
||||||
let else_block = mem::take(&mut (x.1).0).into_vec();
|
optimize_stmt_block(if_block, state, preserve_result, true, false).into();
|
||||||
(x.1).0 = optimize_stmt_block(else_block, state, preserve_result, true, false).into();
|
let else_block = mem::take(x.1.statements()).into_vec();
|
||||||
|
*x.1.statements() =
|
||||||
|
optimize_stmt_block(else_block, state, preserve_result, true, false).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch const { ... }
|
// switch const { ... }
|
||||||
@ -455,9 +457,13 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
// switch const { case if condition => stmt, _ => def } => if condition { stmt } else { def }
|
// switch const { case if condition => stmt, _ => def } => if condition { stmt } else { def }
|
||||||
optimize_expr(&mut condition, state);
|
optimize_expr(&mut condition, state);
|
||||||
|
|
||||||
let def_block = mem::take(&mut (x.1).0).into_vec();
|
let def_block = mem::take(&mut *x.1).into_vec();
|
||||||
let def_stmt = optimize_stmt_block(def_block, state, true, true, false);
|
let def_stmt = optimize_stmt_block(def_block, state, true, true, false);
|
||||||
let def_pos = if (x.1).1.is_none() { *pos } else { (x.1).1 };
|
let def_pos = if x.1.position().is_none() {
|
||||||
|
*pos
|
||||||
|
} else {
|
||||||
|
x.1.position()
|
||||||
|
};
|
||||||
|
|
||||||
*stmt = Stmt::If(
|
*stmt = Stmt::If(
|
||||||
condition,
|
condition,
|
||||||
@ -469,16 +475,21 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Promote the matched case
|
// Promote the matched case
|
||||||
let StmtBlock(statements, new_pos) = mem::take(&mut block.1);
|
let new_pos = block.1.position();
|
||||||
|
let statements = mem::take(&mut *block.1);
|
||||||
let statements =
|
let statements =
|
||||||
optimize_stmt_block(statements.into_vec(), state, true, true, false);
|
optimize_stmt_block(statements.into_vec(), state, true, true, false);
|
||||||
*stmt = Stmt::Block(statements, new_pos);
|
*stmt = Stmt::Block(statements, new_pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Promote the default case
|
// Promote the default case
|
||||||
let def_block = mem::take(&mut (x.1).0).into_vec();
|
let def_block = mem::take(&mut *x.1).into_vec();
|
||||||
let def_stmt = optimize_stmt_block(def_block, state, true, true, false);
|
let def_stmt = optimize_stmt_block(def_block, state, true, true, false);
|
||||||
let def_pos = if (x.1).1.is_none() { *pos } else { (x.1).1 };
|
let def_pos = if x.1.position().is_none() {
|
||||||
|
*pos
|
||||||
|
} else {
|
||||||
|
x.1.position()
|
||||||
|
};
|
||||||
*stmt = Stmt::Block(def_stmt, def_pos);
|
*stmt = Stmt::Block(def_stmt, def_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,9 +509,13 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
_ => {
|
_ => {
|
||||||
block.0 = Some(condition);
|
block.0 = Some(condition);
|
||||||
|
|
||||||
let match_block = mem::take(&mut (block.1).0).into_vec();
|
*block.1.statements() = optimize_stmt_block(
|
||||||
(block.1).0 =
|
mem::take(block.1.statements()).into_vec(),
|
||||||
optimize_stmt_block(match_block, state, preserve_result, true, false)
|
state,
|
||||||
|
preserve_result,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
)
|
||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -515,8 +530,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
x.0.remove(&key);
|
x.0.remove(&key);
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_block = mem::take(&mut (x.1).0).into_vec();
|
let def_block = mem::take(x.1.statements()).into_vec();
|
||||||
(x.1).0 = optimize_stmt_block(def_block, state, preserve_result, true, false).into()
|
*x.1.statements() =
|
||||||
|
optimize_stmt_block(def_block, state, preserve_result, true, false).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// while false { block } -> Noop
|
// while false { block } -> Noop
|
||||||
@ -527,12 +543,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
// while expr { block }
|
// while expr { block }
|
||||||
Stmt::While(condition, body, _) => {
|
Stmt::While(condition, body, _) => {
|
||||||
optimize_expr(condition, state);
|
optimize_expr(condition, state);
|
||||||
|
let block = mem::take(body.statements()).into_vec();
|
||||||
let block = mem::take(&mut body.0).into_vec();
|
*body.statements() = optimize_stmt_block(block, state, false, true, false).into();
|
||||||
body.0 = optimize_stmt_block(block, state, false, true, false).into();
|
|
||||||
|
|
||||||
if body.len() == 1 {
|
if body.len() == 1 {
|
||||||
match body.0[0] {
|
match body[0] {
|
||||||
// while expr { break; } -> { expr; }
|
// while expr { break; } -> { expr; }
|
||||||
Stmt::Break(pos) => {
|
Stmt::Break(pos) => {
|
||||||
// Only a single break statement - turn into running the guard expression once
|
// Only a single break statement - turn into running the guard expression once
|
||||||
@ -555,23 +570,24 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
Stmt::Do(body, Expr::BoolConstant(true, _), false, _)
|
Stmt::Do(body, Expr::BoolConstant(true, _), false, _)
|
||||||
| Stmt::Do(body, Expr::BoolConstant(false, _), true, _) => {
|
| Stmt::Do(body, Expr::BoolConstant(false, _), true, _) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let block = mem::take(&mut body.0).into_vec();
|
let block_pos = body.position();
|
||||||
|
let block = mem::take(body.statements()).into_vec();
|
||||||
*stmt = Stmt::Block(
|
*stmt = Stmt::Block(
|
||||||
optimize_stmt_block(block, state, false, true, false),
|
optimize_stmt_block(block, state, false, true, false),
|
||||||
body.1,
|
block_pos,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// do { block } while|until expr
|
// do { block } while|until expr
|
||||||
Stmt::Do(body, condition, _, _) => {
|
Stmt::Do(body, condition, _, _) => {
|
||||||
optimize_expr(condition, state);
|
optimize_expr(condition, state);
|
||||||
let block = mem::take(&mut body.0).into_vec();
|
let block = mem::take(body.statements()).into_vec();
|
||||||
body.0 = optimize_stmt_block(block, state, false, true, false).into();
|
*body.statements() = optimize_stmt_block(block, state, false, true, false).into();
|
||||||
}
|
}
|
||||||
// for id in expr { block }
|
// for id in expr { block }
|
||||||
Stmt::For(iterable, x, _) => {
|
Stmt::For(iterable, x, _) => {
|
||||||
optimize_expr(iterable, state);
|
optimize_expr(iterable, state);
|
||||||
let body = mem::take(&mut (x.1).0).into_vec();
|
let body = mem::take(x.1.statements()).into_vec();
|
||||||
(x.1).0 = optimize_stmt_block(body, state, false, true, false).into();
|
*x.1.statements() = optimize_stmt_block(body, state, false, true, false).into();
|
||||||
}
|
}
|
||||||
// let id = expr;
|
// let id = expr;
|
||||||
Stmt::Let(expr, _, _, _) => optimize_expr(expr, state),
|
Stmt::Let(expr, _, _, _) => optimize_expr(expr, state),
|
||||||
@ -597,31 +613,32 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// try { pure try_block } catch ( var ) { catch_block } -> try_block
|
// try { pure try_block } catch ( var ) { catch_block } -> try_block
|
||||||
Stmt::TryCatch(x, _, _) if (x.0).0.iter().all(Stmt::is_pure) => {
|
Stmt::TryCatch(x, _, _) if x.0.iter().all(Stmt::is_pure) => {
|
||||||
// If try block is pure, there will never be any exceptions
|
// If try block is pure, there will never be any exceptions
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let try_block = mem::take(&mut (x.0).0).into_vec();
|
let try_pos = x.0.position();
|
||||||
|
let try_block = mem::take(&mut *x.0).into_vec();
|
||||||
*stmt = Stmt::Block(
|
*stmt = Stmt::Block(
|
||||||
optimize_stmt_block(try_block, state, false, true, false),
|
optimize_stmt_block(try_block, state, false, true, false),
|
||||||
(x.0).1,
|
try_pos,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// try { try_block } catch ( var ) { catch_block }
|
// try { try_block } catch ( var ) { catch_block }
|
||||||
Stmt::TryCatch(x, _, _) => {
|
Stmt::TryCatch(x, _, _) => {
|
||||||
let try_block = mem::take(&mut (x.0).0).into_vec();
|
let try_block = mem::take(x.0.statements()).into_vec();
|
||||||
(x.0).0 = optimize_stmt_block(try_block, state, false, true, false).into();
|
*x.0.statements() = optimize_stmt_block(try_block, state, false, true, false).into();
|
||||||
let catch_block = mem::take(&mut (x.2).0).into_vec();
|
let catch_block = mem::take(x.2.statements()).into_vec();
|
||||||
(x.2).0 = optimize_stmt_block(catch_block, state, false, true, false).into();
|
*x.2.statements() = optimize_stmt_block(catch_block, state, false, true, false).into();
|
||||||
}
|
}
|
||||||
// {}
|
// {}
|
||||||
Stmt::Expr(Expr::Stmt(x)) if x.0.is_empty() => {
|
Stmt::Expr(Expr::Stmt(x)) if x.is_empty() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Noop(x.1);
|
*stmt = Stmt::Noop(x.position());
|
||||||
}
|
}
|
||||||
// {...};
|
// {...};
|
||||||
Stmt::Expr(Expr::Stmt(x)) => {
|
Stmt::Expr(Expr::Stmt(x)) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Block(mem::take(&mut x.0).into_vec(), x.1);
|
*stmt = mem::take(x.as_mut()).into();
|
||||||
}
|
}
|
||||||
// expr;
|
// expr;
|
||||||
Stmt::Expr(expr) => optimize_expr(expr, state),
|
Stmt::Expr(expr) => optimize_expr(expr, state),
|
||||||
@ -644,13 +661,13 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
// {}
|
// {}
|
||||||
Expr::Stmt(x) if x.0.is_empty() => { state.set_dirty(); *expr = Expr::Unit(x.1) }
|
Expr::Stmt(x) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(x.position()) }
|
||||||
// { stmt; ... } - do not count promotion as dirty because it gets turned back into an array
|
// { stmt; ... } - do not count promotion as dirty because it gets turned back into an array
|
||||||
Expr::Stmt(x) => {
|
Expr::Stmt(x) => {
|
||||||
x.0 = optimize_stmt_block(mem::take(&mut x.0).into_vec(), state, true, true, false).into();
|
*x.statements() = optimize_stmt_block(mem::take(x.statements()).into_vec(), state, true, true, false).into();
|
||||||
|
|
||||||
// { Stmt(Expr) } - promote
|
// { Stmt(Expr) } - promote
|
||||||
match x.0.as_mut() {
|
match x.as_mut().as_mut() {
|
||||||
[ Stmt::Expr(e) ] => { state.set_dirty(); *expr = mem::take(e); }
|
[ Stmt::Expr(e) ] => { state.set_dirty(); *expr = mem::take(e); }
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
@ -1068,14 +1085,13 @@ pub fn optimize_into_ast(
|
|||||||
.map(|fn_def| {
|
.map(|fn_def| {
|
||||||
let mut fn_def = crate::fn_native::shared_take_or_clone(fn_def);
|
let mut fn_def = crate::fn_native::shared_take_or_clone(fn_def);
|
||||||
|
|
||||||
let mut body = fn_def.body.0.into_vec();
|
|
||||||
|
|
||||||
// Optimize the function body
|
// Optimize the function body
|
||||||
let state = &mut State::new(engine, lib2, level);
|
let state = &mut State::new(engine, lib2, level);
|
||||||
|
|
||||||
body = optimize_stmt_block(body, state, true, true, true);
|
let body = mem::take(fn_def.body.statements()).into_vec();
|
||||||
|
|
||||||
fn_def.body.0 = body.into();
|
*fn_def.body.statements() =
|
||||||
|
optimize_stmt_block(body, state, true, true, true).into();
|
||||||
|
|
||||||
fn_def
|
fn_def
|
||||||
})
|
})
|
||||||
|
@ -2888,7 +2888,7 @@ fn make_curry_from_externals(
|
|||||||
let mut statements: StaticVec<_> = Default::default();
|
let mut statements: StaticVec<_> = Default::default();
|
||||||
statements.extend(externals.into_iter().map(Stmt::Share));
|
statements.extend(externals.into_iter().map(Stmt::Share));
|
||||||
statements.push(Stmt::Expr(expr));
|
statements.push(Stmt::Expr(expr));
|
||||||
Expr::Stmt(Box::new(StmtBlock(statements, pos)))
|
Expr::Stmt(Box::new(StmtBlock::new(statements, pos)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an anonymous function definition.
|
/// Parse an anonymous function definition.
|
||||||
|
Loading…
Reference in New Issue
Block a user