Add is_def_var and is_def_fn.
This commit is contained in:
@@ -14,7 +14,9 @@ Versions
|
||||
|
||||
This Book is for version **{{version}}** of Rhai.
|
||||
|
||||
{% if rootUrl != "" and not rootUrl is ending_with("vnext") %}
|
||||
For the latest development version, see [here]({{rootUrl}}/vnext/).
|
||||
{% endif %}
|
||||
|
||||
|
||||
Etymology of the name "Rhai"
|
||||
|
@@ -3,36 +3,38 @@ Keywords List
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
| Keyword | Description | Inactive under | Overloadable |
|
||||
| :-------------------: | ------------------------------------------- | :-------------: | :----------: |
|
||||
| `true` | boolean true literal | | no |
|
||||
| `false` | boolean false literal | | no |
|
||||
| `let` | variable declaration | | no |
|
||||
| `const` | constant declaration | | no |
|
||||
| `is_shared` | is a value shared? | | no |
|
||||
| `if` | if statement | | no |
|
||||
| `else` | else block of if statement | | no |
|
||||
| `while` | while loop | | no |
|
||||
| `loop` | infinite loop | | no |
|
||||
| `for` | for loop | | no |
|
||||
| `in` | 1) containment test<br/>2) part of for loop | | no |
|
||||
| `continue` | continue a loop at the next iteration | | no |
|
||||
| `break` | break out of loop iteration | | no |
|
||||
| `return` | return value | | no |
|
||||
| `throw` | throw exception | | no |
|
||||
| `import` | import module | [`no_module`] | no |
|
||||
| `export` | export variable | [`no_module`] | no |
|
||||
| `as` | alias for variable export | [`no_module`] | no |
|
||||
| `private` | mark function private | [`no_function`] | no |
|
||||
| `fn` (lower-case `f`) | function definition | [`no_function`] | no |
|
||||
| `Fn` (capital `F`) | create a [function pointer] | | yes |
|
||||
| `call` | call a [function pointer] | | no |
|
||||
| `curry` | curry a [function pointer] | | no |
|
||||
| `this` | reference to base object for method call | [`no_function`] | no |
|
||||
| `type_of` | get type name of value | | yes |
|
||||
| `print` | print value | | yes |
|
||||
| `debug` | print value in debug format | | yes |
|
||||
| `eval` | evaluate script | | yes |
|
||||
| Keyword | Description | Inactive under | Is function? | Overloadable |
|
||||
| :-------------------: | ------------------------------------------- | :-------------: | :----------: | :----------: |
|
||||
| `true` | boolean true literal | | no | |
|
||||
| `false` | boolean false literal | | no | |
|
||||
| `let` | variable declaration | | no | |
|
||||
| `const` | constant declaration | | no | |
|
||||
| `is_def_var` | is a variable declared? | | yes | yes |
|
||||
| `is_shared` | is a value shared? | [`no_closure`] | yes | no |
|
||||
| `if` | if statement | | no | |
|
||||
| `else` | else block of if statement | | no | |
|
||||
| `while` | while loop | | no | |
|
||||
| `loop` | infinite loop | | no | |
|
||||
| `for` | for loop | | no | |
|
||||
| `in` | 1) containment test<br/>2) part of for loop | | no | |
|
||||
| `continue` | continue a loop at the next iteration | | no | |
|
||||
| `break` | break out of loop iteration | | no | |
|
||||
| `return` | return value | | no | |
|
||||
| `throw` | throw exception | | no | |
|
||||
| `import` | import module | [`no_module`] | no | |
|
||||
| `export` | export variable | [`no_module`] | no | |
|
||||
| `as` | alias for variable export | [`no_module`] | no | |
|
||||
| `private` | mark function private | [`no_function`] | no | |
|
||||
| `fn` (lower-case `f`) | function definition | [`no_function`] | no | |
|
||||
| `Fn` (capital `F`) | create a [function pointer] | | yes | yes |
|
||||
| `call` | call a [function pointer] | | yes | no |
|
||||
| `curry` | curry a [function pointer] | | yes | no |
|
||||
| `this` | reference to base object for method call | [`no_function`] | no | |
|
||||
| `is_def_fn` | is a scripted function defined? | [`no_function`] | yes | yes |
|
||||
| `type_of` | get type name of value | | yes | yes |
|
||||
| `print` | print value | | yes | yes |
|
||||
| `debug` | print value in debug format | | yes | yes |
|
||||
| `eval` | evaluate script | | yes | yes |
|
||||
|
||||
|
||||
Reserved Keywords
|
||||
|
@@ -101,6 +101,21 @@ a statement in the script can freely call a function defined afterwards.
|
||||
This is similar to Rust and many other modern languages, such as JavaScript's `function` keyword.
|
||||
|
||||
|
||||
`is_def_fn`
|
||||
-----------
|
||||
|
||||
Use `is_def_fn` to detect if a function is defined (and therefore callable), based on its name
|
||||
and the number of parameters.
|
||||
|
||||
```rust
|
||||
fn foo(x) { x + 1 }
|
||||
|
||||
is_def_fn("foo", 1) == true;
|
||||
|
||||
is_def_fn("bar", 1) == false;
|
||||
```
|
||||
|
||||
|
||||
Arguments are Passed by Value
|
||||
----------------------------
|
||||
|
||||
|
@@ -37,6 +37,8 @@ If none is provided, it defaults to [`()`].
|
||||
|
||||
A variable defined within a statement block is _local_ to that block.
|
||||
|
||||
Use `is_def_var` to detect if a variable is defined.
|
||||
|
||||
```rust
|
||||
let x; // ok - value is '()'
|
||||
let x = 3; // ok
|
||||
@@ -57,4 +59,10 @@ X == 123;
|
||||
x == 999; // access to local 'x'
|
||||
}
|
||||
x == 42; // the parent block's 'x' is not changed
|
||||
|
||||
is_def_var("x") == true;
|
||||
|
||||
is_def_var("_x") == true;
|
||||
|
||||
is_def_var("y") == false;
|
||||
```
|
||||
|
@@ -32,28 +32,97 @@ are _merged_ into a _unified_ namespace.
|
||||
| my_module.rhai |
|
||||
------------------
|
||||
|
||||
// This function overrides any in the main script.
|
||||
private fn inner_message() { "hello! from module!" }
|
||||
|
||||
fn greet(callback) { print(callback.call()); }
|
||||
fn greet() {
|
||||
print(inner_message()); // call function in module script
|
||||
}
|
||||
|
||||
fn greet_main() {
|
||||
print(main_message()); // call function not in module script
|
||||
}
|
||||
|
||||
-------------
|
||||
| main.rhai |
|
||||
-------------
|
||||
|
||||
fn main_message() { "hi! from main!" }
|
||||
// This function is overridden by the module script.
|
||||
fn inner_message() { "hi! from main!" }
|
||||
|
||||
// This function is found by the module script.
|
||||
fn main_message() { "main here!" }
|
||||
|
||||
import "my_module" as m;
|
||||
|
||||
m::greet(|| "hello, " + "world!"); // works - anonymous function in global
|
||||
m::greet(); // prints "hello! from module!"
|
||||
|
||||
m::greet(|| inner_message()); // works - function in module
|
||||
|
||||
m::greet(|| main_message()); // works - function in global
|
||||
m::greet_main(); // prints "main here!"
|
||||
```
|
||||
|
||||
### Simulating virtual functions
|
||||
|
||||
When calling a namespace-qualified function defined within a module, other functions defined within
|
||||
the same module script override any similar-named functions (with the same number of parameters)
|
||||
defined in the global namespace. This is to ensure that a module acts as a self-contained unit and
|
||||
functions defined in the calling script do not override module code.
|
||||
|
||||
In some situations, however, it is actually beneficial to do it in reverse: have module code call functions
|
||||
defined in the calling script (i.e. in the global namespace) if they exist, and only call those defined
|
||||
in the module script if none are found.
|
||||
|
||||
One such situation is the need to provide a _default implementation_ to a simulated _virtual_ function:
|
||||
|
||||
```rust
|
||||
------------------
|
||||
| my_module.rhai |
|
||||
------------------
|
||||
|
||||
// Do not do this (it will override the main script):
|
||||
// fn message() { "hello! from module!" }
|
||||
|
||||
// This function acts as the default implementation.
|
||||
private fn default_message() { "hello! from module!" }
|
||||
|
||||
// This function depends on a 'virtual' function 'message'
|
||||
// which is not defined in the module script.
|
||||
fn greet() {
|
||||
if is_def_fn("message", 0) { // 'is_def_fn' detects if 'message' is defined.
|
||||
print(message());
|
||||
} else {
|
||||
print(default_message());
|
||||
}
|
||||
}
|
||||
|
||||
-------------
|
||||
| main.rhai |
|
||||
-------------
|
||||
|
||||
// The main script defines 'message' which is needed by the module script.
|
||||
fn message() { "hi! from main!" }
|
||||
|
||||
import "my_module" as m;
|
||||
|
||||
m::greet(); // prints "hi! from main!"
|
||||
|
||||
--------------
|
||||
| main2.rhai |
|
||||
--------------
|
||||
|
||||
// The main script does not define 'message' which is needed by the module script.
|
||||
|
||||
import "my_module" as m;
|
||||
|
||||
m::greet(); // prints "hello! from module!"
|
||||
```
|
||||
|
||||
### Changing the base directory
|
||||
|
||||
The base directory can be changed via the `FileModuleResolver::new_with_path` constructor function.
|
||||
|
||||
`FileModuleResolver::create_module` loads a script file and returns a module.
|
||||
### Returning a module instead
|
||||
|
||||
`FileModuleResolver::create_module` loads a script file and returns a module with the standard behavior.
|
||||
|
||||
|
||||
`StaticModuleResolver`
|
||||
|
Reference in New Issue
Block a user