use crate::host::HostFunction;
use crate::object::function::JSFunction;
use crate::object::object::JSObject;
use crate::runtime::atom::Atom;
use crate::runtime::context::JSContext;
use crate::value::JSValue;
fn throw_type_error(ctx: &mut JSContext, msg: &str) {
let mut err = JSObject::new();
if let Some(proto_ptr) = ctx.get_type_error_prototype() {
err.prototype = Some(proto_ptr);
}
err.set(
ctx.common_atoms.name,
JSValue::new_string(ctx.intern("TypeError")),
);
err.set(
ctx.common_atoms.message,
JSValue::new_string(ctx.intern(msg)),
);
let ptr = Box::into_raw(Box::new(err)) as usize;
ctx.runtime_mut().gc_heap_mut().track(ptr);
ctx.pending_exception = Some(JSValue::new_object(ptr));
}
fn create_builtin_function(ctx: &mut JSContext, name: &str, arity: u32) -> JSValue {
let mut func = JSFunction::new_builtin(ctx.intern(name), arity);
func.set_builtin_marker(ctx, name);
let ptr = Box::into_raw(Box::new(func)) as usize;
ctx.runtime_mut().gc_heap_mut().track_function(ptr);
JSValue::new_function(ptr)
}
pub const NO_DESCRIPTION: Atom = Atom(u32::MAX);
fn create_symbol(ctx: &mut JSContext, description: Option<Atom>) -> JSValue {
let desc = description.unwrap_or(NO_DESCRIPTION);
if desc != NO_DESCRIPTION {
ctx.mark_symbol_atom(desc);
}
let id = ctx.runtime_mut().next_symbol_id();
JSValue::new_symbol_with_id(desc, id)
}
fn symbol_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
let desc = if args.is_empty() {
None
} else {
let desc_val = args[0];
if desc_val.is_string() {
Some(desc_val.get_atom())
} else if desc_val.is_undefined() {
None
} else if desc_val.is_symbol() {
throw_type_error(ctx, "Cannot convert a Symbol value to a string");
return JSValue::undefined();
} else {
let s = if desc_val.is_int() {
desc_val.get_int().to_string()
} else if desc_val.is_float() {
desc_val.get_float().to_string()
} else if desc_val.is_bool() {
desc_val.get_bool().to_string()
} else {
String::new()
};
Some(ctx.intern(&s))
}
};
create_symbol(ctx, desc)
}
fn symbol_for(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
let key_val = if args.is_empty() {
JSValue::new_string(ctx.intern("undefined"))
} else {
let v = args[0];
if v.is_string() {
v
} else if v.is_int() {
JSValue::new_string(ctx.intern(&v.get_int().to_string()))
} else if v.is_float() {
JSValue::new_string(ctx.intern(&v.get_float().to_string()))
} else if v.is_bool() {
JSValue::new_string(ctx.intern(if v.get_bool() { "true" } else { "false" }))
} else if v.is_undefined() {
JSValue::new_string(ctx.intern("undefined"))
} else if v.is_null() {
JSValue::new_string(ctx.intern("null"))
} else if v.is_symbol() {
throw_type_error(ctx, "Can't convert symbol to string");
return JSValue::undefined();
} else {
JSValue::new_string(ctx.intern(""))
}
};
let key = key_val.get_atom();
let global = ctx.global();
if global.is_object() {
let global_obj = global.as_object_mut();
let reg_atom = ctx.intern("__symbol_registry__");
if let Some(reg) = global_obj.get(reg_atom) {
if reg.is_object() {
let reg_obj = reg.as_object_mut();
let len_atom = ctx.common_atoms.length;
let len = reg_obj
.get(len_atom)
.map(|v| v.get_int() as usize)
.unwrap_or(0);
for i in 0..len {
let idx_atom = ctx.intern(&i.to_string());
if let Some(entry) = reg_obj.get(idx_atom) {
if entry.is_object() {
let entry_obj = entry.as_object_mut();
let desc_atom = ctx.intern("description");
if let Some(desc) = entry_obj.get(desc_atom) {
if desc.is_string() && desc.get_atom() == key {
let sym_atom = ctx.intern("symbol");
if let Some(sym) = entry_obj.get(sym_atom) {
return sym;
}
}
}
}
}
}
}
}
let new_sym = create_symbol(ctx, Some(key));
let reg = if let Some(r) = global_obj.get(reg_atom) {
if r.is_object() {
unsafe { JSValue::object_from_ptr_mut(r.get_ptr()) }
} else {
let mut new_reg = JSObject::new_array();
new_reg.set(ctx.common_atoms.length, JSValue::new_int(0));
let reg_ptr = Box::into_raw(Box::new(new_reg)) as usize;
let val = JSValue::new_object(reg_ptr);
global_obj.set(reg_atom, val);
unsafe { JSValue::object_from_ptr_mut(reg_ptr) }
}
} else {
let mut new_reg = JSObject::new_array();
new_reg.set(ctx.common_atoms.length, JSValue::new_int(0));
let reg_ptr = Box::into_raw(Box::new(new_reg)) as usize;
let val = JSValue::new_object(reg_ptr);
global_obj.set(reg_atom, val);
unsafe { JSValue::object_from_ptr_mut(reg_ptr) }
};
let len_atom = ctx.common_atoms.length;
let len = reg.get(len_atom).map(|v| v.get_int() as usize).unwrap_or(0);
let mut entry = JSObject::new();
entry.set(ctx.intern("description"), JSValue::new_string(key));
entry.set(ctx.intern("symbol"), new_sym);
let entry_ptr = Box::into_raw(Box::new(entry)) as usize;
let entry_val = JSValue::new_object(entry_ptr);
let idx_atom = ctx.intern(&len.to_string());
reg.set(idx_atom, entry_val);
reg.set(len_atom, JSValue::new_int((len + 1) as i64));
return new_sym;
}
create_symbol(ctx, Some(key))
}
fn symbol_key_for(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
if args.is_empty() {
throw_type_error(ctx, "Symbol.keyFor requires a symbol");
return JSValue::undefined();
}
let sym_val = args[0];
if !sym_val.is_symbol() {
throw_type_error(ctx, "Symbol.keyFor requires a symbol");
return JSValue::undefined();
}
let global = ctx.global();
if global.is_object() {
let global_obj = global.as_object();
let reg_atom = ctx.intern("__symbol_registry__");
if let Some(reg) = global_obj.get(reg_atom) {
if reg.is_object() {
let reg_obj = reg.as_object();
let len_atom = ctx.common_atoms.length;
let len = reg_obj
.get(len_atom)
.map(|v| v.get_int() as usize)
.unwrap_or(0);
for i in 0..len {
let idx_atom = ctx.intern(&i.to_string());
if let Some(entry) = reg_obj.get(idx_atom) {
if entry.is_object() {
let entry_obj = entry.as_object();
let sym_atom = ctx.intern("symbol");
if let Some(sym) = entry_obj.get(sym_atom) {
if sym.strict_eq(&sym_val) {
let desc_atom = ctx.intern("description");
if let Some(desc) = entry_obj.get(desc_atom) {
return desc;
}
}
}
}
}
}
}
}
}
JSValue::undefined()
}
fn symbol_description(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
if args.is_empty() {
throw_type_error(
ctx,
"Symbol.prototype.description requires that 'this' be a Symbol",
);
return JSValue::undefined();
}
let this_val = &args[0];
let sym = if this_val.is_symbol() {
this_val.clone()
} else if this_val.is_object() {
if let Some(v) = this_val.as_object().get(ctx.common_atoms.__value__) {
if v.is_symbol() {
v
} else {
throw_type_error(
ctx,
"Symbol.prototype.description requires that 'this' be a Symbol",
);
return JSValue::undefined();
}
} else {
throw_type_error(
ctx,
"Symbol.prototype.description requires that 'this' be a Symbol",
);
return JSValue::undefined();
}
} else {
throw_type_error(
ctx,
"Symbol.prototype.description requires that 'this' be a Symbol",
);
return JSValue::undefined();
};
let desc_atom = sym.get_atom();
if desc_atom == NO_DESCRIPTION {
JSValue::undefined()
} else {
JSValue::new_string(desc_atom)
}
}
fn symbol_to_primitive(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
if args.is_empty() {
throw_type_error(
ctx,
"Symbol.prototype[Symbol.toPrimitive] requires that 'this' be a Symbol",
);
return JSValue::undefined();
}
let this_val = &args[0];
if this_val.is_symbol() {
return this_val.clone();
}
if this_val.is_object() {
if let Some(v) = this_val.as_object().get(ctx.common_atoms.__value__) {
if v.is_symbol() {
return v;
}
}
}
throw_type_error(
ctx,
"Symbol.prototype[Symbol.toPrimitive] requires that 'this' be a Symbol",
);
JSValue::undefined()
}
fn symbol_value_of(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
if args.is_empty() {
throw_type_error(
ctx,
"Symbol.prototype.valueOf requires that 'this' be a Symbol",
);
return JSValue::undefined();
}
let this_val = &args[0];
if this_val.is_symbol() {
return this_val.clone();
}
if this_val.is_object() {
if let Some(v) = this_val.as_object().get(ctx.common_atoms.__value__) {
if v.is_symbol() {
return v;
}
}
}
throw_type_error(
ctx,
"Symbol.prototype.valueOf requires that 'this' be a Symbol",
);
JSValue::undefined()
}
fn symbol_to_string(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
let this_val = if args.is_empty() {
return JSValue::new_string(ctx.intern("Symbol()"));
} else {
&args[0]
};
let sym = if this_val.is_symbol() {
this_val.clone()
} else if this_val.is_object() {
let inner = this_val.as_object().get(ctx.common_atoms.__value__);
if let Some(v) = inner {
if v.is_symbol() {
v
} else {
throw_type_error(
ctx,
"Symbol.prototype.toString requires that 'this' be a Symbol",
);
return JSValue::undefined();
}
} else {
throw_type_error(
ctx,
"Symbol.prototype.toString requires that 'this' be a Symbol",
);
return JSValue::undefined();
}
} else {
throw_type_error(
ctx,
"Symbol.prototype.toString requires that 'this' be a Symbol",
);
return JSValue::undefined();
};
let desc_atom = sym.get_atom();
if desc_atom == NO_DESCRIPTION {
JSValue::new_string(ctx.intern("Symbol()"))
} else {
let desc = ctx.get_atom_str(desc_atom);
JSValue::new_string(ctx.intern(&format!("Symbol({})", desc)))
}
}
const SYMBOL_ITERATOR_DESC: &str = "Symbol.iterator";
const SYMBOL_TO_STRING_TAG_DESC: &str = "Symbol.toStringTag";
const SYMBOL_SPECIES_DESC: &str = "Symbol.species";
const SYMBOL_TO_PRIMITIVE_DESC: &str = "Symbol.toPrimitive";
const SYMBOL_IS_CONCAT_SPREADABLE_DESC: &str = "Symbol.isConcatSpreadable";
const SYMBOL_MATCH_DESC: &str = "Symbol.match";
const SYMBOL_REPLACE_DESC: &str = "Symbol.replace";
const SYMBOL_SEARCH_DESC: &str = "Symbol.search";
const SYMBOL_SPLIT_DESC: &str = "Symbol.split";
const SYMBOL_UNSCOPABLES_DESC: &str = "Symbol.unscopables";
const SYMBOL_HAS_INSTANCE_DESC: &str = "Symbol.hasInstance";
const SYMBOL_ASYNC_ITERATOR_DESC: &str = "Symbol.asyncIterator";
const SYMBOL_MATCH_ALL_DESC: &str = "Symbol.matchAll";
const SYMBOL_ASYNC_DISPOSE_DESC: &str = "Symbol.asyncDispose";
const SYMBOL_DISPOSE_DESC: &str = "Symbol.dispose";
pub fn get_or_create_well_known_symbol(ctx: &mut JSContext, description: &str) -> JSValue {
let desc_atom = ctx.intern(description);
let global = ctx.global();
if global.is_object() {
let global_obj = global.as_object_mut();
if let Some(sym) = global_obj.get(desc_atom) {
return sym;
}
let sym = create_symbol(ctx, Some(desc_atom));
global_obj.set(desc_atom, sym);
return sym;
}
create_symbol(ctx, Some(desc_atom))
}
pub fn init_symbol(ctx: &mut JSContext) {
let symbol_atom = ctx.intern("Symbol");
let global = ctx.global();
if global.is_object() {
if global.as_object().get(symbol_atom).is_some() {
return;
}
}
let mut symbol_ctor = JSFunction::new_builtin(ctx.intern("Symbol"), 0);
symbol_ctor.set_builtin_marker(ctx, "symbol_constructor");
let for_func = create_builtin_function(ctx, "symbol_for", 1);
let key_for_func = create_builtin_function(ctx, "symbol_keyFor", 1);
symbol_ctor.base.define_property(
ctx.intern("for"),
crate::object::object::PropertyDescriptor {
value: Some(for_func),
writable: true,
enumerable: false,
configurable: true,
get: None,
set: None,
},
);
symbol_ctor.base.define_property(
ctx.intern("keyFor"),
crate::object::object::PropertyDescriptor {
value: Some(key_for_func),
writable: true,
enumerable: false,
configurable: true,
get: None,
set: None,
},
);
let symbol_iter = get_or_create_well_known_symbol(ctx, SYMBOL_ITERATOR_DESC);
symbol_ctor.base.define_property(
ctx.intern("iterator"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_iter),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_to_string_tag = get_or_create_well_known_symbol(ctx, SYMBOL_TO_STRING_TAG_DESC);
symbol_ctor.base.define_property(
ctx.intern("toStringTag"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_to_string_tag),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_species = get_or_create_well_known_symbol(ctx, SYMBOL_SPECIES_DESC);
symbol_ctor.base.define_property(
ctx.intern("species"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_species),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_to_primitive = get_or_create_well_known_symbol(ctx, SYMBOL_TO_PRIMITIVE_DESC);
symbol_ctor.base.define_property(
ctx.intern("toPrimitive"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_to_primitive),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_is_concat_spreadable =
get_or_create_well_known_symbol(ctx, SYMBOL_IS_CONCAT_SPREADABLE_DESC);
symbol_ctor.base.define_property(
ctx.intern("isConcatSpreadable"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_is_concat_spreadable),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_match = get_or_create_well_known_symbol(ctx, SYMBOL_MATCH_DESC);
symbol_ctor.base.define_property(
ctx.intern("match"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_match),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_replace = get_or_create_well_known_symbol(ctx, SYMBOL_REPLACE_DESC);
symbol_ctor.base.define_property(
ctx.intern("replace"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_replace),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_search = get_or_create_well_known_symbol(ctx, SYMBOL_SEARCH_DESC);
symbol_ctor.base.define_property(
ctx.intern("search"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_search),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_split = get_or_create_well_known_symbol(ctx, SYMBOL_SPLIT_DESC);
symbol_ctor.base.define_property(
ctx.intern("split"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_split),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_unscopables = get_or_create_well_known_symbol(ctx, SYMBOL_UNSCOPABLES_DESC);
symbol_ctor.base.define_property(
ctx.intern("unscopables"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_unscopables),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_has_instance = get_or_create_well_known_symbol(ctx, SYMBOL_HAS_INSTANCE_DESC);
symbol_ctor.base.define_property(
ctx.intern("hasInstance"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_has_instance),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_async_iterator = get_or_create_well_known_symbol(ctx, SYMBOL_ASYNC_ITERATOR_DESC);
symbol_ctor.base.define_property(
ctx.intern("asyncIterator"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_async_iterator),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_match_all = get_or_create_well_known_symbol(ctx, SYMBOL_MATCH_ALL_DESC);
symbol_ctor.base.define_property(
ctx.intern("matchAll"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_match_all),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_async_dispose = get_or_create_well_known_symbol(ctx, SYMBOL_ASYNC_DISPOSE_DESC);
symbol_ctor.base.define_property(
ctx.intern("asyncDispose"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_async_dispose),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let symbol_dispose = get_or_create_well_known_symbol(ctx, SYMBOL_DISPOSE_DESC);
symbol_ctor.base.define_property(
ctx.intern("dispose"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_dispose),
writable: false,
enumerable: false,
configurable: false,
get: None,
set: None,
},
);
let mut sym_proto = JSObject::new();
if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
sym_proto.prototype = Some(obj_proto_ptr);
}
let to_string_fn = create_builtin_function(ctx, "symbol_toString", 0);
let value_of_fn = create_builtin_function(ctx, "symbol_valueOf", 0);
let description_fn = create_builtin_function(ctx, "symbol_description", 0);
let to_primitive_fn = create_builtin_function(ctx, "symbol_toPrimitive", 1);
sym_proto.set(ctx.intern("toString"), to_string_fn.clone());
sym_proto.set(ctx.intern("valueOf"), value_of_fn.clone());
let proto_ptr = Box::into_raw(Box::new(sym_proto)) as usize;
ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
let proto_value = JSValue::new_object(proto_ptr);
symbol_ctor.base.set(ctx.intern("prototype"), proto_value);
ctx.set_symbol_prototype(proto_ptr);
let symbol_to_string_tag = get_or_create_well_known_symbol(ctx, SYMBOL_TO_STRING_TAG_DESC);
let tag_key = crate::runtime::atom::Atom(0x40000000 | symbol_to_string_tag.get_symbol_id());
proto_value.as_object_mut().define_property(
tag_key,
crate::object::object::PropertyDescriptor {
value: Some(JSValue::new_string(ctx.intern("Symbol"))),
writable: false,
enumerable: false,
configurable: true,
get: None,
set: None,
},
);
let symbol_ptr = Box::into_raw(Box::new(symbol_ctor)) as usize;
ctx.runtime_mut().gc_heap_mut().track_function(symbol_ptr);
let symbol_ctor_val = JSValue::new_function(symbol_ptr);
proto_value.as_object_mut().define_property(
ctx.intern("constructor"),
crate::object::object::PropertyDescriptor {
value: Some(symbol_ctor_val.clone()),
writable: true,
enumerable: false,
configurable: true,
get: None,
set: None,
},
);
proto_value.as_object_mut().define_property(
ctx.intern("toString"),
crate::object::object::PropertyDescriptor {
value: Some(to_string_fn),
writable: true,
enumerable: false,
configurable: true,
get: None,
set: None,
},
);
proto_value.as_object_mut().define_property(
ctx.intern("valueOf"),
crate::object::object::PropertyDescriptor {
value: Some(value_of_fn),
writable: true,
enumerable: false,
configurable: true,
get: None,
set: None,
},
);
proto_value.as_object_mut().define_property(
ctx.intern("description"),
crate::object::object::PropertyDescriptor {
value: None,
writable: false,
enumerable: false,
configurable: true,
get: Some(description_fn),
set: None,
},
);
let symbol_to_primitive_sym = get_or_create_well_known_symbol(ctx, SYMBOL_TO_PRIMITIVE_DESC);
let to_prim_key =
crate::runtime::atom::Atom(0x40000000 | symbol_to_primitive_sym.get_symbol_id());
proto_value.as_object_mut().define_property(
to_prim_key,
crate::object::object::PropertyDescriptor {
value: Some(to_primitive_fn),
writable: false,
enumerable: false,
configurable: true,
get: None,
set: None,
},
);
let symbol_atom = ctx.intern("Symbol");
let global = ctx.global();
if global.is_object() {
let global_obj = global.as_object_mut();
crate::builtins::global::set_non_enumerable(global_obj, symbol_atom, symbol_ctor_val);
}
}
pub fn register_builtins(ctx: &mut JSContext) {
ctx.register_builtin(
"symbol_constructor",
HostFunction::new("Symbol", 0, symbol_constructor),
);
ctx.register_builtin("symbol_for", HostFunction::new("for", 1, symbol_for));
ctx.register_builtin(
"symbol_keyFor",
HostFunction::new("keyFor", 1, symbol_key_for),
);
ctx.register_builtin(
"symbol_valueOf",
HostFunction::method("valueOf", 0, symbol_value_of),
);
ctx.register_builtin(
"symbol_toString",
HostFunction::method("toString", 0, symbol_to_string),
);
ctx.register_builtin(
"symbol_description",
HostFunction::method("description", 0, symbol_description),
);
ctx.register_builtin(
"symbol_toPrimitive",
HostFunction::method("[Symbol.toPrimitive]", 1, symbol_to_primitive),
);
}
pub fn fix_prototype_chain(ctx: &mut JSContext) {
if let Some(sym_proto_ptr) = ctx.get_symbol_prototype() {
if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
unsafe {
(*sym_proto_ptr).prototype = Some(obj_proto_ptr);
}
}
}
}
pub fn get_symbol_iterator(ctx: &mut JSContext) -> JSValue {
get_or_create_well_known_symbol(ctx, SYMBOL_ITERATOR_DESC)
}
pub fn get_symbol_iterator_atom(ctx: &mut JSContext) -> Atom {
ctx.intern("Symbol.iterator")
}
pub fn get_symbol_split(ctx: &mut JSContext) -> JSValue {
get_or_create_well_known_symbol(ctx, SYMBOL_SPLIT_DESC)
}
pub fn get_symbol_split_atom(ctx: &mut JSContext) -> Atom {
ctx.intern("Symbol.split")
}
pub fn get_symbol_unscopables(ctx: &mut JSContext) -> JSValue {
get_or_create_well_known_symbol(ctx, SYMBOL_UNSCOPABLES_DESC)
}
pub fn get_symbol_unscopables_atom(ctx: &mut JSContext) -> Atom {
ctx.intern("Symbol.unscopables")
}
pub fn get_symbol_has_instance(ctx: &mut JSContext) -> JSValue {
get_or_create_well_known_symbol(ctx, SYMBOL_HAS_INSTANCE_DESC)
}
pub fn get_symbol_has_instance_atom(ctx: &mut JSContext) -> Atom {
ctx.intern("Symbol.hasInstance")
}
pub fn get_symbol_async_iterator(ctx: &mut JSContext) -> JSValue {
get_or_create_well_known_symbol(ctx, SYMBOL_ASYNC_ITERATOR_DESC)
}
pub fn get_symbol_async_iterator_atom(ctx: &mut JSContext) -> Atom {
ctx.intern("Symbol.asyncIterator")
}
pub fn get_symbol_to_string_tag_prop_key(ctx: &mut JSContext) -> Atom {
let sym = get_or_create_well_known_symbol(ctx, SYMBOL_TO_STRING_TAG_DESC);
crate::runtime::atom::Atom(0x40000000 | sym.get_symbol_id())
}
pub fn is_symbol(val: &JSValue) -> bool {
val.is_symbol()
}