Browse Source

Remove direct conversion from `&str` to `JsValue`/`PropertyKey`. (#3319)

* Remove direct conversion from `&str` to `JsValue`/`PropertyKey`.

* Allow unused static strings

* Introduce DHAT to benchmark data usage

* Create new release profile

* Fix docs
pull/3323/head
José Julián Espina 1 year ago committed by GitHub
parent
commit
b80409d87d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .gitignore
  2. 50
      Cargo.lock
  3. 4
      Cargo.toml
  4. 2
      boa_cli/Cargo.toml
  5. 31
      boa_cli/src/debug/function.rs
  6. 10
      boa_cli/src/debug/gc.rs
  7. 5
      boa_cli/src/debug/limits.rs
  8. 18
      boa_cli/src/debug/mod.rs
  9. 7
      boa_cli/src/debug/object.rs
  10. 5
      boa_cli/src/debug/optimizer.rs
  11. 6
      boa_cli/src/debug/realm.rs
  12. 8
      boa_cli/src/debug/shape.rs
  13. 17
      boa_cli/src/main.rs
  14. 1
      boa_engine/Cargo.toml
  15. 7
      boa_engine/src/builtins/array/array_iterator.rs
  16. 83
      boa_engine/src/builtins/array/mod.rs
  17. 22
      boa_engine/src/builtins/array/tests.rs
  18. 19
      boa_engine/src/builtins/array_buffer/mod.rs
  19. 7
      boa_engine/src/builtins/async_function/mod.rs
  20. 14
      boa_engine/src/builtins/async_generator/mod.rs
  21. 7
      boa_engine/src/builtins/async_generator_function/mod.rs
  22. 22
      boa_engine/src/builtins/bigint/mod.rs
  23. 10
      boa_engine/src/builtins/bigint/tests.rs
  24. 14
      boa_engine/src/builtins/boolean/mod.rs
  25. 64
      boa_engine/src/builtins/dataview/mod.rs
  26. 200
      boa_engine/src/builtins/date/mod.rs
  27. 22
      boa_engine/src/builtins/date/tests.rs
  28. 11
      boa_engine/src/builtins/error/aggregate.rs
  29. 11
      boa_engine/src/builtins/error/eval.rs
  30. 12
      boa_engine/src/builtins/error/mod.rs
  31. 11
      boa_engine/src/builtins/error/range.rs
  32. 13
      boa_engine/src/builtins/error/reference.rs
  33. 11
      boa_engine/src/builtins/error/syntax.rs
  34. 66
      boa_engine/src/builtins/error/tests.rs
  35. 13
      boa_engine/src/builtins/error/type.rs
  36. 11
      boa_engine/src/builtins/error/uri.rs
  37. 8
      boa_engine/src/builtins/escape/mod.rs
  38. 5
      boa_engine/src/builtins/eval/mod.rs
  39. 18
      boa_engine/src/builtins/function/mod.rs
  40. 14
      boa_engine/src/builtins/function/tests.rs
  41. 14
      boa_engine/src/builtins/generator/mod.rs
  42. 7
      boa_engine/src/builtins/generator_function/mod.rs
  43. 55
      boa_engine/src/builtins/intl/collator/mod.rs
  44. 10
      boa_engine/src/builtins/intl/date_time_format.rs
  45. 56
      boa_engine/src/builtins/intl/list_format/mod.rs
  46. 58
      boa_engine/src/builtins/intl/locale/mod.rs
  47. 5
      boa_engine/src/builtins/intl/locale/utils.rs
  48. 16
      boa_engine/src/builtins/intl/mod.rs
  49. 33
      boa_engine/src/builtins/intl/plural_rules/mod.rs
  50. 21
      boa_engine/src/builtins/intl/segmenter/mod.rs
  51. 2
      boa_engine/src/builtins/intl/segmenter/segments.rs
  52. 9
      boa_engine/src/builtins/iterable/async_from_sync_iterator.rs
  53. 10
      boa_engine/src/builtins/json/mod.rs
  54. 66
      boa_engine/src/builtins/json/tests.rs
  55. 7
      boa_engine/src/builtins/map/map_iterator.rs
  56. 33
      boa_engine/src/builtins/map/mod.rs
  57. 18
      boa_engine/src/builtins/map/tests.rs
  58. 96
      boa_engine/src/builtins/math/mod.rs
  59. 22
      boa_engine/src/builtins/mod.rs
  60. 12
      boa_engine/src/builtins/number/globals.rs
  61. 99
      boa_engine/src/builtins/number/mod.rs
  62. 239
      boa_engine/src/builtins/number/tests.rs
  63. 5
      boa_engine/src/builtins/object/for_in_iterator.rs
  64. 110
      boa_engine/src/builtins/object/mod.rs
  65. 29
      boa_engine/src/builtins/object/tests.rs
  66. 45
      boa_engine/src/builtins/promise/mod.rs
  67. 11
      boa_engine/src/builtins/proxy/mod.rs
  68. 34
      boa_engine/src/builtins/reflect/mod.rs
  69. 9
      boa_engine/src/builtins/reflect/tests.rs
  70. 120
      boa_engine/src/builtins/regexp/mod.rs
  71. 7
      boa_engine/src/builtins/regexp/regexp_string_iterator.rs
  72. 26
      boa_engine/src/builtins/regexp/tests.rs
  73. 27
      boa_engine/src/builtins/set/mod.rs
  74. 7
      boa_engine/src/builtins/set/set_iterator.rs
  75. 134
      boa_engine/src/builtins/string/mod.rs
  76. 6
      boa_engine/src/builtins/string/string_iterator.rs
  77. 131
      boa_engine/src/builtins/string/tests.rs
  78. 50
      boa_engine/src/builtins/symbol/mod.rs
  79. 4
      boa_engine/src/builtins/symbol/tests.rs
  80. 194
      boa_engine/src/builtins/typed_array/mod.rs
  81. 10
      boa_engine/src/builtins/uri/mod.rs
  82. 12
      boa_engine/src/builtins/weak/weak_ref.rs
  83. 17
      boa_engine/src/builtins/weak_map/mod.rs
  84. 15
      boa_engine/src/builtins/weak_set/mod.rs
  85. 9
      boa_engine/src/class.rs
  86. 2
      boa_engine/src/context/intrinsics.rs
  87. 35
      boa_engine/src/context/mod.rs
  88. 40
      boa_engine/src/error.rs
  89. 6
      boa_engine/src/object/builtins/jsdate.rs
  90. 70
      boa_engine/src/object/builtins/jsmap.rs
  91. 49
      boa_engine/src/object/builtins/jspromise.rs
  92. 30
      boa_engine/src/object/builtins/jsregexp.rs
  93. 2
      boa_engine/src/object/internal_methods/integer_indexed.rs
  94. 3
      boa_engine/src/object/jsobject.rs
  95. 31
      boa_engine/src/object/mod.rs
  96. 2
      boa_engine/src/optimizer/pass/constant_folding.rs
  97. 24
      boa_engine/src/property/mod.rs
  98. 289
      boa_engine/src/string/common.rs
  99. 2
      boa_engine/src/string/mod.rs
  100. 26
      boa_engine/src/symbol.rs
  101. Some files were not shown because too many files have changed in this diff Show More

4
.gitignore vendored

@ -39,3 +39,7 @@ chrome_profiler.json
# e2e test
playwright-report
test-results
# dhat
dhat-*.json
perf.data*

50
Cargo.lock generated

@ -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"

4
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.

2
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

31
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<JsValue> {
@ -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<JsV
pub(super) fn create_object(context: &mut Context<'_>) -> 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()
}

10
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<JsValue> {
@ -8,6 +10,10 @@ fn collect(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue>
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()
}

5
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,

18
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,
)

7
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<JsValue> {
};
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()
}

5
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,

6
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<JsValue> {
@ -9,6 +11,6 @@ fn create(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue>
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()
}

8
boa_cli/src/debug/shape.rs

@ -23,7 +23,7 @@ fn id(_: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue> {
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<JsValue>
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()
}

17
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");
}

1
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 }

7
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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();

83
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::<Self>(), "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 {

22
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")),
]);
}

