General cleanup.
This commit is contained in:
parent
708c285a0a
commit
880bce1114
@ -18,6 +18,7 @@ include = [
|
||||
num-traits = "*"
|
||||
|
||||
[features]
|
||||
#default = ["no_index", "no_float", "only_i32", "no_stdlib", "unchecked"]
|
||||
default = []
|
||||
debug_msgs = []
|
||||
unchecked = []
|
||||
|
@ -2,45 +2,23 @@
|
||||
//! _standard library_ of utility functions.
|
||||
|
||||
use crate::any::Any;
|
||||
use crate::engine::Engine;
|
||||
use crate::fn_register::RegisterFn;
|
||||
use crate::parser::INT;
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
use crate::{parser::Position, result::EvalAltResult, RegisterResultFn};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::engine::Array;
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::engine::Engine;
|
||||
use crate::fn_register::{RegisterFn, RegisterResultFn};
|
||||
use crate::parser::{Position, INT};
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::FLOAT;
|
||||
|
||||
use num_traits::{
|
||||
identities::Zero, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl,
|
||||
CheckedShr, CheckedSub,
|
||||
};
|
||||
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
ops::{BitAnd, BitOr, BitXor, Range},
|
||||
};
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
use std::ops::{Shl, Shr};
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use std::{i32, i64};
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
use std::u32;
|
||||
|
||||
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
use {
|
||||
num_traits::{
|
||||
CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr,
|
||||
CheckedSub,
|
||||
},
|
||||
std::convert::TryFrom,
|
||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Range, Rem, Shl, Shr, Sub},
|
||||
{i32, i64, u32},
|
||||
};
|
||||
|
||||
macro_rules! reg_op {
|
||||
@ -162,12 +140,9 @@ impl Engine<'_> {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
fn div<T>(x: T, y: T) -> Result<T, EvalAltResult>
|
||||
where
|
||||
T: Display + CheckedDiv + PartialEq + TryFrom<i8>,
|
||||
{
|
||||
if y == <T as TryFrom<i8>>::try_from(0)
|
||||
.map_err(|_| ())
|
||||
.expect("zero should always succeed")
|
||||
T: Display + CheckedDiv + PartialEq + Zero,
|
||||
{
|
||||
if y == T::zero() {
|
||||
return Err(EvalAltResult::ErrorArithmetic(
|
||||
format!("Division by zero: {} / {}", x, y),
|
||||
Position::none(),
|
||||
@ -191,8 +166,10 @@ impl Engine<'_> {
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
fn abs<T: Display + CheckedNeg + PartialOrd + From<i8>>(x: T) -> Result<T, EvalAltResult> {
|
||||
if x >= 0.into() {
|
||||
fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> Result<T, EvalAltResult> {
|
||||
// FIX - We don't use Signed::abs() here because, contrary to documentation, it panics
|
||||
// when the number is ::MIN instead of returning ::MIN itself.
|
||||
if x >= <T as Zero>::zero() {
|
||||
Ok(x)
|
||||
} else {
|
||||
x.checked_neg().ok_or_else(|| {
|
||||
@ -224,14 +201,15 @@ impl Engine<'_> {
|
||||
-x
|
||||
}
|
||||
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||
fn abs_u<T: Neg + PartialOrd + From<i8>>(x: T) -> T
|
||||
fn abs_u<T>(x: T) -> <T as Neg>::Output
|
||||
where
|
||||
<T as Neg>::Output: Into<T>,
|
||||
T: Neg + PartialOrd + Default + Into<<T as Neg>::Output>,
|
||||
{
|
||||
if x < 0.into() {
|
||||
(-x).into()
|
||||
// Numbers should default to zero
|
||||
if x < Default::default() {
|
||||
-x
|
||||
} else {
|
||||
x
|
||||
x.into()
|
||||
}
|
||||
}
|
||||
fn lt<T: PartialOrd>(x: T, y: T) -> bool {
|
||||
|
@ -4,8 +4,6 @@ use crate::any::{Any, AnyExt, Dynamic, Variant};
|
||||
use crate::parser::{Expr, FnDef, Position, Stmt};
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::scope::Scope;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::INT;
|
||||
|
||||
use std::{
|
||||
@ -788,6 +786,9 @@ impl Engine<'_> {
|
||||
.eval_index_expr(scope, lhs, idx_expr, *idx_pos)
|
||||
.map(|(_, _, _, x)| x),
|
||||
|
||||
#[cfg(feature = "no_index")]
|
||||
Expr::Index(_, _, _) => panic!("encountered an index expression during no_index!"),
|
||||
|
||||
// Statement block
|
||||
Expr::Stmt(stmt, _) => self.eval_stmt(scope, stmt),
|
||||
|
||||
@ -855,6 +856,8 @@ impl Engine<'_> {
|
||||
|
||||
Ok(Box::new(arr))
|
||||
}
|
||||
#[cfg(feature = "no_index")]
|
||||
Expr::Array(_, _) => panic!("encountered an array during no_index!"),
|
||||
|
||||
Expr::FunctionCall(fn_name, args, def_val, pos) => {
|
||||
let mut args = args
|
||||
|
@ -120,8 +120,9 @@ macro_rules! def_register {
|
||||
const NUM_ARGS: usize = count_args!($($par)*);
|
||||
|
||||
if args.len() != NUM_ARGS {
|
||||
Err(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos))
|
||||
} else {
|
||||
return Err(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos));
|
||||
}
|
||||
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut drain = args.drain(..);
|
||||
$(
|
||||
@ -133,7 +134,6 @@ macro_rules! def_register {
|
||||
// potentially clone the value, otherwise pass the reference.
|
||||
let r = f($(($clone)($par)),*);
|
||||
Ok(Box::new(r) as Dynamic)
|
||||
}
|
||||
};
|
||||
self.register_fn_raw(name, Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
|
||||
}
|
||||
@ -152,8 +152,9 @@ macro_rules! def_register {
|
||||
const NUM_ARGS: usize = count_args!($($par)*);
|
||||
|
||||
if args.len() != NUM_ARGS {
|
||||
Err(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos))
|
||||
} else {
|
||||
return Err(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos));
|
||||
}
|
||||
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut drain = args.drain(..);
|
||||
$(
|
||||
@ -164,7 +165,6 @@ macro_rules! def_register {
|
||||
// Call the user-supplied function using ($clone) to
|
||||
// potentially clone the value, otherwise pass the reference.
|
||||
Ok(f($(($clone)($par)),*))
|
||||
}
|
||||
};
|
||||
self.register_fn_raw(name, Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
|
||||
}
|
||||
@ -184,8 +184,9 @@ macro_rules! def_register {
|
||||
const NUM_ARGS: usize = count_args!($($par)*);
|
||||
|
||||
if args.len() != NUM_ARGS {
|
||||
Err(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos))
|
||||
} else {
|
||||
return Err(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos));
|
||||
}
|
||||
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut drain = args.drain(..);
|
||||
$(
|
||||
@ -202,7 +203,6 @@ macro_rules! def_register {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
self.register_fn_raw(name, Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
|
||||
}
|
||||
|
@ -141,6 +141,7 @@ fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
||||
Box::new(optimize_expr(*rhs, changed)),
|
||||
pos,
|
||||
),
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Index(lhs, rhs, pos) => match (*lhs, *rhs) {
|
||||
(Expr::Array(mut items, _), Expr::IntegerConstant(i, _))
|
||||
@ -158,6 +159,9 @@ fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
||||
pos,
|
||||
),
|
||||
},
|
||||
#[cfg(feature = "no_index")]
|
||||
Expr::Index(_, _, _) => panic!("encountered an index expression during no_index!"),
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Array(items, pos) => {
|
||||
let original_len = items.len();
|
||||
@ -172,6 +176,9 @@ fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
||||
Expr::Array(items, pos)
|
||||
}
|
||||
|
||||
#[cfg(feature = "no_index")]
|
||||
Expr::Array(_, _) => panic!("encountered an array during no_index!"),
|
||||
|
||||
Expr::And(lhs, rhs) => match (*lhs, *rhs) {
|
||||
(Expr::True(_), rhs) => {
|
||||
*changed = true;
|
||||
@ -208,7 +215,6 @@ fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
||||
Box::new(optimize_expr(rhs, changed)),
|
||||
),
|
||||
},
|
||||
|
||||
Expr::FunctionCall(id, args, def_value, pos) => {
|
||||
let original_len = args.len();
|
||||
|
||||
|
@ -3,13 +3,18 @@
|
||||
use crate::any::Dynamic;
|
||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||
use crate::optimize::optimize;
|
||||
|
||||
use std::{borrow::Cow, char, fmt, iter::Peekable, str::Chars, str::FromStr, usize};
|
||||
|
||||
/// The system integer type
|
||||
/// The system integer type.
|
||||
///
|
||||
/// If the `only_i32` feature is enabled, this will be `i32` instead.
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
pub type INT = i64;
|
||||
|
||||
/// The system integer type
|
||||
///
|
||||
/// If the `only_i32` feature is not enabled, this will be `i64` instead.
|
||||
#[cfg(feature = "only_i32")]
|
||||
pub type INT = i32;
|
||||
|
||||
@ -179,9 +184,7 @@ pub enum Expr {
|
||||
FunctionCall(String, Vec<Expr>, Option<Dynamic>, Position),
|
||||
Assignment(Box<Expr>, Box<Expr>, Position),
|
||||
Dot(Box<Expr>, Box<Expr>, Position),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Index(Box<Expr>, Box<Expr>, Position),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Array(Vec<Expr>, Position),
|
||||
And(Box<Expr>, Box<Expr>),
|
||||
Or(Box<Expr>, Box<Expr>),
|
||||
@ -197,24 +200,21 @@ impl Expr {
|
||||
| Expr::Identifier(_, pos)
|
||||
| Expr::CharConstant(_, pos)
|
||||
| Expr::StringConstant(_, pos)
|
||||
| Expr::FunctionCall(_, _, _, pos)
|
||||
| Expr::Stmt(_, pos)
|
||||
| Expr::FunctionCall(_, _, _, pos)
|
||||
| Expr::Array(_, pos)
|
||||
| Expr::True(pos)
|
||||
| Expr::False(pos)
|
||||
| Expr::Unit(pos) => *pos,
|
||||
|
||||
Expr::Assignment(e, _, _) | Expr::Dot(e, _, _) | Expr::And(e, _) | Expr::Or(e, _) => {
|
||||
e.position()
|
||||
}
|
||||
Expr::Assignment(e, _, _)
|
||||
| Expr::Dot(e, _, _)
|
||||
| Expr::Index(e, _, _)
|
||||
| Expr::And(e, _)
|
||||
| Expr::Or(e, _) => e.position(),
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Expr::FloatConstant(_, pos) => *pos,
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Index(e, _, _) => e.position(),
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Array(_, pos) => *pos,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
use crate::any::Dynamic;
|
||||
use crate::error::ParseError;
|
||||
use crate::parser::{Position, INT};
|
||||
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
/// Evaluation result.
|
||||
@ -75,12 +76,12 @@ impl Error for EvalAltResult {
|
||||
Self::ErrorArrayBounds(_, index, _) if *index < 0 => {
|
||||
"Array access expects non-negative index"
|
||||
}
|
||||
Self::ErrorArrayBounds(max, _, _) if *max == 0 => "Access of empty array",
|
||||
Self::ErrorArrayBounds(0, _, _) => "Access of empty array",
|
||||
Self::ErrorArrayBounds(_, _, _) => "Array index out of bounds",
|
||||
Self::ErrorStringBounds(_, index, _) if *index < 0 => {
|
||||
"Indexing a string expects a non-negative index"
|
||||
}
|
||||
Self::ErrorStringBounds(max, _, _) if *max == 0 => "Indexing of empty string",
|
||||
Self::ErrorStringBounds(0, _, _) => "Indexing of empty string",
|
||||
Self::ErrorStringBounds(_, _, _) => "String index out of bounds",
|
||||
Self::ErrorIfGuard(_) => "If guard expects boolean expression",
|
||||
Self::ErrorFor(_) => "For loop expects array or range",
|
||||
@ -128,6 +129,16 @@ impl fmt::Display for EvalAltResult {
|
||||
write!(f, "{} '{}': {}", desc, filename, err)
|
||||
}
|
||||
Self::ErrorParsing(p) => write!(f, "Syntax error: {}", p),
|
||||
Self::ErrorFunctionArgsMismatch(fun, 0, n, pos) => write!(
|
||||
f,
|
||||
"Function '{}' expects no argument but {} found ({})",
|
||||
fun, n, pos
|
||||
),
|
||||
Self::ErrorFunctionArgsMismatch(fun, 1, n, pos) => write!(
|
||||
f,
|
||||
"Function '{}' expects one argument but {} found ({})",
|
||||
fun, n, pos
|
||||
),
|
||||
Self::ErrorFunctionArgsMismatch(fun, need, n, pos) => write!(
|
||||
f,
|
||||
"Function '{}' expects {} argument(s) but {} found ({})",
|
||||
@ -142,26 +153,30 @@ impl fmt::Display for EvalAltResult {
|
||||
Self::ErrorArrayBounds(_, index, pos) if *index < 0 => {
|
||||
write!(f, "{}: {} < 0 ({})", desc, index, pos)
|
||||
}
|
||||
Self::ErrorArrayBounds(max, _, pos) if *max == 0 => write!(f, "{} ({})", desc, pos),
|
||||
Self::ErrorArrayBounds(0, _, pos) => write!(f, "{} ({})", desc, pos),
|
||||
Self::ErrorArrayBounds(1, index, pos) => write!(
|
||||
f,
|
||||
"Array index {} is out of bounds: only one element in the array ({})",
|
||||
index, pos
|
||||
),
|
||||
Self::ErrorArrayBounds(max, index, pos) => write!(
|
||||
f,
|
||||
"Array index {} is out of bounds: only {} element{} in the array ({})",
|
||||
index,
|
||||
max,
|
||||
if *max > 1 { "s" } else { "" },
|
||||
pos
|
||||
"Array index {} is out of bounds: only {} elements in the array ({})",
|
||||
index, max, pos
|
||||
),
|
||||
Self::ErrorStringBounds(_, index, pos) if *index < 0 => {
|
||||
write!(f, "{}: {} < 0 ({})", desc, index, pos)
|
||||
}
|
||||
Self::ErrorStringBounds(max, _, pos) if *max == 0 => write!(f, "{} ({})", desc, pos),
|
||||
Self::ErrorStringBounds(0, _, pos) => write!(f, "{} ({})", desc, pos),
|
||||
Self::ErrorStringBounds(1, index, pos) => write!(
|
||||
f,
|
||||
"String index {} is out of bounds: only one character in the string ({})",
|
||||
index, pos
|
||||
),
|
||||
Self::ErrorStringBounds(max, index, pos) => write!(
|
||||
f,
|
||||
"String index {} is out of bounds: only {} character{} in the string ({})",
|
||||
index,
|
||||
max,
|
||||
if *max > 1 { "s" } else { "" },
|
||||
pos
|
||||
"String index {} is out of bounds: only {} characters in the string ({})",
|
||||
index, max, pos
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Module that defines the `Scope` type representing a function call-stack scope.
|
||||
|
||||
use crate::any::{Any, Dynamic};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// A type containing information about current scope.
|
||||
|
@ -24,6 +24,10 @@ fn test_math() -> Result<(), EvalAltResult> {
|
||||
{
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
{
|
||||
match engine.eval::<INT>("(-9223372036854775808).abs()") {
|
||||
Err(EvalAltResult::ErrorArithmetic(_, _)) => (),
|
||||
r => panic!("should return overflow error: {:?}", r),
|
||||
}
|
||||
match engine.eval::<INT>("9223372036854775807 + 1") {
|
||||
Err(EvalAltResult::ErrorArithmetic(_, _)) => (),
|
||||
r => panic!("should return overflow error: {:?}", r),
|
||||
|
Loading…
Reference in New Issue
Block a user