mirror of
https://github.com/RGBCube/serenity
synced 2025-06-18 23:02:08 +00:00
LibJS: Add and begin using a completion-compatible string builder
ThrowableStringBuilder is a thin wrapper around StringBuilder to map results from the try_* methods to a throw completion. This will let us try to throw on OOM conditions rather than just blowing up.
This commit is contained in:
parent
fab8ef3dfc
commit
76b9d06b19
4 changed files with 107 additions and 30 deletions
|
@ -231,6 +231,7 @@ set(SOURCES
|
||||||
Runtime/Temporal/ZonedDateTime.cpp
|
Runtime/Temporal/ZonedDateTime.cpp
|
||||||
Runtime/Temporal/ZonedDateTimeConstructor.cpp
|
Runtime/Temporal/ZonedDateTimeConstructor.cpp
|
||||||
Runtime/Temporal/ZonedDateTimePrototype.cpp
|
Runtime/Temporal/ZonedDateTimePrototype.cpp
|
||||||
|
Runtime/ThrowableStringBuilder.cpp
|
||||||
Runtime/TypedArray.cpp
|
Runtime/TypedArray.cpp
|
||||||
Runtime/TypedArrayConstructor.cpp
|
Runtime/TypedArrayConstructor.cpp
|
||||||
Runtime/TypedArrayPrototype.cpp
|
Runtime/TypedArrayPrototype.cpp
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include <AK/Checked.h>
|
#include <AK/Checked.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/StringBuilder.h>
|
|
||||||
#include <AK/Utf16View.h>
|
#include <AK/Utf16View.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
#include <LibJS/Heap/Heap.h>
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
|
@ -24,6 +23,7 @@
|
||||||
#include <LibJS/Runtime/StringIterator.h>
|
#include <LibJS/Runtime/StringIterator.h>
|
||||||
#include <LibJS/Runtime/StringObject.h>
|
#include <LibJS/Runtime/StringObject.h>
|
||||||
#include <LibJS/Runtime/StringPrototype.h>
|
#include <LibJS/Runtime/StringPrototype.h>
|
||||||
|
#include <LibJS/Runtime/ThrowableStringBuilder.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
#include <LibJS/Runtime/Utf16String.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
#include <LibLocale/Locale.h>
|
#include <LibLocale/Locale.h>
|
||||||
|
@ -528,11 +528,11 @@ static ThrowCompletionOr<Value> pad_string(VM& vm, Utf16String string, PadPlacem
|
||||||
auto fill_code_units = fill_string.length_in_code_units();
|
auto fill_code_units = fill_string.length_in_code_units();
|
||||||
auto fill_length = max_length - string_length;
|
auto fill_length = max_length - string_length;
|
||||||
|
|
||||||
StringBuilder filler_builder;
|
ThrowableStringBuilder filler_builder(vm);
|
||||||
for (size_t i = 0; i < fill_length / fill_code_units; ++i)
|
for (size_t i = 0; i < fill_length / fill_code_units; ++i)
|
||||||
filler_builder.append(fill_string.view());
|
TRY(filler_builder.append(fill_string.view()));
|
||||||
|
|
||||||
filler_builder.append(fill_string.substring_view(0, fill_length % fill_code_units));
|
TRY(filler_builder.append(fill_string.substring_view(0, fill_length % fill_code_units)));
|
||||||
auto filler = filler_builder.build();
|
auto filler = filler_builder.build();
|
||||||
|
|
||||||
auto formatted = placement == PadPlacement::Start
|
auto formatted = placement == PadPlacement::Start
|
||||||
|
@ -575,9 +575,9 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat)
|
||||||
if (string.is_empty())
|
if (string.is_empty())
|
||||||
return PrimitiveString::create(vm, DeprecatedString::empty());
|
return PrimitiveString::create(vm, DeprecatedString::empty());
|
||||||
|
|
||||||
StringBuilder builder;
|
ThrowableStringBuilder builder(vm);
|
||||||
for (size_t i = 0; i < n; ++i)
|
for (size_t i = 0; i < n; ++i)
|
||||||
builder.append(string);
|
TRY(builder.append(string));
|
||||||
return PrimitiveString::create(vm, builder.to_deprecated_string());
|
return PrimitiveString::create(vm, builder.to_deprecated_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,10 +615,10 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace)
|
||||||
replacement = TRY(get_substitution(vm, search_string.view(), string.view(), *position, {}, js_undefined(), replace_value));
|
replacement = TRY(get_substitution(vm, search_string.view(), string.view(), *position, {}, js_undefined(), replace_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder builder;
|
ThrowableStringBuilder builder(vm);
|
||||||
builder.append(preserved);
|
TRY(builder.append(preserved));
|
||||||
builder.append(replacement);
|
TRY(builder.append(replacement));
|
||||||
builder.append(string.substring_view(*position + search_string.length_in_code_units()));
|
TRY(builder.append(string.substring_view(*position + search_string.length_in_code_units())));
|
||||||
|
|
||||||
return PrimitiveString::create(vm, builder.build());
|
return PrimitiveString::create(vm, builder.build());
|
||||||
}
|
}
|
||||||
|
@ -667,7 +667,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace_all)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t end_of_last_match = 0;
|
size_t end_of_last_match = 0;
|
||||||
StringBuilder result;
|
ThrowableStringBuilder result(vm);
|
||||||
|
|
||||||
for (auto position : match_positions) {
|
for (auto position : match_positions) {
|
||||||
auto preserved = string.substring_view(end_of_last_match, position - end_of_last_match);
|
auto preserved = string.substring_view(end_of_last_match, position - end_of_last_match);
|
||||||
|
@ -680,14 +680,14 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace_all)
|
||||||
replacement = TRY(get_substitution(vm, search_string.view(), string.view(), position, {}, js_undefined(), replace_value));
|
replacement = TRY(get_substitution(vm, search_string.view(), string.view(), position, {}, js_undefined(), replace_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append(preserved);
|
TRY(result.append(preserved));
|
||||||
result.append(replacement);
|
TRY(result.append(replacement));
|
||||||
|
|
||||||
end_of_last_match = position + search_length;
|
end_of_last_match = position + search_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_of_last_match < string_length)
|
if (end_of_last_match < string_length)
|
||||||
result.append(string.substring_view(end_of_last_match));
|
TRY(result.append(string.substring_view(end_of_last_match)));
|
||||||
|
|
||||||
return PrimitiveString::create(vm, result.build());
|
return PrimitiveString::create(vm, result.build());
|
||||||
}
|
}
|
||||||
|
@ -995,7 +995,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_well_formed)
|
||||||
size_t k = 0;
|
size_t k = 0;
|
||||||
|
|
||||||
// 5. Let result be the empty String.
|
// 5. Let result be the empty String.
|
||||||
StringBuilder result;
|
ThrowableStringBuilder result(vm);
|
||||||
|
|
||||||
// 6. Repeat, while k < strLen,
|
// 6. Repeat, while k < strLen,
|
||||||
while (k < length) {
|
while (k < length) {
|
||||||
|
@ -1005,12 +1005,12 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_well_formed)
|
||||||
// b. If cp.[[IsUnpairedSurrogate]] is true, then
|
// b. If cp.[[IsUnpairedSurrogate]] is true, then
|
||||||
if (code_point.is_unpaired_surrogate) {
|
if (code_point.is_unpaired_surrogate) {
|
||||||
// i. Set result to the string-concatenation of result and 0xFFFD (REPLACEMENT CHARACTER).
|
// i. Set result to the string-concatenation of result and 0xFFFD (REPLACEMENT CHARACTER).
|
||||||
result.append_code_point(0xfffd);
|
TRY(result.append_code_point(0xfffd));
|
||||||
}
|
}
|
||||||
// c. Else,
|
// c. Else,
|
||||||
else {
|
else {
|
||||||
// i. Set result to the string-concatenation of result and UTF16EncodeCodePoint(cp.[[CodePoint]]).
|
// i. Set result to the string-concatenation of result and UTF16EncodeCodePoint(cp.[[CodePoint]]).
|
||||||
result.append_code_point(code_point.code_point);
|
TRY(result.append_code_point(code_point.code_point));
|
||||||
}
|
}
|
||||||
|
|
||||||
// d. Set k to k + cp.[[CodeUnitCount]].
|
// d. Set k to k + cp.[[CodeUnitCount]].
|
||||||
|
@ -1119,22 +1119,22 @@ static ThrowCompletionOr<Value> create_html(VM& vm, Value string, DeprecatedStri
|
||||||
{
|
{
|
||||||
TRY(require_object_coercible(vm, string));
|
TRY(require_object_coercible(vm, string));
|
||||||
auto str = TRY(string.to_string(vm));
|
auto str = TRY(string.to_string(vm));
|
||||||
StringBuilder builder;
|
ThrowableStringBuilder builder(vm);
|
||||||
builder.append('<');
|
TRY(builder.append('<'));
|
||||||
builder.append(tag);
|
TRY(builder.append(tag));
|
||||||
if (!attribute.is_empty()) {
|
if (!attribute.is_empty()) {
|
||||||
auto value_string = TRY(value.to_string(vm));
|
auto value_string = TRY(value.to_string(vm));
|
||||||
builder.append(' ');
|
TRY(builder.append(' '));
|
||||||
builder.append(attribute);
|
TRY(builder.append(attribute));
|
||||||
builder.append("=\""sv);
|
TRY(builder.append("=\""sv));
|
||||||
builder.append(value_string.replace("\""sv, """sv, ReplaceMode::All));
|
TRY(builder.append(value_string.replace("\""sv, """sv, ReplaceMode::All)));
|
||||||
builder.append('"');
|
TRY(builder.append('"'));
|
||||||
}
|
}
|
||||||
builder.append('>');
|
TRY(builder.append('>'));
|
||||||
builder.append(str);
|
TRY(builder.append(str));
|
||||||
builder.append("</"sv);
|
TRY(builder.append("</"sv));
|
||||||
builder.append(tag);
|
TRY(builder.append(tag));
|
||||||
builder.append('>');
|
TRY(builder.append('>'));
|
||||||
return PrimitiveString::create(vm, builder.build());
|
return PrimitiveString::create(vm, builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
Userland/Libraries/LibJS/Runtime/ThrowableStringBuilder.cpp
Normal file
45
Userland/Libraries/LibJS/Runtime/ThrowableStringBuilder.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/Utf16View.h>
|
||||||
|
#include <LibJS/Runtime/ThrowableStringBuilder.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
ThrowableStringBuilder::ThrowableStringBuilder(VM& vm)
|
||||||
|
: m_vm(vm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> ThrowableStringBuilder::append(char ch)
|
||||||
|
{
|
||||||
|
if (try_append(ch).is_error())
|
||||||
|
return m_vm.throw_completion<InternalError>(ErrorType::NotEnoughMemoryToAllocate, length() + 1);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> ThrowableStringBuilder::append(StringView string)
|
||||||
|
{
|
||||||
|
if (try_append(string).is_error())
|
||||||
|
return m_vm.throw_completion<InternalError>(ErrorType::NotEnoughMemoryToAllocate, length() + string.length());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> ThrowableStringBuilder::append(Utf16View const& string)
|
||||||
|
{
|
||||||
|
if (try_append(string).is_error())
|
||||||
|
return m_vm.throw_completion<InternalError>(ErrorType::NotEnoughMemoryToAllocate, length() + (string.length_in_code_units() * 2));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> ThrowableStringBuilder::append_code_point(u32 value)
|
||||||
|
{
|
||||||
|
if (auto result = try_append_code_point(value); result.is_error())
|
||||||
|
return m_vm.throw_completion<InternalError>(ErrorType::NotEnoughMemoryToAllocate, length() + sizeof(value));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
Userland/Libraries/LibJS/Runtime/ThrowableStringBuilder.h
Normal file
31
Userland/Libraries/LibJS/Runtime/ThrowableStringBuilder.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <AK/StringView.h>
|
||||||
|
#include <LibJS/Forward.h>
|
||||||
|
#include <LibJS/Runtime/Completion.h>
|
||||||
|
#include <LibJS/Runtime/ErrorTypes.h>
|
||||||
|
#include <LibJS/Runtime/VM.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
class ThrowableStringBuilder : public AK::StringBuilder {
|
||||||
|
public:
|
||||||
|
explicit ThrowableStringBuilder(VM&);
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> append(char);
|
||||||
|
ThrowCompletionOr<void> append(StringView);
|
||||||
|
ThrowCompletionOr<void> append(Utf16View const&);
|
||||||
|
ThrowCompletionOr<void> append_code_point(u32 value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VM& m_vm;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue