Disable on_progress with unchecked.
This commit is contained in:
parent
ed18b3f32a
commit
a5d4a0abb9
@ -17,6 +17,7 @@ Breaking changes
|
|||||||
|
|
||||||
* `Dynamic::is_shared` and `Dynamic::is_locked` are removed under the `no_closure` feature. They used to always return `false`.
|
* `Dynamic::is_shared` and `Dynamic::is_locked` are removed under the `no_closure` feature. They used to always return `false`.
|
||||||
* `Engine::call_fn` now evaluates the `AST` before calling the function.
|
* `Engine::call_fn` now evaluates the `AST` before calling the function.
|
||||||
|
* `Engine::on_progress` is disabled with `unchecked`.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt};
|
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt};
|
||||||
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
||||||
use crate::fn_native::{
|
use crate::fn_native::{
|
||||||
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnProgressCallback,
|
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnVarCallback,
|
||||||
OnVarCallback,
|
|
||||||
};
|
};
|
||||||
use crate::module::NamespaceRef;
|
use crate::module::NamespaceRef;
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
@ -775,7 +774,8 @@ pub struct Engine {
|
|||||||
/// Callback closure for implementing the `debug` command.
|
/// Callback closure for implementing the `debug` command.
|
||||||
pub(crate) debug: OnDebugCallback,
|
pub(crate) debug: OnDebugCallback,
|
||||||
/// Callback closure for progress reporting.
|
/// Callback closure for progress reporting.
|
||||||
pub(crate) progress: Option<OnProgressCallback>,
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
pub(crate) progress: Option<crate::fn_native::OnProgressCallback>,
|
||||||
|
|
||||||
/// Optimize the AST after compilation.
|
/// Optimize the AST after compilation.
|
||||||
pub(crate) optimization_level: OptimizationLevel,
|
pub(crate) optimization_level: OptimizationLevel,
|
||||||
@ -879,6 +879,7 @@ impl Engine {
|
|||||||
debug: Box::new(default_debug),
|
debug: Box::new(default_debug),
|
||||||
|
|
||||||
// progress callback
|
// progress callback
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
progress: None,
|
progress: None,
|
||||||
|
|
||||||
// optimization level
|
// optimization level
|
||||||
@ -939,6 +940,8 @@ impl Engine {
|
|||||||
|
|
||||||
print: Box::new(|_| {}),
|
print: Box::new(|_| {}),
|
||||||
debug: Box::new(|_, _, _| {}),
|
debug: Box::new(|_, _, _| {}),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
progress: None,
|
progress: None,
|
||||||
|
|
||||||
optimization_level: if cfg!(feature = "no_optimize") {
|
optimization_level: if cfg!(feature = "no_optimize") {
|
||||||
@ -1459,8 +1462,9 @@ impl Engine {
|
|||||||
|
|
||||||
match lhs {
|
match lhs {
|
||||||
// id.??? or id[???]
|
// id.??? or id[???]
|
||||||
Expr::Variable(_, var_pos, x) => {
|
Expr::Variable(_, _var_pos, x) => {
|
||||||
self.inc_operations(state, *var_pos)?;
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(state, *_var_pos)?;
|
||||||
|
|
||||||
let (target, pos) =
|
let (target, pos) =
|
||||||
self.search_namespace(scope, mods, state, lib, this_ptr, lhs)?;
|
self.search_namespace(scope, mods, state, lib, this_ptr, lhs)?;
|
||||||
@ -1511,6 +1515,7 @@ impl Engine {
|
|||||||
size: usize,
|
size: usize,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, expr.position())?;
|
self.inc_operations(state, expr.position())?;
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
@ -1620,6 +1625,7 @@ impl Engine {
|
|||||||
_indexers: bool,
|
_indexers: bool,
|
||||||
_level: usize,
|
_level: usize,
|
||||||
) -> Result<Target<'t>, Box<EvalAltResult>> {
|
) -> Result<Target<'t>, Box<EvalAltResult>> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, Position::NONE)?;
|
self.inc_operations(state, Position::NONE)?;
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
@ -1654,18 +1660,15 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
let arr_idx = if index < 0 {
|
let arr_idx = if index < 0 {
|
||||||
|
// Count from end if negative
|
||||||
arr_len - index.abs() as usize
|
arr_len - index.abs() as usize
|
||||||
} else {
|
} else {
|
||||||
index as usize
|
index as usize
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
arr.get_mut(arr_idx)
|
||||||
return arr.get_mut(arr_idx).map(Target::from).ok_or_else(|| {
|
.map(Target::from)
|
||||||
EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into()
|
.ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into())
|
||||||
});
|
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
|
||||||
return Ok(Target::from(&mut arr[arr_idx]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -1679,26 +1682,26 @@ impl Engine {
|
|||||||
map.insert(index.clone().into(), Default::default());
|
map.insert(index.clone().into(), Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(map
|
Ok(map
|
||||||
.get_mut(index.as_str())
|
.get_mut(index.as_str())
|
||||||
.map(Target::from)
|
.map(Target::from)
|
||||||
.unwrap_or_else(|| Target::from(())));
|
.unwrap_or_else(|| Target::from(Dynamic::UNIT)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Str(s, _)) => {
|
Dynamic(Union::Str(s, _)) => {
|
||||||
// val_string[idx]
|
// val_string[idx]
|
||||||
let _chars_len = s.chars().count();
|
|
||||||
let index = _idx
|
let index = _idx
|
||||||
.as_int()
|
.as_int()
|
||||||
.map_err(|err| self.make_type_mismatch_err::<crate::INT>(err, idx_pos))?;
|
.map_err(|err| self.make_type_mismatch_err::<crate::INT>(err, idx_pos))?;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
let (ch, offset) = if index >= 0 {
|
let (ch, offset) = if index >= 0 {
|
||||||
|
// Count from end if negative
|
||||||
let offset = index as usize;
|
let offset = index as usize;
|
||||||
(
|
(
|
||||||
s.chars().nth(offset).ok_or_else(|| {
|
s.chars().nth(offset).ok_or_else(|| {
|
||||||
EvalAltResult::ErrorStringBounds(_chars_len, index, idx_pos)
|
let chars_len = s.chars().count();
|
||||||
|
EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos)
|
||||||
})?,
|
})?,
|
||||||
offset,
|
offset,
|
||||||
)
|
)
|
||||||
@ -1706,24 +1709,17 @@ impl Engine {
|
|||||||
let offset = index as usize;
|
let offset = index as usize;
|
||||||
(
|
(
|
||||||
s.chars().rev().nth(offset - 1).ok_or_else(|| {
|
s.chars().rev().nth(offset - 1).ok_or_else(|| {
|
||||||
EvalAltResult::ErrorStringBounds(_chars_len, index, idx_pos)
|
let chars_len = s.chars().count();
|
||||||
|
EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos)
|
||||||
})?,
|
})?,
|
||||||
offset,
|
offset,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return EvalAltResult::ErrorStringBounds(_chars_len, index, idx_pos).into();
|
let chars_len = s.chars().count();
|
||||||
|
return EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos).into();
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
Ok(Target::StringChar(target, offset, ch.into()))
|
||||||
let (ch, offset) = if index >= 0 {
|
|
||||||
let offset = index as usize;
|
|
||||||
(s.chars().nth(offset).unwrap(), offset)
|
|
||||||
} else {
|
|
||||||
let offset = index.abs() as usize;
|
|
||||||
(s.chars().rev().nth(offset - 1).unwrap(), offset)
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok(Target::StringChar(target, offset, ch.into()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -1733,32 +1729,27 @@ impl Engine {
|
|||||||
let hash_get =
|
let hash_get =
|
||||||
FnCallHashes::from_native(calc_fn_hash(std::iter::empty(), FN_IDX_GET, 2));
|
FnCallHashes::from_native(calc_fn_hash(std::iter::empty(), FN_IDX_GET, 2));
|
||||||
|
|
||||||
return self
|
self.exec_fn_call(
|
||||||
.exec_fn_call(
|
_mods, state, _lib, FN_IDX_GET, hash_get, args, _is_ref, true, idx_pos, None,
|
||||||
_mods, state, _lib, FN_IDX_GET, hash_get, args, _is_ref, true, idx_pos,
|
_level,
|
||||||
None, _level,
|
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v.into())
|
.map(|(v, _)| v.into())
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.ends_with(']') => {
|
||||||
if fn_sig.ends_with(']') =>
|
|
||||||
{
|
|
||||||
Box::new(EvalAltResult::ErrorIndexingType(
|
Box::new(EvalAltResult::ErrorIndexingType(
|
||||||
type_name.into(),
|
type_name.into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => err,
|
_ => err,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => EvalAltResult::ErrorIndexingType(
|
||||||
return EvalAltResult::ErrorIndexingType(
|
|
||||||
self.map_type_name(target.type_name()).into(),
|
self.map_type_name(target.type_name()).into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into()
|
.into(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1773,6 +1764,7 @@ impl Engine {
|
|||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, expr.position())?;
|
self.inc_operations(state, expr.position())?;
|
||||||
|
|
||||||
let result = match expr {
|
let result = match expr {
|
||||||
@ -2110,6 +2102,7 @@ impl Engine {
|
|||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, stmt.position())?;
|
self.inc_operations(state, stmt.position())?;
|
||||||
|
|
||||||
let result = match stmt {
|
let result = match stmt {
|
||||||
@ -2138,6 +2131,7 @@ impl Engine {
|
|||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, pos)?;
|
self.inc_operations(state, pos)?;
|
||||||
|
|
||||||
if lhs_ptr.is_read_only() {
|
if lhs_ptr.is_read_only() {
|
||||||
@ -2332,7 +2326,6 @@ impl Engine {
|
|||||||
// For loop
|
// For loop
|
||||||
Stmt::For(expr, x, _) => {
|
Stmt::For(expr, x, _) => {
|
||||||
let (Ident { name, .. }, statements) = x.as_ref();
|
let (Ident { name, .. }, statements) = x.as_ref();
|
||||||
let pos = statements.position();
|
|
||||||
let iter_obj = self
|
let iter_obj = self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.flatten();
|
.flatten();
|
||||||
@ -2386,7 +2379,8 @@ impl Engine {
|
|||||||
*loop_var = value;
|
*loop_var = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inc_operations(state, pos)?;
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(state, statements.position())?;
|
||||||
|
|
||||||
if statements.is_empty() {
|
if statements.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@ -2828,6 +2822,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the number of operations stay within limit.
|
/// Check if the number of operations stay within limit.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn inc_operations(
|
pub(crate) fn inc_operations(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
@ -2835,7 +2830,6 @@ impl Engine {
|
|||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
state.operations += 1;
|
state.operations += 1;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
// Guard against too many operations
|
// Guard against too many operations
|
||||||
if self.max_operations() > 0 && state.operations > self.max_operations() {
|
if self.max_operations() > 0 && state.operations > self.max_operations() {
|
||||||
return EvalAltResult::ErrorTooManyOperations(pos).into();
|
return EvalAltResult::ErrorTooManyOperations(pos).into();
|
||||||
|
@ -2105,6 +2105,7 @@ impl Engine {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn on_progress(
|
pub fn on_progress(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -294,6 +294,7 @@ impl Engine {
|
|||||||
is_op_assignment: bool,
|
is_op_assignment: bool,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, pos)?;
|
self.inc_operations(state, pos)?;
|
||||||
|
|
||||||
let state_source = state.source.clone();
|
let state_source = state.source.clone();
|
||||||
@ -483,6 +484,7 @@ impl Engine {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, pos)?;
|
self.inc_operations(state, pos)?;
|
||||||
|
|
||||||
if fn_def.body.is_empty() {
|
if fn_def.body.is_empty() {
|
||||||
@ -844,10 +846,11 @@ impl Engine {
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
script: &str,
|
script: &str,
|
||||||
pos: Position,
|
_pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
self.inc_operations(state, pos)?;
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(state, _pos)?;
|
||||||
|
|
||||||
let script = script.trim();
|
let script = script.trim();
|
||||||
if script.is_empty() {
|
if script.is_empty() {
|
||||||
@ -1305,14 +1308,15 @@ impl Engine {
|
|||||||
.chain(constant_args.iter().map(|(v, _)| Ok(v.clone())))
|
.chain(constant_args.iter().map(|(v, _)| Ok(v.clone())))
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
let (mut target, pos) =
|
let (mut target, _pos) =
|
||||||
self.search_namespace(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
self.search_namespace(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
||||||
|
|
||||||
if target.as_ref().is_read_only() {
|
if target.as_ref().is_read_only() {
|
||||||
target = target.into_owned();
|
target = target.into_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inc_operations(state, pos)?;
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(state, _pos)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let target_is_shared = target.is_shared();
|
let target_is_shared = target.is_shared();
|
||||||
@ -1396,10 +1400,11 @@ impl Engine {
|
|||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
// Get target reference to first argument
|
// Get target reference to first argument
|
||||||
let (target, pos) =
|
let (target, _pos) =
|
||||||
self.search_scope_only(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
self.search_scope_only(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
||||||
|
|
||||||
self.inc_operations(state, pos)?;
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(state, _pos)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let target_is_shared = target.is_shared();
|
let target_is_shared = target.is_shared();
|
||||||
@ -1439,6 +1444,7 @@ impl Engine {
|
|||||||
let func = match module.get_qualified_fn(hash) {
|
let func = match module.get_qualified_fn(hash) {
|
||||||
// Then search in Rust functions
|
// Then search in Rust functions
|
||||||
None => {
|
None => {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, pos)?;
|
self.inc_operations(state, pos)?;
|
||||||
|
|
||||||
let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id()));
|
let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id()));
|
||||||
|
@ -418,9 +418,11 @@ pub type FnPlugin = dyn PluginFunction;
|
|||||||
pub type FnPlugin = dyn PluginFunction + Send + Sync;
|
pub type FnPlugin = dyn PluginFunction + Send + Sync;
|
||||||
|
|
||||||
/// A standard callback function for progress reporting.
|
/// A standard callback function for progress reporting.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub type OnProgressCallback = Box<dyn Fn(u64) -> Option<Dynamic> + 'static>;
|
pub type OnProgressCallback = Box<dyn Fn(u64) -> Option<Dynamic> + 'static>;
|
||||||
/// A standard callback function for progress reporting.
|
/// A standard callback function for progress reporting.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub type OnProgressCallback = Box<dyn Fn(u64) -> Option<Dynamic> + Send + Sync + 'static>;
|
pub type OnProgressCallback = Box<dyn Fn(u64) -> Option<Dynamic> + Send + Sync + 'static>;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user