Commit graph

122 commits

Author SHA1 Message Date
Linus Groh
50428ea8d2 LibJS: Move intrinsics to the realm
Intrinsics, i.e. mostly constructor and prototype objects, but also
things like empty and new object shape now live on a new heap-allocated
JS::Intrinsics object, thus completing the long journey of taking all
the magic away from the global object.
This represents the Realm's [[Intrinsics]] slot in the spec and matches
its existing [[GlobalObject]] / [[GlobalEnv]] slots in terms of
architecture.

In the majority of cases it should now be possibly to fully allocate a
regular object without the global object existing, and in fact that's
what we do now - the realm is allocated before the global object, and
the intrinsics between both :^)
2022-08-27 11:29:10 +01:00
Linus Groh
b345a0acca LibJS+LibWeb: Reduce use of GlobalObject as an intermediary
- Prefer VM::current_realm() over GlobalObject::associated_realm()
- Prefer VM::heap() over GlobalObject::heap()
- Prefer Cell::vm() over Cell::global_object()
- Prefer Wrapper::vm() over Wrapper::global_object()
- Inline Realm::global_object() calls used to access intrinsics as they
  will later perform a direct lookup without going through the global
  object
2022-08-23 13:58:30 +01:00
Linus Groh
a022e548b8 LibJS: Replace GlobalObject with VM in Value AOs [Part 4/19]
This is where the fun begins. :^)
2022-08-23 13:58:30 +01:00
Linus Groh
f9705eb2f4 LibJS: Replace GlobalObject with VM in Intl AOs [Part 1/19]
Instead of passing a GlobalObject everywhere, we will simply pass a VM,
from which we can get everything we need: common names, the current
realm, symbols, arguments, the heap, and a few other things.

In some places we already don't actually need a global object and just
do it for consistency - no more `auto& vm = global_object.vm();`!

This will eventually automatically fix the "wrong realm" issue we have
in some places where we (incorrectly) use the global object from the
allocating object, e.g. in call() / construct() implementations. When
only ever a VM is passed around, this issue can't happen :^)

I've decided to split this change into a series of patches that should
keep each commit down do a somewhat manageable size.
2022-08-23 13:58:30 +01:00
Linus Groh
f3117d46dc LibJS: Remove GlobalObject from VM::throw_completion()
This is a continuation of the previous five commits.

A first big step into the direction of no longer having to pass a realm
(or currently, a global object) trough layers upon layers of AOs!
Unlike the create() APIs we can safely assume that this is only ever
called when a running execution context and therefore current realm
exists. If not, you can always manually allocate the Error and put it in
a Completion :^)

In the spec, throw exceptions implicitly use the current realm's
intrinsics as well: https://tc39.es/ecma262/#sec-throw-an-exception
2022-08-23 13:58:30 +01:00
Linus Groh
b99cc7d050 LibJS+LibWeb: Replace GlobalObject with Realm in create() functions
This is a continuation of the previous two commits.

