Optimize data structures.

This commit is contained in:
Stephen Chung 2021-03-30 23:55:29 +08:00
parent 6eb6e07d57
commit a049f7b5ba
4 changed files with 46 additions and 33 deletions

View File

@ -864,19 +864,23 @@ pub enum Stmt {
/// `if` expr `{` stmt `}` `else` `{` stmt `}` /// `if` expr `{` stmt `}` `else` `{` stmt `}`
If(Expr, Box<(StmtBlock, StmtBlock)>, Position), If(Expr, Box<(StmtBlock, StmtBlock)>, Position),
/// `switch` expr `{` literal or _ `=>` stmt `,` ... `}` /// `switch` expr `{` literal or _ `=>` stmt `,` ... `}`
Switch(Expr, Box<(BTreeMap<u64, StmtBlock>, StmtBlock)>, Position), Switch(
Expr,
Box<(BTreeMap<u64, Box<StmtBlock>>, StmtBlock)>,
Position,
),
/// `while` expr `{` stmt `}` /// `while` expr `{` stmt `}`
While(Expr, Box<StmtBlock>, Position), While(Expr, Box<StmtBlock>, Position),
/// `do` `{` stmt `}` `while`|`until` expr /// `do` `{` stmt `}` `while`|`until` expr
Do(Box<StmtBlock>, Expr, bool, Position), Do(Box<StmtBlock>, Expr, bool, Position),
/// `for` id `in` expr `{` stmt `}` /// `for` id `in` expr `{` stmt `}`
For(Expr, Box<(Identifier, StmtBlock)>, Position), For(Expr, Box<(Ident, StmtBlock)>, Position),
/// \[`export`\] `let` id `=` expr /// \[`export`\] `let` id `=` expr
Let(Expr, Box<Ident>, bool, Position), Let(Expr, Box<Ident>, bool, Position),
/// \[`export`\] `const` id `=` expr /// \[`export`\] `const` id `=` expr
Const(Expr, Box<Ident>, bool, Position), Const(Expr, Box<Ident>, bool, Position),
/// expr op`=` expr /// expr op`=` expr
Assignment(Box<(Expr, Expr, Option<OpAssignment>)>, Position), Assignment(Box<(Expr, Option<OpAssignment>, Expr)>, Position),
/// `{` stmt`;` ... `}` /// `{` stmt`;` ... `}`
Block(Vec<Stmt>, Position), Block(Vec<Stmt>, Position),
/// `try` `{` stmt; ... `}` `catch` `(` var `)` `{` stmt; ... `}` /// `try` `{` stmt; ... `}` `catch` `(` var `)` `{` stmt; ... `}`
@ -901,7 +905,7 @@ pub enum Stmt {
Export(Vec<(Ident, Option<Ident>)>, Position), Export(Vec<(Ident, Option<Ident>)>, Position),
/// Convert a variable to shared. /// Convert a variable to shared.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Share(Box<Ident>), Share(Identifier),
} }
impl Default for Stmt { impl Default for Stmt {
@ -967,7 +971,7 @@ impl Stmt {
Self::Export(_, pos) => *pos, Self::Export(_, pos) => *pos,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Self::Share(x) => x.pos, Self::Share(_) => Position::NONE,
} }
} }
/// Override the [position][Position] of this statement. /// Override the [position][Position] of this statement.
@ -998,7 +1002,7 @@ impl Stmt {
Self::Export(_, pos) => *pos = new_pos, Self::Export(_, pos) => *pos = new_pos,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Self::Share(x) => x.pos = new_pos, Self::Share(_) => (),
} }
self self
@ -1203,7 +1207,7 @@ impl Stmt {
if !x.0.walk(path, on_node) { if !x.0.walk(path, on_node) {
return false; return false;
} }
if !x.1.walk(path, on_node) { if !x.2.walk(path, on_node) {
return false; return false;
} }
} }

View File

