commit
4c2630b71f
@ -1,7 +1,6 @@
|
|||||||
//! Module containing all deprecated API that will be removed in the next major version.
|
//! Module containing all deprecated API that will be removed in the next major version.
|
||||||
|
|
||||||
use crate::func::RegisterNativeFunction;
|
use crate::func::RegisterNativeFunction;
|
||||||
use crate::plugin::*;
|
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, NativeCallContext,
|
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, NativeCallContext,
|
||||||
@ -633,6 +632,9 @@ impl Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::plugin::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
pub mod deprecated_array_functions {
|
pub mod deprecated_array_functions {
|
||||||
|
@ -489,11 +489,13 @@ impl Expr {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::Map(x, ..) if self.is_constant() => {
|
Self::Map(x, ..) if self.is_constant() => {
|
||||||
Dynamic::from_map(x.0.iter().fold(x.1.clone(), |mut map, (k, v)| {
|
let mut map = x.1.clone();
|
||||||
let value_ref = map.get_mut(k.name.as_str()).unwrap();
|
|
||||||
*value_ref = v.get_literal_value().unwrap();
|
for (k, v) in &x.0 {
|
||||||
map
|
*map.get_mut(k.name.as_str()).unwrap() = v.get_literal_value().unwrap();
|
||||||
}))
|
}
|
||||||
|
|
||||||
|
Dynamic::from_map(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolated string
|
// Interpolated string
|
||||||
|
@ -18,23 +18,37 @@ impl Dynamic {
|
|||||||
/// Panics if any interior data is shared (should never happen).
|
/// Panics if any interior data is shared (should never happen).
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn calc_array_sizes(array: &crate::Array, _top: bool) -> (usize, usize, usize) {
|
pub(crate) fn calc_array_sizes(array: &crate::Array) -> (usize, usize, usize) {
|
||||||
array
|
let (mut ax, mut mx, mut sx) = (0, 0, 0);
|
||||||
.iter()
|
|
||||||
.fold((0, 0, 0), |(ax, mx, sx), value| match value.0 {
|
for value in array {
|
||||||
Union::Array(..) => {
|
ax += 1;
|
||||||
let (a, m, s) = value.calc_data_sizes(false);
|
|
||||||
(ax + a + 1, mx + m, sx + s)
|
match value.0 {
|
||||||
|
Union::Array(ref a, ..) => {
|
||||||
|
let (a, m, s) = Self::calc_array_sizes(a);
|
||||||
|
ax += a;
|
||||||
|
mx += m;
|
||||||
|
sx += s;
|
||||||
}
|
}
|
||||||
Union::Blob(ref a, ..) => (ax + 1 + a.len(), mx, sx),
|
Union::Blob(ref a, ..) => ax += 1 + a.len(),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(..) => {
|
Union::Map(ref m, ..) => {
|
||||||
let (a, m, s) = value.calc_data_sizes(false);
|
let (a, m, s) = Self::calc_map_sizes(m);
|
||||||
(ax + a + 1, mx + m, sx + s)
|
ax += a;
|
||||||
|
mx += m;
|
||||||
|
sx += s;
|
||||||
}
|
}
|
||||||
Union::Str(ref s, ..) => (ax + 1, mx, sx + s.len()),
|
Union::Str(ref s, ..) => sx += s.len(),
|
||||||
_ => (ax + 1, mx, sx),
|
#[cfg(not(feature = "no_closure"))]
|
||||||
})
|
Union::Shared(..) => {
|
||||||
|
unreachable!("shared values discovered within data")
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(ax, mx, sx)
|
||||||
}
|
}
|
||||||
/// Recursively calculate the sizes of a map.
|
/// Recursively calculate the sizes of a map.
|
||||||
///
|
///
|
||||||
@ -45,23 +59,38 @@ impl Dynamic {
|
|||||||
/// Panics if any interior data is shared (should never happen).
|
/// Panics if any interior data is shared (should never happen).
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn calc_map_sizes(map: &crate::Map, _top: bool) -> (usize, usize, usize) {
|
pub(crate) fn calc_map_sizes(map: &crate::Map) -> (usize, usize, usize) {
|
||||||
map.values()
|
let (mut ax, mut mx, mut sx) = (0, 0, 0);
|
||||||
.fold((0, 0, 0), |(ax, mx, sx), value| match value.0 {
|
|
||||||
|
for value in map.values() {
|
||||||
|
mx += 1;
|
||||||
|
|
||||||
|
match value.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(..) => {
|
Union::Array(ref a, ..) => {
|
||||||
let (a, m, s) = value.calc_data_sizes(false);
|
let (a, m, s) = Self::calc_array_sizes(a);
|
||||||
(ax + a, mx + m + 1, sx + s)
|
ax += a;
|
||||||
|
mx += m;
|
||||||
|
sx += s;
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(ref a, ..) => (ax + a.len(), mx, sx),
|
Union::Blob(ref a, ..) => ax += 1 + a.len(),
|
||||||
Union::Map(..) => {
|
Union::Map(ref m, ..) => {
|
||||||
let (a, m, s) = value.calc_data_sizes(false);
|
let (a, m, s) = Self::calc_map_sizes(m);
|
||||||
(ax + a, mx + m + 1, sx + s)
|
ax += a;
|
||||||
|
mx += m;
|
||||||
|
sx += s;
|
||||||
}
|
}
|
||||||
Union::Str(ref s, ..) => (ax, mx + 1, sx + s.len()),
|
Union::Str(ref s, ..) => sx += s.len(),
|
||||||
_ => (ax, mx + 1, sx),
|
#[cfg(not(feature = "no_closure"))]
|
||||||
})
|
Union::Shared(..) => {
|
||||||
|
unreachable!("shared values discovered within data")
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(ax, mx, sx)
|
||||||
}
|
}
|
||||||
/// Recursively calculate the sizes of a value.
|
/// Recursively calculate the sizes of a value.
|
||||||
///
|
///
|
||||||
@ -74,11 +103,11 @@ impl Dynamic {
|
|||||||
pub(crate) fn calc_data_sizes(&self, _top: bool) -> (usize, usize, usize) {
|
pub(crate) fn calc_data_sizes(&self, _top: bool) -> (usize, usize, usize) {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref arr, ..) => Self::calc_array_sizes(&**arr, _top),
|
Union::Array(ref arr, ..) => Self::calc_array_sizes(&**arr),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(ref blob, ..) => (blob.len(), 0, 0),
|
Union::Blob(ref blob, ..) => (blob.len(), 0, 0),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(ref map, ..) => Self::calc_map_sizes(&**map, _top),
|
Union::Map(ref map, ..) => Self::calc_map_sizes(&**map),
|
||||||
Union::Str(ref s, ..) => (0, 0, s.len()),
|
Union::Str(ref s, ..) => (0, 0, s.len()),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(..) if _top => self.read_lock::<Self>().unwrap().calc_data_sizes(true),
|
Union::Shared(..) if _top => self.read_lock::<Self>().unwrap().calc_data_sizes(true),
|
||||||
|
@ -286,7 +286,7 @@ impl Engine {
|
|||||||
Expr::InterpolatedString(x, _) => {
|
Expr::InterpolatedString(x, _) => {
|
||||||
let mut concat = SmartString::new_const();
|
let mut concat = SmartString::new_const();
|
||||||
|
|
||||||
x.iter().try_for_each(|expr| -> RhaiResultOf<()> {
|
for expr in &**x {
|
||||||
let item = &mut self
|
let item = &mut self
|
||||||
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
|
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
|
||||||
.flatten();
|
.flatten();
|
||||||
@ -304,9 +304,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.throw_on_size((0, 0, concat.len()))
|
self.throw_on_size((0, 0, concat.len()))
|
||||||
.map_err(|err| err.fill_position(pos))?;
|
.map_err(|err| err.fill_position(pos))?;
|
||||||
|
}
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(self.get_interned_string(concat).into())
|
Ok(self.get_interned_string(concat).into())
|
||||||
}
|
}
|
||||||
@ -318,7 +316,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let mut total_data_sizes = (0, 0, 0);
|
let mut total_data_sizes = (0, 0, 0);
|
||||||
|
|
||||||
x.iter().try_for_each(|item_expr| -> RhaiResultOf<()> {
|
for item_expr in &**x {
|
||||||
let value = self
|
let value = self
|
||||||
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), item_expr)?
|
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), item_expr)?
|
||||||
.flatten();
|
.flatten();
|
||||||
@ -337,9 +335,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
array.push(value);
|
array.push(value);
|
||||||
|
}
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Dynamic::from_array(array))
|
Ok(Dynamic::from_array(array))
|
||||||
}
|
}
|
||||||
@ -351,28 +347,25 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let mut total_data_sizes = (0, 0, 0);
|
let mut total_data_sizes = (0, 0, 0);
|
||||||
|
|
||||||
x.0.iter()
|
for (key, value_expr) in &x.0 {
|
||||||
.try_for_each(|(key, value_expr)| -> RhaiResultOf<()> {
|
let value = self
|
||||||
let value = self
|
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), value_expr)?
|
||||||
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), value_expr)?
|
.flatten();
|
||||||
.flatten();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if self.has_data_size_limit() {
|
if self.has_data_size_limit() {
|
||||||
let delta = value.calc_data_sizes(true);
|
let delta = value.calc_data_sizes(true);
|
||||||
total_data_sizes = (
|
total_data_sizes = (
|
||||||
total_data_sizes.0 + delta.0,
|
total_data_sizes.0 + delta.0,
|
||||||
total_data_sizes.1 + delta.1 + 1,
|
total_data_sizes.1 + delta.1 + 1,
|
||||||
total_data_sizes.2 + delta.2,
|
total_data_sizes.2 + delta.2,
|
||||||
);
|
);
|
||||||
self.throw_on_size(total_data_sizes)
|
self.throw_on_size(total_data_sizes)
|
||||||
.map_err(|err| err.fill_position(value_expr.position()))?;
|
.map_err(|err| err.fill_position(value_expr.position()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
*map.get_mut(key.as_str()).unwrap() = value;
|
*map.get_mut(key.as_str()).unwrap() = value;
|
||||||
|
}
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Dynamic::from_map(map))
|
Ok(Dynamic::from_map(map))
|
||||||
}
|
}
|
||||||
|
@ -129,9 +129,9 @@ impl Engine {
|
|||||||
let OpAssignment {
|
let OpAssignment {
|
||||||
hash_op_assign,
|
hash_op_assign,
|
||||||
hash_op,
|
hash_op,
|
||||||
op_assign: op_assign_token,
|
op_assign,
|
||||||
op: op_token,
|
op,
|
||||||
pos: op_pos,
|
pos,
|
||||||
} = op_info;
|
} = op_info;
|
||||||
|
|
||||||
let mut lock_guard = target.write_lock::<Dynamic>().unwrap();
|
let mut lock_guard = target.write_lock::<Dynamic>().unwrap();
|
||||||
@ -141,15 +141,15 @@ impl Engine {
|
|||||||
|
|
||||||
if self.fast_operators() {
|
if self.fast_operators() {
|
||||||
if let Some((func, need_context)) =
|
if let Some((func, need_context)) =
|
||||||
get_builtin_op_assignment_fn(op_assign_token.clone(), args[0], args[1])
|
get_builtin_op_assignment_fn(op_assign.clone(), args[0], args[1])
|
||||||
{
|
{
|
||||||
// Built-in found
|
// Built-in found
|
||||||
let op = op_assign_token.literal_syntax();
|
|
||||||
auto_restore! { let orig_level = global.level; global.level += 1 }
|
auto_restore! { let orig_level = global.level; global.level += 1 }
|
||||||
|
|
||||||
let context = if need_context {
|
let context = if need_context {
|
||||||
|
let op = op_assign.literal_syntax();
|
||||||
let source = global.source();
|
let source = global.source();
|
||||||
Some((self, op, source, &*global, *op_pos).into())
|
Some((self, op, source, &*global, *pos).into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -157,23 +157,20 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let op_assign = op_assign_token.literal_syntax();
|
let token = Some(op_assign.clone());
|
||||||
let op = op_token.literal_syntax();
|
let op_assign = op_assign.literal_syntax();
|
||||||
let token = Some(op_assign_token.clone());
|
|
||||||
|
|
||||||
match self
|
match self.exec_native_fn_call(global, caches, op_assign, token, hash, args, true, *pos)
|
||||||
.exec_native_fn_call(global, caches, op_assign, token, hash, args, true, *op_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)) =>
|
||||||
{
|
{
|
||||||
// Expand to `var = var op rhs`
|
// Expand to `var = var op rhs`
|
||||||
let token = Some(op_token.clone());
|
let token = Some(op.clone());
|
||||||
|
let op = op.literal_syntax();
|
||||||
|
|
||||||
*args[0] = self
|
*args[0] = self
|
||||||
.exec_native_fn_call(
|
.exec_native_fn_call(global, caches, op, token, *hash_op, args, true, *pos)?
|
||||||
global, caches, op, token, *hash_op, args, true, *op_pos,
|
|
||||||
)?
|
|
||||||
.0;
|
.0;
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
@ -864,25 +861,23 @@ impl Engine {
|
|||||||
// Share statement
|
// Share statement
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Stmt::Share(x) => {
|
Stmt::Share(x) => {
|
||||||
x.iter()
|
for (name, index, pos) in &**x {
|
||||||
.try_for_each(|(name, index, pos)| {
|
if let Some(index) = index
|
||||||
index
|
.map(|n| scope.len() - n.get())
|
||||||
.map(|n| scope.len() - n.get())
|
.or_else(|| scope.search(name))
|
||||||
.or_else(|| scope.search(name))
|
{
|
||||||
.map_or_else(
|
let val = scope.get_mut_by_index(index);
|
||||||
|| Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into()),
|
|
||||||
|index| {
|
|
||||||
let val = scope.get_mut_by_index(index);
|
|
||||||
|
|
||||||
if !val.is_shared() {
|
if !val.is_shared() {
|
||||||
// Replace the variable with a shared value.
|
// Replace the variable with a shared value.
|
||||||
*val = std::mem::take(val).into_shared();
|
*val = std::mem::take(val).into_shared();
|
||||||
}
|
}
|
||||||
Ok(())
|
} else {
|
||||||
},
|
return Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into());
|
||||||
)
|
}
|
||||||
})
|
}
|
||||||
.map(|_| Dynamic::UNIT)
|
|
||||||
|
Ok(Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unreachable!("statement cannot be evaluated: {:?}", stmt),
|
_ => unreachable!("statement cannot be evaluated: {:?}", stmt),
|
||||||
|
@ -1118,12 +1118,11 @@ impl Engine {
|
|||||||
let mut fn_ptr = arg_value.cast::<FnPtr>();
|
let mut fn_ptr = arg_value.cast::<FnPtr>();
|
||||||
|
|
||||||
// Append the new curried arguments to the existing list.
|
// Append the new curried arguments to the existing list.
|
||||||
a_expr.iter().try_for_each(|expr| -> Result<_, RhaiError> {
|
for expr in a_expr {
|
||||||
let (value, ..) =
|
let (value, ..) =
|
||||||
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
|
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
|
||||||
fn_ptr.add_curry(value);
|
fn_ptr.add_curry(value);
|
||||||
Ok(())
|
}
|
||||||
})?;
|
|
||||||
|
|
||||||
return Ok(fn_ptr.into());
|
return Ok(fn_ptr.into());
|
||||||
}
|
}
|
||||||
@ -1229,14 +1228,11 @@ impl Engine {
|
|||||||
// If so, do it separately because we cannot convert the first argument (if it is a simple
|
// If so, do it separately because we cannot convert the first argument (if it is a simple
|
||||||
// variable access) to &mut because `scope` is needed.
|
// variable access) to &mut because `scope` is needed.
|
||||||
if capture_scope && !scope.is_empty() {
|
if capture_scope && !scope.is_empty() {
|
||||||
first_arg
|
for expr in first_arg.iter().copied().chain(a_expr.iter()) {
|
||||||
.iter()
|
let (value, ..) =
|
||||||
.copied()
|
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
|
||||||
.chain(a_expr.iter())
|
arg_values.push(value.flatten());
|
||||||
.try_for_each(|expr| {
|
}
|
||||||
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
|
|
||||||
.map(|(value, ..)| arg_values.push(value.flatten()))
|
|
||||||
})?;
|
|
||||||
args.extend(curry.iter_mut());
|
args.extend(curry.iter_mut());
|
||||||
args.extend(arg_values.iter_mut());
|
args.extend(arg_values.iter_mut());
|
||||||
|
|
||||||
@ -1265,10 +1261,11 @@ impl Engine {
|
|||||||
self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), first_expr)?;
|
self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), first_expr)?;
|
||||||
|
|
||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
a_expr.iter().try_for_each(|expr| {
|
for expr in a_expr {
|
||||||
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
|
let (value, ..) =
|
||||||
.map(|(value, ..)| arg_values.push(value.flatten()))
|
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
|
||||||
})?;
|
arg_values.push(value.flatten());
|
||||||
|
}
|
||||||
|
|
||||||
let mut target =
|
let mut target =
|
||||||
self.search_namespace(global, caches, scope, this_ptr, first_expr)?;
|
self.search_namespace(global, caches, scope, this_ptr, first_expr)?;
|
||||||
@ -1289,13 +1286,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// func(..., ...)
|
// func(..., ...)
|
||||||
first_arg
|
for expr in first_arg.into_iter().chain(a_expr.iter()) {
|
||||||
.into_iter()
|
let (value, ..) =
|
||||||
.chain(a_expr.iter())
|
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
|
||||||
.try_for_each(|expr| {
|
arg_values.push(value.flatten());
|
||||||
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
|
}
|
||||||
.map(|(value, ..)| arg_values.push(value.flatten()))
|
|
||||||
})?;
|
|
||||||
args.extend(curry.iter_mut());
|
args.extend(curry.iter_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1345,10 +1340,11 @@ impl Engine {
|
|||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
arg_values.push(Dynamic::UNIT);
|
arg_values.push(Dynamic::UNIT);
|
||||||
|
|
||||||
args_expr.iter().skip(1).try_for_each(|expr| {
|
for expr in args_expr.iter().skip(1) {
|
||||||
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
|
let (value, ..) =
|
||||||
.map(|(value, ..)| arg_values.push(value.flatten()))
|
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
|
||||||
})?;
|
arg_values.push(value.flatten());
|
||||||
|
}
|
||||||
|
|
||||||
// Get target reference to first argument
|
// Get target reference to first argument
|
||||||
let first_arg = &args_expr[0];
|
let first_arg = &args_expr[0];
|
||||||
@ -1374,10 +1370,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// func(..., ...) or func(mod::x, ...)
|
// func(..., ...) or func(mod::x, ...)
|
||||||
args_expr.iter().try_for_each(|expr| {
|
for expr in args_expr {
|
||||||
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
|
let (value, ..) =
|
||||||
.map(|(value, ..)| arg_values.push(value.flatten()))
|
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
|
||||||
})?;
|
arg_values.push(value.flatten());
|
||||||
|
}
|
||||||
args.extend(arg_values.iter_mut());
|
args.extend(arg_values.iter_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ pub mod array_functions {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_array_size() > 0 {
|
if _ctx.engine().max_array_size() > 0 {
|
||||||
let pad = len - array.len();
|
let pad = len - array.len();
|
||||||
let (a, m, s) = Dynamic::calc_array_sizes(array, true);
|
let (a, m, s) = Dynamic::calc_array_sizes(array);
|
||||||
let (ax, mx, sx) = item.calc_data_sizes(true);
|
let (ax, mx, sx) = item.calc_data_sizes(true);
|
||||||
|
|
||||||
_ctx.engine()
|
_ctx.engine()
|
||||||
|
@ -546,11 +546,11 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
|
settings: ParseSettings,
|
||||||
id: ImmutableString,
|
id: ImmutableString,
|
||||||
no_args: bool,
|
no_args: bool,
|
||||||
capture_parent_scope: bool,
|
capture_parent_scope: bool,
|
||||||
namespace: Namespace,
|
namespace: Namespace,
|
||||||
settings: ParseSettings,
|
|
||||||
) -> ParseResult<Expr> {
|
) -> ParseResult<Expr> {
|
||||||
let (token, token_pos) = if no_args {
|
let (token, token_pos) = if no_args {
|
||||||
&(Token::RightParen, Position::NONE)
|
&(Token::RightParen, Position::NONE)
|
||||||
@ -743,10 +743,10 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
|
settings: ParseSettings,
|
||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
options: ASTFlags,
|
options: ASTFlags,
|
||||||
check_index_type: bool,
|
check_index_type: bool,
|
||||||
settings: ParseSettings,
|
|
||||||
) -> ParseResult<Expr> {
|
) -> ParseResult<Expr> {
|
||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
|
|
||||||
@ -869,7 +869,7 @@ impl Engine {
|
|||||||
_ => unreachable!("`[` or `?[`"),
|
_ => unreachable!("`[` or `?[`"),
|
||||||
};
|
};
|
||||||
let idx_expr = self.parse_index_chain(
|
let idx_expr = self.parse_index_chain(
|
||||||
input, state, lib, idx_expr, options, false, settings,
|
input, state, lib, settings, idx_expr, options, false,
|
||||||
)?;
|
)?;
|
||||||
// Indexing binds to right
|
// Indexing binds to right
|
||||||
Ok(Expr::Index(
|
Ok(Expr::Index(
|
||||||
@ -1307,8 +1307,8 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
is_property: bool,
|
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
|
is_property: bool,
|
||||||
) -> ParseResult<Expr> {
|
) -> ParseResult<Expr> {
|
||||||
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
|
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
|
||||||
|
|
||||||
@ -1460,7 +1460,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.parse_anon_fn(input, new_state, state, lib, new_settings.level_up()?);
|
self.parse_anon_fn(input, new_state, lib, new_settings.level_up()?, state);
|
||||||
|
|
||||||
// Restore the strings interner by swapping it back
|
// Restore the strings interner by swapping it back
|
||||||
std::mem::swap(state.interned_strings, new_state.interned_strings);
|
std::mem::swap(state.interned_strings, new_state.interned_strings);
|
||||||
@ -1468,28 +1468,22 @@ impl Engine {
|
|||||||
let (expr, fn_def) = result?;
|
let (expr, fn_def) = result?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
new_state
|
for Ident { name, pos } in new_state.external_vars.as_deref().into_iter().flatten()
|
||||||
.external_vars
|
{
|
||||||
.as_deref()
|
let (index, is_func) = state.access_var(name, lib, *pos);
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.try_for_each(|Ident { name, pos }| {
|
|
||||||
let (index, is_func) = state.access_var(name, lib, *pos);
|
|
||||||
|
|
||||||
if !is_func
|
if !is_func
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !settings.has_flag(ParseSettingFlags::CLOSURE_SCOPE)
|
&& !settings.has_flag(ParseSettingFlags::CLOSURE_SCOPE)
|
||||||
&& settings.has_option(LangOptions::STRICT_VAR)
|
&& settings.has_option(LangOptions::STRICT_VAR)
|
||||||
&& !state.scope.contains(name)
|
&& !state.scope.contains(name)
|
||||||
{
|
{
|
||||||
// If the parent scope is not inside another capturing closure
|
// If the parent scope is not inside another capturing closure
|
||||||
// then we can conclude that the captured variable doesn't exist.
|
// then we can conclude that the captured variable doesn't exist.
|
||||||
// Under Strict Variables mode, this is not allowed.
|
// Under Strict Variables mode, this is not allowed.
|
||||||
Err(PERR::VariableUndefined(name.to_string()).into_err(*pos))
|
return Err(PERR::VariableUndefined(name.to_string()).into_err(*pos));
|
||||||
} else {
|
}
|
||||||
Ok(())
|
}
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let hash_script = calc_fn_hash(None, &fn_def.name, fn_def.params.len());
|
let hash_script = calc_fn_hash(None, &fn_def.name, fn_def.params.len());
|
||||||
lib.insert(hash_script, fn_def);
|
lib.insert(hash_script, fn_def);
|
||||||
@ -1696,7 +1690,7 @@ impl Engine {
|
|||||||
return Ok(root_expr);
|
return Ok(root_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.parse_postfix(input, state, lib, root_expr, settings)
|
self.parse_postfix(input, state, lib, settings, root_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tail processing of all possible postfix operators of a primary expression.
|
/// Tail processing of all possible postfix operators of a primary expression.
|
||||||
@ -1705,8 +1699,8 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
mut lhs: Expr,
|
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
|
mut lhs: Expr,
|
||||||
) -> ParseResult<Expr> {
|
) -> ParseResult<Expr> {
|
||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
|
|
||||||
@ -1753,14 +1747,14 @@ impl Engine {
|
|||||||
|
|
||||||
let (.., ns, _, name) = *x;
|
let (.., ns, _, name) = *x;
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
self.parse_fn_call(input, state, lib, name, no_args, true, ns, settings)?
|
self.parse_fn_call(input, state, lib, settings, name, no_args, true, ns)?
|
||||||
}
|
}
|
||||||
// Function call
|
// Function call
|
||||||
(Expr::Variable(x, .., pos), t @ (Token::LeftParen | Token::Unit)) => {
|
(Expr::Variable(x, .., pos), t @ (Token::LeftParen | Token::Unit)) => {
|
||||||
let (.., ns, _, name) = *x;
|
let (.., ns, _, name) = *x;
|
||||||
let no_args = t == Token::Unit;
|
let no_args = t == Token::Unit;
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
self.parse_fn_call(input, state, lib, name, no_args, false, ns, settings)?
|
self.parse_fn_call(input, state, lib, settings, name, no_args, false, ns)?
|
||||||
}
|
}
|
||||||
// module access
|
// module access
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -1786,7 +1780,7 @@ impl Engine {
|
|||||||
_ => unreachable!("`[` or `?[`"),
|
_ => unreachable!("`[` or `?[`"),
|
||||||
};
|
};
|
||||||
let settings = settings.level_up()?;
|
let settings = settings.level_up()?;
|
||||||
self.parse_index_chain(input, state, lib, expr, opt, true, settings)?
|
self.parse_index_chain(input, state, lib, settings, expr, opt, true)?
|
||||||
}
|
}
|
||||||
// Property access
|
// Property access
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -1807,7 +1801,7 @@ impl Engine {
|
|||||||
(.., pos) => return Err(PERR::PropertyExpected.into_err(*pos)),
|
(.., pos) => return Err(PERR::PropertyExpected.into_err(*pos)),
|
||||||
}
|
}
|
||||||
|
|
||||||
let rhs = self.parse_primary(input, state, lib, true, settings.level_up()?)?;
|
let rhs = self.parse_primary(input, state, lib, settings.level_up()?, true)?;
|
||||||
let op_flags = match op {
|
let op_flags = match op {
|
||||||
Token::Period => ASTFlags::NONE,
|
Token::Period => ASTFlags::NONE,
|
||||||
Token::Elvis => ASTFlags::NEGATED,
|
Token::Elvis => ASTFlags::NEGATED,
|
||||||
@ -1984,7 +1978,7 @@ impl Engine {
|
|||||||
// <EOF>
|
// <EOF>
|
||||||
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
// All other tokens
|
// All other tokens
|
||||||
_ => self.parse_primary(input, state, lib, false, settings),
|
_ => self.parse_primary(input, state, lib, settings, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2234,9 +2228,9 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
|
settings: ParseSettings,
|
||||||
parent_precedence: Option<Precedence>,
|
parent_precedence: Option<Precedence>,
|
||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
settings: ParseSettings,
|
|
||||||
) -> ParseResult<Expr> {
|
) -> ParseResult<Expr> {
|
||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
settings.pos = lhs.position();
|
settings.pos = lhs.position();
|
||||||
@ -2294,7 +2288,7 @@ impl Engine {
|
|||||||
// If same precedence, then check if the operator binds right
|
// If same precedence, then check if the operator binds right
|
||||||
let rhs =
|
let rhs =
|
||||||
if (precedence == next_precedence && bind_right) || precedence < next_precedence {
|
if (precedence == next_precedence && bind_right) || precedence < next_precedence {
|
||||||
self.parse_binary_op(input, state, lib, precedence, rhs, settings)?
|
self.parse_binary_op(input, state, lib, settings, precedence, rhs)?
|
||||||
} else {
|
} else {
|
||||||
// Otherwise bind to left (even if next operator has the same precedence)
|
// Otherwise bind to left (even if next operator has the same precedence)
|
||||||
rhs
|
rhs
|
||||||
@ -2629,7 +2623,7 @@ impl Engine {
|
|||||||
let precedence = Precedence::new(1);
|
let precedence = Precedence::new(1);
|
||||||
let settings = settings.level_up()?;
|
let settings = settings.level_up()?;
|
||||||
let lhs = self.parse_unary(input, state, lib, settings)?;
|
let lhs = self.parse_unary(input, state, lib, settings)?;
|
||||||
self.parse_binary_op(input, state, lib, precedence, lhs, settings)
|
self.parse_binary_op(input, state, lib, settings, precedence, lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an if statement.
|
/// Parse an if statement.
|
||||||
@ -2863,9 +2857,9 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
|
settings: ParseSettings,
|
||||||
access: AccessMode,
|
access: AccessMode,
|
||||||
is_export: bool,
|
is_export: bool,
|
||||||
settings: ParseSettings,
|
|
||||||
) -> ParseResult<Stmt> {
|
) -> ParseResult<Stmt> {
|
||||||
// let/const... (specified in `var_type`)
|
// let/const... (specified in `var_type`)
|
||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
@ -3016,7 +3010,7 @@ impl Engine {
|
|||||||
let pos = *pos;
|
let pos = *pos;
|
||||||
let settings = settings.level_up()?;
|
let settings = settings.level_up()?;
|
||||||
let mut stmt =
|
let mut stmt =
|
||||||
self.parse_let(input, state, lib, AccessMode::ReadWrite, true, settings)?;
|
self.parse_let(input, state, lib, settings, AccessMode::ReadWrite, true)?;
|
||||||
stmt.set_position(pos);
|
stmt.set_position(pos);
|
||||||
return Ok(stmt);
|
return Ok(stmt);
|
||||||
}
|
}
|
||||||
@ -3024,7 +3018,7 @@ impl Engine {
|
|||||||
let pos = *pos;
|
let pos = *pos;
|
||||||
let settings = settings.level_up()?;
|
let settings = settings.level_up()?;
|
||||||
let mut stmt =
|
let mut stmt =
|
||||||
self.parse_let(input, state, lib, AccessMode::ReadOnly, true, settings)?;
|
self.parse_let(input, state, lib, settings, AccessMode::ReadOnly, true)?;
|
||||||
stmt.set_position(pos);
|
stmt.set_position(pos);
|
||||||
return Ok(stmt);
|
return Ok(stmt);
|
||||||
}
|
}
|
||||||
@ -3344,8 +3338,8 @@ impl Engine {
|
|||||||
input,
|
input,
|
||||||
new_state,
|
new_state,
|
||||||
lib,
|
lib,
|
||||||
access,
|
|
||||||
new_settings,
|
new_settings,
|
||||||
|
access,
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
comments,
|
comments,
|
||||||
)?;
|
)?;
|
||||||
@ -3455,9 +3449,9 @@ impl Engine {
|
|||||||
|
|
||||||
Token::Try => self.parse_try_catch(input, state, lib, settings.level_up()?),
|
Token::Try => self.parse_try_catch(input, state, lib, settings.level_up()?),
|
||||||
|
|
||||||
Token::Let => self.parse_let(input, state, lib, ReadWrite, false, settings.level_up()?),
|
Token::Let => self.parse_let(input, state, lib, settings.level_up()?, ReadWrite, false),
|
||||||
Token::Const => {
|
Token::Const => {
|
||||||
self.parse_let(input, state, lib, ReadOnly, false, settings.level_up()?)
|
self.parse_let(input, state, lib, settings.level_up()?, ReadOnly, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -3555,8 +3549,8 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
access: crate::FnAccess,
|
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
|
access: crate::FnAccess,
|
||||||
#[cfg(feature = "metadata")] comments: impl IntoIterator<Item = Identifier>,
|
#[cfg(feature = "metadata")] comments: impl IntoIterator<Item = Identifier>,
|
||||||
) -> ParseResult<ScriptFnDef> {
|
) -> ParseResult<ScriptFnDef> {
|
||||||
let settings = settings.level_up()?;
|
let settings = settings.level_up()?;
|
||||||
@ -3712,9 +3706,9 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
_parent: &mut ParseState,
|
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
|
_parent: &mut ParseState,
|
||||||
) -> ParseResult<(Expr, Shared<ScriptFnDef>)> {
|
) -> ParseResult<(Expr, Shared<ScriptFnDef>)> {
|
||||||
let settings = settings.level_up()?;
|
let settings = settings.level_up()?;
|
||||||
let mut params_list = StaticVec::<ImmutableString>::new_const();
|
let mut params_list = StaticVec::<ImmutableString>::new_const();
|
||||||
|
@ -371,6 +371,7 @@ impl FnPtr {
|
|||||||
/// of arguments to call it directly (one version attaches extra arguments).
|
/// of arguments to call it directly (one version attaches extra arguments).
|
||||||
#[cfg(not(feature = "internals"))]
|
#[cfg(not(feature = "internals"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) fn call_raw_with_extra_args<const N: usize, const E: usize>(
|
pub(crate) fn call_raw_with_extra_args<const N: usize, const E: usize>(
|
||||||
&self,
|
&self,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
@ -112,20 +112,22 @@ impl StringsInterner {
|
|||||||
// We leave at least two entries, one for the empty string, and one for the string
|
// We leave at least two entries, one for the empty string, and one for the string
|
||||||
// that has just been inserted.
|
// that has just been inserted.
|
||||||
while self.cache.len() > MAX_INTERNED_STRINGS - 3 {
|
while self.cache.len() > MAX_INTERNED_STRINGS - 3 {
|
||||||
let (_, _, n) = self
|
let mut max_len = 0;
|
||||||
.cache
|
let mut min_count = usize::MAX;
|
||||||
.iter()
|
let mut index = 0;
|
||||||
.fold((0, usize::MAX, 0), |(x, c, n), (&k, v)| {
|
|
||||||
if k != skip_hash
|
|
||||||
&& (v.strong_count() < c || (v.strong_count() == c && v.len() > x))
|
|
||||||
{
|
|
||||||
(v.len(), v.strong_count(), k)
|
|
||||||
} else {
|
|
||||||
(x, c, n)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.cache.remove(&n);
|
for (&k, v) in &self.cache {
|
||||||
|
if k != skip_hash
|
||||||
|
&& (v.strong_count() < min_count
|
||||||
|
|| (v.strong_count() == min_count && v.len() > max_len))
|
||||||
|
{
|
||||||
|
max_len = v.len();
|
||||||
|
min_count = v.strong_count();
|
||||||
|
index = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cache.remove(&index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user