Merge pull request #355 from schungx/master
Built-in interop between FLOAT/Decimal and INT.
This commit is contained in:
commit
1b33c60988
@ -6,7 +6,7 @@ members = [
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "0.19.12"
|
version = "0.19.13"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
||||||
description = "Embedded scripting for Rust"
|
description = "Embedded scripting for Rust"
|
||||||
|
30
RELEASES.md
30
RELEASES.md
@ -1,9 +1,37 @@
|
|||||||
Rhai Release Notes
|
Rhai Release Notes
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
Version 0.19.13
|
||||||
|
===============
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Bug in `Position::is_beginning_of_line` is fixed.
|
||||||
|
|
||||||
|
New features
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Comparisons between `FLOAT`/[`Decimal`](https://crates.io/crates/rust_decimal) and `INT` are now built in.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Built-in operators between `FLOAT`/[`Decimal`](https://crates.io/crates/rust_decimal) and `INT` are now implemented for more speed under those cases.
|
||||||
|
* Error position in `eval` statements is now wrapped in an `EvalAltResult::ErrorInFunctionCall`.
|
||||||
|
* `Position` now implements `Add` and `AddAssign`.
|
||||||
|
* `Scope` now implements `IntoIterator`.
|
||||||
|
|
||||||
|
|
||||||
Version 0.19.12
|
Version 0.19.12
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
This version is an incremental release with a number of enhancements and bug fixes.
|
||||||
|
|
||||||
|
Notice that there are a number of breaking changes, especially with regards to replacing the `~`
|
||||||
|
exponential operator with `**`, and the addition of the `decimal` feature that turns on
|
||||||
|
[`Decimal`](https://crates.io/crates/rust_decimal) support.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@ -33,7 +61,7 @@ Enhancements
|
|||||||
|
|
||||||
* Functions resolution cache is used in more cases, making repeated function calls faster.
|
* Functions resolution cache is used in more cases, making repeated function calls faster.
|
||||||
* Added `atan(x, y)` and `hypot(x, y)` to `BasicMathPackage`.
|
* Added `atan(x, y)` and `hypot(x, y)` to `BasicMathPackage`.
|
||||||
* Added standard arithmetic operators between `FLOAT` and `INT`.
|
* Added standard arithmetic operators between `FLOAT`/[`Decimal`](https://crates.io/crates/rust_decimal) and `INT`.
|
||||||
|
|
||||||
|
|
||||||
Version 0.19.11
|
Version 0.19.11
|
||||||
|
@ -378,8 +378,8 @@ impl Parse for ExportedFn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check return type.
|
// Check return type.
|
||||||
if let syn::ReturnType::Type(_, ref rtype) = fn_all.sig.output {
|
if let syn::ReturnType::Type(_, ref ret_type) = fn_all.sig.output {
|
||||||
match flatten_type_groups(rtype.as_ref()) {
|
match flatten_type_groups(ret_type.as_ref()) {
|
||||||
syn::Type::Ptr(_) => {
|
syn::Type::Ptr(_) => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
fn_all.sig.output.span(),
|
fn_all.sig.output.span(),
|
||||||
@ -495,8 +495,8 @@ impl ExportedFn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn return_type(&self) -> Option<&syn::Type> {
|
pub(crate) fn return_type(&self) -> Option<&syn::Type> {
|
||||||
if let syn::ReturnType::Type(_, ref rtype) = self.signature.output {
|
if let syn::ReturnType::Type(_, ref ret_type) = self.signature.output {
|
||||||
Some(flatten_type_groups(rtype))
|
Some(flatten_type_groups(ret_type))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -616,8 +616,8 @@ impl ExportedFn {
|
|||||||
let arguments: Vec<syn::Ident> = dynamic_signature
|
let arguments: Vec<syn::Ident> = dynamic_signature
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|fnarg| {
|
.filter_map(|fn_arg| {
|
||||||
if let syn::FnArg::Typed(syn::PatType { ref pat, .. }) = fnarg {
|
if let syn::FnArg::Typed(syn::PatType { ref pat, .. }) = fn_arg {
|
||||||
if let syn::Pat::Ident(ref ident) = pat.as_ref() {
|
if let syn::Pat::Ident(ref ident) = pat.as_ref() {
|
||||||
Some(ident.ident.clone())
|
Some(ident.ident.clone())
|
||||||
} else {
|
} else {
|
||||||
@ -718,7 +718,7 @@ impl ExportedFn {
|
|||||||
let arg_count = self.arg_count();
|
let arg_count = self.arg_count();
|
||||||
let is_method_call = self.mutable_receiver();
|
let is_method_call = self.mutable_receiver();
|
||||||
|
|
||||||
let mut unpack_stmts: Vec<syn::Stmt> = Vec::new();
|
let mut unpack_statements: Vec<syn::Stmt> = Vec::new();
|
||||||
let mut unpack_exprs: Vec<syn::Expr> = Vec::new();
|
let mut unpack_exprs: Vec<syn::Expr> = Vec::new();
|
||||||
let mut input_type_names: Vec<String> = Vec::new();
|
let mut input_type_names: Vec<String> = Vec::new();
|
||||||
let mut input_type_exprs: Vec<syn::Expr> = Vec::new();
|
let mut input_type_exprs: Vec<syn::Expr> = Vec::new();
|
||||||
@ -748,7 +748,7 @@ impl ExportedFn {
|
|||||||
};
|
};
|
||||||
let downcast_span = quote_spanned!(
|
let downcast_span = quote_spanned!(
|
||||||
arg_type.span()=> &mut args[0usize].write_lock::<#arg_type>().unwrap());
|
arg_type.span()=> &mut args[0usize].write_lock::<#arg_type>().unwrap());
|
||||||
unpack_stmts.push(
|
unpack_statements.push(
|
||||||
syn::parse2::<syn::Stmt>(quote! {
|
syn::parse2::<syn::Stmt>(quote! {
|
||||||
let #var = #downcast_span;
|
let #var = #downcast_span;
|
||||||
})
|
})
|
||||||
@ -811,7 +811,7 @@ impl ExportedFn {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
unpack_stmts.push(
|
unpack_statements.push(
|
||||||
syn::parse2::<syn::Stmt>(quote! {
|
syn::parse2::<syn::Stmt>(quote! {
|
||||||
let #var = #downcast_span;
|
let #var = #downcast_span;
|
||||||
})
|
})
|
||||||
@ -847,8 +847,8 @@ impl ExportedFn {
|
|||||||
// that as needing to borrow the entire array, all of the previous argument unpacking via
|
// that as needing to borrow the entire array, all of the previous argument unpacking via
|
||||||
// clone needs to happen first.
|
// clone needs to happen first.
|
||||||
if is_method_call {
|
if is_method_call {
|
||||||
let arg0 = unpack_stmts.remove(0);
|
let arg0 = unpack_statements.remove(0);
|
||||||
unpack_stmts.push(arg0);
|
unpack_statements.push(arg0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle "raw returns", aka cases where the result is a dynamic or an error.
|
// Handle "raw returns", aka cases where the result is a dynamic or an error.
|
||||||
@ -881,7 +881,7 @@ impl ExportedFn {
|
|||||||
debug_assert_eq!(args.len(), #arg_count,
|
debug_assert_eq!(args.len(), #arg_count,
|
||||||
"wrong arg count: {} != {}",
|
"wrong arg count: {} != {}",
|
||||||
args.len(), #arg_count);
|
args.len(), #arg_count);
|
||||||
#(#unpack_stmts)*
|
#(#unpack_statements)*
|
||||||
#return_expr
|
#return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,12 +293,12 @@ pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro
|
|||||||
/// ```
|
/// ```
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let (engine_expr, export_name, rust_modpath) = match crate::register::parse_register_macro(args)
|
let (engine_expr, export_name, rust_mod_path) =
|
||||||
{
|
match crate::register::parse_register_macro(args) {
|
||||||
Ok(triple) => triple,
|
Ok(triple) => triple,
|
||||||
Err(e) => return e.to_compile_error().into(),
|
Err(e) => return e.to_compile_error().into(),
|
||||||
};
|
};
|
||||||
let gen_mod_path = crate::register::generated_module_path(&rust_modpath);
|
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
#engine_expr.register_result_fn(&(#export_name), #gen_mod_path::dynamic_result_fn);
|
#engine_expr.register_result_fn(&(#export_name), #gen_mod_path::dynamic_result_fn);
|
||||||
};
|
};
|
||||||
@ -332,12 +332,12 @@ pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenS
|
|||||||
/// ```
|
/// ```
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let (module_expr, export_name, rust_modpath) = match crate::register::parse_register_macro(args)
|
let (module_expr, export_name, rust_mod_path) =
|
||||||
{
|
match crate::register::parse_register_macro(args) {
|
||||||
Ok(triple) => triple,
|
Ok(triple) => triple,
|
||||||
Err(e) => return e.to_compile_error().into(),
|
Err(e) => return e.to_compile_error().into(),
|
||||||
};
|
};
|
||||||
let gen_mod_path = crate::register::generated_module_path(&rust_modpath);
|
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
|
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
|
||||||
Some(#gen_mod_path::token_input_names().as_ref()),
|
Some(#gen_mod_path::token_input_names().as_ref()),
|
||||||
@ -374,12 +374,12 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream
|
|||||||
/// ```
|
/// ```
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let (module_expr, export_name, rust_modpath) = match crate::register::parse_register_macro(args)
|
let (module_expr, export_name, rust_mod_path) =
|
||||||
{
|
match crate::register::parse_register_macro(args) {
|
||||||
Ok(triple) => triple,
|
Ok(triple) => triple,
|
||||||
Err(e) => return e.to_compile_error().into(),
|
Err(e) => return e.to_compile_error().into(),
|
||||||
};
|
};
|
||||||
let gen_mod_path = crate::register::generated_module_path(&rust_modpath);
|
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
|
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
|
||||||
Some(#gen_mod_path::token_input_names().as_ref()),
|
Some(#gen_mod_path::token_input_names().as_ref()),
|
||||||
|
@ -101,7 +101,7 @@ pub(crate) struct Module {
|
|||||||
mod_all: syn::ItemMod,
|
mod_all: syn::ItemMod,
|
||||||
fns: Vec<ExportedFn>,
|
fns: Vec<ExportedFn>,
|
||||||
consts: Vec<ExportedConst>,
|
consts: Vec<ExportedConst>,
|
||||||
submodules: Vec<Module>,
|
sub_modules: Vec<Module>,
|
||||||
params: ExportedModParams,
|
params: ExportedModParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ impl Parse for Module {
|
|||||||
let mut mod_all: syn::ItemMod = input.parse()?;
|
let mut mod_all: syn::ItemMod = input.parse()?;
|
||||||
let fns: Vec<_>;
|
let fns: Vec<_>;
|
||||||
let mut consts: Vec<_> = new_vec![];
|
let mut consts: Vec<_> = new_vec![];
|
||||||
let mut submodules: Vec<_> = Vec::new();
|
let mut sub_modules: Vec<_> = Vec::new();
|
||||||
if let Some((_, ref mut content)) = mod_all.content {
|
if let Some((_, ref mut content)) = mod_all.content {
|
||||||
// Gather and parse functions.
|
// Gather and parse functions.
|
||||||
fns = content
|
fns = content
|
||||||
@ -126,16 +126,16 @@ impl Parse for Module {
|
|||||||
syn::Item::Fn(f) => Some(f),
|
syn::Item::Fn(f) => Some(f),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.try_fold(Vec::new(), |mut vec, itemfn| {
|
.try_fold(Vec::new(), |mut vec, item_fn| {
|
||||||
// #[cfg] attributes are not allowed on functions
|
// #[cfg] attributes are not allowed on functions
|
||||||
crate::attrs::deny_cfg_attr(&itemfn.attrs)?;
|
crate::attrs::deny_cfg_attr(&item_fn.attrs)?;
|
||||||
|
|
||||||
let params: ExportedFnParams =
|
let params: ExportedFnParams =
|
||||||
match crate::attrs::inner_item_attributes(&mut itemfn.attrs, "rhai_fn") {
|
match crate::attrs::inner_item_attributes(&mut item_fn.attrs, "rhai_fn") {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
syn::parse2::<ExportedFn>(itemfn.to_token_stream())
|
syn::parse2::<ExportedFn>(item_fn.to_token_stream())
|
||||||
.and_then(|mut f| {
|
.and_then(|mut f| {
|
||||||
f.set_params(params)?;
|
f.set_params(params)?;
|
||||||
Ok(f)
|
Ok(f)
|
||||||
@ -163,29 +163,31 @@ impl Parse for Module {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Gather and parse submodule definitions.
|
// Gather and parse sub-module definitions.
|
||||||
//
|
//
|
||||||
// They are actually removed from the module's body, because they will need
|
// They are actually removed from the module's body, because they will need
|
||||||
// re-generating later when generated code is added.
|
// re-generating later when generated code is added.
|
||||||
submodules.reserve(content.len() - fns.len() - consts.len());
|
sub_modules.reserve(content.len() - fns.len() - consts.len());
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < content.len() {
|
while i < content.len() {
|
||||||
if let syn::Item::Mod(_) = &content[i] {
|
if let syn::Item::Mod(_) = &content[i] {
|
||||||
let mut itemmod = match content.remove(i) {
|
let mut item_mod = match content.remove(i) {
|
||||||
syn::Item::Mod(m) => m,
|
syn::Item::Mod(m) => m,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let params: ExportedModParams =
|
let params: ExportedModParams = match crate::attrs::inner_item_attributes(
|
||||||
match crate::attrs::inner_item_attributes(&mut itemmod.attrs, "rhai_mod") {
|
&mut item_mod.attrs,
|
||||||
Ok(p) => p,
|
"rhai_mod",
|
||||||
Err(e) => return Err(e),
|
) {
|
||||||
};
|
Ok(p) => p,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
let module =
|
let module =
|
||||||
syn::parse2::<Module>(itemmod.to_token_stream()).and_then(|mut m| {
|
syn::parse2::<Module>(item_mod.to_token_stream()).and_then(|mut m| {
|
||||||
m.set_params(params)?;
|
m.set_params(params)?;
|
||||||
Ok(m)
|
Ok(m)
|
||||||
})?;
|
})?;
|
||||||
submodules.push(module);
|
sub_modules.push(module);
|
||||||
} else {
|
} else {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@ -197,7 +199,7 @@ impl Parse for Module {
|
|||||||
mod_all,
|
mod_all,
|
||||||
fns,
|
fns,
|
||||||
consts,
|
consts,
|
||||||
submodules,
|
sub_modules,
|
||||||
params: ExportedModParams::default(),
|
params: ExportedModParams::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -251,7 +253,7 @@ impl Module {
|
|||||||
mut mod_all,
|
mut mod_all,
|
||||||
mut fns,
|
mut fns,
|
||||||
consts,
|
consts,
|
||||||
mut submodules,
|
mut sub_modules,
|
||||||
params,
|
params,
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
@ -266,13 +268,13 @@ impl Module {
|
|||||||
let mod_gen = crate::rhai_module::generate_body(
|
let mod_gen = crate::rhai_module::generate_body(
|
||||||
&mut fns,
|
&mut fns,
|
||||||
&consts,
|
&consts,
|
||||||
&mut submodules,
|
&mut sub_modules,
|
||||||
¶ms.scope,
|
¶ms.scope,
|
||||||
);
|
);
|
||||||
|
|
||||||
// NB: submodules must have their new items for exporting generated in depth-first order
|
// NB: sub-modules must have their new items for exporting generated in depth-first order
|
||||||
// to avoid issues caused by re-parsing them
|
// to avoid issues caused by re-parsing them
|
||||||
let inner_modules: Vec<proc_macro2::TokenStream> = submodules.drain(..)
|
let inner_modules: Vec<proc_macro2::TokenStream> = sub_modules.drain(..)
|
||||||
.try_fold::<Vec<proc_macro2::TokenStream>, _,
|
.try_fold::<Vec<proc_macro2::TokenStream>, _,
|
||||||
Result<Vec<proc_macro2::TokenStream>, syn::Error>>(
|
Result<Vec<proc_macro2::TokenStream>, syn::Error>>(
|
||||||
Vec::new(), |mut acc, m| { acc.push(m.generate_inner()?); Ok(acc) })?;
|
Vec::new(), |mut acc, m| { acc.push(m.generate_inner()?); Ok(acc) })?;
|
||||||
@ -309,8 +311,8 @@ impl Module {
|
|||||||
&self.fns
|
&self.fns
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn submodules(&self) -> &[Module] {
|
pub fn sub_modules(&self) -> &[Module] {
|
||||||
&self.submodules
|
&self.sub_modules
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content(&self) -> Option<&Vec<syn::Item>> {
|
pub fn content(&self) -> Option<&Vec<syn::Item>> {
|
||||||
|
@ -33,11 +33,11 @@ pub fn parse_register_macro(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let export_name = match &items[1] {
|
let export_name = match &items[1] {
|
||||||
syn::Expr::Lit(litstr) => quote_spanned!(items[1].span()=>
|
syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span()=>
|
||||||
#litstr.to_string()),
|
#lit_str.to_string()),
|
||||||
expr => quote! { #expr },
|
expr => quote! { #expr },
|
||||||
};
|
};
|
||||||
let rust_modpath = if let syn::Expr::Path(ref path) = &items[2] {
|
let rust_mod_path = if let syn::Expr::Path(ref path) = &items[2] {
|
||||||
path.path.clone()
|
path.path.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
@ -46,5 +46,5 @@ pub fn parse_register_macro(
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
let module = items.remove(0);
|
let module = items.remove(0);
|
||||||
Ok((module, export_name, rust_modpath))
|
Ok((module, export_name, rust_mod_path))
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,11 @@ pub(crate) type ExportedConst = (String, Box<syn::Type>, syn::Expr);
|
|||||||
pub(crate) fn generate_body(
|
pub(crate) fn generate_body(
|
||||||
fns: &mut [ExportedFn],
|
fns: &mut [ExportedFn],
|
||||||
consts: &[ExportedConst],
|
consts: &[ExportedConst],
|
||||||
submodules: &mut [Module],
|
sub_modules: &mut [Module],
|
||||||
parent_scope: &ExportScope,
|
parent_scope: &ExportScope,
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let mut set_fn_stmts: Vec<syn::Stmt> = Vec::new();
|
let mut set_fn_statements: Vec<syn::Stmt> = Vec::new();
|
||||||
let mut set_const_stmts: Vec<syn::Stmt> = Vec::new();
|
let mut set_const_statements: Vec<syn::Stmt> = Vec::new();
|
||||||
let mut add_mod_blocks: Vec<syn::ExprBlock> = Vec::new();
|
let mut add_mod_blocks: Vec<syn::ExprBlock> = Vec::new();
|
||||||
let mut set_flattened_mod_blocks: Vec<syn::ExprBlock> = Vec::new();
|
let mut set_flattened_mod_blocks: Vec<syn::ExprBlock> = Vec::new();
|
||||||
let str_type_path = syn::parse2::<syn::Path>(quote! { str }).unwrap();
|
let str_type_path = syn::parse2::<syn::Path>(quote! { str }).unwrap();
|
||||||
@ -27,7 +27,7 @@ pub(crate) fn generate_body(
|
|||||||
for (const_name, _, _) in consts {
|
for (const_name, _, _) in consts {
|
||||||
let const_literal = syn::LitStr::new(&const_name, proc_macro2::Span::call_site());
|
let const_literal = syn::LitStr::new(&const_name, proc_macro2::Span::call_site());
|
||||||
let const_ref = syn::Ident::new(&const_name, proc_macro2::Span::call_site());
|
let const_ref = syn::Ident::new(&const_name, proc_macro2::Span::call_site());
|
||||||
set_const_stmts.push(
|
set_const_statements.push(
|
||||||
syn::parse2::<syn::Stmt>(quote! {
|
syn::parse2::<syn::Stmt>(quote! {
|
||||||
m.set_var(#const_literal, #const_ref);
|
m.set_var(#const_literal, #const_ref);
|
||||||
})
|
})
|
||||||
@ -35,17 +35,17 @@ pub(crate) fn generate_body(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for itemmod in submodules {
|
for item_mod in sub_modules {
|
||||||
itemmod.update_scope(&parent_scope);
|
item_mod.update_scope(&parent_scope);
|
||||||
if itemmod.skipped() {
|
if item_mod.skipped() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let module_name = itemmod.module_name();
|
let module_name = item_mod.module_name();
|
||||||
let exported_name: syn::LitStr = syn::LitStr::new(
|
let exported_name: syn::LitStr = syn::LitStr::new(
|
||||||
itemmod.exported_name().as_ref(),
|
item_mod.exported_name().as_ref(),
|
||||||
proc_macro2::Span::call_site(),
|
proc_macro2::Span::call_site(),
|
||||||
);
|
);
|
||||||
let cfg_attrs: Vec<&syn::Attribute> = itemmod
|
let cfg_attrs: Vec<&syn::Attribute> = item_mod
|
||||||
.attrs()
|
.attrs()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&a| a.path.get_ident().map(|i| *i == "cfg").unwrap_or(false))
|
.filter(|&a| a.path.get_ident().map(|i| *i == "cfg").unwrap_or(false))
|
||||||
@ -83,7 +83,7 @@ pub(crate) fn generate_body(
|
|||||||
|
|
||||||
let fn_input_names: Vec<String> = function
|
let fn_input_names: Vec<String> = function
|
||||||
.arg_list()
|
.arg_list()
|
||||||
.map(|fnarg| match fnarg {
|
.map(|fn_arg| match fn_arg {
|
||||||
syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"),
|
syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"),
|
||||||
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
|
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
|
||||||
format!("{}: {}", pat.to_token_stream(), print_type(ty))
|
format!("{}: {}", pat.to_token_stream(), print_type(ty))
|
||||||
@ -93,7 +93,7 @@ pub(crate) fn generate_body(
|
|||||||
|
|
||||||
let fn_input_types: Vec<syn::Expr> = function
|
let fn_input_types: Vec<syn::Expr> = function
|
||||||
.arg_list()
|
.arg_list()
|
||||||
.map(|fnarg| match fnarg {
|
.map(|fn_arg| match fn_arg {
|
||||||
syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"),
|
syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"),
|
||||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
|
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
|
||||||
let arg_type = match flatten_type_groups(ty.as_ref()) {
|
let arg_type = match flatten_type_groups(ty.as_ref()) {
|
||||||
@ -169,7 +169,7 @@ pub(crate) fn generate_body(
|
|||||||
},
|
},
|
||||||
fn_literal.span(),
|
fn_literal.span(),
|
||||||
);
|
);
|
||||||
set_fn_stmts.push(
|
set_fn_statements.push(
|
||||||
syn::parse2::<syn::Stmt>(quote! {
|
syn::parse2::<syn::Stmt>(quote! {
|
||||||
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
|
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
|
||||||
Some(&[#(#fn_input_names,)* #return_type]), &[#(#fn_input_types),*],
|
Some(&[#(#fn_input_names,)* #return_type]), &[#(#fn_input_types),*],
|
||||||
@ -190,7 +190,7 @@ pub(crate) fn generate_body(
|
|||||||
gen_fn_tokens.push(function.generate_return_type(&fn_token_name.to_string()));
|
gen_fn_tokens.push(function.generate_return_type(&fn_token_name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut generate_fncall = syn::parse2::<syn::ItemMod>(quote! {
|
let mut generate_fn_call = syn::parse2::<syn::ItemMod>(quote! {
|
||||||
pub mod generate_info {
|
pub mod generate_info {
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -203,8 +203,8 @@ pub(crate) fn generate_body(
|
|||||||
}
|
}
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||||
#(#set_fn_stmts)*
|
#(#set_fn_statements)*
|
||||||
#(#set_const_stmts)*
|
#(#set_const_statements)*
|
||||||
|
|
||||||
if flatten {
|
if flatten {
|
||||||
#(#set_flattened_mod_blocks)*
|
#(#set_flattened_mod_blocks)*
|
||||||
@ -216,7 +216,7 @@ pub(crate) fn generate_body(
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (_, generate_call_content) = generate_fncall.content.take().unwrap();
|
let (_, generate_call_content) = generate_fn_call.content.take().unwrap();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#(#generate_call_content)*
|
#(#generate_call_content)*
|
||||||
@ -225,39 +225,39 @@ pub(crate) fn generate_body(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::Error> {
|
pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::Error> {
|
||||||
fn make_key(name: impl ToString, itemfn: &ExportedFn) -> String {
|
fn make_key(name: impl ToString, item_fn: &ExportedFn) -> String {
|
||||||
itemfn
|
item_fn
|
||||||
.arg_list()
|
.arg_list()
|
||||||
.fold(name.to_string(), |mut argstr, fnarg| {
|
.fold(name.to_string(), |mut arg_str, fn_arg| {
|
||||||
let type_string: String = match fnarg {
|
let type_string: String = match fn_arg {
|
||||||
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
|
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
|
||||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty),
|
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty),
|
||||||
};
|
};
|
||||||
argstr.push('.');
|
arg_str.push('.');
|
||||||
argstr.push_str(&type_string);
|
arg_str.push_str(&type_string);
|
||||||
argstr
|
arg_str
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut renames = HashMap::<String, proc_macro2::Span>::new();
|
let mut renames = HashMap::<String, proc_macro2::Span>::new();
|
||||||
let mut fn_defs = HashMap::<String, proc_macro2::Span>::new();
|
let mut fn_defs = HashMap::<String, proc_macro2::Span>::new();
|
||||||
|
|
||||||
for itemfn in fns.iter() {
|
for item_fn in fns.iter() {
|
||||||
if !itemfn.params().name.is_empty() || itemfn.params().special != FnSpecialAccess::None {
|
if !item_fn.params().name.is_empty() || item_fn.params().special != FnSpecialAccess::None {
|
||||||
let mut names: Vec<_> = itemfn
|
let mut names: Vec<_> = item_fn
|
||||||
.params()
|
.params()
|
||||||
.name
|
.name
|
||||||
.iter()
|
.iter()
|
||||||
.map(|n| (n.clone(), n.clone()))
|
.map(|n| (n.clone(), n.clone()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some((s, n, _)) = itemfn.params().special.get_fn_name() {
|
if let Some((s, n, _)) = item_fn.params().special.get_fn_name() {
|
||||||
names.push((s, n));
|
names.push((s, n));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, fn_name) in names {
|
for (name, fn_name) in names {
|
||||||
let current_span = itemfn.params().span.unwrap();
|
let current_span = item_fn.params().span.unwrap();
|
||||||
let key = make_key(&name, itemfn);
|
let key = make_key(&name, item_fn);
|
||||||
if let Some(other_span) = renames.insert(key, current_span) {
|
if let Some(other_span) = renames.insert(key, current_span) {
|
||||||
let mut err = syn::Error::new(
|
let mut err = syn::Error::new(
|
||||||
current_span,
|
current_span,
|
||||||
@ -271,7 +271,7 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let ident = itemfn.name();
|
let ident = item_fn.name();
|
||||||
if let Some(other_span) = fn_defs.insert(ident.to_string(), ident.span()) {
|
if let Some(other_span) = fn_defs.insert(ident.to_string(), ident.span()) {
|
||||||
let mut err = syn::Error::new(
|
let mut err = syn::Error::new(
|
||||||
ident.span(),
|
ident.span(),
|
||||||
@ -283,7 +283,7 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
|
|||||||
));
|
));
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
let key = make_key(ident, itemfn);
|
let key = make_key(ident, item_fn);
|
||||||
if let Some(fn_span) = renames.get(&key) {
|
if let Some(fn_span) = renames.get(&key) {
|
||||||
let mut err = syn::Error::new(
|
let mut err = syn::Error::new(
|
||||||
ident.span(),
|
ident.span(),
|
||||||
|
@ -106,10 +106,10 @@ mod module_tests {
|
|||||||
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
||||||
assert!(item_mod.fns().is_empty());
|
assert!(item_mod.fns().is_empty());
|
||||||
assert!(item_mod.consts().is_empty());
|
assert!(item_mod.consts().is_empty());
|
||||||
assert_eq!(item_mod.submodules().len(), 1);
|
assert_eq!(item_mod.sub_modules().len(), 1);
|
||||||
assert_eq!(&item_mod.submodules()[0].consts()[0].0, "MYSTIC_NUMBER");
|
assert_eq!(&item_mod.sub_modules()[0].consts()[0].0, "MYSTIC_NUMBER");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
item_mod.submodules()[0].consts()[0].2,
|
item_mod.sub_modules()[0].consts()[0].2,
|
||||||
syn::parse2::<syn::Expr>(quote! { 42 }).unwrap()
|
syn::parse2::<syn::Expr>(quote! { 42 }).unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -130,11 +130,11 @@ mod module_tests {
|
|||||||
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
||||||
assert!(item_mod.fns().is_empty());
|
assert!(item_mod.fns().is_empty());
|
||||||
assert!(item_mod.consts().is_empty());
|
assert!(item_mod.consts().is_empty());
|
||||||
assert_eq!(item_mod.submodules().len(), 1);
|
assert_eq!(item_mod.sub_modules().len(), 1);
|
||||||
assert_eq!(item_mod.submodules()[0].fns().len(), 1);
|
assert_eq!(item_mod.sub_modules()[0].fns().len(), 1);
|
||||||
assert!(item_mod.submodules()[0].fns()[0].skipped());
|
assert!(item_mod.sub_modules()[0].fns()[0].skipped());
|
||||||
assert!(item_mod.submodules()[0].consts().is_empty());
|
assert!(item_mod.sub_modules()[0].consts().is_empty());
|
||||||
assert!(item_mod.submodules()[0].submodules().is_empty());
|
assert!(item_mod.sub_modules()[0].sub_modules().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -153,8 +153,8 @@ mod module_tests {
|
|||||||
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
||||||
assert!(item_mod.fns().is_empty());
|
assert!(item_mod.fns().is_empty());
|
||||||
assert!(item_mod.consts().is_empty());
|
assert!(item_mod.consts().is_empty());
|
||||||
assert_eq!(item_mod.submodules().len(), 1);
|
assert_eq!(item_mod.sub_modules().len(), 1);
|
||||||
assert!(item_mod.submodules()[0].skipped());
|
assert!(item_mod.sub_modules()[0].skipped());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -958,7 +958,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_skipped_submodule() {
|
fn one_skipped_sub_module() {
|
||||||
let input_tokens: TokenStream = quote! {
|
let input_tokens: TokenStream = quote! {
|
||||||
pub mod one_fn {
|
pub mod one_fn {
|
||||||
pub fn get_mystic_number() -> INT {
|
pub fn get_mystic_number() -> INT {
|
||||||
|
@ -29,7 +29,7 @@ fn one_fn_module_nested_attr_test() -> Result<(), Box<EvalAltResult>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod one_fn_submodule_nested_attr {
|
pub mod one_fn_sub_module_nested_attr {
|
||||||
use rhai::plugin::*;
|
use rhai::plugin::*;
|
||||||
|
|
||||||
#[export_module]
|
#[export_module]
|
||||||
@ -47,9 +47,9 @@ pub mod one_fn_submodule_nested_attr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_fn_submodule_nested_attr_test() -> Result<(), Box<EvalAltResult>> {
|
fn one_fn_sub_module_nested_attr_test() -> Result<(), Box<EvalAltResult>> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
let m = rhai::exported_module!(crate::one_fn_submodule_nested_attr::advanced_math);
|
let m = rhai::exported_module!(crate::one_fn_sub_module_nested_attr::advanced_math);
|
||||||
engine.register_static_module("Math::Advanced", m.into());
|
engine.register_static_module("Math::Advanced", m.into());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -627,17 +627,17 @@ pub struct Limits {
|
|||||||
|
|
||||||
/// Context of a script evaluation process.
|
/// Context of a script evaluation process.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EvalContext<'e, 'x, 'px: 'x, 'a, 's, 'm, 'pm: 'm, 't, 'pt: 't> {
|
pub struct EvalContext<'e, 'x, 'px: 'x, 'a, 's, 'm, 't, 'pt: 't> {
|
||||||
pub(crate) engine: &'e Engine,
|
pub(crate) engine: &'e Engine,
|
||||||
pub(crate) scope: &'x mut Scope<'px>,
|
pub(crate) scope: &'x mut Scope<'px>,
|
||||||
pub(crate) mods: &'a mut Imports,
|
pub(crate) mods: &'a mut Imports,
|
||||||
pub(crate) state: &'s mut State,
|
pub(crate) state: &'s mut State,
|
||||||
pub(crate) lib: &'m [&'pm Module],
|
pub(crate) lib: &'m [&'m Module],
|
||||||
pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>,
|
pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>,
|
||||||
pub(crate) level: usize,
|
pub(crate) level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> {
|
impl<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> {
|
||||||
/// The current [`Engine`].
|
/// The current [`Engine`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn engine(&self) -> &Engine {
|
pub fn engine(&self) -> &Engine {
|
||||||
|
353
src/fn_call.rs
353
src/fn_call.rs
@ -32,6 +32,9 @@ use crate::FLOAT;
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
@ -798,6 +801,7 @@ impl Engine {
|
|||||||
self.eval_global_statements(scope, mods, &mut new_state, ast.statements(), lib, level);
|
self.eval_global_statements(scope, mods, &mut new_state, ast.statements(), lib, level);
|
||||||
|
|
||||||
state.operations = new_state.operations;
|
state.operations = new_state.operations;
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1067,17 +1071,27 @@ impl Engine {
|
|||||||
if name == KEYWORD_EVAL && args_expr.len() == 1 {
|
if name == KEYWORD_EVAL && args_expr.len() == 1 {
|
||||||
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
|
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
|
||||||
|
|
||||||
|
let script_expr = &args_expr[0];
|
||||||
|
|
||||||
if !self.has_override(Some(mods), Some(state), lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(Some(mods), Some(state), lib, hash_fn, hash_script, pub_only) {
|
||||||
|
let script_pos = script_expr.position();
|
||||||
|
|
||||||
// eval - only in function call style
|
// eval - only in function call style
|
||||||
let prev_len = scope.len();
|
let prev_len = scope.len();
|
||||||
let script =
|
let script =
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
|
self.eval_expr(scope, mods, state, lib, this_ptr, script_expr, level)?;
|
||||||
let script = script.as_str().map_err(|typ| {
|
let script = script.as_str().map_err(|typ| {
|
||||||
self.make_type_mismatch_err::<ImmutableString>(typ, args_expr[0].position())
|
self.make_type_mismatch_err::<ImmutableString>(typ, script_pos)
|
||||||
})?;
|
})?;
|
||||||
let pos = args_expr[0].position();
|
let result = self.eval_script_expr_in_place(
|
||||||
let result =
|
scope,
|
||||||
self.eval_script_expr_in_place(scope, mods, state, lib, script, pos, level + 1);
|
mods,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
script,
|
||||||
|
script_pos,
|
||||||
|
level + 1,
|
||||||
|
);
|
||||||
|
|
||||||
// IMPORTANT! If the eval defines new variables in the current scope,
|
// IMPORTANT! If the eval defines new variables in the current scope,
|
||||||
// all variable offsets from this point on will be mis-aligned.
|
// all variable offsets from this point on will be mis-aligned.
|
||||||
@ -1085,7 +1099,18 @@ impl Engine {
|
|||||||
state.always_search = true;
|
state.always_search = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result.map_err(|err| {
|
||||||
|
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||||
|
KEYWORD_EVAL.to_string(),
|
||||||
|
state
|
||||||
|
.source
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| "", |s| s.as_str())
|
||||||
|
.to_string(),
|
||||||
|
err,
|
||||||
|
pos,
|
||||||
|
))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,33 +1350,115 @@ pub fn run_builtin_binary_op(
|
|||||||
x: &Dynamic,
|
x: &Dynamic,
|
||||||
y: &Dynamic,
|
y: &Dynamic,
|
||||||
) -> Result<Option<Dynamic>, Box<EvalAltResult>> {
|
) -> Result<Option<Dynamic>, Box<EvalAltResult>> {
|
||||||
let args_type = x.type_id();
|
let first_type = x.type_id();
|
||||||
let second_type = y.type_id();
|
let second_type = y.type_id();
|
||||||
|
|
||||||
if second_type != args_type {
|
let type_id = (first_type, second_type);
|
||||||
if args_type == TypeId::of::<char>() && second_type == TypeId::of::<ImmutableString>() {
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
if let Some((x, y)) = if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<FLOAT>()) {
|
||||||
|
Some((x.clone().cast::<FLOAT>(), y.clone().cast::<FLOAT>()))
|
||||||
|
} else if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<INT>()) {
|
||||||
|
Some((x.clone().cast::<FLOAT>(), y.clone().cast::<INT>() as FLOAT))
|
||||||
|
} else if type_id == (TypeId::of::<INT>(), TypeId::of::<FLOAT>()) {
|
||||||
|
Some((x.clone().cast::<INT>() as FLOAT, y.clone().cast::<FLOAT>()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
} {
|
||||||
|
match op {
|
||||||
|
"+" => return Ok(Some((x + y).into())),
|
||||||
|
"-" => return Ok(Some((x - y).into())),
|
||||||
|
"*" => return Ok(Some((x * y).into())),
|
||||||
|
"/" => return Ok(Some((x / y).into())),
|
||||||
|
"%" => return Ok(Some((x % y).into())),
|
||||||
|
"**" => return Ok(Some(x.powf(y).into())),
|
||||||
|
"==" => return Ok(Some((x == y).into())),
|
||||||
|
"!=" => return Ok(Some((x != y).into())),
|
||||||
|
">" => return Ok(Some((x > y).into())),
|
||||||
|
">=" => return Ok(Some((x >= y).into())),
|
||||||
|
"<" => return Ok(Some((x < y).into())),
|
||||||
|
"<=" => return Ok(Some((x <= y).into())),
|
||||||
|
_ => return Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some((x, y)) = if type_id == (TypeId::of::<Decimal>(), TypeId::of::<Decimal>()) {
|
||||||
|
Some((
|
||||||
|
*x.read_lock::<Decimal>().unwrap(),
|
||||||
|
*y.read_lock::<Decimal>().unwrap(),
|
||||||
|
))
|
||||||
|
} else if type_id == (TypeId::of::<Decimal>(), TypeId::of::<INT>()) {
|
||||||
|
Some((
|
||||||
|
*x.read_lock::<Decimal>().unwrap(),
|
||||||
|
y.clone().cast::<INT>().into(),
|
||||||
|
))
|
||||||
|
} else if type_id == (TypeId::of::<INT>(), TypeId::of::<Decimal>()) {
|
||||||
|
Some((
|
||||||
|
x.clone().cast::<INT>().into(),
|
||||||
|
*y.read_lock::<Decimal>().unwrap(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
} {
|
||||||
|
if cfg!(not(feature = "unchecked")) {
|
||||||
|
use crate::packages::arithmetic::decimal_functions::*;
|
||||||
|
|
||||||
|
match op {
|
||||||
|
"+" => return add(x, y).map(Some),
|
||||||
|
"-" => return subtract(x, y).map(Some),
|
||||||
|
"*" => return multiply(x, y).map(Some),
|
||||||
|
"/" => return divide(x, y).map(Some),
|
||||||
|
"%" => return modulo(x, y).map(Some),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match op {
|
||||||
|
"+" => return Ok(Some((x + y).into())),
|
||||||
|
"-" => return Ok(Some((x - y).into())),
|
||||||
|
"*" => return Ok(Some((x * y).into())),
|
||||||
|
"/" => return Ok(Some((x / y).into())),
|
||||||
|
"%" => return Ok(Some((x % y).into())),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match op {
|
||||||
|
"==" => return Ok(Some((x == y).into())),
|
||||||
|
"!=" => return Ok(Some((x != y).into())),
|
||||||
|
">" => return Ok(Some((x > y).into())),
|
||||||
|
">=" => return Ok(Some((x >= y).into())),
|
||||||
|
"<" => return Ok(Some((x < y).into())),
|
||||||
|
"<=" => return Ok(Some((x <= y).into())),
|
||||||
|
_ => return Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if second_type != first_type {
|
||||||
|
if type_id == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
|
||||||
let x = x.clone().cast::<char>();
|
let x = x.clone().cast::<char>();
|
||||||
let y = &*y.read_lock::<ImmutableString>().unwrap();
|
let y = &*y.read_lock::<ImmutableString>().unwrap();
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
"+" => return Ok(Some(format!("{}{}", x, y).into())),
|
"+" => return Ok(Some(format!("{}{}", x, y).into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<ImmutableString>()
|
}
|
||||||
&& second_type == TypeId::of::<char>()
|
|
||||||
{
|
if type_id == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
|
||||||
let x = &*x.read_lock::<ImmutableString>().unwrap();
|
let x = &*x.read_lock::<ImmutableString>().unwrap();
|
||||||
let y = y.clone().cast::<char>();
|
let y = y.clone().cast::<char>();
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
"+" => return Ok(Some((x + y).into())),
|
"+" => return Ok(Some((x + y).into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if args_type == TypeId::of::<INT>() {
|
if first_type == TypeId::of::<INT>() {
|
||||||
let x = x.clone().cast::<INT>();
|
let x = x.clone().cast::<INT>();
|
||||||
let y = y.clone().cast::<INT>();
|
let y = y.clone().cast::<INT>();
|
||||||
|
|
||||||
@ -1393,9 +1500,11 @@ pub fn run_builtin_binary_op(
|
|||||||
"&" => return Ok(Some((x & y).into())),
|
"&" => return Ok(Some((x & y).into())),
|
||||||
"|" => return Ok(Some((x | y).into())),
|
"|" => return Ok(Some((x | y).into())),
|
||||||
"^" => return Ok(Some((x ^ y).into())),
|
"^" => return Ok(Some((x ^ y).into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<bool>() {
|
}
|
||||||
|
|
||||||
|
if first_type == TypeId::of::<bool>() {
|
||||||
let x = x.clone().cast::<bool>();
|
let x = x.clone().cast::<bool>();
|
||||||
let y = y.clone().cast::<bool>();
|
let y = y.clone().cast::<bool>();
|
||||||
|
|
||||||
@ -1405,9 +1514,11 @@ pub fn run_builtin_binary_op(
|
|||||||
"^" => return Ok(Some((x ^ y).into())),
|
"^" => return Ok(Some((x ^ y).into())),
|
||||||
"==" => return Ok(Some((x == y).into())),
|
"==" => return Ok(Some((x == y).into())),
|
||||||
"!=" => return Ok(Some((x != y).into())),
|
"!=" => return Ok(Some((x != y).into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<ImmutableString>() {
|
}
|
||||||
|
|
||||||
|
if first_type == TypeId::of::<ImmutableString>() {
|
||||||
let x = &*x.read_lock::<ImmutableString>().unwrap();
|
let x = &*x.read_lock::<ImmutableString>().unwrap();
|
||||||
let y = &*y.read_lock::<ImmutableString>().unwrap();
|
let y = &*y.read_lock::<ImmutableString>().unwrap();
|
||||||
|
|
||||||
@ -1419,9 +1530,11 @@ pub fn run_builtin_binary_op(
|
|||||||
">=" => return Ok(Some((x >= y).into())),
|
">=" => return Ok(Some((x >= y).into())),
|
||||||
"<" => return Ok(Some((x < y).into())),
|
"<" => return Ok(Some((x < y).into())),
|
||||||
"<=" => return Ok(Some((x <= y).into())),
|
"<=" => return Ok(Some((x <= y).into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<char>() {
|
}
|
||||||
|
|
||||||
|
if first_type == TypeId::of::<char>() {
|
||||||
let x = x.clone().cast::<char>();
|
let x = x.clone().cast::<char>();
|
||||||
let y = y.clone().cast::<char>();
|
let y = y.clone().cast::<char>();
|
||||||
|
|
||||||
@ -1433,73 +1546,15 @@ pub fn run_builtin_binary_op(
|
|||||||
">=" => return Ok(Some((x >= y).into())),
|
">=" => return Ok(Some((x >= y).into())),
|
||||||
"<" => return Ok(Some((x < y).into())),
|
"<" => return Ok(Some((x < y).into())),
|
||||||
"<=" => return Ok(Some((x <= y).into())),
|
"<=" => return Ok(Some((x <= y).into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<()>() {
|
}
|
||||||
|
|
||||||
|
if first_type == TypeId::of::<()>() {
|
||||||
match op {
|
match op {
|
||||||
"==" => return Ok(Some(true.into())),
|
"==" => return Ok(Some(true.into())),
|
||||||
"!=" | ">" | ">=" | "<" | "<=" => return Ok(Some(false.into())),
|
"!=" | ">" | ">=" | "<" | "<=" => return Ok(Some(false.into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
if args_type == TypeId::of::<FLOAT>() {
|
|
||||||
let x = x.clone().cast::<FLOAT>();
|
|
||||||
let y = y.clone().cast::<FLOAT>();
|
|
||||||
|
|
||||||
match op {
|
|
||||||
"+" => return Ok(Some((x + y).into())),
|
|
||||||
"-" => return Ok(Some((x - y).into())),
|
|
||||||
"*" => return Ok(Some((x * y).into())),
|
|
||||||
"/" => return Ok(Some((x / y).into())),
|
|
||||||
"%" => return Ok(Some((x % y).into())),
|
|
||||||
"**" => return Ok(Some(x.powf(y).into())),
|
|
||||||
"==" => return Ok(Some((x == y).into())),
|
|
||||||
"!=" => return Ok(Some((x != y).into())),
|
|
||||||
">" => return Ok(Some((x > y).into())),
|
|
||||||
">=" => return Ok(Some((x >= y).into())),
|
|
||||||
"<" => return Ok(Some((x < y).into())),
|
|
||||||
"<=" => return Ok(Some((x <= y).into())),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
if args_type == TypeId::of::<rust_decimal::Decimal>() {
|
|
||||||
let x = x.clone().cast::<rust_decimal::Decimal>();
|
|
||||||
let y = y.clone().cast::<rust_decimal::Decimal>();
|
|
||||||
|
|
||||||
if cfg!(not(feature = "unchecked")) {
|
|
||||||
use crate::packages::arithmetic::decimal_functions::*;
|
|
||||||
|
|
||||||
match op {
|
|
||||||
"+" => return add(x, y).map(Some),
|
|
||||||
"-" => return subtract(x, y).map(Some),
|
|
||||||
"*" => return multiply(x, y).map(Some),
|
|
||||||
"/" => return divide(x, y).map(Some),
|
|
||||||
"%" => return modulo(x, y).map(Some),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match op {
|
|
||||||
"+" => return Ok(Some((x + y).into())),
|
|
||||||
"-" => return Ok(Some((x - y).into())),
|
|
||||||
"*" => return Ok(Some((x * y).into())),
|
|
||||||
"/" => return Ok(Some((x / y).into())),
|
|
||||||
"%" => return Ok(Some((x % y).into())),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match op {
|
|
||||||
"==" => return Ok(Some((x == y).into())),
|
|
||||||
"!=" => return Ok(Some((x != y).into())),
|
|
||||||
">" => return Ok(Some((x > y).into())),
|
|
||||||
">=" => return Ok(Some((x >= y).into())),
|
|
||||||
"<" => return Ok(Some((x < y).into())),
|
|
||||||
"<=" => return Ok(Some((x <= y).into())),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1512,24 +1567,80 @@ pub fn run_builtin_op_assignment(
|
|||||||
x: &mut Dynamic,
|
x: &mut Dynamic,
|
||||||
y: &Dynamic,
|
y: &Dynamic,
|
||||||
) -> Result<Option<()>, Box<EvalAltResult>> {
|
) -> Result<Option<()>, Box<EvalAltResult>> {
|
||||||
let args_type = x.type_id();
|
let first_type = x.type_id();
|
||||||
let second_type = y.type_id();
|
let second_type = y.type_id();
|
||||||
|
|
||||||
if second_type != args_type {
|
let type_id = (first_type, second_type);
|
||||||
if args_type == TypeId::of::<ImmutableString>() && second_type == TypeId::of::<char>() {
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
if let Some((mut x, y)) = if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<FLOAT>()) {
|
||||||
|
let y = y.clone().cast::<FLOAT>();
|
||||||
|
Some((x.write_lock::<FLOAT>().unwrap(), y))
|
||||||
|
} else if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<INT>()) {
|
||||||
|
let y = y.clone().cast::<INT>() as FLOAT;
|
||||||
|
Some((x.write_lock::<FLOAT>().unwrap(), y))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
} {
|
||||||
|
match op {
|
||||||
|
"+=" => return Ok(Some(*x += y)),
|
||||||
|
"-=" => return Ok(Some(*x -= y)),
|
||||||
|
"*=" => return Ok(Some(*x *= y)),
|
||||||
|
"/=" => return Ok(Some(*x /= y)),
|
||||||
|
"%=" => return Ok(Some(*x %= y)),
|
||||||
|
"**=" => return Ok(Some(*x = x.powf(y))),
|
||||||
|
_ => return Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if let Some((mut x, y)) = if type_id == (TypeId::of::<Decimal>(), TypeId::of::<Decimal>()) {
|
||||||
|
let y = *y.read_lock::<Decimal>().unwrap();
|
||||||
|
Some((x.write_lock::<Decimal>().unwrap(), y))
|
||||||
|
} else if type_id == (TypeId::of::<Decimal>(), TypeId::of::<INT>()) {
|
||||||
|
let y = y.clone().cast::<INT>().into();
|
||||||
|
Some((x.write_lock::<Decimal>().unwrap(), y))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
} {
|
||||||
|
if cfg!(not(feature = "unchecked")) {
|
||||||
|
use crate::packages::arithmetic::decimal_functions::*;
|
||||||
|
|
||||||
|
match op {
|
||||||
|
"+=" => return Ok(Some(*x = add(*x, y)?.as_decimal().unwrap())),
|
||||||
|
"-=" => return Ok(Some(*x = subtract(*x, y)?.as_decimal().unwrap())),
|
||||||
|
"*=" => return Ok(Some(*x = multiply(*x, y)?.as_decimal().unwrap())),
|
||||||
|
"/=" => return Ok(Some(*x = divide(*x, y)?.as_decimal().unwrap())),
|
||||||
|
"%=" => return Ok(Some(*x = modulo(*x, y)?.as_decimal().unwrap())),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match op {
|
||||||
|
"+=" => return Ok(Some(*x += y)),
|
||||||
|
"-=" => return Ok(Some(*x -= y)),
|
||||||
|
"*=" => return Ok(Some(*x *= y)),
|
||||||
|
"/=" => return Ok(Some(*x /= y)),
|
||||||
|
"%=" => return Ok(Some(*x %= y)),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if second_type != first_type {
|
||||||
|
if type_id == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
|
||||||
let y = y.read_lock::<char>().unwrap().deref().clone();
|
let y = y.read_lock::<char>().unwrap().deref().clone();
|
||||||
let mut x = x.write_lock::<ImmutableString>().unwrap();
|
let mut x = x.write_lock::<ImmutableString>().unwrap();
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
"+=" => return Ok(Some(*x += y)),
|
"+=" => return Ok(Some(*x += y)),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if args_type == TypeId::of::<INT>() {
|
if first_type == TypeId::of::<INT>() {
|
||||||
let y = y.clone().cast::<INT>();
|
let y = y.clone().cast::<INT>();
|
||||||
let mut x = x.write_lock::<INT>().unwrap();
|
let mut x = x.write_lock::<INT>().unwrap();
|
||||||
|
|
||||||
@ -1565,76 +1676,38 @@ pub fn run_builtin_op_assignment(
|
|||||||
"&=" => return Ok(Some(*x &= y)),
|
"&=" => return Ok(Some(*x &= y)),
|
||||||
"|=" => return Ok(Some(*x |= y)),
|
"|=" => return Ok(Some(*x |= y)),
|
||||||
"^=" => return Ok(Some(*x ^= y)),
|
"^=" => return Ok(Some(*x ^= y)),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<bool>() {
|
}
|
||||||
|
|
||||||
|
if first_type == TypeId::of::<bool>() {
|
||||||
let y = y.clone().cast::<bool>();
|
let y = y.clone().cast::<bool>();
|
||||||
let mut x = x.write_lock::<bool>().unwrap();
|
let mut x = x.write_lock::<bool>().unwrap();
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
"&=" => return Ok(Some(*x = *x && y)),
|
"&=" => return Ok(Some(*x = *x && y)),
|
||||||
"|=" => return Ok(Some(*x = *x || y)),
|
"|=" => return Ok(Some(*x = *x || y)),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<char>() {
|
}
|
||||||
|
|
||||||
|
if first_type == TypeId::of::<char>() {
|
||||||
let y = y.read_lock::<char>().unwrap().deref().clone();
|
let y = y.read_lock::<char>().unwrap().deref().clone();
|
||||||
let mut x = x.write_lock::<Dynamic>().unwrap();
|
let mut x = x.write_lock::<Dynamic>().unwrap();
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
"+=" => return Ok(Some(*x = format!("{}{}", *x, y).into())),
|
"+=" => return Ok(Some(*x = format!("{}{}", *x, y).into())),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
} else if args_type == TypeId::of::<ImmutableString>() {
|
}
|
||||||
|
|
||||||
|
if first_type == TypeId::of::<ImmutableString>() {
|
||||||
let y = y.read_lock::<ImmutableString>().unwrap().deref().clone();
|
let y = y.read_lock::<ImmutableString>().unwrap().deref().clone();
|
||||||
let mut x = x.write_lock::<ImmutableString>().unwrap();
|
let mut x = x.write_lock::<ImmutableString>().unwrap();
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
"+=" => return Ok(Some(*x += y)),
|
"+=" => return Ok(Some(*x += y)),
|
||||||
_ => (),
|
_ => return Ok(None),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
if args_type == TypeId::of::<FLOAT>() {
|
|
||||||
let y = y.clone().cast::<FLOAT>();
|
|
||||||
let mut x = x.write_lock::<FLOAT>().unwrap();
|
|
||||||
|
|
||||||
match op {
|
|
||||||
"+=" => return Ok(Some(*x += y)),
|
|
||||||
"-=" => return Ok(Some(*x -= y)),
|
|
||||||
"*=" => return Ok(Some(*x *= y)),
|
|
||||||
"/=" => return Ok(Some(*x /= y)),
|
|
||||||
"%=" => return Ok(Some(*x %= y)),
|
|
||||||
"**=" => return Ok(Some(*x = x.powf(y))),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
if args_type == TypeId::of::<rust_decimal::Decimal>() {
|
|
||||||
let y = y.clone().cast::<rust_decimal::Decimal>();
|
|
||||||
let mut x = x.write_lock::<rust_decimal::Decimal>().unwrap();
|
|
||||||
|
|
||||||
if cfg!(not(feature = "unchecked")) {
|
|
||||||
use crate::packages::arithmetic::decimal_functions::*;
|
|
||||||
|
|
||||||
match op {
|
|
||||||
"+=" => return Ok(Some(*x = add(*x, y)?.as_decimal().unwrap())),
|
|
||||||
"-=" => return Ok(Some(*x = subtract(*x, y)?.as_decimal().unwrap())),
|
|
||||||
"*=" => return Ok(Some(*x = multiply(*x, y)?.as_decimal().unwrap())),
|
|
||||||
"/=" => return Ok(Some(*x = divide(*x, y)?.as_decimal().unwrap())),
|
|
||||||
"%=" => return Ok(Some(*x = modulo(*x, y)?.as_decimal().unwrap())),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match op {
|
|
||||||
"+=" => return Ok(Some(*x += y)),
|
|
||||||
"-=" => return Ok(Some(*x -= y)),
|
|
||||||
"*=" => return Ok(Some(*x *= y)),
|
|
||||||
"/=" => return Ok(Some(*x /= y)),
|
|
||||||
"%=" => return Ok(Some(*x %= y)),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,17 +55,17 @@ pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
|
|||||||
|
|
||||||
/// Context of a native Rust function call.
|
/// Context of a native Rust function call.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct NativeCallContext<'e, 'n, 's, 'a, 'm, 'pm: 'm> {
|
pub struct NativeCallContext<'e, 'n, 's, 'a, 'm> {
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
fn_name: &'n str,
|
fn_name: &'n str,
|
||||||
source: Option<&'s str>,
|
source: Option<&'s str>,
|
||||||
pub(crate) mods: Option<&'a Imports>,
|
pub(crate) mods: Option<&'a Imports>,
|
||||||
pub(crate) lib: &'m [&'pm Module],
|
pub(crate) lib: &'m [&'m Module],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'n, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized>
|
impl<'e, 'n, 's, 'a, 'm, M: AsRef<[&'m Module]> + ?Sized>
|
||||||
From<(&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)>
|
From<(&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)>
|
||||||
for NativeCallContext<'e, 'n, 's, 'a, 'm, 'pm>
|
for NativeCallContext<'e, 'n, 's, 'a, 'm>
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)) -> Self {
|
fn from(value: (&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)) -> Self {
|
||||||
@ -79,8 +79,8 @@ impl<'e, 'n, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'n, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'n str, &'m M)>
|
impl<'e, 'n, 'm, M: AsRef<[&'m Module]> + ?Sized> From<(&'e Engine, &'n str, &'m M)>
|
||||||
for NativeCallContext<'e, 'n, '_, '_, 'm, 'pm>
|
for NativeCallContext<'e, 'n, '_, '_, 'm>
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (&'e Engine, &'n str, &'m M)) -> Self {
|
fn from(value: (&'e Engine, &'n str, &'m M)) -> Self {
|
||||||
@ -94,10 +94,10 @@ impl<'e, 'n, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'n, 's, 'a, 'm, 'pm> NativeCallContext<'e, 'n, 's, 'a, 'm, 'pm> {
|
impl<'e, 'n, 's, 'a, 'm> NativeCallContext<'e, 'n, 's, 'a, 'm> {
|
||||||
/// Create a new [`NativeCallContext`].
|
/// Create a new [`NativeCallContext`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(engine: &'e Engine, fn_name: &'n str, lib: &'m impl AsRef<[&'pm Module]>) -> Self {
|
pub fn new(engine: &'e Engine, fn_name: &'n str, lib: &'m impl AsRef<[&'m Module]>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -116,7 +116,7 @@ impl<'e, 'n, 's, 'a, 'm, 'pm> NativeCallContext<'e, 'n, 's, 'a, 'm, 'pm> {
|
|||||||
fn_name: &'n str,
|
fn_name: &'n str,
|
||||||
source: &'s Option<&str>,
|
source: &'s Option<&str>,
|
||||||
imports: &'a mut Imports,
|
imports: &'a mut Imports,
|
||||||
lib: &'m impl AsRef<[&'pm Module]>,
|
lib: &'m impl AsRef<[&'m Module]>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
|
@ -254,47 +254,47 @@ mod f32_functions {
|
|||||||
pub fn pow_f_f(x: f32, y: f32) -> f32 {
|
pub fn pow_f_f(x: f32, y: f32) -> f32 {
|
||||||
x.powf(y)
|
x.powf(y)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_if(x: INT, y: f32) -> f32 {
|
pub fn add_if(x: INT, y: f32) -> f32 {
|
||||||
(x as f32) + (y as f32)
|
(x as f32) + (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_fi(x: f32, y: INT) -> f32 {
|
pub fn add_fi(x: f32, y: INT) -> f32 {
|
||||||
(x as f32) + (y as f32)
|
(x as f32) + (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
pub fn subtract_if(x: INT, y: f32) -> f32 {
|
pub fn subtract_if(x: INT, y: f32) -> f32 {
|
||||||
(x as f32) - (y as f32)
|
(x as f32) - (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
pub fn subtract_fi(x: f32, y: INT) -> f32 {
|
pub fn subtract_fi(x: f32, y: INT) -> f32 {
|
||||||
(x as f32) - (y as f32)
|
(x as f32) - (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "*")]
|
#[rhai_fn(name = "*")]
|
||||||
pub fn multiply_if(x: INT, y: f32) -> f32 {
|
pub fn multiply_if(x: INT, y: f32) -> f32 {
|
||||||
(x as f32) * (y as f32)
|
(x as f32) * (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "*")]
|
#[rhai_fn(name = "*")]
|
||||||
pub fn multiply_fi(x: f32, y: INT) -> f32 {
|
pub fn multiply_fi(x: f32, y: INT) -> f32 {
|
||||||
(x as f32) * (y as f32)
|
(x as f32) * (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "/")]
|
#[rhai_fn(name = "/")]
|
||||||
pub fn divide_if(x: INT, y: f32) -> f32 {
|
pub fn divide_if(x: INT, y: f32) -> f32 {
|
||||||
(x as f32) / (y as f32)
|
(x as f32) / (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "/")]
|
#[rhai_fn(name = "/")]
|
||||||
pub fn divide_fi(x: f32, y: INT) -> f32 {
|
pub fn divide_fi(x: f32, y: INT) -> f32 {
|
||||||
(x as f32) / (y as f32)
|
(x as f32) / (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "%")]
|
#[rhai_fn(name = "%")]
|
||||||
pub fn modulo_if(x: INT, y: f32) -> f32 {
|
pub fn modulo_if(x: INT, y: f32) -> f32 {
|
||||||
(x as f32) % (y as f32)
|
(x as f32) % (y as f32)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "%")]
|
#[rhai_fn(name = "%")]
|
||||||
pub fn modulo_fi(x: f32, y: INT) -> f32 {
|
pub fn modulo_fi(x: f32, y: INT) -> f32 {
|
||||||
(x as f32) % (y as f32)
|
(x as f32) % (y as f32)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
@ -359,47 +359,47 @@ mod f64_functions {
|
|||||||
pub fn pow_f_f(x: f64, y: f64) -> f64 {
|
pub fn pow_f_f(x: f64, y: f64) -> f64 {
|
||||||
x.powf(y)
|
x.powf(y)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_if(x: INT, y: f64) -> f64 {
|
pub fn add_if(x: INT, y: f64) -> f64 {
|
||||||
(x as f64) + (y as f64)
|
(x as f64) + (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_fi(x: f64, y: INT) -> f64 {
|
pub fn add_fi(x: f64, y: INT) -> f64 {
|
||||||
(x as f64) + (y as f64)
|
(x as f64) + (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
pub fn subtract_if(x: INT, y: f64) -> f64 {
|
pub fn subtract_if(x: INT, y: f64) -> f64 {
|
||||||
(x as f64) - (y as f64)
|
(x as f64) - (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
pub fn subtract_fi(x: f64, y: INT) -> f64 {
|
pub fn subtract_fi(x: f64, y: INT) -> f64 {
|
||||||
(x as f64) - (y as f64)
|
(x as f64) - (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "*")]
|
#[rhai_fn(name = "*")]
|
||||||
pub fn multiply_if(x: INT, y: f64) -> f64 {
|
pub fn multiply_if(x: INT, y: f64) -> f64 {
|
||||||
(x as f64) * (y as f64)
|
(x as f64) * (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "*")]
|
#[rhai_fn(name = "*")]
|
||||||
pub fn multiply_fi(x: f64, y: INT) -> f64 {
|
pub fn multiply_fi(x: f64, y: INT) -> f64 {
|
||||||
(x as f64) * (y as f64)
|
(x as f64) * (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "/")]
|
#[rhai_fn(name = "/")]
|
||||||
pub fn divide_if(x: INT, y: f64) -> f64 {
|
pub fn divide_if(x: INT, y: f64) -> f64 {
|
||||||
(x as f64) / (y as f64)
|
(x as f64) / (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "/")]
|
#[rhai_fn(name = "/")]
|
||||||
pub fn divide_fi(x: f64, y: INT) -> f64 {
|
pub fn divide_fi(x: f64, y: INT) -> f64 {
|
||||||
(x as f64) / (y as f64)
|
(x as f64) / (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "%")]
|
#[rhai_fn(name = "%")]
|
||||||
pub fn modulo_if(x: INT, y: f64) -> f64 {
|
pub fn modulo_if(x: INT, y: f64) -> f64 {
|
||||||
(x as f64) % (y as f64)
|
(x as f64) % (y as f64)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "%")]
|
#[rhai_fn(name = "%")]
|
||||||
pub fn modulo_fi(x: f64, y: INT) -> f64 {
|
pub fn modulo_fi(x: f64, y: INT) -> f64 {
|
||||||
(x as f64) % (y as f64)
|
(x as f64) % (y as f64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
@ -440,61 +440,37 @@ mod f64_functions {
|
|||||||
mod decimal_functions {
|
mod decimal_functions {
|
||||||
use rust_decimal::{prelude::Zero, Decimal};
|
use rust_decimal::{prelude::Zero, Decimal};
|
||||||
|
|
||||||
#[rhai_fn(name = "+", return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn add(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn add(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_add(y)
|
x.checked_add(y)
|
||||||
.ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y)))
|
.ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y)))
|
||||||
.map(Dynamic::from)
|
.map(Into::<Dynamic>::into)
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x + y))
|
Ok(Dynamic::from(x + y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+", return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn add_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
add(x.into(), y)
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "+", return_raw)]
|
|
||||||
pub fn add_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
add(x, y.into())
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "-", return_raw)]
|
|
||||||
pub fn subtract(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn subtract(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_sub(y)
|
x.checked_sub(y)
|
||||||
.ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y)))
|
.ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y)))
|
||||||
.map(Dynamic::from)
|
.map(Into::<Dynamic>::into)
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x - y))
|
Ok(Dynamic::from(x - y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-", return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn subtract_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
subtract(x.into(), y)
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "-", return_raw)]
|
|
||||||
pub fn subtract_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
subtract(x, y.into())
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "*", return_raw)]
|
|
||||||
pub fn multiply(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn multiply(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_mul(y)
|
x.checked_mul(y)
|
||||||
.ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y)))
|
.ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y)))
|
||||||
.map(Dynamic::from)
|
.map(Into::<Dynamic>::into)
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x * y))
|
Ok(Dynamic::from(x * y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "*", return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn multiply_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
multiply(x.into(), y)
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "*", return_raw)]
|
|
||||||
pub fn multiply_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
multiply(x, y.into())
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "/", return_raw)]
|
|
||||||
pub fn divide(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn divide(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
// Detect division by zero
|
// Detect division by zero
|
||||||
@ -503,21 +479,13 @@ mod decimal_functions {
|
|||||||
} else {
|
} else {
|
||||||
x.checked_div(y)
|
x.checked_div(y)
|
||||||
.ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y)))
|
.ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y)))
|
||||||
.map(Dynamic::from)
|
.map(Into::<Dynamic>::into)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x / y))
|
Ok(Dynamic::from(x / y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "/", return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn divide_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
divide(x.into(), y)
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "/", return_raw)]
|
|
||||||
pub fn divide_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
divide(x, y.into())
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "%", return_raw)]
|
|
||||||
pub fn modulo(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn modulo(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_rem(y)
|
x.checked_rem(y)
|
||||||
@ -527,19 +495,11 @@ mod decimal_functions {
|
|||||||
x, y
|
x, y
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.map(Dynamic::from)
|
.map(Into::<Dynamic>::into)
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x % y))
|
Ok(Dynamic::from(x % y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "%", return_raw)]
|
|
||||||
pub fn modulo_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
modulo(x.into(), y)
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "%", return_raw)]
|
|
||||||
pub fn modulo_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
modulo(x, y.into())
|
|
||||||
}
|
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
pub fn neg(x: Decimal) -> Decimal {
|
pub fn neg(x: Decimal) -> Decimal {
|
||||||
-x
|
-x
|
||||||
|
@ -70,13 +70,18 @@ def_package!(crate:LogicPackage:"Logical operators.", lib, {
|
|||||||
{
|
{
|
||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "f32_float"))]
|
||||||
reg_functions!(lib += float; f32);
|
reg_functions!(lib += float; f32);
|
||||||
|
combine_with_exported_module!(lib, "f32", f32_functions);
|
||||||
|
|
||||||
#[cfg(feature = "f32_float")]
|
#[cfg(feature = "f32_float")]
|
||||||
reg_functions!(lib += float; f64);
|
reg_functions!(lib += float; f64);
|
||||||
|
combine_with_exported_module!(lib, "f64", f64_functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
reg_functions!(lib += decimal; Decimal);
|
{
|
||||||
|
reg_functions!(lib += decimal; Decimal);
|
||||||
|
combine_with_exported_module!(lib, "decimal", decimal_functions);
|
||||||
|
}
|
||||||
|
|
||||||
set_exported_fn!(lib, "!", not);
|
set_exported_fn!(lib, "!", not);
|
||||||
});
|
});
|
||||||
@ -106,3 +111,169 @@ gen_cmp_functions!(float => f64);
|
|||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
gen_cmp_functions!(decimal => Decimal);
|
gen_cmp_functions!(decimal => Decimal);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[export_module]
|
||||||
|
mod f32_functions {
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
|
#[rhai_fn(name = "==")]
|
||||||
|
pub fn eq_if(x: INT, y: f32) -> bool {
|
||||||
|
(x as f32) == (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "==")]
|
||||||
|
pub fn eq_fi(x: f32, y: INT) -> bool {
|
||||||
|
(x as f32) == (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "!=")]
|
||||||
|
pub fn neq_if(x: INT, y: f32) -> bool {
|
||||||
|
(x as f32) != (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "!=")]
|
||||||
|
pub fn neq_fi(x: f32, y: INT) -> bool {
|
||||||
|
(x as f32) != (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">")]
|
||||||
|
pub fn gt_if(x: INT, y: f32) -> bool {
|
||||||
|
(x as f32) > (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">")]
|
||||||
|
pub fn gt_fi(x: f32, y: INT) -> bool {
|
||||||
|
(x as f32) > (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">=")]
|
||||||
|
pub fn gte_if(x: INT, y: f32) -> bool {
|
||||||
|
(x as f32) >= (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">=")]
|
||||||
|
pub fn gte_fi(x: f32, y: INT) -> bool {
|
||||||
|
(x as f32) >= (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<")]
|
||||||
|
pub fn lt_if(x: INT, y: f32) -> bool {
|
||||||
|
(x as f32) < (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<")]
|
||||||
|
pub fn lt_fi(x: f32, y: INT) -> bool {
|
||||||
|
(x as f32) < (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<=")]
|
||||||
|
pub fn lte_if(x: INT, y: f32) -> bool {
|
||||||
|
(x as f32) <= (y as f32)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<=")]
|
||||||
|
pub fn lte_fi(x: f32, y: INT) -> bool {
|
||||||
|
(x as f32) <= (y as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[export_module]
|
||||||
|
mod f64_functions {
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
|
#[rhai_fn(name = "==")]
|
||||||
|
pub fn eq_if(x: INT, y: f64) -> bool {
|
||||||
|
(x as f64) == (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "==")]
|
||||||
|
pub fn eq_fi(x: f64, y: INT) -> bool {
|
||||||
|
(x as f64) == (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "!=")]
|
||||||
|
pub fn neq_if(x: INT, y: f64) -> bool {
|
||||||
|
(x as f64) != (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "!=")]
|
||||||
|
pub fn neq_fi(x: f64, y: INT) -> bool {
|
||||||
|
(x as f64) != (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">")]
|
||||||
|
pub fn gt_if(x: INT, y: f64) -> bool {
|
||||||
|
(x as f64) > (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">")]
|
||||||
|
pub fn gt_fi(x: f64, y: INT) -> bool {
|
||||||
|
(x as f64) > (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">=")]
|
||||||
|
pub fn gte_if(x: INT, y: f64) -> bool {
|
||||||
|
(x as f64) >= (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">=")]
|
||||||
|
pub fn gte_fi(x: f64, y: INT) -> bool {
|
||||||
|
(x as f64) >= (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<")]
|
||||||
|
pub fn lt_if(x: INT, y: f64) -> bool {
|
||||||
|
(x as f64) < (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<")]
|
||||||
|
pub fn lt_fi(x: f64, y: INT) -> bool {
|
||||||
|
(x as f64) < (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<=")]
|
||||||
|
pub fn lte_if(x: INT, y: f64) -> bool {
|
||||||
|
(x as f64) <= (y as f64)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<=")]
|
||||||
|
pub fn lte_fi(x: f64, y: INT) -> bool {
|
||||||
|
(x as f64) <= (y as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
#[export_module]
|
||||||
|
mod decimal_functions {
|
||||||
|
use crate::INT;
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
|
#[rhai_fn(name = "==")]
|
||||||
|
pub fn eq_if(x: INT, y: Decimal) -> bool {
|
||||||
|
Decimal::from(x) == y
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "==")]
|
||||||
|
pub fn eq_fi(x: Decimal, y: INT) -> bool {
|
||||||
|
x == Decimal::from(y)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "!=")]
|
||||||
|
pub fn neq_if(x: INT, y: Decimal) -> bool {
|
||||||
|
Decimal::from(x) != y
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "!=")]
|
||||||
|
pub fn neq_fi(x: Decimal, y: INT) -> bool {
|
||||||
|
x != Decimal::from(y)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">")]
|
||||||
|
pub fn gt_if(x: INT, y: Decimal) -> bool {
|
||||||
|
Decimal::from(x) > y
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">")]
|
||||||
|
pub fn gt_fi(x: Decimal, y: INT) -> bool {
|
||||||
|
x > Decimal::from(y)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">=")]
|
||||||
|
pub fn gte_if(x: INT, y: Decimal) -> bool {
|
||||||
|
Decimal::from(x) >= y
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = ">=")]
|
||||||
|
pub fn gte_fi(x: Decimal, y: INT) -> bool {
|
||||||
|
x >= Decimal::from(y)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<")]
|
||||||
|
pub fn lt_if(x: INT, y: Decimal) -> bool {
|
||||||
|
Decimal::from(x) < y
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<")]
|
||||||
|
pub fn lt_fi(x: Decimal, y: INT) -> bool {
|
||||||
|
x < Decimal::from(y)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<=")]
|
||||||
|
pub fn lte_if(x: INT, y: Decimal) -> bool {
|
||||||
|
Decimal::from(x) <= y
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "<=")]
|
||||||
|
pub fn lte_fi(x: Decimal, y: INT) -> bool {
|
||||||
|
x <= Decimal::from(y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3167,48 +3167,20 @@ pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option<Expr> {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value, _) => Some(Expr::FloatConstant(value, pos)),
|
Union::Float(value, _) => Some(Expr::FloatConstant(value, pos)),
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
Union::Decimal(value, _) => Some(Expr::DynamicConstant(Box::new((*value).into()), pos)),
|
||||||
|
|
||||||
Union::Unit(_, _) => Some(Expr::Unit(pos)),
|
Union::Unit(_, _) => Some(Expr::Unit(pos)),
|
||||||
Union::Int(value, _) => Some(Expr::IntegerConstant(value, pos)),
|
Union::Int(value, _) => Some(Expr::IntegerConstant(value, pos)),
|
||||||
Union::Char(value, _) => Some(Expr::CharConstant(value, pos)),
|
Union::Char(value, _) => Some(Expr::CharConstant(value, pos)),
|
||||||
Union::Str(value, _) => Some(Expr::StringConstant(value, pos)),
|
Union::Str(value, _) => Some(Expr::StringConstant(value, pos)),
|
||||||
Union::Bool(value, _) => Some(Expr::BoolConstant(value, pos)),
|
Union::Bool(value, _) => Some(Expr::BoolConstant(value, pos)),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(array, _) => {
|
Union::Array(array, _) => Some(Expr::DynamicConstant(Box::new((*array).into()), pos)),
|
||||||
let items: Vec<_> = array
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| map_dynamic_to_expr(x, pos))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if items.iter().all(Option::is_some) {
|
|
||||||
Some(Expr::Array(
|
|
||||||
Box::new(items.into_iter().map(Option::unwrap).collect()),
|
|
||||||
pos,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(map, _) => {
|
Union::Map(map, _) => Some(Expr::DynamicConstant(Box::new((*map).into()), pos)),
|
||||||
let items: Vec<_> = map
|
|
||||||
.into_iter()
|
|
||||||
.map(|(name, value)| (Ident { name, pos }, map_dynamic_to_expr(value, pos)))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if items.iter().all(|(_, expr)| expr.is_some()) {
|
|
||||||
Some(Expr::Map(
|
|
||||||
Box::new(
|
|
||||||
items
|
|
||||||
.into_iter()
|
|
||||||
.map(|(k, expr)| (k, expr.unwrap()))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
pos,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
14
src/scope.rs
14
src/scope.rs
@ -64,6 +64,20 @@ impl Default for Scope<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for Scope<'a> {
|
||||||
|
type Item = (Cow<'a, str>, Dynamic);
|
||||||
|
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
Box::new(
|
||||||
|
self.values
|
||||||
|
.into_iter()
|
||||||
|
.zip(self.names.into_iter())
|
||||||
|
.map(|(value, (name, _))| (name, value)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Scope<'a> {
|
impl<'a> Scope<'a> {
|
||||||
/// Create a new [`Scope`].
|
/// Create a new [`Scope`].
|
||||||
///
|
///
|
||||||
|
@ -61,7 +61,7 @@ impl Expression<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
|
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
|
||||||
/// Evaluate an [expression tree][Expression].
|
/// Evaluate an [expression tree][Expression].
|
||||||
///
|
///
|
||||||
/// # WARNING - Low Level API
|
/// # WARNING - Low Level API
|
||||||
|
28
src/token.rs
28
src/token.rs
@ -9,6 +9,7 @@ use crate::stdlib::{
|
|||||||
char, fmt, format,
|
char, fmt, format,
|
||||||
iter::Peekable,
|
iter::Peekable,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
|
ops::{Add, AddAssign},
|
||||||
str::{Chars, FromStr},
|
str::{Chars, FromStr},
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
};
|
};
|
||||||
@ -120,7 +121,7 @@ impl Position {
|
|||||||
/// Is this [`Position`] at the beginning of a line?
|
/// Is this [`Position`] at the beginning of a line?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_beginning_of_line(self) -> bool {
|
pub fn is_beginning_of_line(self) -> bool {
|
||||||
self.line == 0 && !self.is_none()
|
self.pos == 0 && !self.is_none()
|
||||||
}
|
}
|
||||||
/// Is there no [`Position`]?
|
/// Is there no [`Position`]?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -154,6 +155,31 @@ impl fmt::Debug for Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add for Position {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
if rhs.is_none() {
|
||||||
|
self
|
||||||
|
} else {
|
||||||
|
Self {
|
||||||
|
line: self.line + rhs.line - 1,
|
||||||
|
pos: if rhs.is_beginning_of_line() {
|
||||||
|
self.pos
|
||||||
|
} else {
|
||||||
|
self.pos + rhs.pos - 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Position {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self + rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ A Rhai language token.
|
/// _(INTERNALS)_ A Rhai language token.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
|
@ -106,7 +106,7 @@ fn test_max_operations_eval() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorTooManyOperations(_)
|
EvalAltResult::ErrorInFunctionCall(_, _, err, _) if matches!(*err, EvalAltResult::ErrorTooManyOperations(_))
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user