diff --git a/boa_ast/src/temporal/mod.rs b/boa_ast/src/temporal/mod.rs index 2005fbb8696..aa4f63b5a57 100644 --- a/boa_ast/src/temporal/mod.rs +++ b/boa_ast/src/temporal/mod.rs @@ -9,10 +9,22 @@ pub struct IsoParseRecord { pub date: DateRecord, /// Parsed Time pub time: Option, - /// Parsed Offset - /// Parsed `TimeZoneAnnotation` + /// Parsed `TimeZone` data (UTCOffset | IANA name) pub tz: Option, - /// Parsed Annotations + /// The parsed calendar value. + pub calendar: Option, +} + +/// An ISO Date Node consisting of only date fields and any calendar value. +#[derive(Default, Debug)] +pub struct ISODate { + /// Date Year + pub year: i32, + /// Date Month + pub month: i32, + /// Date Day + pub day: i32, + /// The calendar value. pub calendar: Option, } @@ -69,7 +81,7 @@ pub struct TimeZone { /// TimeZoneIANAName pub name: Option, /// TimeZoneOffset - pub offset: Option, + pub offset: Option, } /// A valid `TimeZoneIdentifier` that is defined by @@ -78,14 +90,14 @@ pub struct TimeZone { #[derive(Debug, Clone)] pub enum TzIdentifier { /// A valid UTC `TimeZoneIdentifier` value - UtcOffset(UtcOffset), + UtcOffset(UTCOffset), /// A valid IANA name `TimeZoneIdentifier` value TzIANAName(String), } /// A full precision `UtcOffset` #[derive(Debug, Clone, Copy)] -pub struct UtcOffset { +pub struct UTCOffset { /// The `+`/`-` sign of this `UtcOffset` pub sign: i8, /// The hour value of the `UtcOffset` diff --git a/boa_cli/src/debug/mod.rs b/boa_cli/src/debug/mod.rs index b844fe4510c..f4991ea51a0 100644 --- a/boa_cli/src/debug/mod.rs +++ b/boa_cli/src/debug/mod.rs @@ -20,7 +20,7 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject { let realm_module = realm::create_object(context); let limits_module = limits::create_object(context); - ObjectInitializer::new(context.realm().clone()) + ObjectInitializer::new(context) .property( js_string!("function"), function_module, diff --git a/boa_engine/Cargo.toml b/boa_engine/Cargo.toml index 1bca8a30ba4..ff1e7c64432 100644 --- a/boa_engine/Cargo.toml +++ b/boa_engine/Cargo.toml @@ -37,8 +37,6 @@ intl = [ fuzz = ["boa_ast/arbitrary", "boa_interner/arbitrary"] -experimental = ["boa_parser/experimental", "dep:icu_calendar"] - # Enable Boa's VM instruction flowgraph generator. flowgraph = [] @@ -49,7 +47,7 @@ trace = [] annex-b = ["boa_parser/annex-b"] # Enable experimental features, like Stage 3 proposals. -experimental = [] +experimental = ["boa_parser/experimental", "dep:icu_calendar"] [dependencies] boa_interner.workspace = true diff --git a/boa_engine/src/builtins/intl/segmenter/mod.rs b/boa_engine/src/builtins/intl/segmenter/mod.rs index 1bb744d49c2..d8265fea694 100644 --- a/boa_engine/src/builtins/intl/segmenter/mod.rs +++ b/boa_engine/src/builtins/intl/segmenter/mod.rs @@ -249,7 +249,7 @@ impl Segmenter { // b. Let v be the value of segmenter's internal slot whose name is the Internal Slot value of the current row. // c. Assert: v is not undefined. // d. Perform ! CreateDataPropertyOrThrow(options, p, v). - let options = ObjectInitializer::new(context.realm().clone()) + let options = ObjectInitializer::new(context) .property( js_string!("locale"), js_string!(segmenter.locale.to_string()), @@ -314,7 +314,7 @@ fn create_segment_data_object( let segment = js_string!(&string[range]); // 5. Let result be OrdinaryObjectCreate(%Object.prototype%). - let object = &mut ObjectInitializer::new(context.realm().clone()); + let object = &mut ObjectInitializer::new(context); object // 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment). diff --git a/boa_engine/src/builtins/mod.rs b/boa_engine/src/builtins/mod.rs index 045993106ba..acb3308fcc1 100644 --- a/boa_engine/src/builtins/mod.rs +++ b/boa_engine/src/builtins/mod.rs @@ -39,9 +39,6 @@ pub mod escape; #[cfg(feature = "intl")] pub mod intl; -#[cfg(feature = "experimental")] -pub mod temporal; - // TODO: remove `cfg` when `Temporal` gets to stage 4. #[cfg(any(feature = "intl", feature = "experimental"))] pub(crate) mod options; diff --git a/boa_engine/src/builtins/temporal/calendar/iso.rs b/boa_engine/src/builtins/temporal/calendar/iso.rs index 0e74c5802e8..434335b41c6 100644 --- a/boa_engine/src/builtins/temporal/calendar/iso.rs +++ b/boa_engine/src/builtins/temporal/calendar/iso.rs @@ -2,25 +2,21 @@ use crate::{ builtins::temporal::{ - self, create_temporal_date, create_temporal_duration, - date_equations::{ - epoch_time_for_year, mathematical_days_in_year, mathematical_in_leap_year, - }, - options::{get_temporal_unit, ArithmeticOverflow, TemporalUnit}, + self, create_temporal_date, + date_equations::mathematical_days_in_year, + options::{ArithmeticOverflow, TemporalUnit}, plain_date::iso::IsoDateRecord, - to_temporal_date, }, js_string, property::PropertyKey, string::utf16, - Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, + Context, JsNativeError, JsResult, JsString, JsValue, }; use super::BuiltinCalendar; use icu_calendar::{ iso::Iso, - types::IsoWeekday, week::{RelativeUnit, WeekCalculator}, Calendar, Date, }; @@ -55,7 +51,7 @@ impl BuiltinCalendar for IsoCalendar { // 9. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], "iso8601"). Ok(create_temporal_date( IsoDateRecord::from_date_iso(date), - "iso8601".into(), + js_string!("iso8601").into(), None, context, )? @@ -88,7 +84,7 @@ impl BuiltinCalendar for IsoCalendar { // 10. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]], "iso8601", result.[[ReferenceISODay]]). temporal::create_temporal_year_month( IsoDateRecord::from_date_iso(result), - "iso8601".into(), + js_string!("iso8601").into(), None, context, ) @@ -120,7 +116,7 @@ impl BuiltinCalendar for IsoCalendar { // 10. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]], "iso8601", result.[[ReferenceISOYear]]). temporal::create_temporal_month_day( IsoDateRecord::from_date_iso(result), - JsValue::from("iso8601"), + js_string!("iso8601").into(), None, context, ) @@ -209,7 +205,7 @@ impl BuiltinCalendar for IsoCalendar { ) .map_err(|err| JsNativeError::range().with_message(err.to_string()))?; - Ok(date.month().code.to_string().into()) + Ok(JsString::from(date.month().code.to_string()).into()) } /// Returns the `day` for the `Iso` calendar. @@ -354,9 +350,9 @@ impl BuiltinCalendar for IsoCalendar { let key_string = key.to_string(); result.push(key); if key_string.as_str() == "month" { - result.push("monthCode".into()); + result.push(utf16!("monthCode").into()); } else if key_string.as_str() == "monthCode" { - result.push("month".into()); + result.push(utf16!("month").into()); } } result diff --git a/boa_engine/src/builtins/temporal/calendar/mod.rs b/boa_engine/src/builtins/temporal/calendar/mod.rs index d4858e59895..337823a51db 100644 --- a/boa_engine/src/builtins/temporal/calendar/mod.rs +++ b/boa_engine/src/builtins/temporal/calendar/mod.rs @@ -18,8 +18,8 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, ObjectData}, property::{Attribute, PropertyKey}, realm::Realm, - string::utf16, - Context, JsArgs, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + string::{common::StaticJsStrings, utf16}, + Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; use rustc_hash::FxHashMap; @@ -160,21 +160,24 @@ impl core::fmt::Debug for dyn BuiltinCalendar { // ==== Calendar Abstractions ==== +const ISO: &[u16] = utf16!("iso8601"); + // NOTE: potentially move these to `Realm`, so that there can be // host defined calendars. // Returns a map of all available calendars. -fn available_calendars() -> FxHashMap<&'static str, Box> { +fn available_calendars() -> FxHashMap<&'static [u16], Box> { let mut map = FxHashMap::default(); let iso: Box = Box::new(IsoCalendar); - map.insert("iso8601", iso); + map.insert(ISO, iso); map } // Returns if an identifier is a builtin calendar. -pub(crate) fn is_builtin_calendar(identifier: &str) -> bool { +pub(crate) fn is_builtin_calendar(identifier: &JsString) -> bool { let calendars = available_calendars(); - calendars.contains_key(identifier.to_ascii_lowercase().as_str()) + // TODO: Potentially implement `to_ascii_lowercase`. + calendars.contains_key(identifier.as_slice()) } /// The `Temporal.Calendar` object. @@ -184,15 +187,15 @@ pub struct Calendar { } impl BuiltInObject for Calendar { - const NAME: &'static str = "Temporal.Calendar"; + const NAME: JsString = StaticJsStrings::CALENDAR; } impl IntrinsicObject for Calendar { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_id = BuiltInBuilder::callable(realm, Self::get_id) - .name("get Id") + .name(js_string!("get Id")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -202,28 +205,38 @@ impl IntrinsicObject for Calendar { Attribute::CONFIGURABLE, ) .accessor(utf16!("id"), Some(get_id), None, Attribute::default()) - .method(Self::date_from_fields, "dateFromFields", 2) - .method(Self::year_month_from_fields, "yearMonthFromFields", 2) - .method(Self::month_day_from_fields, "monthDayFromFields", 2) - .method(Self::date_add, "dateAdd", 3) - .method(Self::date_until, "dateUntil", 3) - .method(Self::year, "year", 1) - .method(Self::month, "month", 1) - .method(Self::month_code, "monthCode", 1) - .method(Self::day, "day", 1) - .method(Self::day_of_week, "dayOfWeek", 1) - .method(Self::day_of_year, "dayOfYear", 1) - .method(Self::week_of_year, "weekOfYear", 1) - .method(Self::year_of_week, "yearOfWeek", 1) - .method(Self::days_in_week, "daysInWeek", 1) - .method(Self::days_in_month, "daysInMonth", 1) - .method(Self::days_in_year, "daysInYear", 1) - .method(Self::months_in_year, "monthsInYear", 1) - .method(Self::in_leap_year, "inLeapYear", 1) - .method(Self::fields, "fields", 1) - .method(Self::merge_fields, "mergeFields", 2) - .method(Self::get_id, "toString", 0) - .method(Self::get_id, "toJSON", 0) + .method(Self::date_from_fields, js_string!("dateFromFields"), 2) + .method( + Self::year_month_from_fields, + js_string!("yearMonthFromFields"), + 2, + ) + .method( + Self::month_day_from_fields, + js_string!("monthDayFromFields"), + 2, + ) + .method(Self::date_add, js_string!("dateAdd"), 3) + .method(Self::date_until, js_string!("dateUntil"), 3) + .method(Self::era, js_string!("era"), 1) + .method(Self::era_year, js_string!("eraYear"), 1) + .method(Self::year, js_string!("year"), 1) + .method(Self::month, js_string!("month"), 1) + .method(Self::month_code, js_string!("monthCode"), 1) + .method(Self::day, js_string!("day"), 1) + .method(Self::day_of_week, js_string!("dayOfWeek"), 1) + .method(Self::day_of_year, js_string!("dayOfYear"), 1) + .method(Self::week_of_year, js_string!("weekOfYear"), 1) + .method(Self::year_of_week, js_string!("yearOfWeek"), 1) + .method(Self::days_in_week, js_string!("daysInWeek"), 1) + .method(Self::days_in_month, js_string!("daysInMonth"), 1) + .method(Self::days_in_year, js_string!("daysInYear"), 1) + .method(Self::months_in_year, js_string!("monthsInYear"), 1) + .method(Self::in_leap_year, js_string!("inLeapYear"), 1) + .method(Self::fields, js_string!("fields"), 1) + .method(Self::merge_fields, js_string!("mergeFields"), 2) + .method(Self::get_id, js_string!("toString"), 0) + .method(Self::get_id, js_string!("toJSON"), 0) .build(); } @@ -263,7 +276,7 @@ impl BuiltInConstructor for Calendar { }; // 3. If IsBuiltinCalendar(id) is false, then - if !is_builtin_calendar(&id.to_std_string_escaped()) { + if !is_builtin_calendar(id) { // a. Throw a RangeError exception. return Err(JsNativeError::range() .with_message("Calendar ID must be a valid builtin calendar.") @@ -297,23 +310,18 @@ impl Calendar { ) -> JsResult { // 1. Let calendar be the this value. // 2. Perform ? RequireInternalSlot(calendar, [[InitializedTemporalCalendar]]). - let o = this.as_object().ok_or_else(|| { + let o = this.as_object().map(JsObject::borrow).ok_or_else(|| { JsNativeError::typ().with_message("this value of Calendar must be an object.") })?; - let o = o.borrow(); let calendar = o.as_calendar().ok_or_else(|| { JsNativeError::typ() .with_message("the this value of Calendar must be a Calendar object.") })?; - let identifier = calendar.identifier.to_std_string_escaped(); - - drop(o); - // Retrieve the current CalendarProtocol. let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(identifier.as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. If Type(fields) is not Object, throw a TypeError exception. @@ -334,7 +342,7 @@ impl Calendar { ]); // 6. If calendar.[[Identifier]] is "iso8601", then - let mut fields = if identifier.as_str() == "iso8601" { + let mut fields = if calendar.identifier.as_slice() == ISO { // a. Set fields to ? PrepareTemporalFields(fields, relevantFieldNames, « "year", "day" »). let mut required_fields = Vec::from(["year".to_owned(), "day".to_owned()]); temporal::TemporalFields::from_js_object( @@ -392,13 +400,10 @@ impl Calendar { .with_message("the this value of Calendar must be a Calendar object.") })?; - let identifier = calendar.identifier.to_std_string_escaped(); - drop(o); - let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(identifier.as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let fields = args.get_or_undefined(0); let fields_obj = fields.as_object().ok_or_else(|| { @@ -415,7 +420,7 @@ impl Calendar { ]); // 6. Set fields to ? PrepareTemporalFields(fields, « "month", "monthCode", "year" », « "year" »). - let mut fields = if identifier.as_str() == "iso8601" { + let mut fields = if calendar.identifier.as_slice() == ISO { // a. Set fields to ? PrepareTemporalFields(fields, relevantFieldNames, « "year" »). let mut required_fields = Vec::from(["year".to_owned()]); temporal::TemporalFields::from_js_object( @@ -471,14 +476,10 @@ impl Calendar { .with_message("the this value of Calendar must be a Calendar object.") })?; - let identifier = calendar.identifier.to_std_string_escaped(); - - drop(o); - let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(identifier.as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. If Type(fields) is not Object, throw a TypeError exception. @@ -499,7 +500,7 @@ impl Calendar { ]); // 6. If calendar.[[Identifier]] is "iso8601", then - let mut fields = if identifier.as_str() == "iso8601" { + let mut fields = if calendar.identifier.as_slice() == ISO { // a. Set fields to ? PrepareTemporalFields(fields, relevantFieldNames, « "day" »). let mut required_fields = Vec::from(["day".to_owned()]); temporal::TemporalFields::from_js_object( @@ -549,12 +550,10 @@ impl Calendar { .with_message("the this value of Calendar must be a Calendar object.") })?; - let identifier = calendar.identifier.to_std_string_escaped(); - let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(identifier.as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 4. Set date to ? ToTemporalDate(date). @@ -563,7 +562,7 @@ impl Calendar { // 5. Set duration to ? ToTemporalDuration(duration). let duration_like = args.get_or_undefined(1); - let mut duration = temporal::duration::to_temporal_duration(duration_like, context)?; + let mut duration = temporal::duration::to_temporal_duration(duration_like)?; // 6. Set options to ? GetOptionsObject(options). let options = args.get_or_undefined(2); @@ -575,11 +574,9 @@ impl Calendar { .unwrap_or(ArithmeticOverflow::Constrain); // 8. Let balanceResult be ? BalanceTimeDuration(duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]], "day"). - duration - .inner - .balance_time_duration(TemporalUnit::Day, None)?; + duration.balance_time_duration(TemporalUnit::Day, None)?; - this_calendar.date_add(&date, &duration.inner, overflow, context) + this_calendar.date_add(&date, &duration, overflow, context) } ///15.8.2.5 `Temporal.Calendar.prototype.dateUntil ( one, two [ , options ] )` - Supercedes 12.5.8 @@ -602,7 +599,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 4. Set one to ? ToTemporalDate(one). @@ -640,7 +637,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -686,7 +683,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -732,7 +729,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -778,7 +775,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -837,7 +834,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -889,7 +886,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -941,7 +938,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. Let temporalDate be ? ToTemporalDate(temporalDateLike). @@ -968,7 +965,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. Let temporalDate be ? ToTemporalDate(temporalDateLike). @@ -994,7 +991,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. Let temporalDate be ? ToTemporalDate(temporalDateLike). @@ -1020,7 +1017,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. Let temporalDate be ? ToTemporalDate(temporalDateLike). @@ -1046,7 +1043,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. Let temporalDate be ? ToTemporalDate(temporalDateLike). @@ -1072,7 +1069,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -1122,7 +1119,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -1172,7 +1169,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -1222,7 +1219,7 @@ impl Calendar { let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(calendar.identifier.to_std_string_escaped().as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let date_like = args.get_or_undefined(0); @@ -1267,13 +1264,10 @@ impl Calendar { .with_message("the this value of Calendar must be a Calendar object.") })?; - let identifier = calendar.identifier.to_std_string_escaped(); - drop(o); - let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(identifier.as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); // 3. Let iteratorRecord be ? GetIterator(fields, sync). @@ -1327,7 +1321,7 @@ impl Calendar { // 7. Let result be fieldNames. // 8. If calendar.[[Identifier]] is not "iso8601", then - if identifier.as_str() != "iso8601" { + if calendar.identifier.as_slice() != ISO { // a. NOTE: Every built-in calendar preserves all input field names in output. // b. Let extraFieldDescriptors be CalendarFieldDescriptors(calendar.[[Identifier]], fieldNames). let extended_fields = this_calendar.field_descriptors(&fields_names); @@ -1339,10 +1333,13 @@ impl Calendar { } // 9. Return CreateArrayFromList(result). - Ok( - Array::create_array_from_list(fields_names.iter().map(|s| s.clone().into()), context) - .into(), + Ok(Array::create_array_from_list( + fields_names + .iter() + .map(|s| JsString::from(s.clone()).into()), + context, ) + .into()) } /// 15.8.2.22 `Temporal.Calendar.prototype.mergeFields ( fields, additionalFields )` @@ -1361,13 +1358,10 @@ impl Calendar { .with_message("the this value of Calendar must be a Calendar object.") })?; - let identifier = calendar.identifier.to_std_string_escaped(); - drop(o); - let available_calendars = available_calendars(); let this_calendar = available_calendars - .get(identifier.as_str()) + .get(calendar.identifier.as_slice()) .expect("builtin must exist"); let fields = args.get_or_undefined(0).to_object(context)?; @@ -1449,7 +1443,7 @@ pub(crate) fn create_temporal_calendar( context: &mut Context<'_>, ) -> JsResult { // 1. Assert: IsBuiltinCalendar(identifier) is true. - assert!(is_builtin_calendar(&identifier.to_std_string_escaped())); + assert!(is_builtin_calendar(identifier)); let calendar = Calendar { identifier: identifier.clone(), @@ -1477,6 +1471,7 @@ pub(crate) fn create_temporal_calendar( } /// 12.2.21 `GetTemporalCalendarSlotValueWithISODefault ( item )` +#[allow(unused)] pub(crate) fn get_temporal_calendar_slot_value_with_default( item: &JsObject, context: &mut Context<'_>, @@ -1522,12 +1517,13 @@ pub(crate) fn get_temporal_calendar_slot_value_with_default( } // 2. Let calendarLike be ? Get(item, "calendar"). - let calendar_like = item.get("calendar", context)?; + let calendar_like = item.get(utf16!("calendar"), context)?; // 3. Return ? ToTemporalCalendarSlotValue(calendarLike, "iso8601"). - to_temporal_calendar_slot_value(&calendar_like, Some(JsString::from("iso8601"))) + to_temporal_calendar_slot_value(&calendar_like, Some(ISO.into())) } +#[allow(unused)] fn to_temporal_calendar_slot_value( calendar_like: &JsValue, default: Option, @@ -1536,7 +1532,7 @@ fn to_temporal_calendar_slot_value( if calendar_like.is_undefined() { if let Some(default) = default { // a. Assert: IsBuiltinCalendar(default) is true. - if is_builtin_calendar(&default.to_std_string_escaped()) { + if is_builtin_calendar(&default) { // b. Return default. return Ok(default.into()); } @@ -1596,7 +1592,7 @@ fn to_temporal_calendar_slot_value( // 4. Let identifier be ? ParseTemporalCalendarString(temporalCalendarLike). // 5. If IsBuiltinCalendar(identifier) is false, throw a RangeError exception. // 6. Return the ASCII-lowercase of identifier. - Ok("iso8601".into()) + Ok(js_string!(ISO).into()) } // ---------------------------- AbstractCalendar Methods ---------------------------- @@ -1635,6 +1631,7 @@ fn call_method_on_abstract_calendar( /// 12.2.2 `CalendarFields ( calendar, fieldNames )` /// /// Returns either a normal completion containing a List of Strings, or a throw completion. +#[allow(unused)] pub(crate) fn calendar_fields( calendar: &JsValue, field_names: Vec, @@ -1662,6 +1659,7 @@ pub(crate) fn calendar_fields( /// 12.2.3 `CalendarMergeFields ( calendar, fields, additionalFields )` /// /// Returns either a normal completion containing an Object, or a throw completion. +#[allow(unused)] pub(crate) fn calendar_merge_fields( calendar: &JsValue, fields: &TemporalFields, @@ -1692,6 +1690,7 @@ pub(crate) fn calendar_merge_fields( /// 12.2.4 `CalendarDateAdd ( calendar, date, duration [ , options [ , dateAdd ] ] )` /// /// Returns either a normal completion containing a `Temporal.PlainDate`, or an abrupt completion. +#[allow(unused)] pub(crate) fn calendar_date_add( calendar: &JsValue, date: &JsObject, @@ -1727,6 +1726,7 @@ pub(crate) fn calendar_date_add( /// 12.2.5 `CalendarDateUntil ( calendar, one, two, options [ , dateUntil ] )` /// /// Returns either a normal completion containing a `Temporal.Duration`, or an abrupt completion. +#[allow(unused)] pub(crate) fn calendar_date_until( calendar: &JsValue, one: &JsObject, @@ -1767,6 +1767,7 @@ pub(crate) fn calendar_date_until( /// 12.2.6 `CalendarYear ( calendar, dateLike )` /// /// Returns either a normal completion containing an integer, or an abrupt completion. +#[allow(unused)] pub(crate) fn calendar_year( calendar: &JsValue, datelike: &JsValue, @@ -1802,6 +1803,7 @@ pub(crate) fn calendar_year( } /// 12.2.7 `CalendarMonth ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_month( calendar: &JsValue, datelike: &JsValue, @@ -1844,6 +1846,7 @@ pub(crate) fn calendar_month( } /// 12.2.8 `CalendarMonthCode ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_month_code( calendar: &JsValue, datelike: &JsValue, @@ -1871,6 +1874,7 @@ pub(crate) fn calendar_month_code( } /// 12.2.9 `CalendarDay ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_day( calendar: &JsValue, datelike: &JsValue, @@ -1913,6 +1917,7 @@ pub(crate) fn calendar_day( } /// 12.2.10 `CalendarDayOfWeek ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_day_of_week( calendar: &JsValue, datelike: &JsValue, @@ -1955,6 +1960,7 @@ pub(crate) fn calendar_day_of_week( } /// 12.2.11 `CalendarDayOfYear ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_day_of_year( calendar: &JsValue, datelike: &JsValue, @@ -1997,6 +2003,7 @@ pub(crate) fn calendar_day_of_year( } /// 12.2.12 `CalendarWeekOfYear ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_week_of_year( calendar: &JsValue, datelike: &JsValue, @@ -2039,6 +2046,7 @@ pub(crate) fn calendar_week_of_year( } /// 12.2.13 `CalendarYearOfWeek ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_year_of_week( calendar: &JsValue, datelike: &JsValue, @@ -2074,6 +2082,7 @@ pub(crate) fn calendar_year_of_week( } /// 12.2.14 `CalendarDaysInWeek ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_days_in_week( calendar: &JsValue, datelike: &JsValue, @@ -2116,6 +2125,7 @@ pub(crate) fn calendar_days_in_week( } /// 12.2.15 `CalendarDaysInMonth ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_days_in_month( calendar: &JsValue, datelike: &JsValue, @@ -2158,6 +2168,7 @@ pub(crate) fn calendar_days_in_month( } /// 12.2.16 `CalendarDaysInYear ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_days_in_year( calendar: &JsValue, datelike: &JsValue, @@ -2200,6 +2211,7 @@ pub(crate) fn calendar_days_in_year( } /// 12.2.17 `CalendarMonthsInYear ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_months_in_year( calendar: &JsValue, datelike: &JsValue, @@ -2242,6 +2254,7 @@ pub(crate) fn calendar_months_in_year( } /// 12.2.18 `CalendarInLeapYear ( calendar, dateLike )` +#[allow(unused)] pub(crate) fn calendar_in_lear_year( calendar: &JsValue, datelike: &JsValue, @@ -2269,6 +2282,7 @@ pub(crate) fn calendar_in_lear_year( } /// 12.2.24 `CalendarDateFromFields ( calendar, fields [ , options [ , dateFromFields ] ] )` +#[allow(unused)] pub(crate) fn calendar_date_from_fields( _calendar: &JsValue, _fields: &JsObject, diff --git a/boa_engine/src/builtins/temporal/calendar/tests.rs b/boa_engine/src/builtins/temporal/calendar/tests.rs index 303f1521e5d..de24f03efc2 100644 --- a/boa_engine/src/builtins/temporal/calendar/tests.rs +++ b/boa_engine/src/builtins/temporal/calendar/tests.rs @@ -1,12 +1,11 @@ -use crate::{run_test_actions, TestAction}; -use indoc::indoc; +use crate::{js_string, run_test_actions, TestAction}; #[test] fn calendar_constructor() { // TODO: Add other BuiltinCalendars run_test_actions([TestAction::assert_eq( "new Temporal.Calendar('iso8601').id", - "iso8601", + js_string!("iso8601"), )]); } diff --git a/boa_engine/src/builtins/temporal/calendar/utils.rs b/boa_engine/src/builtins/temporal/calendar/utils.rs index 29e27d514da..58a10441893 100644 --- a/boa_engine/src/builtins/temporal/calendar/utils.rs +++ b/boa_engine/src/builtins/temporal/calendar/utils.rs @@ -1,6 +1,8 @@ -use crate::builtins::temporal::{ - self, date_equations, plain_date::iso::IsoDateRecord, TemporalFields, -}; +//! Calendar utility calculations + +// TODO: determine if which are needed. + +use crate::builtins::temporal::{self, date_equations, plain_date::iso::IsoDateRecord}; use crate::JsString; /// 12.2.31 `ISODaysInMonth ( year, month )` @@ -20,6 +22,7 @@ pub(crate) fn iso_days_in_month(year: i32, month: i32) -> i32 { /// 12.2.32 `ToISOWeekOfYear ( year, month, day )` /// /// Takes an `[[IsoYear]]`, `[[IsoMonth]]`, and `[[IsoDay]]` and returns a (week, year) record. +#[allow(unused)] pub(crate) fn to_iso_week_of_year(year: i32, month: i32, day: i32) -> (i32, i32) { // Function constants // 2. Let wednesday be 3. @@ -56,6 +59,7 @@ pub(crate) fn to_iso_week_of_year(year: i32, month: i32, day: i32) -> (i32, i32) } /// 12.2.33 `ISOMonthCode ( month )` +#[allow(unused)] fn iso_month_code(month: i32) -> JsString { // TODO: optimize if month < 10 { @@ -81,6 +85,7 @@ fn iso_month_code(month: i32) -> JsString { // TODO: determine usefulness. /// 12.2.39 `ToISODayOfYear ( year, month, day )` +#[allow(unused)] fn to_iso_day_of_year(year: i32, month: i32, day: i32) -> i32 { // TODO: update fn parameter to take IsoDateRecord. let iso = IsoDateRecord::new(year, month - 1, day); @@ -89,6 +94,7 @@ fn to_iso_day_of_year(year: i32, month: i32, day: i32) -> i32 { } /// 12.2.40 `ToISODayOfWeek ( year, month, day )` +#[allow(unused)] pub(crate) fn to_iso_day_of_week(year: i32, month: i32, day: i32) -> i32 { let iso = IsoDateRecord::new(year, month - 1, day); let epoch_days = iso.as_epoch_days(); diff --git a/boa_engine/src/builtins/temporal/date_equations.rs b/boa_engine/src/builtins/temporal/date_equations.rs index af7ccedf6ea..aa5e1df808b 100644 --- a/boa_engine/src/builtins/temporal/date_equations.rs +++ b/boa_engine/src/builtins/temporal/date_equations.rs @@ -2,7 +2,7 @@ //! //! [spec]: https://tc39.es/proposal-temporal/#sec-date-equations -use std::ops::{Add, Mul}; +use std::ops::Mul; pub(crate) fn epoch_time_to_day_number(t: f64) -> i32 { (t / super::NS_PER_DAY as f64).floor() as i32 diff --git a/boa_engine/src/builtins/temporal/duration/mod.rs b/boa_engine/src/builtins/temporal/duration/mod.rs index b304a770096..4e9f6119e88 100644 --- a/boa_engine/src/builtins/temporal/duration/mod.rs +++ b/boa_engine/src/builtins/temporal/duration/mod.rs @@ -1,4 +1,4 @@ -#![allow(dead_code, unused_variables)] +// Boa's implementation of the `Temporal.Duration` Builtin Object. use crate::{ builtins::{ @@ -7,10 +7,11 @@ use crate::{ BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, ObjectData}, - property::{Attribute, PropertyKey}, + property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; @@ -20,8 +21,7 @@ use super::{ options::{ get_temporal_rounding_increment, get_temporal_unit, TemporalUnit, TemporalUnitGroup, }, - plain_date::iso::IsoDateRecord, - to_integer_if_integral, zoned_date_time, DateTimeValues, + to_integer_if_integral, DateTimeValues, }; mod record; @@ -43,59 +43,59 @@ pub struct Duration { } impl BuiltInObject for Duration { - const NAME: &'static str = "Temporal.Duration"; + const NAME: JsString = StaticJsStrings::DURATION; } impl IntrinsicObject for Duration { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_years = BuiltInBuilder::callable(realm, Self::get_years) - .name("get Years") + .name(js_string!("get Years")) .build(); let get_months = BuiltInBuilder::callable(realm, Self::get_months) - .name("get Months") + .name(js_string!("get Months")) .build(); let get_weeks = BuiltInBuilder::callable(realm, Self::get_weeks) - .name("get Weeks") + .name(js_string!("get Weeks")) .build(); let get_days = BuiltInBuilder::callable(realm, Self::get_days) - .name("get Days") + .name(js_string!("get Days")) .build(); let get_hours = BuiltInBuilder::callable(realm, Self::get_hours) - .name("get Hours") + .name(js_string!("get Hours")) .build(); let get_minutes = BuiltInBuilder::callable(realm, Self::get_minutes) - .name("get Minutes") + .name(js_string!("get Minutes")) .build(); let get_seconds = BuiltInBuilder::callable(realm, Self::get_seconds) - .name("get Seconds") + .name(js_string!("get Seconds")) .build(); let get_milliseconds = BuiltInBuilder::callable(realm, Self::get_milliseconds) - .name("get Milliseconds") + .name(js_string!("get Milliseconds")) .build(); let get_microseconds = BuiltInBuilder::callable(realm, Self::get_microseconds) - .name("get Microseconds") + .name(js_string!("get Microseconds")) .build(); let get_nanoseconds = BuiltInBuilder::callable(realm, Self::get_nanoseconds) - .name("get Nanoseconds") + .name(js_string!("get Nanoseconds")) .build(); let get_sign = BuiltInBuilder::callable(realm, Self::get_sign) - .name("get Sign") + .name(js_string!("get Sign")) .build(); let is_blank = BuiltInBuilder::callable(realm, Self::get_blank) - .name("get blank") + .name(js_string!("get blank")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -146,15 +146,15 @@ impl IntrinsicObject for Duration { ) .accessor(utf16!("sign"), Some(get_sign), None, Attribute::default()) .accessor(utf16!("blank"), Some(is_blank), None, Attribute::default()) - .method(Self::with, "with", 1) - .method(Self::negated, "negated", 0) - .method(Self::abs, "abs", 0) - .method(Self::add, "add", 2) - .method(Self::subtract, "subtract", 2) - .method(Self::round, "round", 1) - .method(Self::total, "total", 1) - .method(Self::to_string, "toString", 1) - .method(Self::to_json, "toJSON", 0) + .method(Self::with, js_string!("with"), 1) + .method(Self::negated, js_string!("negated"), 0) + .method(Self::abs, js_string!("abs"), 0) + .method(Self::add, js_string!("add"), 2) + .method(Self::subtract, js_string!("subtract"), 2) + .method(Self::round, js_string!("round"), 1) + .method(Self::total, js_string!("total"), 1) + .method(Self::to_string, js_string!("toString"), 1) + .method(Self::to_json, js_string!("toJSON"), 0) .build(); } @@ -519,7 +519,7 @@ impl Duration { } /// 7.3.16 `Temporal.Duration.prototype.negated ( )` - pub(crate) fn negated(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + pub(crate) fn negated(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { // 1. Let duration be the this value. // 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). // 3. Return ! CreateNegatedTemporalDuration(duration). @@ -553,18 +553,14 @@ impl Duration { } /// 7.3.18 `Temporal.Duration.prototype.add ( other [ , options ] )` - pub(crate) fn add(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + pub(crate) fn add(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::range() .with_message("not yet implemented.") .into()) } /// 7.3.19 `Temporal.Duration.prototype.subtract ( other [ , options ] )` - pub(crate) fn subtract( - this: &JsValue, - _: &[JsValue], - _: &mut Context<'_>, - ) -> JsResult { + pub(crate) fn subtract(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::range() .with_message("not yet implemented.") .into()) @@ -601,7 +597,7 @@ impl Duration { let new_round_to = JsObject::with_null_proto(); // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). new_round_to.create_data_property_or_throw( - "smallestUnit", + utf16!("smallestUnit"), param_string, context, )?; @@ -774,7 +770,11 @@ impl Duration { // b. Set totalOf to OrdinaryObjectCreate(null). let total_of = JsObject::with_null_proto(); // c. Perform ! CreateDataPropertyOrThrow(totalOf, "unit", paramString). - total_of.create_data_property_or_throw("unit", param_string.clone(), context)?; + total_of.create_data_property_or_throw( + utf16!("unit"), + param_string.clone(), + context, + )?; total_of } // 5. Else, @@ -903,7 +903,7 @@ impl Duration { /// 7.3.22 `Temporal.Duration.prototype.toString ( [ options ] )` pub(crate) fn to_string( - this: &JsValue, + _this: &JsValue, _: &[JsValue], _: &mut Context<'_>, ) -> JsResult { @@ -913,7 +913,11 @@ impl Duration { } /// 7.3.23 `Temporal.Duration.prototype.toJSON ( )` - pub(crate) fn to_json(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + pub(crate) fn to_json( + _this: &JsValue, + _: &[JsValue], + _: &mut Context<'_>, + ) -> JsResult { Err(JsNativeError::range() .with_message("not yet implemented.") .into()) @@ -923,10 +927,7 @@ impl Duration { // -- Duration Abstract Operations -- /// 7.5.8 `ToTemporalDuration ( item )` -pub(crate) fn to_temporal_duration( - item: &JsValue, - context: &mut Context<'_>, -) -> JsResult { +pub(crate) fn to_temporal_duration(item: &JsValue) -> JsResult { // 1a. If Type(item) is Object if item.is_object() { // 1b. and item has an [[InitializedTemporalDuration]] internal slot, then @@ -937,16 +938,14 @@ pub(crate) fn to_temporal_duration( // a. Return item. let obj = o.borrow(); let duration = obj.as_duration().expect("must be a duration."); - return Ok(Duration { - inner: duration.inner, - }); + return Ok(duration.inner.clone()); } } // 2. Let result be ? ToTemporalDurationRecord(item). let result = to_temporal_duration_record(item)?; // 3. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]). - Ok(Duration { inner: result }) + Ok(result) } /// 7.5.9 `ToTemporalDurationRecord ( temporalDurationLike )` diff --git a/boa_engine/src/builtins/temporal/duration/record.rs b/boa_engine/src/builtins/temporal/duration/record.rs index 3b16a679ef2..e22f2b3a8e6 100644 --- a/boa_engine/src/builtins/temporal/duration/record.rs +++ b/boa_engine/src/builtins/temporal/duration/record.rs @@ -1,18 +1,13 @@ -// use DurationRecord and Duration { inner: Duration } - -use icu_calendar::types::Time; +use boa_macros::utf16; use crate::{ builtins::{ options::RoundingMode, - temporal::{self, create_temporal_date, options::TemporalUnit, to_temporal_date, Temporal}, + temporal::{self, create_temporal_date, options::TemporalUnit, to_temporal_date}, }, - Context, JsArgs, JsError, JsNativeError, JsNativeErrorKind, JsObject, JsResult, JsString, - JsSymbol, JsValue, + js_string, Context, JsNativeError, JsObject, JsResult, JsValue, }; -use bitflags::bitflags; - use super::super::{calendar, to_integer_if_integral, zoned_date_time}; // ==== `DateDuration` ==== @@ -211,70 +206,70 @@ impl DurationRecord { // 3. NOTE: The following steps read properties and perform independent validation in alphabetical order. // 4. Let days be ? Get(temporalDurationLike, "days"). - let days = unknown_object.get("days", context)?; + let days = unknown_object.get(utf16!("days"), context)?; if !days.is_undefined() { // 5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days). result.set_days(f64::from(to_integer_if_integral(&days, context)?)); } // 6. Let hours be ? Get(temporalDurationLike, "hours"). - let hours = unknown_object.get("hours", context)?; + let hours = unknown_object.get(utf16!("hours"), context)?; // 7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours). if !hours.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&hours, context)?)); } // 8. Let microseconds be ? Get(temporalDurationLike, "microseconds"). - let microseconds = unknown_object.get("microseconds", context)?; + let microseconds = unknown_object.get(utf16!("microseconds"), context)?; // 9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds). if !microseconds.is_undefined() { result.set_days(f64::from(to_integer_if_integral(µseconds, context)?)); } // 10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds"). - let milliseconds = unknown_object.get("milliseconds", context)?; + let milliseconds = unknown_object.get(utf16!("milliseconds"), context)?; // 11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds). if !milliseconds.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&milliseconds, context)?)); } // 12. Let minutes be ? Get(temporalDurationLike, "minutes"). - let minutes = unknown_object.get("minutes", context)?; + let minutes = unknown_object.get(utf16!("minutes"), context)?; // 13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes). if !minutes.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&minutes, context)?)); } // 14. Let months be ? Get(temporalDurationLike, "months"). - let months = unknown_object.get("months", context)?; + let months = unknown_object.get(utf16!("months"), context)?; // 15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months). if !months.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&months, context)?)); } // 16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds"). - let nanoseconds = unknown_object.get("nanoseconds", context)?; + let nanoseconds = unknown_object.get(utf16!("nanoseconds"), context)?; // 17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds). if !nanoseconds.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&nanoseconds, context)?)); } // 18. Let seconds be ? Get(temporalDurationLike, "seconds"). - let seconds = unknown_object.get("seconds", context)?; + let seconds = unknown_object.get(utf16!("seconds"), context)?; // 19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds). if !seconds.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&seconds, context)?)); } // 20. Let weeks be ? Get(temporalDurationLike, "weeks"). - let weeks = unknown_object.get("weeks", context)?; + let weeks = unknown_object.get(utf16!("weeks"), context)?; // 21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks). if !weeks.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&weeks, context)?)); } // 22. Let years be ? Get(temporalDurationLike, "years"). - let years = unknown_object.get("years", context)?; + let years = unknown_object.get(utf16!("years"), context)?; // 23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years). if !years.is_undefined() { result.set_days(f64::from(to_integer_if_integral(&years, context)?)); @@ -689,7 +684,7 @@ impl DurationRecord { // 4. If largestUnit is one of "year", "month", "week", or "day", then TemporalUnit::Year | TemporalUnit::Month | TemporalUnit::Week | TemporalUnit::Day => { // a. Let result be ? NanosecondsToDays(nanoseconds, relativeTo). - let result = temporal::zoned_date_time::nanoseconds_to_days( + let _result = temporal::zoned_date_time::nanoseconds_to_days( self.nanoseconds(), &relative_to, ); @@ -862,23 +857,23 @@ impl DurationRecord { assert!(sign != 0); // 6. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0). - let one_year = Self::new( + let _one_year = Self::new( DateDuration::new(f64::from(sign), 0.0, 0.0, 0.0), TimeDuration::default(), ); // 7. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0). - let one_month = Self::new( + let _one_month = Self::new( DateDuration::new(0.0, f64::from(sign), 0.0, 0.0), TimeDuration::default(), ); // 8. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0). - let one_week = Self::new( + let _one_week = Self::new( DateDuration::new(0.0, 0.0, f64::from(sign), 0.0), TimeDuration::default(), ); // 9. If relativeTo is not undefined, then - let calendar = if relative_to.is_undefined() { + let _calendar = if relative_to.is_undefined() { // 10. Else // a. Let calendar be undefined. None @@ -965,6 +960,7 @@ impl DurationRecord { } /// `BalanceDateDurationRelative` + #[allow(unused)] pub(crate) fn balance_date_duration_relative( &mut self, largest_unit: TemporalUnit, @@ -1010,7 +1006,7 @@ impl DurationRecord { TimeDuration::default(), ); // 9. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0). - let one_week = Self::new( + let _one_week = Self::new( DateDuration::new(0.0, 0.0, f64::from(sign), 0.0), TimeDuration::default(), ); @@ -1295,11 +1291,6 @@ impl DurationRecord { // i. Let dateAdd be ? GetMethod(calendar, "dateAdd"). // c. Else, // i. Let dateAdd be unused. - let date_add: JsValue = calendar_obj - .get_method("dateAdd", context)? - .expect("dateAdd must exist on a calendar prototype") - .into(); - // d. Let yearsLater be ? CalendarDateAdd(calendar, relativeTo, yearsDuration, undefined, dateAdd). let years_later = calendar::calendar_date_add( @@ -1361,7 +1352,11 @@ impl DurationRecord { // l. Let untilOptions be OrdinaryObjectCreate(null). let until_options = JsObject::with_null_proto(); // m. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "year"). - until_options.create_data_property_or_throw("largestUnit", "year", context)?; + until_options.create_data_property_or_throw( + utf16!("largestUnit"), + js_string!("year"), + context, + )?; // n. Let timePassed be ? CalendarDateUntil(calendar, relativeTo, wholeDaysLater, untilOptions). let time_passed = calendar::calendar_date_until( @@ -1462,10 +1457,6 @@ impl DurationRecord { // i. Let dateAdd be ? GetMethod(calendar, "dateAdd"). // c. Else, // i. Let dateAdd be unused. - let date_add: JsValue = calendar_obj - .get_method("dateAdd", context)? - .expect("dateAdd must exist on a calendar prototype") - .into(); // d. Let yearsMonthsLater be ? CalendarDateAdd(calendar, relativeTo, yearsMonths, undefined, dateAdd). let years_months_later = calendar::calendar_date_add( @@ -1582,10 +1573,6 @@ impl DurationRecord { // i. Let dateAdd be ? GetMethod(calendar, "dateAdd"). // d. Else, // i. Let dateAdd be unused. - let date_add: JsValue = calendar_obj - .get_method("dateAdd", context)? - .expect("dateAdd must exist on a calendar prototype") - .into(); // e. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek, dateAdd). let move_result = @@ -1753,11 +1740,12 @@ impl DurationRecord { /// 7.5.27 `AdjustRoundedDurationDays ( years, months, weeks, days, hours, minutes, seconds, milliseconds, /// microseconds, nanoseconds, increment, unit, roundingMode, relativeTo )` + #[allow(unused)] pub(crate) fn adjust_rounded_duration_days( &mut self, increment: f64, - unit: &JsString, - rounding_mode: &JsString, + unit: TemporalUnit, + rounding_mode: RoundingMode, relative_to: Option<&JsValue>, context: &mut Context<'_>, ) -> JsResult<()> { @@ -1778,11 +1766,13 @@ impl DurationRecord { _ => return Ok(()), }; - match unit.to_std_string_escaped().as_str() { + match unit { // a. Return ! CreateDurationRecord(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds). - "year" | "month" | "week" | "day" => return Ok(()), + TemporalUnit::Year | TemporalUnit::Month | TemporalUnit::Week | TemporalUnit::Day => { + return Ok(()) + } // a. Return ! CreateDurationRecord(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds). - "nanosecond" if (increment - 1_f64).abs() < f64::EPSILON => return Ok(()), + TemporalUnit::Nanosecond if (increment - 1_f64).abs() < f64::EPSILON => return Ok(()), _ => {} } @@ -1791,7 +1781,7 @@ impl DurationRecord { Self::from_day_and_time(0.0, self.time()).total_duration_nanoseconds(0.0); // 3. If timeRemainderNs = 0, let direction be 0. - let direction = if time_remainder_ns == 0_f64 { + let _direction = if time_remainder_ns == 0_f64 { 0 // 4. Else if timeRemainderNs < 0, let direction be -1. } else if time_remainder_ns < 0_f64 { diff --git a/boa_engine/src/builtins/temporal/duration/tests.rs b/boa_engine/src/builtins/temporal/duration/tests.rs index c9b80ebecc6..4deadf08195 100644 --- a/boa_engine/src/builtins/temporal/duration/tests.rs +++ b/boa_engine/src/builtins/temporal/duration/tests.rs @@ -1,5 +1,4 @@ use crate::{run_test_actions, TestAction}; -use indoc::indoc; #[test] fn duration_constructor() { @@ -10,7 +9,7 @@ fn duration_constructor() { TestAction::assert_eq("dur.weeks", 0), TestAction::assert_eq("dur.days", 1), TestAction::assert_eq("dur.milliseconds", 0), - ]) + ]); } #[test] @@ -24,5 +23,5 @@ fn duration_abs() { TestAction::assert_eq("abs.weeks", 0), TestAction::assert_eq("abs.days", 1), TestAction::assert_eq("abs.milliseconds", 0), - ]) + ]); } diff --git a/boa_engine/src/builtins/temporal/fields.rs b/boa_engine/src/builtins/temporal/fields.rs index 29f3c84142f..f1208eef786 100644 --- a/boa_engine/src/builtins/temporal/fields.rs +++ b/boa_engine/src/builtins/temporal/fields.rs @@ -1,11 +1,13 @@ +//! A Rust native implementation of the `fields` object used in `Temporal`. + use crate::{ - js_string, property::PropertyKey, string::utf16, value::PreferredType, Context, JsNativeError, - JsObject, JsResult, JsString, JsValue, + js_string, property::PropertyKey, value::PreferredType, Context, JsNativeError, JsObject, + JsResult, JsString, JsValue, }; -use super::{options::ArithmeticOverflow, plain_date::iso::IsoDateRecord}; +use super::options::ArithmeticOverflow; -use bitflags::{bitflags, iter::Iter, Flags}; +use bitflags::bitflags; use rustc_hash::FxHashSet; bitflags! { @@ -273,6 +275,7 @@ impl TemporalFields { } impl TemporalFields { + // TODO: Shift to JsString or utf16 over String. /// A method for creating a Native representation for `TemporalFields` from /// a `JsObject`. /// @@ -329,7 +332,8 @@ impl TemporalFields { // b. If property is not equal to previousProperty, then if new_value { // i. Let value be ? Get(fields, property). - let value = fields.get(PropertyKey::from(field.clone()), context)?; + let value = + fields.get(PropertyKey::from(JsString::from(field.clone())), context)?; // ii. If value is not undefined, then if !value.is_undefined() { // 1. Set any to true. @@ -395,21 +399,21 @@ impl TemporalFields { match bit { FieldMap::YEAR => { obj.create_data_property_or_throw( - "year", + js_string!("year"), self.year.map_or(JsValue::undefined(), JsValue::from), context, )?; } FieldMap::MONTH => { obj.create_data_property_or_throw( - "month", + js_string!("month"), self.month.map_or(JsValue::undefined(), JsValue::from), context, )?; } FieldMap::MONTH_CODE => { obj.create_data_property_or_throw( - "monthCode", + js_string!("monthCode"), self.month_code .as_ref() .map_or(JsValue::undefined(), |f| f.clone().into()), @@ -418,32 +422,44 @@ impl TemporalFields { } FieldMap::DAY => { obj.create_data_property( - "day", + js_string!("day"), self.day().map_or(JsValue::undefined(), JsValue::from), context, )?; } FieldMap::HOUR => { - obj.create_data_property("hour", self.hour, context)?; + obj.create_data_property(js_string!("hour"), self.hour, context)?; } FieldMap::MINUTE => { - obj.create_data_property("minute", self.minute, context)?; + obj.create_data_property(js_string!("minute"), self.minute, context)?; } FieldMap::SECOND => { - obj.create_data_property_or_throw("second", self.second, context)?; + obj.create_data_property_or_throw(js_string!("second"), self.second, context)?; } FieldMap::MILLISECOND => { - obj.create_data_property_or_throw("millisecond", self.millisecond, context)?; + obj.create_data_property_or_throw( + js_string!("millisecond"), + self.millisecond, + context, + )?; } FieldMap::MICROSECOND => { - obj.create_data_property_or_throw("microsecond", self.microsecond, context)?; + obj.create_data_property_or_throw( + js_string!("microsecond"), + self.microsecond, + context, + )?; } FieldMap::NANOSECOND => { - obj.create_data_property_or_throw("nanosecond", self.nanosecond, context)?; + obj.create_data_property_or_throw( + js_string!("nanosecond"), + self.nanosecond, + context, + )?; } FieldMap::OFFSET => { obj.create_data_property_or_throw( - "offset", + js_string!("offset"), self.offset .as_ref() .map_or(JsValue::undefined(), |s| s.clone().into()), @@ -452,7 +468,7 @@ impl TemporalFields { } FieldMap::ERA => { obj.create_data_property_or_throw( - "era", + js_string!("era"), self.era .as_ref() .map_or(JsValue::undefined(), |s| s.clone().into()), @@ -461,14 +477,14 @@ impl TemporalFields { } FieldMap::ERA_YEAR => { obj.create_data_property_or_throw( - "eraYear", + js_string!("eraYear"), self.era_year.map_or(JsValue::undefined(), JsValue::from), context, )?; } FieldMap::TIME_ZONE => { obj.create_data_property_or_throw( - "timeZone", + js_string!("timeZone"), self.time_zone .as_ref() .map_or(JsValue::undefined(), |s| s.clone().into()), diff --git a/boa_engine/src/builtins/temporal/instant/mod.rs b/boa_engine/src/builtins/temporal/instant/mod.rs index 9ec9af777f9..ae183a9a981 100644 --- a/boa_engine/src/builtins/temporal/instant/mod.rs +++ b/boa_engine/src/builtins/temporal/instant/mod.rs @@ -9,20 +9,18 @@ use crate::{ options::{ get_temporal_rounding_increment, get_temporal_unit, TemporalUnit, TemporalUnitGroup, }, - Duration, }, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, ObjectData}, - property::{Attribute, PropertyKey}, + property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, Context, JsArgs, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; -use num_bigint::ToBigInt; -use num_traits::ToPrimitive; use super::{duration, ns_max_instant, ns_min_instant, MICRO_PER_DAY, MILLI_PER_DAY, NS_PER_DAY}; @@ -37,27 +35,27 @@ pub struct Instant { } impl BuiltInObject for Instant { - const NAME: &'static str = "Temporal.Instant"; + const NAME: JsString = StaticJsStrings::INSTANT; } impl IntrinsicObject for Instant { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_seconds = BuiltInBuilder::callable(realm, Self::get_epoc_seconds) - .name("get epochSeconds") + .name(js_string!("get epochSeconds")) .build(); let get_millis = BuiltInBuilder::callable(realm, Self::get_epoc_milliseconds) - .name("get epochMilliseconds") + .name(js_string!("get epochMilliseconds")) .build(); let get_micros = BuiltInBuilder::callable(realm, Self::get_epoc_microseconds) - .name("get epochMicroseconds") + .name(js_string!("get epochMicroseconds")) .build(); let get_nanos = BuiltInBuilder::callable(realm, Self::get_epoc_nanoseconds) - .name("get epochNanoseconds") + .name(js_string!("get epochNanoseconds")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -90,14 +88,18 @@ impl IntrinsicObject for Instant { None, Attribute::default(), ) - .method(Self::add, "add", 1) - .method(Self::subtract, "subtract", 1) - .method(Self::until, "until", 2) - .method(Self::since, "since", 2) - .method(Self::round, "round", 1) - .method(Self::equals, "equals", 1) - .method(Self::to_zoned_date_time, "toZonedDateTime", 1) - .method(Self::to_zoned_date_time_iso, "toZonedDateTimeISO", 1) + .method(Self::add, js_string!("add"), 1) + .method(Self::subtract, js_string!("subtract"), 1) + .method(Self::until, js_string!("until"), 2) + .method(Self::since, js_string!("since"), 2) + .method(Self::round, js_string!("round"), 1) + .method(Self::equals, js_string!("equals"), 1) + .method(Self::to_zoned_date_time, js_string!("toZonedDateTime"), 1) + .method( + Self::to_zoned_date_time_iso, + js_string!("toZonedDateTimeISO"), + 1, + ) .build(); } @@ -344,9 +346,9 @@ impl Instant { .expect("roundTo is confirmed to be a string here."); // b. Set roundTo to OrdinaryObjectCreate(null). let new_round_to = JsObject::with_null_proto(); - // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). + // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit"), paramString). new_round_to.create_data_property_or_throw( - "smallestUnit", + utf16!("smallestUnit"), param_string.clone(), context, )?; @@ -367,7 +369,7 @@ impl Instant { get_option::(&round_to, utf16!("roundingMode"), false, context)? .unwrap_or_default(); - // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required). + // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit"), time, required). let smallest_unit = get_temporal_unit( &round_to, utf16!("smallestUnit"), @@ -378,19 +380,19 @@ impl Instant { )?; let maximum = match smallest_unit { - // 10. If smallestUnit is "hour", then + // 10. If smallestUnit is "hour"), then // a. Let maximum be HoursPerDay. TemporalUnit::Hour => 24, - // 11. Else if smallestUnit is "minute", then + // 11. Else if smallestUnit is "minute"), then // a. Let maximum be MinutesPerHour × HoursPerDay. TemporalUnit::Minute => 14400, - // 12. Else if smallestUnit is "second", then + // 12. Else if smallestUnit is "second"), then // a. Let maximum be SecondsPerMinute × MinutesPerHour × HoursPerDay. TemporalUnit::Second => 86400, - // 13. Else if smallestUnit is "millisecond", then + // 13. Else if smallestUnit is "millisecond"), then // a. Let maximum be ℝ(msPerDay). TemporalUnit::Millisecond => MILLI_PER_DAY, - // 14. Else if smallestUnit is "microsecond", then + // 14. Else if smallestUnit is "microsecond"), then // a. Let maximum be 103 × ℝ(msPerDay). TemporalUnit::Microsecond => MICRO_PER_DAY, // 15. Else, @@ -504,7 +506,7 @@ fn create_temporal_instant( .constructor() .into() }); - // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Instant.prototype%", « [[InitializedTemporalInstant]], [[Nanoseconds]] »). + // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Instant.prototype%"), « [[InitializedTemporalInstant]], [[Nanoseconds]] »). let proto = get_prototype_from_constructor(&new_target, StandardConstructors::instant, context)?; @@ -633,27 +635,27 @@ fn round_temporal_instant( rounding_mode: RoundingMode, ) -> JsResult { let increment_ns = match unit { - // 1. If unit is "hour", then + // 1. If unit is "hour"), then TemporalUnit::Hour => { // a. Let incrementNs be increment × 3.6 × 10^12. increment as i64 * NANOSECONDS_PER_HOUR } - // 2. Else if unit is "minute", then + // 2. Else if unit is "minute"), then TemporalUnit::Minute => { // a. Let incrementNs be increment × 6 × 10^10. increment as i64 * NANOSECONDS_PER_MINUTE } - // 3. Else if unit is "second", then + // 3. Else if unit is "second"), then TemporalUnit::Second => { // a. Let incrementNs be increment × 10^9. increment as i64 * NANOSECONDS_PER_SECOND } - // 4. Else if unit is "millisecond", then + // 4. Else if unit is "millisecond"), then TemporalUnit::Millisecond => { // a. Let incrementNs be increment × 10^6. increment as i64 * 1_000_000 } - // 5. Else if unit is "microsecond", then + // 5. Else if unit is "microsecond"), then TemporalUnit::Microsecond => { // a. Let incrementNs be increment × 10^3. increment as i64 * 1000 @@ -689,7 +691,7 @@ fn diff_temporal_instant( let resolved_options = super::snapshot_own_properties(&get_options_object(options)?, None, None, context)?; - // 4. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, time, « », "nanosecond", "second"). + // 4. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, time, « », "nanosecond"), "second"). let settings = super::get_diff_settings( op, &resolved_options, diff --git a/boa_engine/src/builtins/temporal/mod.rs b/boa_engine/src/builtins/temporal/mod.rs index 991d624148b..e1093d477d0 100644 --- a/boa_engine/src/builtins/temporal/mod.rs +++ b/boa_engine/src/builtins/temporal/mod.rs @@ -3,7 +3,6 @@ //! More information: //! //! [spec]: https://tc39.es/proposal-temporal/ -#![allow(unreachable_code, dead_code, unused_imports)] // Unimplemented mod calendar; mod date_equations; @@ -20,24 +19,19 @@ mod plain_year_month; mod time_zone; mod zoned_date_time; -use std::ops::Mul; - #[cfg(feature = "experimental")] #[cfg(test)] mod tests; pub(crate) use fields::TemporalFields; +use self::options::{ + get_temporal_rounding_increment, get_temporal_unit, TemporalUnit, TemporalUnitGroup, +}; pub use self::{ calendar::*, duration::*, instant::*, now::*, plain_date::*, plain_date_time::*, plain_month_day::*, plain_time::*, plain_year_month::*, time_zone::*, zoned_date_time::*, }; -use self::{ - date_equations::mathematical_days_in_year, - options::{ - get_temporal_rounding_increment, get_temporal_unit, TemporalUnit, TemporalUnitGroup, - }, -}; use crate::{ builtins::{ @@ -45,17 +39,14 @@ use crate::{ options::{get_option, RoundingMode, UnsignedRoundingMode}, BuiltInBuilder, BuiltInObject, IntrinsicObject, }, - context::intrinsics::{Intrinsics, StandardConstructors}, + context::intrinsics::Intrinsics, js_string, - object::{internal_methods::get_prototype_from_constructor, ObjectData, ObjectInitializer}, - property::{Attribute, PropertyKey}, + property::Attribute, realm::Realm, - string::utf16, - value::{IntegerOrInfinity, Type}, - Context, JsBigInt, JsNativeError, JsNativeErrorKind, JsObject, JsResult, JsString, JsSymbol, - JsValue, NativeFunction, + string::{common::StaticJsStrings, utf16}, + value::Type, + Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; -use boa_ast::temporal::{self, UtcOffset}; use boa_profiler::Profiler; // Relavant numeric constants @@ -75,6 +66,7 @@ pub(crate) fn ns_min_instant() -> JsBigInt { } // An enum representing common fields across `Temporal` objects. +#[allow(unused)] pub(crate) enum DateTimeValues { Year, Month, @@ -89,107 +81,6 @@ pub(crate) enum DateTimeValues { Nanosecond, } -/// `TemporalUnits` represents the temporal relationship laid out in table 13 of the [ECMAScript Specification][spec] -/// -/// [spec]: https://tc39.es/proposal-temporal/#table-temporal-units -#[derive(Debug)] -pub struct TemporalUnits { - year: (&'static [u16], &'static [u16]), - month: (&'static [u16], &'static [u16]), - week: (&'static [u16], &'static [u16]), - day: (&'static [u16], &'static [u16]), - hour: (&'static [u16], &'static [u16]), - minute: (&'static [u16], &'static [u16]), - second: (&'static [u16], &'static [u16]), - millisecond: (&'static [u16], &'static [u16]), - microsecond: (&'static [u16], &'static [u16]), - nanosecond: (&'static [u16], &'static [u16]), -} - -impl Default for TemporalUnits { - fn default() -> Self { - Self { - year: (utf16!("year"), utf16!("years")), - month: (utf16!("month"), utf16!("months")), - week: (utf16!("week"), utf16!("weeks")), - day: (utf16!("day"), utf16!("days")), - hour: (utf16!("hour"), utf16!("hours")), - minute: (utf16!("minute"), utf16!("minutes")), - second: (utf16!("second"), utf16!("seconds")), - millisecond: (utf16!("millisecond"), utf16!("milliseconds")), - microsecond: (utf16!("microsecond"), utf16!("microseconds")), - nanosecond: (utf16!("nanosecond"), utf16!("nanoseconds")), - } - } -} - -impl TemporalUnits { - /// Returns a vector of all date singualar `TemporalUnits`. - fn date_singulars(&self) -> Vec { - vec![ - self.year.0.into(), - self.month.0.into(), - self.week.0.into(), - self.day.0.into(), - ] - } - - /// Returns a vector of all time singular `TemporalUnits`. - fn time_singulars(&self) -> Vec { - vec![ - self.hour.0.into(), - self.minute.0.into(), - self.second.0.into(), - self.millisecond.0.into(), - self.microsecond.0.into(), - self.nanosecond.0.into(), - ] - } - - /// Return a vector of all datetime singular `TemporalUnits`. - fn datetime_singulars(&self) -> Vec { - let mut output = self.date_singulars(); - output.extend(self.time_singulars()); - output - } - - /// Return a vector of all stored singular and plural `TemporalUnits`. - fn all(&self) -> Vec<(&'static [u16], &'static [u16])> { - vec![ - self.year, - self.month, - self.week, - self.day, - self.hour, - self.minute, - self.second, - self.millisecond, - self.microsecond, - self.nanosecond, - ] - } - - fn append_plural_units(&self, singulars: &mut Vec) { - let units_table = self.all(); - for (singular, plural) in units_table { - let singular_string: JsString = singular.into(); - if singulars.contains(&singular_string) { - singulars.push(plural.into()); - } - } - } - - fn plural_lookup(&self, value: &JsString) -> JsString { - let units_table = self.all(); - for (singular, plural) in units_table { - if plural == value { - return singular.into(); - } - } - value.clone() - } -} - /// The [`Temporal`][spec] builtin object. /// /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal-objects @@ -197,12 +88,12 @@ impl TemporalUnits { pub(crate) struct Temporal; impl BuiltInObject for Temporal { - const NAME: &'static str = "Temporal"; + const NAME: JsString = StaticJsStrings::TEMPORAL; } impl IntrinsicObject for Temporal { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::with_intrinsic::(realm) .static_property( @@ -211,32 +102,32 @@ impl IntrinsicObject for Temporal { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "Now", + js_string!("Now"), realm.intrinsics().objects().now(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "Calendar", + js_string!("Calendar"), realm.intrinsics().constructors().calendar().constructor(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "Duration", + js_string!("Duration"), realm.intrinsics().constructors().duration().constructor(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "Instant", + js_string!("Instant"), realm.intrinsics().constructors().instant().constructor(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "PlainDate", + js_string!("PlainDate"), realm.intrinsics().constructors().plain_date().constructor(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "PlainDateTime", + js_string!("PlainDateTime"), realm .intrinsics() .constructors() @@ -245,7 +136,7 @@ impl IntrinsicObject for Temporal { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "PlainMonthDay", + js_string!("PlainMonthDay"), realm .intrinsics() .constructors() @@ -254,12 +145,12 @@ impl IntrinsicObject for Temporal { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "PlainTime", + js_string!("PlainTime"), realm.intrinsics().constructors().plain_time().constructor(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "PlainYearMonth", + js_string!("PlainYearMonth"), realm .intrinsics() .constructors() @@ -268,12 +159,12 @@ impl IntrinsicObject for Temporal { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "TimeZone", + js_string!("TimeZone"), realm.intrinsics().constructors().time_zone().constructor(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( - "ZonedDateTime", + js_string!("ZonedDateTime"), realm .intrinsics() .constructors() @@ -594,7 +485,7 @@ pub(crate) fn to_relative_temporal_object( ) -> JsResult { // 1. Assert: Type(options) is Object. // 2. Let value be ? Get(options, "relativeTo"). - let value = options.get("relativeTo", context)?; + let value = options.get(js_string!("relativeTo"), context)?; // 3. If value is undefined, then if value.is_undefined() { // a. Return value. diff --git a/boa_engine/src/builtins/temporal/now.rs b/boa_engine/src/builtins/temporal/now.rs index baed2425c12..a67023a8d5f 100644 --- a/boa_engine/src/builtins/temporal/now.rs +++ b/boa_engine/src/builtins/temporal/now.rs @@ -5,12 +5,12 @@ use crate::{ temporal::{create_temporal_time_zone, default_time_zone}, BuiltInBuilder, BuiltInObject, IntrinsicObject, }, - context::intrinsics::{Intrinsics, StandardConstructors}, - object::{internal_methods::get_prototype_from_constructor, ObjectData, ObjectInitializer}, + context::intrinsics::Intrinsics, + js_string, property::Attribute, realm::Realm, - value::IntegerOrInfinity, - Context, JsBigInt, JsNativeError, JsObject, JsResult, JsSymbol, JsValue, NativeFunction, + string::common::StaticJsStrings, + Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; @@ -24,7 +24,7 @@ pub struct Now; impl IntrinsicObject for Now { /// Initializes the `Temporal.Now` object. fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); // is an ordinary object. // has a [[Prototype]] internal slot whose value is %Object.prototype%. @@ -37,14 +37,14 @@ impl IntrinsicObject for Now { Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .static_method(Self::time_zone_id, "timeZoneId", 0) - .static_method(Self::instant, "instant", 0) - .static_method(Self::plain_date_time, "plainDateTime", 2) - .static_method(Self::plain_date_time_iso, "plainDateTimeISO", 1) - .static_method(Self::zoned_date_time, "zonedDateTime", 2) - .static_method(Self::zoned_date_time_iso, "zonedDateTimeISO", 1) - .static_method(Self::plain_date, "plainDate", 2) - .static_method(Self::plain_date_iso, "plainDateISO", 1) + .static_method(Self::time_zone_id, js_string!("timeZoneId"), 0) + .static_method(Self::instant, js_string!("instant"), 0) + .static_method(Self::plain_date_time, js_string!("plainDateTime"), 2) + .static_method(Self::plain_date_time_iso, js_string!("plainDateTimeISO"), 1) + .static_method(Self::zoned_date_time, js_string!("zonedDateTime"), 2) + .static_method(Self::zoned_date_time_iso, js_string!("zonedDateTimeISO"), 1) + .static_method(Self::plain_date, js_string!("plainDate"), 2) + .static_method(Self::plain_date_iso, js_string!("plainDateISO"), 1) .build(); } @@ -54,7 +54,7 @@ impl IntrinsicObject for Now { } impl BuiltInObject for Now { - const NAME: &'static str = "Temporal.Now"; + const NAME: JsString = StaticJsStrings::NOW; } impl Now { @@ -143,6 +143,7 @@ fn clamp_epoc_nanos(ns: JsBigInt) -> JsBigInt { } /// 2.3.2 `SystemUTCEpochMilliseconds` +#[allow(unused)] fn system_utc_epoch_millis() -> JsResult { let now = host_system_utc_epoch_nanoseconds()?; Ok(now.to_f64().div_euclid(1_000_000_f64).floor()) diff --git a/boa_engine/src/builtins/temporal/options.rs b/boa_engine/src/builtins/temporal/options.rs index 7d70aee9638..c39e1836fe7 100644 --- a/boa_engine/src/builtins/temporal/options.rs +++ b/boa_engine/src/builtins/temporal/options.rs @@ -8,10 +8,8 @@ // // https://github.com/tc39/proposal-temporal/blob/main/polyfill/index.d.ts -use boa_macros::utf16; - use crate::{ - builtins::options::{get_option, ParsableOptionType, ParseRoundingModeError}, + builtins::options::{get_option, ParsableOptionType}, js_string, Context, JsNativeError, JsObject, JsResult, }; use std::{fmt, str::FromStr}; diff --git a/boa_engine/src/builtins/temporal/plain_date/mod.rs b/boa_engine/src/builtins/temporal/plain_date/mod.rs index 935014d3001..e09caf05745 100644 --- a/boa_engine/src/builtins/temporal/plain_date/mod.rs +++ b/boa_engine/src/builtins/temporal/plain_date/mod.rs @@ -6,10 +6,11 @@ use crate::{ BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_parser::temporal::{IsoCursor, TemporalDateTimeString}; @@ -27,67 +28,67 @@ pub struct PlainDate { } impl BuiltInObject for PlainDate { - const NAME: &'static str = "Temporal.PlainDate"; + const NAME: JsString = StaticJsStrings::PLAIN_DATE; } impl IntrinsicObject for PlainDate { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_calendar_id = BuiltInBuilder::callable(realm, Self::get_calendar_id) - .name("get calendarId") + .name(js_string!("get calendarId")) .build(); let get_year = BuiltInBuilder::callable(realm, Self::get_year) - .name("get year") + .name(js_string!("get year")) .build(); let get_month = BuiltInBuilder::callable(realm, Self::get_month) - .name("get month") + .name(js_string!("get month")) .build(); let get_month_code = BuiltInBuilder::callable(realm, Self::get_month_code) - .name("get monthCode") + .name(js_string!("get monthCode")) .build(); let get_day = BuiltInBuilder::callable(realm, Self::get_day) - .name("get day") + .name(js_string!("get day")) .build(); let get_day_of_week = BuiltInBuilder::callable(realm, Self::get_day_of_week) - .name("get dayOfWeek") + .name(js_string!("get dayOfWeek")) .build(); let get_day_of_year = BuiltInBuilder::callable(realm, Self::get_day_of_year) - .name("get dayOfYear") + .name(js_string!("get dayOfYear")) .build(); let get_week_of_year = BuiltInBuilder::callable(realm, Self::get_week_of_year) - .name("get weekOfYear") + .name(js_string!("get weekOfYear")) .build(); let get_year_of_week = BuiltInBuilder::callable(realm, Self::get_year_of_week) - .name("get yearOfWeek") + .name(js_string!("get yearOfWeek")) .build(); let get_days_in_week = BuiltInBuilder::callable(realm, Self::get_days_in_week) - .name("get daysInWeek") + .name(js_string!("get daysInWeek")) .build(); let get_days_in_month = BuiltInBuilder::callable(realm, Self::get_days_in_month) - .name("get daysInMonth") + .name(js_string!("get daysInMonth")) .build(); let get_days_in_year = BuiltInBuilder::callable(realm, Self::get_days_in_year) - .name("get daysInYear") + .name(js_string!("get daysInYear")) .build(); let get_months_in_year = BuiltInBuilder::callable(realm, Self::get_months_in_year) - .name("get monthsInYear") + .name(js_string!("get monthsInYear")) .build(); let get_in_leap_year = BuiltInBuilder::callable(realm, Self::get_in_leap_year) - .name("get inLeapYear") + .name(js_string!("get inLeapYear")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -165,17 +166,17 @@ impl IntrinsicObject for PlainDate { None, Attribute::default(), ) - .method(Self::to_plain_year_month, "toPlainYearMonth", 0) - .method(Self::to_plain_month_day, "toPlainMonthDay", 0) - .method(Self::get_iso_fields, "getISOFields", 0) - .method(Self::get_calendar, "getCalendar", 0) - .method(Self::add, "add", 2) - .method(Self::subtract, "subtract", 2) - .method(Self::with, "with", 2) - .method(Self::with_calendar, "withCalendar", 1) - .method(Self::until, "until", 2) - .method(Self::since, "since", 2) - .method(Self::equals, "equals", 1) + .method(Self::to_plain_year_month, js_string!("toPlainYearMonth"), 0) + .method(Self::to_plain_month_day, js_string!("toPlainMonthDay"), 0) + .method(Self::get_iso_fields, js_string!("getISOFields"), 0) + .method(Self::get_calendar, js_string!("getCalendar"), 0) + .method(Self::add, js_string!("add"), 2) + .method(Self::subtract, js_string!("subtract"), 2) + .method(Self::with, js_string!("with"), 2) + .method(Self::with_calendar, js_string!("withCalendar"), 1) + .method(Self::until, js_string!("until"), 2) + .method(Self::since, js_string!("since"), 2) + .method(Self::equals, js_string!("equals"), 1) .build(); } @@ -204,7 +205,7 @@ impl BuiltInConstructor for PlainDate { let iso_year = super::to_integer_with_truncation(args.get_or_undefined(0), context)?; let iso_month = super::to_integer_with_truncation(args.get_or_undefined(1), context)?; let iso_day = super::to_integer_with_truncation(args.get_or_undefined(2), context)?; - let default_calendar = JsValue::from("iso8601"); + let default_calendar = JsValue::from(js_string!("iso8601")); let calendar_like = args.get(3).unwrap_or(&default_calendar); let iso = IsoDateRecord::new(iso_year, iso_month, iso_day); @@ -519,7 +520,9 @@ pub(crate) fn to_temporal_date( // 7. Assert: IsValidISODate(result.[[Year]], result.[[Month]], result.[[Day]]) is true. // 8. Let calendar be result.[[Calendar]]. // 9. If calendar is undefined, set calendar to "iso8601". - let identifier = result.calendar.unwrap_or_else(|| "iso8601".to_string()); + let identifier = result + .calendar + .map_or_else(|| js_string!("iso8601"), JsString::from); // 10. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception. if !super::calendar::is_builtin_calendar(&identifier) { @@ -528,8 +531,8 @@ pub(crate) fn to_temporal_date( .into()); } + // TODO: impl to ASCII-lowercase on JsStirng // 11. Set calendar to the ASCII-lowercase of calendar. - let calendar = identifier.to_ascii_lowercase(); // 12. Perform ? ToTemporalOverflow(options). let _result = @@ -539,7 +542,7 @@ pub(crate) fn to_temporal_date( // 13. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar). Ok(PlainDate { inner: IsoDateRecord::new(result.date.year, result.date.month, result.date.day), - calendar: calendar.into(), + calendar: identifier.into(), }) } _ => Err(JsNativeError::typ() diff --git a/boa_engine/src/builtins/temporal/plain_date_time/mod.rs b/boa_engine/src/builtins/temporal/plain_date_time/mod.rs index 643a3c6d490..d12f55cd074 100644 --- a/boa_engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/boa_engine/src/builtins/temporal/plain_date_time/mod.rs @@ -1,16 +1,16 @@ #![allow(dead_code, unused_variables)] use crate::{ - builtins::{date::utils, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, + builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, property::Attribute, realm::Realm, - Context, JsBigInt, JsNativeError, JsObject, JsResult, JsSymbol, JsValue, + string::common::StaticJsStrings, + Context, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; use self::iso::IsoDateTimeRecord; -use super::DateTimeValues; pub(crate) mod iso; /// The `Temporal.PlainDateTime` object. @@ -21,12 +21,12 @@ pub struct PlainDateTime { } impl BuiltInObject for PlainDateTime { - const NAME: &'static str = "Temporal.PlainDateTime"; + const NAME: JsString = StaticJsStrings::PLAIN_DATETIME; } impl IntrinsicObject for PlainDateTime { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .static_property( diff --git a/boa_engine/src/builtins/temporal/plain_month_day/mod.rs b/boa_engine/src/builtins/temporal/plain_month_day/mod.rs index 95b68cc7710..ac26a522f40 100644 --- a/boa_engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/boa_engine/src/builtins/temporal/plain_month_day/mod.rs @@ -2,9 +2,10 @@ use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, - object::internal_methods::get_prototype_from_constructor, + object::{internal_methods::get_prototype_from_constructor, ObjectData}, property::Attribute, realm::Realm, + string::common::StaticJsStrings, Context, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; @@ -19,12 +20,12 @@ pub struct PlainMonthDay { } impl BuiltInObject for PlainMonthDay { - const NAME: &'static str = "Temporal.PlainMonthDay"; + const NAME: JsString = StaticJsStrings::PLAIN_MD; } impl IntrinsicObject for PlainMonthDay { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .static_property( @@ -97,26 +98,24 @@ pub(crate) fn create_temporal_month_day( }; // 4. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainMonthDay.prototype%", « [[InitializedTemporalMonthDay]], [[ISOMonth]], [[ISODay]], [[ISOYear]], [[Calendar]] »). - let new_month_day = get_prototype_from_constructor( + let proto = get_prototype_from_constructor( &new_target, StandardConstructors::plain_month_day, context, )?; - let mut obj = new_month_day.borrow_mut(); - let month_day = obj - .as_plain_month_day_mut() - .expect("this value must be a date"); - // 5. Set object.[[ISOMonth]] to isoMonth. // 6. Set object.[[ISODay]] to isoDay. // 7. Set object.[[Calendar]] to calendar. // 8. Set object.[[ISOYear]] to referenceISOYear. - month_day.inner = iso; - month_day.calendar = calendar; - - drop(obj); + let obj = JsObject::from_proto_and_data( + proto, + ObjectData::plain_month_day(PlainMonthDay { + inner: iso, + calendar, + }), + ); // 9. Return object. - Ok(new_month_day.into()) + Ok(obj.into()) } diff --git a/boa_engine/src/builtins/temporal/plain_time/mod.rs b/boa_engine/src/builtins/temporal/plain_time/mod.rs index d7025b49289..88fd5eeb176 100644 --- a/boa_engine/src/builtins/temporal/plain_time/mod.rs +++ b/boa_engine/src/builtins/temporal/plain_time/mod.rs @@ -4,7 +4,8 @@ use crate::{ context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, property::Attribute, realm::Realm, - Context, JsNativeError, JsObject, JsResult, JsSymbol, JsValue, + string::common::StaticJsStrings, + Context, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; @@ -20,12 +21,12 @@ pub struct PlainTime { } impl BuiltInObject for PlainTime { - const NAME: &'static str = "Temporal.PlainTime"; + const NAME: JsString = StaticJsStrings::PLAIN_TIME; } impl IntrinsicObject for PlainTime { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .static_property( diff --git a/boa_engine/src/builtins/temporal/plain_year_month/mod.rs b/boa_engine/src/builtins/temporal/plain_year_month/mod.rs index 994fa76d076..d5c6ead7bdf 100644 --- a/boa_engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/boa_engine/src/builtins/temporal/plain_year_month/mod.rs @@ -1,17 +1,18 @@ -#![allow(dead_code, unused_variables)] +//! Boa's implementation of the `Temporal.PlainYearMonth` builtin object. use crate::{ builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject}, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::{internal_methods::get_prototype_from_constructor, ObjectData}, property::Attribute, realm::Realm, - string::utf16, + string::{common::StaticJsStrings, utf16}, Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; -use super::{plain_date::iso::IsoDateRecord, TemporalFields}; +use super::plain_date::iso::IsoDateRecord; /// The `Temporal.PlainYearMonth` object. #[derive(Debug, Clone)] @@ -21,43 +22,43 @@ pub struct PlainYearMonth { } impl BuiltInObject for PlainYearMonth { - const NAME: &'static str = "Temporal.PlainYearMonth"; + const NAME: JsString = StaticJsStrings::PLAIN_YM; } impl IntrinsicObject for PlainYearMonth { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_calendar_id = BuiltInBuilder::callable(realm, Self::get_calendar_id) - .name("get calendarId") + .name(js_string!("get calendarId")) .build(); let get_year = BuiltInBuilder::callable(realm, Self::get_year) - .name("get year") + .name(js_string!("get year")) .build(); let get_month = BuiltInBuilder::callable(realm, Self::get_month) - .name("get month") + .name(js_string!("get month")) .build(); let get_month_code = BuiltInBuilder::callable(realm, Self::get_month_code) - .name("get monthCode") + .name(js_string!("get monthCode")) .build(); let get_days_in_month = BuiltInBuilder::callable(realm, Self::get_days_in_month) - .name("get daysInMonth") + .name(js_string!("get daysInMonth")) .build(); let get_days_in_year = BuiltInBuilder::callable(realm, Self::get_days_in_year) - .name("get daysInYear") + .name(js_string!("get daysInYear")) .build(); let get_months_in_year = BuiltInBuilder::callable(realm, Self::get_months_in_year) - .name("get monthsInYear") + .name(js_string!("get monthsInYear")) .build(); let get_in_leap_year = BuiltInBuilder::callable(realm, Self::get_in_leap_year) - .name("get inLeapYear") + .name(js_string!("get inLeapYear")) .build(); BuiltInBuilder::from_standard_constructor::(realm) @@ -104,12 +105,12 @@ impl IntrinsicObject for PlainYearMonth { None, Attribute::default(), ) - .method(Self::with, "with", 2) - .method(Self::add, "add", 2) - .method(Self::subtract, "subtract", 2) - .method(Self::until, "until", 2) - .method(Self::since, "since", 2) - .method(Self::equals, "equals", 1) + .method(Self::with, js_string!("with"), 2) + .method(Self::add, js_string!("add"), 2) + .method(Self::subtract, js_string!("subtract"), 2) + .method(Self::until, js_string!("until"), 2) + .method(Self::since, js_string!("since"), 2) + .method(Self::equals, js_string!("equals"), 1) .build(); } @@ -157,56 +158,65 @@ impl BuiltInConstructor for PlainYearMonth { // 7. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget). let record = IsoDateRecord::new(y, m, ref_day); - create_temporal_year_month(record, JsValue::from("iso8601"), Some(new_target), context) + create_temporal_year_month( + record, + JsValue::from(js_string!("iso8601")), + Some(new_target), + context, + ) } } // ==== `PlainYearMonth` Accessor Implementations ==== impl PlainYearMonth { - fn get_calendar_id(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_calendar_id(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn get_year(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_year(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn get_month(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_month(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn get_month_code(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_month_code(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn get_days_in_year(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_days_in_year(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn get_days_in_month(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_days_in_month(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn get_months_in_year(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_months_in_year( + _this: &JsValue, + _: &[JsValue], + _: &mut Context<'_>, + ) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn get_in_leap_year(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn get_in_leap_year(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) @@ -216,37 +226,37 @@ impl PlainYearMonth { // ==== `PlainYearMonth` Method Implementations ==== impl PlainYearMonth { - fn with(this: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn with(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::typ() .with_message("not yet implemented.") .into()) } - fn add(this: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn add(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::typ() .with_message("not yet implemented.") .into()) } - fn subtract(this: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn subtract(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::typ() .with_message("not yet implemented.") .into()) } - fn until(this: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn until(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::typ() .with_message("not yet implemented.") .into()) } - fn since(this: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn since(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::typ() .with_message("not yet implemented.") .into()) } - fn equals(this: &JsValue, args: &[JsValue], _: &mut Context<'_>) -> JsResult { + fn equals(_this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { Err(JsNativeError::typ() .with_message("not yet implemented.") .into()) @@ -256,36 +266,7 @@ impl PlainYearMonth { // ==== Abstract Operations ==== // 9.5.2 `RegulateISOYearMonth ( year, month, overflow )` -pub(crate) fn regulate_iso_year_month( - year: i32, - month: i32, - overflow: &JsString, -) -> JsResult<(i32, i32)> { - // 1. Assert: year and month are integers. - // 2. Assert: overflow is either "constrain" or "reject". - // 3. If overflow is "constrain", then - let month = match overflow.to_std_string_escaped().as_str() { - "constrain" => { - // a. Set month to the result of clamping month between 1 and 12. - // b. Return the Record { [[Year]]: year, [[Month]]: month }. - month.clamp(1, 12) - } - "reject" => { - // a. Assert: overflow is "reject". - // b. If month < 1 or month > 12, throw a RangeError exception. - if !(1..=12).contains(&month) { - return Err(JsNativeError::range() - .with_message("month is not within the valid range.") - .into()); - } - // c. Return the Record { [[Year]]: year, [[Month]]: month }. - month - } - _ => unreachable!(), - }; - - Ok((year, month)) -} +// Implemented on `TemporalFields`. // 9.5.5 `CreateTemporalYearMonth ( isoYear, isoMonth, calendar, referenceISODay [ , newTarget ] )` pub(crate) fn create_temporal_year_month( diff --git a/boa_engine/src/builtins/temporal/tests.rs b/boa_engine/src/builtins/temporal/tests.rs index e87b642df31..7400eb98f80 100644 --- a/boa_engine/src/builtins/temporal/tests.rs +++ b/boa_engine/src/builtins/temporal/tests.rs @@ -1,5 +1,4 @@ -use crate::{object::JsObject, run_test_actions, JsNativeErrorKind, JsValue, TestAction}; -use indoc::indoc; +use crate::{js_string, run_test_actions, JsValue, TestAction}; #[test] fn temporal_object() { @@ -7,11 +6,11 @@ fn temporal_object() { run_test_actions([ TestAction::assert_eq( "Object.prototype.toString.call(Temporal)", - "[object Temporal]", + js_string!("[object Temporal]"), ), - TestAction::assert_eq("String(Temporal)", "[object Temporal]"), + TestAction::assert_eq("String(Temporal)", js_string!("[object Temporal]")), TestAction::assert_eq("Object.keys(Temporal).length === 0", true), - ]) + ]); } #[test] @@ -21,12 +20,12 @@ fn now_object() { TestAction::assert_eq("Object.isExtensible(Temporal.Now)", true), TestAction::assert_eq( "Object.prototype.toString.call(Temporal.Now)", - "[object Temporal.Now]", + js_string!("[object Temporal.Now]"), ), TestAction::assert_eq( "Object.getPrototypeOf(Temporal.Now) === Object.prototype", true, ), TestAction::assert_eq("Temporal.Now.prototype", JsValue::undefined()), - ]) + ]); } diff --git a/boa_engine/src/builtins/temporal/time_zone/mod.rs b/boa_engine/src/builtins/temporal/time_zone/mod.rs index 7f96cf75fcb..1f053ade575 100644 --- a/boa_engine/src/builtins/temporal/time_zone/mod.rs +++ b/boa_engine/src/builtins/temporal/time_zone/mod.rs @@ -1,8 +1,5 @@ #![allow(dead_code)] -use boa_ast::temporal::{TzIdentifier, UtcOffset}; -use chrono::format::parse; - use crate::{ builtins::{ temporal::to_zero_padded_decimal_string, BuiltInBuilder, BuiltInConstructor, BuiltInObject, @@ -10,14 +7,10 @@ use crate::{ }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, js_string, - object::{ - internal_methods::get_prototype_from_constructor, ConstructorBuilder, - FunctionObjectBuilder, ObjectData, ObjectInitializer, CONSTRUCTOR, - }, + object::{internal_methods::get_prototype_from_constructor, ObjectData, CONSTRUCTOR}, property::Attribute, realm::Realm, - string::utf16, - value::{AbstractRelation, IntegerOrInfinity}, + string::{common::StaticJsStrings, utf16}, Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; @@ -31,31 +24,51 @@ pub struct TimeZone { } impl BuiltInObject for TimeZone { - const NAME: &'static str = "Temporal.TimeZone"; + const NAME: JsString = StaticJsStrings::TIMEZONE; } impl IntrinsicObject for TimeZone { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); let get_id = BuiltInBuilder::callable(realm, Self::get_id) - .name("get Id") + .name(js_string!("get Id")) .build(); BuiltInBuilder::from_standard_constructor::(realm) .method( Self::get_offset_nanoseconds_for, - "getOffsetNanosecondsFor", + js_string!("getOffsetNanosecondsFor"), + 1, + ) + .method( + Self::get_offset_string_for, + js_string!("getOffsetStringFor"), + 1, + ) + .method( + Self::get_plain_date_time_for, + js_string!("getPlainDateTimeFor"), + 2, + ) + .method(Self::get_instant_for, js_string!("getInstantFor"), 2) + .method( + Self::get_possible_instants_for, + js_string!("getPossibleInstantFor"), 1, ) - .method(Self::get_offset_string_for, "getOffsetStringFor", 1) - .method(Self::get_plain_date_time_for, "getPlainDateTimeFor", 2) - .method(Self::get_instant_for, "getInstantFor", 2) - .method(Self::get_possible_instants_for, "getPossibleInstantFor", 1) - .method(Self::get_next_transition, "getNextTransition", 1) - .method(Self::get_previous_transition, "getPreviousTransition", 1) - .method(Self::to_string, "toString", 0) - .method(Self::to_string, "toJSON", 0) + .method( + Self::get_next_transition, + js_string!("getNextTransition"), + 1, + ) + .method( + Self::get_previous_transition, + js_string!("getPreviousTransition"), + 1, + ) + .method(Self::to_string, js_string!("toString"), 0) + .method(Self::to_string, js_string!("toJSON"), 0) .static_property( JsSymbol::to_string_tag(), Self::NAME, @@ -118,14 +131,13 @@ impl BuiltInConstructor for TimeZone { impl TimeZone { // NOTE: id, toJSON, toString currently share the exact same implementation -> Consolidate into one function and define multiple accesors? pub(crate) fn get_id(this: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult { - let o = this.as_object().ok_or_else(|| { + let o = this.as_object().map(JsObject::borrow).ok_or_else(|| { JsNativeError::typ().with_message("this value must be a Temporal.TimeZone") })?; - let o = o.borrow(); let tz = o.as_time_zone().ok_or_else(|| { JsNativeError::typ().with_message("this value must be a Temporal.TimeZone") })?; - Ok(tz.identifier.clone().into()) + Ok(JsString::from(tz.identifier.clone()).into()) } pub(crate) fn get_offset_nanoseconds_for( @@ -250,7 +262,7 @@ impl TimeZone { JsNativeError::typ().with_message("this value must be a Temporal.TimeZone") })?; // 3. Return timeZone.[[Identifier]]. - Ok(tz.identifier.clone().into()) + Ok(JsString::from(tz.identifier.clone()).into()) } } diff --git a/boa_engine/src/builtins/temporal/zoned_date_time/mod.rs b/boa_engine/src/builtins/temporal/zoned_date_time/mod.rs index b31cfe12394..6034dec9f3f 100644 --- a/boa_engine/src/builtins/temporal/zoned_date_time/mod.rs +++ b/boa_engine/src/builtins/temporal/zoned_date_time/mod.rs @@ -4,7 +4,8 @@ use crate::{ context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, property::Attribute, realm::Realm, - Context, JsBigInt, JsNativeError, JsObject, JsResult, JsSymbol, JsValue, + string::common::StaticJsStrings, + Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; @@ -17,12 +18,12 @@ pub struct ZonedDateTime { } impl BuiltInObject for ZonedDateTime { - const NAME: &'static str = "Temporal.ZonedDateTime"; + const NAME: JsString = StaticJsStrings::ZONED_DT; } impl IntrinsicObject for ZonedDateTime { fn init(realm: &Realm) { - let _timer = Profiler::global().start_event(Self::NAME, "init"); + let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); BuiltInBuilder::from_standard_constructor::(realm) .static_property( diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 3fa1776f6bf..8651af7dd77 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -70,12 +70,6 @@ use crate::{ Context, JsBigInt, JsString, JsSymbol, JsValue, }; -#[cfg(feature = "temporal")] -use crate::builtins::temporal::{ - Calendar, Duration, Instant, PlainDate, PlainDateTime, PlainMonthDay, PlainTime, - PlainYearMonth, TimeZone, ZonedDateTime, -}; - use boa_gc::{custom_trace, Finalize, Trace, WeakGc}; use std::{ any::{Any, TypeId}, @@ -443,43 +437,43 @@ pub enum ObjectKind { PluralRules(PluralRules), /// The `Temporal.Instant` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Instant(Instant), /// The `Temporal.PlainDateTime` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] PlainDateTime(PlainDateTime), /// The `Temporal.PlainDate` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] PlainDate(PlainDate), /// The `Temporal.PlainTime` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] PlainTime(PlainTime), /// The `Temporal.PlainYearMonth` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] PlainYearMonth(PlainYearMonth), /// The `Temporal.PlainMonthDay` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] PlainMonthDay(PlainMonthDay), /// The `Temporal.TimeZone` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] TimeZone(Box), /// The `Temporal.Duration` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Duration(Duration), /// The `Temporal.ZonedDateTime` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] ZonedDateTime(ZonedDateTime), /// The `Temporal.Calendar` object kind. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Calendar(Box), } @@ -534,7 +528,7 @@ unsafe impl Trace for ObjectKind { | Self::Global | Self::Number(_) | Self::Symbol(_) => {} - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::Instant(_) | Self::PlainDateTime(_) | Self::PlainDate(_) @@ -980,7 +974,7 @@ impl ObjectData { } /// Create the `Instant` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn instant(instant: Instant) -> Self { Self { @@ -990,7 +984,7 @@ impl ObjectData { } /// Create the `PlainDateTime` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn plain_date_time(date_time: PlainDateTime) -> Self { Self { @@ -999,7 +993,7 @@ impl ObjectData { } } /// Create the `PlainDate` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn plain_date(date: PlainDate) -> Self { Self { @@ -1009,7 +1003,7 @@ impl ObjectData { } /// Create the `PlainTime` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn plain_time(time: PlainTime) -> Self { Self { @@ -1019,7 +1013,7 @@ impl ObjectData { } /// Create the `PlainYearMonth` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn plain_year_month(year_month: PlainYearMonth) -> Self { Self { @@ -1029,7 +1023,7 @@ impl ObjectData { } /// Create the `PlainMonthDay` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn plain_month_day(month_day: PlainMonthDay) -> Self { Self { @@ -1039,7 +1033,7 @@ impl ObjectData { } /// Create the `TimeZone` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn time_zone(time_zone: TimeZone) -> Self { Self { @@ -1049,7 +1043,7 @@ impl ObjectData { } /// Create the `Duration` object data - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn duration(duration: Duration) -> Self { Self { @@ -1059,7 +1053,7 @@ impl ObjectData { } /// Create the `ZonedDateTime` object data. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn zoned_date_time(zoned_date_time: ZonedDateTime) -> Self { Self { @@ -1069,7 +1063,7 @@ impl ObjectData { } /// Create the `Calendar` object data. - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] #[must_use] pub fn calendar(calendar: Calendar) -> Self { Self { @@ -1135,25 +1129,25 @@ impl Debug for ObjectKind { Self::SegmentIterator(_) => "SegmentIterator", #[cfg(feature = "intl")] Self::PluralRules(_) => "PluralRules", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::Instant(_) => "Instant", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::PlainDateTime(_) => "PlainDateTime", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::PlainDate(_) => "PlainDate", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::PlainTime(_) => "PlainTime", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::PlainYearMonth(_) => "PlainYearMonth", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::PlainMonthDay(_) => "PlainMonthDay", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::TimeZone(_) => "TimeZone", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::Duration(_) => "Duration", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::ZonedDateTime(_) => "ZonedDateTime", - #[cfg(feature = "temporal")] + #[cfg(feature = "experimental")] Self::Calendar(_) => "Calendar", }) } diff --git a/boa_engine/src/string/common.rs b/boa_engine/src/string/common.rs index 8e8b05febee..3416b38b969 100644 --- a/boa_engine/src/string/common.rs +++ b/boa_engine/src/string/common.rs @@ -160,6 +160,18 @@ impl StaticJsStrings { (WEAK_REF, "WeakRef"), (WEAK_MAP, "WeakMap"), (WEAK_SET, "WeakSet"), + (TEMPORAL, "Temporal"), + (NOW, "Temporal.Now"), + (INSTANT, "Temporal.Instant"), + (DURATION, "Temporal.Duration"), + (PLAIN_DATE, "Temporal.PlainDate"), + (PLAIN_DATETIME, "Temporal.PlainDateTime"), + (PLAIN_TIME, "Temporal.PlainTime"), + (PLAIN_YM, "Temporal.PlainYearMonth"), + (PLAIN_MD, "Temporal.PlainMonthDay"), + (CALENDAR, "Temporal.Calendar"), + (TIMEZONE, "Temporal.TimeZone"), + (ZONED_DT, "Temporal.ZonedDateTime"), } } @@ -288,6 +300,18 @@ const RAW_STATICS: &[&[u16]] = &[ utf16!("WeakRef"), utf16!("WeakMap"), utf16!("WeakSet"), + utf16!("Temporal"), + utf16!("Temporal.Now"), + utf16!("Temporal.Instant"), + utf16!("Temporal.Duration"), + utf16!("Temporal.Calendar"), + utf16!("Temporal.PlainDate"), + utf16!("Temporal.PlainDateTime"), + utf16!("Temporal.PlainMonthDay"), + utf16!("Temporal.PlainYearMonth"), + utf16!("Temporal.PlainTime"), + utf16!("Temporal.TimeZone"), + utf16!("Temporal.ZonedDateTime"), // Misc utf16!(","), utf16!(":"), diff --git a/boa_parser/src/temporal/mod.rs b/boa_parser/src/temporal/mod.rs index c4dd7845c7a..46d93f0c24b 100644 --- a/boa_parser/src/temporal/mod.rs +++ b/boa_parser/src/temporal/mod.rs @@ -5,12 +5,14 @@ mod annotations; mod date_time; mod duration; mod grammar; -#[cfg(test)] -mod tests; mod time; mod time_zone; -use boa_ast::temporal::{DateRecord, DurationParseRecord, IsoParseRecord, TimeZone}; +use boa_ast::temporal::{DurationParseRecord, ISODate, IsoParseRecord, TimeZone}; + +#[cfg(feature = "experimental")] +#[cfg(test)] +mod tests; // TODO: optimize where possible. // @@ -69,32 +71,33 @@ impl TemporalYearMonthString { /// /// The parse will error if the provided target is not valid /// ISO8601 grammar. - pub fn parse(cursor: &mut IsoCursor) -> ParseResult { + pub fn parse(cursor: &mut IsoCursor) -> ParseResult { if date_time::peek_year_month(cursor)? { let ym = date_time::parse_year_month(cursor)?; - let (tz_annotation, calendar) = if cursor.check_or(false, |ch| ch == '[') { + let calendar = if cursor.check_or(false, |ch| ch == '[') { let set = annotations::parse_annotation_set(false, cursor)?; - (set.tz, set.calendar) + set.calendar } else { - (None, None) + None }; - let tz = tz_annotation.map(|annotation| annotation.tz); - - return Ok(IsoParseRecord { - date: DateRecord { - year: ym.0, - month: ym.1, - day: 0, - }, - time: None, - tz, + return Ok(ISODate { + year: ym.0, + month: ym.1, + day: 0, calendar, }); } - date_time::parse_annotated_date_time(false, false, false, cursor) + let parse_record = date_time::parse_annotated_date_time(false, false, false, cursor)?; + + Ok(ISODate { + year: parse_record.date.year, + month: parse_record.date.month, + day: parse_record.date.day, + calendar: parse_record.calendar, + }) } } @@ -111,32 +114,33 @@ impl TemporalMonthDayString { /// /// The parse will error if the provided target is not valid /// ISO8601 grammar. - pub fn parse(cursor: &mut IsoCursor) -> ParseResult { + pub fn parse(cursor: &mut IsoCursor) -> ParseResult { if date_time::peek_month_day(cursor)? { let md = date_time::parse_month_day(cursor)?; - let (tz_annotation, calendar) = if cursor.check_or(false, |ch| ch == '[') { + let calendar = if cursor.check_or(false, |ch| ch == '[') { let set = annotations::parse_annotation_set(false, cursor)?; - (set.tz, set.calendar) + set.calendar } else { - (None, None) + None }; - let tz = tz_annotation.map(|annotation| annotation.tz); - - return Ok(IsoParseRecord { - date: DateRecord { - year: 0, - month: md.0, - day: md.1, - }, - time: None, - tz, + return Ok(ISODate { + year: 0, + month: md.0, + day: md.1, calendar, }); } - date_time::parse_annotated_date_time(false, false, false, cursor) + let parse_record = date_time::parse_annotated_date_time(false, false, false, cursor)?; + + Ok(ISODate { + year: parse_record.date.year, + month: parse_record.date.month, + day: parse_record.date.day, + calendar: parse_record.calendar, + }) } } diff --git a/boa_parser/src/temporal/tests.rs b/boa_parser/src/temporal/tests.rs index f21db73d846..0660a5cb683 100644 --- a/boa_parser/src/temporal/tests.rs +++ b/boa_parser/src/temporal/tests.rs @@ -96,20 +96,20 @@ fn temporal_annotated_date_time() { fn temporal_year_month() { let possible_year_months = &[ "+002020-11", - "2020-11[+04:00]", + "2020-11[u-ca=iso8601]", "+00202011", - "202011[+04:00]", + "202011[u-ca=iso8601]", ]; for ym in possible_year_months { let result = TemporalYearMonthString::parse(&mut IsoCursor::new(ym)).unwrap(); - assert_eq!(result.date.year, 2020); - assert_eq!(result.date.month, 11); + assert_eq!(result.year, 2020); + assert_eq!(result.month, 11); - let offset = &result.tz.unwrap().offset.unwrap(); - - assert_eq!(offset.hour, 4); + if let Some(calendar) = result.calendar { + assert_eq!(calendar, "iso8601"); + } } } @@ -120,8 +120,8 @@ fn temporal_month_day() { for md in possible_month_day { let result = TemporalMonthDayString::parse(&mut IsoCursor::new(md)).unwrap(); - assert_eq!(result.date.month, 11); - assert_eq!(result.date.day, 7); + assert_eq!(result.month, 11); + assert_eq!(result.day, 7); } } diff --git a/boa_parser/src/temporal/time_zone.rs b/boa_parser/src/temporal/time_zone.rs index 227e80399cd..123784d1a39 100644 --- a/boa_parser/src/temporal/time_zone.rs +++ b/boa_parser/src/temporal/time_zone.rs @@ -16,7 +16,7 @@ use crate::{ }; use boa_ast::{ - temporal::{TimeZone, TimeZoneAnnotation, UtcOffset}, + temporal::{TimeZone, TimeZoneAnnotation, UTCOffset}, Position, }; @@ -209,7 +209,7 @@ pub(crate) fn parse_date_time_utc(cursor: &mut IsoCursor) -> ParseResult ParseResult { +pub(crate) fn parse_utc_offset_minute_precision(cursor: &mut IsoCursor) -> ParseResult { let sign = if let Some(ch) = cursor.next() { if ch == '+' { 1_i8 @@ -226,7 +226,7 @@ pub(crate) fn parse_utc_offset_minute_precision(cursor: &mut IsoCursor) -> Parse .check(|ch| !(ch.is_ascii_digit() || is_time_separator(ch))) .ok_or_else(|| Error::AbruptEnd)? { - return Ok(UtcOffset { + return Ok(UTCOffset { sign, hour, minute: 0, @@ -241,7 +241,7 @@ pub(crate) fn parse_utc_offset_minute_precision(cursor: &mut IsoCursor) -> Parse let minute = parse_minute_second(cursor, false)?; - Ok(UtcOffset { + Ok(UTCOffset { sign, hour, minute,