Move if_def_fn into CorePackage.
This commit is contained in:
parent
e5c9ca23b5
commit
739dce72e3
@ -104,7 +104,7 @@ This is similar to Rust and many other modern languages, such as JavaScript's `f
|
|||||||
`is_def_fn`
|
`is_def_fn`
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Use `is_def_fn` to detect if a function is defined (and therefore callable), based on its name
|
Use `is_def_fn` to detect if a Rhai function is defined (and therefore callable), based on its name
|
||||||
and the number of parameters.
|
and the number of parameters.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -178,9 +178,7 @@ pub const KEYWORD_FN_PTR_CURRY: &str = "curry";
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
pub const KEYWORD_IS_SHARED: &str = "is_shared";
|
pub const KEYWORD_IS_SHARED: &str = "is_shared";
|
||||||
pub const KEYWORD_IS_DEF_VAR: &str = "is_def_var";
|
pub const KEYWORD_IS_DEF_VAR: &str = "is_def_var";
|
||||||
pub const KEYWORD_IS_DEF_FN: &str = "is_def_fn";
|
|
||||||
pub const KEYWORD_THIS: &str = "this";
|
pub const KEYWORD_THIS: &str = "this";
|
||||||
pub const FN_TO_STRING: &str = "to_string";
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub const FN_GET: &str = "get$";
|
pub const FN_GET: &str = "get$";
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
use crate::ast::{Expr, Stmt};
|
use crate::ast::{Expr, Stmt};
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
search_imports, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
search_imports, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
||||||
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR,
|
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
|
||||||
};
|
};
|
||||||
use crate::fn_native::FnCallArgs;
|
use crate::fn_native::FnCallArgs;
|
||||||
use crate::module::NamespaceRef;
|
use crate::module::NamespaceRef;
|
||||||
@ -419,7 +418,7 @@ impl Engine {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn has_override_by_name_and_arguments(
|
pub(crate) fn has_override_by_name_and_arguments(
|
||||||
&self,
|
&self,
|
||||||
mods: &Imports,
|
mods: Option<&Imports>,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
arg_types: impl AsRef<[TypeId]>,
|
arg_types: impl AsRef<[TypeId]>,
|
||||||
@ -436,7 +435,7 @@ impl Engine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn has_override(
|
pub(crate) fn has_override(
|
||||||
&self,
|
&self,
|
||||||
mods: &Imports,
|
mods: Option<&Imports>,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
hash_fn: u64,
|
hash_fn: u64,
|
||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
@ -454,8 +453,7 @@ impl Engine {
|
|||||||
|| self.packages.contains_fn(hash_script)
|
|| self.packages.contains_fn(hash_script)
|
||||||
|| self.packages.contains_fn(hash_fn)
|
|| self.packages.contains_fn(hash_fn)
|
||||||
// Then check imported modules
|
// Then check imported modules
|
||||||
|| mods.contains_fn(hash_script)
|
|| mods.map(|m| m.contains_fn(hash_script) || m.contains_fn(hash_fn)).unwrap_or(false)
|
||||||
|| mods.contains_fn(hash_fn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform an actual function call, native Rust or scripted, taking care of special functions.
|
/// Perform an actual function call, native Rust or scripted, taking care of special functions.
|
||||||
@ -494,7 +492,7 @@ impl Engine {
|
|||||||
// type_of
|
// type_of
|
||||||
KEYWORD_TYPE_OF
|
KEYWORD_TYPE_OF
|
||||||
if args.len() == 1
|
if args.len() == 1
|
||||||
&& !self.has_override(mods, lib, hash_fn, hash_script, pub_only) =>
|
&& !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) =>
|
||||||
{
|
{
|
||||||
Ok((
|
Ok((
|
||||||
self.map_type_name(args[0].type_name()).to_string().into(),
|
self.map_type_name(args[0].type_name()).to_string().into(),
|
||||||
@ -506,7 +504,7 @@ impl Engine {
|
|||||||
// by a function pointer so it isn't caught at parse time.
|
// by a function pointer so it isn't caught at parse time.
|
||||||
KEYWORD_FN_PTR | KEYWORD_EVAL
|
KEYWORD_FN_PTR | KEYWORD_EVAL
|
||||||
if args.len() == 1
|
if args.len() == 1
|
||||||
&& !self.has_override(mods, lib, hash_fn, hash_script, pub_only) =>
|
&& !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) =>
|
||||||
{
|
{
|
||||||
EvalAltResult::ErrorRuntime(
|
EvalAltResult::ErrorRuntime(
|
||||||
format!(
|
format!(
|
||||||
@ -521,7 +519,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Script-like function found
|
// Script-like function found
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ if self.has_override(mods, lib, 0, hash_script, pub_only) => {
|
_ if self.has_override(Some(mods), lib, 0, hash_script, pub_only) => {
|
||||||
// Get function
|
// Get function
|
||||||
let func = lib
|
let func = lib
|
||||||
.iter()
|
.iter()
|
||||||
@ -856,7 +854,7 @@ impl Engine {
|
|||||||
let hash_fn =
|
let hash_fn =
|
||||||
calc_native_fn_hash(empty(), fn_name, once(TypeId::of::<ImmutableString>()));
|
calc_native_fn_hash(empty(), fn_name, once(TypeId::of::<ImmutableString>()));
|
||||||
|
|
||||||
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) {
|
||||||
// Fn - only in function call style
|
// Fn - only in function call style
|
||||||
return self
|
return self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?
|
||||||
@ -912,7 +910,7 @@ impl Engine {
|
|||||||
|
|
||||||
if name == KEYWORD_FN_PTR_CALL
|
if name == KEYWORD_FN_PTR_CALL
|
||||||
&& args_expr.len() >= 1
|
&& args_expr.len() >= 1
|
||||||
&& !self.has_override(mods, lib, 0, hash_script, pub_only)
|
&& !self.has_override(Some(mods), lib, 0, hash_script, pub_only)
|
||||||
{
|
{
|
||||||
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
|
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
|
||||||
|
|
||||||
@ -942,7 +940,7 @@ impl Engine {
|
|||||||
if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 {
|
if name == KEYWORD_IS_DEF_VAR && 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>()));
|
||||||
|
|
||||||
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) {
|
||||||
let var_name =
|
let var_name =
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
|
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
|
||||||
let var_name = var_name.as_str().map_err(|err| {
|
let var_name = var_name.as_str().map_err(|err| {
|
||||||
@ -952,44 +950,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle is_def_fn()
|
|
||||||
if name == KEYWORD_IS_DEF_FN && args_expr.len() == 2 {
|
|
||||||
let hash_fn = calc_native_fn_hash(
|
|
||||||
empty(),
|
|
||||||
name,
|
|
||||||
[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()]
|
|
||||||
.iter()
|
|
||||||
.cloned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) {
|
|
||||||
let fn_name =
|
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
|
|
||||||
let num_params =
|
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[1], level)?;
|
|
||||||
|
|
||||||
let fn_name = fn_name.as_str().map_err(|err| {
|
|
||||||
self.make_type_mismatch_err::<ImmutableString>(err, args_expr[0].position())
|
|
||||||
})?;
|
|
||||||
let num_params = num_params.as_int().map_err(|err| {
|
|
||||||
self.make_type_mismatch_err::<INT>(err, args_expr[1].position())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
return Ok(if num_params < 0 {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
let hash = calc_script_fn_hash(empty(), fn_name, num_params as usize);
|
|
||||||
lib.iter().any(|&m| m.contains_fn(hash, false))
|
|
||||||
}
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle eval()
|
// Handle eval()
|
||||||
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>()));
|
||||||
|
|
||||||
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) {
|
||||||
// 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 =
|
||||||
|
@ -49,8 +49,8 @@ pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
|
|||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> {
|
pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> {
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
mods: Option<&'a Imports>,
|
pub(crate) mods: Option<&'a Imports>,
|
||||||
lib: &'m [&'pm Module],
|
pub(crate) lib: &'m [&'pm Module],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'a Imports, &'m M)>
|
impl<'e, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'a Imports, &'m M)>
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
//! Module implementing the AST optimizer.
|
//! Module implementing the AST optimizer.
|
||||||
|
|
||||||
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
||||||
use crate::engine::{
|
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||||
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
|
|
||||||
KEYWORD_TYPE_OF,
|
|
||||||
};
|
|
||||||
use crate::fn_call::run_builtin_binary_op;
|
use crate::fn_call::run_builtin_binary_op;
|
||||||
use crate::parser::map_dynamic_to_expr;
|
use crate::parser::map_dynamic_to_expr;
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
@ -467,11 +464,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
||||||
// These keywords are handled specially
|
// These keywords are handled specially
|
||||||
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
||||||
KEYWORD_PRINT, // side effects
|
KEYWORD_PRINT, // side effects
|
||||||
KEYWORD_DEBUG, // side effects
|
KEYWORD_DEBUG, // side effects
|
||||||
KEYWORD_EVAL, // arbitrary scripts
|
KEYWORD_EVAL, // arbitrary scripts
|
||||||
KEYWORD_IS_DEF_FN, // functions collection is volatile
|
|
||||||
KEYWORD_IS_DEF_VAR, // variables scope is volatile
|
|
||||||
];
|
];
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
@ -650,7 +645,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect();
|
let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect();
|
||||||
|
|
||||||
// Search for overloaded operators (can override built-in).
|
// Search for overloaded operators (can override built-in).
|
||||||
if !state.engine.has_override_by_name_and_arguments(&state.engine.global_sub_modules, state.lib, x.name.as_ref(), arg_types.as_ref(), false) {
|
if !state.engine.has_override_by_name_and_arguments(Some(&state.engine.global_sub_modules), state.lib, x.name.as_ref(), arg_types.as_ref(), false) {
|
||||||
if let Some(result) = run_builtin_binary_op(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
if let Some(result) = run_builtin_binary_op(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
||||||
.ok().flatten()
|
.ok().flatten()
|
||||||
.and_then(|result| map_dynamic_to_expr(result, *pos))
|
.and_then(|result| map_dynamic_to_expr(result, *pos))
|
||||||
|
@ -4,9 +4,34 @@ use super::iter_basic::BasicIteratorPackage;
|
|||||||
use super::logic::LogicPackage;
|
use super::logic::LogicPackage;
|
||||||
use super::string_basic::BasicStringPackage;
|
use super::string_basic::BasicStringPackage;
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::fn_native::{CallableFunction, FnCallArgs};
|
||||||
|
use crate::stdlib::{any::TypeId, iter::empty};
|
||||||
|
use crate::{
|
||||||
|
calc_script_fn_hash, def_package, FnAccess, FnNamespace, ImmutableString, NativeCallContext,
|
||||||
|
INT,
|
||||||
|
};
|
||||||
|
|
||||||
def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, {
|
def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, {
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
{
|
||||||
|
let f = |ctx: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
|
let num_params = args[1].clone().cast::<INT>();
|
||||||
|
let fn_name = args[0].as_str().unwrap();
|
||||||
|
|
||||||
|
Ok(if num_params < 0 {
|
||||||
|
false.into()
|
||||||
|
} else {
|
||||||
|
let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize);
|
||||||
|
ctx.engine().has_override(ctx.mods, ctx.lib, 0, hash_script, true).into()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
lib.set_fn("is_def_fn", FnNamespace::Global, FnAccess::Public,
|
||||||
|
Some(&["fn_name: &str", "num_params: INT"]),
|
||||||
|
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()],
|
||||||
|
CallableFunction::from_method(Box::new(f)));
|
||||||
|
}
|
||||||
|
|
||||||
ArithmeticPackage::init(lib);
|
ArithmeticPackage::init(lib);
|
||||||
LogicPackage::init(lib);
|
LogicPackage::init(lib);
|
||||||
BasicStringPackage::init(lib);
|
BasicStringPackage::init(lib);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::engine::{FN_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
use crate::engine::{KEYWORD_DEBUG, KEYWORD_PRINT};
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
@ -32,7 +32,7 @@ macro_rules! gen_functions {
|
|||||||
|
|
||||||
macro_rules! reg_print_functions {
|
macro_rules! reg_print_functions {
|
||||||
($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $(
|
($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $(
|
||||||
set_exported_fn!($mod_name, FN_TO_STRING, $root::$arg_type::to_string_func);
|
set_exported_fn!($mod_name, "to_string", $root::$arg_type::to_string_func);
|
||||||
set_exported_fn!($mod_name, KEYWORD_PRINT, $root::$arg_type::to_string_func);
|
set_exported_fn!($mod_name, KEYWORD_PRINT, $root::$arg_type::to_string_func);
|
||||||
)* }
|
)* }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user