diff --git a/CHANGELOG.md b/CHANGELOG.md index 060f305b..7fc56bb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Enhancements * Array adds a `sort` method with no parameters which sorts homogeneous arrays of built-in comparable types (e.g. `INT`). * Inlining is disabled for error-path functions because errors are exceptional and scripts usually fail completely when an error is encountered. * The `optimize` module is completely eliminated under `no_optimize`, which should yield smaller code size. +* Add `NativeCallContext::position` to return the position of the function call. Deprecated API's ---------------- diff --git a/src/fn_call.rs b/src/fn_call.rs index 14998eb8..7412b469 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -339,12 +339,14 @@ impl Engine { .map(|s| s.as_str()); let result = if func.is_plugin_fn() { + let context = (self, name, source, mods, lib, pos).into(); func.get_plugin_fn() .expect("plugin function") - .call((self, name, source, mods, lib).into(), args) + .call(context, args) } else { let func = func.get_native_fn().expect("native function"); - func((self, name, source, mods, lib).into(), args) + let context = (self, name, source, mods, lib, pos).into(); + func(context, args) }; // Restore the original reference @@ -1448,17 +1450,19 @@ impl Engine { } } - Some(f) if f.is_plugin_fn() => f - .get_plugin_fn() - .expect("plugin function") - .clone() - .call((self, fn_name, module.id(), &*mods, lib).into(), &mut args) - .map_err(|err| err.fill_position(pos)), + Some(f) if f.is_plugin_fn() => { + let context = (self, fn_name, module.id(), &*mods, lib, pos).into(); + f.get_plugin_fn() + .expect("plugin function") + .clone() + .call(context, &mut args) + .map_err(|err| err.fill_position(pos)) + } Some(f) if f.is_native() => { let func = f.get_native_fn().expect("native function"); - func((self, fn_name, module.id(), &*mods, lib).into(), &mut args) - .map_err(|err| err.fill_position(pos)) + let context = (self, fn_name, module.id(), &*mods, lib, pos).into(); + func(context, &mut args).map_err(|err| err.fill_position(pos)) } Some(f) => unreachable!("unknown function type: {:?}", f), diff --git a/src/fn_native.rs b/src/fn_native.rs index ac5ad4d5..31799527 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -54,34 +54,53 @@ pub struct NativeCallContext<'a> { source: Option<&'a str>, mods: Option<&'a Imports>, lib: &'a [&'a Module], + pos: Position, } impl<'a, M: AsRef<[&'a Module]> + ?Sized> - From<(&'a Engine, &'a str, Option<&'a str>, &'a Imports, &'a M)> for NativeCallContext<'a> + From<( + &'a Engine, + &'a str, + Option<&'a str>, + &'a Imports, + &'a M, + Position, + )> for NativeCallContext<'a> { #[inline(always)] - fn from(value: (&'a Engine, &'a str, Option<&'a str>, &'a Imports, &'a M)) -> Self { + fn from( + value: ( + &'a Engine, + &'a str, + Option<&'a str>, + &'a Imports, + &'a M, + Position, + ), + ) -> Self { Self { engine: value.0, fn_name: value.1, source: value.2, mods: Some(value.3), lib: value.4.as_ref(), + pos: value.5, } } } -impl<'a, M: AsRef<[&'a Module]> + ?Sized> From<(&'a Engine, &'a str, &'a M)> +impl<'a, M: AsRef<[&'a Module]> + ?Sized> From<(&'a Engine, &'a str, &'a M, Position)> for NativeCallContext<'a> { #[inline(always)] - fn from(value: (&'a Engine, &'a str, &'a M)) -> Self { + fn from(value: (&'a Engine, &'a str, &'a M, Position)) -> Self { Self { engine: value.0, fn_name: value.1, source: None, mods: None, lib: value.2.as_ref(), + pos: value.3, } } } @@ -90,13 +109,19 @@ impl<'a> NativeCallContext<'a> { /// Create a new [`NativeCallContext`]. #[inline(always)] #[must_use] - pub const fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [&Module]) -> Self { + pub const fn new( + engine: &'a Engine, + fn_name: &'a str, + lib: &'a [&Module], + pos: Position, + ) -> Self { Self { engine, fn_name, source: None, mods: None, lib, + pos, } } /// _(internals)_ Create a new [`NativeCallContext`]. @@ -113,6 +138,7 @@ impl<'a> NativeCallContext<'a> { source: Option<&'a str>, imports: &'a Imports, lib: &'a [&Module], + pos: Position, ) -> Self { Self { engine, @@ -120,6 +146,7 @@ impl<'a> NativeCallContext<'a> { source, mods: Some(imports), lib, + pos, } } /// The current [`Engine`]. @@ -134,6 +161,12 @@ impl<'a> NativeCallContext<'a> { pub const fn fn_name(&self) -> &str { self.fn_name } + /// [Position][`Position`] of the function call. + #[inline(always)] + #[must_use] + pub const fn position(&self) -> Position { + self.pos + } /// The current source. #[inline(always)] #[must_use] diff --git a/src/optimize.rs b/src/optimize.rs index 08c1f5bf..3f6f2e82 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -1000,9 +1000,9 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { _ if x.args.len() == 2 && !state.has_native_fn(x.hashes.native, arg_types.as_ref()) => { if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1]) .and_then(|f| { - let ctx = (state.engine, x.name.as_ref(), state.lib).into(); + let context = (state.engine, x.name.as_ref(), state.lib, Position::NONE).into(); let (first, second) = arg_values.split_first_mut().expect("`arg_values` is not empty"); - (f)(ctx, &mut [ first, &mut second[0] ]).ok() + (f)(context, &mut [ first, &mut second[0] ]).ok() }) { state.set_dirty(); *expr = Expr::from_dynamic(result, *pos); diff --git a/src/tests.rs b/src/tests.rs index 98f23fdc..6bcc7033 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -36,4 +36,5 @@ fn check_struct_sizes() { if cfg!(feature = "no_position") { 8 } else { 16 } ); assert_eq!(size_of::(), 72); + assert_eq!(size_of::(), 72); } diff --git a/tests/closures.rs b/tests/closures.rs index c68038f5..598469c4 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -338,7 +338,7 @@ fn test_closures_external() -> Result<(), Box> { // Create native call context let fn_name = fn_ptr.fn_name().to_string(); - let context = NativeCallContext::new(&engine, &fn_name, &lib); + let context = NativeCallContext::new(&engine, &fn_name, &lib, rhai::Position::NONE); // Closure 'f' captures: the engine, the AST, and the curried function pointer let f = move |x: INT| fn_ptr.call_dynamic(&context, None, [x.into()]);