Browse Source

Some string optimizations (#4030)

* chore: replace `js_str` with `js_string`

* chore: replace `boolean`'s `to_string` with literal

* chore: remove unnecessary `to_string`

* chore: fix lint and format

* chore: add feature gate to import `js_str`

* chore: change `get_typed_fn`'s name to `JsString`

* chore: replace js_str with js_string(cli)

* chore: replace js_str with js_string(`try_into_js`)

* chore: replace js_str with js_string(`Console`)

* chore: fix lint

* perf: use more efficient `LazyLock` on `RAW_STATICS_CACHE`

* chore: move `js_str` together with other imports
pull/4036/head
CrazyboyQCD 2 weeks ago committed by GitHub
parent
commit
f30514b085
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 9
      cli/src/debug/function.rs
  2. 20
      cli/src/debug/limits.rs
  3. 20
      cli/src/debug/mod.rs
  4. 6
      cli/src/debug/optimizer.rs
  5. 3
      core/engine/src/builtins/array/array_iterator.rs
  6. 39
      core/engine/src/builtins/array/mod.rs
  7. 4
      core/engine/src/builtins/async_generator/mod.rs
  8. 7
      core/engine/src/builtins/atomics/mod.rs
  9. 6
      core/engine/src/builtins/boolean/mod.rs
  10. 12
      core/engine/src/builtins/builder.rs
  11. 9
      core/engine/src/builtins/error/aggregate.rs
  12. 7
      core/engine/src/builtins/error/eval.rs
  13. 8
      core/engine/src/builtins/error/mod.rs
  14. 7
      core/engine/src/builtins/error/range.rs
  15. 7
      core/engine/src/builtins/error/reference.rs
  16. 7
      core/engine/src/builtins/error/syntax.rs
  17. 9
      core/engine/src/builtins/error/type.rs
  18. 7
      core/engine/src/builtins/error/uri.rs
  19. 6
      core/engine/src/builtins/function/mod.rs
  20. 48
      core/engine/src/builtins/intl/collator/mod.rs
  21. 39
      core/engine/src/builtins/intl/date_time_format.rs
  22. 30
      core/engine/src/builtins/intl/list_format/mod.rs
  23. 19
      core/engine/src/builtins/intl/locale/mod.rs
  24. 3
      core/engine/src/builtins/intl/locale/utils.rs
  25. 14
      core/engine/src/builtins/intl/number_format/mod.rs
  26. 30
      core/engine/src/builtins/intl/number_format/options.rs
  27. 4
      core/engine/src/builtins/intl/options.rs
  28. 60
      core/engine/src/builtins/intl/plural_rules/mod.rs
  29. 18
      core/engine/src/builtins/intl/segmenter/mod.rs
  30. 11
      core/engine/src/builtins/iterable/async_from_sync_iterator.rs
  31. 10
      core/engine/src/builtins/iterable/mod.rs
  32. 8
      core/engine/src/builtins/json/mod.rs
  33. 3
      core/engine/src/builtins/map/mod.rs
  34. 10
      core/engine/src/builtins/mod.rs
  35. 11
      core/engine/src/builtins/number/mod.rs
  36. 18
      core/engine/src/builtins/object/mod.rs
  37. 4
      core/engine/src/builtins/options.rs
  38. 36
      core/engine/src/builtins/promise/mod.rs
  39. 31
      core/engine/src/builtins/proxy/mod.rs
  40. 104
      core/engine/src/builtins/regexp/mod.rs
  41. 5
      core/engine/src/builtins/regexp/regexp_string_iterator.rs
  42. 3
      core/engine/src/builtins/set/mod.rs
  43. 13
      core/engine/src/builtins/string/mod.rs
  44. 4
      core/engine/src/builtins/temporal/calendar/mod.rs
  45. 35
      core/engine/src/builtins/temporal/duration/mod.rs
  46. 17
      core/engine/src/builtins/temporal/instant/mod.rs
  47. 9
      core/engine/src/builtins/temporal/mod.rs
  48. 16
      core/engine/src/builtins/temporal/options.rs
  49. 41
      core/engine/src/builtins/temporal/plain_date/mod.rs
  50. 70
      core/engine/src/builtins/temporal/plain_date_time/mod.rs
  51. 14
      core/engine/src/builtins/temporal/plain_month_day/mod.rs
  52. 45
      core/engine/src/builtins/temporal/plain_time/mod.rs
  53. 21
      core/engine/src/builtins/temporal/plain_year_month/mod.rs
  54. 4
      core/engine/src/builtins/typed_array/builtin.rs
  55. 5
      core/engine/src/builtins/typed_array/mod.rs
  56. 3
      core/engine/src/builtins/weak_map/mod.rs
  57. 3
      core/engine/src/builtins/weak_set/mod.rs
  58. 8
      core/engine/src/class.rs
  59. 19
      core/engine/src/context/intrinsics.rs
  60. 16
      core/engine/src/context/mod.rs
  61. 21
      core/engine/src/error.rs
  62. 6
      core/engine/src/module/mod.rs
  63. 4
      core/engine/src/object/builtins/jsdate.rs
  64. 64
      core/engine/src/object/builtins/jsmap.rs
  65. 12
      core/engine/src/object/builtins/jspromise.rs
  66. 28
      core/engine/src/object/builtins/jsproxy.rs
  67. 17
      core/engine/src/object/jsobject.rs
  68. 9
      core/engine/src/object/mod.rs
  69. 3
      core/engine/src/value/conversions/try_into_js.rs
  70. 8
      core/engine/src/value/display.rs
  71. 32
      core/engine/src/value/mod.rs
  72. 1
      core/engine/src/value/tests.rs
  73. 3
      core/engine/src/vm/mod.rs
  74. 6
      core/engine/src/vm/opcode/await/mod.rs
  75. 6
      core/engine/src/vm/opcode/generator/mod.rs
  76. 4
      core/engine/src/vm/opcode/iteration/for_in.rs
  77. 7
      core/engine/src/vm/opcode/iteration/iterator.rs
  78. 2
      core/engine/src/vm/opcode/push/class/private.rs
  79. 4
      core/engine/src/vm/opcode/templates/mod.rs
  80. 4
      core/engine/tests/gcd.rs
  81. 4
      core/interop/tests/fibonacci.rs
  82. 4
      core/interop/tests/gcd_callback.rs
  83. 2
      core/macros/src/lib.rs
  84. 6
      core/runtime/src/console/mod.rs
  85. 2
      core/runtime/src/console/tests.rs
  86. 27
      core/string/src/common.rs
  87. 4
      examples/src/bin/loadfile.rs

9
cli/src/debug/function.rs

@ -1,6 +1,6 @@
use boa_engine::{ use boa_engine::{
builtins::function::OrdinaryFunction, builtins::function::OrdinaryFunction,
js_str, js_string, js_string,
object::ObjectInitializer, object::ObjectInitializer,
vm::flowgraph::{Direction, Graph}, vm::flowgraph::{Direction, Graph},
Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction, Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction,
@ -68,9 +68,10 @@ fn flowgraph(_this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResu
let mut direction = Direction::LeftToRight; let mut direction = Direction::LeftToRight;
if let Some(arguments) = args.get(1) { if let Some(arguments) = args.get(1) {
if let Some(arguments) = arguments.as_object() { if let Some(arguments) = arguments.as_object() {
format = flowgraph_parse_format_option(&arguments.get(js_str!("format"), context)?)?; format = flowgraph_parse_format_option(&arguments.get(js_string!("format"), context)?)?;
direction = direction = flowgraph_parse_direction_option(
flowgraph_parse_direction_option(&arguments.get(js_str!("direction"), context)?)?; &arguments.get(js_string!("direction"), context)?,
)?;
} else if value.is_string() { } else if value.is_string() {
format = flowgraph_parse_format_option(value)?; format = flowgraph_parse_format_option(value)?;
} else { } else {

20
cli/src/debug/limits.rs

@ -1,5 +1,5 @@
use boa_engine::{ use boa_engine::{
js_str, js_string,
object::{FunctionObjectBuilder, ObjectInitializer}, object::{FunctionObjectBuilder, ObjectInitializer},
property::Attribute, property::Attribute,
Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction, Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction,
@ -51,51 +51,51 @@ fn set_recursion(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResu
pub(super) fn create_object(context: &mut Context) -> JsObject { pub(super) fn create_object(context: &mut Context) -> JsObject {
let get_loop = let get_loop =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_loop)) FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_loop))
.name(js_str!("get loop")) .name(js_string!("get loop"))
.length(0) .length(0)
.build(); .build();
let set_loop = let set_loop =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_loop)) FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_loop))
.name(js_str!("set loop")) .name(js_string!("set loop"))
.length(1) .length(1)
.build(); .build();
let get_stack = let get_stack =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_stack)) FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_stack))
.name(js_str!("get stack")) .name(js_string!("get stack"))
.length(0) .length(0)
.build(); .build();
let set_stack = let set_stack =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_stack)) FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_stack))
.name(js_str!("set stack")) .name(js_string!("set stack"))
.length(1) .length(1)
.build(); .build();
let get_recursion = let get_recursion =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_recursion)) FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_recursion))
.name(js_str!("get recursion")) .name(js_string!("get recursion"))
.length(0) .length(0)
.build(); .build();
let set_recursion = let set_recursion =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_recursion)) FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_recursion))
.name(js_str!("set recursion")) .name(js_string!("set recursion"))
.length(1) .length(1)
.build(); .build();
ObjectInitializer::new(context) ObjectInitializer::new(context)
.accessor( .accessor(
js_str!("loop"), js_string!("loop"),
Some(get_loop), Some(get_loop),
Some(set_loop), Some(set_loop),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
) )
.accessor( .accessor(
js_str!("stack"), js_string!("stack"),
Some(get_stack), Some(get_stack),
Some(set_stack), Some(set_stack),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
) )
.accessor( .accessor(
js_str!("recursion"), js_string!("recursion"),
Some(get_recursion), Some(get_recursion),
Some(set_recursion), Some(set_recursion),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,

20
cli/src/debug/mod.rs

@ -1,7 +1,7 @@
// Allow lint so it, doesn't warn about `JsResult<>` unneeded return on functions. // Allow lint so it, doesn't warn about `JsResult<>` unneeded return on functions.
#![allow(clippy::unnecessary_wraps)] #![allow(clippy::unnecessary_wraps)]
use boa_engine::{js_str, object::ObjectInitializer, property::Attribute, Context, JsObject}; use boa_engine::{js_string, object::ObjectInitializer, property::Attribute, Context, JsObject};
mod function; mod function;
mod gc; mod gc;
@ -24,42 +24,42 @@ fn create_boa_object(context: &mut Context) -> JsObject {
ObjectInitializer::new(context) ObjectInitializer::new(context)
.property( .property(
js_str!("function"), js_string!("function"),
function_module, function_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("object"), js_string!("object"),
object_module, object_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("shape"), js_string!("shape"),
shape_module, shape_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("optimizer"), js_string!("optimizer"),
optimizer_module, optimizer_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("gc"), js_string!("gc"),
gc_module, gc_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("realm"), js_string!("realm"),
realm_module, realm_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("limits"), js_string!("limits"),
limits_module, limits_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("string"), js_string!("string"),
string_module, string_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )
@ -71,7 +71,7 @@ pub(crate) fn init_boa_debug_object(context: &mut Context) {
let boa_object = create_boa_object(context); let boa_object = create_boa_object(context);
context context
.register_global_property( .register_global_property(
js_str!("$boa"), js_string!("$boa"),
boa_object, boa_object,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
) )

6
cli/src/debug/optimizer.rs

@ -1,5 +1,5 @@
use boa_engine::{ use boa_engine::{
js_str, js_string,
object::{FunctionObjectBuilder, ObjectInitializer}, object::{FunctionObjectBuilder, ObjectInitializer},
optimizer::OptimizerOptions, optimizer::OptimizerOptions,
property::Attribute, property::Attribute,
@ -64,13 +64,13 @@ pub(super) fn create_object(context: &mut Context) -> JsObject {
.build(); .build();
ObjectInitializer::new(context) ObjectInitializer::new(context)
.accessor( .accessor(
js_str!("constantFolding"), js_string!("constantFolding"),
Some(get_constant_folding), Some(get_constant_folding),
Some(set_constant_folding), Some(set_constant_folding),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
) )
.accessor( .accessor(
js_str!("statistics"), js_string!("statistics"),
Some(get_statistics), Some(get_statistics),
Some(set_statistics), Some(set_statistics),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,

3
core/engine/src/builtins/array/array_iterator.rs

@ -20,7 +20,6 @@ use crate::{
Context, JsData, JsResult, Context, JsData, JsResult,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
/// The Array Iterator object represents an iteration over an array. It implements the iterator protocol. /// The Array Iterator object represents an iteration over an array. It implements the iterator protocol.
@ -53,7 +52,7 @@ impl IntrinsicObject for ArrayIterator {
.static_method(Self::next, js_string!("next"), 0) .static_method(Self::next, js_string!("next"), 0)
.static_property( .static_property(
JsSymbol::to_string_tag(), JsSymbol::to_string_tag(),
js_str!("Array Iterator"), js_string!("Array Iterator"),
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.build(); .build();

39
core/engine/src/builtins/array/mod.rs

@ -10,7 +10,6 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use thin_vec::ThinVec; use thin_vec::ThinVec;
@ -2169,12 +2168,12 @@ impl Array {
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
{ {
// TODO: this should eventually return a locale-sensitive separator. // TODO: this should eventually return a locale-sensitive separator.
js_str!(", ") js_string!(", ")
} }
#[cfg(not(feature = "intl"))] #[cfg(not(feature = "intl"))]
{ {
js_str!(", ") js_string!(", ")
} }
}; };
@ -2197,7 +2196,7 @@ impl Array {
if !next.is_null_or_undefined() { if !next.is_null_or_undefined() {
// i. Let S be ? ToString(? Invoke(nextElement, "toLocaleString", « locales, options »)). // i. Let S be ? ToString(? Invoke(nextElement, "toLocaleString", « locales, options »)).
let s = next let s = next
.invoke(js_str!("toLocaleString"), args, context)? .invoke(js_string!("toLocaleString"), args, context)?
.to_string(context)?; .to_string(context)?;
// ii. Set R to the string-concatenation of R and S. // ii. Set R to the string-concatenation of R and S.
@ -3258,37 +3257,37 @@ impl Array {
{ {
let mut obj = unscopable_list.borrow_mut(); let mut obj = unscopable_list.borrow_mut();
// 2. Perform ! CreateDataPropertyOrThrow(unscopableList, "at", true). // 2. Perform ! CreateDataPropertyOrThrow(unscopableList, "at", true).
obj.insert(js_str!("at"), true_prop.clone()); obj.insert(js_string!("at"), true_prop.clone());
// 3. Perform ! CreateDataPropertyOrThrow(unscopableList, "copyWithin", true). // 3. Perform ! CreateDataPropertyOrThrow(unscopableList, "copyWithin", true).
obj.insert(js_str!("copyWithin"), true_prop.clone()); obj.insert(js_string!("copyWithin"), true_prop.clone());
// 4. Perform ! CreateDataPropertyOrThrow(unscopableList, "entries", true). // 4. Perform ! CreateDataPropertyOrThrow(unscopableList, "entries", true).
obj.insert(js_str!("entries"), true_prop.clone()); obj.insert(js_string!("entries"), true_prop.clone());
// 5. Perform ! CreateDataPropertyOrThrow(unscopableList, "fill", true). // 5. Perform ! CreateDataPropertyOrThrow(unscopableList, "fill", true).
obj.insert(js_str!("fill"), true_prop.clone()); obj.insert(js_string!("fill"), true_prop.clone());
// 6. Perform ! CreateDataPropertyOrThrow(unscopableList, "find", true). // 6. Perform ! CreateDataPropertyOrThrow(unscopableList, "find", true).
obj.insert(js_str!("find"), true_prop.clone()); obj.insert(js_string!("find"), true_prop.clone());
// 7. Perform ! CreateDataPropertyOrThrow(unscopableList, "findIndex", true). // 7. Perform ! CreateDataPropertyOrThrow(unscopableList, "findIndex", true).
obj.insert(js_str!("findIndex"), true_prop.clone()); obj.insert(js_string!("findIndex"), true_prop.clone());
// 8. Perform ! CreateDataPropertyOrThrow(unscopableList, "findLast", true). // 8. Perform ! CreateDataPropertyOrThrow(unscopableList, "findLast", true).
obj.insert(js_str!("findLast"), true_prop.clone()); obj.insert(js_string!("findLast"), true_prop.clone());
// 9. Perform ! CreateDataPropertyOrThrow(unscopableList, "findLastIndex", true). // 9. Perform ! CreateDataPropertyOrThrow(unscopableList, "findLastIndex", true).
obj.insert(js_str!("findLastIndex"), true_prop.clone()); obj.insert(js_string!("findLastIndex"), true_prop.clone());
// 10. Perform ! CreateDataPropertyOrThrow(unscopableList, "flat", true). // 10. Perform ! CreateDataPropertyOrThrow(unscopableList, "flat", true).
obj.insert(js_str!("flat"), true_prop.clone()); obj.insert(js_string!("flat"), true_prop.clone());
// 11. Perform ! CreateDataPropertyOrThrow(unscopableList, "flatMap", true). // 11. Perform ! CreateDataPropertyOrThrow(unscopableList, "flatMap", true).
obj.insert(js_str!("flatMap"), true_prop.clone()); obj.insert(js_string!("flatMap"), true_prop.clone());
// 12. Perform ! CreateDataPropertyOrThrow(unscopableList, "includes", true). // 12. Perform ! CreateDataPropertyOrThrow(unscopableList, "includes", true).
obj.insert(js_str!("includes"), true_prop.clone()); obj.insert(js_string!("includes"), true_prop.clone());
// 13. Perform ! CreateDataPropertyOrThrow(unscopableList, "keys", true). // 13. Perform ! CreateDataPropertyOrThrow(unscopableList, "keys", true).
obj.insert(js_str!("keys"), true_prop.clone()); obj.insert(js_string!("keys"), true_prop.clone());
// 14. Perform ! CreateDataPropertyOrThrow(unscopableList, "toReversed", true). // 14. Perform ! CreateDataPropertyOrThrow(unscopableList, "toReversed", true).
obj.insert(js_str!("toReversed"), true_prop.clone()); obj.insert(js_string!("toReversed"), true_prop.clone());
// 15. Perform ! CreateDataPropertyOrThrow(unscopableList, "toSorted", true). // 15. Perform ! CreateDataPropertyOrThrow(unscopableList, "toSorted", true).
obj.insert(js_str!("toSorted"), true_prop.clone()); obj.insert(js_string!("toSorted"), true_prop.clone());
// 16. Perform ! CreateDataPropertyOrThrow(unscopableList, "toSpliced", true). // 16. Perform ! CreateDataPropertyOrThrow(unscopableList, "toSpliced", true).
obj.insert(js_str!("toSpliced"), true_prop.clone()); obj.insert(js_string!("toSpliced"), true_prop.clone());
// 17. Perform ! CreateDataPropertyOrThrow(unscopableList, "values", true). // 17. Perform ! CreateDataPropertyOrThrow(unscopableList, "values", true).
obj.insert(js_str!("values"), true_prop); obj.insert(js_string!("values"), true_prop);
} }
// 13. Return unscopableList. // 13. Return unscopableList.

4
core/engine/src/builtins/async_generator/mod.rs

@ -561,7 +561,7 @@ impl AsyncGenerator {
generator.clone(), generator.clone(),
), ),
) )
.name(js_string!("")) .name(js_string!())
.length(1) .length(1)
.build(); .build();
@ -592,7 +592,7 @@ impl AsyncGenerator {
generator.clone(), generator.clone(),
), ),
) )
.name(js_string!("")) .name(js_string!())
.length(1) .length(1)
.build(); .build();

7
core/engine/src/builtins/atomics/mod.rs

@ -21,7 +21,6 @@ use crate::{
JsString, JsValue, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{ use super::{
@ -468,9 +467,9 @@ impl Atomics {
}; };
Ok(match result { Ok(match result {
futex::AtomicsWaitResult::NotEqual => js_str!("not-equal"), futex::AtomicsWaitResult::NotEqual => js_string!("not-equal"),
futex::AtomicsWaitResult::TimedOut => js_str!("timed-out"), futex::AtomicsWaitResult::TimedOut => js_string!("timed-out"),
futex::AtomicsWaitResult::Ok => js_str!("ok"), futex::AtomicsWaitResult::Ok => js_string!("ok"),
} }
.into()) .into())
} }

6
core/engine/src/builtins/boolean/mod.rs

@ -112,7 +112,11 @@ impl Boolean {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
pub(crate) fn to_string(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> { pub(crate) fn to_string(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
let boolean = Self::this_boolean_value(this)?; let boolean = Self::this_boolean_value(this)?;
Ok(JsValue::new(js_string!(boolean.to_string()))) Ok(JsValue::new(if boolean {
js_string!("true")
} else {
js_string!("false")
}))
} }
/// The `valueOf()` method returns the primitive value of a `Boolean` object. /// The `valueOf()` method returns the primitive value of a `Boolean` object.

12
core/engine/src/builtins/builder.rs

@ -1,5 +1,3 @@
use boa_macros::js_str;
use crate::{ use crate::{
js_string, js_string,
native_function::{NativeFunctionObject, NativeFunctionPointer}, native_function::{NativeFunctionObject, NativeFunctionPointer},
@ -119,7 +117,7 @@ impl<S: ApplyToObject + IsConstructor> ApplyToObject for Callable<S> {
.configurable(true), .configurable(true),
); );
object.insert( object.insert(
js_str!("name"), js_string!("name"),
PropertyDescriptor::builder() PropertyDescriptor::builder()
.value(self.name) .value(self.name)
.writable(false) .writable(false)
@ -368,8 +366,8 @@ impl BuiltInConstructorWithPrototype<'_> {
let length = self.length; let length = self.length;
let name = self.name.clone(); let name = self.name.clone();
let prototype = self.prototype.clone(); let prototype = self.prototype.clone();
self = self.static_property(js_str!("length"), length, Attribute::CONFIGURABLE); self = self.static_property(js_string!("length"), length, Attribute::CONFIGURABLE);
self = self.static_property(js_str!("name"), name, Attribute::CONFIGURABLE); self = self.static_property(js_string!("name"), name, Attribute::CONFIGURABLE);
self = self.static_property(PROTOTYPE, prototype, Attribute::empty()); self = self.static_property(PROTOTYPE, prototype, Attribute::empty());
let attributes = self.attributes; let attributes = self.attributes;
@ -416,8 +414,8 @@ impl BuiltInConstructorWithPrototype<'_> {
pub(crate) fn build_without_prototype(mut self) { pub(crate) fn build_without_prototype(mut self) {
let length = self.length; let length = self.length;
let name = self.name.clone(); let name = self.name.clone();
self = self.static_property(js_str!("length"), length, Attribute::CONFIGURABLE); self = self.static_property(js_string!("length"), length, Attribute::CONFIGURABLE);
self = self.static_property(js_str!("name"), name, Attribute::CONFIGURABLE); self = self.static_property(js_string!("name"), name, Attribute::CONFIGURABLE);
let mut object = self.object.borrow_mut(); let mut object = self.object.borrow_mut();
let function = object let function = object

9
core/engine/src/builtins/error/aggregate.rs

@ -20,7 +20,6 @@ use crate::{
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{Error, ErrorObject}; use super::{Error, ErrorObject};
@ -36,8 +35,8 @@ impl IntrinsicObject for AggregateError {
BuiltInBuilder::from_standard_constructor::<Self>(realm) BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor()) .prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype())) .inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(js_str!("name"), Self::NAME, attribute) .property(js_string!("name"), Self::NAME, attribute)
.property(js_str!("message"), js_string!(), attribute) .property(js_string!("message"), js_string!(), attribute)
.build(); .build();
} }
@ -102,7 +101,7 @@ impl BuiltInConstructor for AggregateError {
let msg = message.to_string(context)?; let msg = message.to_string(context)?;
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context);
} }
// 4. Perform ? InstallErrorCause(O, options). // 4. Perform ? InstallErrorCause(O, options).
@ -122,7 +121,7 @@ impl BuiltInConstructor for AggregateError {
// [[Value]]: CreateArrayFromList(errorsList) // [[Value]]: CreateArrayFromList(errorsList)
// }). // }).
o.define_property_or_throw( o.define_property_or_throw(
js_str!("errors"), js_string!("errors"),
PropertyDescriptorBuilder::new() PropertyDescriptorBuilder::new()
.configurable(true) .configurable(true)
.enumerable(false) .enumerable(false)

7
core/engine/src/builtins/error/eval.rs

@ -21,7 +21,6 @@ use crate::{
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{Error, ErrorObject}; use super::{Error, ErrorObject};
@ -38,8 +37,8 @@ impl IntrinsicObject for EvalError {
BuiltInBuilder::from_standard_constructor::<Self>(realm) BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor()) .prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype())) .inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(js_str!("name"), Self::NAME, attribute) .property(js_string!("name"), Self::NAME, attribute)
.property(js_str!("message"), js_string!(), attribute) .property(js_string!("message"), js_string!(), attribute)
.build(); .build();
} }
@ -97,7 +96,7 @@ impl BuiltInConstructor for EvalError {
let msg = message.to_string(context)?; let msg = message.to_string(context)?;
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context);
} }
// 4. Perform ? InstallErrorCause(O, options). // 4. Perform ? InstallErrorCause(O, options).

8
core/engine/src/builtins/error/mod.rs

@ -214,9 +214,9 @@ impl Error {
// 1. If Type(options) is Object and ? HasProperty(options, "cause") is true, then // 1. If Type(options) is Object and ? HasProperty(options, "cause") is true, then
// 1.a. Let cause be ? Get(options, "cause"). // 1.a. Let cause be ? Get(options, "cause").
if let Some(options) = options.as_object() { if let Some(options) = options.as_object() {
if let Some(cause) = options.try_get(js_str!("cause"), context)? { if let Some(cause) = options.try_get(js_string!("cause"), context)? {
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause).
o.create_non_enumerable_data_property_or_throw(js_str!("cause"), cause, context); o.create_non_enumerable_data_property_or_throw(js_string!("cause"), cause, context);
} }
} }
@ -247,7 +247,7 @@ impl Error {
.ok_or_else(|| JsNativeError::typ().with_message("'this' is not an Object"))?; .ok_or_else(|| JsNativeError::typ().with_message("'this' is not an Object"))?;
// 3. Let name be ? Get(O, "name"). // 3. Let name be ? Get(O, "name").
let name = o.get(js_str!("name"), context)?; let name = o.get(js_string!("name"), context)?;
// 4. If name is undefined, set name to "Error"; otherwise set name to ? ToString(name). // 4. If name is undefined, set name to "Error"; otherwise set name to ? ToString(name).
let name = if name.is_undefined() { let name = if name.is_undefined() {
@ -257,7 +257,7 @@ impl Error {
}; };
// 5. Let msg be ? Get(O, "message"). // 5. Let msg be ? Get(O, "message").
let msg = o.get(js_str!("message"), context)?; let msg = o.get(js_string!("message"), context)?;
// 6. If msg is undefined, set msg to the empty String; otherwise set msg to ? ToString(msg). // 6. If msg is undefined, set msg to the empty String; otherwise set msg to ? ToString(msg).
let msg = if msg.is_undefined() { let msg = if msg.is_undefined() {

7
core/engine/src/builtins/error/range.rs

@ -19,7 +19,6 @@ use crate::{
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{Error, ErrorObject}; use super::{Error, ErrorObject};
@ -36,8 +35,8 @@ impl IntrinsicObject for RangeError {
BuiltInBuilder::from_standard_constructor::<Self>(realm) BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor()) .prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype())) .inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(js_str!("name"), Self::NAME, attribute) .property(js_string!("name"), Self::NAME, attribute)
.property(js_str!("message"), js_string!(), attribute) .property(js_string!("message"), js_string!(), attribute)
.build(); .build();
} }
@ -95,7 +94,7 @@ impl BuiltInConstructor for RangeError {
let msg = message.to_string(context)?; let msg = message.to_string(context)?;
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context);
} }
// 4. Perform ? InstallErrorCause(O, options). // 4. Perform ? InstallErrorCause(O, options).

7
core/engine/src/builtins/error/reference.rs

@ -19,7 +19,6 @@ use crate::{
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{Error, ErrorObject}; use super::{Error, ErrorObject};
@ -35,8 +34,8 @@ impl IntrinsicObject for ReferenceError {
BuiltInBuilder::from_standard_constructor::<Self>(realm) BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor()) .prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype())) .inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(js_str!("name"), Self::NAME, attribute) .property(js_string!("name"), Self::NAME, attribute)
.property(js_str!("message"), js_string!(), attribute) .property(js_string!("message"), js_string!(), attribute)
.build(); .build();
} }
@ -97,7 +96,7 @@ impl BuiltInConstructor for ReferenceError {
let msg = message.to_string(context)?; let msg = message.to_string(context)?;
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context);
} }
// 4. Perform ? InstallErrorCause(O, options). // 4. Perform ? InstallErrorCause(O, options).

7
core/engine/src/builtins/error/syntax.rs

@ -21,7 +21,6 @@ use crate::{
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{Error, ErrorObject}; use super::{Error, ErrorObject};
@ -38,8 +37,8 @@ impl IntrinsicObject for SyntaxError {
BuiltInBuilder::from_standard_constructor::<Self>(realm) BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor()) .prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype())) .inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(js_str!("name"), Self::NAME, attribute) .property(js_string!("name"), Self::NAME, attribute)
.property(js_str!("message"), js_string!(), attribute) .property(js_string!("message"), js_string!(), attribute)
.build(); .build();
} }
@ -100,7 +99,7 @@ impl BuiltInConstructor for SyntaxError {
let msg = message.to_string(context)?; let msg = message.to_string(context)?;
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context);
} }
// 4. Perform ? InstallErrorCause(O, options). // 4. Perform ? InstallErrorCause(O, options).

9
core/engine/src/builtins/error/type.rs

