From 59a9ff0b0fc7d11e4650e86676e1d21a3ad57834 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 15 Dec 2021 14:18:03 +0800 Subject: [PATCH] Fix range precedences and add comparison operators. --- src/func/builtin.rs | 80 +++++++++++++++++++++++++++++--------- src/packages/iter_basic.rs | 22 +++++++---- src/tokenizer.rs | 4 +- 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/func/builtin.rs b/src/func/builtin.rs index e2bb1c74..a257e2fd 100644 --- a/src/func/builtin.rs +++ b/src/func/builtin.rs @@ -2,7 +2,9 @@ use super::call::FnCallArgs; 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; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -55,24 +57,6 @@ pub fn get_builtin_binary_op_fn( let type1 = x.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); macro_rules! impl_op { @@ -301,6 +285,64 @@ pub fn get_builtin_binary_op_fn( }; } + // Non-compatible ranges + if types_pair + == ( + TypeId::of::(), + TypeId::of::(), + ) + || types_pair + == ( + TypeId::of::(), + TypeId::of::(), + ) + { + 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::() { + if type1 == type2 { + return match op { + "==" => Some(impl_op!(ExclusiveRange == ExclusiveRange)), + "!=" => Some(impl_op!(ExclusiveRange != ExclusiveRange)), + _ => None, + }; + } + } + + if type1 == TypeId::of::() { + 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 if type2 != type1 { return match op { diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 1b4e1e97..c5a0941b 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -530,15 +530,15 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { #[export_module] mod range_functions { #[rhai_fn(get = "start", name = "start", pure)] - pub fn range_start(range: &mut ExclusiveRange) -> INT { + pub fn start(range: &mut ExclusiveRange) -> INT { range.start } #[rhai_fn(get = "end", name = "end", pure)] - pub fn range_end(range: &mut ExclusiveRange) -> INT { + pub fn end(range: &mut ExclusiveRange) -> INT { range.end } #[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) } #[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)] @@ -546,20 +546,28 @@ mod range_functions { let _range = range; 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)] - pub fn range_inclusive_start(range: &mut InclusiveRange) -> INT { + pub fn start_inclusive(range: &mut InclusiveRange) -> INT { *range.start() } #[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() } #[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) } + #[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)] - pub fn range_inclusive_is_inclusive(range: &mut InclusiveRange) -> bool { + pub fn is_inclusive_inclusive(range: &mut InclusiveRange) -> bool { let _range = range; true } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 9e93f582..4a3ab161 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -878,8 +878,6 @@ impl Token { | LeftShiftAssign | RightShiftAssign | AndAssign | OrAssign | XOrAssign | ModuloAssign => 0, - ExclusiveRange | InclusiveRange => 10, - Or | XOr | Pipe => 30, And | Ampersand => 60, @@ -890,6 +888,8 @@ impl Token { LessThan | LessThanEqualsTo | GreaterThan | GreaterThanEqualsTo => 130, + ExclusiveRange | InclusiveRange => 140, + Plus | Minus => 150, Divide | Multiply | Modulo => 180,