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

Implement latin1 encoded JsStrings #3450

Merged
merged 1 commit into from
May 1, 2024
Merged
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
9 changes: 4 additions & 5 deletions cli/src/debug/function.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use boa_engine::{
builtins::function::OrdinaryFunction,
js_string,
js_str, js_string,
object::ObjectInitializer,
vm::flowgraph::{Direction, Graph},
Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction,
Expand Down Expand Up @@ -68,10 +68,9 @@ fn flowgraph(_this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResu
let mut direction = Direction::LeftToRight;
if let Some(arguments) = args.get(1) {
if let Some(arguments) = arguments.as_object() {
format = flowgraph_parse_format_option(&arguments.get(js_string!("format"), context)?)?;
direction = flowgraph_parse_direction_option(
&arguments.get(js_string!("direction"), context)?,
)?;
format = flowgraph_parse_format_option(&arguments.get(js_str!("format"), context)?)?;
direction =
flowgraph_parse_direction_option(&arguments.get(js_str!("direction"), context)?)?;
} else if value.is_string() {
format = flowgraph_parse_format_option(value)?;
} else {
Expand Down
20 changes: 10 additions & 10 deletions cli/src/debug/limits.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use boa_engine::{
js_string,
js_str,
object::{FunctionObjectBuilder, ObjectInitializer},
property::Attribute,
Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction,
Expand Down Expand Up @@ -51,51 +51,51 @@ fn set_recursion(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResu
pub(super) fn create_object(context: &mut Context) -> JsObject {
let get_loop =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_loop))
.name("get loop")
.name(js_str!("get loop"))
.length(0)
.build();
let set_loop =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_loop))
.name("set loop")
.name(js_str!("set loop"))
.length(1)
.build();

let get_stack =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_stack))
.name("get stack")
.name(js_str!("get stack"))
.length(0)
.build();
let set_stack =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_stack))
.name("set stack")
.name(js_str!("set stack"))
.length(1)
.build();

