commit
b6ddd276f0
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ benches/results
|
|||||||
before*
|
before*
|
||||||
after*
|
after*
|
||||||
.rhai-repl-history.txt
|
.rhai-repl-history.txt
|
||||||
|
clippy.toml
|
||||||
|
@ -45,6 +45,8 @@ Enhancements
|
|||||||
* `as_string` is added to BLOB's to convert it into a string by interpreting it as a UTF-8 byte stream.
|
* `as_string` is added to BLOB's to convert it into a string by interpreting it as a UTF-8 byte stream.
|
||||||
* `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.
|
||||||
|
* The code base is cleaner by running it through Clippy.
|
||||||
|
|
||||||
|
|
||||||
Version 1.8.0
|
Version 1.8.0
|
||||||
|
@ -120,14 +120,14 @@ pub fn inner_item_attributes<T: ExportedParams>(
|
|||||||
// Find the #[rhai_fn] attribute which will turn be read for function parameters.
|
// Find the #[rhai_fn] attribute which will turn be read for function parameters.
|
||||||
if let Some(index) = attrs
|
if let Some(index) = attrs
|
||||||
.iter()
|
.iter()
|
||||||
.position(|a| a.path.get_ident().map(|i| *i == attr_name).unwrap_or(false))
|
.position(|a| a.path.get_ident().map_or(false, |i| *i == attr_name))
|
||||||
{
|
{
|
||||||
let rhai_fn_attr = attrs.remove(index);
|
let rhai_fn_attr = attrs.remove(index);
|
||||||
|
|
||||||
// Cannot have more than one #[rhai_fn]
|
// Cannot have more than one #[rhai_fn]
|
||||||
if let Some(duplicate) = attrs
|
if let Some(duplicate) = attrs
|
||||||
.iter()
|
.iter()
|
||||||
.find(|a| a.path.get_ident().map(|i| *i == attr_name).unwrap_or(false))
|
.find(|a| a.path.get_ident().map_or(false, |i| *i == attr_name))
|
||||||
{
|
{
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
duplicate.span(),
|
duplicate.span(),
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +177,7 @@ pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {
|
|||||||
pub fn collect_cfg_attr(attrs: &[syn::Attribute]) -> Vec<syn::Attribute> {
|
pub fn collect_cfg_attr(attrs: &[syn::Attribute]) -> Vec<syn::Attribute> {
|
||||||
attrs
|
attrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&a| a.path.get_ident().map(|i| *i == "cfg").unwrap_or(false))
|
.filter(|&a| a.path.get_ident().map_or(false, |i| *i == "cfg"))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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.
|
||||||
|
@ -252,7 +252,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// Standard keyword in first position but not disabled
|
// Standard keyword in first position but not disabled
|
||||||
_ if segments.is_empty()
|
_ if segments.is_empty()
|
||||||
&& token.as_ref().map_or(false, |v| v.is_standard_keyword())
|
&& token.as_ref().map_or(false, Token::is_standard_keyword)
|
||||||
&& (self.disabled_symbols.is_empty() || !self.disabled_symbols.contains(s)) =>
|
&& (self.disabled_symbols.is_empty() || !self.disabled_symbols.contains(s)) =>
|
||||||
{
|
{
|
||||||
return Err(LexError::ImproperSymbol(
|
return Err(LexError::ImproperSymbol(
|
||||||
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
@ -295,20 +291,18 @@ impl FuncInfo {
|
|||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
let (param_name, param_type) = self
|
let (param_name, param_type) =
|
||||||
.metadata
|
self.metadata
|
||||||
.params_info
|
.params_info
|
||||||
.get(i)
|
.get(i)
|
||||||
.map(|s| {
|
.map_or(("_", "?".into()), |s| {
|
||||||
let mut s = s.splitn(2, ':');
|
let mut s = s.splitn(2, ':');
|
||||||
(
|
(
|
||||||
s.next().unwrap_or("_").split(' ').last().unwrap(),
|
s.next().unwrap_or("_").split(' ').last().unwrap(),
|
||||||
s.next()
|
s.next()
|
||||||
.map(|ty| def_type_name(ty, def.engine))
|
.map_or(Cow::Borrowed("?"), |ty| def_type_name(ty, def.engine)),
|
||||||
.unwrap_or(Cow::Borrowed("?")),
|
)
|
||||||
)
|
});
|
||||||
})
|
|
||||||
.unwrap_or(("_", "?".into()));
|
|
||||||
|
|
||||||
if operator {
|
if operator {
|
||||||
write!(writer, "{param_type}")?;
|
write!(writer, "{param_type}")?;
|
||||||
@ -342,8 +336,7 @@ fn def_type_name<'a>(ty: &'a str, engine: &'a Engine) -> Cow<'a, str> {
|
|||||||
let ty = ty
|
let ty = ty
|
||||||
.strip_prefix("RhaiResultOf<")
|
.strip_prefix("RhaiResultOf<")
|
||||||
.and_then(|s| s.strip_suffix('>'))
|
.and_then(|s| s.strip_suffix('>'))
|
||||||
.map(str::trim)
|
.map_or(ty, str::trim);
|
||||||
.unwrap_or(ty);
|
|
||||||
|
|
||||||
let ty = ty
|
let ty = ty
|
||||||
.replace("Iterator<Item=", "Iterator<")
|
.replace("Iterator<Item=", "Iterator<")
|
||||||
|
@ -152,6 +152,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// Data types not supported by JSON serialize into formats that may invalidate the result.
|
/// Data types not supported by JSON serialize into formats that may invalidate the result.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
pub fn format_map_as_json(map: &Map) -> String {
|
pub fn format_map_as_json(map: &Map) -> String {
|
||||||
let mut result = String::from('{');
|
let mut result = String::from('{');
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,17 +51,20 @@ impl Engine {
|
|||||||
/// Is `if`-expression allowed?
|
/// Is `if`-expression allowed?
|
||||||
/// Default is `true`.
|
/// Default is `true`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn allow_if_expression(&self) -> bool {
|
pub const fn allow_if_expression(&self) -> bool {
|
||||||
self.options.contains(LangOptions::IF_EXPR)
|
self.options.contains(LangOptions::IF_EXPR)
|
||||||
}
|
}
|
||||||
/// Set whether `if`-expression is allowed.
|
/// Set whether `if`-expression is allowed.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn set_allow_if_expression(&mut self, enable: bool) {
|
pub fn set_allow_if_expression(&mut self, enable: bool) {
|
||||||
self.options.set(LangOptions::IF_EXPR, enable)
|
self.options.set(LangOptions::IF_EXPR, enable);
|
||||||
}
|
}
|
||||||
/// Is `switch` expression allowed?
|
/// Is `switch` expression allowed?
|
||||||
/// Default is `true`.
|
/// Default is `true`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn allow_switch_expression(&self) -> bool {
|
pub const fn allow_switch_expression(&self) -> bool {
|
||||||
self.options.contains(LangOptions::SWITCH_EXPR)
|
self.options.contains(LangOptions::SWITCH_EXPR)
|
||||||
}
|
}
|
||||||
@ -73,6 +76,7 @@ impl Engine {
|
|||||||
/// Is statement-expression allowed?
|
/// Is statement-expression allowed?
|
||||||
/// Default is `true`.
|
/// Default is `true`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn allow_statement_expression(&self) -> bool {
|
pub const fn allow_statement_expression(&self) -> bool {
|
||||||
self.options.contains(LangOptions::STMT_EXPR)
|
self.options.contains(LangOptions::STMT_EXPR)
|
||||||
}
|
}
|
||||||
@ -87,6 +91,7 @@ impl Engine {
|
|||||||
/// Not available under `no_function`.
|
/// Not available under `no_function`.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn allow_anonymous_fn(&self) -> bool {
|
pub const fn allow_anonymous_fn(&self) -> bool {
|
||||||
self.options.contains(LangOptions::ANON_FN)
|
self.options.contains(LangOptions::ANON_FN)
|
||||||
}
|
}
|
||||||
@ -101,6 +106,7 @@ impl Engine {
|
|||||||
/// Is looping allowed?
|
/// Is looping allowed?
|
||||||
/// Default is `true`.
|
/// Default is `true`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn allow_looping(&self) -> bool {
|
pub const fn allow_looping(&self) -> bool {
|
||||||
self.options.contains(LangOptions::LOOPING)
|
self.options.contains(LangOptions::LOOPING)
|
||||||
}
|
}
|
||||||
@ -112,6 +118,7 @@ impl Engine {
|
|||||||
/// Is variables shadowing allowed?
|
/// Is variables shadowing allowed?
|
||||||
/// Default is `true`.
|
/// Default is `true`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn allow_shadowing(&self) -> bool {
|
pub const fn allow_shadowing(&self) -> bool {
|
||||||
self.options.contains(LangOptions::SHADOW)
|
self.options.contains(LangOptions::SHADOW)
|
||||||
}
|
}
|
||||||
@ -123,6 +130,7 @@ impl Engine {
|
|||||||
/// Is strict variables mode enabled?
|
/// Is strict variables mode enabled?
|
||||||
/// Default is `false`.
|
/// Default is `false`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn strict_variables(&self) -> bool {
|
pub const fn strict_variables(&self) -> bool {
|
||||||
self.options.contains(LangOptions::STRICT_VAR)
|
self.options.contains(LangOptions::STRICT_VAR)
|
||||||
}
|
}
|
||||||
@ -137,6 +145,7 @@ impl Engine {
|
|||||||
/// Not available under `no_object`.
|
/// Not available under `no_object`.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn fail_on_invalid_map_property(&self) -> bool {
|
pub const fn fail_on_invalid_map_property(&self) -> bool {
|
||||||
self.options
|
self.options
|
||||||
.contains(LangOptions::FAIL_ON_INVALID_MAP_PROPERTY)
|
.contains(LangOptions::FAIL_ON_INVALID_MAP_PROPERTY)
|
||||||
|
@ -70,7 +70,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let param_type_names: crate::StaticVec<_> =
|
let param_type_names: crate::StaticVec<_> =
|
||||||
param_type_names.iter().map(|ty| ty.as_str()).collect();
|
param_type_names.iter().map(String::as_str).collect();
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let param_type_names = Some(param_type_names.as_ref());
|
let param_type_names = Some(param_type_names.as_ref());
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let param_type_names: crate::StaticVec<_> =
|
let param_type_names: crate::StaticVec<_> =
|
||||||
param_type_names.iter().map(|ty| ty.as_str()).collect();
|
param_type_names.iter().map(String::as_str).collect();
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let param_type_names = Some(param_type_names.as_ref());
|
let param_type_names = Some(param_type_names.as_ref());
|
||||||
|
|
||||||
@ -989,16 +989,7 @@ impl Engine {
|
|||||||
let separator = crate::tokenizer::Token::DoubleColon.syntax();
|
let separator = crate::tokenizer::Token::DoubleColon.syntax();
|
||||||
let separator = separator.as_ref();
|
let separator = separator.as_ref();
|
||||||
|
|
||||||
if !name.contains(separator) {
|
if name.contains(separator) {
|
||||||
if !module.is_indexed() {
|
|
||||||
// Index the module (making a clone copy if necessary) if it is not indexed
|
|
||||||
let mut module = crate::func::shared_take_or_clone(module);
|
|
||||||
module.build_index();
|
|
||||||
root.insert(name.into(), module.into());
|
|
||||||
} else {
|
|
||||||
root.insert(name.into(), module);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut iter = name.splitn(2, separator);
|
let mut iter = name.splitn(2, separator);
|
||||||
let sub_module = iter.next().expect("contains separator").trim();
|
let sub_module = iter.next().expect("contains separator").trim();
|
||||||
let remainder = iter.next().expect("contains separator").trim();
|
let remainder = iter.next().expect("contains separator").trim();
|
||||||
@ -1015,6 +1006,13 @@ impl Engine {
|
|||||||
m.build_index();
|
m.build_index();
|
||||||
root.insert(sub_module.into(), m.into());
|
root.insert(sub_module.into(), m.into());
|
||||||
}
|
}
|
||||||
|
} else if module.is_indexed() {
|
||||||
|
root.insert(name.into(), module);
|
||||||
|
} else {
|
||||||
|
// Index the module (making a clone copy if necessary) if it is not indexed
|
||||||
|
let mut module = crate::func::shared_take_or_clone(module);
|
||||||
|
module.build_index();
|
||||||
|
root.insert(name.into(), module.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1039,7 +1037,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
for (name, m) in &self.global_sub_modules {
|
for (name, m) in &self.global_sub_modules {
|
||||||
signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f)))
|
signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
signatures.extend(
|
signatures.extend(
|
||||||
|
@ -51,7 +51,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
ast.as_ref(),
|
ast.as_ref(),
|
||||||
];
|
];
|
||||||
let lib = if lib.first().map(|m: &&Module| m.is_empty()).unwrap_or(true) {
|
let lib = if lib.first().map_or(true, |m: &&Module| m.is_empty()) {
|
||||||
&lib[0..0]
|
&lib[0..0]
|
||||||
} else {
|
} else {
|
||||||
&lib
|
&lib
|
||||||
|
@ -144,13 +144,13 @@ 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 {
|
|
||||||
format!("&mut {}", r).into()
|
return if x == r {
|
||||||
} else {
|
|
||||||
name.into()
|
name.into()
|
||||||
|
} else {
|
||||||
|
format!("&mut {}", r).into()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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()
|
||||||
|
@ -554,19 +554,19 @@ impl AST {
|
|||||||
lib
|
lib
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut _ast = if !other.source.is_empty() {
|
let mut _ast = if other.source.is_empty() {
|
||||||
|
Self::new(
|
||||||
|
merged,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
lib,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
Self::new_with_source(
|
Self::new_with_source(
|
||||||
merged,
|
merged,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
lib,
|
lib,
|
||||||
other.source.clone(),
|
other.source.clone(),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
Self::new(
|
|
||||||
merged,
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
lib,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -977,6 +977,7 @@ impl Eq for ASTNode<'_> {}
|
|||||||
|
|
||||||
impl ASTNode<'_> {
|
impl ASTNode<'_> {
|
||||||
/// Get the [`Position`] of this [`ASTNode`].
|
/// Get the [`Position`] of this [`ASTNode`].
|
||||||
|
#[must_use]
|
||||||
pub fn position(&self) -> Position {
|
pub fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
ASTNode::Stmt(stmt) => stmt.position(),
|
ASTNode::Stmt(stmt) => stmt.position(),
|
||||||
|
@ -326,10 +326,10 @@ impl<F: Float + FromStr> FromStr for FloatWrapper<F> {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
impl<F: Float> FloatWrapper<F> {
|
impl<F: Float> FloatWrapper<F> {
|
||||||
/// Maximum floating-point number for natural display before switching to scientific notation.
|
/// Maximum floating-point number for natural display before switching to scientific notation.
|
||||||
pub const MAX_NATURAL_FLOAT_FOR_DISPLAY: f32 = 10000000000000.0;
|
pub const MAX_NATURAL_FLOAT_FOR_DISPLAY: f32 = 10_000_000_000_000.0;
|
||||||
|
|
||||||
/// Minimum floating-point number for natural display before switching to scientific notation.
|
/// Minimum floating-point number for natural display before switching to scientific notation.
|
||||||
pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.0000000000001;
|
pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.000_000_000_000_1;
|
||||||
|
|
||||||
/// Create a new [`FloatWrapper`].
|
/// Create a new [`FloatWrapper`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -728,10 +728,10 @@ impl Expr {
|
|||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Variable(x, ..) => {
|
Self::Variable(x, ..) => {
|
||||||
if !x.1.is_empty() {
|
if x.1.is_empty() {
|
||||||
x.1.position()
|
|
||||||
} else {
|
|
||||||
self.position()
|
self.position()
|
||||||
|
} else {
|
||||||
|
x.1.position()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ impl Ident {
|
|||||||
|
|
||||||
/// Get the name of the identifier as a string slice.
|
/// Get the name of the identifier as a string slice.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
self.name.as_str()
|
self.name.as_str()
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ impl fmt::Debug for Namespace {
|
|||||||
&self
|
&self
|
||||||
.path
|
.path
|
||||||
.iter()
|
.iter()
|
||||||
.map(|m| m.as_str())
|
.map(Ident::as_str)
|
||||||
.collect::<StaticVec<_>>()
|
.collect::<StaticVec<_>>()
|
||||||
.join(Token::DoubleColon.literal_syntax()),
|
.join(Token::DoubleColon.literal_syntax()),
|
||||||
)
|
)
|
||||||
@ -59,7 +59,7 @@ impl fmt::Display for Namespace {
|
|||||||
&self
|
&self
|
||||||
.path
|
.path
|
||||||
.iter()
|
.iter()
|
||||||
.map(|m| m.as_str())
|
.map(Ident::as_str)
|
||||||
.collect::<StaticVec<_>>()
|
.collect::<StaticVec<_>>()
|
||||||
.join(Token::DoubleColon.literal_syntax()),
|
.join(Token::DoubleColon.literal_syntax()),
|
||||||
)
|
)
|
||||||
@ -126,7 +126,7 @@ impl Namespace {
|
|||||||
/// Set the [`Scope`][crate::Scope] index offset.
|
/// Set the [`Scope`][crate::Scope] index offset.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) {
|
pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) {
|
||||||
self.index = index
|
self.index = index;
|
||||||
}
|
}
|
||||||
/// Get the [position][Position] of this [`Namespace`].
|
/// Get the [position][Position] of this [`Namespace`].
|
||||||
///
|
///
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
|
|
||||||
use super::{FnAccess, StmtBlock};
|
use super::{FnAccess, StmtBlock};
|
||||||
use crate::{Identifier, StaticVec};
|
use crate::{Identifier, SmartString, StaticVec};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{fmt, hash::Hash};
|
use std::{fmt, hash::Hash};
|
||||||
@ -71,7 +71,7 @@ impl fmt::Display for ScriptFnDef {
|
|||||||
self.name,
|
self.name,
|
||||||
self.params
|
self.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.as_str())
|
.map(SmartString::as_str)
|
||||||
.collect::<StaticVec<_>>()
|
.collect::<StaticVec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
)
|
)
|
||||||
@ -120,7 +120,7 @@ impl fmt::Display for ScriptFnMetadata<'_> {
|
|||||||
self.name,
|
self.name,
|
||||||
self.params
|
self.params
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.copied()
|
||||||
.collect::<StaticVec<_>>()
|
.collect::<StaticVec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
)
|
)
|
||||||
@ -132,7 +132,7 @@ impl<'a> From<&'a ScriptFnDef> for ScriptFnMetadata<'a> {
|
|||||||
fn from(value: &'a ScriptFnDef) -> Self {
|
fn from(value: &'a ScriptFnDef) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: &value.name,
|
name: &value.name,
|
||||||
params: value.params.iter().map(|s| s.as_str()).collect(),
|
params: value.params.iter().map(SmartString::as_str).collect(),
|
||||||
access: value.access,
|
access: value.access,
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
comments: value.comments.iter().map(<_>::as_ref).collect(),
|
comments: value.comments.iter().map(<_>::as_ref).collect(),
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
@ -514,7 +507,7 @@ impl<'a> IntoIterator for &'a StmtBlock {
|
|||||||
impl Extend<Stmt> for StmtBlock {
|
impl Extend<Stmt> for StmtBlock {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn extend<T: IntoIterator<Item = Stmt>>(&mut self, iter: T) {
|
fn extend<T: IntoIterator<Item = Stmt>>(&mut self, iter: T) {
|
||||||
self.block.extend(iter)
|
self.block.extend(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -806,7 +799,7 @@ impl Stmt {
|
|||||||
Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Stmt::is_pure),
|
Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Stmt::is_pure),
|
||||||
|
|
||||||
Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false,
|
Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false,
|
||||||
Self::Block(block, ..) => block.iter().all(|stmt| stmt.is_pure()),
|
Self::Block(block, ..) => block.iter().all(Stmt::is_pure),
|
||||||
Self::BreakLoop(..) | Self::Return(..) => false,
|
Self::BreakLoop(..) | Self::Return(..) => false,
|
||||||
Self::TryCatch(x, ..) => {
|
Self::TryCatch(x, ..) => {
|
||||||
x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure)
|
x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure)
|
||||||
|
@ -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"] => {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ impl fmt::Debug for Engine {
|
|||||||
&self
|
&self
|
||||||
.custom_syntax
|
.custom_syntax
|
||||||
.keys()
|
.keys()
|
||||||
.map(|s| s.as_str())
|
.map(crate::SmartString::as_str)
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -147,10 +147,10 @@ impl fmt::Display for BreakPoint {
|
|||||||
pos,
|
pos,
|
||||||
enabled,
|
enabled,
|
||||||
} => {
|
} => {
|
||||||
if !source.is_empty() {
|
if source.is_empty() {
|
||||||
write!(f, "{} @ {:?}", source, pos)?;
|
|
||||||
} else {
|
|
||||||
write!(f, "@ {:?}", pos)?;
|
write!(f, "@ {:?}", pos)?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{} @ {:?}", source, pos)?;
|
||||||
}
|
}
|
||||||
if !*enabled {
|
if !*enabled {
|
||||||
f.write_str(" (disabled)")?;
|
f.write_str(" (disabled)")?;
|
||||||
@ -201,6 +201,7 @@ impl fmt::Display for BreakPoint {
|
|||||||
impl BreakPoint {
|
impl BreakPoint {
|
||||||
/// Is this [`BreakPoint`] enabled?
|
/// Is this [`BreakPoint`] enabled?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn is_enabled(&self) -> bool {
|
pub fn is_enabled(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
@ -441,7 +442,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 +464,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 +513,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,
|
||||||
|
@ -113,7 +113,7 @@ impl<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> EvalContext<'a, 's, 'ps, 'g, 'pg, '
|
|||||||
/// Get an iterator over the namespaces containing definition of all script-defined functions.
|
/// Get an iterator over the namespaces containing definition of all script-defined functions.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
|
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
|
||||||
self.lib.iter().cloned()
|
self.lib.iter().copied()
|
||||||
}
|
}
|
||||||
/// _(internals)_ The current set of namespaces containing definitions of all script-defined functions.
|
/// _(internals)_ The current set of namespaces containing definitions of all script-defined functions.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
@ -133,7 +133,7 @@ impl<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> EvalContext<'a, 's, 'ps, 'g, 'pg, '
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn this_ptr_mut(&mut self) -> &mut Option<&'pt mut Dynamic> {
|
pub fn this_ptr_mut(&mut self) -> &mut Option<&'pt mut Dynamic> {
|
||||||
&mut self.this_ptr
|
self.this_ptr
|
||||||
}
|
}
|
||||||
/// The current nesting level of function calls.
|
/// The current nesting level of function calls.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -149,7 +149,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
_ if global.always_search_scope => (0, expr.start_position()),
|
_ if global.always_search_scope => (0, expr.start_position()),
|
||||||
Expr::Variable(.., Some(i), pos) => (i.get() as usize, *pos),
|
Expr::Variable(.., Some(i), pos) => (i.get() as usize, *pos),
|
||||||
Expr::Variable(v, None, pos) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos),
|
Expr::Variable(v, None, pos) => (v.0.map_or(0, NonZeroUsize::get), *pos),
|
||||||
_ => unreachable!("Expr::Variable expected but gets {:?}", expr),
|
_ => unreachable!("Expr::Variable expected but gets {:?}", expr),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -485,7 +485,7 @@ impl Engine {
|
|||||||
let custom_def = self.custom_syntax.get(key_token).ok_or_else(|| {
|
let custom_def = self.custom_syntax.get(key_token).ok_or_else(|| {
|
||||||
Box::new(ERR::ErrorCustomSyntax(
|
Box::new(ERR::ErrorCustomSyntax(
|
||||||
format!("Invalid custom syntax prefix: {}", key_token),
|
format!("Invalid custom syntax prefix: {}", key_token),
|
||||||
custom.tokens.iter().map(|s| s.to_string()).collect(),
|
custom.tokens.iter().map(<_>::to_string).collect(),
|
||||||
*pos,
|
*pos,
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
@ -284,26 +284,26 @@ impl GlobalRuntimeState<'_> {
|
|||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn hash_idx_get(&mut self) -> u64 {
|
pub(crate) fn hash_idx_get(&mut self) -> u64 {
|
||||||
if self.fn_hash_indexing != (0, 0) {
|
if self.fn_hash_indexing == (0, 0) {
|
||||||
self.fn_hash_indexing.0
|
|
||||||
} else {
|
|
||||||
let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2);
|
let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2);
|
||||||
let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3);
|
let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3);
|
||||||
self.fn_hash_indexing = (n1, n2);
|
self.fn_hash_indexing = (n1, n2);
|
||||||
n1
|
n1
|
||||||
|
} else {
|
||||||
|
self.fn_hash_indexing.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get the pre-calculated index setter hash.
|
/// Get the pre-calculated index setter hash.
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn hash_idx_set(&mut self) -> u64 {
|
pub(crate) fn hash_idx_set(&mut self) -> u64 {
|
||||||
if self.fn_hash_indexing != (0, 0) {
|
if self.fn_hash_indexing == (0, 0) {
|
||||||
self.fn_hash_indexing.1
|
|
||||||
} else {
|
|
||||||
let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2);
|
let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2);
|
||||||
let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3);
|
let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3);
|
||||||
self.fn_hash_indexing = (n1, n2);
|
self.fn_hash_indexing = (n1, n2);
|
||||||
n2
|
n2
|
||||||
|
} else {
|
||||||
|
self.fn_hash_indexing.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,21 +368,21 @@ impl Engine {
|
|||||||
|
|
||||||
match guard_val {
|
match guard_val {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
if !if_block.is_empty() {
|
if if_block.is_empty() {
|
||||||
|
Ok(Dynamic::UNIT)
|
||||||
|
} else {
|
||||||
self.eval_stmt_block(
|
self.eval_stmt_block(
|
||||||
scope, global, caches, lib, this_ptr, if_block, true, level,
|
scope, global, caches, lib, this_ptr, if_block, true, level,
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
Ok(Dynamic::UNIT)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(false) => {
|
Ok(false) => {
|
||||||
if !else_block.is_empty() {
|
if else_block.is_empty() {
|
||||||
|
Ok(Dynamic::UNIT)
|
||||||
|
} else {
|
||||||
self.eval_stmt_block(
|
self.eval_stmt_block(
|
||||||
scope, global, caches, lib, this_ptr, else_block, true, level,
|
scope, global, caches, lib, this_ptr, else_block, true, level,
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
Ok(Dynamic::UNIT)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err => err.map(Into::into),
|
err => err.map(Into::into),
|
||||||
@ -510,7 +510,10 @@ impl Engine {
|
|||||||
Stmt::While(x, ..) if matches!(x.0, Expr::Unit(..)) => loop {
|
Stmt::While(x, ..) if matches!(x.0, Expr::Unit(..)) => loop {
|
||||||
let (.., body) = &**x;
|
let (.., body) = &**x;
|
||||||
|
|
||||||
if !body.is_empty() {
|
if body.is_empty() {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(&mut global.num_operations, body.position())?;
|
||||||
|
} else {
|
||||||
match self
|
match self
|
||||||
.eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level)
|
.eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level)
|
||||||
{
|
{
|
||||||
@ -521,9 +524,6 @@ impl Engine {
|
|||||||
_ => break Err(err),
|
_ => break Err(err),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.inc_operations(&mut global.num_operations, body.position())?;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -624,11 +624,11 @@ impl Engine {
|
|||||||
if let Some(func) = func {
|
if let Some(func) = func {
|
||||||
// Add the loop variables
|
// Add the loop variables
|
||||||
let orig_scope_len = scope.len();
|
let orig_scope_len = scope.len();
|
||||||
let counter_index = if !counter.is_empty() {
|
let counter_index = if counter.is_empty() {
|
||||||
|
usize::MAX
|
||||||
|
} else {
|
||||||
scope.push(counter.name.clone(), 0 as INT);
|
scope.push(counter.name.clone(), 0 as INT);
|
||||||
scope.len() - 1
|
scope.len() - 1
|
||||||
} else {
|
|
||||||
usize::MAX
|
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.push(var_name.name.clone(), ());
|
scope.push(var_name.name.clone(), ());
|
||||||
@ -979,13 +979,13 @@ impl Engine {
|
|||||||
|
|
||||||
if let Ok(module) = module_result {
|
if let Ok(module) = module_result {
|
||||||
if !export.is_empty() {
|
if !export.is_empty() {
|
||||||
if !module.is_indexed() {
|
if module.is_indexed() {
|
||||||
|
global.push_import(export.name.clone(), module);
|
||||||
|
} else {
|
||||||
// Index the module (making a clone copy if necessary) if it is not indexed
|
// Index the module (making a clone copy if necessary) if it is not indexed
|
||||||
let mut m = crate::func::shared_take_or_clone(module);
|
let mut m = crate::func::shared_take_or_clone(module);
|
||||||
m.build_index();
|
m.build_index();
|
||||||
global.push_import(export.name.clone(), m);
|
global.push_import(export.name.clone(), m);
|
||||||
} else {
|
|
||||||
global.push_import(export.name.clone(), module);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -287,7 +287,7 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
return match op {
|
return match op {
|
||||||
OP_CONTAINS => Some(|_, args| {
|
OP_CONTAINS => Some(|_, args| {
|
||||||
let blob = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
let blob = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
||||||
let x = (args[1].as_int().expect("`INT`") & 0x000000ff) as u8;
|
let x = (args[1].as_int().expect("`INT`") & 0x0000_00ff) as u8;
|
||||||
Ok((!blob.is_empty() && blob.contains(&x)).into())
|
Ok((!blob.is_empty() && blob.contains(&x)).into())
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -517,16 +517,14 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
let blob1 = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
let blob1 = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
||||||
let blob2 = &*args[1].read_lock::<Blob>().expect(BUILTIN);
|
let blob2 = &*args[1].read_lock::<Blob>().expect(BUILTIN);
|
||||||
|
|
||||||
Ok(Dynamic::from_blob(if !blob2.is_empty() {
|
Ok(Dynamic::from_blob(if blob2.is_empty() {
|
||||||
if blob1.is_empty() {
|
|
||||||
blob2.clone()
|
|
||||||
} else {
|
|
||||||
let mut blob = blob1.clone();
|
|
||||||
blob.extend(blob2);
|
|
||||||
blob
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
blob1.clone()
|
blob1.clone()
|
||||||
|
} else if blob1.is_empty() {
|
||||||
|
blob2.clone()
|
||||||
|
} else {
|
||||||
|
let mut blob = blob1.clone();
|
||||||
|
blob.extend(blob2);
|
||||||
|
blob
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
"==" => Some(impl_op!(Blob == Blob)),
|
"==" => Some(impl_op!(Blob == Blob)),
|
||||||
|
@ -140,10 +140,10 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let (ns, sep) = (
|
let (ns, sep) = (
|
||||||
namespace.to_string(),
|
namespace.to_string(),
|
||||||
if !namespace.is_empty() {
|
if namespace.is_empty() {
|
||||||
crate::tokenizer::Token::DoubleColon.literal_syntax()
|
|
||||||
} else {
|
|
||||||
""
|
""
|
||||||
|
} else {
|
||||||
|
crate::tokenizer::Token::DoubleColon.literal_syntax()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
@ -169,7 +169,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// Search order:
|
/// Search order:
|
||||||
/// 1) AST - script functions in the AST
|
/// 1) AST - script functions in the AST
|
||||||
/// 2) Global namespace - functions registered via Engine::register_XXX
|
/// 2) Global namespace - functions registered via `Engine::register_XXX`
|
||||||
/// 3) Global registered modules - packages
|
/// 3) Global registered modules - packages
|
||||||
/// 4) Imported modules - functions marked with global namespace
|
/// 4) Imported modules - functions marked with global namespace
|
||||||
/// 5) Static registered modules
|
/// 5) Static registered modules
|
||||||
@ -280,16 +280,7 @@ 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| {
|
|
||||||
FnResolutionCacheEntry {
|
|
||||||
func: CallableFunction::from_method(
|
|
||||||
Box::new(f) as Box<FnAny>
|
|
||||||
),
|
|
||||||
source: None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let (first_arg, rest_args) = args.split_first().unwrap();
|
let (first_arg, rest_args) = args.split_first().unwrap();
|
||||||
|
|
||||||
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0]).map(
|
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0]).map(
|
||||||
@ -300,6 +291,15 @@ impl Engine {
|
|||||||
source: None,
|
source: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
get_builtin_binary_op_fn(fn_name, args[0], args[1]).map(|f| {
|
||||||
|
FnResolutionCacheEntry {
|
||||||
|
func: CallableFunction::from_method(
|
||||||
|
Box::new(f) as Box<FnAny>
|
||||||
|
),
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -312,11 +312,11 @@ impl Engine {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, a)| {
|
.map(|(i, a)| {
|
||||||
let mask = 1usize << (num_args - i - 1);
|
let mask = 1usize << (num_args - i - 1);
|
||||||
if bitmask & mask != 0 {
|
if bitmask & mask == 0 {
|
||||||
|
a.type_id()
|
||||||
|
} else {
|
||||||
// Replace with `Dynamic`
|
// Replace with `Dynamic`
|
||||||
TypeId::of::<Dynamic>()
|
TypeId::of::<Dynamic>()
|
||||||
} else {
|
|
||||||
a.type_id()
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -371,7 +371,7 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if func.is_some() {
|
if func.is_some() {
|
||||||
let is_method = func.map(|f| f.func.is_method()).unwrap_or(false);
|
let is_method = func.map_or(false, |f| f.func.is_method());
|
||||||
|
|
||||||
// Push a new call stack frame
|
// Push a new call stack frame
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
@ -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)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,8 +680,7 @@ impl Engine {
|
|||||||
&mut global.source,
|
&mut global.source,
|
||||||
source
|
source
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| (**s).clone())
|
.map_or(crate::Identifier::new_const(), |s| (**s).clone()),
|
||||||
.unwrap_or(crate::Identifier::new_const()),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = if _is_method_call {
|
let result = if _is_method_call {
|
||||||
@ -841,14 +840,12 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
KEYWORD_FN_PTR_CALL => {
|
KEYWORD_FN_PTR_CALL => {
|
||||||
if !call_args.is_empty() {
|
if call_args.is_empty() {
|
||||||
if !call_args[0].is::<FnPtr>() {
|
|
||||||
let typ = self.map_type_name(call_args[0].type_name());
|
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(typ, first_arg_pos));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let typ = self.map_type_name(target.type_name());
|
let typ = self.map_type_name(target.type_name());
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
|
||||||
|
} else if !call_args[0].is::<FnPtr>() {
|
||||||
|
let typ = self.map_type_name(call_args[0].type_name());
|
||||||
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, first_arg_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FnPtr call on object
|
// FnPtr call on object
|
||||||
@ -1036,10 +1033,10 @@ impl Engine {
|
|||||||
|
|
||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
let args_len = total_args + curry.len();
|
let args_len = total_args + curry.len();
|
||||||
hashes = if !hashes.is_native_only() {
|
hashes = if hashes.is_native_only() {
|
||||||
calc_fn_hash(name, args_len).into()
|
|
||||||
} else {
|
|
||||||
FnCallHashes::from_native(calc_fn_hash(name, args_len))
|
FnCallHashes::from_native(calc_fn_hash(name, args_len))
|
||||||
|
} else {
|
||||||
|
calc_fn_hash(name, args_len).into()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Handle Fn()
|
// Handle Fn()
|
||||||
@ -1180,7 +1177,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)
|
||||||
@ -1236,7 +1233,7 @@ impl Engine {
|
|||||||
|
|
||||||
if target_is_shared || target.is_temp_value() {
|
if target_is_shared || target.is_temp_value() {
|
||||||
arg_values.insert(0, target.take_or_clone().flatten());
|
arg_values.insert(0, target.take_or_clone().flatten());
|
||||||
args.extend(arg_values.iter_mut())
|
args.extend(arg_values.iter_mut());
|
||||||
} 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;
|
||||||
@ -1370,11 +1367,11 @@ impl Engine {
|
|||||||
while bitmask < max_bitmask {
|
while bitmask < max_bitmask {
|
||||||
let hash_params = calc_fn_params_hash(args.iter().enumerate().map(|(i, a)| {
|
let hash_params = calc_fn_params_hash(args.iter().enumerate().map(|(i, a)| {
|
||||||
let mask = 1usize << (num_args - i - 1);
|
let mask = 1usize << (num_args - i - 1);
|
||||||
if bitmask & mask != 0 {
|
if bitmask & mask == 0 {
|
||||||
|
a.type_id()
|
||||||
|
} else {
|
||||||
// Replace with `Dynamic`
|
// Replace with `Dynamic`
|
||||||
TypeId::of::<Dynamic>()
|
TypeId::of::<Dynamic>()
|
||||||
} else {
|
|
||||||
a.type_id()
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
||||||
@ -1392,7 +1389,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clone first argument if the function is not a method after-all
|
// Clone first argument if the function is not a method after-all
|
||||||
if !func.map(|f| f.is_method()).unwrap_or(true) {
|
if !func.map_or(true, CallableFunction::is_method) {
|
||||||
if let Some(first) = first_arg_value {
|
if let Some(first) = first_arg_value {
|
||||||
*first = args[0].clone();
|
*first = args[0].clone();
|
||||||
args[0] = first;
|
args[0] = first;
|
||||||
|
@ -47,7 +47,7 @@ impl Hasher for StraightHasher {
|
|||||||
self.0 = u64::from_ne_bytes(key);
|
self.0 = u64::from_ne_bytes(key);
|
||||||
|
|
||||||
if self.0 == 0 {
|
if self.0 == 0 {
|
||||||
self.0 = ALT_ZERO_HASH
|
self.0 = ALT_ZERO_HASH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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() {
|
||||||
|
@ -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.
|
||||||
@ -255,7 +252,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
/// in reverse order.
|
/// in reverse order.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
|
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
|
||||||
self.lib.iter().rev().cloned()
|
self.lib.iter().rev().copied()
|
||||||
}
|
}
|
||||||
/// _(internals)_ The current set of namespaces containing definitions of all script-defined functions.
|
/// _(internals)_ The current set of namespaces containing definitions of all script-defined functions.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
@ -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();
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ use std::{any::TypeId, mem};
|
|||||||
pub struct Mut<T>(T);
|
pub struct Mut<T>(T);
|
||||||
//pub struct Ref<T>(T);
|
//pub struct Ref<T>(T);
|
||||||
|
|
||||||
/// Dereference into DynamicWriteLock
|
/// Dereference into [`DynamicWriteLock`]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[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> {
|
||||||
@ -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.
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
@ -132,7 +128,7 @@ impl Engine {
|
|||||||
} else {
|
} else {
|
||||||
caches.push_fn_resolution_cache();
|
caches.push_fn_resolution_cache();
|
||||||
lib_merged.push(&**fn_lib);
|
lib_merged.push(&**fn_lib);
|
||||||
lib_merged.extend(lib.iter().cloned());
|
lib_merged.extend(lib.iter().copied());
|
||||||
&lib_merged
|
&lib_merged
|
||||||
},
|
},
|
||||||
Some(mem::replace(&mut global.constants, constants.clone())),
|
Some(mem::replace(&mut global.constants, constants.clone())),
|
||||||
@ -209,7 +205,7 @@ impl Engine {
|
|||||||
scope.rewind(orig_scope_len);
|
scope.rewind(orig_scope_len);
|
||||||
} else if !args.is_empty() {
|
} else if !args.is_empty() {
|
||||||
// Remove arguments only, leaving new variables in the scope
|
// Remove arguments only, leaving new variables in the scope
|
||||||
scope.remove_range(orig_scope_len, args.len())
|
scope.remove_range(orig_scope_len, args.len());
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
global.truncate_imports(orig_imports_len);
|
global.truncate_imports(orig_imports_len);
|
||||||
@ -237,7 +233,7 @@ impl Engine {
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
let cache = caches.fn_resolution_cache_mut();
|
let cache = caches.fn_resolution_cache_mut();
|
||||||
|
|
||||||
if let Some(result) = cache.get(&hash_script).map(|v| v.is_some()) {
|
if let Some(result) = cache.get(&hash_script).map(Option::is_some) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -8,7 +8,7 @@ use crate::func::{
|
|||||||
use crate::types::{dynamic::Variant, CustomTypesCollection};
|
use crate::types::{dynamic::Variant, CustomTypesCollection};
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier,
|
calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier,
|
||||||
ImmutableString, NativeCallContext, RhaiResultOf, Shared, StaticVec,
|
ImmutableString, NativeCallContext, RhaiResultOf, Shared, SmartString, StaticVec,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -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()
|
||||||
@ -182,7 +181,15 @@ impl FuncInfo {
|
|||||||
|
|
||||||
let return_type = Self::format_type(&self.metadata.return_type, true);
|
let return_type = Self::format_type(&self.metadata.return_type, true);
|
||||||
|
|
||||||
if !self.metadata.params_info.is_empty() {
|
if self.metadata.params_info.is_empty() {
|
||||||
|
for x in 0..self.metadata.params {
|
||||||
|
sig.push('_');
|
||||||
|
if x < self.metadata.params - 1 {
|
||||||
|
sig.push_str(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sig.push(')');
|
||||||
|
} else {
|
||||||
let params: StaticVec<_> = self
|
let params: StaticVec<_> = self
|
||||||
.metadata
|
.metadata
|
||||||
.params_info
|
.params_info
|
||||||
@ -204,14 +211,6 @@ impl FuncInfo {
|
|||||||
.collect();
|
.collect();
|
||||||
sig.push_str(¶ms.join(", "));
|
sig.push_str(¶ms.join(", "));
|
||||||
sig.push(')');
|
sig.push(')');
|
||||||
} else {
|
|
||||||
for x in 0..self.metadata.params {
|
|
||||||
sig.push('_');
|
|
||||||
if x < self.metadata.params - 1 {
|
|
||||||
sig.push_str(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sig.push(')');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.func.is_script() && !return_type.is_empty() {
|
if !self.func.is_script() && !return_type.is_empty() {
|
||||||
@ -239,7 +238,7 @@ pub fn calc_native_fn_hash<'a>(
|
|||||||
params: &[TypeId],
|
params: &[TypeId],
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let hash_script = calc_qualified_fn_hash(modules, fn_name, params.len());
|
let hash_script = calc_qualified_fn_hash(modules, fn_name, params.len());
|
||||||
let hash_params = calc_fn_params_hash(params.iter().cloned());
|
let hash_params = calc_fn_params_hash(params.iter().copied());
|
||||||
combine_hashes(hash_script, hash_params)
|
combine_hashes(hash_script, hash_params)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +298,7 @@ impl fmt::Debug for Module {
|
|||||||
&self
|
&self
|
||||||
.modules
|
.modules
|
||||||
.keys()
|
.keys()
|
||||||
.map(|m| m.as_str())
|
.map(SmartString::as_str)
|
||||||
.collect::<BTreeSet<_>>(),
|
.collect::<BTreeSet<_>>(),
|
||||||
)
|
)
|
||||||
.field("vars", &self.variables)
|
.field("vars", &self.variables)
|
||||||
@ -585,6 +584,7 @@ impl Module {
|
|||||||
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
|
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
|
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
|
||||||
self.custom_types.get(key)
|
self.custom_types.get(key)
|
||||||
}
|
}
|
||||||
@ -648,7 +648,7 @@ impl Module {
|
|||||||
FnAccess::Public => true,
|
FnAccess::Public => true,
|
||||||
FnAccess::Private => false,
|
FnAccess::Private => false,
|
||||||
})
|
})
|
||||||
.map(|f| f.gen_signature())
|
.map(FuncInfo::gen_signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does a variable exist in the [`Module`]?
|
/// Does a variable exist in the [`Module`]?
|
||||||
@ -664,10 +664,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_var(&self, name: &str) -> bool {
|
pub fn contains_var(&self, name: &str) -> bool {
|
||||||
if !self.variables.is_empty() {
|
if self.variables.is_empty() {
|
||||||
self.variables.contains_key(name)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.variables.contains_key(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,10 +700,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_var(&self, name: &str) -> Option<Dynamic> {
|
pub fn get_var(&self, name: &str) -> Option<Dynamic> {
|
||||||
if !self.variables.is_empty() {
|
if self.variables.is_empty() {
|
||||||
self.variables.get(name).cloned()
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
self.variables.get(name).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,10 +740,10 @@ impl Module {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Option<Dynamic> {
|
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Option<Dynamic> {
|
||||||
if !self.all_variables.is_empty() {
|
if self.all_variables.is_empty() {
|
||||||
self.all_variables.get(&hash_var).cloned()
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
self.all_variables.get(&hash_var).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,14 +795,14 @@ impl Module {
|
|||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
num_params: usize,
|
num_params: usize,
|
||||||
) -> Option<&Shared<crate::ast::ScriptFnDef>> {
|
) -> Option<&Shared<crate::ast::ScriptFnDef>> {
|
||||||
if !self.functions.is_empty() {
|
if self.functions.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
let name = name.as_ref();
|
let name = name.as_ref();
|
||||||
|
|
||||||
self.iter_fn()
|
self.iter_fn()
|
||||||
.find(|f| f.metadata.params == num_params && f.metadata.name == name)
|
.find(|f| f.metadata.params == num_params && f.metadata.name == name)
|
||||||
.and_then(|f| f.func.get_script_fn_def())
|
.and_then(|f| f.func.get_script_fn_def())
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,10 +841,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_sub_module(&self, name: &str) -> bool {
|
pub fn contains_sub_module(&self, name: &str) -> bool {
|
||||||
if !self.modules.is_empty() {
|
if self.modules.is_empty() {
|
||||||
self.modules.contains_key(name)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.modules.contains_key(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,10 +862,10 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
|
pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
|
||||||
if !self.modules.is_empty() {
|
if self.modules.is_empty() {
|
||||||
self.modules.get(name).map(|m| &**m)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
self.modules.get(name).map(|m| &**m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,10 +909,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_fn(&self, hash_fn: u64) -> bool {
|
pub fn contains_fn(&self, hash_fn: u64) -> bool {
|
||||||
if !self.functions.is_empty() {
|
if self.functions.is_empty() {
|
||||||
self.functions.contains_key(&hash_fn)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.functions.contains_key(&hash_fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1062,7 +1062,7 @@ impl Module {
|
|||||||
let mut param_types: StaticVec<_> = arg_types
|
let mut param_types: StaticVec<_> = arg_types
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.copied()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, type_id)| Self::map_type(!is_method || i > 0, type_id))
|
.map(|(i, type_id)| Self::map_type(!is_method || i > 0, type_id))
|
||||||
.collect();
|
.collect();
|
||||||
@ -1328,8 +1328,10 @@ impl Module {
|
|||||||
where
|
where
|
||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
T: Variant + Clone,
|
T: Variant + Clone,
|
||||||
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>,
|
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>
|
||||||
F: Fn(&mut A) -> RhaiResultOf<T> + SendSync + 'static,
|
+ Fn(&mut A) -> RhaiResultOf<T>
|
||||||
|
+ SendSync
|
||||||
|
+ 'static,
|
||||||
{
|
{
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
crate::engine::make_getter(name.as_ref()).as_str(),
|
crate::engine::make_getter(name.as_ref()).as_str(),
|
||||||
@ -1370,8 +1372,10 @@ impl Module {
|
|||||||
where
|
where
|
||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>>,
|
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>>
|
||||||
F: Fn(&mut A, B) -> RhaiResultOf<()> + SendSync + 'static,
|
+ Fn(&mut A, B) -> RhaiResultOf<()>
|
||||||
|
+ SendSync
|
||||||
|
+ 'static,
|
||||||
{
|
{
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
crate::engine::make_setter(name.as_ref()).as_str(),
|
crate::engine::make_setter(name.as_ref()).as_str(),
|
||||||
@ -1417,8 +1421,10 @@ impl Module {
|
|||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
T: Variant + Clone,
|
T: Variant + Clone,
|
||||||
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>,
|
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>
|
||||||
F: Fn(&mut A, B) -> RhaiResultOf<T> + SendSync + 'static,
|
+ Fn(&mut A, B) -> RhaiResultOf<T>
|
||||||
|
+ SendSync
|
||||||
|
+ 'static,
|
||||||
{
|
{
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
|
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
|
||||||
@ -1479,8 +1485,10 @@ impl Module {
|
|||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
C: Variant + Clone,
|
C: Variant + Clone,
|
||||||
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>>,
|
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>>
|
||||||
F: Fn(&mut A, B, C) -> RhaiResultOf<()> + SendSync + 'static,
|
+ Fn(&mut A, B, C) -> RhaiResultOf<()>
|
||||||
|
+ SendSync
|
||||||
|
+ 'static,
|
||||||
{
|
{
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
|
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
|
||||||
@ -1564,10 +1572,10 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&CallableFunction> {
|
pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&CallableFunction> {
|
||||||
if !self.functions.is_empty() {
|
if self.functions.is_empty() {
|
||||||
self.functions.get(&hash_native).map(|f| &f.func)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
self.functions.get(&hash_native).map(|f| &f.func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1575,10 +1583,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn contains_dynamic_fn(&self, hash_script: u64) -> bool {
|
pub(crate) fn contains_dynamic_fn(&self, hash_script: u64) -> bool {
|
||||||
if !self.dynamic_functions.is_empty() {
|
if self.dynamic_functions.is_empty() {
|
||||||
self.dynamic_functions.contains(&hash_script)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.dynamic_functions.contains(&hash_script)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1588,10 +1596,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool {
|
pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool {
|
||||||
if !self.all_functions.is_empty() {
|
if self.all_functions.is_empty() {
|
||||||
self.all_functions.contains_key(&hash_fn)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.all_functions.contains_key(&hash_fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1602,10 +1610,10 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
|
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
|
||||||
if !self.all_functions.is_empty() {
|
if self.all_functions.is_empty() {
|
||||||
self.all_functions.get(&hash_qualified_fn)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
self.all_functions.get(&hash_qualified_fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1684,7 +1692,7 @@ impl Module {
|
|||||||
self.functions.entry(k).or_insert_with(|| v.clone());
|
self.functions.entry(k).or_insert_with(|| v.clone());
|
||||||
}
|
}
|
||||||
self.dynamic_functions
|
self.dynamic_functions
|
||||||
.extend(other.dynamic_functions.iter().cloned());
|
.extend(other.dynamic_functions.iter().copied());
|
||||||
for (&k, v) in &other.type_iterators {
|
for (&k, v) in &other.type_iterators {
|
||||||
self.type_iterators.entry(k).or_insert_with(|| v.clone());
|
self.type_iterators.entry(k).or_insert_with(|| v.clone());
|
||||||
}
|
}
|
||||||
@ -1746,7 +1754,7 @@ impl Module {
|
|||||||
);
|
);
|
||||||
// This may introduce entries that are superfluous because the function has been filtered away.
|
// This may introduce entries that are superfluous because the function has been filtered away.
|
||||||
self.dynamic_functions
|
self.dynamic_functions
|
||||||
.extend(other.dynamic_functions.iter().cloned());
|
.extend(other.dynamic_functions.iter().copied());
|
||||||
|
|
||||||
self.type_iterators
|
self.type_iterators
|
||||||
.extend(other.type_iterators.iter().map(|(&k, v)| (k, v.clone())));
|
.extend(other.type_iterators.iter().map(|(&k, v)| (k, v.clone())));
|
||||||
@ -1896,7 +1904,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<
|
||||||
@ -2147,14 +2154,14 @@ impl Module {
|
|||||||
|
|
||||||
if !f.func.is_script() {
|
if !f.func.is_script() {
|
||||||
let hash_qualified_fn = calc_native_fn_hash(
|
let hash_qualified_fn = calc_native_fn_hash(
|
||||||
path.iter().cloned(),
|
path.iter().copied(),
|
||||||
f.metadata.name.as_str(),
|
f.metadata.name.as_str(),
|
||||||
&f.param_types,
|
&f.param_types,
|
||||||
);
|
);
|
||||||
functions.insert(hash_qualified_fn, f.func.clone());
|
functions.insert(hash_qualified_fn, f.func.clone());
|
||||||
} else if cfg!(not(feature = "no_function")) {
|
} else if cfg!(not(feature = "no_function")) {
|
||||||
let hash_qualified_script = crate::calc_qualified_fn_hash(
|
let hash_qualified_script = crate::calc_qualified_fn_hash(
|
||||||
path.iter().cloned(),
|
path.iter().copied(),
|
||||||
f.metadata.name.as_str(),
|
f.metadata.name.as_str(),
|
||||||
f.metadata.params,
|
f.metadata.params,
|
||||||
);
|
);
|
||||||
@ -2194,10 +2201,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_qualified_iter(&self, id: TypeId) -> bool {
|
pub fn contains_qualified_iter(&self, id: TypeId) -> bool {
|
||||||
if !self.all_type_iterators.is_empty() {
|
if self.all_type_iterators.is_empty() {
|
||||||
self.all_type_iterators.contains_key(&id)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.all_type_iterators.contains_key(&id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2205,10 +2212,10 @@ impl Module {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_iter(&self, id: TypeId) -> bool {
|
pub fn contains_iter(&self, id: TypeId) -> bool {
|
||||||
if !self.type_iterators.is_empty() {
|
if self.type_iterators.is_empty() {
|
||||||
self.type_iterators.contains_key(&id)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.type_iterators.contains_key(&id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2275,10 +2282,10 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&IteratorFn> {
|
pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&IteratorFn> {
|
||||||
if !self.all_type_iterators.is_empty() {
|
if self.all_type_iterators.is_empty() {
|
||||||
self.all_type_iterators.get(&id).map(|f| &**f)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
self.all_type_iterators.get(&id).map(|f| &**f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2286,10 +2293,10 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> {
|
pub(crate) fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> {
|
||||||
if !self.type_iterators.is_empty() {
|
if self.type_iterators.is_empty() {
|
||||||
self.type_iterators.get(&id).map(|f| &**f)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
self.type_iterators.get(&id).map(|f| &**f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -31,6 +31,7 @@ impl DummyModuleResolver {
|
|||||||
/// engine.set_module_resolver(resolver);
|
/// engine.set_module_resolver(resolver);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self
|
Self
|
||||||
}
|
}
|
||||||
|
@ -244,10 +244,10 @@ impl FileModuleResolver {
|
|||||||
|
|
||||||
let cache = locked_read(&self.cache);
|
let cache = locked_read(&self.cache);
|
||||||
|
|
||||||
if !cache.is_empty() {
|
if cache.is_empty() {
|
||||||
cache.contains_key(path.as_ref())
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
cache.contains_key(path.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Empty the internal cache.
|
/// Empty the internal cache.
|
||||||
@ -277,7 +277,7 @@ impl FileModuleResolver {
|
|||||||
file_path = self
|
file_path = self
|
||||||
.base_path
|
.base_path
|
||||||
.clone()
|
.clone()
|
||||||
.or_else(|| source_path.map(|p| p.into()))
|
.or_else(|| source_path.map(Into::into))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
file_path.push(path);
|
file_path.push(path);
|
||||||
} else {
|
} else {
|
||||||
@ -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(
|
||||||
|
@ -66,10 +66,10 @@ impl StaticModuleResolver {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_path(&self, path: &str) -> bool {
|
pub fn contains_path(&self, path: &str) -> bool {
|
||||||
if !self.0.is_empty() {
|
if self.0.is_empty() {
|
||||||
self.0.contains_key(path)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
self.0.contains_key(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get an iterator of all the [modules][Module].
|
/// Get an iterator of all the [modules][Module].
|
||||||
@ -85,7 +85,7 @@ impl StaticModuleResolver {
|
|||||||
/// Get an iterator of all the [module][Module] paths.
|
/// Get an iterator of all the [module][Module] paths.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn paths(&self) -> impl Iterator<Item = &str> {
|
pub fn paths(&self) -> impl Iterator<Item = &str> {
|
||||||
self.0.keys().map(|s| s.as_str())
|
self.0.keys().map(SmartString::as_str)
|
||||||
}
|
}
|
||||||
/// Get an iterator of all the [modules][Module].
|
/// Get an iterator of all the [modules][Module].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -100,6 +100,7 @@ impl StaticModuleResolver {
|
|||||||
}
|
}
|
||||||
/// Is this [`StaticModuleResolver`] empty?
|
/// Is this [`StaticModuleResolver`] empty?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.0.is_empty()
|
self.0.is_empty()
|
||||||
}
|
}
|
||||||
|
107
src/optimizer.rs
107
src/optimizer.rs
@ -103,7 +103,7 @@ impl<'a> OptimizerState<'a> {
|
|||||||
/// Prune the list of constants back to a specified size.
|
/// Prune the list of constants back to a specified size.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn restore_var(&mut self, len: usize) {
|
pub fn restore_var(&mut self, len: usize) {
|
||||||
self.variables.truncate(len)
|
self.variables.truncate(len);
|
||||||
}
|
}
|
||||||
/// Add a new variable to the list.
|
/// Add a new variable to the list.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -113,7 +113,7 @@ impl<'a> OptimizerState<'a> {
|
|||||||
access: AccessMode,
|
access: AccessMode,
|
||||||
value: Option<Dynamic>,
|
value: Option<Dynamic>,
|
||||||
) {
|
) {
|
||||||
self.variables.push((name.into(), access, value))
|
self.variables.push((name.into(), access, value));
|
||||||
}
|
}
|
||||||
/// Look up a constant from the list.
|
/// Look up a constant from the list.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -169,7 +169,7 @@ fn has_native_fn_override(
|
|||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
arg_types: impl AsRef<[TypeId]>,
|
arg_types: impl AsRef<[TypeId]>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let hash_params = calc_fn_params_hash(arg_types.as_ref().iter().cloned());
|
let hash_params = calc_fn_params_hash(arg_types.as_ref().iter().copied());
|
||||||
let hash = combine_hashes(hash_script, hash_params);
|
let hash = combine_hashes(hash_script, hash_params);
|
||||||
|
|
||||||
// First check the global namespace and packages, but skip modules that are standard because
|
// First check the global namespace and packages, but skip modules that are standard because
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -438,7 +433,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
if !x.0.is_op_assignment()
|
if !x.0.is_op_assignment()
|
||||||
&& x.1.lhs.is_variable_access(true)
|
&& x.1.lhs.is_variable_access(true)
|
||||||
&& matches!(&x.1.rhs, Expr::FnCall(x2, ..)
|
&& matches!(&x.1.rhs, Expr::FnCall(x2, ..)
|
||||||
if Token::lookup_from_syntax(&x2.name).map(|t| t.has_op_assignment()).unwrap_or(false)
|
if Token::lookup_from_syntax(&x2.name).map_or(false, |t| t.has_op_assignment())
|
||||||
&& x2.args.len() == 2
|
&& x2.args.len() == 2
|
||||||
&& x2.args[0].get_variable_name(true) == x.1.lhs.get_variable_name(true)
|
&& x2.args[0].get_variable_name(true) == x.1.lhs.get_variable_name(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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,12 +721,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove if no entry left
|
// Remove if no entry left
|
||||||
match list.is_empty() {
|
if list.is_empty() {
|
||||||
true => {
|
state.set_dirty();
|
||||||
state.set_dirty();
|
false
|
||||||
false
|
} else {
|
||||||
}
|
true
|
||||||
false => true,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -773,7 +765,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
Stmt::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => match x.0 {
|
Stmt::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => match x.0 {
|
||||||
Expr::BoolConstant(false, pos) => {
|
Expr::BoolConstant(false, pos) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Noop(pos)
|
*stmt = Stmt::Noop(pos);
|
||||||
}
|
}
|
||||||
_ => unreachable!("`Expr::BoolConstant"),
|
_ => unreachable!("`Expr::BoolConstant"),
|
||||||
},
|
},
|
||||||
@ -792,14 +784,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
Stmt::BreakLoop(options, pos) if options.contains(ASTFlags::BREAK) => {
|
Stmt::BreakLoop(options, pos) if options.contains(ASTFlags::BREAK) => {
|
||||||
// Only a single break statement - turn into running the guard expression once
|
// Only a single break statement - turn into running the guard expression once
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
if !condition.is_unit() {
|
if condition.is_unit() {
|
||||||
|
*stmt = Stmt::Noop(pos);
|
||||||
|
} else {
|
||||||
let mut statements = vec![Stmt::Expr(mem::take(condition).into())];
|
let mut statements = vec![Stmt::Expr(mem::take(condition).into())];
|
||||||
if preserve_result {
|
if preserve_result {
|
||||||
statements.push(Stmt::Noop(pos))
|
statements.push(Stmt::Noop(pos));
|
||||||
}
|
}
|
||||||
*stmt = (statements, Span::new(pos, Position::NONE)).into();
|
*stmt = (statements, Span::new(pos, Position::NONE)).into();
|
||||||
} else {
|
|
||||||
*stmt = Stmt::Noop(pos);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -842,7 +834,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
// let id = expr;
|
// let id = expr;
|
||||||
Stmt::Var(x, options, ..) if !options.contains(ASTFlags::CONSTANT) => {
|
Stmt::Var(x, options, ..) if !options.contains(ASTFlags::CONSTANT) => {
|
||||||
optimize_expr(&mut x.1, state, false)
|
optimize_expr(&mut x.1, state, false);
|
||||||
}
|
}
|
||||||
// import expr as var;
|
// import expr as var;
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -958,10 +950,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"))]
|
||||||
@ -979,8 +968,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.as_str() == prop)
|
*expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.as_str() == prop)
|
||||||
.map(|(.., mut expr)| { expr.set_position(*pos); expr })
|
.map_or_else(|| Expr::Unit(*pos), |(.., mut expr)| { expr.set_position(*pos); expr });
|
||||||
.unwrap_or_else(|| Expr::Unit(*pos));
|
|
||||||
}
|
}
|
||||||
// var.rhs
|
// var.rhs
|
||||||
(Expr::Variable(..), rhs) => optimize_expr(rhs, state, true),
|
(Expr::Variable(..), rhs) => optimize_expr(rhs, state, true),
|
||||||
@ -1010,11 +998,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;
|
||||||
@ -1025,8 +1013,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.as_str() == s.as_str())
|
*expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.as_str() == s.as_str())
|
||||||
.map(|(.., mut expr)| { expr.set_position(*pos); expr })
|
.map_or_else(|| Expr::Unit(*pos), |(.., mut expr)| { expr.set_position(*pos); expr });
|
||||||
.unwrap_or_else(|| Expr::Unit(*pos));
|
|
||||||
}
|
}
|
||||||
// int[int]
|
// int[int]
|
||||||
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < crate::INT_BITS => {
|
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < crate::INT_BITS => {
|
||||||
@ -1035,10 +1022,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 +1034,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),
|
||||||
@ -1158,7 +1145,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
_ => Dynamic::UNIT
|
_ => Dynamic::UNIT
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(fn_ptr) = fn_name.into_immutable_string().map_err(|err| err.into()).and_then(FnPtr::try_from) {
|
if let Ok(fn_ptr) = fn_name.into_immutable_string().map_err(Into::into).and_then(FnPtr::try_from) {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos);
|
*expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos);
|
||||||
} else {
|
} else {
|
||||||
@ -1348,10 +1335,10 @@ fn optimize_top_level(
|
|||||||
|
|
||||||
// Add constants and variables from the scope
|
// Add constants and variables from the scope
|
||||||
for (name, constant, value) in scope.iter() {
|
for (name, constant, value) in scope.iter() {
|
||||||
if !constant {
|
if constant {
|
||||||
state.push_var(name, AccessMode::ReadWrite, None);
|
|
||||||
} else {
|
|
||||||
state.push_var(name, AccessMode::ReadOnly, Some(value));
|
state.push_var(name, AccessMode::ReadOnly, Some(value));
|
||||||
|
} else {
|
||||||
|
state.push_var(name, AccessMode::ReadWrite, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,16 +145,14 @@ pub mod array_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn concat(array1: Array, array2: Array) -> Array {
|
pub fn concat(array1: Array, array2: Array) -> Array {
|
||||||
if !array2.is_empty() {
|
if array2.is_empty() {
|
||||||
if array1.is_empty() {
|
|
||||||
array2
|
|
||||||
} else {
|
|
||||||
let mut array = array1;
|
|
||||||
array.extend(array2);
|
|
||||||
array
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
array1
|
array1
|
||||||
|
} else if array1.is_empty() {
|
||||||
|
array2
|
||||||
|
} else {
|
||||||
|
let mut array = array1;
|
||||||
|
array.extend(array2);
|
||||||
|
array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Add a new element into the array at a particular `index` position.
|
/// Add a new element into the array at a particular `index` position.
|
||||||
@ -290,7 +288,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.
|
||||||
@ -432,7 +430,7 @@ pub mod array_functions {
|
|||||||
pub fn splice_range(array: &mut Array, range: ExclusiveRange, replace: Array) {
|
pub fn splice_range(array: &mut Array, range: ExclusiveRange, replace: Array) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
splice(array, start, end - start, replace)
|
splice(array, start, end - start, replace);
|
||||||
}
|
}
|
||||||
/// Replace an inclusive range of the array with another array.
|
/// Replace an inclusive range of the array with another array.
|
||||||
///
|
///
|
||||||
@ -450,7 +448,7 @@ pub mod array_functions {
|
|||||||
pub fn splice_inclusive_range(array: &mut Array, range: InclusiveRange, replace: Array) {
|
pub fn splice_inclusive_range(array: &mut Array, range: InclusiveRange, replace: Array) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
splice(array, start, end - start + 1, replace)
|
splice(array, start, end - start + 1, replace);
|
||||||
}
|
}
|
||||||
/// Replace a portion of the array with another array.
|
/// Replace a portion of the array with another array.
|
||||||
///
|
///
|
||||||
@ -1344,7 +1342,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)
|
||||||
});
|
});
|
||||||
@ -1739,13 +1737,15 @@ pub mod array_functions {
|
|||||||
.call_raw(&ctx, None, [x.clone(), y.clone()])
|
.call_raw(&ctx, None, [x.clone(), y.clone()])
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|v| v.as_int().ok())
|
.and_then(|v| v.as_int().ok())
|
||||||
.map(|v| match v {
|
.map_or_else(
|
||||||
v if v > 0 => Ordering::Greater,
|
|| x.type_id().cmp(&y.type_id()),
|
||||||
v if v < 0 => Ordering::Less,
|
|v| match v {
|
||||||
0 => Ordering::Equal,
|
v if v > 0 => Ordering::Greater,
|
||||||
_ => unreachable!("v is {}", v),
|
v if v < 0 => Ordering::Less,
|
||||||
})
|
0 => Ordering::Equal,
|
||||||
.unwrap_or_else(|| x.type_id().cmp(&y.type_id()))
|
_ => unreachable!("v is {}", v),
|
||||||
|
},
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -2119,7 +2119,7 @@ pub mod array_functions {
|
|||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
|
|
||||||
while x < array.len() {
|
while x < array.len() {
|
||||||
if !filter
|
if filter
|
||||||
.call_raw(&ctx, None, [array[x].clone()])
|
.call_raw(&ctx, None, [array[x].clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
@ -2140,9 +2140,9 @@ pub mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
drained.push(array.remove(x));
|
|
||||||
} else {
|
|
||||||
x += 1;
|
x += 1;
|
||||||
|
} else {
|
||||||
|
drained.push(array.remove(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
|
@ -86,7 +86,7 @@ pub mod blob_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut blob = Blob::new();
|
let mut blob = Blob::new();
|
||||||
blob.resize(len, (value & 0x000000ff) as u8);
|
blob.resize(len, (value & 0x0000_00ff) as u8);
|
||||||
Ok(blob)
|
Ok(blob)
|
||||||
}
|
}
|
||||||
/// Convert the BLOB into an array of integers.
|
/// Convert the BLOB into an array of integers.
|
||||||
@ -205,7 +205,7 @@ pub mod blob_functions {
|
|||||||
let (index, ..) = calc_offset_len(blob.len(), index, 0);
|
let (index, ..) = calc_offset_len(blob.len(), index, 0);
|
||||||
|
|
||||||
if index < blob.len() {
|
if index < blob.len() {
|
||||||
blob[index] = (value & 0x000000ff) as u8;
|
blob[index] = (value & 0x0000_00ff) as u8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Add a new byte `value` to the end of the BLOB.
|
/// Add a new byte `value` to the end of the BLOB.
|
||||||
@ -223,7 +223,7 @@ pub mod blob_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "push", name = "append")]
|
#[rhai_fn(name = "push", name = "append")]
|
||||||
pub fn push(blob: &mut Blob, value: INT) {
|
pub fn push(blob: &mut Blob, value: INT) {
|
||||||
blob.push((value & 0x000000ff) as u8);
|
blob.push((value & 0x0000_00ff) as u8);
|
||||||
}
|
}
|
||||||
/// Add another BLOB to the end of the BLOB.
|
/// Add another BLOB to the end of the BLOB.
|
||||||
///
|
///
|
||||||
@ -298,7 +298,7 @@ pub mod blob_functions {
|
|||||||
/// print(b); // prints "[4242184242]"
|
/// print(b); // prints "[4242184242]"
|
||||||
/// ```
|
/// ```
|
||||||
pub fn insert(blob: &mut Blob, index: INT, value: INT) {
|
pub fn insert(blob: &mut Blob, index: INT, value: INT) {
|
||||||
let value = (value & 0x000000ff) as u8;
|
let value = (value & 0x0000_00ff) as u8;
|
||||||
|
|
||||||
if blob.is_empty() {
|
if blob.is_empty() {
|
||||||
blob.push(value);
|
blob.push(value);
|
||||||
@ -338,7 +338,7 @@ pub mod blob_functions {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = (value & 0x000000ff) as u8;
|
let value = (value & 0x0000_00ff) as u8;
|
||||||
let _ctx = ctx;
|
let _ctx = ctx;
|
||||||
|
|
||||||
// Check if blob will be over max size limit
|
// Check if blob will be over max size limit
|
||||||
@ -528,7 +528,7 @@ pub mod blob_functions {
|
|||||||
pub fn splice_range(blob: &mut Blob, range: ExclusiveRange, replace: Blob) {
|
pub fn splice_range(blob: &mut Blob, range: ExclusiveRange, replace: Blob) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
splice(blob, start, end - start, replace)
|
splice(blob, start, end - start, replace);
|
||||||
}
|
}
|
||||||
/// Replace an inclusive `range` of the BLOB with another BLOB.
|
/// Replace an inclusive `range` of the BLOB with another BLOB.
|
||||||
///
|
///
|
||||||
@ -546,7 +546,7 @@ pub mod blob_functions {
|
|||||||
pub fn splice_range_inclusive(blob: &mut Blob, range: InclusiveRange, replace: Blob) {
|
pub fn splice_range_inclusive(blob: &mut Blob, range: InclusiveRange, replace: Blob) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
splice(blob, start, end - start + 1, replace)
|
splice(blob, start, end - start + 1, replace);
|
||||||
}
|
}
|
||||||
/// Replace a portion of the BLOB with another BLOB.
|
/// Replace a portion of the BLOB with another BLOB.
|
||||||
///
|
///
|
||||||
@ -1220,7 +1220,7 @@ mod write_int_functions {
|
|||||||
pub fn write_le_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) {
|
pub fn write_le_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
write_le_int(blob, start, end - start, value)
|
write_le_int(blob, start, end - start, value);
|
||||||
}
|
}
|
||||||
/// Write an `INT` value to the bytes within an inclusive `range` in the BLOB
|
/// Write an `INT` value to the bytes within an inclusive `range` in the BLOB
|
||||||
/// in little-endian byte order.
|
/// in little-endian byte order.
|
||||||
@ -1239,7 +1239,7 @@ mod write_int_functions {
|
|||||||
pub fn write_le_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) {
|
pub fn write_le_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
write_le_int(blob, start, end - start + 1, value)
|
write_le_int(blob, start, end - start + 1, value);
|
||||||
}
|
}
|
||||||
/// Write an `INT` value to the bytes beginning at the `start` position in the BLOB
|
/// Write an `INT` value to the bytes beginning at the `start` position in the BLOB
|
||||||
/// in little-endian byte order.
|
/// in little-endian byte order.
|
||||||
@ -1262,7 +1262,7 @@ mod write_int_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "write_le")]
|
#[rhai_fn(name = "write_le")]
|
||||||
pub fn write_le_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
pub fn write_le_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
||||||
write_int(blob, start, len, value, true)
|
write_int(blob, start, len, value, true);
|
||||||
}
|
}
|
||||||
/// Write an `INT` value to the bytes within an exclusive `range` in the BLOB
|
/// Write an `INT` value to the bytes within an exclusive `range` in the BLOB
|
||||||
/// in big-endian byte order.
|
/// in big-endian byte order.
|
||||||
@ -1281,7 +1281,7 @@ mod write_int_functions {
|
|||||||
pub fn write_be_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) {
|
pub fn write_be_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
write_be_int(blob, start, end - start, value)
|
write_be_int(blob, start, end - start, value);
|
||||||
}
|
}
|
||||||
/// Write an `INT` value to the bytes within an inclusive `range` in the BLOB
|
/// Write an `INT` value to the bytes within an inclusive `range` in the BLOB
|
||||||
/// in big-endian byte order.
|
/// in big-endian byte order.
|
||||||
@ -1300,7 +1300,7 @@ mod write_int_functions {
|
|||||||
pub fn write_be_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) {
|
pub fn write_be_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
write_be_int(blob, start, end - start + 1, value)
|
write_be_int(blob, start, end - start + 1, value);
|
||||||
}
|
}
|
||||||
/// Write an `INT` value to the bytes beginning at the `start` position in the BLOB
|
/// Write an `INT` value to the bytes beginning at the `start` position in the BLOB
|
||||||
/// in big-endian byte order.
|
/// in big-endian byte order.
|
||||||
@ -1323,7 +1323,7 @@ mod write_int_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "write_be")]
|
#[rhai_fn(name = "write_be")]
|
||||||
pub fn write_be_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
pub fn write_be_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
||||||
write_int(blob, start, len, value, false)
|
write_int(blob, start, len, value, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1360,7 +1360,7 @@ mod write_float_functions {
|
|||||||
pub fn write_le_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) {
|
pub fn write_le_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
write_le_float(blob, start, end - start, value)
|
write_le_float(blob, start, end - start, value);
|
||||||
}
|
}
|
||||||
/// Write a `FLOAT` value to the bytes within an inclusive `range` in the BLOB
|
/// Write a `FLOAT` value to the bytes within an inclusive `range` in the BLOB
|
||||||
/// in little-endian byte order.
|
/// in little-endian byte order.
|
||||||
@ -1371,7 +1371,7 @@ mod write_float_functions {
|
|||||||
pub fn write_le_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) {
|
pub fn write_le_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
write_le_float(blob, start, end - start + 1, value)
|
write_le_float(blob, start, end - start + 1, value);
|
||||||
}
|
}
|
||||||
/// Write a `FLOAT` value to the bytes beginning at the `start` position in the BLOB
|
/// Write a `FLOAT` value to the bytes beginning at the `start` position in the BLOB
|
||||||
/// in little-endian byte order.
|
/// in little-endian byte order.
|
||||||
@ -1386,7 +1386,7 @@ mod write_float_functions {
|
|||||||
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes in `range` are not modified.
|
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes in `range` are not modified.
|
||||||
#[rhai_fn(name = "write_le")]
|
#[rhai_fn(name = "write_le")]
|
||||||
pub fn write_le_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
pub fn write_le_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
||||||
write_float(blob, start, len, value, true)
|
write_float(blob, start, len, value, true);
|
||||||
}
|
}
|
||||||
/// Write a `FLOAT` value to the bytes within an exclusive `range` in the BLOB
|
/// Write a `FLOAT` value to the bytes within an exclusive `range` in the BLOB
|
||||||
/// in big-endian byte order.
|
/// in big-endian byte order.
|
||||||
@ -1397,7 +1397,7 @@ mod write_float_functions {
|
|||||||
pub fn write_be_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) {
|
pub fn write_be_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
write_be_float(blob, start, end - start, value)
|
write_be_float(blob, start, end - start, value);
|
||||||
}
|
}
|
||||||
/// Write a `FLOAT` value to the bytes within an inclusive `range` in the BLOB
|
/// Write a `FLOAT` value to the bytes within an inclusive `range` in the BLOB
|
||||||
/// in big-endian byte order.
|
/// in big-endian byte order.
|
||||||
@ -1408,7 +1408,7 @@ mod write_float_functions {
|
|||||||
pub fn write_be_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) {
|
pub fn write_be_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
write_be_float(blob, start, end - start + 1, value)
|
write_be_float(blob, start, end - start + 1, value);
|
||||||
}
|
}
|
||||||
/// Write a `FLOAT` value to the bytes beginning at the `start` position in the BLOB
|
/// Write a `FLOAT` value to the bytes beginning at the `start` position in the BLOB
|
||||||
/// in big-endian byte order.
|
/// in big-endian byte order.
|
||||||
@ -1423,7 +1423,7 @@ mod write_float_functions {
|
|||||||
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes in `range` are not modified.
|
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes in `range` are not modified.
|
||||||
#[rhai_fn(name = "write_be")]
|
#[rhai_fn(name = "write_be")]
|
||||||
pub fn write_be_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
pub fn write_be_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
||||||
write_float(blob, start, len, value, false)
|
write_float(blob, start, len, value, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1471,7 +1471,7 @@ mod write_string_functions {
|
|||||||
pub fn write_utf8_string_range(blob: &mut Blob, range: ExclusiveRange, string: &str) {
|
pub fn write_utf8_string_range(blob: &mut Blob, range: ExclusiveRange, string: &str) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
write_string(blob, start, end - start, string, false)
|
write_string(blob, start, end - start, string, false);
|
||||||
}
|
}
|
||||||
/// Write a string to the bytes within an inclusive `range` in the BLOB in UTF-8 encoding.
|
/// Write a string to the bytes within an inclusive `range` in the BLOB in UTF-8 encoding.
|
||||||
///
|
///
|
||||||
@ -1489,7 +1489,7 @@ mod write_string_functions {
|
|||||||
pub fn write_utf8_string_range_inclusive(blob: &mut Blob, range: InclusiveRange, string: &str) {
|
pub fn write_utf8_string_range_inclusive(blob: &mut Blob, range: InclusiveRange, string: &str) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
write_string(blob, start, end - start + 1, string, false)
|
write_string(blob, start, end - start + 1, string, false);
|
||||||
}
|
}
|
||||||
/// Write a string to the bytes within an inclusive `range` in the BLOB in UTF-8 encoding.
|
/// Write a string to the bytes within an inclusive `range` in the BLOB in UTF-8 encoding.
|
||||||
///
|
///
|
||||||
@ -1511,7 +1511,7 @@ mod write_string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "write_utf8")]
|
#[rhai_fn(name = "write_utf8")]
|
||||||
pub fn write_utf8_string(blob: &mut Blob, start: INT, len: INT, string: &str) {
|
pub fn write_utf8_string(blob: &mut Blob, start: INT, len: INT, string: &str) {
|
||||||
write_string(blob, start, len, string, false)
|
write_string(blob, start, len, string, false);
|
||||||
}
|
}
|
||||||
/// Write an ASCII string to the bytes within an exclusive `range` in the BLOB.
|
/// Write an ASCII string to the bytes within an exclusive `range` in the BLOB.
|
||||||
///
|
///
|
||||||
@ -1532,7 +1532,7 @@ mod write_string_functions {
|
|||||||
pub fn write_ascii_string_range(blob: &mut Blob, range: ExclusiveRange, string: &str) {
|
pub fn write_ascii_string_range(blob: &mut Blob, range: ExclusiveRange, string: &str) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
write_string(blob, start, end - start, string, true)
|
write_string(blob, start, end - start, string, true);
|
||||||
}
|
}
|
||||||
/// Write an ASCII string to the bytes within an inclusive `range` in the BLOB.
|
/// Write an ASCII string to the bytes within an inclusive `range` in the BLOB.
|
||||||
///
|
///
|
||||||
@ -1557,7 +1557,7 @@ mod write_string_functions {
|
|||||||
) {
|
) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
write_string(blob, start, end - start + 1, string, true)
|
write_string(blob, start, end - start + 1, string, true);
|
||||||
}
|
}
|
||||||
/// Write an ASCII string to the bytes within an exclusive `range` in the BLOB.
|
/// Write an ASCII string to the bytes within an exclusive `range` in the BLOB.
|
||||||
///
|
///
|
||||||
@ -1579,6 +1579,6 @@ mod write_string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "write_ascii")]
|
#[rhai_fn(name = "write_ascii")]
|
||||||
pub fn write_ascii_string(blob: &mut Blob, start: INT, len: INT, string: &str) {
|
pub fn write_ascii_string(blob: &mut Blob, start: INT, len: INT, string: &str) {
|
||||||
write_string(blob, start, len, string, true)
|
write_string(blob, start, len, string, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Range iterator with step
|
// Range iterator with step
|
||||||
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct StepRange<T: Debug + Copy + PartialOrd> {
|
pub struct StepRange<T: Debug + Copy + PartialOrd> {
|
||||||
pub from: T,
|
pub from: T,
|
||||||
pub to: T,
|
pub to: T,
|
||||||
@ -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)
|
||||||
@ -115,7 +110,7 @@ impl<T: Debug + Copy + PartialOrd> Iterator for StepRange<T> {
|
|||||||
impl<T: Debug + Copy + PartialOrd> FusedIterator for StepRange<T> {}
|
impl<T: Debug + Copy + PartialOrd> FusedIterator for StepRange<T> {}
|
||||||
|
|
||||||
// Bit-field iterator with step
|
// Bit-field iterator with step
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct BitRange(INT, INT, usize);
|
pub struct BitRange(INT, INT, usize);
|
||||||
|
|
||||||
impl BitRange {
|
impl BitRange {
|
||||||
@ -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)
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ fn collect_fn_metadata(
|
|||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.engine()
|
ctx.engine()
|
||||||
@ -237,7 +237,7 @@ fn collect_fn_metadata(
|
|||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -255,7 +255,7 @@ fn collect_fn_metadata(
|
|||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -264,7 +264,7 @@ fn collect_fn_metadata(
|
|||||||
fn scan_module(
|
fn scan_module(
|
||||||
list: &mut Array,
|
list: &mut Array,
|
||||||
dict: &BTreeSet<Identifier>,
|
dict: &BTreeSet<Identifier>,
|
||||||
namespace: Identifier,
|
namespace: &str,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
filter: impl Fn(
|
filter: impl Fn(
|
||||||
FnNamespace,
|
FnNamespace,
|
||||||
@ -278,7 +278,7 @@ fn collect_fn_metadata(
|
|||||||
module
|
module
|
||||||
.iter_script_fn()
|
.iter_script_fn()
|
||||||
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
|
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
|
||||||
.for_each(|(.., f)| list.push(make_metadata(dict, namespace.clone(), f).into()));
|
.for_each(|(.., f)| list.push(make_metadata(dict, namespace.into(), f).into()));
|
||||||
for (ns, m) in module.iter_sub_modules() {
|
for (ns, m) in module.iter_sub_modules() {
|
||||||
let ns = format!(
|
let ns = format!(
|
||||||
"{}{}{}",
|
"{}{}{}",
|
||||||
@ -286,12 +286,12 @@ fn collect_fn_metadata(
|
|||||||
crate::tokenizer::Token::DoubleColon.literal_syntax(),
|
crate::tokenizer::Token::DoubleColon.literal_syntax(),
|
||||||
ns
|
ns
|
||||||
);
|
);
|
||||||
scan_module(list, dict, ns.into(), &**m, filter)
|
scan_module(list, dict, &ns, &**m, filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ns, m) in ctx.iter_imports_raw() {
|
for (ns, m) in ctx.iter_imports_raw() {
|
||||||
scan_module(&mut list, &dict, ns.clone(), &**m, filter)
|
scan_module(&mut list, &dict, ns, &**m, filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,10 +92,10 @@ mod map_functions {
|
|||||||
/// print(m); // prints "#{a:1, c:3}"
|
/// print(m); // prints "#{a:1, c:3}"
|
||||||
/// ```
|
/// ```
|
||||||
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)
|
|
||||||
} else {
|
|
||||||
Dynamic::UNIT
|
Dynamic::UNIT
|
||||||
|
} else {
|
||||||
|
map.remove(property).unwrap_or(Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Add all property values of another object map into the object map.
|
/// Add all property values of another object map into the object map.
|
||||||
@ -160,9 +160,9 @@ mod map_functions {
|
|||||||
if map.is_empty() {
|
if map.is_empty() {
|
||||||
*map = map2;
|
*map = map2;
|
||||||
} else {
|
} else {
|
||||||
map2.into_iter().for_each(|(key, value)| {
|
for (key, value) in map2 {
|
||||||
map.entry(key).or_insert(value);
|
map.entry(key).or_insert(value);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ macro_rules! def_package {
|
|||||||
|
|
||||||
impl $package {
|
impl $package {
|
||||||
#[doc=concat!("Create a new `", stringify!($package), "`")]
|
#[doc=concat!("Create a new `", stringify!($package), "`")]
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut module = $crate::Module::new();
|
let mut module = $crate::Module::new();
|
||||||
<Self as $crate::packages::Package>::init(&mut module);
|
<Self as $crate::packages::Package>::init(&mut module);
|
||||||
|
@ -114,7 +114,7 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_prepend(utf8: Blob, string: ImmutableString) -> ImmutableString {
|
pub fn add_prepend(utf8: Blob, string: &str) -> ImmutableString {
|
||||||
let s = String::from_utf8_lossy(&utf8);
|
let s = String::from_utf8_lossy(&utf8);
|
||||||
let mut s = match s {
|
let mut s = match s {
|
||||||
std::borrow::Cow::Borrowed(_) => String::from_utf8(utf8).unwrap(),
|
std::borrow::Cow::Borrowed(_) => String::from_utf8(utf8).unwrap(),
|
||||||
@ -122,7 +122,7 @@ mod string_functions {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !string.is_empty() {
|
if !string.is_empty() {
|
||||||
s.push_str(&string);
|
s.push_str(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.into()
|
s.into()
|
||||||
@ -440,7 +440,7 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "make_upper")]
|
#[rhai_fn(name = "make_upper")]
|
||||||
pub fn make_upper_char(character: &mut char) {
|
pub fn make_upper_char(character: &mut char) {
|
||||||
*character = to_upper_char(*character)
|
*character = to_upper_char(*character);
|
||||||
}
|
}
|
||||||
/// Convert the character to lower-case and return it as a new character.
|
/// Convert the character to lower-case and return it as a new character.
|
||||||
///
|
///
|
||||||
@ -476,7 +476,7 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "make_lower")]
|
#[rhai_fn(name = "make_lower")]
|
||||||
pub fn make_lower_char(character: &mut char) {
|
pub fn make_lower_char(character: &mut char) {
|
||||||
*character = to_lower_char(*character)
|
*character = to_lower_char(*character);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the string starts with a specified string.
|
/// Return `true` if the string starts with a specified string.
|
||||||
@ -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
|
||||||
@ -561,10 +558,9 @@ mod string_functions {
|
|||||||
.len()
|
.len()
|
||||||
};
|
};
|
||||||
|
|
||||||
string[start..]
|
string[start..].find(character).map_or(-1 as INT, |index| {
|
||||||
.find(character)
|
string[0..start + index].chars().count() as INT
|
||||||
.map(|index| string[0..start + index].chars().count() as INT)
|
})
|
||||||
.unwrap_or(-1 as INT)
|
|
||||||
}
|
}
|
||||||
/// Find the specified `character` in the string and return the first index where it is found.
|
/// Find the specified `character` in the string and return the first index where it is found.
|
||||||
/// If the `character` is not found, `-1` is returned.
|
/// If the `character` is not found, `-1` is returned.
|
||||||
@ -585,8 +581,7 @@ mod string_functions {
|
|||||||
} else {
|
} else {
|
||||||
string
|
string
|
||||||
.find(character)
|
.find(character)
|
||||||
.map(|index| string[0..index].chars().count() as INT)
|
.map_or(-1 as INT, |index| string[0..index].chars().count() as INT)
|
||||||
.unwrap_or(-1 as INT)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Find the specified sub-string in the string, starting from the specified `start` position,
|
/// Find the specified sub-string in the string, starting from the specified `start` position,
|
||||||
@ -615,20 +610,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
|
||||||
@ -644,8 +636,9 @@ mod string_functions {
|
|||||||
|
|
||||||
string[start..]
|
string[start..]
|
||||||
.find(find_string)
|
.find(find_string)
|
||||||
.map(|index| string[0..start + index].chars().count() as INT)
|
.map_or(-1 as INT, |index| {
|
||||||
.unwrap_or(-1 as INT)
|
string[0..start + index].chars().count() as INT
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/// Find the specified `character` in the string and return the first index where it is found.
|
/// Find the specified `character` in the string and return the first index where it is found.
|
||||||
/// If the `character` is not found, `-1` is returned.
|
/// If the `character` is not found, `-1` is returned.
|
||||||
@ -666,8 +659,7 @@ mod string_functions {
|
|||||||
} else {
|
} else {
|
||||||
string
|
string
|
||||||
.find(find_string)
|
.find(find_string)
|
||||||
.map(|index| string[0..index].chars().count() as INT)
|
.map_or(-1 as INT, |index| string[0..index].chars().count() as INT)
|
||||||
.unwrap_or(-1 as INT)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,15 +686,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 +726,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 +811,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();
|
||||||
@ -850,7 +838,7 @@ mod string_functions {
|
|||||||
.iter()
|
.iter()
|
||||||
.skip(offset)
|
.skip(offset)
|
||||||
.take(len)
|
.take(len)
|
||||||
.cloned()
|
.copied()
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
@ -899,7 +887,7 @@ mod string_functions {
|
|||||||
pub fn crop_range(string: &mut ImmutableString, range: ExclusiveRange) {
|
pub fn crop_range(string: &mut ImmutableString, range: ExclusiveRange) {
|
||||||
let start = INT::max(range.start, 0);
|
let start = INT::max(range.start, 0);
|
||||||
let end = INT::max(range.end, start);
|
let end = INT::max(range.end, start);
|
||||||
crop(string, start, end - start)
|
crop(string, start, end - start);
|
||||||
}
|
}
|
||||||
/// Remove all characters from the string except those within an inclusive `range`.
|
/// Remove all characters from the string except those within an inclusive `range`.
|
||||||
///
|
///
|
||||||
@ -916,7 +904,7 @@ mod string_functions {
|
|||||||
pub fn crop_inclusive_range(string: &mut ImmutableString, range: InclusiveRange) {
|
pub fn crop_inclusive_range(string: &mut ImmutableString, range: InclusiveRange) {
|
||||||
let start = INT::max(*range.start(), 0);
|
let start = INT::max(*range.start(), 0);
|
||||||
let end = INT::max(*range.end(), start);
|
let end = INT::max(*range.end(), start);
|
||||||
crop(string, start, end - start + 1)
|
crop(string, start, end - start + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove all characters from the string except those within a range.
|
/// Remove all characters from the string except those within a range.
|
||||||
@ -952,15 +940,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 +1241,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();
|
||||||
|
110
src/parser.rs
110
src/parser.rs
@ -130,6 +130,7 @@ impl<'e> ParseState<'e> {
|
|||||||
/// If the variable is not present in the scope, the first return value is zero.
|
/// If the variable is not present in the scope, the first return value is zero.
|
||||||
///
|
///
|
||||||
/// The second return value indicates whether the barrier has been hit before finding the variable.
|
/// The second return value indicates whether the barrier has been hit before finding the variable.
|
||||||
|
#[must_use]
|
||||||
pub fn find_var(&self, name: &str) -> (usize, bool) {
|
pub fn find_var(&self, name: &str) -> (usize, bool) {
|
||||||
let mut hit_barrier = false;
|
let mut hit_barrier = false;
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ impl<'e> ParseState<'e> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.allow_capture = true
|
self.allow_capture = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if hit_barrier {
|
if hit_barrier {
|
||||||
@ -265,10 +266,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(())
|
||||||
}
|
}
|
||||||
@ -362,7 +361,10 @@ impl Expr {
|
|||||||
|
|
||||||
/// Make sure that the next expression is not a statement expression (i.e. wrapped in `{}`).
|
/// Make sure that the next expression is not a statement expression (i.e. wrapped in `{}`).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ensure_not_statement_expr(input: &mut TokenStream, type_name: impl ToString) -> ParseResult<()> {
|
fn ensure_not_statement_expr(
|
||||||
|
input: &mut TokenStream,
|
||||||
|
type_name: &(impl ToString + ?Sized),
|
||||||
|
) -> ParseResult<()> {
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
(Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
|
(Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
@ -521,7 +523,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash = if !namespace.is_empty() {
|
let hash = if namespace.is_empty() {
|
||||||
|
calc_fn_hash(&id, 0)
|
||||||
|
} else {
|
||||||
let root = namespace.root();
|
let root = namespace.root();
|
||||||
let index = state.find_module(root);
|
let index = state.find_module(root);
|
||||||
|
|
||||||
@ -531,18 +535,19 @@ 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);
|
||||||
|
|
||||||
crate::calc_qualified_fn_hash(namespace.iter().map(|m| m.as_str()), &id, 0)
|
crate::calc_qualified_fn_hash(namespace.iter().map(Ident::as_str), &id, 0)
|
||||||
} else {
|
|
||||||
calc_fn_hash(&id, 0)
|
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
let hash = calc_fn_hash(&id, 0);
|
let hash = calc_fn_hash(&id, 0);
|
||||||
@ -585,7 +590,9 @@ impl Engine {
|
|||||||
eat_token(input, Token::RightParen);
|
eat_token(input, Token::RightParen);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash = if !namespace.is_empty() {
|
let hash = if namespace.is_empty() {
|
||||||
|
calc_fn_hash(&id, args.len())
|
||||||
|
} else {
|
||||||
let root = namespace.root();
|
let root = namespace.root();
|
||||||
let index = state.find_module(root);
|
let index = state.find_module(root);
|
||||||
|
|
||||||
@ -595,22 +602,22 @@ 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);
|
||||||
|
|
||||||
crate::calc_qualified_fn_hash(
|
crate::calc_qualified_fn_hash(
|
||||||
namespace.iter().map(|m| m.as_str()),
|
namespace.iter().map(Ident::as_str),
|
||||||
&id,
|
&id,
|
||||||
args.len(),
|
args.len(),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
calc_fn_hash(&id, args.len())
|
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
let hash = calc_fn_hash(&id, args.len());
|
let hash = calc_fn_hash(&id, args.len());
|
||||||
@ -785,7 +792,7 @@ impl Engine {
|
|||||||
// Any more indexing following?
|
// Any more indexing following?
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
// If another indexing level, right-bind it
|
// If another indexing level, right-bind it
|
||||||
(Token::LeftBracket, ..) | (Token::QuestionBracket, ..) => {
|
(Token::LeftBracket | Token::QuestionBracket, ..) => {
|
||||||
let (token, pos) = input.next().expect(NEVER_ENDS);
|
let (token, pos) = input.next().expect(NEVER_ENDS);
|
||||||
let prev_pos = settings.pos;
|
let prev_pos = settings.pos;
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
@ -1085,7 +1092,10 @@ impl Engine {
|
|||||||
return Err(PERR::WrongSwitchCaseCondition.into_err(if_pos));
|
return Err(PERR::WrongSwitchCaseCondition.into_err(if_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
(Default::default(), Expr::BoolConstant(true, Position::NONE))
|
(
|
||||||
|
StaticVec::default(),
|
||||||
|
Expr::BoolConstant(true, Position::NONE),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ if def_case.is_some() => {
|
_ if def_case.is_some() => {
|
||||||
return Err(PERR::WrongSwitchDefaultCase.into_err(def_case_pos))
|
return Err(PERR::WrongSwitchDefaultCase.into_err(def_case_pos))
|
||||||
@ -1146,7 +1156,9 @@ impl Engine {
|
|||||||
expressions.push((condition, Expr::Stmt(stmt_block.into())).into());
|
expressions.push((condition, Expr::Stmt(stmt_block.into())).into());
|
||||||
let index = expressions.len() - 1;
|
let index = expressions.len() - 1;
|
||||||
|
|
||||||
if !case_expr_list.is_empty() {
|
if case_expr_list.is_empty() {
|
||||||
|
def_case = Some(index);
|
||||||
|
} else {
|
||||||
for expr in case_expr_list {
|
for expr in case_expr_list {
|
||||||
let value = expr.get_literal_value().ok_or_else(|| {
|
let value = expr.get_literal_value().ok_or_else(|| {
|
||||||
PERR::ExprExpected("a literal".to_string()).into_err(expr.start_position())
|
PERR::ExprExpected("a literal".to_string()).into_err(expr.start_position())
|
||||||
@ -1197,8 +1209,6 @@ impl Engine {
|
|||||||
.and_modify(|cases| cases.push(index))
|
.and_modify(|cases| cases.push(index))
|
||||||
.or_insert_with(|| [index].into());
|
.or_insert_with(|| [index].into());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
def_case = Some(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
@ -1687,7 +1697,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// Indexing
|
// Indexing
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
(expr, token @ Token::LeftBracket) | (expr, token @ Token::QuestionBracket) => {
|
(expr, token @ (Token::LeftBracket | Token::QuestionBracket)) => {
|
||||||
let opt = match token {
|
let opt = match token {
|
||||||
Token::LeftBracket => ASTFlags::NONE,
|
Token::LeftBracket => ASTFlags::NONE,
|
||||||
Token::QuestionBracket => ASTFlags::NEGATED,
|
Token::QuestionBracket => ASTFlags::NEGATED,
|
||||||
@ -1697,7 +1707,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// Property access
|
// Property access
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
(expr, op @ Token::Period) | (expr, op @ Token::Elvis) => {
|
(expr, op @ (Token::Period | Token::Elvis)) => {
|
||||||
// Expression after dot must start with an identifier
|
// Expression after dot must start with an identifier
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
(Token::Identifier(..), ..) => {
|
(Token::Identifier(..), ..) => {
|
||||||
@ -1742,7 +1752,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if let Some((.., namespace, hash, name)) = namespaced_variable {
|
if let Some((.., namespace, hash, name)) = namespaced_variable {
|
||||||
if !namespace.is_empty() {
|
if !namespace.is_empty() {
|
||||||
*hash = crate::calc_qualified_var_hash(namespace.iter().map(|v| v.as_str()), name);
|
*hash = crate::calc_qualified_var_hash(namespace.iter().map(Ident::as_str), name);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
@ -1755,11 +1765,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);
|
||||||
@ -2190,7 +2203,7 @@ impl Engine {
|
|||||||
Token::Custom(c) => self
|
Token::Custom(c) => self
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(c)
|
||||||
.cloned()
|
.copied()
|
||||||
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*current_pos))?,
|
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*current_pos))?,
|
||||||
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
||||||
return Err(PERR::UnknownOperator(c.to_string()).into_err(*current_pos))
|
return Err(PERR::UnknownOperator(c.to_string()).into_err(*current_pos))
|
||||||
@ -2215,7 +2228,7 @@ impl Engine {
|
|||||||
Token::Custom(c) => self
|
Token::Custom(c) => self
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(c)
|
||||||
.cloned()
|
.copied()
|
||||||
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*next_pos))?,
|
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*next_pos))?,
|
||||||
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
||||||
return Err(PERR::UnknownOperator(c.to_string()).into_err(*next_pos))
|
return Err(PERR::UnknownOperator(c.to_string()).into_err(*next_pos))
|
||||||
@ -2519,13 +2532,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 +2807,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 +3205,6 @@ impl Engine {
|
|||||||
level: 0,
|
level: 0,
|
||||||
options,
|
options,
|
||||||
pos,
|
pos,
|
||||||
..settings
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let func = self.parse_fn(
|
let func = self.parse_fn(
|
||||||
@ -3424,7 +3436,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
let s = state.get_identifier("", s);
|
let s = state.get_identifier("", s);
|
||||||
state.stack.push(s.clone(), ());
|
state.stack.push(s.clone(), ());
|
||||||
params.push((s, pos))
|
params.push((s, pos));
|
||||||
}
|
}
|
||||||
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
||||||
(.., pos) => {
|
(.., pos) => {
|
||||||
@ -3560,7 +3572,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
let s = state.get_identifier("", s);
|
let s = state.get_identifier("", s);
|
||||||
state.stack.push(s.clone(), ());
|
state.stack.push(s.clone(), ());
|
||||||
params_list.push(s)
|
params_list.push(s);
|
||||||
}
|
}
|
||||||
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
||||||
(.., pos) => {
|
(.., pos) => {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
//! Implement deserialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
|
//! Implement deserialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
|
||||||
|
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::dynamic::Union;
|
||||||
use crate::{Dynamic, ImmutableString, LexError, Position, RhaiError, RhaiResultOf, ERR};
|
use crate::{
|
||||||
|
Dynamic, ImmutableString, LexError, Position, RhaiError, RhaiResultOf, SmartString, ERR,
|
||||||
|
};
|
||||||
use serde::de::{Error, IntoDeserializer, Visitor};
|
use serde::de::{Error, IntoDeserializer, Visitor};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -420,7 +422,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|| self.type_error(),
|
|| self.type_error(),
|
||||||
|map| {
|
|map| {
|
||||||
_visitor.visit_map(IterateMap::new(
|
_visitor.visit_map(IterateMap::new(
|
||||||
map.keys().map(|key| key.as_str()),
|
map.keys().map(SmartString::as_str),
|
||||||
map.values(),
|
map.values(),
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
@ -455,7 +457,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 {
|
||||||
|
@ -181,7 +181,7 @@ impl ModuleMetadata<'_> {
|
|||||||
|
|
||||||
impl<'a> From<&'a crate::Module> for ModuleMetadata<'a> {
|
impl<'a> From<&'a crate::Module> for ModuleMetadata<'a> {
|
||||||
fn from(module: &'a crate::Module) -> Self {
|
fn from(module: &'a crate::Module) -> Self {
|
||||||
let mut functions: Vec<_> = module.iter_fn().map(|f| f.into()).collect();
|
let mut functions: Vec<_> = module.iter_fn().map(Into::into).collect();
|
||||||
functions.sort();
|
functions.sort();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -210,7 +210,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
/// Print this [`Position`] for debug purposes.
|
/// Print this [`Position`] for debug purposes.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn debug_print(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
pub(crate) fn debug_print(self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if !self.is_none() {
|
if !self.is_none() {
|
||||||
write!(_f, " @ {:?}", self)?;
|
write!(_f, " @ {:?}", self)?;
|
||||||
}
|
}
|
||||||
@ -1215,7 +1215,7 @@ pub fn parse_string_literal(
|
|||||||
if allow_interpolation
|
if allow_interpolation
|
||||||
&& next_char == '$'
|
&& next_char == '$'
|
||||||
&& escape.is_empty()
|
&& escape.is_empty()
|
||||||
&& stream.peek_next().map(|ch| ch == '{').unwrap_or(false)
|
&& stream.peek_next().map_or(false, |ch| ch == '{')
|
||||||
{
|
{
|
||||||
interpolated = true;
|
interpolated = true;
|
||||||
state.is_within_text_terminated_by = None;
|
state.is_within_text_terminated_by = None;
|
||||||
@ -1245,7 +1245,7 @@ pub fn parse_string_literal(
|
|||||||
|
|
||||||
match next_char {
|
match next_char {
|
||||||
// \r - ignore if followed by \n
|
// \r - ignore if followed by \n
|
||||||
'\r' if stream.peek_next().map(|ch| ch == '\n').unwrap_or(false) => (),
|
'\r' if stream.peek_next().map_or(false, |ch| ch == '\n') => (),
|
||||||
// \...
|
// \...
|
||||||
'\\' if !verbatim && escape.is_empty() => {
|
'\\' if !verbatim && escape.is_empty() => {
|
||||||
escape.push('\\');
|
escape.push('\\');
|
||||||
@ -1271,7 +1271,7 @@ pub fn parse_string_literal(
|
|||||||
result.push('\r');
|
result.push('\r');
|
||||||
}
|
}
|
||||||
// \x??, \u????, \U????????
|
// \x??, \u????, \U????????
|
||||||
ch @ 'x' | ch @ 'u' | ch @ 'U' if !escape.is_empty() => {
|
ch @ ('x' | 'u' | 'U') if !escape.is_empty() => {
|
||||||
let mut seq = escape.clone();
|
let mut seq = escape.clone();
|
||||||
escape.clear();
|
escape.clear();
|
||||||
seq.push(ch);
|
seq.push(ch);
|
||||||
@ -1307,7 +1307,7 @@ pub fn parse_string_literal(
|
|||||||
// \{termination_char} - escaped
|
// \{termination_char} - escaped
|
||||||
_ if termination_char == next_char && !escape.is_empty() => {
|
_ if termination_char == next_char && !escape.is_empty() => {
|
||||||
escape.clear();
|
escape.clear();
|
||||||
result.push(next_char)
|
result.push(next_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verbatim
|
// Verbatim
|
||||||
@ -1598,7 +1598,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 0x????, 0o????, 0b???? at beginning
|
// 0x????, 0o????, 0b???? at beginning
|
||||||
ch @ 'x' | ch @ 'o' | ch @ 'b' | ch @ 'X' | ch @ 'O' | ch @ 'B'
|
ch @ ('x' | 'o' | 'b' | 'X' | 'O' | 'B')
|
||||||
if c == '0' && result.len() <= 1 =>
|
if c == '0' && result.len() <= 1 =>
|
||||||
{
|
{
|
||||||
result.push(next_char);
|
result.push(next_char);
|
||||||
@ -1639,12 +1639,14 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
UNSIGNED_INT::from_str_radix(&out, radix)
|
UNSIGNED_INT::from_str_radix(&out, radix)
|
||||||
.map(|v| v as INT)
|
.map(|v| v as INT)
|
||||||
.map(Token::IntegerConstant)
|
.map_or_else(
|
||||||
.unwrap_or_else(|_| {
|
|_| {
|
||||||
Token::LexError(
|
Token::LexError(
|
||||||
LERR::MalformedNumber(result.into_iter().collect()).into(),
|
LERR::MalformedNumber(result.into_iter().collect()).into(),
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
Token::IntegerConstant,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let out: String =
|
let out: String =
|
||||||
result.iter().filter(|&&c| c != NUMBER_SEPARATOR).collect();
|
result.iter().filter(|&&c| c != NUMBER_SEPARATOR).collect();
|
||||||
@ -1680,7 +1682,7 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
// letter or underscore ...
|
// letter or underscore ...
|
||||||
#[cfg(not(feature = "unicode-xid-ident"))]
|
#[cfg(not(feature = "unicode-xid-ident"))]
|
||||||
('a'..='z', ..) | ('_', ..) | ('A'..='Z', ..) => {
|
('a'..='z' | '_' | 'A'..='Z', ..) => {
|
||||||
return get_identifier(stream, pos, start_pos, c);
|
return get_identifier(stream, pos, start_pos, c);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "unicode-xid-ident")]
|
#[cfg(feature = "unicode-xid-ident")]
|
||||||
@ -2161,7 +2163,7 @@ fn get_identifier(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_valid_identifier = is_valid_identifier(result.iter().cloned());
|
let is_valid_identifier = is_valid_identifier(result.iter().copied());
|
||||||
|
|
||||||
let identifier: String = result.into_iter().collect();
|
let identifier: String = result.into_iter().collect();
|
||||||
|
|
||||||
@ -2384,7 +2386,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
("::<", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
("::<", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
||||||
"'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(),
|
"'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(),
|
||||||
).into()),
|
).into()),
|
||||||
("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
("(*" | "*)", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
||||||
"'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(),
|
"'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(),
|
||||||
).into()),
|
).into()),
|
||||||
("# {", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
("# {", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
||||||
|
@ -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),
|
||||||
@ -739,7 +739,7 @@ impl Dynamic {
|
|||||||
/// A [`Dynamic`] containing the integer 1,000.
|
/// A [`Dynamic`] containing the integer 1,000.
|
||||||
pub const THOUSAND: Self = Self::from_int(1000);
|
pub const THOUSAND: Self = Self::from_int(1000);
|
||||||
/// A [`Dynamic`] containing the integer 1,000,000.
|
/// A [`Dynamic`] containing the integer 1,000,000.
|
||||||
pub const MILLION: Self = Self::from_int(1000000);
|
pub const MILLION: Self = Self::from_int(1_000_000);
|
||||||
/// A [`Dynamic`] containing the integer -1.
|
/// A [`Dynamic`] containing the integer -1.
|
||||||
pub const NEGATIVE_ONE: Self = Self::from_int(-1);
|
pub const NEGATIVE_ONE: Self = Self::from_int(-1);
|
||||||
/// A [`Dynamic`] containing the integer -2.
|
/// A [`Dynamic`] containing the integer -2.
|
||||||
@ -778,7 +778,7 @@ impl Dynamic {
|
|||||||
///
|
///
|
||||||
/// Not available under `no_float`.
|
/// Not available under `no_float`.
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
pub const FLOAT_MILLION: Self = Self::from_float(1000000.0);
|
pub const FLOAT_MILLION: Self = Self::from_float(1_000_000.0);
|
||||||
/// A [`Dynamic`] containing `-1.0`.
|
/// A [`Dynamic`] containing `-1.0`.
|
||||||
///
|
///
|
||||||
/// Not available under `no_float`.
|
/// Not available under `no_float`.
|
||||||
@ -823,7 +823,7 @@ impl Dynamic {
|
|||||||
///
|
///
|
||||||
/// Not available under `no_float`.
|
/// Not available under `no_float`.
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
pub const FLOAT_MILLIONTH: Self = Self::from_float(0.000001);
|
pub const FLOAT_MILLIONTH: Self = Self::from_float(0.000_001);
|
||||||
/// A [`Dynamic`] containing π.
|
/// A [`Dynamic`] containing π.
|
||||||
///
|
///
|
||||||
/// Not available under `no_float`.
|
/// Not available under `no_float`.
|
||||||
@ -867,16 +867,19 @@ impl Dynamic {
|
|||||||
|
|
||||||
/// Create a new [`Dynamic`] from a [`bool`].
|
/// Create a new [`Dynamic`] from a [`bool`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn from_bool(value: bool) -> Self {
|
pub const fn from_bool(value: bool) -> Self {
|
||||||
Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
/// Create a new [`Dynamic`] from an [`INT`].
|
/// Create a new [`Dynamic`] from an [`INT`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn from_int(value: INT) -> Self {
|
pub const fn from_int(value: INT) -> Self {
|
||||||
Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
/// Create a new [`Dynamic`] from a [`char`].
|
/// Create a new [`Dynamic`] from a [`char`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn from_char(value: char) -> Self {
|
pub const fn from_char(value: char) -> Self {
|
||||||
Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
@ -885,6 +888,7 @@ impl Dynamic {
|
|||||||
/// Not available under `no_float`.
|
/// Not available under `no_float`.
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub const fn from_float(value: crate::FLOAT) -> Self {
|
pub const fn from_float(value: crate::FLOAT) -> Self {
|
||||||
Self(Union::Float(
|
Self(Union::Float(
|
||||||
crate::ast::FloatWrapper::new_const(value),
|
crate::ast::FloatWrapper::new_const(value),
|
||||||
@ -897,24 +901,28 @@ impl Dynamic {
|
|||||||
/// Exported under the `decimal` feature only.
|
/// Exported under the `decimal` feature only.
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn from_decimal(value: rust_decimal::Decimal) -> Self {
|
pub fn from_decimal(value: rust_decimal::Decimal) -> Self {
|
||||||
Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
/// Create a [`Dynamic`] from an [`Array`][crate::Array].
|
/// Create a [`Dynamic`] from an [`Array`][crate::Array].
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn from_array(array: crate::Array) -> Self {
|
pub fn from_array(array: crate::Array) -> Self {
|
||||||
Self(Union::Array(array.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Array(array.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
/// Create a [`Dynamic`] from a [`Blob`][crate::Blob].
|
/// Create a [`Dynamic`] from a [`Blob`][crate::Blob].
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn from_blob(blob: crate::Blob) -> Self {
|
pub fn from_blob(blob: crate::Blob) -> Self {
|
||||||
Self(Union::Blob(blob.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Blob(blob.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
/// Create a [`Dynamic`] from a [`Map`][crate::Map].
|
/// Create a [`Dynamic`] from a [`Map`][crate::Map].
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn from_map(map: crate::Map) -> Self {
|
pub fn from_map(map: crate::Map) -> Self {
|
||||||
Self(Union::Map(map.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Map(map.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
@ -923,6 +931,7 @@ impl Dynamic {
|
|||||||
/// Not available under `no-std`.
|
/// Not available under `no-std`.
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn from_timestamp(value: Instant) -> Self {
|
pub fn from_timestamp(value: Instant) -> Self {
|
||||||
Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
@ -993,6 +1002,7 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Make this [`Dynamic`] read-only (i.e. a constant).
|
/// Make this [`Dynamic`] read-only (i.e. a constant).
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn into_read_only(self) -> Self {
|
pub fn into_read_only(self) -> Self {
|
||||||
let mut value = self;
|
let mut value = self;
|
||||||
value.set_access_mode(AccessMode::ReadOnly);
|
value.set_access_mode(AccessMode::ReadOnly);
|
||||||
@ -1018,17 +1028,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 +1372,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
|
||||||
@ -1397,13 +1398,13 @@ impl Dynamic {
|
|||||||
Union::Shared(ref cell, ..) => {
|
Union::Shared(ref cell, ..) => {
|
||||||
let value = locked_read(cell);
|
let value = locked_read(cell);
|
||||||
|
|
||||||
if (*value).type_id() != TypeId::of::<T>()
|
return if (*value).type_id() != TypeId::of::<T>()
|
||||||
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
|
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
|
||||||
{
|
{
|
||||||
return None;
|
None
|
||||||
} else {
|
} else {
|
||||||
return Some(DynamicReadLock(DynamicReadLockInner::Guard(value)));
|
Some(DynamicReadLock(DynamicReadLockInner::Guard(value)))
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -1429,13 +1430,13 @@ impl Dynamic {
|
|||||||
Union::Shared(ref cell, ..) => {
|
Union::Shared(ref cell, ..) => {
|
||||||
let guard = crate::func::locked_write(cell);
|
let guard = crate::func::locked_write(cell);
|
||||||
|
|
||||||
if (*guard).type_id() != TypeId::of::<T>()
|
return if (*guard).type_id() != TypeId::of::<T>()
|
||||||
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
|
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
|
||||||
{
|
{
|
||||||
return None;
|
None
|
||||||
} else {
|
} else {
|
||||||
return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(guard)));
|
Some(DynamicWriteLock(DynamicWriteLockInner::Guard(guard)))
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -1791,7 +1792,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 +1814,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()
|
||||||
}
|
}
|
||||||
|
@ -24,15 +24,15 @@ pub struct FnPtr {
|
|||||||
|
|
||||||
impl fmt::Debug for FnPtr {
|
impl fmt::Debug for FnPtr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if !self.is_curried() {
|
if self.is_curried() {
|
||||||
write!(f, "Fn({})", self.fn_name())
|
|
||||||
} else {
|
|
||||||
self.curry
|
self.curry
|
||||||
.iter()
|
.iter()
|
||||||
.fold(f.debug_tuple("Fn").field(&self.name), |f, curry| {
|
.fold(f.debug_tuple("Fn").field(&self.name), |f, curry| {
|
||||||
f.field(curry)
|
f.field(curry)
|
||||||
})
|
})
|
||||||
.finish()
|
.finish()
|
||||||
|
} else {
|
||||||
|
write!(f, "Fn({})", self.fn_name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ impl FnPtr {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ast.as_ref(),
|
_ast.as_ref(),
|
||||||
];
|
];
|
||||||
let lib = if lib.first().map(|m: &&Module| m.is_empty()).unwrap_or(true) {
|
let lib = if lib.first().map_or(true, |m: &&Module| m.is_empty()) {
|
||||||
&lib[0..0]
|
&lib[0..0]
|
||||||
} else {
|
} else {
|
||||||
&lib
|
&lib
|
||||||
|
@ -159,7 +159,7 @@ impl FromIterator<char> for ImmutableString {
|
|||||||
impl<'a> FromIterator<&'a char> for ImmutableString {
|
impl<'a> FromIterator<&'a char> for ImmutableString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
|
||||||
Self(iter.into_iter().cloned().collect::<SmartString>().into())
|
Self(iter.into_iter().copied().collect::<SmartString>().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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())
|
||||||
@ -576,6 +576,7 @@ impl PartialOrd<ImmutableString> for String {
|
|||||||
impl ImmutableString {
|
impl ImmutableString {
|
||||||
/// Create a new [`ImmutableString`].
|
/// Create a new [`ImmutableString`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(SmartString::new_const().into())
|
Self(SmartString::new_const().into())
|
||||||
}
|
}
|
||||||
@ -583,6 +584,7 @@ impl ImmutableString {
|
|||||||
///
|
///
|
||||||
/// If there are other references to the same string, a cloned copy is returned.
|
/// If there are other references to the same string, a cloned copy is returned.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
pub fn into_owned(mut self) -> String {
|
pub fn into_owned(mut self) -> String {
|
||||||
self.make_mut(); // Make sure it is unique reference
|
self.make_mut(); // Make sure it is unique reference
|
||||||
shared_take(self.0).into() // Should succeed
|
shared_take(self.0).into() // Should succeed
|
||||||
@ -620,6 +622,7 @@ impl ImmutableString {
|
|||||||
/// assert!(!s2.ptr_eq(&s3));
|
/// assert!(!s2.ptr_eq(&s3));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn ptr_eq(&self, other: &Self) -> bool {
|
pub fn ptr_eq(&self, other: &Self) -> bool {
|
||||||
Shared::ptr_eq(&self.0, &other.0)
|
Shared::ptr_eq(&self.0, &other.0)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -436,12 +436,11 @@ impl Scope<'_> {
|
|||||||
/// assert_eq!(my_scope.is_constant("y"), None);
|
/// assert_eq!(my_scope.is_constant("y"), None);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
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.
|
||||||
@ -550,6 +549,41 @@ impl Scope<'_> {
|
|||||||
pub fn get(&self, name: &str) -> Option<&Dynamic> {
|
pub fn get(&self, name: &str) -> Option<&Dynamic> {
|
||||||
self.get_index(name).map(|(index, _)| &self.values[index])
|
self.get_index(name).map(|(index, _)| &self.values[index])
|
||||||
}
|
}
|
||||||
|
/// Remove the last entry in the [`Scope`] by the specified name and return its value.
|
||||||
|
///
|
||||||
|
/// If the entry by the specified name is not found, [`None`] is returned.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Scope;
|
||||||
|
///
|
||||||
|
/// let mut my_scope = Scope::new();
|
||||||
|
///
|
||||||
|
/// my_scope.push("x", 123_i64); // first 'x'
|
||||||
|
/// my_scope.push("x", 42_i64); // second 'x', shadows first
|
||||||
|
///
|
||||||
|
/// assert_eq!(my_scope.len(), 2);
|
||||||
|
///
|
||||||
|
/// let value = my_scope.remove::<i64>("x").expect("x should exist");
|
||||||
|
///
|
||||||
|
/// assert_eq!(value, 42);
|
||||||
|
///
|
||||||
|
/// assert_eq!(my_scope.len(), 1);
|
||||||
|
///
|
||||||
|
/// let value = my_scope.get_value::<i64>("x").expect("x should still exist");
|
||||||
|
///
|
||||||
|
/// assert_eq!(value, 123);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn remove<T: Variant + Clone>(&mut self, name: &str) -> Option<T> {
|
||||||
|
self.get_index(name).and_then(|(index, _)| {
|
||||||
|
self.names.remove(index);
|
||||||
|
self.aliases.remove(index);
|
||||||
|
self.values.remove(index).try_cast()
|
||||||
|
})
|
||||||
|
}
|
||||||
/// Get a mutable reference to an entry in the [`Scope`].
|
/// Get a mutable reference to an entry in the [`Scope`].
|
||||||
///
|
///
|
||||||
/// If the entry by the specified name is not found, or if it is read-only,
|
/// If the entry by the specified name is not found, or if it is read-only,
|
||||||
|
Loading…
Reference in New Issue
Block a user