Produce JS-visible string results as UTF-16 at their source, including numeric formatting, BigInt and BigFraction formatting, URI encoding, console formatting, parser errors, regular expression errors, Intl and Temporal records, LibUnicode locale boundaries, and LibWeb bindings. Handle fractional radix formatting through the UTF-16 builder view.
626 lines
27 KiB
Python
626 lines
27 KiB
Python
# Copyright (c) 2026-present, the Ladybird developers.
|
||
#
|
||
# SPDX-License-Identifier: BSD-2-Clause
|
||
|
||
from typing import TextIO
|
||
|
||
from Generators.libweb_bindings.context import GenerationContext
|
||
from Generators.libweb_bindings.cpp_types import add_binding_include_for_type
|
||
from Generators.libweb_bindings.cpp_types import add_buffer_source_type_include
|
||
from Generators.libweb_bindings.cpp_types import cpp_name
|
||
from Generators.libweb_bindings.cpp_types import cpp_type_details
|
||
from Generators.libweb_bindings.cpp_types import cpp_type_for_idl_type
|
||
from Generators.libweb_bindings.cpp_types import cpp_type_for_idl_type_details
|
||
from Generators.libweb_bindings.cpp_types import implementation_header_for_interface
|
||
from Generators.libweb_bindings.cpp_types import interface_like_type_for_idl_type
|
||
from Generators.libweb_bindings.cpp_types import is_buffer_source_type
|
||
from Generators.libweb_bindings.cpp_types import is_optional_without_default
|
||
from Generators.libweb_bindings.cpp_types import is_string_type
|
||
from Generators.libweb_bindings.includes import GeneratedIncludes
|
||
from Utils.utils import make_name_acceptable_cpp
|
||
from Utils.utils import string_to_cpp_enum_name
|
||
from Utils.utils import title_case_to_snake_case
|
||
from Utils.webidl_parser import Dictionary
|
||
from Utils.webidl_parser import DictionaryMember
|
||
from Utils.webidl_parser import Enumeration
|
||
from Utils.webidl_parser import IDLParameterizedType
|
||
from Utils.webidl_parser import IDLType
|
||
from Utils.webidl_parser import IDLUnionType
|
||
|
||
|
||
def unsupported_to_javascript_value(idl_type: IDLType) -> str:
|
||
raise RuntimeError(f"Unsupported IDL value conversion for '{idl_type.name}'")
|
||
|
||
|
||
def to_value_function_name(dictionary: Dictionary) -> str:
|
||
return f"{make_name_acceptable_cpp(title_case_to_snake_case(dictionary.name))}_to_value"
|
||
|
||
|
||
def write_enumeration_to_javascript_value_declaration(
|
||
out: TextIO,
|
||
enumeration: Enumeration,
|
||
includes: GeneratedIncludes,
|
||
) -> None:
|
||
includes.add("AK/Utf16String.h")
|
||
|
||
out.write(f"Utf16String idl_enum_to_string({enumeration.name});\n\n")
|
||
|
||
|
||
def write_dictionary_to_javascript_value_declaration(out: TextIO, dictionary: Dictionary) -> None:
|
||
if "GenerateToValue" not in dictionary.extended_attributes:
|
||
return
|
||
|
||
out.write(f"JS::Value {to_value_function_name(dictionary)}(JS::Realm&, {dictionary.name} const&);\n\n")
|
||
|
||
|
||
def write_enumeration_to_javascript_value_conversion(out: TextIO, enumeration: Enumeration) -> None:
|
||
out.write(
|
||
f"""// https://webidl.spec.whatwg.org/#idl-enumeration
|
||
Utf16String idl_enum_to_string({enumeration.name} value)
|
||
{{
|
||
// The result of converting an IDL enumeration type value to a JavaScript value is the String value that represents the same sequence of code units as the enumeration value.
|
||
switch (value) {{
|
||
"""
|
||
)
|
||
|
||
for value in enumeration.values:
|
||
out.write(f" case {enumeration.name}::{string_to_cpp_enum_name(value)}:\n")
|
||
out.write(f' return "{value}"_utf16;\n')
|
||
|
||
out.write(
|
||
""" }
|
||
VERIFY_NOT_REACHED();
|
||
}
|
||
|
||
"""
|
||
)
|
||
|
||
|
||
def write_dictionary_to_javascript_value_conversion(
|
||
out: TextIO,
|
||
dictionary: Dictionary,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> None:
|
||
if "GenerateToValue" not in dictionary.extended_attributes:
|
||
return
|
||
|
||
includes.add("LibJS/Runtime/Object.h")
|
||
out.write(
|
||
f"""JS::Value {to_value_function_name(dictionary)}(JS::Realm& realm, {dictionary.name} const& dictionary)
|
||
{{
|
||
auto& vm = realm.vm();
|
||
return {to_javascript_value(IDLType(dictionary.name), "dictionary", includes, context)};
|
||
}}
|
||
|
||
"""
|
||
)
|
||
|
||
|
||
def integer_to_javascript_value(cpp_type_name: str, value: str, includes: GeneratedIncludes) -> str:
|
||
includes.add("LibWeb/WebIDL/Types.h")
|
||
return f"JS::Value(static_cast<{cpp_type_name}>({value}))"
|
||
|
||
|
||
# 3.2.1. any, https://webidl.spec.whatwg.org/#js-any
|
||
def any_to_javascript_value(value: str) -> str:
|
||
# An IDL any value is converted to a JavaScript value according to the rules for converting the specific type of the
|
||
# NB: We're getting passed a JS::Value - which is already our JS representation, so we can just return it as-is.
|
||
return value
|
||
|
||
|
||
# 3.2.2. undefined, https://webidl.spec.whatwg.org/#js-undefined
|
||
def undefined_to_javascript_value() -> str:
|
||
# The unique IDL undefined value is converted to the JavaScript undefined value.
|
||
return "JS::js_undefined()"
|
||
|
||
|
||
# 3.2.3. boolean, https://webidl.spec.whatwg.org/#js-boolean
|
||
def boolean_to_javascript_value(value: str) -> str:
|
||
# The IDL boolean value true is converted to the JavaScript true value and the IDL boolean value false is converted
|
||
# to the JavaScript false value.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.4.1. byte, https://webidl.spec.whatwg.org/#js-byte
|
||
def byte_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL byte value to a JavaScript value is a Number that represents the same numeric value
|
||
# as the IDL byte value. The Number value will be an integer in the range [−128, 127].
|
||
return integer_to_javascript_value("WebIDL::Byte", value, includes)
|
||
|
||
|
||
# 3.2.4.2. octet, https://webidl.spec.whatwg.org/#js-octet
|
||
def octet_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL octet value to a JavaScript value is a Number that represents the same numeric value
|
||
# as the IDL octet value. The Number value will be an integer in the range [0, 255].
|
||
return integer_to_javascript_value("WebIDL::Octet", value, includes)
|
||
|
||
|
||
# 3.2.4.3. short, https://webidl.spec.whatwg.org/#js-short
|
||
def short_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL short value to a JavaScript value is a Number that represents the same numeric value
|
||
# as the IDL short value. The Number value will be an integer in the range [−32768, 32767].
|
||
return integer_to_javascript_value("WebIDL::Short", value, includes)
|
||
|
||
|
||
# 3.2.4.4. unsigned short, https://webidl.spec.whatwg.org/#js-unsigned-short
|
||
def unsigned_short_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL unsigned short value to a JavaScript value is a Number that represents the same numeric
|
||
# value as the IDL unsigned short value. The Number value will be an integer in the range [0, 65535].
|
||
return integer_to_javascript_value("WebIDL::UnsignedShort", value, includes)
|
||
|
||
|
||
# 3.2.4.5. long, https://webidl.spec.whatwg.org/#js-long
|
||
def long_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL long value to a JavaScript value is a Number that represents the same numeric value as
|
||
# the IDL long value. The Number value will be an integer in the range [−2147483648, 2147483647].
|
||
return integer_to_javascript_value("WebIDL::Long", value, includes)
|
||
|
||
|
||
# 3.2.4.6. unsigned long, https://webidl.spec.whatwg.org/#js-unsigned-long
|
||
def unsigned_long_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL unsigned long value to a JavaScript value is a Number that represents the same numeric
|
||
# value as the IDL unsigned long value. The Number value will be an integer in the range [0, 4294967295].
|
||
return integer_to_javascript_value("WebIDL::UnsignedLong", value, includes)
|
||
|
||
|
||
# 3.2.4.7. long long,
|
||
def long_long_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL long long value to a JavaScript value is a Number value that represents the closest
|
||
# numeric value to the long long, choosing the numeric value with an even significand if there are two equally close
|
||
# values. If the long long is in the range [−2^53 + 1, 2^53 − 1], then the Number will be able to represent exactly
|
||
# the same value as the long long.
|
||
return integer_to_javascript_value("double", value, includes)
|
||
|
||
|
||
# 3.2.4.8. unsigned long long, https://webidl.spec.whatwg.org/#js-unsigned-long-long
|
||
def unsigned_long_long_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
# The result of converting an IDL unsigned long long value to a JavaScript value is a Number value that represents
|
||
# the closest numeric value to the unsigned long long, choosing the numeric value with an even significand if there
|
||
# are two equally close values. If the unsigned long long is less than or equal to 253 − 1, then the Number will be
|
||
# able to represent exactly the same value as the unsigned long long.
|
||
return integer_to_javascript_value("double", value, includes)
|
||
|
||
|
||
# 3.2.5. float, https://webidl.spec.whatwg.org/#js-float
|
||
def float_to_javascript_value(value: str) -> str:
|
||
# The result of converting an IDL float value to a JavaScript value is the Number value that represents the same
|
||
# numeric value as the IDL float value.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.6. unrestricted float, https://webidl.spec.whatwg.org/#js-unrestricted-float
|
||
def unrestricted_float_to_javascript_value(value: str) -> str:
|
||
# 1. If the IDL unrestricted float value is a NaN, then the Number value is NaN.
|
||
# 2. Otherwise, the Number value is the one that represents the same numeric value as the IDL unrestricted float value.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.7. double, https://webidl.spec.whatwg.org/#js-double
|
||
def double_to_javascript_value(value: str) -> str:
|
||
# The result of converting an IDL double value to a JavaScript value is the Number value that represents the same
|
||
# numeric value as the IDL double value.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.8. unrestricted double, https://webidl.spec.whatwg.org/#js-unrestricted-double
|
||
def unrestricted_double_to_javascript_value(value: str) -> str:
|
||
# 1. If the IDL unrestricted double value is a NaN, then the Number value is NaN.
|
||
# 2. Otherwise, the Number value is the one that represents the same numeric value as the IDL unrestricted double value.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.10. DOMString, https://webidl.spec.whatwg.org/#js-DOMString
|
||
def domstring_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
includes.add("LibWeb/WebIDL/AbstractOperations.h")
|
||
return f"WebIDL::primitive_string_from_string(vm, {value})"
|
||
|
||
|
||
# 3.2.11. ByteString, https://webidl.spec.whatwg.org/#js-ByteString
|
||
def bytestring_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
includes.add("LibWeb/WebIDL/AbstractOperations.h")
|
||
# The result of converting an IDL ByteString value to a JavaScript value is a String value whose length is the length
|
||
# of the ByteString, and the value of each element of which is the value of the corresponding element of the ByteString.
|
||
return f"WebIDL::primitive_string_from_string(vm, {value})"
|
||
|
||
|
||
# 3.2.12. USVString, https://webidl.spec.whatwg.org/#js-USVString
|
||
def usvstring_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
includes.add("LibWeb/WebIDL/AbstractOperations.h")
|
||
# The result of converting an IDL USVString value S to a JavaScript value is S.
|
||
return f"WebIDL::primitive_string_from_string(vm, {value})"
|
||
|
||
|
||
# 3.2.13. object, https://webidl.spec.whatwg.org/#js-object
|
||
def object_to_javascript_value(value: str) -> str:
|
||
# The result of converting an IDL object value to a JavaScript value is the Object value that represents a reference to
|
||
# the same object that the IDL object represents.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.15. Interface types, https://webidl.spec.whatwg.org/#js-interface
|
||
def interface_to_javascript_value(value: str, includes: GeneratedIncludes, interface_like_type) -> str:
|
||
includes.add(interface_like_type.implementation_header)
|
||
# FIXME: Do we need this const cast?
|
||
# The result of converting an IDL interface type value to a JavaScript value is the Object value that represents a
|
||
# reference to the same object that the IDL interface type value represents.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.16. Callback interface types, https://webidl.spec.whatwg.org/#js-callback-interface
|
||
def callback_interface_to_javascript_value(value: str, includes: GeneratedIncludes, interface) -> str:
|
||
# The result of converting an IDL callback interface type value to a JavaScript value is the Object value that represents
|
||
# a reference to the same object that the IDL callback interface type value represents.
|
||
includes.add(implementation_header_for_interface(interface))
|
||
return f"{value}->callback().callback"
|
||
|
||
|
||
def dictionary_member_to_javascript_conversion(
|
||
member: DictionaryMember,
|
||
dictionary_value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> tuple[str, str]:
|
||
member_value = f"{dictionary_value}.{cpp_name(member)}"
|
||
member_type = member.type
|
||
member_exists = ""
|
||
|
||
if is_optional_without_default(member):
|
||
cpp_type = cpp_type_details(member, context)
|
||
if cpp_type.gc_ref_target_type and not member.type.nullable:
|
||
member_exists = member_value
|
||
else:
|
||
member_exists = f"{member_value}.has_value()"
|
||
member_value = f"{member_value}.value()"
|
||
if member.type.nullable and not isinstance(member.type, IDLUnionType) and not cpp_type.is_optional_presence:
|
||
member_type = member.type.without_nullable()
|
||
|
||
return member_exists, to_javascript_value(member_type, member_value, includes, context)
|
||
|
||
|
||
# 3.2.17. Dictionary types, https://webidl.spec.whatwg.org/#js-dictionary
|
||
def dictionary_to_javascript_value(
|
||
idl_type: IDLType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> str:
|
||
dictionary = context.dictionary(idl_type)
|
||
if dictionary is None:
|
||
raise RuntimeError(f"Unknown dictionary '{idl_type.name}'")
|
||
add_binding_include_for_type(idl_type, includes, context)
|
||
includes.add("LibJS/Runtime/Object.h")
|
||
generated_conversion = """[&]() -> JS::Value {
|
||
// 1. Let O be OrdinaryObjectCreate(%Object.prototype%).
|
||
auto dictionary_object = JS::Object::create(realm, realm.intrinsics().object_prototype());
|
||
"""
|
||
|
||
# 2. Let dictionaries be a list consisting of D and all of D's inherited dictionaries, in order from least to most derived.
|
||
# 3. For each dictionary dictionary in dictionaries, in order:
|
||
for dictionary_in_stack in reversed(context.dictionary_inheritance_stack(dictionary)):
|
||
# 1. For each dictionary member member declared on dictionary, in lexicographical order:
|
||
for member in dictionary_in_stack.members:
|
||
member_exists, converted_member_value = dictionary_member_to_javascript_conversion(
|
||
member, value, includes, context
|
||
)
|
||
|
||
generated_conversion += """
|
||
// 1. Let key be the identifier of member.
|
||
// 2. If V[key] exists, then:
|
||
"""
|
||
if member_exists:
|
||
generated_conversion += f" if ({member_exists}) {{\n"
|
||
|
||
generated_conversion += f"""
|
||
// 1. Let idlValue be V[key].
|
||
// 2. Let value be the result of converting idlValue to a JavaScript value.
|
||
// 3. Perform ! CreateDataPropertyOrThrow(O, key, value).
|
||
MUST(dictionary_object->create_data_property("{member.name}"_utf16_fly_string, {converted_member_value}));
|
||
"""
|
||
if member_exists:
|
||
generated_conversion += " }\n"
|
||
|
||
generated_conversion += """
|
||
// 4. Return O.
|
||
return dictionary_object;
|
||
}()"""
|
||
return generated_conversion
|
||
|
||
|
||
# 3.2.18. Enumeration types, https://webidl.spec.whatwg.org/#js-enumeration
|
||
def enumeration_to_javascript_value(
|
||
idl_type: IDLType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> str:
|
||
add_binding_include_for_type(idl_type, includes, context)
|
||
includes.add("LibJS/Runtime/PrimitiveString.h")
|
||
# The result of converting an IDL enumeration type value to a JavaScript value is the String value that represents the
|
||
# same sequence of code units as the enumeration value.
|
||
return f"JS::PrimitiveString::create(vm, idl_enum_to_string({value}))"
|
||
|
||
|
||
# 3.2.19. Callback function types, https://webidl.spec.whatwg.org/#js-callback-function
|
||
def callback_function_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
includes.add("LibWeb/WebIDL/CallbackType.h")
|
||
# The result of converting an IDL callback function type value to a JavaScript value is a reference to the same object
|
||
# that the IDL callback function type value represents.
|
||
return f"{value}->callback"
|
||
|
||
|
||
# 3.2.20. Nullable types — T?, https://webidl.spec.whatwg.org/#js-nullable-type
|
||
def nullable_to_javascript_value(
|
||
idl_type: IDLType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> str:
|
||
inner_type = idl_type.clone_with_nullable(False)
|
||
value_is_nullable_pointer = bool(cpp_type_for_idl_type_details(idl_type, context).gc_ref_target_type)
|
||
inner_value = value if value_is_nullable_pointer else f"{value}.value()"
|
||
has_value = value if value_is_nullable_pointer else f"{value}.has_value()"
|
||
return f"""[&]() -> JS::Value {{
|
||
// 1. If the IDL nullable type T? value is null, then the JavaScript value is null.
|
||
if (!{has_value})
|
||
return JS::js_null();
|
||
|
||
// 2. Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type T.
|
||
return JS::Value({to_javascript_value(inner_type, inner_value, includes, context)});
|
||
}}()"""
|
||
|
||
|
||
# 3.2.21. Sequences — sequence<T>, https://webidl.spec.whatwg.org/#js-sequence
|
||
def sequence_to_javascript_value(
|
||
sequence_type: IDLParameterizedType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
freeze: bool = False,
|
||
) -> str:
|
||
includes.add("LibJS/Runtime/Array.h")
|
||
element_type = sequence_type.parameters[0]
|
||
length_name = "sequence_length"
|
||
array_name = "sequence_array"
|
||
index_name = "sequence_index"
|
||
element_name = "sequence_element"
|
||
js_element_name = "js_sequence_element"
|
||
converted_element = to_javascript_value(element_type, element_name, includes, context)
|
||
|
||
freeze_array = ""
|
||
if freeze:
|
||
freeze_array = f"""
|
||
MUST({array_name}->set_integrity_level(JS::Object::IntegrityLevel::Frozen));
|
||
"""
|
||
|
||
return f"""[&]() -> JS::Value {{
|
||
// An IDL sequence<T> value S is converted to a JavaScript value as follows:
|
||
// 1. Let n be the length of S.
|
||
auto {length_name} = {value}.size();
|
||
|
||
// 2. Let A be a new Array object created as if by the expression [].
|
||
auto {array_name} = MUST(JS::Array::create(realm, {length_name}));
|
||
|
||
// 3. Initialize i to be 0.
|
||
// 4. While i < n:
|
||
for (size_t {index_name} = 0; {index_name} < {length_name}; ++{index_name}) {{
|
||
// 1. Let V be the value in S at index i.
|
||
auto& {element_name} = {value}.at({index_name});
|
||
|
||
// 2. Let E be the result of converting V to a JavaScript value.
|
||
JS::Value {js_element_name} = {converted_element};
|
||
|
||
// 3. Let P be the result of calling ! ToString(i).
|
||
// 4. Perform ! CreateDataPropertyOrThrow(A, P, E).
|
||
MUST({array_name}->create_data_property(JS::PropertyKey {{ {index_name} }}, {js_element_name}));
|
||
|
||
// 5. Set i to i + 1.
|
||
}}
|
||
{freeze_array}
|
||
// 5. Return A.
|
||
return {array_name};
|
||
}}()"""
|
||
|
||
|
||
# 3.2.23. Records — record<K, V>, https://webidl.spec.whatwg.org/#js-record
|
||
def record_to_javascript_value(
|
||
record_type: IDLParameterizedType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> str:
|
||
if len(record_type.parameters) != 2:
|
||
raise RuntimeError("Record type must have two parameters")
|
||
key_type = record_type.parameters[0]
|
||
if not is_string_type(key_type.name):
|
||
raise RuntimeError(f"Unsupported record key type '{key_type.name}'")
|
||
|
||
includes.add("AK/Utf16FlyString.h")
|
||
includes.add("LibJS/Runtime/Object.h")
|
||
value_type = record_type.parameters[1]
|
||
object_name = "record_object"
|
||
key_name = "record_key"
|
||
value_name = "record_value"
|
||
converted_value = to_javascript_value(value_type, value_name, includes, context)
|
||
|
||
return f"""[&]() -> JS::Value {{
|
||
// 1. Let result be OrdinaryObjectCreate(%Object.prototype%).
|
||
auto {object_name} = JS::Object::create(realm, realm.intrinsics().object_prototype());
|
||
|
||
// 2. For each key → value of D:
|
||
for (auto const& [{key_name}, {value_name}] : {value}) {{
|
||
// 1. Let jsKey be key converted to a JavaScript value.
|
||
// 2. Let jsValue be value converted to a JavaScript value.
|
||
// 3. Let created be ! CreateDataProperty(result, jsKey, jsValue).
|
||
// 4. Assert: created is true.
|
||
MUST({object_name}->create_data_property(Utf16FlyString::from_utf8({key_name}), {converted_value}));
|
||
}}
|
||
|
||
// 3. Return result.
|
||
return {object_name};
|
||
}}()"""
|
||
|
||
|
||
# 3.2.24. Promise types — Promise<T>, https://webidl.spec.whatwg.org/#js-promise
|
||
def promise_to_javascript_value(value: str, includes: GeneratedIncludes) -> str:
|
||
includes.add("AK/TypeCasts.h")
|
||
includes.add("LibJS/Runtime/Promise.h")
|
||
includes.add("LibWeb/WebIDL/Promise.h")
|
||
# The result of converting an IDL promise type value to a JavaScript value is the value of the [[Promise]] field of the
|
||
# record that IDL promise type represents.
|
||
return f"GC::Ref {{ as<JS::Promise>(*{value}->promise()) }}"
|
||
|
||
|
||
# 3.2.25. Union types, https://webidl.spec.whatwg.org/#js-union
|
||
def union_to_javascript_value(
|
||
union_type: IDLUnionType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> str:
|
||
includes.add("AK/Variant.h")
|
||
# An IDL union type value is converted to a JavaScript value according to the rules for converting the specific type of the
|
||
# IDL union type value as described in this section (§ 3.2 JavaScript type mapping).
|
||
conversions = []
|
||
for index, member_type in enumerate(union_type.flattened_member_types()):
|
||
if member_type.name == "undefined":
|
||
continue
|
||
inner_type = member_type.clone_with_nullable(False)
|
||
visited_value = f"visited_union_value{index}"
|
||
visited_cpp_type = cpp_type_for_idl_type(inner_type, context)
|
||
converted_value = to_javascript_value(inner_type, visited_value, includes, context)
|
||
conversions.append(
|
||
f""" [&]({visited_cpp_type} const& {visited_value}) -> JS::Value
|
||
{{
|
||
return {converted_value};
|
||
}}"""
|
||
)
|
||
|
||
if union_type.includes_nullable_type():
|
||
conversions.append(
|
||
""" [](Empty) -> JS::Value
|
||
{
|
||
return JS::js_null();
|
||
}"""
|
||
)
|
||
elif union_type.includes_undefined():
|
||
conversions.append(
|
||
""" [](Empty) -> JS::Value
|
||
{
|
||
return JS::js_undefined();
|
||
}"""
|
||
)
|
||
|
||
joined_conversions = ",\n".join(conversions)
|
||
return f"""{value}.visit(
|
||
{joined_conversions}
|
||
)"""
|
||
|
||
|
||
# 3.2.26. Buffer source types, https://webidl.spec.whatwg.org/#js-buffer-source-types
|
||
def buffer_source_to_javascript_value(idl_type: IDLType, value: str, includes: GeneratedIncludes) -> str:
|
||
add_buffer_source_type_include(idl_type, includes)
|
||
# The result of converting an IDL value of any buffer source type to a JavaScript value is the Object value that
|
||
# represents a reference to the same object that the IDL value represents.
|
||
return f"JS::Value({value})"
|
||
|
||
|
||
# 3.2.27. Frozen arrays — FrozenArray<T>, https://webidl.spec.whatwg.org/#js-frozen-array
|
||
def frozen_array_to_javascript_value(
|
||
frozen_array_type: IDLParameterizedType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> str:
|
||
# The result of converting an IDL FrozenArray<T> value to a JavaScript value is the Object value that represents a
|
||
# reference to the same object that the IDL FrozenArray<T> represents.
|
||
return sequence_to_javascript_value(frozen_array_type, value, includes, context, freeze=True)
|
||
|
||
|
||
def to_javascript_value(
|
||
idl_type: IDLType,
|
||
value: str,
|
||
includes: GeneratedIncludes,
|
||
context: GenerationContext,
|
||
) -> str:
|
||
includes.add("LibJS/Runtime/Value.h")
|
||
type_name = idl_type.name
|
||
|
||
if isinstance(idl_type, IDLUnionType):
|
||
return union_to_javascript_value(idl_type, value, includes, context)
|
||
|
||
if idl_type.nullable:
|
||
return nullable_to_javascript_value(idl_type, value, includes, context)
|
||
|
||
if type_name == "undefined":
|
||
return undefined_to_javascript_value()
|
||
if type_name == "any":
|
||
return any_to_javascript_value(value)
|
||
if type_name == "object":
|
||
return object_to_javascript_value(value)
|
||
if is_buffer_source_type(idl_type):
|
||
return buffer_source_to_javascript_value(idl_type, value, includes)
|
||
if type_name == "boolean":
|
||
return boolean_to_javascript_value(value)
|
||
if type_name == "byte":
|
||
return byte_to_javascript_value(value, includes)
|
||
if type_name == "octet":
|
||
return octet_to_javascript_value(value, includes)
|
||
if type_name == "short":
|
||
return short_to_javascript_value(value, includes)
|
||
if type_name == "unsigned short":
|
||
return unsigned_short_to_javascript_value(value, includes)
|
||
if type_name == "long":
|
||
return long_to_javascript_value(value, includes)
|
||
if type_name == "unsigned long":
|
||
return unsigned_long_to_javascript_value(value, includes)
|
||
if type_name == "long long":
|
||
return long_long_to_javascript_value(value, includes)
|
||
if type_name == "unsigned long long":
|
||
return unsigned_long_long_to_javascript_value(value, includes)
|
||
if type_name == "float":
|
||
return float_to_javascript_value(value)
|
||
if type_name == "unrestricted float":
|
||
return unrestricted_float_to_javascript_value(value)
|
||
if type_name == "double":
|
||
return double_to_javascript_value(value)
|
||
if type_name == "unrestricted double":
|
||
return unrestricted_double_to_javascript_value(value)
|
||
|
||
if type_name in ("DOMString", "Utf16DOMString"):
|
||
return domstring_to_javascript_value(value, includes)
|
||
if type_name in ("ByteString",):
|
||
return bytestring_to_javascript_value(value, includes)
|
||
if type_name in ("USVString", "Utf16USVString"):
|
||
return usvstring_to_javascript_value(value, includes)
|
||
|
||
if context.enumeration(idl_type) is not None:
|
||
return enumeration_to_javascript_value(idl_type, value, includes, context)
|
||
|
||
if context.dictionary(idl_type) is not None:
|
||
return dictionary_to_javascript_value(idl_type, value, includes, context)
|
||
|
||
if type_name == "Promise":
|
||
return promise_to_javascript_value(value, includes)
|
||
|
||
interface_like_type = interface_like_type_for_idl_type(idl_type, context)
|
||
if interface_like_type is not None:
|
||
return interface_to_javascript_value(value, includes, interface_like_type)
|
||
|
||
interface = context.interface(idl_type)
|
||
if interface is not None and interface.is_callback_interface:
|
||
return callback_interface_to_javascript_value(value, includes, interface)
|
||
|
||
if context.callback_function(idl_type) is not None:
|
||
return callback_function_to_javascript_value(value, includes)
|
||
|
||
if isinstance(idl_type, IDLParameterizedType) and type_name == "sequence":
|
||
return sequence_to_javascript_value(idl_type, value, includes, context)
|
||
|
||
if isinstance(idl_type, IDLParameterizedType) and type_name == "record":
|
||
return record_to_javascript_value(idl_type, value, includes, context)
|
||
|
||
if isinstance(idl_type, IDLParameterizedType) and type_name == "FrozenArray":
|
||
return frozen_array_to_javascript_value(idl_type, value, includes, context)
|
||
|
||
return unsupported_to_javascript_value(idl_type)
|