Merge pull request #440 from schungx/master

Minor refinements.
This commit is contained in:
Stephen Chung 2021-08-30 12:23:40 +08:00 committed by GitHub
commit bb28ec03a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 379 additions and 396 deletions

View File

@ -25,6 +25,7 @@ Enhancements
* `Scope::set_value` now takes anything that implements `Into<Cow<str>>`. * `Scope::set_value` now takes anything that implements `Into<Cow<str>>`.
* Added `Scope::is_constant` to check if a variable is constant. * Added `Scope::is_constant` to check if a variable is constant.
* Added `Scope::set_or_push` to add a new variable only if one doesn't already exist. * Added `Scope::set_or_push` to add a new variable only if one doesn't already exist.
* `Engine::register_type_XXX` are now available even under `no_object`.
Version 1.0.2 Version 1.0.2

View File

@ -20,12 +20,12 @@ Rhai is an embedded scripting language and evaluation engine for Rust that gives
to add scripting to any application. to add scripting to any application.
Supported targets and builds Targets and builds
--------------------------- ------------------
* All common CPU targets for Windows, Linux and MacOS. * All CPU and O/S targets supported by Rust, including:
* WebAssembly (WASM) * WebAssembly (WASM)
* `no-std` * `no-std`
* Minimum Rust version 1.49 * Minimum Rust version 1.49

View File

@ -5,7 +5,7 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
| |
note: required by a bound in `rhai::Dynamic::from` note: required by a bound in `rhai::Dynamic::from`
--> $DIR/dynamic.rs:1127:30 --> $DIR/dynamic.rs:1121:30
| |
1127 | pub fn from<T: Variant + Clone>(mut value: T) -> Self { 1121 | pub fn from<T: Variant + Clone>(mut value: T) -> Self {
| ^^^^^ required by this bound in `rhai::Dynamic::from` | ^^^^^ required by this bound in `rhai::Dynamic::from`

View File

@ -5,7 +5,7 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
| |
note: required by a bound in `rhai::Dynamic::from` note: required by a bound in `rhai::Dynamic::from`
--> $DIR/dynamic.rs:1127:30 --> $DIR/dynamic.rs:1121:30
| |
1127 | pub fn from<T: Variant + Clone>(mut value: T) -> Self { 1121 | pub fn from<T: Variant + Clone>(mut value: T) -> Self {
| ^^^^^ required by this bound in `rhai::Dynamic::from` | ^^^^^ required by this bound in `rhai::Dynamic::from`

View File

@ -1490,8 +1490,7 @@ impl Stmt {
_ => (), _ => (),
} }
path.pop() path.pop().expect("`path` contains current node");
.expect("never fails because `path` always contains the current node");
true true
} }
@ -1566,7 +1565,7 @@ impl OpAssignment<'_> {
pub fn new(op: Token) -> Self { pub fn new(op: Token) -> Self {
let op_raw = op let op_raw = op
.map_op_assignment() .map_op_assignment()
.expect("never fails because token must be an op-assignment operator") .expect("token is op-assignment operator")
.literal_syntax(); .literal_syntax();
let op_assignment = op.literal_syntax(); let op_assignment = op.literal_syntax();
@ -2018,7 +2017,7 @@ impl Expr {
let mut arr = Array::with_capacity(x.len()); let mut arr = Array::with_capacity(x.len());
arr.extend(x.iter().map(|v| { arr.extend(x.iter().map(|v| {
v.get_literal_value() v.get_literal_value()
.expect("never fails because a constant array always has a constant value") .expect("constant array has constant value")
})); }));
Dynamic::from_array(arr) Dynamic::from_array(arr)
} }
@ -2028,9 +2027,9 @@ impl Expr {
let mut map = x.1.clone(); let mut map = x.1.clone();
x.0.iter().for_each(|(k, v)| { x.0.iter().for_each(|(k, v)| {
*map.get_mut(k.name.as_str()) *map.get_mut(k.name.as_str())
.expect("never fails because the template should contain all the keys") = v .expect("template contains all keys") = v
.get_literal_value() .get_literal_value()
.expect("never fails because a constant map always has a constant value") .expect("constant map has constant value")
}); });
Dynamic::from_map(map) Dynamic::from_map(map)
} }
@ -2309,8 +2308,7 @@ impl Expr {
_ => (), _ => (),
} }
path.pop() path.pop().expect("`path` contains current node");
.expect("never fails because `path` always contains the current node");
true true
} }

View File

