Use interned strings for AST nodes.
This commit is contained in:
parent
1c7b80ed13
commit
28743594d0
@ -60,7 +60,7 @@ pub struct CustomExpr {
|
|||||||
/// List of keywords.
|
/// List of keywords.
|
||||||
pub inputs: StaticVec<Expr>,
|
pub inputs: StaticVec<Expr>,
|
||||||
/// List of tokens actually parsed.
|
/// List of tokens actually parsed.
|
||||||
pub tokens: StaticVec<Identifier>,
|
pub tokens: StaticVec<ImmutableString>,
|
||||||
/// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement
|
/// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement
|
||||||
/// (e.g. introducing a new variable)?
|
/// (e.g. introducing a new variable)?
|
||||||
pub scope_may_be_changed: bool,
|
pub scope_may_be_changed: bool,
|
||||||
@ -183,7 +183,7 @@ pub struct FnCallExpr {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub namespace: super::Namespace,
|
pub namespace: super::Namespace,
|
||||||
/// Function name.
|
/// Function name.
|
||||||
pub name: Identifier,
|
pub name: ImmutableString,
|
||||||
/// Pre-calculated hashes.
|
/// Pre-calculated hashes.
|
||||||
pub hashes: FnCallHashes,
|
pub hashes: FnCallHashes,
|
||||||
/// List of function call argument expressions.
|
/// List of function call argument expressions.
|
||||||
@ -392,14 +392,18 @@ pub enum Expr {
|
|||||||
/// This is to avoid reading a pointer redirection during each variable access.
|
/// This is to avoid reading a pointer redirection during each variable access.
|
||||||
Variable(
|
Variable(
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Box<(Option<NonZeroUsize>, super::Namespace, u64, Identifier)>,
|
Box<(Option<NonZeroUsize>, super::Namespace, u64, ImmutableString)>,
|
||||||
#[cfg(feature = "no_module")] Box<(Option<NonZeroUsize>, (), u64, Identifier)>,
|
#[cfg(feature = "no_module")] Box<(Option<NonZeroUsize>, (), u64, ImmutableString)>,
|
||||||
Option<NonZeroU8>,
|
Option<NonZeroU8>,
|
||||||
Position,
|
Position,
|
||||||
),
|
),
|
||||||
/// Property access - ((getter, hash), (setter, hash), prop)
|
/// Property access - ((getter, hash), (setter, hash), prop)
|
||||||
Property(
|
Property(
|
||||||
Box<((Identifier, u64), (Identifier, u64), ImmutableString)>,
|
Box<(
|
||||||
|
(ImmutableString, u64),
|
||||||
|
(ImmutableString, u64),
|
||||||
|
ImmutableString,
|
||||||
|
)>,
|
||||||
Position,
|
Position,
|
||||||
),
|
),
|
||||||
/// xxx `.` method `(` expr `,` ... `)`
|
/// xxx `.` method `(` expr `,` ... `)`
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Module defining script identifiers.
|
//! Module defining script identifiers.
|
||||||
|
|
||||||
use crate::{Identifier, Position};
|
use crate::{ImmutableString, Position};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{
|
use std::{
|
||||||
@ -14,7 +14,7 @@ use std::{
|
|||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Ident {
|
pub struct Ident {
|
||||||
/// Identifier name.
|
/// Identifier name.
|
||||||
pub name: Identifier,
|
pub name: ImmutableString,
|
||||||
/// Position.
|
/// Position.
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ impl AsRef<str> for Ident {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Ident {
|
impl Deref for Ident {
|
||||||
type Target = Identifier;
|
type Target = ImmutableString;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -50,12 +50,6 @@ impl DerefMut for Ident {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ident {
|
impl Ident {
|
||||||
/// An empty [`Ident`].
|
|
||||||
pub const EMPTY: Self = Self {
|
|
||||||
name: Identifier::new_const(),
|
|
||||||
pos: Position::NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Get the name of the identifier as a string slice.
|
/// Get the name of the identifier as a string slice.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
|
|
||||||
use super::{FnAccess, StmtBlock};
|
use super::{FnAccess, StmtBlock};
|
||||||
use crate::{Identifier, SmartString, StaticVec};
|
use crate::{Identifier, ImmutableString, StaticVec};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{fmt, hash::Hash};
|
use std::{fmt, hash::Hash};
|
||||||
@ -38,11 +38,11 @@ pub struct ScriptFnDef {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub environ: Option<EncapsulatedEnviron>,
|
pub environ: Option<EncapsulatedEnviron>,
|
||||||
/// Function name.
|
/// Function name.
|
||||||
pub name: Identifier,
|
pub name: ImmutableString,
|
||||||
/// Function access mode.
|
/// Function access mode.
|
||||||
pub access: FnAccess,
|
pub access: FnAccess,
|
||||||
/// Names of function parameters.
|
/// Names of function parameters.
|
||||||
pub params: StaticVec<Identifier>,
|
pub params: StaticVec<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.
|
||||||
///
|
///
|
||||||
@ -71,7 +71,7 @@ impl fmt::Display for ScriptFnDef {
|
|||||||
self.name,
|
self.name,
|
||||||
self.params
|
self.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(SmartString::as_str)
|
.map(|s| s.as_str())
|
||||||
.collect::<StaticVec<_>>()
|
.collect::<StaticVec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
)
|
)
|
||||||
@ -132,7 +132,7 @@ impl<'a> From<&'a ScriptFnDef> for ScriptFnMetadata<'a> {
|
|||||||
fn from(value: &'a ScriptFnDef) -> Self {
|
fn from(value: &'a ScriptFnDef) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: &value.name,
|
name: &value.name,
|
||||||
params: value.params.iter().map(SmartString::as_str).collect(),
|
params: value.params.iter().map(|s| s.as_str()).collect(),
|
||||||
access: value.access,
|
access: value.access,
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
comments: value.comments.iter().map(<_>::as_ref).collect(),
|
comments: value.comments.iter().map(<_>::as_ref).collect(),
|
||||||
|
@ -594,7 +594,7 @@ pub enum Stmt {
|
|||||||
/// This variant does not map to any language structure. It is currently only used only to
|
/// This variant does not map to any language structure. It is currently only used only to
|
||||||
/// convert a normal variable into a shared variable when the variable is _captured_ by a closure.
|
/// convert a normal variable into a shared variable when the variable is _captured_ by a closure.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Share(Box<crate::Identifier>, Position),
|
Share(crate::ImmutableString, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Stmt {
|
impl Default for Stmt {
|
||||||
|
@ -94,7 +94,7 @@ impl Engine {
|
|||||||
if namespace.len() == 1 && namespace.root() == crate::engine::KEYWORD_GLOBAL {
|
if namespace.len() == 1 && namespace.root() == crate::engine::KEYWORD_GLOBAL {
|
||||||
if let Some(ref constants) = global.constants {
|
if let Some(ref constants) = global.constants {
|
||||||
if let Some(value) =
|
if let Some(value) =
|
||||||
crate::func::locked_write(constants).get_mut(var_name)
|
crate::func::locked_write(constants).get_mut(var_name.as_str())
|
||||||
{
|
{
|
||||||
let mut target: Target = value.clone().into();
|
let mut target: Target = value.clone().into();
|
||||||
// Module variables are constant
|
// Module variables are constant
|
||||||
@ -155,7 +155,7 @@ impl Engine {
|
|||||||
if lib
|
if lib
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|&m| m.iter_script_fn())
|
.flat_map(|&m| m.iter_script_fn())
|
||||||
.any(|(_, _, f, ..)| f == v.3) =>
|
.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(), Default::default()).into();
|
||||||
@ -497,7 +497,7 @@ 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).ok_or_else(|| {
|
let custom_def = self.custom_syntax.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(),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Global runtime state.
|
//! Global runtime state.
|
||||||
|
|
||||||
use crate::{Dynamic, Engine, Identifier};
|
use crate::{Dynamic, Engine, Identifier, ImmutableString};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{fmt, marker::PhantomData};
|
use std::{fmt, marker::PhantomData};
|
||||||
@ -9,7 +9,7 @@ use std::{fmt, marker::PhantomData};
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub type GlobalConstants =
|
pub type GlobalConstants =
|
||||||
crate::Shared<crate::Locked<std::collections::BTreeMap<Identifier, Dynamic>>>;
|
crate::Shared<crate::Locked<std::collections::BTreeMap<ImmutableString, Dynamic>>>;
|
||||||
|
|
||||||
/// _(internals)_ Global runtime states.
|
/// _(internals)_ Global runtime states.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
|
@ -913,7 +913,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if let Some(alias) = _alias {
|
if let Some(alias) = _alias {
|
||||||
scope.add_alias_by_index(scope.len() - 1, alias.name.clone());
|
scope.add_alias_by_index(scope.len() - 1, alias.name.as_str().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
@ -995,11 +995,11 @@ impl Engine {
|
|||||||
// Export statement
|
// Export statement
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Export(x, ..) => {
|
Stmt::Export(x, ..) => {
|
||||||
let (Ident { name, pos, .. }, 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.get_index(name) {
|
if let Some((index, ..)) = scope.get_index(name) {
|
||||||
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);
|
scope.add_alias_by_index(index, alias.into());
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
} else {
|
} else {
|
||||||
Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into())
|
Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into())
|
||||||
|
@ -759,12 +759,12 @@ impl Module {
|
|||||||
let num_params = fn_def.params.len();
|
let num_params = fn_def.params.len();
|
||||||
let hash_script = crate::calc_fn_hash(&fn_def.name, num_params);
|
let hash_script = crate::calc_fn_hash(&fn_def.name, num_params);
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let params_info = fn_def.params.iter().cloned().collect();
|
let params_info = fn_def.params.iter().map(Into::into).collect();
|
||||||
self.functions.insert(
|
self.functions.insert(
|
||||||
hash_script,
|
hash_script,
|
||||||
FuncInfo {
|
FuncInfo {
|
||||||
metadata: FnMetadata {
|
metadata: FnMetadata {
|
||||||
name: fn_def.name.clone(),
|
name: fn_def.name.as_str().into(),
|
||||||
namespace: FnNamespace::Internal,
|
namespace: FnNamespace::Internal,
|
||||||
access: fn_def.access,
|
access: fn_def.access,
|
||||||
params: num_params,
|
params: num_params,
|
||||||
|
@ -143,7 +143,7 @@ fn collect_fn_metadata(
|
|||||||
if !namespace.is_empty() {
|
if !namespace.is_empty() {
|
||||||
map.insert("namespace".into(), dict.get(namespace).into());
|
map.insert("namespace".into(), dict.get(namespace).into());
|
||||||
}
|
}
|
||||||
map.insert("name".into(), dict.get(&func.name).into());
|
map.insert("name".into(), dict.get(func.name.as_str()).into());
|
||||||
map.insert(
|
map.insert(
|
||||||
"access".into(),
|
"access".into(),
|
||||||
dict.get(match func.access {
|
dict.get(match func.access {
|
||||||
@ -160,7 +160,7 @@ fn collect_fn_metadata(
|
|||||||
"params".into(),
|
"params".into(),
|
||||||
func.params
|
func.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| dict.get(p).into())
|
.map(|p| dict.get(p.as_str()).into())
|
||||||
.collect::<Array>()
|
.collect::<Array>()
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
193
src/parser.rs
193
src/parser.rs
@ -43,13 +43,22 @@ const NEVER_ENDS: &str = "`Token`";
|
|||||||
/// Unroll `switch` ranges no larger than this.
|
/// Unroll `switch` ranges no larger than this.
|
||||||
const SMALL_SWITCH_RANGE: usize = 16;
|
const SMALL_SWITCH_RANGE: usize = 16;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct InternedStrings<'e> {
|
||||||
|
pub main: StringsInterner<'e>,
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
pub getters: StringsInterner<'e>,
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
pub setters: StringsInterner<'e>,
|
||||||
|
}
|
||||||
|
|
||||||
/// _(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> {
|
||||||
/// 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,
|
||||||
/// Interned strings.
|
/// String interners.
|
||||||
interned_strings: StringsInterner<'e>,
|
interned_strings: InternedStrings<'e>,
|
||||||
/// 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.
|
||||||
@ -71,10 +80,10 @@ pub struct ParseState<'e> {
|
|||||||
pub allow_capture: bool,
|
pub allow_capture: bool,
|
||||||
/// Encapsulates a local stack with imported [module][crate::Module] names.
|
/// Encapsulates a local stack with imported [module][crate::Module] names.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub imports: StaticVec<Identifier>,
|
pub imports: StaticVec<ImmutableString>,
|
||||||
/// List of globally-imported [module][crate::Module] names.
|
/// List of globally-imported [module][crate::Module] names.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub global_imports: StaticVec<Identifier>,
|
pub global_imports: StaticVec<ImmutableString>,
|
||||||
/// Maximum levels of expression nesting (0 for unlimited).
|
/// Maximum levels of expression nesting (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub max_expr_depth: usize,
|
pub max_expr_depth: usize,
|
||||||
@ -109,7 +118,7 @@ impl<'e> ParseState<'e> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &'e Scope,
|
scope: &'e Scope,
|
||||||
interned_strings: StringsInterner<'e>,
|
interners: InternedStrings<'e>,
|
||||||
tokenizer_control: TokenizerControl,
|
tokenizer_control: TokenizerControl,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -119,7 +128,7 @@ impl<'e> ParseState<'e> {
|
|||||||
external_vars: Vec::new(),
|
external_vars: Vec::new(),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
allow_capture: true,
|
allow_capture: true,
|
||||||
interned_strings,
|
interned_strings: interners,
|
||||||
scope,
|
scope,
|
||||||
global: GlobalRuntimeState::new(engine),
|
global: GlobalRuntimeState::new(engine),
|
||||||
stack: Scope::new(),
|
stack: Scope::new(),
|
||||||
@ -235,28 +244,10 @@ impl<'e> ParseState<'e> {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|&(.., n)| n == name)
|
.find(|(.., n)| n.as_str() == name)
|
||||||
.and_then(|(i, ..)| NonZeroUsize::new(i + 1))
|
.and_then(|(i, ..)| NonZeroUsize::new(i + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an interned identifier, creating one if it is not yet interned.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_identifier(&mut self, text: impl AsRef<str> + Into<ImmutableString>) -> Identifier {
|
|
||||||
self.get_identifier_with_prefix("", text).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an interned identifier, creating one if it is not yet interned.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_identifier_with_prefix(
|
|
||||||
&mut self,
|
|
||||||
prefix: impl AsRef<str>,
|
|
||||||
text: impl AsRef<str> + Into<ImmutableString>,
|
|
||||||
) -> Identifier {
|
|
||||||
self.interned_strings.get_with_prefix(prefix, text).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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)]
|
#[inline(always)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -265,19 +256,35 @@ impl<'e> ParseState<'e> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
text: impl AsRef<str> + Into<ImmutableString>,
|
text: impl AsRef<str> + Into<ImmutableString>,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
self.get_interned_string_with_prefix("", text)
|
self.interned_strings.main.get(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an interned string, creating one if it is not yet interned.
|
/// Get an interned property getter, creating one if it is not yet interned.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_interned_string_with_prefix(
|
pub fn get_interned_getter(
|
||||||
&mut self,
|
&mut self,
|
||||||
prefix: impl AsRef<str>,
|
|
||||||
text: impl AsRef<str> + Into<ImmutableString>,
|
text: impl AsRef<str> + Into<ImmutableString>,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
self.interned_strings.get_with_prefix(prefix, text)
|
self.interned_strings
|
||||||
|
.getters
|
||||||
|
.get_with_mapper(|s| crate::engine::make_getter(s.as_ref()).into(), text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get an interned property setter, creating one if it is not yet interned.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[inline(always)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_interned_setter(
|
||||||
|
&mut self,
|
||||||
|
text: impl AsRef<str> + Into<ImmutableString>,
|
||||||
|
) -> ImmutableString {
|
||||||
|
self.interned_strings
|
||||||
|
.setters
|
||||||
|
.get_with_mapper(|s| crate::engine::make_setter(s.as_ref()).into(), text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,18 +360,14 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Variable(x, ..) if !x.1.is_empty() => unreachable!("qualified property"),
|
Self::Variable(x, ..) if !x.1.is_empty() => unreachable!("qualified property"),
|
||||||
Self::Variable(x, .., pos) => {
|
Self::Variable(x, .., pos) => {
|
||||||
let ident = x.3;
|
let ident = x.3.clone();
|
||||||
let getter = state.get_identifier_with_prefix(crate::engine::FN_GET, &ident);
|
let getter = state.get_interned_getter(ident.as_str());
|
||||||
let hash_get = calc_fn_hash(&getter, 1);
|
let hash_get = calc_fn_hash(&getter, 1);
|
||||||
let setter = state.get_identifier_with_prefix(crate::engine::FN_SET, &ident);
|
let setter = state.get_interned_setter(ident.as_str());
|
||||||
let hash_set = calc_fn_hash(&setter, 2);
|
let hash_set = calc_fn_hash(&setter, 2);
|
||||||
|
|
||||||
Self::Property(
|
Self::Property(
|
||||||
Box::new((
|
Box::new(((getter, hash_get), (setter, hash_set), ident)),
|
||||||
(getter, hash_get),
|
|
||||||
(setter, hash_set),
|
|
||||||
state.get_interned_string(&ident),
|
|
||||||
)),
|
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -539,7 +542,7 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
id: Identifier,
|
id: ImmutableString,
|
||||||
no_args: bool,
|
no_args: bool,
|
||||||
capture_parent_scope: bool,
|
capture_parent_scope: bool,
|
||||||
#[cfg(not(feature = "no_module"))] namespace: crate::ast::Namespace,
|
#[cfg(not(feature = "no_module"))] namespace: crate::ast::Namespace,
|
||||||
@ -591,7 +594,7 @@ impl Engine {
|
|||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !is_global
|
&& !is_global
|
||||||
&& !state.global_imports.iter().any(|m| m == root)
|
&& !state.global_imports.iter().any(|m| m.as_str() == root)
|
||||||
&& !self.global_sub_modules.contains_key(root)
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
{
|
{
|
||||||
return Err(
|
return Err(
|
||||||
@ -615,7 +618,7 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_identifier(id),
|
name: id,
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
@ -659,7 +662,7 @@ impl Engine {
|
|||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !is_global
|
&& !is_global
|
||||||
&& !state.global_imports.iter().any(|m| m == root)
|
&& !state.global_imports.iter().any(|m| m.as_str() == root)
|
||||||
&& !self.global_sub_modules.contains_key(root)
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
{
|
{
|
||||||
return Err(PERR::ModuleUndefined(root.to_string())
|
return Err(PERR::ModuleUndefined(root.to_string())
|
||||||
@ -686,7 +689,7 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_identifier(id),
|
name: state.get_interned_string(id),
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
@ -1054,8 +1057,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
||||||
let name = state.get_identifier(name);
|
|
||||||
template.insert(name.clone(), crate::Dynamic::UNIT);
|
template.insert(name.clone(), crate::Dynamic::UNIT);
|
||||||
|
|
||||||
|
let name = state.get_interned_string(name);
|
||||||
map.push((Ident { name, pos }, expr));
|
map.push((Ident { name, pos }, expr));
|
||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
@ -1380,12 +1384,12 @@ impl Engine {
|
|||||||
// | ...
|
// | ...
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Token::Pipe | Token::Or if settings.options.contains(LangOptions::ANON_FN) => {
|
Token::Pipe | Token::Or if settings.options.contains(LangOptions::ANON_FN) => {
|
||||||
let interned_strings = std::mem::take(&mut state.interned_strings);
|
let interners = 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,
|
interners,
|
||||||
state.tokenizer_control.clone(),
|
state.tokenizer_control.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1564,7 +1568,7 @@ impl Engine {
|
|||||||
state.allow_capture = true;
|
state.allow_capture = true;
|
||||||
}
|
}
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
(None, ns, 0, state.get_identifier(s)).into(),
|
(None, ns, 0, state.get_interned_string(s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
)
|
)
|
||||||
@ -1578,7 +1582,7 @@ impl Engine {
|
|||||||
state.allow_capture = true;
|
state.allow_capture = true;
|
||||||
}
|
}
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
(None, ns, 0, state.get_identifier(s)).into(),
|
(None, ns, 0, state.get_interned_string(s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
)
|
)
|
||||||
@ -1605,7 +1609,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
(index, ns, 0, state.get_identifier(s)).into(),
|
(index, ns, 0, state.get_interned_string(s)).into(),
|
||||||
short_index,
|
short_index,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
)
|
)
|
||||||
@ -1629,7 +1633,7 @@ impl Engine {
|
|||||||
// Function call is allowed to have reserved keyword
|
// Function call is allowed to have reserved keyword
|
||||||
Token::LeftParen | Token::Bang | Token::Unit if is_keyword_function(&s) => {
|
Token::LeftParen | Token::Bang | Token::Unit if is_keyword_function(&s) => {
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
(None, ns, 0, state.get_identifier(s)).into(),
|
(None, ns, 0, state.get_interned_string(s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
)
|
)
|
||||||
@ -1637,7 +1641,7 @@ impl Engine {
|
|||||||
// Access to `this` as a variable is OK within a function scope
|
// Access to `this` as a variable is OK within a function scope
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ if &*s == KEYWORD_THIS && settings.in_fn_scope => Expr::Variable(
|
_ if &*s == KEYWORD_THIS && settings.in_fn_scope => Expr::Variable(
|
||||||
(None, ns, 0, state.get_identifier(s)).into(),
|
(None, ns, 0, state.get_interned_string(s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
),
|
),
|
||||||
@ -1764,7 +1768,7 @@ impl Engine {
|
|||||||
namespace.push(var_name_def);
|
namespace.push(var_name_def);
|
||||||
|
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
(None, namespace, 0, state.get_identifier(id2)).into(),
|
(None, namespace, 0, state.get_interned_string(id2)).into(),
|
||||||
None,
|
None,
|
||||||
pos2,
|
pos2,
|
||||||
)
|
)
|
||||||
@ -1842,7 +1846,7 @@ impl Engine {
|
|||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !is_global
|
&& !is_global
|
||||||
&& !state.global_imports.iter().any(|m| m == root)
|
&& !state.global_imports.iter().any(|m| m.as_str() == root)
|
||||||
&& !self.global_sub_modules.contains_key(root)
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
{
|
{
|
||||||
return Err(
|
return Err(
|
||||||
@ -1909,7 +1913,7 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(FnCallExpr {
|
Ok(FnCallExpr {
|
||||||
name: state.get_identifier("-"),
|
name: state.get_interned_string("-"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
@ -1936,7 +1940,7 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(FnCallExpr {
|
Ok(FnCallExpr {
|
||||||
name: state.get_identifier("+"),
|
name: state.get_interned_string("+"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
@ -1954,7 +1958,7 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(FnCallExpr {
|
Ok(FnCallExpr {
|
||||||
name: state.get_identifier("!"),
|
name: state.get_interned_string("!"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
@ -2329,7 +2333,7 @@ impl Engine {
|
|||||||
let hash = calc_fn_hash(&op, 2);
|
let hash = calc_fn_hash(&op, 2);
|
||||||
|
|
||||||
let op_base = FnCallExpr {
|
let op_base = FnCallExpr {
|
||||||
name: state.get_identifier(op.as_ref()),
|
name: state.get_interned_string(op.as_ref()),
|
||||||
hashes: FnCallHashes::from_native(hash),
|
hashes: FnCallHashes::from_native(hash),
|
||||||
pos,
|
pos,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -2401,7 +2405,7 @@ impl Engine {
|
|||||||
FnCallExpr {
|
FnCallExpr {
|
||||||
hashes: calc_fn_hash(OP_CONTAINS, 2).into(),
|
hashes: calc_fn_hash(OP_CONTAINS, 2).into(),
|
||||||
args,
|
args,
|
||||||
name: state.get_identifier(OP_CONTAINS),
|
name: state.get_interned_string(OP_CONTAINS),
|
||||||
..op_base
|
..op_base
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos)
|
.into_fn_call_expr(pos)
|
||||||
@ -2460,14 +2464,14 @@ impl Engine {
|
|||||||
if syntax.scope_may_be_changed {
|
if syntax.scope_may_be_changed {
|
||||||
// Add a barrier variable to the stack so earlier variables will not be matched.
|
// Add a barrier variable to the stack so earlier variables will not be matched.
|
||||||
// Variable searches stop at the first barrier.
|
// Variable searches stop at the first barrier.
|
||||||
let marker = state.get_identifier(SCOPE_SEARCH_BARRIER_MARKER);
|
let marker = state.get_interned_string(SCOPE_SEARCH_BARRIER_MARKER);
|
||||||
state.stack.push(marker, ());
|
state.stack.push(marker, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
let parse_func = &*syntax.parse;
|
let parse_func = &*syntax.parse;
|
||||||
let mut required_token: ImmutableString = key.into();
|
let mut required_token: ImmutableString = key.into();
|
||||||
|
|
||||||
tokens.push(required_token.clone().into());
|
tokens.push(required_token.clone());
|
||||||
segments.push(required_token.clone());
|
segments.push(required_token.clone());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -2491,7 +2495,7 @@ impl Engine {
|
|||||||
match required_token.as_str() {
|
match required_token.as_str() {
|
||||||
CUSTOM_SYNTAX_MARKER_IDENT => {
|
CUSTOM_SYNTAX_MARKER_IDENT => {
|
||||||
let (name, pos) = parse_var_name(input)?;
|
let (name, pos) = parse_var_name(input)?;
|
||||||
let name = state.get_identifier(name);
|
let name = state.get_interned_string(name);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let ns = crate::ast::Namespace::NONE;
|
let ns = crate::ast::Namespace::NONE;
|
||||||
@ -2499,19 +2503,19 @@ impl Engine {
|
|||||||
let ns = ();
|
let ns = ();
|
||||||
|
|
||||||
segments.push(name.clone().into());
|
segments.push(name.clone().into());
|
||||||
tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_IDENT));
|
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_IDENT));
|
||||||
inputs.push(Expr::Variable((None, ns, 0, name).into(), None, pos));
|
inputs.push(Expr::Variable((None, ns, 0, name).into(), None, pos));
|
||||||
}
|
}
|
||||||
CUSTOM_SYNTAX_MARKER_SYMBOL => {
|
CUSTOM_SYNTAX_MARKER_SYMBOL => {
|
||||||
let (symbol, pos) = parse_symbol(input)?;
|
let (symbol, pos) = parse_symbol(input)?;
|
||||||
let symbol = state.get_interned_string(symbol);
|
let symbol = state.get_interned_string(symbol);
|
||||||
segments.push(symbol.clone());
|
segments.push(symbol.clone());
|
||||||
tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_SYMBOL));
|
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_SYMBOL));
|
||||||
inputs.push(Expr::StringConstant(symbol, pos));
|
inputs.push(Expr::StringConstant(symbol, pos));
|
||||||
}
|
}
|
||||||
CUSTOM_SYNTAX_MARKER_EXPR => {
|
CUSTOM_SYNTAX_MARKER_EXPR => {
|
||||||
inputs.push(self.parse_expr(input, state, lib, settings)?);
|
inputs.push(self.parse_expr(input, state, lib, settings)?);
|
||||||
let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_EXPR);
|
let keyword = state.get_interned_string(CUSTOM_SYNTAX_MARKER_EXPR);
|
||||||
segments.push(keyword.clone().into());
|
segments.push(keyword.clone().into());
|
||||||
tokens.push(keyword);
|
tokens.push(keyword);
|
||||||
}
|
}
|
||||||
@ -2519,7 +2523,7 @@ impl Engine {
|
|||||||
match self.parse_block(input, state, lib, settings)? {
|
match self.parse_block(input, state, lib, settings)? {
|
||||||
block @ Stmt::Block(..) => {
|
block @ Stmt::Block(..) => {
|
||||||
inputs.push(Expr::Stmt(Box::new(block.into())));
|
inputs.push(Expr::Stmt(Box::new(block.into())));
|
||||||
let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_BLOCK);
|
let keyword = state.get_interned_string(CUSTOM_SYNTAX_MARKER_BLOCK);
|
||||||
segments.push(keyword.clone().into());
|
segments.push(keyword.clone().into());
|
||||||
tokens.push(keyword);
|
tokens.push(keyword);
|
||||||
}
|
}
|
||||||
@ -2530,7 +2534,7 @@ impl Engine {
|
|||||||
(b @ (Token::True | Token::False), pos) => {
|
(b @ (Token::True | Token::False), pos) => {
|
||||||
inputs.push(Expr::BoolConstant(b == Token::True, pos));
|
inputs.push(Expr::BoolConstant(b == Token::True, pos));
|
||||||
segments.push(state.get_interned_string(b.literal_syntax()));
|
segments.push(state.get_interned_string(b.literal_syntax()));
|
||||||
tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_BOOL));
|
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_BOOL));
|
||||||
}
|
}
|
||||||
(.., pos) => {
|
(.., pos) => {
|
||||||
return Err(
|
return Err(
|
||||||
@ -2543,7 +2547,7 @@ impl Engine {
|
|||||||
(Token::IntegerConstant(i), pos) => {
|
(Token::IntegerConstant(i), pos) => {
|
||||||
inputs.push(Expr::IntegerConstant(i, pos));
|
inputs.push(Expr::IntegerConstant(i, pos));
|
||||||
segments.push(i.to_string().into());
|
segments.push(i.to_string().into());
|
||||||
tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_INT));
|
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_INT));
|
||||||
}
|
}
|
||||||
(.., pos) => {
|
(.., pos) => {
|
||||||
return Err(
|
return Err(
|
||||||
@ -2557,7 +2561,7 @@ impl Engine {
|
|||||||
(Token::FloatConstant(f), pos) => {
|
(Token::FloatConstant(f), pos) => {
|
||||||
inputs.push(Expr::FloatConstant(f, pos));
|
inputs.push(Expr::FloatConstant(f, pos));
|
||||||
segments.push(f.to_string().into());
|
segments.push(f.to_string().into());
|
||||||
tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_FLOAT));
|
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_FLOAT));
|
||||||
}
|
}
|
||||||
(.., pos) => {
|
(.., pos) => {
|
||||||
return Err(PERR::MissingSymbol(
|
return Err(PERR::MissingSymbol(
|
||||||
@ -2571,7 +2575,7 @@ impl Engine {
|
|||||||
let s = state.get_interned_string(s);
|
let s = state.get_interned_string(s);
|
||||||
inputs.push(Expr::StringConstant(s.clone(), pos));
|
inputs.push(Expr::StringConstant(s.clone(), pos));
|
||||||
segments.push(s);
|
segments.push(s);
|
||||||
tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_STRING));
|
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_STRING));
|
||||||
}
|
}
|
||||||
(.., pos) => {
|
(.., pos) => {
|
||||||
return Err(
|
return Err(
|
||||||
@ -2835,11 +2839,11 @@ impl Engine {
|
|||||||
state.stack.push(name.clone(), ());
|
state.stack.push(name.clone(), ());
|
||||||
}
|
}
|
||||||
let counter_var = Ident {
|
let counter_var = Ident {
|
||||||
name: state.get_identifier(counter_name),
|
name: state.get_interned_string(counter_name),
|
||||||
pos: counter_pos,
|
pos: counter_pos,
|
||||||
};
|
};
|
||||||
|
|
||||||
let loop_var = state.get_identifier(name);
|
let loop_var = state.get_interned_string(name);
|
||||||
state.stack.push(loop_var.clone(), ());
|
state.stack.push(loop_var.clone(), ());
|
||||||
let loop_var = Ident {
|
let loop_var = Ident {
|
||||||
name: loop_var,
|
name: loop_var,
|
||||||
@ -2912,7 +2916,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = state.get_identifier(name);
|
let name = state.get_interned_string(name);
|
||||||
|
|
||||||
// let name = ...
|
// let name = ...
|
||||||
let expr = if match_token(input, Token::Equals).0 {
|
let expr = if match_token(input, Token::Equals).0 {
|
||||||
@ -2978,14 +2982,18 @@ impl Engine {
|
|||||||
// import expr ...
|
// import expr ...
|
||||||
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
// import expr as ...
|
// import expr;
|
||||||
if !match_token(input, Token::As).0 {
|
if !match_token(input, Token::As).0 {
|
||||||
return Ok(Stmt::Import((expr, Ident::EMPTY).into(), settings.pos));
|
let empty = Ident {
|
||||||
|
name: state.get_interned_string(""),
|
||||||
|
pos: Position::NONE,
|
||||||
|
};
|
||||||
|
return Ok(Stmt::Import((expr, empty).into(), settings.pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
// import expr as name ...
|
// import expr as name ...
|
||||||
let (name, pos) = parse_var_name(input)?;
|
let (name, pos) = parse_var_name(input)?;
|
||||||
let name = state.get_identifier(name);
|
let name = state.get_interned_string(name);
|
||||||
state.imports.push(name.clone());
|
state.imports.push(name.clone());
|
||||||
|
|
||||||
Ok(Stmt::Import(
|
Ok(Stmt::Import(
|
||||||
@ -3038,11 +3046,11 @@ impl Engine {
|
|||||||
|
|
||||||
let export = (
|
let export = (
|
||||||
Ident {
|
Ident {
|
||||||
name: state.get_identifier(id),
|
name: state.get_interned_string(id),
|
||||||
pos: id_pos,
|
pos: id_pos,
|
||||||
},
|
},
|
||||||
Ident {
|
Ident {
|
||||||
name: state.get_identifier(alias.as_ref().map_or("", <_>::as_ref)),
|
name: state.get_interned_string(alias.as_ref().map_or("", <_>::as_ref)),
|
||||||
pos: alias_pos,
|
pos: alias_pos,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -3251,12 +3259,12 @@ impl Engine {
|
|||||||
|
|
||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::Fn, pos) => {
|
(Token::Fn, pos) => {
|
||||||
let interned_strings = std::mem::take(&mut state.interned_strings);
|
let interners = 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,
|
interners,
|
||||||
state.tokenizer_control.clone(),
|
state.tokenizer_control.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3451,11 +3459,14 @@ impl Engine {
|
|||||||
.into_err(err_pos));
|
.into_err(err_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = state.get_identifier(name);
|
let name = state.get_interned_string(name);
|
||||||
state.stack.push(name.clone(), ());
|
state.stack.push(name.clone(), ());
|
||||||
Ident { name, pos }
|
Ident { name, pos }
|
||||||
} else {
|
} else {
|
||||||
Ident::EMPTY
|
Ident {
|
||||||
|
name: state.get_interned_string(""),
|
||||||
|
pos: Position::NONE,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// try { try_block } catch ( var ) { catch_block }
|
// try { try_block } catch ( var ) { catch_block }
|
||||||
@ -3515,7 +3526,7 @@ impl Engine {
|
|||||||
(.., pos) => return Err(PERR::FnMissingParams(name.to_string()).into_err(*pos)),
|
(.., pos) => return Err(PERR::FnMissingParams(name.to_string()).into_err(*pos)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut params = StaticVec::new_const();
|
let mut params = StaticVec::<(ImmutableString, _)>::new_const();
|
||||||
|
|
||||||
if !no_params {
|
if !no_params {
|
||||||
let sep_err = format!("to separate the parameters of function '{name}'");
|
let sep_err = format!("to separate the parameters of function '{name}'");
|
||||||
@ -3524,11 +3535,11 @@ impl Engine {
|
|||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::RightParen, ..) => break,
|
(Token::RightParen, ..) => break,
|
||||||
(Token::Identifier(s), pos) => {
|
(Token::Identifier(s), pos) => {
|
||||||
if params.iter().any(|(p, _)| p == &*s) {
|
if params.iter().any(|(p, _)| p.as_str() == &*s) {
|
||||||
return Err(PERR::FnDuplicatedParam(name.to_string(), s.to_string())
|
return Err(PERR::FnDuplicatedParam(name.to_string(), s.to_string())
|
||||||
.into_err(pos));
|
.into_err(pos));
|
||||||
}
|
}
|
||||||
let s = state.get_identifier(s);
|
let s = state.get_interned_string(s);
|
||||||
state.stack.push(s.clone(), ());
|
state.stack.push(s.clone(), ());
|
||||||
params.push((s, pos));
|
params.push((s, pos));
|
||||||
}
|
}
|
||||||
@ -3567,7 +3578,7 @@ impl Engine {
|
|||||||
params.shrink_to_fit();
|
params.shrink_to_fit();
|
||||||
|
|
||||||
Ok(ScriptFnDef {
|
Ok(ScriptFnDef {
|
||||||
name: state.get_identifier(name),
|
name: state.get_interned_string(name),
|
||||||
access,
|
access,
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
@ -3617,7 +3628,7 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let expr = FnCallExpr {
|
let expr = FnCallExpr {
|
||||||
name: state.get_identifier(crate::engine::KEYWORD_FN_PTR_CURRY),
|
name: state.get_interned_string(crate::engine::KEYWORD_FN_PTR_CURRY),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(
|
hashes: FnCallHashes::from_native(calc_fn_hash(
|
||||||
crate::engine::KEYWORD_FN_PTR_CURRY,
|
crate::engine::KEYWORD_FN_PTR_CURRY,
|
||||||
num_externals + 1,
|
num_externals + 1,
|
||||||
@ -3634,7 +3645,7 @@ impl Engine {
|
|||||||
statements.extend(
|
statements.extend(
|
||||||
externals
|
externals
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|crate::ast::Ident { name, pos }| Stmt::Share(name.into(), pos)),
|
.map(|crate::ast::Ident { name, pos }| Stmt::Share(name, pos)),
|
||||||
);
|
);
|
||||||
statements.push(Stmt::Expr(expr.into()));
|
statements.push(Stmt::Expr(expr.into()));
|
||||||
Expr::Stmt(crate::ast::StmtBlock::new(statements, pos, Position::NONE).into())
|
Expr::Stmt(crate::ast::StmtBlock::new(statements, pos, Position::NONE).into())
|
||||||
@ -3653,18 +3664,18 @@ impl Engine {
|
|||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
let mut params_list = StaticVec::new_const();
|
let mut params_list = StaticVec::<ImmutableString>::new_const();
|
||||||
|
|
||||||
if input.next().expect(NEVER_ENDS).0 != Token::Or && !match_token(input, Token::Pipe).0 {
|
if input.next().expect(NEVER_ENDS).0 != Token::Or && !match_token(input, Token::Pipe).0 {
|
||||||
loop {
|
loop {
|
||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::Pipe, ..) => break,
|
(Token::Pipe, ..) => break,
|
||||||
(Token::Identifier(s), pos) => {
|
(Token::Identifier(s), pos) => {
|
||||||
if params_list.iter().any(|p| p == &*s) {
|
if params_list.iter().any(|p| p.as_str() == &*s) {
|
||||||
return Err(PERR::FnDuplicatedParam("".to_string(), s.to_string())
|
return Err(PERR::FnDuplicatedParam("".to_string(), s.to_string())
|
||||||
.into_err(pos));
|
.into_err(pos));
|
||||||
}
|
}
|
||||||
let s = state.get_identifier(s);
|
let s = state.get_interned_string(s);
|
||||||
state.stack.push(s.clone(), ());
|
state.stack.push(s.clone(), ());
|
||||||
params_list.push(s);
|
params_list.push(s);
|
||||||
}
|
}
|
||||||
@ -3722,7 +3733,7 @@ impl Engine {
|
|||||||
params.iter().for_each(|p| p.hash(hasher));
|
params.iter().for_each(|p| p.hash(hasher));
|
||||||
body.hash(hasher);
|
body.hash(hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
let fn_name = state.get_identifier(make_anonymous_fn(hash));
|
let fn_name = state.get_interned_string(make_anonymous_fn(hash));
|
||||||
|
|
||||||
// Define the function
|
// Define the function
|
||||||
let script = ScriptFnDef {
|
let script = ScriptFnDef {
|
||||||
|
@ -26,12 +26,6 @@ pub struct StringsInterner<'a> {
|
|||||||
max: usize,
|
max: usize,
|
||||||
/// Normal strings.
|
/// Normal strings.
|
||||||
strings: BTreeMap<u64, ImmutableString>,
|
strings: BTreeMap<u64, ImmutableString>,
|
||||||
/// Property getters.
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
getters: BTreeMap<u64, ImmutableString>,
|
|
||||||
/// Property setters.
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
setters: BTreeMap<u64, ImmutableString>,
|
|
||||||
/// Take care of the lifetime parameter.
|
/// Take care of the lifetime parameter.
|
||||||
dummy: PhantomData<&'a ()>,
|
dummy: PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
@ -51,71 +45,38 @@ impl StringsInterner<'_> {
|
|||||||
Self::new_with_capacity(MAX_INTERNED_STRINGS)
|
Self::new_with_capacity(MAX_INTERNED_STRINGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`StringsInterner`] with a maximum capacity.
|
/// Create a new [`StringsInterner`] with maximum capacity.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_with_capacity(capacity: usize) -> Self {
|
pub fn new_with_capacity(capacity: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
max: capacity,
|
max: capacity,
|
||||||
strings: BTreeMap::new(),
|
strings: BTreeMap::new(),
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
getters: BTreeMap::new(),
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
setters: BTreeMap::new(),
|
|
||||||
dummy: PhantomData,
|
dummy: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Get an identifier from a text string, adding it to the interner if necessary.
|
||||||
/// Get an identifier from a text string and prefix, adding it to the interner if necessary.
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get(&mut self, text: impl AsRef<str> + Into<ImmutableString>) -> ImmutableString {
|
pub fn get<T: AsRef<str> + Into<ImmutableString>>(&mut self, text: T) -> ImmutableString {
|
||||||
self.get_with_prefix("", text)
|
self.get_with_mapper(|s| s.into(), text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an identifier from a text string and prefix, adding it to the interner if necessary.
|
/// Get an identifier from a text string, adding it to the interner if necessary.
|
||||||
///
|
|
||||||
/// # Prefix
|
|
||||||
///
|
|
||||||
/// Currently recognized prefixes are:
|
|
||||||
///
|
|
||||||
/// * `""` - None (normal string)
|
|
||||||
/// * `"get$"` - Property getter, not available under `no_object`
|
|
||||||
/// * `"set$"` - Property setter, not available under `no_object`
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the prefix is not recognized.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_with_prefix<T: AsRef<str> + Into<ImmutableString>>(
|
pub fn get_with_mapper<T: AsRef<str> + Into<ImmutableString>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
prefix: impl AsRef<str>,
|
mapper: fn(T) -> ImmutableString,
|
||||||
text: T,
|
text: T,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
let prefix = prefix.as_ref();
|
|
||||||
let key = text.as_ref();
|
let key = text.as_ref();
|
||||||
|
|
||||||
// Do not intern numbers
|
// Do not intern numbers
|
||||||
if prefix == "" && key.bytes().all(|c| c == b'.' || (c >= b'0' && c <= b'9')) {
|
if key.bytes().all(|c| c == b'.' || (c >= b'0' && c <= b'9')) {
|
||||||
return text.into();
|
return text.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (dict, mapper): (_, fn(T) -> ImmutableString) = match prefix {
|
|
||||||
"" => (&mut self.strings, |s| s.into()),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
crate::engine::FN_GET => (&mut self.getters, |s| {
|
|
||||||
crate::engine::make_getter(s.as_ref()).into()
|
|
||||||
}),
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
crate::engine::FN_SET => (&mut self.setters, |s| {
|
|
||||||
crate::engine::make_setter(s.as_ref()).into()
|
|
||||||
}),
|
|
||||||
|
|
||||||
_ => unreachable!("unsupported prefix {}", prefix),
|
|
||||||
};
|
|
||||||
|
|
||||||
if key.len() > MAX_STRING_LEN {
|
if key.len() > MAX_STRING_LEN {
|
||||||
return mapper(text);
|
return mapper(text);
|
||||||
}
|
}
|
||||||
@ -124,8 +85,8 @@ impl StringsInterner<'_> {
|
|||||||
key.hash(hasher);
|
key.hash(hasher);
|
||||||
let key = hasher.finish();
|
let key = hasher.finish();
|
||||||
|
|
||||||
if !dict.is_empty() && dict.contains_key(&key) {
|
if !self.strings.is_empty() && self.strings.contains_key(&key) {
|
||||||
return dict.get(&key).unwrap().clone();
|
return self.strings.get(&key).unwrap().clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = mapper(text);
|
let value = mapper(text);
|
||||||
@ -134,7 +95,7 @@ impl StringsInterner<'_> {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
dict.insert(key, value.clone());
|
self.strings.insert(key, value.clone());
|
||||||
|
|
||||||
// If the interner is over capacity, remove the longest entry
|
// If the interner is over capacity, remove the longest entry
|
||||||
if self.strings.len() > self.max {
|
if self.strings.len() > self.max {
|
||||||
@ -160,37 +121,23 @@ impl StringsInterner<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Number of strings interned.
|
/// Number of strings interned.
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
#[cfg(not(feature = "no_object"))]
|
self.strings.len()
|
||||||
return self.strings.len() + self.getters.len() + self.setters.len();
|
|
||||||
|
|
||||||
#[cfg(feature = "no_object")]
|
|
||||||
return self.strings.len();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of strings interned.
|
/// Number of strings interned.
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
#[cfg(not(feature = "no_object"))]
|
self.strings.is_empty()
|
||||||
return self.strings.is_empty() || self.getters.is_empty() || self.setters.is_empty();
|
|
||||||
|
|
||||||
#[cfg(feature = "no_object")]
|
|
||||||
return self.strings.is_empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear all interned strings.
|
/// Clear all interned strings.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.strings.clear();
|
self.strings.clear();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
{
|
|
||||||
self.getters.clear();
|
|
||||||
self.setters.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,12 +145,6 @@ impl AddAssign<Self> for StringsInterner<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_assign(&mut self, rhs: Self) {
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
self.strings.extend(rhs.strings.into_iter());
|
self.strings.extend(rhs.strings.into_iter());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
{
|
|
||||||
self.getters.extend(rhs.getters.into_iter());
|
|
||||||
self.setters.extend(rhs.setters.into_iter());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,13 +153,5 @@ impl AddAssign<&Self> for StringsInterner<'_> {
|
|||||||
fn add_assign(&mut self, rhs: &Self) {
|
fn add_assign(&mut self, rhs: &Self) {
|
||||||
self.strings
|
self.strings
|
||||||
.extend(rhs.strings.iter().map(|(&k, v)| (k, v.clone())));
|
.extend(rhs.strings.iter().map(|(&k, v)| (k, v.clone())));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
{
|
|
||||||
self.getters
|
|
||||||
.extend(rhs.getters.iter().map(|(&k, v)| (k, v.clone())));
|
|
||||||
self.setters
|
|
||||||
.extend(rhs.setters.iter().map(|(&k, v)| (k, v.clone())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user