Use Engine's interner.
This commit is contained in:
parent
6791ef64da
commit
d1913edf3c
@ -1,7 +1,6 @@
|
|||||||
//! Module that defines the public compilation API of [`Engine`].
|
//! Module that defines the public compilation API of [`Engine`].
|
||||||
|
|
||||||
use crate::parser::{ParseResult, ParseState};
|
use crate::parser::{ParseResult, ParseState};
|
||||||
use crate::types::StringsInterner;
|
|
||||||
use crate::{Engine, OptimizationLevel, Scope, AST};
|
use crate::{Engine, OptimizationLevel, Scope, AST};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -222,7 +221,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, StringsInterner::default(), tokenizer_control);
|
let interned_strings = &mut *self.interned_strings.borrow_mut();
|
||||||
|
let mut state = ParseState::new(self, 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"));
|
||||||
@ -295,7 +295,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, StringsInterner::default(), tokenizer_control);
|
let interned_strings = &mut *self.interned_strings.borrow_mut();
|
||||||
|
let mut state = ParseState::new(self, 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::eval::{Caches, GlobalRuntimeState};
|
use crate::eval::{Caches, GlobalRuntimeState};
|
||||||
use crate::parser::ParseState;
|
use crate::parser::ParseState;
|
||||||
use crate::types::{dynamic::Variant, StringsInterner};
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{
|
use crate::{
|
||||||
reify, Dynamic, Engine, OptimizationLevel, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR,
|
reify, Dynamic, Engine, OptimizationLevel, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR,
|
||||||
};
|
};
|
||||||
@ -117,12 +117,16 @@ impl Engine {
|
|||||||
script: &str,
|
script: &str,
|
||||||
) -> RhaiResultOf<T> {
|
) -> RhaiResultOf<T> {
|
||||||
let scripts = [script];
|
let scripts = [script];
|
||||||
|
let ast = {
|
||||||
|
let interned_strings = &mut *self.interned_strings.borrow_mut();
|
||||||
|
|
||||||
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, StringsInterner::default(), tokenizer_control);
|
|
||||||
|
let mut state = ParseState::new(self, 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 +134,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)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use crate::parser::{ParseSettingFlags, ParseState};
|
use crate::parser::{ParseSettingFlags, ParseState};
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::types::StringsInterner;
|
|
||||||
use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope};
|
use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -117,11 +116,12 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let ast = {
|
||||||
let scope = Scope::new();
|
let scope = Scope::new();
|
||||||
let mut state =
|
let interned_strings = &mut *self.interned_strings.borrow_mut();
|
||||||
ParseState::new(self, &scope, StringsInterner::default(), tokenizer_control);
|
let mut state = ParseState::new(self, &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.flags |= ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES,
|
|s| s.flags |= ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES,
|
||||||
@ -129,7 +129,8 @@ impl Engine {
|
|||||||
OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
OptimizationLevel::default(),
|
OptimizationLevel::default(),
|
||||||
)?;
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
self.eval_ast(&ast)
|
self.eval_ast(&ast)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use crate::eval::{Caches, GlobalRuntimeState};
|
use crate::eval::{Caches, GlobalRuntimeState};
|
||||||
use crate::parser::ParseState;
|
use crate::parser::ParseState;
|
||||||
use crate::types::StringsInterner;
|
|
||||||
use crate::{Engine, RhaiResultOf, Scope, AST};
|
use crate::{Engine, RhaiResultOf, Scope, AST};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -57,10 +56,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 *self.interned_strings.borrow_mut();
|
||||||
|
|
||||||
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, StringsInterner::default(), tokenizer_control);
|
|
||||||
let ast = self.parse(&mut stream.peekable(), &mut state, self.optimization_level)?;
|
let mut state = ParseState::new(self, 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`].
|
||||||
|
@ -103,7 +103,7 @@ pub struct Engine {
|
|||||||
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: BTreeSet<Identifier>,
|
||||||
|
@ -6,6 +6,9 @@ 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) {
|
||||||
@ -76,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;
|
||||||
}
|
}
|
||||||
@ -90,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 {
|
||||||
@ -121,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)
|
||||||
}
|
}
|
||||||
@ -146,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",
|
||||||
})
|
})
|
||||||
@ -171,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(),
|
||||||
);
|
);
|
||||||
@ -187,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(),
|
||||||
);
|
);
|
||||||
@ -196,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()
|
||||||
@ -205,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(),
|
||||||
@ -222,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(),
|
||||||
@ -240,9 +273,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(),
|
||||||
@ -251,41 +284,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 (name, m) in module.iter_sub_modules() {
|
for (name, m) in module.iter_sub_modules() {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
let mut ns = crate::SmartString::new_const();
|
let mut ns = SmartString::new_const();
|
||||||
write!(
|
write!(&mut ns, "{namespace}{}{name}", DoubleColon.literal_syntax()).unwrap();
|
||||||
&mut ns,
|
scan_module(engine, list, &ns, &**m, filter);
|
||||||
"{namespace}{}{name}",
|
|
||||||
crate::tokenizer::Token::DoubleColon.literal_syntax()
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
scan_module(dict, 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,13 +46,13 @@ const SMALL_SWITCH_RANGE: INT = 16;
|
|||||||
|
|
||||||
/// _(internals)_ A type that encapsulates the current state of the parser.
|
/// _(internals)_ A type that encapsulates the current state of the parser.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
pub struct ParseState<'e> {
|
pub struct ParseState<'e, 's> {
|
||||||
/// Input stream buffer containing the next character to read.
|
/// Input stream buffer containing the next character to read.
|
||||||
pub tokenizer_control: TokenizerControl,
|
pub tokenizer_control: TokenizerControl,
|
||||||
/// Controls whether parsing of an expression should stop given the next token.
|
/// Controls whether parsing of an expression should stop given the next token.
|
||||||
pub expr_filter: fn(&Token) -> bool,
|
pub expr_filter: fn(&Token) -> bool,
|
||||||
/// String interners.
|
/// String interners.
|
||||||
interned_strings: StringsInterner<'e>,
|
interned_strings: &'s mut StringsInterner,
|
||||||
/// External [scope][Scope] with constants.
|
/// External [scope][Scope] with constants.
|
||||||
pub scope: &'e Scope<'e>,
|
pub scope: &'e Scope<'e>,
|
||||||
/// Global runtime state.
|
/// Global runtime state.
|
||||||
@ -81,7 +81,7 @@ pub struct ParseState<'e> {
|
|||||||
pub max_expr_depth: usize,
|
pub max_expr_depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ParseState<'_> {
|
impl fmt::Debug for ParseState<'_, '_> {
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
@ -105,14 +105,14 @@ impl fmt::Debug for ParseState<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e> ParseState<'e> {
|
impl<'e, 's> ParseState<'e, 's> {
|
||||||
/// Create a new [`ParseState`].
|
/// Create a new [`ParseState`].
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &'e Scope,
|
scope: &'e Scope,
|
||||||
interned_strings: StringsInterner<'e>,
|
interned_strings: &'s mut StringsInterner,
|
||||||
tokenizer_control: TokenizerControl,
|
tokenizer_control: TokenizerControl,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -1422,15 +1422,17 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Token::Pipe | Token::Or if settings.has_option(LangOptions::ANON_FN) => {
|
Token::Pipe | Token::Or if settings.has_option(LangOptions::ANON_FN) => {
|
||||||
// Build new parse state
|
// Build new parse state
|
||||||
let interned_strings = std::mem::take(&mut state.interned_strings);
|
let new_interner = &mut StringsInterner::new();
|
||||||
|
|
||||||
let mut new_state = ParseState::new(
|
let mut new_state = ParseState::new(
|
||||||
self,
|
self,
|
||||||
state.scope,
|
state.scope,
|
||||||
interned_strings,
|
new_interner,
|
||||||
state.tokenizer_control.clone(),
|
state.tokenizer_control.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// We move the strings interner to the new parse state object by swapping it...
|
||||||
|
std::mem::swap(state.interned_strings, new_state.interned_strings);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
// Do not allow storing an index to a globally-imported module
|
// Do not allow storing an index to a globally-imported module
|
||||||
@ -1471,8 +1473,8 @@ impl Engine {
|
|||||||
|
|
||||||
let result = self.parse_anon_fn(input, &mut new_state, state, lib, new_settings);
|
let result = self.parse_anon_fn(input, &mut new_state, state, lib, new_settings);
|
||||||
|
|
||||||
// Restore parse state
|
// Restore the strings interner by swapping it back
|
||||||
state.interned_strings = new_state.interned_strings;
|
std::mem::swap(state.interned_strings, new_state.interned_strings);
|
||||||
|
|
||||||
let (expr, func) = result?;
|
let (expr, func) = result?;
|
||||||
|
|
||||||
@ -3301,12 +3303,10 @@ impl Engine {
|
|||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::Fn, pos) => {
|
(Token::Fn, pos) => {
|
||||||
// Build new parse state
|
// Build new parse state
|
||||||
let interned_strings = std::mem::take(&mut state.interned_strings);
|
|
||||||
|
|
||||||
let mut new_state = ParseState::new(
|
let mut new_state = ParseState::new(
|
||||||
self,
|
self,
|
||||||
state.scope,
|
state.scope,
|
||||||
interned_strings,
|
state.interned_strings,
|
||||||
state.tokenizer_control.clone(),
|
state.tokenizer_control.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3353,8 +3353,6 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Restore parse state
|
// Restore parse state
|
||||||
state.interned_strings = new_state.interned_strings;
|
|
||||||
|
|
||||||
let func = func?;
|
let func = func?;
|
||||||
|
|
||||||
let hash = calc_fn_hash(None, &func.name, func.params.len());
|
let hash = calc_fn_hash(None, &func.name, func.params.len());
|
||||||
|
@ -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,7 +23,9 @@ 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)]
|
||||||
|
#[must_use]
|
||||||
|
pub struct StringsInterner {
|
||||||
/// Maximum number of strings interned.
|
/// Maximum number of strings interned.
|
||||||
pub capacity: usize,
|
pub capacity: usize,
|
||||||
/// Maximum string length.
|
/// Maximum string length.
|
||||||
@ -33,19 +34,16 @@ pub struct StringsInterner<'a> {
|
|||||||
cache: StraightHashMap<ImmutableString>,
|
cache: StraightHashMap<ImmutableString>,
|
||||||
/// Bloom filter to avoid caching "one-hit wonders".
|
/// Bloom filter to avoid caching "one-hit wonders".
|
||||||
filter: BloomFilterU64,
|
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 +51,15 @@ 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,
|
capacity: MAX_INTERNED_STRINGS,
|
||||||
max_string_len: MAX_STRING_LEN,
|
max_string_len: MAX_STRING_LEN,
|
||||||
cache: StraightHashMap::default(),
|
cache: StraightHashMap::default(),
|
||||||
filter: BloomFilterU64::new(),
|
filter: BloomFilterU64::new(),
|
||||||
dummy: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,14 +165,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
|
||||||
|
Loading…
Reference in New Issue
Block a user