Streamline string handling.
This commit is contained in:
parent
3a1e93e324
commit
c4fe1782df
@ -293,7 +293,7 @@ pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenS
|
|||||||
Ok((engine_expr, export_name, rust_mod_path)) => {
|
Ok((engine_expr, export_name, rust_mod_path)) => {
|
||||||
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
||||||
proc_macro::TokenStream::from(quote! {
|
proc_macro::TokenStream::from(quote! {
|
||||||
#engine_expr.register_result_fn(&(#export_name), #gen_mod_path::dynamic_result_fn);
|
#engine_expr.register_result_fn(#export_name, #gen_mod_path::dynamic_result_fn);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(e) => e.to_compile_error().into(),
|
Err(e) => e.to_compile_error().into(),
|
||||||
|
@ -21,7 +21,7 @@ fn count_string_bytes(s: &str) -> INT {
|
|||||||
|
|
||||||
/// This version uses `ImmutableString` and `&str`.
|
/// This version uses `ImmutableString` and `&str`.
|
||||||
fn find_substring(s: ImmutableString, sub: &str) -> INT {
|
fn find_substring(s: ImmutableString, sub: &str) -> INT {
|
||||||
s.as_str().find(sub).map(|x| x as INT).unwrap_or(-1)
|
s.find(sub).map(|x| x as INT).unwrap_or(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<EvalAltResult>> {
|
fn main() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
@ -6,7 +6,7 @@ use crate::module::NamespaceRef;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::BTreeMap,
|
collections::{BTreeMap, BTreeSet},
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
@ -58,7 +58,7 @@ pub struct ScriptFnDef {
|
|||||||
pub params: StaticVec<ImmutableString>,
|
pub params: StaticVec<ImmutableString>,
|
||||||
/// Access to external variables.
|
/// Access to external variables.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
pub externals: StaticVec<ImmutableString>,
|
pub externals: BTreeSet<ImmutableString>,
|
||||||
/// Function doc-comments (if any).
|
/// Function doc-comments (if any).
|
||||||
pub comments: StaticVec<String>,
|
pub comments: StaticVec<String>,
|
||||||
}
|
}
|
||||||
|
@ -1349,7 +1349,7 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
if TypeId::of::<T>() == TypeId::of::<String>() {
|
if TypeId::of::<T>() == TypeId::of::<String>() {
|
||||||
return match &self.0 {
|
return match &self.0 {
|
||||||
Union::Str(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
|
Union::Str(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref() as &String),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ impl Imports {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|(i, key)| if key.as_str() == name { Some(i) } else { None })
|
.find_map(|(i, key)| if *key == name { Some(i) } else { None })
|
||||||
}
|
}
|
||||||
/// Push an imported [modules][Module] onto the stack.
|
/// Push an imported [modules][Module] onto the stack.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -996,7 +996,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if the variable is `this`
|
// Check if the variable is `this`
|
||||||
if name.as_str() == KEYWORD_THIS {
|
if *name == KEYWORD_THIS {
|
||||||
return if let Some(val) = this_ptr {
|
return if let Some(val) = this_ptr {
|
||||||
Ok(((*val).into(), *pos))
|
Ok(((*val).into(), *pos))
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,8 +13,8 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, Module, NativeCallContext,
|
scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module,
|
||||||
ParseError, Position, RhaiResult, Shared, StaticVec, AST,
|
NativeCallContext, ParseError, Position, RhaiResult, Shared, StaticVec, AST,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -52,7 +52,11 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn register_fn<A, F>(&mut self, name: &str, func: F) -> &mut Self
|
pub fn register_fn<A, F>(
|
||||||
|
&mut self,
|
||||||
|
name: impl AsRef<str> + Into<ImmutableString>,
|
||||||
|
func: F,
|
||||||
|
) -> &mut Self
|
||||||
where
|
where
|
||||||
F: RegisterNativeFunction<A, ()>,
|
F: RegisterNativeFunction<A, ()>,
|
||||||
{
|
{
|
||||||
@ -102,7 +106,11 @@ impl Engine {
|
|||||||
/// .expect_err("expecting division by zero error!");
|
/// .expect_err("expecting division by zero error!");
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn register_result_fn<A, F, R>(&mut self, name: &str, func: F) -> &mut Self
|
pub fn register_result_fn<A, F, R>(
|
||||||
|
&mut self,
|
||||||
|
name: impl AsRef<str> + Into<ImmutableString>,
|
||||||
|
func: F,
|
||||||
|
) -> &mut Self
|
||||||
where
|
where
|
||||||
F: RegisterNativeFunction<A, Result<R, Box<EvalAltResult>>>,
|
F: RegisterNativeFunction<A, Result<R, Box<EvalAltResult>>>,
|
||||||
{
|
{
|
||||||
@ -144,7 +152,7 @@ impl Engine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn register_raw_fn<T: Variant + Clone>(
|
pub fn register_raw_fn<T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: impl AsRef<str> + Into<ImmutableString>,
|
||||||
arg_types: &[TypeId],
|
arg_types: &[TypeId],
|
||||||
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
||||||
+ SendSync
|
+ SendSync
|
||||||
@ -878,25 +886,29 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn register_static_module(&mut self, name: &str, module: Shared<Module>) -> &mut Self {
|
pub fn register_static_module(
|
||||||
|
&mut self,
|
||||||
|
name: impl AsRef<str> + Into<ImmutableString>,
|
||||||
|
module: Shared<Module>,
|
||||||
|
) -> &mut Self {
|
||||||
fn register_static_module_raw(
|
fn register_static_module_raw(
|
||||||
root: &mut crate::stdlib::collections::BTreeMap<crate::ImmutableString, Shared<Module>>,
|
root: &mut crate::stdlib::collections::BTreeMap<crate::ImmutableString, Shared<Module>>,
|
||||||
name: &str,
|
name: impl AsRef<str> + Into<ImmutableString>,
|
||||||
module: Shared<Module>,
|
module: Shared<Module>,
|
||||||
) {
|
) {
|
||||||
let separator = crate::token::Token::DoubleColon.syntax();
|
let separator = crate::token::Token::DoubleColon.syntax();
|
||||||
|
|
||||||
if !name.contains(separator.as_ref()) {
|
if !name.as_ref().contains(separator.as_ref()) {
|
||||||
if !module.is_indexed() {
|
if !module.is_indexed() {
|
||||||
// Index the module (making a clone copy if necessary) if it is not indexed
|
// Index the module (making a clone copy if necessary) if it is not indexed
|
||||||
let mut module = crate::fn_native::shared_take_or_clone(module);
|
let mut module = crate::fn_native::shared_take_or_clone(module);
|
||||||
module.build_index();
|
module.build_index();
|
||||||
root.insert(name.trim().into(), module.into());
|
root.insert(name.into(), module.into());
|
||||||
} else {
|
} else {
|
||||||
root.insert(name.trim().into(), module);
|
root.insert(name.into(), module);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut iter = name.splitn(2, separator.as_ref());
|
let mut iter = name.as_ref().splitn(2, separator.as_ref());
|
||||||
let sub_module = iter.next().unwrap().trim();
|
let sub_module = iter.next().unwrap().trim();
|
||||||
let remainder = iter.next().unwrap().trim();
|
let remainder = iter.next().unwrap().trim();
|
||||||
|
|
||||||
@ -915,7 +927,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module);
|
register_static_module_raw(&mut self.global_sub_modules, name, module);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -927,7 +939,11 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[deprecated = "use `register_static_module` instead"]
|
#[deprecated = "use `register_static_module` instead"]
|
||||||
pub fn register_module(&mut self, name: &str, module: impl Into<Shared<Module>>) -> &mut Self {
|
pub fn register_module(
|
||||||
|
&mut self,
|
||||||
|
name: impl AsRef<str> + Into<ImmutableString>,
|
||||||
|
module: impl Into<Shared<Module>>,
|
||||||
|
) -> &mut Self {
|
||||||
self.register_static_module(name, module.into())
|
self.register_static_module(name, module.into())
|
||||||
}
|
}
|
||||||
/// Compile a string into an [`AST`], which can be used later for evaluation.
|
/// Compile a string into an [`AST`], which can be used later for evaluation.
|
||||||
@ -1013,7 +1029,6 @@ impl Engine {
|
|||||||
fn_native::shared_take_or_clone,
|
fn_native::shared_take_or_clone,
|
||||||
module::resolvers::StaticModuleResolver,
|
module::resolvers::StaticModuleResolver,
|
||||||
stdlib::collections::BTreeSet,
|
stdlib::collections::BTreeSet,
|
||||||
ImmutableString,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn collect_imports(
|
fn collect_imports(
|
||||||
@ -1271,9 +1286,14 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn parse_json(&self, json: &str, has_null: bool) -> Result<Map, Box<EvalAltResult>> {
|
pub fn parse_json(
|
||||||
|
&self,
|
||||||
|
json: impl AsRef<str>,
|
||||||
|
has_null: bool,
|
||||||
|
) -> Result<Map, Box<EvalAltResult>> {
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
|
|
||||||
|
let json = json.as_ref();
|
||||||
let mut scope = Default::default();
|
let mut scope = Default::default();
|
||||||
|
|
||||||
// Trims the JSON string and add a '#' in front
|
// Trims the JSON string and add a '#' in front
|
||||||
@ -1765,7 +1785,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
name: &str,
|
name: impl AsRef<str>,
|
||||||
args: impl crate::fn_args::FuncArgs,
|
args: impl crate::fn_args::FuncArgs,
|
||||||
) -> Result<T, Box<EvalAltResult>> {
|
) -> Result<T, Box<EvalAltResult>> {
|
||||||
let mut arg_values: crate::StaticVec<_> = Default::default();
|
let mut arg_values: crate::StaticVec<_> = Default::default();
|
||||||
@ -1844,7 +1864,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
eval_ast: bool,
|
eval_ast: bool,
|
||||||
name: &str,
|
name: impl AsRef<str>,
|
||||||
mut this_ptr: Option<&mut Dynamic>,
|
mut this_ptr: Option<&mut Dynamic>,
|
||||||
mut arg_values: impl AsMut<[Dynamic]>,
|
mut arg_values: impl AsMut<[Dynamic]>,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
@ -1867,7 +1887,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
eval_ast: bool,
|
eval_ast: bool,
|
||||||
name: &str,
|
name: impl AsRef<str>,
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
@ -1881,12 +1901,14 @@ impl Engine {
|
|||||||
|
|
||||||
let fn_def = ast
|
let fn_def = ast
|
||||||
.lib()
|
.lib()
|
||||||
.get_script_fn(name, args.len())
|
.get_script_fn(name.as_ref(), args.len())
|
||||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?;
|
.ok_or_else(|| {
|
||||||
|
EvalAltResult::ErrorFunctionNotFound(name.as_ref().into(), Position::NONE)
|
||||||
|
})?;
|
||||||
|
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
crate::fn_call::ensure_no_data_race(name, args, false)?;
|
crate::fn_call::ensure_no_data_race(name.as_ref(), args, false)?;
|
||||||
|
|
||||||
self.call_script_fn(
|
self.call_script_fn(
|
||||||
scope,
|
scope,
|
||||||
|
@ -236,7 +236,7 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn disable_symbol(&mut self, symbol: &str) -> &mut Self {
|
pub fn disable_symbol(&mut self, symbol: impl Into<String>) -> &mut Self {
|
||||||
self.disabled_symbols.insert(symbol.into());
|
self.disabled_symbols.insert(symbol.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn register_custom_operator(
|
pub fn register_custom_operator(
|
||||||
&mut self,
|
&mut self,
|
||||||
keyword: &str,
|
keyword: impl AsRef<str> + Into<String>,
|
||||||
precedence: u8,
|
precedence: u8,
|
||||||
) -> Result<&mut Self, String> {
|
) -> Result<&mut Self, String> {
|
||||||
let precedence = Precedence::new(precedence);
|
let precedence = Precedence::new(precedence);
|
||||||
@ -279,25 +279,25 @@ impl Engine {
|
|||||||
return Err("precedence cannot be zero".into());
|
return Err("precedence cannot be zero".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
match Token::lookup_from_syntax(keyword) {
|
match Token::lookup_from_syntax(keyword.as_ref()) {
|
||||||
// Standard identifiers, reserved keywords and custom keywords are OK
|
// Standard identifiers, reserved keywords and custom keywords are OK
|
||||||
None | Some(Token::Reserved(_)) | Some(Token::Custom(_)) => (),
|
None | Some(Token::Reserved(_)) | Some(Token::Custom(_)) => (),
|
||||||
// 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_keyword() => {
|
Some(token) if token.is_keyword() => {
|
||||||
if !self.disabled_symbols.contains(token.syntax().as_ref()) {
|
if !self.disabled_symbols.contains(token.syntax().as_ref()) {
|
||||||
return Err(format!("'{}' is a reserved keyword", keyword).into());
|
return Err(format!("'{}' is a reserved keyword", keyword.as_ref()).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Active standard symbols cannot be made custom
|
// Active standard symbols cannot be made custom
|
||||||
Some(token) if token.is_symbol() => {
|
Some(token) if token.is_symbol() => {
|
||||||
if !self.disabled_symbols.contains(token.syntax().as_ref()) {
|
if !self.disabled_symbols.contains(token.syntax().as_ref()) {
|
||||||
return Err(format!("'{}' is a reserved operator", keyword).into());
|
return Err(format!("'{}' is a reserved operator", keyword.as_ref()).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Active standard symbols cannot be made custom
|
// Active standard symbols cannot be made custom
|
||||||
Some(token) if !self.disabled_symbols.contains(token.syntax().as_ref()) => {
|
Some(token) if !self.disabled_symbols.contains(token.syntax().as_ref()) => {
|
||||||
return Err(format!("'{}' is a reserved symbol", keyword).into())
|
return Err(format!("'{}' is a reserved symbol", keyword.as_ref()).into())
|
||||||
}
|
}
|
||||||
// Disabled symbols are OK
|
// Disabled symbols are OK
|
||||||
Some(_) => (),
|
Some(_) => (),
|
||||||
|
@ -475,9 +475,9 @@ impl Engine {
|
|||||||
fn_def
|
fn_def
|
||||||
.lib
|
.lib
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|m| m.id())
|
.and_then(|m| m.id().map(|id| id.to_string()))
|
||||||
.unwrap_or_else(|| state.source.as_ref().map_or_else(|| "", |s| s.as_str()))
|
.or_else(|| state.source.as_ref().map(|s| s.to_string()))
|
||||||
.to_string(),
|
.unwrap_or_default(),
|
||||||
err,
|
err,
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
@ -651,14 +651,14 @@ impl Engine {
|
|||||||
crate::engine::KEYWORD_IS_DEF_FN
|
crate::engine::KEYWORD_IS_DEF_FN
|
||||||
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
|
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
|
||||||
{
|
{
|
||||||
let fn_name = args[0].read_lock::<ImmutableString>().unwrap();
|
let fn_name = &*args[0].read_lock::<ImmutableString>().unwrap();
|
||||||
let num_params = args[1].as_int().unwrap();
|
let num_params = args[1].as_int().unwrap();
|
||||||
|
|
||||||
return Ok((
|
return Ok((
|
||||||
if num_params < 0 {
|
if num_params < 0 {
|
||||||
Dynamic::FALSE
|
Dynamic::FALSE
|
||||||
} else {
|
} else {
|
||||||
let hash_script = calc_fn_hash(empty(), &fn_name, num_params as usize);
|
let hash_script = calc_fn_hash(empty(), fn_name, num_params as usize);
|
||||||
self.has_script_fn(Some(mods), state, lib, hash_script)
|
self.has_script_fn(Some(mods), state, lib, hash_script)
|
||||||
.into()
|
.into()
|
||||||
},
|
},
|
||||||
@ -737,7 +737,7 @@ impl Engine {
|
|||||||
if !func.externals.is_empty() {
|
if !func.externals.is_empty() {
|
||||||
captured
|
captured
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(name, _, _)| func.externals.iter().any(|ex| ex == name))
|
.filter(|(name, _, _)| func.externals.contains(name.as_ref()))
|
||||||
.for_each(|(name, value, _)| {
|
.for_each(|(name, value, _)| {
|
||||||
// Consume the scope values.
|
// Consume the scope values.
|
||||||
scope.push_dynamic(name, value);
|
scope.push_dynamic(name, value);
|
||||||
@ -1219,8 +1219,8 @@ impl Engine {
|
|||||||
state
|
state
|
||||||
.source
|
.source
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or_else(|| "", |s| s.as_str())
|
.map(|s| s.to_string())
|
||||||
.to_string(),
|
.unwrap_or_default(),
|
||||||
err,
|
err,
|
||||||
pos,
|
pos,
|
||||||
))
|
))
|
||||||
|
@ -184,10 +184,12 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn call_fn_dynamic_raw(
|
pub fn call_fn_dynamic_raw(
|
||||||
&self,
|
&self,
|
||||||
fn_name: &str,
|
fn_name: impl AsRef<str>,
|
||||||
is_method: bool,
|
is_method: bool,
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
|
let fn_name = fn_name.as_ref();
|
||||||
|
|
||||||
let hash = if is_method {
|
let hash = if is_method {
|
||||||
FnCallHash::from_script_and_native(
|
FnCallHash::from_script_and_native(
|
||||||
calc_fn_hash(empty(), fn_name, args.len() - 1),
|
calc_fn_hash(empty(), fn_name, args.len() - 1),
|
||||||
|
@ -7,7 +7,7 @@ use crate::fn_register::RegisterNativeFunction;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::BTreeMap,
|
||||||
fmt, format,
|
fmt, format,
|
||||||
iter::empty,
|
iter::empty,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
@ -16,6 +16,7 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
|
use crate::utils::StringInterner;
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, EvalAltResult, ImmutableString,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, EvalAltResult, ImmutableString,
|
||||||
NativeCallContext, Position, Shared, StaticVec,
|
NativeCallContext, Position, Shared, StaticVec,
|
||||||
@ -114,7 +115,7 @@ impl FuncInfo {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn calc_native_fn_hash<'a>(
|
fn calc_native_fn_hash<'a>(
|
||||||
modules: impl Iterator<Item = &'a str>,
|
modules: impl Iterator<Item = &'a str>,
|
||||||
fn_name: &str,
|
fn_name: impl AsRef<str>,
|
||||||
params: &[TypeId],
|
params: &[TypeId],
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let hash_script = calc_fn_hash(modules, fn_name, params.len());
|
let hash_script = calc_fn_hash(modules, fn_name, params.len());
|
||||||
@ -148,7 +149,7 @@ pub struct Module {
|
|||||||
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
|
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
|
||||||
contains_indexed_global_functions: bool,
|
contains_indexed_global_functions: bool,
|
||||||
/// Interned strings
|
/// Interned strings
|
||||||
interned_strings: BTreeSet<ImmutableString>,
|
interned_strings: StringInterner,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Module {
|
impl Default for Module {
|
||||||
@ -361,15 +362,6 @@ impl Module {
|
|||||||
self.indexed
|
self.indexed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an interned string.
|
|
||||||
fn get_interned_string(&mut self, s: &str) -> ImmutableString {
|
|
||||||
self.interned_strings.get(s).cloned().unwrap_or_else(|| {
|
|
||||||
let s: ImmutableString = s.into();
|
|
||||||
self.interned_strings.insert(s.clone());
|
|
||||||
s
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate signatures for all the non-private functions in the [`Module`].
|
/// Generate signatures for all the non-private functions in the [`Module`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
|
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
|
||||||
@ -625,7 +617,7 @@ impl Module {
|
|||||||
pub fn update_fn_metadata(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self {
|
pub fn update_fn_metadata(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self {
|
||||||
let param_names = arg_names
|
let param_names = arg_names
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&name| self.get_interned_string(name))
|
.map(|&name| self.interned_strings.get(name))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
||||||
@ -657,7 +649,7 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fn(
|
pub fn set_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: impl AsRef<str> + Into<ImmutableString>,
|
||||||
namespace: FnNamespace,
|
namespace: FnNamespace,
|
||||||
access: FnAccess,
|
access: FnAccess,
|
||||||
arg_names: Option<&[&str]>,
|
arg_names: Option<&[&str]>,
|
||||||
@ -690,11 +682,11 @@ impl Module {
|
|||||||
|
|
||||||
let hash_fn = calc_native_fn_hash(empty(), &name, ¶m_types);
|
let hash_fn = calc_native_fn_hash(empty(), &name, ¶m_types);
|
||||||
|
|
||||||
let name = self.get_interned_string(name);
|
let name = self.interned_strings.get(name);
|
||||||
let param_names = arg_names
|
let param_names = arg_names
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|p| p.iter())
|
.flat_map(|p| p.iter())
|
||||||
.map(|&name| self.get_interned_string(name))
|
.map(|&arg| self.interned_strings.get(arg))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.functions.insert(
|
self.functions.insert(
|
||||||
@ -783,16 +775,21 @@ impl Module {
|
|||||||
/// assert!(module.contains_fn(hash));
|
/// assert!(module.contains_fn(hash));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_raw_fn<T: Variant + Clone>(
|
pub fn set_raw_fn<N, T, F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: N,
|
||||||
namespace: FnNamespace,
|
namespace: FnNamespace,
|
||||||
access: FnAccess,
|
access: FnAccess,
|
||||||
arg_types: &[TypeId],
|
arg_types: &[TypeId],
|
||||||
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
func: F,
|
||||||
|
) -> u64
|
||||||
|
where
|
||||||
|
N: AsRef<str> + Into<ImmutableString>,
|
||||||
|
T: Variant + Clone,
|
||||||
|
F: Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
||||||
+ SendSync
|
+ SendSync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
) -> u64 {
|
{
|
||||||
let f =
|
let f =
|
||||||
move |ctx: NativeCallContext, args: &mut FnCallArgs| func(ctx, args).map(Dynamic::from);
|
move |ctx: NativeCallContext, args: &mut FnCallArgs| func(ctx, args).map(Dynamic::from);
|
||||||
|
|
||||||
@ -830,8 +827,9 @@ impl Module {
|
|||||||
/// assert!(module.contains_fn(hash));
|
/// assert!(module.contains_fn(hash));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_native_fn<ARGS, T, F>(&mut self, name: &str, func: F) -> u64
|
pub fn set_native_fn<ARGS, N, T, F>(&mut self, name: N, func: F) -> u64
|
||||||
where
|
where
|
||||||
|
N: AsRef<str> + Into<ImmutableString>,
|
||||||
T: Variant + Clone,
|
T: Variant + Clone,
|
||||||
F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
|
F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
|
||||||
{
|
{
|
||||||
@ -1079,11 +1077,16 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_indexer_get_set_fn<A, B, T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
get_fn: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
get_fn: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
set_fn: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
set_fn: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> (u64, u64) {
|
) -> (u64, u64)
|
||||||
|
where
|
||||||
|
A: Variant + Clone,
|
||||||
|
B: Variant + Clone,
|
||||||
|
T: Variant + Clone,
|
||||||
|
{
|
||||||
(
|
(
|
||||||
self.set_indexer_get_fn(get_fn),
|
self.set_indexer_get_fn(get_fn),
|
||||||
self.set_indexer_set_fn(set_fn),
|
self.set_indexer_set_fn(set_fn),
|
||||||
|
@ -22,7 +22,7 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
use crate::syntax::{CustomSyntax, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
use crate::syntax::{CustomSyntax, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream};
|
use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream};
|
||||||
use crate::utils::get_hasher;
|
use crate::utils::{get_hasher, StringInterner};
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position,
|
calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position,
|
||||||
Scope, Shared, StaticVec, AST,
|
Scope, Shared, StaticVec, AST,
|
||||||
@ -44,7 +44,7 @@ struct ParseState<'e> {
|
|||||||
/// Reference to the scripting [`Engine`].
|
/// Reference to the scripting [`Engine`].
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
/// Interned strings.
|
/// Interned strings.
|
||||||
interned_strings: BTreeMap<String, ImmutableString>,
|
interned_strings: StringInterner,
|
||||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||||
stack: Vec<(ImmutableString, AccessMode)>,
|
stack: Vec<(ImmutableString, AccessMode)>,
|
||||||
/// Size of the local variables stack upon entry of the current block scope.
|
/// Size of the local variables stack upon entry of the current block scope.
|
||||||
@ -160,24 +160,17 @@ impl<'e> ParseState<'e> {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, n)| **n == name)
|
.find(|&(_, n)| *n == name)
|
||||||
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an interned string, creating one if it is not yet interned.
|
/// Get an interned string, creating one if it is not yet interned.
|
||||||
|
#[inline(always)]
|
||||||
pub fn get_interned_string(
|
pub fn get_interned_string(
|
||||||
&mut self,
|
&mut self,
|
||||||
text: impl AsRef<str> + Into<ImmutableString>,
|
text: impl AsRef<str> + Into<ImmutableString>,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
#[allow(clippy::map_entry)]
|
self.interned_strings.get(text)
|
||||||
if !self.interned_strings.contains_key(text.as_ref()) {
|
|
||||||
let value = text.into();
|
|
||||||
self.interned_strings
|
|
||||||
.insert(value.clone().into(), value.clone());
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
self.interned_strings.get(text.as_ref()).unwrap().clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
src/utils.rs
35
src/utils.rs
@ -6,6 +6,7 @@ use crate::stdlib::{
|
|||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
|
collections::BTreeSet,
|
||||||
fmt,
|
fmt,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
@ -70,7 +71,11 @@ pub fn get_hasher() -> ahash::AHasher {
|
|||||||
///
|
///
|
||||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn calc_fn_hash<'a>(modules: impl Iterator<Item = &'a str>, fn_name: &str, num: usize) -> u64 {
|
pub fn calc_fn_hash<'a>(
|
||||||
|
modules: impl Iterator<Item = &'a str>,
|
||||||
|
fn_name: impl AsRef<str>,
|
||||||
|
num: usize,
|
||||||
|
) -> u64 {
|
||||||
let s = &mut get_hasher();
|
let s = &mut get_hasher();
|
||||||
|
|
||||||
// We always skip the first module
|
// We always skip the first module
|
||||||
@ -80,7 +85,7 @@ pub fn calc_fn_hash<'a>(modules: impl Iterator<Item = &'a str>, fn_name: &str, n
|
|||||||
.skip(1)
|
.skip(1)
|
||||||
.for_each(|m| m.hash(s));
|
.for_each(|m| m.hash(s));
|
||||||
len.hash(s);
|
len.hash(s);
|
||||||
fn_name.hash(s);
|
fn_name.as_ref().hash(s);
|
||||||
num.hash(s);
|
num.hash(s);
|
||||||
s.finish()
|
s.finish()
|
||||||
}
|
}
|
||||||
@ -137,7 +142,7 @@ pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 {
|
|||||||
/// assert_ne!(s2.as_str(), s.as_str());
|
/// assert_ne!(s2.as_str(), s.as_str());
|
||||||
/// assert_eq!(s, "hello, world!");
|
/// assert_eq!(s, "hello, world!");
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
#[derive(Clone, Eq, Ord, Hash, Default)]
|
||||||
pub struct ImmutableString(Shared<String>);
|
pub struct ImmutableString(Shared<String>);
|
||||||
|
|
||||||
impl Deref for ImmutableString {
|
impl Deref for ImmutableString {
|
||||||
@ -156,6 +161,13 @@ impl AsRef<String> for ImmutableString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Borrow<String> for ImmutableString {
|
impl Borrow<String> for ImmutableString {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn borrow(&self) -> &String {
|
fn borrow(&self) -> &String {
|
||||||
@ -559,7 +571,6 @@ impl PartialEq<ImmutableString> for String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<S: AsRef<str>> PartialOrd<S> for ImmutableString {
|
impl<S: AsRef<str>> PartialOrd<S> for ImmutableString {
|
||||||
#[inline(always)]
|
|
||||||
fn partial_cmp(&self, other: &S) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &S) -> Option<Ordering> {
|
||||||
self.as_str().partial_cmp(other.as_ref())
|
self.as_str().partial_cmp(other.as_ref())
|
||||||
}
|
}
|
||||||
@ -594,3 +605,19 @@ impl ImmutableString {
|
|||||||
shared_make_mut(&mut self.0)
|
shared_make_mut(&mut self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A collection of interned strings.
|
||||||
|
#[derive(Debug, Clone, Default, Hash)]
|
||||||
|
pub struct StringInterner(BTreeSet<ImmutableString>);
|
||||||
|
|
||||||
|
impl StringInterner {
|
||||||
|
/// Get an interned string, creating one if it is not yet interned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get(&mut self, text: impl AsRef<str> + Into<ImmutableString>) -> ImmutableString {
|
||||||
|
self.0.get(text.as_ref()).cloned().unwrap_or_else(|| {
|
||||||
|
let s = text.into();
|
||||||
|
self.0.insert(s.clone());
|
||||||
|
s
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user