Browse Source

Refactor JavaScript symbol rust type (#1382)

pull/1380/head
Halid Odat 3 years ago committed by GitHub
parent
commit
ecd56ca7e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      boa/src/builtins/symbol/mod.rs
  2. 10
      boa/src/context.rs
  3. 2
      boa/src/lib.rs
  4. 14
      boa/src/object/iter.rs
  5. 9
      boa/src/object/mod.rs
  6. 8
      boa/src/property/mod.rs
  7. 169
      boa/src/symbol.rs
  8. 42
      boa/src/symbol/rcsymbol.rs
  9. 4
      boa/src/value/conversions.rs
  10. 8
      boa/src/value/mod.rs

12
boa/src/builtins/symbol/mod.rs

@ -22,7 +22,7 @@ use crate::{
builtins::BuiltIn,
object::{ConstructorBuilder, FunctionBuilder},
property::Attribute,
symbol::{RcSymbol, WellKnownSymbols},
symbol::{JsSymbol, WellKnownSymbols},
value::Value,
BoaProfiler, Context, Result,
};
@ -130,10 +130,10 @@ impl Symbol {
_ => None,
};
Ok(context.construct_symbol(description).into())
Ok(JsSymbol::new(description).into())
}
fn this_symbol_value(value: &Value, context: &mut Context) -> Result<RcSymbol> {
fn this_symbol_value(value: &Value, context: &mut Context) -> Result<JsSymbol> {
match value {
Value::Symbol(ref symbol) => return Ok(symbol.clone()),
Value::Object(ref object) => {
@ -161,8 +161,7 @@ impl Symbol {
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
let symbol = Self::this_symbol_value(this, context)?;
let description = symbol.description().unwrap_or("");
Ok(Value::from(format!("Symbol({})", description)))
Ok(symbol.to_string().into())
}
/// `get Symbol.prototype.description`
@ -180,7 +179,8 @@ impl Symbol {
_: &[Value],
context: &mut Context,
) -> Result<Value> {
if let Some(ref description) = Self::this_symbol_value(this, context)?.description {
let symbol = Self::this_symbol_value(this, context)?;
if let Some(ref description) = symbol.description() {
Ok(description.clone().into())
} else {
Ok(Value::undefined())

10
boa/src/context.rs

@ -11,7 +11,6 @@ use crate::{
object::{FunctionBuilder, GcObject, Object, PROTOTYPE},
property::{Attribute, DataDescriptor, PropertyKey},
realm::Realm,
symbol::{RcSymbol, Symbol},
syntax::{
ast::{
node::{
@ -22,8 +21,7 @@ use crate::{
},
Parser,
},
value::{RcString, Value},
BoaProfiler, Executable, Result,
BoaProfiler, Executable, Result, Value,
};
#[cfg(feature = "console")]
@ -297,12 +295,6 @@ impl Context {
builtins::init(self);
}
/// Construct a new `Symbol` with an optional description.
#[inline]
pub fn construct_symbol(&mut self, description: Option<RcString>) -> RcSymbol {
RcSymbol::from(Symbol::new(description))
}
/// Construct an empty object.
#[inline]
pub fn construct_object(&self) -> GcObject {

2
boa/src/lib.rs

@ -71,7 +71,7 @@ pub(crate) use crate::{exec::Executable, profiler::BoaProfiler};
// Export things to root level
#[doc(inline)]
pub use crate::{context::Context, value::Value};
pub use crate::{context::Context, symbol::JsSymbol, value::Value};
use crate::syntax::{
ast::node::StatementList,

14
boa/src/object/iter.rs

@ -1,5 +1,5 @@
use super::{Object, PropertyDescriptor, PropertyKey};
use crate::{symbol::RcSymbol, value::RcString};
use crate::{value::RcString, JsSymbol};
use std::{collections::hash_map, iter::FusedIterator};
impl Object {
@ -110,7 +110,7 @@ impl Object {
pub struct Iter<'a> {
indexed_properties: hash_map::Iter<'a, u32, PropertyDescriptor>,
string_properties: hash_map::Iter<'a, RcString, PropertyDescriptor>,
symbol_properties: hash_map::Iter<'a, RcSymbol, PropertyDescriptor>,
symbol_properties: hash_map::Iter<'a, JsSymbol, PropertyDescriptor>,
}
impl<'a> Iterator for Iter<'a> {
@ -180,10 +180,10 @@ impl FusedIterator for Values<'_> {}
/// An iterator over the `Symbol` property entries of an `Object`
#[derive(Debug, Clone)]
pub struct SymbolProperties<'a>(hash_map::Iter<'a, RcSymbol, PropertyDescriptor>);
pub struct SymbolProperties<'a>(hash_map::Iter<'a, JsSymbol, PropertyDescriptor>);
impl<'a> Iterator for SymbolProperties<'a> {
type Item = (&'a RcSymbol, &'a PropertyDescriptor);
type Item = (&'a JsSymbol, &'a PropertyDescriptor);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
@ -207,10 +207,10 @@ impl FusedIterator for SymbolProperties<'_> {}
/// An iterator over the keys (`RcSymbol`) of an `Object`.
#[derive(Debug, Clone)]
pub struct SymbolPropertyKeys<'a>(hash_map::Keys<'a, RcSymbol, PropertyDescriptor>);
pub struct SymbolPropertyKeys<'a>(hash_map::Keys<'a, JsSymbol, PropertyDescriptor>);
impl<'a> Iterator for SymbolPropertyKeys<'a> {
type Item = &'a RcSymbol;
type Item = &'a JsSymbol;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
@ -234,7 +234,7 @@ impl FusedIterator for SymbolPropertyKeys<'_> {}
/// An iterator over the `Symbol` values (`Property`) of an `Object`.
#[derive(Debug, Clone)]
pub struct SymbolPropertyValues<'a>(hash_map::Values<'a, RcSymbol, PropertyDescriptor>);
pub struct SymbolPropertyValues<'a>(hash_map::Values<'a, JsSymbol, PropertyDescriptor>);
impl<'a> Iterator for SymbolPropertyValues<'a> {
type Item = &'a PropertyDescriptor;

9
boa/src/object/mod.rs

@ -15,9 +15,8 @@ use crate::{
context::StandardConstructor,
gc::{Finalize, Trace},
property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey},
symbol::RcSymbol,
value::{RcBigInt, RcString, Value},
BoaProfiler, Context,
BoaProfiler, Context, JsSymbol,
};
use rustc_hash::FxHashMap;
use std::{
@ -72,7 +71,7 @@ pub struct Object {
/// Properties
string_properties: FxHashMap<RcString, PropertyDescriptor>,
/// Symbol Properties
symbol_properties: FxHashMap<RcSymbol, PropertyDescriptor>,
symbol_properties: FxHashMap<JsSymbol, PropertyDescriptor>,
/// Instance prototype `__proto__`.
prototype: Value,
/// Whether it can have new properties added to it.
@ -97,7 +96,7 @@ pub enum ObjectData {
String(RcString),
StringIterator(StringIterator),
Number(f64),
Symbol(RcSymbol),
Symbol(JsSymbol),
Error,
Ordinary,
Date(Date),
@ -442,7 +441,7 @@ impl Object {
}
#[inline]
pub fn as_symbol(&self) -> Option<RcSymbol> {
pub fn as_symbol(&self) -> Option<JsSymbol> {
match self.data {
ObjectData::Symbol(ref symbol) => Some(symbol.clone()),
_ => None,

8
boa/src/property/mod.rs

@ -17,8 +17,8 @@
use crate::{
gc::{Finalize, Trace},
object::GcObject,
symbol::RcSymbol,
value::{RcString, Value},
JsSymbol,
};
use std::{convert::TryFrom, fmt};
@ -307,7 +307,7 @@ impl PropertyDescriptor {
#[derive(Trace, Finalize, Debug, Clone)]
pub enum PropertyKey {
String(RcString),
Symbol(RcSymbol),
Symbol(JsSymbol),
Index(u32),
}
@ -355,9 +355,9 @@ impl From<Box<str>> for PropertyKey {
}
}
impl From<RcSymbol> for PropertyKey {
impl From<JsSymbol> for PropertyKey {
#[inline]
fn from(symbol: RcSymbol) -> PropertyKey {
fn from(symbol: JsSymbol) -> PropertyKey {
PropertyKey::Symbol(symbol)
}
}

169
boa/src/symbol/mod.rs → boa/src/symbol.rs

@ -15,19 +15,17 @@
//! [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},
gc::{empty_trace, Finalize, Trace},
value::RcString,
};
use std::{
cell::Cell,
fmt::{self, Display},
hash::{Hash, Hasher},
rc::Rc,
};
pub use rcsymbol::RcSymbol;
/// A structure that contains the JavaScript well known symbols.
///
/// # Examples
@ -35,24 +33,24 @@ pub use rcsymbol::RcSymbol;
///# use boa::symbol::WellKnownSymbols;
///
/// let iterator = WellKnownSymbols::iterator();
/// assert_eq!(iterator.description(), Some("Symbol.iterator"));
/// assert_eq!(iterator.description().as_deref(), Some("Symbol.iterator"));
/// ```
/// This is equivalent to `let iterator = Symbol.iterator` in JavaScript.
#[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,
async_iterator: JsSymbol,
has_instance: JsSymbol,
is_concat_spreadable: JsSymbol,
iterator: JsSymbol,
match_: JsSymbol,
match_all: JsSymbol,
replace: JsSymbol,
search: JsSymbol,
species: JsSymbol,
split: JsSymbol,
to_primitive: JsSymbol,
to_string_tag: JsSymbol,
unscopables: JsSymbol,
}
/// Reserved number of symbols.
@ -76,32 +74,32 @@ impl WellKnownSymbols {
fn new() -> Self {
let mut count = 0;
let async_iterator = Symbol::with_hash(count, Some("Symbol.asyncIterator".into())).into();
let async_iterator = JsSymbol::with_hash(count, Some("Symbol.asyncIterator".into()));
count += 1;
let has_instance = Symbol::with_hash(count, Some("Symbol.hasInstance".into())).into();
let has_instance = JsSymbol::with_hash(count, Some("Symbol.hasInstance".into()));
count += 1;
let is_concat_spreadable =
Symbol::with_hash(count, Some("Symbol.isConcatSpreadable".into())).into();
JsSymbol::with_hash(count, Some("Symbol.isConcatSpreadable".into()));
count += 1;
let iterator = Symbol::with_hash(count, Some("Symbol.iterator".into())).into();
let iterator = JsSymbol::with_hash(count, Some("Symbol.iterator".into()));
count += 1;
let match_ = Symbol::with_hash(count, Some("Symbol.match".into())).into();
let match_ = JsSymbol::with_hash(count, Some("Symbol.match".into()));
count += 1;
let match_all = Symbol::with_hash(count, Some("Symbol.matchAll".into())).into();
let match_all = JsSymbol::with_hash(count, Some("Symbol.matchAll".into()));
count += 1;
let replace = Symbol::with_hash(count, Some("Symbol.replace".into())).into();
let replace = JsSymbol::with_hash(count, Some("Symbol.replace".into()));
count += 1;
let search = Symbol::with_hash(count, Some("Symbol.search".into())).into();
let search = JsSymbol::with_hash(count, Some("Symbol.search".into()));
count += 1;
let species = Symbol::with_hash(count, Some("Symbol.species".into())).into();
let species = JsSymbol::with_hash(count, Some("Symbol.species".into()));
count += 1;
let split = Symbol::with_hash(count, Some("Symbol.split".into())).into();
let split = JsSymbol::with_hash(count, Some("Symbol.split".into()));
count += 1;
let to_primitive = Symbol::with_hash(count, Some("Symbol.toPrimitive".into())).into();
let to_primitive = JsSymbol::with_hash(count, Some("Symbol.toPrimitive".into()));
count += 1;
let to_string_tag = Symbol::with_hash(count, Some("Symbol.toStringTag".into())).into();
let to_string_tag = JsSymbol::with_hash(count, Some("Symbol.toStringTag".into()));
count += 1;
let unscopables = Symbol::with_hash(count, Some("Symbol.unscopables".into())).into();
let unscopables = JsSymbol::with_hash(count, Some("Symbol.unscopables".into()));
Self {
async_iterator,
@ -125,7 +123,7 @@ impl WellKnownSymbols {
/// 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() -> RcSymbol {
pub fn async_iterator() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.async_iterator.clone())
}
@ -135,7 +133,7 @@ impl WellKnownSymbols {
/// recognizes an object as one of the `constructor`'s instances.
/// Called by the semantics of the instanceof operator.
#[inline]
pub fn has_instance() -> RcSymbol {
pub fn has_instance() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.has_instance.clone())
}
@ -145,7 +143,7 @@ impl WellKnownSymbols {
/// an object should be flattened to its array elements
/// by `Array.prototype.concat`.
#[inline]
pub fn is_concat_spreadable() -> RcSymbol {
pub fn is_concat_spreadable() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.is_concat_spreadable.clone())
}
@ -154,7 +152,7 @@ impl WellKnownSymbols {
/// A method that returns the default Iterator for an object.
/// Called by the semantics of the `for-of` statement.
#[inline]
pub fn iterator() -> RcSymbol {
pub fn iterator() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.iterator.clone())
}
@ -163,7 +161,7 @@ impl WellKnownSymbols {
/// A regular expression method that matches the regular expression
/// against a string. Called by the `String.prototype.match` method.
#[inline]
pub fn match_() -> RcSymbol {
pub fn match_() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.match_.clone())
}
@ -173,7 +171,7 @@ impl WellKnownSymbols {
/// matches of the regular expression against a string.
/// Called by the `String.prototype.matchAll` method.
#[inline]
pub fn match_all() -> RcSymbol {
pub fn match_all() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.match_all.clone())
}
@ -182,7 +180,7 @@ impl WellKnownSymbols {
/// A regular expression method that replaces matched substrings
/// of a string. Called by the `String.prototype.replace` method.
#[inline]
pub fn replace() -> RcSymbol {
pub fn replace() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.replace.clone())
}
@ -192,7 +190,7 @@ impl WellKnownSymbols {
/// string that matches the regular expression.
/// Called by the `String.prototype.search` method.
#[inline]
pub fn search() -> RcSymbol {
pub fn search() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.search.clone())
}
@ -201,7 +199,7 @@ impl WellKnownSymbols {
/// A function valued property that is the `constructor` function
/// that is used to create derived objects.
#[inline]
pub fn species() -> RcSymbol {
pub fn species() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.species.clone())
}
@ -211,7 +209,7 @@ impl WellKnownSymbols {
/// that match the regular expression.
/// Called by the `String.prototype.split` method.
#[inline]
pub fn split() -> RcSymbol {
pub fn split() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.split.clone())
}
@ -220,7 +218,7 @@ impl WellKnownSymbols {
/// 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() -> RcSymbol {
pub fn to_primitive() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.to_primitive.clone())
}
@ -230,7 +228,7 @@ impl WellKnownSymbols {
/// string description of an object.
/// Accessed by the built-in method `Object.prototype.toString`.
#[inline]
pub fn to_string_tag() -> RcSymbol {
pub fn to_string_tag() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.to_string_tag.clone())
}
@ -239,23 +237,25 @@ impl WellKnownSymbols {
/// 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() -> RcSymbol {
pub fn unscopables() -> JsSymbol {
WELL_KNOW_SYMBOLS.with(|symbols| symbols.unscopables.clone())
}
}
#[derive(Debug, Finalize, Trace, Clone, Eq, PartialOrd, Ord)]
pub struct Symbol {
pub(crate) hash: u64,
pub(crate) description: Option<RcString>,
/// The inner representation of a JavaScript symbol.
#[derive(Debug, Clone)]
struct Inner {
hash: u64,
description: Option<RcString>,
}
impl Symbol {
/// Create a new symbol with a specified hash and description.
fn with_hash(hash: u64, description: Option<RcString>) -> Self {
Self { hash, description }
}
/// This represents a JavaScript symbol primitive.
#[derive(Debug, Clone)]
pub struct JsSymbol {
inner: Rc<Inner>,
}
impl JsSymbol {
/// Create a new symbol.
#[inline]
pub fn new(description: Option<RcString>) -> Self {
@ -264,13 +264,24 @@ impl Symbol {
count.set(hash + 1);
hash
});
Self { hash, description }
Self {
inner: Rc::new(Inner { hash, description }),
}
}
/// Create a new symbol with a specified hash and description.
#[inline]
fn with_hash(hash: u64, description: Option<RcString>) -> Self {
Self {
inner: Rc::new(Inner { hash, description }),
}
}
/// Returns the `Symbol`s description.
#[inline]
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
pub fn description(&self) -> Option<RcString> {
self.inner.description.clone()
}
/// Returns the `Symbol`s hash.
@ -278,20 +289,54 @@ impl Symbol {
/// The hash is guaranteed to be unique.
#[inline]
pub fn hash(&self) -> u64 {
self.hash
self.inner.hash
}
}
impl PartialEq for Symbol {
impl Finalize for JsSymbol {}
// Safety: `JsSymbol` does not contain any object that require trace,
// so this is safe.
unsafe impl Trace for JsSymbol {
empty_trace!();
}
impl Display for JsSymbol {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner.description {
Some(desc) => write!(f, "Symbol({})", desc),
None => write!(f, "Symbol()"),
}
}
}
impl Eq for JsSymbol {}
impl PartialEq for JsSymbol {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
self.inner.hash == other.inner.hash
}
}
impl PartialOrd for JsSymbol {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.inner.hash.partial_cmp(&other.inner.hash)
}
}
impl Ord for JsSymbol {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.inner.hash.cmp(&other.inner.hash)
}
}
impl Hash for Symbol {
impl Hash for JsSymbol {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.hash.hash(state);
self.inner.hash.hash(state);
}
}

42
boa/src/symbol/rcsymbol.rs

@ -1,42 +0,0 @@
use crate::{
gc::{empty_trace, Finalize, Trace},
symbol::Symbol,
};
use std::{
fmt::{self, Display},
ops::Deref,
rc::Rc,
};
#[derive(Debug, Finalize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RcSymbol(Rc<Symbol>);
unsafe impl Trace for RcSymbol {
empty_trace!();
}
impl Display for RcSymbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0.description() {
Some(desc) => write!(f, "Symbol({})", desc),
None => write!(f, "Symbol()"),
}
}
}
impl Deref for RcSymbol {
type Target = Symbol;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Symbol> for RcSymbol {
#[inline]
fn from(symbol: Symbol) -> Self {
Self(Rc::from(symbol))
}
}

4
boa/src/value/conversions.rs

@ -51,9 +51,9 @@ impl From<RcString> for Value {
}
}
impl From<RcSymbol> for Value {
impl From<JsSymbol> for Value {
#[inline]
fn from(value: RcSymbol) -> Self {
fn from(value: JsSymbol) -> Self {
Value::Symbol(value)
}
}

8
boa/src/value/mod.rs

@ -13,7 +13,7 @@ use crate::{
},
object::{GcObject, Object, ObjectData},
property::{Attribute, DataDescriptor, PropertyDescriptor, PropertyKey},
symbol::{RcSymbol, WellKnownSymbols},
symbol::{JsSymbol, WellKnownSymbols},
BoaProfiler, Context, Result,
};
use gc::{Finalize, Trace};
@ -63,7 +63,7 @@ pub enum Value {
/// `Object` - An object, such as `Math`, represented by a binary tree of string keys to Javascript values.
Object(GcObject),
/// `Symbol` - A Symbol Primitive type.
Symbol(RcSymbol),
Symbol(JsSymbol),
}
/// Represents the result of ToIntegerOrInfinity operation
@ -164,7 +164,7 @@ impl Value {
/// Creates a new symbol value.
#[inline]
pub fn symbol(symbol: RcSymbol) -> Self {
pub fn symbol(symbol: JsSymbol) -> Self {
Self::Symbol(symbol)
}
@ -293,7 +293,7 @@ impl Value {
matches!(self, Self::Symbol(_))
}
pub fn as_symbol(&self) -> Option<RcSymbol> {
pub fn as_symbol(&self) -> Option<JsSymbol> {
match self {
Self::Symbol(symbol) => Some(symbol.clone()),
_ => None,

Loading…
Cancel
Save