Optimize data structures.
This commit is contained in:
parent
6eb6e07d57
commit
a049f7b5ba
18
src/ast.rs
18
src/ast.rs
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user