Add support for arrays

This commit is contained in:
jonathandturner 2016-03-26 10:46:28 -07:00
parent ceadc0977f
commit b1ccaf4516
4 changed files with 163 additions and 24 deletions

4
scripts/array.rhai Normal file
View File

@ -0,0 +1,4 @@
var x = [1, 2, 3];
print(x[1]);
x[1] = 5;
print(x[1]);

View File

@ -15,6 +15,7 @@ pub enum EvalAltResult {
ErrorFunctionNotFound,
ErrorFunctionArgMismatch,
ErrorFunctionCallNotSupported,
ErrorIndexMismatch,
ErrorIfGuardMismatch,
ErrorVariableNotFound(String),
ErrorFunctionArityNotSupported,
@ -26,12 +27,14 @@ pub enum EvalAltResult {
Return(Box<Any>)
}
impl Error for EvalAltResult {
fn description(&self) -> &str {
match *self {
EvalAltResult::ErrorFunctionNotFound => "Function not found",
EvalAltResult::ErrorFunctionArgMismatch => "Function argument types do not match",
EvalAltResult::ErrorFunctionCallNotSupported => "Function call with > 2 argument not supported",
EvalAltResult::ErrorIndexMismatch => "Index does not match array",
EvalAltResult::ErrorIfGuardMismatch => "If guards expect boolean expression",
EvalAltResult::ErrorVariableNotFound(_) => "Variable not found",
EvalAltResult::ErrorFunctionArityNotSupported => "Functions of more than 3 parameters are not yet supported",
@ -537,10 +540,32 @@ impl Engine {
}
Err(EvalAltResult::ErrorVariableNotFound(id.clone()))
}
Expr::Index(ref id, ref idx_raw) => {
let idx = try!(self.eval_expr(scope, idx_raw));
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
if *id == *name {
if let Ok(i) = idx.downcast::<i32>() {
if let Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec<Box<Any>>> {
return self.call_fn("clone", Some(&mut arr_typed[*i as usize]), None, None, None, None, None);
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
}
Err(EvalAltResult::ErrorVariableNotFound(id.clone()))
}
Expr::Assignment(ref id, ref rhs) => {
let rhs_val = try!(self.eval_expr(scope, rhs));
match **id {
Expr::Identifier(ref n) => {
let rhs_val = try!(self.eval_expr(scope, rhs));
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
if *n == *name {
@ -551,9 +576,29 @@ impl Engine {
}
Err(EvalAltResult::ErrorVariableNotFound(n.clone()))
}
Expr::Dot(ref dot_lhs, ref dot_rhs) => {
let rhs_val = try!(self.eval_expr(scope, rhs));
Expr::Index(ref id, ref idx_raw) => {
let idx = try!(self.eval_expr(scope, idx_raw));
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
if *id == *name {
if let Ok(i) = idx.downcast::<i32>() {
if let Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec<Box<Any>>> {
arr_typed[*i as usize] = rhs_val;
return Ok(Box::new(()));
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
}
Err(EvalAltResult::ErrorVariableNotFound(id.clone()))
}
Expr::Dot(ref dot_lhs, ref dot_rhs) => {
self.set_dot_val(scope, dot_lhs, dot_rhs, rhs_val)
}
_ => Err(EvalAltResult::ErrorAssignmentToUnknownLHS)
@ -562,6 +607,16 @@ impl Engine {
Expr::Dot(ref lhs, ref rhs) => {
self.get_dot_val(scope, lhs, rhs)
}
Expr::Array(ref contents) => {
let mut arr = Vec::new();
for item in (*contents).iter() {
let arg = try!(self.eval_expr(scope, item));
arr.push(arg);
}
Ok(Box::new(arr))
}
Expr::FnCall(ref fn_name, ref args) => {
if args.len() == 0 {
self.call_fn(&fn_name, None, None, None, None, None, None)
@ -838,6 +893,12 @@ impl Engine {
reg_op!(engine, "||", or, bool);
reg_op!(engine, "&&", and, bool);
//engine.register_fn("[]", idx);
//FIXME? Registering array lookups are a special case because we want to return boxes directly
//let ent = engine.fns.entry("[]".to_string()).or_insert(Vec::new());
//(*ent).push(FnType::ExternalFn2(Box::new(idx)));
}
pub fn new() -> Engine {
@ -1170,3 +1231,24 @@ fn test_string() {
assert!(false);
}
}
#[test]
fn test_vec() {
let mut engine = Engine::new();
if let Ok(result) = engine.eval::<i32>("var x = [1, 2, 3]; x[1]") {
assert_eq!(result, 2);
}
else {
assert!(false);
}
if let Ok(result) = engine.eval::<i32>("var y = [1, 2, 3]; y[1] = 5; y[1]") {
assert_eq!(result, 5);
}
else {
assert!(false);
}
}

View File

@ -8,8 +8,8 @@ pub trait FnRegister<A, RetVal, Args> {
}
impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a mut T, U, V, W, X, Y)> for Engine
where A: 'static+Fn(&mut T, U, V, W, X, Y) -> Z, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any,
X: Clone+Any, Y: Clone+Any, Z: Clone+Any
where A: 'static+Fn(&mut T, U, V, W, X, Y) -> Z, T: Any, U: Clone+Any, V: Clone+Any, W: Clone+Any,
X: Clone+Any, Y: Clone+Any, Z: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>,
@ -41,7 +41,7 @@ impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a mut T, U, V, W, X, Y)> fo
impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a T, U, V, W, X, Y)> for Engine
where A: 'static+Fn(T, U, V, W, X, Y) -> Z, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any,
X: Clone+Any, Y: Clone+Any, Z: Clone+Any
X: Clone+Any, Y: Clone+Any, Z: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>,
@ -72,7 +72,7 @@ impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a T, U, V, W, X, Y)> for En
}
impl<'a, A, T, U, V, W, X, Y> FnRegister<A, Y, (&'a mut T, U, V, W, X)> for Engine
where A: 'static+Fn(&mut T, U, V, W, X) -> Y, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Clone+Any, Y: Clone+Any
where A: 'static+Fn(&mut T, U, V, W, X) -> Y, T: Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Clone+Any, Y: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -100,7 +100,7 @@ impl<'a, A, T, U, V, W, X, Y> FnRegister<A, Y, (&'a mut T, U, V, W, X)> for Engi
}
impl<'a, A, T, U, V, W, X, Y> FnRegister<A, Y, (&'a T, U, V, W, X)> for Engine
where A: 'static+Fn(T, U, V, W, X) -> Y, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Clone+Any, Y: Clone+Any
where A: 'static+Fn(T, U, V, W, X) -> Y, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Clone+Any, Y: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -128,7 +128,7 @@ impl<'a, A, T, U, V, W, X, Y> FnRegister<A, Y, (&'a T, U, V, W, X)> for Engine
}
impl<'a, A, T, U, V, W, X> FnRegister<A, X, (&'a mut T, U, V, W)> for Engine
where A: 'static+Fn(&mut T, U, V, W) -> X, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Clone+Any
where A: 'static+Fn(&mut T, U, V, W) -> X, T: Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -152,7 +152,7 @@ impl<'a, A, T, U, V, W, X> FnRegister<A, X, (&'a mut T, U, V, W)> for Engine
}
impl<'a, A, T, U, V, W, X> FnRegister<A, X, (&'a T, U, V, W)> for Engine
where A: 'static+Fn(T, U, V, W) -> X, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Clone+Any
where A: 'static+Fn(T, U, V, W) -> X, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any, X: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -176,7 +176,7 @@ impl<'a, A, T, U, V, W, X> FnRegister<A, X, (&'a T, U, V, W)> for Engine
}
impl<'a, A, T, U, V, W> FnRegister<A, W, (&'a mut T, U, V)> for Engine
where A: 'static+Fn(&mut T, U, V) -> W, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any
where A: 'static+Fn(&mut T, U, V) -> W, T: Any, U: Clone+Any, V: Clone+Any, W: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -199,7 +199,7 @@ impl<'a, A, T, U, V, W> FnRegister<A, W, (&'a mut T, U, V)> for Engine
}
impl<'a, A, T, U, V, W> FnRegister<A, W, (&'a T, U, V)> for Engine
where A: 'static+Fn(T, U, V) -> W, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Clone+Any
where A: 'static+Fn(T, U, V) -> W, T: Clone+Any, U: Clone+Any, V: Clone+Any, W: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -222,7 +222,7 @@ impl<'a, A, T, U, V, W> FnRegister<A, W, (&'a T, U, V)> for Engine
}
impl<'a, A, T, U, V> FnRegister<A, V, (&'a mut T, U)> for Engine
where A: 'static+Fn(&mut T, U) -> V, T: Clone+Any, U: Clone+Any, V: Clone+Any
where A: 'static+Fn(&mut T, U) -> V, T: Any, U: Clone+Any, V: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -244,7 +244,7 @@ impl<'a, A, T, U, V> FnRegister<A, V, (&'a mut T, U)> for Engine
}
impl<'a, A, T, U, V> FnRegister<A, V, (&'a T, U)> for Engine
where A: 'static+Fn(T, U) -> V, T: Clone+Any, U: Clone+Any, V: Clone+Any
where A: 'static+Fn(T, U) -> V, T: Clone+Any, U: Clone+Any, V: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -266,7 +266,7 @@ impl<'a, A, T, U, V> FnRegister<A, V, (&'a T, U)> for Engine
}
impl<'a, A, T, U> FnRegister<A, U, (&'a mut T)> for Engine
where A: 'static+Fn(&mut T) -> U, T: Clone+Any, U: Clone+Any
where A: 'static+Fn(&mut T) -> U, T: Any, U: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -288,7 +288,7 @@ impl<'a, A, T, U> FnRegister<A, U, (&'a mut T)> for Engine
impl<'a, A, T, U> FnRegister<A, U, (&'a T)> for Engine
where A: 'static+Fn(T) -> U, T: Clone+Any, U: Clone+Any
where A: 'static+Fn(T) -> U, T: Clone+Any, U: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn(&mut Box<Any>)->Result<Box<Any>, EvalAltResult>> =
@ -308,7 +308,7 @@ impl<'a, A, T, U> FnRegister<A, U, (&'a T)> for Engine
}
impl<A, T> FnRegister<A, T, ()> for Engine
where A: 'static+Fn() -> T, T: Clone+Any
where A: 'static+Fn() -> T, T: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped : Box<Fn()->Result<Box<Any>, EvalAltResult>> =

