General code fixups.
This commit is contained in:
parent
23cc48f937
commit
694ac5b5bd
@ -205,7 +205,6 @@ impl Parse for Module {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Module {
|
||||
pub fn attrs(&self) -> &Vec<syn::Attribute> {
|
||||
&self.mod_all.attrs
|
||||
@ -300,22 +299,27 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn name(&self) -> &syn::Ident {
|
||||
&self.mod_all.ident
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn consts(&self) -> &[ExportedConst] {
|
||||
&self.consts
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn fns(&self) -> &[ExportedFn] {
|
||||
&self.fns
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn sub_modules(&self) -> &[Module] {
|
||||
&self.sub_modules
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn content(&self) -> Option<&Vec<syn::Item>> {
|
||||
match self.mod_all {
|
||||
syn::ItemMod {
|
||||
|
@ -1399,15 +1399,6 @@ pub struct CustomExpr {
|
||||
pub tokens: StaticVec<Identifier>,
|
||||
}
|
||||
|
||||
impl CustomExpr {
|
||||
/// Convert this into a [`Expr::Custom`].
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn into_custom_syntax_expr(self, pos: Position) -> Expr {
|
||||
Expr::Custom(self.into(), pos)
|
||||
}
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A binary expression.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
|
@ -163,21 +163,22 @@ impl Engine {
|
||||
/// Register a custom syntax with the [`Engine`].
|
||||
///
|
||||
/// * `keywords` holds a slice of strings that define the custom syntax.
|
||||
/// * `scope_may_be_changed` specifies variables have been added/removed by this custom syntax.
|
||||
/// * `scope_may_be_changed` specifies variables _may_ be added/removed by this custom syntax.
|
||||
/// * `func` is the implementation function.
|
||||
///
|
||||
/// # Caveat - Do not change beyond block scope
|
||||
/// ## Note on `scope_may_be_changed`
|
||||
///
|
||||
/// If `scope_may_be_changed` is `true`, then the current [`Scope`][crate::Scope] is assumed to be
|
||||
/// modified by this custom syntax.
|
||||
/// If `scope_may_be_changed` is `true`, then _size_ of the current [`Scope`][crate::Scope]
|
||||
/// _may_ be modified by this custom syntax.
|
||||
///
|
||||
/// Adding new variables and/or removing variables are allowed. Simply modifying the values of
|
||||
/// variables does NOT count, so `false` should be passed in this case.
|
||||
/// Adding new variables and/or removing variables count.
|
||||
///
|
||||
/// However, only variables declared within the current _block scope_ should be touched,
|
||||
/// since they all go away at the end of the block.
|
||||
/// Simply modifying the values of existing variables does NOT count, as the _size_ of the
|
||||
/// current [`Scope`][crate::Scope] is unchanged, so `false` should be passed.
|
||||
///
|
||||
/// Variables in parent blocks should be left untouched as they persist beyond the current block.
|
||||
/// Replacing one variable with another (i.e. adding a new variable and removing one variable at
|
||||
/// the same time so that the total _size_ of the [`Scope`][crate::Scope] is unchanged) also
|
||||
/// does NOT count, so `false` should be passed.
|
||||
#[must_use]
|
||||
pub fn register_custom_syntax<S: AsRef<str> + Into<Identifier>>(
|
||||
&mut self,
|
||||
|
@ -564,7 +564,8 @@ impl Hash for Dynamic {
|
||||
}
|
||||
}
|
||||
|
||||
_ => unimplemented!("{} cannot be hashed", self.type_name()),
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::TimeStamp(_, _, _) => unimplemented!("{} cannot be hashed", self.type_name()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ impl<'a> Target<'a> {
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_ref(&self) -> bool {
|
||||
pub const fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
Self::RefMut(_) => true,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -393,7 +393,7 @@ impl<'a> Target<'a> {
|
||||
/// Is the `Target` a temp value?
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_temp_value(&self) -> bool {
|
||||
pub const fn is_temp_value(&self) -> bool {
|
||||
match self {
|
||||
Self::RefMut(_) => false,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -608,7 +608,12 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry in a function resolution cache.
|
||||
/// _(INTERNALS)_ An entry in a function resolution cache.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FnResolutionCacheEntry {
|
||||
/// Function.
|
||||
@ -617,7 +622,12 @@ pub struct FnResolutionCacheEntry {
|
||||
pub source: Option<Identifier>,
|
||||
}
|
||||
|
||||
/// A function resolution cache.
|
||||
/// _(INTERNALS)_ A function resolution cache.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>;
|
||||
|
||||
/// _(INTERNALS)_ A type that holds all the current states of the [`Engine`].
|
||||
@ -627,15 +637,15 @@ pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>;
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct State {
|
||||
pub struct EvalState {
|
||||
/// Source of the current context.
|
||||
pub source: Option<Identifier>,
|
||||
/// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup.
|
||||
/// In some situation, e.g. after running an `eval` statement, subsequent offsets become mis-aligned.
|
||||
/// When that happens, this flag is turned on to force a scope lookup by name.
|
||||
pub always_search: bool,
|
||||
/// Level of the current scope. The global (root) level is zero, a new block
|
||||
/// (or function call) is one level higher, and so on.
|
||||
/// Normally, access to variables are parsed with a relative offset into the [`Scope`] to avoid a lookup.
|
||||
/// In some situation, e.g. after running an `eval` statement, subsequent offsets may become mis-aligned.
|
||||
/// When that happens, this flag is turned on to force a [`Scope`] search by name.
|
||||
pub always_search_scope: bool,
|
||||
/// Level of the current scope. The global (root) level is zero, a new block (or function call)
|
||||
/// is one level higher, and so on.
|
||||
pub scope_level: usize,
|
||||
/// Number of operations performed.
|
||||
pub operations: u64,
|
||||
@ -644,15 +654,29 @@ pub struct State {
|
||||
/// Embedded module resolver.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
||||
/// Function resolution cache and free list.
|
||||
fn_resolution_caches: StaticVec<FnResolutionCache>,
|
||||
/// Stack of function resolution caches.
|
||||
fn_resolution_caches: Vec<FnResolutionCache>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
impl EvalState {
|
||||
/// Create a new [`EvalState`].
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
source: None,
|
||||
always_search_scope: false,
|
||||
scope_level: 0,
|
||||
operations: 0,
|
||||
modules: 0,
|
||||
resolver: None,
|
||||
fn_resolution_caches: Vec::new(),
|
||||
}
|
||||
}
|
||||
/// Is the state currently at global (root) level?
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_global(&self) -> bool {
|
||||
pub const fn is_global(&self) -> bool {
|
||||
self.scope_level == 0
|
||||
}
|
||||
/// Get a mutable reference to the current function resolution cache.
|
||||
@ -759,13 +783,13 @@ pub struct EvalContext<'a, 'x, 'px, 'm, 's, 'b, 't, 'pt> {
|
||||
pub(crate) engine: &'a Engine,
|
||||
pub(crate) scope: &'x mut Scope<'px>,
|
||||
pub(crate) mods: &'m mut Imports,
|
||||
pub(crate) state: &'s mut State,
|
||||
pub(crate) state: &'s mut EvalState,
|
||||
pub(crate) lib: &'b [&'b Module],
|
||||
pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>,
|
||||
pub(crate) level: usize,
|
||||
}
|
||||
|
||||
impl<'x, 'px> EvalContext<'_, 'x, 'px, '_, '_, '_, '_, '_> {
|
||||
impl<'x, 'px, 'pt> EvalContext<'_, 'x, 'px, '_, '_, '_, '_, 'pt> {
|
||||
/// The current [`Engine`].
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
@ -826,6 +850,12 @@ impl<'x, 'px> EvalContext<'_, 'x, 'px, '_, '_, '_, '_, '_> {
|
||||
pub fn this_ptr(&self) -> Option<&Dynamic> {
|
||||
self.this_ptr.as_ref().map(|v| &**v)
|
||||
}
|
||||
/// Mutable reference to the current bound `this` pointer, if any.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn this_ptr_mut(&mut self) -> Option<&mut &'pt mut Dynamic> {
|
||||
self.this_ptr.as_mut()
|
||||
}
|
||||
/// The current nesting level of function calls.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
@ -1032,13 +1062,13 @@ impl Engine {
|
||||
pub(crate) fn search_imports(
|
||||
&self,
|
||||
mods: &Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
namespace: &NamespaceRef,
|
||||
) -> Option<Shared<Module>> {
|
||||
let root = &namespace[0].name;
|
||||
|
||||
// Qualified - check if the root module is directly indexed
|
||||
let index = if state.always_search {
|
||||
let index = if state.always_search_scope {
|
||||
None
|
||||
} else {
|
||||
namespace.index()
|
||||
@ -1067,7 +1097,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &'s mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||
expr: &Expr,
|
||||
@ -1117,7 +1147,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &'s mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||
expr: &Expr,
|
||||
@ -1133,7 +1163,7 @@ impl Engine {
|
||||
EvalAltResult::ErrorUnboundThis(*pos).into()
|
||||
}
|
||||
}
|
||||
_ if state.always_search => (0, expr.position()),
|
||||
_ if state.always_search_scope => (0, expr.position()),
|
||||
Expr::Variable(Some(i), pos, _) => (i.get() as usize, *pos),
|
||||
Expr::Variable(None, pos, v) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos),
|
||||
_ => unreachable!("Expr::Variable expected, but gets {:?}", expr),
|
||||
@ -1190,7 +1220,7 @@ impl Engine {
|
||||
fn eval_dot_index_chain_helper(
|
||||
&self,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
target: &mut Target,
|
||||
@ -1622,7 +1652,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
expr: &Expr,
|
||||
@ -1686,7 +1716,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
expr: &Expr,
|
||||
@ -1815,7 +1845,7 @@ impl Engine {
|
||||
fn get_indexed_mut<'t>(
|
||||
&self,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
target: &'t mut Dynamic,
|
||||
mut idx: Dynamic,
|
||||
@ -1873,7 +1903,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Dynamic(Union::Map(map, _, _)) => {
|
||||
// val_map[idx]
|
||||
let index = &*idx.read_lock::<ImmutableString>().ok_or_else(|| {
|
||||
let index = idx.read_lock::<ImmutableString>().ok_or_else(|| {
|
||||
self.make_type_mismatch_err::<ImmutableString>(idx.type_name(), idx_pos)
|
||||
})?;
|
||||
|
||||
@ -1987,7 +2017,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
expr: &Expr,
|
||||
@ -2188,7 +2218,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
statements: &[Stmt],
|
||||
@ -2200,7 +2230,7 @@ impl Engine {
|
||||
}
|
||||
|
||||
let mut _extra_fn_resolution_cache = false;
|
||||
let prev_always_search = state.always_search;
|
||||
let prev_always_search_scope = state.always_search_scope;
|
||||
let prev_scope_len = scope.len();
|
||||
let prev_mods_len = mods.len();
|
||||
|
||||
@ -2253,7 +2283,7 @@ impl Engine {
|
||||
|
||||
// The impact of new local variables goes away at the end of a block
|
||||
// because any new variables introduced will go out of scope
|
||||
state.always_search = prev_always_search;
|
||||
state.always_search_scope = prev_always_search_scope;
|
||||
}
|
||||
|
||||
result
|
||||
@ -2265,7 +2295,7 @@ impl Engine {
|
||||
pub(crate) fn eval_op_assignment(
|
||||
&self,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
op_info: Option<OpAssignment>,
|
||||
op_pos: Position,
|
||||
@ -2340,7 +2370,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
stmt: &Stmt,
|
||||
@ -3107,7 +3137,7 @@ impl Engine {
|
||||
#[must_use]
|
||||
pub(crate) fn inc_operations(
|
||||
&self,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
pos: Position,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
state.operations += 1;
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Module that defines the extern API of [`Engine`].
|
||||
|
||||
use crate::dynamic::Variant;
|
||||
use crate::engine::{EvalContext, Imports, State};
|
||||
use crate::engine::{EvalContext, EvalState, Imports};
|
||||
use crate::fn_call::FnCallArgs;
|
||||
use crate::fn_native::SendSync;
|
||||
use crate::fn_register::RegisterNativeFunction;
|
||||
@ -1749,7 +1749,7 @@ impl Engine {
|
||||
ast: &'a AST,
|
||||
level: usize,
|
||||
) -> RhaiResult {
|
||||
let mut state: State = Default::default();
|
||||
let mut state = EvalState::new();
|
||||
state.source = ast.source_raw().cloned();
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
@ -1831,7 +1831,7 @@ impl Engine {
|
||||
ast: &AST,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
let mods = &mut Default::default();
|
||||
let mut state: State = Default::default();
|
||||
let mut state = EvalState::new();
|
||||
state.source = ast.source_raw().cloned();
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
@ -2004,7 +2004,7 @@ impl Engine {
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
args: &mut FnCallArgs,
|
||||
) -> RhaiResult {
|
||||
let state = &mut Default::default();
|
||||
let state = &mut EvalState::new();
|
||||
let mods = &mut Default::default();
|
||||
let lib = &[ast.lib()];
|
||||
let statements = ast.statements();
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::ast::FnCallHashes;
|
||||
use crate::engine::{
|
||||
FnResolutionCacheEntry, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
||||
EvalState, FnResolutionCacheEntry, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
||||
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||
MAX_DYNAMIC_PARAMETERS,
|
||||
};
|
||||
@ -162,7 +162,7 @@ impl Engine {
|
||||
fn resolve_fn<'s>(
|
||||
&self,
|
||||
mods: &Imports,
|
||||
state: &'s mut State,
|
||||
state: &'s mut EvalState,
|
||||
lib: &[&Module],
|
||||
fn_name: &str,
|
||||
hash_script: u64,
|
||||
@ -266,7 +266,7 @@ impl Engine {
|
||||
pub(crate) fn call_native_fn(
|
||||
&self,
|
||||
mods: &Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
name: &str,
|
||||
hash: u64,
|
||||
@ -439,7 +439,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
fn_def: &crate::ast::ScriptFnDef,
|
||||
@ -451,7 +451,7 @@ impl Engine {
|
||||
fn make_error(
|
||||
name: String,
|
||||
fn_def: &crate::ast::ScriptFnDef,
|
||||
state: &State,
|
||||
state: &EvalState,
|
||||
err: Box<EvalAltResult>,
|
||||
pos: Position,
|
||||
) -> RhaiResult {
|
||||
@ -569,7 +569,7 @@ impl Engine {
|
||||
pub(crate) fn has_script_fn(
|
||||
&self,
|
||||
mods: Option<&Imports>,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
hash_script: u64,
|
||||
) -> bool {
|
||||
@ -608,7 +608,7 @@ impl Engine {
|
||||
pub(crate) fn exec_fn_call(
|
||||
&self,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
fn_name: &str,
|
||||
hashes: FnCallHashes,
|
||||
@ -644,7 +644,7 @@ impl Engine {
|
||||
crate::engine::KEYWORD_IS_DEF_FN
|
||||
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
|
||||
{
|
||||
let fn_name = &*args[0]
|
||||
let fn_name = args[0]
|
||||
.read_lock::<ImmutableString>()
|
||||
.expect("never fails because `args[0]` is `FnPtr`");
|
||||
let num_params = args[1]
|
||||
@ -655,7 +655,7 @@ impl Engine {
|
||||
if num_params < 0 {
|
||||
Dynamic::FALSE
|
||||
} else {
|
||||
let hash_script = calc_fn_hash(fn_name, num_params as usize);
|
||||
let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize);
|
||||
self.has_script_fn(Some(mods), state, lib, hash_script)
|
||||
.into()
|
||||
},
|
||||
@ -788,7 +788,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
statements: &[Stmt],
|
||||
lib: &[&Module],
|
||||
level: usize,
|
||||
@ -809,7 +809,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
script: &str,
|
||||
_pos: Position,
|
||||
@ -842,7 +842,7 @@ impl Engine {
|
||||
}
|
||||
|
||||
// Evaluate the AST
|
||||
let mut new_state: State = Default::default();
|
||||
let mut new_state = EvalState::new();
|
||||
new_state.source = state.source.clone();
|
||||
new_state.operations = state.operations;
|
||||
|
||||
@ -860,7 +860,7 @@ impl Engine {
|
||||
pub(crate) fn make_method_call(
|
||||
&self,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
fn_name: &str,
|
||||
mut hash: FnCallHashes,
|
||||
@ -1024,7 +1024,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
level: usize,
|
||||
@ -1046,7 +1046,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
fn_name: &str,
|
||||
@ -1202,7 +1202,7 @@ impl Engine {
|
||||
// IMPORTANT! If the eval defines new variables in the current scope,
|
||||
// all variable offsets from this point on will be mis-aligned.
|
||||
if scope.len() != prev_len {
|
||||
state.always_search = true;
|
||||
state.always_search_scope = true;
|
||||
}
|
||||
|
||||
return result.map_err(|err| {
|
||||
@ -1298,7 +1298,7 @@ impl Engine {
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
namespace: &NamespaceRef,
|
||||
|
@ -399,7 +399,7 @@ impl CallableFunction {
|
||||
/// Is this an iterator function?
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_iter(&self) -> bool {
|
||||
pub const fn is_iter(&self) -> bool {
|
||||
match self {
|
||||
Self::Iterator(_) => true,
|
||||
Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => false,
|
||||
@ -411,7 +411,7 @@ impl CallableFunction {
|
||||
/// Is this a Rhai-scripted function?
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_script(&self) -> bool {
|
||||
pub const fn is_script(&self) -> bool {
|
||||
match self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
Self::Script(_) => true,
|
||||
@ -422,7 +422,7 @@ impl CallableFunction {
|
||||
/// Is this a plugin function?
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_plugin_fn(&self) -> bool {
|
||||
pub const fn is_plugin_fn(&self) -> bool {
|
||||
match self {
|
||||
Self::Plugin(_) => true,
|
||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => false,
|
||||
@ -434,7 +434,7 @@ impl CallableFunction {
|
||||
/// Is this a native Rust function?
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_native(&self) -> bool {
|
||||
pub const fn is_native(&self) -> bool {
|
||||
match self {
|
||||
Self::Pure(_) | Self::Method(_) => true,
|
||||
Self::Plugin(_) => true,
|
||||
|
@ -233,10 +233,11 @@ pub use ast::{
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[deprecated = "this type is volatile and may change"]
|
||||
pub use engine::{Imports, State as EvalState};
|
||||
pub use engine::{EvalState, FnResolutionCache, FnResolutionCacheEntry, Imports};
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[deprecated = "this type is volatile and may change"]
|
||||
pub use engine::Limits;
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
|
@ -1731,6 +1731,12 @@ impl From<StaticVec<Ident>> for NamespaceRef {
|
||||
}
|
||||
|
||||
impl NamespaceRef {
|
||||
/// Create a new [`NamespaceRef`].
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn new(&self) -> Self {
|
||||
Default::default()
|
||||
}
|
||||
/// Get the [`Scope`][crate::Scope] index offset.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
|
@ -43,7 +43,7 @@ impl Default for OptimizationLevel {
|
||||
|
||||
/// Mutable state throughout an optimization pass.
|
||||
#[derive(Debug, Clone)]
|
||||
struct State<'a> {
|
||||
struct OptimizerState<'a> {
|
||||
/// Has the [`AST`] been changed during this pass?
|
||||
changed: bool,
|
||||
/// Collection of constants to use for eager function evaluations.
|
||||
@ -58,7 +58,7 @@ struct State<'a> {
|
||||
optimization_level: OptimizationLevel,
|
||||
}
|
||||
|
||||
impl<'a> State<'a> {
|
||||
impl<'a> OptimizerState<'a> {
|
||||
/// Create a new State.
|
||||
#[inline(always)]
|
||||
pub const fn new(
|
||||
@ -121,7 +121,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
// Has a system function a Rust-native override?
|
||||
fn has_native_fn(state: &State, hash_script: u64, arg_types: &[TypeId]) -> bool {
|
||||
fn has_native_fn(state: &OptimizerState, hash_script: u64, arg_types: &[TypeId]) -> bool {
|
||||
let hash_params = calc_fn_params_hash(arg_types.iter().cloned());
|
||||
let hash = combine_hashes(hash_script, hash_params);
|
||||
|
||||
@ -135,7 +135,7 @@ fn has_native_fn(state: &State, hash_script: u64, arg_types: &[TypeId]) -> bool
|
||||
|
||||
/// Call a registered function
|
||||
fn call_fn_with_constant_arguments(
|
||||
state: &State,
|
||||
state: &OptimizerState,
|
||||
fn_name: &str,
|
||||
arg_values: &mut [Dynamic],
|
||||
) -> Option<Dynamic> {
|
||||
@ -159,7 +159,7 @@ fn call_fn_with_constant_arguments(
|
||||
/// Optimize a block of [statements][Stmt].
|
||||
fn optimize_stmt_block(
|
||||
mut statements: Vec<Stmt>,
|
||||
state: &mut State,
|
||||
state: &mut OptimizerState,
|
||||
preserve_result: bool,
|
||||
is_internal: bool,
|
||||
reduce_return: bool,
|
||||
@ -368,7 +368,7 @@ fn optimize_stmt_block(
|
||||
}
|
||||
|
||||
/// Optimize a [statement][Stmt].
|
||||
fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
||||
fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: bool) {
|
||||
match stmt {
|
||||
// var = var op expr => var op= expr
|
||||
Stmt::Assignment(x, _)
|
||||
@ -682,7 +682,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
||||
}
|
||||
|
||||
/// Optimize an [expression][Expr].
|
||||
fn optimize_expr(expr: &mut Expr, state: &mut State, _chaining: bool) {
|
||||
fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
||||
// These keywords are handled specially
|
||||
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
||||
KEYWORD_PRINT, // side effects
|
||||
@ -1077,7 +1077,7 @@ fn optimize_top_level(
|
||||
}
|
||||
|
||||
// Set up the state
|
||||
let mut state = State::new(engine, lib, optimization_level);
|
||||
let mut state = OptimizerState::new(engine, lib, optimization_level);
|
||||
|
||||
// Add constants and variables from the scope
|
||||
scope.iter().for_each(|(name, constant, value)| {
|
||||
@ -1142,7 +1142,7 @@ pub fn optimize_into_ast(
|
||||
let mut fn_def = crate::fn_native::shared_take_or_clone(fn_def);
|
||||
|
||||
// Optimize the function body
|
||||
let state = &mut State::new(engine, lib2, level);
|
||||
let state = &mut OptimizerState::new(engine, lib2, level);
|
||||
|
||||
let body = mem::take(fn_def.body.statements_mut()).into_vec();
|
||||
|
||||
|
75
src/parse.rs
75
src/parse.rs
@ -137,7 +137,7 @@ impl<'e> ParseState<'e> {
|
||||
///
|
||||
/// If the variable is not present in the scope adds it to the list of external variables
|
||||
///
|
||||
/// The return value is the offset to be deducted from `ParseState::stack::len`,
|
||||
/// The return value is the offset to be deducted from `ParseState::stack::len()`,
|
||||
/// i.e. the top element of [`ParseState`]'s variables stack is offset 1.
|
||||
///
|
||||
/// Return `None` when the variable name is not found in the `stack`.
|
||||
@ -156,7 +156,7 @@ impl<'e> ParseState<'e> {
|
||||
barrier = true;
|
||||
false
|
||||
} else {
|
||||
*n == name
|
||||
n == name
|
||||
}
|
||||
})
|
||||
.and_then(|(i, _)| NonZeroUsize::new(i + 1));
|
||||
@ -324,7 +324,30 @@ impl Expr {
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure that the next expression is not a statement expression (i.e. wrapped in `{}`).
|
||||
#[inline(always)]
|
||||
fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result<(), ParseError> {
|
||||
match input.peek().expect(NEVER_ENDS) {
|
||||
(Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure that the next expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
|
||||
#[inline(always)]
|
||||
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
|
||||
match input.peek().expect(NEVER_ENDS) {
|
||||
(Token::Equals, pos) => Err(LexError::ImproperSymbol(
|
||||
"=".to_string(),
|
||||
"Possibly a typo of '=='?".to_string(),
|
||||
)
|
||||
.into_err(*pos)),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume a particular [token][Token], checking that it is the expected one.
|
||||
#[inline]
|
||||
fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
||||
let (t, pos) = input.next().expect(NEVER_ENDS);
|
||||
|
||||
@ -340,6 +363,7 @@ fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
||||
}
|
||||
|
||||
/// Match a particular [token][Token], consuming it if matched.
|
||||
#[inline]
|
||||
fn match_token(input: &mut TokenStream, token: Token) -> (bool, Position) {
|
||||
let (t, pos) = input.peek().expect(NEVER_ENDS);
|
||||
if *t == token {
|
||||
@ -2113,46 +2137,6 @@ fn parse_expr(
|
||||
)
|
||||
}
|
||||
|
||||
/// Make sure that the expression is not a statement expression (i.e. wrapped in `{}`).
|
||||
fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result<(), ParseError> {
|
||||
match input.peek().expect(NEVER_ENDS) {
|
||||
// Disallow statement expressions
|
||||
(Token::LeftBrace, pos) | (Token::EOF, pos) => {
|
||||
Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos))
|
||||
}
|
||||
// No need to check for others at this time - leave it for the expr parser
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure that the expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
|
||||
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
|
||||
match input.peek().expect(NEVER_ENDS) {
|
||||
(Token::Equals, pos) => Err(LexError::ImproperSymbol(
|
||||
"=".to_string(),
|
||||
"Possibly a typo of '=='?".to_string(),
|
||||
)
|
||||
.into_err(*pos)),
|
||||
(token @ Token::PlusAssign, pos)
|
||||
| (token @ Token::MinusAssign, pos)
|
||||
| (token @ Token::MultiplyAssign, pos)
|
||||
| (token @ Token::DivideAssign, pos)
|
||||
| (token @ Token::LeftShiftAssign, pos)
|
||||
| (token @ Token::RightShiftAssign, pos)
|
||||
| (token @ Token::ModuloAssign, pos)
|
||||
| (token @ Token::PowerOfAssign, pos)
|
||||
| (token @ Token::AndAssign, pos)
|
||||
| (token @ Token::OrAssign, pos)
|
||||
| (token @ Token::XOrAssign, pos) => Err(LexError::ImproperSymbol(
|
||||
token.syntax().to_string(),
|
||||
"Expecting a boolean expression, not an assignment".to_string(),
|
||||
)
|
||||
.into_err(*pos)),
|
||||
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse an if statement.
|
||||
fn parse_if(
|
||||
input: &mut TokenStream,
|
||||
@ -2207,15 +2191,15 @@ fn parse_while_loop(
|
||||
(Token::While, pos) => {
|
||||
ensure_not_statement_expr(input, "a boolean")?;
|
||||
let expr = parse_expr(input, state, lib, settings.level_up())?.ensure_bool_expr()?;
|
||||
ensure_not_assignment(input)?;
|
||||
(expr, pos)
|
||||
}
|
||||
(Token::Loop, pos) => (Expr::Unit(Position::NONE), pos),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
settings.pos = token_pos;
|
||||
|
||||
ensure_not_assignment(input)?;
|
||||
settings.is_breakable = true;
|
||||
|
||||
let body = parse_block(input, state, lib, settings.level_up())?;
|
||||
|
||||
Ok(Stmt::While(guard, Box::new(body.into()), settings.pos))
|
||||
@ -2249,8 +2233,9 @@ fn parse_do(
|
||||
}
|
||||
};
|
||||
|
||||
ensure_not_statement_expr(input, "a boolean")?;
|
||||
settings.is_breakable = false;
|
||||
|
||||
ensure_not_statement_expr(input, "a boolean")?;
|
||||
let guard = parse_expr(input, state, lib, settings.level_up())?.ensure_bool_expr()?;
|
||||
ensure_not_assignment(input)?;
|
||||
|
||||
|
@ -30,6 +30,7 @@ fn test_native_context_fn_name() -> Result<(), Box<EvalAltResult>> {
|
||||
|
||||
let mut engine = Engine::new();
|
||||
|
||||
#[allow(deprecated)]
|
||||
engine
|
||||
.register_raw_fn(
|
||||
"add_double",
|
||||
|
@ -160,6 +160,7 @@ mod test_switch_enum {
|
||||
use super::*;
|
||||
use rhai::Array;
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
enum MyEnum {
|
||||
Foo,
|
||||
Bar(INT),
|
||||
|
Loading…
Reference in New Issue
Block a user