Clean up clippy.

This commit is contained in:
Stephen Chung 2022-07-27 16:04:24 +08:00
parent 21f822020f
commit 39dee556c4
36 changed files with 271 additions and 369 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ benches/results
before* before*
after* after*
.rhai-repl-history.txt .rhai-repl-history.txt
clippy.toml

View File

@ -46,6 +46,7 @@ Enhancements
* `FnAccess::is_private`, `FnAccess::is_public`, `FnNamespace::is_module_namespace` and `FnNameSpace::is_global_namespace` are added for convenience. * `FnAccess::is_private`, `FnAccess::is_public`, `FnNamespace::is_module_namespace` and `FnNameSpace::is_global_namespace` are added for convenience.
* `Iterator<Item=T>` type for functions metadata is simplified to `Iterator<T>`. * `Iterator<Item=T>` type for functions metadata is simplified to `Iterator<T>`.
* `Scope::remove` is added to remove a variable from a `Scope`, returning its value. * `Scope::remove` is added to remove a variable from a `Scope`, returning its value.
* The code base is cleaner by running it through Clippy.
Version 1.8.0 Version 1.8.0

View File

@ -149,25 +149,23 @@ pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {
for attr in attrs { for attr in attrs {
if let Some(i) = attr.path.get_ident() { if let Some(i) = attr.path.get_ident() {
if *i == "doc" { if *i == "doc" {
match attr.parse_meta()? { if let syn::Meta::NameValue(syn::MetaNameValue {
syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s),
lit: syn::Lit::Str(s), ..
.. }) = attr.parse_meta()?
}) => { {
let mut line = s.value(); let mut line = s.value();
if line.contains('\n') { if line.contains('\n') {
// Must be a block comment `/** ... */` // Must be a block comment `/** ... */`
line.insert_str(0, "/**"); line.insert_str(0, "/**");
line.push_str("*/"); line.push_str("*/");
} else { } else {
// Single line - assume it is `///` // Single line - assume it is `///`
line.insert_str(0, "///"); line.insert_str(0, "///");
}
comments.push(line);
} }
_ => (),
comments.push(line);
} }
} }
} }

View File

@ -302,18 +302,15 @@ impl Parse for ExportedFn {
let visibility = fn_all.vis; let visibility = fn_all.vis;
// Determine if the function requires a call context // Determine if the function requires a call context
match fn_all.sig.inputs.first() { if let Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) = fn_all.sig.inputs.first() {
Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) => { match flatten_type_groups(ty.as_ref()) {
match flatten_type_groups(ty.as_ref()) { syn::Type::Path(p)
syn::Type::Path(p) if p.path == context_type_path1 || p.path == context_type_path2 =>
if p.path == context_type_path1 || p.path == context_type_path2 => {
{ pass_context = true;
pass_context = true;
}
_ => {}
} }
_ => {}
} }
_ => {}
} }
let skip_slots = if pass_context { 1 } else { 0 }; let skip_slots = if pass_context { 1 } else { 0 };
@ -378,25 +375,22 @@ impl Parse for ExportedFn {
} }
// Check return type. // Check return type.
match fn_all.sig.output { if let syn::ReturnType::Type(.., ref ret_type) = fn_all.sig.output {
syn::ReturnType::Type(.., ref ret_type) => { match flatten_type_groups(ret_type.as_ref()) {
match flatten_type_groups(ret_type.as_ref()) { syn::Type::Ptr(..) => {
syn::Type::Ptr(..) => { return Err(syn::Error::new(
return Err(syn::Error::new( fn_all.sig.output.span(),
fn_all.sig.output.span(), "Rhai functions cannot return pointers",
"Rhai functions cannot return pointers", ))
))
}
syn::Type::Reference(..) => {
return Err(syn::Error::new(
fn_all.sig.output.span(),
"Rhai functions cannot return references",
))
}
_ => {}
} }
syn::Type::Reference(..) => {
return Err(syn::Error::new(
fn_all.sig.output.span(),
"Rhai functions cannot return references",
))
}
_ => {}
} }
_ => {}
} }
Ok(ExportedFn { Ok(ExportedFn {
entire_span, entire_span,

View File

@ -138,38 +138,38 @@ impl Parse for Module {
})?; })?;
// Gather and parse constants definitions. // Gather and parse constants definitions.
for item in &*content { for item in &*content {
match item { if let syn::Item::Const(syn::ItemConst {
syn::Item::Const(syn::ItemConst { vis: syn::Visibility::Public(..),
vis: syn::Visibility::Public(..), ref expr,
ref expr, ident,
ident, attrs,
attrs, ty,
ty, ..
.. }) = item
}) => consts.push(ExportedConst { {
consts.push(ExportedConst {
name: ident.to_string(), name: ident.to_string(),
typ: ty.clone(), typ: ty.clone(),
expr: expr.as_ref().clone(), expr: expr.as_ref().clone(),
cfg_attrs: crate::attrs::collect_cfg_attr(attrs), cfg_attrs: crate::attrs::collect_cfg_attr(attrs),
}), })
_ => {}
} }
} }
// Gather and parse type definitions. // Gather and parse type definitions.
for item in &*content { for item in &*content {
match item { if let syn::Item::Type(syn::ItemType {
syn::Item::Type(syn::ItemType { vis: syn::Visibility::Public(..),
vis: syn::Visibility::Public(..), ident,
ident, attrs,
attrs, ty,
ty, ..
.. }) = item
}) => custom_types.push(ExportedType { {
custom_types.push(ExportedType {
name: ident.to_string(), name: ident.to_string(),
typ: ty.clone(), typ: ty.clone(),
cfg_attrs: crate::attrs::collect_cfg_attr(attrs), cfg_attrs: crate::attrs::collect_cfg_attr(attrs),
}), })
_ => {}
} }
} }
// Gather and parse sub-module definitions. // Gather and parse sub-module definitions.

View File

@ -270,11 +270,10 @@ impl Engine {
// 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.is_empty() && self.disabled_symbols.contains(s)) if (!self.disabled_symbols.is_empty() && self.disabled_symbols.contains(s))
|| token.map_or(false, |v| v.is_reserved()) || token.map_or(false, |v| v.is_reserved())
&& self.custom_keywords.is_empty()
|| !self.custom_keywords.contains_key(s)
{ {
if self.custom_keywords.is_empty() || !self.custom_keywords.contains_key(s) self.custom_keywords.insert(s.into(), None);
{
self.custom_keywords.insert(s.into(), None);
}
} }
s.into() s.into()
} }

View File

