Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
d05c1ed
added temporal intrinsic
sebastianjacmatt Sep 30, 2025
8e2bd76
Added Placeholders for InstantConstructor%Temporal.Instant% and Insta…
sebastianjacmatt Oct 8, 2025
4a2b459
added engine and heap backing to %temporal.instant%
sebastianjacmatt Oct 16, 2025
b371cec
added data.rs
sebastianjacmatt Oct 19, 2025
4323b26
fix errors after rebase
aapoalas Oct 19, 2025
a1839e6
cleanup
aapoalas Oct 19, 2025
453176e
create Temporal global property
aapoalas Oct 19, 2025
3012401
Temporal.Instant constructor
aapoalas Oct 19, 2025
f3ab3dc
add prototype methods
lockels Oct 19, 2025
82ca419
get it working
aapoalas Oct 19, 2025
8ba37bb
lint
aapoalas Oct 19, 2025
e1a417a
fromEpochMillisecondswith sus gc subscoping
sebastianjacmatt Oct 23, 2025
8f09370
corrected gc scoping
sebastianjacmatt Oct 23, 2025
dcc24d7
from_epoch_nanoseconds
sebastianjacmatt Oct 23, 2025
8115549
implementation of Temporal.Instant.compare
lockels Oct 25, 2025
8b7700b
bit of cleanup
lockels Oct 25, 2025
5596f32
get_epoch_milliseconds and get_epoch_nanoseconds
lockels Oct 29, 2025
100790e
add BigInt::from_i128, and add skeleton methods for Seb
lockels Oct 29, 2025
2611dd2
add better structure to the code. introduce new modules instant_proto…
lockels Oct 29, 2025
6561cef
add skeleton for the rest of Temporal.Instant implementation
lockels Oct 29, 2025
e638530
implementation of 8.3.14 Temporal.Instant.prototype.valueOf
lockels Oct 29, 2025
2d6f399
cargo fmt and cargo clippy
lockels Oct 29, 2025
93f00be
ignore unused parameters
lockels Oct 29, 2025
973e271
implementation of 8.3.10 Temporal.Instant.prototype.equals
lockels Oct 29, 2025
cad0f5d
immediatly scope instant after require internal slot in Instant.proto…
lockels Oct 29, 2025
dd306af
added instant.proto.add/subtract along with %duration% stubs
sebastianjacmatt Nov 5, 2025
0206ab5
properly impl to_temporal_duration along with some since&untill stuff
sebastianjacmatt Nov 9, 2025
eeebd85
remove to_big_int and instead cast to i128 in to_temporal_partial_dur…
sebastianjacmatt Nov 11, 2025
b37b1fe
cargo fmt
sebastianjacmatt Nov 11, 2025
350834a
some work on instant.prototype.round
lockels Nov 12, 2025
bdafc7c
use PropertyKey instead of String<'static> as key
lockels Nov 12, 2025
f140094
bring up test262 test passing results, bug fixing, refactoring, groun…
lockels Nov 17, 2025
00c7dae
fix oversights in previous commit
lockels Nov 17, 2025
fd03c63
difference_temporal_instant and uncompleted get_difference_settings
sebastianjacmatt Nov 17, 2025
7db97c4
awful awful code so far, WIP
lockels Nov 19, 2025
93ed842
Instant.prototype.round tests now passing
lockels Nov 19, 2025
764ea2e
add comment
lockels Nov 19, 2025
364373e
added proper duration backing
sebastianjacmatt Nov 20, 2025
8998d1a
instant.proto.to_string
sebastianjacmatt Nov 20, 2025
dbf3cdd
small check fixes
sebastianjacmatt Nov 20, 2025
62899a3
fix: finish Temporal.Instant.prototype.toString impl
aapoalas Nov 27, 2025
9054c0c
fix errors from rebase
aapoalas Nov 27, 2025
3e38634
plain_time constructor and prototype structs and stubs
sebastianjacmatt Nov 27, 2025
c74f2d1
to_local_string, to_json
sebastianjacmatt Dec 2, 2025
a888e94
cargo fmt
sebastianjacmatt Dec 2, 2025
a2472ed
_ in front of unused
sebastianjacmatt Dec 2, 2025
ffc6180
duration constructor, missing ao create_temporal_duration
sebastianjacmatt Dec 5, 2025
6f06887
changed duration constructor to gc scope instead of gc bind
sebastianjacmatt Dec 9, 2025
9ca1b7b
create_temporal_duration and require_internal_slot_temporal_duration
sebastianjacmatt Dec 9, 2025
654a34e
fixes: small changes to imports, instant->duration in duration and pr…
sebastianjacmatt Dec 9, 2025
24a6f4d
remove references to plaintime object. since it is outside of the sco…
lockels Dec 5, 2025
9a29cbf
change property capapcity of temporal 4->3
lockels Dec 5, 2025
a63ac30
Rebase with main and fix imports
jesperkha Feb 8, 2026
7baacdb
Fix comments in PR or make todos for stuff we dont understand
jesperkha Feb 9, 2026
2d8a4c4
Fix odos
jesperkha Feb 10, 2026
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 @@ -52,6 +52,7 @@ unicode-normalization = "0.1.24"
usdt = { git = "https://github.com/aapoalas/usdt.git", branch = "nova-aarch64-branch" }
wtf8 = "0.1"
xsum = "0.1.6"
temporal_rs = "0.1.0"

