Improve error messages to lists.
This commit is contained in:
parent
5ad2d24251
commit
705fbd0c1b
@ -13,6 +13,7 @@ include = [
|
|||||||
"scripts/*.rhai",
|
"scripts/*.rhai",
|
||||||
"Cargo.toml"
|
"Cargo.toml"
|
||||||
]
|
]
|
||||||
|
keywords = [ "scripting" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num-traits = "*"
|
num-traits = "*"
|
||||||
|
36
README.md
36
README.md
@ -171,7 +171,7 @@ let ast = engine.compile("40 + 2")?;
|
|||||||
for _ in 0..42 {
|
for _ in 0..42 {
|
||||||
let result: i64 = engine.eval_ast(&ast)?;
|
let result: i64 = engine.eval_ast(&ast)?;
|
||||||
|
|
||||||
println!("Answer: {}", result); // prints 42
|
println!("Answer #{}: {}", i, result); // prints 42
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -193,14 +193,17 @@ use rhai::Engine;
|
|||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
// Define a function in a script and load it into the Engine.
|
// Define a function in a script and load it into the Engine.
|
||||||
engine.consume(true, // pass true to 'retain_functions' otherwise these functions
|
// Pass true to 'retain_functions' otherwise these functions will be cleared at the end of consume()
|
||||||
r" // will be cleared at the end of consume()
|
engine.consume(true,
|
||||||
fn hello(x, y) { // a function with two parameters: String and i64
|
r"
|
||||||
x.len() + y // returning i64
|
// a function with two parameters: String and i64
|
||||||
|
fn hello(x, y) {
|
||||||
|
x.len() + y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hello(x) { // functions can be overloaded: this one takes only one parameter
|
// functions can be overloaded: this one takes only one parameter
|
||||||
x * 2 // returning i64
|
fn hello(x) {
|
||||||
|
x * 2
|
||||||
}
|
}
|
||||||
")?;
|
")?;
|
||||||
|
|
||||||
@ -495,22 +498,21 @@ let result = engine.eval::<i64>("let x = new_ts(); x.foo()")?;
|
|||||||
println!("result: {}", result); // prints 1
|
println!("result: {}", result); // prints 1
|
||||||
```
|
```
|
||||||
|
|
||||||
`type_of` works fine with custom types and returns the name of the type:
|
`type_of` works fine with custom types and returns the name of the type. If `register_type_with_name` is used to register the custom type
|
||||||
|
with a special "pretty-print" name, `type_of` will return that name instead.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let x = new_ts();
|
let x = new_ts();
|
||||||
print(x.type_of()); // prints "foo::bar::TestStruct"
|
print(x.type_of()); // prints "foo::bar::TestStruct"
|
||||||
|
// prints "Hello" if TestStruct is registered with
|
||||||
|
// engine.register_type_with_name::<TestStruct>("Hello")?;
|
||||||
```
|
```
|
||||||
|
|
||||||
If `register_type_with_name` is used to register the custom type with a special "pretty-print" name, `type_of` will return that name instead.
|
|
||||||
|
|
||||||
Getters and setters
|
Getters and setters
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Similarly, custom types can expose members by registering a `get` and/or `set` function.
|
Similarly, custom types can expose members by registering a `get` and/or `set` function.
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TestStruct {
|
struct TestStruct {
|
||||||
@ -565,8 +567,8 @@ fn main() -> Result<(), EvalAltResult>
|
|||||||
// Then push some initialized variables into the state
|
// Then push some initialized variables into the state
|
||||||
// NOTE: Remember the system number types in Rhai are i64 (i32 if 'only_i32') ond f64.
|
// NOTE: Remember the system number types in Rhai are i64 (i32 if 'only_i32') ond f64.
|
||||||
// Better stick to them or it gets hard working with the script.
|
// Better stick to them or it gets hard working with the script.
|
||||||
scope.push("y".into(), 42_i64);
|
scope.push("y", 42_i64);
|
||||||
scope.push("z".into(), 999_i64);
|
scope.push("z", 999_i64);
|
||||||
|
|
||||||
// First invocation
|
// First invocation
|
||||||
engine.eval_with_scope::<()>(&mut scope, r"
|
engine.eval_with_scope::<()>(&mut scope, r"
|
||||||
@ -684,7 +686,7 @@ Numeric operators generally follow C styles.
|
|||||||
| `%` | Modulo (remainder) | |
|
| `%` | Modulo (remainder) | |
|
||||||
| `~` | Power | |
|
| `~` | Power | |
|
||||||
| `&` | Binary _And_ bit-mask | Yes |
|
| `&` | Binary _And_ bit-mask | Yes |
|
||||||
| `|` | Binary _Or_ bit-mask | Yes |
|
| `\|` | Binary _Or_ bit-mask | Yes |
|
||||||
| `^` | Binary _Xor_ bit-mask | Yes |
|
| `^` | Binary _Xor_ bit-mask | Yes |
|
||||||
| `<<` | Left bit-shift | Yes |
|
| `<<` | Left bit-shift | Yes |
|
||||||
| `>>` | Right bit-shift | Yes |
|
| `>>` | Right bit-shift | Yes |
|
||||||
@ -948,9 +950,9 @@ Boolean operators
|
|||||||
| -------- | ------------------------------- |
|
| -------- | ------------------------------- |
|
||||||
| `!` | Boolean _Not_ |
|
| `!` | Boolean _Not_ |
|
||||||
| `&&` | Boolean _And_ (short-circuits) |
|
| `&&` | Boolean _And_ (short-circuits) |
|
||||||
| `||` | Boolean _Or_ (short-circuits) |
|
| `\|\|` | Boolean _Or_ (short-circuits) |
|
||||||
| `&` | Boolean _And_ (full evaluation) |
|
| `&` | Boolean _And_ (full evaluation) |
|
||||||
| `|` | Boolean _Or_ (full evaluation) |
|
| `\|` | Boolean _Or_ (full evaluation) |
|
||||||
|
|
||||||
Double boolean operators `&&` and `||` _short-circuit_, meaning that the second operand will not be evaluated
|
Double boolean operators `&&` and `||` _short-circuit_, meaning that the second operand will not be evaluated
|
||||||
if the first one already proves the condition wrong.
|
if the first one already proves the condition wrong.
|
||||||
|
@ -1026,30 +1026,29 @@ impl Engine<'_> {
|
|||||||
// Block scope
|
// Block scope
|
||||||
Stmt::Block(block, _) => {
|
Stmt::Block(block, _) => {
|
||||||
let prev_len = scope.len();
|
let prev_len = scope.len();
|
||||||
let mut last_result: Result<Dynamic, EvalAltResult> = Ok(().into_dynamic());
|
let mut result: Result<Dynamic, EvalAltResult> = Ok(().into_dynamic());
|
||||||
|
|
||||||
for block_stmt in block.iter() {
|
for stmt in block.iter() {
|
||||||
last_result = self.eval_stmt(scope, block_stmt);
|
result = self.eval_stmt(scope, stmt);
|
||||||
|
|
||||||
if let Err(x) = last_result {
|
if result.is_err() {
|
||||||
last_result = Err(x);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.rewind(prev_len);
|
scope.rewind(prev_len);
|
||||||
|
|
||||||
last_result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
// If-else statement
|
// If-else statement
|
||||||
Stmt::IfElse(guard, body, else_body) => self
|
Stmt::IfElse(guard, if_body, else_body) => self
|
||||||
.eval_expr(scope, guard)?
|
.eval_expr(scope, guard)?
|
||||||
.downcast::<bool>()
|
.downcast::<bool>()
|
||||||
.map_err(|_| EvalAltResult::ErrorIfGuard(guard.position()))
|
.map_err(|_| EvalAltResult::ErrorIfGuard(guard.position()))
|
||||||
.and_then(|guard_val| {
|
.and_then(|guard_val| {
|
||||||
if *guard_val {
|
if *guard_val {
|
||||||
self.eval_stmt(scope, body)
|
self.eval_stmt(scope, if_body)
|
||||||
} else if let Some(stmt) = else_body {
|
} else if let Some(stmt) = else_body {
|
||||||
self.eval_stmt(scope, stmt.as_ref())
|
self.eval_stmt(scope, stmt.as_ref())
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,6 +58,8 @@ pub enum ParseErrorType {
|
|||||||
/// An open `[` is missing the corresponding closing `]`.
|
/// An open `[` is missing the corresponding closing `]`.
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
MissingRightBracket(String),
|
MissingRightBracket(String),
|
||||||
|
/// A list of expressions is missing the separating ','.
|
||||||
|
MissingComma(String),
|
||||||
/// An expression in function call arguments `()` has syntax error.
|
/// An expression in function call arguments `()` has syntax error.
|
||||||
MalformedCallExpr(String),
|
MalformedCallExpr(String),
|
||||||
/// An expression in indexing brackets `[]` has syntax error.
|
/// An expression in indexing brackets `[]` has syntax error.
|
||||||
@ -116,6 +118,7 @@ impl ParseError {
|
|||||||
ParseErrorType::MissingRightBrace(_) => "Expecting '}'",
|
ParseErrorType::MissingRightBrace(_) => "Expecting '}'",
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
ParseErrorType::MissingRightBracket(_) => "Expecting ']'",
|
ParseErrorType::MissingRightBracket(_) => "Expecting ']'",
|
||||||
|
ParseErrorType::MissingComma(_) => "Expecting ','",
|
||||||
ParseErrorType::MalformedCallExpr(_) => "Invalid expression in function call arguments",
|
ParseErrorType::MalformedCallExpr(_) => "Invalid expression in function call arguments",
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
ParseErrorType::MalformedIndexExpr(_) => "Invalid index in indexing expression",
|
ParseErrorType::MalformedIndexExpr(_) => "Invalid index in indexing expression",
|
||||||
@ -165,6 +168,8 @@ impl fmt::Display for ParseError {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
ParseErrorType::MissingRightBracket(ref s) => write!(f, "{} for {}", self.desc(), s)?,
|
ParseErrorType::MissingRightBracket(ref s) => write!(f, "{} for {}", self.desc(), s)?,
|
||||||
|
|
||||||
|
ParseErrorType::MissingComma(ref s) => write!(f, "{} for {}", self.desc(), s)?,
|
||||||
|
|
||||||
ParseErrorType::AssignmentToConstant(ref s) if s.is_empty() => {
|
ParseErrorType::AssignmentToConstant(ref s) if s.is_empty() => {
|
||||||
write!(f, "{}", self.desc())?
|
write!(f, "{}", self.desc())?
|
||||||
}
|
}
|
||||||
|
829
src/parser.rs
829
src/parser.rs
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user