diff --git a/RELEASES.md b/RELEASES.md index bae0c5ef..6fa1e36b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -19,7 +19,7 @@ Breaking changes ---------------- * `Module::set_fn`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`. -* `unless` is now a reserved keyword. +* `begin`, `end`, `unless` are now reserved keywords. * `EvalPackage` is removed in favor of `Engine::disable_symbol`. New features diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 73332147..e6a4da84 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -97,7 +97,7 @@ The Rhai Scripting Language 19. [Modules](language/modules/index.md) 1. [Export Variables, Functions and Sub-Modules](language/modules/export.md) 2. [Import Modules](language/modules/import.md) - 20. [Eval Statement](language/eval.md) + 20. [Eval Function](language/eval.md) 6. [Safety and Protection](safety/index.md) 1. [Checked Arithmetic](safety/checked.md) 2. [Sand-Boxing](safety/sandbox.md) diff --git a/doc/src/appendix/keywords.md b/doc/src/appendix/keywords.md index 0e542dcf..b11e8421 100644 --- a/doc/src/appendix/keywords.md +++ b/doc/src/appendix/keywords.md @@ -49,6 +49,8 @@ Reserved Keywords | --------- | --------------------- | | `var` | variable declaration | | `static` | variable declaration | +| `begin` | block scope | +| `end` | block scope | | `shared` | share value | | `each` | looping | | `then` | control flow | diff --git a/doc/src/language/eval.md b/doc/src/language/eval.md index 0b9eb8b0..7e9bdd4d 100644 --- a/doc/src/language/eval.md +++ b/doc/src/language/eval.md @@ -1,4 +1,4 @@ -`eval` Statement +`eval` Function =============== {{#include ../links.md}} diff --git a/doc/src/language/keywords.md b/doc/src/language/keywords.md index c7cd5f3a..53f3ca65 100644 --- a/doc/src/language/keywords.md +++ b/doc/src/language/keywords.md @@ -5,21 +5,22 @@ Keywords The following are reserved keywords in Rhai: -| Active keywords | Reserved keywords | Usage | Inactive under feature | -| ------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: | -| `true`, `false` | | boolean constants | | -| `let`, `const` | `var`, `static` | variable declarations | | -| `is_shared` | | shared values | [`no_closure`] | -| `if`, `else` | `then`, `goto`, `exit` | control flow | | -| | `switch`, `match`, `case` | matching | | -| `while`, `loop`, `for`, `in`, `continue`, `break` | `do`, `each` | looping | | -| `fn`, `private` | `public`, `new` | functions | [`no_function`] | -| `return` | | return values | | -| `throw`, `try`, `catch` | | throw/catch exceptions | | -| `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] | -| `Fn`, `call`, `curry` | | function pointers | | -| | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | | -| `type_of`, `print`, `debug`, `eval` | | special functions | | -| | `default`, `void`, `null`, `nil` | special values | | +| Active keywords | Reserved keywords | Usage | Inactive under feature | +| ---------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: | +| `true`, `false` | | constants | | +| `let`, `const` | `var`, `static` | variables | | +| | `begin`, `end` | block scopes | | +| `is_shared` | | shared values | [`no_closure`] | +| `if`, `else` | `then`, `unless`, `goto`, `exit` | control flow | | +| `switch` | `match`, `case` | switching and matching | | +| `do`, `while`, `loop`, `until`, `for`, `in`, `continue`, `break` | `each` | looping | | +| `fn`, `private` | `public`, `new` | functions | [`no_function`] | +| `return` | | return values | | +| `throw`, `try`, `catch` | | throw/catch exceptions | | +| `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] | +| `Fn`, `call`, `curry` | | function pointers | | +| | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | | +| `type_of`, `print`, `debug`, `eval` | | special functions | | +| | `default`, `void`, `null`, `nil` | special values | | Keywords cannot become the name of a [function] or [variable], even when they are disabled. diff --git a/doc/src/language/statements.md b/doc/src/language/statements.md index 450011c2..a4fad876 100644 --- a/doc/src/language/statements.md +++ b/doc/src/language/statements.md @@ -9,7 +9,7 @@ Terminated by '`;`' Statements are terminated by semicolons '`;`' and they are mandatory, except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted. -Semicolons can also be omitted if the statement contains a block itself +Semicolons can also be omitted if the statement ends with a block itself (e.g. the `if`, `while`, `for` and `loop` statements). ```rust @@ -35,6 +35,8 @@ Statement Expression A statement can be used anywhere where an expression is expected. These are called, for lack of a more creative name, "statement expressions." -The _last_ statement of a statement block is _always_ the block's return value when used as a statement. +The _last_ statement of a statement block is _always_ the block's return value when used as a statement, +_regardless_ of whether it is terminated by a semicolon or not. This is different from Rust where, +if the last statement is terminated by a semicolon, the block's return value is taken to be `()`. If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`]. diff --git a/src/token.rs b/src/token.rs index cd54059d..6cea048f 100644 --- a/src/token.rs +++ b/src/token.rs @@ -532,11 +532,10 @@ impl Token { "import" | "export" | "as" => Reserved(syntax.into()), "===" | "!==" | "->" | "<-" | ":=" | "::<" | "(*" | "*)" | "#" | "public" | "new" - | "use" | "module" | "package" | "var" | "static" | "shared" | "with" | "each" - | "then" | "goto" | "unless" | "exit" | "match" | "case" | "default" | "void" - | "null" | "nil" | "spawn" | "thread" | "go" | "sync" | "async" | "await" | "yield" => { - Reserved(syntax.into()) - } + | "use" | "module" | "package" | "var" | "static" | "begin" | "end" | "shared" + | "with" | "each" | "then" | "goto" | "unless" | "exit" | "match" | "case" + | "default" | "void" | "null" | "nil" | "spawn" | "thread" | "go" | "sync" + | "async" | "await" | "yield" => Reserved(syntax.into()), KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR @@ -1670,12 +1669,12 @@ impl<'a> Iterator for TokenIterator<'a, '_> { "'<-' is not a valid symbol. This is not Go! Should it be '<='?".to_string(), )), (":=", false) => Token::LexError(LERR::ImproperSymbol(s, - "':=' is not a valid assignment operator. This is not Go! Should it be simply '='?".to_string(), + "':=' is not a valid assignment operator. This is not Go or Pascal! Should it be simply '='?".to_string(), )), ("::<", false) => Token::LexError(LERR::ImproperSymbol(s, "'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(), )), - ("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol(s, + ("(*", false) | ("*)", false) | ("begin", false) | ("end", false) => Token::LexError(LERR::ImproperSymbol(s, "'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(), )), ("#", false) => Token::LexError(LERR::ImproperSymbol(s,