Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Redesign Intl API and implement some services #2478

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,821 changes: 2,601 additions & 220 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"boa_wasm",
"boa_examples",
"boa_macros",
"boa_icu_provider",
]

[workspace.package]
Expand All @@ -32,6 +33,7 @@ boa_unicode = { version = "0.16.0", path = "boa_unicode" }
boa_macros = { version = "0.16.0", path = "boa_macros" }
boa_ast = { version = "0.16.0", path = "boa_ast" }
boa_parser = { version = "0.16.0", path = "boa_parser" }
boa_icu_provider = { version = "0.16.0", path = "boa_icu_provider" }

[workspace.metadata.workspaces]
allow_branch = "main"
Expand Down
19 changes: 10 additions & 9 deletions boa_ast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Boa's **boa_ast** crate implements an ECMAScript abstract syntax tree.
//! Boa's **`boa_ast`** crate implements an ECMAScript abstract syntax tree.
//!
//! # Crate Overview
//! **boa_ast** contains representations of [**Parse Nodes**][grammar] as defined by the ECMAScript
//! **`boa_ast`** contains representations of [**Parse Nodes**][grammar] as defined by the ECMAScript
//! spec. Some `Parse Node`s are not represented by Boa's AST, because a lot of grammar productions
//! are only used to throw [**Early Errors**][early], and don't influence the evaluation of the AST
//! itself.
Expand All @@ -17,13 +17,14 @@
//! Try out the most recent release with Boa's live demo [playground][boa-playground].
//!
//! # Boa Crates
//! - **boa_ast** - Boa's ECMAScript Abstract Syntax Tree.
//! - **boa_engine** - Boa's implementation of ECMAScript builtin objects and execution.
//! - **boa_gc** - Boa's garbage collector
//! - **boa_interner** - Boa's string interner
//! - **boa_parser** - Boa's lexer and parser
//! - **boa_profiler** - Boa's code profiler
//! - **boa_unicode** - Boa's Unicode identifier
//! - **`boa_ast`** - Boa's ECMAScript Abstract Syntax Tree.
//! - **`boa_engine`** - Boa's implementation of ECMAScript builtin objects and execution.
//! - **`boa_gc`** - Boa's garbage collector.
//! - **`boa_interner`** - Boa's string interner.
//! - **`boa_parser`** - Boa's lexer and parser.
//! - **`boa_profiler`** - Boa's code profiler.
//! - **`boa_unicode`** - Boa's Unicode identifier.
//! - **`boa_icu_provider`** - Boa's ICU4X data provider.
//!
//! [grammar]: https://tc39.es/ecma262/#sec-syntactic-grammar
//! [early]: https://tc39.es/ecma262/#sec-static-semantic-rules
Expand Down
2 changes: 1 addition & 1 deletion boa_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repository.workspace = true
rust-version.workspace = true

[dependencies]
boa_engine = { workspace = true, features = ["deser", "console", "flowgraph"] }
boa_engine = { workspace = true, features = ["deser", "console", "flowgraph", "intl"] }
boa_ast = { workspace = true, features = ["serde"]}
boa_parser.workspace = true
rustyline = "10.0.0"
Expand Down
30 changes: 21 additions & 9 deletions boa_engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ rust-version.workspace = true
profiler = ["boa_profiler/profiler"]
deser = ["boa_interner/serde", "boa_ast/serde"]
intl = [
"dep:icu_locale_canonicalizer",
"dep:boa_icu_provider",
"dep:icu_locid_transform",
"dep:icu_locid",
"dep:icu_datetime",
"dep:icu_plurals",
"dep:icu_provider",
"dep:icu_testdata",
"dep:sys-locale"
"dep:icu_provider_adapters",
"dep:icu_calendar",
"dep:icu_collator",
"dep:icu_list",
"dep:writeable",
"dep:sys-locale",
]

fuzz = ["boa_ast/fuzz", "boa_interner/fuzz"]
Expand Down Expand Up @@ -59,12 +64,19 @@ tap = "1.0.1"
sptr = "0.3.2"
static_assertions = "1.1.0"
thiserror = "1.0.38"
icu_locale_canonicalizer = { version = "0.6.0", features = ["serde"], optional = true }
icu_locid = { version = "0.6.0", features = ["serde"], optional = true }
icu_datetime = { version = "0.6.0", features = ["serde"], optional = true }
icu_plurals = { version = "0.6.0", features = ["serde"], optional = true }
icu_provider = { version = "0.6.0", optional = true }
icu_testdata = { version = "0.6.0", optional = true }

