Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5477540
added temporal intrinsic
sebastianjacmatt Sep 30, 2025
a9a074e
Added Placeholders for InstantConstructor%Temporal.Instant% and Insta…
sebastianjacmatt Oct 8, 2025
7905959
added engine and heap backing to %temporal.instant%
sebastianjacmatt Oct 16, 2025
5003bb5
added data.rs
sebastianjacmatt Oct 19, 2025
1efcf9d
fix errors after rebase
aapoalas Oct 19, 2025
c485800
cleanup
aapoalas Oct 19, 2025
da9f21e
create Temporal global property
aapoalas Oct 19, 2025
02e8063
Temporal.Instant constructor
aapoalas Oct 19, 2025
74a3139
add prototype methods
lockels Oct 19, 2025
0f4472d
get it working
aapoalas Oct 19, 2025
a26ba27
lint
aapoalas Oct 19, 2025
3ea2a37
fromEpochMillisecondswith sus gc subscoping
sebastianjacmatt Oct 23, 2025
b3c232c
corrected gc scoping
sebastianjacmatt Oct 23, 2025
3205e8b
from_epoch_nanoseconds
sebastianjacmatt Oct 23, 2025
f120a69
implementation of Temporal.Instant.compare
lockels Oct 25, 2025
835df63
bit of cleanup
lockels Oct 25, 2025
a363df6
get_epoch_milliseconds and get_epoch_nanoseconds
lockels Oct 29, 2025
8f49946
add BigInt::from_i128, and add skeleton methods for Seb
lockels Oct 29, 2025
9574528
add better structure to the code. introduce new modules instant_proto…
lockels Oct 29, 2025
c14f71f
add skeleton for the rest of Temporal.Instant implementation
lockels Oct 29, 2025
6f0114b
implementation of 8.3.14 Temporal.Instant.prototype.valueOf
lockels Oct 29, 2025
5f0cd73
cargo fmt and cargo clippy
lockels Oct 29, 2025
82b9a74
ignore unused parameters
lockels Oct 29, 2025
09274b6
implementation of 8.3.10 Temporal.Instant.prototype.equals
lockels Oct 29, 2025
f18bdda
immediatly scope instant after require internal slot in Instant.proto…
lockels Oct 29, 2025
fa28d43
added instant.proto.add/subtract along with %duration% stubs
sebastianjacmatt Nov 5, 2025
bffe729
properly impl to_temporal_duration along with some since&untill stuff
sebastianjacmatt Nov 9, 2025
e8fb97e
remove to_big_int and instead cast to i128 in to_temporal_partial_dur…
sebastianjacmatt Nov 11, 2025
bddb79d
cargo fmt
sebastianjacmatt Nov 11, 2025
49db0c9
some work on instant.prototype.round
lockels Nov 12, 2025
9046465
use PropertyKey instead of String<'static> as key
lockels Nov 12, 2025
91c8886
bring up test262 test passing results, bug fixing, refactoring, groun…
lockels Nov 17, 2025
186855c
fix oversights in previous commit
lockels Nov 17, 2025
fed7aa8
difference_temporal_instant and uncompleted get_difference_settings
sebastianjacmatt Nov 17, 2025
01baa0b
awful awful code so far, WIP
lockels Nov 19, 2025
f9a5f11
Instant.prototype.round tests now passing
lockels Nov 19, 2025
9aa1db5
add comment
lockels Nov 19, 2025
1fc9a5f
added proper duration backing
sebastianjacmatt Nov 20, 2025
0abe18f
instant.proto.to_string
sebastianjacmatt Nov 20, 2025
6c9f50b
small check fixes
sebastianjacmatt Nov 20, 2025
61b8e1d
fix: finish Temporal.Instant.prototype.toString impl
aapoalas Nov 27, 2025
20d4473
fix errors from rebase
aapoalas Nov 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ sonic-rs = "0.3.17"
unicode-normalization = "0.1.24"
usdt = { git = "https://github.com/aapoalas/usdt.git", branch = "nova-aarch64-branch" }
wtf8 = "0.1"
temporal_rs = "0.1.0"

