Add no_float feature to disable floating-point.
This commit is contained in:
parent
52b5732bcb
commit
cc772c6e2a
@ -23,6 +23,7 @@ debug_msgs = []
|
|||||||
unchecked = []
|
unchecked = []
|
||||||
no_stdlib = []
|
no_stdlib = []
|
||||||
no_index = []
|
no_index = []
|
||||||
|
no_float = []
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
@ -44,6 +44,7 @@ Optional features
|
|||||||
| `no_stdlib` | Exclude the standard library of utility functions in the build, and only include the minimum necessary functionalities. |
|
| `no_stdlib` | Exclude the standard library of utility functions in the build, and only include the minimum necessary functionalities. |
|
||||||
| `unchecked` | Exclude arithmetic checking in the standard library. Beware that a bad script may panic the entire system! |
|
| `unchecked` | Exclude arithmetic checking in the standard library. Beware that a bad script may panic the entire system! |
|
||||||
| `no_index` | Disable arrays and indexing features |
|
| `no_index` | Disable arrays and indexing features |
|
||||||
|
| `no_float` | Disable floating-point numbers and math |
|
||||||
|
|
||||||
Related
|
Related
|
||||||
-------
|
-------
|
||||||
|
231
src/builtin.rs
231
src/builtin.rs
@ -11,13 +11,16 @@ use crate::engine::Array;
|
|||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
i32, i64,
|
i32, i64,
|
||||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Range, Rem, Sub},
|
ops::{BitAnd, BitOr, BitXor, Range},
|
||||||
u32,
|
u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
use std::ops::{Shl, Shr};
|
use std::ops::{Shl, Shr};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
|
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use {
|
use {
|
||||||
crate::{parser::Position, result::EvalAltResult, RegisterResultFn},
|
crate::{parser::Position, result::EvalAltResult, RegisterResultFn},
|
||||||
@ -188,21 +191,27 @@ impl Engine<'_> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn add_u<T: Add>(x: T, y: T) -> <T as Add>::Output {
|
fn add_u<T: Add>(x: T, y: T) -> <T as Add>::Output {
|
||||||
x + y
|
x + y
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn sub_u<T: Sub>(x: T, y: T) -> <T as Sub>::Output {
|
fn sub_u<T: Sub>(x: T, y: T) -> <T as Sub>::Output {
|
||||||
x - y
|
x - y
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn mul_u<T: Mul>(x: T, y: T) -> <T as Mul>::Output {
|
fn mul_u<T: Mul>(x: T, y: T) -> <T as Mul>::Output {
|
||||||
x * y
|
x * y
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn div_u<T: Div>(x: T, y: T) -> <T as Div>::Output {
|
fn div_u<T: Div>(x: T, y: T) -> <T as Div>::Output {
|
||||||
x / y
|
x / y
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn neg_u<T: Neg>(x: T) -> <T as Neg>::Output {
|
fn neg_u<T: Neg>(x: T) -> <T as Neg>::Output {
|
||||||
-x
|
-x
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn abs_u<T: Neg + PartialOrd + From<i8>>(x: T) -> T
|
fn abs_u<T: Neg + PartialOrd + From<i8>>(x: T) -> T
|
||||||
where
|
where
|
||||||
<T as Neg>::Output: Into<T>,
|
<T as Neg>::Output: Into<T>,
|
||||||
@ -298,6 +307,7 @@ impl Engine<'_> {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn modulo_u<T: Rem>(x: T, y: T) -> <T as Rem>::Output {
|
fn modulo_u<T: Rem>(x: T, y: T) -> <T as Rem>::Output {
|
||||||
x % y
|
x % y
|
||||||
}
|
}
|
||||||
@ -321,10 +331,12 @@ impl Engine<'_> {
|
|||||||
fn pow_i64_i64(x: i64, y: i64) -> i64 {
|
fn pow_i64_i64(x: i64, y: i64) -> i64 {
|
||||||
x.pow(y as u32)
|
x.pow(y as u32)
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
fn pow_f64_f64(x: f64, y: f64) -> f64 {
|
fn pow_f64_f64(x: f64, y: f64) -> f64 {
|
||||||
x.powf(y)
|
x.powf(y)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
fn pow_f64_i64_u(x: f64, y: i64) -> Result<f64, EvalAltResult> {
|
fn pow_f64_i64_u(x: f64, y: i64) -> Result<f64, EvalAltResult> {
|
||||||
if y > (i32::MAX as i64) {
|
if y > (i32::MAX as i64) {
|
||||||
return Err(EvalAltResult::ErrorArithmetic(
|
return Err(EvalAltResult::ErrorArithmetic(
|
||||||
@ -336,6 +348,7 @@ impl Engine<'_> {
|
|||||||
Ok(x.powi(y as i32))
|
Ok(x.powi(y as i32))
|
||||||
}
|
}
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
fn pow_f64_i64(x: f64, y: i64) -> f64 {
|
fn pow_f64_i64(x: f64, y: i64) -> f64 {
|
||||||
x.powi(y as i32)
|
x.powi(y as i32)
|
||||||
}
|
}
|
||||||
@ -356,21 +369,30 @@ impl Engine<'_> {
|
|||||||
reg_op!(self, "/", div_u, i8, u8, i16, u16, i32, i64, u32, u64);
|
reg_op!(self, "/", div_u, i8, u8, i16, u16, i32, i64, u32, u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_op!(self, "+", add_u, f32, f64);
|
#[cfg(not(feature = "no_float"))]
|
||||||
reg_op!(self, "-", sub_u, f32, f64);
|
{
|
||||||
reg_op!(self, "*", mul_u, f32, f64);
|
reg_op!(self, "+", add_u, f32, f64);
|
||||||
reg_op!(self, "/", div_u, f32, f64);
|
reg_op!(self, "-", sub_u, f32, f64);
|
||||||
|
reg_op!(self, "*", mul_u, f32, f64);
|
||||||
|
reg_op!(self, "/", div_u, f32, f64);
|
||||||
|
}
|
||||||
|
|
||||||
reg_cmp!(self, "<", lt, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64, String, char);
|
reg_cmp!(self, "<", lt, i8, u8, i16, u16, i32, i64, u32, u64, String, char);
|
||||||
reg_cmp!(self, "<=", lte, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64, String, char);
|
reg_cmp!(self, "<=", lte, i8, u8, i16, u16, i32, i64, u32, u64, String, char);
|
||||||
reg_cmp!(self, ">", gt, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64, String, char);
|
reg_cmp!(self, ">", gt, i8, u8, i16, u16, i32, i64, u32, u64, String, char);
|
||||||
reg_cmp!(self, ">=", gte, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64, String, char);
|
reg_cmp!(self, ">=", gte, i8, u8, i16, u16, i32, i64, u32, u64, String, char);
|
||||||
reg_cmp!(
|
reg_cmp!(self, "==", eq, i8, u8, i16, u16, i32, i64, u32, u64, bool, String, char);
|
||||||
self, "==", eq, i8, u8, i16, u16, i32, i64, u32, u64, bool, f32, f64, String, char
|
reg_cmp!(self, "!=", ne, i8, u8, i16, u16, i32, i64, u32, u64, bool, String, char);
|
||||||
);
|
|
||||||
reg_cmp!(
|
#[cfg(not(feature = "no_float"))]
|
||||||
self, "!=", ne, i8, u8, i16, u16, i32, i64, u32, u64, bool, f32, f64, String, char
|
{
|
||||||
);
|
reg_cmp!(self, "<", lt, f32, f64);
|
||||||
|
reg_cmp!(self, "<=", lte, f32, f64);
|
||||||
|
reg_cmp!(self, ">", gt, f32, f64);
|
||||||
|
reg_cmp!(self, ">=", gte, f32, f64);
|
||||||
|
reg_cmp!(self, "==", eq, f32, f64);
|
||||||
|
reg_cmp!(self, "!=", ne, f32, f64);
|
||||||
|
}
|
||||||
|
|
||||||
//reg_op!(self, "||", or, bool);
|
//reg_op!(self, "||", or, bool);
|
||||||
//reg_op!(self, "&&", and, bool);
|
//reg_op!(self, "&&", and, bool);
|
||||||
@ -396,19 +418,25 @@ impl Engine<'_> {
|
|||||||
reg_op!(self, "%", modulo_u, i8, u8, i16, u16, i32, i64, u32, u64);
|
reg_op!(self, "%", modulo_u, i8, u8, i16, u16, i32, i64, u32, u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_op!(self, "%", modulo_u, f32, f64);
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
{
|
||||||
self.register_fn("~", pow_f64_f64);
|
reg_op!(self, "%", modulo_u, f32, f64);
|
||||||
|
self.register_fn("~", pow_f64_f64);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
self.register_result_fn("~", pow_i64_i64_u);
|
self.register_result_fn("~", pow_i64_i64_u);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
self.register_result_fn("~", pow_f64_i64_u);
|
self.register_result_fn("~", pow_f64_i64_u);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
{
|
{
|
||||||
self.register_fn("~", pow_i64_i64);
|
self.register_fn("~", pow_i64_i64);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
self.register_fn("~", pow_f64_i64);
|
self.register_fn("~", pow_f64_i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,8 +452,12 @@ impl Engine<'_> {
|
|||||||
reg_un!(self, "abs", abs_u, i8, i16, i32, i64);
|
reg_un!(self, "abs", abs_u, i8, i16, i32, i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_un!(self, "-", neg_u, f32, f64);
|
#[cfg(not(feature = "no_float"))]
|
||||||
reg_un!(self, "abs", abs_u, f32, f64);
|
{
|
||||||
|
reg_un!(self, "-", neg_u, f32, f64);
|
||||||
|
reg_un!(self, "abs", abs_u, f32, f64);
|
||||||
|
}
|
||||||
|
|
||||||
reg_un!(self, "!", not, bool);
|
reg_un!(self, "!", not, bool);
|
||||||
|
|
||||||
self.register_fn("+", |x: String, y: String| x + &y); // String + String
|
self.register_fn("+", |x: String, y: String| x + &y); // String + String
|
||||||
@ -441,13 +473,19 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
reg_func1!(self, "print", print, String, i8, u8, i16, u16);
|
reg_func1!(self, "print", print, String, i8, u8, i16, u16);
|
||||||
reg_func1!(self, "print", print, String, i32, i64, u32, u64);
|
reg_func1!(self, "print", print, String, i32, i64, u32, u64);
|
||||||
reg_func1!(self, "print", print, String, f32, f64, bool, char, String);
|
reg_func1!(self, "print", print, String, bool, char, String);
|
||||||
self.register_fn("print", || "".to_string());
|
self.register_fn("print", || "".to_string());
|
||||||
self.register_fn("print", |_: ()| "".to_string());
|
self.register_fn("print", |_: ()| "".to_string());
|
||||||
|
|
||||||
reg_func1!(self, "debug", print_debug, String, i8, u8, i16, u16);
|
reg_func1!(self, "debug", print_debug, String, i8, u8, i16, u16);
|
||||||
reg_func1!(self, "debug", print_debug, String, i32, i64, u32, u64);
|
reg_func1!(self, "debug", print_debug, String, i32, i64, u32, u64);
|
||||||
reg_func1!(self, "debug", print_debug, String, f32, f64, bool, char);
|
reg_func1!(self, "debug", print_debug, String, bool, char);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
{
|
||||||
|
reg_func1!(self, "print", print, String, f32, f64);
|
||||||
|
reg_func1!(self, "debug", print_debug, String, f32, f64);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
@ -479,43 +517,46 @@ impl Engine<'_> {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::fn_register::RegisterDynamicFn;
|
use crate::fn_register::RegisterDynamicFn;
|
||||||
|
|
||||||
// Advanced math functions
|
#[cfg(not(feature = "no_float"))]
|
||||||
self.register_fn("sin", |x: f64| x.to_radians().sin());
|
{
|
||||||
self.register_fn("cos", |x: f64| x.to_radians().cos());
|
// Advanced math functions
|
||||||
self.register_fn("tan", |x: f64| x.to_radians().tan());
|
self.register_fn("sin", |x: f64| x.to_radians().sin());
|
||||||
self.register_fn("sinh", |x: f64| x.to_radians().sinh());
|
self.register_fn("cos", |x: f64| x.to_radians().cos());
|
||||||
self.register_fn("cosh", |x: f64| x.to_radians().cosh());
|
self.register_fn("tan", |x: f64| x.to_radians().tan());
|
||||||
self.register_fn("tanh", |x: f64| x.to_radians().tanh());
|
self.register_fn("sinh", |x: f64| x.to_radians().sinh());
|
||||||
self.register_fn("asin", |x: f64| x.asin().to_degrees());
|
self.register_fn("cosh", |x: f64| x.to_radians().cosh());
|
||||||
self.register_fn("acos", |x: f64| x.acos().to_degrees());
|
self.register_fn("tanh", |x: f64| x.to_radians().tanh());
|
||||||
self.register_fn("atan", |x: f64| x.atan().to_degrees());
|
self.register_fn("asin", |x: f64| x.asin().to_degrees());
|
||||||
self.register_fn("asinh", |x: f64| x.asinh().to_degrees());
|
self.register_fn("acos", |x: f64| x.acos().to_degrees());
|
||||||
self.register_fn("acosh", |x: f64| x.acosh().to_degrees());
|
self.register_fn("atan", |x: f64| x.atan().to_degrees());
|
||||||
self.register_fn("atanh", |x: f64| x.atanh().to_degrees());
|
self.register_fn("asinh", |x: f64| x.asinh().to_degrees());
|
||||||
self.register_fn("sqrt", |x: f64| x.sqrt());
|
self.register_fn("acosh", |x: f64| x.acosh().to_degrees());
|
||||||
self.register_fn("exp", |x: f64| x.exp());
|
self.register_fn("atanh", |x: f64| x.atanh().to_degrees());
|
||||||
self.register_fn("ln", |x: f64| x.ln());
|
self.register_fn("sqrt", |x: f64| x.sqrt());
|
||||||
self.register_fn("log", |x: f64, base: f64| x.log(base));
|
self.register_fn("exp", |x: f64| x.exp());
|
||||||
self.register_fn("log10", |x: f64| x.log10());
|
self.register_fn("ln", |x: f64| x.ln());
|
||||||
self.register_fn("floor", |x: f64| x.floor());
|
self.register_fn("log", |x: f64, base: f64| x.log(base));
|
||||||
self.register_fn("ceiling", |x: f64| x.ceil());
|
self.register_fn("log10", |x: f64| x.log10());
|
||||||
self.register_fn("round", |x: f64| x.ceil());
|
self.register_fn("floor", |x: f64| x.floor());
|
||||||
self.register_fn("int", |x: f64| x.trunc());
|
self.register_fn("ceiling", |x: f64| x.ceil());
|
||||||
self.register_fn("fraction", |x: f64| x.fract());
|
self.register_fn("round", |x: f64| x.ceil());
|
||||||
self.register_fn("is_nan", |x: f64| x.is_nan());
|
self.register_fn("int", |x: f64| x.trunc());
|
||||||
self.register_fn("is_finite", |x: f64| x.is_finite());
|
self.register_fn("fraction", |x: f64| x.fract());
|
||||||
self.register_fn("is_infinite", |x: f64| x.is_infinite());
|
self.register_fn("is_nan", |x: f64| x.is_nan());
|
||||||
|
self.register_fn("is_finite", |x: f64| x.is_finite());
|
||||||
|
self.register_fn("is_infinite", |x: f64| x.is_infinite());
|
||||||
|
|
||||||
// Register conversion functions
|
// Register conversion functions
|
||||||
self.register_fn("to_float", |x: i8| x as f64);
|
self.register_fn("to_float", |x: i8| x as f64);
|
||||||
self.register_fn("to_float", |x: u8| x as f64);
|
self.register_fn("to_float", |x: u8| x as f64);
|
||||||
self.register_fn("to_float", |x: i16| x as f64);
|
self.register_fn("to_float", |x: i16| x as f64);
|
||||||
self.register_fn("to_float", |x: u16| x as f64);
|
self.register_fn("to_float", |x: u16| x as f64);
|
||||||
self.register_fn("to_float", |x: i32| x as f64);
|
self.register_fn("to_float", |x: i32| x as f64);
|
||||||
self.register_fn("to_float", |x: u32| x as f64);
|
self.register_fn("to_float", |x: u32| x as f64);
|
||||||
self.register_fn("to_float", |x: i64| x as f64);
|
self.register_fn("to_float", |x: i64| x as f64);
|
||||||
self.register_fn("to_float", |x: u64| x as f64);
|
self.register_fn("to_float", |x: u64| x as f64);
|
||||||
self.register_fn("to_float", |x: f32| x as f64);
|
self.register_fn("to_float", |x: f32| x as f64);
|
||||||
|
}
|
||||||
|
|
||||||
self.register_fn("to_int", |x: i8| x as i64);
|
self.register_fn("to_int", |x: i8| x as i64);
|
||||||
self.register_fn("to_int", |x: u8| x as i64);
|
self.register_fn("to_int", |x: u8| x as i64);
|
||||||
@ -526,34 +567,37 @@ impl Engine<'_> {
|
|||||||
self.register_fn("to_int", |x: u64| x as i64);
|
self.register_fn("to_int", |x: u64| x as i64);
|
||||||
self.register_fn("to_int", |ch: char| ch as i64);
|
self.register_fn("to_int", |ch: char| ch as i64);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
self.register_result_fn("to_int", |x: f32| {
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if x > (i64::MAX as f32) {
|
{
|
||||||
return Err(EvalAltResult::ErrorArithmetic(
|
self.register_result_fn("to_int", |x: f32| {
|
||||||
format!("Integer overflow: to_int({})", x),
|
if x > (i64::MAX as f32) {
|
||||||
Position::none(),
|
return Err(EvalAltResult::ErrorArithmetic(
|
||||||
));
|
format!("Integer overflow: to_int({})", x),
|
||||||
}
|
Position::none(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(x.trunc() as i64)
|
Ok(x.trunc() as i64)
|
||||||
});
|
});
|
||||||
self.register_result_fn("to_int", |x: f64| {
|
self.register_result_fn("to_int", |x: f64| {
|
||||||
if x > (i64::MAX as f64) {
|
if x > (i64::MAX as f64) {
|
||||||
return Err(EvalAltResult::ErrorArithmetic(
|
return Err(EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer overflow: to_int({})", x),
|
format!("Integer overflow: to_int({})", x),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(x.trunc() as i64)
|
Ok(x.trunc() as i64)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
{
|
{
|
||||||
self.register_fn("to_int", |x: f32| x as i64);
|
self.register_fn("to_int", |x: f32| x as i64);
|
||||||
self.register_fn("to_int", |x: f64| x as i64);
|
self.register_fn("to_int", |x: f64| x as i64);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -572,14 +616,19 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
reg_func2x!(self, "push", push, &mut Array, (), i8, u8, i16, u16);
|
reg_func2x!(self, "push", push, &mut Array, (), i8, u8, i16, u16);
|
||||||
reg_func2x!(self, "push", push, &mut Array, (), i32, i64, u32, u64);
|
reg_func2x!(self, "push", push, &mut Array, (), i32, i64, u32, u64);
|
||||||
reg_func2x!(self, "push", push, &mut Array, (), f32, f64, bool, char);
|
reg_func2x!(self, "push", push, &mut Array, (), bool, char);
|
||||||
reg_func2x!(self, "push", push, &mut Array, (), String, Array, ());
|
reg_func2x!(self, "push", push, &mut Array, (), String, Array, ());
|
||||||
reg_func3!(self, "pad", pad, &mut Array, i64, (), i8, u8, i16, u16);
|
reg_func3!(self, "pad", pad, &mut Array, i64, (), i8, u8, i16, u16);
|
||||||
reg_func3!(self, "pad", pad, &mut Array, i64, (), i32, u32, f32);
|
reg_func3!(self, "pad", pad, &mut Array, i64, (), i32, u32, i64, u64);
|
||||||
reg_func3!(self, "pad", pad, &mut Array, i64, (), i64, u64, f64);
|
|
||||||
reg_func3!(self, "pad", pad, &mut Array, i64, (), bool, char);
|
reg_func3!(self, "pad", pad, &mut Array, i64, (), bool, char);
|
||||||
reg_func3!(self, "pad", pad, &mut Array, i64, (), String, Array, ());
|
reg_func3!(self, "pad", pad, &mut Array, i64, (), String, Array, ());
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
{
|
||||||
|
reg_func2x!(self, "push", push, &mut Array, (), f32, f64);
|
||||||
|
reg_func3!(self, "pad", pad, &mut Array, i64, (), f32, f64);
|
||||||
|
}
|
||||||
|
|
||||||
self.register_dynamic_fn("pop", |list: &mut Array| {
|
self.register_dynamic_fn("pop", |list: &mut Array| {
|
||||||
list.pop().unwrap_or_else(|| ().into_dynamic())
|
list.pop().unwrap_or_else(|| ().into_dynamic())
|
||||||
});
|
});
|
||||||
@ -605,17 +654,21 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reg_func2x!(
|
reg_func2x!(
|
||||||
self, "+", append, String, String, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64,
|
self, "+", append, String, String, i8, u8, i16, u16, i32, i64, u32, u64, bool, char
|
||||||
bool, char
|
|
||||||
);
|
);
|
||||||
self.register_fn("+", |x: String, _: ()| format!("{}", x));
|
self.register_fn("+", |x: String, _: ()| format!("{}", x));
|
||||||
|
|
||||||
reg_func2y!(
|
reg_func2y!(
|
||||||
self, "+", prepend, String, String, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64,
|
self, "+", prepend, String, String, i8, u8, i16, u16, i32, i64, u32, u64, bool, char
|
||||||
bool, char
|
|
||||||
);
|
);
|
||||||
self.register_fn("+", |_: (), y: String| format!("{}", y));
|
self.register_fn("+", |_: (), y: String| format!("{}", y));
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
{
|
||||||
|
reg_func2x!(self, "+", append, String, String, f32, f64);
|
||||||
|
reg_func2y!(self, "+", prepend, String, String, f32, f64);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
self.register_fn("+", |x: String, y: Array| format!("{}{:?}", x, y));
|
self.register_fn("+", |x: String, y: Array| format!("{}{:?}", x, y));
|
||||||
|
@ -768,8 +768,10 @@ impl Engine<'_> {
|
|||||||
/// Evaluate an expression
|
/// Evaluate an expression
|
||||||
fn eval_expr(&mut self, scope: &mut Scope, expr: &Expr) -> Result<Dynamic, EvalAltResult> {
|
fn eval_expr(&mut self, scope: &mut Scope, expr: &Expr) -> Result<Dynamic, EvalAltResult> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::IntegerConstant(i, _) => Ok(i.into_dynamic()),
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(f, _) => Ok(f.into_dynamic()),
|
Expr::FloatConstant(f, _) => Ok(f.into_dynamic()),
|
||||||
|
|
||||||
|
Expr::IntegerConstant(i, _) => Ok(i.into_dynamic()),
|
||||||
Expr::StringConstant(s, _) => Ok(s.into_dynamic()),
|
Expr::StringConstant(s, _) => Ok(s.into_dynamic()),
|
||||||
Expr::CharConstant(c, _) => Ok(c.into_dynamic()),
|
Expr::CharConstant(c, _) => Ok(c.into_dynamic()),
|
||||||
Expr::Identifier(id, pos) => {
|
Expr::Identifier(id, pos) => {
|
||||||
|
@ -112,7 +112,6 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool) -> Stmt {
|
|||||||
fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::IntegerConstant(_, _)
|
Expr::IntegerConstant(_, _)
|
||||||
| Expr::FloatConstant(_, _)
|
|
||||||
| Expr::Identifier(_, _)
|
| Expr::Identifier(_, _)
|
||||||
| Expr::CharConstant(_, _)
|
| Expr::CharConstant(_, _)
|
||||||
| Expr::StringConstant(_, _)
|
| Expr::StringConstant(_, _)
|
||||||
@ -120,6 +119,9 @@ fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
|||||||
| Expr::False(_)
|
| Expr::False(_)
|
||||||
| Expr::Unit(_) => expr,
|
| Expr::Unit(_) => expr,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Expr::FloatConstant(_, _) => expr,
|
||||||
|
|
||||||
Expr::Stmt(stmt, pos) => match optimize_stmt(*stmt, changed) {
|
Expr::Stmt(stmt, pos) => match optimize_stmt(*stmt, changed) {
|
||||||
Stmt::Noop(_) => {
|
Stmt::Noop(_) => {
|
||||||
*changed = true;
|
*changed = true;
|
||||||
@ -144,9 +146,9 @@ fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr {
|
|||||||
(Expr::Array(mut items, _), Expr::IntegerConstant(i, _))
|
(Expr::Array(mut items, _), Expr::IntegerConstant(i, _))
|
||||||
if i >= 0
|
if i >= 0
|
||||||
&& (i as usize) < items.len()
|
&& (i as usize) < items.len()
|
||||||
&& !items.iter().any(|x| x.is_constant()) =>
|
&& !items.iter().any(|x| x.is_constant() || x.is_identifier()) =>
|
||||||
{
|
{
|
||||||
// Array where everything is a constant - promote the item
|
// Array where everything is a constant or identifier - promote the item
|
||||||
*changed = true;
|
*changed = true;
|
||||||
items.remove(i as usize)
|
items.remove(i as usize)
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,7 @@ impl Stmt {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
IntegerConstant(i64, Position),
|
IntegerConstant(i64, Position),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
FloatConstant(f64, Position),
|
FloatConstant(f64, Position),
|
||||||
Identifier(String, Position),
|
Identifier(String, Position),
|
||||||
CharConstant(char, Position),
|
CharConstant(char, Position),
|
||||||
@ -182,7 +183,6 @@ impl Expr {
|
|||||||
pub fn position(&self) -> Position {
|
pub fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
Expr::IntegerConstant(_, pos)
|
Expr::IntegerConstant(_, pos)
|
||||||
| Expr::FloatConstant(_, pos)
|
|
||||||
| Expr::Identifier(_, pos)
|
| Expr::Identifier(_, pos)
|
||||||
| Expr::CharConstant(_, pos)
|
| Expr::CharConstant(_, pos)
|
||||||
| Expr::StringConstant(_, pos)
|
| Expr::StringConstant(_, pos)
|
||||||
@ -196,6 +196,9 @@ impl Expr {
|
|||||||
e.position()
|
e.position()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Expr::FloatConstant(_, pos) => *pos,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(e, _, _) => e.position(),
|
Expr::Index(e, _, _) => e.position(),
|
||||||
|
|
||||||
@ -207,14 +210,22 @@ impl Expr {
|
|||||||
pub fn is_constant(&self) -> bool {
|
pub fn is_constant(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Expr::IntegerConstant(_, _)
|
Expr::IntegerConstant(_, _)
|
||||||
| Expr::FloatConstant(_, _)
|
|
||||||
| Expr::Identifier(_, _)
|
|
||||||
| Expr::CharConstant(_, _)
|
| Expr::CharConstant(_, _)
|
||||||
| Expr::StringConstant(_, _)
|
| Expr::StringConstant(_, _)
|
||||||
| Expr::True(_)
|
| Expr::True(_)
|
||||||
| Expr::False(_)
|
| Expr::False(_)
|
||||||
| Expr::Unit(_) => true,
|
| Expr::Unit(_) => true,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Expr::FloatConstant(_, _) => true,
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_identifier(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Expr::Identifier(_, _) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,6 +234,7 @@ impl Expr {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
IntegerConstant(i64),
|
IntegerConstant(i64),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
FloatConstant(f64),
|
FloatConstant(f64),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
CharConstant(char),
|
CharConstant(char),
|
||||||
@ -293,6 +305,7 @@ impl Token {
|
|||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
IntegerConstant(ref i) => i.to_string().into(),
|
IntegerConstant(ref i) => i.to_string().into(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
FloatConstant(ref f) => f.to_string().into(),
|
FloatConstant(ref f) => f.to_string().into(),
|
||||||
Identifier(ref s) => s.into(),
|
Identifier(ref s) => s.into(),
|
||||||
CharConstant(ref c) => c.to_string().into(),
|
CharConstant(ref c) => c.to_string().into(),
|
||||||
@ -622,6 +635,7 @@ impl<'a> TokenIterator<'a> {
|
|||||||
self.char_stream.next();
|
self.char_stream.next();
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
'.' => {
|
'.' => {
|
||||||
result.push(next_char);
|
result.push(next_char);
|
||||||
self.char_stream.next();
|
self.char_stream.next();
|
||||||
@ -707,6 +721,17 @@ impl<'a> TokenIterator<'a> {
|
|||||||
} else {
|
} else {
|
||||||
let out: String = result.iter().filter(|&&c| c != '_').collect();
|
let out: String = result.iter().filter(|&&c| c != '_').collect();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
return Some((
|
||||||
|
i64::from_str(&out)
|
||||||
|
.map(Token::IntegerConstant)
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
Token::LexError(LERR::MalformedNumber(result.iter().collect()))
|
||||||
|
}),
|
||||||
|
pos,
|
||||||
|
));
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
return Some((
|
return Some((
|
||||||
i64::from_str(&out)
|
i64::from_str(&out)
|
||||||
.map(Token::IntegerConstant)
|
.map(Token::IntegerConstant)
|
||||||
@ -1190,6 +1215,7 @@ fn parse_index_expr<'a>(
|
|||||||
*pos,
|
*pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(_, pos) => {
|
Expr::FloatConstant(_, pos) => {
|
||||||
return Err(ParseError::new(
|
return Err(ParseError::new(
|
||||||
PERR::MalformedIndexExpr("Array access expects integer index, not a float".into()),
|
PERR::MalformedIndexExpr("Array access expects integer index, not a float".into()),
|
||||||
@ -1332,8 +1358,10 @@ fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pa
|
|||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut root_expr = match token {
|
let mut root_expr = match token {
|
||||||
Some((Token::IntegerConstant(x), pos)) => Ok(Expr::IntegerConstant(x, pos)),
|
#[cfg(not(feature = "no_float"))]
|
||||||
Some((Token::FloatConstant(x), pos)) => Ok(Expr::FloatConstant(x, pos)),
|
Some((Token::FloatConstant(x), pos)) => Ok(Expr::FloatConstant(x, pos)),
|
||||||
|
|
||||||
|
Some((Token::IntegerConstant(x), pos)) => Ok(Expr::IntegerConstant(x, pos)),
|
||||||
Some((Token::CharConstant(c), pos)) => Ok(Expr::CharConstant(c, pos)),
|
Some((Token::CharConstant(c), pos)) => Ok(Expr::CharConstant(c, pos)),
|
||||||
Some((Token::StringConst(s), pos)) => {
|
Some((Token::StringConst(s), pos)) => {
|
||||||
can_be_indexed = true;
|
can_be_indexed = true;
|
||||||
@ -1383,14 +1411,31 @@ fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pars
|
|||||||
|
|
||||||
match parse_unary(input) {
|
match parse_unary(input) {
|
||||||
// Negative integer
|
// Negative integer
|
||||||
Ok(Expr::IntegerConstant(i, pos)) => Ok(i
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Ok(Expr::IntegerConstant(i, _)) => Ok(i
|
||||||
.checked_neg()
|
.checked_neg()
|
||||||
.map(|x| Expr::IntegerConstant(x, pos))
|
.map(|x| Expr::IntegerConstant(x, pos))
|
||||||
.unwrap_or_else(|| Expr::FloatConstant(-(i as f64), pos))),
|
.unwrap_or_else(|| Expr::FloatConstant(-(i as f64), pos))),
|
||||||
|
|
||||||
|
// Negative integer
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
Ok(Expr::IntegerConstant(i, _)) => i
|
||||||
|
.checked_neg()
|
||||||
|
.map(|x| Expr::IntegerConstant(x, pos))
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ParseError::new(
|
||||||
|
PERR::BadInput(LERR::MalformedNumber(format!("-{}", i)).to_string()),
|
||||||
|
pos,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
// Negative float
|
// Negative float
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
Ok(Expr::FloatConstant(f, pos)) => Ok(Expr::FloatConstant(-f, pos)),
|
Ok(Expr::FloatConstant(f, pos)) => Ok(Expr::FloatConstant(-f, pos)),
|
||||||
|
|
||||||
// Call negative function
|
// Call negative function
|
||||||
Ok(expr) => Ok(Expr::FunctionCall("-".into(), vec![expr], None, pos)),
|
Ok(expr) => Ok(Expr::FunctionCall("-".into(), vec![expr], None, pos)),
|
||||||
|
|
||||||
err @ Err(_) => err,
|
err @ Err(_) => err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1418,10 +1463,9 @@ fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result<Expr, ParseEr
|
|||||||
Expr::Identifier(_, pos) => (true, *pos),
|
Expr::Identifier(_, pos) => (true, *pos),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(idx_lhs, _, _) => match idx_lhs.as_ref() {
|
Expr::Index(idx_lhs, _, _) if idx_lhs.is_identifier() => (true, idx_lhs.position()),
|
||||||
Expr::Identifier(_, _) => (true, idx_lhs.position()),
|
#[cfg(not(feature = "no_index"))]
|
||||||
_ => (false, idx_lhs.position()),
|
Expr::Index(idx_lhs, _, _) => (false, idx_lhs.position()),
|
||||||
},
|
|
||||||
|
|
||||||
Expr::Dot(dot_lhs, dot_rhs, _) => match dot_lhs.as_ref() {
|
Expr::Dot(dot_lhs, dot_rhs, _) => match dot_lhs.as_ref() {
|
||||||
Expr::Identifier(_, _) => valid_assignment_chain(dot_rhs),
|
Expr::Identifier(_, _) => valid_assignment_chain(dot_rhs),
|
||||||
@ -1460,29 +1504,6 @@ fn parse_op_assignment(
|
|||||||
Expr::FunctionCall(function.into(), vec![lhs_copy, rhs], None, pos),
|
Expr::FunctionCall(function.into(), vec![lhs_copy, rhs], None, pos),
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
const LHS_VALUE: &'static str = "@LHS_VALUE@";
|
|
||||||
|
|
||||||
let lhs_pos = lhs.position();
|
|
||||||
|
|
||||||
Ok(Expr::Block(
|
|
||||||
Box::new(Stmt::Block(vec![
|
|
||||||
Stmt::Let(LHS_VALUE.to_string(), Some(Box::new(lhs)), lhs_pos),
|
|
||||||
Stmt::Expr(Box::new(parse_assignment(
|
|
||||||
lhs,
|
|
||||||
Expr::FunctionCall(
|
|
||||||
function.into(),
|
|
||||||
vec![Expr::Identifier(LHS_VALUE.to_string(), lhs_pos), rhs],
|
|
||||||
None,
|
|
||||||
pos,
|
|
||||||
),
|
|
||||||
pos,
|
|
||||||
)?)),
|
|
||||||
])),
|
|
||||||
pos,
|
|
||||||
))
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_binary_op<'a>(
|
fn parse_binary_op<'a>(
|
||||||
@ -1532,6 +1553,7 @@ fn parse_binary_op<'a>(
|
|||||||
Token::Equals => parse_assignment(current_lhs, rhs, pos)?,
|
Token::Equals => parse_assignment(current_lhs, rhs, pos)?,
|
||||||
Token::PlusAssign => parse_op_assignment("+", current_lhs, rhs, pos)?,
|
Token::PlusAssign => parse_op_assignment("+", current_lhs, rhs, pos)?,
|
||||||
Token::MinusAssign => parse_op_assignment("-", current_lhs, rhs, pos)?,
|
Token::MinusAssign => parse_op_assignment("-", current_lhs, rhs, pos)?,
|
||||||
|
|
||||||
Token::Period => Expr::Dot(Box::new(current_lhs), Box::new(rhs), pos),
|
Token::Period => Expr::Dot(Box::new(current_lhs), Box::new(rhs), pos),
|
||||||
|
|
||||||
// Comparison operators default to false when passed invalid operands
|
// Comparison operators default to false when passed invalid operands
|
||||||
|
Loading…
Reference in New Issue
Block a user