@ -27,7 +27,6 @@ use crate::{
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsResult, JsString, JsValue, NativeFunction, Context, JsArgs, JsResult, JsString, JsValue, NativeFunction,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{Error, ErrorObject}; use super::{Error, ErrorObject};
@ -44,8 +43,8 @@ impl IntrinsicObject for TypeError {
BuiltInBuilder::from_standard_constructor::<Self>(realm) BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor()) .prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype())) .inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(js_str!("name"), Self::NAME, attribute) .property(js_string!("name"), Self::NAME, attribute)
.property(js_str!("message"), js_string!(), attribute) .property(js_string!("message"), js_string!(), attribute)
.build(); .build();
} }
@ -103,7 +102,7 @@ impl BuiltInConstructor for TypeError {
let msg = message.to_string(context)?; let msg = message.to_string(context)?;
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context);
} }
// 4. Perform ? InstallErrorCause(O, options). // 4. Perform ? InstallErrorCause(O, options).
@ -122,7 +121,7 @@ impl IntrinsicObject for ThrowTypeError {
let obj = BuiltInBuilder::with_intrinsic::<Self>(realm) let obj = BuiltInBuilder::with_intrinsic::<Self>(realm)
.prototype(realm.intrinsics().constructors().function().prototype()) .prototype(realm.intrinsics().constructors().function().prototype())
.static_property(StaticJsStrings::LENGTH, 0, Attribute::empty()) .static_property(StaticJsStrings::LENGTH, 0, Attribute::empty())
.static_property(js_str!("name"), js_string!(), Attribute::empty()) .static_property(js_string!("name"), js_string!(), Attribute::empty())
.build(); .build();
let mut obj = obj.borrow_mut(); let mut obj = obj.borrow_mut();

7
core/engine/src/builtins/error/uri.rs

@ -20,7 +20,6 @@ use crate::{
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::{Error, ErrorObject}; use super::{Error, ErrorObject};
@ -37,8 +36,8 @@ impl IntrinsicObject for UriError {
BuiltInBuilder::from_standard_constructor::<Self>(realm) BuiltInBuilder::from_standard_constructor::<Self>(realm)
.prototype(realm.intrinsics().constructors().error().constructor()) .prototype(realm.intrinsics().constructors().error().constructor())
.inherits(Some(realm.intrinsics().constructors().error().prototype())) .inherits(Some(realm.intrinsics().constructors().error().prototype()))
.property(js_str!("name"), Self::NAME, attribute) .property(js_string!("name"), Self::NAME, attribute)
.property(js_str!("message"), js_string!(), attribute) .property(js_string!("message"), js_string!(), attribute)
.build(); .build();
} }
@ -96,7 +95,7 @@ impl BuiltInConstructor for UriError {
let msg = message.to_string(context)?; let msg = message.to_string(context)?;
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context);
} }
// 4. Perform ? InstallErrorCause(O, options). // 4. Perform ? InstallErrorCause(O, options).

6
core/engine/src/builtins/function/mod.rs

