Add is_def_var and is_def_fn.

This commit is contained in:
Stephen Chung
2020-10-03 16:25:58 +08:00
parent eec3f4e1bf
commit fbfb7677c1
10 changed files with 220 additions and 56 deletions

View File

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