Add language options.
This commit is contained in:
parent
9a5bd9396a
commit
7cd76c6d18
@ -14,6 +14,11 @@ Bug fixes
|
|||||||
|
|
||||||
* BLOB's no longer panic when accessed with an out-of-bounds index.
|
* BLOB's no longer panic when accessed with an out-of-bounds index.
|
||||||
|
|
||||||
|
New features
|
||||||
|
------------
|
||||||
|
|
||||||
|
* New options for `Engine` which allows disabling `if`-expressions, `switch`-expressions, statement expressions and/or anonymous functions.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -7,8 +7,7 @@ use std::prelude::v1::*;
|
|||||||
|
|
||||||
use std::num::{NonZeroU64, NonZeroUsize};
|
use std::num::{NonZeroU64, NonZeroUsize};
|
||||||
|
|
||||||
/// _(internals)_ A type containing all the limits imposed by the [`Engine`].
|
/// A type containing all the limits imposed by the [`Engine`].
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
///
|
///
|
||||||
/// Not available under `unchecked`.
|
/// Not available under `unchecked`.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
|
@ -12,6 +12,8 @@ pub mod register;
|
|||||||
|
|
||||||
pub mod call_fn;
|
pub mod call_fn;
|
||||||
|
|
||||||
|
pub mod options;
|
||||||
|
|
||||||
pub mod limits;
|
pub mod limits;
|
||||||
|
|
||||||
pub mod events;
|
pub mod events;
|
||||||
|
87
src/api/options.rs
Normal file
87
src/api/options.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
//! Settings for [`Engine`]'s language options.
|
||||||
|
|
||||||
|
use crate::Engine;
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
/// A type containing all language options for the [`Engine`].
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct LanguageOptions {
|
||||||
|
/// Is `if`-expression allowed?
|
||||||
|
pub allow_if_expr: bool,
|
||||||
|
/// Is `switch` expression allowed?
|
||||||
|
pub allow_switch_expr: bool,
|
||||||
|
/// Is statement-expression allowed?
|
||||||
|
pub allow_stmt_expr: bool,
|
||||||
|
/// Is anonymous function allowed?
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
pub allow_anonymous_fn: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LanguageOptions {
|
||||||
|
/// Create a new [`Options`] with default values.
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
allow_if_expr: true,
|
||||||
|
allow_switch_expr: true,
|
||||||
|
allow_stmt_expr: true,
|
||||||
|
allow_anonymous_fn: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LanguageOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
/// Is `if`-expression allowed?
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn allow_if_expression(&self) -> bool {
|
||||||
|
self.options.allow_if_expr
|
||||||
|
}
|
||||||
|
/// Set whether `if`-expression is allowed.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_allow_if_expression(&mut self, enable: bool) {
|
||||||
|
self.options.allow_if_expr = enable;
|
||||||
|
}
|
||||||
|
/// Is `switch` expression allowed?
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn allow_switch_expression(&self) -> bool {
|
||||||
|
self.options.allow_switch_expr
|
||||||
|
}
|
||||||
|
/// Set whether `switch` expression is allowed.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_allow_switch_expression(&mut self, enable: bool) {
|
||||||
|
self.options.allow_switch_expr = enable;
|
||||||
|
}
|
||||||
|
/// Is statement-expression allowed?
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn allow_statement_expression(&self) -> bool {
|
||||||
|
self.options.allow_stmt_expr
|
||||||
|
}
|
||||||
|
/// Set whether statement-expression is allowed.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_allow_statement_expression(&mut self, enable: bool) {
|
||||||
|
self.options.allow_stmt_expr = enable;
|
||||||
|
}
|
||||||
|
/// Is anonymous function allowed?
|
||||||
|
///
|
||||||
|
/// Not available under `no_function`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn allow_anonymous_fn(&self) -> bool {
|
||||||
|
self.options.allow_anonymous_fn
|
||||||
|
}
|
||||||
|
/// Set whether anonymous function is allowed.
|
||||||
|
///
|
||||||
|
/// Not available under `no_function`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_allow_anonymous_fn(&mut self, enable: bool) {
|
||||||
|
self.options.allow_anonymous_fn = enable;
|
||||||
|
}
|
||||||
|
}
|
@ -973,6 +973,9 @@ pub struct Engine {
|
|||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
pub(crate) optimization_level: crate::OptimizationLevel,
|
pub(crate) optimization_level: crate::OptimizationLevel,
|
||||||
|
|
||||||
|
/// Language options.
|
||||||
|
pub(crate) options: crate::api::options::LanguageOptions,
|
||||||
|
|
||||||
/// Max limits.
|
/// Max limits.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) limits: crate::api::limits::Limits,
|
pub(crate) limits: crate::api::limits::Limits,
|
||||||
@ -1096,6 +1099,8 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
optimization_level: crate::OptimizationLevel::default(),
|
optimization_level: crate::OptimizationLevel::default(),
|
||||||
|
|
||||||
|
options: crate::api::options::LanguageOptions::new(),
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
limits: crate::api::limits::Limits::new(),
|
limits: crate::api::limits::Limits::new(),
|
||||||
};
|
};
|
||||||
|
@ -214,10 +214,6 @@ pub use ast::FloatWrapper;
|
|||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use engine::{EvalState, FnResolutionCache, FnResolutionCacheEntry, Imports};
|
pub use engine::{EvalState, FnResolutionCache, FnResolutionCacheEntry, Imports};
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
pub use api::limits::Limits;
|
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use module::NamespaceRef;
|
pub use module::NamespaceRef;
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Main module defining the lexer and parser.
|
//! Main module defining the lexer and parser.
|
||||||
|
|
||||||
|
use crate::api::options::LanguageOptions;
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ScriptFnDef, Stmt,
|
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ScriptFnDef, Stmt,
|
||||||
StmtBlock, AST_OPTION_FLAGS::*,
|
StmtBlock, AST_OPTION_FLAGS::*,
|
||||||
@ -227,12 +228,14 @@ struct ParseSettings {
|
|||||||
is_function_scope: bool,
|
is_function_scope: bool,
|
||||||
/// Is the current position inside a loop?
|
/// Is the current position inside a loop?
|
||||||
is_breakable: bool,
|
is_breakable: bool,
|
||||||
|
/// Default language options.
|
||||||
|
default_options: LanguageOptions,
|
||||||
/// Is anonymous function allowed?
|
/// Is anonymous function allowed?
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
allow_anonymous_fn: bool,
|
allow_anonymous_fn: bool,
|
||||||
/// Is if-expression allowed?
|
/// Is `if`-expression allowed?
|
||||||
allow_if_expr: bool,
|
allow_if_expr: bool,
|
||||||
/// Is switch expression allowed?
|
/// Is `switch` expression allowed?
|
||||||
allow_switch_expr: bool,
|
allow_switch_expr: bool,
|
||||||
/// Is statement-expression allowed?
|
/// Is statement-expression allowed?
|
||||||
allow_stmt_expr: bool,
|
allow_stmt_expr: bool,
|
||||||
@ -1167,15 +1170,15 @@ fn parse_primary(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
allow_if_expr: true,
|
allow_if_expr: settings.default_options.allow_if_expr,
|
||||||
allow_switch_expr: true,
|
allow_switch_expr: settings.default_options.allow_switch_expr,
|
||||||
allow_stmt_expr: true,
|
allow_stmt_expr: settings.default_options.allow_stmt_expr,
|
||||||
allow_anonymous_fn: true,
|
allow_anonymous_fn: settings.default_options.allow_anonymous_fn,
|
||||||
is_global: false,
|
is_global: false,
|
||||||
is_function_scope: true,
|
is_function_scope: true,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
level: 0,
|
level: 0,
|
||||||
pos: settings.pos,
|
..settings
|
||||||
};
|
};
|
||||||
|
|
||||||
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
||||||
@ -2795,15 +2798,16 @@ fn parse_stmt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
allow_if_expr: true,
|
allow_if_expr: settings.default_options.allow_if_expr,
|
||||||
allow_switch_expr: true,
|
allow_switch_expr: settings.default_options.allow_switch_expr,
|
||||||
allow_stmt_expr: true,
|
allow_stmt_expr: settings.default_options.allow_stmt_expr,
|
||||||
allow_anonymous_fn: true,
|
allow_anonymous_fn: settings.default_options.allow_anonymous_fn,
|
||||||
is_global: false,
|
is_global: false,
|
||||||
is_function_scope: true,
|
is_function_scope: true,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
level: 0,
|
level: 0,
|
||||||
pos,
|
pos,
|
||||||
|
..settings
|
||||||
};
|
};
|
||||||
|
|
||||||
let func = parse_fn(
|
let func = parse_fn(
|
||||||
@ -3232,6 +3236,7 @@ impl Engine {
|
|||||||
let mut functions = BTreeMap::new();
|
let mut functions = BTreeMap::new();
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
|
default_options: self.options,
|
||||||
allow_if_expr: false,
|
allow_if_expr: false,
|
||||||
allow_switch_expr: false,
|
allow_switch_expr: false,
|
||||||
allow_stmt_expr: false,
|
allow_stmt_expr: false,
|
||||||
@ -3288,11 +3293,12 @@ impl Engine {
|
|||||||
|
|
||||||
while !input.peek().expect(NEVER_ENDS).0.is_eof() {
|
while !input.peek().expect(NEVER_ENDS).0.is_eof() {
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
allow_if_expr: true,
|
default_options: self.options,
|
||||||
allow_switch_expr: true,
|
allow_if_expr: self.options.allow_if_expr,
|
||||||
allow_stmt_expr: true,
|
allow_switch_expr: self.options.allow_switch_expr,
|
||||||
|
allow_stmt_expr: self.options.allow_stmt_expr,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
allow_anonymous_fn: true,
|
allow_anonymous_fn: self.options.allow_anonymous_fn,
|
||||||
is_global: true,
|
is_global: true,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
is_function_scope: false,
|
is_function_scope: false,
|
||||||
|
@ -15,8 +15,10 @@ fn check_struct_sizes() {
|
|||||||
|
|
||||||
assert_eq!(size_of::<Dynamic>(), if PACKED { 8 } else { 16 });
|
assert_eq!(size_of::<Dynamic>(), if PACKED { 8 } else { 16 });
|
||||||
assert_eq!(size_of::<Option<Dynamic>>(), if PACKED { 8 } else { 16 });
|
assert_eq!(size_of::<Option<Dynamic>>(), if PACKED { 8 } else { 16 });
|
||||||
#[cfg(not(feature = "no_position"))]
|
assert_eq!(
|
||||||
assert_eq!(size_of::<Position>(), 4);
|
size_of::<Position>(),
|
||||||
|
if cfg!(feature = "no_position") { 0 } else { 4 }
|
||||||
|
);
|
||||||
assert_eq!(size_of::<ast::Expr>(), 16);
|
assert_eq!(size_of::<ast::Expr>(), 16);
|
||||||
assert_eq!(size_of::<Option<ast::Expr>>(), 16);
|
assert_eq!(size_of::<Option<ast::Expr>>(), 16);
|
||||||
assert_eq!(size_of::<ast::Stmt>(), 32);
|
assert_eq!(size_of::<ast::Stmt>(), 32);
|
||||||
|
26
tests/options.rs
Normal file
26
tests/options.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use rhai::{Engine, EvalAltResult};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_options() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
engine.compile("let x = if y { z } else { w };")?;
|
||||||
|
|
||||||
|
engine.set_allow_if_expression(false);
|
||||||
|
|
||||||
|
assert!(engine.compile("let x = if y { z } else { w };").is_err());
|
||||||
|
|
||||||
|
engine.compile("let x = { let z = 0; z + 1 };")?;
|
||||||
|
|
||||||
|
engine.set_allow_statement_expression(false);
|
||||||
|
|
||||||
|
assert!(engine.compile("let x = { let z = 0; z + 1 };").is_err());
|
||||||
|
|
||||||
|
engine.compile("let x = || 42;")?;
|
||||||
|
|
||||||
|
engine.set_allow_anonymous_fn(false);
|
||||||
|
|
||||||
|
assert!(engine.compile("let x = || 42;").is_err());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user