Revise on_def_var API.
This commit is contained in:
parent
5bb6ce835f
commit
fb9964e1a3
@ -5,6 +5,19 @@ use crate::{Dynamic, Engine, EvalContext, Position, RhaiResultOf};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
/// Information on a variable definition.
|
||||
#[non_exhaustive]
|
||||
pub struct VarDefInfo<'a> {
|
||||
/// Name of the variable to be defined.
|
||||
pub name: &'a str,
|
||||
/// `true` if the statement is `const`, otherwise it is `let`.
|
||||
pub is_const: bool,
|
||||
/// The current nesting level, with zero being the global level.
|
||||
pub nesting_level: usize,
|
||||
/// Will the variable _shadow_ an existing variable?
|
||||
pub will_shadow: bool,
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
/// Provide a callback that will be invoked before each variable access.
|
||||
///
|
||||
@ -65,18 +78,19 @@ impl Engine {
|
||||
}
|
||||
/// Provide a callback that will be invoked before the definition of each variable .
|
||||
///
|
||||
/// # WARNING - Unstable API
|
||||
///
|
||||
/// This API is volatile and may change in the future.
|
||||
///
|
||||
/// # Callback Function Signature
|
||||
///
|
||||
/// The callback function signature takes the following form:
|
||||
///
|
||||
/// > `Fn(name: &str, is_const: bool, block_level: usize, will_shadow: bool, context: &EvalContext) -> Result<bool, Box<EvalAltResult>>`
|
||||
/// > `Fn(is_runtime: bool, info: VarInfo, context: &EvalContext) -> Result<bool, Box<EvalAltResult>>`
|
||||
///
|
||||
/// where:
|
||||
/// * `name`: name of the variable to be defined.
|
||||
/// * `is_runtime`: `true` if the variable definition event happens during runtime, `false` if during compilation.
|
||||
/// * `is_const`: `true` if the statement is `const`, otherwise it is `let`.
|
||||
/// * `block_level`: the current nesting level of statement blocks, with zero being the global level.
|
||||
/// * `will_shadow`: will the variable _shadow_ an existing variable?
|
||||
/// * `info`: information on the variable.
|
||||
/// * `context`: the current [evaluation context][`EvalContext`].
|
||||
///
|
||||
/// ## Return value
|
||||
@ -97,9 +111,9 @@ impl Engine {
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Register a variable definition filter.
|
||||
/// engine.on_def_var(|name, _, is_const, _, _, _| {
|
||||
/// engine.on_def_var(|_, info, _| {
|
||||
/// // Disallow defining MYSTIC_NUMBER as a constant
|
||||
/// if name == "MYSTIC_NUMBER" && is_const {
|
||||
/// if info.name == "MYSTIC_NUMBER" && info.is_const {
|
||||
/// Ok(false)
|
||||
/// } else {
|
||||
/// Ok(true)
|
||||
@ -115,12 +129,11 @@ impl Engine {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[deprecated = "This API is volatile and may change in the future."]
|
||||
#[inline(always)]
|
||||
pub fn on_def_var(
|
||||
&mut self,
|
||||
callback: impl Fn(&str, bool, bool, usize, bool, &EvalContext) -> RhaiResultOf<bool>
|
||||
+ SendSync
|
||||
+ 'static,
|
||||
callback: impl Fn(bool, VarDefInfo, &EvalContext) -> RhaiResultOf<bool> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
self.def_var_filter = Some(Box::new(callback));
|
||||
self
|
||||
@ -322,8 +335,13 @@ impl Engine {
|
||||
self.debug = Some(Box::new(callback));
|
||||
self
|
||||
}
|
||||
/// _(debugging)_ Register callbacks for debugging.
|
||||
/// _(debugging)_ Register a callback for debugging.
|
||||
/// Exported under the `debugging` feature only.
|
||||
///
|
||||
/// # WARNING - Unstable API
|
||||
///
|
||||
/// This API is volatile and may change in the future.
|
||||
#[deprecated = "This API is volatile and may change in the future."]
|
||||
#[cfg(feature = "debugging")]
|
||||
#[inline(always)]
|
||||
pub fn register_debugger(
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Module defining functions for evaluating a statement.
|
||||
|
||||
use super::{EvalContext, EvalState, GlobalRuntimeState, Target};
|
||||
use crate::api::events::VarDefInfo;
|
||||
use crate::ast::{
|
||||
BinaryExpr, Expr, Ident, OpAssignment, Stmt, SwitchCases, TryCatchBlock, AST_OPTION_FLAGS::*,
|
||||
};
|
||||
@ -818,9 +819,15 @@ impl Engine {
|
||||
let export = options.contains(AST_OPTION_EXPORTED);
|
||||
|
||||
let result = if let Some(ref filter) = self.def_var_filter {
|
||||
let shadowing = scope.contains(var_name);
|
||||
let scope_level = state.scope_level;
|
||||
let will_shadow = scope.contains(var_name);
|
||||
let nesting_level = state.scope_level;
|
||||
let is_const = entry_type == AccessMode::ReadOnly;
|
||||
let info = VarDefInfo {
|
||||
name: var_name,
|
||||
is_const,
|
||||
nesting_level,
|
||||
will_shadow,
|
||||
};
|
||||
let context = EvalContext {
|
||||
engine: self,
|
||||
scope,
|
||||
@ -828,10 +835,10 @@ impl Engine {
|
||||
state,
|
||||
lib,
|
||||
this_ptr,
|
||||
level: level,
|
||||
level,
|
||||
};
|
||||
|
||||
match filter(var_name, true, is_const, scope_level, shadowing, &context) {
|
||||
match filter(true, info, &context) {
|
||||
Ok(true) => None,
|
||||
Ok(false) => {
|
||||
Some(Err(
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Module defining interfaces to native-Rust functions.
|
||||
|
||||
use super::call::FnCallArgs;
|
||||
use crate::api::events::VarDefInfo;
|
||||
use crate::ast::FnCallHashes;
|
||||
use crate::eval::{EvalState, GlobalRuntimeState};
|
||||
use crate::plugin::PluginFunction;
|
||||
@ -447,9 +448,8 @@ pub type OnVarCallback =
|
||||
|
||||
/// Callback function for variable definition.
|
||||
#[cfg(not(feature = "sync"))]
|
||||
pub type OnDefVarCallback =
|
||||
dyn Fn(&str, bool, bool, usize, bool, &EvalContext) -> RhaiResultOf<bool>;
|
||||
pub type OnDefVarCallback = dyn Fn(bool, VarDefInfo, &EvalContext) -> RhaiResultOf<bool>;
|
||||
/// Callback function for variable definition.
|
||||
#[cfg(feature = "sync")]
|
||||
pub type OnDefVarCallback =
|
||||
dyn Fn(&str, bool, bool, usize, bool, &EvalContext) -> RhaiResultOf<bool> + Send + Sync;
|
||||
dyn Fn(bool, VarDefInfo, &EvalContext) -> RhaiResultOf<bool> + Send + Sync;
|
||||
|
@ -147,6 +147,7 @@ type ExclusiveRange = std::ops::Range<INT>;
|
||||
type InclusiveRange = std::ops::RangeInclusive<INT>;
|
||||
|
||||
pub use api::custom_syntax::Expression;
|
||||
pub use api::events::VarDefInfo;
|
||||
pub use ast::{FnAccess, AST};
|
||||
pub use engine::{Engine, OP_CONTAINS, OP_EQUALS};
|
||||
pub use eval::EvalContext;
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Main module defining the lexer and parser.
|
||||
|
||||
use crate::api::custom_syntax::{markers::*, CustomSyntax};
|
||||
use crate::api::events::VarDefInfo;
|
||||
use crate::api::options::LanguageOptions;
|
||||
use crate::ast::{
|
||||
BinaryExpr, ConditionalStmtBlock, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident,
|
||||
@ -109,7 +110,7 @@ impl<'e> ParseState<'e> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn access_var(&mut self, name: &str, pos: Position) -> Option<NonZeroUsize> {
|
||||
let mut barrier = false;
|
||||
let mut hit_barrier = false;
|
||||
let _pos = pos;
|
||||
|
||||
let index = self
|
||||
@ -119,7 +120,7 @@ impl<'e> ParseState<'e> {
|
||||
.find(|&(.., (n, ..))| {
|
||||
if n == SCOPE_SEARCH_BARRIER_MARKER {
|
||||
// Do not go beyond the barrier
|
||||
barrier = true;
|
||||
hit_barrier = true;
|
||||
false
|
||||
} else {
|
||||
n == name
|
||||
@ -139,7 +140,7 @@ impl<'e> ParseState<'e> {
|
||||
self.allow_capture = true
|
||||
}
|
||||
|
||||
if barrier {
|
||||
if hit_barrier {
|
||||
None
|
||||
} else {
|
||||
index
|
||||
@ -2566,16 +2567,13 @@ fn parse_for(
|
||||
let name = state.get_identifier("", name);
|
||||
let pos = counter_pos.expect("`Some`");
|
||||
state.stack.push(name.clone(), ());
|
||||
Ident {
|
||||
name: name.clone(),
|
||||
pos,
|
||||
}
|
||||
Ident { name, pos }
|
||||
});
|
||||
|
||||
let loop_var = state.get_identifier("", name);
|
||||
state.stack.push(loop_var.clone(), ());
|
||||
let loop_var = Ident {
|
||||
name: loop_var.clone(),
|
||||
name: loop_var,
|
||||
pos: name_pos,
|
||||
};
|
||||
|
||||
@ -2617,9 +2615,15 @@ fn parse_let(
|
||||
}
|
||||
|
||||
if let Some(ref filter) = state.engine.def_var_filter {
|
||||
let shadowing = state.stack.iter().any(|(v, ..)| v == name.as_ref());
|
||||
let will_shadow = state.stack.iter().any(|(v, ..)| v == name.as_ref());
|
||||
let level = settings.level;
|
||||
let is_const = var_type == AccessMode::ReadOnly;
|
||||
let info = VarDefInfo {
|
||||
name: &name,
|
||||
is_const,
|
||||
nesting_level: level,
|
||||
will_shadow,
|
||||
};
|
||||
let context = EvalContext {
|
||||
engine: state.engine,
|
||||
scope: &mut state.stack,
|
||||
@ -2630,7 +2634,7 @@ fn parse_let(
|
||||
level,
|
||||
};
|
||||
|
||||
match filter(&name, false, is_const, level, shadowing, &context) {
|
||||
match filter(false, info, &context) {
|
||||
Ok(true) => (),
|
||||
Ok(false) => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)),
|
||||
Err(err) => match *err {
|
||||
|
@ -128,7 +128,7 @@ fn test_var_def_filter() -> Result<(), Box<EvalAltResult>> {
|
||||
let ast = engine.compile("let x = 42;")?;
|
||||
engine.run_ast(&ast)?;
|
||||
|
||||
engine.on_def_var(|name, _, _, scope_level, _, _| match (name, scope_level) {
|
||||
engine.on_def_var(|_, info, _| match (info.name, info.nesting_level) {
|
||||
("x", 0 | 1) => Ok(false),
|
||||
_ => Ok(true),
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user