@ -1957,7 +1957,7 @@ impl Engine {
// var op= rhs // var op= rhs
Stmt::Assignment(x, op_pos) if x.0.get_variable_access(false).is_some() => { Stmt::Assignment(x, op_pos) if x.0.get_variable_access(false).is_some() => {
let (lhs_expr, rhs_expr, op_info) = x.as_ref(); let (lhs_expr, op_info, rhs_expr) = x.as_ref();
let rhs_val = self let rhs_val = self
.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?
.flatten(); .flatten();
@ -1998,7 +1998,7 @@ impl Engine {
// lhs op= rhs // lhs op= rhs
Stmt::Assignment(x, op_pos) => { Stmt::Assignment(x, op_pos) => {
let (lhs_expr, rhs_expr, op_info) = x.as_ref(); let (lhs_expr, op_info, rhs_expr) = x.as_ref();
let rhs_val = self let rhs_val = self
.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?
.flatten(); .flatten();
@ -2083,7 +2083,9 @@ impl Engine {
value.hash(hasher); value.hash(hasher);
let hash = hasher.finish(); let hash = hasher.finish();
table.get(&hash).map(|StmtBlock { statements, .. }| { table.get(&hash).map(|t| {
let statements = &t.statements;
if !statements.is_empty() { if !statements.is_empty() {
self.eval_stmt_block( self.eval_stmt_block(
scope, mods, state, lib, this_ptr, statements, true, level, scope, mods, state, lib, this_ptr, statements, true, level,
@ -2178,7 +2180,7 @@ impl Engine {
// For loop // For loop
Stmt::For(expr, x, _) => { Stmt::For(expr, x, _) => {
let (name, StmtBlock { statements, pos }) = x.as_ref(); let (Ident { name, .. }, StmtBlock { statements, pos }) = x.as_ref();
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();
@ -2479,8 +2481,8 @@ impl Engine {
// Share statement // Share statement
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Stmt::Share(x) => { Stmt::Share(name) => {
if let Some((index, _)) = scope.get_index(&x.name) { if let Some((index, _)) = scope.get_index(name) {
let val = scope.get_mut_by_index(index); let val = scope.get_mut_by_index(index);
if !val.is_shared() { if !val.is_shared() {

View File

@ -385,10 +385,10 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
match stmt { match stmt {
// expr op= expr // expr op= expr
Stmt::Assignment(x, _) => match x.0 { Stmt::Assignment(x, _) => match x.0 {
Expr::Variable(_) => optimize_expr(&mut x.1, state), Expr::Variable(_) => optimize_expr(&mut x.2, state),
_ => { _ => {
optimize_expr(&mut x.0, state); optimize_expr(&mut x.0, state);
optimize_expr(&mut x.1, state); optimize_expr(&mut x.2, state);
} }
}, },

View File

@ -813,7 +813,7 @@ fn parse_switch(
} }
} }
let mut table = BTreeMap::<u64, StmtBlock>::new(); let mut table = BTreeMap::<u64, Box<StmtBlock>>::new();
let mut def_stmt = None; let mut def_stmt = None;
loop { loop {
@ -873,7 +873,7 @@ fn parse_switch(
let need_comma = !stmt.is_self_terminated(); let need_comma = !stmt.is_self_terminated();
def_stmt = if let Some(hash) = hash { def_stmt = if let Some(hash) = hash {
table.insert(hash, stmt.into()); table.insert(hash, Box::new(stmt.into()));
None None
} else { } else {
Some(stmt.into()) Some(stmt.into())
@ -1390,14 +1390,14 @@ fn make_assignment_stmt<'a>(
} }
// var (non-indexed) = rhs // var (non-indexed) = rhs
Expr::Variable(x) if x.0.is_none() => { Expr::Variable(x) if x.0.is_none() => {
Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos))
} }
// var (indexed) = rhs // var (indexed) = rhs
Expr::Variable(x) => { Expr::Variable(x) => {
let (index, _, Ident { name, pos, .. }) = x.as_ref(); let (index, _, Ident { name, pos, .. }) = x.as_ref();
match state.stack[(state.stack.len() - index.unwrap().get())].1 { match state.stack[(state.stack.len() - index.unwrap().get())].1 {
AccessMode::ReadWrite => { AccessMode::ReadWrite => {
Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos))
} }
// Constant values cannot be assigned to // Constant values cannot be assigned to
AccessMode::ReadOnly => { AccessMode::ReadOnly => {
@ -1411,14 +1411,14 @@ fn make_assignment_stmt<'a>(
Position::NONE => match &x.lhs { Position::NONE => match &x.lhs {
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs // var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
Expr::Variable(x) if x.0.is_none() => { Expr::Variable(x) if x.0.is_none() => {
Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos))
} }
// var[???] (indexed) = rhs, var.??? (indexed) = rhs // var[???] (indexed) = rhs, var.??? (indexed) = rhs
Expr::Variable(x) => { Expr::Variable(x) => {
let (index, _, Ident { name, pos, .. }) = x.as_ref(); let (index, _, Ident { name, pos, .. }) = x.as_ref();
match state.stack[(state.stack.len() - index.unwrap().get())].1 { match state.stack[(state.stack.len() - index.unwrap().get())].1 {
AccessMode::ReadWrite => { AccessMode::ReadWrite => {
Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos))
} }
// Constant values cannot be assigned to // Constant values cannot be assigned to
AccessMode::ReadOnly => { AccessMode::ReadOnly => {
@ -2091,9 +2091,9 @@ fn parse_for(
settings.pos = eat_token(input, Token::For); settings.pos = eat_token(input, Token::For);
// for name ... // for name ...
let name = match input.next().unwrap() { let (name, name_pos) = match input.next().unwrap() {
// Variable name // Variable name
(Token::Identifier(s), _) => s, (Token::Identifier(s), pos) => (s, pos),
// Reserved keyword // Reserved keyword
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => { (Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
return Err(PERR::Reserved(s).into_err(pos)); return Err(PERR::Reserved(s).into_err(pos));
@ -2131,7 +2131,13 @@ fn parse_for(
Ok(Stmt::For( Ok(Stmt::For(
expr, expr,
Box::new((loop_var, body.into())), Box::new((
Ident {
name: loop_var,
pos: name_pos,
},
body.into(),
)),
settings.pos, settings.pos,
)) ))
} }
@ -2766,7 +2772,7 @@ fn parse_fn(
fn make_curry_from_externals( fn make_curry_from_externals(
state: &mut ParseState, state: &mut ParseState,
fn_expr: Expr, fn_expr: Expr,
externals: StaticVec<Ident>, externals: StaticVec<Identifier>,
pos: Position, pos: Position,
) -> Expr { ) -> Expr {
// If there are no captured variables, no need to curry // If there are no captured variables, no need to curry
@ -2780,7 +2786,11 @@ fn make_curry_from_externals(
args.push(fn_expr); args.push(fn_expr);
externals.iter().for_each(|x| { externals.iter().for_each(|x| {
args.push(Expr::Variable(Box::new((None, None, x.clone())))); let var_def = Ident {
name: x.clone(),
pos: Position::NONE,
};
args.push(Expr::Variable(Box::new((None, None, var_def))));
}); });
let expr = Expr::FnCall( let expr = Expr::FnCall(
@ -2800,7 +2810,7 @@ fn make_curry_from_externals(
// Convert the entire expression into a statement block, then insert the relevant // Convert the entire expression into a statement block, then insert the relevant
// [`Share`][Stmt::Share] statements. // [`Share`][Stmt::Share] statements.
let mut statements: StaticVec<_> = Default::default(); let mut statements: StaticVec<_> = Default::default();
statements.extend(externals.into_iter().map(|v| Stmt::Share(Box::new(v)))); 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 { statements, pos }))
} }
@ -2863,16 +2873,13 @@ fn parse_anon_fn(
// External variables may need to be processed in a consistent order, // External variables may need to be processed in a consistent order,
// so extract them into a list. // so extract them into a list.
let externals: StaticVec<Ident> = { let externals: StaticVec<Identifier> = {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
{ {
state state
.external_vars .external_vars
.iter() .iter()
.map(|(name, &pos)| Ident { .map(|(name, _)| name.clone())
name: name.clone(),
pos,
})
.collect() .collect()
} }
#[cfg(feature = "no_closure")] #[cfg(feature = "no_closure")]
@ -2882,7 +2889,7 @@ fn parse_anon_fn(
let params: StaticVec<_> = if cfg!(not(feature = "no_closure")) { let params: StaticVec<_> = if cfg!(not(feature = "no_closure")) {
externals externals
.iter() .iter()
.map(|k| k.name.clone()) .cloned()
.chain(params.into_iter().map(|(v, _)| v)) .chain(params.into_iter().map(|(v, _)| v))
.collect() .collect()
} else { } else {