Fix op-assignment hashes.

This commit is contained in:
Stephen Chung 2023-02-11 15:06:17 +08:00
parent 9cb5154979
commit 557b368fdb
6 changed files with 57 additions and 38 deletions

View File

@ -5,8 +5,8 @@ use crate::engine::{KEYWORD_FN_PTR, OP_EXCLUSIVE_RANGE, OP_INCLUSIVE_RANGE};
use crate::tokenizer::Token; use crate::tokenizer::Token;
use crate::types::dynamic::Union; use crate::types::dynamic::Union;
use crate::{ use crate::{
calc_fn_hash, Dynamic, FnPtr, Identifier, ImmutableString, Position, SmartString, StaticVec, calc_fn_hash, Dynamic, FnArgsVec, FnPtr, Identifier, ImmutableString, Position, SmartString,
INT, StaticVec, INT,
}; };
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -201,7 +201,7 @@ pub struct FnCallExpr {
/// Pre-calculated hashes. /// Pre-calculated hashes.
pub hashes: FnCallHashes, pub hashes: FnCallHashes,
/// List of function call argument expressions. /// List of function call argument expressions.
pub args: StaticVec<Expr>, pub args: FnArgsVec<Expr>,
/// Does this function call capture the parent scope? /// Does this function call capture the parent scope?
pub capture_parent_scope: bool, pub capture_parent_scope: bool,
/// Is this function call a native operator? /// Is this function call a native operator?

View File

@ -24,15 +24,15 @@ use std::{
#[derive(Clone, PartialEq, Hash)] #[derive(Clone, PartialEq, Hash)]
pub struct OpAssignment { pub struct OpAssignment {
/// Hash of the op-assignment call. /// Hash of the op-assignment call.
pub hash_op_assign: u64, hash_op_assign: u64,
/// Hash of the underlying operator call (for fallback). /// Hash of the underlying operator call (for fallback).
pub hash_op: u64, hash_op: u64,
/// Op-assignment operator. /// Op-assignment operator.
pub op_assign: Token, op_assign: Token,
/// Underlying operator. /// Underlying operator.
pub op: Token, op: Token,
/// [Position] of the op-assignment operator. /// [Position] of the op-assignment operator.
pub pos: Position, pos: Position,
} }
impl OpAssignment { impl OpAssignment {
@ -51,8 +51,31 @@ impl OpAssignment {
/// Is this an op-assignment? /// Is this an op-assignment?
#[must_use] #[must_use]
#[inline(always)] #[inline(always)]
pub const fn is_op_assignment(&self) -> bool { pub fn is_op_assignment(&self) -> bool {
self.hash_op_assign != 0 || self.hash_op != 0 !matches!(self.op, Token::Equals)
}
/// Get information if this [`OpAssignment`] is an op-assignment.
///
/// Returns `( hash_op_assign, hash_op, op_assign, op )`:
///
/// * `hash_op_assign`: Hash of the op-assignment call.
/// * `hash_op`: Hash of the underlying operator call (for fallback).
/// * `op_assign`: Op-assignment operator.
/// * `op`: Underlying operator.
#[must_use]
#[inline]
pub fn get_op_assignment_info(&self) -> Option<(u64, u64, &Token, &Token)> {
if self.is_op_assignment() {
Some((self.hash_op_assign, self.hash_op, &self.op_assign, &self.op))
} else {
None
}
}
/// Get the [position][Position] of this [`OpAssignment`].
#[must_use]
#[inline(always)]
pub const fn position(&self) -> Position {
self.pos
} }
/// Create a new [`OpAssignment`]. /// Create a new [`OpAssignment`].
/// ///

View File

@ -621,7 +621,7 @@ impl Engine {
self.eval_op_assignment( self.eval_op_assignment(
global, caches, op_info, root, obj_ptr, new_val, global, caches, op_info, root, obj_ptr, new_val,
)?; )?;
self.check_data_size(obj_ptr.as_ref(), op_info.pos)?; self.check_data_size(obj_ptr.as_ref(), op_info.position())?;
None None
} }
// Indexed value cannot be referenced - use indexer // Indexed value cannot be referenced - use indexer
@ -647,7 +647,7 @@ impl Engine {
)?; )?;
// Replace new value // Replace new value
new_val = val.take_or_clone(); new_val = val.take_or_clone();
self.check_data_size(&new_val, op_info.pos)?; self.check_data_size(&new_val, op_info.position())?;
} }
} }
@ -729,7 +729,7 @@ impl Engine {
global, caches, op_info, root, val_target, new_val, global, caches, op_info, root, val_target, new_val,
)?; )?;
} }
self.check_data_size(target.source(), op_info.pos)?; self.check_data_size(target.source(), op_info.position())?;
Ok((Dynamic::UNIT, true)) Ok((Dynamic::UNIT, true))
} }
// {xxx:map}.id // {xxx:map}.id

View File

