Merge pull request #674 from schungx/master
Clippy and other refactors.
This commit is contained in:
commit
e78c3239f0
@ -4,6 +4,11 @@ Rhai Release Notes
|
|||||||
Version 1.12.0
|
Version 1.12.0
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
Buf fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Integer numbers that are too large to deserialize into `INT` now fall back to `Decimal` or `FLOAT` instead of silently truncating.
|
||||||
|
|
||||||
Net features
|
Net features
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@ -20,6 +25,7 @@ Enhancements
|
|||||||
* The `TypeBuilder` type and `CustomType` trait are no longer marked as volatile.
|
* The `TypeBuilder` type and `CustomType` trait are no longer marked as volatile.
|
||||||
* `FuncArgs` is also implemented for arrays.
|
* `FuncArgs` is also implemented for arrays.
|
||||||
* `Engine::set_XXX` API can now be chained.
|
* `Engine::set_XXX` API can now be chained.
|
||||||
|
* `EvalContext::scope_mut` now returns `&mut Scope` instead of `&mut &mut Scope`.
|
||||||
|
|
||||||
|
|
||||||
Version 1.11.0
|
Version 1.11.0
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
//! This file is automatically recreated during build time by `build.rs` from `build.template`.
|
//! This file is automatically recreated during build time by `build.rs` from `build.template`.
|
||||||
|
|
||||||
pub(crate) const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}};
|
pub const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}};
|
||||||
|
@ -5,6 +5,8 @@ edition = "2018"
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
authors = ["jhwgh1968", "Stephen Chung"]
|
authors = ["jhwgh1968", "Stephen Chung"]
|
||||||
description = "Procedural macros support package for Rhai, a scripting language and engine for Rust"
|
description = "Procedural macros support package for Rhai, a scripting language and engine for Rust"
|
||||||
|
keywords = ["rhai", "scripting", "scripting-engine", "scripting-language", "embedded", "plugin", "macros", "code-generation"]
|
||||||
|
categories = ["no-std", "embedded", "wasm", "parser-implementations"]
|
||||||
homepage = "https://rhai.rs/book/plugins/index.html"
|
homepage = "https://rhai.rs/book/plugins/index.html"
|
||||||
repository = "https://github.com/rhaiscript/rhai"
|
repository = "https://github.com/rhaiscript/rhai"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
@ -313,7 +313,7 @@ impl Parse for ExportedFn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let skip_slots = if pass_context { 1 } else { 0 };
|
let skip_slots = usize::from(pass_context);
|
||||||
|
|
||||||
// Determine whether function generates a special calling convention for a mutable receiver.
|
// Determine whether function generates a special calling convention for a mutable receiver.
|
||||||
let mut_receiver = match fn_all.sig.inputs.iter().nth(skip_slots) {
|
let mut_receiver = match fn_all.sig.inputs.iter().nth(skip_slots) {
|
||||||
@ -485,12 +485,12 @@ impl ExportedFn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg_list(&self) -> impl Iterator<Item = &syn::FnArg> {
|
pub fn arg_list(&self) -> impl Iterator<Item = &syn::FnArg> {
|
||||||
let skip = if self.pass_context { 1 } else { 0 };
|
let skip = usize::from(self.pass_context);
|
||||||
self.signature.inputs.iter().skip(skip)
|
self.signature.inputs.iter().skip(skip)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg_count(&self) -> usize {
|
pub fn arg_count(&self) -> usize {
|
||||||
let skip = if self.pass_context { 1 } else { 0 };
|
let skip = usize::from(self.pass_context);
|
||||||
self.signature.inputs.len() - skip
|
self.signature.inputs.len() - skip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ pub fn main() {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
use rhai::{CallFnOptions, Dynamic, Engine, ImmutableString, Map, Scope, AST};
|
use rhai::{CallFnOptions, Dynamic, Engine, Map, Scope, AST};
|
||||||
use std::io::{stdin, stdout, Write};
|
use std::io::{stdin, stdout, Write};
|
||||||
|
|
||||||
const SCRIPT_FILE: &str = "event_handler_js/script.rhai";
|
const SCRIPT_FILE: &str = "event_handler_js/script.rhai";
|
||||||
|
@ -18,6 +18,7 @@ use std::{
|
|||||||
/// Options for calling a script-defined function via [`Engine::call_fn_with_options`].
|
/// Options for calling a script-defined function via [`Engine::call_fn_with_options`].
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
#[must_use]
|
||||||
pub struct CallFnOptions<'t> {
|
pub struct CallFnOptions<'t> {
|
||||||
/// A value for binding to the `this` pointer (if any).
|
/// A value for binding to the `this` pointer (if any).
|
||||||
pub this_ptr: Option<&'t mut Dynamic>,
|
pub this_ptr: Option<&'t mut Dynamic>,
|
||||||
@ -120,7 +121,7 @@ impl Engine {
|
|||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
args: impl FuncArgs,
|
args: impl FuncArgs,
|
||||||
) -> RhaiResultOf<T> {
|
) -> RhaiResultOf<T> {
|
||||||
self.call_fn_with_options(Default::default(), scope, ast, name, args)
|
self.call_fn_with_options(CallFnOptions::default(), scope, ast, name, args)
|
||||||
}
|
}
|
||||||
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
|
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
|
||||||
///
|
///
|
||||||
@ -255,7 +256,11 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
crate::func::ensure_no_data_race(name, args, false).map(|_| Dynamic::UNIT)?;
|
crate::func::ensure_no_data_race(name, args, false).map(|_| Dynamic::UNIT)?;
|
||||||
|
|
||||||
if let Some(fn_def) = ast.shared_lib().get_script_fn(name, args.len()) {
|
ast.shared_lib()
|
||||||
|
.get_script_fn(name, args.len())
|
||||||
|
.map_or_else(
|
||||||
|
|| Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into()),
|
||||||
|
|fn_def| {
|
||||||
self.call_script_fn(
|
self.call_script_fn(
|
||||||
global,
|
global,
|
||||||
caches,
|
caches,
|
||||||
@ -266,14 +271,13 @@ impl Engine {
|
|||||||
rewind_scope,
|
rewind_scope,
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
} else {
|
},
|
||||||
Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into())
|
)
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
if self.debugger.is_some() {
|
if self.debugger.is_some() {
|
||||||
global.debugger.status = crate::eval::DebuggerStatus::Terminate;
|
global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate;
|
||||||
let node = &crate::ast::Stmt::Noop(Position::NONE);
|
let node = &crate::ast::Stmt::Noop(Position::NONE);
|
||||||
self.run_debugger(global, caches, scope, this_ptr, node)?;
|
self.run_debugger(global, caches, scope, this_ptr, node)?;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Module that defines the public compilation API of [`Engine`].
|
//! Module that defines the public compilation API of [`Engine`].
|
||||||
|
|
||||||
|
use crate::func::native::locked_write;
|
||||||
use crate::parser::{ParseResult, ParseState};
|
use crate::parser::{ParseResult, ParseState};
|
||||||
use crate::{Engine, OptimizationLevel, Scope, AST};
|
use crate::{Engine, OptimizationLevel, Scope, AST};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -221,7 +222,8 @@ impl Engine {
|
|||||||
scripts.as_ref(),
|
scripts.as_ref(),
|
||||||
self.token_mapper.as_ref().map(<_>::as_ref),
|
self.token_mapper.as_ref().map(<_>::as_ref),
|
||||||
);
|
);
|
||||||
let mut state = ParseState::new(self, scope, Default::default(), tokenizer_control);
|
let interned_strings = &mut *locked_write(&self.interned_strings);
|
||||||
|
let mut state = ParseState::new(scope, interned_strings, tokenizer_control);
|
||||||
let mut _ast = self.parse(&mut stream.peekable(), &mut state, optimization_level)?;
|
let mut _ast = self.parse(&mut stream.peekable(), &mut state, optimization_level)?;
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
_ast.set_doc(state.tokenizer_control.borrow().global_comments.join("\n"));
|
_ast.set_doc(state.tokenizer_control.borrow().global_comments.join("\n"));
|
||||||
@ -294,7 +296,8 @@ impl Engine {
|
|||||||
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
|
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
|
||||||
|
|
||||||
let mut peekable = stream.peekable();
|
let mut peekable = stream.peekable();
|
||||||
let mut state = ParseState::new(self, scope, Default::default(), tokenizer_control);
|
let interned_strings = &mut *locked_write(&self.interned_strings);
|
||||||
|
let mut state = ParseState::new(scope, interned_strings, tokenizer_control);
|
||||||
self.parse_global_expr(&mut peekable, &mut state, |_| {}, self.optimization_level)
|
self.parse_global_expr(&mut peekable, &mut state, |_| {}, self.optimization_level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,7 @@ impl Engine {
|
|||||||
scope_may_be_changed: bool,
|
scope_may_be_changed: bool,
|
||||||
func: impl Fn(&mut EvalContext, &[Expression]) -> RhaiResult + SendSync + 'static,
|
func: impl Fn(&mut EvalContext, &[Expression]) -> RhaiResult + SendSync + 'static,
|
||||||
) -> ParseResult<&mut Self> {
|
) -> ParseResult<&mut Self> {
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use markers::*;
|
use markers::*;
|
||||||
|
|
||||||
let mut segments = StaticVec::<ImmutableString>::new();
|
let mut segments = StaticVec::<ImmutableString>::new();
|
||||||
@ -256,19 +257,29 @@ impl Engine {
|
|||||||
// Standard or reserved keyword/symbol not in first position
|
// Standard or reserved keyword/symbol not in first position
|
||||||
_ if !segments.is_empty() && token.is_some() => {
|
_ if !segments.is_empty() && token.is_some() => {
|
||||||
// Make it a custom keyword/symbol if it is disabled or reserved
|
// Make it a custom keyword/symbol if it is disabled or reserved
|
||||||
if ((!self.disabled_symbols.is_empty() && self.disabled_symbols.contains(s))
|
if (self
|
||||||
|
.disabled_symbols
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains(s))
|
||||||
|| token.map_or(false, |v| v.is_reserved()))
|
|| token.map_or(false, |v| v.is_reserved()))
|
||||||
&& (self.custom_keywords.is_empty()
|
&& !self
|
||||||
|| !self.custom_keywords.contains_key(s))
|
.custom_keywords
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains_key(s))
|
||||||
{
|
{
|
||||||
self.custom_keywords.insert(s.into(), None);
|
self.custom_keywords
|
||||||
|
.get_or_insert_with(Default::default)
|
||||||
|
.insert(s.into(), None);
|
||||||
}
|
}
|
||||||
s.into()
|
s.into()
|
||||||
}
|
}
|
||||||
// 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, Token::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
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains(s)) =>
|
||||||
{
|
{
|
||||||
return Err(LexError::ImproperSymbol(
|
return Err(LexError::ImproperSymbol(
|
||||||
s.to_string(),
|
s.to_string(),
|
||||||
@ -282,12 +293,19 @@ impl Engine {
|
|||||||
// Identifier in first position
|
// Identifier in first position
|
||||||
_ if segments.is_empty() && is_valid_identifier(s) => {
|
_ if segments.is_empty() && is_valid_identifier(s) => {
|
||||||
// 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
|
||||||
|| token.map_or(false, |v| v.is_reserved())
|
.disabled_symbols
|
||||||
&& self.custom_keywords.is_empty()
|
.as_ref()
|
||||||
|| !self.custom_keywords.contains_key(s)
|
.map_or(false, |m| m.contains(s))
|
||||||
|
|| (token.map_or(false, |v| v.is_reserved())
|
||||||
|
&& !self
|
||||||
|
.custom_keywords
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains_key(s)))
|
||||||
{
|
{
|
||||||
self.custom_keywords.insert(s.into(), None);
|
self.custom_keywords
|
||||||
|
.get_or_insert_with(Default::default)
|
||||||
|
.insert(s.into(), None);
|
||||||
}
|
}
|
||||||
s.into()
|
s.into()
|
||||||
}
|
}
|
||||||
@ -372,7 +390,9 @@ impl Engine {
|
|||||||
scope_may_be_changed: bool,
|
scope_may_be_changed: bool,
|
||||||
func: impl Fn(&mut EvalContext, &[Expression], &Dynamic) -> RhaiResult + SendSync + 'static,
|
func: impl Fn(&mut EvalContext, &[Expression], &Dynamic) -> RhaiResult + SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.custom_syntax.insert(
|
self.custom_syntax
|
||||||
|
.get_or_insert_with(Default::default)
|
||||||
|
.insert(
|
||||||
key.into(),
|
key.into(),
|
||||||
CustomSyntax {
|
CustomSyntax {
|
||||||
parse: Box::new(parse),
|
parse: Box::new(parse),
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#![cfg(feature = "internals")]
|
#![cfg(feature = "internals")]
|
||||||
#![cfg(feature = "metadata")]
|
#![cfg(feature = "metadata")]
|
||||||
|
|
||||||
use crate::module::FuncInfo;
|
use crate::module::{FuncInfo, ModuleFlags};
|
||||||
use crate::tokenizer::{is_valid_function_name, Token};
|
use crate::tokenizer::{is_valid_function_name, Token};
|
||||||
use crate::{Engine, FnAccess, FnPtr, Module, Scope, INT};
|
use crate::{Engine, FnAccess, FnPtr, Module, Scope, INT};
|
||||||
|
|
||||||
@ -77,7 +77,6 @@ pub struct DefinitionsConfig {
|
|||||||
|
|
||||||
impl Default for DefinitionsConfig {
|
impl Default for DefinitionsConfig {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
write_headers: false,
|
write_headers: false,
|
||||||
@ -105,13 +104,13 @@ impl Definitions<'_> {
|
|||||||
/// Headers are always present in content that is expected to be written to a file
|
/// Headers are always present in content that is expected to be written to a file
|
||||||
/// (i.e. `write_to*` and `*_file` methods).
|
/// (i.e. `write_to*` and `*_file` methods).
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_headers(mut self, headers: bool) -> Self {
|
pub const fn with_headers(mut self, headers: bool) -> Self {
|
||||||
self.config.write_headers = headers;
|
self.config.write_headers = headers;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// Include standard packages when writing definition files.
|
/// Include standard packages when writing definition files.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn include_standard_packages(mut self, include_standard_packages: bool) -> Self {
|
pub const fn include_standard_packages(mut self, include_standard_packages: bool) -> Self {
|
||||||
self.config.include_standard_packages = include_standard_packages;
|
self.config.include_standard_packages = include_standard_packages;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -129,7 +128,6 @@ impl Definitions<'_> {
|
|||||||
}
|
}
|
||||||
/// Get the configuration.
|
/// Get the configuration.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
pub(crate) const fn config(&self) -> &DefinitionsConfig {
|
pub(crate) const fn config(&self) -> &DefinitionsConfig {
|
||||||
&self.config
|
&self.config
|
||||||
}
|
}
|
||||||
@ -177,19 +175,19 @@ impl Definitions<'_> {
|
|||||||
let mut def_file = String::from("module static;\n\n");
|
let mut def_file = String::from("module static;\n\n");
|
||||||
|
|
||||||
if config.include_standard_packages {
|
if config.include_standard_packages {
|
||||||
def_file += &self.builtin_functions_operators_impl(&config);
|
def_file += &Self::builtin_functions_operators_impl(config);
|
||||||
def_file += "\n";
|
def_file += "\n";
|
||||||
def_file += &self.builtin_functions_impl(&config);
|
def_file += &Self::builtin_functions_impl(config);
|
||||||
def_file += "\n";
|
def_file += "\n";
|
||||||
}
|
}
|
||||||
def_file += &self.static_module_impl(&config);
|
def_file += &self.static_module_impl(config);
|
||||||
def_file += "\n";
|
def_file += "\n";
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
for (module_name, module_def) in self.modules_impl(&config) {
|
for (module_name, module_def) in self.modules_impl(config) {
|
||||||
write!(
|
write!(
|
||||||
&mut def_file,
|
&mut def_file,
|
||||||
"\nmodule {module_name} {{\n{module_def}\n}}\n"
|
"\nmodule {module_name} {{\n{module_def}\n}}\n"
|
||||||
@ -199,7 +197,7 @@ impl Definitions<'_> {
|
|||||||
def_file += "\n";
|
def_file += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
def_file += &self.scope_items_impl(&config);
|
def_file += &self.scope_items_impl(config);
|
||||||
|
|
||||||
def_file += "\n";
|
def_file += "\n";
|
||||||
|
|
||||||
@ -220,11 +218,11 @@ impl Definitions<'_> {
|
|||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
"__builtin__.d.rhai".to_string(),
|
"__builtin__.d.rhai".to_string(),
|
||||||
self.builtin_functions_impl(&config),
|
Self::builtin_functions_impl(config),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"__builtin-operators__.d.rhai".to_string(),
|
"__builtin-operators__.d.rhai".to_string(),
|
||||||
self.builtin_functions_operators_impl(&config),
|
Self::builtin_functions_operators_impl(config),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
@ -233,18 +231,18 @@ impl Definitions<'_> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(std::iter::once((
|
.chain(std::iter::once((
|
||||||
"__static__.d.rhai".to_string(),
|
"__static__.d.rhai".to_string(),
|
||||||
self.static_module_impl(&config),
|
self.static_module_impl(config),
|
||||||
)))
|
)))
|
||||||
.chain(self.scope.iter().map(move |_| {
|
.chain(self.scope.iter().map(move |_| {
|
||||||
(
|
(
|
||||||
"__scope__.d.rhai".to_string(),
|
"__scope__.d.rhai".to_string(),
|
||||||
self.scope_items_impl(&config),
|
self.scope_items_impl(config),
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
.chain(
|
.chain(
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
self.modules_impl(&config)
|
self.modules_impl(config)
|
||||||
.map(|(name, def)| (format!("{name}.d.rhai"), def))
|
.map(|(name, def)| (format!("{name}.d.rhai"), def))
|
||||||
},
|
},
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
@ -258,12 +256,12 @@ impl Definitions<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn builtin_functions(&self) -> String {
|
pub fn builtin_functions(&self) -> String {
|
||||||
self.builtin_functions_impl(&self.config)
|
Self::builtin_functions_impl(self.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return definitions for all builtin functions.
|
/// Return definitions for all builtin functions.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn builtin_functions_impl(&self, config: &DefinitionsConfig) -> String {
|
fn builtin_functions_impl(config: DefinitionsConfig) -> String {
|
||||||
let def = include_str!("builtin-functions.d.rhai");
|
let def = include_str!("builtin-functions.d.rhai");
|
||||||
|
|
||||||
if config.write_headers {
|
if config.write_headers {
|
||||||
@ -277,12 +275,12 @@ impl Definitions<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn builtin_functions_operators(&self) -> String {
|
pub fn builtin_functions_operators(&self) -> String {
|
||||||
self.builtin_functions_operators_impl(&self.config)
|
Self::builtin_functions_operators_impl(self.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return definitions for all builtin operators.
|
/// Return definitions for all builtin operators.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn builtin_functions_operators_impl(&self, config: &DefinitionsConfig) -> String {
|
fn builtin_functions_operators_impl(config: DefinitionsConfig) -> String {
|
||||||
let def = include_str!("builtin-operators.d.rhai");
|
let def = include_str!("builtin-operators.d.rhai");
|
||||||
|
|
||||||
if config.write_headers {
|
if config.write_headers {
|
||||||
@ -296,22 +294,28 @@ impl Definitions<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn static_module(&self) -> String {
|
pub fn static_module(&self) -> String {
|
||||||
self.static_module_impl(&self.config)
|
self.static_module_impl(self.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return definitions for all globally available functions and constants.
|
/// Return definitions for all globally available functions and constants.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn static_module_impl(&self, config: &DefinitionsConfig) -> String {
|
fn static_module_impl(&self, config: DefinitionsConfig) -> String {
|
||||||
let mut s = if config.write_headers {
|
let mut s = if config.write_headers {
|
||||||
String::from("module static;\n\n")
|
String::from("module static;\n\n")
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let exclude_flags = if self.config.include_standard_packages {
|
||||||
|
ModuleFlags::empty()
|
||||||
|
} else {
|
||||||
|
ModuleFlags::STANDARD_LIB
|
||||||
|
};
|
||||||
|
|
||||||
self.engine
|
self.engine
|
||||||
.global_modules
|
.global_modules
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|m| self.config.include_standard_packages || !m.standard)
|
.filter(|m| !m.flags.contains(exclude_flags))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, m)| {
|
.for_each(|(i, m)| {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
@ -327,12 +331,12 @@ impl Definitions<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn scope_items(&self) -> String {
|
pub fn scope_items(&self) -> String {
|
||||||
self.scope_items_impl(&self.config)
|
self.scope_items_impl(self.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return definitions for all items inside the [`Scope`], if any.
|
/// Return definitions for all items inside the [`Scope`], if any.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn scope_items_impl(&self, config: &DefinitionsConfig) -> String {
|
fn scope_items_impl(&self, config: DefinitionsConfig) -> String {
|
||||||
let mut s = if config.write_headers {
|
let mut s = if config.write_headers {
|
||||||
String::from("module static;\n\n")
|
String::from("module static;\n\n")
|
||||||
} else {
|
} else {
|
||||||
@ -352,19 +356,20 @@ impl Definitions<'_> {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn modules(&self) -> impl Iterator<Item = (String, String)> + '_ {
|
pub fn modules(&self) -> impl Iterator<Item = (String, String)> + '_ {
|
||||||
self.modules_impl(&self.config)
|
self.modules_impl(self.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a (module name, definitions) pair for each registered static [module][Module].
|
/// Return a (module name, definitions) pair for each registered static [module][Module].
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
fn modules_impl(
|
fn modules_impl(
|
||||||
&self,
|
&self,
|
||||||
config: &DefinitionsConfig,
|
config: DefinitionsConfig,
|
||||||
) -> impl Iterator<Item = (String, String)> + '_ {
|
) -> impl Iterator<Item = (String, String)> + '_ {
|
||||||
let mut m = self
|
let mut m = self
|
||||||
.engine
|
.engine
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(|m| m.iter())
|
||||||
.map(move |(name, module)| {
|
.map(move |(name, module)| {
|
||||||
(
|
(
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
@ -425,10 +430,11 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut func_infos = self.iter_fn().collect::<Vec<_>>();
|
let mut func_infos = self.iter_fn().collect::<Vec<_>>();
|
||||||
func_infos.sort_by(|a, b| match a.name.cmp(&b.name) {
|
func_infos.sort_by(|a, b| match a.metadata.name.cmp(&b.metadata.name) {
|
||||||
Ordering::Equal => match a.num_params.cmp(&b.num_params) {
|
Ordering::Equal => match a.metadata.num_params.cmp(&b.metadata.num_params) {
|
||||||
Ordering::Equal => (a.params_info.join("") + a.return_type.as_str())
|
Ordering::Equal => (a.metadata.params_info.join("")
|
||||||
.cmp(&(b.params_info.join("") + b.return_type.as_str())),
|
+ a.metadata.return_type.as_str())
|
||||||
|
.cmp(&(b.metadata.params_info.join("") + b.metadata.return_type.as_str())),
|
||||||
o => o,
|
o => o,
|
||||||
},
|
},
|
||||||
o => o,
|
o => o,
|
||||||
@ -440,13 +446,17 @@ impl Module {
|
|||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
if f.access != FnAccess::Private {
|
if f.metadata.access != FnAccess::Private {
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
let operator =
|
||||||
let operator = def.engine.custom_keywords.contains_key(f.name.as_str())
|
!f.metadata.name.contains('$') && !is_valid_function_name(&f.metadata.name);
|
||||||
|| (!f.name.contains('$') && !is_valid_function_name(f.name.as_str()));
|
|
||||||
|
|
||||||
#[cfg(feature = "no_custom_syntax")]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
let operator = !f.name.contains('$') && !is_valid_function_name(&f.name);
|
let operator = operator
|
||||||
|
|| def
|
||||||
|
.engine
|
||||||
|
.custom_keywords
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains_key(f.metadata.name.as_str()));
|
||||||
|
|
||||||
f.write_definition(writer, def, operator)?;
|
f.write_definition(writer, def, operator)?;
|
||||||
}
|
}
|
||||||
@ -464,7 +474,7 @@ impl FuncInfo {
|
|||||||
def: &Definitions,
|
def: &Definitions,
|
||||||
operator: bool,
|
operator: bool,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
for comment in &*self.comments {
|
for comment in &*self.metadata.comments {
|
||||||
writeln!(writer, "{comment}")?;
|
writeln!(writer, "{comment}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,22 +484,26 @@ impl FuncInfo {
|
|||||||
writer.write_str("fn ")?;
|
writer.write_str("fn ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = self.name.strip_prefix("get$") {
|
if let Some(name) = self.metadata.name.strip_prefix("get$") {
|
||||||
write!(writer, "get {name}(")?;
|
write!(writer, "get {name}(")?;
|
||||||
} else if let Some(name) = self.name.strip_prefix("set$") {
|
} else if let Some(name) = self.metadata.name.strip_prefix("set$") {
|
||||||
write!(writer, "set {name}(")?;
|
write!(writer, "set {name}(")?;
|
||||||
} else {
|
} else {
|
||||||
write!(writer, "{}(", self.name)?;
|
write!(writer, "{}(", self.metadata.name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for i in 0..self.num_params {
|
for i in 0..self.metadata.num_params {
|
||||||
if !first {
|
if !first {
|
||||||
writer.write_str(", ")?;
|
writer.write_str(", ")?;
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
let (param_name, param_type) = self.params_info.get(i).map_or(("_", "?".into()), |s| {
|
let (param_name, param_type) =
|
||||||
|
self.metadata
|
||||||
|
.params_info
|
||||||
|
.get(i)
|
||||||
|
.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(),
|
||||||
@ -508,7 +522,7 @@ impl FuncInfo {
|
|||||||
write!(
|
write!(
|
||||||
writer,
|
writer,
|
||||||
") -> {};",
|
") -> {};",
|
||||||
def_type_name(&self.return_type, def.engine)
|
def_type_name(&self.metadata.return_type, def.engine)
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
use crate::func::RegisterNativeFunction;
|
use crate::func::RegisterNativeFunction;
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, NativeCallContext,
|
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, NativeCallContext,
|
||||||
Position, RhaiResult, RhaiResultOf, Scope, SharedModule, AST,
|
Position, RhaiResult, RhaiResultOf, Scope, SharedModule, TypeBuilder, AST,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -534,7 +534,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
impl<'a, T: Variant + Clone> crate::TypeBuilder<'a, T> {
|
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
||||||
/// Register a custom fallible function.
|
/// Register a custom fallible function.
|
||||||
///
|
///
|
||||||
/// # Deprecated
|
/// # Deprecated
|
||||||
@ -642,3 +642,19 @@ impl<'a, T: Variant + Clone> crate::TypeBuilder<'a, T> {
|
|||||||
self.with_indexer_set(set_fn)
|
self.with_indexer_set(set_fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
/// Create a new [`Module`] with a pre-sized capacity for functions.
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
///
|
||||||
|
/// This method is deprecated. Use `new` instead.
|
||||||
|
///
|
||||||
|
/// This method will be removed in the next major version.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[deprecated(since = "1.12.0", note = "use `new` instead")]
|
||||||
|
pub fn with_capacity(_capacity: usize) -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Module that defines the public evaluation API of [`Engine`].
|
//! Module that defines the public evaluation API of [`Engine`].
|
||||||
|
|
||||||
use crate::eval::{Caches, GlobalRuntimeState};
|
use crate::eval::{Caches, GlobalRuntimeState};
|
||||||
|
use crate::func::native::locked_write;
|
||||||
use crate::parser::ParseState;
|
use crate::parser::ParseState;
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -69,7 +70,7 @@ impl Engine {
|
|||||||
) -> RhaiResultOf<T> {
|
) -> RhaiResultOf<T> {
|
||||||
let ast = self.compile_with_scope_and_optimization_level(
|
let ast = self.compile_with_scope_and_optimization_level(
|
||||||
scope,
|
scope,
|
||||||
&[script],
|
[script],
|
||||||
self.optimization_level,
|
self.optimization_level,
|
||||||
)?;
|
)?;
|
||||||
self.eval_ast_with_scope(scope, &ast)
|
self.eval_ast_with_scope(scope, &ast)
|
||||||
@ -117,12 +118,16 @@ impl Engine {
|
|||||||
script: &str,
|
script: &str,
|
||||||
) -> RhaiResultOf<T> {
|
) -> RhaiResultOf<T> {
|
||||||
let scripts = [script];
|
let scripts = [script];
|
||||||
|
let ast = {
|
||||||
|
let interned_strings = &mut *locked_write(&self.interned_strings);
|
||||||
|
|
||||||
let (stream, tokenizer_control) =
|
let (stream, tokenizer_control) =
|
||||||
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
|
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
|
||||||
let mut state = ParseState::new(self, scope, Default::default(), tokenizer_control);
|
|
||||||
|
let mut state = ParseState::new(scope, interned_strings, tokenizer_control);
|
||||||
|
|
||||||
// No need to optimize a lone expression
|
// No need to optimize a lone expression
|
||||||
let ast = self.parse_global_expr(
|
self.parse_global_expr(
|
||||||
&mut stream.peekable(),
|
&mut stream.peekable(),
|
||||||
&mut state,
|
&mut state,
|
||||||
|_| {},
|
|_| {},
|
||||||
@ -130,7 +135,8 @@ impl Engine {
|
|||||||
OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
OptimizationLevel::default(),
|
OptimizationLevel::default(),
|
||||||
)?;
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
self.eval_ast_with_scope(scope, &ast)
|
self.eval_ast_with_scope(scope, &ast)
|
||||||
}
|
}
|
||||||
@ -238,7 +244,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
if self.debugger.is_some() {
|
if self.debugger.is_some() {
|
||||||
global.debugger.status = crate::eval::DebuggerStatus::Terminate;
|
global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate;
|
||||||
let mut this = Dynamic::NULL;
|
let mut this = Dynamic::NULL;
|
||||||
let node = &crate::ast::Stmt::Noop(Position::NONE);
|
let node = &crate::ast::Stmt::Noop(Position::NONE);
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ impl Engine {
|
|||||||
+ SendSync
|
+ SendSync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.debugger = Some((Box::new(init), Box::new(callback)));
|
self.debugger = Some(Box::new((Box::new(init), Box::new(callback))));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
//! Module that defines JSON manipulation functions for [`Engine`].
|
//! Module that defines JSON manipulation functions for [`Engine`].
|
||||||
#![cfg(not(feature = "no_object"))]
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use crate::parser::ParseState;
|
use crate::func::native::locked_write;
|
||||||
|
use crate::parser::{ParseSettingFlags, ParseState};
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope};
|
use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -116,18 +117,21 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let ast = {
|
||||||
let scope = Scope::new();
|
let scope = Scope::new();
|
||||||
let mut state = ParseState::new(self, &scope, Default::default(), tokenizer_control);
|
let interned_strings = &mut *locked_write(&self.interned_strings);
|
||||||
|
let mut state = ParseState::new(&scope, interned_strings, tokenizer_control);
|
||||||
|
|
||||||
let ast = self.parse_global_expr(
|
self.parse_global_expr(
|
||||||
&mut stream.peekable(),
|
&mut stream.peekable(),
|
||||||
&mut state,
|
&mut state,
|
||||||
|s| s.allow_unquoted_map_properties = false,
|
|s| s.flags |= ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES,
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
OptimizationLevel::default(),
|
OptimizationLevel::default(),
|
||||||
)?;
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
self.eval_ast(&ast)
|
self.eval_ast(&ast)
|
||||||
}
|
}
|
||||||
@ -165,7 +169,7 @@ pub fn format_map_as_json(map: &Map) -> String {
|
|||||||
result.push(':');
|
result.push(':');
|
||||||
|
|
||||||
if let Some(val) = value.read_lock::<Map>() {
|
if let Some(val) = value.read_lock::<Map>() {
|
||||||
result.push_str(&format_map_as_json(&*val));
|
result.push_str(&format_map_as_json(&val));
|
||||||
} else if value.is_unit() {
|
} else if value.is_unit() {
|
||||||
result.push_str("null");
|
result.push_str("null");
|
||||||
} else {
|
} else {
|
||||||
|
@ -107,7 +107,9 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn disable_symbol(&mut self, symbol: impl Into<Identifier>) -> &mut Self {
|
pub fn disable_symbol(&mut self, symbol: impl Into<Identifier>) -> &mut Self {
|
||||||
self.disabled_symbols.insert(symbol.into());
|
self.disabled_symbols
|
||||||
|
.get_or_insert_with(Default::default)
|
||||||
|
.insert(symbol.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,24 +165,30 @@ impl Engine {
|
|||||||
// Active standard keywords cannot be made custom
|
// Active standard keywords cannot be made custom
|
||||||
// Disabled keywords are OK
|
// Disabled keywords are OK
|
||||||
Some(token) if token.is_standard_keyword() => {
|
Some(token) if token.is_standard_keyword() => {
|
||||||
if self.disabled_symbols.is_empty()
|
if !self
|
||||||
|| !self.disabled_symbols.contains(&*token.syntax())
|
.disabled_symbols
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains(token.literal_syntax()))
|
||||||
{
|
{
|
||||||
return Err(format!("'{keyword}' is a reserved keyword"));
|
return Err(format!("'{keyword}' is a reserved keyword"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Active standard symbols cannot be made custom
|
// Active standard symbols cannot be made custom
|
||||||
Some(token) if token.is_standard_symbol() => {
|
Some(token) if token.is_standard_symbol() => {
|
||||||
if self.disabled_symbols.is_empty()
|
if !self
|
||||||
|| !self.disabled_symbols.contains(&*token.syntax())
|
.disabled_symbols
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains(token.literal_syntax()))
|
||||||
{
|
{
|
||||||
return Err(format!("'{keyword}' is a reserved operator"));
|
return Err(format!("'{keyword}' is a reserved operator"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Active standard symbols cannot be made custom
|
// Active standard symbols cannot be made custom
|
||||||
Some(token)
|
Some(token)
|
||||||
if self.disabled_symbols.is_empty()
|
if !self
|
||||||
|| !self.disabled_symbols.contains(&*token.syntax()) =>
|
.disabled_symbols
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.contains(token.literal_syntax())) =>
|
||||||
{
|
{
|
||||||
return Err(format!("'{keyword}' is a reserved symbol"))
|
return Err(format!("'{keyword}' is a reserved symbol"))
|
||||||
}
|
}
|
||||||
@ -190,6 +198,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Add to custom keywords
|
// Add to custom keywords
|
||||||
self.custom_keywords
|
self.custom_keywords
|
||||||
|
.get_or_insert_with(Default::default)
|
||||||
.insert(keyword.into(), Some(precedence));
|
.insert(keyword.into(), Some(precedence));
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@ -198,7 +207,7 @@ impl Engine {
|
|||||||
/// Get the default value of the custom state for each evaluation run.
|
/// Get the default value of the custom state for each evaluation run.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn default_tag(&self) -> &Dynamic {
|
pub const fn default_tag(&self) -> &Dynamic {
|
||||||
&self.def_tag
|
&self.def_tag
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the default value of the custom state for each evaluation run.
|
/// Get a mutable reference to the default value of the custom state for each evaluation run.
|
||||||
|
@ -683,13 +683,14 @@ impl Engine {
|
|||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
module: SharedModule,
|
module: SharedModule,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
fn register_static_module_raw(
|
fn register_static_module_raw(
|
||||||
root: &mut std::collections::BTreeMap<Identifier, SharedModule>,
|
root: &mut BTreeMap<Identifier, SharedModule>,
|
||||||
name: &str,
|
name: &str,
|
||||||
module: SharedModule,
|
module: SharedModule,
|
||||||
) {
|
) {
|
||||||
let separator = crate::tokenizer::Token::DoubleColon.syntax();
|
let separator = crate::tokenizer::Token::DoubleColon.literal_syntax();
|
||||||
let separator = separator.as_ref();
|
|
||||||
|
|
||||||
if name.contains(separator) {
|
if name.contains(separator) {
|
||||||
let mut iter = name.splitn(2, separator);
|
let mut iter = name.splitn(2, separator);
|
||||||
@ -718,7 +719,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module);
|
register_static_module_raw(
|
||||||
|
self.global_sub_modules.get_or_insert_with(Default::default),
|
||||||
|
name.as_ref(),
|
||||||
|
module,
|
||||||
|
);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// _(metadata)_ Generate a list of all registered functions.
|
/// _(metadata)_ Generate a list of all registered functions.
|
||||||
@ -738,15 +743,21 @@ impl Engine {
|
|||||||
signatures.extend(self.global_namespace().gen_fn_signatures());
|
signatures.extend(self.global_namespace().gen_fn_signatures());
|
||||||
|
|
||||||
#[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.iter().flat_map(|m| m.iter()) {
|
||||||
signatures.extend(m.gen_fn_signatures().map(|f| format!("{name}::{f}")));
|
signatures.extend(m.gen_fn_signatures().map(|f| format!("{name}::{f}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let exclude_flags = if include_packages {
|
||||||
|
crate::module::ModuleFlags::INTERNAL
|
||||||
|
} else {
|
||||||
|
crate::module::ModuleFlags::INTERNAL | crate::module::ModuleFlags::STANDARD_LIB
|
||||||
|
};
|
||||||
|
|
||||||
signatures.extend(
|
signatures.extend(
|
||||||
self.global_modules
|
self.global_modules
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.filter(|m| !m.internal && (include_packages || !m.standard))
|
.filter(|m| !m.flags.contains(exclude_flags))
|
||||||
.flat_map(|m| m.gen_fn_signatures()),
|
.flat_map(|m| m.gen_fn_signatures()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Module that defines the public evaluation API of [`Engine`].
|
//! Module that defines the public evaluation API of [`Engine`].
|
||||||
|
|
||||||
use crate::eval::{Caches, GlobalRuntimeState};
|
use crate::eval::{Caches, GlobalRuntimeState};
|
||||||
|
use crate::func::native::locked_write;
|
||||||
use crate::parser::ParseState;
|
use crate::parser::ParseState;
|
||||||
use crate::{Engine, RhaiResultOf, Scope, AST};
|
use crate::{Engine, RhaiResultOf, Scope, AST};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -56,10 +57,16 @@ impl Engine {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn run_with_scope(&self, scope: &mut Scope, script: &str) -> RhaiResultOf<()> {
|
pub fn run_with_scope(&self, scope: &mut Scope, script: &str) -> RhaiResultOf<()> {
|
||||||
let scripts = [script];
|
let scripts = [script];
|
||||||
|
let ast = {
|
||||||
|
let interned_strings = &mut *locked_write(&self.interned_strings);
|
||||||
|
|
||||||
let (stream, tokenizer_control) =
|
let (stream, tokenizer_control) =
|
||||||
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
|
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
|
||||||
let mut state = ParseState::new(self, scope, Default::default(), tokenizer_control);
|
|
||||||
let ast = self.parse(&mut stream.peekable(), &mut state, self.optimization_level)?;
|
let mut state = ParseState::new(scope, interned_strings, tokenizer_control);
|
||||||
|
|
||||||
|
self.parse(&mut stream.peekable(), &mut state, self.optimization_level)?
|
||||||
|
};
|
||||||
self.run_ast_with_scope(scope, &ast)
|
self.run_ast_with_scope(scope, &ast)
|
||||||
}
|
}
|
||||||
/// Evaluate an [`AST`].
|
/// Evaluate an [`AST`].
|
||||||
@ -130,7 +137,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
if self.debugger.is_some() {
|
if self.debugger.is_some() {
|
||||||
global.debugger.status = crate::eval::DebuggerStatus::Terminate;
|
global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate;
|
||||||
let mut this = crate::Dynamic::NULL;
|
let mut this = crate::Dynamic::NULL;
|
||||||
let node = &crate::ast::Stmt::Noop(crate::Position::NONE);
|
let node = &crate::ast::Stmt::Noop(crate::Position::NONE);
|
||||||
self.run_debugger(global, caches, scope, &mut this, node)?;
|
self.run_debugger(global, caches, scope, &mut this, node)?;
|
||||||
|
@ -139,8 +139,8 @@ pub fn format_type(typ: &str, is_return_type: bool) -> std::borrow::Cow<str> {
|
|||||||
} else {
|
} else {
|
||||||
format!("&mut {r}").into()
|
format!("&mut {r}").into()
|
||||||
};
|
};
|
||||||
} else if typ.contains(" ") {
|
} else if typ.contains(' ') {
|
||||||
let typ = typ.replace(" ", "");
|
let typ = typ.replace(' ', "");
|
||||||
let r = format_type(&typ, is_return_type);
|
let r = format_type(&typ, is_return_type);
|
||||||
return r.into_owned().into();
|
return r.into_owned().into();
|
||||||
}
|
}
|
||||||
@ -205,6 +205,7 @@ impl Engine {
|
|||||||
return self
|
return self
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(|m| m.iter())
|
||||||
.find_map(|(_, m)| m.get_custom_type(name));
|
.find_map(|(_, m)| m.get_custom_type(name));
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
return None;
|
return None;
|
||||||
@ -238,6 +239,7 @@ impl Engine {
|
|||||||
return self
|
return self
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(|m| m.iter())
|
||||||
.find_map(|(_, m)| m.get_custom_type(name));
|
.find_map(|(_, m)| m.get_custom_type(name));
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
return None;
|
return None;
|
||||||
|
@ -772,7 +772,7 @@ impl AST {
|
|||||||
/// Not available under `no_function`.
|
/// Not available under `no_function`.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_functions<'a>(&'a self) -> impl Iterator<Item = super::ScriptFnMetadata> + 'a {
|
pub fn iter_functions(&self) -> impl Iterator<Item = super::ScriptFnMetadata> {
|
||||||
self.lib
|
self.lib
|
||||||
.iter_script_fn()
|
.iter_script_fn()
|
||||||
.map(|(.., fn_def)| fn_def.as_ref().into())
|
.map(|(.., fn_def)| fn_def.as_ref().into())
|
||||||
@ -942,7 +942,7 @@ impl Borrow<crate::Module> for AST {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn borrow(&self) -> &crate::Module {
|
fn borrow(&self) -> &crate::Module {
|
||||||
&self.shared_lib()
|
self.shared_lib()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1012,7 +1012,20 @@ impl PartialEq for ASTNode<'_> {
|
|||||||
impl Eq for ASTNode<'_> {}
|
impl Eq for ASTNode<'_> {}
|
||||||
|
|
||||||
impl ASTNode<'_> {
|
impl ASTNode<'_> {
|
||||||
|
/// Is this [`ASTNode`] a [`Stmt`]?
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn is_stmt(&self) -> bool {
|
||||||
|
matches!(self, Self::Stmt(..))
|
||||||
|
}
|
||||||
|
/// Is this [`ASTNode`] an [`Expr`]?
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn is_expr(&self) -> bool {
|
||||||
|
matches!(self, Self::Expr(..))
|
||||||
|
}
|
||||||
/// Get the [`Position`] of this [`ASTNode`].
|
/// Get the [`Position`] of this [`ASTNode`].
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn position(&self) -> Position {
|
pub fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
|
@ -173,7 +173,7 @@ impl FnCallHashes {
|
|||||||
/// The hash returned is never zero.
|
/// The hash returned is never zero.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn native(&self) -> u64 {
|
pub const fn native(&self) -> u64 {
|
||||||
self.native.get()
|
self.native.get()
|
||||||
}
|
}
|
||||||
/// Get the script hash.
|
/// Get the script hash.
|
||||||
@ -361,7 +361,7 @@ impl fmt::Debug for Expr {
|
|||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut display_pos = format!(" @ {:?}", self.start_position());
|
let mut display_pos = self.start_position();
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::DynamicConstant(value, ..) => write!(f, "{value:?}"),
|
Self::DynamicConstant(value, ..) => write!(f, "{value:?}"),
|
||||||
@ -395,7 +395,7 @@ impl fmt::Debug for Expr {
|
|||||||
write!(f, "{}{}", x.1, Token::DoubleColon.literal_syntax())?;
|
write!(f, "{}{}", x.1, Token::DoubleColon.literal_syntax())?;
|
||||||
let pos = x.1.position();
|
let pos = x.1.position();
|
||||||
if !pos.is_none() {
|
if !pos.is_none() {
|
||||||
display_pos = format!(" @ {pos:?}");
|
display_pos = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.write_str(&x.3)?;
|
f.write_str(&x.3)?;
|
||||||
@ -413,7 +413,7 @@ impl fmt::Debug for Expr {
|
|||||||
Self::Stmt(x) => {
|
Self::Stmt(x) => {
|
||||||
let pos = x.span();
|
let pos = x.span();
|
||||||
if !pos.is_none() {
|
if !pos.is_none() {
|
||||||
display_pos = format!(" @ {pos:?}");
|
display_pos = pos.start();
|
||||||
}
|
}
|
||||||
f.write_str("ExprStmtBlock")?;
|
f.write_str("ExprStmtBlock")?;
|
||||||
f.debug_list().entries(x.iter()).finish()
|
f.debug_list().entries(x.iter()).finish()
|
||||||
@ -421,7 +421,7 @@ impl fmt::Debug for Expr {
|
|||||||
Self::FnCall(x, ..) => fmt::Debug::fmt(x, f),
|
Self::FnCall(x, ..) => fmt::Debug::fmt(x, f),
|
||||||
Self::Index(x, options, pos) => {
|
Self::Index(x, options, pos) => {
|
||||||
if !pos.is_none() {
|
if !pos.is_none() {
|
||||||
display_pos = format!(" @ {pos:?}");
|
display_pos = *pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut f = f.debug_struct("Index");
|
let mut f = f.debug_struct("Index");
|
||||||
@ -434,7 +434,7 @@ impl fmt::Debug for Expr {
|
|||||||
}
|
}
|
||||||
Self::Dot(x, options, pos) => {
|
Self::Dot(x, options, pos) => {
|
||||||
if !pos.is_none() {
|
if !pos.is_none() {
|
||||||
display_pos = format!(" @ {pos:?}");
|
display_pos = *pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut f = f.debug_struct("Dot");
|
let mut f = f.debug_struct("Dot");
|
||||||
@ -454,7 +454,7 @@ impl fmt::Debug for Expr {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !pos.is_none() {
|
if !pos.is_none() {
|
||||||
display_pos = format!(" @ {pos:?}");
|
display_pos = *pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.debug_struct(op_name)
|
f.debug_struct(op_name)
|
||||||
@ -466,7 +466,7 @@ impl fmt::Debug for Expr {
|
|||||||
Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(),
|
Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
f.write_str(&display_pos)
|
write!(f, " @ {display_pos:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,18 +837,12 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Self::Custom(..) => false,
|
Self::Custom(..) => false,
|
||||||
|
|
||||||
Self::Variable(..) => match token {
|
Self::Variable(..) => matches!(
|
||||||
Token::LeftParen => true,
|
token,
|
||||||
Token::Unit => true,
|
Token::LeftParen | Token::Unit | Token::Bang | Token::DoubleColon
|
||||||
Token::Bang => true,
|
),
|
||||||
Token::DoubleColon => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Property(..) => match token {
|
Self::Property(..) => matches!(token, Token::LeftParen),
|
||||||
Token::LeftParen => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Recursively walk this expression.
|
/// Recursively walk this expression.
|
||||||
|
@ -6,7 +6,7 @@ use std::prelude::v1::*;
|
|||||||
|
|
||||||
/// A type representing the access mode of a function.
|
/// A type representing the access mode of a function.
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
#[cfg_attr(feature = "metadata", derive(serde::Serialize))]
|
#[cfg_attr(feature = "metadata", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[cfg_attr(feature = "metadata", serde(rename_all = "camelCase"))]
|
#[cfg_attr(feature = "metadata", serde(rename_all = "camelCase"))]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum FnAccess {
|
pub enum FnAccess {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
|
|
||||||
use super::{FnAccess, StmtBlock};
|
use super::{FnAccess, StmtBlock};
|
||||||
use crate::{ImmutableString, StaticVec};
|
use crate::{FnArgsVec, ImmutableString};
|
||||||
#[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};
|
||||||
@ -42,7 +42,7 @@ pub struct ScriptFnDef {
|
|||||||
/// Function access mode.
|
/// Function access mode.
|
||||||
pub access: FnAccess,
|
pub access: FnAccess,
|
||||||
/// Names of function parameters.
|
/// Names of function parameters.
|
||||||
pub params: StaticVec<ImmutableString>,
|
pub params: FnArgsVec<ImmutableString>,
|
||||||
/// _(metadata)_ Function doc-comments (if any).
|
/// _(metadata)_ Function doc-comments (if any).
|
||||||
/// Exported under the `metadata` feature only.
|
/// Exported under the `metadata` feature only.
|
||||||
///
|
///
|
||||||
@ -72,7 +72,7 @@ impl fmt::Display for ScriptFnDef {
|
|||||||
self.params
|
self.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.as_str())
|
.map(|s| s.as_str())
|
||||||
.collect::<StaticVec<_>>()
|
.collect::<FnArgsVec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ impl fmt::Display for ScriptFnMetadata<'_> {
|
|||||||
self.params
|
self.params
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.collect::<StaticVec<_>>()
|
.collect::<FnArgsVec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -926,10 +926,7 @@ impl Stmt {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_control_flow_break(&self) -> bool {
|
pub const fn is_control_flow_break(&self) -> bool {
|
||||||
match self {
|
matches!(self, Self::Return(..) | Self::BreakLoop(..))
|
||||||
Self::Return(..) | Self::BreakLoop(..) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Recursively walk this statement.
|
/// Recursively walk this statement.
|
||||||
/// Return `false` from the callback to terminate the walk.
|
/// Return `false` from the callback to terminate the walk.
|
||||||
|
@ -61,7 +61,7 @@ fn print_current_source(
|
|||||||
) {
|
) {
|
||||||
let current_source = &mut *context
|
let current_source = &mut *context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.state_mut()
|
.state_mut()
|
||||||
.write_lock::<ImmutableString>()
|
.write_lock::<ImmutableString>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -241,7 +241,7 @@ fn debug_callback(
|
|||||||
DebuggerEvent::End => println!("\x1b[31m! Script end\x1b[39m"),
|
DebuggerEvent::End => println!("\x1b[31m! Script end\x1b[39m"),
|
||||||
DebuggerEvent::Step => (),
|
DebuggerEvent::Step => (),
|
||||||
DebuggerEvent::BreakPoint(n) => {
|
DebuggerEvent::BreakPoint(n) => {
|
||||||
match context.global_runtime_state().debugger.break_points()[n] {
|
match context.global_runtime_state().debugger().break_points()[n] {
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
BreakPoint::AtPosition { .. } => (),
|
BreakPoint::AtPosition { .. } => (),
|
||||||
BreakPoint::AtFunctionName { ref name, .. }
|
BreakPoint::AtFunctionName { ref name, .. }
|
||||||
@ -260,7 +260,7 @@ fn debug_callback(
|
|||||||
"! Return from function call '{}' => {:?}",
|
"! Return from function call '{}' => {:?}",
|
||||||
context
|
context
|
||||||
.global_runtime_state()
|
.global_runtime_state()
|
||||||
.debugger
|
.debugger()
|
||||||
.call_stack()
|
.call_stack()
|
||||||
.last()
|
.last()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -273,7 +273,7 @@ fn debug_callback(
|
|||||||
"! Return from function call '{}' with error: {}",
|
"! Return from function call '{}' with error: {}",
|
||||||
context
|
context
|
||||||
.global_runtime_state()
|
.global_runtime_state()
|
||||||
.debugger
|
.debugger()
|
||||||
.call_stack()
|
.call_stack()
|
||||||
.last()
|
.last()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -373,7 +373,7 @@ fn debug_callback(
|
|||||||
["backtrace" | "bt"] => {
|
["backtrace" | "bt"] => {
|
||||||
for frame in context
|
for frame in context
|
||||||
.global_runtime_state()
|
.global_runtime_state()
|
||||||
.debugger
|
.debugger()
|
||||||
.call_stack()
|
.call_stack()
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
@ -384,7 +384,7 @@ fn debug_callback(
|
|||||||
["info" | "i", "break" | "b"] => Iterator::for_each(
|
["info" | "i", "break" | "b"] => Iterator::for_each(
|
||||||
context
|
context
|
||||||
.global_runtime_state()
|
.global_runtime_state()
|
||||||
.debugger
|
.debugger()
|
||||||
.break_points()
|
.break_points()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate(),
|
.enumerate(),
|
||||||
@ -402,13 +402,13 @@ fn debug_callback(
|
|||||||
if let Ok(n) = n.parse::<usize>() {
|
if let Ok(n) = n.parse::<usize>() {
|
||||||
let range = 1..=context
|
let range = 1..=context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger()
|
||||||
.break_points()
|
.break_points()
|
||||||
.len();
|
.len();
|
||||||
if range.contains(&n) {
|
if range.contains(&n) {
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.get_mut(n - 1)
|
.get_mut(n - 1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -425,13 +425,13 @@ fn debug_callback(
|
|||||||
if let Ok(n) = n.parse::<usize>() {
|
if let Ok(n) = n.parse::<usize>() {
|
||||||
let range = 1..=context
|
let range = 1..=context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger()
|
||||||
.break_points()
|
.break_points()
|
||||||
.len();
|
.len();
|
||||||
if range.contains(&n) {
|
if range.contains(&n) {
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.get_mut(n - 1)
|
.get_mut(n - 1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -448,13 +448,13 @@ fn debug_callback(
|
|||||||
if let Ok(n) = n.parse::<usize>() {
|
if let Ok(n) = n.parse::<usize>() {
|
||||||
let range = 1..=context
|
let range = 1..=context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger()
|
||||||
.break_points()
|
.break_points()
|
||||||
.len();
|
.len();
|
||||||
if range.contains(&n) {
|
if range.contains(&n) {
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.remove(n - 1);
|
.remove(n - 1);
|
||||||
println!("Break-point #{n} deleted.")
|
println!("Break-point #{n} deleted.")
|
||||||
@ -468,7 +468,7 @@ fn debug_callback(
|
|||||||
["delete" | "d"] => {
|
["delete" | "d"] => {
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.clear();
|
.clear();
|
||||||
println!("All break-points deleted.");
|
println!("All break-points deleted.");
|
||||||
@ -483,7 +483,7 @@ fn debug_callback(
|
|||||||
println!("Break-point added for {bp}");
|
println!("Break-point added for {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(bp);
|
.push(bp);
|
||||||
} else {
|
} else {
|
||||||
@ -500,7 +500,7 @@ fn debug_callback(
|
|||||||
println!("Break-point added for {bp}");
|
println!("Break-point added for {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(bp);
|
.push(bp);
|
||||||
}
|
}
|
||||||
@ -523,7 +523,7 @@ fn debug_callback(
|
|||||||
println!("Break-point added {bp}");
|
println!("Break-point added {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(bp);
|
.push(bp);
|
||||||
} else {
|
} else {
|
||||||
@ -539,7 +539,7 @@ fn debug_callback(
|
|||||||
println!("Break-point added for {bp}");
|
println!("Break-point added for {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(bp);
|
.push(bp);
|
||||||
}
|
}
|
||||||
@ -553,7 +553,7 @@ fn debug_callback(
|
|||||||
println!("Break-point added {bp}");
|
println!("Break-point added {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(bp);
|
.push(bp);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ impl WhenTheHokmaSuppression {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn the_price_of_silence(self) {
|
pub fn the_price_of_silence(self) {
|
||||||
self.hokma.lock.store(self.state, Ordering::SeqCst);
|
self.hokma.lock.store(self.state, Ordering::SeqCst);
|
||||||
mem::forget(self)
|
mem::forget(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,58 +80,65 @@ impl Drop for WhenTheHokmaSuppression {
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.hokma
|
self.hokma
|
||||||
.lock
|
.lock
|
||||||
.store(self.state.wrapping_add(2), Ordering::SeqCst)
|
.store(self.state.wrapping_add(2), Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
fn hokmalock(address: usize) -> &'static HokmaLock {
|
fn hokmalock(address: usize) -> &'static HokmaLock {
|
||||||
const LEN: usize = 787;
|
const LEN: usize = 787;
|
||||||
|
#[allow(clippy::declare_interior_mutable_const)]
|
||||||
const LCK: HokmaLock = HokmaLock::new();
|
const LCK: HokmaLock = HokmaLock::new();
|
||||||
static RECORDS: [HokmaLock; LEN] = [LCK; LEN];
|
static RECORDS: [HokmaLock; LEN] = [LCK; LEN];
|
||||||
|
|
||||||
&RECORDS[address % LEN]
|
&RECORDS[address % LEN]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: lol, there is a reason its called `SusLock<T>`
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// LOL, there is a reason its called `SusLock`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
struct SusLock<T>
|
pub struct SusLock<T: 'static> {
|
||||||
where
|
|
||||||
T: 'static,
|
|
||||||
{
|
|
||||||
initialized: AtomicBool,
|
initialized: AtomicBool,
|
||||||
data: UnsafeCell<MaybeUninit<T>>,
|
data: UnsafeCell<MaybeUninit<T>>,
|
||||||
_marker: PhantomData<T>,
|
_marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SusLock<T>
|
impl<T: 'static> Default for SusLock<T> {
|
||||||
where
|
#[inline(always)]
|
||||||
T: 'static,
|
fn default() -> Self {
|
||||||
{
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> SusLock<T> {
|
||||||
|
/// Create a new [`SusLock`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new() -> SusLock<T> {
|
pub const fn new() -> Self {
|
||||||
SusLock {
|
Self {
|
||||||
initialized: AtomicBool::new(false),
|
initialized: AtomicBool::new(false),
|
||||||
data: UnsafeCell::new(MaybeUninit::uninit()),
|
data: UnsafeCell::new(MaybeUninit::uninit()),
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the [`SusLock`] initialized?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_initialized(&self) -> bool {
|
pub fn is_initialized(&self) -> bool {
|
||||||
self.initialized.load(Ordering::SeqCst)
|
self.initialized.load(Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the value of the [`SusLock`] (if initialized).
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get(&self) -> Option<&'static T> {
|
pub fn get(&self) -> Option<&'static T> {
|
||||||
if self.initialized.load(Ordering::SeqCst) {
|
if self.initialized.load(Ordering::SeqCst) {
|
||||||
let hokma = hokmalock(unsafe { mem::transmute(self.data.get()) });
|
let hokma = hokmalock(self.data.get() as usize);
|
||||||
// we forgo the optimistic read, because we don't really care
|
// we forgo the optimistic read, because we don't really care
|
||||||
let guard = hokma.write();
|
let guard = hokma.write();
|
||||||
let cast: *const T = self.data.get().cast();
|
let cast: *const T = self.data.get().cast();
|
||||||
let val = unsafe { mem::transmute::<*const T, &'static T>(cast) };
|
let val = unsafe { &*cast.cast::<T>() };
|
||||||
guard.the_price_of_silence();
|
guard.the_price_of_silence();
|
||||||
Some(val)
|
Some(val)
|
||||||
} else {
|
} else {
|
||||||
@ -139,11 +146,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the value of the [`SusLock`], initializing it if not yet done.
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_or_init(&self, f: impl FnOnce() -> T) -> &'static T {
|
pub fn get_or_init(&self, f: impl FnOnce() -> T) -> &'static T {
|
||||||
if !self.initialized.load(Ordering::SeqCst) {
|
if !self.initialized.load(Ordering::SeqCst) {
|
||||||
self.initialized.store(true, Ordering::SeqCst);
|
self.initialized.store(true, Ordering::SeqCst);
|
||||||
let hokma = hokmalock(unsafe { mem::transmute(self.data.get()) });
|
let hokma = hokmalock(self.data.get() as usize);
|
||||||
hokma.write();
|
hokma.write();
|
||||||
unsafe {
|
unsafe {
|
||||||
self.data.get().write(MaybeUninit::new(f()));
|
self.data.get().write(MaybeUninit::new(f()));
|
||||||
@ -153,7 +162,13 @@ where
|
|||||||
self.get().unwrap()
|
self.get().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&self, value: T) -> Result<(), T> {
|
/// Initialize the value of the [`SusLock`].
|
||||||
|
///
|
||||||
|
/// # Error
|
||||||
|
///
|
||||||
|
/// If the [`SusLock`] has already been initialized, the current value is returned as error.
|
||||||
|
#[inline]
|
||||||
|
pub fn init(&self, value: T) -> Result<(), T> {
|
||||||
if self.initialized.load(Ordering::SeqCst) {
|
if self.initialized.load(Ordering::SeqCst) {
|
||||||
Err(value)
|
Err(value)
|
||||||
} else {
|
} else {
|
||||||
@ -163,18 +178,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Sync + Send> Sync for SusLock<T> where T: 'static {}
|
unsafe impl<T: Sync + Send> Sync for SusLock<T> {}
|
||||||
unsafe impl<T: Send> Send for SusLock<T> where T: 'static {}
|
unsafe impl<T: Send> Send for SusLock<T> {}
|
||||||
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SusLock<T> where T: 'static {}
|
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SusLock<T> {}
|
||||||
|
|
||||||
impl<T> Drop for SusLock<T>
|
impl<T: 'static> Drop for SusLock<T> {
|
||||||
where
|
|
||||||
T: 'static,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.initialized.load(Ordering::SeqCst) {
|
if self.initialized.load(Ordering::SeqCst) {
|
||||||
unsafe { (&mut *self.data.get()).assume_init_drop() };
|
unsafe { (*self.data.get()).assume_init_drop() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +219,7 @@ static AHASH_SEED: SusLock<Option<[u64; 4]>> = SusLock::new();
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> {
|
pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> {
|
||||||
AHASH_SEED.set(new_seed)
|
AHASH_SEED.init(new_seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current hashing Seed.
|
/// Get the current hashing Seed.
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
//! This file is automatically recreated during build time by `build.rs` from `build.template`.
|
//! This file is automatically recreated during build time by `build.rs` from `build.template`.
|
||||||
|
|
||||||
pub(crate) const AHASH_SEED: Option<[u64; 4]> = None;
|
pub const AHASH_SEED: Option<[u64; 4]> = None;
|
||||||
|
@ -5,6 +5,7 @@ use crate::func::native::{
|
|||||||
locked_write, OnDebugCallback, OnDefVarCallback, OnParseTokenCallback, OnPrintCallback,
|
locked_write, OnDebugCallback, OnDefVarCallback, OnParseTokenCallback, OnPrintCallback,
|
||||||
OnVarCallback,
|
OnVarCallback,
|
||||||
};
|
};
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::packages::{Package, StandardPackage};
|
use crate::packages::{Package, StandardPackage};
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::types::StringsInterner;
|
use crate::types::StringsInterner;
|
||||||
@ -95,24 +96,27 @@ pub struct Engine {
|
|||||||
pub(crate) global_modules: StaticVec<SharedModule>,
|
pub(crate) global_modules: StaticVec<SharedModule>,
|
||||||
/// A collection of all sub-modules directly loaded into the Engine.
|
/// A collection of all sub-modules directly loaded into the Engine.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) global_sub_modules: std::collections::BTreeMap<Identifier, SharedModule>,
|
pub(crate) global_sub_modules:
|
||||||
|
Option<Box<std::collections::BTreeMap<Identifier, SharedModule>>>,
|
||||||
|
|
||||||
/// A module resolution service.
|
/// A module resolution service.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
|
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
|
||||||
|
|
||||||
/// An empty [`ImmutableString`] for cloning purposes.
|
/// An empty [`ImmutableString`] for cloning purposes.
|
||||||
pub(crate) interned_strings: Locked<StringsInterner<'static>>,
|
pub(crate) interned_strings: Locked<StringsInterner>,
|
||||||
|
|
||||||
/// A set of symbols to disable.
|
/// A set of symbols to disable.
|
||||||
pub(crate) disabled_symbols: BTreeSet<Identifier>,
|
pub(crate) disabled_symbols: Option<Box<BTreeSet<Identifier>>>,
|
||||||
/// A map containing custom keywords and precedence to recognize.
|
/// A map containing custom keywords and precedence to recognize.
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
pub(crate) custom_keywords: std::collections::BTreeMap<Identifier, Option<Precedence>>,
|
pub(crate) custom_keywords:
|
||||||
|
Option<Box<std::collections::BTreeMap<Identifier, Option<Precedence>>>>,
|
||||||
/// Custom syntax.
|
/// Custom syntax.
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
pub(crate) custom_syntax:
|
pub(crate) custom_syntax: Option<
|
||||||
std::collections::BTreeMap<Identifier, crate::api::custom_syntax::CustomSyntax>,
|
Box<std::collections::BTreeMap<Identifier, crate::api::custom_syntax::CustomSyntax>>,
|
||||||
|
>,
|
||||||
/// Callback closure for filtering variable definition.
|
/// Callback closure for filtering variable definition.
|
||||||
pub(crate) def_var_filter: Option<Box<OnDefVarCallback>>,
|
pub(crate) def_var_filter: Option<Box<OnDefVarCallback>>,
|
||||||
/// Callback closure for resolving variable access.
|
/// Callback closure for resolving variable access.
|
||||||
@ -143,10 +147,12 @@ pub struct Engine {
|
|||||||
|
|
||||||
/// Callback closure for debugging.
|
/// Callback closure for debugging.
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
pub(crate) debugger: Option<(
|
pub(crate) debugger: Option<
|
||||||
|
Box<(
|
||||||
Box<crate::eval::OnDebuggingInit>,
|
Box<crate::eval::OnDebuggingInit>,
|
||||||
Box<crate::eval::OnDebuggerCallback>,
|
Box<crate::eval::OnDebuggerCallback>,
|
||||||
)>,
|
)>,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Engine {
|
impl fmt::Debug for Engine {
|
||||||
@ -167,7 +173,8 @@ impl fmt::Debug for Engine {
|
|||||||
"custom_syntax",
|
"custom_syntax",
|
||||||
&self
|
&self
|
||||||
.custom_syntax
|
.custom_syntax
|
||||||
.keys()
|
.iter()
|
||||||
|
.flat_map(|m| m.keys())
|
||||||
.map(crate::SmartString::as_str)
|
.map(crate::SmartString::as_str)
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
);
|
);
|
||||||
@ -263,17 +270,17 @@ impl Engine {
|
|||||||
global_modules: StaticVec::new_const(),
|
global_modules: StaticVec::new_const(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
global_sub_modules: std::collections::BTreeMap::new(),
|
global_sub_modules: None,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
module_resolver: Box::new(crate::module::resolvers::DummyModuleResolver::new()),
|
module_resolver: Box::new(crate::module::resolvers::DummyModuleResolver::new()),
|
||||||
|
|
||||||
interned_strings: StringsInterner::new().into(),
|
interned_strings: StringsInterner::new().into(),
|
||||||
disabled_symbols: BTreeSet::new(),
|
disabled_symbols: None,
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
custom_keywords: std::collections::BTreeMap::new(),
|
custom_keywords: None,
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
custom_syntax: std::collections::BTreeMap::new(),
|
custom_syntax: None,
|
||||||
|
|
||||||
def_var_filter: None,
|
def_var_filter: None,
|
||||||
resolve_var: None,
|
resolve_var: None,
|
||||||
@ -302,8 +309,8 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add the global namespace module
|
// Add the global namespace module
|
||||||
let mut global_namespace = Module::with_capacity(0);
|
let mut global_namespace = Module::new();
|
||||||
global_namespace.internal = true;
|
global_namespace.flags |= ModuleFlags::INTERNAL;
|
||||||
engine.global_modules.push(global_namespace.into());
|
engine.global_modules.push(global_namespace.into());
|
||||||
|
|
||||||
engine
|
engine
|
||||||
|
@ -72,7 +72,7 @@ impl Caches {
|
|||||||
/// Push an empty function resolution cache onto the stack and make it current.
|
/// Push an empty function resolution cache onto the stack and make it current.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push_fn_resolution_cache(&mut self) {
|
pub fn push_fn_resolution_cache(&mut self) {
|
||||||
self.0.push(Default::default());
|
self.0.push(FnResolutionCache::default());
|
||||||
}
|
}
|
||||||
/// Rewind the function resolution caches stack to a particular size.
|
/// Rewind the function resolution caches stack to a particular size.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -3,13 +3,36 @@
|
|||||||
|
|
||||||
use super::{Caches, GlobalRuntimeState, Target};
|
use super::{Caches, GlobalRuntimeState, Target};
|
||||||
use crate::ast::{ASTFlags, Expr, OpAssignment};
|
use crate::ast::{ASTFlags, Expr, OpAssignment};
|
||||||
|
use crate::config::hashing::SusLock;
|
||||||
|
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::dynamic::Union;
|
||||||
use crate::types::RestoreOnDrop;
|
use crate::types::RestoreOnDrop;
|
||||||
use crate::{Dynamic, Engine, FnArgsVec, Position, RhaiResult, RhaiResultOf, Scope, ERR};
|
use crate::{
|
||||||
|
calc_fn_hash, Dynamic, Engine, FnArgsVec, Position, RhaiResult, RhaiResultOf, Scope, ERR,
|
||||||
|
};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
/// Function call hashes to index getters and setters.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Uses the extremely unsafe [`SusLock`]. Change to [`OnceCell`] when it is stabilized.
|
||||||
|
static INDEXER_HASHES: SusLock<(u64, u64)> = SusLock::new();
|
||||||
|
|
||||||
|
/// Get the pre-calculated index getter/setter hashes.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn hash_idx() -> (u64, u64) {
|
||||||
|
*INDEXER_HASHES.get_or_init(|| {
|
||||||
|
(
|
||||||
|
calc_fn_hash(None, FN_IDX_GET, 2),
|
||||||
|
calc_fn_hash(None, FN_IDX_SET, 3),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Method of chaining.
|
/// Method of chaining.
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub enum ChainType {
|
pub enum ChainType {
|
||||||
@ -45,15 +68,20 @@ impl Engine {
|
|||||||
idx: &mut Dynamic,
|
idx: &mut Dynamic,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<Dynamic> {
|
) -> RhaiResultOf<Dynamic> {
|
||||||
let args = &mut [target, idx];
|
|
||||||
let hash = global.hash_idx_get();
|
|
||||||
let fn_name = crate::engine::FN_IDX_GET;
|
|
||||||
|
|
||||||
let orig_level = global.level;
|
let orig_level = global.level;
|
||||||
global.level += 1;
|
global.level += 1;
|
||||||
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
|
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
|
||||||
|
|
||||||
self.exec_native_fn_call(global, caches, fn_name, None, hash, args, true, pos)
|
self.exec_native_fn_call(
|
||||||
|
global,
|
||||||
|
caches,
|
||||||
|
FN_IDX_GET,
|
||||||
|
None,
|
||||||
|
hash_idx().0,
|
||||||
|
&mut [target, idx],
|
||||||
|
true,
|
||||||
|
pos,
|
||||||
|
)
|
||||||
.map(|(r, ..)| r)
|
.map(|(r, ..)| r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,15 +97,20 @@ impl Engine {
|
|||||||
is_ref_mut: bool,
|
is_ref_mut: bool,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
let hash = global.hash_idx_set();
|
|
||||||
let args = &mut [target, idx, new_val];
|
|
||||||
let fn_name = crate::engine::FN_IDX_SET;
|
|
||||||
|
|
||||||
let orig_level = global.level;
|
let orig_level = global.level;
|
||||||
global.level += 1;
|
global.level += 1;
|
||||||
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
|
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
|
||||||
|
|
||||||
self.exec_native_fn_call(global, caches, fn_name, None, hash, args, is_ref_mut, pos)
|
self.exec_native_fn_call(
|
||||||
|
global,
|
||||||
|
caches,
|
||||||
|
FN_IDX_SET,
|
||||||
|
None,
|
||||||
|
hash_idx().1,
|
||||||
|
&mut [target, idx, new_val],
|
||||||
|
is_ref_mut,
|
||||||
|
pos,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value at the indexed position of a base type.
|
/// Get the value at the indexed position of a base type.
|
||||||
@ -168,6 +201,7 @@ impl Engine {
|
|||||||
ERR::ErrorBitFieldBounds(crate::INT_BITS, end, idx_pos).into()
|
ERR::ErrorBitFieldBounds(crate::INT_BITS, end, idx_pos).into()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
if end <= start {
|
if end <= start {
|
||||||
(0, 0)
|
(0, 0)
|
||||||
} else if end == crate::INT_BITS && start == 0 {
|
} else if end == crate::INT_BITS && start == 0 {
|
||||||
@ -193,6 +227,7 @@ impl Engine {
|
|||||||
ERR::ErrorBitFieldBounds(crate::INT_BITS, end, idx_pos).into()
|
ERR::ErrorBitFieldBounds(crate::INT_BITS, end, idx_pos).into()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
if end < start {
|
if end < start {
|
||||||
(0, 0)
|
(0, 0)
|
||||||
} else if end == crate::INT_BITS - 1 && start == 0 {
|
} else if end == crate::INT_BITS - 1 && start == 0 {
|
||||||
@ -237,6 +272,7 @@ impl Engine {
|
|||||||
Ok(Target::Bit {
|
Ok(Target::Bit {
|
||||||
source: target,
|
source: target,
|
||||||
value: bit_value.into(),
|
value: bit_value.into(),
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
bit: bit as u8,
|
bit: bit as u8,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -249,12 +285,14 @@ impl Engine {
|
|||||||
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
|
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
|
||||||
|
|
||||||
let (ch, offset) = if index >= 0 {
|
let (ch, offset) = if index >= 0 {
|
||||||
|
#[allow(clippy::absurd_extreme_comparisons)]
|
||||||
if index >= crate::MAX_USIZE_INT {
|
if index >= crate::MAX_USIZE_INT {
|
||||||
return Err(
|
return Err(
|
||||||
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into()
|
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||||
let offset = index as usize;
|
let offset = index as usize;
|
||||||
(
|
(
|
||||||
s.chars().nth(offset).ok_or_else(|| {
|
s.chars().nth(offset).ok_or_else(|| {
|
||||||
@ -271,6 +309,7 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let offset = abs_index as usize;
|
let offset = abs_index as usize;
|
||||||
(
|
(
|
||||||
// Count from end if negative
|
// Count from end if negative
|
||||||
@ -317,7 +356,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
this_ptr: &mut Dynamic,
|
this_ptr: &mut Dynamic,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
new_val: &mut Option<(Dynamic, &OpAssignment)>,
|
new_val: Option<(Dynamic, &OpAssignment)>,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let chain_type = ChainType::from(expr);
|
let chain_type = ChainType::from(expr);
|
||||||
|
|
||||||
@ -507,7 +546,7 @@ impl Engine {
|
|||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
idx_values: &mut FnArgsVec<Dynamic>,
|
idx_values: &mut FnArgsVec<Dynamic>,
|
||||||
new_val: &mut Option<(Dynamic, &OpAssignment)>,
|
new_val: Option<(Dynamic, &OpAssignment)>,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
let is_ref_mut = target.is_ref();
|
let is_ref_mut = target.is_ref();
|
||||||
let op_pos = parent.position();
|
let op_pos = parent.position();
|
||||||
@ -576,7 +615,7 @@ impl Engine {
|
|||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(global, caches, scope, this_ptr, parent)?;
|
self.run_debugger(global, caches, scope, this_ptr, parent)?;
|
||||||
|
|
||||||
let (new_val, op_info) = new_val.take().expect("`Some`");
|
let (new_val, op_info) = new_val.expect("`Some`");
|
||||||
let idx_val = &mut idx_values.pop().unwrap();
|
let idx_val = &mut idx_values.pop().unwrap();
|
||||||
let idx = &mut idx_val.clone();
|
let idx = &mut idx_val.clone();
|
||||||
|
|
||||||
@ -657,8 +696,9 @@ impl Engine {
|
|||||||
let reset =
|
let reset =
|
||||||
self.run_debugger_with_reset(global, caches, scope, this_ptr, rhs)?;
|
self.run_debugger_with_reset(global, caches, scope, this_ptr, rhs)?;
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let global = &mut *RestoreOnDrop::lock(global, move |g| {
|
let global =
|
||||||
g.debugger.reset_status(reset)
|
&mut *RestoreOnDrop::lock_if(reset.is_some(), global, move |g| {
|
||||||
|
g.debugger_mut().reset_status(reset)
|
||||||
});
|
});
|
||||||
|
|
||||||
let crate::ast::FnCallExpr {
|
let crate::ast::FnCallExpr {
|
||||||
@ -686,12 +726,12 @@ impl Engine {
|
|||||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
}
|
}
|
||||||
// {xxx:map}.id op= ???
|
// {xxx:map}.id op= ???
|
||||||
Expr::Property(x, pos) if target.is_map() && new_val.is_some() => {
|
Expr::Property(x, pos) if new_val.is_some() && target.is_map() => {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(global, caches, scope, this_ptr, rhs)?;
|
self.run_debugger(global, caches, scope, this_ptr, rhs)?;
|
||||||
|
|
||||||
let index = &mut x.2.clone().into();
|
let index = &mut x.2.clone().into();
|
||||||
let (new_val, op_info) = new_val.take().expect("`Some`");
|
let (new_val, op_info) = new_val.expect("`Some`");
|
||||||
{
|
{
|
||||||
let val_target = &mut self.get_indexed_mut(
|
let val_target = &mut self.get_indexed_mut(
|
||||||
global, caches, target, index, *pos, op_pos, true, false,
|
global, caches, target, index, *pos, op_pos, true, false,
|
||||||
@ -720,7 +760,7 @@ impl Engine {
|
|||||||
self.run_debugger(global, caches, scope, this_ptr, rhs)?;
|
self.run_debugger(global, caches, scope, this_ptr, rhs)?;
|
||||||
|
|
||||||
let ((getter, hash_get), (setter, hash_set), name) = &**x;
|
let ((getter, hash_get), (setter, hash_set), name) = &**x;
|
||||||
let (mut new_val, op_info) = new_val.take().expect("`Some`");
|
let (mut new_val, op_info) = new_val.expect("`Some`");
|
||||||
|
|
||||||
if op_info.is_op_assignment() {
|
if op_info.is_op_assignment() {
|
||||||
let args = &mut [target.as_mut()];
|
let args = &mut [target.as_mut()];
|
||||||
@ -826,9 +866,11 @@ impl Engine {
|
|||||||
global, caches, scope, this_ptr, _node,
|
global, caches, scope, this_ptr, _node,
|
||||||
)?;
|
)?;
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let global = &mut *RestoreOnDrop::lock(global, move |g| {
|
let global = &mut *RestoreOnDrop::lock_if(
|
||||||
g.debugger.reset_status(reset)
|
reset.is_some(),
|
||||||
});
|
global,
|
||||||
|
move |g| g.debugger_mut().reset_status(reset),
|
||||||
|
);
|
||||||
|
|
||||||
let crate::ast::FnCallExpr {
|
let crate::ast::FnCallExpr {
|
||||||
name, hashes, args, ..
|
name, hashes, args, ..
|
||||||
@ -950,9 +992,11 @@ impl Engine {
|
|||||||
global, caches, scope, this_ptr, _node,
|
global, caches, scope, this_ptr, _node,
|
||||||
)?;
|
)?;
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let global = &mut *RestoreOnDrop::lock(global, move |g| {
|
let global = &mut *RestoreOnDrop::lock_if(
|
||||||
g.debugger.reset_status(reset)
|
reset.is_some(),
|
||||||
});
|
global,
|
||||||
|
move |g| g.debugger_mut().reset_status(reset),
|
||||||
|
);
|
||||||
|
|
||||||
let crate::ast::FnCallExpr {
|
let crate::ast::FnCallExpr {
|
||||||
name, hashes, args, ..
|
name, hashes, args, ..
|
||||||
|
@ -8,7 +8,7 @@ use std::borrow::Borrow;
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
impl Engine {
|
impl Dynamic {
|
||||||
/// Recursively calculate the sizes of a value.
|
/// Recursively calculate the sizes of a value.
|
||||||
///
|
///
|
||||||
/// Sizes returned are `(` [`Array`][crate::Array], [`Map`][crate::Map] and [`String`] `)`.
|
/// Sizes returned are `(` [`Array`][crate::Array], [`Map`][crate::Map] and [`String`] `)`.
|
||||||
@ -16,20 +16,20 @@ impl Engine {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if any interior data is shared (should never happen).
|
/// Panics if any interior data is shared (should never happen).
|
||||||
pub(crate) fn calc_data_sizes(value: &Dynamic, _top: bool) -> (usize, usize, usize) {
|
pub(crate) fn calc_data_sizes(&self, _top: bool) -> (usize, usize, usize) {
|
||||||
match value.0 {
|
match self.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref arr, ..) => {
|
Union::Array(ref arr, ..) => {
|
||||||
arr.iter()
|
arr.iter()
|
||||||
.fold((0, 0, 0), |(ax, mx, sx), value| match value.0 {
|
.fold((0, 0, 0), |(ax, mx, sx), value| match value.0 {
|
||||||
Union::Array(..) => {
|
Union::Array(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = value.calc_data_sizes(false);
|
||||||
(ax + a + 1, mx + m, sx + s)
|
(ax + a + 1, mx + m, sx + s)
|
||||||
}
|
}
|
||||||
Union::Blob(ref a, ..) => (ax + 1 + a.len(), mx, sx),
|
Union::Blob(ref a, ..) => (ax + 1 + a.len(), mx, sx),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(..) => {
|
Union::Map(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = value.calc_data_sizes(false);
|
||||||
(ax + a + 1, mx + m, sx + s)
|
(ax + a + 1, mx + m, sx + s)
|
||||||
}
|
}
|
||||||
Union::Str(ref s, ..) => (ax + 1, mx, sx + s.len()),
|
Union::Str(ref s, ..) => (ax + 1, mx, sx + s.len()),
|
||||||
@ -44,13 +44,13 @@ impl Engine {
|
|||||||
.fold((0, 0, 0), |(ax, mx, sx), value| match value.0 {
|
.fold((0, 0, 0), |(ax, mx, sx), value| match value.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(..) => {
|
Union::Array(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = value.calc_data_sizes(false);
|
||||||
(ax + a, mx + m + 1, sx + s)
|
(ax + a, mx + m + 1, sx + s)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(ref a, ..) => (ax + a.len(), mx, sx),
|
Union::Blob(ref a, ..) => (ax + a.len(), mx, sx),
|
||||||
Union::Map(..) => {
|
Union::Map(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = value.calc_data_sizes(false);
|
||||||
(ax + a, mx + m + 1, sx + s)
|
(ax + a, mx + m + 1, sx + s)
|
||||||
}
|
}
|
||||||
Union::Str(ref s, ..) => (ax, mx + 1, sx + s.len()),
|
Union::Str(ref s, ..) => (ax, mx + 1, sx + s.len()),
|
||||||
@ -59,17 +59,17 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
Union::Str(ref s, ..) => (0, 0, s.len()),
|
Union::Str(ref s, ..) => (0, 0, s.len()),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(..) if _top => {
|
Union::Shared(..) if _top => self.read_lock::<Self>().unwrap().calc_data_sizes(true),
|
||||||
Self::calc_data_sizes(&*value.read_lock::<Dynamic>().unwrap(), true)
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(..) => {
|
Union::Shared(..) => {
|
||||||
unreachable!("shared values discovered within data: {}", value)
|
unreachable!("shared values discovered within data: {}", self)
|
||||||
}
|
}
|
||||||
_ => (0, 0, 0),
|
_ => (0, 0, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
/// Raise an error if any data size exceeds limit.
|
/// Raise an error if any data size exceeds limit.
|
||||||
///
|
///
|
||||||
/// [`Position`] in [`EvalAltResult`][crate::EvalAltResult] is always [`NONE`][Position::NONE]
|
/// [`Position`] in [`EvalAltResult`][crate::EvalAltResult] is always [`NONE`][Position::NONE]
|
||||||
@ -125,7 +125,7 @@ impl Engine {
|
|||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sizes = Self::calc_data_sizes(value.borrow(), true);
|
let sizes = value.borrow().calc_data_sizes(true);
|
||||||
|
|
||||||
self.raise_err_if_over_data_size_limit(sizes)
|
self.raise_err_if_over_data_size_limit(sizes)
|
||||||
.map(|_| value)
|
.map(|_| value)
|
||||||
|
@ -193,7 +193,7 @@ impl BreakPoint {
|
|||||||
/// Is this [`BreakPoint`] enabled?
|
/// Is this [`BreakPoint`] enabled?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_enabled(&self) -> bool {
|
pub const fn is_enabled(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
Self::AtPosition { enabled, .. } => *enabled,
|
Self::AtPosition { enabled, .. } => *enabled,
|
||||||
@ -268,7 +268,7 @@ impl Debugger {
|
|||||||
/// Create a new [`Debugger`].
|
/// Create a new [`Debugger`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(status: DebuggerStatus, state: Dynamic) -> Self {
|
pub const fn new(status: DebuggerStatus, state: Dynamic) -> Self {
|
||||||
Self {
|
Self {
|
||||||
status,
|
status,
|
||||||
break_points: Vec::new(),
|
break_points: Vec::new(),
|
||||||
@ -297,7 +297,7 @@ impl Debugger {
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
) {
|
) {
|
||||||
self.call_stack.push(CallStackFrame {
|
self.call_stack.push(CallStackFrame {
|
||||||
fn_name: fn_name.into(),
|
fn_name,
|
||||||
args,
|
args,
|
||||||
source,
|
source,
|
||||||
pos,
|
pos,
|
||||||
@ -419,7 +419,7 @@ impl Engine {
|
|||||||
if let Some(cmd) =
|
if let Some(cmd) =
|
||||||
self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node)?
|
self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node)?
|
||||||
{
|
{
|
||||||
global.debugger.status = cmd;
|
global.debugger_mut().status = cmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,27 +469,28 @@ impl Engine {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let event = match global.debugger.status {
|
if let Some(ref dbg) = global.debugger {
|
||||||
|
let event = match dbg.status {
|
||||||
DebuggerStatus::Init => Some(DebuggerEvent::Start),
|
DebuggerStatus::Init => Some(DebuggerEvent::Start),
|
||||||
DebuggerStatus::CONTINUE => None,
|
DebuggerStatus::NEXT if node.is_stmt() => Some(DebuggerEvent::Step),
|
||||||
DebuggerStatus::NEXT if matches!(node, ASTNode::Stmt(..)) => Some(DebuggerEvent::Step),
|
DebuggerStatus::INTO if node.is_expr() => Some(DebuggerEvent::Step),
|
||||||
DebuggerStatus::NEXT => None,
|
|
||||||
DebuggerStatus::INTO if matches!(node, ASTNode::Expr(..)) => Some(DebuggerEvent::Step),
|
|
||||||
DebuggerStatus::INTO => None,
|
|
||||||
DebuggerStatus::STEP => Some(DebuggerEvent::Step),
|
DebuggerStatus::STEP => Some(DebuggerEvent::Step),
|
||||||
DebuggerStatus::FunctionExit(..) => None,
|
|
||||||
DebuggerStatus::Terminate => Some(DebuggerEvent::End),
|
DebuggerStatus::Terminate => Some(DebuggerEvent::End),
|
||||||
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let event = match event {
|
let event = match event {
|
||||||
Some(e) => e,
|
Some(e) => e,
|
||||||
None => match global.debugger.is_break_point(global.source(), node) {
|
None => match dbg.is_break_point(global.source(), node) {
|
||||||
Some(bp) => DebuggerEvent::BreakPoint(bp),
|
Some(bp) => DebuggerEvent::BreakPoint(bp),
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
self.run_debugger_raw(global, caches, scope, this_ptr, node, event)
|
self.run_debugger_raw(global, caches, scope, this_ptr, node, event)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Run the debugger callback unconditionally.
|
/// Run the debugger callback unconditionally.
|
||||||
///
|
///
|
||||||
@ -511,24 +512,26 @@ impl Engine {
|
|||||||
let src = src.as_ref().map(|s| s.as_str());
|
let src = src.as_ref().map(|s| s.as_str());
|
||||||
let context = crate::EvalContext::new(self, global, caches, scope, this_ptr);
|
let context = crate::EvalContext::new(self, global, caches, scope, this_ptr);
|
||||||
|
|
||||||
if let Some((.., ref on_debugger)) = self.debugger {
|
if let Some(ref x) = self.debugger {
|
||||||
|
let (.., ref on_debugger) = **x;
|
||||||
|
|
||||||
let command = on_debugger(context, event, node, src, node.position())?;
|
let command = on_debugger(context, event, node, src, node.position())?;
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
DebuggerCommand::Continue => {
|
DebuggerCommand::Continue => {
|
||||||
global.debugger.status = DebuggerStatus::CONTINUE;
|
global.debugger_mut().status = DebuggerStatus::CONTINUE;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
DebuggerCommand::Next => {
|
DebuggerCommand::Next => {
|
||||||
global.debugger.status = DebuggerStatus::CONTINUE;
|
global.debugger_mut().status = DebuggerStatus::CONTINUE;
|
||||||
Ok(Some(DebuggerStatus::NEXT))
|
Ok(Some(DebuggerStatus::NEXT))
|
||||||
}
|
}
|
||||||
DebuggerCommand::StepOver => {
|
DebuggerCommand::StepOver => {
|
||||||
global.debugger.status = DebuggerStatus::CONTINUE;
|
global.debugger_mut().status = DebuggerStatus::CONTINUE;
|
||||||
Ok(Some(DebuggerStatus::STEP))
|
Ok(Some(DebuggerStatus::STEP))
|
||||||
}
|
}
|
||||||
DebuggerCommand::StepInto => {
|
DebuggerCommand::StepInto => {
|
||||||
global.debugger.status = DebuggerStatus::STEP;
|
global.debugger_mut().status = DebuggerStatus::STEP;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
DebuggerCommand::FunctionExit => {
|
DebuggerCommand::FunctionExit => {
|
||||||
@ -542,7 +545,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
_ => global.level,
|
_ => global.level,
|
||||||
};
|
};
|
||||||
global.debugger.status = DebuggerStatus::FunctionExit(level);
|
global.debugger_mut().status = DebuggerStatus::FunctionExit(level);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,8 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
|
|||||||
/// Get a mutable reference to the current [`Scope`].
|
/// Get a mutable reference to the current [`Scope`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn scope_mut(&mut self) -> &mut &'s mut Scope<'ps> {
|
pub fn scope_mut(&mut self) -> &mut Scope<'ps> {
|
||||||
&mut self.scope
|
self.scope
|
||||||
}
|
}
|
||||||
/// Get an iterator over the current set of modules imported via `import` statements,
|
/// Get an iterator over the current set of modules imported via `import` statements,
|
||||||
/// in reverse order (i.e. modules imported last come first).
|
/// in reverse order (i.e. modules imported last come first).
|
||||||
@ -105,7 +105,7 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
|
pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
|
||||||
self.global.lib.iter().map(|m| m.as_ref())
|
self.global.lib.iter().map(AsRef::as_ref)
|
||||||
}
|
}
|
||||||
/// _(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.
|
||||||
|
@ -36,7 +36,12 @@ impl Engine {
|
|||||||
|
|
||||||
// Do a text-match search if the index doesn't work
|
// Do a text-match search if the index doesn't work
|
||||||
global.find_import(root).map_or_else(
|
global.find_import(root).map_or_else(
|
||||||
|| self.global_sub_modules.get(root).cloned(),
|
|| {
|
||||||
|
self.global_sub_modules
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|m| m.get(root))
|
||||||
|
.cloned()
|
||||||
|
},
|
||||||
|offset| global.get_shared_import(offset),
|
|offset| global.get_shared_import(offset),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -156,7 +161,7 @@ impl Engine {
|
|||||||
.any(|(_, _, f, ..)| f == v.3.as_str()) =>
|
.any(|(_, _, f, ..)| f == v.3.as_str()) =>
|
||||||
{
|
{
|
||||||
let val: Dynamic =
|
let val: Dynamic =
|
||||||
crate::FnPtr::new_unchecked(v.3.as_str(), Default::default()).into();
|
crate::FnPtr::new_unchecked(v.3.as_str(), crate::StaticVec::default()).into();
|
||||||
return Ok(val.into());
|
return Ok(val.into());
|
||||||
}
|
}
|
||||||
Expr::Variable(v, None, ..) => v.0.map_or(0, NonZeroUsize::get),
|
Expr::Variable(v, None, ..) => v.0.map_or(0, NonZeroUsize::get),
|
||||||
@ -186,14 +191,20 @@ impl Engine {
|
|||||||
match scope.search(var_name) {
|
match scope.search(var_name) {
|
||||||
Some(index) => index,
|
Some(index) => index,
|
||||||
None => {
|
None => {
|
||||||
return match self.global_modules.iter().find_map(|m| m.get_var(var_name)) {
|
return self
|
||||||
Some(val) => Ok(val.into()),
|
.global_modules
|
||||||
None => Err(ERR::ErrorVariableNotFound(
|
.iter()
|
||||||
|
.find_map(|m| m.get_var(var_name))
|
||||||
|
.map_or_else(
|
||||||
|
|| {
|
||||||
|
Err(ERR::ErrorVariableNotFound(
|
||||||
var_name.to_string(),
|
var_name.to_string(),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
)
|
)
|
||||||
.into()),
|
.into())
|
||||||
}
|
},
|
||||||
|
|val| Ok(val.into()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -221,8 +232,9 @@ impl Engine {
|
|||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?;
|
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?;
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| {
|
let global =
|
||||||
g.debugger.reset_status(reset)
|
&mut *crate::types::RestoreOnDrop::lock_if(reset.is_some(), global, move |g| {
|
||||||
|
g.debugger_mut().reset_status(reset)
|
||||||
});
|
});
|
||||||
|
|
||||||
self.track_operation(global, expr.position())?;
|
self.track_operation(global, expr.position())?;
|
||||||
@ -254,8 +266,9 @@ impl Engine {
|
|||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?;
|
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?;
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| {
|
let global =
|
||||||
g.debugger.reset_status(reset)
|
&mut *crate::types::RestoreOnDrop::lock_if(reset.is_some(), global, move |g| {
|
||||||
|
g.debugger_mut().reset_status(reset)
|
||||||
});
|
});
|
||||||
|
|
||||||
self.track_operation(global, expr.position())?;
|
self.track_operation(global, expr.position())?;
|
||||||
@ -307,7 +320,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if self.has_data_size_limit() {
|
if self.has_data_size_limit() {
|
||||||
let val_sizes = Self::calc_data_sizes(&value, true);
|
let val_sizes = value.calc_data_sizes(true);
|
||||||
|
|
||||||
total_data_sizes = (
|
total_data_sizes = (
|
||||||
total_data_sizes.0 + val_sizes.0,
|
total_data_sizes.0 + val_sizes.0,
|
||||||
@ -339,7 +352,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if self.has_data_size_limit() {
|
if self.has_data_size_limit() {
|
||||||
let delta = Self::calc_data_sizes(&value, true);
|
let delta = value.calc_data_sizes(true);
|
||||||
total_data_sizes = (
|
total_data_sizes = (
|
||||||
total_data_sizes.0 + delta.0,
|
total_data_sizes.0 + delta.0,
|
||||||
total_data_sizes.1 + delta.1,
|
total_data_sizes.1 + delta.1,
|
||||||
@ -393,7 +406,11 @@ impl Engine {
|
|||||||
// The first token acts as the custom syntax's key
|
// The first token acts as the custom syntax's key
|
||||||
let key_token = custom.tokens.first().unwrap();
|
let key_token = custom.tokens.first().unwrap();
|
||||||
// The key should exist, unless the AST is compiled in a different Engine
|
// The key should exist, unless the AST is compiled in a different Engine
|
||||||
let custom_def = self.custom_syntax.get(key_token.as_str()).ok_or_else(|| {
|
let custom_def = self
|
||||||
|
.custom_syntax
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|m| m.get(key_token.as_str()))
|
||||||
|
.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(<_>::to_string).collect(),
|
custom.tokens.iter().map(<_>::to_string).collect(),
|
||||||
@ -411,13 +428,11 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(..) => {
|
Expr::Index(..) => {
|
||||||
self.eval_dot_index_chain(global, caches, scope, this_ptr, expr, &mut None)
|
self.eval_dot_index_chain(global, caches, scope, this_ptr, expr, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(..) => {
|
Expr::Dot(..) => self.eval_dot_index_chain(global, caches, scope, this_ptr, expr, None),
|
||||||
self.eval_dot_index_chain(global, caches, scope, this_ptr, expr, &mut None)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => unreachable!("expression cannot be evaluated: {:?}", expr),
|
_ => unreachable!("expression cannot be evaluated: {:?}", expr),
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,11 @@ pub type GlobalConstants =
|
|||||||
pub struct GlobalRuntimeState {
|
pub struct GlobalRuntimeState {
|
||||||
/// Names of imported [modules][crate::Module].
|
/// Names of imported [modules][crate::Module].
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
imports: crate::StaticVec<ImmutableString>,
|
imports: Option<Box<crate::StaticVec<ImmutableString>>>,
|
||||||
/// Stack of imported [modules][crate::Module].
|
/// Stack of imported [modules][crate::Module].
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: crate::StaticVec<crate::SharedModule>,
|
modules: Option<Box<crate::StaticVec<crate::SharedModule>>>,
|
||||||
|
|
||||||
/// The current stack of loaded [modules][crate::Module] containing script-defined functions.
|
/// The current stack of loaded [modules][crate::Module] containing script-defined functions.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub lib: crate::StaticVec<crate::SharedModule>,
|
pub lib: crate::StaticVec<crate::SharedModule>,
|
||||||
@ -57,9 +58,6 @@ pub struct GlobalRuntimeState {
|
|||||||
///
|
///
|
||||||
/// When that happens, this flag is turned on.
|
/// When that happens, this flag is turned on.
|
||||||
pub always_search_scope: bool,
|
pub always_search_scope: bool,
|
||||||
/// Function call hashes to index getters and setters.
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
fn_hash_indexing: (u64, u64),
|
|
||||||
/// Embedded [module][crate::Module] resolver.
|
/// Embedded [module][crate::Module] resolver.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub embedded_module_resolver:
|
pub embedded_module_resolver:
|
||||||
@ -74,7 +72,7 @@ pub struct GlobalRuntimeState {
|
|||||||
pub tag: Dynamic,
|
pub tag: Dynamic,
|
||||||
/// Debugging interface.
|
/// Debugging interface.
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
pub debugger: super::Debugger,
|
pub(crate) debugger: Option<super::Debugger>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalRuntimeState {
|
impl GlobalRuntimeState {
|
||||||
@ -84,9 +82,9 @@ impl GlobalRuntimeState {
|
|||||||
pub fn new(engine: &Engine) -> Self {
|
pub fn new(engine: &Engine) -> Self {
|
||||||
Self {
|
Self {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
imports: crate::StaticVec::new_const(),
|
imports: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: crate::StaticVec::new_const(),
|
modules: None,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
lib: crate::StaticVec::new_const(),
|
lib: crate::StaticVec::new_const(),
|
||||||
source: None,
|
source: None,
|
||||||
@ -98,11 +96,6 @@ impl GlobalRuntimeState {
|
|||||||
always_search_scope: false,
|
always_search_scope: false,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
embedded_module_resolver: None,
|
embedded_module_resolver: None,
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
fn_hash_indexing: (
|
|
||||||
crate::calc_fn_hash(None, crate::engine::FN_IDX_GET, 2),
|
|
||||||
crate::calc_fn_hash(None, crate::engine::FN_IDX_SET, 3),
|
|
||||||
),
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
constants: None,
|
constants: None,
|
||||||
@ -110,36 +103,28 @@ impl GlobalRuntimeState {
|
|||||||
tag: engine.default_tag().clone(),
|
tag: engine.default_tag().clone(),
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
debugger: crate::eval::Debugger::new(
|
debugger: engine.debugger.as_ref().map(|x| {
|
||||||
if engine.debugger.is_some() {
|
crate::eval::Debugger::new(crate::eval::DebuggerStatus::Init, (x.0)(engine))
|
||||||
crate::eval::DebuggerStatus::Init
|
}),
|
||||||
} else {
|
|
||||||
crate::eval::DebuggerStatus::CONTINUE
|
|
||||||
},
|
|
||||||
match engine.debugger {
|
|
||||||
Some((ref init, ..)) => init(engine),
|
|
||||||
None => Dynamic::UNIT,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get the length of the stack of globally-imported [modules][crate::Module].
|
/// Get the length of the stack of globally-imported [modules][crate::Module].
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn num_imports(&self) -> usize {
|
pub fn num_imports(&self) -> usize {
|
||||||
self.modules.len()
|
self.modules.as_ref().map_or(0, |m| m.len())
|
||||||
}
|
}
|
||||||
/// Get the globally-imported [module][crate::Module] at a particular index.
|
/// Get the globally-imported [module][crate::Module] at a particular index.
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_shared_import(&self, index: usize) -> Option<crate::SharedModule> {
|
pub fn get_shared_import(&self, index: usize) -> Option<crate::SharedModule> {
|
||||||
self.modules.get(index).cloned()
|
self.modules.as_ref().and_then(|m| m.get(index).cloned())
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the globally-imported [module][crate::Module] at a
|
/// Get a mutable reference to the globally-imported [module][crate::Module] at a
|
||||||
/// particular index.
|
/// particular index.
|
||||||
@ -147,13 +132,13 @@ impl GlobalRuntimeState {
|
|||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_shared_import_mut(
|
pub(crate) fn get_shared_import_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> Option<&mut crate::SharedModule> {
|
) -> Option<&mut crate::SharedModule> {
|
||||||
self.modules.get_mut(index)
|
self.modules.as_mut().and_then(|m| m.get_mut(index))
|
||||||
}
|
}
|
||||||
/// Get the index of a globally-imported [module][crate::Module] by name.
|
/// Get the index of a globally-imported [module][crate::Module] by name.
|
||||||
///
|
///
|
||||||
@ -162,33 +147,45 @@ impl GlobalRuntimeState {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn find_import(&self, name: &str) -> Option<usize> {
|
pub fn find_import(&self, name: &str) -> Option<usize> {
|
||||||
self.imports
|
self.imports.as_ref().and_then(|imports| {
|
||||||
|
imports
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.position(|key| key.as_str() == name)
|
.position(|key| key.as_str() == name)
|
||||||
.map(|i| self.imports.len() - 1 - i)
|
.map(|i| imports.len() - 1 - i)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/// Push an imported [module][crate::Module] onto the stack.
|
/// Push an imported [module][crate::Module] onto the stack.
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn push_import(
|
pub fn push_import(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<ImmutableString>,
|
name: impl Into<ImmutableString>,
|
||||||
module: impl Into<crate::SharedModule>,
|
module: impl Into<crate::SharedModule>,
|
||||||
) {
|
) {
|
||||||
self.imports.push(name.into());
|
self.imports
|
||||||
self.modules.push(module.into());
|
.get_or_insert_with(|| crate::StaticVec::new_const().into())
|
||||||
|
.push(name.into());
|
||||||
|
|
||||||
|
self.modules
|
||||||
|
.get_or_insert_with(|| crate::StaticVec::new_const().into())
|
||||||
|
.push(module.into());
|
||||||
}
|
}
|
||||||
/// Truncate the stack of globally-imported [modules][crate::Module] to a particular length.
|
/// Truncate the stack of globally-imported [modules][crate::Module] to a particular length.
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn truncate_imports(&mut self, size: usize) {
|
pub fn truncate_imports(&mut self, size: usize) {
|
||||||
self.imports.truncate(size);
|
if size == 0 {
|
||||||
self.modules.truncate(size);
|
self.imports = None;
|
||||||
|
self.modules = None;
|
||||||
|
} else if self.imports.is_some() {
|
||||||
|
self.imports.as_mut().unwrap().truncate(size);
|
||||||
|
self.modules.as_mut().unwrap().truncate(size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order.
|
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order.
|
||||||
///
|
///
|
||||||
@ -198,8 +195,9 @@ impl GlobalRuntimeState {
|
|||||||
pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &crate::Module)> {
|
pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &crate::Module)> {
|
||||||
self.imports
|
self.imports
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.modules.iter())
|
.flat_map(|x| x.iter())
|
||||||
.rev()
|
.rev()
|
||||||
|
.zip(self.modules.iter().flat_map(|x| x.iter()).rev())
|
||||||
.map(|(name, module)| (name.as_str(), &**module))
|
.map(|(name, module)| (name.as_str(), &**module))
|
||||||
}
|
}
|
||||||
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order.
|
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order.
|
||||||
@ -210,7 +208,11 @@ impl GlobalRuntimeState {
|
|||||||
pub(crate) fn iter_imports_raw(
|
pub(crate) fn iter_imports_raw(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = (&ImmutableString, &crate::SharedModule)> {
|
) -> impl Iterator<Item = (&ImmutableString, &crate::SharedModule)> {
|
||||||
self.imports.iter().zip(self.modules.iter()).rev()
|
self.imports
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.iter())
|
||||||
|
.rev()
|
||||||
|
.zip(self.modules.iter().flat_map(|x| x.iter()).rev())
|
||||||
}
|
}
|
||||||
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order.
|
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order.
|
||||||
///
|
///
|
||||||
@ -220,18 +222,21 @@ impl GlobalRuntimeState {
|
|||||||
pub fn scan_imports_raw(
|
pub fn scan_imports_raw(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = (&ImmutableString, &crate::SharedModule)> {
|
) -> impl Iterator<Item = (&ImmutableString, &crate::SharedModule)> {
|
||||||
self.imports.iter().zip(self.modules.iter())
|
self.imports
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.iter())
|
||||||
|
.zip(self.modules.iter().flat_map(|x| x.iter()))
|
||||||
}
|
}
|
||||||
/// Can the particular function with [`Dynamic`] parameter(s) exist in the stack of
|
/// Can the particular function with [`Dynamic`] parameter(s) exist in the stack of
|
||||||
/// globally-imported [modules][crate::Module]?
|
/// globally-imported [modules][crate::Module]?
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub(crate) fn may_contain_dynamic_fn(&self, hash_script: u64) -> bool {
|
pub(crate) fn may_contain_dynamic_fn(&self, hash_script: u64) -> bool {
|
||||||
self.modules
|
self.modules.as_ref().map_or(false, |m| {
|
||||||
.iter()
|
m.iter().any(|m| m.may_contain_dynamic_fn(hash_script))
|
||||||
.any(|m| m.may_contain_dynamic_fn(hash_script))
|
})
|
||||||
}
|
}
|
||||||
/// Does the specified function hash key exist in the stack of globally-imported
|
/// Does the specified function hash key exist in the stack of globally-imported
|
||||||
/// [modules][crate::Module]?
|
/// [modules][crate::Module]?
|
||||||
@ -242,7 +247,9 @@ impl GlobalRuntimeState {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_qualified_fn(&self, hash: u64) -> bool {
|
pub fn contains_qualified_fn(&self, hash: u64) -> bool {
|
||||||
self.modules.iter().any(|m| m.contains_qualified_fn(hash))
|
self.modules
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.iter().any(|m| m.contains_qualified_fn(hash)))
|
||||||
}
|
}
|
||||||
/// Get the specified function via its hash key from the stack of globally-imported
|
/// Get the specified function via its hash key from the stack of globally-imported
|
||||||
/// [modules][crate::Module].
|
/// [modules][crate::Module].
|
||||||
@ -255,10 +262,11 @@ impl GlobalRuntimeState {
|
|||||||
&self,
|
&self,
|
||||||
hash: u64,
|
hash: u64,
|
||||||
) -> Option<(&crate::func::CallableFunction, Option<&ImmutableString>)> {
|
) -> Option<(&crate::func::CallableFunction, Option<&ImmutableString>)> {
|
||||||
self.modules
|
self.modules.as_ref().and_then(|m| {
|
||||||
.iter()
|
m.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
|
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in the stack of
|
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in the stack of
|
||||||
/// globally-imported [modules][crate::Module]?
|
/// globally-imported [modules][crate::Module]?
|
||||||
@ -269,7 +277,9 @@ impl GlobalRuntimeState {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_iter(&self, id: std::any::TypeId) -> bool {
|
pub fn contains_iter(&self, id: std::any::TypeId) -> bool {
|
||||||
self.modules.iter().any(|m| m.contains_qualified_iter(id))
|
self.modules
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |m| m.iter().any(|m| m.contains_qualified_iter(id)))
|
||||||
}
|
}
|
||||||
/// Get the specified [`TypeId`][std::any::TypeId] iterator from the stack of globally-imported
|
/// Get the specified [`TypeId`][std::any::TypeId] iterator from the stack of globally-imported
|
||||||
/// [modules][crate::Module].
|
/// [modules][crate::Module].
|
||||||
@ -280,9 +290,8 @@ impl GlobalRuntimeState {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_iter(&self, id: std::any::TypeId) -> Option<&crate::func::IteratorFn> {
|
pub fn get_iter(&self, id: std::any::TypeId) -> Option<&crate::func::IteratorFn> {
|
||||||
self.modules
|
self.modules
|
||||||
.iter()
|
.as_ref()
|
||||||
.rev()
|
.and_then(|m| m.iter().rev().find_map(|m| m.get_qualified_iter(id)))
|
||||||
.find_map(|m| m.get_qualified_iter(id))
|
|
||||||
}
|
}
|
||||||
/// Get the current source.
|
/// Get the current source.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -297,19 +306,24 @@ impl GlobalRuntimeState {
|
|||||||
pub(crate) const fn source_raw(&self) -> Option<&ImmutableString> {
|
pub(crate) const fn source_raw(&self) -> Option<&ImmutableString> {
|
||||||
self.source.as_ref()
|
self.source.as_ref()
|
||||||
}
|
}
|
||||||
/// Get the pre-calculated index getter hash.
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
/// Return a reference to the debugging interface.
|
||||||
#[inline(always)]
|
///
|
||||||
#[must_use]
|
/// # Panics
|
||||||
pub(crate) fn hash_idx_get(&mut self) -> u64 {
|
///
|
||||||
self.fn_hash_indexing.0
|
/// Panics if the debugging interface is not set.
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
pub fn debugger(&self) -> &super::Debugger {
|
||||||
|
self.debugger.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
/// Get the pre-calculated index setter hash.
|
/// Return a mutable reference to the debugging interface.
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
///
|
||||||
#[inline(always)]
|
/// # Panics
|
||||||
#[must_use]
|
///
|
||||||
pub(crate) fn hash_idx_set(&mut self) -> u64 {
|
/// Panics if the debugging interface is not set.
|
||||||
self.fn_hash_indexing.1
|
#[cfg(feature = "debugging")]
|
||||||
|
pub fn debugger_mut(&mut self) -> &mut super::Debugger {
|
||||||
|
self.debugger.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,9 +331,16 @@ impl GlobalRuntimeState {
|
|||||||
impl<K: Into<ImmutableString>, M: Into<crate::SharedModule>> Extend<(K, M)> for GlobalRuntimeState {
|
impl<K: Into<ImmutableString>, M: Into<crate::SharedModule>> Extend<(K, M)> for GlobalRuntimeState {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extend<T: IntoIterator<Item = (K, M)>>(&mut self, iter: T) {
|
fn extend<T: IntoIterator<Item = (K, M)>>(&mut self, iter: T) {
|
||||||
|
let imports = self
|
||||||
|
.imports
|
||||||
|
.get_or_insert_with(|| crate::StaticVec::new_const().into());
|
||||||
|
let modules = self
|
||||||
|
.modules
|
||||||
|
.get_or_insert_with(|| crate::StaticVec::new_const().into());
|
||||||
|
|
||||||
for (k, m) in iter {
|
for (k, m) in iter {
|
||||||
self.imports.push(k.into());
|
imports.push(k.into());
|
||||||
self.modules.push(m.into());
|
modules.push(m.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,9 +365,6 @@ impl fmt::Debug for GlobalRuntimeState {
|
|||||||
.field("scope_level", &self.scope_level)
|
.field("scope_level", &self.scope_level)
|
||||||
.field("always_search_scope", &self.always_search_scope);
|
.field("always_search_scope", &self.always_search_scope);
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
f.field("fn_hash_indexing", &self.fn_hash_indexing);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
f.field("constants", &self.constants);
|
f.field("constants", &self.constants);
|
||||||
|
@ -21,7 +21,9 @@ pub use eval_context::EvalContext;
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub use global_state::GlobalConstants;
|
pub use global_state::GlobalConstants;
|
||||||
pub use global_state::GlobalRuntimeState;
|
pub use global_state::GlobalRuntimeState;
|
||||||
pub use target::{calc_index, calc_offset_len, Target};
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
pub use target::calc_offset_len;
|
||||||
|
pub use target::{calc_index, Target};
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
mod unchecked {
|
mod unchecked {
|
||||||
|
@ -194,7 +194,9 @@ impl Engine {
|
|||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, stmt)?;
|
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, stmt)?;
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let global = &mut *RestoreOnDrop::lock(global, move |g| g.debugger.reset_status(reset));
|
let global = &mut *RestoreOnDrop::lock_if(reset.is_some(), global, move |g| {
|
||||||
|
g.debugger_mut().reset_status(reset)
|
||||||
|
});
|
||||||
|
|
||||||
// Coded this way for better branch prediction.
|
// Coded this way for better branch prediction.
|
||||||
// Popular branches are lifted out of the `match` statement into their own branches.
|
// Popular branches are lifted out of the `match` statement into their own branches.
|
||||||
@ -258,7 +260,7 @@ impl Engine {
|
|||||||
rhs_val = self.get_interned_string(value).into();
|
rhs_val = self.get_interned_string(value).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let _new_val = &mut Some((rhs_val, op_info));
|
let _new_val = Some((rhs_val, op_info));
|
||||||
|
|
||||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||||
match lhs {
|
match lhs {
|
||||||
@ -500,7 +502,8 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let func = func.or_else(|| global.get_iter(iter_type)).or_else(|| {
|
let func = func.or_else(|| global.get_iter(iter_type)).or_else(|| {
|
||||||
self.global_sub_modules
|
self.global_sub_modules
|
||||||
.values()
|
.iter()
|
||||||
|
.flat_map(|m| m.values())
|
||||||
.find_map(|m| m.get_qualified_iter(iter_type))
|
.find_map(|m| m.get_qualified_iter(iter_type))
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -533,6 +536,7 @@ impl Engine {
|
|||||||
let index_value = x as INT;
|
let index_value = x as INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[allow(clippy::absurd_extreme_comparisons)]
|
||||||
if index_value > crate::MAX_USIZE_INT {
|
if index_value > crate::MAX_USIZE_INT {
|
||||||
return Err(ERR::ErrorArithmetic(
|
return Err(ERR::ErrorArithmetic(
|
||||||
format!("for-loop counter overflow: {x}"),
|
format!("for-loop counter overflow: {x}"),
|
||||||
@ -764,6 +768,8 @@ impl Engine {
|
|||||||
// Import statement
|
// Import statement
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(x, _pos) => {
|
Stmt::Import(x, _pos) => {
|
||||||
|
use crate::ModuleResolver;
|
||||||
|
|
||||||
let (expr, export) = &**x;
|
let (expr, export) = &**x;
|
||||||
|
|
||||||
// Guard against too many modules
|
// Guard against too many modules
|
||||||
@ -777,8 +783,6 @@ impl Engine {
|
|||||||
self.make_type_mismatch_err::<crate::ImmutableString>(typ, expr.position())
|
self.make_type_mismatch_err::<crate::ImmutableString>(typ, expr.position())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
use crate::ModuleResolver;
|
|
||||||
|
|
||||||
let path_pos = expr.start_position();
|
let path_pos = expr.start_position();
|
||||||
|
|
||||||
let resolver = global.embedded_module_resolver.clone();
|
let resolver = global.embedded_module_resolver.clone();
|
||||||
@ -799,10 +803,10 @@ impl Engine {
|
|||||||
Err(ERR::ErrorModuleNotFound(path.to_string(), path_pos).into())
|
Err(ERR::ErrorModuleNotFound(path.to_string(), path_pos).into())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let (export, must_be_indexed) = if !export.is_empty() {
|
let (export, must_be_indexed) = if export.is_empty() {
|
||||||
(export.name.clone(), true)
|
|
||||||
} else {
|
|
||||||
(self.const_empty_string(), false)
|
(self.const_empty_string(), false)
|
||||||
|
} else {
|
||||||
|
(export.name.clone(), true)
|
||||||
};
|
};
|
||||||
|
|
||||||
if !must_be_indexed || module.is_indexed() {
|
if !must_be_indexed || module.is_indexed() {
|
||||||
@ -824,13 +828,14 @@ impl Engine {
|
|||||||
Stmt::Export(x, ..) => {
|
Stmt::Export(x, ..) => {
|
||||||
let (Ident { name, pos, .. }, Ident { name: alias, .. }) = &**x;
|
let (Ident { name, pos, .. }, Ident { name: alias, .. }) = &**x;
|
||||||
// Mark scope variables as public
|
// Mark scope variables as public
|
||||||
if let Some(index) = scope.search(name) {
|
scope.search(name).map_or_else(
|
||||||
|
|| Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into()),
|
||||||
|
|index| {
|
||||||
let alias = if alias.is_empty() { name } else { alias }.clone();
|
let alias = if alias.is_empty() { name } else { alias }.clone();
|
||||||
scope.add_alias_by_index(index, alias.into());
|
scope.add_alias_by_index(index, alias);
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
} else {
|
},
|
||||||
Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into())
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Share statement
|
// Share statement
|
||||||
@ -838,10 +843,12 @@ impl Engine {
|
|||||||
Stmt::Share(x) => {
|
Stmt::Share(x) => {
|
||||||
x.iter()
|
x.iter()
|
||||||
.try_for_each(|(name, index, pos)| {
|
.try_for_each(|(name, index, pos)| {
|
||||||
if let Some(index) = index
|
index
|
||||||
.map(|n| scope.len() - n.get())
|
.map(|n| scope.len() - n.get())
|
||||||
.or_else(|| scope.search(name))
|
.or_else(|| scope.search(name))
|
||||||
{
|
.map_or_else(
|
||||||
|
|| Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into()),
|
||||||
|
|index| {
|
||||||
let val = scope.get_mut_by_index(index);
|
let val = scope.get_mut_by_index(index);
|
||||||
|
|
||||||
if !val.is_shared() {
|
if !val.is_shared() {
|
||||||
@ -849,9 +856,8 @@ impl Engine {
|
|||||||
*val = std::mem::take(val).into_shared();
|
*val = std::mem::take(val).into_shared();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
},
|
||||||
Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into())
|
)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.map(|_| Dynamic::UNIT)
|
.map(|_| Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,13 @@ use std::{
|
|||||||
/// Negative starting positions count from the end.
|
/// Negative starting positions count from the end.
|
||||||
///
|
///
|
||||||
/// Values going over bounds are limited to the actual length.
|
/// Values going over bounds are limited to the actual length.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(
|
||||||
|
clippy::cast_sign_loss,
|
||||||
|
clippy::absurd_extreme_comparisons,
|
||||||
|
clippy::cast_possible_truncation
|
||||||
|
)]
|
||||||
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 {
|
||||||
let abs_start = start.unsigned_abs();
|
let abs_start = start.unsigned_abs();
|
||||||
@ -47,22 +52,26 @@ pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (us
|
|||||||
/// Values going over bounds call the provided closure to return a default value or an error.
|
/// Values going over bounds call the provided closure to return a default value or an error.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[allow(
|
||||||
|
clippy::cast_sign_loss,
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::absurd_extreme_comparisons
|
||||||
|
)]
|
||||||
pub fn calc_index<E>(
|
pub fn calc_index<E>(
|
||||||
length: usize,
|
length: usize,
|
||||||
start: crate::INT,
|
start: crate::INT,
|
||||||
negative_count_from_end: bool,
|
negative_count_from_end: bool,
|
||||||
err_func: impl FnOnce() -> Result<usize, E>,
|
err_func: impl FnOnce() -> Result<usize, E>,
|
||||||
) -> Result<usize, E> {
|
) -> Result<usize, E> {
|
||||||
if start < 0 {
|
if start < 0 && negative_count_from_end {
|
||||||
if negative_count_from_end {
|
let abs_start = start.unsigned_abs();
|
||||||
let abs_start = start.unsigned_abs() as usize;
|
return Ok(if abs_start as u64 > crate::MAX_USIZE_INT as u64 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
length - usize::min(abs_start as usize, length)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Count from end if negative
|
|
||||||
if abs_start <= length {
|
|
||||||
return Ok(length - abs_start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if start <= crate::MAX_USIZE_INT && (start as usize) < length {
|
if start <= crate::MAX_USIZE_INT && (start as usize) < length {
|
||||||
return Ok(start as usize);
|
return Ok(start as usize);
|
||||||
}
|
}
|
||||||
@ -315,8 +324,11 @@ impl<'a> Target<'a> {
|
|||||||
|
|
||||||
let value = &mut *source.write_lock::<crate::Blob>().expect("`Blob`");
|
let value = &mut *source.write_lock::<crate::Blob>().expect("`Blob`");
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
|
{
|
||||||
value[*index] = (new_byte & 0x00ff) as u8;
|
value[*index] = (new_byte & 0x00ff) as u8;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar {
|
Self::StringChar {
|
||||||
source,
|
source,
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
//! Built-in implementations for common operators.
|
//! Built-in implementations for common operators.
|
||||||
|
|
||||||
|
#![allow(clippy::float_cmp)]
|
||||||
|
|
||||||
use super::call::FnCallArgs;
|
use super::call::FnCallArgs;
|
||||||
use super::native::FnBuiltin;
|
use super::native::FnBuiltin;
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use crate::tokenizer::{Token, Token::*};
|
use crate::tokenizer::{Token, Token::*};
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, NativeCallContext, RhaiResult, INT,
|
Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, NativeCallContext, RhaiResult,
|
||||||
|
SmartString, INT,
|
||||||
};
|
};
|
||||||
use std::any::TypeId;
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
use std::{any::TypeId, fmt::Write};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::FLOAT;
|
use crate::FLOAT;
|
||||||
@ -67,13 +71,11 @@ fn is_numeric(type_id: TypeId) -> bool {
|
|||||||
|
|
||||||
/// A function that returns `true`.
|
/// A function that returns `true`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
fn const_true_fn(_: NativeCallContext, _: &mut [&mut Dynamic]) -> RhaiResult {
|
fn const_true_fn(_: NativeCallContext, _: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
Ok(Dynamic::TRUE)
|
Ok(Dynamic::TRUE)
|
||||||
}
|
}
|
||||||
/// A function that returns `false`.
|
/// A function that returns `false`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
fn const_false_fn(_: NativeCallContext, _: &mut [&mut Dynamic]) -> RhaiResult {
|
fn const_false_fn(_: NativeCallContext, _: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
Ok(Dynamic::FALSE)
|
Ok(Dynamic::FALSE)
|
||||||
}
|
}
|
||||||
@ -142,6 +144,7 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
if type1 == type2 {
|
if type1 == type2 {
|
||||||
if type1 == TypeId::of::<INT>() {
|
if type1 == TypeId::of::<INT>() {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::arithmetic::arith_basic::INT::functions::*;
|
use crate::packages::arithmetic::arith_basic::INT::functions::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -241,7 +244,9 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
let x = args[0].as_char().expect(BUILTIN);
|
let x = args[0].as_char().expect(BUILTIN);
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
|
|
||||||
let result = format!("{x}{y}");
|
let mut result = SmartString::new_const();
|
||||||
|
result.push(x);
|
||||||
|
result.push(y);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
_ctx.engine()
|
_ctx.engine()
|
||||||
@ -337,6 +342,7 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::arithmetic::decimal_functions::builtin::*;
|
use crate::packages::arithmetic::decimal_functions::builtin::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -399,7 +405,10 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
Plus => Some(|_ctx, args| {
|
Plus => Some(|_ctx, args| {
|
||||||
let x = args[0].as_char().expect(BUILTIN);
|
let x = args[0].as_char().expect(BUILTIN);
|
||||||
let y = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
let y = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let result = format!("{x}{y}");
|
|
||||||
|
let mut result = SmartString::new_const();
|
||||||
|
result.push(x);
|
||||||
|
result.push_str(y);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
_ctx.engine()
|
_ctx.engine()
|
||||||
@ -523,25 +532,21 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle ranges here because ranges are implemented as custom type
|
// Handle ranges here because ranges are implemented as custom type
|
||||||
if type1 == TypeId::of::<ExclusiveRange>() {
|
if type1 == TypeId::of::<ExclusiveRange>() && type1 == type2 {
|
||||||
if type1 == type2 {
|
|
||||||
return match op {
|
return match op {
|
||||||
EqualsTo => Some(impl_op!(ExclusiveRange == ExclusiveRange)),
|
EqualsTo => Some(impl_op!(ExclusiveRange == ExclusiveRange)),
|
||||||
NotEqualsTo => Some(impl_op!(ExclusiveRange != ExclusiveRange)),
|
NotEqualsTo => Some(impl_op!(ExclusiveRange != ExclusiveRange)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if type1 == TypeId::of::<InclusiveRange>() {
|
if type1 == TypeId::of::<InclusiveRange>() && type1 == type2 {
|
||||||
if type1 == type2 {
|
|
||||||
return match op {
|
return match op {
|
||||||
EqualsTo => Some(impl_op!(InclusiveRange == InclusiveRange)),
|
EqualsTo => Some(impl_op!(InclusiveRange == InclusiveRange)),
|
||||||
NotEqualsTo => Some(impl_op!(InclusiveRange != InclusiveRange)),
|
NotEqualsTo => Some(impl_op!(InclusiveRange != InclusiveRange)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// One of the operands is a custom type, so it is never built-in
|
// One of the operands is a custom type, so it is never built-in
|
||||||
if x.is_variant() || y.is_variant() {
|
if x.is_variant() || y.is_variant() {
|
||||||
@ -630,6 +635,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
if type1 == type2 {
|
if type1 == type2 {
|
||||||
if type1 == TypeId::of::<INT>() {
|
if type1 == TypeId::of::<INT>() {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::arithmetic::arith_basic::INT::functions::*;
|
use crate::packages::arithmetic::arith_basic::INT::functions::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -679,7 +685,12 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_, args| {
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
let x = &mut *args[0].write_lock::<Dynamic>().expect(BUILTIN);
|
let x = &mut *args[0].write_lock::<Dynamic>().expect(BUILTIN);
|
||||||
Ok((*x = format!("{x}{y}").into()).into())
|
|
||||||
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{y}").unwrap();
|
||||||
|
buf.push(y);
|
||||||
|
|
||||||
|
Ok((*x = buf.into()).into())
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -713,6 +724,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if type1 == TypeId::of::<crate::Array>() {
|
if type1 == TypeId::of::<crate::Array>() {
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::array_basic::array_functions::*;
|
use crate::packages::array_basic::array_functions::*;
|
||||||
use crate::Array;
|
use crate::Array;
|
||||||
|
|
||||||
@ -744,6 +756,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if type1 == TypeId::of::<crate::Blob>() {
|
if type1 == TypeId::of::<crate::Blob>() {
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::blob_basic::blob_functions::*;
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
use crate::Blob;
|
use crate::Blob;
|
||||||
|
|
||||||
@ -794,6 +807,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::arithmetic::decimal_functions::builtin::*;
|
use crate::packages::arithmetic::decimal_functions::builtin::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -880,6 +894,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
// array op= any
|
// array op= any
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if type1 == TypeId::of::<crate::Array>() {
|
if type1 == TypeId::of::<crate::Array>() {
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::array_basic::array_functions::*;
|
use crate::packages::array_basic::array_functions::*;
|
||||||
use crate::Array;
|
use crate::Array;
|
||||||
|
|
||||||
@ -909,6 +924,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
// blob op= int
|
// blob op= int
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<INT>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<INT>()) {
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::blob_basic::blob_functions::*;
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
@ -928,6 +944,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
// blob op= char
|
// blob op= char
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<char>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<char>()) {
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::blob_basic::blob_functions::*;
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
@ -947,6 +964,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
// blob op= string
|
// blob op= string
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<ImmutableString>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<ImmutableString>()) {
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::packages::blob_basic::blob_functions::*;
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
|
@ -90,11 +90,7 @@ impl<'a> ArgBackup<'a> {
|
|||||||
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
|
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn restore_first_arg(&mut self, args: &mut FnCallArgs<'a>) {
|
pub fn restore_first_arg(&mut self, args: &mut FnCallArgs<'a>) {
|
||||||
if let Some(p) = self.orig_mut.take() {
|
args[0] = self.orig_mut.take().expect("`Some`");
|
||||||
args[0] = p;
|
|
||||||
} else {
|
|
||||||
unreachable!("`Some`");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +112,7 @@ pub fn ensure_no_data_race(fn_name: &str, args: &FnCallArgs, is_ref_mut: bool) -
|
|||||||
if let Some((n, ..)) = args
|
if let Some((n, ..)) = args
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(if is_ref_mut { 1 } else { 0 })
|
.skip(usize::from(is_ref_mut))
|
||||||
.find(|(.., a)| a.is_locked())
|
.find(|(.., a)| a.is_locked())
|
||||||
{
|
{
|
||||||
return Err(ERR::ErrorDataRace(
|
return Err(ERR::ErrorDataRace(
|
||||||
@ -216,7 +212,8 @@ impl Engine {
|
|||||||
} else {
|
} else {
|
||||||
func.or_else(|| _global.get_qualified_fn(hash)).or_else(|| {
|
func.or_else(|| _global.get_qualified_fn(hash)).or_else(|| {
|
||||||
self.global_sub_modules
|
self.global_sub_modules
|
||||||
.values()
|
.iter()
|
||||||
|
.flat_map(|m| m.values())
|
||||||
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
|
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@ -256,7 +253,8 @@ impl Engine {
|
|||||||
|| _global.may_contain_dynamic_fn(hash_base)
|
|| _global.may_contain_dynamic_fn(hash_base)
|
||||||
|| self
|
|| self
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.values()
|
.iter()
|
||||||
|
.flat_map(|m| m.values())
|
||||||
.any(|m| m.may_contain_dynamic_fn(hash_base));
|
.any(|m| m.may_contain_dynamic_fn(hash_base));
|
||||||
|
|
||||||
// Set maximum bitmask when there are dynamic versions of the function
|
// Set maximum bitmask when there are dynamic versions of the function
|
||||||
@ -277,7 +275,7 @@ impl Engine {
|
|||||||
Some(token) if token.is_op_assignment() => {
|
Some(token) if token.is_op_assignment() => {
|
||||||
let (first_arg, rest_args) = args.split_first().unwrap();
|
let (first_arg, rest_args) = args.split_first().unwrap();
|
||||||
|
|
||||||
get_builtin_op_assignment_fn(token, *first_arg, rest_args[0])
|
get_builtin_op_assignment_fn(token, first_arg, rest_args[0])
|
||||||
.map(|f| FnResolutionCacheEntry {
|
.map(|f| FnResolutionCacheEntry {
|
||||||
func: CallableFunction::Method(Shared::new(f)),
|
func: CallableFunction::Method(Shared::new(f)),
|
||||||
source: None,
|
source: None,
|
||||||
@ -344,7 +342,7 @@ impl Engine {
|
|||||||
name: &str,
|
name: &str,
|
||||||
op_token: Option<&Token>,
|
op_token: Option<&Token>,
|
||||||
hash: u64,
|
hash: u64,
|
||||||
mut args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref_mut: bool,
|
is_ref_mut: bool,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
@ -368,7 +366,10 @@ impl Engine {
|
|||||||
|
|
||||||
// Push a new call stack frame
|
// Push a new call stack frame
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let orig_call_stack_len = global.debugger.call_stack().len();
|
let orig_call_stack_len = global
|
||||||
|
.debugger
|
||||||
|
.as_ref()
|
||||||
|
.map_or(0, |dbg| dbg.call_stack().len());
|
||||||
|
|
||||||
let backup = &mut ArgBackup::new();
|
let backup = &mut ArgBackup::new();
|
||||||
|
|
||||||
@ -381,14 +382,16 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let args =
|
let args =
|
||||||
&mut *RestoreOnDrop::lock_if(swap, &mut args, move |a| backup.restore_first_arg(a));
|
&mut *RestoreOnDrop::lock_if(swap, args, move |a| backup.restore_first_arg(a));
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
if self.debugger.is_some() {
|
if self.debugger.is_some() {
|
||||||
global.debugger.push_call_stack_frame(
|
let source = source.clone().or_else(|| global.source.clone());
|
||||||
|
|
||||||
|
global.debugger_mut().push_call_stack_frame(
|
||||||
self.get_interned_string(name),
|
self.get_interned_string(name),
|
||||||
args.iter().map(|v| (*v).clone()).collect(),
|
args.iter().map(|v| (*v).clone()).collect(),
|
||||||
source.clone().or_else(|| global.source.clone()),
|
source,
|
||||||
pos,
|
pos,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -414,16 +417,16 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
{
|
if self.debugger.is_some() {
|
||||||
use crate::eval::{DebuggerEvent, DebuggerStatus};
|
use crate::eval::{DebuggerEvent, DebuggerStatus};
|
||||||
|
|
||||||
let trigger = match global.debugger.status {
|
let trigger = match global.debugger().status {
|
||||||
DebuggerStatus::FunctionExit(n) => n >= global.level,
|
DebuggerStatus::FunctionExit(n) => n >= global.level,
|
||||||
DebuggerStatus::Next(.., true) => true,
|
DebuggerStatus::Next(.., true) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if trigger {
|
if trigger {
|
||||||
let scope = &mut &mut Scope::new();
|
let scope = &mut Scope::new();
|
||||||
let mut this = Dynamic::NULL;
|
let mut this = Dynamic::NULL;
|
||||||
let node = crate::ast::Stmt::Noop(pos);
|
let node = crate::ast::Stmt::Noop(pos);
|
||||||
let node = (&node).into();
|
let node = (&node).into();
|
||||||
@ -440,7 +443,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pop the call stack
|
// Pop the call stack
|
||||||
global.debugger.rewind_call_stack(orig_call_stack_len);
|
global.debugger_mut().rewind_call_stack(orig_call_stack_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = _result?;
|
let result = _result?;
|
||||||
@ -597,12 +600,13 @@ impl Engine {
|
|||||||
let num_params = _args[1].as_int().expect("`INT`");
|
let num_params = _args[1].as_int().expect("`INT`");
|
||||||
|
|
||||||
return Ok((
|
return Ok((
|
||||||
if num_params < 0 || num_params > crate::MAX_USIZE_INT {
|
if (0..=crate::MAX_USIZE_INT).contains(&num_params) {
|
||||||
false
|
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||||
} else {
|
|
||||||
let hash_script =
|
let hash_script =
|
||||||
calc_fn_hash(None, fn_name.as_str(), num_params as usize);
|
calc_fn_hash(None, fn_name.as_str(), num_params as usize);
|
||||||
self.has_script_fn(global, caches, hash_script)
|
self.has_script_fn(global, caches, hash_script)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
false,
|
false,
|
||||||
@ -647,12 +651,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut empty_scope;
|
let mut empty_scope;
|
||||||
let scope = match _scope {
|
let scope = if let Some(scope) = _scope {
|
||||||
Some(scope) => scope,
|
scope
|
||||||
None => {
|
} else {
|
||||||
empty_scope = Scope::new();
|
empty_scope = Scope::new();
|
||||||
&mut empty_scope
|
&mut empty_scope
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let orig_source = mem::replace(&mut global.source, source.clone());
|
let orig_source = mem::replace(&mut global.source, source.clone());
|
||||||
@ -676,7 +679,7 @@ impl Engine {
|
|||||||
backup.change_first_arg_to_copy(_args);
|
backup.change_first_arg_to_copy(_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = &mut *RestoreOnDrop::lock_if(swap, &mut _args, move |a| {
|
let args = &mut *RestoreOnDrop::lock_if(swap, _args, move |a| {
|
||||||
backup.restore_first_arg(a)
|
backup.restore_first_arg(a)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -718,11 +721,15 @@ impl Engine {
|
|||||||
|
|
||||||
// Do not match function exit for arguments
|
// Do not match function exit for arguments
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset = global.debugger.clear_status_if(|status| {
|
let reset = global.debugger.as_mut().and_then(|dbg| {
|
||||||
|
dbg.clear_status_if(|status| {
|
||||||
matches!(status, crate::eval::DebuggerStatus::FunctionExit(..))
|
matches!(status, crate::eval::DebuggerStatus::FunctionExit(..))
|
||||||
|
})
|
||||||
});
|
});
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let global = &mut *RestoreOnDrop::lock(global, move |g| g.debugger.reset_status(reset));
|
let global = &mut *RestoreOnDrop::lock_if(reset.is_some(), global, move |g| {
|
||||||
|
g.debugger_mut().reset_status(reset)
|
||||||
|
});
|
||||||
|
|
||||||
self.eval_expr(global, caches, scope, this_ptr, arg_expr)
|
self.eval_expr(global, caches, scope, this_ptr, arg_expr)
|
||||||
.map(|r| (r, arg_expr.start_position()))
|
.map(|r| (r, arg_expr.start_position()))
|
||||||
@ -901,7 +908,7 @@ impl Engine {
|
|||||||
call_args = &mut _arg_values;
|
call_args = &mut _arg_values;
|
||||||
}
|
}
|
||||||
// Recalculate the hash based on the new function name and new arguments
|
// Recalculate the hash based on the new function name and new arguments
|
||||||
hash = if !is_anon && !is_valid_function_name(&fn_name) {
|
hash = if !is_anon && !is_valid_function_name(fn_name) {
|
||||||
FnCallHashes::from_native(calc_fn_hash(
|
FnCallHashes::from_native(calc_fn_hash(
|
||||||
None,
|
None,
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -963,7 +970,7 @@ impl Engine {
|
|||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let mut first_arg = first_arg;
|
let mut first_arg = first_arg;
|
||||||
let mut a_expr = args_expr;
|
let mut a_expr = args_expr;
|
||||||
let mut total_args = if first_arg.is_some() { 1 } else { 0 } + a_expr.len();
|
let mut total_args = usize::from(first_arg.is_some()) + a_expr.len();
|
||||||
let mut curry = FnArgsVec::new_const();
|
let mut curry = FnArgsVec::new_const();
|
||||||
let mut name = fn_name;
|
let mut name = fn_name;
|
||||||
let mut hashes = hashes;
|
let mut hashes = hashes;
|
||||||
@ -1077,9 +1084,10 @@ impl Engine {
|
|||||||
.as_int()
|
.as_int()
|
||||||
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?;
|
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?;
|
||||||
|
|
||||||
return Ok(if num_params < 0 || num_params > crate::MAX_USIZE_INT {
|
return Ok(if !(0..=crate::MAX_USIZE_INT).contains(&num_params) {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
let hash_script = calc_fn_hash(None, &fn_name, num_params as usize);
|
let hash_script = calc_fn_hash(None, &fn_name, num_params as usize);
|
||||||
self.has_script_fn(global, caches, hash_script)
|
self.has_script_fn(global, caches, hash_script)
|
||||||
}
|
}
|
||||||
@ -1437,7 +1445,7 @@ impl Engine {
|
|||||||
// No optimizations because we only run it once
|
// No optimizations because we only run it once
|
||||||
let ast = self.compile_with_scope_and_optimization_level(
|
let ast = self.compile_with_scope_and_optimization_level(
|
||||||
&Scope::new(),
|
&Scope::new(),
|
||||||
&[script],
|
[script],
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
|
@ -132,9 +132,7 @@ impl CallableFunction {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(..) | Self::Method(..) => true,
|
Self::Pure(..) | Self::Method(..) | Self::Plugin(..) | Self::Iterator(..) => true,
|
||||||
Self::Plugin(..) => true,
|
|
||||||
Self::Iterator(..) => true,
|
|
||||||
Self::Script(..) => false,
|
Self::Script(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,8 +145,9 @@ impl CallableFunction {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
match self {
|
match self {
|
||||||
Self::Plugin(..) => FnAccess::Public,
|
Self::Plugin(..) | Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => {
|
||||||
Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => FnAccess::Public,
|
FnAccess::Public
|
||||||
|
}
|
||||||
Self::Script(f) => f.access,
|
Self::Script(f) => f.access,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,6 @@ pub trait Func<ARGS, RET> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
|
||||||
fn create_from_script(self, script: &str, entry_point: &str) -> ParseResult<Self::Output>;
|
fn create_from_script(self, script: &str, entry_point: &str) -> ParseResult<Self::Output>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_with_all_fields(
|
pub const fn new_with_all_fields(
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
fn_name: &'a str,
|
fn_name: &'a str,
|
||||||
source: Option<&'a str>,
|
source: Option<&'a str>,
|
||||||
@ -182,7 +182,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
fn_name: &context.fn_name,
|
fn_name: &context.fn_name,
|
||||||
source: context.source.as_ref().map(String::as_str),
|
source: context.source.as_deref(),
|
||||||
global: &context.global,
|
global: &context.global,
|
||||||
pos: context.pos,
|
pos: context.pos,
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
/// Custom state kept in a [`Dynamic`].
|
/// Custom state kept in a [`Dynamic`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tag(&self) -> Option<&Dynamic> {
|
pub const fn tag(&self) -> Option<&Dynamic> {
|
||||||
Some(&self.global.tag)
|
Some(&self.global.tag)
|
||||||
}
|
}
|
||||||
/// Get an iterator over the current set of modules imported via `import` statements
|
/// Get an iterator over the current set of modules imported via `import` statements
|
||||||
@ -278,7 +278,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
|
pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
|
||||||
self.global.lib.iter().map(|m| m.as_ref())
|
self.global.lib.iter().map(AsRef::as_ref)
|
||||||
}
|
}
|
||||||
/// _(internals)_ The current stack of namespaces containing definitions of all script-defined functions.
|
/// _(internals)_ The current stack of namespaces containing definitions of all script-defined functions.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
|
@ -83,7 +83,10 @@ impl Engine {
|
|||||||
let orig_imports_len = global.num_imports();
|
let orig_imports_len = global.num_imports();
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let orig_call_stack_len = global.debugger.call_stack().len();
|
let orig_call_stack_len = global
|
||||||
|
.debugger
|
||||||
|
.as_ref()
|
||||||
|
.map_or(0, |dbg| dbg.call_stack().len());
|
||||||
|
|
||||||
// Put arguments into scope as variables
|
// Put arguments into scope as variables
|
||||||
scope.extend(fn_def.params.iter().cloned().zip(args.iter_mut().map(|v| {
|
scope.extend(fn_def.params.iter().cloned().zip(args.iter_mut().map(|v| {
|
||||||
@ -94,10 +97,12 @@ impl Engine {
|
|||||||
// Push a new call stack frame
|
// Push a new call stack frame
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
if self.debugger.is_some() {
|
if self.debugger.is_some() {
|
||||||
global.debugger.push_call_stack_frame(
|
let source = global.source.clone();
|
||||||
|
|
||||||
|
global.debugger_mut().push_call_stack_frame(
|
||||||
fn_def.name.clone(),
|
fn_def.name.clone(),
|
||||||
scope.iter().skip(orig_scope_len).map(|(.., v)| v).collect(),
|
scope.iter().skip(orig_scope_len).map(|(.., v)| v).collect(),
|
||||||
global.source.clone(),
|
source,
|
||||||
pos,
|
pos,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -126,7 +131,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
{
|
if self.debugger.is_some() {
|
||||||
let node = crate::ast::Stmt::Noop(fn_def.body.position());
|
let node = crate::ast::Stmt::Noop(fn_def.body.position());
|
||||||
self.run_debugger(global, caches, scope, this_ptr, &node)?;
|
self.run_debugger(global, caches, scope, this_ptr, &node)?;
|
||||||
}
|
}
|
||||||
@ -156,12 +161,13 @@ impl Engine {
|
|||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
{
|
if self.debugger.is_some() {
|
||||||
let trigger = match global.debugger.status {
|
let trigger = match global.debugger_mut().status {
|
||||||
crate::eval::DebuggerStatus::FunctionExit(n) => n >= global.level,
|
crate::eval::DebuggerStatus::FunctionExit(n) => n >= global.level,
|
||||||
crate::eval::DebuggerStatus::Next(.., true) => true,
|
crate::eval::DebuggerStatus::Next(.., true) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if trigger {
|
if trigger {
|
||||||
let node = crate::ast::Stmt::Noop(fn_def.body.end_position().or_else(pos));
|
let node = crate::ast::Stmt::Noop(fn_def.body.end_position().or_else(pos));
|
||||||
let node = (&node).into();
|
let node = (&node).into();
|
||||||
@ -176,7 +182,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pop the call stack
|
// Pop the call stack
|
||||||
global.debugger.rewind_call_stack(orig_call_stack_len);
|
global
|
||||||
|
.debugger
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.rewind_call_stack(orig_call_stack_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all local variables and imported modules
|
// Remove all local variables and imported modules
|
||||||
@ -226,7 +236,7 @@ impl Engine {
|
|||||||
// Then check imported modules
|
// Then check imported modules
|
||||||
global.contains_qualified_fn(hash_script)
|
global.contains_qualified_fn(hash_script)
|
||||||
// Then check sub-modules
|
// Then check sub-modules
|
||||||
|| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash_script));
|
|| self.global_sub_modules.iter().flat_map(|m| m.values()).any(|m| m.contains_qualified_fn(hash_script));
|
||||||
|
|
||||||
if !result && !cache.filter.is_absent_and_set(hash_script) {
|
if !result && !cache.filter.is_absent_and_set(hash_script) {
|
||||||
// Do not cache "one-hit wonders"
|
// Do not cache "one-hit wonders"
|
||||||
|
@ -65,11 +65,15 @@
|
|||||||
// #![warn(clippy::undocumented_unsafe_blocks)]
|
// #![warn(clippy::undocumented_unsafe_blocks)]
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
#![allow(clippy::missing_errors_doc)]
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
#![allow(clippy::missing_panics_doc)]
|
||||||
#![allow(clippy::used_underscore_binding)]
|
#![allow(clippy::used_underscore_binding)]
|
||||||
#![allow(clippy::inline_always)]
|
#![allow(clippy::inline_always)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(clippy::module_name_repetitions)]
|
||||||
#![allow(clippy::negative_feature_names)]
|
#![allow(clippy::negative_feature_names)]
|
||||||
#![allow(clippy::module_inception)]
|
#![allow(clippy::module_inception)]
|
||||||
|
#![allow(clippy::box_collection)]
|
||||||
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
#![allow(clippy::upper_case_acronyms)]
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@ use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT,
|
|||||||
use crate::eval::{Caches, GlobalRuntimeState};
|
use crate::eval::{Caches, GlobalRuntimeState};
|
||||||
use crate::func::builtin::get_builtin_binary_op_fn;
|
use crate::func::builtin::get_builtin_binary_op_fn;
|
||||||
use crate::func::hashing::get_hasher;
|
use crate::func::hashing::get_hasher;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::types::dynamic::AccessMode;
|
use crate::types::dynamic::AccessMode;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -168,7 +169,7 @@ fn has_native_fn_override(
|
|||||||
if engine
|
if engine
|
||||||
.global_modules
|
.global_modules
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|m| !m.standard)
|
.filter(|m| !m.flags.contains(ModuleFlags::STANDARD_LIB))
|
||||||
.any(|m| m.contains_fn(hash))
|
.any(|m| m.contains_fn(hash))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -178,7 +179,8 @@ fn has_native_fn_override(
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if engine
|
if engine
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.values()
|
.iter()
|
||||||
|
.flat_map(|m| m.values())
|
||||||
.any(|m| m.contains_qualified_fn(hash))
|
.any(|m| m.contains_qualified_fn(hash))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, Position, RhaiError, RhaiResultOf, ERR, INT};
|
use crate::{def_package, Position, RhaiError, RhaiResultOf, ERR, INT};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -192,7 +193,7 @@ macro_rules! reg_functions {
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Basic arithmetic package.
|
/// Basic arithmetic package.
|
||||||
pub ArithmeticPackage(lib) {
|
pub ArithmeticPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "int", int_functions);
|
combine_with_exported_module!(lib, "int", int_functions);
|
||||||
reg_functions!(lib += signed_basic; INT);
|
reg_functions!(lib += signed_basic; INT);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use crate::engine::OP_EQUALS;
|
use crate::engine::OP_EQUALS;
|
||||||
use crate::eval::{calc_index, calc_offset_len};
|
use crate::eval::{calc_index, calc_offset_len};
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext,
|
def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext,
|
||||||
@ -14,7 +15,7 @@ use std::{any::TypeId, cmp::Ordering, mem};
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic array utilities.
|
/// Package of basic array utilities.
|
||||||
pub BasicArrayPackage(lib) {
|
pub BasicArrayPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "array", array_functions);
|
combine_with_exported_module!(lib, "array", array_functions);
|
||||||
|
|
||||||
@ -229,6 +230,8 @@ pub mod array_functions {
|
|||||||
// Check if array will be over max size limit
|
// Check if array will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
|
use crate::types::dynamic::Union;
|
||||||
|
|
||||||
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
|
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
|
||||||
return Err(
|
return Err(
|
||||||
ERR::ErrorDataTooLarge("Size of array".to_string(), Position::NONE).into(),
|
ERR::ErrorDataTooLarge("Size of array".to_string(), Position::NONE).into(),
|
||||||
@ -236,10 +239,10 @@ pub mod array_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let check_sizes = match item.0 {
|
let check_sizes = match item.0 {
|
||||||
crate::types::dynamic::Union::Str(..) => true,
|
Union::Str(..) => true,
|
||||||
crate::types::dynamic::Union::Array(..) => true,
|
Union::Array(..) => true,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
crate::types::dynamic::Union::Map(..) => true,
|
Union::Map(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,8 +250,8 @@ pub mod array_functions {
|
|||||||
let mut arr_len = array.len();
|
let mut arr_len = array.len();
|
||||||
let mut arr = Dynamic::from_array(mem::take(array));
|
let mut arr = Dynamic::from_array(mem::take(array));
|
||||||
|
|
||||||
let (mut a1, mut m1, mut s1) = crate::Engine::calc_data_sizes(&arr, true);
|
let (mut a1, mut m1, mut s1) = arr.calc_data_sizes(true);
|
||||||
let (a2, m2, s2) = crate::Engine::calc_data_sizes(&item, true);
|
let (a2, m2, s2) = item.calc_data_sizes(true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut guard = arr.write_lock::<Array>().unwrap();
|
let mut guard = arr.write_lock::<Array>().unwrap();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::eval::calc_index;
|
use crate::eval::calc_index;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
def_package, ExclusiveRange, InclusiveRange, Position, RhaiResultOf, ERR, INT, INT_BITS,
|
def_package, ExclusiveRange, InclusiveRange, Position, RhaiResultOf, ERR, INT, INT_BITS,
|
||||||
@ -10,7 +11,7 @@ use std::prelude::v1::*;
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic bit-field utilities.
|
/// Package of basic bit-field utilities.
|
||||||
pub BitFieldPackage(lib) {
|
pub BitFieldPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "bit_field", bit_field_functions);
|
combine_with_exported_module!(lib, "bit_field", bit_field_functions);
|
||||||
}
|
}
|
||||||
@ -142,7 +143,7 @@ mod bit_field_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2^bits - 1
|
// 2^bits - 1
|
||||||
let mask = ((2 as UNSIGNED_INT).pow(bits as u32) - 1) as crate::INT;
|
let mask = ((2 as UNSIGNED_INT).pow(bits as u32) - 1) as INT;
|
||||||
|
|
||||||
Ok(((value & (mask << bit)) >> bit) & mask)
|
Ok(((value & (mask << bit)) >> bit) & mask)
|
||||||
}
|
}
|
||||||
@ -229,7 +230,7 @@ mod bit_field_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2^bits - 1
|
// 2^bits - 1
|
||||||
let mask = ((2 as UNSIGNED_INT).pow(bits as u32) - 1) as crate::INT;
|
let mask = ((2 as UNSIGNED_INT).pow(bits as u32) - 1) as INT;
|
||||||
|
|
||||||
*value &= !(mask << bit);
|
*value &= !(mask << bit);
|
||||||
*value |= (new_value & mask) << bit;
|
*value |= (new_value & mask) << bit;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#![cfg(not(feature = "no_index"))]
|
#![cfg(not(feature = "no_index"))]
|
||||||
|
|
||||||
use crate::eval::{calc_index, calc_offset_len};
|
use crate::eval::{calc_index, calc_offset_len};
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position,
|
def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position,
|
||||||
RhaiResultOf, INT, INT_BYTES, MAX_USIZE_INT,
|
RhaiResultOf, ERR, INT, INT_BYTES, MAX_USIZE_INT,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -16,7 +17,7 @@ use crate::{FLOAT, FLOAT_BYTES};
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic BLOB utilities.
|
/// Package of basic BLOB utilities.
|
||||||
pub BasicBlobPackage(lib) {
|
pub BasicBlobPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "blob", blob_functions);
|
combine_with_exported_module!(lib, "blob", blob_functions);
|
||||||
combine_with_exported_module!(lib, "parse_int", parse_int_functions);
|
combine_with_exported_module!(lib, "parse_int", parse_int_functions);
|
||||||
@ -362,9 +363,7 @@ pub mod blob_functions {
|
|||||||
|
|
||||||
// Check if blob will be over max size limit
|
// Check if blob will be over max size limit
|
||||||
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
|
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
|
||||||
return Err(
|
return Err(ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into());
|
||||||
crate::ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len > blob.len() {
|
if len > blob.len() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![cfg(feature = "debugging")]
|
#![cfg(feature = "debugging")]
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -17,7 +18,7 @@ use crate::Map;
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic debugging utilities.
|
/// Package of basic debugging utilities.
|
||||||
pub DebuggingPackage(lib) {
|
pub DebuggingPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "debugging", debugging_functions);
|
combine_with_exported_module!(lib, "debugging", debugging_functions);
|
||||||
}
|
}
|
||||||
@ -33,16 +34,18 @@ mod debugging_functions {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn back_trace(ctx: NativeCallContext) -> Array {
|
pub fn back_trace(ctx: NativeCallContext) -> Array {
|
||||||
ctx.global_runtime_state()
|
use crate::debugger::CallStackFrame;
|
||||||
.debugger
|
|
||||||
|
if let Some(ref debugger) = ctx.global_runtime_state().debugger {
|
||||||
|
debugger
|
||||||
.call_stack()
|
.call_stack()
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.filter(|crate::debugger::CallStackFrame { fn_name, args, .. }| {
|
.filter(|CallStackFrame { fn_name, args, .. }| {
|
||||||
fn_name.as_str() != "back_trace" || !args.is_empty()
|
fn_name.as_str() != "back_trace" || !args.is_empty()
|
||||||
})
|
})
|
||||||
.map(
|
.map(
|
||||||
|frame @ crate::debugger::CallStackFrame {
|
|frame @ CallStackFrame {
|
||||||
fn_name: _fn_name,
|
fn_name: _fn_name,
|
||||||
args: _args,
|
args: _args,
|
||||||
source: _source,
|
source: _source,
|
||||||
@ -52,20 +55,25 @@ mod debugging_functions {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
let mut map = Map::new();
|
let mut map = Map::new();
|
||||||
map.insert("display".into(), display.into());
|
map.insert("display".into(), display.into());
|
||||||
map.insert("fn_name".into(), _fn_name.into());
|
map.insert("fn_name".into(), _fn_name.into());
|
||||||
if !_args.is_empty() {
|
if !_args.is_empty() {
|
||||||
map.insert("args".into(), Dynamic::from_array(_args.clone().to_vec()));
|
map.insert(
|
||||||
|
"args".into(),
|
||||||
|
Dynamic::from_array(_args.clone().to_vec()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if let Some(source) = _source {
|
if let Some(source) = _source {
|
||||||
map.insert("source".into(), source.into());
|
map.insert("source".into(), source.into());
|
||||||
}
|
}
|
||||||
if !_pos.is_none() {
|
if !_pos.is_none() {
|
||||||
map.insert("line".into(), (_pos.line().unwrap() as crate::INT).into());
|
map.insert("line".into(), (_pos.line().unwrap() as INT).into());
|
||||||
map.insert(
|
map.insert(
|
||||||
"position".into(),
|
"position".into(),
|
||||||
(_pos.position().unwrap_or(0) as crate::INT).into(),
|
(_pos.position().unwrap_or(0) as INT).into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Dynamic::from_map(map)
|
Dynamic::from_map(map)
|
||||||
@ -75,5 +83,8 @@ mod debugging_functions {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.collect()
|
.collect()
|
||||||
|
} else {
|
||||||
|
Array::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, FnPtr, ImmutableString, NativeCallContext};
|
use crate::{def_package, FnPtr, ImmutableString, NativeCallContext};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -6,7 +7,7 @@ use std::prelude::v1::*;
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic function pointer utilities.
|
/// Package of basic function pointer utilities.
|
||||||
pub BasicFnPackage(lib) {
|
pub BasicFnPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "FnPtr", fn_ptr_functions);
|
combine_with_exported_module!(lib, "FnPtr", fn_ptr_functions);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use crate::eval::calc_index;
|
use crate::eval::calc_index;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS, MAX_USIZE_INT,
|
def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, ERR, INT, INT_BITS, MAX_USIZE_INT,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -65,13 +66,10 @@ impl<T: Copy + PartialOrd> StepRange<T> {
|
|||||||
if let Some(n) = add(from, step) {
|
if let Some(n) = add(from, step) {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if n == from {
|
if n == from {
|
||||||
return Err(crate::ERR::ErrorInFunctionCall(
|
return Err(ERR::ErrorInFunctionCall(
|
||||||
"range".to_string(),
|
"range".to_string(),
|
||||||
String::new(),
|
String::new(),
|
||||||
crate::ERR::ErrorArithmetic(
|
ERR::ErrorArithmetic("step value cannot be zero".to_string(), Position::NONE)
|
||||||
"step value cannot be zero".to_string(),
|
|
||||||
Position::NONE,
|
|
||||||
)
|
|
||||||
.into(),
|
.into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
@ -127,7 +125,7 @@ pub struct BitRange(INT, usize);
|
|||||||
impl BitRange {
|
impl BitRange {
|
||||||
pub fn new(value: INT, from: INT, len: INT) -> RhaiResultOf<Self> {
|
pub fn new(value: INT, from: INT, len: INT) -> RhaiResultOf<Self> {
|
||||||
let from = calc_index(INT_BITS, from, true, || {
|
let from = calc_index(INT_BITS, from, true, || {
|
||||||
crate::ERR::ErrorBitFieldBounds(INT_BITS, from, Position::NONE).into()
|
ERR::ErrorBitFieldBounds(INT_BITS, from, Position::NONE).into()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let len = if len < 0 {
|
let len = if len < 0 {
|
||||||
@ -329,7 +327,7 @@ macro_rules! reg_range {
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic range iterators
|
/// Package of basic range iterators
|
||||||
pub BasicIteratorPackage(lib) {
|
pub BasicIteratorPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
reg_range!(lib | "range" => INT);
|
reg_range!(lib | "range" => INT);
|
||||||
|
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::types::dynamic::Tag;
|
use crate::types::dynamic::Tag;
|
||||||
use crate::{Dynamic, RhaiResultOf, ERR, INT};
|
use crate::{Dynamic, RhaiResultOf, ERR, INT};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
use crate::FLOAT;
|
||||||
|
|
||||||
def_package! {
|
def_package! {
|
||||||
/// Package of core language features.
|
/// Package of core language features.
|
||||||
pub LanguageCorePackage(lib) {
|
pub LanguageCorePackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "core", core_functions);
|
combine_with_exported_module!(lib, "core", core_functions);
|
||||||
|
|
||||||
@ -75,10 +79,17 @@ mod core_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Block the current thread for a particular number of `seconds`.
|
/// Block the current thread for a particular number of `seconds`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// // Do nothing for 10 seconds!
|
||||||
|
/// sleep(10.0);
|
||||||
|
/// ```
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[rhai_fn(name = "sleep")]
|
#[rhai_fn(name = "sleep")]
|
||||||
pub fn sleep_float(seconds: crate::FLOAT) {
|
pub fn sleep_float(seconds: FLOAT) {
|
||||||
if seconds <= 0.0 {
|
if seconds <= 0.0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -89,6 +100,13 @@ mod core_functions {
|
|||||||
std::thread::sleep(std::time::Duration::from_secs_f32(seconds));
|
std::thread::sleep(std::time::Duration::from_secs_f32(seconds));
|
||||||
}
|
}
|
||||||
/// Block the current thread for a particular number of `seconds`.
|
/// Block the current thread for a particular number of `seconds`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// // Do nothing for 10 seconds!
|
||||||
|
/// sleep(10);
|
||||||
|
/// ```
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub fn sleep(seconds: INT) {
|
pub fn sleep(seconds: INT) {
|
||||||
if seconds <= 0 {
|
if seconds <= 0 {
|
||||||
@ -120,17 +138,24 @@ mod core_functions {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod reflection_functions {
|
mod reflection_functions {
|
||||||
pub fn get_fn_metadata_list(ctx: NativeCallContext) -> crate::Array {
|
use crate::Array;
|
||||||
|
|
||||||
|
/// Return an array of object maps containing metadata of all script-defined functions.
|
||||||
|
pub fn get_fn_metadata_list(ctx: NativeCallContext) -> Array {
|
||||||
collect_fn_metadata(ctx, |_, _, _, _, _| true)
|
collect_fn_metadata(ctx, |_, _, _, _, _| true)
|
||||||
}
|
}
|
||||||
|
/// Return an array of object maps containing metadata of all script-defined functions
|
||||||
|
/// matching the specified name.
|
||||||
#[rhai_fn(name = "get_fn_metadata_list")]
|
#[rhai_fn(name = "get_fn_metadata_list")]
|
||||||
pub fn get_fn_metadata(ctx: NativeCallContext, name: &str) -> crate::Array {
|
pub fn get_fn_metadata(ctx: NativeCallContext, name: &str) -> Array {
|
||||||
collect_fn_metadata(ctx, |_, _, n, _, _| n == name)
|
collect_fn_metadata(ctx, |_, _, n, _, _| n == name)
|
||||||
}
|
}
|
||||||
|
/// Return an array of object maps containing metadata of all script-defined functions
|
||||||
|
/// matching the specified name and arity (number of parameters).
|
||||||
#[rhai_fn(name = "get_fn_metadata_list")]
|
#[rhai_fn(name = "get_fn_metadata_list")]
|
||||||
pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array {
|
pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> Array {
|
||||||
if params < 0 || params > crate::MAX_USIZE_INT {
|
if params < 0 || params > crate::MAX_USIZE_INT {
|
||||||
crate::Array::new()
|
Array::new()
|
||||||
} else {
|
} else {
|
||||||
collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name)
|
collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name)
|
||||||
}
|
}
|
||||||
@ -145,24 +170,33 @@ fn collect_fn_metadata(
|
|||||||
filter: impl Fn(FnNamespace, FnAccess, &str, usize, &crate::Shared<crate::ast::ScriptFnDef>) -> bool
|
filter: impl Fn(FnNamespace, FnAccess, &str, usize, &crate::Shared<crate::ast::ScriptFnDef>) -> bool
|
||||||
+ Copy,
|
+ Copy,
|
||||||
) -> crate::Array {
|
) -> crate::Array {
|
||||||
use crate::{ast::ScriptFnDef, Array, Map};
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::Identifier;
|
||||||
|
use crate::{ast::ScriptFnDef, engine::FN_ANONYMOUS, Array, Map};
|
||||||
|
|
||||||
// Create a metadata record for a function.
|
// Create a metadata record for a function.
|
||||||
fn make_metadata(
|
fn make_metadata(
|
||||||
dict: &mut crate::types::StringsInterner,
|
engine: &Engine,
|
||||||
#[cfg(not(feature = "no_module"))] namespace: crate::Identifier,
|
#[cfg(not(feature = "no_module"))] namespace: Identifier,
|
||||||
func: &ScriptFnDef,
|
func: &ScriptFnDef,
|
||||||
) -> Map {
|
) -> Map {
|
||||||
let mut map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if !namespace.is_empty() {
|
if !namespace.is_empty() {
|
||||||
map.insert("namespace".into(), dict.get(namespace).into());
|
map.insert(
|
||||||
|
"namespace".into(),
|
||||||
|
engine.get_interned_string(namespace).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
map.insert("name".into(), dict.get(func.name.as_str()).into());
|
map.insert(
|
||||||
|
"name".into(),
|
||||||
|
engine.get_interned_string(func.name.clone()).into(),
|
||||||
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
"access".into(),
|
"access".into(),
|
||||||
dict.get(match func.access {
|
engine
|
||||||
|
.get_interned_string(match func.access {
|
||||||
FnAccess::Public => "public",
|
FnAccess::Public => "public",
|
||||||
FnAccess::Private => "private",
|
FnAccess::Private => "private",
|
||||||
})
|
})
|
||||||
@ -170,13 +204,13 @@ fn collect_fn_metadata(
|
|||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
"is_anonymous".into(),
|
"is_anonymous".into(),
|
||||||
func.name.starts_with(crate::engine::FN_ANONYMOUS).into(),
|
func.name.starts_with(FN_ANONYMOUS).into(),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
"params".into(),
|
"params".into(),
|
||||||
func.params
|
func.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| dict.get(p.as_str()).into())
|
.map(|p| engine.get_interned_string(p.clone()).into())
|
||||||
.collect::<Array>()
|
.collect::<Array>()
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
@ -186,7 +220,7 @@ fn collect_fn_metadata(
|
|||||||
"comments".into(),
|
"comments".into(),
|
||||||
func.comments
|
func.comments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| dict.get(s.as_ref()).into())
|
.map(|s| engine.get_interned_string(s.as_ref()).into())
|
||||||
.collect::<Array>()
|
.collect::<Array>()
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
@ -195,7 +229,7 @@ fn collect_fn_metadata(
|
|||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
let dict = &mut crate::types::StringsInterner::new();
|
let engine = ctx.engine();
|
||||||
let mut list = Array::new();
|
let mut list = Array::new();
|
||||||
|
|
||||||
ctx.iter_namespaces()
|
ctx.iter_namespaces()
|
||||||
@ -204,9 +238,9 @@ fn collect_fn_metadata(
|
|||||||
.for_each(|(.., f)| {
|
.for_each(|(.., f)| {
|
||||||
list.push(
|
list.push(
|
||||||
make_metadata(
|
make_metadata(
|
||||||
dict,
|
engine,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
crate::Identifier::new_const(),
|
Identifier::new_const(),
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
@ -221,9 +255,9 @@ fn collect_fn_metadata(
|
|||||||
.for_each(|(.., f)| {
|
.for_each(|(.., f)| {
|
||||||
list.push(
|
list.push(
|
||||||
make_metadata(
|
make_metadata(
|
||||||
dict,
|
engine,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
crate::Identifier::new_const(),
|
Identifier::new_const(),
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
@ -233,15 +267,16 @@ fn collect_fn_metadata(
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
ctx.engine()
|
ctx.engine()
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.values()
|
.iter()
|
||||||
|
.flat_map(|m| m.values())
|
||||||
.flat_map(|m| m.iter_script_fn())
|
.flat_map(|m| m.iter_script_fn())
|
||||||
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
|
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
|
||||||
.for_each(|(.., f)| {
|
.for_each(|(.., f)| {
|
||||||
list.push(
|
list.push(
|
||||||
make_metadata(
|
make_metadata(
|
||||||
dict,
|
engine,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
crate::Identifier::new_const(),
|
Identifier::new_const(),
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
@ -250,36 +285,31 @@ fn collect_fn_metadata(
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
|
use crate::{tokenizer::Token::DoubleColon, Shared, SmartString};
|
||||||
|
|
||||||
// Recursively scan modules for script-defined functions.
|
// Recursively scan modules for script-defined functions.
|
||||||
fn scan_module(
|
fn scan_module(
|
||||||
dict: &mut crate::types::StringsInterner,
|
engine: &Engine,
|
||||||
list: &mut Array,
|
list: &mut Array,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
filter: impl Fn(
|
filter: impl Fn(FnNamespace, FnAccess, &str, usize, &Shared<ScriptFnDef>) -> bool + Copy,
|
||||||
FnNamespace,
|
|
||||||
FnAccess,
|
|
||||||
&str,
|
|
||||||
usize,
|
|
||||||
&crate::Shared<crate::ast::ScriptFnDef>,
|
|
||||||
) -> bool
|
|
||||||
+ Copy,
|
|
||||||
) {
|
) {
|
||||||
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.into(), f).into()));
|
.for_each(|(.., f)| list.push(make_metadata(engine, namespace.into(), f).into()));
|
||||||
for (ns, m) in module.iter_sub_modules() {
|
for (name, m) in module.iter_sub_modules() {
|
||||||
let ns = format!(
|
use std::fmt::Write;
|
||||||
"{namespace}{}{ns}",
|
|
||||||
crate::tokenizer::Token::DoubleColon.literal_syntax()
|
let mut ns = SmartString::new_const();
|
||||||
);
|
write!(&mut ns, "{namespace}{}{name}", DoubleColon.literal_syntax()).unwrap();
|
||||||
scan_module(dict, list, &ns, &**m, filter);
|
scan_module(engine, list, &ns, m, filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ns, m) in ctx.iter_imports_raw() {
|
for (ns, m) in ctx.iter_imports_raw() {
|
||||||
scan_module(dict, &mut list, ns, &**m, filter);
|
scan_module(engine, &mut list, ns, m, filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -38,7 +39,7 @@ macro_rules! reg_functions {
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic logic operators.
|
/// Package of basic logic operators.
|
||||||
pub LogicPackage(lib) {
|
pub LogicPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
@ -92,6 +93,7 @@ mod logic_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod f32_functions {
|
mod f32_functions {
|
||||||
use crate::INT;
|
use crate::INT;
|
||||||
@ -147,6 +149,7 @@ mod f32_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod f64_functions {
|
mod f64_functions {
|
||||||
use crate::INT;
|
use crate::INT;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![cfg(not(feature = "no_object"))]
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use crate::engine::OP_EQUALS;
|
use crate::engine::OP_EQUALS;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, Dynamic, ImmutableString, Map, NativeCallContext, RhaiResultOf, INT};
|
use crate::{def_package, Dynamic, ImmutableString, Map, NativeCallContext, RhaiResultOf, INT};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -12,7 +13,7 @@ use crate::Array;
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic object map utilities.
|
/// Package of basic object map utilities.
|
||||||
pub BasicMapPackage(lib) {
|
pub BasicMapPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "map", map_functions);
|
combine_with_exported_module!(lib, "map", map_functions);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, Position, RhaiResultOf, ERR, INT};
|
use crate::{def_package, Position, RhaiResultOf, ERR, INT};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -54,7 +55,7 @@ macro_rules! reg_functions {
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Basic mathematical package.
|
/// Basic mathematical package.
|
||||||
pub BasicMathPackage(lib) {
|
pub BasicMathPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
// Integer functions
|
// Integer functions
|
||||||
combine_with_exported_module!(lib, "int", int_functions);
|
combine_with_exported_module!(lib, "int", int_functions);
|
||||||
@ -144,6 +145,7 @@ mod int_functions {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||||
INT::from_str_radix(string.trim(), radix as u32).map_err(|err| {
|
INT::from_str_radix(string.trim(), radix as u32).map_err(|err| {
|
||||||
ERR::ErrorArithmetic(
|
ERR::ErrorArithmetic(
|
||||||
format!("Error parsing integer number '{string}': {err}"),
|
format!("Error parsing integer number '{string}': {err}"),
|
||||||
@ -157,8 +159,6 @@ mod int_functions {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod trig_functions {
|
mod trig_functions {
|
||||||
use crate::FLOAT;
|
|
||||||
|
|
||||||
/// Return the sine of the floating-point number in radians.
|
/// Return the sine of the floating-point number in radians.
|
||||||
pub fn sin(x: FLOAT) -> FLOAT {
|
pub fn sin(x: FLOAT) -> FLOAT {
|
||||||
x.sin()
|
x.sin()
|
||||||
@ -221,8 +221,6 @@ mod trig_functions {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod float_functions {
|
mod float_functions {
|
||||||
use crate::FLOAT;
|
|
||||||
|
|
||||||
/// Return the natural number _e_.
|
/// Return the natural number _e_.
|
||||||
#[rhai_fn(name = "E")]
|
#[rhai_fn(name = "E")]
|
||||||
pub fn e() -> FLOAT {
|
pub fn e() -> FLOAT {
|
||||||
@ -312,6 +310,7 @@ mod float_functions {
|
|||||||
/// Convert the floating-point number into an integer.
|
/// Convert the floating-point number into an integer.
|
||||||
#[rhai_fn(name = "to_int", return_raw)]
|
#[rhai_fn(name = "to_int", return_raw)]
|
||||||
pub fn f32_to_int(x: f32) -> RhaiResultOf<INT> {
|
pub fn f32_to_int(x: f32) -> RhaiResultOf<INT> {
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
if cfg!(not(feature = "unchecked")) && (x > (INT::MAX as f32) || x < (INT::MIN as f32)) {
|
if cfg!(not(feature = "unchecked")) && (x > (INT::MAX as f32) || x < (INT::MIN as f32)) {
|
||||||
Err(
|
Err(
|
||||||
ERR::ErrorArithmetic(format!("Integer overflow: to_int({x})"), Position::NONE)
|
ERR::ErrorArithmetic(format!("Integer overflow: to_int({x})"), Position::NONE)
|
||||||
@ -324,6 +323,7 @@ mod float_functions {
|
|||||||
/// Convert the floating-point number into an integer.
|
/// Convert the floating-point number into an integer.
|
||||||
#[rhai_fn(name = "to_int", return_raw)]
|
#[rhai_fn(name = "to_int", return_raw)]
|
||||||
pub fn f64_to_int(x: f64) -> RhaiResultOf<INT> {
|
pub fn f64_to_int(x: f64) -> RhaiResultOf<INT> {
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
if cfg!(not(feature = "unchecked")) && (x > (INT::MAX as f64) || x < (INT::MIN as f64)) {
|
if cfg!(not(feature = "unchecked")) && (x > (INT::MAX as f64) || x < (INT::MIN as f64)) {
|
||||||
Err(
|
Err(
|
||||||
ERR::ErrorArithmetic(format!("Integer overflow: to_int({x})"), Position::NONE)
|
ERR::ErrorArithmetic(format!("Integer overflow: to_int({x})"), Position::NONE)
|
||||||
@ -356,7 +356,7 @@ mod float_functions {
|
|||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "f32_float"))]
|
||||||
#[rhai_fn(name = "to_float")]
|
#[rhai_fn(name = "to_float")]
|
||||||
pub fn f32_to_f64(x: f32) -> f64 {
|
pub fn f32_to_f64(x: f32) -> f64 {
|
||||||
x as f64
|
x.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,6 +477,7 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
Ok(x.round_dp(digits as u32))
|
Ok(x.round_dp(digits as u32))
|
||||||
}
|
}
|
||||||
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
||||||
@ -494,6 +495,7 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::AwayFromZero))
|
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::AwayFromZero))
|
||||||
}
|
}
|
||||||
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
||||||
@ -511,6 +513,7 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::ToZero))
|
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::ToZero))
|
||||||
}
|
}
|
||||||
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
||||||
@ -528,6 +531,7 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::MidpointAwayFromZero))
|
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::MidpointAwayFromZero))
|
||||||
}
|
}
|
||||||
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
/// Round the decimal number to the specified number of `digits` after the decimal point and return it.
|
||||||
@ -545,6 +549,7 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::MidpointTowardZero))
|
Ok(x.round_dp_with_strategy(digits as u32, RoundingStrategy::MidpointTowardZero))
|
||||||
}
|
}
|
||||||
/// Convert the decimal number into an integer.
|
/// Convert the decimal number into an integer.
|
||||||
@ -562,14 +567,15 @@ mod decimal_functions {
|
|||||||
return Some(n);
|
return Some(n);
|
||||||
});
|
});
|
||||||
|
|
||||||
match n {
|
n.map_or_else(
|
||||||
Some(n) => Ok(n),
|
|| {
|
||||||
_ => Err(ERR::ErrorArithmetic(
|
Err(
|
||||||
format!("Integer overflow: to_int({x})"),
|
ERR::ErrorArithmetic(format!("Integer overflow: to_int({x})"), Position::NONE)
|
||||||
Position::NONE,
|
.into(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Ok,
|
||||||
)
|
)
|
||||||
.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Return the integral part of the decimal number.
|
/// Return the integral part of the decimal number.
|
||||||
#[rhai_fn(name = "int", get = "int")]
|
#[rhai_fn(name = "int", get = "int")]
|
||||||
|
@ -3,6 +3,7 @@ use std::prelude::v1::*;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
|
|
||||||
def_package! {
|
def_package! {
|
||||||
/// Core package containing basic facilities.
|
/// Core package containing basic facilities.
|
||||||
@ -23,6 +24,6 @@ def_package! {
|
|||||||
BasicFnPackage,
|
BasicFnPackage,
|
||||||
#[cfg(feature = "debugging")] DebuggingPackage
|
#[cfg(feature = "debugging")] DebuggingPackage
|
||||||
{
|
{
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use std::prelude::v1::*;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
|
|
||||||
def_package! {
|
def_package! {
|
||||||
/// Standard package containing all built-in features.
|
/// Standard package containing all built-in features.
|
||||||
@ -29,6 +30,6 @@ def_package! {
|
|||||||
#[cfg(not(feature = "no_time"))] BasicTimePackage,
|
#[cfg(not(feature = "no_time"))] BasicTimePackage,
|
||||||
MoreStringPackage
|
MoreStringPackage
|
||||||
{
|
{
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, FnPtr, INT};
|
use crate::{def_package, FnPtr, ImmutableString, SmartString, INT};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::fmt::{Binary, LowerHex, Octal};
|
use std::fmt::{Binary, LowerHex, Octal, Write};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ pub const FUNC_TO_DEBUG: &str = "to_debug";
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic string utilities (e.g. printing)
|
/// Package of basic string utilities (e.g. printing)
|
||||||
pub BasicStringPackage(lib) {
|
pub BasicStringPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "print_debug", print_debug_functions);
|
combine_with_exported_module!(lib, "print_debug", print_debug_functions);
|
||||||
combine_with_exported_module!(lib, "number_formatting", number_formatting);
|
combine_with_exported_module!(lib, "number_formatting", number_formatting);
|
||||||
@ -25,7 +26,7 @@ def_package! {
|
|||||||
// Register characters iterator
|
// Register characters iterator
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
lib.set_iter(TypeId::of::<ImmutableString>(), |value| Box::new(
|
lib.set_iter(TypeId::of::<ImmutableString>(), |value| Box::new(
|
||||||
value.cast::<ImmutableString>().chars().map(Into::into).collect::<crate::Array>().into_iter()
|
value.cast::<ImmutableString>().chars().map(Into::into).collect::<Array>().into_iter()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,7 +38,7 @@ pub fn print_with_func(
|
|||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
ctx: &NativeCallContext,
|
ctx: &NativeCallContext,
|
||||||
value: &mut Dynamic,
|
value: &mut Dynamic,
|
||||||
) -> crate::ImmutableString {
|
) -> ImmutableString {
|
||||||
match ctx.call_native_fn_raw(fn_name, true, &mut [value]) {
|
match ctx.call_native_fn_raw(fn_name, true, &mut [value]) {
|
||||||
Ok(result) if result.is_string() => {
|
Ok(result) if result.is_string() => {
|
||||||
result.into_immutable_string().expect("`ImmutableString`")
|
result.into_immutable_string().expect("`ImmutableString`")
|
||||||
@ -49,8 +50,6 @@ pub fn print_with_func(
|
|||||||
|
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod print_debug_functions {
|
mod print_debug_functions {
|
||||||
use crate::ImmutableString;
|
|
||||||
|
|
||||||
/// Convert the value of the `item` into a string.
|
/// Convert the value of the `item` into a string.
|
||||||
#[rhai_fn(name = "print", pure)]
|
#[rhai_fn(name = "print", pure)]
|
||||||
pub fn print_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
pub fn print_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
||||||
@ -69,7 +68,9 @@ mod print_debug_functions {
|
|||||||
/// Convert the value of the `item` into a string in debug format.
|
/// Convert the value of the `item` into a string in debug format.
|
||||||
#[rhai_fn(name = "to_debug", pure)]
|
#[rhai_fn(name = "to_debug", pure)]
|
||||||
pub fn to_debug_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
pub fn to_debug_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
||||||
ctx.engine().map_type_name(&format!("{item:?}")).into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{item:?}").unwrap();
|
||||||
|
ctx.engine().map_type_name(&buf).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the empty string.
|
/// Return the empty string.
|
||||||
@ -86,7 +87,9 @@ mod print_debug_functions {
|
|||||||
/// Convert the string into debug format.
|
/// Convert the string into debug format.
|
||||||
#[rhai_fn(name = "debug", name = "to_debug", pure)]
|
#[rhai_fn(name = "debug", name = "to_debug", pure)]
|
||||||
pub fn debug_string(string: &mut ImmutableString) -> ImmutableString {
|
pub fn debug_string(string: &mut ImmutableString) -> ImmutableString {
|
||||||
format!("{string:?}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{string:?}").unwrap();
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the character into a string.
|
/// Return the character into a string.
|
||||||
@ -97,7 +100,9 @@ mod print_debug_functions {
|
|||||||
/// Convert the string into debug format.
|
/// Convert the string into debug format.
|
||||||
#[rhai_fn(name = "debug", name = "to_debug")]
|
#[rhai_fn(name = "debug", name = "to_debug")]
|
||||||
pub fn debug_char(character: char) -> ImmutableString {
|
pub fn debug_char(character: char) -> ImmutableString {
|
||||||
format!("{character:?}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
buf.push(character);
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the function pointer into a string in debug format.
|
/// Convert the function pointer into a string in debug format.
|
||||||
@ -114,7 +119,9 @@ mod print_debug_functions {
|
|||||||
/// Convert the boolean value into a string in debug format.
|
/// Convert the boolean value into a string in debug format.
|
||||||
#[rhai_fn(name = "debug", name = "to_debug")]
|
#[rhai_fn(name = "debug", name = "to_debug")]
|
||||||
pub fn debug_bool(value: bool) -> ImmutableString {
|
pub fn debug_bool(value: bool) -> ImmutableString {
|
||||||
format!("{value:?}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{value:?}").unwrap();
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the empty string.
|
/// Return the empty string.
|
||||||
@ -147,14 +154,18 @@ mod print_debug_functions {
|
|||||||
#[rhai_fn(name = "debug", name = "to_debug")]
|
#[rhai_fn(name = "debug", name = "to_debug")]
|
||||||
pub fn debug_f64(number: f64) -> ImmutableString {
|
pub fn debug_f64(number: f64) -> ImmutableString {
|
||||||
let number = crate::types::FloatWrapper::new(number);
|
let number = crate::types::FloatWrapper::new(number);
|
||||||
format!("{number:?}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{number:?}").unwrap();
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
/// Convert the value of `number` into a string.
|
/// Convert the value of `number` into a string.
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[rhai_fn(name = "debug", name = "to_debug")]
|
#[rhai_fn(name = "debug", name = "to_debug")]
|
||||||
pub fn debug_f32(number: f32) -> ImmutableString {
|
pub fn debug_f32(number: f32) -> ImmutableString {
|
||||||
let number = crate::types::FloatWrapper::new(number);
|
let number = crate::types::FloatWrapper::new(number);
|
||||||
format!("{number:?}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{number:?}").unwrap();
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the array into a string.
|
/// Convert the array into a string.
|
||||||
@ -217,13 +228,19 @@ mod print_debug_functions {
|
|||||||
#[export_module]
|
#[export_module]
|
||||||
mod number_formatting {
|
mod number_formatting {
|
||||||
fn to_hex<T: LowerHex>(value: T) -> ImmutableString {
|
fn to_hex<T: LowerHex>(value: T) -> ImmutableString {
|
||||||
format!("{value:x}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{value:x}").unwrap();
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
fn to_octal<T: Octal>(value: T) -> ImmutableString {
|
fn to_octal<T: Octal>(value: T) -> ImmutableString {
|
||||||
format!("{value:o}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{value:o}").unwrap();
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
fn to_binary<T: Binary>(value: T) -> ImmutableString {
|
fn to_binary<T: Binary>(value: T) -> ImmutableString {
|
||||||
format!("{value:b}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
write!(&mut buf, "{value:b}").unwrap();
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the `value` into a string in hex format.
|
/// Convert the `value` into a string in hex format.
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT,
|
def_package, Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, Position, RhaiResultOf,
|
||||||
MAX_USIZE_INT,
|
SmartString, StaticVec, ERR, INT, MAX_USIZE_INT,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -12,7 +13,7 @@ use super::string_basic::{print_with_func, FUNC_TO_STRING};
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of additional string utilities over [`BasicStringPackage`][super::BasicStringPackage]
|
/// Package of additional string utilities over [`BasicStringPackage`][super::BasicStringPackage]
|
||||||
pub MoreStringPackage(lib) {
|
pub MoreStringPackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
combine_with_exported_module!(lib, "string", string_functions);
|
combine_with_exported_module!(lib, "string", string_functions);
|
||||||
}
|
}
|
||||||
@ -20,8 +21,6 @@ def_package! {
|
|||||||
|
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod string_functions {
|
mod string_functions {
|
||||||
use crate::{ImmutableString, SmartString};
|
|
||||||
|
|
||||||
#[rhai_fn(name = "+", pure)]
|
#[rhai_fn(name = "+", pure)]
|
||||||
pub fn add_append(
|
pub fn add_append(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
@ -33,7 +32,9 @@ mod string_functions {
|
|||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
string.clone()
|
string.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("{string}{s}").into()
|
let mut buf = SmartString::from(string.as_str());
|
||||||
|
buf.push_str(&s);
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+=", name = "append")]
|
#[rhai_fn(name = "+=", name = "append")]
|
||||||
@ -41,7 +42,9 @@ mod string_functions {
|
|||||||
let s = print_with_func(FUNC_TO_STRING, &ctx, &mut item);
|
let s = print_with_func(FUNC_TO_STRING, &ctx, &mut item);
|
||||||
|
|
||||||
if !s.is_empty() {
|
if !s.is_empty() {
|
||||||
*string = format!("{string}{s}").into();
|
let mut buf = SmartString::from(string.as_str());
|
||||||
|
buf.push_str(&s);
|
||||||
|
*string = buf.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+", pure)]
|
#[rhai_fn(name = "+", pure)]
|
||||||
@ -74,7 +77,10 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_prepend_char(character: char, string: &str) -> ImmutableString {
|
pub fn add_prepend_char(character: char, string: &str) -> ImmutableString {
|
||||||
format!("{character}{string}").into()
|
let mut buf = SmartString::new_const();
|
||||||
|
buf.push(character);
|
||||||
|
buf.push_str(string);
|
||||||
|
buf.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
@ -127,7 +133,7 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(name = "+=", name = "append")]
|
#[rhai_fn(name = "+=", name = "append")]
|
||||||
pub fn add(string: &mut ImmutableString, utf8: Blob) {
|
pub fn add(string: &mut ImmutableString, utf8: Blob) {
|
||||||
let mut s = crate::SmartString::from(string.as_str());
|
let mut s = SmartString::from(string.as_str());
|
||||||
if !utf8.is_empty() {
|
if !utf8.is_empty() {
|
||||||
s.push_str(&String::from_utf8_lossy(&utf8));
|
s.push_str(&String::from_utf8_lossy(&utf8));
|
||||||
*string = s.into();
|
*string = s.into();
|
||||||
@ -147,6 +153,25 @@ mod string_functions {
|
|||||||
|
|
||||||
s.into()
|
s.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert the string into an UTF-8 encoded byte-stream as a BLOB.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let text = "朝には紅顔ありて夕べには白骨となる";
|
||||||
|
///
|
||||||
|
/// let bytes = text.to_blob();
|
||||||
|
///
|
||||||
|
/// print(bytes.len()); // prints 51
|
||||||
|
/// ```
|
||||||
|
pub fn to_blob(string: &str) -> Blob {
|
||||||
|
if string.is_empty() {
|
||||||
|
Blob::new()
|
||||||
|
} else {
|
||||||
|
string.as_bytes().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the length of the string, in number of characters.
|
/// Return the length of the string, in number of characters.
|
||||||
@ -188,25 +213,6 @@ mod string_functions {
|
|||||||
string.len() as INT
|
string.len() as INT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Convert the string into an UTF-8 encoded byte-stream as a BLOB.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rhai
|
|
||||||
/// let text = "朝には紅顔ありて夕べには白骨となる";
|
|
||||||
///
|
|
||||||
/// let bytes = text.to_blob();
|
|
||||||
///
|
|
||||||
/// print(bytes.len()); // prints 51
|
|
||||||
/// ```
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
pub fn to_blob(string: &str) -> crate::Blob {
|
|
||||||
if string.is_empty() {
|
|
||||||
crate::Blob::new()
|
|
||||||
} else {
|
|
||||||
string.as_bytes().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Remove all occurrences of a sub-string from the string.
|
/// Remove all occurrences of a sub-string from the string.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -239,9 +245,10 @@ mod string_functions {
|
|||||||
/// Clear the string, making it empty.
|
/// Clear the string, making it empty.
|
||||||
pub fn clear(string: &mut ImmutableString) {
|
pub fn clear(string: &mut ImmutableString) {
|
||||||
if !string.is_empty() {
|
if !string.is_empty() {
|
||||||
match string.get_mut() {
|
if let Some(s) = string.get_mut() {
|
||||||
Some(s) => s.clear(),
|
s.clear()
|
||||||
_ => *string = ImmutableString::new(),
|
} else {
|
||||||
|
*string = ImmutableString::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,6 +272,7 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn truncate(string: &mut ImmutableString, len: INT) {
|
pub fn truncate(string: &mut ImmutableString, len: INT) {
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
let len = len.min(MAX_USIZE_INT) as usize;
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
let chars: StaticVec<_> = string.chars().collect();
|
let chars: StaticVec<_> = string.chars().collect();
|
||||||
let copy = string.make_mut();
|
let copy = string.make_mut();
|
||||||
@ -286,15 +294,13 @@ mod string_functions {
|
|||||||
/// print(text); // prints "hello"
|
/// print(text); // prints "hello"
|
||||||
/// ```
|
/// ```
|
||||||
pub fn trim(string: &mut ImmutableString) {
|
pub fn trim(string: &mut ImmutableString) {
|
||||||
match string.get_mut() {
|
if let Some(s) = string.get_mut() {
|
||||||
Some(s) => {
|
|
||||||
let trimmed = s.trim();
|
let trimmed = s.trim();
|
||||||
|
|
||||||
if trimmed != s {
|
if trimmed != s {
|
||||||
*s = trimmed.into();
|
*s = trimmed.into();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
None => {
|
|
||||||
let trimmed = string.trim();
|
let trimmed = string.trim();
|
||||||
|
|
||||||
if trimmed != string {
|
if trimmed != string {
|
||||||
@ -302,7 +308,6 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/// Remove the last character from the string and return it.
|
/// Remove the last character from the string and return it.
|
||||||
///
|
///
|
||||||
/// If the string is empty, `()` is returned.
|
/// If the string is empty, `()` is returned.
|
||||||
@ -536,7 +541,7 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "contains")]
|
#[rhai_fn(name = "contains")]
|
||||||
pub fn contains_char(string: &str, character: char) -> bool {
|
pub fn contains_char(string: &str, character: char) -> bool {
|
||||||
string.contains(character).into()
|
string.contains(character)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the string starts with a specified string.
|
/// Return `true` if the string starts with a specified string.
|
||||||
@ -1219,11 +1224,9 @@ mod string_functions {
|
|||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
|
||||||
return Err(crate::ERR::ErrorDataTooLarge(
|
return Err(
|
||||||
"Length of string".to_string(),
|
ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(),
|
||||||
crate::Position::NONE,
|
);
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let orig_len = string.chars().count();
|
let orig_len = string.chars().count();
|
||||||
@ -1237,11 +1240,9 @@ mod string_functions {
|
|||||||
|
|
||||||
if _ctx.engine().max_string_size() > 0 && string.len() > _ctx.engine().max_string_size()
|
if _ctx.engine().max_string_size() > 0 && string.len() > _ctx.engine().max_string_size()
|
||||||
{
|
{
|
||||||
return Err(crate::ERR::ErrorDataTooLarge(
|
return Err(
|
||||||
"Length of string".to_string(),
|
ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(),
|
||||||
crate::Position::NONE,
|
);
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,11 +1280,9 @@ mod string_functions {
|
|||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
|
||||||
return Err(crate::ERR::ErrorDataTooLarge(
|
return Err(
|
||||||
"Length of string".to_string(),
|
ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(),
|
||||||
crate::Position::NONE,
|
);
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut str_len = string.chars().count();
|
let mut str_len = string.chars().count();
|
||||||
@ -1304,11 +1303,9 @@ mod string_functions {
|
|||||||
|
|
||||||
if _ctx.engine().max_string_size() > 0 && string.len() > _ctx.engine().max_string_size()
|
if _ctx.engine().max_string_size() > 0 && string.len() > _ctx.engine().max_string_size()
|
||||||
{
|
{
|
||||||
return Err(crate::ERR::ErrorDataTooLarge(
|
return Err(
|
||||||
"Length of string".to_string(),
|
ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(),
|
||||||
crate::Position::NONE,
|
);
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1317,7 +1314,7 @@ mod string_functions {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub mod arrays {
|
pub mod arrays {
|
||||||
use crate::{Array, ImmutableString};
|
use crate::Array;
|
||||||
|
|
||||||
/// Split the string into two at the specified `index` position and return it both strings
|
/// Split the string into two at the specified `index` position and return it both strings
|
||||||
/// as an array.
|
/// as an array.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![cfg(not(feature = "no_time"))]
|
#![cfg(not(feature = "no_time"))]
|
||||||
|
|
||||||
use super::arithmetic::make_err as make_arithmetic_err;
|
use super::arithmetic::make_err as make_arithmetic_err;
|
||||||
|
use crate::module::ModuleFlags;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, Dynamic, RhaiResult, RhaiResultOf, INT};
|
use crate::{def_package, Dynamic, RhaiResult, RhaiResultOf, INT};
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ use instant::{Duration, Instant};
|
|||||||
def_package! {
|
def_package! {
|
||||||
/// Package of basic timing utilities.
|
/// Package of basic timing utilities.
|
||||||
pub BasicTimePackage(lib) {
|
pub BasicTimePackage(lib) {
|
||||||
lib.standard = true;
|
lib.flags |= ModuleFlags::STANDARD_LIB;
|
||||||
|
|
||||||
// Register date/time functions
|
// Register date/time functions
|
||||||
combine_with_exported_module!(lib, "time", time_functions);
|
combine_with_exported_module!(lib, "time", time_functions);
|
||||||
|
927
src/parser.rs
927
src/parser.rs
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,7 @@ impl<'de> DynamicDeserializer<'de> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deserialize_int<V: Visitor<'de>>(self, v: crate::INT, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_int<V: Visitor<'de>>(v: crate::INT, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
return visitor.visit_i64(v);
|
return visitor.visit_i64(v);
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
@ -185,7 +185,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<i8>()
|
.downcast_ref::<i8>()
|
||||||
@ -195,7 +195,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<i16>()
|
.downcast_ref::<i16>()
|
||||||
@ -205,7 +205,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else if cfg!(feature = "only_i32") {
|
} else if cfg!(feature = "only_i32") {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
@ -217,7 +217,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else if cfg!(not(feature = "only_i32")) {
|
} else if cfg!(not(feature = "only_i32")) {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
@ -229,7 +229,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else if cfg!(not(feature = "only_i32")) {
|
} else if cfg!(not(feature = "only_i32")) {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
@ -241,7 +241,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u8>()
|
.downcast_ref::<u8>()
|
||||||
@ -251,7 +251,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u16>()
|
.downcast_ref::<u16>()
|
||||||
@ -261,7 +261,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u32>()
|
.downcast_ref::<u32>()
|
||||||
@ -271,7 +271,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u64>()
|
.downcast_ref::<u64>()
|
||||||
@ -281,7 +281,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u128>()
|
.downcast_ref::<u128>()
|
||||||
@ -296,7 +296,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.downcast_ref::<f32>()
|
.downcast_ref::<f32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
{
|
{
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
@ -308,9 +309,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
|
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
self.type_error_str("f32")
|
||||||
#[cfg(not(feature = "decimal"))]
|
}
|
||||||
return self.type_error_str("f32");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
@ -320,7 +320,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.downcast_ref::<f64>()
|
.downcast_ref::<f64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
{
|
{
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
@ -332,9 +333,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
|
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
self.type_error_str("f64")
|
||||||
#[cfg(not(feature = "decimal"))]
|
}
|
||||||
return self.type_error_str("f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
@ -517,10 +517,9 @@ impl<'de, ITER: Iterator<Item = &'de Dynamic>> serde::de::SeqAccess<'de>
|
|||||||
seed: T,
|
seed: T,
|
||||||
) -> RhaiResultOf<Option<T::Value>> {
|
) -> RhaiResultOf<Option<T::Value>> {
|
||||||
// Deserialize each item coming out of the iterator.
|
// Deserialize each item coming out of the iterator.
|
||||||
match self.iter.next() {
|
self.iter.next().map_or(Ok(None), |item| {
|
||||||
Some(item) => seed.deserialize(item.into_deserializer()).map(Some),
|
seed.deserialize(item.into_deserializer()).map(Some)
|
||||||
None => Ok(None),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,10 +552,10 @@ impl<'de, K: Iterator<Item = &'de str>, V: Iterator<Item = &'de Dynamic>> serde:
|
|||||||
seed: S,
|
seed: S,
|
||||||
) -> RhaiResultOf<Option<S::Value>> {
|
) -> RhaiResultOf<Option<S::Value>> {
|
||||||
// Deserialize each `Identifier` key coming out of the keys iterator.
|
// Deserialize each `Identifier` key coming out of the keys iterator.
|
||||||
match self.keys.next().map(<_>::into_deserializer) {
|
self.keys
|
||||||
Some(d) => seed.deserialize(d).map(Some),
|
.next()
|
||||||
None => Ok(None),
|
.map(<_>::into_deserializer)
|
||||||
}
|
.map_or(Ok(None), |d| seed.deserialize(d).map(Some))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_value_seed<S: serde::de::DeserializeSeed<'de>>(
|
fn next_value_seed<S: serde::de::DeserializeSeed<'de>>(
|
||||||
|
@ -9,6 +9,9 @@ use std::fmt;
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
struct DynamicVisitor;
|
struct DynamicVisitor;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for DynamicVisitor {
|
impl<'de> Visitor<'de> for DynamicVisitor {
|
||||||
@ -38,14 +41,43 @@ impl<'de> Visitor<'de> for DynamicVisitor {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
|
fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(v.into());
|
||||||
Ok(v.into())
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as i64 {
|
if v <= INT::MAX as i64 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.visit_i32(v as i32)
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_i64(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn visit_i128<E: Error>(self, v: i128) -> Result<Self::Value, E> {
|
||||||
|
if v <= i128::from(INT::MAX) {
|
||||||
|
return Ok(Dynamic::from(v as INT));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_i128(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -59,57 +91,105 @@ impl<'de> Visitor<'de> for DynamicVisitor {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
|
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(INT::from(v).into())
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as u32 {
|
if v <= INT::MAX as u32 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.visit_i32(v as i32)
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_u32(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
|
fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= INT::MAX as u64 {
|
||||||
if v > i64::MAX as u64 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.visit_i64(v as i64)
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
if v > i32::MAX as u64 {
|
#[cfg(feature = "decimal")]
|
||||||
Ok(Dynamic::from(v))
|
if let Some(n) = rust_decimal::Decimal::from_u64(v) {
|
||||||
} else {
|
return Ok(Dynamic::from_decimal(n));
|
||||||
self.visit_i32(v as i32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn visit_u128<E: Error>(self, v: u128) -> Result<Self::Value, E> {
|
||||||
|
if v <= INT::MAX as u128 {
|
||||||
|
return Ok(Dynamic::from(v as INT));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_u128(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return self.visit_f64(v as f64);
|
return Ok((v as crate::FLOAT).into());
|
||||||
#[cfg(feature = "f32_float")]
|
|
||||||
return Ok(v.into());
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_f32(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::custom(format!(
|
||||||
|
"floating-point number is not supported: {v}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return Ok(v.into());
|
return Ok((v as crate::FLOAT).into());
|
||||||
#[cfg(feature = "f32_float")]
|
|
||||||
return self.visit_f32(v as f32);
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_f64(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::custom(format!(
|
||||||
|
"floating-point number is not supported: {v}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
Decimal::try_from(v)
|
rust_decimal::Decimal::try_from(v)
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
.map_err(Error::custom)
|
.map_err(Error::custom)
|
||||||
}
|
}
|
||||||
@ -117,10 +197,9 @@ impl<'de> Visitor<'de> for DynamicVisitor {
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
Decimal::try_from(v)
|
rust_decimal::Decimal::try_from(v)
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
.map_err(Error::custom)
|
.map_err(Error::custom)
|
||||||
}
|
}
|
||||||
@ -216,10 +295,9 @@ impl<'de> Deserialize<'de> for Scope<'de> {
|
|||||||
where
|
where
|
||||||
A: SeqAccess<'de>,
|
A: SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut scope = match access.size_hint() {
|
let mut scope = access
|
||||||
Some(size) => Scope::with_capacity(size),
|
.size_hint()
|
||||||
None => Scope::new(),
|
.map_or_else(Scope::new, Scope::with_capacity);
|
||||||
};
|
|
||||||
|
|
||||||
while let Some(ScopeEntry {
|
while let Some(ScopeEntry {
|
||||||
name,
|
name,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#![cfg(feature = "metadata")]
|
#![cfg(feature = "metadata")]
|
||||||
|
|
||||||
use crate::api::type_names::format_type;
|
use crate::api::type_names::format_type;
|
||||||
use crate::module::{calc_native_fn_hash, FuncInfo};
|
use crate::module::{calc_native_fn_hash, FuncInfo, ModuleFlags};
|
||||||
use crate::{calc_fn_hash, Engine, FnAccess, SmartString, StaticVec, AST};
|
use crate::{calc_fn_hash, Engine, FnAccess, SmartString, StaticVec, AST};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -66,13 +66,13 @@ impl Ord for FnMetadata<'_> {
|
|||||||
|
|
||||||
impl<'a> From<&'a FuncInfo> for FnMetadata<'a> {
|
impl<'a> From<&'a FuncInfo> for FnMetadata<'a> {
|
||||||
fn from(info: &'a FuncInfo) -> Self {
|
fn from(info: &'a FuncInfo) -> Self {
|
||||||
let base_hash = calc_fn_hash(None, &info.name, info.num_params);
|
let base_hash = calc_fn_hash(None, &info.metadata.name, info.metadata.num_params);
|
||||||
let (typ, full_hash) = if info.func.is_script() {
|
let (typ, full_hash) = if info.func.is_script() {
|
||||||
(FnType::Script, base_hash)
|
(FnType::Script, base_hash)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
FnType::Native,
|
FnType::Native,
|
||||||
calc_native_fn_hash(None, &info.name, &info.param_types),
|
calc_native_fn_hash(None, &info.metadata.name, &info.metadata.param_types),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,12 +80,13 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> {
|
|||||||
base_hash,
|
base_hash,
|
||||||
full_hash,
|
full_hash,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace: info.namespace,
|
namespace: info.metadata.namespace,
|
||||||
access: info.access,
|
access: info.metadata.access,
|
||||||
name: &info.name,
|
name: &info.metadata.name,
|
||||||
typ,
|
typ,
|
||||||
num_params: info.num_params,
|
num_params: info.metadata.num_params,
|
||||||
params: info
|
params: info
|
||||||
|
.metadata
|
||||||
.params_info
|
.params_info
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
@ -99,7 +100,7 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
_dummy: None,
|
_dummy: None,
|
||||||
return_type: format_type(&info.return_type, true),
|
return_type: format_type(&info.metadata.return_type, true),
|
||||||
signature: info.gen_signature().into(),
|
signature: info.gen_signature().into(),
|
||||||
doc_comments: if info.func.is_script() {
|
doc_comments: if info.func.is_script() {
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
@ -114,7 +115,7 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> {
|
|||||||
.map(<_>::as_ref)
|
.map(<_>::as_ref)
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
info.comments.iter().map(<_>::as_ref).collect()
|
info.metadata.comments.iter().map(<_>::as_ref).collect()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,14 +171,20 @@ pub fn gen_metadata_to_json(
|
|||||||
let mut global = ModuleMetadata::new();
|
let mut global = ModuleMetadata::new();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
for (name, m) in &engine.global_sub_modules {
|
for (name, m) in engine.global_sub_modules.iter().flat_map(|m| m.iter()) {
|
||||||
global.modules.insert(name, m.as_ref().into());
|
global.modules.insert(name, m.as_ref().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let exclude_flags = if include_standard_packages {
|
||||||
|
ModuleFlags::empty()
|
||||||
|
} else {
|
||||||
|
ModuleFlags::STANDARD_LIB
|
||||||
|
};
|
||||||
|
|
||||||
engine
|
engine
|
||||||
.global_modules
|
.global_modules
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|m| include_standard_packages || !m.standard)
|
.filter(|m| !m.flags.contains(exclude_flags))
|
||||||
.flat_map(|m| m.iter_fn())
|
.flat_map(|m| m.iter_fn())
|
||||||
.for_each(|f| {
|
.for_each(|f| {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
|
208
src/serde/ser.rs
208
src/serde/ser.rs
@ -1,6 +1,6 @@
|
|||||||
//! Implement serialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
|
//! Implement serialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
|
||||||
|
|
||||||
use crate::{Dynamic, Identifier, Position, RhaiError, RhaiResult, RhaiResultOf, ERR};
|
use crate::{Dynamic, Identifier, Position, RhaiError, RhaiResult, RhaiResultOf, ERR, INT};
|
||||||
use serde::ser::{
|
use serde::ser::{
|
||||||
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
|
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
|
||||||
};
|
};
|
||||||
@ -9,6 +9,9 @@ use std::fmt;
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
/// Serializer for [`Dynamic`][crate::Dynamic].
|
/// Serializer for [`Dynamic`][crate::Dynamic].
|
||||||
pub struct DynamicSerializer {
|
pub struct DynamicSerializer {
|
||||||
/// Buffer to hold a temporary key.
|
/// Buffer to hold a temporary key.
|
||||||
@ -37,8 +40,9 @@ impl DynamicSerializer {
|
|||||||
/// # #[cfg(not(feature = "no_index"))]
|
/// # #[cfg(not(feature = "no_index"))]
|
||||||
/// # #[cfg(not(feature = "no_object"))]
|
/// # #[cfg(not(feature = "no_object"))]
|
||||||
/// # #[cfg(not(feature = "no_float"))]
|
/// # #[cfg(not(feature = "no_float"))]
|
||||||
|
/// # #[cfg(not(feature = "f32_float"))]
|
||||||
/// # {
|
/// # {
|
||||||
/// use rhai::{Dynamic, Array, Map, INT};
|
/// use rhai::{Dynamic, Array, Map};
|
||||||
/// use rhai::serde::to_dynamic;
|
/// use rhai::serde::to_dynamic;
|
||||||
/// use serde::Serialize;
|
/// use serde::Serialize;
|
||||||
///
|
///
|
||||||
@ -112,151 +116,166 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_i8(self, v: i8) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i8(self, v: i8) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_i16(self, v: i16) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i16(self, v: i16) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_i32(self, v: i32) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i32(self, v: i32) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return Ok(v.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_i64(self, v: i64) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i64(self, v: i64) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(v.into());
|
||||||
Ok(v.into())
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as i64 {
|
if v <= INT::MAX as i64 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.serialize_i32(v as i32)
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_i64(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_i128(self, v: i128) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i128(self, v: i128) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= i128::from(INT::MAX) {
|
||||||
if v > i64::MAX as i128 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.serialize_i64(v as i64)
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
if v > i32::MAX as i128 {
|
#[allow(unreachable_code)]
|
||||||
Ok(Dynamic::from(v))
|
{
|
||||||
} else {
|
#[cfg(feature = "decimal")]
|
||||||
self.serialize_i32(v as i32)
|
if let Some(n) = rust_decimal::Decimal::from_i128(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_u8(self, v: u8) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u8(self, v: u8) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_u16(self, v: u16) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u16(self, v: u16) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_u32(self, v: u32) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u32(self, v: u32) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(Dynamic::from(v as INT));
|
||||||
self.serialize_i64(i64::from(v))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as u32 {
|
if v <= INT::MAX as u32 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.serialize_i32(v as i32)
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_u32(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_u64(self, v: u64) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u64(self, v: u64) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= INT::MAX as u64 {
|
||||||
if v > i64::MAX as u64 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.serialize_i64(v as i64)
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
if v > i32::MAX as u64 {
|
#[cfg(feature = "decimal")]
|
||||||
Ok(Dynamic::from(v))
|
if let Some(n) = rust_decimal::Decimal::from_u64(v) {
|
||||||
} else {
|
return Ok(Dynamic::from_decimal(n));
|
||||||
self.serialize_i32(v as i32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_u128(self, v: u128) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u128(self, v: u128) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= INT::MAX as u128 {
|
||||||
if v > i64::MAX as u128 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.serialize_i64(v as i64)
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
if v > i32::MAX as u128 {
|
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.serialize_i32(v as i32)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some(n) = rust_decimal::Decimal::from_u128(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return Ok(Dynamic::from_float(v as crate::FLOAT));
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
Err(Error::custom(format!("integer number too large: {v}")))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn serialize_f32(self, v: f32) -> RhaiResultOf<Self::Ok> {
|
fn serialize_f32(self, v: f32) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return Ok(Dynamic::from(v));
|
return Ok((v as crate::FLOAT).into());
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[allow(unreachable_code)]
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
{
|
{
|
||||||
use rust_decimal::Decimal;
|
#[cfg(feature = "decimal")]
|
||||||
use std::convert::TryFrom;
|
if let Some(n) = rust_decimal::Decimal::from_f32(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
Decimal::try_from(v)
|
Err(Error::custom(format!(
|
||||||
.map(|v| v.into())
|
"floating-point number is not supported: {v}"
|
||||||
.map_err(Error::custom)
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn serialize_f64(self, v: f64) -> RhaiResultOf<Self::Ok> {
|
fn serialize_f64(self, v: f64) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return Ok(Dynamic::from(v));
|
return Ok((v as crate::FLOAT).into());
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[allow(unreachable_code)]
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
{
|
{
|
||||||
use rust_decimal::Decimal;
|
#[cfg(feature = "decimal")]
|
||||||
use std::convert::TryFrom;
|
if let Some(n) = rust_decimal::Decimal::from_f64(v) {
|
||||||
|
return Ok(Dynamic::from_decimal(n));
|
||||||
|
}
|
||||||
|
|
||||||
Decimal::try_from(v)
|
Err(Error::custom(format!(
|
||||||
.map(|v| v.into())
|
"floating-point number is not supported: {v}"
|
||||||
.map_err(Error::custom)
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,10 +351,7 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
_value: &T,
|
_value: &T,
|
||||||
) -> RhaiResultOf<Self::Ok> {
|
) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
return Ok(make_variant(_variant, to_dynamic(_value)?));
|
||||||
let content = to_dynamic(_value)?;
|
|
||||||
make_variant(_variant, content)
|
|
||||||
}
|
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return Err(ERR::ErrorMismatchDataType(
|
return Err(ERR::ErrorMismatchDataType(
|
||||||
"".into(),
|
"".into(),
|
||||||
@ -688,7 +704,7 @@ impl serde::ser::SerializeTupleVariant for TupleVariantSerializer {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn end(self) -> RhaiResultOf<Self::Ok> {
|
fn end(self) -> RhaiResultOf<Self::Ok> {
|
||||||
make_variant(self.variant, self.array.into())
|
Ok(make_variant(self.variant, self.array.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -716,14 +732,14 @@ impl serde::ser::SerializeStructVariant for StructVariantSerializer {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn end(self) -> RhaiResultOf<Self::Ok> {
|
fn end(self) -> RhaiResultOf<Self::Ok> {
|
||||||
make_variant(self.variant, self.map.into())
|
Ok(make_variant(self.variant, self.map.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn make_variant(variant: &'static str, value: Dynamic) -> RhaiResult {
|
fn make_variant(variant: &'static str, value: Dynamic) -> Dynamic {
|
||||||
let mut map = crate::Map::new();
|
let mut map = crate::Map::new();
|
||||||
map.insert(variant.into(), value);
|
map.insert(variant.into(), value);
|
||||||
Ok(map.into())
|
map.into()
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ impl Serialize for Dynamic {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref a, ..) => (**a).serialize(ser),
|
Union::Array(ref a, ..) => (**a).serialize(ser),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(ref a, ..) => ser.serialize_bytes(&**a),
|
Union::Blob(ref a, ..) => ser.serialize_bytes(a),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(ref m, ..) => {
|
Union::Map(ref m, ..) => {
|
||||||
let mut map = ser.serialize_map(Some(m.len()))?;
|
let mut map = ser.serialize_map(Some(m.len()))?;
|
||||||
|
162
src/tokenizer.rs
162
src/tokenizer.rs
@ -9,7 +9,6 @@ use crate::{Engine, Identifier, LexError, SmartString, StaticVec, INT, UNSIGNED_
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
char, fmt,
|
char, fmt,
|
||||||
iter::{FusedIterator, Peekable},
|
iter::{FusedIterator, Peekable},
|
||||||
@ -591,14 +590,67 @@ pub enum Token {
|
|||||||
impl fmt::Display for Token {
|
impl fmt::Display for Token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.write_str(&self.syntax())
|
#[allow(clippy::enum_glob_use)]
|
||||||
|
use Token::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
IntegerConstant(i) => write!(f, "{i}"),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
FloatConstant(v) => write!(f, "{v}"),
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
DecimalConstant(d) => write!(f, "{d}"),
|
||||||
|
StringConstant(s) => write!(f, r#""{s}""#),
|
||||||
|
InterpolatedString(..) => f.write_str("string"),
|
||||||
|
CharConstant(c) => write!(f, "{c}"),
|
||||||
|
Identifier(s) => f.write_str(s),
|
||||||
|
Reserved(s) => f.write_str(s),
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
Custom(s) => f.write_str(s),
|
||||||
|
LexError(err) => write!(f, "{err}"),
|
||||||
|
Comment(s) => f.write_str(s),
|
||||||
|
|
||||||
|
EOF => f.write_str("{EOF}"),
|
||||||
|
|
||||||
|
token => f.write_str(token.literal_syntax()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
|
/// Is the token a literal symbol?
|
||||||
|
#[must_use]
|
||||||
|
pub const fn is_literal(&self) -> bool {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
|
use Token::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
IntegerConstant(..) => false,
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
FloatConstant(..) => false,
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
DecimalConstant(..) => false,
|
||||||
|
StringConstant(..)
|
||||||
|
| InterpolatedString(..)
|
||||||
|
| CharConstant(..)
|
||||||
|
| Identifier(..)
|
||||||
|
| Reserved(..) => false,
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
Custom(..) => false,
|
||||||
|
LexError(..) | Comment(..) => false,
|
||||||
|
|
||||||
|
EOF => false,
|
||||||
|
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Get the literal syntax of the token.
|
/// Get the literal syntax of the token.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the token is not a literal symbol.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn literal_syntax(&self) -> &'static str {
|
pub const fn literal_syntax(&self) -> &'static str {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
@ -690,34 +742,7 @@ impl Token {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
As => "as",
|
As => "as",
|
||||||
|
|
||||||
_ => "ERROR: NOT A KEYWORD",
|
_ => panic!("token is not a literal symbol"),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the syntax of the token.
|
|
||||||
#[must_use]
|
|
||||||
pub fn syntax(&self) -> Cow<'static, str> {
|
|
||||||
use Token::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
IntegerConstant(i) => i.to_string().into(),
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
FloatConstant(f) => f.to_string().into(),
|
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
DecimalConstant(d) => d.to_string().into(),
|
|
||||||
StringConstant(s) => format!("\"{s}\"").into(),
|
|
||||||
InterpolatedString(..) => "string".into(),
|
|
||||||
CharConstant(c) => c.to_string().into(),
|
|
||||||
Identifier(s) => s.to_string().into(),
|
|
||||||
Reserved(s) => s.to_string().into(),
|
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
|
||||||
Custom(s) => s.to_string().into(),
|
|
||||||
LexError(err) => err.to_string().into(),
|
|
||||||
Comment(s) => s.to_string().into(),
|
|
||||||
|
|
||||||
EOF => "{EOF}".into(),
|
|
||||||
|
|
||||||
token => token.literal_syntax().into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,6 +827,7 @@ impl Token {
|
|||||||
/// Reverse lookup a symbol token from a piece of syntax.
|
/// Reverse lookup a symbol token from a piece of syntax.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn lookup_symbol_from_syntax(syntax: &str) -> Option<Self> {
|
pub fn lookup_symbol_from_syntax(syntax: &str) -> Option<Self> {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
Some(match syntax {
|
Some(match syntax {
|
||||||
@ -941,21 +967,20 @@ impl Token {
|
|||||||
/// (not sure about `fn` name).
|
/// (not sure about `fn` name).
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_next_unary(&self) -> bool {
|
pub const fn is_next_unary(&self) -> bool {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
LexError(..) |
|
|
||||||
SemiColon | // ; - is unary
|
SemiColon | // ; - is unary
|
||||||
Colon | // #{ foo: - is unary
|
Colon | // #{ foo: - is unary
|
||||||
Comma | // ( ... , -expr ) - is unary
|
Comma | // ( ... , -expr ) - is unary
|
||||||
//Period |
|
//Period |
|
||||||
//Elvis |
|
//Elvis |
|
||||||
//DoubleQuestion |
|
DoubleQuestion | // ?? - is unary
|
||||||
//QuestionBracket |
|
|
||||||
ExclusiveRange | // .. - is unary
|
ExclusiveRange | // .. - is unary
|
||||||
InclusiveRange | // ..= - is unary
|
InclusiveRange | // ..= - is unary
|
||||||
LeftBrace | // { -expr } - is unary
|
LeftBrace | // { -expr } - is unary
|
||||||
// RightBrace | { expr } - expr not unary & is closing
|
// RightBrace | // { expr } - expr not unary & is closing
|
||||||
LeftParen | // ( -expr ) - is unary
|
LeftParen | // ( -expr ) - is unary
|
||||||
// RightParen | // ( expr ) - expr not unary & is closing
|
// RightParen | // ( expr ) - expr not unary & is closing
|
||||||
LeftBracket | // [ -expr ] - is unary
|
LeftBracket | // [ -expr ] - is unary
|
||||||
@ -1002,6 +1027,11 @@ impl Token {
|
|||||||
Return |
|
Return |
|
||||||
Throw => true,
|
Throw => true,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
QuestionBracket => true, // ?[ - is unary
|
||||||
|
|
||||||
|
LexError(..) => true,
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1009,6 +1039,7 @@ impl Token {
|
|||||||
/// Get the precedence number of the token.
|
/// Get the precedence number of the token.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn precedence(&self) -> Option<Precedence> {
|
pub const fn precedence(&self) -> Option<Precedence> {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
Precedence::new(match self {
|
Precedence::new(match self {
|
||||||
@ -1041,6 +1072,7 @@ impl Token {
|
|||||||
/// Does an expression bind to the right (instead of left)?
|
/// Does an expression bind to the right (instead of left)?
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_bind_right(&self) -> bool {
|
pub const fn is_bind_right(&self) -> bool {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
@ -1054,6 +1086,7 @@ impl Token {
|
|||||||
/// Is this token a standard symbol used in the language?
|
/// Is this token a standard symbol used in the language?
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_standard_symbol(&self) -> bool {
|
pub const fn is_standard_symbol(&self) -> bool {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
@ -1080,6 +1113,7 @@ impl Token {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_standard_keyword(&self) -> bool {
|
pub const fn is_standard_keyword(&self) -> bool {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
@ -1127,7 +1161,7 @@ impl Token {
|
|||||||
impl From<Token> for String {
|
impl From<Token> for String {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(token: Token) -> Self {
|
fn from(token: Token) -> Self {
|
||||||
token.syntax().into()
|
token.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1476,13 +1510,13 @@ pub fn get_next_token(
|
|||||||
|
|
||||||
/// Test if the given character is a hex character.
|
/// Test if the given character is a hex character.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_hex_digit(c: char) -> bool {
|
const fn is_hex_digit(c: char) -> bool {
|
||||||
matches!(c, 'a'..='f' | 'A'..='F' | '0'..='9')
|
matches!(c, 'a'..='f' | 'A'..='F' | '0'..='9')
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test if the given character is a numeric digit.
|
/// Test if the given character is a numeric digit.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_numeric_digit(c: char) -> bool {
|
const fn is_numeric_digit(c: char) -> bool {
|
||||||
matches!(c, '0'..='9')
|
matches!(c, '0'..='9')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1662,21 +1696,8 @@ fn get_next_token_inner(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Parse number
|
// Parse number
|
||||||
return Some((
|
let token = radix_base.map_or_else(
|
||||||
if let Some(radix) = radix_base {
|
|| {
|
||||||
let result = &result[2..];
|
|
||||||
|
|
||||||
UNSIGNED_INT::from_str_radix(&result, radix)
|
|
||||||
.map(|v| v as INT)
|
|
||||||
.map_or_else(
|
|
||||||
|_| {
|
|
||||||
Token::LexError(
|
|
||||||
LERR::MalformedNumber(result.to_string()).into(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Token::IntegerConstant,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let num = INT::from_str(&result).map(Token::IntegerConstant);
|
let num = INT::from_str(&result).map(Token::IntegerConstant);
|
||||||
|
|
||||||
// If integer parsing is unnecessary, try float instead
|
// If integer parsing is unnecessary, try float instead
|
||||||
@ -1705,8 +1726,23 @@ fn get_next_token_inner(
|
|||||||
Token::LexError(LERR::MalformedNumber(result.to_string()).into())
|
Token::LexError(LERR::MalformedNumber(result.to_string()).into())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
num_pos,
|
|radix| {
|
||||||
));
|
let result = &result[2..];
|
||||||
|
|
||||||
|
UNSIGNED_INT::from_str_radix(result, radix)
|
||||||
|
.map(|v| v as INT)
|
||||||
|
.map_or_else(
|
||||||
|
|_| {
|
||||||
|
Token::LexError(
|
||||||
|
LERR::MalformedNumber(result.to_string()).into(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Token::IntegerConstant,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return Some((token, num_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
// letter or underscore ...
|
// letter or underscore ...
|
||||||
@ -1735,7 +1771,7 @@ fn get_next_token_inner(
|
|||||||
Some('\r') => {
|
Some('\r') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
// `\r\n
|
// `\r\n
|
||||||
if let Some('\n') = stream.peek_next() {
|
if stream.peek_next() == Some('\n') {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
}
|
}
|
||||||
pos.new_line();
|
pos.new_line();
|
||||||
@ -1763,7 +1799,7 @@ fn get_next_token_inner(
|
|||||||
// ' - character literal
|
// ' - character literal
|
||||||
('\'', '\'') => {
|
('\'', '\'') => {
|
||||||
return Some((
|
return Some((
|
||||||
Token::LexError(LERR::MalformedChar("".to_string()).into()),
|
Token::LexError(LERR::MalformedChar(String::new()).into()),
|
||||||
start_pos,
|
start_pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -1916,7 +1952,7 @@ fn get_next_token_inner(
|
|||||||
while let Some(c) = stream.get_next() {
|
while let Some(c) = stream.get_next() {
|
||||||
if c == '\r' {
|
if c == '\r' {
|
||||||
// \r\n
|
// \r\n
|
||||||
if let Some('\n') = stream.peek_next() {
|
if stream.peek_next() == Some('\n') {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
}
|
}
|
||||||
pos.new_line();
|
pos.new_line();
|
||||||
@ -2399,7 +2435,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
Some((Token::Reserved(s), pos)) => (match
|
Some((Token::Reserved(s), pos)) => (match
|
||||||
(s.as_str(),
|
(s.as_str(),
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
(!self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s)),
|
self.engine.custom_keywords.as_ref().map_or(false, |m| m.contains_key(&*s)),
|
||||||
#[cfg(feature = "no_custom_syntax")]
|
#[cfg(feature = "no_custom_syntax")]
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
@ -2436,7 +2472,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
#[cfg(feature = "no_custom_syntax")]
|
#[cfg(feature = "no_custom_syntax")]
|
||||||
(.., true) => unreachable!("no custom operators"),
|
(.., true) => unreachable!("no custom operators"),
|
||||||
// Reserved keyword that is not custom and disabled.
|
// Reserved keyword that is not custom and disabled.
|
||||||
(token, false) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token) => {
|
(token, false) if self.engine.disabled_symbols.as_ref().map_or(false,|m| m.contains(token)) => {
|
||||||
let msg = format!("reserved {} '{token}' is disabled", if is_valid_identifier(token) { "keyword"} else {"symbol"});
|
let msg = format!("reserved {} '{token}' is disabled", if is_valid_identifier(token) { "keyword"} else {"symbol"});
|
||||||
Token::LexError(LERR::ImproperSymbol(s.to_string(), msg).into())
|
Token::LexError(LERR::ImproperSymbol(s.to_string(), msg).into())
|
||||||
},
|
},
|
||||||
@ -2445,13 +2481,13 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
}, pos),
|
}, pos),
|
||||||
// Custom keyword
|
// Custom keyword
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Some((Token::Identifier(s), pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s) => {
|
Some((Token::Identifier(s), pos)) if self.engine.custom_keywords.as_ref().map_or(false,|m| m.contains_key(&*s)) => {
|
||||||
(Token::Custom(s), pos)
|
(Token::Custom(s), pos)
|
||||||
}
|
}
|
||||||
// Custom keyword/symbol - must be disabled
|
// Custom keyword/symbol - must be disabled
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Some((token, pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(token.literal_syntax()) => {
|
Some((token, pos)) if token.is_literal() && self.engine.custom_keywords.as_ref().map_or(false,|m| m.contains_key(token.literal_syntax())) => {
|
||||||
if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) {
|
if self.engine.disabled_symbols.as_ref().map_or(false,|m| m.contains(token.literal_syntax())) {
|
||||||
// Disabled standard keyword/symbol
|
// Disabled standard keyword/symbol
|
||||||
(Token::Custom(Box::new(token.literal_syntax().into())), pos)
|
(Token::Custom(Box::new(token.literal_syntax().into())), pos)
|
||||||
} else {
|
} else {
|
||||||
@ -2460,7 +2496,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Disabled symbol
|
// Disabled symbol
|
||||||
Some((token, pos)) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) => {
|
Some((token, pos)) if token.is_literal() && self.engine.disabled_symbols.as_ref().map_or(false,|m| m.contains(token.literal_syntax())) => {
|
||||||
(Token::Reserved(Box::new(token.literal_syntax().into())), pos)
|
(Token::Reserved(Box::new(token.literal_syntax().into())), pos)
|
||||||
}
|
}
|
||||||
// Normal symbol
|
// Normal symbol
|
||||||
|
@ -105,7 +105,7 @@ impl Add<BloomFilterU64> for &BloomFilterU64 {
|
|||||||
impl AddAssign<Self> for BloomFilterU64 {
|
impl AddAssign<Self> for BloomFilterU64 {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_assign(&mut self, rhs: Self) {
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
*self += &rhs
|
*self += &rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ pub struct CustomTypeInfo {
|
|||||||
|
|
||||||
/// _(internals)_ A collection of custom types.
|
/// _(internals)_ A collection of custom types.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
#[derive(Clone, Hash, Default)]
|
#[derive(Clone, Hash)]
|
||||||
pub struct CustomTypesCollection(BTreeMap<Identifier, CustomTypeInfo>);
|
pub struct CustomTypesCollection(BTreeMap<Identifier, CustomTypeInfo>);
|
||||||
|
|
||||||
impl fmt::Debug for CustomTypesCollection {
|
impl fmt::Debug for CustomTypesCollection {
|
||||||
@ -25,6 +25,13 @@ impl fmt::Debug for CustomTypesCollection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for CustomTypesCollection {
|
||||||
|
#[inline(always)]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CustomTypesCollection {
|
impl CustomTypesCollection {
|
||||||
/// Create a new [`CustomTypesCollection`].
|
/// Create a new [`CustomTypesCollection`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -158,7 +158,7 @@ impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
DynamicWriteLockInner::Reference(ref reference) => *reference,
|
DynamicWriteLockInner::Reference(ref reference) => reference,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED),
|
DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED),
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ impl<'d, T: Any + Clone> DerefMut for DynamicWriteLock<'d, T> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
DynamicWriteLockInner::Reference(ref mut reference) => *reference,
|
DynamicWriteLockInner::Reference(ref mut reference) => reference,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().expect(CHECKED),
|
DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().expect(CHECKED),
|
||||||
}
|
}
|
||||||
@ -640,6 +640,7 @@ impl fmt::Debug for Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use AccessMode::*;
|
use AccessMode::*;
|
||||||
|
|
||||||
impl Clone for Dynamic {
|
impl Clone for Dynamic {
|
||||||
@ -1088,7 +1089,7 @@ impl Dynamic {
|
|||||||
pub fn from<T: Variant + Clone>(value: T) -> Self {
|
pub fn from<T: Variant + Clone>(value: T) -> Self {
|
||||||
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
||||||
|
|
||||||
reify!(value, |v: Dynamic| return v);
|
reify!(value, |v: Self| return v);
|
||||||
reify!(value, |v: INT| return v.into());
|
reify!(value, |v: INT| return v.into());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -1187,7 +1188,7 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
self.flatten_in_place();
|
self.flatten_in_place();
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
if TypeId::of::<T>() == TypeId::of::<Self>() {
|
||||||
return Some(reify!(self => T));
|
return Some(reify!(self => T));
|
||||||
}
|
}
|
||||||
if TypeId::of::<T>() == TypeId::of::<()>() {
|
if TypeId::of::<T>() == TypeId::of::<()>() {
|
||||||
@ -1309,7 +1310,7 @@ impl Dynamic {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn cast<T: Any + Clone>(self) -> T {
|
pub fn cast<T: Any + Clone>(self) -> T {
|
||||||
// Bail out early if the return type needs no cast
|
// Bail out early if the return type needs no cast
|
||||||
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
if TypeId::of::<T>() == TypeId::of::<Self>() {
|
||||||
return reify!(self => T);
|
return reify!(self => T);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1710,10 +1711,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Unit(..) => true,
|
Union::Unit(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Unit(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Unit(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1724,10 +1724,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Int(..) => true,
|
Union::Int(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Int(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Int(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1741,10 +1740,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Float(..) => true,
|
Union::Float(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Float(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Float(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1758,10 +1756,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Decimal(..) => true,
|
Union::Decimal(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Decimal(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Decimal(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1772,10 +1769,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Bool(..) => true,
|
Union::Bool(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Bool(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Bool(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1786,10 +1782,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Char(..) => true,
|
Union::Char(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Char(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Char(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1800,10 +1795,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Str(..) => true,
|
Union::Str(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Str(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Str(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1817,10 +1811,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Array(..) => true,
|
Union::Array(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Array(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Array(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1834,10 +1827,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Blob(..) => true,
|
Union::Blob(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Blob(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Blob(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1851,10 +1843,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Map(..) => true,
|
Union::Map(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::Map(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::Map(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1865,10 +1856,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::FnPtr(..) => true,
|
Union::FnPtr(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::FnPtr(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::FnPtr(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1882,10 +1872,9 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::TimeStamp(..) => true,
|
Union::TimeStamp(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
Union::Shared(ref cell, ..) => {
|
||||||
Union::TimeStamp(..) => true,
|
matches!(crate::func::locked_read(cell).0, Union::TimeStamp(..))
|
||||||
_ => false,
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,10 +299,7 @@ impl EvalAltResult {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_pseudo_error(&self) -> bool {
|
pub const fn is_pseudo_error(&self) -> bool {
|
||||||
match self {
|
matches!(self, Self::LoopBreak(..) | Self::Return(..))
|
||||||
Self::LoopBreak(..) | Self::Return(..) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Can this error be caught?
|
/// Can this error be caught?
|
||||||
#[cold]
|
#[cold]
|
||||||
@ -357,20 +354,17 @@ impl EvalAltResult {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_system_exception(&self) -> bool {
|
pub const fn is_system_exception(&self) -> bool {
|
||||||
match self {
|
matches!(
|
||||||
Self::ErrorSystem(..) => true,
|
self,
|
||||||
Self::ErrorParsing(..) => true,
|
Self::ErrorSystem(..)
|
||||||
|
| Self::ErrorParsing(..)
|
||||||
Self::ErrorCustomSyntax(..)
|
| Self::ErrorCustomSyntax(..)
|
||||||
| Self::ErrorTooManyOperations(..)
|
| Self::ErrorTooManyOperations(..)
|
||||||
| Self::ErrorTooManyModules(..)
|
| Self::ErrorTooManyModules(..)
|
||||||
| Self::ErrorStackOverflow(..)
|
| Self::ErrorStackOverflow(..)
|
||||||
| Self::ErrorDataTooLarge(..) => true,
|
| Self::ErrorDataTooLarge(..)
|
||||||
|
| Self::ErrorTerminated(..)
|
||||||
Self::ErrorTerminated(..) => true,
|
)
|
||||||
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Get the [position][Position] of this error.
|
/// Get the [position][Position] of this error.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -459,7 +453,6 @@ impl EvalAltResult {
|
|||||||
/// Unwrap this error and get the very base error.
|
/// Unwrap this error and get the very base error.
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[must_use]
|
|
||||||
pub fn unwrap_inner(&self) -> &Self {
|
pub fn unwrap_inner(&self) -> &Self {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorInFunctionCall(.., err, _) | Self::ErrorInModule(.., err, _) => {
|
Self::ErrorInFunctionCall(.., err, _) | Self::ErrorInModule(.., err, _) => {
|
||||||
|
@ -14,7 +14,7 @@ use num_traits::float::FloatCore as Float;
|
|||||||
/// A type that wraps a floating-point number and implements [`Hash`].
|
/// A type that wraps a floating-point number and implements [`Hash`].
|
||||||
///
|
///
|
||||||
/// Not available under `no_float`.
|
/// Not available under `no_float`.
|
||||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd)]
|
||||||
pub struct FloatWrapper<F>(F);
|
pub struct FloatWrapper<F>(F);
|
||||||
|
|
||||||
impl Hash for FloatWrapper<crate::FLOAT> {
|
impl Hash for FloatWrapper<crate::FLOAT> {
|
||||||
|
@ -147,7 +147,6 @@ impl FromStr for ImmutableString {
|
|||||||
type Err = ();
|
type Err = ();
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let s: SmartString = s.into();
|
let s: SmartString = s.into();
|
||||||
Ok(Self(s.into()))
|
Ok(Self(s.into()))
|
||||||
|
@ -12,7 +12,6 @@ use std::prelude::v1::*;
|
|||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
marker::PhantomData,
|
|
||||||
ops::AddAssign,
|
ops::AddAssign,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,28 +23,23 @@ pub const MAX_STRING_LEN: usize = 24;
|
|||||||
|
|
||||||
/// _(internals)_ A cache for interned strings.
|
/// _(internals)_ A cache for interned strings.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
pub struct StringsInterner<'a> {
|
#[derive(Clone)]
|
||||||
/// Maximum number of strings interned.
|
#[must_use]
|
||||||
pub capacity: usize,
|
pub struct StringsInterner {
|
||||||
/// Maximum string length.
|
|
||||||
pub max_string_len: usize,
|
|
||||||
/// Cached strings.
|
/// Cached strings.
|
||||||
cache: StraightHashMap<ImmutableString>,
|
cache: StraightHashMap<ImmutableString>,
|
||||||
/// Bloom filter to avoid caching "one-hit wonders".
|
/// Bloom filter to avoid caching "one-hit wonders".
|
||||||
filter: BloomFilterU64,
|
bloom_filter: BloomFilterU64,
|
||||||
/// Take care of the lifetime parameter.
|
|
||||||
dummy: PhantomData<&'a ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for StringsInterner<'_> {
|
impl Default for StringsInterner {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for StringsInterner<'_> {
|
impl fmt::Debug for StringsInterner {
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
@ -53,17 +47,13 @@ impl fmt::Debug for StringsInterner<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StringsInterner<'_> {
|
impl StringsInterner {
|
||||||
/// Create a new [`StringsInterner`].
|
/// Create a new [`StringsInterner`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
capacity: MAX_INTERNED_STRINGS,
|
|
||||||
max_string_len: MAX_STRING_LEN,
|
|
||||||
cache: StraightHashMap::default(),
|
cache: StraightHashMap::default(),
|
||||||
filter: BloomFilterU64::new(),
|
bloom_filter: BloomFilterU64::new(),
|
||||||
dummy: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,22 +69,26 @@ impl StringsInterner<'_> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_with_mapper<S: AsRef<str>>(
|
pub fn get_with_mapper<S: AsRef<str>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &str,
|
category: &str,
|
||||||
mapper: impl FnOnce(S) -> ImmutableString,
|
mapper: impl FnOnce(S) -> ImmutableString,
|
||||||
text: S,
|
text: S,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
let key = text.as_ref();
|
let key = text.as_ref();
|
||||||
|
|
||||||
let hasher = &mut get_hasher();
|
let hasher = &mut get_hasher();
|
||||||
id.hash(hasher);
|
category.hash(hasher);
|
||||||
key.hash(hasher);
|
key.hash(hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
|
|
||||||
// Cache long strings only on the second try to avoid caching "one-hit wonders".
|
// Cache long strings only on the second try to avoid caching "one-hit wonders".
|
||||||
if key.len() > MAX_STRING_LEN && self.filter.is_absent_and_set(hash) {
|
if key.len() > MAX_STRING_LEN && self.bloom_filter.is_absent_and_set(hash) {
|
||||||
return mapper(text);
|
return mapper(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.cache.is_empty() {
|
||||||
|
self.cache.reserve(MAX_INTERNED_STRINGS);
|
||||||
|
}
|
||||||
|
|
||||||
let result = match self.cache.entry(hash) {
|
let result = match self.cache.entry(hash) {
|
||||||
Entry::Occupied(e) => return e.get().clone(),
|
Entry::Occupied(e) => return e.get().clone(),
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
@ -114,26 +108,22 @@ impl StringsInterner<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If the interner is over capacity, remove the longest entry that has the lowest count
|
/// If the interner is over capacity, remove the longest entry that has the lowest count
|
||||||
fn throttle_cache(&mut self, hash: u64) {
|
#[inline]
|
||||||
if self.cache.len() <= self.capacity {
|
fn throttle_cache(&mut self, skip_hash: u64) {
|
||||||
|
if self.cache.len() <= MAX_INTERNED_STRINGS {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave some buffer to grow when shrinking the cache.
|
// Leave some buffer to grow when shrinking the cache.
|
||||||
// We leave at least two entries, one for the empty string, and one for the string
|
// We leave at least two entries, one for the empty string, and one for the string
|
||||||
// that has just been inserted.
|
// that has just been inserted.
|
||||||
let max = if self.capacity < 5 {
|
while self.cache.len() > MAX_INTERNED_STRINGS - 3 {
|
||||||
2
|
|
||||||
} else {
|
|
||||||
self.capacity - 3
|
|
||||||
};
|
|
||||||
|
|
||||||
while self.cache.len() > max {
|
|
||||||
let (_, _, n) = self
|
let (_, _, n) = self
|
||||||
.cache
|
.cache
|
||||||
.iter()
|
.iter()
|
||||||
.fold((0, usize::MAX, 0), |(x, c, n), (&k, v)| {
|
.fold((0, usize::MAX, 0), |(x, c, n), (&k, v)| {
|
||||||
if k != hash && (v.strong_count() < c || (v.strong_count() == c && v.len() > x))
|
if k != skip_hash
|
||||||
|
&& (v.strong_count() < c || (v.strong_count() == c && v.len() > x))
|
||||||
{
|
{
|
||||||
(v.len(), v.strong_count(), k)
|
(v.len(), v.strong_count(), k)
|
||||||
} else {
|
} else {
|
||||||
@ -169,14 +159,14 @@ impl StringsInterner<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<Self> for StringsInterner<'_> {
|
impl AddAssign<Self> for StringsInterner {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_assign(&mut self, rhs: Self) {
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
self.cache.extend(rhs.cache.into_iter());
|
self.cache.extend(rhs.cache.into_iter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<&Self> for StringsInterner<'_> {
|
impl AddAssign<&Self> for StringsInterner {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_assign(&mut self, rhs: &Self) {
|
fn add_assign(&mut self, rhs: &Self) {
|
||||||
self.cache
|
self.cache
|
||||||
|
@ -175,7 +175,6 @@ impl ParseErrorType {
|
|||||||
/// Make a [`ParseError`] using the current type and position.
|
/// Make a [`ParseError`] using the current type and position.
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[must_use]
|
|
||||||
pub(crate) fn into_err(self, pos: Position) -> ParseError {
|
pub(crate) fn into_err(self, pos: Position) -> ParseError {
|
||||||
ParseError(self.into(), pos)
|
ParseError(self.into(), pos)
|
||||||
}
|
}
|
||||||
@ -299,7 +298,6 @@ impl ParseError {
|
|||||||
/// Get the [type][ParseErrorType] of this parse error.
|
/// Get the [type][ParseErrorType] of this parse error.
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[must_use]
|
|
||||||
pub const fn err_type(&self) -> &ParseErrorType {
|
pub const fn err_type(&self) -> &ParseErrorType {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
@ -316,7 +314,7 @@ impl From<ParseErrorType> for RhaiError {
|
|||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn from(err: ParseErrorType) -> Self {
|
fn from(err: ParseErrorType) -> Self {
|
||||||
Box::new(err.into())
|
Self::new(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +330,7 @@ impl From<ParseError> for RhaiError {
|
|||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn from(err: ParseError) -> Self {
|
fn from(err: ParseError) -> Self {
|
||||||
Box::new(err.into())
|
Self::new(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@ use std::prelude::v1::*;
|
|||||||
|
|
||||||
/// Run custom restoration logic upon the end of scope.
|
/// Run custom restoration logic upon the end of scope.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct RestoreOnDrop<'a, T, R: FnOnce(&mut T)> {
|
pub struct RestoreOnDrop<'a, T: ?Sized, R: FnOnce(&mut T)> {
|
||||||
value: &'a mut T,
|
value: &'a mut T,
|
||||||
restore: Option<R>,
|
restore: Option<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: FnOnce(&mut T)> RestoreOnDrop<'a, T, R> {
|
impl<'a, T: ?Sized, R: FnOnce(&mut T)> RestoreOnDrop<'a, T, R> {
|
||||||
/// Create a new [`RestoreOnDrop`] that locks a mutable reference and runs restoration logic at
|
/// Create a new [`RestoreOnDrop`] that locks a mutable reference and runs restoration logic at
|
||||||
/// the end of scope only when `need_restore` is `true`.
|
/// the end of scope only when `need_restore` is `true`.
|
||||||
///
|
///
|
||||||
@ -39,7 +39,7 @@ impl<'a, T, R: FnOnce(&mut T)> RestoreOnDrop<'a, T, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: FnOnce(&mut T)> Drop for RestoreOnDrop<'a, T, R> {
|
impl<'a, T: ?Sized, R: FnOnce(&mut T)> Drop for RestoreOnDrop<'a, T, R> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(restore) = self.restore.take() {
|
if let Some(restore) = self.restore.take() {
|
||||||
@ -48,7 +48,7 @@ impl<'a, T, R: FnOnce(&mut T)> Drop for RestoreOnDrop<'a, T, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: FnOnce(&mut T)> Deref for RestoreOnDrop<'a, T, R> {
|
impl<'a, T: ?Sized, R: FnOnce(&mut T)> Deref for RestoreOnDrop<'a, T, R> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -57,7 +57,7 @@ impl<'a, T, R: FnOnce(&mut T)> Deref for RestoreOnDrop<'a, T, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: FnOnce(&mut T)> DerefMut for RestoreOnDrop<'a, T, R> {
|
impl<'a, T: ?Sized, R: FnOnce(&mut T)> DerefMut for RestoreOnDrop<'a, T, R> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.value
|
self.value
|
||||||
|
@ -353,6 +353,43 @@ impl Scope<'_> {
|
|||||||
self.values.push(value);
|
self.values.push(value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
/// Remove the last entry from the [`Scope`].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics is the [`Scope`] is empty.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Scope;
|
||||||
|
///
|
||||||
|
/// let mut my_scope = Scope::new();
|
||||||
|
///
|
||||||
|
/// my_scope.push("x", 42_i64);
|
||||||
|
/// my_scope.push("y", 123_i64);
|
||||||
|
/// assert!(my_scope.contains("x"));
|
||||||
|
/// assert!(my_scope.contains("y"));
|
||||||
|
/// assert_eq!(my_scope.len(), 2);
|
||||||
|
///
|
||||||
|
/// my_scope.pop();
|
||||||
|
/// assert!(my_scope.contains("x"));
|
||||||
|
/// assert!(!my_scope.contains("y"));
|
||||||
|
/// assert_eq!(my_scope.len(), 1);
|
||||||
|
///
|
||||||
|
/// my_scope.pop();
|
||||||
|
/// assert!(!my_scope.contains("x"));
|
||||||
|
/// assert!(!my_scope.contains("y"));
|
||||||
|
/// assert_eq!(my_scope.len(), 0);
|
||||||
|
/// assert!(my_scope.is_empty());
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pop(&mut self) -> &mut Self {
|
||||||
|
self.names.pop().expect("`Scope` must not be empty");
|
||||||
|
self.values.pop().expect("`Scope` must not be empty");
|
||||||
|
self.aliases.pop().expect("`Scope` must not be empty");
|
||||||
|
self
|
||||||
|
}
|
||||||
/// Truncate (rewind) the [`Scope`] to a previous size.
|
/// Truncate (rewind) the [`Scope`] to a previous size.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -14,7 +14,7 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
engine.register_raw_fn(
|
engine.register_raw_fn(
|
||||||
"call_with_arg",
|
"call_with_arg",
|
||||||
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|
[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|
||||||
|context, args| {
|
|context, args| {
|
||||||
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>();
|
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>();
|
||||||
fn_ptr.call_raw(&context, None, [std::mem::take(args[1])])
|
fn_ptr.call_raw(&context, None, [std::mem::take(args[1])])
|
||||||
@ -165,7 +165,7 @@ fn test_closures() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
engine.register_raw_fn(
|
engine.register_raw_fn(
|
||||||
"custom_call",
|
"custom_call",
|
||||||
&[TypeId::of::<INT>(), TypeId::of::<FnPtr>()],
|
[TypeId::of::<INT>(), TypeId::of::<FnPtr>()],
|
||||||
|context, args| {
|
|context, args| {
|
||||||
let func = take(args[1]).cast::<FnPtr>();
|
let func = take(args[1]).cast::<FnPtr>();
|
||||||
|
|
||||||
@ -348,7 +348,7 @@ fn test_closures_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let p1 = Rc::new(RefCell::new(41));
|
let p1 = Rc::new(RefCell::new(41));
|
||||||
let p2 = Rc::new(RefCell::new(1));
|
let p2 = Rc::new(RefCell::new(1));
|
||||||
|
|
||||||
f(p1.clone(), p2.clone())?;
|
f(p1.clone(), p2)?;
|
||||||
|
|
||||||
assert_eq!(*p1.borrow(), 42);
|
assert_eq!(*p1.borrow(), 42);
|
||||||
|
|
||||||
|
@ -266,7 +266,8 @@ fn test_custom_syntax_raw() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*state = Dynamic::FALSE;
|
*state = Dynamic::FALSE;
|
||||||
Ok(Some("$ident$".into()))
|
Ok(Some("$ident$".into()))
|
||||||
}
|
}
|
||||||
2 => match stream[1].as_str() {
|
2 => {
|
||||||
|
match stream[1].as_str() {
|
||||||
"world" if state.as_bool().unwrap_or(false) => Ok(Some("$$world".into())),
|
"world" if state.as_bool().unwrap_or(false) => Ok(Some("$$world".into())),
|
||||||
"world" => Ok(Some("$$hello".into())),
|
"world" => Ok(Some("$$hello".into())),
|
||||||
"kitty" => {
|
"kitty" => {
|
||||||
@ -274,9 +275,9 @@ fn test_custom_syntax_raw() -> Result<(), Box<EvalAltResult>> {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
s => Err(LexError::ImproperSymbol(s.to_string(), String::new())
|
s => Err(LexError::ImproperSymbol(s.to_string(), String::new())
|
||||||
.into_err(Position::NONE)
|
.into_err(Position::NONE)),
|
||||||
.into()),
|
}
|
||||||
},
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
@ -59,13 +59,13 @@ fn test_debugger_state() -> Result<(), Box<EvalAltResult>> {
|
|||||||
// Print debugger state - which is an object map
|
// Print debugger state - which is an object map
|
||||||
println!(
|
println!(
|
||||||
"Current state = {}",
|
"Current state = {}",
|
||||||
context.global_runtime_state_mut().debugger.state()
|
context.global_runtime_state_mut().debugger().state()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Modify state
|
// Modify state
|
||||||
let mut state = context
|
let mut state = context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger_mut()
|
||||||
.state_mut()
|
.state_mut()
|
||||||
.write_lock::<Map>()
|
.write_lock::<Map>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -13,22 +13,20 @@ use rhai::Array;
|
|||||||
use rhai::Map;
|
use rhai::Map;
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use rhai::FLOAT;
|
use rhai::FLOAT;
|
||||||
#[cfg(feature = "no_float")]
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
||||||
assert!(to_dynamic(42_u64)?.is_int());
|
assert!(to_dynamic(42_u64)?.is_int());
|
||||||
assert!(to_dynamic(u64::MAX)?.is::<u64>());
|
|
||||||
assert!(to_dynamic(42 as INT)?.is_int());
|
assert!(to_dynamic(42 as INT)?.is_int());
|
||||||
assert!(to_dynamic(true)?.is_bool());
|
assert!(to_dynamic(true)?.is_bool());
|
||||||
assert!(to_dynamic(())?.is_unit());
|
assert!(to_dynamic(())?.is_unit());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
assert!(to_dynamic(123.456_f64)?.is::<f64>());
|
assert!(to_dynamic(123.456_f64)?.is::<FLOAT>());
|
||||||
assert!(to_dynamic(123.456_f32)?.is::<f32>());
|
assert!(to_dynamic(123.456_f32)?.is::<FLOAT>());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
@ -749,6 +747,31 @@ fn test_serde_json() -> serde_json::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "metadata")]
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
fn test_serde_json_numbers() -> serde_json::Result<()> {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
let d: Dynamic = serde_json::from_str("100000000000")?;
|
||||||
|
assert!(d.is::<INT>());
|
||||||
|
assert_eq!(d.as_int().unwrap(), 100000000000);
|
||||||
|
|
||||||
|
let d: Dynamic = serde_json::from_str("10000000000000000000")?;
|
||||||
|
assert!(d.is::<Decimal>());
|
||||||
|
assert_eq!(
|
||||||
|
d.as_decimal().unwrap(),
|
||||||
|
Decimal::from_str("10000000000000000000").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
let d: Dynamic = serde_json::from_str("10000000000000000000000000")?;
|
||||||
|
assert!(d.is::<FLOAT>());
|
||||||
|
assert_eq!(d.as_float().unwrap(), 10000000000000000000000000.0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn test_serde_optional() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_optional() -> Result<(), Box<EvalAltResult>> {
|
||||||
@ -825,7 +848,14 @@ fn test_serde_blob() -> Result<(), Box<EvalAltResult>> {
|
|||||||
fn test_serde_json_borrowed_string() {
|
fn test_serde_json_borrowed_string() {
|
||||||
let value = json!({ "a": "b" });
|
let value = json!({ "a": "b" });
|
||||||
println!("value: {value:?}");
|
println!("value: {value:?}");
|
||||||
let _: Dynamic = serde_json::from_value(value).unwrap();
|
|
||||||
|
let result: Dynamic = serde_json::from_value(value.clone()).unwrap();
|
||||||
|
println!("result: {result:?}");
|
||||||
|
|
||||||
|
let value2 = serde_json::to_value(&result).unwrap();
|
||||||
|
println!("value2: {value2:?}");
|
||||||
|
|
||||||
|
assert_eq!(value, value2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user