[workspace.metadata.dylint]
libraries = [{ path = "nova_lint" }]
Expand Down
6 changes: 6 additions & 0 deletions nova_vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ sonic-rs = { workspace = true, optional = true }
unicode-normalization = { workspace = true }
usdt = { workspace = true }
wtf8 = { workspace = true }
temporal_rs = { workspace = true, optional = true }

[features]
default = [
Expand All @@ -52,6 +53,7 @@ default = [
"regexp",
"set",
"annex-b",
"temporal",
]
array-buffer = ["ecmascript_atomics"]
atomics = ["array-buffer", "shared-array-buffer", "ecmascript_atomics", "ecmascript_futex"]
Expand All @@ -63,6 +65,7 @@ shared-array-buffer = ["array-buffer", "ecmascript_atomics"]
weak-refs = []
set = []
typescript = []
temporal = ["temporal_rs"]

# Enables features defined by [Annex B](https://tc39.es/ecma262/#sec-additional-ecmascript-features-for-web-browsers)
annex-b = ["annex-b-string", "annex-b-global", "annex-b-date", "annex-b-regexp"]
Expand All @@ -84,6 +87,7 @@ proposals = [
"proposal-math-clamp",
"proposal-is-error",
"proposal-atomics-microwait",
"proposal-temporal",
]
# Enables the [Float16Array proposal](https://tc39.es/proposal-float16array/)
proposal-float16array = ["array-buffer"]
Expand All @@ -95,6 +99,8 @@ proposal-math-clamp = ["math"]
proposal-is-error = []
# Enables the [Atomics.pause proposal](https://tc39.es/proposal-atomics-microwait/)
proposal-atomics-microwait = ["atomics"]
# Enable the [Temporal proposal](https://tc39.es/proposal-temporal/)
proposal-temporal = ["temporal"]

[build-dependencies]
small_string = { path = "../small_string", version = "0.2.0" }
Expand Down
38 changes: 36 additions & 2 deletions nova_vm/src/builtin_strings
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ __proto__
#[cfg(feature = "math")]abs
#[cfg(feature = "math")]acos
#[cfg(feature = "math")]acosh
#[cfg(any(feature = "atomics", feature = "set", feature = "weak-refs"))]add
#[cfg(any(feature = "atomics", feature = "set", feature = "weak-refs", feature = "temporal"))]add
AggregateError
all
allSettled
Expand Down Expand Up @@ -87,13 +87,15 @@ codePointAt
concat
configurable
construct
compare
constructor
copyWithin
#[cfg(feature = "math")]cos
#[cfg(feature = "math")]cosh
create
#[cfg(feature = "array-buffer")]DataView
#[cfg(feature = "date")]Date
#[cfg(feature = "temporal")]days
decodeURI
decodeURIComponent
default
Expand All @@ -106,13 +108,17 @@ description
#[cfg(feature = "array-buffer")]detached
done
#[cfg(feature = "regexp")]dotAll
#[cfg(feature="temporal")]Duration
#[cfg(feature = "math")]E
encodeURI
encodeURIComponent
endsWith
entries
enumerable
#[cfg(feature = "temporal")]epochMilliseconds
#[cfg(feature = "temporal")]epochNanoseconds
EPSILON
#[cfg(feature = "temporal")]equals
Error
errors
#[cfg(any(feature = "annex-b-string", feature = "regexp"))]escape
Expand All @@ -133,6 +139,7 @@ find
findIndex
findLast
findLastIndex
#[cfg(feature = "temporal")]fractionalSecondDigits
#[cfg(feature = "annex-b-string")]fixed
#[cfg(feature = "regexp")]flags
flat
Expand All @@ -147,6 +154,8 @@ for
forEach
freeze
from
#[cfg(feature = "temporal")]fromEpochNanoseconds
#[cfg(feature = "temporal")]fromEpochMilliseconds
fromCharCode
fromCodePoint
fromEntries
Expand Down Expand Up @@ -183,6 +192,8 @@ get size
#[cfg(feature = "array-buffer")]getBigUint64
#[cfg(feature = "date")]getDate
#[cfg(feature = "date")]getDay
#[cfg(feature = "temporal")]get epochMilliseconds
#[cfg(feature = "temporal")]get epochNanoseconds
#[cfg(feature = "proposal-float16array")]getFloat16
#[cfg(feature = "array-buffer")]getFloat32
#[cfg(feature = "array-buffer")]getFloat64
Expand Down Expand Up @@ -225,6 +236,7 @@ hasInstance
hasOwn
hasOwnProperty
#[cfg(feature = "math")]hypot
#[cfg(feature = "temporal")]hours
#[cfg(feature = "regexp")]ignoreCase
#[cfg(feature = "math")]imul
includes
Expand All @@ -250,6 +262,8 @@ isSealed
#[cfg(feature = "array-buffer")]isView
isWellFormed
#[cfg(feature = "annex-b-string")]italics
#[cfg(feature = "temporal")]Instant
#[cfg(feature = "temporal")]largestUnit
Iterator
iterator
join
Expand Down Expand Up @@ -281,13 +295,18 @@ MAX_SAFE_INTEGER
MAX_VALUE
#[cfg(feature = "array-buffer")]maxByteLength
message
#[cfg(feature = "temporal")]microseconds
#[cfg(feature = "temporal")]milliseconds
#[cfg(feature = "temporal")]minutes
#[cfg(feature = "temporal")]months
#[cfg(feature = "math")]min
MIN_SAFE_INTEGER
MIN_VALUE
Module
#[cfg(feature = "regexp")]multiline
name
NaN
#[cfg(feature = "temporal")]nanoseconds
NEGATIVE_INFINITY
next
normalize
Expand All @@ -310,6 +329,7 @@ parseFloat
parseInt
#[cfg(feature = "proposal-atomics-microwait")]pause
#[cfg(feature = "math")]PI
#[cfg(feature = "temporal")]PlainTime
pop
POSITIVE_INFINITY
#[cfg(feature = "math")]pow
Expand Down Expand Up @@ -343,9 +363,12 @@ resolve
return
reverse
revocable
#[cfg(feature = "math")]round
#[cfg(any(feature = "math", feature = "temporal"))]round
#[cfg(feature = "temporal")]roundingMode
#[cfg(feature = "temporal")]roundingIncrement
seal
#[cfg(feature = "regexp")]search
#[cfg(feature = "temporal")]seconds
set
#[cfg(feature = "set")]Set
set [Symbol.toStringTag]
Expand Down Expand Up @@ -381,10 +404,12 @@ setPrototypeOf
shift
#[cfg(feature = "math")]sign
#[cfg(feature = "math")]sin
#[cfg(feature = "temporal")]since
#[cfg(feature = "math")]sinh
size
slice
#[cfg(feature = "annex-b-string")]small
#[cfg(feature = "temporal")]smallestUnit
some
sort
#[cfg(feature = "regexp")]source
Expand All @@ -407,6 +432,7 @@ String Iterator
#[cfg(feature = "array-buffer")]subarray
#[cfg(feature = "annex-b-string")]substr
substring
#[cfg(feature = "temporal")]subtract
#[cfg(feature = "proposal-math-sum")]sumPrecise
#[cfg(feature = "annex-b-string")]sup
symbol
Expand All @@ -426,12 +452,16 @@ Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables
SyntaxError
#[cfg(feature = "temporal")]Temporal
#[cfg(feature = "temporal")]Temporal.Duration
#[cfg(feature = "temporal")]Temporal.Instant
#[cfg(feature = "math")]tan
#[cfg(feature = "math")]tanh
#[cfg(feature = "regexp")]test
then
throw
#[cfg(feature = "atomics")]timed-out
#[cfg(feature = "temporal")]timeZone
toArray
#[cfg(feature = "date")]toDateString
toExponential
Expand All @@ -454,6 +484,7 @@ toStringTag
#[cfg(feature = "date")]toTimeString
toUpperCase
#[cfg(feature = "date")]toUTCString
#[cfg(feature = "temporal")]toZonedDateTimeISO
toWellFormed
#[cfg(feature = "array-buffer")]transfer
#[cfg(feature = "array-buffer")]transferToFixedLength
Expand All @@ -478,6 +509,7 @@ undefined
unregister
unscopables
unshift
#[cfg(feature = "temporal")]until
URIError
#[cfg(feature = "date")]UTC
value
Expand All @@ -488,7 +520,9 @@ values
#[cfg(feature = "weak-refs")]WeakMap
#[cfg(feature = "weak-refs")]WeakRef
#[cfg(feature = "weak-refs")]WeakSet
#[cfg(feature = "temporal")]weeks
with
withResolvers
writable
#[cfg(feature = "atomics")]xor
#[cfg(feature = "temporal")]years
30 changes: 30 additions & 0 deletions nova_vm/src/ecmascript/abstract_operations/type_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,36 @@ pub(crate) fn try_to_index<'a>(
js_result_into_try(validate_index(agent, integer, gc))
}

