Add NativeCallContext::position.

This commit is contained in:
Stephen Chung 2021-11-05 19:35:33 +08:00
parent ff9ac41da2
commit affbb81d8a
6 changed files with 57 additions and 18 deletions

View File

@ -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
----------------

View File

@ -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),

View File

@ -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]

View File

@ -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);

View File

@ -36,4 +36,5 @@ fn check_struct_sizes() {
if cfg!(feature = "no_position") { 8 } else { 16 }
);
assert_eq!(size_of::<EvalAltResult>(), 72);
assert_eq!(size_of::<NativeCallContext>(), 72);
}

View File

@ -338,7 +338,7 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
// 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()]);