As allocating a JS cell already primarily involves a realm instead of a
global object, and we'll need to pass one to the allocate() function
itself eventually (it's bridged via the global object right now), the
create() functions need to receive a realm as well.
The plan is for this to be the highest-level function that actually
receives a realm and passes it around, AOs on an even higher level will
use the "current realm" concept via VM::current_realm() as that's what
the spec assumes; passing around realms (or global objects, for that
matter) on higher AO levels is pointless and unlike for allocating
individual objects, which may happen outside of regular JS execution, we
don't need control over the specific realm that is being used there.
2022-08-23 13:58:30 +01:00
Timothy Flynn
fd7d97fba5 LibJS: Allow out-of-order number ranges to be formatted
This is a normative change to the Intl NumberFormat V3 spec:
https://github.com/tc39/proposal-intl-numberformat-v3/commit/0c3d849
2022-07-26 10:46:08 -07:00
Timothy Flynn
e9e187d15c LibJS: Implement Intl.NumberFormat.prototype.formatRangeToParts 2022-07-20 22:30:16 +01:00
Timothy Flynn
b4a772cde2 LibJS: Implement Intl.NumberFormat.prototype.formatRange 2022-07-20 22:30:16 +01:00
Timothy Flynn
292b8908b5 LibJS: Hook the Intl mathematical value into Intl.NumberFormat 2022-07-20 18:21:24 +01:00
Timothy Flynn
99b79766cd LibJS: Return an enum from ApplyUnsignedRoundingMode
After the Intl MV is implemented, returning a copy of the desired value
here may involve copying non-trivial data. Instead, return an enum to
indicate which decision was made.
2022-07-20 18:21:24 +01:00
Timothy Flynn
20533c2594 LibJS: Avoid FormatNumericToString spec issue more carefully
This becomes more of an issue when implementing the Intl mathematical
value, where negative zero is treated as a special enum value. In that
case, we already previously changed the value from -0 to +0 in step 1b.
Entering the branch for step 4 will then set it back to -0.

The math that follows after these steps worked fine with both +0/-0, but
assertions will be reached in the Intl MV implementation.
2022-07-20 18:21:24 +01:00
Timothy Flynn
4b415a23c1 LibJS: Implement Intl.NumberFormat V3's [[RoundingIncrement]] changes 2022-07-18 23:37:31 +01:00
Timothy Flynn
8ee485c350 LibJS: Implement Intl.NumberFormat V3's [[RoundingMode]] changes 2022-07-18 23:37:31 +01:00
Timothy Flynn
800a0ddc63 LibJS: Relax integer size requirements on some NumberFormat helpers
These were changed to i8 while investigating the issues fixed by commit
9e50f25. When [[RoundingIncrement]] is implemented, some of these will
be invoked with [[RoundingIncrement]]'s value, which can be up to 5000.
Change these to i32, and wrap them with AK::Checked for good measure.
Also change a couple helpers that are always comparing against zero to
not need an explicit check.
2022-07-18 23:37:31 +01:00
Timothy Flynn
cb5f7bf696 LibJS: Add missing VERIFY_NOT_REACHED in string-to-enum conversion
Noticed this while working on [[RoundingMode]].
2022-07-18 23:37:31 +01:00
Timothy Flynn
37ab7cc694 LibJS: Implement Intl.NumberFormat V3's [[TrailingZeroDisplay]] changes 2022-07-18 08:51:07 +01:00
Timothy Flynn
a712c7b5e1 LibJS: Replace comparisons of "0"_bigint with SignedBigInteger::is_zero
This just avoids creating UnsignedBigInteger's underlying vector.
2022-07-18 08:51:07 +01:00
Timothy Flynn
bb9a44cd50 LibJS: Implement Intl.NumberFormat V3's [[RoundingPriority]] changes 2022-07-18 08:51:07 +01:00
Timothy Flynn
9e50f25ac4 LibJS: Prevent i64 overflow when computing large NumberFormat exponents
The largest exponents we compute are on the order of 10^21 (governed by
the maximumSignificantDigits option, which has a max value of 21). That
is too large to fit into the i64 we were using when multiplying this
exponent by the value to be formatted.

Instead, split up the logic to multiply that value by this exponent
based on the value's underlying type:

Number: Do not cast the result of pow() to an i64, and perform the
follow-up multiplication with doubles.

BigInt: Do not use pow(). Instead, compute the exponent as a BigInt
from the start, then perform the follow-up multiplication with that
BigInt.
2022-07-18 08:51:07 +01:00
Timothy Flynn
cff2d631da LibJS: Implement Intl.NumberFormat V3's [[SignDisplay]] changes
Intl.NumberFormat V3 adds a "negative" option for [[SignDisplay]] to
only use the locale's signed pattern for negative numbers.
2022-07-13 19:22:26 +01:00
Timothy Flynn
733192089f LibJS: Implement Intl.NumberFormat V3's [[UseGrouping]] changes
In the main spec, [[UseGrouping]] can be true or false. In V3, it may be
one of:

    auto: Respect the per-locale preference for grouping.

    always: Ignore per-locale preference for grouping and always insert
    the grouping separator (note: true is now an alias for always).

    min2: Ignore per-locale preference for grouping and only insert the
    grouping separator if the primary group has at least 2 digits.

    false: Ignore per-locale preference for grouping and never insert
    the grouping separator.
2022-07-13 19:22:26 +01:00
Timothy Flynn
33698b9615 LibJS+js: Parse new constructor options from Intl.NumberFormat V3
This contains minimal changes to parse newly added and modified options
from the Intl.NumberFormat V3 proposal, while maintaining main spec
behavior in Intl.NumberFormat.prototype.format. The parsed options are
reflected only in Intl.NumberFormat.prototype.resolvedOptions and the js
REPL.
2022-07-13 19:22:26 +01:00
Timothy Flynn
5b68c1a06c LibJS: Use Intl.PluralRules within Intl.NumberFormat
This also allows removing a bit of a BigInt hack to resolve plurality of
BigInt numbers (because the AOs used in ResolvePlural support BigInt,
wherease the naive Unicode::select_pattern_with_plurality did not).

We use cardinal form here; the number format patterns in the CLDR align
with the cardinal form of the plural rules.
2022-07-08 20:33:52 +02:00
Timothy Flynn
2982aa0373 LibJS: Mark the NumberFormat parameter of FormatNumericToString as const
Not critical, but in subsequent commits this will be invoked from a
constant context.
2022-07-08 11:51:54 +02:00
Linus Groh
9f3f3b0864 LibJS: Remove implicit wrapping/unwrapping of completion records
This is an editorial change in the ECMA-262 spec, with similar changes
in some proposals.

See:
- https://github.com/tc39/ecma262/commit/7575f74
- https://github.com/tc39/proposal-array-grouping/commit/df899eb
- https://github.com/tc39/proposal-shadowrealm/commit/9eb5a12
- https://github.com/tc39/proposal-shadowrealm/commit/c81f527
2022-05-03 01:09:29 +02:00
Timothy Flynn
4fd463dae0 LibJS: Normalize mathematical references to negative zero
This is an editorial change in the Intl spec. See:
https://github.com/tc39/ecma402/commit/d4be24e
2022-03-30 14:24:32 +01:00
Timothy Flynn
1a76839e8d LibJS: Use consistent ASCII case-transformation and string language
Also update the incorrect spec link for IsWellFormedCurrencyCode.

These are editorial changes in the Intl spec. See:
https://github.com/tc39/ecma402/commit/6939b44
https://github.com/tc39/ecma402/commit/3a775eb
https://github.com/tc39/ecma402/commit/97a7940
https://github.com/tc39/ecma402/commit/129c790
https://github.com/tc39/ecma402/commit/42ec908
https://github.com/tc39/ecma402/commit/ea25c36
2022-03-30 14:24:32 +01:00
Timothy Flynn
7c41e6058a LibJS: Explicitly indicate infallible incovations
These are editorial changes in the Intl spec.

See:
https://github.com/tc39/ecma402/commit/6804096
https://github.com/tc39/ecma402/commit/6361167
https://github.com/tc39/ecma402/commit/8718171
https://github.com/tc39/ecma402/commit/fd37cb4
https://github.com/tc39/ecma402/commit/00fcfb0
https://github.com/tc39/ecma402/commit/913f832
2022-03-30 14:24:32 +01:00
Timothy Flynn
812d3a7ef8 LibJS: Reorganize spec steps for Intl.NumberFormat
This is an editorial change in the Intl spec:
https://github.com/tc39/ecma402/commit/110cb1f
2022-03-15 17:30:58 +01:00
Timothy Flynn
6efbafa6e0 Everywhere: Update copyrights with my new serenityos.org e-mail :^) 2022-01-31 18:23:22 +00:00
Timothy Flynn
d6e926e5b1 LibJS: Support BigInt number formatting with Intl.NumberFormat 2022-01-30 20:05:27 +00:00
Timothy Flynn
a0253af8c1 LibJS: Generalize Intl.NumberFormat to operate on Value types
Intl.NumberFormat is meant to format both Number and BigInt types. To
prepare for formatting BigInt types, this generalizes our NumberFormat
implementation to operate on Value instances rather than doubles. All
arithmetic is moved to static helpers that can now be updated with
BigInt semantics.
2022-01-30 20:05:27 +00:00
Timothy Flynn
ac3e42a8de LibJS: Move some Intl.NumberFormat fields into a NumberFormatBase class
Other Intl objects, such as PluralRules, are to be treated as a
NumberFormat object in some AOs. There's only a handful of fields which
are to be shared between those objects - move them to a base class for
shared reuse.

