Merge pull request #87 from timfish/feat/2018
Feat: Rust 2018 + rustfmt
This commit is contained in:
commit
20d30d93c3
@ -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"
|
||||||
|
@ -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); }
|
||||||
|
|
||||||
|
@ -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]")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
use rhai::{Engine, RegisterFn};
|
use rhai::{Engine, RegisterFn};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
45
src/any.rs
45
src/any.rs
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
210
src/engine.rs
210
src/engine.rs
@ -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
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
547
src/parser.rs
547
src/parser.rs
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
use rhai::RegisterFn;
|
use rhai::RegisterFn;
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -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);
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
20
tests/not.rs
20
tests/not.rs
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -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") {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
extern crate rhai;
|
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user