Use ImmutableString for source.

This commit is contained in:
Stephen Chung 2022-10-29 14:12:18 +08:00
parent d0998a44b9
commit 4100e6da64
14 changed files with 112 additions and 126 deletions

View File

@ -217,7 +217,7 @@ impl Engine {
level: usize, level: usize,
) -> RhaiResult { ) -> RhaiResult {
let mut caches = Caches::new(); let mut caches = Caches::new();
global.source = ast.source_raw().clone(); global.source = ast.source_raw().cloned();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let orig_embedded_module_resolver = std::mem::replace( let orig_embedded_module_resolver = std::mem::replace(

View File

@ -113,7 +113,7 @@ impl Engine {
pub fn run_ast_with_scope(&self, scope: &mut Scope, ast: &AST) -> RhaiResultOf<()> { pub fn run_ast_with_scope(&self, scope: &mut Scope, ast: &AST) -> RhaiResultOf<()> {
let caches = &mut Caches::new(); let caches = &mut Caches::new();
let global = &mut GlobalRuntimeState::new(self); let global = &mut GlobalRuntimeState::new(self);
global.source = ast.source_raw().clone(); global.source = ast.source_raw().cloned();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
{ {

View File

@ -1,7 +1,7 @@
//! Module defining the AST (abstract syntax tree). //! Module defining the AST (abstract syntax tree).
use super::{ASTFlags, Expr, FnAccess, Stmt, StmtBlock, StmtBlockContainer}; use super::{ASTFlags, Expr, FnAccess, Stmt, StmtBlock, StmtBlockContainer};
use crate::{Dynamic, FnNamespace, Identifier, Position}; use crate::{Dynamic, FnNamespace, ImmutableString, Position};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{ use std::{
@ -20,8 +20,7 @@ use std::{
#[derive(Clone)] #[derive(Clone)]
pub struct AST { pub struct AST {
/// Source of the [`AST`]. /// Source of the [`AST`].
/// No source if string is empty. source: Option<ImmutableString>,
source: Identifier,
/// [`AST`] documentation. /// [`AST`] documentation.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: crate::SmartString, doc: crate::SmartString,
@ -98,7 +97,7 @@ impl AST {
#[cfg(not(feature = "no_function"))] functions: impl Into<crate::Shared<crate::Module>>, #[cfg(not(feature = "no_function"))] functions: impl Into<crate::Shared<crate::Module>>,
) -> Self { ) -> Self {
Self { Self {
source: Identifier::new_const(), source: None,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: crate::SmartString::new_const(), doc: crate::SmartString::new_const(),
body: StmtBlock::new(statements, Position::NONE, Position::NONE), body: StmtBlock::new(statements, Position::NONE, Position::NONE),
@ -133,7 +132,7 @@ impl AST {
pub fn new_with_source( pub fn new_with_source(
statements: impl IntoIterator<Item = Stmt>, statements: impl IntoIterator<Item = Stmt>,
#[cfg(not(feature = "no_function"))] functions: impl Into<crate::Shared<crate::Module>>, #[cfg(not(feature = "no_function"))] functions: impl Into<crate::Shared<crate::Module>>,
source: impl Into<Identifier>, source: impl Into<ImmutableString>,
) -> Self { ) -> Self {
let mut ast = Self::new( let mut ast = Self::new(
statements, statements,
@ -148,7 +147,7 @@ impl AST {
#[must_use] #[must_use]
pub fn empty() -> Self { pub fn empty() -> Self {
Self { Self {
source: Identifier::new_const(), source: None,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: crate::SmartString::new_const(), doc: crate::SmartString::new_const(),
body: StmtBlock::NONE, body: StmtBlock::NONE,
@ -159,36 +158,39 @@ impl AST {
} }
} }
/// Get the source, if any. /// Get the source, if any.
#[inline] #[inline(always)]
#[must_use] #[must_use]
pub fn source(&self) -> Option<&str> { pub fn source(&self) -> Option<&str> {
if self.source.is_empty() { self.source.as_ref().map(|s| s.as_str())
None
} else {
Some(self.source.as_str())
}
} }
/// Get a reference to the source. /// Get a reference to the source.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) const fn source_raw(&self) -> &Identifier { pub(crate) const fn source_raw(&self) -> Option<&ImmutableString> {
&self.source self.source.as_ref()
} }
/// Set the source. /// Set the source.
#[inline] #[inline]
pub fn set_source(&mut self, source: impl Into<Identifier>) -> &mut Self { pub fn set_source(&mut self, source: impl Into<ImmutableString>) -> &mut Self {
let source = source.into(); let source = source.into();
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
crate::Shared::get_mut(&mut self.lib) crate::Shared::get_mut(&mut self.lib)
.as_mut() .as_mut()
.map(|m| m.set_id(source.clone())); .map(|m| m.set_id(source.clone()));
self.source = source;
if source.is_empty() {
self.source = None;
} else {
self.source = Some(source);
}
self self
} }
/// Clear the source. /// Clear the source.
#[inline(always)] #[inline(always)]
pub fn clear_source(&mut self) -> &mut Self { pub fn clear_source(&mut self) -> &mut Self {
self.source.clear(); self.source = None;
self self
} }
/// Get the documentation (if any). /// Get the documentation (if any).
@ -559,18 +561,18 @@ impl AST {
lib lib
}; };
let mut _ast = if other.source.is_empty() { let mut _ast = if let Some(ref source) = other.source {
Self::new(
merged,
#[cfg(not(feature = "no_function"))]
lib,
)
} else {
Self::new_with_source( Self::new_with_source(
merged, merged,
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
lib, lib,
other.source.clone(), source.clone(),
)
} else {
Self::new(
merged,
#[cfg(not(feature = "no_function"))]
lib,
) )
}; };

View File

@ -2,7 +2,7 @@
use crate::func::{CallableFunction, StraightHashMap}; use crate::func::{CallableFunction, StraightHashMap};
use crate::types::BloomFilterU64; use crate::types::BloomFilterU64;
use crate::{Identifier, StaticVec}; use crate::{ImmutableString, StaticVec};
use std::marker::PhantomData; use std::marker::PhantomData;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -14,7 +14,7 @@ pub struct FnResolutionCacheEntry {
/// Function. /// Function.
pub func: CallableFunction, pub func: CallableFunction,
/// Optional source. /// Optional source.
pub source: Option<Box<Identifier>>, pub source: Option<ImmutableString>,
} }
/// _(internals)_ A function resolution cache with a bloom filter. /// _(internals)_ A function resolution cache with a bloom filter.

View File

@ -3,7 +3,10 @@
use super::{EvalContext, GlobalRuntimeState}; use super::{EvalContext, GlobalRuntimeState};
use crate::ast::{ASTNode, Expr, Stmt}; use crate::ast::{ASTNode, Expr, Stmt};
use crate::{Dynamic, Engine, EvalAltResult, Identifier, Module, Position, RhaiResultOf, Scope}; use crate::{
Dynamic, Engine, EvalAltResult, Identifier, ImmutableString, Module, Position, RhaiResultOf,
Scope,
};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{fmt, iter::repeat, mem}; use std::{fmt, iter::repeat, mem};
@ -226,8 +229,8 @@ pub struct CallStackFrame {
pub fn_name: Identifier, pub fn_name: Identifier,
/// Copies of function call arguments, if any. /// Copies of function call arguments, if any.
pub args: crate::StaticVec<Dynamic>, pub args: crate::StaticVec<Dynamic>,
/// Source of the function, empty if none. /// Source of the function.
pub source: Identifier, pub source: Option<ImmutableString>,
/// [Position][`Position`] of the function call. /// [Position][`Position`] of the function call.
pub pos: Position, pub pos: Position,
} }
@ -243,8 +246,8 @@ impl fmt::Display for CallStackFrame {
fp.finish()?; fp.finish()?;
if !self.pos.is_none() { if !self.pos.is_none() {
if !self.source.is_empty() { if let Some(ref source) = self.source {
write!(f, ": {}", self.source)?; write!(f, ": {source}")?;
} }
write!(f, " @ {:?}", self.pos)?; write!(f, " @ {:?}", self.pos)?;
} }
@ -295,13 +298,13 @@ impl Debugger {
&mut self, &mut self,
fn_name: impl Into<Identifier>, fn_name: impl Into<Identifier>,
args: crate::StaticVec<Dynamic>, args: crate::StaticVec<Dynamic>,
source: impl Into<Identifier>, source: Option<ImmutableString>,
pos: Position, pos: Position,
) { ) {
self.call_stack.push(CallStackFrame { self.call_stack.push(CallStackFrame {
fn_name: fn_name.into(), fn_name: fn_name.into(),
args, args,
source: source.into(), source,
pos, pos,
}); });
} }
@ -487,7 +490,10 @@ impl Engine {
let event = match event { let event = match event {
Some(e) => e, Some(e) => e,
None => match global.debugger.is_break_point(&global.source, node) { None => match global
.debugger
.is_break_point(global.source().unwrap_or(""), node)
{
Some(bp) => DebuggerEvent::BreakPoint(bp), Some(bp) => DebuggerEvent::BreakPoint(bp),
None => return Ok(None), None => return Ok(None),
}, },
@ -512,17 +518,12 @@ impl Engine {
event: DebuggerEvent, event: DebuggerEvent,
level: usize, level: usize,
) -> Result<Option<DebuggerStatus>, Box<crate::EvalAltResult>> { ) -> Result<Option<DebuggerStatus>, Box<crate::EvalAltResult>> {
let source = global.source.clone(); let src = global.source_raw().cloned();
let source = if source.is_empty() { let src = src.as_ref().map(|s| s.as_str());
None
} else {
Some(source.as_str())
};
let context = crate::EvalContext::new(self, scope, global, None, lib, this_ptr, level); let context = crate::EvalContext::new(self, scope, global, None, lib, this_ptr, level);
if let Some((.., ref on_debugger)) = self.debugger { if let Some((.., ref on_debugger)) = self.debugger {
let command = on_debugger(context, event, node, source, node.position())?; let command = on_debugger(context, event, node, src, node.position())?;
match command { match command {
DebuggerCommand::Continue => { DebuggerCommand::Continue => {

View File

@ -58,11 +58,7 @@ impl<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> EvalContext<'a, 's, 'ps, 'g, 'pg, '
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn source(&self) -> Option<&str> { pub fn source(&self) -> Option<&str> {
if self.global.source.is_empty() { self.global.source()
None
} else {
Some(self.global.source.as_str())
}
} }
/// The current [`Scope`]. /// The current [`Scope`].
#[inline(always)] #[inline(always)]

View File

@ -1,6 +1,6 @@
//! Global runtime state. //! Global runtime state.
use crate::{Dynamic, Engine, Identifier}; use crate::{Dynamic, Engine, 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<crate::ImmutableString, 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.
@ -25,14 +25,14 @@ pub type GlobalConstants =
pub struct GlobalRuntimeState<'a> { pub struct GlobalRuntimeState<'a> {
/// Names of imported [modules][crate::Module]. /// Names of imported [modules][crate::Module].
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
imports: crate::StaticVec<crate::ImmutableString>, imports: crate::StaticVec<ImmutableString>,
/// Stack of imported [modules][crate::Module]. /// Stack of imported [modules][crate::Module].
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
modules: crate::StaticVec<crate::Shared<crate::Module>>, modules: crate::StaticVec<crate::Shared<crate::Module>>,
/// Source of the current context. /// Source of the current context.
/// ///
/// No source if the string is empty. /// No source if the string is empty.
pub source: Identifier, pub source: Option<ImmutableString>,
/// Number of operations performed. /// Number of operations performed.
pub num_operations: u64, pub num_operations: u64,
/// Number of modules loaded. /// Number of modules loaded.
@ -84,7 +84,7 @@ impl GlobalRuntimeState<'_> {
imports: crate::StaticVec::new_const(), imports: crate::StaticVec::new_const(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
modules: crate::StaticVec::new_const(), modules: crate::StaticVec::new_const(),
source: Identifier::new_const(), source: None,
num_operations: 0, num_operations: 0,
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
num_modules_loaded: 0, num_modules_loaded: 0,
@ -168,7 +168,7 @@ impl GlobalRuntimeState<'_> {
#[inline(always)] #[inline(always)]
pub fn push_import( pub fn push_import(
&mut self, &mut self,
name: impl Into<crate::ImmutableString>, name: impl Into<ImmutableString>,
module: impl Into<crate::Shared<crate::Module>>, module: impl Into<crate::Shared<crate::Module>>,
) { ) {
self.imports.push(name.into()); self.imports.push(name.into());
@ -202,7 +202,7 @@ impl GlobalRuntimeState<'_> {
#[inline] #[inline]
pub(crate) fn iter_imports_raw( pub(crate) fn iter_imports_raw(
&self, &self,
) -> impl Iterator<Item = (&crate::ImmutableString, &crate::Shared<crate::Module>)> { ) -> impl Iterator<Item = (&ImmutableString, &crate::Shared<crate::Module>)> {
self.imports.iter().zip(self.modules.iter()).rev() self.imports.iter().zip(self.modules.iter()).rev()
} }
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order. /// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order.
@ -212,7 +212,7 @@ impl GlobalRuntimeState<'_> {
#[inline] #[inline]
pub fn scan_imports_raw( pub fn scan_imports_raw(
&self, &self,
) -> impl Iterator<Item = (&crate::ImmutableString, &crate::Shared<crate::Module>)> { ) -> impl Iterator<Item = (&ImmutableString, &crate::Shared<crate::Module>)> {
self.imports.iter().zip(self.modules.iter()) self.imports.iter().zip(self.modules.iter())
} }
/// Can the particular function with [`Dynamic`] parameter(s) exist in the stack of /// Can the particular function with [`Dynamic`] parameter(s) exist in the stack of
@ -247,11 +247,11 @@ impl GlobalRuntimeState<'_> {
pub fn get_qualified_fn( pub fn get_qualified_fn(
&self, &self,
hash: u64, hash: u64,
) -> Option<(&crate::func::CallableFunction, Option<&str>)> { ) -> Option<(&crate::func::CallableFunction, Option<&ImmutableString>)> {
self.modules self.modules
.iter() .iter()
.rev() .rev()
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id()))) .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
} }
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in the stack of /// Does the specified [`TypeId`][std::any::TypeId] iterator exist in the stack of
/// globally-imported [modules][crate::Module]? /// globally-imported [modules][crate::Module]?
@ -278,14 +278,16 @@ impl GlobalRuntimeState<'_> {
.find_map(|m| m.get_qualified_iter(id)) .find_map(|m| m.get_qualified_iter(id))
} }
/// Get the current source. /// Get the current source.
#[inline] #[inline(always)]
#[must_use] #[must_use]
pub fn source(&self) -> Option<&str> { pub fn source(&self) -> Option<&str> {
if self.source.is_empty() { self.source.as_ref().map(|s| s.as_str())
None }
} else { /// Get the current source.
Some(self.source.as_str()) #[inline(always)]
} #[must_use]
pub(crate) const fn source_raw(&self) -> Option<&ImmutableString> {
self.source.as_ref()
} }
/// Get the pre-calculated index getter hash. /// Get the pre-calculated index getter hash.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
@ -317,10 +319,10 @@ impl GlobalRuntimeState<'_> {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
impl IntoIterator for GlobalRuntimeState<'_> { impl IntoIterator for GlobalRuntimeState<'_> {
type Item = (crate::ImmutableString, crate::Shared<crate::Module>); type Item = (ImmutableString, crate::Shared<crate::Module>);
type IntoIter = std::iter::Rev< type IntoIter = std::iter::Rev<
std::iter::Zip< std::iter::Zip<
smallvec::IntoIter<[crate::ImmutableString; crate::STATIC_VEC_INLINE_SIZE]>, smallvec::IntoIter<[ImmutableString; crate::STATIC_VEC_INLINE_SIZE]>,
smallvec::IntoIter<[crate::Shared<crate::Module>; crate::STATIC_VEC_INLINE_SIZE]>, smallvec::IntoIter<[crate::Shared<crate::Module>; crate::STATIC_VEC_INLINE_SIZE]>,
>, >,
>; >;
@ -332,10 +334,10 @@ impl IntoIterator for GlobalRuntimeState<'_> {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
impl<'a> IntoIterator for &'a GlobalRuntimeState<'_> { impl<'a> IntoIterator for &'a GlobalRuntimeState<'_> {
type Item = (&'a crate::ImmutableString, &'a crate::Shared<crate::Module>); type Item = (&'a ImmutableString, &'a crate::Shared<crate::Module>);
type IntoIter = std::iter::Rev< type IntoIter = std::iter::Rev<
std::iter::Zip< std::iter::Zip<
std::slice::Iter<'a, crate::ImmutableString>, std::slice::Iter<'a, ImmutableString>,
std::slice::Iter<'a, crate::Shared<crate::Module>>, std::slice::Iter<'a, crate::Shared<crate::Module>>,
>, >,
>; >;
@ -346,7 +348,7 @@ impl<'a> IntoIterator for &'a GlobalRuntimeState<'_> {
} }
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
impl<K: Into<crate::ImmutableString>, M: Into<crate::Shared<crate::Module>>> Extend<(K, M)> impl<K: Into<ImmutableString>, M: Into<crate::Shared<crate::Module>>> Extend<(K, M)>
for GlobalRuntimeState<'_> for GlobalRuntimeState<'_>
{ {
#[inline] #[inline]

View File

@ -719,8 +719,8 @@ impl Engine {
err_map.insert("message".into(), err.to_string().into()); err_map.insert("message".into(), err.to_string().into());
if !global.source.is_empty() { if let Some(ref source) = global.source {
err_map.insert("source".into(), global.source.clone().into()); err_map.insert("source".into(), source.into());
} }
if !err_pos.is_none() { if !err_pos.is_none() {

View File

@ -218,7 +218,7 @@ impl Engine {
.iter() .iter()
.copied() .copied()
.chain(self.global_modules.iter().map(|m| m.as_ref())) .chain(self.global_modules.iter().map(|m| m.as_ref()))
.find_map(|m| m.get_fn(hash).map(|f| (f, m.id()))); .find_map(|m| m.get_fn(hash).map(|f| (f, m.id_raw())));
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let func = if args.is_none() { let func = if args.is_none() {
@ -228,7 +228,7 @@ impl Engine {
func.or_else(|| _global.get_qualified_fn(hash)).or_else(|| { func.or_else(|| _global.get_qualified_fn(hash)).or_else(|| {
self.global_sub_modules self.global_sub_modules
.values() .values()
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id()))) .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
}) })
}; };
@ -236,7 +236,7 @@ impl Engine {
// Specific version found // Specific version found
let new_entry = Some(FnResolutionCacheEntry { let new_entry = Some(FnResolutionCacheEntry {
func: f.clone(), func: f.clone(),
source: s.map(|s| Box::new(s.into())), source: s.cloned(),
}); });
return if cache.filter.is_absent_and_set(hash) { return if cache.filter.is_absent_and_set(hash) {
// Do not cache "one-hit wonders" // Do not cache "one-hit wonders"
@ -358,7 +358,6 @@ impl Engine {
) -> RhaiResultOf<(Dynamic, bool)> { ) -> RhaiResultOf<(Dynamic, bool)> {
self.track_operation(global, pos)?; self.track_operation(global, pos)?;
let parent_source = global.source.clone();
let op_assign = if is_op_assign { let op_assign = if is_op_assign {
Token::lookup_from_syntax(name) Token::lookup_from_syntax(name)
} else { } else {
@ -398,24 +397,19 @@ impl Engine {
backup.change_first_arg_to_copy(args); backup.change_first_arg_to_copy(args);
} }
let source = match (source, parent_source.as_str()) {
(None, "") => None,
(None, s) => Some(s),
(Some(s), ..) => Some(s.as_str()),
};
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() { if self.debugger.is_some() {
global.debugger.push_call_stack_frame( global.debugger.push_call_stack_frame(
name, name,
args.iter().map(|v| (*v).clone()).collect(), args.iter().map(|v| (*v).clone()).collect(),
source.unwrap_or(""), source.clone().or_else(|| global.source.clone()),
pos, pos,
); );
} }
// Run external function // Run external function
let context = (self, name, source, &*global, lib, pos, level).into(); let src = source.as_ref().map(|s| s.as_str());
let context = (self, name, src, &*global, lib, pos, level).into();
let result = if func.is_plugin_fn() { let result = if func.is_plugin_fn() {
let f = func.get_plugin_fn().unwrap(); let f = func.get_plugin_fn().unwrap();
@ -484,12 +478,7 @@ impl Engine {
let t = self.map_type_name(type_name::<ImmutableString>()).into(); let t = self.map_type_name(type_name::<ImmutableString>()).into();
ERR::ErrorMismatchOutputType(t, typ.into(), pos) ERR::ErrorMismatchOutputType(t, typ.into(), pos)
})?; })?;
let source = if global.source.is_empty() { ((*self.debug)(&text, global.source(), pos).into(), false)
None
} else {
Some(global.source.as_str())
};
((*self.debug)(&text, source, pos).into(), false)
} }
_ => (result, is_method), _ => (result, is_method),
}); });
@ -685,12 +674,7 @@ impl Engine {
} }
}; };
let orig_source = mem::replace( let orig_source = mem::replace(&mut global.source, source.clone());
&mut global.source,
source
.as_ref()
.map_or(crate::Identifier::new_const(), |s| (**s).clone()),
);
let result = if _is_method_call { let result = if _is_method_call {
// Method call of script function - map first argument to `this` // Method call of script function - map first argument to `this`
@ -1172,7 +1156,7 @@ impl Engine {
return result.map_err(|err| { return result.map_err(|err| {
ERR::ErrorInFunctionCall( ERR::ErrorInFunctionCall(
KEYWORD_EVAL.to_string(), KEYWORD_EVAL.to_string(),
global.source.to_string(), global.source().unwrap_or("").to_string(),
err, err,
pos, pos,
) )
@ -1416,14 +1400,13 @@ impl Engine {
Some(f) if f.is_script() => { Some(f) if f.is_script() => {
let fn_def = f.get_script_fn_def().expect("script-defined function"); let fn_def = f.get_script_fn_def().expect("script-defined function");
let new_scope = &mut Scope::new(); let new_scope = &mut Scope::new();
let mut source = module.id_raw().clone(); let orig_source = mem::replace(&mut global.source, module.id_raw().cloned());
mem::swap(&mut global.source, &mut source);
let result = self.call_script_fn( let result = self.call_script_fn(
new_scope, global, caches, lib, &mut None, fn_def, &mut args, true, pos, level, new_scope, global, caches, lib, &mut None, fn_def, &mut args, true, pos, level,
); );
global.source = source; global.source = orig_source;
result result
} }

View File

@ -54,7 +54,7 @@ impl Engine {
Err(ERR::ErrorInFunctionCall( Err(ERR::ErrorInFunctionCall(
name, name,
source.unwrap_or_else(|| global.source.to_string()), source.unwrap_or_else(|| global.source().unwrap_or("").to_string()),
err, err,
pos, pos,
) )

View File

@ -160,8 +160,7 @@ pub fn calc_native_fn_hash<'a>(
#[derive(Clone)] #[derive(Clone)]
pub struct Module { pub struct Module {
/// ID identifying the module. /// ID identifying the module.
/// No ID if string is empty. id: Option<ImmutableString>,
id: Identifier,
/// Module documentation. /// Module documentation.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: crate::SmartString, doc: crate::SmartString,
@ -292,7 +291,7 @@ impl Module {
#[must_use] #[must_use]
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self {
Self { Self {
id: Identifier::new_const(), id: None,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: crate::SmartString::new_const(), doc: crate::SmartString::new_const(),
internal: false, internal: false,
@ -324,18 +323,14 @@ impl Module {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn id(&self) -> Option<&str> { pub fn id(&self) -> Option<&str> {
if self.id_raw().is_empty() { self.id.as_ref().map(|s| s.as_str())
None
} else {
Some(self.id_raw())
}
} }
/// Get the ID of the [`Module`] as an [`Identifier`], if any. /// Get the ID of the [`Module`] as an [`Identifier`], if any.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) const fn id_raw(&self) -> &Identifier { pub(crate) const fn id_raw(&self) -> Option<&ImmutableString> {
&self.id self.id.as_ref()
} }
/// Set the ID of the [`Module`]. /// Set the ID of the [`Module`].
@ -351,8 +346,15 @@ impl Module {
/// assert_eq!(module.id(), Some("hello")); /// assert_eq!(module.id(), Some("hello"));
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn set_id(&mut self, id: impl Into<Identifier>) -> &mut Self { pub fn set_id(&mut self, id: impl Into<ImmutableString>) -> &mut Self {
self.id = id.into(); let id = id.into();
if id.is_empty() {
self.id = None;
} else {
self.id = Some(id);
}
self self
} }
@ -370,7 +372,7 @@ impl Module {
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn clear_id(&mut self) -> &mut Self { pub fn clear_id(&mut self) -> &mut Self {
self.id.clear(); self.id = None;
self self
} }
@ -434,7 +436,7 @@ impl Module {
/// Clear the [`Module`]. /// Clear the [`Module`].
#[inline(always)] #[inline(always)]
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.id.clear(); self.id = None;
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
self.doc.clear(); self.doc.clear();
self.internal = false; self.internal = false;
@ -2078,7 +2080,7 @@ impl Module {
}); });
} }
module.set_id(ast.source_raw().clone()); module.id = ast.source_raw().cloned();
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
module.set_doc(ast.doc()); module.set_doc(ast.doc());

View File

@ -62,8 +62,8 @@ mod debugging_functions {
Dynamic::from_array(_args.clone().to_vec()), Dynamic::from_array(_args.clone().to_vec()),
); );
} }
if !_source.is_empty() { if let Some(source) = _source {
map.insert("source".into(), _source.into()); map.insert("source".into(), source.into());
} }
if !_pos.is_none() { if !_pos.is_none() {
map.insert( map.insert(

View File

@ -578,7 +578,7 @@ fn test_module_context() -> Result<(), Box<EvalAltResult>> {
let new_context = NativeCallContext::new_with_all_fields( let new_context = NativeCallContext::new_with_all_fields(
engine, engine,
&fn_name, &fn_name,
source.as_ref().map(|s| s.as_str()), source.as_ref().map(String::as_str),
&global, &global,
&lib, &lib,
pos, pos,

View File

@ -89,21 +89,21 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: "", doc: "", resolver: None, body: [Expr(123 @ 1:53)] }"# r#"AST { source: None, doc: "", resolver: None, body: [Expr(123 @ 1:53)] }"#
); );
let ast = engine.compile("const DECISION = false; if DECISION { 42 } else { 123 }")?; let ast = engine.compile("const DECISION = false; if DECISION { 42 } else { 123 }")?;
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: "", doc: "", resolver: None, body: [Var(("DECISION" @ 1:7, false @ 1:18, None), CONSTANT, 1:1), Expr(123 @ 1:51)] }"# r#"AST { source: None, doc: "", resolver: None, body: [Var(("DECISION" @ 1:7, false @ 1:18, None), CONSTANT, 1:1), Expr(123 @ 1:51)] }"#
); );
let ast = engine.compile("if 1 == 2 { 42 }")?; let ast = engine.compile("if 1 == 2 { 42 }")?;
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: "", doc: "", resolver: None, body: [] }"# r#"AST { source: None, doc: "", resolver: None, body: [] }"#
); );
engine.set_optimization_level(OptimizationLevel::Full); engine.set_optimization_level(OptimizationLevel::Full);
@ -112,14 +112,14 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: "", doc: "", resolver: None, body: [Expr(42 @ 1:1)] }"# r#"AST { source: None, doc: "", resolver: None, body: [Expr(42 @ 1:1)] }"#
); );
let ast = engine.compile("NUMBER")?; let ast = engine.compile("NUMBER")?;
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: "", doc: "", resolver: None, body: [Expr(Variable(NUMBER) @ 1:1)] }"# r#"AST { source: None, doc: "", resolver: None, body: [Expr(Variable(NUMBER) @ 1:1)] }"#
); );
let mut module = Module::new(); let mut module = Module::new();
@ -131,7 +131,7 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: "", doc: "", resolver: None, body: [Expr(42 @ 1:1)] }"# r#"AST { source: None, doc: "", resolver: None, body: [Expr(42 @ 1:1)] }"#
); );
Ok(()) Ok(())