Merge pull request #87 from timfish/feat/2018

Feat: Rust 2018 + rustfmt
This commit is contained in:
Jonathan Turner 2019-10-01 05:45:30 +13:00 committed by GitHub
commit 20d30d93c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 533 additions and 490 deletions

View File

@ -1,6 +1,7 @@
[package] [package]
name = "rhai" name = "rhai"
version = "0.9.1" version = "0.9.1"
edition = "2018"
authors = ["Jonathan Turner", "Lukáš Hozda"] authors = ["Jonathan Turner", "Lukáš Hozda"]
description = "Embedded scripting for Rust" description = "Embedded scripting for Rust"
homepage = "https://github.com/jonathandturner/rhai" homepage = "https://github.com/jonathandturner/rhai"

View File

@ -266,7 +266,7 @@ use rhai::{Engine, Scope};
fn main() { fn main() {
let mut engine = Engine::new(); let mut engine = Engine::new();
let mut scope: Scope = Vec::new(); let mut scope = Scope::new();
if let Ok(_) = engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5") { } else { assert!(false); } if let Ok(_) = engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5") { } else { assert!(false); }

View File

@ -1,4 +1,3 @@
extern crate rhai;
use rhai::{Engine, RegisterFn}; use rhai::{Engine, RegisterFn};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -24,6 +23,12 @@ fn main() {
engine.register_fn("update", TestStruct::update); engine.register_fn("update", TestStruct::update);
engine.register_fn("new_ts", TestStruct::new); engine.register_fn("new_ts", TestStruct::new);
println!("{:?}", engine.eval::<TestStruct>("let x = new_ts(); x.update(); x")); println!(
println!("{:?}", engine.eval::<TestStruct>("let x = [new_ts()]; x[0].update(); x[0]")); "{:?}",
engine.eval::<TestStruct>("let x = new_ts(); x.update(); x")
);
println!(
"{:?}",
engine.eval::<TestStruct>("let x = [new_ts()]; x[0].update(); x[0]")
);
} }

View File

@ -1,4 +1,3 @@
extern crate rhai;
use rhai::{Engine, RegisterFn}; use rhai::{Engine, RegisterFn};
#[derive(Clone)] #[derive(Clone)]

View File

