Move default comparisons into builtin.
This commit is contained in:
parent
5b1f80f5ce
commit
7262d63909
@ -71,6 +71,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { field: 1 } }
|
/// fn new() -> Self { Self { field: 1 } }
|
||||||
|
///
|
||||||
/// fn update(&mut self, offset: i64) { self.field += offset; }
|
/// fn update(&mut self, offset: i64) { self.field += offset; }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -170,6 +171,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { field: 1 } }
|
/// fn new() -> Self { Self { field: 1 } }
|
||||||
|
///
|
||||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||||
/// fn get_field(&mut self) -> i64 { self.field }
|
/// fn get_field(&mut self) -> i64 { self.field }
|
||||||
/// }
|
/// }
|
||||||
@ -216,8 +218,9 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { field: 1 } }
|
/// fn new() -> Self { Self { field: 1 } }
|
||||||
|
///
|
||||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||||
/// fn get_field(&mut self) -> RhaiResult {
|
/// fn get_field(&mut self) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
/// Ok(self.field.into())
|
/// Ok(self.field.into())
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
@ -258,6 +261,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { field: 1 } }
|
/// fn new() -> Self { Self { field: 1 } }
|
||||||
|
///
|
||||||
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
|
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -305,6 +309,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { field: 1 } }
|
/// fn new() -> Self { Self { field: 1 } }
|
||||||
|
///
|
||||||
/// fn set_field(&mut self, new_val: i64) -> Result<(), Box<EvalAltResult>> {
|
/// fn set_field(&mut self, new_val: i64) -> Result<(), Box<EvalAltResult>> {
|
||||||
/// self.field = new_val;
|
/// self.field = new_val;
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
@ -356,8 +361,10 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { field: 1 } }
|
/// fn new() -> Self { Self { field: 1 } }
|
||||||
|
///
|
||||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||||
/// fn get_field(&mut self) -> i64 { self.field }
|
/// fn get_field(&mut self) -> i64 { self.field }
|
||||||
|
///
|
||||||
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
|
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -407,6 +414,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
||||||
|
///
|
||||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||||
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
|
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
|
||||||
/// }
|
/// }
|
||||||
@ -473,8 +481,9 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
||||||
|
///
|
||||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||||
/// fn get_field(&mut self, index: i64) -> RhaiResult {
|
/// fn get_field(&mut self, index: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
/// Ok(self.fields[index as usize].into())
|
/// Ok(self.fields[index as usize].into())
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
@ -535,6 +544,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
||||||
|
///
|
||||||
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
|
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -601,6 +611,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
||||||
|
///
|
||||||
/// fn set_field(&mut self, index: i64, value: i64) -> Result<(), Box<EvalAltResult>> {
|
/// fn set_field(&mut self, index: i64, value: i64) -> Result<(), Box<EvalAltResult>> {
|
||||||
/// self.fields[index as usize] = value;
|
/// self.fields[index as usize] = value;
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
@ -672,8 +683,10 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// impl TestStruct {
|
/// impl TestStruct {
|
||||||
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
||||||
|
///
|
||||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||||
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
|
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
|
||||||
|
///
|
||||||
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
|
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
@ -14,6 +14,29 @@ use rust_decimal::Decimal;
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
|
|
||||||
|
/// Is the type a numeric type?
|
||||||
|
fn is_numeric(type_id: TypeId) -> bool {
|
||||||
|
let result = type_id == TypeId::of::<u8>()
|
||||||
|
|| type_id == TypeId::of::<u16>()
|
||||||
|
|| type_id == TypeId::of::<u32>()
|
||||||
|
|| type_id == TypeId::of::<u64>()
|
||||||
|
|| type_id == TypeId::of::<i8>()
|
||||||
|
|| type_id == TypeId::of::<i16>()
|
||||||
|
|| type_id == TypeId::of::<i32>()
|
||||||
|
|| type_id == TypeId::of::<i64>();
|
||||||
|
|
||||||
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
||||||
|
let result = result || type_id == TypeId::of::<u128>() || type_id == TypeId::of::<i128>();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
let result = result || type_id == TypeId::of::<f32>() || type_id == TypeId::of::<f64>();
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
let result = result || type_id == TypeId::of::<rust_decimal::Decimal>();
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// Build in common binary operator implementations to avoid the cost of calling a registered function.
|
/// Build in common binary operator implementations to avoid the cost of calling a registered function.
|
||||||
pub fn get_builtin_binary_op_fn(
|
pub fn get_builtin_binary_op_fn(
|
||||||
op: &str,
|
op: &str,
|
||||||
@ -23,15 +46,26 @@ pub fn get_builtin_binary_op_fn(
|
|||||||
let type1 = x.type_id();
|
let type1 = x.type_id();
|
||||||
let type2 = y.type_id();
|
let type2 = y.type_id();
|
||||||
|
|
||||||
if x.is_variant() || y.is_variant() {
|
|
||||||
// One of the operands is a custom type, so it is never built-in
|
// One of the operands is a custom type, so it is never built-in
|
||||||
|
if x.is_variant() || y.is_variant() {
|
||||||
|
if is_numeric(type1) && is_numeric(type2) {
|
||||||
|
// Disallow comparisons between different numeric types
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the types are not the same, default to not compare
|
||||||
|
if type1 != type2 {
|
||||||
return match op {
|
return match op {
|
||||||
"!=" if type1 != type2 => Some(|_, _| Ok(Dynamic::TRUE)),
|
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
|
||||||
"==" | ">" | ">=" | "<" | "<=" if type1 != type2 => Some(|_, _| Ok(Dynamic::FALSE)),
|
"==" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disallow comparisons between the same type
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let types_pair = (type1, type2);
|
let types_pair = (type1, type2);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
@ -1,11 +1,11 @@
|
|||||||
//! Implement function-calling mechanism for [`Engine`].
|
//! Implement function-calling mechanism for [`Engine`].
|
||||||
|
|
||||||
use crate::builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL,
|
Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL,
|
||||||
KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
MAX_DYNAMIC_PARAMETERS,
|
MAX_DYNAMIC_PARAMETERS,
|
||||||
};
|
};
|
||||||
|
use crate::fn_builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
||||||
use crate::fn_native::{FnAny, FnCallArgs};
|
use crate::fn_native::{FnAny, FnCallArgs};
|
||||||
use crate::module::NamespaceRef;
|
use crate::module::NamespaceRef;
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
@ -243,8 +243,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Stop when all permutations are exhausted
|
// Stop when all permutations are exhausted
|
||||||
None if bitmask >= max_bitmask => {
|
None if bitmask >= max_bitmask => {
|
||||||
return if num_args != 2 || args[0].is_variant() || args[1].is_variant()
|
return if num_args != 2 {
|
||||||
{
|
|
||||||
None
|
None
|
||||||
} else if !is_op_assignment {
|
} else if !is_op_assignment {
|
||||||
if let Some(f) =
|
if let Some(f) =
|
||||||
|
@ -52,7 +52,7 @@ pub trait RegisterResultFn<FN, ARGS> {
|
|||||||
/// use rhai::{Engine, Dynamic, RegisterResultFn, EvalAltResult};
|
/// use rhai::{Engine, Dynamic, RegisterResultFn, EvalAltResult};
|
||||||
///
|
///
|
||||||
/// // Normal function
|
/// // Normal function
|
||||||
/// fn div(x: i64, y: i64) -> RhaiResult {
|
/// fn div(x: i64, y: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
/// if y == 0 {
|
/// if y == 0 {
|
||||||
/// // '.into()' automatically converts to 'Box<EvalAltResult::ErrorRuntime>'
|
/// // '.into()' automatically converts to 'Box<EvalAltResult::ErrorRuntime>'
|
||||||
/// Err("division by zero!".into())
|
/// Err("division by zero!".into())
|
||||||
|
@ -64,12 +64,12 @@ extern crate alloc;
|
|||||||
// Internal modules
|
// Internal modules
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod builtin;
|
|
||||||
mod dynamic;
|
mod dynamic;
|
||||||
mod engine;
|
mod engine;
|
||||||
mod engine_api;
|
mod engine_api;
|
||||||
mod engine_settings;
|
mod engine_settings;
|
||||||
mod fn_args;
|
mod fn_args;
|
||||||
|
mod fn_builtin;
|
||||||
mod fn_call;
|
mod fn_call;
|
||||||
mod fn_func;
|
mod fn_func;
|
||||||
mod fn_native;
|
mod fn_native;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! Module implementing the [`AST`] optimizer.
|
//! Module implementing the [`AST`] optimizer.
|
||||||
|
|
||||||
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
||||||
use crate::builtin::get_builtin_binary_op_fn;
|
|
||||||
use crate::dynamic::AccessMode;
|
use crate::dynamic::AccessMode;
|
||||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||||
|
use crate::fn_builtin::get_builtin_binary_op_fn;
|
||||||
use crate::parser::map_dynamic_to_expr;
|
use crate::parser::map_dynamic_to_expr;
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::builtin::get_builtin_binary_op_fn;
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
|
||||||
@ -40,8 +39,6 @@ macro_rules! reg_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def_package!(crate:LogicPackage:"Logical operators.", lib, {
|
def_package!(crate:LogicPackage:"Logical operators.", lib, {
|
||||||
combine_with_exported_module!(lib, "logic", logic_functions);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
@ -97,66 +94,6 @@ gen_cmp_functions!(float => f64);
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
gen_cmp_functions!(decimal => Decimal);
|
gen_cmp_functions!(decimal => Decimal);
|
||||||
|
|
||||||
#[export_module]
|
|
||||||
mod logic_functions {
|
|
||||||
fn is_numeric(type_id: TypeId) -> bool {
|
|
||||||
let result = type_id == TypeId::of::<u8>()
|
|
||||||
|| type_id == TypeId::of::<u16>()
|
|
||||||
|| type_id == TypeId::of::<u32>()
|
|
||||||
|| type_id == TypeId::of::<u64>()
|
|
||||||
|| type_id == TypeId::of::<i8>()
|
|
||||||
|| type_id == TypeId::of::<i16>()
|
|
||||||
|| type_id == TypeId::of::<i32>()
|
|
||||||
|| type_id == TypeId::of::<i64>();
|
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
|
||||||
let result = result || type_id == TypeId::of::<u128>() || type_id == TypeId::of::<i128>();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
let result = result || type_id == TypeId::of::<f32>() || type_id == TypeId::of::<f64>();
|
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
let result = result || type_id == TypeId::of::<rust_decimal::Decimal>();
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rhai_fn(
|
|
||||||
name = "==",
|
|
||||||
name = "!=",
|
|
||||||
name = ">",
|
|
||||||
name = ">=",
|
|
||||||
name = "<",
|
|
||||||
name = "<=",
|
|
||||||
return_raw,
|
|
||||||
pure
|
|
||||||
)]
|
|
||||||
pub fn cmp(
|
|
||||||
ctx: NativeCallContext,
|
|
||||||
x: &mut Dynamic,
|
|
||||||
mut y: Dynamic,
|
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
let type_x = x.type_id();
|
|
||||||
let type_y = y.type_id();
|
|
||||||
|
|
||||||
if type_x != type_y && is_numeric(type_x) && is_numeric(type_y) {
|
|
||||||
// Disallow comparisons between different number types
|
|
||||||
} else if let Some(f) = get_builtin_binary_op_fn(ctx.fn_name(), x, &y) {
|
|
||||||
return f(ctx, &mut [x, &mut y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
|
||||||
format!(
|
|
||||||
"{} ({}, {})",
|
|
||||||
ctx.fn_name(),
|
|
||||||
ctx.engine().map_type_name(x.type_name()),
|
|
||||||
ctx.engine().map_type_name(y.type_name())
|
|
||||||
),
|
|
||||||
Position::NONE,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod f32_functions {
|
mod f32_functions {
|
||||||
|
Loading…
Reference in New Issue
Block a user