This also updates the couple of NumberFormat AOs that are meant to
operate on these NumberFormat-like objects.

Alternatively, we could just have objects like PluralRules inherit from
NumberFormat directly. But that messes up the is<NumberFormat> runtime
checks, so this feels safer.
2022-01-28 19:38:47 +00:00
Timothy Flynn
cf92bc42a2 LibJS: Respect per-locale minimum grouping digits when number formatting 2022-01-27 20:30:52 +00:00
Timothy Flynn
0865f71d37 LibJS: Convert Intl.NumberFormat to use Unicode::Style 2022-01-25 19:02:59 +00:00
Timothy Flynn
8126cb2545 LibJS+LibUnicode: Remove unnecessary locale currency mapping wrapper
Before LibUnicode generated methods were weakly linked, we had a public
method (get_locale_currency_mapping) for retrieving currency mappings.
That method invoked one of several style-specific methods that only
existed in the generated UnicodeLocale.

One caveat of weakly linked functions is that every such function must
have a public declaration. The result is that each of those styled
methods are declared publicly, which makes the wrapper redundant
because it is just as easy to invoke the method for the desired style.
2022-01-13 13:43:57 +01:00
Timothy Flynn
cc5e9f0579 LibJS+LibUnicode: Move replacement of number system digits to LibUnicode
There are a few algorithms in TR-35 that need to replace digits before
returning any results to callers. For example, when formatting time zone
offsets, a string like "GMT+12:34" must have its digits replaced with
the default numbering system for the desired locale.
2022-01-11 23:56:35 +01:00
mjz19910
10ec98dd38 Everywhere: Fix spelling mistakes 2022-01-07 15:44:42 +01:00
Timothy Flynn
f16f3c4677 LibJS: Update ToRawPrecision / ToRawFixed AO spec comments
This is a normative change in the Intl spec:
https://github.com/tc39/ecma402/commit/f0f66cf