# intl deps
boa_icu_provider = { workspace = true, optional = true }
icu_locid_transform = { version = "1.0.0", features = ["serde"], optional = true }
icu_locid = { version = "1.0.0", features = ["serde"], optional = true }
icu_datetime = { version = "1.0.0", features = ["serde", "experimental"], optional = true }
icu_calendar = { version = "1.0.0", optional = true }
icu_collator = { version = "1.0.1", features = ["serde"], optional = true }
icu_plurals = { version = "1.0.0", features = ["serde"], optional = true }
icu_provider = { version = "1.0.1", optional = true }
icu_provider_adapters = { version = "1.0.0", features = ["serde"], optional = true }
icu_list = { version = "1.0.0", features = ["serde"], optional = true }
writeable = { version = "0.5.0", optional = true }
sys-locale = { version = "0.2.3", optional = true }

[dev-dependencies]
Expand Down
68 changes: 68 additions & 0 deletions boa_engine/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod array_iterator;
#[cfg(test)]
mod tests;

use boa_macros::utf16;
use boa_profiler::Profiler;
use tap::{Conv, Pipe};

Expand Down Expand Up @@ -117,6 +118,7 @@ impl BuiltIn for Array {
.method(Self::some, "some", 1)
.method(Self::sort, "sort", 1)
.method(Self::splice, "splice", 2)
.method(Self::to_locale_string, "toLocaleString", 0)
.method(Self::reduce, "reduce", 1)
.method(Self::reduce_right, "reduceRight", 1)
.method(Self::keys, "keys", 0)
Expand Down Expand Up @@ -2027,6 +2029,72 @@ impl Array {
Ok(a.into())
}

/// [`Array.prototype.toLocaleString ( [ locales [ , options ] ] )`][spec].
///
/// Returns a string representing the elements of the array. The elements are converted to
/// strings using their `toLocaleString` methods and these strings are separated by a
/// locale-specific string (such as a comma ",").
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma402/#sup-array.prototype.tolocalestring
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toLocaleString
pub(crate) fn to_locale_string(
this: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
// 1. Let array be ? ToObject(this value).
let array = this.to_object(context)?;
// 2. Let len be ? ToLength(? Get(array, "length")).
let len = array.length_of_array_like(context)?;

// 3. Let separator be the implementation-defined list-separator String value appropriate for the host environment's current locale (such as ", ").
let separator = {
#[cfg(feature = "intl")]
{
// TODO: this should eventually return a locale-sensitive separator.
utf16!(", ")
}

#[cfg(not(feature = "intl"))]
{
utf16!(", ")
}
};

// 4. Let R be the empty String.
let mut r = Vec::new();

// 5. Let k be 0.
// 6. Repeat, while k < len,
for k in 0..len {
// a. If k > 0, then
if k > 0 {
// i. Set R to the string-concatenation of R and separator.
r.extend_from_slice(separator);
}

// b. Let nextElement be ? Get(array, ! ToString(k)).
let next = array.get(k, context)?;

// c. If nextElement is not undefined or null, then
if !next.is_null_or_undefined() {
// i. Let S be ? ToString(? Invoke(nextElement, "toLocaleString", « locales, options »)).
let s = next
.invoke("toLocaleString", args, context)?
.to_string(context)?;

// ii. Set R to the string-concatenation of R and S.
r.extend_from_slice(&s);
}
// d. Increase k by 1.
}
// 7. Return R.
Ok(js_string!(r).into())
}

/// `Array.prototype.splice ( start, [deleteCount[, ...items]] )`
///
/// Splices an array by following
Expand Down
23 changes: 9 additions & 14 deletions boa_engine/src/builtins/console/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,16 @@ fn logger(msg: LogMessage, console_state: &Console) {

/// This represents the `console` formatter.
pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
let target = data
.get(0)
.cloned()
.unwrap_or_default()
.to_string(context)?;

match data.len() {
0 => Ok(String::new()),
1 => Ok(target.to_std_string_escaped()),
_ => {
match data {
[] => Ok(String::new()),
[val] => Ok(val.to_string(context)?.to_std_string_escaped()),
data => {
let mut formatted = String::new();
let mut arg_index = 1;
let target = target.to_std_string_escaped();
let target = data
.get_or_undefined(0)
.to_string(context)?
.to_std_string_escaped();
let mut chars = target.chars();
while let Some(c) = chars.next() {
if c == '%' {
Expand Down Expand Up @@ -94,9 +91,7 @@ pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
/* string */
's' => {
let arg = data
.get(arg_index)
.cloned()
.unwrap_or_default()
.get_or_undefined(arg_index)
.to_string(context)?
.to_std_string_escaped();
formatted.push_str(&arg);
Expand Down
Loading