Add switch expression.
This commit is contained in:
@@ -77,13 +77,14 @@ The Rhai Scripting Language
|
||||
7. [Logic Operators](language/logic.md)
|
||||
8. [Other Operators](language/other-op.md)
|
||||
9. [If Statement](language/if.md)
|
||||
10. [While Loop](language/while.md)
|
||||
11. [Loop Statement](language/loop.md)
|
||||
12. [For Loop](language/for.md)
|
||||
13. [Return Values](language/return.md)
|
||||
14. [Throw Exception on Error](language/throw.md)
|
||||
15. [Catch Exceptions](language/try-catch.md)
|
||||
16. [Functions](language/functions.md)
|
||||
10. [Switch Expression](language/switch.md)
|
||||
11. [While Loop](language/while.md)
|
||||
12. [Loop Statement](language/loop.md)
|
||||
13. [For Loop](language/for.md)
|
||||
14. [Return Values](language/return.md)
|
||||
15. [Throw Exception on Error](language/throw.md)
|
||||
16. [Catch Exceptions](language/try-catch.md)
|
||||
17. [Functions](language/functions.md)
|
||||
1. [Call Method as Function](language/method.md)
|
||||
2. [Overloading](language/overload.md)
|
||||
3. [Namespaces](language/fn-namespaces.md)
|
||||
@@ -91,11 +92,11 @@ The Rhai Scripting Language
|
||||
5. [Currying](language/fn-curry.md)
|
||||
6. [Anonymous Functions](language/fn-anon.md)
|
||||
7. [Closures](language/fn-closure.md)
|
||||
17. [Print and Debug](language/print-debug.md)
|
||||
18. [Modules](language/modules/index.md)
|
||||
18. [Print and Debug](language/print-debug.md)
|
||||
19. [Modules](language/modules/index.md)
|
||||
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
|
||||
2. [Import Modules](language/modules/import.md)
|
||||
19. [Eval Statement](language/eval.md)
|
||||
20. [Eval Statement](language/eval.md)
|
||||
6. [Safety and Protection](safety/index.md)
|
||||
1. [Checked Arithmetic](safety/checked.md)
|
||||
2. [Sand-Boxing](safety/sandbox.md)
|
||||
|
@@ -13,6 +13,7 @@ Keywords List
|
||||
| `is_shared` | is a value shared? | [`no_closure`] | yes | no |
|
||||
| `if` | if statement | | no | |
|
||||
| `else` | else block of if statement | | no | |
|
||||
| `switch` | matching | | no | |
|
||||
| `while` | while loop | | no | |
|
||||
| `loop` | infinite loop | | no | |
|
||||
| `for` | for loop | | no | |
|
||||
@@ -52,7 +53,6 @@ Reserved Keywords
|
||||
| `then` | control flow |
|
||||
| `goto` | control flow |
|
||||
| `exit` | control flow |
|
||||
| `switch` | matching |
|
||||
| `match` | matching |
|
||||
| `case` | matching |
|
||||
| `public` | function/field access |
|
||||
|
@@ -39,6 +39,7 @@ Symbols and Patterns
|
||||
|
||||
| Symbol | Name | Description |
|
||||
| ---------------------------------- | :------------------: | ------------------------------------- |
|
||||
| `_` | underscore | default `switch` case |
|
||||
| `;` | semicolon | statement separator |
|
||||
| `,` | comma | list separator |
|
||||
| `:` | colon | [object map] property value separator |
|
||||
@@ -52,6 +53,7 @@ Symbols and Patterns
|
||||
| <code>\|</code> .. <code>\|</code> | pipes | closure |
|
||||
| `[` .. `]` | brackets | [array] literal |
|
||||
| `!` | bang | function call in calling scope |
|
||||
| `=>` | double arrow | `switch` expression case separator |
|
||||
| `//` | comment | line comment |
|
||||
| `/*` .. `*/` | comment | block comment |
|
||||
| `(*` .. `*)` | comment | _reserved_ |
|
||||
@@ -64,7 +66,6 @@ Symbols and Patterns
|
||||
| `#` | hash | _reserved_ |
|
||||
| `@` | at | _reserved_ |
|
||||
| `$` | dollar | _reserved_ |
|
||||
| `=>` | double arrow | _reserved_ |
|
||||
| `->` | arrow | _reserved_ |
|
||||
| `<-` | left arrow | _reserved_ |
|
||||
| `===` | strict equals to | _reserved_ |
|
||||
|
@@ -49,7 +49,7 @@ For example:
|
||||
let animal = "rabbit";
|
||||
let food = "carrot";
|
||||
|
||||
animal eats food // custom operator - 'eats'
|
||||
animal eats food // custom operator 'eats'
|
||||
|
||||
eats(animal, food) // <- the above really de-sugars to this
|
||||
```
|
||||
@@ -61,7 +61,7 @@ nevertheless it makes the DSL syntax much simpler and expressive.
|
||||
Custom Syntax
|
||||
-------------
|
||||
|
||||
For advanced DSL scenarios, it is possible to define entire expression [_syntax_][custom syntax] -
|
||||
For advanced DSL scenarios, it is possible to define entire expression [_syntax_][custom syntax] &ndash
|
||||
essentially custom statement types.
|
||||
|
||||
For example, the following is a SQL-like syntax for some obscure DSL operation:
|
||||
|
@@ -1,5 +1,5 @@
|
||||
`Scope` - Initializing and Maintaining State
|
||||
===========================================
|
||||
=================================================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
@@ -12,27 +12,19 @@ Use `type_of()` to Get Value Type
|
||||
Because [`type_of()`] a `Dynamic` value returns the type of the actual value,
|
||||
it is usually used to perform type-specific actions based on the actual value's type.
|
||||
|
||||
```rust
|
||||
```c
|
||||
let mystery = get_some_dynamic_value();
|
||||
|
||||
if type_of(mystery) == "i64" {
|
||||
print("Hey, I got an integer here!");
|
||||
} else if type_of(mystery) == "f64" {
|
||||
print("Hey, I got a float here!");
|
||||
} else if type_of(mystery) == "string" {
|
||||
print("Hey, I got a string here!");
|
||||
} else if type_of(mystery) == "bool" {
|
||||
print("Hey, I got a boolean here!");
|
||||
} else if type_of(mystery) == "array" {
|
||||
print("Hey, I got an array here!");
|
||||
} else if type_of(mystery) == "map" {
|
||||
print("Hey, I got an object map here!");
|
||||
} else if type_of(mystery) == "Fn" {
|
||||
print("Hey, I got a function pointer here!");
|
||||
} else if type_of(mystery) == "TestStruct" {
|
||||
print("Hey, I got the TestStruct custom type here!");
|
||||
} else {
|
||||
print("I don't know what this is: " + type_of(mystery));
|
||||
switch mystery {
|
||||
"i64" => print("Hey, I got an integer here!"),
|
||||
"f64" => print("Hey, I got a float here!"),
|
||||
"string" => print("Hey, I got a string here!"),
|
||||
"bool" => print("Hey, I got a boolean here!"),
|
||||
"array" => print("Hey, I got an array here!"),
|
||||
"map" => print("Hey, I got an object map here!"),
|
||||
"Fn" => print("Hey, I got a function pointer here!"),
|
||||
"TestStruct" => print("Hey, I got the TestStruct custom type here!"),
|
||||
_ => print("I don't know what this is: " + type_of(mystery))
|
||||
}
|
||||
```
|
||||
|
||||
|
97
doc/src/language/switch.md
Normal file
97
doc/src/language/switch.md
Normal file
@@ -0,0 +1,97 @@
|
||||
`switch` Expression
|
||||
===================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
The `switch` _expression_ allows matching on literal values, and it mostly follows Rust's
|
||||
`match` syntax:
|
||||
|
||||
```c
|
||||
switch calc_secret_value(x) {
|
||||
1 => print("It's one!"),
|
||||
2 => {
|
||||
print("It's two!");
|
||||
print("Again!");
|
||||
}
|
||||
3 => print("Go!"),
|
||||
// _ is the default when no cases match
|
||||
_ => print("Oops! Something's wrong: " + x)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Expression, Not Statement
|
||||
------------------------
|
||||
|
||||
`switch` is not a statement, but an expression. This means that a `switch` expression can
|
||||
appear anywhere a regular expression can, e.g. as function call arguments.
|
||||
|
||||
```c
|
||||
let x = switch foo { 1 => true, _ => false };
|
||||
|
||||
func(switch foo {
|
||||
"hello" => 42,
|
||||
"world" => 123,
|
||||
_ => 0
|
||||
});
|
||||
|
||||
// The above is somewhat equivalent to:
|
||||
|
||||
let x = if foo == 1 { true } else { false };
|
||||
|
||||
if foo == "hello" {
|
||||
func(42);
|
||||
} else if foo == "world" {
|
||||
func(123);
|
||||
} else {
|
||||
func(0);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Array and Object Map Literals Also Work
|
||||
--------------------------------------
|
||||
|
||||
The `switch` expression can match against any _literal_, including [array] and [object map] literals.
|
||||
|
||||
```c
|
||||
// Match on arrays
|
||||
switch [foo, bar, baz] {
|
||||
["hello", 42, true] => { ... }
|
||||
["hello", 123, false] => { ... }
|
||||
["world", 1, true] => { ... }
|
||||
_ => { ... }
|
||||
}
|
||||
|
||||
// Match on object maps
|
||||
switch map {
|
||||
#{ a: 1, b: 2, c: true } => { ... }
|
||||
#{ a: 42, d: "hello" } => { ... }
|
||||
_ => { ... }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Difference From If-Else Chain
|
||||
-----------------------------
|
||||
|
||||
Although a `switch` expression looks _almost_ the same as an `if`-`else` chain,
|
||||
there are subtle differences between the two.
|
||||
|
||||
A `switch` expression matches through _hashing_ via a look-up table.
|
||||
Therefore, matching is very fast. Walking down an `if`-`else` chain
|
||||
will be _much_ slower.
|
||||
|
||||
On the other hand, operators can be [overloaded][operator overloading] in Rhai,
|
||||
meaning that it is possible to override the `==` operator for integers such
|
||||
that `if x == y` returns a different result from the built-in default.
|
||||
|
||||
`switch` expressions do _not_ use the `==` operator for comparison;
|
||||
instead, they _hash_ the data values and jump directly to the correct
|
||||
statements via a pre-compiled look-up table. This makes matching extremely
|
||||
efficient, but it also means that [overloading][operator overloading]
|
||||
the `==` operator will have no effect.
|
||||
|
||||
Therefore, in environments where it is desirable to [overload][operator overloading]
|
||||
the `==` operator - though it is difficult to think of valid scenarios where you'd want
|
||||
`1 == 1` to return something other than `true` - avoid using the `switch` expression.
|
Reference in New Issue
Block a user