Use StaticVec for parsing.

This commit is contained in:
Stephen Chung 2021-09-12 14:34:00 +08:00
parent b961a10d27
commit c84f80d433
3 changed files with 51 additions and 50 deletions

View File

@ -2040,7 +2040,7 @@ impl Engine {
let lib = Default::default(); let lib = Default::default();
let stmt = std::mem::take(ast.statements_mut()); let stmt = std::mem::take(ast.statements_mut());
crate::optimize::optimize_into_ast(self, scope, stmt.into_vec(), lib, optimization_level) crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level)
} }
/// _(metadata)_ Generate a list of all registered functions. /// _(metadata)_ Generate a list of all registered functions.
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
@ -2053,9 +2053,7 @@ impl Engine {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> { pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> {
let mut signatures = Vec::new(); let mut signatures = self.global_namespace().gen_fn_signatures();
signatures.extend(self.global_namespace().gen_fn_signatures());
self.global_sub_modules.iter().for_each(|(name, m)| { self.global_sub_modules.iter().for_each(|(name, m)| {
signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f))) signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f)))

View File

@ -51,7 +51,7 @@ struct OptimizerState<'a> {
/// Has the [`AST`] been changed during this pass? /// Has the [`AST`] been changed during this pass?
changed: bool, changed: bool,
/// Collection of constants to use for eager function evaluations. /// Collection of constants to use for eager function evaluations.
variables: Vec<(String, AccessMode, Option<Dynamic>)>, variables: StaticVec<(String, AccessMode, Option<Dynamic>)>,
/// Activate constants propagation? /// Activate constants propagation?
propagate_constants: bool, propagate_constants: bool,
/// An [`Engine`] instance for eager function evaluation. /// An [`Engine`] instance for eager function evaluation.
@ -65,14 +65,14 @@ struct OptimizerState<'a> {
impl<'a> OptimizerState<'a> { impl<'a> OptimizerState<'a> {
/// Create a new State. /// Create a new State.
#[inline(always)] #[inline(always)]
pub const fn new( pub fn new(
engine: &'a Engine, engine: &'a Engine,
lib: &'a [&'a Module], lib: &'a [&'a Module],
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
) -> Self { ) -> Self {
Self { Self {
changed: false, changed: false,
variables: Vec::new(), variables: StaticVec::new(),
propagate_constants: true, propagate_constants: true,
engine, engine,
lib, lib,
@ -158,12 +158,12 @@ impl<'a> OptimizerState<'a> {
/// Optimize a block of [statements][Stmt]. /// Optimize a block of [statements][Stmt].
fn optimize_stmt_block( fn optimize_stmt_block(
mut statements: Vec<Stmt>, mut statements: StaticVec<Stmt>,
state: &mut OptimizerState, state: &mut OptimizerState,
preserve_result: bool, preserve_result: bool,
is_internal: bool, is_internal: bool,
reduce_return: bool, reduce_return: bool,
) -> Vec<Stmt> { ) -> StaticVec<Stmt> {
if statements.is_empty() { if statements.is_empty() {
return statements; return statements;
} }
@ -456,7 +456,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// 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).into_vec(); let else_block = mem::take(&mut *x.1);
*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.position()), statements if statements.is_empty() => Stmt::Noop(x.1.position()),
statements => Stmt::Block(statements.into_boxed_slice(), x.1.position()), statements => Stmt::Block(statements.into_boxed_slice(), x.1.position()),
@ -465,7 +465,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// 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).into_vec(); let if_block = mem::take(&mut *x.0);
*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.position()), statements if statements.is_empty() => Stmt::Noop(x.0.position()),
statements => Stmt::Block(statements.into_boxed_slice(), x.0.position()), statements => Stmt::Block(statements.into_boxed_slice(), x.0.position()),
@ -474,10 +474,10 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// 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, false); optimize_expr(condition, state, false);
let if_block = mem::take(x.0.deref_mut()).into_vec(); let if_block = mem::take(x.0.deref_mut());
*x.0 = optimize_stmt_block(if_block, state, preserve_result, true, false).into(); *x.0 = optimize_stmt_block(if_block, state, preserve_result, true, false);
let else_block = mem::take(x.1.deref_mut()).into_vec(); let else_block = mem::take(x.1.deref_mut());
*x.1 = optimize_stmt_block(else_block, state, preserve_result, true, false).into(); *x.1 = optimize_stmt_block(else_block, state, preserve_result, true, false);
} }
// switch const { ... } // switch const { ... }
@ -497,7 +497,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// 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, false); optimize_expr(&mut condition, state, false);
let def_block = mem::take(&mut *x.1).into_vec(); let def_block = mem::take(&mut *x.1);
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.position().is_none() { let def_pos = if x.1.position().is_none() {
*pos *pos
@ -517,13 +517,12 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// Promote the matched case // Promote the matched case
let new_pos = block.1.position(); let new_pos = block.1.position();
let statements = mem::take(&mut *block.1); let statements = mem::take(&mut *block.1);
let statements = let statements = optimize_stmt_block(statements, state, true, true, false);
optimize_stmt_block(statements.into_vec(), state, true, true, false);
*stmt = Stmt::Block(statements.into_boxed_slice(), new_pos); *stmt = Stmt::Block(statements.into_boxed_slice(), new_pos);
} }
} else { } else {
// Promote the default case // Promote the default case
let def_block = mem::take(&mut *x.1).into_vec(); let def_block = mem::take(&mut *x.1);
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.position().is_none() { let def_pos = if x.1.position().is_none() {
*pos *pos
@ -551,13 +550,12 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
block.0 = Some(condition); block.0 = Some(condition);
*block.1 = optimize_stmt_block( *block.1 = optimize_stmt_block(
mem::take(block.1.deref_mut()).into_vec(), mem::take(block.1.deref_mut()),
state, state,
preserve_result, preserve_result,
true, true,
false, false,
) );
.into();
} }
} }
}); });
@ -571,8 +569,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
x.0.remove(&key); x.0.remove(&key);
} }
let def_block = mem::take(x.1.deref_mut()).into_vec(); let def_block = mem::take(x.1.deref_mut());
*x.1 = optimize_stmt_block(def_block, state, preserve_result, true, false).into(); *x.1 = optimize_stmt_block(def_block, state, preserve_result, true, false);
} }
// while false { block } -> Noop // while false { block } -> Noop
@ -586,9 +584,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
if let Expr::BoolConstant(true, pos) = condition { if let Expr::BoolConstant(true, pos) = condition {
*condition = Expr::Unit(*pos); *condition = Expr::Unit(*pos);
} }
let block = mem::take(body.as_mut().deref_mut()).into_vec(); let block = mem::take(body.as_mut().deref_mut());
*body.as_mut().deref_mut() = *body.as_mut().deref_mut() = optimize_stmt_block(block, state, false, true, false);
optimize_stmt_block(block, state, false, true, false).into();
if body.len() == 1 { if body.len() == 1 {
match body[0] { match body[0] {
@ -616,7 +613,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
{ {
state.set_dirty(); state.set_dirty();
let block_pos = body.position(); let block_pos = body.position();
let block = mem::take(body.as_mut().deref_mut()).into_vec(); let block = mem::take(body.as_mut().deref_mut());
*stmt = Stmt::Block( *stmt = Stmt::Block(
optimize_stmt_block(block, state, false, true, false).into_boxed_slice(), optimize_stmt_block(block, state, false, true, false).into_boxed_slice(),
block_pos, block_pos,
@ -625,15 +622,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// do { block } while|until expr // do { block } while|until expr
Stmt::Do(body, condition, _, _) => { Stmt::Do(body, condition, _, _) => {
optimize_expr(condition, state, false); optimize_expr(condition, state, false);
let block = mem::take(body.as_mut().deref_mut()).into_vec(); let block = mem::take(body.as_mut().deref_mut());
*body.as_mut().deref_mut() = *body.as_mut().deref_mut() = optimize_stmt_block(block, state, false, true, false);
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, false); optimize_expr(iterable, state, false);
let body = mem::take(x.2.deref_mut()).into_vec(); let body = mem::take(x.2.deref_mut());
*x.2 = optimize_stmt_block(body, state, false, true, false).into(); *x.2 = optimize_stmt_block(body, state, false, true, false);
} }
// let id = expr; // let id = expr;
Stmt::Var(expr, _, options, _) if !options.contains(AST_OPTION_CONSTANT) => { Stmt::Var(expr, _, options, _) if !options.contains(AST_OPTION_CONSTANT) => {
@ -644,7 +640,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
Stmt::Import(expr, _, _) => optimize_expr(expr, state, false), Stmt::Import(expr, _, _) => optimize_expr(expr, state, false),
// { block } // { block }
Stmt::Block(statements, pos) => { Stmt::Block(statements, pos) => {
let statements = mem::take(statements).into_vec(); let statements = mem::take(statements).into_vec().into();
let mut block = optimize_stmt_block(statements, state, preserve_result, true, false); let mut block = optimize_stmt_block(statements, state, preserve_result, true, false);
match block.as_mut_slice() { match block.as_mut_slice() {
@ -665,7 +661,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// 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_pos = x.0.position(); let try_pos = x.0.position();
let try_block = mem::take(&mut *x.0).into_vec(); let try_block = mem::take(&mut *x.0);
*stmt = Stmt::Block( *stmt = Stmt::Block(
optimize_stmt_block(try_block, state, false, true, false).into_boxed_slice(), optimize_stmt_block(try_block, state, false, true, false).into_boxed_slice(),
try_pos, try_pos,
@ -673,10 +669,10 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
} }
// 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(x.0.deref_mut()).into_vec(); let try_block = mem::take(x.0.deref_mut());
*x.0 = optimize_stmt_block(try_block, state, false, true, false).into(); *x.0 = optimize_stmt_block(try_block, state, false, true, false);
let catch_block = mem::take(x.2.deref_mut()).into_vec(); let catch_block = mem::take(x.2.deref_mut());
*x.2 = optimize_stmt_block(catch_block, state, false, true, false).into(); *x.2 = optimize_stmt_block(catch_block, state, false, true, false);
} }
// func(...) // func(...)
Stmt::Expr(expr @ Expr::FnCall(_, _)) => { Stmt::Expr(expr @ Expr::FnCall(_, _)) => {
@ -726,7 +722,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
// { 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.as_mut().deref_mut() = *x.as_mut().deref_mut() =
optimize_stmt_block(mem::take(x.as_mut().deref_mut()).into_vec(), state, true, true, false).into(); optimize_stmt_block(mem::take(x.as_mut().deref_mut()), state, true, true, false);
// { Stmt(Expr) } - promote // { Stmt(Expr) } - promote
match x.as_mut().as_mut() { match x.as_mut().as_mut() {
@ -1091,12 +1087,12 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
/// Optimize a block of [statements][Stmt] at top level. /// Optimize a block of [statements][Stmt] at top level.
fn optimize_top_level( fn optimize_top_level(
statements: Vec<Stmt>, statements: StaticVec<Stmt>,
engine: &Engine, engine: &Engine,
scope: &Scope, scope: &Scope,
lib: &[&Module], lib: &[&Module],
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
) -> Vec<Stmt> { ) -> StaticVec<Stmt> {
let mut statements = statements; let mut statements = statements;
// If optimization level is None then skip optimizing // If optimization level is None then skip optimizing
@ -1125,8 +1121,8 @@ fn optimize_top_level(
pub fn optimize_into_ast( pub fn optimize_into_ast(
engine: &Engine, engine: &Engine,
scope: &Scope, scope: &Scope,
statements: Vec<Stmt>, statements: StaticVec<Stmt>,
functions: Vec<crate::Shared<crate::ast::ScriptFnDef>>, functions: StaticVec<crate::Shared<crate::ast::ScriptFnDef>>,
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
) -> AST { ) -> AST {
let level = if cfg!(feature = "no_optimize") { let level = if cfg!(feature = "no_optimize") {
@ -1176,9 +1172,9 @@ pub fn optimize_into_ast(
// Optimize the function body // Optimize the function body
let state = &mut OptimizerState::new(engine, lib2, level); let state = &mut OptimizerState::new(engine, lib2, level);
let body = mem::take(fn_def.body.deref_mut()).into_vec(); let body = mem::take(fn_def.body.deref_mut());
*fn_def.body = optimize_stmt_block(body, state, true, true, true).into(); *fn_def.body = optimize_stmt_block(body, state, true, true, true);
fn_def fn_def
}) })

View File

@ -3244,11 +3244,18 @@ impl Engine {
} }
} }
let expr = vec![Stmt::Expr(expr)]; let mut statements = StaticVec::new();
statements.push(Stmt::Expr(expr));
Ok( Ok(
// Optimize AST // Optimize AST
optimize_into_ast(self, scope, expr, Default::default(), optimization_level), optimize_into_ast(
self,
scope,
statements,
Default::default(),
optimization_level,
),
) )
} }
@ -3257,8 +3264,8 @@ impl Engine {
&self, &self,
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
) -> Result<(Vec<Stmt>, Vec<Shared<ScriptFnDef>>), ParseError> { ) -> Result<(StaticVec<Stmt>, StaticVec<Shared<ScriptFnDef>>), ParseError> {
let mut statements = Vec::with_capacity(16); let mut statements = StaticVec::new();
let mut functions = BTreeMap::new(); let mut functions = BTreeMap::new();
while !input.peek().expect(NEVER_ENDS).0.is_eof() { while !input.peek().expect(NEVER_ENDS).0.is_eof() {