-
Notifications
You must be signed in to change notification settings - Fork 77
feat(ecmascript): PlainTime.prototype.since + until #981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,13 +9,20 @@ mod plain_time_prototype; | |
| pub(crate) use data::*; | ||
| pub(crate) use plain_time_constructor::*; | ||
| pub(crate) use plain_time_prototype::*; | ||
| use sonic_rs::{Object, value::object::IterMut}; | ||
| use temporal_rs::{ | ||
| duration, | ||
| options::{Unit, UnitGroup}, | ||
| }; | ||
|
|
||
| use crate::{ | ||
| ecmascript::{ | ||
| Agent, ExceptionType, Function, InternalMethods, InternalSlots, JsResult, OrdinaryObject, | ||
| ProtoIntrinsics, Value, object_handle, ordinary_populate_from_constructor, | ||
| Agent, DurationRecord, ExceptionType, Function, InternalMethods, InternalSlots, JsResult, | ||
| Object, OrdinaryObject, ProtoIntrinsics, String, TemporalDuration, Value, | ||
| get_difference_settings, get_options_object, object_handle, | ||
| ordinary_populate_from_constructor, temporal_err_to_js_err, | ||
| }, | ||
| engine::{Bindable, GcScope, NoGcScope}, | ||
| engine::{Bindable, GcScope, NoGcScope, Scopable}, | ||
| heap::{ | ||
| ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, | ||
| HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, arena_vec_access, | ||
|
|
@@ -133,3 +140,162 @@ pub(crate) fn create_temporal_plain_time<'gc>( | |
| .unwrap(), | ||
| ) | ||
| } | ||
|
|
||
| /// ### [4.5.6 ToTemporalTime ( item [ , options ] )](https://tc39.es/proposal-temporal/#sec-temporal-totemporaltime) | ||
| /// | ||
| /// The abstract operation ToTemporalTime takes argument item (an ECMAScript language value) and optional argument | ||
| /// options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainTime | ||
| /// or a throw Completion. Converts item to a new Temporal.PlainTime instance if possible, and throws otherwise. | ||
| pub(crate) fn to_temporal_time<'gc>( | ||
| agent: &mut Agent, | ||
| item: Value, | ||
| options: Option<Value>, | ||
| mut gc: GcScope<'gc, '_>, | ||
| ) -> JsResult<'gc, temporal_rs::PlainTime> { | ||
| let item = item.bind(gc.nogc()); | ||
|
|
||
| // 1. If options is not present, set options to undefined. | ||
| let options = options.unwrap_or(Value::Undefined); | ||
|
|
||
| // 2. If item is an Object, then | ||
| if let Ok(item) = Object::try_from(item) { | ||
| // a. If item has an [[InitializedTemporalTime]] internal slot, then | ||
| if let Ok(time) = TemporalPlainTime::try_from(item) { | ||
| // i. Let resolvedOptions be ? GetOptionsObject(options). | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: |
||
| let resolved_options = get_options_object(agent, options, gc.nogc()).unbind()?; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: Missing |
||
| // ii. Perform ? GetTemporalOverflowOption(resolvedOptions). | ||
| get_temporal_overflow_option(agent, resolved_options, gc.reborrow()).unbind()?; | ||
| // iii. Return ! CreateTemporalTime(item.[[Time]]). | ||
| return Ok(*time.inner_plain_time(agent)); | ||
| } | ||
|
|
||
| // b. If item has an [[InitializedTemporalDateTime]] internal slot, then | ||
| // i. Let resolvedOptions be ? GetOptionsObject(options). | ||
| // ii. Perform ? GetTemporalOverflowOption(resolvedOptions). | ||
| // iii. Return ! CreateTemporalTime(item.[[ISODateTime]].[[Time]]). | ||
|
|
||
| // c. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then | ||
| // i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]). | ||
| // ii. Let resolvedOptions be ? GetOptionsObject(options). | ||
| // iii. Perform ? GetTemporalOverflowOption(resolvedOptions). | ||
| // iv. Return ! CreateTemporalTime(isoDateTime.[[Time]]). | ||
|
|
||
| // d. Let result be ? ToTemporalTimeRecord(item). | ||
| let result = to_temporal_time_record(agent, item.unbind(), gc.reborrow()).unbind()?; | ||
| // e. Let resolvedOptions be ? GetOptionsObject(options). | ||
| let resolved_options = get_options_object(agent, options, gc.nogc()).unbind()?; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: Missing |
||
| // f. Let overflow be ? GetTemporalOverflowOption(resolvedOptions). | ||
| let overflow = | ||
| get_temporal_overflow_option(agent, resolved_options, gc.reborrow()).unbind()?; | ||
| // g. Set result to ? RegulateTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], overflow). | ||
| return result | ||
| .regulate(overflow) | ||
| .map_err(|err| temporal_err_to_js_err(agent, err, gc.into_nogc())); | ||
| } | ||
|
|
||
| // 3. Else, | ||
| // a. If item is not a String, throw a TypeError exception. | ||
| let Ok(item) = String::try_from(item) else { | ||
| return Err(agent.throw_exception_with_static_message( | ||
| ExceptionType::TypeError, | ||
| "Item is not a String", | ||
|
aapoalas marked this conversation as resolved.
|
||
| gc.into_nogc(), | ||
| )); | ||
| }; | ||
|
|
||
| // b. Let parseResult be ? ParseISODateTime(item, « TemporalTimeString »). | ||
| // c. Assert: parseResult.[[Time]] is not start-of-day. | ||
| // d. Set result to parseResult.[[Time]]. | ||
| // e. NOTE: A successful parse using TemporalTimeString guarantees absence of ambiguity with respect to any ISO 8601 date-only, year-month, or month-day representation. | ||
| let result = temporal_rs::PlainTime::from_utf8(item.as_bytes(agent)) | ||
| .map_err(|err| temporal_err_to_js_err(agent, err, gc.into_nogc()))?; | ||
| // f. Let resolvedOptions be ? GetOptionsObject(options). | ||
| let resolved_options = get_options_object(agent, options, gc.reborrow()).unbind()?; | ||
| // g. Perform ? GetTemporalOverflowOption(resolvedOptions). | ||
| get_temporal_overflow_option(agent, resolved_options, gc.reborrow()).unbind()?; | ||
|
|
||
| // 4. Return ! CreateTemporalTime(result). | ||
| Ok(result) | ||
| } | ||
|
|
||
| /// ### [4.5.17 DifferenceTemporalPlainTime ( operation, temporalTime, other, options )](https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalplaintime) | ||
| /// The abstract operation DifferenceTemporalPlainTime takes arguments | ||
| /// operation (either since or until), temporalTime (a Temporal.PlainTime), | ||
| /// other (an ECMAScript language value), and options | ||
| /// (an ECMAScript language value) and returns either | ||
| /// a normal completion containing a Temporal.Duration or a | ||
| /// throw completion. It computes the difference between the | ||
| /// two times represented by temporalTime and other, optionally | ||
| /// rounds it, and returns it as a Temporal.Duration object. | ||
| fn difference_temporal_plain_time<'gc, const IS_UNTIL: bool>( | ||
| agent: &mut Agent, | ||
| plain_time: TemporalPlainTime, | ||
| other: Value, | ||
| options: Value, | ||
| mut gc: GcScope<'gc, '_>, | ||
| ) -> JsResult<'gc, TemporalDuration<'gc>> { | ||
| let plain_time = plain_time.scope(agent, gc.nogc()); | ||
| let other = other.bind(gc.nogc()); | ||
| let options = options.scope(agent, gc.nogc()); | ||
| // 1. Set other to ? ToTemporalTime(other). | ||
| let other = to_temporal_time(agent, other.unbind(), options, gc.reborrow()); | ||
| // 2. Let resolvedOptions be ? GetOptionsObject(options). | ||
| let resolved_option = get_options_object(agent, options.get(agent), gc.nogc()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: You can |
||
| .unbind()? | ||
| .bind(gc.nogc()); | ||
| // 3. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, | ||
| // time, « », nanosecond, hour). | ||
| // 4. Let timeDuration be | ||
| // DifferenceTime(temporalTime.[[Time]], other.[[Time]]). | ||
| // 5. Set timeDuration to ! RoundTimeDuration(timeDuration, | ||
| // settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]). | ||
| // 6. Let duration be | ||
| // CombineDateAndTimeDuration(ZeroDateDuration(), timeDuration). | ||
| // 7. Let result be ! | ||
| // TemporalDurationFromInternal(duration, settings.[[LargestUnit]]). | ||
| // 8. If operation is since, set result to | ||
| // CreateNegatedTemporalDuration(result). | ||
| let duration = if IS_UNTIL { | ||
| const UNTIL: bool = true; | ||
| let settings = get_difference_settings::<UNTIL>( | ||
| agent, | ||
| resolved_option.unbind(), | ||
| UnitGroup::Time, | ||
| &[], | ||
| Unit::Nanosecond, | ||
| Unit::Hour, | ||
| gc.reborrow(), | ||
| ) | ||
| .unbind()?; | ||
| temporal_rs::PlainTime::until( | ||
| plain_time.get(agent).inner_plain_time(agent), | ||
| &other.unbind()?, | ||
| settings, | ||
| ) | ||
| } else { | ||
| const SINCE: bool = false; | ||
| let settings = get_difference_settings::<SINCE>( | ||
| agent, | ||
| resolved_option.unbind(), | ||
| UnitGroup::Time, | ||
| &[], | ||
| Unit::Nanosecond, | ||
| Unit::Hour, | ||
| gc.reborrow(), | ||
| ) | ||
| .unbind()?; | ||
| temporal_rs::PlainTime::since( | ||
| plain_time.get(agent).inner_plain_time(agent), | ||
| &other.unbind()?, | ||
| settings, | ||
| ) | ||
| }; | ||
| let gc = gc.into_nogc(); | ||
| let duration = duration.map_err(|err| temporal_err_to_js_err(agent, err, gc))?; | ||
|
|
||
| // 9. Return result. | ||
| Ok(agent.heap.create(DurationRecord { | ||
| object_index: None, | ||
| duration, | ||
| })) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Missing
bindcall here.