Refine op-assignment.
This commit is contained in:
parent
e58b57b6e7
commit
61b559a58f
19
src/ast.rs
19
src/ast.rs
@ -1347,13 +1347,22 @@ pub struct OpAssignment {
|
||||
}
|
||||
|
||||
impl OpAssignment {
|
||||
pub fn new(op: &'static str) -> Self {
|
||||
let op2 = &op[..op.len() - 1]; // extract operator without =
|
||||
/// Create a new [`OpAssignment`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the operator name is not an op-assignment operator.
|
||||
pub fn new(op: Token) -> Self {
|
||||
let op_raw = op
|
||||
.map_op_assignment()
|
||||
.expect("token must be an op-assignment operator")
|
||||
.keyword_syntax();
|
||||
let op_assignment = op.keyword_syntax();
|
||||
|
||||
Self {
|
||||
hash_op_assign: calc_fn_hash(empty(), op, 2),
|
||||
hash_op: calc_fn_hash(empty(), op2, 2),
|
||||
op,
|
||||
hash_op_assign: calc_fn_hash(empty(), op_assignment, 2),
|
||||
hash_op: calc_fn_hash(empty(), op_raw, 2),
|
||||
op: op_assignment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use crate::optimize::OptimizationLevel;
|
||||
use crate::packages::{Package, StandardPackage};
|
||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||
use crate::syntax::CustomSyntax;
|
||||
use crate::token::Token;
|
||||
use crate::utils::get_hasher;
|
||||
use crate::{
|
||||
Dynamic, EvalAltResult, Identifier, ImmutableString, Module, Position, RhaiResult, Scope,
|
||||
@ -221,14 +222,14 @@ pub const FN_ANONYMOUS: &str = "anon$";
|
||||
/// Standard equality comparison operator.
|
||||
pub const OP_EQUALS: &str = "==";
|
||||
|
||||
/// Standard concatenation operator.
|
||||
pub const OP_CONCAT: &str = "+=";
|
||||
|
||||
/// Standard method function for containment testing.
|
||||
///
|
||||
/// The `in` operator is implemented as a call to this method.
|
||||
pub const OP_CONTAINS: &str = "contains";
|
||||
|
||||
/// Standard concatenation operator token.
|
||||
pub const TOKEN_OP_CONCAT: Token = Token::PlusAssign;
|
||||
|
||||
/// Method of chaining.
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
@ -1792,7 +1793,7 @@ impl Engine {
|
||||
mods,
|
||||
state,
|
||||
lib,
|
||||
Some(OpAssignment::new(OP_CONCAT)),
|
||||
Some(OpAssignment::new(TOKEN_OP_CONCAT)),
|
||||
pos,
|
||||
(&mut result).into(),
|
||||
item,
|
||||
|
@ -387,7 +387,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
||||
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()
|
||||
if Token::lookup_from_syntax(&x2.name).map(|t| t.has_op_assignment()).unwrap_or(false)
|
||||
&& x2.args_count() == 2 && x2.args.len() >= 1
|
||||
&& x2.args[0].get_variable_name(true) == x.0.get_variable_name(true)
|
||||
) =>
|
||||
@ -397,7 +397,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
||||
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.1 = Some(OpAssignment::new(op_assignment));
|
||||
x.2 = if x2.args.len() > 1 {
|
||||
mem::take(&mut x2.args[1])
|
||||
} else {
|
||||
|
@ -1409,7 +1409,7 @@ fn parse_unary(
|
||||
|
||||
/// Make an assignment statement.
|
||||
fn make_assignment_stmt<'a>(
|
||||
op: &'static str,
|
||||
op: Option<Token>,
|
||||
state: &mut ParseState,
|
||||
lhs: Expr,
|
||||
rhs: Expr,
|
||||
@ -1432,11 +1432,7 @@ fn make_assignment_stmt<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
let op_info = if op.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(OpAssignment::new(op))
|
||||
};
|
||||
let op_info = op.map(|v| OpAssignment::new(v));
|
||||
|
||||
match &lhs {
|
||||
// const_expr = rhs
|
||||
@ -1516,13 +1512,12 @@ fn parse_op_assignment_stmt(
|
||||
let (token, token_pos) = input.peek().unwrap();
|
||||
settings.pos = *token_pos;
|
||||
|
||||
let op = match token {
|
||||
Token::Equals => "",
|
||||
_ if token.map_op_assignment().is_some() => token.keyword_syntax(),
|
||||
let (op, pos) = match token {
|
||||
Token::Equals => (None, input.next().unwrap().1),
|
||||
_ if token.is_op_assignment() => input.next().map(|(op, pos)| (Some(op), pos)).unwrap(),
|
||||
_ => return Ok(Stmt::Expr(lhs)),
|
||||
};
|
||||
|
||||
let (_, pos) = input.next().unwrap();
|
||||
let rhs = parse_expr(input, state, lib, settings.level_up())?;
|
||||
make_assignment_stmt(op, state, lhs, rhs, pos)
|
||||
}
|
||||
|
38
src/token.rs
38
src/token.rs
@ -578,6 +578,25 @@ impl Token {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this token an op-assignment operator?
|
||||
#[inline]
|
||||
pub fn is_op_assignment(&self) -> bool {
|
||||
match self {
|
||||
Self::PlusAssign
|
||||
| Self::MinusAssign
|
||||
| Self::MultiplyAssign
|
||||
| Self::DivideAssign
|
||||
| Self::LeftShiftAssign
|
||||
| Self::RightShiftAssign
|
||||
| Self::ModuloAssign
|
||||
| Self::PowerOfAssign
|
||||
| Self::AndAssign
|
||||
| Self::OrAssign
|
||||
| Self::XOrAssign => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@ -596,6 +615,25 @@ impl Token {
|
||||
})
|
||||
}
|
||||
|
||||
/// Has this token a corresponding op-assignment operator?
|
||||
#[inline]
|
||||
pub fn has_op_assignment(&self) -> bool {
|
||||
match self {
|
||||
Self::Plus
|
||||
| Self::Minus
|
||||
| Self::Multiply
|
||||
| Self::Divide
|
||||
| Self::LeftShift
|
||||
| Self::RightShift
|
||||
| Self::Modulo
|
||||
| Self::PowerOf
|
||||
| Self::Ampersand
|
||||
| Self::Pipe
|
||||
| Self::XOr => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the corresponding op-assignment operator of the token.
|
||||
pub fn make_op_assignment(&self) -> Option<Self> {
|
||||
Some(match self {
|
||||
|
Loading…
Reference in New Issue
Block a user