View File

@ -41,7 +41,9 @@ pub enum ParseError {
MissingRParen,
MissingLCurly,
MissingRCurly,
MissingRSquare,
MalformedCallExpr,
MalformedIndexExpr,
VarExpectsIdentifier,
FnMissingName,
FnMissingParams
@ -56,7 +58,9 @@ impl Error for ParseError {
ParseError::MissingRParen => "Expected ')'",
ParseError::MissingLCurly => "Expected '{'",
ParseError::MissingRCurly => "Expected '}'",
ParseError::MissingRSquare => "Expected ']'",
ParseError::MalformedCallExpr => "Call contains bad expression",
ParseError::MalformedIndexExpr => "Indexing expression missing correct index",
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable",
ParseError::FnMissingName => "Function declaration is missing name",
ParseError::FnMissingParams => "Function declaration is missing parameters"
@ -87,7 +91,7 @@ pub enum Stmt { If(Box<Expr>, Box<Stmt>), IfElse(Box<Expr>, Box<Stmt>, Box<Stmt>
#[derive(Debug, Clone)]
pub enum Expr { IntConst(i32), Identifier(String), StringConst(String), FnCall(String, Box<Vec<Expr>>),
Assignment(Box<Expr>, Box<Expr>), Dot(Box<Expr>, Box<Expr>), True, False }
Assignment(Box<Expr>, Box<Expr>), Dot(Box<Expr>, Box<Expr>), Index(String, Box<Expr>), Array(Box<Vec<Expr>>), True, False }
#[derive(Debug)]
pub enum Token { IntConst(i32), Identifier(String), StringConst(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare,
@ -355,12 +359,7 @@ fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr,
}
}
fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
match input.peek() {
Some(&Token::LParen) => {input.next();},
_ => return Ok(Expr::Identifier(id))
}
fn parse_call_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
let mut args = Vec::new();
match input.peek() {
@ -392,6 +391,59 @@ fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) ->
}
}
fn parse_index_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
if let Ok(idx) = parse_expr(input) {
match input.peek() {
Some(&Token::RSquare) => {
input.next();
return Ok(Expr::Index(id, Box::new(idx)))
},
_ => return Err(ParseError::MalformedIndexExpr)
}
}
else {
return Err(ParseError::MalformedIndexExpr);
}
}
fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
match input.peek() {
Some(&Token::LParen) => {input.next(); parse_call_expr(id, input)},
Some(&Token::LSquare) => {input.next(); parse_index_expr(id, input)},
_ => return Ok(Expr::Identifier(id))
}
}
fn parse_array_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
let mut arr = Vec::new();
let skip_contents = match input.peek() {
Some(& Token::RSquare) => true,
_ => false
};
if !skip_contents {
while let Some(_) = input.peek() {
arr.push(try!(parse_expr(input)));
match input.peek() {
Some(& Token::Comma) => {input.next();},
_ => ()
}
match input.peek() {
Some(& Token::RSquare) => break,
_ => ()
}
}
}
match input.peek() {
Some(& Token::RSquare) => {input.next(); Ok(Expr::Array(Box::new(arr)))},
_ => Err(ParseError::MissingRSquare)
}
}
fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
if let Some(token) = input.next() {
match token {
@ -399,6 +451,7 @@ fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pa
Token::StringConst(ref s) => {Ok(Expr::StringConst(s.clone()))},
Token::Identifier(ref s) => {parse_ident_expr(s.clone(), input)},
Token::LParen => {parse_paren_expr(input)},
Token::LSquare => {parse_array_expr(input)},
Token::True => {Ok(Expr::True)},
Token::False => {Ok(Expr::False)},
Token::LexErr(le) => {println!("Error: {}", le); Err(ParseError::BadInput)}