There are two main changes here:
1. Converting BigInt/Number objects to mathematical values.
2. A change in how ToRawPrecision computes its exponent and significant
   digits.

For (1), we do not yet support BigInt number formatting, thus already
have coerced Number objects to a double. When BigInt is supported, the
number passed into these methods will likely still be a Value, thus can
be coereced then.

For (2), our implementation already returns the expected edge-case
results pointed out on the spec PR.
2022-01-02 20:07:03 +01:00
Timothy Flynn
a3149c11e5 LibJS: Explicitly handle postive/negative infinity in Intl.NumberFormat
This is a normative change in the Intl spec:
https://github.com/tc39/ecma402/commit/f0f66cf

Our implementation is unaffected by this change. LibUnicode pre-computes
positive, negative, and signless format patterns, so we already format
negative infinity correctly. Also, the CLDR does not contain specific
locale-dependent strings for negative infinity anyways.
2022-01-02 20:07:03 +01:00
Timothy Flynn
9ce4ff4265 LibJS: Avoid crashing when the Unicode data generators are disabled
The general idea when ENABLE_UNICODE_DATABASE_DOWNLOAD is OFF has been
that the Intl APIs will provide obviously incorrect results, but should
not crash. This regressed a bit with NumberFormat and DateTimeFormat.
2021-12-22 17:30:43 +01:00
Timothy Flynn
2a7f36b392 LibJS+LibUnicode: Generate unique numeric symbol lists
There are 443 number system objects generated, each of which held an
array of number system symbols. Of those 443 arrays, only 39 are unique.

To uniquely store these, this change moves the generated NumericSymbol
enumeration to the public LibUnicode/NumberFormat.h header with a pre-
defined set of symbols that we need. This is to ensure the generated,
unique arrays are created in a known order with known symbols. While it
is unfortunate to no longer discover these symbols at generation time,
it does allow us to ignore unwanted symbols and perform less string-to-
enumeration conversions at lookup time.
2021-12-11 14:17:47 +00:00
Timothy Flynn
d2588d852b LibJS: Change all [[RelevantExtensionKeys]] to return constexpr arrays
There's no need to allocate a vector for this internal slot. Similar to
commit: bb11437792
2021-12-01 16:36:26 +00:00
Timothy Flynn
914675e826 LibJS+LibUnicode: Separate number formatting methods from Locale.h
Currently, we generate separate data files for locale and number format
related tables/methods, but provide public accessors for all of the data
in one Locale.h file. Rather than continuing this trend for date-time,
relative time, etc. formatting, it's a bit easier to reason about if the
public accessors are also in separate files.
2021-11-29 22:48:46 +00:00
Timothy Flynn
251f692440 LibJS: Re-implement SetNumberFormatDigitOptions AO
This is an editorial change in the Intl spec.

See: https://github.com/tc39/ecma402/commit/d89c84f
2021-11-24 14:17:15 +00:00
Timothy Flynn
a1d5849e67 LibJS: Implement unit number formatting 2021-11-16 23:14:09 +00:00
Timothy Flynn
04b8b87c17 LibJS+LibUnicode: Support multiple identifiers within format pattern
This wasn't the case for compact patterns, but unit patterns can contain
multiple (up to 2, really) identifiers that must each be recognized by
LibJS.

Each generated NumberFormat object now stores an array of identifiers
parsed. The format pattern itself is encoded with the index into this
array for that identifier, e.g. the compact format string "0K" will
become "{number}{compactIdentifier:0}".
2021-11-16 23:14:09 +00:00
Timothy Flynn
3b68370212 LibJS+LibUnicode: Rename the generated compact_identifier to identifier
This field is currently used to store the StringView into the compact
name/symbol in the format string. Units will need to store a similar
field, so rename the field to be more generic, and extract the parser
for it.
2021-11-16 23:14:09 +00:00
Timothy Flynn
6d34a0b4e8 LibJS+LibUnicode: Rename method to select a NumberFormat plurality
Instead of currency pattern lookups within select_currency_unit_pattern,
rename the method to select_pattern_with_plurality and accept any list
of patterns. This method will be needed for units.
2021-11-16 23:14:09 +00:00