Disable on_progress with unchecked.

This commit is contained in:
Stephen Chung 2021-04-25 15:27:58 +08:00
parent ed18b3f32a
commit a5d4a0abb9
5 changed files with 66 additions and 62 deletions

View File

@ -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
------------ ------------

View File

@ -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, _) if fn_sig.ends_with(']') => {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) Box::new(EvalAltResult::ErrorIndexingType(
if fn_sig.ends_with(']') => type_name.into(),
{ Position::NONE,
Box::new(EvalAltResult::ErrorIndexingType( ))
type_name.into(), }
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();

View File

@ -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,

View File

@ -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()));

View File

@ -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>;