Use NonZeroU64 for function hashes.
This commit is contained in:
parent
c81a59435b
commit
8506640073
17
src/ast.rs
17
src/ast.rs
@ -9,7 +9,7 @@ use crate::stdlib::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
num::NonZeroUsize,
|
num::{NonZeroU64, NonZeroUsize},
|
||||||
ops::{Add, AddAssign},
|
ops::{Add, AddAssign},
|
||||||
string::String,
|
string::String,
|
||||||
vec,
|
vec,
|
||||||
@ -914,10 +914,8 @@ pub struct BinaryExpr {
|
|||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct FnCallExpr {
|
pub struct FnCallExpr {
|
||||||
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
|
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
|
||||||
pub hash: u64,
|
/// None if native Rust only.
|
||||||
/// Call native functions only? Set to [`true`] to skip searching for script-defined function overrides
|
pub hash_script: Option<NonZeroU64>,
|
||||||
/// when it is certain that the function must be native (e.g. an operator).
|
|
||||||
pub native_only: bool,
|
|
||||||
/// Does this function call capture the parent scope?
|
/// Does this function call capture the parent scope?
|
||||||
pub capture: bool,
|
pub capture: bool,
|
||||||
/// Default value when the function is not found, mostly used to provide a default for comparison functions.
|
/// Default value when the function is not found, mostly used to provide a default for comparison functions.
|
||||||
@ -964,7 +962,14 @@ pub enum Expr {
|
|||||||
/// ()
|
/// ()
|
||||||
Unit(Position),
|
Unit(Position),
|
||||||
/// Variable access - (optional index, optional modules, hash, variable name)
|
/// Variable access - (optional index, optional modules, hash, variable name)
|
||||||
Variable(Box<(Option<NonZeroUsize>, Option<Box<NamespaceRef>>, u64, Ident)>),
|
Variable(
|
||||||
|
Box<(
|
||||||
|
Option<NonZeroUsize>,
|
||||||
|
Option<Box<NamespaceRef>>,
|
||||||
|
Option<NonZeroU64>,
|
||||||
|
Ident,
|
||||||
|
)>,
|
||||||
|
),
|
||||||
/// Property access - (getter, setter), prop
|
/// Property access - (getter, setter), prop
|
||||||
Property(Box<((ImmutableString, ImmutableString), Ident)>),
|
Property(Box<((ImmutableString, ImmutableString), Ident)>),
|
||||||
/// { [statement][Stmt] }
|
/// { [statement][Stmt] }
|
||||||
|
@ -19,6 +19,7 @@ use crate::stdlib::{
|
|||||||
fmt, format,
|
fmt, format,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::{empty, once},
|
iter::{empty, once},
|
||||||
|
num::NonZeroU64,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
ops::DerefMut,
|
ops::DerefMut,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -112,24 +113,16 @@ impl Imports {
|
|||||||
}
|
}
|
||||||
/// Does the specified function hash key exist in this stack of imported [modules][Module]?
|
/// Does the specified function hash key exist in this stack of imported [modules][Module]?
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn contains_fn(&self, hash: u64) -> bool {
|
pub fn contains_fn(&self, hash: NonZeroU64) -> bool {
|
||||||
if hash == 0 {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
self.0.iter().any(|(_, m)| m.contains_qualified_fn(hash))
|
self.0.iter().any(|(_, m)| m.contains_qualified_fn(hash))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/// Get specified function via its hash key.
|
/// Get specified function via its hash key.
|
||||||
pub fn get_fn(&self, hash: u64) -> Option<&CallableFunction> {
|
pub fn get_fn(&self, hash: NonZeroU64) -> Option<&CallableFunction> {
|
||||||
if hash == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|(_, m)| m.get_qualified_fn(hash))
|
.find_map(|(_, m)| m.get_qualified_fn(hash))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]?
|
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]?
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn contains_iter(&self, id: TypeId) -> bool {
|
pub fn contains_iter(&self, id: TypeId) -> bool {
|
||||||
@ -478,7 +471,7 @@ pub struct State {
|
|||||||
/// Number of modules loaded.
|
/// Number of modules loaded.
|
||||||
pub modules: usize,
|
pub modules: usize,
|
||||||
/// Cached lookup values for function hashes.
|
/// Cached lookup values for function hashes.
|
||||||
pub functions_cache: HashMap<u64, Option<CallableFunction>, StraightHasherBuilder>,
|
pub functions_cache: HashMap<NonZeroU64, Option<CallableFunction>, StraightHasherBuilder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
@ -870,7 +863,10 @@ impl Engine {
|
|||||||
// Qualified variable
|
// Qualified variable
|
||||||
(_, Some(modules), hash_var, Ident { name, pos }) => {
|
(_, Some(modules), hash_var, Ident { name, pos }) => {
|
||||||
let module = search_imports(mods, state, modules)?;
|
let module = search_imports(mods, state, modules)?;
|
||||||
let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
|
let target =
|
||||||
|
module
|
||||||
|
.get_qualified_var(hash_var.unwrap())
|
||||||
|
.map_err(|mut err| {
|
||||||
match *err {
|
match *err {
|
||||||
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
|
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
|
||||||
*err_name = format!("{}{}", modules, name);
|
*err_name = format!("{}{}", modules, name);
|
||||||
@ -1047,7 +1043,7 @@ impl Engine {
|
|||||||
let args = &mut [target_val, &mut idx_val2, &mut new_val.0];
|
let args = &mut [target_val, &mut idx_val2, &mut new_val.0];
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, FN_IDX_SET, 0, args, is_ref, true, false,
|
mods, state, lib, FN_IDX_SET, None, args, is_ref, true, false,
|
||||||
new_val.1, None, None, level,
|
new_val.1, None, None, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
@ -1083,16 +1079,15 @@ impl Engine {
|
|||||||
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
native_only: native,
|
hash_script: hash,
|
||||||
hash,
|
|
||||||
def_value,
|
def_value,
|
||||||
..
|
..
|
||||||
} = x.as_ref();
|
} = x.as_ref();
|
||||||
let def_value = def_value.as_ref();
|
let def_value = def_value.as_ref();
|
||||||
let args = idx_val.as_fn_call_args();
|
let args = idx_val.as_fn_call_args();
|
||||||
self.make_method_call(
|
self.make_method_call(
|
||||||
mods, state, lib, name, *hash, target, args, def_value, *native, false,
|
mods, state, lib, name, *hash, target, args, def_value, false, *pos,
|
||||||
*pos, level,
|
level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
@ -1126,7 +1121,7 @@ impl Engine {
|
|||||||
let mut new_val = new_val;
|
let mut new_val = new_val;
|
||||||
let mut args = [target_val, &mut new_val.as_mut().unwrap().0];
|
let mut args = [target_val, &mut new_val.as_mut().unwrap().0];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, setter, 0, &mut args, is_ref, true, false, *pos,
|
mods, state, lib, setter, None, &mut args, is_ref, true, false, *pos,
|
||||||
None, None, level,
|
None, None, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| (v, true))
|
.map(|(v, _)| (v, true))
|
||||||
@ -1137,7 +1132,7 @@ impl Engine {
|
|||||||
let ((getter, _), Ident { pos, .. }) = x.as_ref();
|
let ((getter, _), Ident { pos, .. }) = x.as_ref();
|
||||||
let mut args = [target_val];
|
let mut args = [target_val];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, getter, 0, &mut args, is_ref, true, false, *pos,
|
mods, state, lib, getter, None, &mut args, is_ref, true, false, *pos,
|
||||||
None, None, level,
|
None, None, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| (v, false))
|
.map(|(v, _)| (v, false))
|
||||||
@ -1158,16 +1153,15 @@ impl Engine {
|
|||||||
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
native_only: native,
|
hash_script: hash,
|
||||||
hash,
|
|
||||||
def_value,
|
def_value,
|
||||||
..
|
..
|
||||||
} = x.as_ref();
|
} = x.as_ref();
|
||||||
let def_value = def_value.as_ref();
|
let def_value = def_value.as_ref();
|
||||||
let args = idx_val.as_fn_call_args();
|
let args = idx_val.as_fn_call_args();
|
||||||
let (val, _) = self.make_method_call(
|
let (val, _) = self.make_method_call(
|
||||||
mods, state, lib, name, *hash, target, args, def_value,
|
mods, state, lib, name, *hash, target, args, def_value, false,
|
||||||
*native, false, *pos, level,
|
*pos, level,
|
||||||
)?;
|
)?;
|
||||||
val.into()
|
val.into()
|
||||||
}
|
}
|
||||||
@ -1193,7 +1187,7 @@ impl Engine {
|
|||||||
let args = &mut arg_values[..1];
|
let args = &mut arg_values[..1];
|
||||||
let (mut val, updated) = self
|
let (mut val, updated) = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
mods, state, lib, getter, 0, args, is_ref, true, false,
|
mods, state, lib, getter, None, args, is_ref, true, false,
|
||||||
*pos, None, None, level,
|
*pos, None, None, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))?;
|
.map_err(|err| err.fill_position(*pos))?;
|
||||||
@ -1220,7 +1214,7 @@ impl Engine {
|
|||||||
// Re-use args because the first &mut parameter will not be consumed
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
arg_values[1] = val;
|
arg_values[1] = val;
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, setter, 0, arg_values, is_ref, true,
|
mods, state, lib, setter, None, arg_values, is_ref, true,
|
||||||
false, *pos, None, None, level,
|
false, *pos, None, None, level,
|
||||||
)
|
)
|
||||||
.or_else(
|
.or_else(
|
||||||
@ -1240,16 +1234,15 @@ impl Engine {
|
|||||||
Expr::FnCall(f, pos) if f.namespace.is_none() => {
|
Expr::FnCall(f, pos) if f.namespace.is_none() => {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
native_only: native,
|
hash_script: hash,
|
||||||
hash,
|
|
||||||
def_value,
|
def_value,
|
||||||
..
|
..
|
||||||
} = f.as_ref();
|
} = f.as_ref();
|
||||||
let def_value = def_value.as_ref();
|
let def_value = def_value.as_ref();
|
||||||
let args = idx_val.as_fn_call_args();
|
let args = idx_val.as_fn_call_args();
|
||||||
let (mut val, _) = self.make_method_call(
|
let (mut val, _) = self.make_method_call(
|
||||||
mods, state, lib, name, *hash, target, args, def_value,
|
mods, state, lib, name, *hash, target, args, def_value, false,
|
||||||
*native, false, *pos, level,
|
*pos, level,
|
||||||
)?;
|
)?;
|
||||||
let val = &mut val;
|
let val = &mut val;
|
||||||
let target = &mut val.into();
|
let target = &mut val.into();
|
||||||
@ -1501,8 +1494,8 @@ impl Engine {
|
|||||||
let mut idx = idx;
|
let mut idx = idx;
|
||||||
let args = &mut [target, &mut idx];
|
let args = &mut [target, &mut idx];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
_mods, state, _lib, FN_IDX_GET, 0, args, _is_ref, true, false, idx_pos, None,
|
_mods, state, _lib, FN_IDX_GET, None, args, _is_ref, true, false, idx_pos,
|
||||||
None, _level,
|
None, None, _level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v.into())
|
.map(|(v, _)| v.into())
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
@ -1553,7 +1546,8 @@ impl Engine {
|
|||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
||||||
let hash =
|
let hash =
|
||||||
calc_native_fn_hash(empty(), OP_EQUALS, args.iter().map(|a| a.type_id()));
|
calc_native_fn_hash(empty(), OP_EQUALS, args.iter().map(|a| a.type_id()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let pos = rhs.position();
|
let pos = rhs.position();
|
||||||
|
|
||||||
@ -1680,7 +1674,7 @@ impl Engine {
|
|||||||
let ((getter, _), Ident { pos, .. }) = p.as_ref();
|
let ((getter, _), Ident { pos, .. }) = p.as_ref();
|
||||||
let mut args = [target.as_mut()];
|
let mut args = [target.as_mut()];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, getter, 0, &mut args, is_ref, true, false, *pos,
|
mods, state, lib, getter, None, &mut args, is_ref, true, false, *pos,
|
||||||
None, None, level,
|
None, None, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| (v.into(), *pos))
|
.map(|(v, _)| (v.into(), *pos))
|
||||||
@ -1778,17 +1772,16 @@ impl Engine {
|
|||||||
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
native_only: native,
|
|
||||||
capture: cap_scope,
|
capture: cap_scope,
|
||||||
hash,
|
hash_script: hash,
|
||||||
args,
|
args,
|
||||||
def_value,
|
def_value,
|
||||||
..
|
..
|
||||||
} = x.as_ref();
|
} = x.as_ref();
|
||||||
let def_value = def_value.as_ref();
|
let def_value = def_value.as_ref();
|
||||||
self.make_function_call(
|
self.make_function_call(
|
||||||
scope, mods, state, lib, this_ptr, name, args, def_value, *hash, *native,
|
scope, mods, state, lib, this_ptr, name, args, def_value, *hash, false, *pos,
|
||||||
false, *pos, *cap_scope, level,
|
*cap_scope, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1797,15 +1790,16 @@ impl Engine {
|
|||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
namespace,
|
namespace,
|
||||||
hash,
|
hash_script: hash,
|
||||||
args,
|
args,
|
||||||
def_value,
|
def_value,
|
||||||
..
|
..
|
||||||
} = x.as_ref();
|
} = x.as_ref();
|
||||||
let namespace = namespace.as_ref().map(|v| v.as_ref());
|
let namespace = namespace.as_ref().map(|v| v.as_ref());
|
||||||
|
let hash = hash.unwrap();
|
||||||
let def_value = def_value.as_ref();
|
let def_value = def_value.as_ref();
|
||||||
self.make_qualified_function_call(
|
self.make_qualified_function_call(
|
||||||
scope, mods, state, lib, this_ptr, namespace, name, args, def_value, *hash,
|
scope, mods, state, lib, this_ptr, namespace, name, args, def_value, hash,
|
||||||
*pos, level,
|
*pos, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1966,7 +1960,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
||||||
let arg_types = once(lhs_ptr.as_mut().type_id()).chain(once(rhs_val.type_id()));
|
let arg_types = once(lhs_ptr.as_mut().type_id()).chain(once(rhs_val.type_id()));
|
||||||
let hash_fn = calc_native_fn_hash(empty(), op, arg_types);
|
let hash_fn = calc_native_fn_hash(empty(), op, arg_types).unwrap();
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.global_namespace
|
.global_namespace
|
||||||
@ -2015,8 +2009,8 @@ impl Engine {
|
|||||||
|
|
||||||
// Run function
|
// Run function
|
||||||
let (value, _) = self.exec_fn_call(
|
let (value, _) = self.exec_fn_call(
|
||||||
mods, state, lib, op, 0, args, false, false, false, *op_pos, None,
|
mods, state, lib, op, None, args, false, false, false, *op_pos,
|
||||||
None, level,
|
None, None, level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let value = value.flatten();
|
let value = value.flatten();
|
||||||
@ -2051,7 +2045,7 @@ impl Engine {
|
|||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
mods, state, lib, op, 0, args, false, false, false, *op_pos, None,
|
mods, state, lib, op, None, args, false, false, false, *op_pos, None,
|
||||||
None, level,
|
None, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)?;
|
.map(|(v, _)| v)?;
|
||||||
|
@ -15,6 +15,7 @@ use crate::stdlib::{
|
|||||||
format,
|
format,
|
||||||
iter::{empty, once},
|
iter::{empty, once},
|
||||||
mem,
|
mem,
|
||||||
|
num::NonZeroU64,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
string::ToString,
|
string::ToString,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
@ -161,7 +162,7 @@ impl Engine {
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
hash_fn: u64,
|
hash_fn: NonZeroU64,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
@ -453,22 +454,22 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
mods: Option<&Imports>,
|
mods: Option<&Imports>,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
hash_fn: u64,
|
hash_fn: Option<NonZeroU64>,
|
||||||
hash_script: u64,
|
hash_script: Option<NonZeroU64>,
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// First check script-defined functions
|
// First check script-defined functions
|
||||||
(hash_script != 0 && lib.iter().any(|&m| m.contains_fn(hash_script, pub_only)))
|
hash_script.map(|hash| lib.iter().any(|&m| m.contains_fn(hash, pub_only))).unwrap_or(false)
|
||||||
//|| lib.iter().any(|&m| m.contains_fn(hash_fn, pub_only))
|
//|| hash_fn.map(|hash| lib.iter().any(|&m| m.contains_fn(hash, pub_only))).unwrap_or(false)
|
||||||
// Then check registered functions
|
// Then check registered functions
|
||||||
//|| (hash_script != 0 && self.global_namespace.contains_fn(hash_script, pub_only))
|
//|| hash_script.map(|hash| self.global_namespace.contains_fn(hash, pub_only)).unwrap_or(false)
|
||||||
|| self.global_namespace.contains_fn(hash_fn, false)
|
|| hash_fn.map(|hash| self.global_namespace.contains_fn(hash, false)).unwrap_or(false)
|
||||||
// Then check packages
|
// Then check packages
|
||||||
|| (hash_script != 0 && self.global_modules.iter().any(|m| m.contains_fn(hash_script, false)))
|
|| hash_script.map(|hash| self.global_modules.iter().any(|m| m.contains_fn(hash, false))).unwrap_or(false)
|
||||||
|| self.global_modules.iter().any(|m| m.contains_fn(hash_fn, false))
|
|| hash_fn.map(|hash| self.global_modules.iter().any(|m| m.contains_fn(hash, false))).unwrap_or(false)
|
||||||
// Then check imported modules
|
// Then check imported modules
|
||||||
|| (hash_script != 0 && mods.map(|m| m.contains_fn(hash_script)).unwrap_or(false))
|
|| hash_script.map(|hash| mods.map(|m| m.contains_fn(hash)).unwrap_or(false)).unwrap_or(false)
|
||||||
|| mods.map(|m| m.contains_fn(hash_fn)).unwrap_or(false)
|
|| hash_fn.map(|hash| mods.map(|m| m.contains_fn(hash)).unwrap_or(false)).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
@ -484,7 +485,7 @@ impl Engine {
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
hash_script: u64,
|
hash_script: Option<NonZeroU64>,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
_is_method: bool,
|
_is_method: bool,
|
||||||
@ -534,9 +535,11 @@ impl Engine {
|
|||||||
|
|
||||||
// Script-like function found
|
// Script-like function found
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ if hash_script != 0
|
_ if hash_script.is_some()
|
||||||
&& self.has_override(Some(mods), lib, 0, hash_script, pub_only) =>
|
&& self.has_override(Some(mods), lib, None, hash_script, pub_only) =>
|
||||||
{
|
{
|
||||||
|
let hash_script = hash_script.unwrap();
|
||||||
|
|
||||||
// Get function
|
// Get function
|
||||||
let (func, mut source) = lib
|
let (func, mut source) = lib
|
||||||
.iter()
|
.iter()
|
||||||
@ -636,7 +639,16 @@ impl Engine {
|
|||||||
|
|
||||||
// Normal native function call
|
// Normal native function call
|
||||||
_ => self.call_native_fn(
|
_ => self.call_native_fn(
|
||||||
mods, state, lib, fn_name, hash_fn, args, is_ref, pub_only, pos, def_val,
|
mods,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
fn_name,
|
||||||
|
hash_fn.unwrap(),
|
||||||
|
args,
|
||||||
|
is_ref,
|
||||||
|
pub_only,
|
||||||
|
pos,
|
||||||
|
def_val,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,11 +735,10 @@ impl Engine {
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
hash_script: u64,
|
hash_script: Option<NonZeroU64>,
|
||||||
target: &mut crate::engine::Target,
|
target: &mut crate::engine::Target,
|
||||||
mut call_args: StaticVec<Dynamic>,
|
mut call_args: StaticVec<Dynamic>,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
native: bool,
|
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -745,11 +756,7 @@ impl Engine {
|
|||||||
let fn_name = fn_ptr.fn_name();
|
let fn_name = fn_ptr.fn_name();
|
||||||
let args_len = call_args.len() + fn_ptr.curry().len();
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
let hash = if native {
|
let hash = hash_script.and_then(|_| calc_script_fn_hash(empty(), fn_name, args_len));
|
||||||
0
|
|
||||||
} else {
|
|
||||||
calc_script_fn_hash(empty(), fn_name, args_len)
|
|
||||||
};
|
|
||||||
// Arguments are passed as-is, adding the curried arguments
|
// Arguments are passed as-is, adding the curried arguments
|
||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
let mut arg_values = curry
|
let mut arg_values = curry
|
||||||
@ -773,11 +780,7 @@ impl Engine {
|
|||||||
let fn_name = fn_ptr.fn_name();
|
let fn_name = fn_ptr.fn_name();
|
||||||
let args_len = call_args.len() + fn_ptr.curry().len();
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
let hash = if native {
|
let hash = hash_script.and_then(|_| calc_script_fn_hash(empty(), fn_name, args_len));
|
||||||
0
|
|
||||||
} else {
|
|
||||||
calc_script_fn_hash(empty(), fn_name, args_len)
|
|
||||||
};
|
|
||||||
// Replace the first argument with the object pointer, adding the curried arguments
|
// Replace the first argument with the object pointer, adding the curried arguments
|
||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
let mut arg_values = once(obj)
|
let mut arg_values = once(obj)
|
||||||
@ -837,17 +840,14 @@ impl Engine {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, v)| call_args.insert(i, v));
|
.for_each(|(i, v)| call_args.insert(i, v));
|
||||||
// Recalculate the hash based on the new function name and new arguments
|
// Recalculate the hash based on the new function name and new arguments
|
||||||
hash = if native {
|
hash = hash_script
|
||||||
0
|
.and_then(|_| calc_script_fn_hash(empty(), fn_name, call_args.len()));
|
||||||
} else {
|
|
||||||
calc_script_fn_hash(empty(), fn_name, call_args.len())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if native {
|
if hash_script.is_none() {
|
||||||
hash = 0;
|
hash = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attached object pointer in front of the arguments
|
// Attached object pointer in front of the arguments
|
||||||
@ -881,8 +881,7 @@ impl Engine {
|
|||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
args_expr: impl AsRef<[Expr]>,
|
args_expr: impl AsRef<[Expr]>,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
mut hash_script: u64,
|
mut hash_script: Option<NonZeroU64>,
|
||||||
native: bool,
|
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
capture_scope: bool,
|
capture_scope: bool,
|
||||||
@ -951,7 +950,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(Some(mods), lib, 0, hash_script, pub_only)
|
&& !self.has_override(Some(mods), lib, None, 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)?;
|
||||||
|
|
||||||
@ -1071,11 +1070,21 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash = if native { 0 } else { hash_script };
|
|
||||||
let args = args.as_mut();
|
let args = args.as_mut();
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, name, hash, args, is_ref, false, pub_only, pos, capture, def_val,
|
mods,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
name,
|
||||||
|
hash_script,
|
||||||
|
args,
|
||||||
|
is_ref,
|
||||||
|
false,
|
||||||
|
pub_only,
|
||||||
|
pos,
|
||||||
|
capture,
|
||||||
|
def_val,
|
||||||
level,
|
level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
@ -1093,7 +1102,7 @@ impl Engine {
|
|||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
args_expr: impl AsRef<[Expr]>,
|
args_expr: impl AsRef<[Expr]>,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
hash_script: u64,
|
hash_script: NonZeroU64,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
@ -1167,9 +1176,10 @@ impl Engine {
|
|||||||
// 2) Calculate a second hash with no qualifiers, empty function name,
|
// 2) Calculate a second hash with no qualifiers, empty function name,
|
||||||
// and the actual list of argument `TypeId`'.s
|
// and the actual list of argument `TypeId`'.s
|
||||||
let hash_fn_args =
|
let hash_fn_args =
|
||||||
calc_native_fn_hash(empty(), "", args.iter().map(|a| a.type_id()));
|
calc_native_fn_hash(empty(), "", args.iter().map(|a| a.type_id())).unwrap();
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let hash_qualified_fn = hash_script ^ hash_fn_args;
|
let hash_qualified_fn =
|
||||||
|
NonZeroU64::new(hash_script.get() ^ hash_fn_args.get()).unwrap();
|
||||||
|
|
||||||
module.get_qualified_fn(hash_qualified_fn)
|
module.get_qualified_fn(hash_qualified_fn)
|
||||||
}
|
}
|
||||||
|
14
src/lib.rs
14
src/lib.rs
@ -1,14 +1,18 @@
|
|||||||
//! # Rhai - embedded scripting for Rust
|
//! # Rhai - embedded scripting for Rust
|
||||||
//!
|
//!
|
||||||
|
//! ![Rhai logo](https://schungx.github.io/rhai/images/logo/rhai-banner-transparent-colour.svg)
|
||||||
|
//!
|
||||||
//! Rhai is a tiny, simple and fast embedded scripting language for Rust
|
//! Rhai is a tiny, simple and fast embedded scripting language for Rust
|
||||||
//! that gives you a safe and easy way to add scripting to your applications.
|
//! that gives you a safe and easy way to add scripting to your applications.
|
||||||
//! It provides a familiar syntax based on JavaScript and Rust and a simple Rust interface.
|
|
||||||
//! Here is a quick example.
|
|
||||||
//!
|
//!
|
||||||
//! First, the contents of `my_script.rhai`:
|
//! It provides a familiar syntax based on JavaScript+Rust and a simple Rust interface.
|
||||||
|
//!
|
||||||
|
//! # A Quick Example
|
||||||
|
//!
|
||||||
|
//! ## Contents of `my_script.rhai`
|
||||||
//!
|
//!
|
||||||
//! ```,ignore
|
//! ```,ignore
|
||||||
//! // Brute force factorial function
|
//! /// Brute force factorial function
|
||||||
//! fn factorial(x) {
|
//! fn factorial(x) {
|
||||||
//! if x == 1 { return 1; }
|
//! if x == 1 { return 1; }
|
||||||
//! x * factorial(x - 1)
|
//! x * factorial(x - 1)
|
||||||
@ -18,7 +22,7 @@
|
|||||||
//! compute(factorial(10))
|
//! compute(factorial(10))
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! And the Rust part:
|
//! ## The Rust part
|
||||||
//!
|
//!
|
||||||
//! ```,no_run
|
//! ```,no_run
|
||||||
//! use rhai::{Engine, EvalAltResult, RegisterFn};
|
//! use rhai::{Engine, EvalAltResult, RegisterFn};
|
||||||
|
@ -10,6 +10,7 @@ use crate::stdlib::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt, format,
|
fmt, format,
|
||||||
iter::empty,
|
iter::empty,
|
||||||
|
num::NonZeroU64,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
ops::{Add, AddAssign, Deref, DerefMut},
|
ops::{Add, AddAssign, Deref, DerefMut},
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -137,12 +138,12 @@ pub struct Module {
|
|||||||
/// Module variables.
|
/// Module variables.
|
||||||
variables: HashMap<ImmutableString, Dynamic>,
|
variables: HashMap<ImmutableString, Dynamic>,
|
||||||
/// Flattened collection of all module variables, including those in sub-modules.
|
/// Flattened collection of all module variables, including those in sub-modules.
|
||||||
all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>,
|
all_variables: HashMap<NonZeroU64, Dynamic, StraightHasherBuilder>,
|
||||||
/// External Rust functions.
|
/// External Rust functions.
|
||||||
functions: HashMap<u64, FuncInfo, StraightHasherBuilder>,
|
functions: HashMap<NonZeroU64, FuncInfo, StraightHasherBuilder>,
|
||||||
/// Flattened collection of all external Rust functions, native or scripted.
|
/// Flattened collection of all external Rust functions, native or scripted.
|
||||||
/// including those in sub-modules.
|
/// including those in sub-modules.
|
||||||
all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>,
|
all_functions: HashMap<NonZeroU64, CallableFunction, StraightHasherBuilder>,
|
||||||
/// Iterator functions, keyed by the type producing the iterator.
|
/// Iterator functions, keyed by the type producing the iterator.
|
||||||
type_iterators: HashMap<TypeId, IteratorFn>,
|
type_iterators: HashMap<TypeId, IteratorFn>,
|
||||||
/// Flattened collection of iterator functions, including those in sub-modules.
|
/// Flattened collection of iterator functions, including those in sub-modules.
|
||||||
@ -398,29 +399,28 @@ impl Module {
|
|||||||
/// Get a reference to a namespace-qualified variable.
|
/// Get a reference to a namespace-qualified variable.
|
||||||
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated by the function [`crate::calc_native_fn_hash`].
|
/// The [`NonZeroU64`] hash is calculated by the function [`crate::calc_native_fn_hash`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Result<&Dynamic, Box<EvalAltResult>> {
|
pub(crate) fn get_qualified_var(
|
||||||
if hash_var == 0 {
|
&self,
|
||||||
Err(EvalAltResult::ErrorVariableNotFound(String::new(), Position::NONE).into())
|
hash_var: NonZeroU64,
|
||||||
} else {
|
) -> Result<&Dynamic, Box<EvalAltResult>> {
|
||||||
self.all_variables.get(&hash_var).ok_or_else(|| {
|
self.all_variables.get(&hash_var).ok_or_else(|| {
|
||||||
EvalAltResult::ErrorVariableNotFound(String::new(), Position::NONE).into()
|
EvalAltResult::ErrorVariableNotFound(String::new(), Position::NONE).into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a script-defined function into the module.
|
/// Set a script-defined function into the module.
|
||||||
///
|
///
|
||||||
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_script_fn(&mut self, fn_def: impl Into<Shared<ScriptFnDef>>) -> u64 {
|
pub(crate) fn set_script_fn(&mut self, fn_def: impl Into<Shared<ScriptFnDef>>) -> NonZeroU64 {
|
||||||
let fn_def = fn_def.into();
|
let fn_def = fn_def.into();
|
||||||
|
|
||||||
// None + function name + number of arguments.
|
// None + function name + number of arguments.
|
||||||
let num_params = fn_def.params.len();
|
let num_params = fn_def.params.len();
|
||||||
let hash_script = crate::calc_script_fn_hash(empty(), &fn_def.name, num_params);
|
let hash_script = crate::calc_script_fn_hash(empty(), &fn_def.name, num_params).unwrap();
|
||||||
let mut param_names: StaticVec<_> = fn_def.params.iter().cloned().collect();
|
let mut param_names: StaticVec<_> = fn_def.params.iter().cloned().collect();
|
||||||
param_names.push("Dynamic".into());
|
param_names.push("Dynamic".into());
|
||||||
self.functions.insert(
|
self.functions.insert(
|
||||||
@ -526,7 +526,7 @@ impl Module {
|
|||||||
|
|
||||||
/// Does the particular Rust function exist in the module?
|
/// Does the particular Rust function exist in the module?
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated by the function [`crate::calc_native_fn_hash`].
|
/// The [`NonZeroU64`] hash is calculated by the function [`crate::calc_native_fn_hash`].
|
||||||
/// It is also returned by the `set_fn_XXX` calls.
|
/// It is also returned by the `set_fn_XXX` calls.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -539,10 +539,8 @@ impl Module {
|
|||||||
/// assert!(module.contains_fn(hash, true));
|
/// assert!(module.contains_fn(hash, true));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains_fn(&self, hash_fn: u64, public_only: bool) -> bool {
|
pub fn contains_fn(&self, hash_fn: NonZeroU64, public_only: bool) -> bool {
|
||||||
if hash_fn == 0 {
|
if public_only {
|
||||||
false
|
|
||||||
} else if public_only {
|
|
||||||
self.functions
|
self.functions
|
||||||
.get(&hash_fn)
|
.get(&hash_fn)
|
||||||
.map(|FuncInfo { access, .. }| access.is_public())
|
.map(|FuncInfo { access, .. }| access.is_public())
|
||||||
@ -554,7 +552,7 @@ impl Module {
|
|||||||
|
|
||||||
/// Update the metadata (parameter names/types and return type) of a registered function.
|
/// Update the metadata (parameter names/types and return type) of a registered function.
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated either by the function [`crate::calc_native_fn_hash`] or
|
/// The [`NonZeroU64`] hash is calculated either by the function [`crate::calc_native_fn_hash`] or
|
||||||
/// the function [`crate::calc_script_fn_hash`].
|
/// the function [`crate::calc_script_fn_hash`].
|
||||||
///
|
///
|
||||||
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
|
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
|
||||||
@ -563,7 +561,7 @@ impl Module {
|
|||||||
/// In other words, the number of entries should be one larger than the number of parameters.
|
/// In other words, the number of entries should be one larger than the number of parameters.
|
||||||
pub fn update_fn_metadata<'a>(
|
pub fn update_fn_metadata<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hash_fn: u64,
|
hash_fn: NonZeroU64,
|
||||||
arg_names: impl AsRef<[&'a str]>,
|
arg_names: impl AsRef<[&'a str]>,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
||||||
@ -574,9 +572,13 @@ impl Module {
|
|||||||
|
|
||||||
/// Update the namespace of a registered function.
|
/// Update the namespace of a registered function.
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated either by the function [`crate::calc_native_fn_hash`] or
|
/// The [`NonZeroU64`] hash is calculated either by the function [`crate::calc_native_fn_hash`] or
|
||||||
/// the function [`crate::calc_script_fn_hash`].
|
/// the function [`crate::calc_script_fn_hash`].
|
||||||
pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self {
|
pub fn update_fn_namespace(
|
||||||
|
&mut self,
|
||||||
|
hash_fn: NonZeroU64,
|
||||||
|
namespace: FnNamespace,
|
||||||
|
) -> &mut Self {
|
||||||
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
||||||
f.namespace = namespace;
|
f.namespace = namespace;
|
||||||
}
|
}
|
||||||
@ -599,10 +601,11 @@ impl Module {
|
|||||||
arg_names: Option<&[&str]>,
|
arg_names: Option<&[&str]>,
|
||||||
arg_types: &[TypeId],
|
arg_types: &[TypeId],
|
||||||
func: CallableFunction,
|
func: CallableFunction,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
|
|
||||||
let hash_fn = crate::calc_native_fn_hash(empty(), &name, arg_types.iter().cloned());
|
let hash_fn =
|
||||||
|
crate::calc_native_fn_hash(empty(), &name, arg_types.iter().cloned()).unwrap();
|
||||||
|
|
||||||
let param_types = arg_types
|
let param_types = arg_types
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -712,7 +715,7 @@ impl Module {
|
|||||||
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
||||||
+ SendSync
|
+ SendSync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f =
|
let f =
|
||||||
move |ctx: NativeCallContext, args: &mut FnCallArgs| func(ctx, args).map(Dynamic::from);
|
move |ctx: NativeCallContext, args: &mut FnCallArgs| func(ctx, args).map(Dynamic::from);
|
||||||
|
|
||||||
@ -748,7 +751,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, _: &mut FnCallArgs| func().map(Dynamic::from);
|
let f = move |_: NativeCallContext, _: &mut FnCallArgs| func().map(Dynamic::from);
|
||||||
let arg_types = [];
|
let arg_types = [];
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
@ -783,7 +786,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
|
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
@ -823,7 +826,7 @@ impl Module {
|
|||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
namespace: FnNamespace,
|
namespace: FnNamespace,
|
||||||
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
|
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
@ -862,7 +865,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
self.set_fn_1_mut(
|
self.set_fn_1_mut(
|
||||||
crate::engine::make_getter(&name.into()),
|
crate::engine::make_getter(&name.into()),
|
||||||
FnNamespace::Global,
|
FnNamespace::Global,
|
||||||
@ -894,7 +897,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let a = cast_arg::<A>(&mut args[0]);
|
let a = cast_arg::<A>(&mut args[0]);
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
@ -941,7 +944,7 @@ impl Module {
|
|||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
namespace: FnNamespace,
|
namespace: FnNamespace,
|
||||||
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
let a = &mut args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
@ -987,7 +990,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
self.set_fn_2_mut(
|
self.set_fn_2_mut(
|
||||||
crate::engine::make_setter(&name.into()),
|
crate::engine::make_setter(&name.into()),
|
||||||
FnNamespace::Global,
|
FnNamespace::Global,
|
||||||
@ -1026,7 +1029,7 @@ impl Module {
|
|||||||
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||||
panic!("Cannot register indexer for arrays.");
|
panic!("Cannot register indexer for arrays.");
|
||||||
}
|
}
|
||||||
@ -1073,7 +1076,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let a = cast_arg::<A>(&mut args[0]);
|
let a = cast_arg::<A>(&mut args[0]);
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
@ -1126,7 +1129,7 @@ impl Module {
|
|||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
namespace: FnNamespace,
|
namespace: FnNamespace,
|
||||||
func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let b = cast_arg::<B>(&mut args[2]);
|
let b = cast_arg::<B>(&mut args[2]);
|
||||||
let c = cast_arg::<C>(&mut args[3]);
|
let c = cast_arg::<C>(&mut args[3]);
|
||||||
@ -1177,7 +1180,7 @@ impl Module {
|
|||||||
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: impl Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||||
panic!("Cannot register indexer for arrays.");
|
panic!("Cannot register indexer for arrays.");
|
||||||
}
|
}
|
||||||
@ -1249,7 +1252,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
getter: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
getter: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
setter: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
setter: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> (u64, u64) {
|
) -> (NonZeroU64, NonZeroU64) {
|
||||||
(
|
(
|
||||||
self.set_indexer_get_fn(getter),
|
self.set_indexer_get_fn(getter),
|
||||||
self.set_indexer_set_fn(setter),
|
self.set_indexer_set_fn(setter),
|
||||||
@ -1286,7 +1289,7 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let a = cast_arg::<A>(&mut args[0]);
|
let a = cast_arg::<A>(&mut args[0]);
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
@ -1346,7 +1349,7 @@ impl Module {
|
|||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
namespace: FnNamespace,
|
namespace: FnNamespace,
|
||||||
func: impl Fn(&mut A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> NonZeroU64 {
|
||||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
let c = cast_arg::<C>(&mut args[2]);
|
let c = cast_arg::<C>(&mut args[2]);
|
||||||
@ -1373,13 +1376,14 @@ impl Module {
|
|||||||
|
|
||||||
/// Get a Rust function.
|
/// Get a Rust function.
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated by the function [`crate::calc_native_fn_hash`].
|
/// The [`NonZeroU64`] hash is calculated by the function [`crate::calc_native_fn_hash`].
|
||||||
/// It is also returned by the `set_fn_XXX` calls.
|
/// It is also returned by the `set_fn_XXX` calls.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> {
|
pub(crate) fn get_fn(
|
||||||
if hash_fn == 0 {
|
&self,
|
||||||
None
|
hash_fn: NonZeroU64,
|
||||||
} else {
|
public_only: bool,
|
||||||
|
) -> Option<&CallableFunction> {
|
||||||
self.functions
|
self.functions
|
||||||
.get(&hash_fn)
|
.get(&hash_fn)
|
||||||
.and_then(|FuncInfo { access, func, .. }| match access {
|
.and_then(|FuncInfo { access, func, .. }| match access {
|
||||||
@ -1388,34 +1392,28 @@ impl Module {
|
|||||||
FnAccess::Private => None,
|
FnAccess::Private => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Does the particular namespace-qualified function exist in the module?
|
/// Does the particular namespace-qualified function exist in the module?
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated by the function [`crate::calc_native_fn_hash`] and must match
|
/// The [`NonZeroU64`] hash is calculated by the function [`crate::calc_native_fn_hash`] and must match
|
||||||
/// the hash calculated by [`build_index`][Module::build_index].
|
/// the hash calculated by [`build_index`][Module::build_index].
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool {
|
pub fn contains_qualified_fn(&self, hash_fn: NonZeroU64) -> bool {
|
||||||
if hash_fn == 0 {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
self.all_functions.contains_key(&hash_fn)
|
self.all_functions.contains_key(&hash_fn)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a namespace-qualified function.
|
/// Get a namespace-qualified function.
|
||||||
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated by the function [`crate::calc_native_fn_hash`] and must match
|
/// The [`NonZeroU64`] hash is calculated by the function [`crate::calc_native_fn_hash`] and must match
|
||||||
/// the hash calculated by [`build_index`][Module::build_index].
|
/// the hash calculated by [`build_index`][Module::build_index].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
|
pub(crate) fn get_qualified_fn(
|
||||||
if hash_qualified_fn == 0 {
|
&self,
|
||||||
None
|
hash_qualified_fn: NonZeroU64,
|
||||||
} else {
|
) -> Option<&CallableFunction> {
|
||||||
self.all_functions.get(&hash_qualified_fn)
|
self.all_functions.get(&hash_qualified_fn)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Combine another module into this module.
|
/// Combine another module into this module.
|
||||||
/// The other module is consumed to merge into this module.
|
/// The other module is consumed to merge into this module.
|
||||||
@ -1760,8 +1758,8 @@ impl Module {
|
|||||||
fn index_module<'a>(
|
fn index_module<'a>(
|
||||||
module: &'a Module,
|
module: &'a Module,
|
||||||
qualifiers: &mut Vec<&'a str>,
|
qualifiers: &mut Vec<&'a str>,
|
||||||
variables: &mut HashMap<u64, Dynamic, StraightHasherBuilder>,
|
variables: &mut HashMap<NonZeroU64, Dynamic, StraightHasherBuilder>,
|
||||||
functions: &mut HashMap<u64, CallableFunction, StraightHasherBuilder>,
|
functions: &mut HashMap<NonZeroU64, CallableFunction, StraightHasherBuilder>,
|
||||||
type_iterators: &mut HashMap<TypeId, IteratorFn>,
|
type_iterators: &mut HashMap<TypeId, IteratorFn>,
|
||||||
) {
|
) {
|
||||||
module.modules.iter().for_each(|(name, m)| {
|
module.modules.iter().for_each(|(name, m)| {
|
||||||
@ -1775,7 +1773,7 @@ impl Module {
|
|||||||
module.variables.iter().for_each(|(var_name, value)| {
|
module.variables.iter().for_each(|(var_name, value)| {
|
||||||
// Qualifiers + variable name
|
// Qualifiers + variable name
|
||||||
let hash_var =
|
let hash_var =
|
||||||
crate::calc_script_fn_hash(qualifiers.iter().map(|&v| v), var_name, 0);
|
crate::calc_script_fn_hash(qualifiers.iter().map(|&v| v), var_name, 0).unwrap();
|
||||||
variables.insert(hash_var, value.clone());
|
variables.insert(hash_var, value.clone());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1808,7 +1806,8 @@ impl Module {
|
|||||||
|
|
||||||
// Qualifiers + function name + number of arguments.
|
// Qualifiers + function name + number of arguments.
|
||||||
let hash_qualified_script =
|
let hash_qualified_script =
|
||||||
crate::calc_script_fn_hash(qualifiers.iter().cloned(), name, *params);
|
crate::calc_script_fn_hash(qualifiers.iter().cloned(), name, *params)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if !func.is_script() {
|
if !func.is_script() {
|
||||||
assert_eq!(*params, param_types.len());
|
assert_eq!(*params, param_types.len());
|
||||||
@ -1822,9 +1821,12 @@ impl Module {
|
|||||||
empty(),
|
empty(),
|
||||||
"",
|
"",
|
||||||
param_types.iter().cloned(),
|
param_types.iter().cloned(),
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
|
let hash_qualified_fn =
|
||||||
|
NonZeroU64::new(hash_qualified_script.get() ^ hash_fn_args.get())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
functions.insert(hash_qualified_fn, func.clone());
|
functions.insert(hash_qualified_fn, func.clone());
|
||||||
} else if cfg!(not(feature = "no_function")) {
|
} else if cfg!(not(feature = "no_function")) {
|
||||||
@ -1912,7 +1914,7 @@ impl Module {
|
|||||||
/// _(INTERNALS)_ A chain of [module][Module] names to namespace-qualify a variable or function call.
|
/// _(INTERNALS)_ A chain of [module][Module] names to namespace-qualify a variable or function call.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
/// A [`u64`] hash key is cached for quick search purposes.
|
/// A [`NonZeroU64`] hash key is cached for quick search purposes.
|
||||||
///
|
///
|
||||||
/// A [`StaticVec`] is used because most namespace-qualified access contains only one level,
|
/// A [`StaticVec`] is used because most namespace-qualified access contains only one level,
|
||||||
/// and it is wasteful to always allocate a [`Vec`] with one element.
|
/// and it is wasteful to always allocate a [`Vec`] with one element.
|
||||||
|
@ -138,7 +138,7 @@ fn call_fn_with_constant_arguments(
|
|||||||
&mut Default::default(),
|
&mut Default::default(),
|
||||||
state.lib,
|
state.lib,
|
||||||
fn_name,
|
fn_name,
|
||||||
hash_fn,
|
hash_fn.unwrap(),
|
||||||
arg_values.iter_mut().collect::<StaticVec<_>>().as_mut(),
|
arg_values.iter_mut().collect::<StaticVec<_>>().as_mut(),
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
@ -32,7 +32,7 @@ mod fn_ptr_functions {
|
|||||||
} else {
|
} else {
|
||||||
let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize);
|
let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize);
|
||||||
ctx.engine()
|
ctx.engine()
|
||||||
.has_override(ctx.mods, ctx.lib, 0, hash_script, true)
|
.has_override(ctx.mods, ctx.lib, None, hash_script, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ use crate::stdlib::{
|
|||||||
format,
|
format,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::empty,
|
iter::empty,
|
||||||
num::NonZeroUsize,
|
num::{NonZeroU64, NonZeroUsize},
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec,
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
@ -34,7 +34,7 @@ use crate::FnAccess;
|
|||||||
|
|
||||||
type PERR = ParseErrorType;
|
type PERR = ParseErrorType;
|
||||||
|
|
||||||
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
|
type FunctionsLib = HashMap<NonZeroU64, ScriptFnDef, StraightHasherBuilder>;
|
||||||
|
|
||||||
/// A type that encapsulates the current state of the parser.
|
/// A type that encapsulates the current state of the parser.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -335,7 +335,7 @@ fn parse_fn_call(
|
|||||||
Token::RightParen => {
|
Token::RightParen => {
|
||||||
eat_token(input, Token::RightParen);
|
eat_token(input, Token::RightParen);
|
||||||
|
|
||||||
let hash_script = if let Some(modules) = namespace.as_mut() {
|
let mut hash_script = if let Some(modules) = namespace.as_mut() {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules.set_index(state.find_module(&modules[0].name));
|
modules.set_index(state.find_module(&modules[0].name));
|
||||||
|
|
||||||
@ -352,13 +352,17 @@ fn parse_fn_call(
|
|||||||
calc_script_fn_hash(empty(), &id, 0)
|
calc_script_fn_hash(empty(), &id, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// script functions can only be valid identifiers
|
||||||
|
if !is_valid_identifier(id.chars()) {
|
||||||
|
hash_script = None;
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(Expr::FnCall(
|
return Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: id.to_string().into(),
|
name: id.to_string().into(),
|
||||||
native_only: !is_valid_identifier(id.chars()), // script functions can only be valid identifiers
|
|
||||||
capture,
|
capture,
|
||||||
namespace,
|
namespace,
|
||||||
hash: hash_script,
|
hash_script,
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -383,7 +387,7 @@ fn parse_fn_call(
|
|||||||
(Token::RightParen, _) => {
|
(Token::RightParen, _) => {
|
||||||
eat_token(input, Token::RightParen);
|
eat_token(input, Token::RightParen);
|
||||||
|
|
||||||
let hash_script = if let Some(modules) = namespace.as_mut() {
|
let mut hash_script = if let Some(modules) = namespace.as_mut() {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules.set_index(state.find_module(&modules[0].name));
|
modules.set_index(state.find_module(&modules[0].name));
|
||||||
|
|
||||||
@ -400,13 +404,17 @@ fn parse_fn_call(
|
|||||||
calc_script_fn_hash(empty(), &id, args.len())
|
calc_script_fn_hash(empty(), &id, args.len())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// script functions can only be valid identifiers
|
||||||
|
if !is_valid_identifier(id.chars()) {
|
||||||
|
hash_script = None;
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(Expr::FnCall(
|
return Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: id.to_string().into(),
|
name: id.to_string().into(),
|
||||||
native_only: !is_valid_identifier(id.chars()), // script functions can only be valid identifiers
|
|
||||||
capture,
|
capture,
|
||||||
namespace,
|
namespace,
|
||||||
hash: hash_script,
|
hash_script,
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -973,7 +981,7 @@ fn parse_primary(
|
|||||||
name: state.get_interned_string(s),
|
name: state.get_interned_string(s),
|
||||||
pos: settings.pos,
|
pos: settings.pos,
|
||||||
};
|
};
|
||||||
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
Expr::Variable(Box::new((None, None, None, var_name_def)))
|
||||||
}
|
}
|
||||||
// Namespace qualification
|
// Namespace qualification
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -987,7 +995,7 @@ fn parse_primary(
|
|||||||
name: state.get_interned_string(s),
|
name: state.get_interned_string(s),
|
||||||
pos: settings.pos,
|
pos: settings.pos,
|
||||||
};
|
};
|
||||||
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
Expr::Variable(Box::new((None, None, None, var_name_def)))
|
||||||
}
|
}
|
||||||
// Normal variable access
|
// Normal variable access
|
||||||
Token::Identifier(s) => {
|
Token::Identifier(s) => {
|
||||||
@ -996,7 +1004,7 @@ fn parse_primary(
|
|||||||
name: state.get_interned_string(s),
|
name: state.get_interned_string(s),
|
||||||
pos: settings.pos,
|
pos: settings.pos,
|
||||||
};
|
};
|
||||||
Expr::Variable(Box::new((index, None, 0, var_name_def)))
|
Expr::Variable(Box::new((index, None, None, var_name_def)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function call is allowed to have reserved keyword
|
// Function call is allowed to have reserved keyword
|
||||||
@ -1006,7 +1014,7 @@ fn parse_primary(
|
|||||||
name: state.get_interned_string(s),
|
name: state.get_interned_string(s),
|
||||||
pos: settings.pos,
|
pos: settings.pos,
|
||||||
};
|
};
|
||||||
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
Expr::Variable(Box::new((None, None, None, var_name_def)))
|
||||||
} else {
|
} else {
|
||||||
return Err(PERR::Reserved(s).into_err(settings.pos));
|
return Err(PERR::Reserved(s).into_err(settings.pos));
|
||||||
}
|
}
|
||||||
@ -1022,7 +1030,7 @@ fn parse_primary(
|
|||||||
name: state.get_interned_string(s),
|
name: state.get_interned_string(s),
|
||||||
pos: settings.pos,
|
pos: settings.pos,
|
||||||
};
|
};
|
||||||
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
Expr::Variable(Box::new((None, None, None, var_name_def)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1109,7 +1117,7 @@ fn parse_primary(
|
|||||||
name: state.get_interned_string(id2),
|
name: state.get_interned_string(id2),
|
||||||
pos: pos2,
|
pos: pos2,
|
||||||
};
|
};
|
||||||
Expr::Variable(Box::new((index, modules, 0, var_name_def)))
|
Expr::Variable(Box::new((index, modules, None, var_name_def)))
|
||||||
}
|
}
|
||||||
(Token::Reserved(id2), pos2) if is_valid_identifier(id2.chars()) => {
|
(Token::Reserved(id2), pos2) if is_valid_identifier(id2.chars()) => {
|
||||||
return Err(PERR::Reserved(id2).into_err(pos2));
|
return Err(PERR::Reserved(id2).into_err(pos2));
|
||||||
@ -1208,16 +1216,12 @@ fn parse_unary(
|
|||||||
// Call negative function
|
// Call negative function
|
||||||
expr => {
|
expr => {
|
||||||
let op = "-";
|
let op = "-";
|
||||||
let hash = calc_script_fn_hash(empty(), op, 1);
|
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
args.push(expr);
|
args.push(expr);
|
||||||
|
|
||||||
Ok(Expr::FnCall(
|
Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: op.into(),
|
name: op.into(),
|
||||||
native_only: true,
|
|
||||||
namespace: None,
|
|
||||||
hash,
|
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -1238,16 +1242,12 @@ fn parse_unary(
|
|||||||
// Call plus function
|
// Call plus function
|
||||||
expr => {
|
expr => {
|
||||||
let op = "+";
|
let op = "+";
|
||||||
let hash = calc_script_fn_hash(empty(), op, 1);
|
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
args.push(expr);
|
args.push(expr);
|
||||||
|
|
||||||
Ok(Expr::FnCall(
|
Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: op.into(),
|
name: op.into(),
|
||||||
native_only: true,
|
|
||||||
namespace: None,
|
|
||||||
hash,
|
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -1264,13 +1264,10 @@ fn parse_unary(
|
|||||||
args.push(expr);
|
args.push(expr);
|
||||||
|
|
||||||
let op = "!";
|
let op = "!";
|
||||||
let hash = calc_script_fn_hash(empty(), op, 1);
|
|
||||||
|
|
||||||
Ok(Expr::FnCall(
|
Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: op.into(),
|
name: op.into(),
|
||||||
native_only: true,
|
|
||||||
hash,
|
|
||||||
args,
|
args,
|
||||||
def_value: Some(false.into()), // NOT operator, when operating on invalid operand, defaults to false
|
def_value: Some(false.into()), // NOT operator, when operating on invalid operand, defaults to false
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -1310,7 +1307,7 @@ fn parse_unary(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len());
|
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len()).unwrap();
|
||||||
|
|
||||||
lib.insert(hash, func);
|
lib.insert(hash, func);
|
||||||
|
|
||||||
@ -1723,11 +1720,9 @@ fn parse_binary_op(
|
|||||||
|
|
||||||
let cmp_def = Some(false.into());
|
let cmp_def = Some(false.into());
|
||||||
let op = op_token.syntax();
|
let op = op_token.syntax();
|
||||||
let hash = calc_script_fn_hash(empty(), &op, 2);
|
|
||||||
|
|
||||||
let op_base = FnCallExpr {
|
let op_base = FnCallExpr {
|
||||||
name: op,
|
name: op,
|
||||||
native_only: true,
|
|
||||||
capture: false,
|
capture: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -1747,19 +1742,11 @@ fn parse_binary_op(
|
|||||||
| Token::PowerOf
|
| Token::PowerOf
|
||||||
| Token::Ampersand
|
| Token::Ampersand
|
||||||
| Token::Pipe
|
| Token::Pipe
|
||||||
| Token::XOr => Expr::FnCall(
|
| Token::XOr => Expr::FnCall(Box::new(FnCallExpr { args, ..op_base }), pos),
|
||||||
Box::new(FnCallExpr {
|
|
||||||
hash,
|
|
||||||
args,
|
|
||||||
..op_base
|
|
||||||
}),
|
|
||||||
pos,
|
|
||||||
),
|
|
||||||
|
|
||||||
// '!=' defaults to true when passed invalid operands
|
// '!=' defaults to true when passed invalid operands
|
||||||
Token::NotEqualsTo => Expr::FnCall(
|
Token::NotEqualsTo => Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
hash,
|
|
||||||
args,
|
args,
|
||||||
def_value: Some(true.into()),
|
def_value: Some(true.into()),
|
||||||
..op_base
|
..op_base
|
||||||
@ -1774,7 +1761,6 @@ fn parse_binary_op(
|
|||||||
| Token::GreaterThan
|
| Token::GreaterThan
|
||||||
| Token::GreaterThanEqualsTo => Expr::FnCall(
|
| Token::GreaterThanEqualsTo => Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
hash,
|
|
||||||
args,
|
args,
|
||||||
def_value: cmp_def,
|
def_value: cmp_def,
|
||||||
..op_base
|
..op_base
|
||||||
@ -1821,9 +1807,8 @@ fn parse_binary_op(
|
|||||||
// Accept non-native functions for custom operators
|
// Accept non-native functions for custom operators
|
||||||
Expr::FnCall(
|
Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
hash,
|
hash_script: calc_script_fn_hash(empty(), &s, 2),
|
||||||
args,
|
args,
|
||||||
native_only: false,
|
|
||||||
..op_base
|
..op_base
|
||||||
}),
|
}),
|
||||||
pos,
|
pos,
|
||||||
@ -1892,7 +1877,7 @@ fn parse_custom_syntax(
|
|||||||
segments.push(name.clone());
|
segments.push(name.clone());
|
||||||
tokens.push(state.get_interned_string(MARKER_IDENT));
|
tokens.push(state.get_interned_string(MARKER_IDENT));
|
||||||
let var_name_def = Ident { name, pos };
|
let var_name_def = Ident { name, pos };
|
||||||
keywords.push(Expr::Variable(Box::new((None, None, 0, var_name_def))));
|
keywords.push(Expr::Variable(Box::new((None, None, None, var_name_def))));
|
||||||
}
|
}
|
||||||
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
|
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
|
||||||
return Err(PERR::Reserved(s).into_err(pos));
|
return Err(PERR::Reserved(s).into_err(pos));
|
||||||
@ -2549,7 +2534,7 @@ fn parse_stmt(
|
|||||||
let func = parse_fn(input, &mut new_state, lib, access, settings, comments)?;
|
let func = parse_fn(input, &mut new_state, lib, access, settings, comments)?;
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len());
|
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len()).unwrap();
|
||||||
|
|
||||||
lib.insert(hash, func);
|
lib.insert(hash, func);
|
||||||
|
|
||||||
@ -2812,7 +2797,12 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Po
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals.iter().for_each(|x| {
|
externals.iter().for_each(|x| {
|
||||||
args.push(Expr::Variable(Box::new((None, None, 0, x.clone().into()))));
|
args.push(Expr::Variable(Box::new((
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
x.clone().into(),
|
||||||
|
))));
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "no_closure")]
|
#[cfg(feature = "no_closure")]
|
||||||
@ -2822,12 +2812,12 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Po
|
|||||||
|
|
||||||
let curry_func = crate::engine::KEYWORD_FN_PTR_CURRY;
|
let curry_func = crate::engine::KEYWORD_FN_PTR_CURRY;
|
||||||
|
|
||||||
let hash = calc_script_fn_hash(empty(), curry_func, num_externals + 1);
|
let hash_script = calc_script_fn_hash(empty(), curry_func, num_externals + 1);
|
||||||
|
|
||||||
let expr = Expr::FnCall(
|
let expr = Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: curry_func.into(),
|
name: curry_func.into(),
|
||||||
hash,
|
hash_script,
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
29
src/utils.rs
29
src/utils.rs
@ -9,30 +9,31 @@ use crate::stdlib::{
|
|||||||
fmt,
|
fmt,
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
iter::{empty, FromIterator},
|
iter::{empty, FromIterator},
|
||||||
|
num::NonZeroU64,
|
||||||
ops::{Add, AddAssign, Deref},
|
ops::{Add, AddAssign, Deref},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
};
|
};
|
||||||
use crate::Shared;
|
use crate::Shared;
|
||||||
|
|
||||||
/// A hasher that only takes one single [`u64`] and returns it as a hash key.
|
/// A hasher that only takes one single [`NonZeroU64`] and returns it as a hash key.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics when hashing any data type other than a [`u64`].
|
/// Panics when hashing any data type other than a [`NonZeroU64`].
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct StraightHasher(u64);
|
pub struct StraightHasher(NonZeroU64);
|
||||||
|
|
||||||
impl Hasher for StraightHasher {
|
impl Hasher for StraightHasher {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn finish(&self) -> u64 {
|
fn finish(&self) -> u64 {
|
||||||
self.0
|
self.0.get()
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write(&mut self, bytes: &[u8]) {
|
fn write(&mut self, bytes: &[u8]) {
|
||||||
let mut key = [0_u8; 8];
|
let mut key = [0_u8; 8];
|
||||||
key.copy_from_slice(&bytes[..8]); // Panics if fewer than 8 bytes
|
key.copy_from_slice(&bytes[..8]); // Panics if fewer than 8 bytes
|
||||||
self.0 = u64::from_le_bytes(key);
|
self.0 = NonZeroU64::new(u64::from_le_bytes(key)).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,11 +46,11 @@ impl BuildHasher for StraightHasherBuilder {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn build_hasher(&self) -> Self::Hasher {
|
fn build_hasher(&self) -> Self::Hasher {
|
||||||
Default::default()
|
StraightHasher(NonZeroU64::new(1).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ Calculate a [`u64`] hash key from a namespace-qualified function name and parameter types.
|
/// _(INTERNALS)_ Calculate a [`NonZeroU64`] hash key from a namespace-qualified function name and parameter types.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
/// Module names are passed in via `&str` references from an iterator.
|
/// Module names are passed in via `&str` references from an iterator.
|
||||||
@ -63,11 +64,11 @@ pub fn calc_native_fn_hash<'a>(
|
|||||||
modules: impl Iterator<Item = &'a str>,
|
modules: impl Iterator<Item = &'a str>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
params: impl Iterator<Item = TypeId>,
|
params: impl Iterator<Item = TypeId>,
|
||||||
) -> u64 {
|
) -> Option<NonZeroU64> {
|
||||||
calc_fn_hash(modules, fn_name, None, params)
|
calc_fn_hash(modules, fn_name, None, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ Calculate a [`u64`] hash key from a namespace-qualified function name
|
/// _(INTERNALS)_ Calculate a [`NonZeroU64`] hash key from a namespace-qualified function name
|
||||||
/// and the number of parameters, but no parameter types.
|
/// and the number of parameters, but no parameter types.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
@ -82,7 +83,7 @@ pub fn calc_script_fn_hash<'a>(
|
|||||||
modules: impl Iterator<Item = &'a str>,
|
modules: impl Iterator<Item = &'a str>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
num: usize,
|
num: usize,
|
||||||
) -> u64 {
|
) -> Option<NonZeroU64> {
|
||||||
calc_fn_hash(modules, fn_name, Some(num), empty())
|
calc_fn_hash(modules, fn_name, Some(num), empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ pub fn get_hasher() -> impl Hasher {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate a [`u64`] hash key from a namespace-qualified function name and parameter types.
|
/// Calculate a [`NonZeroU64`] hash key from a namespace-qualified function name and parameter types.
|
||||||
///
|
///
|
||||||
/// Module names are passed in via `&str` references from an iterator.
|
/// Module names are passed in via `&str` references from an iterator.
|
||||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||||
@ -109,7 +110,7 @@ fn calc_fn_hash<'a>(
|
|||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
num: Option<usize>,
|
num: Option<usize>,
|
||||||
params: impl Iterator<Item = TypeId>,
|
params: impl Iterator<Item = TypeId>,
|
||||||
) -> u64 {
|
) -> Option<NonZeroU64> {
|
||||||
let s = &mut get_hasher();
|
let s = &mut get_hasher();
|
||||||
|
|
||||||
// Hash a boolean indicating whether the hash is namespace-qualified.
|
// Hash a boolean indicating whether the hash is namespace-qualified.
|
||||||
@ -122,7 +123,7 @@ fn calc_fn_hash<'a>(
|
|||||||
} else {
|
} else {
|
||||||
params.for_each(|t| t.hash(s));
|
params.for_each(|t| t.hash(s));
|
||||||
}
|
}
|
||||||
s.finish()
|
NonZeroU64::new(s.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The system immutable string type.
|
/// The system immutable string type.
|
||||||
|
Loading…
Reference in New Issue
Block a user