Optimize op-assignment.
This commit is contained in:
parent
335ab64a2c
commit
cc1f941875
@ -1,10 +1,11 @@
|
|||||||
//! Module implementing the [`AST`] optimizer.
|
//! Module implementing the [`AST`] optimizer.
|
||||||
|
|
||||||
use crate::ast::{Expr, Stmt};
|
use crate::ast::{Expr, OpAssignment, Stmt};
|
||||||
use crate::dynamic::AccessMode;
|
use crate::dynamic::AccessMode;
|
||||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||||
use crate::fn_builtin::get_builtin_binary_op_fn;
|
use crate::fn_builtin::get_builtin_binary_op_fn;
|
||||||
use crate::parser::map_dynamic_to_expr;
|
use crate::parser::map_dynamic_to_expr;
|
||||||
|
use crate::token::Token;
|
||||||
use crate::utils::get_hasher;
|
use crate::utils::get_hasher;
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, ImmutableString,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, ImmutableString,
|
||||||
@ -381,6 +382,33 @@ fn optimize_stmt_block(
|
|||||||
/// Optimize a [statement][Stmt].
|
/// Optimize a [statement][Stmt].
|
||||||
fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
||||||
match stmt {
|
match stmt {
|
||||||
|
// var = var op expr => var op= expr
|
||||||
|
Stmt::Assignment(x, _)
|
||||||
|
if x.1.is_none()
|
||||||
|
&& x.0.is_variable_access(true)
|
||||||
|
&& matches!(&x.2, Expr::FnCall(x2, _)
|
||||||
|
if Token::lookup_from_syntax(&x2.name).and_then(|t| t.make_op_assignment()).is_some()
|
||||||
|
&& x2.args_count() == 2 && x2.args.len() >= 1
|
||||||
|
&& x2.args[0].get_variable_name(true) == x.0.get_variable_name(true)
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
match &mut x.2 {
|
||||||
|
Expr::FnCall(x2, _) => {
|
||||||
|
state.set_dirty();
|
||||||
|
let op = Token::lookup_from_syntax(&x2.name).unwrap();
|
||||||
|
let op_assignment = op.make_op_assignment().unwrap();
|
||||||
|
x.1 = Some(OpAssignment::new(op_assignment.keyword_syntax()));
|
||||||
|
x.2 = if x2.args.len() > 1 {
|
||||||
|
mem::take(&mut x2.args[1])
|
||||||
|
} else {
|
||||||
|
let (value, pos) = mem::take(&mut x2.constant_args[0]);
|
||||||
|
Expr::DynamicConstant(Box::new(value), pos)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// expr op= expr
|
// expr op= expr
|
||||||
Stmt::Assignment(x, _) => match x.0 {
|
Stmt::Assignment(x, _) => match x.0 {
|
||||||
Expr::Variable(_, _, _) => optimize_expr(&mut x.2, state),
|
Expr::Variable(_, _, _) => optimize_expr(&mut x.2, state),
|
||||||
|
@ -1518,19 +1518,7 @@ fn parse_op_assignment_stmt(
|
|||||||
|
|
||||||
let op = match token {
|
let op = match token {
|
||||||
Token::Equals => "",
|
Token::Equals => "",
|
||||||
|
_ if token.map_op_assignment().is_some() => token.keyword_syntax(),
|
||||||
Token::PlusAssign
|
|
||||||
| Token::MinusAssign
|
|
||||||
| Token::MultiplyAssign
|
|
||||||
| Token::DivideAssign
|
|
||||||
| Token::LeftShiftAssign
|
|
||||||
| Token::RightShiftAssign
|
|
||||||
| Token::ModuloAssign
|
|
||||||
| Token::PowerOfAssign
|
|
||||||
| Token::AndAssign
|
|
||||||
| Token::OrAssign
|
|
||||||
| Token::XOrAssign => token.keyword_syntax(),
|
|
||||||
|
|
||||||
_ => return Ok(Stmt::Expr(lhs)),
|
_ => return Ok(Stmt::Expr(lhs)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
36
src/token.rs
36
src/token.rs
@ -578,6 +578,42 @@ impl Token {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the corresponding operator of the token if it is an op-assignment operator.
|
||||||
|
pub fn map_op_assignment(&self) -> Option<Self> {
|
||||||
|
Some(match self {
|
||||||
|
Self::PlusAssign => Self::Plus,
|
||||||
|
Self::MinusAssign => Self::Minus,
|
||||||
|
Self::MultiplyAssign => Self::Multiply,
|
||||||
|
Self::DivideAssign => Self::Divide,
|
||||||
|
Self::LeftShiftAssign => Self::LeftShift,
|
||||||
|
Self::RightShiftAssign => Self::RightShift,
|
||||||
|
Self::ModuloAssign => Self::Modulo,
|
||||||
|
Self::PowerOfAssign => Self::PowerOf,
|
||||||
|
Self::AndAssign => Self::Ampersand,
|
||||||
|
Self::OrAssign => Self::Pipe,
|
||||||
|
Self::XOrAssign => Self::XOr,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the corresponding op-assignment operator of the token.
|
||||||
|
pub fn make_op_assignment(&self) -> Option<Self> {
|
||||||
|
Some(match self {
|
||||||
|
Self::Plus => Self::PlusAssign,
|
||||||
|
Self::Minus => Self::MinusAssign,
|
||||||
|
Self::Multiply => Self::MultiplyAssign,
|
||||||
|
Self::Divide => Self::DivideAssign,
|
||||||
|
Self::LeftShift => Self::LeftShiftAssign,
|
||||||
|
Self::RightShift => Self::RightShiftAssign,
|
||||||
|
Self::Modulo => Self::ModuloAssign,
|
||||||
|
Self::PowerOf => Self::PowerOfAssign,
|
||||||
|
Self::Ampersand => Self::AndAssign,
|
||||||
|
Self::Pipe => Self::OrAssign,
|
||||||
|
Self::XOr => Self::XOrAssign,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Reverse lookup a token from a piece of syntax.
|
/// Reverse lookup a token from a piece of syntax.
|
||||||
pub fn lookup_from_syntax(syntax: &str) -> Option<Self> {
|
pub fn lookup_from_syntax(syntax: &str) -> Option<Self> {
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user