/// [14.5.1.1 ToIntegerIfIntegral ( argument )](https://tc39.es/proposal-temporal/#sec-tointegerifintegral)
/// The abstract operation ToIntegerIfIntegral takes argument argument
/// (an ECMAScript language value) and returns either a normal completion containing
/// an integer or a throw completion.
/// It converts argument to an integer representing its Number value,
/// or throws a RangeError when that value is not integral.
pub(crate) fn to_integer_if_integral<'gc>(
agent: &mut Agent,
argument: Value,
mut gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Number<'gc>> {
let argument = argument.bind(gc.nogc());
// 1. Let number be ? ToNumber(argument).
let number = to_number(agent, argument.unbind(), gc.reborrow())
.unbind()?
.bind(gc.nogc());
// 2. If number is not an integral Number, throw a RangeError exception.
if !number.is_integer(agent) {
Err(agent.throw_exception_with_static_message(
ExceptionType::RangeError,
"Number must be integral",
gc.into_nogc(),
))
} else {
// 3. Return ℝ(number).
// Ok(number.into_i64(agent)) // TODO: more performant
Ok(number.unbind())
}
}

/// Helper function to check if a `char` is trimmable.
///
/// Copied from Boa JS engine. Source https://github.com/boa-dev/boa/blob/183e763c32710e4e3ea83ba762cf815b7a89cd1f/core/string/src/lib.rs#L51
Expand Down
2 changes: 2 additions & 0 deletions nova_vm/src/ecmascript/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ pub(crate) mod set;
#[cfg(feature = "shared-array-buffer")]
pub(crate) mod shared_array_buffer;
pub(crate) mod structured_data;
#[cfg(feature = "temporal")]
pub mod temporal;
pub(crate) mod text_processing;
#[cfg(feature = "array-buffer")]
pub(crate) mod typed_array;
Expand Down
26 changes: 26 additions & 0 deletions nova_vm/src/ecmascript/builtins/ordinary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ use caches::{CacheToPopulate, Caches, PropertyLookupCache, PropertyOffset};