@ -154,8 +154,8 @@ impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
/// Definition of a custom syntax definition. /// Definition of a custom syntax definition.
pub struct CustomSyntax { pub struct CustomSyntax {
/// A parsing function to return the next keyword in a custom syntax based on the /// A parsing function to return the next token in a custom syntax based on the
/// keywords parsed so far. /// symbols parsed so far.
pub parse: Box<FnCustomSyntaxParse>, pub parse: Box<FnCustomSyntaxParse>,
/// Custom syntax implementation function. /// Custom syntax implementation function.
pub func: Shared<FnCustomSyntaxEval>, pub func: Shared<FnCustomSyntaxEval>,
@ -166,10 +166,17 @@ pub struct CustomSyntax {
impl Engine { impl Engine {
/// Register a custom syntax with the [`Engine`]. /// Register a custom syntax with the [`Engine`].
/// ///
/// * `keywords` holds a slice of strings that define the custom syntax. /// * `symbols` holds a slice of strings that define the custom syntax.
/// * `scope_may_be_changed` specifies variables _may_ be added/removed by this custom syntax. /// * `scope_may_be_changed` specifies variables _may_ be added/removed by this custom syntax.
/// * `func` is the implementation function. /// * `func` is the implementation function.
/// ///
/// ## Note on `symbols`
///
/// * Whitespaces around symbols are stripped.
/// * Symbols that are all-whitespace or empty are ignored.
/// * If `symbols` does not contain at least one valid token, then the custom syntax registration
/// is simply ignored.
///
/// ## Note on `scope_may_be_changed` /// ## Note on `scope_may_be_changed`
/// ///
/// If `scope_may_be_changed` is `true`, then _size_ of the current [`Scope`][crate::Scope] /// If `scope_may_be_changed` is `true`, then _size_ of the current [`Scope`][crate::Scope]
@ -185,7 +192,7 @@ impl Engine {
/// does NOT count, so `false` should be passed. /// does NOT count, so `false` should be passed.
pub fn register_custom_syntax<S: AsRef<str> + Into<Identifier>>( pub fn register_custom_syntax<S: AsRef<str> + Into<Identifier>>(
&mut self, &mut self,
keywords: &[S], symbols: &[S],
scope_may_be_changed: bool, scope_may_be_changed: bool,
func: impl Fn(&mut EvalContext, &[Expression]) -> RhaiResult + SendSync + 'static, func: impl Fn(&mut EvalContext, &[Expression]) -> RhaiResult + SendSync + 'static,
) -> Result<&mut Self, ParseError> { ) -> Result<&mut Self, ParseError> {
@ -193,10 +200,10 @@ impl Engine {
let mut segments: StaticVec<ImmutableString> = Default::default(); let mut segments: StaticVec<ImmutableString> = Default::default();
for s in keywords { for s in symbols {
let s = s.as_ref().trim(); let s = s.as_ref().trim();
// Skip empty keywords // Skip empty symbols
if s.is_empty() { if s.is_empty() {
continue; continue;
} }
@ -220,10 +227,10 @@ impl Engine {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
CUSTOM_SYNTAX_MARKER_FLOAT if !segments.is_empty() => s.into(), CUSTOM_SYNTAX_MARKER_FLOAT if !segments.is_empty() => s.into(),
// Standard or reserved keyword/symbol not in first position // Standard or reserved keyword/symbol not in first position
s if !segments.is_empty() && token.is_some() => { _ if !segments.is_empty() && token.is_some() => {
// Make it a custom keyword/symbol if it is disabled or reserved // Make it a custom keyword/symbol if it is disabled or reserved
if (self.disabled_symbols.contains(s) if (self.disabled_symbols.contains(s)
|| matches!(token, Some(Token::Reserved(_)))) || token.map_or(false, |v| v.is_reserved()))
&& !self.custom_keywords.contains_key(s) && !self.custom_keywords.contains_key(s)
{ {
self.custom_keywords.insert(s.into(), None); self.custom_keywords.insert(s.into(), None);
@ -273,7 +280,7 @@ impl Engine {
segments.push(seg); segments.push(seg);
} }
// If the syntax has no keywords, just ignore the registration // If the syntax has no symbols, just ignore the registration
if segments.is_empty() { if segments.is_empty() {
return Ok(self); return Ok(self);
} }
@ -307,8 +314,8 @@ impl Engine {
/// * `parse` is the parsing function. /// * `parse` is the parsing function.
/// * `func` is the implementation function. /// * `func` is the implementation function.
/// ///
/// All custom keywords must be manually registered via [`Engine::register_custom_operator`]. /// All custom keywords used as symbols must be manually registered via [`Engine::register_custom_operator`].
/// Otherwise, custom keywords won't be recognized. /// Otherwise, they won't be recognized.
pub fn register_custom_syntax_raw( pub fn register_custom_syntax_raw(
&mut self, &mut self,
key: impl Into<Identifier>, key: impl Into<Identifier>,

View File

@ -34,8 +34,8 @@ use fmt::Debug;
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
use instant::Instant; use instant::Instant;
/// The message: never fails because the type was checked /// The message: data type was checked
const CHECKED: &str = "never fails because the type was checked"; const CHECKED: &str = "data type was checked";
mod private { mod private {
use crate::fn_native::SendSync; use crate::fn_native::SendSync;
@ -259,9 +259,7 @@ impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> {
match self.0 { match self.0 {
DynamicReadLockInner::Reference(ref reference) => *reference, DynamicReadLockInner::Reference(ref reference) => *reference,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
DynamicReadLockInner::Guard(ref guard) => guard.downcast_ref().expect( DynamicReadLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED),
"never fails because the read guard was created after checking the data type",
),
} }
} }
} }
@ -302,9 +300,7 @@ impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> {
match self.0 { match self.0 {
DynamicWriteLockInner::Reference(ref reference) => *reference, DynamicWriteLockInner::Reference(ref reference) => *reference,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().expect( DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED),
"never fails because the write guard was created after checking the data type",
),
} }
} }
} }
@ -315,9 +311,7 @@ impl<'d, T: Any + Clone> DerefMut for DynamicWriteLock<'d, T> {
match self.0 { match self.0 {
DynamicWriteLockInner::Reference(ref mut reference) => *reference, DynamicWriteLockInner::Reference(ref mut reference) => *reference,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().expect( DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().expect(CHECKED),
"never fails because the write guard was created after checking the data type",
),
} }
} }
} }
@ -1261,7 +1255,7 @@ impl Dynamic {
/// ///
/// let x = Dynamic::from(42_u32); /// let x = Dynamic::from(42_u32);
/// ///
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42); /// assert_eq!(x.try_cast::<u32>().expect("x should be u32"), 42);
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]

View File

@ -501,7 +501,7 @@ impl<'a> Target<'a> {
let value = &mut *value let value = &mut *value
.write_lock::<crate::INT>() .write_lock::<crate::INT>()
.expect("never fails because `BitField` always holds an `INT`"); .expect("`BitField` holds `INT`");
let index = *index; let index = *index;
@ -529,7 +529,7 @@ impl<'a> Target<'a> {
let s = &mut *s let s = &mut *s
.write_lock::<ImmutableString>() .write_lock::<ImmutableString>()
.expect("never fails because `StringChar` always holds an `ImmutableString`"); .expect("`StringChar` holds `ImmutableString`");
let index = *index; let index = *index;
@ -553,9 +553,7 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
// Cloning is cheap for a shared value // Cloning is cheap for a shared value
let container = value.clone(); let container = value.clone();
return Self::LockGuard(( return Self::LockGuard((
value value.write_lock::<Dynamic>().expect("cast to `Dynamic`"),
.write_lock::<Dynamic>()
.expect("never fails when casting to `Dynamic`"),
container, container,
)); ));
} }
@ -701,9 +699,9 @@ impl EvalState {
// Push a new function resolution cache if the stack is empty // Push a new function resolution cache if the stack is empty
self.fn_resolution_caches.push(Default::default()); self.fn_resolution_caches.push(Default::default());
} }
self.fn_resolution_caches.last_mut().expect( self.fn_resolution_caches
"never fails because there is at least one function resolution cache by this point", .last_mut()
) .expect("at least one function resolution cache")
} }
/// Push an empty function resolution cache onto the stack and make it current. /// Push an empty function resolution cache onto the stack and make it current.
#[allow(dead_code)] #[allow(dead_code)]
@ -720,7 +718,7 @@ impl EvalState {
pub fn pop_fn_resolution_cache(&mut self) { pub fn pop_fn_resolution_cache(&mut self) {
self.fn_resolution_caches self.fn_resolution_caches
.pop() .pop()
.expect("there should be at least one function resolution cache"); .expect("at least one function resolution cache");
} }
} }
@ -900,8 +898,6 @@ impl<'x, 'px, 'pt> EvalContext<'_, 'x, 'px, '_, '_, '_, '_, 'pt> {
/// # } /// # }
/// ``` /// ```
pub struct Engine { pub struct Engine {
/// A module containing all functions directly loaded into the Engine.
pub(crate) global_namespace: Module,
/// A collection of all modules loaded into the global namespace of the Engine. /// A collection of all modules loaded into the global namespace of the Engine.
pub(crate) global_modules: StaticVec<Shared<Module>>, pub(crate) global_modules: StaticVec<Shared<Module>>,
/// A collection of all sub-modules directly loaded into the Engine. /// A collection of all sub-modules directly loaded into the Engine.
@ -1036,7 +1032,6 @@ impl Engine {
#[must_use] #[must_use]
pub fn new_raw() -> Self { pub fn new_raw() -> Self {
let mut engine = Self { let mut engine = Self {
global_namespace: Default::default(),
global_modules: Default::default(), global_modules: Default::default(),
global_sub_modules: Default::default(), global_sub_modules: Default::default(),
@ -1063,7 +1058,10 @@ impl Engine {
limits: Default::default(), limits: Default::default(),
}; };
engine.global_namespace.internal = true; // Add the global namespace module
let mut global_namespace = Module::new();
global_namespace.internal = true;
engine.global_modules.push(global_namespace.into());
engine engine
} }
@ -1088,16 +1086,10 @@ impl Engine {
if let Some(index) = index { if let Some(index) = index {
let offset = mods.len() - index.get(); let offset = mods.len() - index.get();
Some( Some(mods.get(offset).expect("offset within range"))
mods.get(offset)
.expect("never fails because offset should be within range"),
)
} else { } else {
mods.find(root) mods.find(root)
.map(|n| { .map(|n| mods.get(n).expect("index is valid"))
mods.get(n)
.expect("never fails because the index came from `find`")
})
.or_else(|| self.global_sub_modules.get(root).cloned()) .or_else(|| self.global_sub_modules.get(root).cloned())
} }
} }
@ -1191,8 +1183,7 @@ impl Engine {
level: 0, level: 0,
}; };
match resolve_var( match resolve_var(
expr.get_variable_name(true) expr.get_variable_name(true).expect("`expr` is `Variable`"),
.expect("`expr` should be `Variable`"),
index, index,
&context, &context,
) { ) {
@ -1209,9 +1200,7 @@ impl Engine {
scope.len() - index scope.len() - index
} else { } else {
// Find the variable in the scope // Find the variable in the scope
let var_name = expr let var_name = expr.get_variable_name(true).expect("`expr` is `Variable`");
.get_variable_name(true)
.expect("`expr` should be `Variable`");
scope scope
.get_index(var_name) .get_index(var_name)
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(var_name.to_string(), var_pos))? .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(var_name.to_string(), var_pos))?
@ -1245,9 +1234,7 @@ impl Engine {
let _terminate_chaining = terminate_chaining; let _terminate_chaining = terminate_chaining;
// Pop the last index value // Pop the last index value
let idx_val = idx_values let idx_val = idx_values.pop().expect("index chain is never empty");
.pop()
.expect("never fails because an index chain is never empty");
match chain_type { match chain_type {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -1255,7 +1242,7 @@ impl Engine {
let pos = rhs.position(); let pos = rhs.position();
let idx_val = idx_val let idx_val = idx_val
.into_index_value() .into_index_value()
.expect("never fails because `chain_type` is `ChainType::Index`"); .expect("`chain_type` is `ChainType::Index`");
match rhs { match rhs {
// xxx[idx].expr... | xxx[idx][expr]... // xxx[idx].expr... | xxx[idx][expr]...
@ -1277,7 +1264,7 @@ impl Engine {
// xxx[rhs] op= new_val // xxx[rhs] op= new_val
_ if new_val.is_some() => { _ if new_val.is_some() => {
let ((new_val, new_pos), (op_info, op_pos)) = let ((new_val, new_pos), (op_info, op_pos)) =
new_val.expect("never fails because `new_val` is `Some`"); new_val.expect("`new_val` is `Some`");
let mut idx_val_for_setter = idx_val.clone(); let mut idx_val_for_setter = idx_val.clone();
let try_setter = match self.get_indexed_mut( let try_setter = match self.get_indexed_mut(
@ -1333,7 +1320,7 @@ impl Engine {
let FnCallExpr { name, hashes, .. } = x.as_ref(); let FnCallExpr { name, hashes, .. } = x.as_ref();
let call_args = &mut idx_val let call_args = &mut idx_val
.into_fn_call_args() .into_fn_call_args()
.expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`"); .expect("`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`");
self.make_method_call( self.make_method_call(
mods, state, lib, name, *hashes, target, call_args, *pos, level, mods, state, lib, name, *hashes, target, call_args, *pos, level,
) )
@ -1350,7 +1337,7 @@ impl Engine {
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => { Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
let (name, pos) = &x.2; let (name, pos) = &x.2;
let ((new_val, new_pos), (op_info, op_pos)) = let ((new_val, new_pos), (op_info, op_pos)) =
new_val.expect("never fails because `new_val` is `Some`"); new_val.expect("`new_val` is `Some`");
let index = name.into(); let index = name.into();
{ {
let val_target = &mut self.get_indexed_mut( let val_target = &mut self.get_indexed_mut(
@ -1378,7 +1365,7 @@ impl Engine {
Expr::Property(x) if new_val.is_some() => { Expr::Property(x) if new_val.is_some() => {
let ((getter, hash_get), (setter, hash_set), (name, pos)) = x.as_ref(); let ((getter, hash_get), (setter, hash_set), (name, pos)) = x.as_ref();
let ((mut new_val, new_pos), (op_info, op_pos)) = let ((mut new_val, new_pos), (op_info, op_pos)) =
new_val.expect("never fails because `new_val` is `Some`"); new_val.expect("`new_val` is `Some`");
if op_info.is_some() { if op_info.is_some() {
let hash = FnCallHashes::from_native(*hash_get); let hash = FnCallHashes::from_native(*hash_get);
@ -1498,9 +1485,9 @@ impl Engine {
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr // {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
Expr::FnCall(ref x, pos) if !x.is_qualified() => { Expr::FnCall(ref x, pos) if !x.is_qualified() => {
let FnCallExpr { name, hashes, .. } = x.as_ref(); let FnCallExpr { name, hashes, .. } = x.as_ref();
let call_args = &mut idx_val let call_args = &mut idx_val.into_fn_call_args().expect(
.into_fn_call_args() "`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`",
.expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`"); );
let (val, _) = self.make_method_call( let (val, _) = self.make_method_call(
mods, state, lib, name, *hashes, target, call_args, pos, level, mods, state, lib, name, *hashes, target, call_args, pos, level,
)?; )?;
@ -1620,9 +1607,9 @@ impl Engine {
Expr::FnCall(ref f, pos) if !f.is_qualified() => { Expr::FnCall(ref f, pos) if !f.is_qualified() => {
let FnCallExpr { name, hashes, .. } = f.as_ref(); let FnCallExpr { name, hashes, .. } = f.as_ref();
let rhs_chain = match_chaining_type(rhs); let rhs_chain = match_chaining_type(rhs);
let args = &mut idx_val let args = &mut idx_val.into_fn_call_args().expect(
.into_fn_call_args() "`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`",
.expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`"); );
let (mut val, _) = self.make_method_call( let (mut val, _) = self.make_method_call(
mods, state, lib, name, *hashes, target, args, pos, level, mods, state, lib, name, *hashes, target, args, pos, level,
)?; )?;
@ -2117,7 +2104,7 @@ impl Engine {
for (Ident { name: key, .. }, expr) in &x.0 { for (Ident { name: key, .. }, expr) in &x.0 {
let value_ref = map let value_ref = map
.get_mut(key.as_str()) .get_mut(key.as_str())
.expect("never fails because the template should contain all the keys"); .expect("template contains all keys");
*value_ref = self *value_ref = self
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
.flatten(); .flatten();
@ -2135,9 +2122,7 @@ impl Engine {
constants, constants,
.. ..
} = x.as_ref(); } = x.as_ref();
let namespace = namespace let namespace = namespace.as_ref().expect("qualified function call");
.as_ref()
.expect("never fails because function call is qualified");
let hash = hashes.native; let hash = hashes.native;
self.make_qualified_function_call( self.make_qualified_function_call(
scope, mods, state, lib, this_ptr, namespace, name, args, constants, hash, scope, mods, state, lib, this_ptr, namespace, name, args, constants, hash,
@ -2192,12 +2177,14 @@ impl Engine {
Expr::Custom(custom, _) => { Expr::Custom(custom, _) => {
let expressions: StaticVec<_> = custom.keywords.iter().map(Into::into).collect(); let expressions: StaticVec<_> = custom.keywords.iter().map(Into::into).collect();
let key_token = custom.tokens.first().expect( let key_token = custom
"never fails because a custom syntax stream must contain at least one token", .tokens
); .first()
.expect("custom syntax stream contains at least one token");
let custom_def = self let custom_def = self
.custom_syntax.get(key_token) .custom_syntax
.expect("never fails because the custom syntax leading token should match with definition"); .get(key_token)
.expect("custom syntax leading token matches with definition");
let mut context = EvalContext { let mut context = EvalContext {
engine: self, engine: self,
scope, scope,
@ -2329,9 +2316,7 @@ impl Engine {
let target_is_shared = false; let target_is_shared = false;
if target_is_shared { if target_is_shared {
lock_guard = target lock_guard = target.write_lock::<Dynamic>().expect("cast to `Dynamic`");
.write_lock::<Dynamic>()
.expect("never fails when casting to `Dynamic`");
lhs_ptr_inner = &mut *lock_guard; lhs_ptr_inner = &mut *lock_guard;
} else { } else {
lhs_ptr_inner = &mut *target; lhs_ptr_inner = &mut *target;
@ -2403,7 +2388,7 @@ impl Engine {
let var_name = lhs_expr let var_name = lhs_expr
.get_variable_name(false) .get_variable_name(false)
.expect("never fails because `lhs_ptr` is a `Variable`s"); .expect("`lhs_ptr` is `Variable`");
if !lhs_ptr.is_ref() { if !lhs_ptr.is_ref() {
return EvalAltResult::ErrorAssignmentToConstant(var_name.to_string(), pos) return EvalAltResult::ErrorAssignmentToConstant(var_name.to_string(), pos)
@ -2633,13 +2618,9 @@ impl Engine {
// 3) Imported modules - functions marked with global namespace // 3) Imported modules - functions marked with global namespace
// 4) Global sub-modules - functions marked with global namespace // 4) Global sub-modules - functions marked with global namespace
let func = self let func = self
.global_namespace .global_modules
.get_iter(iter_type) .iter()
.or_else(|| { .find_map(|m| m.get_iter(iter_type))
self.global_modules
.iter()
.find_map(|m| m.get_iter(iter_type))
})
.or_else(|| mods.get_iter(iter_type)) .or_else(|| mods.get_iter(iter_type))
.or_else(|| { .or_else(|| {
self.global_sub_modules self.global_sub_modules
@ -2667,10 +2648,7 @@ impl Engine {
if x > INT::MAX as usize { if x > INT::MAX as usize {
return EvalAltResult::ErrorArithmetic( return EvalAltResult::ErrorArithmetic(
format!("for-loop counter overflow: {}", x), format!("for-loop counter overflow: {}", x),
counter counter.as_ref().expect("`counter` is `Some`").pos,
.as_ref()
.expect("never fails because `counter` is `Some`")
.pos,
) )
.into(); .into();
} }
@ -2678,7 +2656,7 @@ impl Engine {
let mut counter_var = scope let mut counter_var = scope
.get_mut_by_index(c) .get_mut_by_index(c)
.write_lock::<INT>() .write_lock::<INT>()
.expect("never fails because the counter always holds an `INT`"); .expect("counter holds `INT`");
*counter_var = x as INT; *counter_var = x as INT;
} }
@ -2691,9 +2669,7 @@ impl Engine {
let loop_var_is_shared = false; let loop_var_is_shared = false;
if loop_var_is_shared { if loop_var_is_shared {
let mut value_ref = loop_var let mut value_ref = loop_var.write_lock().expect("cast to `Dynamic`");
.write_lock()
.expect("never fails when casting to `Dynamic`");
*value_ref = value; *value_ref = value;
} else { } else {
*loop_var = value; *loop_var = value;
@ -2744,9 +2720,7 @@ impl Engine {
constants, constants,
.. ..
} = x.as_ref(); } = x.as_ref();
let namespace = namespace let namespace = namespace.as_ref().expect("qualified function call");
.as_ref()
.expect("never fails because function call is qualified");
let hash = hashes.native; let hash = hashes.native;
self.make_qualified_function_call( self.make_qualified_function_call(
scope, mods, state, lib, this_ptr, namespace, name, args, constants, hash, scope, mods, state, lib, this_ptr, namespace, name, args, constants, hash,
@ -2805,11 +2779,16 @@ impl Engine {
if err_pos.is_none() { if err_pos.is_none() {
// No position info // No position info
} else { } else {
let line = err_pos.line().expect("never fails because a non-NONE `Position` always has a line number") as INT; let line = err_pos
.line()
.expect("non-NONE `Position` has line number")
as INT;
let position = if err_pos.is_beginning_of_line() { let position = if err_pos.is_beginning_of_line() {
0 0
} else { } else {
err_pos.position().expect("never fails because a non-NONE `Position` always has a character position") err_pos
.position()
.expect("non-NONE `Position` has character position")
} as INT; } as INT;
err_map.insert("line".into(), line.into()); err_map.insert("line".into(), line.into());
err_map.insert("position".into(), position.into()); err_map.insert("position".into(), position.into());
@ -2893,10 +2872,7 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
if entry_type == AccessMode::ReadOnly && lib.iter().any(|&m| !m.is_empty()) { if entry_type == AccessMode::ReadOnly && lib.iter().any(|&m| !m.is_empty()) {
let global = if let Some(index) = mods.find(KEYWORD_GLOBAL) { let global = if let Some(index) = mods.find(KEYWORD_GLOBAL) {
match mods match mods.get_mut(index).expect("index is valid") {
.get_mut(index)
.expect("never fails because the index came from `find`")
{
m if m.internal => Some(m), m if m.internal => Some(m),
_ => None, _ => None,
} }
@ -2905,15 +2881,12 @@ impl Engine {
let mut global = Module::new(); let mut global = Module::new();
global.internal = true; global.internal = true;
mods.push(KEYWORD_GLOBAL, global); mods.push(KEYWORD_GLOBAL, global);
Some( Some(mods.get_mut(mods.len() - 1).expect("global module exists"))
mods.get_mut(mods.len() - 1)
.expect("never fails because the global module was just added"),
)
}; };
if let Some(global) = global { if let Some(global) = global {
Shared::get_mut(global) Shared::get_mut(global)
.expect("never fails because the global module is never shared") .expect("global module is not shared")
.set_var(name.clone(), value.clone()); .set_var(name.clone(), value.clone());
} }
} }

View File

@ -21,8 +21,26 @@ use crate::Array;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::Map; use crate::Map;
/// Engine public API
impl Engine { impl Engine {
/// Get the global namespace module (which is the last module in `global_modules`).
#[inline(always)]
#[allow(dead_code)]
pub(crate) fn global_namespace(&self) -> &Module {
self.global_modules
.last()
.expect("global_modules contains at least one module")
}
/// Get a mutable reference to the global namespace module
/// (which is the last module in `global_modules`).
#[inline(always)]
pub(crate) fn global_namespace_mut(&mut self) -> &mut Module {
Shared::get_mut(
self.global_modules
.last_mut()
.expect("global_modules contains at least one module"),
)
.expect("global namespace module is never shared")
}
/// Register a custom function with the [`Engine`]. /// Register a custom function with the [`Engine`].
/// ///
/// # Example /// # Example
@ -75,7 +93,7 @@ impl Engine {
#[cfg(not(feature = "metadata"))] #[cfg(not(feature = "metadata"))]
let param_type_names: Option<[&str; 0]> = None; let param_type_names: Option<[&str; 0]> = None;
self.global_namespace.set_fn( self.global_namespace_mut().set_fn(
name, name,
FnNamespace::Global, FnNamespace::Global,
FnAccess::Public, FnAccess::Public,
@ -133,7 +151,7 @@ impl Engine {
#[cfg(not(feature = "metadata"))] #[cfg(not(feature = "metadata"))]
let param_type_names: Option<[&str; 0]> = None; let param_type_names: Option<[&str; 0]> = None;
self.global_namespace.set_fn( self.global_namespace_mut().set_fn(
name, name,
FnNamespace::Global, FnNamespace::Global,
FnAccess::Public, FnAccess::Public,
@ -172,7 +190,7 @@ impl Engine {
N: AsRef<str> + Into<Identifier>, N: AsRef<str> + Into<Identifier>,
T: Variant + Clone, T: Variant + Clone,
{ {
self.global_namespace.set_raw_fn( self.global_namespace_mut().set_raw_fn(
name, name,
FnNamespace::Global, FnNamespace::Global,
FnAccess::Public, FnAccess::Public,
@ -184,8 +202,6 @@ impl Engine {
/// Register a custom type for use with the [`Engine`]. /// Register a custom type for use with the [`Engine`].
/// The type must implement [`Clone`]. /// The type must implement [`Clone`].
/// ///
/// Not available under `no_object`.
///
/// # Example /// # Example
/// ///
/// ``` /// ```
@ -195,9 +211,8 @@ impl Engine {
/// } /// }
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { field: 1 } } /// fn new() -> Self { Self { field: 1 } }
/// /// fn update(&mut self, offset: i64) { self.field += offset; }
/// fn update(&mut self, offset: i64) { self.field += offset; }
/// } /// }
/// ///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> { /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
@ -212,6 +227,7 @@ impl Engine {
/// // Use `register_fn` to register methods on the type. /// // Use `register_fn` to register methods on the type.
/// .register_fn("update", TestStruct::update); /// .register_fn("update", TestStruct::update);
/// ///
/// # #[cfg(not(feature = "no_object"))]
/// assert_eq!( /// assert_eq!(
/// engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?, /// engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?,
/// TestStruct { field: 42 } /// TestStruct { field: 42 }
@ -219,7 +235,6 @@ impl Engine {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn register_type<T: Variant + Clone>(&mut self) -> &mut Self { pub fn register_type<T: Variant + Clone>(&mut self) -> &mut Self {
self.register_type_with_name::<T>(type_name::<T>()) self.register_type_with_name::<T>(type_name::<T>())
@ -227,8 +242,6 @@ impl Engine {
/// Register a custom type for use with the [`Engine`], with a pretty-print name /// Register a custom type for use with the [`Engine`], with a pretty-print name
/// for the `type_of` function. The type must implement [`Clone`]. /// for the `type_of` function. The type must implement [`Clone`].
/// ///
/// Not available under `no_object`.
///
/// # Example /// # Example
/// ///
/// ``` /// ```
@ -266,7 +279,6 @@ impl Engine {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self { pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
// Add the pretty-print type name into the map // Add the pretty-print type name into the map
@ -282,7 +294,7 @@ impl Engine {
T: Variant + Clone + IntoIterator, T: Variant + Clone + IntoIterator,
<T as IntoIterator>::Item: Variant + Clone, <T as IntoIterator>::Item: Variant + Clone,
{ {
self.global_namespace.set_iterable::<T>(); self.global_namespace_mut().set_iterable::<T>();
self self
} }
/// Register a getter function for a member of a registered type with the [`Engine`]. /// Register a getter function for a member of a registered type with the [`Engine`].
@ -300,8 +312,7 @@ impl Engine {
/// } /// }
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { field: 1 } } /// fn new() -> Self { Self { field: 1 } }
///
/// // Even a getter must start with `&mut self` and not `&self`. /// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self) -> i64 { self.field } /// fn get_field(&mut self) -> i64 { self.field }
/// } /// }
@ -349,7 +360,6 @@ impl Engine {
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { field: 1 } } /// fn new() -> Self { Self { field: 1 } }
///
/// // Even a getter must start with `&mut self` and not `&self`. /// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self) -> Result<i64, Box<EvalAltResult>> { /// fn get_field(&mut self) -> Result<i64, Box<EvalAltResult>> {
/// Ok(self.field) /// Ok(self.field)
@ -392,9 +402,8 @@ impl Engine {
/// } /// }
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { field: 1 } } /// fn new() -> Self { Self { field: 1 } }
/// /// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// } /// }
/// ///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> { /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
@ -442,7 +451,6 @@ impl Engine {
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { field: 1 } } /// fn new() -> Self { Self { field: 1 } }
///
/// fn set_field(&mut self, new_val: i64) -> Result<(), Box<EvalAltResult>> { /// fn set_field(&mut self, new_val: i64) -> Result<(), Box<EvalAltResult>> {
/// self.field = new_val; /// self.field = new_val;
/// Ok(()) /// Ok(())
@ -492,12 +500,10 @@ impl Engine {
/// } /// }
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { field: 1 } } /// fn new() -> Self { Self { field: 1 } }
///
/// // Even a getter must start with `&mut self` and not `&self`. /// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self) -> i64 { self.field } /// fn get_field(&mut self) -> i64 { self.field }
/// /// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// } /// }
/// ///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> { /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
@ -549,7 +555,6 @@ impl Engine {
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
///
/// // Even a getter must start with `&mut self` and not `&self`. /// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] } /// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
/// } /// }
@ -623,7 +628,6 @@ impl Engine {
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
///
/// // Even a getter must start with `&mut self` and not `&self`. /// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self, index: i64) -> Result<i64, Box<EvalAltResult>> { /// fn get_field(&mut self, index: i64) -> Result<i64, Box<EvalAltResult>> {
/// Ok(self.fields[index as usize]) /// Ok(self.fields[index as usize])
@ -697,7 +701,6 @@ impl Engine {
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
///
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; } /// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
/// } /// }
/// ///
@ -771,7 +774,6 @@ impl Engine {
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
///
/// fn set_field(&mut self, index: i64, value: i64) -> Result<(), Box<EvalAltResult>> { /// fn set_field(&mut self, index: i64, value: i64) -> Result<(), Box<EvalAltResult>> {
/// self.fields[index as usize] = value; /// self.fields[index as usize] = value;
/// Ok(()) /// Ok(())
@ -847,11 +849,9 @@ impl Engine {
/// } /// }
/// ///
/// impl TestStruct { /// impl TestStruct {
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } } /// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
///
/// // Even a getter must start with `&mut self` and not `&self`. /// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] } /// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
///
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; } /// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
/// } /// }
/// ///
@ -957,14 +957,8 @@ impl Engine {
} }
} else { } else {
let mut iter = name.as_ref().splitn(2, separator.as_ref()); let mut iter = name.as_ref().splitn(2, separator.as_ref());
let sub_module = iter let sub_module = iter.next().expect("name contains separator").trim();
.next() let remainder = iter.next().expect("name contains separator").trim();
.expect("never fails because the name contains a separator")
.trim();
let remainder = iter
.next()
.expect("never fails because the name contains a separator")
.trim();
if !root.contains_key(sub_module) { if !root.contains_key(sub_module) {
let mut m: Module = Default::default(); let mut m: Module = Default::default();
@ -974,7 +968,7 @@ impl Engine {
} else { } else {
let m = root let m = root
.remove(sub_module) .remove(sub_module)
.expect("never fails because the root contains the sub-module"); .expect("root contains the sub-module");
let mut m = crate::fn_native::shared_take_or_clone(m); let mut m = crate::fn_native::shared_take_or_clone(m);
register_static_module_raw(m.sub_modules_mut(), remainder, module); register_static_module_raw(m.sub_modules_mut(), remainder, module);
m.build_index(); m.build_index();
@ -1079,19 +1073,18 @@ impl Engine {
resolver: &StaticModuleResolver, resolver: &StaticModuleResolver,
imports: &mut BTreeSet<Identifier>, imports: &mut BTreeSet<Identifier>,
) { ) {
ast.walk(&mut |path| match path ast.walk(
.last() &mut |path| match path.last().expect("`path` contains the current node") {
.expect("never fails because `path` always contains the current node") // Collect all `import` statements with a string constant path
{ ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _))
// Collect all `import` statements with a string constant path if !resolver.contains_path(s) && !imports.contains(s.as_str()) =>
ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _)) {
if !resolver.contains_path(s) && !imports.contains(s.as_str()) => imports.insert(s.clone().into());
{ true
imports.insert(s.clone().into()); }
true _ => true,
} },
_ => true, );
});
} }
let mut ast = self.compile_scripts_with_scope(scope, &[script])?; let mut ast = self.compile_scripts_with_scope(scope, &[script])?;
@ -1335,12 +1328,12 @@ impl Engine {
/// true)?; /// true)?;
/// ///
/// assert_eq!(map.len(), 4); /// assert_eq!(map.len(), 4);
/// assert_eq!(map["a"].as_int().unwrap(), 123); /// assert_eq!(map["a"].as_int().expect("a should exist"), 123);
/// assert_eq!(map["b"].as_int().unwrap(), 42); /// assert_eq!(map["b"].as_int().expect("b should exist"), 42);
/// assert!(map["d"].is::<()>()); /// assert!(map["d"].is::<()>());
/// ///
/// let c = map["c"].read_lock::<Map>().unwrap(); /// let c = map["c"].read_lock::<Map>().expect("c should exist");
/// assert_eq!(c["x"].as_bool().unwrap(), false); /// assert_eq!(c["x"].as_bool().expect("x should be bool"), false);
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
@ -1933,7 +1926,7 @@ impl Engine {
/// let mut value: Dynamic = 1_i64.into(); /// let mut value: Dynamic = 1_i64.into();
/// let result = engine.call_fn_dynamic(&mut scope, &ast, true, "action", Some(&mut value), [ 41_i64.into() ])?; /// let result = engine.call_fn_dynamic(&mut scope, &ast, true, "action", Some(&mut value), [ 41_i64.into() ])?;
/// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer /// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer
/// assert_eq!(value.as_int().unwrap(), 42); /// assert_eq!(value.as_int().expect("value should be INT"), 42);
/// # } /// # }
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -2038,7 +2031,7 @@ impl Engine {
.map(|f| { .map(|f| {
f.func f.func
.get_script_fn_def() .get_script_fn_def()
.expect("never fails because the function is scripted") .expect("scripted function")
.clone() .clone()
}) })
.collect(); .collect();
@ -2062,7 +2055,7 @@ impl Engine {
pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> { pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> {
let mut signatures: Vec<_> = Default::default(); let mut signatures: Vec<_> = Default::default();
signatures.extend(self.global_namespace.gen_fn_signatures()); signatures.extend(self.global_namespace().gen_fn_signatures());
self.global_sub_modules.iter().for_each(|(name, m)| { self.global_sub_modules.iter().for_each(|(name, m)| {
signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f))) signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f)))
@ -2072,6 +2065,7 @@ impl Engine {
signatures.extend( signatures.extend(
self.global_modules self.global_modules
.iter() .iter()
.take(self.global_modules.len() - 1)
.flat_map(|m| m.gen_fn_signatures()), .flat_map(|m| m.gen_fn_signatures()),
); );
} }

View File

@ -279,7 +279,7 @@ impl Engine {
/// ///
/// // Register a custom operator called 'foo' and give it /// // Register a custom operator called 'foo' and give it
/// // a precedence of 160 (i.e. between +|- and *|/). /// // a precedence of 160 (i.e. between +|- and *|/).
/// engine.register_custom_operator("foo", 160).unwrap(); /// engine.register_custom_operator("foo", 160).expect("should succeed");
/// ///
/// // Register a binary function named 'foo' /// // Register a binary function named 'foo'
/// engine.register_fn("foo", |x: i64, y: i64| (x * y) - (x + y)); /// engine.register_fn("foo", |x: i64, y: i64| (x * y) - (x + y));

View File

@ -303,7 +303,7 @@ impl EvalAltResult {
format!("{:?}", self) format!("{:?}", self)
.split('(') .split('(')
.next() .next()
.expect("never fails because the debug format of an error is `ErrorXXX(...)`") .expect("debug format of error is `ErrorXXX(...)`")
.into(), .into(),
); );

View File

@ -14,8 +14,8 @@ use crate::FLOAT;
#[cfg(feature = "decimal")] #[cfg(feature = "decimal")]
use rust_decimal::Decimal; use rust_decimal::Decimal;
/// The message: never fails because this is built-in code and the type is already checked /// The message: data type was checked
const BUILTIN: &str = "never fails because this is built-in code and the type is already checked"; const BUILTIN: &str = "data type was checked";
/// Is the type a numeric type? /// Is the type a numeric type?
#[inline] #[inline]

View File

@ -190,17 +190,39 @@ impl Engine {
let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic`
loop { loop {
let func = lib.iter().find_map(|m| m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { let func = lib
func, source: m.id_raw().cloned() .iter()
})).or_else(|| self.global_namespace.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { .find_map(|m| {
func, source: None m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
})).or_else(|| self.global_modules.iter().find_map(|m| m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { func,
func, source: m.id_raw().cloned() source: m.id_raw().cloned(),
}))).or_else(|| mods.get_fn(hash).map(|(func, source)| FnResolutionCacheEntry { })
func: func.clone(), source: source.cloned() })
})).or_else(|| self.global_sub_modules.values().find_map(|m| m.get_qualified_fn(hash).cloned().map(|func| FnResolutionCacheEntry { .or_else(|| {
func, source: m.id_raw().cloned() self.global_modules.iter().find_map(|m| {
}))); m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
func,
source: m.id_raw().cloned(),
})
})
})
.or_else(|| {
mods.get_fn(hash)
.map(|(func, source)| FnResolutionCacheEntry {
func: func.clone(),
source: source.cloned(),
})
})
.or_else(|| {
self.global_sub_modules.values().find_map(|m| {
m.get_qualified_fn(hash).cloned().map(|func| {
FnResolutionCacheEntry {
func,
source: m.id_raw().cloned(),
}
})
})
});
match func { match func {
// Specific version found // Specific version found
@ -215,17 +237,26 @@ impl Engine {
return args.and_then(|args| { return args.and_then(|args| {
if !is_op_assignment { if !is_op_assignment {
get_builtin_binary_op_fn(fn_name, &args[0], &args[1]).map(|f| { get_builtin_binary_op_fn(fn_name, &args[0], &args[1]).map(|f| {
FnResolutionCacheEntry { func: CallableFunction::from_method( FnResolutionCacheEntry {
Box::new(f) as Box<FnAny> func: CallableFunction::from_method(
), source: None } Box::new(f) as Box<FnAny>
),
source: None,
}
}) })
} else { } else {
let (first, second) = args.split_first() let (first, second) = args
.expect("never fails because an op-assignment must have two arguments"); .split_first()
.expect("op-assignment has two arguments");
get_builtin_op_assignment_fn(fn_name, *first, second[0]).map(|f| FnResolutionCacheEntry { get_builtin_op_assignment_fn(fn_name, *first, second[0]).map(
func: CallableFunction::from_method(Box::new(f) as Box<FnAny>), source: None |f| FnResolutionCacheEntry {
}) func: CallableFunction::from_method(
Box::new(f) as Box<FnAny>
),
source: None,
},
)
} }
.map(Box::new) .map(Box::new)
}); });
@ -234,17 +265,19 @@ impl Engine {
// Try all permutations with `Dynamic` wildcards // Try all permutations with `Dynamic` wildcards
None => { None => {
let hash_params = calc_fn_params_hash( let hash_params = calc_fn_params_hash(
args.as_ref().expect("never fails because there are no permutations if there are no arguments") args.as_ref()
.iter().enumerate().map(|(i, a)| .expect("no permutations if no arguments")
{ .iter()
let mask = 1usize << (num_args - i - 1); .enumerate()
if bitmask & mask != 0 { .map(|(i, a)| {
// Replace with `Dynamic` let mask = 1usize << (num_args - i - 1);
TypeId::of::<Dynamic>() if bitmask & mask != 0 {
} else { // Replace with `Dynamic`
a.type_id() TypeId::of::<Dynamic>()
} } else {
}), a.type_id()
}
}),
); );
hash = combine_hashes(hash_script, hash_params); hash = combine_hashes(hash_script, hash_params);
@ -290,7 +323,10 @@ impl Engine {
let mut backup: Option<ArgBackup> = None; let mut backup: Option<ArgBackup> = None;
if is_method_call && func.is_pure() && !args.is_empty() { if is_method_call && func.is_pure() && !args.is_empty() {
backup = Some(Default::default()); backup = Some(Default::default());
backup.as_mut().unwrap().change_first_arg_to_copy(args); backup
.as_mut()
.expect("`backup` is `Some`")
.change_first_arg_to_copy(args);
} }
// Run external function // Run external function
@ -301,12 +337,10 @@ impl Engine {
let result = if func.is_plugin_fn() { let result = if func.is_plugin_fn() {
func.get_plugin_fn() func.get_plugin_fn()
.expect("never fails because the function is a plugin") .expect("plugin function")
.call((self, name, source, mods, lib).into(), args) .call((self, name, source, mods, lib).into(), args)
} else { } else {
let func = func let func = func.get_native_fn().expect("native function");
.get_native_fn()
.expect("never fails because the function is native");
func((self, name, source, mods, lib).into(), args) func((self, name, source, mods, lib).into(), args)
}; };
@ -579,8 +613,6 @@ impl Engine {
// First check script-defined functions // First check script-defined functions
let result = lib.iter().any(|&m| m.contains_fn(hash_script)) let result = lib.iter().any(|&m| m.contains_fn(hash_script))
// Then check registered functions
|| self.global_namespace.contains_fn(hash_script)
// Then check packages // Then check packages
|| self.global_modules.iter().any(|m| m.contains_fn(hash_script)) || self.global_modules.iter().any(|m| m.contains_fn(hash_script))
// Then check imported modules // Then check imported modules
@ -644,10 +676,8 @@ impl Engine {
{ {
let fn_name = args[0] let fn_name = args[0]
.read_lock::<ImmutableString>() .read_lock::<ImmutableString>()
.expect("never fails because `args[0]` is `FnPtr`"); .expect("`args[0]` is `FnPtr`");
let num_params = args[1] let num_params = args[1].as_int().expect("`args[1]` is `INT`");
.as_int()
.expect("never fails because `args[1]` is `INT`");
return Ok(( return Ok((
if num_params < 0 { if num_params < 0 {
@ -691,9 +721,7 @@ impl Engine {
// Script function call // Script function call
assert!(func.is_script()); assert!(func.is_script());
let func = func let func = func.get_script_fn_def().expect("scripted function");
.get_script_fn_def()
.expect("never fails because the function is scripted");
if func.body.is_empty() { if func.body.is_empty() {
return Ok((Dynamic::UNIT, false)); return Ok((Dynamic::UNIT, false));
@ -719,7 +747,7 @@ impl Engine {
// Method call of script function - map first argument to `this` // Method call of script function - map first argument to `this`
let (first, rest) = args let (first, rest) = args
.split_first_mut() .split_first_mut()
.expect("never fails because a method call always has a first parameter"); .expect("method call has first parameter");
let orig_source = state.source.take(); let orig_source = state.source.take();
state.source = source; state.source = source;
@ -748,7 +776,10 @@ impl Engine {
let mut backup: Option<ArgBackup> = None; let mut backup: Option<ArgBackup> = None;
if is_ref_mut && !args.is_empty() { if is_ref_mut && !args.is_empty() {
backup = Some(Default::default()); backup = Some(Default::default());
backup.as_mut().unwrap().change_first_arg_to_copy(args); backup
.as_mut()
.expect("`backup` is `Some`")
.change_first_arg_to_copy(args);
} }
let orig_source = state.source.take(); let orig_source = state.source.take();
@ -871,9 +902,7 @@ impl Engine {
let (result, updated) = match fn_name { let (result, updated) = match fn_name {
KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => { KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => {
// FnPtr call // FnPtr call
let fn_ptr = target let fn_ptr = target.read_lock::<FnPtr>().expect("`obj` is `FnPtr`");
.read_lock::<FnPtr>()
.expect("never fails because `obj` is `FnPtr`");
// Redirect function name // Redirect function name
let fn_name = fn_ptr.fn_name(); let fn_name = fn_ptr.fn_name();
let args_len = call_args.len() + fn_ptr.curry().len(); let args_len = call_args.len() + fn_ptr.curry().len();
@ -938,9 +967,7 @@ impl Engine {
)); ));
} }
let fn_ptr = target let fn_ptr = target.read_lock::<FnPtr>().expect("`obj` is `FnPtr`");
.read_lock::<FnPtr>()
.expect("never fails because `obj` is `FnPtr`");
// Curry call // Curry call
Ok(( Ok((
@ -1264,7 +1291,7 @@ impl Engine {
} else { } else {
// Turn it into a method call only if the object is not shared and not a simple value // Turn it into a method call only if the object is not shared and not a simple value
is_ref_mut = true; is_ref_mut = true;
let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared"); let obj_ref = target.take_ref().expect("`target` is reference");
args.push(obj_ref); args.push(obj_ref);
args.extend(arg_values.iter_mut()); args.extend(arg_values.iter_mut());
} }
@ -1345,9 +1372,9 @@ impl Engine {
// Turn it into a method call only if the object is not shared and not a simple value // Turn it into a method call only if the object is not shared and not a simple value
let (first, rest) = arg_values let (first, rest) = arg_values
.split_first_mut() .split_first_mut()
.expect("never fails because the arguments list is not empty"); .expect("arguments list is not empty");
first_arg_value = Some(first); first_arg_value = Some(first);
let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared"); let obj_ref = target.take_ref().expect("`target` is reference");
args.push(obj_ref); args.push(obj_ref);
args.extend(rest.iter_mut()); args.extend(rest.iter_mut());
} }
@ -1393,9 +1420,7 @@ impl Engine {
match func { match func {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Some(f) if f.is_script() => { Some(f) if f.is_script() => {
let fn_def = f let fn_def = f.get_script_fn_def().expect("scripted function");
.get_script_fn_def()
.expect("never fails because the function is scripted");
if fn_def.body.is_empty() { if fn_def.body.is_empty() {
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
@ -1419,15 +1444,13 @@ impl Engine {
Some(f) if f.is_plugin_fn() => f Some(f) if f.is_plugin_fn() => f
.get_plugin_fn() .get_plugin_fn()
.expect("never fails because the function is a plugin") .expect("plugin function")
.clone() .clone()
.call((self, fn_name, module.id(), &*mods, lib).into(), &mut args) .call((self, fn_name, module.id(), &*mods, lib).into(), &mut args)
.map_err(|err| err.fill_position(pos)), .map_err(|err| err.fill_position(pos)),
Some(f) if f.is_native() => { Some(f) if f.is_native() => {
let func = f let func = f.get_native_fn().expect("native function");
.get_native_fn()
.expect("never fails because the function is native");
func((self, fn_name, module.id(), &*mods, lib).into(), &mut args) func((self, fn_name, module.id(), &*mods, lib).into(), &mut args)
.map_err(|err| err.fill_position(pos)) .map_err(|err| err.fill_position(pos))
} }

View File

@ -259,7 +259,7 @@ pub fn shared_try_take<T>(value: Shared<T>) -> Result<T, Shared<T>> {
pub fn shared_take<T>(value: Shared<T>) -> T { pub fn shared_take<T>(value: Shared<T>) -> T {
shared_try_take(value) shared_try_take(value)
.ok() .ok()
.expect("resource should have no outstanding references") .expect("no outstanding references")
} }
/// A general function trail object. /// A general function trail object.

View File

@ -34,8 +34,7 @@ pub struct Mut<T>(T);
#[must_use] #[must_use]
pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> { pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> {
// Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data. // Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data.
data.write_lock::<T>() data.write_lock::<T>().expect("data type was checked")
.expect("never fails because the type was checked")
} }
/// Dereference into value. /// Dereference into value.
@ -47,15 +46,15 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
data.flatten_in_place(); data.flatten_in_place();
let ref_str = data let ref_str = data
.as_str_ref() .as_str_ref()
.expect("never fails because argument passed by value should not be shared"); .expect("argument passed by value is not shared");
let ref_t = unsafe { mem::transmute::<_, &T>(&ref_str) }; let ref_t = unsafe { mem::transmute::<_, &T>(&ref_str) };
ref_t.clone() ref_t.clone()
} else if TypeId::of::<T>() == TypeId::of::<String>() { } else if TypeId::of::<T>() == TypeId::of::<String>() {
// If T is `String`, data must be `ImmutableString`, so map directly to it // If T is `String`, data must be `ImmutableString`, so map directly to it
let value = mem::take(data) let value = mem::take(data)
.into_string() .into_string()
.expect("never fails because the type was checked"); .expect("data type was checked");
unsafe_try_cast(value).expect("never fails because the type was checked") unsafe_try_cast(value).expect("data type was checked")
} else { } else {
// We consume the argument and then replace it with () - the argument is not supposed to be used again. // We consume the argument and then replace it with () - the argument is not supposed to be used again.
// This way, we avoid having to clone the argument again, because it is already a clone when passed here. // This way, we avoid having to clone the argument again, because it is already a clone when passed here.
@ -131,7 +130,7 @@ macro_rules! def_register {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut(); let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
// Call the function with each argument value // Call the function with each argument value
let r = self($($arg),*); let r = self($($arg),*);
@ -159,7 +158,7 @@ macro_rules! def_register {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut(); let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
// Call the function with each argument value // Call the function with each argument value
let r = self(ctx, $($arg),*); let r = self(ctx, $($arg),*);
@ -187,7 +186,7 @@ macro_rules! def_register {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut(); let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
// Call the function with each argument value // Call the function with each argument value
self($($arg),*).map(Dynamic::from) self($($arg),*).map(Dynamic::from)
@ -212,7 +211,7 @@ macro_rules! def_register {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut(); let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().expect("never fails because arguments list is fixed")); )* $($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
// Call the function with each argument value // Call the function with each argument value
self(ctx, $($arg),*).map(Dynamic::from) self(ctx, $($arg),*).map(Dynamic::from)

View File

@ -238,7 +238,7 @@ impl Module {
/// # use rhai::Module; /// # use rhai::Module;
/// let mut module = Module::new(); /// let mut module = Module::new();
/// module.set_var("answer", 42_i64); /// module.set_var("answer", 42_i64);
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42); /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -400,7 +400,7 @@ impl Module {
/// # use rhai::Module; /// # use rhai::Module;
/// let mut module = Module::new(); /// let mut module = Module::new();
/// module.set_var("answer", 42_i64); /// module.set_var("answer", 42_i64);
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42); /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -416,7 +416,7 @@ impl Module {
/// # use rhai::Module; /// # use rhai::Module;
/// let mut module = Module::new(); /// let mut module = Module::new();
/// module.set_var("answer", 42_i64); /// module.set_var("answer", 42_i64);
/// assert_eq!(module.get_var("answer").unwrap().cast::<i64>(), 42); /// assert_eq!(module.get_var("answer").expect("answer should exist").cast::<i64>(), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -434,7 +434,7 @@ impl Module {
/// # use rhai::Module; /// # use rhai::Module;
/// let mut module = Module::new(); /// let mut module = Module::new();
/// module.set_var("answer", 42_i64); /// module.set_var("answer", 42_i64);
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42); /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// ``` /// ```
#[inline] #[inline]
pub fn set_var( pub fn set_var(
@ -1337,9 +1337,7 @@ impl Module {
f.access, f.access,
f.name.as_str(), f.name.as_str(),
f.params, f.params,
f.func f.func.get_script_fn_def().expect("scripted function"),
.get_script_fn_def()
.expect("never fails because the function is scripted"),
) )
}) })
} }
@ -1407,7 +1405,7 @@ impl Module {
/// let ast = engine.compile("let answer = 42; export answer;")?; /// let ast = engine.compile("let answer = 42; export answer;")?;
/// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?; /// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
/// assert!(module.contains_var("answer")); /// assert!(module.contains_var("answer"));
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42); /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
@ -1431,9 +1429,7 @@ impl Module {
match aliases.len() { match aliases.len() {
0 => (), 0 => (),
1 => { 1 => {
let alias = aliases let alias = aliases.pop().expect("list has one item");
.pop()
.expect("never fails because the list has one item");
module.set_var(alias, value); module.set_var(alias, value);
} }
_ => aliases.into_iter().for_each(|alias| { _ => aliases.into_iter().for_each(|alias| {
@ -1465,7 +1461,7 @@ impl Module {
let mut func = f let mut func = f
.func .func
.get_script_fn_def() .get_script_fn_def()
.expect("never fails because the function is scripted") .expect("scripted function")
.as_ref() .as_ref()
.clone(); .clone();
func.lib = Some(ast.shared_lib()); func.lib = Some(ast.shared_lib());

View File

@ -148,10 +148,8 @@ impl<'a> OptimizerState<'a> {
let hash_params = calc_fn_params_hash(arg_types.iter().cloned()); let hash_params = calc_fn_params_hash(arg_types.iter().cloned());
let hash = combine_hashes(hash_script, hash_params); let hash = combine_hashes(hash_script, hash_params);
// First check registered functions // First check packages
self.engine.global_namespace.contains_fn(hash) self.engine.global_modules.iter().any(|m| m.contains_fn(hash))
// Then check packages
|| self.engine.global_modules.iter().any(|m| m.contains_fn(hash))
// Then check sub-modules // Then check sub-modules
|| self.engine.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash)) || self.engine.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash))
} }
@ -282,18 +280,23 @@ fn optimize_stmt_block(
if reduce_return && !last_stmt.returns_value() => if reduce_return && !last_stmt.returns_value() =>
{ {
state.set_dirty(); state.set_dirty();
statements.pop().unwrap(); statements
.pop()
.expect("`statements` contains at least two elements");
} }
// { ...; return val; } -> { ...; val } // { ...; return val; } -> { ...; val }
[.., Stmt::Return(crate::ast::ReturnType::Return, ref mut expr, pos)] [.., Stmt::Return(crate::ast::ReturnType::Return, ref mut expr, pos)]
if reduce_return => if reduce_return =>
{ {
state.set_dirty(); state.set_dirty();
*statements.last_mut().unwrap() = if let Some(expr) = expr { *statements
Stmt::Expr(mem::take(expr)) .last_mut()
} else { .expect("`statements` contains at least two elements") =
Stmt::Noop(pos) if let Some(expr) = expr {
}; Stmt::Expr(mem::take(expr))
} else {
Stmt::Noop(pos)
};
} }
// { ...; stmt; noop } -> done // { ...; stmt; noop } -> done
[.., ref second_last_stmt, Stmt::Noop(_)] [.., ref second_last_stmt, Stmt::Noop(_)]
@ -308,9 +311,14 @@ fn optimize_stmt_block(
{ {
state.set_dirty(); state.set_dirty();
if second_last_stmt.returns_value() { if second_last_stmt.returns_value() {
*statements.last_mut().unwrap() = Stmt::Noop(last_stmt.position()); *statements
.last_mut()
.expect("`statements` contains at least two elements") =
Stmt::Noop(last_stmt.position());
} else { } else {
statements.pop().unwrap(); statements
.pop()
.expect("`statements` contains at least two elements");
} }
} }
_ => break, _ => break,
@ -328,18 +336,24 @@ fn optimize_stmt_block(
if reduce_return => if reduce_return =>
{ {
state.set_dirty(); state.set_dirty();
statements.pop().unwrap(); statements
.pop()
.expect("`statements` contains at least two elements");
} }
// { ...; return pure_val; } -> { ... } // { ...; return pure_val; } -> { ... }
[.., Stmt::Return(crate::ast::ReturnType::Return, Some(ref expr), _)] [.., Stmt::Return(crate::ast::ReturnType::Return, Some(ref expr), _)]
if reduce_return && expr.is_pure() => if reduce_return && expr.is_pure() =>
{ {
state.set_dirty(); state.set_dirty();
statements.pop().unwrap(); statements
.pop()
.expect("`statements` contains at least two elements");
} }
[.., ref last_stmt] if is_pure(last_stmt) => { [.., ref last_stmt] if is_pure(last_stmt) => {
state.set_dirty(); state.set_dirty();
statements.pop().unwrap(); statements
.pop()
.expect("`statements` contains at least one element");
} }
_ => break, _ => break,
} }
@ -381,14 +395,18 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
match x.2 { match x.2 {
Expr::FnCall(ref mut x2, _) => { Expr::FnCall(ref mut x2, _) => {
state.set_dirty(); state.set_dirty();
let op = Token::lookup_from_syntax(&x2.name).unwrap(); let op = Token::lookup_from_syntax(&x2.name).expect("`x2` is operator");
let op_assignment = op.make_op_assignment().unwrap(); let op_assignment = op.make_op_assignment().expect("`op` is operator");
x.1 = Some(OpAssignment::new(op_assignment)); x.1 = Some(OpAssignment::new(op_assignment));
let value = mem::take(&mut x2.args[1]); let value = mem::take(&mut x2.args[1]);
if let Expr::Stack(slot, pos) = value { if let Expr::Stack(slot, pos) = value {
let value = mem::take(x2.constants.get_mut(slot).unwrap()); let value = mem::take(
x2.constants
.get_mut(slot)
.expect("`constants[slot]` is valid"),
);
x.2 = Expr::from_dynamic(value, pos); x.2 = Expr::from_dynamic(value, pos);
} else { } else {
x.2 = value; x.2 = value;
@ -459,7 +477,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// switch const { ... } // switch const { ... }
Stmt::Switch(match_expr, x, pos) if match_expr.is_constant() => { Stmt::Switch(match_expr, x, pos) if match_expr.is_constant() => {
let value = match_expr.get_literal_value().unwrap(); let value = match_expr
.get_literal_value()
.expect("`match_expr` is constant");
let hasher = &mut get_hasher(); let hasher = &mut get_hasher();
value.hash(hasher); value.hash(hasher);
let hash = hasher.finish(); let hash = hasher.finish();
@ -782,13 +802,13 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.chars().count() => { (Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.chars().count() => {
// String literal indexing - get the character // String literal indexing - get the character
state.set_dirty(); state.set_dirty();
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos); *expr = Expr::CharConstant(s.chars().nth(*i as usize).expect("character position is valid"), *pos);
} }
// string[-int] // string[-int]
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => { (Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => {
// String literal indexing - get the character // String literal indexing - get the character
state.set_dirty(); state.set_dirty();
*expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).unwrap(), *pos); *expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).expect("character position is valid"), *pos);
} }
// var[rhs] // var[rhs]
(Expr::Variable(_, _, _), rhs) => optimize_expr(rhs, state, true), (Expr::Variable(_, _, _), rhs) => optimize_expr(rhs, state, true),
@ -855,7 +875,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Expr::Array(_, _) if expr.is_constant() => { Expr::Array(_, _) if expr.is_constant() => {
state.set_dirty(); state.set_dirty();
*expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position()); *expr = Expr::DynamicConstant(expr.get_literal_value().expect("`expr` is constant").into(), expr.position());
} }
// [ items .. ] // [ items .. ]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -864,7 +884,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Map(_, _) if expr.is_constant() => { Expr::Map(_, _) if expr.is_constant() => {
state.set_dirty(); state.set_dirty();
*expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position()); *expr = Expr::DynamicConstant(expr.get_literal_value().expect("`expr` is constant").into(), expr.position());
} }
// #{ key:value, .. } // #{ key:value, .. }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -935,7 +955,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
if let Some(fn_name) = fn_name { if let Some(fn_name) = fn_name {
if fn_name.is::<ImmutableString>() { if fn_name.is::<ImmutableString>() {
state.set_dirty(); state.set_dirty();
let fn_ptr = FnPtr::new_unchecked(fn_name.as_str_ref().unwrap().into(), Default::default()); let fn_ptr = FnPtr::new_unchecked(
fn_name.as_str_ref().expect("`fn_name` is `ImmutableString`").into(),
Default::default()
);
*expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos); *expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos);
} }
} }
@ -955,7 +978,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
=> { => {
let arg_values = &mut x.args.iter().map(|e| match e { let arg_values = &mut x.args.iter().map(|e| match e {
Expr::Stack(slot, _) => x.constants[*slot].clone(), Expr::Stack(slot, _) => x.constants[*slot].clone(),
_ => e.get_literal_value().unwrap() _ => e.get_literal_value().expect("`e` is constant")
}).collect::<StaticVec<_>>(); }).collect::<StaticVec<_>>();
let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect(); let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect();
@ -969,7 +992,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1]) get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
.and_then(|f| { .and_then(|f| {
let ctx = (state.engine, x.name.as_ref(), state.lib).into(); let ctx = (state.engine, x.name.as_ref(), state.lib).into();
let (first, second) = arg_values.split_first_mut().unwrap(); let (first, second) = arg_values.split_first_mut().expect("`arg_values` is not empty");
(f)(ctx, &mut [ first, &mut second[0] ]).ok() (f)(ctx, &mut [ first, &mut second[0] ]).ok()
}) })
} }
@ -1009,7 +1032,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
if !has_script_fn { if !has_script_fn {
let arg_values = &mut x.args.iter().map(|e| match e { let arg_values = &mut x.args.iter().map(|e| match e {
Expr::Stack(slot, _) => x.constants[*slot].clone(), Expr::Stack(slot, _) => x.constants[*slot].clone(),
_ => e.get_literal_value().unwrap() _ => e.get_literal_value().expect("`e` is constant")
}).collect::<StaticVec<_>>(); }).collect::<StaticVec<_>>();
let result = match x.name.as_str() { let result = match x.name.as_str() {
@ -1044,7 +1067,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
// constant-name // constant-name
Expr::Variable(_, pos, x) if x.1.is_none() && state.find_constant(&x.2).is_some() => { Expr::Variable(_, pos, x) if x.1.is_none() && state.find_constant(&x.2).is_some() => {
// Replace constant with value // Replace constant with value
*expr = Expr::from_dynamic(state.find_constant(&x.2).unwrap().clone(), *pos); *expr = Expr::from_dynamic(state.find_constant(&x.2).expect("constant exists").clone(), *pos);
state.set_dirty(); state.set_dirty();
} }

View File

@ -45,7 +45,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
namespace: Option<Identifier>, namespace: Option<Identifier>,
f: &ScriptFnDef, f: &ScriptFnDef,
) -> Map { ) -> Map {
const DICT: &str = "never fails because the dictionary is pre-filled with all the keys"; const DICT: &str = "key exists";
let mut map = Map::new(); let mut map = Map::new();

View File

@ -31,7 +31,7 @@ pub fn print_with_func(
match ctx.call_fn_dynamic_raw(fn_name, true, &mut [value]) { match ctx.call_fn_dynamic_raw(fn_name, true, &mut [value]) {
Ok(result) if result.is::<crate::ImmutableString>() => result Ok(result) if result.is::<crate::ImmutableString>() => result
.into_immutable_string() .into_immutable_string()
.expect("never fails as the result is `ImmutableString`"), .expect("result is `ImmutableString`"),
Ok(result) => ctx.engine().map_type_name(result.type_name()).into(), Ok(result) => ctx.engine().map_type_name(result.type_name()).into(),
Err(_) => ctx.engine().map_type_name(value.type_name()).into(), Err(_) => ctx.engine().map_type_name(value.type_name()).into(),
} }

View File

@ -116,9 +116,7 @@ mod string_functions {
#[rhai_fn(name = "to_upper")] #[rhai_fn(name = "to_upper")]
pub fn to_upper_char(character: char) -> char { pub fn to_upper_char(character: char) -> char {
let mut stream = character.to_uppercase(); let mut stream = character.to_uppercase();
let ch = stream let ch = stream.next().expect("at least one character");
.next()
.expect("never fails because there should be at least one character");
if stream.next().is_some() { if stream.next().is_some() {
character character
} else { } else {
@ -134,7 +132,7 @@ mod string_functions {
let mut stream = character.to_lowercase(); let mut stream = character.to_lowercase();
let ch = stream let ch = stream
.next() .next()
.expect("never fails because there should be at least one character"); .expect("there should be at least one character");
if stream.next().is_some() { if stream.next().is_some() {
character character
} else { } else {

View File

@ -38,8 +38,8 @@ type FunctionsLib = BTreeMap<u64, Shared<ScriptFnDef>>;
/// Invalid variable name that acts as a search barrier in a [`Scope`]. /// Invalid variable name that acts as a search barrier in a [`Scope`].
const SCOPE_SEARCH_BARRIER_MARKER: &str = "$BARRIER$"; const SCOPE_SEARCH_BARRIER_MARKER: &str = "$BARRIER$";
/// The message: never fails because `TokenStream` never ends /// The message: `TokenStream` never ends
const NEVER_ENDS: &str = "never fails because `TokenStream` never ends"; const NEVER_ENDS: &str = "`TokenStream` never ends";
/// A factory of identifiers from text strings. /// A factory of identifiers from text strings.
/// ///
@ -1602,9 +1602,7 @@ fn make_assignment_stmt(
let index = i.map_or_else( let index = i.map_or_else(
|| { || {
index index
.expect( .expect("the long index is `Some` when the short index is `None`")
"never fails because the long index is `Some` when the short index is `None`",
)
.get() .get()
}, },
|n| n.get() as usize, |n| n.get() as usize,
@ -1695,8 +1693,9 @@ fn make_dot_expr(
} }
// lhs.module::id - syntax error // lhs.module::id - syntax error
(_, Expr::Variable(_, _, x)) => { (_, Expr::Variable(_, _, x)) => {
return Err(PERR::PropertyExpected return Err(
.into_err(x.1.expect("never fails because the namespace is `Some`").0[0].pos)) PERR::PropertyExpected.into_err(x.1.expect("the namespace is `Some`").0[0].pos)
)
} }
// lhs.prop // lhs.prop
(lhs, prop @ Expr::Property(_)) => { (lhs, prop @ Expr::Property(_)) => {
@ -1901,12 +1900,8 @@ fn parse_binary_op(
| Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos), | Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
Token::Or => { Token::Or => {
let rhs = args let rhs = args.pop().expect("`||` has two arguments");
.pop() let current_lhs = args.pop().expect("`||` has two arguments");
.expect("never fails because `||` has two arguments");
let current_lhs = args
.pop()
.expect("never fails because `||` has two arguments");
Expr::Or( Expr::Or(
BinaryExpr { BinaryExpr {
lhs: current_lhs.ensure_bool_expr()?, lhs: current_lhs.ensure_bool_expr()?,
@ -1917,12 +1912,8 @@ fn parse_binary_op(
) )
} }
Token::And => { Token::And => {
let rhs = args let rhs = args.pop().expect("`&&` has two arguments");
.pop() let current_lhs = args.pop().expect("`&&` has two arguments");
.expect("never fails because `&&` has two arguments");
let current_lhs = args
.pop()
.expect("never fails because `&&` has two arguments");
Expr::And( Expr::And(
BinaryExpr { BinaryExpr {
lhs: current_lhs.ensure_bool_expr()?, lhs: current_lhs.ensure_bool_expr()?,
@ -2391,7 +2382,7 @@ fn parse_for(
}, },
counter_var.map(|name| Ident { counter_var.map(|name| Ident {
name, name,
pos: counter_pos.expect("never fails because `counter_var` is `Some`"), pos: counter_pos.expect("`counter_var` is `Some`"),
}), }),
body.into(), body.into(),
)), )),

View File

@ -32,8 +32,8 @@ const SCOPE_ENTRIES_INLINED: usize = 8;
/// ///
/// assert_eq!(engine.eval_with_scope::<i64>(&mut my_scope, "x + 1")?, 42); /// assert_eq!(engine.eval_with_scope::<i64>(&mut my_scope, "x + 1")?, 42);
/// ///
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 41); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 41);
/// assert_eq!(my_scope.get_value::<i64>("z").unwrap(), 0); /// assert_eq!(my_scope.get_value::<i64>("z").expect("z should exist"), 0);
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
@ -85,7 +85,7 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push("x", 42_i64); /// my_scope.push("x", 42_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -163,7 +163,7 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push("x", 42_i64); /// my_scope.push("x", 42_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn push( pub fn push(
@ -183,7 +183,7 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push_dynamic("x", Dynamic::from(42_i64)); /// my_scope.push_dynamic("x", Dynamic::from(42_i64));
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self { pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self {
@ -202,7 +202,7 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push_constant("x", 42_i64); /// my_scope.push_constant("x", 42_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn push_constant( pub fn push_constant(
@ -225,7 +225,7 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push_constant_dynamic("x", Dynamic::from(42_i64)); /// my_scope.push_constant_dynamic("x", Dynamic::from(42_i64));
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn push_constant_dynamic( pub fn push_constant_dynamic(
@ -327,7 +327,7 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push("x", 42_i64); /// my_scope.push("x", 42_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
@ -377,15 +377,15 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.set_or_push("x", 42_i64); /// my_scope.set_or_push("x", 42_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// assert_eq!(my_scope.len(), 1); /// assert_eq!(my_scope.len(), 1);
/// ///
/// my_scope.set_or_push("x", 0_i64); /// my_scope.set_or_push("x", 0_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 0); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 0);
/// assert_eq!(my_scope.len(), 1); /// assert_eq!(my_scope.len(), 1);
/// ///
/// my_scope.set_or_push("y", 123_i64); /// my_scope.set_or_push("y", 123_i64);
/// assert_eq!(my_scope.get_value::<i64>("y").unwrap(), 123); /// assert_eq!(my_scope.get_value::<i64>("y").expect("y should exist"), 123);
/// assert_eq!(my_scope.len(), 2); /// assert_eq!(my_scope.len(), 2);
/// ``` /// ```
#[inline] #[inline]
@ -399,10 +399,7 @@ impl<'a> Scope<'a> {
self.push(name, value); self.push(name, value);
} }
Some((index, AccessMode::ReadWrite)) => { Some((index, AccessMode::ReadWrite)) => {
let value_ref = self let value_ref = self.values.get_mut(index).expect("index is valid");
.values
.get_mut(index)
.expect("never fails because the index is returned by `get_index`");
*value_ref = Dynamic::from(value); *value_ref = Dynamic::from(value);
} }
} }
@ -425,10 +422,10 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push("x", 42_i64); /// my_scope.push("x", 42_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ///
/// my_scope.set_value("x", 0_i64); /// my_scope.set_value("x", 0_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 0); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 0);
/// ``` /// ```
#[inline] #[inline]
pub fn set_value( pub fn set_value(
@ -442,10 +439,7 @@ impl<'a> Scope<'a> {
} }
Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()), Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()),
Some((index, AccessMode::ReadWrite)) => { Some((index, AccessMode::ReadWrite)) => {
let value_ref = self let value_ref = self.values.get_mut(index).expect("index is valid");
.values
.get_mut(index)
.expect("never fails because the index is returned by `get_index`");
*value_ref = Dynamic::from(value); *value_ref = Dynamic::from(value);
} }
} }
@ -464,12 +458,12 @@ impl<'a> Scope<'a> {
/// let mut my_scope = Scope::new(); /// let mut my_scope = Scope::new();
/// ///
/// my_scope.push("x", 42_i64); /// my_scope.push("x", 42_i64);
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 42);
/// ///
/// let ptr = my_scope.get_mut("x").unwrap(); /// let ptr = my_scope.get_mut("x").expect("x should exist");
/// *ptr = 123_i64.into(); /// *ptr = 123_i64.into();
/// ///
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 123); /// assert_eq!(my_scope.get_value::<i64>("x").expect("x should exist"), 123);
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
@ -488,9 +482,7 @@ impl<'a> Scope<'a> {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn get_mut_by_index(&mut self, index: usize) -> &mut Dynamic { pub(crate) fn get_mut_by_index(&mut self, index: usize) -> &mut Dynamic {
self.values self.values.get_mut(index).expect("index is out of bounds")
.get_mut(index)
.expect("never fails unless the index is out of bounds")
} }
/// Update the access type of an entry in the [`Scope`]. /// Update the access type of an entry in the [`Scope`].
/// ///
@ -500,10 +492,7 @@ impl<'a> Scope<'a> {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline] #[inline]
pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self { pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self {
let (_, aliases) = self let (_, aliases) = self.names.get_mut(index).expect("index is out of bounds");
.names
.get_mut(index)
.expect("never fails unless the index is out of bounds");
match aliases { match aliases {
None => { None => {
let mut list = StaticVec::new(); let mut list = StaticVec::new();
@ -563,12 +552,12 @@ impl<'a> Scope<'a> {
/// ///
/// let mut iter = my_scope.iter(); /// let mut iter = my_scope.iter();
/// ///
/// let (name, is_constant, value) = iter.next().unwrap(); /// let (name, is_constant, value) = iter.next().expect("value should exist");
/// assert_eq!(name, "x"); /// assert_eq!(name, "x");
/// assert!(!is_constant); /// assert!(!is_constant);
/// assert_eq!(value.cast::<i64>(), 42); /// assert_eq!(value.cast::<i64>(), 42);
/// ///
/// let (name, is_constant, value) = iter.next().unwrap(); /// let (name, is_constant, value) = iter.next().expect("value should exist");
/// assert_eq!(name, "foo"); /// assert_eq!(name, "foo");
/// assert!(is_constant); /// assert!(is_constant);
/// assert_eq!(value.cast::<String>(), "hello"); /// assert_eq!(value.cast::<String>(), "hello");

View File

@ -568,7 +568,7 @@ where
) -> Result<V::Value, Box<EvalAltResult>> { ) -> Result<V::Value, Box<EvalAltResult>> {
// Deserialize each value item coming out of the iterator. // Deserialize each value item coming out of the iterator.
seed.deserialize(&mut DynamicDeserializer::from_dynamic( seed.deserialize(&mut DynamicDeserializer::from_dynamic(
self.values.next().unwrap(), self.values.next().expect("value should exist"),
)) ))
} }
} }

View File

@ -53,21 +53,27 @@ struct FnParam {
impl PartialOrd for FnParam { impl PartialOrd for FnParam {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(match self.name.partial_cmp(&other.name).unwrap() { Some(
Ordering::Less => Ordering::Less, match self
Ordering::Greater => Ordering::Greater, .name
Ordering::Equal => match (self.typ.is_none(), other.typ.is_none()) { .partial_cmp(&other.name)
(true, true) => Ordering::Equal, .expect("String::partial_cmp should succeed")
(true, false) => Ordering::Greater, {
(false, true) => Ordering::Less, Ordering::Less => Ordering::Less,
(false, false) => self Ordering::Greater => Ordering::Greater,
.typ Ordering::Equal => match (self.typ.is_none(), other.typ.is_none()) {
.as_ref() (true, true) => Ordering::Equal,
.unwrap() (true, false) => Ordering::Greater,
.partial_cmp(other.typ.as_ref().unwrap()) (false, true) => Ordering::Less,
.unwrap(), (false, false) => self
.typ
.as_ref()
.expect("`typ` is not `None`")
.partial_cmp(other.typ.as_ref().expect("`typ` is not `None`"))
.expect("String::partial_cmp should succeed"),
},
}, },
}) )
} }
} }
@ -157,7 +163,7 @@ impl From<&crate::module::FuncInfo> for FnMetadata {
{ {
info.func info.func
.get_script_fn_def() .get_script_fn_def()
.expect("never fails because the function is scripted") .expect("scripted function")
.comments .comments
.to_vec() .to_vec()
} }
@ -238,6 +244,7 @@ impl Engine {
if include_global { if include_global {
self.global_modules self.global_modules
.iter() .iter()
.take(self.global_modules.len() - 1)
.flat_map(|m| m.iter_fn()) .flat_map(|m| m.iter_fn())
.for_each(|f| global.functions.push(f.into())); .for_each(|f| global.functions.push(f.into()));
} }
@ -246,7 +253,7 @@ impl Engine {
global.modules.insert(name.to_string(), m.as_ref().into()); global.modules.insert(name.to_string(), m.as_ref().into());
}); });
self.global_namespace self.global_namespace()
.iter_fn() .iter_fn()
.for_each(|f| global.functions.push(f.into())); .for_each(|f| global.functions.push(f.into()));

View File

@ -1207,7 +1207,7 @@ pub fn parse_string_literal(
{ {
let start_position = start let start_position = start
.position() .position()
.expect("never fails because the string must have a starting position"); .expect("string must have starting position");
skip_whitespace_until = start_position + 1; skip_whitespace_until = start_position + 1;
} }
} }
@ -1229,9 +1229,7 @@ pub fn parse_string_literal(
// Whitespace to skip // Whitespace to skip
#[cfg(not(feature = "no_position"))] #[cfg(not(feature = "no_position"))]
_ if next_char.is_whitespace() _ if next_char.is_whitespace()
&& pos && pos.position().expect("character must have position")
.position()
.expect("never fails because a character must have a position")
< skip_whitespace_until => {} < skip_whitespace_until => {}
// All other characters // All other characters
@ -1379,16 +1377,12 @@ fn get_next_token_inner(
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
let return_comment = return_comment let return_comment =
|| is_doc_comment( return_comment || is_doc_comment(comment.as_ref().expect("`include_comments` is true"));
comment
.as_ref()
.expect("never fails because `include_comments` is true"),
);
if return_comment { if return_comment {
return Some(( return Some((
Token::Comment(comment.expect("never fails because `return_comment` is true")), Token::Comment(comment.expect("`return_comment` is true")),
start_pos, start_pos,
)); ));
} }
@ -1440,7 +1434,7 @@ fn get_next_token_inner(
} }
#[cfg(any(not(feature = "no_float"), feature = "decimal"))] #[cfg(any(not(feature = "no_float"), feature = "decimal"))]
'.' => { '.' => {
stream.get_next().expect("never fails because it is `.`"); stream.get_next().expect("it is `.`");
// Check if followed by digits or something that cannot start a property name // Check if followed by digits or something that cannot start a property name
match stream.peek_next().unwrap_or('\0') { match stream.peek_next().unwrap_or('\0') {
@ -1474,7 +1468,7 @@ fn get_next_token_inner(
} }
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
'e' => { 'e' => {
stream.get_next().expect("never fails it is `e`"); stream.get_next().expect("it is `e`");
// Check if followed by digits or +/- // Check if followed by digits or +/-
match stream.peek_next().unwrap_or('\0') { match stream.peek_next().unwrap_or('\0') {
@ -1487,11 +1481,7 @@ fn get_next_token_inner(
'+' | '-' => { '+' | '-' => {
result.push(next_char); result.push(next_char);
pos.advance(); pos.advance();
result.push( result.push(stream.get_next().expect("it is `+` or `-`"));
stream
.get_next()
.expect("never fails because it is `+` or `-`"),
);
pos.advance(); pos.advance();
} }
// Not a floating-point number // Not a floating-point number
@ -1639,7 +1629,7 @@ fn get_next_token_inner(
|(err, err_pos)| (Token::LexError(err), err_pos), |(err, err_pos)| (Token::LexError(err), err_pos),
|(result, _)| { |(result, _)| {
let mut chars = result.chars(); let mut chars = result.chars();
let first = chars.next().unwrap(); let first = chars.next().expect("`chars` is not empty");
if chars.next().is_some() { if chars.next().is_some() {
(Token::LexError(LERR::MalformedChar(result)), start_pos) (Token::LexError(LERR::MalformedChar(result)), start_pos)