Rename AccessType to ReadWrite and ReadOnly.

This commit is contained in:
Stephen Chung 2020-12-09 18:37:52 +08:00
parent 7598ec136f
commit dbee0eb0f5
7 changed files with 127 additions and 118 deletions

View File

@ -8,6 +8,7 @@ Bug fixes
--------- ---------
* Constants are no longer propagated by the optimizer if shadowed by a non-constant variable. * 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 Version 0.19.7

View File

@ -1,6 +1,6 @@
//! Module defining the AST (abstract syntax tree). //! 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::fn_native::shared_make_mut;
use crate::module::NamespaceRef; use crate::module::NamespaceRef;
use crate::stdlib::{ use crate::stdlib::{
@ -942,7 +942,7 @@ impl Expr {
Self::StringConstant(x, _) => x.clone().into(), Self::StringConstant(x, _) => x.clone().into(),
Self::FnPointer(x, _) => Dynamic(Union::FnPtr( Self::FnPointer(x, _) => Dynamic(Union::FnPtr(
Box::new(FnPtr::new_unchecked(x.clone(), Default::default())), Box::new(FnPtr::new_unchecked(x.clone(), Default::default())),
AccessType::Constant, AccessMode::ReadOnly,
)), )),
Self::BoolConstant(x, _) => (*x).into(), Self::BoolConstant(x, _) => (*x).into(),
Self::Unit(_) => ().into(), Self::Unit(_) => ().into(),
@ -954,7 +954,7 @@ impl Expr {
x.len(), x.len(),
)); ));
arr.extend(x.iter().map(|v| v.get_constant_value().unwrap())); 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"))] #[cfg(not(feature = "no_object"))]
@ -967,7 +967,7 @@ impl Expr {
x.iter() x.iter()
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())), .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, _ => return None,

View File

