Browse Source

General code clean-up and new lint addition (#1809)

This PR adds some Clippy lints. Mainly, it adds the list of pedantic lints excluding some lints that were causing too many warnings. I also denied some useful restriction and pedantic lints, to make sure we use `Self` all the possible times (for better maintainability), and that we pass elements by reference where possible, for example, or that the documentation is properly written.

This might even have some small performance gains.

I also added a perfect hash function for the CLI keywords, which should be more efficient than a `HashSet`. This is something we could use elsewhere too.
pull/1817/head
Iban Eguia 3 years ago
parent
commit
60b7eb8934
  1. 58
      Cargo.lock
  2. 12
      boa/src/bigint.rs
  3. 8
      boa/src/builtins/array/array_iterator.rs
  4. 36
      boa/src/builtins/array/mod.rs
  5. 2
      boa/src/builtins/array/tests.rs
  6. 10
      boa/src/builtins/array_buffer/mod.rs
  7. 4
      boa/src/builtins/array_buffer/tests.rs
  8. 21
      boa/src/builtins/bigint/mod.rs
  9. 2
      boa/src/builtins/boolean/mod.rs
  10. 15
      boa/src/builtins/console/mod.rs
  11. 144
      boa/src/builtins/dataview/mod.rs
  12. 105
      boa/src/builtins/date/mod.rs
  13. 212
      boa/src/builtins/date/tests.rs
  14. 2
      boa/src/builtins/error/syntax.rs
  15. 12
      boa/src/builtins/function/arguments.rs
  16. 11
      boa/src/builtins/function/mod.rs
  17. 2
      boa/src/builtins/function/tests.rs
  18. 2
      boa/src/builtins/intl/mod.rs
  19. 2
      boa/src/builtins/intrinsics.rs
  20. 14
      boa/src/builtins/iterable/mod.rs
  21. 27
      boa/src/builtins/json/mod.rs
  22. 8
      boa/src/builtins/map/map_iterator.rs
  23. 7
      boa/src/builtins/map/mod.rs
  24. 12
      boa/src/builtins/map/ordered_map.rs
  25. 5
      boa/src/builtins/math/mod.rs
  26. 6
      boa/src/builtins/number/conversions.rs
  27. 94
      boa/src/builtins/number/mod.rs
  28. 12
      boa/src/builtins/object/for_in_iterator.rs
  29. 22
      boa/src/builtins/object/mod.rs
  30. 2
      boa/src/builtins/object/tests.rs
  31. 32
      boa/src/builtins/reflect/mod.rs
  32. 101
      boa/src/builtins/regexp/mod.rs
  33. 17
      boa/src/builtins/regexp/regexp_string_iterator.rs
  34. 11
      boa/src/builtins/set/mod.rs
  35. 39
      boa/src/builtins/set/ordered_set.rs
  36. 10
      boa/src/builtins/set/set_iterator.rs
  37. 98
      boa/src/builtins/string/mod.rs
  38. 8
      boa/src/builtins/string/string_iterator.rs
  39. 11
      boa/src/builtins/string/tests.rs
  40. 6
      boa/src/builtins/symbol/mod.rs
  41. 6
      boa/src/builtins/typed_array/integer_indexed_object.rs
  42. 38
      boa/src/builtins/typed_array/mod.rs
  43. 103
      boa/src/bytecompiler.rs
  44. 10
      boa/src/context.rs
  45. 6
      boa/src/environment/declarative_environment_record.rs
  46. 6
      boa/src/environment/environment_record_trait.rs
  47. 8
      boa/src/environment/function_environment_record.rs
  48. 11
      boa/src/environment/global_environment_record.rs
  49. 15
      boa/src/environment/object_environment_record.rs
  50. 29
      boa/src/lib.rs
  51. 3
      boa/src/object/internal_methods/arguments.rs
  52. 2
      boa/src/object/internal_methods/array.rs
  53. 15
      boa/src/object/internal_methods/integer_indexed.rs
  54. 35
      boa/src/object/internal_methods/mod.rs
  55. 15
      boa/src/object/internal_methods/proxy.rs
  56. 13
      boa/src/object/internal_methods/string.rs
  57. 18
      boa/src/object/jsobject.rs
  58. 9
      boa/src/object/mod.rs
  59. 50
      boa/src/object/operations.rs
  60. 4
      boa/src/object/property_map.rs
  61. 14
      boa/src/profiler.rs
  62. 113
      boa/src/property/mod.rs
  63. 32
      boa/src/string.rs
  64. 2
      boa/src/symbol.rs
  65. 4
      boa/src/syntax/ast/keyword.rs
  66. 2
      boa/src/syntax/ast/node/conditional/conditional_op/mod.rs
  67. 2
      boa/src/syntax/ast/node/conditional/if_node/mod.rs
  68. 61
      boa/src/syntax/ast/node/declaration/mod.rs
  69. 2
      boa/src/syntax/ast/node/field/get_const_field/mod.rs
  70. 2
      boa/src/syntax/ast/node/field/get_field/mod.rs
  71. 2
      boa/src/syntax/ast/node/iteration/break_node/mod.rs
  72. 2
      boa/src/syntax/ast/node/iteration/continue_node/mod.rs
  73. 2
      boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs
  74. 2
      boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs
  75. 6
      boa/src/syntax/ast/node/iteration/tests.rs
  76. 14
      boa/src/syntax/ast/node/mod.rs
  77. 10
      boa/src/syntax/ast/node/object/mod.rs
  78. 4
      boa/src/syntax/ast/node/return_smt/mod.rs
  79. 2
      boa/src/syntax/ast/node/spread/mod.rs
  80. 6
      boa/src/syntax/ast/node/template/mod.rs
  81. 2
      boa/src/syntax/ast/node/throw/mod.rs
  82. 4
      boa/src/syntax/ast/node/yield/mod.rs
  83. 6
      boa/src/syntax/ast/position.rs
  84. 7
      boa/src/syntax/lexer/comment.rs
  85. 27
      boa/src/syntax/lexer/cursor.rs
  86. 11
      boa/src/syntax/lexer/identifier.rs
  87. 6
      boa/src/syntax/lexer/mod.rs
  88. 41
      boa/src/syntax/lexer/number.rs
  89. 5
      boa/src/syntax/lexer/regex.rs
  90. 29
      boa/src/syntax/lexer/string.rs
  91. 6
      boa/src/syntax/lexer/template.rs
  92. 18
      boa/src/syntax/lexer/tests.rs
  93. 8
      boa/src/syntax/parser/cursor/buffered_lexer/mod.rs
  94. 16
      boa/src/syntax/parser/cursor/mod.rs
  95. 4
      boa/src/syntax/parser/error.rs
  96. 4
      boa/src/syntax/parser/expression/assignment/arrow_function.rs
  97. 11
      boa/src/syntax/parser/expression/assignment/exponentiation.rs
  98. 4
      boa/src/syntax/parser/expression/assignment/mod.rs
  99. 4
      boa/src/syntax/parser/expression/assignment/yield.rs
  100. 2
      boa/src/syntax/parser/expression/left_hand_side/call.rs
  101. Some files were not shown because too many files have changed in this diff Show More

58
Cargo.lock generated

@ -100,7 +100,7 @@ dependencies = [
"Boa",
"colored",
"jemallocator",
"lazy_static",
"phf",
"regex",
"rustyline",
"rustyline-derive",
@ -938,6 +938,50 @@ dependencies = [
"libc",
]
[[package]]
name = "phf"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_macros",
"phf_shared",
"proc-macro-hack",
]
[[package]]
name = "phf_generator"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_macros"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
"siphasher",
]
[[package]]
name = "pkg-config"
version = "0.3.24"
@ -1002,6 +1046,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.36"
@ -1295,6 +1345,12 @@ dependencies = [
"yaml-rust",
]
[[package]]
name = "siphasher"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
[[package]]
name = "smallvec"
version = "1.8.0"

12
boa/src/bigint.rs

