mirror of https://github.com/boa-dev/boa.git
HalidOdat
4 years ago
committed by
GitHub
13 changed files with 570 additions and 195 deletions
@ -0,0 +1,145 @@ |
|||||||
|
//! This module implements the `Attribute` struct which contains the attibutes for property descriptors.
|
||||||
|
|
||||||
|
use bitflags::bitflags; |
||||||
|
use gc::{unsafe_empty_trace, Finalize, Trace}; |
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests; |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// This struct constains the property flags as describen in the ECMAScript specification.
|
||||||
|
///
|
||||||
|
/// It contains the following flags:
|
||||||
|
/// - `[[Writable]]` (`WRITABLE`) - If `false`, attempts by ECMAScript code to change the property's `[[Value]]` attribute using `[[Set]]` will not succeed.
|
||||||
|
/// - `[[Enumerable]]` (`ENUMERABLE`) - If the property will be enumerated by a for-in enumeration.
|
||||||
|
/// - `[[Configurable]]` (`CONFIGURABLE`) - If `false`, attempts to delete the property, change the property to be an `accessor property`, or change its attributes (other than `[[Value]]`, or changing `[[Writable]]` to `false`) will fail.
|
||||||
|
///
|
||||||
|
/// Additionaly there are flags for when the flags are defined.
|
||||||
|
#[derive(Finalize)] |
||||||
|
pub struct Attribute: u8 { |
||||||
|
/// None of the flags are present.
|
||||||
|
const NONE = 0b0000_0000; |
||||||
|
|
||||||
|
/// The `Writable` attribute decides whether the value associated with the property can be changed or not, from its initial value.
|
||||||
|
const WRITABLE = 0b0000_0011; |
||||||
|
|
||||||
|
/// The property is not writable.
|
||||||
|
const READONLY = 0b0000_0010; |
||||||
|
|
||||||
|
/// Is the `Writable` flag defined.
|
||||||
|
const HAS_WRITABLE = 0b0000_0010; |
||||||
|
|
||||||
|
/// If the property can be enumerated by a `for-in` loop.
|
||||||
|
const ENUMERABLE = 0b0000_1100; |
||||||
|
|
||||||
|
/// The property can not be enumerated in a `for-in` loop.
|
||||||
|
const NON_ENUMERABLE = 0b0000_1000; |
||||||
|
|
||||||
|
/// Is the `Enumerable` flag defined.
|
||||||
|
const HAS_ENUMERABLE = 0b0000_1000; |
||||||
|
|
||||||
|
/// If the property descriptor can be changed later.
|
||||||
|
const CONFIGURABLE = 0b0011_0000; |
||||||
|
|
||||||
|
/// The property descriptor cannot be changed.
|
||||||
|
const PERMANENT = 0b0010_0000; |
||||||
|
|
||||||
|
/// Is the `Configurable` flag defined.
|
||||||
|
const HAS_CONFIGURABLE = 0b0010_0000; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// We implement `Trace` manualy rather that wih derive, beacuse `rust-gc`,
|
||||||
|
// derive `Trace` does not allow `Copy` and `Trace` to be both implemented.
|
||||||
|
//
|
||||||
|
// SAFETY: The `Attribute` struct only contains an `u8`
|
||||||
|
// and therefore it should be safe to implement an empty trace.
|
||||||
|
unsafe impl Trace for Attribute { |
||||||
|
unsafe_empty_trace!(); |
||||||
|
} |
||||||
|
|
||||||
|
impl Attribute { |
||||||
|
/// Clear all flags.
|
||||||
|
#[inline] |
||||||
|
pub fn clear(&mut self) { |
||||||
|
self.bits = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/// Is the `writable` flag defined.
|
||||||
|
#[inline] |
||||||
|
pub fn has_writable(self) -> bool { |
||||||
|
self.contains(Self::HAS_WRITABLE) |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the `writable` flag.
|
||||||
|
#[inline] |
||||||
|
pub fn set_writable(&mut self, value: bool) { |
||||||
|
if value { |
||||||
|
*self |= Self::WRITABLE; |
||||||
|
} else { |
||||||
|
*self |= *self & !Self::WRITABLE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets the `writable` flag.
|
||||||
|
#[inline] |
||||||
|
pub fn writable(self) -> bool { |
||||||
|
debug_assert!(self.has_writable()); |
||||||
|
self.contains(Self::WRITABLE) |
||||||
|
} |
||||||
|
|
||||||
|
/// Is the `enumerable` flag defined.
|
||||||
|
#[inline] |
||||||
|
pub fn has_enumerable(self) -> bool { |
||||||
|
self.contains(Self::HAS_ENUMERABLE) |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the `enumerable` flag.
|
||||||
|
#[inline] |
||||||
|
pub fn set_enumerable(&mut self, value: bool) { |
||||||
|
if value { |
||||||
|
*self |= Self::ENUMERABLE; |
||||||
|
} else { |
||||||
|
*self |= *self & !Self::ENUMERABLE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets the `enumerable` flag.
|
||||||
|
#[inline] |
||||||
|
pub fn enumerable(self) -> bool { |
||||||
|
debug_assert!(self.has_enumerable()); |
||||||
|
self.contains(Self::ENUMERABLE) |
||||||
|
} |
||||||
|
|
||||||
|
/// Is the `configurable` flag defined.
|
||||||
|
#[inline] |
||||||
|
pub fn has_configurable(self) -> bool { |
||||||
|
self.contains(Self::HAS_CONFIGURABLE) |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the `configurable` flag.
|
||||||
|
#[inline] |
||||||
|
pub fn set_configurable(&mut self, value: bool) { |
||||||
|
if value { |
||||||
|
*self |= Self::CONFIGURABLE; |
||||||
|
} else { |
||||||
|
*self |= *self & !Self::CONFIGURABLE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets the `configurable` flag.
|
||||||
|
#[inline] |
||||||
|
pub fn configurable(self) -> bool { |
||||||
|
debug_assert!(self.has_configurable()); |
||||||
|
self.contains(Self::CONFIGURABLE) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for Attribute { |
||||||
|
/// Returns the default flags according to the [ECMAScript specification][spec].
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#table-default-attribute-values
|
||||||
|
fn default() -> Self { |
||||||
|
Self::READONLY | Self::NON_ENUMERABLE | Self::PERMANENT |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,167 @@ |
|||||||
|
use super::Attribute; |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn writable() { |
||||||
|
let attribute = Attribute::WRITABLE; |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(attribute.writable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn enumerable() { |
||||||
|
let attribute = Attribute::ENUMERABLE; |
||||||
|
|
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(attribute.enumerable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn configurable() { |
||||||
|
let attribute = Attribute::CONFIGURABLE; |
||||||
|
|
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn writable_and_enumerable() { |
||||||
|
let attribute = Attribute::WRITABLE | Attribute::ENUMERABLE; |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(attribute.enumerable()); |
||||||
|
|
||||||
|
assert!(!attribute.has_configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn enumerable_configurable() { |
||||||
|
let attribute = Attribute::ENUMERABLE | Attribute::CONFIGURABLE; |
||||||
|
|
||||||
|
assert!(!attribute.has_writable()); |
||||||
|
|
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn writable_enumerable_configurable() { |
||||||
|
let attribute = Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE; |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn default() { |
||||||
|
let attribute = Attribute::default(); |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn clear() { |
||||||
|
let mut attribute = Attribute::default(); |
||||||
|
|
||||||
|
attribute.clear(); |
||||||
|
|
||||||
|
assert!(!attribute.has_writable()); |
||||||
|
assert!(!attribute.has_enumerable()); |
||||||
|
assert!(!attribute.has_configurable()); |
||||||
|
|
||||||
|
assert!(attribute.is_empty()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set_writable_to_true() { |
||||||
|
let mut attribute = Attribute::default(); |
||||||
|
|
||||||
|
attribute.set_writable(true); |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(!attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(!attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set_writable_to_false() { |
||||||
|
let mut attribute = Attribute::default(); |
||||||
|
|
||||||
|
attribute.set_writable(false); |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(!attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(!attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(!attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set_enumerable_to_true() { |
||||||
|
let mut attribute = Attribute::default(); |
||||||
|
|
||||||
|
attribute.set_enumerable(true); |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(!attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(!attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set_enumerable_to_false() { |
||||||
|
let mut attribute = Attribute::default(); |
||||||
|
|
||||||
|
attribute.set_enumerable(false); |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(!attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(!attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(!attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set_configurable_to_true() { |
||||||
|
let mut attribute = Attribute::default(); |
||||||
|
|
||||||
|
attribute.set_configurable(true); |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(!attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(!attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(attribute.configurable()); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set_configurable_to_false() { |
||||||
|
let mut attribute = Attribute::default(); |
||||||
|
|
||||||
|
attribute.set_configurable(false); |
||||||
|
|
||||||
|
assert!(attribute.has_writable()); |
||||||
|
assert!(!attribute.writable()); |
||||||
|
assert!(attribute.has_enumerable()); |
||||||
|
assert!(!attribute.enumerable()); |
||||||
|
assert!(attribute.has_configurable()); |
||||||
|
assert!(!attribute.configurable()); |
||||||
|
} |
Loading…
Reference in new issue