@ -28,7 +28,6 @@ impl Engine {
/// # } /// # }
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use]
pub fn definitions(&self) -> Definitions { pub fn definitions(&self) -> Definitions {
Definitions { Definitions {
engine: self, engine: self,
@ -54,7 +53,6 @@ impl Engine {
/// # } /// # }
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use]
pub fn definitions_with_scope<'e>(&'e self, scope: &'e Scope<'e>) -> Definitions<'e> { pub fn definitions_with_scope<'e>(&'e self, scope: &'e Scope<'e>) -> Definitions<'e> {
Definitions { Definitions {
engine: self, engine: self,
@ -112,7 +110,6 @@ impl<'e> Definitions<'e> {
/// ///
/// The returned iterator yields all definition files as (filename, content) pairs. /// The returned iterator yields all definition files as (filename, content) pairs.
#[inline] #[inline]
#[must_use]
pub fn iter_files(&self) -> impl Iterator<Item = (String, String)> + '_ { pub fn iter_files(&self) -> impl Iterator<Item = (String, String)> + '_ {
IntoIterator::into_iter([ IntoIterator::into_iter([
( (
@ -182,7 +179,6 @@ impl<'e> Definitions<'e> {
/// ///
/// Always starts with `module <module name>;`. /// Always starts with `module <module name>;`.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[must_use]
pub fn modules(&self) -> impl Iterator<Item = (String, String)> + '_ { pub fn modules(&self) -> impl Iterator<Item = (String, String)> + '_ {
let mut m = self let mut m = self
.engine .engine

View File

@ -9,24 +9,24 @@ bitflags! {
/// Bit-flags containing all language options for the [`Engine`]. /// Bit-flags containing all language options for the [`Engine`].
pub struct LangOptions: u8 { pub struct LangOptions: u8 {
/// Is `if`-expression allowed? /// Is `if`-expression allowed?
const IF_EXPR = 0b_00000001; const IF_EXPR = 0b_0000_0001;
/// Is `switch` expression allowed? /// Is `switch` expression allowed?
const SWITCH_EXPR = 0b_00000010; const SWITCH_EXPR = 0b_0000_0010;
/// Is statement-expression allowed? /// Is statement-expression allowed?
const STMT_EXPR = 0b_00000100; const STMT_EXPR = 0b_0000_0100;
/// Is anonymous function allowed? /// Is anonymous function allowed?
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
const ANON_FN = 0b_00001000; const ANON_FN = 0b_0000_1000;
/// Is looping allowed? /// Is looping allowed?
const LOOPING = 0b_00010000; const LOOPING = 0b_0001_0000;
/// Is variables shadowing allowed? /// Is variables shadowing allowed?
const SHADOW = 0b_00100000; const SHADOW = 0b_0010_0000;
/// Strict variables mode? /// Strict variables mode?
const STRICT_VAR = 0b_01000000; const STRICT_VAR = 0b_0100_0000;
/// Raise error if an object map property does not exist? /// Raise error if an object map property does not exist?
/// Returns `()` if `false`. /// Returns `()` if `false`.
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
const FAIL_ON_INVALID_MAP_PROPERTY = 0b_10000000; const FAIL_ON_INVALID_MAP_PROPERTY = 0b_1000_0000;
} }
} }

View File

@ -144,9 +144,9 @@ impl Engine {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn format_type_name<'a>(&'a self, name: &'a str) -> std::borrow::Cow<'a, str> { pub(crate) fn format_type_name<'a>(&'a self, name: &'a str) -> std::borrow::Cow<'a, str> {
if name.starts_with("&mut ") { if let Some(x) = name.strip_prefix("&mut ") {
let x = &name[5..];
let r = self.format_type_name(x); let r = self.format_type_name(x);
return if x != r { return if x != r {
format!("&mut {}", r).into() format!("&mut {}", r).into()
} else { } else {
@ -167,9 +167,9 @@ impl Engine {
return None; return None;
}) })
.unwrap_or_else(|| match name { .unwrap_or_else(|| match name {
"INT" => return type_name::<crate::INT>(), "INT" => type_name::<crate::INT>(),
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
"FLOAT" => return type_name::<crate::FLOAT>(), "FLOAT" => type_name::<crate::FLOAT>(),
_ => map_std_type_name(name, false), _ => map_std_type_name(name, false),
}) })
.into() .into()

View File

@ -158,19 +158,13 @@ impl ConditionalExpr {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_always_true(&self) -> bool { pub fn is_always_true(&self) -> bool {
match self.condition { matches!(self.condition, Expr::BoolConstant(true, ..))
Expr::BoolConstant(true, ..) => true,
_ => false,
}
} }
/// Is the condition always `false`? /// Is the condition always `false`?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_always_false(&self) -> bool { pub fn is_always_false(&self) -> bool {
match self.condition { matches!(self.condition, Expr::BoolConstant(false, ..))
Expr::BoolConstant(false, ..) => true,
_ => false,
}
} }
} }
@ -388,7 +382,6 @@ impl StmtBlock {
} }
/// Get an iterator over the statements of this statements block. /// Get an iterator over the statements of this statements block.
#[inline(always)] #[inline(always)]
#[must_use]
pub fn iter(&self) -> impl Iterator<Item = &Stmt> { pub fn iter(&self) -> impl Iterator<Item = &Stmt> {
self.block.iter() self.block.iter()
} }

View File

@ -29,7 +29,7 @@ fn print_source(lines: &[String], pos: Position, offset: usize, window: (usize,
println!("{0:>1$}", "^", pos + offset + line_no_len + 2); println!("{0:>1$}", "^", pos + offset + line_no_len + 2);
} }
} else { } else {
for n in start..=end { for (n, s) in lines.iter().enumerate().take(end + 1).skip(start) {
let marker = if n == line { "> " } else { " " }; let marker = if n == line { "> " } else { " " };
println!( println!(
@ -38,7 +38,7 @@ fn print_source(lines: &[String], pos: Position, offset: usize, window: (usize,
marker, marker,
n + 1, n + 1,
line_no_len, line_no_len,
lines[n], s,
if n == line { "\x1b[39m" } else { "" }, if n == line { "\x1b[39m" } else { "" },
); );
@ -161,7 +161,7 @@ fn print_debug_help() {
// Load script to debug. // Load script to debug.
fn load_script(engine: &Engine) -> (rhai::AST, String) { fn load_script(engine: &Engine) -> (rhai::AST, String) {
if let Some(filename) = env::args().skip(1).next() { if let Some(filename) = env::args().nth(1) {
let mut contents = String::new(); let mut contents = String::new();
let filename = match Path::new(&filename).canonicalize() { let filename = match Path::new(&filename).canonicalize() {
@ -301,12 +301,7 @@ fn debug_callback(
match stdin().read_line(&mut input) { match stdin().read_line(&mut input) {
Ok(0) => break Ok(DebuggerCommand::Continue), Ok(0) => break Ok(DebuggerCommand::Continue),
Ok(_) => match input Ok(_) => match input.split_whitespace().collect::<Vec<_>>().as_slice() {
.trim()
.split_whitespace()
.collect::<Vec<_>>()
.as_slice()
{
["help" | "h"] => print_debug_help(), ["help" | "h"] => print_debug_help(),
["exit" | "quit" | "q" | "kill", ..] => { ["exit" | "quit" | "q" | "kill", ..] => {
println!("Script terminated. Bye!"); println!("Script terminated. Bye!");
@ -328,14 +323,14 @@ fn debug_callback(
["source"] => { ["source"] => {
println!("{}", context.global_runtime_state().source().unwrap_or("")) println!("{}", context.global_runtime_state().source().unwrap_or(""))
} }
["list" | "l"] => print_current_source(&mut context, source, pos, &lines, (3, 6)), ["list" | "l"] => print_current_source(&mut context, source, pos, lines, (3, 6)),
["list" | "l", n] if n.parse::<usize>().is_ok() => { ["list" | "l", n] if n.parse::<usize>().is_ok() => {
let num = n.parse::<usize>().unwrap(); let num = n.parse::<usize>().unwrap();
if num <= 0 || num > lines.len() { if num == 0 || num > lines.len() {
eprintln!("\x1b[31mInvalid line: {}\x1b[39m", num); eprintln!("\x1b[31mInvalid line: {}\x1b[39m", num);
} else { } else {
let pos = Position::new(num as u16, 0); let pos = Position::new(num as u16, 0);
print_current_source(&mut context, source, pos, &lines, (3, 6)); print_current_source(&mut context, source, pos, lines, (3, 6));
} }
} }
["continue" | "c"] => break Ok(DebuggerCommand::Continue), ["continue" | "c"] => break Ok(DebuggerCommand::Continue),
@ -405,7 +400,7 @@ fn debug_callback(
rhai::debugger::BreakPoint::AtPosition { pos, .. } => { rhai::debugger::BreakPoint::AtPosition { pos, .. } => {
let line_num = format!("[{}] line ", i + 1); let line_num = format!("[{}] line ", i + 1);
print!("{}", line_num); print!("{}", line_num);
print_source(&lines, *pos, line_num.len(), (0, 0)); print_source(lines, *pos, line_num.len(), (0, 0));
} }
_ => println!("[{}] {}", i + 1, bp), _ => println!("[{}] {}", i + 1, bp),
}, },
@ -580,7 +575,7 @@ fn debug_callback(
break Err(EvalAltResult::ErrorRuntime(value, pos).into()); break Err(EvalAltResult::ErrorRuntime(value, pos).into());
} }
["throw", ..] => { ["throw", ..] => {
let msg = input.trim().splitn(2, ' ').skip(1).next().unwrap_or(""); let msg = input.trim().split_once(' ').map(|(_, x)| x).unwrap_or("");
break Err(EvalAltResult::ErrorRuntime(msg.trim().into(), pos).into()); break Err(EvalAltResult::ErrorRuntime(msg.trim().into(), pos).into());
} }
["run" | "r"] => { ["run" | "r"] => {

View File

@ -158,7 +158,7 @@ fn load_script_files(engine: &mut Engine) {
.map_err(|err| err.into()) .map_err(|err| err.into())
.and_then(|mut ast| { .and_then(|mut ast| {
ast.set_source(filename.to_string_lossy().to_string()); ast.set_source(filename.to_string_lossy().to_string());
Module::eval_ast_as_new(Scope::new(), &ast, &engine) Module::eval_ast_as_new(Scope::new(), &ast, engine)
}) { }) {
Err(err) => { Err(err) => {
let filename = filename.to_string_lossy(); let filename = filename.to_string_lossy();
@ -166,7 +166,7 @@ fn load_script_files(engine: &mut Engine) {
eprintln!("{:=<1$}", "", filename.len()); eprintln!("{:=<1$}", "", filename.len());
eprintln!("{}", filename); eprintln!("{}", filename);
eprintln!("{:=<1$}", "", filename.len()); eprintln!("{:=<1$}", "", filename.len());
eprintln!(""); eprintln!();
print_error(&contents, *err); print_error(&contents, *err);
exit(1); exit(1);
@ -353,7 +353,7 @@ fn main() {
match rl.readline(prompt) { match rl.readline(prompt) {
// Line continuation // Line continuation
Ok(mut line) if line.ends_with("\\") => { Ok(mut line) if line.ends_with('\\') => {
line.pop(); line.pop();
input += &line; input += &line;
input.push('\n'); input.push('\n');
@ -361,10 +361,12 @@ fn main() {
Ok(line) => { Ok(line) => {
input += &line; input += &line;
let cmd = input.trim(); let cmd = input.trim();
if !cmd.is_empty() && !cmd.starts_with('!') && cmd.trim() != "history" { if !cmd.is_empty()
if rl.add_history_entry(input.clone()) { && !cmd.starts_with('!')
history_offset += 1; && cmd.trim() != "history"
} && rl.add_history_entry(input.clone())
{
history_offset += 1;
} }
break; break;
} }

View File

@ -14,7 +14,7 @@ fn eprint_error(input: &str, mut err: EvalAltResult) {
line_no.len() + pos.position().unwrap(), line_no.len() + pos.position().unwrap(),
err_msg err_msg
); );
eprintln!(""); eprintln!();
} }
let lines: Vec<_> = input.split('\n').collect(); let lines: Vec<_> = input.split('\n').collect();
@ -96,7 +96,7 @@ fn main() {
eprintln!("{:=<1$}", "", filename.len()); eprintln!("{:=<1$}", "", filename.len());
eprintln!("{}", filename); eprintln!("{}", filename);
eprintln!("{:=<1$}", "", filename.len()); eprintln!("{:=<1$}", "", filename.len());
eprintln!(""); eprintln!();
eprint_error(contents, *err); eprint_error(contents, *err);
} }

View File

@ -322,22 +322,19 @@ impl Engine {
/// Check a result to ensure that it is valid. /// Check a result to ensure that it is valid.
pub(crate) fn check_return_value(&self, mut result: RhaiResult, _pos: Position) -> RhaiResult { pub(crate) fn check_return_value(&self, mut result: RhaiResult, _pos: Position) -> RhaiResult {
match result { if let Ok(ref mut r) = result {
Ok(ref mut r) => { // Concentrate all empty strings into one instance to save memory
// Concentrate all empty strings into one instance to save memory if let Dynamic(Union::Str(s, ..)) = r {
if let Dynamic(Union::Str(s, ..)) = r { if s.is_empty() {
if s.is_empty() { if !s.ptr_eq(&self.empty_string) {
if !s.ptr_eq(&self.empty_string) { *s = self.const_empty_string();
*s = self.const_empty_string();
}
return result;
} }
return result;
} }
#[cfg(not(feature = "unchecked"))]
self.check_data_size(r, _pos)?;
} }
_ => (),
#[cfg(not(feature = "unchecked"))]
self.check_data_size(r, _pos)?;
} }
result result

View File

@ -980,8 +980,8 @@ impl Engine {
})?, })?,
offset, offset,
) )
} else if let Some(abs_index) = index.checked_abs() { } else {
let offset = abs_index as usize; let offset = index.unsigned_abs() as usize;
( (
// Count from end if negative // Count from end if negative
s.chars().rev().nth(offset - 1).ok_or_else(|| { s.chars().rev().nth(offset - 1).ok_or_else(|| {
@ -990,9 +990,6 @@ impl Engine {
})?, })?,
offset, offset,
) )
} else {
let chars_len = s.chars().count();
return Err(ERR::ErrorStringBounds(chars_len, index, idx_pos).into());
}; };
Ok(Target::StringChar { Ok(Target::StringChar {

View File

@ -441,7 +441,6 @@ impl Engine {
/// ///
/// It is up to the [`Engine`] to reactivate the debugger. /// It is up to the [`Engine`] to reactivate the debugger.
#[inline(always)] #[inline(always)]
#[must_use]
pub(crate) fn run_debugger_with_reset<'a>( pub(crate) fn run_debugger_with_reset<'a>(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
@ -464,7 +463,6 @@ impl Engine {
/// ///
/// It is up to the [`Engine`] to reactivate the debugger. /// It is up to the [`Engine`] to reactivate the debugger.
#[inline] #[inline]
#[must_use]
pub(crate) fn run_debugger_with_reset_raw<'a>( pub(crate) fn run_debugger_with_reset_raw<'a>(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
@ -514,7 +512,6 @@ impl Engine {
/// ///
/// It is up to the [`Engine`] to reactivate the debugger. /// It is up to the [`Engine`] to reactivate the debugger.
#[inline] #[inline]
#[must_use]
pub(crate) fn run_debugger_raw<'a>( pub(crate) fn run_debugger_raw<'a>(
&self, &self,
scope: &mut Scope, scope: &mut Scope,

View File

@ -15,9 +15,7 @@ use std::prelude::v1::*;
#[allow(dead_code)] #[allow(dead_code)]
pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) { pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) {
let start = if start < 0 { let start = if start < 0 {
start.checked_abs().map_or(0, |positive_start| { length - usize::min(start.unsigned_abs() as usize, length)
length - usize::min(positive_start as usize, length)
})
} else if start as usize >= length { } else if start as usize >= length {
return (length, 0); return (length, 0);
} else { } else {
@ -50,20 +48,14 @@ pub fn calc_index<E>(
) -> Result<usize, E> { ) -> Result<usize, E> {
if start < 0 { if start < 0 {
if negative_count_from_end { if negative_count_from_end {
let abs_start = start.unsigned_abs() as usize;
// Count from end if negative // Count from end if negative
#[cfg(not(feature = "unchecked"))] if abs_start > length {
return match start.checked_abs() { err()
Some(positive_start) => { } else {
if (positive_start as usize) > length { Ok(length - abs_start)
err() }
} else {
Ok(length - (positive_start as usize))
}
}
None => err(),
};
#[cfg(feature = "unchecked")]
return Ok(length - (start.abs() as usize));
} else { } else {
err() err()
} }

View File

@ -453,7 +453,7 @@ impl Engine {
// Check the data size of any `&mut` object, which may be changed. // Check the data size of any `&mut` object, which may be changed.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if is_ref_mut && args.len() > 0 { if is_ref_mut && !args.is_empty() {
self.check_data_size(args[0], pos)?; self.check_data_size(args[0], pos)?;
} }
@ -1180,7 +1180,7 @@ impl Engine {
if capture_scope && !scope.is_empty() { if capture_scope && !scope.is_empty() {
first_arg first_arg
.iter() .iter()
.map(|&v| v) .copied()
.chain(a_expr.iter()) .chain(a_expr.iter())
.try_for_each(|expr| { .try_for_each(|expr| {
self.get_arg_value(scope, global, caches, lib, this_ptr, expr, level) self.get_arg_value(scope, global, caches, lib, this_ptr, expr, level)

View File

@ -173,10 +173,10 @@ pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 {
pub fn calc_fn_params_hash(params: impl IntoIterator<Item = TypeId>) -> u64 { pub fn calc_fn_params_hash(params: impl IntoIterator<Item = TypeId>) -> u64 {
let s = &mut get_hasher(); let s = &mut get_hasher();
let mut len = 0; let mut len = 0;
params params.into_iter().for_each(|t| {
.into_iter() len += 1;
.inspect(|_| len += 1) t.hash(s)
.for_each(|t| t.hash(s)); });
len.hash(s); len.hash(s);
match s.finish() { match s.finish() {

View File

@ -37,17 +37,14 @@ pub use std::sync::Arc as Shared;
/// Synchronized shared object. /// Synchronized shared object.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
#[allow(dead_code)]
pub use std::cell::RefCell as Locked; pub use std::cell::RefCell as Locked;
/// Read-only lock guard for synchronized shared object. /// Read-only lock guard for synchronized shared object.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
#[allow(dead_code)]
pub type LockGuard<'a, T> = std::cell::Ref<'a, T>; pub type LockGuard<'a, T> = std::cell::Ref<'a, T>;
/// Mutable lock guard for synchronized shared object. /// Mutable lock guard for synchronized shared object.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
#[allow(dead_code)]
pub type LockGuardMut<'a, T> = std::cell::RefMut<'a, T>; pub type LockGuardMut<'a, T> = std::cell::RefMut<'a, T>;
/// Synchronized shared object. /// Synchronized shared object.
@ -397,7 +394,7 @@ pub fn shared_take<T>(value: Shared<T>) -> T {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
#[allow(dead_code)] #[allow(dead_code)]
pub fn locked_read<'a, T>(value: &'a Locked<T>) -> LockGuard<'a, T> { pub fn locked_read<T>(value: &Locked<T>) -> LockGuard<T> {
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
return value.borrow(); return value.borrow();
@ -409,7 +406,7 @@ pub fn locked_read<'a, T>(value: &'a Locked<T>) -> LockGuard<'a, T> {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
#[allow(dead_code)] #[allow(dead_code)]
pub fn locked_write<'a, T>(value: &'a Locked<T>) -> LockGuardMut<'a, T> { pub fn locked_write<T>(value: &Locked<T>) -> LockGuardMut<T> {
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
return value.borrow_mut(); return value.borrow_mut();

View File

@ -56,7 +56,7 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
// 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.
return mem::take(data).cast::<T>(); mem::take(data).cast::<T>()
} }
/// Trait to register custom Rust functions. /// Trait to register custom Rust functions.

View File

@ -88,7 +88,7 @@ impl Engine {
let orig_call_stack_len = global.debugger.call_stack().len(); let orig_call_stack_len = global.debugger.call_stack().len();
// Put arguments into scope as variables // Put arguments into scope as variables
scope.extend(fn_def.params.iter().cloned().zip(args.into_iter().map(|v| { scope.extend(fn_def.params.iter().cloned().zip(args.iter_mut().map(|v| {
// Actually consume the arguments instead of cloning them // Actually consume the arguments instead of cloning them
mem::take(*v) mem::take(*v)
}))); })));
@ -98,11 +98,7 @@ impl Engine {
if self.debugger.is_some() { if self.debugger.is_some() {
global.debugger.push_call_stack_frame( global.debugger.push_call_stack_frame(
fn_def.name.clone(), fn_def.name.clone(),
scope scope.iter().skip(orig_scope_len).map(|(.., v)| v).collect(),
.iter()
.skip(orig_scope_len)
.map(|(.., v)| v.clone())
.collect(),
global.source.clone(), global.source.clone(),
pos, pos,
); );

View File

@ -58,6 +58,7 @@
#![cfg_attr(feature = "no_std", no_std)] #![cfg_attr(feature = "no_std", no_std)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![allow(clippy::unit_arg)]
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
extern crate alloc; extern crate alloc;

View File

@ -128,10 +128,9 @@ impl FuncInfo {
let typ = typ.trim(); let typ = typ.trim();
if typ.starts_with("rhai::") { if let Some(x) = typ.strip_prefix("rhai::") {
return Self::format_type(&typ[6..], is_return_type); return Self::format_type(x, is_return_type);
} else if typ.starts_with("&mut ") { } else if let Some(x) = typ.strip_prefix("&mut ") {
let x = &typ[5..];
let r = Self::format_type(x, false); let r = Self::format_type(x, false);
return if r == x { return if r == x {
typ.into() typ.into()
@ -1896,7 +1895,6 @@ impl Module {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]
#[must_use]
pub fn iter_script_fn_info( pub fn iter_script_fn_info(
&self, &self,
) -> impl Iterator< ) -> impl Iterator<

View File

@ -20,6 +20,7 @@ use std::{ops::AddAssign, slice::Iter, vec::IntoIter};
/// let mut engine = Engine::new(); /// let mut engine = Engine::new();
/// engine.set_module_resolver(collection); /// engine.set_module_resolver(collection);
/// ``` /// ```
#[derive(Default)]
pub struct ModuleResolversCollection(Vec<Box<dyn ModuleResolver>>); pub struct ModuleResolversCollection(Vec<Box<dyn ModuleResolver>>);
impl ModuleResolversCollection { impl ModuleResolversCollection {
@ -41,7 +42,7 @@ impl ModuleResolversCollection {
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new() -> Self { pub const fn new() -> Self {
Self(Vec::new()) Self(Vec::new())
} }
/// Append a [module resolver][ModuleResolver] to the end. /// Append a [module resolver][ModuleResolver] to the end.

View File

@ -374,7 +374,7 @@ impl ModuleResolver for FileModuleResolver {
pos: Position, pos: Position,
) -> Option<RhaiResultOf<crate::AST>> { ) -> Option<RhaiResultOf<crate::AST>> {
// Construct the script file path // Construct the script file path
let file_path = self.get_file_path(path, source_path.map(|s| Path::new(s))); let file_path = self.get_file_path(path, source_path.map(Path::new));
// Load the script file and compile it // Load the script file and compile it
Some( Some(

View File

@ -212,26 +212,21 @@ fn optimize_stmt_block(
}; };
// Flatten blocks // Flatten blocks
loop { while let Some(n) = statements.iter().position(
if let Some(n) = statements.iter().position(|s| match s { |s| matches!(s, Stmt::Block(block, ..) if !block.iter().any(Stmt::is_block_dependent)),
Stmt::Block(block, ..) if !block.iter().any(Stmt::is_block_dependent) => true, ) {
_ => false, let (first, second) = statements.split_at_mut(n);
}) { let stmt = mem::take(&mut second[0]);
let (first, second) = statements.split_at_mut(n); let mut stmts = match stmt {
let stmt = mem::take(&mut second[0]); Stmt::Block(block, ..) => block,
let mut stmts = match stmt { stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
Stmt::Block(block, ..) => block, };
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt), statements = first
}; .iter_mut()
statements = first .map(mem::take)
.iter_mut() .chain(stmts.iter_mut().map(mem::take))
.map(mem::take) .chain(second.iter_mut().skip(1).map(mem::take))
.chain(stmts.iter_mut().map(mem::take)) .collect();
.chain(second.iter_mut().skip(1).map(mem::take))
.collect();
} else {
break;
}
is_dirty = true; is_dirty = true;
} }
@ -606,7 +601,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
.iter() .iter()
.all(|r| expressions[r.index()].is_always_true()) .all(|r| expressions[r.index()].is_always_true())
{ {
for r in ranges.iter().filter(|r| r.contains(value)) { if let Some(r) = ranges.iter().find(|r| r.contains(value)) {
let range_block = &mut expressions[r.index()]; let range_block = &mut expressions[r.index()];
if range_block.is_always_true() { if range_block.is_always_true() {
@ -698,11 +693,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
optimize_expr(&mut b.condition, state, false); optimize_expr(&mut b.condition, state, false);
optimize_expr(&mut b.expr, state, false); optimize_expr(&mut b.expr, state, false);
if b.is_always_false() { if b.is_always_false() && !b.expr.is_unit() {
if !b.expr.is_unit() { b.expr = Expr::Unit(b.expr.position());
b.expr = Expr::Unit(b.expr.position()); state.set_dirty();
state.set_dirty();
}
} }
} }
@ -958,10 +951,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
***x = optimize_stmt_block(mem::take(&mut **x), state, true, true, false); ***x = optimize_stmt_block(mem::take(&mut **x), state, true, true, false);
// { Stmt(Expr) } - promote // { Stmt(Expr) } - promote
match &mut ****x { if let [ Stmt::Expr(e) ] = &mut ****x { state.set_dirty(); *expr = mem::take(e); }
[ Stmt::Expr(e) ] => { state.set_dirty(); *expr = mem::take(e); }
_ => ()
}
} }
// ()?.rhs // ()?.rhs
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -1010,11 +1000,11 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
*expr = result; *expr = result;
} }
// array[-int] // array[-int]
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|n| n as usize <= a.len()).unwrap_or(false) && a.iter().all(Expr::is_pure) => { (Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= a.len() && a.iter().all(Expr::is_pure) => {
// Array literal where everything is pure - promote the indexed item. // Array literal where everything is pure - promote the indexed item.
// All other items can be thrown away. // All other items can be thrown away.
state.set_dirty(); state.set_dirty();
let index = a.len() - i.abs() as usize; let index = a.len() - i.unsigned_abs() as usize;
let mut result = mem::take(&mut a[index]); let mut result = mem::take(&mut a[index]);
result.set_position(*pos); result.set_position(*pos);
*expr = result; *expr = result;
@ -1035,10 +1025,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
*expr = Expr::BoolConstant((*n & (1 << (*i as usize))) != 0, *pos); *expr = Expr::BoolConstant((*n & (1 << (*i as usize))) != 0, *pos);
} }
// int[-int] // int[-int]
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|i| i as usize <= crate::INT_BITS).unwrap_or(false) => { (Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= crate::INT_BITS => {
// Bit-field literal indexing - get the bit // Bit-field literal indexing - get the bit
state.set_dirty(); state.set_dirty();
*expr = Expr::BoolConstant((*n & (1 << (crate::INT_BITS - i.abs() as usize))) != 0, *pos); *expr = Expr::BoolConstant((*n & (1 << (crate::INT_BITS - i.unsigned_abs() as usize))) != 0, *pos);
} }
// string[int] // string[int]
(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() => {
@ -1047,10 +1037,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos); *expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *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.unsigned_abs() 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().rev().nth(i.abs() as usize - 1).unwrap(), *pos); *expr = Expr::CharConstant(s.chars().rev().nth(i.unsigned_abs() as usize - 1).unwrap(), *pos);
} }
// var[rhs] // var[rhs]
(Expr::Variable(..), rhs) => optimize_expr(rhs, state, true), (Expr::Variable(..), rhs) => optimize_expr(rhs, state, true),

View File

@ -290,7 +290,7 @@ pub mod array_functions {
if array.is_empty() { if array.is_empty() {
Dynamic::UNIT Dynamic::UNIT
} else { } else {
array.pop().unwrap_or_else(|| Dynamic::UNIT) array.pop().unwrap_or(Dynamic::UNIT)
} }
} }
/// Remove the first element from the array and return it. /// Remove the first element from the array and return it.
@ -1344,7 +1344,7 @@ pub mod array_functions {
array.dedup_by(|x, y| { array.dedup_by(|x, y| {
comparer comparer
.call_raw(&ctx, None, [y.clone(), x.clone()]) .call_raw(&ctx, None, [y.clone(), x.clone()])
.unwrap_or_else(|_| Dynamic::FALSE) .unwrap_or(Dynamic::FALSE)
.as_bool() .as_bool()
.unwrap_or(false) .unwrap_or(false)
}); });

View File

@ -96,16 +96,11 @@ impl<T: Debug + Copy + PartialOrd> Iterator for StepRange<T> {
self.from = (self.add)(self.from, self.step)?; self.from = (self.add)(self.from, self.step)?;
if self.dir > 0 { match self.dir.cmp(&0) {
if self.from >= self.to { Ordering::Greater if self.from >= self.to => self.dir = 0,
self.dir = 0; Ordering::Less if self.from <= self.to => self.dir = 0,
} Ordering::Equal => unreachable!("`dir` != 0"),
} else if self.dir < 0 { _ => (),
if self.from <= self.to {
self.dir = 0;
}
} else {
unreachable!("`dir` != 0");
} }
Some(v) Some(v)
@ -184,28 +179,15 @@ impl CharsStream {
0, 0,
); );
} }
#[cfg(not(feature = "unchecked"))]
return if let Some(abs_from) = from.checked_abs() {
let num_chars = string.chars().count();
let offset = if num_chars < (abs_from as usize) {
0
} else {
num_chars - (abs_from as usize)
};
Self(string.chars().skip(offset).take(len as usize).collect(), 0)
} else {
Self(string.chars().skip(0).take(len as usize).collect(), 0)
};
#[cfg(feature = "unchecked")] let abs_from = from.unsigned_abs() as usize;
return Self( let num_chars = string.chars().count();
string let offset = if num_chars < abs_from {
.chars() 0
.skip(from as usize) } else {
.take(len as usize) num_chars - abs_from
.collect(), };
0, Self(string.chars().skip(offset).take(len as usize).collect(), 0)
);
} }
} }

View File

@ -93,7 +93,7 @@ mod map_functions {
/// ``` /// ```
pub fn remove(map: &mut Map, property: &str) -> Dynamic { pub fn remove(map: &mut Map, property: &str) -> Dynamic {
if !map.is_empty() { if !map.is_empty() {
map.remove(property).unwrap_or_else(|| Dynamic::UNIT) map.remove(property).unwrap_or(Dynamic::UNIT)
} else { } else {
Dynamic::UNIT Dynamic::UNIT
} }

View File

@ -534,20 +534,17 @@ mod string_functions {
} }
let start = if start < 0 { let start = if start < 0 {
if let Some(n) = start.checked_abs() { let abs_start = start.unsigned_abs() as usize;
let chars: Vec<_> = string.chars().collect(); let chars: Vec<_> = string.chars().collect();
let num_chars = chars.len(); let num_chars = chars.len();
if n as usize > num_chars { if abs_start > num_chars {
0
} else {
chars
.into_iter()
.take(num_chars - n as usize)
.collect::<String>()
.len()
}
} else {
0 0
} else {
chars
.into_iter()
.take(num_chars - abs_start)
.collect::<String>()
.len()
} }
} else if start == 0 { } else if start == 0 {
0 0
@ -615,20 +612,17 @@ mod string_functions {
} }
let start = if start < 0 { let start = if start < 0 {
if let Some(n) = start.checked_abs() { let abs_start = start.unsigned_abs() as usize;
let chars = string.chars().collect::<Vec<_>>(); let chars = string.chars().collect::<Vec<_>>();
let num_chars = chars.len(); let num_chars = chars.len();
if n as usize > num_chars { if abs_start > num_chars {
0
} else {
chars
.into_iter()
.take(num_chars - n as usize)
.collect::<String>()
.len()
}
} else {
0 0
} else {
chars
.into_iter()
.take(num_chars - abs_start)
.collect::<String>()
.len()
} }
} else if start == 0 { } else if start == 0 {
0 0
@ -694,15 +688,13 @@ mod string_functions {
.chars() .chars()
.nth(index as usize) .nth(index as usize)
.map_or_else(|| Dynamic::UNIT, Into::into) .map_or_else(|| Dynamic::UNIT, Into::into)
} else if let Some(abs_index) = index.checked_abs() { } else {
// Count from end if negative // Count from end if negative
string string
.chars() .chars()
.rev() .rev()
.nth((abs_index as usize) - 1) .nth((index.unsigned_abs() as usize) - 1)
.map_or_else(|| Dynamic::UNIT, Into::into) .map_or_else(|| Dynamic::UNIT, Into::into)
} else {
Dynamic::UNIT
} }
} }
/// Set the `index` position in the string to a new `character`. /// Set the `index` position in the string to a new `character`.
@ -736,11 +728,12 @@ mod string_functions {
.enumerate() .enumerate()
.map(|(i, ch)| if i == index { character } else { ch }) .map(|(i, ch)| if i == index { character } else { ch })
.collect(); .collect();
} else if let Some(abs_index) = index.checked_abs() { } else {
let abs_index = index.unsigned_abs() as usize;
let string_len = string.chars().count(); let string_len = string.chars().count();
if abs_index as usize <= string_len { if abs_index <= string_len {
let index = string_len - (abs_index as usize); let index = string_len - abs_index;
*string = string *string = string
.chars() .chars()
.enumerate() .enumerate()
@ -820,15 +813,12 @@ mod string_functions {
let offset = if string.is_empty() || len <= 0 { let offset = if string.is_empty() || len <= 0 {
return ctx.engine().const_empty_string(); return ctx.engine().const_empty_string();
} else if start < 0 { } else if start < 0 {
if let Some(n) = start.checked_abs() { let abs_start = start.unsigned_abs() as usize;
chars.extend(string.chars()); chars.extend(string.chars());
if n as usize > chars.len() { if abs_start > chars.len() {
0
} else {
chars.len() - n as usize
}
} else {
0 0
} else {
chars.len() - abs_start
} }
} else if start as usize >= string.chars().count() { } else if start as usize >= string.chars().count() {
return ctx.engine().const_empty_string(); return ctx.engine().const_empty_string();
@ -952,15 +942,12 @@ mod string_functions {
string.make_mut().clear(); string.make_mut().clear();
return; return;
} else if start < 0 { } else if start < 0 {
if let Some(n) = start.checked_abs() { let abs_start = start.unsigned_abs() as usize;
chars.extend(string.chars()); chars.extend(string.chars());
if n as usize > chars.len() { if abs_start > chars.len() {
0
} else {
chars.len() - n as usize
}
} else {
0 0
} else {
chars.len() - abs_start
} }
} else if start as usize >= string.chars().count() { } else if start as usize >= string.chars().count() {
string.make_mut().clear(); string.make_mut().clear();
@ -1256,23 +1243,17 @@ mod string_functions {
#[rhai_fn(name = "split")] #[rhai_fn(name = "split")]
pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array { pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array {
if index <= 0 { if index <= 0 {
if let Some(n) = index.checked_abs() { let abs_index = index.unsigned_abs() as usize;
let num_chars = string.chars().count(); let num_chars = string.chars().count();
if n as usize > num_chars { if abs_index > num_chars {
vec![
ctx.engine().const_empty_string().into(),
string.as_str().into(),
]
} else {
let prefix: String = string.chars().take(num_chars - n as usize).collect();
let prefix_len = prefix.len();
vec![prefix.into(), string[prefix_len..].into()]
}
} else {
vec![ vec![
ctx.engine().const_empty_string().into(), ctx.engine().const_empty_string().into(),
string.as_str().into(), string.as_str().into(),
] ]
} else {
let prefix: String = string.chars().take(num_chars - abs_index).collect();
let prefix_len = prefix.len();
vec![prefix.into(), string[prefix_len..].into()]
} }
} else { } else {
let prefix: String = string.chars().take(index as usize).collect(); let prefix: String = string.chars().take(index as usize).collect();

View File

@ -265,10 +265,8 @@ impl ParseSettings {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline] #[inline]
pub fn ensure_level_within_max_limit(&self, limit: usize) -> ParseResult<()> { pub fn ensure_level_within_max_limit(&self, limit: usize) -> ParseResult<()> {
if limit > 0 { if limit > 0 && self.level > limit {
if self.level > limit { return Err(PERR::ExprTooDeep.into_err(self.pos));
return Err(PERR::ExprTooDeep.into_err(self.pos));
}
} }
Ok(()) Ok(())
} }
@ -531,11 +529,14 @@ impl Engine {
#[cfg(any(feature = "no_function", feature = "no_module"))] #[cfg(any(feature = "no_function", feature = "no_module"))]
let is_global = false; let is_global = false;
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() { if settings.options.contains(LangOptions::STRICT_VAR)
if !is_global && !self.global_sub_modules.contains_key(root) { && index.is_none()
return Err(PERR::ModuleUndefined(root.to_string()) && !is_global
.into_err(namespace.position())); && !self.global_sub_modules.contains_key(root)
} {
return Err(
PERR::ModuleUndefined(root.to_string()).into_err(namespace.position())
);
} }
namespace.set_index(index); namespace.set_index(index);
@ -595,11 +596,13 @@ impl Engine {
#[cfg(any(feature = "no_function", feature = "no_module"))] #[cfg(any(feature = "no_function", feature = "no_module"))]
let is_global = false; let is_global = false;
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() { if settings.options.contains(LangOptions::STRICT_VAR)
if !is_global && !self.global_sub_modules.contains_key(root) { && index.is_none()
return Err(PERR::ModuleUndefined(root.to_string()) && !is_global
.into_err(namespace.position())); && !self.global_sub_modules.contains_key(root)
} {
return Err(PERR::ModuleUndefined(root.to_string())
.into_err(namespace.position()));
} }
namespace.set_index(index); namespace.set_index(index);
@ -1755,11 +1758,14 @@ impl Engine {
#[cfg(any(feature = "no_function", feature = "no_module"))] #[cfg(any(feature = "no_function", feature = "no_module"))]
let is_global = false; let is_global = false;
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() { if settings.options.contains(LangOptions::STRICT_VAR)
if !is_global && !self.global_sub_modules.contains_key(root) { && index.is_none()
return Err(PERR::ModuleUndefined(root.to_string()) && !is_global
.into_err(namespace.position())); && !self.global_sub_modules.contains_key(root)
} {
return Err(
PERR::ModuleUndefined(root.to_string()).into_err(namespace.position())
);
} }
namespace.set_index(index); namespace.set_index(index);
@ -2519,13 +2525,13 @@ impl Engine {
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax(); const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax(); const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
let self_terminated = match required_token.as_str() { let self_terminated = matches!(
required_token.as_str(),
// It is self-terminating if the last symbol is a block // It is self-terminating if the last symbol is a block
CUSTOM_SYNTAX_MARKER_BLOCK => true, CUSTOM_SYNTAX_MARKER_BLOCK |
// If the last symbol is `;` or `}`, it is self-terminating // If the last symbol is `;` or `}`, it is self-terminating
KEYWORD_SEMICOLON | KEYWORD_CLOSE_BRACE => true, KEYWORD_SEMICOLON | KEYWORD_CLOSE_BRACE
_ => false, );
};
Ok(Expr::Custom( Ok(Expr::Custom(
crate::ast::CustomExpr { crate::ast::CustomExpr {
@ -2794,12 +2800,12 @@ impl Engine {
// let name ... // let name ...
let (name, pos) = parse_var_name(input)?; let (name, pos) = parse_var_name(input)?;
if !self.allow_shadowing() && state.stack.iter().any(|(v, ..)| v == &name) { if !self.allow_shadowing() && state.stack.iter().any(|(v, ..)| v == name) {
return Err(PERR::VariableExists(name.to_string()).into_err(pos)); return Err(PERR::VariableExists(name.to_string()).into_err(pos));
} }
if let Some(ref filter) = self.def_var_filter { if let Some(ref filter) = self.def_var_filter {
let will_shadow = state.stack.iter().any(|(v, ..)| v == &name); let will_shadow = state.stack.iter().any(|(v, ..)| v == name);
let level = settings.level; let level = settings.level;
let is_const = access == AccessMode::ReadOnly; let is_const = access == AccessMode::ReadOnly;
let info = VarDefInfo { let info = VarDefInfo {
@ -3192,7 +3198,6 @@ impl Engine {
level: 0, level: 0,
options, options,
pos, pos,
..settings
}; };
let func = self.parse_fn( let func = self.parse_fn(

View File

@ -455,7 +455,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
let second = iter.next(); let second = iter.next();
if let (Some((key, value)), None) = (first, second) { if let (Some((key, value)), None) = (first, second) {
visitor.visit_enum(EnumDeserializer { visitor.visit_enum(EnumDeserializer {
tag: &key, tag: key,
content: DynamicDeserializer::from_dynamic(value), content: DynamicDeserializer::from_dynamic(value),
}) })
} else { } else {

View File

@ -439,7 +439,7 @@ impl Hash for Dynamic {
mem::discriminant(&self.0).hash(state); mem::discriminant(&self.0).hash(state);
match self.0 { match self.0 {
Union::Unit(..) => ().hash(state), Union::Unit(..) => (),
Union::Bool(ref b, ..) => b.hash(state), Union::Bool(ref b, ..) => b.hash(state),
Union::Str(ref s, ..) => s.hash(state), Union::Str(ref s, ..) => s.hash(state),
Union::Char(ref c, ..) => c.hash(state), Union::Char(ref c, ..) => c.hash(state),
@ -1018,17 +1018,11 @@ impl Dynamic {
#[must_use] #[must_use]
pub fn is_read_only(&self) -> bool { pub fn is_read_only(&self) -> bool {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
match self.0 { if let Union::Shared(ref cell, ..) = self.0 {
// Shared values do not consider the current access mode return match locked_read(cell).access_mode() {
//Union::Shared(.., ReadOnly) => return true, ReadWrite => false,
Union::Shared(ref cell, ..) => { ReadOnly => true,
return match locked_read(cell).access_mode() { };
ReadWrite => false,
ReadOnly => true,
}
}
_ => (),
} }
match self.access_mode() { match self.access_mode() {
@ -1368,14 +1362,11 @@ impl Dynamic {
#[must_use] #[must_use]
pub fn is_locked(&self) -> bool { pub fn is_locked(&self) -> bool {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
match self.0 { if let Union::Shared(ref _cell, ..) = self.0 {
Union::Shared(ref _cell, ..) => { #[cfg(not(feature = "sync"))]
#[cfg(not(feature = "sync"))] return _cell.try_borrow().is_err();
return _cell.try_borrow().is_err(); #[cfg(feature = "sync")]
#[cfg(feature = "sync")] return false;
return false;
}
_ => (),
} }
false false
@ -1791,7 +1782,7 @@ impl Dynamic {
#[cfg(feature = "no_closure")] #[cfg(feature = "no_closure")]
let typ = v.type_name(); let typ = v.type_name();
v.try_cast::<T>().ok_or_else(|| typ) v.try_cast::<T>().ok_or(typ)
}) })
.collect(), .collect(),
Union::Blob(..) if TypeId::of::<T>() == TypeId::of::<u8>() => Ok(self.cast::<Vec<T>>()), Union::Blob(..) if TypeId::of::<T>() == TypeId::of::<u8>() => Ok(self.cast::<Vec<T>>()),
@ -1813,7 +1804,7 @@ impl Dynamic {
#[cfg(feature = "no_closure")] #[cfg(feature = "no_closure")]
let typ = v.type_name(); let typ = v.type_name();
v.read_lock::<T>().ok_or_else(|| typ).map(|v| v.clone()) v.read_lock::<T>().ok_or(typ).map(|v| v.clone())
}) })
.collect() .collect()
} }

View File

@ -170,14 +170,14 @@ impl<'a> FromIterator<&'a str> for ImmutableString {
} }
} }
impl<'a> FromIterator<String> for ImmutableString { impl FromIterator<String> for ImmutableString {
#[inline] #[inline]
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
Self(iter.into_iter().collect::<SmartString>().into()) Self(iter.into_iter().collect::<SmartString>().into())
} }
} }
impl<'a> FromIterator<SmartString> for ImmutableString { impl FromIterator<SmartString> for ImmutableString {
#[inline] #[inline]
fn from_iter<T: IntoIterator<Item = SmartString>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = SmartString>>(iter: T) -> Self {
Self(iter.into_iter().collect::<SmartString>().into()) Self(iter.into_iter().collect::<SmartString>().into())

View File

@ -112,7 +112,7 @@ impl Clone for Scope<'_> {
.collect(), .collect(),
names: self.names.clone(), names: self.names.clone(),
aliases: self.aliases.clone(), aliases: self.aliases.clone(),
dummy: self.dummy.clone(), dummy: self.dummy,
} }
} }
} }
@ -437,11 +437,9 @@ impl Scope<'_> {
/// ``` /// ```
#[inline] #[inline]
pub fn is_constant(&self, name: &str) -> Option<bool> { pub fn is_constant(&self, name: &str) -> Option<bool> {
self.get_index(name).and_then(|(.., access)| { self.get_index(name).map(|(.., access)| match access {
Some(match access { AccessMode::ReadWrite => false,
AccessMode::ReadWrite => false, AccessMode::ReadOnly => true,
AccessMode::ReadOnly => true,
})
}) })
} }
/// Update the value of the named entry in the [`Scope`] if it already exists and is not constant. /// Update the value of the named entry in the [`Scope`] if it already exists and is not constant.