Improve repl and rhai_runner examples with error messages.
This commit is contained in:
parent
2d80ee2f18
commit
711cd9bb1c
40
README.md
40
README.md
@ -55,7 +55,7 @@ Other cool projects to check out:
|
|||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
The repository contains several examples in the `examples` folder:
|
A number of examples can be found in the `examples` folder:
|
||||||
|
|
||||||
| Example | Description |
|
| Example | Description |
|
||||||
| -------------------------- | ------------------------------------------------------------------------- |
|
| -------------------------- | ------------------------------------------------------------------------- |
|
||||||
@ -65,7 +65,7 @@ The repository contains several examples in the `examples` folder:
|
|||||||
| `reuse_scope` | evaluates two pieces of code in separate runs, but using a common scope |
|
| `reuse_scope` | evaluates two pieces of code in separate runs, but using a common scope |
|
||||||
| `rhai_runner` | runs each filename passed to it as a Rhai script |
|
| `rhai_runner` | runs each filename passed to it as a Rhai script |
|
||||||
| `simple_fn` | shows how to register a Rust function to a Rhai engine |
|
| `simple_fn` | shows how to register a Rust function to a Rhai engine |
|
||||||
| `repl` | a simple REPL, see source code for what it can do at the moment |
|
| `repl` | a simple REPL, interactively evaluate statements from stdin |
|
||||||
|
|
||||||
Examples can be run with the following command:
|
Examples can be run with the following command:
|
||||||
|
|
||||||
@ -73,10 +73,13 @@ Examples can be run with the following command:
|
|||||||
cargo run --example name
|
cargo run --example name
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `repl` example is a particularly good one as it allows you to interactively try out Rhai's
|
||||||
|
language features in a standard REPL (**R**ead-**E**val-**P**rint **L**oop).
|
||||||
|
|
||||||
Example Scripts
|
Example Scripts
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
We also have a few examples scripts that showcase Rhai's features, all stored in the `scripts` folder:
|
There are also a number of examples scripts that showcase Rhai's features, all in the `scripts` folder:
|
||||||
|
|
||||||
| Script | Description |
|
| Script | Description |
|
||||||
| --------------------- | ------------------------------------------------------------- |
|
| --------------------- | ------------------------------------------------------------- |
|
||||||
@ -96,8 +99,7 @@ We also have a few examples scripts that showcase Rhai's features, all stored in
|
|||||||
| `string.rhai` | string operations |
|
| `string.rhai` | string operations |
|
||||||
| `while.rhai` | while loop |
|
| `while.rhai` | while loop |
|
||||||
|
|
||||||
To run the scripts, you can either make your own tiny program, or make use of the `rhai_runner`
|
To run the scripts, either make a tiny program or use of the `rhai_runner` example:
|
||||||
example program:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo run --example rhai_runner scripts/any_script.rhai
|
cargo run --example rhai_runner scripts/any_script.rhai
|
||||||
@ -106,12 +108,13 @@ cargo run --example rhai_runner scripts/any_script.rhai
|
|||||||
Hello world
|
Hello world
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
To get going with Rhai, you create an instance of the scripting engine and then run eval.
|
To get going with Rhai, create an instance of the scripting engine and then call `eval`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::{Engine, EvalAltResult};
|
use rhai::{Engine, EvalAltResult};
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult> {
|
fn main() -> Result<(), EvalAltResult>
|
||||||
|
{
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
let result = engine.eval::<i64>("40 + 2")?;
|
let result = engine.eval::<i64>("40 + 2")?;
|
||||||
@ -232,7 +235,8 @@ fn get_an_any() -> Dynamic {
|
|||||||
Box::new(42_i64)
|
Box::new(42_i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult> {
|
fn main() -> Result<(), EvalAltResult>
|
||||||
|
{
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
engine.register_fn("add", add);
|
engine.register_fn("add", add);
|
||||||
@ -278,7 +282,8 @@ fn showit<T: Display>(x: &mut T) -> () {
|
|||||||
println!("{}", x)
|
println!("{}", x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main()
|
||||||
|
{
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
engine.register_fn("print", showit as fn(x: &mut i64)->());
|
engine.register_fn("print", showit as fn(x: &mut i64)->());
|
||||||
@ -310,7 +315,8 @@ fn safe_divide(x: i64, y: i64) -> Result<i64, EvalAltResult> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main()
|
||||||
|
{
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
// Fallible functions that return Result values must use register_result_fn()
|
// Fallible functions that return Result values must use register_result_fn()
|
||||||
@ -360,7 +366,8 @@ impl TestStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult> {
|
fn main() -> Result<(), EvalAltResult>
|
||||||
|
{
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
engine.register_type::<TestStruct>();
|
engine.register_type::<TestStruct>();
|
||||||
@ -492,7 +499,8 @@ In this example, we first create a state with a few initialized variables, then
|
|||||||
```rust
|
```rust
|
||||||
use rhai::{Engine, Scope, EvalAltResult};
|
use rhai::{Engine, Scope, EvalAltResult};
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult> {
|
fn main() -> Result<(), EvalAltResult>
|
||||||
|
{
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
// First create the state
|
// First create the state
|
||||||
@ -505,13 +513,15 @@ fn main() -> Result<(), EvalAltResult> {
|
|||||||
scope.push("z".into(), 999_i64);
|
scope.push("z".into(), 999_i64);
|
||||||
|
|
||||||
// First invocation
|
// First invocation
|
||||||
engine.eval_with_scope::<()>(&mut scope, r"
|
// (the second boolean argument indicates that we don't need to retain function definitions
|
||||||
|
// because we didn't declare any!)
|
||||||
|
engine.eval_with_scope::<()>(&mut scope, false, r"
|
||||||
let x = 4 + 5 - y + z;
|
let x = 4 + 5 - y + z;
|
||||||
y = 1;
|
y = 1;
|
||||||
")?;
|
")?;
|
||||||
|
|
||||||
// Second invocation using the same state
|
// Second invocation using the same state
|
||||||
let result = engine.eval_with_scope::<i64>(&mut scope, "x")?;
|
let result = engine.eval_with_scope::<i64>(&mut scope, false, "x")?;
|
||||||
|
|
||||||
println!("result: {}", result); // should print 966
|
println!("result: {}", result); // should print 966
|
||||||
|
|
||||||
@ -545,7 +555,7 @@ let /* intruder comment */ name = "Bob";
|
|||||||
Variables
|
Variables
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Variables in `Rhai` follow normal naming rules (i.e. must contain only ASCII letters, digits and '`_`' underscores).
|
Variables in Rhai follow normal naming rules (i.e. must contain only ASCII letters, digits and '`_`' underscores).
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let x = 3;
|
let x = 3;
|
||||||
|
@ -1,25 +1,66 @@
|
|||||||
use rhai::{Engine, RegisterFn, Scope};
|
use rhai::{Engine, EvalAltResult, Scope};
|
||||||
use std::io::{stdin, stdout, Write};
|
use std::{
|
||||||
use std::process::exit;
|
io::{stdin, stdout, Write},
|
||||||
|
iter,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn main() {
|
fn print_error(input: &str, err: EvalAltResult) {
|
||||||
|
fn padding(pad: &str, len: usize) -> String {
|
||||||
|
iter::repeat(pad).take(len).collect::<String>()
|
||||||
|
}
|
||||||
|
|
||||||
|
let lines: Vec<_> = input.split("\n").collect();
|
||||||
|
|
||||||
|
// Print error
|
||||||
|
match err.position() {
|
||||||
|
p if p.is_eof() => {
|
||||||
|
// EOF
|
||||||
|
let last = lines[lines.len() - 2];
|
||||||
|
println!("{}", last);
|
||||||
|
println!("{}^ {}", padding(" ", last.len() - 1), err);
|
||||||
|
}
|
||||||
|
p if p.is_none() => {
|
||||||
|
// No position
|
||||||
|
println!("{}", err);
|
||||||
|
}
|
||||||
|
p => {
|
||||||
|
// Specific position
|
||||||
|
let pos_text = format!(
|
||||||
|
" (line {}, position {})",
|
||||||
|
p.line().unwrap(),
|
||||||
|
p.position().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("{}", lines[p.line().unwrap() - 1]);
|
||||||
|
println!(
|
||||||
|
"{}^ {}",
|
||||||
|
padding(" ", p.position().unwrap() - 1),
|
||||||
|
err.to_string().replace(&pos_text, "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
engine.register_fn("exit", || exit(0));
|
let mut input = String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
print!("> ");
|
print!("rhai> ");
|
||||||
|
|
||||||
let mut input = String::new();
|
|
||||||
stdout().flush().expect("couldn't flush stdout");
|
stdout().flush().expect("couldn't flush stdout");
|
||||||
|
|
||||||
if let Err(e) = stdin().read_line(&mut input) {
|
input.clear();
|
||||||
println!("input error: {}", e);
|
|
||||||
|
if let Err(err) = stdin().read_line(&mut input) {
|
||||||
|
println!("input error: {}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = engine.consume_with_scope(&mut scope, &input) {
|
if let Err(err) = engine.consume_with_scope(&mut scope, true, &input) {
|
||||||
println!("error: {}", e);
|
println!("");
|
||||||
|
print_error(&input, err);
|
||||||
|
println!("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,79 @@
|
|||||||
use rhai::{Engine, RegisterFn};
|
use rhai::{Engine, EvalAltResult};
|
||||||
use std::env;
|
use std::{env, fs::File, io::Read, iter, process::exit};
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
fn showit<T: Display>(x: &mut T) -> () {
|
fn padding(pad: &str, len: usize) -> String {
|
||||||
println!("{}", x)
|
iter::repeat(pad).take(len).collect::<String>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eprint_error(input: &str, err: EvalAltResult) {
|
||||||
|
fn eprint_line(lines: &Vec<&str>, line: usize, pos: usize, err: &str) {
|
||||||
|
let line_no = format!("{}: ", line);
|
||||||
|
let pos_text = format!(" (line {}, position {})", line, pos);
|
||||||
|
|
||||||
|
eprintln!("{}{}", line_no, lines[line - 1]);
|
||||||
|
eprintln!(
|
||||||
|
"{}^ {}",
|
||||||
|
padding(" ", line_no.len() + pos - 1),
|
||||||
|
err.replace(&pos_text, "")
|
||||||
|
);
|
||||||
|
eprintln!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
let lines: Vec<_> = input.split("\n").collect();
|
||||||
|
|
||||||
|
// Print error
|
||||||
|
match err.position() {
|
||||||
|
p if p.is_eof() => {
|
||||||
|
// EOF
|
||||||
|
let line = lines.len() - 1;
|
||||||
|
let pos = lines[line - 1].len();
|
||||||
|
eprint_line(&lines, line, pos, &err.to_string());
|
||||||
|
}
|
||||||
|
p if p.is_none() => {
|
||||||
|
// No position
|
||||||
|
eprintln!("{}", err);
|
||||||
|
}
|
||||||
|
p => {
|
||||||
|
// Specific position
|
||||||
|
eprint_line(
|
||||||
|
&lines,
|
||||||
|
p.line().unwrap(),
|
||||||
|
p.position().unwrap(),
|
||||||
|
&err.to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
for fname in env::args().skip(1) {
|
for filename in env::args().skip(1) {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
engine.register_fn("print", showit as fn(x: &mut i32) -> ());
|
let mut f = match File::open(&filename) {
|
||||||
engine.register_fn("print", showit as fn(x: &mut i64) -> ());
|
Err(err) => {
|
||||||
engine.register_fn("print", showit as fn(x: &mut u32) -> ());
|
eprintln!("Error reading script file: {}\n{}", filename, err);
|
||||||
engine.register_fn("print", showit as fn(x: &mut u64) -> ());
|
exit(1);
|
||||||
engine.register_fn("print", showit as fn(x: &mut f32) -> ());
|
}
|
||||||
engine.register_fn("print", showit as fn(x: &mut f64) -> ());
|
Ok(f) => f,
|
||||||
engine.register_fn("print", showit as fn(x: &mut bool) -> ());
|
};
|
||||||
engine.register_fn("print", showit as fn(x: &mut String) -> ());
|
|
||||||
|
|
||||||
match engine.eval_file::<()>(&fname) {
|
let mut contents = String::new();
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => println!("Error: {}", e),
|
match f.read_to_string(&mut contents) {
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Error reading script file: {}\n{}", filename, err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(err) = engine.consume(&contents) {
|
||||||
|
eprintln!("{}", padding("=", filename.len()));
|
||||||
|
eprintln!("{}", filename);
|
||||||
|
eprintln!("{}", padding("=", filename.len()));
|
||||||
|
eprintln!("");
|
||||||
|
|
||||||
|
eprint_error(&contents, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user