[workspace.metadata.dylint]
libraries = [{ path = "nova_lint" }]
Expand Down
13 changes: 12 additions & 1 deletion nova_vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ unicode-normalization = { workspace = true }
usdt = { workspace = true }
wtf8 = { workspace = true }
xsum = { workspace = true }
temporal_rs = { workspace = true, optional = true }

[features]
default = [
Expand All @@ -53,9 +54,15 @@ default = [
"regexp",
"set",
"annex-b",
"temporal",
]
array-buffer = ["ecmascript_atomics"]
atomics = ["array-buffer", "shared-array-buffer", "ecmascript_atomics", "ecmascript_futex"]
atomics = [
"array-buffer",
"shared-array-buffer",
"ecmascript_atomics",
"ecmascript_futex",
]
date = []
json = ["dep:sonic-rs"]
math = []
Expand All @@ -64,6 +71,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 +92,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 @@ -93,6 +102,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
37 changes: 35 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 Down Expand Up @@ -343,9 +362,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 +403,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 +431,7 @@ String Iterator
#[cfg(feature = "array-buffer")]subarray
#[cfg(feature = "annex-b-string")]substr
substring
#[cfg(feature = "temporal")]subtract
sumPrecise
#[cfg(feature = "annex-b-string")]sup
symbol
Expand All @@ -426,12 +451,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 +483,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 +508,7 @@ undefined
unregister
unscopables
unshift
#[cfg(feature = "temporal")]until
URIError
#[cfg(feature = "date")]UTC
value
Expand All @@ -488,7 +519,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
31 changes: 31 additions & 0 deletions nova_vm/src/ecmascript/abstract_operations/type_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,37 @@ 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.
#[cfg(feature = "array-buffer")]
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
4 changes: 4 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 @@ mod set;
#[cfg(feature = "shared-array-buffer")]
mod shared_array_buffer;
mod structured_data;
#[cfg(feature = "temporal")]
mod temporal;
mod text_processing;
#[cfg(feature = "array-buffer")]
mod typed_array;
Expand Down Expand Up @@ -112,6 +114,8 @@ pub use set::*;
#[cfg(feature = "shared-array-buffer")]
pub use shared_array_buffer::*;
pub(crate) use structured_data::*;
#[cfg(feature = "temporal")]
pub use temporal::*;
pub use text_processing::*;
#[cfg(feature = "array-buffer")]
pub use typed_array::*;
Expand Down
10 changes: 10 additions & 0 deletions nova_vm/src/ecmascript/builtins/ordinary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use std::{
use crate::ecmascript::SharedDataViewRecord;
#[cfg(feature = "array-buffer")]
use crate::ecmascript::try_get_result_into_value;
#[cfg(feature = "temporal")]
use crate::ecmascript::{DurationHeapData, InstantRecord};
use crate::{
ecmascript::{
Agent, ArgumentsList, BUILTIN_STRING_MEMORY, ExceptionType, Function, InternalMethods,
Expand Down Expand Up @@ -1651,6 +1653,10 @@ pub(crate) fn ordinary_object_create_with_intrinsics<'a>(
.heap
.create(ErrorHeapData::new(ExceptionType::SyntaxError, None, None))
.into(),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalInstant => agent.heap.create(InstantRecord::default()).into(),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalDuration => agent.heap.create(DurationHeapData::default()).into(),
ProtoIntrinsics::TypeError => agent
.heap
.create(ErrorHeapData::new(ExceptionType::TypeError, None, None))
Expand Down Expand Up @@ -2084,6 +2090,10 @@ fn get_intrinsic_constructor<'a>(
ProtoIntrinsics::WeakRef => Some(intrinsics.weak_ref().into()),
#[cfg(feature = "weak-refs")]
ProtoIntrinsics::WeakSet => Some(intrinsics.weak_set().into()),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalInstant => Some(intrinsics.temporal_instant().into()),
#[cfg(feature = "temporal")]
ProtoIntrinsics::TemporalDuration => Some(intrinsics.temporal_duration().into()),
}
}

Expand Down
Loading