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 passed as the `this` parameter to Rhai functions now throws an error if assigned to.
Version 0.19.7

View File

@ -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,

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)]
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))
}
}

View File

@ -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() {

View File

@ -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

View File

@ -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)),

View File

@ -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);
}
}