Skip to content

Commit

Permalink
Partial implementation for Intl.DateTimeFormat (#2025)
Browse files Browse the repository at this point in the history
<!---
Thank you for contributing to Boa! Please fill out the template below, and remove or add any
information as you feel neccesary.
--->

This Pull Request provides initial implementation for DateTimeFormat constructor. It relates to #1562.

It changes the following:

- Adds `Intl.DateTimeFormat` property
- Partially implements `DateTimeFormat` constructor (`InitializeDateTimeFormat` step is postponed).
- Introduces `ObjectData::DateTimeFormat`
  • Loading branch information
Razican committed Jun 8, 2022
1 parent 887d345 commit fa2e4b6
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 0 deletions.
114 changes: 114 additions & 0 deletions boa_engine/src/builtins/intl/date_time_format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//! This module implements the global `Intl.DateTimeFormat` object.
//!
//! `Intl.DateTimeFormat` is a built-in object that has properties and methods for date and time i18n.
//!
//! More information:
//! - [ECMAScript reference][spec]
//!
//! [spec]: https://tc39.es/ecma402/#datetimeformat-objects

use crate::{
context::intrinsics::StandardConstructors,
object::internal_methods::get_prototype_from_constructor,
object::{ConstructorBuilder, JsObject, ObjectData},
Context, JsResult, JsString, JsValue,
};

use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;

/// JavaScript `Intl.DateTimeFormat` object.
#[derive(Debug, Clone, Trace, Finalize)]
pub struct DateTimeFormat {
initialized_date_time_format: bool,
locale: JsString,
calendar: JsString,
numbering_system: JsString,
time_zone: JsString,
weekday: JsString,
era: JsString,
year: JsString,
month: JsString,
day: JsString,
day_period: JsString,
hour: JsString,
minute: JsString,
second: JsString,
fractional_second_digits: JsString,
time_zone_name: JsString,
hour_cycle: JsString,
pattern: JsString,
bound_format: JsString,
}

impl DateTimeFormat {
const NAME: &'static str = "DateTimeFormat";

pub(super) fn init(context: &mut Context) -> JsObject {
let _timer = Profiler::global().start_event(Self::NAME, "init");

ConstructorBuilder::new(context, Self::constructor)
.name(Self::NAME)
.length(0)
.build()
}
}

impl DateTimeFormat {
/// The `Intl.DateTimeFormat` constructor is the `%DateTimeFormat%` intrinsic object and a standard built-in property of the `Intl` object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma402/#datetimeformat-objects
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
pub(crate) fn constructor(
new_target: &JsValue,
_args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
// 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
let prototype = get_prototype_from_constructor(
new_target,
StandardConstructors::date_time_format,
context,
)?;
// 2. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%DateTimeFormat.prototype%",
// « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], [[Weekday]],
// [[Era]], [[Year]], [[Month]], [[Day]], [[DayPeriod]], [[Hour]], [[Minute]], [[Second]],
// [[FractionalSecondDigits]], [[TimeZoneName]], [[HourCycle]], [[Pattern]], [[BoundFormat]] »).
let date_time_format = JsObject::from_proto_and_data(
prototype,
ObjectData::date_time_format(Box::new(Self {
initialized_date_time_format: true,
locale: JsString::from("en-US"),
calendar: JsString::from("gregory"),
numbering_system: JsString::from("arab"),
time_zone: JsString::from("UTC"),
weekday: JsString::from("narrow"),
era: JsString::from("narrow"),
year: JsString::from("numeric"),
month: JsString::from("narrow"),
day: JsString::from("numeric"),
day_period: JsString::from("narrow"),
hour: JsString::from("numeric"),
minute: JsString::from("numeric"),
second: JsString::from("numeric"),
fractional_second_digits: JsString::from(""),
time_zone_name: JsString::from(""),
hour_cycle: JsString::from("h24"),
pattern: JsString::from("{hour}:{minute}"),
bound_format: JsString::from("undefined"),
})),
);

// TODO 3. Perform ? InitializeDateTimeFormat(dateTimeFormat, locales, options).
// TODO 4. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then
// TODO a. Let this be the this value.
// TODO b. Return ? ChainDateTimeFormat(dateTimeFormat, NewTarget, this).

// 5. Return dateTimeFormat.
Ok(JsValue::Object(date_time_format))
}
}
10 changes: 10 additions & 0 deletions boa_engine/src/builtins/intl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
//! [spec]: https://tc39.es/ecma402/#intl-object

use crate::{
builtins::intl::date_time_format::DateTimeFormat,
builtins::{Array, BuiltIn, JsArgs},
object::ObjectInitializer,
property::Attribute,
symbol::WellKnownSymbols,
Context, JsResult, JsString, JsValue,
};

pub mod date_time_format;

use boa_profiler::Profiler;
use indexmap::IndexSet;
use tap::{Conv, Pipe};
Expand All @@ -29,13 +33,19 @@ impl BuiltIn for Intl {
let _timer = Profiler::global().start_event(Self::NAME, "init");

let string_tag = WellKnownSymbols::to_string_tag();
let date_time_format = DateTimeFormat::init(context);
ObjectInitializer::new(context)
.function(Self::get_canonical_locales, "getCanonicalLocales", 1)
.property(
string_tag,
Self::NAME,
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
"DateTimeFormat",
date_time_format,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build()
.conv::<JsValue>()
.pipe(Some)
Expand Down
7 changes: 7 additions & 0 deletions boa_engine/src/context/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ pub struct StandardConstructors {
array_buffer: StandardConstructor,
data_view: StandardConstructor,
promise: StandardConstructor,
date_time_format: StandardConstructor,
}

impl Default for StandardConstructors {
Expand Down Expand Up @@ -163,6 +164,7 @@ impl Default for StandardConstructors {
array_buffer: StandardConstructor::default(),
data_view: StandardConstructor::default(),
promise: StandardConstructor::default(),
date_time_format: StandardConstructor::default(),
};

// The value of `Array.prototype` is the Array prototype object.
Expand Down Expand Up @@ -365,6 +367,11 @@ impl StandardConstructors {
pub fn promise(&self) -> &StandardConstructor {
&self.promise
}

#[inline]
pub fn date_time_format(&self) -> &StandardConstructor {
&self.date_time_format
}
}

/// Cached intrinsic objects
Expand Down
11 changes: 11 additions & 0 deletions boa_engine/src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::{
arguments::ParameterMap, BoundFunction, Captures, Function, NativeFunctionSignature,
},
generator::Generator,
intl::date_time_format::DateTimeFormat,
map::map_iterator::MapIterator,
map::ordered_map::OrderedMap,
object::for_in_iterator::ForInIterator,
Expand Down Expand Up @@ -164,6 +165,7 @@ pub enum ObjectKind {
NativeObject(Box<dyn NativeObject>),
IntegerIndexed(IntegerIndexed),
Promise(Promise),
DateTimeFormat(Box<DateTimeFormat>),
}

impl ObjectData {
Expand Down Expand Up @@ -428,6 +430,14 @@ impl ObjectData {
internal_methods: &INTEGER_INDEXED_EXOTIC_INTERNAL_METHODS,
}
}

/// Create the `DateTimeFormat` object data
pub fn date_time_format(date_time_fmt: Box<DateTimeFormat>) -> Self {
Self {
kind: ObjectKind::DateTimeFormat(date_time_fmt),
internal_methods: &ORDINARY_INTERNAL_METHODS,
}
}
}

impl Display for ObjectKind {
Expand Down Expand Up @@ -463,6 +473,7 @@ impl Display for ObjectKind {
Self::IntegerIndexed(_) => "TypedArray",
Self::DataView(_) => "DataView",
Self::Promise(_) => "Promise",
Self::DateTimeFormat(_) => "DateTimeFormat",
})
}
}
Expand Down

0 comments on commit fa2e4b6

Please sign in to comment.