diff --git a/boa_ast/src/temporal/mod.rs b/boa_ast/src/temporal/mod.rs index aa4f63b5a57..25e5c976569 100644 --- a/boa_ast/src/temporal/mod.rs +++ b/boa_ast/src/temporal/mod.rs @@ -1,21 +1,6 @@ //! AST nodes for Temporal's implementation of ISO8601 grammar. -/// An `ISOParseRecord` is the full record of a node that is returned via the parse records. -/// -/// This node comes complete with the parsed date, time, time zone, and calendar data. -#[derive(Default, Debug)] -pub struct IsoParseRecord { - /// Parsed Date Record - pub date: DateRecord, - /// Parsed Time - pub time: Option, - /// Parsed `TimeZone` data (UTCOffset | IANA name) - pub tz: Option, - /// The parsed calendar value. - pub calendar: Option, -} - -/// An ISO Date Node consisting of only date fields and any calendar value. +/// An ISO Date Node consisting of non-validated date fields and calendar value. #[derive(Default, Debug)] pub struct ISODate { /// Date Year @@ -28,51 +13,54 @@ pub struct ISODate { pub calendar: Option, } +/// The `ISOTime` node consists of non-validated time fields. #[derive(Default, Debug, Clone, Copy)] -/// The record of a parsed date. -pub struct DateRecord { - /// Date Year - pub year: i32, - /// Date Month - pub month: i32, - /// Date Day - pub day: i32, +pub struct ISOTime { + /// An hour value between 0-23 + pub hour: u8, + /// A minute value between 0-59 + pub minute: u8, + /// A second value between 0-60 + pub second: u8, + /// A millisecond value between 0-999 + pub millisecond: u16, + /// A microsecond value between 0-999 + pub microsecond: u16, + /// A nanosecond value between 0-999 + pub nanosecond: u16, } -/// Parsed Time info -#[derive(Debug, Default, Clone, Copy)] -#[allow(dead_code)] -pub struct TimeSpec { - /// An hour - pub hour: i8, - /// A minute value - pub minute: i8, - /// A floating point second value. - pub second: f64, -} - -/// `TimeZone` UTC Offset info. -#[derive(Debug, Clone, Copy)] -pub struct DateTimeUtcOffset; +impl ISOTime { + #[must_use] + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + /// A utility initialization function to create `ISOTime` from the `TimeSpec` components. + pub fn from_components(hour: u8, minute: u8, second: u8, fraction: f64) -> Self { + // Note: Precision on nanoseconds drifts, so opting for round over floor or ceil for now. + // e.g. 0.329402834 becomes 329.402833.999 + let millisecond = fraction * 1000.0; + let micros = millisecond.rem_euclid(1.0) * 1000.0; + let nanos = micros.rem_euclid(1.0) * 1000.0; -#[derive(Debug, Default, Clone)] -/// A `DateTime` Parse Node that contains the date, time, and offset info. -pub struct DateTimeRecord { - /// Date - pub date: DateRecord, - /// Time - pub time: Option, - /// Tz Offset - pub time_zone: Option, + Self { + hour, + minute, + second, + millisecond: millisecond.floor() as u16, + microsecond: micros.floor() as u16, + nanosecond: nanos.round() as u16, + } + } } -/// A `TimeZoneAnnotation`. -#[derive(Debug, Clone)] -pub struct TimeZoneAnnotation { - /// Critical Flag for the annotation. - pub critical: bool, - /// TimeZone Data - pub tz: TimeZone, +/// The `ISODateTime` node output by the ISO parser +#[derive(Default, Debug)] +pub struct ISODateTime { + /// The `ISODate` record + pub date: ISODate, + /// The `ISOTime` record + pub time: ISOTime, + /// The `TimeZone` value for this `ISODateTime` + pub tz: Option, } /// `TimeZone` data @@ -84,55 +72,24 @@ pub struct TimeZone { pub offset: Option, } -/// A valid `TimeZoneIdentifier` that is defined by -/// the specification as either a UTC Offset to minute -/// precision or a `TimeZoneIANAName` -#[derive(Debug, Clone)] -pub enum TzIdentifier { - /// A valid UTC `TimeZoneIdentifier` value - UtcOffset(UTCOffset), - /// A valid IANA name `TimeZoneIdentifier` value - TzIANAName(String), -} - /// A full precision `UtcOffset` #[derive(Debug, Clone, Copy)] pub struct UTCOffset { /// The `+`/`-` sign of this `UtcOffset` pub sign: i8, /// The hour value of the `UtcOffset` - pub hour: i8, + pub hour: u8, /// The minute value of the `UtcOffset`. - pub minute: i8, - /// A float representing the second value of the `UtcOffset`. - pub second: f64, -} - -/// A `KeyValueAnnotation` Parse Node. -#[derive(Debug, Clone)] -pub struct KeyValueAnnotation { - /// An `Annotation`'s Key. - pub key: String, - /// An `Annotation`'s value. - pub value: String, - /// Whether the annotation was flagged as critical. - pub critical: bool, -} - -/// A ISO8601 `DurationRecord` Parse Node. -#[derive(Debug, Clone, Copy)] -pub struct DurationParseRecord { - /// Duration Sign - pub sign: bool, - /// A `DateDuration` record. - pub date: DateDuration, - /// A `TimeDuration` record. - pub time: TimeDuration, + pub minute: u8, + /// The second value of the `UtcOffset`. + pub second: u8, + /// Any sub second components of the `UTCOffset` + pub fraction: f64, } -/// A `DateDuration` Parse Node. -#[derive(Default, Debug, Clone, Copy)] -pub struct DateDuration { +/// An `ISODuration` Node output by the ISO parser. +#[derive(Debug, Default, Clone, Copy)] +pub struct ISODuration { /// Years value. pub years: i32, /// Months value. @@ -141,15 +98,16 @@ pub struct DateDuration { pub weeks: i32, /// Days value. pub days: i32, -} - -/// A `TimeDuration` Parse Node -#[derive(Default, Debug, Clone, Copy)] -pub struct TimeDuration { - /// Hours value with fraction. - pub hours: f64, - /// Minutes value with fraction. + /// Hours value. + pub hours: i32, + /// Minutes value. pub minutes: f64, - /// Seconds value with fraction. + /// Seconds value. pub seconds: f64, + /// Milliseconds value. + pub milliseconds: f64, + /// Microseconds value. + pub microseconds: f64, + /// Nanoseconds value. + pub nanoseconds: f64, } diff --git a/boa_engine/src/builtins/temporal/duration/mod.rs b/boa_engine/src/builtins/temporal/duration/mod.rs index 4e9f6119e88..3598ceef359 100644 --- a/boa_engine/src/builtins/temporal/duration/mod.rs +++ b/boa_engine/src/builtins/temporal/duration/mod.rs @@ -938,7 +938,7 @@ pub(crate) fn to_temporal_duration(item: &JsValue) -> JsResult { // a. Return item. let obj = o.borrow(); let duration = obj.as_duration().expect("must be a duration."); - return Ok(duration.inner.clone()); + return Ok(duration.inner); } } diff --git a/boa_engine/src/builtins/temporal/plain_date/mod.rs b/boa_engine/src/builtins/temporal/plain_date/mod.rs index e09caf05745..88748716074 100644 --- a/boa_engine/src/builtins/temporal/plain_date/mod.rs +++ b/boa_engine/src/builtins/temporal/plain_date/mod.rs @@ -521,6 +521,7 @@ pub(crate) fn to_temporal_date( // 8. Let calendar be result.[[Calendar]]. // 9. If calendar is undefined, set calendar to "iso8601". let identifier = result + .date .calendar .map_or_else(|| js_string!("iso8601"), JsString::from); diff --git a/boa_parser/src/temporal/annotations.rs b/boa_parser/src/temporal/annotations.rs index c3d88bad931..f9c0ae13ce0 100644 --- a/boa_parser/src/temporal/annotations.rs +++ b/boa_parser/src/temporal/annotations.rs @@ -7,17 +7,27 @@ use crate::{ is_a_key_char, is_a_key_leading_char, is_annotation_close, is_annotation_key_value_separator, is_annotation_value_component, is_critical_flag, }, - time_zone, IsoCursor, + time_zone, + time_zone::TimeZoneAnnotation, + IsoCursor, }, }; -use boa_ast::{ - temporal::{KeyValueAnnotation, TimeZoneAnnotation}, - Position, Span, -}; +use boa_ast::{Position, Span}; use super::grammar::{is_annotation_open, is_hyphen}; +/// A `KeyValueAnnotation` Parse Node. +#[derive(Debug, Clone)] +pub(crate) struct KeyValueAnnotation { + /// An `Annotation`'s Key. + pub(crate) key: String, + /// An `Annotation`'s value. + pub(crate) value: String, + /// Whether the annotation was flagged as critical. + pub(crate) critical: bool, +} + /// Strictly a Parsing Intermediary for the checking the common annotation backing. pub(crate) struct AnnotationSet { pub(crate) tz: Option, diff --git a/boa_parser/src/temporal/date_time.rs b/boa_parser/src/temporal/date_time.rs index aab08b4c234..d64d4ef1e88 100644 --- a/boa_parser/src/temporal/date_time.rs +++ b/boa_parser/src/temporal/date_time.rs @@ -6,17 +6,38 @@ use crate::{ temporal::{ annotations, grammar::{is_date_time_separator, is_sign, is_utc_designator}, - time, time_zone, IsoCursor, + time, + time::TimeSpec, + time_zone, IsoCursor, IsoParseRecord, }, }; -use boa_ast::{ - temporal::{DateRecord, DateTimeRecord, IsoParseRecord, TimeZone}, - Position, Span, -}; +use boa_ast::{temporal::TimeZone, Position, Span}; use super::grammar::{is_annotation_open, is_hyphen}; +#[derive(Debug, Default, Clone)] +/// A `DateTime` Parse Node that contains the date, time, and offset info. +pub(crate) struct DateTimeRecord { + /// Date + pub(crate) date: DateRecord, + /// Time + pub(crate) time: Option, + /// Tz Offset + pub(crate) time_zone: Option, +} + +#[derive(Default, Debug, Clone, Copy)] +/// The record of a parsed date. +pub(crate) struct DateRecord { + /// Date Year + pub(crate) year: i32, + /// Date Month + pub(crate) month: i32, + /// Date Day + pub(crate) day: i32, +} + /// This function handles parsing for [`AnnotatedDateTime`][datetime], /// [`AnnotatedDateTimeTimeRequred`][time], and /// [`TemporalInstantString.`][instant] according to the requirements diff --git a/boa_parser/src/temporal/duration.rs b/boa_parser/src/temporal/duration.rs index 45d1bbae588..e99dd87bc2f 100644 --- a/boa_parser/src/temporal/duration.rs +++ b/boa_parser/src/temporal/duration.rs @@ -1,5 +1,4 @@ use boa_ast::Position; -use core::ops::Add; use crate::{ error::{Error, ParseResult}, @@ -14,7 +13,46 @@ use crate::{ }, }; -use boa_ast::temporal::{DateDuration, DurationParseRecord, TimeDuration}; +/// A ISO8601 `DurationRecord` Parse Node. +#[derive(Debug, Clone, Copy)] +pub(crate) struct DurationParseRecord { + /// Duration Sign + pub(crate) sign: bool, + /// A `DateDuration` record. + pub(crate) date: DateDuration, + /// A `TimeDuration` record. + pub(crate) time: TimeDuration, +} + +/// A `DateDuration` Parse Node. +#[derive(Default, Debug, Clone, Copy)] +pub(crate) struct DateDuration { + /// Years value. + pub(crate) years: i32, + /// Months value. + pub(crate) months: i32, + /// Weeks value. + pub(crate) weeks: i32, + /// Days value. + pub(crate) days: i32, +} + +/// A `TimeDuration` Parse Node +#[derive(Default, Debug, Clone, Copy)] +pub(crate) struct TimeDuration { + /// Hours value. + pub(crate) hours: i32, + /// Hours fraction value. + pub(crate) fhours: f64, + /// Minutes value with fraction. + pub(crate) minutes: i32, + /// Minutes fraction value. + pub(crate) fminutes: f64, + /// Seconds value with fraction. + pub(crate) seconds: i32, + /// Seconds fraction value, + pub(crate) fseconds: f64, +} pub(crate) fn parse_duration(cursor: &mut IsoCursor) -> ParseResult { let sign = if cursor.check(is_sign).ok_or_else(|| Error::AbruptEnd)? { @@ -168,18 +206,19 @@ pub(crate) fn parse_time_duration(cursor: &mut IsoCursor) -> ParseResult() + .parse::() .map_err(|err| { Error::general(err.to_string(), Position::new(digit_start, cursor.pos())) })?; - if cursor.check_or(false, is_decimal_separator) { - let fraction = parse_fraction(cursor)?; - value = value.add(fraction); + let fraction = if cursor.check_or(false, is_decimal_separator) { fraction_present = true; - } + parse_fraction(cursor)? + } else { + 0.0 + }; match cursor.peek() { Some(ch) if is_hour_designator(ch) => { @@ -190,6 +229,7 @@ pub(crate) fn parse_time_duration(cursor: &mut IsoCursor) -> ParseResult { @@ -200,6 +240,7 @@ pub(crate) fn parse_time_duration(cursor: &mut IsoCursor) -> ParseResult { @@ -210,6 +251,7 @@ pub(crate) fn parse_time_duration(cursor: &mut IsoCursor) -> ParseResult return Err(Error::AbruptEnd), diff --git a/boa_parser/src/temporal/mod.rs b/boa_parser/src/temporal/mod.rs index 46d93f0c24b..fdcf7243240 100644 --- a/boa_parser/src/temporal/mod.rs +++ b/boa_parser/src/temporal/mod.rs @@ -1,4 +1,5 @@ //! Implementation of ISO8601 grammar lexing/parsing + use crate::error::ParseResult; mod annotations; @@ -8,18 +9,31 @@ mod grammar; mod time; mod time_zone; -use boa_ast::temporal::{DurationParseRecord, ISODate, IsoParseRecord, TimeZone}; +use boa_ast::temporal::{ISODate, ISODateTime, ISODuration, ISOTime, TimeZone}; + +use date_time::DateRecord; +use time::TimeSpec; #[cfg(feature = "experimental")] #[cfg(test)] mod tests; // TODO: optimize where possible. -// -// NOTE: -// Rough max length source given iso calendar and no extraneous annotations -// is ~100 characters (+10-20 for some calendars): -// +001970-01-01T00:00:00.000000000+00:00:00.000000000[!America/Argentina/ComodRivadavia][!u-ca=iso8601] + +/// An `ISOParseRecord` is an intermediary record returned by ISO parsing functions. +/// +/// `ISOParseRecord` is converted into the ISO AST Nodes. +#[derive(Default, Debug)] +pub(crate) struct IsoParseRecord { + /// Parsed Date Record + pub(crate) date: DateRecord, + /// Parsed Time + pub(crate) time: Option, + /// Parsed `TimeZone` data (UTCOffset | IANA name) + pub(crate) tz: Option, + /// The parsed calendar value. + pub(crate) calendar: Option, +} /// Parse a [`TemporalDateTimeString`][proposal]. /// @@ -34,8 +48,25 @@ impl TemporalDateTimeString { /// /// The parse will error if the provided target is not valid /// ISO8601 grammar. - pub fn parse(zoned: bool, cursor: &mut IsoCursor) -> ParseResult { - date_time::parse_annotated_date_time(zoned, false, false, cursor) + pub fn parse(zoned: bool, cursor: &mut IsoCursor) -> ParseResult { + let parse_record = date_time::parse_annotated_date_time(zoned, false, false, cursor)?; + + let date = ISODate { + year: parse_record.date.year, + month: parse_record.date.month, + day: parse_record.date.day, + calendar: parse_record.calendar, + }; + + let time = parse_record.time.map_or_else(ISOTime::default, |time| { + ISOTime::from_components(time.hour, time.minute, time.second, time.fraction) + }); + + Ok(ISODateTime { + date, + time, + tz: parse_record.tz, + }) } } @@ -45,7 +76,6 @@ impl TemporalDateTimeString { #[derive(Debug, Clone, Copy)] pub struct TemporalTimeZoneString; -// TODO: Return a IsoParseRecord instead of a `TzIdentifier`. impl TemporalTimeZoneString { /// Parses a targeted string as a `TimeZone`. /// @@ -157,8 +187,25 @@ impl TemporalInstantString { /// /// The parse will error if the provided target is not valid /// ISO8601 grammar. - pub fn parse(cursor: &mut IsoCursor) -> ParseResult { - date_time::parse_annotated_date_time(false, true, true, cursor) + pub fn parse(cursor: &mut IsoCursor) -> ParseResult { + let parse_record = date_time::parse_annotated_date_time(false, true, true, cursor)?; + + let date = ISODate { + year: parse_record.date.year, + month: parse_record.date.month, + day: parse_record.date.day, + calendar: parse_record.calendar, + }; + + let time = parse_record.time.map_or_else(ISOTime::default, |time| { + ISOTime::from_components(time.hour, time.minute, time.second, time.fraction) + }); + + Ok(ISODateTime { + date, + time, + tz: parse_record.tz, + }) } } @@ -177,8 +224,46 @@ impl TemporalDurationString { /// /// The parse will error if the provided target is not valid /// ISO8601 grammar. - pub fn parse(cursor: &mut IsoCursor) -> ParseResult { - duration::parse_duration(cursor) + pub fn parse(cursor: &mut IsoCursor) -> ParseResult { + let parse_record = duration::parse_duration(cursor)?; + + let minutes = if parse_record.time.fhours > 0.0 { + parse_record.time.fhours * 60.0 + } else { + f64::from(parse_record.time.minutes) + }; + + let seconds = if parse_record.time.fminutes > 0.0 { + parse_record.time.fminutes * 60.0 + } else if parse_record.time.seconds > 0 { + f64::from(parse_record.time.seconds) + } else { + minutes.rem_euclid(1.0) * 60.0 + }; + + let milliseconds = if parse_record.time.fseconds > 0.0 { + parse_record.time.fseconds * 1000.0 + } else { + seconds.rem_euclid(1.0) * 1000.0 + }; + + let micro = milliseconds.rem_euclid(1.0) * 1000.0; + let nano = micro.rem_euclid(1.0) * 1000.0; + + let sign = if parse_record.sign { 1 } else { -1 }; + + Ok(ISODuration { + years: parse_record.date.years * sign, + months: parse_record.date.months * sign, + weeks: parse_record.date.weeks * sign, + days: parse_record.date.days * sign, + hours: parse_record.time.hours * sign, + minutes: minutes.floor() * f64::from(sign), + seconds: seconds.floor() * f64::from(sign), + milliseconds: milliseconds.floor() * f64::from(sign), + microseconds: micro.floor() * f64::from(sign), + nanoseconds: nano.floor() * f64::from(sign), + }) } } diff --git a/boa_parser/src/temporal/tests.rs b/boa_parser/src/temporal/tests.rs index 64df2754542..20d91e1edae 100644 --- a/boa_parser/src/temporal/tests.rs +++ b/boa_parser/src/temporal/tests.rs @@ -25,18 +25,19 @@ fn temporal_parser_basic() { #[allow(clippy::cast_possible_truncation)] fn temporal_date_time_max() { // Fractions not accurate, but for testing purposes. - let date_time = "+002020-11-08T12:28:32.329402834-03:00:00.123456789[!America/Argentina/ComodRivadavia][!u-ca=iso8601]"; + let date_time = + "+002020-11-08T12:28:32.329402834[!America/Argentina/ComodRivadavia][!u-ca=iso8601]"; let result = TemporalDateTimeString::parse(false, &mut IsoCursor::new(date_time)).unwrap(); - let time_results = &result.time.unwrap(); + let time_results = &result.time; assert_eq!(time_results.hour, 12); assert_eq!(time_results.minute, 28); - assert_eq!( - time_results.second.mul_add(f64::from(100_000), 0.0).trunc() as i64, - 32.329_402_834_f64.mul_add(100_000_f64, 0.0).trunc() as i64 - ); + assert_eq!(time_results.second, 32); + assert_eq!(time_results.millisecond, 329); + assert_eq!(time_results.microsecond, 402); + assert_eq!(time_results.nanosecond, 834); let tz = &result.tz.unwrap(); @@ -47,7 +48,7 @@ fn temporal_date_time_max() { assert_eq!(tz_name, "America/Argentina/ComodRivadavia"); - assert_eq!(&result.calendar, &Some("iso8601".to_string())); + assert_eq!(&result.date.calendar, &Some("iso8601".to_string())); } #[test] @@ -73,16 +74,13 @@ fn temporal_annotated_date_time() { assert_eq!(tz, "America/Argentina/ComodRivadavia"); - assert_eq!(&result.calendar, &Some("iso8601".to_string())); + assert_eq!(&result.date.calendar, &Some("iso8601".to_string())); let omit_result = TemporalDateTimeString::parse(false, &mut IsoCursor::new(omitted)).unwrap(); - println!("omit result is:"); - println!("{omit_result:?\n\n}"); - assert!(&omit_result.tz.is_none()); - assert_eq!(&omit_result.calendar, &Some("iso8601".to_string())); + assert_eq!(&omit_result.date.calendar, &Some("iso8601".to_string())); } #[test] @@ -152,22 +150,28 @@ fn temporal_duration_parsing() { let durations = [ "p1y1m1dt1h1m1s", "P1Y1M1W1DT1H1M1.1S", - "P1Y1M1W1DT1H1M1.123456789S", + "-P1Y1M1W1DT1H1M1.123456789S", "-P1Y3wT0,5H", ]; for dur in durations { - let _ok_result = TemporalDurationString::parse(&mut IsoCursor::new(dur)).unwrap(); - //assert!(ok_result.is_ok()) + let ok_result = TemporalDurationString::parse(&mut IsoCursor::new(dur)); + assert!(ok_result.is_ok()); } + let sub = durations[2]; + let sub_second = TemporalDurationString::parse(&mut IsoCursor::new(sub)).unwrap(); + + assert_eq!(sub_second.milliseconds, -123.0); + assert_eq!(sub_second.microseconds, -456.0); + assert_eq!(sub_second.nanoseconds, -789.0); + let dur = durations[3]; let test_result = TemporalDurationString::parse(&mut IsoCursor::new(dur)).unwrap(); - assert!(!test_result.sign); - assert_eq!(test_result.date.years, 1); - assert_eq!(test_result.date.weeks, 3); - assert_eq!(test_result.time.hours.mul_add(10.0, 0.0).trunc() as i32, 5); + assert_eq!(test_result.years, -1); + assert_eq!(test_result.weeks, -3); + assert_eq!(test_result.minutes, -30.0); } #[test] diff --git a/boa_parser/src/temporal/time.rs b/boa_parser/src/temporal/time.rs index c28e89f5fda..f8b8075f646 100644 --- a/boa_parser/src/temporal/time.rs +++ b/boa_parser/src/temporal/time.rs @@ -9,7 +9,20 @@ use crate::{ lexer::Error as LexError, }; -use boa_ast::{temporal::TimeSpec, Position}; +/// Parsed Time info +#[derive(Debug, Default, Clone, Copy)] +pub(crate) struct TimeSpec { + /// An hour + pub(crate) hour: u8, + /// A minute value + pub(crate) minute: u8, + /// A second value. + pub(crate) second: u8, + /// A floating point number representing the sub-second values + pub(crate) fraction: f64, +} + +use boa_ast::Position; /// Parse `TimeSpec` pub(crate) fn parse_time_spec(cursor: &mut IsoCursor) -> ParseResult { @@ -25,7 +38,8 @@ pub(crate) fn parse_time_spec(cursor: &mut IsoCursor) -> ParseResult { return Ok(TimeSpec { hour, minute: 0, - second: 0.0, + second: 0, + fraction: 0.0, }); } @@ -44,29 +58,31 @@ pub(crate) fn parse_time_spec(cursor: &mut IsoCursor) -> ParseResult { return Ok(TimeSpec { hour, minute, - second: 0.0, + second: 0, + fraction: 0.0, }); } let second = parse_minute_second(cursor, true)?; - let double = if cursor.check_or(false, is_decimal_separator) { - f64::from(second) + parse_fraction(cursor)? + let fraction = if cursor.check_or(false, is_decimal_separator) { + parse_fraction(cursor)? } else { - f64::from(second) + 0.0 }; Ok(TimeSpec { hour, minute, - second: double, + second, + fraction, }) } -pub(crate) fn parse_hour(cursor: &mut IsoCursor) -> ParseResult { +pub(crate) fn parse_hour(cursor: &mut IsoCursor) -> ParseResult { let hour_value = cursor .slice(cursor.pos(), cursor.pos() + 2) - .parse::() + .parse::() .map_err(|e| Error::general(e.to_string(), Position::new(1, cursor.pos())))?; if !(0..=23).contains(&hour_value) { return Err(LexError::syntax( @@ -81,10 +97,10 @@ pub(crate) fn parse_hour(cursor: &mut IsoCursor) -> ParseResult { // NOTE: `TimeSecond` is a 60 inclusive `MinuteSecond`. /// Parse `MinuteSecond` -pub(crate) fn parse_minute_second(cursor: &mut IsoCursor, inclusive: bool) -> ParseResult { +pub(crate) fn parse_minute_second(cursor: &mut IsoCursor, inclusive: bool) -> ParseResult { let min_sec_value = cursor .slice(cursor.pos(), cursor.pos() + 2) - .parse::() + .parse::() .map_err(|e| Error::general(e.to_string(), Position::new(1, cursor.pos())))?; let valid_range = if inclusive { 0..=60 } else { 0..=59 }; diff --git a/boa_parser/src/temporal/time_zone.rs b/boa_parser/src/temporal/time_zone.rs index 123784d1a39..1905eb1f10f 100644 --- a/boa_parser/src/temporal/time_zone.rs +++ b/boa_parser/src/temporal/time_zone.rs @@ -16,10 +16,20 @@ use crate::{ }; use boa_ast::{ - temporal::{TimeZone, TimeZoneAnnotation, UTCOffset}, + temporal::{TimeZone, UTCOffset}, Position, }; +/// A `TimeZoneAnnotation`. +#[derive(Debug, Clone)] +#[allow(unused)] +pub(crate) struct TimeZoneAnnotation { + /// Critical Flag for the annotation. + pub(crate) critical: bool, + /// TimeZone Data + pub(crate) tz: TimeZone, +} + // ==== Time Zone Annotation Parsing ==== pub(crate) fn parse_ambiguous_tz_annotation( @@ -193,15 +203,16 @@ pub(crate) fn parse_date_time_utc(cursor: &mut IsoCursor) -> ParseResult Parse sign, hour, minute: 0, - second: 0.0, + second: 0, + fraction: 0.0, }); } @@ -245,6 +257,7 @@ pub(crate) fn parse_utc_offset_minute_precision(cursor: &mut IsoCursor) -> Parse sign, hour, minute, - second: 0.0, + second: 0, + fraction: 0.0, }) }