Skip to content

Commit

Permalink
Merge 3c6e4bd into e775743
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Sep 20, 2020
2 parents e775743 + 3c6e4bd commit ebeb17c
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 21 deletions.
232 changes: 213 additions & 19 deletions boa/src/builtins/symbol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,200 @@ use crate::{
};
use gc::{Finalize, Trace};

/// 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, u32) {
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.async_iterator.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: u32,
Expand Down Expand Up @@ -109,32 +303,32 @@ impl Symbol {

/// Initialise the `Symbol` object on the global object.
#[inline]
pub fn init(interpreter: &mut Context) -> (&'static str, Value) {
pub fn init(context: &mut Context) -> (&'static str, Value) {
// Define the Well-Known Symbols
// https://tc39.es/ecma262/#sec-well-known-symbols
let symbol_async_iterator =
interpreter.construct_symbol(Some("Symbol.asyncIterator".into()));
let symbol_has_instance = interpreter.construct_symbol(Some("Symbol.hasInstance".into()));
let symbol_is_concat_spreadable =
interpreter.construct_symbol(Some("Symbol.isConcatSpreadable".into()));
let symbol_iterator = interpreter.construct_symbol(Some("Symbol.iterator".into()));
let symbol_match = interpreter.construct_symbol(Some("Symbol.match".into()));
let symbol_match_all = interpreter.construct_symbol(Some("Symbol.matchAll".into()));
let symbol_replace = interpreter.construct_symbol(Some("Symbol.replace".into()));
let symbol_search = interpreter.construct_symbol(Some("Symbol.search".into()));
let symbol_species = interpreter.construct_symbol(Some("Symbol.species".into()));
let symbol_split = interpreter.construct_symbol(Some("Symbol.split".into()));
let symbol_to_primitive = interpreter.construct_symbol(Some("Symbol.toPrimitive".into()));
let symbol_to_string_tag = interpreter.construct_symbol(Some("Symbol.toStringTag".into()));
let symbol_unscopables = interpreter.construct_symbol(Some("Symbol.unscopables".into()));

let global = interpreter.global_object();
let well_known_symbols = context.well_known_symbols();

let symbol_async_iterator = well_known_symbols.async_iterator_symbol();
let symbol_has_instance = well_known_symbols.has_instance_symbol();
let symbol_is_concat_spreadable = well_known_symbols.is_concat_spreadable_symbol();
let symbol_iterator = well_known_symbols.iterator_symbol();
let symbol_match = well_known_symbols.match_symbol();
let symbol_match_all = well_known_symbols.match_all_symbol();
let symbol_replace = well_known_symbols.replace_symbol();
let symbol_search = well_known_symbols.search_symbol();
let symbol_species = well_known_symbols.species_symbol();
let symbol_split = well_known_symbols.split_symbol();
let symbol_to_primitive = well_known_symbols.to_primitive_symbol();
let symbol_to_string_tag = well_known_symbols.to_string_tag_symbol();
let symbol_unscopables = well_known_symbols.unscopables_symbol();

let global = context.global_object();
let _timer = BoaProfiler::global().start_event(Self::NAME, "init");

// Create prototype object
let prototype = Value::new_object(Some(global));

make_builtin_fn(Self::to_string, "toString", &prototype, 0, interpreter);
make_builtin_fn(Self::to_string, "toString", &prototype, 0, context);

let symbol_object = make_constructor_fn(
Self::NAME,
Expand Down
26 changes: 24 additions & 2 deletions boa/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::{
builtins::{
self,
function::{Function, FunctionFlags, NativeFunction},
Console, Symbol,
symbol::{Symbol, WellKnownSymbols},
Console,
},
class::{Class, ClassBuilder},
exec::Interpreter,
Expand Down Expand Up @@ -46,17 +47,22 @@ pub struct Context {

/// console object state.
console: Console,

/// Cached well known symbols
well_known_symbols: WellKnownSymbols,
}

impl Default for Context {
fn default() -> Self {
let realm = Realm::create();
let executor = Interpreter::new();
let (well_known_symbols, symbol_count) = WellKnownSymbols::new();
let mut context = Self {
realm,
executor,
symbol_count: 0,
symbol_count,
console: Console::default(),
well_known_symbols,
};

// Add new builtIns to Context Realm
Expand Down Expand Up @@ -495,4 +501,20 @@ impl Context {

result
}

/// Returns a structure that contains the JavaScript well known symbols.
///
/// # Examples
/// ```
///# use boa::Context;
/// let mut context = Context::new();
///
/// let iterator = context.well_known_symbols().iterator_symbol();
/// assert_eq!(iterator.description(), Some("Symbol.iterator"));
/// ```
/// This is equivalent to `let iterator = Symbol.iterator` in JavaScript.
#[inline]
pub fn well_known_symbols(&self) -> &WellKnownSymbols {
&self.well_known_symbols
}
}

0 comments on commit ebeb17c

Please sign in to comment.