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 {
|
impl OpAssignment {
|
||||||
pub fn new(op: &'static str) -> Self {
|
/// Create a new [`OpAssignment`].
|
||||||
let op2 = &op[..op.len() - 1]; // extract operator without =
|
///
|
||||||
|
/// # 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 {
|
Self {
|
||||||
hash_op_assign: calc_fn_hash(empty(), op, 2),
|
hash_op_assign: calc_fn_hash(empty(), op_assignment, 2),
|
||||||
hash_op: calc_fn_hash(empty(), op2, 2),
|
hash_op: calc_fn_hash(empty(), op_raw, 2),
|
||||||
op,
|
op: op_assignment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ use crate::optimize::OptimizationLevel;
|
|||||||
use crate::packages::{Package, StandardPackage};
|
use crate::packages::{Package, StandardPackage};
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
use crate::syntax::CustomSyntax;
|
use crate::syntax::CustomSyntax;
|
||||||
|
use crate::token::Token;
|
||||||
use crate::utils::get_hasher;
|
use crate::utils::get_hasher;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, EvalAltResult, Identifier, ImmutableString, Module, Position, RhaiResult, Scope,
|
Dynamic, EvalAltResult, Identifier, ImmutableString, Module, Position, RhaiResult, Scope,
|
||||||
@ -221,14 +222,14 @@ pub const FN_ANONYMOUS: &str = "anon$";
|
|||||||
/// Standard equality comparison operator.
|
/// Standard equality comparison operator.
|
||||||
pub const OP_EQUALS: &str = "==";
|
pub const OP_EQUALS: &str = "==";
|
||||||
|
|
||||||
/// Standard concatenation operator.
|
|
||||||
pub const OP_CONCAT: &str = "+=";
|
|
||||||
|
|
||||||
/// Standard method function for containment testing.
|
/// Standard method function for containment testing.
|
||||||
///
|
///
|
||||||
/// The `in` operator is implemented as a call to this method.
|
/// The `in` operator is implemented as a call to this method.
|
||||||
pub const OP_CONTAINS: &str = "contains";
|
pub const OP_CONTAINS: &str = "contains";
|
||||||
|
|
||||||
|
/// Standard concatenation operator token.
|
||||||
|
pub const TOKEN_OP_CONCAT: Token = Token::PlusAssign;
|
||||||
|
|
||||||
/// Method of chaining.
|
/// Method of chaining.
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
@ -1792,7 +1793,7 @@ impl Engine {
|
|||||||
mods,
|
mods,
|
||||||
state,
|
state,
|
||||||
lib,
|
lib,
|
||||||
Some(OpAssignment::new(OP_CONCAT)),
|
Some(OpAssignment::new(TOKEN_OP_CONCAT)),
|
||||||
pos,
|
pos,
|
||||||
(&mut result).into(),
|
(&mut result).into(),
|
||||||
item,
|
item,
|
||||||
|
@ -387,7 +387,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
if x.1.is_none()
|
if x.1.is_none()
|
||||||
&& x.0.is_variable_access(true)
|
&& x.0.is_variable_access(true)
|
||||||
&& matches!(&x.2, Expr::FnCall(x2, _)
|
&& 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_count() == 2 && x2.args.len() >= 1
|
||||||
&& x2.args[0].get_variable_name(true) == x.0.get_variable_name(true)
|
&& 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();
|
state.set_dirty();
|
||||||
let op = Token::lookup_from_syntax(&x2.name).unwrap();
|
let op = Token::lookup_from_syntax(&x2.name).unwrap();
|
||||||
let op_assignment = op.make_op_assignment().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 {
|
x.2 = if x2.args.len() > 1 {
|
||||||
mem::take(&mut x2.args[1])
|
mem::take(&mut x2.args[1])
|
||||||
} else {
|
} else {
|
||||||
|
@ -1409,7 +1409,7 @@ fn parse_unary(
|
|||||||
|
|
||||||
/// Make an assignment statement.
|
/// Make an assignment statement.
|
||||||
fn make_assignment_stmt<'a>(
|
fn make_assignment_stmt<'a>(
|
||||||
op: &'static str,
|
op: Option<Token>,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
rhs: Expr,
|
rhs: Expr,
|
||||||
@ -1432,11 +1432,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let op_info = if op.is_empty() {
|
let op_info = op.map(|v| OpAssignment::new(v));
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(OpAssignment::new(op))
|
|
||||||
};
|
|
||||||
|
|
||||||
match &lhs {
|
match &lhs {
|
||||||
// const_expr = rhs
|
// const_expr = rhs
|
||||||
@ -1516,13 +1512,12 @@ fn parse_op_assignment_stmt(
|
|||||||
let (token, token_pos) = input.peek().unwrap();
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
settings.pos = *token_pos;
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
let op = match token {
|
let (op, pos) = match token {
|
||||||
Token::Equals => "",
|
Token::Equals => (None, input.next().unwrap().1),
|
||||||
_ if token.map_op_assignment().is_some() => token.keyword_syntax(),
|
_ if token.is_op_assignment() => input.next().map(|(op, pos)| (Some(op), pos)).unwrap(),
|
||||||
_ => return Ok(Stmt::Expr(lhs)),
|
_ => return Ok(Stmt::Expr(lhs)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_, pos) = input.next().unwrap();
|
|
||||||
let rhs = parse_expr(input, state, lib, settings.level_up())?;
|
let rhs = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
make_assignment_stmt(op, state, lhs, rhs, pos)
|
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.
|
/// Get the corresponding operator of the token if it is an op-assignment operator.
|
||||||
pub fn map_op_assignment(&self) -> Option<Self> {
|
pub fn map_op_assignment(&self) -> Option<Self> {
|
||||||
Some(match 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.
|
/// Get the corresponding op-assignment operator of the token.
|
||||||
pub fn make_op_assignment(&self) -> Option<Self> {
|
pub fn make_op_assignment(&self) -> Option<Self> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
|
Loading…
Reference in New Issue
Block a user