@ -116,21 +116,21 @@ impl dyn Variant {
} }
} }
/// Type of an entry in the Scope. /// Modes of access.
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
pub enum AccessType { pub enum AccessMode {
/// Normal value. /// Mutable.
Normal, ReadWrite,
/// Immutable constant value. /// Immutable.
Constant, ReadOnly,
} }
impl AccessType { impl AccessMode {
/// Is the access type [`Constant`]? /// Is the access type [`ReadOnly`]?
pub fn is_constant(self) -> bool { pub fn is_read_only(self) -> bool {
match self { match self {
Self::Normal => false, Self::ReadWrite => false,
Self::Constant => true, Self::ReadOnly => true,
} }
} }
} }
@ -142,25 +142,25 @@ pub struct Dynamic(pub(crate) Union);
/// ///
/// Most variants are boxed to reduce the size. /// Most variants are boxed to reduce the size.
pub enum Union { pub enum Union {
Unit((), AccessType), Unit((), AccessMode),
Bool(bool, AccessType), Bool(bool, AccessMode),
Str(ImmutableString, AccessType), Str(ImmutableString, AccessMode),
Char(char, AccessType), Char(char, AccessMode),
Int(INT, AccessType), Int(INT, AccessMode),
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
Float(FLOAT, AccessType), Float(FLOAT, AccessMode),
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Array(Box<Array>, AccessType), Array(Box<Array>, AccessMode),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Map(Box<Map>, AccessType), Map(Box<Map>, AccessMode),
FnPtr(Box<FnPtr>, AccessType), FnPtr(Box<FnPtr>, AccessMode),
#[cfg(not(feature = "no_std"))] #[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"))] #[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`]. /// 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. /// The cloned copy is marked [`AccessType::Normal`] even if the original is constant.
fn clone(&self) -> Self { fn clone(&self) -> Self {
match self.0 { match self.0 {
Union::Unit(value, _) => Self(Union::Unit(value, AccessType::Normal)), Union::Unit(value, _) => Self(Union::Unit(value, AccessMode::ReadWrite)),
Union::Bool(value, _) => Self(Union::Bool(value, AccessType::Normal)), Union::Bool(value, _) => Self(Union::Bool(value, AccessMode::ReadWrite)),
Union::Str(ref value, _) => Self(Union::Str(value.clone(), AccessType::Normal)), Union::Str(ref value, _) => Self(Union::Str(value.clone(), AccessMode::ReadWrite)),
Union::Char(value, _) => Self(Union::Char(value, AccessType::Normal)), Union::Char(value, _) => Self(Union::Char(value, AccessMode::ReadWrite)),
Union::Int(value, _) => Self(Union::Int(value, AccessType::Normal)), Union::Int(value, _) => Self(Union::Int(value, AccessMode::ReadWrite)),
#[cfg(not(feature = "no_float"))] #[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"))] #[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"))] #[cfg(not(feature = "no_object"))]
Union::Map(ref value, _) => Self(Union::Map(value.clone(), AccessType::Normal)), Union::Map(ref value, _) => Self(Union::Map(value.clone(), AccessMode::ReadWrite)),
Union::FnPtr(ref value, _) => Self(Union::FnPtr(value.clone(), AccessType::Normal)), Union::FnPtr(ref value, _) => Self(Union::FnPtr(value.clone(), AccessMode::ReadWrite)),
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
Union::TimeStamp(ref value, _) => { 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(), Union::Variant(ref value, _) => (***value).clone_into_dynamic(),
#[cfg(not(feature = "no_closure"))] #[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 { impl Dynamic {
/// A [`Dynamic`] containing a `()`. /// 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`. /// 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`]. /// 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. /// 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. /// 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. /// 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. /// A [`Dynamic`] containing the floating-point zero.
#[cfg(not(feature = "no_float"))] #[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. /// A [`Dynamic`] containing the floating-point one.
#[cfg(not(feature = "no_float"))] #[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. /// A [`Dynamic`] containing the floating-point negative one.
#[cfg(not(feature = "no_float"))] #[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`]. /// Get the [`AccessMode`] for this [`Dynamic`].
pub(crate) fn access_type(&self) -> AccessType { pub(crate) fn access_mode(&self) -> AccessMode {
match self.0 { match self.0 {
Union::Unit(_, access) Union::Unit(_, access)
| Union::Bool(_, access) | Union::Bool(_, access)
@ -584,8 +584,8 @@ impl Dynamic {
Union::Shared(_, access) => access, Union::Shared(_, access) => access,
} }
} }
/// Set the [`AccessType`] for this [`Dynamic`]. /// Set the [`AccessMode`] for this [`Dynamic`].
pub(crate) fn set_access_type(&mut self, typ: AccessType) { pub(crate) fn set_access_mode(&mut self, typ: AccessMode) {
match &mut self.0 { match &mut self.0 {
Union::Unit(_, access) Union::Unit(_, access)
| Union::Bool(_, 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 /// if its value is going to be modified. This safe-guards constant values from being modified
/// from within Rust functions. /// from within Rust functions.
pub fn is_read_only(&self) -> bool { 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. /// 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`]`>>` /// 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. /// 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. /// Panics under the `no_closure` feature.
#[inline(always)] #[inline(always)]
pub fn into_shared(self) -> Self { pub fn into_shared(self) -> Self {
let _access = self.access_type(); let _access = self.access_mode();
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
return match self.0 { return match self.0 {
@ -1338,38 +1338,38 @@ impl Dynamic {
impl From<()> for Dynamic { impl From<()> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: ()) -> Self { fn from(value: ()) -> Self {
Self(Union::Unit(value, AccessType::Normal)) Self(Union::Unit(value, AccessMode::ReadWrite))
} }
} }
impl From<bool> for Dynamic { impl From<bool> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: bool) -> Self { fn from(value: bool) -> Self {
Self(Union::Bool(value, AccessType::Normal)) Self(Union::Bool(value, AccessMode::ReadWrite))
} }
} }
impl From<INT> for Dynamic { impl From<INT> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: INT) -> Self { fn from(value: INT) -> Self {
Self(Union::Int(value, AccessType::Normal)) Self(Union::Int(value, AccessMode::ReadWrite))
} }
} }
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
impl From<FLOAT> for Dynamic { impl From<FLOAT> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: FLOAT) -> Self { fn from(value: FLOAT) -> Self {
Self(Union::Float(value, AccessType::Normal)) Self(Union::Float(value, AccessMode::ReadWrite))
} }
} }
impl From<char> for Dynamic { impl From<char> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: char) -> Self { 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 { impl<S: Into<ImmutableString>> From<S> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: S) -> Self { fn from(value: S) -> Self {
Self(Union::Str(value.into(), AccessType::Normal)) Self(Union::Str(value.into(), AccessMode::ReadWrite))
} }
} }
#[cfg(not(feature = "no_index"))] #[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 { fn from(value: crate::stdlib::vec::Vec<T>) -> Self {
Self(Union::Array( Self(Union::Array(
Box::new(value.into_iter().map(Dynamic::from).collect()), 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 { fn from(value: &[T]) -> Self {
Self(Union::Array( Self(Union::Array(
Box::new(value.iter().cloned().map(Dynamic::from).collect()), 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))) .map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(), .collect(),
), ),
AccessType::Normal, AccessMode::ReadWrite,
)) ))
} }
} }
impl From<FnPtr> for Dynamic { impl From<FnPtr> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: FnPtr) -> Self { 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 { impl From<Box<FnPtr>> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: Box<FnPtr>) -> Self { fn from(value: Box<FnPtr>) -> Self {
Self(Union::FnPtr(value, AccessType::Normal)) Self(Union::FnPtr(value, AccessMode::ReadWrite))
} }
} }
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
impl From<Instant> for Dynamic { impl From<Instant> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: Instant) -> Self { fn from(value: Instant) -> Self {
Self(Union::TimeStamp(Box::new(value), AccessType::Normal)) Self(Union::TimeStamp(Box::new(value), AccessMode::ReadWrite))
} }
} }

View File

@ -1,7 +1,7 @@
//! Main module defining the script evaluation [`Engine`]. //! Main module defining the script evaluation [`Engine`].
use crate::ast::{Expr, FnCallExpr, Ident, IdentX, ReturnType, Stmt}; 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_call::run_builtin_op_assignment;
use crate::fn_native::{CallableFunction, Callback, IteratorFn, OnVarCallback}; use crate::fn_native::{CallableFunction, Callback, IteratorFn, OnVarCallback};
use crate::module::NamespaceRef; use crate::module::NamespaceRef;
@ -850,7 +850,7 @@ impl Engine {
// Module variables are constant // Module variables are constant
let mut target = target.clone(); let mut target = target.clone();
target.set_access_type(AccessType::Constant); target.set_access_mode(AccessMode::ReadOnly);
Ok((target.into(), name, *pos)) Ok((target.into(), name, *pos))
} }
// Normal variable access // Normal variable access
@ -905,7 +905,7 @@ impl Engine {
if let Some(mut result) = if let Some(mut result) =
resolve_var(name, index, &context).map_err(|err| err.fill_position(*pos))? 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)); return Ok((result.into(), name, *pos));
} }
} }
@ -1732,7 +1732,7 @@ impl Engine {
for item in x.as_ref() { for item in x.as_ref() {
arr.push(self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?); 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"))] #[cfg(not(feature = "no_object"))]
@ -1745,7 +1745,7 @@ impl Engine {
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?, 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 // Normal function call
@ -2289,8 +2289,8 @@ impl Engine {
// Let/const statement // Let/const statement
Stmt::Let(var_def, expr, export, _) | Stmt::Const(var_def, expr, export, _) => { Stmt::Let(var_def, expr, export, _) | Stmt::Const(var_def, expr, export, _) => {
let entry_type = match stmt { let entry_type = match stmt {
Stmt::Let(_, _, _, _) => AccessType::Normal, Stmt::Let(_, _, _, _) => AccessMode::ReadWrite,
Stmt::Const(_, _, _, _) => AccessType::Constant, Stmt::Const(_, _, _, _) => AccessMode::ReadOnly,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -2384,7 +2384,7 @@ impl Engine {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Stmt::Share(x) => { Stmt::Share(x) => {
match scope.get_index(&x.name) { match scope.get_index(&x.name) {
Some((index, AccessType::Normal)) => { Some((index, AccessMode::ReadWrite)) => {
let val = scope.get_mut(index); let val = scope.get_mut(index);
if !val.is_shared() { if !val.is_shared() {

View File

@ -1,7 +1,7 @@
//! Module implementing the [`AST`] optimizer. //! Module implementing the [`AST`] optimizer.
use crate::ast::{Expr, ScriptFnDef, Stmt}; 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::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
use crate::fn_call::run_builtin_binary_op; use crate::fn_call::run_builtin_binary_op;
use crate::parser::map_dynamic_to_expr; use crate::parser::map_dynamic_to_expr;
@ -59,7 +59,7 @@ struct State<'a> {
/// Has the [`AST`] been changed during this pass? /// Has the [`AST`] been changed during this pass?
changed: bool, changed: bool,
/// Collection of constants to use for eager function evaluations. /// 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. /// An [`Engine`] instance for eager function evaluation.
engine: &'a Engine, engine: &'a Engine,
/// [Module] containing script-defined functions. /// [Module] containing script-defined functions.
@ -102,7 +102,7 @@ impl<'a> State<'a> {
} }
/// Add a new constant to the list. /// Add a new constant to the list.
#[inline(always)] #[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)) self.variables.push((name.into(), access, value))
} }
/// Look up a constant from the list. /// Look up a constant from the list.
@ -110,7 +110,7 @@ impl<'a> State<'a> {
pub fn find_constant(&self, name: &str) -> Option<&Expr> { pub fn find_constant(&self, name: &str) -> Option<&Expr> {
for (n, access, expr) in self.variables.iter().rev() { for (n, access, expr) in self.variables.iter().rev() {
if n == name { if n == name {
return if access.is_constant() { return if access.is_read_only() {
Some(expr) Some(expr)
} else { } else {
None None
@ -163,14 +163,18 @@ fn optimize_stmt_block(
statements.iter_mut().for_each(|stmt| match stmt { statements.iter_mut().for_each(|stmt| match stmt {
// Add constant literals into the state // Add constant literals into the state
Stmt::Const(var_def, Some(expr), _, _) if expr.is_constant() => { 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, _, _) => { 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 // Add variables into the state
Stmt::Let(var_def, _, _, _) => { 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 the statement
_ => optimize_stmt(stmt, state, preserve_result), _ => optimize_stmt(stmt, state, preserve_result),
@ -749,11 +753,11 @@ fn optimize_top_level(
// Add constants and variables from the scope // Add constants and variables from the scope
scope.iter().for_each(|(name, constant, value)| { scope.iter().for_each(|(name, constant, value)| {
if !constant { 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) { } 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 { } 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); optimize_expr(value_expr, &mut state);
if value_expr.is_constant() { 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 // Keep it in the global scope
@ -784,10 +788,14 @@ fn optimize_top_level(
} }
} }
Stmt::Const(var_def, None, _, _) => { 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, _, _, _) => { 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 // Keep all variable declarations at this level

View File

@ -3,7 +3,7 @@
use crate::ast::{ use crate::ast::{
BinaryExpr, CustomExpr, Expr, FnCallExpr, Ident, IdentX, ReturnType, ScriptFnDef, Stmt, 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::engine::{KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
use crate::module::NamespaceRef; use crate::module::NamespaceRef;
use crate::optimize::optimize_into_ast; use crate::optimize::optimize_into_ast;
@ -48,7 +48,7 @@ struct ParseState<'e> {
/// Interned strings. /// Interned strings.
strings: HashMap<String, ImmutableString>, strings: HashMap<String, ImmutableString>,
/// Encapsulates a local stack with variable names to simulate an actual runtime scope. /// 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. /// Size of the local variables stack upon entry of the current block scope.
entry_stack_len: usize, entry_stack_len: usize,
/// Tracks a list of external variables (variables that are not explicitly declared in the scope). /// 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(); ) = x.as_ref();
match state.stack[(state.stack.len() - index.unwrap().get())].1 { 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)) Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
} }
// Constant values cannot be assigned to // Constant values cannot be assigned to
AccessType::Constant => { AccessMode::ReadOnly => {
Err(PERR::AssignmentToConstant(name.to_string()).into_err(*name_pos)) Err(PERR::AssignmentToConstant(name.to_string()).into_err(*name_pos))
} }
} }
@ -1317,11 +1317,11 @@ fn make_assignment_stmt<'a>(
}, },
) = x.as_ref(); ) = x.as_ref();
match state.stack[(state.stack.len() - index.unwrap().get())].1 { 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)) Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
} }
// Constant values cannot be assigned to // Constant values cannot be assigned to
AccessType::Constant => { AccessMode::ReadOnly => {
Err(PERR::AssignmentToConstant(name.to_string()).into_err(*name_pos)) 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. // Variable searches stop at the first empty variable name.
state.stack.resize( state.stack.resize(
state.stack.len() + delta as usize, 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(), 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 loop_var = state.get_interned_string(name.clone());
let prev_stack_len = state.stack.len(); 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; settings.is_breakable = true;
let body = parse_block(input, state, lib, settings.level_up())?; let body = parse_block(input, state, lib, settings.level_up())?;
@ -2124,7 +2124,7 @@ fn parse_let(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
var_type: AccessType, var_type: AccessMode,
export: bool, export: bool,
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
@ -2155,16 +2155,16 @@ fn parse_let(
match var_type { match var_type {
// let name = expr // let name = expr
AccessType::Normal => { AccessMode::ReadWrite => {
let var_name = state.get_interned_string(name.clone()); 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); let var_def = Ident::new(name, pos);
Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos)) Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos))
} }
// const name = { expr:constant } // const name = { expr:constant }
AccessType::Constant => { AccessMode::ReadOnly => {
let var_name = state.get_interned_string(name.clone()); 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); let var_def = Ident::new(name, pos);
Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos)) Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos))
} }
@ -2231,13 +2231,13 @@ fn parse_export(
match input.peek().unwrap() { match input.peek().unwrap() {
(Token::Let, pos) => { (Token::Let, pos) => {
let pos = *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); stmt.set_position(pos);
return Ok(stmt); return Ok(stmt);
} }
(Token::Const, pos) => { (Token::Const, pos) => {
let pos = *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); stmt.set_position(pos);
return Ok(stmt); return Ok(stmt);
} }
@ -2392,7 +2392,7 @@ fn parse_stmt(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Option<Stmt>, ParseError> { ) -> Result<Option<Stmt>, ParseError> {
use AccessType::{Constant, Normal}; use AccessMode::{ReadOnly, ReadWrite};
let (token, token_pos) = match input.peek().unwrap() { let (token, token_pos) = match input.peek().unwrap() {
(Token::EOF, pos) => return Ok(Some(Stmt::Noop(*pos))), (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::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 => { 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"))] #[cfg(not(feature = "no_module"))]
@ -2636,7 +2636,7 @@ fn parse_fn(
return Err(PERR::FnDuplicatedParam(name, s).into_err(pos)); return Err(PERR::FnDuplicatedParam(name, s).into_err(pos));
} }
let s = state.get_interned_string(s); 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)) params.push((s, pos))
} }
(Token::LexError(err), pos) => return Err(err.into_err(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)); return Err(PERR::FnDuplicatedParam("".to_string(), s).into_err(pos));
} }
let s = state.get_interned_string(s); 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)) params.push((s, pos))
} }
(Token::LexError(err), pos) => return Err(err.into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),

View File

@ -1,6 +1,6 @@
//! Module that defines the [`Scope`] type representing a function call-stack scope. //! 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::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};
use crate::{Dynamic, StaticVec}; use crate::{Dynamic, StaticVec};
@ -156,7 +156,7 @@ impl<'a> Scope<'a> {
name: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>,
value: impl Variant + Clone, value: impl Variant + Clone,
) -> &mut Self { ) -> &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`]. /// Add (push) a new [`Dynamic`] entry to the [`Scope`].
/// ///
@ -172,7 +172,7 @@ impl<'a> Scope<'a> {
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self { 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`]. /// Add (push) a new constant to the [`Scope`].
/// ///
@ -195,7 +195,7 @@ impl<'a> Scope<'a> {
name: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>,
value: impl Variant + Clone, value: impl Variant + Clone,
) -> &mut Self { ) -> &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. /// 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>>, name: impl Into<Cow<'a, str>>,
value: Dynamic, value: Dynamic,
) -> &mut Self { ) -> &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`]. /// Add (push) a new entry with a [`Dynamic`] value to the [`Scope`].
#[inline] #[inline]
pub(crate) fn push_dynamic_value( pub(crate) fn push_dynamic_value(
&mut self, &mut self,
name: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>,
access: AccessType, access: AccessMode,
mut value: Dynamic, mut value: Dynamic,
) -> &mut Self { ) -> &mut Self {
self.names.push((name.into(), Box::new(Default::default()))); 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.values.push(value.into());
self self
} }
@ -287,14 +287,14 @@ impl<'a> Scope<'a> {
} }
/// Find an entry in the [`Scope`], starting from the last. /// Find an entry in the [`Scope`], starting from the last.
#[inline(always)] #[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 self.names
.iter() .iter()
.enumerate() .enumerate()
.rev() // Always search a Scope in reverse order .rev() // Always search a Scope in reverse order
.find_map(|(index, (key, _))| { .find_map(|(index, (key, _))| {
if name == key.as_ref() { if name == key.as_ref() {
Some((index, self.values[index].access_type())) Some((index, self.values[index].access_mode()))
} else { } else {
None None
} }
@ -349,8 +349,8 @@ impl<'a> Scope<'a> {
None => { None => {
self.push(name, value); self.push(name, value);
} }
Some((_, AccessType::Constant)) => panic!("variable {} is constant", name), Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name),
Some((index, AccessType::Normal)) => { Some((index, AccessMode::ReadWrite)) => {
*self.values.get_mut(index).unwrap() = Dynamic::from(value); *self.values.get_mut(index).unwrap() = Dynamic::from(value);
} }
} }