| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-06 17:49:48 -07:00
										 |  |  | #include <AK/StringBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2021-08-02 17:02:17 -04:00
										 |  |  | #include <AK/Utf16View.h>
 | 
					
						
							| 
									
										
										
										
											2020-05-31 00:47:28 +01:00
										 |  |  | #include <AK/Utf32View.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-28 13:14:41 +03:00
										 |  |  | #include <LibJS/Runtime/AbstractOperations.h>
 | 
					
						
							| 
									
										
										
										
											2020-05-06 17:49:48 -07:00
										 |  |  | #include <LibJS/Runtime/Array.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | #include <LibJS/Runtime/Error.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-18 13:18:06 +02:00
										 |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | #include <LibJS/Runtime/StringConstructor.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/StringObject.h>
 | 
					
						
							| 
									
										
										
										
											2021-08-09 09:06:45 -04:00
										 |  |  | #include <LibJS/Runtime/Utf16String.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace JS { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  | StringConstructor::StringConstructor(Realm& realm) | 
					
						
							| 
									
										
										
										
											2022-09-14 19:10:27 -04:00
										 |  |  |     : NativeFunction(realm.vm().names.String.as_string(), *realm.intrinsics().function_prototype()) | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-20 15:40:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-28 12:33:35 -05:00
										 |  |  | ThrowCompletionOr<void> StringConstructor::initialize(Realm& realm) | 
					
						
							| 
									
										
										
										
											2020-06-20 15:40:48 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-13 23:49:19 +02:00
										 |  |  |     auto& vm = this->vm(); | 
					
						
							| 
									
										
										
										
											2023-01-28 12:33:35 -05:00
										 |  |  |     MUST_OR_THROW_OOM(NativeFunction::initialize(realm)); | 
					
						
							| 
									
										
										
										
											2021-06-13 00:22:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // 22.1.2.3 String.prototype, https://tc39.es/ecma262/#sec-string.prototype
 | 
					
						
							| 
									
										
										
										
											2022-08-27 00:54:55 +01:00
										 |  |  |     define_direct_property(vm.names.prototype, realm.intrinsics().string_prototype(), 0); | 
					
						
							| 
									
										
										
										
											2021-06-13 00:22:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-31 00:47:28 +01:00
										 |  |  |     u8 attr = Attribute::Writable | Attribute::Configurable; | 
					
						
							| 
									
										
										
										
											2022-08-22 21:47:35 +01:00
										 |  |  |     define_native_function(realm, vm.names.raw, raw, 1, attr); | 
					
						
							|  |  |  |     define_native_function(realm, vm.names.fromCharCode, from_char_code, 1, attr); | 
					
						
							|  |  |  |     define_native_function(realm, vm.names.fromCodePoint, from_code_point, 1, attr); | 
					
						
							| 
									
										
										
										
											2021-07-08 02:49:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     define_direct_property(vm.names.length, Value(1), Attribute::Configurable); | 
					
						
							| 
									
										
										
										
											2023-01-28 12:33:35 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 00:22:35 +01:00
										 |  |  | // 22.1.1.1 String ( value ), https://tc39.es/ecma262/#sec-string-constructor-string-value
 | 
					
						
							| 
									
										
										
										
											2021-10-20 21:16:30 +01:00
										 |  |  | ThrowCompletionOr<Value> StringConstructor::call() | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     auto& vm = this->vm(); | 
					
						
							|  |  |  |     if (!vm.argument_count()) | 
					
						
							| 
									
										
										
										
											2023-01-14 10:40:08 -05:00
										 |  |  |         return PrimitiveString::create(vm, String {}); | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     if (vm.argument(0).is_symbol()) | 
					
						
							| 
									
										
										
										
											2023-02-11 16:14:41 +00:00
										 |  |  |         return PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, vm.argument(0).as_symbol().descriptive_string())); | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     return TRY(vm.argument(0).to_primitive_string(vm)); | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 00:22:35 +01:00
										 |  |  | // 22.1.1.1 String ( value ), https://tc39.es/ecma262/#sec-string-constructor-string-value
 | 
					
						
							| 
									
										
										
										
											2022-12-14 19:18:10 +00:00
										 |  |  | ThrowCompletionOr<NonnullGCPtr<Object>> StringConstructor::construct(FunctionObject& new_target) | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-16 00:20:49 +01:00
										 |  |  |     auto& vm = this->vm(); | 
					
						
							| 
									
										
										
										
											2022-08-22 19:00:49 +01:00
										 |  |  |     auto& realm = *vm.current_realm(); | 
					
						
							| 
									
										
										
										
											2021-06-30 18:13:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     PrimitiveString* primitive_string; | 
					
						
							|  |  |  |     if (!vm.argument_count()) | 
					
						
							| 
									
										
										
										
											2023-02-09 07:50:12 -05:00
										 |  |  |         primitive_string = PrimitiveString::create(vm, String {}); | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         primitive_string = TRY(vm.argument(0).to_primitive_string(vm)); | 
					
						
							| 
									
										
										
										
											2022-08-27 00:54:55 +01:00
										 |  |  |     auto* prototype = TRY(get_prototype_from_constructor(vm, new_target, &Intrinsics::string_prototype)); | 
					
						
							| 
									
										
										
										
											2023-01-28 13:40:56 -05:00
										 |  |  |     return MUST_OR_THROW_OOM(StringObject::create(realm, *primitive_string, *prototype)); | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 00:22:35 +01:00
										 |  |  | // 22.1.2.4 String.raw ( template, ...substitutions ), https://tc39.es/ecma262/#sec-string.raw
 | 
					
						
							| 
									
										
										
										
											2021-10-23 02:54:12 +03:00
										 |  |  | JS_DEFINE_NATIVE_FUNCTION(StringConstructor::raw) | 
					
						
							| 
									
										
										
										
											2020-05-06 17:49:48 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     auto* cooked = TRY(vm.argument(0).to_object(vm)); | 
					
						
							| 
									
										
										
										
											2021-10-23 02:54:12 +03:00
										 |  |  |     auto raw_value = TRY(cooked->get(vm.names.raw)); | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |     auto* raw = TRY(raw_value.to_object(vm)); | 
					
						
							| 
									
										
										
										
											2022-08-21 19:24:32 +01:00
										 |  |  |     auto literal_segments = TRY(length_of_array_like(vm, *raw)); | 
					
						
							| 
									
										
										
										
											2021-06-28 13:14:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (literal_segments == 0) | 
					
						
							| 
									
										
										
										
											2023-02-09 07:50:12 -05:00
										 |  |  |         return PrimitiveString::create(vm, String {}); | 
					
						
							| 
									
										
										
										
											2020-05-06 17:49:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  |     auto const number_of_substituions = vm.argument_count() - 1; | 
					
						
							| 
									
										
										
										
											2020-05-06 17:49:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 13:14:41 +03:00
										 |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     for (size_t i = 0; i < literal_segments; ++i) { | 
					
						
							| 
									
										
										
										
											2022-12-04 18:02:33 +00:00
										 |  |  |         auto next_key = DeprecatedString::number(i); | 
					
						
							| 
									
										
										
										
											2021-10-23 02:54:12 +03:00
										 |  |  |         auto next_segment_value = TRY(raw->get(next_key)); | 
					
						
							| 
									
										
										
										
											2023-01-13 10:29:02 -05:00
										 |  |  |         auto next_segment = TRY(next_segment_value.to_deprecated_string(vm)); | 
					
						
							| 
									
										
										
										
											2021-06-28 13:14:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         builder.append(next_segment); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (i + 1 == literal_segments) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (i < number_of_substituions) { | 
					
						
							|  |  |  |             auto next = vm.argument(i + 1); | 
					
						
							| 
									
										
										
										
											2023-01-13 10:29:02 -05:00
										 |  |  |             auto next_sub = TRY(next.to_deprecated_string(vm)); | 
					
						
							| 
									
										
										
										
											2021-06-28 13:14:41 +03:00
										 |  |  |             builder.append(next_sub); | 
					
						
							| 
									
										
										
										
											2020-05-15 13:39:24 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-06 17:49:48 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-26 18:58:09 +00:00
										 |  |  |     return PrimitiveString::create(vm, builder.to_deprecated_string()); | 
					
						
							| 
									
										
										
										
											2020-05-06 17:49:48 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 00:22:35 +01:00
										 |  |  | // 22.1.2.1 String.fromCharCode ( ...codeUnits ), https://tc39.es/ecma262/#sec-string.fromcharcode
 | 
					
						
							| 
									
										
										
										
											2021-10-23 02:54:12 +03:00
										 |  |  | JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_char_code) | 
					
						
							| 
									
										
										
										
											2020-05-31 00:47:28 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-06 11:00:24 -05:00
										 |  |  |     Utf16Data string; | 
					
						
							| 
									
										
										
										
											2021-08-02 17:02:17 -04:00
										 |  |  |     string.ensure_capacity(vm.argument_count()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-17 23:48:24 +03:00
										 |  |  |     for (size_t i = 0; i < vm.argument_count(); ++i) | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         string.append(TRY(vm.argument(i).to_u16(vm))); | 
					
						
							| 
									
										
										
										
											2021-08-02 17:02:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-07 12:24:05 -05:00
										 |  |  |     return PrimitiveString::create(vm, TRY(Utf16String::create(vm, move(string)))); | 
					
						
							| 
									
										
										
										
											2020-05-31 00:47:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 11:36:23 +03:00
										 |  |  | // 22.1.2.2 String.fromCodePoint ( ...codePoints ), https://tc39.es/ecma262/#sec-string.fromcodepoint
 | 
					
						
							| 
									
										
										
										
											2021-10-23 02:54:12 +03:00
										 |  |  | JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_code_point) | 
					
						
							| 
									
										
										
										
											2021-06-16 11:36:23 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-06 11:00:24 -05:00
										 |  |  |     Utf16Data string; | 
					
						
							| 
									
										
										
										
											2021-08-02 17:02:17 -04:00
										 |  |  |     string.ensure_capacity(vm.argument_count()); // This will be an under-estimate if any code point is > 0xffff.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 11:36:23 +03:00
										 |  |  |     for (size_t i = 0; i < vm.argument_count(); ++i) { | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         auto next_code_point = TRY(vm.argument(i).to_number(vm)); | 
					
						
							| 
									
										
										
										
											2021-10-23 02:54:12 +03:00
										 |  |  |         if (!next_code_point.is_integral_number()) | 
					
						
							| 
									
										
										
										
											2023-02-12 20:38:28 -05:00
										 |  |  |             return vm.throw_completion<RangeError>(ErrorType::InvalidCodePoint, next_code_point.to_deprecated_string_without_side_effects()); | 
					
						
							| 
									
										
										
										
											2022-08-21 14:00:56 +01:00
										 |  |  |         auto code_point = TRY(next_code_point.to_i32(vm)); | 
					
						
							| 
									
										
										
										
											2021-10-23 02:54:12 +03:00
										 |  |  |         if (code_point < 0 || code_point > 0x10FFFF) | 
					
						
							| 
									
										
										
										
											2023-02-12 20:38:28 -05:00
										 |  |  |             return vm.throw_completion<RangeError>(ErrorType::InvalidCodePoint, next_code_point.to_deprecated_string_without_side_effects()); | 
					
						
							| 
									
										
										
										
											2021-08-02 17:02:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 13:19:34 -05:00
										 |  |  |         TRY_OR_THROW_OOM(vm, code_point_to_utf16(string, static_cast<u32>(code_point))); | 
					
						
							| 
									
										
										
										
											2021-06-16 11:36:23 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-02 17:02:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-07 12:24:05 -05:00
										 |  |  |     return PrimitiveString::create(vm, TRY(Utf16String::create(vm, move(string)))); | 
					
						
							| 
									
										
										
										
											2021-06-16 11:36:23 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 14:14:02 +02:00
										 |  |  | } |