rhaiscript / rhai

Rhai - An embedded scripting language for Rust.
https://crates.io/crates/rhai
Apache License 2.0
3.79k stars 177 forks source link

`in` operator. (was: can Any::downcast_ref be public? after upgrading rhai it's private now) #124

Closed GopherJ closed 4 years ago

schungx commented 4 years ago

No reason why it can't. I'll make it public.

Watch for it to show up at the latest PR https://github.com/jonathandturner/rhai/pull/123

GopherJ commented 4 years ago

Hello @schungx cool, also I'm thinking if rhai can add in operator to detect if some element is in a list.

My use case is in casbin-rs: https://github.com/casbin/casbin-rs

We use rhai for evaluating string expression. Now rhai doesn't support in operator so we have to convert

r.sub in ("alice", "bob")

into

inMatch(r.sub, ["alice", "bob"])

and register an inMatch function.

schungx commented 4 years ago

You can probably write your own very simple function to do it. Rhai doesn't provide one for arrays because, technically speaking, you can override the == operator and define your own equality comparisons.

fn contains(array, element) {
    for item in array {
        if item == element { return true; }
    }
    false
}

Then you can write something like:

let list = ["alice", "bob"];
if list.contains(r.sub) {
    .... do something
}

However, this will be quite inefficient because the list array is copied by value every time you call the function. If you want it fast, you can write your own small function in Rust and then register_fn it. For example, if you're only handling arrays of strings, you can do something similar to:

engine.register_fn("contains", |list: &mut Array, item: String| {
    list.iter().map(|x| x.as_ref().downcast_ref::<String>().unwrap()).any(|s| s == &item)
});
schungx commented 4 years ago

My use case is in casbin-rs: https://github.com/casbin/casbin-rs

Your use case only seems to need expressions instead of full scripting. Therefore, you should check out compile_expression which only compiles a subset of the language -- those to support expressions -- to an AST. Then you can repeatedly evaluate that AST without needing to parse again.

You'd also want to exclude language features you don't need. For example, you may not need the standard library of functions, so no_stdlib. You may not need floating-point (no_float), or different integer types (only_i32). And definitely you'd not need to define any functions (no_function).

GopherJ commented 4 years ago

@schungx that's actually not convinent, I'm using that method but I need to use regex to convert the following expressing:

r.sub in ("alice", "bob")

to

contains(r.sub, ["alice", "bob"])
GopherJ commented 4 years ago

ideally we should support the javascript-like in operator in rhai

schungx commented 4 years ago

So what you're suggesting is:

Expression :    Expression  'in'  Expression (must evaluate to Array)

This is probably easily doable by adding an in infix operator. Let me experiment a bit.

Might as well add:

let x = #{a: 1, b:2};
("a" in x) == true;      // JavaScript
schungx commented 4 years ago

contains(r.sub, ["alice", "bob"])

It might be easier for your code generation to convert it into:

let x = r.sub;
(x == "alice") || (x == "bob")

Should be more efficient since arrays and strings do not need to be copied around.

GopherJ commented 4 years ago

It's already implemented for the conversion but I would like to have it supported in rhai

https://github.com/casbin/casbin-rs/blob/301420c7630cd3b6021f9738facf213e19080dc8/src/util.rs#L13

because it's not a graceful solution, I would like to remove it when in operator is supported in rhai.

schungx commented 4 years ago

PR https://github.com/jonathandturner/rhai/pull/128 adds 'in' expressions.

GopherJ commented 4 years ago

@schungx Cool, could you notify me when it's merged and published? I'll test it. Thanks for your awesome work

schungx commented 4 years ago

It is already merged and published to crates.io as 0.11.1.

GopherJ commented 4 years ago

@schungx I mean #128

schungx commented 4 years ago

Yes, https://github.com/jonathandturner/rhai/pull/128 is published as 0.11.1.