Merge branch 'master' into plugins
This commit is contained in:
commit
d2ea981fac
@ -46,7 +46,7 @@ struct Config {
|
|||||||
### Make Shared Object
|
### Make Shared Object
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let config: Rc<RefCell<Config>> = Rc::new(RefCell::(Default::default()));
|
let config: Rc<RefCell<Config>> = Rc::new(RefCell::new(Default::default()));
|
||||||
```
|
```
|
||||||
|
|
||||||
### Register Config API
|
### Register Config API
|
||||||
@ -76,7 +76,17 @@ engine.register_fn("config_add", move |values: &mut Array|
|
|||||||
|
|
||||||
let cfg = config.clone();
|
let cfg = config.clone();
|
||||||
engine.register_fn("config_add", move |key: String, value: bool|
|
engine.register_fn("config_add", move |key: String, value: bool|
|
||||||
cfg.borrow_mut().som_map.insert(key, value)
|
cfg.borrow_mut().some_map.insert(key, value)
|
||||||
|
);
|
||||||
|
|
||||||
|
let cfg = config.clone();
|
||||||
|
engine.register_fn("config_contains", move |value: String|
|
||||||
|
cfg.borrow().some_list.contains(&value)
|
||||||
|
);
|
||||||
|
|
||||||
|
let cfg = config.clone();
|
||||||
|
engine.register_fn("config_is_set", move |value: String|
|
||||||
|
cfg.borrow().some_map.get(&value).cloned().unwrap_or(false)
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -91,7 +101,10 @@ config_set_id("hello");
|
|||||||
|
|
||||||
config_add("foo"); // add to list
|
config_add("foo"); // add to list
|
||||||
config_add("bar", true); // add to map
|
config_add("bar", true); // add to map
|
||||||
config_add("baz", false); // add to map
|
|
||||||
|
if config_contains("hey") || config_is_set("hey") {
|
||||||
|
config_add("baz", false); // add to map
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Load the Configuration
|
### Load the Configuration
|
||||||
@ -103,3 +116,35 @@ let id = config_get_id();
|
|||||||
|
|
||||||
id == "hello";
|
id == "hello";
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Consider a Custom Syntax
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
This is probably one of the few scenarios where a [custom syntax] can be recommended.
|
||||||
|
|
||||||
|
A properly-designed [custom syntax] can make the configuration file clean, simple to write,
|
||||||
|
easy to understand and quick to modify.
|
||||||
|
|
||||||
|
For example, the above configuration example may be expressed by this custom syntax:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
------------------
|
||||||
|
| my_config.rhai |
|
||||||
|
------------------
|
||||||
|
|
||||||
|
// Configure ID
|
||||||
|
id "hello";
|
||||||
|
|
||||||
|
// Add to list
|
||||||
|
list +"foo"
|
||||||
|
|
||||||
|
// Add to map
|
||||||
|
map "bar" => true;
|
||||||
|
|
||||||
|
if config contains "hey" || config is_set "hey" {
|
||||||
|
map "baz" => false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that `contains` and `is_set` may be implemented as a [custom operator].
|
||||||
|
@ -171,9 +171,9 @@ to partition the slice:
|
|||||||
let (first, rest) = args.split_at_mut(1);
|
let (first, rest) = args.split_at_mut(1);
|
||||||
|
|
||||||
// Mutable reference to the first parameter
|
// Mutable reference to the first parameter
|
||||||
let this_ptr: &mut Dynamic = &mut *first[0].write_lock::<A>().unwrap();
|
let this_ptr: &mut A = &mut *first[0].write_lock::<A>().unwrap();
|
||||||
|
|
||||||
// Immutable reference to the second value parameter
|
// Immutable reference to the second value parameter
|
||||||
// This can be mutable but there is no point because the parameter is passed by value
|
// This can be mutable but there is no point because the parameter is passed by value
|
||||||
let value_ref: &Dynamic = &*rest[0].read_lock::<B>().unwrap();
|
let value_ref: &B = &*rest[0].read_lock::<B>().unwrap();
|
||||||
```
|
```
|
||||||
|
@ -611,9 +611,9 @@ impl Module {
|
|||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
let mut a = args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
|
|
||||||
func(&mut a, b).map(Dynamic::from)
|
func(a, b).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
|
||||||
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
|
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
|
||||||
@ -735,9 +735,9 @@ impl Module {
|
|||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
let c = mem::take(args[2]).cast::<C>();
|
let c = mem::take(args[2]).cast::<C>();
|
||||||
let mut a = args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
|
|
||||||
func(&mut a, b, c).map(Dynamic::from)
|
func(a, b, c).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
||||||
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
|
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
|
||||||
@ -769,9 +769,9 @@ impl Module {
|
|||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
let c = mem::take(args[2]).cast::<C>();
|
let c = mem::take(args[2]).cast::<C>();
|
||||||
let mut a = args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
|
|
||||||
func(&mut a, b, c).map(Dynamic::from)
|
func(a, b, c).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
@ -892,9 +892,9 @@ impl Module {
|
|||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
let c = mem::take(args[2]).cast::<C>();
|
let c = mem::take(args[2]).cast::<C>();
|
||||||
let d = mem::take(args[3]).cast::<D>();
|
let d = mem::take(args[3]).cast::<D>();
|
||||||
let mut a = args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
|
|
||||||
func(&mut a, b, c, d).map(Dynamic::from)
|
func(a, b, c, d).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
let arg_types = [
|
let arg_types = [
|
||||||
TypeId::of::<A>(),
|
TypeId::of::<A>(),
|
||||||
|
@ -414,7 +414,8 @@ struct ParseState<'e> {
|
|||||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: HashMap<String, Position>,
|
externals: HashMap<String, Position>,
|
||||||
/// An indicator that disables variable capturing into externals one single time.
|
/// An indicator that disables variable capturing into externals one single time
|
||||||
|
/// up until the nearest consumed Identifier token.
|
||||||
/// If set to false the next call to `access_var` will not capture the variable.
|
/// If set to false the next call to `access_var` will not capture the variable.
|
||||||
/// All consequent calls to `access_var` will not be affected
|
/// All consequent calls to `access_var` will not be affected
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -1637,6 +1638,11 @@ fn parse_primary(
|
|||||||
|
|
||||||
// Function call
|
// Function call
|
||||||
Token::Identifier(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
Token::Identifier(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
||||||
|
// Once the identifier consumed we must enable next variables capturing
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
{
|
||||||
|
state.allow_capture = true;
|
||||||
|
}
|
||||||
Expr::Variable(Box::new(((s, settings.pos), None, 0, None)))
|
Expr::Variable(Box::new(((s, settings.pos), None, 0, None)))
|
||||||
}
|
}
|
||||||
// Normal variable access
|
// Normal variable access
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, Module, RegisterFn, INT};
|
use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, Module, RegisterFn, INT};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
use std::mem::take;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
|
fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
|
||||||
@ -88,6 +89,59 @@ fn test_closures() -> Result<(), Box<EvalAltResult>> {
|
|||||||
42
|
42
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
r#"
|
||||||
|
let a = 40;
|
||||||
|
let f = |x| {
|
||||||
|
let f = |x| {
|
||||||
|
let f = |x| plus_one(a) + x;
|
||||||
|
f.call(x)
|
||||||
|
};
|
||||||
|
f.call(x)
|
||||||
|
};
|
||||||
|
f.call(1)
|
||||||
|
"#
|
||||||
|
)?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
r#"
|
||||||
|
let a = 21;
|
||||||
|
let f = |x| a += x;
|
||||||
|
f.call(a);
|
||||||
|
a
|
||||||
|
"#
|
||||||
|
)?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
|
engine.register_raw_fn(
|
||||||
|
"custom_call",
|
||||||
|
&[TypeId::of::<INT>(), TypeId::of::<FnPtr>()],
|
||||||
|
|engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| {
|
||||||
|
let func = take(args[1]).cast::<FnPtr>();
|
||||||
|
|
||||||
|
func.call_dynamic(engine, module, None, [])
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
r#"
|
||||||
|
let a = 41;
|
||||||
|
let b = 0;
|
||||||
|
let f = || b.custom_call(|| a + 1);
|
||||||
|
|
||||||
|
f.call()
|
||||||
|
"#
|
||||||
|
)?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user