let get_recursion =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_recursion))
.name("get recursion")
.name(js_str!("get recursion"))
.length(0)
.build();
let set_recursion =
FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_recursion))
.name("set recursion")
.name(js_str!("set recursion"))
.length(1)
.build();
ObjectInitializer::new(context)
.accessor(
js_string!("loop"),
js_str!("loop"),
Some(get_loop),
Some(set_loop),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.accessor(
js_string!("stack"),
js_str!("stack"),
Some(get_stack),
Some(set_stack),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.accessor(
js_string!("recursion"),
js_str!("recursion"),
Some(get_recursion),
Some(set_recursion),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
Expand Down
25 changes: 16 additions & 9 deletions cli/src/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Allow lint so it, doesn't warn about `JsResult<>` unneeded return on functions.
#![allow(clippy::unnecessary_wraps)]

use boa_engine::{js_string, object::ObjectInitializer, property::Attribute, Context, JsObject};
use boa_engine::{js_str, object::ObjectInitializer, property::Attribute, Context, JsObject};

mod function;
mod gc;
Expand All @@ -10,6 +10,7 @@ mod object;
mod optimizer;
mod realm;
mod shape;
mod string;

fn create_boa_object(context: &mut Context) -> JsObject {
let function_module = function::create_object(context);
Expand All @@ -19,43 +20,49 @@ fn create_boa_object(context: &mut Context) -> JsObject {
let gc_module = gc::create_object(context);
let realm_module = realm::create_object(context);
let limits_module = limits::create_object(context);
let string_module = string::create_string(context);

ObjectInitializer::new(context)
.property(
js_string!("function"),
js_str!("function"),
function_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
js_string!("object"),
js_str!("object"),
object_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
js_string!("shape"),
js_str!("shape"),
shape_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
js_string!("optimizer"),
js_str!("optimizer"),
optimizer_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
js_string!("gc"),
js_str!("gc"),
gc_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
js_string!("realm"),
js_str!("realm"),
realm_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
js_string!("limits"),
js_str!("limits"),
limits_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
js_str!("string"),
string_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build()
}

Expand All @@ -64,7 +71,7 @@ pub(crate) fn init_boa_debug_object(context: &mut Context) {
let boa_object = create_boa_object(context);
context
.register_global_property(
js_string!("$boa"),
js_str!("$boa"),
boa_object,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
Expand Down
6 changes: 3 additions & 3 deletions cli/src/debug/optimizer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use boa_engine::{
js_string,
js_str,
object::{FunctionObjectBuilder, ObjectInitializer},
optimizer::OptimizerOptions,
property::Attribute,
Expand Down Expand Up @@ -64,13 +64,13 @@ pub(super) fn create_object(context: &mut Context) -> JsObject {
.build();
ObjectInitializer::new(context)
.accessor(
js_string!("constantFolding"),
js_str!("constantFolding"),
Some(get_constant_folding),
Some(set_constant_folding),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
)
.accessor(
js_string!("statistics"),
js_str!("statistics"),
Some(get_statistics),
Some(set_statistics),
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
Expand Down
93 changes: 93 additions & 0 deletions cli/src/debug/string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use boa_engine::{
js_string, object::ObjectInitializer, property::Attribute, string::JsStrVariant, Context,
JsNativeError, JsObject, JsResult, JsValue, NativeFunction,
};

fn storage(_: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
let Some(value) = args.first() else {
return Err(JsNativeError::typ()
.with_message("expected string argument")
.into());
};

let Some(string) = value.as_string() else {
return Err(JsNativeError::typ()
.with_message(format!("expected string, got {}", value.type_of()))
.into());
};

let storage = if string.is_static() { "static" } else { "heap" };
Ok(js_string!(storage).into())
}

fn encoding(_: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
let Some(value) = args.first() else {
return Err(JsNativeError::typ()
.with_message("expected string argument")
.into());
};

let Some(string) = value.as_string() else {
return Err(JsNativeError::typ()
.with_message(format!("expected string, got {}", value.type_of()))
.into());
};

let str = string.as_str();
let encoding = match str.variant() {
JsStrVariant::Latin1(_) => "latin1",
JsStrVariant::Utf16(_) => "utf16",
};
Ok(js_string!(encoding).into())
}

fn summary(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let Some(value) = args.first() else {
return Err(JsNativeError::typ()
.with_message("expected string argument")
.into());
};

let Some(string) = value.as_string() else {
return Err(JsNativeError::typ()
.with_message(format!("expected string, got {}", value.type_of()))
.into());
};

let storage = if string.is_static() { "static" } else { "heap" };
let encoding = match string.as_str().variant() {
JsStrVariant::Latin1(_) => "latin1",
JsStrVariant::Utf16(_) => "utf16",
};

let summary = ObjectInitializer::new(context)
.property(js_string!("storage"), js_string!(storage), Attribute::all())
.property(
js_string!("encoding"),
js_string!(encoding),
Attribute::all(),
)
.build();

Ok(summary.into())
}

pub(super) fn create_string(context: &mut Context) -> JsObject {
ObjectInitializer::new(context)
.function(
NativeFunction::from_fn_ptr(storage),
js_string!("storage"),
1,
)
.function(
NativeFunction::from_fn_ptr(encoding),
js_string!("encoding"),
1,
)
.function(
NativeFunction::from_fn_ptr(summary),
js_string!("summary"),
1,
)
.build()
}
18 changes: 17 additions & 1 deletion core/engine/src/bigint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Boa's implementation of ECMAScript's bigint primitive type.

use crate::{builtins::Number, error::JsNativeError, JsData, JsResult};
use crate::{builtins::Number, error::JsNativeError, JsData, JsResult, JsString};
use boa_gc::{Finalize, Trace};
use num_integer::Integer;
use num_traits::{pow::Pow, FromPrimitive, One, ToPrimitive, Zero};
Expand Down Expand Up @@ -89,6 +89,22 @@ impl JsBigInt {
})
}

/// Abstract operation `StringToBigInt ( str )`
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-stringtobigint
pub(crate) fn from_js_string(string: &JsString) -> Option<JsBigInt> {
// 1. Let text be ! StringToCodePoints(str).
// 2. Let literal be ParseText(text, StringIntegerLiteral).
// 3. If literal is a List of errors, return undefined.
// 4. Let mv be the MV of literal.
// 5. Assert: mv is an integer.
// 6. Return ℤ(mv).
JsBigInt::from_string(string.to_std_string().ok().as_ref()?)
}

/// This function takes a string and converts it to `BigInt` type.
///
/// More information:
Expand Down
3 changes: 2 additions & 1 deletion core/engine/src/builtins/array/array_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
Context, JsData, JsResult,
};
use boa_gc::{Finalize, Trace};
use boa_macros::js_str;
use boa_profiler::Profiler;

/// The Array Iterator object represents an iteration over an array. It implements the iterator protocol.
Expand Down Expand Up @@ -52,7 +53,7 @@ impl IntrinsicObject for ArrayIterator {
.static_method(Self::next, js_string!("next"), 0)
.static_property(
JsSymbol::to_string_tag(),
js_string!("Array Iterator"),
js_str!("Array Iterator"),
Attribute::CONFIGURABLE,
)
.build();
Expand Down
Loading
Loading