19
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::<Self>(), "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::<Self>(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 {

7
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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 {

14
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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 )`
///

7
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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 {

22
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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()`

10
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")),
]);
}

14
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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<JsValue> {
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.

64
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::<Self>(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 {

200
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::<Self>(), "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::<Self>(realm)
.static_method(Self::now, "now", 0)
.static_method(Self::parse, "parse", 1)
.static_method(Self::utc, "UTC", 7)
.method(Self::get_date::<true>, "getDate", 0)
.method(Self::get_day::<true>, "getDay", 0)
.method(Self::get_full_year::<true>, "getFullYear", 0)
.method(Self::get_hours::<true>, "getHours", 0)
.method(Self::get_milliseconds::<true>, "getMilliseconds", 0)
.method(Self::get_minutes::<true>, "getMinutes", 0)
.method(Self::get_month::<true>, "getMonth", 0)
.method(Self::get_seconds::<true>, "getSeconds", 0)
.method(Self::get_time, "getTime", 0)
.method(Self::get_timezone_offset, "getTimezoneOffset", 0)
.method(Self::get_date::<false>, "getUTCDate", 0)
.method(Self::get_day::<false>, "getUTCDay", 0)
.method(Self::get_full_year::<false>, "getUTCFullYear", 0)
.method(Self::get_hours::<false>, "getUTCHours", 0)
.method(Self::get_milliseconds::<false>, "getUTCMilliseconds", 0)
.method(Self::get_minutes::<false>, "getUTCMinutes", 0)
.method(Self::get_month::<false>, "getUTCMonth", 0)
.method(Self::get_seconds::<false>, "getUTCSeconds", 0)
.method(Self::get_year, "getYear", 0)
.method(Self::set_date::<true>, "setDate", 1)
.method(Self::set_full_year::<true>, "setFullYear", 3)
.method(Self::set_hours::<true>, "setHours", 4)
.method(Self::set_milliseconds::<true>, "setMilliseconds", 1)
.method(Self::set_minutes::<true>, "setMinutes", 3)
.method(Self::set_month::<true>, "setMonth", 2)
.method(Self::set_seconds::<true>, "setSeconds", 2)
.method(Self::set_time, "setTime", 1)
.method(Self::set_date::<false>, "setUTCDate", 1)
.method(Self::set_full_year::<false>, "setUTCFullYear", 3)
.method(Self::set_hours::<false>, "setUTCHours", 4)
.method(Self::set_milliseconds::<false>, "setUTCMilliseconds", 1)
.method(Self::set_minutes::<false>, "setUTCMinutes", 3)
.method(Self::set_month::<false>, "setUTCMonth", 2)
.method(Self::set_seconds::<false>, "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::<true>, js_string!("getDate"), 0)
.method(Self::get_day::<true>, js_string!("getDay"), 0)
.method(Self::get_full_year::<true>, js_string!("getFullYear"), 0)
.method(Self::get_hours::<true>, js_string!("getHours"), 0)
.method(
Self::get_milliseconds::<true>,
js_string!("getMilliseconds"),
0,
)
.method(Self::get_minutes::<true>, js_string!("getMinutes"), 0)
.method(Self::get_month::<true>, js_string!("getMonth"), 0)
.method(Self::get_seconds::<true>, 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::<false>, js_string!("getUTCDate"), 0)
.method(Self::get_day::<false>, js_string!("getUTCDay"), 0)
.method(
Self::get_full_year::<false>,
js_string!("getUTCFullYear"),
0,
)
.method(Self::get_hours::<false>, js_string!("getUTCHours"), 0)
.method(
Self::get_milliseconds::<false>,
js_string!("getUTCMilliseconds"),
0,
)
.method(Self::get_minutes::<false>, js_string!("getUTCMinutes"), 0)
.method(Self::get_month::<false>, js_string!("getUTCMonth"), 0)
.method(Self::get_seconds::<false>, js_string!("getUTCSeconds"), 0)
.method(Self::get_year, js_string!("getYear"), 0)
.method(Self::set_date::<true>, js_string!("setDate"), 1)
.method(Self::set_full_year::<true>, js_string!("setFullYear"), 3)
.method(Self::set_hours::<true>, js_string!("setHours"), 4)
.method(
Self::set_milliseconds::<true>,
js_string!("setMilliseconds"),
1,
)
.method(Self::set_minutes::<true>, js_string!("setMinutes"), 3)
.method(Self::set_month::<true>, js_string!("setMonth"), 2)
.method(Self::set_seconds::<true>, js_string!("setSeconds"), 2)
.method(Self::set_time, js_string!("setTime"), 1)
.method(Self::set_date::<false>, js_string!("setUTCDate"), 1)
.method(
Self::set_full_year::<false>,
js_string!("setUTCFullYear"),
3,
)
.method(Self::set_hours::<false>, js_string!("setUTCHours"), 4)
.method(
Self::set_milliseconds::<false>,
js_string!("setUTCMilliseconds"),
1,
)
.method(Self::set_minutes::<false>, js_string!("setUTCMinutes"), 3)
.method(Self::set_month::<false>, js_string!("setUTCMonth"), 2)
.method(Self::set_seconds::<false>, 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<JsValue> {
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<JsValue> {
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<JsValue> {
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].

22
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"}"#),
)]);
}

11
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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 {

11
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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 {

12
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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 {

11
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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 {

13
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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 {

11
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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 {

66
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")),
]);
}

13
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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::<Self>(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();

11
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::<Self>(), "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::from_standard_constructor::<Self>(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 {

8
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.

5
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::<Self>(), "init");
BuiltInBuilder::callable_with_intrinsic::<Self>(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 {

18
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::<Self>(), "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::<Self>(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 {

14
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!")),
]);
}

14
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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 )`
///

7
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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 {

55
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::<Self>(), "init");
let compare = BuiltInBuilder::callable(realm, Self::compare)
.name("get compare")
.name(js_string!("get compare"))
.build();
BuiltInBuilder::from_standard_constructor::<Self>(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,

10
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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)?;
}
}

56
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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,

58
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::<Self>(), "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::<Self>(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 {

5
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,
))
}

16
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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,
)))
}

33
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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(),
);

21
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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();

2
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::<Self>(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]")),

9
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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();
}

10
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::<Self>(), "init");
let to_string_tag = JsSymbol::to_string_tag();
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
BuiltInBuilder::with_intrinsic::<Self>(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 {

66
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")),
]);
}

7
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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();

33
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::<Self>(), "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::<Self>(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 {

18
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")),
]);
}

96
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::<Self>(), "init");
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
BuiltInBuilder::with_intrinsic::<Self>(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 {

22
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<N: Into<JsString>>(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<N: Into<JsString>>(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<FnTyp> BuiltInBuilder<'_, Callable<FnTyp>> {
/// Specify the name of the constructor function.
///
/// Default is `""`
fn name<N: Into<JsString>>(mut self, name: N) -> Self {
self.kind.name = name.into();
fn name(mut self, name: JsString) -> Self {
self.kind.name = name;
self
}
}

12
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;
}

99
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::<Self>(), "init");
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
BuiltInBuilder::from_standard_constructor::<Self>(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<JsValue> {
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)
}

239
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"),
),
]);
}

5
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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();
}

110
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::<Self>(), "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::<Self>(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<JsValue> {
// 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,
}
});

29
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")),
]);
}

45
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::<Self>(), "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::<Self>(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)
// <https://tc39.es/ecma262/#sec-promise.prototype-@@tostringtag>
.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(

11
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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 {

34
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::<Self>(), "init");
let to_string_tag = JsSymbol::to_string_tag();
BuiltInBuilder::with_intrinsic::<Self>(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 {

9
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")),
]);
}

120
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::<Self>(), "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::<Self>(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 )

7
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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();

26
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"),

27
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::<Self>(), "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::<Self>(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 {

7
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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();

134
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::<Self>(), "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::<Self>(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::<false>, "toLowerCase", 0)
.method(Self::to_case::<true>, "toUpperCase", 0)
.method(Self::to_well_formed, "toWellFormed", 0)
.method(Self::to_locale_case::<false>, "toLocaleLowerCase", 0)
.method(Self::to_locale_case::<true>, "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::<false>, js_string!("toLowerCase"), 0)
.method(Self::to_case::<true>, js_string!("toUpperCase"), 0)
.method(Self::to_well_formed, js_string!("toWellFormed"), 0)
.method(
Self::to_locale_case::<false>,
js_string!("toLocaleLowerCase"),
0,
)
.method(
Self::to_locale_case::<true>,
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::<std::string::String>();
// 7. Return result.
Ok(result.into())
Ok(js_string!(result).into())
}
/// `String.prototype.substring( indexStart[, indexEnd] )`

6
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::<Self>(), "init");
BuiltInBuilder::with_intrinsic::<Self>(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();

131
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,

50
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::<Self>(), "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::<Self>(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 {

4
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)"),
)]);
}

194
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::<Self>(), "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::<Self>(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
);

10
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.

12
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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);
}

17
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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);
}

15
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::<Self>(), "init");
BuiltInBuilder::from_standard_constructor::<Self>(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);
}

9
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<T: Class> 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<str>,
{
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<str>,
{
self.builder.static_method(function, name.as_ref(), length);
self.builder
.static_method(function, js_string!(name.as_ref()), length);
self
}

2
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(),

35
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<K, V>(
@ -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(())
}

40
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::<Vec<_>>();
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)

6
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(())

70
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<JsValue> = vec![JsValue::new("first-key"), JsValue::new("first-value")];
/// let vec_one: Vec<JsValue> = 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<JsValue> = vec![JsValue::new("first-key"), JsValue::new("first-value")];
/// let vec_one: Vec<JsValue> = 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(())

49
boa_engine/src/object/builtins/jspromise.rs

@ -35,7 +35,11 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace};
/// # fn main() -> Result<(), Box<dyn Error>> {
/// 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<dyn Error>> {
/// 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(())
/// # }

30
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(())
/// # }
/// ```

2
boa_engine/src/object/internal_methods/integer_indexed.rs

@ -45,7 +45,7 @@ fn canonical_numeric_index_string(argument: &JsString) -> Option<f64> {
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);
}

3
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"),
});
}

31
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<String> for FunctionBinding {
#[inline]
fn from(name: String) -> Self {
let name: JsString = name.into();
Self {
binding: name.clone().into(),
name,
}
}
}
impl From<JsString> 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();

2
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)))

24
boa_engine/src/property/mod.rs

@ -678,28 +678,6 @@ impl From<JsString> 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<String> for PropertyKey {
#[inline]
fn from(string: String) -> Self {
parse_u32_index(string.bytes()).map_or_else(|| Self::String(string.into()), Self::Index)
}
}
impl From<Box<str>> for PropertyKey {
#[inline]
fn from(string: Box<str>) -> Self {
parse_u32_index(string.bytes())
.map_or_else(|| Self::String(string.as_ref().into()), Self::Index)
}
}
impl From<JsSymbol> for PropertyKey {
#[inline]
fn from(symbol: JsSymbol) -> Self {
@ -737,7 +715,7 @@ impl From<PropertyKey> 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(),
}
}
}

289
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]"),
];

2
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
}
}

26
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,
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save