Add source info to native calls.

This commit is contained in:
Stephen Chung 2021-01-03 00:20:13 +08:00
parent ef48f47b74
commit 1bbf473ec7
4 changed files with 39 additions and 32 deletions

View File

@ -13,6 +13,7 @@ Enhancements
------------ ------------
* Source information is provided when there is an error within a call to a function defined in another module. * Source information is provided when there is an error within a call to a function defined in another module.
* Source information is provided to the `NativeCallContext` for native Rust functions.
Version 0.19.9 Version 0.19.9

View File

@ -126,11 +126,14 @@ impl Imports {
} }
/// Get specified function via its hash key. /// Get specified function via its hash key.
#[inline(always)] #[inline(always)]
pub fn get_fn(&self, hash: NonZeroU64) -> Option<&CallableFunction> { pub fn get_fn(
&self,
hash: NonZeroU64,
) -> Option<(&CallableFunction, &Option<ImmutableString>)> {
self.0 self.0
.iter() .iter()
.rev() .rev()
.find_map(|(_, m)| m.get_qualified_fn(hash)) .find_map(|(_, m)| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
} }
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]? /// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]?
#[allow(dead_code)] #[allow(dead_code)]
@ -2046,15 +2049,16 @@ impl Engine {
match self match self
.global_namespace .global_namespace
.get_fn(hash_fn, false) .get_fn(hash_fn, false)
.map(|f| (f, None))
.or_else(|| { .or_else(|| {
self.global_modules self.global_modules.iter().find_map(|m| {
.iter() m.get_fn(hash_fn, false).map(|f| (f, m.id_raw().as_ref()))
.find_map(|m| m.get_fn(hash_fn, false)) })
}) })
.or_else(|| mods.get_fn(hash_fn)) .or_else(|| mods.get_fn(hash_fn).map(|(f, source)| (f, source.as_ref())))
{ {
// op= function registered as method // op= function registered as method
Some(func) if func.is_method() => { Some((func, source)) if func.is_method() => {
let mut lock_guard; let mut lock_guard;
let lhs_ptr_inner; let lhs_ptr_inner;
@ -2068,14 +2072,16 @@ impl Engine {
let args = &mut [lhs_ptr_inner, &mut rhs_val]; let args = &mut [lhs_ptr_inner, &mut rhs_val];
// Overriding exact implementation // Overriding exact implementation
let source = if source.is_none() {
state.source.as_ref()
} else {
source
};
if func.is_plugin_fn() { if func.is_plugin_fn() {
func.get_plugin_fn() func.get_plugin_fn()
.call((self, &state.source, &*mods, lib).into(), args)?; .call((self, source, &*mods, lib).into(), args)?;
} else { } else {
func.get_native_fn()( func.get_native_fn()((self, source, &*mods, lib).into(), args)?;
(self, &state.source, &*mods, lib).into(),
args,
)?;
} }
} }
// Built-in op-assignment function // Built-in op-assignment function

View File

@ -176,15 +176,14 @@ impl Engine {
self.inc_operations(state, pos)?; self.inc_operations(state, pos)?;
// Check if function access already in the cache // Check if function access already in the cache
if !state.functions_cache.contains_key(&hash_fn) { let func = &*state.functions_cache.entry(hash_fn).or_insert_with(|| {
// Search for the native function // Search for the native function
// First search registered functions (can override packages) // First search registered functions (can override packages)
// Then search packages // Then search packages
// Finally search modules // Finally search modules
//lib.get_fn(hash_fn, pub_only) //lib.get_fn(hash_fn, pub_only)
let f = self self.global_namespace
.global_namespace
.get_fn(hash_fn, pub_only) .get_fn(hash_fn, pub_only)
.cloned() .cloned()
.map(|f| (f, None)) .map(|f| (f, None))
@ -195,13 +194,11 @@ impl Engine {
.map(|f| (f, m.id_raw().clone())) .map(|f| (f, m.id_raw().clone()))
}) })
}) })
.or_else(|| mods.get_fn(hash_fn).cloned().map(|f| (f, None))); .or_else(|| {
mods.get_fn(hash_fn)
// Store into cache .map(|(f, source)| (f.clone(), source.clone()))
state.functions_cache.insert(hash_fn, f); })
} });
let func = state.functions_cache.get(&hash_fn).unwrap();
if let Some((func, source)) = func { if let Some((func, source)) = func {
assert!(func.is_native()); assert!(func.is_native());
@ -212,9 +209,9 @@ impl Engine {
// Run external function // Run external function
let source = if source.is_none() { let source = if source.is_none() {
&state.source state.source.as_ref()
} else { } else {
source source.as_ref()
}; };
let result = if func.is_plugin_fn() { let result = if func.is_plugin_fn() {
func.get_plugin_fn() func.get_plugin_fn()
@ -1240,10 +1237,10 @@ impl Engine {
result result
} }
Some(f) if f.is_plugin_fn() => f Some(f) if f.is_plugin_fn() => f.get_plugin_fn().clone().call(
.get_plugin_fn() (self, module.id_raw().as_ref(), &*mods, lib).into(),
.clone() args.as_mut(),
.call((self, module.id_raw(), &*mods, lib).into(), args.as_mut()), ),
Some(f) if f.is_native() => { Some(f) if f.is_native() => {
if !f.is_method() { if !f.is_method() {
// Clone first argument // Clone first argument
@ -1254,7 +1251,10 @@ impl Engine {
} }
} }
f.get_native_fn()((self, module.id_raw(), &*mods, lib).into(), args.as_mut()) f.get_native_fn()(
(self, module.id_raw().as_ref(), &*mods, lib).into(),
args.as_mut(),
)
} }
Some(f) => unreachable!("unknown function type: {:?}", f), Some(f) => unreachable!("unknown function type: {:?}", f),
None if def_val.is_some() => Ok(def_val.unwrap().clone()), None if def_val.is_some() => Ok(def_val.unwrap().clone()),

View File

@ -63,14 +63,14 @@ pub struct NativeCallContext<'e, 's, 'a, 'm, 'pm: 'm> {
} }
impl<'e, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> impl<'e, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized>
From<(&'e Engine, &'s Option<ImmutableString>, &'a Imports, &'m M)> From<(&'e Engine, Option<&'s ImmutableString>, &'a Imports, &'m M)>
for NativeCallContext<'e, 's, 'a, 'm, 'pm> for NativeCallContext<'e, 's, 'a, 'm, 'pm>
{ {
#[inline(always)] #[inline(always)]
fn from(value: (&'e Engine, &'s Option<ImmutableString>, &'a Imports, &'m M)) -> Self { fn from(value: (&'e Engine, Option<&'s ImmutableString>, &'a Imports, &'m M)) -> Self {
Self { Self {
engine: value.0, engine: value.0,
source: value.1.as_ref().map(|s| s.as_str()), source: value.1.map(|s| s.as_str()),
mods: Some(value.2), mods: Some(value.2),
lib: value.3.as_ref(), lib: value.3.as_ref(),
} }