reorganize module

This commit is contained in:
Timur Gordon
2025-04-04 08:28:07 +02:00
parent 1ea37e2e7f
commit 939b6b4e57
375 changed files with 7580 additions and 191 deletions

View File

@@ -0,0 +1,184 @@
Generate Definition Files for Language Server
=============================================
{{#include ../../links.md}}
Rhai's [language server][lsp] works with IDEs to provide integrated support for the Rhai scripting language.
Functions and [modules] registered with an [`Engine`] can output their [metadata][functions metadata]
into _definition files_ which are used by the [language server][lsp].
Definitions are generated via the `Engine::definitions` and `Engine::definitions_with_scope` API.
This API requires the [`metadata`] and [`internals`] feature.
Configurable Options
--------------------
The `Definitions` type supports the following options in a fluent method-chaining style.
| Option | Method | Default |
| ------------------------------------------------------------------- | --------------------------- | :-----: |
| Write headers in definition files? | `with_headers` | `false` |
| Include [standard packages][built-in packages] in definition files? | `include_standard_packages` | `true` |
```rust
engine
.definitions()
.with_headers(true) // write headers in all files
.include_standard_packages(false) // skip standard packages
.write_to_dir("path/to/my/definitions")
.unwrap();
```
Example
-------
```rust
use rhai::{Engine, Scope};
use rhai::plugin::*;
// Plugin module: 'general_kenobi'
#[export_module]
pub mod general_kenobi {
use std::convert::TryInto;
/// Returns a string where "hello there" is repeated 'n' times.
pub fn hello_there(n: i64) -> String {
"hello there ".repeat(n.try_into().unwrap())
}
}
// Create scripting engine
let mut engine = Engine::new();
// Create custom Scope
let mut scope = Scope::new();
// This variable will also show up in the generated definition file.
scope.push("hello_there", "hello there");
// Static module namespaces will generate independent definition files.
engine.register_static_module(
"general_kenobi",
exported_module!(general_kenobi).into()
);
// Custom operators will also show up in the generated definition file.
engine.register_custom_operator("minus", 100).unwrap();
engine.register_fn("minus", |a: i64, b: i64| a - b);
engine.run_with_scope(&mut scope,
"hello_there = general_kenobi::hello_there(4 minus 2);"
)?;
// Output definition files in the specified directory.
engine
.definitions()
.write_to_dir("path/to/my/definitions")
.unwrap();
// Output definition files in the specified directory.
// Variables in the provided 'Scope' are included.
engine
.definitions_with_scope(&scope)
.write_to_dir("path/to/my/definitions")
.unwrap();
// Output a single definition file with everything merged.
// Variables in the provided 'Scope' are included.
engine
.definitions_with_scope(&scope)
.write_to_file("path/to/my/definitions/all_in_one.d.rhai")
.unwrap();
// Output functions metadata to a JSON string.
// Functions in standard packages are skipped and not included.
let json = engine
.definitions()
.include_standard_packages(false) // skip standard packages
.unwrap();
```
Definition Files
----------------
The generated definition files will look like the following.
```rust
┌───────────────────────┐
general_kenobi.d.rhai
└───────────────────────┘
module general_kenobi;
/// Returns a string where "hello there" is repeated 'n' times.
fn hello_there(n: int) -> String;
┌──────────────────┐
__scope__.d.rhai
└──────────────────┘
module static;
let hello_there;
┌───────────────────┐
__static__.d.rhai
└───────────────────┘
module static;
op minus(int, int) -> int;
:
:
┌────────────────────┐
__builtin__.d.rhai
└────────────────────┘
module static;
:
:
┌──────────────────────────────┐
__builtin-operators__.d.rhai
└──────────────────────────────┘
module static;
:
:
```
All-in-One Definition File
--------------------------
`Definitions::write_to_file` generates a single definition file with everything merged in, like the following.
```rust
module static;
op minus(int, int) -> int;
:
:
module general_kenobi {
/// Returns a string where "hello there" is repeated 'n' times.
fn hello_there(n: int) -> String;
}
let hello_there;
```

View File

@@ -0,0 +1,147 @@
Export Functions Metadata to JSON
=================================
{{#include ../../links.md}}
`Engine::gen_fn_metadata_to_json`<br/>`Engine::gen_fn_metadata_with_ast_to_json`
--------------------------------------------------------------------------------
As part of a _reflections_ API, `Engine::gen_fn_metadata_to_json` and the corresponding
`Engine::gen_fn_metadata_with_ast_to_json` export the full list of [custom types] and
[functions metadata] in JSON format.
~~~admonish warning.small "Requires `metadata`"
The [`metadata`] feature is required for this API, which also pulls in the
[`serde_json`](https://crates.io/crates/serde_json) crate.
~~~
### Sources
Functions and [custom types] from the following sources are included:
1. Script-defined functions in an [`AST`] (for `Engine::gen_fn_metadata_with_ast_to_json`)
2. Native Rust functions registered into the global namespace via the `Engine::register_XXX` API
3. [Custom types] registered into the global namespace via the `Engine::register_type_with_name` API
4. _Public_ (i.e. non-[`private`]) functions (native Rust or Rhai scripted) and [custom types] in static modules
registered via `Engine::register_static_module`
5. Native Rust functions and [custom types] in external [packages] registered via `Engine::register_global_module`
6. Native Rust functions and [custom types] in [built-in packages] (optional)
JSON Schema
-----------
The JSON schema used to hold metadata is very simple, containing a nested structure of
`modules`, a list of `customTypes` and a list of `functions`.
### Module Schema
```json
{
"doc": "//! Module documentation",
"modules":
{
"sub_module_1": /* namespace 'sub_module_1' */
{
"modules":
{
"sub_sub_module_A": /* namespace 'sub_module_1::sub_sub_module_A' */
{
"doc": "//! Module documentation can also occur in any sub-module",
"customTypes": /* custom types exported in 'sub_module_1::sub_sub_module_A' */
[
{ ... custom type metadata ... },
{ ... custom type metadata ... },
{ ... custom type metadata ... }
...
],
"functions": /* functions exported in 'sub_module_1::sub_sub_module_A' */
[
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... }
...
]
},
"sub_sub_module_B": /* namespace 'sub_module_1::sub_sub_module_B' */
{
...
}
}
},
"sub_module_2": /* namespace 'sub_module_2' */
{
...
},
...
},
"customTypes": /* custom types registered globally */
[
{ ... custom type metadata ... },
{ ... custom type metadata ... },
{ ... custom type metadata ... },
...
],
"functions": /* functions registered globally or in the 'AST' */
[
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... },
...
]
}
```
### Custom Type Metadata Schema
```json
{
"typeName": "alloc::string::String", /* name of Rust type */
"displayName": "MyType",
"docComments": /* omitted if none */
[
"/// My super-string type.",
...
]
}
```
### Function Metadata Schema
```json
{
"baseHash": 9876543210, /* partial hash with only number of parameters */
"fullHash": 1234567890, /* full hash with actual parameter types */
"namespace": "internal" | "global",
"access": "public" | "private",
"name": "fn_name",
"isAnonymous": false,
"type": "native" | "script",
"numParams": 42, /* number of parameters */
"params": /* omitted if no parameters */
[
{ "name": "param_1", "type": "type_1" },
{ "name": "param_2" }, /* no type name */
{ "type": "type_3" }, /* no parameter name */
...
],
"thisType": "this_type", /* omitted if none */
"returnType": "ret_type", /* omitted if () or unknown */
"signature": "[private] fn_name(param_1: type_1, param_2, _: type_3) -> ret_type",
"docComments": /* omitted if none */
[
"/// doc-comment line 1",
"/// doc-comment line 2",
"/** doc-comment block */",
...
]
}
```

View File

@@ -0,0 +1,93 @@
Get Native Function Signatures
==============================
{{#include ../../links.md}}
`Engine::gen_fn_signatures`
---------------------------
As part of a _reflections_ API, `Engine::gen_fn_signatures` returns a list of function _signatures_
(as `Vec<String>`), each corresponding to a particular native function available to that [`Engine`] instance.
> _name_ `(`_param 1_`:`_type 1_`,` _param 2_`:`_type 2_`,` ... `,` _param n_`:`_type n_`) ->` _return type_
The [`metadata`] feature must be used to turn on this API.
### Sources
Functions from the following sources are included, in order:
1. Native Rust functions registered into the global namespace via the `Engine::register_XXX` API
2. _Public_ (i.e. non-[`private`]) functions (native Rust or Rhai scripted) in global sub-modules
registered via `Engine::register_static_module`.
3. Native Rust functions in external [packages] registered via `Engine::register_global_module`
4. Native Rust functions in [built-in packages] (optional)
Functions Metadata
------------------
Beware, however, that not all function signatures contain parameters and return value information.
### `Engine::register_XXX`
For instance, functions registered via `Engine::register_XXX` contain no information on the names of
parameter because Rust simply does not make such metadata available natively.
Type names, however, _are_ provided.
A function registered under the name `foo` with three parameters.
> `foo(_: i64, _: char, _: &str) -> String`
An [operator] function. Notice that function names do not need to be valid identifiers.
> `+=(_: &mut i64, _: i64)`
A [property setter][getters/setters].
Notice that function names do not need to be valid identifiers.
In this case, the first parameter should be `&mut T` of the custom type and the return value is `()`:
> `set$prop(_: &mut TestStruct, _: i64)`
### Script-Defined Functions
Script-defined [function] signatures contain parameter names.
Since _all_ parameters, as well as the return value, are [`Dynamic`] the types are simply not shown.
> `foo(x, y, z)`
is probably defined simply as:
```rust
/// This is a doc-comment, included in this function's metadata.
fn foo(x, y, z) {
...
}
```
which is really the same as:
> `foo(x: Dynamic, y: Dynamic, z: Dynamic) -> Result<Dynamic, Box<EvalAltResult>>`
### Plugin Functions
Functions defined in [plugin modules] are the best.
They contain all metadata describing the functions, including [doc-comments].
For example, a plugin function `combine`:
> `/// This is a doc-comment, included in this function's metadata.`
> `combine(list: &mut MyStruct<i64>, num: usize, name: &str) -> bool`
Notice that function names do not need to be valid identifiers.
For example, an [operator] defined as a [fallible function] in a [plugin module] via
`#[rhai_fn(name="+=", return_raw)]` returns `Result<bool, Box<EvalAltResult>>`:
> `+=(list: &mut MyStruct<i64>, value: &str) -> Result<bool, Box<EvalAltResult>>`
For example, a [property getter][getters/setters] defined in a [plugin module]:
> `get$prop(obj: &mut MyStruct<i64>) -> String`

View File

@@ -0,0 +1,49 @@
Functions and Custom Types Metadata
===================================
{{#include ../../links.md}}
~~~admonish warning.small "Requires `metadata`"
Exporting metadata requires the [`metadata`] feature.
~~~
Functions
---------
The _metadata_ of a [function] means all relevant information related to a function's
definition including:
1. Its callable name
2. Its access mode (public or [private][`private`])
3. Its parameter names and types (if any)
4. Its return value and type (if any)
5. Its nature (i.e. native Rust or Rhai-scripted)
6. Its [namespace][function namespace] ([module] or global)
7. Its purpose, in the form of [doc-comments]
8. Usage notes, warnings, examples etc., in the form of [doc-comments]
A function's _signature_ encapsulates the first four pieces of information in a single concise line
of definition:
> `[private]` _name_ `(`_param 1_`:`_type 1_`,` _param 2_`:`_type 2_`,` ... `,` _param n_`:`_type n_`) ->` _return type_
Custom Types
------------
The _metadata_ of a [custom type] include:
1. Its full Rust type name
2. Its pretty-print _display name_ (which can be the same as its Rust type name)
3. Its purpose, in the form of [doc-comments]