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
|
||||
--------
|
||||
|
||||
The repository contains several examples in the `examples` folder:
|
||||
A number of examples can be found in the `examples` folder:
|
||||
|
||||
| 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 |
|
||||
| `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 |
|
||||
| `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:
|
||||
|
||||
@ -73,10 +73,13 @@ Examples can be run with the following command:
|
||||
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
|
||||
---------------
|
||||
|
||||
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 |
|
||||
| --------------------- | ------------------------------------------------------------- |
|
||||
@ -96,8 +99,7 @@ We also have a few examples scripts that showcase Rhai's features, all stored in
|
||||
| `string.rhai` | string operations |
|
||||
| `while.rhai` | while loop |
|
||||
|
||||
To run the scripts, you can either make your own tiny program, or make use of the `rhai_runner`
|
||||
example program:
|
||||
To run the scripts, either make a tiny program or use of the `rhai_runner` example:
|
||||
|
||||
```bash
|
||||
cargo run --example rhai_runner scripts/any_script.rhai
|
||||
@ -106,12 +108,13 @@ cargo run --example rhai_runner scripts/any_script.rhai
|
||||
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
|
||||
use rhai::{Engine, EvalAltResult};
|
||||
|
||||
fn main() -> Result<(), EvalAltResult> {
|
||||
fn main() -> Result<(), EvalAltResult>
|
||||
{
|
||||
let mut engine = Engine::new();
|
||||
|
||||
let result = engine.eval::<i64>("40 + 2")?;
|
||||
@ -232,7 +235,8 @@ fn get_an_any() -> Dynamic {
|
||||
Box::new(42_i64)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), EvalAltResult> {
|
||||
fn main() -> Result<(), EvalAltResult>
|
||||
{
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_fn("add", add);
|
||||
@ -278,7 +282,8 @@ fn showit<T: Display>(x: &mut T) -> () {
|
||||
println!("{}", x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main()
|
||||
{
|
||||
let mut engine = Engine::new();
|
||||
|
||||
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();
|
||||
|
||||
// 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();
|
||||
|
||||
engine.register_type::<TestStruct>();
|
||||
@ -492,7 +499,8 @@ In this example, we first create a state with a few initialized variables, then
|
||||
```rust
|
||||
use rhai::{Engine, Scope, EvalAltResult};
|
||||
|
||||
fn main() -> Result<(), EvalAltResult> {
|
||||
fn main() -> Result<(), EvalAltResult>
|
||||
{
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// First create the state
|
||||
@ -505,13 +513,15 @@ fn main() -> Result<(), EvalAltResult> {
|
||||
scope.push("z".into(), 999_i64);
|
||||
|
||||
// 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;
|
||||
y = 1;
|
||||
")?;
|
||||
|
||||
// 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
|
||||
|
||||
@ -545,7 +555,7 @@ let /* intruder comment */ name = "Bob";
|
||||
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
|
||||
let x = 3;
|
||||
|
@ -1,25 +1,66 @@
|
||||
use rhai::{Engine, RegisterFn, Scope};
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::process::exit;
|
||||
use rhai::{Engine, EvalAltResult, Scope};
|
||||
use std::{
|
||||
io::{stdin, stdout, Write},
|
||||
iter,
|
||||
};
|
||||
|
||||
pub fn main() {
|
||||
let mut engine = Engine::new();
|
||||
let mut scope = Scope::new();
|
||||
|
||||
engine.register_fn("exit", || exit(0));
|
||||
|
||||
loop {
|
||||
print!("> ");
|
||||
|
||||
let mut input = String::new();
|
||||
stdout().flush().expect("couldn't flush stdout");
|
||||
|
||||
if let Err(e) = stdin().read_line(&mut input) {
|
||||
println!("input error: {}", e);
|
||||
fn print_error(input: &str, err: EvalAltResult) {
|
||||
fn padding(pad: &str, len: usize) -> String {
|
||||
iter::repeat(pad).take(len).collect::<String>()
|
||||
}
|
||||
|
||||
if let Err(e) = engine.consume_with_scope(&mut scope, &input) {
|
||||
println!("error: {}", e);
|
||||
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 scope = Scope::new();
|
||||
|
||||
let mut input = String::new();
|
||||
|
||||
loop {
|
||||
print!("rhai> ");
|
||||
stdout().flush().expect("couldn't flush stdout");
|
||||
|
||||
input.clear();
|
||||
|
||||
if let Err(err) = stdin().read_line(&mut input) {
|
||||
println!("input error: {}", err);
|
||||
}
|
||||
|
||||
if let Err(err) = engine.consume_with_scope(&mut scope, true, &input) {
|
||||
println!("");
|
||||
print_error(&input, err);
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,79 @@
|
||||
use rhai::{Engine, RegisterFn};
|
||||
use std::env;
|
||||
use std::fmt::Display;
|
||||
use rhai::{Engine, EvalAltResult};
|
||||
use std::{env, fs::File, io::Read, iter, process::exit};
|
||||
|
||||
fn showit<T: Display>(x: &mut T) -> () {
|
||||
println!("{}", x)
|
||||
fn padding(pad: &str, len: usize) -> String {
|
||||
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() {
|
||||
for fname in env::args().skip(1) {
|
||||
for filename in env::args().skip(1) {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_fn("print", showit as fn(x: &mut i32) -> ());
|
||||
engine.register_fn("print", showit as fn(x: &mut i64) -> ());
|
||||
engine.register_fn("print", showit as fn(x: &mut u32) -> ());
|
||||
engine.register_fn("print", showit as fn(x: &mut u64) -> ());
|
||||
engine.register_fn("print", showit as fn(x: &mut f32) -> ());
|
||||
engine.register_fn("print", showit as fn(x: &mut f64) -> ());
|
||||
engine.register_fn("print", showit as fn(x: &mut bool) -> ());
|
||||
engine.register_fn("print", showit as fn(x: &mut String) -> ());
|
||||
let mut f = match File::open(&filename) {
|
||||
Err(err) => {
|
||||
eprintln!("Error reading script file: {}\n{}", filename, err);
|
||||
exit(1);
|
||||
}
|
||||
Ok(f) => f,
|
||||
};
|
||||
|
||||
match engine.eval_file::<()>(&fname) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Error: {}", e),
|
||||
let mut contents = String::new();
|
||||
|
||||
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