diff --git a/src/ast.rs b/src/ast.rs index 0e819c5c..83072539 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -14,6 +14,7 @@ use std::{ fmt, hash::Hash, iter::empty, + mem, num::{NonZeroU8, NonZeroUsize}, ops::{Add, AddAssign, Deref, DerefMut}, }; @@ -203,9 +204,10 @@ impl AST { statements: impl IntoIterator, functions: impl Into>, ) -> Self { + let statements: StaticVec<_> = statements.into_iter().collect(); Self { source: None, - body: StmtBlock(statements.into_iter().collect(), Position::NONE), + body: StmtBlock::new(statements, Position::NONE), functions: functions.into(), #[cfg(not(feature = "no_module"))] resolver: None, @@ -218,9 +220,10 @@ impl AST { functions: impl Into>, source: impl Into, ) -> Self { + let statements: StaticVec<_> = statements.into_iter().collect(); Self { source: Some(source.into()), - body: StmtBlock(statements.into_iter().collect(), Position::NONE), + body: StmtBlock::new(statements, Position::NONE), functions: functions.into(), #[cfg(not(feature = "no_module"))] resolver: None, @@ -852,7 +855,9 @@ pub struct StmtBlock(StaticVec, Position); impl StmtBlock { /// Create a new [`StmtBlock`]. pub fn new(statements: impl Into>, pos: Position) -> Self { - Self(statements.into(), pos) + let mut statements = statements.into(); + statements.shrink_to_fit(); + Self(statements, pos) } /// Is this statements block empty? #[inline(always)] @@ -899,7 +904,7 @@ impl fmt::Debug for StmtBlock { impl From for Stmt { fn from(block: StmtBlock) -> Self { let block_pos = block.position(); - Self::Block(block.0.into_vec(), block_pos) + Self::Block(block.0.into_boxed_slice(), block_pos) } } @@ -939,7 +944,7 @@ pub enum Stmt { /// function call forming one statement. FnCall(Box, Position), /// `{` stmt`;` ... `}` - Block(Vec, Position), + Block(Box<[Stmt]>, Position), /// `try` `{` stmt; ... `}` `catch` `(` var `)` `{` stmt; ... `}` TryCatch( Box<(StmtBlock, Option, StmtBlock)>, @@ -959,7 +964,7 @@ pub enum Stmt { Import(Expr, Option>, Position), /// `export` var `as` var `,` ... #[cfg(not(feature = "no_module"))] - Export(Vec<(Ident, Option)>, Position), + Export(Box<[(Ident, Option)]>, Position), /// Convert a variable to shared. #[cfg(not(feature = "no_closure"))] Share(Identifier), @@ -976,7 +981,9 @@ impl From for StmtBlock { #[inline(always)] fn from(stmt: Stmt) -> Self { match stmt { - Stmt::Block(block, pos) => Self(block.into(), pos), + Stmt::Block(mut block, pos) => { + Self(block.iter_mut().map(|v| mem::take(v)).collect(), pos) + } Stmt::Noop(pos) => Self(Default::default(), pos), _ => { let pos = stmt.position(); @@ -1282,7 +1289,7 @@ impl Stmt { } } Self::Block(x, _) => { - for s in x { + for s in x.iter() { if !s.walk(path, on_node) { return false; } @@ -1330,10 +1337,10 @@ impl Stmt { pub struct CustomExpr { /// List of keywords. pub keywords: StaticVec, - /// List of tokens actually parsed. - pub tokens: Vec, /// Delta number of variables in the scope. pub scope_delta: isize, + /// List of tokens actually parsed. + pub tokens: StaticVec, } /// _(INTERNALS)_ A binary expression. diff --git a/src/module/mod.rs b/src/module/mod.rs index 3dc8265e..1fbfaca1 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -695,19 +695,22 @@ impl Module { ) -> u64 { let is_method = func.is_method(); - let param_types: StaticVec<_> = arg_types + let mut param_types: StaticVec<_> = arg_types .iter() .cloned() .enumerate() .map(|(i, type_id)| Self::map_type(!is_method || i > 0, type_id)) .collect(); + param_types.shrink_to_fit(); #[cfg(feature = "metadata")] - let param_names = _arg_names + let mut param_names: StaticVec<_> = _arg_names .iter() .flat_map(|p| p.iter()) .map(|&arg| self.identifiers.get(arg)) .collect(); + #[cfg(feature = "metadata")] + param_names.shrink_to_fit(); let hash_fn = calc_native_fn_hash(empty(), &name, ¶m_types); @@ -1692,6 +1695,8 @@ impl DerefMut for NamespaceRef { impl From> for NamespaceRef { #[inline(always)] fn from(path: StaticVec) -> Self { + let mut path = path; + path.shrink_to_fit(); Self { index: None, path } } } diff --git a/src/optimize.rs b/src/optimize.rs index 77243bbf..93878e85 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -417,7 +417,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { *stmt = if preserve_result { // -> { expr, Noop } - Stmt::Block(vec![Stmt::Expr(expr), Stmt::Noop(pos)], pos) + Stmt::Block(Box::new([Stmt::Expr(expr), Stmt::Noop(pos)]), pos) } else { // -> expr Stmt::Expr(expr) @@ -434,7 +434,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { let else_block = mem::take(&mut *x.1).into_vec(); *stmt = match optimize_stmt_block(else_block, state, preserve_result, true, false) { statements if statements.is_empty() => Stmt::Noop(x.1.position()), - statements => Stmt::Block(statements, x.1.position()), + statements => Stmt::Block(statements.into_boxed_slice(), x.1.position()), } } // if true { if_block } else { else_block } -> if_block @@ -443,7 +443,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { let if_block = mem::take(&mut *x.0).into_vec(); *stmt = match optimize_stmt_block(if_block, state, preserve_result, true, false) { statements if statements.is_empty() => Stmt::Noop(x.0.position()), - statements => Stmt::Block(statements, x.0.position()), + statements => Stmt::Block(statements.into_boxed_slice(), x.0.position()), } } // if expr { if_block } else { else_block } @@ -484,7 +484,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { condition, Box::new(( mem::take(&mut block.1), - Stmt::Block(def_stmt, def_pos).into(), + Stmt::Block(def_stmt.into_boxed_slice(), def_pos).into(), )), match_expr.position(), ); @@ -494,7 +494,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { let statements = mem::take(&mut *block.1); let statements = optimize_stmt_block(statements.into_vec(), state, true, true, false); - *stmt = Stmt::Block(statements, new_pos); + *stmt = Stmt::Block(statements.into_boxed_slice(), new_pos); } } else { // Promote the default case @@ -505,7 +505,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { } else { x.1.position() }; - *stmt = Stmt::Block(def_stmt, def_pos); + *stmt = Stmt::Block(def_stmt.into_boxed_slice(), def_pos); } } // switch @@ -572,7 +572,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { if preserve_result { statements.push(Stmt::Noop(pos)) } - *stmt = Stmt::Block(statements, pos); + *stmt = Stmt::Block(statements.into_boxed_slice(), pos); } else { *stmt = Stmt::Noop(pos); }; @@ -588,7 +588,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { let block_pos = body.position(); let block = mem::take(body.statements()).into_vec(); *stmt = Stmt::Block( - optimize_stmt_block(block, state, false, true, false), + optimize_stmt_block(block, state, false, true, false).into_boxed_slice(), block_pos, ); } @@ -611,8 +611,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { Stmt::Import(expr, _, _) => optimize_expr(expr, state), // { block } Stmt::Block(statements, pos) => { - let mut block = - optimize_stmt_block(mem::take(statements), state, preserve_result, true, false); + let statements = mem::take(statements).into_vec(); + let mut block = optimize_stmt_block(statements, state, preserve_result, true, false); match block.as_mut_slice() { [] => { @@ -624,7 +624,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { state.set_dirty(); *stmt = mem::take(s); } - _ => *stmt = Stmt::Block(block, *pos), + _ => *stmt = Stmt::Block(block.into_boxed_slice(), *pos), } } // try { pure try_block } catch ( var ) { catch_block } -> try_block @@ -634,7 +634,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { let try_pos = x.0.position(); let try_block = mem::take(&mut *x.0).into_vec(); *stmt = Stmt::Block( - optimize_stmt_block(try_block, state, false, true, false), + optimize_stmt_block(try_block, state, false, true, false).into_boxed_slice(), try_pos, ); } @@ -820,6 +820,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { } } } + + x.shrink_to_fit(); } // [ constant .. ] #[cfg(not(feature = "no_index"))] @@ -947,6 +949,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { } x.args.shrink_to_fit(); + x.constant_args.shrink_to_fit(); } // Eagerly call functions @@ -1006,6 +1009,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { } x.args.shrink_to_fit(); + x.constant_args.shrink_to_fit(); } // constant-name diff --git a/src/parser.rs b/src/parser.rs index 7dc5816b..aaa9a11e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -348,6 +348,8 @@ fn parse_fn_call( FnCallHashes::from_native(hash) }; + args.shrink_to_fit(); + return Ok(Expr::FnCall( Box::new(FnCallExpr { name: state.get_identifier(id), @@ -393,6 +395,8 @@ fn parse_fn_call( FnCallHashes::from_native(hash) }; + args.shrink_to_fit(); + return Ok(Expr::FnCall( Box::new(FnCallExpr { name: state.get_identifier(id), @@ -1066,6 +1070,7 @@ fn parse_primary( } } + segments.shrink_to_fit(); Expr::InterpolatedString(Box::new(segments)) } @@ -1344,6 +1349,7 @@ fn parse_unary( expr => { let mut args = StaticVec::new(); args.push(expr); + args.shrink_to_fit(); Ok(Expr::FnCall( Box::new(FnCallExpr { @@ -1370,6 +1376,7 @@ fn parse_unary( expr => { let mut args = StaticVec::new(); args.push(expr); + args.shrink_to_fit(); Ok(Expr::FnCall( Box::new(FnCallExpr { @@ -1387,8 +1394,8 @@ fn parse_unary( Token::Bang => { let pos = eat_token(input, Token::Bang); let mut args = StaticVec::new(); - let expr = parse_unary(input, state, lib, settings.level_up())?; - args.push(expr); + args.push(parse_unary(input, state, lib, settings.level_up())?); + args.shrink_to_fit(); Ok(Expr::FnCall( Box::new(FnCallExpr { @@ -1730,6 +1737,7 @@ fn parse_binary_op( let mut args = StaticVec::new(); args.push(root); args.push(rhs); + args.shrink_to_fit(); root = match op_token { Token::Plus @@ -1782,6 +1790,7 @@ fn parse_binary_op( // Swap the arguments let current_lhs = args.remove(0); args.push(current_lhs); + args.shrink_to_fit(); // Convert into a call to `contains` let hash = calc_fn_hash(empty(), OP_CONTAINS, 2); @@ -1836,7 +1845,7 @@ fn parse_custom_syntax( ) -> Result { let mut keywords: StaticVec = Default::default(); let mut segments: StaticVec<_> = Default::default(); - let mut tokens: Vec<_> = Default::default(); + let mut tokens: StaticVec<_> = Default::default(); // Adjust the variables stack match syntax.scope_delta { @@ -1920,6 +1929,9 @@ fn parse_custom_syntax( } } + keywords.shrink_to_fit(); + tokens.shrink_to_fit(); + Ok(Expr::Custom( Box::new(CustomExpr { keywords, @@ -2366,7 +2378,7 @@ fn parse_export( } } - Ok(Stmt::Export(exports, settings.pos)) + Ok(Stmt::Export(exports.into_boxed_slice(), settings.pos)) } /// Parse a statement block. @@ -2467,7 +2479,7 @@ fn parse_block( #[cfg(not(feature = "no_module"))] state.modules.truncate(prev_mods_len); - Ok(Stmt::Block(statements, settings.pos)) + Ok(Stmt::Block(statements.into_boxed_slice(), settings.pos)) } /// Parse an expression as a statement. @@ -2820,7 +2832,8 @@ fn parse_fn( } .into(); - let params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect(); + let mut params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect(); + params.shrink_to_fit(); #[cfg(not(feature = "no_closure"))] let externals = state @@ -2874,6 +2887,8 @@ fn make_curry_from_externals( )); }); + args.shrink_to_fit(); + let expr = Expr::FnCall( Box::new(FnCallExpr { name: state.get_identifier(crate::engine::KEYWORD_FN_PTR_CURRY), @@ -2967,7 +2982,7 @@ fn parse_anon_fn( Default::default() }; - let params: StaticVec<_> = if cfg!(not(feature = "no_closure")) { + let mut params: StaticVec<_> = if cfg!(not(feature = "no_closure")) { externals .iter() .cloned() @@ -2976,6 +2991,7 @@ fn parse_anon_fn( } else { params.into_iter().map(|(v, _)| v).collect() }; + params.shrink_to_fit(); // Create unique function name by hashing the script body plus the parameters. let hasher = &mut get_hasher();