Fix builds.
This commit is contained in:
parent
95dc2ad502
commit
c5f2b0a253
@ -222,14 +222,14 @@ impl NativeCallContext<'_> {
|
|||||||
///
|
///
|
||||||
/// # WARNING
|
/// # WARNING
|
||||||
///
|
///
|
||||||
/// All arguments may be _consumed_, meaning that they may be replaced by `()`.
|
/// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
|
||||||
/// This is to avoid unnecessarily cloning the arguments.
|
/// unnecessarily cloning the arguments.
|
||||||
///
|
///
|
||||||
/// Do not use the arguments after this call. If they are needed afterwards,
|
/// Do not use the arguments after this call. If they are needed afterwards, clone them _before_
|
||||||
/// clone them _before_ calling this function.
|
/// calling this function.
|
||||||
///
|
///
|
||||||
/// If `is_method` is [`true`], the first argument is assumed to be passed
|
/// If `is_method` is [`true`], the first argument is assumed to be passed by reference and is
|
||||||
/// by reference and is not consumed.
|
/// not consumed.
|
||||||
///
|
///
|
||||||
/// # Deprecated
|
/// # Deprecated
|
||||||
///
|
///
|
||||||
|
@ -63,9 +63,6 @@ pub struct ScriptFnDef {
|
|||||||
pub params: StaticVec<Identifier>,
|
pub params: StaticVec<Identifier>,
|
||||||
/// _(metadata)_ Function doc-comments (if any).
|
/// _(metadata)_ Function doc-comments (if any).
|
||||||
/// Exported under the `metadata` feature only.
|
/// Exported under the `metadata` feature only.
|
||||||
///
|
|
||||||
/// Not available under `no_function`.
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
pub comments: Option<Box<[Box<str>]>>,
|
pub comments: Option<Box<[Box<str>]>>,
|
||||||
}
|
}
|
||||||
@ -100,15 +97,12 @@ pub struct ScriptFnMetadata<'a> {
|
|||||||
/// _(metadata)_ Function doc-comments (if any).
|
/// _(metadata)_ Function doc-comments (if any).
|
||||||
/// Exported under the `metadata` feature only.
|
/// Exported under the `metadata` feature only.
|
||||||
///
|
///
|
||||||
/// Not available under `no_function`.
|
|
||||||
///
|
|
||||||
/// Block doc-comments are kept in a single string slice with line-breaks within.
|
/// Block doc-comments are kept in a single string slice with line-breaks within.
|
||||||
///
|
///
|
||||||
/// Line doc-comments are kept in one string slice per line without the termination line-break.
|
/// Line doc-comments are kept in one string slice per line without the termination line-break.
|
||||||
///
|
///
|
||||||
/// Leading white-spaces are stripped, and each string slice always starts with the corresponding
|
/// Leading white-spaces are stripped, and each string slice always starts with the corresponding
|
||||||
/// doc-comment leader: `///` or `/**`.
|
/// doc-comment leader: `///` or `/**`.
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
pub comments: Vec<&'a str>,
|
pub comments: Vec<&'a str>,
|
||||||
/// Function access mode.
|
/// Function access mode.
|
||||||
|
187
src/func/call.rs
187
src/func/call.rs
@ -303,6 +303,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// Function call arguments be _consumed_ when the function requires them to be passed by value.
|
/// Function call arguments be _consumed_ when the function requires them to be passed by value.
|
||||||
/// All function arguments not in the first position are always passed by value and thus consumed.
|
/// All function arguments not in the first position are always passed by value and thus consumed.
|
||||||
|
///
|
||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
||||||
pub(crate) fn call_native_fn(
|
pub(crate) fn call_native_fn(
|
||||||
&self,
|
&self,
|
||||||
@ -472,197 +473,13 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call a script-defined function.
|
|
||||||
///
|
|
||||||
/// If `rewind_scope` is `false`, arguments are removed from the scope but new variables are not.
|
|
||||||
///
|
|
||||||
/// # WARNING
|
|
||||||
///
|
|
||||||
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
|
||||||
/// All function arguments not in the first position are always passed by value and thus consumed.
|
|
||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub(crate) fn call_script_fn(
|
|
||||||
&self,
|
|
||||||
scope: &mut Scope,
|
|
||||||
mods: &mut Imports,
|
|
||||||
state: &mut EvalState,
|
|
||||||
lib: &[&Module],
|
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
|
||||||
fn_def: &crate::ast::ScriptFnDef,
|
|
||||||
args: &mut FnCallArgs,
|
|
||||||
pos: Position,
|
|
||||||
rewind_scope: bool,
|
|
||||||
level: usize,
|
|
||||||
) -> RhaiResult {
|
|
||||||
#[inline(never)]
|
|
||||||
fn make_error(
|
|
||||||
name: String,
|
|
||||||
fn_def: &crate::ast::ScriptFnDef,
|
|
||||||
mods: &Imports,
|
|
||||||
err: Box<EvalAltResult>,
|
|
||||||
pos: Position,
|
|
||||||
) -> RhaiResult {
|
|
||||||
Err(EvalAltResult::ErrorInFunctionCall(
|
|
||||||
name,
|
|
||||||
fn_def
|
|
||||||
.lib
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|m| m.id().map(|id| id.to_string()))
|
|
||||||
.or_else(|| mods.source.as_ref().map(|s| s.to_string()))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
err,
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(fn_def.params.len() == args.len());
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.inc_operations(&mut mods.num_operations, pos)?;
|
|
||||||
|
|
||||||
if fn_def.body.is_empty() {
|
|
||||||
return Ok(Dynamic::UNIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for stack overflow
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if level > self.max_call_levels() {
|
|
||||||
return Err(EvalAltResult::ErrorStackOverflow(pos).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let orig_scope_len = scope.len();
|
|
||||||
let orig_mods_len = mods.len();
|
|
||||||
|
|
||||||
// Put arguments into scope as variables
|
|
||||||
// Actually consume the arguments instead of cloning them
|
|
||||||
scope.extend(
|
|
||||||
fn_def
|
|
||||||
.params
|
|
||||||
.iter()
|
|
||||||
.zip(args.iter_mut().map(|v| mem::take(*v)))
|
|
||||||
.map(|(name, value)| {
|
|
||||||
let var_name: std::borrow::Cow<'_, str> =
|
|
||||||
crate::r#unsafe::unsafe_cast_var_name_to_lifetime(name).into();
|
|
||||||
(var_name, value)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Merge in encapsulated environment, if any
|
|
||||||
let mut lib_merged = StaticVec::with_capacity(lib.len() + 1);
|
|
||||||
let orig_fn_resolution_caches_len = state.fn_resolution_caches_len();
|
|
||||||
|
|
||||||
let lib = if let Some(ref fn_lib) = fn_def.lib {
|
|
||||||
if fn_lib.is_empty() {
|
|
||||||
lib
|
|
||||||
} else {
|
|
||||||
state.push_fn_resolution_cache();
|
|
||||||
lib_merged.push(fn_lib.as_ref());
|
|
||||||
lib_merged.extend(lib.iter().cloned());
|
|
||||||
&lib_merged
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lib
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
if !fn_def.mods.is_empty() {
|
|
||||||
fn_def
|
|
||||||
.mods
|
|
||||||
.iter_raw()
|
|
||||||
.for_each(|(n, m)| mods.push(n.clone(), m.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the function
|
|
||||||
let body = &fn_def.body;
|
|
||||||
let result = self
|
|
||||||
.eval_stmt_block(
|
|
||||||
scope,
|
|
||||||
mods,
|
|
||||||
state,
|
|
||||||
lib,
|
|
||||||
this_ptr,
|
|
||||||
body,
|
|
||||||
true,
|
|
||||||
rewind_scope,
|
|
||||||
level,
|
|
||||||
)
|
|
||||||
.or_else(|err| match *err {
|
|
||||||
// Convert return statement to return value
|
|
||||||
EvalAltResult::Return(x, _) => Ok(x),
|
|
||||||
// Error in sub function call
|
|
||||||
EvalAltResult::ErrorInFunctionCall(name, src, err, _) => {
|
|
||||||
let fn_name = if src.is_empty() {
|
|
||||||
format!("{} < {}", name, fn_def.name)
|
|
||||||
} else {
|
|
||||||
format!("{} @ '{}' < {}", name, src, fn_def.name)
|
|
||||||
};
|
|
||||||
|
|
||||||
make_error(fn_name, fn_def, mods, err, pos)
|
|
||||||
}
|
|
||||||
// System errors are passed straight-through
|
|
||||||
mut err if err.is_system_exception() => {
|
|
||||||
err.set_position(pos);
|
|
||||||
Err(err.into())
|
|
||||||
}
|
|
||||||
// Other errors are wrapped in `ErrorInFunctionCall`
|
|
||||||
_ => make_error(fn_def.name.to_string(), fn_def, mods, err, pos),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove all local variables
|
|
||||||
if rewind_scope {
|
|
||||||
scope.rewind(orig_scope_len);
|
|
||||||
} else if !args.is_empty() {
|
|
||||||
// Remove arguments only, leaving new variables in the scope
|
|
||||||
scope.remove_range(orig_scope_len, args.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
mods.truncate(orig_mods_len);
|
|
||||||
state.rewind_fn_resolution_caches(orig_fn_resolution_caches_len);
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does a scripted function exist?
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[must_use]
|
|
||||||
pub(crate) fn has_script_fn(
|
|
||||||
&self,
|
|
||||||
mods: Option<&Imports>,
|
|
||||||
state: &mut EvalState,
|
|
||||||
lib: &[&Module],
|
|
||||||
hash_script: u64,
|
|
||||||
) -> bool {
|
|
||||||
let cache = state.fn_resolution_cache_mut();
|
|
||||||
|
|
||||||
if let Some(result) = cache.get(&hash_script).map(|v| v.is_some()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First check script-defined functions
|
|
||||||
let result = lib.iter().any(|&m| m.contains_fn(hash_script))
|
|
||||||
// Then check the global namespace and packages
|
|
||||||
|| self.global_modules.iter().any(|m| m.contains_fn(hash_script))
|
|
||||||
// Then check imported modules
|
|
||||||
|| mods.map_or(false, |m| m.contains_fn(hash_script))
|
|
||||||
// Then check sub-modules
|
|
||||||
|| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash_script));
|
|
||||||
|
|
||||||
if !result {
|
|
||||||
cache.insert(hash_script, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// # WARNING
|
/// # WARNING
|
||||||
///
|
///
|
||||||
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
||||||
/// All function arguments not in the first position are always passed by value and thus consumed.
|
/// All function arguments not in the first position are always passed by value and thus consumed.
|
||||||
|
///
|
||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
||||||
pub(crate) fn exec_fn_call(
|
pub(crate) fn exec_fn_call(
|
||||||
&self,
|
&self,
|
||||||
|
@ -8,6 +8,7 @@ pub mod hashing;
|
|||||||
pub mod native;
|
pub mod native;
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
|
pub mod script;
|
||||||
|
|
||||||
pub use args::FuncArgs;
|
pub use args::FuncArgs;
|
||||||
pub use builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
pub use builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
||||||
|
@ -227,19 +227,19 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
}
|
}
|
||||||
/// Call a function inside the call context.
|
/// Call a function inside the call context.
|
||||||
///
|
///
|
||||||
/// If `is_method_call` is [`true`], the first argument is assumed to be the
|
/// If `is_method_call` is [`true`], the first argument is assumed to be the `this` pointer for
|
||||||
/// `this` pointer for a script-defined function (or the object of a method call).
|
/// a script-defined function (or the object of a method call).
|
||||||
///
|
///
|
||||||
/// # WARNING
|
/// # WARNING
|
||||||
///
|
///
|
||||||
/// All arguments may be _consumed_, meaning that they may be replaced by `()`.
|
/// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
|
||||||
/// This is to avoid unnecessarily cloning the arguments.
|
/// unnecessarily cloning the arguments.
|
||||||
///
|
///
|
||||||
/// Do not use the arguments after this call. If they are needed afterwards,
|
/// **DO NOT** reuse the arguments after this call. If they are needed afterwards, clone them
|
||||||
/// clone them _before_ calling this function.
|
/// _before_ calling this function.
|
||||||
///
|
///
|
||||||
/// If `is_ref_mut` is [`true`], the first argument is assumed to be passed
|
/// If `is_ref_mut` is [`true`], the first argument is assumed to be passed by reference and is
|
||||||
/// by reference and is not consumed.
|
/// not consumed.
|
||||||
pub fn call_fn_raw(
|
pub fn call_fn_raw(
|
||||||
&self,
|
&self,
|
||||||
fn_name: impl AsRef<str>,
|
fn_name: impl AsRef<str>,
|
||||||
|
196
src/func/script.rs
Normal file
196
src/func/script.rs
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
//! Implement script function-calling mechanism for [`Engine`].
|
||||||
|
#![cfg(not(feature = "no_function"))]
|
||||||
|
|
||||||
|
use crate::ast::ScriptFnDef;
|
||||||
|
use crate::engine::{EvalState, Imports};
|
||||||
|
use crate::func::call::FnCallArgs;
|
||||||
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
|
use crate::{Dynamic, Engine, EvalAltResult, Module, Position, RhaiResult, Scope, StaticVec};
|
||||||
|
use std::mem;
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
/// Call a script-defined function.
|
||||||
|
///
|
||||||
|
/// If `rewind_scope` is `false`, arguments are removed from the scope but new variables are not.
|
||||||
|
///
|
||||||
|
/// # WARNING
|
||||||
|
///
|
||||||
|
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
||||||
|
/// All function arguments not in the first position are always passed by value and thus consumed.
|
||||||
|
///
|
||||||
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
||||||
|
pub(crate) fn call_script_fn(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope,
|
||||||
|
mods: &mut Imports,
|
||||||
|
state: &mut EvalState,
|
||||||
|
lib: &[&Module],
|
||||||
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
|
fn_def: &ScriptFnDef,
|
||||||
|
args: &mut FnCallArgs,
|
||||||
|
pos: Position,
|
||||||
|
rewind_scope: bool,
|
||||||
|
level: usize,
|
||||||
|
) -> RhaiResult {
|
||||||
|
#[inline(never)]
|
||||||
|
fn make_error(
|
||||||
|
name: String,
|
||||||
|
fn_def: &ScriptFnDef,
|
||||||
|
mods: &Imports,
|
||||||
|
err: Box<EvalAltResult>,
|
||||||
|
pos: Position,
|
||||||
|
) -> RhaiResult {
|
||||||
|
Err(EvalAltResult::ErrorInFunctionCall(
|
||||||
|
name,
|
||||||
|
fn_def
|
||||||
|
.lib
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|m| m.id().map(|id| id.to_string()))
|
||||||
|
.or_else(|| mods.source.as_ref().map(|s| s.to_string()))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
err,
|
||||||
|
pos,
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(fn_def.params.len() == args.len());
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(&mut mods.num_operations, pos)?;
|
||||||
|
|
||||||
|
if fn_def.body.is_empty() {
|
||||||
|
return Ok(Dynamic::UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for stack overflow
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if level > self.max_call_levels() {
|
||||||
|
return Err(EvalAltResult::ErrorStackOverflow(pos).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let orig_scope_len = scope.len();
|
||||||
|
let orig_mods_len = mods.len();
|
||||||
|
|
||||||
|
// Put arguments into scope as variables
|
||||||
|
// Actually consume the arguments instead of cloning them
|
||||||
|
scope.extend(
|
||||||
|
fn_def
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.zip(args.iter_mut().map(|v| mem::take(*v)))
|
||||||
|
.map(|(name, value)| {
|
||||||
|
let var_name: std::borrow::Cow<'_, str> =
|
||||||
|
unsafe_cast_var_name_to_lifetime(name).into();
|
||||||
|
(var_name, value)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Merge in encapsulated environment, if any
|
||||||
|
let mut lib_merged = StaticVec::with_capacity(lib.len() + 1);
|
||||||
|
let orig_fn_resolution_caches_len = state.fn_resolution_caches_len();
|
||||||
|
|
||||||
|
let lib = if let Some(ref fn_lib) = fn_def.lib {
|
||||||
|
if fn_lib.is_empty() {
|
||||||
|
lib
|
||||||
|
} else {
|
||||||
|
state.push_fn_resolution_cache();
|
||||||
|
lib_merged.push(fn_lib.as_ref());
|
||||||
|
lib_merged.extend(lib.iter().cloned());
|
||||||
|
&lib_merged
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lib
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
if !fn_def.mods.is_empty() {
|
||||||
|
fn_def
|
||||||
|
.mods
|
||||||
|
.iter_raw()
|
||||||
|
.for_each(|(n, m)| mods.push(n.clone(), m.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the function
|
||||||
|
let body = &fn_def.body;
|
||||||
|
let result = self
|
||||||
|
.eval_stmt_block(
|
||||||
|
scope,
|
||||||
|
mods,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
this_ptr,
|
||||||
|
body,
|
||||||
|
true,
|
||||||
|
rewind_scope,
|
||||||
|
level,
|
||||||
|
)
|
||||||
|
.or_else(|err| match *err {
|
||||||
|
// Convert return statement to return value
|
||||||
|
EvalAltResult::Return(x, _) => Ok(x),
|
||||||
|
// Error in sub function call
|
||||||
|
EvalAltResult::ErrorInFunctionCall(name, src, err, _) => {
|
||||||
|
let fn_name = if src.is_empty() {
|
||||||
|
format!("{} < {}", name, fn_def.name)
|
||||||
|
} else {
|
||||||
|
format!("{} @ '{}' < {}", name, src, fn_def.name)
|
||||||
|
};
|
||||||
|
|
||||||
|
make_error(fn_name, fn_def, mods, err, pos)
|
||||||
|
}
|
||||||
|
// System errors are passed straight-through
|
||||||
|
mut err if err.is_system_exception() => {
|
||||||
|
err.set_position(pos);
|
||||||
|
Err(err.into())
|
||||||
|
}
|
||||||
|
// Other errors are wrapped in `ErrorInFunctionCall`
|
||||||
|
_ => make_error(fn_def.name.to_string(), fn_def, mods, err, pos),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove all local variables
|
||||||
|
if rewind_scope {
|
||||||
|
scope.rewind(orig_scope_len);
|
||||||
|
} else if !args.is_empty() {
|
||||||
|
// Remove arguments only, leaving new variables in the scope
|
||||||
|
scope.remove_range(orig_scope_len, args.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
mods.truncate(orig_mods_len);
|
||||||
|
state.rewind_fn_resolution_caches(orig_fn_resolution_caches_len);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does a scripted function exist?
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn has_script_fn(
|
||||||
|
&self,
|
||||||
|
mods: Option<&Imports>,
|
||||||
|
state: &mut EvalState,
|
||||||
|
lib: &[&Module],
|
||||||
|
hash_script: u64,
|
||||||
|
) -> bool {
|
||||||
|
let cache = state.fn_resolution_cache_mut();
|
||||||
|
|
||||||
|
if let Some(result) = cache.get(&hash_script).map(|v| v.is_some()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First check script-defined functions
|
||||||
|
let result = lib.iter().any(|&m| m.contains_fn(hash_script))
|
||||||
|
// Then check the global namespace and packages
|
||||||
|
|| self.global_modules.iter().any(|m| m.contains_fn(hash_script))
|
||||||
|
// Then check imported modules
|
||||||
|
|| mods.map_or(false, |m| m.contains_fn(hash_script))
|
||||||
|
// Then check sub-modules
|
||||||
|
|| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash_script));
|
||||||
|
|
||||||
|
if !result {
|
||||||
|
cache.insert(hash_script, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
@ -3,19 +3,16 @@ use crate::{Engine, EvalAltResult, Module, Position, Shared, AST};
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
mod dummy;
|
|
||||||
pub use dummy::DummyModuleResolver;
|
|
||||||
|
|
||||||
mod collection;
|
mod collection;
|
||||||
pub use collection::ModuleResolversCollection;
|
mod dummy;
|
||||||
|
|
||||||
mod file;
|
mod file;
|
||||||
|
mod stat;
|
||||||
|
|
||||||
|
pub use collection::ModuleResolversCollection;
|
||||||
|
pub use dummy::DummyModuleResolver;
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
||||||
pub use file::FileModuleResolver;
|
pub use file::FileModuleResolver;
|
||||||
|
|
||||||
mod stat;
|
|
||||||
pub use stat::StaticModuleResolver;
|
pub use stat::StaticModuleResolver;
|
||||||
|
|
||||||
/// Trait that encapsulates a module resolution service.
|
/// Trait that encapsulates a module resolution service.
|
||||||
|
@ -40,12 +40,8 @@ pub enum OptimizationLevel {
|
|||||||
impl Default for OptimizationLevel {
|
impl Default for OptimizationLevel {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
if cfg!(feature = "no_optimize") {
|
|
||||||
Self::None
|
|
||||||
} else {
|
|
||||||
Self::Simple
|
Self::Simple
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutable state throughout an optimization pass.
|
/// Mutable state throughout an optimization pass.
|
||||||
@ -1145,19 +1141,13 @@ pub fn optimize_into_ast(
|
|||||||
>,
|
>,
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> AST {
|
) -> AST {
|
||||||
let level = if cfg!(feature = "no_optimize") {
|
|
||||||
OptimizationLevel::default()
|
|
||||||
} else {
|
|
||||||
optimization_level
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut statements = statements;
|
let mut statements = statements;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = {
|
let lib = {
|
||||||
let mut module = crate::Module::new();
|
let mut module = crate::Module::new();
|
||||||
|
|
||||||
if level != OptimizationLevel::None {
|
if optimization_level != OptimizationLevel::None {
|
||||||
// We only need the script library's signatures for optimization purposes
|
// We only need the script library's signatures for optimization purposes
|
||||||
let mut lib2 = crate::Module::new();
|
let mut lib2 = crate::Module::new();
|
||||||
|
|
||||||
@ -1189,7 +1179,8 @@ pub fn optimize_into_ast(
|
|||||||
// Optimize the function body
|
// Optimize the function body
|
||||||
let body = mem::take(fn_def.body.deref_mut());
|
let body = mem::take(fn_def.body.deref_mut());
|
||||||
|
|
||||||
*fn_def.body = optimize_top_level(body, engine, scope, lib2, level);
|
*fn_def.body =
|
||||||
|
optimize_top_level(body, engine, scope, lib2, optimization_level);
|
||||||
|
|
||||||
fn_def
|
fn_def
|
||||||
})
|
})
|
||||||
@ -1208,7 +1199,7 @@ pub fn optimize_into_ast(
|
|||||||
statements.shrink_to_fit();
|
statements.shrink_to_fit();
|
||||||
|
|
||||||
AST::new(
|
AST::new(
|
||||||
match level {
|
match optimization_level {
|
||||||
OptimizationLevel::None => statements,
|
OptimizationLevel::None => statements,
|
||||||
OptimizationLevel::Simple | OptimizationLevel::Full => optimize_top_level(
|
OptimizationLevel::Simple | OptimizationLevel::Full => optimize_top_level(
|
||||||
statements,
|
statements,
|
||||||
@ -1216,7 +1207,7 @@ pub fn optimize_into_ast(
|
|||||||
&scope,
|
&scope,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
&[&lib],
|
&[&lib],
|
||||||
level,
|
optimization_level,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
@ -3270,7 +3270,11 @@ impl Engine {
|
|||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
return Ok(AST::new(statements, crate::Module::new()));
|
return Ok(AST::new(
|
||||||
|
statements,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
crate::Module::new(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the global level statements.
|
/// Parse the global level statements.
|
||||||
@ -3371,6 +3375,10 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
return Ok(AST::new(statements, crate::Module::new()));
|
return Ok(AST::new(
|
||||||
|
statements,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
crate::Module::new(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user