@ -1,4 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
fn main() { fn main() {

View File

@ -1,9 +1,7 @@
extern crate rhai;
use std::fmt::Display;
use std::process::exit;
use std::io::{stdin, stdout, Write};
use rhai::{Engine, RegisterFn, Scope}; use rhai::{Engine, RegisterFn, Scope};
use std::fmt::Display;
use std::io::{stdin, stdout, Write};
use std::process::exit;
fn showit<T: Display>(x: &mut T) -> () { fn showit<T: Display>(x: &mut T) -> () {
println!("{}", x) println!("{}", x)

View File

@ -1,11 +1,12 @@
extern crate rhai;
use rhai::{Engine, Scope}; use rhai::{Engine, Scope};
fn main() { fn main() {
let mut engine = Engine::new(); let mut engine = Engine::new();
let mut scope: Scope = Vec::new(); let mut scope = Scope::new();
assert!(engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5").is_ok()); assert!(engine
.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")
.is_ok());
if let Ok(result) = engine.eval_with_scope::<i64>(&mut scope, "x") { if let Ok(result) = engine.eval_with_scope::<i64>(&mut scope, "x") {
println!("result: {}", result); println!("result: {}", result);

View File

@ -1,9 +1,7 @@
use rhai::{Engine, RegisterFn};
use std::env; use std::env;
use std::fmt::Display; use std::fmt::Display;
extern crate rhai;
use rhai::{Engine, RegisterFn};
fn showit<T: Display>(x: &mut T) -> () { fn showit<T: Display>(x: &mut T) -> () {
println!("{}", x) println!("{}", x)
} }

View File

@ -1,4 +1,3 @@
extern crate rhai;
use rhai::{Engine, RegisterFn}; use rhai::{Engine, RegisterFn};
fn add(x: i64, y: i64) -> i64 { fn add(x: i64, y: i64) -> i64 {

View File

@ -4,7 +4,7 @@ use std::fmt;
pub trait Any: StdAny { pub trait Any: StdAny {
fn type_id(&self) -> TypeId; fn type_id(&self) -> TypeId;
fn box_clone(&self) -> Box<Any>; fn box_clone(&self) -> Box<dyn Any>;
/// This type may only be implemented by `rhai`. /// This type may only be implemented by `rhai`.
#[doc(hidden)] #[doc(hidden)]
@ -12,8 +12,8 @@ pub trait Any: StdAny {
} }
impl<T> Any for T impl<T> Any for T
where where
T: Clone + StdAny + ?Sized T: Clone + StdAny + ?Sized,
{ {
#[inline] #[inline]
fn type_id(&self) -> TypeId { fn type_id(&self) -> TypeId {
@ -21,23 +21,24 @@ impl<T> Any for T
} }
#[inline] #[inline]
fn box_clone(&self) -> Box<Any> { fn box_clone(&self) -> Box<dyn Any> {
Box::new(self.clone()) Box::new(self.clone())
} }
fn _closed(&self) -> _Private { _Private } fn _closed(&self) -> _Private {
_Private
}
} }
impl Any { impl dyn Any {
#[inline] //#[inline]
fn box_clone(&self) -> Box<Any> { // fn box_clone(&self) -> Box<dyn Any> {
Any::box_clone(self) // Any::box_clone(self)
} // }
#[inline] #[inline]
pub fn is<T: Any>(&self) -> bool { pub fn is<T: Any>(&self) -> bool {
let t = TypeId::of::<T>(); let t = TypeId::of::<T>();
let boxed = <Any as Any>::type_id(self); let boxed = <dyn Any as Any>::type_id(self);
t == boxed t == boxed
} }
@ -45,9 +46,7 @@ impl Any {
#[inline] #[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> { pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() { if self.is::<T>() {
unsafe { unsafe { Some(&*(self as *const dyn Any as *const T)) }
Some(&*(self as *const Any as *const T))
}
} else { } else {
None None
} }
@ -56,23 +55,21 @@ impl Any {
#[inline] #[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.is::<T>() { if self.is::<T>() {
unsafe { unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) }
Some(&mut *(self as *mut Any as *mut T))
}
} else { } else {
None None
} }
} }
} }
impl Clone for Box<Any> { impl Clone for Box<dyn Any> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Any::box_clone(self.as_ref() as &Any) Any::box_clone(self.as_ref() as &dyn Any)
} }
} }
impl fmt::Debug for Any { impl fmt::Debug for dyn Any {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("Any") f.pad("Any")
} }
} }
@ -81,11 +78,11 @@ pub trait AnyExt: Sized {
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self>; fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self>;
} }
impl AnyExt for Box<Any> { impl AnyExt for Box<dyn Any> {
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self> { fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self> {
if self.is::<T>() { if self.is::<T>() {
unsafe { unsafe {
let raw: *mut Any = Box::into_raw(self); let raw: *mut dyn Any = Box::into_raw(self);
Ok(Box::from_raw(raw as *mut T)) Ok(Box::from_raw(raw as *mut T))
} }
} else { } else {

View File

@ -1,10 +1,10 @@
//! Helper module which defines `FnArgs` //! Helper module which defines `FnArgs`
//! to make function calling easier. //! to make function calling easier.
use any::Any; use crate::any::Any;
pub trait FunArgs<'a> { pub trait FunArgs<'a> {
fn into_vec(self) -> Vec<&'a mut Any>; fn into_vec(self) -> Vec<&'a mut dyn Any>;
} }
macro_rules! impl_args { macro_rules! impl_args {
@ -13,11 +13,12 @@ macro_rules! impl_args {
where where
$($p: Any + Clone),* $($p: Any + Clone),*
{ {
fn into_vec(self) -> Vec<&'a mut Any> { fn into_vec(self) -> Vec<&'a mut dyn Any> {
let ($($p,)*) = self; let ($($p,)*) = self;
#[allow(unused_variables, unused_mut)]
let mut v = Vec::new(); let mut v = Vec::new();
$(v.push($p as &mut Any);)* $(v.push($p as &mut dyn Any);)*
v v
} }

View File

@ -1,16 +1,15 @@
use std::any::TypeId; use std::any::TypeId;
use std::borrow::Borrow;
use std::cmp::{PartialEq, PartialOrd}; use std::cmp::{PartialEq, PartialOrd};
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub};
use std::sync::Arc; use std::sync::Arc;
use std::ops::{Add, BitAnd, BitOr, BitXor, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub};
use any::{Any, AnyExt}; use crate::any::{Any, AnyExt};
use fn_register::{Mut, RegisterFn}; use crate::call::FunArgs;
use parser::{lex, parse, Expr, FnDef, Stmt}; use crate::fn_register::RegisterFn;
use call::FunArgs; use crate::parser::{lex, parse, Expr, FnDef, Stmt};
#[derive(Debug)] #[derive(Debug)]
pub enum EvalAltResult { pub enum EvalAltResult {
@ -26,7 +25,7 @@ pub enum EvalAltResult {
ErrorCantOpenScriptFile, ErrorCantOpenScriptFile,
InternalErrorMalformedDotExpression, InternalErrorMalformedDotExpression,
LoopBreak, LoopBreak,
Return(Box<Any>), Return(Box<dyn Any>),
} }
impl EvalAltResult { impl EvalAltResult {
@ -35,7 +34,7 @@ impl EvalAltResult {
EvalAltResult::ErrorVariableNotFound(ref s) => Some(s.as_str()), EvalAltResult::ErrorVariableNotFound(ref s) => Some(s.as_str()),
EvalAltResult::ErrorFunctionNotFound(ref s) => Some(s.as_str()), EvalAltResult::ErrorFunctionNotFound(ref s) => Some(s.as_str()),
EvalAltResult::ErrorMismatchOutputType(ref s) => Some(s.as_str()), EvalAltResult::ErrorMismatchOutputType(ref s) => Some(s.as_str()),
_ => None _ => None,
} }
} }
} }
@ -89,13 +88,13 @@ impl Error for EvalAltResult {
} }
} }
fn cause(&self) -> Option<&Error> { fn cause(&self) -> Option<&dyn Error> {
None None
} }
} }
impl fmt::Display for EvalAltResult { impl fmt::Display for EvalAltResult {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(s) = self.as_str() { if let Some(s) = self.as_str() {
write!(f, "{}: {}", self.description(), s) write!(f, "{}: {}", self.description(), s)
} else { } else {
@ -128,7 +127,7 @@ pub struct FnSpec {
pub struct Engine { pub struct Engine {
/// A hashmap containing all functions known to the engine /// A hashmap containing all functions known to the engine
pub fns: HashMap<FnSpec, Arc<FnIntExt>>, pub fns: HashMap<FnSpec, Arc<FnIntExt>>,
pub type_names: HashMap<TypeId,String>, pub type_names: HashMap<TypeId, String>,
} }
pub enum FnIntExt { pub enum FnIntExt {
@ -136,7 +135,7 @@ pub enum FnIntExt {
Int(FnDef), Int(FnDef),
} }
pub type FnAny = Fn(Vec<&mut Any>) -> Result<Box<Any>, EvalAltResult>; pub type FnAny = dyn Fn(Vec<&mut dyn Any>) -> Result<Box<dyn Any>, EvalAltResult>;
/// A type containing information about current scope. /// A type containing information about current scope.
/// Useful for keeping state between `Engine` runs /// Useful for keeping state between `Engine` runs
@ -152,7 +151,7 @@ pub type FnAny = Fn(Vec<&mut Any>) -> Result<Box<Any>, EvalAltResult>;
/// ``` /// ```
/// ///
/// Between runs, `Engine` only remembers functions when not using own `Scope`. /// Between runs, `Engine` only remembers functions when not using own `Scope`.
pub type Scope = Vec<(String, Box<Any>)>; pub type Scope = Vec<(String, Box<dyn Any>)>;
impl Engine { impl Engine {
pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result<T, EvalAltResult> pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result<T, EvalAltResult>
@ -174,8 +173,8 @@ impl Engine {
pub fn call_fn_raw( pub fn call_fn_raw(
&self, &self,
ident: String, ident: String,
args: Vec<&mut Any>, args: Vec<&mut dyn Any>,
) -> Result<Box<Any>, EvalAltResult> { ) -> Result<Box<dyn Any>, EvalAltResult> {
debug_println!( debug_println!(
"Trying to call function {:?} with args {:?}", "Trying to call function {:?} with args {:?}",
ident, ident,
@ -184,17 +183,27 @@ impl Engine {
let spec = FnSpec { let spec = FnSpec {
ident: ident.clone(), ident: ident.clone(),
args: Some(args.iter().map(|a| <Any as Any>::type_id(&**a)).collect()), args: Some(
args.iter()
.map(|a| <dyn Any as Any>::type_id(&**a))
.collect(),
),
}; };
self.fns self.fns
.get(&spec) .get(&spec)
.or_else(|| { .or_else(|| {
let spec1 = FnSpec { ident: ident.clone(), args: None }; let spec1 = FnSpec {
ident: ident.clone(),
args: None,
};
self.fns.get(&spec1) self.fns.get(&spec1)
}) })
.ok_or_else(|| { .ok_or_else(|| {
let typenames = args.iter().map(|x| self.nice_type_name((&**x).box_clone())).collect::<Vec<_>>(); let typenames = args
.iter()
.map(|x| self.nice_type_name((&**x).box_clone()))
.collect::<Vec<_>>();
EvalAltResult::ErrorFunctionNotFound(format!("{} ({})", ident, typenames.join(","))) EvalAltResult::ErrorFunctionNotFound(format!("{} ({})", ident, typenames.join(",")))
}) })
.and_then(move |f| match **f { .and_then(move |f| match **f {
@ -272,14 +281,15 @@ impl Engine {
fn get_dot_val_helper( fn get_dot_val_helper(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Any, this_ptr: &mut dyn Any,
dot_rhs: &Expr, dot_rhs: &Expr,
) -> Result<Box<Any>, EvalAltResult> { ) -> Result<Box<dyn Any>, EvalAltResult> {
use std::iter::once; use std::iter::once;
match *dot_rhs { match *dot_rhs {
Expr::FnCall(ref fn_name, ref args) => { Expr::FnCall(ref fn_name, ref args) => {
let mut args: Vec<Box<Any>> = args.iter() let mut args: Vec<Box<dyn Any>> = args
.iter()
.map(|arg| self.eval_expr(scope, arg)) .map(|arg| self.eval_expr(scope, arg))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let args = once(this_ptr) let args = once(this_ptr)
@ -299,7 +309,7 @@ impl Engine {
let mut val = self.call_fn_raw(get_fn_name, vec![this_ptr])?; let mut val = self.call_fn_raw(get_fn_name, vec![this_ptr])?;
((*val).downcast_mut() as Option<&mut Vec<Box<Any>>>) ((*val).downcast_mut() as Option<&mut Vec<Box<dyn Any>>>)
.and_then(|arr| idx.downcast_ref::<i64>().map(|idx| (arr, *idx as usize))) .and_then(|arr| idx.downcast_ref::<i64>().map(|idx| (arr, *idx as usize)))
.map(|(arr, idx)| arr[idx].clone()) .map(|(arr, idx)| arr[idx].clone())
.ok_or(EvalAltResult::ErrorIndexMismatch) .ok_or(EvalAltResult::ErrorIndexMismatch)
@ -322,7 +332,7 @@ impl Engine {
map: F, map: F,
) -> Result<(usize, T), EvalAltResult> ) -> Result<(usize, T), EvalAltResult>
where where
F: FnOnce(&'a mut Any) -> Result<T, EvalAltResult>, F: FnOnce(&'a mut dyn Any) -> Result<T, EvalAltResult>,
{ {
scope scope
.iter_mut() .iter_mut()
@ -338,13 +348,14 @@ impl Engine {
scope: &mut Scope, scope: &mut Scope,
id: &str, id: &str,
idx: &Expr, idx: &Expr,
) -> Result<(usize, usize, Box<Any>), EvalAltResult> { ) -> Result<(usize, usize, Box<dyn Any>), EvalAltResult> {
let idx_boxed = self.eval_expr(scope, idx)? let idx_boxed = self
.eval_expr(scope, idx)?
.downcast::<i64>() .downcast::<i64>()
.map_err(|_| EvalAltResult::ErrorIndexMismatch)?; .map_err(|_| EvalAltResult::ErrorIndexMismatch)?;
let idx = *idx_boxed as usize; let idx = *idx_boxed as usize;
let (idx_sc, val) = Self::search_scope(scope, id, |val| { let (idx_sc, val) = Self::search_scope(scope, id, |val| {
((*val).downcast_mut() as Option<&mut Vec<Box<Any>>>) ((*val).downcast_mut() as Option<&mut Vec<Box<dyn Any>>>)
.map(|arr| arr[idx].clone()) .map(|arr| arr[idx].clone())
.ok_or(EvalAltResult::ErrorIndexMismatch) .ok_or(EvalAltResult::ErrorIndexMismatch)
})?; })?;
@ -357,7 +368,7 @@ impl Engine {
scope: &mut Scope, scope: &mut Scope,
dot_lhs: &Expr, dot_lhs: &Expr,
dot_rhs: &Expr, dot_rhs: &Expr,
) -> Result<Box<Any>, EvalAltResult> { ) -> Result<Box<dyn Any>, EvalAltResult> {
match *dot_lhs { match *dot_lhs {
Expr::Identifier(ref id) => { Expr::Identifier(ref id) => {
let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?; let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?;
@ -375,7 +386,7 @@ impl Engine {
// In case the expression mutated `target`, we need to reassign it because // In case the expression mutated `target`, we need to reassign it because
// of the above `clone`. // of the above `clone`.
scope[sc_idx].1.downcast_mut::<Vec<Box<Any>>>().unwrap()[idx] = target; scope[sc_idx].1.downcast_mut::<Vec<Box<dyn Any>>>().unwrap()[idx] = target;
value value
} }
@ -385,10 +396,10 @@ impl Engine {
fn set_dot_val_helper( fn set_dot_val_helper(
&self, &self,
this_ptr: &mut Any, this_ptr: &mut dyn Any,
dot_rhs: &Expr, dot_rhs: &Expr,
mut source_val: Box<Any>, mut source_val: Box<dyn Any>,
) -> Result<Box<Any>, EvalAltResult> { ) -> Result<Box<dyn Any>, EvalAltResult> {
match *dot_rhs { match *dot_rhs {
Expr::Identifier(ref id) => { Expr::Identifier(ref id) => {
let set_fn_name = "set$".to_string() + id; let set_fn_name = "set$".to_string() + id;
@ -419,8 +430,8 @@ impl Engine {
scope: &mut Scope, scope: &mut Scope,
dot_lhs: &Expr, dot_lhs: &Expr,
dot_rhs: &Expr, dot_rhs: &Expr,
source_val: Box<Any>, source_val: Box<dyn Any>,
) -> Result<Box<Any>, EvalAltResult> { ) -> Result<Box<dyn Any>, EvalAltResult> {
match *dot_lhs { match *dot_lhs {
Expr::Identifier(ref id) => { Expr::Identifier(ref id) => {
let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?; let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?;
@ -438,7 +449,7 @@ impl Engine {
// In case the expression mutated `target`, we need to reassign it because // In case the expression mutated `target`, we need to reassign it because
// of the above `clone`. // of the above `clone`.
scope[sc_idx].1.downcast_mut::<Vec<Box<Any>>>().unwrap()[idx] = target; scope[sc_idx].1.downcast_mut::<Vec<Box<dyn Any>>>().unwrap()[idx] = target;
value value
} }
@ -446,7 +457,7 @@ impl Engine {
} }
} }
fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result<Box<Any>, EvalAltResult> { fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result<Box<dyn Any>, EvalAltResult> {
match *expr { match *expr {
Expr::IntConst(i) => Ok(Box::new(i)), Expr::IntConst(i) => Ok(Box::new(i)),
Expr::FloatConst(i) => Ok(Box::new(i)), Expr::FloatConst(i) => Ok(Box::new(i)),
@ -484,7 +495,7 @@ impl Engine {
if *id == *name { if *id == *name {
if let Some(i) = idx.downcast_ref::<i64>() { if let Some(i) = idx.downcast_ref::<i64>() {
if let Some(arr_typed) = if let Some(arr_typed) =
(*val).downcast_mut() as Option<&mut Vec<Box<Any>>> (*val).downcast_mut() as Option<&mut Vec<Box<dyn Any>>>
{ {
arr_typed[*i as usize] = rhs_val; arr_typed[*i as usize] = rhs_val;
return Ok(Box::new(())); return Ok(Box::new(()));
@ -520,7 +531,7 @@ impl Engine {
fn_name.to_owned(), fn_name.to_owned(),
args.iter() args.iter()
.map(|ex| self.eval_expr(scope, ex)) .map(|ex| self.eval_expr(scope, ex))
.collect::<Result<Vec<Box<Any>>, _>>()? .collect::<Result<Vec<Box<dyn Any>>, _>>()?
.iter_mut() .iter_mut()
.map(|b| b.as_mut()) .map(|b| b.as_mut())
.collect(), .collect(),
@ -531,12 +542,12 @@ impl Engine {
} }
} }
fn eval_stmt(&self, scope: &mut Scope, stmt: &Stmt) -> Result<Box<Any>, EvalAltResult> { fn eval_stmt(&self, scope: &mut Scope, stmt: &Stmt) -> Result<Box<dyn Any>, EvalAltResult> {
match *stmt { match *stmt {
Stmt::Expr(ref e) => self.eval_expr(scope, e), Stmt::Expr(ref e) => self.eval_expr(scope, e),
Stmt::Block(ref b) => { Stmt::Block(ref b) => {
let prev_len = scope.len(); let prev_len = scope.len();
let mut last_result: Result<Box<Any>, EvalAltResult> = Ok(Box::new(())); let mut last_result: Result<Box<dyn Any>, EvalAltResult> = Ok(Box::new(()));
for s in b.iter() { for s in b.iter() {
last_result = self.eval_stmt(scope, s); last_result = self.eval_stmt(scope, s);
@ -621,8 +632,8 @@ impl Engine {
} }
} }
fn nice_type_name(&self, b: Box<Any>) -> String { fn nice_type_name(&self, b: Box<dyn Any>) -> String {
let tid = <Any as Any>::type_id(&*b); let tid = <dyn Any as Any>::type_id(&*b);
if let Some(name) = self.type_names.get(&tid) { if let Some(name) = self.type_names.get(&tid) {
name.to_string() name.to_string()
} else { } else {
@ -650,7 +661,7 @@ impl Engine {
/// Evaluate a string /// Evaluate a string
pub fn eval<T: Any + Clone>(&mut self, input: &str) -> Result<T, EvalAltResult> { pub fn eval<T: Any + Clone>(&mut self, input: &str) -> Result<T, EvalAltResult> {
let mut scope: Scope = Vec::new(); let mut scope = Scope::new();
self.eval_with_scope(&mut scope, input) self.eval_with_scope(&mut scope, input)
} }
@ -668,7 +679,7 @@ impl Engine {
match tree { match tree {
Ok((ref os, ref fns)) => { Ok((ref os, ref fns)) => {
let mut x: Result<Box<Any>, EvalAltResult> = Ok(Box::new(())); let mut x: Result<Box<dyn Any>, EvalAltResult> = Ok(Box::new(()));
for f in fns { for f in fns {
let name = f.name.clone(); let name = f.name.clone();
@ -693,7 +704,9 @@ impl Engine {
match x.downcast::<T>() { match x.downcast::<T>() {
Ok(out) => Ok(*out), Ok(out) => Ok(*out),
Err(a) => Err(EvalAltResult::ErrorMismatchOutputType(self.nice_type_name(a))), Err(a) => Err(EvalAltResult::ErrorMismatchOutputType(
self.nice_type_name(a),
)),
} }
} }
Err(_) => Err(EvalAltResult::ErrorFunctionArgMismatch), Err(_) => Err(EvalAltResult::ErrorFunctionArgMismatch),
@ -786,12 +799,12 @@ impl Engine {
engine.register_type_name::<String>("string"); engine.register_type_name::<String>("string");
engine.register_type_name::<char>("char"); engine.register_type_name::<char>("char");
engine.register_type_name::<bool>("boolean"); engine.register_type_name::<bool>("boolean");
engine.register_type_name::<Vec<Box<Any>>>("array"); engine.register_type_name::<Vec<Box<dyn Any>>>("array");
macro_rules! reg_op { macro_rules! reg_op {
($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => (
$( $(
$engine.register_fn($x, ($op as fn(x: $y, y: $y)->$y)); $engine.register_fn($x, $op as fn(x: $y, y: $y)->$y);
)* )*
) )
} }
@ -799,7 +812,7 @@ impl Engine {
macro_rules! reg_un { macro_rules! reg_un {
($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => (
$( $(
$engine.register_fn($x, ($op as fn(x: $y)->$y)); $engine.register_fn($x, $op as fn(x: $y)->$y);
)* )*
) )
} }
@ -807,36 +820,86 @@ impl Engine {
macro_rules! reg_cmp { macro_rules! reg_cmp {
($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => (
$( $(
$engine.register_fn($x, ($op as fn(x: $y, y: $y)->bool)); $engine.register_fn($x, $op as fn(x: $y, y: $y)->bool);
)* )*
) )
} }
fn add<T: Add>(x: T, y: T) -> <T as Add>::Output { x + y } fn add<T: Add>(x: T, y: T) -> <T as Add>::Output {
fn sub<T: Sub>(x: T, y: T) -> <T as Sub>::Output { x - y } x + y
fn mul<T: Mul>(x: T, y: T) -> <T as Mul>::Output { x * y } }
fn div<T: Div>(x: T, y: T) -> <T as Div>::Output { x / y } fn sub<T: Sub>(x: T, y: T) -> <T as Sub>::Output {
fn neg<T: Neg>(x: T) -> <T as Neg>::Output { -x } x - y
fn lt<T: PartialOrd>(x: T, y: T) -> bool { x < y } }
fn lte<T: PartialOrd>(x: T, y: T) -> bool { x <= y } fn mul<T: Mul>(x: T, y: T) -> <T as Mul>::Output {
fn gt<T: PartialOrd>(x: T, y: T) -> bool { x > y } x * y
fn gte<T: PartialOrd>(x: T, y: T) -> bool { x >= y } }
fn eq<T: PartialEq>(x: T, y: T) -> bool { x == y } fn div<T: Div>(x: T, y: T) -> <T as Div>::Output {
fn ne<T: PartialEq>(x: T, y: T) -> bool { x != y } x / y
fn and(x: bool, y: bool) -> bool { x && y } }
fn or(x: bool, y: bool) -> bool { x || y } fn neg<T: Neg>(x: T) -> <T as Neg>::Output {
fn not(x: bool) -> bool { !x } -x
fn concat(x: String, y: String) -> String { x + &y } }
fn binary_and<T: BitAnd>(x: T, y: T) -> <T as BitAnd>::Output { x & y } fn lt<T: PartialOrd>(x: T, y: T) -> bool {
fn binary_or<T: BitOr>(x: T, y: T) -> <T as BitOr>::Output { x | y } x < y
fn binary_xor<T: BitXor>(x: T, y: T) -> <T as BitXor>::Output { x ^ y } }
fn left_shift<T: Shl<T>>(x: T, y: T) -> <T as Shl<T>>::Output { x.shl(y) } fn lte<T: PartialOrd>(x: T, y: T) -> bool {
fn right_shift<T: Shr<T>>(x: T, y: T) -> <T as Shr<T>>::Output { x.shr(y) } x <= y
fn modulo<T: Rem<T>>(x: T, y: T) -> <T as Rem<T>>::Output { x % y } }
fn pow_i64_i64(x: i64, y: i64) -> i64 { x.pow(y as u32) } fn gt<T: PartialOrd>(x: T, y: T) -> bool {
fn pow_f64_f64(x: f64, y: f64) -> f64 { x.powf(y) } x > y
fn pow_f64_i64(x: f64, y: i64) -> f64 { x.powi(y as i32) } }
fn unit_eq(a: (), b: ()) -> bool { true } fn gte<T: PartialOrd>(x: T, y: T) -> bool {
x >= y
}
fn eq<T: PartialEq>(x: T, y: T) -> bool {
x == y
}
fn ne<T: PartialEq>(x: T, y: T) -> bool {
x != y
}
fn and(x: bool, y: bool) -> bool {
x && y
}
fn or(x: bool, y: bool) -> bool {
x || y
}
fn not(x: bool) -> bool {
!x
}
fn concat(x: String, y: String) -> String {
x + &y
}
fn binary_and<T: BitAnd>(x: T, y: T) -> <T as BitAnd>::Output {
x & y
}
fn binary_or<T: BitOr>(x: T, y: T) -> <T as BitOr>::Output {
x | y
}
fn binary_xor<T: BitXor>(x: T, y: T) -> <T as BitXor>::Output {
x ^ y
}
fn left_shift<T: Shl<T>>(x: T, y: T) -> <T as Shl<T>>::Output {
x.shl(y)
}
fn right_shift<T: Shr<T>>(x: T, y: T) -> <T as Shr<T>>::Output {
x.shr(y)
}
fn modulo<T: Rem<T>>(x: T, y: T) -> <T as Rem<T>>::Output {
x % y
}
fn pow_i64_i64(x: i64, y: i64) -> i64 {
x.pow(y as u32)
}
fn pow_f64_f64(x: f64, y: f64) -> f64 {
x.powf(y)
}
fn pow_f64_i64(x: f64, y: i64) -> f64 {
x.powi(y as i32)
}
fn unit_eq(_a: (), _b: ()) -> bool {
true
}
reg_op!(engine, "+", add, i32, i64, u32, u64, f32, f64); reg_op!(engine, "+", add, i32, i64, u32, u64, f32, f64);
reg_op!(engine, "-", sub, i32, i64, u32, u64, f32, f64); reg_op!(engine, "-", sub, i32, i64, u32, u64, f32, f64);
@ -874,7 +937,6 @@ impl Engine {
// FIXME? Registering array lookups are a special case because we want to return boxes // FIXME? Registering array lookups are a special case because we want to return boxes
// directly let ent = engine.fns.entry("[]".to_string()).or_insert_with(Vec::new); // directly let ent = engine.fns.entry("[]".to_string()).or_insert_with(Vec::new);
// (*ent).push(FnType::ExternalFn2(Box::new(idx))); // (*ent).push(FnType::ExternalFn2(Box::new(idx)));
} }
/// Make a new engine /// Make a new engine

View File

@ -1,7 +1,7 @@
use std::any::TypeId; use std::any::TypeId;
use any::Any; use crate::any::Any;
use engine::{Engine, EvalAltResult}; use crate::engine::{Engine, EvalAltResult};
pub trait RegisterFn<FN, ARGS, RET> { pub trait RegisterFn<FN, ARGS, RET> {
fn register_fn(&mut self, name: &str, f: FN); fn register_fn(&mut self, name: &str, f: FN);
@ -27,13 +27,14 @@ macro_rules! def_register {
RET: Any, RET: Any,
{ {
fn register_fn(&mut self, name: &str, f: FN) { fn register_fn(&mut self, name: &str, f: FN) {
let fun = move |mut args: Vec<&mut Any>| { let fun = move |mut args: Vec<&mut dyn Any>| {
// Check for length at the beginning to avoid // Check for length at the beginning to avoid
// per-element bound checks. // per-element bound checks.
if args.len() != count_args!($($par)*) { if args.len() != count_args!($($par)*) {
return Err(EvalAltResult::ErrorFunctionArgMismatch); return Err(EvalAltResult::ErrorFunctionArgMismatch);
} }
#[allow(unused_variables, unused_mut)]
let mut drain = args.drain(..); let mut drain = args.drain(..);
$( $(
// Downcast every element, return in case of a type mismatch // Downcast every element, return in case of a type mismatch
@ -43,7 +44,7 @@ macro_rules! def_register {
// Call the user-supplied function using ($clone) to // Call the user-supplied function using ($clone) to
// potentially clone the value, otherwise pass the reference. // potentially clone the value, otherwise pass the reference.
Ok(Box::new(f($(($clone)($par)),*)) as Box<Any>) Ok(Box::new(f($(($clone)($par)),*)) as Box<dyn Any>)
}; };
self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun)); self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
} }

View File

@ -30,9 +30,7 @@
//! //!
//! [Check out the README on GitHub for more information!](https://github.com/jonathandturner/rhai) //! [Check out the README on GitHub for more information!](https://github.com/jonathandturner/rhai)
// lints required by Rhai #![allow(non_snake_case)]
#![allow(warnings, unknown_lints, type_complexity, new_without_default_derive,
needless_pass_by_value, too_many_arguments)]
// needs to be here, because order matters for macros // needs to be here, because order matters for macros
macro_rules! debug_println { macro_rules! debug_println {
@ -50,4 +48,3 @@ mod parser;
pub use any::Any; pub use any::Any;
pub use engine::{Engine, EvalAltResult, Scope}; pub use engine::{Engine, EvalAltResult, Scope};
pub use fn_register::RegisterFn; pub use fn_register::RegisterFn;

View File

@ -1,8 +1,8 @@
use std::char;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::iter::Peekable; use std::iter::Peekable;
use std::str::Chars; use std::str::Chars;
use std::char;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum LexError { pub enum LexError {
@ -10,7 +10,7 @@ pub enum LexError {
MalformedEscapeSequence, MalformedEscapeSequence,
MalformedNumber, MalformedNumber,
MalformedChar, MalformedChar,
Nothing Nothing,
} }
impl Error for LexError { impl Error for LexError {
@ -20,13 +20,13 @@ impl Error for LexError {
LexError::MalformedEscapeSequence => "Unexpected values in escape sequence", LexError::MalformedEscapeSequence => "Unexpected values in escape sequence",
LexError::MalformedNumber => "Unexpected characters in number", LexError::MalformedNumber => "Unexpected characters in number",
LexError::MalformedChar => "Char constant not a single character", LexError::MalformedChar => "Char constant not a single character",
LexError::Nothing => "This error is for internal use only" LexError::Nothing => "This error is for internal use only",
} }
} }
} }
impl fmt::Display for LexError { impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.description()) write!(f, "{}", self.description())
} }
} }
@ -65,11 +65,13 @@ impl Error for ParseError {
} }
} }
fn cause(&self) -> Option<&Error> { None } fn cause(&self) -> Option<&dyn Error> {
None
}
} }
impl fmt::Display for ParseError { impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.description()) write!(f, "{}", self.description())
} }
} }
@ -268,11 +270,7 @@ impl Token {
use self::Token::*; use self::Token::*;
match *self { match *self {
UnaryPlus | UnaryPlus | UnaryMinus | Equals | Bang | Return => true,
UnaryMinus |
Equals |
Bang |
Return => true,
_ => false, _ => false,
} }
} }
@ -390,14 +388,14 @@ impl<'a> TokenIterator<'a> {
fn inner_next(&mut self) -> Option<Token> { fn inner_next(&mut self) -> Option<Token> {
while let Some(c) = self.char_stream.next() { while let Some(c) = self.char_stream.next() {
match c { match c {
'0'...'9' => { '0'..='9' => {
let mut result = Vec::new(); let mut result = Vec::new();
let mut radix_base: Option<u32> = None; let mut radix_base: Option<u32> = None;
result.push(c); result.push(c);
while let Some(&nxt) = self.char_stream.peek() { while let Some(&nxt) = self.char_stream.peek() {
match nxt { match nxt {
'0'...'9' => { '0'..='9' => {
result.push(nxt); result.push(nxt);
self.char_stream.next(); self.char_stream.next();
} }
@ -406,7 +404,7 @@ impl<'a> TokenIterator<'a> {
self.char_stream.next(); self.char_stream.next();
while let Some(&nxt_float) = self.char_stream.peek() { while let Some(&nxt_float) = self.char_stream.peek() {
match nxt_float { match nxt_float {
'0'...'9' => { '0'..='9' => {
result.push(nxt_float); result.push(nxt_float);
self.char_stream.next(); self.char_stream.next();
} }
@ -419,7 +417,7 @@ impl<'a> TokenIterator<'a> {
self.char_stream.next(); self.char_stream.next();
while let Some(&nxt_hex) = self.char_stream.peek() { while let Some(&nxt_hex) = self.char_stream.peek() {
match nxt_hex { match nxt_hex {
'0'...'9' | 'a'...'f' | 'A'...'F' => { '0'..='9' | 'a'..='f' | 'A'..='F' => {
result.push(nxt_hex); result.push(nxt_hex);
self.char_stream.next(); self.char_stream.next();
} }
@ -433,7 +431,7 @@ impl<'a> TokenIterator<'a> {
self.char_stream.next(); self.char_stream.next();
while let Some(&nxt_oct) = self.char_stream.peek() { while let Some(&nxt_oct) = self.char_stream.peek() {
match nxt_oct { match nxt_oct {
'0'...'8' => { '0'..='8' => {
result.push(nxt_oct); result.push(nxt_oct);
self.char_stream.next(); self.char_stream.next();
} }
@ -461,7 +459,12 @@ impl<'a> TokenIterator<'a> {
} }
if let Some(radix) = radix_base { if let Some(radix) = radix_base {
let out: String = result.iter().cloned().skip(2).filter(|c| c != &'_').collect(); let out: String = result
.iter()
.cloned()
.skip(2)
.filter(|c| c != &'_')
.collect();
if let Ok(val) = i64::from_str_radix(&out, radix) { if let Ok(val) = i64::from_str_radix(&out, radix) {
return Some(Token::IntConst(val)); return Some(Token::IntConst(val));
} }
@ -476,7 +479,7 @@ impl<'a> TokenIterator<'a> {
} }
return Some(Token::LexErr(LexError::MalformedNumber)); return Some(Token::LexErr(LexError::MalformedNumber));
} }
'A'...'Z' | 'a'...'z' | '_' => { 'A'..='Z' | 'a'..='z' | '_' => {
let mut result = Vec::new(); let mut result = Vec::new();
result.push(c); result.push(c);
@ -505,30 +508,26 @@ impl<'a> TokenIterator<'a> {
x => return Some(Token::Identifier(x.to_string())), x => return Some(Token::Identifier(x.to_string())),
} }
} }
'"' => { '"' => match self.parse_string_const('"') {
match self.parse_string_const('"') { Ok(out) => return Some(Token::StringConst(out)),
Ok(out) => return Some(Token::StringConst(out)), Err(e) => return Some(Token::LexErr(e)),
Err(e) => return Some(Token::LexErr(e)), },
} '\'' => match self.parse_string_const('\'') {
} Ok(result) => {
'\'' => { let mut chars = result.chars();
match self.parse_string_const('\'') {
Ok(result) => {
let mut chars = result.chars();
if let Some(out) = chars.next() { if let Some(out) = chars.next() {
println!("result: {}", result); println!("result: {}", result);
if chars.count() != 0 { if chars.count() != 0 {
return Some(Token::LexErr(LexError::MalformedChar));
}
return Some(Token::CharConst(out));
} else {
return Some(Token::LexErr(LexError::MalformedChar)); return Some(Token::LexErr(LexError::MalformedChar));
} }
return Some(Token::CharConst(out));
} else {
return Some(Token::LexErr(LexError::MalformedChar));
} }
Err(e) => return Some(Token::LexErr(e)),
} }
} Err(e) => return Some(Token::LexErr(e)),
},
'{' => return Some(Token::LCurly), '{' => return Some(Token::LCurly),
'}' => return Some(Token::RCurly), '}' => return Some(Token::RCurly),
'(' => return Some(Token::LParen), '(' => return Some(Token::LParen),
@ -540,182 +539,168 @@ impl<'a> TokenIterator<'a> {
Some(&'=') => { Some(&'=') => {
self.char_stream.next(); self.char_stream.next();
Some(Token::PlusAssign) Some(Token::PlusAssign)
}, }
_ if self.last.is_next_unary() => Some(Token::UnaryPlus), _ if self.last.is_next_unary() => Some(Token::UnaryPlus),
_ => Some(Token::Plus), _ => Some(Token::Plus),
} }
}, }
'-' => { '-' => {
return match self.char_stream.peek() { return match self.char_stream.peek() {
Some(&'=') => { Some(&'=') => {
self.char_stream.next(); self.char_stream.next();
Some(Token::MinusAssign) Some(Token::MinusAssign)
}, }
_ if self.last.is_next_unary() => Some(Token::UnaryMinus), _ if self.last.is_next_unary() => Some(Token::UnaryMinus),
_ => Some(Token::Minus), _ => Some(Token::Minus),
} }
}, }
'*' => { '*' => {
return match self.char_stream.peek() { return match self.char_stream.peek() {
Some(&'=') => { Some(&'=') => {
self.char_stream.next(); self.char_stream.next();
Some(Token::MultiplyAssign) Some(Token::MultiplyAssign)
},
_ => Some(Token::Multiply)
}
},
'/' => {
match self.char_stream.peek() {
Some(&'/') => {
self.char_stream.next();
while let Some(c) = self.char_stream.next() {
if c == '\n' { break; }
}
} }
Some(&'*') => { _ => Some(Token::Multiply),
let mut level = 1;
self.char_stream.next();
while let Some(c) = self.char_stream.next() {
match c {
'/' => if let Some('*') = self.char_stream.next() {
level+=1;
}
'*' => if let Some('/') = self.char_stream.next() {
level-=1;
}
_ => (),
}
if level == 0 {
break;
}
}
}
Some(&'=') => {
self.char_stream.next();
return Some(Token::DivideAssign);
}
_ => return Some(Token::Divide),
} }
} }
'/' => match self.char_stream.peek() {
Some(&'/') => {
self.char_stream.next();
while let Some(c) = self.char_stream.next() {
if c == '\n' {
break;
}
}
}
Some(&'*') => {
let mut level = 1;
self.char_stream.next();
while let Some(c) = self.char_stream.next() {
match c {
'/' => {
if let Some('*') = self.char_stream.next() {
level += 1;
}
}
'*' => {
if let Some('/') = self.char_stream.next() {
level -= 1;
}
}
_ => (),
}
if level == 0 {
break;
}
}
}
Some(&'=') => {
self.char_stream.next();
return Some(Token::DivideAssign);
}
_ => return Some(Token::Divide),
},
';' => return Some(Token::Semicolon), ';' => return Some(Token::Semicolon),
':' => return Some(Token::Colon), ':' => return Some(Token::Colon),
',' => return Some(Token::Comma), ',' => return Some(Token::Comma),
'.' => return Some(Token::Period), '.' => return Some(Token::Period),
'=' => { '=' => match self.char_stream.peek() {
match self.char_stream.peek() { Some(&'=') => {
Some(&'=') => { self.char_stream.next();
self.char_stream.next(); return Some(Token::EqualTo);
return Some(Token::EqualTo);
}
_ => return Some(Token::Equals),
}
}
'<' => {
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::LessThanEqual);
}
Some(&'<') => {
self.char_stream.next();
return match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
Some(Token::LeftShiftAssign)
},
_ => {
self.char_stream.next();
Some(Token::LeftShift)
}
}
}
_ => return Some(Token::LessThan),
}
}
'>' => {
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::GreaterThanEqual);
}
Some(&'>') => {
self.char_stream.next();
return match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
Some(Token::RightShiftAssign)
},
_ => {
self.char_stream.next();
Some(Token::RightShift)
}
}
}
_ => return Some(Token::GreaterThan),
}
}
'!' => {
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::NotEqualTo);
}
_ => return Some(Token::Bang),
}
}
'|' => {
match self.char_stream.peek() {
Some(&'|') => {
self.char_stream.next();
return Some(Token::Or);
}
Some(&'=') => {
self.char_stream.next();
return Some(Token::OrAssign);
}
_ => return Some(Token::Pipe),
}
}
'&' => {
match self.char_stream.peek() {
Some(&'&') => {
self.char_stream.next();
return Some(Token::And);
}
Some(&'=') => {
self.char_stream.next();
return Some(Token::AndAssign);
}
_ => return Some(Token::Ampersand),
}
}
'^' => {
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::XOrAssign);
}
_ => return Some(Token::XOr)
} }
_ => return Some(Token::Equals),
}, },
'%' => { '<' => match self.char_stream.peek() {
match self.char_stream.peek() { Some(&'=') => {
Some(&'=') => { self.char_stream.next();
self.char_stream.next(); return Some(Token::LessThanEqual);
return Some(Token::ModuloAssign);
}
_ => return Some(Token::Modulo)
} }
Some(&'<') => {
self.char_stream.next();
return match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
Some(Token::LeftShiftAssign)
}
_ => {
self.char_stream.next();
Some(Token::LeftShift)
}
};
}
_ => return Some(Token::LessThan),
}, },
'~' => { '>' => match self.char_stream.peek() {
match self.char_stream.peek() { Some(&'=') => {
Some(&'=') => { self.char_stream.next();
self.char_stream.next(); return Some(Token::GreaterThanEqual);
return Some(Token::PowerOfAssign);
}
_ => return Some(Token::PowerOf)
} }
Some(&'>') => {
self.char_stream.next();
return match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
Some(Token::RightShiftAssign)
}
_ => {
self.char_stream.next();
Some(Token::RightShift)
}
};
}
_ => return Some(Token::GreaterThan),
},
'!' => match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::NotEqualTo);
}
_ => return Some(Token::Bang),
},
'|' => match self.char_stream.peek() {
Some(&'|') => {
self.char_stream.next();
return Some(Token::Or);
}
Some(&'=') => {
self.char_stream.next();
return Some(Token::OrAssign);
}
_ => return Some(Token::Pipe),
},
'&' => match self.char_stream.peek() {
Some(&'&') => {
self.char_stream.next();
return Some(Token::And);
}
Some(&'=') => {
self.char_stream.next();
return Some(Token::AndAssign);
}
_ => return Some(Token::Ampersand),
},
'^' => match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::XOrAssign);
}
_ => return Some(Token::XOr),
},
'%' => match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::ModuloAssign);
}
_ => return Some(Token::Modulo),
},
'~' => match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
return Some(Token::PowerOfAssign);
}
_ => return Some(Token::PowerOf),
}, },
_x if _x.is_whitespace() => (), _x if _x.is_whitespace() => (),
_ => return Some(Token::LexErr(LexError::UnexpectedChar)), _ => return Some(Token::LexErr(LexError::UnexpectedChar)),
@ -739,8 +724,11 @@ impl<'a> Iterator for TokenIterator<'a> {
} }
} }
pub fn lex(input: &str) -> TokenIterator { pub fn lex(input: &str) -> TokenIterator<'_> {
TokenIterator { last: Token::LexErr(LexError::Nothing), char_stream: input.chars().peekable() } TokenIterator {
last: Token::LexErr(LexError::Nothing),
char_stream: input.chars().peekable(),
}
} }
fn get_precedence(token: &Token) -> i32 { fn get_precedence(token: &Token) -> i32 {
@ -757,24 +745,17 @@ fn get_precedence(token: &Token) -> i32 {
| Token::XOrAssign | Token::XOrAssign
| Token::ModuloAssign | Token::ModuloAssign
| Token::PowerOfAssign => 10, | Token::PowerOfAssign => 10,
Token::Or Token::Or | Token::XOr | Token::Pipe => 11,
| Token::XOr Token::And | Token::Ampersand => 12,
| Token::Pipe => 11,
Token::And
| Token::Ampersand => 12,
Token::LessThan Token::LessThan
| Token::LessThanEqual | Token::LessThanEqual
| Token::GreaterThan | Token::GreaterThan
| Token::GreaterThanEqual | Token::GreaterThanEqual
| Token::EqualTo | Token::EqualTo
| Token::NotEqualTo => 15, | Token::NotEqualTo => 15,
Token::Plus Token::Plus | Token::Minus => 20,
| Token::Minus => 20, Token::Divide | Token::Multiply | Token::PowerOf => 40,
Token::Divide Token::LeftShift | Token::RightShift => 50,
| Token::Multiply
| Token::PowerOf => 40,
Token::LeftShift
| Token::RightShift => 50,
Token::Modulo => 60, Token::Modulo => 60,
Token::Period => 100, Token::Period => 100,
_ => -1, _ => -1,
@ -782,7 +763,7 @@ fn get_precedence(token: &Token) -> i32 {
} }
fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> { fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
let expr = try!(parse_expr(input)); let expr = parse_expr(input)?;
match input.next() { match input.next() {
Some(Token::RParen) => Ok(expr), Some(Token::RParen) => Ok(expr),
@ -790,9 +771,10 @@ fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr,
} }
} }
fn parse_call_expr<'a>(id: String, fn parse_call_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>) id: String,
-> Result<Expr, ParseError> { input: &mut Peekable<TokenIterator<'a>>,
) -> Result<Expr, ParseError> {
let mut args = Vec::new(); let mut args = Vec::new();
if let Some(&Token::RParen) = input.peek() { if let Some(&Token::RParen) = input.peek() {
@ -820,9 +802,10 @@ fn parse_call_expr<'a>(id: String,
} }
} }
fn parse_index_expr<'a>(id: String, fn parse_index_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>) id: String,
-> Result<Expr, ParseError> { input: &mut Peekable<TokenIterator<'a>>,
) -> Result<Expr, ParseError> {
if let Ok(idx) = parse_expr(input) { if let Ok(idx) = parse_expr(input) {
match input.peek() { match input.peek() {
Some(&Token::RSquare) => { Some(&Token::RSquare) => {
@ -836,9 +819,10 @@ fn parse_index_expr<'a>(id: String,
} }
} }
fn parse_ident_expr<'a>(id: String, fn parse_ident_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>) id: String,
-> Result<Expr, ParseError> { input: &mut Peekable<TokenIterator<'a>>,
) -> Result<Expr, ParseError> {
match input.peek() { match input.peek() {
Some(&Token::LParen) => { Some(&Token::LParen) => {
input.next(); input.next();
@ -862,12 +846,14 @@ fn parse_array_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr,
if !skip_contents { if !skip_contents {
while let Some(_) = input.peek() { while let Some(_) = input.peek() {
arr.push(try!(parse_expr(input))); arr.push(parse_expr(input)?);
if let Some(&Token::Comma) = input.peek() { if let Some(&Token::Comma) = input.peek() {
input.next(); input.next();
} }
if let Some(&Token::RSquare) = input.peek() { break } if let Some(&Token::RSquare) = input.peek() {
break;
}
} }
} }
@ -878,7 +864,6 @@ fn parse_array_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr,
} }
_ => Err(ParseError::MissingRSquare), _ => Err(ParseError::MissingRSquare),
} }
} }
fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> { fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
@ -914,17 +899,27 @@ fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pars
}; };
match tok { match tok {
Token::UnaryMinus => { input.next(); Ok(Expr::FnCall("-".to_string(), vec![parse_primary(input)?])) } Token::UnaryMinus => {
Token::UnaryPlus => { input.next(); parse_primary(input) } input.next();
Token::Bang => { input.next(); Ok(Expr::FnCall("!".to_string(), vec![parse_primary(input)?])) } Ok(Expr::FnCall("-".to_string(), vec![parse_primary(input)?]))
_ => parse_primary(input) }
Token::UnaryPlus => {
input.next();
parse_primary(input)
}
Token::Bang => {
input.next();
Ok(Expr::FnCall("!".to_string(), vec![parse_primary(input)?]))
}
_ => parse_primary(input),
} }
} }
fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>, fn parse_binop<'a>(
prec: i32, input: &mut Peekable<TokenIterator<'a>>,
lhs: Expr) prec: i32,
-> Result<Expr, ParseError> { lhs: Expr,
) -> Result<Expr, ParseError> {
let mut lhs_curr = lhs; let mut lhs_curr = lhs;
loop { loop {
@ -939,7 +934,7 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>,
} }
if let Some(op_token) = input.next() { if let Some(op_token) = input.next() {
let mut rhs = try!(parse_unary(input)); let mut rhs = parse_unary(input)?;
let mut next_prec = -1; let mut next_prec = -1;
@ -948,10 +943,10 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>,
} }
if curr_prec < next_prec { if curr_prec < next_prec {
rhs = try!(parse_binop(input, curr_prec + 1, rhs)); rhs = parse_binop(input, curr_prec + 1, rhs)?;
} else if curr_prec >= 100 { } else if curr_prec >= 100 {
// Always bind right to left for precedence over 100 // Always bind right to left for precedence over 100
rhs = try!(parse_binop(input, curr_prec, rhs)); rhs = parse_binop(input, curr_prec, rhs)?;
} }
lhs_curr = match op_token { lhs_curr = match op_token {
@ -960,31 +955,27 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>,
Token::Multiply => Expr::FnCall("*".to_string(), vec![lhs_curr, rhs]), Token::Multiply => Expr::FnCall("*".to_string(), vec![lhs_curr, rhs]),
Token::Divide => Expr::FnCall("/".to_string(), vec![lhs_curr, rhs]), Token::Divide => Expr::FnCall("/".to_string(), vec![lhs_curr, rhs]),
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)), Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
Token::PlusAssign => { Token::PlusAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("+".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("+".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::MinusAssign => { Token::MinusAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("-".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("-".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::Period => Expr::Dot(Box::new(lhs_curr), Box::new(rhs)), Token::Period => Expr::Dot(Box::new(lhs_curr), Box::new(rhs)),
Token::EqualTo => Expr::FnCall("==".to_string(), vec![lhs_curr, rhs]), Token::EqualTo => Expr::FnCall("==".to_string(), vec![lhs_curr, rhs]),
Token::NotEqualTo => Expr::FnCall("!=".to_string(), vec![lhs_curr, rhs]), Token::NotEqualTo => Expr::FnCall("!=".to_string(), vec![lhs_curr, rhs]),
Token::LessThan => Expr::FnCall("<".to_string(), vec![lhs_curr, rhs]), Token::LessThan => Expr::FnCall("<".to_string(), vec![lhs_curr, rhs]),
Token::LessThanEqual => { Token::LessThanEqual => Expr::FnCall("<=".to_string(), vec![lhs_curr, rhs]),
Expr::FnCall("<=".to_string(), vec![lhs_curr, rhs])
}
Token::GreaterThan => Expr::FnCall(">".to_string(), vec![lhs_curr, rhs]), Token::GreaterThan => Expr::FnCall(">".to_string(), vec![lhs_curr, rhs]),
Token::GreaterThanEqual => { Token::GreaterThanEqual => Expr::FnCall(">=".to_string(), vec![lhs_curr, rhs]),
Expr::FnCall(">=".to_string(), vec![lhs_curr, rhs])
}
Token::Or => Expr::FnCall("||".to_string(), vec![lhs_curr, rhs]), Token::Or => Expr::FnCall("||".to_string(), vec![lhs_curr, rhs]),
Token::And => Expr::FnCall("&&".to_string(), vec![lhs_curr, rhs]), Token::And => Expr::FnCall("&&".to_string(), vec![lhs_curr, rhs]),
Token::XOr => Expr::FnCall("^".to_string(), vec![lhs_curr, rhs]), Token::XOr => Expr::FnCall("^".to_string(), vec![lhs_curr, rhs]),
@ -992,73 +983,71 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>,
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("|".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("|".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::AndAssign => { Token::AndAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("&".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("&".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::XOrAssign => { Token::XOrAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("^".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("^".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::MultiplyAssign => { Token::MultiplyAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("*".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("*".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::DivideAssign => { Token::DivideAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("/".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("/".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::Pipe => { Token::Pipe => Expr::FnCall("|".to_string(), vec![lhs_curr, rhs]),
Expr::FnCall("|".to_string(), vec![lhs_curr, rhs])
},
Token::LeftShift => Expr::FnCall("<<".to_string(), vec![lhs_curr, rhs]), Token::LeftShift => Expr::FnCall("<<".to_string(), vec![lhs_curr, rhs]),
Token::RightShift => Expr::FnCall(">>".to_string(), vec![lhs_curr, rhs]), Token::RightShift => Expr::FnCall(">>".to_string(), vec![lhs_curr, rhs]),
Token::LeftShiftAssign => { Token::LeftShiftAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("<<".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("<<".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::RightShiftAssign => { Token::RightShiftAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall(">>".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall(">>".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::Ampersand => Expr::FnCall("&".to_string(), vec![lhs_curr, rhs]), Token::Ampersand => Expr::FnCall("&".to_string(), vec![lhs_curr, rhs]),
Token::Modulo => Expr::FnCall("%".to_string(), vec![lhs_curr, rhs]), Token::Modulo => Expr::FnCall("%".to_string(), vec![lhs_curr, rhs]),
Token::ModuloAssign => { Token::ModuloAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("%".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("%".to_string(), vec![lhs_copy, rhs])),
) )
}, }
Token::PowerOf => Expr::FnCall("~".to_string(), vec![lhs_curr, rhs]), Token::PowerOf => Expr::FnCall("~".to_string(), vec![lhs_curr, rhs]),
Token::PowerOfAssign => { Token::PowerOfAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = lhs_curr.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("~".to_string(), vec![lhs_copy, rhs])) Box::new(Expr::FnCall("~".to_string(), vec![lhs_copy, rhs])),
) )
}, }
_ => return Err(ParseError::UnknownOperator), _ => return Err(ParseError::UnknownOperator),
}; };
} }
@ -1069,7 +1058,7 @@ fn parse_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Parse
match input.peek() { match input.peek() {
Some(Token::RParen) => Ok(Expr::Unit), Some(Token::RParen) => Ok(Expr::Unit),
_ => { _ => {
let lhs = try!(parse_unary(input)); let lhs = parse_unary(input)?;
parse_binop(input, 0, lhs) parse_binop(input, 0, lhs)
} }
@ -1079,14 +1068,18 @@ fn parse_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Parse
fn parse_if<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> { fn parse_if<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
input.next(); input.next();
let guard = try!(parse_expr(input)); let guard = parse_expr(input)?;
let body = try!(parse_block(input)); let body = parse_block(input)?;
match input.peek() { match input.peek() {
Some(&Token::Else) => { Some(&Token::Else) => {
input.next(); input.next();
let else_body = try!(parse_block(input)); let else_body = parse_block(input)?;
Ok(Stmt::IfElse(Box::new(guard), Box::new(body), Box::new(else_body))) Ok(Stmt::IfElse(
Box::new(guard),
Box::new(body),
Box::new(else_body),
))
} }
_ => Ok(Stmt::If(Box::new(guard), Box::new(body))), _ => Ok(Stmt::If(Box::new(guard), Box::new(body))),
} }
@ -1095,8 +1088,8 @@ fn parse_if<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseEr
fn parse_while<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> { fn parse_while<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
input.next(); input.next();
let guard = try!(parse_expr(input)); let guard = parse_expr(input)?;
let body = try!(parse_block(input)); let body = parse_block(input)?;
Ok(Stmt::While(Box::new(guard), Box::new(body))) Ok(Stmt::While(Box::new(guard), Box::new(body)))
} }
@ -1104,7 +1097,7 @@ fn parse_while<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
fn parse_loop<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> { fn parse_loop<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
input.next(); input.next();
let body = try!(parse_block(input)); let body = parse_block(input)?;
Ok(Stmt::Loop(Box::new(body))) Ok(Stmt::Loop(Box::new(body)))
} }
@ -1120,7 +1113,7 @@ fn parse_var<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseE
match input.peek() { match input.peek() {
Some(&Token::Equals) => { Some(&Token::Equals) => {
input.next(); input.next();
let initializer = try!(parse_expr(input)); let initializer = parse_expr(input)?;
Ok(Stmt::Var(name, Some(Box::new(initializer)))) Ok(Stmt::Var(name, Some(Box::new(initializer))))
} }
_ => Ok(Stmt::Var(name, None)), _ => Ok(Stmt::Var(name, None)),
@ -1144,13 +1137,15 @@ fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
if !skip_body { if !skip_body {
while let Some(_) = input.peek() { while let Some(_) = input.peek() {
stmts.push(try!(parse_stmt(input))); stmts.push(parse_stmt(input)?);
if let Some(&Token::Semicolon) = input.peek() { if let Some(&Token::Semicolon) = input.peek() {
input.next(); input.next();
} }
if let Some(&Token::RCurly) = input.peek() { break } if let Some(&Token::RCurly) = input.peek() {
break;
}
} }
} }
@ -1164,7 +1159,7 @@ fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
} }
fn parse_expr_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> { fn parse_expr_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
let expr = try!(parse_expr(input)); let expr = parse_expr(input)?;
Ok(Stmt::Expr(Box::new(expr))) Ok(Stmt::Expr(Box::new(expr)))
} }
@ -1182,7 +1177,7 @@ fn parse_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Parse
match input.peek() { match input.peek() {
Some(&Token::Semicolon) => Ok(Stmt::Return), Some(&Token::Semicolon) => Ok(Stmt::Return),
_ => { _ => {
let ret = try!(parse_expr(input)); let ret = parse_expr(input)?;
Ok(Stmt::ReturnWithVal(Box::new(ret))) Ok(Stmt::ReturnWithVal(Box::new(ret)))
} }
} }
@ -1240,15 +1235,16 @@ fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseE
}) })
} }
fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) fn parse_top_level<'a>(
-> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> { input: &mut Peekable<TokenIterator<'a>>,
) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
let mut stmts = Vec::new(); let mut stmts = Vec::new();
let mut fndefs = Vec::new(); let mut fndefs = Vec::new();
while let Some(_) = input.peek() { while let Some(_) = input.peek() {
match input.peek() { match input.peek() {
Some(&Token::Fn) => fndefs.push(try!(parse_fn(input))), Some(&Token::Fn) => fndefs.push(parse_fn(input)?),
_ => stmts.push(try!(parse_stmt(input))), _ => stmts.push(parse_stmt(input)?),
} }
if let Some(&Token::Semicolon) = input.peek() { if let Some(&Token::Semicolon) = input.peek() {
@ -1259,7 +1255,8 @@ fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>)
Ok((stmts, fndefs)) Ok((stmts, fndefs))
} }
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) pub fn parse<'a>(
-> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> { input: &mut Peekable<TokenIterator<'a>>,
) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
parse_top_level(input) parse_top_level(input)
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
use rhai::RegisterFn; use rhai::RegisterFn;
@ -59,8 +57,10 @@ fn test_array_with_structs() {
assert!(false); assert!(false);
} }
if let Ok(result) = engine.eval::<i64>("let a = [new_ts()]; a[0].x = 100; a[0].update(); \ if let Ok(result) = engine.eval::<i64>(
a[0].x") { "let a = [new_ts()]; a[0].x = 100; a[0].update(); \
a[0].x",
) {
assert_eq!(result, 1100); assert_eq!(result, 1100);
} else { } else {
assert!(false); assert!(false);

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,12 +1,14 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
fn test_comments() { fn test_comments() {
let mut engine = Engine::new(); let mut engine = Engine::new();
assert!(engine.eval::<i64>("let x = 5; x // I am a single line comment, yay!").is_ok()); assert!(engine
.eval::<i64>("let x = 5; x // I am a single line comment, yay!")
.is_ok());
assert!(engine.eval::<i64>("let /* I am a multiline comment, yay! */ x = 5; x").is_ok()); assert!(engine
.eval::<i64>("let /* I am a multiline comment, yay! */ x = 5; x")
.is_ok());
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
use rhai::RegisterFn; use rhai::RegisterFn;

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
use rhai::RegisterFn; use rhai::RegisterFn;
@ -74,7 +72,9 @@ fn test_big_get_set() {
} }
fn new() -> TestParent { fn new() -> TestParent {
TestParent { child: TestChild::new() } TestParent {
child: TestChild::new(),
}
} }
} }
@ -88,5 +88,8 @@ fn test_big_get_set() {
engine.register_fn("new_tp", TestParent::new); engine.register_fn("new_tp", TestParent::new);
assert_eq!(engine.eval::<i64>("let a = new_tp(); a.child.x = 500; a.child.x"), Ok(500)); assert_eq!(
engine.eval::<i64>("let a = new_tp(); a.child.x = 500; a.child.x"),
Ok(500)
);
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
@ -23,8 +21,10 @@ fn test_internal_fn() {
fn test_big_internal_fn() { fn test_big_internal_fn() {
let mut engine = Engine::new(); let mut engine = Engine::new();
if let Ok(result) = engine.eval::<i64>("fn mathme(a, b, c, d, e, f) { a - b * c + d * e - f \ if let Ok(result) = engine.eval::<i64>(
} mathme(100, 5, 2, 9, 6, 32)") { "fn mathme(a, b, c, d, e, f) { a - b * c + d * e - f \
} mathme(100, 5, 2, 9, 6, 32)",
) {
assert_eq!(result, 112); assert_eq!(result, 112);
} else { } else {
assert!(false); assert!(false);

View File

@ -1,13 +1,12 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
fn test_loop() { fn test_loop() {
let mut engine = Engine::new(); let mut engine = Engine::new();
assert!( assert!(engine
engine.eval::<bool>(" .eval::<bool>(
"
let x = 0; let x = 0;
let i = 0; let i = 0;
@ -22,6 +21,7 @@ fn test_loop() {
} }
x == 45 x == 45
").unwrap() "
) )
.unwrap())
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
use rhai::RegisterFn; use rhai::RegisterFn;
@ -32,5 +30,4 @@ fn test_method_call() {
} else { } else {
assert!(false); assert!(false);
} }
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::{Engine, EvalAltResult}; use rhai::{Engine, EvalAltResult};
#[test] #[test]
@ -8,6 +6,8 @@ fn test_mismatched_op() {
assert_eq!( assert_eq!(
engine.eval::<i64>("60 + \"hello\""), engine.eval::<i64>("60 + \"hello\""),
Err(EvalAltResult::ErrorFunctionNotFound("+ (integer,string)".into())) Err(EvalAltResult::ErrorFunctionNotFound(
"+ (integer,string)".into()
))
); );
} }

View File

@ -1,15 +1,21 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
fn test_not() { fn test_not() {
let mut engine = Engine::new(); let mut engine = Engine::new();
assert_eq!(engine.eval::<bool>("let not_true = !true; not_true").unwrap(), false); assert_eq!(
engine
.eval::<bool>("let not_true = !true; not_true")
.unwrap(),
false
);
assert_eq!(engine.eval::<bool>("fn not(x) { !x } not(false)").unwrap(), true); assert_eq!(
engine.eval::<bool>("fn not(x) { !x } not(false)").unwrap(),
true
);
// TODO - do we allow stacking unary operators directly? e.g '!!!!!!!true' // TODO - do we allow stacking unary operators directly? e.g '!!!!!!!true'
assert_eq!(engine.eval::<bool>("!(!(!(!(true))))").unwrap(), true) assert_eq!(engine.eval::<bool>("!(!(!(!(true))))").unwrap(), true)
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
@ -8,7 +6,10 @@ fn test_power_of() {
assert_eq!(engine.eval::<i64>("2 ~ 3").unwrap(), 8); assert_eq!(engine.eval::<i64>("2 ~ 3").unwrap(), 8);
assert_eq!(engine.eval::<i64>("(-2 ~ 3)").unwrap(), -8); assert_eq!(engine.eval::<i64>("(-2 ~ 3)").unwrap(), -8);
assert_eq!(engine.eval::<f64>("2.2 ~ 3.3").unwrap(), 13.489468760533386_f64); assert_eq!(
engine.eval::<f64>("2.2 ~ 3.3").unwrap(),
13.489468760533386_f64
);
assert_eq!(engine.eval::<f64>("2.0~-2.0").unwrap(), 0.25_f64); assert_eq!(engine.eval::<f64>("2.0~-2.0").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<f64>("(-2.0~-2.0)").unwrap(), 0.25_f64); assert_eq!(engine.eval::<f64>("(-2.0~-2.0)").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<f64>("(-2.0~-2)").unwrap(), 0.25_f64); assert_eq!(engine.eval::<f64>("(-2.0~-2)").unwrap(), 0.25_f64);
@ -21,9 +22,21 @@ fn test_power_of_equals() {
assert_eq!(engine.eval::<i64>("let x = 2; x ~= 3; x").unwrap(), 8); assert_eq!(engine.eval::<i64>("let x = 2; x ~= 3; x").unwrap(), 8);
assert_eq!(engine.eval::<i64>("let x = -2; x ~= 3; x").unwrap(), -8); assert_eq!(engine.eval::<i64>("let x = -2; x ~= 3; x").unwrap(), -8);
assert_eq!(engine.eval::<f64>("let x = 2.2; x ~= 3.3; x").unwrap(), 13.489468760533386_f64); assert_eq!(
assert_eq!(engine.eval::<f64>("let x = 2.0; x ~= -2.0; x").unwrap(), 0.25_f64); engine.eval::<f64>("let x = 2.2; x ~= 3.3; x").unwrap(),
assert_eq!(engine.eval::<f64>("let x = -2.0; x ~= -2.0; x").unwrap(), 0.25_f64); 13.489468760533386_f64
assert_eq!(engine.eval::<f64>("let x = -2.0; x ~= -2; x").unwrap(), 0.25_f64); );
assert_eq!(
engine.eval::<f64>("let x = 2.0; x ~= -2.0; x").unwrap(),
0.25_f64
);
assert_eq!(
engine.eval::<f64>("let x = -2.0; x ~= -2.0; x").unwrap(),
0.25_f64
);
assert_eq!(
engine.eval::<f64>("let x = -2.0; x ~= -2; x").unwrap(),
0.25_f64
);
assert_eq!(engine.eval::<i64>("let x =4; x ~= 3; x").unwrap(), 64); assert_eq!(engine.eval::<i64>("let x =4; x ~= 3; x").unwrap(), 64);
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,12 +1,9 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
// TODO also add test case for unary after compound // TODO also add test case for unary after compound
// Hah, turns out unary + has a good use after all! // Hah, turns out unary + has a good use after all!
fn test_unary_after_binary() fn test_unary_after_binary() {
{
let mut engine = Engine::new(); let mut engine = Engine::new();
if let Ok(result) = engine.eval::<i64>("10 % +4") { if let Ok(result) = engine.eval::<i64>("10 % +4") {

View File

@ -1,14 +1,12 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
fn test_unary_minus() { fn test_unary_minus() {
let mut engine = Engine::new(); let mut engine = Engine::new();
assert_eq!(engine.eval::<i64>("let x = -5; x").unwrap(), -5); assert_eq!(engine.eval::<i64>("let x = -5; x").unwrap(), -5);
assert_eq!(engine.eval::<i64>("fn n(x) { -x } n(5)").unwrap(), -5); assert_eq!(engine.eval::<i64>("fn n(x) { -x } n(5)").unwrap(), -5);
assert_eq!(engine.eval::<i64>("5 - -(-5)").unwrap(), 0); assert_eq!(engine.eval::<i64>("5 - -(-5)").unwrap(), 0);
} }

View File

@ -1,5 +1,3 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]

View File

@ -1,11 +1,9 @@
extern crate rhai;
use rhai::{Engine, Scope}; use rhai::{Engine, Scope};
#[test] #[test]
fn test_var_scope() { fn test_var_scope() {
let mut engine = Engine::new(); let mut engine = Engine::new();
let mut scope: Scope = Vec::new(); let mut scope = Scope::new();
if let Ok(_) = engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5") { if let Ok(_) = engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5") {
} else { } else {

View File

@ -1,13 +1,13 @@
extern crate rhai;
use rhai::Engine; use rhai::Engine;
#[test] #[test]
fn test_while() { fn test_while() {
let mut engine = Engine::new(); let mut engine = Engine::new();
if let Ok(result) = engine.eval::<i64>("let x = 0; while x < 10 { x = x + 1; if x > 5 { \ if let Ok(result) = engine.eval::<i64>(
break } } x") { "let x = 0; while x < 10 { x = x + 1; if x > 5 { \
break } } x",
) {
assert_eq!(result, 6); assert_eq!(result, 6);
} else { } else {
assert!(false); assert!(false);