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

View File

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

View File

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