2021-09-08 21:34:27 -04:00
/*
2024-06-08 11:22:05 -04:00
* Copyright ( c ) 2021 - 2024 , Tim Flynn < trflynn89 @ serenityos . org >
2021-09-08 21:34:27 -04:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-07-18 08:56:56 -04:00
# include <AK/Checked.h>
2023-08-30 12:30:39 -04:00
# include <AK/StringBuilder.h>
2021-11-13 23:59:12 -05:00
# include <AK/Utf8View.h>
2022-01-30 13:00:09 -05:00
# include <LibCrypto/BigInt/SignedBigInteger.h>
2022-07-16 12:46:14 -04:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-11-13 11:33:55 -05:00
# include <LibJS/Runtime/Array.h>
2022-01-30 13:00:09 -05:00
# include <LibJS/Runtime/BigInt.h>
2021-09-11 11:09:18 -04:00
# include <LibJS/Runtime/GlobalObject.h>
2021-09-08 21:34:27 -04:00
# include <LibJS/Runtime/Intl/NumberFormat.h>
2021-11-10 12:34:14 -05:00
# include <LibJS/Runtime/Intl/NumberFormatFunction.h>
2022-07-08 12:05:09 -04:00
# include <LibJS/Runtime/Intl/PluralRules.h>
2023-10-06 17:54:21 +02:00
# include <LibJS/Runtime/ValueInlines.h>
2024-06-08 11:22:05 -04:00
# include <LibLocale/DisplayNames.h>
2021-09-11 11:09:18 -04:00
# include <LibUnicode/CurrencyCode.h>
2021-11-10 12:34:14 -05:00
# include <math.h>
# include <stdlib.h>
2021-09-08 21:34:27 -04:00
namespace JS : : Intl {
2023-11-19 09:45:05 +01:00
JS_DEFINE_ALLOCATOR ( NumberFormatBase ) ;
JS_DEFINE_ALLOCATOR ( NumberFormat ) ;
2022-01-28 12:52:32 -05:00
NumberFormatBase : : NumberFormatBase ( Object & prototype )
2022-12-14 12:17:58 +01:00
: Object ( ConstructWithPrototypeTag : : Tag , prototype )
2022-01-28 12:52:32 -05:00
{
}
2021-09-08 21:34:27 -04:00
// 15 NumberFormat Objects, https://tc39.es/ecma402/#numberformat-objects
NumberFormat : : NumberFormat ( Object & prototype )
2022-01-28 12:52:32 -05:00
: NumberFormatBase ( prototype )
2021-09-08 21:34:27 -04:00
{
}
2021-11-10 12:34:14 -05:00
void NumberFormat : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
if ( m_bound_format )
visitor . visit ( m_bound_format ) ;
}
2023-08-11 07:50:34 -04:00
StringView NumberFormatBase : : computed_rounding_priority_string ( ) const
{
switch ( m_computed_rounding_priority ) {
case ComputedRoundingPriority : : Auto :
return " auto " sv ;
case ComputedRoundingPriority : : MorePrecision :
return " morePrecision " sv ;
case ComputedRoundingPriority : : LessPrecision :
return " lessPrecision " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-30 12:30:39 -04:00
Value NumberFormat : : use_grouping_to_value ( VM & vm ) const
2022-07-12 13:18:23 -04:00
{
switch ( m_use_grouping ) {
2024-06-09 14:36:48 -04:00
case : : Locale : : Grouping : : Always :
case : : Locale : : Grouping : : Auto :
case : : Locale : : Grouping : : Min2 :
return PrimitiveString : : create ( vm , : : Locale : : grouping_to_string ( m_use_grouping ) ) ;
case : : Locale : : Grouping : : False :
2022-07-12 13:18:23 -04:00
return Value ( false ) ;
default :
VERIFY_NOT_REACHED ( ) ;
}
}
void NumberFormat : : set_use_grouping ( StringOrBoolean const & use_grouping )
{
use_grouping . visit (
[ this ] ( StringView grouping ) {
2024-06-09 14:36:48 -04:00
m_use_grouping = : : Locale : : grouping_from_string ( grouping ) ;
2022-07-12 13:18:23 -04:00
} ,
[ this ] ( bool grouping ) {
VERIFY ( ! grouping ) ;
2024-06-09 14:36:48 -04:00
m_use_grouping = : : Locale : : Grouping : : False ;
2022-07-12 13:18:23 -04:00
} ) ;
}
2024-06-09 14:36:48 -04:00
: : Locale : : RoundingOptions NumberFormatBase : : rounding_options ( ) const
2021-09-08 21:34:27 -04:00
{
2024-06-09 14:36:48 -04:00
return {
. type = m_rounding_type ,
. mode = m_rounding_mode ,
. trailing_zero_display = m_trailing_zero_display ,
. min_significant_digits = m_min_significant_digits ,
. max_significant_digits = m_max_significant_digits ,
. min_fraction_digits = m_min_fraction_digits ,
. max_fraction_digits = m_max_fraction_digits ,
. min_integer_digits = m_min_integer_digits ,
. rounding_increment = m_rounding_increment
} ;
2021-09-08 21:34:27 -04:00
}
2024-06-09 14:36:48 -04:00
: : Locale : : DisplayOptions NumberFormat : : display_options ( ) const
2021-09-08 21:34:27 -04:00
{
2024-06-09 14:36:48 -04:00
return {
. style = m_style ,
. sign_display = m_sign_display ,
. notation = m_notation ,
. compact_display = m_compact_display ,
. grouping = m_use_grouping ,
. currency = m_currency ,
. currency_display = m_currency_display ,
. currency_sign = m_currency_sign ,
. unit = m_unit ,
. unit_display = m_unit_display ,
} ;
2021-09-08 21:34:27 -04:00
}
2022-03-15 10:58:47 -04:00
// 15.5.1 CurrencyDigits ( currency ), https://tc39.es/ecma402/#sec-currencydigits
2021-09-11 11:09:18 -04:00
int currency_digits ( StringView currency )
{
// 1. If the ISO 4217 currency and funds code list contains currency as an alphabetic code, return the minor
// unit value corresponding to the currency from the list; otherwise, return 2.
if ( auto currency_code = Unicode : : get_currency_code ( currency ) ; currency_code . has_value ( ) )
return currency_code - > minor_unit . value_or ( 2 ) ;
return 2 ;
}
2022-03-15 10:58:47 -04:00
// 15.5.3 FormatNumericToString ( intlObject, x ), https://tc39.es/ecma402/#sec-formatnumberstring
2024-06-09 14:36:48 -04:00
String format_numeric_to_string ( NumberFormatBase const & intl_object , MathematicalValue const & number )
2021-11-10 12:34:14 -05:00
{
2024-06-09 14:36:48 -04:00
return intl_object . formatter ( ) . format_to_decimal ( number . to_value ( ) ) ;
2021-11-10 12:34:14 -05:00
}
2022-03-15 10:58:47 -04:00
// 15.5.4 PartitionNumberPattern ( numberFormat, x ), https://tc39.es/ecma402/#sec-partitionnumberpattern
2024-06-09 14:36:48 -04:00
Vector < : : Locale : : NumberFormat : : Partition > partition_number_pattern ( NumberFormat const & number_format , MathematicalValue const & number )
2021-11-10 12:34:14 -05:00
{
2024-06-09 14:36:48 -04:00
return number_format . formatter ( ) . format_to_parts ( number . to_value ( ) ) ;
2021-11-10 12:34:14 -05:00
}
2022-03-15 10:58:47 -04:00
// 15.5.6 FormatNumeric ( numberFormat, x ), https://tc39.es/ecma402/#sec-formatnumber
2024-06-09 14:36:48 -04:00
String format_numeric ( NumberFormat const & number_format , MathematicalValue const & number )
2021-11-10 12:34:14 -05:00
{
// 1. Let parts be ? PartitionNumberPattern(numberFormat, x).
// 2. Let result be the empty String.
// 3. For each Record { [[Type]], [[Value]] } part in parts, do
2024-06-09 14:36:48 -04:00
// a. Set result to the string-concatenation of result and part.[[Value]].
2021-11-10 12:34:14 -05:00
// 4. Return result.
2024-06-09 14:36:48 -04:00
return number_format . formatter ( ) . format ( number . to_value ( ) ) ;
2021-11-10 12:34:14 -05:00
}
2022-03-15 10:58:47 -04:00
// 15.5.7 FormatNumericToParts ( numberFormat, x ), https://tc39.es/ecma402/#sec-formatnumbertoparts
2024-06-09 14:36:48 -04:00
NonnullGCPtr < Array > format_numeric_to_parts ( VM & vm , NumberFormat const & number_format , MathematicalValue const & number )
2021-11-13 11:33:55 -05:00
{
2022-08-20 08:25:24 +01:00
auto & realm = * vm . current_realm ( ) ;
2021-11-13 11:33:55 -05:00
// 1. Let parts be ? PartitionNumberPattern(numberFormat, x).
2024-06-09 14:36:48 -04:00
auto parts = partition_number_pattern ( number_format , number ) ;
2021-11-13 11:33:55 -05:00
2022-03-28 08:30:48 -04:00
// 2. Let result be ! ArrayCreate(0).
2022-12-13 20:49:49 +00:00
auto result = MUST ( Array : : create ( realm , 0 ) ) ;
2021-11-13 11:33:55 -05:00
// 3. Let n be 0.
size_t n = 0 ;
// 4. For each Record { [[Type]], [[Value]] } part in parts, do
for ( auto & part : parts ) {
2022-05-02 20:54:39 +02:00
// a. Let O be OrdinaryObjectCreate(%Object.prototype%).
2022-12-13 20:49:50 +00:00
auto object = Object : : create ( realm , realm . intrinsics ( ) . object_prototype ( ) ) ;
2021-11-13 11:33:55 -05:00
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
2023-08-08 18:25:57 +02:00
MUST ( object - > create_data_property_or_throw ( vm . names . type , PrimitiveString : : create ( vm , part . type ) ) ) ;
2021-11-13 11:33:55 -05:00
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
2022-12-06 22:17:27 +00:00
MUST ( object - > create_data_property_or_throw ( vm . names . value , PrimitiveString : : create ( vm , move ( part . value ) ) ) ) ;
2021-11-13 11:33:55 -05:00
// d. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O).
MUST ( result - > create_data_property_or_throw ( n , object ) ) ;
// e. Increment n by 1.
+ + n ;
}
// 5. Return result.
2023-08-30 12:30:39 -04:00
return result ;
2021-11-13 11:33:55 -05:00
}
2023-04-11 08:45:51 -04:00
// 15.5.16 ToIntlMathematicalValue ( value ), https://tc39.es/ecma402/#sec-tointlmathematicalvalue
2022-08-20 08:25:24 +01:00
ThrowCompletionOr < MathematicalValue > to_intl_mathematical_value ( VM & vm , Value value )
2022-07-19 12:11:34 -04:00
{
// 1. Let primValue be ? ToPrimitive(value, number).
2022-08-21 14:00:56 +01:00
auto primitive_value = TRY ( value . to_primitive ( vm , Value : : PreferredType : : Number ) ) ;
2022-07-19 12:11:34 -04:00
// 2. If Type(primValue) is BigInt, return the mathematical value of primValue.
if ( primitive_value . is_bigint ( ) )
return primitive_value . as_bigint ( ) . big_integer ( ) ;
// FIXME: The remaining steps are being refactored into a new Runtime Semantic, StringIntlMV.
// We short-circuit some of these steps to avoid known pitfalls.
// See: https://github.com/tc39/proposal-intl-numberformat-v3/pull/82
if ( ! primitive_value . is_string ( ) ) {
2022-08-21 14:00:56 +01:00
auto number = TRY ( primitive_value . to_number ( vm ) ) ;
2022-07-19 12:11:34 -04:00
return number . as_double ( ) ;
}
// 3. If Type(primValue) is String,
// a. Let str be primValue.
2023-08-08 19:17:55 +02:00
auto string = primitive_value . as_string ( ) . utf8_string ( ) ;
2022-07-19 12:11:34 -04:00
// Step 4 handled separately by the FIXME above.
// 5. If the grammar cannot interpret str as an expansion of StringNumericLiteral, return not-a-number.
// 6. Let mv be the MV, a mathematical value, of ? ToNumber(str), as described in 7.1.4.1.1.
2022-08-21 14:00:56 +01:00
auto mathematical_value = TRY ( primitive_value . to_number ( vm ) ) . as_double ( ) ;
2022-07-19 12:11:34 -04:00
// 7. If mv is 0 and the first non white space code point in str is -, return negative-zero.
2023-01-22 11:55:26 -05:00
if ( mathematical_value = = 0.0 & & string . bytes_as_string_view ( ) . trim_whitespace ( TrimMode : : Left ) . starts_with ( ' - ' ) )
2022-07-19 12:11:34 -04:00
return MathematicalValue : : Symbol : : NegativeZero ;
// 8. If mv is 10^10000 and str contains Infinity, return positive-infinity.
if ( mathematical_value = = pow ( 10 , 10000 ) & & string . contains ( " Infinity " sv ) )
return MathematicalValue : : Symbol : : PositiveInfinity ;
// 9. If mv is -10^10000 and str contains Infinity, return negative-infinity.
if ( mathematical_value = = pow ( - 10 , 10000 ) & & string . contains ( " Infinity " sv ) )
return MathematicalValue : : Symbol : : NegativeInfinity ;
// 10. Return mv.
return mathematical_value ;
}
2023-04-11 08:45:51 -04:00
// 15.5.19 PartitionNumberRangePattern ( numberFormat, x, y ), https://tc39.es/ecma402/#sec-partitionnumberrangepattern
2022-08-20 08:25:24 +01:00
ThrowCompletionOr < Vector < PatternPartitionWithSource > > partition_number_range_pattern ( VM & vm , NumberFormat & number_format , MathematicalValue start , MathematicalValue end )
2022-07-20 15:08:01 -04:00
{
// 1. If x is NaN or y is NaN, throw a RangeError exception.
if ( start . is_nan ( ) )
2023-06-25 10:11:37 -04:00
return vm . throw_completion < RangeError > ( ErrorType : : NumberIsNaN , " start " sv ) ;
2022-07-20 15:08:01 -04:00
if ( end . is_nan ( ) )
2023-06-25 10:11:37 -04:00
return vm . throw_completion < RangeError > ( ErrorType : : NumberIsNaN , " end " sv ) ;
2022-07-20 15:08:01 -04:00
2022-07-26 06:55:25 -04:00
// 2. Let result be a new empty List.
2022-07-20 15:08:01 -04:00
Vector < PatternPartitionWithSource > result ;
2022-07-26 06:55:25 -04:00
// 3. Let xResult be ? PartitionNumberPattern(numberFormat, x).
2024-06-09 14:36:48 -04:00
auto raw_start_result = partition_number_pattern ( number_format , start ) ;
2023-08-30 11:08:15 -04:00
auto start_result = PatternPartitionWithSource : : create_from_parent_list ( move ( raw_start_result ) ) ;
2022-07-20 15:08:01 -04:00
2022-07-26 06:55:25 -04:00
// 4. Let yResult be ? PartitionNumberPattern(numberFormat, y).
2024-06-09 14:36:48 -04:00
auto raw_end_result = partition_number_pattern ( number_format , end ) ;
2023-08-30 11:08:15 -04:00
auto end_result = PatternPartitionWithSource : : create_from_parent_list ( move ( raw_end_result ) ) ;
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 5. If ! FormatNumeric(numberFormat, x) is equal to ! FormatNumeric(numberFormat, y), then
2024-06-09 14:36:48 -04:00
auto formatted_start = format_numeric ( number_format , start ) ;
auto formatted_end = format_numeric ( number_format , end ) ;
2023-04-11 08:45:51 -04:00
if ( formatted_start = = formatted_end ) {
2023-01-12 08:03:13 -05:00
// a. Let appxResult be ? FormatApproximately(numberFormat, xResult).
2023-08-30 12:30:39 -04:00
auto approximate_result = format_approximately ( number_format , move ( start_result ) ) ;
2023-01-12 08:03:13 -05:00
// b. For each r in appxResult, do
for ( auto & result : approximate_result ) {
// i. Set r.[[Source]] to "shared".
result . source = " shared " sv ;
}
// c. Return appxResult.
return approximate_result ;
}
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 6. For each element r in xResult, do
2023-08-30 12:30:39 -04:00
result . ensure_capacity ( start_result . size ( ) ) ;
2023-04-11 08:45:51 -04:00
for ( auto & start_part : start_result ) {
// a. Append a new Record { [[Type]]: r.[[Type]], [[Value]]: r.[[Value]], [[Source]]: "startRange" } as the last element of result.
PatternPartitionWithSource part ;
part . type = start_part . type ;
part . value = move ( start_part . value ) ;
2022-07-20 15:08:01 -04:00
part . source = " startRange " sv ;
2023-04-11 08:45:51 -04:00
result . unchecked_append ( move ( part ) ) ;
}
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 7. Let rangeSeparator be an ILND String value used to separate two numbers.
2023-08-22 15:39:18 -04:00
auto range_separator_symbol = : : Locale : : get_number_system_symbol ( number_format . data_locale ( ) , number_format . numbering_system ( ) , : : Locale : : NumericSymbol : : RangeSeparator ) . value_or ( " - " sv ) ;
2023-08-22 16:12:51 -04:00
auto range_separator = : : Locale : : augment_range_pattern ( range_separator_symbol , result . last ( ) . value , end_result [ 0 ] . value ) ;
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 8. Append a new Record { [[Type]]: "literal", [[Value]]: rangeSeparator, [[Source]]: "shared" } element to result.
2022-07-20 15:08:01 -04:00
PatternPartitionWithSource part ;
part . type = " literal " sv ;
2023-01-22 11:55:26 -05:00
part . value = range_separator . has_value ( )
? range_separator . release_value ( )
2023-08-30 12:30:39 -04:00
: MUST ( String : : from_utf8 ( range_separator_symbol ) ) ;
2022-07-20 15:08:01 -04:00
part . source = " shared " sv ;
2023-08-30 12:30:39 -04:00
result . append ( move ( part ) ) ;
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 9. For each element r in yResult, do
2023-08-30 12:30:39 -04:00
result . ensure_capacity ( result . size ( ) + end_result . size ( ) ) ;
2023-04-11 08:45:51 -04:00
for ( auto & end_part : end_result ) {
// a. Append a new Record { [[Type]]: r.[[Type]], [[Value]]: r.[[Value]], [[Source]]: "endRange" } as the last element of result.
PatternPartitionWithSource part ;
part . type = end_part . type ;
part . value = move ( end_part . value ) ;
2022-07-20 15:08:01 -04:00
part . source = " endRange " sv ;
2023-04-11 08:45:51 -04:00
result . unchecked_append ( move ( part ) ) ;
}
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 10. Return ! CollapseNumberRange(result).
2022-07-20 15:08:01 -04:00
return collapse_number_range ( move ( result ) ) ;
}
2023-04-11 08:45:51 -04:00
// 15.5.20 FormatApproximately ( numberFormat, result ), https://tc39.es/ecma402/#sec-formatapproximately
2023-08-30 12:30:39 -04:00
Vector < PatternPartitionWithSource > format_approximately ( NumberFormat & number_format , Vector < PatternPartitionWithSource > result )
2022-07-20 15:08:01 -04:00
{
2023-04-11 08:45:51 -04:00
// 1. Let approximatelySign be an ILND String value used to signify that a number is approximate.
2023-08-22 15:39:18 -04:00
auto approximately_sign = : : Locale : : get_number_system_symbol ( number_format . data_locale ( ) , number_format . numbering_system ( ) , : : Locale : : NumericSymbol : : ApproximatelySign ) ;
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 2. If approximatelySign is not empty, insert a new Record { [[Type]]: "approximatelySign", [[Value]]: approximatelySign } at an ILND index in result. For example, if numberFormat has [[Locale]] "en-US" and [[NumberingSystem]] "latn" and [[Style]] "decimal", the new Record might be inserted before the first element of result.
2023-01-30 09:56:54 -05:00
if ( approximately_sign . has_value ( ) & & ! approximately_sign - > is_empty ( ) ) {
PatternPartitionWithSource partition ;
partition . type = " approximatelySign " sv ;
2023-08-30 12:30:39 -04:00
partition . value = MUST ( String : : from_utf8 ( * approximately_sign ) ) ;
2022-07-20 15:08:01 -04:00
2023-08-30 12:30:39 -04:00
result . insert_before_matching ( move ( partition ) , [ ] ( auto const & part ) {
2023-01-30 09:56:54 -05:00
return part . type . is_one_of ( " integer " sv , " decimal " sv , " plusSign " sv , " minusSign " sv , " percentSign " sv , " currency " sv ) ;
2023-08-30 12:30:39 -04:00
} ) ;
2023-01-30 09:56:54 -05:00
}
2022-07-20 15:08:01 -04:00
2023-04-11 08:45:51 -04:00
// 3. Return result.
2022-07-20 15:08:01 -04:00
return result ;
}
2023-04-11 08:45:51 -04:00
// 15.5.21 CollapseNumberRange ( result ), https://tc39.es/ecma402/#sec-collapsenumberrange
2022-07-20 15:08:01 -04:00
Vector < PatternPartitionWithSource > collapse_number_range ( Vector < PatternPartitionWithSource > result )
{
// Returning result unmodified is guaranteed to be a correct implementation of CollapseNumberRange.
return result ;
}
2023-04-11 08:45:51 -04:00
// 15.5.22 FormatNumericRange ( numberFormat, x, y ), https://tc39.es/ecma402/#sec-formatnumericrange
2023-01-22 11:55:26 -05:00
ThrowCompletionOr < String > format_numeric_range ( VM & vm , NumberFormat & number_format , MathematicalValue start , MathematicalValue end )
2022-07-20 15:08:01 -04:00
{
// 1. Let parts be ? PartitionNumberRangePattern(numberFormat, x, y).
2022-08-20 08:25:24 +01:00
auto parts = TRY ( partition_number_range_pattern ( vm , number_format , move ( start ) , move ( end ) ) ) ;
2022-07-20 15:08:01 -04:00
// 2. Let result be the empty String.
2023-08-30 12:30:39 -04:00
StringBuilder result ;
2022-07-20 15:08:01 -04:00
// 3. For each part in parts, do
for ( auto & part : parts ) {
// a. Set result to the string-concatenation of result and part.[[Value]].
2023-08-30 12:30:39 -04:00
result . append ( part . value ) ;
2022-07-20 15:08:01 -04:00
}
// 4. Return result.
2023-08-30 12:30:39 -04:00
return MUST ( result . to_string ( ) ) ;
2022-07-20 15:08:01 -04:00
}
2023-04-11 08:45:51 -04:00
// 15.5.23 FormatNumericRangeToParts ( numberFormat, x, y ), https://tc39.es/ecma402/#sec-formatnumericrangetoparts
2023-08-30 12:30:39 -04:00
ThrowCompletionOr < NonnullGCPtr < Array > > format_numeric_range_to_parts ( VM & vm , NumberFormat & number_format , MathematicalValue start , MathematicalValue end )
2022-07-20 15:29:00 -04:00
{
2022-08-20 08:25:24 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-07-20 15:29:00 -04:00
// 1. Let parts be ? PartitionNumberRangePattern(numberFormat, x, y).
2022-08-20 08:25:24 +01:00
auto parts = TRY ( partition_number_range_pattern ( vm , number_format , move ( start ) , move ( end ) ) ) ;
2022-07-20 15:29:00 -04:00
// 2. Let result be ! ArrayCreate(0).
2022-12-13 20:49:49 +00:00
auto result = MUST ( Array : : create ( realm , 0 ) ) ;
2022-07-20 15:29:00 -04:00
// 3. Let n be 0.
size_t n = 0 ;
// 4. For each Record { [[Type]], [[Value]] } part in parts, do
for ( auto & part : parts ) {
// a. Let O be OrdinaryObjectCreate(%Object.prototype%).
2022-12-13 20:49:50 +00:00
auto object = Object : : create ( realm , realm . intrinsics ( ) . object_prototype ( ) ) ;
2022-07-20 15:29:00 -04:00
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
2023-08-08 18:25:57 +02:00
MUST ( object - > create_data_property_or_throw ( vm . names . type , PrimitiveString : : create ( vm , part . type ) ) ) ;
2022-07-20 15:29:00 -04:00
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
2022-12-06 22:17:27 +00:00
MUST ( object - > create_data_property_or_throw ( vm . names . value , PrimitiveString : : create ( vm , move ( part . value ) ) ) ) ;
2022-07-20 15:29:00 -04:00
// d. Perform ! CreateDataPropertyOrThrow(O, "source", part.[[Source]]).
2023-08-08 18:25:57 +02:00
MUST ( object - > create_data_property_or_throw ( vm . names . source , PrimitiveString : : create ( vm , part . source ) ) ) ;
2022-07-20 15:29:00 -04:00
// e. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O).
MUST ( result - > create_data_property_or_throw ( n , object ) ) ;
// f. Increment n by 1.
+ + n ;
}
// 5. Return result.
2023-08-30 12:30:39 -04:00
return result ;
2022-07-20 15:29:00 -04:00
}
2021-09-08 21:34:27 -04:00
}