@ -77,15 +77,15 @@ impl JsBigInt {
self.inner.to_str_radix(radix)
}
/// Converts the BigInt to a f64 type.
/// Converts the `BigInt` to a f64 type.
///
/// Returns `f64::INFINITY` if the BigInt is too big.
/// Returns `f64::INFINITY` if the `BigInt` is too big.
#[inline]
pub fn to_f64(&self) -> f64 {
self.inner.to_f64().unwrap_or(f64::INFINITY)
}
/// Converts a string to a BigInt with the specified radix.
/// Converts a string to a `BigInt` with the specified radix.
#[inline]
pub fn from_string_radix(buf: &str, radix: u32) -> Option<Self> {
Some(Self {
@ -93,7 +93,7 @@ impl JsBigInt {
})
}
/// This function takes a string and conversts it to BigInt type.
/// This function takes a string and conversts it to `BigInt` type.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -104,7 +104,7 @@ impl JsBigInt {
string = string.trim();
if string.is_empty() {
return Some(JsBigInt::zero());
return Some(Self::zero());
}
let mut radix = 10;
@ -149,7 +149,7 @@ impl JsBigInt {
/// Checks for mathematical equality.
///
/// The abstract operation BigInt::equal takes arguments x (a `BigInt`) and y (a `BigInt`).
/// The abstract operation `BigInt::equal` takes arguments x (a `BigInt`) and y (a `BigInt`).
/// It returns `true` if x and y have the same mathematical integer value and false otherwise.
///
/// More information:

8
boa/src/builtins/array/array_iterator.rs

@ -25,7 +25,7 @@ impl ArrayIterator {
pub(crate) const NAME: &'static str = "ArrayIterator";
fn new(array: JsObject, kind: PropertyNameKind) -> Self {
ArrayIterator {
Self {
array,
kind,
next_index: 0,
@ -33,7 +33,7 @@ impl ArrayIterator {
}
}
/// CreateArrayIterator( array, kind )
/// `CreateArrayIterator( array, kind )`
///
/// Creates a new iterator over the given array.
///
@ -62,7 +62,7 @@ impl ArrayIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut array_iterator = this.as_object().map(|obj| obj.borrow_mut());
let mut array_iterator = this.as_object().map(JsObject::borrow_mut);
let array_iterator = array_iterator
.as_mut()
.and_then(|obj| obj.as_array_iterator_mut())
@ -111,7 +111,7 @@ impl ArrayIterator {
}
}
/// Create the %ArrayIteratorPrototype% object
/// Create the `%ArrayIteratorPrototype%` object
///
/// More information:
/// - [ECMA reference][spec]

36
boa/src/builtins/array/mod.rs

@ -142,7 +142,7 @@ impl Array {
// 4. If numberOfArgs = 0, then
if number_of_args == 0 {
// 4.a. Return ! ArrayCreate(0, proto).
Ok(Array::array_create(0, Some(prototype), context)
Ok(Self::array_create(0, Some(prototype), context)
.unwrap()
.into())
// 5. Else if numberOfArgs = 1, then
@ -150,8 +150,9 @@ impl Array {
// a. Let len be values[0].
let len = &args[0];
// b. Let array be ! ArrayCreate(0, proto).
let array = Array::array_create(0, Some(prototype), context).unwrap();
let array = Self::array_create(0, Some(prototype), context).unwrap();
// c. If Type(len) is not Number, then
#[allow(clippy::if_not_else)]
let int_len = if !len.is_number() {
// i. Perform ! CreateDataPropertyOrThrow(array, "0", len).
array
@ -179,7 +180,7 @@ impl Array {
debug_assert!(number_of_args >= 2);
// b. Let array be ? ArrayCreate(numberOfArgs, proto).
let array = Array::array_create(number_of_args, Some(prototype), context)?;
let array = Self::array_create(number_of_args, Some(prototype), context)?;
// c. Let k be 0.
// d. Repeat, while k < numberOfArgs,
for (i, item) in args.iter().cloned().enumerate() {
@ -304,13 +305,14 @@ impl Array {
///
/// [spec]: https://tc39.es/ecma262/#sec-get-array-@@species
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/@@species
#[allow(clippy::unnecessary_wraps)]
fn get_species(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// 1. Return the this value.
Ok(this.clone())
}
/// Utility function used to specify the creation of a new Array object using a constructor
/// function that is derived from original_array.
/// function that is derived from `original_array`.
///
/// see: <https://tc39.es/ecma262/#sec-arrayspeciescreate>
pub(crate) fn array_species_create(
@ -414,9 +416,7 @@ impl Array {
context: &mut Context,
) -> JsResult<JsValue> {
// 1. Return ? IsArray(arg).
args.get_or_undefined(0)
.is_array(context)
.map(|ok| ok.into())
args.get_or_undefined(0).is_array(context).map(Into::into)
}
/// `Array.of(...items)`
@ -448,7 +448,7 @@ impl Array {
.ok_or_else(|| {
context.construct_type_error("object constructor didn't return an object")
})?,
_ => Array::array_create(len, None, context)?,
_ => Self::array_create(len, None, context)?,
};
// 6. Let k be 0.
@ -574,7 +574,7 @@ impl Array {
// iii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), E).
arr.create_data_property_or_throw(n, item, context)?;
// iv. Set n to n + 1.
n += 1
n += 1;
}
}
// 6. Perform ? Set(A, "length", 𝔽(n), true).
@ -1152,7 +1152,7 @@ impl Array {
let mut k;
if n >= 0 {
// a. Let k be n.
k = n
k = n;
// 9. Else,
} else {
// a. Let k be len + n.
@ -1189,7 +1189,7 @@ impl Array {
/// `Array.prototype.lastIndexOf( searchElement[, fromIndex ] )`
///
///
/// lastIndexOf compares searchElement to the elements of the array in descending order
/// `lastIndexOf` compares searchElement to the elements of the array in descending order
/// using the Strict Equality Comparison algorithm, and if found at one or more indices,
/// returns the largest such index; otherwise, -1 is returned.
///
@ -1426,9 +1426,9 @@ impl Array {
/// `Array.prototype.findLastIndex( predicate [ , thisArg ] )`
///
/// findLastIndex calls predicate once for each element of the array, in descending order,
/// until it finds one where predicate returns true. If such an element is found, findLastIndex
/// immediately returns the index of that element value. Otherwise, findLastIndex returns -1.
/// `findLastIndex` calls predicate once for each element of the array, in descending order,
/// until it finds one where predicate returns true. If such an element is found, `findLastIndex`
/// immediately returns the index of that element value. Otherwise, `findLastIndex` returns -1.
///
/// More information:
/// - [ECMAScript proposal][spec]
@ -1565,7 +1565,7 @@ impl Array {
source_len as u64,
0,
1,
Some(mapper_function.clone()),
Some(mapper_function),
args.get_or_undefined(1),
context,
)?;
@ -1587,7 +1587,7 @@ impl Array {
source_len: u64,
start: u64,
depth: u64,
mapper_function: Option<JsObject>,
mapper_function: Option<&JsObject>,
this_arg: &JsValue,
context: &mut Context,
) -> JsResult<u64> {
@ -1618,7 +1618,7 @@ impl Array {
let mut element = source.get(p, context)?;
// ii. If mapperFunction is present, then
if let Some(ref mapper_function) = mapper_function {
if let Some(mapper_function) = mapper_function {
// 1. Set element to ? Call(mapperFunction, thisArg, <<element, sourceIndex, source>>)
element = mapper_function.call(
this_arg,
@ -1781,7 +1781,7 @@ impl Array {
let mut k;
if n >= 0 {
// a. Let k be n.
k = n
k = n;
// 9. Else,
} else {
// a. Let k be len + n.

2
boa/src/builtins/array/tests.rs

@ -818,7 +818,7 @@ fn map() {
// One but it uses `this` inside the callback
let one_with_this = forward(&mut context, "one.map(callbackThatUsesThis, _this)[0];");
assert_eq!(one_with_this, String::from("\"The answer to life is: 42\""))
assert_eq!(one_with_this, String::from("\"The answer to life is: 42\""));
}
#[test]

10
boa/src/builtins/array_buffer/mod.rs

@ -105,6 +105,7 @@ impl ArrayBuffer {
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-arraybuffer-@@species
#[allow(clippy::unnecessary_wraps)]
fn get_species(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// 1. Return the this value.
Ok(this.clone())
@ -116,6 +117,7 @@ impl ArrayBuffer {
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-arraybuffer.isview
#[allow(clippy::unnecessary_wraps)]
fn is_view(_: &JsValue, args: &[JsValue], _context: &mut Context) -> JsResult<JsValue> {
// 1. If Type(arg) is not Object, return false.
// 2. If arg has a [[ViewedArrayBuffer]] internal slot, return true.
@ -320,7 +322,7 @@ impl ArrayBuffer {
// 3. Set obj.[[ArrayBufferData]] to block.
// 4. Set obj.[[ArrayBufferByteLength]] to byteLength.
obj.borrow_mut().data = ObjectData::array_buffer(ArrayBuffer {
obj.borrow_mut().data = ObjectData::array_buffer(Self {
array_buffer_data: Some(block),
array_buffer_byte_length: byte_length,
array_buffer_detach_key: JsValue::Undefined,
@ -600,7 +602,7 @@ impl ArrayBuffer {
/// [spec]: https://tc39.es/ecma262/#sec-numerictorawbytes
fn numeric_to_raw_bytes(
t: TypedArrayName,
value: JsValue,
value: &JsValue,
is_little_endian: bool,
context: &mut Context,
) -> JsResult<Vec<u8>> {
@ -696,7 +698,7 @@ impl ArrayBuffer {
&mut self,
byte_index: usize,
t: TypedArrayName,
value: JsValue,
value: &JsValue,
_order: SharedMemoryOrder,
is_little_endian: Option<bool>,
context: &mut Context,
@ -804,7 +806,7 @@ fn copy_data_block_bytes(
// TODO: Allow unused variants until shared array buffers are implemented.
#[allow(dead_code)]
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub(crate) enum SharedMemoryOrder {
Init,
SeqCst,

4
boa/src/builtins/array_buffer/tests.rs

@ -4,12 +4,12 @@ use super::*;
fn ut_sunnyy_day_create_byte_data_block() {
let mut context = Context::default();
assert!(create_byte_data_block(100, &mut context).is_ok())
assert!(create_byte_data_block(100, &mut context).is_ok());
}
#[test]
fn ut_rainy_day_create_byte_data_block() {
let mut context = Context::default();
assert!(create_byte_data_block(usize::MAX, &mut context).is_err())
assert!(create_byte_data_block(usize::MAX, &mut context).is_err());
}

21
boa/src/builtins/bigint/mod.rs

@ -71,7 +71,7 @@ impl BigInt {
/// `BigInt()`
///
/// The `BigInt()` constructor is used to create BigInt objects.
/// The `BigInt()` constructor is used to create `BigInt` objects.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -111,10 +111,10 @@ impl BigInt {
Ok(JsBigInt::from(number.to_bigint().expect("This conversion must be safe")).into())
}
/// The abstract operation thisBigIntValue takes argument value.
/// The abstract operation `thisBigIntValue` takes argument value.
///
/// The phrase “this BigInt value” within the specification of a method refers to the
/// result returned by calling the abstract operation thisBigIntValue with the `this` value
/// The phrase “this `BigInt` value” within the specification of a method refers to the
/// result returned by calling the abstract operation `thisBigIntValue` with the `this` value
/// of the method invocation passed as the argument.
///
/// More information:
@ -141,7 +141,7 @@ impl BigInt {
/// `BigInt.prototype.toString( [radix] )`
///
/// The `toString()` method returns a string representing the specified BigInt object.
/// The `toString()` method returns a string representing the specified `BigInt` object.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -225,11 +225,16 @@ impl BigInt {
let (modulo, bits) = Self::calculate_as_uint_n(args, context)?;
if bits > 0
&& modulo >= JsBigInt::pow(&JsBigInt::new(2), &JsBigInt::new(bits as i64 - 1), context)?
&& modulo
>= JsBigInt::pow(
&JsBigInt::new(2),
&JsBigInt::new(i64::from(bits) - 1),
context,
)?
{
Ok(JsValue::new(JsBigInt::sub(
&modulo,
&JsBigInt::pow(&JsBigInt::new(2), &JsBigInt::new(bits as i64), context)?,
&JsBigInt::pow(&JsBigInt::new(2), &JsBigInt::new(i64::from(bits)), context)?,
)))
} else {
Ok(JsValue::new(modulo))
@ -270,7 +275,7 @@ impl BigInt {
Ok((
JsBigInt::mod_floor(
&bigint,
&JsBigInt::pow(&JsBigInt::new(2), &JsBigInt::new(bits as i64), context)?,
&JsBigInt::pow(&JsBigInt::new(2), &JsBigInt::new(i64::from(bits)), context)?,
),
bits,
))

2
boa/src/builtins/boolean/mod.rs

@ -65,7 +65,7 @@ impl Boolean {
context: &mut Context,
) -> JsResult<JsValue> {
// Get the argument, if any
let data = args.get(0).map(|x| x.to_boolean()).unwrap_or(false);
let data = args.get(0).map_or(false, JsValue::to_boolean);
if new_target.is_undefined() {
return Ok(JsValue::new(data));
}

15
boa/src/builtins/console/mod.rs

@ -86,13 +86,13 @@ pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
.unwrap_or_default()
.to_number(context)?;
formatted.push_str(&format!("{number:.prec$}", number = arg, prec = 6));
arg_index += 1
arg_index += 1;
}
/* object, FIXME: how to render this properly? */
'o' | 'O' => {
let arg = data.get_or_undefined(arg_index);
formatted.push_str(&format!("{}", arg.display()));
arg_index += 1
arg_index += 1;
}
/* string */
's' => {
@ -102,7 +102,7 @@ pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
.unwrap_or_default()
.to_string(context)?;
formatted.push_str(&arg);
arg_index += 1
arg_index += 1;
}
'%' => formatted.push('%'),
/* TODO: %c is not implemented */
@ -118,7 +118,7 @@ pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
/* unformatted data */
for rest in data.iter().skip(arg_index) {
formatted.push_str(&format!(" {}", rest.to_string(context)?))
formatted.push_str(&format!(" {}", rest.to_string(context)?));
}
Ok(formatted)
@ -189,7 +189,7 @@ impl Console {
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let assertion = args.get(0).map(JsValue::to_boolean).unwrap_or(false);
let assertion = args.get(0).map_or(false, JsValue::to_boolean);
if !assertion {
let mut args: Vec<JsValue> = args.iter().skip(1).cloned().collect();
@ -222,6 +222,7 @@ impl Console {
///
/// [spec]: https://console.spec.whatwg.org/#clear
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/clear
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn clear(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
context.console_mut().groups.clear();
Ok(JsValue::undefined())
@ -334,7 +335,7 @@ impl Console {
);
let stack_trace_dump = Self::get_stack_trace(context).join("\n");
logger(LogMessage::Log(stack_trace_dump), context.console())
logger(LogMessage::Log(stack_trace_dump), context.console());
}
Ok(JsValue::undefined())
@ -557,6 +558,7 @@ impl Console {
///
/// [spec]: https://console.spec.whatwg.org/#groupend
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/groupEnd
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn group_end(
_: &JsValue,
_: &[JsValue],
@ -577,6 +579,7 @@ impl Console {
///
/// [spec]: https://console.spec.whatwg.org/#dir
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/dir
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn dir(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
logger(
LogMessage::Info(display_obj(args.get_or_undefined(0), true)),

144
boa/src/builtins/dataview/mod.rs

@ -87,13 +87,13 @@ impl DataView {
/// `25.3.2.1 DataView ( buffer [ , byteOffset [ , byteLength ] ] )`
///
/// The `DataView` view provides a low-level interface for reading and writing multiple number
/// types in a binary `ArrayBuffer`, without having to care about the platform's endianness.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN][mdn]
///
/// The DataView view provides a low-level interface for reading and writing multiple number types in a
/// binary ArrayBuffer, without having to care about the platform's endianness.
///
/// [spec]: https://tc39.es/ecma262/#sec-dataview-buffer-byteoffset-bytelength
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/DataView
pub(crate) fn constructor(
@ -142,9 +142,9 @@ impl DataView {
// 8.b. If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
if offset + view_byte_length > buffer_byte_length {
return context.throw_range_error("Invalid data view length");
} else {
view_byte_length
}
view_byte_length
};
(offset, view_byte_length)
};
@ -165,9 +165,9 @@ impl DataView {
let obj = JsObject::from_proto_and_data(
prototype,
ObjectData::data_view(DataView {
ObjectData::data_view(Self {
// 11. Set O.[[ViewedArrayBuffer]] to buffer.
viewed_array_buffer: buffer_obj.to_owned(),
viewed_array_buffer: buffer_obj.clone(),
// 12. Set O.[[ByteLength]] to viewByteLength.
byte_length: view_byte_length,
// 13. Set O.[[ByteOffset]] to offset.
@ -181,7 +181,8 @@ impl DataView {
/// `25.3.4.1 get DataView.prototype.buffer`
///
/// The buffer accessor property represents the ArrayBuffer or SharedArrayBuffer referenced by the DataView at construction time.
/// The buffer accessor property represents the `ArrayBuffer` or `SharedArrayBuffer` referenced
/// by the `DataView` at construction time.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -196,7 +197,7 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Let O be the this value.
// 2. Perform ? RequireInternalSlot(O, [[DataView]]).
let dataview = this.as_object().map(|obj| obj.borrow());
let dataview = this.as_object().map(JsObject::borrow);
let dataview = dataview
.as_ref()
.and_then(|obj| obj.as_data_view())
@ -210,7 +211,7 @@ impl DataView {
/// `25.3.4.1 get DataView.prototype.byteLength`
///
/// The byteLength accessor property represents the length (in bytes) of the dataview.
/// The `byteLength` accessor property represents the length (in bytes) of the dataview.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -225,7 +226,7 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Let O be the this value.
// 2. Perform ? RequireInternalSlot(O, [[DataView]]).
let dataview = this.as_object().map(|obj| obj.borrow());
let dataview = this.as_object().map(JsObject::borrow);
let dataview = dataview
.as_ref()
.and_then(|obj| obj.as_data_view())
@ -248,7 +249,8 @@ impl DataView {
/// `25.3.4.1 get DataView.prototype.byteOffset`
///
/// The byteOffset accessor property represents the offset (in bytes) of this view from the start of its ArrayBuffer or SharedArrayBuffer.
/// The `byteOffset` accessor property represents the offset (in bytes) of this view from the
/// start of its `ArrayBuffer` or `SharedArrayBuffer`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -263,7 +265,7 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Let O be the this value.
// 2. Perform ? RequireInternalSlot(O, [[DataView]]).
let dataview = this.as_object().map(|obj| obj.borrow());
let dataview = this.as_object().map(JsObject::borrow);
let dataview = dataview
.as_ref()
.and_then(|obj| obj.as_data_view())
@ -286,8 +288,9 @@ impl DataView {
/// `25.3.1.1 GetViewValue ( view, requestIndex, isLittleEndian, type )`
///
/// The abstract operation GetViewValue takes arguments view, requestIndex, isLittleEndian, and type.
/// It is used by functions on DataView instances to retrieve values from the view's buffer.
/// The abstract operation `GetViewValue` takes arguments view, requestIndex, `isLittleEndian`,
/// and type. It is used by functions on `DataView` instances to retrieve values from the
/// view's buffer.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -302,7 +305,7 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Perform ? RequireInternalSlot(view, [[DataView]]).
// 2. Assert: view has a [[ViewedArrayBuffer]] internal slot.
let view = view.as_object().map(|obj| obj.borrow());
let view = view.as_object().map(JsObject::borrow);
let view = view
.as_ref()
.and_then(|obj| obj.as_data_view())
@ -353,7 +356,8 @@ impl DataView {
/// `25.3.4.5 DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] )`
///
/// The getBigInt64() method gets a signed 64-bit integer (long long) at the specified byte offset from the start of the DataView.
/// The `getBigInt64()` method gets a signed 64-bit integer (long long) at the specified byte
/// offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -370,7 +374,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -381,7 +385,8 @@ impl DataView {
/// `25.3.4.6 DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] )`
///
/// The getBigUint64() method gets an unsigned 64-bit integer (unsigned long long) at the specified byte offset from the start of the DataView.
/// The `getBigUint64()` method gets an unsigned 64-bit integer (unsigned long long) at the
/// specified byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -398,7 +403,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -409,7 +414,8 @@ impl DataView {
/// `25.3.4.7 DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] )`
///
/// The getFloat32() method gets a signed 32-bit float (float) at the specified byte offset from the start of the DataView.
/// The `getFloat32()` method gets a signed 32-bit float (float) at the specified byte offset
/// from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -426,7 +432,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -437,7 +443,8 @@ impl DataView {
/// `25.3.4.8 DataView.prototype.getFloat64 ( byteOffset [ , littleEndian ] )`
///
/// The getFloat64() method gets a signed 64-bit float (double) at the specified byte offset from the start of the DataView.
/// The `getFloat64()` method gets a signed 64-bit float (double) at the specified byte offset
/// from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -454,7 +461,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -465,7 +472,8 @@ impl DataView {
/// `25.3.4.9 DataView.prototype.getInt8 ( byteOffset [ , littleEndian ] )`
///
/// The getInt8() method gets a signed 8-bit integer (byte) at the specified byte offset from the start of the DataView.
/// The `getInt8()` method gets a signed 8-bit integer (byte) at the specified byte offset
/// from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -482,7 +490,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -493,7 +501,8 @@ impl DataView {
/// `25.3.4.10 DataView.prototype.getInt16 ( byteOffset [ , littleEndian ] )`
///
/// The getInt16() method gets a signed 16-bit integer (short) at the specified byte offset from the start of the DataView.
/// The `getInt16()` method gets a signed 16-bit integer (short) at the specified byte offset
/// from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -510,7 +519,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -521,7 +530,8 @@ impl DataView {
/// `25.3.4.11 DataView.prototype.getInt32 ( byteOffset [ , littleEndian ] )`
///
/// The getInt32() method gets a signed 32-bit integer (long) at the specified byte offset from the start of the DataView.
/// The `getInt32()` method gets a signed 32-bit integer (long) at the specified byte offset
/// from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -538,7 +548,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -549,7 +559,8 @@ impl DataView {
/// `25.3.4.12 DataView.prototype.getUint8 ( byteOffset [ , littleEndian ] )`
///
/// The getUint8() method gets an unsigned 8-bit integer (unsigned byte) at the specified byte offset from the start of the DataView.
/// The `getUint8()` method gets an unsigned 8-bit integer (unsigned byte) at the specified
/// byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -566,7 +577,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -577,7 +588,8 @@ impl DataView {
/// `25.3.4.13 DataView.prototype.getUint16 ( byteOffset [ , littleEndian ] )`
///
/// The getUint16() method gets an unsigned 16-bit integer (unsigned short) at the specified byte offset from the start of the DataView.
/// The `getUint16()` method gets an unsigned 16-bit integer (unsigned short) at the specified
/// byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -594,7 +606,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -605,7 +617,8 @@ impl DataView {
/// `25.3.4.14 DataView.prototype.getUint32 ( byteOffset [ , littleEndian ] )`
///
/// The getUint32() method gets an unsigned 32-bit integer (unsigned long) at the specified byte offset from the start of the DataView.
/// The `getUint32()` method gets an unsigned 32-bit integer (unsigned long) at the specified
/// byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -622,7 +635,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(1);
// 1. Let v be the this value.
// 2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).
DataView::get_view_value(
Self::get_view_value(
this,
byte_offset,
is_little_endian,
@ -633,8 +646,9 @@ impl DataView {
/// `25.3.1.1 SetViewValue ( view, requestIndex, isLittleEndian, type )`
///
/// The abstract operation SetViewValue takes arguments view, requestIndex, isLittleEndian, type, and value.
/// It is used by functions on DataView instances to store values into the view's buffer.
/// The abstract operation `SetViewValue` takes arguments view, requestIndex, `isLittleEndian`,
/// type, and value. It is used by functions on `DataView` instances to store values into the
/// view's buffer.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -650,7 +664,7 @@ impl DataView {
) -> JsResult<JsValue> {
// 1. Perform ? RequireInternalSlot(view, [[DataView]]).
// 2. Assert: view has a [[ViewedArrayBuffer]] internal slot.
let view = view.as_object().map(|obj| obj.borrow());
let view = view.as_object().map(JsObject::borrow);
let view = view
.as_ref()
.and_then(|obj| obj.as_data_view())
@ -701,7 +715,7 @@ impl DataView {
buffer.set_value_in_buffer(
buffer_index,
t,
number_value,
&number_value,
SharedMemoryOrder::Unordered,
Some(is_little_endian),
context,
@ -710,7 +724,8 @@ impl DataView {
/// `25.3.4.15 DataView.prototype.setBigInt64 ( byteOffset, value [ , littleEndian ] )`
///
/// The setBigInt64() method stores a signed 64-bit integer (long long) value at the specified byte offset from the start of the DataView.
/// The `setBigInt64()` method stores a signed 64-bit integer (long long) value at the
/// specified byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -728,7 +743,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, BigUint64, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -740,7 +755,8 @@ impl DataView {
/// `25.3.4.16 DataView.prototype.setBigUint64 ( byteOffset, value [ , littleEndian ] )`
///
/// The setBigUint64() method stores an unsigned 64-bit integer (unsigned long long) value at the specified byte offset from the start of the DataView.
/// The `setBigUint64()` method stores an unsigned 64-bit integer (unsigned long long) value at
/// the specified byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -758,7 +774,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, BigUint64, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -770,7 +786,8 @@ impl DataView {
/// `25.3.4.17 DataView.prototype.setFloat32 ( byteOffset, value [ , littleEndian ] )`
///
/// The setFloat32() method stores a signed 32-bit float (float) value at the specified byte offset from the start of the DataView.
/// The `setFloat32()` method stores a signed 32-bit float (float) value at the specified byte
/// offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -788,7 +805,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Float32, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -800,7 +817,8 @@ impl DataView {
/// `25.3.4.18 DataView.prototype.setFloat64 ( byteOffset, value [ , littleEndian ] )`
///
/// The setFloat64() method stores a signed 64-bit float (double) value at the specified byte offset from the start of the DataView.
/// The `setFloat64()` method stores a signed 64-bit float (double) value at the specified byte
/// offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -818,7 +836,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Float64, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -830,7 +848,8 @@ impl DataView {
/// `25.3.4.19 DataView.prototype.setInt8 ( byteOffset, value [ , littleEndian ] )`
///
/// The setInt8() method stores a signed 8-bit integer (byte) value at the specified byte offset from the start of the DataView.
/// The `setInt8()` method stores a signed 8-bit integer (byte) value at the specified byte
/// offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -848,7 +867,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Int8, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -860,7 +879,8 @@ impl DataView {
/// `25.3.4.20 DataView.prototype.setInt16 ( byteOffset, value [ , littleEndian ] )`
///
/// The setInt16() method stores a signed 16-bit integer (short) value at the specified byte offset from the start of the DataView.
/// The `setInt16()` method stores a signed 16-bit integer (short) value at the specified byte
/// offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -878,7 +898,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Int16, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -890,7 +910,8 @@ impl DataView {
/// `25.3.4.21 DataView.prototype.setInt32 ( byteOffset, value [ , littleEndian ] )`
///
/// The setInt32() method stores a signed 32-bit integer (long) value at the specified byte offset from the start of the DataView.
/// The `setInt32()` method stores a signed 32-bit integer (long) value at the specified byte
/// offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -908,7 +929,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Int32, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -920,7 +941,8 @@ impl DataView {
/// `25.3.4.22 DataView.prototype.setUint8 ( byteOffset, value [ , littleEndian ] )`
///
/// The setUint8() method stores an unsigned 8-bit integer (byte) value at the specified byte offset from the start of the DataView.
/// The `setUint8()` method stores an unsigned 8-bit integer (byte) value at the specified byte
/// offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -938,7 +960,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Uint8, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -950,7 +972,8 @@ impl DataView {
/// `25.3.4.23 DataView.prototype.setUint16 ( byteOffset, value [ , littleEndian ] )`
///
/// The setUint16() method stores an unsigned 16-bit integer (unsigned short) value at the specified byte offset from the start of the DataView.
/// The `setUint16()` method stores an unsigned 16-bit integer (unsigned short) value at the
/// specified byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -968,7 +991,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Uint16, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,
@ -980,7 +1003,8 @@ impl DataView {
/// `25.3.4.24 DataView.prototype.setUint32 ( byteOffset, value [ , littleEndian ] )`
///
/// The setUint32() method stores an unsigned 32-bit integer (unsigned long) value at the specified byte offset from the start of the DataView.
/// The `setUint32()` method stores an unsigned 32-bit integer (unsigned long) value at the
/// specified byte offset from the start of the `DataView`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -998,7 +1022,7 @@ impl DataView {
let is_little_endian = args.get_or_undefined(2);
// 1. Let v be the this value.
// 2. Return ? SetViewValue(v, byteOffset, littleEndian, Uint32, value).
DataView::set_view_value(
Self::set_view_value(
this,
byte_offset,
is_little_endian,

105
boa/src/builtins/date/mod.rs

@ -29,9 +29,7 @@ const MILLIS_PER_SECOND: i64 = 1000;
#[inline]
fn is_zero_or_normal_opt(value: Option<f64>) -> bool {
value
.map(|value| value == 0f64 || value.is_normal())
.unwrap_or(true)
value.map_or(true, |value| value == 0f64 || value.is_normal())
}
macro_rules! check_normal_opt {
@ -43,8 +41,7 @@ macro_rules! check_normal_opt {
#[inline]
fn ignore_ambiguity<T>(result: LocalResult<T>) -> Option<T> {
match result {
LocalResult::Ambiguous(v, _) => Some(v),
LocalResult::Single(v) => Some(v),
LocalResult::Ambiguous(v, _) | LocalResult::Single(v) => Some(v),
LocalResult::None => None,
}
}
@ -290,14 +287,14 @@ impl Date {
};
self.0 = naive.and_then(|naive| {
let year = year.unwrap_or_else(|| naive.year() as f64) as i32;
let month = month.unwrap_or_else(|| naive.month0() as f64) as i32;
let day = (day.unwrap_or_else(|| naive.day() as f64) as i32).checked_sub(1)?;
let hour = hour.unwrap_or_else(|| naive.hour() as f64) as i64;
let minute = minute.unwrap_or_else(|| naive.minute() as f64) as i64;
let second = second.unwrap_or_else(|| naive.second() as f64) as i64;
let year = year.unwrap_or_else(|| f64::from(naive.year())) as i32;
let month = month.unwrap_or_else(|| f64::from(naive.month0())) as i32;
let day = (day.unwrap_or_else(|| f64::from(naive.day())) as i32).checked_sub(1)?;
let hour = hour.unwrap_or_else(|| f64::from(naive.hour())) as i64;
let minute = minute.unwrap_or_else(|| f64::from(naive.minute())) as i64;
let second = second.unwrap_or_else(|| f64::from(naive.second())) as i64;
let millisecond = millisecond
.unwrap_or_else(|| naive.nanosecond() as f64 / NANOS_PER_MS as f64)
.unwrap_or_else(|| f64::from(naive.nanosecond()) / NANOS_PER_MS as f64)
as i64;
let (year, month, day) = fix_day(year, month, day)?;
@ -384,7 +381,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date-constructor
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date
pub(crate) fn make_date_now(prototype: JsObject) -> JsObject {
JsObject::from_proto_and_data(prototype, ObjectData::date(Date::default()))
JsObject::from_proto_and_data(prototype, ObjectData::date(Self::default()))
}
/// `Date(value)`
@ -416,8 +413,8 @@ impl Date {
None
} else {
let secs = (tv / 1_000f64) as i64;
let nsecs = ((tv % 1_000f64) * 1_000_000f64) as u32;
NaiveDateTime::from_timestamp_opt(secs, nsecs)
let nano_secs = ((tv % 1_000f64) * 1_000_000f64) as u32;
NaiveDateTime::from_timestamp_opt(secs, nano_secs)
}
}
},
@ -426,7 +423,7 @@ impl Date {
let tv = tv.filter(|time| Self::time_clip(time.timestamp_millis() as f64).is_some());
Ok(JsObject::from_proto_and_data(
prototype,
ObjectData::date(Date(tv)),
ObjectData::date(Self(tv)),
))
}
@ -467,12 +464,12 @@ impl Date {
if !check_normal_opt!(year, month, day, hour, min, sec, milli) {
return Ok(JsObject::from_proto_and_data(
prototype,
ObjectData::date(Date(None)),
ObjectData::date(Self(None)),
));
}
if (0.0..=99.0).contains(&year) {
year += 1900.0
year += 1900.0;
}
let mut date = Self(
@ -525,10 +522,10 @@ impl Date {
let hint = args.get_or_undefined(0);
let try_first = match hint.as_string().map(|s| s.as_str()) {
let try_first = match hint.as_string().map(JsString::as_str) {
// 3. If hint is "string" or "default", then
// a. Let tryFirst be string.
Some("string") | Some("default") => PreferredType::String,
Some("string" | "default") => PreferredType::String,
// 4. Else if hint is "number", then
// a. Let tryFirst be number.
Some("number") => PreferredType::Number,
@ -554,7 +551,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getdate
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDate
pub fn get_date(&self) -> f64 {
self.to_local().map_or(f64::NAN, |dt| dt.day() as f64)
self.to_local().map_or(f64::NAN, |dt| f64::from(dt.day()))
}
/// `Date.prototype.getDay()`
@ -572,7 +569,7 @@ impl Date {
self.to_local().map_or(f64::NAN, |dt| {
let weekday = dt.weekday() as u32;
let weekday = (weekday + 1) % 7; // 0 represents Monday in Chrono
weekday as f64
f64::from(weekday)
})
}
@ -587,7 +584,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getfullyear
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getFullYear
pub fn get_full_year(&self) -> f64 {
self.to_local().map_or(f64::NAN, |dt| dt.year() as f64)
self.to_local().map_or(f64::NAN, |dt| f64::from(dt.year()))
}
/// `Date.prototype.getHours()`
@ -601,7 +598,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.gethours
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getHours
pub fn get_hours(&self) -> f64 {
self.to_local().map_or(f64::NAN, |dt| dt.hour() as f64)
self.to_local().map_or(f64::NAN, |dt| f64::from(dt.hour()))
}
/// `Date.prototype.getMilliseconds()`
@ -615,8 +612,9 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getmilliseconds
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMilliseconds
pub fn get_milliseconds(&self) -> f64 {
self.to_local()
.map_or(f64::NAN, |dt| dt.nanosecond() as f64 / NANOS_PER_MS as f64)
self.to_local().map_or(f64::NAN, |dt| {
f64::from(dt.nanosecond()) / NANOS_PER_MS as f64
})
}
/// `Date.prototype.getMinutes()`
@ -630,7 +628,8 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getminutes
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMinutes
pub fn get_minutes(&self) -> f64 {
self.to_local().map_or(f64::NAN, |dt| dt.minute() as f64)
self.to_local()
.map_or(f64::NAN, |dt| f64::from(dt.minute()))
}
/// `Date.prototype.getMonth()`
@ -645,7 +644,8 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getmonth
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMonth
pub fn get_month(&self) -> f64 {
self.to_local().map_or(f64::NAN, |dt| dt.month0() as f64)
self.to_local()
.map_or(f64::NAN, |dt| f64::from(dt.month0()))
}
/// `Date.prototype.getSeconds()`
@ -659,13 +659,15 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getseconds
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getSeconds
pub fn get_seconds(&self) -> f64 {
self.to_local().map_or(f64::NAN, |dt| dt.second() as f64)
self.to_local()
.map_or(f64::NAN, |dt| f64::from(dt.second()))
}
/// `Date.prototype.getYear()`
///
/// The getYear() method returns the year in the specified date according to local time. Because getYear() does not
/// return full years ("year 2000 problem"), it is no longer used and has been replaced by the getFullYear() method.
/// The `getYear()` method returns the year in the specified date according to local time.
/// Because `getYear()` does not return full years ("year 2000 problem"), it is no longer used
/// and has been replaced by the `getFullYear()` method.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -675,7 +677,7 @@ impl Date {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getYear
pub fn get_year(&self) -> f64 {
self.to_local()
.map_or(f64::NAN, |dt| dt.year() as f64 - 1900f64)
.map_or(f64::NAN, |dt| f64::from(dt.year()) - 1900f64)
}
/// `Date.prototype.getTime()`
@ -695,7 +697,7 @@ impl Date {
/// `Date.prototype.getTimeZoneOffset()`
///
/// The getTimezoneOffset() method returns the time zone difference, in minutes, from current locale (host system
/// The `getTimezoneOffset()` method returns the time zone difference, in minutes, from current locale (host system
/// settings) to UTC.
///
/// More information:
@ -720,7 +722,7 @@ impl Date {
// 3. Return (t - LocalTime(t)) / msPerMinute.
Ok(JsValue::new(
-Local::now().offset().local_minus_utc() as f64 / 60f64,
f64::from(-Local::now().offset().local_minus_utc()) / 60f64,
))
}
@ -735,7 +737,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcdate
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCDate
pub fn get_utc_date(&self) -> f64 {
self.to_utc().map_or(f64::NAN, |dt| dt.day() as f64)
self.to_utc().map_or(f64::NAN, |dt| f64::from(dt.day()))
}
/// `Date.prototype.getUTCDay()`
@ -753,7 +755,7 @@ impl Date {
self.to_utc().map_or(f64::NAN, |dt| {
let weekday = dt.weekday() as u32;
let weekday = (weekday + 1) % 7; // 0 represents Monday in Chrono
weekday as f64
f64::from(weekday)
})
}
@ -768,7 +770,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcfullyear
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCFullYear
pub fn get_utc_full_year(&self) -> f64 {
self.to_utc().map_or(f64::NAN, |dt| dt.year() as f64)
self.to_utc().map_or(f64::NAN, |dt| f64::from(dt.year()))
}
/// `Date.prototype.getUTCHours()`
@ -782,7 +784,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutchours
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCHours
pub fn get_utc_hours(&self) -> f64 {
self.to_utc().map_or(f64::NAN, |dt| dt.hour() as f64)
self.to_utc().map_or(f64::NAN, |dt| f64::from(dt.hour()))
}
/// `Date.prototype.getUTCMilliseconds()`
@ -796,8 +798,9 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcmilliseconds
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMilliseconds
pub fn get_utc_milliseconds(&self) -> f64 {
self.to_utc()
.map_or(f64::NAN, |dt| dt.nanosecond() as f64 / NANOS_PER_MS as f64)
self.to_utc().map_or(f64::NAN, |dt| {
f64::from(dt.nanosecond()) / NANOS_PER_MS as f64
})
}
/// `Date.prototype.getUTCMinutes()`
@ -811,7 +814,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcminutes
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMinutes
pub fn get_utc_minutes(&self) -> f64 {
self.to_utc().map_or(f64::NAN, |dt| dt.minute() as f64)
self.to_utc().map_or(f64::NAN, |dt| f64::from(dt.minute()))
}
/// `Date.prototype.getUTCMonth()`
@ -826,7 +829,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcmonth
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCMonth
pub fn get_utc_month(&self) -> f64 {
self.to_utc().map_or(f64::NAN, |dt| dt.month0() as f64)
self.to_utc().map_or(f64::NAN, |dt| f64::from(dt.month0()))
}
/// `Date.prototype.getUTCSeconds()`
@ -840,7 +843,7 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.getutcseconds
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCSeconds
pub fn get_utc_seconds(&self) -> f64 {
self.to_utc().map_or(f64::NAN, |dt| dt.second() as f64)
self.to_utc().map_or(f64::NAN, |dt| f64::from(dt.second()))
}
/// `Date.prototype.setDate()`
@ -1204,7 +1207,7 @@ impl Date {
// 4. If y is NaN, then
if y.is_nan() {
// a. Set the [[DateValue]] internal slot of this Date object to NaN.
this.set_data(ObjectData::date(Date(None)));
this.set_data(ObjectData::date(Self(None)));
// b. Return NaN.
return Ok(JsValue::nan());
@ -1248,12 +1251,12 @@ impl Date {
let t = t.to_number(context)?;
let seconds = (t / 1_000f64) as i64;
let nanoseconds = ((t % 1_000f64) * 1_000_000f64) as u32;
Date(
Self(
ignore_ambiguity(Local.timestamp_opt(seconds, nanoseconds))
.map(|dt| dt.naive_utc()),
)
} else {
Date(None)
Self(None)
};
// 3. Let v be TimeClip(t).
@ -1793,9 +1796,10 @@ impl Date {
/// [spec]: https://tc39.es/ecma262/#sec-date.prototype.toutcstring
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString
pub fn to_utc_string(self) -> String {
self.to_utc()
.map(|date_time| date_time.format("%a, %d %b %Y %H:%M:%S GMT").to_string())
.unwrap_or_else(|| "Invalid Date".to_string())
self.to_utc().map_or_else(
|| "Invalid Date".to_string(),
|date_time| date_time.format("%a, %d %b %Y %H:%M:%S GMT").to_string(),
)
}
/// `Date.prototype.valueOf()`
@ -1822,6 +1826,7 @@ impl Date {
///
/// [spec]: https://tc39.es/ecma262/#sec-date.now
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn now(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Ok(JsValue::new(Utc::now().timestamp_millis() as f64))
}
@ -1829,7 +1834,7 @@ impl Date {
/// `Date.parse()`
///
/// The `Date.parse()` method parses a string representation of a date, and returns the number of milliseconds since
/// January 1, 1970, 00:00:00 UTC or NaN if the string is unrecognized or, in some cases, contains illegal date
/// January 1, 1970, 00:00:00 UTC or `NaN` if the string is unrecognized or, in some cases, contains illegal date
/// values.
///
/// More information:

212
boa/src/builtins/date/tests.rs

@ -70,7 +70,7 @@ fn date_this_time_value() {
}
#[test]
fn date_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_call() {
let mut context = Context::default();
let dt1 = forward(&mut context, "Date()");
@ -80,11 +80,10 @@ fn date_call() -> Result<(), Box<dyn std::error::Error>> {
let dt2 = forward(&mut context, "Date()");
assert_ne!(dt1, dt2);
Ok(())
}
#[test]
fn date_ctor_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call() {
let mut context = Context::default();
let dt1 = forward_dt_local(&mut context, "new Date()");
@ -94,11 +93,10 @@ fn date_ctor_call() -> Result<(), Box<dyn std::error::Error>> {
let dt2 = forward_dt_local(&mut context, "new Date()");
assert_ne!(dt1, dt2);
Ok(())
}
#[test]
fn date_ctor_call_string() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call_string() {
let mut context = Context::default();
let date_time = forward_dt_utc(&mut context, "new Date('2020-06-08T09:16:15.779-06:30')");
@ -108,20 +106,18 @@ fn date_ctor_call_string() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2020, 06, 08).and_hms_milli(15, 46, 15, 779)),
date_time
);
Ok(())
}
#[test]
fn date_ctor_call_string_invalid() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call_string_invalid() {
let mut context = Context::default();
let date_time = forward_dt_local(&mut context, "new Date('nope')");
assert_eq!(None, date_time);
Ok(())
}
#[test]
fn date_ctor_call_number() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call_number() {
let mut context = Context::default();
let date_time = forward_dt_utc(&mut context, "new Date(1594199775779)");
@ -129,11 +125,10 @@ fn date_ctor_call_number() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2020, 07, 08).and_hms_milli(09, 16, 15, 779)),
date_time
);
Ok(())
}
#[test]
fn date_ctor_call_date() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call_date() {
let mut context = Context::default();
let date_time = forward_dt_utc(&mut context, "new Date(new Date(1594199775779))");
@ -142,11 +137,10 @@ fn date_ctor_call_date() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2020, 07, 08).and_hms_milli(09, 16, 15, 779)),
date_time
);
Ok(())
}
#[test]
fn date_ctor_call_multiple() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call_multiple() {
let mut context = Context::default();
let date_time = forward_dt_local(&mut context, "new Date(2020, 06, 08, 09, 16, 15, 779)");
@ -155,11 +149,10 @@ fn date_ctor_call_multiple() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2020, 07, 08).and_hms_milli(09, 16, 15, 779)),
date_time
);
Ok(())
}
#[test]
fn date_ctor_call_multiple_90s() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call_multiple_90s() {
let mut context = Context::default();
let date_time = forward_dt_local(&mut context, "new Date(99, 06, 08, 09, 16, 15, 779)");
@ -168,11 +161,10 @@ fn date_ctor_call_multiple_90s() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(1999, 07, 08).and_hms_milli(09, 16, 15, 779)),
date_time
);
Ok(())
}
#[test]
fn date_ctor_call_multiple_nan() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_call_multiple_nan() {
fn check(src: &str) {
let mut context = Context::default();
let date_time = forward_dt_local(&mut context, src);
@ -186,48 +178,43 @@ fn date_ctor_call_multiple_nan() -> Result<(), Box<dyn std::error::Error>> {
check("new Date(2020, 06, 08, 09, 1/0, 15, 779)");
check("new Date(2020, 06, 08, 09, 16, 1/0, 779)");
check("new Date(2020, 06, 08, 09, 16, 15, 1/0)");
Ok(())
}
#[test]
fn date_ctor_now_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_now_call() {
let mut context = Context::default();
let date_time = forward(&mut context, "Date.now()");
let dt1 = date_time.parse::<u64>()?;
let dt1 = date_time.parse::<u64>().unwrap();
std::thread::sleep(std::time::Duration::from_millis(1));
let date_time = forward(&mut context, "Date.now()");
let dt2 = date_time.parse::<u64>()?;
let dt2 = date_time.parse::<u64>().unwrap();
assert_ne!(dt1, dt2);
Ok(())
}
#[test]
fn date_ctor_parse_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_parse_call() {
let mut context = Context::default();
let date_time = forward_val(&mut context, "Date.parse('2020-06-08T09:16:15.779-07:30')");
assert_eq!(Ok(JsValue::new(1591634775779f64)), date_time);
Ok(())
}
#[test]
fn date_ctor_utc_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_utc_call() {
let mut context = Context::default();
let date_time = forward_val(&mut context, "Date.UTC(2020, 06, 08, 09, 16, 15, 779)");
assert_eq!(Ok(JsValue::new(1594199775779f64)), date_time);
Ok(())
}
#[test]
fn date_ctor_utc_call_nan() -> Result<(), Box<dyn std::error::Error>> {
fn date_ctor_utc_call_nan() {
fn check(src: &str) {
let mut context = Context::default();
let date_time = forward_val(&mut context, src).expect("Expected Success");
@ -241,12 +228,10 @@ fn date_ctor_utc_call_nan() -> Result<(), Box<dyn std::error::Error>> {
check("Date.UTC(2020, 06, 08, 09, 1/0, 15, 779)");
check("Date.UTC(2020, 06, 08, 09, 16, 1/0, 779)");
check("Date.UTC(2020, 06, 08, 09, 16, 15, 1/0)");
Ok(())
}
#[test]
fn date_proto_get_date_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_date_call() {
let mut context = Context::default();
let actual = forward_val(
@ -257,12 +242,10 @@ fn date_proto_get_date_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getDate()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_day_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_day_call() {
let mut context = Context::default();
let actual = forward_val(
@ -273,11 +256,10 @@ fn date_proto_get_day_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getDay()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_full_year_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_full_year_call() {
let mut context = Context::default();
let actual = forward_val(
@ -288,11 +270,10 @@ fn date_proto_get_full_year_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getFullYear()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_hours_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_hours_call() {
let mut context = Context::default();
let actual = forward_val(
@ -303,11 +284,10 @@ fn date_proto_get_hours_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getHours()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_milliseconds_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_milliseconds_call() {
let mut context = Context::default();
let actual = forward_val(
@ -318,11 +298,10 @@ fn date_proto_get_milliseconds_call() -> Result<(), Box<dyn std::error::Error>>
let actual = forward_val(&mut context, "new Date(1/0).getMilliseconds()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_minutes_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_minutes_call() {
let mut context = Context::default();
let actual = forward_val(
@ -333,11 +312,10 @@ fn date_proto_get_minutes_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getMinutes()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_month() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_month() {
let mut context = Context::default();
let actual = forward_val(
@ -348,12 +326,10 @@ fn date_proto_get_month() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getMonth()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_seconds() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_seconds() {
let mut context = Context::default();
let actual = forward_val(
@ -364,11 +340,10 @@ fn date_proto_get_seconds() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getSeconds()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_time() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_time() {
let mut context = Context::default();
let actual = forward_val(
@ -384,11 +359,10 @@ fn date_proto_get_time() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getTime()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_year() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_year() {
let mut context = Context::default();
let actual = forward_val(
@ -399,11 +373,10 @@ fn date_proto_get_year() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getYear()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_timezone_offset() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_timezone_offset() {
let mut context = Context::default();
let actual = forward_val(
@ -420,7 +393,7 @@ fn date_proto_get_timezone_offset() -> Result<(), Box<dyn std::error::Error>> {
);
// The value of now().offset() depends on the host machine, so we have to replicate the method code here.
let offset_seconds = chrono::Local::now().offset().local_minus_utc() as f64;
let offset_seconds = f64::from(chrono::Local::now().offset().local_minus_utc());
let offset_minutes = -offset_seconds / 60f64;
assert_eq!(Ok(JsValue::new(offset_minutes)), actual);
@ -429,11 +402,10 @@ fn date_proto_get_timezone_offset() -> Result<(), Box<dyn std::error::Error>> {
"new Date('1975-08-19T23:15:30+07:00').getTimezoneOffset()",
);
assert_eq!(Ok(JsValue::new(offset_minutes)), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_date_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_date_call() {
let mut context = Context::default();
let actual = forward_val(
@ -444,12 +416,10 @@ fn date_proto_get_utc_date_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getUTCDate()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_day_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_day_call() {
let mut context = Context::default();
let actual = forward_val(
@ -460,11 +430,10 @@ fn date_proto_get_utc_day_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getUTCDay()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_full_year_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_full_year_call() {
let mut context = Context::default();
let actual = forward_val(
@ -475,11 +444,10 @@ fn date_proto_get_utc_full_year_call() -> Result<(), Box<dyn std::error::Error>>
let actual = forward_val(&mut context, "new Date(1/0).getUTCFullYear()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_hours_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_hours_call() {
let mut context = Context::default();
let actual = forward_val(
@ -490,11 +458,10 @@ fn date_proto_get_utc_hours_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getUTCHours()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_milliseconds_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_milliseconds_call() {
let mut context = Context::default();
let actual = forward_val(
@ -505,11 +472,10 @@ fn date_proto_get_utc_milliseconds_call() -> Result<(), Box<dyn std::error::Erro
let actual = forward_val(&mut context, "new Date(1/0).getUTCMilliseconds()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_minutes_call() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_minutes_call() {
let mut context = Context::default();
let actual = forward_val(
@ -520,11 +486,10 @@ fn date_proto_get_utc_minutes_call() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getUTCMinutes()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_month() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_month() {
let mut context = Context::default();
let actual = forward_val(
@ -535,12 +500,10 @@ fn date_proto_get_utc_month() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getUTCMonth()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_get_utc_seconds() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_get_utc_seconds() {
let mut context = Context::default();
let actual = forward_val(
@ -551,11 +514,10 @@ fn date_proto_get_utc_seconds() -> Result<(), Box<dyn std::error::Error>> {
let actual = forward_val(&mut context, "new Date(1/0).getUTCSeconds()");
assert_eq!(Ok(JsValue::nan()), actual);
Ok(())
}
#[test]
fn date_proto_set_date() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_date() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -582,12 +544,10 @@ fn date_proto_set_date() -> Result<(), Box<dyn std::error::Error>> {
"dt = new Date(2020, 06, 08, 09, 16, 15, 779); dt.setDate(1/0); dt",
);
assert_eq!(None, actual);
Ok(())
}
#[test]
fn date_proto_set_full_year() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_full_year() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -654,12 +614,10 @@ fn date_proto_set_full_year() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2010, 02, 23).and_hms_milli(09, 16, 15, 779)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_hours() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_hours() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -708,12 +666,10 @@ fn date_proto_set_hours() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2021, 09, 11).and_hms_milli(21, 40, 40, 123)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_milliseconds() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_milliseconds() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -736,12 +692,10 @@ fn date_proto_set_milliseconds() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2020, 07, 08).and_hms_milli(09, 16, 55, 123)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_minutes() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_minutes() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -782,12 +736,10 @@ fn date_proto_set_minutes() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2021, 08, 29).and_hms_milli(09, 20, 40, 123)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_month() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_month() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -819,12 +771,10 @@ fn date_proto_set_month() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2023, 07, 22).and_hms_milli(09, 16, 15, 779)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_seconds() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_seconds() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -856,12 +806,10 @@ fn date_proto_set_seconds() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2021, 11, 14).and_hms_milli(08, 23, 20, 123)),
actual
);
Ok(())
}
#[test]
fn set_year() -> Result<(), Box<dyn std::error::Error>> {
fn set_year() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -881,12 +829,10 @@ fn set_year() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2001, 07, 08).and_hms_milli(09, 16, 15, 779)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_time() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_time() {
let mut context = Context::default();
let actual = forward_dt_local(
@ -897,12 +843,10 @@ fn date_proto_set_time() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2020, 07, 08).and_hms_milli(09, 16, 15, 779)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_utc_date() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_utc_date() {
let mut context = Context::default();
let actual = forward_dt_utc(
@ -929,12 +873,10 @@ fn date_proto_set_utc_date() -> Result<(), Box<dyn std::error::Error>> {
"dt = new Date(Date.UTC(2020, 06, 08, 09, 16, 15, 779)); dt.setUTCDate(1/0); dt",
);
assert_eq!(None, actual);
Ok(())
}
#[test]
fn date_proto_set_utc_full_year() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_utc_full_year() {
let mut context = Context::default();
let actual = forward_dt_utc(
@ -1001,12 +943,10 @@ fn date_proto_set_utc_full_year() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2010, 02, 23).and_hms_milli(09, 16, 15, 779)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_utc_hours() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_utc_hours() {
let mut context = Context::default();
let actual = forward_dt_utc(
@ -1055,12 +995,10 @@ fn date_proto_set_utc_hours() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2021, 09, 11).and_hms_milli(21, 40, 40, 123)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_utc_milliseconds() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_utc_milliseconds() {
let mut context = Context::default();
let actual = forward_dt_utc(
@ -1083,12 +1021,10 @@ fn date_proto_set_utc_milliseconds() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2020, 07, 08).and_hms_milli(09, 16, 55, 123)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_utc_minutes() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_utc_minutes() {
let mut context = Context::default();
let actual = forward_dt_utc(
@ -1129,12 +1065,10 @@ fn date_proto_set_utc_minutes() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2021, 08, 29).and_hms_milli(09, 20, 40, 123)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_utc_month() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_utc_month() {
let mut context = Context::default();
let actual = forward_dt_utc(
@ -1166,12 +1100,10 @@ fn date_proto_set_utc_month() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2023, 07, 22).and_hms_milli(09, 16, 15, 779)),
actual
);
Ok(())
}
#[test]
fn date_proto_set_utc_seconds() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_set_utc_seconds() {
let mut context = Context::default();
let actual = forward_dt_utc(
@ -1203,12 +1135,10 @@ fn date_proto_set_utc_seconds() -> Result<(), Box<dyn std::error::Error>> {
Some(NaiveDate::from_ymd(2021, 11, 14).and_hms_milli(08, 23, 20, 123)),
actual
);
Ok(())
}
#[test]
fn date_proto_to_date_string() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_to_date_string() {
let mut context = Context::default();
let actual = forward_val(
@ -1217,12 +1147,10 @@ fn date_proto_to_date_string() -> Result<(), Box<dyn std::error::Error>> {
)
.expect("Successful eval");
assert_eq!(JsValue::new("Wed Jul 08 2020"), actual);
Ok(())
}
#[test]
fn date_proto_to_gmt_string() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_to_gmt_string() {
let mut context = Context::default();
let actual = forward_val(
@ -1231,12 +1159,10 @@ fn date_proto_to_gmt_string() -> Result<(), Box<dyn std::error::Error>> {
)
.expect("Successful eval");
assert_eq!(JsValue::new("Wed, 08 Jul 2020 09:16:15 GMT"), actual);
Ok(())
}
#[test]
fn date_proto_to_iso_string() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_to_iso_string() {
let mut context = Context::default();
let actual = forward_val(
@ -1245,12 +1171,10 @@ fn date_proto_to_iso_string() -> Result<(), Box<dyn std::error::Error>> {
)
.expect("Successful eval");
assert_eq!(JsValue::new("2020-07-08T09:16:15.779Z"), actual);
Ok(())
}
#[test]
fn date_proto_to_json() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_to_json() {
let mut context = Context::default();
let actual = forward_val(
@ -1259,12 +1183,10 @@ fn date_proto_to_json() -> Result<(), Box<dyn std::error::Error>> {
)
.expect("Successful eval");
assert_eq!(JsValue::new("2020-07-08T09:16:15.779Z"), actual);
Ok(())
}
#[test]
fn date_proto_to_string() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_to_string() {
let mut context = Context::default();
let actual = forward_val(
@ -1287,12 +1209,10 @@ fn date_proto_to_string() -> Result<(), Box<dyn std::error::Error>> {
)),
actual
);
Ok(())
}
#[test]
fn date_proto_to_time_string() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_to_time_string() {
let mut context = Context::default();
let actual = forward_val(
@ -1315,12 +1235,10 @@ fn date_proto_to_time_string() -> Result<(), Box<dyn std::error::Error>> {
)),
actual
);
Ok(())
}
#[test]
fn date_proto_to_utc_string() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_to_utc_string() {
let mut context = Context::default();
let actual = forward_val(
@ -1329,12 +1247,10 @@ fn date_proto_to_utc_string() -> Result<(), Box<dyn std::error::Error>> {
)
.expect("Successful eval");
assert_eq!(JsValue::new("Wed, 08 Jul 2020 09:16:15 GMT"), actual);
Ok(())
}
#[test]
fn date_proto_value_of() -> Result<(), Box<dyn std::error::Error>> {
fn date_proto_value_of() {
let mut context = Context::default();
let actual = forward_val(
@ -1343,12 +1259,10 @@ fn date_proto_value_of() -> Result<(), Box<dyn std::error::Error>> {
)
.expect("Successful eval");
assert_eq!(JsValue::new(1594199775779f64), actual);
Ok(())
}
#[test]
fn date_neg() -> Result<(), Box<dyn std::error::Error>> {
fn date_neg() {
let mut context = Context::default();
let actual = forward_val(
@ -1357,12 +1271,10 @@ fn date_neg() -> Result<(), Box<dyn std::error::Error>> {
)
.expect("Successful eval");
assert_eq!(JsValue::new(-1594199775779f64), actual);
Ok(())
}
#[test]
fn date_json() -> Result<(), Box<dyn std::error::Error>> {
fn date_json() {
let mut context = Context::default();
let actual = forward_val(
@ -1374,6 +1286,4 @@ fn date_json() -> Result<(), Box<dyn std::error::Error>> {
JsValue::new(r#"{"date":"2020-07-08T09:16:15.779Z"}"#),
actual
);
Ok(())
}

2
boa/src/builtins/error/syntax.rs

@ -1,6 +1,6 @@
//! This module implements the global `SyntaxError` object.
//!
//! The SyntaxError object represents an error when trying to interpret syntactically invalid code.
//! The `SyntaxError` object represents an error when trying to interpret syntactically invalid code.
//! It is thrown when the JavaScript context encounters tokens or token order that does not conform
//! to the syntax of the language when parsing code.
//!

12
boa/src/builtins/function/arguments.rs

@ -44,7 +44,7 @@ impl Arguments {
// 3. Set obj.[[ParameterMap]] to undefined.
// skipped because the `Arguments` enum ensures ordinary argument objects don't have a `[[ParameterMap]]`
obj.borrow_mut().data = ObjectData::arguments(Arguments::Unmapped);
obj.borrow_mut().data = ObjectData::arguments(Self::Unmapped);
// 4. Perform DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len),
// [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
@ -133,7 +133,7 @@ impl Arguments {
// 11. Set obj.[[ParameterMap]] to map.
let obj = JsObject::from_proto_and_data(
context.standard_objects().object_object().prototype(),
ObjectData::arguments(Arguments::Mapped(MappedArguments(map.clone()))),
ObjectData::arguments(Self::Mapped(MappedArguments(map.clone()))),
);
// 14. Let index be 0.
@ -169,7 +169,9 @@ impl Arguments {
// 19. Repeat, while index ≥ 0,
// a. Let name be parameterNames[index].
for (index, parameter_name_vec) in formals.iter().map(|fp| fp.names()).enumerate().rev() {
for (index, parameter_name_vec) in
formals.iter().map(FormalParameter::names).enumerate().rev()
{
for parameter_name in parameter_name_vec.iter().copied() {
// b. If name is not an element of mappedNames, then
if !mapped_names.contains(&parameter_name) {
@ -190,7 +192,7 @@ impl Arguments {
|_, _, captures, context| {
captures.0.get_binding_value(captures.1, false, context)
},
(env.clone(), parameter_name.to_owned()),
(env.clone(), parameter_name),
)
.length(0)
.name("")
@ -215,7 +217,7 @@ impl Arguments {
.map(|_| JsValue::Undefined)
// Ok(JsValue::Undefined)
},
(env.clone(), parameter_name.to_owned()),
(env.clone(), parameter_name),
)
.length(1)
.name("")

11
boa/src/builtins/function/mod.rs

@ -2,7 +2,7 @@
//!
//! Objects wrap `Function`s and expose them via call/construct slots.
//!
//! `The `Function` object is used for matching text with a pattern.
//! The `Function` object is used for matching text with a pattern.
//!
//! More information:
//! - [ECMAScript reference][spec]
@ -158,7 +158,8 @@ impl Captures {
/// Boa representation of a Function Object.
///
/// FunctionBody is specific to this interpreter, it will either be Rust code or JavaScript code (AST Node)
/// `FunctionBody` is specific to this interpreter, it will either be Rust code or JavaScript code
/// (AST Node).
///
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects>
#[derive(Trace, Finalize)]
@ -190,8 +191,7 @@ impl Function {
/// Returns true if the function object is a constructor.
pub fn is_constructor(&self) -> bool {
match self {
Self::Native { constructor, .. } => *constructor,
Self::Closure { constructor, .. } => *constructor,
Self::Native { constructor, .. } | Self::Closure { constructor, .. } => *constructor,
Self::VmOrdinary { code, .. } => code.constructor,
}
}
@ -477,6 +477,7 @@ impl BuiltInFunctionObject {
Ok(JsValue::ordinary_has_instance(this, args.get_or_undefined(0), context)?.into())
}
#[allow(clippy::unnecessary_wraps)]
fn prototype(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Ok(JsValue::undefined())
}
@ -623,7 +624,7 @@ impl BoundFunction {
Ok(JsObject::from_proto_and_data(
proto,
ObjectData::bound_function(
BoundFunction {
Self {
target_function,
this,
args,

2
boa/src/builtins/function/tests.rs

@ -142,7 +142,7 @@ fn function_prototype_call_throw() {
let value = forward_val(&mut context, throw).unwrap_err();
assert!(value.is_object());
let string = value.to_string(&mut context).unwrap();
assert!(string.starts_with("TypeError"))
assert!(string.starts_with("TypeError"));
}
#[test]

2
boa/src/builtins/intl/mod.rs

@ -132,7 +132,7 @@ impl Intl {
let ll = Self::canonicalize_locale_list(args, context)?;
// 2. Return CreateArrayFromList(ll).
Ok(JsValue::Object(Array::create_array_from_list(
ll.into_iter().map(|x| x.into()),
ll.into_iter().map(Into::into),
context,
)))
}

2
boa/src/builtins/intrinsics.rs

@ -11,7 +11,7 @@ pub struct IntrinsicObjects {
}
impl IntrinsicObjects {
pub fn init(context: &mut Context) -> IntrinsicObjects {
pub fn init(context: &mut Context) -> Self {
Self {
throw_type_error: create_throw_type_error(context),
}

14
boa/src/builtins/iterable/mod.rs

@ -75,7 +75,7 @@ impl IteratorPrototypes {
/// `CreateIterResultObject( value, done )`
///
/// Generates an object supporting the IteratorResult interface.
/// Generates an object supporting the `IteratorResult` interface.
pub fn create_iter_result_object(value: JsValue, done: bool, context: &mut Context) -> JsValue {
// 1. Assert: Type(done) is Boolean.
// 2. Let obj be ! OrdinaryObjectCreate(%Object.prototype%).
@ -109,7 +109,7 @@ impl JsValue {
&self,
context: &mut Context,
hint: Option<IteratorHint>,
method: Option<JsValue>,
method: Option<Self>,
) -> JsResult<IteratorRecord> {
// 1. If hint is not present, set hint to sync.
let hint = hint.unwrap_or(IteratorHint::Sync);
@ -130,7 +130,7 @@ impl JsValue {
// 1. Let syncMethod be ? GetMethod(obj, @@iterator).
let sync_method = self
.get_method(WellKnownSymbols::iterator(), context)?
.map_or(JsValue::Undefined, JsValue::from);
.map_or(Self::Undefined, Self::from);
// 2. Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod).
let _sync_iterator_record =
self.get_iterator(context, Some(IteratorHint::Sync), Some(sync_method));
@ -140,7 +140,7 @@ impl JsValue {
} else {
// b. Otherwise, set method to ? GetMethod(obj, @@iterator).
self.get_method(WellKnownSymbols::iterator(), context)?
.map_or(JsValue::Undefined, JsValue::from)
.map_or(Self::Undefined, Self::from)
}
};
@ -161,7 +161,7 @@ impl JsValue {
}
}
/// Create the %IteratorPrototype% object
/// Create the `%IteratorPrototype%` object
///
/// More information:
/// - [ECMA reference][spec]
@ -277,7 +277,7 @@ impl IteratorRecord {
/// [spec]: https://tc39.es/ecma262/#sec-iterabletolist
pub(crate) fn iterable_to_list(
context: &mut Context,
items: JsValue,
items: &JsValue,
method: Option<JsValue>,
) -> JsResult<Vec<JsValue>> {
// 1. If method is present, then
@ -305,7 +305,7 @@ pub(crate) fn iterable_to_list(
break;
}
values.push(next.value)
values.push(next.value);
}
// 6. Return values.

27
boa/src/builtins/json/mod.rs

@ -232,7 +232,7 @@ impl Json {
// a. If IsCallable(replacer) is true, then
if replacer_obj.is_callable() {
// i. Set ReplacerFunction to replacer.
replacer_function = Some(replacer_obj.clone())
replacer_function = Some(replacer_obj.clone());
// b. Else,
} else {
// i. Let isArray be ? IsArray(replacer).
@ -260,7 +260,7 @@ impl Json {
// g. If item is not undefined and item is not currently an element of PropertyList, then
// i. Append item to the end of PropertyList.
if let Some(s) = v.as_string() {
property_set.insert(s.to_owned());
property_set.insert(s.clone());
} else if v.is_number() {
property_set.insert(
v.to_string(context)
@ -348,7 +348,7 @@ impl Json {
// 12. Return ? SerializeJSONProperty(state, the empty String, wrapper).
Ok(
Self::serialize_json_property(&mut state, JsString::new(""), &wrapper, context)?
.map(|s| s.into())
.map(Into::into)
.unwrap_or_default(),
)
}
@ -385,7 +385,7 @@ impl Json {
// 3. If state.[[ReplacerFunction]] is not undefined, then
if let Some(obj) = &state.replacer_function {
// a. Set value to ? Call(state.[[ReplacerFunction]], holder, « key, value »).
value = obj.call(&holder.clone().into(), &[key.into(), value], context)?
value = obj.call(&holder.clone().into(), &[key.into(), value], context)?;
}
// 4. If Type(value) is Object, then
@ -403,12 +403,12 @@ impl Json {
// c. Else if value has a [[BooleanData]] internal slot, then
else if let Some(boolean) = obj.borrow().as_boolean() {
// i. Set value to value.[[BooleanData]].
value = boolean.into()
value = boolean.into();
}
// d. Else if value has a [[BigIntData]] internal slot, then
else if let Some(bigint) = obj.borrow().as_bigint() {
// i. Set value to value.[[BigIntData]].
value = bigint.clone().into()
value = bigint.clone().into();
}
}
@ -420,10 +420,11 @@ impl Json {
// 6. If value is true, return "true".
// 7. If value is false, return "false".
if value.is_boolean() {
return match value.to_boolean() {
true => Ok(Some(JsString::new("true"))),
false => Ok(Some(JsString::new("false"))),
};
return Ok(Some(JsString::new(if value.to_boolean() {
"true"
} else {
"false"
})));
}
// 8. If Type(value) is String, return QuoteJSONString(value).
@ -503,7 +504,7 @@ impl Json {
code_point => {
// i. Set product to the string-concatenation of product and ! UTF16EncodeCodePoint(C).
product.push(
char::from_u32(code_point as u32)
char::from_u32(u32::from(code_point))
.expect("char from code point cannot fail here"),
);
}
@ -674,11 +675,11 @@ impl Json {
// b. If strP is undefined, then
if let Some(str_p) = str_p {
// i. Append strP to partial.
partial.push(str_p)
partial.push(str_p);
// c. Else,
} else {
// i. Append "null" to partial.
partial.push("null".into())
partial.push("null".into());
}
// d. Set index to index + 1.

8
boa/src/builtins/map/map_iterator.rs

@ -25,7 +25,7 @@ pub struct MapIterator {
impl MapIterator {
pub(crate) const NAME: &'static str = "MapIterator";
/// Abstract operation CreateMapIterator( map, kind )
/// Abstract operation `CreateMapIterator( map, kind )`
///
/// Creates a new iterator over the given map.
///
@ -41,7 +41,7 @@ impl MapIterator {
if let Some(map_obj) = map.as_object() {
if let Some(map) = map_obj.borrow_mut().as_map_mut() {
let lock = map.lock(map_obj.clone());
let iter = MapIterator {
let iter = Self {
iterated_map: Some(map_obj.clone()),
map_next_index: 0,
map_iteration_kind: kind,
@ -66,7 +66,7 @@ impl MapIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%mapiteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut map_iterator = this.as_object().map(|obj| obj.borrow_mut());
let mut map_iterator = this.as_object().map(JsObject::borrow_mut);
let map_iterator = map_iterator
.as_mut()
.and_then(|obj| obj.as_map_iterator_mut())
@ -110,7 +110,7 @@ impl MapIterator {
))
}
/// Create the %MapIteratorPrototype% object
/// Create the `%MapIteratorPrototype%` object
///
/// More information:
/// - [ECMA reference][spec]

7
boa/src/builtins/map/mod.rs

@ -161,6 +161,7 @@ impl Map {
///
/// [spec]: https://tc39.es/ecma262/#sec-get-map-@@species
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@species
#[allow(clippy::unnecessary_wraps)]
fn get_species(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// 1. Return the this value.
Ok(this.clone())
@ -330,10 +331,9 @@ impl Map {
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let key = args.get_or_undefined(0);
const JS_ZERO: &JsValue = &JsValue::Rational(0f64);
let key = args.get_or_undefined(0);
let key = match key {
JsValue::Rational(r) => {
if r.is_zero() {
@ -403,10 +403,9 @@ impl Map {
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let key = args.get_or_undefined(0);
const JS_ZERO: &JsValue = &JsValue::Rational(0f64);
let key = args.get_or_undefined(0);
let key = match key {
JsValue::Rational(r) => {
if r.is_zero() {

12
boa/src/builtins/map/ordered_map.rs

@ -31,12 +31,12 @@ impl Equivalent<MapKey> for JsValue {
fn equivalent(&self, key: &MapKey) -> bool {
match key {
MapKey::Key(v) => v == self,
_ => false,
MapKey::Empty(_) => false,
}
}
}
/// A newtype wrapping indexmap::IndexMap
/// A structure wrapping `indexmap::IndexMap`.
#[derive(Clone)]
pub struct OrderedMap<V, S = RandomState> {
map: IndexMap<MapKey, Option<V>, S>,
@ -70,7 +70,7 @@ impl<V> Default for OrderedMap<V> {
impl<V> OrderedMap<V> {
pub fn new() -> Self {
OrderedMap {
Self {
map: IndexMap::new(),
lock: 0,
empty_count: 0,
@ -78,7 +78,7 @@ impl<V> OrderedMap<V> {
}
pub fn with_capacity(capacity: usize) -> Self {
OrderedMap {
Self {
map: IndexMap::with_capacity(capacity),
lock: 0,
empty_count: 0,
@ -147,7 +147,7 @@ impl<V> OrderedMap<V> {
pub fn clear(&mut self) {
self.map.clear();
self.map.shrink_to_fit();
self.empty_count = 0
self.empty_count = 0;
}
/// Return a reference to the value stored for `key`, if it is present,
@ -160,7 +160,7 @@ impl<V> OrderedMap<V> {
/// Get a key-value pair by index.
///
/// Valid indices are 0 <= index < self.full_len().
/// Valid indices are `0 <= index < self.full_len()`.
///
/// Computes in O(1) time.
pub fn get_index(&self, index: usize) -> Option<(&JsValue, &V)> {

5
boa/src/builtins/math/mod.rs

@ -83,7 +83,7 @@ impl BuiltIn for Math {
.function(Self::trunc, "trunc", 1)
.property(
string_tag,
Math::NAME,
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
@ -466,7 +466,7 @@ impl Math {
// 4. Let n32 be the result of converting n to a value in IEEE 754-2019 binary32 format using roundTiesToEven mode.
// 5. Let n64 be the result of converting n32 to a value in IEEE 754-2019 binary64 format.
// 6. Return the ECMAScript Number value corresponding to n64.
Ok((x as f32 as f64).into())
Ok(f64::from(x as f32).into())
}
/// Get an approximation of the square root of the sum of squares of all arguments.
@ -715,6 +715,7 @@ impl Math {
///
/// [spec]: https://tc39.es/ecma262/#sec-math.random
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn random(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// NOTE: Each Math.random function created for distinct realms must produce a distinct sequence of values from successive calls.
Ok(rand::random::<f64>().into())

6
boa/src/builtins/number/conversions.rs

@ -36,10 +36,10 @@ pub(crate) fn f64_to_int32(number: f64) -> i32 {
let d64 = number.to_bits();
let significand = d64 & SIGNIFICAND_MASK;
if !is_denormal(number) {
significand + HIDDEN_BIT
} else {
if is_denormal(number) {
significand
} else {
significand + HIDDEN_BIT
}
}

94
boa/src/builtins/number/mod.rs

@ -4,7 +4,7 @@
//! A `Number` object is created using the `Number()` constructor. A primitive type object number is created using the `Number()` **function**.
//!
//! The JavaScript `Number` type is double-precision 64-bit binary format IEEE 754 value. In more recent implementations,
//! JavaScript also supports integers with arbitrary precision using the BigInt type.
//! JavaScript also supports integers with arbitrary precision using the `BigInt` type.
//!
//! More information:
//! - [ECMAScript reference][spec]
@ -301,7 +301,7 @@ impl Number {
Ok(JsValue::new(this_str_num))
}
/// flt_str_to_exp - used in to_precision
/// `flt_str_to_exp` - used in `to_precision`
///
/// This function traverses a string representing a number,
/// returning the floored log10 of this number.
@ -325,7 +325,7 @@ impl Number {
(flt.len() as i32) - 1
}
/// round_to_precision - used in to_precision
/// `round_to_precision` - used in `to_precision`
///
/// This procedure has two roles:
/// - If there are enough or more than enough digits in the
@ -367,14 +367,14 @@ impl Number {
}
}
digits.clear();
let replacement = if !propagated {
let replacement = if propagated {
replacement.as_str()
} else {
digits.push('1');
&replacement.as_str()[1..]
} else {
replacement.as_str()
};
for c in replacement.chars().rev() {
digits.push(c)
digits.push(c);
}
!propagated
} else {
@ -541,7 +541,7 @@ impl Number {
let mut fraction_cursor = 0;
let negative = value.is_sign_negative();
if negative {
value = -value
value = -value;
}
// Split the value into an integer part and a fractional part.
// let mut integer = value.trunc();
@ -559,15 +559,15 @@ impl Number {
fraction_cursor += 1;
loop {
// Shift up by one digit.
fraction *= radix as f64;
delta *= radix as f64;
fraction *= f64::from(radix);
delta *= f64::from(radix);
// Write digit.
let digit = fraction as u32;
frac_buf[fraction_cursor] =
std::char::from_digit(digit, radix as u32).unwrap() as u8;
std::char::from_digit(digit, u32::from(radix)).unwrap() as u8;
fraction_cursor += 1;
// Calculate remainder.
fraction -= digit as f64;
fraction -= f64::from(digit);
// Round to even.
if fraction + delta > 1.0
&& (fraction > 0.5 || (fraction - 0.5).abs() < f64::EPSILON && digit & 1 != 0)
@ -583,11 +583,11 @@ impl Number {
let c: u8 = frac_buf[fraction_cursor];
// Reconstruct digit.
let digit_0 = (c as char).to_digit(10).unwrap();
if digit_0 + 1 >= radix as u32 {
if digit_0 + 1 >= u32::from(radix) {
continue;
}
frac_buf[fraction_cursor] =
std::char::from_digit(digit_0 + 1, radix as u32).unwrap() as u8;
std::char::from_digit(digit_0 + 1, u32::from(radix)).unwrap() as u8;
fraction_cursor += 1;
}
break;
@ -603,15 +603,15 @@ impl Number {
// Compute integer digits. Fill unrepresented digits with zero.
let mut int_iter = int_buf.iter_mut().enumerate().rev(); //.rev();
while FloatCore::integer_decode(integer / f64::from(radix)).1 > 0 {
integer /= radix as f64;
integer /= f64::from(radix);
*int_iter.next().unwrap().1 = b'0';
}
loop {
let remainder = integer % (radix as f64);
let remainder = integer % f64::from(radix);
*int_iter.next().unwrap().1 =
std::char::from_digit(remainder as u32, radix as u32).unwrap() as u8;
integer = (integer - remainder) / radix as f64;
std::char::from_digit(remainder as u32, u32::from(radix)).unwrap() as u8;
integer = (integer - remainder) / f64::from(radix);
if integer <= 0f64 {
break;
}
@ -761,6 +761,7 @@ impl Number {
let mut strip_prefix = true;
// 8. If R ≠ 0, then
#[allow(clippy::if_not_else)]
if var_r != 0 {
// a. If R < 2 or R > 36, return NaN.
if !(2..=36).contains(&var_r) {
@ -769,7 +770,7 @@ impl Number {
// b. If R ≠ 16, set stripPrefix to false.
if var_r != 16 {
strip_prefix = false
strip_prefix = false;
}
} else {
// 9. Else,
@ -823,9 +824,9 @@ impl Number {
if math_int == 0_f64 {
if sign == -1 {
return Ok(JsValue::new(-0_f64));
} else {
return Ok(JsValue::new(0_f64));
}
return Ok(JsValue::new(0_f64));
}
// 16. Return 𝔽(sign × mathInt).
@ -873,15 +874,16 @@ impl Number {
// Prevent fast_float from parsing "inf", "+inf" as Infinity and "-inf" as -Infinity
Ok(JsValue::nan())
} else {
Ok(fast_float::parse_partial::<f64, _>(s)
.map(|(f, len)| {
Ok(fast_float::parse_partial::<f64, _>(s).map_or_else(
|_| JsValue::nan(),
|(f, len)| {
if len > 0 {
JsValue::new(f)
} else {
JsValue::nan()
}
})
.unwrap_or_else(|_| JsValue::nan()))
},
))
}
} else {
// Not enough arguments to parseFloat.
@ -893,7 +895,7 @@ impl Number {
///
/// Converts the argument to a number, throwing a type error if the conversion is invalid.
///
/// If the number is NaN, +∞, or -∞ false is returned.
/// If the number is `NaN`, `+∞`, or `-∞`, `false` is returned.
///
/// Otherwise true is returned.
///
@ -920,7 +922,7 @@ impl Number {
///
/// Converts the argument to a number, throwing a type error if the conversion is invalid.
///
/// If the number is NaN true is returned.
/// If the number is `NaN`, `true` is returned.
///
/// Otherwise false is returned.
///
@ -947,7 +949,7 @@ impl Number {
///
/// Checks if the argument is a number, returning false if it isn't.
///
/// If the number is NaN, +∞, or -∞ false is returned.
/// If the number is `NaN`, `+∞`, or `-∞`, `false` is returned.
///
/// Otherwise true is returned.
///
@ -957,6 +959,7 @@ impl Number {
///
/// [spec]: https://tc39.es/ecma262/#sec-number.isfinite
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn number_is_finite(
_: &JsValue,
args: &[JsValue],
@ -983,6 +986,7 @@ impl Number {
///
/// [spec]: https://tc39.es/ecma262/#sec-number.isinteger
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn number_is_integer(
_: &JsValue,
args: &[JsValue],
@ -995,7 +999,7 @@ impl Number {
///
/// Checks if the argument is a number, returning false if it isn't.
///
/// If the number is NaN true is returned.
/// If the number is `NaN`, `true` is returned.
///
/// Otherwise false is returned.
///
@ -1005,27 +1009,26 @@ impl Number {
///
/// [spec]: https://tc39.es/ecma262/#sec-isnan-number
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn number_is_nan(
_: &JsValue,
args: &[JsValue],
_ctx: &mut Context,
) -> JsResult<JsValue> {
Ok(JsValue::new(if let Some(val) = args.get(0) {
match val {
JsValue::Integer(_) => false,
JsValue::Rational(number) => number.is_nan(),
_ => false,
}
} else {
false
}))
Ok(JsValue::new(
if let Some(&JsValue::Rational(number)) = args.get(0) {
number.is_nan()
} else {
false
},
))
}
/// `Number.isSafeInteger( number )`
///
/// Checks if the argument is an integer, returning false if it isn't.
///
/// If abs(number) ≤ MAX_SAFE_INTEGER true is returned.
/// If `abs(number) ≤ MAX_SAFE_INTEGER`, `true` is returned.
///
/// Otherwise false is returned.
///
@ -1035,6 +1038,7 @@ impl Number {
///
/// [spec]: https://tc39.es/ecma262/#sec-isnan-number
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn is_safe_integer(
_: &JsValue,
args: &[JsValue],
@ -1043,13 +1047,13 @@ impl Number {
Ok(JsValue::new(match args.get(0) {
Some(JsValue::Integer(_)) => true,
Some(JsValue::Rational(number)) if Self::is_float_integer(*number) => {
number.abs() <= Number::MAX_SAFE_INTEGER
number.abs() <= Self::MAX_SAFE_INTEGER
}
_ => false,
}))
}
/// Checks if the argument is a finite integer Number value.
/// Checks if the argument is a finite integer number value.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -1059,7 +1063,7 @@ impl Number {
pub(crate) fn is_integer(val: &JsValue) -> bool {
match val {
JsValue::Integer(_) => true,
JsValue::Rational(number) => Number::is_float_integer(*number),
JsValue::Rational(number) => Self::is_float_integer(*number),
_ => false,
}
}
@ -1071,7 +1075,7 @@ impl Number {
number.is_finite() && number.abs().floor() == number.abs()
}
/// The abstract operation Number::equal takes arguments
/// The abstract operation `Number::equal` takes arguments
/// x (a Number) and y (a Number). It performs the following steps when called:
///
/// <https://tc39.es/ecma262/#sec-numeric-types-number-equal>
@ -1081,7 +1085,7 @@ impl Number {
x == y
}
/// The abstract operation Number::sameValue takes arguments
/// The abstract operation `Number::sameValue` takes arguments
/// x (a Number) and y (a Number). It performs the following steps when called:
///
/// <https://tc39.es/ecma262/#sec-numeric-types-number-sameValue>
@ -1093,7 +1097,7 @@ impl Number {
a == b && a.signum() == b.signum()
}
/// The abstract operation Number::sameValueZero takes arguments
/// The abstract operation `Number::sameValueZero` takes arguments
/// x (a Number) and y (a Number). It performs the following steps when called:
///
/// <https://tc39.es/ecma262/#sec-numeric-types-number-sameValueZero>

12
boa/src/builtins/object/for_in_iterator.rs

@ -10,7 +10,7 @@ use crate::{
use rustc_hash::FxHashSet;
use std::collections::VecDeque;
/// The ForInIterator object represents an iteration over some specific object.
/// The `ForInIterator` object represents an iteration over some specific object.
/// It implements the iterator protocol.
///
/// More information:
@ -29,7 +29,7 @@ impl ForInIterator {
pub(crate) const NAME: &'static str = "ForInIterator";
fn new(object: JsValue) -> Self {
ForInIterator {
Self {
object,
visited_keys: FxHashSet::default(),
remaining_keys: VecDeque::default(),
@ -37,7 +37,7 @@ impl ForInIterator {
}
}
/// CreateForInIterator( object )
/// `CreateForInIterator( object )`
///
/// Creates a new iterator over the given object.
///
@ -62,7 +62,7 @@ impl ForInIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%foriniteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut iterator = this.as_object().map(|obj| obj.borrow_mut());
let mut iterator = this.as_object().map(JsObject::borrow_mut);
let iterator = iterator
.as_mut()
.and_then(|obj| obj.as_for_in_iterator_mut())
@ -79,7 +79,7 @@ impl ForInIterator {
PropertyKey::Index(i) => {
iterator.remaining_keys.push_back(i.to_string().into());
}
_ => {}
PropertyKey::Symbol(_) => {}
}
}
iterator.object_was_visited = true;
@ -118,7 +118,7 @@ impl ForInIterator {
}
}
/// Create the %ArrayIteratorPrototype% object
/// Create the `%ArrayIteratorPrototype%` object
///
/// More information:
/// - [ECMA reference][spec]

22
boa/src/builtins/object/mod.rs

@ -23,7 +23,7 @@ use crate::{
property::{Attribute, PropertyDescriptor, PropertyKey, PropertyNameKind},
symbol::WellKnownSymbols,
value::JsValue,
BoaProfiler, Context, JsResult,
BoaProfiler, Context, JsResult, JsString,
};
use super::Array;
@ -148,7 +148,7 @@ impl Object {
};
if !properties.is_undefined() {
object_define_properties(&obj, properties.clone(), context)?;
object_define_properties(&obj, properties, context)?;
return Ok(obj.into());
}
@ -287,7 +287,7 @@ impl Object {
}
}
/// Uses the SameValue algorithm to check equality of objects
/// Uses the `SameValue` algorithm to check equality of objects
pub fn is(_: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
let x = args.get_or_undefined(0);
let y = args.get_or_undefined(1);
@ -441,7 +441,7 @@ impl Object {
let arg = args.get_or_undefined(0);
if let JsValue::Object(obj) = arg {
let props = args.get_or_undefined(1);
object_define_properties(obj, props.clone(), context)?;
object_define_properties(obj, props, context)?;
Ok(arg.clone())
} else {
context.throw_type_error("Expected an object")
@ -517,7 +517,7 @@ impl Object {
let tag = o.get(WellKnownSymbols::to_string_tag(), context)?;
// 16. If Type(tag) is not String, set tag to builtinTag.
let tag_str = tag.as_string().map(|s| s.as_str()).unwrap_or(builtin_tag);
let tag_str = tag.as_string().map_or(builtin_tag, JsString::as_str);
// 17. Return the string-concatenation of "[object ", tag, and "]".
Ok(format!("[object {}]", tag_str).into())
@ -951,7 +951,7 @@ impl Object {
}
}
/// The abstract operation ObjectDefineProperties
/// The abstract operation `ObjectDefineProperties`
///
/// More information:
/// - [ECMAScript reference][spec]
@ -960,7 +960,7 @@ impl Object {
#[inline]
fn object_define_properties(
object: &JsObject,
props: JsValue,
props: &JsValue,
context: &mut Context,
) -> JsResult<()> {
// 1. Assert: Type(O) is Object.
@ -1003,14 +1003,14 @@ fn object_define_properties(
Ok(())
}
/// Type enum used in the abstract operation GetOwnPropertyKeys
/// Type enum used in the abstract operation `GetOwnPropertyKeys`.
#[derive(Debug, Copy, Clone)]
enum PropertyKeyType {
String,
Symbol,
}
/// The abstract operation GetOwnPropertyKeys
/// The abstract operation `GetOwnPropertyKeys`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -1033,9 +1033,9 @@ fn get_own_property_keys(
// a. If Type(nextKey) is Symbol and type is symbol or Type(nextKey) is String and type is string, then
// i. Append nextKey as the last element of nameList.
match (r#type, &next_key) {
(PropertyKeyType::String, PropertyKey::String(_)) => Some(next_key.into()),
(PropertyKeyType::String, PropertyKey::String(_))
| (PropertyKeyType::Symbol, PropertyKey::Symbol(_)) => Some(next_key.into()),
(PropertyKeyType::String, PropertyKey::Index(index)) => Some(index.to_string().into()),
(PropertyKeyType::Symbol, PropertyKey::Symbol(_)) => Some(next_key.into()),
_ => None,
}
});

2
boa/src/builtins/object/tests.rs

@ -172,7 +172,7 @@ fn object_property_is_enumerable() {
assert_eq!(
forward(&mut context, r#"x.propertyIsEnumerable()"#),
"false",
)
);
}
#[test]

32
boa/src/builtins/reflect/mod.rs

@ -12,7 +12,7 @@
use crate::{
builtins::{self, BuiltIn},
object::ObjectInitializer,
object::{JsObject, ObjectInitializer},
property::Attribute,
symbol::WellKnownSymbols,
BoaProfiler, Context, JsResult, JsValue,
@ -79,7 +79,7 @@ impl Reflect {
pub(crate) fn apply(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be a function"))?;
let this_arg = args.get_or_undefined(1);
let args_list = args.get_or_undefined(2);
@ -106,7 +106,7 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be a function"))?;
let args_list = args.get_or_undefined(1);
@ -115,7 +115,7 @@ impl Reflect {
}
let new_target = if let Some(new_target) = args.get(2) {
if new_target.as_object().map(|o| o.is_constructor()) != Some(true) {
if new_target.as_object().map(JsObject::is_constructor) != Some(true) {
return context.throw_type_error("newTarget must be constructor");
}
new_target.clone()
@ -142,7 +142,7 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
let key = args.get_or_undefined(1).to_property_key(context)?;
let prop_desc: JsValue = args
@ -153,7 +153,7 @@ impl Reflect {
target
.__define_own_property__(key, prop_desc.to_property_descriptor(context)?, context)
.map(|b| b.into())
.map(Into::into)
}
/// Defines a property on an object.
@ -171,7 +171,7 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
let key = args.get_or_undefined(1).to_property_key(context)?;
@ -190,7 +190,7 @@ impl Reflect {
// 1. If Type(target) is not Object, throw a TypeError exception.
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
// 2. Let key be ? ToPropertyKey(propertyKey).
let key = args.get_or_undefined(1).to_property_key(context)?;
@ -246,7 +246,7 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
Ok(target
.__get_prototype_of__(context)?
@ -264,7 +264,7 @@ impl Reflect {
pub(crate) fn has(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
let key = args
.get(1)
@ -288,7 +288,7 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
Ok(target.__is_extensible__(context)?.into())
}
@ -308,13 +308,13 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
let keys: Vec<JsValue> = target
.__own_property_keys__(context)?
.into_iter()
.map(|key| key.into())
.map(Into::into)
.collect();
Ok(Array::create_array_from_list(keys, context).into())
@ -335,7 +335,7 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
Ok(target.__prevent_extensions__(context)?.into())
@ -352,7 +352,7 @@ impl Reflect {
pub(crate) fn set(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
let key = args.get_or_undefined(1).to_property_key(context)?;
let value = args.get_or_undefined(2);
@ -381,7 +381,7 @@ impl Reflect {
) -> JsResult<JsValue> {
let target = args
.get(0)
.and_then(|v| v.as_object())
.and_then(JsValue::as_object)
.ok_or_else(|| context.construct_type_error("target must be an object"))?;
let proto = match args.get_or_undefined(1) {
JsValue::Object(obj) => Some(obj.clone()),

101
boa/src/builtins/regexp/mod.rs

@ -1,6 +1,6 @@
//! This module implements the global `RegExp` object.
//!
//! `The `RegExp` object is used for matching text with a pattern.
//! The `RegExp` object is used for matching text with a pattern.
//!
//! More information:
//! - [ECMAScript reference][spec]
@ -237,10 +237,10 @@ impl RegExp {
};
// 7. Let O be ? RegExpAlloc(newTarget).
let o = RegExp::alloc(new_target, &[], context)?;
let o = Self::alloc(new_target, &[], context)?;
// 8.Return ? RegExpInitialize(O, P, F).
RegExp::initialize(&o, &[p, f], context)
Self::initialize(&o, &[p, f], context)
}
/// `22.2.3.2.1 RegExpAlloc ( newTarget )`
@ -335,7 +335,7 @@ impl RegExp {
Ok(val) => val,
};
let regexp = RegExp {
let regexp = Self {
matcher,
dot_all,
global,
@ -361,19 +361,19 @@ impl RegExp {
/// [spec]: https://tc39.es/ecma262/#sec-regexpcreate
pub(crate) fn create(p: JsValue, f: JsValue, context: &mut Context) -> JsResult<JsValue> {
// 1. Let obj be ? RegExpAlloc(%RegExp%).
let obj = RegExp::alloc(
&context.global_object().get(RegExp::NAME, context)?,
let obj = Self::alloc(
&context.global_object().get(Self::NAME, context)?,
&[],
context,
)?;
// 2. Return ? RegExpInitialize(obj, P, F).
RegExp::initialize(&obj, &[p, f], context)
Self::initialize(&obj, &[p, f], context)
}
/// `get RegExp [ @@species ]`
///
/// The `RegExp [ @@species ]` accessor property returns the RegExp constructor.
/// The `RegExp [ @@species ]` accessor property returns the `RegExp` constructor.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -381,6 +381,7 @@ impl RegExp {
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp-@@species
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@species
#[allow(clippy::unnecessary_wraps)]
fn get_species(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// 1. Return the this value.
Ok(this.clone())
@ -639,7 +640,10 @@ impl RegExp {
// 5. Let src be R.[[OriginalSource]].
// 6. Let flags be R.[[OriginalFlags]].
// 7. Return EscapeRegExpPattern(src, flags).
RegExp::escape_pattern(&re.original_source, &re.original_flags)
Ok(Self::escape_pattern(
&re.original_source,
&re.original_flags,
))
}
}
} else {
@ -653,9 +657,9 @@ impl RegExp {
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-escaperegexppattern
fn escape_pattern(src: &str, _flags: &str) -> JsResult<JsValue> {
fn escape_pattern(src: &str, _flags: &str) -> JsValue {
if src.is_empty() {
Ok(JsValue::new("(?:)"))
JsValue::new("(?:)")
} else {
let mut s = String::from("");
@ -668,7 +672,7 @@ impl RegExp {
}
}
Ok(JsValue::new(s))
JsValue::new(s)
}
}
@ -744,7 +748,7 @@ impl RegExp {
let arg_str = args.get_or_undefined(0).to_string(context)?;
// 4. Return ? RegExpBuiltinExec(R, S).
if let Some(v) = Self::abstract_builtin_exec(obj, arg_str, context)? {
if let Some(v) = Self::abstract_builtin_exec(obj, &arg_str, context)? {
Ok(v.into())
} else {
Ok(JsValue::null())
@ -788,7 +792,7 @@ impl RegExp {
}
// 6. Return ? RegExpBuiltinExec(R, S).
Self::abstract_builtin_exec(this, input, context)
Self::abstract_builtin_exec(this, &input, context)
}
/// `22.2.5.2.2 RegExpBuiltinExec ( R, S )`
@ -799,7 +803,7 @@ impl RegExp {
/// [spec]: https://tc39.es/ecma262/#sec-regexpbuiltinexec
pub(crate) fn abstract_builtin_exec(
this: &JsObject,
input: JsString,
input: &JsString,
context: &mut Context,
) -> JsResult<Option<JsObject>> {
// 1. Assert: R is an initialized RegExp instance.
@ -866,7 +870,7 @@ impl RegExp {
.throw_type_error("Failed to get byte index from utf16 encoded string")
}
};
let r = matcher.find_from(&input, last_byte_index).next();
let r = matcher.find_from(input, last_byte_index).next();
match r {
// c. If r is failure, then
@ -881,12 +885,12 @@ impl RegExp {
}
// ii. Set lastIndex to AdvanceStringIndex(S, lastIndex, fullUnicode).
last_index = advance_string_index(input.clone(), last_index, unicode);
last_index = advance_string_index(input, last_index, unicode);
}
Some(m) => {
// c. If r is failure, then
// d. Else,
#[allow(clippy::if_not_else)]
if m.start() != last_index {
// i. If sticky is true, then
if sticky {
@ -898,7 +902,8 @@ impl RegExp {
}
// ii. Set lastIndex to AdvanceStringIndex(S, lastIndex, fullUnicode).
last_index = advance_string_index(input.clone(), last_index, unicode);
last_index = advance_string_index(input, last_index, unicode);
// d. Else,
} else {
//i. Assert: r is a State.
//ii. Set matchSucceeded to true.
@ -1052,7 +1057,7 @@ impl RegExp {
let global = rx.get("global", context)?.to_boolean();
// 5. If global is false, then
// 6. Else,
#[allow(clippy::if_not_else)]
if !global {
// a. Return ? RegExpExec(rx, S).
if let Some(v) = Self::abstract_exec(rx, arg_str, context)? {
@ -1060,6 +1065,7 @@ impl RegExp {
} else {
Ok(JsValue::null())
}
// 6. Else,
} else {
// a. Assert: global is true.
@ -1096,7 +1102,7 @@ impl RegExp {
let this_index = rx.get("lastIndex", context)?.to_length(context)?;
// b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
let next_index = advance_string_index(arg_str.clone(), this_index, unicode);
let next_index = advance_string_index(&arg_str, this_index, unicode);
// c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true).
rx.set("lastIndex", JsValue::new(next_index), true, context)?;
@ -1106,12 +1112,11 @@ impl RegExp {
n += 1;
} else {
// 1. If n = 0, return null.
// 2. Return A.
if n == 0 {
return Ok(JsValue::null());
} else {
return Ok(a.into());
}
// 2. Return A.
return Ok(a.into());
}
}
}
@ -1208,13 +1213,13 @@ impl RegExp {
let unicode = flags.contains('u');
// 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).
RegExpStringIterator::create_regexp_string_iterator(
Ok(RegExpStringIterator::create_regexp_string_iterator(
matcher.clone(),
arg_str,
global,
unicode,
context,
)
))
}
/// `RegExp.prototype [ @@replace ] ( string, replaceValue )`
@ -1258,7 +1263,7 @@ impl RegExp {
let mut replace_value = args.get_or_undefined(1).clone();
let functional_replace = replace_value
.as_object()
.map(|obj| obj.is_callable())
.map(JsObject::is_callable)
.unwrap_or_default();
// 6. If functionalReplace is false, then
@ -1296,24 +1301,24 @@ impl RegExp {
results.push(result.clone());
// ii. If global is false, set done to true.
// iii. Else,
if !global {
break;
} else {
// 1. Let matchStr be ? ToString(? Get(result, "0")).
let match_str = result.get("0", context)?.to_string(context)?;
}
// iii. Else,
// 1. Let matchStr be ? ToString(? Get(result, "0")).
let match_str = result.get("0", context)?.to_string(context)?;
// 2. If matchStr is the empty String, then
if match_str.is_empty() {
// a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))).
let this_index = rx.get("lastIndex", context)?.to_length(context)?;
// 2. If matchStr is the empty String, then
if match_str.is_empty() {
// a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))).
let this_index = rx.get("lastIndex", context)?.to_length(context)?;
// b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
let next_index = advance_string_index(arg_str.clone(), this_index, unicode);
// b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
let next_index = advance_string_index(&arg_str, this_index, unicode);
// c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true).
rx.set("lastIndex", JsValue::new(next_index), true, context)?;
}
// c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true).
rx.set("lastIndex", JsValue::new(next_index), true, context)?;
}
} else {
break;
@ -1420,12 +1425,12 @@ impl RegExp {
// ii. Let replacement be ? GetSubstitution(matched, S, position, captures, namedCaptures, replaceValue).
replacement = string::get_substitution(
matched.to_string(),
arg_str.to_string(),
matched.as_str(),
arg_str.as_str(),
position,
captures,
named_captures,
replace_value.to_string(context)?,
&captures,
&named_captures,
&replace_value.to_string(context)?,
context,
)?;
}
@ -1652,7 +1657,7 @@ impl RegExp {
// iii. If e = p, set q to AdvanceStringIndex(S, q, unicodeMatching).
// iv. Else,
if e == p {
q = advance_string_index(arg_str.clone(), q, unicode);
q = advance_string_index(&arg_str, q, unicode);
} else {
// 1. Let T be the substring of S from p to q.
let arg_str_substring = String::from_utf16_lossy(
@ -1711,7 +1716,7 @@ impl RegExp {
q = p;
}
} else {
q = advance_string_index(arg_str.clone(), q, unicode);
q = advance_string_index(&arg_str, q, unicode);
}
}
@ -1739,7 +1744,7 @@ impl RegExp {
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-advancestringindex
fn advance_string_index(s: JsString, index: usize, unicode: bool) -> usize {
fn advance_string_index(s: &JsString, index: usize, unicode: bool) -> usize {
// Regress only works with utf8, so this function differs from the spec.
// 1. Assert: index ≤ 2^53 - 1.

17
boa/src/builtins/regexp/regexp_string_iterator.rs

@ -1,8 +1,9 @@
//! This module implements the global `RegExp String Iterator` object.
//!
//! A RegExp String Iterator is an object, that represents a specific iteration over some specific String instance object, matching against some specific RegExp instance object.
//! There is not a named constructor for RegExp String Iterator objects.
//! Instead, RegExp String Iterator objects are created by calling certain methods of RegExp instance objects.
//! A `RegExp` String Iterator is an object, that represents a specific iteration over some
//! specific String instance object, matching against some specific `RegExp` instance object.
//! There is not a named constructor for `RegExp` String Iterator objects. Instead, `RegExp`
//! String Iterator objects are created by calling certain methods of `RegExp` instance objects.
//!
//! More information:
//! - [ECMAScript reference][spec]
@ -54,7 +55,7 @@ impl RegExpStringIterator {
global: bool,
unicode: bool,
context: &mut Context,
) -> JsResult<JsValue> {
) -> JsValue {
// TODO: Implement this with closures and generators.
// For now all values of the closure are stored in RegExpStringIterator and the actual closure execution is in `.next()`.
@ -72,11 +73,11 @@ impl RegExpStringIterator {
ObjectData::reg_exp_string_iterator(Self::new(matcher, string, global, unicode)),
);
Ok(regexp_string_iterator.into())
regexp_string_iterator.into()
}
pub fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut iterator = this.as_object().map(|obj| obj.borrow_mut());
let mut iterator = this.as_object().map(JsObject::borrow_mut);
let iterator = iterator
.as_mut()
.and_then(|obj| obj.as_regexp_string_iterator_mut())
@ -116,7 +117,7 @@ impl RegExpStringIterator {
// 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode).
let next_index =
advance_string_index(iterator.string.clone(), this_index, iterator.unicode);
advance_string_index(&iterator.string, this_index, iterator.unicode);
// 3. Perform ? Set(R, "lastIndex", 𝔽(nextIndex), true).
iterator
@ -137,7 +138,7 @@ impl RegExpStringIterator {
}
}
/// Create the %ArrayIteratorPrototype% object
/// Create the `%ArrayIteratorPrototype%` object
///
/// More information:
/// - [ECMA reference][spec]

11
boa/src/builtins/set/mod.rs

@ -162,7 +162,7 @@ impl Set {
return iterator_record.close(Err(status), context);
}
next = iterator_record.next(context)?
next = iterator_record.next(context)?;
}
// 8.b
@ -179,6 +179,7 @@ impl Set {
///
/// [spec]: https://tc39.es/ecma262/#sec-get-set-@@species
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/@@species
#[allow(clippy::unnecessary_wraps)]
fn get_species(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// 1. Return the this value.
Ok(this.clone())
@ -203,7 +204,7 @@ impl Set {
if let Some(object) = this.as_object() {
if let Some(set) = object.borrow_mut().as_set_mut() {
set.add(if value.as_number().map(|n| n == -0f64).unwrap_or(false) {
set.add(if value.as_number().map_or(false, |n| n == -0f64) {
JsValue::Integer(0)
} else {
value.clone()
@ -336,7 +337,7 @@ impl Set {
let mut index = 0;
while index < Set::get_size(this, context)? {
while index < Self::get_size(this, context)? {
let arguments = this
.as_object()
.and_then(|obj| {
@ -418,13 +419,13 @@ impl Set {
}
fn size_getter(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Set::get_size(this, context).map(JsValue::from)
Self::get_size(this, context).map(JsValue::from)
}
/// Helper function to get the size of the set.
fn get_size(set: &JsValue, context: &mut Context) -> JsResult<usize> {
set.as_object()
.and_then(|obj| obj.borrow().as_set_ref().map(|set| set.size()))
.and_then(|obj| obj.borrow().as_set_ref().map(OrderedSet::size))
.ok_or_else(|| context.construct_type_error("'this' is not a Set"))
}
}

39
boa/src/builtins/set/ordered_set.rs

@ -9,16 +9,19 @@ use std::{
hash::{BuildHasher, Hash},
};
/// A newtype wrapping indexmap::IndexSet
/// A type wrapping `indexmap::IndexSet`
#[derive(Clone)]
pub struct OrderedSet<V, S = RandomState>(IndexSet<V, S>)
pub struct OrderedSet<V, S = RandomState>
where
V: Hash + Eq;
V: Hash + Eq,
{
inner: IndexSet<V, S>,
}
impl<V: Eq + Hash + Trace, S: BuildHasher> Finalize for OrderedSet<V, S> {}
unsafe impl<V: Eq + Hash + Trace, S: BuildHasher> Trace for OrderedSet<V, S> {
custom_trace!(this, {
for v in this.0.iter() {
for v in this.inner.iter() {
mark(v);
}
});
@ -26,7 +29,7 @@ unsafe impl<V: Eq + Hash + Trace, S: BuildHasher> Trace for OrderedSet<V, S> {
impl<V: Hash + Eq + Debug> Debug for OrderedSet<V> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
self.0.fmt(formatter)
self.inner.fmt(formatter)
}
}
@ -41,25 +44,29 @@ where
V: Hash + Eq,
{
pub fn new() -> Self {
OrderedSet(IndexSet::new())
Self {
inner: IndexSet::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
OrderedSet(IndexSet::with_capacity(capacity))
Self {
inner: IndexSet::with_capacity(capacity),
}
}
/// Return the number of key-value pairs in the map.
///
/// Computes in **O(1)** time.
pub fn size(&self) -> usize {
self.0.len()
self.inner.len()
}
/// Returns true if the map contains no elements.
///
/// Computes in **O(1)** time.
pub fn is_empty(&self) -> bool {
self.0.len() == 0
self.inner.len() == 0
}
/// Insert a value pair in the set.
@ -71,7 +78,7 @@ where
///
/// Computes in **O(1)** time (amortized average).
pub fn add(&mut self, value: V) -> bool {
self.0.insert(value)
self.inner.insert(value)
}
/// Delete the `value` from the set and return true if successful
@ -80,7 +87,7 @@ where
///
/// Computes in **O(n)** time (average).
pub fn delete(&mut self, value: &V) -> bool {
self.0.shift_remove(value)
self.inner.shift_remove(value)
}
/// Checks if a given value is present in the set
@ -89,19 +96,19 @@ where
///
/// Computes in **O(n)** time (average).
pub fn contains(&self, value: &V) -> bool {
self.0.contains(value)
self.inner.contains(value)
}
/// Get a key-value pair by index
/// Valid indices are 0 <= index < self.len()
/// Computes in O(1) time.
pub fn get_index(&self, index: usize) -> Option<&V> {
self.0.get_index(index)
self.inner.get_index(index)
}
/// Return an iterator over the values of the set, in their order
pub fn iter(&self) -> Iter<'_, V> {
self.0.iter()
self.inner.iter()
}
}
@ -113,7 +120,7 @@ where
type Item = &'a V;
type IntoIter = Iter<'a, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
self.inner.iter()
}
}
@ -125,6 +132,6 @@ where
type Item = V;
type IntoIter = IntoIter<V>;
fn into_iter(self) -> IntoIter<V> {
self.0.into_iter()
self.inner.into_iter()
}
}

10
boa/src/builtins/set/set_iterator.rs

@ -25,14 +25,14 @@ impl SetIterator {
/// Constructs a new `SetIterator`, that will iterate over `set`, starting at index 0
fn new(set: JsValue, kind: PropertyNameKind) -> Self {
SetIterator {
Self {
iterated_set: set,
next_index: 0,
iteration_kind: kind,
}
}
/// Abstract operation CreateSetIterator( set, kind )
/// Abstract operation `CreateSetIterator( set, kind )`
///
/// Creates a new iterator over the given set.
///
@ -61,7 +61,7 @@ impl SetIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%setiteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut set_iterator = this.as_object().map(|obj| obj.borrow_mut());
let mut set_iterator = this.as_object().map(JsObject::borrow_mut);
let set_iterator = set_iterator
.as_mut()
@ -80,7 +80,7 @@ impl SetIterator {
));
}
let entries = m.as_object().map(|obj| obj.borrow());
let entries = m.as_object().map(JsObject::borrow);
let entries = entries
.as_ref()
.and_then(|obj| obj.as_set_ref())
@ -119,7 +119,7 @@ impl SetIterator {
))
}
/// Create the %SetIteratorPrototype% object
/// Create the `%SetIteratorPrototype%` object
///
/// More information:
/// - [ECMA reference][spec]

98
boa/src/builtins/string/mod.rs

@ -13,13 +13,13 @@ pub mod string_iterator;
#[cfg(test)]
mod tests;
use crate::builtins::Symbol;
use crate::context::StandardObjects;
use crate::object::internal_methods::get_prototype_from_constructor;
use crate::object::JsObject;
use super::JsArgs;
use crate::{
builtins::{string::string_iterator::StringIterator, Array, BuiltIn, RegExp},
object::{ConstructorBuilder, ObjectData},
builtins::{string::string_iterator::StringIterator, Array, BuiltIn, RegExp, Symbol},
context::StandardObjects,
object::{
internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData,
},
property::{Attribute, PropertyDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, JsResult, JsString, JsValue,
@ -31,9 +31,7 @@ use std::{
};
use unicode_normalization::UnicodeNormalization;
use super::JsArgs;
pub(crate) fn code_point_at(string: JsString, position: i32) -> Option<(u32, u8, bool)> {
pub(crate) fn code_point_at(string: &JsString, position: i32) -> Option<(u32, u8, bool)> {
let size = string.encode_utf16().count() as i32;
if position < 0 || position >= size {
return None;
@ -41,16 +39,16 @@ pub(crate) fn code_point_at(string: JsString, position: i32) -> Option<(u32, u8,
let mut encoded = string.encode_utf16();
let first = encoded.nth(position as usize)?;
if !is_leading_surrogate(first) && !is_trailing_surrogate(first) {
return Some((first as u32, 1, false));
return Some((u32::from(first), 1, false));
}
if is_trailing_surrogate(first) || position + 1 == size {
return Some((first as u32, 1, true));
return Some((u32::from(first), 1, true));
}
let second = encoded.next()?;
if !is_trailing_surrogate(second) {
return Some((first as u32, 1, true));
return Some((u32::from(first), 1, true));
}
let cp = (first as u32 - 0xD800) * 0x400 + (second as u32 - 0xDC00) + 0x10000;
let cp = (u32::from(first) - 0xD800) * 0x400 + (u32::from(second) - 0xDC00) + 0x10000;
Some((cp, 2, false))
}
@ -385,7 +383,7 @@ impl String {
// Note that this is an O(N) operation (because UTF-8 is complex) while getting the number of
// bytes is an O(1) operation.
if let Some(utf16_val) = primitive_val.encode_utf16().nth(pos as usize) {
Ok(JsValue::new(from_u32(utf16_val as u32).unwrap()))
Ok(JsValue::new(from_u32(u32::from(utf16_val)).unwrap()))
} else {
Ok("".into())
}
@ -411,7 +409,7 @@ impl String {
.cloned()
.unwrap_or_default()
.to_integer(context)?;
let k = if relative_index < 0 as f64 {
let k = if relative_index < 0_f64 {
len - (-relative_index as usize)
} else {
relative_index as usize
@ -459,7 +457,7 @@ impl String {
return Ok(JsValue::undefined());
}
if let Some((code_point, _, _)) = code_point_at(primitive_val, pos) {
if let Some((code_point, _, _)) = code_point_at(&primitive_val, pos) {
Ok(JsValue::new(code_point))
} else {
Ok(JsValue::undefined())
@ -843,7 +841,7 @@ impl String {
// 5. Let functionalReplace be IsCallable(replaceValue).
let functional_replace = replace_value
.as_object()
.map(|obj| obj.is_callable())
.map(JsObject::is_callable)
.unwrap_or_default();
// 6. If functionalReplace is false, then
@ -883,12 +881,12 @@ impl String {
// c. Let replacement be ! GetSubstitution(searchString, string, position, captures, undefined, replaceValue).
get_substitution(
search_str.to_string(),
this_str.to_string(),
search_str.as_str(),
this_str.as_str(),
position,
captures,
JsValue::undefined(),
replace_value.to_string(context)?,
&captures,
&JsValue::undefined(),
&replace_value.to_string(context)?,
context,
)?
};
@ -910,9 +908,11 @@ impl String {
/// `22.1.3.18 String.prototype.replaceAll ( searchValue, replaceValue )`
///
/// The replaceAll() method returns a new string with all matches of a pattern replaced by a replacement.
/// The replaceAll() method returns a new string with all matches of a pattern replaced by a
/// replacement.
///
/// The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match.
/// The pattern can be a string or a `RegExp`, and the replacement can be a string or a
/// function to be called for each match.
///
/// The original string is left unchanged.
///
@ -973,15 +973,16 @@ impl String {
// 5. Let functionalReplace be IsCallable(replaceValue).
let functional_replace = replace_value
.as_object()
.map(|obj| obj.is_callable())
.map(JsObject::is_callable)
.unwrap_or_default();
// 6. If functionalReplace is false, then
#[allow(clippy::if_not_else)]
let replace_value_string = if !functional_replace {
// a. Set replaceValue to ? ToString(replaceValue).
replace_value.to_string(context)?
} else {
JsString::new("")
JsString::empty()
};
// 7. Let searchLength be the length of searchString.
@ -1043,12 +1044,12 @@ impl String {
// ii. Let captures be a new empty List.
// iii. Let replacement be ! GetSubstitution(searchString, string, p, captures, undefined, replaceValue).
get_substitution(
search_string.to_string(),
string.to_string(),
search_string.as_str(),
string.as_str(),
p,
Vec::new(),
JsValue::undefined(),
replace_value_string.clone(),
&[],
&JsValue::undefined(),
&replace_value_string,
context,
)
.expect("GetSubstitution should never fail here.")
@ -1221,7 +1222,7 @@ impl String {
fn string_pad(
primitive: JsString,
max_length: i32,
fill_string: Option<JsString>,
fill_string: Option<&JsString>,
at_start: bool,
) -> JsValue {
let primitive_length = primitive.len() as i32;
@ -1230,7 +1231,7 @@ impl String {
return JsValue::new(primitive);
}
let filler = fill_string.as_deref().unwrap_or(" ");
let filler = fill_string.map_or(" ", JsString::as_str);
if filler.is_empty() {
return JsValue::new(primitive);
@ -1280,7 +1281,12 @@ impl String {
let fill_string = args.get(1).map(|arg| arg.to_string(context)).transpose()?;
Ok(Self::string_pad(primitive, max_length, fill_string, false))
Ok(Self::string_pad(
primitive,
max_length,
fill_string.as_ref(),
false,
))
}
/// `String.prototype.padStart( targetLength [, padString] )`
@ -1311,7 +1317,12 @@ impl String {
let fill_string = args.get(1).map(|arg| arg.to_string(context)).transpose()?;
Ok(Self::string_pad(primitive, max_length, fill_string, true))
Ok(Self::string_pad(
primitive,
max_length,
fill_string.as_ref(),
true,
))
}
/// String.prototype.trim()
@ -1858,12 +1869,12 @@ impl String {
///
/// [spec]: https://tc39.es/ecma262/#sec-getsubstitution
pub(crate) fn get_substitution(
matched: StdString,
str: StdString,
matched: &str,
str: &str,
position: usize,
captures: Vec<JsValue>,
named_captures: JsValue,
replacement: JsString,
captures: &[JsValue],
named_captures: &JsValue,
replacement: &JsString,
context: &mut Context,
) -> JsResult<JsString> {
// 1. Assert: Type(matched) is String.
@ -1910,7 +1921,7 @@ pub(crate) fn get_substitution(
// $&
(Some('&'), _) => {
// matched
result.push_str(&matched);
result.push_str(matched);
}
// $`
(Some('`'), _) => {
@ -1971,7 +1982,7 @@ pub(crate) fn get_substitution(
// 1. If namedCaptures is undefined, the replacement text is the String "$<".
// 2. Else,
if named_captures.is_undefined() {
result.push_str("$<")
result.push_str("$<");
} else {
// a. Assert: Type(namedCaptures) is Object.
@ -1990,10 +2001,11 @@ pub(crate) fn get_substitution(
}
// c. If none is found, the replacement text is the String "$<".
// d. Else,
#[allow(clippy::if_not_else)]
if !found {
result.push_str("$<");
result.push_str(&group_name);
// d. Else,
} else {
// i. Let groupName be the enclosed substring.
// ii. Let capture be ? Get(namedCaptures, groupName).

8
boa/src/builtins/string/string_iterator.rs

@ -32,7 +32,7 @@ impl StringIterator {
}
pub fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut string_iterator = this.as_object().map(|obj| obj.borrow_mut());
let mut string_iterator = this.as_object().map(JsObject::borrow_mut);
let string_iterator = string_iterator
.as_mut()
.and_then(|obj| obj.as_string_iterator_mut())
@ -57,8 +57,8 @@ impl StringIterator {
));
}
let (_, code_unit_count, _) =
code_point_at(native_string, position).expect("Invalid code point position");
string_iterator.next_index += code_unit_count as i32;
code_point_at(&native_string, position).expect("Invalid code point position");
string_iterator.next_index += i32::from(code_unit_count);
let result_string = crate::builtins::string::String::substring(
&string_iterator.string,
&[position.into(), string_iterator.next_index.into()],
@ -67,7 +67,7 @@ impl StringIterator {
Ok(create_iter_result_object(result_string, false, context))
}
/// Create the %ArrayIteratorPrototype% object
/// Create the `%ArrayIteratorPrototype%` object
///
/// More information:
/// - [ECMA reference][spec]

11
boa/src/builtins/string/tests.rs

@ -350,7 +350,7 @@ fn starts_with_with_regex_arg() {
&mut context, scenario
),
"\"TypeError: First argument to String.prototype.startsWith must not be a regular expression\""
)
);
}
#[test]
@ -394,7 +394,7 @@ fn ends_with_with_regex_arg() {
&mut context, scenario
),
"\"TypeError: First argument to String.prototype.endsWith must not be a regular expression\""
)
);
}
#[test]
@ -438,7 +438,7 @@ fn includes_with_regex_arg() {
&mut context, scenario
),
"\"TypeError: First argument to String.prototype.includes must not be a regular expression\""
)
);
}
#[test]
@ -680,7 +680,10 @@ fn split() {
// TODO: Support keeping invalid code point in string
assert_eq!(
forward(&mut context, "'𝟘𝟙𝟚𝟛'.split('')"),
forward(
&mut context,
"\'\u{1d7d8}\u{1d7d9}\u{1d7da}\u{1d7db}\'.split(\'\')"
),
forward(&mut context, "['<EFBFBD>','<EFBFBD>','<EFBFBD>','<EFBFBD>','<EFBFBD>','<EFBFBD>','<EFBFBD>','<EFBFBD>']")
);
}

6
boa/src/builtins/symbol/mod.rs

@ -61,8 +61,8 @@ impl GlobalSymbolRegistry {
symbol
}
fn get_symbol(&self, sym: JsSymbol) -> Option<JsString> {
if let Some(key) = self.symbols.get(&sym) {
fn get_symbol(&self, sym: &JsSymbol) -> Option<JsString> {
if let Some(key) = self.symbols.get(sym) {
return Some(key.clone());
}
@ -311,7 +311,7 @@ impl Symbol {
// 4. Return undefined.
let symbol = GLOBAL_SYMBOL_REGISTRY.with(move |registry| {
let registry = registry.borrow();
registry.get_symbol(sym)
registry.get_symbol(&sym)
});
Ok(symbol.map(JsValue::from).unwrap_or_default())

6
boa/src/builtins/typed_array/integer_indexed_object.rs

@ -56,14 +56,16 @@ impl IntegerIndexed {
/// `IntegerIndexedObjectCreate ( prototype )`
///
/// Create a new `JsObject from a prototype and a `IntergetIndexedObject`
/// Create a new `JsObject` from a prototype and a `IntergetIndexedObject`
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-integerindexedobjectcreate
pub(super) fn create(prototype: JsObject, data: Self, context: &Context) -> JsObject {
// 1. Let internalSlotsList be « [[Prototype]], [[Extensible]], [[ViewedArrayBuffer]], [[TypedArrayName]], [[ContentType]], [[ByteLength]], [[ByteOffset]], [[ArrayLength]] ».
// 1. Let internalSlotsList be « [[Prototype]], [[Extensible]], [[ViewedArrayBuffer]],
// [[TypedArrayName]], [[ContentType]], [[ByteLength]], [[ByteOffset]],
// [[ArrayLength]] ».
// 2. Let A be ! MakeBasicObject(internalSlotsList).
let a = context.construct_object();

38
boa/src/builtins/typed_array/mod.rs

@ -146,11 +146,7 @@ macro_rules! typed_array {
// ii. If firstArgument has a [[TypedArrayName]] internal slot, then
if first_argument.is_typed_array() {
// 1. Perform ? InitializeTypedArrayFromTypedArray(O, firstArgument).
TypedArray::initialize_from_typed_array(
&o,
first_argument.clone(),
context,
)?;
TypedArray::initialize_from_typed_array(&o, first_argument, context)?;
} else if first_argument.is_array_buffer() {
// iii. Else if firstArgument has an [[ArrayBufferData]] internal slot, then
@ -185,7 +181,7 @@ macro_rules! typed_array {
// a. Let values be ? IterableToList(firstArgument, usingIterator).
let values = iterable_to_list(
context,
first_argument_v,
&first_argument_v,
Some(using_iterator.into()),
)?;
@ -418,7 +414,7 @@ impl TypedArray {
// 6. If usingIterator is not undefined, then
if let Some(using_iterator) = using_iterator {
// a. Let values be ? IterableToList(source, usingIterator).
let values = iterable_to_list(context, source.clone(), Some(using_iterator.into()))?;
let values = iterable_to_list(context, source, Some(using_iterator.into()))?;
// b. Let len be the number of elements in values.
// c. Let targetObj be ? TypedArrayCreate(C, « 𝔽(len) »).
@ -525,6 +521,7 @@ impl TypedArray {
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-%typedarray%-@@species
#[allow(clippy::unnecessary_wraps)]
fn get_species(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// 1. Return the this value.
Ok(this.clone())
@ -600,8 +597,7 @@ impl TypedArray {
// 5. Return buffer.
Ok(typed_array
.viewed_array_buffer()
.map(|buffer| buffer.clone().into())
.unwrap_or_else(JsValue::undefined))
.map_or_else(JsValue::undefined, |buffer| buffer.clone().into()))
}
/// `23.2.3.3 get %TypedArray%.prototype.byteLength`
@ -810,7 +806,7 @@ impl TypedArray {
buffer.set_value_in_buffer(
to_byte_index as usize,
TypedArrayName::Uint8Array,
value,
&value,
SharedMemoryOrder::Unordered,
None,
context,
@ -2071,7 +2067,7 @@ impl TypedArray {
.set_value_in_buffer(
target_byte_index,
TypedArrayName::Uint8Array,
value,
&value,
SharedMemoryOrder::Unordered,
None,
context,
@ -2105,7 +2101,7 @@ impl TypedArray {
.set_value_in_buffer(
target_byte_index,
target_name,
value,
&value,
SharedMemoryOrder::Unordered,
None,
context,
@ -2220,7 +2216,7 @@ impl TypedArray {
target_buffer.set_value_in_buffer(
target_byte_index,
target_name,
value,
&value,
SharedMemoryOrder::Unordered,
None,
context,
@ -2310,6 +2306,7 @@ impl TypedArray {
// d. Let targetName be the String value of A.[[TypedArrayName]].
// e. Let targetType be the Element Type value in Table 73 for targetName.
// f. If srcType is different from targetType, then
#[allow(clippy::if_not_else)]
if o.typed_array_name() != a_array.typed_array_name() {
// i. Let n be 0.
let mut n = 0;
@ -2379,7 +2376,7 @@ impl TypedArray {
target_buffer.set_value_in_buffer(
target_byte_index,
TypedArrayName::Uint8Array,
value,
&value,
SharedMemoryOrder::Unordered,
None,
context,
@ -2785,6 +2782,7 @@ impl TypedArray {
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-%typedarray%.prototype-@@tostringtag
#[allow(clippy::unnecessary_wraps)]
fn to_string_tag(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// 1. Let O be the this value.
// 2. If Type(O) is not Object, return undefined.
@ -2947,7 +2945,7 @@ impl TypedArray {
let o_inner = o.as_typed_array_mut().expect("expected a TypedArray");
// 2. Perform ? AllocateTypedArrayBuffer(O, len).
TypedArray::allocate_buffer(o_inner, len, context)?;
Self::allocate_buffer(o_inner, len, context)?;
}
// 3. Let k be 0.
@ -3001,7 +2999,7 @@ impl TypedArray {
// 8. Else,
if let Some(length) = length {
// a. Perform ? AllocateTypedArrayBuffer(obj, length).
TypedArray::allocate_buffer(&mut indexed, length, context)?;
Self::allocate_buffer(&mut indexed, length, context)?;
}
// 2. Let obj be ! IntegerIndexedObjectCreate(proto).
@ -3019,7 +3017,7 @@ impl TypedArray {
/// [spec]: https://tc39.es/ecma262/#sec-initializetypedarrayfromtypedarray
fn initialize_from_typed_array(
o: &JsObject,
src_array: JsObject,
src_array: &JsObject,
context: &mut Context,
) -> JsResult<()> {
let o_obj = o.borrow();
@ -3121,7 +3119,7 @@ impl TypedArray {
data.set_value_in_buffer(
target_byte_index,
constructor_name,
value,
&value,
SharedMemoryOrder::Unordered,
None,
context,
@ -3268,7 +3266,7 @@ impl TypedArray {
{
let mut o_borrow = o.borrow_mut();
let o = o_borrow.as_typed_array_mut().expect("Must be typed array");
TypedArray::allocate_buffer(o, len, context)?;
Self::allocate_buffer(o, len, context)?;
}
// 3. Let k be 0.
@ -3348,7 +3346,7 @@ impl TypedArrayName {
}
}
pub(crate) fn is_big_int_element_type(&self) -> bool {
pub(crate) fn is_big_int_element_type(self) -> bool {
matches!(
self,
TypedArrayName::BigUint64Array | TypedArrayName::BigInt64Array

103
boa/src/bytecompiler.rs

@ -140,7 +140,7 @@ impl<'b> ByteCompiler<'b> {
#[inline]
fn emit_opcode(&mut self, opcode: Opcode) {
self.emit_u8(opcode as u8)
self.emit_u8(opcode as u8);
}
#[inline]
@ -153,11 +153,11 @@ impl<'b> ByteCompiler<'b> {
match value {
0 => self.emit_opcode(Opcode::PushZero),
1 => self.emit_opcode(Opcode::PushOne),
x if x as i8 as i32 == x => {
x if i32::from(x as i8) == x => {
self.emit_opcode(Opcode::PushInt8);
self.emit_u8(x as i8 as u8);
}
x if x as i16 as i32 == x => {
x if i32::from(x as i16) == x => {
self.emit_opcode(Opcode::PushInt16);
self.emit_u16(x as i16 as u16);
}
@ -180,14 +180,13 @@ impl<'b> ByteCompiler<'b> {
if value.is_infinite() {
if value.is_sign_positive() {
return self.emit_opcode(Opcode::PushPositiveInfinity);
} else {
return self.emit_opcode(Opcode::PushNegativeInfinity);
}
return self.emit_opcode(Opcode::PushNegativeInfinity);
}
// Check if the f64 value can fit in an i32.
#[allow(clippy::float_cmp)]
if value as i32 as f64 == value {
if f64::from(value as i32) == value {
self.emit_push_integer(value as i32);
} else {
self.emit_opcode(Opcode::PushRational);
@ -245,7 +244,7 @@ impl<'b> ByteCompiler<'b> {
breaks: Vec::new(),
try_continues: Vec::new(),
for_of_in_loop: false,
})
});
}
#[inline]
@ -257,7 +256,7 @@ impl<'b> ByteCompiler<'b> {
breaks: Vec::new(),
try_continues: Vec::new(),
for_of_in_loop: true,
})
});
}
#[inline]
@ -280,7 +279,7 @@ impl<'b> ByteCompiler<'b> {
breaks: Vec::new(),
try_continues: Vec::new(),
for_of_in_loop: false,
})
});
}
#[inline]
@ -306,7 +305,7 @@ impl<'b> ByteCompiler<'b> {
breaks: Vec::new(),
try_continues: Vec::new(),
for_of_in_loop: false,
})
});
}
}
@ -324,7 +323,7 @@ impl<'b> ByteCompiler<'b> {
if label.index < finally_start_address {
self.patch_jump_with_target(label, finally_start_address);
} else {
self.patch_jump_with_target(label, info.start_address)
self.patch_jump_with_target(label, info.start_address);
}
}
@ -730,46 +729,18 @@ impl<'b> ByteCompiler<'b> {
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
}
},
MethodDefinitionKind::Generator => {
MethodDefinitionKind::Generator
| MethodDefinitionKind::Async
| MethodDefinitionKind::AsyncGenerator => {
// TODO: Implement generators
match name {
PropertyName::Literal(name) => {
self.emit_opcode(Opcode::PushUndefined);
self.emit_opcode(Opcode::Swap);
let index = self.get_or_insert_name(*name);
self.emit(Opcode::DefineOwnPropertyByName, &[index]);
}
PropertyName::Computed(name_node) => {
self.compile_stmt(name_node, true);
self.emit_opcode(Opcode::PushUndefined);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
}
}
}
MethodDefinitionKind::Async => {
// TODO: Implement async
match name {
PropertyName::Literal(name) => {
self.emit_opcode(Opcode::PushUndefined);
self.emit_opcode(Opcode::Swap);
let index = self.get_or_insert_name(*name);
self.emit(Opcode::DefineOwnPropertyByName, &[index])
}
PropertyName::Computed(name_node) => {
self.compile_stmt(name_node, true);
self.emit_opcode(Opcode::PushUndefined);
self.emit_opcode(Opcode::DefineOwnPropertyByValue);
}
}
}
MethodDefinitionKind::AsyncGenerator => {
// TODO: Implement async generators
match name {
PropertyName::Literal(name) => {
self.emit_opcode(Opcode::PushUndefined);
self.emit_opcode(Opcode::Swap);
let index = self.get_or_insert_name(*name);
self.emit(Opcode::DefineOwnPropertyByName, &[index])
self.emit(Opcode::DefineOwnPropertyByName, &[index]);
}
PropertyName::Computed(name_node) => {
self.compile_stmt(name_node, true);
@ -853,8 +824,7 @@ impl<'b> ByteCompiler<'b> {
Node::Spread(spread) => self.compile_expr(spread.val(), true),
Node::FunctionExpr(_function) => self.function(expr, use_expr),
Node::ArrowFunctionDecl(_function) => self.function(expr, use_expr),
Node::Call(_) => self.call(expr, use_expr),
Node::New(_) => self.call(expr, use_expr),
Node::Call(_) | Node::New(_) => self.call(expr, use_expr),
Node::TemplateLit(template_literal) => {
for element in template_literal.elements() {
match element {
@ -877,23 +847,15 @@ impl<'b> ByteCompiler<'b> {
}
}
// TODO: implement AsyncFunctionExpr
Node::AsyncFunctionExpr(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
// TODO: implement AwaitExpr
Node::AwaitExpr(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
// TODO: implement GeneratorExpr
Node::GeneratorExpr(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
// TODO: implement AsyncGeneratorExpr
Node::AsyncGeneratorExpr(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
// TODO: implement Yield
Node::Yield(_) => {
Node::AsyncFunctionExpr(_)
| Node::AwaitExpr(_)
| Node::GeneratorExpr(_)
| Node::AsyncGeneratorExpr(_)
| Node::Yield(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
Node::TaggedTemplate(template) => {
@ -1428,15 +1390,9 @@ impl<'b> ByteCompiler<'b> {
}
}
// TODO: implement AsyncFunctionDecl
Node::AsyncFunctionDecl(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
// TODO: implement GeneratorDecl
Node::GeneratorDecl(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
// TODO: implement AsyncGeneratorDecl
Node::AsyncGeneratorDecl(_) => {
Node::AsyncFunctionDecl(_) | Node::GeneratorDecl(_) | Node::AsyncGeneratorDecl(_) => {
self.emit_opcode(Opcode::PushUndefined);
}
Node::Empty => {}
@ -1522,7 +1478,7 @@ impl<'b> ByteCompiler<'b> {
}
if has_parameter_expressions {
compiler.emit_opcode(Opcode::PushFunctionEnvironment)
compiler.emit_opcode(Opcode::PushFunctionEnvironment);
}
for node in body.items() {
@ -1600,11 +1556,11 @@ impl<'b> ByteCompiler<'b> {
match kind {
CallKind::Call if last_is_rest_parameter => {
self.emit(Opcode::CallWithRest, &[call.args().len() as u32])
self.emit(Opcode::CallWithRest, &[call.args().len() as u32]);
}
CallKind::Call => self.emit(Opcode::Call, &[call.args().len() as u32]),
CallKind::New if last_is_rest_parameter => {
self.emit(Opcode::NewWithRest, &[call.args().len() as u32])
self.emit(Opcode::NewWithRest, &[call.args().len() as u32]);
}
CallKind::New => self.emit(Opcode::New, &[call.args().len() as u32]),
}
@ -1635,7 +1591,9 @@ impl<'b> ByteCompiler<'b> {
self.emit_opcode(Opcode::RequireObjectCoercible);
for binding in pattern.bindings() {
use BindingPatternTypeObject::*;
use BindingPatternTypeObject::{
BindingPattern, Empty, RestProperty, SingleName,
};
match binding {
// ObjectBindingPattern : { }
@ -1710,7 +1668,10 @@ impl<'b> ByteCompiler<'b> {
self.emit_opcode(Opcode::InitIterator);
for (i, binding) in pattern.bindings().iter().enumerate() {
use BindingPatternTypeArray::*;
use BindingPatternTypeArray::{
BindingPattern, BindingPatternRest, Elision, Empty, SingleName,
SingleNameRest,
};
let next = if i == pattern.bindings().len() - 1 {
Opcode::IteratorNextFull
@ -1745,7 +1706,7 @@ impl<'b> ByteCompiler<'b> {
// BindingElement : BindingPattern Initializer[opt]
BindingPattern { pattern } => {
self.emit_opcode(next);
self.compile_declaration_pattern(pattern, def)
self.compile_declaration_pattern(pattern, def);
}
// BindingRestElement : ... BindingIdentifier
SingleNameRest { ident } => {

10
boa/src/context.rs

@ -397,7 +397,7 @@ impl Default for Context {
console: Console::default(),
iterator_prototypes: IteratorPrototypes::default(),
typed_array_constructor: StandardConstructor::default(),
standard_objects: Default::default(),
standard_objects: StandardObjects::default(),
intrinsic_objects: IntrinsicObjects::default(),
strict: false,
vm: Vm {
@ -761,7 +761,7 @@ impl Context {
#[inline]
pub fn register_global_closure<F>(&mut self, name: &str, length: usize, body: F) -> JsResult<()>
where
F: Fn(&JsValue, &[JsValue], &mut Context) -> JsResult<JsValue> + Copy + 'static,
F: Fn(&JsValue, &[JsValue], &mut Self) -> JsResult<JsValue> + Copy + 'static,
{
let function = FunctionBuilder::closure(self, body)
.name(name)
@ -886,7 +886,7 @@ impl Context {
where
S: AsRef<[u8]>,
{
let main_timer = BoaProfiler::global().start_event("Main", "Main");
let main_timer = BoaProfiler::global().start_event("Evaluation", "Main");
let parsing_result = Parser::new(src.as_ref(), false)
.parse_all(&mut self.interner)
@ -924,7 +924,7 @@ impl Context {
/// `Gc<CodeBlock>` returned by the [`Self::compile()`] function.
#[inline]
pub fn execute(&mut self, code_block: Gc<CodeBlock>) -> JsResult<JsValue> {
let _ = BoaProfiler::global().start_event("Execute", "Main");
let _ = BoaProfiler::global().start_event("Execution", "Main");
let global_object = self.global_object().into();
self.vm.push_frame(CallFrame {
@ -950,7 +950,7 @@ impl Context {
&self.iterator_prototypes
}
/// Return the cached TypedArray constructor.
/// Return the cached `TypedArray` constructor.
#[inline]
pub(crate) fn typed_array_constructor(&self) -> &StandardConstructor {
&self.typed_array_constructor

6
boa/src/environment/declarative_environment_record.rs

@ -39,9 +39,9 @@ pub struct DeclarativeEnvironmentRecord {
}
impl DeclarativeEnvironmentRecord {
pub fn new(env: Option<Environment>) -> DeclarativeEnvironmentRecord {
pub fn new(env: Option<Environment>) -> Self {
let _timer = BoaProfiler::global().start_event("new_declarative_environment", "env");
DeclarativeEnvironmentRecord {
Self {
env_rec: gc::Cell::new(FxHashMap::default()),
outer_env: env,
}
@ -337,7 +337,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
}
impl From<DeclarativeEnvironmentRecord> for Environment {
fn from(env: DeclarativeEnvironmentRecord) -> Environment {
fn from(env: DeclarativeEnvironmentRecord) -> Self {
Gc::new(Box::new(env))
}
}

6
boa/src/environment/environment_record_trait.rs

@ -60,9 +60,11 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize {
fn initialize_binding(&self, name: Sym, value: JsValue, context: &mut Context) -> JsResult<()>;
/// Set the value of an already existing mutable binding in an Environment Record.
///
/// The String value `name` is the text of the bound name.
/// value is the `value` for the binding and may be a value of any ECMAScript language type. S is a Boolean flag.
/// If `strict` is true and the binding cannot be set throw a TypeError exception.
/// value is the `value` for the binding and may be a value of any ECMAScript language type.
/// `S` is a `Boolean` flag. If `strict` is true and the binding cannot be set throw a
/// `TypeError` exception.
fn set_mutable_binding(
&self,
name: Sym,

8
boa/src/environment/function_environment_record.rs

@ -64,8 +64,8 @@ impl FunctionEnvironmentRecord {
binding_status: BindingStatus,
new_target: JsValue,
context: &mut Context,
) -> JsResult<FunctionEnvironmentRecord> {
let mut func_env = FunctionEnvironmentRecord {
) -> JsResult<Self> {
let mut func_env = Self {
declarative_record: DeclarativeEnvironmentRecord::new(outer), // the outer environment will come from Environment set as a private property of F - https://tc39.es/ecma262/#sec-ecmascript-function-objects
function: f,
this_binding_status: binding_status,
@ -247,7 +247,7 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
}
fn set_outer_environment(&mut self, env: Environment) {
self.declarative_record.set_outer_environment(env)
self.declarative_record.set_outer_environment(env);
}
fn get_environment_type(&self) -> EnvironmentType {
@ -276,7 +276,7 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
}
impl From<FunctionEnvironmentRecord> for Environment {
fn from(env: FunctionEnvironmentRecord) -> Environment {
fn from(env: FunctionEnvironmentRecord) -> Self {
Gc::new(Box::new(env))
}
}

11
boa/src/environment/global_environment_record.rs

@ -31,7 +31,7 @@ pub struct GlobalEnvironmentRecord {
}
impl GlobalEnvironmentRecord {
pub fn new(global: JsObject, this_value: JsObject) -> GlobalEnvironmentRecord {
pub fn new(global: JsObject, this_value: JsObject) -> Self {
let obj_rec = ObjectEnvironmentRecord {
bindings: global,
outer_env: None,
@ -45,7 +45,7 @@ impl GlobalEnvironmentRecord {
let dcl_rec = DeclarativeEnvironmentRecord::new(None);
GlobalEnvironmentRecord {
Self {
object_record: obj_rec,
global_this_binding: this_value,
declarative_record: dcl_rec,
@ -236,10 +236,7 @@ impl GlobalEnvironmentRecord {
.__get_own_property__(&context.interner().resolve_expect(name).into(), context)?;
// 4. If existingProp is undefined or existingProp.[[Configurable]] is true, then
let desc = if existing_prop
.map(|f| f.expect_configurable())
.unwrap_or(true)
{
let desc = if existing_prop.map_or(true, |f| f.expect_configurable()) {
// a. Let desc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D }.
PropertyDescriptor::builder()
.value(value.clone())
@ -568,7 +565,7 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
}
impl From<GlobalEnvironmentRecord> for Environment {
fn from(env: GlobalEnvironmentRecord) -> Environment {
fn from(env: GlobalEnvironmentRecord) -> Self {
Gc::new(Box::new(env))
}
}

15
boa/src/environment/object_environment_record.rs

@ -27,8 +27,8 @@ pub struct ObjectEnvironmentRecord {
}
impl ObjectEnvironmentRecord {
pub fn new(object: JsObject, environment: Option<Environment>) -> ObjectEnvironmentRecord {
ObjectEnvironmentRecord {
pub fn new(object: JsObject, environment: Option<Environment>) -> Self {
Self {
bindings: object,
outer_env: environment,
/// Object Environment Records created for with statements (13.11)
@ -194,12 +194,11 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord {
// a. If S is false, return the value undefined; otherwise throw a ReferenceError exception.
if !strict {
return Ok(JsValue::undefined());
} else {
return context.throw_reference_error(format!(
"{} has no binding",
context.interner().resolve_expect(name)
));
}
return context.throw_reference_error(format!(
"{} has no binding",
context.interner().resolve_expect(name)
));
}
// 4. Return ? Get(bindingObject, N).
@ -276,7 +275,7 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord {
}
impl From<ObjectEnvironmentRecord> for Environment {
fn from(env: ObjectEnvironmentRecord) -> Environment {
fn from(env: ObjectEnvironmentRecord) -> Self {
Gc::new(Box::new(env))
}
}

29
boa/src/lib.rs

@ -10,8 +10,27 @@
html_logo_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo.svg"
)]
#![warn(
clippy::perf,
clippy::single_match_else,
clippy::dbg_macro,
clippy::doc_markdown,
clippy::wildcard_imports,
clippy::struct_excessive_bools,
clippy::doc_markdown,
clippy::semicolon_if_nothing_returned,
clippy::pedantic
)]
#![deny(
clippy::all,
clippy::cast_lossless,
clippy::redundant_closure_for_method_calls,
clippy::use_self,
clippy::unnested_or_patterns,
clippy::trivially_copy_pass_by_ref,
clippy::needless_pass_by_value,
clippy::match_wildcard_for_single_variants,
clippy::map_unwrap_or,
unused_qualifications,
unused_import_braces,
unused_lifetimes,
@ -28,8 +47,16 @@
future_incompatible,
nonstandard_style,
)]
#![warn(clippy::perf, clippy::single_match_else, clippy::dbg_macro)]
#![allow(
clippy::module_name_repetitions,
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss,
clippy::cast_possible_wrap,
clippy::cast_ptr_alignment,
clippy::missing_panics_doc,
clippy::too_many_lines,
clippy::unreadable_literal,
clippy::missing_inline_in_public_items,
clippy::cognitive_complexity,
clippy::must_use_candidate,

3
boa/src/object/internal_methods/arguments.rs

@ -70,6 +70,7 @@ pub(crate) fn arguments_exotic_get_own_property(
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-arguments-exotic-objects-defineownproperty-p-desc
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn arguments_exotic_define_own_property(
obj: &JsObject,
key: PropertyKey,
@ -130,7 +131,7 @@ pub(crate) fn arguments_exotic_define_own_property(
let set_status = map.set(key.clone(), value, false, context);
// 2. Assert: setStatus is true because formal parameters mapped by argument objects are always writable.
assert_eq!(set_status, Ok(true))
assert_eq!(set_status, Ok(true));
}
// ii. If Desc.[[Writable]] is present and its value is false, then

2
boa/src/object/internal_methods/array.rs

@ -61,7 +61,7 @@ pub(crate) fn array_exotic_define_own_property(
// 5. If SameValueZero(newLen, numberLen) is false, throw a RangeError exception.
#[allow(clippy::float_cmp)]
if new_len as f64 != number_len {
if f64::from(new_len) != number_len {
return context.throw_range_error("bad length for array");
}

15
boa/src/object/internal_methods/integer_indexed.rs

@ -25,7 +25,7 @@ pub(crate) static INTEGER_INDEXED_EXOTIC_INTERNAL_METHODS: InternalObjectMethods
..ORDINARY_INTERNAL_METHODS
};
/// InternalMethod `[[GetOwnProperty]]` for Integer-Indexed exotic objects.
/// `[[GetOwnProperty]]` internal method for Integer-Indexed exotic objects.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -58,7 +58,7 @@ pub(crate) fn integer_indexed_exotic_get_own_property(
}
}
/// InternalMethod `[[HasProperty]]` for Integer-Indexed exotic objects.
/// `[[HasProperty]]` internal method for Integer-Indexed exotic objects.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -81,7 +81,7 @@ pub(crate) fn integer_indexed_exotic_has_property(
}
}
/// InternalMethod `[[DefineOwnProperty]]` for Integer-Indexed exotic objects.
/// `[[DefineOwnProperty]]` internal method for Integer-Indexed exotic objects.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -116,7 +116,7 @@ pub(crate) fn integer_indexed_exotic_define_own_property(
// vi. If Desc has a [[Value]] field, perform ? IntegerIndexedElementSet(O, numericIndex, Desc.[[Value]]).
if let Some(value) = desc.value() {
integer_indexed_element_set(obj, index as usize, value, context)?
integer_indexed_element_set(obj, index as usize, value, context)?;
}
// vii. Return true.
@ -212,6 +212,7 @@ pub(crate) fn integer_indexed_exotic_delete(
///
/// [spec]: https://tc39.es/ecma262/#sec-integer-indexed-exotic-objects-ownpropertykeys
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn integer_indexed_exotic_own_property_keys(
obj: &JsObject,
_context: &mut Context,
@ -240,7 +241,7 @@ pub(crate) fn integer_indexed_exotic_own_property_keys(
obj.properties
.string_property_keys()
.cloned()
.map(|s| s.into()),
.map(Into::into),
);
// 4. For each own property key P of O such that Type(P) is Symbol, in ascending chronological order of property creation, do
@ -249,7 +250,7 @@ pub(crate) fn integer_indexed_exotic_own_property_keys(
obj.properties
.symbol_property_keys()
.cloned()
.map(|sym| sym.into()),
.map(Into::into),
);
// 5. Return keys.
@ -375,7 +376,7 @@ fn integer_indexed_element_set(
.set_value_in_buffer(
indexed_position,
elem_type,
num_value,
&num_value,
SharedMemoryOrder::Unordered,
None,
context,

35
boa/src/object/internal_methods/mod.rs

@ -333,6 +333,7 @@ pub(crate) struct InternalObjectMethods {
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinarygetprototypeof
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn ordinary_get_prototype_of(
obj: &JsObject,
_context: &mut Context,
@ -350,6 +351,7 @@ pub(crate) fn ordinary_get_prototype_of(
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinarysetprototypeof
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn ordinary_set_prototype_of(
obj: &JsObject,
val: JsPrototype,
@ -392,9 +394,7 @@ pub(crate) fn ordinary_set_prototype_of(
break;
}
// ii. Else, set p to p.[[Prototype]].
else {
p = proto.prototype().clone();
}
p = proto.prototype().clone();
}
// 9. Set O.[[Prototype]] to V.
@ -411,18 +411,20 @@ pub(crate) fn ordinary_set_prototype_of(
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinaryisextensible
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn ordinary_is_extensible(obj: &JsObject, _context: &mut Context) -> JsResult<bool> {
// 1. Return O.[[Extensible]].
Ok(obj.borrow().extensible)
}
/// Abstract operation `OrdinaryPreventExtensions.
/// Abstract operation `OrdinaryPreventExtensions`.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinarypreventextensions
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn ordinary_prevent_extensions(
obj: &JsObject,
_context: &mut Context,
@ -441,6 +443,7 @@ pub(crate) fn ordinary_prevent_extensions(
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinarygetownproperty
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn ordinary_get_own_property(
obj: &JsObject,
key: &PropertyKey,
@ -519,9 +522,8 @@ pub(crate) fn ordinary_has_property(
parent
// 5. If parent is not null, then
// a. Return ? parent.[[HasProperty]](P).
.map(|obj| obj.__has_property__(key, context))
// 6. Return false.
.unwrap_or(Ok(false))
.map_or(Ok(false), |obj| obj.__has_property__(key, context))
}
}
@ -652,11 +654,9 @@ pub(crate) fn ordinary_set(
);
}
// e. Else
else {
// i. Assert: Receiver does not currently have a property P.
// ii. Return ? CreateDataProperty(Receiver, P, V).
return receiver.create_data_property(key, value, context);
}
// i. Assert: Receiver does not currently have a property P.
// ii. Return ? CreateDataProperty(Receiver, P, V).
return receiver.create_data_property(key, value, context);
}
// 4. Assert: IsAccessorDescriptor(ownDesc) is true.
@ -715,6 +715,7 @@ pub(crate) fn ordinary_delete(
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn ordinary_own_property_keys(
obj: &JsObject,
_context: &mut Context,
@ -736,7 +737,7 @@ pub(crate) fn ordinary_own_property_keys(
// 2. For each own property key P of O such that P is an array index, in ascending numeric index order, do
// a. Add P as the last element of keys.
keys.extend(ordered_indexes.into_iter().map(|idx| idx.into()));
keys.extend(ordered_indexes.into_iter().map(Into::into));
// 3. For each own property key P of O such that Type(P) is String and P is not an array index, in ascending chronological order of property creation, do
// a. Add P as the last element of keys.
@ -745,7 +746,7 @@ pub(crate) fn ordinary_own_property_keys(
.properties
.string_property_keys()
.cloned()
.map(|s| s.into()),
.map(Into::into),
);
// 4. For each own property key P of O such that Type(P) is Symbol, in ascending chronological order of property creation, do
@ -755,7 +756,7 @@ pub(crate) fn ordinary_own_property_keys(
.properties
.symbol_property_keys()
.cloned()
.map(|sym| sym.into()),
.map(Into::into),
);
// 5. Return keys.
@ -812,7 +813,7 @@ pub(crate) fn validate_and_apply_property_descriptor(
if let Some((obj, key)) = obj_and_key {
obj.borrow_mut().properties.insert(
key,
&key,
// c. If IsGenericDescriptor(Desc) is true or IsDataDescriptor(Desc) is true, then
if desc.is_generic_descriptor() || desc.is_data_descriptor() {
// i. If O is not undefined, create an own data property named P of
@ -928,8 +929,8 @@ pub(crate) fn validate_and_apply_property_descriptor(
if let Some((obj, key)) = obj_and_key {
// a. For each field of Desc that is present, set the corresponding attribute of the
// property named P of object O to the value of the field.
current.fill_with(desc);
obj.borrow_mut().properties.insert(key, current);
current.fill_with(&desc);
obj.borrow_mut().properties.insert(&key, current);
}
// 10. Return true.

15
boa/src/object/internal_methods/proxy.rs

@ -159,7 +159,7 @@ pub(crate) fn proxy_exotic_set_prototype_of(
&handler.into(),
&[
target.clone().into(),
val.clone().map_or(JsValue::Null, |obj| obj.into()),
val.clone().map_or(JsValue::Null, Into::into),
],
context,
)?
@ -338,14 +338,13 @@ pub(crate) fn proxy_exotic_get_own_property(
return context.throw_type_error(
"Proxy trap result is undefined and target is not extensible",
);
// e. Return undefined.
} else {
return Ok(None);
}
} else {
// a. If targetDesc is undefined, return undefined.
// e. Return undefined.
return Ok(None);
}
// a. If targetDesc is undefined, return undefined.
return Ok(None);
}
// 11. Let extensibleTarget be ? IsExtensible(target).
@ -829,7 +828,7 @@ pub(crate) fn proxy_exotic_own_property_keys(
"Proxy trap result contains duplicate string property keys",
);
}
trap_result.push(s.clone().into())
trap_result.push(s.clone().into());
}
JsValue::Symbol(s) => {
if !unchecked_result_keys.insert(s.clone().into()) {
@ -837,7 +836,7 @@ pub(crate) fn proxy_exotic_own_property_keys(
"Proxy trap result contains duplicate symbol property keys",
);
}
trap_result.push(s.clone().into())
trap_result.push(s.clone().into());
}
_ => {}
}

13
boa/src/object/internal_methods/string.rs

@ -84,6 +84,7 @@ pub(crate) fn string_exotic_define_own_property(
///
/// [spec]: https://tc39.es/ecma262/#sec-string-exotic-objects-ownpropertykeys
#[inline]
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn string_exotic_own_property_keys(
obj: &JsObject,
_context: &mut Context,
@ -103,7 +104,7 @@ pub(crate) fn string_exotic_own_property_keys(
// 5. For each integer i starting with 0 such that i < len, in ascending order, do
// a. Add ! ToString(𝔽(i)) as the last element of keys.
keys.extend((0..len).into_iter().map(|idx| idx.into()));
keys.extend((0..len).into_iter().map(Into::into));
// 6. For each own property key P of O such that P is an array index
// and ! ToIntegerOrInfinity(P) ≥ len, in ascending numeric index order, do
@ -111,11 +112,11 @@ pub(crate) fn string_exotic_own_property_keys(
let mut remaining_indices: Vec<_> = obj
.properties
.index_property_keys()
.cloned()
.copied()
.filter(|idx| (*idx as usize) >= len)
.collect();
remaining_indices.sort_unstable();
keys.extend(remaining_indices.into_iter().map(|idx| idx.into()));
keys.extend(remaining_indices.into_iter().map(Into::into));
// 7. For each own property key P of O such that Type(P) is String and P is not
// an array index, in ascending chronological order of property creation, do
@ -124,7 +125,7 @@ pub(crate) fn string_exotic_own_property_keys(
obj.properties
.string_property_keys()
.cloned()
.map(|s| s.into()),
.map(Into::into),
);
// 8. For each own property key P of O such that Type(P) is Symbol, in ascending
@ -134,14 +135,14 @@ pub(crate) fn string_exotic_own_property_keys(
obj.properties
.symbol_property_keys()
.cloned()
.map(|sym| sym.into()),
.map(Into::into),
);
// 9. Return keys.
Ok(keys)
}
/// StringGetOwnProperty abstract operation
/// `StringGetOwnProperty` abstract operation
///
/// More information:
/// - [ECMAScript reference][spec]

18
boa/src/object/jsobject.rs

@ -2,7 +2,7 @@
//!
//! The `JsObject` is a garbage collected Object.
use super::{JsPrototype, NativeObject, Object};
use super::{JsPrototype, NativeObject, Object, PropertyMap};
use crate::{
gc::{self, Finalize, Gc, Trace},
object::{ObjectData, ObjectKind},
@ -46,12 +46,12 @@ impl JsObject {
/// Create a `JsObject` and automatically set its internal methods and
/// internal slots from the `data` provided.
#[inline]
pub fn from_proto_and_data<O: Into<Option<JsObject>>>(prototype: O, data: ObjectData) -> Self {
pub fn from_proto_and_data<O: Into<Option<Self>>>(prototype: O, data: ObjectData) -> Self {
Self::from_object(Object {
data,
prototype: prototype.into(),
extensible: true,
properties: Default::default(),
properties: PropertyMap::default(),
})
}
@ -245,7 +245,7 @@ impl JsObject {
#[inline]
#[track_caller]
pub fn prototype(&self) -> Ref<'_, JsPrototype> {
Ref::map(self.borrow(), |obj| obj.prototype())
Ref::map(self.borrow(), Object::prototype)
}
/// Get the extensibility of the object.
@ -549,7 +549,7 @@ Cannot both specify accessors and a value or writable attribute",
// 5. Let keys be ? from.[[OwnPropertyKeys]]().
// 6. For each element nextKey of keys, do
let excluded_keys: Vec<PropertyKey> = excluded_keys.into_iter().map(|e| e.into()).collect();
let excluded_keys: Vec<PropertyKey> = excluded_keys.into_iter().map(Into::into).collect();
for key in from.__own_property_keys__(context)? {
// a. Let excluded be false.
let mut excluded = false;
@ -617,7 +617,7 @@ Cannot both specify accessors and a value or writable attribute",
/// It determines if Object is a callable function with a `[[Call]]` internal method.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-iscallable
#[inline]
@ -629,7 +629,7 @@ Cannot both specify accessors and a value or writable attribute",
/// It determines if Object is a function object with a `[[Construct]]` internal method.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-isconstructor
#[inline]
@ -638,7 +638,7 @@ Cannot both specify accessors and a value or writable attribute",
self.borrow().data.internal_methods.__construct__.is_some()
}
/// Returns true if the JsObject is the global for a Realm
/// Returns true if the `JsObject` is the global for a Realm
pub fn is_global(&self) -> bool {
matches!(
self.borrow().data,
@ -659,7 +659,7 @@ impl AsRef<gc::Cell<Object>> for JsObject {
impl PartialEq for JsObject {
fn eq(&self, other: &Self) -> bool {
JsObject::equals(self, other)
Self::equals(self, other)
}
}

9
boa/src/object/mod.rs

@ -416,7 +416,7 @@ impl Debug for ObjectData {
}
impl Default for Object {
/// Return a new ObjectData struct, with `kind` set to Ordinary
/// Return a new `ObjectData` struct, with `kind` set to Ordinary
#[inline]
fn default() -> Self {
Self {
@ -1144,7 +1144,7 @@ impl Object {
K: Into<PropertyKey>,
P: Into<PropertyDescriptor>,
{
self.properties.insert(key.into(), property.into())
self.properties.insert(&key.into(), property.into())
}
/// Helper function for property removal.
@ -1339,8 +1339,9 @@ impl<'context> FunctionBuilder<'context> {
#[inline]
pub fn constructor(&mut self, yes: bool) -> &mut Self {
match self.function.as_mut() {
Some(Function::Native { constructor, .. }) => *constructor = yes,
Some(Function::Closure { constructor, .. }) => *constructor = yes,
Some(Function::Native { constructor, .. } | Function::Closure { constructor, .. }) => {
*constructor = yes;
}
_ => unreachable!(),
}
self

50
boa/src/object/operations.rs

@ -189,7 +189,7 @@ impl JsObject {
/// Defines the property or throws a `TypeError` if the operation fails.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-definepropertyorthrow
#[inline]
@ -421,9 +421,10 @@ impl JsObject {
/// `7.3.22 SpeciesConstructor ( O, defaultConstructor )`
///
/// The abstract operation SpeciesConstructor takes arguments O (an Object) and defaultConstructor (a constructor).
/// It is used to retrieve the constructor that should be used to create new objects that are derived from O.
/// defaultConstructor is the constructor to use if a constructor @@species property cannot be found starting from O.
/// The abstract operation `SpeciesConstructor` takes arguments `O` (an Object) and
/// `defaultConstructor` (a constructor). It is used to retrieve the constructor that should be
/// used to create new objects that are derived from `O`. `defaultConstructor` is the
/// constructor to use if a constructor `@@species` property cannot be found starting from `O`.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -433,7 +434,7 @@ impl JsObject {
&self,
default_constructor: F,
context: &mut Context,
) -> JsResult<JsObject>
) -> JsResult<Self>
where
F: FnOnce(&StandardObjects) -> &StandardConstructor,
{
@ -471,7 +472,7 @@ impl JsObject {
/// It is used to iterate over names of object's keys.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-enumerableownpropertynames
pub(crate) fn enumerable_own_property_names(
@ -491,7 +492,7 @@ impl JsObject {
let key_str = match &key {
PropertyKey::String(s) => Some(s.clone()),
PropertyKey::Index(i) => Some(i.to_string().into()),
_ => None,
PropertyKey::Symbol(_) => None,
};
if let Some(key_str) = key_str {
@ -507,7 +508,7 @@ impl JsObject {
// a. Let value be ? Get(O, key).
// b. If kind is value, append value to properties.
PropertyNameKind::Value => {
properties.push(self.get(key.clone(), context)?)
properties.push(self.get(key.clone(), context)?);
}
// c. Else,
// i. Assert: kind is key+value.
@ -535,10 +536,10 @@ impl JsObject {
/// Retrieves the value of a specific property, when the value of the property is expected to be a function.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-getmethod
pub(crate) fn get_method<K>(&self, key: K, context: &mut Context) -> JsResult<Option<JsObject>>
pub(crate) fn get_method<K>(&self, key: K, context: &mut Context) -> JsResult<Option<Self>>
where
K: Into<PropertyKey>,
{
@ -618,11 +619,11 @@ impl JsValue {
/// type of the value.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-getmethod
#[inline]
pub(crate) fn get_v<K>(&self, key: K, context: &mut Context) -> JsResult<JsValue>
pub(crate) fn get_v<K>(&self, key: K, context: &mut Context) -> JsResult<Self>
where
K: Into<PropertyKey>,
{
@ -638,7 +639,7 @@ impl JsValue {
/// Retrieves the value of a specific property, when the value of the property is expected to be a function.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-getmethod
#[inline]
@ -655,14 +656,14 @@ impl JsValue {
/// self.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-createlistfromarraylike
pub(crate) fn create_list_from_array_like(
&self,
element_types: &[Type],
context: &mut Context,
) -> JsResult<Vec<JsValue>> {
) -> JsResult<Vec<Self>> {
// 1. If elementTypes is not present, set elementTypes to « Undefined, Null, Boolean, String, Symbol, Number, BigInt, Object ».
let types = if element_types.is_empty() {
&[
@ -709,20 +710,15 @@ impl JsValue {
Ok(list)
}
/// Abstract operation `( V, P [ , argumentsList ] )
/// Abstract operation `( V, P [ , argumentsList ] )`
///
/// Calls a method property of an ECMAScript language value.
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-invoke
pub(crate) fn invoke<K>(
&self,
key: K,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue>
pub(crate) fn invoke<K>(&self, key: K, args: &[Self], context: &mut Context) -> JsResult<Self>
where
K: Into<PropertyKey>,
{
@ -737,12 +733,12 @@ impl JsValue {
/// Abstract operation `OrdinaryHasInstance ( C, O )`
///
/// More information:
/// - [EcmaScript reference][spec]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-ordinaryhasinstance
pub fn ordinary_has_instance(
function: &JsValue,
object: &JsValue,
function: &Self,
object: &Self,
context: &mut Context,
) -> JsResult<bool> {
// 1. If IsCallable(C) is false, return false.
@ -756,7 +752,7 @@ impl JsValue {
if let Some(bound_function) = function.borrow().as_bound_function() {
// a. Let BC be C.[[BoundTargetFunction]].
// b. Return ? InstanceofOperator(O, BC).
return JsValue::instance_of(
return Self::instance_of(
object,
&bound_function.target_function().clone().into(),
context,

4
boa/src/object/property_map.rs

@ -7,7 +7,7 @@ use indexmap::IndexMap;
use rustc_hash::{FxHashMap, FxHasher};
use std::{collections::hash_map, hash::BuildHasherDefault, iter::FusedIterator};
/// Wrapper around indexmap::IndexMap for usage in PropertyMap
/// Wrapper around `indexmap::IndexMap` for usage in `PropertyMap`.
#[derive(Debug, Finalize)]
struct OrderedHashMap<K: Trace>(IndexMap<K, PropertyDescriptor, BuildHasherDefault<FxHasher>>);
@ -49,7 +49,7 @@ impl PropertyMap {
pub fn insert(
&mut self,
key: PropertyKey,
key: &PropertyKey,
property: PropertyDescriptor,
) -> Option<PropertyDescriptor> {
match &key {

14
boa/src/profiler.rs

@ -70,18 +70,14 @@ impl Debug for BoaProfiler {
#[cfg(not(feature = "profiler"))]
pub struct BoaProfiler;
#[allow(clippy::unused_unit)]
#[allow(clippy::unused_unit, clippy::unused_self)]
#[cfg(not(feature = "profiler"))]
impl BoaProfiler {
pub fn start_event(&self, _label: &str, _category: &str) -> () {
()
}
pub fn start_event(&self, _label: &str, _category: &str) -> () {}
pub fn drop(&self) {
()
}
pub fn drop(&self) {}
pub fn global() -> BoaProfiler {
BoaProfiler
pub fn global() -> Self {
Self
}
}

113
boa/src/property/mod.rs

@ -1,10 +1,11 @@
//! This module implements the Property Descriptor.
//!
//! The Property Descriptor type is used to explain the manipulation and reification of Object property attributes.
//! Values of the Property Descriptor type are Records. Each field's name is an attribute name
//! and its value is a corresponding attribute value as specified in [6.1.7.1][section].
//! In addition, any field may be present or absent.
//! The schema name used within this specification to tag literal descriptions of Property Descriptor records is “PropertyDescriptor”.
//! The Property Descriptor type is used to explain the manipulation and reification of `Object`
//! property attributes. Values of the Property Descriptor type are Records. Each field's name is
//! an attribute name and its value is a corresponding attribute value as specified in
//! [6.1.7.1][section]. In addition, any field may be present or absent. The schema name used
//! within this specification to tag literal descriptions of Property Descriptor records is
//! `PropertyDescriptor`.
//!
//! More information:
//! - [MDN documentation][mdn]
@ -245,7 +246,7 @@ impl PropertyDescriptor {
}
#[inline]
pub fn fill_with(&mut self, desc: Self) {
pub fn fill_with(&mut self, desc: &Self) {
match (&mut self.kind, &desc.kind) {
(
DescriptorKind::Data { value, writable },
@ -255,10 +256,10 @@ impl PropertyDescriptor {
},
) => {
if let Some(desc_value) = desc_value {
*value = Some(desc_value.clone())
*value = Some(desc_value.clone());
}
if let Some(desc_writable) = desc_writable {
*writable = Some(*desc_writable)
*writable = Some(*desc_writable);
}
}
(
@ -269,10 +270,10 @@ impl PropertyDescriptor {
},
) => {
if let Some(desc_get) = desc_get {
*get = Some(desc_get.clone())
*get = Some(desc_get.clone());
}
if let Some(desc_set) = desc_set {
*set = Some(desc_set.clone())
*set = Some(desc_set.clone());
}
}
(_, DescriptorKind::Generic) => {}
@ -280,10 +281,10 @@ impl PropertyDescriptor {
}
if let Some(enumerable) = desc.enumerable {
self.enumerable = Some(enumerable)
self.enumerable = Some(enumerable);
}
if let Some(configurable) = desc.configurable {
self.configurable = Some(configurable)
self.configurable = Some(configurable);
}
}
}
@ -423,10 +424,10 @@ impl PropertyDescriptorBuilder {
ref mut writable,
} => {
if value.is_none() {
*value = Some(JsValue::undefined())
*value = Some(JsValue::undefined());
}
if writable.is_none() {
*writable = Some(false)
*writable = Some(false);
}
}
DescriptorKind::Accessor {
@ -434,10 +435,10 @@ impl PropertyDescriptorBuilder {
ref mut get,
} => {
if set.is_none() {
*set = Some(JsValue::undefined())
*set = Some(JsValue::undefined());
}
if get.is_none() {
*get = Some(JsValue::undefined())
*get = Some(JsValue::undefined());
}
}
}
@ -465,7 +466,7 @@ impl From<PropertyDescriptorBuilder> for PropertyDescriptor {
}
}
/// This abstracts away the need for IsPropertyKey by transforming the PropertyKey
/// This abstracts away the need for `IsPropertyKey` by transforming the `PropertyKey`
/// values into an enum with both valid types: String and Symbol
///
/// More information:
@ -481,52 +482,52 @@ pub enum PropertyKey {
impl From<JsString> for PropertyKey {
#[inline]
fn from(string: JsString) -> PropertyKey {
fn from(string: JsString) -> Self {
if let Ok(index) = string.parse() {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(string)
Self::String(string)
}
}
}
impl From<&str> for PropertyKey {
#[inline]
fn from(string: &str) -> PropertyKey {
fn from(string: &str) -> Self {
if let Ok(index) = string.parse() {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(string.into())
Self::String(string.into())
}
}
}
impl From<String> for PropertyKey {
#[inline]
fn from(string: String) -> PropertyKey {
fn from(string: String) -> Self {
if let Ok(index) = string.parse() {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(string.into())
Self::String(string.into())
}
}
}
impl From<Box<str>> for PropertyKey {
#[inline]
fn from(string: Box<str>) -> PropertyKey {
fn from(string: Box<str>) -> Self {
if let Ok(index) = string.parse() {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(string.into())
Self::String(string.into())
}
}
}
impl From<JsSymbol> for PropertyKey {
#[inline]
fn from(symbol: JsSymbol) -> PropertyKey {
PropertyKey::Symbol(symbol)
fn from(symbol: JsSymbol) -> Self {
Self::Symbol(symbol)
}
}
@ -534,24 +535,24 @@ impl fmt::Display for PropertyKey {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PropertyKey::String(ref string) => string.fmt(f),
PropertyKey::Symbol(ref symbol) => symbol.fmt(f),
PropertyKey::Index(index) => index.fmt(f),
Self::String(ref string) => string.fmt(f),
Self::Symbol(ref symbol) => symbol.fmt(f),
Self::Index(index) => index.fmt(f),
}
}
}
impl From<&PropertyKey> for JsValue {
#[inline]
fn from(property_key: &PropertyKey) -> JsValue {
fn from(property_key: &PropertyKey) -> Self {
match property_key {
PropertyKey::String(ref string) => string.clone().into(),
PropertyKey::Symbol(ref symbol) => symbol.clone().into(),
PropertyKey::Index(index) => {
if let Ok(integer) = i32::try_from(*index) {
JsValue::new(integer)
Self::new(integer)
} else {
JsValue::new(*index)
Self::new(*index)
}
}
}
@ -560,15 +561,15 @@ impl From<&PropertyKey> for JsValue {
impl From<PropertyKey> for JsValue {
#[inline]
fn from(property_key: PropertyKey) -> JsValue {
fn from(property_key: PropertyKey) -> Self {
match property_key {
PropertyKey::String(ref string) => string.clone().into(),
PropertyKey::Symbol(ref symbol) => symbol.clone().into(),
PropertyKey::Index(index) => {
if let Ok(integer) = i32::try_from(index) {
JsValue::new(integer)
Self::new(integer)
} else {
JsValue::new(index)
Self::new(index)
}
}
}
@ -577,28 +578,28 @@ impl From<PropertyKey> for JsValue {
impl From<u8> for PropertyKey {
fn from(value: u8) -> Self {
PropertyKey::Index(value.into())
Self::Index(value.into())
}
}
impl From<u16> for PropertyKey {
fn from(value: u16) -> Self {
PropertyKey::Index(value.into())
Self::Index(value.into())
}
}
impl From<u32> for PropertyKey {
fn from(value: u32) -> Self {
PropertyKey::Index(value)
Self::Index(value)
}
}
impl From<usize> for PropertyKey {
fn from(value: usize) -> Self {
if let Ok(index) = u32::try_from(value) {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(JsString::from(value.to_string()))
Self::String(JsString::from(value.to_string()))
}
}
}
@ -606,9 +607,9 @@ impl From<usize> for PropertyKey {
impl From<i64> for PropertyKey {
fn from(value: i64) -> Self {
if let Ok(index) = u32::try_from(value) {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(JsString::from(value.to_string()))
Self::String(JsString::from(value.to_string()))
}
}
}
@ -616,9 +617,9 @@ impl From<i64> for PropertyKey {
impl From<u64> for PropertyKey {
fn from(value: u64) -> Self {
if let Ok(index) = u32::try_from(value) {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(JsString::from(value.to_string()))
Self::String(JsString::from(value.to_string()))
}
}
}
@ -626,9 +627,9 @@ impl From<u64> for PropertyKey {
impl From<isize> for PropertyKey {
fn from(value: isize) -> Self {
if let Ok(index) = u32::try_from(value) {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(JsString::from(value.to_string()))
Self::String(JsString::from(value.to_string()))
}
}
}
@ -636,9 +637,9 @@ impl From<isize> for PropertyKey {
impl From<i32> for PropertyKey {
fn from(value: i32) -> Self {
if let Ok(index) = u32::try_from(value) {
PropertyKey::Index(index)
Self::Index(index)
} else {
PropertyKey::String(JsString::from(value.to_string()))
Self::String(JsString::from(value.to_string()))
}
}
}
@ -647,17 +648,17 @@ impl From<f64> for PropertyKey {
fn from(value: f64) -> Self {
use num_traits::cast::FromPrimitive;
if let Some(index) = u32::from_f64(value) {
return PropertyKey::Index(index);
return Self::Index(index);
}
PropertyKey::String(ryu_js::Buffer::new().format(value).into())
Self::String(ryu_js::Buffer::new().format(value).into())
}
}
impl PartialEq<&str> for PropertyKey {
fn eq(&self, other: &&str) -> bool {
match self {
PropertyKey::String(ref string) => string == other,
Self::String(ref string) => string == other,
_ => false,
}
}

32
boa/src/string.rs

@ -211,16 +211,16 @@ impl Inner {
fn new(s: &str) -> NonNull<Self> {
// We get the layout of the `Inner` type and we extend by the size
// of the string array.
let inner_layout = Layout::new::<Inner>();
let inner_layout = Layout::new::<Self>();
let (layout, offset) = inner_layout
.extend(Layout::array::<u8>(s.len()).unwrap())
.unwrap();
let inner = unsafe {
let inner = alloc(layout) as *mut Inner;
let inner = alloc(layout).cast::<Self>();
// Write the first part, the Inner.
inner.write(Inner {
inner.write(Self {
len: s.len(),
refcount: Cell::new(1),
data: [0; 0],
@ -243,7 +243,7 @@ impl Inner {
/// Concatenate array of strings.
#[inline]
fn concat_array(strings: &[&str]) -> NonNull<Inner> {
fn concat_array(strings: &[&str]) -> NonNull<Self> {
let mut total_string_size = 0;
for string in strings {
total_string_size += string.len();
@ -251,16 +251,16 @@ impl Inner {
// We get the layout of the `Inner` type and we extend by the size
// of the string array.
let inner_layout = Layout::new::<Inner>();
let inner_layout = Layout::new::<Self>();
let (layout, offset) = inner_layout
.extend(Layout::array::<u8>(total_string_size).unwrap())
.unwrap();
let inner = unsafe {
let inner = alloc(layout) as *mut Inner;
let inner = alloc(layout).cast::<Self>();
// Write the first part, the Inner.
inner.write(Inner {
inner.write(Self {
len: total_string_size,
refcount: Cell::new(1),
data: [0; 0],
@ -287,15 +287,15 @@ impl Inner {
/// Deallocate inner type with string data.
#[inline]
unsafe fn dealloc(x: NonNull<Inner>) {
unsafe fn dealloc(x: NonNull<Self>) {
let len = (*x.as_ptr()).len;
let inner_layout = Layout::new::<Inner>();
let inner_layout = Layout::new::<Self>();
let (layout, _offset) = inner_layout
.extend(Layout::array::<u8>(len).unwrap())
.unwrap();
dealloc(x.as_ptr() as _, layout);
dealloc(x.as_ptr().cast::<_>(), layout);
}
}
@ -322,7 +322,7 @@ impl JsString {
/// Create an empty string, same as calling default.
#[inline]
pub fn empty() -> Self {
JsString::default()
Self::default()
}
/// Create a new JavaScript string.
@ -343,7 +343,7 @@ impl JsString {
}
/// Concatenate two string.
pub fn concat<T, U>(x: T, y: U) -> JsString
pub fn concat<T, U>(x: T, y: U) -> Self
where
T: AsRef<str>,
U: AsRef<str>,
@ -366,7 +366,7 @@ impl JsString {
}
/// Concatenate array of string.
pub fn concat_array(strings: &[&str]) -> JsString {
pub fn concat_array(strings: &[&str]) -> Self {
let this = Self {
inner: Inner::concat_array(strings),
_marker: PhantomData,
@ -500,7 +500,7 @@ impl Clone for JsString {
let inner = self.inner();
inner.refcount.set(inner.refcount.get() + 1);
JsString {
Self {
inner: self.inner,
_marker: PhantomData,
}
@ -581,7 +581,7 @@ impl Deref for JsString {
}
}
impl PartialEq<JsString> for JsString {
impl PartialEq<Self> for JsString {
#[inline]
fn eq(&self, other: &Self) -> bool {
// If they point at the same memory allocation, then they are equal.
@ -651,7 +651,7 @@ mod tests {
#[test]
fn empty() {
let _ = JsString::new("");
let _empty = JsString::new("");
}
#[test]

2
boa/src/symbol.rs

@ -120,7 +120,7 @@ impl WellKnownSymbols {
/// The `Symbol.asyncIterator` well known symbol.
///
/// A method that returns the default AsyncIterator for an object.
/// A method that returns the default `AsyncIterator` for an object.
/// Called by the semantics of the `for-await-of` statement.
#[inline]
pub fn async_iterator() -> JsSymbol {

4
boa/src/syntax/ast/keyword.rs

@ -386,8 +386,8 @@ pub enum Keyword {
/// - [MDN documentation][mdn]
///
/// [node]: ../node/enum.Node.html#variant.Throw
/// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
/// [spec]: https://tc39.es/ecma262/#sec-throw-statement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw
Throw,
/// The `true` keyword

2
boa/src/syntax/ast/node/conditional/conditional_op/mod.rs

@ -69,7 +69,7 @@ impl ToInternedString for ConditionalOp {
}
impl From<ConditionalOp> for Node {
fn from(cond_op: ConditionalOp) -> Node {
fn from(cond_op: ConditionalOp) -> Self {
Self::ConditionalOp(cond_op)
}
}

2
boa/src/syntax/ast/node/conditional/if_node/mod.rs

@ -88,7 +88,7 @@ impl ToInternedString for If {
}
impl From<If> for Node {
fn from(if_stm: If) -> Node {
fn from(if_stm: If) -> Self {
Self::If(if_stm)
}
}

61
boa/src/syntax/ast/node/declaration/mod.rs

@ -95,7 +95,7 @@ pub enum DeclarationList {
impl AsRef<[Declaration]> for DeclarationList {
fn as_ref(&self) -> &[Declaration] {
use DeclarationList::*;
use DeclarationList::{Const, Let, Var};
match self {
Var(list) | Const(list) | Let(list) => list,
}
@ -104,8 +104,10 @@ impl AsRef<[Declaration]> for DeclarationList {
impl ToInternedString for DeclarationList {
fn to_interned_string(&self, interner: &Interner) -> String {
if !self.as_ref().is_empty() {
use DeclarationList::*;
if self.as_ref().is_empty() {
String::new()
} else {
use DeclarationList::{Const, Let, Var};
format!(
"{} {}",
match &self {
@ -115,19 +117,17 @@ impl ToInternedString for DeclarationList {
},
join_nodes(interner, self.as_ref())
)
} else {
String::new()
}
}
}
impl From<DeclarationList> for Node {
fn from(list: DeclarationList) -> Self {
use DeclarationList::*;
use DeclarationList::{Const, Let, Var};
match &list {
Let(_) => Node::LetDeclList(list),
Const(_) => Node::ConstDeclList(list),
Var(_) => Node::VarDeclList(list),
Let(_) => Self::LetDeclList(list),
Const(_) => Self::ConstDeclList(list),
Var(_) => Self::VarDeclList(list),
}
}
}
@ -140,9 +140,9 @@ impl From<Declaration> for Box<[Declaration]> {
/// Declaration represents either an individual binding or a binding pattern.
///
/// For `let` and `const` declarations this type represents a [LexicalBinding][spec1]
/// For `let` and `const` declarations this type represents a [`LexicalBinding`][spec1]
///
/// For `var` declarations this type represents a [VariableDeclaration][spec2]
/// For `var` declarations this type represents a [`VariableDeclaration`][spec2]
///
/// More information:
/// - [ECMAScript reference: 14.3 Declarations and the Variable Statement][spec3]
@ -176,7 +176,7 @@ impl ToInternedString for Declaration {
}
impl Declaration {
/// Creates a new variable declaration with a BindingIdentifier.
/// Creates a new variable declaration with a `BindingIdentifier`.
#[inline]
pub(in crate::syntax) fn new_with_identifier<N, I>(ident: N, init: I) -> Self
where
@ -189,7 +189,7 @@ impl Declaration {
}
}
/// Creates a new variable declaration with an ObjectBindingPattern.
/// Creates a new variable declaration with an `ObjectBindingPattern`.
#[inline]
pub(in crate::syntax) fn new_with_object_pattern<I>(
bindings: Vec<BindingPatternTypeObject>,
@ -204,7 +204,7 @@ impl Declaration {
)))
}
/// Creates a new variable declaration with an ArrayBindingPattern.
/// Creates a new variable declaration with an `ArrayBindingPattern`.
#[inline]
pub(in crate::syntax) fn new_with_array_pattern<I>(
bindings: Vec<BindingPatternTypeArray>,
@ -229,12 +229,12 @@ impl Declaration {
}
}
/// DeclarationPattern represents an object or array binding pattern.
/// `DeclarationPattern` represents an object or array binding pattern.
///
/// This enum mostly wraps the functionality of the specific binding pattern types.
///
/// More information:
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - BindingPattern][spec1]
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - `BindingPattern`][spec1]
///
/// [spec1]: https://tc39.es/ecma262/#prod-BindingPattern
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
@ -275,12 +275,12 @@ impl DeclarationPattern {
}
}
/// DeclarationPatternObject represents an object binding pattern.
/// `DeclarationPatternObject` represents an object binding pattern.
///
/// This struct holds a list of bindings, and an optional initializer for the binding pattern.
///
/// More information:
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - ObjectBindingPattern][spec1]
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - `ObjectBindingPattern`][spec1]
///
/// [spec1]: https://tc39.es/ecma262/#prod-ObjectBindingPattern
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
@ -339,7 +339,7 @@ impl DeclarationPatternObject {
let mut idents = Vec::new();
for binding in &self.bindings {
use BindingPatternTypeObject::*;
use BindingPatternTypeObject::{BindingPattern, Empty, RestProperty, SingleName};
match binding {
Empty => {}
@ -372,12 +372,12 @@ impl DeclarationPatternObject {
}
}
/// DeclarationPatternArray represents an array binding pattern.
/// `DeclarationPatternArray` represents an array binding pattern.
///
/// This struct holds a list of bindings, and an optional initializer for the binding pattern.
///
/// More information:
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - ArrayBindingPattern][spec1]
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - `ArrayBindingPattern`][spec1]
///
/// [spec1]: https://tc39.es/ecma262/#prod-ArrayBindingPattern
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
@ -394,7 +394,7 @@ impl ToInternedString for DeclarationPatternArray {
if i == self.bindings.len() - 1 {
match binding {
BindingPatternTypeArray::Elision => {
buf.push_str(&format!("{}, ", binding.to_interned_string(interner)))
buf.push_str(&format!("{}, ", binding.to_interned_string(interner)));
}
_ => buf.push_str(&format!("{} ", binding.to_interned_string(interner))),
}
@ -438,11 +438,12 @@ impl DeclarationPatternArray {
let mut idents = Vec::new();
for binding in &self.bindings {
use BindingPatternTypeArray::*;
use BindingPatternTypeArray::{
BindingPattern, BindingPatternRest, Elision, Empty, SingleName, SingleNameRest,
};
match binding {
Empty => {}
Elision => {}
Empty | Elision => {}
SingleName {
ident,
default_init: _,
@ -451,7 +452,7 @@ impl DeclarationPatternArray {
}
BindingPattern { pattern } | BindingPatternRest { pattern } => {
let mut i = pattern.idents();
idents.append(&mut i)
idents.append(&mut i);
}
SingleNameRest { ident } => idents.push(*ident),
}
@ -461,10 +462,10 @@ impl DeclarationPatternArray {
}
}
/// BindingPatternTypeObject represents the different types of bindings that an object binding pattern may contain.
/// `BindingPatternTypeObject` represents the different types of bindings that an object binding pattern may contain.
///
/// More information:
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - ObjectBindingPattern][spec1]
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - `ObjectBindingPattern`][spec1]
///
/// [spec1]: https://tc39.es/ecma262/#prod-ObjectBindingPattern
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
@ -565,10 +566,10 @@ impl ToInternedString for BindingPatternTypeObject {
}
}
/// BindingPatternTypeArray represents the different types of bindings that an array binding pattern may contain.
/// `BindingPatternTypeArray` represents the different types of bindings that an array binding pattern may contain.
///
/// More information:
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - ArrayBindingPattern][spec1]
/// - [ECMAScript reference: 14.3.3 Destructuring Binding Patterns - `ArrayBindingPattern`][spec1]
///
/// [spec1]: https://tc39.es/ecma262/#prod-ArrayBindingPattern
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]

2
boa/src/syntax/ast/node/field/get_const_field/mod.rs

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
/// [dot notation][mdn].
///
/// In the object.property syntax, the property must be a valid JavaScript identifier.
/// (In the ECMAScript standard, the names of properties are technically "IdentifierNames", not
/// (In the ECMAScript standard, the names of properties are technically `IdentifierNames`, not
/// "Identifiers", so reserved words can be used but are not recommended).
///
/// One can think of an object as an associative array (a.k.a. map, dictionary, hash, lookup

2
boa/src/syntax/ast/node/field/get_field/mod.rs

@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
/// This property accessor provides access to an object's properties by using the
/// [bracket notation][mdn].
///
/// In the object\[property_name\] syntax, the property_name is just a string or
/// In the `object[property_name]` syntax, the `property_name` is just a string or
/// [Symbol][symbol]. So, it can be any string, including '1foo', '!bar!', or even ' ' (a
/// space).
///

2
boa/src/syntax/ast/node/iteration/break_node/mod.rs

@ -65,7 +65,7 @@ impl ToInternedString for Break {
}
impl From<Break> for Node {
fn from(break_smt: Break) -> Node {
fn from(break_smt: Break) -> Self {
Self::Break(break_smt)
}
}

2
boa/src/syntax/ast/node/iteration/continue_node/mod.rs

@ -53,7 +53,7 @@ impl ToInternedString for Continue {
}
impl From<Continue> for Node {
fn from(cont: Continue) -> Node {
fn from(cont: Continue) -> Self {
Self::Continue(cont)
}
}

2
boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs

@ -79,7 +79,7 @@ impl ToInternedString for ForInLoop {
}
impl From<ForInLoop> for Node {
fn from(for_in: ForInLoop) -> Node {
fn from(for_in: ForInLoop) -> Self {
Self::ForInLoop(for_in)
}
}

2
boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs

@ -80,7 +80,7 @@ impl ToInternedString for ForOfLoop {
}
impl From<ForOfLoop> for Node {
fn from(for_of: ForOfLoop) -> Node {
fn from(for_of: ForOfLoop) -> Self {
Self::ForOfLoop(for_of)
}
}

6
boa/src/syntax/ast/node/iteration/tests.rs

@ -336,7 +336,7 @@ fn for_loop_break_label() {
}
str
"#;
assert_eq!(&exec(scenario), "\"01\"")
assert_eq!(&exec(scenario), "\"01\"");
}
#[test]
@ -462,7 +462,7 @@ fn for_in_break_label() {
}
str
"#;
assert_eq!(&exec(scenario), "\"0\"")
assert_eq!(&exec(scenario), "\"0\"");
}
#[test]
@ -481,7 +481,7 @@ fn for_in_continue_label() {
}
str
"#;
assert_eq!(&exec(scenario), "\"00\"")
assert_eq!(&exec(scenario), "\"00\"");
}
#[test]

14
boa/src/syntax/ast/node/mod.rs

@ -230,7 +230,8 @@ impl From<Const> for Node {
impl Node {
/// Returns a node ordering based on the hoistability of each node.
pub(crate) fn hoistable_order(a: &Node, b: &Node) -> Ordering {
#[allow(clippy::match_same_arms)]
pub(crate) fn hoistable_order(a: &Self, b: &Self) -> Ordering {
match (a, b) {
(Node::FunctionDecl(_), Node::FunctionDecl(_)) => Ordering::Equal,
(_, Node::FunctionDecl(_)) => Ordering::Greater,
@ -307,8 +308,9 @@ impl Node {
Self::TemplateLit(ref template) => template.to_interned_string(interner),
Self::Throw(ref throw) => throw.to_interned_string(interner),
Self::Assign(ref op) => op.to_interned_string(interner),
Self::LetDeclList(ref decl) => decl.to_interned_string(interner),
Self::ConstDeclList(ref decl) => decl.to_interned_string(interner),
Self::LetDeclList(ref decl) | Self::ConstDeclList(ref decl) => {
decl.to_interned_string(interner)
}
Self::AsyncFunctionDecl(ref decl) => decl.to_indented_string(interner, indentation),
Self::AsyncFunctionExpr(ref expr) => expr.to_indented_string(interner, indentation),
Self::AwaitExpr(ref expr) => expr.to_interned_string(interner),
@ -341,7 +343,7 @@ where
} else {
buf.push_str(", ");
}
buf.push_str(&e.to_interned_string(interner))
buf.push_str(&e.to_interned_string(interner));
}
buf
}
@ -606,7 +608,7 @@ unsafe impl Trace for MethodDefinitionKind {
empty_trace!();
}
/// PropertyName can be either a literal or computed.
/// `PropertyName` can be either a literal or computed.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -657,7 +659,7 @@ unsafe impl Trace for PropertyName {
}
/// This parses the given source code, and then makes sure that
/// the resulting StatementList is formatted in the same manner
/// the resulting `StatementList` is formatted in the same manner
/// as the source code. This is expected to have a preceding
/// newline.
///

10
boa/src/syntax/ast/node/object/mod.rs

@ -49,10 +49,10 @@ impl Object {
pub(in crate::syntax::ast::node) fn to_indented_string(
&self,
interner: &Interner,
indent: usize,
indent_n: usize,
) -> String {
let mut buf = "{\n".to_owned();
let indentation = " ".repeat(indent + 1);
let indentation = " ".repeat(indent_n + 1);
for property in self.properties().iter() {
buf.push_str(&match property {
PropertyDefinition::IdentifierReference(ident) => {
@ -63,7 +63,7 @@ impl Object {
"{}{}: {},\n",
indentation,
key.to_interned_string(interner),
value.to_no_indent_string(interner, indent + 1)
value.to_no_indent_string(interner, indent_n + 1)
)
}
PropertyDefinition::SpreadObject(key) => {
@ -83,12 +83,12 @@ impl Object {
},
key.to_interned_string(interner),
join_nodes(interner, node.parameters()),
block_to_string(node.body(), interner, indent + 1)
block_to_string(node.body(), interner, indent_n + 1)
)
}
});
}
buf.push_str(&format!("{}}}", " ".repeat(indent)));
buf.push_str(&format!("{}}}", " ".repeat(indent_n)));
buf
}

4
boa/src/syntax/ast/node/return_smt/mod.rs

@ -59,8 +59,8 @@ impl Return {
}
impl From<Return> for Node {
fn from(return_smt: Return) -> Node {
Node::Return(return_smt)
fn from(return_smt: Return) -> Self {
Self::Return(return_smt)
}
}

2
boa/src/syntax/ast/node/spread/mod.rs

@ -56,7 +56,7 @@ impl ToInternedString for Spread {
}
impl From<Spread> for Node {
fn from(spread: Spread) -> Node {
fn from(spread: Spread) -> Self {
Self::Spread(spread)
}
}

6
boa/src/syntax/ast/node/template/mod.rs

@ -29,7 +29,7 @@ impl TemplateLit {
where
E: Into<Box<[TemplateElement]>>,
{
TemplateLit {
Self {
elements: elements.into(),
}
}
@ -47,7 +47,7 @@ impl ToInternedString for TemplateLit {
match elt {
TemplateElement::String(s) => buf.push_str(interner.resolve_expect(*s)),
TemplateElement::Expr(n) => {
buf.push_str(&format!("${{{}}}", n.to_interned_string(interner)))
buf.push_str(&format!("${{{}}}", n.to_interned_string(interner)));
}
}
}
@ -117,7 +117,7 @@ impl ToInternedString for TaggedTemplate {
impl From<TaggedTemplate> for Node {
fn from(template: TaggedTemplate) -> Self {
Node::TaggedTemplate(template)
Self::TaggedTemplate(template)
}
}

2
boa/src/syntax/ast/node/throw/mod.rs

@ -53,7 +53,7 @@ impl ToInternedString for Throw {
}
impl From<Throw> for Node {
fn from(trw: Throw) -> Node {
fn from(trw: Throw) -> Self {
Self::Throw(trw)
}
}

4
boa/src/syntax/ast/node/yield/mod.rs

@ -45,8 +45,8 @@ impl Yield {
}
impl From<Yield> for Node {
fn from(r#yield: Yield) -> Node {
Node::Yield(r#yield)
fn from(r#yield: Yield) -> Self {
Self::Yield(r#yield)
}
}

6
boa/src/syntax/ast/position.rs

@ -9,8 +9,9 @@ use serde::{Deserialize, Serialize};
///
/// Stores both the column number and the line number.
///
/// Note that spans are of the form [begining, end) i.e. that the begining position is inclusive and the end position is exclusive.
/// See test check_positions from syntax/lexer/tests.rs for an example.
/// Note that spans are of the form [begining, end) i.e. that the begining position is inclusive
/// and the end position is exclusive. See test `check_positions` from `syntax/lexer/tests.rs` for
/// an example.
///
/// ## Similar Implementations
/// [V8: Location](https://cs.chromium.org/chromium/src/v8/src/parsing/scanner.h?type=cs&q=isValid+Location&g=0&l=216)
@ -126,6 +127,7 @@ impl fmt::Display for Span {
}
#[cfg(test)]
#[allow(clippy::similar_names)]
mod tests {
use super::{Position, Span};

7
boa/src/syntax/lexer/comment.rs

@ -40,10 +40,9 @@ impl<R> Tokenizer<R> for SingleLineComment {
while let Some(ch) = cursor.peek()? {
if ch == b'\n' || ch == b'\r' {
break;
} else {
// Consume char.
cursor.next_byte()?.expect("Comment character vanished");
}
// Consume char.
cursor.next_byte()?.expect("Comment character vanished");
}
Ok(Token::new(
TokenKind::Comment,
@ -91,7 +90,7 @@ impl<R> Tokenizer<R> for MultiLineComment {
))
}
Ok(c) if c == '\r' || c == '\n' || c == '\u{2028}' || c == '\u{2029}' => {
new_line = true
new_line = true;
}
_ => {}
};

27
boa/src/syntax/lexer/cursor.rs

@ -38,7 +38,7 @@ impl<R> Cursor<R> {
#[inline]
pub(super) fn set_strict_mode(&mut self, strict_mode: bool) {
self.strict_mode = strict_mode
self.strict_mode = strict_mode;
}
}
@ -236,7 +236,7 @@ where
// Try to take a newline if it's next, for windows "\r\n" newlines
// Otherwise, treat as a Mac OS9 bare '\r' newline
if self.peek()? == Some(b'\n') {
let _ = self.iter.next_byte();
let _next = self.iter.next_byte();
}
self.next_line();
}
@ -270,12 +270,12 @@ where
// Try to take a newline if it's next, for windows "\r\n" newlines
// Otherwise, treat as a Mac OS9 bare '\r' newline
if self.peek()? == Some(0xA) {
let _ = self.iter.next_byte();
let _next = self.iter.next_byte();
}
self.next_line();
}
// '\n' | '\u{2028}' | '\u{2029}'
Some(0xA) | Some(0x2028) | Some(0x2029) => self.next_line(),
Some(0xA | 0x2028 | 0x2029) => self.next_line(),
Some(_) => self.next_column(),
_ => {}
}
@ -286,6 +286,7 @@ where
/// Inner iterator for a cursor.
#[derive(Debug)]
#[allow(clippy::option_option)]
struct InnerIter<R> {
iter: Bytes<R>,
num_peeked_bytes: u8,
@ -348,7 +349,7 @@ where
match self.iter.next().transpose()? {
Some(byte) => {
self.num_peeked_bytes = 1;
self.peeked_bytes = byte as u32;
self.peeked_bytes = u32::from(byte);
Ok(Some(byte))
}
None => Ok(None),
@ -362,7 +363,7 @@ where
while self.num_peeked_bytes < n && self.num_peeked_bytes < 4 {
match self.iter.next().transpose()? {
Some(byte) => {
self.peeked_bytes |= (byte as u32) << (self.num_peeked_bytes * 8);
self.peeked_bytes |= u32::from(byte) << (self.num_peeked_bytes * 8);
self.num_peeked_bytes += 1;
}
None => break,
@ -387,8 +388,8 @@ where
// Decode UTF-8
let x = match self.peek_byte()? {
Some(b) if b < 128 => {
self.peeked_char = Some(Some(b as u32));
return Ok(Some(b as u32));
self.peeked_char = Some(Some(u32::from(b)));
return Ok(Some(u32::from(b)));
}
Some(b) => b,
None => {
@ -407,7 +408,7 @@ where
// [[x y z] w] case
// 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
let z = (self.peek_n_bytes(3)? >> 16) as u8;
let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
let y_z = utf8_acc_cont_byte(u32::from(y & CONT_MASK), z);
ch = init << 12 | y_z;
if x >= 0xF0 {
// [x y z w] case
@ -448,7 +449,7 @@ where
// Decode UTF-8
let x = match self.next_byte()? {
Some(b) if b < 128 => return Ok(Some(b as u32)),
Some(b) if b < 128 => return Ok(Some(u32::from(b))),
Some(b) => b,
None => return Ok(None),
};
@ -463,7 +464,7 @@ where
// [[x y z] w] case
// 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
let z = unwrap_or_0(self.next_byte()?);
let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
let y_z = utf8_acc_cont_byte(u32::from(y & CONT_MASK), z);
ch = init << 12 | y_z;
if x >= 0xF0 {
// [x y z w] case
@ -485,13 +486,13 @@ const CONT_MASK: u8 = 0b0011_1111;
/// for width 3, and 3 bits for width 4.
#[inline]
fn utf8_first_byte(byte: u8, width: u32) -> u32 {
(byte & (0x7F >> width)) as u32
u32::from(byte & (0x7F >> width))
}
/// Returns the value of `ch` updated with continuation byte `byte`.
#[inline]
fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 {
(ch << 6) | (byte & CONT_MASK) as u32
(ch << 6) | u32::from(byte & CONT_MASK)
}
/// Checks whether the byte is a UTF-8 first byte (i.e., ascii byte or starts with the

11
boa/src/syntax/lexer/identifier.rs

@ -47,7 +47,7 @@ impl Identifier {
Self { init }
}
/// Checks if a character is IdentifierStart as per ECMAScript standards.
/// Checks if a character is `IdentifierStart` as per ECMAScript standards.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -62,7 +62,7 @@ impl Identifier {
}
}
/// Checks if a character is IdentifierPart as per ECMAScript standards.
/// Checks if a character is `IdentifierPart` as per ECMAScript standards.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -146,6 +146,9 @@ impl Identifier {
where
R: Read,
{
let _timer =
BoaProfiler::global().start_event("Identifier::take_identifier_name", "Lexing");
let mut contains_escaped_chars = false;
let mut identifier_name = if init == '\\' && cursor.next_is(b'u')? {
let ch = StringLiteral::take_unicode_escape_sequence(cursor, start_pos)?;
@ -165,8 +168,8 @@ impl Identifier {
let ch = match cursor.peek_char()? {
Some(0x005C /* \ */) if cursor.peek_n(2)? >> 8 == 0x0075 /* u */ => {
let pos = cursor.pos();
let _ = cursor.next_byte();
let _ = cursor.next_byte();
let _next = cursor.next_byte();
let _next = cursor.next_byte();
let ch = StringLiteral::take_unicode_escape_sequence(cursor, pos)?;
if Self::is_identifier_part(ch) {

6
boa/src/syntax/lexer/mod.rs

@ -106,7 +106,7 @@ impl<R> Lexer<R> {
#[inline]
pub(super) fn set_strict_mode(&mut self, strict_mode: bool) {
self.cursor.set_strict_mode(strict_mode)
self.cursor.set_strict_mode(strict_mode);
}
/// Creates a new lexer.
@ -117,7 +117,7 @@ impl<R> Lexer<R> {
{
Self {
cursor: Cursor::new(reader),
goal_symbol: Default::default(),
goal_symbol: InputElement::default(),
}
}
@ -333,6 +333,6 @@ pub(crate) enum InputElement {
impl Default for InputElement {
fn default() -> Self {
InputElement::RegExp
Self::RegExp
}
}

41
boa/src/syntax/lexer/number.rs

@ -49,17 +49,15 @@ impl NumericKind {
fn base(self) -> u32 {
match self {
Self::Rational => 10,
Self::Integer(base) => base,
Self::BigInt(base) => base,
Self::Integer(base) | Self::BigInt(base) => base,
}
}
/// Converts `self` to BigInt kind.
/// Converts `self` to `BigInt` kind.
fn to_bigint(self) -> Self {
match self {
Self::Rational => unreachable!("can not convert rational number to BigInt"),
Self::Integer(base) => Self::BigInt(base),
Self::BigInt(base) => Self::BigInt(base),
Self::Integer(base) | Self::BigInt(base) => Self::BigInt(base),
}
}
}
@ -68,7 +66,7 @@ impl NumericKind {
fn take_signed_integer<R>(
buf: &mut Vec<u8>,
cursor: &mut Cursor<R>,
kind: &NumericKind,
kind: NumericKind,
) -> Result<(), Error>
where
R: Read,
@ -118,7 +116,7 @@ where
fn take_integer<R>(
buf: &mut Vec<u8>,
cursor: &mut Cursor<R>,
kind: &NumericKind,
kind: NumericKind,
separator_allowed: bool,
) -> Result<(), Error>
where
@ -156,7 +154,8 @@ where
}
Ok(())
}
/// Utility function for checking the NumericLiteral is not followed by an `IdentifierStart` or `DecimalDigit` character.
/// Utility function for checking the `NumericLiteral` is not followed by an `IdentifierStart` or `DecimalDigit` character.
///
/// More information:
/// - [ECMAScript Specification][spec]
@ -268,14 +267,14 @@ impl<R> Tokenizer<R> for NumberLiteral {
"implicit octal literals are not allowed in strict mode",
start_pos,
));
} else {
// Remove the initial '0' from buffer.
buf.pop();
}
buf.push(cursor.next_byte()?.expect("'0' character vanished"));
// Remove the initial '0' from buffer.
buf.pop();
kind = NumericKind::Integer(8);
}
buf.push(cursor.next_byte()?.expect("'0' character vanished"));
kind = NumericKind::Integer(8);
} else if ch.is_digit(10) {
// Indicates a numerical digit comes after then 0 but it isn't an octal digit
// so therefore this must be a number with an unneeded leading 0. This is
@ -304,7 +303,7 @@ impl<R> Tokenizer<R> for NumberLiteral {
} else {
// Consume digits and separators until a non-digit non-separator
// character is encountered or all the characters are consumed.
take_integer(&mut buf, cursor, &kind, !legacy_octal)?;
take_integer(&mut buf, cursor, kind, !legacy_octal)?;
cursor.peek()?
};
@ -346,18 +345,18 @@ impl<R> Tokenizer<R> for NumberLiteral {
// Consume digits and separators until a non-digit non-separator
// character is encountered or all the characters are consumed.
take_integer(&mut buf, cursor, &kind, true)?;
take_integer(&mut buf, cursor, kind, true)?;
// The non-digit character at this point must be an 'e' or 'E' to indicate an Exponent Part.
// Another '.' or 'n' is not allowed.
match cursor.peek()? {
Some(b'e') | Some(b'E') => {
Some(b'e' | b'E') => {
// Consume the ExponentIndicator.
cursor.next_byte()?.expect("e or E token vanished");
buf.push(b'E');
take_signed_integer(&mut buf, cursor, &kind)?;
take_signed_integer(&mut buf, cursor, kind)?;
}
Some(_) | None => {
// Finished lexing.
@ -365,11 +364,11 @@ impl<R> Tokenizer<R> for NumberLiteral {
}
}
}
Some(b'e') | Some(b'E') => {
Some(b'e' | b'E') => {
kind = NumericKind::Rational;
cursor.next_byte()?.expect("e or E character vanished"); // Consume the ExponentIndicator.
buf.push(b'E');
take_signed_integer(&mut buf, cursor, &kind)?;
take_signed_integer(&mut buf, cursor, kind)?;
}
Some(_) | None => {
// Indicates lexing finished.
@ -392,7 +391,7 @@ impl<R> Tokenizer<R> for NumberLiteral {
// The truncated float should be identically to the non-truncated float for the conversion to be loss-less,
// any other different and the number must be stored as a rational.
#[allow(clippy::float_cmp)]
if (int_val as f64) == val {
if f64::from(int_val) == val {
// For performance reasons we attempt to store values as integers if possible.
Numeric::Integer(int_val)
} else {

5
boa/src/syntax/lexer/regex.rs

@ -110,7 +110,7 @@ impl<R> Tokenizer<R> for RegexLiteral {
let mut flags = Vec::new();
let flags_start = cursor.pos();
cursor.take_while_ascii_pred(&mut flags, &|c: char| c.is_alphabetic())?;
cursor.take_while_ascii_pred(&mut flags, &char::is_alphabetic)?;
let flags_str = unsafe { str::from_utf8_unchecked(flags.as_slice()) };
if let Ok(body_str) = str::from_utf8(body.as_slice()) {
@ -166,9 +166,8 @@ fn parse_regex_flags(s: &str, start: Position, interner: &mut Interner) -> Resul
format!("repeated regular expression flag {}", char::from(c)),
start,
));
} else {
flags.insert(new_flag);
}
flags.insert(new_flag);
}
Ok(interner.get_or_intern(flags.to_string()))
}

29
boa/src/syntax/lexer/string.rs

@ -100,7 +100,7 @@ impl<R> Tokenizer<R> for StringLiteral {
}
impl StringLiteral {
/// Checks if a character is LineTerminator as per ECMAScript standards.
/// Checks if a character is `LineTerminator` as per ECMAScript standards.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -212,9 +212,8 @@ impl StringLiteral {
"\\8 and \\9 are not allowed in strict mode",
start_pos,
));
} else {
Some(escape_ch)
}
Some(escape_ch)
}
_ if (0x0030..=0x0037 /* '0'..='7' */).contains(&escape_ch) => {
if is_template_literal {
@ -222,17 +221,19 @@ impl StringLiteral {
"octal escape sequences are not allowed in template literal",
start_pos,
));
} else if is_strict_mode {
}
if is_strict_mode {
return Err(Error::syntax(
"octal escape sequences are not allowed in strict mode",
start_pos,
));
} else {
Some(Self::take_legacy_octal_escape_sequence(
cursor,
escape_ch as u8,
)?)
}
Some(Self::take_legacy_octal_escape_sequence(
cursor,
escape_ch as u8,
)?)
}
_ if Self::is_line_terminator(escape_ch) => {
// Grammar: LineContinuation
@ -293,7 +294,7 @@ impl StringLiteral {
.and_then(|code_point_str| u16::from_str_radix(code_point_str, 16).ok())
.ok_or_else(|| Error::syntax("invalid Unicode escape sequence", start_pos))?;
Ok(code_point as u32)
Ok(u32::from(code_point))
}
}
@ -312,7 +313,7 @@ impl StringLiteral {
.and_then(|code_point_str| u16::from_str_radix(code_point_str, 16).ok())
.ok_or_else(|| Error::syntax("invalid Hexadecimal escape sequence", start_pos))?;
Ok(code_point as u32)
Ok(u32::from(code_point))
}
#[inline]
@ -324,21 +325,21 @@ impl StringLiteral {
R: Read,
{
// Grammar: OctalDigit
let mut code_point = (init_byte - b'0') as u32;
let mut code_point = u32::from(init_byte - b'0');
// Grammar: ZeroToThree OctalDigit
// Grammar: FourToSeven OctalDigit
if let Some(byte) = cursor.peek()? {
if (b'0'..=b'7').contains(&byte) {
let _ = cursor.next_byte()?;
code_point = (code_point * 8) + (byte - b'0') as u32;
code_point = (code_point * 8) + u32::from(byte - b'0');
if (b'0'..=b'3').contains(&init_byte) {
// Grammar: ZeroToThree OctalDigit OctalDigit
if let Some(byte) = cursor.peek()? {
if (b'0'..=b'7').contains(&byte) {
let _ = cursor.next_byte()?;
code_point = (code_point * 8) + (byte - b'0') as u32;
code_point = (code_point * 8) + u32::from(byte - b'0');
}
}
}

6
boa/src/syntax/lexer/template.rs

@ -86,7 +86,7 @@ impl TemplateString {
/// Template literal lexing.
///
/// Expects: Initial ` to already be consumed by cursor.
/// Expects: Initial `` ` `` to already be consumed by cursor.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -147,9 +147,9 @@ impl<R> Tokenizer<R> for TemplateLiteral {
))
})?;
buf.push(b'\\' as u16);
buf.push(u16::from(b'\\'));
match escape_ch {
b'`' | b'$' | b'\\' => buf.push(cursor.next_byte()?.unwrap() as u16),
b'`' | b'$' | b'\\' => buf.push(u16::from(cursor.next_byte()?.unwrap())),
_ => continue,
}
}

18
boa/src/syntax/lexer/tests.rs

@ -105,7 +105,7 @@ fn check_identifier() {
fn check_invalid_identifier_start() {
let invalid_identifier_starts = ["\u{200C}", "\u{200D}", "😀"];
for s in invalid_identifier_starts.iter() {
for s in &invalid_identifier_starts {
let mut lexer = Lexer::new(s.as_bytes());
let mut interner = Interner::default();
lexer
@ -120,7 +120,7 @@ fn check_invalid_identifier_part() {
let mut interner = Interner::default();
let sym = interner.get_or_intern_static("x");
for part in invalid_identifier_parts.iter() {
for part in &invalid_identifier_parts {
let s = String::from("x") + part;
let mut lexer = Lexer::new(s.as_bytes());
let mut interner = Interner::default();
@ -535,7 +535,7 @@ fn numbers_with_bad_separators() {
"0b_10", "0x_10", "10_", "1._10", "1e+_10", "1E_10", "10__00",
];
for n in numbers.iter() {
for n in &numbers {
let mut lexer = Lexer::new(n.as_bytes());
let mut interner = Interner::default();
assert!(lexer.next(&mut interner).is_err());
@ -860,7 +860,7 @@ fn illegal_following_numeric_literal() {
.next(&mut interner)
.expect_err("DecimalDigit following NumericLiteral not rejected as expected");
if let Error::Syntax(_, pos) = err {
assert_eq!(pos, Position::new(1, 5))
assert_eq!(pos, Position::new(1, 5));
} else {
panic!("invalid error type");
}
@ -1001,7 +1001,7 @@ fn string_legacy_octal_escape() {
(r#"'\101'"#, "A"),
];
for (s, expected) in test_cases.iter() {
for (s, expected) in &test_cases {
let mut lexer = Lexer::new(s.as_bytes());
let mut interner = Interner::default();
@ -1011,7 +1011,7 @@ fn string_legacy_octal_escape() {
expect_tokens(&mut lexer, &expected_tokens, &mut interner);
}
for (s, _) in test_cases.iter() {
for (s, _) in &test_cases {
let mut lexer = Lexer::new(s.as_bytes());
let mut interner = Interner::default();
lexer.set_strict_mode(true);
@ -1031,7 +1031,7 @@ fn string_legacy_octal_escape() {
fn string_zero_escape() {
let test_cases = [(r#"'\0'"#, "\u{0}"), (r#"'\0A'"#, "\u{0}A")];
for (s, expected) in test_cases.iter() {
for (s, expected) in &test_cases {
let mut lexer = Lexer::new(s.as_bytes());
let mut interner = Interner::default();
@ -1046,7 +1046,7 @@ fn string_zero_escape() {
fn string_non_octal_decimal_escape() {
let test_cases = [(r#"'\8'"#, "8"), (r#"'\9'"#, "9")];
for (s, expected) in test_cases.iter() {
for (s, expected) in &test_cases {
let mut lexer = Lexer::new(s.as_bytes());
let mut interner = Interner::default();
@ -1056,7 +1056,7 @@ fn string_non_octal_decimal_escape() {
expect_tokens(&mut lexer, &expected_tokens, &mut interner);
}
for (s, _) in test_cases.iter() {
for (s, _) in &test_cases {
let mut lexer = Lexer::new(s.as_bytes());
let mut interner = Interner::default();
lexer.set_strict_mode(true);

8
boa/src/syntax/parser/cursor/buffered_lexer/mod.rs

@ -74,7 +74,7 @@ where
#[inline]
pub(super) fn set_goal(&mut self, elm: InputElement) {
let _timer = BoaProfiler::global().start_event("cursor::set_goal()", "Parsing");
self.lexer.set_goal(elm)
self.lexer.set_goal(elm);
}
/// Lexes the next tokens as a regex assuming that the starting '/' has already been consumed.
@ -88,7 +88,7 @@ where
self.set_goal(InputElement::RegExp);
self.lexer
.lex_slash_token(start, interner)
.map_err(|e| e.into())
.map_err(Into::into)
}
/// Lexes the next tokens as template middle or template tail assuming that the starting
@ -110,7 +110,7 @@ where
#[inline]
pub(super) fn set_strict_mode(&mut self, strict_mode: bool) {
self.lexer.set_strict_mode(strict_mode)
self.lexer.set_strict_mode(strict_mode);
}
/// Fills the peeking buffer with the next token.
@ -162,7 +162,7 @@ where
/// Moves the cursor to the next token and returns the token.
///
/// If skip_line_terminators is true then line terminators will be discarded.
/// If `skip_line_terminators` is true then line terminators will be discarded.
///
/// This follows iterator semantics in that a `peek(0, false)` followed by a `next(false)` will
/// return the same value. Note that because a `peek(n, false)` may return a line terminator a

16
boa/src/syntax/parser/cursor/mod.rs

@ -41,7 +41,7 @@ where
#[inline]
pub(super) fn set_goal(&mut self, elm: InputElement) {
self.buffered_lexer.set_goal(elm)
self.buffered_lexer.set_goal(elm);
}
#[inline]
@ -83,7 +83,7 @@ where
#[inline]
pub(super) fn set_strict_mode(&mut self, strict_mode: bool) {
self.buffered_lexer.set_strict_mode(strict_mode)
self.buffered_lexer.set_strict_mode(strict_mode);
}
/// Returns an error if the next token is not of kind `kind`.
@ -124,11 +124,8 @@ where
) -> Result<SemicolonResult<'_>, ParseError> {
match self.buffered_lexer.peek(0, false, interner)? {
Some(tk) => match tk.kind() {
TokenKind::Punctuator(Punctuator::Semicolon)
| TokenKind::LineTerminator
| TokenKind::Punctuator(Punctuator::CloseBlock) => {
Ok(SemicolonResult::Found(Some(tk)))
}
TokenKind::Punctuator(Punctuator::Semicolon | Punctuator::CloseBlock)
| TokenKind::LineTerminator => Ok(SemicolonResult::Found(Some(tk))),
_ => Ok(SemicolonResult::NotFound(tk)),
},
None => Ok(SemicolonResult::Found(None)),
@ -149,7 +146,7 @@ where
match self.peek_semicolon(interner)? {
SemicolonResult::Found(Some(tk)) => match *tk.kind() {
TokenKind::Punctuator(Punctuator::Semicolon) | TokenKind::LineTerminator => {
let _ = self.buffered_lexer.next(false, interner)?;
let _next = self.buffered_lexer.next(false, interner)?;
Ok(())
}
_ => Ok(()),
@ -168,7 +165,8 @@ where
///
/// It expects that the token stream does not end here.
///
/// This is just syntatic sugar for a .peek(skip_n) call followed by a check that the result is not a line terminator or None.
/// This is just syntatic sugar for a `.peek(skip_n)` call followed by a check that the result
/// is not a line terminator or `None`.
#[inline]
pub(super) fn peek_expect_no_lineterminator(
&mut self,

4
boa/src/syntax/parser/error.rs

@ -19,8 +19,8 @@ impl<T> ErrorContext for Result<T, ParseError> {
}
impl From<LexError> for ParseError {
fn from(e: LexError) -> ParseError {
ParseError::lex(e)
fn from(e: LexError) -> Self {
Self::lex(e)
}
}

4
boa/src/syntax/parser/expression/assignment/arrow_function.rs

@ -141,7 +141,7 @@ where
{
let lexically_declared_names = body.lexically_declared_names(interner);
for param in params.parameters.as_ref() {
for param_name in param.names().into_iter() {
for param_name in param.names() {
if lexically_declared_names.contains(&param_name) {
return Err(ParseError::lex(LexError::Syntax(
format!(
@ -198,7 +198,7 @@ where
.kind()
{
TokenKind::Punctuator(Punctuator::OpenBlock) => {
let _ = cursor.next(interner)?;
let _next = cursor.next(interner)?;
let body = FunctionBody::new(false, false).parse(cursor, interner)?;
cursor.expect(Punctuator::CloseBlock, "arrow function", interner)?;
Ok(body)

11
boa/src/syntax/parser/expression/assignment/exponentiation.rs

@ -66,13 +66,10 @@ where
Ok(if let Some(tok) = cursor.peek(0, interner)? {
matches!(
tok.kind(),
TokenKind::Keyword(Keyword::Delete)
| TokenKind::Keyword(Keyword::Void)
| TokenKind::Keyword(Keyword::TypeOf)
| TokenKind::Punctuator(Punctuator::Add)
| TokenKind::Punctuator(Punctuator::Sub)
| TokenKind::Punctuator(Punctuator::Not)
| TokenKind::Punctuator(Punctuator::Neg)
TokenKind::Keyword(Keyword::Delete | Keyword::Void | Keyword::TypeOf)
| TokenKind::Punctuator(
Punctuator::Add | Punctuator::Sub | Punctuator::Not | Punctuator::Neg
)
)
} else {
false

4
boa/src/syntax/parser/expression/assignment/mod.rs

@ -96,9 +96,7 @@ where
.parse(cursor, interner)
}
// ArrowFunction[?In, ?Yield, ?Await] -> ArrowParameters[?Yield, ?Await] -> BindingIdentifier[?Yield, ?Await]
TokenKind::Identifier(_)
| TokenKind::Keyword(Keyword::Yield)
| TokenKind::Keyword(Keyword::Await) => {
TokenKind::Identifier(_) | TokenKind::Keyword(Keyword::Yield | Keyword::Await) => {
if let Ok(tok) =
cursor.peek_expect_no_lineterminator(1, "assignment expression", interner)
{

4
boa/src/syntax/parser/expression/assignment/yield.rs

@ -1,4 +1,4 @@
//! YieldExpression parsing.
//! `YieldExpression` parsing.
//!
//! More information:
//! - [MDN documentation][mdn]
@ -23,7 +23,7 @@ use std::io::Read;
use super::AssignmentExpression;
/// YieldExpression parsing.
/// `YieldExpression` parsing.
///
/// More information:
/// - [MDN documentation][mdn]

2
boa/src/syntax/parser/expression/left_hand_side/call.rs

@ -110,7 +110,7 @@ where
}
}
TokenKind::Punctuator(Punctuator::OpenBracket) => {
let _ = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?; // We move the parser.
let _next = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?; // We move the parser.
let idx = Expression::new(true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
cursor.expect(Punctuator::CloseBracket, "call expression", interner)?;

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

Loading…
Cancel
Save