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