commit
60069424c3
@ -4,6 +4,8 @@ Rhai Release Notes
|
||||
Version 0.20.3
|
||||
==============
|
||||
|
||||
This version adds support to index into an integer number, treating it as a bit-field.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
@ -13,7 +15,7 @@ Bug fixes
|
||||
Breaking changes
|
||||
----------------
|
||||
|
||||
* To keep the API consistent, strings are no longer iterable by default. Use the `chars` method to iterator the characters in a string.
|
||||
* To keep the API consistent, strings are no longer iterable by default. Use the `chars` method to iterate through the characters in a string.
|
||||
* `Dynamic::take_string` and `Dynamic::take_immutable_string` are renamed to `Dynamic::as_string` and `Dynamic::as_immutable_string` respectively.
|
||||
|
||||
New features
|
||||
|
@ -20,7 +20,7 @@ smallvec = { version = "1.6", default-features = false, features = ["union"] }
|
||||
ahash = { version = "0.7", default-features = false }
|
||||
num-traits = { version = "0.2", default-features = false }
|
||||
smartstring = { version = "0.2.6", default-features = false }
|
||||
rhai_codegen = { version = "0.4.0", path = "codegen", default-features = false }
|
||||
rhai_codegen = { version = ">=0.4.0", path = "codegen", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["smartstring/std", "ahash/std", "num-traits/std"] # remove 'smartstring/std' when smartstring is updated to support no-std
|
||||
|
@ -38,7 +38,7 @@ Standard features
|
||||
* Freely pass Rust values into a script as [variables](https://rhai.rs/book/language/variables.html)/[constants](https://rhai.rs/book/language/constants.html) via an external [`Scope`](https://rhai.rs/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait. Or tap directly into the [variable resolution process](https://rhai.rs/book/engine/var.html).
|
||||
* Built-in support for most common [data types](https://rhai.rs/book/language/values-and-types.html) including booleans, [integers](https://rhai.rs/book/language/numbers.html), [floating-point numbers](https://rhai.rs/book/language/numbers.html) (including [`Decimal`](https://crates.io/crates/rust_decimal)), [strings](https://rhai.rs/book/language/strings-chars.html), [Unicode characters](https://rhai.rs/book/language/strings-chars.html), [arrays](https://rhai.rs/book/language/arrays.html) and [object maps](https://rhai.rs/book/language/object-maps.html).
|
||||
* Easily [call a script-defined function](https://rhai.rs/book/engine/call-fn.html) from Rust.
|
||||
* Relatively little `unsafe` code (yes there are some for performance reasons), and `unsafe` code is only used for type casting, never to get around the borrow checker.
|
||||
* Relatively little `unsafe` code (yes there are some for performance reasons).
|
||||
* Few dependencies - currently only [`smallvec`](https://crates.io/crates/smallvec), [`num-traits`](https://crates.io/crates/num-traits), [`ahash`](https://crates.io/crates/ahash) and [`smartstring`](https://crates.io/crates/smartstring).
|
||||
* Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature).
|
||||
* Compile once to [AST](https://rhai.rs/book/engine/compile.html) form for repeated evaluations.
|
||||
|
@ -1498,12 +1498,12 @@ impl fmt::Debug for FnCallHashes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(script) = self.script {
|
||||
if script == self.native {
|
||||
write!(f, "({}=={})", script, self.native)
|
||||
fmt::Debug::fmt(&self.native, f)
|
||||
} else {
|
||||
write!(f, "({}, {})", script, self.native)
|
||||
}
|
||||
} else {
|
||||
write!(f, "{}", self.native)
|
||||
write!(f, "{} (native only)", self.native)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ impl Imports {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find_map(|(i, key)| if *key == name { Some(i) } else { None })
|
||||
.find_map(|(i, key)| if key == name { Some(i) } else { None })
|
||||
}
|
||||
/// Push an imported [modules][Module] onto the stack.
|
||||
#[inline(always)]
|
||||
|
@ -76,75 +76,55 @@ pub fn get_builtin_binary_op_fn(
|
||||
let types_pair = (type1, type2);
|
||||
|
||||
macro_rules! impl_op {
|
||||
($xx:ident $op:tt $yy:ident) => {
|
||||
Some(|_, args| {
|
||||
($xx:ident $op:tt $yy:ident) => { |_, args| {
|
||||
let x = &*args[0].read_lock::<$xx>().expect(BUILTIN);
|
||||
let y = &*args[1].read_lock::<$yy>().expect(BUILTIN);
|
||||
Ok((x $op y).into())
|
||||
})
|
||||
};
|
||||
($xx:ident . $func:ident ( $yy:ty )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($xx:ident . $func:ident ( $yy:ty )) => { |_, args| {
|
||||
let x = &*args[0].read_lock::<$xx>().expect(BUILTIN);
|
||||
let y = &*args[1].read_lock::<$yy>().expect(BUILTIN);
|
||||
Ok(x.$func(y).into())
|
||||
})
|
||||
};
|
||||
($xx:ident . $func:ident ( $yy:ident . $yyy:ident () )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($xx:ident . $func:ident ( $yy:ident . $yyy:ident () )) => { |_, args| {
|
||||
let x = &*args[0].read_lock::<$xx>().expect(BUILTIN);
|
||||
let y = &*args[1].read_lock::<$yy>().expect(BUILTIN);
|
||||
Ok(x.$func(y.$yyy()).into())
|
||||
})
|
||||
};
|
||||
($func:ident ( $op:tt )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($func:ident ( $op:tt )) => { |_, args| {
|
||||
let (x, y) = $func(args);
|
||||
Ok((x $op y).into())
|
||||
})
|
||||
};
|
||||
($base:ty => $xx:ident $op:tt $yy:ident) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($base:ty => $xx:ident $op:tt $yy:ident) => { |_, args| {
|
||||
let x = args[0].$xx().expect(BUILTIN) as $base;
|
||||
let y = args[1].$yy().expect(BUILTIN) as $base;
|
||||
Ok((x $op y).into())
|
||||
})
|
||||
};
|
||||
($base:ty => $xx:ident . $func:ident ( $yy:ident as $yyy:ty)) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($base:ty => $xx:ident . $func:ident ( $yy:ident as $yyy:ty)) => { |_, args| {
|
||||
let x = args[0].$xx().expect(BUILTIN) as $base;
|
||||
let y = args[1].$yy().expect(BUILTIN) as $base;
|
||||
Ok(x.$func(y as $yyy).into())
|
||||
})
|
||||
};
|
||||
($base:ty => $func:ident ( $xx:ident, $yy:ident )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($base:ty => $func:ident ( $xx:ident, $yy:ident )) => { |_, args| {
|
||||
let x = args[0].$xx().expect(BUILTIN) as $base;
|
||||
let y = args[1].$yy().expect(BUILTIN) as $base;
|
||||
$func(x, y).map(Into::<Dynamic>::into)
|
||||
})
|
||||
};
|
||||
(from $base:ty => $xx:ident $op:tt $yy:ident) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
(from $base:ty => $xx:ident $op:tt $yy:ident) => { |_, args| {
|
||||
let x = <$base>::from(args[0].$xx().expect(BUILTIN));
|
||||
let y = <$base>::from(args[1].$yy().expect(BUILTIN));
|
||||
Ok((x $op y).into())
|
||||
})
|
||||
};
|
||||
(from $base:ty => $xx:ident . $func:ident ( $yy:ident )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
(from $base:ty => $xx:ident . $func:ident ( $yy:ident )) => { |_, args| {
|
||||
let x = <$base>::from(args[0].$xx().expect(BUILTIN));
|
||||
let y = <$base>::from(args[1].$yy().expect(BUILTIN));
|
||||
Ok(x.$func(y).into())
|
||||
})
|
||||
};
|
||||
(from $base:ty => $func:ident ( $xx:ident, $yy:ident )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
(from $base:ty => $func:ident ( $xx:ident, $yy:ident )) => { |_, args| {
|
||||
let x = <$base>::from(args[0].$xx().expect(BUILTIN));
|
||||
let y = <$base>::from(args[1].$yy().expect(BUILTIN));
|
||||
$func(x, y).map(Into::<Dynamic>::into)
|
||||
})
|
||||
};
|
||||
} };
|
||||
}
|
||||
|
||||
macro_rules! impl_float {
|
||||
@ -152,18 +132,18 @@ pub fn get_builtin_binary_op_fn(
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if types_pair == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||
return match op {
|
||||
"+" => impl_op!(FLOAT => $xx + $yy),
|
||||
"-" => impl_op!(FLOAT => $xx - $yy),
|
||||
"*" => impl_op!(FLOAT => $xx * $yy),
|
||||
"/" => impl_op!(FLOAT => $xx / $yy),
|
||||
"%" => impl_op!(FLOAT => $xx % $yy),
|
||||
"**" => impl_op!(FLOAT => $xx.powf($yy as FLOAT)),
|
||||
"==" => impl_op!(FLOAT => $xx == $yy),
|
||||
"!=" => impl_op!(FLOAT => $xx != $yy),
|
||||
">" => impl_op!(FLOAT => $xx > $yy),
|
||||
">=" => impl_op!(FLOAT => $xx >= $yy),
|
||||
"<" => impl_op!(FLOAT => $xx < $yy),
|
||||
"<=" => impl_op!(FLOAT => $xx <= $yy),
|
||||
"+" => Some(impl_op!(FLOAT => $xx + $yy)),
|
||||
"-" => Some(impl_op!(FLOAT => $xx - $yy)),
|
||||
"*" => Some(impl_op!(FLOAT => $xx * $yy)),
|
||||
"/" => Some(impl_op!(FLOAT => $xx / $yy)),
|
||||
"%" => Some(impl_op!(FLOAT => $xx % $yy)),
|
||||
"**" => Some(impl_op!(FLOAT => $xx.powf($yy as FLOAT))),
|
||||
"==" => Some(impl_op!(FLOAT => $xx == $yy)),
|
||||
"!=" => Some(impl_op!(FLOAT => $xx != $yy)),
|
||||
">" => Some(impl_op!(FLOAT => $xx > $yy)),
|
||||
">=" => Some(impl_op!(FLOAT => $xx >= $yy)),
|
||||
"<" => Some(impl_op!(FLOAT => $xx < $yy)),
|
||||
"<=" => Some(impl_op!(FLOAT => $xx <= $yy)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -183,12 +163,12 @@ pub fn get_builtin_binary_op_fn(
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
match op {
|
||||
"+" => return impl_op!(from Decimal => add($xx, $yy)),
|
||||
"-" => return impl_op!(from Decimal => subtract($xx, $yy)),
|
||||
"*" => return impl_op!(from Decimal => multiply($xx, $yy)),
|
||||
"/" => return impl_op!(from Decimal => divide($xx, $yy)),
|
||||
"%" => return impl_op!(from Decimal => modulo($xx, $yy)),
|
||||
"**" => return impl_op!(from Decimal => power($xx, $yy)),
|
||||
"+" => return Some(impl_op!(from Decimal => add($xx, $yy))),
|
||||
"-" => return Some(impl_op!(from Decimal => subtract($xx, $yy))),
|
||||
"*" => return Some(impl_op!(from Decimal => multiply($xx, $yy))),
|
||||
"/" => return Some(impl_op!(from Decimal => divide($xx, $yy))),
|
||||
"%" => return Some(impl_op!(from Decimal => modulo($xx, $yy))),
|
||||
"**" => return Some(impl_op!(from Decimal => power($xx, $yy))),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
@ -197,22 +177,22 @@ pub fn get_builtin_binary_op_fn(
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
match op {
|
||||
"+" => return impl_op!(from Decimal => $xx + $yy),
|
||||
"-" => return impl_op!(from Decimal => $xx - $yy),
|
||||
"*" => return impl_op!(from Decimal => $xx * $yy),
|
||||
"/" => return impl_op!(from Decimal => $xx / $yy),
|
||||
"%" => return impl_op!(from Decimal => $xx % $yy),
|
||||
"**" => return impl_op!(from Decimal => $xx.powd($yy)),
|
||||
"+" => return Some(impl_op!(from Decimal => $xx + $yy)),
|
||||
"-" => return Some(impl_op!(from Decimal => $xx - $yy)),
|
||||
"*" => return Some(impl_op!(from Decimal => $xx * $yy)),
|
||||
"/" => return Some(impl_op!(from Decimal => $xx / $yy)),
|
||||
"%" => return Some(impl_op!(from Decimal => $xx % $yy)),
|
||||
"**" => return Some(impl_op!(from Decimal => $xx.powd($yy))),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
return match op {
|
||||
"==" => impl_op!(from Decimal => $xx == $yy),
|
||||
"!=" => impl_op!(from Decimal => $xx != $yy),
|
||||
">" => impl_op!(from Decimal => $xx > $yy),
|
||||
">=" => impl_op!(from Decimal => $xx >= $yy),
|
||||
"<" => impl_op!(from Decimal => $xx < $yy),
|
||||
"<=" => impl_op!(from Decimal => $xx <= $yy),
|
||||
"==" => Some(impl_op!(from Decimal => $xx == $yy)),
|
||||
"!=" => Some(impl_op!(from Decimal => $xx != $yy)),
|
||||
">" => Some(impl_op!(from Decimal => $xx > $yy)),
|
||||
">=" => Some(impl_op!(from Decimal => $xx >= $yy)),
|
||||
"<" => Some(impl_op!(from Decimal => $xx < $yy)),
|
||||
"<=" => Some(impl_op!(from Decimal => $xx <= $yy)),
|
||||
_ => None
|
||||
};
|
||||
}
|
||||
@ -241,12 +221,12 @@ pub fn get_builtin_binary_op_fn(
|
||||
let y = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||
Ok(format!("{}{}", x, y).into())
|
||||
}),
|
||||
"==" => impl_op!(get_s1s2(==)),
|
||||
"!=" => impl_op!(get_s1s2(!=)),
|
||||
">" => impl_op!(get_s1s2(>)),
|
||||
">=" => impl_op!(get_s1s2(>=)),
|
||||
"<" => impl_op!(get_s1s2(<)),
|
||||
"<=" => impl_op!(get_s1s2(<=)),
|
||||
"==" => Some(impl_op!(get_s1s2(==))),
|
||||
"!=" => Some(impl_op!(get_s1s2(!=))),
|
||||
">" => Some(impl_op!(get_s1s2(>))),
|
||||
">=" => Some(impl_op!(get_s1s2(>=))),
|
||||
"<" => Some(impl_op!(get_s1s2(<))),
|
||||
"<=" => Some(impl_op!(get_s1s2(<=))),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -273,12 +253,12 @@ pub fn get_builtin_binary_op_fn(
|
||||
let y = args[1].as_char().expect(BUILTIN);
|
||||
Ok((x - y).into())
|
||||
}),
|
||||
"==" => impl_op!(get_s1s2(==)),
|
||||
"!=" => impl_op!(get_s1s2(!=)),
|
||||
">" => impl_op!(get_s1s2(>)),
|
||||
">=" => impl_op!(get_s1s2(>=)),
|
||||
"<" => impl_op!(get_s1s2(<)),
|
||||
"<=" => impl_op!(get_s1s2(<=)),
|
||||
"==" => Some(impl_op!(get_s1s2(==))),
|
||||
"!=" => Some(impl_op!(get_s1s2(!=))),
|
||||
">" => Some(impl_op!(get_s1s2(>))),
|
||||
">=" => Some(impl_op!(get_s1s2(>=))),
|
||||
"<" => Some(impl_op!(get_s1s2(<))),
|
||||
"<=" => Some(impl_op!(get_s1s2(<=))),
|
||||
OP_CONTAINS => Some(|_, args| {
|
||||
let s = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||
let c = args[1].as_char().expect(BUILTIN);
|
||||
@ -294,7 +274,7 @@ pub fn get_builtin_binary_op_fn(
|
||||
use crate::Map;
|
||||
|
||||
return match op {
|
||||
OP_CONTAINS => impl_op!(Map.contains_key(ImmutableString.as_str())),
|
||||
OP_CONTAINS => Some(impl_op!(Map.contains_key(ImmutableString.as_str()))),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -316,69 +296,69 @@ pub fn get_builtin_binary_op_fn(
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
match op {
|
||||
"+" => return impl_op!(INT => add(as_int, as_int)),
|
||||
"-" => return impl_op!(INT => subtract(as_int, as_int)),
|
||||
"*" => return impl_op!(INT => multiply(as_int, as_int)),
|
||||
"/" => return impl_op!(INT => divide(as_int, as_int)),
|
||||
"%" => return impl_op!(INT => modulo(as_int, as_int)),
|
||||
"**" => return impl_op!(INT => power(as_int, as_int)),
|
||||
">>" => return impl_op!(INT => shift_right(as_int, as_int)),
|
||||
"<<" => return impl_op!(INT => shift_left(as_int, as_int)),
|
||||
"+" => return Some(impl_op!(INT => add(as_int, as_int))),
|
||||
"-" => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
||||
"*" => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
||||
"/" => return Some(impl_op!(INT => divide(as_int, as_int))),
|
||||
"%" => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
||||
"**" => return Some(impl_op!(INT => power(as_int, as_int))),
|
||||
">>" => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
||||
"<<" => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
match op {
|
||||
"+" => return impl_op!(INT => as_int + as_int),
|
||||
"-" => return impl_op!(INT => as_int - as_int),
|
||||
"*" => return impl_op!(INT => as_int * as_int),
|
||||
"/" => return impl_op!(INT => as_int / as_int),
|
||||
"%" => return impl_op!(INT => as_int % as_int),
|
||||
"**" => return impl_op!(INT => as_int.pow(as_int as u32)),
|
||||
">>" => return impl_op!(INT => as_int >> as_int),
|
||||
"<<" => return impl_op!(INT => as_int << as_int),
|
||||
"+" => return Some(impl_op!(INT => as_int + as_int)),
|
||||
"-" => return Some(impl_op!(INT => as_int - as_int)),
|
||||
"*" => return Some(impl_op!(INT => as_int * as_int)),
|
||||
"/" => return Some(impl_op!(INT => as_int / as_int)),
|
||||
"%" => return Some(impl_op!(INT => as_int % as_int)),
|
||||
"**" => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
||||
">>" => return Some(impl_op!(INT => as_int >> as_int)),
|
||||
"<<" => return Some(impl_op!(INT => as_int << as_int)),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
return match op {
|
||||
"==" => impl_op!(INT => as_int == as_int),
|
||||
"!=" => impl_op!(INT => as_int != as_int),
|
||||
">" => impl_op!(INT => as_int > as_int),
|
||||
">=" => impl_op!(INT => as_int >= as_int),
|
||||
"<" => impl_op!(INT => as_int < as_int),
|
||||
"<=" => impl_op!(INT => as_int <= as_int),
|
||||
"&" => impl_op!(INT => as_int & as_int),
|
||||
"|" => impl_op!(INT => as_int | as_int),
|
||||
"^" => impl_op!(INT => as_int ^ as_int),
|
||||
"==" => Some(impl_op!(INT => as_int == as_int)),
|
||||
"!=" => Some(impl_op!(INT => as_int != as_int)),
|
||||
">" => Some(impl_op!(INT => as_int > as_int)),
|
||||
">=" => Some(impl_op!(INT => as_int >= as_int)),
|
||||
"<" => Some(impl_op!(INT => as_int < as_int)),
|
||||
"<=" => Some(impl_op!(INT => as_int <= as_int)),
|
||||
"&" => Some(impl_op!(INT => as_int & as_int)),
|
||||
"|" => Some(impl_op!(INT => as_int | as_int)),
|
||||
"^" => Some(impl_op!(INT => as_int ^ as_int)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
if type1 == TypeId::of::<bool>() {
|
||||
return match op {
|
||||
"==" => impl_op!(bool => as_bool == as_bool),
|
||||
"!=" => impl_op!(bool => as_bool != as_bool),
|
||||
">" => impl_op!(bool => as_bool > as_bool),
|
||||
">=" => impl_op!(bool => as_bool >= as_bool),
|
||||
"<" => impl_op!(bool => as_bool < as_bool),
|
||||
"<=" => impl_op!(bool => as_bool <= as_bool),
|
||||
"&" => impl_op!(bool => as_bool & as_bool),
|
||||
"|" => impl_op!(bool => as_bool | as_bool),
|
||||
"^" => impl_op!(bool => as_bool ^ as_bool),
|
||||
"==" => Some(impl_op!(bool => as_bool == as_bool)),
|
||||
"!=" => Some(impl_op!(bool => as_bool != as_bool)),
|
||||
">" => Some(impl_op!(bool => as_bool > as_bool)),
|
||||
">=" => Some(impl_op!(bool => as_bool >= as_bool)),
|
||||
"<" => Some(impl_op!(bool => as_bool < as_bool)),
|
||||
"<=" => Some(impl_op!(bool => as_bool <= as_bool)),
|
||||
"&" => Some(impl_op!(bool => as_bool & as_bool)),
|
||||
"|" => Some(impl_op!(bool => as_bool | as_bool)),
|
||||
"^" => Some(impl_op!(bool => as_bool ^ as_bool)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
if type1 == TypeId::of::<ImmutableString>() {
|
||||
return match op {
|
||||
"+" => impl_op!(ImmutableString + ImmutableString),
|
||||
"-" => impl_op!(ImmutableString - ImmutableString),
|
||||
"==" => impl_op!(ImmutableString == ImmutableString),
|
||||
"!=" => impl_op!(ImmutableString != ImmutableString),
|
||||
">" => impl_op!(ImmutableString > ImmutableString),
|
||||
">=" => impl_op!(ImmutableString >= ImmutableString),
|
||||
"<" => impl_op!(ImmutableString < ImmutableString),
|
||||
"<=" => impl_op!(ImmutableString <= ImmutableString),
|
||||
"+" => Some(impl_op!(ImmutableString + ImmutableString)),
|
||||
"-" => Some(impl_op!(ImmutableString - ImmutableString)),
|
||||
"==" => Some(impl_op!(ImmutableString == ImmutableString)),
|
||||
"!=" => Some(impl_op!(ImmutableString != ImmutableString)),
|
||||
">" => Some(impl_op!(ImmutableString > ImmutableString)),
|
||||
">=" => Some(impl_op!(ImmutableString >= ImmutableString)),
|
||||
"<" => Some(impl_op!(ImmutableString < ImmutableString)),
|
||||
"<=" => Some(impl_op!(ImmutableString <= ImmutableString)),
|
||||
OP_CONTAINS => Some(|_, args| {
|
||||
let s1 = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||
let s2 = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||
@ -395,12 +375,12 @@ pub fn get_builtin_binary_op_fn(
|
||||
let y = args[1].as_char().expect(BUILTIN);
|
||||
Ok(format!("{}{}", x, y).into())
|
||||
}),
|
||||
"==" => impl_op!(char => as_char == as_char),
|
||||
"!=" => impl_op!(char => as_char != as_char),
|
||||
">" => impl_op!(char => as_char > as_char),
|
||||
">=" => impl_op!(char => as_char >= as_char),
|
||||
"<" => impl_op!(char => as_char < as_char),
|
||||
"<=" => impl_op!(char => as_char <= as_char),
|
||||
"==" => Some(impl_op!(char => as_char == as_char)),
|
||||
"!=" => Some(impl_op!(char => as_char != as_char)),
|
||||
">" => Some(impl_op!(char => as_char > as_char)),
|
||||
">=" => Some(impl_op!(char => as_char >= as_char)),
|
||||
"<" => Some(impl_op!(char => as_char < as_char)),
|
||||
"<=" => Some(impl_op!(char => as_char <= as_char)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -433,59 +413,43 @@ pub fn get_builtin_op_assignment_fn(
|
||||
let types_pair = (type1, type2);
|
||||
|
||||
macro_rules! impl_op {
|
||||
($x:ty = x $op:tt $yy:ident) => {
|
||||
Some(|_, args| {
|
||||
($x:ty = x $op:tt $yy:ident) => { |_, args| {
|
||||
let x = args[0].$yy().expect(BUILTIN);
|
||||
let y = args[1].$yy().expect(BUILTIN) as $x;
|
||||
Ok((*args[0].write_lock::<$x>().expect(BUILTIN) = x $op y).into())
|
||||
})
|
||||
};
|
||||
($x:ident $op:tt $yy:ident) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($x:ident $op:tt $yy:ident) => { |_, args| {
|
||||
let y = args[1].$yy().expect(BUILTIN) as $x;
|
||||
Ok((*args[0].write_lock::<$x>().expect(BUILTIN) $op y).into())
|
||||
})
|
||||
};
|
||||
($x:ident $op:tt $yy:ident as $yyy:ty) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($x:ident $op:tt $yy:ident as $yyy:ty) => { |_, args| {
|
||||
let y = args[1].$yy().expect(BUILTIN) as $yyy;
|
||||
Ok((*args[0].write_lock::<$x>().expect(BUILTIN) $op y).into())
|
||||
})
|
||||
};
|
||||
($x:ty => $xx:ident . $func:ident ( $yy:ident as $yyy:ty )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($x:ty => $xx:ident . $func:ident ( $yy:ident as $yyy:ty )) => { |_, args| {
|
||||
let x = args[0].$xx().expect(BUILTIN);
|
||||
let y = args[1].$yy().expect(BUILTIN) as $x;
|
||||
Ok((*args[0].write_lock::<$x>().expect(BUILTIN) = x.$func(y as $yyy)).into())
|
||||
})
|
||||
};
|
||||
($x:ty => $func:ident ( $xx:ident, $yy:ident )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
($x:ty => $func:ident ( $xx:ident, $yy:ident )) => { |_, args| {
|
||||
let x = args[0].$xx().expect(BUILTIN);
|
||||
let y = args[1].$yy().expect(BUILTIN) as $x;
|
||||
Ok((*args[0].write_lock().expect(BUILTIN) = $func(x, y)?).into())
|
||||
})
|
||||
};
|
||||
(from $x:ident $op:tt $yy:ident) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
(from $x:ident $op:tt $yy:ident) => { |_, args| {
|
||||
let y = <$x>::from(args[1].$yy().expect(BUILTIN));
|
||||
Ok((*args[0].write_lock::<$x>().expect(BUILTIN) $op y).into())
|
||||
})
|
||||
};
|
||||
(from $x:ty => $xx:ident . $func:ident ( $yy:ident )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
(from $x:ty => $xx:ident . $func:ident ( $yy:ident )) => { |_, args| {
|
||||
let x = args[0].$xx().expect(BUILTIN);
|
||||
let y = <$x>::from(args[1].$yy().expect(BUILTIN));
|
||||
Ok((*args[0].write_lock::<$x>().expect(BUILTIN) = x.$func(y)).into())
|
||||
})
|
||||
};
|
||||
(from $x:ty => $func:ident ( $xx:ident, $yy:ident )) => {
|
||||
Some(|_, args| {
|
||||
} };
|
||||
(from $x:ty => $func:ident ( $xx:ident, $yy:ident )) => { |_, args| {
|
||||
let x = args[0].$xx().expect(BUILTIN);
|
||||
let y = <$x>::from(args[1].$yy().expect(BUILTIN));
|
||||
Ok((*args[0].write_lock().expect(BUILTIN) = $func(x, y)?).into())
|
||||
})
|
||||
};
|
||||
} };
|
||||
}
|
||||
|
||||
macro_rules! impl_float {
|
||||
@ -493,12 +457,12 @@ pub fn get_builtin_op_assignment_fn(
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if types_pair == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||
return match op {
|
||||
"+=" => impl_op!($x += $yy),
|
||||
"-=" => impl_op!($x -= $yy),
|
||||
"*=" => impl_op!($x *= $yy),
|
||||
"/=" => impl_op!($x /= $yy),
|
||||
"%=" => impl_op!($x %= $yy),
|
||||
"**=" => impl_op!($x => $xx.powf($yy as $x)),
|
||||
"+=" => Some(impl_op!($x += $yy)),
|
||||
"-=" => Some(impl_op!($x -= $yy)),
|
||||
"*=" => Some(impl_op!($x *= $yy)),
|
||||
"/=" => Some(impl_op!($x /= $yy)),
|
||||
"%=" => Some(impl_op!($x %= $yy)),
|
||||
"**=" => Some(impl_op!($x => $xx.powf($yy as $x))),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -517,12 +481,12 @@ pub fn get_builtin_op_assignment_fn(
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
return match op {
|
||||
"+=" => impl_op!(from $x => add($xx, $yy)),
|
||||
"-=" => impl_op!(from $x => subtract($xx, $yy)),
|
||||
"*=" => impl_op!(from $x => multiply($xx, $yy)),
|
||||
"/=" => impl_op!(from $x => divide($xx, $yy)),
|
||||
"%=" => impl_op!(from $x => modulo($xx, $yy)),
|
||||
"**=" => impl_op!(from $x => power($xx, $yy)),
|
||||
"+=" => Some(impl_op!(from $x => add($xx, $yy))),
|
||||
"-=" => Some(impl_op!(from $x => subtract($xx, $yy))),
|
||||
"*=" => Some(impl_op!(from $x => multiply($xx, $yy))),
|
||||
"/=" => Some(impl_op!(from $x => divide($xx, $yy))),
|
||||
"%=" => Some(impl_op!(from $x => modulo($xx, $yy))),
|
||||
"**=" => Some(impl_op!(from $x => power($xx, $yy))),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@ -531,12 +495,12 @@ pub fn get_builtin_op_assignment_fn(
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
return match op {
|
||||
"+=" => impl_op!(from $x += $yy),
|
||||
"-=" => impl_op!(from $x -= $yy),
|
||||
"*=" => impl_op!(from $x *= $yy),
|
||||
"/=" => impl_op!(from $x /= $yy),
|
||||
"%=" => impl_op!(from $x %= $yy),
|
||||
"**=" => impl_op!(from $x => $xx.powd($yy)),
|
||||
"+=" => Some(impl_op!(from $x += $yy)),
|
||||
"-=" => Some(impl_op!(from $x -= $yy)),
|
||||
"*=" => Some(impl_op!(from $x *= $yy)),
|
||||
"/=" => Some(impl_op!(from $x /= $yy)),
|
||||
"%=" => Some(impl_op!(from $x %= $yy)),
|
||||
"**=" => Some(impl_op!(from $x => $xx.powd($yy))),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -549,8 +513,8 @@ pub fn get_builtin_op_assignment_fn(
|
||||
// string op= char
|
||||
if types_pair == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
|
||||
return match op {
|
||||
"+=" => impl_op!(ImmutableString += as_char as char),
|
||||
"-=" => impl_op!(ImmutableString -= as_char as char),
|
||||
"+=" => Some(impl_op!(ImmutableString += as_char as char)),
|
||||
"-=" => Some(impl_op!(ImmutableString -= as_char as char)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -585,42 +549,42 @@ pub fn get_builtin_op_assignment_fn(
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
match op {
|
||||
"+=" => return impl_op!(INT => add(as_int, as_int)),
|
||||
"-=" => return impl_op!(INT => subtract(as_int, as_int)),
|
||||
"*=" => return impl_op!(INT => multiply(as_int, as_int)),
|
||||
"/=" => return impl_op!(INT => divide(as_int, as_int)),
|
||||
"%=" => return impl_op!(INT => modulo(as_int, as_int)),
|
||||
"**=" => return impl_op!(INT => power(as_int, as_int)),
|
||||
">>=" => return impl_op!(INT => shift_right(as_int, as_int)),
|
||||
"<<=" => return impl_op!(INT => shift_left(as_int, as_int)),
|
||||
"+=" => return Some(impl_op!(INT => add(as_int, as_int))),
|
||||
"-=" => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
||||
"*=" => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
||||
"/=" => return Some(impl_op!(INT => divide(as_int, as_int))),
|
||||
"%=" => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
||||
"**=" => return Some(impl_op!(INT => power(as_int, as_int))),
|
||||
">>=" => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
||||
"<<=" => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
match op {
|
||||
"+=" => return impl_op!(INT += as_int),
|
||||
"-=" => return impl_op!(INT -= as_int),
|
||||
"*=" => return impl_op!(INT *= as_int),
|
||||
"/=" => return impl_op!(INT /= as_int),
|
||||
"%=" => return impl_op!(INT %= as_int),
|
||||
"**=" => return impl_op!(INT => as_int.pow(as_int as u32)),
|
||||
">>=" => return impl_op!(INT >>= as_int),
|
||||
"<<=" => return impl_op!(INT <<= as_int),
|
||||
"+=" => return Some(impl_op!(INT += as_int)),
|
||||
"-=" => return Some(impl_op!(INT -= as_int)),
|
||||
"*=" => return Some(impl_op!(INT *= as_int)),
|
||||
"/=" => return Some(impl_op!(INT /= as_int)),
|
||||
"%=" => return Some(impl_op!(INT %= as_int)),
|
||||
"**=" => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
||||
">>=" => return Some(impl_op!(INT >>= as_int)),
|
||||
"<<=" => return Some(impl_op!(INT <<= as_int)),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
return match op {
|
||||
"&=" => impl_op!(INT &= as_int),
|
||||
"|=" => impl_op!(INT |= as_int),
|
||||
"^=" => impl_op!(INT ^= as_int),
|
||||
"&=" => Some(impl_op!(INT &= as_int)),
|
||||
"|=" => Some(impl_op!(INT |= as_int)),
|
||||
"^=" => Some(impl_op!(INT ^= as_int)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
if type1 == TypeId::of::<bool>() {
|
||||
return match op {
|
||||
"&=" => impl_op!(bool = x && as_bool),
|
||||
"|=" => impl_op!(bool = x || as_bool),
|
||||
"&=" => Some(impl_op!(bool = x && as_bool)),
|
||||
"|=" => Some(impl_op!(bool = x || as_bool)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ impl Engine {
|
||||
.map(|a| if a.is::<ImmutableString>() {
|
||||
"&str | ImmutableString | String"
|
||||
} else {
|
||||
self.map_type_name((*a).type_name())
|
||||
self.map_type_name(a.type_name())
|
||||
})
|
||||
.collect::<StaticVec<_>>()
|
||||
.join(", ")
|
||||
@ -171,8 +171,10 @@ impl Engine {
|
||||
is_op_assignment: bool,
|
||||
) -> &'s Option<Box<FnResolutionCacheEntry>> {
|
||||
let mut hash = args.as_ref().map_or(hash_script, |args| {
|
||||
let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id()));
|
||||
combine_hashes(hash_script, hash_params)
|
||||
combine_hashes(
|
||||
hash_script,
|
||||
calc_fn_params_hash(args.iter().map(|a| a.type_id())),
|
||||
)
|
||||
});
|
||||
|
||||
&*state
|
||||
@ -188,43 +190,17 @@ impl Engine {
|
||||
let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic`
|
||||
|
||||
loop {
|
||||
let func = lib
|
||||
.iter()
|
||||
.find_map(|m| {
|
||||
m.get_fn(hash).cloned().map(|func| {
|
||||
let source = m.id_raw().cloned();
|
||||
FnResolutionCacheEntry { func, source }
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
self.global_namespace
|
||||
.get_fn(hash)
|
||||
.cloned()
|
||||
.map(|func| FnResolutionCacheEntry { func, source: None })
|
||||
})
|
||||
.or_else(|| {
|
||||
self.global_modules.iter().find_map(|m| {
|
||||
m.get_fn(hash).cloned().map(|func| {
|
||||
let source = m.id_raw().cloned();
|
||||
FnResolutionCacheEntry { func, source }
|
||||
})
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
mods.get_fn(hash).map(|(func, source)| {
|
||||
let func = func.clone();
|
||||
let source = source.cloned();
|
||||
FnResolutionCacheEntry { func, source }
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
self.global_sub_modules.values().find_map(|m| {
|
||||
m.get_qualified_fn(hash).cloned().map(|func| {
|
||||
let source = m.id_raw().cloned();
|
||||
FnResolutionCacheEntry { func, source }
|
||||
})
|
||||
})
|
||||
});
|
||||
let func = lib.iter().find_map(|m| m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
|
||||
func, source: m.id_raw().cloned()
|
||||
})).or_else(|| self.global_namespace.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
|
||||
func, source: None
|
||||
})).or_else(|| self.global_modules.iter().find_map(|m| m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
|
||||
func, source: m.id_raw().cloned()
|
||||
}))).or_else(|| mods.get_fn(hash).map(|(func, source)| FnResolutionCacheEntry {
|
||||
func: func.clone(), source: source.cloned()
|
||||
})).or_else(|| self.global_sub_modules.values().find_map(|m| m.get_qualified_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
|
||||
func, source: m.id_raw().cloned()
|
||||
})));
|
||||
|
||||
match func {
|
||||
// Specific version found
|
||||
@ -239,23 +215,17 @@ impl Engine {
|
||||
return args.and_then(|args| {
|
||||
if !is_op_assignment {
|
||||
get_builtin_binary_op_fn(fn_name, &args[0], &args[1]).map(|f| {
|
||||
let func = CallableFunction::from_method(
|
||||
FnResolutionCacheEntry { func: CallableFunction::from_method(
|
||||
Box::new(f) as Box<FnAny>
|
||||
);
|
||||
FnResolutionCacheEntry { func, source: None }
|
||||
), source: None }
|
||||
})
|
||||
} else {
|
||||
let (first, second) = args.split_first()
|
||||
.expect("never fails because an op-assignment must have two arguments");
|
||||
|
||||
get_builtin_op_assignment_fn(fn_name, *first, second[0]).map(
|
||||
|f| {
|
||||
let func = CallableFunction::from_method(
|
||||
Box::new(f) as Box<FnAny>
|
||||
);
|
||||
FnResolutionCacheEntry { func, source: None }
|
||||
},
|
||||
)
|
||||
get_builtin_op_assignment_fn(fn_name, *first, second[0]).map(|f| FnResolutionCacheEntry {
|
||||
func: CallableFunction::from_method(Box::new(f) as Box<FnAny>), source: None
|
||||
})
|
||||
}
|
||||
.map(Box::new)
|
||||
});
|
||||
@ -437,11 +407,10 @@ impl Engine {
|
||||
}
|
||||
|
||||
// Raise error
|
||||
_ => EvalAltResult::ErrorFunctionNotFound(
|
||||
self.gen_call_signature(None, name, args.as_ref()),
|
||||
pos,
|
||||
)
|
||||
.into(),
|
||||
_ => {
|
||||
EvalAltResult::ErrorFunctionNotFound(self.gen_call_signature(None, name, args), pos)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1451,7 +1420,7 @@ impl Engine {
|
||||
Some(f) => unreachable!("unknown function type: {:?}", f),
|
||||
|
||||
None => EvalAltResult::ErrorFunctionNotFound(
|
||||
self.gen_call_signature(Some(namespace), fn_name, args.as_ref()),
|
||||
self.gen_call_signature(Some(namespace), fn_name, &args),
|
||||
pos,
|
||||
)
|
||||
.into(),
|
||||
|
@ -191,7 +191,7 @@ impl<'e> ParseState<'e> {
|
||||
.iter()
|
||||
.rev()
|
||||
.enumerate()
|
||||
.find(|&(_, n)| *n == name)
|
||||
.find(|&(_, n)| n == name)
|
||||
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
||||
}
|
||||
|
||||
@ -1070,8 +1070,8 @@ fn parse_primary(
|
||||
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
new_state.external_vars.iter().for_each(|(closure, pos)| {
|
||||
state.access_var(closure, *pos);
|
||||
new_state.external_vars.iter().for_each(|(closure, &pos)| {
|
||||
state.access_var(closure, pos);
|
||||
});
|
||||
|
||||
let hash_script = calc_fn_hash(&func.name, func.params.len());
|
||||
|
@ -448,7 +448,7 @@ impl<'a> Scope<'a> {
|
||||
.1
|
||||
.as_mut()
|
||||
.expect("never fails because the list is initialized");
|
||||
if !list.iter().any(|a| &alias == a) {
|
||||
if !list.iter().any(|a| a == &alias) {
|
||||
list.push(alias);
|
||||
}
|
||||
self
|
||||
|
Loading…
Reference in New Issue
Block a user