Rename AccessType to ReadWrite and ReadOnly.
This commit is contained in:
parent
7598ec136f
commit
dbee0eb0f5
@ -8,6 +8,7 @@ Bug fixes
|
||||
---------
|
||||
|
||||
* Constants are no longer propagated by the optimizer if shadowed by a non-constant variable.
|
||||
* Constants passed as the `this` parameter to Rhai functions now throws an error if assigned to.
|
||||
|
||||
|
||||
Version 0.19.7
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Module defining the AST (abstract syntax tree).
|
||||
|
||||
use crate::dynamic::{AccessType, Union};
|
||||
use crate::dynamic::{AccessMode, Union};
|
||||
use crate::fn_native::shared_make_mut;
|
||||
use crate::module::NamespaceRef;
|
||||
use crate::stdlib::{
|
||||
@ -942,7 +942,7 @@ impl Expr {
|
||||
Self::StringConstant(x, _) => x.clone().into(),
|
||||
Self::FnPointer(x, _) => Dynamic(Union::FnPtr(
|
||||
Box::new(FnPtr::new_unchecked(x.clone(), Default::default())),
|
||||
AccessType::Constant,
|
||||
AccessMode::ReadOnly,
|
||||
)),
|
||||
Self::BoolConstant(x, _) => (*x).into(),
|
||||
Self::Unit(_) => ().into(),
|
||||
@ -954,7 +954,7 @@ impl Expr {
|
||||
x.len(),
|
||||
));
|
||||
arr.extend(x.iter().map(|v| v.get_constant_value().unwrap()));
|
||||
Dynamic(Union::Array(Box::new(arr), AccessType::Constant))
|
||||
Dynamic(Union::Array(Box::new(arr), AccessMode::ReadOnly))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
@ -967,7 +967,7 @@ impl Expr {
|
||||
x.iter()
|
||||
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())),
|
||||
);
|
||||
Dynamic(Union::Map(Box::new(map), AccessType::Constant))
|
||||
Dynamic(Union::Map(Box::new(map), AccessMode::ReadOnly))
|
||||
}
|
||||
|
||||
_ => return None,
|
||||
|
124
src/dynamic.rs
124
src/dynamic.rs
@ -116,21 +116,21 @@ impl dyn Variant {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of an entry in the Scope.
|
||||
/// Modes of access.
|
||||
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
||||
pub enum AccessType {
|
||||
/// Normal value.
|
||||
Normal,
|
||||
/// Immutable constant value.
|
||||
Constant,
|
||||
pub enum AccessMode {
|
||||
/// Mutable.
|
||||
ReadWrite,
|
||||
/// Immutable.
|
||||
ReadOnly,
|
||||
}
|
||||
|
||||
impl AccessType {
|
||||
/// Is the access type [`Constant`]?
|
||||
pub fn is_constant(self) -> bool {
|
||||
impl AccessMode {
|
||||
/// Is the access type [`ReadOnly`]?
|
||||
pub fn is_read_only(self) -> bool {
|
||||
match self {
|
||||
Self::Normal => false,
|
||||
Self::Constant => true,
|
||||
Self::ReadWrite => false,
|
||||
Self::ReadOnly => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,25 +142,25 @@ pub struct Dynamic(pub(crate) Union);
|
||||
///
|
||||
/// Most variants are boxed to reduce the size.
|
||||
pub enum Union {
|
||||
Unit((), AccessType),
|
||||
Bool(bool, AccessType),
|
||||
Str(ImmutableString, AccessType),
|
||||
Char(char, AccessType),
|
||||
Int(INT, AccessType),
|
||||
Unit((), AccessMode),
|
||||
Bool(bool, AccessMode),
|
||||
Str(ImmutableString, AccessMode),
|
||||
Char(char, AccessMode),
|
||||
Int(INT, AccessMode),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Float(FLOAT, AccessType),
|
||||
Float(FLOAT, AccessMode),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Array(Box<Array>, AccessType),
|
||||
Array(Box<Array>, AccessMode),
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Map(Box<Map>, AccessType),
|
||||
FnPtr(Box<FnPtr>, AccessType),
|
||||
Map(Box<Map>, AccessMode),
|
||||
FnPtr(Box<FnPtr>, AccessMode),
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
TimeStamp(Box<Instant>, AccessType),
|
||||
TimeStamp(Box<Instant>, AccessMode),
|
||||
|
||||
Variant(Box<Box<dyn Variant>>, AccessType),
|
||||
Variant(Box<Box<dyn Variant>>, AccessMode),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Shared(crate::Shared<crate::Locked<Dynamic>>, AccessType),
|
||||
Shared(crate::Shared<crate::Locked<Dynamic>>, AccessMode),
|
||||
}
|
||||
|
||||
/// Underlying [`Variant`] read guard for [`Dynamic`].
|
||||
@ -506,27 +506,27 @@ impl Clone for Dynamic {
|
||||
/// The cloned copy is marked [`AccessType::Normal`] even if the original is constant.
|
||||
fn clone(&self) -> Self {
|
||||
match self.0 {
|
||||
Union::Unit(value, _) => Self(Union::Unit(value, AccessType::Normal)),
|
||||
Union::Bool(value, _) => Self(Union::Bool(value, AccessType::Normal)),
|
||||
Union::Str(ref value, _) => Self(Union::Str(value.clone(), AccessType::Normal)),
|
||||
Union::Char(value, _) => Self(Union::Char(value, AccessType::Normal)),
|
||||
Union::Int(value, _) => Self(Union::Int(value, AccessType::Normal)),
|
||||
Union::Unit(value, _) => Self(Union::Unit(value, AccessMode::ReadWrite)),
|
||||
Union::Bool(value, _) => Self(Union::Bool(value, AccessMode::ReadWrite)),
|
||||
Union::Str(ref value, _) => Self(Union::Str(value.clone(), AccessMode::ReadWrite)),
|
||||
Union::Char(value, _) => Self(Union::Char(value, AccessMode::ReadWrite)),
|
||||
Union::Int(value, _) => Self(Union::Int(value, AccessMode::ReadWrite)),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Union::Float(value, _) => Self(Union::Float(value, AccessType::Normal)),
|
||||
Union::Float(value, _) => Self(Union::Float(value, AccessMode::ReadWrite)),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Union::Array(ref value, _) => Self(Union::Array(value.clone(), AccessType::Normal)),
|
||||
Union::Array(ref value, _) => Self(Union::Array(value.clone(), AccessMode::ReadWrite)),
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Union::Map(ref value, _) => Self(Union::Map(value.clone(), AccessType::Normal)),
|
||||
Union::FnPtr(ref value, _) => Self(Union::FnPtr(value.clone(), AccessType::Normal)),
|
||||
Union::Map(ref value, _) => Self(Union::Map(value.clone(), AccessMode::ReadWrite)),
|
||||
Union::FnPtr(ref value, _) => Self(Union::FnPtr(value.clone(), AccessMode::ReadWrite)),
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::TimeStamp(ref value, _) => {
|
||||
Self(Union::TimeStamp(value.clone(), AccessType::Normal))
|
||||
Self(Union::TimeStamp(value.clone(), AccessMode::ReadWrite))
|
||||
}
|
||||
|
||||
Union::Variant(ref value, _) => (***value).clone_into_dynamic(),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref cell, _) => Self(Union::Shared(cell.clone(), AccessType::Normal)),
|
||||
Union::Shared(ref cell, _) => Self(Union::Shared(cell.clone(), AccessMode::ReadWrite)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -540,29 +540,29 @@ impl Default for Dynamic {
|
||||
|
||||
impl Dynamic {
|
||||
/// A [`Dynamic`] containing a `()`.
|
||||
pub const UNIT: Dynamic = Self(Union::Unit((), AccessType::Normal));
|
||||
pub const UNIT: Dynamic = Self(Union::Unit((), AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing a `true`.
|
||||
pub const TRUE: Dynamic = Self(Union::Bool(true, AccessType::Normal));
|
||||
pub const TRUE: Dynamic = Self(Union::Bool(true, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing a [`false`].
|
||||
pub const FALSE: Dynamic = Self(Union::Bool(false, AccessType::Normal));
|
||||
pub const FALSE: Dynamic = Self(Union::Bool(false, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the integer zero.
|
||||
pub const ZERO: Dynamic = Self(Union::Int(0, AccessType::Normal));
|
||||
pub const ZERO: Dynamic = Self(Union::Int(0, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the integer one.
|
||||
pub const ONE: Dynamic = Self(Union::Int(1, AccessType::Normal));
|
||||
pub const ONE: Dynamic = Self(Union::Int(1, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the integer negative one.
|
||||
pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, AccessType::Normal));
|
||||
pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the floating-point zero.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub const FLOAT_ZERO: Dynamic = Self(Union::Float(0.0, AccessType::Normal));
|
||||
pub const FLOAT_ZERO: Dynamic = Self(Union::Float(0.0, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the floating-point one.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub const FLOAT_ONE: Dynamic = Self(Union::Float(1.0, AccessType::Normal));
|
||||
pub const FLOAT_ONE: Dynamic = Self(Union::Float(1.0, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the floating-point negative one.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub const FLOAT_NEGATIVE_ONE: Dynamic = Self(Union::Float(-1.0, AccessType::Normal));
|
||||
pub const FLOAT_NEGATIVE_ONE: Dynamic = Self(Union::Float(-1.0, AccessMode::ReadWrite));
|
||||
|
||||
/// Get the [`AccessType`] for this [`Dynamic`].
|
||||
pub(crate) fn access_type(&self) -> AccessType {
|
||||
/// Get the [`AccessMode`] for this [`Dynamic`].
|
||||
pub(crate) fn access_mode(&self) -> AccessMode {
|
||||
match self.0 {
|
||||
Union::Unit(_, access)
|
||||
| Union::Bool(_, access)
|
||||
@ -584,8 +584,8 @@ impl Dynamic {
|
||||
Union::Shared(_, access) => access,
|
||||
}
|
||||
}
|
||||
/// Set the [`AccessType`] for this [`Dynamic`].
|
||||
pub(crate) fn set_access_type(&mut self, typ: AccessType) {
|
||||
/// Set the [`AccessMode`] for this [`Dynamic`].
|
||||
pub(crate) fn set_access_mode(&mut self, typ: AccessMode) {
|
||||
match &mut self.0 {
|
||||
Union::Unit(_, access)
|
||||
| Union::Bool(_, access)
|
||||
@ -615,7 +615,7 @@ impl Dynamic {
|
||||
/// if its value is going to be modified. This safe-guards constant values from being modified
|
||||
/// from within Rust functions.
|
||||
pub fn is_read_only(&self) -> bool {
|
||||
self.access_type().is_constant()
|
||||
self.access_mode().is_read_only()
|
||||
}
|
||||
/// Create a [`Dynamic`] from any type. A [`Dynamic`] value is simply returned as is.
|
||||
///
|
||||
@ -733,7 +733,7 @@ impl Dynamic {
|
||||
}
|
||||
}
|
||||
|
||||
Self(Union::Variant(Box::new(boxed), AccessType::Normal))
|
||||
Self(Union::Variant(Box::new(boxed), AccessMode::ReadWrite))
|
||||
}
|
||||
/// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an [`Rc`][std::rc::Rc]`<`[`RefCell`][std::cell::RefCell]`<`[`Dynamic`]`>>`
|
||||
/// or [`Arc`][std::sync::Arc]`<`[`RwLock`][std::sync::RwLock]`<`[`Dynamic`]`>>` depending on the `sync` feature.
|
||||
@ -750,7 +750,7 @@ impl Dynamic {
|
||||
/// Panics under the `no_closure` feature.
|
||||
#[inline(always)]
|
||||
pub fn into_shared(self) -> Self {
|
||||
let _access = self.access_type();
|
||||
let _access = self.access_mode();
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
return match self.0 {
|
||||
@ -1338,38 +1338,38 @@ impl Dynamic {
|
||||
impl From<()> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: ()) -> Self {
|
||||
Self(Union::Unit(value, AccessType::Normal))
|
||||
Self(Union::Unit(value, AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
impl From<bool> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: bool) -> Self {
|
||||
Self(Union::Bool(value, AccessType::Normal))
|
||||
Self(Union::Bool(value, AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
impl From<INT> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: INT) -> Self {
|
||||
Self(Union::Int(value, AccessType::Normal))
|
||||
Self(Union::Int(value, AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl From<FLOAT> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FLOAT) -> Self {
|
||||
Self(Union::Float(value, AccessType::Normal))
|
||||
Self(Union::Float(value, AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
impl From<char> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: char) -> Self {
|
||||
Self(Union::Char(value, AccessType::Normal))
|
||||
Self(Union::Char(value, AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
impl<S: Into<ImmutableString>> From<S> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: S) -> Self {
|
||||
Self(Union::Str(value.into(), AccessType::Normal))
|
||||
Self(Union::Str(value.into(), AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
@ -1378,7 +1378,7 @@ impl<T: Variant + Clone> From<crate::stdlib::vec::Vec<T>> for Dynamic {
|
||||
fn from(value: crate::stdlib::vec::Vec<T>) -> Self {
|
||||
Self(Union::Array(
|
||||
Box::new(value.into_iter().map(Dynamic::from).collect()),
|
||||
AccessType::Normal,
|
||||
AccessMode::ReadWrite,
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -1388,7 +1388,7 @@ impl<T: Variant + Clone> From<&[T]> for Dynamic {
|
||||
fn from(value: &[T]) -> Self {
|
||||
Self(Union::Array(
|
||||
Box::new(value.iter().cloned().map(Dynamic::from).collect()),
|
||||
AccessType::Normal,
|
||||
AccessMode::ReadWrite,
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -1405,26 +1405,26 @@ impl<K: Into<ImmutableString>, T: Variant + Clone> From<crate::stdlib::collectio
|
||||
.map(|(k, v)| (k.into(), Dynamic::from(v)))
|
||||
.collect(),
|
||||
),
|
||||
AccessType::Normal,
|
||||
AccessMode::ReadWrite,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl From<FnPtr> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FnPtr) -> Self {
|
||||
Self(Union::FnPtr(Box::new(value), AccessType::Normal))
|
||||
Self(Union::FnPtr(Box::new(value), AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
impl From<Box<FnPtr>> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: Box<FnPtr>) -> Self {
|
||||
Self(Union::FnPtr(value, AccessType::Normal))
|
||||
Self(Union::FnPtr(value, AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
impl From<Instant> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: Instant) -> Self {
|
||||
Self(Union::TimeStamp(Box::new(value), AccessType::Normal))
|
||||
Self(Union::TimeStamp(Box::new(value), AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Main module defining the script evaluation [`Engine`].
|
||||
|
||||
use crate::ast::{Expr, FnCallExpr, Ident, IdentX, ReturnType, Stmt};
|
||||
use crate::dynamic::{map_std_type_name, AccessType, Union, Variant};
|
||||
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
||||
use crate::fn_call::run_builtin_op_assignment;
|
||||
use crate::fn_native::{CallableFunction, Callback, IteratorFn, OnVarCallback};
|
||||
use crate::module::NamespaceRef;
|
||||
@ -850,7 +850,7 @@ impl Engine {
|
||||
|
||||
// Module variables are constant
|
||||
let mut target = target.clone();
|
||||
target.set_access_type(AccessType::Constant);
|
||||
target.set_access_mode(AccessMode::ReadOnly);
|
||||
Ok((target.into(), name, *pos))
|
||||
}
|
||||
// Normal variable access
|
||||
@ -905,7 +905,7 @@ impl Engine {
|
||||
if let Some(mut result) =
|
||||
resolve_var(name, index, &context).map_err(|err| err.fill_position(*pos))?
|
||||
{
|
||||
result.set_access_type(AccessType::Constant);
|
||||
result.set_access_mode(AccessMode::ReadOnly);
|
||||
return Ok((result.into(), name, *pos));
|
||||
}
|
||||
}
|
||||
@ -1732,7 +1732,7 @@ impl Engine {
|
||||
for item in x.as_ref() {
|
||||
arr.push(self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?);
|
||||
}
|
||||
Ok(Dynamic(Union::Array(Box::new(arr), AccessType::Normal)))
|
||||
Ok(Dynamic(Union::Array(Box::new(arr), AccessMode::ReadWrite)))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
@ -1745,7 +1745,7 @@ impl Engine {
|
||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?,
|
||||
);
|
||||
}
|
||||
Ok(Dynamic(Union::Map(Box::new(map), AccessType::Normal)))
|
||||
Ok(Dynamic(Union::Map(Box::new(map), AccessMode::ReadWrite)))
|
||||
}
|
||||
|
||||
// Normal function call
|
||||
@ -2289,8 +2289,8 @@ impl Engine {
|
||||
// Let/const statement
|
||||
Stmt::Let(var_def, expr, export, _) | Stmt::Const(var_def, expr, export, _) => {
|
||||
let entry_type = match stmt {
|
||||
Stmt::Let(_, _, _, _) => AccessType::Normal,
|
||||
Stmt::Const(_, _, _, _) => AccessType::Constant,
|
||||
Stmt::Let(_, _, _, _) => AccessMode::ReadWrite,
|
||||
Stmt::Const(_, _, _, _) => AccessMode::ReadOnly,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@ -2384,7 +2384,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Stmt::Share(x) => {
|
||||
match scope.get_index(&x.name) {
|
||||
Some((index, AccessType::Normal)) => {
|
||||
Some((index, AccessMode::ReadWrite)) => {
|
||||
let val = scope.get_mut(index);
|
||||
|
||||
if !val.is_shared() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Module implementing the [`AST`] optimizer.
|
||||
|
||||
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
||||
use crate::dynamic::AccessType;
|
||||
use crate::dynamic::AccessMode;
|
||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||
use crate::fn_call::run_builtin_binary_op;
|
||||
use crate::parser::map_dynamic_to_expr;
|
||||
@ -59,7 +59,7 @@ struct State<'a> {
|
||||
/// Has the [`AST`] been changed during this pass?
|
||||
changed: bool,
|
||||
/// Collection of constants to use for eager function evaluations.
|
||||
variables: Vec<(String, AccessType, Expr)>,
|
||||
variables: Vec<(String, AccessMode, Expr)>,
|
||||
/// An [`Engine`] instance for eager function evaluation.
|
||||
engine: &'a Engine,
|
||||
/// [Module] containing script-defined functions.
|
||||
@ -102,7 +102,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
/// Add a new constant to the list.
|
||||
#[inline(always)]
|
||||
pub fn push_var(&mut self, name: &str, access: AccessType, value: Expr) {
|
||||
pub fn push_var(&mut self, name: &str, access: AccessMode, value: Expr) {
|
||||
self.variables.push((name.into(), access, value))
|
||||
}
|
||||
/// Look up a constant from the list.
|
||||
@ -110,7 +110,7 @@ impl<'a> State<'a> {
|
||||
pub fn find_constant(&self, name: &str) -> Option<&Expr> {
|
||||
for (n, access, expr) in self.variables.iter().rev() {
|
||||
if n == name {
|
||||
return if access.is_constant() {
|
||||
return if access.is_read_only() {
|
||||
Some(expr)
|
||||
} else {
|
||||
None
|
||||
@ -163,14 +163,18 @@ fn optimize_stmt_block(
|
||||
statements.iter_mut().for_each(|stmt| match stmt {
|
||||
// Add constant literals into the state
|
||||
Stmt::Const(var_def, Some(expr), _, _) if expr.is_constant() => {
|
||||
state.push_var(&var_def.name, AccessType::Constant, mem::take(expr));
|
||||
state.push_var(&var_def.name, AccessMode::ReadOnly, mem::take(expr));
|
||||
}
|
||||
Stmt::Const(var_def, None, _, _) => {
|
||||
state.push_var(&var_def.name, AccessType::Constant, Expr::Unit(var_def.pos));
|
||||
state.push_var(&var_def.name, AccessMode::ReadOnly, Expr::Unit(var_def.pos));
|
||||
}
|
||||
// Add variables into the state
|
||||
Stmt::Let(var_def, _, _, _) => {
|
||||
state.push_var(&var_def.name, AccessType::Normal, Expr::Unit(var_def.pos));
|
||||
state.push_var(
|
||||
&var_def.name,
|
||||
AccessMode::ReadWrite,
|
||||
Expr::Unit(var_def.pos),
|
||||
);
|
||||
}
|
||||
// Optimize the statement
|
||||
_ => optimize_stmt(stmt, state, preserve_result),
|
||||
@ -749,11 +753,11 @@ fn optimize_top_level(
|
||||
// Add constants and variables from the scope
|
||||
scope.iter().for_each(|(name, constant, value)| {
|
||||
if !constant {
|
||||
state.push_var(name, AccessType::Normal, Expr::Unit(Position::NONE));
|
||||
state.push_var(name, AccessMode::ReadWrite, Expr::Unit(Position::NONE));
|
||||
} else if let Some(val) = map_dynamic_to_expr(value, Position::NONE) {
|
||||
state.push_var(name, AccessType::Constant, val);
|
||||
state.push_var(name, AccessMode::ReadOnly, val);
|
||||
} else {
|
||||
state.push_var(name, AccessType::Constant, Expr::Unit(Position::NONE));
|
||||
state.push_var(name, AccessMode::ReadOnly, Expr::Unit(Position::NONE));
|
||||
}
|
||||
});
|
||||
|
||||
@ -774,7 +778,7 @@ fn optimize_top_level(
|
||||
optimize_expr(value_expr, &mut state);
|
||||
|
||||
if value_expr.is_constant() {
|
||||
state.push_var(&var_def.name, AccessType::Constant, value_expr.clone());
|
||||
state.push_var(&var_def.name, AccessMode::ReadOnly, value_expr.clone());
|
||||
}
|
||||
|
||||
// Keep it in the global scope
|
||||
@ -784,10 +788,14 @@ fn optimize_top_level(
|
||||
}
|
||||
}
|
||||
Stmt::Const(var_def, None, _, _) => {
|
||||
state.push_var(&var_def.name, AccessType::Constant, Expr::Unit(var_def.pos));
|
||||
state.push_var(&var_def.name, AccessMode::ReadOnly, Expr::Unit(var_def.pos));
|
||||
}
|
||||
Stmt::Let(var_def, _, _, _) => {
|
||||
state.push_var(&var_def.name, AccessType::Normal, Expr::Unit(var_def.pos));
|
||||
state.push_var(
|
||||
&var_def.name,
|
||||
AccessMode::ReadWrite,
|
||||
Expr::Unit(var_def.pos),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
// Keep all variable declarations at this level
|
||||
|
@ -3,7 +3,7 @@
|
||||
use crate::ast::{
|
||||
BinaryExpr, CustomExpr, Expr, FnCallExpr, Ident, IdentX, ReturnType, ScriptFnDef, Stmt,
|
||||
};
|
||||
use crate::dynamic::{AccessType, Union};
|
||||
use crate::dynamic::{AccessMode, Union};
|
||||
use crate::engine::{KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||
use crate::module::NamespaceRef;
|
||||
use crate::optimize::optimize_into_ast;
|
||||
@ -48,7 +48,7 @@ struct ParseState<'e> {
|
||||
/// Interned strings.
|
||||
strings: HashMap<String, ImmutableString>,
|
||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||
stack: Vec<(ImmutableString, AccessType)>,
|
||||
stack: Vec<(ImmutableString, AccessMode)>,
|
||||
/// Size of the local variables stack upon entry of the current block scope.
|
||||
entry_stack_len: usize,
|
||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||
@ -1290,11 +1290,11 @@ fn make_assignment_stmt<'a>(
|
||||
},
|
||||
) = x.as_ref();
|
||||
match state.stack[(state.stack.len() - index.unwrap().get())].1 {
|
||||
AccessType::Normal => {
|
||||
AccessMode::ReadWrite => {
|
||||
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||
}
|
||||
// Constant values cannot be assigned to
|
||||
AccessType::Constant => {
|
||||
AccessMode::ReadOnly => {
|
||||
Err(PERR::AssignmentToConstant(name.to_string()).into_err(*name_pos))
|
||||
}
|
||||
}
|
||||
@ -1317,11 +1317,11 @@ fn make_assignment_stmt<'a>(
|
||||
},
|
||||
) = x.as_ref();
|
||||
match state.stack[(state.stack.len() - index.unwrap().get())].1 {
|
||||
AccessType::Normal => {
|
||||
AccessMode::ReadWrite => {
|
||||
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||
}
|
||||
// Constant values cannot be assigned to
|
||||
AccessType::Constant => {
|
||||
AccessMode::ReadOnly => {
|
||||
Err(PERR::AssignmentToConstant(name.to_string()).into_err(*name_pos))
|
||||
}
|
||||
}
|
||||
@ -1810,7 +1810,7 @@ fn parse_custom_syntax(
|
||||
// Variable searches stop at the first empty variable name.
|
||||
state.stack.resize(
|
||||
state.stack.len() + delta as usize,
|
||||
("".into(), AccessType::Normal),
|
||||
("".into(), AccessMode::ReadWrite),
|
||||
);
|
||||
}
|
||||
delta if delta < 0 && state.stack.len() <= delta.abs() as usize => state.stack.clear(),
|
||||
@ -2109,7 +2109,7 @@ fn parse_for(
|
||||
|
||||
let loop_var = state.get_interned_string(name.clone());
|
||||
let prev_stack_len = state.stack.len();
|
||||
state.stack.push((loop_var, AccessType::Normal));
|
||||
state.stack.push((loop_var, AccessMode::ReadWrite));
|
||||
|
||||
settings.is_breakable = true;
|
||||
let body = parse_block(input, state, lib, settings.level_up())?;
|
||||
@ -2124,7 +2124,7 @@ fn parse_let(
|
||||
input: &mut TokenStream,
|
||||
state: &mut ParseState,
|
||||
lib: &mut FunctionsLib,
|
||||
var_type: AccessType,
|
||||
var_type: AccessMode,
|
||||
export: bool,
|
||||
mut settings: ParseSettings,
|
||||
) -> Result<Stmt, ParseError> {
|
||||
@ -2155,16 +2155,16 @@ fn parse_let(
|
||||
|
||||
match var_type {
|
||||
// let name = expr
|
||||
AccessType::Normal => {
|
||||
AccessMode::ReadWrite => {
|
||||
let var_name = state.get_interned_string(name.clone());
|
||||
state.stack.push((var_name, AccessType::Normal));
|
||||
state.stack.push((var_name, AccessMode::ReadWrite));
|
||||
let var_def = Ident::new(name, pos);
|
||||
Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos))
|
||||
}
|
||||
// const name = { expr:constant }
|
||||
AccessType::Constant => {
|
||||
AccessMode::ReadOnly => {
|
||||
let var_name = state.get_interned_string(name.clone());
|
||||
state.stack.push((var_name, AccessType::Constant));
|
||||
state.stack.push((var_name, AccessMode::ReadOnly));
|
||||
let var_def = Ident::new(name, pos);
|
||||
Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos))
|
||||
}
|
||||
@ -2231,13 +2231,13 @@ fn parse_export(
|
||||
match input.peek().unwrap() {
|
||||
(Token::Let, pos) => {
|
||||
let pos = *pos;
|
||||
let mut stmt = parse_let(input, state, lib, AccessType::Normal, true, settings)?;
|
||||
let mut stmt = parse_let(input, state, lib, AccessMode::ReadWrite, true, settings)?;
|
||||
stmt.set_position(pos);
|
||||
return Ok(stmt);
|
||||
}
|
||||
(Token::Const, pos) => {
|
||||
let pos = *pos;
|
||||
let mut stmt = parse_let(input, state, lib, AccessType::Constant, true, settings)?;
|
||||
let mut stmt = parse_let(input, state, lib, AccessMode::ReadOnly, true, settings)?;
|
||||
stmt.set_position(pos);
|
||||
return Ok(stmt);
|
||||
}
|
||||
@ -2392,7 +2392,7 @@ fn parse_stmt(
|
||||
lib: &mut FunctionsLib,
|
||||
mut settings: ParseSettings,
|
||||
) -> Result<Option<Stmt>, ParseError> {
|
||||
use AccessType::{Constant, Normal};
|
||||
use AccessMode::{ReadOnly, ReadWrite};
|
||||
|
||||
let (token, token_pos) = match input.peek().unwrap() {
|
||||
(Token::EOF, pos) => return Ok(Some(Stmt::Noop(*pos))),
|
||||
@ -2520,9 +2520,9 @@ fn parse_stmt(
|
||||
|
||||
Token::Try => parse_try_catch(input, state, lib, settings.level_up()).map(Some),
|
||||
|
||||
Token::Let => parse_let(input, state, lib, Normal, false, settings.level_up()).map(Some),
|
||||
Token::Let => parse_let(input, state, lib, ReadWrite, false, settings.level_up()).map(Some),
|
||||
Token::Const => {
|
||||
parse_let(input, state, lib, Constant, false, settings.level_up()).map(Some)
|
||||
parse_let(input, state, lib, ReadOnly, false, settings.level_up()).map(Some)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
@ -2636,7 +2636,7 @@ fn parse_fn(
|
||||
return Err(PERR::FnDuplicatedParam(name, s).into_err(pos));
|
||||
}
|
||||
let s = state.get_interned_string(s);
|
||||
state.stack.push((s.clone(), AccessType::Normal));
|
||||
state.stack.push((s.clone(), AccessMode::ReadWrite));
|
||||
params.push((s, pos))
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
||||
@ -2769,7 +2769,7 @@ fn parse_anon_fn(
|
||||
return Err(PERR::FnDuplicatedParam("".to_string(), s).into_err(pos));
|
||||
}
|
||||
let s = state.get_interned_string(s);
|
||||
state.stack.push((s.clone(), AccessType::Normal));
|
||||
state.stack.push((s.clone(), AccessMode::ReadWrite));
|
||||
params.push((s, pos))
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
||||
|
22
src/scope.rs
22
src/scope.rs
@ -1,6 +1,6 @@
|
||||
//! Module that defines the [`Scope`] type representing a function call-stack scope.
|
||||
|
||||
use crate::dynamic::{AccessType, Variant};
|
||||
use crate::dynamic::{AccessMode, Variant};
|
||||
use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};
|
||||
use crate::{Dynamic, StaticVec};
|
||||
|
||||
@ -156,7 +156,7 @@ impl<'a> Scope<'a> {
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
value: impl Variant + Clone,
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(name, AccessType::Normal, Dynamic::from(value))
|
||||
self.push_dynamic_value(name, AccessMode::ReadWrite, Dynamic::from(value))
|
||||
}
|
||||
/// Add (push) a new [`Dynamic`] entry to the [`Scope`].
|
||||
///
|
||||
@ -172,7 +172,7 @@ impl<'a> Scope<'a> {
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self {
|
||||
self.push_dynamic_value(name, value.access_type(), value)
|
||||
self.push_dynamic_value(name, value.access_mode(), value)
|
||||
}
|
||||
/// Add (push) a new constant to the [`Scope`].
|
||||
///
|
||||
@ -195,7 +195,7 @@ impl<'a> Scope<'a> {
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
value: impl Variant + Clone,
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(name, AccessType::Constant, Dynamic::from(value))
|
||||
self.push_dynamic_value(name, AccessMode::ReadOnly, Dynamic::from(value))
|
||||
}
|
||||
/// Add (push) a new constant with a [`Dynamic`] value to the Scope.
|
||||
///
|
||||
@ -218,18 +218,18 @@ impl<'a> Scope<'a> {
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
value: Dynamic,
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(name, AccessType::Constant, value)
|
||||
self.push_dynamic_value(name, AccessMode::ReadOnly, value)
|
||||
}
|
||||
/// Add (push) a new entry with a [`Dynamic`] value to the [`Scope`].
|
||||
#[inline]
|
||||
pub(crate) fn push_dynamic_value(
|
||||
&mut self,
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
access: AccessType,
|
||||
access: AccessMode,
|
||||
mut value: Dynamic,
|
||||
) -> &mut Self {
|
||||
self.names.push((name.into(), Box::new(Default::default())));
|
||||
value.set_access_type(access);
|
||||
value.set_access_mode(access);
|
||||
self.values.push(value.into());
|
||||
self
|
||||
}
|
||||
@ -287,14 +287,14 @@ impl<'a> Scope<'a> {
|
||||
}
|
||||
/// Find an entry in the [`Scope`], starting from the last.
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, AccessType)> {
|
||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, AccessMode)> {
|
||||
self.names
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev() // Always search a Scope in reverse order
|
||||
.find_map(|(index, (key, _))| {
|
||||
if name == key.as_ref() {
|
||||
Some((index, self.values[index].access_type()))
|
||||
Some((index, self.values[index].access_mode()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -349,8 +349,8 @@ impl<'a> Scope<'a> {
|
||||
None => {
|
||||
self.push(name, value);
|
||||
}
|
||||
Some((_, AccessType::Constant)) => panic!("variable {} is constant", name),
|
||||
Some((index, AccessType::Normal)) => {
|
||||
Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name),
|
||||
Some((index, AccessMode::ReadWrite)) => {
|
||||
*self.values.get_mut(index).unwrap() = Dynamic::from(value);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user