Fix range precedences and add comparison operators.

This commit is contained in:
Stephen Chung 2021-12-15 14:18:03 +08:00
parent eda80488d5
commit 59a9ff0b0f
3 changed files with 78 additions and 28 deletions

View File

@ -2,7 +2,9 @@
use super::call::FnCallArgs; use super::call::FnCallArgs;
use crate::engine::OP_CONTAINS; use crate::engine::OP_CONTAINS;
use crate::{Dynamic, ImmutableString, NativeCallContext, RhaiResult, INT}; use crate::{
Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, NativeCallContext, RhaiResult, INT,
};
use std::any::TypeId; use std::any::TypeId;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -55,24 +57,6 @@ 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();
// One of the operands is a custom type, so it is never built-in
if x.is_variant() || y.is_variant() {
return if is_numeric(type1) && is_numeric(type2) {
// Disallow comparisons between different numeric types
None
} else if type1 != type2 {
// If the types are not the same, default to not compare
match op {
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
"==" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
_ => None,
}
} else {
// Disallow comparisons between the same type
None
};
}
let types_pair = (type1, type2); let types_pair = (type1, type2);
macro_rules! impl_op { macro_rules! impl_op {
@ -301,6 +285,64 @@ pub fn get_builtin_binary_op_fn(
}; };
} }
// Non-compatible ranges
if types_pair
== (
TypeId::of::<ExclusiveRange>(),
TypeId::of::<InclusiveRange>(),
)
|| types_pair
== (
TypeId::of::<InclusiveRange>(),
TypeId::of::<ExclusiveRange>(),
)
{
return match op {
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
"==" => Some(|_, _| Ok(Dynamic::FALSE)),
_ => None,
};
}
// Handle ranges here because ranges are implemented as custom type
if type1 == TypeId::of::<ExclusiveRange>() {
if type1 == type2 {
return match op {
"==" => Some(impl_op!(ExclusiveRange == ExclusiveRange)),
"!=" => Some(impl_op!(ExclusiveRange != ExclusiveRange)),
_ => None,
};
}
}
if type1 == TypeId::of::<InclusiveRange>() {
if type1 == type2 {
return match op {
"==" => Some(impl_op!(InclusiveRange == InclusiveRange)),
"!=" => Some(impl_op!(InclusiveRange != InclusiveRange)),
_ => None,
};
}
}
// One of the operands is a custom type, so it is never built-in
if x.is_variant() || y.is_variant() {
return if is_numeric(type1) && is_numeric(type2) {
// Disallow comparisons between different numeric types
None
} else if type1 != type2 {
// If the types are not the same, default to not compare
match op {
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
"==" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
_ => None,
}
} else {
// Disallow comparisons between the same type
None
};
}
// Default comparison operators for different types // Default comparison operators for different types
if type2 != type1 { if type2 != type1 {
return match op { return match op {

View File

@ -530,15 +530,15 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
#[export_module] #[export_module]
mod range_functions { mod range_functions {
#[rhai_fn(get = "start", name = "start", pure)] #[rhai_fn(get = "start", name = "start", pure)]
pub fn range_start(range: &mut ExclusiveRange) -> INT { pub fn start(range: &mut ExclusiveRange) -> INT {
range.start range.start
} }
#[rhai_fn(get = "end", name = "end", pure)] #[rhai_fn(get = "end", name = "end", pure)]
pub fn range_end(range: &mut ExclusiveRange) -> INT { pub fn end(range: &mut ExclusiveRange) -> INT {
range.end range.end
} }
#[rhai_fn(name = "contains", pure)] #[rhai_fn(name = "contains", pure)]
pub fn range_contains(range: &mut ExclusiveRange, value: INT) -> bool { pub fn contains(range: &mut ExclusiveRange, value: INT) -> bool {
range.contains(&value) range.contains(&value)
} }
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)] #[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
@ -546,20 +546,28 @@ mod range_functions {
let _range = range; let _range = range;
false false
} }
#[rhai_fn(get = "is_empty", name = "is_empty", pure)]
pub fn is_empty(range: &mut ExclusiveRange) -> bool {
range.is_empty()
}
#[rhai_fn(get = "start", name = "start", pure)] #[rhai_fn(get = "start", name = "start", pure)]
pub fn range_inclusive_start(range: &mut InclusiveRange) -> INT { pub fn start_inclusive(range: &mut InclusiveRange) -> INT {
*range.start() *range.start()
} }
#[rhai_fn(get = "end", name = "end", pure)] #[rhai_fn(get = "end", name = "end", pure)]
pub fn range_inclusive_end(range: &mut InclusiveRange) -> INT { pub fn end_inclusive(range: &mut InclusiveRange) -> INT {
*range.end() *range.end()
} }
#[rhai_fn(name = "contains", pure)] #[rhai_fn(name = "contains", pure)]
pub fn range_inclusive_contains(range: &mut InclusiveRange, value: INT) -> bool { pub fn contains_inclusive(range: &mut InclusiveRange, value: INT) -> bool {
range.contains(&value) range.contains(&value)
} }
#[rhai_fn(get = "is_empty", name = "is_empty", pure)]
pub fn is_empty_inclusive(range: &mut InclusiveRange) -> bool {
range.is_empty()
}
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)] #[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
pub fn range_inclusive_is_inclusive(range: &mut InclusiveRange) -> bool { pub fn is_inclusive_inclusive(range: &mut InclusiveRange) -> bool {
let _range = range; let _range = range;
true true
} }

View File

@ -878,8 +878,6 @@ impl Token {
| LeftShiftAssign | RightShiftAssign | AndAssign | OrAssign | XOrAssign | LeftShiftAssign | RightShiftAssign | AndAssign | OrAssign | XOrAssign
| ModuloAssign => 0, | ModuloAssign => 0,
ExclusiveRange | InclusiveRange => 10,
Or | XOr | Pipe => 30, Or | XOr | Pipe => 30,
And | Ampersand => 60, And | Ampersand => 60,
@ -890,6 +888,8 @@ impl Token {
LessThan | LessThanEqualsTo | GreaterThan | GreaterThanEqualsTo => 130, LessThan | LessThanEqualsTo | GreaterThan | GreaterThanEqualsTo => 130,
ExclusiveRange | InclusiveRange => 140,
Plus | Minus => 150, Plus | Minus => 150,
Divide | Multiply | Modulo => 180, Divide | Multiply | Modulo => 180,