diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index 05d1c60be88..af23881f956 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -19,219 +19,12 @@ mod tests; use crate::{ - builtins::BuiltIn, - gc::{Finalize, Trace}, - object::ConstructorBuilder, - property::Attribute, - value::{RcString, RcSymbol, Value}, - BoaProfiler, Context, Result, + builtins::BuiltIn, object::ConstructorBuilder, property::Attribute, symbol::RcSymbol, + value::Value, BoaProfiler, Context, Result, }; -/// A structure that contains the JavaScript well known symbols. -#[derive(Debug, Clone)] -pub struct WellKnownSymbols { - async_iterator: RcSymbol, - has_instance: RcSymbol, - is_concat_spreadable: RcSymbol, - iterator: RcSymbol, - match_: RcSymbol, - match_all: RcSymbol, - replace: RcSymbol, - search: RcSymbol, - species: RcSymbol, - split: RcSymbol, - to_primitive: RcSymbol, - to_string_tag: RcSymbol, - unscopables: RcSymbol, -} - -impl WellKnownSymbols { - pub(crate) fn new() -> (Self, u64) { - let mut count = 0; - - let async_iterator = Symbol::new(count, Some("Symbol.asyncIterator".into())).into(); - count += 1; - let has_instance = Symbol::new(count, Some("Symbol.hasInstance".into())).into(); - count += 1; - let is_concat_spreadable = - Symbol::new(count, Some("Symbol.isConcatSpreadable".into())).into(); - count += 1; - let iterator = Symbol::new(count, Some("Symbol.iterator".into())).into(); - count += 1; - let match_ = Symbol::new(count, Some("Symbol.match".into())).into(); - count += 1; - let match_all = Symbol::new(count, Some("Symbol.matchAll".into())).into(); - count += 1; - let replace = Symbol::new(count, Some("Symbol.replace".into())).into(); - count += 1; - let search = Symbol::new(count, Some("Symbol.search".into())).into(); - count += 1; - let species = Symbol::new(count, Some("Symbol.species".into())).into(); - count += 1; - let split = Symbol::new(count, Some("Symbol.split".into())).into(); - count += 1; - let to_primitive = Symbol::new(count, Some("Symbol.toPrimitive".into())).into(); - count += 1; - let to_string_tag = Symbol::new(count, Some("Symbol.toStringTag".into())).into(); - count += 1; - let unscopables = Symbol::new(count, Some("Symbol.unscopables".into())).into(); - count += 1; - - ( - Self { - async_iterator, - has_instance, - is_concat_spreadable, - iterator, - match_, - match_all, - replace, - search, - species, - split, - to_primitive, - to_string_tag, - unscopables, - }, - count, - ) - } - - /// The `Symbol.asyncIterator` well known symbol. - /// - /// A method that returns the default AsyncIterator for an object. - /// Called by the semantics of the `for-await-of` statement. - #[inline] - pub fn async_iterator_symbol(&self) -> RcSymbol { - self.async_iterator.clone() - } - - /// The `Symbol.hasInstance` well known symbol. - /// - /// A method that determines if a `constructor` object - /// recognizes an object as one of the `constructor`'s instances. - /// Called by the semantics of the instanceof operator. - #[inline] - pub fn has_instance_symbol(&self) -> RcSymbol { - self.has_instance.clone() - } - - /// The `Symbol.isConcatSpreadable` well known symbol. - /// - /// A Boolean valued property that if `true` indicates that - /// an object should be flattened to its array elements - /// by `Array.prototype.concat`. - #[inline] - pub fn is_concat_spreadable_symbol(&self) -> RcSymbol { - self.is_concat_spreadable.clone() - } - - /// The `Symbol.iterator` well known symbol. - /// - /// A method that returns the default Iterator for an object. - /// Called by the semantics of the `for-of` statement. - #[inline] - pub fn iterator_symbol(&self) -> RcSymbol { - self.iterator.clone() - } - - /// The `Symbol.match` well known symbol. - /// - /// A regular expression method that matches the regular expression - /// against a string. Called by the `String.prototype.match` method. - #[inline] - pub fn match_symbol(&self) -> RcSymbol { - self.match_.clone() - } - - /// The `Symbol.matchAll` well known symbol. - /// - /// A regular expression method that returns an iterator, that yields - /// matches of the regular expression against a string. - /// Called by the `String.prototype.matchAll` method. - #[inline] - pub fn match_all_symbol(&self) -> RcSymbol { - self.match_all.clone() - } - - /// The `Symbol.replace` well known symbol. - /// - /// A regular expression method that replaces matched substrings - /// of a string. Called by the `String.prototype.replace` method. - #[inline] - pub fn replace_symbol(&self) -> RcSymbol { - self.replace.clone() - } - - /// The `Symbol.search` well known symbol. - /// - /// A regular expression method that returns the index within a - /// string that matches the regular expression. - /// Called by the `String.prototype.search` method. - #[inline] - pub fn search_symbol(&self) -> RcSymbol { - self.search.clone() - } - - /// The `Symbol.species` well known symbol. - /// - /// A function valued property that is the `constructor` function - /// that is used to create derived objects. - #[inline] - pub fn species_symbol(&self) -> RcSymbol { - self.species.clone() - } - - /// The `Symbol.split` well known symbol. - /// - /// A regular expression method that splits a string at the indices - /// that match the regular expression. - /// Called by the `String.prototype.split` method. - #[inline] - pub fn split_symbol(&self) -> RcSymbol { - self.split.clone() - } - - /// The `Symbol.toPrimitive` well known symbol. - /// - /// A method that converts an object to a corresponding primitive value. - /// Called by the `ToPrimitive` (`Value::to_primitve`) abstract operation. - #[inline] - pub fn to_primitive_symbol(&self) -> RcSymbol { - self.to_primitive.clone() - } - - /// The `Symbol.toStringTag` well known symbol. - /// - /// A String valued property that is used in the creation of the default - /// string description of an object. - /// Accessed by the built-in method `Object.prototype.toString`. - #[inline] - pub fn to_string_tag_symbol(&self) -> RcSymbol { - self.to_string_tag.clone() - } - - /// The `Symbol.unscopables` well known symbol. - /// - /// An object valued property whose own and inherited property names are property - /// names that are excluded from the `with` environment bindings of the associated object. - #[inline] - pub fn unscopables_symbol(&self) -> RcSymbol { - self.unscopables.clone() - } -} - -#[derive(Debug, Finalize, Trace, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Symbol { - hash: u64, - description: Option, -} - -impl Symbol { - pub(crate) fn new(hash: u64, description: Option) -> Self { - Self { hash, description } - } -} +#[derive(Debug, Clone, Copy)] +pub struct Symbol; impl BuiltIn for Symbol { const NAME: &'static str = "Symbol"; @@ -294,16 +87,6 @@ impl Symbol { /// The amount of arguments this function object takes. pub(crate) const LENGTH: usize = 0; - /// Returns the `Symbol`s description. - pub fn description(&self) -> Option<&str> { - self.description.as_deref() - } - - /// Returns the `Symbol`s hash. - pub fn hash(&self) -> u64 { - self.hash - } - /// The `Symbol()` constructor returns a value of type symbol. /// /// It is incomplete as a constructor because it does not support diff --git a/boa/src/context.rs b/boa/src/context.rs index 183a16af66e..e83b76ad9bd 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -5,13 +5,13 @@ use crate::{ self, function::{Function, FunctionFlags, NativeFunction}, iterable::IteratorPrototypes, - symbol::{Symbol, WellKnownSymbols}, }, class::{Class, ClassBuilder}, exec::Interpreter, object::{GcObject, Object, PROTOTYPE}, property::{Attribute, DataDescriptor, PropertyKey}, realm::Realm, + symbol::{RcSymbol, Symbol, WellKnownSymbols}, syntax::{ ast::{ node::{ @@ -22,7 +22,7 @@ use crate::{ }, Parser, }, - value::{RcString, RcSymbol, Value}, + value::{RcString, Value}, BoaProfiler, Executable, Result, }; diff --git a/boa/src/lib.rs b/boa/src/lib.rs index 26ba04ca8c0..a3f98917cd3 100644 --- a/boa/src/lib.rs +++ b/boa/src/lib.rs @@ -54,6 +54,7 @@ pub mod profiler; pub mod property; pub mod realm; // syntax module has a lot of acronyms +pub mod symbol; #[allow(clippy::upper_case_acronyms)] pub mod syntax; pub mod value; diff --git a/boa/src/object/iter.rs b/boa/src/object/iter.rs index 9eb8cefe04f..f765b227c48 100644 --- a/boa/src/object/iter.rs +++ b/boa/src/object/iter.rs @@ -1,5 +1,5 @@ use super::{Object, PropertyDescriptor, PropertyKey}; -use crate::value::{RcString, RcSymbol}; +use crate::{symbol::RcSymbol, value::RcString}; use std::{collections::hash_map, iter::FusedIterator}; impl Object { diff --git a/boa/src/object/mod.rs b/boa/src/object/mod.rs index da2f80a4ee0..413a6d60799 100644 --- a/boa/src/object/mod.rs +++ b/boa/src/object/mod.rs @@ -12,7 +12,8 @@ use crate::{ context::StandardConstructor, gc::{Finalize, Trace}, property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, - value::{same_value, RcBigInt, RcString, RcSymbol, Value}, + symbol::RcSymbol, + value::{same_value, RcBigInt, RcString, Value}, BoaProfiler, Context, }; use rustc_hash::FxHashMap; diff --git a/boa/src/property/mod.rs b/boa/src/property/mod.rs index f74dd439928..0233d2d050c 100644 --- a/boa/src/property/mod.rs +++ b/boa/src/property/mod.rs @@ -17,7 +17,8 @@ use crate::{ gc::{Finalize, Trace}, object::GcObject, - value::{RcString, RcSymbol, Value}, + symbol::RcSymbol, + value::{RcString, Value}, }; use std::{convert::TryFrom, fmt}; diff --git a/boa/src/symbol/mod.rs b/boa/src/symbol/mod.rs new file mode 100644 index 00000000000..fadd5e95da0 --- /dev/null +++ b/boa/src/symbol/mod.rs @@ -0,0 +1,243 @@ +//! This module implements the global `Symbol` object. +//! +//! The data type symbol is a primitive data type. +//! The `Symbol()` function returns a value of type symbol, has static properties that expose +//! several members of built-in objects, has static methods that expose the global symbol registry, +//! and resembles a built-in object class, but is incomplete as a constructor because it does not +//! support the syntax "`new Symbol()`". +//! +//! Every symbol value returned from `Symbol()` is unique. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [ECMAScript reference][spec] +//! +//! [spec]: https://tc39.es/ecma262/#sec-symbol-value +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol + +mod rcsymbol; + +use crate::{ + gc::{Finalize, Trace}, + value::RcString, +}; + +pub use rcsymbol::RcSymbol; + +/// A structure that contains the JavaScript well known symbols. +#[derive(Debug, Clone)] +pub struct WellKnownSymbols { + async_iterator: RcSymbol, + has_instance: RcSymbol, + is_concat_spreadable: RcSymbol, + iterator: RcSymbol, + match_: RcSymbol, + match_all: RcSymbol, + replace: RcSymbol, + search: RcSymbol, + species: RcSymbol, + split: RcSymbol, + to_primitive: RcSymbol, + to_string_tag: RcSymbol, + unscopables: RcSymbol, +} + +impl WellKnownSymbols { + pub(crate) fn new() -> (Self, u64) { + let mut count = 0; + + let async_iterator = Symbol::new(count, Some("Symbol.asyncIterator".into())).into(); + count += 1; + let has_instance = Symbol::new(count, Some("Symbol.hasInstance".into())).into(); + count += 1; + let is_concat_spreadable = + Symbol::new(count, Some("Symbol.isConcatSpreadable".into())).into(); + count += 1; + let iterator = Symbol::new(count, Some("Symbol.iterator".into())).into(); + count += 1; + let match_ = Symbol::new(count, Some("Symbol.match".into())).into(); + count += 1; + let match_all = Symbol::new(count, Some("Symbol.matchAll".into())).into(); + count += 1; + let replace = Symbol::new(count, Some("Symbol.replace".into())).into(); + count += 1; + let search = Symbol::new(count, Some("Symbol.search".into())).into(); + count += 1; + let species = Symbol::new(count, Some("Symbol.species".into())).into(); + count += 1; + let split = Symbol::new(count, Some("Symbol.split".into())).into(); + count += 1; + let to_primitive = Symbol::new(count, Some("Symbol.toPrimitive".into())).into(); + count += 1; + let to_string_tag = Symbol::new(count, Some("Symbol.toStringTag".into())).into(); + count += 1; + let unscopables = Symbol::new(count, Some("Symbol.unscopables".into())).into(); + count += 1; + + ( + Self { + async_iterator, + has_instance, + is_concat_spreadable, + iterator, + match_, + match_all, + replace, + search, + species, + split, + to_primitive, + to_string_tag, + unscopables, + }, + count, + ) + } + + /// The `Symbol.asyncIterator` well known symbol. + /// + /// A method that returns the default AsyncIterator for an object. + /// Called by the semantics of the `for-await-of` statement. + #[inline] + pub fn async_iterator_symbol(&self) -> RcSymbol { + self.async_iterator.clone() + } + + /// The `Symbol.hasInstance` well known symbol. + /// + /// A method that determines if a `constructor` object + /// recognizes an object as one of the `constructor`'s instances. + /// Called by the semantics of the instanceof operator. + #[inline] + pub fn has_instance_symbol(&self) -> RcSymbol { + self.has_instance.clone() + } + + /// The `Symbol.isConcatSpreadable` well known symbol. + /// + /// A Boolean valued property that if `true` indicates that + /// an object should be flattened to its array elements + /// by `Array.prototype.concat`. + #[inline] + pub fn is_concat_spreadable_symbol(&self) -> RcSymbol { + self.is_concat_spreadable.clone() + } + + /// The `Symbol.iterator` well known symbol. + /// + /// A method that returns the default Iterator for an object. + /// Called by the semantics of the `for-of` statement. + #[inline] + pub fn iterator_symbol(&self) -> RcSymbol { + self.iterator.clone() + } + + /// The `Symbol.match` well known symbol. + /// + /// A regular expression method that matches the regular expression + /// against a string. Called by the `String.prototype.match` method. + #[inline] + pub fn match_symbol(&self) -> RcSymbol { + self.match_.clone() + } + + /// The `Symbol.matchAll` well known symbol. + /// + /// A regular expression method that returns an iterator, that yields + /// matches of the regular expression against a string. + /// Called by the `String.prototype.matchAll` method. + #[inline] + pub fn match_all_symbol(&self) -> RcSymbol { + self.match_all.clone() + } + + /// The `Symbol.replace` well known symbol. + /// + /// A regular expression method that replaces matched substrings + /// of a string. Called by the `String.prototype.replace` method. + #[inline] + pub fn replace_symbol(&self) -> RcSymbol { + self.replace.clone() + } + + /// The `Symbol.search` well known symbol. + /// + /// A regular expression method that returns the index within a + /// string that matches the regular expression. + /// Called by the `String.prototype.search` method. + #[inline] + pub fn search_symbol(&self) -> RcSymbol { + self.search.clone() + } + + /// The `Symbol.species` well known symbol. + /// + /// A function valued property that is the `constructor` function + /// that is used to create derived objects. + #[inline] + pub fn species_symbol(&self) -> RcSymbol { + self.species.clone() + } + + /// The `Symbol.split` well known symbol. + /// + /// A regular expression method that splits a string at the indices + /// that match the regular expression. + /// Called by the `String.prototype.split` method. + #[inline] + pub fn split_symbol(&self) -> RcSymbol { + self.split.clone() + } + + /// The `Symbol.toPrimitive` well known symbol. + /// + /// A method that converts an object to a corresponding primitive value. + /// Called by the `ToPrimitive` (`Value::to_primitve`) abstract operation. + #[inline] + pub fn to_primitive_symbol(&self) -> RcSymbol { + self.to_primitive.clone() + } + + /// The `Symbol.toStringTag` well known symbol. + /// + /// A String valued property that is used in the creation of the default + /// string description of an object. + /// Accessed by the built-in method `Object.prototype.toString`. + #[inline] + pub fn to_string_tag_symbol(&self) -> RcSymbol { + self.to_string_tag.clone() + } + + /// The `Symbol.unscopables` well known symbol. + /// + /// An object valued property whose own and inherited property names are property + /// names that are excluded from the `with` environment bindings of the associated object. + #[inline] + pub fn unscopables_symbol(&self) -> RcSymbol { + self.unscopables.clone() + } +} + +#[derive(Debug, Finalize, Trace, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Symbol { + hash: u64, + description: Option, +} + +impl Symbol { + pub(crate) fn new(hash: u64, description: Option) -> Self { + Self { hash, description } + } + + /// Returns the `Symbol`s description. + #[inline] + pub fn description(&self) -> Option<&str> { + self.description.as_deref() + } + + /// Returns the `Symbol`s hash. + #[inline] + pub fn hash(&self) -> u64 { + self.hash + } +} diff --git a/boa/src/value/rcsymbol.rs b/boa/src/symbol/rcsymbol.rs similarity index 97% rename from boa/src/value/rcsymbol.rs rename to boa/src/symbol/rcsymbol.rs index 827bcd5d037..c7b34696e67 100644 --- a/boa/src/value/rcsymbol.rs +++ b/boa/src/symbol/rcsymbol.rs @@ -1,6 +1,6 @@ use crate::{ - builtins::Symbol, gc::{empty_trace, Finalize, Trace}, + symbol::Symbol, }; use std::{ diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs index b6a62fd8587..c9b3eb6a759 100644 --- a/boa/src/value/mod.rs +++ b/boa/src/value/mod.rs @@ -13,6 +13,7 @@ use crate::{ }, object::{GcObject, Object, ObjectData}, property::{Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, + symbol::RcSymbol, BoaProfiler, Context, Result, }; use gc::{Finalize, Trace}; @@ -31,7 +32,6 @@ mod hash; mod operations; mod rcbigint; mod rcstring; -mod rcsymbol; mod r#type; pub use conversions::*; @@ -42,7 +42,6 @@ pub use operations::*; pub use r#type::Type; pub use rcbigint::RcBigInt; pub use rcstring::RcString; -pub use rcsymbol::RcSymbol; /// A Javascript value #[derive(Trace, Finalize, Debug, Clone)]