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 ------- ```rust 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::("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): ```rust 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]. ```rust 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. ```rust engine .register_custom_operator("foo", 160)? .register_fn("foo", |x: i64| x * x); engine.eval::("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.