#[cfg(feature = "shared-array-buffer")]
use crate::ecmascript::builtins::data_view::data::SharedDataViewRecord;
#[cfg(feature = "temporal")]
use crate::ecmascript::builtins::temporal::{
duration::data::DurationHeapData, instant::data::InstantRecord,
plain_time::data::PlainTimeHeapData,
};
#[cfg(feature = "array-buffer")]
use crate::ecmascript::types::try_get_result_into_value;
use crate::{
Expand Down Expand Up @@ -1685,6 +1690,19 @@ pub(crate) fn ordinary_object_create_with_intrinsics<'a>(
.heap
.create(ErrorHeapData::new(ExceptionType::SyntaxError, None, None))
.into_object(),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalInstant => {
agent.heap.create(InstantRecord::default()).into_object()
}
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalDuration => {
agent.heap.create(DurationHeapData::default()).into_object()
}
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalPlainTime => agent
.heap
.create(PlainTimeHeapData::default())
.into_object(),
ProtoIntrinsics::TypeError => agent
.heap
.create(ErrorHeapData::new(ExceptionType::TypeError, None, None))
Expand Down Expand Up @@ -2073,6 +2091,14 @@ fn get_intrinsic_constructor<'a>(
ProtoIntrinsics::WeakRef => Some(intrinsics.weak_ref().into_function()),
#[cfg(feature = "weak-refs")]
ProtoIntrinsics::WeakSet => Some(intrinsics.weak_set().into_function()),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalInstant => Some(intrinsics.temporal_instant().into_function()),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalDuration => Some(intrinsics.temporal_duration().into_function()),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalPlainTime => {
Some(intrinsics.temporal_plain_time().into_function())
}
}
}

Expand Down
Loading