rhai/doc/src/engine/custom-op.md
2020-07-13 13:41:01 +08:00

4.3 KiB

Custom Operators

{{#include ../links.md}}

For use as a DSL (Domain-Specific Languages), it is sometimes more convenient to augment Rhai with customized operators performing specific logic.

Engine::register_custom_operator registers a keyword as a custom operator.

Example

use rhai::{Engine, RegisterFn};

let mut engine = Engine::new();

// Register a custom operator named 'foo' and give it a precedence of 160
// (i.e. between +|- and *|/)
// Also register the implementation of the customer operator as a function
engine
    .register_custom_operator("foo", 160)?
    .register_fn("foo", |x: i64, y: i64| (x * y) - (x + y));

// The custom operator can be used in expressions
let result = engine.eval_expression::<i64>("1 + 2 * 3 foo 4 - 5 / 6")?;
//                                                    ^ custom operator

// The above is equivalent to: 1 + ((2 * 3) foo 4) - (5 / 6)
result == 15;

Alternatives to a Custom Operator

Custom operators are merely syntactic sugar. They map directly to registered functions.

Therefore, the following are equivalent (assuming foo has been registered as a custom operator):

1 + 2 * 3 foo 4 - 5 / 6     // use custom operator

1 + foo(2 * 3, 4) - 5 / 6   // use function call

A script using custom operators can always be pre-processed, via a pre-processor application, into a syntax that uses the corresponding function calls.

Using Engine::register_custom_operator merely enables a convenient shortcut.

Must Follow Variable Naming

All custom operators must be identifiers that follow the same naming rules as [variables].

engine.register_custom_operator("foo", 20);     // 'foo' is a valid custom operator

engine.register_custom_operator("=>", 30);      // <- error: '=>' is not a valid custom operator

Binary Operators Only

All custom operators must be binary (i.e. they take two operands). Unary custom operators are not supported.

engine
    .register_custom_operator("foo", 160)?
    .register_fn("foo", |x: i64| x * x);

engine.eval::<i64>("1 + 2 * 3 foo 4 - 5 / 6")?; // error: function 'foo (i64, i64)' not found

Operator Precedence

All operators in Rhai has a precedence indicating how tightly they bind.

The following precedence table show the built-in precedence of standard Rhai operators:

Category Operators Precedence (0-255)
Assignments =, +=, -=, *=, /=, ~=, %=,
<<=, >>=, &=, |=, ^=
0
Logic and bit masks ||, |, ^ 30
Logic and bit masks &, && 60
Comparisons ==, != 90
Comparisons >, >=, <, <= 110
in 130
Arithmetic +, - 150
Arithmetic *, /, ~, % 180
Bit-shifts <<, >> 210
Object . (binds to right) 240
Others 0

A higher precedence binds more tightly than a lower precedence, so * and / binds before + and - etc.

When registering a custom operator, the operator's precedence must also be provided.