commit
714b8de834
@ -10,8 +10,9 @@ Each function defined in an `AST` can optionally attach _doc-comments_ (which, a
|
|||||||
are comments prefixed by either `///` or `/**`). Doc-comments allow third-party tools to
|
are comments prefixed by either `///` or `/**`). Doc-comments allow third-party tools to
|
||||||
automatically generate documentation for functions defined in a Rhai script.
|
automatically generate documentation for functions defined in a Rhai script.
|
||||||
|
|
||||||
A new API, `Engine::gen_fn_metadata_to_json`, paired with the new `metadata` feature,
|
A new API, `Engine::gen_fn_metadata_to_json` and `Engine::gen_fn_metadata_with_ast_to_json`,
|
||||||
exports the full list of functions metadata (including those in an `AST`) as a JSON document.
|
paired with the new `metadata` feature, exports the full list of functions metadata
|
||||||
|
(including those in an `AST`) as a JSON document.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
@ -36,7 +37,9 @@ New features
|
|||||||
|
|
||||||
* `AST::iter_functions` now returns `ScriptFnMetadata` which includes, among others, _doc-comments_ for functions prefixed by `///` or `/**`.
|
* `AST::iter_functions` now returns `ScriptFnMetadata` which includes, among others, _doc-comments_ for functions prefixed by `///` or `/**`.
|
||||||
* _Doc-comments_ can be enabled/disabled with the new `Engine::set_doc_comments` method.
|
* _Doc-comments_ can be enabled/disabled with the new `Engine::set_doc_comments` method.
|
||||||
* A new feature `metadata` is added that pulls in `serde_json` and enables `Engine::gen_fn_metadata_to_json` which exports the full list of functions metadata (including those inside an `AST`) in JSON format.
|
* A new feature `metadata` is added that pulls in `serde_json` and enables `Engine::gen_fn_metadata_to_json` and ``Engine::gen_fn_metadata_with_ast_to_json` which exports the full list of functions metadata (including those inside an `AST`) in JSON format.
|
||||||
|
* `Engine::on_debug` provides two additional parameters: `source: Option<&str>` and `pos: Position`.
|
||||||
|
* `NativeCallContext` and `EvalContext` both expose `source()` which returns the current source, if any.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
@ -122,6 +122,7 @@ where:
|
|||||||
| • `scope()` | `&Scope` | reference to the current [`Scope`] |
|
| • `scope()` | `&Scope` | reference to the current [`Scope`] |
|
||||||
| • `scope_mut()` | `&mut Scope` | mutable reference to the current [`Scope`]; variables can be added to/removed from it |
|
| • `scope_mut()` | `&mut Scope` | mutable reference to the current [`Scope`]; variables can be added to/removed from it |
|
||||||
| • `engine()` | `&Engine` | reference to the current [`Engine`] |
|
| • `engine()` | `&Engine` | reference to the current [`Engine`] |
|
||||||
|
| • `source()` | `Option<&str>` | reference to the current source, if any |
|
||||||
| • `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements |
|
| • `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements |
|
||||||
| • `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
| • `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
||||||
| • `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any |
|
| • `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any |
|
||||||
|
@ -74,6 +74,7 @@ where:
|
|||||||
| `context` | `&EvalContext` | reference to the current evaluation _context_ |
|
| `context` | `&EvalContext` | reference to the current evaluation _context_ |
|
||||||
| • `scope()` | `&Scope` | reference to the current [`Scope`] |
|
| • `scope()` | `&Scope` | reference to the current [`Scope`] |
|
||||||
| • `engine()` | `&Engine` | reference to the current [`Engine`] |
|
| • `engine()` | `&Engine` | reference to the current [`Engine`] |
|
||||||
|
| • `source()` | `Option<&str>` | reference to the current source, if any |
|
||||||
| • `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements |
|
| • `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements |
|
||||||
| • `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
| • `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
||||||
| • `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any |
|
| • `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any |
|
||||||
|
@ -228,6 +228,7 @@ of the particular call to a registered Rust function. It is a type that exposes
|
|||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
| ------------------- | :-----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| ------------------- | :-----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
||||||
|
| `source()` | `Option<&str>` | reference to the current source, if any |
|
||||||
| `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
| `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
||||||
| `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
| `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
||||||
|
|
||||||
@ -254,11 +255,11 @@ let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
|
|||||||
// Get rid of the script, retaining only functions
|
// Get rid of the script, retaining only functions
|
||||||
ast.retain_functions(|_, _, _| true);
|
ast.retain_functions(|_, _, _| true);
|
||||||
|
|
||||||
|
// Create function namespace from the 'AST'
|
||||||
|
let lib = [ast.as_ref()];
|
||||||
|
|
||||||
// Create native call context
|
// Create native call context
|
||||||
let context = NativeCallContext::new(
|
let context = NativeCallContext::new(&engine, &lib);
|
||||||
&engine, // the 'Engine'
|
|
||||||
&[ast.as_ref()] // function namespace from the 'AST'
|
|
||||||
);
|
|
||||||
|
|
||||||
// 'f' captures: the engine, the AST, and the closure
|
// 'f' captures: the engine, the AST, and the closure
|
||||||
let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]);
|
let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]);
|
||||||
|
@ -89,6 +89,7 @@ specially by the plugins system.
|
|||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
| ------------------- | :-----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| ------------------- | :-----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
||||||
|
| `source()` | `Option<&str>` | reference to the current source, if any |
|
||||||
| `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
| `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
||||||
| `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
| `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
||||||
|
|
||||||
|
@ -400,6 +400,7 @@ specially by the plugins system.
|
|||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
| ------------------- | :-----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| ------------------- | :-----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
||||||
|
| `source()` | `Option<&str>` | reference to the current source, if any |
|
||||||
| `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
| `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
||||||
| `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
| `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ where:
|
|||||||
| `T` | `impl Clone` | return type of the function |
|
| `T` | `impl Clone` | return type of the function |
|
||||||
| `context` | `NativeCallContext` | the current _native call context_ |
|
| `context` | `NativeCallContext` | the current _native call context_ |
|
||||||
| • `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
| • `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
|
||||||
|
| • `source()` | `Option<&str>` | reference to the current source, if any |
|
||||||
| • `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
| • `imports()` | `Option<&Imports>` | reference to the current stack of [modules] imported via `import` statements (if any) |
|
||||||
| • `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
| • `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
|
||||||
| `args` | `&mut [&mut Dynamic]` | a slice containing `&mut` references to [`Dynamic`] values.<br/>The slice is guaranteed to contain enough arguments _of the correct types_. |
|
| `args` | `&mut [&mut Dynamic]` | a slice containing `&mut` references to [`Dynamic`] values.<br/>The slice is guaranteed to contain enough arguments _of the correct types_. |
|
||||||
|
@ -560,6 +560,11 @@ impl<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm,
|
|||||||
pub fn engine(&self) -> &'e Engine {
|
pub fn engine(&self) -> &'e Engine {
|
||||||
self.engine
|
self.engine
|
||||||
}
|
}
|
||||||
|
/// The current source.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn source<'z: 's>(&'z self) -> Option<&'s str> {
|
||||||
|
self.state.source.as_ref().map(|s| s.as_str())
|
||||||
|
}
|
||||||
/// The current [`Scope`].
|
/// The current [`Scope`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn scope(&self) -> &Scope<'px> {
|
pub fn scope(&self) -> &Scope<'px> {
|
||||||
@ -2002,9 +2007,12 @@ impl Engine {
|
|||||||
// Overriding exact implementation
|
// Overriding exact implementation
|
||||||
if func.is_plugin_fn() {
|
if func.is_plugin_fn() {
|
||||||
func.get_plugin_fn()
|
func.get_plugin_fn()
|
||||||
.call((self, &*mods, lib).into(), args)?;
|
.call((self, &state.source, &*mods, lib).into(), args)?;
|
||||||
} else {
|
} else {
|
||||||
func.get_native_fn()((self, &*mods, lib).into(), args)?;
|
func.get_native_fn()(
|
||||||
|
(self, &state.source, &*mods, lib).into(),
|
||||||
|
args,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Built-in op-assignment function
|
// Built-in op-assignment function
|
||||||
|
@ -178,7 +178,9 @@ impl Engine {
|
|||||||
// 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
|
||||||
// lib.get_fn(hash_fn, pub_only)
|
// Finally search modules
|
||||||
|
|
||||||
|
//lib.get_fn(hash_fn, pub_only)
|
||||||
let f = self
|
let f = self
|
||||||
.global_namespace
|
.global_namespace
|
||||||
.get_fn(hash_fn, pub_only)
|
.get_fn(hash_fn, pub_only)
|
||||||
@ -198,9 +200,10 @@ impl Engine {
|
|||||||
|
|
||||||
// Run external function
|
// Run external function
|
||||||
let result = if func.is_plugin_fn() {
|
let result = if func.is_plugin_fn() {
|
||||||
func.get_plugin_fn().call((self, mods, lib).into(), args)
|
func.get_plugin_fn()
|
||||||
|
.call((self, &state.source, mods, lib).into(), args)
|
||||||
} else {
|
} else {
|
||||||
func.get_native_fn()((self, mods, lib).into(), args)
|
func.get_native_fn()((self, &state.source, mods, lib).into(), args)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
@ -210,17 +213,16 @@ impl Engine {
|
|||||||
|
|
||||||
// See if the function match print/debug (which requires special processing)
|
// See if the function match print/debug (which requires special processing)
|
||||||
return Ok(match fn_name {
|
return Ok(match fn_name {
|
||||||
KEYWORD_PRINT => (
|
KEYWORD_PRINT => {
|
||||||
(self.print)(result.as_str().map_err(|typ| {
|
let text = result.as_str().map_err(|typ| {
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
})?)
|
})?;
|
||||||
.into(),
|
((self.print)(text).into(), false)
|
||||||
false,
|
}
|
||||||
),
|
|
||||||
KEYWORD_DEBUG => {
|
KEYWORD_DEBUG => {
|
||||||
let text = result.as_str().map_err(|typ| {
|
let text = result.as_str().map_err(|typ| {
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
@ -534,10 +536,13 @@ impl Engine {
|
|||||||
// Get function
|
// Get function
|
||||||
let (func, mut source) = lib
|
let (func, mut source) = lib
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|&m| m.get_fn(hash_script, pub_only).map(|f| (f, m.clone_id())))
|
.find_map(|&m| {
|
||||||
|
m.get_fn(hash_script, pub_only)
|
||||||
|
.map(|f| (f, m.id_raw().clone()))
|
||||||
|
})
|
||||||
//.or_else(|| self.global_namespace.get_fn(hash_script, pub_only))
|
//.or_else(|| self.global_namespace.get_fn(hash_script, pub_only))
|
||||||
.or_else(|| self.packages.get_fn(hash_script).map(|f| (f, None)))
|
.or_else(|| self.packages.get_fn(hash_script).map(|f| (f, None)))
|
||||||
//.or_else(|| mods.iter().find_map(|(_, m)| m.get_qualified_fn(hash_script).map(|f| (f, m.clone_id()))))
|
//.or_else(|| mods.iter().find_map(|(_, m)| m.get_qualified_fn(hash_script).map(|f| (f, m.id_raw().clone()))))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if func.is_script() {
|
if func.is_script() {
|
||||||
@ -1176,7 +1181,7 @@ impl Engine {
|
|||||||
let new_scope = &mut Default::default();
|
let new_scope = &mut Default::default();
|
||||||
let fn_def = f.get_fn_def().clone();
|
let fn_def = f.get_fn_def().clone();
|
||||||
|
|
||||||
let mut source = module.clone_id();
|
let mut source = module.id_raw().clone();
|
||||||
mem::swap(&mut state.source, &mut source);
|
mem::swap(&mut state.source, &mut source);
|
||||||
|
|
||||||
let result = self.call_script_fn(
|
let result = self.call_script_fn(
|
||||||
@ -1190,7 +1195,7 @@ impl Engine {
|
|||||||
Some(f) if f.is_plugin_fn() => f
|
Some(f) if f.is_plugin_fn() => f
|
||||||
.get_plugin_fn()
|
.get_plugin_fn()
|
||||||
.clone()
|
.clone()
|
||||||
.call((self, &*mods, lib).into(), 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
|
||||||
@ -1201,7 +1206,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.get_native_fn()((self, &*mods, lib).into(), args.as_mut())
|
f.get_native_fn()((self, module.id_raw(), &*mods, lib).into(), args.as_mut())
|
||||||
}
|
}
|
||||||
Some(_) => unreachable!(),
|
Some(_) => unreachable!(),
|
||||||
None if def_val.is_some() => Ok(def_val.unwrap().clone()),
|
None if def_val.is_some() => Ok(def_val.unwrap().clone()),
|
||||||
|
@ -47,42 +47,47 @@ pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
|
|||||||
|
|
||||||
/// Context of a native Rust function call.
|
/// Context of a native Rust function call.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> {
|
pub struct NativeCallContext<'e, 's, 'a, 'm, 'pm: 'm> {
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
|
source: Option<&'s str>,
|
||||||
pub(crate) mods: Option<&'a Imports>,
|
pub(crate) mods: Option<&'a Imports>,
|
||||||
pub(crate) lib: &'m [&'pm Module],
|
pub(crate) lib: &'m [&'pm Module],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'a Imports, &'m M)>
|
impl<'e, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized>
|
||||||
for NativeCallContext<'e, 'a, 'm, 'pm>
|
From<(&'e Engine, &'s Option<ImmutableString>, &'a Imports, &'m M)>
|
||||||
|
for NativeCallContext<'e, 's, 'a, 'm, 'pm>
|
||||||
{
|
{
|
||||||
fn from(value: (&'e Engine, &'a Imports, &'m M)) -> Self {
|
fn from(value: (&'e Engine, &'s Option<ImmutableString>, &'a Imports, &'m M)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
mods: Some(value.1),
|
source: value.1.as_ref().map(|s| s.as_str()),
|
||||||
lib: value.2.as_ref(),
|
mods: Some(value.2),
|
||||||
|
lib: value.3.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'m M)>
|
impl<'e, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'m M)>
|
||||||
for NativeCallContext<'e, '_, 'm, 'pm>
|
for NativeCallContext<'e, '_, '_, 'm, 'pm>
|
||||||
{
|
{
|
||||||
fn from(value: (&'e Engine, &'m M)) -> Self {
|
fn from(value: (&'e Engine, &'m M)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
|
source: None,
|
||||||
mods: None,
|
mods: None,
|
||||||
lib: value.1.as_ref(),
|
lib: value.1.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'a, 'm, 'pm> NativeCallContext<'e, 'a, 'm, 'pm> {
|
impl<'e, 's, 'a, 'm, 'pm> NativeCallContext<'e, 's, 'a, 'm, 'pm> {
|
||||||
/// Create a new [`NativeCallContext`].
|
/// Create a new [`NativeCallContext`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(engine: &'e Engine, lib: &'m impl AsRef<[&'pm Module]>) -> Self {
|
pub fn new(engine: &'e Engine, lib: &'m impl AsRef<[&'pm Module]>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
|
source: None,
|
||||||
mods: None,
|
mods: None,
|
||||||
lib: lib.as_ref(),
|
lib: lib.as_ref(),
|
||||||
}
|
}
|
||||||
@ -92,13 +97,15 @@ impl<'e, 'a, 'm, 'pm> NativeCallContext<'e, 'a, 'm, 'pm> {
|
|||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new_with_imports(
|
pub fn new_with_all_fields(
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
|
source: &'s Option<ImmutableString>,
|
||||||
mods: &'a mut Imports,
|
mods: &'a mut Imports,
|
||||||
lib: &'m impl AsRef<[&'pm Module]>,
|
lib: &'m impl AsRef<[&'pm Module]>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
|
source: source.as_ref().map(|s| s.as_str()),
|
||||||
mods: Some(mods),
|
mods: Some(mods),
|
||||||
lib: lib.as_ref(),
|
lib: lib.as_ref(),
|
||||||
}
|
}
|
||||||
@ -108,6 +115,11 @@ impl<'e, 'a, 'm, 'pm> NativeCallContext<'e, 'a, 'm, 'pm> {
|
|||||||
pub fn engine(&self) -> &'e Engine {
|
pub fn engine(&self) -> &'e Engine {
|
||||||
self.engine
|
self.engine
|
||||||
}
|
}
|
||||||
|
/// The current source.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn source<'z: 's>(&'z self) -> Option<&'s str> {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
/// _(INTERNALS)_ The current set of modules imported via `import` statements.
|
/// _(INTERNALS)_ The current set of modules imported via `import` statements.
|
||||||
/// Available under the `internals` feature only.
|
/// Available under the `internals` feature only.
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
|
@ -244,8 +244,8 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the ID of the module, if any.
|
/// Get the ID of the module, if any.
|
||||||
pub(crate) fn clone_id(&self) -> Option<ImmutableString> {
|
pub(crate) fn id_raw(&self) -> &Option<ImmutableString> {
|
||||||
self.id.clone()
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the ID of the module.
|
/// Set the ID of the module.
|
||||||
|
@ -1005,7 +1005,7 @@ fn parse_primary(
|
|||||||
Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => {
|
Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => {
|
||||||
if !settings.is_function_scope {
|
if !settings.is_function_scope {
|
||||||
let msg = format!("'{}' can only be used in functions", s);
|
let msg = format!("'{}' can only be used in functions", s);
|
||||||
return Err(PERR::BadInput(LexError::ImproperSymbol(s, msg)).into_err(settings.pos));
|
return Err(LexError::ImproperSymbol(s, msg).into_err(settings.pos));
|
||||||
} else {
|
} else {
|
||||||
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
||||||
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
||||||
@ -1027,8 +1027,7 @@ fn parse_primary(
|
|||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(
|
return Err(
|
||||||
PERR::BadInput(LexError::UnexpectedInput(token.syntax().to_string()))
|
LexError::UnexpectedInput(token.syntax().to_string()).into_err(settings.pos)
|
||||||
.into_err(settings.pos),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1050,10 +1049,10 @@ fn parse_primary(
|
|||||||
return Err(if !match_token(input, Token::LeftParen).0 {
|
return Err(if !match_token(input, Token::LeftParen).0 {
|
||||||
LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos)
|
LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos)
|
||||||
} else {
|
} else {
|
||||||
PERR::BadInput(LexError::ImproperSymbol(
|
LexError::ImproperSymbol(
|
||||||
"!".to_string(),
|
"!".to_string(),
|
||||||
"'!' cannot be used to call module functions".to_string(),
|
"'!' cannot be used to call module functions".to_string(),
|
||||||
))
|
)
|
||||||
.into_err(token_pos)
|
.into_err(token_pos)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1375,10 +1374,10 @@ fn make_assignment_stmt<'a>(
|
|||||||
Err(PERR::AssignmentToConstant("".into()).into_err(lhs.position()))
|
Err(PERR::AssignmentToConstant("".into()).into_err(lhs.position()))
|
||||||
}
|
}
|
||||||
// ??? && ??? = rhs, ??? || ??? = rhs
|
// ??? && ??? = rhs, ??? || ??? = rhs
|
||||||
Expr::And(_, _) | Expr::Or(_, _) => Err(PERR::BadInput(LexError::ImproperSymbol(
|
Expr::And(_, _) | Expr::Or(_, _) => Err(LexError::ImproperSymbol(
|
||||||
"=".to_string(),
|
"=".to_string(),
|
||||||
"Possibly a typo of '=='?".to_string(),
|
"Possibly a typo of '=='?".to_string(),
|
||||||
))
|
)
|
||||||
.into_err(pos)),
|
.into_err(pos)),
|
||||||
// expr = rhs
|
// expr = rhs
|
||||||
_ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())),
|
_ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())),
|
||||||
@ -1482,13 +1481,13 @@ fn make_dot_expr(
|
|||||||
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
|
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
|
||||||
.contains(&x.name.as_ref()) =>
|
.contains(&x.name.as_ref()) =>
|
||||||
{
|
{
|
||||||
return Err(PERR::BadInput(LexError::ImproperSymbol(
|
return Err(LexError::ImproperSymbol(
|
||||||
x.name.to_string(),
|
x.name.to_string(),
|
||||||
format!(
|
format!(
|
||||||
"'{}' should not be called in method style. Try {}(...);",
|
"'{}' should not be called in method style. Try {}(...);",
|
||||||
x.name, x.name
|
x.name, x.name
|
||||||
),
|
),
|
||||||
))
|
)
|
||||||
.into_err(pos));
|
.into_err(pos));
|
||||||
}
|
}
|
||||||
// lhs.func!(...)
|
// lhs.func!(...)
|
||||||
@ -1806,7 +1805,6 @@ fn parse_binary_op(
|
|||||||
make_in_expr(current_lhs, rhs, pos)?
|
make_in_expr(current_lhs, rhs, pos)?
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is needed to parse closure followed by a dot.
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Token::Period => {
|
Token::Period => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = args.pop().unwrap();
|
||||||
@ -1991,10 +1989,10 @@ fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result
|
|||||||
/// Make sure that the expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
|
/// Make sure that the expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
|
||||||
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
|
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
|
||||||
match input.peek().unwrap() {
|
match input.peek().unwrap() {
|
||||||
(Token::Equals, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
|
(Token::Equals, pos) => Err(LexError::ImproperSymbol(
|
||||||
"=".to_string(),
|
"=".to_string(),
|
||||||
"Possibly a typo of '=='?".to_string(),
|
"Possibly a typo of '=='?".to_string(),
|
||||||
))
|
)
|
||||||
.into_err(*pos)),
|
.into_err(*pos)),
|
||||||
(token @ Token::PlusAssign, pos)
|
(token @ Token::PlusAssign, pos)
|
||||||
| (token @ Token::MinusAssign, pos)
|
| (token @ Token::MinusAssign, pos)
|
||||||
@ -2006,10 +2004,10 @@ fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
|
|||||||
| (token @ Token::PowerOfAssign, pos)
|
| (token @ Token::PowerOfAssign, pos)
|
||||||
| (token @ Token::AndAssign, pos)
|
| (token @ Token::AndAssign, pos)
|
||||||
| (token @ Token::OrAssign, pos)
|
| (token @ Token::OrAssign, pos)
|
||||||
| (token @ Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
|
| (token @ Token::XOrAssign, pos) => Err(LexError::ImproperSymbol(
|
||||||
token.syntax().to_string(),
|
token.syntax().to_string(),
|
||||||
"Expecting a boolean expression, not an assignment".to_string(),
|
"Expecting a boolean expression, not an assignment".to_string(),
|
||||||
))
|
)
|
||||||
.into_err(*pos)),
|
.into_err(*pos)),
|
||||||
|
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
@ -2985,10 +2983,7 @@ impl Engine {
|
|||||||
(Token::EOF, _) => (),
|
(Token::EOF, _) => (),
|
||||||
// Return error if the expression doesn't end
|
// Return error if the expression doesn't end
|
||||||
(token, pos) => {
|
(token, pos) => {
|
||||||
return Err(
|
return Err(LexError::UnexpectedInput(token.syntax().to_string()).into_err(*pos))
|
||||||
PERR::BadInput(LexError::UnexpectedInput(token.syntax().to_string()))
|
|
||||||
.into_err(*pos),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use super::str::ImmutableStringDeserializer;
|
use super::str::ImmutableStringDeserializer;
|
||||||
use crate::dynamic::Union;
|
use crate::dynamic::Union;
|
||||||
use crate::stdlib::{any::type_name, boxed::Box, fmt, string::ToString};
|
use crate::stdlib::{any::type_name, boxed::Box, fmt, string::ToString};
|
||||||
use crate::{Dynamic, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position};
|
use crate::{Dynamic, EvalAltResult, ImmutableString, LexError, Position};
|
||||||
use serde::de::{
|
use serde::de::{
|
||||||
DeserializeSeed, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor,
|
DeserializeSeed, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor,
|
||||||
};
|
};
|
||||||
@ -119,11 +119,9 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>(
|
|||||||
|
|
||||||
impl Error for Box<EvalAltResult> {
|
impl Error for Box<EvalAltResult> {
|
||||||
fn custom<T: fmt::Display>(err: T) -> Self {
|
fn custom<T: fmt::Display>(err: T) -> Self {
|
||||||
EvalAltResult::ErrorParsing(
|
LexError::ImproperSymbol("".to_string(), err.to_string())
|
||||||
ParseErrorType::BadInput(LexError::ImproperSymbol("".to_string(), err.to_string())),
|
.into_err(Position::NONE)
|
||||||
Position::NONE,
|
.into()
|
||||||
)
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,17 +213,17 @@ impl From<&crate::Module> for ModuleMetadata {
|
|||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl Engine {
|
impl Engine {
|
||||||
/// Generate a list of all functions (including those defined in an [`AST`][crate::AST], if provided)
|
/// Generate a list of all functions (including those defined in an [`AST`][crate::AST])
|
||||||
/// in JSON format. Available only under the `metadata` feature.
|
/// in JSON format. Available only under the `metadata` feature.
|
||||||
///
|
///
|
||||||
/// Functions from the following sources are included:
|
/// Functions from the following sources are included:
|
||||||
/// 1) Functions defined in an [`AST`][crate::AST] (if provided)
|
/// 1) Functions defined in an [`AST`][crate::AST]
|
||||||
/// 2) Functions registered into the global namespace
|
/// 2) Functions registered into the global namespace
|
||||||
/// 3) Functions in registered sub-modules
|
/// 3) Functions in registered sub-modules
|
||||||
/// 4) Functions in packages (optional)
|
/// 4) Functions in packages (optional)
|
||||||
pub fn gen_fn_metadata_to_json(
|
pub fn gen_fn_metadata_with_ast_to_json(
|
||||||
&self,
|
&self,
|
||||||
ast: Option<&AST>,
|
ast: &AST,
|
||||||
include_packages: bool,
|
include_packages: bool,
|
||||||
) -> serde_json::Result<String> {
|
) -> serde_json::Result<String> {
|
||||||
let mut global: ModuleMetadata = Default::default();
|
let mut global: ModuleMetadata = Default::default();
|
||||||
@ -254,4 +254,15 @@ impl Engine {
|
|||||||
|
|
||||||
serde_json::to_string_pretty(&global)
|
serde_json::to_string_pretty(&global)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a list of all functions in JSON format.
|
||||||
|
/// Available only under the `metadata` feature.
|
||||||
|
///
|
||||||
|
/// Functions from the following sources are included:
|
||||||
|
/// 1) Functions registered into the global namespace
|
||||||
|
/// 2) Functions in registered sub-modules
|
||||||
|
/// 3) Functions in packages (optional)
|
||||||
|
pub fn gen_fn_metadata_to_json(&self, include_packages: bool) -> serde_json::Result<String> {
|
||||||
|
self.gen_fn_metadata_with_ast_to_json(&Default::default(), include_packages)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
use rhai::{Engine, EvalAltResult, FnPtr, ParseErrorType, RegisterFn, Scope, INT};
|
use rhai::{
|
||||||
|
Engine, EvalAltResult, FnPtr, NativeCallContext, ParseErrorType, RegisterFn, Scope, INT,
|
||||||
|
};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem::take;
|
use std::mem::take;
|
||||||
@ -269,8 +271,14 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
|||||||
// Get rid of the script, retaining only functions
|
// Get rid of the script, retaining only functions
|
||||||
ast.retain_functions(|_, _, _, _| true);
|
ast.retain_functions(|_, _, _, _| true);
|
||||||
|
|
||||||
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
// Create function namespace from the 'AST'
|
||||||
let f = move |x: INT| fn_ptr.call_dynamic((&engine, &[ast.as_ref()]).into(), None, [x.into()]);
|
let lib = [ast.as_ref()];
|
||||||
|
|
||||||
|
// Create native call context
|
||||||
|
let context = NativeCallContext::new(&engine, &lib);
|
||||||
|
|
||||||
|
// 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()]);
|
||||||
|
|
||||||
assert_eq!(f(42)?.as_str(), Ok("hello42"));
|
assert_eq!(f(42)?.as_str(), Ok("hello42"));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user