Minor code refactoring.

This commit is contained in:
Stephen Chung 2020-03-02 00:11:00 +08:00
parent a64b01692b
commit bedfe55005

View File

@ -2,14 +2,12 @@ use std::any::TypeId;
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::sync::Arc; use std::sync::Arc;
use crate::any::{Any, AnyExt, Dynamic, Variant}; use crate::any::{Any, AnyExt, Dynamic, Variant};
use crate::call::FunArgs; use crate::call::FunArgs;
use crate::fn_register::RegisterFn; use crate::fn_register::RegisterFn;
use crate::parser::{lex, parse, Expr, FnDef, ParseError, Stmt, AST}; use crate::parser::{lex, parse, Expr, FnDef, ParseError, Stmt, AST};
use fmt::Debug;
pub type Array = Vec<Dynamic>; pub type Array = Vec<Dynamic>;
pub type FnCallArgs<'a> = Vec<&'a mut Variant>; pub type FnCallArgs<'a> = Vec<&'a mut Variant>;
@ -112,8 +110,8 @@ impl Error for EvalAltResult {
} }
} }
impl fmt::Display for EvalAltResult { impl std::fmt::Display for EvalAltResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::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 {
@ -241,6 +239,7 @@ impl Engine {
.iter() .iter()
.map(|x| (*(&**x).into_dynamic()).type_name()) .map(|x| (*(&**x).into_dynamic()).type_name())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
EvalAltResult::ErrorFunctionNotFound(format!( EvalAltResult::ErrorFunctionNotFound(format!(
"{} ({})", "{} ({})",
ident, ident,
@ -250,6 +249,7 @@ impl Engine {
.and_then(move |f| match **f { .and_then(move |f| match **f {
FnIntExt::Ext(ref f) => { FnIntExt::Ext(ref f) => {
let r = f(args); let r = f(args);
if r.is_err() { if r.is_err() {
return r; return r;
} }
@ -270,6 +270,7 @@ impl Engine {
} }
FnIntExt::Int(ref f) => { FnIntExt::Int(ref f) => {
let mut scope = Scope::new(); let mut scope = Scope::new();
scope.extend( scope.extend(
f.params f.params
.iter() .iter()
@ -357,17 +358,20 @@ impl Engine {
.iter() .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)
.chain(args.iter_mut().map(|b| b.as_mut())) .chain(args.iter_mut().map(|b| b.as_mut()))
.collect(); .collect();
self.call_fn_raw(fn_name.to_owned(), args) self.call_fn_raw(fn_name.to_owned(), args)
} }
Expr::Identifier(id) => { Expr::Identifier(id) => {
let get_fn_name = "get$".to_string() + id; let get_fn_name = "get$".to_string() + id;
self.call_fn_raw(get_fn_name, vec![this_ptr]) self.call_fn_raw(get_fn_name, vec![this_ptr])
} }
Expr::Index(id, idx_raw) => { Expr::Index(id, idx_raw) => {
let idx = self let idx = self
.eval_expr(scope, idx_raw)? .eval_expr(scope, idx_raw)?
@ -380,26 +384,27 @@ 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])?;
if let Some(arr) = (*val).downcast_mut() as Option<&mut Array> { if let Some(arr) = (*val).downcast_mut() as Option<&mut Array> {
if idx < 0 { if idx >= 0 {
Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx))
} else {
arr.get(idx as usize) arr.get(idx as usize)
.cloned() .cloned()
.ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr.len(), idx)) .ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr.len(), idx))
} else {
Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx))
} }
} else if let Some(s) = (*val).downcast_mut() as Option<&mut String> { } else if let Some(s) = (*val).downcast_mut() as Option<&mut String> {
if idx < 0 { if idx >= 0 {
Err(EvalAltResult::ErrorStringBounds(s.chars().count(), idx))
} else {
s.chars() s.chars()
.nth(idx as usize) .nth(idx as usize)
.map(|ch| Box::new(ch) as Dynamic) .map(|ch| Box::new(ch) as Dynamic)
.ok_or_else(|| EvalAltResult::ErrorStringBounds(s.chars().count(), idx)) .ok_or_else(|| EvalAltResult::ErrorStringBounds(s.chars().count(), idx))
} else {
Err(EvalAltResult::ErrorStringBounds(s.chars().count(), idx))
} }
} else { } else {
Err(EvalAltResult::ErrorIndexing) Err(EvalAltResult::ErrorIndexing)
} }
} }
Expr::Dot(inner_lhs, inner_rhs) => match **inner_lhs { Expr::Dot(inner_lhs, inner_rhs) => match **inner_lhs {
Expr::Identifier(ref id) => { Expr::Identifier(ref id) => {
let get_fn_name = "get$".to_string() + id; let get_fn_name = "get$".to_string() + id;
@ -462,29 +467,27 @@ impl Engine {
if let Some(arr) = (*val).downcast_mut() as Option<&mut Array> { if let Some(arr) = (*val).downcast_mut() as Option<&mut Array> {
is_array = true; is_array = true;
return if idx < 0 { if idx >= 0 {
Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx))
} else {
arr.get(idx as usize) arr.get(idx as usize)
.cloned() .cloned()
.ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr.len(), idx)) .ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr.len(), idx))
}; } else {
Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx))
} }
} else if let Some(s) = (*val).downcast_mut() as Option<&mut String> {
if let Some(s) = (*val).downcast_mut() as Option<&mut String> {
is_array = false; is_array = false;
return if idx < 0 { if idx >= 0 {
Err(EvalAltResult::ErrorStringBounds(s.chars().count(), idx))
} else {
s.chars() s.chars()
.nth(idx as usize) .nth(idx as usize)
.map(|ch| Box::new(ch) as Dynamic) .map(|ch| Box::new(ch) as Dynamic)
.ok_or_else(|| EvalAltResult::ErrorStringBounds(s.chars().count(), idx)) .ok_or_else(|| EvalAltResult::ErrorStringBounds(s.chars().count(), idx))
}; } else {
Err(EvalAltResult::ErrorStringBounds(s.chars().count(), idx))
} }
} else {
Err(EvalAltResult::ErrorIndexing) Err(EvalAltResult::ErrorIndexing)
}
}) })
.map(|(idx_sc, val)| (is_array, idx_sc, idx as usize, val)) .map(|(idx_sc, val)| (is_array, idx_sc, idx as usize, val))
} }
@ -522,6 +525,7 @@ impl Engine {
value value
} }
Expr::Index(id, idx_raw) => { Expr::Index(id, idx_raw) => {
let (is_array, sc_idx, idx, mut target) = self.indexed_value(scope, id, idx_raw)?; let (is_array, sc_idx, idx, mut target) = self.indexed_value(scope, id, idx_raw)?;
let value = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); let value = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs);
@ -532,13 +536,11 @@ impl Engine {
if is_array { if is_array {
scope[sc_idx].1.downcast_mut::<Array>().unwrap()[idx] = target; scope[sc_idx].1.downcast_mut::<Array>().unwrap()[idx] = target;
} else { } else {
// Target should be a char Self::str_replace_char(
let new_ch = *target.downcast::<char>().unwrap(); scope[sc_idx].1.downcast_mut::<String>().unwrap(), // Root is a string
idx,
// Root should be a String *target.downcast::<char>().unwrap(), // Target should be a char
let s = scope[sc_idx].1.downcast_mut::<String>().unwrap(); );
Self::str_replace_char(s, idx, new_ch);
} }
value value
@ -556,11 +558,14 @@ impl Engine {
match dot_rhs { match dot_rhs {
Expr::Identifier(id) => { Expr::Identifier(id) => {
let set_fn_name = "set$".to_string() + id; let set_fn_name = "set$".to_string() + id;
self.call_fn_raw(set_fn_name, vec![this_ptr, source_val.as_mut()]) self.call_fn_raw(set_fn_name, vec![this_ptr, source_val.as_mut()])
} }
Expr::Dot(inner_lhs, inner_rhs) => match **inner_lhs { Expr::Dot(inner_lhs, inner_rhs) => match **inner_lhs {
Expr::Identifier(ref id) => { Expr::Identifier(ref id) => {
let get_fn_name = "get$".to_string() + id; let get_fn_name = "get$".to_string() + id;
self.call_fn_raw(get_fn_name, vec![this_ptr]) self.call_fn_raw(get_fn_name, vec![this_ptr])
.and_then(|mut v| { .and_then(|mut v| {
self.set_dot_val_helper(v.as_mut(), inner_rhs, source_val) self.set_dot_val_helper(v.as_mut(), inner_rhs, source_val)
@ -596,6 +601,7 @@ impl Engine {
value value
} }
Expr::Index(id, idx_raw) => { Expr::Index(id, idx_raw) => {
let (is_array, sc_idx, idx, mut target) = self.indexed_value(scope, id, idx_raw)?; let (is_array, sc_idx, idx, mut target) = self.indexed_value(scope, id, idx_raw)?;
let value = self.set_dot_val_helper(target.as_mut(), dot_rhs, source_val); let value = self.set_dot_val_helper(target.as_mut(), dot_rhs, source_val);
@ -605,13 +611,11 @@ impl Engine {
if is_array { if is_array {
scope[sc_idx].1.downcast_mut::<Array>().unwrap()[idx] = target; scope[sc_idx].1.downcast_mut::<Array>().unwrap()[idx] = target;
} else { } else {
// Target should be a char Self::str_replace_char(
let new_ch = *target.downcast::<char>().unwrap(); scope[sc_idx].1.downcast_mut::<String>().unwrap(), // Root is a string
idx,
// Root should be a String *target.downcast::<char>().unwrap(), // Target should be a char
let s = scope[sc_idx].1.downcast_mut::<String>().unwrap(); );
Self::str_replace_char(s, idx, new_ch);
} }
value value
@ -626,28 +630,34 @@ impl Engine {
Expr::FloatConstant(i) => Ok(Box::new(*i)), Expr::FloatConstant(i) => Ok(Box::new(*i)),
Expr::StringConstant(s) => Ok(Box::new(s.clone())), Expr::StringConstant(s) => Ok(Box::new(s.clone())),
Expr::CharConstant(c) => Ok(Box::new(*c)), Expr::CharConstant(c) => Ok(Box::new(*c)),
Expr::Identifier(id) => {
match scope.iter().rev().filter(|(name, _)| id == name).next() { Expr::Identifier(id) => scope
Some((_, val)) => Ok(val.clone()), .iter()
_ => Err(EvalAltResult::ErrorVariableNotFound(id.clone())), .rev()
} .filter(|(name, _)| id == name)
} .next()
.map(|(_, val)| val.clone())
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(id.clone())),
Expr::Index(id, idx_raw) => { Expr::Index(id, idx_raw) => {
self.indexed_value(scope, id, idx_raw).map(|(_, _, _, x)| x) self.indexed_value(scope, id, idx_raw).map(|(_, _, _, x)| x)
} }
Expr::Assignment(ref id, rhs) => { Expr::Assignment(ref id, rhs) => {
let rhs_val = self.eval_expr(scope, rhs)?; let rhs_val = self.eval_expr(scope, rhs)?;
match **id { match **id {
Expr::Identifier(ref n) => { Expr::Identifier(ref n) => scope
match scope.iter_mut().rev().filter(|(name, _)| n == name).next() { .iter_mut()
Some((_, val)) => { .rev()
.filter(|(name, _)| n == name)
.next()
.map(|(_, val)| {
*val = rhs_val; *val = rhs_val;
Ok(Box::new(())) Box::new(()) as Dynamic
} })
_ => Err(EvalAltResult::ErrorVariableNotFound(n.clone())), .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(n.clone())),
}
}
Expr::Index(ref id, ref idx_raw) => { Expr::Index(ref id, ref idx_raw) => {
let idx = *match self.eval_expr(scope, &idx_raw)?.downcast_ref::<i64>() { let idx = *match self.eval_expr(scope, &idx_raw)?.downcast_ref::<i64>() {
Some(x) => x, Some(x) => x,
@ -667,32 +677,32 @@ impl Engine {
}; };
if let Some(arr) = val.downcast_mut() as Option<&mut Array> { if let Some(arr) = val.downcast_mut() as Option<&mut Array> {
return if idx < 0 { if idx < 0 {
Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx)) Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx))
} else if idx as usize >= arr.len() { } else if idx as usize >= arr.len() {
Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx)) Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx))
} else { } else {
arr[idx as usize] = rhs_val; arr[idx as usize] = rhs_val;
Ok(Box::new(())) Ok(Box::new(()))
};
} }
} else if let Some(s) = val.downcast_mut() as Option<&mut String> {
if let Some(s) = val.downcast_mut() as Option<&mut String> {
let s_len = s.chars().count(); let s_len = s.chars().count();
return if idx < 0 { if idx < 0 {
Err(EvalAltResult::ErrorStringBounds(s_len, idx)) Err(EvalAltResult::ErrorStringBounds(s_len, idx))
} else if idx as usize >= s_len { } else if idx as usize >= s_len {
Err(EvalAltResult::ErrorStringBounds(s_len, idx)) Err(EvalAltResult::ErrorStringBounds(s_len, idx))
} else { } else {
// Should be a char Self::str_replace_char(
let new_ch = *rhs_val.downcast::<char>().unwrap(); s,
Self::str_replace_char(s, idx as usize, new_ch); idx as usize,
*rhs_val.downcast::<char>().unwrap(),
);
Ok(Box::new(())) Ok(Box::new(()))
};
} }
} else {
return Err(EvalAltResult::ErrorIndexExpr); Err(EvalAltResult::ErrorIndexExpr)
}
} }
Expr::Dot(ref dot_lhs, ref dot_rhs) => { Expr::Dot(ref dot_lhs, ref dot_rhs) => {
self.set_dot_val(scope, dot_lhs, dot_rhs, rhs_val) self.set_dot_val(scope, dot_lhs, dot_rhs, rhs_val)
@ -700,7 +710,9 @@ impl Engine {
_ => Err(EvalAltResult::ErrorAssignmentToUnknownLHS), _ => Err(EvalAltResult::ErrorAssignmentToUnknownLHS),
} }
} }
Expr::Dot(lhs, rhs) => self.get_dot_val(scope, lhs, rhs), Expr::Dot(lhs, rhs) => self.get_dot_val(scope, lhs, rhs),
Expr::Array(contents) => { Expr::Array(contents) => {
let mut arr = Vec::new(); let mut arr = Vec::new();
@ -712,6 +724,7 @@ impl Engine {
Ok(Box::new(arr)) Ok(Box::new(arr))
} }
Expr::FunctionCall(fn_name, args) => self.call_fn_raw( Expr::FunctionCall(fn_name, args) => self.call_fn_raw(
fn_name.to_owned(), fn_name.to_owned(),
args.iter() args.iter()
@ -721,6 +734,7 @@ impl Engine {
.map(|b| b.as_mut()) .map(|b| b.as_mut())
.collect(), .collect(),
), ),
Expr::True => Ok(Box::new(true)), Expr::True => Ok(Box::new(true)),
Expr::False => Ok(Box::new(false)), Expr::False => Ok(Box::new(false)),
Expr::Unit => Ok(Box::new(())), Expr::Unit => Ok(Box::new(())),
@ -730,12 +744,14 @@ impl Engine {
fn eval_stmt(&self, scope: &mut Scope, stmt: &Stmt) -> Result<Dynamic, EvalAltResult> { fn eval_stmt(&self, scope: &mut Scope, stmt: &Stmt) -> Result<Dynamic, EvalAltResult> {
match stmt { match stmt {
Stmt::Expr(expr) => self.eval_expr(scope, expr), Stmt::Expr(expr) => self.eval_expr(scope, expr),
Stmt::Block(block) => { Stmt::Block(block) => {
let prev_len = scope.len(); let prev_len = scope.len();
let mut last_result: Result<Dynamic, EvalAltResult> = Ok(Box::new(())); let mut last_result: Result<Dynamic, EvalAltResult> = Ok(Box::new(()));
for block_stmt in block.iter() { for block_stmt in block.iter() {
last_result = self.eval_stmt(scope, block_stmt); last_result = self.eval_stmt(scope, block_stmt);
if let Err(x) = last_result { if let Err(x) = last_result {
last_result = Err(x); last_result = Err(x);
break; break;
@ -748,6 +764,7 @@ impl Engine {
last_result last_result
} }
Stmt::If(guard, body) => self Stmt::If(guard, body) => self
.eval_expr(scope, guard)? .eval_expr(scope, guard)?
.downcast::<bool>() .downcast::<bool>()
@ -759,6 +776,7 @@ impl Engine {
Ok(Box::new(())) Ok(Box::new(()))
} }
}), }),
Stmt::IfElse(guard, body, else_body) => self Stmt::IfElse(guard, body, else_body) => self
.eval_expr(scope, guard)? .eval_expr(scope, guard)?
.downcast::<bool>() .downcast::<bool>()
@ -770,6 +788,7 @@ impl Engine {
self.eval_stmt(scope, else_body) self.eval_stmt(scope, else_body)
} }
}), }),
Stmt::While(guard, body) => loop { Stmt::While(guard, body) => loop {
match self.eval_expr(scope, guard)?.downcast::<bool>() { match self.eval_expr(scope, guard)?.downcast::<bool>() {
Ok(guard_val) => { Ok(guard_val) => {
@ -786,6 +805,7 @@ impl Engine {
Err(_) => return Err(EvalAltResult::ErrorIfGuard), Err(_) => return Err(EvalAltResult::ErrorIfGuard),
} }
}, },
Stmt::Loop(body) => loop { Stmt::Loop(body) => loop {
match self.eval_stmt(scope, body) { match self.eval_stmt(scope, body) {
Err(EvalAltResult::LoopBreak) => return Ok(Box::new(())), Err(EvalAltResult::LoopBreak) => return Ok(Box::new(())),
@ -793,14 +813,18 @@ impl Engine {
_ => (), _ => (),
} }
}, },
Stmt::For(name, expr, body) => { Stmt::For(name, expr, body) => {
let arr = self.eval_expr(scope, expr)?; let arr = self.eval_expr(scope, expr)?;
let tid = Any::type_id(&*arr); let tid = Any::type_id(&*arr);
if let Some(iter_fn) = self.type_iterators.get(&tid) { if let Some(iter_fn) = self.type_iterators.get(&tid) {
scope.push((name.clone(), Box::new(()))); scope.push((name.clone(), Box::new(())));
let idx = scope.len() - 1; let idx = scope.len() - 1;
for a in iter_fn(&arr) { for a in iter_fn(&arr) {
scope[idx].1 = a; scope[idx].1 = a;
match self.eval_stmt(scope, body) { match self.eval_stmt(scope, body) {
Err(EvalAltResult::LoopBreak) => break, Err(EvalAltResult::LoopBreak) => break,
Err(x) => return Err(x), Err(x) => return Err(x),
@ -813,12 +837,16 @@ impl Engine {
return Err(EvalAltResult::ErrorFor); return Err(EvalAltResult::ErrorFor);
} }
} }
Stmt::Break => Err(EvalAltResult::LoopBreak), Stmt::Break => Err(EvalAltResult::LoopBreak),
Stmt::Return => Err(EvalAltResult::Return(Box::new(()))), Stmt::Return => Err(EvalAltResult::Return(Box::new(()))),
Stmt::ReturnWithVal(a) => { Stmt::ReturnWithVal(a) => {
let result = self.eval_expr(scope, a)?; let result = self.eval_expr(scope, a)?;
Err(EvalAltResult::Return(result)) Err(EvalAltResult::Return(result))
} }
Stmt::Let(name, init) => { Stmt::Let(name, init) => {
if let Some(v) = init { if let Some(v) = init {
let i = self.eval_expr(scope, v)?; let i = self.eval_expr(scope, v)?;