@ -125,18 +125,10 @@ impl Engine {
return Err(ERR::ErrorAssignmentToConstant(name.to_string(), pos).into()); return Err(ERR::ErrorAssignmentToConstant(name.to_string(), pos).into());
} }
if op_info.is_op_assignment() { let pos = op_info.position();
let OpAssignment {
hash_op_assign,
hash_op,
op_assign,
op,
pos,
} = op_info;
if let Some((hash1, hash2, op_assign, op)) = op_info.get_op_assignment_info() {
let mut lock_guard = target.write_lock::<Dynamic>().unwrap(); let mut lock_guard = target.write_lock::<Dynamic>().unwrap();
let hash = *hash_op_assign;
let args = &mut [&mut *lock_guard, &mut new_val]; let args = &mut [&mut *lock_guard, &mut new_val];
if self.fast_operators() { if self.fast_operators() {
@ -149,7 +141,7 @@ impl Engine {
let context = if need_context { let context = if need_context {
let op = op_assign.literal_syntax(); let op = op_assign.literal_syntax();
let source = global.source(); let source = global.source();
Some((self, op, source, &*global, *pos).into()) Some((self, op, source, &*global, pos).into())
} else { } else {
None None
}; };
@ -160,7 +152,7 @@ impl Engine {
let token = Some(op_assign); let token = Some(op_assign);
let op_assign = op_assign.literal_syntax(); let op_assign = op_assign.literal_syntax();
match self.exec_native_fn_call(global, caches, op_assign, token, hash, args, true, *pos) match self.exec_native_fn_call(global, caches, op_assign, token, hash1, args, true, pos)
{ {
Ok(_) => (), Ok(_) => (),
Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) => Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) =>
@ -170,7 +162,7 @@ impl Engine {
let op = op.literal_syntax(); let op = op.literal_syntax();
*args[0] = self *args[0] = self
.exec_native_fn_call(global, caches, op, token, *hash_op, args, true, *pos)? .exec_native_fn_call(global, caches, op, token, hash2, args, true, pos)?
.0; .0;
} }
Err(err) => return Err(err), Err(err) => return Err(err),
@ -189,7 +181,7 @@ impl Engine {
} }
} }
target.propagate_changed_value(op_info.pos) target.propagate_changed_value(pos)
} }
/// Evaluate a statement. /// Evaluate a statement.

View File

@ -513,7 +513,11 @@ pub mod blob_functions {
/// ///
/// print(b); // prints "[030405]" /// print(b); // prints "[030405]"
/// ``` /// ```
#[allow(clippy::cast_sign_loss, clippy::needless_pass_by_value, clippy::cast_possible_truncation)] #[allow(
clippy::cast_sign_loss,
clippy::needless_pass_by_value,
clippy::cast_possible_truncation
)]
pub fn chop(blob: &mut Blob, len: INT) { pub fn chop(blob: &mut Blob, len: INT) {
if !blob.is_empty() { if !blob.is_empty() {
if len <= 0 { if len <= 0 {

View File

@ -17,9 +17,9 @@ use crate::tokenizer::{
use crate::types::dynamic::AccessMode; use crate::types::dynamic::AccessMode;
use crate::types::StringsInterner; use crate::types::StringsInterner;
use crate::{ use crate::{
calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ExclusiveRange, Identifier, calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ExclusiveRange, FnArgsVec,
ImmutableString, InclusiveRange, LexError, OptimizationLevel, ParseError, Position, Scope, Identifier, ImmutableString, InclusiveRange, LexError, OptimizationLevel, ParseError, Position,
Shared, SmartString, StaticVec, AST, INT, PERR, Scope, Shared, SmartString, StaticVec, AST, INT, PERR,
}; };
use bitflags::bitflags; use bitflags::bitflags;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
@ -567,7 +567,7 @@ impl Engine {
}; };
let mut _namespace = namespace; let mut _namespace = namespace;
let mut args = StaticVec::new_const(); let mut args = FnArgsVec::new_const();
match token { match token {
// id( <EOF> // id( <EOF>
@ -1945,7 +1945,7 @@ impl Engine {
// Call negative function // Call negative function
expr => { expr => {
let mut args = StaticVec::new_const(); let mut args = FnArgsVec::new_const();
args.push(expr); args.push(expr);
args.shrink_to_fit(); args.shrink_to_fit();
@ -1973,7 +1973,7 @@ impl Engine {
// Call plus function // Call plus function
expr => { expr => {
let mut args = StaticVec::new_const(); let mut args = FnArgsVec::new_const();
args.push(expr); args.push(expr);
args.shrink_to_fit(); args.shrink_to_fit();
@ -1994,7 +1994,7 @@ impl Engine {
let token = token.clone(); let token = token.clone();
let pos = eat_token(input, Token::Bang); let pos = eat_token(input, Token::Bang);
let mut args = StaticVec::new_const(); let mut args = FnArgsVec::new_const();
args.push(self.parse_unary(input, state, lib, settings.level_up()?)?); args.push(self.parse_unary(input, state, lib, settings.level_up()?)?);
args.shrink_to_fit(); args.shrink_to_fit();
@ -2359,7 +2359,7 @@ impl Engine {
Some(op_token.clone()) Some(op_token.clone())
}; };
let mut args = StaticVec::new_const(); let mut args = FnArgsVec::new_const();
args.push(root); args.push(root);
args.push(rhs); args.push(rhs);
args.shrink_to_fit(); args.shrink_to_fit();
@ -2419,7 +2419,7 @@ impl Engine {
} else { } else {
// Put a `!` call in front // Put a `!` call in front
let op = Token::Bang.literal_syntax(); let op = Token::Bang.literal_syntax();
let mut args = StaticVec::new_const(); let mut args = FnArgsVec::new_const();
args.push(fn_call); args.push(fn_call);
let not_base = FnCallExpr { let not_base = FnCallExpr {
@ -3708,7 +3708,7 @@ impl Engine {
} }
let num_externals = externals.len(); let num_externals = externals.len();
let mut args = StaticVec::with_capacity(externals.len() + 1); let mut args = FnArgsVec::with_capacity(externals.len() + 1);
args.push(fn_expr); args.push(fn_expr);