@ -776,7 +776,7 @@ impl BuiltInFunctionObject {
.expect("defining the `length` property for a new object should not fail"); .expect("defining the `length` property for a new object should not fail");
// 8. Let targetName be ? Get(Target, "name"). // 8. Let targetName be ? Get(Target, "name").
let target_name = target.get(js_str!("name"), context)?; let target_name = target.get(js_string!("name"), context)?;
// 9. If Type(targetName) is not String, set targetName to the empty String. // 9. If Type(targetName) is not String, set targetName to the empty String.
let target_name = target_name let target_name = target_name
@ -849,7 +849,7 @@ impl BuiltInFunctionObject {
let name = { let name = {
// Is there a case here where if there is no name field on a value // Is there a case here where if there is no name field on a value
// name should default to None? Do all functions have names set? // name should default to None? Do all functions have names set?
let value = object.get(js_str!("name"), &mut *context)?; let value = object.get(js_string!("name"), &mut *context)?;
if value.is_null_or_undefined() { if value.is_null_or_undefined() {
js_string!() js_string!()
} else { } else {
@ -943,7 +943,7 @@ pub(crate) fn set_function_name(
// [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }). // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }).
function function
.define_property_or_throw( .define_property_or_throw(
js_str!("name"), js_string!("name"),
PropertyDescriptor::builder() PropertyDescriptor::builder()
.value(name) .value(name)
.writable(false) .writable(false)

48
core/engine/src/builtins/intl/collator/mod.rs

@ -1,5 +1,4 @@
use boa_gc::{custom_trace, Finalize, Trace}; use boa_gc::{custom_trace, Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use icu_collator::{ use icu_collator::{
provider::CollationMetadataV1Marker, AlternateHandling, CaseFirst, MaxVariable, Numeric, provider::CollationMetadataV1Marker, AlternateHandling, CaseFirst, MaxVariable, Numeric,
@ -243,28 +242,29 @@ impl BuiltInConstructor for Collator {
// a. Let localeData be %Collator%.[[SortLocaleData]]. // a. Let localeData be %Collator%.[[SortLocaleData]].
// 6. Else, // 6. Else,
// a. Let localeData be %Collator%.[[SearchLocaleData]]. // a. Let localeData be %Collator%.[[SearchLocaleData]].
let usage = get_option(&options, js_str!("usage"), context)?.unwrap_or_default(); let usage = get_option(&options, js_string!("usage"), context)?.unwrap_or_default();
// 7. Let opt be a new Record. // 7. Let opt be a new Record.
// 8. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 8. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
// 9. Set opt.[[localeMatcher]] to matcher. // 9. Set opt.[[localeMatcher]] to matcher.
let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); let matcher =
get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default();
// 10. Let collation be ? GetOption(options, "collation", string, empty, undefined). // 10. Let collation be ? GetOption(options, "collation", string, empty, undefined).
// 11. If collation is not undefined, then // 11. If collation is not undefined, then
// a. If collation does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. // a. If collation does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
// 12. Set opt.[[co]] to collation. // 12. Set opt.[[co]] to collation.
let collation = get_option(&options, js_str!("collation"), context)?; let collation = get_option(&options, js_string!("collation"), context)?;
// 13. Let numeric be ? GetOption(options, "numeric", boolean, empty, undefined). // 13. Let numeric be ? GetOption(options, "numeric", boolean, empty, undefined).
// 14. If numeric is not undefined, then // 14. If numeric is not undefined, then
// a. Let numeric be ! ToString(numeric). // a. Let numeric be ! ToString(numeric).
// 15. Set opt.[[kn]] to numeric. // 15. Set opt.[[kn]] to numeric.
let numeric = get_option(&options, js_str!("numeric"), context)?; let numeric = get_option(&options, js_string!("numeric"), context)?;
// 16. Let caseFirst be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined). // 16. Let caseFirst be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined).
// 17. Set opt.[[kf]] to caseFirst. // 17. Set opt.[[kf]] to caseFirst.
let case_first = get_option(&options, js_str!("caseFirst"), context)?; let case_first = get_option(&options, js_string!("caseFirst"), context)?;
let mut intl_options = IntlOptions { let mut intl_options = IntlOptions {
matcher, matcher,
@ -316,7 +316,7 @@ impl BuiltInConstructor for Collator {
// 26. Let sensitivity be ? GetOption(options, "sensitivity", string, « "base", "accent", "case", "variant" », undefined). // 26. Let sensitivity be ? GetOption(options, "sensitivity", string, « "base", "accent", "case", "variant" », undefined).
// 28. Set collator.[[Sensitivity]] to sensitivity. // 28. Set collator.[[Sensitivity]] to sensitivity.
let sensitivity = get_option(&options, js_str!("sensitivity"), context)? let sensitivity = get_option(&options, js_string!("sensitivity"), context)?
// 27. If sensitivity is undefined, then // 27. If sensitivity is undefined, then
// a. If usage is "sort", then // a. If usage is "sort", then
// i. Let sensitivity be "variant". // i. Let sensitivity be "variant".
@ -329,7 +329,7 @@ impl BuiltInConstructor for Collator {
// 29. Let ignorePunctuation be ? GetOption(options, "ignorePunctuation", boolean, empty, false). // 29. Let ignorePunctuation be ? GetOption(options, "ignorePunctuation", boolean, empty, false).
// 30. Set collator.[[IgnorePunctuation]] to ignorePunctuation. // 30. Set collator.[[IgnorePunctuation]] to ignorePunctuation.
let ignore_punctuation: bool = let ignore_punctuation: bool =
get_option(&options, js_str!("ignorePunctuation"), context)?.unwrap_or_default(); get_option(&options, js_string!("ignorePunctuation"), context)?.unwrap_or_default();
let (strength, case_level) = sensitivity.map(Sensitivity::to_collator_options).unzip(); let (strength, case_level) = sensitivity.map(Sensitivity::to_collator_options).unzip();
@ -523,58 +523,58 @@ impl Collator {
// 5. Return options. // 5. Return options.
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("locale"), js_string!("locale"),
js_string!(collator.locale.to_string()), js_string!(collator.locale.to_string()),
context, context,
) )
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("usage"), js_string!("usage"),
match collator.usage { match collator.usage {
Usage::Search => js_str!("search"), Usage::Search => js_string!("search"),
Usage::Sort => js_str!("sort"), Usage::Sort => js_string!("sort"),
}, },
context, context,
) )
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("sensitivity"), js_string!("sensitivity"),
match collator.sensitivity { match collator.sensitivity {
Sensitivity::Base => js_str!("base"), Sensitivity::Base => js_string!("base"),
Sensitivity::Accent => js_str!("accent"), Sensitivity::Accent => js_string!("accent"),
Sensitivity::Case => js_str!("case"), Sensitivity::Case => js_string!("case"),
Sensitivity::Variant => js_str!("variant"), Sensitivity::Variant => js_string!("variant"),
}, },
context, context,
) )
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("ignorePunctuation"), js_string!("ignorePunctuation"),
collator.ignore_punctuation, collator.ignore_punctuation,
context, context,
) )
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("collation"), js_string!("collation"),
js_string!(collator.collation.to_string()), js_string!(collator.collation.to_string()),
context, context,
) )
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
options options
.create_data_property_or_throw(js_str!("numeric"), collator.numeric, context) .create_data_property_or_throw(js_string!("numeric"), collator.numeric, context)
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
if let Some(kf) = collator.case_first { if let Some(kf) = collator.case_first {
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("caseFirst"), js_string!("caseFirst"),
match kf { match kf {
CaseFirst::Off => js_str!("false"), CaseFirst::Off => js_string!("false"),
CaseFirst::LowerFirst => js_str!("lower"), CaseFirst::LowerFirst => js_string!("lower"),
CaseFirst::UpperFirst => js_str!("upper"), CaseFirst::UpperFirst => js_string!("upper"),
_ => unreachable!(), _ => unreachable!(),
}, },
context, context,

39
core/engine/src/builtins/intl/date_time_format.rs

@ -22,7 +22,6 @@ use crate::{
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use icu_datetime::options::preferences::HourCycle; use icu_datetime::options::preferences::HourCycle;
@ -142,8 +141,8 @@ impl BuiltInConstructor for DateTimeFormat {
hour: js_string!("numeric"), hour: js_string!("numeric"),
minute: js_string!("numeric"), minute: js_string!("numeric"),
second: js_string!("numeric"), second: js_string!("numeric"),
fractional_second_digits: js_string!(""), fractional_second_digits: js_string!(),
time_zone_name: js_string!(""), time_zone_name: js_string!(),
hour_cycle: js_string!("h24"), hour_cycle: js_string!("h24"),
pattern: js_string!("{hour}:{minute}"), pattern: js_string!("{hour}:{minute}"),
bound_format: js_string!("undefined"), bound_format: js_string!("undefined"),
@ -208,10 +207,10 @@ pub(crate) fn to_date_time_options(
if [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(required) { if [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(required) {
// a. For each property name prop of « "weekday", "year", "month", "day" », do // a. For each property name prop of « "weekday", "year", "month", "day" », do
for property in [ for property in [
js_str!("weekday"), js_string!("weekday"),
js_str!("year"), js_string!("year"),
js_str!("month"), js_string!("month"),
js_str!("day"), js_string!("day"),
] { ] {
// i. Let value be ? Get(options, prop). // i. Let value be ? Get(options, prop).
let value = options.get(property, context)?; let value = options.get(property, context)?;
@ -228,11 +227,11 @@ pub(crate) fn to_date_time_options(
// a. For each property name prop of « "dayPeriod", "hour", "minute", "second", // a. For each property name prop of « "dayPeriod", "hour", "minute", "second",
// "fractionalSecondDigits" », do // "fractionalSecondDigits" », do
for property in [ for property in [
js_str!("dayPeriod"), js_string!("dayPeriod"),
js_str!("hour"), js_string!("hour"),
js_str!("minute"), js_string!("minute"),
js_str!("second"), js_string!("second"),
js_str!("fractionalSecondDigits"), js_string!("fractionalSecondDigits"),
] { ] {
// i. Let value be ? Get(options, prop). // i. Let value be ? Get(options, prop).
let value = options.get(property, context)?; let value = options.get(property, context)?;
@ -245,10 +244,10 @@ pub(crate) fn to_date_time_options(
} }
// 6. Let dateStyle be ? Get(options, "dateStyle"). // 6. Let dateStyle be ? Get(options, "dateStyle").
let date_style = options.get(js_str!("dateStyle"), context)?; let date_style = options.get(js_string!("dateStyle"), context)?;
// 7. Let timeStyle be ? Get(options, "timeStyle"). // 7. Let timeStyle be ? Get(options, "timeStyle").
let time_style = options.get(js_str!("timeStyle"), context)?; let time_style = options.get(js_string!("timeStyle"), context)?;
// 8. If dateStyle is not undefined or timeStyle is not undefined, let needDefaults be false. // 8. If dateStyle is not undefined or timeStyle is not undefined, let needDefaults be false.
if !date_style.is_undefined() || !time_style.is_undefined() { if !date_style.is_undefined() || !time_style.is_undefined() {
@ -274,18 +273,22 @@ pub(crate) fn to_date_time_options(
// 11. If needDefaults is true and defaults is either "date" or "all", then // 11. If needDefaults is true and defaults is either "date" or "all", then
if need_defaults && [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(defaults) { if need_defaults && [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(defaults) {
// a. For each property name prop of « "year", "month", "day" », do // a. For each property name prop of « "year", "month", "day" », do
for property in [js_str!("year"), js_str!("month"), js_str!("day")] { for property in [js_string!("year"), js_string!("month"), js_string!("day")] {
// i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
options.create_data_property_or_throw(property, js_str!("numeric"), context)?; options.create_data_property_or_throw(property, js_string!("numeric"), context)?;
} }
} }
// 12. If needDefaults is true and defaults is either "time" or "all", then // 12. If needDefaults is true and defaults is either "time" or "all", then
if need_defaults && [DateTimeReqs::Time, DateTimeReqs::AnyAll].contains(defaults) { if need_defaults && [DateTimeReqs::Time, DateTimeReqs::AnyAll].contains(defaults) {
// a. For each property name prop of « "hour", "minute", "second" », do // a. For each property name prop of « "hour", "minute", "second" », do
for property in [js_str!("hour"), js_str!("minute"), js_str!("second")] { for property in [
js_string!("hour"),
js_string!("minute"),
js_string!("second"),
] {
// i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
options.create_data_property_or_throw(property, js_str!("numeric"), context)?; options.create_data_property_or_throw(property, js_string!("numeric"), context)?;
} }
} }

30
core/engine/src/builtins/intl/list_format/mod.rs

@ -1,7 +1,6 @@
use std::fmt::Write; use std::fmt::Write;
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use icu_list::{provider::AndListV1Marker, ListFormatter, ListLength}; use icu_list::{provider::AndListV1Marker, ListFormatter, ListLength};
use icu_locid::Locale; use icu_locid::Locale;
@ -121,7 +120,8 @@ impl BuiltInConstructor for ListFormat {
// 5. Let opt be a new Record. // 5. Let opt be a new Record.
// 6. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 6. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); let matcher =
get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default();
// 7. Set opt.[[localeMatcher]] to matcher. // 7. Set opt.[[localeMatcher]] to matcher.
// 8. Let localeData be %ListFormat%.[[LocaleData]]. // 8. Let localeData be %ListFormat%.[[LocaleData]].
@ -138,11 +138,11 @@ impl BuiltInConstructor for ListFormat {
// 11. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction"). // 11. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction").
// 12. Set listFormat.[[Type]] to type. // 12. Set listFormat.[[Type]] to type.
let typ = get_option(&options, js_str!("type"), context)?.unwrap_or_default(); let typ = get_option(&options, js_string!("type"), context)?.unwrap_or_default();
// 13. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long"). // 13. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long").
// 14. Set listFormat.[[Style]] to style. // 14. Set listFormat.[[Style]] to style.
let style = get_option(&options, js_str!("style"), context)?.unwrap_or(ListLength::Wide); let style = get_option(&options, js_string!("style"), context)?.unwrap_or(ListLength::Wide);
// 15. Let dataLocale be r.[[dataLocale]]. // 15. Let dataLocale be r.[[dataLocale]].
// 16. Let dataLocaleData be localeData.[[<dataLocale>]]. // 16. Let dataLocaleData be localeData.[[<dataLocale>]].
@ -390,11 +390,11 @@ impl ListFormat {
.create(OrdinaryObject, vec![]); .create(OrdinaryObject, vec![]);
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]). // b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
o.create_data_property_or_throw(js_str!("type"), js_string!(part.typ()), context) o.create_data_property_or_throw(js_string!("type"), js_string!(part.typ()), context)
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]). // c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
o.create_data_property_or_throw(js_str!("value"), js_string!(part.value()), context) o.create_data_property_or_throw(js_string!("value"), js_string!(part.value()), context)
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
// d. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O). // d. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O).
@ -445,29 +445,29 @@ impl ListFormat {
// d. Perform ! CreateDataPropertyOrThrow(options, p, v). // d. Perform ! CreateDataPropertyOrThrow(options, p, v).
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("locale"), js_string!("locale"),
js_string!(lf.locale.to_string()), js_string!(lf.locale.to_string()),
context, context,
) )
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("type"), js_string!("type"),
match lf.typ { match lf.typ {
ListFormatType::Conjunction => js_str!("conjunction"), ListFormatType::Conjunction => js_string!("conjunction"),
ListFormatType::Disjunction => js_str!("disjunction"), ListFormatType::Disjunction => js_string!("disjunction"),
ListFormatType::Unit => js_str!("unit"), ListFormatType::Unit => js_string!("unit"),
}, },
context, context,
) )
.expect("operation must not fail per the spec"); .expect("operation must not fail per the spec");
options options
.create_data_property_or_throw( .create_data_property_or_throw(
js_str!("style"), js_string!("style"),
match lf.style { match lf.style {
ListLength::Wide => js_str!("long"), ListLength::Wide => js_string!("long"),
ListLength::Short => js_str!("short"), ListLength::Short => js_string!("short"),
ListLength::Narrow => js_str!("narrow"), ListLength::Narrow => js_string!("narrow"),
_ => unreachable!(), _ => unreachable!(),
}, },
context, context,

19
core/engine/src/builtins/intl/locale/mod.rs

@ -1,5 +1,4 @@
use crate::{builtins::options::get_option, realm::Realm, string::StaticJsStrings}; use crate::{builtins::options::get_option, realm::Realm, string::StaticJsStrings};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use icu_collator::CaseFirst; use icu_collator::CaseFirst;
use icu_datetime::options::preferences::HourCycle; use icu_datetime::options::preferences::HourCycle;
@ -235,17 +234,17 @@ impl BuiltInConstructor for Locale {
// 4. Let language be ? GetOption(options, "language", string, empty, undefined). // 4. Let language be ? GetOption(options, "language", string, empty, undefined).
// 5. If language is not undefined, then // 5. If language is not undefined, then
// a. If language does not match the unicode_language_subtag production, throw a RangeError exception. // a. If language does not match the unicode_language_subtag production, throw a RangeError exception.
let language = get_option(options, js_str!("language"), context)?; let language = get_option(options, js_string!("language"), context)?;
// 6. Let script be ? GetOption(options, "script", string, empty, undefined). // 6. Let script be ? GetOption(options, "script", string, empty, undefined).
// 7. If script is not undefined, then // 7. If script is not undefined, then
// a. If script does not match the unicode_script_subtag production, throw a RangeError exception. // a. If script does not match the unicode_script_subtag production, throw a RangeError exception.
let script = get_option(options, js_str!("script"), context)?; let script = get_option(options, js_string!("script"), context)?;
// 8. Let region be ? GetOption(options, "region", string, empty, undefined). // 8. Let region be ? GetOption(options, "region", string, empty, undefined).
// 9. If region is not undefined, then // 9. If region is not undefined, then
// a. If region does not match the unicode_region_subtag production, throw a RangeError exception. // a. If region does not match the unicode_region_subtag production, throw a RangeError exception.
let region = get_option(options, js_str!("region"), context)?; let region = get_option(options, js_string!("region"), context)?;
// 10. Set tag to ! CanonicalizeUnicodeLocaleId(tag). // 10. Set tag to ! CanonicalizeUnicodeLocaleId(tag).
context context
@ -293,17 +292,17 @@ impl BuiltInConstructor for Locale {
// 14. If calendar is not undefined, then // 14. If calendar is not undefined, then
// 15. Set opt.[[ca]] to calendar. // 15. Set opt.[[ca]] to calendar.
// a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. // a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
let ca = get_option(options, js_str!("calendar"), context)?; let ca = get_option(options, js_string!("calendar"), context)?;
// 16. Let collation be ? GetOption(options, "collation", string, empty, undefined). // 16. Let collation be ? GetOption(options, "collation", string, empty, undefined).
// 17. If collation is not undefined, then // 17. If collation is not undefined, then
// 18. Set opt.[[co]] to collation. // 18. Set opt.[[co]] to collation.
// a. If collation does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. // a. If collation does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
let co = get_option(options, js_str!("collation"), context)?; let co = get_option(options, js_string!("collation"), context)?;
// 19. Let hc be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined). // 19. Let hc be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined).
// 20. Set opt.[[hc]] to hc. // 20. Set opt.[[hc]] to hc.
let hc = get_option(options, js_str!("hourCycle"), context)?.map(|hc| match hc { let hc = get_option(options, js_string!("hourCycle"), context)?.map(|hc| match hc {
HourCycle::H24 => value!("h24"), HourCycle::H24 => value!("h24"),
HourCycle::H23 => value!("h23"), HourCycle::H23 => value!("h23"),
HourCycle::H12 => value!("h12"), HourCycle::H12 => value!("h12"),
@ -312,7 +311,7 @@ impl BuiltInConstructor for Locale {
// 21. Let kf be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined). // 21. Let kf be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined).
// 22. Set opt.[[kf]] to kf. // 22. Set opt.[[kf]] to kf.
let kf = get_option(options, js_str!("caseFirst"), context)?.map(|kf| match kf { let kf = get_option(options, js_string!("caseFirst"), context)?.map(|kf| match kf {
CaseFirst::UpperFirst => value!("upper"), CaseFirst::UpperFirst => value!("upper"),
CaseFirst::LowerFirst => value!("lower"), CaseFirst::LowerFirst => value!("lower"),
CaseFirst::Off => value!("false"), CaseFirst::Off => value!("false"),
@ -322,7 +321,7 @@ impl BuiltInConstructor for Locale {
// 23. Let kn be ? GetOption(options, "numeric", boolean, empty, undefined). // 23. Let kn be ? GetOption(options, "numeric", boolean, empty, undefined).
// 24. If kn is not undefined, set kn to ! ToString(kn). // 24. If kn is not undefined, set kn to ! ToString(kn).
// 25. Set opt.[[kn]] to kn. // 25. Set opt.[[kn]] to kn.
let kn = get_option(options, js_str!("numeric"), context)?.map(|b| { let kn = get_option(options, js_string!("numeric"), context)?.map(|b| {
if b { if b {
value!("true") value!("true")
} else { } else {
@ -334,7 +333,7 @@ impl BuiltInConstructor for Locale {
// 27. If numberingSystem is not undefined, then // 27. If numberingSystem is not undefined, then
// 28. Set opt.[[nu]] to numberingSystem. // 28. Set opt.[[nu]] to numberingSystem.
// a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
let nu = get_option(options, js_str!("numberingSystem"), context)?; let nu = get_option(options, js_string!("numberingSystem"), context)?;
// 29. Let r be ! ApplyUnicodeExtensionToTag(tag, opt, relevantExtensionKeys). // 29. Let r be ! ApplyUnicodeExtensionToTag(tag, opt, relevantExtensionKeys).
// 30. Set locale.[[Locale]] to r.[[locale]]. // 30. Set locale.[[Locale]] to r.[[locale]].

3
core/engine/src/builtins/intl/locale/utils.rs

@ -13,7 +13,6 @@ use crate::{
Context, JsNativeError, JsResult, JsValue, Context, JsNativeError, JsResult, JsValue,
}; };
use boa_macros::js_str;
use icu_locid::{ use icu_locid::{
extensions::unicode::{Key, Value}, extensions::unicode::{Key, Value},
subtags::Variants, subtags::Variants,
@ -420,7 +419,7 @@ where
let options = coerce_options_to_object(options, context)?; let options = coerce_options_to_object(options, context)?;
// 2. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 2. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); let matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default();
// 3. Let subset be a new empty List. // 3. Let subset be a new empty List.
let mut subset = Vec::with_capacity(requested_locales.len()); let mut subset = Vec::with_capacity(requested_locales.len());

14
core/engine/src/builtins/intl/number_format/mod.rs

@ -1,7 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use fixed_decimal::{FixedDecimal, FloatPrecision, SignDisplay}; use fixed_decimal::{FixedDecimal, FloatPrecision, SignDisplay};
use icu_decimal::{ use icu_decimal::{
@ -227,13 +226,14 @@ impl BuiltInConstructor for NumberFormat {
// 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
// 5. Set opt.[[localeMatcher]] to matcher. // 5. Set opt.[[localeMatcher]] to matcher.
let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); let matcher =
get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default();
// 6. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined). // 6. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined).
// 7. If numberingSystem is not undefined, then // 7. If numberingSystem is not undefined, then
// a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception. // a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
// 8. Set opt.[[nu]] to numberingSystem. // 8. Set opt.[[nu]] to numberingSystem.
let numbering_system = get_option(&options, js_str!("numberingSystem"), context)?; let numbering_system = get_option(&options, js_string!("numberingSystem"), context)?;
let mut intl_options = IntlOptions { let mut intl_options = IntlOptions {
matcher, matcher,
@ -283,7 +283,7 @@ impl BuiltInConstructor for NumberFormat {
// 18. Let notation be ? GetOption(options, "notation", string, « "standard", "scientific", "engineering", "compact" », "standard"). // 18. Let notation be ? GetOption(options, "notation", string, « "standard", "scientific", "engineering", "compact" », "standard").
// 19. Set numberFormat.[[Notation]] to notation. // 19. Set numberFormat.[[Notation]] to notation.
let notation = get_option(&options, js_str!("notation"), context)?.unwrap_or_default(); let notation = get_option(&options, js_string!("notation"), context)?.unwrap_or_default();
// 20. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation). // 20. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
let digit_options = DigitFormatOptions::from_options( let digit_options = DigitFormatOptions::from_options(
@ -296,7 +296,7 @@ impl BuiltInConstructor for NumberFormat {
// 21. Let compactDisplay be ? GetOption(options, "compactDisplay", string, « "short", "long" », "short"). // 21. Let compactDisplay be ? GetOption(options, "compactDisplay", string, « "short", "long" », "short").
let compact_display = let compact_display =
get_option(&options, js_str!("compactDisplay"), context)?.unwrap_or_default(); get_option(&options, js_string!("compactDisplay"), context)?.unwrap_or_default();
// 22. Let defaultUseGrouping be "auto". // 22. Let defaultUseGrouping be "auto".
let mut default_use_grouping = GroupingStrategy::Auto; let mut default_use_grouping = GroupingStrategy::Auto;
@ -331,7 +331,7 @@ impl BuiltInConstructor for NumberFormat {
// <https://tc39.es/ecma402/#sec-getbooleanorstringnumberformatoption> // <https://tc39.es/ecma402/#sec-getbooleanorstringnumberformatoption>
// 1. Let value be ? Get(options, property). // 1. Let value be ? Get(options, property).
let value = options.get(js_str!("useGrouping"), context)?; let value = options.get(js_string!("useGrouping"), context)?;
// 2. If value is undefined, return fallback. // 2. If value is undefined, return fallback.
if value.is_undefined() { if value.is_undefined() {
@ -369,7 +369,7 @@ impl BuiltInConstructor for NumberFormat {
// 29. Let signDisplay be ? GetOption(options, "signDisplay", string, « "auto", "never", "always", "exceptZero", "negative" », "auto"). // 29. Let signDisplay be ? GetOption(options, "signDisplay", string, « "auto", "never", "always", "exceptZero", "negative" », "auto").
// 30. Set numberFormat.[[SignDisplay]] to signDisplay. // 30. Set numberFormat.[[SignDisplay]] to signDisplay.
let sign_display = let sign_display =
get_option(&options, js_str!("signDisplay"), context)?.unwrap_or(SignDisplay::Auto); get_option(&options, js_string!("signDisplay"), context)?.unwrap_or(SignDisplay::Auto);
let mut options = FixedDecimalFormatterOptions::default(); let mut options = FixedDecimalFormatterOptions::default();
options.grouping_strategy = use_grouping; options.grouping_strategy = use_grouping;

30
core/engine/src/builtins/intl/number_format/options.rs

@ -392,12 +392,12 @@ impl UnitFormatOptions {
pub(crate) fn from_options(options: &JsObject, context: &mut Context) -> JsResult<Self> { pub(crate) fn from_options(options: &JsObject, context: &mut Context) -> JsResult<Self> {
// 1. Let style be ? GetOption(options, "style", string, « "decimal", "percent", "currency", "unit" », "decimal"). // 1. Let style be ? GetOption(options, "style", string, « "decimal", "percent", "currency", "unit" », "decimal").
// 2. Set intlObj.[[Style]] to style. // 2. Set intlObj.[[Style]] to style.
let style: Style = get_option(options, js_str!("style"), context)?.unwrap_or_default(); let style: Style = get_option(options, js_string!("style"), context)?.unwrap_or_default();
// 3. Let currency be ? GetOption(options, "currency", string, empty, undefined). // 3. Let currency be ? GetOption(options, "currency", string, empty, undefined).
// 5. Else, // 5. Else,
// a. If IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception. // a. If IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception.
let currency = get_option(options, js_str!("currency"), context)?; let currency = get_option(options, js_string!("currency"), context)?;
// 4. If currency is undefined, then // 4. If currency is undefined, then
if currency.is_none() { if currency.is_none() {
@ -413,16 +413,16 @@ impl UnitFormatOptions {
// 6. Let currencyDisplay be ? GetOption(options, "currencyDisplay", string, « "code", "symbol", "narrowSymbol", "name" », "symbol"). // 6. Let currencyDisplay be ? GetOption(options, "currencyDisplay", string, « "code", "symbol", "narrowSymbol", "name" », "symbol").
let currency_display = let currency_display =
get_option(options, js_str!("currencyDisplay"), context)?.unwrap_or_default(); get_option(options, js_string!("currencyDisplay"), context)?.unwrap_or_default();
// 7. Let currencySign be ? GetOption(options, "currencySign", string, « "standard", "accounting" », "standard"). // 7. Let currencySign be ? GetOption(options, "currencySign", string, « "standard", "accounting" », "standard").
let currency_sign = let currency_sign =
get_option(options, js_str!("currencySign"), context)?.unwrap_or_default(); get_option(options, js_string!("currencySign"), context)?.unwrap_or_default();
// 8. Let unit be ? GetOption(options, "unit", string, empty, undefined). // 8. Let unit be ? GetOption(options, "unit", string, empty, undefined).
// 10. Else, // 10. Else,
// a. If IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception. // a. If IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception.
let unit = get_option(options, js_str!("unit"), context)?; let unit = get_option(options, js_string!("unit"), context)?;
// 9. If unit is undefined, then // 9. If unit is undefined, then
if unit.is_none() { if unit.is_none() {
// a. If style is "unit", throw a TypeError exception. // a. If style is "unit", throw a TypeError exception.
@ -437,7 +437,7 @@ impl UnitFormatOptions {
// 11. Let unitDisplay be ? GetOption(options, "unitDisplay", string, « "short", "narrow", "long" », "short"). // 11. Let unitDisplay be ? GetOption(options, "unitDisplay", string, « "short", "narrow", "long" », "short").
let unit_display = let unit_display =
get_option(options, js_str!("unitDisplay"), context)?.unwrap_or_default(); get_option(options, js_string!("unitDisplay"), context)?.unwrap_or_default();
// 14. Return unused. // 14. Return unused.
Ok(match style { Ok(match style {
@ -492,25 +492,25 @@ impl DigitFormatOptions {
) -> JsResult<Self> { ) -> JsResult<Self> {
// 1. Let mnid be ? GetNumberOption(options, "minimumIntegerDigits,", 1, 21, 1). // 1. Let mnid be ? GetNumberOption(options, "minimumIntegerDigits,", 1, 21, 1).
let minimum_integer_digits = let minimum_integer_digits =
get_number_option(options, js_str!("minimumIntegerDigits"), 1, 21, context)? get_number_option(options, js_string!("minimumIntegerDigits"), 1, 21, context)?
.unwrap_or(1); .unwrap_or(1);
// 2. Let mnfd be ? Get(options, "minimumFractionDigits"). // 2. Let mnfd be ? Get(options, "minimumFractionDigits").
let min_float_digits = options.get(js_str!("minimumFractionDigits"), context)?; let min_float_digits = options.get(js_string!("minimumFractionDigits"), context)?;
// 3. Let mxfd be ? Get(options, "maximumFractionDigits"). // 3. Let mxfd be ? Get(options, "maximumFractionDigits").
let max_float_digits = options.get(js_str!("maximumFractionDigits"), context)?; let max_float_digits = options.get(js_string!("maximumFractionDigits"), context)?;
// 4. Let mnsd be ? Get(options, "minimumSignificantDigits"). // 4. Let mnsd be ? Get(options, "minimumSignificantDigits").
let min_sig_digits = options.get(js_str!("minimumSignificantDigits"), context)?; let min_sig_digits = options.get(js_string!("minimumSignificantDigits"), context)?;
// 5. Let mxsd be ? Get(options, "maximumSignificantDigits"). // 5. Let mxsd be ? Get(options, "maximumSignificantDigits").
let max_sig_digits = options.get(js_str!("maximumSignificantDigits"), context)?; let max_sig_digits = options.get(js_string!("maximumSignificantDigits"), context)?;
// 7. Let roundingPriority be ? GetOption(options, "roundingPriority", string, « "auto", "morePrecision", "lessPrecision" », "auto"). // 7. Let roundingPriority be ? GetOption(options, "roundingPriority", string, « "auto", "morePrecision", "lessPrecision" », "auto").
let mut rounding_priority = let mut rounding_priority =
get_option(options, js_str!("roundingPriority"), context)?.unwrap_or_default(); get_option(options, js_string!("roundingPriority"), context)?.unwrap_or_default();
// 8. Let roundingIncrement be ? GetNumberOption(options, "roundingIncrement", 1, 5000, 1). // 8. Let roundingIncrement be ? GetNumberOption(options, "roundingIncrement", 1, 5000, 1).
// 9. If roundingIncrement is not in « 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000 », throw a RangeError exception. // 9. If roundingIncrement is not in « 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000 », throw a RangeError exception.
let rounding_increment = let rounding_increment =
get_number_option(options, js_str!("roundingIncrement"), 1, 5000, context)? get_number_option(options, js_string!("roundingIncrement"), 1, 5000, context)?
.unwrap_or(1); .unwrap_or(1);
let rounding_increment = let rounding_increment =
@ -520,11 +520,11 @@ impl DigitFormatOptions {
// 10. Let roundingMode be ? GetOption(options, "roundingMode", string, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfExpand"). // 10. Let roundingMode be ? GetOption(options, "roundingMode", string, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfExpand").
let rounding_mode = let rounding_mode =
get_option(options, js_str!("roundingMode"), context)?.unwrap_or_default(); get_option(options, js_string!("roundingMode"), context)?.unwrap_or_default();
// 11. Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", string, « "auto", "stripIfInteger" », "auto"). // 11. Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", string, « "auto", "stripIfInteger" », "auto").
let trailing_zero_display = let trailing_zero_display =
get_option(options, js_str!("trailingZeroDisplay"), context)?.unwrap_or_default(); get_option(options, js_string!("trailingZeroDisplay"), context)?.unwrap_or_default();
// 12. NOTE: All fields required by SetNumberFormatDigitOptions have now been read from options. The remainder of this AO interprets the options and may throw exceptions. // 12. NOTE: All fields required by SetNumberFormatDigitOptions have now been read from options. The remainder of this AO interprets the options and may throw exceptions.

4
core/engine/src/builtins/intl/options.rs

@ -5,7 +5,7 @@ use num_traits::FromPrimitive;
use crate::{ use crate::{
builtins::{options::ParsableOptionType, OrdinaryObject}, builtins::{options::ParsableOptionType, OrdinaryObject},
object::JsObject, object::JsObject,
Context, JsNativeError, JsResult, JsStr, JsValue, Context, JsNativeError, JsResult, JsString, JsValue,
}; };
/// `IntlOptions` aggregates the `locale_matcher` selector and any other object /// `IntlOptions` aggregates the `locale_matcher` selector and any other object
@ -60,7 +60,7 @@ impl ParsableOptionType for LocaleMatcher {}
/// [spec]: https://tc39.es/ecma402/#sec-getnumberoption /// [spec]: https://tc39.es/ecma402/#sec-getnumberoption
pub(super) fn get_number_option<T>( pub(super) fn get_number_option<T>(
options: &JsObject, options: &JsObject,
property: JsStr<'_>, property: JsString,
minimum: T, minimum: T,
maximum: T, maximum: T,
context: &mut Context, context: &mut Context,

60
core/engine/src/builtins/intl/plural_rules/mod.rs

@ -1,7 +1,6 @@
mod options; mod options;
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use fixed_decimal::FixedDecimal; use fixed_decimal::FixedDecimal;
use icu_locid::Locale; use icu_locid::Locale;
@ -25,7 +24,7 @@ use crate::{
property::Attribute, property::Attribute,
realm::Realm, realm::Realm,
string::StaticJsStrings, string::StaticJsStrings,
Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsStr, JsString, JsSymbol, JsValue, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
}; };
use super::{ use super::{
@ -126,12 +125,13 @@ impl BuiltInConstructor for PluralRules {
// 3. Let opt be a new Record. // 3. Let opt be a new Record.
// 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
// 5. Set opt.[[localeMatcher]] to matcher. // 5. Set opt.[[localeMatcher]] to matcher.
let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); let matcher =
get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default();
// 6. Let t be ? GetOption(options, "type", string, « "cardinal", "ordinal" », "cardinal"). // 6. Let t be ? GetOption(options, "type", string, « "cardinal", "ordinal" », "cardinal").
// 7. Set pluralRules.[[Type]] to t. // 7. Set pluralRules.[[Type]] to t.
let rule_type = let rule_type =
get_option(&options, js_str!("type"), context)?.unwrap_or(PluralRuleType::Cardinal); get_option(&options, js_string!("type"), context)?.unwrap_or(PluralRuleType::Cardinal);
// 8. Perform ? SetNumberFormatDigitOptions(pluralRules, options, +0𝔽, 3𝔽, "standard"). // 8. Perform ? SetNumberFormatDigitOptions(pluralRules, options, +0𝔽, 3𝔽, "standard").
let format_options = let format_options =
@ -330,21 +330,21 @@ impl PluralRules {
let mut options = ObjectInitializer::new(context); let mut options = ObjectInitializer::new(context);
options options
.property( .property(
js_str!("locale"), js_string!("locale"),
js_string!(plural_rules.locale.to_string()), js_string!(plural_rules.locale.to_string()),
Attribute::all(), Attribute::all(),
) )
.property( .property(
js_str!("type"), js_string!("type"),
match plural_rules.rule_type { match plural_rules.rule_type {
PluralRuleType::Cardinal => js_str!("cardinal"), PluralRuleType::Cardinal => js_string!("cardinal"),
PluralRuleType::Ordinal => js_str!("ordinal"), PluralRuleType::Ordinal => js_string!("ordinal"),
_ => js_str!("unknown"), _ => js_string!("unknown"),
}, },
Attribute::all(), Attribute::all(),
) )
.property( .property(
js_str!("minimumIntegerDigits"), js_string!("minimumIntegerDigits"),
plural_rules.format_options.minimum_integer_digits, plural_rules.format_options.minimum_integer_digits,
Attribute::all(), Attribute::all(),
); );
@ -353,8 +353,16 @@ impl PluralRules {
plural_rules.format_options.rounding_type.fraction_digits() plural_rules.format_options.rounding_type.fraction_digits()
{ {
options options
.property(js_str!("minimumFractionDigits"), minimum, Attribute::all()) .property(
.property(js_str!("maximumFractionDigits"), maximum, Attribute::all()); js_string!("minimumFractionDigits"),
minimum,
Attribute::all(),
)
.property(
js_string!("maximumFractionDigits"),
maximum,
Attribute::all(),
);
} }
if let Some(Extrema { minimum, maximum }) = plural_rules if let Some(Extrema { minimum, maximum }) = plural_rules
@ -364,12 +372,12 @@ impl PluralRules {
{ {
options options
.property( .property(
js_str!("minimumSignificantDigits"), js_string!("minimumSignificantDigits"),
minimum, minimum,
Attribute::all(), Attribute::all(),
) )
.property( .property(
js_str!("maximumSignificantDigits"), js_string!("maximumSignificantDigits"),
maximum, maximum,
Attribute::all(), Attribute::all(),
); );
@ -377,17 +385,17 @@ impl PluralRules {
options options
.property( .property(
js_str!("roundingMode"), js_string!("roundingMode"),
js_string!(plural_rules.format_options.rounding_mode.to_js_string()), js_string!(plural_rules.format_options.rounding_mode.to_js_string()),
Attribute::all(), Attribute::all(),
) )
.property( .property(
js_str!("roundingIncrement"), js_string!("roundingIncrement"),
plural_rules.format_options.rounding_increment.to_u16(), plural_rules.format_options.rounding_increment.to_u16(),
Attribute::all(), Attribute::all(),
) )
.property( .property(
js_str!("trailingZeroDisplay"), js_string!("trailingZeroDisplay"),
plural_rules plural_rules
.format_options .format_options
.trailing_zero_display .trailing_zero_display
@ -408,7 +416,7 @@ impl PluralRules {
// 6. Perform ! CreateDataProperty(options, "pluralCategories", CreateArrayFromList(pluralCategories)). // 6. Perform ! CreateDataProperty(options, "pluralCategories", CreateArrayFromList(pluralCategories)).
options.property( options.property(
js_str!("pluralCategories"), js_string!("pluralCategories"),
plural_categories, plural_categories,
Attribute::all(), Attribute::all(),
); );
@ -420,7 +428,7 @@ impl PluralRules {
// 9. Else, // 9. Else,
// a. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "auto"). // a. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "auto").
options.property( options.property(
js_str!("roundingPriority"), js_string!("roundingPriority"),
js_string!(plural_rules.format_options.rounding_priority.to_js_string()), js_string!(plural_rules.format_options.rounding_priority.to_js_string()),
Attribute::all(), Attribute::all(),
); );
@ -472,13 +480,13 @@ fn resolve_plural(plural_rules: &PluralRules, n: f64) -> ResolvedPlural {
} }
} }
fn plural_category_to_js_string(category: PluralCategory) -> JsStr<'static> { fn plural_category_to_js_string(category: PluralCategory) -> JsString {
match category { match category {
PluralCategory::Zero => js_str!("zero"), PluralCategory::Zero => js_string!("zero"),
PluralCategory::One => js_str!("one"), PluralCategory::One => js_string!("one"),
PluralCategory::Two => js_str!("two"), PluralCategory::Two => js_string!("two"),
PluralCategory::Few => js_str!("few"), PluralCategory::Few => js_string!("few"),
PluralCategory::Many => js_str!("many"), PluralCategory::Many => js_string!("many"),
PluralCategory::Other => js_str!("other"), PluralCategory::Other => js_string!("other"),
} }
} }

18
core/engine/src/builtins/intl/segmenter/mod.rs

@ -1,7 +1,6 @@
use std::ops::Range; use std::ops::Range;
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use icu_collator::provider::CollationDiacriticsV1Marker; use icu_collator::provider::CollationDiacriticsV1Marker;
use icu_locid::Locale; use icu_locid::Locale;
@ -147,7 +146,8 @@ impl BuiltInConstructor for Segmenter {
// 6. Let opt be a new Record. // 6. Let opt be a new Record.
// 7. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 7. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); let matcher =
get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default();
// 8. Set opt.[[localeMatcher]] to matcher. // 8. Set opt.[[localeMatcher]] to matcher.
// 9. Let localeData be %Segmenter%.[[LocaleData]]. // 9. Let localeData be %Segmenter%.[[LocaleData]].
@ -164,7 +164,7 @@ impl BuiltInConstructor for Segmenter {
// 12. Let granularity be ? GetOption(options, "granularity", string, « "grapheme", "word", "sentence" », "grapheme"). // 12. Let granularity be ? GetOption(options, "granularity", string, « "grapheme", "word", "sentence" », "grapheme").
let granularity = let granularity =
get_option(&options, js_str!("granularity"), context)?.unwrap_or_default(); get_option(&options, js_string!("granularity"), context)?.unwrap_or_default();
// 13. Set segmenter.[[SegmenterGranularity]] to granularity. // 13. Set segmenter.[[SegmenterGranularity]] to granularity.
let native = match (granularity, context.intl_provider().erased_provider()) { let native = match (granularity, context.intl_provider().erased_provider()) {
@ -269,12 +269,12 @@ impl Segmenter {
// d. Perform ! CreateDataPropertyOrThrow(options, p, v). // d. Perform ! CreateDataPropertyOrThrow(options, p, v).
let options = ObjectInitializer::new(context) let options = ObjectInitializer::new(context)
.property( .property(
js_str!("locale"), js_string!("locale"),
js_string!(segmenter.locale.to_string()), js_string!(segmenter.locale.to_string()),
Attribute::all(), Attribute::all(),
) )
.property( .property(
js_str!("granularity"), js_string!("granularity"),
js_string!(segmenter.native.granularity().to_string()), js_string!(segmenter.native.granularity().to_string()),
Attribute::all(), Attribute::all(),
) )
@ -336,18 +336,18 @@ fn create_segment_data_object(
object object
// 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment). // 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment).
.property(js_str!("segment"), segment, Attribute::all()) .property(js_string!("segment"), segment, Attribute::all())
// 8. Perform ! CreateDataPropertyOrThrow(result, "index", 𝔽(startIndex)). // 8. Perform ! CreateDataPropertyOrThrow(result, "index", 𝔽(startIndex)).
.property(js_str!("index"), start, Attribute::all()) .property(js_string!("index"), start, Attribute::all())
// 9. Perform ! CreateDataPropertyOrThrow(result, "input", string). // 9. Perform ! CreateDataPropertyOrThrow(result, "input", string).
.property(js_str!("input"), string, Attribute::all()); .property(js_string!("input"), string, Attribute::all());
// 10. Let granularity be segmenter.[[SegmenterGranularity]]. // 10. Let granularity be segmenter.[[SegmenterGranularity]].
// 11. If granularity is "word", then // 11. If granularity is "word", then
if let Some(is_word_like) = is_word_like { if let Some(is_word_like) = is_word_like {
// a. Let isWordLike be a Boolean value indicating whether the segment in string is "word-like" according to locale segmenter.[[Locale]]. // a. Let isWordLike be a Boolean value indicating whether the segment in string is "word-like" according to locale segmenter.[[Locale]].
// b. Perform ! CreateDataPropertyOrThrow(result, "isWordLike", isWordLike). // b. Perform ! CreateDataPropertyOrThrow(result, "isWordLike", isWordLike).
object.property(js_str!("isWordLike"), is_word_like, Attribute::all()); object.property(js_string!("isWordLike"), is_word_like, Attribute::all());
} }
// 12. Return result. // 12. Return result.

11
core/engine/src/builtins/iterable/async_from_sync_iterator.rs

@ -12,7 +12,6 @@ use crate::{
Context, JsArgs, JsData, JsError, JsNativeError, JsResult, JsValue, Context, JsArgs, JsData, JsError, JsNativeError, JsResult, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
/// `%AsyncFromSyncIteratorPrototype%` object. /// `%AsyncFromSyncIteratorPrototype%` object.
@ -80,7 +79,7 @@ impl AsyncFromSyncIterator {
// 3. Let nextMethod be ! Get(asyncIterator, "next"). // 3. Let nextMethod be ! Get(asyncIterator, "next").
let next_method = async_iterator let next_method = async_iterator
.get(js_str!("next"), context) .get(js_string!("next"), context)
.expect("async from sync iterator prototype must have next method"); .expect("async from sync iterator prototype must have next method");
// 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: asyncIterator, [[NextMethod]]: nextMethod, [[Done]]: false }. // 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: asyncIterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
@ -158,7 +157,7 @@ impl AsyncFromSyncIterator {
.expect("cannot fail with promise constructor"); .expect("cannot fail with promise constructor");
// 6. Let return be Completion(GetMethod(syncIterator, "return")). // 6. Let return be Completion(GetMethod(syncIterator, "return")).
let r#return = sync_iterator.get_method(js_str!("return"), context); let r#return = sync_iterator.get_method(js_string!("return"), context);
// 7. IfAbruptRejectPromise(return, promiseCapability). // 7. IfAbruptRejectPromise(return, promiseCapability).
let r#return = if_abrupt_reject_promise!(r#return, promise_capability, context); let r#return = if_abrupt_reject_promise!(r#return, promise_capability, context);
@ -235,7 +234,7 @@ impl AsyncFromSyncIterator {
.expect("cannot fail with promise constructor"); .expect("cannot fail with promise constructor");
// 6. Let throw be Completion(GetMethod(syncIterator, "throw")). // 6. Let throw be Completion(GetMethod(syncIterator, "throw")).
let throw = sync_iterator.get_method(js_str!("throw"), context); let throw = sync_iterator.get_method(js_string!("throw"), context);
// 7. IfAbruptRejectPromise(throw, promiseCapability). // 7. IfAbruptRejectPromise(throw, promiseCapability).
let throw = if_abrupt_reject_promise!(throw, promise_capability, context); let throw = if_abrupt_reject_promise!(throw, promise_capability, context);
@ -360,7 +359,7 @@ impl AsyncFromSyncIterator {
)) ))
}), }),
) )
.name(js_str!("")) .name(js_string!())
.length(1) .length(1)
.build(); .build();
@ -393,7 +392,7 @@ impl AsyncFromSyncIterator {
sync_iterator_record, sync_iterator_record,
), ),
) )
.name(js_str!("")) .name(js_string!())
.length(1) .length(1)
.build(), .build(),
) )

10
core/engine/src/builtins/iterable/mod.rs

@ -4,13 +4,13 @@ use crate::{
builtins::{BuiltInBuilder, IntrinsicObject}, builtins::{BuiltInBuilder, IntrinsicObject},
context::intrinsics::Intrinsics, context::intrinsics::Intrinsics,
error::JsNativeError, error::JsNativeError,
js_string,
object::JsObject, object::JsObject,
realm::Realm, realm::Realm,
symbol::JsSymbol, symbol::JsSymbol,
Context, JsResult, JsValue, Context, JsResult, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
mod async_from_sync_iterator; mod async_from_sync_iterator;
@ -243,7 +243,7 @@ impl JsValue {
JsNativeError::typ().with_message("returned iterator is not an object") JsNativeError::typ().with_message("returned iterator is not an object")
})?; })?;
// 3. Let nextMethod be ? Get(iterator, "next"). // 3. Let nextMethod be ? Get(iterator, "next").
let next_method = iterator_obj.get(js_str!("next"), context)?; let next_method = iterator_obj.get(js_string!("next"), context)?;
// 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }. // 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
// 5. Return iteratorRecord. // 5. Return iteratorRecord.
Ok(IteratorRecord::new(iterator_obj.clone(), next_method)) Ok(IteratorRecord::new(iterator_obj.clone(), next_method))
@ -341,7 +341,7 @@ impl IteratorResult {
#[inline] #[inline]
pub fn complete(&self, context: &mut Context) -> JsResult<bool> { pub fn complete(&self, context: &mut Context) -> JsResult<bool> {
// 1. Return ToBoolean(? Get(iterResult, "done")). // 1. Return ToBoolean(? Get(iterResult, "done")).
Ok(self.object.get(js_str!("done"), context)?.to_boolean()) Ok(self.object.get(js_string!("done"), context)?.to_boolean())
} }
/// `IteratorValue ( iterResult )` /// `IteratorValue ( iterResult )`
@ -357,7 +357,7 @@ impl IteratorResult {
#[inline] #[inline]
pub fn value(&self, context: &mut Context) -> JsResult<JsValue> { pub fn value(&self, context: &mut Context) -> JsResult<JsValue> {
// 1. Return ? Get(iterResult, "value"). // 1. Return ? Get(iterResult, "value").
self.object.get(js_str!("value"), context) self.object.get(js_string!("value"), context)
} }
} }
@ -588,7 +588,7 @@ impl IteratorRecord {
let iterator = &self.iterator; let iterator = &self.iterator;
// 3. Let innerResult be Completion(GetMethod(iterator, "return")). // 3. Let innerResult be Completion(GetMethod(iterator, "return")).
let inner_result = iterator.get_method(js_str!("return"), context); let inner_result = iterator.get_method(js_string!("return"), context);
// 4. If innerResult.[[Type]] is normal, then // 4. If innerResult.[[Type]] is normal, then
let inner_result = match inner_result { let inner_result = match inner_result {

8
core/engine/src/builtins/json/mod.rs

@ -16,7 +16,7 @@
use std::{borrow::Cow, iter::once}; use std::{borrow::Cow, iter::once};
use boa_ast::scope::Scope; use boa_ast::scope::Scope;
use boa_macros::{js_str, utf16}; use boa_macros::utf16;
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
@ -154,7 +154,7 @@ impl Json {
// b. Let rootName be the empty String. // b. Let rootName be the empty String.
// c. Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered). // c. Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered).
root.create_data_property_or_throw(js_str!(""), unfiltered, context) root.create_data_property_or_throw(js_string!(), unfiltered, context)
.expect("CreateDataPropertyOrThrow should never throw here"); .expect("CreateDataPropertyOrThrow should never throw here");
// d. Return ? InternalizeJSONProperty(root, rootName, reviver). // d. Return ? InternalizeJSONProperty(root, rootName, reviver).
@ -386,7 +386,7 @@ impl Json {
// 10. Perform ! CreateDataPropertyOrThrow(wrapper, the empty String, value). // 10. Perform ! CreateDataPropertyOrThrow(wrapper, the empty String, value).
wrapper wrapper
.create_data_property_or_throw(js_str!(""), args.get_or_undefined(0).clone(), context) .create_data_property_or_throw(js_string!(), args.get_or_undefined(0).clone(), context)
.expect("CreateDataPropertyOrThrow should never fail here"); .expect("CreateDataPropertyOrThrow should never fail here");
// 11. Let state be the Record { [[ReplacerFunction]]: ReplacerFunction, [[Stack]]: stack, [[Indent]]: indent, [[Gap]]: gap, [[PropertyList]]: PropertyList }. // 11. Let state be the Record { [[ReplacerFunction]]: ReplacerFunction, [[Stack]]: stack, [[Indent]]: indent, [[Gap]]: gap, [[PropertyList]]: PropertyList }.
@ -424,7 +424,7 @@ impl Json {
// 2. If Type(value) is Object or BigInt, then // 2. If Type(value) is Object or BigInt, then
if value.is_object() || value.is_bigint() { if value.is_object() || value.is_bigint() {
// a. Let toJSON be ? GetV(value, "toJSON"). // a. Let toJSON be ? GetV(value, "toJSON").
let to_json = value.get_v(js_str!("toJSON"), context)?; let to_json = value.get_v(js_string!("toJSON"), context)?;
// b. If IsCallable(toJSON) is true, then // b. If IsCallable(toJSON) is true, then
if let Some(obj) = to_json.as_object() { if let Some(obj) = to_json.as_object() {

3
core/engine/src/builtins/map/mod.rs

@ -22,7 +22,6 @@ use crate::{
symbol::JsSymbol, symbol::JsSymbol,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use num_traits::Zero; use num_traits::Zero;
@ -155,7 +154,7 @@ impl BuiltInConstructor for Map {
// 5. Let adder be ? Get(map, "set"). // 5. Let adder be ? Get(map, "set").
// 6. If IsCallable(adder) is false, throw a TypeError exception. // 6. If IsCallable(adder) is false, throw a TypeError exception.
let adder = map let adder = map
.get(js_str!("set"), context)? .get(js_string!("set"), context)?
.as_function() .as_function()
.ok_or_else(|| { .ok_or_else(|| {
JsNativeError::typ() JsNativeError::typ()

10
core/engine/src/builtins/mod.rs

@ -36,7 +36,6 @@ pub mod weak_set;
mod builder; mod builder;
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use builder::BuiltInBuilder; use builder::BuiltInBuilder;
@ -107,6 +106,7 @@ use crate::{
weak_set::WeakSet, weak_set::WeakSet,
}, },
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
js_string,
object::JsObject, object::JsObject,
property::{Attribute, PropertyDescriptor}, property::{Attribute, PropertyDescriptor},
realm::Realm, realm::Realm,
@ -314,7 +314,7 @@ pub(crate) fn set_default_global_bindings(context: &mut Context) -> JsResult<()>
let global_object = context.global_object(); let global_object = context.global_object();
global_object.define_property_or_throw( global_object.define_property_or_throw(
js_str!("globalThis"), js_string!("globalThis"),
PropertyDescriptor::builder() PropertyDescriptor::builder()
.value(context.realm().global_this().clone()) .value(context.realm().global_this().clone())
.writable(true) .writable(true)
@ -327,17 +327,17 @@ pub(crate) fn set_default_global_bindings(context: &mut Context) -> JsResult<()>
.enumerable(false) .enumerable(false)
.configurable(false); .configurable(false);
global_object.define_property_or_throw( global_object.define_property_or_throw(
js_str!("Infinity"), js_string!("Infinity"),
restricted.clone().value(f64::INFINITY), restricted.clone().value(f64::INFINITY),
context, context,
)?; )?;
global_object.define_property_or_throw( global_object.define_property_or_throw(
js_str!("NaN"), js_string!("NaN"),
restricted.clone().value(f64::NAN), restricted.clone().value(f64::NAN),
context, context,
)?; )?;
global_object.define_property_or_throw( global_object.define_property_or_throw(
js_str!("undefined"), js_string!("undefined"),
restricted.value(JsValue::undefined()), restricted.value(JsValue::undefined()),
context, context,
)?; )?;

11
core/engine/src/builtins/number/mod.rs

@ -25,7 +25,6 @@ use crate::{
value::{AbstractRelation, IntegerOrInfinity, JsValue}, value::{AbstractRelation, IntegerOrInfinity, JsValue},
Context, JsArgs, JsResult, JsString, Context, JsArgs, JsResult, JsString,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use num_traits::float::FloatCore; use num_traits::float::FloatCore;
@ -648,7 +647,7 @@ impl Number {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
pub(crate) fn to_js_string(x: f64) -> JsString { pub(crate) fn to_js_string(x: f64) -> JsString {
let mut buffer = ryu_js::Buffer::new(); let mut buffer = ryu_js::Buffer::new();
js_string!(buffer.format(x).to_string()) js_string!(buffer.format(x))
} }
/// `Number.prototype.toString( [radix] )` /// `Number.prototype.toString( [radix] )`
@ -693,13 +692,13 @@ impl Number {
} }
if x == -0. { if x == -0. {
return Ok(JsValue::new(js_str!("0"))); return Ok(JsValue::new(js_string!("0")));
} else if x.is_nan() { } else if x.is_nan() {
return Ok(JsValue::new(js_str!("NaN"))); return Ok(JsValue::new(js_string!("NaN")));
} else if x.is_infinite() && x.is_sign_positive() { } else if x.is_infinite() && x.is_sign_positive() {
return Ok(JsValue::new(js_str!("Infinity"))); return Ok(JsValue::new(js_string!("Infinity")));
} else if x.is_infinite() && x.is_sign_negative() { } else if x.is_infinite() && x.is_sign_negative() {
return Ok(JsValue::new(js_str!("-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 // This is a Optimization from the v8 source code to print values that can fit in a single character

18
core/engine/src/builtins/object/mod.rs

@ -575,42 +575,42 @@ impl OrdinaryObject {
// 4. If Desc has a [[Value]] field, then // 4. If Desc has a [[Value]] field, then
if let Some(value) = desc.value() { if let Some(value) = desc.value() {
// a. Perform ! CreateDataPropertyOrThrow(obj, "value", Desc.[[Value]]). // a. Perform ! CreateDataPropertyOrThrow(obj, "value", Desc.[[Value]]).
obj.create_data_property_or_throw(js_str!("value"), value.clone(), context) obj.create_data_property_or_throw(js_string!("value"), value.clone(), context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
} }
// 5. If Desc has a [[Writable]] field, then // 5. If Desc has a [[Writable]] field, then
if let Some(writable) = desc.writable() { if let Some(writable) = desc.writable() {
// a. Perform ! CreateDataPropertyOrThrow(obj, "writable", Desc.[[Writable]]). // a. Perform ! CreateDataPropertyOrThrow(obj, "writable", Desc.[[Writable]]).
obj.create_data_property_or_throw(js_str!("writable"), writable, context) obj.create_data_property_or_throw(js_string!("writable"), writable, context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
} }
// 6. If Desc has a [[Get]] field, then // 6. If Desc has a [[Get]] field, then
if let Some(get) = desc.get() { if let Some(get) = desc.get() {
// a. Perform ! CreateDataPropertyOrThrow(obj, "get", Desc.[[Get]]). // a. Perform ! CreateDataPropertyOrThrow(obj, "get", Desc.[[Get]]).
obj.create_data_property_or_throw(js_str!("get"), get.clone(), context) obj.create_data_property_or_throw(js_string!("get"), get.clone(), context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
} }
// 7. If Desc has a [[Set]] field, then // 7. If Desc has a [[Set]] field, then
if let Some(set) = desc.set() { if let Some(set) = desc.set() {
// a. Perform ! CreateDataPropertyOrThrow(obj, "set", Desc.[[Set]]). // a. Perform ! CreateDataPropertyOrThrow(obj, "set", Desc.[[Set]]).
obj.create_data_property_or_throw(js_str!("set"), set.clone(), context) obj.create_data_property_or_throw(js_string!("set"), set.clone(), context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
} }
// 8. If Desc has an [[Enumerable]] field, then // 8. If Desc has an [[Enumerable]] field, then
if let Some(enumerable) = desc.enumerable() { if let Some(enumerable) = desc.enumerable() {
// a. Perform ! CreateDataPropertyOrThrow(obj, "enumerable", Desc.[[Enumerable]]). // a. Perform ! CreateDataPropertyOrThrow(obj, "enumerable", Desc.[[Enumerable]]).
obj.create_data_property_or_throw(js_str!("enumerable"), enumerable, context) obj.create_data_property_or_throw(js_string!("enumerable"), enumerable, context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
} }
// 9. If Desc has a [[Configurable]] field, then // 9. If Desc has a [[Configurable]] field, then
if let Some(configurable) = desc.configurable() { if let Some(configurable) = desc.configurable() {
// a. Perform ! CreateDataPropertyOrThrow(obj, "configurable", Desc.[[Configurable]]). // a. Perform ! CreateDataPropertyOrThrow(obj, "configurable", Desc.[[Configurable]]).
obj.create_data_property_or_throw(js_str!("configurable"), configurable, context) obj.create_data_property_or_throw(js_string!("configurable"), configurable, context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
} }
@ -826,11 +826,11 @@ impl OrdinaryObject {
pub fn to_string(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> { pub fn to_string(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
// 1. If the this value is undefined, return "[object Undefined]". // 1. If the this value is undefined, return "[object Undefined]".
if this.is_undefined() { if this.is_undefined() {
return Ok(js_str!("[object Undefined]").into()); return Ok(js_string!("[object Undefined]").into());
} }
// 2. If the this value is null, return "[object Null]". // 2. If the this value is null, return "[object Null]".
if this.is_null() { if this.is_null() {
return Ok(js_str!("[object Null]").into()); return Ok(js_string!("[object Null]").into());
} }
// 3. Let O be ! ToObject(this value). // 3. Let O be ! ToObject(this value).
let o = this.to_object(context).expect("toObject cannot fail here"); let o = this.to_object(context).expect("toObject cannot fail here");
@ -898,7 +898,7 @@ impl OrdinaryObject {
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
// 1. Let O be the this value. // 1. Let O be the this value.
// 2. Return ? Invoke(O, "toString"). // 2. Return ? Invoke(O, "toString").
this.invoke(js_str!("toString"), &[], context) this.invoke(js_string!("toString"), &[], context)
} }
/// `Object.prototype.hasOwnProperty( property )` /// `Object.prototype.hasOwnProperty( property )`

4
core/engine/src/builtins/options.rs

@ -2,7 +2,7 @@
use std::{fmt, str::FromStr}; use std::{fmt, str::FromStr};
use crate::{object::JsObject, string::JsStr, Context, JsNativeError, JsResult, JsString, JsValue}; use crate::{object::JsObject, Context, JsNativeError, JsResult, JsString, JsValue};
/// A type used as an option parameter for [`get_option`]. /// A type used as an option parameter for [`get_option`].
pub(crate) trait OptionType: Sized { pub(crate) trait OptionType: Sized {
@ -50,7 +50,7 @@ where
/// [spec]: https://tc39.es/ecma402/#sec-getoption /// [spec]: https://tc39.es/ecma402/#sec-getoption
pub(crate) fn get_option<T: OptionType>( pub(crate) fn get_option<T: OptionType>(
options: &JsObject, options: &JsObject,
property: JsStr<'_>, property: JsString,
context: &mut Context, context: &mut Context,
) -> JsResult<Option<T>> { ) -> JsResult<Option<T>> {
// 1. Let value be ? Get(options, property). // 1. Let value be ? Get(options, property).

36
core/engine/src/builtins/promise/mod.rs

@ -26,7 +26,7 @@ use crate::{
Context, JsArgs, JsError, JsResult, JsString, Context, JsArgs, JsError, JsResult, JsString,
}; };
use boa_gc::{custom_trace, Finalize, Gc, GcRefCell, Trace}; use boa_gc::{custom_trace, Finalize, Gc, GcRefCell, Trace};
use boa_macros::{js_str, JsData}; use boa_macros::JsData;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use std::{cell::Cell, rc::Rc}; use std::{cell::Cell, rc::Rc};
use tap::{Conv, Pipe}; use tap::{Conv, Pipe};
@ -739,7 +739,7 @@ impl Promise {
// n. Perform ? Invoke(nextPromise, "then", « onFulfilled, resultCapability.[[Reject]] »). // n. Perform ? Invoke(nextPromise, "then", « onFulfilled, resultCapability.[[Reject]] »).
next_promise.invoke( next_promise.invoke(
js_str!("then"), js_string!("then"),
&[ &[
on_fulfilled.into(), on_fulfilled.into(),
result_capability.functions.reject.clone().into(), result_capability.functions.reject.clone().into(),
@ -915,15 +915,15 @@ impl Promise {
// 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "fulfilled"). // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "fulfilled").
obj.create_data_property_or_throw( obj.create_data_property_or_throw(
js_str!("status"), js_string!("status"),
js_str!("fulfilled"), js_string!("fulfilled"),
context, context,
) )
.expect("cannot fail per spec"); .expect("cannot fail per spec");
// 11. Perform ! CreateDataPropertyOrThrow(obj, "value", x). // 11. Perform ! CreateDataPropertyOrThrow(obj, "value", x).
obj.create_data_property_or_throw( obj.create_data_property_or_throw(
js_str!("value"), js_string!("value"),
args.get_or_undefined(0).clone(), args.get_or_undefined(0).clone(),
context, context,
) )
@ -1005,15 +1005,15 @@ impl Promise {
// 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "rejected"). // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "rejected").
obj.create_data_property_or_throw( obj.create_data_property_or_throw(
js_str!("status"), js_string!("status"),
js_str!("rejected"), js_string!("rejected"),
context, context,
) )
.expect("cannot fail per spec"); .expect("cannot fail per spec");
// 11. Perform ! CreateDataPropertyOrThrow(obj, "reason", x). // 11. Perform ! CreateDataPropertyOrThrow(obj, "reason", x).
obj.create_data_property_or_throw( obj.create_data_property_or_throw(
js_str!("reason"), js_string!("reason"),
args.get_or_undefined(0).clone(), args.get_or_undefined(0).clone(),
context, context,
) )
@ -1065,7 +1065,7 @@ impl Promise {
// w. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »). // w. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »).
next_promise.invoke( next_promise.invoke(
js_str!("then"), js_string!("then"),
&[on_fulfilled.into(), on_rejected.into()], &[on_fulfilled.into(), on_rejected.into()],
context, context,
)?; )?;
@ -1286,7 +1286,7 @@ impl Promise {
// n. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], onRejected »). // n. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], onRejected »).
next_promise.invoke( next_promise.invoke(
js_str!("then"), js_string!("then"),
&[ &[
result_capability.functions.resolve.clone().into(), result_capability.functions.resolve.clone().into(),
on_rejected.into(), on_rejected.into(),
@ -1417,7 +1417,7 @@ impl Promise {
let next_promise = promise_resolve.call(&constructor, &[next], context)?; let next_promise = promise_resolve.call(&constructor, &[next], context)?;
// d. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »). // d. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
next_promise.invoke( next_promise.invoke(
js_str!("then"), js_string!("then"),
&[ &[
result_capability.functions.resolve.clone().into(), result_capability.functions.resolve.clone().into(),
result_capability.functions.reject.clone().into(), result_capability.functions.reject.clone().into(),
@ -1576,7 +1576,7 @@ impl Promise {
let promise = this; let promise = this;
// 2. Return ? Invoke(promise, "then", « undefined, onRejected »). // 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
promise.invoke( promise.invoke(
js_str!("then"), js_string!("then"),
&[JsValue::undefined(), on_rejected.clone()], &[JsValue::undefined(), on_rejected.clone()],
context, context,
) )
@ -1622,7 +1622,7 @@ impl Promise {
// a. Let thenFinally be onFinally. // a. Let thenFinally be onFinally.
// b. Let catchFinally be onFinally. // b. Let catchFinally be onFinally.
// 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
let then = promise.get(js_str!("then"), context)?; let then = promise.get(js_string!("then"), context)?;
return then.call(this, &[on_finally.clone(), on_finally.clone()], context); return then.call(this, &[on_finally.clone(), on_finally.clone()], context);
}; };
@ -1630,7 +1630,7 @@ impl Promise {
Self::then_catch_finally_closures(c, on_finally, context); Self::then_catch_finally_closures(c, on_finally, context);
// 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
let then = promise.get(js_str!("then"), context)?; let then = promise.get(js_string!("then"), context)?;
then.call(this, &[then_finally.into(), catch_finally.into()], context) then.call(this, &[then_finally.into(), catch_finally.into()], context)
} }
@ -1685,7 +1685,7 @@ impl Promise {
let value_thunk = return_value.length(0).name("").build(); let value_thunk = return_value.length(0).name("").build();
// v. Return ? Invoke(promise, "then", « valueThunk »). // v. Return ? Invoke(promise, "then", « valueThunk »).
promise.invoke(js_str!("then"), &[value_thunk.into()], context) promise.invoke(js_string!("then"), &[value_thunk.into()], context)
}, },
FinallyCaptures { FinallyCaptures {
on_finally: on_finally.clone(), on_finally: on_finally.clone(),
@ -1736,7 +1736,7 @@ impl Promise {
let thrower = throw_reason.length(0).name("").build(); let thrower = throw_reason.length(0).name("").build();
// v. Return ? Invoke(promise, "then", « thrower »). // v. Return ? Invoke(promise, "then", « thrower »).
promise.invoke(js_str!("then"), &[thrower.into()], context) promise.invoke(js_string!("then"), &[thrower.into()], context)
}, },
FinallyCaptures { on_finally, c }, FinallyCaptures { on_finally, c },
), ),
@ -1941,7 +1941,7 @@ impl Promise {
context: &mut Context, context: &mut Context,
) -> JsResult<JsObject> { ) -> JsResult<JsObject> {
// 1. Let promiseResolve be ? Get(promiseConstructor, "resolve"). // 1. Let promiseResolve be ? Get(promiseConstructor, "resolve").
let promise_resolve = promise_constructor.get(js_str!("resolve"), context)?; let promise_resolve = promise_constructor.get(js_string!("resolve"), context)?;
// 2. If IsCallable(promiseResolve) is false, throw a TypeError exception. // 2. If IsCallable(promiseResolve) is false, throw a TypeError exception.
promise_resolve.as_callable().cloned().ok_or_else(|| { promise_resolve.as_callable().cloned().ok_or_else(|| {
@ -2139,7 +2139,7 @@ impl Promise {
}; };
// 9. Let then be Completion(Get(resolution, "then")). // 9. Let then be Completion(Get(resolution, "then")).
let then_action = match then.get(js_str!("then"), context) { let then_action = match then.get(js_string!("then"), context) {
// 10. If then is an abrupt completion, then // 10. If then is an abrupt completion, then
Err(e) => { Err(e) => {
// a. Perform RejectPromise(promise, then.[[Value]]). // a. Perform RejectPromise(promise, then.[[Value]]).

31
core/engine/src/builtins/proxy/mod.rs

@ -31,7 +31,6 @@ use crate::{
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_gc::{Finalize, GcRefCell, Trace}; use boa_gc::{Finalize, GcRefCell, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
@ -237,12 +236,12 @@ impl Proxy {
// 6. Perform ! CreateDataPropertyOrThrow(result, "proxy", p). // 6. Perform ! CreateDataPropertyOrThrow(result, "proxy", p).
result result
.create_data_property_or_throw(js_str!("proxy"), p, context) .create_data_property_or_throw(js_string!("proxy"), p, context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
// 7. Perform ! CreateDataPropertyOrThrow(result, "revoke", revoker). // 7. Perform ! CreateDataPropertyOrThrow(result, "revoke", revoker).
result result
.create_data_property_or_throw(js_str!("revoke"), revoker, context) .create_data_property_or_throw(js_string!("revoke"), revoker, context)
.expect("CreateDataPropertyOrThrow cannot fail here"); .expect("CreateDataPropertyOrThrow cannot fail here");
// 8. Return result. // 8. Return result.
@ -270,7 +269,7 @@ pub(crate) fn proxy_exotic_get_prototype_of(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
let Some(trap) = handler.get_method(js_str!("getPrototypeOf"), context)? else { let Some(trap) = handler.get_method(js_string!("getPrototypeOf"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[GetPrototypeOf]](). // a. Return ? target.[[GetPrototypeOf]]().
return target.__get_prototype_of__(context); return target.__get_prototype_of__(context);
@ -331,7 +330,7 @@ pub(crate) fn proxy_exotic_set_prototype_of(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "setPrototypeOf"). // 5. Let trap be ? GetMethod(handler, "setPrototypeOf").
let Some(trap) = handler.get_method(js_str!("setPrototypeOf"), context)? else { let Some(trap) = handler.get_method(js_string!("setPrototypeOf"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[SetPrototypeOf]](V). // a. Return ? target.[[SetPrototypeOf]](V).
return target.__set_prototype_of__(val, context); return target.__set_prototype_of__(val, context);
@ -390,7 +389,7 @@ pub(crate) fn proxy_exotic_is_extensible(obj: &JsObject, context: &mut Context)
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "isExtensible"). // 5. Let trap be ? GetMethod(handler, "isExtensible").
let Some(trap) = handler.get_method(js_str!("isExtensible"), context)? else { let Some(trap) = handler.get_method(js_string!("isExtensible"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? IsExtensible(target). // a. Return ? IsExtensible(target).
return target.is_extensible(context); return target.is_extensible(context);
@ -435,7 +434,7 @@ pub(crate) fn proxy_exotic_prevent_extensions(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "preventExtensions"). // 5. Let trap be ? GetMethod(handler, "preventExtensions").
let Some(trap) = handler.get_method(js_str!("preventExtensions"), context)? else { let Some(trap) = handler.get_method(js_string!("preventExtensions"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[PreventExtensions]](). // a. Return ? target.[[PreventExtensions]]().
return target.__prevent_extensions__(context); return target.__prevent_extensions__(context);
@ -482,7 +481,7 @@ pub(crate) fn proxy_exotic_get_own_property(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). // 5. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
let Some(trap) = handler.get_method(js_str!("getOwnPropertyDescriptor"), context)? else { let Some(trap) = handler.get_method(js_string!("getOwnPropertyDescriptor"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[GetOwnProperty]](P). // a. Return ? target.[[GetOwnProperty]](P).
return target.__get_own_property__(key, context); return target.__get_own_property__(key, context);
@ -607,7 +606,7 @@ pub(crate) fn proxy_exotic_define_own_property(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "defineProperty"). // 5. Let trap be ? GetMethod(handler, "defineProperty").
let Some(trap) = handler.get_method(js_str!("defineProperty"), context)? else { let Some(trap) = handler.get_method(js_string!("defineProperty"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[DefineOwnProperty]](P, Desc). // a. Return ? target.[[DefineOwnProperty]](P, Desc).
return target.__define_own_property__(key, desc, context); return target.__define_own_property__(key, desc, context);
@ -719,7 +718,7 @@ pub(crate) fn proxy_exotic_has_property(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "has"). // 5. Let trap be ? GetMethod(handler, "has").
let Some(trap) = handler.get_method(js_str!("has"), context)? else { let Some(trap) = handler.get_method(js_string!("has"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[HasProperty]](P). // a. Return ? target.[[HasProperty]](P).
return target.has_property(key.clone(), context); return target.has_property(key.clone(), context);
@ -811,7 +810,7 @@ pub(crate) fn proxy_exotic_get(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "get"). // 5. Let trap be ? GetMethod(handler, "get").
let Some(trap) = handler.get_method(js_str!("get"), context)? else { let Some(trap) = handler.get_method(js_string!("get"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[Get]](P, Receiver). // a. Return ? target.[[Get]](P, Receiver).
return target.__get__(key, receiver, context); return target.__get__(key, receiver, context);
@ -881,7 +880,7 @@ pub(crate) fn proxy_exotic_set(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "set"). // 5. Let trap be ? GetMethod(handler, "set").
let Some(trap) = handler.get_method(js_str!("set"), context)? else { let Some(trap) = handler.get_method(js_string!("set"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[Set]](P, V, Receiver). // a. Return ? target.[[Set]](P, V, Receiver).
return target.__set__(key, value, receiver, context); return target.__set__(key, value, receiver, context);
@ -961,7 +960,7 @@ pub(crate) fn proxy_exotic_delete(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "deleteProperty"). // 5. Let trap be ? GetMethod(handler, "deleteProperty").
let Some(trap) = handler.get_method(js_str!("deleteProperty"), context)? else { let Some(trap) = handler.get_method(js_string!("deleteProperty"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[Delete]](P). // a. Return ? target.[[Delete]](P).
return target.__delete__(key, context); return target.__delete__(key, context);
@ -1026,7 +1025,7 @@ pub(crate) fn proxy_exotic_own_property_keys(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "ownKeys"). // 5. Let trap be ? GetMethod(handler, "ownKeys").
let Some(trap) = handler.get_method(js_str!("ownKeys"), context)? else { let Some(trap) = handler.get_method(js_string!("ownKeys"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? target.[[OwnPropertyKeys]](). // a. Return ? target.[[OwnPropertyKeys]]().
return target.__own_property_keys__(context); return target.__own_property_keys__(context);
@ -1160,7 +1159,7 @@ fn proxy_exotic_call(
.try_data()?; .try_data()?;
// 5. Let trap be ? GetMethod(handler, "apply"). // 5. Let trap be ? GetMethod(handler, "apply").
let Some(trap) = handler.get_method(js_str!("apply"), context)? else { let Some(trap) = handler.get_method(js_string!("apply"), context)? else {
// 6. If trap is undefined, then // 6. If trap is undefined, then
// a. Return ? Call(target, thisArgument, argumentsList). // a. Return ? Call(target, thisArgument, argumentsList).
return Ok(target.__call__(argument_count)); return Ok(target.__call__(argument_count));
@ -1208,7 +1207,7 @@ fn proxy_exotic_construct(
assert!(target.is_constructor()); assert!(target.is_constructor());
// 6. Let trap be ? GetMethod(handler, "construct"). // 6. Let trap be ? GetMethod(handler, "construct").
let Some(trap) = handler.get_method(js_str!("construct"), context)? else { let Some(trap) = handler.get_method(js_string!("construct"), context)? else {
// 7. If trap is undefined, then // 7. If trap is undefined, then
// a. Return ? Construct(target, argumentsList, newTarget). // a. Return ? Construct(target, argumentsList, newTarget).
return Ok(target.__construct__(argument_count)); return Ok(target.__construct__(argument_count));

104
core/engine/src/builtins/regexp/mod.rs

@ -241,12 +241,12 @@ impl BuiltInConstructor for RegExp {
(p, f) (p, f)
} else if let Some(pattern) = pattern_is_regexp { } else if let Some(pattern) = pattern_is_regexp {
// a. Let P be ? Get(pattern, "source"). // a. Let P be ? Get(pattern, "source").
let p = pattern.get(js_str!("source"), context)?; let p = pattern.get(js_string!("source"), context)?;
// b. If flags is undefined, then // b. If flags is undefined, then
let f = if flags.is_undefined() { let f = if flags.is_undefined() {
// i. Let F be ? Get(pattern, "flags"). // i. Let F be ? Get(pattern, "flags").
pattern.get(js_str!("flags"), context)? pattern.get(js_string!("flags"), context)?
// c. Else, // c. Else,
} else { } else {
// i. Let F be flags. // i. Let F be flags.
@ -643,49 +643,49 @@ impl RegExp {
// 4. Let hasIndices be ToBoolean(? Get(R, "hasIndices")). // 4. Let hasIndices be ToBoolean(? Get(R, "hasIndices")).
// 5. If hasIndices is true, append the code unit 0x0064 (LATIN SMALL LETTER D) to codeUnits. // 5. If hasIndices is true, append the code unit 0x0064 (LATIN SMALL LETTER D) to codeUnits.
if object.get(js_str!("hasIndices"), context)?.to_boolean() { if object.get(js_string!("hasIndices"), context)?.to_boolean() {
code_units.push('d'); code_units.push('d');
} }
// 6. Let global be ToBoolean(? Get(R, "global")). // 6. Let global be ToBoolean(? Get(R, "global")).
// 7. If global is true, append the code unit 0x0067 (LATIN SMALL LETTER G) to codeUnits. // 7. If global is true, append the code unit 0x0067 (LATIN SMALL LETTER G) to codeUnits.
if object.get(js_str!("global"), context)?.to_boolean() { if object.get(js_string!("global"), context)?.to_boolean() {
code_units.push('g'); code_units.push('g');
} }
// 8. Let ignoreCase be ToBoolean(? Get(R, "ignoreCase")). // 8. Let ignoreCase be ToBoolean(? Get(R, "ignoreCase")).
// 9. If ignoreCase is true, append the code unit 0x0069 (LATIN SMALL LETTER I) to codeUnits. // 9. If ignoreCase is true, append the code unit 0x0069 (LATIN SMALL LETTER I) to codeUnits.
if object.get(js_str!("ignoreCase"), context)?.to_boolean() { if object.get(js_string!("ignoreCase"), context)?.to_boolean() {
code_units.push('i'); code_units.push('i');
} }
// 10. Let multiline be ToBoolean(? Get(R, "multiline")). // 10. Let multiline be ToBoolean(? Get(R, "multiline")).
// 11. If multiline is true, append the code unit 0x006D (LATIN SMALL LETTER M) to codeUnits. // 11. If multiline is true, append the code unit 0x006D (LATIN SMALL LETTER M) to codeUnits.
if object.get(js_str!("multiline"), context)?.to_boolean() { if object.get(js_string!("multiline"), context)?.to_boolean() {
code_units.push('m'); code_units.push('m');
} }
// 12. Let dotAll be ToBoolean(? Get(R, "dotAll")). // 12. Let dotAll be ToBoolean(? Get(R, "dotAll")).
// 13. If dotAll is true, append the code unit 0x0073 (LATIN SMALL LETTER S) to codeUnits. // 13. If dotAll is true, append the code unit 0x0073 (LATIN SMALL LETTER S) to codeUnits.
if object.get(js_str!("dotAll"), context)?.to_boolean() { if object.get(js_string!("dotAll"), context)?.to_boolean() {
code_units.push('s'); code_units.push('s');
} }
// 14. Let unicode be ToBoolean(? Get(R, "unicode")). // 14. Let unicode be ToBoolean(? Get(R, "unicode")).
// 15. If unicode is true, append the code unit 0x0075 (LATIN SMALL LETTER U) to codeUnits. // 15. If unicode is true, append the code unit 0x0075 (LATIN SMALL LETTER U) to codeUnits.
if object.get(js_str!("unicode"), context)?.to_boolean() { if object.get(js_string!("unicode"), context)?.to_boolean() {
code_units.push('u'); code_units.push('u');
} }
// 16. Let unicodeSets be ToBoolean(? Get(R, "unicodeSets")). // 16. Let unicodeSets be ToBoolean(? Get(R, "unicodeSets")).
// 17. If unicodeSets is true, append the code unit 0x0076 (LATIN SMALL LETTER V) to codeUnits. // 17. If unicodeSets is true, append the code unit 0x0076 (LATIN SMALL LETTER V) to codeUnits.
if object.get(js_str!("unicodeSets"), context)?.to_boolean() { if object.get(js_string!("unicodeSets"), context)?.to_boolean() {
code_units.push('v'); code_units.push('v');
} }
// 18. Let sticky be ToBoolean(? Get(R, "sticky")). // 18. Let sticky be ToBoolean(? Get(R, "sticky")).
// 19. If sticky is true, append the code unit 0x0079 (LATIN SMALL LETTER Y) to codeUnits. // 19. If sticky is true, append the code unit 0x0079 (LATIN SMALL LETTER Y) to codeUnits.
if object.get(js_str!("sticky"), context)?.to_boolean() { if object.get(js_string!("sticky"), context)?.to_boolean() {
code_units.push('y'); code_units.push('y');
} }
@ -727,7 +727,7 @@ impl RegExp {
this, this,
&JsValue::new(context.intrinsics().constructors().regexp().prototype()), &JsValue::new(context.intrinsics().constructors().regexp().prototype()),
) { ) {
Ok(JsValue::new(js_str!("(?:)"))) Ok(JsValue::new(js_string!("(?:)")))
} else { } else {
Err(JsNativeError::typ() Err(JsNativeError::typ()
.with_message("RegExp.prototype.source method called on incompatible value") .with_message("RegExp.prototype.source method called on incompatible value")
@ -755,7 +755,7 @@ impl RegExp {
/// [spec]: https://tc39.es/ecma262/#sec-escaperegexppattern /// [spec]: https://tc39.es/ecma262/#sec-escaperegexppattern
fn escape_pattern(src: &JsString, _flags: &JsString) -> JsValue { fn escape_pattern(src: &JsString, _flags: &JsString) -> JsValue {
if src.is_empty() { if src.is_empty() {
js_str!("(?:)").into() js_string!("(?:)").into()
} else { } else {
let mut s = Vec::with_capacity(src.len()); let mut s = Vec::with_capacity(src.len());
let mut buf = [0; 2]; let mut buf = [0; 2];
@ -866,7 +866,7 @@ impl RegExp {
// 2. Assert: Type(S) is String. // 2. Assert: Type(S) is String.
// 3. Let exec be ? Get(R, "exec"). // 3. Let exec be ? Get(R, "exec").
let exec = this.get(js_str!("exec"), context)?; let exec = this.get(js_string!("exec"), context)?;
// 4. If IsCallable(exec) is true, then // 4. If IsCallable(exec) is true, then
if let Some(exec) = exec.as_callable() { if let Some(exec) = exec.as_callable() {
@ -919,7 +919,7 @@ impl RegExp {
// 2. Let lastIndex be ℝ(? ToLength(? Get(R, "lastIndex"))). // 2. Let lastIndex be ℝ(? ToLength(? Get(R, "lastIndex"))).
let mut last_index = this let mut last_index = this
.get(js_str!("lastIndex"), context)? .get(js_string!("lastIndex"), context)?
.to_length(context)?; .to_length(context)?;
// 3. Let flags be R.[[OriginalFlags]]. // 3. Let flags be R.[[OriginalFlags]].
@ -957,7 +957,7 @@ impl RegExp {
// i. If global is true or sticky is true, then // i. If global is true or sticky is true, then
if global || sticky { if global || sticky {
// 1. Perform ? Set(R, "lastIndex", +0𝔽, true). // 1. Perform ? Set(R, "lastIndex", +0𝔽, true).
this.set(js_str!("lastIndex"), 0, true, context)?; this.set(js_string!("lastIndex"), 0, true, context)?;
} }
// ii. Return null. // ii. Return null.
@ -990,7 +990,7 @@ impl RegExp {
// 13.a.i. If global is true or sticky is true, then // 13.a.i. If global is true or sticky is true, then
if global || sticky { if global || sticky {
// 1. Perform ? Set(R, "lastIndex", +0𝔽, true). // 1. Perform ? Set(R, "lastIndex", +0𝔽, true).
this.set(js_str!("lastIndex"), 0, true, context)?; this.set(js_string!("lastIndex"), 0, true, context)?;
} }
// MOVE: ii. Set lastIndex to AdvanceStringIndex(S, lastIndex, fullUnicode). // MOVE: ii. Set lastIndex to AdvanceStringIndex(S, lastIndex, fullUnicode).
@ -1009,7 +1009,7 @@ impl RegExp {
// NOTE: regress currently doesn't support the sticky flag so we have to emulate it. // NOTE: regress currently doesn't support the sticky flag so we have to emulate it.
if sticky && match_value.start() != last_index as usize { if sticky && match_value.start() != last_index as usize {
// 1. Perform ? Set(R, "lastIndex", +0𝔽, true). // 1. Perform ? Set(R, "lastIndex", +0𝔽, true).
this.set(js_str!("lastIndex"), 0, true, context)?; this.set(js_string!("lastIndex"), 0, true, context)?;
// 2. Return null. // 2. Return null.
return Ok(None); return Ok(None);
@ -1027,7 +1027,7 @@ impl RegExp {
// 16. If global is true or sticky is true, then // 16. If global is true or sticky is true, then
if global || sticky { if global || sticky {
// a. Perform ? Set(R, "lastIndex", 𝔽(e), true). // a. Perform ? Set(R, "lastIndex", 𝔽(e), true).
this.set(js_str!("lastIndex"), e, true, context)?; this.set(js_string!("lastIndex"), e, true, context)?;
} }
// 17. Let n be the number of elements in r's captures List. // 17. Let n be the number of elements in r's captures List.
@ -1041,11 +1041,11 @@ impl RegExp {
let a = Array::array_create(n + 1, None, context)?; let a = Array::array_create(n + 1, None, context)?;
// 22. Perform ! CreateDataPropertyOrThrow(A, "index", 𝔽(lastIndex)). // 22. Perform ! CreateDataPropertyOrThrow(A, "index", 𝔽(lastIndex)).
a.create_data_property_or_throw(js_str!("index"), last_index, context) a.create_data_property_or_throw(js_string!("index"), last_index, context)
.expect("this CreateDataPropertyOrThrow call must not fail"); .expect("this CreateDataPropertyOrThrow call must not fail");
// 23. Perform ! CreateDataPropertyOrThrow(A, "input", S). // 23. Perform ! CreateDataPropertyOrThrow(A, "input", S).
a.create_data_property_or_throw(js_str!("input"), input.clone(), context) a.create_data_property_or_throw(js_string!("input"), input.clone(), context)
.expect("this CreateDataPropertyOrThrow call must not fail"); .expect("this CreateDataPropertyOrThrow call must not fail");
// 24. Let match be the Match Record { [[StartIndex]]: lastIndex, [[EndIndex]]: e }. // 24. Let match be the Match Record { [[StartIndex]]: lastIndex, [[EndIndex]]: e }.
@ -1141,11 +1141,11 @@ impl RegExp {
// 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups ) // 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups )
// 8. Perform ! CreateDataPropertyOrThrow(A, "groups", groups). // 8. Perform ! CreateDataPropertyOrThrow(A, "groups", groups).
indices indices
.create_data_property_or_throw(js_str!("groups"), group_names, context) .create_data_property_or_throw(js_string!("groups"), group_names, context)
.expect("this CreateDataPropertyOrThrow call must not fail"); .expect("this CreateDataPropertyOrThrow call must not fail");
// 32. Perform ! CreateDataPropertyOrThrow(A, "groups", groups). // 32. Perform ! CreateDataPropertyOrThrow(A, "groups", groups).
a.create_data_property_or_throw(js_str!("groups"), groups, context) a.create_data_property_or_throw(js_string!("groups"), groups, context)
.expect("this CreateDataPropertyOrThrow call must not fail"); .expect("this CreateDataPropertyOrThrow call must not fail");
// 27. For each integer i such that i ≥ 1 and i ≤ n, in ascending order, do // 27. For each integer i such that i ≥ 1 and i ≤ n, in ascending order, do
@ -1186,7 +1186,7 @@ impl RegExp {
// a. Let indicesArray be MakeMatchIndicesIndexPairArray(S, indices, groupNames, hasGroups). // a. Let indicesArray be MakeMatchIndicesIndexPairArray(S, indices, groupNames, hasGroups).
// b. Perform ! CreateDataPropertyOrThrow(A, "indices", indicesArray). // b. Perform ! CreateDataPropertyOrThrow(A, "indices", indicesArray).
if has_indices { if has_indices {
a.create_data_property_or_throw(js_str!("indices"), indices, context) a.create_data_property_or_throw(js_string!("indices"), indices, context)
.expect("this CreateDataPropertyOrThrow call must not fail"); .expect("this CreateDataPropertyOrThrow call must not fail");
} }
@ -1221,7 +1221,7 @@ impl RegExp {
let arg_str = args.get_or_undefined(0).to_string(context)?; let arg_str = args.get_or_undefined(0).to_string(context)?;
// 4. Let flags be ? ToString(? Get(rx, "flags")). // 4. Let flags be ? ToString(? Get(rx, "flags")).
let flags = rx.get(js_str!("flags"), context)?.to_string(context)?; let flags = rx.get(js_string!("flags"), context)?.to_string(context)?;
// 5. If flags does not contain "g", then // 5. If flags does not contain "g", then
if !flags.contains(b'g') { if !flags.contains(b'g') {
@ -1236,7 +1236,7 @@ impl RegExp {
let full_unicode = flags.contains(b'u') || flags.contains(b'v'); let full_unicode = flags.contains(b'u') || flags.contains(b'v');
// b. Perform ? Set(rx, "lastIndex", +0𝔽, true). // b. Perform ? Set(rx, "lastIndex", +0𝔽, true).
rx.set(js_str!("lastIndex"), 0, true, context)?; rx.set(js_string!("lastIndex"), 0, true, context)?;
// c. Let A be ! ArrayCreate(0). // c. Let A be ! ArrayCreate(0).
let a = Array::array_create(0, None, context).expect("this ArrayCreate call must not fail"); let a = Array::array_create(0, None, context).expect("this ArrayCreate call must not fail");
@ -1262,14 +1262,16 @@ impl RegExp {
// 3. If matchStr is the empty String, then // 3. If matchStr is the empty String, then
if match_str.is_empty() { if match_str.is_empty() {
// a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))). // a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))).
let this_index = rx.get(js_str!("lastIndex"), context)?.to_length(context)?; let this_index = rx
.get(js_string!("lastIndex"), context)?
.to_length(context)?;
// b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode). // b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
let next_index = advance_string_index(&arg_str, this_index, full_unicode); let next_index = advance_string_index(&arg_str, this_index, full_unicode);
// c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true). // c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true).
rx.set( rx.set(
js_str!("lastIndex"), js_string!("lastIndex"),
JsValue::new(next_index), JsValue::new(next_index),
true, true,
context, context,
@ -1313,10 +1315,14 @@ impl RegExp {
})?; })?;
// 3. Let pattern be ? ToString(? Get(R, "source")). // 3. Let pattern be ? ToString(? Get(R, "source")).
let pattern = regexp.get(js_str!("source"), context)?.to_string(context)?; let pattern = regexp
.get(js_string!("source"), context)?
.to_string(context)?;
// 4. Let flags be ? ToString(? Get(R, "flags")). // 4. Let flags be ? ToString(? Get(R, "flags")).
let flags = regexp.get(js_str!("flags"), context)?.to_string(context)?; let flags = regexp
.get(js_string!("flags"), context)?
.to_string(context)?;
// 5. Let result be the string-concatenation of "/", pattern, "/", and flags. // 5. Let result be the string-concatenation of "/", pattern, "/", and flags.
// 6. Return result. // 6. Return result.
@ -1352,18 +1358,20 @@ impl RegExp {
let c = regexp.species_constructor(StandardConstructors::regexp, context)?; let c = regexp.species_constructor(StandardConstructors::regexp, context)?;
// 5. Let flags be ? ToString(? Get(R, "flags")). // 5. Let flags be ? ToString(? Get(R, "flags")).
let flags = regexp.get(js_str!("flags"), context)?.to_string(context)?; let flags = regexp
.get(js_string!("flags"), context)?
.to_string(context)?;
// 6. Let matcher be ? Construct(C, « R, flags »). // 6. Let matcher be ? Construct(C, « R, flags »).
let matcher = c.construct(&[this.clone(), flags.clone().into()], Some(&c), context)?; let matcher = c.construct(&[this.clone(), flags.clone().into()], Some(&c), context)?;
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
let last_index = regexp let last_index = regexp
.get(js_str!("lastIndex"), context)? .get(js_string!("lastIndex"), context)?
.to_length(context)?; .to_length(context)?;
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
matcher.set(js_str!("lastIndex"), last_index, true, context)?; matcher.set(js_string!("lastIndex"), last_index, true, context)?;
// 9. If flags contains "g", let global be true. // 9. If flags contains "g", let global be true.
// 10. Else, let global be false. // 10. Else, let global be false.
@ -1434,7 +1442,7 @@ impl RegExp {
}; };
// 7. Let flags be ? ToString(? Get(rx, "flags")). // 7. Let flags be ? ToString(? Get(rx, "flags")).
let flags = rx.get(js_str!("flags"), context)?.to_string(context)?; let flags = rx.get(js_string!("flags"), context)?.to_string(context)?;
// 8. If flags contains "g", let global be true. Otherwise, let global be false. // 8. If flags contains "g", let global be true. Otherwise, let global be false.
let global = flags.contains(b'g'); let global = flags.contains(b'g');
@ -1445,7 +1453,7 @@ impl RegExp {
let full_unicode = flags.contains(b'u'); let full_unicode = flags.contains(b'u');
// b. Perform ? Set(rx, "lastIndex", +0𝔽, true). // b. Perform ? Set(rx, "lastIndex", +0𝔽, true).
rx.set(js_str!("lastIndex"), 0, true, context)?; rx.set(js_string!("lastIndex"), 0, true, context)?;
full_unicode full_unicode
} else { } else {
@ -1487,14 +1495,16 @@ impl RegExp {
// 2. If matchStr is the empty String, then // 2. If matchStr is the empty String, then
if match_str.is_empty() { if match_str.is_empty() {
// a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))). // a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))).
let this_index = rx.get(js_str!("lastIndex"), context)?.to_length(context)?; let this_index = rx
.get(js_string!("lastIndex"), context)?
.to_length(context)?;
// b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode). // b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
let next_index = advance_string_index(&s, this_index, full_unicode); let next_index = advance_string_index(&s, this_index, full_unicode);
// c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true). // c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true).
rx.set( rx.set(
js_str!("lastIndex"), js_string!("lastIndex"),
JsValue::new(next_index), JsValue::new(next_index),
true, true,
context, context,
@ -1527,7 +1537,7 @@ impl RegExp {
// e. Let position be ? ToIntegerOrInfinity(? Get(result, "index")). // e. Let position be ? ToIntegerOrInfinity(? Get(result, "index")).
let position = result let position = result
.get(js_str!("index"), context)? .get(js_string!("index"), context)?
.to_integer_or_infinity(context)?; .to_integer_or_infinity(context)?;
// f. Set position to the result of clamping position between 0 and lengthS. // f. Set position to the result of clamping position between 0 and lengthS.
@ -1559,7 +1569,7 @@ impl RegExp {
} }
// j. Let namedCaptures be ? Get(result, "groups"). // j. Let namedCaptures be ? Get(result, "groups").
let mut named_captures = result.get(js_str!("groups"), context)?; let mut named_captures = result.get(js_string!("groups"), context)?;
let replacement = match replace_value { let replacement = match replace_value {
// k. If functionalReplace is true, then // k. If functionalReplace is true, then
@ -1659,31 +1669,31 @@ impl RegExp {
let arg_str = args.get_or_undefined(0).to_string(context)?; let arg_str = args.get_or_undefined(0).to_string(context)?;
// 4. Let previousLastIndex be ? Get(rx, "lastIndex"). // 4. Let previousLastIndex be ? Get(rx, "lastIndex").
let previous_last_index = rx.get(js_str!("lastIndex"), context)?; let previous_last_index = rx.get(js_string!("lastIndex"), context)?;
// 5. If SameValue(previousLastIndex, +0𝔽) is false, then // 5. If SameValue(previousLastIndex, +0𝔽) is false, then
if !JsValue::same_value(&previous_last_index, &JsValue::new(0)) { if !JsValue::same_value(&previous_last_index, &JsValue::new(0)) {
// a. Perform ? Set(rx, "lastIndex", +0𝔽, true). // a. Perform ? Set(rx, "lastIndex", +0𝔽, true).
rx.set(js_str!("lastIndex"), 0, true, context)?; rx.set(js_string!("lastIndex"), 0, true, context)?;
} }
// 6. Let result be ? RegExpExec(rx, S). // 6. Let result be ? RegExpExec(rx, S).
let result = Self::abstract_exec(rx, arg_str, context)?; let result = Self::abstract_exec(rx, arg_str, context)?;
// 7. Let currentLastIndex be ? Get(rx, "lastIndex"). // 7. Let currentLastIndex be ? Get(rx, "lastIndex").
let current_last_index = rx.get(js_str!("lastIndex"), context)?; let current_last_index = rx.get(js_string!("lastIndex"), context)?;
// 8. If SameValue(currentLastIndex, previousLastIndex) is false, then // 8. If SameValue(currentLastIndex, previousLastIndex) is false, then
if !JsValue::same_value(&current_last_index, &previous_last_index) { if !JsValue::same_value(&current_last_index, &previous_last_index) {
// a. Perform ? Set(rx, "lastIndex", previousLastIndex, true). // a. Perform ? Set(rx, "lastIndex", previousLastIndex, true).
rx.set(js_str!("lastIndex"), previous_last_index, true, context)?; rx.set(js_string!("lastIndex"), previous_last_index, true, context)?;
} }
// 9. If result is null, return -1𝔽. // 9. If result is null, return -1𝔽.
// 10. Return ? Get(result, "index"). // 10. Return ? Get(result, "index").
result.map_or_else( result.map_or_else(
|| Ok(JsValue::new(-1)), || Ok(JsValue::new(-1)),
|result| result.get(js_str!("index"), context), |result| result.get(js_string!("index"), context),
) )
} }
@ -1716,7 +1726,7 @@ impl RegExp {
let constructor = rx.species_constructor(StandardConstructors::regexp, context)?; let constructor = rx.species_constructor(StandardConstructors::regexp, context)?;
// 5. Let flags be ? ToString(? Get(rx, "flags")). // 5. Let flags be ? ToString(? Get(rx, "flags")).
let flags = rx.get(js_str!("flags"), context)?.to_string(context)?; let flags = rx.get(js_string!("flags"), context)?.to_string(context)?;
// 6. If flags contains "u", let unicodeMatching be true. // 6. If flags contains "u", let unicodeMatching be true.
// 7. Else, let unicodeMatching be false. // 7. Else, let unicodeMatching be false.
@ -1785,7 +1795,7 @@ impl RegExp {
// 19. Repeat, while q < size, // 19. Repeat, while q < size,
while q < size { while q < size {
// a. Perform ? Set(splitter, "lastIndex", 𝔽(q), true). // a. Perform ? Set(splitter, "lastIndex", 𝔽(q), true).
splitter.set(js_str!("lastIndex"), JsValue::new(q), true, context)?; splitter.set(js_string!("lastIndex"), JsValue::new(q), true, context)?;
// b. Let z be ? RegExpExec(splitter, S). // b. Let z be ? RegExpExec(splitter, S).
let result = Self::abstract_exec(&splitter, arg_str.clone(), context)?; let result = Self::abstract_exec(&splitter, arg_str.clone(), context)?;
@ -1795,7 +1805,7 @@ impl RegExp {
if let Some(result) = result { if let Some(result) = result {
// i. Let e be ℝ(? ToLength(? Get(splitter, "lastIndex"))). // i. Let e be ℝ(? ToLength(? Get(splitter, "lastIndex"))).
let mut e = splitter let mut e = splitter
.get(js_str!("lastIndex"), context)? .get(js_string!("lastIndex"), context)?
.to_length(context)?; .to_length(context)?;
// ii. Set e to min(e, size). // ii. Set e to min(e, size).
@ -1919,7 +1929,7 @@ impl RegExp {
.expect("already checked that the object was a RegExp") = regexp; .expect("already checked that the object was a RegExp") = regexp;
} }
this.set(js_str!("lastIndex"), 0, true, context)?; this.set(js_string!("lastIndex"), 0, true, context)?;
Ok(this.into()) Ok(this.into())
} }

5
core/engine/src/builtins/regexp/regexp_string_iterator.rs

@ -22,7 +22,6 @@ use crate::{
Context, JsData, JsResult, JsString, JsValue, Context, JsData, JsResult, JsString, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use regexp::{advance_string_index, RegExp}; use regexp::{advance_string_index, RegExp};
@ -160,7 +159,7 @@ impl RegExpStringIterator {
// 1. Let thisIndex be ℝ(? ToLength(? Get(R, "lastIndex"))). // 1. Let thisIndex be ℝ(? ToLength(? Get(R, "lastIndex"))).
let this_index = iterator let this_index = iterator
.matcher .matcher
.get(js_str!("lastIndex"), context)? .get(js_string!("lastIndex"), context)?
.to_length(context)?; .to_length(context)?;
// 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode). // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode).
@ -170,7 +169,7 @@ impl RegExpStringIterator {
// 3. Perform ? Set(R, "lastIndex", 𝔽(nextIndex), true). // 3. Perform ? Set(R, "lastIndex", 𝔽(nextIndex), true).
iterator iterator
.matcher .matcher
.set(js_str!("lastIndex"), next_index, true, context)?; .set(js_string!("lastIndex"), next_index, true, context)?;
} }
// vi. Perform ? Yield(match). // vi. Perform ? Yield(match).

3
core/engine/src/builtins/set/mod.rs

@ -30,7 +30,6 @@ use crate::{
symbol::JsSymbol, symbol::JsSymbol,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use num_traits::Zero; use num_traits::Zero;
@ -146,7 +145,7 @@ impl BuiltInConstructor for Set {
} }
// 5. Let adder be ? Get(set, "add"). // 5. Let adder be ? Get(set, "add").
let adder = set.get(js_str!("add"), context)?; let adder = set.get(js_string!("add"), context)?;
// 6. If IsCallable(adder) is false, throw a TypeError exception. // 6. If IsCallable(adder) is false, throw a TypeError exception.
let adder = adder.as_callable().ok_or_else(|| { let adder = adder.as_callable().ok_or_else(|| {

13
core/engine/src/builtins/string/mod.rs

@ -22,7 +22,8 @@ use crate::{
value::IntegerOrInfinity, value::IntegerOrInfinity,
Context, JsArgs, JsResult, JsString, JsValue, Context, JsArgs, JsResult, JsString, JsValue,
}; };
use boa_macros::{js_str, utf16}; use boa_macros::utf16;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use icu_normalizer::{ComposingNormalizer, DecomposingNormalizer}; use icu_normalizer::{ComposingNormalizer, DecomposingNormalizer};
use std::cmp::{max, min}; use std::cmp::{max, min};
@ -33,7 +34,7 @@ mod string_iterator;
pub(crate) use string_iterator::StringIterator; pub(crate) use string_iterator::StringIterator;
#[cfg(feature = "annex-b")] #[cfg(feature = "annex-b")]
pub use crate::JsStr; pub use crate::{js_str, JsStr};
/// The set of normalizers required for the `String.prototype.normalize` function. /// The set of normalizers required for the `String.prototype.normalize` function.
#[derive(Debug)] #[derive(Debug)]
@ -387,7 +388,7 @@ impl String {
let cooked = args.get_or_undefined(0).to_object(context)?; let cooked = args.get_or_undefined(0).to_object(context)?;
// 3. Let raw be ? ToObject(? Get(cooked, "raw")). // 3. Let raw be ? ToObject(? Get(cooked, "raw")).
let raw = cooked.get(js_str!("raw"), context)?.to_object(context)?; let raw = cooked.get(js_string!("raw"), context)?.to_object(context)?;
// 4. Let literalSegments be ? LengthOfArrayLike(raw). // 4. Let literalSegments be ? LengthOfArrayLike(raw).
let literal_segments = raw.length_of_array_like(context)?; let literal_segments = raw.length_of_array_like(context)?;
@ -1129,7 +1130,7 @@ impl String {
// b. If isRegExp is true, then // b. If isRegExp is true, then
if let Some(obj) = RegExp::is_reg_exp(search_value, context)? { if let Some(obj) = RegExp::is_reg_exp(search_value, context)? {
// i. Let flags be ? Get(searchValue, "flags"). // i. Let flags be ? Get(searchValue, "flags").
let flags = obj.get(js_str!("flags"), context)?; let flags = obj.get(js_string!("flags"), context)?;
// ii. Perform ? RequireObjectCoercible(flags). // ii. Perform ? RequireObjectCoercible(flags).
flags.require_object_coercible()?; flags.require_object_coercible()?;
@ -2074,7 +2075,7 @@ impl String {
// b. If isRegExp is true, then // b. If isRegExp is true, then
if let Some(regexp) = RegExp::is_reg_exp(regexp, context)? { if let Some(regexp) = RegExp::is_reg_exp(regexp, context)? {
// i. Let flags be ? Get(regexp, "flags"). // i. Let flags be ? Get(regexp, "flags").
let flags = regexp.get(js_str!("flags"), context)?; let flags = regexp.get(js_string!("flags"), context)?;
// ii. Perform ? RequireObjectCoercible(flags). // ii. Perform ? RequireObjectCoercible(flags).
flags.require_object_coercible()?; flags.require_object_coercible()?;
@ -2100,7 +2101,7 @@ impl String {
let s = o.to_string(context)?; let s = o.to_string(context)?;
// 4. Let rx be ? RegExpCreate(regexp, "g"). // 4. Let rx be ? RegExpCreate(regexp, "g").
let rx = RegExp::create(regexp, &JsValue::new(js_str!("g")), context)?; let rx = RegExp::create(regexp, &JsValue::new(js_string!("g")), context)?;
// 5. Return ? Invoke(rx, @@matchAll, « S »). // 5. Return ? Invoke(rx, @@matchAll, « S »).
rx.invoke(JsSymbol::match_all(), &[JsValue::new(s)], context) rx.invoke(JsSymbol::match_all(), &[JsValue::new(s)], context)

4
core/engine/src/builtins/temporal/calendar/mod.rs

@ -3,7 +3,7 @@
use std::str::FromStr; use std::str::FromStr;
use super::extract_from_temporal_type; use super::extract_from_temporal_type;
use crate::{js_str, Context, JsNativeError, JsObject, JsResult, JsValue}; use crate::{js_string, Context, JsNativeError, JsObject, JsResult, JsValue};
use temporal_rs::components::calendar::Calendar; use temporal_rs::components::calendar::Calendar;
// -- `Calendar` Abstract Operations -- // -- `Calendar` Abstract Operations --
@ -32,7 +32,7 @@ pub(crate) fn get_temporal_calendar_slot_value_with_default(
} }
// 2. Let calendarLike be ? Get(item, "calendar"). // 2. Let calendarLike be ? Get(item, "calendar").
let calendar_like = item.get(js_str!("calendar"), context)?; let calendar_like = item.get(js_string!("calendar"), context)?;
// 3. Return ? ToTemporalCalendarSlotValue(calendarLike, "iso8601"). // 3. Return ? ToTemporalCalendarSlotValue(calendarLike, "iso8601").
to_temporal_calendar_slot_value(&calendar_like) to_temporal_calendar_slot_value(&calendar_like)

35
core/engine/src/builtins/temporal/duration/mod.rs

@ -14,7 +14,6 @@ use crate::{
Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use temporal_rs::{ use temporal_rs::{
components::{duration::PartialDuration, Duration as InnerDuration}, components::{duration::PartialDuration, Duration as InnerDuration},
@ -659,7 +658,7 @@ impl Duration {
let new_round_to = JsObject::with_null_proto(); let new_round_to = JsObject::with_null_proto();
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
new_round_to.create_data_property_or_throw( new_round_to.create_data_property_or_throw(
js_str!("smallestUnit"), js_string!("smallestUnit"),
param_string, param_string,
context, context,
)?; )?;
@ -681,7 +680,7 @@ impl Duration {
// 9. Let largestUnit be ? GetTemporalUnit(roundTo, "largestUnit", datetime, undefined, « "auto" »). // 9. Let largestUnit be ? GetTemporalUnit(roundTo, "largestUnit", datetime, undefined, « "auto" »).
options.largest_unit = get_temporal_unit( options.largest_unit = get_temporal_unit(
&round_to, &round_to,
js_str!("largestUnit"), js_string!("largestUnit"),
TemporalUnitGroup::DateTime, TemporalUnitGroup::DateTime,
Some([TemporalUnit::Auto].into()), Some([TemporalUnit::Auto].into()),
context, context,
@ -695,16 +694,16 @@ impl Duration {
// 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). // 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo).
options.increment = options.increment =
get_option::<RoundingIncrement>(&round_to, js_str!("roundingIncrement"), context)?; get_option::<RoundingIncrement>(&round_to, js_string!("roundingIncrement"), context)?;
// 14. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). // 14. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
options.rounding_mode = options.rounding_mode =
get_option::<TemporalRoundingMode>(&round_to, js_str!("roundingMode"), context)?; get_option::<TemporalRoundingMode>(&round_to, js_string!("roundingMode"), context)?;
// 15. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", datetime, undefined). // 15. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", datetime, undefined).
options.smallest_unit = get_temporal_unit( options.smallest_unit = get_temporal_unit(
&round_to, &round_to,
js_str!("smallestUnit"), js_string!("smallestUnit"),
TemporalUnitGroup::DateTime, TemporalUnitGroup::DateTime,
None, None,
context, context,
@ -754,7 +753,7 @@ impl Duration {
let total_of = JsObject::with_null_proto(); let total_of = JsObject::with_null_proto();
// c. Perform ! CreateDataPropertyOrThrow(totalOf, "unit", paramString). // c. Perform ! CreateDataPropertyOrThrow(totalOf, "unit", paramString).
total_of.create_data_property_or_throw( total_of.create_data_property_or_throw(
js_str!("unit"), js_string!("unit"),
param_string.clone(), param_string.clone(),
context, context,
)?; )?;
@ -777,7 +776,7 @@ impl Duration {
// 10. Let unit be ? GetTemporalUnit(totalOf, "unit", datetime, required). // 10. Let unit be ? GetTemporalUnit(totalOf, "unit", datetime, required).
let _unit = get_temporal_unit( let _unit = get_temporal_unit(
&total_of, &total_of,
js_str!("unit"), js_string!("unit"),
TemporalUnitGroup::DateTime, TemporalUnitGroup::DateTime,
None, None,
context, context,
@ -935,7 +934,7 @@ pub(crate) fn to_temporal_partial_duration(
// 3. NOTE: The following steps read properties and perform independent validation in alphabetical order. // 3. NOTE: The following steps read properties and perform independent validation in alphabetical order.
// 4. Let days be ? Get(temporalDurationLike, "days"). // 4. Let days be ? Get(temporalDurationLike, "days").
let days = unknown_object.get(js_str!("days"), context)?; let days = unknown_object.get(js_string!("days"), context)?;
if !days.is_undefined() { if !days.is_undefined() {
// 5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days). // 5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days).
let _ = result let _ = result
@ -944,7 +943,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 6. Let hours be ? Get(temporalDurationLike, "hours"). // 6. Let hours be ? Get(temporalDurationLike, "hours").
let hours = unknown_object.get(js_str!("hours"), context)?; let hours = unknown_object.get(js_string!("hours"), context)?;
// 7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours). // 7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours).
if !hours.is_undefined() { if !hours.is_undefined() {
let _ = result let _ = result
@ -953,7 +952,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 8. Let microseconds be ? Get(temporalDurationLike, "microseconds"). // 8. Let microseconds be ? Get(temporalDurationLike, "microseconds").
let microseconds = unknown_object.get(js_str!("microseconds"), context)?; let microseconds = unknown_object.get(js_string!("microseconds"), context)?;
// 9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds). // 9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds).
if !microseconds.is_undefined() { if !microseconds.is_undefined() {
let _ = result let _ = result
@ -965,7 +964,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds"). // 10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds").
let milliseconds = unknown_object.get(js_str!("milliseconds"), context)?; let milliseconds = unknown_object.get(js_string!("milliseconds"), context)?;
// 11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds). // 11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds).
if !milliseconds.is_undefined() { if !milliseconds.is_undefined() {
let _ = result let _ = result
@ -977,7 +976,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 12. Let minutes be ? Get(temporalDurationLike, "minutes"). // 12. Let minutes be ? Get(temporalDurationLike, "minutes").
let minutes = unknown_object.get(js_str!("minutes"), context)?; let minutes = unknown_object.get(js_string!("minutes"), context)?;
// 13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes). // 13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes).
if !minutes.is_undefined() { if !minutes.is_undefined() {
let _ = result let _ = result
@ -986,7 +985,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 14. Let months be ? Get(temporalDurationLike, "months"). // 14. Let months be ? Get(temporalDurationLike, "months").
let months = unknown_object.get(js_str!("months"), context)?; let months = unknown_object.get(js_string!("months"), context)?;
// 15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months). // 15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months).
if !months.is_undefined() { if !months.is_undefined() {
let _ = result let _ = result
@ -995,7 +994,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds"). // 16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds").
let nanoseconds = unknown_object.get(js_str!("nanoseconds"), context)?; let nanoseconds = unknown_object.get(js_string!("nanoseconds"), context)?;
// 17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds). // 17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds).
if !nanoseconds.is_undefined() { if !nanoseconds.is_undefined() {
let _ = result let _ = result
@ -1007,7 +1006,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 18. Let seconds be ? Get(temporalDurationLike, "seconds"). // 18. Let seconds be ? Get(temporalDurationLike, "seconds").
let seconds = unknown_object.get(js_str!("seconds"), context)?; let seconds = unknown_object.get(js_string!("seconds"), context)?;
// 19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds). // 19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds).
if !seconds.is_undefined() { if !seconds.is_undefined() {
let _ = result let _ = result
@ -1016,7 +1015,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 20. Let weeks be ? Get(temporalDurationLike, "weeks"). // 20. Let weeks be ? Get(temporalDurationLike, "weeks").
let weeks = unknown_object.get(js_str!("weeks"), context)?; let weeks = unknown_object.get(js_string!("weeks"), context)?;
// 21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks). // 21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks).
if !weeks.is_undefined() { if !weeks.is_undefined() {
let _ = result let _ = result
@ -1025,7 +1024,7 @@ pub(crate) fn to_temporal_partial_duration(
} }
// 22. Let years be ? Get(temporalDurationLike, "years"). // 22. Let years be ? Get(temporalDurationLike, "years").
let years = unknown_object.get(js_str!("years"), context)?; let years = unknown_object.get(js_string!("years"), context)?;
// 23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years). // 23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years).
if !years.is_undefined() { if !years.is_undefined() {
let _ = result let _ = result

17
core/engine/src/builtins/temporal/instant/mod.rs

@ -21,7 +21,6 @@ use crate::{
JsValue, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use temporal_rs::{ use temporal_rs::{
@ -70,25 +69,25 @@ impl IntrinsicObject for Instant {
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("epochSeconds"), js_string!("epochSeconds"),
Some(get_seconds), Some(get_seconds),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("epochMilliseconds"), js_string!("epochMilliseconds"),
Some(get_millis), Some(get_millis),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("epochMicroseconds"), js_string!("epochMicroseconds"),
Some(get_micros), Some(get_micros),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("epochNanoseconds"), js_string!("epochNanoseconds"),
Some(get_nanos), Some(get_nanos),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
@ -429,7 +428,7 @@ impl Instant {
let new_round_to = JsObject::with_null_proto(); let new_round_to = JsObject::with_null_proto();
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
new_round_to.create_data_property_or_throw( new_round_to.create_data_property_or_throw(
js_str!("smallestUnit"), js_string!("smallestUnit"),
param_string, param_string,
context, context,
)?; )?;
@ -447,16 +446,16 @@ impl Instant {
let mut options = RoundingOptions::default(); let mut options = RoundingOptions::default();
// 7. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). // 7. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo).
options.increment = options.increment =
get_option::<RoundingIncrement>(&round_to, js_str!("roundingIncrement"), context)?; get_option::<RoundingIncrement>(&round_to, js_string!("roundingIncrement"), context)?;
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). // 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
options.rounding_mode = options.rounding_mode =
get_option::<TemporalRoundingMode>(&round_to, js_str!("roundingMode"), context)?; get_option::<TemporalRoundingMode>(&round_to, js_string!("roundingMode"), context)?;
// 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit"), time, required). // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit"), time, required).
let smallest_unit = get_temporal_unit( let smallest_unit = get_temporal_unit(
&round_to, &round_to,
js_str!("smallestUnit"), js_string!("smallestUnit"),
TemporalUnitGroup::Time, TemporalUnitGroup::Time,
None, None,
context, context,

9
core/engine/src/builtins/temporal/mod.rs

@ -30,13 +30,12 @@ use crate::{
builtins::{iterable::IteratorRecord, BuiltInBuilder, BuiltInObject, IntrinsicObject}, builtins::{iterable::IteratorRecord, BuiltInBuilder, BuiltInObject, IntrinsicObject},
context::intrinsics::Intrinsics, context::intrinsics::Intrinsics,
js_string, js_string,
property::{Attribute, PropertyKey}, property::Attribute,
realm::Realm, realm::Realm,
string::StaticJsStrings, string::StaticJsStrings,
value::Type, value::Type,
Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
}; };
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use temporal_rs::{ use temporal_rs::{
components::{Date as TemporalDate, ZonedDateTime as TemporalZonedDateTime}, components::{Date as TemporalDate, ZonedDateTime as TemporalZonedDateTime},
@ -246,7 +245,7 @@ pub(crate) fn to_relative_temporal_object(
options: &JsObject, options: &JsObject,
context: &mut Context, context: &mut Context,
) -> RelativeTemporalObjectResult { ) -> RelativeTemporalObjectResult {
let relative_to = options.get(PropertyKey::from(js_str!("relativeTo")), context)?; let relative_to = options.get(js_string!("relativeTo"), context)?;
let plain_date = match relative_to { let plain_date = match relative_to {
JsValue::String(relative_to_str) => JsValue::from(relative_to_str), JsValue::String(relative_to_str) => JsValue::from(relative_to_str),
JsValue::Object(relative_to_obj) => JsValue::from(relative_to_obj), JsValue::Object(relative_to_obj) => JsValue::from(relative_to_obj),
@ -297,13 +296,13 @@ pub(crate) fn is_partial_temporal_object<'value>(
} }
// 3. Let calendarProperty be ? Get(value, "calendar"). // 3. Let calendarProperty be ? Get(value, "calendar").
let calendar_property = obj.get(js_str!("calendar"), context)?; let calendar_property = obj.get(js_string!("calendar"), context)?;
// 4. If calendarProperty is not undefined, return false. // 4. If calendarProperty is not undefined, return false.
if !calendar_property.is_undefined() { if !calendar_property.is_undefined() {
return Ok(None); return Ok(None);
} }
// 5. Let timeZoneProperty be ? Get(value, "timeZone"). // 5. Let timeZoneProperty be ? Get(value, "timeZone").
let time_zone_property = obj.get(js_str!("timeZone"), context)?; let time_zone_property = obj.get(js_string!("timeZone"), context)?;
// 6. If timeZoneProperty is not undefined, return false. // 6. If timeZoneProperty is not undefined, return false.
if !time_zone_property.is_undefined() { if !time_zone_property.is_undefined() {
return Ok(None); return Ok(None);

16
core/engine/src/builtins/temporal/options.rs

@ -10,10 +10,8 @@
use crate::{ use crate::{
builtins::options::{get_option, OptionType, ParsableOptionType}, builtins::options::{get_option, OptionType, ParsableOptionType},
string::JsStr, js_string, Context, JsNativeError, JsObject, JsResult, JsString, JsValue,
Context, JsNativeError, JsObject, JsResult, JsValue,
}; };
use boa_macros::js_str;
use temporal_rs::options::{ use temporal_rs::options::{
ArithmeticOverflow, CalendarName, DifferenceSettings, DurationOverflow, InstantDisambiguation, ArithmeticOverflow, CalendarName, DifferenceSettings, DurationOverflow, InstantDisambiguation,
OffsetDisambiguation, RoundingIncrement, TemporalRoundingMode, TemporalUnit, OffsetDisambiguation, RoundingIncrement, TemporalRoundingMode, TemporalUnit,
@ -25,7 +23,7 @@ use temporal_rs::options::{
#[inline] #[inline]
pub(crate) fn get_temporal_unit( pub(crate) fn get_temporal_unit(
options: &JsObject, options: &JsObject,
key: JsStr<'_>, key: JsString,
unit_group: TemporalUnitGroup, unit_group: TemporalUnitGroup,
extra_values: Option<Vec<TemporalUnit>>, extra_values: Option<Vec<TemporalUnit>>,
context: &mut Context, context: &mut Context,
@ -53,12 +51,14 @@ pub(crate) fn get_difference_settings(
context: &mut Context, context: &mut Context,
) -> JsResult<DifferenceSettings> { ) -> JsResult<DifferenceSettings> {
let mut settings = DifferenceSettings::default(); let mut settings = DifferenceSettings::default();
settings.largest_unit = get_option::<TemporalUnit>(options, js_str!("largestUnit"), context)?; settings.largest_unit =
get_option::<TemporalUnit>(options, js_string!("largestUnit"), context)?;
settings.increment = settings.increment =
get_option::<RoundingIncrement>(options, js_str!("roundingIncrement"), context)?; get_option::<RoundingIncrement>(options, js_string!("roundingIncrement"), context)?;
settings.rounding_mode = settings.rounding_mode =
get_option::<TemporalRoundingMode>(options, js_str!("roundingMode"), context)?; get_option::<TemporalRoundingMode>(options, js_string!("roundingMode"), context)?;
settings.smallest_unit = get_option::<TemporalUnit>(options, js_str!("smallestUnit"), context)?; settings.smallest_unit =
get_option::<TemporalUnit>(options, js_string!("smallestUnit"), context)?;
Ok(settings) Ok(settings)
} }

41
core/engine/src/builtins/temporal/plain_date/mod.rs

@ -20,7 +20,6 @@ use crate::{
JsValue, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use temporal_rs::{ use temporal_rs::{
components::{ components::{
@ -504,7 +503,7 @@ impl PlainDate {
if let Some(date) = item.as_object().and_then(JsObject::downcast_ref::<Self>) { if let Some(date) = item.as_object().and_then(JsObject::downcast_ref::<Self>) {
let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?; let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?;
let _ = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let _ = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
return create_temporal_date(date.inner.clone(), None, context).map(Into::into); return create_temporal_date(date.inner.clone(), None, context).map(Into::into);
} }
@ -555,20 +554,28 @@ impl PlainDate {
// 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar", temporalDate.[[Calendar]]). // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar", temporalDate.[[Calendar]]).
fields.create_data_property_or_throw( fields.create_data_property_or_throw(
js_str!("calendar"), js_string!("calendar"),
JsString::from(date.inner.calendar().identifier()), JsString::from(date.inner.calendar().identifier()),
context, context,
)?; )?;
// 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay", 𝔽(temporalDate.[[ISODay]])). // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay", 𝔽(temporalDate.[[ISODay]])).
fields.create_data_property_or_throw(js_str!("isoDay"), date.inner.iso_day(), context)?; fields.create_data_property_or_throw(
js_string!("isoDay"),
date.inner.iso_day(),
context,
)?;
// 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth", 𝔽(temporalDate.[[ISOMonth]])). // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth", 𝔽(temporalDate.[[ISOMonth]])).
fields.create_data_property_or_throw( fields.create_data_property_or_throw(
js_str!("isoMonth"), js_string!("isoMonth"),
date.inner.iso_month(), date.inner.iso_month(),
context, context,
)?; )?;
// 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear", 𝔽(temporalDate.[[ISOYear]])). // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear", 𝔽(temporalDate.[[ISOYear]])).
fields.create_data_property_or_throw(js_str!("isoYear"), date.inner.iso_year(), context)?; fields.create_data_property_or_throw(
js_string!("isoYear"),
date.inner.iso_year(),
context,
)?;
// 8. Return fields. // 8. Return fields.
Ok(fields.into()) Ok(fields.into())
} }
@ -589,7 +596,7 @@ impl PlainDate {
// 4. Set options to ? GetOptionsObject(options). // 4. Set options to ? GetOptionsObject(options).
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »).
// 6. Return ? AddDate(calendarRec, temporalDate, duration, options). // 6. Return ? AddDate(calendarRec, temporalDate, duration, options).
@ -611,7 +618,7 @@ impl PlainDate {
// 4. Set options to ? GetOptionsObject(options). // 4. Set options to ? GetOptionsObject(options).
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// 5. Let negatedDuration be CreateNegatedTemporalDuration(duration). // 5. Let negatedDuration be CreateNegatedTemporalDuration(duration).
// 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »).
@ -648,7 +655,7 @@ impl PlainDate {
// 7. Let partialDate be ? PrepareTemporalFields(temporalDateLike, fieldsResult.[[FieldNames]], partial). // 7. Let partialDate be ? PrepareTemporalFields(temporalDateLike, fieldsResult.[[FieldNames]], partial).
// 8. Let fields be ? CalendarMergeFields(calendarRec, fieldsResult.[[Fields]], partialDate). // 8. Let fields be ? CalendarMergeFields(calendarRec, fieldsResult.[[Fields]], partialDate).
// 9. Set fields to ? PrepareTemporalFields(fields, fieldsResult.[[FieldNames]], «»). // 9. Set fields to ? PrepareTemporalFields(fields, fieldsResult.[[FieldNames]], «»).
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
let partial = to_partial_date_record(partial_object, context)?; let partial = to_partial_date_record(partial_object, context)?;
// 10. Return ? CalendarDateFromFields(calendarRec, fields, resolvedOptions). // 10. Return ? CalendarDateFromFields(calendarRec, fields, resolvedOptions).
@ -833,7 +840,7 @@ pub(crate) fn to_temporal_date(
// c. If item has an [[InitializedTemporalDateTime]] internal slot, then // c. If item has an [[InitializedTemporalDateTime]] internal slot, then
} else if let Some(date_time) = object.downcast_ref::<PlainDateTime>() { } else if let Some(date_time) = object.downcast_ref::<PlainDateTime>() {
// i. Perform ? ToTemporalOverflow(options). // i. Perform ? ToTemporalOverflow(options).
let _o = get_option(&options_obj, js_str!("overflow"), context)? let _o = get_option(&options_obj, js_string!("overflow"), context)?
.unwrap_or(ArithmeticOverflow::Constrain); .unwrap_or(ArithmeticOverflow::Constrain);
let date = InnerDate::from(date_time.inner().clone()); let date = InnerDate::from(date_time.inner().clone());
@ -845,7 +852,7 @@ pub(crate) fn to_temporal_date(
// d. Let calendar be ? GetTemporalCalendarSlotValueWithISODefault(item). // d. Let calendar be ? GetTemporalCalendarSlotValueWithISODefault(item).
let calendar = get_temporal_calendar_slot_value_with_default(object, context)?; let calendar = get_temporal_calendar_slot_value_with_default(object, context)?;
let overflow = let overflow =
get_option::<ArithmeticOverflow>(&options_obj, js_str!("overflow"), context)? get_option::<ArithmeticOverflow>(&options_obj, js_string!("overflow"), context)?
.unwrap_or(ArithmeticOverflow::Constrain); .unwrap_or(ArithmeticOverflow::Constrain);
// e. Let fieldNames be ? CalendarFields(calendar, « "day", "month", "monthCode", "year" »). // e. Let fieldNames be ? CalendarFields(calendar, « "day", "month", "monthCode", "year" »).
@ -896,15 +903,15 @@ pub(crate) fn to_partial_date_record(
context: &mut Context, context: &mut Context,
) -> JsResult<PartialDate> { ) -> JsResult<PartialDate> {
let day = partial_object let day = partial_object
.get(js_str!("day"), context)? .get(js_string!("day"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let month = partial_object let month = partial_object
.get(js_str!("month"), context)? .get(js_string!("month"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let month_code = partial_object let month_code = partial_object
.get(js_str!("monthCode"), context)? .get(js_string!("monthCode"), context)?
.map(|v| { .map(|v| {
let JsValue::String(month_code) = let JsValue::String(month_code) =
v.to_primitive(context, crate::value::PreferredType::String)? v.to_primitive(context, crate::value::PreferredType::String)?
@ -917,15 +924,15 @@ pub(crate) fn to_partial_date_record(
}) })
.transpose()?; .transpose()?;
let year = partial_object let year = partial_object
.get(js_str!("year"), context)? .get(js_string!("year"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let era_year = partial_object let era_year = partial_object
.get(js_str!("eraYear"), context)? .get(js_string!("eraYear"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let era = partial_object let era = partial_object
.get(js_str!("era"), context)? .get(js_string!("era"), context)?
.map(|v| { .map(|v| {
let JsValue::String(era) = let JsValue::String(era) =
v.to_primitive(context, crate::value::PreferredType::String)? v.to_primitive(context, crate::value::PreferredType::String)?

70
core/engine/src/builtins/temporal/plain_date_time/mod.rs

@ -16,7 +16,6 @@ use crate::{
Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
#[cfg(test)] #[cfg(test)]
@ -163,116 +162,121 @@ impl IntrinsicObject for PlainDateTime {
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("calendarId"), js_string!("calendarId"),
Some(get_calendar_id), Some(get_calendar_id),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("year"), js_string!("year"),
Some(get_year), Some(get_year),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("month"), js_string!("month"),
Some(get_month), Some(get_month),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("monthCode"), js_string!("monthCode"),
Some(get_month_code), Some(get_month_code),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor(js_str!("day"), Some(get_day), None, Attribute::CONFIGURABLE)
.accessor( .accessor(
js_str!("hour"), js_string!("day"),
Some(get_day),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("hour"),
Some(get_hour), Some(get_hour),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("minute"), js_string!("minute"),
Some(get_minute), Some(get_minute),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("second"), js_string!("second"),
Some(get_second), Some(get_second),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("millisecond"), js_string!("millisecond"),
Some(get_millisecond), Some(get_millisecond),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("microsecond"), js_string!("microsecond"),
Some(get_microsecond), Some(get_microsecond),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("nanosecond"), js_string!("nanosecond"),
Some(get_nanosecond), Some(get_nanosecond),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("dayOfWeek"), js_string!("dayOfWeek"),
Some(get_day_of_week), Some(get_day_of_week),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("dayOfYear"), js_string!("dayOfYear"),
Some(get_day_of_year), Some(get_day_of_year),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("weekOfYear"), js_string!("weekOfYear"),
Some(get_week_of_year), Some(get_week_of_year),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("yearOfWeek"), js_string!("yearOfWeek"),
Some(get_year_of_week), Some(get_year_of_week),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("daysInWeek"), js_string!("daysInWeek"),
Some(get_days_in_week), Some(get_days_in_week),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("daysInMonth"), js_string!("daysInMonth"),
Some(get_days_in_month), Some(get_days_in_month),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("daysInYear"), js_string!("daysInYear"),
Some(get_days_in_year), Some(get_days_in_year),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("monthsInYear"), js_string!("monthsInYear"),
Some(get_months_in_year), Some(get_months_in_year),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.accessor( .accessor(
js_str!("inLeapYear"), js_string!("inLeapYear"),
Some(get_in_leap_year), Some(get_in_leap_year),
None, None,
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
@ -650,7 +654,7 @@ impl PlainDateTime {
let dt = if let Some(pdt) = item.as_object().and_then(JsObject::downcast_ref::<Self>) { let dt = if let Some(pdt) = item.as_object().and_then(JsObject::downcast_ref::<Self>) {
// a. Perform ? GetTemporalOverflowOption(options). // a. Perform ? GetTemporalOverflowOption(options).
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let _ = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let _ = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// b. Return ! CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], // b. Return ! CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]],
// item.[[ISODay]], item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]], // item.[[ISODay]], item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]],
// item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]], // item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]],
@ -706,7 +710,7 @@ impl PlainDateTime {
let partial_dt = PartialDateTime { date, time }; let partial_dt = PartialDateTime { date, time };
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
create_temporal_datetime(dt.inner.with(partial_dt, overflow)?, None, context) create_temporal_datetime(dt.inner.with(partial_dt, overflow)?, None, context)
.map(Into::into) .map(Into::into)
@ -760,7 +764,7 @@ impl PlainDateTime {
// 4. Set options to ? GetOptionsObject(options). // 4. Set options to ? GetOptionsObject(options).
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »).
// 6. Return ? AddDate(calendarRec, temporalDate, duration, options). // 6. Return ? AddDate(calendarRec, temporalDate, duration, options).
@ -783,7 +787,7 @@ impl PlainDateTime {
// 4. Set options to ? GetOptionsObject(options). // 4. Set options to ? GetOptionsObject(options).
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// 5. Let negatedDuration be CreateNegatedTemporalDuration(duration). // 5. Let negatedDuration be CreateNegatedTemporalDuration(duration).
// 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »).
@ -851,7 +855,7 @@ impl PlainDateTime {
let new_round_to = JsObject::with_null_proto(); let new_round_to = JsObject::with_null_proto();
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
new_round_to.create_data_property_or_throw( new_round_to.create_data_property_or_throw(
js_str!("smallestUnit"), js_string!("smallestUnit"),
param_string, param_string,
context, context,
)?; )?;
@ -870,16 +874,16 @@ impl PlainDateTime {
let mut options = RoundingOptions::default(); let mut options = RoundingOptions::default();
options.increment = options.increment =
get_option::<RoundingIncrement>(&round_to, js_str!("roundingIncrement"), context)?; get_option::<RoundingIncrement>(&round_to, js_string!("roundingIncrement"), context)?;
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). // 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
options.rounding_mode = options.rounding_mode =
get_option::<TemporalRoundingMode>(&round_to, js_str!("roundingMode"), context)?; get_option::<TemporalRoundingMode>(&round_to, js_string!("roundingMode"), context)?;
// 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", TIME, REQUIRED, undefined). // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", TIME, REQUIRED, undefined).
options.smallest_unit = get_temporal_unit( options.smallest_unit = get_temporal_unit(
&round_to, &round_to,
js_str!("smallestUnit"), js_string!("smallestUnit"),
TemporalUnitGroup::Time, TemporalUnitGroup::Time,
None, None,
context, context,
@ -983,7 +987,7 @@ pub(crate) fn to_temporal_datetime(
// b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
} else if let Some(_zdt) = object.downcast_ref::<ZonedDateTime>() { } else if let Some(_zdt) = object.downcast_ref::<ZonedDateTime>() {
// i. Perform ? GetTemporalOverflowOption(resolvedOptions). // i. Perform ? GetTemporalOverflowOption(resolvedOptions).
let _ = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let _ = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]). // ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
// iii. Let timeZoneRec be ? CreateTimeZoneMethodsRecord(item.[[TimeZone]], « get-offset-nanoseconds-for »). // iii. Let timeZoneRec be ? CreateTimeZoneMethodsRecord(item.[[TimeZone]], « get-offset-nanoseconds-for »).
// iv. Return ? GetPlainDateTimeFor(timeZoneRec, instant, item.[[Calendar]]). // iv. Return ? GetPlainDateTimeFor(timeZoneRec, instant, item.[[Calendar]]).
@ -993,7 +997,7 @@ pub(crate) fn to_temporal_datetime(
// c. If item has an [[InitializedTemporalDate]] internal slot, then // c. If item has an [[InitializedTemporalDate]] internal slot, then
} else if let Some(date) = object.downcast_ref::<PlainDate>() { } else if let Some(date) = object.downcast_ref::<PlainDate>() {
// i. Perform ? GetTemporalOverflowOption(resolvedOptions). // i. Perform ? GetTemporalOverflowOption(resolvedOptions).
let _ = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let _ = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// ii. Return ? CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], 0, 0, 0, 0, 0, 0, item.[[Calendar]]). // ii. Return ? CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], 0, 0, 0, 0, 0, 0, item.[[Calendar]]).
return Ok(InnerDateTime::new( return Ok(InnerDateTime::new(
date.inner.iso_year(), date.inner.iso_year(),
@ -1029,7 +1033,7 @@ pub(crate) fn to_temporal_datetime(
.into()); .into());
} }
// g. Let result be ? InterpretTemporalDateTimeFields(calendarRec, fields, resolvedOptions). // g. Let result be ? InterpretTemporalDateTimeFields(calendarRec, fields, resolvedOptions).
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
let date = calendar.date_from_fields( let date = calendar.date_from_fields(
&mut TemporalFields::from(partial_date), &mut TemporalFields::from(partial_date),
overflow.unwrap_or(ArithmeticOverflow::Constrain), overflow.unwrap_or(ArithmeticOverflow::Constrain),
@ -1075,7 +1079,7 @@ pub(crate) fn to_temporal_datetime(
// h. Set calendar to CanonicalizeUValue("ca", calendar). // h. Set calendar to CanonicalizeUValue("ca", calendar).
let date = string.to_std_string_escaped().parse::<InnerDateTime>()?; let date = string.to_std_string_escaped().parse::<InnerDateTime>()?;
// i. Perform ? GetTemporalOverflowOption(resolvedOptions). // i. Perform ? GetTemporalOverflowOption(resolvedOptions).
let _ = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let _ = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
// 5. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], // 5. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]],
// result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], // result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]],
// result.[[Microsecond]], result.[[Nanosecond]], calendar). // result.[[Microsecond]], result.[[Nanosecond]], calendar).

14
core/engine/src/builtins/temporal/plain_month_day/mod.rs

@ -16,7 +16,6 @@ use crate::{
Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use temporal_rs::{ use temporal_rs::{
@ -112,8 +111,9 @@ impl PlainMonthDay {
let options = get_options_object(args.get_or_undefined(0))?; let options = get_options_object(args.get_or_undefined(0))?;
// 4. Let showCalendar be ? ToShowCalendarOption(options). // 4. Let showCalendar be ? ToShowCalendarOption(options).
// Get calendarName from the options object // Get calendarName from the options object
let show_calendar = get_option::<CalendarName>(&options, js_str!("calendarName"), context)? let show_calendar =
.unwrap_or(CalendarName::Auto); get_option::<CalendarName>(&options, js_string!("calendarName"), context)?
.unwrap_or(CalendarName::Auto);
Ok(month_day_to_string(inner, show_calendar)) Ok(month_day_to_string(inner, show_calendar))
} }
@ -286,11 +286,11 @@ fn to_temporal_month_day(
options: &JsObject, options: &JsObject,
context: &mut Context, context: &mut Context,
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
let overflow = get_option::<ArithmeticOverflow>(options, js_str!("overflow"), context)? let overflow = get_option::<ArithmeticOverflow>(options, js_string!("overflow"), context)?
.unwrap_or(ArithmeticOverflow::Constrain); .unwrap_or(ArithmeticOverflow::Constrain);
// get the calendar property (string) from the item object // get the calendar property (string) from the item object
let calender_id = item.get_v(js_str!("calendar"), context)?; let calender_id = item.get_v(js_string!("calendar"), context)?;
let calendar = to_temporal_calendar_slot_value(&calender_id)?; let calendar = to_temporal_calendar_slot_value(&calender_id)?;
let inner = if let Some(item_obj) = item let inner = if let Some(item_obj) = item
@ -302,11 +302,11 @@ fn to_temporal_month_day(
InnerMonthDay::from_str(item_string.to_std_string_escaped().as_str())? InnerMonthDay::from_str(item_string.to_std_string_escaped().as_str())?
} else if item.is_object() { } else if item.is_object() {
InnerMonthDay::new( InnerMonthDay::new(
item.get_v(js_str!("month"), context) item.get_v(js_string!("month"), context)
.expect("Month not found") .expect("Month not found")
.to_i32(context) .to_i32(context)
.expect("Cannot convert month to i32"), .expect("Cannot convert month to i32"),
item.get_v(js_str!("day"), context) item.get_v(js_string!("day"), context)
.expect("Day not found") .expect("Day not found")
.to_i32(context) .to_i32(context)
.expect("Cannot convert day to i32"), .expect("Cannot convert day to i32"),

45
core/engine/src/builtins/temporal/plain_time/mod.rs

@ -14,7 +14,6 @@ use crate::{
Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use temporal_rs::{ use temporal_rs::{
components::{PartialTime, Time}, components::{PartialTime, Time},
@ -304,7 +303,7 @@ impl PlainTime {
// 2. Let overflow be ? GetTemporalOverflowOption(options). // 2. Let overflow be ? GetTemporalOverflowOption(options).
let overflow = get_option::<ArithmeticOverflow>( let overflow = get_option::<ArithmeticOverflow>(
&get_options_object(args.get_or_undefined(1))?, &get_options_object(args.get_or_undefined(1))?,
js_str!("overflow"), js_string!("overflow"),
context, context,
)?; )?;
// 3. If item is an Object and item has an [[InitializedTemporalTime]] internal slot, then // 3. If item is an Object and item has an [[InitializedTemporalTime]] internal slot, then
@ -398,7 +397,7 @@ impl PlainTime {
}; };
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let overflow = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let overflow = get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
let partial = to_partial_time_record(partial_object, context)?; let partial = to_partial_time_record(partial_object, context)?;
create_temporal_time(time.inner.with(partial, overflow)?, None, context).map(Into::into) create_temporal_time(time.inner.with(partial, overflow)?, None, context).map(Into::into)
@ -468,7 +467,7 @@ impl PlainTime {
let new_round_to = JsObject::with_null_proto(); let new_round_to = JsObject::with_null_proto();
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
new_round_to.create_data_property_or_throw( new_round_to.create_data_property_or_throw(
js_str!("smallestUnit"), js_string!("smallestUnit"),
param_string, param_string,
context, context,
)?; )?;
@ -484,16 +483,16 @@ impl PlainTime {
// 6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode"). // 6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode").
// 7. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). // 7. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo).
let rounding_increment = let rounding_increment =
get_option::<f64>(&round_to, js_str!("roundingIncrement"), context)?; get_option::<f64>(&round_to, js_string!("roundingIncrement"), context)?;
// 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). // 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
let rounding_mode = let rounding_mode =
get_option::<TemporalRoundingMode>(&round_to, js_str!("roundingMode"), context)?; get_option::<TemporalRoundingMode>(&round_to, js_string!("roundingMode"), context)?;
// 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required). // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required).
let smallest_unit = get_temporal_unit( let smallest_unit = get_temporal_unit(
&round_to, &round_to,
js_str!("smallestUnit"), js_string!("smallestUnit"),
TemporalUnitGroup::Time, TemporalUnitGroup::Time,
None, None,
context, context,
@ -550,29 +549,37 @@ impl PlainTime {
let fields = JsObject::with_object_proto(context.intrinsics()); let fields = JsObject::with_object_proto(context.intrinsics());
// 4. Perform ! CreateDataPropertyOrThrow(fields, "isoHour", 𝔽(temporalTime.[[ISOHour]])). // 4. Perform ! CreateDataPropertyOrThrow(fields, "isoHour", 𝔽(temporalTime.[[ISOHour]])).
fields.create_data_property_or_throw(js_str!("isoHour"), time.inner.hour(), context)?; fields.create_data_property_or_throw(js_string!("isoHour"), time.inner.hour(), context)?;
// 5. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond", 𝔽(temporalTime.[[ISOMicrosecond]])). // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond", 𝔽(temporalTime.[[ISOMicrosecond]])).
fields.create_data_property_or_throw( fields.create_data_property_or_throw(
js_str!("isoMicrosecond"), js_string!("isoMicrosecond"),
time.inner.microsecond(), time.inner.microsecond(),
context, context,
)?; )?;
// 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond", 𝔽(temporalTime.[[ISOMillisecond]])). // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond", 𝔽(temporalTime.[[ISOMillisecond]])).
fields.create_data_property_or_throw( fields.create_data_property_or_throw(
js_str!("isoMillisecond"), js_string!("isoMillisecond"),
time.inner.millisecond(), time.inner.millisecond(),
context, context,
)?; )?;
// 7. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute", 𝔽(temporalTime.[[ISOMinute]])). // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute", 𝔽(temporalTime.[[ISOMinute]])).
fields.create_data_property_or_throw(js_str!("isoMinute"), time.inner.minute(), context)?; fields.create_data_property_or_throw(
js_string!("isoMinute"),
time.inner.minute(),
context,
)?;
// 8. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond", 𝔽(temporalTime.[[ISONanosecond]])). // 8. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond", 𝔽(temporalTime.[[ISONanosecond]])).
fields.create_data_property_or_throw( fields.create_data_property_or_throw(
js_str!("isoNanosecond"), js_string!("isoNanosecond"),
time.inner.nanosecond(), time.inner.nanosecond(),
context, context,
)?; )?;
// 9. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond", 𝔽(temporalTime.[[ISOSecond]])). // 9. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond", 𝔽(temporalTime.[[ISOSecond]])).
fields.create_data_property_or_throw(js_str!("isoSecond"), time.inner.second(), context)?; fields.create_data_property_or_throw(
js_string!("isoSecond"),
time.inner.second(),
context,
)?;
// 10. Return fields. // 10. Return fields.
Ok(fields.into()) Ok(fields.into())
@ -696,32 +703,32 @@ pub(crate) fn to_partial_time_record(
context: &mut Context, context: &mut Context,
) -> JsResult<PartialTime> { ) -> JsResult<PartialTime> {
let hour = partial_object let hour = partial_object
.get(js_str!("hour"), context)? .get(js_string!("hour"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let minute = partial_object let minute = partial_object
.get(js_str!("minute"), context)? .get(js_string!("minute"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let second = partial_object let second = partial_object
.get(js_str!("second"), context)? .get(js_string!("second"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let millisecond = partial_object let millisecond = partial_object
.get(js_str!("millisecond"), context)? .get(js_string!("millisecond"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let microsecond = partial_object let microsecond = partial_object
.get(js_str!("microsecond"), context)? .get(js_string!("microsecond"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;
let nanosecond = partial_object let nanosecond = partial_object
.get(js_str!("nanosecond"), context)? .get(js_string!("nanosecond"), context)?
.map(|v| super::to_integer_if_integral(v, context)) .map(|v| super::to_integer_if_integral(v, context))
.transpose()?; .transpose()?;

21
core/engine/src/builtins/temporal/plain_year_month/mod.rs

@ -16,7 +16,6 @@ use crate::{
Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use temporal_rs::{ use temporal_rs::{
@ -226,26 +225,27 @@ impl PlainYearMonth {
{ {
// Perform ? [GetTemporalOverflowOption](https://tc39.es/proposal-temporal/#sec-temporal-gettemporaloverflowoption)(options). // Perform ? [GetTemporalOverflowOption](https://tc39.es/proposal-temporal/#sec-temporal-gettemporaloverflowoption)(options).
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let _ = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?; let _ =
get_option::<ArithmeticOverflow>(&options, js_string!("overflow"), context)?;
data.inner.clone() data.inner.clone()
} else { } else {
let options = get_options_object(args.get_or_undefined(1))?; let options = get_options_object(args.get_or_undefined(1))?;
let overflow = get_option(&options, js_str!("overflow"), context)? let overflow = get_option(&options, js_string!("overflow"), context)?
.unwrap_or(ArithmeticOverflow::Constrain); .unwrap_or(ArithmeticOverflow::Constrain);
// a. Let calendar be ? ToTemporalCalendar(item). // a. Let calendar be ? ToTemporalCalendar(item).
let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(1))?; let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(1))?;
InnerYearMonth::new( InnerYearMonth::new(
super::to_integer_with_truncation( super::to_integer_with_truncation(
&item.get_v(js_str!("year"), context)?, &item.get_v(js_string!("year"), context)?,
context, context,
)?, )?,
super::to_integer_with_truncation( super::to_integer_with_truncation(
&item.get_v(js_str!("month"), context)?, &item.get_v(js_string!("month"), context)?,
context, context,
)?, )?,
super::to_integer_with_truncation( super::to_integer_with_truncation(
&item.get_v(js_str!("day"), context)?, &item.get_v(js_string!("day"), context)?,
context, context,
) )
.ok(), .ok(),
@ -414,8 +414,9 @@ impl PlainYearMonth {
let options = get_options_object(args.get_or_undefined(0))?; let options = get_options_object(args.get_or_undefined(0))?;
// 4. Let showCalendar be ? ToShowCalendarOption(options). // 4. Let showCalendar be ? ToShowCalendarOption(options).
// Get calendarName from the options object // Get calendarName from the options object
let show_calendar = get_option::<CalendarName>(&options, js_str!("calendarName"), context)? let show_calendar =
.unwrap_or(CalendarName::Auto); get_option::<CalendarName>(&options, js_string!("calendarName"), context)?
.unwrap_or(CalendarName::Auto);
Ok(year_month_to_string(inner, show_calendar)) Ok(year_month_to_string(inner, show_calendar))
} }
@ -484,8 +485,8 @@ fn add_or_subtract_duration(
.into()); .into());
}; };
let overflow = let overflow = get_option(options, js_string!("overflow"), context)?
get_option(options, js_str!("overflow"), context)?.unwrap_or(ArithmeticOverflow::Constrain); .unwrap_or(ArithmeticOverflow::Constrain);
let year_month = this let year_month = this
.as_object() .as_object()

4
core/engine/src/builtins/typed_array/builtin.rs

@ -3,7 +3,7 @@ use std::{
sync::atomic::Ordering, sync::atomic::Ordering,
}; };
use boa_macros::{js_str, utf16}; use boa_macros::utf16;
use num_traits::Zero; use num_traits::Zero;
use super::{ use super::{
@ -2484,7 +2484,7 @@ impl BuiltinTypedArray {
if is_fixed_len || !next_element.is_undefined() { if is_fixed_len || !next_element.is_undefined() {
let s = next_element let s = next_element
.invoke( .invoke(
js_str!("toLocaleString"), js_string!("toLocaleString"),
&[ &[
args.get_or_undefined(0).clone(), args.get_or_undefined(0).clone(),
args.get_or_undefined(1).clone(), args.get_or_undefined(1).clone(),

5
core/engine/src/builtins/typed_array/mod.rs

@ -26,7 +26,6 @@ use crate::{
Context, JsArgs, JsResult, JsString, Context, JsArgs, JsResult, JsString,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
mod builtin; mod builtin;
@ -72,12 +71,12 @@ impl<T: TypedArrayMarker> IntrinsicObject for T {
Attribute::CONFIGURABLE, Attribute::CONFIGURABLE,
) )
.property( .property(
js_str!("BYTES_PER_ELEMENT"), js_string!("BYTES_PER_ELEMENT"),
size_of::<T::Element>(), size_of::<T::Element>(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
) )
.static_property( .static_property(
js_str!("BYTES_PER_ELEMENT"), js_string!("BYTES_PER_ELEMENT"),
size_of::<T::Element>(), size_of::<T::Element>(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
) )

3
core/engine/src/builtins/weak_map/mod.rs

@ -22,7 +22,6 @@ use crate::{
Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
type NativeWeakMap = boa_gc::WeakMap<ErasedVTableObject, JsValue>; type NativeWeakMap = boa_gc::WeakMap<ErasedVTableObject, JsValue>;
@ -105,7 +104,7 @@ impl BuiltInConstructor for WeakMap {
// 5. Let adder be ? Get(map, "set"). // 5. Let adder be ? Get(map, "set").
// 6. If IsCallable(adder) is false, throw a TypeError exception. // 6. If IsCallable(adder) is false, throw a TypeError exception.
let adder = map let adder = map
.get(js_str!("set"), context)? .get(js_string!("set"), context)?
.as_function() .as_function()
.ok_or_else(|| JsNativeError::typ().with_message("WeakMap: 'add' is not a function"))?; .ok_or_else(|| JsNativeError::typ().with_message("WeakMap: 'add' is not a function"))?;

3
core/engine/src/builtins/weak_set/mod.rs

@ -19,7 +19,6 @@ use crate::{
Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use super::iterable::IteratorHint; use super::iterable::IteratorHint;
@ -101,7 +100,7 @@ impl BuiltInConstructor for WeakSet {
} }
// 5. Let adder be ? Get(set, "add"). // 5. Let adder be ? Get(set, "add").
let adder = weak_set.get(js_str!("add"), context)?; let adder = weak_set.get(js_string!("add"), context)?;
// 6. If IsCallable(adder) is false, throw a TypeError exception. // 6. If IsCallable(adder) is false, throw a TypeError exception.
let adder = adder let adder = adder

8
core/engine/src/class.rs

@ -56,7 +56,7 @@
//! let age = args.get_or_undefined(1).to_number(context)?; //! let age = args.get_or_undefined(1).to_number(context)?;
//! //!
//! // Roughly equivalent to `this.age = Number(age)`. //! // Roughly equivalent to `this.age = Number(age)`.
//! instance.set(js_str!("age"), age, true, context)?; //! instance.set(js_string!("age"), age, true, context)?;
//! //!
//! Ok(()) //! Ok(())
//! } //! }
@ -70,9 +70,9 @@
//! if let Some(object) = this.as_object() { //! if let Some(object) = this.as_object() {
//! if let Some(animal) = object.downcast_ref::<Animal>() { //! if let Some(animal) = object.downcast_ref::<Animal>() {
//! return Ok(match &*animal { //! return Ok(match &*animal {
//! Self::Cat => js_str!("meow"), //! Self::Cat => js_string!("meow"),
//! Self::Dog => js_str!("woof"), //! Self::Dog => js_string!("woof"),
//! Self::Other => js_str!(r"¯\_(ツ)_/¯"), //! Self::Other => js_string!(r"¯\_(ツ)_/¯"),
//! }.into()); //! }.into());
//! } //! }
//! } //! }

19
core/engine/src/context/intrinsics.rs

@ -1,7 +1,6 @@
//! Data structures that contain intrinsic objects and constructors. //! Data structures that contain intrinsic objects and constructors.
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use crate::{ use crate::{
builtins::{iterable::IteratorPrototypes, uri::UriFunctions, Array, OrdinaryObject}, builtins::{iterable::IteratorPrototypes, uri::UriFunctions, Array, OrdinaryObject},
@ -1395,7 +1394,7 @@ impl ObjectTemplates {
let ordinary_object = let ordinary_object =
ObjectTemplate::with_prototype(root_shape, constructors.object().prototype()); ObjectTemplate::with_prototype(root_shape, constructors.object().prototype());
let mut array = ObjectTemplate::new(root_shape); let mut array = ObjectTemplate::new(root_shape);
let length_property_key: PropertyKey = js_str!("length").into(); let length_property_key: PropertyKey = js_string!("length").into();
array.property( array.property(
length_property_key.clone(), length_property_key.clone(),
Attribute::WRITABLE | Attribute::PERMANENT | Attribute::NON_ENUMERABLE, Attribute::WRITABLE | Attribute::PERMANENT | Attribute::NON_ENUMERABLE,
@ -1420,7 +1419,7 @@ impl ObjectTemplates {
let mut regexp = regexp_without_proto.clone(); let mut regexp = regexp_without_proto.clone();
regexp.set_prototype(constructors.regexp().prototype()); regexp.set_prototype(constructors.regexp().prototype());
let name_property_key: PropertyKey = js_str!("name").into(); let name_property_key: PropertyKey = js_string!("name").into();
let mut function = ObjectTemplate::new(root_shape); let mut function = ObjectTemplate::new(root_shape);
function.property( function.property(
length_property_key.clone(), length_property_key.clone(),
@ -1479,7 +1478,7 @@ impl ObjectTemplates {
// [[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, // [[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false,
// [[Configurable]]: false }). // [[Configurable]]: false }).
unmapped_arguments.accessor( unmapped_arguments.accessor(
js_str!("callee").into(), js_string!("callee").into(),
true, true,
true, true,
Attribute::NON_ENUMERABLE | Attribute::PERMANENT, Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
@ -1488,17 +1487,17 @@ impl ObjectTemplates {
// 21. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { // 21. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor {
// [[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }). // [[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
mapped_arguments.property( mapped_arguments.property(
js_str!("callee").into(), js_string!("callee").into(),
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
); );
let mut iterator_result = ordinary_object.clone(); let mut iterator_result = ordinary_object.clone();
iterator_result.property( iterator_result.property(
js_str!("value").into(), js_string!("value").into(),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::ENUMERABLE, Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::ENUMERABLE,
); );
iterator_result.property( iterator_result.property(
js_str!("done").into(), js_string!("done").into(),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::ENUMERABLE, Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::ENUMERABLE,
); );
@ -1510,11 +1509,11 @@ impl ObjectTemplates {
with_resolvers with_resolvers
// 4. Perform ! CreateDataPropertyOrThrow(obj, "promise", promiseCapability.[[Promise]]). // 4. Perform ! CreateDataPropertyOrThrow(obj, "promise", promiseCapability.[[Promise]]).
.property(js_str!("promise").into(), Attribute::all()) .property(js_string!("promise").into(), Attribute::all())
// 5. Perform ! CreateDataPropertyOrThrow(obj, "resolve", promiseCapability.[[Resolve]]). // 5. Perform ! CreateDataPropertyOrThrow(obj, "resolve", promiseCapability.[[Resolve]]).
.property(js_str!("resolve").into(), Attribute::all()) .property(js_string!("resolve").into(), Attribute::all())
// 6. Perform ! CreateDataPropertyOrThrow(obj, "reject", promiseCapability.[[Reject]]). // 6. Perform ! CreateDataPropertyOrThrow(obj, "reject", promiseCapability.[[Reject]]).
.property(js_str!("reject").into(), Attribute::all()); .property(js_string!("reject").into(), Attribute::all());
with_resolvers with_resolvers
}; };

16
core/engine/src/context/mod.rs

@ -51,7 +51,7 @@ thread_local! {
/// ///
/// ```rust /// ```rust
/// use boa_engine::{ /// use boa_engine::{
/// js_str, /// js_string,
/// object::ObjectInitializer, /// object::ObjectInitializer,
/// property::{Attribute, PropertyDescriptor}, /// property::{Attribute, PropertyDescriptor},
/// Context, Source, /// Context, Source,
@ -73,10 +73,10 @@ thread_local! {
/// ///
/// // Create an object that can be used in eval calls. /// // Create an object that can be used in eval calls.
/// let arg = ObjectInitializer::new(&mut context) /// let arg = ObjectInitializer::new(&mut context)
/// .property(js_str!("x"), 12, Attribute::READONLY) /// .property(js_string!("x"), 12, Attribute::READONLY)
/// .build(); /// .build();
/// context /// context
/// .register_global_property(js_str!("arg"), arg, Attribute::all()) /// .register_global_property(js_string!("arg"), arg, Attribute::all())
/// .expect("property shouldn't exist"); /// .expect("property shouldn't exist");
/// ///
/// let value = context.eval(Source::from_bytes("test(arg)")).unwrap(); /// let value = context.eval(Source::from_bytes("test(arg)")).unwrap();
@ -211,7 +211,7 @@ impl Context {
/// # Example /// # Example
/// ``` /// ```
/// use boa_engine::{ /// use boa_engine::{
/// js_str, /// js_string,
/// object::ObjectInitializer, /// object::ObjectInitializer,
/// property::{Attribute, PropertyDescriptor}, /// property::{Attribute, PropertyDescriptor},
/// Context, /// Context,
@ -220,15 +220,15 @@ impl Context {
/// let mut context = Context::default(); /// let mut context = Context::default();
/// ///
/// context /// context
/// .register_global_property(js_str!("myPrimitiveProperty"), 10, Attribute::all()) /// .register_global_property(js_string!("myPrimitiveProperty"), 10, Attribute::all())
/// .expect("property shouldn't exist"); /// .expect("property shouldn't exist");
/// ///
/// let object = ObjectInitializer::new(&mut context) /// let object = ObjectInitializer::new(&mut context)
/// .property(js_str!("x"), 0, Attribute::all()) /// .property(js_string!("x"), 0, Attribute::all())
/// .property(js_str!("y"), 1, Attribute::all()) /// .property(js_string!("y"), 1, Attribute::all())
/// .build(); /// .build();
/// context /// context
/// .register_global_property(js_str!("myObjectProperty"), object, Attribute::all()) /// .register_global_property(js_string!("myObjectProperty"), object, Attribute::all())
/// .expect("property shouldn't exist"); /// .expect("property shouldn't exist");
/// ``` /// ```
pub fn register_global_property<K, V>( pub fn register_global_property<K, V>(

21
core/engine/src/error.rs

@ -9,7 +9,6 @@ use crate::{
Context, JsString, JsValue, Context, JsString, JsValue,
}; };
use boa_gc::{custom_trace, Finalize, Trace}; use boa_gc::{custom_trace, Finalize, Trace};
use boa_macros::js_str;
use std::{borrow::Cow, error, fmt}; use std::{borrow::Cow, error, fmt};
use thiserror::Error; use thiserror::Error;
@ -169,13 +168,13 @@ macro_rules! js_error {
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// # use boa_engine::{JsError, JsNativeError, JsNativeErrorKind, JsValue, js_str}; /// # use boa_engine::{JsError, JsNativeError, JsNativeErrorKind, JsValue, js_string};
/// let cause = JsError::from_opaque(js_str!("error!").into()); /// let cause = JsError::from_opaque(js_string!("error!").into());
/// ///
/// assert!(cause.as_opaque().is_some()); /// assert!(cause.as_opaque().is_some());
/// assert_eq!( /// assert_eq!(
/// cause.as_opaque().unwrap(), /// cause.as_opaque().unwrap(),
/// &JsValue::from(js_str!("error!")) /// &JsValue::from(js_string!("error!"))
/// ); /// );
/// ///
/// let native_error: JsError = JsNativeError::typ() /// let native_error: JsError = JsNativeError::typ()
@ -429,7 +428,7 @@ impl JsError {
ErrorObject::Syntax => JsNativeErrorKind::Syntax, ErrorObject::Syntax => JsNativeErrorKind::Syntax,
ErrorObject::Uri => JsNativeErrorKind::Uri, ErrorObject::Uri => JsNativeErrorKind::Uri,
ErrorObject::Aggregate => { ErrorObject::Aggregate => {
let errors = obj.get(js_str!("errors"), context).map_err(|e| { let errors = obj.get(js_string!("errors"), context).map_err(|e| {
TryNativeError::InaccessibleProperty { TryNativeError::InaccessibleProperty {
property: "errors", property: "errors",
source: e, source: e,
@ -1066,7 +1065,7 @@ impl JsNativeError {
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// # use boa_engine::{Context, JsError, JsNativeError, js_str}; /// # use boa_engine::{Context, JsError, JsNativeError, js_string};
/// # use boa_engine::builtins::error::ErrorObject; /// # use boa_engine::builtins::error::ErrorObject;
/// let context = &mut Context::default(); /// let context = &mut Context::default();
/// ///
@ -1075,8 +1074,8 @@ impl JsNativeError {
/// ///
/// assert!(error_obj.is::<ErrorObject>()); /// assert!(error_obj.is::<ErrorObject>());
/// assert_eq!( /// assert_eq!(
/// error_obj.get(js_str!("message"), context).unwrap(), /// error_obj.get(js_string!("message"), context).unwrap(),
/// js_str!("error!").into() /// js_string!("error!").into()
/// ) /// )
/// ``` /// ```
/// ///
@ -1129,14 +1128,14 @@ impl JsNativeError {
JsObject::from_proto_and_data_with_shared_shape(context.root_shape(), prototype, tag); JsObject::from_proto_and_data_with_shared_shape(context.root_shape(), prototype, tag);
o.create_non_enumerable_data_property_or_throw( o.create_non_enumerable_data_property_or_throw(
js_str!("message"), js_string!("message"),
js_string!(message.as_ref()), js_string!(message.as_ref()),
context, context,
); );
if let Some(cause) = cause { if let Some(cause) = cause {
o.create_non_enumerable_data_property_or_throw( o.create_non_enumerable_data_property_or_throw(
js_str!("cause"), js_string!("cause"),
cause.to_opaque(context), cause.to_opaque(context),
context, context,
); );
@ -1149,7 +1148,7 @@ impl JsNativeError {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let errors = Array::create_array_from_list(errors, context); let errors = Array::create_array_from_list(errors, context);
o.define_property_or_throw( o.define_property_or_throw(
js_str!("errors"), js_string!("errors"),
PropertyDescriptor::builder() PropertyDescriptor::builder()
.configurable(true) .configurable(true)
.enumerable(false) .enumerable(false)

6
core/engine/src/module/mod.rs

@ -36,7 +36,6 @@ use boa_interner::Interner;
use boa_parser::source::ReadChar; use boa_parser::source::ReadChar;
use boa_parser::{Parser, Source}; use boa_parser::{Parser, Source};
use boa_profiler::Profiler; use boa_profiler::Profiler;
use boa_string::JsStr;
pub use loader::*; pub use loader::*;
pub use namespace::ModuleNamespace; pub use namespace::ModuleNamespace;
use source::SourceTextModule; use source::SourceTextModule;
@ -625,16 +624,17 @@ impl Module {
/// Get an exported function, typed, from the module. /// Get an exported function, typed, from the module.
#[inline] #[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn get_typed_fn<A, R>( pub fn get_typed_fn<A, R>(
&self, &self,
name: JsStr<'_>, name: JsString,
context: &mut Context, context: &mut Context,
) -> JsResult<TypedJsFunction<A, R>> ) -> JsResult<TypedJsFunction<A, R>>
where where
A: crate::object::TryIntoJsArguments, A: crate::object::TryIntoJsArguments,
R: crate::value::TryFromJs, R: crate::value::TryFromJs,
{ {
let func = self.get_value(name, context)?; let func = self.get_value(name.clone(), context)?;
let func = func.as_function().ok_or_else(|| { let func = func.as_function().ok_or_else(|| {
JsNativeError::typ().with_message(format!("{name:?} is not a function")) JsNativeError::typ().with_message(format!("{name:?} is not a function"))
})?; })?;

4
core/engine/src/object/builtins/jsdate.rs

@ -14,7 +14,7 @@ use time::{format_description::well_known::Rfc3339, OffsetDateTime};
/// Create a `JsDate` object and set date to December 4 1995 /// Create a `JsDate` object and set date to December 4 1995
/// ///
/// ``` /// ```
/// use boa_engine::{js_str, object::builtins::JsDate, Context, JsResult, JsValue}; /// use boa_engine::{js_string, object::builtins::JsDate, Context, JsResult, JsValue};
/// ///
/// fn main() -> JsResult<()> { /// fn main() -> JsResult<()> {
/// // JS mutable Context /// // JS mutable Context
@ -26,7 +26,7 @@ use time::{format_description::well_known::Rfc3339, OffsetDateTime};
/// ///
/// assert_eq!( /// assert_eq!(
/// date.to_date_string(context)?, /// date.to_date_string(context)?,
/// JsValue::from(js_str!("Mon Dec 04 1995")) /// JsValue::from(js_string!("Mon Dec 04 1995"))
/// ); /// );
/// ///
/// Ok(()) /// Ok(())

64
core/engine/src/object/builtins/jsmap.rs

@ -6,13 +6,13 @@ use crate::{
Map, Map,
}, },
error::JsNativeError, error::JsNativeError,
js_string,
object::{JsFunction, JsMapIterator, JsObject}, object::{JsFunction, JsMapIterator, JsObject},
value::TryFromJs, value::TryFromJs,
Context, JsResult, JsValue, Context, JsResult, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use std::ops::Deref; use std::ops::Deref;
/// `JsMap` provides a wrapper for Boa's implementation of the ECMAScript `Map` object. /// `JsMap` provides a wrapper for Boa's implementation of the ECMAScript `Map` object.
@ -23,7 +23,7 @@ use std::ops::Deref;
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::JsMap, /// # object::builtins::JsMap,
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// // Create default `Context` /// // Create default `Context`
@ -33,8 +33,8 @@ use std::ops::Deref;
/// let map = JsMap::new(context); /// let map = JsMap::new(context);
/// ///
/// // Set key-value pairs for the `JsMap`. /// // Set key-value pairs for the `JsMap`.
/// map.set(js_str!("Key-1"), js_str!("Value-1"), context)?; /// map.set(js_string!("Key-1"), js_string!("Value-1"), context)?;
/// map.set(js_str!("Key-2"), 10, context)?; /// map.set(js_string!("Key-2"), 10, context)?;
/// ///
/// assert_eq!(map.get_size(context)?, 2.into()); /// assert_eq!(map.get_size(context)?, 2.into());
/// # Ok(()) /// # Ok(())
@ -45,7 +45,7 @@ use std::ops::Deref;
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::{JsArray, JsMap}, /// # object::builtins::{JsArray, JsMap},
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// // Create a default `Context` /// // Create a default `Context`
@ -56,8 +56,8 @@ use std::ops::Deref;
/// ///
/// // Create a `[key, value]` pair of JsValues /// // Create a `[key, value]` pair of JsValues
/// let vec_one: Vec<JsValue> = vec![ /// let vec_one: Vec<JsValue> = vec![
/// js_str!("first-key").into(), /// js_string!("first-key").into(),
/// js_str!("first-value").into() /// js_string!("first-value").into()
/// ]; /// ];
/// ///
/// // We create an push our `[key, value]` pair onto our array as a `JsArray` /// // We create an push our `[key, value]` pair onto our array as a `JsArray`
@ -67,8 +67,8 @@ use std::ops::Deref;
/// let js_iterable_map = JsMap::from_js_iterable(&js_array.into(), context)?; /// let js_iterable_map = JsMap::from_js_iterable(&js_array.into(), context)?;
/// ///
/// assert_eq!( /// assert_eq!(
/// js_iterable_map.get(js_str!("first-key"), context)?, /// js_iterable_map.get(js_string!("first-key"), context)?,
/// js_str!("first-value").into() /// js_string!("first-value").into()
/// ); /// );
/// ///
/// # Ok(()) /// # Ok(())
@ -105,7 +105,7 @@ impl JsMap {
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::{JsArray, JsMap}, /// # object::builtins::{JsArray, JsMap},
/// # Context, JsResult, JsValue, js_str /// # Context, JsResult, JsValue, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// # // Create a default `Context` /// # // Create a default `Context`
@ -114,7 +114,7 @@ impl JsMap {
/// let js_array = JsArray::new(context); /// let js_array = JsArray::new(context);
/// ///
/// // Create a `[key, value]` pair of JsValues and add it to the `JsArray` as a `JsArray` /// // Create a `[key, value]` pair of JsValues and add it to the `JsArray` as a `JsArray`
/// let vec_one: Vec<JsValue> = vec![js_str!("first-key").into(), js_str!("first-value").into()]; /// 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)?; /// js_array.push(JsArray::from_iter(vec_one, context), context)?;
/// ///
/// // Create a `JsMap` from the `JsArray` using it's iterable property. /// // Create a `JsMap` from the `JsArray` using it's iterable property.
@ -129,7 +129,7 @@ impl JsMap {
// Let adder be Get(map, "set") per spec. This action should not fail with default map. // Let adder be Get(map, "set") per spec. This action should not fail with default map.
let adder = map let adder = map
.get(js_str!("set"), context)? .get(js_string!("set"), context)?
.as_function() .as_function()
.ok_or_else(|| { .ok_or_else(|| {
JsNativeError::typ().with_message("property `set` on new `Map` must be callable") JsNativeError::typ().with_message("property `set` on new `Map` must be callable")
@ -226,16 +226,16 @@ impl JsMap {
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::JsMap, /// # object::builtins::JsMap,
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// # let context = &mut Context::default(); /// # let context = &mut Context::default();
/// let js_map = JsMap::new(context); /// let js_map = JsMap::new(context);
/// ///
/// js_map.set(js_str!("foo"), js_str!("bar"), context)?; /// js_map.set(js_string!("foo"), js_string!("bar"), context)?;
/// js_map.set(2, 4, context)?; /// js_map.set(2, 4, context)?;
/// ///
/// assert_eq!(js_map.get(js_str!("foo"), context)?, js_str!("bar").into()); /// assert_eq!(js_map.get(js_string!("foo"), context)?, js_string!("bar").into());
/// assert_eq!(js_map.get(2, context)?, 4.into()); /// assert_eq!(js_map.get(2, context)?, 4.into());
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -259,13 +259,13 @@ impl JsMap {
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::JsMap, /// # object::builtins::JsMap,
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// # let context = &mut Context::default(); /// # let context = &mut Context::default();
/// let js_map = JsMap::new(context); /// let js_map = JsMap::new(context);
/// ///
/// js_map.set(js_str!("foo"), js_str!("bar"), context)?; /// js_map.set(js_string!("foo"), js_string!("bar"), context)?;
/// ///
/// let map_size = js_map.get_size(context)?; /// let map_size = js_map.get_size(context)?;
/// ///
@ -285,18 +285,18 @@ impl JsMap {
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::JsMap, /// # object::builtins::JsMap,
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// # let context = &mut Context::default(); /// # let context = &mut Context::default();
/// let js_map = JsMap::new(context); /// let js_map = JsMap::new(context);
/// js_map.set(js_str!("foo"), js_str!("bar"), context)?; /// js_map.set(js_string!("foo"), js_string!("bar"), context)?;
/// js_map.set(js_str!("hello"), js_str!("world"), context)?; /// js_map.set(js_string!("hello"), js_string!("world"), context)?;
/// ///
/// js_map.delete(js_str!("foo"), context)?; /// js_map.delete(js_string!("foo"), context)?;
/// ///
/// assert_eq!(js_map.get_size(context)?, 1.into()); /// assert_eq!(js_map.get_size(context)?, 1.into());
/// assert_eq!(js_map.get(js_str!("foo"), context)?, JsValue::undefined()); /// assert_eq!(js_map.get(js_string!("foo"), context)?, JsValue::undefined());
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
@ -314,16 +314,16 @@ impl JsMap {
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::JsMap, /// # object::builtins::JsMap,
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// # let context = &mut Context::default(); /// # let context = &mut Context::default();
/// let js_map = JsMap::new(context); /// let js_map = JsMap::new(context);
/// js_map.set(js_str!("foo"), js_str!("bar"), context)?; /// js_map.set(js_string!("foo"), js_string!("bar"), context)?;
/// ///
/// let retrieved_value = js_map.get(js_str!("foo"), context)?; /// let retrieved_value = js_map.get(js_string!("foo"), context)?;
/// ///
/// assert_eq!(retrieved_value, js_str!("bar").into()); /// assert_eq!(retrieved_value, js_string!("bar").into());
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
@ -341,13 +341,13 @@ impl JsMap {
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::JsMap, /// # object::builtins::JsMap,
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// # let context = &mut Context::default(); /// # let context = &mut Context::default();
/// let js_map = JsMap::new(context); /// let js_map = JsMap::new(context);
/// js_map.set(js_str!("foo"), js_str!("bar"), context)?; /// js_map.set(js_string!("foo"), js_string!("bar"), context)?;
/// js_map.set(js_str!("hello"), js_str!("world"), context)?; /// js_map.set(js_string!("hello"), js_string!("world"), context)?;
/// ///
/// js_map.clear(context)?; /// js_map.clear(context)?;
/// ///
@ -367,14 +367,14 @@ impl JsMap {
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # object::builtins::JsMap, /// # object::builtins::JsMap,
/// # Context, JsValue, JsResult, js_str /// # Context, JsValue, JsResult, js_string
/// # }; /// # };
/// # fn main() -> JsResult<()> { /// # fn main() -> JsResult<()> {
/// # let context = &mut Context::default(); /// # let context = &mut Context::default();
/// let js_map = JsMap::new(context); /// let js_map = JsMap::new(context);
/// js_map.set(js_str!("foo"), js_str!("bar"), context)?; /// js_map.set(js_string!("foo"), js_string!("bar"), context)?;
/// ///
/// let has_key = js_map.has(js_str!("foo"), context)?; /// let has_key = js_map.has(js_string!("foo"), context)?;
/// ///
/// assert_eq!(has_key, true.into()); /// assert_eq!(has_key, true.into());
/// # Ok(()) /// # Ok(())

12
core/engine/src/object/builtins/jspromise.rs

@ -25,7 +25,7 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace};
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # builtins::promise::PromiseState, /// # builtins::promise::PromiseState,
/// # js_str, /// # js_string,
/// # object::{builtins::JsPromise, FunctionObjectBuilder}, /// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # property::Attribute, /// # property::Attribute,
/// # Context, JsArgs, JsError, JsValue, NativeFunction, /// # Context, JsArgs, JsError, JsValue, NativeFunction,
@ -34,11 +34,11 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace};
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let context = &mut Context::default(); /// let context = &mut Context::default();
/// ///
/// context.register_global_property(js_str!("finally"), false, Attribute::all()); /// context.register_global_property(js_string!("finally"), false, Attribute::all());
/// ///
/// let promise = JsPromise::new( /// let promise = JsPromise::new(
/// |resolvers, context| { /// |resolvers, context| {
/// let result = js_str!("hello world!").into(); /// let result = js_string!("hello world!").into();
/// resolvers /// resolvers
/// .resolve /// .resolve
/// .call(&JsValue::undefined(), &[result], context)?; /// .call(&JsValue::undefined(), &[result], context)?;
@ -66,7 +66,7 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace};
/// .finally( /// .finally(
/// NativeFunction::from_fn_ptr(|_, _, context| { /// NativeFunction::from_fn_ptr(|_, _, context| {
/// context.global_object().clone().set( /// context.global_object().clone().set(
/// js_str!("finally"), /// js_string!("finally"),
/// JsValue::from(true), /// JsValue::from(true),
/// true, /// true,
/// context, /// context,
@ -81,14 +81,14 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace};
/// ///
/// assert_eq!( /// assert_eq!(
/// promise.state(), /// promise.state(),
/// PromiseState::Fulfilled(js_str!("hello world!").into()) /// PromiseState::Fulfilled(js_string!("hello world!").into())
/// ); /// );
/// ///
/// assert_eq!( /// assert_eq!(
/// context /// context
/// .global_object() /// .global_object()
/// .clone() /// .clone()
/// .get(js_str!("finally"), context)?, /// .get(js_string!("finally"), context)?,
/// JsValue::from(true) /// JsValue::from(true)
/// ); /// );
/// ///

28
core/engine/src/object/builtins/jsproxy.rs

@ -2,7 +2,7 @@
use super::JsFunction; use super::JsFunction;
use crate::{ use crate::{
builtins::Proxy, builtins::Proxy,
js_str, js_string,
native_function::{NativeFunction, NativeFunctionPointer}, native_function::{NativeFunction, NativeFunctionPointer},
object::{FunctionObjectBuilder, JsObject}, object::{FunctionObjectBuilder, JsObject},
value::TryFromJs, value::TryFromJs,
@ -401,7 +401,7 @@ impl JsProxyBuilder {
.length(3) .length(3)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("apply"), f, context) .create_data_property_or_throw(js_string!("apply"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(construct) = self.construct { if let Some(construct) = self.construct {
@ -410,7 +410,7 @@ impl JsProxyBuilder {
.length(3) .length(3)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("construct"), f, context) .create_data_property_or_throw(js_string!("construct"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(define_property) = self.define_property { if let Some(define_property) = self.define_property {
@ -421,7 +421,7 @@ impl JsProxyBuilder {
.length(3) .length(3)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("defineProperty"), f, context) .create_data_property_or_throw(js_string!("defineProperty"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(delete_property) = self.delete_property { if let Some(delete_property) = self.delete_property {
@ -432,7 +432,7 @@ impl JsProxyBuilder {
.length(2) .length(2)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("deleteProperty"), f, context) .create_data_property_or_throw(js_string!("deleteProperty"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(get) = self.get { if let Some(get) = self.get {
@ -440,7 +440,7 @@ impl JsProxyBuilder {
.length(3) .length(3)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("get"), f, context) .create_data_property_or_throw(js_string!("get"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(get_own_property_descriptor) = self.get_own_property_descriptor { if let Some(get_own_property_descriptor) = self.get_own_property_descriptor {
@ -451,7 +451,7 @@ impl JsProxyBuilder {
.length(2) .length(2)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("getOwnPropertyDescriptor"), f, context) .create_data_property_or_throw(js_string!("getOwnPropertyDescriptor"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(get_prototype_of) = self.get_prototype_of { if let Some(get_prototype_of) = self.get_prototype_of {
@ -462,7 +462,7 @@ impl JsProxyBuilder {
.length(1) .length(1)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("getPrototypeOf"), f, context) .create_data_property_or_throw(js_string!("getPrototypeOf"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(has) = self.has { if let Some(has) = self.has {
@ -470,7 +470,7 @@ impl JsProxyBuilder {
.length(2) .length(2)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("has"), f, context) .create_data_property_or_throw(js_string!("has"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(is_extensible) = self.is_extensible { if let Some(is_extensible) = self.is_extensible {
@ -481,7 +481,7 @@ impl JsProxyBuilder {
.length(1) .length(1)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("isExtensible"), f, context) .create_data_property_or_throw(js_string!("isExtensible"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(own_keys) = self.own_keys { if let Some(own_keys) = self.own_keys {
@ -490,7 +490,7 @@ impl JsProxyBuilder {
.length(1) .length(1)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("ownKeys"), f, context) .create_data_property_or_throw(js_string!("ownKeys"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(prevent_extensions) = self.prevent_extensions { if let Some(prevent_extensions) = self.prevent_extensions {
@ -501,7 +501,7 @@ impl JsProxyBuilder {
.length(1) .length(1)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("preventExtensions"), f, context) .create_data_property_or_throw(js_string!("preventExtensions"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(set) = self.set { if let Some(set) = self.set {
@ -509,7 +509,7 @@ impl JsProxyBuilder {
.length(4) .length(4)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("set"), f, context) .create_data_property_or_throw(js_string!("set"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }
if let Some(set_prototype_of) = self.set_prototype_of { if let Some(set_prototype_of) = self.set_prototype_of {
@ -520,7 +520,7 @@ impl JsProxyBuilder {
.length(2) .length(2)
.build(); .build();
handler handler
.create_data_property_or_throw(js_str!("setPrototypeOf"), f, context) .create_data_property_or_throw(js_string!("setPrototypeOf"), f, context)
.expect("new object should be writable"); .expect("new object should be writable");
} }

17
core/engine/src/object/jsobject.rs

@ -21,7 +21,6 @@ use crate::{
Context, JsResult, JsString, JsValue, Context, JsResult, JsString, JsValue,
}; };
use boa_gc::{self, Finalize, Gc, GcBox, GcRefCell, Trace}; use boa_gc::{self, Finalize, Gc, GcBox, GcRefCell, Trace};
use boa_macros::js_str;
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::HashMap, collections::HashMap,
@ -331,9 +330,9 @@ impl JsObject {
// 4. Else, // 4. Else,
// a. Let methodNames be « "valueOf", "toString" ». // a. Let methodNames be « "valueOf", "toString" ».
let method_names = if hint == PreferredType::String { let method_names = if hint == PreferredType::String {
[js_str!("toString"), js_str!("valueOf")] [js_string!("toString"), js_string!("valueOf")]
} else { } else {
[js_str!("valueOf"), js_str!("toString")] [js_string!("valueOf"), js_string!("toString")]
}; };
// 5. For each name in methodNames in List order, do // 5. For each name in methodNames in List order, do
@ -373,7 +372,7 @@ impl JsObject {
// 3. Let hasEnumerable be ? HasProperty(Obj, "enumerable"). // 3. Let hasEnumerable be ? HasProperty(Obj, "enumerable").
// 4. If hasEnumerable is true, then ... // 4. If hasEnumerable is true, then ...
if let Some(enumerable) = self.try_get(js_str!("enumerable"), context)? { if let Some(enumerable) = self.try_get(js_string!("enumerable"), context)? {
// a. Let enumerable be ! ToBoolean(? Get(Obj, "enumerable")). // a. Let enumerable be ! ToBoolean(? Get(Obj, "enumerable")).
// b. Set desc.[[Enumerable]] to enumerable. // b. Set desc.[[Enumerable]] to enumerable.
desc = desc.enumerable(enumerable.to_boolean()); desc = desc.enumerable(enumerable.to_boolean());
@ -381,7 +380,7 @@ impl JsObject {
// 5. Let hasConfigurable be ? HasProperty(Obj, "configurable"). // 5. Let hasConfigurable be ? HasProperty(Obj, "configurable").
// 6. If hasConfigurable is true, then ... // 6. If hasConfigurable is true, then ...
if let Some(configurable) = self.try_get(js_str!("configurable"), context)? { if let Some(configurable) = self.try_get(js_string!("configurable"), context)? {
// a. Let configurable be ! ToBoolean(? Get(Obj, "configurable")). // a. Let configurable be ! ToBoolean(? Get(Obj, "configurable")).
// b. Set desc.[[Configurable]] to configurable. // b. Set desc.[[Configurable]] to configurable.
desc = desc.configurable(configurable.to_boolean()); desc = desc.configurable(configurable.to_boolean());
@ -389,7 +388,7 @@ impl JsObject {
// 7. Let hasValue be ? HasProperty(Obj, "value"). // 7. Let hasValue be ? HasProperty(Obj, "value").
// 8. If hasValue is true, then ... // 8. If hasValue is true, then ...
if let Some(value) = self.try_get(js_str!("value"), context)? { if let Some(value) = self.try_get(js_string!("value"), context)? {
// a. Let value be ? Get(Obj, "value"). // a. Let value be ? Get(Obj, "value").
// b. Set desc.[[Value]] to value. // b. Set desc.[[Value]] to value.
desc = desc.value(value); desc = desc.value(value);
@ -397,7 +396,7 @@ impl JsObject {
// 9. Let hasWritable be ? HasProperty(Obj, ). // 9. Let hasWritable be ? HasProperty(Obj, ).
// 10. If hasWritable is true, then ... // 10. If hasWritable is true, then ...
if let Some(writable) = self.try_get(js_str!("writable"), context)? { if let Some(writable) = self.try_get(js_string!("writable"), context)? {
// a. Let writable be ! ToBoolean(? Get(Obj, "writable")). // a. Let writable be ! ToBoolean(? Get(Obj, "writable")).
// b. Set desc.[[Writable]] to writable. // b. Set desc.[[Writable]] to writable.
desc = desc.writable(writable.to_boolean()); desc = desc.writable(writable.to_boolean());
@ -406,7 +405,7 @@ impl JsObject {
// 11. Let hasGet be ? HasProperty(Obj, "get"). // 11. Let hasGet be ? HasProperty(Obj, "get").
// 12. If hasGet is true, then // 12. If hasGet is true, then
// 12.a. Let getter be ? Get(Obj, "get"). // 12.a. Let getter be ? Get(Obj, "get").
let get = if let Some(getter) = self.try_get(js_str!("get"), context)? { let get = if let Some(getter) = self.try_get(js_string!("get"), context)? {
// b. If IsCallable(getter) is false and getter is not undefined, throw a TypeError exception. // b. If IsCallable(getter) is false and getter is not undefined, throw a TypeError exception.
// todo: extract IsCallable to be callable from Value // todo: extract IsCallable to be callable from Value
if !getter.is_undefined() && getter.as_object().map_or(true, |o| !o.is_callable()) { if !getter.is_undefined() && getter.as_object().map_or(true, |o| !o.is_callable()) {
@ -423,7 +422,7 @@ impl JsObject {
// 13. Let hasSet be ? HasProperty(Obj, "set"). // 13. Let hasSet be ? HasProperty(Obj, "set").
// 14. If hasSet is true, then // 14. If hasSet is true, then
// 14.a. Let setter be ? Get(Obj, "set"). // 14.a. Let setter be ? Get(Obj, "set").
let set = if let Some(setter) = self.try_get(js_str!("set"), context)? { let set = if let Some(setter) = self.try_get(js_string!("set"), context)? {
// 14.b. If IsCallable(setter) is false and setter is not undefined, throw a TypeError exception. // 14.b. If IsCallable(setter) is false and setter is not undefined, throw a TypeError exception.
// todo: extract IsCallable to be callable from Value // todo: extract IsCallable to be callable from Value
if !setter.is_undefined() && setter.as_object().map_or(true, |o| !o.is_callable()) { if !setter.is_undefined() && setter.as_object().map_or(true, |o| !o.is_callable()) {

9
core/engine/src/object/mod.rs

@ -2,7 +2,6 @@
//! //!
//! For the builtin object wrappers, please see [`object::builtins`][builtins] for implementors. //! For the builtin object wrappers, please see [`object::builtins`][builtins] for implementors.
use boa_macros::js_str;
pub use jsobject::{RecursionLimiter, Ref, RefMut}; pub use jsobject::{RecursionLimiter, Ref, RefMut};
pub use operations::IntegrityLevel; pub use operations::IntegrityLevel;
pub use property_map::*; pub use property_map::*;
@ -24,7 +23,7 @@ use crate::{
property::{Attribute, PropertyDescriptor, PropertyKey}, property::{Attribute, PropertyDescriptor, PropertyKey},
realm::Realm, realm::Realm,
string::StaticJsStrings, string::StaticJsStrings,
Context, JsStr, JsString, JsSymbol, JsValue, Context, JsString, JsSymbol, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
@ -51,10 +50,10 @@ pub use datatypes::JsData;
pub use jsobject::*; pub use jsobject::*;
/// Const `constructor`, usually set on prototypes as a key to point to their respective constructor object. /// Const `constructor`, usually set on prototypes as a key to point to their respective constructor object.
pub const CONSTRUCTOR: JsStr<'_> = js_str!("constructor"); pub const CONSTRUCTOR: JsString = js_string!("constructor");
/// Const `prototype`, usually set on constructors as a key to point to their respective prototype object. /// Const `prototype`, usually set on constructors as a key to point to their respective prototype object.
pub const PROTOTYPE: JsStr<'_> = js_str!("prototype"); pub const PROTOTYPE: JsString = js_string!("prototype");
/// Common field names. /// Common field names.
@ -1023,7 +1022,7 @@ impl<'ctx> ConstructorBuilder<'ctx> {
}; };
constructor.insert(StaticJsStrings::LENGTH, length); constructor.insert(StaticJsStrings::LENGTH, length);
constructor.insert(js_str!("name"), name); constructor.insert(js_string!("name"), name);
if let Some(proto) = self.custom_prototype.take() { if let Some(proto) = self.custom_prototype.take() {
constructor.set_prototype(proto); constructor.set_prototype(proto);

3
core/engine/src/value/conversions/try_into_js.rs

@ -1,5 +1,4 @@
use crate::{Context, JsNativeError, JsResult, JsValue}; use crate::{Context, JsNativeError, JsResult, JsString, JsValue};
use boa_string::JsString;
/// This trait adds a conversions from a Rust Type into [`JsValue`]. /// This trait adds a conversions from a Rust Type into [`JsValue`].
pub trait TryIntoJs: Sized { pub trait TryIntoJs: Sized {

8
core/engine/src/value/display.rs

@ -4,7 +4,7 @@ use crate::{
error::ErrorObject, map::ordered_map::OrderedMap, promise::PromiseState, error::ErrorObject, map::ordered_map::OrderedMap, promise::PromiseState,
set::ordered_set::OrderedSet, Array, Promise, set::ordered_set::OrderedSet, Array, Promise,
}, },
js_str, js_string,
property::PropertyDescriptor, property::PropertyDescriptor,
JsError, JsString, JsError, JsString,
}; };
@ -118,7 +118,7 @@ pub(crate) fn log_string_from(x: &JsValue, print_internals: bool, print_children
} else if v_bor.is::<Array>() { } else if v_bor.is::<Array>() {
let len = v_bor let len = v_bor
.properties() .properties()
.get(&js_str!("length").into()) .get(&js_string!("length").into())
.expect("array object must have 'length' property") .expect("array object must have 'length' property")
// FIXME: handle accessor descriptors // FIXME: handle accessor descriptors
.expect_value() .expect_value()
@ -194,7 +194,7 @@ pub(crate) fn log_string_from(x: &JsValue, print_internals: bool, print_children
} else if v_bor.is::<ErrorObject>() { } else if v_bor.is::<ErrorObject>() {
drop(v_bor); drop(v_bor);
let name: Cow<'static, str> = v let name: Cow<'static, str> = v
.get_property(&js_str!("name").into()) .get_property(&js_string!("name").into())
.as_ref() .as_ref()
.and_then(PropertyDescriptor::value) .and_then(PropertyDescriptor::value)
.map_or_else( .map_or_else(
@ -209,7 +209,7 @@ pub(crate) fn log_string_from(x: &JsValue, print_internals: bool, print_children
}, },
); );
let message = v let message = v
.get_property(&js_str!("message").into()) .get_property(&js_string!("message").into())
.as_ref() .as_ref()
.and_then(PropertyDescriptor::value) .and_then(PropertyDescriptor::value)
.map(|v| { .map(|v| {

32
core/engine/src/value/mod.rs

@ -8,7 +8,6 @@ use std::{
ops::Sub, ops::Sub,
}; };
use boa_macros::js_str;
use num_bigint::BigInt; use num_bigint::BigInt;
use num_integer::Integer; use num_integer::Integer;
use num_traits::{ToPrimitive, Zero}; use num_traits::{ToPrimitive, Zero};
@ -432,9 +431,9 @@ impl JsValue {
// 1. Assert: preferredType is number. // 1. Assert: preferredType is number.
// 2. Let hint be "number". // 2. Let hint be "number".
let hint = match preferred_type { let hint = match preferred_type {
PreferredType::Default => js_str!("default"), PreferredType::Default => js_string!("default"),
PreferredType::String => js_str!("string"), PreferredType::String => js_string!("string"),
PreferredType::Number => js_str!("number"), PreferredType::Number => js_string!("number"),
} }
.into(); .into();
@ -536,7 +535,11 @@ impl JsValue {
match self { match self {
Self::Null => Ok(js_string!("null")), Self::Null => Ok(js_string!("null")),
Self::Undefined => Ok(js_string!("undefined")), Self::Undefined => Ok(js_string!("undefined")),
Self::Boolean(boolean) => Ok(boolean.to_string().into()), Self::Boolean(boolean) => Ok(if *boolean {
js_string!("true")
} else {
js_string!("false")
}),
Self::Rational(rational) => Ok(Number::to_js_string(*rational)), Self::Rational(rational) => Ok(Number::to_js_string(*rational)),
Self::Integer(integer) => Ok(integer.to_string().into()), Self::Integer(integer) => Ok(integer.to_string().into()),
Self::String(string) => Ok(string.clone()), Self::String(string) => Ok(string.clone()),
@ -1034,22 +1037,21 @@ impl JsValue {
#[must_use] #[must_use]
pub fn js_type_of(&self) -> JsString { pub fn js_type_of(&self) -> JsString {
match *self { match *self {
Self::Rational(_) | Self::Integer(_) => js_str!("number"), Self::Rational(_) | Self::Integer(_) => js_string!("number"),
Self::String(_) => js_str!("string"), Self::String(_) => js_string!("string"),
Self::Boolean(_) => js_str!("boolean"), Self::Boolean(_) => js_string!("boolean"),
Self::Symbol(_) => js_str!("symbol"), Self::Symbol(_) => js_string!("symbol"),
Self::Null => js_str!("object"), Self::Null => js_string!("object"),
Self::Undefined => js_str!("undefined"), Self::Undefined => js_string!("undefined"),
Self::BigInt(_) => js_str!("bigint"), Self::BigInt(_) => js_string!("bigint"),
Self::Object(ref object) => { Self::Object(ref object) => {
if object.is_callable() { if object.is_callable() {
js_str!("function") js_string!("function")
} else { } else {
js_str!("object") js_string!("object")
} }
} }
} }
.into()
} }
/// Maps a `JsValue` into a `Option<T>` where T is the result of an /// Maps a `JsValue` into a `Option<T>` where T is the result of an

1
core/engine/src/value/tests.rs

@ -1,3 +1,4 @@
use boa_macros::js_str;
use indoc::indoc; use indoc::indoc;
use super::*; use super::*;

3
core/engine/src/vm/mod.rs

@ -6,12 +6,11 @@
use crate::{ use crate::{
environments::EnvironmentStack, realm::Realm, script::Script, vm::code_block::Readable, environments::EnvironmentStack, realm::Realm, script::Script, vm::code_block::Readable,
Context, JsError, JsNativeError, JsObject, JsResult, JsValue, Module, Context, JsError, JsNativeError, JsObject, JsResult, JsString, JsValue, Module,
}; };
use boa_gc::{custom_trace, Finalize, Gc, Trace}; use boa_gc::{custom_trace, Finalize, Gc, Trace};
use boa_profiler::Profiler; use boa_profiler::Profiler;
use boa_string::JsString;
use std::{future::Future, mem::size_of, ops::ControlFlow, pin::Pin, task}; use std::{future::Future, mem::size_of, ops::ControlFlow, pin::Pin, task};
#[cfg(feature = "trace")] #[cfg(feature = "trace")]

6
core/engine/src/vm/opcode/await/mod.rs

@ -1,13 +1,13 @@
use std::cell::Cell; use std::cell::Cell;
use boa_gc::Gc; use boa_gc::Gc;
use boa_macros::js_str;
use crate::{ use crate::{
builtins::{ builtins::{
async_generator::AsyncGenerator, generator::GeneratorContext, promise::PromiseCapability, async_generator::AsyncGenerator, generator::GeneratorContext, promise::PromiseCapability,
Promise, Promise,
}, },
js_string,
native_function::NativeFunction, native_function::NativeFunction,
object::FunctionObjectBuilder, object::FunctionObjectBuilder,
vm::{opcode::Operation, CompletionType, GeneratorResumeKind}, vm::{opcode::Operation, CompletionType, GeneratorResumeKind},
@ -85,7 +85,7 @@ impl Operation for Await {
captures.clone(), captures.clone(),
), ),
) )
.name(js_str!("")) .name(js_string!())
.length(1) .length(1)
.build(); .build();
@ -124,7 +124,7 @@ impl Operation for Await {
captures, captures,
), ),
) )
.name(js_str!("")) .name(js_string!())
.length(1) .length(1)
.build(); .build();

6
core/engine/src/vm/opcode/generator/mod.rs

@ -8,7 +8,7 @@ use crate::{
generator::{GeneratorContext, GeneratorState}, generator::{GeneratorContext, GeneratorState},
}, },
error::JsNativeError, error::JsNativeError,
js_str, js_string,
object::PROTOTYPE, object::PROTOTYPE,
vm::{ vm::{
call_frame::GeneratorResumeKind, call_frame::GeneratorResumeKind,
@ -252,7 +252,7 @@ impl Operation for GeneratorDelegateNext {
GeneratorResumeKind::Throw => { GeneratorResumeKind::Throw => {
let throw = iterator_record let throw = iterator_record
.iterator() .iterator()
.get_method(js_str!("throw"), context)?; .get_method(js_string!("throw"), context)?;
if let Some(throw) = throw { if let Some(throw) = throw {
let result = throw.call( let result = throw.call(
&iterator_record.iterator().clone().into(), &iterator_record.iterator().clone().into(),
@ -273,7 +273,7 @@ impl Operation for GeneratorDelegateNext {
GeneratorResumeKind::Return => { GeneratorResumeKind::Return => {
let r#return = iterator_record let r#return = iterator_record
.iterator() .iterator()
.get_method(js_str!("return"), context)?; .get_method(js_string!("return"), context)?;
if let Some(r#return) = r#return { if let Some(r#return) = r#return {
let result = r#return.call( let result = r#return.call(
&iterator_record.iterator().clone().into(), &iterator_record.iterator().clone().into(),

4
core/engine/src/vm/opcode/iteration/for_in.rs

@ -1,6 +1,6 @@
use crate::{ use crate::{
builtins::{iterable::IteratorRecord, object::for_in_iterator::ForInIterator}, builtins::{iterable::IteratorRecord, object::for_in_iterator::ForInIterator},
js_str, js_string,
vm::{opcode::Operation, CompletionType}, vm::{opcode::Operation, CompletionType},
Context, JsResult, JsValue, Context, JsResult, JsValue,
}; };
@ -23,7 +23,7 @@ impl Operation for CreateForInIterator {
let object = object.to_object(context)?; let object = object.to_object(context)?;
let iterator = ForInIterator::create_for_in_iterator(JsValue::new(object), context); let iterator = ForInIterator::create_for_in_iterator(JsValue::new(object), context);
let next_method = iterator let next_method = iterator
.get(js_str!("next"), context) .get(js_string!("next"), context)
.expect("ForInIterator must have a `next` method"); .expect("ForInIterator must have a `next` method");
context context

7
core/engine/src/vm/opcode/iteration/iterator.rs

@ -1,6 +1,6 @@
use crate::{ use crate::{
builtins::{iterable::create_iter_result_object, Array}, builtins::{iterable::create_iter_result_object, Array},
js_str, js_string,
vm::{opcode::Operation, CompletionType, GeneratorResumeKind}, vm::{opcode::Operation, CompletionType, GeneratorResumeKind},
Context, JsResult, JsValue, Context, JsResult, JsValue,
}; };
@ -248,7 +248,10 @@ impl Operation for IteratorReturn {
return Ok(CompletionType::Normal); return Ok(CompletionType::Normal);
} }
let Some(ret) = record.iterator().get_method(js_str!("return"), context)? else { let Some(ret) = record
.iterator()
.get_method(js_string!("return"), context)?
else {
context.vm.push(false); context.vm.push(false);
return Ok(CompletionType::Normal); return Ok(CompletionType::Normal);
}; };

2
core/engine/src/vm/opcode/push/class/private.rs

@ -36,7 +36,7 @@ impl PushClassPrivateMethod {
.build(); .build();
method_object method_object
.__define_own_property__( .__define_own_property__(
&js_str!("name").into(), &js_string!("name").into(),
desc, desc,
&mut InternalMethodContext::new(context), &mut InternalMethodContext::new(context),
) )

4
core/engine/src/vm/opcode/templates/mod.rs

@ -1,6 +1,6 @@
use crate::{ use crate::{
builtins::array::Array, builtins::array::Array,
js_str, js_string,
object::IntegrityLevel, object::IntegrityLevel,
property::PropertyDescriptor, property::PropertyDescriptor,
vm::{opcode::Operation, CompletionType}, vm::{opcode::Operation, CompletionType},
@ -79,7 +79,7 @@ impl TemplateCreate {
.expect("should never fail per spec"); .expect("should never fail per spec");
template template
.define_property_or_throw( .define_property_or_throw(
js_str!("raw"), js_string!("raw"),
PropertyDescriptor::builder() PropertyDescriptor::builder()
.value(raw_obj) .value(raw_obj)
.writable(false) .writable(false)

4
core/engine/tests/gcd.rs

@ -6,7 +6,7 @@
// You can execute this example with `cargo run --example gcd` // You can execute this example with `cargo run --example gcd`
use boa_engine::{js_str, Context, Module}; use boa_engine::{js_string, Context, Module};
use boa_parser::Source; use boa_parser::Source;
use std::path::PathBuf; use std::path::PathBuf;
@ -28,7 +28,7 @@ fn gcd() {
.unwrap(); .unwrap();
let js_gcd = module let js_gcd = module
.get_typed_fn::<(i32, i32), i32>(js_str!("gcd"), context) .get_typed_fn::<(i32, i32), i32>(js_string!("gcd"), context)
.unwrap(); .unwrap();
assert_eq!(js_gcd.call(context, (6, 9)), Ok(3)); assert_eq!(js_gcd.call(context, (6, 9)), Ok(3));

4
core/interop/tests/fibonacci.rs

@ -4,7 +4,7 @@
// You can execute this example with `cargo run --example gcd` // You can execute this example with `cargo run --example gcd`
use boa_engine::object::builtins::{JsFunction, TypedJsFunction}; use boa_engine::object::builtins::{JsFunction, TypedJsFunction};
use boa_engine::{js_error, js_str, Context, JsResult, Module, Source}; use boa_engine::{js_error, js_string, Context, JsResult, Module, Source};
use boa_interop::IntoJsFunctionCopied; use boa_interop::IntoJsFunctionCopied;
use std::path::PathBuf; use std::path::PathBuf;
@ -56,7 +56,7 @@ fn fibonacci_test() {
.unwrap(); .unwrap();
let fibonacci_js = module let fibonacci_js = module
.get_typed_fn::<(usize, JsFunction, JsFunction), usize>(js_str!("fibonacci"), context) .get_typed_fn::<(usize, JsFunction, JsFunction), usize>(js_string!("fibonacci"), context)
.unwrap(); .unwrap();
let fibonacci_rust = fibonacci let fibonacci_rust = fibonacci

4
core/interop/tests/gcd_callback.rs

@ -2,7 +2,7 @@
//! A test that mimics the `boa_engine`'s GCD test with a typed callback. //! A test that mimics the `boa_engine`'s GCD test with a typed callback.
use boa_engine::object::builtins::JsFunction; use boa_engine::object::builtins::JsFunction;
use boa_engine::{js_str, Context, Module, Source}; use boa_engine::{js_string, Context, Module, Source};
use boa_gc::Gc; use boa_gc::Gc;
use boa_interop::{ContextData, IntoJsFunctionCopied}; use boa_interop::{ContextData, IntoJsFunctionCopied};
use std::path::PathBuf; use std::path::PathBuf;
@ -32,7 +32,7 @@ fn gcd_callback() {
.unwrap(); .unwrap();
let js_gcd = module let js_gcd = module
.get_typed_fn::<(i32, i32, JsFunction), ()>(js_str!("gcd_callback"), context) .get_typed_fn::<(i32, i32, JsFunction), ()>(js_string!("gcd_callback"), context)
.unwrap(); .unwrap();
let function = callback_from_js let function = callback_from_js

2
core/macros/src/lib.rs

@ -598,7 +598,7 @@ fn generate_obj_properties(fields: FieldsNamed) -> Result<proc_macro2::TokenStre
quote! { boa_engine::value::TryIntoJs::try_into_js(&self.#name, context)? } quote! { boa_engine::value::TryIntoJs::try_into_js(&self.#name, context)? }
}; };
prop_ctors.push(quote! { prop_ctors.push(quote! {
obj.create_data_property_or_throw(boa_engine::js_str!(#prop_key), #value, context)?; obj.create_data_property_or_throw(boa_engine::js_string!(#prop_key), #value, context)?;
}); });
} }

6
core/runtime/src/console/mod.rs

@ -20,7 +20,7 @@ use boa_engine::{
native_function::NativeFunction, native_function::NativeFunction,
object::{JsObject, ObjectInitializer}, object::{JsObject, ObjectInitializer},
value::{JsValue, Numeric}, value::{JsValue, Numeric},
Context, JsArgs, JsData, JsError, JsResult, JsStr, JsString, JsSymbol, Context, JsArgs, JsData, JsError, JsResult, JsString, JsSymbol,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -148,7 +148,7 @@ fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
// If a JS value implements `toString()`, call it. // If a JS value implements `toString()`, call it.
let mut written = false; let mut written = false;
if let Some(obj) = arg.as_object() { if let Some(obj) = arg.as_object() {
if let Ok(to_string) = obj.get(js_str!("toString"), context) { if let Ok(to_string) = obj.get(js_string!("toString"), context) {
if let Some(to_string_fn) = to_string.as_function() { if let Some(to_string_fn) = to_string.as_function() {
let arg = to_string_fn let arg = to_string_fn
.call(arg, &[], context)? .call(arg, &[], context)?
@ -240,7 +240,7 @@ pub struct Console {
impl Console { impl Console {
/// Name of the built-in `console` property. /// Name of the built-in `console` property.
pub const NAME: JsStr<'static> = js_str!("console"); pub const NAME: JsString = js_string!("console");
/// Modify the context to include the `console` object. /// Modify the context to include the `console` object.
/// ///

2
core/runtime/src/console/tests.rs

@ -99,7 +99,7 @@ fn console_log_cyclic() {
let mut context = Context::default(); let mut context = Context::default();
let console = Console::init(&mut context); let console = Console::init(&mut context);
context context
.register_global_property(js_string!(Console::NAME), console, Attribute::all()) .register_global_property(Console::NAME, console, Attribute::all())
.unwrap(); .unwrap();
run_test_actions_with( run_test_actions_with(

27
core/string/src/common.rs

@ -5,7 +5,7 @@ use crate::{tagged::Tagged, JsStr};
use super::JsString; use super::JsString;
use paste::paste; use paste::paste;
use rustc_hash::{FxBuildHasher, FxHashMap}; use rustc_hash::{FxBuildHasher, FxHashMap};
use std::collections::HashMap; use std::{collections::HashMap, sync::LazyLock};
macro_rules! well_known_statics { macro_rules! well_known_statics {
( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => { ( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => {
@ -71,7 +71,7 @@ impl StaticJsStrings {
return None; return None;
} }
let index = RAW_STATICS_CACHE.with(|map| map.get(string).copied())?; let index = RAW_STATICS_CACHE.get(string).copied()?;
Some(JsString { Some(JsString {
ptr: Tagged::from_tag(index), ptr: Tagged::from_tag(index),
@ -220,21 +220,14 @@ const MAX_STATIC_LENGTH: usize = {
max max
}; };
thread_local! { /// Map from a string inside [`RAW_STATICS`] to its corresponding static index on `RAW_STATICS`.
/// Map from a string inside [`RAW_STATICS`] to its corresponding static index on `RAW_STATICS`. static RAW_STATICS_CACHE: LazyLock<FxHashMap<JsStr<'static>, usize>> = LazyLock::new(|| {
static RAW_STATICS_CACHE: FxHashMap<JsStr<'static>, usize> = { RAW_STATICS
let mut constants = HashMap::with_capacity_and_hasher( .iter()
RAW_STATICS.len(), .enumerate()
FxBuildHasher .map(|(v, &k)| (k, v))
); .collect::<HashMap<JsStr<'static>, usize, FxBuildHasher>>()
});
for (idx, &s) in RAW_STATICS.iter().enumerate() {
constants.insert(s, idx);
}
constants
};
}
/// Array of raw static strings that aren't reference counted. /// Array of raw static strings that aren't reference counted.
const RAW_STATICS: &[JsStr<'_>] = &[ const RAW_STATICS: &[JsStr<'_>] = &[

4
examples/src/bin/loadfile.rs

@ -3,7 +3,7 @@
use std::{error::Error, path::Path}; use std::{error::Error, path::Path};
use boa_engine::{js_string, property::Attribute, Context, Source}; use boa_engine::{property::Attribute, Context, Source};
use boa_runtime::Console; use boa_runtime::Console;
/// Adds the custom runtime to the context. /// Adds the custom runtime to the context.
@ -11,7 +11,7 @@ fn add_runtime(context: &mut Context) {
// We first add the `console` object, to be able to call `console.log()`. // We first add the `console` object, to be able to call `console.log()`.
let console = Console::init(context); let console = Console::init(context);
context context
.register_global_property(js_string!(Console::NAME), console, Attribute::all()) .register_global_property(Console::NAME, console, Attribute::all())
.expect("the console builtin shouldn't exist"); .expect("the console builtin shouldn't exist");
} }

Loading…
Cancel
Save