diff --git a/boa_cli/src/debug/mod.rs b/boa_cli/src/debug/mod.rs index 72a24a2d15..c02b24e1e8 100644 --- a/boa_cli/src/debug/mod.rs +++ b/boa_cli/src/debug/mod.rs @@ -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); @@ -19,6 +20,7 @@ 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( @@ -56,6 +58,11 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject { limits_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) + .property( + "string", + string_module, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + ) .build() } diff --git a/boa_cli/src/debug/string.rs b/boa_cli/src/debug/string.rs new file mode 100644 index 0000000000..5b61ba6b8d --- /dev/null +++ b/boa_cli/src/debug/string.rs @@ -0,0 +1,77 @@ +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 { + let Some(value) = args.get(0) 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 { + let Some(value) = args.get(0) 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::Ascii(_) => "ascii", + JsStrVariant::U16(_) => "U16", + }; + Ok(js_string!(encoding).into()) +} + +fn summary(_: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> JsResult { + let Some(value) = args.get(0) 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::Ascii(_) => "ascii", + JsStrVariant::U16(_) => "U16", + }; + + let summary = ObjectInitializer::new(context) + .property("storage", js_string!(storage), Attribute::all()) + .property("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), "storage", 1) + .function(NativeFunction::from_fn_ptr(encoding), "encoding", 1) + .function(NativeFunction::from_fn_ptr(summary), "summary", 1) + .build() +} diff --git a/boa_engine/src/string/mod.rs b/boa_engine/src/string/mod.rs index d45510d27b..e621642710 100644 --- a/boa_engine/src/string/mod.rs +++ b/boa_engine/src/string/mod.rs @@ -920,6 +920,10 @@ impl JsString { pub(crate) fn trim_end(&self) -> JsStr<'_> { self.as_str().trim_end() } + + pub fn is_static(&self) -> bool { + self.ptr.is_tagged() + } } impl Clone for JsString { diff --git a/docs/boa_object.md b/docs/boa_object.md index 64bc38a687..2c44197975 100644 --- a/docs/boa_object.md +++ b/docs/boa_object.md @@ -286,3 +286,34 @@ function x() { } x(); // RuntimeLimit: Maximum recursion limit 100 exceeded ``` + +## Module `$boa.string` + +This module contains helpful functions for getting information about a strings. + +### Function `$boa.string.storage(str)` + +Returns the string's inner storage type, if it's a well known string that is stored in the `STATIC_STRINGS` array in boa, +then `"static"` is returned, `"heap"` otherwise. + +```JavaScript +$boa.string.storage("push") // "static" +$boa.string.storage("specialFunction") // "heap" +``` + +### Function `$boa.string.encoding(str)` + +Returns the string's inner encoding of the string. + +```JavaScript +$boa.string.encoding("Greeting") // "ascii" +$boa.string.encoding("挨拶") // "U16" +``` + +### Function `$boa.string.summary(str)` + +Returns an object with a short summary of the of the given string. + +```JavaScript +$boa.string.summary("Greeting") // { storage: "heap", encoding: "ascii" } +```