diff --git a/.gitignore b/.gitignore index a285de586d2..132f32c4e84 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,7 @@ chrome_profiler.json # e2e test playwright-report test-results + +# dhat +dhat-*.json +perf.data* \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7ccc7f2bb9f..0e5fa645f42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,7 @@ dependencies = [ "boa_runtime", "clap", "colored", + "dhat", "jemallocator", "phf", "pollster", @@ -389,6 +390,7 @@ dependencies = [ "num-traits", "num_enum", "once_cell", + "paste", "pollster", "rand", "regress", @@ -954,6 +956,22 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "dhat" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2aaf837aaf456f6706cb46386ba8dffd4013a757e36f4ea05c20dd46b209a3" +dependencies = [ + "backtrace", + "lazy_static", + "mintex", + "parking_lot 0.12.1", + "rustc-hash", + "serde", + "serde_json", + "thousands", +] + [[package]] name = "displaydoc" version = "0.2.4" @@ -1882,6 +1900,16 @@ dependencies = [ "adler", ] +[[package]] +name = "mintex" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7c5ba1c3b5a23418d7bbf98c71c3d4946a0125002129231da8d6b723d559cb" +dependencies = [ + "once_cell", + "sys-info", +] + [[package]] name = "mio" version = "0.8.8" @@ -2083,6 +2111,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "percent-encoding" version = "2.3.0" @@ -2831,6 +2865,16 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sys-info" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "sys-locale" version = "0.3.1" @@ -2892,6 +2936,12 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "thousands" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" + [[package]] name = "thread_local" version = "1.1.7" diff --git a/Cargo.toml b/Cargo.toml index a447d93e6cb..67f2e471102 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,10 @@ lto = "fat" # Makes sure that all code is compiled together, for LTO codegen-units = 1 +[profile.release-dbg] +inherits = "release" +debug = true + # The test profile, used for `cargo test`. [profile.test] # Enables thin local LTO and some optimizations. diff --git a/boa_cli/Cargo.toml b/boa_cli/Cargo.toml index 6d30aa0164f..33d81dee094 100644 --- a/boa_cli/Cargo.toml +++ b/boa_cli/Cargo.toml @@ -25,9 +25,11 @@ colored.workspace = true regex.workspace = true phf = { workspace = true, features = ["macros"] } pollster.workspace = true +dhat = { version = "0.3.2", optional = true } [features] default = ["boa_engine/annex-b", "boa_engine/experimental", "boa_engine/intl"] +dhat = ["dep:dhat"] [target.x86_64-unknown-linux-gnu.dependencies] jemallocator.workspace = true diff --git a/boa_cli/src/debug/function.rs b/boa_cli/src/debug/function.rs index 40a6dcc3aea..6cb367fdde8 100644 --- a/boa_cli/src/debug/function.rs +++ b/boa_cli/src/debug/function.rs @@ -1,4 +1,5 @@ use boa_engine::{ + js_string, object::ObjectInitializer, vm::flowgraph::{Direction, Graph}, Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction, @@ -67,8 +68,10 @@ fn flowgraph(_this: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> Js let mut direction = Direction::LeftToRight; if let Some(arguments) = args.get(1) { if let Some(arguments) = arguments.as_object() { - format = flowgraph_parse_format_option(&arguments.get("format", context)?)?; - direction = flowgraph_parse_direction_option(&arguments.get("direction", context)?)?; + format = flowgraph_parse_format_option(&arguments.get(js_string!("format"), context)?)?; + direction = flowgraph_parse_direction_option( + &arguments.get(js_string!("direction"), context)?, + )?; } else if value.is_string() { format = flowgraph_parse_format_option(value)?; } else { @@ -97,7 +100,7 @@ fn flowgraph(_this: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> Js FlowgraphFormat::Mermaid => graph.to_mermaid_format(), }; - Ok(JsValue::new(result)) + Ok(JsValue::new(js_string!(result))) } fn bytecode(_: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> JsResult { @@ -122,7 +125,7 @@ fn bytecode(_: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> JsResul JsNativeError::typ().with_message("native functions do not have bytecode") })?; - Ok(code.to_interned_string(context.interner()).into()) + Ok(js_string!(code.to_interned_string(context.interner())).into()) } fn set_trace_flag_in_function_object(object: &JsObject, value: bool) -> JsResult<()> { @@ -176,9 +179,21 @@ fn traceable(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult) -> JsObject { ObjectInitializer::new(context) - .function(NativeFunction::from_fn_ptr(flowgraph), "flowgraph", 1) - .function(NativeFunction::from_fn_ptr(bytecode), "bytecode", 1) - .function(NativeFunction::from_fn_ptr(trace), "trace", 1) - .function(NativeFunction::from_fn_ptr(traceable), "traceable", 2) + .function( + NativeFunction::from_fn_ptr(flowgraph), + js_string!("flowgraph"), + 1, + ) + .function( + NativeFunction::from_fn_ptr(bytecode), + js_string!("bytecode"), + 1, + ) + .function(NativeFunction::from_fn_ptr(trace), js_string!("trace"), 1) + .function( + NativeFunction::from_fn_ptr(traceable), + js_string!("traceable"), + 2, + ) .build() } diff --git a/boa_cli/src/debug/gc.rs b/boa_cli/src/debug/gc.rs index 93c4b625457..69f3a08cdc7 100644 --- a/boa_cli/src/debug/gc.rs +++ b/boa_cli/src/debug/gc.rs @@ -1,4 +1,6 @@ -use boa_engine::{object::ObjectInitializer, Context, JsObject, JsResult, JsValue, NativeFunction}; +use boa_engine::{ + js_string, object::ObjectInitializer, Context, JsObject, JsResult, JsValue, NativeFunction, +}; /// Trigger garbage collection. fn collect(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { @@ -8,6 +10,10 @@ fn collect(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult pub(super) fn create_object(context: &mut Context<'_>) -> JsObject { ObjectInitializer::new(context) - .function(NativeFunction::from_fn_ptr(collect), "collect", 0) + .function( + NativeFunction::from_fn_ptr(collect), + js_string!("collect"), + 0, + ) .build() } diff --git a/boa_cli/src/debug/limits.rs b/boa_cli/src/debug/limits.rs index dfd8f8237b7..bfbdda4e613 100644 --- a/boa_cli/src/debug/limits.rs +++ b/boa_cli/src/debug/limits.rs @@ -1,4 +1,5 @@ use boa_engine::{ + js_string, object::{FunctionObjectBuilder, ObjectInitializer}, property::Attribute, Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction, @@ -55,13 +56,13 @@ pub(super) fn create_object(context: &mut Context<'_>) -> JsObject { .build(); ObjectInitializer::new(context) .accessor( - "loop", + js_string!("loop"), Some(get_loop), Some(set_loop), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, ) .accessor( - "recursion", + js_string!("recursion"), Some(get_recursion), Some(set_recursion), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, diff --git a/boa_cli/src/debug/mod.rs b/boa_cli/src/debug/mod.rs index ca1c22d0773..f4991ea51a0 100644 --- a/boa_cli/src/debug/mod.rs +++ b/boa_cli/src/debug/mod.rs @@ -1,7 +1,7 @@ // Allow lint so it, doesn't warn about `JsResult<>` unneeded return on functions. #![allow(clippy::unnecessary_wraps)] -use boa_engine::{object::ObjectInitializer, property::Attribute, Context, JsObject}; +use boa_engine::{js_string, object::ObjectInitializer, property::Attribute, Context, JsObject}; mod function; mod gc; @@ -22,37 +22,37 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject { ObjectInitializer::new(context) .property( - "function", + js_string!("function"), function_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "object", + js_string!("object"), object_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "shape", + js_string!("shape"), shape_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "optimizer", + js_string!("optimizer"), optimizer_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "gc", + js_string!("gc"), gc_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "realm", + js_string!("realm"), realm_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "limits", + js_string!("limits"), limits_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) @@ -63,7 +63,7 @@ pub(crate) fn init_boa_debug_object(context: &mut Context<'_>) { let boa_object = create_boa_object(context); context .register_global_property( - "$boa", + js_string!("$boa"), boa_object, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) diff --git a/boa_cli/src/debug/object.rs b/boa_cli/src/debug/object.rs index 05fb69ffae5..441d89b5acb 100644 --- a/boa_cli/src/debug/object.rs +++ b/boa_cli/src/debug/object.rs @@ -1,5 +1,6 @@ use boa_engine::{ - object::ObjectInitializer, Context, JsNativeError, JsObject, JsResult, JsValue, NativeFunction, + js_string, object::ObjectInitializer, Context, JsNativeError, JsObject, JsResult, JsValue, + NativeFunction, }; /// Returns objects pointer in memory. @@ -17,11 +18,11 @@ fn id(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { }; let ptr: *const _ = object.as_ref(); - Ok(format!("0x{:X}", ptr as usize).into()) + Ok(js_string!(format!("0x{:X}", ptr as usize)).into()) } pub(super) fn create_object(context: &mut Context<'_>) -> JsObject { ObjectInitializer::new(context) - .function(NativeFunction::from_fn_ptr(id), "id", 1) + .function(NativeFunction::from_fn_ptr(id), js_string!("id"), 1) .build() } diff --git a/boa_cli/src/debug/optimizer.rs b/boa_cli/src/debug/optimizer.rs index 45c76993e65..e7e2679c870 100644 --- a/boa_cli/src/debug/optimizer.rs +++ b/boa_cli/src/debug/optimizer.rs @@ -1,4 +1,5 @@ use boa_engine::{ + js_string, object::{FunctionObjectBuilder, ObjectInitializer}, optimizer::OptimizerOptions, property::Attribute, @@ -71,13 +72,13 @@ pub(super) fn create_object(context: &mut Context<'_>) -> JsObject { .build(); ObjectInitializer::new(context) .accessor( - "constantFolding", + js_string!("constantFolding"), Some(get_constant_folding), Some(set_constant_folding), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, ) .accessor( - "statistics", + js_string!("statistics"), Some(get_statistics), Some(set_statistics), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, diff --git a/boa_cli/src/debug/realm.rs b/boa_cli/src/debug/realm.rs index 7a1e6cff9d1..efe5ccbbddb 100644 --- a/boa_cli/src/debug/realm.rs +++ b/boa_cli/src/debug/realm.rs @@ -1,4 +1,6 @@ -use boa_engine::{object::ObjectInitializer, Context, JsObject, JsResult, JsValue, NativeFunction}; +use boa_engine::{ + js_string, object::ObjectInitializer, Context, JsObject, JsResult, JsValue, NativeFunction, +}; /// Creates a new ECMAScript Realm and returns the global object of the realm. fn create(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { @@ -9,6 +11,6 @@ fn create(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult pub(super) fn create_object(context: &mut Context<'_>) -> JsObject { ObjectInitializer::new(context) - .function(NativeFunction::from_fn_ptr(create), "create", 0) + .function(NativeFunction::from_fn_ptr(create), js_string!("create"), 0) .build() } diff --git a/boa_cli/src/debug/shape.rs b/boa_cli/src/debug/shape.rs index 5bd66e3585c..90844415a6a 100644 --- a/boa_cli/src/debug/shape.rs +++ b/boa_cli/src/debug/shape.rs @@ -23,7 +23,7 @@ fn id(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { let object = get_object(args, 0)?; let object = object.borrow(); let shape = object.shape(); - Ok(format!("0x{:X}", shape.to_addr_usize()).into()) + Ok(js_string!(format!("0x{:X}", shape.to_addr_usize())).into()) } /// Returns object's shape type. @@ -62,8 +62,8 @@ fn same(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult pub(super) fn create_object(context: &mut Context<'_>) -> JsObject { ObjectInitializer::new(context) - .function(NativeFunction::from_fn_ptr(id), "id", 1) - .function(NativeFunction::from_fn_ptr(r#type), "type", 1) - .function(NativeFunction::from_fn_ptr(same), "same", 2) + .function(NativeFunction::from_fn_ptr(id), js_string!("id"), 1) + .function(NativeFunction::from_fn_ptr(r#type), js_string!("type"), 1) + .function(NativeFunction::from_fn_ptr(same), js_string!("same"), 2) .build() } diff --git a/boa_cli/src/main.rs b/boa_cli/src/main.rs index 2727eb67aa2..3c313e4ffde 100644 --- a/boa_cli/src/main.rs +++ b/boa_cli/src/main.rs @@ -70,6 +70,7 @@ use boa_engine::{ builtins::promise::PromiseState, context::ContextBuilder, job::{FutureJob, JobQueue, NativeJob}, + js_string, module::{Module, ModuleLoader, SimpleModuleLoader}, optimizer::OptimizerOptions, property::Attribute, @@ -87,13 +88,22 @@ use std::{ println, }; -#[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))] +#[cfg(all( + target_arch = "x86_64", + target_os = "linux", + target_env = "gnu", + not(feature = "dhat") +))] #[cfg_attr( all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"), global_allocator )] static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; +#[cfg(feature = "dhat")] +#[global_allocator] +static ALLOC: dhat::Alloc = dhat::Alloc; + /// CLI configuration for Boa. static CLI_HISTORY: &str = ".boa_history"; @@ -366,6 +376,9 @@ fn evaluate_files( } fn main() -> Result<(), io::Error> { + #[cfg(feature = "dhat")] + let _profiler = dhat::Profiler::new_heap(); + let args = Opt::parse(); let queue: &dyn JobQueue = &Jobs::default(); @@ -480,7 +493,7 @@ fn main() -> Result<(), io::Error> { fn add_runtime(context: &mut Context<'_>) { let console = Console::init(context); context - .register_global_property(Console::NAME, console, Attribute::all()) + .register_global_property(js_string!(Console::NAME), console, Attribute::all()) .expect("the console object shouldn't exist"); } diff --git a/boa_engine/Cargo.toml b/boa_engine/Cargo.toml index f8a380fdd35..3b925690fc9 100644 --- a/boa_engine/Cargo.toml +++ b/boa_engine/Cargo.toml @@ -80,6 +80,7 @@ pollster.workspace = true thin-vec.workspace = true itertools = { version = "0.11.0", default-features = false } icu_normalizer = "~1.3.0" +paste = "1.0" # intl deps boa_icu_provider = {workspace = true, features = ["std"], optional = true } diff --git a/boa_engine/src/builtins/array/array_iterator.rs b/boa_engine/src/builtins/array/array_iterator.rs index 417efb815ae..bd8196b5220 100644 --- a/boa_engine/src/builtins/array/array_iterator.rs +++ b/boa_engine/src/builtins/array/array_iterator.rs @@ -11,6 +11,7 @@ use crate::{ }, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::{JsObject, ObjectData}, property::{Attribute, PropertyNameKind}, realm::Realm, @@ -37,7 +38,7 @@ pub struct ArrayIterator { impl IntrinsicObject for ArrayIterator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("ArrayIterator", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -47,10 +48,10 @@ impl IntrinsicObject for ArrayIterator { .iterator_prototypes() .iterator(), ) - .static_method(Self::next, "next", 0) + .static_method(Self::next, js_string!("next"), 0) .static_property( JsSymbol::to_string_tag(), - "Array Iterator", + js_string!("Array Iterator"), Attribute::CONFIGURABLE, ) .build(); diff --git a/boa_engine/src/builtins/array/mod.rs b/boa_engine/src/builtins/array/mod.rs index 46f87be67c4..9a2a0941307 100644 --- a/boa_engine/src/builtins/array/mod.rs +++ b/boa_engine/src/builtins/array/mod.rs @@ -23,9 +23,10 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData, CONSTRUCTOR}, property::{Attribute, PropertyDescriptor, PropertyNameKind}, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, value::{IntegerOrInfinity, JsValue}, - Context, JsArgs, JsResult, + Context, JsArgs, JsResult, JsString, }; use std::cmp::{max, min, Ordering}; @@ -49,13 +50,13 @@ pub(crate) struct Array; impl IntrinsicObject for Array { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let symbol_iterator = JsSymbol::iterator(); let symbol_unscopables = JsSymbol::unscopables(); let get_species = BuiltInBuilder::callable(realm, Self::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); let values_function = BuiltInBuilder::callable_with_object( @@ -63,7 +64,7 @@ impl IntrinsicObject for Array { realm.intrinsics().objects().array_prototype_values().into(), Self::values, ) - .name("values") + .name(js_string!("values")) .build(); let to_string_function = BuiltInBuilder::callable_with_object( @@ -75,7 +76,7 @@ impl IntrinsicObject for Array { .into(), Self::to_string, ) - .name("toString") + .name(js_string!("toString")) .build(); let unscopables_object = Self::unscopables_object(); @@ -107,47 +108,47 @@ impl IntrinsicObject for Array { unscopables_object, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .method(Self::at, "at", 1) - .method(Self::concat, "concat", 1) - .method(Self::push, "push", 1) - .method(Self::index_of, "indexOf", 1) - .method(Self::last_index_of, "lastIndexOf", 1) - .method(Self::includes_value, "includes", 1) - .method(Self::map, "map", 1) - .method(Self::fill, "fill", 1) - .method(Self::for_each, "forEach", 1) - .method(Self::filter, "filter", 1) - .method(Self::pop, "pop", 0) - .method(Self::join, "join", 1) + .method(Self::at, js_string!("at"), 1) + .method(Self::concat, js_string!("concat"), 1) + .method(Self::push, js_string!("push"), 1) + .method(Self::index_of, js_string!("indexOf"), 1) + .method(Self::last_index_of, js_string!("lastIndexOf"), 1) + .method(Self::includes_value, js_string!("includes"), 1) + .method(Self::map, js_string!("map"), 1) + .method(Self::fill, js_string!("fill"), 1) + .method(Self::for_each, js_string!("forEach"), 1) + .method(Self::filter, js_string!("filter"), 1) + .method(Self::pop, js_string!("pop"), 0) + .method(Self::join, js_string!("join"), 1) .property( utf16!("toString"), to_string_function, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .method(Self::reverse, "reverse", 0) - .method(Self::shift, "shift", 0) - .method(Self::unshift, "unshift", 1) - .method(Self::every, "every", 1) - .method(Self::find, "find", 1) - .method(Self::find_index, "findIndex", 1) - .method(Self::find_last, "findLast", 1) - .method(Self::find_last_index, "findLastIndex", 1) - .method(Self::flat, "flat", 0) - .method(Self::flat_map, "flatMap", 1) - .method(Self::slice, "slice", 2) - .method(Self::some, "some", 1) - .method(Self::sort, "sort", 1) - .method(Self::splice, "splice", 2) - .method(Self::to_locale_string, "toLocaleString", 0) - .method(Self::reduce, "reduce", 1) - .method(Self::reduce_right, "reduceRight", 1) - .method(Self::keys, "keys", 0) - .method(Self::entries, "entries", 0) - .method(Self::copy_within, "copyWithin", 2) + .method(Self::reverse, js_string!("reverse"), 0) + .method(Self::shift, js_string!("shift"), 0) + .method(Self::unshift, js_string!("unshift"), 1) + .method(Self::every, js_string!("every"), 1) + .method(Self::find, js_string!("find"), 1) + .method(Self::find_index, js_string!("findIndex"), 1) + .method(Self::find_last, js_string!("findLast"), 1) + .method(Self::find_last_index, js_string!("findLastIndex"), 1) + .method(Self::flat, js_string!("flat"), 0) + .method(Self::flat_map, js_string!("flatMap"), 1) + .method(Self::slice, js_string!("slice"), 2) + .method(Self::some, js_string!("some"), 1) + .method(Self::sort, js_string!("sort"), 1) + .method(Self::splice, js_string!("splice"), 2) + .method(Self::to_locale_string, js_string!("toLocaleString"), 0) + .method(Self::reduce, js_string!("reduce"), 1) + .method(Self::reduce_right, js_string!("reduceRight"), 1) + .method(Self::keys, js_string!("keys"), 0) + .method(Self::entries, js_string!("entries"), 0) + .method(Self::copy_within, js_string!("copyWithin"), 2) // Static Methods - .static_method(Self::from, "from", 1) - .static_method(Self::is_array, "isArray", 1) - .static_method(Self::of, "of", 0) + .static_method(Self::from, js_string!("from"), 1) + .static_method(Self::is_array, js_string!("isArray"), 1) + .static_method(Self::of, js_string!("of"), 0) .build(); } @@ -157,7 +158,7 @@ impl IntrinsicObject for Array { } impl BuiltInObject for Array { - const NAME: &'static str = "Array"; + const NAME: JsString = StaticJsStrings::ARRAY; } impl BuiltInConstructor for Array { diff --git a/boa_engine/src/builtins/array/tests.rs b/boa_engine/src/builtins/array/tests.rs index 71b7b39f3ec..d14b610e394 100644 --- a/boa_engine/src/builtins/array/tests.rs +++ b/boa_engine/src/builtins/array/tests.rs @@ -1,5 +1,7 @@ use super::Array; -use crate::{builtins::Number, run_test_actions, Context, JsNativeErrorKind, JsValue, TestAction}; +use crate::{ + builtins::Number, js_string, run_test_actions, Context, JsNativeErrorKind, JsValue, TestAction, +}; use indoc::indoc; #[test] @@ -36,7 +38,7 @@ fn of() { TestAction::assert("arrayEquals(Array.of(), [])"), TestAction::run("let a = Array.of.call(Date, 'a', undefined, 3);"), TestAction::assert("a instanceof Date"), - TestAction::assert_eq("a[0]", "a"), + TestAction::assert_eq("a[0]", js_string!("a")), TestAction::assert_eq("a[1]", JsValue::undefined()), TestAction::assert_eq("a[2]", 3), TestAction::assert_eq("a.length", 3), @@ -72,18 +74,18 @@ fn copy_within() { #[test] fn join() { run_test_actions([ - TestAction::assert_eq("[].join('.')", ""), - TestAction::assert_eq("['a'].join('.')", "a"), - TestAction::assert_eq("['a', 'b', 'c'].join('.')", "a.b.c"), + TestAction::assert_eq("[].join('.')", js_string!()), + TestAction::assert_eq("['a'].join('.')", js_string!("a")), + TestAction::assert_eq("['a', 'b', 'c'].join('.')", js_string!("a.b.c")), ]); } #[test] fn to_string() { run_test_actions([ - TestAction::assert_eq("[].toString()", ""), - TestAction::assert_eq("['a'].toString()", "a"), - TestAction::assert_eq("['a', 'b', 'c'].toString()", "a,b,c"), + TestAction::assert_eq("[].toString()", js_string!()), + TestAction::assert_eq("['a'].toString()", js_string!("a")), + TestAction::assert_eq("['a', 'b', 'c'].toString()", js_string!("a,b,c")), ]); } @@ -113,7 +115,7 @@ fn every() { fn find() { run_test_actions([TestAction::assert_eq( "['a', 'b', 'c'].find(e => e == 'a')", - "a", + js_string!("a"), )]); } @@ -347,7 +349,7 @@ fn fill_obj_ref() { let a = new Array(3).fill(obj); obj.hi = 'hi' "#}), - TestAction::assert_eq("a[2].hi", "hi"), + TestAction::assert_eq("a[2].hi", js_string!("hi")), ]); } diff --git a/boa_engine/src/builtins/array_buffer/mod.rs b/boa_engine/src/builtins/array_buffer/mod.rs index afd4c192fc2..084018b5d80 100644 --- a/boa_engine/src/builtins/array_buffer/mod.rs +++ b/boa_engine/src/builtins/array_buffer/mod.rs @@ -14,13 +14,14 @@ use crate::{ builtins::{typed_array::TypedArrayKind, BuiltInObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::common::StaticJsStrings, symbol::JsSymbol, value::{IntegerOrInfinity, Numeric}, - Context, JsArgs, JsResult, JsValue, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -49,21 +50,21 @@ impl ArrayBuffer { impl IntrinsicObject for ArrayBuffer { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE; let get_species = BuiltInBuilder::callable(realm, Self::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); let get_byte_length = BuiltInBuilder::callable(realm, Self::get_byte_length) - .name("get byteLength") + .name(js_string!("get byteLength")) .build(); BuiltInBuilder::from_standard_constructor::(realm) .accessor( - utf16!("byteLength"), + js_string!("byteLength"), Some(get_byte_length), None, flag_attributes, @@ -74,8 +75,8 @@ impl IntrinsicObject for ArrayBuffer { None, Attribute::CONFIGURABLE, ) - .static_method(Self::is_view, "isView", 1) - .method(Self::slice, "slice", 2) + .static_method(Self::is_view, js_string!("isView"), 1) + .method(Self::slice, js_string!("slice"), 2) .property( JsSymbol::to_string_tag(), Self::NAME, @@ -90,7 +91,7 @@ impl IntrinsicObject for ArrayBuffer { } impl BuiltInObject for ArrayBuffer { - const NAME: &'static str = "ArrayBuffer"; + const NAME: JsString = StaticJsStrings::ARRAY_BUFFER; } impl BuiltInConstructor for ArrayBuffer { diff --git a/boa_engine/src/builtins/async_function/mod.rs b/boa_engine/src/builtins/async_function/mod.rs index be9b448ab50..16674dec764 100644 --- a/boa_engine/src/builtins/async_function/mod.rs +++ b/boa_engine/src/builtins/async_function/mod.rs @@ -12,8 +12,9 @@ use crate::{ context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, - Context, JsResult, JsValue, + Context, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -25,7 +26,7 @@ pub struct AsyncFunction; impl IntrinsicObject for AsyncFunction { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().function().constructor()) @@ -46,7 +47,7 @@ impl IntrinsicObject for AsyncFunction { } impl BuiltInObject for AsyncFunction { - const NAME: &'static str = "AsyncFunction"; + const NAME: JsString = StaticJsStrings::ASYNC_FUNCTION; } impl BuiltInConstructor for AsyncFunction { diff --git a/boa_engine/src/builtins/async_generator/mod.rs b/boa_engine/src/builtins/async_generator/mod.rs index e8504bc0c4c..74af1438a48 100644 --- a/boa_engine/src/builtins/async_generator/mod.rs +++ b/boa_engine/src/builtins/async_generator/mod.rs @@ -12,14 +12,16 @@ use crate::{ }, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, native_function::NativeFunction, object::{FunctionObjectBuilder, JsObject, CONSTRUCTOR}, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, value::JsValue, vm::{CompletionRecord, GeneratorResumeKind}, - Context, JsArgs, JsError, JsResult, + Context, JsArgs, JsError, JsResult, JsString, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -68,7 +70,7 @@ pub struct AsyncGenerator { impl IntrinsicObject for AsyncGenerator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -78,9 +80,9 @@ impl IntrinsicObject for AsyncGenerator { .iterator_prototypes() .async_iterator(), ) - .static_method(Self::next, "next", 1) - .static_method(Self::r#return, "return", 1) - .static_method(Self::throw, "throw", 1) + .static_method(Self::next, js_string!("next"), 1) + .static_method(Self::r#return, js_string!("return"), 1) + .static_method(Self::throw, js_string!("throw"), 1) .static_property( JsSymbol::to_string_tag(), Self::NAME, @@ -104,7 +106,7 @@ impl IntrinsicObject for AsyncGenerator { } impl AsyncGenerator { - const NAME: &'static str = "AsyncGenerator"; + const NAME: JsString = StaticJsStrings::ASYNC_GENERATOR; /// `AsyncGenerator.prototype.next ( value )` /// diff --git a/boa_engine/src/builtins/async_generator_function/mod.rs b/boa_engine/src/builtins/async_generator_function/mod.rs index aa953957bb4..8dd373bc2a6 100644 --- a/boa_engine/src/builtins/async_generator_function/mod.rs +++ b/boa_engine/src/builtins/async_generator_function/mod.rs @@ -11,9 +11,10 @@ use crate::{ object::{JsObject, PROTOTYPE}, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, value::JsValue, - Context, JsResult, + Context, JsResult, JsString, }; use boa_profiler::Profiler; @@ -25,7 +26,7 @@ pub struct AsyncGeneratorFunction; impl IntrinsicObject for AsyncGeneratorFunction { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .inherits(Some( @@ -51,7 +52,7 @@ impl IntrinsicObject for AsyncGeneratorFunction { } impl BuiltInObject for AsyncGeneratorFunction { - const NAME: &'static str = "AsyncGeneratorFunction"; + const NAME: JsString = StaticJsStrings::ASYNC_GENERATOR_FUNCTION; } impl BuiltInConstructor for AsyncGeneratorFunction { diff --git a/boa_engine/src/builtins/bigint/mod.rs b/boa_engine/src/builtins/bigint/mod.rs index d649bf60830..78d1b70a423 100644 --- a/boa_engine/src/builtins/bigint/mod.rs +++ b/boa_engine/src/builtins/bigint/mod.rs @@ -16,12 +16,14 @@ use crate::{ builtins::BuiltInObject, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::JsObject, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, value::{IntegerOrInfinity, PreferredType}, - Context, JsArgs, JsBigInt, JsResult, JsValue, + Context, JsArgs, JsBigInt, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; use num_bigint::ToBigInt; @@ -37,13 +39,13 @@ pub struct BigInt; impl IntrinsicObject for BigInt { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) - .method(Self::to_string, "toString", 0) - .method(Self::value_of, "valueOf", 0) - .static_method(Self::as_int_n, "asIntN", 2) - .static_method(Self::as_uint_n, "asUintN", 2) + .method(Self::to_string, js_string!("toString"), 0) + .method(Self::value_of, js_string!("valueOf"), 0) + .static_method(Self::as_int_n, js_string!("asIntN"), 2) + .static_method(Self::as_uint_n, js_string!("asUintN"), 2) .property( JsSymbol::to_string_tag(), Self::NAME, @@ -58,7 +60,7 @@ impl IntrinsicObject for BigInt { } impl BuiltInObject for BigInt { - const NAME: &'static str = "BigInt"; + const NAME: JsString = StaticJsStrings::BIG_INT; } impl BuiltInConstructor for BigInt { @@ -179,7 +181,7 @@ impl BigInt { let radix_mv = if radix.is_undefined() { // 5. If radixMV = 10, return ! ToString(x). // Note: early return optimization. - return Ok(x.to_string().into()); + return Ok(js_string!(x.to_string()).into()); // 3. Else, let radixMV be ? ToIntegerOrInfinity(radix). } else { radix.to_integer_or_infinity(context)? @@ -197,14 +199,14 @@ impl BigInt { // 5. If radixMV = 10, return ! ToString(x). if radix_mv == 10 { - return Ok(x.to_string().into()); + return Ok(js_string!(x.to_string()).into()); } // 1. Let x be ? thisBigIntValue(this value). // 6. Return the String representation of this Number value using the radix specified by radixMV. // Letters a-z are used for digits with values 10 through 35. // The precise algorithm is implementation-defined, however the algorithm should be a generalization of that specified in 6.1.6.2.23. - Ok(JsValue::new(x.to_string_radix(radix_mv as u32))) + Ok(JsValue::new(js_string!(x.to_string_radix(radix_mv as u32)))) } /// `BigInt.prototype.valueOf()` diff --git a/boa_engine/src/builtins/bigint/tests.rs b/boa_engine/src/builtins/bigint/tests.rs index 5c0f1894fe6..8200f2cdef0 100644 --- a/boa_engine/src/builtins/bigint/tests.rs +++ b/boa_engine/src/builtins/bigint/tests.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsBigInt, JsNativeErrorKind, TestAction}; +use crate::{js_string, run_test_actions, JsBigInt, JsNativeErrorKind, TestAction}; #[test] fn equality() { @@ -147,10 +147,10 @@ fn operations() { #[test] fn to_string() { run_test_actions([ - TestAction::assert_eq("1000n.toString()", "1000"), - TestAction::assert_eq("1000n.toString(2)", "1111101000"), - TestAction::assert_eq("255n.toString(16)", "ff"), - TestAction::assert_eq("1000n.toString(36)", "rs"), + TestAction::assert_eq("1000n.toString()", js_string!("1000")), + TestAction::assert_eq("1000n.toString(2)", js_string!("1111101000")), + TestAction::assert_eq("255n.toString(16)", js_string!("ff")), + TestAction::assert_eq("1000n.toString(36)", js_string!("rs")), ]); } diff --git a/boa_engine/src/builtins/boolean/mod.rs b/boa_engine/src/builtins/boolean/mod.rs index 91f8186f566..fcae01bb373 100644 --- a/boa_engine/src/builtins/boolean/mod.rs +++ b/boa_engine/src/builtins/boolean/mod.rs @@ -16,9 +16,11 @@ use crate::{ builtins::BuiltInObject, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, realm::Realm, - Context, JsResult, JsValue, + string::common::StaticJsStrings, + Context, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -30,11 +32,11 @@ pub(crate) struct Boolean; impl IntrinsicObject for Boolean { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) - .method(Self::to_string, "toString", 0) - .method(Self::value_of, "valueOf", 0) + .method(Self::to_string, js_string!("toString"), 0) + .method(Self::value_of, js_string!("valueOf"), 0) .build(); } @@ -44,7 +46,7 @@ impl IntrinsicObject for Boolean { } impl BuiltInObject for Boolean { - const NAME: &'static str = "Boolean"; + const NAME: JsString = StaticJsStrings::BOOLEAN; } impl BuiltInConstructor for Boolean { @@ -111,7 +113,7 @@ impl Boolean { _: &mut Context<'_>, ) -> JsResult { let boolean = Self::this_boolean_value(this)?; - Ok(JsValue::new(boolean.to_string())) + Ok(JsValue::new(js_string!(boolean.to_string()))) } /// The valueOf() method returns the primitive value of a `Boolean` object. diff --git a/boa_engine/src/builtins/dataview/mod.rs b/boa_engine/src/builtins/dataview/mod.rs index 56ba390303b..ef9a2653bfb 100644 --- a/boa_engine/src/builtins/dataview/mod.rs +++ b/boa_engine/src/builtins/dataview/mod.rs @@ -11,13 +11,14 @@ use crate::{ builtins::{array_buffer::SharedMemoryOrder, typed_array::TypedArrayKind, BuiltInObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::common::StaticJsStrings, symbol::JsSymbol, value::JsValue, - Context, JsArgs, JsResult, + Context, JsArgs, JsResult, JsString, }; use boa_gc::{Finalize, Trace}; @@ -36,51 +37,56 @@ impl IntrinsicObject for DataView { let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE; let get_buffer = BuiltInBuilder::callable(realm, Self::get_buffer) - .name("get buffer") + .name(js_string!("get buffer")) .build(); let get_byte_length = BuiltInBuilder::callable(realm, Self::get_byte_length) - .name("get byteLength") + .name(js_string!("get byteLength")) .build(); let get_byte_offset = BuiltInBuilder::callable(realm, Self::get_byte_offset) - .name("get byteOffset") + .name(js_string!("get byteOffset")) .build(); BuiltInBuilder::from_standard_constructor::(realm) - .accessor(utf16!("buffer"), Some(get_buffer), None, flag_attributes) .accessor( - utf16!("byteLength"), + js_string!("buffer"), + Some(get_buffer), + None, + flag_attributes, + ) + .accessor( + js_string!("byteLength"), Some(get_byte_length), None, flag_attributes, ) .accessor( - utf16!("byteOffset"), + js_string!("byteOffset"), Some(get_byte_offset), None, flag_attributes, ) - .method(Self::get_big_int64, "getBigInt64", 1) - .method(Self::get_big_uint64, "getBigUint64", 1) - .method(Self::get_float32, "getFloat32", 1) - .method(Self::get_float64, "getFloat64", 1) - .method(Self::get_int8, "getInt8", 1) - .method(Self::get_int16, "getInt16", 1) - .method(Self::get_int32, "getInt32", 1) - .method(Self::get_uint8, "getUint8", 1) - .method(Self::get_uint16, "getUint16", 1) - .method(Self::get_uint32, "getUint32", 1) - .method(Self::set_big_int64, "setBigInt64", 2) - .method(Self::set_big_uint64, "setBigUint64", 2) - .method(Self::set_float32, "setFloat32", 2) - .method(Self::set_float64, "setFloat64", 2) - .method(Self::set_int8, "setInt8", 2) - .method(Self::set_int16, "setInt16", 2) - .method(Self::set_int32, "setInt32", 2) - .method(Self::set_uint8, "setUint8", 2) - .method(Self::set_uint16, "setUint16", 2) - .method(Self::set_uint32, "setUint32", 2) + .method(Self::get_big_int64, js_string!("getBigInt64"), 1) + .method(Self::get_big_uint64, js_string!("getBigUint64"), 1) + .method(Self::get_float32, js_string!("getFloat32"), 1) + .method(Self::get_float64, js_string!("getFloat64"), 1) + .method(Self::get_int8, js_string!("getInt8"), 1) + .method(Self::get_int16, js_string!("getInt16"), 1) + .method(Self::get_int32, js_string!("getInt32"), 1) + .method(Self::get_uint8, js_string!("getUint8"), 1) + .method(Self::get_uint16, js_string!("getUint16"), 1) + .method(Self::get_uint32, js_string!("getUint32"), 1) + .method(Self::set_big_int64, js_string!("setBigInt64"), 2) + .method(Self::set_big_uint64, js_string!("setBigUint64"), 2) + .method(Self::set_float32, js_string!("setFloat32"), 2) + .method(Self::set_float64, js_string!("setFloat64"), 2) + .method(Self::set_int8, js_string!("setInt8"), 2) + .method(Self::set_int16, js_string!("setInt16"), 2) + .method(Self::set_int32, js_string!("setInt32"), 2) + .method(Self::set_uint8, js_string!("setUint8"), 2) + .method(Self::set_uint16, js_string!("setUint16"), 2) + .method(Self::set_uint32, js_string!("setUint32"), 2) .property( JsSymbol::to_string_tag(), Self::NAME, @@ -95,7 +101,7 @@ impl IntrinsicObject for DataView { } impl BuiltInObject for DataView { - const NAME: &'static str = "DataView"; + const NAME: JsString = StaticJsStrings::DATA_VIEW; } impl BuiltInConstructor for DataView { diff --git a/boa_engine/src/builtins/date/mod.rs b/boa_engine/src/builtins/date/mod.rs index 8e2cc363699..7c481443e6e 100644 --- a/boa_engine/src/builtins/date/mod.rs +++ b/boa_engine/src/builtins/date/mod.rs @@ -24,10 +24,10 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, value::{IntegerOrNan, JsValue, PreferredType}, - Context, JsArgs, JsError, JsResult, + Context, JsArgs, JsError, JsResult, JsString, }; use boa_profiler::Profiler; use chrono::prelude::*; @@ -94,73 +94,109 @@ impl Date { impl IntrinsicObject for Date { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let to_utc_string = BuiltInBuilder::callable(realm, Self::to_utc_string) - .name("toUTCString") + .name(js_string!("toUTCString")) .length(0) .build(); let to_primitive = BuiltInBuilder::callable(realm, Self::to_primitive) - .name("[Symbol.toPrimitive]") + .name(js_string!("[Symbol.toPrimitive]")) .length(1) .build(); BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::now, "now", 0) - .static_method(Self::parse, "parse", 1) - .static_method(Self::utc, "UTC", 7) - .method(Self::get_date::, "getDate", 0) - .method(Self::get_day::, "getDay", 0) - .method(Self::get_full_year::, "getFullYear", 0) - .method(Self::get_hours::, "getHours", 0) - .method(Self::get_milliseconds::, "getMilliseconds", 0) - .method(Self::get_minutes::, "getMinutes", 0) - .method(Self::get_month::, "getMonth", 0) - .method(Self::get_seconds::, "getSeconds", 0) - .method(Self::get_time, "getTime", 0) - .method(Self::get_timezone_offset, "getTimezoneOffset", 0) - .method(Self::get_date::, "getUTCDate", 0) - .method(Self::get_day::, "getUTCDay", 0) - .method(Self::get_full_year::, "getUTCFullYear", 0) - .method(Self::get_hours::, "getUTCHours", 0) - .method(Self::get_milliseconds::, "getUTCMilliseconds", 0) - .method(Self::get_minutes::, "getUTCMinutes", 0) - .method(Self::get_month::, "getUTCMonth", 0) - .method(Self::get_seconds::, "getUTCSeconds", 0) - .method(Self::get_year, "getYear", 0) - .method(Self::set_date::, "setDate", 1) - .method(Self::set_full_year::, "setFullYear", 3) - .method(Self::set_hours::, "setHours", 4) - .method(Self::set_milliseconds::, "setMilliseconds", 1) - .method(Self::set_minutes::, "setMinutes", 3) - .method(Self::set_month::, "setMonth", 2) - .method(Self::set_seconds::, "setSeconds", 2) - .method(Self::set_time, "setTime", 1) - .method(Self::set_date::, "setUTCDate", 1) - .method(Self::set_full_year::, "setUTCFullYear", 3) - .method(Self::set_hours::, "setUTCHours", 4) - .method(Self::set_milliseconds::, "setUTCMilliseconds", 1) - .method(Self::set_minutes::, "setUTCMinutes", 3) - .method(Self::set_month::, "setUTCMonth", 2) - .method(Self::set_seconds::, "setUTCSeconds", 2) - .method(Self::set_year, "setYear", 1) - .method(Self::to_date_string, "toDateString", 0) - .method(Self::to_iso_string, "toISOString", 0) - .method(Self::to_json, "toJSON", 1) - .method(Self::to_locale_date_string, "toLocaleDateString", 0) - .method(Self::to_locale_string, "toLocaleString", 0) - .method(Self::to_locale_time_string, "toLocaleTimeString", 0) - .method(Self::to_string, "toString", 0) - .method(Self::to_time_string, "toTimeString", 0) - .method(Self::value_of, "valueOf", 0) + .static_method(Self::now, js_string!("now"), 0) + .static_method(Self::parse, js_string!("parse"), 1) + .static_method(Self::utc, js_string!("UTC"), 7) + .method(Self::get_date::, js_string!("getDate"), 0) + .method(Self::get_day::, js_string!("getDay"), 0) + .method(Self::get_full_year::, js_string!("getFullYear"), 0) + .method(Self::get_hours::, js_string!("getHours"), 0) + .method( + Self::get_milliseconds::, + js_string!("getMilliseconds"), + 0, + ) + .method(Self::get_minutes::, js_string!("getMinutes"), 0) + .method(Self::get_month::, js_string!("getMonth"), 0) + .method(Self::get_seconds::, js_string!("getSeconds"), 0) + .method(Self::get_time, js_string!("getTime"), 0) + .method( + Self::get_timezone_offset, + js_string!("getTimezoneOffset"), + 0, + ) + .method(Self::get_date::, js_string!("getUTCDate"), 0) + .method(Self::get_day::, js_string!("getUTCDay"), 0) + .method( + Self::get_full_year::, + js_string!("getUTCFullYear"), + 0, + ) + .method(Self::get_hours::, js_string!("getUTCHours"), 0) + .method( + Self::get_milliseconds::, + js_string!("getUTCMilliseconds"), + 0, + ) + .method(Self::get_minutes::, js_string!("getUTCMinutes"), 0) + .method(Self::get_month::, js_string!("getUTCMonth"), 0) + .method(Self::get_seconds::, js_string!("getUTCSeconds"), 0) + .method(Self::get_year, js_string!("getYear"), 0) + .method(Self::set_date::, js_string!("setDate"), 1) + .method(Self::set_full_year::, js_string!("setFullYear"), 3) + .method(Self::set_hours::, js_string!("setHours"), 4) + .method( + Self::set_milliseconds::, + js_string!("setMilliseconds"), + 1, + ) + .method(Self::set_minutes::, js_string!("setMinutes"), 3) + .method(Self::set_month::, js_string!("setMonth"), 2) + .method(Self::set_seconds::, js_string!("setSeconds"), 2) + .method(Self::set_time, js_string!("setTime"), 1) + .method(Self::set_date::, js_string!("setUTCDate"), 1) + .method( + Self::set_full_year::, + js_string!("setUTCFullYear"), + 3, + ) + .method(Self::set_hours::, js_string!("setUTCHours"), 4) + .method( + Self::set_milliseconds::, + js_string!("setUTCMilliseconds"), + 1, + ) + .method(Self::set_minutes::, js_string!("setUTCMinutes"), 3) + .method(Self::set_month::, js_string!("setUTCMonth"), 2) + .method(Self::set_seconds::, js_string!("setUTCSeconds"), 2) + .method(Self::set_year, js_string!("setYear"), 1) + .method(Self::to_date_string, js_string!("toDateString"), 0) + .method(Self::to_iso_string, js_string!("toISOString"), 0) + .method(Self::to_json, js_string!("toJSON"), 1) + .method( + Self::to_locale_date_string, + js_string!("toLocaleDateString"), + 0, + ) + .method(Self::to_locale_string, js_string!("toLocaleString"), 0) + .method( + Self::to_locale_time_string, + js_string!("toLocaleTimeString"), + 0, + ) + .method(Self::to_string, js_string!("toString"), 0) + .method(Self::to_time_string, js_string!("toTimeString"), 0) + .method(Self::value_of, js_string!("valueOf"), 0) .property( - "toGMTString", + js_string!("toGMTString"), to_utc_string.clone(), Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "toUTCString", + js_string!("toUTCString"), to_utc_string, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) @@ -178,7 +214,7 @@ impl IntrinsicObject for Date { } impl BuiltInObject for Date { - const NAME: &'static str = "Date"; + const NAME: JsString = StaticJsStrings::DATE; } impl BuiltInConstructor for Date { @@ -205,13 +241,11 @@ impl BuiltInConstructor for Date { if new_target.is_undefined() { // a. Let now be the time value (UTC) identifying the current time. // b. Return ToDateString(now). - return Ok(JsValue::new( - context - .host_hooks() - .local_from_utc(context.host_hooks().utc_now()) - .format("%a %b %d %Y %H:%M:%S GMT%:z") - .to_string(), - )); + return Ok(JsValue::new(js_string!(context + .host_hooks() + .local_from_utc(context.host_hooks().utc_now()) + .format("%a %b %d %Y %H:%M:%S GMT%:z") + .to_string()))); } // 2. Let numberOfArgs be the number of elements in values. let dv = match args { @@ -1253,12 +1287,12 @@ impl Date { // 4. Let t be LocalTime(tv). // 5. Return DateString(t). - Ok(context + Ok(js_string!(context .host_hooks() .local_from_utc(tv) .format("%a %b %d %Y") - .to_string() - .into()) + .to_string()) + .into()) } /// [`Date.prototype.toISOString()`][spec]. @@ -1280,11 +1314,11 @@ impl Date { let t = this_time_value(this)? .and_then(NaiveDateTime::from_timestamp_millis) .ok_or_else(|| JsNativeError::range().with_message("Invalid time value"))?; - Ok(Utc + Ok(js_string!(Utc .from_utc_datetime(&t) .format("%Y-%m-%dT%H:%M:%S.%3fZ") - .to_string() - .into()) + .to_string()) + .into()) } /// [`Date.prototype.toJSON()`][spec]. @@ -1334,7 +1368,9 @@ impl Date { _args: &[JsValue], _context: &mut Context<'_>, ) -> JsResult { - Err(JsError::from_opaque(JsValue::new("Function Unimplemented"))) + Err(JsError::from_opaque(JsValue::new(js_string!( + "Function Unimplemented" + )))) } /// [`Date.prototype.toLocaleString()`][spec]. @@ -1351,9 +1387,9 @@ impl Date { _: &[JsValue], _context: &mut Context<'_>, ) -> JsResult { - Err(JsError::from_opaque(JsValue::new( - "Function Unimplemented]", - ))) + Err(JsError::from_opaque(JsValue::new(js_string!( + "Function Unimplemented]" + )))) } /// [`Date.prototype.toLocaleTimeString()`][spec]. @@ -1371,9 +1407,9 @@ impl Date { _args: &[JsValue], _context: &mut Context<'_>, ) -> JsResult { - Err(JsError::from_opaque(JsValue::new( - "Function Unimplemented]", - ))) + Err(JsError::from_opaque(JsValue::new(js_string!( + "Function Unimplemented]" + )))) } /// [`Date.prototype.toString()`][spec]. @@ -1395,12 +1431,12 @@ impl Date { let Some(tv) = this_time_value(this)?.and_then(NaiveDateTime::from_timestamp_millis) else { return Ok(js_string!("Invalid Date").into()); }; - Ok(context + Ok(js_string!(context .host_hooks() .local_from_utc(tv) .format("%a %b %d %Y %H:%M:%S GMT%z") - .to_string() - .into()) + .to_string()) + .into()) } /// [`Date.prototype.toTimeString()`][spec]. @@ -1427,12 +1463,12 @@ impl Date { // 4. Let t be LocalTime(tv). // 5. Return the string-concatenation of TimeString(t) and TimeZoneString(tv). - Ok(context + Ok(js_string!(context .host_hooks() .local_from_utc(tv) .format("%H:%M:%S GMT%z") - .to_string() - .into()) + .to_string()) + .into()) } /// [`Date.prototype.toUTCString()`][spec]. @@ -1466,7 +1502,7 @@ impl Date { // code unit 0x0020 (SPACE), month, the code unit 0x0020 (SPACE), yearSign, paddedYear, the code // unit 0x0020 (SPACE), and TimeString(tv) let utc_string = t.format("%a, %d %b %Y %H:%M:%S GMT").to_string(); - Ok(JsValue::new(utc_string)) + Ok(JsValue::new(js_string!(utc_string))) } /// [`Date.prototype.valueOf()`][spec]. diff --git a/boa_engine/src/builtins/date/tests.rs b/boa_engine/src/builtins/date/tests.rs index 0743c51dbc9..d6845daf17e 100644 --- a/boa_engine/src/builtins/date/tests.rs +++ b/boa_engine/src/builtins/date/tests.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsNativeErrorKind, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, TestAction}; use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone}; use indoc::indoc; @@ -762,7 +762,7 @@ fn date_proto_set_utc_seconds() { fn date_proto_to_date_string() { run_test_actions([TestAction::assert_eq( "new Date(2020, 6, 8, 9, 16, 15, 779).toDateString()", - "Wed Jul 08 2020", + js_string!("Wed Jul 08 2020"), )]); } @@ -770,7 +770,7 @@ fn date_proto_to_date_string() { fn date_proto_to_gmt_string() { run_test_actions([TestAction::assert_eq( "new Date(Date.UTC(2020, 6, 8, 9, 16, 15, 779)).toGMTString()", - "Wed, 08 Jul 2020 09:16:15 GMT", + js_string!("Wed, 08 Jul 2020 09:16:15 GMT"), )]); } @@ -778,7 +778,7 @@ fn date_proto_to_gmt_string() { fn date_proto_to_iso_string() { run_test_actions([TestAction::assert_eq( "new Date(Date.UTC(2020, 6, 8, 9, 16, 15, 779)).toISOString()", - "2020-07-08T09:16:15.779Z", + js_string!("2020-07-08T09:16:15.779Z"), )]); } @@ -786,7 +786,7 @@ fn date_proto_to_iso_string() { fn date_proto_to_json() { run_test_actions([TestAction::assert_eq( "new Date(Date.UTC(2020, 6, 8, 9, 16, 15, 779)).toJSON()", - "2020-07-08T09:16:15.779Z", + js_string!("2020-07-08T09:16:15.779Z"), )]); } @@ -794,7 +794,7 @@ fn date_proto_to_json() { fn date_proto_to_string() { run_test_actions([TestAction::assert_eq( "new Date(2020, 6, 8, 9, 16, 15, 779).toString()", - Local + js_string!(Local .from_local_datetime(&NaiveDateTime::new( NaiveDate::from_ymd_opt(2020, 7, 8).unwrap(), NaiveTime::from_hms_milli_opt(9, 16, 15, 779).unwrap(), @@ -802,7 +802,7 @@ fn date_proto_to_string() { .earliest() .unwrap() .format("Wed Jul 08 2020 09:16:15 GMT%z") - .to_string(), + .to_string()), )]); } @@ -810,7 +810,7 @@ fn date_proto_to_string() { fn date_proto_to_time_string() { run_test_actions([TestAction::assert_eq( "new Date(2020, 6, 8, 9, 16, 15, 779).toTimeString()", - Local + js_string!(Local .from_local_datetime(&NaiveDateTime::new( NaiveDate::from_ymd_opt(2020, 7, 8).unwrap(), NaiveTime::from_hms_milli_opt(9, 16, 15, 779).unwrap(), @@ -818,7 +818,7 @@ fn date_proto_to_time_string() { .earliest() .unwrap() .format("09:16:15 GMT%z") - .to_string(), + .to_string()), )]); } @@ -826,7 +826,7 @@ fn date_proto_to_time_string() { fn date_proto_to_utc_string() { run_test_actions([TestAction::assert_eq( "new Date(Date.UTC(2020, 6, 8, 9, 16, 15, 779)).toUTCString()", - "Wed, 08 Jul 2020 09:16:15 GMT", + js_string!("Wed, 08 Jul 2020 09:16:15 GMT"), )]); } @@ -850,6 +850,6 @@ fn date_neg() { fn date_json() { run_test_actions([TestAction::assert_eq( "JSON.stringify({ date: new Date(Date.UTC(2020, 6, 8, 9, 16, 15, 779)) })", - r#"{"date":"2020-07-08T09:16:15.779Z"}"#, + js_string!(r#"{"date":"2020-07-08T09:16:15.779Z"}"#), )]); } diff --git a/boa_engine/src/builtins/error/aggregate.rs b/boa_engine/src/builtins/error/aggregate.rs index 7ee61332a20..8daf6862246 100644 --- a/boa_engine/src/builtins/error/aggregate.rs +++ b/boa_engine/src/builtins/error/aggregate.rs @@ -13,11 +13,12 @@ use crate::{ IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::{Attribute, PropertyDescriptorBuilder}, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -28,14 +29,14 @@ pub(crate) struct AggregateError; impl IntrinsicObject for AggregateError { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) + .property(utf16!("message"), js_string!(), attribute) .build(); } @@ -45,7 +46,7 @@ impl IntrinsicObject for AggregateError { } impl BuiltInObject for AggregateError { - const NAME: &'static str = "AggregateError"; + const NAME: JsString = StaticJsStrings::AGGREGATE_ERROR; } impl BuiltInConstructor for AggregateError { diff --git a/boa_engine/src/builtins/error/eval.rs b/boa_engine/src/builtins/error/eval.rs index 13cc33bb43e..fe8d417a84c 100644 --- a/boa_engine/src/builtins/error/eval.rs +++ b/boa_engine/src/builtins/error/eval.rs @@ -14,11 +14,12 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -30,14 +31,14 @@ pub(crate) struct EvalError; impl IntrinsicObject for EvalError { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) + .property(utf16!("message"), js_string!(), attribute) .build(); } @@ -47,7 +48,7 @@ impl IntrinsicObject for EvalError { } impl BuiltInObject for EvalError { - const NAME: &'static str = "EvalError"; + const NAME: JsString = StaticJsStrings::EVAL_ERROR; } impl BuiltInConstructor for EvalError { diff --git a/boa_engine/src/builtins/error/mod.rs b/boa_engine/src/builtins/error/mod.rs index 091a8b8abbc..e28c4d6fbfc 100644 --- a/boa_engine/src/builtins/error/mod.rs +++ b/boa_engine/src/builtins/error/mod.rs @@ -18,8 +18,8 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -129,13 +129,13 @@ pub(crate) struct Error; impl IntrinsicObject for Error { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) - .method(Self::to_string, "toString", 0) + .property(utf16!("message"), js_string!(), attribute) + .method(Self::to_string, js_string!("toString"), 0) .build(); } @@ -145,7 +145,7 @@ impl IntrinsicObject for Error { } impl BuiltInObject for Error { - const NAME: &'static str = "Error"; + const NAME: JsString = StaticJsStrings::ERROR; } impl BuiltInConstructor for Error { diff --git a/boa_engine/src/builtins/error/range.rs b/boa_engine/src/builtins/error/range.rs index 04bfdf18d74..972392d0a2c 100644 --- a/boa_engine/src/builtins/error/range.rs +++ b/boa_engine/src/builtins/error/range.rs @@ -12,11 +12,12 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -28,14 +29,14 @@ pub(crate) struct RangeError; impl IntrinsicObject for RangeError { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) + .property(utf16!("message"), js_string!(), attribute) .build(); } @@ -45,7 +46,7 @@ impl IntrinsicObject for RangeError { } impl BuiltInObject for RangeError { - const NAME: &'static str = "RangeError"; + const NAME: JsString = StaticJsStrings::RANGE_ERROR; } impl BuiltInConstructor for RangeError { diff --git a/boa_engine/src/builtins/error/reference.rs b/boa_engine/src/builtins/error/reference.rs index f11a7de1b5b..4ddd5abd7d8 100644 --- a/boa_engine/src/builtins/error/reference.rs +++ b/boa_engine/src/builtins/error/reference.rs @@ -12,11 +12,12 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -27,14 +28,14 @@ pub(crate) struct ReferenceError; impl IntrinsicObject for ReferenceError { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -44,7 +45,7 @@ impl IntrinsicObject for ReferenceError { } impl BuiltInObject for ReferenceError { - const NAME: &'static str = "ReferenceError"; + const NAME: JsString = StaticJsStrings::REFERENCE_ERROR; } impl BuiltInConstructor for ReferenceError { diff --git a/boa_engine/src/builtins/error/syntax.rs b/boa_engine/src/builtins/error/syntax.rs index 7661a155422..91b9f1a6380 100644 --- a/boa_engine/src/builtins/error/syntax.rs +++ b/boa_engine/src/builtins/error/syntax.rs @@ -14,11 +14,12 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -30,14 +31,14 @@ pub(crate) struct SyntaxError; impl IntrinsicObject for SyntaxError { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) + .property(utf16!("message"), js_string!(), attribute) .build(); } @@ -47,7 +48,7 @@ impl IntrinsicObject for SyntaxError { } impl BuiltInObject for SyntaxError { - const NAME: &'static str = "SyntaxError"; + const NAME: JsString = StaticJsStrings::SYNTAX_ERROR; } impl BuiltInConstructor for SyntaxError { diff --git a/boa_engine/src/builtins/error/tests.rs b/boa_engine/src/builtins/error/tests.rs index b1e0e6347d1..ea3950b3041 100644 --- a/boa_engine/src/builtins/error/tests.rs +++ b/boa_engine/src/builtins/error/tests.rs @@ -1,24 +1,42 @@ -use crate::{run_test_actions, TestAction}; +use crate::{js_string, run_test_actions, TestAction}; use indoc::indoc; #[test] fn error_to_string() { run_test_actions([ - TestAction::assert_eq("(new Error('1')).toString()", "Error: 1"), - TestAction::assert_eq("(new RangeError('2')).toString()", "RangeError: 2"), - TestAction::assert_eq("(new ReferenceError('3')).toString()", "ReferenceError: 3"), - TestAction::assert_eq("(new SyntaxError('4')).toString()", "SyntaxError: 4"), - TestAction::assert_eq("(new TypeError('5')).toString()", "TypeError: 5"), - TestAction::assert_eq("(new EvalError('6')).toString()", "EvalError: 6"), - TestAction::assert_eq("(new URIError('7')).toString()", "URIError: 7"), + TestAction::assert_eq("(new Error('1')).toString()", js_string!("Error: 1")), + TestAction::assert_eq( + "(new RangeError('2')).toString()", + js_string!("RangeError: 2"), + ), + TestAction::assert_eq( + "(new ReferenceError('3')).toString()", + js_string!("ReferenceError: 3"), + ), + TestAction::assert_eq( + "(new SyntaxError('4')).toString()", + js_string!("SyntaxError: 4"), + ), + TestAction::assert_eq( + "(new TypeError('5')).toString()", + js_string!("TypeError: 5"), + ), + TestAction::assert_eq( + "(new EvalError('6')).toString()", + js_string!("EvalError: 6"), + ), + TestAction::assert_eq("(new URIError('7')).toString()", js_string!("URIError: 7")), // no message - TestAction::assert_eq("(new Error()).toString()", "Error"), - TestAction::assert_eq("(new RangeError()).toString()", "RangeError"), - TestAction::assert_eq("(new ReferenceError()).toString()", "ReferenceError"), - TestAction::assert_eq("(new SyntaxError()).toString()", "SyntaxError"), - TestAction::assert_eq("(new TypeError()).toString()", "TypeError"), - TestAction::assert_eq("(new EvalError()).toString()", "EvalError"), - TestAction::assert_eq("(new URIError()).toString()", "URIError"), + TestAction::assert_eq("(new Error()).toString()", js_string!("Error")), + TestAction::assert_eq("(new RangeError()).toString()", js_string!("RangeError")), + TestAction::assert_eq( + "(new ReferenceError()).toString()", + js_string!("ReferenceError"), + ), + TestAction::assert_eq("(new SyntaxError()).toString()", js_string!("SyntaxError")), + TestAction::assert_eq("(new TypeError()).toString()", js_string!("TypeError")), + TestAction::assert_eq("(new EvalError()).toString()", js_string!("EvalError")), + TestAction::assert_eq("(new URIError()).toString()", js_string!("URIError")), // no name TestAction::assert_eq( indoc! {r#" @@ -26,7 +44,7 @@ fn error_to_string() { message.name = ''; message.toString() "#}, - "message", + js_string!("message"), ), ]); } @@ -34,14 +52,14 @@ fn error_to_string() { #[test] fn error_names() { run_test_actions([ - TestAction::assert_eq("Error.name", "Error"), - TestAction::assert_eq("EvalError.name", "EvalError"), - TestAction::assert_eq("RangeError.name", "RangeError"), - TestAction::assert_eq("ReferenceError.name", "ReferenceError"), - TestAction::assert_eq("SyntaxError.name", "SyntaxError"), - TestAction::assert_eq("URIError.name", "URIError"), - TestAction::assert_eq("TypeError.name", "TypeError"), - TestAction::assert_eq("AggregateError.name", "AggregateError"), + TestAction::assert_eq("Error.name", js_string!("Error")), + TestAction::assert_eq("EvalError.name", js_string!("EvalError")), + TestAction::assert_eq("RangeError.name", js_string!("RangeError")), + TestAction::assert_eq("ReferenceError.name", js_string!("ReferenceError")), + TestAction::assert_eq("SyntaxError.name", js_string!("SyntaxError")), + TestAction::assert_eq("URIError.name", js_string!("URIError")), + TestAction::assert_eq("TypeError.name", js_string!("TypeError")), + TestAction::assert_eq("AggregateError.name", js_string!("AggregateError")), ]); } diff --git a/boa_engine/src/builtins/error/type.rs b/boa_engine/src/builtins/error/type.rs index 5466c5ca534..550949501ef 100644 --- a/boa_engine/src/builtins/error/type.rs +++ b/boa_engine/src/builtins/error/type.rs @@ -22,11 +22,12 @@ use crate::{ }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData, ObjectKind}, property::Attribute, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, NativeFunction, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, NativeFunction, }; use boa_profiler::Profiler; @@ -38,14 +39,14 @@ pub(crate) struct TypeError; impl IntrinsicObject for TypeError { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) + .property(utf16!("message"), js_string!(), attribute) .build(); } @@ -55,7 +56,7 @@ impl IntrinsicObject for TypeError { } impl BuiltInObject for TypeError { - const NAME: &'static str = "TypeError"; + const NAME: JsString = StaticJsStrings::TYPE_ERROR; } impl BuiltInConstructor for TypeError { @@ -129,7 +130,7 @@ impl IntrinsicObject for ThrowTypeError { let obj = BuiltInBuilder::with_intrinsic::(realm) .prototype(realm.intrinsics().constructors().function().prototype()) .static_property(utf16!("length"), 0, Attribute::empty()) - .static_property(utf16!("name"), "", Attribute::empty()) + .static_property(utf16!("name"), js_string!(), Attribute::empty()) .build(); let mut obj = obj.borrow_mut(); diff --git a/boa_engine/src/builtins/error/uri.rs b/boa_engine/src/builtins/error/uri.rs index 0d96ce8d331..df27792f0d6 100644 --- a/boa_engine/src/builtins/error/uri.rs +++ b/boa_engine/src/builtins/error/uri.rs @@ -13,11 +13,12 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -29,14 +30,14 @@ pub(crate) struct UriError; impl IntrinsicObject for UriError { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) .property(utf16!("name"), Self::NAME, attribute) - .property(utf16!("message"), "", attribute) + .property(utf16!("message"), js_string!(), attribute) .build(); } @@ -46,7 +47,7 @@ impl IntrinsicObject for UriError { } impl BuiltInObject for UriError { - const NAME: &'static str = "URIError"; + const NAME: JsString = StaticJsStrings::URI_ERROR; } impl BuiltInConstructor for UriError { diff --git a/boa_engine/src/builtins/escape/mod.rs b/boa_engine/src/builtins/escape/mod.rs index fc376d1ccae..ea2c07f7bf5 100644 --- a/boa_engine/src/builtins/escape/mod.rs +++ b/boa_engine/src/builtins/escape/mod.rs @@ -11,8 +11,8 @@ //! [spec]: https://tc39.es/ecma262/#sec-additional-properties-of-the-global-object use crate::{ - context::intrinsics::Intrinsics, js_string, realm::Realm, Context, JsArgs, JsObject, JsResult, - JsValue, + context::intrinsics::Intrinsics, js_string, realm::Realm, string::common::StaticJsStrings, + Context, JsArgs, JsObject, JsResult, JsString, JsValue, }; use super::{BuiltInBuilder, BuiltInObject, IntrinsicObject}; @@ -34,7 +34,7 @@ impl IntrinsicObject for Escape { } impl BuiltInObject for Escape { - const NAME: &'static str = "escape"; + const NAME: JsString = StaticJsStrings::ESCAPE; } /// Builtin JavaScript `escape ( string )` function. @@ -106,7 +106,7 @@ impl IntrinsicObject for Unescape { } impl BuiltInObject for Unescape { - const NAME: &'static str = "unescape"; + const NAME: JsString = StaticJsStrings::UNESCAPE; } /// Builtin JavaScript `unescape ( string )` function. diff --git a/boa_engine/src/builtins/eval/mod.rs b/boa_engine/src/builtins/eval/mod.rs index b2793322c9e..1eca3e654a0 100644 --- a/boa_engine/src/builtins/eval/mod.rs +++ b/boa_engine/src/builtins/eval/mod.rs @@ -17,6 +17,7 @@ use crate::{ error::JsNativeError, object::JsObject, realm::Realm, + string::common::StaticJsStrings, vm::{CallFrame, Opcode}, Context, JsArgs, JsResult, JsString, JsValue, }; @@ -33,7 +34,7 @@ pub(crate) struct Eval; impl IntrinsicObject for Eval { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::callable_with_intrinsic::(realm, Self::eval) .name(Self::NAME) @@ -47,7 +48,7 @@ impl IntrinsicObject for Eval { } impl BuiltInObject for Eval { - const NAME: &'static str = "eval"; + const NAME: JsString = StaticJsStrings::EVAL; } impl Eval { diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index ffe64b21531..9574320945f 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -23,7 +23,7 @@ use crate::{ object::{JsFunction, PrivateElement, PrivateName}, property::{Attribute, PropertyDescriptor, PropertyKey}, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, value::IntegerOrInfinity, vm::{ActiveRunnable, CodeBlock}, @@ -461,20 +461,20 @@ pub struct BuiltInFunctionObject; impl IntrinsicObject for BuiltInFunctionObject { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("function", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let has_instance = BuiltInBuilder::callable(realm, Self::has_instance) - .name("[Symbol.hasInstance]") + .name(js_string!("[Symbol.hasInstance]")) .length(1) .build(); let throw_type_error = realm.intrinsics().objects().throw_type_error(); BuiltInBuilder::from_standard_constructor::(realm) - .method(Self::apply, "apply", 2) - .method(Self::bind, "bind", 1) - .method(Self::call, "call", 1) - .method(Self::to_string, "toString", 0) + .method(Self::apply, js_string!("apply"), 2) + .method(Self::bind, js_string!("bind"), 1) + .method(Self::call, js_string!("call"), 1) + .method(Self::to_string, js_string!("toString"), 0) .property(JsSymbol::has_instance(), has_instance, Attribute::default()) .accessor( utf16!("caller"), @@ -493,7 +493,7 @@ impl IntrinsicObject for BuiltInFunctionObject { let prototype = realm.intrinsics().constructors().function().prototype(); BuiltInBuilder::callable_with_object(realm, prototype.clone(), Self::prototype) - .name("") + .name(js_string!()) .length(0) .build(); @@ -506,7 +506,7 @@ impl IntrinsicObject for BuiltInFunctionObject { } impl BuiltInObject for BuiltInFunctionObject { - const NAME: &'static str = "Function"; + const NAME: JsString = StaticJsStrings::FUNCTION; } impl BuiltInConstructor for BuiltInFunctionObject { diff --git a/boa_engine/src/builtins/function/tests.rs b/boa_engine/src/builtins/function/tests.rs index 565e4af2970..7a4cf494fed 100644 --- a/boa_engine/src/builtins/function/tests.rs +++ b/boa_engine/src/builtins/function/tests.rs @@ -50,7 +50,7 @@ fn self_mutating_function_when_constructing() { #[test] fn function_prototype() { run_test_actions([ - TestAction::assert_eq("Function.prototype.name", ""), + TestAction::assert_eq("Function.prototype.name", js_string!()), TestAction::assert_eq("Function.prototype.length", 0), TestAction::assert_eq("Function.prototype()", JsValue::undefined()), TestAction::assert_eq( @@ -69,7 +69,7 @@ fn function_prototype() { fn function_prototype_call() { run_test_actions([TestAction::assert_eq( "Object.prototype.toString.call(new Error())", - "[object Error]", + js_string!("[object Error]"), )]); } @@ -134,9 +134,9 @@ fn closure_capture_clone() { let object = JsObject::with_object_proto(ctx.intrinsics()); object .define_property_or_throw( - "key", + js_string!("key"), PropertyDescriptor::builder() - .value(" world!") + .value(js_string!(" world!")) .writable(false) .enumerable(false) .configurable(false), @@ -153,7 +153,7 @@ fn closure_capture_clone() { let hw = js_string!( string, &object - .__get_own_property__(&"key".into(), context)? + .__get_own_property__(&js_string!("key").into(), context)? .and_then(|prop| prop.value().cloned()) .and_then(|val| val.as_string().cloned()) .ok_or_else( @@ -168,10 +168,10 @@ fn closure_capture_clone() { .name("closure") .build(); - ctx.register_global_property("closure", func, Attribute::default()) + ctx.register_global_property(js_string!("closure"), func, Attribute::default()) .unwrap(); }), - TestAction::assert_eq("closure()", "Hello world!"), + TestAction::assert_eq("closure()", js_string!("Hello world!")), ]); } diff --git a/boa_engine/src/builtins/generator/mod.rs b/boa_engine/src/builtins/generator/mod.rs index f2e4c9cf7bc..fc063eaab85 100644 --- a/boa_engine/src/builtins/generator/mod.rs +++ b/boa_engine/src/builtins/generator/mod.rs @@ -14,13 +14,15 @@ use crate::{ context::intrinsics::Intrinsics, environments::EnvironmentStack, error::JsNativeError, + js_string, object::{JsObject, CONSTRUCTOR}, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, value::JsValue, vm::{CallFrame, CompletionRecord, GeneratorResumeKind}, - Context, JsArgs, JsError, JsResult, + Context, JsArgs, JsError, JsResult, JsString, }; use boa_gc::{custom_trace, Finalize, Trace}; use boa_profiler::Profiler; @@ -136,7 +138,7 @@ pub struct Generator { impl IntrinsicObject for Generator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -146,9 +148,9 @@ impl IntrinsicObject for Generator { .iterator_prototypes() .iterator(), ) - .static_method(Self::next, "next", 1) - .static_method(Self::r#return, "return", 1) - .static_method(Self::throw, "throw", 1) + .static_method(Self::next, js_string!("next"), 1) + .static_method(Self::r#return, js_string!("return"), 1) + .static_method(Self::throw, js_string!("throw"), 1) .static_property( JsSymbol::to_string_tag(), Self::NAME, @@ -172,7 +174,7 @@ impl IntrinsicObject for Generator { } impl Generator { - const NAME: &'static str = "Generator"; + const NAME: JsString = StaticJsStrings::GENERATOR; /// `Generator.prototype.next ( value )` /// diff --git a/boa_engine/src/builtins/generator_function/mod.rs b/boa_engine/src/builtins/generator_function/mod.rs index f4b0c2a626e..5b7fe93fce1 100644 --- a/boa_engine/src/builtins/generator_function/mod.rs +++ b/boa_engine/src/builtins/generator_function/mod.rs @@ -16,9 +16,10 @@ use crate::{ object::PROTOTYPE, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, value::JsValue, - Context, JsResult, + Context, JsResult, JsString, }; use boa_profiler::Profiler; @@ -30,7 +31,7 @@ pub struct GeneratorFunction; impl IntrinsicObject for GeneratorFunction { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .inherits(Some( @@ -56,7 +57,7 @@ impl IntrinsicObject for GeneratorFunction { } impl BuiltInObject for GeneratorFunction { - const NAME: &'static str = "GeneratorFunction"; + const NAME: JsString = StaticJsStrings::GENERATOR_FUNCTION; } impl BuiltInConstructor for GeneratorFunction { diff --git a/boa_engine/src/builtins/intl/collator/mod.rs b/boa_engine/src/builtins/intl/collator/mod.rs index e292992c0ea..d23b0e99ae0 100644 --- a/boa_engine/src/builtins/intl/collator/mod.rs +++ b/boa_engine/src/builtins/intl/collator/mod.rs @@ -19,6 +19,7 @@ use crate::{ intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, BoaProvider, }, + js_string, native_function::NativeFunction, object::{ internal_methods::get_prototype_from_constructor, FunctionObjectBuilder, JsFunction, @@ -26,9 +27,9 @@ use crate::{ }, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, - Context, JsArgs, JsNativeError, JsResult, JsValue, + Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; use super::{ @@ -149,26 +150,30 @@ impl Service for Collator { impl IntrinsicObject for Collator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let compare = BuiltInBuilder::callable(realm, Self::compare) - .name("get compare") + .name(js_string!("get compare")) .build(); BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::supported_locales_of, "supportedLocalesOf", 1) + .static_method( + Self::supported_locales_of, + js_string!("supportedLocalesOf"), + 1, + ) .property( JsSymbol::to_string_tag(), - "Intl.Collator", + js_string!("Intl.Collator"), Attribute::CONFIGURABLE, ) .accessor( - utf16!("compare"), + js_string!("compare"), Some(compare), None, Attribute::CONFIGURABLE, ) - .method(Self::resolved_options, "resolvedOptions", 0) + .method(Self::resolved_options, js_string!("resolvedOptions"), 0) .build(); } @@ -178,7 +183,7 @@ impl IntrinsicObject for Collator { } impl BuiltInObject for Collator { - const NAME: &'static str = "Collator"; + const NAME: JsString = StaticJsStrings::COLLATOR; } impl BuiltInConstructor for Collator { @@ -510,14 +515,18 @@ impl Collator { // i. Perform ! CreateDataPropertyOrThrow(options, p, v). // 5. Return options. options - .create_data_property_or_throw(utf16!("locale"), collator.locale.to_string(), context) + .create_data_property_or_throw( + utf16!("locale"), + js_string!(collator.locale.to_string()), + context, + ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( utf16!("usage"), match collator.usage { - Usage::Search => "search", - Usage::Sort => "sort", + Usage::Search => js_string!("search"), + Usage::Sort => js_string!("sort"), }, context, ) @@ -526,25 +535,25 @@ impl Collator { .create_data_property_or_throw( utf16!("sensitivity"), match collator.sensitivity { - Sensitivity::Base => "base", - Sensitivity::Accent => "accent", - Sensitivity::Case => "case", - Sensitivity::Variant => "variant", + Sensitivity::Base => js_string!("base"), + Sensitivity::Accent => js_string!("accent"), + Sensitivity::Case => js_string!("case"), + Sensitivity::Variant => js_string!("variant"), }, context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - utf16!("ignorePunctuation"), + js_string!("ignorePunctuation"), collator.ignore_punctuation, context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - utf16!("collation"), - collator.collation.to_string(), + js_string!("collation"), + js_string!(collator.collation.to_string()), context, ) .expect("operation must not fail per the spec"); @@ -554,11 +563,11 @@ impl Collator { if let Some(kf) = collator.case_first { options .create_data_property_or_throw( - utf16!("caseFirst"), + js_string!("caseFirst"), match kf { - CaseFirst::Off => "false", - CaseFirst::LowerFirst => "lower", - CaseFirst::UpperFirst => "upper", + CaseFirst::Off => js_string!("false"), + CaseFirst::LowerFirst => js_string!("lower"), + CaseFirst::UpperFirst => js_string!("upper"), _ => unreachable!(), }, context, diff --git a/boa_engine/src/builtins/intl/date_time_format.rs b/boa_engine/src/builtins/intl/date_time_format.rs index 35394f04654..1cad2c007b0 100644 --- a/boa_engine/src/builtins/intl/date_time_format.rs +++ b/boa_engine/src/builtins/intl/date_time_format.rs @@ -16,7 +16,7 @@ use crate::{ js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, Context, JsResult, JsString, JsValue, }; @@ -64,7 +64,7 @@ pub struct DateTimeFormat { impl IntrinsicObject for DateTimeFormat { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm).build(); } @@ -75,7 +75,7 @@ impl IntrinsicObject for DateTimeFormat { } impl BuiltInObject for DateTimeFormat { - const NAME: &'static str = "DateTimeFormat"; + const NAME: JsString = StaticJsStrings::DATE_TIME_FORMAT; } impl BuiltInConstructor for DateTimeFormat { @@ -272,7 +272,7 @@ pub(crate) fn to_date_time_options( // a. For each property name prop of « "year", "month", "day" », do for property in [utf16!("year"), utf16!("month"), utf16!("day")] { // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). - options.create_data_property_or_throw(property, "numeric", context)?; + options.create_data_property_or_throw(property, js_string!("numeric"), context)?; } } @@ -281,7 +281,7 @@ pub(crate) fn to_date_time_options( // a. For each property name prop of « "hour", "minute", "second" », do for property in [utf16!("hour"), utf16!("minute"), utf16!("second")] { // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). - options.create_data_property_or_throw(property, "numeric", context)?; + options.create_data_property_or_throw(property, js_string!("numeric"), context)?; } } diff --git a/boa_engine/src/builtins/intl/list_format/mod.rs b/boa_engine/src/builtins/intl/list_format/mod.rs index 73394c67850..1041ef67863 100644 --- a/boa_engine/src/builtins/intl/list_format/mod.rs +++ b/boa_engine/src/builtins/intl/list_format/mod.rs @@ -11,10 +11,11 @@ use crate::{ Array, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; @@ -44,18 +45,22 @@ impl Service for ListFormat { impl IntrinsicObject for ListFormat { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::supported_locales_of, "supportedLocalesOf", 1) + .static_method( + Self::supported_locales_of, + js_string!("supportedLocalesOf"), + 1, + ) .property( JsSymbol::to_string_tag(), - "Intl.ListFormat", + js_string!("Intl.ListFormat"), Attribute::CONFIGURABLE, ) - .method(Self::format, "format", 1) - .method(Self::format_to_parts, "formatToParts", 1) - .method(Self::resolved_options, "resolvedOptions", 0) + .method(Self::format, js_string!("format"), 1) + .method(Self::format_to_parts, js_string!("formatToParts"), 1) + .method(Self::resolved_options, js_string!("resolvedOptions"), 0) .build(); } @@ -65,7 +70,7 @@ impl IntrinsicObject for ListFormat { } impl BuiltInObject for ListFormat { - const NAME: &'static str = "ListFormat"; + const NAME: JsString = StaticJsStrings::LIST_FORMAT; } impl BuiltInConstructor for ListFormat { @@ -229,11 +234,12 @@ impl ListFormat { // TODO: support for UTF-16 unpaired surrogates formatting let strings = string_list_from_iterable(args.get_or_undefined(0), context)?; - // 4. Return ! FormatList(lf, stringList). - Ok(lf + let formatted = lf .native - .format_to_string(strings.into_iter().map(|s| s.to_std_string_escaped())) - .into()) + .format_to_string(strings.into_iter().map(|s| s.to_std_string_escaped())); + + // 4. Return ! FormatList(lf, stringList). + Ok(js_string!(formatted).into()) } /// [`Intl.ListFormat.prototype.formatToParts ( list )`][spec]. @@ -375,11 +381,11 @@ impl ListFormat { .create(ObjectData::ordinary(), vec![]); // b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]). - o.create_data_property_or_throw(utf16!("type"), part.typ(), context) + o.create_data_property_or_throw(utf16!("type"), js_string!(part.typ()), context) .expect("operation must not fail per the spec"); // c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]). - o.create_data_property_or_throw(utf16!("value"), part.value(), context) + o.create_data_property_or_throw(utf16!("value"), js_string!(part.value()), context) .expect("operation must not fail per the spec"); // d. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O). @@ -433,26 +439,30 @@ impl ListFormat { // c. Assert: v is not undefined. // d. Perform ! CreateDataPropertyOrThrow(options, p, v). options - .create_data_property_or_throw(utf16!("locale"), lf.locale.to_string(), context) + .create_data_property_or_throw( + utf16!("locale"), + js_string!(lf.locale.to_string()), + context, + ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - utf16!("type"), + js_string!("type"), match lf.typ { - ListFormatType::Conjunction => "conjunction", - ListFormatType::Disjunction => "disjunction", - ListFormatType::Unit => "unit", + ListFormatType::Conjunction => js_string!("conjunction"), + ListFormatType::Disjunction => js_string!("disjunction"), + ListFormatType::Unit => js_string!("unit"), }, context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - utf16!("style"), + js_string!("style"), match lf.style { - ListLength::Wide => "long", - ListLength::Short => "short", - ListLength::Narrow => "narrow", + ListLength::Wide => js_string!("long"), + ListLength::Short => js_string!("short"), + ListLength::Narrow => js_string!("narrow"), _ => unreachable!(), }, context, diff --git a/boa_engine/src/builtins/intl/locale/mod.rs b/boa_engine/src/builtins/intl/locale/mod.rs index dcfea8a6082..a0e683d03ba 100644 --- a/boa_engine/src/builtins/intl/locale/mod.rs +++ b/boa_engine/src/builtins/intl/locale/mod.rs @@ -1,4 +1,8 @@ -use crate::{builtins::options::get_option, realm::Realm, string::utf16}; +use crate::{ + builtins::options::get_option, + realm::Realm, + string::{common::StaticJsStrings, utf16}, +}; use boa_profiler::Profiler; use icu_collator::CaseFirst; use icu_datetime::options::preferences::HourCycle; @@ -33,113 +37,113 @@ pub(crate) struct Locale; impl IntrinsicObject for Locale { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let base_name = BuiltInBuilder::callable(realm, Self::base_name) - .name("get baseName") + .name(js_string!("get baseName")) .build(); let calendar = BuiltInBuilder::callable(realm, Self::calendar) - .name("get calendar") + .name(js_string!("get calendar")) .build(); let case_first = BuiltInBuilder::callable(realm, Self::case_first) - .name("get caseFirst") + .name(js_string!("get caseFirst")) .build(); let collation = BuiltInBuilder::callable(realm, Self::collation) - .name("get collation") + .name(js_string!("get collation")) .build(); let hour_cycle = BuiltInBuilder::callable(realm, Self::hour_cycle) - .name("get hourCycle") + .name(js_string!("get hourCycle")) .build(); let numeric = BuiltInBuilder::callable(realm, Self::numeric) - .name("get numeric") + .name(js_string!("get numeric")) .build(); let numbering_system = BuiltInBuilder::callable(realm, Self::numbering_system) - .name("get numberingSystem") + .name(js_string!("get numberingSystem")) .build(); let language = BuiltInBuilder::callable(realm, Self::language) - .name("get language") + .name(js_string!("get language")) .build(); let script = BuiltInBuilder::callable(realm, Self::script) - .name("get script") + .name(js_string!("get script")) .build(); let region = BuiltInBuilder::callable(realm, Self::region) - .name("get region") + .name(js_string!("get region")) .build(); BuiltInBuilder::from_standard_constructor::(realm) .property( JsSymbol::to_string_tag(), - "Intl.Locale", + js_string!("Intl.Locale"), Attribute::CONFIGURABLE, ) - .method(Self::maximize, "maximize", 0) - .method(Self::minimize, "minimize", 0) - .method(Self::to_string, "toString", 0) + .method(Self::maximize, js_string!("maximize"), 0) + .method(Self::minimize, js_string!("minimize"), 0) + .method(Self::to_string, js_string!("toString"), 0) .accessor( - utf16!("baseName"), + js_string!("baseName"), Some(base_name), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("calendar"), + js_string!("calendar"), Some(calendar), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("caseFirst"), + js_string!("caseFirst"), Some(case_first), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("collation"), + js_string!("collation"), Some(collation), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("hourCycle"), + js_string!("hourCycle"), Some(hour_cycle), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("numeric"), + js_string!("numeric"), Some(numeric), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("numberingSystem"), + js_string!("numberingSystem"), Some(numbering_system), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("language"), + js_string!("language"), Some(language), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("script"), + js_string!("script"), Some(script), None, Attribute::CONFIGURABLE, ) .accessor( - utf16!("region"), + js_string!("region"), Some(region), None, Attribute::CONFIGURABLE, @@ -153,7 +157,7 @@ impl IntrinsicObject for Locale { } impl BuiltInObject for Locale { - const NAME: &'static str = "Locale"; + const NAME: JsString = StaticJsStrings::LOCALE; } impl BuiltInConstructor for Locale { diff --git a/boa_engine/src/builtins/intl/locale/utils.rs b/boa_engine/src/builtins/intl/locale/utils.rs index 2169ee56634..b180af564d9 100644 --- a/boa_engine/src/builtins/intl/locale/utils.rs +++ b/boa_engine/src/builtins/intl/locale/utils.rs @@ -8,6 +8,7 @@ use crate::{ Array, }, context::{icu::Icu, BoaProvider}, + js_string, object::JsObject, string::utf16, Context, JsNativeError, JsResult, JsValue, @@ -563,7 +564,9 @@ where // 5. Return CreateArrayFromList(supportedLocales). Ok(Array::create_array_from_list( - elements.into_iter().map(|loc| loc.to_string().into()), + elements + .into_iter() + .map(|loc| js_string!(loc.to_string()).into()), context, )) } diff --git a/boa_engine/src/builtins/intl/mod.rs b/boa_engine/src/builtins/intl/mod.rs index 4cf5f9e624e..9592b6914a9 100644 --- a/boa_engine/src/builtins/intl/mod.rs +++ b/boa_engine/src/builtins/intl/mod.rs @@ -16,11 +16,13 @@ use crate::{ builtins::{Array, BuiltInBuilder, BuiltInObject, IntrinsicObject}, context::{intrinsics::Intrinsics, BoaProvider}, + js_string, object::JsObject, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, - Context, JsArgs, JsResult, JsValue, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -47,7 +49,7 @@ pub(crate) struct Intl; impl IntrinsicObject for Intl { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .static_property( @@ -97,7 +99,11 @@ impl IntrinsicObject for Intl { .constructor(), DateTimeFormat::ATTRIBUTE, ) - .static_method(Self::get_canonical_locales, "getCanonicalLocales", 1) + .static_method( + Self::get_canonical_locales, + js_string!("getCanonicalLocales"), + 1, + ) .build(); } @@ -107,7 +113,7 @@ impl IntrinsicObject for Intl { } impl BuiltInObject for Intl { - const NAME: &'static str = "Intl"; + const NAME: JsString = StaticJsStrings::INTL; } impl Intl { @@ -133,7 +139,7 @@ impl Intl { // 2. Return CreateArrayFromList(ll). Ok(JsValue::Object(Array::create_array_from_list( - ll.into_iter().map(|loc| loc.to_string().into()), + ll.into_iter().map(|loc| js_string!(loc.to_string()).into()), context, ))) } diff --git a/boa_engine/src/builtins/intl/plural_rules/mod.rs b/boa_engine/src/builtins/intl/plural_rules/mod.rs index f890a39933b..72343fb57be 100644 --- a/boa_engine/src/builtins/intl/plural_rules/mod.rs +++ b/boa_engine/src/builtins/intl/plural_rules/mod.rs @@ -19,6 +19,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, ObjectData, ObjectInitializer}, property::Attribute, realm::Realm, + string::common::StaticJsStrings, Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; @@ -48,17 +49,21 @@ impl Service for PluralRules { impl IntrinsicObject for PluralRules { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::supported_locales_of, "supportedLocalesOf", 1) + .static_method( + Self::supported_locales_of, + js_string!("supportedLocalesOf"), + 1, + ) .property( JsSymbol::to_string_tag(), - "Intl.PluralRules", + js_string!("Intl.PluralRules"), Attribute::CONFIGURABLE, ) - .method(Self::resolved_options, "resolvedOptions", 0) - .method(Self::select, "select", 1) + .method(Self::resolved_options, js_string!("resolvedOptions"), 0) + .method(Self::select, js_string!("select"), 1) .build(); } @@ -68,7 +73,7 @@ impl IntrinsicObject for PluralRules { } impl BuiltInObject for PluralRules { - const NAME: &'static str = "PluralRules"; + const NAME: JsString = StaticJsStrings::PLURAL_RULES; } impl BuiltInConstructor for PluralRules { @@ -263,15 +268,15 @@ impl PluralRules { options .property( js_string!("locale"), - plural_rules.locale.to_string(), + js_string!(plural_rules.locale.to_string()), Attribute::all(), ) .property( js_string!("type"), match plural_rules.rule_type { - PluralRuleType::Cardinal => "cardinal", - PluralRuleType::Ordinal => "ordinal", - _ => "unknown", + PluralRuleType::Cardinal => js_string!("cardinal"), + PluralRuleType::Ordinal => js_string!("ordinal"), + _ => js_string!("unknown"), }, Attribute::all(), ) @@ -318,7 +323,7 @@ impl PluralRules { options .property( js_string!("roundingMode"), - plural_rules.format_options.rounding_mode.to_string(), + js_string!(plural_rules.format_options.rounding_mode.to_string()), Attribute::all(), ) .property( @@ -328,10 +333,10 @@ impl PluralRules { ) .property( js_string!("trailingZeroDisplay"), - plural_rules + js_string!(plural_rules .format_options .trailing_zero_display - .to_string(), + .to_string()), Attribute::all(), ); @@ -360,7 +365,7 @@ impl PluralRules { // a. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "auto"). options.property( js_string!("roundingPriority"), - plural_rules.format_options.rounding_priority.to_string(), + js_string!(plural_rules.format_options.rounding_priority.to_string()), Attribute::all(), ); diff --git a/boa_engine/src/builtins/intl/segmenter/mod.rs b/boa_engine/src/builtins/intl/segmenter/mod.rs index a83105f1bc5..d8265fea694 100644 --- a/boa_engine/src/builtins/intl/segmenter/mod.rs +++ b/boa_engine/src/builtins/intl/segmenter/mod.rs @@ -19,6 +19,7 @@ use crate::{ }, property::Attribute, realm::Realm, + string::common::StaticJsStrings, Context, JsArgs, JsNativeError, JsResult, JsString, JsSymbol, JsValue, }; @@ -77,17 +78,21 @@ impl Service for Segmenter { impl IntrinsicObject for Segmenter { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::supported_locales_of, "supportedLocalesOf", 1) + .static_method( + Self::supported_locales_of, + js_string!("supportedLocalesOf"), + 1, + ) .property( JsSymbol::to_string_tag(), - "Intl.Segmenter", + js_string!("Intl.Segmenter"), Attribute::CONFIGURABLE, ) - .method(Self::resolved_options, "resolvedOptions", 0) - .method(Self::segment, "segment", 1) + .method(Self::resolved_options, js_string!("resolvedOptions"), 0) + .method(Self::segment, js_string!("segment"), 1) .build(); } @@ -97,7 +102,7 @@ impl IntrinsicObject for Segmenter { } impl BuiltInObject for Segmenter { - const NAME: &'static str = "Segmenter"; + const NAME: JsString = StaticJsStrings::SEGMENTER; } impl BuiltInConstructor for Segmenter { @@ -247,12 +252,12 @@ impl Segmenter { let options = ObjectInitializer::new(context) .property( js_string!("locale"), - segmenter.locale.to_string(), + js_string!(segmenter.locale.to_string()), Attribute::all(), ) .property( js_string!("granularity"), - segmenter.native.granularity().to_string(), + js_string!(segmenter.native.granularity().to_string()), Attribute::all(), ) .build(); diff --git a/boa_engine/src/builtins/intl/segmenter/segments.rs b/boa_engine/src/builtins/intl/segmenter/segments.rs index 6541a743426..143d798503b 100644 --- a/boa_engine/src/builtins/intl/segmenter/segments.rs +++ b/boa_engine/src/builtins/intl/segmenter/segments.rs @@ -24,7 +24,7 @@ impl IntrinsicObject for Segments { let _timer = Profiler::global().start_event("%SegmentsPrototype%", "init"); BuiltInBuilder::with_intrinsic::(realm) - .static_method(Self::containing, "containing", 1) + .static_method(Self::containing, js_string!("containing"), 1) .static_method( Self::iterator, (JsSymbol::iterator(), js_string!("[Symbol.iterator]")), diff --git a/boa_engine/src/builtins/iterable/async_from_sync_iterator.rs b/boa_engine/src/builtins/iterable/async_from_sync_iterator.rs index c59c72af4d3..4bf413e78f7 100644 --- a/boa_engine/src/builtins/iterable/async_from_sync_iterator.rs +++ b/boa_engine/src/builtins/iterable/async_from_sync_iterator.rs @@ -5,6 +5,7 @@ use crate::{ BuiltInBuilder, IntrinsicObject, Promise, }, context::intrinsics::Intrinsics, + js_string, native_function::NativeFunction, object::{FunctionObjectBuilder, JsObject, ObjectData}, realm::Realm, @@ -28,7 +29,7 @@ pub struct AsyncFromSyncIterator { impl IntrinsicObject for AsyncFromSyncIterator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("AsyncFromSyncIteratorPrototype", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -38,9 +39,9 @@ impl IntrinsicObject for AsyncFromSyncIterator { .iterator_prototypes() .async_iterator(), ) - .static_method(Self::next, "next", 1) - .static_method(Self::r#return, "return", 1) - .static_method(Self::throw, "throw", 1) + .static_method(Self::next, js_string!("next"), 1) + .static_method(Self::r#return, js_string!("return"), 1) + .static_method(Self::throw, js_string!("throw"), 1) .build(); } diff --git a/boa_engine/src/builtins/json/mod.rs b/boa_engine/src/builtins/json/mod.rs index 7e8fefbb6f8..a415d60e597 100644 --- a/boa_engine/src/builtins/json/mod.rs +++ b/boa_engine/src/builtins/json/mod.rs @@ -26,7 +26,7 @@ use crate::{ object::JsObject, property::{Attribute, PropertyNameKind}, realm::Realm, - string::{utf16, CodePoint}, + string::{common::StaticJsStrings, utf16, CodePoint}, symbol::JsSymbol, value::IntegerOrInfinity, vm::CallFrame, @@ -48,14 +48,14 @@ pub(crate) struct Json; impl IntrinsicObject for Json { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let to_string_tag = JsSymbol::to_string_tag(); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; BuiltInBuilder::with_intrinsic::(realm) - .static_method(Self::parse, "parse", 2) - .static_method(Self::stringify, "stringify", 3) + .static_method(Self::parse, js_string!("parse"), 2) + .static_method(Self::stringify, js_string!("stringify"), 3) .static_property(to_string_tag, Self::NAME, attribute) .build(); } @@ -66,7 +66,7 @@ impl IntrinsicObject for Json { } impl BuiltInObject for Json { - const NAME: &'static str = "JSON"; + const NAME: JsString = StaticJsStrings::JSON; } impl Json { diff --git a/boa_engine/src/builtins/json/tests.rs b/boa_engine/src/builtins/json/tests.rs index 72151acf97a..2300260036b 100644 --- a/boa_engine/src/builtins/json/tests.rs +++ b/boa_engine/src/builtins/json/tests.rs @@ -1,12 +1,15 @@ use indoc::indoc; -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; #[test] fn json_sanity() { run_test_actions([ - TestAction::assert_eq(r#"JSON.parse('{"aaa":"bbb"}').aaa"#, "bbb"), - TestAction::assert_eq(r#"JSON.stringify({aaa: 'bbb'})"#, r#"{"aaa":"bbb"}"#), + TestAction::assert_eq(r#"JSON.parse('{"aaa":"bbb"}').aaa"#, js_string!("bbb")), + TestAction::assert_eq( + r#"JSON.stringify({aaa: 'bbb'})"#, + js_string!(r#"{"aaa":"bbb"}"#), + ), ]); } @@ -14,7 +17,7 @@ fn json_sanity() { fn json_stringify_remove_undefined_values_from_objects() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({ aaa: undefined, bbb: 'ccc' })"#, - r#"{"bbb":"ccc"}"#, + js_string!(r#"{"bbb":"ccc"}"#), )]); } @@ -22,7 +25,7 @@ fn json_stringify_remove_undefined_values_from_objects() { fn json_stringify_remove_function_values_from_objects() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({ aaa: () => {}, bbb: 'ccc' })"#, - r#"{"bbb":"ccc"}"#, + js_string!(r#"{"bbb":"ccc"}"#), )]); } @@ -30,7 +33,7 @@ fn json_stringify_remove_function_values_from_objects() { fn json_stringify_remove_symbols_from_objects() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({ aaa: Symbol(), bbb: 'ccc' })"#, - r#"{"bbb":"ccc"}"#, + js_string!(r#"{"bbb":"ccc"}"#), )]); } @@ -38,7 +41,7 @@ fn json_stringify_remove_symbols_from_objects() { fn json_stringify_replacer_array_strings() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({aaa: 'bbb', bbb: 'ccc', ccc: 'ddd'}, ['aaa', 'bbb'])"#, - r#"{"aaa":"bbb","bbb":"ccc"}"#, + js_string!(r#"{"aaa":"bbb","bbb":"ccc"}"#), )]); } @@ -46,7 +49,7 @@ fn json_stringify_replacer_array_strings() { fn json_stringify_replacer_array_numbers() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({ 0: 'aaa', 1: 'bbb', 2: 'ccc'}, [1, 2])"#, - r#"{"1":"bbb","2":"ccc"}"#, + js_string!(r#"{"1":"bbb","2":"ccc"}"#), )]); } @@ -62,7 +65,7 @@ fn json_stringify_replacer_function() { return value; }) "#}, - r#"{"bbb":2}"#, + js_string!(r#"{"bbb":2}"#), )]); } @@ -70,7 +73,7 @@ fn json_stringify_replacer_function() { fn json_stringify_arrays() { run_test_actions([TestAction::assert_eq( "JSON.stringify(['a', 'b'])", - r#"["a","b"]"#, + js_string!(r#"["a","b"]"#), )]); } @@ -78,7 +81,7 @@ fn json_stringify_arrays() { fn json_stringify_object_array() { run_test_actions([TestAction::assert_eq( "JSON.stringify([{a: 'b'}, {b: 'c'}])", - r#"[{"a":"b"},{"b":"c"}]"#, + js_string!(r#"[{"a":"b"},{"b":"c"}]"#), )]); } @@ -86,7 +89,7 @@ fn json_stringify_object_array() { fn json_stringify_array_converts_undefined_to_null() { run_test_actions([TestAction::assert_eq( "JSON.stringify([undefined])", - "[null]", + js_string!("[null]"), )]); } @@ -94,7 +97,7 @@ fn json_stringify_array_converts_undefined_to_null() { fn json_stringify_array_converts_function_to_null() { run_test_actions([TestAction::assert_eq( "JSON.stringify([() => {}])", - "[null]", + js_string!("[null]"), )]); } @@ -102,7 +105,7 @@ fn json_stringify_array_converts_function_to_null() { fn json_stringify_array_converts_symbol_to_null() { run_test_actions([TestAction::assert_eq( "JSON.stringify([Symbol()])", - "[null]", + js_string!("[null]"), )]); } #[test] @@ -147,19 +150,22 @@ fn json_stringify_no_args() { #[test] fn json_stringify_fractional_numbers() { - run_test_actions([TestAction::assert_eq("JSON.stringify(1.2)", "1.2")]); + run_test_actions([TestAction::assert_eq( + "JSON.stringify(1.2)", + js_string!("1.2"), + )]); } #[test] fn json_stringify_pretty_print() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({a: "b", b: "c"}, undefined, 4)"#, - indoc! {r#" + js_string!(indoc! {r#" { "a": "b", "b": "c" }"# - }, + }), )]); } @@ -167,12 +173,12 @@ fn json_stringify_pretty_print() { fn json_stringify_pretty_print_four_spaces() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({a: "b", b: "c"}, undefined, 4.3)"#, - indoc! {r#" + js_string!(indoc! {r#" { "a": "b", "b": "c" }"# - }, + }), )]); } @@ -180,12 +186,12 @@ fn json_stringify_pretty_print_four_spaces() { fn json_stringify_pretty_print_twenty_spaces() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({a: "b", b: "c"}, undefined, 20)"#, - indoc! {r#" + js_string!(indoc! {r#" { "a": "b", "b": "c" }"# - }, + }), )]); } @@ -193,12 +199,12 @@ fn json_stringify_pretty_print_twenty_spaces() { fn json_stringify_pretty_print_with_number_object() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({a: "b", b: "c"}, undefined, new Number(10))"#, - indoc! {r#" + js_string!(indoc! {r#" { "a": "b", "b": "c" }"# - }, + }), )]); } @@ -206,7 +212,7 @@ fn json_stringify_pretty_print_with_number_object() { fn json_stringify_pretty_print_bad_space_argument() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({a: "b", b: "c"}, undefined, [])"#, - r#"{"a":"b","b":"c"}"#, + js_string!(r#"{"a":"b","b":"c"}"#), )]); } @@ -214,12 +220,12 @@ fn json_stringify_pretty_print_bad_space_argument() { fn json_stringify_pretty_print_with_too_long_string() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({a: "b", b: "c"}, undefined, "abcdefghijklmn")"#, - indoc! {r#" + js_string!(indoc! {r#" { abcdefghij"a": "b", abcdefghij"b": "c" }"# - }, + }), )]); } @@ -227,12 +233,12 @@ fn json_stringify_pretty_print_with_too_long_string() { fn json_stringify_pretty_print_with_string_object() { run_test_actions([TestAction::assert_eq( r#"JSON.stringify({a: "b", b: "c"}, undefined, new String("abcd"))"#, - indoc! {r#" + js_string!(indoc! {r#" { abcd"a": "b", abcd"b": "c" }"# - }, + }), )]); } @@ -272,8 +278,8 @@ fn json_parse_object_with_reviver() { var jsonObj = JSON.parse(jsonString, dataReviver); "#}), - TestAction::assert_eq("jsonObj.firstname", "boa"), - TestAction::assert_eq("jsonObj.lastname", "interpreter"), + TestAction::assert_eq("jsonObj.firstname", js_string!("boa")), + TestAction::assert_eq("jsonObj.lastname", js_string!("interpreter")), ]); } diff --git a/boa_engine/src/builtins/map/map_iterator.rs b/boa_engine/src/builtins/map/map_iterator.rs index ca4c555b3c9..0eeb58ea308 100644 --- a/boa_engine/src/builtins/map/map_iterator.rs +++ b/boa_engine/src/builtins/map/map_iterator.rs @@ -12,6 +12,7 @@ use crate::{ }, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::{JsObject, ObjectData}, property::{Attribute, PropertyNameKind}, realm::Realm, @@ -38,7 +39,7 @@ pub struct MapIterator { impl IntrinsicObject for MapIterator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("MapIterator", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -48,10 +49,10 @@ impl IntrinsicObject for MapIterator { .iterator_prototypes() .iterator(), ) - .static_method(Self::next, "next", 0) + .static_method(Self::next, js_string!("next"), 0) .static_property( JsSymbol::to_string_tag(), - "Map Iterator", + js_string!("Map Iterator"), Attribute::CONFIGURABLE, ) .build(); diff --git a/boa_engine/src/builtins/map/mod.rs b/boa_engine/src/builtins/map/mod.rs index bafcc2c98e7..fcb71dd201b 100644 --- a/boa_engine/src/builtins/map/mod.rs +++ b/boa_engine/src/builtins/map/mod.rs @@ -14,12 +14,13 @@ use crate::{ builtins::BuiltInObject, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::{Attribute, PropertyNameKind}, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, - Context, JsArgs, JsResult, JsValue, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; use num_traits::Zero; @@ -39,18 +40,18 @@ pub(crate) struct Map; impl IntrinsicObject for Map { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_species = BuiltInBuilder::callable(realm, Self::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); let get_size = BuiltInBuilder::callable(realm, Self::get_size) - .name("get size") + .name(js_string!("get size")) .build(); let entries_function = BuiltInBuilder::callable(realm, Self::entries) - .name("entries") + .name(js_string!("entries")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -75,16 +76,16 @@ impl IntrinsicObject for Map { Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .method(Self::clear, "clear", 0) - .method(Self::delete, "delete", 1) - .method(Self::for_each, "forEach", 1) - .method(Self::get, "get", 1) - .method(Self::has, "has", 1) - .method(Self::keys, "keys", 0) - .method(Self::set, "set", 2) - .method(Self::values, "values", 0) + .method(Self::clear, js_string!("clear"), 0) + .method(Self::delete, js_string!("delete"), 1) + .method(Self::for_each, js_string!("forEach"), 1) + .method(Self::get, js_string!("get"), 1) + .method(Self::has, js_string!("has"), 1) + .method(Self::keys, js_string!("keys"), 0) + .method(Self::set, js_string!("set"), 2) + .method(Self::values, js_string!("values"), 0) .accessor( - utf16!("size"), + js_string!("size"), Some(get_size), None, Attribute::CONFIGURABLE, @@ -98,7 +99,7 @@ impl IntrinsicObject for Map { } impl BuiltInObject for Map { - const NAME: &'static str = "Map"; + const NAME: JsString = StaticJsStrings::MAP; } impl BuiltInConstructor for Map { diff --git a/boa_engine/src/builtins/map/tests.rs b/boa_engine/src/builtins/map/tests.rs index 75aa377b515..89d2e5cb842 100644 --- a/boa_engine/src/builtins/map/tests.rs +++ b/boa_engine/src/builtins/map/tests.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; use indoc::indoc; #[test] @@ -74,7 +74,7 @@ fn merge() { let merged2 = new Map([...second, ...third]); "#}), TestAction::assert_eq("merged1.size", 3), - TestAction::assert_eq("merged1.get('2')", "second two"), + TestAction::assert_eq("merged1.get('2')", js_string!("second two")), TestAction::assert_eq("merged2.size", 4), ]); } @@ -85,8 +85,8 @@ fn get() { TestAction::run(indoc! {r#" let map = new Map([["1", "one"], ["2", "two"]]); "#}), - TestAction::assert_eq("map.get('1')", "one"), - TestAction::assert_eq("map.get('2')", "two"), + TestAction::assert_eq("map.get('1')", js_string!("one")), + TestAction::assert_eq("map.get('2')", js_string!("two")), TestAction::assert_eq("map.get('3')", JsValue::undefined()), TestAction::assert_eq("map.get()", JsValue::undefined()), ]); @@ -98,7 +98,7 @@ fn set() { TestAction::run("let map = new Map();"), TestAction::assert("map.set(); map.has(undefined)"), TestAction::assert_eq("map.get()", JsValue::undefined()), - TestAction::assert_eq("map.set('1', 'one'); map.get('1')", "one"), + TestAction::assert_eq("map.set('1', 'one'); map.get('1')", js_string!("one")), TestAction::assert("map.set('2'); map.has('2')"), TestAction::assert_eq("map.get('2')", JsValue::undefined()), ]); @@ -148,7 +148,7 @@ fn keys() { let item2 = keysIterator.next(); let item3 = keysIterator.next(); "#}), - TestAction::assert_eq("item1.value", "0"), + TestAction::assert_eq("item1.value", js_string!("0")), TestAction::assert_eq("item2.value", 1), TestAction::assert("item3.done"), ]); @@ -187,8 +187,8 @@ fn values() { let item2 = valuesIterator.next(); let item3 = valuesIterator.next(); "#}), - TestAction::assert_eq("item1.value", "foo"), - TestAction::assert_eq("item2.value", "bar"), + TestAction::assert_eq("item1.value", js_string!("foo")), + TestAction::assert_eq("item2.value", js_string!("bar")), TestAction::assert("item3.done"), ]); } @@ -201,7 +201,7 @@ fn modify_key() { let map = new Map([[obj, "one"]]); obj.field = "Value"; "#}), - TestAction::assert_eq("map.get(obj)", "one"), + TestAction::assert_eq("map.get(obj)", js_string!("one")), ]); } diff --git a/boa_engine/src/builtins/math/mod.rs b/boa_engine/src/builtins/math/mod.rs index 406661c5ff6..6d0693b2ac5 100644 --- a/boa_engine/src/builtins/math/mod.rs +++ b/boa_engine/src/builtins/math/mod.rs @@ -12,9 +12,9 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math use crate::{ - builtins::BuiltInObject, context::intrinsics::Intrinsics, object::JsObject, - property::Attribute, realm::Realm, string::utf16, symbol::JsSymbol, Context, JsArgs, JsResult, - JsValue, + builtins::BuiltInObject, context::intrinsics::Intrinsics, js_string, object::JsObject, + property::Attribute, realm::Realm, string::common::StaticJsStrings, symbol::JsSymbol, Context, + JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -29,57 +29,57 @@ pub(crate) struct Math; impl IntrinsicObject for Math { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; BuiltInBuilder::with_intrinsic::(realm) - .static_property(utf16!("E"), std::f64::consts::E, attribute) - .static_property(utf16!("LN10"), std::f64::consts::LN_10, attribute) - .static_property(utf16!("LN2"), std::f64::consts::LN_2, attribute) - .static_property(utf16!("LOG10E"), std::f64::consts::LOG10_E, attribute) - .static_property(utf16!("LOG2E"), std::f64::consts::LOG2_E, attribute) - .static_property(utf16!("PI"), std::f64::consts::PI, attribute) + .static_property(js_string!("E"), std::f64::consts::E, attribute) + .static_property(js_string!("LN10"), std::f64::consts::LN_10, attribute) + .static_property(js_string!("LN2"), std::f64::consts::LN_2, attribute) + .static_property(js_string!("LOG10E"), std::f64::consts::LOG10_E, attribute) + .static_property(js_string!("LOG2E"), std::f64::consts::LOG2_E, attribute) + .static_property(js_string!("PI"), std::f64::consts::PI, attribute) .static_property( - utf16!("SQRT1_2"), + js_string!("SQRT1_2"), std::f64::consts::FRAC_1_SQRT_2, attribute, ) - .static_property(utf16!("SQRT2"), std::f64::consts::SQRT_2, attribute) - .static_method(Self::abs, "abs", 1) - .static_method(Self::acos, "acos", 1) - .static_method(Self::acosh, "acosh", 1) - .static_method(Self::asin, "asin", 1) - .static_method(Self::asinh, "asinh", 1) - .static_method(Self::atan, "atan", 1) - .static_method(Self::atanh, "atanh", 1) - .static_method(Self::atan2, "atan2", 2) - .static_method(Self::cbrt, "cbrt", 1) - .static_method(Self::ceil, "ceil", 1) - .static_method(Self::clz32, "clz32", 1) - .static_method(Self::cos, "cos", 1) - .static_method(Self::cosh, "cosh", 1) - .static_method(Self::exp, "exp", 1) - .static_method(Self::expm1, "expm1", 1) - .static_method(Self::floor, "floor", 1) - .static_method(Self::fround, "fround", 1) - .static_method(Self::hypot, "hypot", 2) - .static_method(Self::imul, "imul", 2) - .static_method(Self::log, "log", 1) - .static_method(Self::log1p, "log1p", 1) - .static_method(Self::log10, "log10", 1) - .static_method(Self::log2, "log2", 1) - .static_method(Self::max, "max", 2) - .static_method(Self::min, "min", 2) - .static_method(Self::pow, "pow", 2) - .static_method(Self::random, "random", 0) - .static_method(Self::round, "round", 1) - .static_method(Self::sign, "sign", 1) - .static_method(Self::sin, "sin", 1) - .static_method(Self::sinh, "sinh", 1) - .static_method(Self::sqrt, "sqrt", 1) - .static_method(Self::tan, "tan", 1) - .static_method(Self::tanh, "tanh", 1) - .static_method(Self::trunc, "trunc", 1) + .static_property(js_string!("SQRT2"), std::f64::consts::SQRT_2, attribute) + .static_method(Self::abs, js_string!("abs"), 1) + .static_method(Self::acos, js_string!("acos"), 1) + .static_method(Self::acosh, js_string!("acosh"), 1) + .static_method(Self::asin, js_string!("asin"), 1) + .static_method(Self::asinh, js_string!("asinh"), 1) + .static_method(Self::atan, js_string!("atan"), 1) + .static_method(Self::atanh, js_string!("atanh"), 1) + .static_method(Self::atan2, js_string!("atan2"), 2) + .static_method(Self::cbrt, js_string!("cbrt"), 1) + .static_method(Self::ceil, js_string!("ceil"), 1) + .static_method(Self::clz32, js_string!("clz32"), 1) + .static_method(Self::cos, js_string!("cos"), 1) + .static_method(Self::cosh, js_string!("cosh"), 1) + .static_method(Self::exp, js_string!("exp"), 1) + .static_method(Self::expm1, js_string!("expm1"), 1) + .static_method(Self::floor, js_string!("floor"), 1) + .static_method(Self::fround, js_string!("fround"), 1) + .static_method(Self::hypot, js_string!("hypot"), 2) + .static_method(Self::imul, js_string!("imul"), 2) + .static_method(Self::log, js_string!("log"), 1) + .static_method(Self::log1p, js_string!("log1p"), 1) + .static_method(Self::log10, js_string!("log10"), 1) + .static_method(Self::log2, js_string!("log2"), 1) + .static_method(Self::max, js_string!("max"), 2) + .static_method(Self::min, js_string!("min"), 2) + .static_method(Self::pow, js_string!("pow"), 2) + .static_method(Self::random, js_string!("random"), 0) + .static_method(Self::round, js_string!("round"), 1) + .static_method(Self::sign, js_string!("sign"), 1) + .static_method(Self::sin, js_string!("sin"), 1) + .static_method(Self::sinh, js_string!("sinh"), 1) + .static_method(Self::sqrt, js_string!("sqrt"), 1) + .static_method(Self::tan, js_string!("tan"), 1) + .static_method(Self::tanh, js_string!("tanh"), 1) + .static_method(Self::trunc, js_string!("trunc"), 1) .static_property( JsSymbol::to_string_tag(), Self::NAME, @@ -94,7 +94,7 @@ impl IntrinsicObject for Math { } impl BuiltInObject for Math { - const NAME: &'static str = "Math"; + const NAME: JsString = StaticJsStrings::MATH; } impl Math { diff --git a/boa_engine/src/builtins/mod.rs b/boa_engine/src/builtins/mod.rs index fe776aef1ce..440fa20f4c2 100644 --- a/boa_engine/src/builtins/mod.rs +++ b/boa_engine/src/builtins/mod.rs @@ -137,7 +137,7 @@ pub(crate) trait BuiltInObject: IntrinsicObject { /// E.g. If you want access the properties of a `Complex` built-in with the name `Cplx` you must /// assign `"Cplx"` to this constant, making any property inside it accessible from ECMAScript /// as `Cplx.prop` - const NAME: &'static str; + const NAME: JsString; /// Property attribute flags of the built-in. Check [`Attribute`] for more information. const ATTRIBUTE: Attribute = Attribute::WRITABLE @@ -649,8 +649,8 @@ impl BuiltInConstructorWithPrototype<'_> { /// Specify the name of the constructor function. /// /// Default is `""` - fn name>(mut self, name: N) -> Self { - self.name = name.into(); + fn name(mut self, name: JsString) -> Self { + self.name = name; self } @@ -826,8 +826,8 @@ impl BuiltInConstructorWithPrototype<'_> { let length = self.length; let name = self.name.clone(); let prototype = self.prototype.clone(); - self = self.static_property("length", length, Attribute::CONFIGURABLE); - self = self.static_property("name", name, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("length"), length, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("name"), name, Attribute::CONFIGURABLE); self = self.static_property(PROTOTYPE, prototype, Attribute::empty()); let attributes = self.attributes; @@ -877,8 +877,8 @@ impl BuiltInConstructorWithPrototype<'_> { let length = self.length; let name = self.name.clone(); - self = self.static_property("length", length, Attribute::CONFIGURABLE); - self = self.static_property("name", name, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("length"), length, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("name"), name, Attribute::CONFIGURABLE); let mut object = self.object.borrow_mut(); *object.kind_mut() = ObjectKind::Function(function); @@ -916,8 +916,8 @@ impl BuiltInCallable<'_> { /// Specify the name of the constructor function. /// /// Default is `""` - fn name>(mut self, name: N) -> Self { - self.name = name.into(); + fn name(mut self, name: JsString) -> Self { + self.name = name; self } @@ -1074,8 +1074,8 @@ impl BuiltInBuilder<'_, Callable> { /// Specify the name of the constructor function. /// /// Default is `""` - fn name>(mut self, name: N) -> Self { - self.kind.name = name.into(); + fn name(mut self, name: JsString) -> Self { + self.kind.name = name; self } } diff --git a/boa_engine/src/builtins/number/globals.rs b/boa_engine/src/builtins/number/globals.rs index 15ae25b6f47..62ac94104ce 100644 --- a/boa_engine/src/builtins/number/globals.rs +++ b/boa_engine/src/builtins/number/globals.rs @@ -5,8 +5,8 @@ use crate::{ context::intrinsics::Intrinsics, object::JsObject, realm::Realm, - string::Utf16Trim, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, Utf16Trim}, + Context, JsArgs, JsResult, JsString, JsValue, }; use num_traits::Num; @@ -50,7 +50,7 @@ impl IntrinsicObject for IsFinite { } impl BuiltInObject for IsFinite { - const NAME: &'static str = "isFinite"; + const NAME: JsString = StaticJsStrings::IS_FINITE; } /// Builtin javascript 'isNaN(number)' function. @@ -96,7 +96,7 @@ impl IntrinsicObject for IsNaN { } impl BuiltInObject for IsNaN { - const NAME: &'static str = "isNaN"; + const NAME: JsString = StaticJsStrings::IS_NAN; } /// Builtin javascript 'parseInt(str, radix)' function. @@ -237,7 +237,7 @@ impl IntrinsicObject for ParseInt { } impl BuiltInObject for ParseInt { - const NAME: &'static str = "parseInt"; + const NAME: JsString = StaticJsStrings::PARSE_INT; } /// Builtin javascript 'parseFloat(str)' function. @@ -310,5 +310,5 @@ impl IntrinsicObject for ParseFloat { } impl BuiltInObject for ParseFloat { - const NAME: &'static str = "parseFloat"; + const NAME: JsString = StaticJsStrings::PARSE_FLOAT; } diff --git a/boa_engine/src/builtins/number/mod.rs b/boa_engine/src/builtins/number/mod.rs index d87e2b2732b..5a98a89b9e0 100644 --- a/boa_engine/src/builtins/number/mod.rs +++ b/boa_engine/src/builtins/number/mod.rs @@ -17,12 +17,13 @@ use crate::{ builtins::BuiltInObject, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::common::StaticJsStrings, value::{AbstractRelation, IntegerOrInfinity, JsValue}, - Context, JsArgs, JsResult, + Context, JsArgs, JsResult, JsString, }; use boa_profiler::Profiler; use num_traits::float::FloatCore; @@ -47,47 +48,51 @@ pub(crate) struct Number; impl IntrinsicObject for Number { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; BuiltInBuilder::from_standard_constructor::(realm) - .static_property(utf16!("EPSILON"), f64::EPSILON, attribute) + .static_property(js_string!("EPSILON"), f64::EPSILON, attribute) .static_property( - utf16!("MAX_SAFE_INTEGER"), + js_string!("MAX_SAFE_INTEGER"), Self::MAX_SAFE_INTEGER, attribute, ) .static_property( - utf16!("MIN_SAFE_INTEGER"), + js_string!("MIN_SAFE_INTEGER"), Self::MIN_SAFE_INTEGER, attribute, ) - .static_property(utf16!("MAX_VALUE"), Self::MAX_VALUE, attribute) - .static_property(utf16!("MIN_VALUE"), Self::MIN_VALUE, attribute) - .static_property(utf16!("NEGATIVE_INFINITY"), f64::NEG_INFINITY, attribute) - .static_property(utf16!("POSITIVE_INFINITY"), f64::INFINITY, attribute) - .static_property(utf16!("NaN"), f64::NAN, attribute) + .static_property(js_string!("MAX_VALUE"), Self::MAX_VALUE, attribute) + .static_property(js_string!("MIN_VALUE"), Self::MIN_VALUE, attribute) .static_property( - utf16!("parseInt"), + js_string!("NEGATIVE_INFINITY"), + f64::NEG_INFINITY, + attribute, + ) + .static_property(js_string!("POSITIVE_INFINITY"), f64::INFINITY, attribute) + .static_property(js_string!("NaN"), f64::NAN, attribute) + .static_property( + js_string!("parseInt"), realm.intrinsics().objects().parse_int(), Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - utf16!("parseFloat"), + js_string!("parseFloat"), realm.intrinsics().objects().parse_float(), Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .static_method(Self::number_is_finite, "isFinite", 1) - .static_method(Self::number_is_nan, "isNaN", 1) - .static_method(Self::is_safe_integer, "isSafeInteger", 1) - .static_method(Self::number_is_integer, "isInteger", 1) - .method(Self::to_exponential, "toExponential", 1) - .method(Self::to_fixed, "toFixed", 1) - .method(Self::to_locale_string, "toLocaleString", 0) - .method(Self::to_precision, "toPrecision", 1) - .method(Self::to_string, "toString", 1) - .method(Self::value_of, "valueOf", 0) + .static_method(Self::number_is_finite, js_string!("isFinite"), 1) + .static_method(Self::number_is_nan, js_string!("isNaN"), 1) + .static_method(Self::is_safe_integer, js_string!("isSafeInteger"), 1) + .static_method(Self::number_is_integer, js_string!("isInteger"), 1) + .method(Self::to_exponential, js_string!("toExponential"), 1) + .method(Self::to_fixed, js_string!("toFixed"), 1) + .method(Self::to_locale_string, js_string!("toLocaleString"), 0) + .method(Self::to_precision, js_string!("toPrecision"), 1) + .method(Self::to_string, js_string!("toString"), 1) + .method(Self::value_of, js_string!("valueOf"), 0) .build(); } @@ -97,7 +102,7 @@ impl IntrinsicObject for Number { } impl BuiltInObject for Number { - const NAME: &'static str = "Number"; + const NAME: JsString = StaticJsStrings::NUMBER; } impl BuiltInConstructor for Number { @@ -222,7 +227,7 @@ impl Number { }; // 4. If x is not finite, return ! Number::toString(x). if !this_num.is_finite() { - return Ok(JsValue::new(Self::to_native_string(this_num))); + return Ok(JsValue::new(Self::to_js_string(this_num))); } // Get rid of the '-' sign for -0.0 let this_num = if this_num == 0. { 0. } else { this_num }; @@ -276,7 +281,7 @@ impl Number { // 6. If x is not finite, return ! Number::toString(x). if !this_num.is_finite() { - Ok(JsValue::new(Self::to_native_string(this_num))) + Ok(JsValue::new(Self::to_js_string(this_num))) // 10. If x ≥ 10^21, then let m be ! ToString(𝔽(x)). } else if this_num >= 1.0e21 { Ok(JsValue::new(f64_to_exponential(this_num))) @@ -284,7 +289,7 @@ impl Number { // Get rid of the '-' sign for -0.0 because of 9. If x < 0, then set s to "-". let this_num = if this_num == 0_f64 { 0_f64 } else { this_num }; let this_fixed_num = format!("{this_num:.precision$}"); - Ok(JsValue::new(this_fixed_num)) + Ok(JsValue::new(js_string!(this_fixed_num))) } } @@ -309,7 +314,7 @@ impl Number { ) -> JsResult { let this_num = Self::this_number_value(this)?; let this_str_num = this_num.to_string(); - Ok(JsValue::new(this_str_num)) + Ok(JsValue::new(js_string!(this_str_num))) } /// `flt_str_to_exp` - used in `to_precision` @@ -494,14 +499,14 @@ impl Number { // iv, v suffix.push_str(&exponent.to_string()); - return Ok(JsValue::new(prefix + &suffix)); + return Ok(JsValue::new(js_string!(prefix + &suffix))); } } // 11 let e_inc = exponent + 1; if e_inc == precision_i32 { - return Ok(JsValue::new(prefix + &suffix)); + return Ok(JsValue::new(js_string!(prefix + &suffix))); } // 12 @@ -515,7 +520,7 @@ impl Number { } // 14 - Ok(JsValue::new(prefix + &suffix)) + Ok(JsValue::new(js_string!(prefix + &suffix))) } // https://golang.org/src/math/nextafter.go @@ -535,7 +540,7 @@ impl Number { // https://chromium.googlesource.com/v8/v8/+/refs/heads/master/src/numbers/conversions.cc#1230 #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_native_string_radix(mut value: f64, radix: u8) -> String { + pub(crate) fn to_js_string_radix(mut value: f64, radix: u8) -> JsString { assert!(radix >= 2); assert!(radix <= 36); assert!(value.is_finite()); @@ -639,13 +644,15 @@ impl Number { let integer_cursor = int_iter.next().expect("integer buffer exhausted").0 + 1; let fraction_cursor = fraction_cursor + BUF_SIZE / 2; - String::from_utf8_lossy(&buffer[integer_cursor..fraction_cursor]).into() + js_string!(&*String::from_utf8_lossy( + &buffer[integer_cursor..fraction_cursor] + )) } #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_native_string(x: f64) -> String { + pub(crate) fn to_js_string(x: f64) -> JsString { let mut buffer = ryu_js::Buffer::new(); - buffer.format(x).to_string() + js_string!(buffer.format(x).to_string()) } /// `Number.prototype.toString( [radix] )` @@ -686,17 +693,17 @@ impl Number { // 5. If radixNumber = 10, return ! ToString(x). if radix_number == 10 { - return Ok(JsValue::new(Self::to_native_string(x))); + return Ok(JsValue::new(Self::to_js_string(x))); } if x == -0. { - return Ok(JsValue::new("0")); + return Ok(JsValue::new(js_string!("0"))); } else if x.is_nan() { - return Ok(JsValue::new("NaN")); + return Ok(JsValue::new(js_string!("NaN"))); } else if x.is_infinite() && x.is_sign_positive() { - return Ok(JsValue::new("Infinity")); + return Ok(JsValue::new(js_string!("Infinity"))); } else if x.is_infinite() && x.is_sign_negative() { - return Ok(JsValue::new("-Infinity")); + return Ok(JsValue::new(js_string!("-Infinity"))); } // This is a Optimization from the v8 source code to print values that can fit in a single character @@ -708,7 +715,7 @@ impl Number { // } // 6. Return the String representation of this Number value using the radix specified by radixNumber. - Ok(JsValue::new(Self::to_native_string_radix(x, radix_number))) + Ok(JsValue::new(Self::to_js_string_radix(x, radix_number))) } /// `Number.prototype.toString()` @@ -920,22 +927,22 @@ impl Number { } /// Helper function that formats a float as a ES6-style exponential number string. -fn f64_to_exponential(n: f64) -> String { - match n.abs() { +fn f64_to_exponential(n: f64) -> JsString { + js_string!(match n.abs() { x if x >= 1.0 || x == 0.0 => format!("{n:e}").replace('e', "e+"), _ => format!("{n:e}"), - } + }) } /// Helper function that formats a float as a ES6-style exponential number string with a given precision. // We can't use the same approach as in `f64_to_exponential` // because in cases like (0.999).toExponential(0) the result will be 1e0. // Instead we get the index of 'e', and if the next character is not '-' we insert the plus sign -fn f64_to_exponential_with_precision(n: f64, prec: usize) -> String { +fn f64_to_exponential_with_precision(n: f64, prec: usize) -> JsString { let mut res = format!("{n:.prec$e}"); let idx = res.find('e').expect("'e' not found in exponential string"); if res.as_bytes()[idx + 1] != b'-' { res.insert(idx + 1, '+'); } - res + js_string!(res) } diff --git a/boa_engine/src/builtins/number/tests.rs b/boa_engine/src/builtins/number/tests.rs index c5ca4858472..d44ef4ba4d5 100644 --- a/boa_engine/src/builtins/number/tests.rs +++ b/boa_engine/src/builtins/number/tests.rs @@ -1,10 +1,11 @@ use crate::{ - builtins::Number, run_test_actions, value::AbstractRelation, JsNativeErrorKind, TestAction, + builtins::Number, js_string, run_test_actions, value::AbstractRelation, JsNativeErrorKind, + TestAction, }; #[test] fn integer_number_primitive_to_number_object() { - run_test_actions([TestAction::assert_eq("(100).toString()", "100")]); + run_test_actions([TestAction::assert_eq("(100).toString()", js_string!("100"))]); } #[test] @@ -24,23 +25,29 @@ fn call_number() { #[test] fn to_exponential() { run_test_actions([ - TestAction::assert_eq("Number().toExponential()", "0e+0"), - TestAction::assert_eq("Number(5).toExponential()", "5e+0"), - TestAction::assert_eq("Number(1.234).toExponential()", "1.234e+0"), - TestAction::assert_eq("Number(1234).toExponential()", "1.234e+3"), - TestAction::assert_eq("Number('I am also not a number').toExponential()", "NaN"), - TestAction::assert_eq("Number('1.23e+2').toExponential()", "1.23e+2"), + TestAction::assert_eq("Number().toExponential()", js_string!("0e+0")), + TestAction::assert_eq("Number(5).toExponential()", js_string!("5e+0")), + TestAction::assert_eq("Number(1.234).toExponential()", js_string!("1.234e+0")), + TestAction::assert_eq("Number(1234).toExponential()", js_string!("1.234e+3")), + TestAction::assert_eq( + "Number('I am also not a number').toExponential()", + js_string!("NaN"), + ), + TestAction::assert_eq("Number('1.23e+2').toExponential()", js_string!("1.23e+2")), ]); } #[test] fn to_fixed() { run_test_actions([ - TestAction::assert_eq("Number().toFixed()", "0"), - TestAction::assert_eq("Number('3.456e+4').toFixed()", "34560"), - TestAction::assert_eq("Number('3.456e-4').toFixed()", "0"), - TestAction::assert_eq("Number(5).toFixed()", "5"), - TestAction::assert_eq("Number('I am also not a number').toFixed()", "NaN"), + TestAction::assert_eq("Number().toFixed()", js_string!("0")), + TestAction::assert_eq("Number('3.456e+4').toFixed()", js_string!("34560")), + TestAction::assert_eq("Number('3.456e-4').toFixed()", js_string!("0")), + TestAction::assert_eq("Number(5).toFixed()", js_string!("5")), + TestAction::assert_eq( + "Number('I am also not a number').toFixed()", + js_string!("NaN"), + ), ]); } @@ -49,10 +56,10 @@ fn to_locale_string() { // TODO: We don't actually do any locale checking here // To honor the spec we should print numbers according to user locale. run_test_actions([ - TestAction::assert_eq("Number().toLocaleString()", "0"), - TestAction::assert_eq("Number(5).toLocaleString()", "5"), - TestAction::assert_eq("Number('345600').toLocaleString()", "345600"), - TestAction::assert_eq("Number(-25).toLocaleString()", "-25"), + TestAction::assert_eq("Number().toLocaleString()", js_string!("0")), + TestAction::assert_eq("Number(5).toLocaleString()", js_string!("5")), + TestAction::assert_eq("Number('345600').toLocaleString()", js_string!("345600")), + TestAction::assert_eq("Number(-25).toLocaleString()", js_string!("-25")), ]); } @@ -60,21 +67,21 @@ fn to_locale_string() { fn to_precision() { const ERROR: &str = "precision must be an integer at least 1 and no greater than 100"; run_test_actions([ - TestAction::assert_eq("(1/0).toPrecision(3)", "Infinity"), - TestAction::assert_eq("Number().toPrecision()", "0"), - TestAction::assert_eq("Number().toPrecision(undefined)", "0"), - TestAction::assert_eq("(123456789).toPrecision(1)", "1e+8"), - TestAction::assert_eq("(123456789).toPrecision(4)", "1.235e+8"), - TestAction::assert_eq("(123456789).toPrecision(9)", "123456789"), - TestAction::assert_eq("(-123456789).toPrecision(4)", "-1.235e+8"), + TestAction::assert_eq("(1/0).toPrecision(3)", js_string!("Infinity")), + TestAction::assert_eq("Number().toPrecision()", js_string!("0")), + TestAction::assert_eq("Number().toPrecision(undefined)", js_string!("0")), + TestAction::assert_eq("(123456789).toPrecision(1)", js_string!("1e+8")), + TestAction::assert_eq("(123456789).toPrecision(4)", js_string!("1.235e+8")), + TestAction::assert_eq("(123456789).toPrecision(9)", js_string!("123456789")), + TestAction::assert_eq("(-123456789).toPrecision(4)", js_string!("-1.235e+8")), TestAction::assert_eq( "(123456789).toPrecision(50)", - "123456789.00000000000000000000000000000000000000000", + js_string!("123456789.00000000000000000000000000000000000000000"), ), - TestAction::assert_eq("(0.1).toPrecision(4)", "0.1000"), + TestAction::assert_eq("(0.1).toPrecision(4)", js_string!("0.1000")), TestAction::assert_eq( "(1/3).toPrecision(60)", - "0.333333333333333314829616256247390992939472198486328125000000", + js_string!("0.333333333333333314829616256247390992939472198486328125000000"), ), TestAction::assert_native_error("(1).toPrecision(101)", JsNativeErrorKind::Range, ERROR), TestAction::assert_native_error("(1).toPrecision(0)", JsNativeErrorKind::Range, ERROR), @@ -86,90 +93,132 @@ fn to_precision() { #[test] fn to_string() { run_test_actions([ - TestAction::assert_eq("Number(NaN).toString()", "NaN"), - TestAction::assert_eq("Number(1/0).toString()", "Infinity"), - TestAction::assert_eq("Number(-1/0).toString()", "-Infinity"), - TestAction::assert_eq("Number(0).toString()", "0"), - TestAction::assert_eq("Number(9).toString()", "9"), - TestAction::assert_eq("Number(90).toString()", "90"), - TestAction::assert_eq("Number(90.12).toString()", "90.12"), - TestAction::assert_eq("Number(0.1).toString()", "0.1"), - TestAction::assert_eq("Number(0.01).toString()", "0.01"), - TestAction::assert_eq("Number(0.0123).toString()", "0.0123"), - TestAction::assert_eq("Number(0.00001).toString()", "0.00001"), - TestAction::assert_eq("Number(0.000001).toString()", "0.000001"), - TestAction::assert_eq("Number(NaN).toString(16)", "NaN"), - TestAction::assert_eq("Number(1/0).toString(16)", "Infinity"), - TestAction::assert_eq("Number(-1/0).toString(16)", "-Infinity"), - TestAction::assert_eq("Number(0).toString(16)", "0"), - TestAction::assert_eq("Number(9).toString(16)", "9"), - TestAction::assert_eq("Number(90).toString(16)", "5a"), - TestAction::assert_eq("Number(90.12).toString(16)", "5a.1eb851eb852"), - TestAction::assert_eq("Number(0.1).toString(16)", "0.1999999999999a"), - TestAction::assert_eq("Number(0.01).toString(16)", "0.028f5c28f5c28f6"), - TestAction::assert_eq("Number(0.0123).toString(16)", "0.032617c1bda511a"), + TestAction::assert_eq("Number(NaN).toString()", js_string!("NaN")), + TestAction::assert_eq("Number(1/0).toString()", js_string!("Infinity")), + TestAction::assert_eq("Number(-1/0).toString()", js_string!("-Infinity")), + TestAction::assert_eq("Number(0).toString()", js_string!("0")), + TestAction::assert_eq("Number(9).toString()", js_string!("9")), + TestAction::assert_eq("Number(90).toString()", js_string!("90")), + TestAction::assert_eq("Number(90.12).toString()", js_string!("90.12")), + TestAction::assert_eq("Number(0.1).toString()", js_string!("0.1")), + TestAction::assert_eq("Number(0.01).toString()", js_string!("0.01")), + TestAction::assert_eq("Number(0.0123).toString()", js_string!("0.0123")), + TestAction::assert_eq("Number(0.00001).toString()", js_string!("0.00001")), + TestAction::assert_eq("Number(0.000001).toString()", js_string!("0.000001")), + TestAction::assert_eq("Number(NaN).toString(16)", js_string!("NaN")), + TestAction::assert_eq("Number(1/0).toString(16)", js_string!("Infinity")), + TestAction::assert_eq("Number(-1/0).toString(16)", js_string!("-Infinity")), + TestAction::assert_eq("Number(0).toString(16)", js_string!("0")), + TestAction::assert_eq("Number(9).toString(16)", js_string!("9")), + TestAction::assert_eq("Number(90).toString(16)", js_string!("5a")), + TestAction::assert_eq("Number(90.12).toString(16)", js_string!("5a.1eb851eb852")), + TestAction::assert_eq("Number(0.1).toString(16)", js_string!("0.1999999999999a")), + TestAction::assert_eq("Number(0.01).toString(16)", js_string!("0.028f5c28f5c28f6")), + TestAction::assert_eq( + "Number(0.0123).toString(16)", + js_string!("0.032617c1bda511a"), + ), TestAction::assert_eq( "Number(111111111111111111111).toString(16)", - "605f9f6dd18bc8000", + js_string!("605f9f6dd18bc8000"), ), TestAction::assert_eq( "Number(1111111111111111111111).toString(16)", - "3c3bc3a4a2f75c0000", + js_string!("3c3bc3a4a2f75c0000"), ), TestAction::assert_eq( "Number(11111111111111111111111).toString(16)", - "25a55a46e5da9a00000", + js_string!("25a55a46e5da9a00000"), + ), + TestAction::assert_eq( + "Number(0.00001).toString(16)", + js_string!("0.0000a7c5ac471b4788"), + ), + TestAction::assert_eq( + "Number(0.000001).toString(16)", + js_string!("0.000010c6f7a0b5ed8d"), + ), + TestAction::assert_eq( + "Number(0.0000001).toString(16)", + js_string!("0.000001ad7f29abcaf48"), + ), + TestAction::assert_eq( + "Number(0.00000012).toString(16)", + js_string!("0.000002036565348d256"), + ), + TestAction::assert_eq( + "Number(0.000000123).toString(16)", + js_string!("0.0000021047ee22aa466"), + ), + TestAction::assert_eq( + "Number(0.00000001).toString(16)", + js_string!("0.0000002af31dc4611874"), + ), + TestAction::assert_eq( + "Number(0.000000012).toString(16)", + js_string!("0.000000338a23b87483be"), ), - TestAction::assert_eq("Number(0.00001).toString(16)", "0.0000a7c5ac471b4788"), - TestAction::assert_eq("Number(0.000001).toString(16)", "0.000010c6f7a0b5ed8d"), - TestAction::assert_eq("Number(0.0000001).toString(16)", "0.000001ad7f29abcaf48"), - TestAction::assert_eq("Number(0.00000012).toString(16)", "0.000002036565348d256"), - TestAction::assert_eq("Number(0.000000123).toString(16)", "0.0000021047ee22aa466"), - TestAction::assert_eq("Number(0.00000001).toString(16)", "0.0000002af31dc4611874"), - TestAction::assert_eq("Number(0.000000012).toString(16)", "0.000000338a23b87483be"), TestAction::assert_eq( "Number(0.0000000123).toString(16)", - "0.00000034d3fe36aaa0a2", + js_string!("0.00000034d3fe36aaa0a2"), ), - TestAction::assert_eq("Number(-0).toString(16)", "0"), - TestAction::assert_eq("Number(-9).toString(16)", "-9"), + TestAction::assert_eq("Number(-0).toString(16)", js_string!("0")), + TestAction::assert_eq("Number(-9).toString(16)", js_string!("-9")), // - TestAction::assert_eq("Number(-90).toString(16)", "-5a"), - TestAction::assert_eq("Number(-90.12).toString(16)", "-5a.1eb851eb852"), - TestAction::assert_eq("Number(-0.1).toString(16)", "-0.1999999999999a"), - TestAction::assert_eq("Number(-0.01).toString(16)", "-0.028f5c28f5c28f6"), - TestAction::assert_eq("Number(-0.0123).toString(16)", "-0.032617c1bda511a"), + TestAction::assert_eq("Number(-90).toString(16)", js_string!("-5a")), + TestAction::assert_eq("Number(-90.12).toString(16)", js_string!("-5a.1eb851eb852")), + TestAction::assert_eq("Number(-0.1).toString(16)", js_string!("-0.1999999999999a")), + TestAction::assert_eq( + "Number(-0.01).toString(16)", + js_string!("-0.028f5c28f5c28f6"), + ), + TestAction::assert_eq( + "Number(-0.0123).toString(16)", + js_string!("-0.032617c1bda511a"), + ), TestAction::assert_eq( "Number(-111111111111111111111).toString(16)", - "-605f9f6dd18bc8000", + js_string!("-605f9f6dd18bc8000"), ), TestAction::assert_eq( "Number(-1111111111111111111111).toString(16)", - "-3c3bc3a4a2f75c0000", + js_string!("-3c3bc3a4a2f75c0000"), ), TestAction::assert_eq( "Number(-11111111111111111111111).toString(16)", - "-25a55a46e5da9a00000", + js_string!("-25a55a46e5da9a00000"), + ), + TestAction::assert_eq( + "Number(-0.00001).toString(16)", + js_string!("-0.0000a7c5ac471b4788"), + ), + TestAction::assert_eq( + "Number(-0.000001).toString(16)", + js_string!("-0.000010c6f7a0b5ed8d"), + ), + TestAction::assert_eq( + "Number(-0.0000001).toString(16)", + js_string!("-0.000001ad7f29abcaf48"), + ), + TestAction::assert_eq( + "Number(-0.00000012).toString(16)", + js_string!("-0.000002036565348d256"), ), - TestAction::assert_eq("Number(-0.00001).toString(16)", "-0.0000a7c5ac471b4788"), - TestAction::assert_eq("Number(-0.000001).toString(16)", "-0.000010c6f7a0b5ed8d"), - TestAction::assert_eq("Number(-0.0000001).toString(16)", "-0.000001ad7f29abcaf48"), - TestAction::assert_eq("Number(-0.00000012).toString(16)", "-0.000002036565348d256"), TestAction::assert_eq( "Number(-0.000000123).toString(16)", - "-0.0000021047ee22aa466", + js_string!("-0.0000021047ee22aa466"), ), TestAction::assert_eq( "Number(-0.00000001).toString(16)", - "-0.0000002af31dc4611874", + js_string!("-0.0000002af31dc4611874"), ), TestAction::assert_eq( "Number(-0.000000012).toString(16)", - "-0.000000338a23b87483be", + js_string!("-0.000000338a23b87483be"), ), TestAction::assert_eq( "Number(-0.0000000123).toString(16)", - "-0.00000034d3fe36aaa0a2", + js_string!("-0.00000034d3fe36aaa0a2"), ), ]); } @@ -177,26 +226,26 @@ fn to_string() { #[test] fn num_to_string_exponential() { run_test_actions([ - TestAction::assert_eq("(0).toString()", "0"), - TestAction::assert_eq("(-0).toString()", "0"), + TestAction::assert_eq("(0).toString()", js_string!("0")), + TestAction::assert_eq("(-0).toString()", js_string!("0")), TestAction::assert_eq( "(111111111111111111111).toString()", - "111111111111111110000", + js_string!("111111111111111110000"), ), TestAction::assert_eq( "(1111111111111111111111).toString()", - "1.1111111111111111e+21", + js_string!("1.1111111111111111e+21"), ), TestAction::assert_eq( "(11111111111111111111111).toString()", - "1.1111111111111111e+22", - ), - TestAction::assert_eq("(0.0000001).toString()", "1e-7"), - TestAction::assert_eq("(0.00000012).toString()", "1.2e-7"), - TestAction::assert_eq("(0.000000123).toString()", "1.23e-7"), - TestAction::assert_eq("(0.00000001).toString()", "1e-8"), - TestAction::assert_eq("(0.000000012).toString()", "1.2e-8"), - TestAction::assert_eq("(0.0000000123).toString()", "1.23e-8"), + js_string!("1.1111111111111111e+22"), + ), + TestAction::assert_eq("(0.0000001).toString()", js_string!("1e-7")), + TestAction::assert_eq("(0.00000012).toString()", js_string!("1.2e-7")), + TestAction::assert_eq("(0.000000123).toString()", js_string!("1.23e-7")), + TestAction::assert_eq("(0.00000001).toString()", js_string!("1e-8")), + TestAction::assert_eq("(0.000000012).toString()", js_string!("1.2e-8")), + TestAction::assert_eq("(0.0000000123).toString()", js_string!("1.23e-8")), ]); } @@ -475,7 +524,13 @@ fn number_is_safe_integer() { #[test] fn issue_2717() { run_test_actions([ - TestAction::assert_eq("(0.1600057092765239).toString(36)", "0.5rd85dm1ixq"), - TestAction::assert_eq("(0.23046743672210102).toString(36)", "0.8aoosla2phj"), + TestAction::assert_eq( + "(0.1600057092765239).toString(36)", + js_string!("0.5rd85dm1ixq"), + ), + TestAction::assert_eq( + "(0.23046743672210102).toString(36)", + js_string!("0.8aoosla2phj"), + ), ]); } diff --git a/boa_engine/src/builtins/object/for_in_iterator.rs b/boa_engine/src/builtins/object/for_in_iterator.rs index 44af9f42f1c..3d521ff6cb6 100644 --- a/boa_engine/src/builtins/object/for_in_iterator.rs +++ b/boa_engine/src/builtins/object/for_in_iterator.rs @@ -12,6 +12,7 @@ use crate::{ builtins::{iterable::create_iter_result_object, BuiltInBuilder, IntrinsicObject}, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::{JsObject, ObjectData}, property::PropertyKey, realm::Realm, @@ -39,7 +40,7 @@ pub struct ForInIterator { impl IntrinsicObject for ForInIterator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("ForInIterator", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -49,7 +50,7 @@ impl IntrinsicObject for ForInIterator { .iterator_prototypes() .iterator(), ) - .static_method(Self::next, "next", 0) + .static_method(Self::next, js_string!("next"), 0) .build(); } diff --git a/boa_engine/src/builtins/object/mod.rs b/boa_engine/src/builtins/object/mod.rs index 9bac6c64204..a74e6ab5250 100644 --- a/boa_engine/src/builtins/object/mod.rs +++ b/boa_engine/src/builtins/object/mod.rs @@ -28,7 +28,7 @@ use crate::{ }, property::{Attribute, PropertyDescriptor, PropertyKey, PropertyNameKind}, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsResult, JsString, @@ -46,14 +46,14 @@ pub struct Object; impl IntrinsicObject for Object { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let legacy_proto_getter = BuiltInBuilder::callable(realm, Self::legacy_proto_getter) - .name("get __proto__") + .name(js_string!("get __proto__")) .build(); let legacy_setter_proto = BuiltInBuilder::callable(realm, Self::legacy_proto_setter) - .name("set __proto__") + .name(js_string!("set __proto__")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -64,46 +64,74 @@ impl IntrinsicObject for Object { Some(legacy_setter_proto), Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .method(Self::has_own_property, "hasOwnProperty", 1) - .method(Self::property_is_enumerable, "propertyIsEnumerable", 1) - .method(Self::to_string, "toString", 0) - .method(Self::to_locale_string, "toLocaleString", 0) - .method(Self::value_of, "valueOf", 0) - .method(Self::is_prototype_of, "isPrototypeOf", 1) - .method(Self::legacy_define_getter, "__defineGetter__", 2) - .method(Self::legacy_define_setter, "__defineSetter__", 2) - .method(Self::legacy_lookup_getter, "__lookupGetter__", 1) - .method(Self::legacy_lookup_setter, "__lookupSetter__", 1) - .static_method(Self::create, "create", 2) - .static_method(Self::set_prototype_of, "setPrototypeOf", 2) - .static_method(Self::get_prototype_of, "getPrototypeOf", 1) - .static_method(Self::define_property, "defineProperty", 3) - .static_method(Self::define_properties, "defineProperties", 2) - .static_method(Self::assign, "assign", 2) - .static_method(Self::is, "is", 2) - .static_method(Self::keys, "keys", 1) - .static_method(Self::values, "values", 1) - .static_method(Self::entries, "entries", 1) - .static_method(Self::seal, "seal", 1) - .static_method(Self::is_sealed, "isSealed", 1) - .static_method(Self::freeze, "freeze", 1) - .static_method(Self::is_frozen, "isFrozen", 1) - .static_method(Self::prevent_extensions, "preventExtensions", 1) - .static_method(Self::is_extensible, "isExtensible", 1) + .method(Self::has_own_property, js_string!("hasOwnProperty"), 1) + .method( + Self::property_is_enumerable, + js_string!("propertyIsEnumerable"), + 1, + ) + .method(Self::to_string, js_string!("toString"), 0) + .method(Self::to_locale_string, js_string!("toLocaleString"), 0) + .method(Self::value_of, js_string!("valueOf"), 0) + .method(Self::is_prototype_of, js_string!("isPrototypeOf"), 1) + .method( + Self::legacy_define_getter, + js_string!("__defineGetter__"), + 2, + ) + .method( + Self::legacy_define_setter, + js_string!("__defineSetter__"), + 2, + ) + .method( + Self::legacy_lookup_getter, + js_string!("__lookupGetter__"), + 1, + ) + .method( + Self::legacy_lookup_setter, + js_string!("__lookupSetter__"), + 1, + ) + .static_method(Self::create, js_string!("create"), 2) + .static_method(Self::set_prototype_of, js_string!("setPrototypeOf"), 2) + .static_method(Self::get_prototype_of, js_string!("getPrototypeOf"), 1) + .static_method(Self::define_property, js_string!("defineProperty"), 3) + .static_method(Self::define_properties, js_string!("defineProperties"), 2) + .static_method(Self::assign, js_string!("assign"), 2) + .static_method(Self::is, js_string!("is"), 2) + .static_method(Self::keys, js_string!("keys"), 1) + .static_method(Self::values, js_string!("values"), 1) + .static_method(Self::entries, js_string!("entries"), 1) + .static_method(Self::seal, js_string!("seal"), 1) + .static_method(Self::is_sealed, js_string!("isSealed"), 1) + .static_method(Self::freeze, js_string!("freeze"), 1) + .static_method(Self::is_frozen, js_string!("isFrozen"), 1) + .static_method(Self::prevent_extensions, js_string!("preventExtensions"), 1) + .static_method(Self::is_extensible, js_string!("isExtensible"), 1) .static_method( Self::get_own_property_descriptor, - "getOwnPropertyDescriptor", + js_string!("getOwnPropertyDescriptor"), 2, ) .static_method( Self::get_own_property_descriptors, - "getOwnPropertyDescriptors", + js_string!("getOwnPropertyDescriptors"), + 1, + ) + .static_method( + Self::get_own_property_names, + js_string!("getOwnPropertyNames"), 1, ) - .static_method(Self::get_own_property_names, "getOwnPropertyNames", 1) - .static_method(Self::get_own_property_symbols, "getOwnPropertySymbols", 1) - .static_method(Self::has_own, "hasOwn", 2) - .static_method(Self::from_entries, "fromEntries", 1) + .static_method( + Self::get_own_property_symbols, + js_string!("getOwnPropertySymbols"), + 1, + ) + .static_method(Self::has_own, js_string!("hasOwn"), 2) + .static_method(Self::from_entries, js_string!("fromEntries"), 1) .build(); } @@ -113,7 +141,7 @@ impl IntrinsicObject for Object { } impl BuiltInObject for Object { - const NAME: &'static str = "Object"; + const NAME: JsString = StaticJsStrings::OBJECT; } impl BuiltInConstructor for Object { @@ -791,11 +819,11 @@ impl Object { ) -> JsResult { // 1. If the this value is undefined, return "[object Undefined]". if this.is_undefined() { - return Ok("[object Undefined]".into()); + return Ok(js_string!("[object Undefined]").into()); } // 2. If the this value is null, return "[object Null]". if this.is_null() { - return Ok("[object Null]".into()); + return Ok(js_string!("[object Null]").into()); } // 3. Let O be ! ToObject(this value). let o = this.to_object(context).expect("toObject cannot fail here"); @@ -1391,7 +1419,9 @@ fn get_own_property_keys( match (r#type, &next_key) { (PropertyKeyType::String, PropertyKey::String(_)) | (PropertyKeyType::Symbol, PropertyKey::Symbol(_)) => Some(next_key.into()), - (PropertyKeyType::String, PropertyKey::Index(index)) => Some(index.to_string().into()), + (PropertyKeyType::String, PropertyKey::Index(index)) => { + Some(js_string!(index.to_string()).into()) + } _ => None, } }); diff --git a/boa_engine/src/builtins/object/tests.rs b/boa_engine/src/builtins/object/tests.rs index b02d9d97bb2..17c42c1100f 100644 --- a/boa_engine/src/builtins/object/tests.rs +++ b/boa_engine/src/builtins/object/tests.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; use indoc::indoc; #[test] @@ -137,18 +137,21 @@ fn object_to_string() { "#}), TestAction::assert_eq( "Object.prototype.toString.call(undefined)", - "[object Undefined]", + js_string!("[object Undefined]"), ), - TestAction::assert_eq("Object.prototype.toString.call(null)", "[object Null]"), - TestAction::assert_eq("[].toString()", "[object Array]"), - TestAction::assert_eq("(() => {}).toString()", "[object Function]"), - TestAction::assert_eq("(new Error('')).toString()", "[object Error]"), - TestAction::assert_eq("Boolean().toString()", "[object Boolean]"), - TestAction::assert_eq("Number(42).toString()", "[object Number]"), - TestAction::assert_eq("String('boa').toString()", "[object String]"), - TestAction::assert_eq("(new Date()).toString()", "[object Date]"), - TestAction::assert_eq("/boa/.toString()", "[object RegExp]"), - TestAction::assert_eq("({}).toString()", "[object Object]"), + TestAction::assert_eq( + "Object.prototype.toString.call(null)", + js_string!("[object Null]"), + ), + TestAction::assert_eq("[].toString()", js_string!("[object Array]")), + TestAction::assert_eq("(() => {}).toString()", js_string!("[object Function]")), + TestAction::assert_eq("(new Error('')).toString()", js_string!("[object Error]")), + TestAction::assert_eq("Boolean().toString()", js_string!("[object Boolean]")), + TestAction::assert_eq("Number(42).toString()", js_string!("[object Number]")), + TestAction::assert_eq("String('boa').toString()", js_string!("[object String]")), + TestAction::assert_eq("(new Date()).toString()", js_string!("[object Date]")), + TestAction::assert_eq("/boa/.toString()", js_string!("[object RegExp]")), + TestAction::assert_eq("({}).toString()", js_string!("[object Object]")), ]); } @@ -160,7 +163,7 @@ fn define_symbol_property() { let sym = Symbol("key"); Object.defineProperty(obj, sym, { value: "val" }); "#}), - TestAction::assert_eq("obj[sym]", "val"), + TestAction::assert_eq("obj[sym]", js_string!("val")), ]); } diff --git a/boa_engine/src/builtins/promise/mod.rs b/boa_engine/src/builtins/promise/mod.rs index ae5504001be..01cb74f4d70 100644 --- a/boa_engine/src/builtins/promise/mod.rs +++ b/boa_engine/src/builtins/promise/mod.rs @@ -9,6 +9,7 @@ use crate::{ context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, job::{JobCallback, NativeJob}, + js_string, native_function::NativeFunction, object::{ internal_methods::get_prototype_from_constructor, FunctionObjectBuilder, JsFunction, @@ -16,10 +17,10 @@ use crate::{ }, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, value::JsValue, - Context, JsArgs, JsError, JsResult, + Context, JsArgs, JsError, JsResult, JsString, }; use boa_gc::{custom_trace, Finalize, Gc, GcRefCell, Trace}; use boa_profiler::Profiler; @@ -332,28 +333,28 @@ impl PromiseCapability { impl IntrinsicObject for Promise { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_species = BuiltInBuilder::callable(realm, Self::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); let builder = BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::all, "all", 1) - .static_method(Self::all_settled, "allSettled", 1) - .static_method(Self::any, "any", 1) - .static_method(Self::race, "race", 1) - .static_method(Self::reject, "reject", 1) - .static_method(Self::resolve, "resolve", 1) + .static_method(Self::all, js_string!("all"), 1) + .static_method(Self::all_settled, js_string!("allSettled"), 1) + .static_method(Self::any, js_string!("any"), 1) + .static_method(Self::race, js_string!("race"), 1) + .static_method(Self::reject, js_string!("reject"), 1) + .static_method(Self::resolve, js_string!("resolve"), 1) .static_accessor( JsSymbol::species(), Some(get_species), None, Attribute::CONFIGURABLE, ) - .method(Self::then, "then", 2) - .method(Self::catch, "catch", 1) - .method(Self::finally, "finally", 1) + .method(Self::then, js_string!("then"), 2) + .method(Self::catch, js_string!("catch"), 1) + .method(Self::finally, js_string!("finally"), 1) // .property( JsSymbol::to_string_tag(), @@ -374,7 +375,7 @@ impl IntrinsicObject for Promise { } impl BuiltInObject for Promise { - const NAME: &'static str = "Promise"; + const NAME: JsString = StaticJsStrings::PROMISE; } impl BuiltInConstructor for Promise { @@ -901,8 +902,12 @@ impl Promise { let obj = JsObject::with_object_proto(context.intrinsics()); // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "fulfilled"). - obj.create_data_property_or_throw(utf16!("status"), "fulfilled", context) - .expect("cannot fail per spec"); + obj.create_data_property_or_throw( + utf16!("status"), + js_string!("fulfilled"), + context, + ) + .expect("cannot fail per spec"); // 11. Perform ! CreateDataPropertyOrThrow(obj, "value", x). obj.create_data_property_or_throw( @@ -987,8 +992,12 @@ impl Promise { let obj = JsObject::with_object_proto(context.intrinsics()); // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "rejected"). - obj.create_data_property_or_throw(utf16!("status"), "rejected", context) - .expect("cannot fail per spec"); + obj.create_data_property_or_throw( + utf16!("status"), + js_string!("rejected"), + context, + ) + .expect("cannot fail per spec"); // 11. Perform ! CreateDataPropertyOrThrow(obj, "reason", x). obj.create_data_property_or_throw( diff --git a/boa_engine/src/builtins/proxy/mod.rs b/boa_engine/src/builtins/proxy/mod.rs index 9324ea6713f..cffdc4d84e7 100644 --- a/boa_engine/src/builtins/proxy/mod.rs +++ b/boa_engine/src/builtins/proxy/mod.rs @@ -14,11 +14,12 @@ use crate::{ builtins::BuiltInObject, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, native_function::NativeFunction, object::{FunctionObjectBuilder, JsFunction, JsObject, ObjectData}, realm::Realm, - string::utf16, - Context, JsArgs, JsResult, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, GcRefCell, Trace}; use boa_profiler::Profiler; @@ -33,10 +34,10 @@ pub struct Proxy { impl IntrinsicObject for Proxy { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::revocable, "revocable", 2) + .static_method(Self::revocable, js_string!("revocable"), 2) .build_without_prototype(); } @@ -46,7 +47,7 @@ impl IntrinsicObject for Proxy { } impl BuiltInObject for Proxy { - const NAME: &'static str = "Proxy"; + const NAME: JsString = StaticJsStrings::PROXY; } impl BuiltInConstructor for Proxy { diff --git a/boa_engine/src/builtins/reflect/mod.rs b/boa_engine/src/builtins/reflect/mod.rs index a0b2807fe0d..761573d8d07 100644 --- a/boa_engine/src/builtins/reflect/mod.rs +++ b/boa_engine/src/builtins/reflect/mod.rs @@ -15,11 +15,13 @@ use crate::{ builtins::{self, BuiltInObject}, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::JsObject, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, - Context, JsArgs, JsResult, JsValue, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; @@ -32,28 +34,28 @@ pub(crate) struct Reflect; impl IntrinsicObject for Reflect { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let to_string_tag = JsSymbol::to_string_tag(); BuiltInBuilder::with_intrinsic::(realm) - .static_method(Self::apply, "apply", 3) - .static_method(Self::construct, "construct", 2) - .static_method(Self::define_property, "defineProperty", 3) - .static_method(Self::delete_property, "deleteProperty", 2) - .static_method(Self::get, "get", 2) + .static_method(Self::apply, js_string!("apply"), 3) + .static_method(Self::construct, js_string!("construct"), 2) + .static_method(Self::define_property, js_string!("defineProperty"), 3) + .static_method(Self::delete_property, js_string!("deleteProperty"), 2) + .static_method(Self::get, js_string!("get"), 2) .static_method( Self::get_own_property_descriptor, - "getOwnPropertyDescriptor", + js_string!("getOwnPropertyDescriptor"), 2, ) - .static_method(Self::get_prototype_of, "getPrototypeOf", 1) - .static_method(Self::has, "has", 2) - .static_method(Self::is_extensible, "isExtensible", 1) - .static_method(Self::own_keys, "ownKeys", 1) - .static_method(Self::prevent_extensions, "preventExtensions", 1) - .static_method(Self::set, "set", 3) - .static_method(Self::set_prototype_of, "setPrototypeOf", 2) + .static_method(Self::get_prototype_of, js_string!("getPrototypeOf"), 1) + .static_method(Self::has, js_string!("has"), 2) + .static_method(Self::is_extensible, js_string!("isExtensible"), 1) + .static_method(Self::own_keys, js_string!("ownKeys"), 1) + .static_method(Self::prevent_extensions, js_string!("preventExtensions"), 1) + .static_method(Self::set, js_string!("set"), 3) + .static_method(Self::set_prototype_of, js_string!("setPrototypeOf"), 2) .static_property( to_string_tag, Self::NAME, @@ -68,7 +70,7 @@ impl IntrinsicObject for Reflect { } impl BuiltInObject for Reflect { - const NAME: &'static str = "Reflect"; + const NAME: JsString = StaticJsStrings::REFLECT; } impl Reflect { diff --git a/boa_engine/src/builtins/reflect/tests.rs b/boa_engine/src/builtins/reflect/tests.rs index 78f95fb1222..41798586c52 100644 --- a/boa_engine/src/builtins/reflect/tests.rs +++ b/boa_engine/src/builtins/reflect/tests.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsValue, TestAction}; use indoc::indoc; #[test] @@ -68,7 +68,10 @@ fn get_prototype_of() { function F() { this.p = 42 }; let f = new F(); "#}), - TestAction::assert_eq("Reflect.getPrototypeOf(f).constructor.name", "F"), + TestAction::assert_eq( + "Reflect.getPrototypeOf(f).constructor.name", + js_string!("F"), + ), ]); } @@ -131,6 +134,6 @@ fn set_prototype_of() { let obj = {} Reflect.setPrototypeOf(obj, F); "#}), - TestAction::assert_eq("Reflect.getPrototypeOf(obj).name", "F"), + TestAction::assert_eq("Reflect.getPrototypeOf(obj).name", js_string!("F")), ]); } diff --git a/boa_engine/src/builtins/regexp/mod.rs b/boa_engine/src/builtins/regexp/mod.rs index 2605970ee15..c5eff592ea5 100644 --- a/boa_engine/src/builtins/regexp/mod.rs +++ b/boa_engine/src/builtins/regexp/mod.rs @@ -20,7 +20,7 @@ use crate::{ }, property::{Attribute, PropertyDescriptorBuilder}, realm::Realm, - string::{utf16, CodePoint}, + string::{common::StaticJsStrings, utf16, CodePoint}, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsResult, JsString, @@ -49,40 +49,40 @@ pub struct RegExp { impl IntrinsicObject for RegExp { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_species = BuiltInBuilder::callable(realm, Self::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE; let get_has_indices = BuiltInBuilder::callable(realm, Self::get_has_indices) - .name("get hasIndices") + .name(js_string!("get hasIndices")) .build(); let get_global = BuiltInBuilder::callable(realm, Self::get_global) - .name("get global") + .name(js_string!("get global")) .build(); let get_ignore_case = BuiltInBuilder::callable(realm, Self::get_ignore_case) - .name("get ignoreCase") + .name(js_string!("get ignoreCase")) .build(); let get_multiline = BuiltInBuilder::callable(realm, Self::get_multiline) - .name("get multiline") + .name(js_string!("get multiline")) .build(); let get_dot_all = BuiltInBuilder::callable(realm, Self::get_dot_all) - .name("get dotAll") + .name(js_string!("get dotAll")) .build(); let get_unicode = BuiltInBuilder::callable(realm, Self::get_unicode) - .name("get unicode") + .name(js_string!("get unicode")) .build(); let get_sticky = BuiltInBuilder::callable(realm, Self::get_sticky) - .name("get sticky") + .name(js_string!("get sticky")) .build(); let get_flags = BuiltInBuilder::callable(realm, Self::get_flags) - .name("get flags") + .name(js_string!("get flags")) .build(); let get_source = BuiltInBuilder::callable(realm, Self::get_source) - .name("get source") + .name(js_string!("get source")) .build(); let regexp = BuiltInBuilder::from_standard_constructor::(realm) .static_accessor( @@ -91,46 +91,87 @@ impl IntrinsicObject for RegExp { None, Attribute::CONFIGURABLE, ) - .property(utf16!("lastIndex"), 0, Attribute::all()) - .method(Self::test, "test", 1) - .method(Self::exec, "exec", 1) - .method(Self::to_string, "toString", 0) - .method(Self::r#match, (JsSymbol::r#match(), "[Symbol.match]"), 1) + .property(js_string!("lastIndex"), 0, Attribute::all()) + .method(Self::test, js_string!("test"), 1) + .method(Self::exec, js_string!("exec"), 1) + .method(Self::to_string, js_string!("toString"), 0) + .method( + Self::r#match, + (JsSymbol::r#match(), js_string!("[Symbol.match]")), + 1, + ) .method( Self::match_all, - (JsSymbol::match_all(), "[Symbol.matchAll]"), + (JsSymbol::match_all(), js_string!("[Symbol.matchAll]")), + 1, + ) + .method( + Self::replace, + (JsSymbol::replace(), js_string!("[Symbol.replace]")), + 2, + ) + .method( + Self::search, + (JsSymbol::search(), js_string!("[Symbol.search]")), 1, ) - .method(Self::replace, (JsSymbol::replace(), "[Symbol.replace]"), 2) - .method(Self::search, (JsSymbol::search(), "[Symbol.search]"), 1) - .method(Self::split, (JsSymbol::split(), "[Symbol.split]"), 2) + .method( + Self::split, + (JsSymbol::split(), js_string!("[Symbol.split]")), + 2, + ) .accessor( - utf16!("hasIndices"), + js_string!("hasIndices"), Some(get_has_indices), None, flag_attributes, ) - .accessor(utf16!("global"), Some(get_global), None, flag_attributes) .accessor( - utf16!("ignoreCase"), + js_string!("global"), + Some(get_global), + None, + flag_attributes, + ) + .accessor( + js_string!("ignoreCase"), Some(get_ignore_case), None, flag_attributes, ) .accessor( - utf16!("multiline"), + js_string!("multiline"), Some(get_multiline), None, flag_attributes, ) - .accessor(utf16!("dotAll"), Some(get_dot_all), None, flag_attributes) - .accessor(utf16!("unicode"), Some(get_unicode), None, flag_attributes) - .accessor(utf16!("sticky"), Some(get_sticky), None, flag_attributes) - .accessor(utf16!("flags"), Some(get_flags), None, flag_attributes) - .accessor(utf16!("source"), Some(get_source), None, flag_attributes); + .accessor( + js_string!("dotAll"), + Some(get_dot_all), + None, + flag_attributes, + ) + .accessor( + js_string!("unicode"), + Some(get_unicode), + None, + flag_attributes, + ) + .accessor( + js_string!("sticky"), + Some(get_sticky), + None, + flag_attributes, + ) + .accessor(js_string!("flags"), Some(get_flags), None, flag_attributes) + .accessor( + js_string!("source"), + Some(get_source), + None, + flag_attributes, + ); #[cfg(feature = "annex-b")] - let regexp = regexp.method(Self::compile, "compile", 2); + let regexp = regexp.method(Self::compile, js_string!("compile"), 2); regexp.build(); } @@ -141,7 +182,7 @@ impl IntrinsicObject for RegExp { } impl BuiltInObject for RegExp { - const NAME: &'static str = "RegExp"; + const NAME: JsString = StaticJsStrings::REG_EXP; } impl BuiltInConstructor for RegExp { @@ -210,12 +251,12 @@ impl BuiltInConstructor for RegExp { (p, f) } else if let Some(pattern) = pattern_is_regexp { // a. Let P be ? Get(pattern, "source"). - let p = pattern.get("source", context)?; + let p = pattern.get(js_string!("source"), context)?; // b. If flags is undefined, then let f = if flags.is_undefined() { // i. Let F be ? Get(pattern, "flags"). - pattern.get("flags", context)? + pattern.get(js_string!("flags"), context)? // c. Else, } else { // i. Let F be flags. @@ -641,7 +682,7 @@ impl RegExp { } // 18. Return result. - return Ok(result.into()); + return Ok(js_string!(result).into()); } Err(JsNativeError::typ() @@ -684,7 +725,7 @@ impl RegExp { this, &JsValue::new(context.intrinsics().constructors().regexp().prototype()), ) { - Ok(JsValue::new("(?:)")) + Ok(JsValue::new(js_string!("(?:)"))) } else { Err(JsNativeError::typ() .with_message("RegExp.prototype.source method called on incompatible value") @@ -1064,12 +1105,13 @@ impl RegExp { // ii. Perform ! CreateDataPropertyOrThrow(groups, s, capturedValue). // iii. Append s to groupNames. for (name, range) in named_groups { + let name = js_string!(name); if let Some(range) = range { // TODO: Full UTF-16 regex support let value = js_string!(&lossy_input[range.clone()]); groups - .create_data_property_or_throw(name, value, context) + .create_data_property_or_throw(name.clone(), value, context) .expect("this CreateDataPropertyOrThrow call must not fail"); // 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups ) @@ -1079,7 +1121,7 @@ impl RegExp { // d. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(i)), matchIndexPair). group_names .create_data_property_or_throw( - name, + name.clone(), Array::create_array_from_list( [range.start.into(), range.end.into()], context, @@ -1089,7 +1131,7 @@ impl RegExp { .expect("this CreateDataPropertyOrThrow call must not fail"); } else { groups - .create_data_property_or_throw(name, JsValue::undefined(), context) + .create_data_property_or_throw(name.clone(), JsValue::undefined(), context) .expect("this CreateDataPropertyOrThrow call must not fail"); // 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups ) diff --git a/boa_engine/src/builtins/regexp/regexp_string_iterator.rs b/boa_engine/src/builtins/regexp/regexp_string_iterator.rs index 0a16d673cf7..10d668acba6 100644 --- a/boa_engine/src/builtins/regexp/regexp_string_iterator.rs +++ b/boa_engine/src/builtins/regexp/regexp_string_iterator.rs @@ -14,6 +14,7 @@ use crate::{ builtins::{iterable::create_iter_result_object, regexp, BuiltInBuilder, IntrinsicObject}, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::{JsObject, ObjectData}, property::Attribute, realm::Realm, @@ -42,7 +43,7 @@ pub struct RegExpStringIterator { impl IntrinsicObject for RegExpStringIterator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("RegExpStringIterator", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -52,10 +53,10 @@ impl IntrinsicObject for RegExpStringIterator { .iterator_prototypes() .iterator(), ) - .static_method(Self::next, "next", 0) + .static_method(Self::next, js_string!("next"), 0) .static_property( JsSymbol::to_string_tag(), - "RegExp String Iterator", + js_string!("RegExp String Iterator"), Attribute::CONFIGURABLE, ) .build(); diff --git a/boa_engine/src/builtins/regexp/tests.rs b/boa_engine/src/builtins/regexp/tests.rs index 4de00352164..610185df759 100644 --- a/boa_engine/src/builtins/regexp/tests.rs +++ b/boa_engine/src/builtins/regexp/tests.rs @@ -1,4 +1,6 @@ -use crate::{object::JsObject, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{ + js_string, object::JsObject, run_test_actions, JsNativeErrorKind, JsValue, TestAction, +}; use indoc::indoc; #[test] @@ -33,7 +35,7 @@ fn species() { // return-value TestAction::assert("Object.is(accessor.call(thisVal), thisVal)"), // symbol-species-name - TestAction::assert_eq("name.value", "get [Symbol.species]"), + TestAction::assert_eq("name.value", js_string!("get [Symbol.species]")), TestAction::assert("!name.enumerable"), TestAction::assert("!name.writable"), TestAction::assert("name.configurable"), @@ -61,7 +63,7 @@ fn flags() { TestAction::assert("!re_gi.dotAll"), TestAction::assert("!re_gi.unicode"), TestAction::assert("!re_gi.sticky"), - TestAction::assert_eq("re_gi.flags", "gi"), + TestAction::assert_eq("re_gi.flags", js_string!("gi")), // TestAction::assert("!re_sm.global"), TestAction::assert("!re_sm.ignoreCase"), @@ -69,7 +71,7 @@ fn flags() { TestAction::assert("re_sm.dotAll"), TestAction::assert("!re_sm.unicode"), TestAction::assert("!re_sm.sticky"), - TestAction::assert_eq("re_sm.flags", "ms"), + TestAction::assert_eq("re_sm.flags", js_string!("ms")), // TestAction::assert("!re_u.global"), TestAction::assert("!re_u.ignoreCase"), @@ -77,7 +79,7 @@ fn flags() { TestAction::assert("!re_u.dotAll"), TestAction::assert("re_u.unicode"), TestAction::assert("!re_u.sticky"), - TestAction::assert_eq("re_u.flags", "u"), + TestAction::assert_eq("re_u.flags", js_string!("u")), ]); } @@ -110,7 +112,7 @@ fn exec() { TestAction::assert_eq("result.index", 4), TestAction::assert_eq( "result.input", - "The Quick Brown Fox Jumps Over The Lazy Dog", + js_string!("The Quick Brown Fox Jumps Over The Lazy Dog"), ), ]); } @@ -134,11 +136,11 @@ fn no_panic_on_parse_fail() { #[test] fn to_string() { run_test_actions([ - TestAction::assert_eq("(new RegExp('a+b+c')).toString()", "/a+b+c/"), - TestAction::assert_eq("(new RegExp('bar', 'g')).toString()", "/bar/g"), - TestAction::assert_eq(r"(new RegExp('\\n', 'g')).toString()", r"/\n/g"), - TestAction::assert_eq(r"/\n/g.toString()", r"/\n/g"), - TestAction::assert_eq(r"/,\;/.toString()", r"/,\;/"), + TestAction::assert_eq("(new RegExp('a+b+c')).toString()", js_string!("/a+b+c/")), + TestAction::assert_eq("(new RegExp('bar', 'g')).toString()", js_string!("/bar/g")), + TestAction::assert_eq(r"(new RegExp('\\n', 'g')).toString()", js_string!(r"/\n/g")), + TestAction::assert_eq(r"/\n/g.toString()", js_string!(r"/\n/g")), + TestAction::assert_eq(r"/,\;/.toString()", js_string!(r"/,\;/")), ]); } #[test] @@ -160,7 +162,7 @@ fn search() { TestAction::assert("!length.writable"), TestAction::assert("length.configurable"), // name - TestAction::assert_eq("name.value", "[Symbol.search]"), + TestAction::assert_eq("name.value", js_string!("[Symbol.search]")), TestAction::assert("!name.enumerable"), TestAction::assert("!name.writable"), TestAction::assert("name.configurable"), diff --git a/boa_engine/src/builtins/set/mod.rs b/boa_engine/src/builtins/set/mod.rs index 3352f97e091..908cd668219 100644 --- a/boa_engine/src/builtins/set/mod.rs +++ b/boa_engine/src/builtins/set/mod.rs @@ -22,12 +22,13 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::{Attribute, PropertyNameKind}, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, - Context, JsArgs, JsResult, JsValue, + Context, JsArgs, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; use num_traits::Zero; @@ -42,18 +43,18 @@ impl IntrinsicObject for Set { Self::STANDARD_CONSTRUCTOR(intrinsics.constructors()).constructor() } fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_species = BuiltInBuilder::callable(realm, Self::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); let size_getter = BuiltInBuilder::callable(realm, Self::size_getter) - .name("get size") + .name(js_string!("get size")) .build(); let values_function = BuiltInBuilder::callable(realm, Self::values) - .name("values") + .name(js_string!("values")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -63,12 +64,12 @@ impl IntrinsicObject for Set { None, Attribute::CONFIGURABLE, ) - .method(Self::add, "add", 1) - .method(Self::clear, "clear", 0) - .method(Self::delete, "delete", 1) - .method(Self::entries, "entries", 0) - .method(Self::for_each, "forEach", 1) - .method(Self::has, "has", 1) + .method(Self::add, js_string!("add"), 1) + .method(Self::clear, js_string!("clear"), 0) + .method(Self::delete, js_string!("delete"), 1) + .method(Self::entries, js_string!("entries"), 0) + .method(Self::for_each, js_string!("forEach"), 1) + .method(Self::has, js_string!("has"), 1) .property( utf16!("keys"), values_function.clone(), @@ -100,7 +101,7 @@ impl IntrinsicObject for Set { } impl BuiltInObject for Set { - const NAME: &'static str = "Set"; + const NAME: JsString = StaticJsStrings::SET; } impl BuiltInConstructor for Set { diff --git a/boa_engine/src/builtins/set/set_iterator.rs b/boa_engine/src/builtins/set/set_iterator.rs index 514331bb4a0..30de1cfe029 100644 --- a/boa_engine/src/builtins/set/set_iterator.rs +++ b/boa_engine/src/builtins/set/set_iterator.rs @@ -12,6 +12,7 @@ use crate::{ }, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::{JsObject, ObjectData}, property::{Attribute, PropertyNameKind}, realm::Realm, @@ -38,7 +39,7 @@ pub struct SetIterator { impl IntrinsicObject for SetIterator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("SetIterator", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -48,10 +49,10 @@ impl IntrinsicObject for SetIterator { .iterator_prototypes() .iterator(), ) - .static_method(Self::next, "next", 0) + .static_method(Self::next, js_string!("next"), 0) .static_property( JsSymbol::to_string_tag(), - "Set Iterator", + js_string!("Set Iterator"), Attribute::CONFIGURABLE, ) .build(); diff --git a/boa_engine/src/builtins/string/mod.rs b/boa_engine/src/builtins/string/mod.rs index 1d21b32f535..fb3c76e20e6 100644 --- a/boa_engine/src/builtins/string/mod.rs +++ b/boa_engine/src/builtins/string/mod.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::{Attribute, PropertyDescriptor}, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, string::{CodePoint, Utf16Trim}, symbol::JsSymbol, value::IntegerOrInfinity, @@ -76,18 +76,18 @@ pub(crate) struct String; impl IntrinsicObject for String { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let symbol_iterator = JsSymbol::iterator(); let trim_start = BuiltInBuilder::callable(realm, Self::trim_start) .length(0) - .name("trimStart") + .name(js_string!("trimStart")) .build(); let trim_end = BuiltInBuilder::callable(realm, Self::trim_end) .length(0) - .name("trimEnd") + .name(js_string!("trimEnd")) .build(); #[cfg(feature = "annex-b")] @@ -98,81 +98,93 @@ impl IntrinsicObject for String { let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; let builder = BuiltInBuilder::from_standard_constructor::(realm) - .property(utf16!("length"), 0, attribute) + .property(js_string!("length"), 0, attribute) .property( - utf16!("trimStart"), + js_string!("trimStart"), trim_start, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - utf16!("trimEnd"), + js_string!("trimEnd"), trim_end, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .static_method(Self::raw, "raw", 1) - .static_method(Self::from_char_code, "fromCharCode", 1) - .static_method(Self::from_code_point, "fromCodePoint", 1) - .method(Self::char_at, "charAt", 1) - .method(Self::char_code_at, "charCodeAt", 1) - .method(Self::code_point_at, "codePointAt", 1) - .method(Self::to_string, "toString", 0) - .method(Self::concat, "concat", 1) - .method(Self::repeat, "repeat", 1) - .method(Self::slice, "slice", 2) - .method(Self::starts_with, "startsWith", 1) - .method(Self::ends_with, "endsWith", 1) - .method(Self::includes, "includes", 1) - .method(Self::index_of, "indexOf", 1) - .method(Self::is_well_formed, "isWellFormed", 0) - .method(Self::last_index_of, "lastIndexOf", 1) - .method(Self::locale_compare, "localeCompare", 1) - .method(Self::r#match, "match", 1) - .method(Self::normalize, "normalize", 0) - .method(Self::pad_end, "padEnd", 1) - .method(Self::pad_start, "padStart", 1) - .method(Self::trim, "trim", 0) - .method(Self::to_case::, "toLowerCase", 0) - .method(Self::to_case::, "toUpperCase", 0) - .method(Self::to_well_formed, "toWellFormed", 0) - .method(Self::to_locale_case::, "toLocaleLowerCase", 0) - .method(Self::to_locale_case::, "toLocaleUpperCase", 0) - .method(Self::substring, "substring", 2) - .method(Self::split, "split", 2) - .method(Self::value_of, "valueOf", 0) - .method(Self::match_all, "matchAll", 1) - .method(Self::replace, "replace", 2) - .method(Self::replace_all, "replaceAll", 2) - .method(Self::iterator, (symbol_iterator, "[Symbol.iterator]"), 0) - .method(Self::search, "search", 1) - .method(Self::at, "at", 1); + .static_method(Self::raw, js_string!("raw"), 1) + .static_method(Self::from_char_code, js_string!("fromCharCode"), 1) + .static_method(Self::from_code_point, js_string!("fromCodePoint"), 1) + .method(Self::char_at, js_string!("charAt"), 1) + .method(Self::char_code_at, js_string!("charCodeAt"), 1) + .method(Self::code_point_at, js_string!("codePointAt"), 1) + .method(Self::to_string, js_string!("toString"), 0) + .method(Self::concat, js_string!("concat"), 1) + .method(Self::repeat, js_string!("repeat"), 1) + .method(Self::slice, js_string!("slice"), 2) + .method(Self::starts_with, js_string!("startsWith"), 1) + .method(Self::ends_with, js_string!("endsWith"), 1) + .method(Self::includes, js_string!("includes"), 1) + .method(Self::index_of, js_string!("indexOf"), 1) + .method(Self::is_well_formed, js_string!("isWellFormed"), 0) + .method(Self::last_index_of, js_string!("lastIndexOf"), 1) + .method(Self::locale_compare, js_string!("localeCompare"), 1) + .method(Self::r#match, js_string!("match"), 1) + .method(Self::normalize, js_string!("normalize"), 0) + .method(Self::pad_end, js_string!("padEnd"), 1) + .method(Self::pad_start, js_string!("padStart"), 1) + .method(Self::trim, js_string!("trim"), 0) + .method(Self::to_case::, js_string!("toLowerCase"), 0) + .method(Self::to_case::, js_string!("toUpperCase"), 0) + .method(Self::to_well_formed, js_string!("toWellFormed"), 0) + .method( + Self::to_locale_case::, + js_string!("toLocaleLowerCase"), + 0, + ) + .method( + Self::to_locale_case::, + js_string!("toLocaleUpperCase"), + 0, + ) + .method(Self::substring, js_string!("substring"), 2) + .method(Self::split, js_string!("split"), 2) + .method(Self::value_of, js_string!("valueOf"), 0) + .method(Self::match_all, js_string!("matchAll"), 1) + .method(Self::replace, js_string!("replace"), 2) + .method(Self::replace_all, js_string!("replaceAll"), 2) + .method( + Self::iterator, + (symbol_iterator, js_string!("[Symbol.iterator]")), + 0, + ) + .method(Self::search, js_string!("search"), 1) + .method(Self::at, js_string!("at"), 1); #[cfg(feature = "annex-b")] let builder = { builder .property( - utf16!("trimLeft"), + js_string!("trimLeft"), trim_left, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - utf16!("trimRight"), + js_string!("trimRight"), trim_right, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .method(Self::substr, "substr", 2) - .method(Self::anchor, "anchor", 1) - .method(Self::big, "big", 0) - .method(Self::blink, "blink", 0) - .method(Self::bold, "bold", 0) - .method(Self::fixed, "fixed", 0) - .method(Self::fontcolor, "fontcolor", 1) - .method(Self::fontsize, "fontsize", 1) - .method(Self::italics, "italics", 0) - .method(Self::link, "link", 1) - .method(Self::small, "small", 0) - .method(Self::strike, "strike", 0) - .method(Self::sub, "sub", 0) - .method(Self::sup, "sup", 0) + .method(Self::substr, js_string!("substr"), 2) + .method(Self::anchor, js_string!("anchor"), 1) + .method(Self::big, js_string!("big"), 0) + .method(Self::blink, js_string!("blink"), 0) + .method(Self::bold, js_string!("bold"), 0) + .method(Self::fixed, js_string!("fixed"), 0) + .method(Self::fontcolor, js_string!("fontcolor"), 1) + .method(Self::fontsize, js_string!("fontsize"), 1) + .method(Self::italics, js_string!("italics"), 0) + .method(Self::link, js_string!("link"), 1) + .method(Self::small, js_string!("small"), 0) + .method(Self::strike, js_string!("strike"), 0) + .method(Self::sub, js_string!("sub"), 0) + .method(Self::sup, js_string!("sup"), 0) }; builder.build(); @@ -184,7 +196,7 @@ impl IntrinsicObject for String { } impl BuiltInObject for String { - const NAME: &'static str = "String"; + const NAME: JsString = StaticJsStrings::STRING; } impl BuiltInConstructor for String { @@ -1835,7 +1847,7 @@ impl String { .collect::(); // 7. Return result. - Ok(result.into()) + Ok(js_string!(result).into()) } /// `String.prototype.substring( indexStart[, indexEnd] )` diff --git a/boa_engine/src/builtins/string/string_iterator.rs b/boa_engine/src/builtins/string/string_iterator.rs index 52a8083a338..129e60257d1 100644 --- a/boa_engine/src/builtins/string/string_iterator.rs +++ b/boa_engine/src/builtins/string/string_iterator.rs @@ -33,7 +33,7 @@ pub struct StringIterator { impl IntrinsicObject for StringIterator { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event("StringIterator", "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .prototype( @@ -43,10 +43,10 @@ impl IntrinsicObject for StringIterator { .iterator_prototypes() .iterator(), ) - .static_method(Self::next, "next", 0) + .static_method(Self::next, js_string!("next"), 0) .static_property( JsSymbol::to_string_tag(), - "String Iterator", + js_string!("String Iterator"), Attribute::CONFIGURABLE, ) .build(); diff --git a/boa_engine/src/builtins/string/tests.rs b/boa_engine/src/builtins/string/tests.rs index 5a1e918496b..5adc115c196 100644 --- a/boa_engine/src/builtins/string/tests.rs +++ b/boa_engine/src/builtins/string/tests.rs @@ -56,9 +56,12 @@ fn concat() { "#}), TestAction::assert_eq( "hello.concat(world, nice)", - "Hello, world! Have a nice day.", + js_string!("Hello, world! Have a nice day."), + ), + TestAction::assert_eq( + "hello + world + nice", + js_string!("Hello, world! Have a nice day."), ), - TestAction::assert_eq("hello + world + nice", "Hello, world! Have a nice day."), ]); } @@ -69,7 +72,10 @@ fn generic_concat() { Number.prototype.concat = String.prototype.concat; let number = new Number(100); "#}), - TestAction::assert_eq("number.concat(' - 50', ' = 50')", "100 - 50 = 50"), + TestAction::assert_eq( + "number.concat(' - 50', ' = 50')", + js_string!("100 - 50 = 50"), + ), ]); } @@ -90,12 +96,12 @@ fn repeat() { var en = new String('english'); var zh = new String('中文'); "#}), - TestAction::assert_eq("empty.repeat(0)", ""), - TestAction::assert_eq("empty.repeat(1)", ""), - TestAction::assert_eq("en.repeat(0)", ""), - TestAction::assert_eq("zh.repeat(0)", ""), - TestAction::assert_eq("en.repeat(1)", "english"), - TestAction::assert_eq("zh.repeat(2)", "中文中文"), + TestAction::assert_eq("empty.repeat(0)", js_string!()), + TestAction::assert_eq("empty.repeat(1)", js_string!()), + TestAction::assert_eq("en.repeat(0)", js_string!()), + TestAction::assert_eq("zh.repeat(0)", js_string!()), + TestAction::assert_eq("en.repeat(1)", js_string!("english")), + TestAction::assert_eq("zh.repeat(2)", js_string!("中文中文")), ]); } @@ -133,10 +139,10 @@ fn repeat_throws_when_count_overflows_max_length() { fn repeat_generic() { run_test_actions([ TestAction::run("Number.prototype.repeat = String.prototype.repeat;"), - TestAction::assert_eq("(0).repeat(0)", ""), - TestAction::assert_eq("(1).repeat(1)", "1"), - TestAction::assert_eq("(1).repeat(5)", "11111"), - TestAction::assert_eq("(12).repeat(3)", "121212"), + TestAction::assert_eq("(0).repeat(0)", js_string!()), + TestAction::assert_eq("(1).repeat(1)", js_string!("1")), + TestAction::assert_eq("(1).repeat(5)", js_string!("11111")), + TestAction::assert_eq("(12).repeat(3)", js_string!("121212")), ]); } @@ -146,7 +152,7 @@ fn replace() { indoc! {r#" "abc".replace("a", "2") "#}, - "2bc", + js_string!("2bc"), )]); } @@ -156,7 +162,7 @@ fn replace_no_match() { indoc! {r#" "abc".replace(/d/, "$&$&") "#}, - "abc", + js_string!("abc"), )]); } @@ -166,7 +172,7 @@ fn replace_with_capture_groups() { indoc! {r#" "John Smith".replace(/(\w+)\s(\w+)/, '$2, $1') "#}, - "Smith, John", + js_string!("Smith, John"), )]); } @@ -177,7 +183,7 @@ fn replace_with_tenth_capture_group() { var re = /(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)/; "0123456789".replace(re, '$10') "#}, - "9", + js_string!("9"), )]); } @@ -193,11 +199,11 @@ fn replace_substitutions() { var end = a.replace(re, " $' "); var no_sub = a.replace(re, " $_ "); "#}), - TestAction::assert_eq("a.replace(re, \" $$ \")", "one $ three"), - TestAction::assert_eq("a.replace(re, \"$&$&\")", "one two two three"), - TestAction::assert_eq("a.replace(re, \" $` \")", "one one three"), - TestAction::assert_eq("a.replace(re, \" $' \")", "one three three"), - TestAction::assert_eq("a.replace(re, \" $_ \")", "one $_ three"), + TestAction::assert_eq("a.replace(re, \" $$ \")", js_string!("one $ three")), + TestAction::assert_eq("a.replace(re, \"$&$&\")", js_string!("one two two three")), + TestAction::assert_eq("a.replace(re, \" $` \")", js_string!("one one three")), + TestAction::assert_eq("a.replace(re, \" $' \")", js_string!("one three three")), + TestAction::assert_eq("a.replace(re, \" $_ \")", js_string!("one $_ three")), ]); } @@ -216,11 +222,11 @@ fn replace_with_function() { "#}), TestAction::assert_eq( "\"ecmascript is cool\".replace(/c(o)(o)(l)/, replacer)", - "ecmascript is awesome!", + js_string!("ecmascript is awesome!"), ), - TestAction::assert_eq("p1", "o"), - TestAction::assert_eq("p2", "o"), - TestAction::assert_eq("p3", "l"), + TestAction::assert_eq("p1", js_string!("o")), + TestAction::assert_eq("p2", js_string!("o")), + TestAction::assert_eq("p3", js_string!("l")), TestAction::assert_eq("length", 14), ]); } @@ -323,7 +329,7 @@ fn match_all_one() { ) "#}), TestAction::assert_eq("m1.value.index", 0), - TestAction::assert_eq("m1.value.input", "test1test2"), + TestAction::assert_eq("m1.value.input", js_string!("test1test2")), TestAction::assert_eq("m1.value.groups", JsValue::undefined()), TestAction::assert(indoc! {r#" arrayEquals( @@ -332,7 +338,7 @@ fn match_all_one() { ) "#}), TestAction::assert_eq("m2.value.index", 5), - TestAction::assert_eq("m2.value.input", "test1test2"), + TestAction::assert_eq("m2.value.input", js_string!("test1test2")), TestAction::assert_eq("m2.value.groups", JsValue::undefined()), TestAction::assert_eq("m3.value", JsValue::undefined()), ]); @@ -360,7 +366,7 @@ fn match_all_two() { ) "#}), TestAction::assert_eq("m1.value.index", 6), - TestAction::assert_eq("m1.value.input", "table football, foosball"), + TestAction::assert_eq("m1.value.input", js_string!("table football, foosball")), TestAction::assert_eq("m1.value.groups", JsValue::undefined()), TestAction::assert(indoc! {r#" arrayEquals( @@ -369,7 +375,7 @@ fn match_all_two() { ) "#}), TestAction::assert_eq("m2.value.index", 16), - TestAction::assert_eq("m2.value.input", "table football, foosball"), + TestAction::assert_eq("m2.value.input", js_string!("table football, foosball")), TestAction::assert_eq("m2.value.groups", JsValue::undefined()), TestAction::assert_eq("m3.value", JsValue::undefined()), ]); @@ -395,7 +401,7 @@ fn test_match() { TestAction::assert_eq("result1.index", 4), TestAction::assert_eq( "result1.input", - "The Quick Brown Fox Jumps Over The Lazy Dog", + js_string!("The Quick Brown Fox Jumps Over The Lazy Dog"), ), TestAction::assert(indoc! {r#" arrayEquals( @@ -412,7 +418,7 @@ fn test_match() { TestAction::assert_eq("result3.index", 0), TestAction::assert_eq( "result3.input", - "The Quick Brown Fox Jumps Over The Lazy Dog", + js_string!("The Quick Brown Fox Jumps Over The Lazy Dog"), ), TestAction::assert(indoc! {r#" arrayEquals( @@ -426,30 +432,30 @@ fn test_match() { #[test] fn trim() { run_test_actions([ - TestAction::assert_eq(r"'Hello'.trim()", "Hello"), - TestAction::assert_eq(r"' \nHello'.trim()", "Hello"), - TestAction::assert_eq(r"'Hello \n\r'.trim()", "Hello"), - TestAction::assert_eq(r"' Hello '.trim()", "Hello"), + TestAction::assert_eq(r"'Hello'.trim()", js_string!("Hello")), + TestAction::assert_eq(r"' \nHello'.trim()", js_string!("Hello")), + TestAction::assert_eq(r"'Hello \n\r'.trim()", js_string!("Hello")), + TestAction::assert_eq(r"' Hello '.trim()", js_string!("Hello")), ]); } #[test] fn trim_start() { run_test_actions([ - TestAction::assert_eq(r"'Hello'.trimStart()", "Hello"), - TestAction::assert_eq(r"' \nHello'.trimStart()", "Hello"), - TestAction::assert_eq(r"'Hello \n\r'.trimStart()", "Hello \n\r"), - TestAction::assert_eq(r"' Hello '.trimStart()", "Hello "), + TestAction::assert_eq(r"'Hello'.trimStart()", js_string!("Hello")), + TestAction::assert_eq(r"' \nHello'.trimStart()", js_string!("Hello")), + TestAction::assert_eq(r"'Hello \n\r'.trimStart()", js_string!("Hello \n\r")), + TestAction::assert_eq(r"' Hello '.trimStart()", js_string!("Hello ")), ]); } #[test] fn trim_end() { run_test_actions([ - TestAction::assert_eq(r"'Hello'.trimEnd()", "Hello"), - TestAction::assert_eq(r"' \nHello'.trimEnd()", " \nHello"), - TestAction::assert_eq(r"'Hello \n\r'.trimEnd()", "Hello"), - TestAction::assert_eq(r"' Hello '.trimEnd()", " Hello"), + TestAction::assert_eq(r"'Hello'.trimEnd()", js_string!("Hello")), + TestAction::assert_eq(r"' \nHello'.trimEnd()", js_string!(" \nHello")), + TestAction::assert_eq(r"'Hello \n\r'.trimEnd()", js_string!("Hello")), + TestAction::assert_eq(r"' Hello '.trimEnd()", js_string!(" Hello")), ]); } @@ -572,7 +578,7 @@ fn split_with_symbol_split_method() { sep_a[Symbol.split] = function(s, limit) { return s + limit.toString(); }; 'hello'.split(sep_a, 10) "#}, - "hello10", + js_string!("hello10"), ), TestAction::assert(indoc! {r#" let sep_b = {}; @@ -745,11 +751,11 @@ fn last_index_non_integer_position_argument() { #[test] fn char_at() { run_test_actions([ - TestAction::assert_eq("'abc'.charAt(-1)", ""), - TestAction::assert_eq("'abc'.charAt(1)", "b"), - TestAction::assert_eq("'abc'.charAt(9)", ""), - TestAction::assert_eq("'abc'.charAt()", "a"), - TestAction::assert_eq("'abc'.charAt(null)", "a"), + TestAction::assert_eq("'abc'.charAt(-1)", js_string!()), + TestAction::assert_eq("'abc'.charAt(1)", js_string!("b")), + TestAction::assert_eq("'abc'.charAt(9)", js_string!()), + TestAction::assert_eq("'abc'.charAt()", js_string!("a")), + TestAction::assert_eq("'abc'.charAt(null)", js_string!("a")), TestAction::assert_eq(r"'\uDBFF'.charAt(0)", js_string!(&[0xDBFFu16])), ]); } @@ -788,11 +794,11 @@ fn code_point_at() { #[test] fn slice() { run_test_actions([ - TestAction::assert_eq("'abc'.slice()", "abc"), - TestAction::assert_eq("'abc'.slice(1)", "bc"), - TestAction::assert_eq("'abc'.slice(-1)", "c"), - TestAction::assert_eq("'abc'.slice(0, 9)", "abc"), - TestAction::assert_eq("'abc'.slice(9, 10)", ""), + TestAction::assert_eq("'abc'.slice()", js_string!("abc")), + TestAction::assert_eq("'abc'.slice(1)", js_string!("bc")), + TestAction::assert_eq("'abc'.slice(-1)", js_string!("c")), + TestAction::assert_eq("'abc'.slice(0, 9)", js_string!("abc")), + TestAction::assert_eq("'abc'.slice(9, 10)", js_string!()), ]); } @@ -838,8 +844,8 @@ fn unicode_iter() { fn string_get_property() { run_test_actions([ TestAction::assert_eq("'abc'[-1]", JsValue::undefined()), - TestAction::assert_eq("'abc'[1]", "b"), - TestAction::assert_eq("'abc'[2]", "c"), + TestAction::assert_eq("'abc'[1]", js_string!("b")), + TestAction::assert_eq("'abc'[2]", js_string!("c")), TestAction::assert_eq("'abc'[3]", JsValue::undefined()), TestAction::assert_eq("'abc'['foo']", JsValue::undefined()), TestAction::assert_eq("'😀'[0]", js_string!(&[0xD83D])), @@ -860,9 +866,9 @@ fn search() { fn from_code_point() { // Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint run_test_actions([ - TestAction::assert_eq("String.fromCodePoint(42)", "*"), - TestAction::assert_eq("String.fromCodePoint(65, 90)", "AZ"), - TestAction::assert_eq("String.fromCodePoint(0x404)", "Є"), + TestAction::assert_eq("String.fromCodePoint(42)", js_string!("*")), + TestAction::assert_eq("String.fromCodePoint(65, 90)", js_string!("AZ")), + TestAction::assert_eq("String.fromCodePoint(0x404)", js_string!("Є")), TestAction::assert_eq( "String.fromCodePoint(0x2f804)", js_string!(&[0xD87E, 0xDC04]), @@ -876,7 +882,10 @@ fn from_code_point() { "String.fromCharCode(0xD800, 0xD8FF)", js_string!(&[0xD800, 0xD8FF]), ), - TestAction::assert_eq("String.fromCodePoint(9731, 9733, 9842, 0x4F60)", "☃★♲你"), + TestAction::assert_eq( + "String.fromCodePoint(9731, 9733, 9842, 0x4F60)", + js_string!("☃★♲你"), + ), TestAction::assert_native_error( "String.fromCodePoint('_')", JsNativeErrorKind::Range, diff --git a/boa_engine/src/builtins/symbol/mod.rs b/boa_engine/src/builtins/symbol/mod.rs index 64a5a56632e..ebc5efe9b80 100644 --- a/boa_engine/src/builtins/symbol/mod.rs +++ b/boa_engine/src/builtins/symbol/mod.rs @@ -28,7 +28,7 @@ use crate::{ object::JsObject, property::Attribute, realm::Realm, - string::utf16, + string::common::StaticJsStrings, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsResult, JsString, @@ -93,7 +93,7 @@ pub struct Symbol; impl IntrinsicObject for Symbol { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let symbol_async_iterator = JsSymbol::async_iterator(); let symbol_has_instance = JsSymbol::has_instance(); @@ -112,46 +112,50 @@ impl IntrinsicObject for Symbol { let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; let to_primitive = BuiltInBuilder::callable(realm, Self::to_primitive) - .name("[Symbol.toPrimitive]") + .name(js_string!("[Symbol.toPrimitive]")) .length(1) .build(); let get_description = BuiltInBuilder::callable(realm, Self::get_description) - .name("get description") + .name(js_string!("get description")) .build(); BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::for_, "for", 1) - .static_method(Self::key_for, "keyFor", 1) - .static_property(utf16!("asyncIterator"), symbol_async_iterator, attribute) - .static_property(utf16!("hasInstance"), symbol_has_instance, attribute) + .static_method(Self::for_, js_string!("for"), 1) + .static_method(Self::key_for, js_string!("keyFor"), 1) .static_property( - utf16!("isConcatSpreadable"), + js_string!("asyncIterator"), + symbol_async_iterator, + attribute, + ) + .static_property(js_string!("hasInstance"), symbol_has_instance, attribute) + .static_property( + js_string!("isConcatSpreadable"), symbol_is_concat_spreadable, attribute, ) - .static_property(utf16!("iterator"), symbol_iterator, attribute) - .static_property(utf16!("match"), symbol_match, attribute) - .static_property(utf16!("matchAll"), symbol_match_all, attribute) - .static_property(utf16!("replace"), symbol_replace, attribute) - .static_property(utf16!("search"), symbol_search, attribute) - .static_property(utf16!("species"), symbol_species, attribute) - .static_property(utf16!("split"), symbol_split, attribute) + .static_property(js_string!("iterator"), symbol_iterator, attribute) + .static_property(js_string!("match"), symbol_match, attribute) + .static_property(js_string!("matchAll"), symbol_match_all, attribute) + .static_property(js_string!("replace"), symbol_replace, attribute) + .static_property(js_string!("search"), symbol_search, attribute) + .static_property(js_string!("species"), symbol_species, attribute) + .static_property(js_string!("split"), symbol_split, attribute) .static_property( - utf16!("toPrimitive"), + js_string!("toPrimitive"), symbol_to_primitive.clone(), attribute, ) .static_property( - utf16!("toStringTag"), + js_string!("toStringTag"), symbol_to_string_tag.clone(), attribute, ) - .static_property(utf16!("unscopables"), symbol_unscopables, attribute) - .method(Self::to_string, "toString", 0) - .method(Self::value_of, "valueOf", 0) + .static_property(js_string!("unscopables"), symbol_unscopables, attribute) + .method(Self::to_string, js_string!("toString"), 0) + .method(Self::value_of, js_string!("valueOf"), 0) .accessor( - utf16!("description"), + js_string!("description"), Some(get_description), None, Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, @@ -175,7 +179,7 @@ impl IntrinsicObject for Symbol { } impl BuiltInObject for Symbol { - const NAME: &'static str = "Symbol"; + const NAME: JsString = StaticJsStrings::SYMBOL; } impl BuiltInConstructor for Symbol { diff --git a/boa_engine/src/builtins/symbol/tests.rs b/boa_engine/src/builtins/symbol/tests.rs index 37ba0da363f..1ee48cd21f8 100644 --- a/boa_engine/src/builtins/symbol/tests.rs +++ b/boa_engine/src/builtins/symbol/tests.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsValue, TestAction}; use indoc::indoc; #[test] @@ -12,7 +12,7 @@ fn call_symbol_and_check_return_type() { fn print_symbol_expect_description() { run_test_actions([TestAction::assert_eq( "String(Symbol('Hello'))", - "Symbol(Hello)", + js_string!("Symbol(Hello)"), )]); } diff --git a/boa_engine/src/builtins/typed_array/mod.rs b/boa_engine/src/builtins/typed_array/mod.rs index 6b4df4a568c..4f683d7eb6c 100644 --- a/boa_engine/src/builtins/typed_array/mod.rs +++ b/boa_engine/src/builtins/typed_array/mod.rs @@ -29,22 +29,25 @@ use crate::{ }, property::{Attribute, PropertyNameKind}, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, value::{IntegerOrInfinity, JsValue}, - Context, JsArgs, JsResult, + Context, JsArgs, JsResult, JsString, }; use boa_profiler::Profiler; use num_traits::Zero; +use paste::paste; use std::cmp::Ordering; pub mod integer_indexed_object; macro_rules! typed_array { - ($ty:ident, $variant:ident, $name:literal, $global_object_name:ident) => { - #[doc = concat!("JavaScript `", $name, "` built-in implementation.")] - #[derive(Debug, Clone, Copy)] - pub struct $ty; + ($ty:ident, $variant:ident, $name:literal, $js_name:expr, $global_object_name:ident) => { + paste! { + #[doc = "JavaScript `" $name "` built-in implementation."] + #[derive(Debug, Clone, Copy)] + pub struct $ty; + } impl IntrinsicObject for $ty { fn get(intrinsics: &Intrinsics) -> JsObject { @@ -52,10 +55,10 @@ macro_rules! typed_array { } fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_species = BuiltInBuilder::callable(realm, TypedArray::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -76,12 +79,12 @@ macro_rules! typed_array { Attribute::CONFIGURABLE, ) .property( - utf16!("BYTES_PER_ELEMENT"), + js_string!("BYTES_PER_ELEMENT"), TypedArrayKind::$variant.element_size(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT, ) .static_property( - utf16!("BYTES_PER_ELEMENT"), + js_string!("BYTES_PER_ELEMENT"), TypedArrayKind::$variant.element_size(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT, ) @@ -90,7 +93,7 @@ macro_rules! typed_array { } impl BuiltInObject for $ty { - const NAME: &'static str = $name; + const NAME: JsString = $js_name; const ATTRIBUTE: Attribute = Attribute::WRITABLE .union(Attribute::NON_ENUMERABLE) @@ -244,31 +247,31 @@ pub(crate) struct TypedArray; impl IntrinsicObject for TypedArray { fn init(realm: &Realm) { let get_species = BuiltInBuilder::callable(realm, Self::get_species) - .name("get [Symbol.species]") + .name(js_string!("get [Symbol.species]")) .build(); let get_buffer = BuiltInBuilder::callable(realm, Self::buffer) - .name("get buffer") + .name(js_string!("get buffer")) .build(); let get_byte_length = BuiltInBuilder::callable(realm, Self::byte_length) - .name("get byteLength") + .name(js_string!("get byteLength")) .build(); let get_byte_offset = BuiltInBuilder::callable(realm, Self::byte_offset) - .name("get byteOffset") + .name(js_string!("get byteOffset")) .build(); let get_length = BuiltInBuilder::callable(realm, Self::length) - .name("get length") + .name(js_string!("get length")) .build(); let get_to_string_tag = BuiltInBuilder::callable(realm, Self::to_string_tag) - .name("get [Symbol.toStringTag]") + .name(js_string!("get [Symbol.toStringTag]")) .build(); let values_function = BuiltInBuilder::callable(realm, Self::values) - .name("values") + .name(js_string!("values")) .length(0) .build(); @@ -314,44 +317,44 @@ impl IntrinsicObject for TypedArray { None, Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, ) - .static_method(Self::from, "from", 1) - .static_method(Self::of, "of", 0) - .method(Self::at, "at", 1) - .method(Self::copy_within, "copyWithin", 2) - .method(Self::entries, "entries", 0) - .method(Self::every, "every", 1) - .method(Self::fill, "fill", 1) - .method(Self::filter, "filter", 1) - .method(Self::find, "find", 1) - .method(Self::find_index, "findIndex", 1) - .method(Self::find_last, "findLast", 1) - .method(Self::find_last_index, "findLastIndex", 1) - .method(Self::foreach, "forEach", 1) - .method(Self::includes, "includes", 1) - .method(Self::index_of, "indexOf", 1) - .method(Self::join, "join", 1) - .method(Self::keys, "keys", 0) - .method(Self::last_index_of, "lastIndexOf", 1) - .method(Self::map, "map", 1) - .method(Self::reduce, "reduce", 1) - .method(Self::reduceright, "reduceRight", 1) - .method(Self::reverse, "reverse", 0) - .method(Self::set, "set", 1) - .method(Self::slice, "slice", 2) - .method(Self::some, "some", 1) - .method(Self::sort, "sort", 1) - .method(Self::subarray, "subarray", 2) - .method(Self::to_locale_string, "toLocaleString", 0) + .static_method(Self::from, js_string!("from"), 1) + .static_method(Self::of, js_string!("of"), 0) + .method(Self::at, js_string!("at"), 1) + .method(Self::copy_within, js_string!("copyWithin"), 2) + .method(Self::entries, js_string!("entries"), 0) + .method(Self::every, js_string!("every"), 1) + .method(Self::fill, js_string!("fill"), 1) + .method(Self::filter, js_string!("filter"), 1) + .method(Self::find, js_string!("find"), 1) + .method(Self::find_index, js_string!("findIndex"), 1) + .method(Self::find_last, js_string!("findLast"), 1) + .method(Self::find_last_index, js_string!("findLastIndex"), 1) + .method(Self::foreach, js_string!("forEach"), 1) + .method(Self::includes, js_string!("includes"), 1) + .method(Self::index_of, js_string!("indexOf"), 1) + .method(Self::join, js_string!("join"), 1) + .method(Self::keys, js_string!("keys"), 0) + .method(Self::last_index_of, js_string!("lastIndexOf"), 1) + .method(Self::map, js_string!("map"), 1) + .method(Self::reduce, js_string!("reduce"), 1) + .method(Self::reduceright, js_string!("reduceRight"), 1) + .method(Self::reverse, js_string!("reverse"), 0) + .method(Self::set, js_string!("set"), 1) + .method(Self::slice, js_string!("slice"), 2) + .method(Self::some, js_string!("some"), 1) + .method(Self::sort, js_string!("sort"), 1) + .method(Self::subarray, js_string!("subarray"), 2) + .method(Self::to_locale_string, js_string!("toLocaleString"), 0) // 23.2.3.29 %TypedArray%.prototype.toString ( ) // The initial value of the %TypedArray%.prototype.toString data property is the same // built-in function object as the Array.prototype.toString method defined in 23.1.3.30. .property( - utf16!("toString"), + js_string!("toString"), realm.intrinsics().objects().array_prototype_to_string(), Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - "values", + js_string!("values"), values_function, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) @@ -364,7 +367,7 @@ impl IntrinsicObject for TypedArray { } impl BuiltInObject for TypedArray { - const NAME: &'static str = "TypedArray"; + const NAME: JsString = StaticJsStrings::TYPED_ARRAY; } impl BuiltInConstructor for TypedArray { @@ -3676,19 +3679,19 @@ impl TypedArrayKind { } /// Gets the name of this typed array name. - pub(crate) const fn name(&self) -> &str { + pub(crate) const fn name(self) -> JsString { match self { - Self::Int8 => "Int8Array", - Self::Uint8 => "Uint8Array", - Self::Uint8Clamped => "Uint8ClampedArray", - Self::Int16 => "Int16Array", - Self::Uint16 => "Uint16Array", - Self::Int32 => "Int32Array", - Self::Uint32 => "Uint32Array", - Self::BigInt64 => "BigInt64Array", - Self::BigUint64 => "BigUint64Array", - Self::Float32 => "Float32Array", - Self::Float64 => "Float64Array", + Self::Int8 => StaticJsStrings::INT8_ARRAY, + Self::Uint8 => StaticJsStrings::UINT8_ARRAY, + Self::Uint8Clamped => StaticJsStrings::UINT8_CLAMPED_ARRAY, + Self::Int16 => StaticJsStrings::INT16_ARRAY, + Self::Uint16 => StaticJsStrings::UINT16_ARRAY, + Self::Int32 => StaticJsStrings::INT32_ARRAY, + Self::Uint32 => StaticJsStrings::UINT32_ARRAY, + Self::BigInt64 => StaticJsStrings::BIG_INT64_ARRAY, + Self::BigUint64 => StaticJsStrings::BIG_UINT64_ARRAY, + Self::Float32 => StaticJsStrings::FLOAT32_ARRAY, + Self::Float64 => StaticJsStrings::FLOAT64_ARRAY, } } @@ -3697,29 +3700,80 @@ impl TypedArrayKind { } } -typed_array!(Int8Array, Int8, "Int8Array", typed_int8_array); -typed_array!(Uint8Array, Uint8, "Uint8Array", typed_uint8_array); +typed_array!( + Int8Array, + Int8, + "Int8Array", + StaticJsStrings::INT8_ARRAY, + typed_int8_array +); +typed_array!( + Uint8Array, + Uint8, + "UInt8Array", + StaticJsStrings::UINT8_ARRAY, + typed_uint8_array +); typed_array!( Uint8ClampedArray, Uint8Clamped, - "Uint8ClampedArray", + "UInt8ClampedArray", + StaticJsStrings::UINT8_CLAMPED_ARRAY, typed_uint8clamped_array ); -typed_array!(Int16Array, Int16, "Int16Array", typed_int16_array); -typed_array!(Uint16Array, Uint16, "Uint16Array", typed_uint16_array); -typed_array!(Int32Array, Int32, "Int32Array", typed_int32_array); -typed_array!(Uint32Array, Uint32, "Uint32Array", typed_uint32_array); +typed_array!( + Int16Array, + Int16, + "Int16Array", + StaticJsStrings::INT16_ARRAY, + typed_int16_array +); +typed_array!( + Uint16Array, + Uint16, + "UInt16Array", + StaticJsStrings::UINT16_ARRAY, + typed_uint16_array +); +typed_array!( + Int32Array, + Int32, + "Int32Array", + StaticJsStrings::INT32_ARRAY, + typed_int32_array +); +typed_array!( + Uint32Array, + Uint32, + "UInt32Array", + StaticJsStrings::UINT32_ARRAY, + typed_uint32_array +); typed_array!( BigInt64Array, BigInt64, "BigInt64Array", + StaticJsStrings::BIG_INT64_ARRAY, typed_bigint64_array ); typed_array!( BigUint64Array, BigUint64, "BigUint64Array", + StaticJsStrings::BIG_UINT64_ARRAY, typed_biguint64_array ); -typed_array!(Float32Array, Float32, "Float32Array", typed_float32_array); -typed_array!(Float64Array, Float64, "Float64Array", typed_float64_array); +typed_array!( + Float32Array, + Float32, + "Float32Array", + StaticJsStrings::FLOAT32_ARRAY, + typed_float32_array +); +typed_array!( + Float64Array, + Float64, + "Float64Array", + StaticJsStrings::FLOAT64_ARRAY, + typed_float64_array +); diff --git a/boa_engine/src/builtins/uri/mod.rs b/boa_engine/src/builtins/uri/mod.rs index d059fa98468..dfb26d91d9e 100644 --- a/boa_engine/src/builtins/uri/mod.rs +++ b/boa_engine/src/builtins/uri/mod.rs @@ -25,7 +25,7 @@ use crate::{ js_string, object::{JsFunction, JsObject}, realm::Realm, - string::CodePoint, + string::{common::StaticJsStrings, CodePoint}, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; @@ -93,7 +93,7 @@ impl IntrinsicObject for DecodeUri { } impl BuiltInObject for DecodeUri { - const NAME: &'static str = "decodeURI"; + const NAME: JsString = StaticJsStrings::DECODE_URI; } pub(crate) struct DecodeUriComponent; @@ -115,7 +115,7 @@ impl IntrinsicObject for DecodeUriComponent { } impl BuiltInObject for DecodeUriComponent { - const NAME: &'static str = "decodeURIComponent"; + const NAME: JsString = StaticJsStrings::DECODE_URI_COMPONENT; } pub(crate) struct EncodeUri; @@ -133,7 +133,7 @@ impl IntrinsicObject for EncodeUri { } impl BuiltInObject for EncodeUri { - const NAME: &'static str = "encodeURI"; + const NAME: JsString = StaticJsStrings::ENCODE_URI; } pub(crate) struct EncodeUriComponent; @@ -154,7 +154,7 @@ impl IntrinsicObject for EncodeUriComponent { } impl BuiltInObject for EncodeUriComponent { - const NAME: &'static str = "encodeURIComponent"; + const NAME: JsString = StaticJsStrings::ENCODE_URI_COMPONENT; } /// Builtin JavaScript `decodeURI ( encodedURI )` function. diff --git a/boa_engine/src/builtins/weak/weak_ref.rs b/boa_engine/src/builtins/weak/weak_ref.rs index 4ec3bbe1cee..c6f54f4caba 100644 --- a/boa_engine/src/builtins/weak/weak_ref.rs +++ b/boa_engine/src/builtins/weak/weak_ref.rs @@ -4,11 +4,13 @@ use boa_profiler::Profiler; use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, + string::common::StaticJsStrings, symbol::JsSymbol, - Context, JsArgs, JsNativeError, JsResult, JsValue, + Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; /// Boa's implementation of ECMAScript's `WeakRef` builtin object. @@ -30,20 +32,20 @@ impl IntrinsicObject for WeakRef { } fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .property( JsSymbol::to_string_tag(), - "WeakRef", + js_string!("WeakRef"), Attribute::CONFIGURABLE, ) - .method(Self::deref, "deref", 0) + .method(Self::deref, js_string!("deref"), 0) .build(); } } impl BuiltInObject for WeakRef { - const NAME: &'static str = "WeakRef"; + const NAME: JsString = StaticJsStrings::WEAK_REF; const ATTRIBUTE: Attribute = Attribute::WRITABLE.union(Attribute::CONFIGURABLE); } diff --git a/boa_engine/src/builtins/weak_map/mod.rs b/boa_engine/src/builtins/weak_map/mod.rs index 66f5e5aed42..19ec7dc7c22 100644 --- a/boa_engine/src/builtins/weak_map/mod.rs +++ b/boa_engine/src/builtins/weak_map/mod.rs @@ -13,12 +13,13 @@ use crate::{ IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, - Context, JsArgs, JsNativeError, JsResult, JsValue, + Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -32,23 +33,23 @@ impl IntrinsicObject for WeakMap { } fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .property( JsSymbol::to_string_tag(), Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .method(Self::delete, "delete", 1) - .method(Self::get, "get", 1) - .method(Self::has, "has", 1) - .method(Self::set, "set", 2) + .method(Self::delete, js_string!("delete"), 1) + .method(Self::get, js_string!("get"), 1) + .method(Self::has, js_string!("has"), 1) + .method(Self::set, js_string!("set"), 2) .build(); } } impl BuiltInObject for WeakMap { - const NAME: &'static str = "WeakMap"; + const NAME: JsString = StaticJsStrings::WEAK_MAP; const ATTRIBUTE: Attribute = Attribute::WRITABLE.union(Attribute::CONFIGURABLE); } diff --git a/boa_engine/src/builtins/weak_set/mod.rs b/boa_engine/src/builtins/weak_set/mod.rs index fb0ebde46df..65a74221cd6 100644 --- a/boa_engine/src/builtins/weak_set/mod.rs +++ b/boa_engine/src/builtins/weak_set/mod.rs @@ -10,12 +10,13 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, symbol::JsSymbol, - Context, JsArgs, JsNativeError, JsResult, JsValue, + Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace, WeakMap}; use boa_profiler::Profiler; @@ -29,22 +30,22 @@ impl IntrinsicObject for WeakSet { } fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .property( JsSymbol::to_string_tag(), Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .method(Self::add, "add", 1) - .method(Self::delete, "delete", 1) - .method(Self::has, "has", 1) + .method(Self::add, js_string!("add"), 1) + .method(Self::delete, js_string!("delete"), 1) + .method(Self::has, js_string!("has"), 1) .build(); } } impl BuiltInObject for WeakSet { - const NAME: &'static str = "WeakSet"; + const NAME: JsString = StaticJsStrings::WEAK_SET; const ATTRIBUTE: Attribute = Attribute::WRITABLE.union(Attribute::CONFIGURABLE); } diff --git a/boa_engine/src/class.rs b/boa_engine/src/class.rs index 231fcbc8f0a..5c1fd385c62 100644 --- a/boa_engine/src/class.rs +++ b/boa_engine/src/class.rs @@ -67,6 +67,7 @@ use crate::{ error::JsNativeError, + js_string, native_function::NativeFunction, object::{ConstructorBuilder, JsFunction, JsObject, NativeObject, ObjectData, PROTOTYPE}, property::{Attribute, PropertyDescriptor, PropertyKey}, @@ -121,7 +122,7 @@ impl ClassConstructor for T { .into()); } - let class = context.global_object().get(T::NAME, context)?; + let class = context.global_object().get(js_string!(T::NAME), context)?; let JsValue::Object(ref class_constructor) = class else { return Err(JsNativeError::typ() .with_message(format!( @@ -190,7 +191,8 @@ impl<'ctx, 'host> ClassBuilder<'ctx, 'host> { where N: AsRef, { - self.builder.method(function, name.as_ref(), length); + self.builder + .method(function, js_string!(name.as_ref()), length); self } @@ -206,7 +208,8 @@ impl<'ctx, 'host> ClassBuilder<'ctx, 'host> { where N: AsRef, { - self.builder.static_method(function, name.as_ref(), length); + self.builder + .static_method(function, js_string!(name.as_ref()), length); self } diff --git a/boa_engine/src/context/intrinsics.rs b/boa_engine/src/context/intrinsics.rs index 87768a22e9d..2547dea121c 100644 --- a/boa_engine/src/context/intrinsics.rs +++ b/boa_engine/src/context/intrinsics.rs @@ -191,7 +191,7 @@ impl Default for StandardConstructors { )), string: StandardConstructor::with_prototype(JsObject::from_proto_and_data( None, - ObjectData::string("".into()), + ObjectData::string(js_string!()), )), regexp: StandardConstructor::default(), symbol: StandardConstructor::default(), diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index a8ca9f94832..7795fcec9d4 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -20,6 +20,7 @@ use crate::{ builtins, class::{Class, ClassBuilder}, job::{JobQueue, NativeJob, SimpleJobQueue}, + js_string, module::{IdleModuleLoader, ModuleLoader, SimpleModuleLoader}, native_function::NativeFunction, object::{shape::RootShape, FunctionObjectBuilder, JsObject}, @@ -28,7 +29,7 @@ use crate::{ realm::Realm, script::Script, vm::{ActiveRunnable, CallFrame, Vm}, - JsResult, JsValue, Source, + JsResult, JsString, JsValue, Source, }; use boa_ast::{expression::Identifier, StatementList}; use boa_interner::Interner; @@ -48,6 +49,7 @@ use crate::vm::RuntimeLimits; /// /// ```rust /// use boa_engine::{ +/// js_string, /// object::ObjectInitializer, /// property::{Attribute, PropertyDescriptor}, /// Context, Source, @@ -69,9 +71,9 @@ use crate::vm::RuntimeLimits; /// /// // Create an object that can be used in eval calls. /// let arg = ObjectInitializer::new(&mut context) -/// .property("x", 12, Attribute::READONLY) +/// .property(js_string!("x"), 12, Attribute::READONLY) /// .build(); -/// context.register_global_property("arg", arg, Attribute::all()); +/// context.register_global_property(js_string!("arg"), arg, Attribute::all()); /// /// let value = context.eval(Source::from_bytes("test(arg)")).unwrap(); /// @@ -196,6 +198,7 @@ impl<'host> Context<'host> { /// # Example /// ``` /// use boa_engine::{ + /// js_string, /// object::ObjectInitializer, /// property::{Attribute, PropertyDescriptor}, /// Context, @@ -204,15 +207,23 @@ impl<'host> Context<'host> { /// let mut context = Context::default(); /// /// context - /// .register_global_property("myPrimitiveProperty", 10, Attribute::all()) + /// .register_global_property( + /// js_string!("myPrimitiveProperty"), + /// 10, + /// Attribute::all(), + /// ) /// .expect("property shouldn't exist"); /// /// let object = ObjectInitializer::new(&mut context) - /// .property("x", 0, Attribute::all()) - /// .property("y", 1, Attribute::all()) + /// .property(js_string!("x"), 0, Attribute::all()) + /// .property(js_string!("y"), 1, Attribute::all()) /// .build(); /// context - /// .register_global_property("myObjectProperty", object, Attribute::all()) + /// .register_global_property( + /// js_string!("myObjectProperty"), + /// object, + /// Attribute::all(), + /// ) /// .expect("property shouldn't exist"); /// ``` pub fn register_global_property( @@ -251,12 +262,12 @@ impl<'host> Context<'host> { /// can use the [`FunctionObjectBuilder`] API. pub fn register_global_callable( &mut self, - name: &str, + name: JsString, length: usize, body: NativeFunction, ) -> JsResult<()> { let function = FunctionObjectBuilder::new(&self.realm, body) - .name(name) + .name(name.clone()) .length(length) .constructor(true) .build(); @@ -284,12 +295,12 @@ impl<'host> Context<'host> { /// `constructable`. Usage of the function as a constructor will produce a `TypeError`. pub fn register_global_builtin_callable( &mut self, - name: &str, + name: JsString, length: usize, body: NativeFunction, ) -> JsResult<()> { let function = FunctionObjectBuilder::new(&self.realm, body) - .name(name) + .name(name.clone()) .length(length) .constructor(false) .build(); @@ -336,7 +347,7 @@ impl<'host> Context<'host> { .configurable(T::ATTRIBUTES.configurable()); self.global_object() - .define_property_or_throw(T::NAME, property, self)?; + .define_property_or_throw(js_string!(T::NAME), property, self)?; Ok(()) } diff --git a/boa_engine/src/error.rs b/boa_engine/src/error.rs index e3f46077bd9..839f404c687 100644 --- a/boa_engine/src/error.rs +++ b/boa_engine/src/error.rs @@ -2,6 +2,7 @@ use crate::{ builtins::{error::ErrorKind, Array}, + js_string, object::JsObject, object::ObjectData, property::PropertyDescriptor, @@ -28,11 +29,11 @@ use thiserror::Error; /// # Examples /// /// ```rust -/// # use boa_engine::{JsError, JsNativeError, JsNativeErrorKind, JsValue}; -/// let cause = JsError::from_opaque("error!".into()); +/// # use boa_engine::{JsError, JsNativeError, JsNativeErrorKind, JsValue, js_string}; +/// let cause = JsError::from_opaque(js_string!("error!").into()); /// /// assert!(cause.as_opaque().is_some()); -/// assert_eq!(cause.as_opaque().unwrap(), &JsValue::from("error!")); +/// assert_eq!(cause.as_opaque().unwrap(), &JsValue::from(js_string!("error!"))); /// /// let native_error: JsError = JsNativeError::typ() /// .with_message("invalid type!") @@ -228,21 +229,23 @@ impl JsError { .as_error() .ok_or_else(|| TryNativeError::NotAnErrorObject(val.clone()))?; - let try_get_property = |key, context: &mut Context<'_>| { - obj.has_property(key, context) + let try_get_property = |key: JsString, name, context: &mut Context<'_>| { + obj.has_property(key.clone(), context) .map_err(|e| TryNativeError::InaccessibleProperty { - property: key, + property: name, source: e, })? .then(|| obj.get(key, context)) .transpose() .map_err(|e| TryNativeError::InaccessibleProperty { - property: key, + property: name, source: e, }) }; - let message = if let Some(msg) = try_get_property("message", context)? { + let message = if let Some(msg) = + try_get_property(js_string!("message"), "message", context)? + { msg.as_string() .map(JsString::to_std_string) .transpose() @@ -253,7 +256,7 @@ impl JsError { Box::default() }; - let cause = try_get_property("cause", context)?; + let cause = try_get_property(js_string!("cause"), "cause", context)?; let kind = match error { ErrorKind::Error => JsNativeErrorKind::Error, @@ -297,7 +300,7 @@ impl JsError { } }; - let realm = try_get_property("constructor", context)? + let realm = try_get_property(js_string!("constructor"), "constructor", context)? .as_ref() .and_then(JsValue::as_constructor) .ok_or(TryNativeError::InvalidConstructor)? @@ -769,14 +772,17 @@ impl JsNativeError { /// # Examples /// /// ```rust - /// # use boa_engine::{Context, JsError, JsNativeError}; + /// # use boa_engine::{Context, JsError, JsNativeError, js_string}; /// let context = &mut Context::default(); /// /// let error = JsNativeError::error().with_message("error!"); /// let error_obj = error.to_opaque(context); /// /// assert!(error_obj.borrow().is_error()); - /// assert_eq!(error_obj.get("message", context).unwrap(), "error!".into()) + /// assert_eq!( + /// error_obj.get(js_string!("message"), context).unwrap(), + /// js_string!("error!").into() + /// ) /// ``` /// /// # Panics @@ -828,11 +834,15 @@ impl JsNativeError { ObjectData::error(tag), ); - o.create_non_enumerable_data_property_or_throw(utf16!("message"), &**message, context); + o.create_non_enumerable_data_property_or_throw( + js_string!("message"), + js_string!(&**message), + context, + ); if let Some(cause) = cause { o.create_non_enumerable_data_property_or_throw( - utf16!("cause"), + js_string!("cause"), cause.to_opaque(context), context, ); @@ -845,7 +855,7 @@ impl JsNativeError { .collect::>(); let errors = Array::create_array_from_list(errors, context); o.define_property_or_throw( - utf16!("errors"), + js_string!("errors"), PropertyDescriptor::builder() .configurable(true) .enumerable(false) diff --git a/boa_engine/src/object/builtins/jsdate.rs b/boa_engine/src/object/builtins/jsdate.rs index 3393961a8d2..2a190abcf9f 100644 --- a/boa_engine/src/object/builtins/jsdate.rs +++ b/boa_engine/src/object/builtins/jsdate.rs @@ -18,7 +18,9 @@ use crate::{ /// Create a `JsDate` object and set date to December 4 1995 /// /// ``` -/// use boa_engine::{object::builtins::JsDate, Context, JsResult, JsValue}; +/// use boa_engine::{ +/// js_string, object::builtins::JsDate, Context, JsResult, JsValue, +/// }; /// /// fn main() -> JsResult<()> { /// // JS mutable Context @@ -30,7 +32,7 @@ use crate::{ /// /// assert_eq!( /// date.to_date_string(context)?, -/// JsValue::from("Mon Dec 04 1995") +/// JsValue::from(js_string!("Mon Dec 04 1995")) /// ); /// /// Ok(()) diff --git a/boa_engine/src/object/builtins/jsmap.rs b/boa_engine/src/object/builtins/jsmap.rs index 98705788e64..074602b7ab7 100644 --- a/boa_engine/src/object/builtins/jsmap.rs +++ b/boa_engine/src/object/builtins/jsmap.rs @@ -20,7 +20,7 @@ use std::ops::Deref; /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, -/// # Context, JsValue, JsResult, +/// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// // Create default `Context` @@ -30,8 +30,8 @@ use std::ops::Deref; /// let map = JsMap::new(context); /// /// // Set key-value pairs for the `JsMap`. -/// map.set("Key-1", "Value-1", context)?; -/// map.set("Key-2", 10, context)?; +/// map.set(js_string!("Key-1"), js_string!("Value-1"), context)?; +/// map.set(js_string!("Key-2"), 10, context)?; /// /// assert_eq!(map.get_size(context)?, 2.into()); /// # Ok(()) @@ -42,7 +42,7 @@ use std::ops::Deref; /// ``` /// # use boa_engine::{ /// # object::builtins::{JsArray, JsMap}, -/// # Context, JsValue, JsResult, +/// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// // Create a default `Context` @@ -52,7 +52,10 @@ use std::ops::Deref; /// let js_array = JsArray::new(context); /// /// // Create a `[key, value]` pair of JsValues -/// let vec_one: Vec = vec![JsValue::new("first-key"), JsValue::new("first-value")]; +/// let vec_one: Vec = vec![ +/// js_string!("first-key").into(), +/// js_string!("first-value").into() +/// ]; /// /// // We create an push our `[key, value]` pair onto our array as a `JsArray` /// js_array.push(JsArray::from_iter(vec_one, context), context)?; @@ -61,8 +64,8 @@ use std::ops::Deref; /// let js_iterable_map = JsMap::from_js_iterable(&js_array.into(), context)?; /// /// assert_eq!( -/// js_iterable_map.get("first-key", context)?, -/// "first-value".into() +/// js_iterable_map.get(js_string!("first-key"), context)?, +/// js_string!("first-value").into() /// ); /// /// # Ok(()) @@ -99,7 +102,7 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::{JsArray, JsMap}, - /// # Context, JsResult, JsValue, + /// # Context, JsResult, JsValue, js_string /// # }; /// # fn main() -> JsResult<()> { /// # // Create a default `Context` @@ -108,7 +111,10 @@ impl JsMap { /// let js_array = JsArray::new(context); /// /// // Create a `[key, value]` pair of JsValues and add it to the `JsArray` as a `JsArray` - /// let vec_one: Vec = vec![JsValue::new("first-key"), JsValue::new("first-value")]; + /// let vec_one: Vec = vec![ + /// js_string!("first-key").into(), + /// js_string!("first-value").into() + /// ]; /// js_array.push(JsArray::from_iter(vec_one, context), context)?; /// /// // Create a `JsMap` from the `JsArray` using it's iterable property. @@ -217,16 +223,19 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); /// - /// js_map.set("foo", "bar", context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// js_map.set(2, 4, context)?; /// - /// assert_eq!(js_map.get("foo", context)?, "bar".into()); + /// assert_eq!( + /// js_map.get(js_string!("foo"), context)?, + /// js_string!("bar").into() + /// ); /// assert_eq!(js_map.get(2, context)?, 4.into()); /// # Ok(()) /// # } @@ -250,13 +259,13 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); /// - /// js_map.set("foo", "bar", context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// /// let map_size = js_map.get_size(context)?; /// @@ -276,18 +285,21 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set("foo", "bar", context)?; - /// js_map.set("hello", "world", context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; + /// js_map.set(js_string!("hello"), js_string!("world"), context)?; /// - /// js_map.delete("foo", context)?; + /// js_map.delete(js_string!("foo"), context)?; /// /// assert_eq!(js_map.get_size(context)?, 1.into()); - /// assert_eq!(js_map.get("foo", context)?, JsValue::undefined()); + /// assert_eq!( + /// js_map.get(js_string!("foo"), context)?, + /// JsValue::undefined() + /// ); /// # Ok(()) /// # } /// ``` @@ -305,16 +317,16 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set("foo", "bar", context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// - /// let retrieved_value = js_map.get("foo", context)?; + /// let retrieved_value = js_map.get(js_string!("foo"), context)?; /// - /// assert_eq!(retrieved_value, "bar".into()); + /// assert_eq!(retrieved_value, js_string!("bar").into()); /// # Ok(()) /// # } /// ``` @@ -332,13 +344,13 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set("foo", "bar", context)?; - /// js_map.set("hello", "world", context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; + /// js_map.set(js_string!("hello"), js_string!("world"), context)?; /// /// js_map.clear(context)?; /// @@ -358,14 +370,14 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set("foo", "bar", context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// - /// let has_key = js_map.has("foo", context)?; + /// let has_key = js_map.has(js_string!("foo"), context)?; /// /// assert_eq!(has_key, true.into()); /// # Ok(()) diff --git a/boa_engine/src/object/builtins/jspromise.rs b/boa_engine/src/object/builtins/jspromise.rs index b62ae672d9f..2c006944642 100644 --- a/boa_engine/src/object/builtins/jspromise.rs +++ b/boa_engine/src/object/builtins/jspromise.rs @@ -35,7 +35,11 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; /// # fn main() -> Result<(), Box> { /// let context = &mut Context::default(); /// -/// context.register_global_property("finally", false, Attribute::all()); +/// context.register_global_property( +/// js_string!("finally"), +/// false, +/// Attribute::all(), +/// ); /// /// let promise = JsPromise::new( /// |resolvers, context| { @@ -82,7 +86,7 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; /// context.realm(), /// NativeFunction::from_fn_ptr(|_, _, context| { /// context.global_object().clone().set( -/// "finally", +/// js_string!("finally"), /// JsValue::from(true), /// true, /// context, @@ -102,7 +106,10 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; /// ); /// /// assert_eq!( -/// context.global_object().clone().get("finally", context)?, +/// context +/// .global_object() +/// .clone() +/// .get(js_string!("finally"), context)?, /// JsValue::from(true) /// ); /// @@ -617,12 +624,16 @@ impl JsPromise { /// # use boa_engine::{ /// # object::{builtins::JsPromise, FunctionObjectBuilder}, /// # property::Attribute, - /// # Context, JsNativeError, JsValue, NativeFunction, + /// # Context, JsNativeError, JsValue, NativeFunction, js_string /// # }; /// # fn main() -> Result<(), Box> { /// let context = &mut Context::default(); /// - /// context.register_global_property("finally", false, Attribute::all()); + /// context.register_global_property( + /// js_string!("finally"), + /// false, + /// Attribute::all(), + /// ); /// /// let promise = JsPromise::new( /// |resolvers, context| { @@ -642,7 +653,7 @@ impl JsPromise { /// context.realm(), /// NativeFunction::from_fn_ptr(|_, _, context| { /// context.global_object().clone().set( - /// "finally", + /// js_string!("finally"), /// JsValue::from(true), /// true, /// context, @@ -657,7 +668,10 @@ impl JsPromise { /// context.run_jobs(); /// /// assert_eq!( - /// context.global_object().clone().get("finally", context)?, + /// context + /// .global_object() + /// .clone() + /// .get(js_string!("finally"), context)?, /// JsValue::from(true) /// ); /// @@ -788,19 +802,28 @@ impl JsPromise { /// let array = JsArray::from_object(array)?; /// /// let a = array.at(0, context)?.as_object().unwrap().clone(); - /// assert_eq!(a.get("status", context)?, js_string!("fulfilled").into()); - /// assert_eq!(a.get("value", context)?, 1.into()); + /// assert_eq!( + /// a.get(js_string!("status"), context)?, + /// js_string!("fulfilled").into() + /// ); + /// assert_eq!(a.get(js_string!("value"), context)?, 1.into()); /// /// let b = array.at(1, context)?.as_object().unwrap().clone(); - /// assert_eq!(b.get("status", context)?, js_string!("rejected").into()); /// assert_eq!( - /// b.get("reason", context)?.to_string(context)?, + /// b.get(js_string!("status"), context)?, + /// js_string!("rejected").into() + /// ); + /// assert_eq!( + /// b.get(js_string!("reason"), context)?.to_string(context)?, /// js_string!("TypeError") /// ); /// /// let c = array.at(2, context)?.as_object().unwrap().clone(); - /// assert_eq!(c.get("status", context)?, js_string!("fulfilled").into()); - /// assert_eq!(c.get("value", context)?, 3.into()); + /// assert_eq!( + /// c.get(js_string!("status"), context)?, + /// js_string!("fulfilled").into() + /// ); + /// assert_eq!(c.get(js_string!("value"), context)?, 3.into()); /// /// # Ok(()) /// # } diff --git a/boa_engine/src/object/builtins/jsregexp.rs b/boa_engine/src/object/builtins/jsregexp.rs index 86e39697084..dfa4e3493de 100644 --- a/boa_engine/src/object/builtins/jsregexp.rs +++ b/boa_engine/src/object/builtins/jsregexp.rs @@ -18,16 +18,16 @@ use std::ops::Deref; /// ``` /// # use boa_engine::{ /// # object::builtins::JsRegExp, -/// # Context, JsValue, JsResult, +/// # Context, JsValue, JsResult,js_string /// # }; /// # fn main() -> JsResult<()> { /// // Initialize the `Context` /// let context = &mut Context::default(); /// /// // Create a new RegExp with pattern and flags -/// let regexp = JsRegExp::new("foo", "gi", context)?; +/// let regexp = JsRegExp::new(js_string!("foo"), js_string!("gi"), context)?; /// -/// let test_result = regexp.test("football", context)?; +/// let test_result = regexp.test(js_string!("football"), context)?; /// assert!(test_result); /// /// let to_string = regexp.to_string(context)?; @@ -45,14 +45,14 @@ impl JsRegExp { /// ``` /// # use boa_engine::{ /// # object::builtins::JsRegExp, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// // Initialize the `Context` /// let context = &mut Context::default(); /// /// // Create a new RegExp with pattern and flags - /// let regexp = JsRegExp::new("foo", "gi", context)?; + /// let regexp = JsRegExp::new(js_string!("foo"), js_string!("gi"), context)?; /// # Ok(()) /// # } /// ``` @@ -141,11 +141,11 @@ impl JsRegExp { /// ``` /// # use boa_engine::{ /// # object::builtins::JsRegExp, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); - /// let regexp = JsRegExp::new("foo", "gi", context)?; + /// let regexp = JsRegExp::new(js_string!("foo"), js_string!("gi"), context)?; /// /// let flags = regexp.flags(context)?; /// assert_eq!(flags, String::from("gi")); @@ -166,11 +166,11 @@ impl JsRegExp { /// ``` /// # use boa_engine::{ /// # object::builtins::JsRegExp, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); - /// let regexp = JsRegExp::new("foo", "gi", context)?; + /// let regexp = JsRegExp::new(js_string!("foo"), js_string!("gi"), context)?; /// /// let src = regexp.source(context)?; /// assert_eq!(src, String::from("foo")); @@ -191,13 +191,13 @@ impl JsRegExp { /// ``` /// # use boa_engine::{ /// # object::builtins::JsRegExp, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); - /// let regexp = JsRegExp::new("foo", "gi", context)?; + /// let regexp = JsRegExp::new(js_string!("foo"), js_string!("gi"), context)?; /// - /// let test_result = regexp.test("football", context)?; + /// let test_result = regexp.test(js_string!("football"), context)?; /// assert!(test_result); /// # Ok(()) /// # } @@ -233,14 +233,14 @@ impl JsRegExp { /// ``` /// # use boa_engine::{ /// # object::builtins::JsRegExp, - /// # Context, JsValue, JsResult, + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); - /// let regexp = JsRegExp::new("foo", "gi", context)?; + /// let regexp = JsRegExp::new(js_string!("foo"), js_string!("gi"), context)?; /// /// let to_string = regexp.to_string(context)?; - /// assert_eq!(to_string, String::from("/foo/gi")); + /// assert_eq!(to_string, "/foo/gi"); /// # Ok(()) /// # } /// ``` diff --git a/boa_engine/src/object/internal_methods/integer_indexed.rs b/boa_engine/src/object/internal_methods/integer_indexed.rs index c6bbf8bca25..71c1255095c 100644 --- a/boa_engine/src/object/internal_methods/integer_indexed.rs +++ b/boa_engine/src/object/internal_methods/integer_indexed.rs @@ -45,7 +45,7 @@ fn canonical_numeric_index_string(argument: &JsString) -> Option { let n = argument.to_number(); // 3. If ! ToString(n) is argument, return n. - if &JsString::from(Number::to_native_string(n)) == argument { + if &Number::to_js_string(n) == argument { return Some(n); } diff --git a/boa_engine/src/object/jsobject.rs b/boa_engine/src/object/jsobject.rs index 8d0e56440f6..fea283986ed 100644 --- a/boa_engine/src/object/jsobject.rs +++ b/boa_engine/src/object/jsobject.rs @@ -10,6 +10,7 @@ use super::{ use crate::{ context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::{ObjectData, ObjectKind}, property::{PropertyDescriptor, PropertyKey}, string::utf16, @@ -245,7 +246,7 @@ impl JsObject { // we're in a recursive object, bail return Ok(match hint { PreferredType::Number => JsValue::new(0), - PreferredType::String => JsValue::new(""), + PreferredType::String => JsValue::new(js_string!()), PreferredType::Default => unreachable!("checked type hint in step 2"), }); } diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 6c1f71d4b6a..11176a2bf10 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -2013,30 +2013,6 @@ pub struct FunctionBinding { pub(crate) name: JsString, } -impl From<&str> for FunctionBinding { - #[inline] - fn from(name: &str) -> Self { - let name: JsString = name.into(); - - Self { - binding: name.clone().into(), - name, - } - } -} - -impl From for FunctionBinding { - #[inline] - fn from(name: String) -> Self { - let name: JsString = name.into(); - - Self { - binding: name.clone().into(), - name, - } - } -} - impl From for FunctionBinding { #[inline] fn from(name: JsString) -> Self { @@ -2146,15 +2122,16 @@ impl<'realm> FunctionObjectBuilder<'realm> { /// # JsValue, /// # NativeFunction, /// # object::ObjectInitializer, -/// # property::Attribute +/// # property::Attribute, +/// # js_string, /// # }; /// let mut context = Context::default(); /// let object = ObjectInitializer::new(&mut context) -/// .property("hello", "world", Attribute::all()) +/// .property(js_string!("hello"), js_string!("world"), Attribute::all()) /// .property(1, 1, Attribute::all()) /// .function( /// NativeFunction::from_fn_ptr(|_, _, _| Ok(JsValue::undefined())), -/// "func", +/// js_string!("func"), /// 0, /// ) /// .build(); diff --git a/boa_engine/src/optimizer/pass/constant_folding.rs b/boa_engine/src/optimizer/pass/constant_folding.rs index 4e26a0772d5..d510e11310e 100644 --- a/boa_engine/src/optimizer/pass/constant_folding.rs +++ b/boa_engine/src/optimizer/pass/constant_folding.rs @@ -82,7 +82,7 @@ impl ConstantFolding { }, ), (literal, UnaryOp::TypeOf) => Ok(JsValue::new( - literal_to_js_value(literal, context).type_of(), + literal_to_js_value(literal, context).js_type_of(), )), (_, UnaryOp::Delete) => { return PassAction::Replace(Expression::Literal(Literal::Bool(true))) diff --git a/boa_engine/src/property/mod.rs b/boa_engine/src/property/mod.rs index bcfdd7845ac..4d68fa4c8b2 100644 --- a/boa_engine/src/property/mod.rs +++ b/boa_engine/src/property/mod.rs @@ -678,28 +678,6 @@ impl From for PropertyKey { } } -impl From<&str> for PropertyKey { - #[inline] - fn from(string: &str) -> Self { - parse_u32_index(string.bytes()).map_or_else(|| Self::String(string.into()), Self::Index) - } -} - -impl From for PropertyKey { - #[inline] - fn from(string: String) -> Self { - parse_u32_index(string.bytes()).map_or_else(|| Self::String(string.into()), Self::Index) - } -} - -impl From> for PropertyKey { - #[inline] - fn from(string: Box) -> Self { - parse_u32_index(string.bytes()) - .map_or_else(|| Self::String(string.as_ref().into()), Self::Index) - } -} - impl From for PropertyKey { #[inline] fn from(symbol: JsSymbol) -> Self { @@ -737,7 +715,7 @@ impl From for JsValue { match property_key { PropertyKey::String(ref string) => string.clone().into(), PropertyKey::Symbol(ref symbol) => symbol.clone().into(), - PropertyKey::Index(index) => index.to_string().into(), + PropertyKey::Index(index) => js_string!(index.to_string()).into(), } } } diff --git a/boa_engine/src/string/common.rs b/boa_engine/src/string/common.rs index 50a3b711e89..8e8b05febee 100644 --- a/boa_engine/src/string/common.rs +++ b/boa_engine/src/string/common.rs @@ -4,17 +4,20 @@ use crate::tagged::Tagged; use super::JsString; use boa_macros::utf16; +use paste::paste; use rustc_hash::{FxHashMap, FxHasher}; macro_rules! well_known_statics { ( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => { $( - $(#[$attr])* pub(crate) const fn $name() -> JsString { - JsString { + paste!{ + #[doc = "Gets the static `JsString` for `\"" $string "\"`."] + #[allow(unused)] + pub(crate) const $name: JsString = JsString { ptr: Tagged::from_tag( Self::find_index(utf16!($string)), ), - } + }; } )+ }; @@ -74,35 +77,89 @@ impl StaticJsStrings { RAW_STATICS.get(index).copied() } + // Some consts are only used on certain features, which triggers the unused lint. well_known_statics! { - /// Gets the empty string (`""`) `JsString`. - (empty_string, ""), - /// Gets the static `JsString` for `"Symbol.asyncIterator"`. - (symbol_async_iterator, "Symbol.asyncIterator"), - /// Gets the static `JsString` for `"Symbol.hasInstance"`. - (symbol_has_instance, "Symbol.hasInstance"), - /// Gets the static `JsString` for `"Symbol.isConcatSpreadable"`. - (symbol_is_concat_spreadable, "Symbol.isConcatSpreadable"), - /// Gets the static `JsString` for `"Symbol.iterator"`. - (symbol_iterator, "Symbol.iterator"), - /// Gets the static `JsString` for `"Symbol.match"`. - (symbol_match, "Symbol.match"), - /// Gets the static `JsString` for `"Symbol.matchAll"`. - (symbol_match_all, "Symbol.matchAll"), - /// Gets the static `JsString` for `"Symbol.replace"`. - (symbol_replace, "Symbol.replace"), - /// Gets the static `JsString` for `"Symbol.search"`. - (symbol_search, "Symbol.search"), - /// Gets the static `JsString` for `"Symbol.species"`. - (symbol_species, "Symbol.species"), - /// Gets the static `JsString` for `"Symbol.split"`. - (symbol_split, "Symbol.split"), - /// Gets the static `JsString` for `"Symbol.toPrimitive"`. - (symbol_to_primitive, "Symbol.toPrimitive"), - /// Gets the static `JsString` for `"Symbol.toStringTag"`. - (symbol_to_string_tag, "Symbol.toStringTag"), - /// Gets the static `JsString` for `"Symbol.unscopables"`. - (symbol_unscopables, "Symbol.unscopables"), + (EMPTY_STRING, ""), + // Symbols + (SYMBOL_ASYNC_ITERATOR, "Symbol.asyncIterator"), + (SYMBOL_HAS_INSTANCE, "Symbol.hasInstance"), + (SYMBOL_IS_CONCAT_SPREADABLE, "Symbol.isConcatSpreadable"), + (SYMBOL_ITERATOR, "Symbol.iterator"), + (SYMBOL_MATCH, "Symbol.match"), + (SYMBOL_MATCH_ALL, "Symbol.matchAll"), + (SYMBOL_REPLACE, "Symbol.replace"), + (SYMBOL_SEARCH, "Symbol.search"), + (SYMBOL_SPECIES, "Symbol.species"), + (SYMBOL_SPLIT, "Symbol.split"), + (SYMBOL_TO_PRIMITIVE, "Symbol.toPrimitive"), + (SYMBOL_TO_STRING_TAG, "Symbol.toStringTag"), + (SYMBOL_UNSCOPABLES, "Symbol.unscopables"), + // Builtins + (ARRAY, "Array"), + (ARRAY_BUFFER, "ArrayBuffer"), + (ASYNC_FUNCTION, "AsyncFunction"), + (ASYNC_GENERATOR, "AsyncGenerator"), + (ASYNC_GENERATOR_FUNCTION, "AsyncGeneratorFunction"), + (BIG_INT, "BigInt"), + (BOOLEAN, "Boolean"), + (DATA_VIEW, "DataView"), + (DATE, "Date"), + (ERROR, "Error"), + (AGGREGATE_ERROR, "AggregateError"), + (EVAL_ERROR, "EvalError"), + (RANGE_ERROR, "RangeError"), + (REFERENCE_ERROR, "ReferenceError"), + (SYNTAX_ERROR, "SyntaxError"), + (TYPE_ERROR, "TypeError"), + (URI_ERROR, "URIError"), + (ESCAPE, "escape"), + (UNESCAPE, "unescape"), + (EVAL, "eval"), + (FUNCTION, "Function"), + (GENERATOR, "Generator"), + (GENERATOR_FUNCTION, "GeneratorFunction"), + (INTL, "Intl"), + (COLLATOR, "Collator"), + (LIST_FORMAT, "ListFormat"), + (LOCALE, "Locale"), + (PLURAL_RULES, "PluralRules"), + (SEGMENTER, "Segmenter"), + (DATE_TIME_FORMAT, "DateTimeFormat"), + (JSON, "JSON"), + (MAP, "Map"), + (MATH, "Math"), + (NUMBER, "Number"), + (IS_FINITE, "isFinite"), + (IS_NAN, "isNaN"), + (PARSE_INT, "parseInt"), + (PARSE_FLOAT, "parseFloat"), + (OBJECT, "Object"), + (PROMISE, "Promise"), + (PROXY, "Proxy"), + (REFLECT, "Reflect"), + (REG_EXP, "RegExp"), + (SET, "Set"), + (STRING, "String"), + (SYMBOL, "Symbol"), + (TYPED_ARRAY, "TypedArray"), + (INT8_ARRAY, "Int8Array"), + (UINT8_ARRAY, "Uint8Array"), + (UINT8_CLAMPED_ARRAY, "Uint8ClampedArray"), + (INT16_ARRAY, "Int16Array"), + (UINT16_ARRAY, "Uint16Array"), + (INT32_ARRAY, "Int32Array"), + (UINT32_ARRAY, "Uint32Array"), + (BIG_INT64_ARRAY, "BigInt64Array"), + (BIG_UINT64_ARRAY, "BigUint64Array"), + (FLOAT32_ARRAY, "Float32Array"), + (FLOAT64_ARRAY, "Float64Array"), + (ENCODE_URI, "encodeURI"), + (ENCODE_URI_COMPONENT, "encodeURIComponent"), + (DECODE_URI, "decodeURI"), + (DECODE_URI_COMPONENT, "decodeURIComponent"), + (WEAK_REF, "WeakRef"), + (WEAK_MAP, "WeakMap"), + (WEAK_SET, "WeakSet"), } } @@ -136,11 +193,101 @@ thread_local! { } /// Array of raw static strings that aren't reference counted. -/// -/// The macro `static_strings` automatically sorts the array of strings, making it faster -/// for searches by using `binary_search`. const RAW_STATICS: &[&[u16]] = &[ utf16!(""), + // Well known symbols + utf16!("Symbol.asyncIterator"), + utf16!("[Symbol.asyncIterator]"), + utf16!("Symbol.hasInstance"), + utf16!("[Symbol.hasInstance]"), + utf16!("Symbol.isConcatSpreadable"), + utf16!("[Symbol.isConcatSpreadable]"), + utf16!("Symbol.iterator"), + utf16!("[Symbol.iterator]"), + utf16!("Symbol.match"), + utf16!("[Symbol.match]"), + utf16!("Symbol.matchAll"), + utf16!("[Symbol.matchAll]"), + utf16!("Symbol.replace"), + utf16!("[Symbol.replace]"), + utf16!("Symbol.search"), + utf16!("[Symbol.search]"), + utf16!("Symbol.species"), + utf16!("[Symbol.species]"), + utf16!("Symbol.split"), + utf16!("[Symbol.split]"), + utf16!("Symbol.toPrimitive"), + utf16!("[Symbol.toPrimitive]"), + utf16!("Symbol.toStringTag"), + utf16!("[Symbol.toStringTag]"), + utf16!("Symbol.unscopables"), + utf16!("[Symbol.unscopables]"), + // Well known builtins + utf16!("Array"), + utf16!("ArrayBuffer"), + utf16!("AsyncFunction"), + utf16!("AsyncGenerator"), + utf16!("AsyncGeneratorFunction"), + utf16!("BigInt"), + utf16!("Boolean"), + utf16!("DataView"), + utf16!("Date"), + utf16!("Error"), + utf16!("AggregateError"), + utf16!("EvalError"), + utf16!("RangeError"), + utf16!("ReferenceError"), + utf16!("SyntaxError"), + utf16!("TypeError"), + utf16!("URIError"), + utf16!("escape"), + utf16!("unescape"), + utf16!("eval"), + utf16!("Function"), + utf16!("Generator"), + utf16!("GeneratorFunction"), + utf16!("Intl"), + utf16!("Collator"), + utf16!("ListFormat"), + utf16!("Locale"), + utf16!("PluralRules"), + utf16!("Segmenter"), + utf16!("DateTimeFormat"), + utf16!("JSON"), + utf16!("Map"), + utf16!("Math"), + utf16!("Number"), + utf16!("isFinite"), + utf16!("isNaN"), + utf16!("parseInt"), + utf16!("parseFloat"), + utf16!("Object"), + utf16!("Promise"), + utf16!("Proxy"), + utf16!("Reflect"), + utf16!("RegExp"), + utf16!("Set"), + utf16!("String"), + utf16!("Symbol"), + utf16!("TypedArray"), + utf16!("Int8Array"), + utf16!("Uint8Array"), + utf16!("Uint8ClampedArray"), + utf16!("Int16Array"), + utf16!("Uint16Array"), + utf16!("Int32Array"), + utf16!("Uint32Array"), + utf16!("BigInt64Array"), + utf16!("BigUint64Array"), + utf16!("Float32Array"), + utf16!("Float64Array"), + utf16!("encodeURI"), + utf16!("encodeURIComponent"), + utf16!("decodeURI"), + utf16!("decodeURIComponent"), + utf16!("WeakRef"), + utf16!("WeakMap"), + utf16!("WeakSet"), // Misc utf16!(","), utf16!(":"), @@ -197,14 +344,10 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("entries"), utf16!("fromEntries"), // Function object - utf16!("Function"), utf16!("apply"), utf16!("bind"), utf16!("call"), - // Generator object - utf16!("Generator"), // Array object - utf16!("Array"), utf16!("at"), utf16!("from"), utf16!("isArray"), @@ -237,7 +380,6 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("push"), utf16!("pop"), // String object - utf16!("String"), utf16!("charAt"), utf16!("charCodeAt"), utf16!("codePointAt"), @@ -267,13 +409,8 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("trimEnd"), utf16!("trimStart"), // Number object - utf16!("Number"), utf16!("Infinity"), utf16!("NaN"), - utf16!("parseInt"), - utf16!("parseFloat"), - utf16!("isFinite"), - utf16!("isNaN"), utf16!("EPSILON"), utf16!("MAX_SAFE_INTEGER"), utf16!("MIN_SAFE_INTEGER"), @@ -284,14 +421,10 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("toExponential"), utf16!("toFixed"), utf16!("toPrecision"), - // Boolean object - utf16!("Boolean"), // BigInt object - utf16!("BigInt"), utf16!("asIntN"), utf16!("asUintN"), // RegExp object - utf16!("RegExp"), utf16!("exec"), utf16!("test"), utf16!("flags"), @@ -314,7 +447,6 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("get flags"), utf16!("get source"), // Symbol object - utf16!("Symbol"), utf16!("for"), utf16!("keyFor"), utf16!("description"), @@ -327,32 +459,18 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("toPrimitive"), utf16!("get description"), // Map object - utf16!("Map"), utf16!("clear"), utf16!("delete"), utf16!("has"), utf16!("size"), // Set object - utf16!("Set"), utf16!("add"), // Reflect object - utf16!("Reflect"), // Proxy object - utf16!("Proxy"), utf16!("revocable"), // Error objects - utf16!("Error"), - utf16!("AggregateError"), - utf16!("TypeError"), - utf16!("RangeError"), - utf16!("SyntaxError"), - utf16!("ReferenceError"), - utf16!("EvalError"), - utf16!("ThrowTypeError"), - utf16!("URIError"), utf16!("message"), // Date object - utf16!("Date"), utf16!("toJSON"), utf16!("getDate"), utf16!("getDay"), @@ -394,7 +512,6 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("now"), utf16!("UTC"), // JSON object - utf16!("JSON"), utf16!("parse"), utf16!("stringify"), // Iterator object @@ -404,7 +521,6 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("Map Iterator"), utf16!("For In Iterator"), // Math object - utf16!("Math"), utf16!("LN10"), utf16!("LN2"), utf16!("LOG10E"), @@ -447,22 +563,7 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("tan"), utf16!("tanh"), utf16!("trunc"), - // Intl object - utf16!("Intl"), - utf16!("DateTimeFormat"), // TypedArray object - utf16!("TypedArray"), - utf16!("ArrayBuffer"), - utf16!("Int8Array"), - utf16!("Uint8Array"), - utf16!("Int16Array"), - utf16!("Uint16Array"), - utf16!("Int32Array"), - utf16!("Uint32Array"), - utf16!("BigInt64Array"), - utf16!("BigUint64Array"), - utf16!("Float32Array"), - utf16!("Float64Array"), utf16!("buffer"), utf16!("byteLength"), utf16!("byteOffset"), @@ -474,7 +575,6 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("get size"), utf16!("get length"), // DataView object - utf16!("DataView"), utf16!("getBigInt64"), utf16!("getBigUint64"), utf16!("getFloat32"), @@ -569,31 +669,4 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("Z"), utf16!("_"), utf16!("$"), - // Well known symbols - utf16!("Symbol.asyncIterator"), - utf16!("[Symbol.asyncIterator]"), - utf16!("Symbol.hasInstance"), - utf16!("[Symbol.hasInstance]"), - utf16!("Symbol.isConcatSpreadable"), - utf16!("[Symbol.isConcatSpreadable]"), - utf16!("Symbol.iterator"), - utf16!("[Symbol.iterator]"), - utf16!("Symbol.match"), - utf16!("[Symbol.match]"), - utf16!("Symbol.matchAll"), - utf16!("[Symbol.matchAll]"), - utf16!("Symbol.replace"), - utf16!("[Symbol.replace]"), - utf16!("Symbol.search"), - utf16!("[Symbol.search]"), - utf16!("Symbol.species"), - utf16!("[Symbol.species]"), - utf16!("Symbol.split"), - utf16!("[Symbol.split]"), - utf16!("Symbol.toPrimitive"), - utf16!("[Symbol.toPrimitive]"), - utf16!("Symbol.toStringTag"), - utf16!("[Symbol.toStringTag]"), - utf16!("Symbol.unscopables"), - utf16!("[Symbol.unscopables]"), ]; diff --git a/boa_engine/src/string/mod.rs b/boa_engine/src/string/mod.rs index 7089f5457a3..b35abe1da8f 100644 --- a/boa_engine/src/string/mod.rs +++ b/boa_engine/src/string/mod.rs @@ -651,7 +651,7 @@ impl Clone for JsString { impl Default for JsString { #[inline] fn default() -> Self { - StaticJsStrings::empty_string() + StaticJsStrings::EMPTY_STRING } } diff --git a/boa_engine/src/symbol.rs b/boa_engine/src/symbol.rs index 1112d8ab942..a0733ff4f98 100644 --- a/boa_engine/src/symbol.rs +++ b/boa_engine/src/symbol.rs @@ -80,19 +80,19 @@ enum WellKnown { impl WellKnown { const fn description(self) -> JsString { match self { - Self::AsyncIterator => StaticJsStrings::symbol_async_iterator(), - Self::HasInstance => StaticJsStrings::symbol_has_instance(), - Self::IsConcatSpreadable => StaticJsStrings::symbol_is_concat_spreadable(), - Self::Iterator => StaticJsStrings::symbol_iterator(), - Self::Match => StaticJsStrings::symbol_match(), - Self::MatchAll => StaticJsStrings::symbol_match_all(), - Self::Replace => StaticJsStrings::symbol_replace(), - Self::Search => StaticJsStrings::symbol_search(), - Self::Species => StaticJsStrings::symbol_species(), - Self::Split => StaticJsStrings::symbol_split(), - Self::ToPrimitive => StaticJsStrings::symbol_to_primitive(), - Self::ToStringTag => StaticJsStrings::symbol_to_string_tag(), - Self::Unscopables => StaticJsStrings::symbol_unscopables(), + Self::AsyncIterator => StaticJsStrings::SYMBOL_ASYNC_ITERATOR, + Self::HasInstance => StaticJsStrings::SYMBOL_HAS_INSTANCE, + Self::IsConcatSpreadable => StaticJsStrings::SYMBOL_IS_CONCAT_SPREADABLE, + Self::Iterator => StaticJsStrings::SYMBOL_ITERATOR, + Self::Match => StaticJsStrings::SYMBOL_MATCH, + Self::MatchAll => StaticJsStrings::SYMBOL_MATCH_ALL, + Self::Replace => StaticJsStrings::SYMBOL_REPLACE, + Self::Search => StaticJsStrings::SYMBOL_SEARCH, + Self::Species => StaticJsStrings::SYMBOL_SPECIES, + Self::Split => StaticJsStrings::SYMBOL_SPLIT, + Self::ToPrimitive => StaticJsStrings::SYMBOL_TO_PRIMITIVE, + Self::ToStringTag => StaticJsStrings::SYMBOL_TO_STRING_TAG, + Self::Unscopables => StaticJsStrings::SYMBOL_UNSCOPABLES, } } diff --git a/boa_engine/src/tests/control_flow/loops.rs b/boa_engine/src/tests/control_flow/loops.rs index 683ac7a707d..52cebb62430 100644 --- a/boa_engine/src/tests/control_flow/loops.rs +++ b/boa_engine/src/tests/control_flow/loops.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsNativeErrorKind, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, TestAction}; use indoc::indoc; #[test] @@ -87,7 +87,7 @@ fn for_loop() { b } "#}, - "hello", + js_string!("hello"), ), TestAction::assert_eq( indoc! {r#" @@ -192,7 +192,7 @@ fn try_break_finally_edge_cases() { a + b "#; - run_test_actions([TestAction::assert_eq(scenario, "foobar")]); + run_test_actions([TestAction::assert_eq(scenario, js_string!("foobar"))]); } #[test] @@ -228,7 +228,7 @@ fn try_break_labels() { } "#; - run_test_actions([TestAction::assert_eq(scenario, "finally! :)")]); + run_test_actions([TestAction::assert_eq(scenario, js_string!("finally! :)"))]); } #[test] @@ -268,10 +268,10 @@ fn break_nested_labels_loops_and_try() { run_test_actions([ TestAction::run(scenario), - TestAction::assert_eq("nestedLabels(true)", "foobar broke-foo"), + TestAction::assert_eq("nestedLabels(true)", js_string!("foobar broke-foo")), TestAction::assert_eq( "nestedLabels(false)", - "foobar broke-bar broke-spacer broke-foo", + js_string!("foobar broke-bar broke-spacer broke-foo"), ), ]); } @@ -376,7 +376,7 @@ fn break_environment_gauntlet() { } "#; - run_test_actions([TestAction::assert_eq(scenario, "5601try_block")]); + run_test_actions([TestAction::assert_eq(scenario, js_string!("5601try_block"))]); } #[test] @@ -707,7 +707,7 @@ fn for_loop_break_label() { } str "#}, - "01", + js_string!("01"), )]); } @@ -822,7 +822,7 @@ fn for_in_break_label() { } str "#}, - "0", + js_string!("0"), )]); } @@ -843,6 +843,6 @@ fn for_in_continue_label() { } str "#}, - "00", + js_string!("00"), )]); } diff --git a/boa_engine/src/tests/control_flow/mod.rs b/boa_engine/src/tests/control_flow/mod.rs index eabfae5c9c8..270c917f249 100644 --- a/boa_engine/src/tests/control_flow/mod.rs +++ b/boa_engine/src/tests/control_flow/mod.rs @@ -1,7 +1,7 @@ use indoc::indoc; mod loops; -use crate::{run_test_actions, JsNativeErrorKind, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, TestAction}; #[test] fn test_invalid_break() { @@ -381,7 +381,7 @@ fn string_switch() { a; "#}, - "world", + js_string!("world"), )]); } @@ -418,13 +418,13 @@ fn bigger_switch_example() { return b; } "#}), - TestAction::assert_eq("f(0)", "Mon"), - TestAction::assert_eq("f(1)", "Tue"), - TestAction::assert_eq("f(2)", "Wed"), - TestAction::assert_eq("f(3)", "Thurs"), - TestAction::assert_eq("f(4)", "Fri"), - TestAction::assert_eq("f(5)", "Sat"), - TestAction::assert_eq("f(6)", "Sun"), + TestAction::assert_eq("f(0)", js_string!("Mon")), + TestAction::assert_eq("f(1)", js_string!("Tue")), + TestAction::assert_eq("f(2)", js_string!("Wed")), + TestAction::assert_eq("f(3)", js_string!("Thurs")), + TestAction::assert_eq("f(4)", js_string!("Fri")), + TestAction::assert_eq("f(5)", js_string!("Sat")), + TestAction::assert_eq("f(6)", js_string!("Sun")), ]); } @@ -440,7 +440,7 @@ fn break_labelled_if_statement() { } result "#}, - "foo", + js_string!("foo"), )]); } @@ -458,6 +458,6 @@ fn break_labelled_try_statement() { } result "#}, - "foo", + js_string!("foo"), )]); } diff --git a/boa_engine/src/tests/env.rs b/boa_engine/src/tests/env.rs index d4c4101e72b..372641cbf48 100644 --- a/boa_engine/src/tests/env.rs +++ b/boa_engine/src/tests/env.rs @@ -1,6 +1,6 @@ use indoc::indoc; -use crate::{run_test_actions, JsNativeErrorKind, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, TestAction}; #[test] // https://github.com/boa-dev/boa/issues/2317 @@ -15,7 +15,7 @@ fn fun_block_eval_2317() { return y + x; })("arg"); "#}, - "arginner", + js_string!("arginner"), ), TestAction::assert_eq( indoc! {r#" @@ -26,7 +26,7 @@ fn fun_block_eval_2317() { return y + x; })(); "#}, - "defaultinner", + js_string!("defaultinner"), ), ]); } diff --git a/boa_engine/src/tests/function.rs b/boa_engine/src/tests/function.rs index 5fe53613a0c..4a359fff7d1 100644 --- a/boa_engine/src/tests/function.rs +++ b/boa_engine/src/tests/function.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; use indoc::indoc; #[test] @@ -24,7 +24,7 @@ fn property_accessor_member_expression_dot_notation_on_function() { function asd () {}; asd.name; "#}, - "asd", + js_string!("asd"), )]); } @@ -35,7 +35,7 @@ fn property_accessor_member_expression_bracket_notation_on_function() { function asd () {}; asd['name']; "#}, - "asd", + js_string!("asd"), )]); } @@ -62,7 +62,7 @@ fn early_return() { } outer_fnct() "#}, - "outer", + js_string!("outer"), ), ]); } @@ -78,8 +78,8 @@ fn should_set_this_value() { var bar = new Foo(); "#}), - TestAction::assert_eq("bar.a", "a"), - TestAction::assert_eq("bar.b", "b"), + TestAction::assert_eq("bar.a", js_string!("a")), + TestAction::assert_eq("bar.b", js_string!("b")), ]); } diff --git a/boa_engine/src/tests/mod.rs b/boa_engine/src/tests/mod.rs index 182223e8952..4c1e0d658f6 100644 --- a/boa_engine/src/tests/mod.rs +++ b/boa_engine/src/tests/mod.rs @@ -8,7 +8,7 @@ mod operators; mod promise; mod spread; -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; #[test] fn length_correct_value_on_string_literal() { @@ -355,7 +355,7 @@ fn multiline_str_concat() { 'world'; a "#}, - "hello world", + js_string!("hello world"), )]); } @@ -479,7 +479,7 @@ fn template_literal() { let a = 10; `result: ${a} and ${a+10}`; "#}, - "result: 10 and 20", + js_string!("result: 10 and 20"), )]); } diff --git a/boa_engine/src/tests/operators.rs b/boa_engine/src/tests/operators.rs index 4334079c7dd..6d688e1041b 100644 --- a/boa_engine/src/tests/operators.rs +++ b/boa_engine/src/tests/operators.rs @@ -1,16 +1,19 @@ -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; use indoc::indoc; #[test] fn property_accessor_member_expression_dot_notation_on_string_literal() { - run_test_actions([TestAction::assert_eq("typeof 'asd'.matchAll", "function")]); + run_test_actions([TestAction::assert_eq( + "typeof 'asd'.matchAll", + js_string!("function"), + )]); } #[test] fn property_accessor_member_expression_bracket_notation_on_string_literal() { run_test_actions([TestAction::assert_eq( "typeof 'asd'['matchAll']", - "function", + js_string!("function"), )]); } @@ -194,15 +197,15 @@ fn unary_operations_on_this() { #[test] fn typeofs() { run_test_actions([ - TestAction::assert_eq("typeof String()", "string"), - TestAction::assert_eq("typeof 5", "number"), - TestAction::assert_eq("typeof 0.5", "number"), - TestAction::assert_eq("typeof undefined", "undefined"), - TestAction::assert_eq("typeof true", "boolean"), - TestAction::assert_eq("typeof null", "object"), - TestAction::assert_eq("typeof {}", "object"), - TestAction::assert_eq("typeof Symbol()", "symbol"), - TestAction::assert_eq("typeof function(){}", "function"), + TestAction::assert_eq("typeof String()", js_string!("string")), + TestAction::assert_eq("typeof 5", js_string!("number")), + TestAction::assert_eq("typeof 0.5", js_string!("number")), + TestAction::assert_eq("typeof undefined", js_string!("undefined")), + TestAction::assert_eq("typeof true", js_string!("boolean")), + TestAction::assert_eq("typeof null", js_string!("object")), + TestAction::assert_eq("typeof {}", js_string!("object")), + TestAction::assert_eq("typeof Symbol()", js_string!("symbol")), + TestAction::assert_eq("typeof function(){}", js_string!("function")), ]); } @@ -245,7 +248,7 @@ fn unary_void() { const b = void test() + ''; a + b "#}, - "42undefined", + js_string!("42undefined"), ), ]); } @@ -491,7 +494,10 @@ fn logical_assignment() { #[test] fn conditional_op() { - run_test_actions([TestAction::assert_eq("1 === 2 ? 'a' : 'b'", "b")]); + run_test_actions([TestAction::assert_eq( + "1 === 2 ? 'a' : 'b'", + js_string!("b"), + )]); } #[test] diff --git a/boa_engine/src/tests/spread.rs b/boa_engine/src/tests/spread.rs index 05ad16fc954..ff0d9ddecd6 100644 --- a/boa_engine/src/tests/spread.rs +++ b/boa_engine/src/tests/spread.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; use indoc::indoc; #[test] @@ -26,7 +26,7 @@ fn spread_with_arguments() { var result = foo(...a); "#}), TestAction::assert_eq("result[0]", 1), - TestAction::assert_eq("result[1]", "test"), + TestAction::assert_eq("result[1]", js_string!("test")), TestAction::assert_eq("result[2]", 3), TestAction::assert_eq("result[3]", 4), ]); @@ -131,7 +131,7 @@ fn spread_with_new() { } f('message').m; "#}, - "message", + js_string!("message"), )]); } @@ -147,6 +147,6 @@ fn spread_with_call() { } g('message'); "#}, - "message", + js_string!("message"), )]); } diff --git a/boa_engine/src/value/conversions/mod.rs b/boa_engine/src/value/conversions/mod.rs index b90c080ef8f..255ca3d1a38 100644 --- a/boa_engine/src/value/conversions/mod.rs +++ b/boa_engine/src/value/conversions/mod.rs @@ -1,18 +1,17 @@ //! Conversions from JavaScript values into Rust values, and the other way around. +use crate::js_string; + use super::{JsBigInt, JsObject, JsString, JsSymbol, JsValue, Profiler}; mod serde_json; pub(super) mod try_from_js; -impl From for JsValue -where - T: Into, -{ - fn from(value: T) -> Self { - let _timer = Profiler::global().start_event("From", "value"); +impl From for JsValue { + fn from(value: JsString) -> Self { + let _timer = Profiler::global().start_event("From", "value"); - Self::String(value.into()) + Self::String(value) } } @@ -21,7 +20,11 @@ impl From for JsValue { fn from(value: char) -> Self { let _timer = Profiler::global().start_event("From", "value"); - Self::new(value.to_string()) + let mut buf: [u16; 2] = [0; 2]; + + let out = value.encode_utf16(&mut buf); + + Self::from(js_string!(&*out)) } } diff --git a/boa_engine/src/value/conversions/serde_json.rs b/boa_engine/src/value/conversions/serde_json.rs index c33c3f2734d..3f84565d657 100644 --- a/boa_engine/src/value/conversions/serde_json.rs +++ b/boa_engine/src/value/conversions/serde_json.rs @@ -4,6 +4,7 @@ use super::JsValue; use crate::{ builtins::Array, error::JsNativeError, + js_string, object::JsObject, property::{PropertyDescriptor, PropertyKey}, Context, JsResult, @@ -55,7 +56,7 @@ impl JsValue { .with_message(format!("could not convert JSON number {num} to JsValue")) .into() }), - Value::String(string) => Ok(Self::from(string.as_str())), + Value::String(string) => Ok(Self::from(js_string!(string.as_str()))), Value::Array(vec) => { let mut arr = Vec::with_capacity(vec.len()); for val in vec { @@ -71,7 +72,9 @@ impl JsValue { .writable(true) .enumerable(true) .configurable(true); - js_obj.borrow_mut().insert(key.clone(), property); + js_obj + .borrow_mut() + .insert(js_string!(key.clone()), property); } Ok(js_obj.into()) @@ -177,7 +180,7 @@ mod tests { use serde_json::json; use crate::object::JsArray; - use crate::{run_test_actions, TestAction}; + use crate::{js_string, run_test_actions, TestAction}; use crate::{string::utf16, JsValue}; #[test] @@ -206,7 +209,10 @@ mod tests { let value = JsValue::from_json(&json, ctx).unwrap(); let obj = value.as_object().unwrap(); - assert_eq!(obj.get(utf16!("name"), ctx).unwrap(), "John Doe".into()); + assert_eq!( + obj.get(utf16!("name"), ctx).unwrap(), + js_string!("John Doe").into() + ); assert_eq!(obj.get(utf16!("age"), ctx).unwrap(), 43_i32.into()); assert_eq!(obj.get(utf16!("minor"), ctx).unwrap(), false.into()); assert_eq!(obj.get(utf16!("adult"), ctx).unwrap(), true.into()); @@ -220,7 +226,7 @@ mod tests { let phones = phones.as_object().unwrap(); let arr = JsArray::from_object(phones.clone()).unwrap(); - assert_eq!(arr.at(0, ctx).unwrap(), "+44 1234567".into()); + assert_eq!(arr.at(0, ctx).unwrap(), js_string!("+44 1234567").into()); assert_eq!(arr.at(1, ctx).unwrap(), JsValue::from(-45_i32)); assert!(arr.at(2, ctx).unwrap().is_object()); assert_eq!(arr.at(3, ctx).unwrap(), true.into()); diff --git a/boa_engine/src/value/conversions/try_from_js.rs b/boa_engine/src/value/conversions/try_from_js.rs index 975881d4a74..783319dff94 100644 --- a/boa_engine/src/value/conversions/try_from_js.rs +++ b/boa_engine/src/value/conversions/try_from_js.rs @@ -36,7 +36,7 @@ impl TryFromJs for String { match value { JsValue::String(s) => s.to_std_string().map_err(|e| { JsNativeError::typ() - .with_message(format!("could not convert JsString to Rust string, since it has UTF-16 characters: {e}")) + .with_message(format!("could not convert JsString to Rust string: {e}")) .into() }), _ => Err(JsNativeError::typ() diff --git a/boa_engine/src/value/mod.rs b/boa_engine/src/value/mod.rs index d9d2868033b..035146e6c29 100644 --- a/boa_engine/src/value/mod.rs +++ b/boa_engine/src/value/mod.rs @@ -19,6 +19,7 @@ use crate::{ Number, }, error::JsNativeError, + js_string, object::{JsObject, ObjectData}, property::{PropertyDescriptor, PropertyKey}, symbol::JsSymbol, @@ -366,9 +367,9 @@ impl JsValue { // 1. Assert: preferredType is number. // 2. Let hint be "number". let hint = match preferred_type { - PreferredType::Default => "default", - PreferredType::String => "string", - PreferredType::Number => "number", + PreferredType::Default => js_string!("default"), + PreferredType::String => js_string!("string"), + PreferredType::Number => js_string!("number"), } .into(); @@ -471,7 +472,7 @@ impl JsValue { Self::Null => Ok("null".into()), Self::Undefined => Ok("undefined".into()), Self::Boolean(boolean) => Ok(boolean.to_string().into()), - Self::Rational(rational) => Ok(Number::to_native_string(*rational).into()), + Self::Rational(rational) => Ok(Number::to_js_string(*rational)), Self::Integer(integer) => Ok(integer.to_string().into()), Self::String(string) => Ok(string.clone()), Self::Symbol(_) => Err(JsNativeError::typ() @@ -974,6 +975,27 @@ impl JsValue { } } + /// Same as [`JsValue::type_of`], but returning a [`JsString`] instead. + #[must_use] + pub fn js_type_of(&self) -> JsString { + match *self { + Self::Rational(_) | Self::Integer(_) => js_string!("number"), + Self::String(_) => js_string!("string"), + Self::Boolean(_) => js_string!("boolean"), + Self::Symbol(_) => js_string!("symbol"), + Self::Null => js_string!("object"), + Self::Undefined => js_string!("undefined"), + Self::BigInt(_) => js_string!("bigint"), + Self::Object(ref object) => { + if object.is_callable() { + js_string!("function") + } else { + js_string!("object") + } + } + } + } + /// Abstract operation `IsArray ( argument )` /// /// Check if a value is an array. diff --git a/boa_engine/src/value/tests.rs b/boa_engine/src/value/tests.rs index ff7d5f9a266..a99deb4e601 100644 --- a/boa_engine/src/value/tests.rs +++ b/boa_engine/src/value/tests.rs @@ -2,7 +2,7 @@ use boa_macros::utf16; use indoc::indoc; use super::*; -use crate::{run_test_actions, TestAction}; +use crate::{js_string, run_test_actions, TestAction}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -10,7 +10,7 @@ use std::hash::{Hash, Hasher}; #[test] fn string_to_value() { let s = String::from("Hello"); - let v = JsValue::new(s); + let v = JsValue::new(js_string!(s)); assert!(v.is_string()); assert!(!v.is_null()); } @@ -27,9 +27,9 @@ fn get_set_field() { run_test_actions([TestAction::assert_context(|ctx| { let obj = &JsObject::with_object_proto(ctx.intrinsics()); // Create string and convert it to a Value - let s = JsValue::new("bar"); - obj.set("foo", s, false, ctx).unwrap(); - obj.get("foo", ctx).unwrap() == JsValue::new("bar") + let s = JsValue::new(js_string!("bar")); + obj.set(js_string!("foo"), s, false, ctx).unwrap(); + obj.get(js_string!("foo"), ctx).unwrap() == JsValue::new(js_string!("bar")) })]); } @@ -198,9 +198,9 @@ fn float_display() { #[test] fn string_length_is_not_enumerable() { run_test_actions([TestAction::assert_context(|ctx| { - let object = JsValue::new("foo").to_object(ctx).unwrap(); + let object = JsValue::new(js_string!("foo")).to_object(ctx).unwrap(); let length_desc = object - .__get_own_property__(&PropertyKey::from("length"), ctx) + .__get_own_property__(&js_string!("length").into(), ctx) .unwrap() .unwrap(); !length_desc.expect_enumerable() @@ -211,9 +211,9 @@ fn string_length_is_not_enumerable() { fn string_length_is_in_utf16_codeunits() { run_test_actions([TestAction::assert_context(|ctx| { // 😀 is one Unicode code point, but 2 UTF-16 code units - let object = JsValue::new("😀").to_object(ctx).unwrap(); + let object = JsValue::new(js_string!("😀")).to_object(ctx).unwrap(); let length_desc = object - .__get_own_property__(&PropertyKey::from("length"), ctx) + .__get_own_property__(&js_string!("length").into(), ctx) .unwrap() .unwrap(); length_desc @@ -231,14 +231,17 @@ fn add_number_and_number() { #[test] fn add_number_and_string() { - run_test_actions([TestAction::assert_eq("1 + \" + 2 = 3\"", "1 + 2 = 3")]); + run_test_actions([TestAction::assert_eq( + "1 + \" + 2 = 3\"", + js_string!("1 + 2 = 3"), + )]); } #[test] fn add_string_and_string() { run_test_actions([TestAction::assert_eq( "\"Hello\" + \", world\"", - "Hello, world", + js_string!("Hello, world"), )]); } @@ -251,7 +254,7 @@ fn add_number_object_and_number() { fn add_number_object_and_string_object() { run_test_actions([TestAction::assert_eq( "new Number(10) + new String(\"0\")", - "100", + js_string!("100"), )]); } @@ -324,7 +327,7 @@ fn assign_pow_number_and_string() { #[test] fn display_string() { let s = String::from("Hello"); - let v = JsValue::new(s); + let v = JsValue::new(js_string!(s)); assert_eq!(v.display().to_string(), "\"Hello\""); } @@ -434,7 +437,9 @@ fn to_integer_or_infinity() { IntegerOrInfinity::Integer(11) ); assert_eq!( - JsValue::new("12").to_integer_or_infinity(ctx).unwrap(), + JsValue::new(js_string!("12")) + .to_integer_or_infinity(ctx) + .unwrap(), IntegerOrInfinity::Integer(12) ); assert_eq!( @@ -452,8 +457,8 @@ fn test_accessors() { let a = { get b() { return "c" }, set b(value) { arr = arr.concat([value]) }} ; a.b = "a"; "#}), - TestAction::assert_eq("a.b", "c"), - TestAction::assert_eq("arr[0]", "a"), + TestAction::assert_eq("a.b", js_string!("c")), + TestAction::assert_eq("arr[0]", js_string!("a")), ]); } @@ -678,7 +683,7 @@ fn to_string() { assert_eq!(&JsValue::new(55).to_string(ctx).unwrap(), utf16!("55")); assert_eq!(&JsValue::new(55.0).to_string(ctx).unwrap(), utf16!("55")); assert_eq!( - &JsValue::new("hello").to_string(ctx).unwrap(), + &JsValue::new(js_string!("hello")).to_string(ctx).unwrap(), utf16!("hello") ); })]); @@ -691,7 +696,7 @@ fn to_bigint() { assert!(JsValue::undefined().to_bigint(ctx).is_err()); assert!(JsValue::new(55).to_bigint(ctx).is_err()); assert!(JsValue::new(10.0).to_bigint(ctx).is_err()); - assert!(JsValue::new("100").to_bigint(ctx).is_ok()); + assert!(JsValue::new(js_string!("100")).to_bigint(ctx).is_ok()); })]); } @@ -724,7 +729,7 @@ mod cyclic_conversions { let a = [b, b]; JSON.stringify(a) "#}, - "[[],[]]", + js_string!("[[],[]]"), )]); } @@ -739,7 +744,7 @@ mod cyclic_conversions { a[0] = a; a.toString() "#}, - "", + js_string!(), )]); } diff --git a/boa_engine/src/vm/opcode/iteration/for_in.rs b/boa_engine/src/vm/opcode/iteration/for_in.rs index 443e290b727..6f26cd0ddbb 100644 --- a/boa_engine/src/vm/opcode/iteration/for_in.rs +++ b/boa_engine/src/vm/opcode/iteration/for_in.rs @@ -1,5 +1,6 @@ use crate::{ builtins::{iterable::IteratorRecord, object::for_in_iterator::ForInIterator}, + js_string, vm::{opcode::Operation, CompletionType}, Context, JsResult, JsValue, }; @@ -21,7 +22,7 @@ impl Operation for CreateForInIterator { let object = object.to_object(context)?; let iterator = ForInIterator::create_for_in_iterator(JsValue::new(object), context); let next_method = iterator - .get("next", context) + .get(js_string!("next"), context) .expect("ForInIterator must have a `next` method"); context diff --git a/boa_engine/src/vm/opcode/push/class/private.rs b/boa_engine/src/vm/opcode/push/class/private.rs index 31797f39fcb..e18ca0d2eed 100644 --- a/boa_engine/src/vm/opcode/push/class/private.rs +++ b/boa_engine/src/vm/opcode/push/class/private.rs @@ -1,4 +1,5 @@ use crate::{ + js_string, object::PrivateElement, property::PropertyDescriptor, string::utf16, @@ -23,7 +24,7 @@ impl Operation for PushClassPrivateMethod { let method = context.vm.pop(); let method_object = method.as_callable().expect("method must be callable"); - let name_string = format!("#{}", name.to_std_string_escaped()); + let name_string = js_string!(utf16!("#"), &name); let desc = PropertyDescriptor::builder() .value(name_string) .writable(false) diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index b5bfe61d0c8..ad3693d355c 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -1,4 +1,5 @@ use crate::{ + js_string, object::PrivateElement, property::PropertyDescriptor, string::utf16, @@ -81,7 +82,7 @@ impl Operation for SetPrivateMethod { let value = context.vm.pop(); let value = value.as_callable().expect("method must be callable"); - let name_string = format!("#{}", name.to_std_string_escaped()); + let name_string = js_string!(utf16!("#"), &name); let desc = PropertyDescriptor::builder() .value(name_string) .writable(false) @@ -89,7 +90,7 @@ impl Operation for SetPrivateMethod { .configurable(true) .build(); value - .__define_own_property__(&utf16!("name").into(), desc, context) + .__define_own_property__(&js_string!("name").into(), desc, context) .expect("failed to set name property on private method"); let object = context.vm.pop(); diff --git a/boa_engine/src/vm/opcode/unary_ops/mod.rs b/boa_engine/src/vm/opcode/unary_ops/mod.rs index 1473a0e1eaf..a0b5a88fbb9 100644 --- a/boa_engine/src/vm/opcode/unary_ops/mod.rs +++ b/boa_engine/src/vm/opcode/unary_ops/mod.rs @@ -29,7 +29,7 @@ impl Operation for TypeOf { fn execute(context: &mut Context<'_>) -> JsResult { let value = context.vm.pop(); - context.vm.push(value.type_of()); + context.vm.push(value.js_type_of()); Ok(CompletionType::Normal) } } diff --git a/boa_engine/src/vm/tests.rs b/boa_engine/src/vm/tests.rs index b1072538046..f4c70a44e8f 100644 --- a/boa_engine/src/vm/tests.rs +++ b/boa_engine/src/vm/tests.rs @@ -1,4 +1,4 @@ -use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction}; +use crate::{js_string, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; use indoc::indoc; #[test] @@ -8,7 +8,7 @@ fn typeof_string() { const a = "hello"; typeof a; "#}, - "string", + js_string!("string"), )]); } @@ -19,7 +19,7 @@ fn typeof_number() { let a = 1234; typeof a; "#}, - "number", + js_string!("number"), )]); } @@ -50,7 +50,7 @@ fn try_catch_finally_from_init() { } finally { } "#}, - "h", + js_string!("h"), )]); } @@ -85,7 +85,7 @@ fn use_last_expr_try_block() { "Bye!" } "#}, - "Hello!", + js_string!("Hello!"), )]); } @@ -102,7 +102,7 @@ fn use_last_expr_catch_block() { "Hello!"; } "#}, - "Hello!", + js_string!("Hello!"), )]); } @@ -133,7 +133,7 @@ fn finally_block_binding_env() { } buf "#}, - "Hey hey people", + js_string!("Hey hey people"), )]); } @@ -150,7 +150,7 @@ fn run_super_method_in_object() { Object.setPrototypeOf(obj, proto); obj.v(); "#}, - "super", + js_string!("super"), )]); } @@ -174,7 +174,7 @@ fn get_reference_by_super() { obj.method(); fromA + fromB "#}, - "ab", + js_string!("ab"), )]); } @@ -234,7 +234,7 @@ fn order_of_execution_in_assigment_with_comma_expressions() { (f(1), a)[(f(2), 0)][(f(3), 0)] = (f(4), 123); result "#}, - "1234", + js_string!("1234"), )]); } @@ -321,7 +321,7 @@ fn arguments_object_constructor_valid_index() { new F(); typeof args "#}, - "object", + js_string!("object"), )]); } diff --git a/boa_examples/src/bin/classes.rs b/boa_examples/src/bin/classes.rs index 60e95bff593..1f3f138d368 100644 --- a/boa_examples/src/bin/classes.rs +++ b/boa_examples/src/bin/classes.rs @@ -2,6 +2,7 @@ use boa_engine::{ class::{Class, ClassBuilder}, error::JsNativeError, + js_string, native_function::NativeFunction, property::Attribute, Context, JsArgs, JsResult, JsString, JsValue, Source, @@ -111,13 +112,13 @@ impl Class for Person { // We add an `"inheritedProperty"` property to the prototype of `Person` with // a value of `10` and default attribute flags `READONLY`, `NON_ENUMERABLE` and `PERMANENT`. - class.property("inheritedProperty", 10, Attribute::default()); + class.property(js_string!("inheritedProperty"), 10, Attribute::default()); // Finally, we add a `"staticProperty"` property to `Person` with a value // of `"Im a static property"` and attribute flags `WRITABLE`, `ENUMERABLE` and `PERMANENT`. class.static_property( - "staticProperty", - "Im a static property", + js_string!("staticProperty"), + js_string!("Im a static property"), Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::PERMANENT, ); @@ -130,7 +131,7 @@ fn add_runtime(context: &mut Context<'_>) { // We first add the `console` object, to be able to call `console.log()`. let console = Console::init(context); context - .register_global_property(Console::NAME, console, Attribute::all()) + .register_global_property(js_string!(Console::NAME), console, Attribute::all()) .expect("the console builtin shouldn't exist"); // Then we need to register the global class `Person` inside `context`. diff --git a/boa_examples/src/bin/closures.rs b/boa_examples/src/bin/closures.rs index 02ff0763352..8548f79a5e5 100644 --- a/boa_examples/src/bin/closures.rs +++ b/boa_examples/src/bin/closures.rs @@ -24,7 +24,7 @@ fn main() -> Result<(), JsError> { // We register a global closure function that has the name 'closure' with length 0. context .register_global_callable( - "closure", + js_string!("closure"), 0, NativeFunction::from_copy_closure(move |_, _, _| { println!("Called `closure`"); @@ -53,9 +53,9 @@ fn main() -> Result<(), JsError> { // We create a new `JsObject` with some data let object = JsObject::with_object_proto(context.intrinsics()); object.define_property_or_throw( - "name", + js_string!("name"), PropertyDescriptor::builder() - .value("Boa dev") + .value(js_string!("Boa dev")) .writable(false) .enumerable(false) .configurable(false), @@ -78,7 +78,7 @@ fn main() -> Result<(), JsError> { let BigStruct { greeting, object } = &mut *captures; println!("Called `createMessage`"); // We obtain the `name` property of `captures.object` - let name = object.get("name", context)?; + let name = object.get(js_string!("name"), context)?; // We create a new message from our captured variable. let message = js_string!( @@ -112,7 +112,7 @@ fn main() -> Result<(), JsError> { .register_global_property( // We set the key to access the function the same as its name for // consistency, but it may be different if needed. - "createMessage", + js_string!("createMessage"), // We pass `js_function` as a property value. js_function, // We assign to the "createMessage" property the desired attributes. @@ -122,13 +122,13 @@ fn main() -> Result<(), JsError> { assert_eq!( context.eval(Source::from_bytes("createMessage()"))?, - "message from `Boa dev`: Hello!".into() + js_string!("message from `Boa dev`: Hello!").into() ); // The data mutates between calls assert_eq!( context.eval(Source::from_bytes("createMessage(); createMessage();"))?, - "message from `Boa dev`: Hello! Hello! Hello!".into() + js_string!("message from `Boa dev`: Hello! Hello! Hello!").into() ); // We have moved `Clone` variables into a closure and executed that closure @@ -145,7 +145,7 @@ fn main() -> Result<(), JsError> { // We register a global closure that is not `Copy`. context .register_global_callable( - "enumerate", + js_string!("enumerate"), 0, // Note that it is required to use `unsafe` code, since the compiler cannot verify that the // types captured by the closure are not traceable. diff --git a/boa_examples/src/bin/futures.rs b/boa_examples/src/bin/futures.rs index 634496bcfd4..6a688c717d1 100644 --- a/boa_examples/src/bin/futures.rs +++ b/boa_examples/src/bin/futures.rs @@ -7,6 +7,7 @@ use std::{ use boa_engine::{ context::ContextBuilder, job::{FutureJob, JobQueue, NativeJob}, + js_string, native_function::NativeFunction, property::Attribute, Context, JsArgs, JsResult, JsValue, Source, @@ -135,12 +136,16 @@ fn add_runtime(context: &mut Context<'_>) { // First add the `console` object, to be able to call `console.log()`. let console = Console::init(context); context - .register_global_property(Console::NAME, console, Attribute::all()) + .register_global_property(js_string!(Console::NAME), console, Attribute::all()) .expect("the console builtin shouldn't exist"); // Then, bind the defined async function to the ECMAScript function "delay". context - .register_global_builtin_callable("delay", 1, NativeFunction::from_async_fn(delay)) + .register_global_builtin_callable( + js_string!("delay"), + 1, + NativeFunction::from_async_fn(delay), + ) .expect("the delay builtin shouldn't exist"); } diff --git a/boa_examples/src/bin/host_defined.rs b/boa_examples/src/bin/host_defined.rs index 55906b9cda7..c60d4c4dcfb 100644 --- a/boa_examples/src/bin/host_defined.rs +++ b/boa_examples/src/bin/host_defined.rs @@ -1,7 +1,7 @@ // This example goes into the details on how to store user defined structs/state that is shared. use boa_engine::{ - native_function::NativeFunction, Context, JsArgs, JsError, JsNativeError, Source, + js_string, native_function::NativeFunction, Context, JsArgs, JsError, JsNativeError, Source, }; use boa_gc::{Finalize, Trace}; @@ -81,7 +81,7 @@ fn main() -> Result<(), JsError> { // // The funtion lives in the context's realm and has access to the host-defined field. context.register_global_builtin_callable( - "setRealmValue", + js_string!("setRealmValue"), 1, NativeFunction::from_fn_ptr(|_, args, context| { let value: usize = args.get_or_undefined(0).try_js_into(context)?; @@ -100,7 +100,7 @@ fn main() -> Result<(), JsError> { )?; context.register_global_builtin_callable( - "getRealmValue", + js_string!("getRealmValue"), 0, NativeFunction::from_fn_ptr(|_, _, context| { let host_defined = context.realm().host_defined(); diff --git a/boa_examples/src/bin/jsarray.rs b/boa_examples/src/bin/jsarray.rs index 8d8578d4172..a750f16f06d 100644 --- a/boa_examples/src/bin/jsarray.rs +++ b/boa_examples/src/bin/jsarray.rs @@ -1,6 +1,7 @@ // This example shows how to manipulate a Javascript array using Rust code. use boa_engine::{ + js_string, native_function::NativeFunction, object::{builtins::JsArray, FunctionObjectBuilder}, string::utf16, @@ -16,13 +17,16 @@ fn main() -> JsResult<()> { assert!(array.is_empty(context)?); - array.push("Hello, world", context)?; // [ "Hello, world" ] + array.push(js_string!("Hello, world"), context)?; // [ "Hello, world" ] array.push(true, context)?; // [ "Hello, world", true ] assert!(!array.is_empty(context)?); assert_eq!(array.pop(context)?, JsValue::new(true)); // [ "Hello, world" ] - assert_eq!(array.pop(context)?, JsValue::new("Hello, world")); // [ ] + assert_eq!( + array.pop(context)?, + JsValue::new(js_string!("Hello, world")) + ); // [ ] assert_eq!(array.pop(context)?, JsValue::undefined()); // [ ] array.push(1, context)?; // [ 1 ] @@ -113,7 +117,7 @@ fn main() -> JsResult<()> { context .global_object() - .set("myArray", array, true, context)?; + .set(js_string!("myArray"), array, true, context)?; Ok(()) } diff --git a/boa_examples/src/bin/jsarraybuffer.rs b/boa_examples/src/bin/jsarraybuffer.rs index 53aaf2792b8..221e90ef256 100644 --- a/boa_examples/src/bin/jsarraybuffer.rs +++ b/boa_examples/src/bin/jsarraybuffer.rs @@ -1,6 +1,7 @@ // This example shows how to manipulate a Javascript array using Rust code. use boa_engine::{ + js_string, object::builtins::{JsArrayBuffer, JsDataView, JsUint32Array, JsUint8Array}, property::Attribute, Context, JsResult, JsValue, @@ -52,7 +53,7 @@ fn main() -> JsResult<()> { // We can also register it as a global property context .register_global_property( - "myArrayBuffer", + js_string!("myArrayBuffer"), array_buffer, Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE, ) diff --git a/boa_examples/src/bin/jsdate.rs b/boa_examples/src/bin/jsdate.rs index 8d3825db250..8d4953dc616 100644 --- a/boa_examples/src/bin/jsdate.rs +++ b/boa_examples/src/bin/jsdate.rs @@ -1,4 +1,4 @@ -use boa_engine::{object::builtins::JsDate, Context, JsResult, JsValue}; +use boa_engine::{js_string, object::builtins::JsDate, Context, JsResult, JsValue}; fn main() -> JsResult<()> { let context = &mut Context::default(); @@ -51,27 +51,27 @@ fn main() -> JsResult<()> { assert_eq!( date.to_json(context)?, - JsValue::from("2000-10-09T17:42:59.059Z") + JsValue::from(js_string!("2000-10-09T17:42:59.059Z")) ); assert_eq!( date.to_date_string(context)?, - JsValue::from("Mon Oct 09 2000") + JsValue::from(js_string!("Mon Oct 09 2000")) ); assert_eq!( date.to_iso_string(context)?, - JsValue::from("2000-10-09T17:42:59.059Z") + JsValue::from(js_string!("2000-10-09T17:42:59.059Z")) ); assert_eq!( date.to_time_string(context)?, - JsValue::from("23:12:59 GMT+0530") + JsValue::from(js_string!("23:12:59 GMT+0530")) ); assert_eq!( date.to_string(context)?, - JsValue::from("Mon Oct 09 2000 23:12:59 GMT+0530") + JsValue::from(js_string!("Mon Oct 09 2000 23:12:59 GMT+0530")) ); Ok(()) diff --git a/boa_examples/src/bin/jsmap.rs b/boa_examples/src/bin/jsmap.rs index 928d8c66722..3ac1b06c8aa 100644 --- a/boa_examples/src/bin/jsmap.rs +++ b/boa_examples/src/bin/jsmap.rs @@ -1,4 +1,5 @@ use boa_engine::{ + js_string, object::{builtins::JsArray, builtins::JsMap}, Context, JsResult, JsValue, }; @@ -11,9 +12,9 @@ fn main() -> JsResult<()> { let map = JsMap::new(context); // Set a key-value for the map. - map.set("Key-1", "Value-1", context)?; + map.set(js_string!("Key-1"), js_string!("Value-1"), context)?; - let map_check = map.has("Key-1", context)?; + let map_check = map.has(js_string!("Key-1"), context)?; assert_eq!(map_check, true.into()); // true // Set a second key-value to the same map. @@ -21,13 +22,16 @@ fn main() -> JsResult<()> { assert_eq!(map.get_size(context)?, 2.into()); //true - assert_eq!(map.get("Key-1", context)?, "Value-1".into()); + assert_eq!( + map.get(js_string!("Key-1"), context)?, + js_string!("Value-1").into() + ); assert_eq!(map.get(2, context)?, 4.into()); // Delete an entry with a provided key. - map.delete("Key-1", context)?; + map.delete(js_string!("Key-1"), context)?; assert_eq!(map.get_size(context)?, 1.into()); - let deleted_key_one = map.get("Key-1", context)?; + let deleted_key_one = map.get(js_string!("Key-1"), context)?; assert_eq!(deleted_key_one, JsValue::undefined()); @@ -39,8 +43,14 @@ fn main() -> JsResult<()> { // Create a multidimensional array with key value pairs -> [[first-key, first-value], [second-key, second-value]] let js_array = JsArray::new(context); - let vec_one = vec![JsValue::new("first-key"), JsValue::new("first-value")]; - let vec_two = vec![JsValue::new("second-key"), JsValue::new("second-value")]; + let vec_one = vec![ + JsValue::new(js_string!("first-key")), + JsValue::new(js_string!("first-value")), + ]; + let vec_two = vec![ + JsValue::new(js_string!("second-key")), + JsValue::new(js_string!("second-value")), + ]; js_array.push(JsArray::from_iter(vec_one, context), context)?; js_array.push(JsArray::from_iter(vec_two, context), context)?; @@ -48,9 +58,12 @@ fn main() -> JsResult<()> { // Create a map from the JsArray using it's iterable property. let iter_map = JsMap::from_js_iterable(&js_array.into(), context)?; - assert_eq!(iter_map.get("first-key", context)?, "first-value".into()); + assert_eq!( + iter_map.get(js_string!("first-key"), context)?, + js_string!("first-value").into() + ); - iter_map.set("third-key", "third-value", context)?; + iter_map.set(js_string!("third-key"), js_string!("third-value"), context)?; assert_eq!(iter_map.get_size(context)?, JsValue::new(3)); diff --git a/boa_examples/src/bin/jsregexp.rs b/boa_examples/src/bin/jsregexp.rs index 474788eafab..e79bfa52736 100644 --- a/boa_examples/src/bin/jsregexp.rs +++ b/boa_examples/src/bin/jsregexp.rs @@ -1,11 +1,11 @@ -use boa_engine::{object::builtins::JsRegExp, Context, JsResult}; +use boa_engine::{js_string, object::builtins::JsRegExp, Context, JsResult}; fn main() -> JsResult<()> { let context = &mut Context::default(); - let regexp = JsRegExp::new("foo", "gi", context)?; + let regexp = JsRegExp::new(js_string!("foo"), js_string!("gi"), context)?; - let test_result = regexp.test("football", context)?; + let test_result = regexp.test(js_string!("football"), context)?; assert!(test_result); let flags = regexp.flags(context)?; diff --git a/boa_examples/src/bin/jsset.rs b/boa_examples/src/bin/jsset.rs index fbae5849d13..9703db3fe57 100644 --- a/boa_examples/src/bin/jsset.rs +++ b/boa_examples/src/bin/jsset.rs @@ -1,6 +1,6 @@ // This example shows how to manipulate a Javascript Set using Rust code. #![allow(clippy::bool_assert_comparison)] -use boa_engine::{object::builtins::JsSet, Context, JsError, JsValue}; +use boa_engine::{js_string, object::builtins::JsSet, Context, JsError, JsValue}; fn main() -> Result<(), JsError> { // New `Context` for a new Javascript executor. @@ -17,21 +17,21 @@ fn main() -> Result<(), JsError> { set.clear(context)?; assert_eq!(set.size()?, 0); - set.add("one", context)?; - set.add("two", context)?; - set.add("three", context)?; + set.add(js_string!("one"), context)?; + set.add(js_string!("two"), context)?; + set.add(js_string!("three"), context)?; - assert!(set.has("one", context)?); - assert_eq!(set.has("One", context)?, false); + assert!(set.has(js_string!("one"), context)?); + assert_eq!(set.has(js_string!("One"), context)?, false); - set.delete("two", context)?; + set.delete(js_string!("two"), context)?; - assert_eq!(set.has("two", context)?, false); + assert_eq!(set.has(js_string!("two"), context)?, false); set.clear(context)?; - assert_eq!(set.has("one", context)?, false); - assert_eq!(set.has("three", context)?, false); + assert_eq!(set.has(js_string!("one"), context)?, false); + assert_eq!(set.has(js_string!("three"), context)?, false); assert_eq!(set.size()?, 0); // Add a slice into a set; diff --git a/boa_examples/src/bin/jstypedarray.rs b/boa_examples/src/bin/jstypedarray.rs index 1da60569207..fed57da639f 100644 --- a/boa_examples/src/bin/jstypedarray.rs +++ b/boa_examples/src/bin/jstypedarray.rs @@ -1,6 +1,7 @@ // This example shows how to manipulate a Javascript array using Rust code. use boa_engine::{ + js_string, native_function::NativeFunction, object::{builtins::JsUint8Array, FunctionObjectBuilder}, property::Attribute, @@ -42,7 +43,7 @@ fn main() -> JsResult<()> { context .register_global_property( - "myUint8Array", + js_string!("myUint8Array"), array, Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE, ) diff --git a/boa_examples/src/bin/modulehandler.rs b/boa_examples/src/bin/modulehandler.rs index fdb324d1bb5..4e986bd9d02 100644 --- a/boa_examples/src/bin/modulehandler.rs +++ b/boa_examples/src/bin/modulehandler.rs @@ -2,8 +2,8 @@ // the require/module.exports pattern use boa_engine::{ - native_function::NativeFunction, prelude::JsObject, property::Attribute, Context, JsResult, - JsValue, Source, + js_string, native_function::NativeFunction, prelude::JsObject, property::Attribute, Context, + JsResult, JsValue, Source, }; use std::fs::read_to_string; @@ -20,16 +20,29 @@ fn main() { let mut ctx = Context::default(); // Adding custom implementation that mimics 'require' - ctx.register_global_callable("require", 0, NativeFunction::from_fn_ptr(require)) - .unwrap(); + ctx.register_global_callable( + js_string!("require"), + 0, + NativeFunction::from_fn_ptr(require), + ) + .unwrap(); // Adding custom object that mimics 'module.exports' let moduleobj = JsObject::default(); moduleobj - .set("exports", JsValue::from(" "), false, &mut ctx) - .unwrap(); - ctx.register_global_property("module", JsValue::from(moduleobj), Attribute::default()) + .set( + js_string!("exports"), + JsValue::from(js_string!(" ")), + false, + &mut ctx, + ) .unwrap(); + ctx.register_global_property( + js_string!("module"), + JsValue::from(moduleobj), + Attribute::default(), + ) + .unwrap(); // Instantiating the engine with the execution context // Loading, parsing and executing the JS code from the source file @@ -58,7 +71,7 @@ fn require(_: &JsValue, args: &[JsValue], ctx: &mut Context<'_>) -> JsResult Result<(), Box> { // We can access the full namespace of the module with all its exports. let namespace = module.namespace(context); - let result = namespace.get("result", context)?; + let result = namespace.get(js_string!("result"), context)?; println!("result = {}", result.display()); - assert_eq!(namespace.get("result", context)?, JsValue::from(5)); + assert_eq!( + namespace.get(js_string!("result"), context)?, + JsValue::from(5) + ); let mix = namespace - .get("mix", context)? + .get(js_string!("mix"), context)? .as_callable() .cloned() .ok_or_else(|| JsNativeError::typ().with_message("mix export wasn't a function!"))?; diff --git a/boa_macros/src/lib.rs b/boa_macros/src/lib.rs index 3727e9ee6b9..0851ec37d4d 100644 --- a/boa_macros/src/lib.rs +++ b/boa_macros/src/lib.rs @@ -332,7 +332,7 @@ pub fn derive_try_from_js(input: TokenStream) -> TokenStream { // Build the output, possibly using quasi-quotation let expanded = quote! { - impl boa_engine::value::TryFromJs for #type_name { + impl ::boa_engine::value::TryFromJs for #type_name { fn try_from_js(value: &boa_engine::JsValue, context: &mut boa_engine::Context) -> boa_engine::JsResult { match value { @@ -396,24 +396,24 @@ fn generate_conversion(fields: FieldsNamed) -> Result Result(), "init"); let state = Rc::new(RefCell::new(Self::default())); ObjectInitializer::with_native(Self::default(), context) - .function(console_method(Self::assert, state.clone()), "assert", 0) - .function(console_method_mut(Self::clear, state.clone()), "clear", 0) - .function(console_method(Self::debug, state.clone()), "debug", 0) - .function(console_method(Self::error, state.clone()), "error", 0) - .function(console_method(Self::info, state.clone()), "info", 0) - .function(console_method(Self::log, state.clone()), "log", 0) - .function(console_method(Self::trace, state.clone()), "trace", 0) - .function(console_method(Self::warn, state.clone()), "warn", 0) - .function(console_method_mut(Self::count, state.clone()), "count", 0) + .function( + console_method(Self::assert, state.clone()), + js_string!("assert"), + 0, + ) + .function( + console_method_mut(Self::clear, state.clone()), + js_string!("clear"), + 0, + ) + .function( + console_method(Self::debug, state.clone()), + js_string!("debug"), + 0, + ) + .function( + console_method(Self::error, state.clone()), + js_string!("error"), + 0, + ) + .function( + console_method(Self::info, state.clone()), + js_string!("info"), + 0, + ) + .function( + console_method(Self::log, state.clone()), + js_string!("log"), + 0, + ) + .function( + console_method(Self::trace, state.clone()), + js_string!("trace"), + 0, + ) + .function( + console_method(Self::warn, state.clone()), + js_string!("warn"), + 0, + ) + .function( + console_method_mut(Self::count, state.clone()), + js_string!("count"), + 0, + ) .function( console_method_mut(Self::count_reset, state.clone()), - "countReset", + js_string!("countReset"), + 0, + ) + .function( + console_method_mut(Self::group, state.clone()), + js_string!("group"), 0, ) - .function(console_method_mut(Self::group, state.clone()), "group", 0) .function( console_method_mut(Self::group, state.clone()), - "groupCollapsed", + js_string!("groupCollapsed"), 0, ) .function( console_method_mut(Self::group_end, state.clone()), - "groupEnd", + js_string!("groupEnd"), + 0, + ) + .function( + console_method_mut(Self::time, state.clone()), + js_string!("time"), + 0, + ) + .function( + console_method(Self::time_log, state.clone()), + js_string!("timeLog"), 0, ) - .function(console_method_mut(Self::time, state.clone()), "time", 0) - .function(console_method(Self::time_log, state.clone()), "timeLog", 0) .function( console_method_mut(Self::time_end, state.clone()), - "timeEnd", + js_string!("timeEnd"), + 0, + ) + .function( + console_method(Self::dir, state.clone()), + js_string!("dir"), 0, ) - .function(console_method(Self::dir, state.clone()), "dir", 0) - .function(console_method(Self::dir, state), "dirxml", 0) + .function(console_method(Self::dir, state), js_string!("dirxml"), 0) .build() } @@ -219,13 +273,14 @@ impl Console { if !assertion { let mut args: Vec = args.iter().skip(1).cloned().collect(); - let message = "Assertion failed".to_string(); + let message = js_string!("Assertion failed"); if args.is_empty() { args.push(JsValue::new(message)); } else if !args[0].is_string() { args.insert(0, JsValue::new(message)); } else { - let concat = format!("{message}: {}", args[0].display()); + let value: Vec = args[0].display().to_string().encode_utf16().collect(); + let concat = js_string!(&message, utf16!(": "), &value); args[0] = JsValue::new(concat); } diff --git a/boa_runtime/src/console/tests.rs b/boa_runtime/src/console/tests.rs index 1b030256716..ab7596a6b77 100644 --- a/boa_runtime/src/console/tests.rs +++ b/boa_runtime/src/console/tests.rs @@ -1,6 +1,6 @@ use super::{formatter, Console}; use crate::test::{run_test_actions, run_test_actions_with, TestAction}; -use boa_engine::{property::Attribute, Context, JsValue}; +use boa_engine::{js_string, property::Attribute, Context, JsValue}; use indoc::indoc; #[test] @@ -13,7 +13,7 @@ fn formatter_no_args_is_empty_string() { #[test] fn formatter_empty_format_string_is_empty_string() { run_test_actions([TestAction::inspect_context(|ctx| { - assert_eq!(formatter(&[JsValue::new("")], ctx).unwrap(), ""); + assert_eq!(formatter(&[JsValue::new(js_string!())], ctx).unwrap(), ""); })]); } @@ -21,7 +21,7 @@ fn formatter_empty_format_string_is_empty_string() { fn formatter_format_without_args_renders_verbatim() { run_test_actions([TestAction::inspect_context(|ctx| { assert_eq!( - formatter(&[JsValue::new("%d %s %% %f")], ctx).unwrap(), + formatter(&[JsValue::new(js_string!("%d %s %% %f"))], ctx).unwrap(), "%d %s %% %f" ); })]); @@ -33,9 +33,9 @@ fn formatter_empty_format_string_concatenates_rest_of_args() { assert_eq!( formatter( &[ - JsValue::new(""), - JsValue::new("to powinno zostać"), - JsValue::new("połączone"), + JsValue::new(js_string!("")), + JsValue::new(js_string!("to powinno zostać")), + JsValue::new(js_string!("połączone")), ], ctx ) @@ -51,10 +51,10 @@ fn formatter_utf_8_checks() { assert_eq!( formatter( &[ - JsValue::new("Są takie chwile %dą %są tu%sów %привет%ź".to_string()), + JsValue::new(js_string!("Są takie chwile %dą %są tu%sów %привет%ź")), JsValue::new(123), JsValue::new(1.23), - JsValue::new("ł"), + JsValue::new(js_string!("ł")), ], ctx ) @@ -68,7 +68,14 @@ fn formatter_utf_8_checks() { fn formatter_trailing_format_leader_renders() { run_test_actions([TestAction::inspect_context(|ctx| { assert_eq!( - formatter(&[JsValue::new("%%%%%"), JsValue::new("|")], ctx).unwrap(), + formatter( + &[ + JsValue::new(js_string!("%%%%%")), + JsValue::new(js_string!("|")) + ], + ctx + ) + .unwrap(), "%%% |" ); })]); @@ -79,7 +86,7 @@ fn formatter_trailing_format_leader_renders() { fn formatter_float_format_works() { run_test_actions([TestAction::inspect_context(|ctx| { assert_eq!( - formatter(&[JsValue::new("%f"), JsValue::new(3.1415)], ctx).unwrap(), + formatter(&[JsValue::new(js_string!("%f")), JsValue::new(3.1415)], ctx).unwrap(), "3.141500" ); })]); @@ -90,7 +97,7 @@ fn console_log_cyclic() { let mut context = Context::default(); let console = Console::init(&mut context); context - .register_global_property(Console::NAME, console, Attribute::all()) + .register_global_property(js_string!(Console::NAME), console, Attribute::all()) .unwrap(); run_test_actions_with( diff --git a/boa_runtime/src/lib.rs b/boa_runtime/src/lib.rs index bf146379945..ab6dc889cc6 100644 --- a/boa_runtime/src/lib.rs +++ b/boa_runtime/src/lib.rs @@ -6,7 +6,7 @@ //! 1. Add **boa_runtime** as a dependency to your project along with **boa_engine**. //! //! ``` -//! use boa_engine::{ Context, Source, property::Attribute }; +//! use boa_engine::{ Context, Source, property::Attribute, js_string }; //! use boa_runtime::Console; //! //! // Create the context. @@ -17,7 +17,7 @@ //! //! // Register the console as a global property to the context. //! context -//! .register_global_property(Console::NAME, console, Attribute::all()) +//! .register_global_property(js_string!(Console::NAME), console, Attribute::all()) //! .expect("the console object shouldn't exist yet"); //! //! // JavaScript source for parsing. diff --git a/boa_tester/src/exec/js262.rs b/boa_tester/src/exec/js262.rs index 13e81a68308..cec67874476 100644 --- a/boa_tester/src/exec/js262.rs +++ b/boa_tester/src/exec/js262.rs @@ -1,4 +1,5 @@ use boa_engine::{ + js_string, native_function::NativeFunction, object::{JsObject, ObjectInitializer}, property::Attribute, @@ -10,16 +11,24 @@ pub(super) fn register_js262(context: &mut Context<'_>) -> JsObject { let global_obj = context.global_object(); let js262 = ObjectInitializer::new(context) - .function(NativeFunction::from_fn_ptr(create_realm), "createRealm", 0) + .function( + NativeFunction::from_fn_ptr(create_realm), + js_string!("createRealm"), + 0, + ) .function( NativeFunction::from_fn_ptr(detach_array_buffer), - "detachArrayBuffer", + js_string!("detachArrayBuffer"), 2, ) - .function(NativeFunction::from_fn_ptr(eval_script), "evalScript", 1) - .function(NativeFunction::from_fn_ptr(gc), "gc", 0) + .function( + NativeFunction::from_fn_ptr(eval_script), + js_string!("evalScript"), + 1, + ) + .function(NativeFunction::from_fn_ptr(gc), js_string!("gc"), 0) .property( - "global", + js_string!("global"), global_obj, Attribute::WRITABLE | Attribute::CONFIGURABLE, ) @@ -28,7 +37,7 @@ pub(super) fn register_js262(context: &mut Context<'_>) -> JsObject { context .register_global_property( - "$262", + js_string!("$262"), js262.clone(), Attribute::WRITABLE | Attribute::CONFIGURABLE, ) diff --git a/boa_tester/src/exec/mod.rs b/boa_tester/src/exec/mod.rs index 57064fa03f0..8d0201d39c0 100644 --- a/boa_tester/src/exec/mod.rs +++ b/boa_tester/src/exec/mod.rs @@ -8,6 +8,7 @@ use crate::{ }; use boa_engine::{ builtins::promise::PromiseState, + js_string, module::{Module, ModuleLoader, SimpleModuleLoader}, native_function::NativeFunction, object::FunctionObjectBuilder, @@ -606,10 +607,10 @@ fn is_error_type(error: &JsError, target_type: ErrorType, context: &mut Context< .as_opaque() .expect("try_native cannot fail if e is not opaque") .as_object() - .and_then(|o| o.get("constructor", context).ok()) + .and_then(|o| o.get(js_string!("constructor"), context).ok()) .as_ref() .and_then(JsValue::as_object) - .and_then(|o| o.get("name", context).ok()) + .and_then(|o| o.get(js_string!("name"), context).ok()) .as_ref() .and_then(JsValue::as_string) .map(|s| s == target_type.as_str()) @@ -653,7 +654,7 @@ fn register_print_fn(context: &mut Context<'_>, async_result: AsyncResult) { context .register_global_property( - "print", + js_string!("print"), js_function, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, )