diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/bindings/scripts')
95 files changed, 12006 insertions, 3877 deletions
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn b/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn index 8868829c30d..a6cc71426b1 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn +++ b/chromium/third_party/blink/renderer/bindings/scripts/BUILD.gn @@ -37,9 +37,7 @@ action("cached_jinja_templates") { # Dummy file to track dependency. stamp_file = "$bindings_scripts_output_dir/cached_jinja_templates.stamp" - outputs = [ - stamp_file, - ] + outputs = [ stamp_file ] args = [ rebase_path(bindings_scripts_output_dir, root_build_dir), diff --git a/chromium/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py b/chromium/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py index e8a1fd2c9a9..71283002ba8 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py @@ -31,7 +31,6 @@ # Copyright (c) 2009 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Generates a .cpp file that includes all V8 binding .cpp files for interfaces. It is expected to preserve symbol space, and to be acceptable to make static @@ -47,6 +46,8 @@ Usage: Design doc: http://www.chromium.org/developers/design-documents/idl-build """ +from __future__ import print_function + import errno import optparse import os @@ -86,32 +87,35 @@ COPYRIGHT_TEMPLATE = """/* */ """ + def parse_options(): parser = optparse.OptionParser() parser.add_option('--component') options, args = parser.parse_args() if len(args) < 2: - raise Exception('Expected 2 filenames; one is for input, and the other is for output.') + raise Exception( + 'Expected 2 filenames; one is for input, and the other is for output.' + ) return options, args def generate_content(component, basenames): # Add fixed content. - output = [COPYRIGHT_TEMPLATE, - '#define NO_IMPLICIT_ATOMICSTRING\n\n'] + output = [COPYRIGHT_TEMPLATE, '#define NO_IMPLICIT_ATOMICSTRING\n\n'] basenames.sort() - output.extend('#include "third_party/blink/renderer/bindings/%s/v8/v8_%s.cc"\n' % - (component, to_snake_case(basename)) for basename in basenames) + output.extend( + '#include "third_party/blink/renderer/bindings/%s/v8/v8_%s.cc"\n' % + (component, to_snake_case(basename)) for basename in basenames) return ''.join(output) def write_content(content, output_file_name): parent_path, file_name = os.path.split(output_file_name) if not os.path.exists(parent_path): - print 'Creating directory: %s' % parent_path + print('Creating directory: %s' % parent_path) os.makedirs(parent_path) with open(output_file_name, 'w') as f: f.write(content) @@ -121,8 +125,9 @@ def main(): options, filenames = parse_options() component = options.component idl_filenames = read_idl_files_list_from_file(filenames[0]) - basenames = [idl_filename_to_basename(file_path) - for file_path in idl_filenames] + basenames = [ + idl_filename_to_basename(file_path) for file_path in idl_filenames + ] file_contents = generate_content(component, basenames) write_content(file_contents, filenames[1]) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf index 0169b9a6487..2ae9158e446 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/.style.yapf @@ -1,3 +1,4 @@ [style] # https://www.chromium.org/blink/coding-style based_on_style = pep8 +column_limit = 79 diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py index 94a51e669b6..ab16bdb63da 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py @@ -3,7 +3,6 @@ # found in the LICENSE file. import os.path -import platform import sys @@ -13,9 +12,10 @@ def _setup_sys_path(): expected_path = 'third_party/blink/renderer/bindings/scripts/bind_gen/' this_dir = os.path.dirname(__file__) - root_dir = os.path.join(this_dir, *(['..'] * expected_path.count('/'))) + root_dir = os.path.abspath( + os.path.join(this_dir, *(['..'] * expected_path.count('/')))) - sys.path = [ + module_dirs = ( # //third_party/blink/renderer/bindings/scripts/web_idl os.path.join(root_dir, 'third_party', 'blink', 'renderer', 'bindings', 'scripts'), @@ -24,37 +24,34 @@ def _setup_sys_path(): 'scripts'), # //third_party/mako/mako os.path.join(root_dir, 'third_party', 'mako'), - ] + sys.path + ) + for module_dir in reversed(module_dirs): + # Preserve sys.path[0] as is. + # https://docs.python.org/3/library/sys.html?highlight=path[0]#sys.path + sys.path.insert(1, module_dir) _setup_sys_path() - -from . import clang_format +from . import style_format from .dictionary import generate_dictionaries +from .enumeration import generate_enumerations from .interface import generate_interfaces from .path_manager import PathManager +from .union import generate_unions -def _setup_clang_format(): - expected_path = 'third_party/blink/renderer/bindings/scripts/bind_gen/' - - this_dir = os.path.dirname(__file__) - root_dir = os.path.join(this_dir, *(['..'] * expected_path.count('/'))) - - # //third_party/depot_tools/clang-format - command_name = ('clang-format.bat' - if platform.system() == 'Windows' else 'clang-format') - command_path = os.path.abspath( - os.path.join(root_dir, 'third_party', 'depot_tools', command_name)) - - clang_format.init(command_path=command_path) - - -def init(output_dirs): +def init(root_src_dir, root_gen_dir, component_reldirs): """ Args: - output_dirs: Pairs of component and output directory. + root_src_dir: Project's root directory, which corresponds to "//" in GN. + root_gen_dir: Root directory of generated files, which corresponds to + "//out/Default/gen" in GN. + component_reldirs: Pairs of component and output directory. """ - _setup_clang_format() - PathManager.init(output_dirs) + style_format.init(root_src_dir) + + PathManager.init( + root_src_dir=root_src_dir, + root_gen_dir=root_gen_dir, + component_reldirs=component_reldirs) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py index 22438ad3c9f..495a813c64f 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py @@ -5,12 +5,13 @@ import web_idl from . import name_style -from .code_node import CodeNode +from .code_node import Likeliness from .code_node import SymbolDefinitionNode from .code_node import SymbolNode -from .code_node import SymbolScopeNode from .code_node import TextNode -from .code_node import UnlikelyExitNode +from .code_node_cxx import CxxIfElseNode +from .code_node_cxx import CxxLikelyIfNode +from .code_node_cxx import CxxUnlikelyIfNode from .codegen_format import format_template as _format @@ -18,17 +19,32 @@ def blink_class_name(idl_definition): """ Returns the class name of Blink implementation. """ - try: - class_name = idl_definition.extended_attributes.get( - "ImplementedAs").value - except: - class_name = idl_definition.identifier - + class_name = idl_definition.code_generator_info.receiver_implemented_as + if class_name: + return class_name + + assert idl_definition.identifier[0].isupper() + # Do not apply |name_style.class_| in order to respect the original name + # (Web spec'ed name) as much as possible. For example, |interface EXTsRGB| + # is implemented as |class EXTsRGB|, not as |ExtSRgb| nor |ExtsRgb|. if isinstance(idl_definition, - (web_idl.CallbackFunction, web_idl.CallbackInterface)): - return name_style.class_("v8", class_name) + (web_idl.CallbackFunction, web_idl.CallbackInterface, + web_idl.Enumeration)): + return "V8{}".format(idl_definition.identifier) else: - return name_style.class_(class_name) + return idl_definition.identifier + + +def v8_bridge_class_name(idl_definition): + """ + Returns the name of V8-from/to-Blink bridge class. + """ + assert isinstance(idl_definition, (web_idl.Namespace, web_idl.Interface)) + + assert idl_definition.identifier[0].isupper() + # Do not apply |name_style.class_| due to the same reason as + # |blink_class_name|. + return "V8{}".format(idl_definition.identifier) def blink_type_info(idl_type): @@ -39,10 +55,11 @@ def blink_type_info(idl_type): member_t: The type of a member variable. E.g. T => Member<T> ref_t: The type of a local variable that references to an already-existing value. E.g. String => String& + const_ref_t: A const-qualified reference type. value_t: The type of a variable that behaves as a value. E.g. String => String - is_nullable: True if the Blink implementation type can represent IDL null - value by itself. + has_null_value: True if the Blink implementation type can represent IDL + null value by itself without use of base::Optional<T>. """ assert isinstance(idl_type, web_idl.IdlType) @@ -51,13 +68,16 @@ def blink_type_info(idl_type): typename, member_fmt="{}", ref_fmt="{}", + const_ref_fmt="const {}", value_fmt="{}", - is_nullable=False): + has_null_value=False): + self.typename = typename self.member_t = member_fmt.format(typename) self.ref_t = ref_fmt.format(typename) + self.const_ref_t = const_ref_fmt.format(typename) self.value_t = value_fmt.format(typename) # Whether Blink impl type can represent IDL null or not. - self.is_nullable = is_nullable + self.has_null_value = has_null_value real_type = idl_type.unwrap(typedef=True) @@ -77,69 +97,150 @@ def blink_type_info(idl_type): "double": "double", "unrestricted double": "double", } - return TypeInfo(cxx_type[real_type.keyword_typename]) + return TypeInfo( + cxx_type[real_type.keyword_typename], const_ref_fmt="{}") if real_type.is_string: - return TypeInfo("String", ref_fmt="{}&", is_nullable=True) + return TypeInfo( + "String", + ref_fmt="{}&", + const_ref_fmt="const {}&", + value_fmt="bindings::NativeValueTraitsStringAdapter", + has_null_value=True) + + if real_type.is_array_buffer: + assert "AllowShared" not in real_type.extended_attributes + return TypeInfo( + 'DOM{}'.format(real_type.keyword_typename), + member_fmt="Member<{}>", + ref_fmt="{}*", + const_ref_fmt="const {}*", + value_fmt="{}*", + has_null_value=True) + + if real_type.is_buffer_source_type: + if "FlexibleArrayBufferView" in real_type.extended_attributes: + assert "AllowShared" in real_type.extended_attributes + return TypeInfo( + "Flexible{}".format(real_type.keyword_typename), + member_fmt="void", + ref_fmt="{}", + const_ref_fmt="const {}", + value_fmt="{}", + has_null_value=True) + elif "AllowShared" in real_type.extended_attributes: + return TypeInfo( + "MaybeShared<DOM{}>".format(real_type.keyword_typename), + has_null_value=True) + else: + return TypeInfo( + "NotShared<DOM{}>".format(real_type.keyword_typename), + has_null_value=True) if real_type.is_symbol: assert False, "Blink does not support/accept IDL symbol type." if real_type.is_any or real_type.is_object: - return TypeInfo("ScriptValue", ref_fmt="{}&", is_nullable=True) + return TypeInfo( + "ScriptValue", + ref_fmt="{}&", + const_ref_fmt="const {}&", + has_null_value=True) if real_type.is_void: assert False, "Blink does not support/accept IDL void type." + if real_type.is_enumeration: + blink_impl_type = blink_class_name(real_type.type_definition_object) + return TypeInfo(blink_impl_type) + if real_type.type_definition_object is not None: - type_def_obj = real_type.type_definition_object - blink_impl_type = ( - type_def_obj.code_generator_info.receiver_implemented_as - or name_style.class_(type_def_obj.identifier)) + blink_impl_type = blink_class_name(real_type.type_definition_object) return TypeInfo( blink_impl_type, member_fmt="Member<{}>", ref_fmt="{}*", + const_ref_fmt="const {}*", value_fmt="{}*", - is_nullable=True) + has_null_value=True) if (real_type.is_sequence or real_type.is_frozen_array or real_type.is_variadic): - element_type = blink_type_info(real_type.element_type) + element_type = real_type.element_type + element_type_info = blink_type_info(real_type.element_type) + if element_type.type_definition_object is not None: + # In order to support recursive IDL data structures, we have to + # avoid recursive C++ header inclusions and utilize C++ forward + # declarations. Since |VectorOf| requires complete type + # definition, |HeapVector<Member<T>>| is preferred as it + # requires only forward declaration. + vector_fmt = "HeapVector<Member<{}>>" + else: + vector_fmt = "VectorOf<{}>" return TypeInfo( - "VectorOf<{}>".format(element_type.value_t), ref_fmt="{}&") + vector_fmt.format(element_type_info.typename), + ref_fmt="{}&", + const_ref_fmt="const {}&") if real_type.is_record: key_type = blink_type_info(real_type.key_type) value_type = blink_type_info(real_type.value_type) return TypeInfo( - "VectorOfPairs<{}, {}>".format(key_type.value_t, - value_type.value_t), - ref_fmt="{}&") + "VectorOfPairs<{}, {}>".format(key_type.typename, + value_type.typename), + ref_fmt="{}&", + const_ref_fmt="const {}&") if real_type.is_promise: - return TypeInfo("ScriptPromise", ref_fmt="{}&") + return TypeInfo( + "ScriptPromise", ref_fmt="{}&", const_ref_fmt="const {}&") if real_type.is_union: - return TypeInfo("ToBeImplementedUnion") + blink_impl_type = blink_class_name(real_type.union_definition_object) + return TypeInfo( + blink_impl_type, + ref_fmt="{}&", + const_ref_fmt="const {}&", + has_null_value=True) if real_type.is_nullable: inner_type = blink_type_info(real_type.inner_type) - if inner_type.is_nullable: + if inner_type.has_null_value: return inner_type return TypeInfo( - "base::Optional<{}>".format(inner_type.value_t), ref_fmt="{}&") + "base::Optional<{}>".format(inner_type.value_t), + ref_fmt="{}&", + const_ref_fmt="const {}&") + + assert False, "Unknown type: {}".format(idl_type.syntactic_form) def native_value_tag(idl_type): """Returns the tag type of NativeValueTraits.""" assert isinstance(idl_type, web_idl.IdlType) + if idl_type.is_typedef: + if idl_type.identifier in ("EventHandler", + "OnBeforeUnloadEventHandler", + "OnErrorEventHandler"): + return "IDL{}".format(idl_type.identifier) + real_type = idl_type.unwrap(typedef=True) - if (real_type.is_boolean or real_type.is_numeric or real_type.is_string - or real_type.is_any or real_type.is_object): - return "IDL{}".format(real_type.type_name) + if (real_type.is_boolean or real_type.is_numeric or real_type.is_any + or real_type.is_object): + return "IDL{}".format( + idl_type.type_name_with_extended_attribute_key_values) + + if real_type.is_string: + return "IDL{}V2".format( + idl_type.type_name_with_extended_attribute_key_values) + + if real_type.is_array_buffer: + return blink_type_info(real_type).typename + + if real_type.is_buffer_source_type: + return blink_type_info(real_type).value_t if real_type.is_symbol: assert False, "Blink does not support/accept IDL symbol type." @@ -147,13 +248,16 @@ def native_value_tag(idl_type): if real_type.is_void: assert False, "Blink does not support/accept IDL void type." - if real_type.type_definition_object is not None: - return blink_type_info(real_type).value_t + if real_type.type_definition_object: + return blink_class_name(real_type.type_definition_object) if real_type.is_sequence: return "IDLSequence<{}>".format( native_value_tag(real_type.element_type)) + if real_type.is_frozen_array: + return "IDLArray<{}>".format(native_value_tag(real_type.element_type)) + if real_type.is_record: return "IDLRecord<{}, {}>".format( native_value_tag(real_type.key_type), @@ -168,10 +272,140 @@ def native_value_tag(idl_type): if real_type.is_nullable: return "IDLNullable<{}>".format(native_value_tag(real_type.inner_type)) + assert False, "Unknown type: {}".format(idl_type.syntactic_form) + + +def make_default_value_expr(idl_type, default_value): + """ + Returns a set of C++ expressions to be used for initialization with default + values. The returned object has the following attributes. + + initializer: Used as "Type var(|initializer|);". This is None if + "Type var;" sets an appropriate default value. + assignment_value: Used as "var = |assignment_value|;". + """ + assert default_value.is_type_compatible_with(idl_type) + + class DefaultValueExpr: + def __init__(self, initializer, is_initializer_lightweight, + assignment_value): + assert initializer is None or isinstance(initializer, str) + assert isinstance(is_initializer_lightweight, bool) + assert isinstance(assignment_value, str) + self.initializer = initializer + self.is_initializer_lightweight = is_initializer_lightweight + self.assignment_value = assignment_value + + if idl_type.unwrap(typedef=True).is_union: + union_type = idl_type.unwrap(typedef=True) + member_type = None + for member_type in union_type.flattened_member_types: + if default_value.is_type_compatible_with(member_type): + member_type = member_type + break + assert member_type is not None + + union_class_name = blink_class_name(union_type.union_definition_object) + member_default_expr = make_default_value_expr(member_type, + default_value) + if default_value.idl_type.is_nullable: + initializer = None + assignment_value = _format("{}()", union_class_name) + else: + func_name = name_style.func("From", member_type.type_name) + argument = member_default_expr.assignment_value + initializer = _format("{}::{}({})", union_class_name, func_name, + argument) + assignment_value = initializer + return DefaultValueExpr( + initializer=initializer, + is_initializer_lightweight=False, + assignment_value=assignment_value) + + type_info = blink_type_info(idl_type) + + is_initializer_lightweight = False + if default_value.idl_type.is_nullable: + if idl_type.unwrap().type_definition_object is not None: + initializer = "nullptr" + is_initializer_lightweight = True + assignment_value = "nullptr" + elif idl_type.unwrap().is_string: + initializer = None # String::IsNull() by default + assignment_value = "String()" + elif idl_type.unwrap().is_buffer_source_type: + initializer = "nullptr" + is_initializer_lightweight = True + assignment_value = "nullptr" + elif type_info.value_t == "ScriptValue": + initializer = None # ScriptValue::IsEmpty() by default + assignment_value = "ScriptValue()" + elif idl_type.unwrap().is_union: + initializer = None # <union_type>::IsNull() by default + assignment_value = "{}()".format(type_info.value_t) + else: + assert not type_info.has_null_value + initializer = None # !base::Optional::has_value() by default + assignment_value = "base::nullopt" + elif default_value.idl_type.is_sequence: + initializer = None # VectorOf<T>::size() == 0 by default + assignment_value = "{}()".format(type_info.value_t) + elif default_value.idl_type.is_object: + dict_name = blink_class_name(idl_type.unwrap().type_definition_object) + value = _format("{}::Create()", dict_name) + initializer = value + assignment_value = value + elif default_value.idl_type.is_boolean: + value = "true" if default_value.value else "false" + initializer = value + is_initializer_lightweight = True + assignment_value = value + elif default_value.idl_type.is_integer: + initializer = default_value.literal + is_initializer_lightweight = True + assignment_value = default_value.literal + elif default_value.idl_type.is_floating_point_numeric: + if default_value.value == float("NaN"): + value_fmt = "std::numeric_limits<{type}>::quiet_NaN()" + elif default_value.value == float("Infinity"): + value_fmt = "std::numeric_limits<{type}>::infinity()" + elif default_value.value == float("-Infinity"): + value_fmt = "-std::numeric_limits<{type}>::infinity()" + else: + value_fmt = "{value}" + value = value_fmt.format( + type=type_info.value_t, value=default_value.literal) + initializer = value + is_initializer_lightweight = True + assignment_value = value + elif default_value.idl_type.is_string: + if idl_type.unwrap().is_string: + value = "\"{}\"".format(default_value.value) + initializer = value + assignment_value = value + elif idl_type.unwrap().is_enumeration: + enum_class_name = blink_class_name( + idl_type.unwrap().type_definition_object) + enum_value_name = name_style.constant(default_value.value) + initializer = "{}::Enum::{}".format(enum_class_name, + enum_value_name) + is_initializer_lightweight = True + assignment_value = "{}({})".format(enum_class_name, initializer) + else: + assert False + else: + assert False + + return DefaultValueExpr( + initializer=initializer, + is_initializer_lightweight=is_initializer_lightweight, + assignment_value=assignment_value) + def make_v8_to_blink_value(blink_var_name, v8_value_expr, idl_type, + argument_index=None, default_value=None): """ Returns a SymbolNode whose definition converts a v8::Value to a Blink value. @@ -179,23 +413,71 @@ def make_v8_to_blink_value(blink_var_name, assert isinstance(blink_var_name, str) assert isinstance(v8_value_expr, str) assert isinstance(idl_type, web_idl.IdlType) + assert (argument_index is None or isinstance(argument_index, (int, long))) assert (default_value is None or isinstance(default_value, web_idl.LiteralConstant)) - pattern = ( - "const auto& ${{{_1}}} = NativeValueTraits<{_2}>::NativeValue({_3});") - _1 = blink_var_name - _2 = native_value_tag(idl_type) - _3 = ["${isolate}", v8_value_expr, "${exception_state}"] - text = _format(pattern, _1=_1, _2=_2, _3=", ".join(_3)) + T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) def create_definition(symbol_node): - return SymbolDefinitionNode(symbol_node, [ - TextNode(text), - UnlikelyExitNode( - cond=TextNode("${exception_state}.HadException()"), - body=SymbolScopeNode([TextNode("return;")])), - ]) + if argument_index is None: + func_name = "NativeValue" + arguments = ["${isolate}", v8_value_expr, "${exception_state}"] + else: + func_name = "ArgumentValue" + arguments = [ + "${isolate}", + str(argument_index), + v8_value_expr, + "${exception_state}", + ] + if "StringContext" in idl_type.effective_annotations: + arguments.append("${execution_context_of_document_tree}") + blink_value_expr = _format( + "NativeValueTraits<{_1}>::{_2}({_3})", + _1=native_value_tag(idl_type), + _2=func_name, + _3=", ".join(arguments)) + + if default_value is None: + return SymbolDefinitionNode(symbol_node, [ + F("auto&& ${{{}}} = {};", blink_var_name, blink_value_expr), + CxxUnlikelyIfNode( + cond="${exception_state}.HadException()", + body=T("return;")), + ]) + + nodes = [] + type_info = blink_type_info(idl_type) + default_expr = make_default_value_expr(idl_type, default_value) + if default_expr.is_initializer_lightweight: + nodes.append( + F("{} ${{{}}}{{{}}};", type_info.value_t, blink_var_name, + default_expr.initializer)) + else: + nodes.append(F("{} ${{{}}};", type_info.value_t, blink_var_name)) + assignment = [ + F("${{{}}} = {};", blink_var_name, blink_value_expr), + CxxUnlikelyIfNode( + cond="${exception_state}.HadException()", body=T("return;")), + ] + if (default_expr.initializer is None + or default_expr.is_initializer_lightweight): + nodes.append( + CxxLikelyIfNode( + cond="!{}->IsUndefined()".format(v8_value_expr), + body=assignment)) + else: + nodes.append( + CxxIfElseNode( + cond="{}->IsUndefined()".format(v8_value_expr), + then=F("${{{}}} = {};", blink_var_name, + default_expr.assignment_value), + then_likeliness=Likeliness.LIKELY, + else_=assignment, + else_likeliness=Likeliness.LIKELY)) + return SymbolDefinitionNode(symbol_node, nodes) return SymbolNode(blink_var_name, definition_constructor=create_definition) @@ -211,18 +493,26 @@ def make_v8_to_blink_value_variadic(blink_var_name, v8_array, assert isinstance(v8_array_start_index, (int, long)) assert isinstance(idl_type, web_idl.IdlType) - pattern = "const auto& ${{{_1}}} = ToImplArguments<{_2}>({_3});" - _1 = blink_var_name - _2 = native_value_tag(idl_type.element_type) - _3 = [v8_array, str(v8_array_start_index), "${exception_state}"] - text = _format(pattern, _1=_1, _2=_2, _3=", ".join(_3)) + pattern = ("auto&& ${{{_1}}} = " + "bindings::VariadicArgumentsToNativeValues<{_2}>({_3});") + arguments = [ + "${isolate}", v8_array, + str(v8_array_start_index), "${exception_state}" + ] + if "StringContext" in idl_type.element_type.effective_annotations: + arguments.append("${execution_context_of_document_tree}") + text = _format( + pattern, + _1=blink_var_name, + _2=native_value_tag(idl_type.element_type), + _3=", ".join(arguments)) def create_definition(symbol_node): return SymbolDefinitionNode(symbol_node, [ TextNode(text), - UnlikelyExitNode( - cond=TextNode("${exception_state}.HadException()"), - body=SymbolScopeNode([TextNode("return;")])), + CxxUnlikelyIfNode( + cond="${exception_state}.HadException()", + body=TextNode("return;")), ]) return SymbolNode(blink_var_name, definition_constructor=create_definition) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py deleted file mode 100644 index ac060bc80da..00000000000 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2019 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os.path -import subprocess - -_clang_format_command_path = None - - -def init(command_path): - """ - Args: - command_path: Path to the clang_format command. - """ - assert isinstance(command_path, str) - assert os.path.exists(command_path) - - global _clang_format_command_path - assert _clang_format_command_path is None - _clang_format_command_path = command_path - - -def clang_format(contents, filename=None): - command_line = [_clang_format_command_path] - if filename is not None: - command_line.append('-assume-filename={}'.format(filename)) - - proc = subprocess.Popen( - command_line, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - stdout_output, stderr_output = proc.communicate(input=contents) - exit_code = proc.wait() - - return ClangFormatResult( - stdout_output=stdout_output, - stderr_output=stderr_output, - exit_code=exit_code, - filename=filename) - - -class ClangFormatResult(object): - def __init__(self, stdout_output, stderr_output, exit_code, filename): - self._stdout_output = stdout_output - self._stderr_output = stderr_output - self._exit_code = exit_code - self._filename = filename - - @property - def did_succeed(self): - return self._exit_code == 0 - - @property - def contents(self): - assert self.did_succeed - return self._stdout_output - - @property - def error_message(self): - return self._stderr_output - - @property - def filename(self): - return self._filename diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py index 53fe4fe1fce..2e29538399c 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py @@ -8,11 +8,34 @@ provides a collection of the classes that represent code nodes independent from specific bindings, such as ECMAScript bindings. """ -import copy - from .codegen_accumulator import CodeGenAccumulator from .codegen_format import format_template from .mako_renderer import MakoRenderer +from .mako_renderer import MakoTemplate + + +def render_code_node(code_node): + """ + Renders |code_node| and turns it into text letting |code_node| apply all + necessary changes (side effects). Returns the resulting text. + """ + assert isinstance(code_node, CodeNode) + assert code_node.outer is None + + renderer = code_node.renderer + accumulator = code_node.accumulator + + accumulated_size = accumulator.total_size() + while True: + prev_accumulated_size = accumulated_size + renderer.reset() + code_node.render(renderer) + accumulated_size = accumulator.total_size() + if (renderer.is_rendering_complete() + and accumulated_size == prev_accumulated_size): + break + + return renderer.to_text() class Likeliness(object): @@ -58,10 +81,15 @@ class CodeNode(object): """ def __init__(self): - # Symbols used in generated code, but not yet defined. See also - # SymbolNode. Code symbols are accumulated in order from the first - # appearance to the last. This order affects the insertion order of - # SymbolDefinitionNodes at SymbolScopeNode. + # List of SymbolNodes that are defined at this point of rendering. + # Used to determine whether a certain symbol is already defined by + # this point of rendering. + self.defined_code_symbols = [] + + # List of SymbolNodes that are not yet defined at this point of + # rendering. SymbolNodes are accumulated in order of their first + # appearance. The order affects the insertion order of + # SymbolDefinitionNodes. self.undefined_code_symbols = [] # Dict from a SymbolNode to a set of tuples of SymbolScopeNodes @@ -89,7 +117,7 @@ class CodeNode(object): # (Scope1, Scope2A, Scope3), # [1] # (Scope1, Scope2B), # [4] # ]) - self.undefined_code_symbols_scope_chains = {} + self.symbol_to_scope_chains = {} _gensym_seq_id = 0 @@ -135,11 +163,18 @@ class CodeNode(object): self._prev = None # Mako's template text, bindings dict - self._template_text = template_text - self._template_vars = {} + if template_text is None: + self._template = None + else: + self._template = MakoTemplate(template_text) + + # Template variable bindings + self._own_template_vars = None + self._base_template_vars = None + self._cached_template_vars = None self._accumulator = None # CodeGenAccumulator - self._accumulate_requests = [] + self._accumulate_requests = None self._renderer = None # MakoRenderer @@ -151,36 +186,42 @@ class CodeNode(object): def __str__(self): """ - Renders this CodeNode object into a Mako template. This is supposed to - be used in a Mako template as ${code_node}. + Renders this CodeNode object directly into the renderer's text buffer + and always returns the empty string. This is because it's faster to + accumulate the rendering result directly in a single text buffer than + making a lot of string pieces and concatenating them. + + This function is supposed to be used in a Mako template as ${code_node}. """ - return self.render() + renderer = self.renderer + assert renderer - def render(self): + self.render(renderer) + return "" + + def render(self, renderer): """ Renders this CodeNode object as a text string and also propagates updates to related CodeNode objects. As this method has side-effects not only to this object but also other related objects, the resulting text may change on each invocation. """ - assert self.renderer - last_render_state = self._render_state self._render_state = CodeNode._RenderState() self._is_rendering = True try: - text = self._render( - renderer=self.renderer, last_render_state=last_render_state) + self._render( + renderer=renderer, last_render_state=last_render_state) finally: self._is_rendering = False if self._accumulate_requests: - assert self.accumulator + accumulator = self.accumulator + assert accumulator for request in self._accumulate_requests: - request(self.accumulator) - - return text + request(accumulator) + self._accumulate_requests = None def _render(self, renderer, last_render_state): """ @@ -189,10 +230,9 @@ class CodeNode(object): Only limited subclasses may override this method. """ - assert self._template_text is not None - return renderer.render( + renderer.render( caller=self, - template_text=self._template_text, + template=self._template, template_vars=self.template_vars) @property @@ -223,65 +263,112 @@ class CodeNode(object): assert isinstance(prev, CodeNode) or prev is None self._prev = prev - @property - def upstream_of_scope(self): - """ - Returns the upstream CodeNode in the same or outer scope. Only the set - of recursively-collected |upstream_of_scope|s can bring symbol - definitions effective to this node. - """ - if self.prev is None: - return self.outer - - node = self.prev - while isinstance(node, SequenceNode): + def outer_scope(self): + """Returns the outer scope closest to this scope or None.""" + node = self.outer + while node is not None: if isinstance(node, SymbolScopeNode): - return node.upstream_of_scope - if not node: - break - node = node[-1] + return node + node = node.outer + return None + + def outermost(self): + """Returns the outermost node, i.e. the node whose |outer| is None.""" + node = self + while node.outer is not None: + node = node.outer return node + def inclusive_outers(self): + """ + Returns a list of outer nodes including this node in order from this + node to the outermost node. + """ + outers = [] + node = self + while node is not None: + outers.append(node) + node = node.outer + return outers + @property def template_vars(self): """ Returns the template variable bindings available at this point, i.e. bound at this node or outer nodes. - CAUTION: Do not modify the returned dict. This method may return the - original dict in a CodeNode. + CAUTION: This accessor caches the result. This accessor must not be + called during construction of a code node tree. """ - if not self.outer: - return self._template_vars + if self._cached_template_vars is not None: + return self._cached_template_vars - if not self._template_vars: - return self.outer.template_vars + outers = self.inclusive_outers() + bindings = None - binds = copy.copy(self.outer.template_vars) - for name, value in self._template_vars.iteritems(): - assert name not in binds, ( - "Duplicated template variable binding: {}".format(name)) - binds[name] = value - return binds + for node in outers: + if node.base_template_vars is not None: + bindings = dict(node.base_template_vars) + break + if bindings is None: + bindings = {} + + for node in outers: + if node.own_template_vars is None: + continue + for name, value in node.own_template_vars.items(): + assert name not in bindings, ( + "Duplicated template variable binding: {}".format(name)) + bindings[name] = value + + self._cached_template_vars = bindings + return self._cached_template_vars + + @property + def own_template_vars(self): + """Returns the template variables bound at this code node.""" + return self._own_template_vars def add_template_var(self, name, value): - assert name not in self._template_vars, ( + if self._own_template_vars is None: + self._own_template_vars = {} + assert isinstance(name, str) + assert name not in self._own_template_vars, ( "Duplicated template variable binding: {}".format(name)) if isinstance(value, CodeNode): value.set_outer(self) - self._template_vars[name] = value + self._own_template_vars[name] = value def add_template_vars(self, template_vars): assert isinstance(template_vars, dict) - for name, value in template_vars.iteritems(): + for name, value in template_vars.items(): self.add_template_var(name, value) @property + def base_template_vars(self): + """ + Returns the base template variables if it's set at this code node. + + The base template variables are a set of template variables that of + the innermost code node takes effect. It means that the base template + variables are layered and shadowable. + """ + return self._base_template_vars + + def set_base_template_vars(self, template_vars): + assert isinstance(template_vars, dict) + for name, value in template_vars.items(): + assert isinstance(name, str) + assert not isinstance(value, CodeNode) + assert self._base_template_vars is None + self._base_template_vars = template_vars + + @property def accumulator(self): # Always consistently use the accumulator of the root node. - if self.outer is not None: - return self.outer.accumulator - return self._accumulator + if self.outer is None: + return self._accumulator + return self.outermost().accumulator def set_accumulator(self, accumulator): assert isinstance(accumulator, CodeGenAccumulator) @@ -294,15 +381,16 @@ class CodeNode(object): argument of self.accumulator. """ assert callable(request) + if self._accumulate_requests is None: + self._accumulate_requests = [] self._accumulate_requests.append(request) @property def renderer(self): - # Always use the renderer of the root node in order not to mix renderers - # during rendering of a single code node tree. - if self.outer is not None: - return self.outer.renderer - return self._renderer + # Always consistently use the renderer of the root node. + if self.outer is None: + return self._renderer + return self.outermost().renderer def set_renderer(self, renderer): assert isinstance(renderer, MakoRenderer) @@ -319,53 +407,68 @@ class CodeNode(object): assert not self._is_rendering return self._render_state - def is_code_symbol_defined(self, symbol_node): - """ - Returns True if |symbol_node| is defined at this point or upstream. - """ - if self.outer: - return self.upstream_of_scope.is_code_symbol_defined(symbol_node) - return False - - def is_code_symbol_registered(self, symbol_node): - """ - Returns True if |symbol_node| is registered and available for use at - this point. See also |SymbolScopeNode.register_code_symbol|. - """ - if self.outer is not None: - return self.outer.is_code_symbol_registered(symbol_node) - return False - - def on_undefined_code_symbol_found(self, symbol_node, symbol_scope_chain): - """Receives a report of use of an undefined symbol node.""" + def on_code_symbol_referenced(self, symbol_node, symbol_scope_chain): + """Receives a report of use of a symbol node.""" assert isinstance(symbol_node, SymbolNode) assert isinstance(symbol_scope_chain, tuple) assert all( isinstance(scope, SymbolScopeNode) for scope in symbol_scope_chain) - state = self.current_render_state - if symbol_node not in state.undefined_code_symbols: - state.undefined_code_symbols.append(symbol_node) - state.undefined_code_symbols_scope_chains.setdefault( + self.current_render_state.symbol_to_scope_chains.setdefault( symbol_node, set()).add(symbol_scope_chain) +class EmptyNode(CodeNode): + """Represents the zero-length text and renders nothing.""" + + def __init__(self): + CodeNode.__init__(self) + + def _render(self, renderer, last_render_state): + pass + + class LiteralNode(CodeNode): """ Represents a literal text, which will be rendered as is without any template - magic applied. + magic applied. The given literal text object will be stringified on each + rendering. """ def __init__(self, literal_text): - literal_text_gensym = CodeNode.gensym() - template_text = format_template( - "${{{literal_text}}}", literal_text=literal_text_gensym) - template_vars = {literal_text_gensym: literal_text} + CodeNode.__init__(self) - CodeNode.__init__( - self, template_text=template_text, template_vars=template_vars) + self._literal_text = literal_text + + def _render(self, renderer, last_render_state): + renderer.push_caller(self) + try: + renderer.render_text(str(self._literal_text)) + finally: + renderer.pop_caller() + + +def TextNode(template_text): + """ + Represents a template text node. + TextNode is designed to be a leaf node of a code node tree. TextNode + represents a template text while LiteralNode represents a literal text. + All template magics will be applied to |template_text|. -class TextNode(CodeNode): + This function is pretending to be a CodeNode subclass and instantiates one + of text-ish code node subclass depending on the content of |template_text|. + """ + assert isinstance(template_text, str) + + if "$" in template_text or "%" in template_text: + return _TextNode(template_text) + elif template_text: + return LiteralNode(template_text) + else: + return EmptyNode() + + +class _TextNode(CodeNode): """ Represents a template text node. @@ -404,7 +507,7 @@ class CompositeNode(CodeNode): gensym = CodeNode.gensym() gensym_args.append("${{{}}}".format(gensym)) template_vars[gensym] = arg - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): assert isinstance(key, (int, long, str)) assert isinstance(value, (CodeNode, int, long, str)) gensym = CodeNode.gensym() @@ -425,31 +528,27 @@ class ListNode(CodeNode): except that addition and removal of None have no effect. """ - def __init__(self, code_nodes=None, separator=" ", separator_last=""): + def __init__(self, code_nodes=None, separator="\n", head="", tail=""): + """ + Args: + code_nodes: A list of CodeNode to be rendered. + separator: A str inserted between code nodes. + head: + tail: The head and tail sections that will be rendered iff the + content list is not empty. + """ assert isinstance(separator, str) - assert isinstance(separator_last, str) - - element_nodes_gensym = CodeNode.gensym() - element_nodes = [] - template_text = format_template( - """\ -% for node in {element_nodes}: -${node}\\ -% if not loop.last: -{separator}\\ -% endif -% endfor -{separator_last}\\ -""", - element_nodes=element_nodes_gensym, - separator=separator, - separator_last=separator_last) - template_vars = {element_nodes_gensym: element_nodes} + assert isinstance(head, str) + assert isinstance(tail, str) - CodeNode.__init__( - self, template_text=template_text, template_vars=template_vars) + CodeNode.__init__(self) - self._element_nodes = element_nodes + self._element_nodes = [] + self._separator = separator + self._head = head + self._tail = tail + + self._will_skip_separator = False if code_nodes is not None: self.extend(code_nodes) @@ -463,6 +562,26 @@ ${node}\\ def __len__(self): return len(self._element_nodes) + def _render(self, renderer, last_render_state): + renderer.push_caller(self) + try: + if self._element_nodes: + renderer.render_text(self._head) + self._will_skip_separator = True + for node in self._element_nodes: + if self._will_skip_separator: + self._will_skip_separator = False + else: + renderer.render_text(self._separator) + node.render(renderer) + if self._element_nodes: + renderer.render_text(self._tail) + finally: + renderer.pop_caller() + + def skip_separator(self): + self._will_skip_separator = True + def append(self, node): if node is None: return @@ -523,25 +642,30 @@ class SequenceNode(ListNode): and provides the points where SymbolDefinitionNodes can be inserted. """ - def __init__(self, code_nodes=None, separator="\n", separator_last=""): + def __init__(self, code_nodes=None, separator="\n", head="", tail=""): ListNode.__init__( self, code_nodes=code_nodes, separator=separator, - separator_last=separator_last) + head=head, + tail=tail) + + self._to_be_removed = [] def _render(self, renderer, last_render_state): - duplicates = [] - for element_node in self: - if (isinstance(element_node, SymbolDefinitionNode) - and element_node.is_duplicated()): - duplicates.append(element_node) - for element_node in duplicates: - self.remove(element_node) - - return super(SequenceNode, self)._render( + if self._to_be_removed: + for node in self._to_be_removed: + self.remove(node) + self._to_be_removed = [] + + super(SequenceNode, self)._render( renderer=renderer, last_render_state=last_render_state) + def schedule_to_remove(self, node): + """Schedules a task to remove the |node| in the next rendering cycle.""" + assert node in self + self._to_be_removed.append(node) + class SymbolScopeNode(SequenceNode): """ @@ -551,52 +675,72 @@ class SymbolScopeNode(SequenceNode): insert corresponding SymbolDefinitionNodes appropriately. """ - def __init__(self, code_nodes=None, separator="\n", separator_last=""): + def __init__(self, code_nodes=None, separator="\n", head="", tail=""): SequenceNode.__init__( self, code_nodes=code_nodes, separator=separator, - separator_last=separator_last) + head=head, + tail=tail) self._likeliness = Likeliness.ALWAYS self._registered_code_symbols = set() def _render(self, renderer, last_render_state): for symbol_node in last_render_state.undefined_code_symbols: - if (self.is_code_symbol_registered(symbol_node) - and not self.is_code_symbol_defined(symbol_node)): + assert self.is_code_symbol_registered(symbol_node) + if not self.is_code_symbol_defined(symbol_node): self._insert_symbol_definition(symbol_node, last_render_state) - return super(SymbolScopeNode, self)._render( + super(SymbolScopeNode, self)._render( renderer=renderer, last_render_state=last_render_state) + if self.current_render_state.undefined_code_symbols: + renderer.invalidate_rendering_result() + def _insert_symbol_definition(self, symbol_node, last_render_state): - def count_by_likeliness(render_state): - counts = { - Likeliness.UNLIKELY: 0, - Likeliness.LIKELY: 0, - Likeliness.ALWAYS: 0, - } - - scope_chains = (render_state.undefined_code_symbols_scope_chains. - get(symbol_node)) + DIRECT_USES = "u" + DIRECT_CHILD_SCOPES = "s" + ANALYSIS_RESULT_KEYS = ( + # Number of direct uses in this scope + DIRECT_USES, + # Number of direct child scopes + DIRECT_CHILD_SCOPES, + # Number of direct child scopes per likeliness + Likeliness.ALWAYS, + Likeliness.LIKELY, + Likeliness.UNLIKELY, + ) + + def analyze_symbol_usage(render_state): + counts = dict.fromkeys(ANALYSIS_RESULT_KEYS, 0) + + scope_chains = render_state.symbol_to_scope_chains.get(symbol_node) if not scope_chains: return counts self_index = iter(scope_chains).next().index(self) scope_chains = map( lambda scope_chain: scope_chain[self_index + 1:], scope_chains) + scope_to_likeliness = {} for scope_chain in scope_chains: if not scope_chain: - counts[Likeliness.ALWAYS] += 1 + counts[DIRECT_USES] += 1 else: likeliness = min( map(lambda scope: scope.likeliness, scope_chain)) - counts[likeliness] += 1 + scope = scope_chain[0] + scope_to_likeliness[scope] = max( + likeliness, scope_to_likeliness.get(scope, likeliness)) + for likeliness in scope_to_likeliness.values(): + counts[DIRECT_CHILD_SCOPES] += 1 + counts[likeliness] += 1 return counts def likeliness_at(render_state): - counts = count_by_likeliness(render_state) + counts = analyze_symbol_usage(render_state) + if counts[DIRECT_USES] >= 1: + return Likeliness.ALWAYS for likeliness in (Likeliness.ALWAYS, Likeliness.LIKELY, Likeliness.UNLIKELY): if counts[likeliness] > 0: @@ -616,21 +760,32 @@ class SymbolScopeNode(SequenceNode): return True return False - counts = count_by_likeliness(last_render_state) - if counts[Likeliness.ALWAYS] >= 1: + counts = analyze_symbol_usage(last_render_state) + if counts[DIRECT_USES] >= 1: did_insert = insert_before_threshold(self, Likeliness.UNLIKELY) assert did_insert - elif counts[Likeliness.LIKELY] >= 2: + elif counts[DIRECT_CHILD_SCOPES] == 1: + pass # Let the child SymbolScopeNode do the work. + elif counts[Likeliness.ALWAYS] + counts[Likeliness.LIKELY] >= 2: did_insert = insert_before_threshold(self, Likeliness.LIKELY) assert did_insert else: - pass # Do nothing and let descendant SymbolScopeNodes do the work. + pass # Let descendant SymbolScopeNodes do the work. def is_code_symbol_registered(self, symbol_node): + """ + Returns True if |symbol_node| is registered and available for use within + this scope. + """ + assert isinstance(symbol_node, SymbolNode) + if symbol_node in self._registered_code_symbols: return True - return super(SymbolScopeNode, - self).is_code_symbol_registered(symbol_node) + + outer = self.outer_scope() + if outer is None: + return False + return outer.is_code_symbol_registered(symbol_node) def register_code_symbol(self, symbol_node): """Registers a SymbolNode and makes it available in this scope.""" @@ -655,6 +810,33 @@ class SymbolScopeNode(SequenceNode): assert isinstance(likeliness, Likeliness.Level) self._likeliness = likeliness + def is_code_symbol_defined(self, symbol_node): + """ + Returns True if |symbol_node| is defined in this scope by the moment + when the method is called. + """ + assert isinstance(symbol_node, SymbolNode) + + if symbol_node in self.current_render_state.defined_code_symbols: + return True + + outer = self.outer_scope() + if outer is None: + return False + return outer.is_code_symbol_defined(symbol_node) + + def on_code_symbol_defined(self, symbol_node): + """Receives a report that a symbol gets defined.""" + assert isinstance(symbol_node, SymbolNode) + self.current_render_state.defined_code_symbols.append(symbol_node) + + def on_undefined_code_symbol_found(self, symbol_node): + """Receives a report of use of an undefined symbol node.""" + assert isinstance(symbol_node, SymbolNode) + state = self.current_render_state + if symbol_node not in state.undefined_code_symbols: + state.undefined_code_symbols.append(symbol_node) + class SymbolNode(CodeNode): """ @@ -676,19 +858,14 @@ class SymbolNode(CodeNode): given. """ assert isinstance(name, str) and name - assert (template_text is not None - or definition_constructor is not None) - assert template_text is None or definition_constructor is None - if template_text is not None: - assert isinstance(template_text, str) - if definition_constructor is not None: - assert callable(definition_constructor) CodeNode.__init__(self) self._name = name if template_text is not None: + assert isinstance(template_text, str) + assert definition_constructor is None def constructor(symbol_node): return SymbolDefinitionNode( @@ -697,19 +874,34 @@ class SymbolNode(CodeNode): self._definition_constructor = constructor else: + assert template_text is None + assert callable(definition_constructor) + self._definition_constructor = definition_constructor def _render(self, renderer, last_render_state): + self._request_symbol_definition(renderer) + + renderer.render_text(self.name) + + def request_symbol_definition(self): + self._request_symbol_definition(self.renderer) + + def _request_symbol_definition(self, renderer): symbol_scope_chain = tuple( filter(lambda node: isinstance(node, SymbolScopeNode), renderer.callers_from_first_to_last)) for caller in renderer.callers_from_last_to_first: - if caller.is_code_symbol_defined(self): + caller.on_code_symbol_referenced(self, symbol_scope_chain) + if caller is self.outer: break - caller.on_undefined_code_symbol_found(self, symbol_scope_chain) - return self.name + if not symbol_scope_chain[-1].is_code_symbol_defined(self): + for scope in reversed(symbol_scope_chain): + scope.on_undefined_code_symbol_found(self) + if scope is self.outer: + break @property def name(self): @@ -719,7 +911,7 @@ class SymbolNode(CodeNode): """Creates a new definition node.""" node = self._definition_constructor(self) assert isinstance(node, SymbolDefinitionNode) - assert node.is_code_symbol_defined(self) + assert node.target_symbol is self return node @@ -739,195 +931,18 @@ class SymbolDefinitionNode(SequenceNode): self._symbol_node = symbol_node def _render(self, renderer, last_render_state): - if self.is_duplicated(): - return "" - - return super(SymbolDefinitionNode, self)._render( - renderer=renderer, last_render_state=last_render_state) - - def is_code_symbol_defined(self, symbol_node): - if symbol_node is self._symbol_node: - return True - return super(SymbolDefinitionNode, - self).is_code_symbol_defined(symbol_node) - - def is_duplicated(self): - return self.upstream_of_scope.is_code_symbol_defined(self._symbol_node) - - -class ConditionalNode(CodeNode): - """ - This is the base class of code nodes that directly contain conditional - execution. Not all the code nodes inside this node will be executed. - """ - - -class CaseBranchNode(ConditionalNode): - """ - Represents a set of nodes that will be conditionally executed. - - This node mostly follows the concept of 'cond' in Lisp, which is a chain of - if - else if - else if - ... - else. - """ - - def __init__(self, clause_nodes): - # clause_nodes = [ - # (conditional_node1, body_node1, likeliness1), - # (conditional_node2, body_node2, likeliness2), - # ..., - # (None, body_nodeN, likelinessN), # Corresponds to 'else { ... }' - # ] - assert False - - -class ConditionalExitNode(ConditionalNode): - """ - Represents a conditional node that always exits whenever the condition - meets. It's not supposed that the body node does not exit. Equivalent to - - if (CONDITIONAL) { BODY } - - where BODY ends with a return statement. - """ - - def __init__(self, cond, body, body_likeliness): - assert isinstance(cond, CodeNode) - assert isinstance(body, SymbolScopeNode) - assert isinstance(body_likeliness, Likeliness.Level) - - gensyms = { - "conditional": CodeNode.gensym(), - "body": CodeNode.gensym(), - } - template_text = format_template( - """\ -if (${{{conditional}}}) {{ - ${{{body}}} -}}\\ -""", **gensyms) - template_vars = { - gensyms["conditional"]: cond, - gensyms["body"]: body, - } - - ConditionalNode.__init__( - self, template_text=template_text, template_vars=template_vars) - - self._cond_node = cond - self._body_node = body - self._body_node.set_likeliness(body_likeliness) - - -class LikelyExitNode(ConditionalExitNode): - """ - Represents a conditional exit node where it's likely that the condition - meets. - """ - - def __init__(self, cond, body): - ConditionalExitNode.__init__( - self, cond=cond, body=body, body_likeliness=Likeliness.LIKELY) - - -class UnlikelyExitNode(ConditionalExitNode): - """ - Represents a conditional exit node where it's unlikely that the condition - meets. - """ - - def __init__(self, cond, body): - ConditionalExitNode.__init__( - self, cond=cond, body=body, body_likeliness=Likeliness.UNLIKELY) - - -class FunctionDefinitionNode(CodeNode): - """Represents a function definition.""" - - def __init__(self, - name, - arg_decls, - return_type, - member_initializer_list=None, - local_vars=None, - body=None, - comment=None): - """ - Args: - name: Function name node, which may include nested-name-specifier - (i.e. 'namespace_name::' and/or 'type_name::'). - arg_decls: List of argument declaration nodes. - return_type: Return type node. - member_initializer_list: List of initializer nodes. - local_vars: List of SymbolNodes that can be used in the function - body. - body: Function body node (of type SymbolScopeNode). - comment: Function header comment node. - """ - assert isinstance(name, CodeNode) - assert isinstance(arg_decls, (list, tuple)) - assert all(isinstance(arg_decl, CodeNode) for arg_decl in arg_decls) - assert isinstance(return_type, CodeNode) - if member_initializer_list is None: - member_initializer_list = [] - assert isinstance(member_initializer_list, (list, tuple)) - assert all( - isinstance(initializer, CodeNode) - for initializer in member_initializer_list) - if local_vars is None: - local_vars = [] - assert isinstance(local_vars, (list, tuple)) - assert all( - isinstance(local_var, SymbolNode) for local_var in local_vars) - if body is None: - body = SymbolScopeNode() - assert isinstance(body, CodeNode) - if comment is None: - comment = LiteralNode("") - assert isinstance(comment, CodeNode) - - gensyms = { - "name": CodeNode.gensym(), - "arg_decls": CodeNode.gensym(), - "return_type": CodeNode.gensym(), - "member_initializer_list": CodeNode.gensym(), - "body": CodeNode.gensym(), - "comment": CodeNode.gensym(), - } - - maybe_colon = " : " if member_initializer_list else "" - - template_text = format_template( - """\ -${{{comment}}} -${{{return_type}}} ${{{name}}}(${{{arg_decls}}})\ -{maybe_colon}${{{member_initializer_list}}} {{ - ${{{body}}} -}}\\ -""", - maybe_colon=maybe_colon, - **gensyms) - template_vars = { - gensyms["name"]: - name, - gensyms["arg_decls"]: - ListNode(arg_decls, separator=", "), - gensyms["return_type"]: - return_type, - gensyms["member_initializer_list"]: - ListNode(member_initializer_list, separator=", "), - gensyms["body"]: - body, - gensyms["comment"]: - comment, - } - - CodeNode.__init__( - self, template_text=template_text, template_vars=template_vars) + scope = self.outer_scope() + if scope.is_code_symbol_defined(self._symbol_node): + assert isinstance(self.outer, SequenceNode) + self.outer.schedule_to_remove(self) + self.outer.skip_separator() + return - self._body_node = body + scope.on_code_symbol_defined(self._symbol_node) - self._body_node.register_code_symbols(local_vars) + super(SymbolDefinitionNode, self)._render( + renderer=renderer, last_render_state=last_render_state) @property - def body(self): - return self._body_node + def target_symbol(self): + return self._symbol_node diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_cxx.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_cxx.py new file mode 100644 index 00000000000..b52c867c855 --- /dev/null +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_cxx.py @@ -0,0 +1,456 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +""" +This module provides C++ language specific implementations of +code_node.CodeNode. +""" + +from .code_node import CodeNode +from .code_node import CompositeNode +from .code_node import Likeliness +from .code_node import ListNode +from .code_node import SymbolScopeNode +from .code_node import TextNode +from .codegen_expr import CodeGenExpr +from .codegen_format import format_template + + +class CxxBlockNode(CompositeNode): + def __init__(self, body): + template_format = ( + "{{\n" # + " {body}\n" + "}}") + + CompositeNode.__init__( + self, + template_format, + body=_to_symbol_scope_node(body, Likeliness.ALWAYS)) + + +class CxxIfNode(CompositeNode): + def __init__(self, cond, body, likeliness): + template_format = ( + "if ({cond}) {{\n" # + " {body}\n" + "}}") + + CompositeNode.__init__( + self, + template_format, + cond=_to_conditional_node(cond), + body=_to_symbol_scope_node(body, likeliness)) + + +class CxxIfElseNode(CompositeNode): + def __init__(self, cond, then, then_likeliness, else_, else_likeliness): + template_format = ( + "if ({cond}) {{\n" # + " {then}\n" + "}} else {{\n" + " {else_}\n" + "}}") + + CompositeNode.__init__( + self, + template_format, + cond=_to_conditional_node(cond), + then=_to_symbol_scope_node(then, then_likeliness), + else_=_to_symbol_scope_node(else_, else_likeliness)) + + +class CxxLikelyIfNode(CxxIfNode): + def __init__(self, cond, body): + CxxIfNode.__init__(self, cond, body, Likeliness.LIKELY) + + +class CxxUnlikelyIfNode(CxxIfNode): + def __init__(self, cond, body): + CxxIfNode.__init__(self, cond, body, Likeliness.UNLIKELY) + + +class CxxMultiBranchesNode(CodeNode): + class _Clause(object): + def __init__(self, cond, body): + assert isinstance(cond, (CodeNode, bool)) + assert isinstance(body, SymbolScopeNode) + self.cond = cond + self.body = body + + def __init__(self): + clauses_gensym = CodeNode.gensym() + clauses = [] + template_text = format_template( + """\ +% for {clause} in {clauses}: +% if not loop.first: + else \\ +% endif +% if {clause}.cond is not False: +% if {clause}.cond is not True: +if (${{{clause}.cond}}) \\ +% endif +{{ + ${{{clause}.body}} +}}\\ +% if {clause}.cond is True: + <% break %> +% endif +% endif +% endfor\ +""", + clause=CodeNode.gensym(), + clauses=clauses_gensym) + template_vars = {clauses_gensym: clauses} + + CodeNode.__init__( + self, template_text=template_text, template_vars=template_vars) + + self._clauses = clauses + + def append(self, cond, body, likeliness=Likeliness.LIKELY): + if cond is None: + cond = False + elif isinstance(cond, CodeGenExpr): + if cond.is_always_true: + cond = True + elif cond.is_always_false: + cond = False + + if not isinstance(cond, bool): + cond = _to_conditional_node(cond) + body = _to_symbol_scope_node(body, likeliness) + + if isinstance(cond, CodeNode): + cond.set_outer(self) + body.set_outer(self) + + self._clauses.append(self._Clause(cond, body)) + + +class CxxBreakableBlockNode(CompositeNode): + def __init__(self, body, likeliness=Likeliness.LIKELY): + template_format = ("do {{ // Dummy loop for use of 'break'.\n" + " {body}\n" + "}} while (false);") + + CompositeNode.__init__( + self, + template_format, + body=_to_symbol_scope_node(body, likeliness)) + + +class CxxFuncDeclNode(CompositeNode): + def __init__(self, + name, + arg_decls, + return_type, + template_params=None, + static=False, + explicit=False, + constexpr=False, + const=False, + override=False, + default=False, + delete=False): + """ + Args: + name: Function name. + arg_decls: List of argument declarations. + return_type: Return type. + template_params: List of template parameters or None. + static: True makes this a static function. + explicit: True makes this an explicit constructor. + constexpr: True makes this a constexpr function. + const: True makes this a const function. + override: True makes this an overriding function. + default: True makes this have the default implementation. + delete: True makes this function be deleted. + """ + assert isinstance(static, bool) + assert isinstance(explicit, bool) + assert isinstance(constexpr, bool) + assert isinstance(const, bool) + assert isinstance(override, bool) + assert isinstance(default, bool) + assert isinstance(delete, bool) + assert not (default and delete) + + template_format = ("{template}" + "{static}{explicit}{constexpr}" + "{return_type} " + "{name}({arg_decls})" + "{const}" + "{override}" + "{default_or_delete}" + ";") + + if template_params is None: + template = "" + else: + template = "template <{}>\n".format(", ".join(template_params)) + + static = "static " if static else "" + explicit = "explicit " if explicit else "" + constexpr = "constexpr " if constexpr else "" + const = " const" if const else "" + override = " override" if override else "" + + if default: + default_or_delete = " = default" + elif delete: + default_or_delete = " = delete" + else: + default_or_delete = "" + + CompositeNode.__init__( + self, + template_format, + name=_to_maybe_text_node(name), + arg_decls=ListNode( + map(_to_maybe_text_node, arg_decls), separator=", "), + return_type=_to_maybe_text_node(return_type), + template=template, + static=static, + explicit=explicit, + constexpr=constexpr, + const=const, + override=override, + default_or_delete=default_or_delete) + + +class CxxFuncDefNode(CompositeNode): + def __init__(self, + name, + arg_decls, + return_type, + class_name=None, + template_params=None, + static=False, + inline=False, + explicit=False, + constexpr=False, + const=False, + override=False, + member_initializer_list=None): + """ + Args: + name: Function name. + arg_decls: List of argument declarations. + return_type: Return type. + class_name: Class name to be used as nested-name-specifier. + template_params: List of template parameters or None. + static: True makes this a static function. + inline: True makes this an inline function. + explicit: True makes this an explicit constructor. + constexpr: True makes this a constexpr function. + const: True makes this a const function. + override: True makes this an overriding function. + member_initializer_list: List of member initializers. + """ + assert isinstance(static, bool) + assert isinstance(inline, bool) + assert isinstance(explicit, bool) + assert isinstance(constexpr, bool) + assert isinstance(const, bool) + assert isinstance(override, bool) + + template_format = ("{template}" + "{static}{inline}{explicit}{constexpr}" + "{return_type} " + "{class_name}{name}({arg_decls})" + "{const}" + "{override}" + "{member_initializer_list} {{\n" + " {body}\n" + "}}") + + if class_name is None: + class_name = "" + else: + class_name = ListNode([_to_maybe_text_node(class_name)], tail="::") + + if template_params is None: + template = "" + else: + template = "template <{}>\n".format(", ".join(template_params)) + + static = "static " if static else "" + inline = "inline " if inline else "" + explicit = "explicit " if explicit else "" + constexpr = "constexpr " if constexpr else "" + const = " const" if const else "" + override = " override" if override else "" + + if member_initializer_list is None: + member_initializer_list = "" + else: + member_initializer_list = ListNode( + map(_to_maybe_text_node, member_initializer_list), + separator=", ", + head=" : ") + + self._body_node = SymbolScopeNode() + + CompositeNode.__init__( + self, + template_format, + name=_to_maybe_text_node(name), + arg_decls=ListNode( + map(_to_maybe_text_node, arg_decls), separator=", "), + return_type=_to_maybe_text_node(return_type), + class_name=class_name, + template=template, + static=static, + inline=inline, + explicit=explicit, + constexpr=constexpr, + const=const, + override=override, + member_initializer_list=member_initializer_list, + body=self._body_node) + + @property + def body(self): + return self._body_node + + +class CxxClassDefNode(CompositeNode): + def __init__(self, name, base_class_names=None, final=False, export=None): + """ + Args: + name: The class name to be defined. + base_class_names: The list of base class names. + final: True makes this a final class. + export: Class export annotation. + """ + assert isinstance(final, bool) + + template_format = ("class{export} {name}{final}{base_clause} {{\n" + " {top_section}\n" + " {public_section}\n" + " {protected_section}\n" + " {private_section}\n" + " {bottom_section}\n" + "}};") + + if export is None: + export = "" + else: + export = ListNode([_to_maybe_text_node(export)], head=" ") + + final = " final" if final else "" + + if base_class_names is None: + base_clause = "" + else: + base_specifier_list = [ + CompositeNode( + "public {base_class_name}", + base_class_name=_to_maybe_text_node(base_class_name)) + for base_class_name in base_class_names + ] + base_clause = ListNode( + base_specifier_list, separator=", ", head=" : ") + + self._top_section = ListNode(tail="\n") + self._public_section = ListNode(head="public:\n", tail="\n") + self._protected_section = ListNode(head="protected:\n", tail="\n") + self._private_section = ListNode(head="private:\n", tail="\n") + self._bottom_section = ListNode() + + CompositeNode.__init__( + self, + template_format, + name=_to_maybe_text_node(name), + base_clause=base_clause, + final=final, + export=export, + top_section=self._top_section, + public_section=self._public_section, + protected_section=self._protected_section, + private_section=self._private_section, + bottom_section=self._bottom_section) + + @property + def top_section(self): + return self._top_section + + @property + def public_section(self): + return self._public_section + + @property + def protected_section(self): + return self._protected_section + + @property + def private_section(self): + return self._private_section + + @property + def bottom_section(self): + return self._bottom_section + + +class CxxNamespaceNode(CompositeNode): + def __init__(self, name="", body=None): + template_format = ("namespace {name} {{\n" + "\n" + "{body}\n" + "\n" + "}} // namespace {name}") + + if body is None: + self._body = ListNode() + else: + self._body = _to_list_node(body) + + CompositeNode.__init__( + self, template_format, name=name, body=self._body) + + @property + def body(self): + return self._body + + +def _to_conditional_node(cond): + if isinstance(cond, CodeNode): + return cond + if isinstance(cond, CodeGenExpr): + return TextNode(cond.to_text()) + if isinstance(cond, str): + return TextNode(cond) + assert False + + +def _to_list_node(node): + if isinstance(node, ListNode): + return node + if isinstance(node, CodeNode): + return ListNode([node]) + if isinstance(node, (list, tuple)): + return ListNode(node) + assert False + + +def _to_maybe_text_node(node): + if isinstance(node, CodeNode): + return node + if isinstance(node, str): + return TextNode(node) + assert False + + +def _to_symbol_scope_node(node, likeliness): + if isinstance(node, SymbolScopeNode): + pass + elif isinstance(node, CodeNode): + node = SymbolScopeNode([node]) + elif isinstance(node, (list, tuple)): + node = SymbolScopeNode(node) + else: + assert False + node.set_likeliness(likeliness) + return node diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_cxx_test.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_cxx_test.py new file mode 100644 index 00000000000..a18f304eadb --- /dev/null +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_cxx_test.py @@ -0,0 +1,211 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +from .code_node import SymbolNode +from .code_node import SymbolScopeNode +from .code_node import TextNode +from .code_node import render_code_node +from .code_node_cxx import CxxClassDefNode +from .code_node_cxx import CxxFuncDefNode +from .code_node_cxx import CxxLikelyIfNode +from .code_node_cxx import CxxUnlikelyIfNode +from .codegen_accumulator import CodeGenAccumulator +from .mako_renderer import MakoRenderer + + +class CodeNodeCxxTest(unittest.TestCase): + def setUp(self): + super(CodeNodeCxxTest, self).setUp() + self.addTypeEqualityFunc(str, self.assertMultiLineEqual) + + def assertRenderResult(self, node, expected): + if node.renderer is None: + node.set_renderer(MakoRenderer()) + if node.accumulator is None: + node.set_accumulator(CodeGenAccumulator()) + + def simplify(text): + return "\n".join( + [" ".join(line.split()) for line in text.split("\n")]) + + actual = simplify(render_code_node(node)) + expected = simplify(expected) + + self.assertEqual(actual, expected) + + def test_symbol_definition_with_branches(self): + root = SymbolScopeNode() + + root.register_code_symbols([ + SymbolNode("var1", "int ${var1} = 1;"), + SymbolNode("var2", "int ${var2} = 2;"), + SymbolNode("var3", "int ${var3} = 3;"), + SymbolNode("var4", "int ${var4} = 4;"), + SymbolNode("var5", "int ${var5} = 5;"), + SymbolNode("var6", "int ${var6} = 6;"), + ]) + + root.extend([ + TextNode("${var1};"), + CxxUnlikelyIfNode( + cond=TextNode("${var2}"), + body=[ + TextNode("${var3};"), + TextNode("return ${var4};"), + ]), + CxxLikelyIfNode( + cond=TextNode("${var5}"), body=[ + TextNode("return ${var6};"), + ]), + TextNode("${var3};"), + ]) + + self.assertRenderResult( + root, """\ +int var1 = 1; +var1; +int var2 = 2; +int var3 = 3; +if (var2) { + var3; + int var4 = 4; + return var4; +} +int var5 = 5; +if (var5) { + int var6 = 6; + return var6; +} +var3;\ +""") + + def test_symbol_definition_with_nested_branches(self): + root = SymbolScopeNode() + + root.register_code_symbols([ + SymbolNode("var1", "int ${var1} = 1;"), + SymbolNode("var2", "int ${var2} = 2;"), + SymbolNode("var3", "int ${var3} = 3;"), + SymbolNode("var4", "int ${var4} = 4;"), + SymbolNode("var5", "int ${var5} = 5;"), + SymbolNode("var6", "int ${var6} = 6;"), + ]) + + root.extend([ + CxxUnlikelyIfNode( + cond=TextNode("false"), + body=[ + CxxUnlikelyIfNode( + cond=TextNode("false"), + body=[ + TextNode("return ${var1};"), + ]), + TextNode("return;"), + ]), + CxxLikelyIfNode( + cond=TextNode("true"), + body=[ + CxxLikelyIfNode( + cond=TextNode("true"), + body=[ + TextNode("return ${var2};"), + ]), + TextNode("return;"), + ]), + ]) + + self.assertRenderResult( + root, """\ +if (false) { + if (false) { + int var1 = 1; + return var1; + } + return; +} +if (true) { + if (true) { + int var2 = 2; + return var2; + } + return; +}\ +""") + + def test_function_definition_minimum(self): + root = CxxFuncDefNode( + name="blink::bindings::func", arg_decls=[], return_type="void") + + self.assertRenderResult(root, """\ +void blink::bindings::func() { + +}\ +""") + + def test_function_definition_full(self): + root = CxxFuncDefNode( + name="blink::bindings::func", + arg_decls=["int arg1", "int arg2"], + return_type="void", + const=True, + override=True, + member_initializer_list=[ + "member1(0)", + "member2(\"str\")", + ]) + + root.body.register_code_symbols([ + SymbolNode("var1", "int ${var1} = 1;"), + SymbolNode("var2", "int ${var2} = 2;"), + ]) + + root.body.extend([ + CxxUnlikelyIfNode( + cond=TextNode("${var1}"), body=[TextNode("return ${var1};")]), + TextNode("return ${var2};"), + ]) + + self.assertRenderResult( + root, """\ +void blink::bindings::func(int arg1, int arg2) const override\ + : member1(0), member2("str") { + int var1 = 1; + if (var1) { + return var1; + } + int var2 = 2; + return var2; +}\ +""") + + def test_class_definition(self): + root = CxxClassDefNode("X", ["A", "B"], final=True) + + root.public_section.extend([ + TextNode("void m1();"), + TextNode("void m2();"), + ]) + root.private_section.extend([ + TextNode("int m1_;"), + TextNode("int m2_;"), + ]) + + self.assertRenderResult( + root, """\ +class X final : public A, public B { + + public: + void m1(); + void m2(); + + + private: + int m1_; + int m2_; + + +};\ +""") diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_test.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_test.py index de94c59f49e..24756d58e94 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_test.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/code_node_test.py @@ -4,15 +4,13 @@ import unittest -from .code_node import FunctionDefinitionNode -from .code_node import LikelyExitNode -from .code_node import LiteralNode from .code_node import ListNode +from .code_node import LiteralNode from .code_node import SymbolNode from .code_node import SymbolScopeNode from .code_node import TextNode -from .code_node import UnlikelyExitNode -from .codegen_utils import render_code_node +from .code_node import render_code_node +from .codegen_accumulator import CodeGenAccumulator from .mako_renderer import MakoRenderer @@ -24,6 +22,8 @@ class CodeNodeTest(unittest.TestCase): def assertRenderResult(self, node, expected): if node.renderer is None: node.set_renderer(MakoRenderer()) + if node.accumulator is None: + node.set_accumulator(CodeGenAccumulator()) def simplify(text): return "\n".join( @@ -75,6 +75,14 @@ class CodeNodeTest(unittest.TestCase): root.remove(root[-1]) self.assertRenderResult(root, "2,3,5") + def test_list_node_head_and_tail(self): + self.assertRenderResult(ListNode(), "") + self.assertRenderResult(ListNode(head="head"), "") + self.assertRenderResult(ListNode(tail="tail"), "") + self.assertRenderResult( + ListNode([TextNode("-content-")], head="head", tail="tail"), + "head-content-tail") + def test_nested_sequence(self): """Tests nested ListNodes.""" root = ListNode(separator=",") @@ -96,7 +104,7 @@ class CodeNodeTest(unittest.TestCase): Tests that use of SymbolNode inserts necessary SymbolDefinitionNode appropriately. """ - root = SymbolScopeNode(separator_last="\n") + root = SymbolScopeNode(tail="\n") root.register_code_symbols([ SymbolNode("var1", "int ${var1} = ${var2} + ${var3};"), @@ -118,164 +126,6 @@ int var1 = var2 + var3; (void)var1; """) - def test_symbol_definition_with_exit_branches(self): - root = SymbolScopeNode(separator_last="\n") - - root.register_code_symbols([ - SymbolNode("var1", "int ${var1} = 1;"), - SymbolNode("var2", "int ${var2} = 2;"), - SymbolNode("var3", "int ${var3} = 3;"), - SymbolNode("var4", "int ${var4} = 4;"), - SymbolNode("var5", "int ${var5} = 5;"), - SymbolNode("var6", "int ${var6} = 6;"), - ]) - - root.extend([ - TextNode("${var1};"), - UnlikelyExitNode( - cond=TextNode("${var2}"), - body=SymbolScopeNode([ - TextNode("${var3};"), - TextNode("return ${var4};"), - ])), - LikelyExitNode( - cond=TextNode("${var5}"), - body=SymbolScopeNode([ - TextNode("return ${var6};"), - ])), - TextNode("${var3};"), - ]) - - self.assertRenderResult( - root, """\ -int var1 = 1; -var1; -int var2 = 2; -int var3 = 3; -if (var2) { - var3; - int var4 = 4; - return var4; -} -int var5 = 5; -if (var5) { - int var6 = 6; - return var6; -} -var3; -""") - - def test_symbol_definition_with_nested_exit_branches(self): - root = SymbolScopeNode(separator_last="\n") - - root.register_code_symbols([ - SymbolNode("var1", "int ${var1} = 1;"), - SymbolNode("var2", "int ${var2} = 2;"), - SymbolNode("var3", "int ${var3} = 3;"), - SymbolNode("var4", "int ${var4} = 4;"), - SymbolNode("var5", "int ${var5} = 5;"), - SymbolNode("var6", "int ${var6} = 6;"), - ]) - - root.extend([ - UnlikelyExitNode( - cond=LiteralNode("false"), - body=SymbolScopeNode([ - UnlikelyExitNode( - cond=LiteralNode("false"), - body=SymbolScopeNode([ - TextNode("return ${var1};"), - ])), - LiteralNode("return;"), - ])), - LikelyExitNode( - cond=LiteralNode("true"), - body=SymbolScopeNode([ - LikelyExitNode( - cond=LiteralNode("true"), - body=SymbolScopeNode([ - TextNode("return ${var2};"), - ])), - LiteralNode("return;"), - ])), - ]) - - self.assertRenderResult( - root, """\ -if (false) { - if (false) { - int var1 = 1; - return var1; - } - return; -} -if (true) { - if (true) { - int var2 = 2; - return var2; - } - return; -} -""") - - def test_function_definition_minimum(self): - root = SymbolScopeNode(separator_last="\n") - root.append( - FunctionDefinitionNode( - name=LiteralNode("blink::bindings::func"), - arg_decls=[], - return_type=LiteralNode("void"))) - - self.assertRenderResult(root, """\ - -void blink::bindings::func() { - -} -""") - - def test_function_definition_full(self): - root = SymbolScopeNode(separator_last="\n") - - local_vars = [ - SymbolNode("var1", "int ${var1} = 1;"), - SymbolNode("var2", "int ${var2} = 2;"), - ] - - func_body = SymbolScopeNode([ - UnlikelyExitNode( - cond=TextNode("${var1}"), - body=SymbolScopeNode([TextNode("return ${var1};")])), - TextNode("return ${var2};"), - ]) - - root.append( - FunctionDefinitionNode( - name=LiteralNode("blink::bindings::func"), - arg_decls=[LiteralNode("int arg1"), - LiteralNode("int arg2")], - return_type=LiteralNode("void"), - member_initializer_list=[ - LiteralNode("member1(0)"), - LiteralNode("member2(\"str\")") - ], - local_vars=local_vars, - body=func_body, - comment=LiteralNode("// comment1\n// comment2"))) - - self.assertRenderResult( - root, """\ -// comment1 -// comment2 -void blink::bindings::func(int arg1, int arg2) : member1(0), member2("str") { - int var1 = 1; - if (var1) { - return var1; - } - int var2 = 2; - return var2; -} -""") - def test_template_error_handling(self): renderer = MakoRenderer() root = SymbolScopeNode() @@ -288,7 +138,8 @@ void blink::bindings::func(int arg1, int arg2) : member1(0), member2("str") { ])) with self.assertRaises(NameError): - root.render() + renderer.reset() + root.render(renderer) callers_on_error = list(renderer.callers_on_error) self.assertEqual(len(callers_on_error), 3) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_accumulator.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_accumulator.py index 910c4bb185e..f72e41a7421 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_accumulator.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_accumulator.py @@ -14,6 +14,12 @@ class CodeGenAccumulator(object): self._include_headers = set() # Forward declarations of C++ class self._class_decls = set() + # Forward declarations of C++ struct + self._struct_decls = set() + + def total_size(self): + return (len(self.include_headers) + len(self.class_decls) + len( + self.struct_decls)) @property def include_headers(self): @@ -42,3 +48,17 @@ class CodeGenAccumulator(object): @staticmethod def require_class_decls(class_names): return lambda accumulator: accumulator.add_class_decls(class_names) + + @property + def struct_decls(self): + return self._struct_decls + + def add_struct_decl(self, struct_name): + self._struct_decls.add(struct_name) + + def add_struct_decls(self, struct_names): + self._struct_decls.update(struct_names) + + @staticmethod + def require_struct_decls(struct_names): + return lambda accumulator: accumulator.add_struct_decls(struct_names) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_context.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_context.py index 8b06e878898..ae9defa40a2 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_context.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_context.py @@ -4,7 +4,10 @@ import copy +import web_idl + from . import name_style +from .codegen_format import NonRenderable from .path_manager import PathManager @@ -20,8 +23,26 @@ class CodeGenContext(object): # "for_world" attribute values MAIN_WORLD = "main" + NON_MAIN_WORLDS = "other" ALL_WORLDS = "all" + # "v8_callback_type" attribute values + # + # void (*)(const v8::FunctionCallbackInfo<v8::Value>&) + V8_FUNCTION_CALLBACK = "v8::FunctionCallback" + # void (*)(v8::Local<v8::Name>, + # const v8::PropertyCallbackInfo<v8::Value>&) + V8_ACCESSOR_NAME_GETTER_CALLBACK = "v8::AccessorNameGetterCallback" + # void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, + # const v8::PropertyCallbackInfo<void>&) + V8_ACCESSOR_NAME_SETTER_CALLBACK = "v8::AccessorNameSetterCallback" + # void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, + # const v8::PropertyCallbackInfo<v8::Value>&) + V8_GENERIC_NAMED_PROPERTY_SETTER_CALLBACK = ( + "v8::GenericNamedPropertySetterCallback") + # Others + V8_OTHER_CALLBACK = "other callback type" + @classmethod def init(cls): """Initialize the class. Must be called exactly once.""" @@ -49,11 +70,31 @@ class CodeGenContext(object): "constructor": None, "constructor_group": None, "dict_member": None, + "exposed_construct": None, + "legacy_window_alias": None, "operation": None, "operation_group": None, + # Special member-ish definition + "indexed_property_getter": None, + "indexed_property_setter": None, + "named_property_getter": None, + "named_property_setter": None, + "named_property_deleter": None, + "stringifier": None, + + # The names of the class being generated and its base class. + "base_class_name": None, + "class_name": None, + # Main world or all worlds + # Used via [PerWorldBindings] to optimize the code path of the main + # world. "for_world": cls.ALL_WORLDS, + + # Type of V8 callback function which implements IDL attribute, + # IDL operation, etc. + "v8_callback_type": cls.V8_FUNCTION_CALLBACK } # List of computational attribute names @@ -69,11 +110,10 @@ class CodeGenContext(object): "member_like", "property_", "return_type", - "v8_class", ) # Define public readonly properties of this class. - for attr in cls._context_attrs.iterkeys(): + for attr in cls._context_attrs.keys(): def make_get(): _attr = cls._internal_attr(attr) @@ -92,11 +132,11 @@ class CodeGenContext(object): def __init__(self, **kwargs): assert CodeGenContext._was_initialized - for arg in kwargs.iterkeys(): + for arg in kwargs.keys(): assert arg in self._context_attrs, "Unknown argument: {}".format( arg) - for attr, default_value in self._context_attrs.iteritems(): + for attr, default_value in self._context_attrs.items(): value = kwargs[attr] if attr in kwargs else default_value assert (default_value is None or type(value) is type(default_value)), ( @@ -108,13 +148,13 @@ class CodeGenContext(object): Returns a copy of this context applying the updates given as the arguments. """ - for arg in kwargs.iterkeys(): + for arg in kwargs.keys(): assert arg in self._context_attrs, "Unknown argument: {}".format( arg) new_object = copy.copy(self) - for attr, new_value in kwargs.iteritems(): + for attr, new_value in kwargs.items(): old_value = getattr(self, attr) assert old_value is None or type(new_value) is type(old_value), ( "Type mismatch at argument: {}".format(attr)) @@ -131,15 +171,17 @@ class CodeGenContext(object): """ bindings = {} - for attr in self._context_attrs.iterkeys(): + for attr in self._context_attrs.keys(): value = getattr(self, attr) - if value is not None: - bindings[attr] = value + if value is None: + value = NonRenderable(attr) + bindings[attr] = value for attr in self._computational_attrs: value = getattr(self, attr) - if value is not None: - bindings[attr.strip("_")] = value + if value is None: + value = NonRenderable(attr) + bindings[attr.strip("_")] = value return bindings @@ -149,8 +191,18 @@ class CodeGenContext(object): or self.namespace) @property + def does_override_idl_return_type(self): + # Blink implementation returns in a type different from the IDL type. + # Namely, IndexedPropertySetterResult, NamedPropertySetterResult, and + # NamedPropertyDeleterResult are returned ignoring the operation's + # return type. + return (self.indexed_property_setter or self.named_property_setter + or self.named_property_deleter) + + @property def function_like(self): - return (self.callback_function or self.constructor or self.operation) + return (self.callback_function or self.constructor or self.operation + or self._indexed_or_named_property) @property def idl_definition(self): @@ -161,9 +213,9 @@ class CodeGenContext(object): @property def idl_location(self): idl_def = self.member_like or self.idl_definition - if idl_def: + if idl_def and not isinstance(idl_def, web_idl.Union): location = idl_def.debug_info.location - text = PathManager.relpath_to_project_root(location.filepath) + text = location.filepath if location.line_number is not None: text += ":{}".format(location.line_number) return text @@ -185,15 +237,16 @@ class CodeGenContext(object): @property def is_return_by_argument(self): + if self.does_override_idl_return_type: + return False if self.return_type is None: - return None - return_type = self.return_type.unwrap() - return return_type.is_dictionary or return_type.is_union + return False + return self.return_type.unwrap().is_union @property def may_throw_exception(self): if not self.member_like: - return None + return False ext_attr = self.member_like.extended_attributes.get("RaisesException") if not ext_attr: return False @@ -204,28 +257,77 @@ class CodeGenContext(object): @property def member_like(self): return (self.attribute or self.constant or self.constructor - or self.dict_member or self.operation) + or self.dict_member or self.operation + or self._indexed_or_named_property) @property def property_(self): + if self.stringifier: + return _StringifierProperty(self.stringifier) + return (self.attribute or self.constant or self.constructor_group - or self.dict_member or self.operation_group) + or self.dict_member + or (self.legacy_window_alias or self.exposed_construct) + or self.operation_group or self._indexed_or_named_property) @property def return_type(self): if self.attribute_get: return self.attribute.idl_type - if self.callback_function: - return self.callback_function.return_type - if self.operation: - return self.operation.return_type + function_like = self.function_like + if function_like: + return function_like.return_type return None @property - def v8_class(self): - if not self.idl_definition: - return None - return name_style.class_("v8", self.idl_definition.identifier) + def _indexed_or_named_property(self): + return (self.indexed_property_getter or self.indexed_property_setter + or self.named_property_getter or self.named_property_setter + or self.named_property_deleter) CodeGenContext.init() + + +class _PropertyBase(object): + def __init__(self, identifier, extended_attributes, owner, debug_info): + assert isinstance(identifier, web_idl.Identifier) + assert identifier + assert isinstance(extended_attributes, web_idl.ExtendedAttributes) + assert isinstance(debug_info, web_idl.DebugInfo) + + self._identifier = identifier + self._extended_attributes = extended_attributes + self._owner = owner + self._debug_info = debug_info + + @property + def identifier(self): + return self._identifier + + @property + def extended_attributes(self): + return self._extended_attributes + + @property + def owner(self): + return self._owner + + @property + def debug_info(self): + return self._debug_info + + +class _StringifierProperty(_PropertyBase): + def __init__(self, stringifier): + if stringifier.attribute: + extended_attributes = stringifier.attribute.extended_attributes + else: + extended_attributes = stringifier.operation.extended_attributes + + _PropertyBase.__init__( + self, + identifier=web_idl.Identifier("toString"), + extended_attributes=extended_attributes, + owner=stringifier.owner, + debug_info=stringifier.debug_info) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py index de9fb61d764..e1b6c8b1b08 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py @@ -4,7 +4,6 @@ import web_idl - _CODE_GEN_EXPR_PASS_KEY = object() @@ -144,18 +143,22 @@ def expr_uniq(terms): return uniq_terms -def expr_from_exposure(exposure, in_global=None): +def expr_from_exposure(exposure, global_names=None): """ Args: - exposure: web_idl.Exposure - in_global: A global name of [Exposed] that the ExecutionContext is - supposed to be / represent. + exposure: web_idl.Exposure of the target construct. + global_names: When specified, it's taken into account that the global + object implements |global_names|. """ assert isinstance(exposure, web_idl.Exposure) - assert in_global is None or isinstance(in_global, str) + assert (global_names is None + or (isinstance(global_names, (list, tuple)) + and all(isinstance(name, str) for name in global_names))) def ref_enabled(feature): - return _Expr("RuntimeEnabledFeatures::{}Enabled()".format(feature)) + arg = "${execution_context}" if feature.is_context_dependent else "" + return _Expr("RuntimeEnabledFeatures::{}Enabled({})".format( + feature, arg)) top_terms = [_Expr(True)] @@ -172,22 +175,26 @@ def expr_from_exposure(exposure, in_global=None): "Worker": "IsWorkerGlobalScope", "Worklet": "IsWorkletGlobalScope", } - in_globals = set() - if in_global: - in_globals.add(in_global) - for category_name in ("Worker", "Worklet"): - if in_global.endswith(category_name): - in_globals.add(category_name) exposed_terms = [] - for entry in exposure.global_names_and_features: - terms = [] - if entry.global_name not in in_globals: + if global_names: + matched_global_count = 0 + for entry in exposure.global_names_and_features: + if entry.global_name not in global_names: + continue + matched_global_count += 1 + if entry.feature: + exposed_terms.append(ref_enabled(entry.feature)) + assert (not exposure.global_names_and_features + or matched_global_count > 0) + else: + for entry in exposure.global_names_and_features: + terms = [] pred = GLOBAL_NAME_TO_EXECUTION_CONTEXT_TEST[entry.global_name] terms.append(_Expr("${{execution_context}}->{}()".format(pred))) - if entry.feature: - terms.append(ref_enabled(entry.feature)) - if terms: - exposed_terms.append(expr_and(terms)) + if entry.feature: + terms.append(ref_enabled(entry.feature)) + if terms: + exposed_terms.append(expr_and(terms)) if exposed_terms: top_terms.append(expr_or(exposed_terms)) @@ -198,13 +205,14 @@ def expr_from_exposure(exposure, in_global=None): # [SecureContext] if exposure.only_in_secure_contexts is True: - top_terms.append(_Expr("${in_secure_context}")) + top_terms.append(_Expr("${is_in_secure_context}")) elif exposure.only_in_secure_contexts is False: top_terms.append(_Expr(True)) else: terms = map(ref_enabled, exposure.only_in_secure_contexts) top_terms.append( - expr_or([_Expr("${in_secure_context}"), - expr_not(expr_and(terms))])) + expr_or( + [_Expr("${is_in_secure_context}"), + expr_not(expr_and(terms))])) return expr_and(top_terms) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py index 3b215153021..87d26eec3ca 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_format.py @@ -27,7 +27,7 @@ class _TemplateFormatter(string.Formatter): return args[key] assert isinstance(key, str) if not key: - # Before Python 3.1, when a positional argument specifier is + # Prior to Python 3.1, when a positional argument specifier is # omitted, |format_string="{}"| produces |key=""|. Should be # removed once Python2 gets retired. index = self._template_formatter_indexing_count_ @@ -37,3 +37,22 @@ class _TemplateFormatter(string.Formatter): return kwargs[key] else: return "{" + key + "}" + + +class NonRenderable(object): + """ + Represents a non-renderable object. + + Unlike a template variable bound to None, which is a valid Python value, + this object raises an exception when rendered, just like an unbound template + variable. + """ + + def __init__(self, error_message="Undefined"): + self._error_message = error_message + + def __bool__(self): + raise NameError(self._error_message) + + def __str__(self): + raise NameError(self._error_message) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py index 2635adbafae..7021f1a618c 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py @@ -4,10 +4,14 @@ import web_idl -from .clang_format import clang_format +from . import name_style +from . import style_format +from .blink_v8_bridge import blink_type_info from .code_node import CodeNode +from .code_node import EmptyNode from .code_node import LiteralNode from .code_node import SequenceNode +from .code_node import render_code_node from .codegen_accumulator import CodeGenAccumulator from .path_manager import PathManager @@ -20,6 +24,25 @@ def make_copyright_header(): """) +def make_forward_declarations(accumulator): + assert isinstance(accumulator, CodeGenAccumulator) + + class ForwardDeclarations(object): + def __init__(self, accumulator): + self._accumulator = accumulator + + def __str__(self): + return "\n".join([ + "class {};".format(class_name) + for class_name in sorted(self._accumulator.class_decls) + ] + [ + "struct {};".format(struct_name) + for struct_name in sorted(self._accumulator.struct_decls) + ]) + + return LiteralNode(ForwardDeclarations(accumulator)) + + def make_header_include_directives(accumulator): assert isinstance(accumulator, CodeGenAccumulator) @@ -36,6 +59,23 @@ def make_header_include_directives(accumulator): return LiteralNode(HeaderIncludeDirectives(accumulator)) +def component_export(component): + assert isinstance(component, web_idl.Component) + + return name_style.macro(component, "EXPORT") + + +def component_export_header(component): + assert isinstance(component, web_idl.Component) + + if component == "core": + return "third_party/blink/renderer/core/core_export.h" + elif component == "modules": + return "third_party/blink/renderer/modules/modules_export.h" + else: + assert False + + def enclose_with_header_guard(code_node, header_guard): assert isinstance(code_node, CodeNode) assert isinstance(header_guard, str) @@ -43,93 +83,64 @@ def enclose_with_header_guard(code_node, header_guard): return SequenceNode([ LiteralNode("#ifndef {}".format(header_guard)), LiteralNode("#define {}".format(header_guard)), - LiteralNode(""), + EmptyNode(), code_node, - LiteralNode(""), + EmptyNode(), LiteralNode("#endif // {}".format(header_guard)), ]) -def enclose_with_namespace(code_node, namespace): - assert isinstance(code_node, CodeNode) - assert isinstance(namespace, str) - - return SequenceNode([ - LiteralNode("namespace {} {{".format(namespace)), - LiteralNode(""), - code_node, - LiteralNode(""), - LiteralNode("}} // namespace {}".format(namespace)), - ]) - - -def traverse_idl_types(idl_definition, callback): +def collect_include_headers_of_idl_types(idl_types): """ - Traverses in the given |idl_definition| to find all the web_idl.IdlType used - in the IDL definition. Invokes |callback| with each web_idl.IdlType. + Returns a set of header paths that are required by |idl_types|. """ - assert callable(callback) - - def get(obj, attr): - try: - return getattr(obj, attr) - except: - return () - - xs = (get(idl_definition, "attributes") + get(idl_definition, "constants") - + get(idl_definition, "own_members") + (idl_definition, )) - for x in xs: - idl_type = get(x, "idl_type") - if idl_type: - callback(idl_type) - - xs = (get(idl_definition, "constructors") + get(idl_definition, - "operations")) - for x in xs: - for argument in x.arguments: - callback(argument.idl_type) - if x.return_type is not None: - callback(x.return_type) - - xs = get(idl_definition, "flattened_member_types") - for x in xs: - callback(x) - - -def collect_include_headers(idl_definition): - """ - Returns a list of include headers that are required by generated bindings of - |idl_definition|. - """ - type_def_objs = set() - - def collect_type_def_obj(idl_type): - type_def_obj = idl_type.unwrap().type_definition_object - if type_def_obj is not None: - type_def_objs.add(type_def_obj) - - traverse_idl_types(idl_definition, collect_type_def_obj) - header_paths = set() - for type_def_obj in type_def_objs: - if isinstance(type_def_obj, web_idl.Enumeration): - continue - header_paths.add(PathManager(type_def_obj).blink_path(ext="h")) - - return header_paths + def add_header_path(idl_type): + assert isinstance(idl_type, web_idl.IdlType) + + if idl_type.is_numeric or idl_type.is_boolean or idl_type.is_typedef: + pass + elif idl_type.is_string: + header_paths.add( + "third_party/blink/renderer/platform/wtf/text/wtf_string.h") + elif idl_type.is_buffer_source_type: + header_paths.update([ + "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h", + "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h", + "third_party/blink/renderer/platform/heap/handle.h", + ]) + elif idl_type.is_object or idl_type.is_any: + header_paths.add( + "third_party/blink/renderer/bindings/core/v8/script_value.h") + elif idl_type.type_definition_object: + type_def_obj = idl_type.type_definition_object + header_paths.update([ + PathManager(type_def_obj).api_path(ext="h"), + "third_party/blink/renderer/platform/heap/handle.h", + ]) + elif (idl_type.is_sequence or idl_type.is_frozen_array + or idl_type.is_variadic or idl_type.is_record): + header_paths.update([ + "third_party/blink/renderer/platform/wtf/vector.h", + "third_party/blink/renderer/platform/heap/heap_allocator.h", + ]) + elif idl_type.is_promise: + header_paths.add( + "third_party/blink/renderer/bindings/core/v8/script_promise.h") + elif idl_type.is_union: + union_def_obj = idl_type.union_definition_object + header_paths.add(PathManager(union_def_obj).api_path(ext="h")) + elif idl_type.is_nullable: + if not blink_type_info(idl_type.inner_type).has_null_value: + header_paths.add("base/optional.h") + else: + assert False, "Unknown type: {}".format(idl_type.syntactic_form) + + for idl_type in idl_types: + idl_type.apply_to_all_composing_elements(add_header_path) -def render_code_node(code_node): - """ - Renders |code_node| and turns it into text letting |code_node| apply all - necessary changes (side effects). Returns the resulting text. - """ - prev = "_" - current = "" - while current != prev: - prev = current - current = str(code_node) - return current + return header_paths def write_code_node_to_file(code_node, filepath): @@ -139,7 +150,12 @@ def write_code_node_to_file(code_node, filepath): rendered_text = render_code_node(code_node) - format_result = clang_format(rendered_text, filename=filepath) + format_result = style_format.auto_format(rendered_text, filename=filepath) + if not format_result.did_succeed: + raise RuntimeError("Style-formatting failed: filename = {filename}\n" + "---- stderr ----\n" + "{stderr}:".format( + filename=format_result.filename, + stderr=format_result.error_message)) - with open(filepath, "w") as output_file: - output_file.write(format_result.contents) + web_idl.file_io.write_to_file_if_changed(filepath, format_result.contents) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py index 9f2cfae5a15..baeeebbb697 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py @@ -9,20 +9,35 @@ import web_idl from . import name_style from .blink_v8_bridge import blink_class_name from .blink_v8_bridge import blink_type_info +from .blink_v8_bridge import make_default_value_expr from .blink_v8_bridge import make_v8_to_blink_value from .code_node import CodeNode -from .code_node import FunctionDefinitionNode +from .code_node import Likeliness +from .code_node import ListNode from .code_node import SequenceNode +from .code_node import SymbolNode from .code_node import SymbolScopeNode from .code_node import TextNode +from .code_node_cxx import CxxClassDefNode +from .code_node_cxx import CxxFuncDeclNode +from .code_node_cxx import CxxFuncDefNode +from .code_node_cxx import CxxIfElseNode +from .code_node_cxx import CxxLikelyIfNode +from .code_node_cxx import CxxNamespaceNode +from .codegen_accumulator import CodeGenAccumulator from .codegen_context import CodeGenContext from .codegen_expr import expr_from_exposure from .codegen_format import format_template as _format -from .codegen_utils import enclose_with_namespace +from .codegen_utils import collect_include_headers_of_idl_types +from .codegen_utils import component_export +from .codegen_utils import component_export_header +from .codegen_utils import enclose_with_header_guard from .codegen_utils import make_copyright_header +from .codegen_utils import make_forward_declarations +from .codegen_utils import make_header_include_directives from .codegen_utils import write_code_node_to_file from .mako_renderer import MakoRenderer - +from .path_manager import PathManager _DICT_MEMBER_PRESENCE_PREDICATES = { "ScriptValue": "{}.IsEmpty()", @@ -71,178 +86,337 @@ def _member_presence_expr(member): return _format(_DICT_MEMBER_PRESENCE_PREDICATES[blink_type], _1) -def make_dict_member_get_def(cg_context): +def bind_member_iteration_local_vars(code_node): + local_vars = [ + SymbolNode( + "current_context", "v8::Local<v8::Context> ${current_context} = " + "${isolate}->GetCurrentContext();"), + SymbolNode( + "member_names", "const auto* ${member_names} = " + "GetV8MemberNames(${isolate}).data();"), + SymbolNode( + "is_in_secure_context", "const bool ${is_in_secure_context} = " + "${execution_context}->IsSecureContext();"), + ] + + # Execution context + node = SymbolNode( + "execution_context", "ExecutionContext* ${execution_context} = " + "ToExecutionContext(${current_context});") + node.accumulate( + CodeGenAccumulator.require_include_headers([ + "third_party/blink/renderer/core/execution_context/execution_context.h" + ])) + local_vars.append(node) + + code_node.register_code_symbols(local_vars) + + +def _make_include_headers(cg_context): assert isinstance(cg_context, CodeGenContext) - T = TextNode + dictionary = cg_context.dictionary - member = cg_context.dict_member + header_includes = set() + source_includes = set() - func_name = "{}::{}".format( - blink_class_name(cg_context.dictionary), - _blink_member_name(member).get_api) - func_def = FunctionDefinitionNode( - name=T(func_name), - arg_decls=[], - return_type=T(blink_type_info(member.idl_type).ref_t)) + if dictionary.inherited: + header_includes.add( + PathManager(dictionary.inherited).api_path(ext="h")) + else: + header_includes.add( + "third_party/blink/renderer/platform/bindings/dictionary_base.h") + + header_includes.update([ + component_export_header(dictionary.components[0]), + "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h", + "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h", + "v8/include/v8.h", + ]) + source_includes.update([ + "third_party/blink/renderer/platform/bindings/exception_messages.h", + "third_party/blink/renderer/platform/bindings/exception_state.h", + "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h", + "third_party/blink/renderer/platform/heap/visitor.h", + ]) - body = func_def.body - body.add_template_vars(cg_context.template_bindings()) + header_includes.update( + collect_include_headers_of_idl_types( + [member.idl_type for member in dictionary.own_members])) - _1 = _blink_member_name(member).has_api - body.append(T(_format("DCHECK({_1}());", _1=_1))) + return header_includes, source_includes - _1 = _blink_member_name(member).value_var - body.append(T(_format("return {_1};", _1=_1))) - return func_def +def _make_forward_declarations(cg_context): + assert isinstance(cg_context, CodeGenContext) + + dictionary = cg_context.dictionary + + header_class_fwd_decls = set([ + "ExceptionState", + "Visitor", + ]) + header_struct_fwd_decls = set() + + source_class_fwd_decls = set() + source_struct_fwd_decls = set() + + return (header_class_fwd_decls, header_struct_fwd_decls, + source_class_fwd_decls, source_struct_fwd_decls) -def make_dict_member_has_def(cg_context): +def make_dict_member_get(cg_context): assert isinstance(cg_context, CodeGenContext) - T = TextNode + member = cg_context.dict_member + blink_member_name = _blink_member_name(member) + name = blink_member_name.get_api + blink_type = blink_type_info(member.idl_type) + + decls = ListNode() + defs = ListNode() + + func_def = CxxFuncDefNode( + name=name, + arg_decls=[], + return_type=blink_type.const_ref_t, + const=True) + decls.append(func_def) + func_def.set_base_template_vars(cg_context.template_bindings()) + func_def.body.extend([ + TextNode(_format("DCHECK({}());", blink_member_name.has_api)), + TextNode(_format("return {};", blink_member_name.value_var)), + ]) + + if blink_type.ref_t != blink_type.const_ref_t: + func_def = CxxFuncDefNode( + name=name, arg_decls=[], return_type=blink_type.ref_t) + decls.append(func_def) + func_def.set_base_template_vars(cg_context.template_bindings()) + func_def.body.extend([ + TextNode(_format("DCHECK({}());", blink_member_name.has_api)), + TextNode(_format("return {};", blink_member_name.value_var)), + ]) + + return decls, defs + + +def make_dict_member_has(cg_context): + assert isinstance(cg_context, CodeGenContext) member = cg_context.dict_member - func_name = "{}::{}".format( - blink_class_name(cg_context.dictionary), - _blink_member_name(member).has_api) - func_def = FunctionDefinitionNode( - name=T(func_name), arg_decls=[], return_type=T("bool")) + decls = ListNode() + defs = ListNode() + func_def = CxxFuncDefNode( + name=_blink_member_name(member).has_api, + arg_decls=[], + return_type="bool", + const=True) + decls.append(func_def) + func_def.set_base_template_vars(cg_context.template_bindings()) body = func_def.body _1 = _member_presence_expr(member) - body.append(T(_format("return {_1};", _1=_1))) + body.append(TextNode(_format("return {_1};", _1=_1))) - return func_def + return decls, defs -def make_dict_member_set_def(cg_context): +def make_dict_member_set(cg_context): assert isinstance(cg_context, CodeGenContext) T = TextNode member = cg_context.dict_member + blink_member_name = _blink_member_name(member) + real_type = member.idl_type.unwrap(typedef=True) + type_info = blink_type_info(real_type) + + decls = ListNode() + defs = ListNode() + + template_func_def = CxxFuncDefNode( + name=blink_member_name.set_api, + arg_decls=["T&& value"], + return_type="void", + template_params=["typename T"]) + decls.append(template_func_def) + + # This setter with the explicit type declaration makes it possible to set + # the dictionary member with uniform initialization (especially aggregate + # initialization), e.g. setIntVector({3, 1, 4, 1, 5}). + move_func_decl = CxxFuncDeclNode( + name=blink_member_name.set_api, + arg_decls=[_format("{}&&", type_info.member_t)], + return_type="void") + decls.append(move_func_decl) + + move_func_def = CxxFuncDefNode( + name=blink_member_name.set_api, + arg_decls=[_format("{}&& value", type_info.member_t)], + return_type="void", + class_name=cg_context.class_name) + defs.append(move_func_def) + + _1 = blink_member_name.value_var + template_func_def.body.append( + T(_format("{_1} = std::forward<T>(value);", _1=_1))) + move_func_def.body.append(T(_format("{_1} = value;", _1=_1))) + + if _does_use_presence_flag(member): + set_presense_expr = _format("{} = true;", + blink_member_name.presence_var) + template_func_def.body.append(T(set_presense_expr)) + move_func_def.body.append(T(set_presense_expr)) + + # Migration Adapter + if (real_type.is_nullable and + blink_type_info(real_type).typename.startswith("base::Optional")): + to_null_func_def = CxxFuncDefNode( + name=_format("{}ToNull", blink_member_name.set_api), + arg_decls=[], + return_type="void") + decls.append(to_null_func_def) + to_null_func_def.set_base_template_vars(cg_context.template_bindings()) + to_null_func_def.body.append( + T(_format("{}(base::nullopt);", blink_member_name.set_api))) + + return decls, defs + + +def make_dict_member_vars(cg_context): + assert isinstance(cg_context, CodeGenContext) - func_name = "{}::{}".format( - blink_class_name(cg_context.dictionary), - _blink_member_name(member).set_api) - func_def = FunctionDefinitionNode( - name=T(func_name), - arg_decls=[ - T(_format("{} value", - blink_type_info(member.idl_type).ref_t)) - ], - return_type=T("void")) + member = cg_context.dict_member - body = func_def.body - body.add_template_vars(cg_context.template_bindings()) + default_value_initializer = "" + if member.default_value: + default_expr = make_default_value_expr(member.idl_type, + member.default_value) + if default_expr.initializer is not None: + default_value_initializer = _format("{{{}}}", + default_expr.initializer) - _1 = _blink_member_name(member).value_var - body.append(T(_format("{_1} = value;", _1=_1))) + _1 = blink_type_info(member.idl_type).member_t + _2 = _blink_member_name(member).value_var + _3 = default_value_initializer + value_var_def = TextNode(_format("{_1} {_2}{_3};", _1=_1, _2=_2, _3=_3)) if _does_use_presence_flag(member): _1 = _blink_member_name(member).presence_var - body.append(T(_format("{_1} = true;", _1=_1))) + presense_var_def = TextNode(_format("bool {_1} = false;", _1=_1)) + else: + presense_var_def = None - return func_def + return value_var_def, presense_var_def -def make_get_v8_dict_member_names_def(cg_context): +def make_get_v8_dict_member_names_func(cg_context): assert isinstance(cg_context, CodeGenContext) - T = TextNode - dictionary = cg_context.dictionary - - func_name = _format("{}::GetV8MemberNames", - blink_class_name(cg_context.dictionary)) - func_def = FunctionDefinitionNode( - name=T(func_name), - arg_decls=[T("v8::Isolate* isolate")], - return_type=T("const v8::Eternal<v8::Name>*"), - comment=T("// static")) - + name = "GetV8MemberNames" + arg_decls = ["v8::Isolate* isolate"] + return_type = "const base::span<const v8::Eternal<v8::Name>>" + + func_decl = CxxFuncDeclNode( + name=name, arg_decls=arg_decls, return_type=return_type, static=True) + func_def = CxxFuncDefNode( + name=name, + class_name=cg_context.class_name, + arg_decls=arg_decls, + return_type=return_type) + func_def.set_base_template_vars(cg_context.template_bindings()) body = func_def.body - pattern = ("static const char* kKeyStrings[] = {{{_1}}};") - _1 = ", ".join( - _format("\"{}\"", member.identifier) for member in dictionary.members) - body.extend([ - T(_format(pattern, _1=_1)), - T("return V8PerIsolateData::From(isolate)" - "->FindOrCreateEternalNameCache(" - "kKeyStrings, kKeyStrings, base::size(kKeyStrings));") - ]) + if dictionary.own_members: + pattern = "static const char* kKeyStrings[] = {{{_1}}};" + _1 = ", ".join( + _format("\"{}\"", member.identifier) + for member in dictionary.own_members) + body.extend([ + TextNode(_format(pattern, _1=_1)), + TextNode("return V8PerIsolateData::From(isolate)" + "->FindOrCreateEternalNameCache(kKeyStrings, " + "kKeyStrings);"), + ]) + else: + body.append(TextNode("return {};")) - return func_def + return func_decl, func_def -def make_fill_with_dict_members_def(cg_context): +def make_fill_with_dict_members_func(cg_context): assert isinstance(cg_context, CodeGenContext) - T = TextNode - dictionary = cg_context.dictionary - - func_name = _format( - "{_1}::FillWithMembers", _1=blink_class_name(dictionary)) - func_def = FunctionDefinitionNode( - name=T(func_name), - arg_decls=[ - T("v8::Isolate* isolate"), - T("v8::Local<v8::Object> creation_context"), - T("v8::Local<v8::Object> v8_dictionary"), - ], - return_type=T("bool")) - + name = "FillWithMembers" + arg_decls = [ + "v8::Isolate* isolate", + "v8::Local<v8::Object> creation_context", + "v8::Local<v8::Object> v8_dictionary", + ] + return_type = "bool" + + func_decl = CxxFuncDeclNode( + name=name, + arg_decls=arg_decls, + return_type=return_type, + const=True, + override=True) + func_def = CxxFuncDefNode( + name=name, + class_name=cg_context.class_name, + arg_decls=arg_decls, + return_type=return_type, + const=True) + func_def.set_base_template_vars(cg_context.template_bindings()) body = func_def.body - body.add_template_vars(cg_context.template_bindings()) if dictionary.inherited: text = """\ if (!BaseClass::FillWithMembers(isolate, creation_context, v8_dictionary)) { return false; }""" - body.append(T(text)) + body.append(TextNode(text)) body.append( - T("return FillWithOwnMembers(" - "isolate, creation_context, v8_dictionary)")) + TextNode("return FillWithOwnMembers(" + "isolate, creation_context, v8_dictionary);")) - return func_def + return func_decl, func_def -def make_fill_with_own_dict_members_def(cg_context): +def make_fill_with_own_dict_members_func(cg_context): assert isinstance(cg_context, CodeGenContext) T = TextNode dictionary = cg_context.dictionary own_members = dictionary.own_members - - func_name = _format( - "{_1}::FillWithOwnMembers", _1=blink_class_name(dictionary)) - func_def = FunctionDefinitionNode( - name=T(func_name), - arg_decls=[ - T("v8::Isolate* isolate"), - T("v8::Local<v8::Object> creation_context"), - T("v8::Local<v8::Object> v8_dictionary") - ], - return_type=T("bool")) - + name = "FillWithOwnMembers" + arg_decls = [ + "v8::Isolate* isolate", + "v8::Local<v8::Object> creation_context", + "v8::Local<v8::Object> v8_dictionary", + ] + return_type = "bool" + + func_decl = CxxFuncDeclNode( + name=name, arg_decls=arg_decls, return_type=return_type, const=True) + func_def = CxxFuncDefNode( + name=name, + class_name=cg_context.class_name, + arg_decls=arg_decls, + return_type=return_type, + const=True) + func_def.set_base_template_vars(cg_context.template_bindings()) body = func_def.body - body.add_template_vars(cg_context.template_bindings()) - - text = """\ -const v8::Eternal<v8::Name>* member_names = GetV8MemberNames(isolate); -v8::Local<v8::Context> current_context = isolate->GetCurrentContext();""" - body.append(T(text)) + body.add_template_var("isolate", "isolate") + bind_member_iteration_local_vars(body) - # TODO(peria): Support runtime enabled / origin trial members. for key_index, member in enumerate(own_members): _1 = _blink_member_name(member).has_api _2 = key_index @@ -251,8 +425,8 @@ v8::Local<v8::Context> current_context = isolate->GetCurrentContext();""" if ({_1}()) {{ if (!v8_dictionary ->CreateDataProperty( - current_context, - member_names[{_2}].Get(isolate), + ${current_context}, + ${member_names}[{_2}].Get(isolate), ToV8({_3}(), creation_context, isolate)) .ToChecked()) {{ return false; @@ -263,133 +437,162 @@ if ({_1}()) {{ conditional = expr_from_exposure(member.exposure) if not conditional.is_always_true: - node = SequenceNode([ - T(_format("if ({}) {{", conditional.to_text())), - node, - T("}"), - ]) + node = CxxLikelyIfNode(cond=conditional, body=node) body.append(node) body.append(T("return true;")) - return func_def + return func_decl, func_def -def make_dict_create_def(cg_context): +def make_dict_create_funcs(cg_context): assert isinstance(cg_context, CodeGenContext) - T = TextNode - - dictionary = cg_context.dictionary - class_name = blink_class_name(dictionary) - - func_def = FunctionDefinitionNode( - name=T(_format("{_1}::Create", _1=class_name)), - arg_decls=[ - T("v8::Isolate* isolate"), - T("v8::Local<v8::Object> v8_dictionary"), - T("ExceptionState& exception_state"), - ], - return_type=T(_format("{_1}*", _1=class_name)), - comment=T("// static")) - - body = func_def.body - body.add_template_vars(cg_context.template_bindings()) - - pattern = """\ -{_1}* dictionary = MakeGarbageCollected<{_1}>(); -dictionary->FillMembers(isolate, v8_dictionary, exception_state); + name = "Create" + arg_decls = [ + "v8::Isolate* isolate", + "v8::Local<v8::Value> v8_value", + "ExceptionState& exception_state", + ] + return_type = "${class_name}*" + + default_create_def = CxxFuncDefNode( + name=name, arg_decls=[], return_type=return_type, static=True) + default_create_def.set_base_template_vars(cg_context.template_bindings()) + + default_create_def.body.append( + TextNode("return MakeGarbageCollected<${class_name}>();")) + + create_decl = CxxFuncDeclNode( + name=name, arg_decls=arg_decls, return_type=return_type, static=True) + create_def = CxxFuncDefNode( + name=name, + class_name=cg_context.class_name, + arg_decls=arg_decls, + return_type=return_type) + create_def.set_base_template_vars(cg_context.template_bindings()) + + create_def.body.append( + TextNode("""\ +DCHECK(!v8_value.IsEmpty()); + +${class_name}* dictionary = MakeGarbageCollected<${class_name}>(); +dictionary->FillMembers(isolate, v8_value, exception_state); if (exception_state.HadException()) { return nullptr; } -return dictionary;""" - body.append(T(_format(pattern, _1=class_name))) +return dictionary;""")) - return func_def + decls = ListNode([ + default_create_def, + create_decl, + ]) + defs = ListNode([ + create_def, + ]) + return decls, defs -def make_fill_dict_members_def(cg_context): + +def make_fill_dict_members_func(cg_context): assert isinstance(cg_context, CodeGenContext) T = TextNode dictionary = cg_context.dictionary - class_name = blink_class_name(dictionary) own_members = dictionary.own_members required_own_members = list( member for member in own_members if member.is_required) - - func_name = _format("{_1}::FillMembers", _1=class_name) - func_def = FunctionDefinitionNode( - name=T(func_name), - arg_decls=[ - T("v8::Isolate* isolate"), - T("v8::Local<v8::Object> v8_dictionary"), - T("ExceptionState& exception_state"), - ], - return_type=T("void")) - - body = func_def.body - body.add_template_vars(cg_context.template_bindings()) - - text = "if (v8_dictionary->IsUndefinedOrNull()) { return; }" - if len(required_own_members) > 0: - text = """\ -if (v8_dictionary->IsUndefinedOrNull()) { - exception_state.ThrowError(ExceptionMessages::FailedToConstruct( + name = "FillMembers" + arg_decls = [ + "v8::Isolate* isolate", + "v8::Local<v8::Value> v8_value", + "ExceptionState& exception_state", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=name, arg_decls=arg_decls, return_type=return_type) + func_def = CxxFuncDefNode( + name=name, + class_name=cg_context.class_name, + arg_decls=arg_decls, + return_type=return_type) + func_def.set_base_template_vars(cg_context.template_bindings()) + + if required_own_members: + check_required_members_node = T("""\ +if (v8_value->IsNullOrUndefined()) { + exception_state.ThrowTypeError(ExceptionMessages::FailedToConstruct( "${dictionary.identifier}", "has required members, but null/undefined was passed.")); return; -}""" - body.append(T(text)) +}""") + else: + check_required_members_node = T("""\ +if (v8_value->IsNullOrUndefined()) { + return; +}""") # [PermissiveDictionaryConversion] if "PermissiveDictionaryConversion" in dictionary.extended_attributes: - text = """\ -if (!v8_dictionary->IsObject()) { + permissive_conversion_node = T("""\ +if (!v8_value->IsObject()) { // [PermissiveDictionaryConversion] return; -}""" +}""") else: - text = """\ -if (!v8_dictionary->IsObject()) { + permissive_conversion_node = T("""\ +if (!v8_value->IsObject()) { exception_state.ThrowTypeError( ExceptionMessages::FailedToConstruct( "${dictionary.identifier}", "The value is not of type Object")); return; -}""" - body.append(T(text)) +}""") - body.append( - T("FillMembersInternal(isolate, v8_dictionary, exception_state);")) + call_internal_func_node = T("""\ +FillMembersInternal(isolate, v8_value.As<v8::Object>(), exception_state);""") - return func_def + func_def.body.extend([ + check_required_members_node, + permissive_conversion_node, + call_internal_func_node, + ]) + + return func_decl, func_def -def make_fill_dict_members_internal_def(cg_context): +def make_fill_dict_members_internal_func(cg_context): assert isinstance(cg_context, CodeGenContext) T = TextNode dictionary = cg_context.dictionary own_members = dictionary.own_members - class_name = blink_class_name(dictionary) - - func_name = _format("{_1}::FillMembersInternal", _1=class_name) - func_def = FunctionDefinitionNode( - name=T(func_name), - arg_decls=[ - T("v8::Isolate* isolate"), - T("v8::Local<v8::Object> v8_dictionary"), - T("ExceptionState& exception_state"), - ], - return_type=T("void")) - + name = "FillMembersInternal" + arg_decls = [ + "v8::Isolate* isolate", + "v8::Local<v8::Object> v8_dictionary", + "ExceptionState& exception_state", + ] + return_type = "void" + func_decl = CxxFuncDeclNode( + name=name, arg_decls=arg_decls, return_type=return_type) + func_def = CxxFuncDefNode( + name=name, + class_name=cg_context.class_name, + arg_decls=arg_decls, + return_type=return_type) + func_def.set_base_template_vars(cg_context.template_bindings()) body = func_def.body - body.add_template_vars(cg_context.template_bindings()) body.add_template_var("isolate", "isolate") body.add_template_var("exception_state", "exception_state") + bind_member_iteration_local_vars(body) + body.register_code_symbols([ + SymbolNode("try_block", "v8::TryCatch ${try_block}(${isolate});"), + SymbolNode("v8_value", "v8::Local<v8::Value> ${v8_value};"), + ]) if dictionary.inherited: text = """\ @@ -400,20 +603,10 @@ if (${exception_state}.HadException()) { """ body.append(T(text)) - body.extend([ - T("const v8::Eternal<v8::Name>* member_names = " - "GetV8MemberNames(${isolate});"), - T("v8::TryCatch try_block(${isolate});"), - T("v8::Local<v8::Context> current_context = " - "${isolate}->GetCurrentContext();"), - T("v8::Local<v8::Value> v8_value;"), - ]) - - # TODO(peria): Support origin-trials and runtime enabled features. for key_index, member in enumerate(own_members): body.append(make_fill_own_dict_member(key_index, member)) - return func_def + return func_decl, func_def def make_fill_own_dict_member(key_index, member): @@ -423,116 +616,266 @@ def make_fill_own_dict_member(key_index, member): T = TextNode pattern = """ -if (!v8_dictionary->Get(current_context, member_names[{_1}].Get(${isolate})) - .ToLocal(&v8_memer)) {{ - ${exception_state}.RethrowV8Exception(try_block.Exception()); +if (!<% try_block %>v8_dictionary->Get(${current_context}, ${member_names}[{_1}].Get(${isolate})) + .ToLocal(&${v8_value})) {{ + ${exception_state}.RethrowV8Exception(${try_block}.Exception()); return; }}""" get_v8_value_node = T(_format(pattern, _1=key_index)) api_call_node = SymbolScopeNode() api_call_node.register_code_symbol( - make_v8_to_blink_value("blink_value", "v8_value", member.idl_type)) + make_v8_to_blink_value("blink_value", "${v8_value}", member.idl_type)) _1 = _blink_member_name(member).set_api api_call_node.append(T(_format("{_1}(${blink_value});", _1=_1))) - throw_if_required_member_is_missing_node = None if member.is_required: - pattern = """\ + exception_pattern = """\ ${exception_state}.ThrowTypeError( ExceptionMessages::FailedToGet( - "{_1}", "${{dictionary.identifier}}", + "{}", "${{dictionary.identifier}}", "Required member is undefined.")); """ - throw_if_required_member_is_missing_node = T( - _format(pattern, _1=member.identifier)) + + check_and_fill_node = CxxIfElseNode( + cond="!${v8_value}->IsUndefined()", + then=api_call_node, + then_likeliness=Likeliness.LIKELY, + else_=T(_format(exception_pattern, member.identifier)), + else_likeliness=Likeliness.UNLIKELY) + else: + check_and_fill_node = CxxLikelyIfNode( + cond="!${v8_value}->IsUndefined()", body=api_call_node) node = SequenceNode([ get_v8_value_node, - T("if (!v8_value->IsUndefined()) {"), - api_call_node, - T("} else {") if throw_if_required_member_is_missing_node else None, - throw_if_required_member_is_missing_node, - T("}"), + check_and_fill_node, ]) conditional = expr_from_exposure(member.exposure) if not conditional.is_always_true: - node = SequenceNode([ - T(_format("if ({}) {{", conditional.to_text())), - node, - T("}"), - ]) + node = CxxLikelyIfNode(cond=conditional, body=node) return node -def make_dict_trace_def(cg_context): +def make_dict_trace_func(cg_context): assert isinstance(cg_context, CodeGenContext) T = TextNode dictionary = cg_context.dictionary own_members = dictionary.own_members - class_name = blink_class_name(dictionary) - - func_def = FunctionDefinitionNode( - name=T(_format("{_1}::Trace", _1=class_name)), - arg_decls=[ - T("Visitor* visitor"), - ], - return_type=T("void")) - + name = "Trace" + arg_decls = ["Visitor* visitor"] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=name, arg_decls=arg_decls, return_type=return_type, override=True) + func_def = CxxFuncDefNode( + name=name, + class_name=cg_context.class_name, + arg_decls=arg_decls, + return_type=return_type) + func_def.set_base_template_vars(cg_context.template_bindings()) body = func_def.body - body.add_template_vars(cg_context.template_bindings()) - def trace_member_node(member): + def make_trace_member_node(member): pattern = "TraceIfNeeded<{_1}>::Trace(visitor, {_2});" _1 = blink_type_info(member.idl_type).member_t _2 = _blink_member_name(member).value_var - return T(_format(pattern, _1=_1, _2=_2)) - - body.extend(map(trace_member_node, own_members)) + return TextNode(_format(pattern, _1=_1, _2=_2)) - if dictionary.inherited: - body.append(T("BaseClass::Trace(visitor);")) - - return func_def - - -def generate_dictionaries(web_idl_database, output_dirs): - dictionary = web_idl_database.find("MediaDecodingConfiguration") - filename = "example_dictionary.cc" - filepath = os.path.join(output_dirs['core'], filename) + body.extend(map(make_trace_member_node, own_members)) + body.append(TextNode("BaseClass::Trace(visitor);")) - cg_context = CodeGenContext(dictionary=dictionary) + return func_decl, func_def - root_node = SymbolScopeNode(separator_last="\n") - root_node.set_renderer(MakoRenderer()) - code_node = SequenceNode() +def generate_dictionary(dictionary): + assert len(dictionary.components) == 1, ( + "We don't support partial dictionaries across components yet.") + component = dictionary.components[0] - code_node.extend([ - make_get_v8_dict_member_names_def(cg_context), - make_dict_create_def(cg_context), - make_fill_dict_members_def(cg_context), - make_fill_dict_members_internal_def(cg_context), - make_fill_with_dict_members_def(cg_context), - make_fill_with_own_dict_members_def(cg_context), - make_dict_trace_def(cg_context), - ]) - - for member in dictionary.own_members: - code_node.extend([ - make_dict_member_get_def(cg_context.make_copy(dict_member=member)), - make_dict_member_has_def(cg_context.make_copy(dict_member=member)), - make_dict_member_set_def(cg_context.make_copy(dict_member=member)), + path_manager = PathManager(dictionary) + class_name = name_style.class_(blink_class_name(dictionary)) + if dictionary.inherited: + base_class_name = blink_class_name(dictionary.inherited) + else: + base_class_name = "bindings::DictionaryBase" + + cg_context = CodeGenContext( + dictionary=dictionary, + class_name=class_name, + base_class_name=base_class_name) + + # Filepaths + basename = "dictionary_example" + header_path = path_manager.api_path(filename=basename, ext="h") + source_path = path_manager.api_path(filename=basename, ext="cc") + + # Root nodes + header_node = ListNode(tail="\n") + header_node.set_accumulator(CodeGenAccumulator()) + header_node.set_renderer(MakoRenderer()) + source_node = ListNode(tail="\n") + source_node.set_accumulator(CodeGenAccumulator()) + source_node.set_renderer(MakoRenderer()) + + # Namespaces + header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + + # Class definitions + class_def = CxxClassDefNode( + cg_context.class_name, + base_class_names=[cg_context.base_class_name], + export=component_export(component)) + class_def.set_base_template_vars(cg_context.template_bindings()) + class_def.top_section.append( + TextNode("using BaseClass = ${base_class_name};")) + + # Create functions + create_decl, create_def = make_dict_create_funcs(cg_context) + + # Constructor and destructor + constructor_decl = CxxFuncDeclNode( + name=cg_context.class_name, arg_decls=[], return_type="", default=True) + destructor_decl = CxxFuncDeclNode( + name="~${class_name}", arg_decls=[], return_type="", default=True) + + # Fill with members (Blink -> V8 conversion) + (fill_with_members_decl, + fill_with_members_def) = make_fill_with_dict_members_func(cg_context) + (fill_with_own_members_decl, fill_with_own_members_def + ) = make_fill_with_own_dict_members_func(cg_context) + + # Fill members (V8 -> Blink conversion) + (fill_members_decl, + fill_members_def) = make_fill_dict_members_func(cg_context) + (fill_members_internal_decl, fill_members_internal_def + ) = make_fill_dict_members_internal_func(cg_context) + + # Misc. functions + (get_v8_member_names_decl, + get_v8_member_names_def) = make_get_v8_dict_member_names_func(cg_context) + trace_decl, trace_def = make_dict_trace_func(cg_context) + + member_accessor_decls = ListNode() + member_accessor_defs = ListNode() + member_value_var_defs = ListNode() + member_presense_var_defs = ListNode() + for member in cg_context.dictionary.own_members: + member_context = cg_context.make_copy(dict_member=member) + get_decls, get_defs = make_dict_member_get(member_context) + has_decls, has_defs = make_dict_member_has(member_context) + set_decls, set_defs = make_dict_member_set(member_context) + value_var_def, presense_var_def = make_dict_member_vars(member_context) + member_accessor_decls.extend([ + TextNode(""), + get_decls, + has_decls, + set_decls, ]) - - root_node.extend([ + member_accessor_defs.extend([ + TextNode(""), + get_defs, + has_defs, + set_defs, + ]) + member_value_var_defs.append(value_var_def) + member_presense_var_defs.append(presense_var_def) + + # Header part (copyright, include directives, and forward declarations) + header_includes, source_includes = _make_include_headers(cg_context) + header_node.accumulator.add_include_headers(header_includes) + source_node.accumulator.add_include_headers(source_includes) + + (header_class_fwd_decls, header_struct_fwd_decls, source_class_fwd_decls, + source_struct_fwd_decls) = _make_forward_declarations(cg_context) + header_node.accumulator.add_class_decls(header_class_fwd_decls) + header_node.accumulator.add_struct_decls(header_struct_fwd_decls) + source_node.accumulator.add_class_decls(source_class_fwd_decls) + source_node.accumulator.add_struct_decls(source_struct_fwd_decls) + + header_node.extend([ + make_copyright_header(), + TextNode(""), + enclose_with_header_guard( + ListNode([ + make_header_include_directives(header_node.accumulator), + TextNode(""), + header_blink_ns, + ]), name_style.header_guard(header_path)), + ]) + header_blink_ns.body.extend([ + make_forward_declarations(header_node.accumulator), + TextNode(""), + ]) + source_node.extend([ make_copyright_header(), TextNode(""), - enclose_with_namespace(code_node, name_style.namespace("blink")), + TextNode("#include \"{}\"".format(header_path)), + TextNode(""), + make_header_include_directives(source_node.accumulator), + TextNode(""), + source_blink_ns, + ]) + source_blink_ns.body.extend([ + make_forward_declarations(source_node.accumulator), + TextNode(""), + ]) + + # Assemble the parts. + header_blink_ns.body.append(class_def) + class_def.public_section.extend([ + create_decl, + constructor_decl, + destructor_decl, + TextNode(""), + trace_decl, + TextNode(""), + member_accessor_decls, + ]) + class_def.protected_section.extend([ + fill_with_members_decl, + TextNode(""), + fill_members_internal_decl, + ]) + class_def.private_section.extend([ + get_v8_member_names_decl, + TextNode(""), + fill_with_own_members_decl, + TextNode(""), + fill_members_decl, + TextNode(""), + member_value_var_defs, + TextNode(""), + member_presense_var_defs, + ]) + source_blink_ns.body.extend([ + get_v8_member_names_def, + TextNode(""), + create_def, + TextNode(""), + fill_with_members_def, + TextNode(""), + fill_with_own_members_def, + TextNode(""), + fill_members_def, + TextNode(""), + fill_members_internal_def, + TextNode(""), + member_accessor_defs, + TextNode(""), + trace_def, ]) - write_code_node_to_file(root_node, filepath) + # Write down to the files. + write_code_node_to_file(header_node, path_manager.gen_path_to(header_path)) + write_code_node_to_file(source_node, path_manager.gen_path_to(source_path)) + + +def generate_dictionaries(web_idl_database): + dictionary = web_idl_database.find("RTCQuicStreamWriteParameters") + generate_dictionary(dictionary) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/enumeration.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/enumeration.py new file mode 100644 index 00000000000..3401ff9de18 --- /dev/null +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/enumeration.py @@ -0,0 +1,360 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from . import name_style +from .blink_v8_bridge import blink_class_name +from .code_node import EmptyNode +from .code_node import ListNode +from .code_node import TextNode +from .code_node_cxx import CxxClassDefNode +from .code_node_cxx import CxxFuncDeclNode +from .code_node_cxx import CxxFuncDefNode +from .code_node_cxx import CxxNamespaceNode +from .codegen_accumulator import CodeGenAccumulator +from .codegen_context import CodeGenContext +from .codegen_format import format_template as _format +from .codegen_utils import component_export +from .codegen_utils import component_export_header +from .codegen_utils import enclose_with_header_guard +from .codegen_utils import make_copyright_header +from .codegen_utils import make_forward_declarations +from .codegen_utils import make_header_include_directives +from .codegen_utils import write_code_node_to_file +from .mako_renderer import MakoRenderer +from .path_manager import PathManager + + +def make_factory_method(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + + factory_method_def = CxxFuncDefNode( + name="Create", + arg_decls=[ + "v8::Isolate* isolate", + "v8::Local<v8::Value> value", + "ExceptionState& exception_state", + ], + return_type="${class_name}", + static=True) + factory_method_def.set_base_template_vars(cg_context.template_bindings()) + + factory_method_def.body.extend([ + T("const auto& result = bindings::FindIndexInEnumStringTable(" + "isolate, value, string_table_, \"${enumeration.identifier}\", " + "exception_state);"), + T("return result.has_value() ? " + "${class_name}(static_cast<Enum>(result.value())) : " + "${class_name}();"), + ]) + + return factory_method_def, None + + +def make_constructors(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + + class_name = cg_context.class_name + + decls = ListNode([ + CxxFuncDeclNode( + name=class_name, + arg_decls=[], + return_type="", + constexpr=True, + default=True), + CxxFuncDefNode( + name=class_name, + arg_decls=["Enum value"], + return_type="", + explicit=True, + constexpr=True, + member_initializer_list=[ + "${base_class_name}(" + "static_cast<enum_int_t>(value), " + "string_table_[static_cast<enum_int_t>(value)])" + ]), + CxxFuncDeclNode( + name=class_name, + arg_decls=["const ${class_name}&"], + return_type="", + constexpr=True, + default=True), + CxxFuncDeclNode( + name=class_name, + arg_decls=["${class_name}&&"], + return_type="", + constexpr=True, + default=True), + CxxFuncDeclNode( + name="~${class_name}", arg_decls=[], return_type="", default=True), + ]) + + defs = ListNode([ + T("static_assert(" + "std::is_trivially_copyable<${class_name}>::value, \"\");"), + ]) + defs.set_base_template_vars(cg_context.template_bindings()) + + return decls, defs + + +def make_assignment_operators(cg_context): + assert isinstance(cg_context, CodeGenContext) + + decls = ListNode([ + CxxFuncDeclNode( + name="operator=", + arg_decls=["const ${class_name}&"], + return_type="${class_name}&", + default=True), + CxxFuncDeclNode( + name="operator=", + arg_decls=["${class_name}&&"], + return_type="${class_name}&", + default=True), + ]) + defs = ListNode() + + # Migration adapter + func_decl = CxxFuncDeclNode( + name="operator=", + arg_decls=["const String&"], + return_type="${class_name}&") + func_def = CxxFuncDefNode( + name="operator=", + arg_decls=["const String& str_value"], + return_type="${class_name}&", + class_name=cg_context.class_name) + decls.append(func_decl) + defs.append(func_def) + + func_def.set_base_template_vars(cg_context.template_bindings()) + func_def.body.append( + TextNode("""\ +const auto& index = + bindings::FindIndexInEnumStringTable(str_value, string_table_); +CHECK(index.has_value()); +return operator=(${class_name}(static_cast<Enum>(index.value()))); +""")) + + return decls, defs + + +def make_equality_operators(cg_context): + assert isinstance(cg_context, CodeGenContext) + + func1_def = CxxFuncDefNode( + name="operator==", + arg_decls=["const ${class_name}& lhs", "${class_name}::Enum rhs"], + return_type="bool", + inline=True) + func1_def.set_base_template_vars(cg_context.template_bindings()) + func1_def.body.append(TextNode("return lhs.AsEnum() == rhs;")) + + func2_def = CxxFuncDefNode( + name="operator==", + arg_decls=["${class_name}::Enum lhs", "const ${class_name}& rhs"], + return_type="bool", + inline=True) + func2_def.set_base_template_vars(cg_context.template_bindings()) + func2_def.body.append(TextNode("return lhs == rhs.AsEnum();")) + + decls = ListNode([func1_def, EmptyNode(), func2_def]) + + # Migration adapter + func3_def = CxxFuncDefNode( + name="operator==", + arg_decls=["const ${class_name}& lhs", "const String& rhs"], + return_type="bool", + inline=True) + func3_def.set_base_template_vars(cg_context.template_bindings()) + func3_def.body.append(TextNode("return lhs.AsString() == rhs;")) + + func4_def = CxxFuncDefNode( + name="operator==", + arg_decls=["const String& lhs", "const ${class_name}& rhs"], + return_type="bool", + inline=True) + func4_def.set_base_template_vars(cg_context.template_bindings()) + func4_def.body.append(TextNode("return lhs == rhs.AsString();")) + + decls.extend([EmptyNode(), func3_def, EmptyNode(), func4_def]) + + return decls, None + + +def make_as_enum_function(cg_context): + assert isinstance(cg_context, CodeGenContext) + + func_def = CxxFuncDefNode( + name="AsEnum", arg_decls=[], return_type="Enum", const=True) + func_def.body.append(TextNode("return static_cast<Enum>(GetEnumValue());")) + + return func_def, None + + +def make_nested_enum_class_def(cg_context): + assert isinstance(cg_context, CodeGenContext) + + enum_values = [ + TextNode(name_style.constant(value)) + for value in cg_context.enumeration.values + ] + + return ListNode([ + TextNode("enum class Enum : enum_int_t {"), + ListNode(enum_values, separator=", "), + TextNode("};"), + ]) + + +def make_enum_string_table(cg_context): + assert isinstance(cg_context, CodeGenContext) + + str_values = [ + TextNode("\"{}\"".format(value)) + for value in cg_context.enumeration.values + ] + + decls = ListNode([ + TextNode("static constexpr const char* const string_table_[] = {"), + ListNode(str_values, separator=", "), + TextNode("};"), + ]) + + defs = TextNode("const char* const ${class_name}::string_table_[];") + defs.set_base_template_vars(cg_context.template_bindings()) + + return decls, defs + + +def generate_enumeration(enumeration): + path_manager = PathManager(enumeration) + assert path_manager.api_component == path_manager.impl_component + api_component = path_manager.api_component + + # Class names + class_name = blink_class_name(enumeration) + + cg_context = CodeGenContext( + enumeration=enumeration, + class_name=class_name, + base_class_name="bindings::EnumerationBase") + + # Filepaths + header_path = path_manager.api_path(ext="h") + source_path = path_manager.api_path(ext="cc") + + # Root nodes + header_node = ListNode(tail="\n") + header_node.set_accumulator(CodeGenAccumulator()) + header_node.set_renderer(MakoRenderer()) + source_node = ListNode(tail="\n") + source_node.set_accumulator(CodeGenAccumulator()) + source_node.set_renderer(MakoRenderer()) + + # Namespaces + header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + + # Class definition + class_def = CxxClassDefNode( + cg_context.class_name, + base_class_names=["bindings::EnumerationBase"], + final=True, + export=component_export(api_component)) + class_def.set_base_template_vars(cg_context.template_bindings()) + + # Implementation parts + factory_decls, factory_defs = make_factory_method(cg_context) + ctor_decls, ctor_defs = make_constructors(cg_context) + assign_decls, assign_defs = make_assignment_operators(cg_context) + equal_decls, equal_defs = make_equality_operators(cg_context) + nested_enum_class_def = make_nested_enum_class_def(cg_context) + table_decls, table_defs = make_enum_string_table(cg_context) + as_enum_decl, as_enum_def = make_as_enum_function(cg_context) + + # Header part (copyright, include directives, and forward declarations) + header_node.extend([ + make_copyright_header(), + EmptyNode(), + enclose_with_header_guard( + ListNode([ + make_header_include_directives(header_node.accumulator), + EmptyNode(), + header_blink_ns, + ]), name_style.header_guard(header_path)), + ]) + header_blink_ns.body.extend([ + make_forward_declarations(header_node.accumulator), + EmptyNode(), + ]) + source_node.extend([ + make_copyright_header(), + EmptyNode(), + TextNode("#include \"{}\"".format(header_path)), + EmptyNode(), + make_header_include_directives(source_node.accumulator), + EmptyNode(), + source_blink_ns, + ]) + source_blink_ns.body.extend([ + make_forward_declarations(source_node.accumulator), + EmptyNode(), + ]) + header_node.accumulator.add_include_headers([ + component_export_header(api_component), + "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h", + "third_party/blink/renderer/platform/bindings/enumeration_base.h", + ]) + + # Assemble the parts. + header_blink_ns.body.append(class_def) + header_blink_ns.body.append(EmptyNode()) + + class_def.public_section.append(nested_enum_class_def) + class_def.public_section.append(EmptyNode()) + + class_def.public_section.append(factory_decls) + class_def.public_section.append(EmptyNode()) + source_blink_ns.body.append(factory_defs) + source_blink_ns.body.append(EmptyNode()) + + class_def.private_section.append(table_decls) + class_def.private_section.append(EmptyNode()) + source_blink_ns.body.append(table_defs) + source_blink_ns.body.append(EmptyNode()) + + class_def.public_section.append(ctor_decls) + class_def.public_section.append(EmptyNode()) + source_blink_ns.body.append(ctor_defs) + source_blink_ns.body.append(EmptyNode()) + + class_def.public_section.append(assign_decls) + class_def.public_section.append(EmptyNode()) + source_blink_ns.body.append(assign_defs) + source_blink_ns.body.append(EmptyNode()) + + class_def.public_section.append(as_enum_decl) + class_def.public_section.append(EmptyNode()) + source_blink_ns.body.append(as_enum_def) + source_blink_ns.body.append(EmptyNode()) + + header_blink_ns.body.append(equal_decls) + header_blink_ns.body.append(EmptyNode()) + source_blink_ns.body.append(equal_defs) + source_blink_ns.body.append(EmptyNode()) + + # Write down to the files. + write_code_node_to_file(header_node, path_manager.gen_path_to(header_path)) + write_code_node_to_file(source_node, path_manager.gen_path_to(source_path)) + + +def generate_enumerations(web_idl_database): + for enumeration in web_idl_database.enumerations: + generate_enumeration(enumeration) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index 03b2a99a629..9d2ce6944de 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py @@ -3,6 +3,7 @@ # found in the LICENSE file. import itertools +import multiprocessing import os.path import web_idl @@ -12,26 +13,184 @@ from .blink_v8_bridge import blink_class_name from .blink_v8_bridge import blink_type_info from .blink_v8_bridge import make_v8_to_blink_value from .blink_v8_bridge import make_v8_to_blink_value_variadic -from .code_node import CodeNode -from .code_node import FunctionDefinitionNode -from .code_node import LiteralNode +from .blink_v8_bridge import v8_bridge_class_name +from .code_node import EmptyNode +from .code_node import ListNode from .code_node import SequenceNode from .code_node import SymbolDefinitionNode from .code_node import SymbolNode from .code_node import SymbolScopeNode from .code_node import TextNode -from .code_node import UnlikelyExitNode +from .code_node_cxx import CxxBlockNode +from .code_node_cxx import CxxBreakableBlockNode +from .code_node_cxx import CxxClassDefNode +from .code_node_cxx import CxxFuncDeclNode +from .code_node_cxx import CxxFuncDefNode +from .code_node_cxx import CxxLikelyIfNode +from .code_node_cxx import CxxMultiBranchesNode +from .code_node_cxx import CxxNamespaceNode +from .code_node_cxx import CxxUnlikelyIfNode from .codegen_accumulator import CodeGenAccumulator from .codegen_context import CodeGenContext +from .codegen_expr import CodeGenExpr from .codegen_expr import expr_from_exposure from .codegen_expr import expr_or from .codegen_format import format_template as _format -from .codegen_utils import collect_include_headers -from .codegen_utils import enclose_with_namespace +from .codegen_utils import component_export +from .codegen_utils import component_export_header +from .codegen_utils import enclose_with_header_guard from .codegen_utils import make_copyright_header +from .codegen_utils import make_forward_declarations from .codegen_utils import make_header_include_directives from .codegen_utils import write_code_node_to_file from .mako_renderer import MakoRenderer +from .path_manager import PathManager + + +def _is_none_or_str(arg): + return arg is None or isinstance(arg, str) + + +def backward_compatible_api_func(cg_context): + """ + Returns the Blink function name compatible with the old bindings generator. + """ + assert isinstance(cg_context, CodeGenContext) + + name = (cg_context.member_like.code_generator_info.property_implemented_as + or cg_context.member_like.identifier + or cg_context.property_.identifier) + + if cg_context.attribute_get: + # modules/webaudio/biquad_filter_node.idl has readonly attribute "Q" + # and somehow it's implemented as "q" in Blink. + if name == "Q": + name = "q" + + if cg_context.attribute_set: + tokens = name_style.raw.tokenize(name) + if tokens[0] in ("IDL", "css", "xml"): + tokens[0] = tokens[0].upper() + else: + tokens[0] = tokens[0].capitalize() + tokens.insert(0, "set") + name = "".join(tokens) + + if cg_context.indexed_property_getter and not name: + name = "AnonymousIndexedGetter" + if cg_context.indexed_property_setter and not name: + name = "AnonymousIndexedSetter" + if cg_context.named_property_getter and not name: + name = "AnonymousNamedGetter" + if cg_context.named_property_setter and not name: + name = "AnonymousNamedSetter" + if cg_context.named_property_deleter and not name: + name = "AnonymousNamedDeleter" + + return name + + +def callback_function_name(cg_context, + overload_index=None, + for_cross_origin=False): + assert isinstance(cg_context, CodeGenContext) + + def _cxx_name(name): + """ + Returns a property name that the bindings generator can use in + generated code. + + Note that Web IDL allows '-' (hyphen-minus) and '_' (low line) in + identifiers but C++ does not allow or recommend them. This function + encodes these characters. + """ + # In Python3, we can use str.maketrans and str.translate. + # + # We're optimistic about name conflict. It's highly unlikely that + # these replacements will cause a conflict. + assert "Dec45" not in name + assert "Dec95" not in name + name = name.replace("-", "Dec45") + name = name.replace("_", "Dec95") + return name + + if cg_context.constant: + property_name = cg_context.property_.identifier + else: + property_name = _cxx_name(cg_context.property_.identifier) + + if cg_context.attribute_get: + kind = "AttributeGet" + elif cg_context.attribute_set: + kind = "AttributeSet" + elif cg_context.constant: + kind = "Constant" + elif cg_context.constructor_group: + property_name = "" + kind = "Constructor" + elif cg_context.exposed_construct: + if cg_context.legacy_window_alias: + kind = "LegacyWindowAlias" + else: + kind = "ExposedConstruct" + elif cg_context.operation_group: + kind = "Operation" + elif cg_context.stringifier: + kind = "Operation" + + if for_cross_origin: + suffix = "CrossOrigin" + elif overload_index is not None: + suffix = "Overload{}".format(overload_index + 1) + else: + suffix = "Callback" + + if cg_context.for_world == CodeGenContext.MAIN_WORLD: + world_suffix = "ForMainWorld" + elif cg_context.for_world == CodeGenContext.NON_MAIN_WORLDS: + world_suffix = "ForNonMainWorlds" + elif cg_context.for_world == CodeGenContext.ALL_WORLDS: + world_suffix = "" + + return name_style.func(property_name, kind, suffix, world_suffix) + + +def constant_name(cg_context): + assert isinstance(cg_context, CodeGenContext) + assert cg_context.constant + + property_name = cg_context.property_.identifier.lower() + + kind = "Constant" + + return name_style.constant(kind, property_name) + + +def custom_function_name(cg_context): + assert isinstance(cg_context, CodeGenContext) + + if cg_context.named_property_getter: + return "NamedPropertyGetterCustom" + if cg_context.named_property_setter: + return "NamedPropertySetterCustom" + if cg_context.named_property_deleter: + return "NamedPropertyDeleterCustom" + + if cg_context.attribute_get: + suffix = "AttributeGetterCustom" + elif cg_context.attribute_set: + suffix = "AttributeSetterCustom" + elif cg_context.operation_group: + suffix = "MethodCustom" + else: + assert False + + return name_style.func(cg_context.property_.identifier, suffix) + + +# ---------------------------------------------------------------------------- +# Callback functions +# ---------------------------------------------------------------------------- def bind_blink_api_arguments(code_node, cg_context): @@ -43,7 +202,7 @@ def bind_blink_api_arguments(code_node, cg_context): if cg_context.attribute_set: name = "arg1_value" - v8_value = "${info}[0]" + v8_value = "${v8_property_value}" code_node.register_code_symbol( make_v8_to_blink_value(name, v8_value, cg_context.attribute.idl_type)) @@ -58,8 +217,12 @@ def bind_blink_api_arguments(code_node, cg_context): else: v8_value = "${{info}}[{}]".format(argument.index) code_node.register_code_symbol( - make_v8_to_blink_value(name, v8_value, argument.idl_type, - argument.default_value)) + make_v8_to_blink_value( + name, + v8_value, + argument.idl_type, + argument_index=index, + default_value=argument.default_value)) def bind_callback_local_vars(code_node, cg_context): @@ -73,17 +236,15 @@ def bind_callback_local_vars(code_node, cg_context): template_vars = {} local_vars.extend([ + S("blink_property_name", + ("const AtomicString& ${blink_property_name} = " + "ToCoreAtomicString(${v8_property_name}.As<v8::String>());")), S("class_like_name", ("const char* const ${class_like_name} = " "\"${class_like.identifier}\";")), S("current_context", ("v8::Local<v8::Context> ${current_context} = " "${isolate}->GetCurrentContext();")), - S("current_execution_context", - ("ExecutionContext* ${current_execution_context} = " - "ExecutionContext::From(${current_script_state});")), S("current_script_state", ("ScriptState* ${current_script_state} = " "ScriptState::From(${current_context});")), - S("execution_context", ("ExecutionContext* ${execution_context} = " - "ExecutionContext::From(${script_state});")), S("isolate", "v8::Isolate* ${isolate} = ${info}.GetIsolate();"), S("per_context_data", ("V8PerContextData* ${per_context_data} = " "${script_state}->PerContextData();")), @@ -101,7 +262,8 @@ def bind_callback_local_vars(code_node, cg_context): ]) is_receiver_context = (cg_context.member_like - and not cg_context.member_like.is_static) + and not cg_context.member_like.is_static + and not cg_context.constructor) # creation_context pattern = "const v8::Local<v8::Context>& ${creation_context} = {_1};" @@ -119,6 +281,24 @@ def bind_callback_local_vars(code_node, cg_context): if is_receiver_context else "${current_script_state}") local_vars.append(S("script_state", _format(pattern, _1=_1))) + # execution_context + node = S("execution_context", ("ExecutionContext* ${execution_context} = " + "ExecutionContext::From(${script_state});")) + node.accumulate( + CodeGenAccumulator.require_include_headers([ + "third_party/blink/renderer/core/execution_context/execution_context.h" + ])) + local_vars.append(node) + + # execution_context_of_document_tree + pattern = "ExecutionContext* ${execution_context_of_document_tree} = {_1};" + if is_receiver_context: + _1 = "bindings::ExecutionContextFromV8Wrappable(${blink_receiver})" + else: + _1 = "${execution_context}" # of the current context + text = _format(pattern, _1=_1) + local_vars.append(S("execution_context_of_document_tree", text)) + # exception_state_context_type pattern = ( "const ExceptionState::ContextType ${exception_state_context_type} = " @@ -129,6 +309,16 @@ def bind_callback_local_vars(code_node, cg_context): _1 = "ExceptionState::kSetterContext" elif cg_context.constructor: _1 = "ExceptionState::kConstructionContext" + elif cg_context.indexed_property_getter: + _1 = "ExceptionState::kIndexedGetterContext" + elif cg_context.indexed_property_setter: + _1 = "ExceptionState::kIndexedSetterContext" + elif cg_context.named_property_getter: + _1 = "ExceptionState::kGetterContext" + elif cg_context.named_property_setter: + _1 = "ExceptionState::kSetterContext" + elif cg_context.named_property_deleter: + _1 = "ExceptionState::kDeletionContext" else: _1 = "ExceptionState::kExecutionContext" local_vars.append( @@ -138,8 +328,9 @@ def bind_callback_local_vars(code_node, cg_context): pattern = "ExceptionState ${exception_state}({_1});{_2}" _1 = [ "${isolate}", "${exception_state_context_type}", "${class_like_name}", - "${property_name}" ] + if cg_context.property_ and cg_context.property_.identifier: + _1.append("${property_name}") _2 = "" if cg_context.return_type and cg_context.return_type.unwrap().is_promise: _2 = ("\n" @@ -154,26 +345,174 @@ def bind_callback_local_vars(code_node, cg_context): # [ImplementedAs=LocalDOMWindow] instead of [ImplementedAs=DOMWindow], # and [CrossOrigin] properties should be implemented specifically with # DOMWindow class. Then, we'll have less hacks. - if "CrossOrigin" in cg_context.member_like.extended_attributes: + if (not cg_context.member_like or + "CrossOrigin" in cg_context.member_like.extended_attributes): text = ("DOMWindow* ${blink_receiver} = " - "${v8_class}::ToBlinkUnsafe(${v8_receiver});") + "${class_name}::ToWrappableUnsafe(${v8_receiver});") else: text = ("LocalDOMWindow* ${blink_receiver} = To<LocalDOMWindow>(" - "${v8_class}::ToBlinkUnsafe(${v8_receiver}));") + "${class_name}::ToWrappableUnsafe(${v8_receiver}));") else: pattern = ("{_1}* ${blink_receiver} = " - "${v8_class}::ToBlinkUnsafe(${v8_receiver});") + "${class_name}::ToWrappableUnsafe(${v8_receiver});") _1 = blink_class_name(cg_context.class_like) text = _format(pattern, _1=_1) local_vars.append(S("blink_receiver", text)) + # v8_property_value + if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK: + # In case of V8_ACCESSOR_NAME_SETTER_CALLBACK, |v8_property_value| is + # defined as an argument. In case of V8_FUNCTION_CALLBACK (of IDL + # attribute set function), |info[0]| is the value to be set. + local_vars.append( + S("v8_property_value", + "v8::Local<v8::Value> ${v8_property_value} = ${info}[0];")) + code_node.register_code_symbols(local_vars) code_node.add_template_vars(template_vars) -def _make_blink_api_call(cg_context, num_of_args=None): +def _make_reflect_content_attribute_key(code_node, cg_context): + assert isinstance(code_node, SymbolScopeNode) + assert isinstance(cg_context, CodeGenContext) + + name = (cg_context.attribute.extended_attributes.value_of("Reflect") + or cg_context.attribute.identifier.lower()) + if cg_context.attribute_get and name in ("class", "id", "name"): + return None + + if cg_context.class_like.identifier.startswith("SVG"): + namespace = "svg_names" + code_node.accumulate( + CodeGenAccumulator.require_include_headers( + ["third_party/blink/renderer/core/svg_names.h"])) + else: + namespace = "html_names" + code_node.accumulate( + CodeGenAccumulator.require_include_headers( + ["third_party/blink/renderer/core/html_names.h"])) + return "{}::{}".format(namespace, name_style.constant(name, "attr")) + + +def _make_reflect_accessor_func_name(cg_context): + assert isinstance(cg_context, CodeGenContext) + assert cg_context.attribute_get or cg_context.attribute_set + + if cg_context.attribute_get: + name = (cg_context.attribute.extended_attributes.value_of("Reflect") + or cg_context.attribute.identifier.lower()) + if name in ("class", "id", "name"): + return name_style.func("get", name, "attribute") + + if "URL" in cg_context.attribute.extended_attributes: + return "GetURLAttribute" + + FAST_ACCESSORS = { + "boolean": ("FastHasAttribute", "SetBooleanAttribute"), + "long": ("GetIntegralAttribute", "SetIntegralAttribute"), + "unsigned long": ("GetUnsignedIntegralAttribute", + "SetUnsignedIntegralAttribute"), + } + idl_type = cg_context.attribute.idl_type.unwrap() + accessors = FAST_ACCESSORS.get(idl_type.keyword_typename) + if accessors: + return accessors[0 if cg_context.attribute_get else 1] + + if (idl_type.is_interface + and idl_type.type_definition_object.does_implement("Element")): + if cg_context.attribute_get: + return "GetElementAttribute" + else: + return "SetElementAttribute" + + if idl_type.element_type: + element_type = idl_type.element_type.unwrap() + if (element_type.is_interface and + element_type.type_definition_object.does_implement("Element")): + if cg_context.attribute_get: + return "GetElementArrayAttribute" + else: + return "SetElementArrayAttribute" + + if cg_context.attribute_get: + return "FastGetAttribute" + else: + return "setAttribute" + + +def _make_reflect_process_keyword_state(cg_context): + # https://html.spec.whatwg.org/C/#keywords-and-enumerated-attributes + + assert isinstance(cg_context, CodeGenContext) + assert cg_context.attribute_get or cg_context.attribute_set + + T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) + + if not cg_context.attribute_get: + return None + + ext_attrs = cg_context.attribute.extended_attributes + keywords = ext_attrs.values_of("ReflectOnly") + missing_default = ext_attrs.value_of("ReflectMissing") + empty_default = ext_attrs.value_of("ReflectEmpty") + invalid_default = ext_attrs.value_of("ReflectInvalid") + + def constant(keyword): + if not keyword: + return "g_empty_atom" + return "keywords::{}".format(name_style.constant(keyword)) + + branches = CxxMultiBranchesNode() + branches.accumulate( + CodeGenAccumulator.require_include_headers( + ["third_party/blink/renderer/core/keywords.h"])) + nodes = [ + T("// [ReflectOnly]"), + T("const AtomicString reflect_value(${return_value}.LowerASCII());"), + branches, + ] + + if missing_default is not None: + branches.append( + cond="reflect_value.IsNull()", + body=F("${return_value} = {};", constant(missing_default))) + elif cg_context.return_type.unwrap(nullable=False).is_nullable: + branches.append( + cond="reflect_value.IsNull()", + body=T("// Null string to IDL null.")) + + if empty_default is not None: + branches.append( + cond="reflect_value.IsEmpty()", + body=F("${return_value} = {};", constant(empty_default))) + + expr = " || ".join( + map(lambda keyword: "reflect_value == {}".format(constant(keyword)), + keywords)) + branches.append(cond=expr, body=T("${return_value} = reflect_value;")) + + if invalid_default is not None: + branches.append( + cond=True, + body=F("${return_value} = {};", constant(invalid_default))) + else: + branches.append( + cond=True, body=F("${return_value} = {};", constant(""))) + + return SequenceNode(nodes) + + +def _make_blink_api_call(code_node, + cg_context, + num_of_args=None, + overriding_args=None): + assert isinstance(code_node, SymbolScopeNode) assert isinstance(cg_context, CodeGenContext) assert num_of_args is None or isinstance(num_of_args, (int, long)) + assert (overriding_args is None + or (isinstance(overriding_args, (list, tuple)) + and all(isinstance(arg, str) for arg in overriding_args))) arguments = [] ext_attrs = cg_context.member_like.extended_attributes @@ -187,8 +526,24 @@ def _make_blink_api_call(cg_context, num_of_args=None): arguments.append("${script_state}") if "ExecutionContext" in values: arguments.append("${execution_context}") + if "Document" in values: + arguments.append( + "*bindings::ToDocumentFromExecutionContext(${execution_context})") - if cg_context.attribute_get: + code_generator_info = cg_context.member_like.code_generator_info + is_partial = code_generator_info.defined_in_partial + if (is_partial and + not (cg_context.constructor or cg_context.member_like.is_static)): + arguments.append("*${blink_receiver}") + + if "Reflect" in ext_attrs: # [Reflect] + key = _make_reflect_content_attribute_key(code_node, cg_context) + if key: + arguments.append(key) + + if overriding_args is not None: + arguments.extend(overriding_args) + elif cg_context.attribute_get: pass elif cg_context.attribute_set: arguments.append("${arg1_value}") @@ -205,86 +560,106 @@ def _make_blink_api_call(cg_context, num_of_args=None): if cg_context.may_throw_exception: arguments.append("${exception_state}") - code_generator_info = cg_context.member_like.code_generator_info - - func_name = (code_generator_info.property_implemented_as - or name_style.api_func(cg_context.member_like.identifier)) - if cg_context.attribute_set: - func_name = name_style.api_func("set", func_name) + func_name = backward_compatible_api_func(cg_context) + if cg_context.constructor: + func_name = "Create" + if "Reflect" in ext_attrs: # [Reflect] + func_name = _make_reflect_accessor_func_name(cg_context) - is_partial_or_mixin = (code_generator_info.defined_in_partial - or code_generator_info.defined_in_mixin) - if cg_context.member_like.is_static or is_partial_or_mixin: + if (cg_context.constructor or cg_context.member_like.is_static + or is_partial): class_like = cg_context.member_like.owner_mixin or cg_context.class_like class_name = (code_generator_info.receiver_implemented_as or name_style.class_(class_like.identifier)) func_designator = "{}::{}".format(class_name, func_name) - if not cg_context.member_like.is_static: - arguments.insert(0, "*${blink_receiver}") else: func_designator = _format("${blink_receiver}->{}", func_name) return _format("{_1}({_2})", _1=func_designator, _2=", ".join(arguments)) -def bind_return_value(code_node, cg_context): +def bind_return_value(code_node, cg_context, overriding_args=None): assert isinstance(code_node, SymbolScopeNode) assert isinstance(cg_context, CodeGenContext) + assert (overriding_args is None + or (isinstance(overriding_args, (list, tuple)) + and all(isinstance(arg, str) for arg in overriding_args))) T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) def create_definition(symbol_node): - api_calls = [] - arguments = (cg_context.function_like.arguments - if cg_context.function_like else []) - for index, arg in enumerate(arguments): - if arg.is_optional and not arg.default_value: - api_calls.append((index, _make_blink_api_call( - cg_context, index))) - api_calls.append((None, _make_blink_api_call(cg_context))) + api_calls = [] # Pairs of (num_of_args, api_call_text) + if overriding_args is None: + arguments = (cg_context.function_like.arguments + if cg_context.function_like else []) + for index, arg in enumerate(arguments): + if arg.is_optional and not arg.default_value: + api_calls.append((index, + _make_blink_api_call( + code_node, cg_context, index))) + api_calls.append((None, _make_blink_api_call( + code_node, cg_context))) + else: + api_calls.append((None, + _make_blink_api_call( + code_node, + cg_context, + overriding_args=overriding_args))) nodes = [] - is_return_type_void = cg_context.return_type.unwrap().is_void - if not is_return_type_void: + is_return_type_void = ((not cg_context.return_type + or cg_context.return_type.unwrap().is_void) and + not cg_context.does_override_idl_return_type) + if not (is_return_type_void + or cg_context.does_override_idl_return_type): return_type = blink_type_info(cg_context.return_type).value_t if len(api_calls) == 1: _, api_call = api_calls[0] if is_return_type_void: - nodes.append(T(_format("{};", api_call))) + nodes.append(F("{};", api_call)) elif cg_context.is_return_by_argument: - nodes.append(T(_format("{} ${return_value};", return_type))) - nodes.append(T(_format("{};", api_call))) + nodes.append(F("{} ${return_value};", return_type)) + nodes.append(F("{};", api_call)) + elif "ReflectOnly" in cg_context.member_like.extended_attributes: + # [ReflectOnly] + nodes.append(F("auto ${return_value} = {};", api_call)) else: - nodes.append( - T(_format("const auto& ${return_value} = {};", api_call))) + nodes.append(F("auto&& ${return_value} = {};", api_call)) else: - branches = SymbolScopeNode() + branches = SequenceNode() for index, api_call in api_calls: if is_return_type_void or cg_context.is_return_by_argument: - assignment = api_call + assignment = "{};".format(api_call) else: - assignment = _format("${return_value} = {}", api_call) + assignment = _format("${return_value} = {};", api_call) if index is not None: - pattern = ("if (${info}[{index}]->IsUndefined()) {{\n" - " {assignment};\n" - " break;\n" - "}}") + branches.append( + CxxLikelyIfNode( + cond=_format("${info}[{}]->IsUndefined()", index), + body=[ + T(assignment), + T("break;"), + ])) else: - pattern = "{assignment};" - text = _format(pattern, index=index, assignment=assignment) - branches.append(T(text)) + branches.append(T(assignment)) if not is_return_type_void: - nodes.append(T(_format("{} ${return_value};", return_type))) - nodes.append(T("do { // Dummy loop for use of 'break'")) - nodes.append(branches) - nodes.append(T("} while (false);")) + nodes.append(F("{} ${return_value};", return_type)) + nodes.append(CxxBreakableBlockNode(branches)) if cg_context.may_throw_exception: nodes.append( - UnlikelyExitNode( - cond=T("${exception_state}.HadException()"), - body=SymbolScopeNode([T("return;")]))) + CxxUnlikelyIfNode( + cond="${exception_state}.HadException()", + body=T("return;"))) + + if "ReflectOnly" in cg_context.member_like.extended_attributes: + # [ReflectOnly] + node = _make_reflect_process_keyword_state(cg_context) + if node: + nodes.append(EmptyNode()) + nodes.append(node) return SymbolDefinitionNode(symbol_node, nodes) @@ -292,35 +667,81 @@ def bind_return_value(code_node, cg_context): SymbolNode("return_value", definition_constructor=create_definition)) -def bind_v8_set_return_value(code_node, cg_context): - assert isinstance(code_node, SymbolScopeNode) +def make_bindings_trace_event(cg_context): assert isinstance(cg_context, CodeGenContext) - pattern = "{_1}({_2});" - _1 = "V8SetReturnValue" - _2 = ["${info}", "${return_value}"] + event_name = "{}.{}".format(cg_context.class_like.identifier, + cg_context.property_.identifier) + if cg_context.attribute_get: + event_name = "{}.{}".format(event_name, "get") + elif cg_context.attribute_set: + event_name = "{}.{}".format(event_name, "set") + elif cg_context.constructor_group: + event_name = "{}.{}".format(cg_context.class_like.identifier, + "constructor") - return_type = cg_context.return_type.unwrap(nullable=True, typedef=True) - if return_type.is_void: - # Render a SymbolNode |return_value| discarding the content text, and - # let a symbol definition be added. - pattern = "<% str(return_value) %>" - elif (cg_context.for_world == cg_context.MAIN_WORLD - and return_type.is_interface): - _1 = "V8SetReturnValueForMainWorld" - elif return_type.is_interface: - _2.append("${creation_context_object}") + return TextNode("BLINK_BINDINGS_TRACE_EVENT(\"{}\");".format(event_name)) - text = _format(pattern, _1=_1, _2=", ".join(_2)) - code_node.add_template_var("v8_set_return_value", TextNode(text)) +def make_check_argument_length(cg_context): + assert isinstance(cg_context, CodeGenContext) -_callback_common_binders = ( - bind_blink_api_arguments, - bind_callback_local_vars, - bind_return_value, - bind_v8_set_return_value, -) + T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) + + if cg_context.v8_callback_type != CodeGenContext.V8_FUNCTION_CALLBACK: + return None + + if cg_context.attribute_get: + num_of_required_args = 0 + elif cg_context.attribute_set: + idl_type = cg_context.attribute.idl_type + if not (idl_type.does_include_nullable_or_dict + or idl_type.unwrap().is_any or + "TreatNonObjectAsNull" in idl_type.unwrap().extended_attributes + or "PutForwards" in cg_context.attribute.extended_attributes + or "Replaceable" in cg_context.attribute.extended_attributes): + # ES undefined in ${v8_property_value} will cause a TypeError + # anyway, so omit the check against the number of arguments. + return None + num_of_required_args = 1 + elif cg_context.function_like: + num_of_required_args = ( + cg_context.function_like.num_of_required_arguments) + else: + assert False + + if num_of_required_args == 0: + return None + + return CxxUnlikelyIfNode( + cond=_format("UNLIKELY(${info}.Length() < {})", num_of_required_args), + body=[ + F(("${exception_state}.ThrowTypeError(" + "ExceptionMessages::NotEnoughArguments" + "({}, ${info}.Length()));"), num_of_required_args), + T("return;"), + ]) + + +def make_check_constructor_call(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + + return SequenceNode([ + CxxUnlikelyIfNode( + cond="!${info}.IsConstructCall()", + body=T("${exception_state}.ThrowTypeError(" + "ExceptionMessages::ConstructorNotCallableAsFunction(" + "${class_like_name}));\n" + "return;")), + CxxLikelyIfNode( + cond=("ConstructorMode::Current(${isolate}) == " + "ConstructorMode::kWrapExistingObject"), + body=T("bindings::V8SetReturnValue(${info}, ${v8_receiver});\n" + "return;")), + ]) def make_check_receiver(cg_context): @@ -332,24 +753,22 @@ def make_check_receiver(cg_context): and "LenientThis" in cg_context.attribute.extended_attributes): return SequenceNode([ T("// [LenientThis]"), - UnlikelyExitNode( - cond=T( - "!${v8_class}::HasInstance(${v8_receiver}, ${isolate})"), - body=SymbolScopeNode([T("return;")])), + CxxUnlikelyIfNode( + cond="!${class_name}::HasInstance(${isolate}, ${v8_receiver})", + body=T("return;")), ]) - if cg_context.return_type.unwrap().is_promise: + if cg_context.return_type and cg_context.return_type.unwrap().is_promise: return SequenceNode([ T("// Promise returning function: " "Convert a TypeError to a reject promise."), - UnlikelyExitNode( - cond=T( - "!${v8_class}::HasInstance(${v8_receiver}, ${isolate})"), - body=SymbolScopeNode([ + CxxUnlikelyIfNode( + cond="!${class_name}::HasInstance(${isolate}, ${v8_receiver})", + body=[ T("${exception_state}.ThrowTypeError(" "\"Illegal invocation\");"), - T("return;") - ])), + T("return;"), + ]) ]) return None @@ -368,27 +787,47 @@ def make_check_security_of_return_value(cg_context): web_feature = _format( "WebFeature::{}", name_style.constant("CrossOrigin", cg_context.class_like.identifier, - cg_context.member_like.identifier)) - use_counter = _format( - "UseCounter::Count(${current_execution_context}, {});", web_feature) + cg_context.property_.identifier)) + use_counter = _format("UseCounter::Count(${execution_context}, {});", + web_feature) cond = T("!BindingSecurity::ShouldAllowAccessTo(" "ToLocalDOMWindow(${current_context}), ${return_value}, " "BindingSecurity::ErrorReportOption::kDoNotReport)") - body = SymbolScopeNode([ + body = [ T(use_counter), - T("V8SetReturnValueNull(${info});\n" + T("bindings::V8SetReturnValue(${info}, nullptr);\n" "return;"), - ]) - return SequenceNode([ + ] + node = SequenceNode([ T("// [CheckSecurity=ReturnValue]"), - UnlikelyExitNode(cond=cond, body=body), + CxxUnlikelyIfNode(cond=cond, body=body), ]) + node.accumulate( + CodeGenAccumulator.require_include_headers([ + "third_party/blink/renderer/bindings/core/v8/binding_security.h", + "third_party/blink/renderer/core/frame/web_feature.h", + "third_party/blink/renderer/platform/instrumentation/use_counter.h", + ])) + return node + + +def make_cooperative_scheduling_safepoint(cg_context): + assert isinstance(cg_context, CodeGenContext) + + node = TextNode("scheduler::CooperativeSchedulingManager::Instance()" + "->Safepoint();") + node.accumulate( + CodeGenAccumulator.require_include_headers([ + "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h" + ])) + return node def make_log_activity(cg_context): assert isinstance(cg_context, CodeGenContext) - ext_attrs = cg_context.member_like.extended_attributes + target = cg_context.member_like or cg_context.property_ + ext_attrs = target.extended_attributes if "LogActivity" not in ext_attrs: return None target = ext_attrs.value_of("LogActivity") @@ -414,10 +853,10 @@ def make_log_activity(cg_context): if cg_context.attribute_get: _1 = "LogGetter" _4 = "" - if cg_context.attribute_set: + elif cg_context.attribute_set: _1 = "LogSetter" - _4 = ", ${info}[0]" - if cg_context.operation_group: + _4 = ", ${v8_property_value}" + elif cg_context.operation_group: _1 = "LogMethod" _4 = ", ${info}" body = _format(pattern, _1=_1, _2=_2, _3=_3, _4=_4) @@ -426,22 +865,13 @@ def make_log_activity(cg_context): node = TextNode(_format(pattern, _1=cond, _2=body)) node.accumulate( CodeGenAccumulator.require_include_headers([ - "third_party/blink/renderer/" - "platform/bindings/v8_dom_activity_logger.h", + "third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.h", + "third_party/blink/renderer/platform/bindings/v8_per_context_data.h", ])) return node -def _make_overloaded_function_name(function_like): - if isinstance(function_like, web_idl.Constructor): - return name_style.func("constructor", "overload", - function_like.overload_index + 1) - else: - return name_style.func(function_like.identifier, "op", "overload", - function_like.overload_index + 1) - - -def _make_overload_dispatcher_per_arg_size(items): +def _make_overload_dispatcher_per_arg_size(cg_context, items): """ https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm @@ -454,6 +884,12 @@ def _make_overload_dispatcher_per_arg_size(items): exists a case that overload resolution will fail, i.e. a bailout that throws a TypeError is necessary. """ + assert isinstance(cg_context, CodeGenContext) + assert isinstance(items, (list, tuple)) + assert all( + isinstance(item, web_idl.OverloadGroup.EffectiveOverloadItem) + for item in items) + # Variables shared with nested functions if len(items) > 1: arg_index = web_idl.OverloadGroup.distinguishing_argument_index(items) @@ -496,7 +932,8 @@ def _make_overload_dispatcher_per_arg_size(items): def make_node(pattern): value = _format("${info}[{}]", arg_index) - func_name = _make_overloaded_function_name(func_like) + func_name = callback_function_name(cg_context, + func_like.overload_index) return TextNode(_format(pattern, value=value, func_name=func_name)) def dispatch_if(expr): @@ -509,11 +946,7 @@ def _make_overload_dispatcher_per_arg_size(items): node = make_node(pattern) conditional = expr_from_exposure(func_like.exposure) if not conditional.is_always_true: - node = SymbolScopeNode([ - TextNode("if (" + conditional.to_text() + ") {"), - node, - TextNode("}"), - ]) + node = CxxUnlikelyIfNode(cond=conditional, body=node) dispatcher_nodes.append(node) return expr is True and conditional.is_always_true @@ -528,8 +961,7 @@ def _make_overload_dispatcher_per_arg_size(items): dispatch_if("{value}->IsUndefined()") # 12.3. if V is null or undefined, ... - func_like = find( - lambda t, u: t.does_include_nullable_type or u.is_dictionary) + func_like = find(lambda t, u: t.does_include_nullable_or_dict) if func_like: dispatch_if("{value}->IsNullOrUndefined()") @@ -541,27 +973,19 @@ def _make_overload_dispatcher_per_arg_size(items): # Attempt to match from most derived to least derived. for func_like, idl_type in sorted( find_all_interfaces(), key=inheritance_length, reverse=True): - cgc = CodeGenContext( - interface=idl_type.unwrap().type_definition_object) + v8_bridge_name = v8_bridge_class_name( + idl_type.unwrap().type_definition_object) dispatch_if( - _format("{}::HasInstance(${isolate}, {value})", cgc.v8_class)) + _format("{}::HasInstance(${isolate}, {value})", v8_bridge_name)) + # V8 specific optimization: BufferSource = ArrayBufferView or ArrayBuffer is_typedef_name = lambda t, name: t.is_typedef and t.identifier == name - func_like_a = find( - lambda t, u: is_typedef_name(t.unwrap(typedef=False), - "ArrayBufferView")) - func_like_b = find( + func_like = find( lambda t, u: is_typedef_name(t.unwrap(typedef=False), "BufferSource")) - if func_like_a or func_like_b: - # V8 specific optimization: ArrayBufferView - if func_like_a: - func_like = func_like_a - dispatch_if("{value}->IsArrayBufferView()") - if func_like_b: - func_like = func_like_b - dispatch_if("{value}->IsArrayBufferView() || " - "{value}->IsArrayBuffer() || " - "{value}->IsSharedArrayBuffer()") + if func_like: + dispatch_if("{value}->IsArrayBufferView() || " + "{value}->IsArrayBuffer() || " + "{value}->IsSharedArrayBuffer()") else: # 12.5. if Type(V) is Object, V has an [[ArrayBufferData]] internal # slot, ... @@ -570,16 +994,24 @@ def _make_overload_dispatcher_per_arg_size(items): dispatch_if("{value}->IsArrayBuffer() || " "{value}->IsSharedArrayBuffer()") - # 12.6. if Type(V) is Object, V has a [[DataView]] internal slot, ... - func_like = find(lambda t, u: u.is_data_view) + # V8 specific optimization: ArrayBufferView + func_like = find(lambda t, u: u.is_array_buffer_view) if func_like: - dispatch_if("{value}->IsDataView()") + dispatch_if("{value}->IsArrayBufferView()") - # 12.7. if Type(V) is Object, V has a [[TypedArrayName]] internal slot, - # ... - func_like = find(lambda t, u: u.is_typed_array_type) + # 12.6. if Type(V) is Object, V has a [[DataView]] internal slot, ... + func_like = find(lambda t, u: u.is_data_view) + if func_like: + dispatch_if("{value}->IsDataView()") + + # 12.7. if Type(V) is Object, V has a [[TypedArrayName]] internal slot, ... + typed_array_types = ("Int8Array", "Int16Array", "Int32Array", "Uint8Array", + "Uint16Array", "Uint32Array", "Uint8ClampedArray", + "Float32Array", "Float64Array") + for typed_array_type in typed_array_types: + func_like = find(lambda t, u: u.keyword_typename == typed_array_type) if func_like: - dispatch_if("{value}->IsTypedArray()") + dispatch_if(_format("{value}->Is{}()", typed_array_type)) # 12.8. if IsCallable(V) is true, ... func_like = find(lambda t, u: u.is_callback_function) @@ -653,46 +1085,32 @@ def make_overload_dispatcher(cg_context): for arg_size, items in items_grouped_by_arg_size: items = list(items) - node, can_fail = _make_overload_dispatcher_per_arg_size(items) + node, can_fail = _make_overload_dispatcher_per_arg_size( + cg_context, items) if arg_size > 0: - node = SymbolScopeNode([ - T("if (${info}.Length() >= " + str(arg_size) + ") {"), - node, - T("break;") if can_fail else None, - T("}"), - ]) + node = CxxLikelyIfNode( + cond=_format("${info}.Length() >= {}", arg_size), + body=[node, T("break;") if can_fail else None]) did_use_break = did_use_break or can_fail - terms = map( - lambda item: expr_from_exposure(item.function_like.exposure), - items) - conditional = expr_or(terms) + conditional = expr_or( + map(lambda item: expr_from_exposure(item.function_like.exposure), + items)) if not conditional.is_always_true: - node = SymbolScopeNode([ - T("if (" + conditional.to_text() + ") {"), - node, - T("}"), - ]) + node = CxxUnlikelyIfNode(cond=conditional, body=node) branches.append(node) if did_use_break: - branches = SymbolScopeNode([ - T("do { // Dummy loop for use of 'break'"), - branches, - T("} while (false);"), - ]) - # Make the entire branches an indivisible chunk so that SymbolDefinitionNode - # will not be inserted in-between. - branches = LiteralNode(branches) + branches = CxxBreakableBlockNode(branches) if not did_use_break and arg_size == 0 and conditional.is_always_true: return branches return SequenceNode([ branches, - T(""), + EmptyNode(), T("${exception_state}.ThrowTypeError" "(\"Overload resolution failed.\");\n" "return;"), @@ -702,7 +1120,8 @@ def make_overload_dispatcher(cg_context): def make_report_deprecate_as(cg_context): assert isinstance(cg_context, CodeGenContext) - name = cg_context.member_like.extended_attributes.value_of("DeprecateAs") + target = cg_context.member_like or cg_context.property_ + name = target.extended_attributes.value_of("DeprecateAs") if not name: return None @@ -712,16 +1131,16 @@ def make_report_deprecate_as(cg_context): _1 = name node = TextNode(_format(pattern, _1=_1)) node.accumulate( - CodeGenAccumulator.require_include_headers([ - "third_party/blink/renderer/core/frame/deprecation.h", - ])) + CodeGenAccumulator.require_include_headers( + ["third_party/blink/renderer/core/frame/deprecation.h"])) return node def make_report_measure_as(cg_context): assert isinstance(cg_context, CodeGenContext) - ext_attrs = cg_context.member_like.extended_attributes + target = cg_context.member_like or cg_context.property_ + ext_attrs = target.extended_attributes if not ("Measure" in ext_attrs or "MeasureAs" in ext_attrs): assert "HighEntropy" not in ext_attrs, "{}: {}".format( cg_context.idl_location_and_name, @@ -736,9 +1155,11 @@ def make_report_measure_as(cg_context): suffix = "_AttributeSetter" elif cg_context.constructor: suffix = "_Constructor" + elif cg_context.exposed_construct: + suffix = "_ConstructorGetter" elif cg_context.operation: suffix = "_Method" - name = cg_context.member_like.extended_attributes.value_of("MeasureAs") + name = ext_attrs.value_of("MeasureAs") or ext_attrs.value_of("Measure") if name: name = "k{}".format(name) elif cg_context.constructor: @@ -746,7 +1167,7 @@ def make_report_measure_as(cg_context): else: name = "kV8{}_{}{}".format( cg_context.class_like.identifier, - name_style.raw.upper_camel_case(cg_context.member_like.identifier), + name_style.raw.upper_camel_case(cg_context.property_.identifier), suffix) node = SequenceNode() @@ -770,9 +1191,8 @@ def make_report_measure_as(cg_context): _1 = name node.append(TextNode(_format(pattern, _1=_1))) node.accumulate( - CodeGenAccumulator.require_include_headers([ - "third_party/blink/renderer/core/frame/dactyloscoper.h", - ])) + CodeGenAccumulator.require_include_headers( + ["third_party/blink/renderer/core/frame/dactyloscoper.h"])) return node @@ -786,13 +1206,13 @@ def make_return_value_cache_return_early(cg_context): return TextNode("""\ // [CachedAttribute] static const V8PrivateProperty::SymbolKey kPrivatePropertyCachedAttribute; -auto v8_private_cached_attribute = +auto&& v8_private_cached_attribute = V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertyCachedAttribute); -if (!impl->""" + pred + """()) { +if (!${blink_receiver}->""" + pred + """()) { v8::Local<v8::Value> v8_value; if (v8_private_cached_attribute.GetOrUndefined(${v8_receiver}) .ToLocal(&v8_value) && !v8_value->IsUndefined()) { - V8SetReturnValue(${info}, v8_value); + bindings::V8SetReturnValue(${info}, v8_value); return; } }""") @@ -801,13 +1221,13 @@ if (!impl->""" + pred + """()) { return TextNode("""\ // [SaveSameObject] static const V8PrivateProperty::SymbolKey kPrivatePropertySaveSameObject; -auto v8_private_save_same_object = +auto&& v8_private_save_same_object = V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertySaveSameObject); { v8::Local<v8::Value> v8_value; if (v8_private_save_same_object.GetOrUndefined(${v8_receiver}) .ToLocal(&v8_value) && !v8_value->IsUndefined()) { - V8SetReturnValue(${info}, v8_value); + bindings::V8SetReturnValue(${info}, v8_value); return; } }""") @@ -827,63 +1247,266 @@ def make_return_value_cache_update_value(cg_context): "(${v8_receiver}, ${info}.GetReturnValue().Get());") -def make_runtime_call_timer_scope(cg_context): +def make_runtime_call_timer_scope(cg_context, overriding_name=None): assert isinstance(cg_context, CodeGenContext) + assert _is_none_or_str(overriding_name) + + target = cg_context.member_like or cg_context.property_ - pattern = "RUNTIME_CALL_TIMER_SCOPE{_1}(${isolate}, {_2});" - _1 = "_DISABLED_BY_DEFAULT" suffix = "" if cg_context.attribute_get: suffix = "_Getter" elif cg_context.attribute_set: suffix = "_Setter" - counter = cg_context.member_like.extended_attributes.value_of( - "RuntimeCallStatsCounter") + elif cg_context.exposed_construct: + suffix = "_ConstructorGetterCallback" + + counter = (target and + target.extended_attributes.value_of("RuntimeCallStatsCounter")) if counter: - _2 = "k{}{}".format(counter, suffix) + macro_name = "RUNTIME_CALL_TIMER_SCOPE" + counter_name = "RuntimeCallStats::CounterId::k{}{}".format( + counter, suffix) else: - _2 = "\"Blink_{}_{}{}\"".format( - blink_class_name(cg_context.class_like), - cg_context.member_like.identifier, suffix) - node = TextNode(_format(pattern, _1=_1, _2=_2)) - node.accumulate( + macro_name = "RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT" + counter_name = "\"Blink_{}_{}{}\"".format( + blink_class_name(cg_context.class_like), overriding_name + or target.identifier, suffix) + + return TextNode( + _format( + "{macro_name}(${info}.GetIsolate(), {counter_name});", + macro_name=macro_name, + counter_name=counter_name)) + + +def make_steps_of_ce_reactions(cg_context): + assert isinstance(cg_context, CodeGenContext) + assert (cg_context.attribute_set or cg_context.operation + or cg_context.indexed_property_setter + or cg_context.named_property_setter + or cg_context.named_property_deleter) + + T = TextNode + + nodes = [] + + ext_attrs = cg_context.member_like.extended_attributes + if "CustomElementCallbacks" in ext_attrs or "Reflect" in ext_attrs: + if "CustomElementCallbacks" in ext_attrs: + nodes.append(T("// [CustomElementCallbacks]")) + elif "Reflect" in ext_attrs: + nodes.append(T("// [Reflect]")) + nodes.append( + T("V0CustomElementProcessingStack::CallbackDeliveryScope " + "v0_custom_element_scope;")) + + if "CEReactions" in ext_attrs: + nodes.append(T("// [CEReactions]")) + nodes.append(T("CEReactionsScope ce_reactions_scope;")) + + if not nodes: + return None + + nodes = SequenceNode(nodes) + nodes.accumulate( CodeGenAccumulator.require_include_headers([ - "third_party/blink/renderer/platform/bindings/runtime_call_stats.h", + "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h", + "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h" ])) - return node + return nodes -def make_attribute_get_callback_def(cg_context, function_name): +def make_steps_of_put_forwards(cg_context): assert isinstance(cg_context, CodeGenContext) - assert isinstance(function_name, str) T = TextNode - cg_context = cg_context.make_copy(attribute_get=True) + return SequenceNode([ + T("// [PutForwards]"), + T("v8::Local<v8::Value> target;"), + T("if (!${v8_receiver}->Get(${current_context}, " + "V8AtomicString(${isolate}, ${property_name}))" + ".ToLocal(&target)) {\n" + " return;\n" + "}"), + CxxUnlikelyIfNode( + cond="!target->IsObject()", + body=[ + T("${exception_state}.ThrowTypeError(" + "\"The attribute value is not an object\");"), + T("return;"), + ]), + T("bool did_set;"), + T("if (!target.As<v8::Object>()->Set(${current_context}, " + "V8AtomicString(${isolate}, " + "\"${attribute.extended_attributes.value_of(\"PutForwards\")}\"" + "), ${v8_property_value}).To(&did_set)) {{\n" + " return;\n" + "}}"), + ]) + + +def make_steps_of_replaceable(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + + return SequenceNode([ + T("// [Replaceable]"), + T("bool did_create;"), + T("if (!${v8_receiver}->CreateDataProperty(${current_context}, " + "V8AtomicString(${isolate}, ${property_name}), " + "${v8_property_value}).To(&did_create)) {\n" + " return;\n" + "}"), + ]) + + +def make_v8_set_return_value(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + + if cg_context.does_override_idl_return_type: + return T("bindings::V8SetReturnValue(${info}, ${return_value});") + + if not cg_context.return_type or cg_context.return_type.unwrap().is_void: + # Request a SymbolNode |return_value| to define itself without + # rendering any text. + return T("<% return_value.request_symbol_definition() %>") + + operation = cg_context.operation + if operation and (operation.is_setter or operation.is_deleter): + # Blink implementation returns in a type different from the IDL type. + # Namely, IndexedPropertySetterResult, NamedPropertySetterResult, and + # NamedPropertyDeleterResult are returned ignoring the operation's + # return type. + return T("bindings::V8SetReturnValue(${info}, ${return_value});") + + return_type = cg_context.return_type + if return_type.is_typedef: + if return_type.identifier in ("EventHandler", + "OnBeforeUnloadEventHandler", + "OnErrorEventHandler"): + return T("bindings::V8SetReturnValue(${info}, ${return_value}, " + "${isolate}, ${blink_receiver});") + + return_type = return_type.unwrap(typedef=True) + return_type_body = return_type.unwrap() + + V8_RETURN_VALUE_FAST_TYPES = ("boolean", "byte", "octet", "short", + "unsigned short", "long", "unsigned long") + if return_type.keyword_typename in V8_RETURN_VALUE_FAST_TYPES: + return T("bindings::V8SetReturnValue(${info}, ${return_value});") + + if return_type_body.is_string: + args = ["${info}", "${return_value}", "${isolate}"] + if return_type.is_nullable: + args.append("bindings::V8ReturnValue::kNullable") + else: + args.append("bindings::V8ReturnValue::kNonNullable") + return T("bindings::V8SetReturnValue({});".format(", ".join(args))) + + if return_type_body.is_interface: + args = ["${info}", "${return_value}"] + if cg_context.for_world == cg_context.MAIN_WORLD: + args.append("bindings::V8ReturnValue::kMainWorld") + elif cg_context.constructor or cg_context.member_like.is_static: + args.append("${creation_context}") + else: + args.append("${blink_receiver}") + return T("bindings::V8SetReturnValue({});".format(", ".join(args))) + + if return_type.is_frozen_array: + return T("bindings::V8SetReturnValue(${info}, FreezeV8Object(ToV8(" + "${return_value}, ${creation_context_object}, ${isolate}), " + "${isolate}));") + + if return_type.is_promise: + return T("bindings::V8SetReturnValue" + "(${info}, ${return_value}.V8Value());") - func_def = FunctionDefinitionNode( - name=T(function_name), - arg_decls=[T("const v8::FunctionCallbackInfo<v8::Value>& info")], - return_type=T("void")) + return T("bindings::V8SetReturnValue(${info}, " + "ToV8(${return_value}, ${creation_context_object}, ${isolate}));") + +def _make_empty_callback_def(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK: + arg_decls = ["const v8::FunctionCallbackInfo<v8::Value>& info"] + arg_names = ["info"] + elif (cg_context.v8_callback_type == CodeGenContext. + V8_ACCESSOR_NAME_GETTER_CALLBACK): + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + arg_names = ["v8_property_name", "info"] + elif (cg_context.v8_callback_type == CodeGenContext. + V8_ACCESSOR_NAME_SETTER_CALLBACK): + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "v8::Local<v8::Value> v8_property_value", + "const v8::PropertyCallbackInfo<void>& info", + ] + arg_names = ["v8_property_name", "v8_property_value", "info"] + elif (cg_context.v8_callback_type == CodeGenContext. + V8_GENERIC_NAMED_PROPERTY_SETTER_CALLBACK): + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "v8::Local<v8::Value> v8_property_value", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + arg_names = ["v8_property_name", "v8_property_value", "info"] + + func_def = CxxFuncDefNode( + name=function_name, arg_decls=arg_decls, return_type="void") + func_def.set_base_template_vars(cg_context.template_bindings()) body = func_def.body - body.add_template_var("info", "info") - body.add_template_vars(cg_context.template_bindings()) - for bind in _callback_common_binders: - bind(body, cg_context) + for arg_name in arg_names: + body.add_template_var(arg_name, arg_name) + + bind_callback_local_vars(body, cg_context) + if cg_context.attribute or cg_context.function_like: + bind_blink_api_arguments(body, cg_context) + bind_return_value(body, cg_context) + + return func_def + + +def make_attribute_get_callback_def(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = _make_empty_callback_def(cg_context, function_name) + body = func_def.body body.extend([ make_runtime_call_timer_scope(cg_context), + make_bindings_trace_event(cg_context), make_report_deprecate_as(cg_context), make_report_measure_as(cg_context), make_log_activity(cg_context), - T(""), + EmptyNode(), + ]) + + if "Getter" in cg_context.property_.extended_attributes.values_of( + "Custom"): + text = _format("${class_name}::{}(${info});", + custom_function_name(cg_context)) + body.append(TextNode(text)) + return func_def + + body.extend([ make_check_receiver(cg_context), make_return_value_cache_return_early(cg_context), - T(""), + EmptyNode(), make_check_security_of_return_value(cg_context), - T("${v8_set_return_value}"), + make_v8_set_return_value(cg_context), make_return_value_cache_update_value(cg_context), ]) @@ -894,59 +1517,263 @@ def make_attribute_set_callback_def(cg_context, function_name): assert isinstance(cg_context, CodeGenContext) assert isinstance(function_name, str) - return None + ext_attrs = cg_context.attribute.extended_attributes + if cg_context.attribute.is_readonly and not any( + ext_attr in ext_attrs + for ext_attr in ("LenientSetter", "PutForwards", "Replaceable")): + return None + func_def = _make_empty_callback_def(cg_context, function_name) + body = func_def.body -def make_operation_function_def(cg_context, function_name): + if "LenientSetter" in ext_attrs: + body.append(TextNode("// [LenientSetter]")) + return func_def + + body.extend([ + make_runtime_call_timer_scope(cg_context), + make_bindings_trace_event(cg_context), + make_report_deprecate_as(cg_context), + make_report_measure_as(cg_context), + make_log_activity(cg_context), + EmptyNode(), + ]) + + if "Setter" in cg_context.property_.extended_attributes.values_of( + "Custom"): + text = _format("${class_name}::{}(${v8_property_value}, ${info});", + custom_function_name(cg_context)) + body.append(TextNode(text)) + return func_def + + body.extend([ + make_check_receiver(cg_context), + make_check_argument_length(cg_context), + EmptyNode(), + ]) + + if "PutForwards" in ext_attrs: + body.append(make_steps_of_put_forwards(cg_context)) + return func_def + + if "Replaceable" in ext_attrs: + body.append(make_steps_of_replaceable(cg_context)) + return func_def + + body.extend([ + make_steps_of_ce_reactions(cg_context), + EmptyNode(), + make_v8_set_return_value(cg_context), + ]) + + return func_def + + +def make_constant_callback_def(cg_context, function_name): assert isinstance(cg_context, CodeGenContext) assert isinstance(function_name, str) - T = TextNode + logging_nodes = SequenceNode([ + make_report_deprecate_as(cg_context), + make_report_measure_as(cg_context), + make_log_activity(cg_context), + ]) + if not logging_nodes: + return None - func_def = FunctionDefinitionNode( - name=T(function_name), - arg_decls=[T("const v8::FunctionCallbackInfo<v8::Value>& info")], - return_type=T("void")) + func_def = _make_empty_callback_def(cg_context, function_name) + body = func_def.body + v8_set_return_value = _format( + "bindings::V8SetReturnValue(${info}, ${class_name}::{});", + constant_name(cg_context)) + body.extend([ + make_runtime_call_timer_scope(cg_context), + make_bindings_trace_event(cg_context), + logging_nodes, + EmptyNode(), + TextNode(v8_set_return_value), + ]) + + return func_def + + +def make_constant_constant_def(cg_context, constant_name): + # IDL constant's C++ constant definition + assert isinstance(cg_context, CodeGenContext) + assert isinstance(constant_name, str) + + constant_type = blink_type_info(cg_context.constant.idl_type).value_t + return TextNode("static constexpr {type} {name} = {value};".format( + type=constant_type, + name=constant_name, + value=cg_context.constant.value.literal)) + + +def make_overload_dispatcher_function_def(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = _make_empty_callback_def(cg_context, function_name) body = func_def.body - body.add_template_var("info", "info") - body.add_template_vars(cg_context.template_bindings()) - for bind in _callback_common_binders: - bind(body, cg_context) + if cg_context.operation_group: + body.append(make_operation_entry(cg_context)) + body.append(EmptyNode()) + body.append(make_cooperative_scheduling_safepoint(cg_context)) + body.append(EmptyNode()) - body.extend([ + if cg_context.constructor_group: + body.append(make_constructor_entry(cg_context)) + body.append(EmptyNode()) + + body.append(make_overload_dispatcher(cg_context)) + + return func_def + + +def make_constructor_entry(cg_context): + assert isinstance(cg_context, CodeGenContext) + + return SequenceNode([ make_runtime_call_timer_scope(cg_context), + make_bindings_trace_event(cg_context), + EmptyNode(), + make_check_constructor_call(cg_context), + ]) + + +def make_constructor_function_def(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + T = TextNode + + func_def = _make_empty_callback_def(cg_context, function_name) + body = func_def.body + + if len(cg_context.constructor_group) == 1: + body.append(make_constructor_entry(cg_context)) + body.append(EmptyNode()) + + body.extend([ make_report_deprecate_as(cg_context), make_report_measure_as(cg_context), make_log_activity(cg_context), - T(""), - make_check_receiver(cg_context), - T(""), - T("${v8_set_return_value}"), + EmptyNode(), + make_check_argument_length(cg_context), + EmptyNode(), ]) + if "HTMLConstructor" in cg_context.constructor.extended_attributes: + body.append(T("// [HTMLConstructor]")) + text = _format( + "V8HTMLConstructor::HtmlConstructor(" + "${info}, *${class_name}::GetWrapperTypeInfo(), " + "HTMLElementType::{});", + name_style.constant(cg_context.class_like.identifier)) + body.append(T(text)) + else: + body.append( + T("v8::Local<v8::Object> v8_wrapper = " + "${return_value}->AssociateWithWrapper(${isolate}, " + "${class_name}::GetWrapperTypeInfo(), ${v8_receiver});")) + body.append(T("bindings::V8SetReturnValue(${info}, v8_wrapper);")) + return func_def -def make_overload_dispatcher_function_def(cg_context, function_name): +def make_constructor_callback_def(cg_context, function_name): assert isinstance(cg_context, CodeGenContext) assert isinstance(function_name, str) - T = TextNode + constructor_group = cg_context.constructor_group + + if len(constructor_group) == 1: + return make_constructor_function_def( + cg_context.make_copy(constructor=constructor_group[0]), + function_name) + + node = SequenceNode() + for constructor in constructor_group: + cgc = cg_context.make_copy(constructor=constructor) + node.extend([ + make_constructor_function_def( + cgc, callback_function_name(cgc, constructor.overload_index)), + EmptyNode(), + ]) + node.append( + make_overload_dispatcher_function_def(cg_context, function_name)) + return node - func_def = FunctionDefinitionNode( - name=T(function_name), - arg_decls=[T("const v8::FunctionCallbackInfo<v8::Value>& info")], - return_type=T("void")) +def make_exposed_construct_callback_def(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = _make_empty_callback_def(cg_context, function_name) body = func_def.body - body.add_template_var("info", "info") - body.add_template_vars(cg_context.template_bindings()) - bind_callback_local_vars(body, cg_context) + v8_set_return_value = _format( + "bindings::V8SetReturnValue" + "(${info}, {}::GetWrapperTypeInfo(), " + "bindings::V8ReturnValue::kInterfaceObject);", + v8_bridge_class_name(cg_context.exposed_construct)) + body.extend([ + make_runtime_call_timer_scope(cg_context), + make_bindings_trace_event(cg_context), + make_report_deprecate_as(cg_context), + make_report_measure_as(cg_context), + make_log_activity(cg_context), + EmptyNode(), + TextNode(v8_set_return_value), + ]) - body.append(make_overload_dispatcher(cg_context)) + return func_def + + +def make_operation_entry(cg_context): + assert isinstance(cg_context, CodeGenContext) + + return SequenceNode([ + make_runtime_call_timer_scope(cg_context), + make_bindings_trace_event(cg_context), + ]) + + +def make_operation_function_def(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = _make_empty_callback_def(cg_context, function_name) + body = func_def.body + + if not cg_context.operation_group or len(cg_context.operation_group) == 1: + body.append(make_operation_entry(cg_context)) + body.append(EmptyNode()) + + body.extend([ + make_report_deprecate_as(cg_context), + make_report_measure_as(cg_context), + make_log_activity(cg_context), + EmptyNode(), + ]) + + if "Custom" in cg_context.property_.extended_attributes: + text = _format("${class_name}::{}(${info});", + custom_function_name(cg_context)) + body.append(TextNode(text)) + return func_def + + body.extend([ + make_check_receiver(cg_context), + make_check_argument_length(cg_context), + EmptyNode(), + make_steps_of_ce_reactions(cg_context), + EmptyNode(), + make_check_security_of_return_value(cg_context), + make_v8_set_return_value(cg_context), + ]) return func_def @@ -955,7 +1782,10 @@ def make_operation_callback_def(cg_context, function_name): assert isinstance(cg_context, CodeGenContext) assert isinstance(function_name, str) - operation_group = cg_context.constructor_group or cg_context.operation_group + operation_group = cg_context.operation_group + + assert (not ("Custom" in operation_group.extended_attributes) + or len(operation_group) == 1) if len(operation_group) == 1: return make_operation_function_def( @@ -963,16 +1793,938 @@ def make_operation_callback_def(cg_context, function_name): node = SequenceNode() for operation in operation_group: - node.append( + cgc = cg_context.make_copy(operation=operation) + node.extend([ make_operation_function_def( - cg_context.make_copy(operation=operation), - _make_overloaded_function_name(operation))) + cgc, callback_function_name(cgc, operation.overload_index)), + EmptyNode(), + ]) node.append( make_overload_dispatcher_function_def(cg_context, function_name)) return node -def bind_template_installer_local_vars(code_node, cg_context): +def make_indexed_property_getter_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + arg_decls = [ + "uint32_t index", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("index", "index") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + bind_return_value(body, cg_context, overriding_args=["${index}"]) + + body.extend([ + make_runtime_call_timer_scope(cg_context, "IndexedPropertyGetter"), + EmptyNode(), + make_v8_set_return_value(cg_context), + ]) + + return func_decl, func_def + + +def make_indexed_property_setter_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + if cg_context.indexed_property_setter is None: + return None, None + + arg_decls = [ + "uint32_t index", + "v8::Local<v8::Value> v8_value", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("index", "index") + body.add_template_var("v8_value", "v8_value") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + bind_return_value( + body, cg_context, overriding_args=["${index}", "${blink_value}"]) + body.register_code_symbol( + make_v8_to_blink_value( + "blink_value", + "${v8_value}", + cg_context.indexed_property_setter.arguments[1].idl_type, + argument_index=2)) + + body.extend([ + make_runtime_call_timer_scope(cg_context, "IndexedPropertySetter"), + EmptyNode(), + make_steps_of_ce_reactions(cg_context), + EmptyNode(), + make_v8_set_return_value(cg_context), + ]) + + return func_decl, func_def + + +def make_indexed_property_definer_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + arg_decls = [ + "uint32_t index", + "const v8::PropertyDescriptor& desc", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("index", "index") + body.add_template_var("desc", "desc") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + body.append( + TextNode("""\ +// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty +// 3.8.3. [[DefineOwnProperty]] +// step 1.1. If the result of calling IsDataDescriptor(Desc) is false, then +// return false. +if (desc.has_get() || desc.has_set()) { + bindings::V8SetReturnValue(${info}, nullptr); + if (${info}.ShouldThrowOnError()) { + ExceptionState exception_state(${info}.GetIsolate(), + ExceptionState::kIndexedSetterContext, + "${interface.identifier}"); + exception_state.ThrowTypeError("Accessor properties are not allowed."); + } + return; +} +""")) + + writable = bool( + cg_context.interface.indexed_and_named_properties.indexed_setter) + if writable: + body.append( + TextNode("""\ +// step 1.3. Invoke the indexed property setter with P and Desc.[[Value]]. +// +// Return nothing and fall back to +// ${class_name}::IndexedPropertySetterCallback.""")) + else: + body.append( + TextNode("""\ +// step 1.2. If O does not implement an interface with an indexed property +// setter, then return false. +bindings::V8SetReturnValue(${info}, nullptr); +if (${info}.ShouldThrowOnError()) { + ExceptionState exception_state(${info}.GetIsolate(), + ExceptionState::kIndexedSetterContext, + "${interface.identifier}"); + exception_state.ThrowTypeError("Index property setter is not supported."); + return; +}""")) + + return func_decl, func_def + + +def make_indexed_property_descriptor_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + arg_decls = [ + "uint32_t index", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("index", "index") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + pattern = """\ +// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty +// Steps 1.1. to 1.2. are covered here: we rely on +// IndexedPropertyGetterCallback() to call the getter function and check +// that |index| is a valid property index, in which case it will have set +// info.GetReturnValue() to something other than undefined. +${class_name}::IndexedPropertyGetterCallback(${index}, ${info}); +v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get(); +if (v8_value->IsUndefined()) + return; + +// 1.2.5. Let |desc| be a newly created Property Descriptor with no fields. +// 1.2.6. Set desc.[[Value]] to the result of converting value to an +// ECMAScript value. +// 1.2.7. If O implements an interface with an indexed property setter, +// then set desc.[[Writable]] to true, otherwise set it to false. +v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable}); +// 1.2.8. Set desc.[[Enumerable]] and desc.[[Configurable]] to true. +desc.set_enumerable(true); +desc.set_configurable(true); +// 1.2.9. Return |desc|. +bindings::V8SetReturnValue(${info}, desc);""" + writable = bool( + cg_context.interface.indexed_and_named_properties.indexed_setter) + cxx_writable = "true" if writable else "false" + body.append(TextNode(_format(pattern, cxx_writable=cxx_writable))) + + return func_decl, func_def + + +def make_indexed_property_enumerator_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + body.append( + TextNode("""\ +uint32_t length = ${blink_receiver}->length(); +v8::Local<v8::Array> array = + bindings::EnumerateIndexedProperties(${isolate}, length); +bindings::V8SetReturnValue(${info}, array);""")) + + return func_decl, func_def + + +def make_named_property_getter_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + bind_return_value( + body, cg_context, overriding_args=["${blink_property_name}"]) + + body.extend([ + make_runtime_call_timer_scope(cg_context, "NamedPropertyGetter"), + EmptyNode(), + ]) + + if "Custom" in cg_context.named_property_getter.extended_attributes: + text = _format("${class_name}::{}(${blink_property_name}, ${info});", + custom_function_name(cg_context)) + body.append(TextNode(text)) + else: + body.append(make_v8_set_return_value(cg_context)) + + return func_decl, func_def + + +def make_named_property_setter_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + if cg_context.named_property_setter is None: + return None, None + + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "v8::Local<v8::Value> v8_property_value", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("v8_property_value", "v8_property_value") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + bind_return_value( + body, + cg_context, + overriding_args=["${blink_property_name}", "${blink_value}"]) + body.register_code_symbol( + make_v8_to_blink_value( + "blink_value", + "${v8_property_value}", + cg_context.named_property_setter.arguments[1].idl_type, + argument_index=2)) + + body.extend([ + make_runtime_call_timer_scope(cg_context, "NamedPropertySetter"), + EmptyNode(), + ]) + + if "Custom" in cg_context.named_property_setter.extended_attributes: + text = _format( + "${class_name}::{}" + "(${blink_property_name}, ${v8_property_value}, ${info});", + custom_function_name(cg_context)) + body.append(TextNode(text)) + else: + body.extend([ + make_steps_of_ce_reactions(cg_context), + EmptyNode(), + make_v8_set_return_value(cg_context), + ]) + + return func_decl, func_def + + +def make_named_property_deleter_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + if cg_context.named_property_deleter is None: + return None, None + + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "const v8::PropertyCallbackInfo<v8::Boolean>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + bind_return_value( + body, cg_context, overriding_args=["${blink_property_name}"]) + + body.extend([ + make_runtime_call_timer_scope(cg_context), + EmptyNode(), + ]) + + if "Custom" in cg_context.named_property_deleter.extended_attributes: + text = _format("${class_name}::{}(${blink_property_name}, ${info});", + custom_function_name(cg_context)) + body.append(TextNode(text)) + else: + body.extend([ + make_steps_of_ce_reactions(cg_context), + EmptyNode(), + make_v8_set_return_value(cg_context), + ]) + + return func_decl, func_def + + +def make_named_property_definer_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "const v8::PropertyDescriptor& desc", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("desc", "desc") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + body.append( + TextNode("""\ +// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty +// 3.8.3. [[DefineOwnProperty]] +// step 2.2.2.1. If the result of calling IsDataDescriptor(Desc) is false, +// then return false. +if (desc.has_get() || desc.has_set()) { + bindings::V8SetReturnValue(${info}, nullptr); + if (${info}.ShouldThrowOnError()) { + ExceptionState exception_state(${info}.GetIsolate(), + ExceptionState::kSetterContext, + "${interface.identifier}"); + exception_state.ThrowTypeError("Accessor properties are not allowed."); + } + return; +} +""")) + + writable = bool( + cg_context.interface.indexed_and_named_properties.named_setter) + if writable: + body.append( + TextNode("""\ +// step 2.2.2. Invoke the named property setter with P and Desc.[[Value]]. +// +// Return nothing and fall back to +// ${class_name}::NamedPropertySetterCallback.""")) + else: + body.append( + TextNode("""\ +// step 2.2.1. If creating is false and O does not implement an interface +// with a named property setter, then return false. +bindings::V8SetReturnValue(${info}, nullptr); +if (${info}.ShouldThrowOnError()) { + ExceptionState exception_state(${info}.GetIsolate(), + ExceptionState::kSetterContext, + "${interface.identifier}"); + exception_state.ThrowTypeError("Named property setter is not supported."); + return; +}""")) + + return func_decl, func_def + + +def make_named_property_descriptor_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + arg_decls = [ + "v8::Local<v8::Name> v8_property_name", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + pattern = """\ +// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty +// Steps 2.1. is covered here: we rely on +// NamedPropertyGetterCallback() to call the getter function and check +// that |v8_property_name| is a valid property name, in which case it will +// have set info.GetReturnValue() to something other than undefined. +${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info}); +v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get(); +if (v8_value->IsUndefined()) + return; + +// 2.1.5. Let |desc| be a newly created Property Descriptor with no fields. +// 2.1.6. Set desc.[[Value]] to the result of converting value to an +// ECMAScript value. +// 2.1.7. If O implements an interface with a named property setter, then +// set desc.[[Writable]] to true, otherwise set it to false. +v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable}); +// 2.1.8. If O implements an interface with the +// [LegacyUnenumerableNamedProperties] extended attribute, then set +// desc.[[Enumerable]] to false, otherwise set it to true. +desc.set_enumerable({cxx_enumerable}); +// 2.1.9. Set desc.[[Configurable]] to true. +desc.set_configurable(true); +// 1.2.9. Return |desc|. +bindings::V8SetReturnValue(${info}, desc);""" + props = cg_context.interface.indexed_and_named_properties + writable = bool(props.named_setter) + cxx_writable = "true" if writable else "false" + enumerable = props.is_named_property_enumerable + cxx_enumerable = "true" if enumerable else "false" + body.append( + TextNode( + _format( + pattern, + cxx_writable=cxx_writable, + cxx_enumerable=cxx_enumerable))) + + return func_decl, func_def + + +def make_named_property_enumerator_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + if not (cg_context.interface.indexed_and_named_properties. + is_named_property_enumerable): + return None, None + + arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"] + return_type = "void" + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + class_name=cg_context.class_name) + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + body.append( + TextNode("""\ +Vector<String> blink_property_names; +${blink_receiver}->NamedPropertyEnumerator( + blink_property_names, ${exception_state}); +if (${exception_state}.HadException()) + return; +bindings::V8SetReturnValue( + ${info}, + ToV8(blink_property_names, ${creation_context_object}, ${isolate})); +""")) + + return func_decl, func_def + + +def make_stringifier_callback_def(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + if cg_context.stringifier.attribute: + return make_attribute_get_callback_def( + cg_context.make_copy( + attribute=cg_context.stringifier.attribute, + attribute_get=True), function_name) + elif cg_context.stringifier.operation: + return make_operation_function_def( + cg_context.make_copy(operation=cg_context.stringifier.operation), + function_name) + assert False + + +# ---------------------------------------------------------------------------- +# Callback functions of cross origin properties +# ---------------------------------------------------------------------------- + + +def make_cross_origin_access_check_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=[ + "v8::Local<v8::Context> accessing_context", + "v8::Local<v8::Object> accessed_object", + "v8::Local<v8::Value> unused_data", + ], + return_type="bool") + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("accessing_context", "accessing_context") + body.add_template_var("accessed_object", "accessed_object") + bind_callback_local_vars(body, cg_context) + + if cg_context.interface.identifier == "Window": + blink_class = "DOMWindow" + else: + blink_class = blink_class_name(cg_context.interface) + body.extend([ + TextNode( + _format( + "{blink_class}* blink_accessed_object = " + "${class_name}::ToWrappableUnsafe(${accessed_object});", + blink_class=blink_class)), + TextNode("return BindingSecurity::ShouldAllowAccessTo(" + "ToLocalDOMWindow(${accessing_context}), " + "blink_accessed_object, " + "BindingSecurity::ErrorReportOption::kDoNotReport);"), + ]) + + return func_def + + +def make_cross_origin_property_getter_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=[ + "v8::Local<v8::Name> v8_property_name", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ], + return_type="void") + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + string_case_body = [] + string_case_body.append( + TextNode("""\ +for (const auto& attribute : kCrossOriginAttributeTable) { + if (${blink_property_name} != attribute.name) + continue; + if (UNLIKELY(!attribute.get_value)) { + BindingSecurity::FailedAccessCheckFor( + ${info}.GetIsolate(), + ${class_name}::GetWrapperTypeInfo(), + ${info}.This()); + return; + } + return attribute.get_value(${v8_property_name}, ${info}); +} +for (const auto& operation : kCrossOriginOperationTable) { + if (${blink_property_name} != operation.name) + continue; + v8::Local<v8::Function> function; + if (bindings::GetCrossOriginFunction( + ${info}.GetIsolate(), operation.callback, operation.func_length, + ${class_name}::GetWrapperTypeInfo()) + .ToLocal(&function)) { + bindings::V8SetReturnValue(${info}, function); + } + return; +} +% if interface.identifier == "Window": + +// Window object's document-tree child browsing context name property set +// +// TODO(yukishiino): Update the following hard-coded call to an appropriate +// one. +V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info}); +if (!${info}.GetReturnValue().Get()->IsUndefined()) + return; +% endif""")) + + body.extend([ + make_runtime_call_timer_scope(cg_context, "CrossOriginPropertyGetter"), + EmptyNode(), + CxxLikelyIfNode( + cond="${v8_property_name}->IsString()", body=string_case_body), + EmptyNode(), + TextNode("""\ +// 7.2.3.2 CrossOriginPropertyFallback ( P ) +// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-) +if (bindings::IsSupportedInCrossOriginPropertyFallback( + ${info}.GetIsolate(), ${v8_property_name})) { + return ${info}.GetReturnValue().SetUndefined(); +} +BindingSecurity::FailedAccessCheckFor( + ${info}.GetIsolate(), + ${class_name}::GetWrapperTypeInfo(), + ${info}.This());"""), + ]) + + return func_def + + +def make_cross_origin_property_setter_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=[ + "v8::Local<v8::Name> v8_property_name", + "v8::Local<v8::Value> v8_property_value", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ], + return_type="void") + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("v8_property_value", "v8_property_value") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + string_case_body = [] + string_case_body.append( + TextNode("""\ +for (const auto& attribute : kCrossOriginAttributeTable) { + if (${blink_property_name} == attribute.name && attribute.set_value) { + return attribute.set_value( + ${v8_property_name}, ${v8_property_value}, ${info}); + } +}""")) + + body.extend([ + make_runtime_call_timer_scope(cg_context, "CrossOriginPropertySetter"), + EmptyNode(), + CxxLikelyIfNode( + cond="${v8_property_name}->IsString()", body=string_case_body), + EmptyNode(), + TextNode("""\ +BindingSecurity::FailedAccessCheckFor( + ${info}.GetIsolate(), + ${class_name}::GetWrapperTypeInfo(), + ${info}.This());"""), + ]) + + return func_def + + +def make_cross_origin_property_descriptor_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=[ + "v8::Local<v8::Name> v8_property_name", + "const v8::PropertyCallbackInfo<v8::Value>& info", + ], + return_type="void") + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("v8_property_name", "v8_property_name") + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + string_case_body = [] + string_case_body.append( + TextNode("""\ +// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P ) +// https://html.spec.whatwg.org/C/#crossorigingetownpropertyhelper-(-o,-p-) +for (const auto& attribute : kCrossOriginAttributeTable) { + if (${blink_property_name} != attribute.name) + continue; + v8::Local<v8::Value> get; + v8::Local<v8::Value> set; + if (!bindings::GetCrossOriginFunctionOrUndefined( + ${info}.GetIsolate(), attribute.get_callback, 0, + ${class_name}::GetWrapperTypeInfo()) + .ToLocal(&get) || + !bindings::GetCrossOriginFunctionOrUndefined( + ${info}.GetIsolate(), attribute.set_callback, 1, + ${class_name}::GetWrapperTypeInfo()) + .ToLocal(&set)) { + return; + } + v8::PropertyDescriptor desc(get, set); + desc.set_enumerable(false); + desc.set_configurable(true); + return; +} +for (const auto& operation : kCrossOriginOperationTable) { + if (${blink_property_name} != operation.name) + continue; + v8::Local<v8::Function> function; + if (!bindings::GetCrossOriginFunction( + ${info}.GetIsolate(), operation.callback, operation.func_length, + ${class_name}::GetWrapperTypeInfo()) + .ToLocal(&function)) { + return; + } + v8::PropertyDescriptor desc(function, /*writable=*/false); + desc.set_enumerable(false); + desc.set_configurable(true); + bindings::V8SetReturnValue(${info}, desc); + return; +} +% if interface.identifier == "Window": + +// Window object's document-tree child browsing context name property set +// +// TODO(yukishiino): Update the following hard-coded call to an appropriate +// one. +V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info}); +if (!${info}.GetReturnValue().Get()->IsUndefined()) { + v8::PropertyDescriptor desc(${info}.GetReturnValue().Get(), + /*writable=*/false); + desc.set_enumerable(false); + desc.set_configurable(true); + bindings::V8SetReturnValue(${info}, desc); + return; +} +% endif""")) + + body.extend([ + CxxLikelyIfNode( + cond="${v8_property_name}->IsString()", body=string_case_body), + EmptyNode(), + TextNode("""\ +// 7.2.3.2 CrossOriginPropertyFallback ( P ) +// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-) +if (bindings::IsSupportedInCrossOriginPropertyFallback( + ${info}.GetIsolate(), ${v8_property_name})) { + v8::PropertyDescriptor desc(v8::Undefined(${info}.GetIsolate()), + /*writable=*/false); + desc.set_enumerable(false); + desc.set_configurable(true); + bindings::V8SetReturnValue(${info}, desc); + return; +} +BindingSecurity::FailedAccessCheckFor( + ${info}.GetIsolate(), + ${class_name}::GetWrapperTypeInfo(), + ${info}.This());"""), + ]) + + return func_def + + +def make_cross_origin_property_enumerator_callback(cg_context, function_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=["const v8::PropertyCallbackInfo<v8::Array>& info"], + return_type="void") + func_def.set_base_template_vars(cg_context.template_bindings()) + body = func_def.body + body.add_template_var("info", "info") + bind_callback_local_vars(body, cg_context) + + body.append( + TextNode("""\ +bindings::V8SetReturnValue( + ${info}, + bindings::EnumerateCrossOriginProperties( + ${isolate}, + kCrossOriginAttributeTable, + kCrossOriginOperationTable));""")) + + return func_def + + +# ---------------------------------------------------------------------------- +# Installer functions +# ---------------------------------------------------------------------------- + +# FN = function name +FN_INSTALL_INTERFACE_TEMPLATE = name_style.func("InstallInterfaceTemplate") +FN_INSTALL_UNCONDITIONAL_PROPS = name_style.func( + "InstallUnconditionalProperties") +FN_INSTALL_CONTEXT_INDEPENDENT_PROPS = name_style.func( + "InstallContextIndependentProperties") +FN_INSTALL_CONTEXT_DEPENDENT_PROPS = name_style.func( + "InstallContextDependentProperties") + +# TP = trampoline name +TP_INSTALL_INTERFACE_TEMPLATE = name_style.member_var( + "install_interface_template_func") +TP_INSTALL_UNCONDITIONAL_PROPS = name_style.member_var( + "install_unconditional_props_func") +TP_INSTALL_CONTEXT_INDEPENDENT_PROPS = name_style.member_var( + "install_context_independent_props_func") +TP_INSTALL_CONTEXT_DEPENDENT_PROPS = name_style.member_var( + "install_context_dependent_props_func") + + +def bind_installer_local_vars(code_node, cg_context): assert isinstance(code_node, SymbolScopeNode) assert isinstance(cg_context, CodeGenContext) @@ -984,17 +2736,36 @@ def bind_template_installer_local_vars(code_node, cg_context): S("instance_template", ("v8::Local<v8::ObjectTemplate> ${instance_template} = " "${interface_template}->InstanceTemplate();")), + S("interface_template", + ("v8::Local<v8::FunctionTemplate> ${interface_template} = " + "${wrapper_type_info}->DomTemplate(${isolate}, ${world});")), + S("is_in_secure_context", + ("const bool ${is_in_secure_context} = " + "${execution_context}->IsSecureContext();")), + S("isolate", "v8::Isolate* ${isolate} = ${v8_context}->GetIsolate();"), S("prototype_template", ("v8::Local<v8::ObjectTemplate> ${prototype_template} = " "${interface_template}->PrototypeTemplate();")), + S("script_state", + "ScriptState* ${script_state} = ScriptState::From(${v8_context});"), S("signature", ("v8::Local<v8::Signature> ${signature} = " "v8::Signature::New(${isolate}, ${interface_template});")), S("wrapper_type_info", ("const WrapperTypeInfo* const ${wrapper_type_info} = " - "${v8_class}::GetWrapperTypeInfo();")), + "${class_name}::GetWrapperTypeInfo();")), ]) + # execution_context + node = S("execution_context", ("ExecutionContext* ${execution_context} = " + "ExecutionContext::From(${script_state});")) + node.accumulate( + CodeGenAccumulator.require_include_headers([ + "third_party/blink/renderer/core/execution_context/execution_context.h" + ])) + local_vars.append(node) + + # parent_interface_template pattern = ( "v8::Local<v8::FunctionTemplate> ${parent_interface_template}{_1};") _1 = (" = ${wrapper_type_info}->parent_class->dom_template_function" @@ -1003,105 +2774,2093 @@ def bind_template_installer_local_vars(code_node, cg_context): _1 = "" local_vars.append(S("parent_interface_template", _format(pattern, _1=_1))) - code_node.register_code_symbols(local_vars) + # Arguments have priority over local vars. + template_vars = code_node.template_vars + for symbol_node in local_vars: + if symbol_node.name not in template_vars: + code_node.register_code_symbol(symbol_node) + + +def _make_property_entry_v8_property_attribute(property_): + values = [] + if "NotEnumerable" in property_.extended_attributes: + values.append("v8::DontEnum") + if "Unforgeable" in property_.extended_attributes: + values.append("v8::DontDelete") + if not values: + values.append("v8::None") + return "static_cast<v8::PropertyAttribute>({})".format(" | ".join(values)) + + +def _make_property_entry_on_which_object(property_): + ON_INSTANCE = "V8DOMConfiguration::kOnInstance" + ON_PROTOTYPE = "V8DOMConfiguration::kOnPrototype" + ON_INTERFACE = "V8DOMConfiguration::kOnInterface" + if isinstance(property_, web_idl.Constant): + return ON_INTERFACE + if hasattr(property_, "is_static") and property_.is_static: + return ON_INTERFACE + if "Global" in property_.owner.extended_attributes: + return ON_INSTANCE + if "Unforgeable" in property_.extended_attributes: + return ON_INSTANCE + return ON_PROTOTYPE + + +def _make_property_entry_check_receiver(property_): + if ("LenientThis" in property_.extended_attributes + or (isinstance(property_, web_idl.Attribute) + and property_.idl_type.unwrap().is_promise) + or (isinstance(property_, web_idl.OverloadGroup) + and property_[0].return_type.unwrap().is_promise)): + return "V8DOMConfiguration::kDoNotCheckHolder" + else: + return "V8DOMConfiguration::kCheckHolder" -def make_install_interface_template_def(cg_context): - assert isinstance(cg_context, CodeGenContext) +def _make_property_entry_has_side_effect(property_): + if property_.extended_attributes.value_of("Affects") == "Nothing": + return "V8DOMConfiguration::kHasNoSideEffect" + else: + return "V8DOMConfiguration::kHasSideEffect" + + +def _make_property_entry_world(world): + if world == CodeGenContext.MAIN_WORLD: + return "V8DOMConfiguration::kMainWorld" + if world == CodeGenContext.NON_MAIN_WORLDS: + return "V8DOMConfiguration::kNonMainWorlds" + if world == CodeGenContext.ALL_WORLDS: + return "V8DOMConfiguration::kAllWorlds" + assert False + + +def _make_property_entry_constant_type_and_value_format(property_): + idl_type = property_.idl_type.unwrap() + if (idl_type.keyword_typename == "long long" + or idl_type.keyword_typename == "unsigned long long"): + assert False, "64-bit constants are not yet supported." + if idl_type.keyword_typename == "unsigned long": + return ("V8DOMConfiguration::kConstantTypeUnsignedLong", + "static_cast<int>({value})") + if idl_type.is_integer: + return ("V8DOMConfiguration::kConstantTypeLong", + "static_cast<int>({value})") + if idl_type.is_floating_point_numeric: + return ("V8DOMConfiguration::kConstantTypeDouble", + "static_cast<double>({value})") + assert False, "Unsupported type: {}".format(idl_type.syntactic_form) + + +def _make_attribute_registration_table(table_name, attribute_entries): + assert isinstance(table_name, str) + assert isinstance(attribute_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryAttribute) for entry in attribute_entries) T = TextNode - func_def = FunctionDefinitionNode( - name=T("InstallInterfaceTemplate"), - arg_decls=[ - T("v8::Isolate* isolate"), - T("const DOMWrapperWorld& world"), - T("v8::Local<v8::FunctionTemplate> interface_template"), - ], - return_type=T("void")) + entry_nodes = [] + for entry in attribute_entries: + pattern = ("{{" + "\"{property_name}\", " + "{attribute_get_callback}, " + "{attribute_set_callback}, " + "V8PrivateProperty::kNoCachedAccessor, " + "{v8_property_attribute}, " + "{on_which_object}, " + "{check_receiver}, " + "{has_side_effect}, " + "V8DOMConfiguration::kAlwaysCallGetter, " + "{world}" + "}},") + text = _format( + pattern, + property_name=entry.property_.identifier, + attribute_get_callback=entry.attr_get_callback_name, + attribute_set_callback=(entry.attr_set_callback_name or "nullptr"), + v8_property_attribute=_make_property_entry_v8_property_attribute( + entry.property_), + on_which_object=_make_property_entry_on_which_object( + entry.property_), + check_receiver=_make_property_entry_check_receiver( + entry.property_), + has_side_effect=_make_property_entry_has_side_effect( + entry.property_), + world=_make_property_entry_world(entry.world)) + entry_nodes.append(T(text)) + + return ListNode([ + T("static constexpr V8DOMConfiguration::AccessorConfiguration " + + table_name + "[] = {"), + ListNode(entry_nodes), + T("};"), + ]) - body = func_def.body - body.add_template_var("isolate", "isolate") - body.add_template_var("world", "world") - body.add_template_var("interface_template", "interface_template") - body.add_template_vars(cg_context.template_bindings()) - binders = [ - bind_template_installer_local_vars, +def _make_constant_callback_registration_table(table_name, constant_entries): + assert isinstance(table_name, str) + assert isinstance(constant_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryConstant) + and isinstance(entry.const_callback_name, str) + for entry in constant_entries) + + T = TextNode + + entry_nodes = [] + for entry in constant_entries: + pattern = ("{{" "\"{property_name}\", " "{constant_callback}" "}},") + text = _format( + pattern, + property_name=entry.property_.identifier, + constant_callback=entry.const_callback_name) + entry_nodes.append(T(text)) + + return ListNode([ + T("static constexpr V8DOMConfiguration::ConstantCallbackConfiguration " + + table_name + "[] = {"), + ListNode(entry_nodes), + T("};"), + ]) + + +def _make_constant_value_registration_table(table_name, constant_entries): + assert isinstance(table_name, str) + assert isinstance(constant_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryConstant) + and entry.const_callback_name is None for entry in constant_entries) + + T = TextNode + + entry_nodes = [] + for entry in constant_entries: + pattern = ("{{" + "\"{property_name}\", " + "{constant_type}, " + "{constant_value}" + "}},") + constant_type, constant_value_fmt = ( + _make_property_entry_constant_type_and_value_format( + entry.property_)) + constant_value = _format( + constant_value_fmt, value=entry.const_constant_name) + text = _format( + pattern, + property_name=entry.property_.identifier, + constant_type=constant_type, + constant_value=constant_value) + entry_nodes.append(T(text)) + + return ListNode([ + T("static constexpr V8DOMConfiguration::ConstantConfiguration " + + table_name + "[] = {"), + ListNode(entry_nodes), + T("};"), + ]) + + +def _make_exposed_construct_registration_table(table_name, + exposed_construct_entries): + assert isinstance(table_name, str) + assert isinstance(exposed_construct_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryExposedConstruct) + for entry in exposed_construct_entries) + + T = TextNode + + entry_nodes = [] + for entry in exposed_construct_entries: + pattern = ("{{" + "\"{property_name}\", " + "{exposed_construct_callback}, " + "nullptr, " + "static_cast<v8::PropertyAttribute>(v8::DontEnum), " + "V8DOMConfiguration::kOnInstance, " + "V8DOMConfiguration::kDoNotCheckHolder, " + "V8DOMConfiguration::kHasNoSideEffect, " + "V8DOMConfiguration::kAlwaysCallGetter, " + "{world}" + "}}, ") + text = _format( + pattern, + property_name=entry.property_.identifier, + exposed_construct_callback=entry.prop_callback_name, + world=_make_property_entry_world(entry.world)) + entry_nodes.append(T(text)) + + return ListNode([ + T("static constexpr V8DOMConfiguration::AttributeConfiguration " + + table_name + "[] = {"), + ListNode(entry_nodes), + T("};"), + ]) + + +def _make_operation_registration_table(table_name, operation_entries): + assert isinstance(table_name, str) + assert isinstance(operation_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryOperationGroup) + for entry in operation_entries) + + T = TextNode + + entry_nodes = [] + for entry in operation_entries: + pattern = ("{{" + "\"{property_name}\", " + "{operation_callback}, " + "{function_length}, " + "{v8_property_attribute}, " + "{on_which_object}, " + "{check_receiver}, " + "V8DOMConfiguration::kDoNotCheckAccess, " + "{has_side_effect}, " + "{world}" + "}}, ") + text = _format( + pattern, + property_name=entry.property_.identifier, + operation_callback=entry.op_callback_name, + function_length=entry.op_func_length, + v8_property_attribute=_make_property_entry_v8_property_attribute( + entry.property_), + on_which_object=_make_property_entry_on_which_object( + entry.property_), + check_receiver=_make_property_entry_check_receiver( + entry.property_), + has_side_effect=_make_property_entry_has_side_effect( + entry.property_), + world=_make_property_entry_world(entry.world)) + entry_nodes.append(T(text)) + + return ListNode([ + T("static constexpr V8DOMConfiguration::MethodConfiguration " + + table_name + "[] = {"), + ListNode(entry_nodes), + T("};"), + ]) + + +class _PropEntryBase(object): + def __init__(self, is_context_dependent, exposure_conditional, world, + property_): + assert isinstance(is_context_dependent, bool) + assert isinstance(exposure_conditional, CodeGenExpr) + + self.is_context_dependent = is_context_dependent + self.exposure_conditional = exposure_conditional + self.world = world + self.property_ = property_ + + +class _PropEntryAttribute(_PropEntryBase): + def __init__(self, is_context_dependent, exposure_conditional, world, + attribute, attr_get_callback_name, attr_set_callback_name): + assert isinstance(attr_get_callback_name, str) + assert _is_none_or_str(attr_set_callback_name) + + _PropEntryBase.__init__(self, is_context_dependent, + exposure_conditional, world, attribute) + self.attr_get_callback_name = attr_get_callback_name + self.attr_set_callback_name = attr_set_callback_name + + +class _PropEntryConstant(_PropEntryBase): + def __init__(self, is_context_dependent, exposure_conditional, world, + constant, const_callback_name, const_constant_name): + assert _is_none_or_str(const_callback_name) + assert isinstance(const_constant_name, str) + + _PropEntryBase.__init__(self, is_context_dependent, + exposure_conditional, world, constant) + self.const_callback_name = const_callback_name + self.const_constant_name = const_constant_name + + +class _PropEntryConstructorGroup(_PropEntryBase): + def __init__(self, is_context_dependent, exposure_conditional, world, + constructor_group, ctor_callback_name, ctor_func_length): + assert isinstance(ctor_callback_name, str) + assert isinstance(ctor_func_length, (int, long)) + + _PropEntryBase.__init__(self, is_context_dependent, + exposure_conditional, world, constructor_group) + self.ctor_callback_name = ctor_callback_name + self.ctor_func_length = ctor_func_length + + +class _PropEntryExposedConstruct(_PropEntryBase): + def __init__(self, is_context_dependent, exposure_conditional, world, + exposed_construct, prop_callback_name): + assert isinstance(prop_callback_name, str) + + _PropEntryBase.__init__(self, is_context_dependent, + exposure_conditional, world, exposed_construct) + self.prop_callback_name = prop_callback_name + + +class _PropEntryOperationGroup(_PropEntryBase): + def __init__(self, is_context_dependent, exposure_conditional, world, + operation_group, op_callback_name, op_func_length): + assert isinstance(op_callback_name, str) + assert isinstance(op_func_length, (int, long)) + + _PropEntryBase.__init__(self, is_context_dependent, + exposure_conditional, world, operation_group) + self.op_callback_name = op_callback_name + self.op_func_length = op_func_length + + +def _make_property_entries_and_callback_defs( + cg_context, attribute_entries, constant_entries, constructor_entries, + exposed_construct_entries, operation_entries): + """ + Creates intermediate objects to help property installation and also makes + code nodes of callback functions. + + Args: + attribute_entries: + constructor_entries: + exposed_construct_entries: + operation_entries: + Output parameters to store the intermediate objects. + """ + assert isinstance(cg_context, CodeGenContext) + assert isinstance(attribute_entries, list) + assert isinstance(constant_entries, list) + assert isinstance(constructor_entries, list) + assert isinstance(exposed_construct_entries, list) + assert isinstance(operation_entries, list) + + interface = cg_context.interface + global_names = interface.extended_attributes.values_of("Global") + + callback_def_nodes = ListNode() + + def iterate(members, callback): + for member in members: + is_context_dependent = member.exposure.is_context_dependent( + global_names) + exposure_conditional = expr_from_exposure(member.exposure, + global_names) + + if "PerWorldBindings" in member.extended_attributes: + worlds = (CodeGenContext.MAIN_WORLD, + CodeGenContext.NON_MAIN_WORLDS) + else: + worlds = (CodeGenContext.ALL_WORLDS, ) + + for world in worlds: + callback(member, is_context_dependent, exposure_conditional, + world) + + def process_attribute(attribute, is_context_dependent, + exposure_conditional, world): + cgc_attr = cg_context.make_copy(attribute=attribute, for_world=world) + cgc = cgc_attr.make_copy(attribute_get=True) + attr_get_callback_name = callback_function_name(cgc) + attr_get_callback_node = make_attribute_get_callback_def( + cgc, attr_get_callback_name) + cgc = cgc_attr.make_copy(attribute_set=True) + attr_set_callback_name = callback_function_name(cgc) + attr_set_callback_node = make_attribute_set_callback_def( + cgc, attr_set_callback_name) + if attr_set_callback_node is None: + attr_set_callback_name = None + + callback_def_nodes.extend([ + attr_get_callback_node, + EmptyNode(), + attr_set_callback_node, + EmptyNode(), + ]) + + attribute_entries.append( + _PropEntryAttribute( + is_context_dependent=is_context_dependent, + exposure_conditional=exposure_conditional, + world=world, + attribute=attribute, + attr_get_callback_name=attr_get_callback_name, + attr_set_callback_name=attr_set_callback_name)) + + def process_constant(constant, is_context_dependent, exposure_conditional, + world): + cgc = cg_context.make_copy( + constant=constant, + for_world=world, + v8_callback_type=CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK) + const_callback_name = callback_function_name(cgc) + const_callback_node = make_constant_callback_def( + cgc, const_callback_name) + if const_callback_node is None: + const_callback_name = None + # IDL constant's C++ constant name + const_constant_name = _format("${class_name}::{}", constant_name(cgc)) + + callback_def_nodes.extend([ + const_callback_node, + EmptyNode(), + ]) + + constant_entries.append( + _PropEntryConstant( + is_context_dependent=is_context_dependent, + exposure_conditional=exposure_conditional, + world=world, + constant=constant, + const_callback_name=const_callback_name, + const_constant_name=const_constant_name)) + + def process_constructor_group(constructor_group, is_context_dependent, + exposure_conditional, world): + cgc = cg_context.make_copy( + constructor_group=constructor_group, for_world=world) + ctor_callback_name = callback_function_name(cgc) + ctor_callback_node = make_constructor_callback_def( + cgc, ctor_callback_name) + + callback_def_nodes.extend([ + ctor_callback_node, + EmptyNode(), + ]) + + constructor_entries.append( + _PropEntryConstructorGroup( + is_context_dependent=is_context_dependent, + exposure_conditional=exposure_conditional, + world=world, + constructor_group=constructor_group, + ctor_callback_name=ctor_callback_name, + ctor_func_length=( + constructor_group.min_num_of_required_arguments))) + + def process_exposed_construct(exposed_construct, is_context_dependent, + exposure_conditional, world): + if isinstance(exposed_construct, web_idl.LegacyWindowAlias): + cgc = cg_context.make_copy( + exposed_construct=exposed_construct.original, + legacy_window_alias=exposed_construct, + for_world=world, + v8_callback_type=CodeGenContext. + V8_ACCESSOR_NAME_GETTER_CALLBACK) + else: + cgc = cg_context.make_copy( + exposed_construct=exposed_construct, + for_world=world, + v8_callback_type=CodeGenContext. + V8_ACCESSOR_NAME_GETTER_CALLBACK) + prop_callback_name = callback_function_name(cgc) + prop_callback_node = make_exposed_construct_callback_def( + cgc, prop_callback_name) + + callback_def_nodes.extend([ + prop_callback_node, + EmptyNode(), + ]) + + exposed_construct_entries.append( + _PropEntryExposedConstruct( + is_context_dependent=is_context_dependent, + exposure_conditional=exposure_conditional, + world=world, + exposed_construct=exposed_construct, + prop_callback_name=prop_callback_name)) + + def process_operation_group(operation_group, is_context_dependent, + exposure_conditional, world): + cgc = cg_context.make_copy( + operation_group=operation_group, for_world=world) + op_callback_name = callback_function_name(cgc) + op_callback_node = make_operation_callback_def(cgc, op_callback_name) + + callback_def_nodes.extend([ + op_callback_node, + EmptyNode(), + ]) + + operation_entries.append( + _PropEntryOperationGroup( + is_context_dependent=is_context_dependent, + exposure_conditional=exposure_conditional, + world=world, + operation_group=operation_group, + op_callback_name=op_callback_name, + op_func_length=operation_group.min_num_of_required_arguments)) + + def process_stringifier(_, is_context_dependent, exposure_conditional, + world): + cgc = cg_context.make_copy( + stringifier=interface.stringifier, for_world=world) + op_callback_name = callback_function_name(cgc) + op_callback_node = make_stringifier_callback_def(cgc, op_callback_name) + + callback_def_nodes.extend([ + op_callback_node, + EmptyNode(), + ]) + + operation_entries.append( + _PropEntryOperationGroup( + is_context_dependent=is_context_dependent, + exposure_conditional=exposure_conditional, + world=world, + operation_group=cgc.property_, + op_callback_name=op_callback_name, + op_func_length=0)) + + iterate(interface.attributes, process_attribute) + iterate(interface.constants, process_constant) + iterate(interface.constructor_groups, process_constructor_group) + iterate(interface.exposed_constructs, process_exposed_construct) + iterate(interface.legacy_window_aliases, process_exposed_construct) + iterate(interface.operation_groups, process_operation_group) + if interface.stringifier: + iterate([interface.stringifier.operation], process_stringifier) + + return callback_def_nodes + + +def make_install_interface_template( + cg_context, function_name, class_name, trampoline_var_name, + constructor_entries, indexed_and_named_property_install_nodes, + cross_origin_property_install_nodes, install_unconditional_func_name, + install_context_independent_func_name): + """ + Returns: + A triplet of CodeNode of: + - function declaration + - function definition + - trampoline function definition (from the API class to the + implementation class), which is supposed to be defined inline + """ + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + assert _is_none_or_str(class_name) + assert _is_none_or_str(trampoline_var_name) + assert isinstance(constructor_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryConstructorGroup) + for entry in constructor_entries) + assert isinstance(indexed_and_named_property_install_nodes, SequenceNode) + assert isinstance(cross_origin_property_install_nodes, SequenceNode) + assert _is_none_or_str(install_unconditional_func_name) + assert _is_none_or_str(install_context_independent_func_name) + + T = TextNode + + arg_decls = [ + "v8::Isolate* isolate", + "const DOMWrapperWorld& world", + "v8::Local<v8::FunctionTemplate> interface_template", ] - for bind in binders: - bind(body, cg_context) + return_type = "void" + + if trampoline_var_name is None: + trampoline_def = None + else: + trampoline_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + trampoline_def.body.append( + TextNode( + _format("return {}(isolate, world, interface_template);", + trampoline_var_name))) + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + class_name=class_name, + arg_decls=arg_decls, + return_type=return_type) + func_def.set_base_template_vars(cg_context.template_bindings()) + + body = func_def.body + body.add_template_vars({ + "isolate": "isolate", + "world": "world", + "interface_template": "interface_template", + }) + bind_installer_local_vars(body, cg_context) body.extend([ T("V8DOMConfiguration::InitializeDOMInterfaceTemplate(" "${isolate}, ${interface_template}, " "${wrapper_type_info}->interface_name, ${parent_interface_template}, " "kV8DefaultWrapperInternalFieldCount);"), + EmptyNode(), ]) - if cg_context.class_like.constructor_groups: + for entry in constructor_entries: + set_callback = _format("${interface_template}->SetCallHandler({});", + entry.ctor_callback_name) + set_length = _format("${interface_template}->SetLength({});", + entry.ctor_func_length) + if entry.world == CodeGenContext.MAIN_WORLD: + body.append( + CxxLikelyIfNode( + cond="${world}.IsMainWorld()", + body=[T(set_callback), T(set_length)])) + elif entry.world == CodeGenContext.NON_MAIN_WORLDS: + body.append( + CxxLikelyIfNode( + cond="!${world}.IsMainWorld()", + body=[T(set_callback), T(set_length)])) + elif entry.world == CodeGenContext.ALL_WORLDS: + body.extend([T(set_callback), T(set_length)]) + else: + assert False + body.append(EmptyNode()) + + if cross_origin_property_install_nodes: body.extend([ - T("${interface_template}->SetCallHandler(ConstructorCallback);"), - T("${interface_template}->SetLength(" - "${class_like.constructor_groups[0]" - ".min_num_of_required_arguments});"), + cross_origin_property_install_nodes, + EmptyNode(), ]) - return func_def + if cg_context.class_like.identifier == "Location": + body.append( + T("""\ +// https://html.spec.whatwg.org/C/#the-location-interface +// To create a Location object, run these steps: +// step 3. Let valueOf be location's relevant +// Realm.[[Intrinsics]].[[%ObjProto_valueOf%]]. +// step 3. Perform ! location.[[DefineOwnProperty]]("valueOf", +// { [[Value]]: valueOf, [[Writable]]: false, [[Enumerable]]: false, +// [[Configurable]]: false }). +${instance_template}->SetIntrinsicDataProperty( + V8AtomicString(${isolate}, "valueOf"), + v8::kObjProto_valueOf, + static_cast<v8::PropertyAttribute>( + int(v8::ReadOnly) | int(v8::DontEnum) | int(v8::DontDelete))); +// step 4. Perform ! location.[[DefineOwnProperty]](@@toPrimitive, +// { [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false, +// [[Configurable]]: false }). +${instance_template}->Set( + v8::Symbol::GetToPrimitive(${isolate}), + v8::Undefined(${isolate}), + static_cast<v8::PropertyAttribute>( + int(v8::ReadOnly) | int(v8::DontEnum) | int(v8::DontDelete))); +""")) + + if indexed_and_named_property_install_nodes: + body.extend([ + indexed_and_named_property_install_nodes, + EmptyNode(), + ]) + if ("Global" in cg_context.class_like.extended_attributes + or cg_context.class_like.identifier == "Location"): + if "Global" in cg_context.class_like.extended_attributes: + body.append(T("// [Global]")) + if cg_context.class_like.identifier == "Location": + body.append(T("// Location exotic object")) + body.extend([ + T("${instance_template}->SetImmutableProto();"), + T("${prototype_template}->SetImmutableProto();"), + EmptyNode(), + ]) + + if cg_context.class_like.identifier == "HTMLAllCollection": + body.extend([ + T("// HTMLAllCollection"), + T("// https://html.spec.whatwg.org/C/" + "#the-htmlallcollection-interface"), + T("${instance_template}->SetCallAsFunctionHandler" + "(${class_name}::LegacyCallCustom);"), + T("${instance_template}->MarkAsUndetectable();"), + EmptyNode(), + ]) + + func_call_pattern = ("{}(${isolate}, ${world}, ${instance_template}, " + "${prototype_template}, ${interface_template});") + if install_unconditional_func_name: + func_call = _format(func_call_pattern, install_unconditional_func_name) + body.append(T(func_call)) + if install_context_independent_func_name: + func_call = _format(func_call_pattern, + install_context_independent_func_name) + body.append(T(func_call)) -def generate_interfaces(web_idl_database, output_dirs): - filename = "v8_example_interface.cc" - filepath = os.path.join(output_dirs['core'], filename) + return func_decl, func_def, trampoline_def - interface = web_idl_database.find("TestNamespace") - cg_context = CodeGenContext(interface=interface) +def make_install_properties(cg_context, function_name, class_name, + trampoline_var_name, is_context_dependent, + attribute_entries, constant_entries, + exposed_construct_entries, operation_entries): + """ + Returns: + A triplet of CodeNode of: + - function declaration + - function definition + - trampoline function definition (from the API class to the + implementation class), which is supposed to be defined inline + """ + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + assert _is_none_or_str(class_name) + assert _is_none_or_str(trampoline_var_name) + assert isinstance(is_context_dependent, bool) + assert isinstance(attribute_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryAttribute) for entry in attribute_entries) + assert isinstance(constant_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryConstant) for entry in constant_entries) + assert isinstance(exposed_construct_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryExposedConstruct) + for entry in exposed_construct_entries) + assert isinstance(operation_entries, (list, tuple)) + assert all( + isinstance(entry, _PropEntryOperationGroup) + for entry in operation_entries) + + if not (attribute_entries or constant_entries or exposed_construct_entries + or operation_entries): + return None, None, None + + if is_context_dependent: + arg_decls = [ + "v8::Local<v8::Context> context", + "const DOMWrapperWorld& world", + "v8::Local<v8::Object> instance_object", + "v8::Local<v8::Object> prototype_object", + "v8::Local<v8::Function> interface_object", + ] + else: + arg_decls = [ + "v8::Isolate* isolate", + "const DOMWrapperWorld& world", + "v8::Local<v8::ObjectTemplate> instance_template", + "v8::Local<v8::ObjectTemplate> prototype_template", + "v8::Local<v8::FunctionTemplate> interface_template", + ] + return_type = "void" + + if trampoline_var_name is None: + trampoline_def = None + else: + trampoline_def = CxxFuncDefNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + if is_context_dependent: + args = [ + "context", + "world", + "instance_object", + "prototype_object", + "interface_object", + ] + else: + args = [ + "isolate", + "world", + "instance_template", + "prototype_template", + "interface_template", + ] + text = _format( + "return {func}({args});", + func=trampoline_var_name, + args=", ".join(args)) + trampoline_def.body.append(TextNode(text)) + + func_decl = CxxFuncDeclNode( + name=function_name, + arg_decls=arg_decls, + return_type=return_type, + static=True) + + func_def = CxxFuncDefNode( + name=function_name, + class_name=class_name, + arg_decls=arg_decls, + return_type=return_type) + func_def.set_base_template_vars(cg_context.template_bindings()) - root_node = SymbolScopeNode(separator_last="\n") - root_node.set_accumulator(CodeGenAccumulator()) - root_node.set_renderer(MakoRenderer()) + body = func_def.body + if is_context_dependent: + body.add_template_vars({ + "v8_context": "context", # 'context' is reserved by Mako. + "world": "world", + "instance_object": "instance_object", + "prototype_object": "prototype_object", + "interface_object": "interface_object", + }) + else: + body.add_template_vars({ + "isolate": "isolate", + "world": "world", + "instance_template": "instance_template", + "prototype_template": "prototype_template", + "interface_template": "interface_template", + }) + bind_installer_local_vars(body, cg_context) + + def group_by_condition(entries): + unconditional_entries = [] + conditional_to_entries = {} + for entry in entries: + assert entry.is_context_dependent == is_context_dependent + if entry.exposure_conditional.is_always_true: + unconditional_entries.append(entry) + else: + conditional_to_entries.setdefault(entry.exposure_conditional, + []).append(entry) + return unconditional_entries, conditional_to_entries + + def install_properties(table_name, target_entries, make_table_func, + installer_call_text): + unconditional_entries, conditional_to_entries = group_by_condition( + target_entries) + if unconditional_entries: + body.append( + CxxBlockNode([ + make_table_func(table_name, unconditional_entries), + TextNode(installer_call_text), + ])) + body.append(EmptyNode()) + for conditional, entries in conditional_to_entries.items(): + body.append( + CxxUnlikelyIfNode( + cond=conditional, + body=[ + make_table_func(table_name, entries), + TextNode(installer_call_text), + ])) + body.append(EmptyNode()) + + table_name = "kAttributeTable" + if is_context_dependent: + installer_call_text = ( + "V8DOMConfiguration::InstallAccessors(${isolate}, ${world}, " + "${instance_object}, ${prototype_object}, ${interface_object}, " + "${signature}, kAttributeTable, base::size(kAttributeTable));") + else: + installer_call_text = ( + "V8DOMConfiguration::InstallAccessors(${isolate}, ${world}, " + "${instance_template}, ${prototype_template}, " + "${interface_template}, ${signature}, " + "kAttributeTable, base::size(kAttributeTable));") + install_properties(table_name, attribute_entries, + _make_attribute_registration_table, installer_call_text) + + table_name = "kConstantCallbackTable" + if is_context_dependent: + installer_call_text = ( + "V8DOMConfiguration::InstallConstants(${isolate}, " + "${interface_object}, ${prototype_object}, " + "kConstantCallbackTable, base::size(kConstantCallbackTable));") + else: + installer_call_text = ( + "V8DOMConfiguration::InstallConstants(${isolate}, " + "${interface_template}, ${prototype_template}, " + "kConstantCallbackTable, base::size(kConstantCallbackTable));") + constant_callback_entries = filter(lambda entry: entry.const_callback_name, + constant_entries) + install_properties(table_name, constant_callback_entries, + _make_constant_callback_registration_table, + installer_call_text) + + table_name = "kConstantValueTable" + if is_context_dependent: + installer_call_text = ( + "V8DOMConfiguration::InstallConstants(${isolate}, " + "${interface_object}, ${prototype_object}, " + "kConstantValueTable, base::size(kConstantValueTable));") + else: + installer_call_text = ( + "V8DOMConfiguration::InstallConstants(${isolate}, " + "${interface_template}, ${prototype_template}, " + "kConstantValueTable, base::size(kConstantValueTable));") + constant_value_entries = filter( + lambda entry: not entry.const_callback_name, constant_entries) + install_properties(table_name, constant_value_entries, + _make_constant_value_registration_table, + installer_call_text) + + table_name = "kExposedConstructTable" + if is_context_dependent: + installer_call_text = ( + "V8DOMConfiguration::InstallAttributes(${isolate}, ${world}, " + "${instance_object}, ${prototype_object}, " + "kExposedConstructTable, base::size(kExposedConstructTable));") + else: + installer_call_text = ( + "V8DOMConfiguration::InstallAttributes(${isolate}, ${world}, " + "${instance_template}, ${prototype_template}, " + "kExposedConstructTable, base::size(kExposedConstructTable));") + install_properties(table_name, exposed_construct_entries, + _make_exposed_construct_registration_table, + installer_call_text) + + table_name = "kOperationTable" + if is_context_dependent: + installer_call_text = ( + "V8DOMConfiguration::InstallMethods(${isolate}, ${world}, " + "${instance_object}, ${prototype_object}, ${interface_object}, " + "${signature}, kOperationTable, base::size(kOperationTable));") + else: + installer_call_text = ( + "V8DOMConfiguration::InstallMethods(${isolate}, ${world}, " + "${instance_template}, ${prototype_template}, " + "${interface_template}, ${signature}, " + "kOperationTable, base::size(kOperationTable));") + install_properties(table_name, operation_entries, + _make_operation_registration_table, installer_call_text) - root_node.accumulator.add_include_headers( - collect_include_headers(interface)) + return func_decl, func_def, trampoline_def - code_node = SequenceNode() - for attribute in interface.attributes: - func_name = name_style.func(attribute.identifier, - "AttributeGetCallback") - code_node.append( - make_attribute_get_callback_def( - cg_context.make_copy(attribute=attribute), func_name)) - func_name = name_style.func(attribute.identifier, - "AttributeSetCallback") - code_node.append( - make_attribute_set_callback_def( - cg_context.make_copy(attribute=attribute), func_name)) - - for constructor_group in interface.constructor_groups: - func_name = name_style.func("ConstructorCallback") - code_node.append( - make_operation_callback_def( - cg_context.make_copy(constructor_group=constructor_group), - func_name)) +def make_indexed_and_named_property_callbacks_and_install_nodes(cg_context): + assert isinstance(cg_context, CodeGenContext) + func_decls = ListNode() + func_defs = ListNode() + install_nodes = SequenceNode() + + interface = cg_context.interface + if not (interface and interface.indexed_and_named_properties): + return func_decls, func_defs, install_nodes + props = interface.indexed_and_named_properties + + def add_callback(func_decl, func_def): + func_decls.append(func_decl) + if func_def: + func_defs.append(func_def) + func_defs.append(EmptyNode()) + + def most_derived_interface(*interfaces): + key = lambda interface: len(interface.inclusive_inherited_interfaces) + return sorted(filter(None, interfaces), key=key)[-1] + + cg_context = cg_context.make_copy( + v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK) + + if props.own_indexed_getter or props.own_indexed_setter: + add_callback(*make_indexed_property_getter_callback( + cg_context.make_copy(indexed_property_getter=props.indexed_getter), + "IndexedPropertyGetterCallback")) + add_callback(*make_indexed_property_setter_callback( + cg_context.make_copy(indexed_property_setter=props.indexed_setter), + "IndexedPropertySetterCallback")) + add_callback(*make_indexed_property_definer_callback( + cg_context, "IndexedPropertyDefinerCallback")) + add_callback(*make_indexed_property_descriptor_callback( + cg_context, "IndexedPropertyDescriptorCallback")) + add_callback(*make_indexed_property_enumerator_callback( + cg_context, "IndexedPropertyEnumeratorCallback")) + + if props.has_indexed_properties: + impl_bridge = v8_bridge_class_name( + most_derived_interface( + props.indexed_getter.owner, + props.indexed_setter and props.indexed_setter.owner, + )) + flags = [] + if (props.indexed_getter.extended_attributes.value_of("Affects") == + "Nothing"): + flags.append("v8::PropertyHandlerFlags::kHasNoSideEffect") + else: + flags.append("v8::PropertyHandlerFlags::kNone") + property_handler_flags = flags[0] + pattern = """\ +// Indexed properties +${instance_template}->SetHandler( + v8::IndexedPropertyHandlerConfiguration( + {impl_bridge}::IndexedPropertyGetterCallback, +% if interface.indexed_and_named_properties.indexed_setter: + {impl_bridge}::IndexedPropertySetterCallback, +% else: + nullptr, // setter +% endif + {impl_bridge}::IndexedPropertyDescriptorCallback, + nullptr, // deleter + {impl_bridge}::IndexedPropertyEnumeratorCallback, + {impl_bridge}::IndexedPropertyDefinerCallback, + v8::Local<v8::Value>(), + {property_handler_flags}));""" + install_nodes.append( + TextNode( + _format( + pattern, + impl_bridge=impl_bridge, + property_handler_flags=property_handler_flags))) + + if (props.own_named_getter or props.own_named_setter + or props.own_named_deleter): + add_callback(*make_named_property_getter_callback( + cg_context.make_copy(named_property_getter=props.named_getter), + "NamedPropertyGetterCallback")) + add_callback(*make_named_property_setter_callback( + cg_context.make_copy(named_property_setter=props.named_setter), + "NamedPropertySetterCallback")) + add_callback(*make_named_property_deleter_callback( + cg_context.make_copy(named_property_deleter=props.named_deleter), + "NamedPropertyDeleterCallback")) + add_callback(*make_named_property_definer_callback( + cg_context, "NamedPropertyDefinerCallback")) + add_callback(*make_named_property_descriptor_callback( + cg_context, "NamedPropertyDescriptorCallback")) + add_callback(*make_named_property_enumerator_callback( + cg_context, "NamedPropertyEnumeratorCallback")) + + if props.has_named_properties: + impl_bridge = v8_bridge_class_name( + most_derived_interface( + props.named_getter.owner, + props.named_setter and props.named_setter.owner, + props.named_deleter and props.named_deleter.owner, + )) + flags = ["v8::PropertyHandlerFlags::kOnlyInterceptStrings"] + if "OverrideBuiltins" not in interface.extended_attributes: + flags.append("v8::PropertyHandlerFlags::kNonMasking") + if (props.named_getter.extended_attributes.value_of("Affects") == + "Nothing"): + flags.append("v8::PropertyHandlerFlags::kHasNoSideEffect") + property_handler_flags = ( + "static_cast<v8::PropertyHandlerFlags>({})".format(" | ".join( + map(lambda flag: "int({})".format(flag), flags)))) + pattern = """\ +// Named properties +${instance_template}->SetHandler( + v8::NamedPropertyHandlerConfiguration( + {impl_bridge}::NamedPropertyGetterCallback, +% if interface.indexed_and_named_properties.named_setter: + {impl_bridge}::NamedPropertySetterCallback, +% else: + nullptr, // setter +% endif + {impl_bridge}::NamedPropertyDescriptorCallback, +% if interface.indexed_and_named_properties.named_deleter: + {impl_bridge}::NamedPropertyDeleterCallback, +% else: + nullptr, // deleter +% endif +% if interface.indexed_and_named_properties.is_named_property_enumerable: + {impl_bridge}::NamedPropertyEnumeratorCallback, +% else: + nullptr, // enumerator +% endif + {impl_bridge}::NamedPropertyDefinerCallback, + v8::Local<v8::Value>(), + {property_handler_flags}));""" + install_nodes.append( + TextNode( + _format( + pattern, + impl_bridge=impl_bridge, + property_handler_flags=property_handler_flags))) + + return func_decls, func_defs, install_nodes + + +def make_cross_origin_property_callbacks_and_install_nodes( + cg_context, attribute_entries, operation_entries): + assert isinstance(cg_context, CodeGenContext) + + callback_defs = [] + install_nodes = SequenceNode() + + CROSS_ORIGIN_INTERFACES = ("Window", "Location") + if cg_context.interface.identifier not in CROSS_ORIGIN_INTERFACES: + return callback_defs, install_nodes + + entry_nodes = [] + for entry in attribute_entries: + attribute = entry.property_ + if "CrossOrigin" not in attribute.extended_attributes: + continue + assert entry.world == CodeGenContext.ALL_WORLDS + values = attribute.extended_attributes.values_of("CrossOrigin") + get_func = "nullptr" + set_func = "nullptr" + get_value = "nullptr" + set_value = "nullptr" + if not values or "Getter" in values: + get_func = entry.attr_get_callback_name + cgc = cg_context.make_copy( + attribute=attribute, + attribute_get=True, + v8_callback_type=( + CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK)) + get_value = callback_function_name(cgc, for_cross_origin=True) + func_def = make_attribute_get_callback_def(cgc, get_value) + callback_defs.extend([func_def, EmptyNode()]) + if (not values or "Setter" in values) and entry.attr_set_callback_name: + set_func = entry.attr_set_callback_name + cgc = cg_context.make_copy( + attribute=attribute, + attribute_set=True, + v8_callback_type=( + CodeGenContext.V8_GENERIC_NAMED_PROPERTY_SETTER_CALLBACK)) + set_value = callback_function_name(cgc, for_cross_origin=True) + func_def = make_attribute_set_callback_def(cgc, set_value) + callback_defs.extend([func_def, EmptyNode()]) + pattern = ("{{\"{property_name}\", " + "{get_func}, {set_func}, {get_value}, {set_value}}},") + entry_nodes.append( + TextNode( + _format( + pattern, + property_name=attribute.identifier, + get_func=get_func, + set_func=set_func, + get_value=get_value, + set_value=set_value))) + callback_defs.append( + ListNode([ + TextNode("constexpr bindings::CrossOriginAttributeTableEntry " + "kCrossOriginAttributeTable[] = {"), + ListNode(entry_nodes), + TextNode("};"), + EmptyNode(), + ])) + + entry_nodes = [] + for entry in operation_entries: + operation_group = entry.property_ + if "CrossOrigin" not in operation_group.extended_attributes: + continue + assert entry.world == CodeGenContext.ALL_WORLDS + entry_nodes.append( + TextNode( + _format( + "{{\"{property_name}\", {op_callback}, {op_func_length}}},", + property_name=operation_group.identifier, + op_callback=entry.op_callback_name, + op_func_length=entry.op_func_length))) + callback_defs.append( + ListNode([ + TextNode("constexpr bindings::CrossOriginOperationTableEntry " + "kCrossOriginOperationTable[] = {"), + ListNode(entry_nodes), + TextNode("};"), + EmptyNode(), + ])) + + cg_context = cg_context.make_copy( + v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK) + + callback_defs.extend([ + make_cross_origin_access_check_callback( + cg_context, "CrossOriginAccessCheckCallback"), + EmptyNode(), + make_cross_origin_property_getter_callback( + cg_context, "CrossOriginPropertyGetterCallback"), + EmptyNode(), + make_cross_origin_property_setter_callback( + cg_context, "CrossOriginPropertySetterCallback"), + EmptyNode(), + make_cross_origin_property_descriptor_callback( + cg_context, "CrossOriginPropertyDescriptorCallback"), + EmptyNode(), + make_cross_origin_property_enumerator_callback( + cg_context, "CrossOriginPropertyEnumeratorCallback"), + ]) + + text = """\ +// Cross origin properties +${instance_template}->SetAccessCheckCallbackAndHandler( + CrossOriginAccessCheckCallback, + v8::NamedPropertyHandlerConfiguration( + CrossOriginPropertyGetterCallback, + CrossOriginPropertySetterCallback, + CrossOriginPropertyDescriptorCallback, + nullptr, // deleter + CrossOriginPropertyEnumeratorCallback, + nullptr, // definer, + v8::Local<v8::Value>(), + v8::PropertyHandlerFlags::kNone), +% if interface.indexed_and_named_properties and \ + interface.indexed_and_named_properties.has_indexed_properties: + // Reuse non-cross origin indexed property callbacks. + v8::IndexedPropertyHandlerConfiguration( + ${class_name}::IndexedPropertyGetterCallback, + nullptr, // setter + ${class_name}::IndexedPropertyDescriptorCallback, + nullptr, // deleter + ${class_name}::IndexedPropertyEnumeratorCallback, + nullptr, // definer + v8::Local<v8::Value>(), + v8::PropertyHandlerFlags::kNone), +% else: + v8::IndexedPropertyHandlerConfiguration( + nullptr, // getter + nullptr, // setter + nullptr, // descriptor + nullptr, // deleter + nullptr, // enumerator + nullptr, // definer + v8::Local<v8::Value>(), + v8::PropertyHandlerFlags::kNone), +% endif + v8::Local<v8::Value>());""" + install_nodes.append(TextNode(text)) + install_nodes.accumulate( + CodeGenAccumulator.require_include_headers([ + "third_party/blink/renderer/bindings/core/v8/binding_security.h", + "third_party/blink/renderer/platform/bindings/v8_cross_origin_property_support.h", + ])) + + return callback_defs, install_nodes + + +def make_cross_component_init( + cg_context, function_name, class_name, has_unconditional_props, + has_context_independent_props, has_context_dependent_props): + """ + Returns: + A triplet of CodeNode of: + - function declaration + - function definition + - trampoline member variable definitions + """ + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + assert isinstance(class_name, str) + assert isinstance(has_unconditional_props, bool) + assert isinstance(has_context_independent_props, bool) + assert isinstance(has_context_dependent_props, bool) + + T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) + + def filter_four_trampolines(nodes): + assert len(nodes) == 4 + flags = (True, has_unconditional_props, has_context_independent_props, + has_context_dependent_props) + return [node for node, flag in zip(nodes, flags) if flag] + + trampoline_var_decls = ListNode( + filter_four_trampolines([ + F("static InstallInterfaceTemplateFuncType {};", + TP_INSTALL_INTERFACE_TEMPLATE), + F("static InstallUnconditionalPropertiesFuncType {};", + TP_INSTALL_UNCONDITIONAL_PROPS), + F("static InstallContextIndependentPropertiesFuncType {};", + TP_INSTALL_CONTEXT_INDEPENDENT_PROPS), + F("static InstallContextDependentPropertiesFuncType {};", + TP_INSTALL_CONTEXT_DEPENDENT_PROPS), + ])) + + trampoline_var_defs = ListNode( + filter_four_trampolines([ + F(("${class_name}::InstallInterfaceTemplateFuncType " + "${class_name}::{} = nullptr;"), TP_INSTALL_INTERFACE_TEMPLATE), + F(("${class_name}::InstallUnconditionalPropertiesFuncType " + "${class_name}::{} = nullptr;"), + TP_INSTALL_UNCONDITIONAL_PROPS), + F(("${class_name}::InstallContextIndependentPropertiesFuncType " + "${class_name}::{} = nullptr;"), + TP_INSTALL_CONTEXT_INDEPENDENT_PROPS), + F(("${class_name}::InstallContextDependentPropertiesFuncType " + "${class_name}::{} = nullptr;"), + TP_INSTALL_CONTEXT_DEPENDENT_PROPS), + ])) + trampoline_var_defs.set_base_template_vars(cg_context.template_bindings()) + + func_decl = CxxFuncDeclNode( + name=function_name, arg_decls=[], return_type="void", static=True) + + func_def = CxxFuncDefNode( + name=function_name, + class_name=class_name, + arg_decls=[], + return_type="void") + func_def.set_base_template_vars(cg_context.template_bindings()) + + body = func_def.body + body.extend( + filter_four_trampolines([ + F("${class_name}::{} = {};", TP_INSTALL_INTERFACE_TEMPLATE, + FN_INSTALL_INTERFACE_TEMPLATE), + F("${class_name}::{} = {};", TP_INSTALL_UNCONDITIONAL_PROPS, + FN_INSTALL_UNCONDITIONAL_PROPS), + F("${class_name}::{} = {};", TP_INSTALL_CONTEXT_INDEPENDENT_PROPS, + FN_INSTALL_CONTEXT_INDEPENDENT_PROPS), + F("${class_name}::{} = {};", TP_INSTALL_CONTEXT_DEPENDENT_PROPS, + FN_INSTALL_CONTEXT_DEPENDENT_PROPS), + ])) + + return func_decl, func_def, trampoline_var_decls, trampoline_var_defs + + +# ---------------------------------------------------------------------------- +# WrapperTypeInfo +# ---------------------------------------------------------------------------- + +# FN = function name +FN_GET_WRAPPER_TYPE_INFO = name_style.func("GetWrapperTypeInfo") + +# MN = member name +MN_WRAPPER_TYPE_INFO = name_style.member_var("wrapper_type_info_") + + +def make_wrapper_type_info(cg_context, function_name, member_var_name, + install_context_dependent_func_name): + assert isinstance(cg_context, CodeGenContext) + assert isinstance(function_name, str) + assert isinstance(member_var_name, str) + assert _is_none_or_str(install_context_dependent_func_name) + + func_def = CxxFuncDefNode( + name=function_name, + arg_decls=[], + return_type="constexpr const WrapperTypeInfo*", + static=True) + func_def.set_base_template_vars(cg_context.template_bindings()) + func_def.body.append(TextNode("return &{};".format(member_var_name))) + + member_var_def = TextNode( + "static const WrapperTypeInfo {};".format(member_var_name)) + + pattern = """\ +// Migration adapter +v8::Local<v8::FunctionTemplate> ${class_name}::DomTemplate( + v8::Isolate* isolate, + const DOMWrapperWorld& world) {{ + return V8DOMConfiguration::DomClassTemplate( + isolate, world, + const_cast<WrapperTypeInfo*>(${class_name}::GetWrapperTypeInfo()), + ${class_name}::InstallInterfaceTemplate); +}} + +const WrapperTypeInfo ${class_name}::wrapper_type_info_{{ + gin::kEmbedderBlink, + ${class_name}::DomTemplate, + {install_context_dependent_func}, + "${{class_like.identifier}}", + {wrapper_type_info_of_inherited}, + {wrapper_type_prototype}, + {wrapper_class_id}, + {active_script_wrappable_inheritance}, +}};""" + class_like = cg_context.class_like + install_context_dependent_func = ( + "${class_name}::InstallContextDependentAdapter" + if install_context_dependent_func_name else "nullptr") + if class_like.inherited: + wrapper_type_info_of_inherited = "{}::GetWrapperTypeInfo()".format( + v8_bridge_class_name(class_like.inherited)) + else: + wrapper_type_info_of_inherited = "nullptr" + wrapper_type_prototype = ("WrapperTypeInfo::kWrapperTypeObjectPrototype" + if isinstance(class_like, web_idl.Interface) else + "WrapperTypeInfo::kWrapperTypeNoPrototype") + wrapper_class_id = ("WrapperTypeInfo::kNodeClassId" + if class_like.does_implement("Node") else + "WrapperTypeInfo::kObjectClassId") + active_script_wrappable_inheritance = ( + "WrapperTypeInfo::kInheritFromActiveScriptWrappable" + if class_like.code_generator_info.is_active_script_wrappable else + "WrapperTypeInfo::kNotInheritFromActiveScriptWrappable") + text = _format( + pattern, + install_context_dependent_func=install_context_dependent_func, + wrapper_type_info_of_inherited=wrapper_type_info_of_inherited, + wrapper_type_prototype=wrapper_type_prototype, + wrapper_class_id=wrapper_class_id, + active_script_wrappable_inheritance=active_script_wrappable_inheritance + ) + bridge_wrapper_type_info_def = TextNode(text) + + blink_class = blink_class_name(class_like) + pattern = ("const WrapperTypeInfo& {blink_class}::wrapper_type_info_ = " + "${class_name}::wrapper_type_info_;") + blink_wrapper_type_info_def = TextNode( + _format(pattern, blink_class=blink_class)) + + if class_like.code_generator_info.is_active_script_wrappable: + pattern = """\ +// [ActiveScriptWrappable] +static_assert( + std::is_base_of<ActiveScriptWrappableBase, {blink_class}>::value, + "{blink_class} does not inherit from ActiveScriptWrappable<> despite " + "the IDL has [ActiveScriptWrappable] extended attribute."); +static_assert( + !std::is_same<decltype(&{blink_class}::HasPendingActivity), + decltype(&ScriptWrappable::HasPendingActivity)>::value, + "{blink_class} is not overriding hasPendingActivity() despite " + "the IDL has [ActiveScriptWrappable] extended attribute.");""" + else: + pattern = """\ +// non-[ActiveScriptWrappable] +static_assert( + !std::is_base_of<ActiveScriptWrappableBase, {blink_class}>::value, + "{blink_class} inherits from ActiveScriptWrappable<> without " + "[ActiveScriptWrappable] extended attribute."); +static_assert( + std::is_same<decltype(&{blink_class}::HasPendingActivity), + decltype(&ScriptWrappable::HasPendingActivity)>::value, + "{blink_class} is overriding hasPendingActivity() without " + "[ActiveScriptWrappable] extended attribute.");""" + check_active_script_wrappable = TextNode( + _format(pattern, blink_class=blink_class)) + + wrapper_type_info_def = ListNode([ + bridge_wrapper_type_info_def, + EmptyNode(), + blink_wrapper_type_info_def, + EmptyNode(), + check_active_script_wrappable, + ]) + wrapper_type_info_def.set_base_template_vars( + cg_context.template_bindings()) + + return func_def, member_var_def, wrapper_type_info_def + + +# ---------------------------------------------------------------------------- +# Main functions +# ---------------------------------------------------------------------------- + + +def _collect_include_headers(interface): + headers = set(interface.code_generator_info.blink_headers) + + def collect_from_idl_type(idl_type): + idl_type.apply_to_all_composing_elements(add_include_headers) + + def add_include_headers(idl_type): + # ScriptPromise doesn't require any header for the result type. + if idl_type.is_promise: + raise StopIteration(idl_type.syntactic_form) + + type_def_obj = idl_type.type_definition_object + if type_def_obj is not None: + headers.add(PathManager(type_def_obj).api_path(ext="h")) + if isinstance(type_def_obj, web_idl.Interface): + headers.add(PathManager(type_def_obj).blink_path(ext="h")) + raise StopIteration(idl_type.syntactic_form) + + union_def_obj = idl_type.union_definition_object + if union_def_obj is not None: + headers.add(PathManager(union_def_obj).api_path(ext="h")) + + for attribute in interface.attributes: + collect_from_idl_type(attribute.idl_type) + for constructor in interface.constructors: + for argument in constructor.arguments: + collect_from_idl_type(argument.idl_type) + for operation in interface.operations: + collect_from_idl_type(operation.return_type) + for argument in operation.arguments: + collect_from_idl_type(argument.idl_type) + + for exposed_construct in interface.exposed_constructs: + headers.add(PathManager(exposed_construct).api_path(ext="h")) + for legacy_window_alias in interface.legacy_window_aliases: + headers.add( + PathManager(legacy_window_alias.original).api_path(ext="h")) + + path_manager = PathManager(interface) + headers.discard(path_manager.api_path(ext="h")) + headers.discard(path_manager.impl_path(ext="h")) + + # TODO(yukishiino): Window interface should be + # [ImplementedAs=LocalDOMWindow] instead of [ImplementedAs=DOMWindow], and + # [CrossOrigin] properties should be implemented specifically with + # DOMWindow class. Then, we'll have less hacks. + if interface.identifier == "Window": + headers.add("third_party/blink/renderer/core/frame/local_dom_window.h") + + return headers + + +def generate_interface(interface): + path_manager = PathManager(interface) + api_component = path_manager.api_component + impl_component = path_manager.impl_component + is_cross_components = path_manager.is_cross_components + + # Class names + api_class_name = v8_bridge_class_name(interface) + if is_cross_components: + impl_class_name = "{}::Impl".format(api_class_name) + else: + impl_class_name = api_class_name + + cg_context = CodeGenContext(interface=interface, class_name=api_class_name) + + # Filepaths + api_header_path = path_manager.api_path(ext="h") + api_source_path = path_manager.api_path(ext="cc") + if is_cross_components: + impl_header_path = path_manager.impl_path(ext="h") + impl_source_path = path_manager.impl_path(ext="cc") + + # Root nodes + api_header_node = ListNode(tail="\n") + api_header_node.set_accumulator(CodeGenAccumulator()) + api_header_node.set_renderer(MakoRenderer()) + api_source_node = ListNode(tail="\n") + api_source_node.set_accumulator(CodeGenAccumulator()) + api_source_node.set_renderer(MakoRenderer()) + if is_cross_components: + impl_header_node = ListNode(tail="\n") + impl_header_node.set_accumulator(CodeGenAccumulator()) + impl_header_node.set_renderer(MakoRenderer()) + impl_source_node = ListNode(tail="\n") + impl_source_node.set_accumulator(CodeGenAccumulator()) + impl_source_node.set_renderer(MakoRenderer()) + else: + impl_header_node = api_header_node + impl_source_node = api_source_node + + # Namespaces + api_header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + api_source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + if is_cross_components: + impl_header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + impl_source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + else: + impl_header_blink_ns = api_header_blink_ns + impl_source_blink_ns = api_source_blink_ns + + # Class definitions + api_class_def = CxxClassDefNode( + cg_context.class_name, + base_class_names=[ + _format("bindings::V8InterfaceBridge<${class_name}, {}>", + blink_class_name(interface)), + ], + final=True, + export=component_export(api_component)) + api_class_def.set_base_template_vars(cg_context.template_bindings()) + api_class_def.bottom_section.append( + TextNode("friend class {};".format(blink_class_name(interface)))) + if is_cross_components: + impl_class_def = CxxClassDefNode( + impl_class_name, + final=True, + export=component_export(impl_component)) + impl_class_def.set_base_template_vars(cg_context.template_bindings()) + api_class_def.public_section.extend([ + TextNode("// Cross-component implementation class"), + TextNode("class Impl;"), + EmptyNode(), + ]) + else: + impl_class_def = api_class_def + + # Constants + constant_defs = ListNode() + for constant in interface.constants: + cgc = cg_context.make_copy(constant=constant) + constant_defs.append( + make_constant_constant_def(cgc, constant_name(cgc))) + + # Custom callback implementations + custom_callback_impl_decls = ListNode() + + def add_custom_callback_impl_decl(**params): + arg_decls = params.pop("arg_decls") + name = params.pop("name", None) + if name is None: + name = custom_function_name(cg_context.make_copy(**params)) + custom_callback_impl_decls.append( + CxxFuncDeclNode( + name=name, + arg_decls=arg_decls, + return_type="void", + static=True)) + + if interface.identifier == "HTMLAllCollection": + add_custom_callback_impl_decl( + name=name_style.func("LegacyCallCustom"), + arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"]) + for attribute in interface.attributes: + custom_values = attribute.extended_attributes.values_of("Custom") + is_cross_origin = "CrossOrigin" in attribute.extended_attributes + cross_origin_values = attribute.extended_attributes.values_of( + "CrossOrigin") + if "Getter" in custom_values: + add_custom_callback_impl_decl( + attribute=attribute, + attribute_get=True, + arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"]) + if is_cross_origin and (not cross_origin_values + or "Getter" in cross_origin_values): + add_custom_callback_impl_decl( + attribute=attribute, + attribute_get=True, + arg_decls=["const v8::PropertyCallbackInfo<v8::Value>&"]) + if "Setter" in custom_values: + add_custom_callback_impl_decl( + attribute=attribute, + attribute_set=True, + arg_decls=[ + "v8::Local<v8::Value>", + "const v8::FunctionCallbackInfo<v8::Value>&", + ]) + if is_cross_origin and (not cross_origin_values + or "Setter" in cross_origin_values): + add_custom_callback_impl_decl( + attribute=attribute, + attribute_set=True, + arg_decls=[ + "v8::Local<v8::Value>", + "const v8::PropertyCallbackInfo<v8::Value>&", + ]) for operation_group in interface.operation_groups: - func_name = name_style.func(operation_group.identifier, - "OperationCallback") - code_node.append( - make_operation_callback_def( - cg_context.make_copy(operation_group=operation_group), - func_name)) + if "Custom" in operation_group.extended_attributes: + add_custom_callback_impl_decl( + operation_group=operation_group, + arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"]) + if interface.indexed_and_named_properties: + props = interface.indexed_and_named_properties + operation = props.own_named_getter + if operation and "Custom" in operation.extended_attributes: + add_custom_callback_impl_decl( + named_property_getter=operation, + arg_decls=[ + "const AtomicString& property_name", + "const v8::PropertyCallbackInfo<v8::Value>&", + ]) + operation = props.own_named_setter + if operation and "Custom" in operation.extended_attributes: + add_custom_callback_impl_decl( + named_property_setter=operation, + arg_decls=[ + "const AtomicString& property_name", + "v8::Local<v8::Value> v8_property_value", + "const v8::PropertyCallbackInfo<v8::Value>&", + ]) + operation = props.own_named_deleter + if operation and "Custom" in operation.extended_attributes: + add_custom_callback_impl_decl( + named_property_deleter=operation, + arg_decls=[ + "const AtomicString& property_name", + "const v8::PropertyCallbackInfo<v8::Value>&", + ]) + + # Cross-component trampolines + if is_cross_components: + # tp_ = trampoline name + tp_install_interface_template = TP_INSTALL_INTERFACE_TEMPLATE + tp_install_unconditional_props = TP_INSTALL_UNCONDITIONAL_PROPS + tp_install_context_independent_props = ( + TP_INSTALL_CONTEXT_INDEPENDENT_PROPS) + tp_install_context_dependent_props = TP_INSTALL_CONTEXT_DEPENDENT_PROPS + else: + tp_install_interface_template = None + tp_install_unconditional_props = None + tp_install_context_independent_props = None + tp_install_context_dependent_props = None + + # Callback functions + attribute_entries = [] + constant_entries = [] + constructor_entries = [] + exposed_construct_entries = [] + operation_entries = [] + callback_defs = _make_property_entries_and_callback_defs( + cg_context, + attribute_entries=attribute_entries, + constant_entries=constant_entries, + constructor_entries=constructor_entries, + exposed_construct_entries=exposed_construct_entries, + operation_entries=operation_entries) + + # Indexed and named properties + (indexed_and_named_property_decls, indexed_and_named_property_defs, + indexed_and_named_property_install_nodes) = ( + make_indexed_and_named_property_callbacks_and_install_nodes( + cg_context)) + + # Cross origin properties + (cross_origin_property_callback_defs, + cross_origin_property_install_nodes) = ( + make_cross_origin_property_callbacks_and_install_nodes( + cg_context, attribute_entries, operation_entries)) + callback_defs.extend(cross_origin_property_callback_defs) + + # Installer functions + is_unconditional = lambda entry: entry.exposure_conditional.is_always_true + is_context_dependent = lambda entry: entry.is_context_dependent + is_context_independent = ( + lambda e: not is_context_dependent(e) and not is_unconditional(e)) + (install_unconditional_props_decl, install_unconditional_props_def, + install_unconditional_props_trampoline) = make_install_properties( + cg_context, + FN_INSTALL_UNCONDITIONAL_PROPS, + class_name=impl_class_name, + trampoline_var_name=tp_install_unconditional_props, + is_context_dependent=False, + attribute_entries=filter(is_unconditional, attribute_entries), + constant_entries=filter(is_unconditional, constant_entries), + exposed_construct_entries=filter(is_unconditional, + exposed_construct_entries), + operation_entries=filter(is_unconditional, operation_entries)) + (install_context_independent_props_decl, + install_context_independent_props_def, + install_context_independent_props_trampoline) = make_install_properties( + cg_context, + FN_INSTALL_CONTEXT_INDEPENDENT_PROPS, + class_name=impl_class_name, + trampoline_var_name=tp_install_context_independent_props, + is_context_dependent=False, + attribute_entries=filter(is_context_independent, attribute_entries), + constant_entries=filter(is_context_independent, constant_entries), + exposed_construct_entries=filter(is_context_independent, + exposed_construct_entries), + operation_entries=filter(is_context_independent, operation_entries)) + (install_context_dependent_props_decl, install_context_dependent_props_def, + install_context_dependent_props_trampoline) = make_install_properties( + cg_context, + FN_INSTALL_CONTEXT_DEPENDENT_PROPS, + class_name=impl_class_name, + trampoline_var_name=tp_install_context_dependent_props, + is_context_dependent=True, + attribute_entries=filter(is_context_dependent, attribute_entries), + constant_entries=filter(is_context_dependent, constant_entries), + exposed_construct_entries=filter(is_context_dependent, + exposed_construct_entries), + operation_entries=filter(is_context_dependent, operation_entries)) + (install_interface_template_decl, install_interface_template_def, + install_interface_template_trampoline) = make_install_interface_template( + cg_context, + FN_INSTALL_INTERFACE_TEMPLATE, + class_name=impl_class_name, + trampoline_var_name=tp_install_interface_template, + constructor_entries=constructor_entries, + indexed_and_named_property_install_nodes=( + indexed_and_named_property_install_nodes), + cross_origin_property_install_nodes=( + cross_origin_property_install_nodes), + install_unconditional_func_name=(install_unconditional_props_def + and FN_INSTALL_UNCONDITIONAL_PROPS), + install_context_independent_func_name=( + install_context_independent_props_def + and FN_INSTALL_CONTEXT_INDEPENDENT_PROPS)) + installer_function_decls = ListNode([ + install_interface_template_decl, + install_unconditional_props_decl, + install_context_independent_props_decl, + install_context_dependent_props_decl, + ]) + installer_function_defs = ListNode([ + install_interface_template_def, + EmptyNode(), + install_unconditional_props_def, + EmptyNode(), + install_context_independent_props_def, + EmptyNode(), + install_context_dependent_props_def, + ]) + installer_function_trampolines = ListNode([ + install_interface_template_trampoline, + install_unconditional_props_trampoline, + install_context_independent_props_trampoline, + install_context_dependent_props_trampoline, + ]) + + # WrapperTypeInfo + (get_wrapper_type_info_def, wrapper_type_info_var_def, + wrapper_type_info_init) = make_wrapper_type_info( + cg_context, + FN_GET_WRAPPER_TYPE_INFO, + MN_WRAPPER_TYPE_INFO, + install_context_dependent_func_name=( + install_context_dependent_props_def + and FN_INSTALL_CONTEXT_DEPENDENT_PROPS)) + + # Cross-component trampolines + if is_cross_components: + (cross_component_init_decl, cross_component_init_def, + trampoline_var_decls, + trampoline_var_defs) = make_cross_component_init( + cg_context, + "Init", + class_name=impl_class_name, + has_unconditional_props=bool( + install_unconditional_props_trampoline), + has_context_independent_props=bool( + install_context_independent_props_trampoline), + has_context_dependent_props=bool( + install_context_dependent_props_trampoline)) + + # Header part (copyright, include directives, and forward declarations) + api_header_node.extend([ + make_copyright_header(), + EmptyNode(), + enclose_with_header_guard( + ListNode([ + make_header_include_directives(api_header_node.accumulator), + EmptyNode(), + api_header_blink_ns, + ]), name_style.header_guard(api_header_path)), + ]) + api_header_blink_ns.body.extend([ + make_forward_declarations(api_header_node.accumulator), + EmptyNode(), + ]) + api_source_node.extend([ + make_copyright_header(), + EmptyNode(), + TextNode("#include \"{}\"".format(api_header_path)), + EmptyNode(), + make_header_include_directives(api_source_node.accumulator), + EmptyNode(), + api_source_blink_ns, + ]) + api_source_blink_ns.body.extend([ + make_forward_declarations(api_source_node.accumulator), + EmptyNode(), + ]) + if is_cross_components: + impl_header_node.extend([ + make_copyright_header(), + EmptyNode(), + enclose_with_header_guard( + ListNode([ + make_header_include_directives( + impl_header_node.accumulator), + EmptyNode(), + impl_header_blink_ns, + ]), name_style.header_guard(impl_header_path)), + ]) + impl_header_blink_ns.body.extend([ + make_forward_declarations(impl_header_node.accumulator), + EmptyNode(), + ]) + impl_source_node.extend([ + make_copyright_header(), + EmptyNode(), + TextNode("#include \"{}\"".format(impl_header_path)), + EmptyNode(), + make_header_include_directives(impl_source_node.accumulator), + EmptyNode(), + impl_source_blink_ns, + ]) + impl_source_blink_ns.body.extend([ + make_forward_declarations(impl_source_node.accumulator), + EmptyNode(), + ]) + api_header_node.accumulator.add_include_headers([ + interface.code_generator_info.blink_headers[0], + component_export_header(api_component), + "third_party/blink/renderer/platform/bindings/v8_interface_bridge.h", + ]) + api_source_node.accumulator.add_include_headers([ + "third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.h", + ]) + if interface.inherited: + api_source_node.accumulator.add_include_header( + PathManager(interface.inherited).api_path(ext="h")) + if is_cross_components: + impl_header_node.accumulator.add_include_headers([ + api_header_path, + component_export_header(impl_component), + ]) + impl_source_node.accumulator.add_include_headers([ + "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h", + "third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.h", + "third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h", + "third_party/blink/renderer/platform/bindings/exception_messages.h", + "third_party/blink/renderer/platform/bindings/runtime_call_stats.h", + "third_party/blink/renderer/platform/bindings/v8_binding.h", + ]) + impl_source_node.accumulator.add_include_headers( + _collect_include_headers(interface)) + if interface.constructor_groups: + impl_source_node.accumulator.add_include_headers([ + "third_party/blink/renderer/platform/bindings/v8_object_constructor.h", + ]) + + # Assemble the parts. + api_header_blink_ns.body.append(api_class_def) + if is_cross_components: + impl_header_blink_ns.body.append(impl_class_def) + + api_class_def.public_section.append(get_wrapper_type_info_def) + api_class_def.public_section.append(EmptyNode()) + api_class_def.public_section.extend([ + TextNode("// Migration adapter"), + TextNode("static v8::Local<v8::FunctionTemplate> DomTemplate(" + "v8::Isolate* isolate, " + "const DOMWrapperWorld& world);"), + EmptyNode(), + ]) + api_class_def.private_section.append(wrapper_type_info_var_def) + api_class_def.private_section.append(EmptyNode()) + api_source_blink_ns.body.extend([ + wrapper_type_info_init, + EmptyNode(), + ]) + + if is_cross_components: + api_class_def.public_section.append(installer_function_trampolines) + api_class_def.private_section.extend([ + TextNode("// Cross-component trampolines"), + trampoline_var_decls, + EmptyNode(), + ]) + api_source_blink_ns.body.extend([ + TextNode("// Cross-component trampolines"), + trampoline_var_defs, + EmptyNode(), + ]) + impl_class_def.public_section.append(cross_component_init_decl) + impl_class_def.private_section.append(installer_function_decls) + impl_source_blink_ns.body.extend([ + cross_component_init_def, + EmptyNode(), + ]) + else: + api_class_def.public_section.append(installer_function_decls) + api_class_def.public_section.append(EmptyNode()) + + if constant_defs: + api_class_def.public_section.extend([ + TextNode("// Constants"), + constant_defs, + EmptyNode(), + ]) + + if custom_callback_impl_decls: + api_class_def.public_section.extend([ + TextNode("// Custom callback implementations"), + custom_callback_impl_decls, + EmptyNode(), + ]) + + if indexed_and_named_property_decls: + api_class_def.public_section.extend([ + TextNode("// Indexed properties and named properties"), + indexed_and_named_property_decls, + EmptyNode(), + ]) + + impl_source_blink_ns.body.extend([ + CxxNamespaceNode(name="", body=callback_defs), + EmptyNode(), + installer_function_defs, + EmptyNode(), + indexed_and_named_property_defs, + EmptyNode(), + ]) - code_node.append(make_install_interface_template_def(cg_context)) + # Write down to the files. + write_code_node_to_file(api_header_node, + path_manager.gen_path_to(api_header_path)) + write_code_node_to_file(api_source_node, + path_manager.gen_path_to(api_source_path)) + if path_manager.is_cross_components: + write_code_node_to_file(impl_header_node, + path_manager.gen_path_to(impl_header_path)) + write_code_node_to_file(impl_source_node, + path_manager.gen_path_to(impl_source_path)) + + +def generate_init_idl_interfaces(web_idl_database): + # Filepaths + header_path = PathManager.component_path("modules", + "init_idl_interfaces.h") + source_path = PathManager.component_path("modules", + "init_idl_interfaces.cc") + + # Root nodes + header_node = ListNode(tail="\n") + header_node.set_accumulator(CodeGenAccumulator()) + header_node.set_renderer(MakoRenderer()) + source_node = ListNode(tail="\n") + source_node.set_accumulator(CodeGenAccumulator()) + source_node.set_renderer(MakoRenderer()) + + # Namespaces + header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + header_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings")) + source_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings")) + header_blink_ns.body.append(header_bindings_ns) + source_blink_ns.body.append(source_bindings_ns) + + # Function nodes + func_decl = CxxFuncDeclNode( + name="InitIDLInterfaces", arg_decls=[], return_type="void") + func_def = CxxFuncDefNode( + name="InitIDLInterfaces", arg_decls=[], return_type="void") + header_bindings_ns.body.extend([ + TextNode("""\ +// Initializes cross-component trampolines of IDL interface implementations.\ +"""), + func_decl, + ]) + source_bindings_ns.body.append(func_def) - root_node.extend([ + # Assemble the parts. + header_node.extend([ + make_copyright_header(), + EmptyNode(), + enclose_with_header_guard( + ListNode([ + make_header_include_directives(header_node.accumulator), + EmptyNode(), + header_blink_ns, + ]), name_style.header_guard(header_path)), + ]) + source_node.extend([ make_copyright_header(), - TextNode(""), - make_header_include_directives(root_node.accumulator), - TextNode(""), - enclose_with_namespace(code_node, name_style.namespace("blink")), + EmptyNode(), + TextNode("#include \"{}\"".format(header_path)), + EmptyNode(), + make_header_include_directives(source_node.accumulator), + EmptyNode(), + source_blink_ns, ]) - write_code_node_to_file(root_node, filepath) + init_calls = [] + for interface in web_idl_database.interfaces: + # 'Internals' is the only test-only interface that needs + # cross-component trampoline initialization. + if interface.identifier == "Internals": + continue + + path_manager = PathManager(interface) + if path_manager.is_cross_components: + source_node.accumulator.add_include_header( + path_manager.impl_path(ext="h")) + + class_name = v8_bridge_class_name(interface) + init_calls.append(_format("{}::Impl::Init();", class_name)) + for init_call in sorted(init_calls): + func_def.body.append(TextNode(init_call)) + + # Write down to the files. + write_code_node_to_file(header_node, path_manager.gen_path_to(header_path)) + write_code_node_to_file(source_node, path_manager.gen_path_to(source_path)) + + +def generate_interfaces(web_idl_database): + # More processes do not mean better performance. The default size was + # chosen heuristically. + process_pool_size = 8 + cpu_count = multiprocessing.cpu_count() + process_pool_size = max(1, min(cpu_count / 2, process_pool_size)) + + pool = multiprocessing.Pool(process_pool_size) + # Prior to Python3, Pool.map doesn't support user interrupts (e.g. Ctrl-C), + # although Pool.map_async(...).get(...) does. + timeout_in_sec = 3600 # Just enough long time + pool.map_async(generate_interface, + web_idl_database.interfaces).get(timeout_in_sec) + + generate_init_idl_interfaces(web_idl_database) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py index f75b959c3df..b4c70553863 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/mako_renderer.py @@ -4,59 +4,91 @@ import sys -import mako.lookup +import mako.runtime import mako.template +import mako.util +_MAKO_TEMPLATE_PASS_KEY = object() -class MakoRenderer(object): - """Represents a renderer object implemented with Mako templates.""" - def __init__(self, template_dirs=None): - self._template_params = { +class MakoTemplate(object): + """Represents a compiled template object.""" + + _mako_template_cache = {} + + def __init__(self, template_text): + assert isinstance(template_text, str) + + template_params = { "strict_undefined": True, } - self._template_lookup = mako.lookup.TemplateLookup( - directories=template_dirs, **self._template_params) + template = self._mako_template_cache.get(template_text) + if template is None: + template = mako.template.Template( + text=template_text, **template_params) + self._mako_template_cache[template_text] = template + self._template = template + + def mako_template(self, pass_key=None): + assert pass_key is _MAKO_TEMPLATE_PASS_KEY + return self._template + +class MakoRenderer(object): + """Represents a renderer object implemented with Mako templates.""" + + def __init__(self): + self._text_buffer = None + self._is_invalidated = False self._caller_stack = [] self._caller_stack_on_error = [] - def render(self, - caller, - template_path=None, - template_text=None, - template_vars=None): + def reset(self): + """ + Resets the rendering states of this object. Must be called before + the first call to |render| or |render_text|. + """ + self._text_buffer = mako.util.FastEncodingBuffer() + self._is_invalidated = False + + def is_rendering_complete(self): + return not (self._is_invalidated or self._text_buffer is None + or self._caller_stack) + + def invalidate_rendering_result(self): + self._is_invalidated = True + + def to_text(self): + """Returns the rendering result.""" + assert self._text_buffer is not None + return self._text_buffer.getvalue() + + def render(self, caller, template, template_vars): """ Renders the template with variable bindings. It's okay to invoke |render| method recursively and |caller| is pushed - onto the call stack, which is accessible via |callers| and |last_caller| - methods. + onto the call stack, which is accessible via + |callers_from_first_to_last| method, etc. Args: - template_path: A filepath to a template file. - template_text: A text content to be used as a template. Either of - |template_path| or |template_text| must be specified. - template_vars: Template variable bindings. caller: An object to be pushed onto the call stack. + template: A MakoTemplate. + template_vars: A dict of template variable bindings. """ - - assert template_path is not None or template_text is not None - assert template_path is None or template_text is None - assert isinstance(template_vars, dict) assert caller is not None + assert isinstance(template, MakoTemplate) + assert isinstance(template_vars, dict) self._caller_stack.append(caller) try: - if template_path is not None: - template = self._template_lookup.get_template(template_path) - elif template_text is not None: - template = mako.template.Template( - text=template_text, **self._template_params) - - text = template.render(**template_vars) + mako_template = template.mako_template( + pass_key=_MAKO_TEMPLATE_PASS_KEY) + mako_context = mako.runtime.Context(self._text_buffer, + **template_vars) + mako_template.render_context(mako_context) except: # Print stacktrace of template rendering. sys.stderr.write("\n") @@ -64,9 +96,9 @@ class MakoRenderer(object): sys.stderr.write(" * name: {}, type: {}\n".format( _guess_caller_name(self.last_caller), type(self.last_caller))) sys.stderr.write(" * depth: {}, module_id: {}\n".format( - len(self._caller_stack), template.module_id)) + len(self._caller_stack), mako_template.module_id)) sys.stderr.write("---- template source ----\n") - sys.stderr.write(template.source) + sys.stderr.write(mako_template.source) # Save the error state at the deepest call. current = self._caller_stack @@ -82,7 +114,16 @@ class MakoRenderer(object): finally: self._caller_stack.pop() - return text + def render_text(self, text): + """Renders a plain text as is.""" + assert isinstance(text, str) + self._text_buffer.write(text) + + def push_caller(self, caller): + self._caller_stack.append(caller) + + def pop_caller(self): + self._caller_stack.pop() @property def callers_from_first_to_last(self): @@ -125,7 +166,7 @@ def _guess_caller_name(caller): """Returns the best-guessed name of |caller|.""" try: # Outer CodeNode may have a binding to the caller. - for name, value in caller.outer.template_vars.iteritems(): + for name, value in caller.outer.template_vars.items(): if value is caller: return name try: diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/name_style.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/name_style.py index 137de2b88d3..36a858cecbb 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/name_style.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/name_style.py @@ -14,7 +14,7 @@ xxx_f(format_string, *args, **kwargs): The name is formatted with the given format string and arguments. """ -from blinkbuild.name_style_converter import NameStyleConverter +from blinkbuild import name_style_converter def api_func(*args): @@ -132,19 +132,29 @@ def namespace_f(format_string, *args, **kwargs): def _concat(style_func, args): assert callable(style_func) - return style_func(" ".join(map(str, args))) + return style_func(" ".join(map(_tokenize, args))) def _format(style_func, format_string, *args, **kwargs): assert callable(style_func) assert isinstance(format_string, str) - args = map(style_func, map(str, args)) - for key, value in kwargs.iteritems(): - kwargs[key] = style_func(str(value)) + args = map(style_func, map(_tokenize, args)) + for key, value in kwargs.items(): + kwargs[key] = style_func(_tokenize(value)) return format_string.format(*args, **kwargs) +def _tokenize(s): + s = str(s) + if "_" in s and s.isupper(): + # NameStyleConverter doesn't treat "ABC_DEF" as two tokens of "abc" and + # "def" while treating "abc_def" as "abc" and "def". Help + # NameStyleConverter by lowering the string. + return s.lower() + return s + + class raw(object): """ Namespace to provide (unrecommended) raw controls on case conversions. @@ -152,21 +162,27 @@ class raw(object): This class is pretending to be a module. """ + _NameStyleConverter = name_style_converter.NameStyleConverter + def __init__(self): assert False @staticmethod + def tokenize(name): + return name_style_converter.tokenize_name(name) + + @staticmethod def snake_case(name): - return NameStyleConverter(name).to_snake_case() + return raw._NameStyleConverter(name).to_snake_case() @staticmethod def upper_camel_case(name): - return NameStyleConverter(name).to_upper_camel_case() + return raw._NameStyleConverter(name).to_upper_camel_case() @staticmethod def lower_camel_case(name): - return NameStyleConverter(name).to_lower_camel_case() + return raw._NameStyleConverter(name).to_lower_camel_case() @staticmethod def macro_case(name): - return NameStyleConverter(name).to_macro_case() + return raw._NameStyleConverter(name).to_macro_case() diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py index b6997d71e65..47d6c08b8ee 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import os.path import posixpath import web_idl @@ -12,7 +13,16 @@ from .blink_v8_bridge import blink_class_name class PathManager(object): """ - Provides a variety of paths such as Blink headers and output files. + Provides a variety of paths such as Blink headers and output files. Unless + explicitly specified, returned paths are relative to the project's root + directory or the root directory of generated files, e.g. + "third_party/blink/renderer/..." + + Relative paths are represented in POSIX style so that it fits nicely in + generated code, e.g. #include "third_party/blink/renderer/...", while + absolute paths are represented in a platform-specific style so that it works + well with a platform-specific notion, e.g. a drive letter in Windows path + such as "C:\\chromium\\src\\...". About output files, there are two cases. - cross-components case: @@ -26,36 +36,72 @@ class PathManager(object): _is_initialized = False @classmethod - def init(cls, output_dirs): + def init(cls, root_src_dir, root_gen_dir, component_reldirs): """ Args: - output_dirs: Pairs of component and output directory. + root_src_dir: Project's root directory, which corresponds to "//" + in GN. + root_gen_dir: Root directory of generated files, which corresponds + to "//out/Default/gen" in GN. + component_reldirs: Pairs of component and output directory relative + to |root_gen_dir|. """ assert not cls._is_initialized - assert isinstance(output_dirs, dict) - cls._output_dirs = output_dirs + assert isinstance(root_src_dir, str) + assert isinstance(root_gen_dir, str) + assert isinstance(component_reldirs, dict) + cls._blink_path_prefix = posixpath.sep + posixpath.join( "third_party", "blink", "renderer", "") + + cls._root_src_dir = os.path.abspath(root_src_dir) + cls._root_gen_dir = os.path.abspath(root_gen_dir) + cls._component_reldirs = { + component: posixpath.normpath(rel_dir) + for component, rel_dir in component_reldirs.items() + } cls._is_initialized = True @classmethod - def relpath_to_project_root(cls, path): - index = path.find(cls._blink_path_prefix) - if index < 0: - assert path.startswith(cls._blink_path_prefix[1:]) - return path - return path[index + 1:] + def component_path(cls, component, filepath): + """ + Returns the relative path to |filepath| in |component|'s directory. + """ + assert cls._is_initialized, cls._REQUIRE_INIT_MESSAGE + return posixpath.join(cls._component_reldirs[component], filepath) + + @classmethod + def gen_path_to(cls, path): + """ + Returns the absolute path of |path| that must be relative to the root + directory of generated files. + """ + assert cls._is_initialized, cls._REQUIRE_INIT_MESSAGE + return os.path.abspath(os.path.join(cls._root_gen_dir, path)) + + @classmethod + def src_path_to(cls, path): + """ + Returns the absolute path of |path| that must be relative to the + project root directory. + """ + assert cls._is_initialized, cls._REQUIRE_INIT_MESSAGE + return os.path.abspath(os.path.join(cls._root_src_dir, path)) def __init__(self, idl_definition): assert self._is_initialized, self._REQUIRE_INIT_MESSAGE - idl_path = idl_definition.debug_info.location.filepath - self._idl_basepath, _ = posixpath.splitext(idl_path) - self._idl_dir, self._idl_basename = posixpath.split(self._idl_basepath) - - components = sorted(idl_definition.components) + components = sorted(idl_definition.components) # "core" < "modules" - if len(components) == 1: + if len(components) == 0: + assert isinstance(idl_definition, web_idl.Union) + # Unions of built-in types, e.g. DoubleOrString, do not have a + # component. + self._is_cross_components = False + default_component = web_idl.Component("core") + self._api_component = default_component + self._impl_component = default_component + elif len(components) == 1: component = components[0] self._is_cross_components = False self._api_component = component @@ -64,37 +110,36 @@ class PathManager(object): assert components[0] == "core" assert components[1] == "modules" self._is_cross_components = True - self._api_component = "core" - self._impl_component = "modules" + # Union does not have to support cross-component code generation + # because clients of IDL union must be on an upper or same layer to + # any of union members. + if isinstance(idl_definition, web_idl.Union): + self._api_component = components[1] + else: + self._api_component = components[0] + self._impl_component = components[1] else: assert False - self._api_dir = self._output_dirs[self._api_component] - self._impl_dir = self._output_dirs[self._impl_component] - self._out_basename = name_style.file("v8", idl_definition.identifier) - - if isinstance(idl_definition, - (web_idl.CallbackFunction, web_idl.CallbackInterface)): - self._blink_dir = self._api_dir - else: - self._blink_dir = self._idl_dir - self._blink_basename = name_style.file( - blink_class_name(idl_definition)) - - @property - def idl_dir(self): - return self._idl_dir - - def blink_path(self, filename=None, ext=None): - """ - Returns a path to a Blink implementation file relative to the project - root directory, e.g. "third_party/blink/renderer/..." - """ - return self.relpath_to_project_root( - self._join( - dirpath=self._blink_dir, - filename=(filename or self._blink_basename), - ext=ext)) + self._api_dir = self._component_reldirs[self._api_component] + self._impl_dir = self._component_reldirs[self._impl_component] + self._api_basename = name_style.file("v8", idl_definition.identifier) + self._impl_basename = name_style.file("v8", idl_definition.identifier) + # TODO(peria, yukishiino): Add "v8" prefix to union's files. Trying to + # produce the same filepaths with the old bindings generator for the + # time being. + if isinstance(idl_definition, web_idl.Union): + union_class_name = idl_definition.identifier + union_filepath = _BACKWARD_COMPATIBLE_UNION_FILEPATHS.get( + union_class_name, union_class_name) + self._api_basename = name_style.file(union_filepath) + self._impl_basename = name_style.file(union_filepath) + + if not isinstance(idl_definition, web_idl.Union): + idl_path = idl_definition.debug_info.location.filepath + self._blink_dir = posixpath.dirname(idl_path) + self._blink_basename = name_style.file( + blink_class_name(idl_definition)) @property def is_cross_components(self): @@ -111,7 +156,7 @@ class PathManager(object): def api_path(self, filename=None, ext=None): return self._join( dirpath=self.api_dir, - filename=(filename or self._out_basename), + filename=(filename or self._api_basename), ext=ext) @property @@ -125,7 +170,17 @@ class PathManager(object): def impl_path(self, filename=None, ext=None): return self._join( dirpath=self.impl_dir, - filename=(filename or self._out_basename), + filename=(filename or self._impl_basename), + ext=ext) + + @property + def blink_dir(self): + return self._blink_dir + + def blink_path(self, filename=None, ext=None): + return self._join( + dirpath=self.blink_dir, + filename=(filename or self._blink_basename), ext=ext) @staticmethod @@ -133,3 +188,34 @@ class PathManager(object): if ext is not None: filename = posixpath.extsep.join([filename, ext]) return posixpath.join(dirpath, filename) + + +# A hack to make the filepaths to generated IDL unions compatible with the old +# bindings generator. +# +# Copied from |shorten_union_name| defined in +# //third_party/blink/renderer/bindings/scripts/utilities.py +_BACKWARD_COMPATIBLE_UNION_FILEPATHS = { + # modules/canvas2d/CanvasRenderingContext2D.idl + "CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas": + "CanvasImageSource", + # modules/canvas/htmlcanvas/html_canvas_element_module_support_webgl2_compute.idl + "CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrWebGL2ComputeRenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext": + "RenderingContext", + # modules/canvas/htmlcanvas/html_canvas_element_module.idl + "CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext": + "RenderingContext", + # core/frame/window_or_worker_global_scope.idl + "HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas": + "ImageBitmapSource", + # bindings/tests/idls/core/TestTypedefs.idl + "NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord": + "NestedUnionType", + # modules/canvas/offscreencanvas/offscreen_canvas_module_support_webgl2_compute.idl. + # Due to offscreen_canvas_module_support_webgl2_compute.idl and offscreen_canvas_module.idl are exclusive in modules_idl_files.gni, they have same shorten name. + "OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrWebGL2ComputeRenderingContextOrImageBitmapRenderingContext": + "OffscreenRenderingContext", + # modules/canvas/offscreencanvas/offscreen_canvas_module.idl + "OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContext": + "OffscreenRenderingContext", +} diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py new file mode 100644 index 00000000000..dc3493cc394 --- /dev/null +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/style_format.py @@ -0,0 +1,107 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os.path +import subprocess +import sys + +_clang_format_command_path = None +_gn_command_path = None + + +def init(root_src_dir): + global _clang_format_command_path + global _gn_command_path + + assert _clang_format_command_path is None + assert _gn_command_path is None + + root_src_dir = os.path.abspath(root_src_dir) + + # Determine //buildtools/<platform>/ directory + if sys.platform.startswith("linux"): + platform = "linux64" + exe_suffix = "" + elif sys.platform.startswith("darwin"): + platform = "mac" + exe_suffix = "" + elif sys.platform.startswith(("cygwin", "win")): + platform = "win" + exe_suffix = ".exe" + else: + assert False, "Unknown platform: {}".format(sys.platform) + buildtools_platform_dir = os.path.join(root_src_dir, "buildtools", + platform) + + # //buildtools/<platform>/clang-format + _clang_format_command_path = os.path.join( + buildtools_platform_dir, "clang-format{}".format(exe_suffix)) + + # //buildtools/<platform>/gn + _gn_command_path = os.path.join(buildtools_platform_dir, + "gn{}".format(exe_suffix)) + + +def auto_format(contents, filename): + assert isinstance(filename, str) + + _, ext = os.path.splitext(filename) + if ext in (".gn", ".gni"): + return gn_format(contents, filename) + + return clang_format(contents, filename) + + +def clang_format(contents, filename=None): + command_line = [_clang_format_command_path] + if filename is not None: + command_line.append('-assume-filename={}'.format(filename)) + + return _invoke_format_command(command_line, filename, contents) + + +def gn_format(contents, filename=None): + command_line = [_gn_command_path, "format", "--stdin"] + if filename is not None: + command_line.append('-assume-filename={}'.format(filename)) + + return _invoke_format_command(command_line, filename, contents) + + +def _invoke_format_command(command_line, filename, contents): + proc = subprocess.Popen( + command_line, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + stdout_output, stderr_output = proc.communicate(input=contents) + exit_code = proc.wait() + + return StyleFormatResult( + stdout_output=stdout_output, + stderr_output=stderr_output, + exit_code=exit_code, + filename=filename) + + +class StyleFormatResult(object): + def __init__(self, stdout_output, stderr_output, exit_code, filename): + self._stdout_output = stdout_output + self._stderr_output = stderr_output + self._exit_code = exit_code + self._filename = filename + + @property + def did_succeed(self): + return self._exit_code == 0 + + @property + def contents(self): + assert self.did_succeed + return self._stdout_output + + @property + def error_message(self): + return self._stderr_output + + @property + def filename(self): + return self._filename diff --git a/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py new file mode 100644 index 00000000000..18c9d64f92d --- /dev/null +++ b/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/union.py @@ -0,0 +1,188 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os.path + +import web_idl + +from . import name_style +from .blink_v8_bridge import blink_type_info +from .code_node import ListNode +from .code_node import TextNode +from .code_node_cxx import CxxClassDefNode +from .code_node_cxx import CxxFuncDeclNode +from .code_node_cxx import CxxNamespaceNode +from .codegen_accumulator import CodeGenAccumulator +from .codegen_context import CodeGenContext +from .codegen_format import format_template as _format +from .codegen_utils import component_export +from .codegen_utils import enclose_with_header_guard +from .codegen_utils import make_copyright_header +from .codegen_utils import make_forward_declarations +from .codegen_utils import make_header_include_directives +from .codegen_utils import write_code_node_to_file +from .mako_renderer import MakoRenderer +from .path_manager import PathManager + + +def _member_type_name(idl_type): + assert isinstance(idl_type, web_idl.IdlType) + + class MemberTypeName(object): + def __init__(self, idl_type): + type_name = idl_type.type_name + self.old_is_api = name_style.func("Is", type_name) + self.old_get_api = name_style.func("GetAs", type_name) + self.old_set_api = name_style.func("Set", type_name) + # C++ data member that holds a union member. The prefix "um" + # stands for "Union Member." + self.member_var = name_style.member_var("um", type_name) + + return MemberTypeName(idl_type) + + +def make_union_constructor_defs(cg_context): + assert isinstance(cg_context, CodeGenContext) + + class_name = cg_context.class_name + + return ListNode([ + CxxFuncDeclNode( + name=class_name, arg_decls=[], return_type="", default=True), + CxxFuncDeclNode( + name=class_name, + arg_decls=["const ${class_name}&"], + return_type="", + default=True), + CxxFuncDeclNode( + name=class_name, + arg_decls=["${class_name}&&"], + return_type="", + default=True), + CxxFuncDeclNode( + name="~${class_name}", + arg_decls=[], + return_type="", + override=True, + default=True), + ]) + + +def make_union_member_type_enum(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) + + union = cg_context.union + node = ListNode() + enum_members = ListNode(separator=", ") + + node.extend([ + T("enum class MemberType {"), + enum_members, + T("};"), + T("MemberType active_member_type_ = MemberType::kEmpty;"), + ]) + + enum_members.append(T("kEmpty")) + for idl_type in union.flattened_member_types: + enum_members.append(T(name_style.constant(idl_type.type_name))) + if union.does_include_nullable_type: + enum_members.append(T("kNull")) + + return node + + +def make_union_member_vars(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + F = lambda *args, **kwargs: T(_format(*args, **kwargs)) + + union = cg_context.union + node = ListNode() + + node.append( + T("""\ +// C++ data members that hold union members. The prefix "um" stands +// for "Union Member."\ +""")) + for idl_type in union.flattened_member_types: + _1 = blink_type_info(idl_type).member_t + _2 = _member_type_name(idl_type).member_var + node.append(F("{_1} {_2};", _1=_1, _2=_2)) + + return node + + +def make_union_class_def(cg_context): + assert isinstance(cg_context, CodeGenContext) + + T = TextNode + + union = cg_context.union + component = union.components[0] + + class_def = CxxClassDefNode( + cg_context.class_name, export=component_export(component)) + class_def.set_base_template_vars(cg_context.template_bindings()) + + public_section = class_def.public_section + public_section.extend([ + make_union_constructor_defs(cg_context), + T(""), + CxxFuncDeclNode( + name="Trace", arg_decls=["Visitor*"], return_type="void"), + ]) + + class_def.private_section.extend([ + make_union_member_type_enum(cg_context), + T(""), + make_union_member_vars(cg_context), + ]) + + return class_def + + +def generate_union(union): + path_manager = PathManager(union) + class_name = union.identifier + cg_context = CodeGenContext(union=union, class_name=class_name) + + filename = "union_example.h" + header_path = path_manager.api_path(filename=filename) + + header_node = ListNode(tail="\n") + header_node.set_accumulator(CodeGenAccumulator()) + header_node.set_renderer(MakoRenderer()) + + header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) + + class_def = make_union_class_def(cg_context) + + header_node.extend([ + make_copyright_header(), + TextNode(""), + enclose_with_header_guard( + ListNode([ + make_header_include_directives(header_node.accumulator), + TextNode(""), + header_blink_ns, + ]), name_style.header_guard(header_path)), + ]) + header_blink_ns.body.extend([ + make_forward_declarations(header_node.accumulator), + TextNode(""), + ]) + + header_blink_ns.body.append(class_def) + + # Write down to the files. + write_code_node_to_file(header_node, path_manager.gen_path_to(header_path)) + + +def generate_unions(web_idl_database): + union = list(web_idl_database.union_types)[0] + generate_union(union) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_lexer.py b/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_lexer.py index c14b1451115..d041f1dc23f 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_lexer.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_lexer.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Lexer for Blink IDL. The lexer uses the PLY (Python Lex-Yacc) library to build a tokenizer which @@ -54,12 +53,15 @@ http://www.chromium.org/developers/design-documents/idl-compiler#TOC-Front-end # Disable attribute validation, as lint can't import parent class to check # pylint: disable=E1101 +from __future__ import print_function + import os.path import sys # PLY is in Chromium src/third_party/ply module_path, module_name = os.path.split(__file__) -third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir) +third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, + os.pardir) # Insert at front to override system libraries, and after path[0] == script dir sys.path.insert(1, third_party) from ply import lex @@ -73,7 +75,10 @@ LEXTAB = 'lextab' class BlinkIDLLexer(IDLLexer): - def __init__(self, debug=False, optimize=True, outputdir=None, + def __init__(self, + debug=False, + optimize=True, + outputdir=None, rewrite_tables=False): if debug: # Turn off optimization and caching to help debugging @@ -103,21 +108,23 @@ class BlinkIDLLexer(IDLLexer): # error checking), and also allows use of Python's optimized mode. # See: Optimized Mode # http://www.dabeaz.com/ply/ply.html#ply_nn15 - self._lexobj = lex.lex(object=self, - debug=debug, - optimize=optimize, - lextab=lextab, - outputdir=outputdir) + self._lexobj = lex.lex( + object=self, + debug=debug, + optimize=optimize, + lextab=lextab, + outputdir=outputdir) ################################################################################ + def main(argv): # If file itself executed, build and cache lex table try: outputdir = argv[1] except IndexError as err: - print 'Usage: %s OUTPUT_DIR' % argv[0] + print('Usage: %s OUTPUT_DIR' % argv[0]) return 1 # Important: rewrite_tables=True causes the cache file to be deleted if it # exists, thus making sure that PLY doesn't load it instead of regenerating diff --git a/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser.py b/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser.py index a0c2054f7ff..0361deed5df 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Parser for Blink IDL. The parser uses the PLY (Python Lex-Yacc) library to build a set of parsing @@ -55,18 +54,22 @@ http://www.chromium.org/developers/design-documents/idl-compiler#TOC-Front-end # pylint: disable=E1101 # +from __future__ import print_function + import os.path import sys # PLY is in Chromium src/third_party/ply module_path, module_name = os.path.split(__file__) -third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir) +third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, + os.pardir) # Insert at front to override system libraries, and after path[0] == script dir sys.path.insert(1, third_party) from ply import yacc # Base parser is in Chromium src/tools/idl_parser -tools_dir = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir, 'tools') +tools_dir = os.path.join(module_path, os.pardir, os.pardir, os.pardir, + os.pardir, os.pardir, 'tools') sys.path.append(tools_dir) from idl_parser.idl_parser import IDLParser # pylint: disable=import-error from idl_parser.idl_parser import ParseFile as parse_file @@ -76,16 +79,21 @@ import blink_idl_lexer class BlinkIDLParser(IDLParser): - def __init__(self, - # common parameters - debug=False, - # local parameters - rewrite_tables=False, - # idl_parser parameters - lexer=None, verbose=False, mute_error=False, - # yacc parameters - outputdir='', optimize=True, write_tables=False, - picklefile=None): + def __init__( + self, + # common parameters + debug=False, + # local parameters + rewrite_tables=False, + # idl_parser parameters + lexer=None, + verbose=False, + mute_error=False, + # yacc parameters + outputdir='', + optimize=True, + write_tables=False, + picklefile=None): if debug: # Turn off optimization and caching, and write out tables, # to help debugging @@ -94,16 +102,16 @@ class BlinkIDLParser(IDLParser): picklefile = None write_tables = True if outputdir: - picklefile = picklefile or os.path.join(outputdir, 'parsetab.pickle') + picklefile = picklefile or os.path.join(outputdir, + 'parsetab.pickle') if rewrite_tables: try: os.unlink(picklefile) except OSError: pass - lexer = lexer or BlinkIDLLexer(debug=debug, - outputdir=outputdir, - optimize=optimize) + lexer = lexer or BlinkIDLLexer( + debug=debug, outputdir=outputdir, optimize=optimize) self.lexer = lexer self.tokens = lexer.KnownTokens() # Optimized mode substantially decreases startup time (by disabling @@ -115,11 +123,12 @@ class BlinkIDLParser(IDLParser): # as we don't need to modify sys.path; virtually identical speed. # See: CHANGES, Version 3.2 # http://ply.googlecode.com/svn/trunk/CHANGES - self.yaccobj = yacc.yacc(module=self, - debug=debug, - optimize=optimize, - write_tables=write_tables, - picklefile=picklefile) + self.yaccobj = yacc.yacc( + module=self, + debug=debug, + optimize=optimize, + write_tables=write_tables, + picklefile=picklefile) # See IDLParser.__init__() why we set defaulted_states. self.yaccobj.defaulted_states = {} self.parse_debug = debug @@ -134,12 +143,13 @@ class BlinkIDLParser(IDLParser): ################################################################################ + def main(argv): # If file itself executed, cache lex/parse tables try: outputdir = argv[1] except IndexError as err: - print 'Usage: %s OUTPUT_DIR' % argv[0] + print('Usage: %s OUTPUT_DIR' % argv[0]) return 1 blink_idl_lexer.main(argv) # Important: rewrite_tables=True causes the cache file to be deleted if it diff --git a/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser_test.py b/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser_test.py index 309b463dba9..df0719c519e 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser_test.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/blink_idl_parser_test.py @@ -3,7 +3,6 @@ # found in the LICENSE file. # pylint: disable=no-member,relative-import - """Unit tests for blink_idl_parser.py.""" import unittest @@ -12,7 +11,6 @@ from blink_idl_parser import BlinkIDLParser class BlinkIDLParserTest(unittest.TestCase): - def test_missing_semicolon_between_definitions(self): # No semicolon after enum definition. text = '''enum TestEnum { "value" } dictionary TestDictionary {};''' diff --git a/chromium/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py b/chromium/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py index a277ddb0ccb..3629e9c51ba 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py @@ -1,7 +1,6 @@ # Copyright 2019 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """ Builds Web IDL database. @@ -17,11 +16,13 @@ import web_idl def parse_options(): parser = optparse.OptionParser() - parser.add_option('--output', type='string', - help="filepath of the resulting database") - parser.add_option('--runtime_enabled_features', type='string', - action='append', - help="filepath to runtime_enabled_features.json5") + parser.add_option( + '--output', type='string', help="filepath of the resulting database") + parser.add_option( + '--runtime_enabled_features', + type='string', + action='append', + help="filepath to runtime_enabled_features.json5") options, args = parser.parse_args() required_option_names = ('output', 'runtime_enabled_features') @@ -47,8 +48,8 @@ def main(): was_error_reported[0] = True sys.stderr.writelines([message, "\n"]) - database = web_idl.build_database(filepaths=filepaths, - report_error=report_error) + database = web_idl.build_database( + filepaths=filepaths, report_error=report_error) if was_error_reported[0]: sys.exit("Aborted due to error.") diff --git a/chromium/third_party/blink/renderer/bindings/scripts/code_generator.py b/chromium/third_party/blink/renderer/bindings/scripts/code_generator.py index 1905aa85e5a..adbc4876d97 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/code_generator.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/code_generator.py @@ -3,9 +3,10 @@ # found in the LICENSE file. # pylint: disable=import-error,print-statement,relative-import - """Plumbing for a Jinja-based code generator, including CodeGeneratorBase, a base class for all generators.""" +from __future__ import print_function + import os import posixpath import re @@ -17,9 +18,10 @@ from v8_interface import constant_filters from v8_types import set_component_dirs from v8_methods import method_filters from v8_utilities import capitalize -from utilities import (idl_filename_to_component, is_valid_component_dependency, - format_remove_duplicates, format_blink_cpp_source_code, - to_snake_case, normalize_path) +from utilities import (idl_filename_to_component, + is_valid_component_dependency, format_remove_duplicates, + format_blink_cpp_source_code, to_snake_case, + normalize_path) import v8_utilities # Path handling for libraries and templates @@ -31,10 +33,10 @@ import v8_utilities # is regenerated, which causes a race condition and breaks concurrent build, # since some compile processes will try to read the partially written cache. MODULE_PATH, _ = os.path.split(os.path.realpath(__file__)) -THIRD_PARTY_DIR = os.path.normpath(os.path.join( - MODULE_PATH, os.pardir, os.pardir, os.pardir, os.pardir)) -TEMPLATES_DIR = os.path.normpath(os.path.join( - MODULE_PATH, os.pardir, 'templates')) +THIRD_PARTY_DIR = os.path.normpath( + os.path.join(MODULE_PATH, os.pardir, os.pardir, os.pardir, os.pardir)) +TEMPLATES_DIR = os.path.normpath( + os.path.join(MODULE_PATH, os.pardir, 'templates')) # jinja2 is in chromium's third_party directory. # Insert at 1 so at front to override system libraries, and @@ -47,15 +49,15 @@ def generate_indented_conditional(code, conditional): # Indent if statement to level of original code indent = re.match(' *', code).group(0) return ('%sif (%s) {\n' % (indent, conditional) + - ' %s\n' % '\n '.join(code.splitlines()) + - '%s}\n' % indent) + ' %s\n' % '\n '.join(code.splitlines()) + '%s}\n' % indent) # [Exposed] def exposed_if(code, exposed_test): if not exposed_test: return code - return generate_indented_conditional(code, 'execution_context && (%s)' % exposed_test) + return generate_indented_conditional( + code, 'execution_context && (%s)' % exposed_test) # [SecureContext] @@ -66,7 +68,9 @@ def secure_context_if(code, secure_context_test): # [RuntimeEnabled] -def origin_trial_enabled_if(code, origin_trial_feature_name, execution_context=None): +def origin_trial_enabled_if(code, + origin_trial_feature_name, + execution_context=None): if not origin_trial_feature_name: return code @@ -94,14 +98,23 @@ def initialize_jinja_env(cache_dir): lstrip_blocks=True, # so can indent control flow tags trim_blocks=True) jinja_env.filters.update({ - 'blink_capitalize': capitalize, - 'exposed': exposed_if, - 'format_blink_cpp_source_code': format_blink_cpp_source_code, - 'format_remove_duplicates': format_remove_duplicates, - 'origin_trial_enabled': origin_trial_enabled_if, - 'runtime_enabled': runtime_enabled_if, - 'runtime_enabled_function': v8_utilities.runtime_enabled_function, - 'secure_context': secure_context_if}) + 'blink_capitalize': + capitalize, + 'exposed': + exposed_if, + 'format_blink_cpp_source_code': + format_blink_cpp_source_code, + 'format_remove_duplicates': + format_remove_duplicates, + 'origin_trial_enabled': + origin_trial_enabled_if, + 'runtime_enabled': + runtime_enabled_if, + 'runtime_enabled_function': + v8_utilities.runtime_enabled_function, + 'secure_context': + secure_context_if + }) jinja_env.filters.update(constant_filters()) jinja_env.filters.update(method_filters()) return jinja_env @@ -109,10 +122,12 @@ def initialize_jinja_env(cache_dir): _BLINK_RELATIVE_PATH_PREFIXES = ('bindings/', 'core/', 'modules/', 'platform/') + def normalize_and_sort_includes(include_paths): normalized_include_paths = set() for include_path in include_paths: - match = re.search(r'/gen/(third_party/blink/.*)$', posixpath.abspath(include_path)) + match = re.search(r'/gen/(third_party/blink/.*)$', + posixpath.abspath(include_path)) if match: include_path = match.group(1) elif include_path.startswith(_BLINK_RELATIVE_PATH_PREFIXES): @@ -133,6 +148,7 @@ def render_template(template, context): class CodeGeneratorBase(object): """Base class for jinja-powered jinja template generation. """ + def __init__(self, generator_name, info_provider, cache_dir, output_dir): self.generator_name = generator_name self.info_provider = info_provider @@ -150,13 +166,19 @@ class CodeGeneratorBase(object): IdlType.set_dictionaries(interfaces_info['dictionaries']) IdlType.set_enums(self.info_provider.enumerations) IdlType.set_callback_functions(self.info_provider.callback_functions) - IdlType.set_implemented_as_interfaces(interfaces_info['implemented_as_interfaces']) - IdlType.set_garbage_collected_types(interfaces_info['garbage_collected_interfaces']) + IdlType.set_implemented_as_interfaces( + interfaces_info['implemented_as_interfaces']) + IdlType.set_garbage_collected_types( + interfaces_info['garbage_collected_interfaces']) IdlType.set_garbage_collected_types(interfaces_info['dictionaries']) set_component_dirs(interfaces_info['component_dirs']) - def render_templates(self, include_paths, header_template, cpp_template, - context, component=None): + def render_templates(self, + include_paths, + header_template, + cpp_template, + context, + component=None): context['code_generator'] = self.generator_name # Add includes for any dependencies @@ -167,8 +189,10 @@ class CodeGeneratorBase(object): includes.add(include_path) cpp_includes = set(context.get('cpp_includes', [])) - context['cpp_includes'] = normalize_and_sort_includes(cpp_includes | includes) - context['header_includes'] = normalize_and_sort_includes(context['header_includes']) + context['cpp_includes'] = normalize_and_sort_includes(cpp_includes + | includes) + context['header_includes'] = normalize_and_sort_includes( + context['header_includes']) header_text = render_template(header_template, context) cpp_text = render_template(cpp_template, context) @@ -194,14 +218,16 @@ def main(argv): cache_dir = argv[1] dummy_filename = argv[2] except IndexError: - print 'Usage: %s CACHE_DIR DUMMY_FILENAME' % argv[0] + print('Usage: %s CACHE_DIR DUMMY_FILENAME' % argv[0]) return 1 # Cache templates jinja_env = initialize_jinja_env(cache_dir) - template_filenames = [filename for filename in os.listdir(TEMPLATES_DIR) - # Skip .svn, directories, etc. - if filename.endswith(('.tmpl', '.txt'))] + template_filenames = [ + filename for filename in os.listdir(TEMPLATES_DIR) + # Skip .svn, directories, etc. + if filename.endswith(('.tmpl', '.txt')) + ] for template_filename in template_filenames: jinja_env.get_template(template_filename) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/code_generator_v8.py b/chromium/third_party/blink/renderer/bindings/scripts/code_generator_v8.py index 95564bab6e8..f296d486a3c 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/code_generator_v8.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/code_generator_v8.py @@ -27,7 +27,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # pylint: disable=import-error,print-statement,relative-import - """Generate Blink V8 bindings (.h and .cpp files). If run itself, caches Jinja templates (and creates dummy file for build, @@ -61,14 +60,15 @@ import v8_union from v8_utilities import build_basename, cpp_name from utilities import idl_filename_to_component, is_testing_target, shorten_union_name, to_header_guard, to_snake_case - # Make sure extension is .py, not .pyc or .pyo, so doesn't depend on caching MODULE_PYNAME = os.path.splitext(os.path.basename(__file__))[0] + '.py' + def depending_union_type(idl_type): """Returns the union type name if the given idl_type depends on a union type. """ + def find_base_type(current_type): if current_type.is_array_or_sequence_type: return find_base_type(current_type.element_type) @@ -79,6 +79,7 @@ def depending_union_type(idl_type): if current_type.is_nullable: return find_base_type(current_type.inner_type) return current_type + base_type = find_base_type(idl_type) if base_type.is_union_type: return base_type @@ -94,7 +95,7 @@ class TypedefResolver(Visitor): def resolve(self, definitions, definition_name): """Traverse definitions and resolves typedefs with the actual types.""" self.typedefs = {} - for name, typedef in self.info_provider.typedefs.iteritems(): + for name, typedef in self.info_provider.typedefs.items(): self.typedefs[name] = typedef.idl_type self.additional_header_includes = set() definitions.accept(self) @@ -122,7 +123,8 @@ class TypedefResolver(Visitor): union_type = depending_union_type(resolved_idl_type) if union_type: self.additional_header_includes.add( - self.info_provider.include_path_for_union_types(union_type)) + self.info_provider.include_path_for_union_types( + union_type)) # Need to re-assign the attribute, not just mutate idl_type, since # type(idl_type) may change. setattr(typed_object, attribute_name, resolved_idl_type) @@ -135,7 +137,8 @@ class CodeGeneratorV8Base(CodeGeneratorBase): """Base class for v8 bindings generator and IDL dictionary impl generator""" def __init__(self, info_provider, cache_dir, output_dir): - CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir) + CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, + cache_dir, output_dir) self.typedef_resolver = TypedefResolver(info_provider) def generate_code(self, definitions, definition_name): @@ -158,13 +161,16 @@ class CodeGeneratorV8Base(CodeGeneratorBase): class CodeGeneratorV8(CodeGeneratorV8Base): def __init__(self, info_provider, cache_dir, output_dir): - CodeGeneratorV8Base.__init__(self, info_provider, cache_dir, output_dir) + CodeGeneratorV8Base.__init__(self, info_provider, cache_dir, + output_dir) def output_paths(self, definition_name): - header_path = posixpath.join(self.output_dir, self.get_output_filename( - definition_name, '.h', prefix='v8_')) - cpp_path = posixpath.join(self.output_dir, self.get_output_filename( - definition_name, '.cc', prefix='v8_')) + header_path = posixpath.join( + self.output_dir, + self.get_output_filename(definition_name, '.h', prefix='v8_')) + cpp_path = posixpath.join( + self.output_dir, + self.get_output_filename(definition_name, '.cc', prefix='v8_')) return header_path, cpp_path def generate_code_internal(self, definitions, definition_name): @@ -196,31 +202,39 @@ class CodeGeneratorV8(CodeGeneratorV8Base): interface_name += 'Partial' assert component == 'core' component = 'modules' - include_paths = interface_info.get('dependencies_other_component_include_paths') + include_paths = interface_info.get( + 'dependencies_other_component_include_paths') else: header_template_filename = 'interface.h.tmpl' cpp_template_filename = 'interface.cc.tmpl' interface_context = v8_interface.interface_context component_info = self.info_provider.component_info - template_context = interface_context(interface, definitions.interfaces, component_info) - includes.update(interface_info.get('cpp_includes', {}).get(component, set())) + template_context = interface_context(interface, definitions.interfaces, + component_info) + includes.update( + interface_info.get('cpp_includes', {}).get(component, set())) if not interface.is_partial and not is_testing_target(full_path): - template_context['header_includes'].add(self.info_provider.include_path_for_export) - template_context['exported'] = self.info_provider.specifier_for_export + template_context['header_includes'].add( + self.info_provider.include_path_for_export) + template_context['exported'] = \ + self.info_provider.specifier_for_export # Add the include for interface itself if IdlType(interface_name).is_typed_array: - template_context['header_includes'].add('core/typed_arrays/dom_typed_array.h') + template_context['header_includes'].add( + 'core/typed_arrays/dom_typed_array.h') elif interface.is_callback: pass else: - template_context['header_includes'].add(interface_info['include_path']) + template_context['header_includes'].add( + interface_info['include_path']) template_context['header_includes'].update( interface_info.get('additional_header_includes', [])) header_path, cpp_path = self.output_paths(interface_name) this_include_header_path = self.normalize_this_header_path(header_path) template_context['this_include_header_path'] = this_include_header_path - template_context['header_guard'] = to_header_guard(this_include_header_path) + template_context['header_guard'] = to_header_guard( + this_include_header_path) header_template = self.jinja_env.get_template(header_template_filename) cpp_template = self.jinja_env.get_template(cpp_template_filename) header_text, cpp_text = self.render_templates( @@ -245,12 +259,15 @@ class CodeGeneratorV8(CodeGeneratorV8Base): # Add the include for interface itself template_context['header_includes'].add(interface_info['include_path']) if not is_testing_target(interface_info.get('full_path')): - template_context['header_includes'].add(self.info_provider.include_path_for_export) - template_context['exported'] = self.info_provider.specifier_for_export + template_context['header_includes'].add( + self.info_provider.include_path_for_export) + template_context['exported'] = \ + self.info_provider.specifier_for_export header_path, cpp_path = self.output_paths(dictionary_name) this_include_header_path = self.normalize_this_header_path(header_path) template_context['this_include_header_path'] = this_include_header_path - template_context['header_guard'] = to_header_guard(this_include_header_path) + template_context['header_guard'] = to_header_guard( + this_include_header_path) header_text, cpp_text = self.render_templates( include_paths, header_template, cpp_template, template_context) return ( @@ -261,15 +278,16 @@ class CodeGeneratorV8(CodeGeneratorV8Base): class CodeGeneratorDictionaryImpl(CodeGeneratorV8Base): def __init__(self, info_provider, cache_dir, output_dir): - CodeGeneratorV8Base.__init__(self, info_provider, cache_dir, output_dir) + CodeGeneratorV8Base.__init__(self, info_provider, cache_dir, + output_dir) def output_paths(self, definition_name, interface_info): output_dir = posixpath.join(self.output_dir, interface_info['relative_dir']) - header_path = posixpath.join(output_dir, - self.get_output_filename(definition_name, '.h')) - cpp_path = posixpath.join(output_dir, - self.get_output_filename(definition_name, '.cc')) + header_path = posixpath.join( + output_dir, self.get_output_filename(definition_name, '.h')) + cpp_path = posixpath.join( + output_dir, self.get_output_filename(definition_name, '.cc')) return header_path, cpp_path def generate_code_internal(self, definitions, definition_name): @@ -284,14 +302,18 @@ class CodeGeneratorDictionaryImpl(CodeGeneratorV8Base): dictionary, interfaces_info) include_paths = interface_info.get('dependencies_include_paths') if not is_testing_target(interface_info.get('full_path')): - template_context['exported'] = self.info_provider.specifier_for_export - template_context['header_includes'].add(self.info_provider.include_path_for_export) + template_context['exported'] = \ + self.info_provider.specifier_for_export + template_context['header_includes'].add( + self.info_provider.include_path_for_export) template_context['header_includes'].update( interface_info.get('additional_header_includes', [])) - header_path, cpp_path = self.output_paths(definition_name, interface_info) + header_path, cpp_path = self.output_paths(definition_name, + interface_info) this_include_header_path = self.normalize_this_header_path(header_path) template_context['this_include_header_path'] = this_include_header_path - template_context['header_guard'] = to_header_guard(this_include_header_path) + template_context['header_guard'] = to_header_guard( + this_include_header_path) header_text, cpp_text = self.render_templates( include_paths, header_template, cpp_template, template_context) return ( @@ -306,15 +328,17 @@ class CodeGeneratorUnionType(CodeGeneratorBase): CodeGeneratorDictionaryImpl. It assumes that all union types are already collected. It doesn't process idl files directly. """ + def __init__(self, info_provider, cache_dir, output_dir, target_component): - CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir) + CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, + cache_dir, output_dir) self.target_component = target_component # The code below duplicates parts of TypedefResolver. We do not use it # directly because IdlUnionType is not a type defined in # idl_definitions.py. What we do instead is to resolve typedefs in # _generate_container_code() whenever a new union file is generated. self.typedefs = {} - for name, typedef in self.info_provider.typedefs.iteritems(): + for name, typedef in self.info_provider.typedefs.items(): self.typedefs[name] = typedef.idl_type def _generate_container_code(self, union_type): @@ -322,7 +346,8 @@ class CodeGeneratorUnionType(CodeGeneratorBase): union_type = union_type.resolve_typedefs(self.typedefs) header_template = self.jinja_env.get_template('union_container.h.tmpl') cpp_template = self.jinja_env.get_template('union_container.cc.tmpl') - template_context = v8_union.container_context(union_type, self.info_provider) + template_context = v8_union.container_context(union_type, + self.info_provider) template_context['header_includes'].append( self.info_provider.include_path_for_export) template_context['exported'] = self.info_provider.specifier_for_export @@ -331,7 +356,8 @@ class CodeGeneratorUnionType(CodeGeneratorBase): cpp_path = posixpath.join(self.output_dir, '%s.cc' % snake_base_name) this_include_header_path = self.normalize_this_header_path(header_path) template_context['this_include_header_path'] = this_include_header_path - template_context['header_guard'] = to_header_guard(this_include_header_path) + template_context['header_guard'] = to_header_guard( + this_include_header_path) header_text, cpp_text = self.render_templates( [], header_template, cpp_template, template_context) return ( @@ -368,18 +394,22 @@ class CodeGeneratorUnionType(CodeGeneratorBase): class CodeGeneratorCallbackFunction(CodeGeneratorBase): def __init__(self, info_provider, cache_dir, output_dir, target_component): - CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir) + CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, + cache_dir, output_dir) self.target_component = target_component self.typedef_resolver = TypedefResolver(info_provider) def generate_code_internal(self, callback_function, path): - self.typedef_resolver.resolve(callback_function, callback_function.name) - header_template = self.jinja_env.get_template('callback_function.h.tmpl') + self.typedef_resolver.resolve(callback_function, + callback_function.name) + header_template = self.jinja_env.get_template( + 'callback_function.h.tmpl') cpp_template = self.jinja_env.get_template('callback_function.cc.tmpl') template_context = v8_callback_function.callback_function_context( callback_function) if not is_testing_target(path): - template_context['exported'] = self.info_provider.specifier_for_export + template_context['exported'] = \ + self.info_provider.specifier_for_export template_context['header_includes'].append( self.info_provider.include_path_for_export) @@ -388,14 +418,16 @@ class CodeGeneratorCallbackFunction(CodeGeneratorBase): for argument in callback_function.arguments: if argument.idl_type.is_union_type: template_context['header_includes'].append( - self.info_provider.include_path_for_union_types(argument.idl_type)) + self.info_provider.include_path_for_union_types( + argument.idl_type)) snake_base_name = to_snake_case('V8%s' % callback_function.name) header_path = posixpath.join(self.output_dir, '%s.h' % snake_base_name) cpp_path = posixpath.join(self.output_dir, '%s.cc' % snake_base_name) this_include_header_path = self.normalize_this_header_path(header_path) template_context['this_include_header_path'] = this_include_header_path - template_context['header_guard'] = to_header_guard(this_include_header_path) + template_context['header_guard'] = to_header_guard( + this_include_header_path) header_text, cpp_text = self.render_templates( [], header_template, cpp_template, template_context) return ( @@ -409,12 +441,13 @@ class CodeGeneratorCallbackFunction(CodeGeneratorBase): if not callback_functions: return () outputs = set() - for callback_function_dict in callback_functions.itervalues(): + for callback_function_dict in callback_functions.values(): if callback_function_dict['component_dir'] != self.target_component: continue callback_function = callback_function_dict['callback_function'] if 'Custom' in callback_function.extended_attributes: continue path = callback_function_dict['full_path'] - outputs.update(self.generate_code_internal(callback_function, path)) + outputs.update( + self.generate_code_internal(callback_function, path)) return outputs diff --git a/chromium/third_party/blink/renderer/bindings/scripts/collect_idl_files.py b/chromium/third_party/blink/renderer/bindings/scripts/collect_idl_files.py index c6922e536fc..082a545fc51 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/collect_idl_files.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/collect_idl_files.py @@ -1,7 +1,6 @@ # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """ Collects Web IDL definitions in IDL files into a Python object per Blink component. @@ -16,18 +15,21 @@ import blink_idl_parser import utilities import web_idl - _VALID_COMPONENTS = ('core', 'modules') def parse_options(): parser = optparse.OptionParser() - parser.add_option('--idl-list-file', type='string', - help="a file path which lists IDL file paths to process") - parser.add_option('--component', type='choice', choices=_VALID_COMPONENTS, - help="specify a component name") - parser.add_option('--output', type='string', - help="the output file path") + parser.add_option( + '--idl-list-file', + type='string', + help="a file path which lists IDL file paths to process") + parser.add_option( + '--component', + type='choice', + choices=_VALID_COMPONENTS, + help="specify a component name") + parser.add_option('--output', type='string', help="the output file path") options, args = parser.parse_args() if options.idl_list_file is None: diff --git a/chromium/third_party/blink/renderer/bindings/scripts/compute_global_objects.py b/chromium/third_party/blink/renderer/bindings/scripts/compute_global_objects.py index 78d74f825be..7fa1c022a15 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/compute_global_objects.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/compute_global_objects.py @@ -3,7 +3,6 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Compute global objects. Global objects are defined by interfaces with [Global] on @@ -30,13 +29,16 @@ def parse_options(): usage = 'Usage: %prog [options] [GlobalObjects.pickle]' parser = optparse.OptionParser(usage=usage) parser.add_option('--idl-files-list', help='file listing IDL files') - parser.add_option('--global-objects-component-files', action='append', - help='optionally preceeded input pickle filename.') + parser.add_option( + '--global-objects-component-files', + action='append', + help='optionally preceeded input pickle filename.') options, args = parser.parse_args() if options.idl_files_list is None: - parser.error('Must specify a file listing IDL files using --idl-files-list.') + parser.error( + 'Must specify a file listing IDL files using --idl-files-list.') if options.global_objects_component_files is None: options.global_objects_component_files = [] if len(args) != 1: @@ -46,7 +48,7 @@ def parse_options(): def dict_union(dicts): - return dict((k, v) for d in dicts for k, v in d.iteritems()) + return dict((k, v) for d in dicts for k, v in d.items()) def idl_file_to_global_names(idl_filename): @@ -58,22 +60,25 @@ def idl_file_to_global_names(idl_filename): """ full_path = os.path.realpath(idl_filename) idl_file_contents = get_file_contents(full_path) - extended_attributes = get_interface_extended_attributes_from_idl(idl_file_contents) + extended_attributes = get_interface_extended_attributes_from_idl( + idl_file_contents) interface_name = get_first_interface_name_from_idl(idl_file_contents) if 'Global' not in extended_attributes: return global_value = extended_attributes['Global'] if not global_value: - raise ValueError('[Global] must take an indentifier or an identifier list.\n' + - full_path) + raise ValueError( + '[Global] must take an indentifier or an identifier list.\n' + + full_path) return map(str.strip, global_value.strip('()').split(',')) def idl_files_to_interface_name_global_names(idl_files): """Yields pairs (interface_name, global_names) found in IDL files.""" for idl_filename in idl_files: - interface_name = get_first_interface_name_from_idl(get_file_contents(idl_filename)) + interface_name = get_first_interface_name_from_idl( + get_file_contents(idl_filename)) global_names = idl_file_to_global_names(idl_filename) if global_names: yield interface_name, global_names @@ -81,19 +86,20 @@ def idl_files_to_interface_name_global_names(idl_files): ################################################################################ + def main(): options, args = parse_options() output_global_objects_filename = args.pop() interface_name_global_names = dict_union( existing_interface_name_global_names - for existing_interface_name_global_names - in read_pickle_files(options.global_objects_component_files)) + for existing_interface_name_global_names in read_pickle_files( + options.global_objects_component_files)) # File paths of input IDL files are passed in a file, which is generated at # GN time. It is OK because the target IDL files themselves are static. idl_files = read_file_to_list(options.idl_files_list) interface_name_global_names.update( - idl_files_to_interface_name_global_names(idl_files)) + idl_files_to_interface_name_global_names(idl_files)) write_pickle_file(output_global_objects_filename, interface_name_global_names) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py b/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py index 4930013a526..01c23ba15f7 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py @@ -27,7 +27,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Compute global interface information for individual IDL files. Auxiliary module for compute_interfaces_info_overall, which consolidates @@ -58,7 +57,6 @@ from utilities import to_snake_case from utilities import read_pickle_file from utilities import write_pickle_file - module_path = os.path.dirname(__file__) source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir)) gen_path = os.path.join('gen', 'blink') @@ -74,15 +72,21 @@ def parse_options(): parser = optparse.OptionParser(usage=usage) parser.add_option('--cache-directory', help='cache directory') parser.add_option('--idl-files-list', help='file listing IDL files') - parser.add_option('--interfaces-info-file', help='interface info pickle file') - parser.add_option('--component-info-file', help='component wide info pickle file') - parser.add_option('--runtime-enabled-features-file', help='runtime-enabled features pickle file') + parser.add_option( + '--interfaces-info-file', help='interface info pickle file') + parser.add_option( + '--component-info-file', help='component wide info pickle file') + parser.add_option( + '--runtime-enabled-features-file', + help='runtime-enabled features pickle file') options, args = parser.parse_args() if options.interfaces_info_file is None: - parser.error('Must specify an output file using --interfaces-info-file.') + parser.error( + 'Must specify an output file using --interfaces-info-file.') if options.idl_files_list is None: - parser.error('Must specify a file listing IDL files using --idl-files-list.') + parser.error( + 'Must specify a file listing IDL files using --idl-files-list.') return options, args @@ -90,6 +94,7 @@ def parse_options(): # Computations ################################################################################ + def relative_dir_posix(idl_filename, base_path): """Returns relative path to the directory of idl_file in POSIX format.""" relative_path_local = os.path.relpath(idl_filename, base_path) @@ -109,7 +114,8 @@ def include_path(idl_filename, implemented_as=None): relative_dir = relative_dir_posix(idl_filename, source_path) # IDL file basename is used even if only a partial interface file - output_file_basename = implemented_as or idl_filename_to_basename(idl_filename) + output_file_basename = implemented_as or idl_filename_to_basename( + idl_filename) output_file_basename = to_snake_case(output_file_basename) return posixpath.join(relative_dir, output_file_basename + '.h') @@ -133,9 +139,9 @@ def get_includes_from_definitions(definitions, definition_name): def get_put_forward_interfaces_from_definition(definition): - return sorted(set(attribute.idl_type.base_type - for attribute in definition.attributes - if 'PutForwards' in attribute.extended_attributes)) + return sorted( + set(attribute.idl_type.base_type for attribute in definition.attributes + if 'PutForwards' in attribute.extended_attributes)) def get_unforgeable_attributes_from_definition(definition): @@ -145,6 +151,7 @@ def get_unforgeable_attributes_from_definition(definition): def collect_union_types_from_definitions(definitions): """Traverse definitions and collect all union types.""" + class UnionTypeCollector(Visitor): def collect(self, definitions): self._union_types = set() @@ -165,13 +172,14 @@ def collect_union_types_from_definitions(definitions): class InterfaceInfoCollector(object): """A class that collects interface information from idl files.""" + def __init__(self, cache_directory=None): - self.reader = IdlReader(interfaces_info=None, outputdir=cache_directory) + self.reader = IdlReader( + interfaces_info=None, outputdir=cache_directory) self.interfaces_info = {} self.partial_interface_files = defaultdict(lambda: { 'full_paths': [], - 'include_paths': [], - }) + 'include_paths': [], }) self.enumerations = {} self.union_types = set() self.typedefs = {} @@ -196,6 +204,7 @@ class InterfaceInfoCollector(object): def collect_info(self, idl_filename): """Reads an idl file and collects information which is required by the binding code generation.""" + def collect_unforgeable_attributes(definition, idl_filename): """Collects [Unforgeable] attributes so that we can define them on sub-interfaces later. The resulting structure is as follows. @@ -205,17 +214,21 @@ class InterfaceInfoCollector(object): } """ interface_info = {} - unforgeable_attributes = get_unforgeable_attributes_from_definition(definition) + unforgeable_attributes = get_unforgeable_attributes_from_definition( + definition) if not unforgeable_attributes: return interface_info if definition.is_partial: - interface_basename = idl_filename_to_interface_name(idl_filename) + interface_basename = idl_filename_to_interface_name( + idl_filename) # TODO(yukishiino): [PartialInterfaceImplementedAs] is treated # in interface_dependency_resolver.transfer_extended_attributes. # Come up with a better way to keep them consistent. for attr in unforgeable_attributes: - attr.extended_attributes['PartialInterfaceImplementedAs'] = definition.extended_attributes.get('ImplementedAs', interface_basename) + attr.extended_attributes[ + 'PartialInterfaceImplementedAs'] = definition.extended_attributes.get( + 'ImplementedAs', interface_basename) interface_info['unforgeable_attributes'] = unforgeable_attributes return interface_info @@ -224,7 +237,8 @@ class InterfaceInfoCollector(object): this_union_types = collect_union_types_from_definitions(definitions) self.union_types.update(this_union_types) self.typedefs.update(definitions.typedefs) - for callback_function_name, callback_function in definitions.callback_functions.iteritems(): + for callback_function_name, callback_function in \ + definitions.callback_functions.items(): # Set 'component_dir' to specify a directory that callback function files belong to self.callback_functions[callback_function_name] = { 'callback_function': callback_function, @@ -239,10 +253,12 @@ class InterfaceInfoCollector(object): self.enumerations.update(definitions.enumerations) if definitions.interfaces: - definition = next(definitions.interfaces.itervalues()) + definition = next(iter(definitions.interfaces.values())) interface_info = { - 'is_callback_interface': definition.is_callback, - 'is_dictionary': False, + 'is_callback_interface': + definition.is_callback, + 'is_dictionary': + False, # Interfaces that are referenced (used as types) and that we # introspect during code generation (beyond interface-level # data ([ImplementedAs], is_callback_interface, ancestors, and @@ -250,10 +266,11 @@ class InterfaceInfoCollector(object): # These cause rebuilds of referrers, due to the dependency, # so these should be minimized; currently only targets of # [PutForwards]. - 'referenced_interfaces': get_put_forward_interfaces_from_definition(definition), + 'referenced_interfaces': + get_put_forward_interfaces_from_definition(definition), } elif definitions.dictionaries: - definition = next(definitions.dictionaries.itervalues()) + definition = next(iter(definitions.dictionaries.values())) interface_info = { 'is_callback_interface': False, 'is_dictionary': True, @@ -267,8 +284,9 @@ class InterfaceInfoCollector(object): # Remember [Unforgeable] attributes. if definitions.interfaces: - merge_dict_recursively(self.interfaces_info[definition.name], - collect_unforgeable_attributes(definition, idl_filename)) + merge_dict_recursively( + self.interfaces_info[definition.name], + collect_unforgeable_attributes(definition, idl_filename)) component = idl_filename_to_component(idl_filename) extended_attributes = definition.extended_attributes @@ -284,7 +302,8 @@ class InterfaceInfoCollector(object): partial_include_paths = [] if this_include_path: partial_include_paths.append(this_include_path) - self.add_paths_to_partials_dict(definition.name, full_path, partial_include_paths) + self.add_paths_to_partials_dict(definition.name, full_path, + partial_include_paths) # Collects C++ header paths which should be included from generated # .cpp files. The resulting structure is as follows. # interfaces_info[interface_name] = { @@ -297,7 +316,9 @@ class InterfaceInfoCollector(object): if this_include_path: merge_dict_recursively( self.interfaces_info[definition.name], - {'cpp_includes': {component: set([this_include_path])}}) + {'cpp_includes': { + component: set([this_include_path]) + }}) return # 'includes' statements can be included in either the file for the @@ -307,20 +328,31 @@ class InterfaceInfoCollector(object): definitions, definition.name) interface_info.update({ - 'extended_attributes': extended_attributes, - 'full_path': full_path, - 'union_types': this_union_types, - 'implemented_as': implemented_as, - 'included_by_interfaces': includes_interfaces, - 'including_mixins': includes_mixins, - 'include_path': this_include_path, - # FIXME: temporary private field, while removing old treatement of - # 'implements': http://crbug.com/360435 - 'is_legacy_treat_as_partial_interface': 'LegacyTreatAsPartialInterface' in extended_attributes, - 'parent': definition.parent, - 'relative_dir': relative_dir_posix(idl_filename, source_path), + 'extended_attributes': + extended_attributes, + 'full_path': + full_path, + 'union_types': + this_union_types, + 'implemented_as': + implemented_as, + 'included_by_interfaces': + includes_interfaces, + 'including_mixins': + includes_mixins, + 'include_path': + this_include_path, + # FIXME: temporary private field, while removing old + # treatement of 'implements': http://crbug.com/360435 + 'is_legacy_treat_as_partial_interface': + 'LegacyTreatAsPartialInterface' in extended_attributes, + 'parent': + definition.parent, + 'relative_dir': + relative_dir_posix(idl_filename, source_path), }) - merge_dict_recursively(self.interfaces_info[definition.name], interface_info) + merge_dict_recursively(self.interfaces_info[definition.name], + interface_info) def get_info_as_dict(self): """Returns info packaged as a dict.""" @@ -334,17 +366,23 @@ class InterfaceInfoCollector(object): def get_component_info_as_dict(self, runtime_enabled_features): """Returns component wide information as a dict.""" return { - 'callback_functions': self.callback_functions, - 'enumerations': dict((enum.name, enum.values) - for enum in self.enumerations.values()), - 'runtime_enabled_features': runtime_enabled_features, - 'typedefs': self.typedefs, - 'union_types': self.union_types, + 'callback_functions': + self.callback_functions, + 'enumerations': + dict((enum.name, enum.values) + for enum in self.enumerations.values()), + 'runtime_enabled_features': + runtime_enabled_features, + 'typedefs': + self.typedefs, + 'union_types': + self.union_types, } ################################################################################ + def main(): options, _ = parse_options() @@ -360,9 +398,12 @@ def main(): write_pickle_file(options.interfaces_info_file, info_collector.get_info_as_dict()) - runtime_enabled_features = read_pickle_file(options.runtime_enabled_features_file) - write_pickle_file(options.component_info_file, - info_collector.get_component_info_as_dict(runtime_enabled_features)) + runtime_enabled_features = read_pickle_file( + options.runtime_enabled_features_file) + write_pickle_file( + options.component_info_file, + info_collector.get_component_info_as_dict(runtime_enabled_features)) + if __name__ == '__main__': sys.exit(main()) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py b/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py index a3e0484a1f8..235cf0f914a 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py @@ -27,7 +27,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Compute global interface information, including public information, dependencies, and inheritance. Computed data is stored in a global variable, |interfaces_info|, and written as @@ -104,10 +103,11 @@ interfaces_info = {} # Auxiliary variables (not visible to future build steps) partial_interface_files = defaultdict(lambda: { 'full_paths': [], - 'include_paths': [], -}) + 'include_paths': [], }) parent_interfaces = {} -inherited_extended_attributes_by_interface = {} # interface name -> extended attributes + +# interface name -> extended attributes +inherited_extended_attributes_by_interface = {} class IdlInterfaceFileNotFoundError(Exception): @@ -127,12 +127,12 @@ def dict_of_dicts_of_lists_update_or_append(existing, other): Needed for merging partial_interface_files across components. """ - for key, value in other.iteritems(): + for key, value in other.items(): if key not in existing: existing[key] = value continue existing_value = existing[key] - for inner_key, inner_value in value.iteritems(): + for inner_key, inner_value in value.items(): existing_value[inner_key].extend(inner_value) @@ -140,25 +140,33 @@ def dict_of_dicts_of_lists_update_or_append(existing, other): # Computations ################################################################################ + def compute_inheritance_info(interface_name): - """Compute inheritance information, namely ancestors and inherited extended attributes.""" + """Compute inheritance information, namely ancestors and inherited + extended attributes. + """ + def generate_ancestors(interface_name): while interface_name in parent_interfaces: interface_name = parent_interfaces[interface_name] yield interface_name ancestors = list(generate_ancestors(interface_name)) - inherited_extended_attributes = inherited_extended_attributes_by_interface[interface_name] + inherited_extended_attributes = \ + inherited_extended_attributes_by_interface[interface_name] for ancestor in ancestors: # Ancestors may not be present, notably if an ancestor is a generated # IDL file and we are running this script from run_bindings_tests.py, # where we don't generate these files. - ancestor_extended_attributes = inherited_extended_attributes_by_interface.get(ancestor, {}) + ancestor_extended_attributes = \ + inherited_extended_attributes_by_interface.get(ancestor, {}) inherited_extended_attributes.update(ancestor_extended_attributes) interfaces_info[interface_name].update({ - 'ancestors': ancestors, - 'inherited_extended_attributes': inherited_extended_attributes, + 'ancestors': + ancestors, + 'inherited_extended_attributes': + inherited_extended_attributes, }) @@ -170,8 +178,9 @@ def compute_global_type_info(): garbage_collected_interfaces = set() callback_interfaces = set() - for interface_name, interface_info in interfaces_info.iteritems(): - component_dirs[interface_name] = idl_filename_to_component(interface_info['full_path']) + for interface_name, interface_info in interfaces_info.items(): + component_dirs[interface_name] = idl_filename_to_component( + interface_info['full_path']) if interface_info['ancestors']: ancestors[interface_name] = interface_info['ancestors'] @@ -180,16 +189,19 @@ def compute_global_type_info(): if interface_info['is_dictionary']: dictionaries[interface_name] = interface_info['is_dictionary'] if interface_info['implemented_as']: - implemented_as_interfaces[interface_name] = interface_info['implemented_as'] + implemented_as_interfaces[interface_name] = \ + interface_info['implemented_as'] - inherited_extended_attributes = interface_info['inherited_extended_attributes'] + inherited_extended_attributes = \ + interface_info['inherited_extended_attributes'] garbage_collected_interfaces.add(interface_name) interfaces_info['ancestors'] = ancestors interfaces_info['callback_interfaces'] = callback_interfaces interfaces_info['dictionaries'] = dictionaries interfaces_info['implemented_as_interfaces'] = implemented_as_interfaces - interfaces_info['garbage_collected_interfaces'] = garbage_collected_interfaces + interfaces_info['garbage_collected_interfaces'] = \ + garbage_collected_interfaces interfaces_info['component_dirs'] = component_dirs @@ -205,15 +217,14 @@ def compute_interfaces_info_overall(info_individuals): # partial interfaces are used to *extend* interfaces. # We thus need to update or append if already present dict_of_dicts_of_lists_update_or_append( - partial_interface_files, info['partial_interface_files']) + partial_interface_files, info['partial_interface_files']) # Record inheritance information individually - for interface_name, interface_info in interfaces_info.iteritems(): + for interface_name, interface_info in interfaces_info.items(): extended_attributes = interface_info['extended_attributes'] inherited_extended_attributes_by_interface[interface_name] = dict( - (key, value) - for key, value in extended_attributes.iteritems() - if key in INHERITED_EXTENDED_ATTRIBUTES) + (key, value) for key, value in extended_attributes.items() + if key in INHERITED_EXTENDED_ATTRIBUTES) parent = interface_info['parent'] if parent: parent_interfaces[interface_name] = parent @@ -230,26 +241,32 @@ def compute_interfaces_info_overall(info_individuals): # 'includes'). # Note that moving an 'includes' statement between files does not change the # info itself (or hence cause a rebuild)! - for mixin_name, interface_info in interfaces_info.iteritems(): + for mixin_name, interface_info in interfaces_info.items(): for interface_name in interface_info['included_by_interfaces']: - interfaces_info[interface_name]['including_mixins'].append(mixin_name) + interfaces_info[interface_name]['including_mixins'].append( + mixin_name) del interface_info['included_by_interfaces'] # An IDL file's dependencies are partial interface files that extend it, # and files for other interfaces that this interfaces include. - for interface_name, interface_info in interfaces_info.iteritems(): + for interface_name, interface_info in interfaces_info.items(): partial_interface_paths = partial_interface_files[interface_name] partial_interfaces_full_paths = partial_interface_paths['full_paths'] # Partial interface definitions each need an include, as they are # implemented in separate classes from the main interface. - partial_interfaces_include_paths = partial_interface_paths['include_paths'] + partial_interfaces_include_paths = \ + partial_interface_paths['include_paths'] mixins = interface_info['including_mixins'] try: mixins_info = [interfaces_info[mixin] for mixin in mixins] except KeyError as key_name: - raise IdlInterfaceFileNotFoundError('Could not find the IDL file where the following mixin is defined: %s' % key_name) - mixins_full_paths = [mixin_info['full_path'] for mixin_info in mixins_info] + raise IdlInterfaceFileNotFoundError( + 'Could not find the IDL file where the following mixin is defined: %s' + % key_name) + mixins_full_paths = [ + mixin_info['full_path'] for mixin_info in mixins_info + ] # Mixins don't need include files, as this is handled in the Blink # implementation (they are implemented on |impl| itself, hence header # declaration is included in the interface class). @@ -258,7 +275,8 @@ def compute_interfaces_info_overall(info_individuals): # https://crbug.com/360435 mixins_include_paths = [ mixin_info['include_path'] for mixin_info in mixins_info - if mixin_info['is_legacy_treat_as_partial_interface']] + if mixin_info['is_legacy_treat_as_partial_interface'] + ] dependencies_full_paths = mixins_full_paths dependencies_include_paths = mixins_include_paths @@ -274,23 +292,26 @@ def compute_interfaces_info_overall(info_individuals): dependencies_other_component_full_paths.append(full_path) for include_path in partial_interfaces_include_paths: - partial_interface_component = idl_filename_to_component(include_path) + partial_interface_component = idl_filename_to_component( + include_path) if component == partial_interface_component: dependencies_include_paths.append(include_path) else: dependencies_other_component_include_paths.append(include_path) interface_info.update({ - 'dependencies_full_paths': dependencies_full_paths, - 'dependencies_include_paths': dependencies_include_paths, + 'dependencies_full_paths': + dependencies_full_paths, + 'dependencies_include_paths': + dependencies_include_paths, 'dependencies_other_component_full_paths': - dependencies_other_component_full_paths, + dependencies_other_component_full_paths, 'dependencies_other_component_include_paths': - dependencies_other_component_include_paths, + dependencies_other_component_include_paths, }) # Clean up temporary private information - for interface_info in interfaces_info.itervalues(): + for interface_info in interfaces_info.values(): del interface_info['extended_attributes'] del interface_info['union_types'] del interface_info['is_legacy_treat_as_partial_interface'] @@ -302,6 +323,7 @@ def compute_interfaces_info_overall(info_individuals): ################################################################################ + def main(): _, args = parse_options() # args = Input1, Input2, ..., Output diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.py index 71bfb0383b4..51c66c38c5e 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.py @@ -1,7 +1,6 @@ # Copyright 2019 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """ Runs the bindings code generator for the given tasks. """ @@ -9,22 +8,40 @@ Runs the bindings code generator for the given tasks. import optparse import sys -import bind_gen import web_idl +import bind_gen def parse_options(): parser = optparse.OptionParser(usage="%prog [options] TASK...") - parser.add_option('--web_idl_database', type='string', - help="filepath of the input database") - parser.add_option('--output_dir_core', type='string', - help="outout directory for 'core' component") - parser.add_option('--output_dir_modules', type='string', - help="outout directory for 'modules' component") + parser.add_option( + "--web_idl_database", + type="string", + help="filepath of the input database") + parser.add_option( + "--root_src_dir", + type="string", + help='root directory of chromium project, i.e. "//"') + parser.add_option( + "--root_gen_dir", + type="string", + help='root directory of generated code files, i.e. ' + '"//out/Default/gen"') + parser.add_option( + "--output_core_reldir", + type="string", + help='output directory for "core" component relative to ' + 'root_gen_dir') + parser.add_option( + "--output_modules_reldir", + type="string", + help='output directory for "modules" component relative ' + 'to root_gen_dir') options, args = parser.parse_args() - required_option_names = ( - 'web_idl_database', 'output_dir_core', 'output_dir_modules') + required_option_names = ("web_idl_database", "root_src_dir", + "root_gen_dir", "output_core_reldir", + "output_modules_reldir") for opt_name in required_option_names: if getattr(options, opt_name) is None: parser.error("--{} is a required option.".format(opt_name)) @@ -40,24 +57,29 @@ def main(): dispatch_table = { 'dictionary': bind_gen.generate_dictionaries, + 'enumeration': bind_gen.generate_enumerations, 'interface': bind_gen.generate_interfaces, + 'union': bind_gen.generate_unions, } for task in tasks: if task not in dispatch_table: sys.exit("Unknown task: {}".format(task)) - web_idl_database = web_idl.Database.read_from_file(options.web_idl_database) - output_dirs = { - web_idl.Component('core'): options.output_dir_core, - web_idl.Component('modules'): options.output_dir_modules, + web_idl_database = web_idl.Database.read_from_file( + options.web_idl_database) + component_reldirs = { + web_idl.Component('core'): options.output_core_reldir, + web_idl.Component('modules'): options.output_modules_reldir, } - bind_gen.init(output_dirs) + bind_gen.init( + root_src_dir=options.root_src_dir, + root_gen_dir=options.root_gen_dir, + component_reldirs=component_reldirs) for task in tasks: - dispatch_table[task](web_idl_database=web_idl_database, - output_dirs=output_dirs) + dispatch_table[task](web_idl_database=web_idl_database) if __name__ == '__main__': diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps b/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps index c4edf6a2c2a..e2b7256dbb0 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps @@ -10,7 +10,6 @@ ../../../../mako/mako/ext/__init__.py ../../../../mako/mako/filters.py ../../../../mako/mako/lexer.py -../../../../mako/mako/lookup.py ../../../../mako/mako/parsetree.py ../../../../mako/mako/pygen.py ../../../../mako/mako/pyparser.py @@ -31,18 +30,21 @@ ../../build/scripts/blinkbuild/name_style_converter.py bind_gen/__init__.py bind_gen/blink_v8_bridge.py -bind_gen/clang_format.py bind_gen/code_node.py +bind_gen/code_node_cxx.py bind_gen/codegen_accumulator.py bind_gen/codegen_context.py bind_gen/codegen_expr.py bind_gen/codegen_format.py bind_gen/codegen_utils.py bind_gen/dictionary.py +bind_gen/enumeration.py bind_gen/interface.py bind_gen/mako_renderer.py bind_gen/name_style.py bind_gen/path_manager.py +bind_gen/style_format.py +bind_gen/union.py generate_bindings.py web_idl/__init__.py web_idl/argument.py diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_event_interfaces.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_event_interfaces.py index 62cee43cf39..32120e11e65 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/generate_event_interfaces.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_event_interfaces.py @@ -27,7 +27,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Generate event interfaces .json5 file (EventInterfaces.json5). The event interfaces .json5 file contains a list of all Event interfaces, i.e., @@ -54,21 +53,29 @@ EXPORTED_EXTENDED_ATTRIBUTES = ( 'RuntimeEnabled', ) module_path = os.path.dirname(os.path.realpath(__file__)) -REPO_ROOT_DIR = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir, - os.pardir, os.pardir, os.pardir)) +REPO_ROOT_DIR = os.path.normpath( + os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir, + os.pardir)) def parse_options(): parser = OptionParser() - parser.add_option('--event-idl-files-list', help='file listing event IDL files') + parser.add_option( + '--event-idl-files-list', help='file listing event IDL files') parser.add_option('--event-interfaces-file', help='output file') - parser.add_option('--suffix', help='specify a suffix to the namespace, i.e., "Modules". Default is None.') + parser.add_option( + '--suffix', + help= + 'specify a suffix to the namespace, i.e., "Modules". Default is None.') options, args = parser.parse_args() if options.event_idl_files_list is None: - parser.error('Must specify a file listing event IDL files using --event-idl-files-list.') + parser.error( + 'Must specify a file listing event IDL files using --event-idl-files-list.' + ) if options.event_interfaces_file is None: - parser.error('Must specify an output file using --event-interfaces-file.') + parser.error( + 'Must specify an output file using --event-interfaces-file.') if args: parser.error('No arguments allowed, but %d given.' % len(args)) return options @@ -76,35 +83,30 @@ def parse_options(): def write_event_interfaces_file(event_idl_files, destination_filename, suffix): def interface_line(full_path): - relative_dir_local = os.path.dirname(os.path.relpath(full_path, REPO_ROOT_DIR)) + relative_dir_local = os.path.dirname( + os.path.relpath(full_path, REPO_ROOT_DIR)) relative_dir_posix = relative_dir_local.replace(os.sep, posixpath.sep) idl_file_contents = get_file_contents(full_path) interface_name = get_first_interface_name_from_idl(idl_file_contents) - extended_attributes = get_interface_extended_attributes_from_idl(idl_file_contents) - extended_attributes_list = [ - (name, extended_attributes[name]) - for name in EXPORTED_EXTENDED_ATTRIBUTES - if name in extended_attributes] + extended_attributes = get_interface_extended_attributes_from_idl( + idl_file_contents) + extended_attributes_list = [(name, extended_attributes[name]) + for name in EXPORTED_EXTENDED_ATTRIBUTES + if name in extended_attributes] return (relative_dir_posix, interface_name, extended_attributes_list) - lines = [ - '{', - 'metadata: {', - ' namespace: "event_interface_names",' - ] + lines = ['{', 'metadata: {', ' namespace: "event_interface_names",'] if suffix: lines.append(' suffix: "' + suffix + '",') lines.append(' export: "%s_EXPORT",' % suffix.upper()) else: lines.append(' export: "CORE_EXPORT",') - lines.extend([ - '},', - 'data: [' - ]) - interface_lines = [interface_line(event_idl_file) - for event_idl_file in event_idl_files] + lines.extend(['},', 'data: [']) + interface_lines = [ + interface_line(event_idl_file) for event_idl_file in event_idl_files + ] interface_lines.sort() for relative_dir, name, attributes in interface_lines: lines.extend([ @@ -117,20 +119,17 @@ def write_event_interfaces_file(event_idl_files, destination_filename, suffix): value += 'Enabled' lines.append(' %s: "%s",' % (param, value)) lines.append(' },') - lines.extend([ - ']', - '}' - ]) + lines.extend([']', '}']) write_file('\n'.join(lines), destination_filename) ################################################################################ + def main(): options = parse_options() event_idl_files = read_file_to_list(options.event_idl_files_list) - write_event_interfaces_file(event_idl_files, - options.event_interfaces_file, + write_event_interfaces_file(event_idl_files, options.event_interfaces_file, options.suffix) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_global_constructors.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_global_constructors.py index 57b677409ba..987f737caf2 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/generate_global_constructors.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_global_constructors.py @@ -3,7 +3,6 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Generates interface properties on global objects. Concretely these are implemented as "constructor attributes", meaning @@ -41,22 +40,26 @@ from v8_utilities import EXPOSED_EXECUTION_CONTEXT_METHOD interface_name_to_global_names = {} global_name_to_constructors = defaultdict(list) - HEADER_FORMAT = """// Stub header file for {{idl_basename}} -// Required because the IDL compiler assumes that a corresponding header file -// exists for each IDL file. +// Required because the IDL compiler assumes that a corresponding header +// file exists for each IDL file. """ + def parse_options(): parser = optparse.OptionParser() parser.add_option('--idl-files-list', help='file listing IDL files') - parser.add_option('--global-objects-file', help='pickle file of global objects') + parser.add_option( + '--global-objects-file', help='pickle file of global objects') options, args = parser.parse_args() if options.idl_files_list is None: - parser.error('Must specify a file listing IDL files using --idl-files-list.') + parser.error( + 'Must specify a file listing IDL files using --idl-files-list.') if options.global_objects_file is None: - parser.error('Must specify a pickle file of global objects using --global-objects-file.') + parser.error( + 'Must specify a pickle file of global objects using --global-objects-file.' + ) return options, args @@ -75,16 +78,17 @@ def interface_name_to_constructors(interface_name): def record_global_constructors(idl_filename): full_path = os.path.realpath(idl_filename) idl_file_contents = get_file_contents(full_path) - extended_attributes = get_interface_extended_attributes_from_idl(idl_file_contents) + extended_attributes = get_interface_extended_attributes_from_idl( + idl_file_contents) interface_name = get_first_interface_name_from_idl(idl_file_contents) # An interface property is produced for every non-callback interface # that does not have [NoInterfaceObject]. # http://heycam.github.io/webidl/#es-interfaces - if (not should_generate_impl_file_from_idl(idl_file_contents) or - is_non_legacy_callback_interface_from_idl(idl_file_contents) or - is_interface_mixin_from_idl(idl_file_contents) or - 'NoInterfaceObject' in extended_attributes): + if (not should_generate_impl_file_from_idl(idl_file_contents) + or is_non_legacy_callback_interface_from_idl(idl_file_contents) + or is_interface_mixin_from_idl(idl_file_contents) + or 'NoInterfaceObject' in extended_attributes): return exposed_arguments = get_interface_exposed_arguments(idl_file_contents) @@ -92,31 +96,40 @@ def record_global_constructors(idl_filename): # Exposed(Arguments) case for argument in exposed_arguments: if 'RuntimeEnabled' in extended_attributes: - raise ValueError('RuntimeEnabled should not be used with Exposed(Arguments)') + raise ValueError( + 'RuntimeEnabled should not be used with Exposed(Arguments)' + ) attributes = extended_attributes.copy() attributes['RuntimeEnabled'] = argument['runtime_enabled'] - new_constructors_list = generate_global_constructors_list(interface_name, attributes) - global_name_to_constructors[argument['exposed']].extend(new_constructors_list) + new_constructors_list = generate_global_constructors_list( + interface_name, attributes) + global_name_to_constructors[argument['exposed']].extend( + new_constructors_list) else: # Exposed=env or Exposed=(env1,...) case exposed_value = extended_attributes.get('Exposed', 'Window') - exposed_global_names = map(str.strip, exposed_value.strip('()').split(',')) - new_constructors_list = generate_global_constructors_list(interface_name, extended_attributes) + exposed_global_names = map(str.strip, + exposed_value.strip('()').split(',')) + new_constructors_list = generate_global_constructors_list( + interface_name, extended_attributes) for name in exposed_global_names: global_name_to_constructors[name].extend(new_constructors_list) def generate_global_constructors_list(interface_name, extended_attributes): extended_attributes_list = [ - name + (('=' + extended_attributes[name]) if extended_attributes[name] else '') - for name in 'RuntimeEnabled', 'ContextEnabled', 'SecureContext' - if name in extended_attributes] + name + (('=' + extended_attributes[name]) + if extended_attributes[name] else '') + for name in ['RuntimeEnabled', 'ContextEnabled', 'SecureContext'] + if name in extended_attributes + ] if extended_attributes_list: extended_string = '[%s] ' % ', '.join(extended_attributes_list) else: extended_string = '' - attribute_string = 'attribute {interface_name}Constructor {interface_name}'.format(interface_name=interface_name) + attribute_string = 'attribute {interface_name}Constructor {interface_name}'.format( + interface_name=interface_name) attributes_list = [extended_string + attribute_string] # In addition to the usual interface property, for every [NamedConstructor] @@ -129,30 +142,36 @@ def generate_global_constructors_list(interface_name, extended_attributes): constructor_name = re.sub(r'\(.*', '', named_constructor) # Note the reduplicated 'ConstructorConstructor' # FIXME: rename to NamedConstructor - attribute_string = 'attribute %sConstructorConstructor %s' % (interface_name, constructor_name) + attribute_string = 'attribute %sConstructorConstructor %s' % ( + interface_name, constructor_name) attributes_list.append(extended_string + attribute_string) return attributes_list -def write_global_constructors_partial_interface(interface_name, idl_filename, constructor_attributes_list): +def write_global_constructors_partial_interface(interface_name, idl_filename, + constructor_attributes_list): idl_basename = os.path.basename(idl_filename) basename = os.path.splitext(idl_basename)[0] # FIXME: replace this with a simple Jinja template - lines = (['[\n', - ' ImplementedAs=%s\n' % basename, - '] partial interface %s {\n' % interface_name] + - [' %s;\n' % constructor_attribute - # FIXME: sort by interface name (not first by extended attributes) - for constructor_attribute in sorted(constructor_attributes_list)] + - ['};\n']) + lines = ([ + '[\n', + ' ImplementedAs=%s\n' % basename, + '] partial interface %s {\n' % interface_name + ] + [ + ' %s;\n' % constructor_attribute + # FIXME: sort by interface name (not first by extended attributes) + for constructor_attribute in sorted(constructor_attributes_list) + ] + ['};\n']) write_file(''.join(lines), idl_filename) header_filename = os.path.splitext(idl_filename)[0] + '.h' - write_file(HEADER_FORMAT.format(idl_basename=idl_basename), header_filename) + write_file( + HEADER_FORMAT.format(idl_basename=idl_basename), header_filename) ################################################################################ + def main(): options, args = parse_options() @@ -167,7 +186,8 @@ def main(): interface_name_idl_filename = [(args[i], args[i + 1]) for i in range(0, len(args), 2)] - interface_name_to_global_names.update(read_pickle_file(options.global_objects_file)) + interface_name_to_global_names.update( + read_pickle_file(options.global_objects_file)) for idl_filename in idl_files: record_global_constructors(idl_filename) @@ -176,7 +196,8 @@ def main(): known_global_names = EXPOSED_EXECUTION_CONTEXT_METHOD.keys() exposed_global_names = frozenset(global_name_to_constructors) if not exposed_global_names.issubset(known_global_names): - unknown_global_names = exposed_global_names.difference(known_global_names) + unknown_global_names = exposed_global_names.difference( + known_global_names) raise ValueError('The following global names were used in ' '[Exposed=xxx] but do not match any global names: %s' % list(unknown_global_names)) @@ -185,8 +206,8 @@ def main(): # global interface. for interface_name, idl_filename in interface_name_idl_filename: constructors = interface_name_to_constructors(interface_name) - write_global_constructors_partial_interface( - interface_name, idl_filename, constructors) + write_global_constructors_partial_interface(interface_name, + idl_filename, constructors) if __name__ == '__main__': diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.py new file mode 100644 index 00000000000..a247e0032ac --- /dev/null +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.py @@ -0,0 +1,137 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +""" +Generate of table of APIs and their attributes based on the WebIDL database. + +The columns of the table are as follows: + + * interface : Name of interface. + * name : Member name. Will be empty for interfaces. + * entity_type : One of 'interface', 'namespace', 'const', 'attribute', + 'operation', 'constructor', 'stringifier', 'iterable', + 'maplike', 'setlike', 'dictionary' + * idl_type : Type of the object. For function-like entries, this is the + type of the return value. Note that the type is stripped + of nullable unions. + * syntactic_form : Human readable idl_type. + * use_counter : If usage is being measured, this is the UseCounter. + * secure_context : 'True' if the [SecureContext] extended attribute is + present. Empty otherwise. + * high_entropy : 'True' if the [HighEntropy] extended attribute is present. + Empty otherwise. +""" + +import optparse +from io import BytesIO +from csv import DictWriter + +from utilities import write_file +from v8_utilities import capitalize +import web_idl + + +def parse_options(): + parser = optparse.OptionParser(usage="%prog [options]") + parser.add_option( + "--web_idl_database", + type="string", + help="filepath of the input database") + parser.add_option( + "--output", type="string", help="filepath of output file") + options, args = parser.parse_args() + + required_option_names = ("web_idl_database", "output") + for opt_name in required_option_names: + if getattr(options, opt_name) is None: + parser.error("--{} is a required option.".format(opt_name)) + + return options, args + + +def get_idl_type_name(idl_type): + assert isinstance(idl_type, web_idl.IdlType) + unwrapped_type = idl_type.unwrap() + return unwrapped_type.type_name, unwrapped_type.syntactic_form + + +def true_or_nothing(v): + return 'True' if v else '' + + +def record(csv_writer, entity): + interface = '' + name = '' + entity_type = '' + use_counter = '' + secure_context = '' + high_entropy = '' + idl_type = '' + syntactic_form = '' + + secure_context = ('SecureContext' in entity.extended_attributes) + high_entropy = ('HighEntropy' in entity.extended_attributes) + + if 'Measure' in entity.extended_attributes: + use_counter = capitalize(entity.identifier) + if not isinstance(entity, web_idl.Interface): + use_counter = ( + capitalize(entity.owner.identifier) + '_' + use_counter) + elif 'MeasureAs' in entity.extended_attributes: + use_counter = entity.extended_attributes.value_of('MeasureAs') + + if isinstance(entity, web_idl.Interface): + interface = entity.identifier + name = '' + entity_type = 'interface' + else: + interface = entity.owner.identifier + name = entity.identifier + + if isinstance(entity, web_idl.Attribute): + entity_type = 'attribute' + idl_type, syntactic_form = get_idl_type_name(entity.idl_type) + elif isinstance(entity, web_idl.Operation): + entity_type = 'operation' + idl_type, syntactic_form = get_idl_type_name(entity.return_type) + elif isinstance(entity, web_idl.Constant): + entity_type = 'constant' + idl_type, syntactic_form = get_idl_type_name(entity.idl_type) + else: + assert False, "Unexpected IDL construct" + csv_writer.writerow({ + 'interface': interface, + 'name': name, + 'entity_type': entity_type, + 'idl_type': idl_type, + 'syntactic_form': syntactic_form, + 'use_counter': use_counter, + 'secure_context': true_or_nothing(secure_context), + 'high_entropy': true_or_nothing(high_entropy) + }) + + +def main(): + options, _ = parse_options() + with BytesIO() as out_buffer: + csv_writer = DictWriter( + out_buffer, + fieldnames=[ + 'interface', 'name', 'entity_type', 'idl_type', + 'syntactic_form', 'use_counter', 'secure_context', + 'high_entropy' + ]) + csv_writer.writeheader() + + web_idl_database = web_idl.Database.read_from_file( + options.web_idl_database) + for interface in web_idl_database.interfaces: + record(csv_writer, interface) + for entity in (interface.attributes + interface.operations + + interface.constants): + record(csv_writer, entity) + write_file(out_buffer.getvalue(), options.output) + + +if __name__ == '__main__': + main() diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.pydeps b/chromium/third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.pydeps new file mode 100644 index 00000000000..1d9e7f3b75a --- /dev/null +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.pydeps @@ -0,0 +1,51 @@ +# Generated by running: +# build/print_python_deps.py --root third_party/blink/renderer/bindings/scripts --output third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.pydeps third_party/blink/renderer/bindings/scripts/generate_high_entropy_list.py +../../../../pyjson5/src/json5/__init__.py +../../../../pyjson5/src/json5/arg_parser.py +../../../../pyjson5/src/json5/host.py +../../../../pyjson5/src/json5/lib.py +../../../../pyjson5/src/json5/parser.py +../../../../pyjson5/src/json5/tool.py +../../../../pyjson5/src/json5/version.py +../../build/scripts/blinkbuild/__init__.py +../../build/scripts/blinkbuild/name_style_converter.py +generate_high_entropy_list.py +idl_definitions.py +idl_types.py +utilities.py +v8_globals.py +v8_utilities.py +web_idl/__init__.py +web_idl/argument.py +web_idl/ast_group.py +web_idl/attribute.py +web_idl/callback_function.py +web_idl/callback_interface.py +web_idl/code_generator_info.py +web_idl/composition_parts.py +web_idl/constant.py +web_idl/constructor.py +web_idl/database.py +web_idl/database_builder.py +web_idl/dictionary.py +web_idl/enumeration.py +web_idl/exposure.py +web_idl/extended_attribute.py +web_idl/file_io.py +web_idl/function_like.py +web_idl/idl_compiler.py +web_idl/idl_type.py +web_idl/includes.py +web_idl/interface.py +web_idl/ir_builder.py +web_idl/ir_map.py +web_idl/literal_constant.py +web_idl/make_copy.py +web_idl/namespace.py +web_idl/operation.py +web_idl/reference.py +web_idl/runtime_enabled_features.py +web_idl/typedef.py +web_idl/union.py +web_idl/user_defined_type.py +web_idl/validator.py diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py index 0e44fe91b66..fca4d565c96 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py @@ -2,11 +2,14 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - -"""Generate initPartialInterfacesInModules(), which registers partial interfaces in modules to core interfaces.""" +"""Generate initPartialInterfacesInModules(), which registers partial +interfaces in modules to core interfaces. +""" # pylint: disable=relative-import +from __future__ import print_function + from optparse import OptionParser import os import posixpath @@ -19,7 +22,6 @@ from utilities import should_generate_impl_file_from_idl from utilities import write_file from v8_utilities import build_basename - _COPYRIGHT = """// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -41,15 +43,18 @@ void InitPartialInterfacesInModules() { def parse_options(): usage = 'Usage: %prog [options]' parser = OptionParser(usage=usage) - parser.add_option('--idl-files-list', - help='a text file containing the IDL file paths, so the command line doesn\'t exceed OS length limits.') + parser.add_option( + '--idl-files-list', + help='a text file containing the IDL file paths, so the command ' + 'line doesn\'t exceed OS length limits.') parser.add_option('--output') options, args = parser.parse_args() if options.output is None: parser.error('Must specify output file using --output.') if options.idl_files_list is None: - parser.error('Must specify a list of IDL files using --idl-files-list.') + parser.error( + 'Must specify a list of IDL files using --idl-files-list.') return options @@ -59,10 +64,10 @@ def extract_meta_data(file_paths): for file_path in file_paths: if not file_path.endswith('.idl'): - print 'WARNING: non-IDL file passed: "%s"' % file_path + print('WARNING: non-IDL file passed: "%s"' % file_path) continue if not os.path.exists(file_path): - print 'WARNING: file not found: "%s"' % file_path + print('WARNING: file not found: "%s"' % file_path) continue idl_file_contents = get_file_contents(file_path) @@ -86,20 +91,22 @@ def main(): idl_file_names = read_idl_files_list_from_file(options.idl_files_list) meta_data_list = extract_meta_data(idl_file_names) - interface_names = ['V8%sPartial' % meta_data['basename'] - for meta_data in meta_data_list] + interface_names = [ + 'V8%sPartial' % meta_data['basename'] for meta_data in meta_data_list + ] interface_names.sort() - includes = ['#include "third_party/blink/renderer/bindings/modules/v8/%s.h"' % - build_basename(interface_name) - for interface_name in interface_names] - initialize_calls = [' %s::Initialize();' % interface_name - for interface_name in interface_names] - - content = _INIT_PARTIAL_INTERFACE % ( - _COPYRIGHT, - '\n'.join(includes), - '\n'.join(initialize_calls)) + includes = [ + '#include "third_party/blink/renderer/bindings/modules/v8/%s.h"' % + build_basename(interface_name) for interface_name in interface_names + ] + initialize_calls = [ + ' %s::Initialize();' % interface_name + for interface_name in interface_names + ] + + content = _INIT_PARTIAL_INTERFACE % (_COPYRIGHT, '\n'.join(includes), + '\n'.join(initialize_calls)) write_file(content, options.output) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py index 0ec3953411b..c2b40844ad1 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py @@ -25,9 +25,9 @@ from v8_utilities import (binding_header_filename, v8_class_name, # Make sure extension is .py, not .pyc or .pyo, so doesn't depend on caching MODULE_PYNAME = os.path.splitext(os.path.basename(__file__))[0] + '.py' - -OriginTrialInterfaceInfo = namedtuple('OriginTrialInterfaceInfo', [ - 'name', 'v8_class', 'v8_class_or_partial', 'is_global']) +OriginTrialInterfaceInfo = namedtuple( + 'OriginTrialInterfaceInfo', + ['name', 'v8_class', 'v8_class_or_partial', 'is_global']) def get_install_functions(interfaces, feature_names): @@ -38,15 +38,14 @@ def get_install_functions(interfaces, feature_names): feature_names is a list of strings, containing names of features which can be installed on those interfaces. """ - return [ - {'condition': 'RuntimeEnabledFeatures::%sEnabled' % feature_name, - 'name': feature_name, - 'install_method': 'Install%s' % feature_name, - 'interface_is_global': interface_info.is_global, - 'v8_class': interface_info.v8_class, - 'v8_class_or_partial': interface_info.v8_class_or_partial} - for feature_name in feature_names - for interface_info in interfaces] + return [{ + 'condition': 'RuntimeEnabledFeatures::%sEnabled' % feature_name, + 'name': feature_name, + 'install_method': 'Install%s' % feature_name, + 'interface_is_global': interface_info.is_global, + 'v8_class': interface_info.v8_class, + 'v8_class_or_partial': interface_info.v8_class_or_partial + } for feature_name in feature_names for interface_info in interfaces] def get_origin_trial_feature_names_from_interface(interface, runtime_features): @@ -78,7 +77,8 @@ def interface_is_global(interface): return 'Global' in interface.extended_attributes -def origin_trial_features_info(info_provider, reader, idl_filenames, target_component): +def origin_trial_features_info(info_provider, reader, idl_filenames, + target_component): """Read a set of IDL files and compile the mapping between interfaces and the conditional features defined on them. @@ -95,10 +95,13 @@ def origin_trial_features_info(info_provider, reader, idl_filenames, target_comp for idl_filename in idl_filenames: interface, includes = read_idl_file(reader, idl_filename) - feature_names = get_origin_trial_feature_names_from_interface(interface, runtime_features) + feature_names = get_origin_trial_feature_names_from_interface( + interface, runtime_features) # If this interface is a mixin, we don't generate V8 bindings code for # it. + # TODO(crbug.com/1061995): This incorrectly ignores includes in the + # mixin idl like "SomeInterface includes MixinInterface". if interface.is_mixin: continue @@ -109,7 +112,8 @@ def origin_trial_features_info(info_provider, reader, idl_filenames, target_comp mixin, _ = read_idl_file( reader, info_provider.interfaces_info[include.mixin].get('full_path')) - feature_names |= get_origin_trial_feature_names_from_interface(mixin, runtime_features) + feature_names |= get_origin_trial_feature_names_from_interface( + mixin, runtime_features) feature_names = list(feature_names) if feature_names: @@ -118,28 +122,29 @@ def origin_trial_features_info(info_provider, reader, idl_filenames, target_comp # For partial interfaces, we need to generate different # |include_files| if the parent interface is in a different # component. - parent_interface_info = info_provider.interfaces_info[interface.name] + parent_interface_info = \ + info_provider.interfaces_info[interface.name] parent_interface, _ = read_idl_file( reader, parent_interface_info.get('full_path')) is_global = is_global or interface_is_global(parent_interface) parent_component = idl_filename_to_component( parent_interface_info.get('full_path')) if interface.is_partial and target_component != parent_component: - include_files.add('bindings/%s/v8/%s' % - (parent_component, binding_header_filename(interface.name))) - include_files.add('bindings/%s/v8/%s' % - (target_component, binding_header_filename(interface.name + 'Partial'))) + include_files.add('bindings/%s/v8/%s' % ( + parent_component, binding_header_filename(interface.name))) + include_files.add( + 'bindings/%s/v8/%s' % + (target_component, + binding_header_filename(interface.name + 'Partial'))) else: - include_files.add('bindings/%s/v8/%s' % - (target_component, binding_header_filename(interface.name))) + include_files.add('bindings/%s/v8/%s' % ( + target_component, binding_header_filename(interface.name))) # If this is a partial interface in the same component as # its parent, then treat it as a non-partial interface. interface.is_partial = False - interface_info = OriginTrialInterfaceInfo(interface.name, - v8_class_name(interface), - v8_class_name_or_partial( - interface), - is_global) + interface_info = OriginTrialInterfaceInfo( + interface.name, v8_class_name(interface), + v8_class_name_or_partial(interface), is_global) for feature_name in feature_names: features_for_type[interface_info].add(feature_name) types_for_feature[feature_name].add(interface_info) @@ -171,21 +176,28 @@ def origin_trial_features_context(generator_name, feature_info): # For each interface, collect a list of bindings installation functions to # call, organized by conditional feature. - context['installers_by_interface'] = [ - {'name': interface_info.name, - 'is_global': interface_info.is_global, - 'v8_class': interface_info.v8_class, - 'installers': get_install_functions([interface_info], feature_names)} - for interface_info, feature_names in features_for_type.items()] + context['installers_by_interface'] = [{ + 'name': + interface_info.name, + 'is_global': + interface_info.is_global, + 'v8_class': + interface_info.v8_class, + 'installers': + get_install_functions([interface_info], feature_names) + } for interface_info, feature_names in features_for_type.items()] context['installers_by_interface'].sort(key=lambda x: x['name']) # For each conditional feature, collect a list of bindings installation # functions to call, organized by interface. - context['installers_by_feature'] = [ - {'name': feature_name, - 'name_constant': 'OriginTrialFeature::k%s' % feature_name, - 'installers': get_install_functions(interfaces, [feature_name])} - for feature_name, interfaces in types_for_feature.items()] + context['installers_by_feature'] = [{ + 'name': + feature_name, + 'name_constant': + 'OriginTrialFeature::k%s' % feature_name, + 'installers': + get_install_functions(interfaces, [feature_name]) + } for feature_name, interfaces in types_for_feature.items()] context['installers_by_feature'].sort(key=lambda x: x['name']) return context @@ -193,14 +205,16 @@ def origin_trial_features_context(generator_name, feature_info): def parse_options(): parser = optparse.OptionParser() - parser.add_option('--cache-directory', - help='cache directory, defaults to output directory') + parser.add_option( + '--cache-directory', + help='cache directory, defaults to output directory') parser.add_option('--output-directory') parser.add_option('--info-dir') - parser.add_option('--target-component', - type='choice', - choices=['core', 'modules'], - help='target component to generate code') + parser.add_option( + '--target-component', + type='choice', + choices=['core', 'modules'], + help='target component to generate code') parser.add_option('--idl-files-list') options, _ = parser.parse_args() @@ -215,23 +229,25 @@ def generate_origin_trial_features(info_provider, options, idl_filenames): # Extract the bidirectional mapping of conditional features <-> interfaces # from the global info provider and the supplied list of IDL files. - feature_info = origin_trial_features_info(info_provider, - reader, idl_filenames, - options.target_component) + feature_info = origin_trial_features_info( + info_provider, reader, idl_filenames, options.target_component) # Convert that mapping into the context required for the Jinja2 templates. - template_context = origin_trial_features_context( - MODULE_PYNAME, feature_info) + template_context = origin_trial_features_context(MODULE_PYNAME, + feature_info) file_basename = 'origin_trial_features_for_%s' % options.target_component # Generate and write out the header file - header_text = render_template(jinja_env.get_template(file_basename + '.h.tmpl'), template_context) - header_path = posixpath.join(options.output_directory, file_basename + '.h') + header_text = render_template( + jinja_env.get_template(file_basename + '.h.tmpl'), template_context) + header_path = posixpath.join(options.output_directory, + file_basename + '.h') write_file(header_text, header_path) # Generate and write out the implementation file - cpp_text = render_template(jinja_env.get_template(file_basename + '.cc.tmpl'), template_context) + cpp_text = render_template( + jinja_env.get_template(file_basename + '.cc.tmpl'), template_context) cpp_path = posixpath.join(options.output_directory, file_basename + '.cc') write_file(cpp_text, cpp_path) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py b/chromium/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py index 3fc8a81a152..4f23b299d0d 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py @@ -17,14 +17,14 @@ import v8_interface import v8_types import v8_utilities - INCLUDES = frozenset([ 'third_party/blink/renderer/bindings/core/v8/generated_code_helper.h', 'third_party/blink/renderer/bindings/core/v8/v8_html_document.h', 'third_party/blink/renderer/bindings/core/v8/v8_initializer.h', 'third_party/blink/renderer/bindings/core/v8/v8_window.h', 'third_party/blink/renderer/platform/bindings/v8_object_constructor.h', - 'v8/include/v8.h']) + 'v8/include/v8.h' +]) TEMPLATE_FILE = 'external_reference_table.cc.tmpl' @@ -39,22 +39,27 @@ SNAPSHOTTED_INTERFACES = frozenset([ def parse_args(): parser = argparse.ArgumentParser() - parser.add_argument('--idl-files-list', type=str, required=True, - help='file listing IDL files') - parser.add_argument('--output', type=str, required=True, - help='output file path') - parser.add_argument('--info-dir', type=str, required=True, - help='directory contains component info') - parser.add_argument('--cache-dir', type=str, required=True, - help='cache directory') - parser.add_argument('--target-component', type=str, required=True, - help='target component') + parser.add_argument( + '--idl-files-list', + type=str, + required=True, + help='file listing IDL files') + parser.add_argument( + '--output', type=str, required=True, help='output file path') + parser.add_argument( + '--info-dir', + type=str, + required=True, + help='directory contains component info') + parser.add_argument( + '--cache-dir', type=str, required=True, help='cache directory') + parser.add_argument( + '--target-component', type=str, required=True, help='target component') return parser.parse_known_args() # This class creates a Jinja template context about an interface. class InterfaceTemplateContextBuilder(object): - def __init__(self, opts, info_provider): self._opts = opts self._info_provider = info_provider @@ -64,12 +69,14 @@ class InterfaceTemplateContextBuilder(object): assert component in ['core', 'modules'] - name = '%s%s' % (v8_utilities.cpp_name(interface), 'Partial' if interface.is_partial else '') + name = '%s%s' % (v8_utilities.cpp_name(interface), + 'Partial' if interface.is_partial else '') # Constructors has_constructor_callback = False if not interface.is_partial: - constructors = any(constructor.name == 'Constructor' for constructor in interface.constructors) + constructors = any(constructor.name == 'Constructor' + for constructor in interface.constructors) custom_constructors = interface.custom_constructors html_constructor = 'HTMLConstructor' in interface.extended_attributes has_constructor_callback = constructors or custom_constructors or html_constructor @@ -86,9 +93,13 @@ class InterfaceTemplateContextBuilder(object): named_property_getter = None component_info = self._info_provider.component_info if interface.name in SNAPSHOTTED_INTERFACES: - attributes = [v8_attributes.attribute_context(interface, attribute, interfaces, component_info) - for attribute in interface.attributes] - methods = v8_interface.methods_context(interface, component_info)['methods'] + attributes = [ + v8_attributes.attribute_context(interface, attribute, + interfaces, component_info) + for attribute in interface.attributes + ] + methods = v8_interface.methods_context(interface, + component_info)['methods'] is_global = 'Global' in interface.extended_attributes named_property_getter = v8_interface.property_getter( @@ -97,37 +108,68 @@ class InterfaceTemplateContextBuilder(object): interface.indexed_property_getter, ['index']) if not interface.is_partial: - has_security_check = ('CheckSecurity' in interface.extended_attributes and - interface.name != 'EventTarget') - has_cross_origin_named_getter = (any(method['is_cross_origin'] for method in methods) or - any(attribute['has_cross_origin_getter'] for attribute in attributes)) - has_cross_origin_named_setter = any(attribute['has_cross_origin_setter'] for attribute in attributes) - has_cross_origin_indexed_getter = indexed_property_getter and indexed_property_getter['is_cross_origin'] - has_cross_origin_named_enum = has_cross_origin_named_getter or has_cross_origin_named_setter - if named_property_getter and named_property_getter['is_cross_origin']: + has_security_check = ( + 'CheckSecurity' in interface.extended_attributes + and interface.name != 'EventTarget') + has_cross_origin_named_getter = ( + any(method['is_cross_origin'] for method in methods) + or any(attribute['has_cross_origin_getter'] + for attribute in attributes)) + has_cross_origin_named_setter = any( + attribute['has_cross_origin_setter'] + for attribute in attributes) + has_cross_origin_indexed_getter = ( + indexed_property_getter + and indexed_property_getter['is_cross_origin']) + has_cross_origin_named_enum = has_cross_origin_named_getter \ + or has_cross_origin_named_setter + if (named_property_getter + and named_property_getter['is_cross_origin']): has_cross_origin_named_getter = True return { - 'attributes': attributes, - 'component': component, - 'has_constructor_callback': has_constructor_callback, - 'has_cross_origin_named_getter': has_cross_origin_named_getter, - 'has_cross_origin_named_setter': has_cross_origin_named_setter, - 'has_cross_origin_named_enumerator': has_cross_origin_named_enum, - 'has_cross_origin_indexed_getter': has_cross_origin_indexed_getter, - 'has_security_check': has_security_check, - 'indexed_property_getter': indexed_property_getter, - 'indexed_property_setter': v8_interface.property_setter(interface.indexed_property_setter, interface), - 'indexed_property_deleter': v8_interface.property_deleter(interface.indexed_property_deleter), - 'internal_namespace': v8_interface.internal_namespace(interface), - 'is_partial': interface.is_partial, - 'methods': methods, - 'name': name, - 'named_constructor': v8_interface.named_constructor_context(interface), - 'named_property_getter': named_property_getter, - 'named_property_setter': v8_interface.property_setter(interface.named_property_setter, interface), - 'named_property_deleter': v8_interface.property_deleter(interface.named_property_deleter), - 'v8_class': v8_utilities.v8_class_name_or_partial(interface), + 'attributes': + attributes, + 'component': + component, + 'has_constructor_callback': + has_constructor_callback, + 'has_cross_origin_named_getter': + has_cross_origin_named_getter, + 'has_cross_origin_named_setter': + has_cross_origin_named_setter, + 'has_cross_origin_named_enumerator': + has_cross_origin_named_enum, + 'has_cross_origin_indexed_getter': + has_cross_origin_indexed_getter, + 'has_security_check': + has_security_check, + 'indexed_property_getter': + indexed_property_getter, + 'indexed_property_setter': + v8_interface.property_setter(interface.indexed_property_setter, + interface), + 'indexed_property_deleter': + v8_interface.property_deleter(interface.indexed_property_deleter), + 'internal_namespace': + v8_interface.internal_namespace(interface), + 'is_partial': + interface.is_partial, + 'methods': + methods, + 'name': + name, + 'named_constructor': + v8_interface.named_constructor_context(interface), + 'named_property_getter': + named_property_getter, + 'named_property_setter': + v8_interface.property_setter(interface.named_property_setter, + interface), + 'named_property_deleter': + v8_interface.property_deleter(interface.named_property_deleter), + 'v8_class': + v8_utilities.v8_class_name_or_partial(interface), } @@ -136,11 +178,11 @@ class ExternalReferenceTableGenerator(object): def __init__(self, opts, info_provider): self._opts = opts self._info_provider = info_provider - self._reader = IdlReader( - info_provider.interfaces_info, opts.cache_dir) + self._reader = IdlReader(info_provider.interfaces_info, opts.cache_dir) self._interface_contexts = {} self._include_files = set(INCLUDES) - v8_types.set_component_dirs(info_provider.interfaces_info['component_dirs']) + v8_types.set_component_dirs( + info_provider.interfaces_info['component_dirs']) # Creates a Jinja context from an IDL file. def process_idl_file(self, idl_filename): @@ -162,19 +204,25 @@ class ExternalReferenceTableGenerator(object): # Non legacy callback interface does not provide V8 callbacks. if interface.is_callback: return len(interface.constants) > 0 - if v8_utilities.runtime_enabled_feature_name(interface, runtime_features): + if v8_utilities.runtime_enabled_feature_name( + interface, runtime_features): return False if 'Exposed' not in interface.extended_attributes: return True - return any(exposure.exposed == 'Window' and exposure.runtime_enabled is None - for exposure in interface.extended_attributes['Exposed']) + return any( + exposure.exposed == 'Window' + and exposure.runtime_enabled is None + for exposure in interface.extended_attributes['Exposed']) if not has_impl(interface): return - context_builder = InterfaceTemplateContextBuilder(self._opts, self._info_provider) - context = context_builder.create_interface_context(interface, component, interfaces) - name = '%s%s' % (interface.name, 'Partial' if interface.is_partial else '') + context_builder = InterfaceTemplateContextBuilder( + self._opts, self._info_provider) + context = context_builder.create_interface_context( + interface, component, interfaces) + name = '%s%s' % (interface.name, + 'Partial' if interface.is_partial else '') self._interface_contexts[name] = context # Do not include unnecessary header files. @@ -213,8 +261,8 @@ class ExternalReferenceTableGenerator(object): def main(): opts, _ = parse_args() # TODO(peria): get rid of |info_provider| - info_provider = create_component_info_provider( - opts.info_dir, opts.target_component) + info_provider = create_component_info_provider(opts.info_dir, + opts.target_component) generator = ExternalReferenceTableGenerator(opts, info_provider) idl_files = utilities.read_idl_files_list_from_file(opts.idl_files_list) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_compiler.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_compiler.py index d4f4f54ecd4..94ba1bd4750 100755 --- a/chromium/third_party/blink/renderer/bindings/scripts/idl_compiler.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_compiler.py @@ -26,7 +26,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Compile an .idl file to Blink V8 bindings (.h and .cpp files). Design doc: https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/IDLCompiler.md @@ -49,22 +48,23 @@ from utilities import write_file def parse_options(): parser = OptionParser() - parser.add_option('--cache-directory', - help='cache directory, defaults to output directory') - parser.add_option('--generate-impl', - action='store_true', default=False) - parser.add_option('--read-idl-list-from-file', - action='store_true', default=False) + parser.add_option( + '--cache-directory', + help='cache directory, defaults to output directory') + parser.add_option('--generate-impl', action='store_true', default=False) + parser.add_option( + '--read-idl-list-from-file', action='store_true', default=False) parser.add_option('--output-directory') parser.add_option('--impl-output-directory') parser.add_option('--info-dir') # FIXME: We should always explicitly specify --target-component and # remove the default behavior. - parser.add_option('--target-component', - type='choice', - choices=['core', 'modules'], - help='target component to generate code, defaults to ' - 'component of input idl file') + parser.add_option( + '--target-component', + type='choice', + choices=['core', 'modules'], + help='target component to generate code, defaults to ' + 'component of input idl file') # ensure output comes last, so command line easy to parse via regexes parser.disable_interspersed_args() @@ -72,7 +72,9 @@ def parse_options(): if options.output_directory is None: parser.error('Must specify output directory using --output-directory.') if len(args) != 1: - parser.error('Must specify exactly 1 input file as argument, but %d given.' % len(args)) + parser.error( + 'Must specify exactly 1 input file as argument, but %d given.' % + len(args)) idl_filename = os.path.realpath(args[0]) return options, idl_filename @@ -83,8 +85,11 @@ class IdlCompiler(object): """ __metaclass__ = abc.ABCMeta - def __init__(self, output_directory, cache_directory=None, - code_generator_class=None, info_provider=None, + def __init__(self, + output_directory, + cache_directory=None, + code_generator_class=None, + info_provider=None, target_component=None): """ Args: @@ -99,9 +104,8 @@ class IdlCompiler(object): self.output_directory = output_directory self.target_component = target_component self.reader = IdlReader(info_provider.interfaces_info, cache_directory) - self.code_generator = code_generator_class(self.info_provider, - self.cache_directory, - self.output_directory) + self.code_generator = code_generator_class( + self.info_provider, self.cache_directory, self.output_directory) def compile_and_write(self, idl_filename): definitions = self.reader.read_idl_definitions(idl_filename) @@ -149,11 +153,9 @@ def generate_dictionary_impl(code_generator_class, info_provider, options, def generate_union_type_containers(code_generator_class, info_provider, options): - generator = code_generator_class( - info_provider, - options.cache_directory, - options.output_directory, - options.target_component) + generator = code_generator_class(info_provider, options.cache_directory, + options.output_directory, + options.target_component) output_code_list = generator.generate_code() for output_path, output_code in output_code_list: write_file(output_code, output_path) @@ -161,11 +163,9 @@ def generate_union_type_containers(code_generator_class, info_provider, def generate_callback_function_impl(code_generator_class, info_provider, options): - generator = code_generator_class( - info_provider, - options.cache_directory, - options.output_directory, - options.target_component) + generator = code_generator_class(info_provider, options.cache_directory, + options.output_directory, + options.target_component) output_code_list = generator.generate_code() for output_path, output_code in output_code_list: write_file(output_code, output_path) @@ -173,8 +173,8 @@ def generate_callback_function_impl(code_generator_class, info_provider, def main(): options, input_filename = parse_options() - info_provider = create_component_info_provider( - options.info_dir, options.target_component) + info_provider = create_component_info_provider(options.info_dir, + options.target_component) if options.generate_impl or options.read_idl_list_from_file: # |input_filename| should be a file which contains a list of IDL # dictionary paths. diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py index 27c6b032902..11f6846eef2 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions.py @@ -27,7 +27,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # pylint: disable=relative-import - """Blink IDL Intermediate Representation (IR) classes. Classes are primarily constructors, which build an IdlDefinitions object @@ -73,11 +72,11 @@ from idl_types import IdlUnionType SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER'] - ################################################################################ # TypedObject ################################################################################ + class TypedObject(object): """Object with a type, such as an Attribute or Operation (return value). @@ -85,13 +84,14 @@ class TypedObject(object): by the TypedefResolver before passing data to the code generator. """ __metaclass__ = abc.ABCMeta - idl_type_attributes = ('idl_type',) + idl_type_attributes = ('idl_type', ) ################################################################################ # Definitions (main container class) ################################################################################ + class IdlDefinitions(object): def __init__(self, node): """Args: node: AST root node, class == 'File'""" @@ -123,7 +123,8 @@ class IdlDefinitions(object): self.enumerations[enumeration.name] = enumeration elif child_class == 'Callback': callback_function = IdlCallbackFunction(child) - self.callback_functions[callback_function.name] = callback_function + self.callback_functions[callback_function. + name] = callback_function elif child_class == 'Includes': self.includes.append(IdlIncludes(child)) elif child_class == 'Dictionary': @@ -136,22 +137,22 @@ class IdlDefinitions(object): def accept(self, visitor): visitor.visit_definitions(self) - for interface in self.interfaces.itervalues(): + for interface in self.interfaces.values(): interface.accept(visitor) - for callback_function in self.callback_functions.itervalues(): + for callback_function in self.callback_functions.values(): callback_function.accept(visitor) - for dictionary in self.dictionaries.itervalues(): + for dictionary in self.dictionaries.values(): dictionary.accept(visitor) - for enumeration in self.enumerations.itervalues(): + for enumeration in self.enumerations.values(): enumeration.accept(visitor) for include in self.includes: include.accept(visitor) - for typedef in self.typedefs.itervalues(): + for typedef in self.typedefs.values(): typedef.accept(visitor) def update(self, other): """Update with additional IdlDefinitions.""" - for interface_name, new_interface in other.interfaces.iteritems(): + for interface_name, new_interface in other.interfaces.items(): if not new_interface.is_partial: # Add as new interface self.interfaces[interface_name] = new_interface @@ -162,8 +163,8 @@ class IdlDefinitions(object): self.interfaces[interface_name].merge(new_interface) except KeyError: raise Exception('Tried to merge partial interface for {0}, ' - 'but no existing interface by that name' - .format(interface_name)) + 'but no existing interface by that name'. + format(interface_name)) # Merge callbacks and enumerations self.enumerations.update(other.enumerations) @@ -174,6 +175,7 @@ class IdlDefinitions(object): # Callback Functions ################################################################################ + class IdlCallbackFunction(TypedObject): def __init__(self, node): children = node.GetChildren() @@ -185,12 +187,14 @@ class IdlCallbackFunction(TypedObject): if num_children == 3: ext_attributes_node = children[2] self.extended_attributes = ( - ext_attributes_node_to_extended_attributes(ext_attributes_node)) + ext_attributes_node_to_extended_attributes(ext_attributes_node) + ) else: self.extended_attributes = {} arguments_node_class = arguments_node.GetClass() if arguments_node_class != 'Arguments': - raise ValueError('Expected Arguments node, got %s' % arguments_node_class) + raise ValueError( + 'Expected Arguments node, got %s' % arguments_node_class) self.name = node.GetName() self.idl_type = type_node_to_type(type_node) @@ -206,6 +210,7 @@ class IdlCallbackFunction(TypedObject): # Dictionary ################################################################################ + class IdlDictionary(object): def __init__(self, node): self.extended_attributes = {} @@ -258,6 +263,7 @@ class IdlDictionaryMember(TypedObject): # Enumerations ################################################################################ + class IdlEnum(object): def __init__(self, node): self.name = node.GetName() @@ -273,8 +279,9 @@ class IdlEnum(object): # Typedefs ################################################################################ + class IdlTypedef(object): - idl_type_attributes = ('idl_type',) + idl_type_attributes = ('idl_type', ) def __init__(self, node): self.name = node.GetName() @@ -288,6 +295,7 @@ class IdlTypedef(object): # Interfaces ################################################################################ + class IdlInterface(object): def __init__(self, node): self.attributes = [] @@ -315,6 +323,14 @@ class IdlInterface(object): has_indexed_property_getter = False has_integer_typed_length = False + # These are used to support both constructor operations and old style + # [Constructor] extended attributes. Ideally we should do refactoring + # for constructor code generation but we will use a new code generator + # soon so this kind of workaround should be fine. + constructor_operations = [] + custom_constructor_operations = [] + constructor_operations_extended_attributes = {} + def is_blacklisted_attribute_type(idl_type): return idl_type.is_callback_function or \ idl_type.is_dictionary or \ @@ -327,14 +343,17 @@ class IdlInterface(object): if child_class == 'Attribute': attr = IdlAttribute(child) if is_blacklisted_attribute_type(attr.idl_type): - raise ValueError('Type "%s" cannot be used as an attribute.' % attr.idl_type) + raise ValueError( + 'Type "%s" cannot be used as an attribute.' % + attr.idl_type) if attr.idl_type.is_integer_type and attr.name == 'length': has_integer_typed_length = True self.attributes.append(attr) elif child_class == 'Const': self.constants.append(IdlConstant(child)) elif child_class == 'ExtAttributes': - extended_attributes = ext_attributes_node_to_extended_attributes(child) + extended_attributes = ext_attributes_node_to_extended_attributes( + child) self.constructors, self.custom_constructors = ( extended_attributes_to_constructors(extended_attributes)) clear_constructor_attributes(extended_attributes) @@ -347,6 +366,20 @@ class IdlInterface(object): elif str(op.arguments[0].idl_type) == 'DOMString': self.has_named_property_getter = True self.operations.append(op) + elif child_class == 'Constructor': + operation = constructor_operation_from_node(child) + if operation.is_custom: + custom_constructor_operations.append(operation.constructor) + else: + # Check extended attributes consistency when we previously + # handle constructor operations. + if constructor_operations: + check_constructor_operations_extended_attributes( + constructor_operations_extended_attributes, + operation.extended_attributes) + constructor_operations.append(operation.constructor) + constructor_operations_extended_attributes.update( + operation.extended_attributes) elif child_class == 'Inherit': self.parent = child.GetName() elif child_class == 'Stringifier': @@ -362,7 +395,9 @@ class IdlInterface(object): raise ValueError('Unrecognized node class: %s' % child_class) if len(filter(None, [self.iterable, self.maplike, self.setlike])) > 1: - raise ValueError('Interface can only have one of iterable<>, maplike<> and setlike<>.') + raise ValueError( + 'Interface can only have one of iterable<>, maplike<> and setlike<>.' + ) # TODO(rakuco): This validation logic should be in v8_interface according to bashi@. # At the moment, doing so does not work because several IDL files are partial Window @@ -370,19 +405,39 @@ class IdlInterface(object): # to prevent these partial interfaces from resetting has_named_property to False. if 'LegacyUnenumerableNamedProperties' in self.extended_attributes and \ not self.has_named_property_getter: - raise ValueError('[LegacyUnenumerableNamedProperties] can be used only in interfaces ' - 'that support named properties.') + raise ValueError( + '[LegacyUnenumerableNamedProperties] can be used only in interfaces ' + 'that support named properties.') if has_integer_typed_length and has_indexed_property_getter: self.has_indexed_elements = True else: if self.iterable is not None and self.iterable.key_type is None: - raise ValueError('Value iterators (iterable<V>) must be accompanied by an indexed ' - 'property getter and an integer-typed length attribute.') + raise ValueError( + 'Value iterators (iterable<V>) must be accompanied by an indexed ' + 'property getter and an integer-typed length attribute.') if 'Unforgeable' in self.extended_attributes: raise ValueError('[Unforgeable] cannot appear on interfaces.') + if constructor_operations or custom_constructor_operations: + if self.constructors or self.custom_constructors: + raise ValueError('Detected mixed [Constructor] and consructor ' + 'operations. Do not use both in a single ' + 'interface.') + extended_attributes = ( + convert_constructor_operations_extended_attributes( + constructor_operations_extended_attributes)) + if any(name in extended_attributes.keys() + for name in self.extended_attributes.keys()): + raise ValueError('Detected mixed extended attributes for ' + 'both [Constructor] and constructor ' + 'operations. Do not use both in a single ' + 'interface') + self.constructors = constructor_operations + self.custom_constructors = custom_constructor_operations + self.extended_attributes.update(extended_attributes) + def accept(self, visitor): visitor.visit_interface(self) for attribute in self.attributes: @@ -423,9 +478,11 @@ class IdlInterface(object): # Attributes ################################################################################ + class IdlAttribute(TypedObject): def __init__(self, node=None): - self.is_read_only = bool(node.GetProperty('READONLY')) if node else False + self.is_read_only = bool( + node.GetProperty('READONLY')) if node else False self.is_static = bool(node.GetProperty('STATIC')) if node else False self.name = node.GetName() if node else None self.idl_type = None @@ -441,12 +498,15 @@ class IdlAttribute(TypedObject): if child_class == 'Type': self.idl_type = type_node_to_type(child) elif child_class == 'ExtAttributes': - self.extended_attributes = ext_attributes_node_to_extended_attributes(child) + self.extended_attributes = ext_attributes_node_to_extended_attributes( + child) else: - raise ValueError('Unrecognized node class: %s' % child_class) + raise ValueError( + 'Unrecognized node class: %s' % child_class) if 'Unforgeable' in self.extended_attributes and self.is_static: - raise ValueError('[Unforgeable] cannot appear on static attributes.') + raise ValueError( + '[Unforgeable] cannot appear on static attributes.') def accept(self, visitor): visitor.visit_attribute(self) @@ -456,6 +516,7 @@ class IdlAttribute(TypedObject): # Constants ################################################################################ + class IdlConstant(TypedObject): def __init__(self, node): children = node.GetChildren() @@ -479,7 +540,8 @@ class IdlConstant(TypedObject): if num_children == 3: ext_attributes_node = children[2] - self.extended_attributes = ext_attributes_node_to_extended_attributes(ext_attributes_node) + self.extended_attributes = ext_attributes_node_to_extended_attributes( + ext_attributes_node) else: self.extended_attributes = {} @@ -491,6 +553,7 @@ class IdlConstant(TypedObject): # Literals ################################################################################ + class IdlLiteral(object): def __init__(self, idl_type, value): self.idl_type = idl_type @@ -548,6 +611,7 @@ def default_node_to_idl_literal(node): # Operations ################################################################################ + class IdlOperation(TypedObject): def __init__(self, node=None): self.arguments = [] @@ -579,12 +643,14 @@ class IdlOperation(TypedObject): elif child_class == 'Type': self.idl_type = type_node_to_type(child) elif child_class == 'ExtAttributes': - self.extended_attributes = ext_attributes_node_to_extended_attributes(child) + self.extended_attributes = ext_attributes_node_to_extended_attributes( + child) else: raise ValueError('Unrecognized node class: %s' % child_class) if 'Unforgeable' in self.extended_attributes and self.is_static: - raise ValueError('[Unforgeable] cannot appear on static operations.') + raise ValueError( + '[Unforgeable] cannot appear on static operations.') @classmethod def constructor_from_arguments_node(cls, name, arguments_node): @@ -604,6 +670,7 @@ class IdlOperation(TypedObject): # Arguments ################################################################################ + class IdlArgument(TypedObject): def __init__(self, node=None): self.extended_attributes = {} @@ -624,11 +691,14 @@ class IdlArgument(TypedObject): if child_class == 'Type': self.idl_type = type_node_to_type(child) elif child_class == 'ExtAttributes': - self.extended_attributes = ext_attributes_node_to_extended_attributes(child) + self.extended_attributes = ext_attributes_node_to_extended_attributes( + child) elif child_class == 'Argument': child_name = child.GetName() if child_name != '...': - raise ValueError('Unrecognized Argument node; expected "...", got "%s"' % child_name) + raise ValueError( + 'Unrecognized Argument node; expected "...", got "%s"' + % child_name) self.is_variadic = bool(child.GetProperty('ELLIPSIS')) elif child_class == 'Default': self.default_value = default_node_to_idl_literal(child) @@ -653,6 +723,7 @@ def arguments_node_to_arguments(node): # Stringifiers ################################################################################ + class IdlStringifier(object): def __init__(self, node): self.attribute = None @@ -668,7 +739,8 @@ class IdlStringifier(object): if operation.name: self.operation = operation elif child_class == 'ExtAttributes': - self.extended_attributes = ext_attributes_node_to_extended_attributes(child) + self.extended_attributes = ext_attributes_node_to_extended_attributes( + child) else: raise ValueError('Unrecognized node class: %s' % child_class) @@ -683,6 +755,7 @@ class IdlStringifier(object): # Iterable, Maplike, Setlike ################################################################################ + class IdlIterableOrMaplikeOrSetlike(TypedObject): def __init__(self, node): self.extended_attributes = {} @@ -691,7 +764,8 @@ class IdlIterableOrMaplikeOrSetlike(TypedObject): for child in node.GetChildren(): child_class = child.GetClass() if child_class == 'ExtAttributes': - self.extended_attributes = ext_attributes_node_to_extended_attributes(child) + self.extended_attributes = ext_attributes_node_to_extended_attributes( + child) elif child_class == 'Type': self.type_children.append(child) else: @@ -711,7 +785,8 @@ class IdlIterable(IdlIterableOrMaplikeOrSetlike): self.key_type = type_node_to_type(self.type_children[0]) self.value_type = type_node_to_type(self.type_children[1]) else: - raise ValueError('Unexpected number of type children: %d' % len(self.type_children)) + raise ValueError('Unexpected number of type children: %d' % len( + self.type_children)) del self.type_children def accept(self, visitor): @@ -730,7 +805,8 @@ class IdlMaplike(IdlIterableOrMaplikeOrSetlike): self.key_type = type_node_to_type(self.type_children[0]) self.value_type = type_node_to_type(self.type_children[1]) else: - raise ValueError('Unexpected number of children: %d' % len(self.type_children)) + raise ValueError( + 'Unexpected number of children: %d' % len(self.type_children)) del self.type_children def accept(self, visitor): @@ -738,7 +814,7 @@ class IdlMaplike(IdlIterableOrMaplikeOrSetlike): class IdlSetlike(IdlIterableOrMaplikeOrSetlike): - idl_type_attributes = ('value_type',) + idl_type_attributes = ('value_type', ) def __init__(self, node): super(IdlSetlike, self).__init__(node) @@ -748,7 +824,8 @@ class IdlSetlike(IdlIterableOrMaplikeOrSetlike): if len(self.type_children) == 1: self.value_type = type_node_to_type(self.type_children[0]) else: - raise ValueError('Unexpected number of children: %d' % len(self.type_children)) + raise ValueError( + 'Unexpected number of children: %d' % len(self.type_children)) del self.type_children def accept(self, visitor): @@ -759,6 +836,7 @@ class IdlSetlike(IdlIterableOrMaplikeOrSetlike): # Includes statements ################################################################################ + class IdlIncludes(object): def __init__(self, node): self.interface = node.GetName() @@ -772,12 +850,14 @@ class IdlIncludes(object): # Extended attributes ################################################################################ + class Exposure: """An Exposure holds one Exposed or RuntimeEnabled condition. Each exposure has two properties: exposed and runtime_enabled. Exposure(e, r) corresponds to [Exposed(e r)]. Exposure(e) corresponds to [Exposed=e]. """ + def __init__(self, exposed, runtime_enabled=None): self.exposed = exposed self.runtime_enabled = runtime_enabled @@ -801,8 +881,7 @@ def ext_attributes_node_to_extended_attributes(node): # overloading, and thus are stored in temporary lists. # However, Named Constructors cannot be overloaded, and thus do not have # a list. - # FIXME: move Constructor logic into separate function, instead of modifying - # extended attributes in-place. + # TODO(bashi): Remove |constructors| and |custom_constructors|. constructors = [] custom_constructors = [] extended_attributes = {} @@ -812,7 +891,9 @@ def ext_attributes_node_to_extended_attributes(node): if not children: return None if len(children) > 1: - raise ValueError('ExtAttributes node with %s children, expected at most 1' % len(children)) + raise ValueError( + 'ExtAttributes node with %s children, expected at most 1' % + len(children)) return children[0] extended_attribute_node_list = node.GetChildren() @@ -821,25 +902,29 @@ def ext_attributes_node_to_extended_attributes(node): child = child_node(extended_attribute_node) child_class = child and child.GetClass() if name == 'Constructor': - if child_class and child_class != 'Arguments': - raise ValueError('Constructor only supports Arguments as child, but has child of class: %s' % child_class) - constructors.append(child) + raise ValueError('[Constructor] is deprecated. Use constructor ' + 'operations') elif name == 'CustomConstructor': - if child_class and child_class != 'Arguments': - raise ValueError('[CustomConstructor] only supports Arguments as child, but has child of class: %s' % child_class) - custom_constructors.append(child) + raise ValueError('[CustomConstructor] is deprecated. Use ' + 'constructor operations with [Custom]') elif name == 'NamedConstructor': if child_class and child_class != 'Call': - raise ValueError('[NamedConstructor] only supports Call as child, but has child of class: %s' % child_class) + raise ValueError( + '[NamedConstructor] only supports Call as child, but has child of class: %s' + % child_class) extended_attributes[name] = child elif name == 'Exposed': if child_class and child_class != 'Arguments': - raise ValueError('[Exposed] only supports Arguments as child, but has child of class: %s' % child_class) + raise ValueError( + '[Exposed] only supports Arguments as child, but has child of class: %s' + % child_class) exposures = [] if child_class == 'Arguments': - exposures = [Exposure(exposed=str(arg.idl_type), - runtime_enabled=arg.name) - for arg in arguments_node_to_arguments(child)] + exposures = [ + Exposure( + exposed=str(arg.idl_type), runtime_enabled=arg.name) + for arg in arguments_node_to_arguments(child) + ] else: value = extended_attribute_node.GetProperty('VALUE') if type(value) is str: @@ -848,7 +933,8 @@ def ext_attributes_node_to_extended_attributes(node): exposures = [Exposure(exposed=v) for v in value] extended_attributes[name] = exposures elif child: - raise ValueError('ExtAttributes node with unexpected children: %s' % name) + raise ValueError( + 'ExtAttributes node with unexpected children: %s' % name) else: value = extended_attribute_node.GetProperty('VALUE') extended_attributes[name] = value @@ -869,15 +955,21 @@ def extended_attributes_to_constructors(extended_attributes): Auxiliary function for IdlInterface.__init__. """ + # TODO(bashi): Remove 'Constructors' and 'CustomConstructors'. + constructor_list = extended_attributes.get('Constructors', []) constructors = [ - IdlOperation.constructor_from_arguments_node('Constructor', arguments_node) - for arguments_node in constructor_list] + IdlOperation.constructor_from_arguments_node('Constructor', + arguments_node) + for arguments_node in constructor_list + ] custom_constructor_list = extended_attributes.get('CustomConstructors', []) custom_constructors = [ - IdlOperation.constructor_from_arguments_node('CustomConstructor', arguments_node) - for arguments_node in custom_constructor_list] + IdlOperation.constructor_from_arguments_node('CustomConstructor', + arguments_node) + for arguments_node in custom_constructor_list + ] if 'NamedConstructor' in extended_attributes: # FIXME: support overloaded named constructors, and make homogeneous @@ -886,15 +978,102 @@ def extended_attributes_to_constructors(extended_attributes): extended_attributes['NamedConstructor'] = call_node.GetName() children = call_node.GetChildren() if len(children) != 1: - raise ValueError('NamedConstructor node expects 1 child, got %s.' % len(children)) + raise ValueError('NamedConstructor node expects 1 child, got %s.' % + len(children)) arguments_node = children[0] - named_constructor = IdlOperation.constructor_from_arguments_node('NamedConstructor', arguments_node) + named_constructor = IdlOperation.constructor_from_arguments_node( + 'NamedConstructor', arguments_node) # FIXME: should return named_constructor separately; appended for Perl constructors.append(named_constructor) return constructors, custom_constructors +class ConstructorOperation(object): + """Represents a constructor operation. This is a tentative object used to + create constructors in IdlInterface. + """ + + def __init__(self, constructor, extended_attributes, is_custom): + self.constructor = constructor + self.extended_attributes = extended_attributes + self.is_custom = is_custom + + +def constructor_operation_from_node(node): + """Creates a ConstructorOperation from the given |node|. + """ + + arguments_node = None + extended_attributes = {} + + for child in node.GetChildren(): + child_class = child.GetClass() + if child_class == 'Arguments': + arguments_node = child + elif child_class == 'ExtAttributes': + extended_attributes = ext_attributes_node_to_extended_attributes( + child) + else: + raise ValueError('Unrecognized node class: %s' % child_class) + + if not arguments_node: + raise ValueError('Expected Arguments node for constructor operation') + + if 'Custom' in extended_attributes: + if extended_attributes['Custom']: + raise ValueError('[Custom] should not have a value on constructor ' + 'operations') + del extended_attributes['Custom'] + constructor = IdlOperation.constructor_from_arguments_node( + 'CustomConstructor', arguments_node) + return ConstructorOperation( + constructor, extended_attributes, is_custom=True) + else: + constructor = IdlOperation.constructor_from_arguments_node( + 'Constructor', arguments_node) + return ConstructorOperation( + constructor, extended_attributes, is_custom=False) + + +def check_constructor_operations_extended_attributes(current_attrs, new_attrs): + """Raises a ValueError if two extended attribute lists have different values + of constructor related attributes. + """ + + attrs_to_check = ['CallWith', 'RaisesException'] + for attr in attrs_to_check: + if current_attrs.get(attr) != new_attrs.get(attr): + raise ValueError('[{}] should have the same value on all ' + 'constructor operations'.format(attr)) + + +def convert_constructor_operations_extended_attributes(extended_attributes): + """Converts extended attributes specified on constructor operations to + extended attributes for an interface definition (e.g. [ConstructorCallWith]) + """ + + converted = {} + for name, value in extended_attributes.items(): + if name == "CallWith": + converted["ConstructorCallWith"] = value + elif name == "RaisesException": + if value: + raise ValueError( + '[RaisesException] should not have a value on ' + 'constructor operations') + converted["RaisesException"] = 'Constructor' + elif name == "MeasureAs": + converted["MeasureAs"] = value + elif name == "Measure": + converted["Measure"] = None + else: + raise ValueError( + '[{}] is not supported on constructor operations'.format(name)) + + return converted + + def clear_constructor_attributes(extended_attributes): # Deletes Constructor*s* (plural), sets Constructor (singular) if 'Constructors' in extended_attributes: @@ -909,14 +1088,17 @@ def clear_constructor_attributes(extended_attributes): # Types ################################################################################ + def type_node_to_type(node): children = node.GetChildren() if len(children) != 1 and len(children) != 2: - raise ValueError('Type node expects 1 or 2 child(ren), got %d.' % len(children)) + raise ValueError( + 'Type node expects 1 or 2 child(ren), got %d.' % len(children)) base_type = type_node_inner_to_type(children[0]) if len(children) == 2: - extended_attributes = ext_attributes_node_to_extended_attributes(children[1]) + extended_attributes = ext_attributes_node_to_extended_attributes( + children[1]) base_type = IdlAnnotatedType(base_type, extended_attributes) if node.GetProperty('NULLABLE'): @@ -950,21 +1132,25 @@ def type_node_inner_to_type(node): def record_node_to_type(node): children = node.GetChildren() if len(children) != 2: - raise ValueError('record<K,V> node expects exactly 2 children, got %d' % (len(children))) + raise ValueError('record<K,V> node expects exactly 2 children, got %d' + % (len(children))) key_child = children[0] value_child = children[1] if key_child.GetClass() != 'StringType': raise ValueError('Keys in record<K,V> nodes must be string types.') if value_child.GetClass() != 'Type': - raise ValueError('Unrecognized node class for record<K,V> value: %s' % value_child.GetClass()) - return IdlRecordType(IdlType(key_child.GetName()), type_node_to_type(value_child)) + raise ValueError('Unrecognized node class for record<K,V> value: %s' % + value_child.GetClass()) + return IdlRecordType( + IdlType(key_child.GetName()), type_node_to_type(value_child)) def sequence_node_to_type(node): children = node.GetChildren() class_name = node.GetClass() if len(children) != 1: - raise ValueError('%s node expects exactly 1 child, got %s' % (class_name, len(children))) + raise ValueError('%s node expects exactly 1 child, got %s' % + (class_name, len(children))) sequence_child = children[0] sequence_child_class = sequence_child.GetClass() if sequence_child_class != 'Type': @@ -984,7 +1170,8 @@ def sequence_node_to_type(node): def typedef_node_to_type(node): children = node.GetChildren() if len(children) != 1: - raise ValueError('Typedef node with %s children, expected 1' % len(children)) + raise ValueError( + 'Typedef node with %s children, expected 1' % len(children)) child = children[0] child_class = child.GetClass() if child_class != 'Type': @@ -993,8 +1180,10 @@ def typedef_node_to_type(node): def union_type_node_to_idl_union_type(node): - member_types = [type_node_to_type(member_type_node) - for member_type_node in node.GetChildren()] + member_types = [ + type_node_to_type(member_type_node) + for member_type_node in node.GetChildren() + ] return IdlUnionType(member_types) @@ -1002,6 +1191,7 @@ def union_type_node_to_idl_union_type(node): # Visitor ################################################################################ + class Visitor(object): """Abstract visitor class for IDL definitions traverse.""" diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions_test.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions_test.py index 78dd7320744..e2a91843a9a 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions_test.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_definitions_test.py @@ -3,7 +3,6 @@ # found in the LICENSE file. # pylint: disable=import-error,print-statement,relative-import - """Unit tests for idl_definitions.py.""" import unittest @@ -12,7 +11,6 @@ from idl_definitions import IdlAttribute class IdlAttributeTest(unittest.TestCase): - def test_no_params(self): try: IdlAttribute() diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py index 3b0895ed5b5..8d72865a6ca 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_reader.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Read an IDL file or complete IDL interface, producing an IdlDefinitions object. Design doc: @@ -56,28 +55,28 @@ def validate_blink_idl_definitions(idl_filename, idl_file_basename, definitions. There is no filename convention in this case. - Otherwise, an IDL file is invalid. """ - targets = (definitions.interfaces.values() + - definitions.dictionaries.values()) + targets = ( + definitions.interfaces.values() + definitions.dictionaries.values()) number_of_targets = len(targets) if number_of_targets > 1: raise Exception( - 'Expected exactly 1 definition in file {0}, but found {1}' - .format(idl_filename, number_of_targets)) + 'Expected exactly 1 definition in file {0}, but found {1}'.format( + idl_filename, number_of_targets)) if number_of_targets == 0: - number_of_definitions = ( - len(definitions.enumerations) + len(definitions.typedefs) + - len(definitions.callback_functions)) + number_of_definitions = (len(definitions.enumerations) + len( + definitions.typedefs) + len(definitions.callback_functions)) if number_of_definitions == 0: - raise Exception( - 'No definition found in %s' % idl_filename) + raise Exception('No definition found in %s. (Missing semicolon?)' % + idl_filename) return target = targets[0] if target.is_partial: return - if target.name != idl_file_basename and to_snake_case(target.name) != idl_file_basename: + if (target.name != idl_file_basename + and to_snake_case(target.name) != idl_file_basename): raise Exception( - 'Definition name "{0}" disagrees with IDL file basename "{1}".' - .format(target.name, idl_file_basename)) + 'Definition name "{0}" disagrees with IDL file basename "{1}".'. + format(target.name, idl_file_basename)) class IdlReader(object): @@ -86,7 +85,8 @@ class IdlReader(object): self.interfaces_info = interfaces_info if interfaces_info: - self.interface_dependency_resolver = InterfaceDependencyResolver(interfaces_info, self) + self.interface_dependency_resolver = InterfaceDependencyResolver( + interfaces_info, self) else: self.interface_dependency_resolver = None @@ -105,7 +105,8 @@ class IdlReader(object): if not definitions.interfaces: return {component: definitions} - return self.interface_dependency_resolver.resolve_dependencies(definitions, component) + return self.interface_dependency_resolver.resolve_dependencies( + definitions, component) def read_idl_file(self, idl_filename): """Returns an IdlDefinitions object for an IDL file, without any dependencies. @@ -119,15 +120,16 @@ class IdlReader(object): idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename)) definitions = IdlDefinitions(ast) - validate_blink_idl_definitions( - idl_filename, idl_file_basename, definitions) + validate_blink_idl_definitions(idl_filename, idl_file_basename, + definitions) # Validate extended attributes if not self.extended_attribute_validator: return definitions try: - self.extended_attribute_validator.validate_extended_attributes(definitions) + self.extended_attribute_validator.validate_extended_attributes( + definitions) except IDLInvalidExtendedAttributeError as error: raise IDLInvalidExtendedAttributeError(""" IDL ATTRIBUTE ERROR in file: diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py index acb20cf69e0..cd4f0c3513b 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_types.py @@ -18,7 +18,6 @@ IdlTypes are picklable because we store them in interfaces_info. from collections import defaultdict - ################################################################################ # IDL types ################################################################################ @@ -35,24 +34,26 @@ INTEGER_TYPES = frozenset([ 'long long', 'unsigned long long', ]) -NUMERIC_TYPES = (INTEGER_TYPES | frozenset([ - # http://www.w3.org/TR/WebIDL/#dfn-numeric-type - 'float', - 'unrestricted float', - 'double', - 'unrestricted double', -])) +NUMERIC_TYPES = ( + INTEGER_TYPES | frozenset([ + # http://www.w3.org/TR/WebIDL/#dfn-numeric-type + 'float', + 'unrestricted float', + 'double', + 'unrestricted double', + ])) # http://www.w3.org/TR/WebIDL/#dfn-primitive-type PRIMITIVE_TYPES = (frozenset(['boolean']) | NUMERIC_TYPES) -BASIC_TYPES = (PRIMITIVE_TYPES | frozenset([ - # Built-in, non-composite, non-object data types - # http://heycam.github.io/webidl/#idl-types - 'DOMString', - 'ByteString', - 'USVString', - # http://heycam.github.io/webidl/#idl-types - 'void', -])) +BASIC_TYPES = ( + PRIMITIVE_TYPES | frozenset([ + # Built-in, non-composite, non-object data types + # http://heycam.github.io/webidl/#idl-types + 'DOMString', + 'ByteString', + 'USVString', + # http://heycam.github.io/webidl/#idl-types + 'void', + ])) TYPE_NAMES = { # http://heycam.github.io/webidl/#dfn-type-name 'any': 'Any', @@ -84,8 +85,10 @@ STRING_TYPES = frozenset([ ]) EXTENDED_ATTRIBUTES_APPLICABLE_TO_TYPES = frozenset([ + 'AllowShared', 'Clamp', 'EnforceRange', + 'StringContext', 'TreatNullAs', ]) @@ -95,9 +98,10 @@ EXTENDED_ATTRIBUTES_APPLICABLE_TO_TYPES = frozenset([ ancestors = defaultdict(list) # interface_name -> ancestors + def inherits_interface(interface_name, ancestor_name): - return (interface_name == ancestor_name or - ancestor_name in ancestors[interface_name]) + return (interface_name == ancestor_name + or ancestor_name in ancestors[interface_name]) def set_ancestors(new_ancestors): @@ -105,11 +109,12 @@ def set_ancestors(new_ancestors): class IdlTypeBase(object): - """Base class for IdlType, IdlUnionType, IdlArrayOrSequenceType and IdlNullableType.""" + """Base class for IdlType, IdlUnionType, IdlArrayOrSequenceType + and IdlNullableType. + """ def __str__(self): - raise NotImplementedError( - '__str__() should be defined in subclasses') + raise NotImplementedError('__str__() should be defined in subclasses') def __getattr__(self, name): # Default undefined attributes to None (analogous to Jinja variables). @@ -131,6 +136,7 @@ class IdlTypeBase(object): # IdlType ################################################################################ + class IdlType(IdlTypeBase): # FIXME: incorporate Nullable, etc. # to support types like short?[] vs. short[]?, instead of treating these @@ -184,8 +190,8 @@ class IdlType(IdlTypeBase): @property def is_enum(self): - # FIXME: add an IdlEnumType class and a resolve_enums step at end of - # IdlDefinitions constructor + # FIXME: add an IdlEnumType class and a resolve_enums step + # at end of IdlDefinitions constructor return self.name in IdlType.enums @property @@ -218,13 +224,10 @@ class IdlType(IdlTypeBase): # http://www.w3.org/TR/WebIDL/#idl-types # http://www.w3.org/TR/WebIDL/#idl-interface # In C++ these are RefPtr types. - return not(self.is_basic_type or - self.is_callback_function or - self.is_dictionary or - self.is_enum or - self.name == 'Any' or - self.name == 'Object' or - self.name == 'Promise') # Promise will be basic in future + return not (self.is_basic_type or self.is_callback_function + or self.is_dictionary or self.is_enum or self.name == 'Any' + or self.name == 'Object' or self.name == 'Promise' + ) # Promise will be basic in future @property def is_string_type(self): @@ -256,15 +259,22 @@ class IdlType(IdlTypeBase): cls.enums.update(new_enums) def resolve_typedefs(self, typedefs): - # This function either returns |self| or a different object. - # FIXME: Rename typedefs_resolved(). - return typedefs.get(self.base_type, self) + base_type = self.base_type + if base_type in typedefs: + resolved_type = typedefs[base_type] + if resolved_type.base_type in typedefs: + raise ValueError("We can't typedef a typedef'ed type.") + # For the case that the resolved type contains other typedef'ed + # type(s). + return resolved_type.resolve_typedefs(typedefs) + return self ################################################################################ # IdlUnionType ################################################################################ + class IdlUnionType(IdlTypeBase): # http://heycam.github.io/webidl/#idl-union # IdlUnionType has __hash__() and __eq__() methods because they are stored @@ -274,7 +284,8 @@ class IdlUnionType(IdlTypeBase): self.member_types = member_types def __str__(self): - return '(' + ' or '.join(str(member_type) for member_type in self.member_types) + ')' + return '(' + ' or '.join( + str(member_type) for member_type in self.member_types) + ')' def __hash__(self): return hash(self.name) @@ -296,14 +307,16 @@ class IdlUnionType(IdlTypeBase): https://heycam.github.io/webidl/#dfn-flattened-union-member-types """ - # We cannot use a set directly because each member is an IdlTypeBase-derived class, and - # comparing two objects of the same type is not the same as comparing their names. In - # other words: + # We cannot use a set directly because each member is an + # IdlTypeBase-derived class, and comparing two objects of the + # same type is not the same as comparing their names. + # In other words: # x = IdlType('ByteString') # y = IdlType('ByteString') # x == y # False # x.name == y.name # True - # |flattened_members|'s keys are type names, the values are type |objects. + # |flattened_members|'s keys are type names, the values are type + # |objects|. # We assume we can use two IDL objects of the same type interchangeably. flattened_members = {} for member in self.member_types: @@ -344,8 +357,8 @@ class IdlUnionType(IdlTypeBase): @property def string_member_type(self): return self.single_matching_member_type( - lambda member_type: (member_type.is_string_type or - member_type.is_enum)) + lambda member_type: (member_type.is_string_type or member_type.is_enum) + ) @property def numeric_member_type(self): @@ -383,7 +396,8 @@ class IdlUnionType(IdlTypeBase): def resolve_typedefs(self, typedefs): self.member_types = [ member_type.resolve_typedefs(typedefs) - for member_type in self.member_types] + for member_type in self.member_types + ] return self def idl_types(self): @@ -397,6 +411,7 @@ class IdlUnionType(IdlTypeBase): # IdlArrayOrSequenceType, IdlSequenceType, IdlFrozenArrayType ################################################################################ + # TODO(bashi): Rename this like "IdlArrayTypeBase" or something. class IdlArrayOrSequenceType(IdlTypeBase): """Base class for array-like types.""" @@ -479,6 +494,7 @@ class IdlFrozenArrayType(IdlArrayOrSequenceType): # IdlRecordType ################################################################################ + class IdlRecordType(IdlTypeBase): def __init__(self, key_type, value_type): super(IdlRecordType, self).__init__() @@ -523,6 +539,7 @@ class IdlRecordType(IdlTypeBase): # IdlNullableType ################################################################################ + # https://heycam.github.io/webidl/#idl-nullable-type class IdlNullableType(IdlTypeBase): def __init__(self, inner_type): @@ -599,9 +616,11 @@ class IdlNullableType(IdlTypeBase): # IdlAnnotatedType ################################################################################ + class IdlAnnotatedType(IdlTypeBase): """IdlAnnoatedType represents an IDL type with extended attributes. - [Clamp], [EnforceRange], and [TreatNullAs] are applicable to types. + [Clamp], [EnforceRange], [StringContext], and [TreatNullAs] are applicable + to types. https://heycam.github.io/webidl/#idl-annotated-types """ @@ -612,11 +631,18 @@ class IdlAnnotatedType(IdlTypeBase): if any(key not in EXTENDED_ATTRIBUTES_APPLICABLE_TO_TYPES for key in extended_attributes): - raise ValueError('Extended attributes not applicable to types: %s' % self) + raise ValueError( + 'Extended attributes not applicable to types: %s' % self) + + if ('StringContext' in extended_attributes + and inner_type.base_type not in ['DOMString', 'USVString']): + raise ValueError( + 'StringContext is only applicable to string types.') def __str__(self): - annotation = ', '.join((key + ('' if val is None else '=' + val)) - for key, val in self.extended_attributes.iteritems()) + annotation = ', '.join( + (key + ('' if val is None else '=' + val)) + for key, val in self.extended_attributes.items()) return '[%s] %s' % (annotation, str(self.inner_type)) def __getattr__(self, name): @@ -637,9 +663,14 @@ class IdlAnnotatedType(IdlTypeBase): return True @property + def has_string_context(self): + return 'StringContext' in self.extended_attributes + + @property def name(self): - annotation = ''.join((key + ('' if val is None else val)) - for key, val in sorted(self.extended_attributes.iteritems())) + annotation = ''.join( + (key + ('' if val is None else val)) + for key, val in sorted(self.extended_attributes.items())) return self.inner_type.name + annotation def resolve_typedefs(self, typedefs): diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_types_test.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_types_test.py index 2948ca9922f..519fbcf84e8 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/idl_types_test.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_types_test.py @@ -3,7 +3,6 @@ # found in the LICENSE file. # pylint: disable=import-error,print-statement,relative-import - """Unit tests for idl_types.py.""" import unittest @@ -16,7 +15,6 @@ from idl_types import IdlUnionType class IdlTypeTest(unittest.TestCase): - def test_is_void(self): idl_type = IdlType('void') self.assertTrue(idl_type.is_void) @@ -25,7 +23,6 @@ class IdlTypeTest(unittest.TestCase): class IdlRecordTypeTest(unittest.TestCase): - def test_idl_types(self): idl_type = IdlRecordType(IdlType('USVString'), IdlType('long')) idl_types = list(idl_type.idl_types()) @@ -33,21 +30,28 @@ class IdlRecordTypeTest(unittest.TestCase): self.assertIs(idl_types[0], idl_type) self.assertEqual(idl_types[1].name, 'USVString') self.assertEqual(idl_types[2].name, 'Long') - self.assertListEqual(list(idl_type.idl_types()), - [idl_type, idl_type.key_type, idl_type.value_type]) + self.assertListEqual( + list(idl_type.idl_types()), + [idl_type, idl_type.key_type, idl_type.value_type]) - idl_type = IdlRecordType(IdlType('DOMString'), IdlSequenceType(IdlType('unrestricted float'))) + idl_type = IdlRecordType( + IdlType('DOMString'), IdlSequenceType( + IdlType('unrestricted float'))) idl_types = list(idl_type.idl_types()) self.assertEqual(len(idl_types), 4) self.assertIs(idl_types[0], idl_type) self.assertEqual(idl_types[1].name, 'String') self.assertEqual(idl_types[2].name, 'UnrestrictedFloatSequence') self.assertEqual(idl_types[3].name, 'UnrestrictedFloat') - self.assertListEqual(list(idl_type.idl_types()), - [idl_type, idl_type.key_type, idl_type.value_type, idl_type.value_type.element_type]) - - idl_type = IdlRecordType(IdlType('ByteString'), - IdlRecordType(IdlType('DOMString'), IdlType('octet'))) + self.assertListEqual( + list(idl_type.idl_types()), [ + idl_type, idl_type.key_type, idl_type.value_type, + idl_type.value_type.element_type + ]) + + idl_type = IdlRecordType( + IdlType('ByteString'), + IdlRecordType(IdlType('DOMString'), IdlType('octet'))) idl_types = list(idl_type.idl_types()) self.assertEqual(len(idl_types), 5) self.assertIs(idl_types[0], idl_type) @@ -55,38 +59,48 @@ class IdlRecordTypeTest(unittest.TestCase): self.assertEqual(idl_types[2].name, 'StringOctetRecord') self.assertEqual(idl_types[3].name, 'String') self.assertEqual(idl_types[4].name, 'Octet') - self.assertListEqual(list(idl_type.idl_types()), - [idl_type, idl_type.key_type, idl_type.value_type, idl_type.value_type.key_type, - idl_type.value_type.value_type]) + self.assertListEqual( + list(idl_type.idl_types()), [ + idl_type, idl_type.key_type, idl_type.value_type, + idl_type.value_type.key_type, idl_type.value_type.value_type + ]) def test_is_record(self): idl_type = IdlType('USVString') self.assertFalse(idl_type.is_record_type) - idl_type = IdlSequenceType(IdlRecordType(IdlType('DOMString'), IdlType('byte'))) + idl_type = IdlSequenceType( + IdlRecordType(IdlType('DOMString'), IdlType('byte'))) self.assertFalse(idl_type.is_record_type) idl_type = IdlRecordType(IdlType('USVString'), IdlType('long')) self.assertTrue(idl_type.is_record_type) - idl_type = IdlRecordType(IdlType('USVString'), IdlSequenceType(IdlType('boolean'))) + idl_type = IdlRecordType( + IdlType('USVString'), IdlSequenceType(IdlType('boolean'))) self.assertTrue(idl_type.is_record_type) def test_name(self): idl_type = IdlRecordType(IdlType('ByteString'), IdlType('octet')) self.assertEqual(idl_type.name, 'ByteStringOctetRecord') - idl_type = IdlRecordType(IdlType('USVString'), IdlSequenceType(IdlType('double'))) + idl_type = IdlRecordType( + IdlType('USVString'), IdlSequenceType(IdlType('double'))) self.assertEqual(idl_type.name, 'USVStringDoubleSequenceRecord') - idl_type = IdlRecordType(IdlType('DOMString'), - IdlRecordType(IdlType('ByteString'), - IdlSequenceType(IdlType('unsigned short')))) - self.assertEqual(idl_type.name, 'StringByteStringUnsignedShortSequenceRecordRecord') + idl_type = IdlRecordType( + IdlType('DOMString'), + IdlRecordType( + IdlType('ByteString'), + IdlSequenceType(IdlType('unsigned short')))) + self.assertEqual(idl_type.name, + 'StringByteStringUnsignedShortSequenceRecordRecord') class IdlUnionTypeTest(unittest.TestCase): - def test_flattened_member_types(self): - # We are only testing the algorithm here, so we do create some ambiguous union types. + # We are only testing the algorithm here, so we do create some + # ambiguous union types. def compare_flattened_members(actual, expected): - """Compare a set of IDL types by name, as the objects are different""" + """Compare a set of IDL types by name, as the objects + are different + """ actual_names = set([member.name for member in actual]) expected_names = set([member.name for member in expected]) self.assertEqual(actual_names, expected_names) @@ -96,46 +110,80 @@ class IdlUnionTypeTest(unittest.TestCase): idl_type.flattened_member_types, set([IdlType('long'), IdlType('SomeInterface')])) - idl_type = IdlUnionType([IdlUnionType([IdlType('ByteString'), IdlType('float')]), - IdlType('boolean')]) + idl_type = IdlUnionType([ + IdlUnionType([IdlType('ByteString'), + IdlType('float')]), + IdlType('boolean') + ]) compare_flattened_members( idl_type.flattened_member_types, - set([IdlType('float'), IdlType('boolean'), IdlType('ByteString')])) - - idl_type = IdlUnionType([IdlUnionType([IdlType('ByteString'), IdlType('DOMString')]), - IdlType('DOMString')]) + set([IdlType('float'), + IdlType('boolean'), + IdlType('ByteString')])) + + idl_type = IdlUnionType([ + IdlUnionType([IdlType('ByteString'), + IdlType('DOMString')]), + IdlType('DOMString') + ]) compare_flattened_members( idl_type.flattened_member_types, - set([IdlType('DOMString'), IdlType('ByteString')])) + set([IdlType('DOMString'), + IdlType('ByteString')])) idl_type = IdlUnionType( - [IdlNullableType(IdlType('ByteString')), IdlType('byte')]) + [IdlNullableType(IdlType('ByteString')), + IdlType('byte')]) compare_flattened_members( idl_type.flattened_member_types, set([IdlType('ByteString'), IdlType('byte')])) - idl_type = IdlUnionType( - [IdlNullableType(IdlType('ByteString')), IdlType('byte'), - IdlUnionType([IdlType('ByteString'), IdlType('float')])]) + idl_type = IdlUnionType([ + IdlNullableType(IdlType('ByteString')), + IdlType('byte'), + IdlUnionType([IdlType('ByteString'), + IdlType('float')]) + ]) self.assertEqual(len(idl_type.flattened_member_types), 3) compare_flattened_members( idl_type.flattened_member_types, - set([IdlType('ByteString'), IdlType('byte'), IdlType('float')])) - - # From the example in the spec: "the flattened member types of the union type (Node or (sequence<long> or Event) or - # (XMLHttpRequest or DOMString)? or sequence<(sequence<double> or NodeList)>) are the six types Node, sequence<long>, - # Event, XMLHttpRequest, DOMString and sequence<(sequence<double> or NodeList)>" - idl_type = IdlUnionType( - [IdlType('Node'), - IdlUnionType([IdlSequenceType(IdlType('long')), IdlType('Event')]), - IdlNullableType(IdlUnionType([IdlType('XMLHttpRequest'), IdlType('DOMString')])), - IdlSequenceType(IdlUnionType([IdlSequenceType(IdlType('double')), IdlType('NodeList')]))]) + set([IdlType('ByteString'), + IdlType('byte'), + IdlType('float')])) + + # From the example in the spec: "the flattened member types of the + # union type (Node or (sequence<long> or Event) or + # (XMLHttpRequest or DOMString)? or + # sequence<(sequence<double> or NodeList)>) are the six types Node, + # sequence<long>, Event, XMLHttpRequest, DOMString and + # sequence<(sequence<double> or NodeList)>" + idl_type = IdlUnionType([ + IdlType('Node'), + IdlUnionType([IdlSequenceType(IdlType('long')), + IdlType('Event')]), + IdlNullableType( + IdlUnionType([IdlType('XMLHttpRequest'), + IdlType('DOMString')])), + IdlSequenceType( + IdlUnionType( + [IdlSequenceType(IdlType('double')), + IdlType('NodeList')])) + ]) self.assertEqual(len(idl_type.flattened_member_types), 6) compare_flattened_members( idl_type.flattened_member_types, - set([IdlType('Node'), IdlSequenceType(IdlType('long')), IdlType('Event'), - IdlType('XMLHttpRequest'), IdlType('DOMString'), - IdlSequenceType(IdlUnionType([IdlSequenceType(IdlType('double')), IdlType('NodeList')]))])) + set([ + IdlType('Node'), + IdlSequenceType(IdlType('long')), + IdlType('Event'), + IdlType('XMLHttpRequest'), + IdlType('DOMString'), + IdlSequenceType( + IdlUnionType([ + IdlSequenceType(IdlType('double')), + IdlType('NodeList') + ])) + ])) def test_resolve_typedefs(self): # This is a simplification of the typedef mechanism to avoid having to @@ -147,13 +195,17 @@ class IdlUnionTypeTest(unittest.TestCase): } # (long long or MyBooleanType) - union = IdlUnionType([IdlType('long long'), IdlType('MyBooleanType')]).resolve_typedefs(typedefs) + union = IdlUnionType( + [IdlType('long long'), + IdlType('MyBooleanType')]).resolve_typedefs(typedefs) self.assertEqual(union.name, 'LongLongOrBoolean') self.assertEqual(union.member_types[0].name, 'LongLong') self.assertEqual(union.member_types[1].name, 'Boolean') # (Foo or SomeInterfaceT) - union = IdlUnionType([IdlType('Foo'), IdlType('SomeInterfaceT')]).resolve_typedefs(typedefs) + union = IdlUnionType( + [IdlType('Foo'), + IdlType('SomeInterfaceT')]).resolve_typedefs(typedefs) self.assertEqual(union.name, 'UnsignedShortOrMyInterface') self.assertEqual(union.member_types[0].name, 'UnsignedShort') self.assertEqual(union.member_types[1].name, 'MyInterface') @@ -161,16 +213,19 @@ class IdlUnionTypeTest(unittest.TestCase): # (Foo or sequence<(MyBooleanType or double)>) union = IdlUnionType([ IdlType('Foo'), - IdlSequenceType(IdlUnionType([IdlType('MyBooleanType'), - IdlType('double')]))]).resolve_typedefs(typedefs) + IdlSequenceType( + IdlUnionType([IdlType('MyBooleanType'), + IdlType('double')])) + ]).resolve_typedefs(typedefs) self.assertEqual(union.name, 'UnsignedShortOrBooleanOrDoubleSequence') self.assertEqual(union.member_types[0].name, 'UnsignedShort') self.assertEqual(union.member_types[1].name, 'BooleanOrDoubleSequence') - self.assertEqual(union.member_types[1].element_type.name, 'BooleanOrDouble') - self.assertEqual(union.member_types[1].element_type.member_types[0].name, - 'Boolean') - self.assertEqual(union.member_types[1].element_type.member_types[1].name, - 'Double') + self.assertEqual(union.member_types[1].element_type.name, + 'BooleanOrDouble') + self.assertEqual( + union.member_types[1].element_type.member_types[0].name, 'Boolean') + self.assertEqual( + union.member_types[1].element_type.member_types[1].name, 'Double') self.assertEqual(2, len(union.flattened_member_types)) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/idl_validator.py b/chromium/third_party/blink/renderer/bindings/scripts/idl_validator.py index 85de1cc1d83..64e84ef7da1 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/idl_validator.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/idl_validator.py @@ -25,13 +25,11 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Validate extended attributes. Design doc: http://www.chromium.org/developers/design-documents/idl-compiler#TOC-Extended-attribute-validation """ - import os.path import re @@ -42,6 +40,7 @@ EXTENDED_ATTRIBUTES_RELATIVE_PATH = os.path.join('bindings', EXTENDED_ATTRIBUTES_FILENAME = os.path.join(source_path, EXTENDED_ATTRIBUTES_RELATIVE_PATH) + class IDLInvalidExtendedAttributeError(Exception): pass @@ -52,7 +51,7 @@ class IDLExtendedAttributeValidator(object): def validate_extended_attributes(self, definitions): # FIXME: this should be done when parsing the file, rather than after. - for interface in definitions.interfaces.itervalues(): + for interface in definitions.interfaces.values(): self.validate_extended_attributes_node(interface) for attribute in interface.attributes: self.validate_extended_attributes_node(attribute) @@ -60,18 +59,17 @@ class IDLExtendedAttributeValidator(object): self.validate_extended_attributes_node(operation) for argument in operation.arguments: self.validate_extended_attributes_node(argument) - for dictionary in definitions.dictionaries.itervalues(): + for dictionary in definitions.dictionaries.values(): self.validate_extended_attributes_node(dictionary) for member in dictionary.members: self.validate_extended_attributes_node(member) - for callback_function in definitions.callback_functions.itervalues(): + for callback_function in definitions.callback_functions.values(): self.validate_extended_attributes_node(callback_function) for argument in callback_function.arguments: self.validate_extended_attributes_node(argument) - def validate_extended_attributes_node(self, node): - for name, values_string in node.extended_attributes.iteritems(): + for name, values_string in node.extended_attributes.items(): self.validate_name_values_string(name, values_string) def validate_name_values_string(self, name, values_string): @@ -106,7 +104,9 @@ def read_extended_attributes_file(): if not line or line.startswith('#'): continue name, _, values_string = map(str.strip, line.partition('=')) - value_list = [value.strip() for value in values_string.split('|')] + value_list = [ + value.strip() for value in values_string.split('|') + ] yield name, value_list valid_extended_attributes = {} @@ -114,6 +114,6 @@ def read_extended_attributes_file(): if not value_list: valid_extended_attributes[name] = set([None]) continue - valid_extended_attributes[name] = set([value if value else None - for value in value_list]) + valid_extended_attributes[name] = set( + [value if value else None for value in value_list]) return valid_extended_attributes diff --git a/chromium/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py b/chromium/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py index ebd88a668ec..030ca1c9f9c 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Resolve interface dependencies, producing a merged IdlDefinitions object. This library computes interface dependencies (partial interfaces and @@ -102,7 +101,7 @@ class InterfaceDependencyResolver(object): 'this definition: %s, because this should ' 'have a dictionary.' % definitions.idl_name) - target_interface = next(definitions.interfaces.itervalues()) + target_interface = next(iter(definitions.interfaces.values())) interface_name = target_interface.name interface_info = self.interfaces_info[interface_name] @@ -111,34 +110,36 @@ class InterfaceDependencyResolver(object): interface_info['inherited_extended_attributes']) resolved_definitions = merge_interface_dependencies( - definitions, - component, - target_interface, + definitions, component, target_interface, interface_info['dependencies_full_paths'] + interface_info['dependencies_other_component_full_paths'], self.reader) - inherit_unforgeable_attributes(resolved_definitions, self.interfaces_info) + inherit_unforgeable_attributes(resolved_definitions, + self.interfaces_info) - for referenced_interface_name in interface_info['referenced_interfaces']: + for referenced_interface_name in \ + interface_info['referenced_interfaces']: referenced_definitions = self.reader.read_idl_definitions( self.interfaces_info[referenced_interface_name]['full_path']) for referenced_component in referenced_definitions: - if not is_valid_component_dependency(component, referenced_component): + if not is_valid_component_dependency(component, + referenced_component): raise Exception('This definitions: %s is defined in %s ' 'but reference interface:%s is defined ' - 'in %s' % (definitions.idl_name, - component, + 'in %s' % (definitions.idl_name, component, referenced_interface_name, referenced_component)) - resolved_definitions[component].update(referenced_definitions[component]) + resolved_definitions[component].update( + referenced_definitions[component]) return resolved_definitions -def merge_interface_dependencies(definitions, component, target_interface, dependency_idl_filenames, reader): +def merge_interface_dependencies(definitions, component, target_interface, + dependency_idl_filenames, reader): """Merge dependencies ('partial interface' and 'implements') in dependency_idl_filenames into target_interface. Args: @@ -158,9 +159,11 @@ def merge_interface_dependencies(definitions, component, target_interface, depen # Sort so order consistent, so can compare output from run to run. for dependency_idl_filename in sorted(dependency_idl_filenames): dependency_definitions = reader.read_idl_file(dependency_idl_filename) - dependency_component = idl_filename_to_component(dependency_idl_filename) + dependency_component = idl_filename_to_component( + dependency_idl_filename) - dependency_interface = next(dependency_definitions.interfaces.itervalues()) + dependency_interface = next( + iter(dependency_definitions.interfaces.values())) transfer_extended_attributes(dependency_interface, dependency_idl_filename) @@ -176,12 +179,13 @@ def merge_interface_dependencies(definitions, component, target_interface, depen # However, # - A partial interface defined in core cannot update # the original interface defined in modules. - if not is_valid_component_dependency(dependency_component, component): - raise Exception('The partial interface:%s in %s cannot update ' - 'the original interface:%s in %s' % (dependency_interface.name, - dependency_component, - target_interface.name, - component)) + if not is_valid_component_dependency(dependency_component, + component): + raise Exception( + 'The partial interface:%s in %s cannot update ' + 'the original interface:%s in %s' % + (dependency_interface.name, dependency_component, + target_interface.name, component)) if dependency_component in resolved_definitions: # When merging a new partial interfaces, should not overwrite @@ -189,12 +193,16 @@ def merge_interface_dependencies(definitions, component, target_interface, depen # interface. # See also the below "if 'ImplementedAs' not in ... " line's # comment. - dependency_interface.extended_attributes.pop('ImplementedAs', None) - resolved_definitions[dependency_component].update(dependency_definitions) + dependency_interface.extended_attributes.pop( + 'ImplementedAs', None) + resolved_definitions[dependency_component].update( + dependency_definitions) continue - dependency_interface.extended_attributes.update(target_interface.extended_attributes) - assert target_interface == definitions.interfaces[dependency_interface.name] + dependency_interface.extended_attributes.update( + target_interface.extended_attributes) + assert target_interface == \ + definitions.interfaces[dependency_interface.name] # A partial interface should use its original interface's # ImplementedAs. If the original interface doesn't have, # remove ImplementedAs defined in the partial interface. @@ -208,7 +216,8 @@ def merge_interface_dependencies(definitions, component, target_interface, depen # files correctly. ImplementedAs should not be allowed in # partial interfaces. if 'ImplementedAs' not in target_interface.extended_attributes: - dependency_interface.extended_attributes.pop('ImplementedAs', None) + dependency_interface.extended_attributes.pop( + 'ImplementedAs', None) dependency_interface.original_interface = target_interface target_interface.partial_interfaces.append(dependency_interface) resolved_definitions[dependency_component] = dependency_definitions @@ -221,20 +230,21 @@ def merge_interface_dependencies(definitions, component, target_interface, depen # - An interface defined in core cannot include an interface mixin # defined in modules. if not dependency_interface.is_mixin: - raise Exception('The interface:%s cannot include ' - 'the non-mixin interface: %s.' % ( - target_interface.name, - dependency_interface.name)) - - if not is_valid_component_dependency(component, dependency_component): - raise Exception('The interface:%s in %s cannot include ' - 'the interface mixin:%s in %s.' % ( - target_interface.name, - component, - dependency_interface.name, - dependency_component)) - - resolved_definitions[component].update(dependency_definitions) # merges partial interfaces + raise Exception( + 'The interface:%s cannot include ' + 'the non-mixin interface: %s.' % + (target_interface.name, dependency_interface.name)) + + if not is_valid_component_dependency(component, + dependency_component): + raise Exception( + 'The interface:%s in %s cannot include ' + 'the interface mixin:%s in %s.' % + (target_interface.name, component, + dependency_interface.name, dependency_component)) + + # merges partial interfaces + resolved_definitions[component].update(dependency_definitions) # Mixins are also merged into the target interface, so Code # Generator can just iterate over one list (and not need to handle # 'includes' itself). @@ -243,7 +253,8 @@ def merge_interface_dependencies(definitions, component, target_interface, depen return resolved_definitions -def transfer_extended_attributes(dependency_interface, dependency_idl_filename): +def transfer_extended_attributes(dependency_interface, + dependency_idl_filename): """Transfer extended attributes from dependency interface onto members. Merging consists of storing certain interface-level data in extended @@ -263,7 +274,8 @@ def transfer_extended_attributes(dependency_interface, dependency_idl_filename): if key not in dependency_interface.extended_attributes: continue - merged_extended_attributes[key] = dependency_interface.extended_attributes[key] + merged_extended_attributes[key] = \ + dependency_interface.extended_attributes[key] # Remove the merged attributes from the original dependency interface. # This ensures that if other dependency interfaces are merged onto this # one, its extended_attributes do not leak through @@ -307,11 +319,14 @@ def transfer_extended_attributes(dependency_interface, dependency_idl_filename): attributes[key] = value for attribute in dependency_interface.attributes: - update_attributes(attribute.extended_attributes, merged_extended_attributes) + update_attributes(attribute.extended_attributes, + merged_extended_attributes) for constant in dependency_interface.constants: - update_attributes(constant.extended_attributes, merged_extended_attributes) + update_attributes(constant.extended_attributes, + merged_extended_attributes) for operation in dependency_interface.operations: - update_attributes(operation.extended_attributes, merged_extended_attributes) + update_attributes(operation.extended_attributes, + merged_extended_attributes) def inherit_unforgeable_attributes(resolved_definitions, interfaces_info): @@ -322,35 +337,47 @@ def inherit_unforgeable_attributes(resolved_definitions, interfaces_info): 'referenced_interfaces' and 'cpp_includes' in |interfaces_info| are updated accordingly. """ + def collect_unforgeable_attributes_in_ancestors(interface_name, component): if not interface_name: # unforgeable_attributes, referenced_interfaces, cpp_includes return [], [], set() interface = interfaces_info[interface_name] - unforgeable_attributes, referenced_interfaces, cpp_includes = collect_unforgeable_attributes_in_ancestors(interface.get('parent'), component) + unforgeable_attributes, referenced_interfaces, cpp_includes = \ + collect_unforgeable_attributes_in_ancestors( + interface.get('parent'), component) this_unforgeable = interface.get('unforgeable_attributes', []) for attr in this_unforgeable: if attr.defined_in is None: attr.defined_in = interface_name unforgeable_attributes.extend(this_unforgeable) - this_referenced = [attr.idl_type.base_type for attr in this_unforgeable - if attr.idl_type.base_type in - interface.get('referenced_interfaces', [])] + this_referenced = [ + attr.idl_type.base_type for attr in this_unforgeable + if attr.idl_type.base_type in interface.get( + 'referenced_interfaces', []) + ] referenced_interfaces.extend(this_referenced) - cpp_includes.update(interface.get('cpp_includes', {}).get(component, {})) + cpp_includes.update( + interface.get('cpp_includes', {}).get(component, {})) return unforgeable_attributes, referenced_interfaces, cpp_includes - for component, definitions in resolved_definitions.iteritems(): - for interface_name, interface in definitions.interfaces.iteritems(): + for component, definitions in resolved_definitions.items(): + for interface_name, interface in definitions.interfaces.items(): interface_info = interfaces_info[interface_name] - inherited_unforgeable_attributes, referenced_interfaces, cpp_includes = collect_unforgeable_attributes_in_ancestors(interface_info.get('parent'), component) + inherited_unforgeable_attributes, referenced_interfaces, cpp_includes = \ + collect_unforgeable_attributes_in_ancestors( + interface_info.get('parent'), component) # This loop may process the same interface many times, so it's # possible that we're adding the same attributes twice or more. # So check if there is a duplicate. for attr in inherited_unforgeable_attributes: if attr not in interface.attributes: interface.attributes.append(attr) - referenced_interfaces.extend(interface_info.get('referenced_interfaces', [])) - interface_info['referenced_interfaces'] = sorted(set(referenced_interfaces)) + referenced_interfaces.extend( + interface_info.get('referenced_interfaces', [])) + interface_info['referenced_interfaces'] = sorted( + set(referenced_interfaces)) merge_dict_recursively(interface_info, - {'cpp_includes': {component: cpp_includes}}) + {'cpp_includes': { + component: cpp_includes + }}) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm.py b/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm.py index 351ca8e40ed..309de695493 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm.py @@ -182,11 +182,12 @@ def method_overloads_by_name(methods): """Returns generator of overloaded methods by name: [name, [method]]""" # Filter to only methods that are actually overloaded method_counts = Counter(method['name'] for method in methods) - overloaded_method_names = set(name - for name, count in method_counts.iteritems() - if count > 1) - overloaded_methods = [method for method in methods - if method['name'] in overloaded_method_names] + overloaded_method_names = set( + name for name, count in method_counts.items() if count > 1) + overloaded_methods = [ + method for method in methods + if method['name'] in overloaded_method_names + ] # Group by name (generally will be defined together, but not necessarily) return sort_and_groupby(overloaded_methods, itemgetter('name')) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm_test.py b/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm_test.py index 44ccd2095b1..3a94c06e615 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm_test.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/overload_set_algorithm_test.py @@ -3,12 +3,14 @@ # found in the LICENSE file. # pylint: disable=import-error,print-statement,relative-import,protected-access - """Unit tests for overload_set_algorithm.py.""" import unittest from overload_set_algorithm import effective_overload_set +# disabling yapf formating for complex data, see +# https://github.com/google/yapf#why-does-yapf-destroy-my-awesome-formatting +# yapf: disable class EffectiveOverloadSetTest(unittest.TestCase): def test_example_in_comments(self): @@ -334,3 +336,4 @@ class EffectiveOverloadSetTest(unittest.TestCase): ())] self.assertEqual(effective_overload_set(operation_list), overload_set) +# yapf: enable diff --git a/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni b/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni index 00a0b2a5ce5..9f1b79be3e6 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni +++ b/chromium/third_party/blink/renderer/bindings/scripts/scripts.gni @@ -125,9 +125,7 @@ template("generate_event_interfaces") { output_file = "$root_gen_dir/third_party/blink/renderer/" + invoker.output_file - outputs = [ - output_file, - ] + outputs = [ output_file ] script = "//third_party/blink/renderer/bindings/scripts/generate_event_interfaces.py" args = [ @@ -161,7 +159,9 @@ template("idl_compiler") { # "import site" to speed up startup. Figure out if we need this and do # something similar (not really expressible in GN now). _script = "//third_party/blink/renderer/bindings/scripts/idl_compiler.py" - _inputs = idl_lexer_parser_files + idl_compiler_files # to be explicit (covered by parsetab) + _inputs = + idl_lexer_parser_files + idl_compiler_files # to be explicit (covered by + # parsetab) _inputs += [ "$bindings_scripts_output_dir/lextab.py", "$bindings_scripts_output_dir/parsetab.pickle", @@ -250,7 +250,9 @@ template("idl_impl") { idl_files_list = "$target_gen_dir/${target_name}_file_list.tmp" write_file(idl_files_list, rebase_path(invoker.dict_idls, root_build_dir)) - inputs = idl_lexer_parser_files + idl_compiler_files # to be explicit (covered by parsetab) + inputs = + idl_lexer_parser_files + idl_compiler_files # to be explicit (covered + # by parsetab) inputs += [ "$bindings_scripts_output_dir/lextab.py", "$bindings_scripts_output_dir/parsetab.pickle", @@ -342,9 +344,7 @@ template("compute_global_objects") { idl_files_list, ] + invoker.sources_generated + invoker.sources - outputs = [ - invoker.output_file, - ] + outputs = [ invoker.output_file ] args = [ "--idl-files-list", diff --git a/chromium/third_party/blink/renderer/bindings/scripts/utilities.py b/chromium/third_party/blink/renderer/bindings/scripts/utilities.py index ebca696912d..1dc06544585 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/utilities.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/utilities.py @@ -1,24 +1,25 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Utility functions (file reading, simple IDL parsing by regexes) for IDL build. Design doc: http://www.chromium.org/developers/design-documents/idl-build """ import os -import cPickle as pickle import re import shlex -import string import subprocess import sys -sys.path.append(os.path.join(os.path.dirname(__file__), - '..', '..', 'build', 'scripts')) -from blinkbuild.name_style_converter import NameStyleConverter +if sys.version_info.major == 2: + import cPickle as pickle +else: + import pickle +sys.path.append( + os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'scripts')) +from blinkbuild.name_style_converter import NameStyleConverter KNOWN_COMPONENTS = frozenset(['core', 'modules']) KNOWN_COMPONENTS_WITH_TESTING = frozenset(['core', 'modules', 'testing']) @@ -29,7 +30,8 @@ def idl_filename_to_basename(idl_filename): return os.path.splitext(os.path.basename(idl_filename))[0] -def idl_filename_to_component_with_known_components(idl_filename, known_components): +def idl_filename_to_component_with_known_components(idl_filename, + known_components): path = os.path.dirname(os.path.realpath(idl_filename)) while path: dirname, basename = os.path.split(path) @@ -42,11 +44,13 @@ def idl_filename_to_component_with_known_components(idl_filename, known_componen def idl_filename_to_component(idl_filename): - return idl_filename_to_component_with_known_components(idl_filename, KNOWN_COMPONENTS) + return idl_filename_to_component_with_known_components( + idl_filename, KNOWN_COMPONENTS) def is_testing_target(idl_filename): - component = idl_filename_to_component_with_known_components(idl_filename, KNOWN_COMPONENTS_WITH_TESTING) + component = idl_filename_to_component_with_known_components( + idl_filename, KNOWN_COMPONENTS_WITH_TESTING) return component == 'testing' @@ -69,6 +73,7 @@ class ComponentInfoProvider(object): """Base class of information provider which provides component-specific information. """ + def __init__(self): pass @@ -176,11 +181,14 @@ class ComponentInfoProviderModules(ComponentInfoProvider): def union_types(self): # Remove duplicate union types from component_info_modules to avoid # generating multiple container generation. - return self._component_info_modules['union_types'] - self._component_info_core['union_types'] + return (self._component_info_modules['union_types'] - + self._component_info_core['union_types']) def include_path_for_union_types(self, union_type): - core_union_type_names = [core_union_type.name for core_union_type - in self._component_info_core['union_types']] + core_union_type_names = [ + core_union_type.name + for core_union_type in self._component_info_core['union_types'] + ] name = shorten_union_name(union_type) if union_type.name in core_union_type_names: return 'bindings/core/v8/%s.h' % to_snake_case(name) @@ -201,7 +209,8 @@ class ComponentInfoProviderModules(ComponentInfoProvider): def load_interfaces_info_overall_pickle(info_dir): - with open(os.path.join(info_dir, 'interfaces_info.pickle')) as interface_info_file: + with open(os.path.join(info_dir, + 'interfaces_info.pickle')) as interface_info_file: return pickle.load(interface_info_file) @@ -210,7 +219,7 @@ def merge_dict_recursively(target, diff): |target| will be updated with |diff|. Part of |diff| may be re-used in |target|. """ - for key, value in diff.iteritems(): + for key, value in diff.items(): if key not in target: target[key] = value elif type(value) == dict: @@ -227,19 +236,26 @@ def merge_dict_recursively(target, diff): def create_component_info_provider_core(info_dir): interfaces_info = load_interfaces_info_overall_pickle(info_dir) - with open(os.path.join(info_dir, 'core', 'component_info_core.pickle')) as component_info_file: + with open( + os.path.join(info_dir, 'core', + 'component_info_core.pickle')) as component_info_file: component_info = pickle.load(component_info_file) return ComponentInfoProviderCore(interfaces_info, component_info) def create_component_info_provider_modules(info_dir): interfaces_info = load_interfaces_info_overall_pickle(info_dir) - with open(os.path.join(info_dir, 'core', 'component_info_core.pickle')) as component_info_file: + with open( + os.path.join(info_dir, 'core', + 'component_info_core.pickle')) as component_info_file: component_info_core = pickle.load(component_info_file) - with open(os.path.join(info_dir, 'modules', 'component_info_modules.pickle')) as component_info_file: + with open( + os.path.join( + info_dir, 'modules', + 'component_info_modules.pickle')) as component_info_file: component_info_modules = pickle.load(component_info_file) - return ComponentInfoProviderModules( - interfaces_info, component_info_core, component_info_modules) + return ComponentInfoProviderModules(interfaces_info, component_info_core, + component_info_modules) def create_component_info_provider(info_dir, component): @@ -255,6 +271,7 @@ def create_component_info_provider(info_dir, component): # Basic file reading/writing ################################################################################ + def get_file_contents(filename): with open(filename) as f: return f.read() @@ -270,7 +287,11 @@ def resolve_cygpath(cygdrive_names): if not cygdrive_names: return [] cmd = ['cygpath', '-f', '-', '-wa'] - process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + process = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) idl_file_names = [] for file_name in cygdrive_names: process.stdin.write('%s\n' % file_name) @@ -285,10 +306,14 @@ def read_idl_files_list_from_file(filename): """Similar to read_file_to_list, but also resolves cygpath.""" with open(filename) as input_file: file_names = sorted(shlex.split(input_file)) - idl_file_names = [file_name for file_name in file_names - if not file_name.startswith('/cygdrive')] - cygdrive_names = [file_name for file_name in file_names - if file_name.startswith('/cygdrive')] + idl_file_names = [ + file_name for file_name in file_names + if not file_name.startswith('/cygdrive') + ] + cygdrive_names = [ + file_name for file_name in file_names + if file_name.startswith('/cygdrive') + ] idl_file_names.extend(resolve_cygpath(cygdrive_names)) return idl_file_names @@ -299,7 +324,7 @@ def read_pickle_files(pickle_filenames): def read_pickle_file(pickle_filename): - with open(pickle_filename) as pickle_file: + with open(pickle_filename, 'rb') as pickle_file: return pickle.load(pickle_file) @@ -311,12 +336,12 @@ def write_file(new_text, destination_filename): return destination_dirname = os.path.dirname(destination_filename) - if not os.path.exists(destination_dirname): + if destination_dirname and not os.path.exists(destination_dirname): os.makedirs(destination_dirname) # Write file in binary so that when run on Windows, line endings are not # converted with open(destination_filename, 'wb') as destination_file: - destination_file.write(new_text) + destination_file.write(new_text.encode('utf-8')) def write_pickle_file(pickle_filename, data): @@ -329,7 +354,7 @@ def write_pickle_file(pickle_filename, data): except Exception: # If trouble unpickling, overwrite pass - with open(pickle_filename, 'w') as pickle_file: + with open(pickle_filename, 'wb') as pickle_file: pickle.dump(data, pickle_file) @@ -342,6 +367,7 @@ def write_pickle_file(pickle_filename, data): # Leading and trailing context (e.g. following '{') used to avoid false matches. ################################################################################ + def is_non_legacy_callback_interface_from_idl(file_contents): """Returns True if the specified IDL is a non-legacy callback interface.""" match = re.search(r'callback\s+interface\s+\w+\s*{', file_contents) @@ -378,20 +404,24 @@ def match_interface_extended_attributes_and_name_from_idl(file_contents): r'(\w+)\s*' r'(:\s*\w+\s*)?' r'{', - file_contents, flags=re.DOTALL) + file_contents, + flags=re.DOTALL) return match def get_interface_extended_attributes_from_idl(file_contents): - match = match_interface_extended_attributes_and_name_from_idl(file_contents) + match = match_interface_extended_attributes_and_name_from_idl( + file_contents) if not match or not match.group(1): return {} extended_attributes_string = match.group(1).strip() - parts = [extended_attribute.strip() - for extended_attribute in re.split(',', extended_attributes_string) - # Discard empty parts, which may exist due to trailing comma - if extended_attribute.strip()] + parts = [ + extended_attribute.strip() + for extended_attribute in re.split(',', extended_attributes_string) + # Discard empty parts, which may exist due to trailing comma + if extended_attribute.strip() + ] # Joins |parts| with commas as far as the parences are not balanced, # and then converts a (joined) term to a dict entry. @@ -406,14 +436,15 @@ def get_interface_extended_attributes_from_idl(file_contents): if parences < 0 or square_brackets < 0: raise ValueError('You have more close braces than open braces.') if parences == 0 and square_brackets == 0: - name, _, value = map(string.strip, concatenated.partition('=')) + name, _, value = map(str.strip, concatenated.partition('=')) extended_attributes[name] = value concatenated = None return extended_attributes def get_interface_exposed_arguments(file_contents): - match = match_interface_extended_attributes_and_name_from_idl(file_contents) + match = match_interface_extended_attributes_and_name_from_idl( + file_contents) if not match or not match.group(1): return None @@ -422,15 +453,19 @@ def get_interface_exposed_arguments(file_contents): if not match: return None arguments = [] - for argument in map(string.strip, match.group(1).split(',')): + for argument in map(str.strip, match.group(1).split(',')): exposed, runtime_enabled = argument.split() - arguments.append({'exposed': exposed, 'runtime_enabled': runtime_enabled}) + arguments.append({ + 'exposed': exposed, + 'runtime_enabled': runtime_enabled + }) return arguments def get_first_interface_name_from_idl(file_contents): - match = match_interface_extended_attributes_and_name_from_idl(file_contents) + match = match_interface_extended_attributes_and_name_from_idl( + file_contents) if match: return match.group(3) return None @@ -442,21 +477,28 @@ def get_first_interface_name_from_idl(file_contents): def shorten_union_name(union_type): aliases = { # modules/canvas2d/CanvasRenderingContext2D.idl - 'CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas': 'CanvasImageSource', + 'CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas': + 'CanvasImageSource', # modules/canvas/htmlcanvas/html_canvas_element_module_support_webgl2_compute.idl # Due to html_canvas_element_module_support_webgl2_compute.idl and html_canvas_element_module.idl are exclusive in modules_idl_files.gni, they have same shorten name. - 'CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrWebGL2ComputeRenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext': 'RenderingContext', + 'CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrWebGL2ComputeRenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext': + 'RenderingContext', # modules/canvas/htmlcanvas/html_canvas_element_module.idl - 'CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext': 'RenderingContext', + 'CanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContextOrGPUCanvasContext': + 'RenderingContext', # core/frame/window_or_worker_global_scope.idl - 'HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas': 'ImageBitmapSource', + 'HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas': + 'ImageBitmapSource', # bindings/tests/idls/core/TestTypedefs.idl - 'NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord': 'NestedUnionType', + 'NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord': + 'NestedUnionType', # modules/canvas/offscreencanvas/offscreen_canvas_module_support_webgl2_compute.idl. # Due to offscreen_canvas_module_support_webgl2_compute.idl and offscreen_canvas_module.idl are exclusive in modules_idl_files.gni, they have same shorten name. - 'OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrWebGL2ComputeRenderingContextOrImageBitmapRenderingContext': 'OffscreenRenderingContext', + 'OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrWebGL2ComputeRenderingContextOrImageBitmapRenderingContext': + 'OffscreenRenderingContext', # modules/canvas/offscreencanvas/offscreen_canvas_module.idl - 'OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContext': 'OffscreenRenderingContext', + 'OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContextOrImageBitmapRenderingContext': + 'OffscreenRenderingContext', } idl_type = union_type @@ -563,7 +605,8 @@ def format_blink_cpp_source_code(text): if was_open_brace: # No empty line just after an open brace. pass - elif match and match.group('first') == '}' and 'namespace' not in line: + elif (match and match.group('first') == '}' + and 'namespace' not in line): # No empty line just before a closing brace. pass else: @@ -578,7 +621,8 @@ def format_blink_cpp_source_code(text): match = re_last_brace.search(line) else: match = None - was_open_brace = (match and match.group('last') == '{' and 'namespace' not in line) + was_open_brace = (match and match.group('last') == '{' + and 'namespace' not in line) # Let |'\n'.join| emit the last newline. if output: diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py index e58cc6148f5..26fbd984024 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_attributes.py @@ -27,7 +27,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # pylint: disable=relative-import - """Generate template values for attributes. Extends IdlType with property |constructor_type_name|. @@ -38,17 +37,23 @@ Design doc: http://www.chromium.org/developers/design-documents/idl-compiler import os import sys -sys.path.append(os.path.join(os.path.dirname(__file__), - '..', '..', 'build', 'scripts')) +sys.path.append( + os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'scripts')) from blinkbuild.name_style_converter import NameStyleConverter import idl_types from idl_types import inherits_interface from v8_globals import includes import v8_types import v8_utilities -from v8_utilities import (cpp_name_or_partial, capitalize, cpp_name, has_extended_attribute, - has_extended_attribute_value, scoped_name, strip_suffix, - uncapitalize, extended_attribute_value_as_list, is_unforgeable) +from v8_utilities import capitalize +from v8_utilities import cpp_encoded_property_name +from v8_utilities import cpp_name +from v8_utilities import extended_attribute_value_as_list +from v8_utilities import has_extended_attribute_value +from v8_utilities import is_unforgeable +from v8_utilities import scoped_name +from v8_utilities import strip_suffix +from v8_utilities import uncapitalize from blinkbuild.name_style_converter import NameStyleConverter @@ -73,14 +78,14 @@ def attribute_context(interface, attribute, interfaces, component_info): idl_type.add_includes_for_type(extended_attributes) if idl_type.enum_values: includes.add('core/inspector/console_message.h') + includes.add('platform/heap/heap.h') # [CheckSecurity] is_cross_origin = 'CrossOrigin' in extended_attributes - is_check_security_for_receiver = ( - has_extended_attribute_value(interface, 'CheckSecurity', 'Receiver') and - is_cross_origin) - is_check_security_for_return_value = ( - has_extended_attribute_value(attribute, 'CheckSecurity', 'ReturnValue')) + is_check_security_for_receiver = (has_extended_attribute_value( + interface, 'CheckSecurity', 'Receiver') and is_cross_origin) + is_check_security_for_return_value = (has_extended_attribute_value( + attribute, 'CheckSecurity', 'ReturnValue')) if is_check_security_for_receiver or is_check_security_for_return_value: includes.add('bindings/core/v8/binding_security.h') if is_check_security_for_return_value: @@ -93,7 +98,8 @@ def attribute_context(interface, attribute, interfaces, component_info): # TODO(yukishiino): Constructors are much like methods although constructors # are not methods. Constructors must be data-type properties, and we can # support them as a kind of methods. - constructor_type = idl_type.constructor_type_name if is_constructor_attribute(attribute) else None + constructor_type = idl_type.constructor_type_name if is_constructor_attribute( + attribute) else None # [CEReactions] is_ce_reactions = 'CEReactions' in extended_attributes if is_ce_reactions: @@ -111,11 +117,17 @@ def attribute_context(interface, attribute, interfaces, component_info): includes.add('core/html/custom/v0_custom_element_processing_stack.h') # [PerWorldBindings] if 'PerWorldBindings' in extended_attributes: - assert idl_type.is_wrapper_type or 'LogActivity' in extended_attributes, '[PerWorldBindings] should only be used with wrapper types: %s.%s' % (interface.name, attribute.name) + assert idl_type.is_wrapper_type or 'LogActivity' in \ + extended_attributes, \ + '[PerWorldBindings] should only be used with wrapper types: %s.%s' % \ + (interface.name, attribute.name) # [SaveSameObject] - is_save_same_object = ( - 'SameObject' in attribute.extended_attributes and - 'SaveSameObject' in attribute.extended_attributes) + is_save_same_object = ('SameObject' in attribute.extended_attributes and + 'SaveSameObject' in attribute.extended_attributes) + + # [StringContext] + if idl_type.has_string_context: + includes.add('bindings/core/v8/generated_code_helper.h') # [CachedAccessor] is_cached_accessor = 'CachedAccessor' in extended_attributes @@ -124,40 +136,29 @@ def attribute_context(interface, attribute, interfaces, component_info): is_lenient_setter = 'LenientSetter' in extended_attributes # [CachedAttribute] - cached_attribute_validation_method = extended_attributes.get('CachedAttribute') + cached_attribute_validation_method = extended_attributes.get( + 'CachedAttribute') keep_alive_for_gc = is_keep_alive_for_gc(interface, attribute) - does_generate_getter = ( - not has_custom_getter(attribute) and - not constructor_type - ) + does_generate_getter = (not has_custom_getter(attribute) + and not constructor_type) does_generate_setter = ( - has_setter(interface, attribute) and - not (has_custom_setter(attribute) or is_lenient_setter) - ) - - use_private_property_in_getter = ( - does_generate_getter and ( - cached_attribute_validation_method or - is_save_same_object or - keep_alive_for_gc - ) - ) - use_private_property_in_setter = ( - does_generate_setter and - cached_attribute_validation_method - ) + has_setter(interface, attribute) + and not (has_custom_setter(attribute) or is_lenient_setter)) + + use_private_property_in_getter = (does_generate_getter + and (cached_attribute_validation_method + or is_save_same_object + or keep_alive_for_gc)) + use_private_property_in_setter = (does_generate_setter + and cached_attribute_validation_method) private_property_is_shared_between_getter_and_setter = ( - use_private_property_in_getter and - use_private_property_in_setter - ) - - does_use_private_property = ( - use_private_property_in_getter or - use_private_property_in_setter or - is_cached_accessor - ) + use_private_property_in_getter and use_private_property_in_setter) + + does_use_private_property = (use_private_property_in_getter + or use_private_property_in_setter + or is_cached_accessor) if does_use_private_property: includes.add('platform/bindings/v8_private_property.h') @@ -178,29 +179,50 @@ def attribute_context(interface, attribute, interfaces, component_info): runtime_features = component_info['runtime_enabled_features'] + internal_name = cpp_encoded_property_name(attribute) + + cpp_type = idl_type.cpp_type + if idl_type.is_explicit_nullable: + cpp_type = v8_types.cpp_template_type('base::Optional', cpp_type) + context = { - 'activity_logging_world_list_for_getter': v8_utilities.activity_logging_world_list(attribute, 'Getter'), # [ActivityLogging] - 'activity_logging_world_list_for_setter': v8_utilities.activity_logging_world_list(attribute, 'Setter'), # [ActivityLogging] - 'activity_logging_world_check': v8_utilities.activity_logging_world_check(attribute), # [ActivityLogging] - 'cached_accessor_name': '%s%sCachedAccessor' % (interface.name, attribute.name.capitalize()), - 'cached_attribute_validation_method': cached_attribute_validation_method, - 'camel_case_name': NameStyleConverter(attribute.name).to_upper_camel_case(), - 'constructor_type': constructor_type, - 'context_enabled_feature_name': v8_utilities.context_enabled_feature_name(attribute), + # [ActivityLogging] + 'activity_logging_world_list_for_getter': + v8_utilities.activity_logging_world_list(attribute, 'Getter'), + # [ActivityLogging] + 'activity_logging_world_list_for_setter': + v8_utilities.activity_logging_world_list(attribute, 'Setter'), + # [ActivityLogging] + 'activity_logging_world_check': + v8_utilities.activity_logging_world_check(attribute), + 'cached_accessor_name': + '%s%sCachedAccessor' % (interface.name, attribute.name.capitalize()), + 'cached_attribute_validation_method': + cached_attribute_validation_method, + 'camel_case_name': + NameStyleConverter(internal_name).to_upper_camel_case(), + 'constructor_type': + constructor_type, + 'context_enabled_feature_name': + v8_utilities.context_enabled_feature_name(attribute), 'cpp_name': cpp_name(attribute), - 'cpp_type': idl_type.cpp_type, + 'cpp_type': cpp_type, 'cpp_type_initializer': idl_type.cpp_type_initializer, 'deprecate_as': deprecate_as, 'does_generate_getter': does_generate_getter, 'does_generate_setter': does_generate_setter, 'enum_type': idl_type.enum_type, 'enum_values': idl_type.enum_values, - 'exposed_test': v8_utilities.exposed(attribute, interface), # [Exposed] - 'getter_has_no_side_effect': has_extended_attribute_value(attribute, 'Affects', 'Nothing'), + # [Exposed] + 'exposed_test': + v8_utilities.exposed(attribute, interface), + 'getter_has_no_side_effect': + has_extended_attribute_value(attribute, 'Affects', 'Nothing'), 'has_cross_origin_getter': has_extended_attribute_value(attribute, 'CrossOrigin', None) or has_extended_attribute_value(attribute, 'CrossOrigin', 'Getter'), - 'has_cross_origin_setter': has_extended_attribute_value(attribute, 'CrossOrigin', 'Setter'), + 'has_cross_origin_setter': + has_extended_attribute_value(attribute, 'CrossOrigin', 'Setter'), 'has_custom_getter': has_custom_getter(attribute), 'has_custom_setter': has_custom_setter(attribute), 'has_promise_type': idl_type.name == 'Promise', @@ -208,11 +230,14 @@ def attribute_context(interface, attribute, interfaces, component_info): 'high_entropy': high_entropy, 'idl_type': str(idl_type), 'is_cached_accessor': is_cached_accessor, - 'is_call_with_execution_context': has_extended_attribute_value(attribute, 'CallWith', 'ExecutionContext'), - 'is_call_with_script_state': has_extended_attribute_value(attribute, 'CallWith', 'ScriptState'), + 'is_call_with_execution_context': + has_extended_attribute_value(attribute, 'CallWith', 'ExecutionContext'), + 'is_call_with_script_state': + has_extended_attribute_value(attribute, 'CallWith', 'ScriptState'), 'is_ce_reactions': is_ce_reactions, 'is_check_security_for_receiver': is_check_security_for_receiver, - 'is_check_security_for_return_value': is_check_security_for_return_value, + 'is_check_security_for_return_value': + is_check_security_for_return_value, 'is_custom_element_callbacks': is_custom_element_callbacks, # TODO(yukishiino): Make all DOM attributes accessor-type properties. 'is_data_type_property': is_data_type_property(interface, attribute), @@ -242,9 +267,11 @@ def attribute_context(interface, attribute, interfaces, component_info): 'on_instance': v8_utilities.on_instance(interface, attribute), 'on_interface': v8_utilities.on_interface(interface, attribute), 'on_prototype': v8_utilities.on_prototype(interface, attribute), + # [RuntimeEnabled] for origin trial 'origin_trial_feature_name': - v8_utilities.origin_trial_feature_name(attribute, runtime_features), # [RuntimeEnabled] for origin trial - 'private_property_is_shared_between_getter_and_setter': private_property_is_shared_between_getter_and_setter, + v8_utilities.origin_trial_feature_name(attribute, runtime_features), + 'private_property_is_shared_between_getter_and_setter': + private_property_is_shared_between_getter_and_setter, 'property_attributes': property_attributes(interface, attribute), 'reflect_empty': cpp_content_attribute_value_name( interface, extended_attributes.get('ReflectEmpty')), @@ -253,9 +280,11 @@ def attribute_context(interface, attribute, interfaces, component_info): 'reflect_missing': cpp_content_attribute_value_name( interface, extended_attributes.get('ReflectMissing')), 'reflect_only': reflect_only, + # [RuntimeEnabled] if not in origin trial 'runtime_enabled_feature_name': - v8_utilities.runtime_enabled_feature_name(attribute, runtime_features), # [RuntimeEnabled] if not in origin trial - 'secure_context_test': v8_utilities.secure_context(attribute, interface), # [SecureContext] + v8_utilities.runtime_enabled_feature_name(attribute, runtime_features), + # [SecureContext] + 'secure_context_test': v8_utilities.secure_context(attribute, interface), 'use_output_parameter_for_result': idl_type.use_output_parameter_for_result, 'world_suffixes': ( ['', 'ForMainWorld'] @@ -275,28 +304,38 @@ def attribute_context(interface, attribute, interfaces, component_info): # for them here. if is_cross_origin: if context['has_cross_origin_setter'] and context['has_custom_setter']: - raise Exception('[CrossOrigin] and [Custom] are incompatible on the same setter: %s.%s', interface.name, attribute.name) + raise Exception( + '[CrossOrigin] and [Custom] are incompatible on the same setter: %s.%s', + interface.name, attribute.name) if context['is_per_world_bindings']: - raise Exception('[CrossOrigin] and [PerWorldBindings] are incompatible: %s.%s', interface.name, attribute.name) + raise Exception( + '[CrossOrigin] and [PerWorldBindings] are incompatible: %s.%s', + interface.name, attribute.name) if context['constructor_type']: - raise Exception('[CrossOrigin] cannot be used for constructors: %s.%s', interface.name, attribute.name) + raise Exception( + '[CrossOrigin] cannot be used for constructors: %s.%s', + interface.name, attribute.name) return context def runtime_call_stats_context(interface, attribute, context): includes.add('platform/bindings/runtime_call_stats.h') - generic_counter_name = 'Blink_' + v8_utilities.cpp_name(interface) + '_' + attribute.name - (counter, extended_attribute_defined) = v8_utilities.rcs_counter_name(attribute, generic_counter_name) + generic_counter_name = ( + 'Blink_' + v8_utilities.cpp_name(interface) + '_' + attribute.name) + (counter, extended_attribute_defined) = v8_utilities.rcs_counter_name( + attribute, generic_counter_name) runtime_call_stats = { - 'extended_attribute_defined': extended_attribute_defined, - 'getter_counter': '%s_Getter' % counter, - 'setter_counter': '%s_Setter' % counter, - 'constructor_getter_callback_counter': '%s_ConstructorGetterCallback' % generic_counter_name, + 'extended_attribute_defined': + extended_attribute_defined, + 'getter_counter': + '%s_Getter' % counter, + 'setter_counter': + '%s_Setter' % counter, + 'constructor_getter_callback_counter': + '%s_ConstructorGetterCallback' % generic_counter_name, } - context.update({ - 'runtime_call_stats': runtime_call_stats - }) + context.update({'runtime_call_stats': runtime_call_stats}) def is_origin_trial_enabled(attribute): @@ -308,46 +347,51 @@ def is_secure_context(attribute): def filter_accessors(attributes): - return [attribute for attribute in attributes if - not (attribute['exposed_test'] or - is_secure_context(attribute) or - attribute['context_enabled_feature_name'] or - is_origin_trial_enabled(attribute) or - attribute['runtime_enabled_feature_name']) and - not attribute['is_data_type_property']] + return [ + attribute for attribute in attributes + if not (attribute['exposed_test'] or is_secure_context(attribute) + or attribute['context_enabled_feature_name'] + or is_origin_trial_enabled(attribute) + or attribute['runtime_enabled_feature_name']) + and not attribute['is_data_type_property'] + ] def is_data_attribute(attribute): - return (not (attribute['exposed_test'] or - is_secure_context(attribute) or - attribute['context_enabled_feature_name'] or - is_origin_trial_enabled(attribute) or - attribute['runtime_enabled_feature_name']) and - attribute['is_data_type_property']) + return (not (attribute['exposed_test'] or is_secure_context(attribute) + or attribute['context_enabled_feature_name'] + or is_origin_trial_enabled(attribute) + or attribute['runtime_enabled_feature_name']) + and attribute['is_data_type_property']) def filter_data_attributes(attributes): - return [attribute for attribute in attributes if is_data_attribute(attribute)] + return [ + attribute for attribute in attributes if is_data_attribute(attribute) + ] def filter_runtime_enabled(attributes): - return [attribute for attribute in attributes if - not (attribute['exposed_test'] or - is_secure_context(attribute)) and - attribute['runtime_enabled_feature_name']] + return [ + attribute for attribute in attributes + if not (attribute['exposed_test'] or is_secure_context(attribute)) + and attribute['runtime_enabled_feature_name'] + ] def filter_conditionally_enabled(attributes): - return [attribute for attribute in attributes if - attribute['exposed_test'] or - (is_secure_context(attribute) and - not is_origin_trial_enabled(attribute))] + return [ + attribute for attribute in attributes + if attribute['exposed_test'] or (is_secure_context( + attribute) and not is_origin_trial_enabled(attribute)) + ] ################################################################################ # Getter ################################################################################ + def getter_context(interface, attribute, context): idl_type = attribute.idl_type base_idl_type = idl_type.base_type @@ -360,51 +404,68 @@ def getter_context(interface, attribute, context): # exceptions), we need to use a local variable. # FIXME: check if compilers are smart enough to inline this, and if so, # always use a local variable (for readability and CG simplicity). - if (idl_type.is_explicit_nullable or - base_idl_type == 'EventHandler' or - 'CachedAttribute' in extended_attributes or - 'ReflectOnly' in extended_attributes or - context['is_keep_alive_for_gc'] or - context['is_getter_raises_exception']): + if (idl_type.is_explicit_nullable or base_idl_type == 'EventHandler' + or 'CachedAttribute' in extended_attributes + or 'ReflectOnly' in extended_attributes + or context['is_keep_alive_for_gc'] + or context['is_getter_raises_exception']): context['cpp_value_original'] = cpp_value cpp_value = 'cpp_value' def v8_set_return_value_statement(for_main_world=False): - if context['is_keep_alive_for_gc'] or 'CachedAttribute' in extended_attributes: + if (context['is_keep_alive_for_gc'] + or 'CachedAttribute' in extended_attributes): return 'V8SetReturnValue(info, v8_value)' + if idl_type.is_explicit_nullable: + cpp_return_value = 'cpp_value.value()' + if idl_type.is_frozen_array: + cpp_return_value = 'FreezeV8Object(ToV8(cpp_value.value(), info.Holder(), info.GetIsolate()), info.GetIsolate())' + return 'V8SetReturnValue(info, {})'.format(cpp_return_value) return idl_type.v8_set_return_value( - cpp_value, extended_attributes=extended_attributes, script_wrappable='impl', - for_main_world=for_main_world, is_static=attribute.is_static) + cpp_value, + extended_attributes=extended_attributes, + script_wrappable='impl', + for_main_world=for_main_world, + is_static=attribute.is_static) cpp_value_to_script_wrappable = cpp_value if idl_type.is_array_buffer_view_or_typed_array: cpp_value_to_script_wrappable += '.View()' context.update({ - 'cpp_value': cpp_value, - 'cpp_value_to_script_wrappable': cpp_value_to_script_wrappable, - 'cpp_value_to_v8_value': idl_type.cpp_value_to_v8_value( - cpp_value=cpp_value, creation_context='holder', + 'cpp_value': + cpp_value, + 'cpp_value_to_script_wrappable': + cpp_value_to_script_wrappable, + 'cpp_value_to_v8_value': + idl_type.cpp_value_to_v8_value( + cpp_value=cpp_value, + creation_context='holder', extended_attributes=extended_attributes), - 'v8_set_return_value_for_main_world': v8_set_return_value_statement(for_main_world=True), - 'v8_set_return_value': v8_set_return_value_statement(), + 'v8_set_return_value_for_main_world': + v8_set_return_value_statement(for_main_world=True), + 'v8_set_return_value': + v8_set_return_value_statement(), }) + def getter_expression(interface, attribute, context): - arguments = [] - this_getter_base_name = getter_base_name(interface, attribute, arguments) + extra_arguments = [] + this_getter_base_name = getter_base_name(interface, attribute, + extra_arguments) getter_name = scoped_name(interface, attribute, this_getter_base_name) - arguments.extend(v8_utilities.call_with_arguments( - attribute.extended_attributes.get('CallWith'))) + arguments = [] + arguments.extend( + v8_utilities.call_with_arguments( + attribute.extended_attributes.get('CallWith'))) # Members of IDL partial interface definitions are implemented in C++ as # static member functions, which for instance members (non-static members) # take *impl as their first argument - if ('PartialInterfaceImplementedAs' in attribute.extended_attributes and - not attribute.is_static): + if ('PartialInterfaceImplementedAs' in attribute.extended_attributes + and not attribute.is_static): arguments.append('*impl') - if attribute.idl_type.is_explicit_nullable: - arguments.append('is_null') + arguments.extend(extra_arguments) if context['is_getter_raises_exception']: arguments.append('exception_state') if attribute.idl_type.use_output_parameter_for_result: @@ -413,8 +474,8 @@ def getter_expression(interface, attribute, context): expression = '%s(%s)' % (getter_name, ', '.join(arguments)) # Needed to handle getter expressions returning Type& as the # use site for |expression| expects Type*. - if (attribute.idl_type.is_interface_type and len(arguments) == 0 and - not attribute.idl_type.is_array_buffer_view_or_typed_array): + if (attribute.idl_type.is_interface_type and len(arguments) == 0 + and not attribute.idl_type.is_array_buffer_view_or_typed_array): return 'WTF::GetPtr(%s)' % expression return expression @@ -435,7 +496,8 @@ def getter_base_name(interface, attribute, arguments): return name if 'ImplementedAs' in extended_attributes \ else uncapitalize(name) - content_attribute_name = extended_attributes['Reflect'] or attribute.name.lower() + content_attribute_name = (extended_attributes['Reflect'] + or attribute.name.lower()) if content_attribute_name in ['class', 'id', 'name']: # Special-case for performance optimization. return 'Get%sAttribute' % content_attribute_name.capitalize() @@ -459,28 +521,31 @@ def is_keep_alive_for_gc(interface, attribute): extended_attributes = attribute.extended_attributes if attribute.is_static: return False + if idl_type.is_array_buffer_or_view: + return False return ( # For readonly attributes, for performance reasons we keep the attribute # wrapper alive while the owner wrapper is alive, because the attribute # never changes. - (attribute.is_read_only and - idl_type.is_wrapper_type and - # There are some exceptions, however: - not( - # Node lifetime is managed by object grouping. - inherits_interface(interface.name, 'Node') or - inherits_interface(base_idl_type, 'Node') or - # A self-reference is unnecessary. - attribute.name == 'self' or - # FIXME: Remove these hard-coded hacks. - base_idl_type in ['EventTarget', 'Window'] or - base_idl_type.startswith(('HTML', 'SVG'))))) + ( + attribute.is_read_only and idl_type.is_wrapper_type and + # There are some exceptions, however: + not ( + # Node lifetime is managed by object grouping. + inherits_interface(interface.name, 'Node') + or inherits_interface(base_idl_type, 'Node') or + # A self-reference is unnecessary. + attribute.name == 'self' or + # FIXME: Remove these hard-coded hacks. + base_idl_type in ['EventTarget', 'Window'] + or base_idl_type.startswith(('HTML', 'SVG'))))) ################################################################################ # Setter ################################################################################ + def setter_context(interface, attribute, interfaces, context): if 'PutForwards' in attribute.extended_attributes: # Make sure the target interface and attribute exist. @@ -488,8 +553,7 @@ def setter_context(interface, attribute, interfaces, context): target_attribute_name = attribute.extended_attributes['PutForwards'] interface = interfaces[target_interface_name] try: - next(candidate - for candidate in interface.attributes + next(candidate for candidate in interface.attributes if candidate.name == target_attribute_name) except StopIteration: raise Exception('[PutForward] target not found:\n' @@ -504,8 +568,8 @@ def setter_context(interface, attribute, interfaces, context): # exception. context['cpp_setter'] = ( 'if (info.Holder()->CreateDataProperty(' + - 'info.GetIsolate()->GetCurrentContext(), property_name, v8_value).IsNothing())' + - '\n return') + 'info.GetIsolate()->GetCurrentContext(), ' + + 'property_name, v8_value).IsNothing())' + '\n return') return extended_attributes = attribute.extended_attributes @@ -513,8 +577,8 @@ def setter_context(interface, attribute, interfaces, context): # [RaisesException], [RaisesException=Setter] is_setter_raises_exception = ( - 'RaisesException' in extended_attributes and - extended_attributes['RaisesException'] in [None, 'Setter']) + 'RaisesException' in extended_attributes + and extended_attributes['RaisesException'] in [None, 'Setter']) has_type_checking_interface = idl_type.is_wrapper_type @@ -524,27 +588,36 @@ def setter_context(interface, attribute, interfaces, context): # [CEReactions, Reflect, RuntimeEnabled], # * the type is boolean, DOMString, or DOMString?, and # * the interface inherits from 'Element'. - if ('Reflect' in extended_attributes and - 'CEReactions' in extended_attributes and - str(idl_type) in ('boolean', 'DOMString', 'DOMString?') and - inherits_interface(interface.name, 'Element')): - if (len(extended_attributes) == 2 or - (len(extended_attributes) == 3 and 'RuntimeEnabled' in extended_attributes)): + if ('Reflect' in extended_attributes + and 'CEReactions' in extended_attributes + and str(idl_type) in ('boolean', 'DOMString', 'DOMString?') + and inherits_interface(interface.name, 'Element')): + if (len(extended_attributes) == 2 + or (len(extended_attributes) == 3 + and 'RuntimeEnabled' in extended_attributes)): use_common_reflection_setter = True context.update({ 'has_setter_exception_state': - is_setter_raises_exception or has_type_checking_interface or - idl_type.v8_conversion_needs_exception_state, - 'has_type_checking_interface': has_type_checking_interface, - 'is_setter_call_with_execution_context': has_extended_attribute_value( - attribute, 'SetterCallWith', 'ExecutionContext'), - 'is_setter_call_with_script_state': has_extended_attribute_value( - attribute, 'SetterCallWith', 'ScriptState'), - 'is_setter_raises_exception': is_setter_raises_exception, - 'use_common_reflection_setter': use_common_reflection_setter, - 'v8_value_to_local_cpp_value': idl_type.v8_value_to_local_cpp_value( - extended_attributes, 'v8_value', 'cpp_value', + is_setter_raises_exception or has_type_checking_interface + or idl_type.v8_conversion_needs_exception_state, + 'has_type_checking_interface': + has_type_checking_interface, + 'is_setter_call_with_execution_context': + has_extended_attribute_value(attribute, 'SetterCallWith', + 'ExecutionContext'), + 'is_setter_call_with_script_state': + has_extended_attribute_value(attribute, 'SetterCallWith', + 'ScriptState'), + 'is_setter_raises_exception': + is_setter_raises_exception, + 'use_common_reflection_setter': + use_common_reflection_setter, + 'v8_value_to_local_cpp_value': + idl_type.v8_value_to_local_cpp_value( + extended_attributes, + 'v8_value', + 'cpp_value', code_generation_target='attribute_set'), }) @@ -555,18 +628,21 @@ def setter_context(interface, attribute, interfaces, context): def setter_expression(interface, attribute, context): extended_attributes = attribute.extended_attributes arguments = v8_utilities.call_with_arguments( - extended_attributes.get('SetterCallWith') or - extended_attributes.get('CallWith')) + extended_attributes.get('SetterCallWith') + or extended_attributes.get('CallWith')) - this_setter_base_name = setter_base_name(interface, attribute, arguments) + extra_arguments = [] + this_setter_base_name = setter_base_name(interface, attribute, + extra_arguments) setter_name = scoped_name(interface, attribute, this_setter_base_name) # Members of IDL partial interface definitions are implemented in C++ as # static member functions, which for instance members (non-static members) # take *impl as their first argument - if ('PartialInterfaceImplementedAs' in extended_attributes and - not attribute.is_static): + if ('PartialInterfaceImplementedAs' in extended_attributes + and not attribute.is_static): arguments.append('*impl') + arguments.extend(extra_arguments) idl_type = attribute.idl_type if idl_type.base_type == 'EventHandler': handler_type = 'kEventHandler' @@ -574,25 +650,21 @@ def setter_expression(interface, attribute, context): handler_type = 'kOnErrorEventHandler' elif attribute.name == 'onbeforeunload': handler_type = 'kOnBeforeUnloadEventHandler' - arguments.append( - 'JSEventHandler::CreateOrNull(' + - 'v8_value, ' + - 'JSEventHandler::HandlerType::' + handler_type + - ')') - elif idl_type.base_type == 'SerializedScriptValue': - arguments.append('std::move(cpp_value)') + arguments.append('JSEventHandler::CreateOrNull(' + 'v8_value, ' + + 'JSEventHandler::HandlerType::' + handler_type + ')') else: arguments.append('cpp_value') - if idl_type.is_explicit_nullable: - arguments.append('is_null') if context['is_setter_raises_exception']: arguments.append('exception_state') if context['use_common_reflection_setter']: attr_name = scoped_content_attribute_name(interface, attribute) if idl_type.base_type == 'boolean': setter_name = 'V8SetReflectedBooleanAttribute' - arguments = ['info', '"%s"' % interface.name, - '"%s"' % attribute.name, attr_name] + arguments = [ + 'info', + '"%s"' % interface.name, + '"%s"' % attribute.name, attr_name + ] elif idl_type.base_type == 'DOMString': if idl_type.is_nullable: setter_name = 'V8SetReflectedNullableDOMStringAttribute' @@ -626,8 +698,10 @@ def setter_base_name(interface, attribute, arguments): def scoped_content_attribute_name(interface, attribute): - content_attribute_name = attribute.extended_attributes['Reflect'] or attribute.name.lower() - symbol_name = 'k' + NameStyleConverter(content_attribute_name).to_upper_camel_case() + content_attribute_name = (attribute.extended_attributes['Reflect'] + or attribute.name.lower()) + symbol_name = 'k' + NameStyleConverter( + content_attribute_name).to_upper_camel_case() if interface.name.startswith('SVG'): namespace = 'svg_names' includes.add('core/svg_names.h') @@ -650,25 +724,26 @@ def cpp_content_attribute_value_name(interface, value): # Attribute configuration ################################################################################ + # Property descriptor's {writable: boolean} def is_writable(attribute): - return (not attribute.is_read_only or - any(keyword in attribute.extended_attributes for keyword in [ - 'PutForwards', 'Replaceable', 'LenientSetter'])) + return (not attribute.is_read_only or any( + keyword in attribute.extended_attributes + for keyword in ['PutForwards', 'Replaceable', 'LenientSetter'])) def is_data_type_property(interface, attribute): if 'CachedAccessor' in attribute.extended_attributes: return False - return (is_constructor_attribute(attribute) or - 'CrossOrigin' in attribute.extended_attributes) + return (is_constructor_attribute(attribute) + or 'CrossOrigin' in attribute.extended_attributes) # [PutForwards], [Replaceable], [LenientSetter] def has_setter(interface, attribute): - if (is_data_type_property(interface, attribute) and - (is_constructor_attribute(attribute) or - 'Replaceable' in attribute.extended_attributes)): + if (is_data_type_property(interface, attribute) + and (is_constructor_attribute(attribute) + or 'Replaceable' in attribute.extended_attributes)): return False return is_writable(attribute) @@ -678,8 +753,8 @@ def has_setter(interface, attribute): def property_attributes(interface, attribute): extended_attributes = attribute.extended_attributes property_attributes_list = [] - if ('NotEnumerable' in extended_attributes or - is_constructor_attribute(attribute)): + if ('NotEnumerable' in extended_attributes + or is_constructor_attribute(attribute)): property_attributes_list.append('v8::DontEnum') if is_unforgeable(attribute): property_attributes_list.append('v8::DontDelete') @@ -691,16 +766,15 @@ def property_attributes(interface, attribute): # [Custom], [Custom=Getter] def has_custom_getter(attribute): extended_attributes = attribute.extended_attributes - return ('Custom' in extended_attributes and - extended_attributes['Custom'] in [None, 'Getter']) + return ('Custom' in extended_attributes + and extended_attributes['Custom'] in [None, 'Getter']) # [Custom], [Custom=Setter] def has_custom_setter(attribute): extended_attributes = attribute.extended_attributes - return (not attribute.is_read_only and - 'Custom' in extended_attributes and - extended_attributes['Custom'] in [None, 'Setter']) + return (not attribute.is_read_only and 'Custom' in extended_attributes + and extended_attributes['Custom'] in [None, 'Setter']) ################################################################################ diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_function.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_function.py index bdd5965ca9d..76de914834a 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_function.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_function.py @@ -1,7 +1,6 @@ # Copyright 2016 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Generate template values for a callback function. Design doc: http://www.chromium.org/developers/design-documents/idl-compiler @@ -43,15 +42,24 @@ def callback_function_context(callback_function): # the moment, the two are being defined because their values may change # in the future (e.g. if we support [ImplementedAs=] in callback # functions). - 'callback_function_name': callback_function.name, - 'cpp_class': 'V8%s' % callback_function.name, - 'cpp_includes': sorted(includes), - 'forward_declarations': sorted(forward_declarations(callback_function)), - 'header_includes': sorted(CALLBACK_FUNCTION_H_INCLUDES), - 'idl_type': idl_type_str, - 'is_treat_non_object_as_null': 'TreatNonObjectAsNull' in callback_function.extended_attributes, - 'native_value_traits_tag': v8_types.idl_type_to_native_value_traits_tag(idl_type), - 'return_cpp_type': idl_type.cpp_type, + 'callback_function_name': + callback_function.name, + 'cpp_class': + 'V8%s' % callback_function.name, + 'cpp_includes': + sorted(includes), + 'forward_declarations': + sorted(forward_declarations(callback_function)), + 'header_includes': + sorted(CALLBACK_FUNCTION_H_INCLUDES), + 'idl_type': + idl_type_str, + 'is_treat_non_object_as_null': + 'TreatNonObjectAsNull' in callback_function.extended_attributes, + 'native_value_traits_tag': + v8_types.idl_type_to_native_value_traits_tag(idl_type), + 'return_cpp_type': + idl_type.cpp_type, } context.update(arguments_context(callback_function.arguments)) @@ -78,14 +86,21 @@ def arguments_context(arguments): def argument_context(argument): idl_type = argument.idl_type return { - 'cpp_value_to_v8_value': idl_type.cpp_value_to_v8_value( - argument.name, isolate='GetIsolate()', + 'cpp_value_to_v8_value': + idl_type.cpp_value_to_v8_value( + argument.name, + isolate='GetIsolate()', creation_context='argument_creation_context'), - 'enum_type': idl_type.enum_type, - 'enum_values': idl_type.enum_values, - 'is_variadic': argument.is_variadic, - 'name': argument.name, - 'v8_name': 'v8_%s' % argument.name, + 'enum_type': + idl_type.enum_type, + 'enum_values': + idl_type.enum_values, + 'is_variadic': + argument.is_variadic, + 'name': + argument.name, + 'v8_name': + 'v8_%s' % argument.name, } def argument_cpp_type(argument): @@ -98,7 +113,9 @@ def arguments_context(arguments): else: return cpp_type - argument_declarations = ['bindings::V8ValueOrScriptWrappableAdapter callback_this_value'] + argument_declarations = [ + 'bindings::V8ValueOrScriptWrappableAdapter callback_this_value' + ] argument_declarations.extend( '%s %s' % (argument_cpp_type(argument), argument.name) for argument in arguments) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py index e4580fd9319..973a1edde51 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Generate template values for a callback interface. Extends IdlTypeBase with property |callback_cpp_type|. @@ -69,10 +68,12 @@ def _cpp_type(idl_type): # Callbacks use raw pointers, so raw_type=True raw_cpp_type = idl_type.cpp_type_args(raw_type=True) # Pass containers and dictionaries to callback method by const reference rather than by value - if raw_cpp_type.startswith(('Vector', 'HeapVector')) or idl_type.is_dictionary: + if (raw_cpp_type.startswith(('Vector', 'HeapVector')) + or idl_type.is_dictionary): return 'const %s&' % raw_cpp_type return raw_cpp_type + IdlTypeBase.callback_cpp_type = property(_cpp_type) @@ -90,9 +91,8 @@ def callback_interface_context(callback_interface, _, component_info): # https://heycam.github.io/webidl/#dfn-single-operation-callback-interface is_single_operation = True - if (callback_interface.parent or - len(callback_interface.attributes) > 0 or - len(callback_interface.operations) == 0): + if (callback_interface.parent or len(callback_interface.attributes) > 0 + or len(callback_interface.operations) == 0): is_single_operation = False else: operations = callback_interface.operations @@ -103,18 +103,30 @@ def callback_interface_context(callback_interface, _, component_info): break return { - 'constants': [constant_context(constant, callback_interface, component_info) - for constant in callback_interface.constants], - 'cpp_class': callback_interface.name, - 'do_not_check_constants': 'DoNotCheckConstants' in callback_interface.extended_attributes, - 'forward_declarations': sorted(forward_declarations(callback_interface)), - 'header_includes': header_includes, - 'interface_name': callback_interface.name, - 'is_legacy_callback_interface': is_legacy_callback_interface, - 'is_single_operation_callback_interface': is_single_operation, - 'methods': [method_context(operation) - for operation in callback_interface.operations], - 'v8_class': v8_utilities.v8_class_name(callback_interface), + 'constants': [ + constant_context(constant, callback_interface, component_info) + for constant in callback_interface.constants + ], + 'cpp_class': + callback_interface.name, + 'do_not_check_constants': + 'DoNotCheckConstants' in callback_interface.extended_attributes, + 'forward_declarations': + sorted(forward_declarations(callback_interface)), + 'header_includes': + header_includes, + 'interface_name': + callback_interface.name, + 'is_legacy_callback_interface': + is_legacy_callback_interface, + 'is_single_operation_callback_interface': + is_single_operation, + 'methods': [ + method_context(operation) + for operation in callback_interface.operations + ], + 'v8_class': + v8_utilities.v8_class_name(callback_interface), } @@ -150,10 +162,14 @@ def method_context(operation): add_includes_for_operation(operation) context = { - 'cpp_type': idl_type.callback_cpp_type, - 'idl_type': idl_type_str, - 'name': operation.name, - 'native_value_traits_tag': v8_types.idl_type_to_native_value_traits_tag(idl_type), + 'cpp_type': + idl_type.callback_cpp_type, + 'idl_type': + idl_type_str, + 'name': + operation.name, + 'native_value_traits_tag': + v8_types.idl_type_to_native_value_traits_tag(idl_type), } context.update(arguments_context(operation.arguments)) return context @@ -162,18 +178,24 @@ def method_context(operation): def arguments_context(arguments): def argument_context(argument): return { - 'cpp_value_to_v8_value': argument.idl_type.cpp_value_to_v8_value( - argument.name, isolate='GetIsolate()', + 'cpp_value_to_v8_value': + argument.idl_type.cpp_value_to_v8_value( + argument.name, + isolate='GetIsolate()', creation_context='argument_creation_context'), - 'name': argument.name, - 'v8_name': 'v8_' + argument.name, + 'name': + argument.name, + 'v8_name': + 'v8_' + argument.name, } - argument_declarations = ['bindings::V8ValueOrScriptWrappableAdapter callback_this_value'] + argument_declarations = [ + 'bindings::V8ValueOrScriptWrappableAdapter callback_this_value' + ] argument_declarations.extend( '%s %s' % (argument.idl_type.callback_cpp_type, argument.name) for argument in arguments) - return { + return { 'argument_declarations': argument_declarations, 'arguments': [argument_context(argument) for argument in arguments], } diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py index 5beb8a3a1ac..c799496ec88 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_dictionary.py @@ -1,21 +1,21 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Generate template contexts of dictionaries for both v8 bindings and implementation classes that are used by blink's core/modules. """ -import operator +from blinkbuild.name_style_converter import NameStyleConverter from idl_types import IdlType from utilities import to_snake_case from v8_globals import includes +from v8_utilities import has_extended_attribute_value +import operator import v8_types import v8_utilities -from v8_utilities import has_extended_attribute_value - DICTIONARY_H_INCLUDES = frozenset([ + 'base/containers/span.h', 'bindings/core/v8/native_value_traits.h', 'bindings/core/v8/to_v8_for_core.h', 'bindings/core/v8/v8_binding_for_core.h', @@ -30,24 +30,24 @@ DICTIONARY_CPP_INCLUDES = frozenset([ def getter_name_for_dictionary_member(member): name = v8_utilities.cpp_name(member) - return name + return NameStyleConverter(name).to_lower_camel_case() def setter_name_for_dictionary_member(member): - name = v8_utilities.cpp_name(member) - return 'set%s' % v8_utilities.capitalize(name) + name = 'set_{}'.format(v8_utilities.cpp_name(member)) + return NameStyleConverter(name).to_lower_camel_case() def null_setter_name_for_dictionary_member(member): if member.idl_type.is_nullable: - name = v8_utilities.cpp_name(member) - return 'set%sToNull' % v8_utilities.capitalize(name) + name = 'set_{}_to_null'.format(v8_utilities.cpp_name(member)) + return NameStyleConverter(name).to_lower_camel_case() return None def has_method_name_for_dictionary_member(member): - name = v8_utilities.cpp_name(member) - return 'has%s' % v8_utilities.capitalize(name) + name = NameStyleConverter('has_' + v8_utilities.cpp_name(member)) + return name.to_lower_camel_case() def unwrap_nullable_if_needed(idl_type): @@ -58,6 +58,7 @@ def unwrap_nullable_if_needed(idl_type): # Context for V8 bindings + def dictionary_context(dictionary, interfaces_info, component_info): includes.clear() includes.update(DICTIONARY_CPP_INCLUDES) @@ -66,9 +67,11 @@ def dictionary_context(dictionary, interfaces_info, component_info): raise Exception( 'Dictionary cannot be RuntimeEnabled: %s' % dictionary.name) - members = [member_context(dictionary, member, component_info) - for member in sorted(dictionary.members, - key=operator.attrgetter('name'))] + members = [ + member_context(dictionary, member, component_info) + for member in sorted( + dictionary.members, key=operator.attrgetter('name')) + ] for member in members: if member['runtime_enabled_feature_name']: @@ -85,15 +88,22 @@ def dictionary_context(dictionary, interfaces_info, component_info): cpp_class = v8_utilities.cpp_name(dictionary) context = { - 'cpp_class': cpp_class, - 'has_origin_trial_members': has_origin_trial_members, - 'header_includes': set(DICTIONARY_H_INCLUDES), - 'members': members, - 'required_member_names': sorted([member.name - for member in dictionary.members - if member.is_required]), - 'use_permissive_dictionary_conversion': 'PermissiveDictionaryConversion' in dictionary.extended_attributes, - 'v8_class': v8_types.v8_type(cpp_class), + 'cpp_class': + cpp_class, + 'has_origin_trial_members': + has_origin_trial_members, + 'header_includes': + set(DICTIONARY_H_INCLUDES), + 'members': + members, + 'required_member_names': + sorted([ + member.name for member in dictionary.members if member.is_required + ]), + 'use_permissive_dictionary_conversion': + 'PermissiveDictionaryConversion' in dictionary.extended_attributes, + 'v8_class': + v8_types.v8_type(cpp_class), } if dictionary.parent: IdlType(dictionary.parent).add_includes_for_type() @@ -126,8 +136,8 @@ def member_context(_, member, component_info): # states for some types for memory usage and performance. # For types whose |has_explicit_presence| is True, we provide explicit # states of presence. - has_explicit_presence = ( - idl_type.is_nullable and idl_type.inner_type.is_interface_type) + has_explicit_presence = (idl_type.is_nullable + and idl_type.inner_type.is_interface_type) def default_values(): if not member.default_value: @@ -138,7 +148,8 @@ def member_context(_, member, component_info): cpp_default_value = unwrapped_idl_type.literal_cpp_value( member.default_value) v8_default_value = unwrapped_idl_type.cpp_value_to_v8_value( - cpp_value=cpp_default_value, isolate='isolate', + cpp_value=cpp_default_value, + isolate='isolate', creation_context='creationContext') return cpp_default_value, v8_default_value @@ -148,48 +159,78 @@ def member_context(_, member, component_info): v8_value = snake_case_name + "_value" has_value_or_default = snake_case_name + "_has_value_or_default" getter_name = getter_name_for_dictionary_member(member) - is_deprecated_dictionary = unwrapped_idl_type.name == 'Dictionary' runtime_features = component_info['runtime_enabled_features'] return { - 'cpp_default_value': cpp_default_value, - 'cpp_type': unwrapped_idl_type.cpp_type, - 'cpp_value': cpp_value, - 'cpp_value_to_v8_value': unwrapped_idl_type.cpp_value_to_v8_value( - cpp_value='impl->%s()' % getter_name, isolate='isolate', + 'cpp_default_value': + cpp_default_value, + 'cpp_type': + unwrapped_idl_type.cpp_type, + 'cpp_value': + cpp_value, + 'cpp_value_to_v8_value': + unwrapped_idl_type.cpp_value_to_v8_value( + cpp_value='impl->%s()' % getter_name, + isolate='isolate', creation_context='creationContext', extended_attributes=extended_attributes), - 'deprecate_as': v8_utilities.deprecate_as(member), - 'enum_type': idl_type.enum_type, - 'enum_values': idl_type.enum_values, - 'getter_name': getter_name, - 'has_explicit_presence': has_explicit_presence, - 'has_method_name': has_method_name_for_dictionary_member(member), - 'idl_type': idl_type.base_type, - 'is_callback_function_type': idl_type.is_callback_function, - 'is_interface_type': idl_type.is_interface_type and not is_deprecated_dictionary, - 'is_nullable': idl_type.is_nullable, - 'is_object': unwrapped_idl_type.name == 'Object' or is_deprecated_dictionary, - 'is_string_type': idl_type.preprocessed_type.is_string_type, - 'is_required': member.is_required, - 'name': member.name, + 'deprecate_as': + v8_utilities.deprecate_as(member), + 'enum_type': + idl_type.enum_type, + 'enum_values': + idl_type.enum_values, + 'getter_name': + getter_name, + 'has_explicit_presence': + has_explicit_presence, + 'has_method_name': + has_method_name_for_dictionary_member(member), + 'idl_type': + idl_type.base_type, + 'is_callback_function_type': + idl_type.is_callback_function, + 'is_interface_type': + idl_type.is_interface_type, + 'is_nullable': + idl_type.is_nullable, + 'is_object': + unwrapped_idl_type.name == 'Object', + 'is_string_type': + idl_type.preprocessed_type.is_string_type, + 'is_required': + member.is_required, + 'name': + member.name, + # [RuntimeEnabled] for origin trial 'origin_trial_feature_name': - v8_utilities.origin_trial_feature_name(member, runtime_features), # [RuntimeEnabled] for origin trial + v8_utilities.origin_trial_feature_name(member, runtime_features), + # [RuntimeEnabled] if not in origin trial 'runtime_enabled_feature_name': - v8_utilities.runtime_enabled_feature_name(member, runtime_features), # [RuntimeEnabled] if not in origin trial - 'setter_name': setter_name_for_dictionary_member(member), - 'has_value_or_default': has_value_or_default, - 'null_setter_name': null_setter_name_for_dictionary_member(member), - 'v8_default_value': v8_default_value, - 'v8_value': v8_value, - 'v8_value_to_local_cpp_value': idl_type.v8_value_to_local_cpp_value( - extended_attributes, v8_value, cpp_value, isolate='isolate', + v8_utilities.runtime_enabled_feature_name(member, runtime_features), + 'setter_name': + setter_name_for_dictionary_member(member), + 'has_value_or_default': + has_value_or_default, + 'null_setter_name': + null_setter_name_for_dictionary_member(member), + 'v8_default_value': + v8_default_value, + 'v8_value': + v8_value, + 'v8_value_to_local_cpp_value': + idl_type.v8_value_to_local_cpp_value( + extended_attributes, + v8_value, + cpp_value, + isolate='isolate', use_exception_state=True), } # Context for implementation classes + def dictionary_impl_context(dictionary, interfaces_info): def remove_duplicate_members(members): # When [ImplementedAs] is used, cpp_name can conflict. For example, @@ -202,14 +243,17 @@ def dictionary_impl_context(dictionary, interfaces_info): if duplicated_member and duplicated_member != member: raise Exception('Member name conflict: %s' % cpp_name) members_dict[cpp_name] = member - return sorted(members_dict.values(), key=lambda member: member['cpp_name']) + return sorted( + members_dict.values(), key=lambda member: member['cpp_name']) includes.clear() header_forward_decls = set() header_includes = set(['platform/heap/handle.h']) - members = [member_impl_context(member, interfaces_info, - header_includes, header_forward_decls) - for member in dictionary.members] + members = [ + member_impl_context(member, interfaces_info, header_includes, + header_forward_decls) + for member in dictionary.members + ] members = remove_duplicate_members(members) context = { 'header_forward_decls': header_forward_decls, @@ -218,8 +262,9 @@ def dictionary_impl_context(dictionary, interfaces_info): 'members': members, } if dictionary.parent: - context['parent_cpp_class'] = v8_utilities.cpp_name_from_interfaces_info( - dictionary.parent, interfaces_info) + context['parent_cpp_class'] = \ + v8_utilities.cpp_name_from_interfaces_info(dictionary.parent, + interfaces_info) parent_interface_info = interfaces_info.get(dictionary.parent) if parent_interface_info: context['header_includes'].add( @@ -241,8 +286,8 @@ def member_impl_context(member, interfaces_info, header_includes, # states for some types for memory usage and performance. # For types whose |has_explicit_presence| is True, we provide explicit # states of presence. - has_explicit_presence = ( - member.idl_type.is_nullable and member.idl_type.inner_type.is_interface_type) + has_explicit_presence = (member.idl_type.is_nullable + and member.idl_type.inner_type.is_interface_type) nullable_indicator_name = None if not idl_type.cpp_type_has_null_value or has_explicit_presence: @@ -256,50 +301,66 @@ def member_impl_context(member, interfaces_info, header_includes, if idl_type.name == 'Any': return '!({0}_.IsEmpty() || {0}_.IsUndefined())'.format(cpp_name) if idl_type.name == 'Object': - return '!({0}_.IsEmpty() || {0}_.IsNull() || {0}_.IsUndefined())'.format(cpp_name) - if idl_type.name == 'Dictionary': - return '!%s_.IsUndefinedOrNull()' % cpp_name - return '%s_' % cpp_name + return '!({0}_.IsEmpty() || {0}_.IsNull() || {0}_.IsUndefined())'.format( + cpp_name) + return '!!%s_' % cpp_name cpp_default_value = None if member.default_value: if not member.default_value.is_null or has_explicit_presence: - cpp_default_value = idl_type.literal_cpp_value(member.default_value) + cpp_default_value = idl_type.literal_cpp_value( + member.default_value) forward_decl_name = idl_type.impl_forward_declaration_name if forward_decl_name: includes.update(idl_type.impl_includes_for_type(interfaces_info)) header_forward_decls.add(forward_decl_name) else: - header_includes.update(idl_type.impl_includes_for_type(interfaces_info)) + header_includes.update( + idl_type.impl_includes_for_type(interfaces_info)) setter_value = 'value' - if idl_type.is_array_buffer_view_or_typed_array: - setter_value += '.View()' - non_null_type = idl_type.inner_type if idl_type.is_nullable else idl_type - setter_inline = 'inline ' if ( - non_null_type.is_basic_type or - non_null_type.is_enum or - non_null_type.is_wrapper_type) else '' + setter_inline = 'inline ' if (non_null_type.is_basic_type + or non_null_type.is_enum + or non_null_type.is_wrapper_type) else '' extended_attributes = member.extended_attributes return { - 'cpp_default_value': cpp_default_value, - 'cpp_name': cpp_name, - 'has_explicit_presence': has_explicit_presence, - 'getter_expression': cpp_name + '_', - 'getter_name': getter_name_for_dictionary_member(member), - 'has_method_expression': has_method_expression(), - 'has_method_name': has_method_name_for_dictionary_member(member), - 'is_nullable': idl_type.is_nullable, - 'is_traceable': idl_type.is_traceable, - 'member_cpp_type': idl_type.cpp_type_args(used_in_cpp_sequence=True, extended_attributes=extended_attributes), - 'null_setter_name': null_setter_name_for_dictionary_member(member), - 'nullable_indicator_name': nullable_indicator_name, - 'rvalue_cpp_type': idl_type.cpp_type_args(used_as_rvalue_type=True, extended_attributes=extended_attributes), - 'setter_inline': setter_inline, - 'setter_name': setter_name_for_dictionary_member(member), - 'setter_value': setter_value, + 'cpp_default_value': + cpp_default_value, + 'cpp_name': + cpp_name, + 'has_explicit_presence': + has_explicit_presence, + 'getter_expression': + cpp_name + '_', + 'getter_name': + getter_name_for_dictionary_member(member), + 'has_method_expression': + has_method_expression(), + 'has_method_name': + has_method_name_for_dictionary_member(member), + 'is_nullable': + idl_type.is_nullable, + 'is_traceable': + idl_type.is_traceable, + 'member_cpp_type': + idl_type.cpp_type_args( + used_in_cpp_sequence=True, + extended_attributes=extended_attributes), + 'null_setter_name': + null_setter_name_for_dictionary_member(member), + 'nullable_indicator_name': + nullable_indicator_name, + 'rvalue_cpp_type': + idl_type.cpp_type_args( + used_as_rvalue_type=True, extended_attributes=extended_attributes), + 'setter_inline': + setter_inline, + 'setter_name': + setter_name_for_dictionary_member(member), + 'setter_value': + setter_value, } diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_globals.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_globals.py index 55ed25722ed..49fb86151e3 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_globals.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_globals.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Module to share global variables (includes and interfaces) across modules.""" includes = set() diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py index 39ab8717569..02f604dee9d 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # pylint: disable=relative-import - """Generate template values for an interface. Design doc: http://www.chromium.org/developers/design-documents/idl-compiler @@ -37,8 +36,8 @@ import os import sys from operator import or_ -sys.path.append(os.path.join(os.path.dirname(__file__), - '..', '..', 'build', 'scripts')) +sys.path.append( + os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'scripts')) from blinkbuild.name_style_converter import NameStyleConverter from idl_definitions import IdlAttribute, IdlOperation, IdlArgument from idl_types import IdlType, inherits_interface @@ -50,11 +49,9 @@ from v8_globals import includes import v8_methods import v8_types import v8_utilities -from v8_utilities import (binding_header_filename, context_enabled_feature_name, - cpp_name_or_partial, cpp_name, - has_extended_attribute_value, - runtime_enabled_feature_name) - +from v8_utilities import ( + binding_header_filename, context_enabled_feature_name, cpp_name_or_partial, + cpp_name, has_extended_attribute_value, runtime_enabled_feature_name) INTERFACE_H_INCLUDES = frozenset([ 'bindings/core/v8/generated_code_helper.h', @@ -68,6 +65,7 @@ INTERFACE_H_INCLUDES = frozenset([ ]) INTERFACE_CPP_INCLUDES = frozenset([ 'base/memory/scoped_refptr.h', + 'bindings/core/v8/native_value_traits_impl.h', 'bindings/core/v8/v8_dom_configuration.h', 'core/execution_context/execution_context.h', 'platform/scheduler/public/cooperative_scheduling_manager.h', @@ -79,34 +77,42 @@ INTERFACE_CPP_INCLUDES = frozenset([ def filter_has_constant_configuration(constants): - return [constant for constant in constants if - not constant['measure_as'] and - not constant['deprecate_as'] and - not constant['runtime_enabled_feature_name'] and - not constant['origin_trial_feature_name']] + return [ + constant for constant in constants + if not constant['measure_as'] and not constant['deprecate_as'] + and not constant['runtime_enabled_feature_name'] + and not constant['origin_trial_feature_name'] + ] def filter_has_special_getter(constants): - return [constant for constant in constants if - constant['measure_as'] or - constant['deprecate_as']] + return [ + constant for constant in constants + if constant['measure_as'] or constant['deprecate_as'] + ] def filter_runtime_enabled(constants): - return [constant for constant in constants if - constant['runtime_enabled_feature_name']] + return [ + constant for constant in constants + if constant['runtime_enabled_feature_name'] + ] def filter_origin_trial_enabled(constants): - return [constant for constant in constants if - constant['origin_trial_feature_name']] + return [ + constant for constant in constants + if constant['origin_trial_feature_name'] + ] def constant_filters(): - return {'has_constant_configuration': filter_has_constant_configuration, - 'has_special_getter': filter_has_special_getter, - 'runtime_enabled_constants': filter_runtime_enabled, - 'origin_trial_enabled_constants': filter_origin_trial_enabled} + return { + 'has_constant_configuration': filter_has_constant_configuration, + 'has_special_getter': filter_has_special_getter, + 'runtime_enabled_constants': filter_runtime_enabled, + 'origin_trial_enabled_constants': filter_origin_trial_enabled + } def origin_trial_features(interface, constants, attributes, methods): @@ -128,26 +134,40 @@ def origin_trial_features(interface, constants, attributes, methods): # Collect all members visible on this interface with a defined origin trial origin_trial_constants = member_filter(constants) origin_trial_attributes = member_filter(attributes) - origin_trial_methods = member_filter([method for method in methods - if v8_methods.method_is_visible(method, interface.is_partial) and - not v8_methods.custom_registration(method)]) + origin_trial_methods = member_filter([ + method for method in methods + if v8_methods.method_is_visible(method, interface.is_partial) + and not v8_methods.custom_registration(method) + ]) - feature_names = set([member[KEY] for member in origin_trial_constants + origin_trial_attributes + origin_trial_methods]) + feature_names = set([ + member[KEY] for member in origin_trial_constants + + origin_trial_attributes + origin_trial_methods + ]) # Construct the list of dictionaries. 'needs_instance' will be true if any # member for the feature has 'on_instance' defined as true. - features = [{'name': name, - 'constants': member_filter_by_name(origin_trial_constants, name), - 'attributes': member_filter_by_name(origin_trial_attributes, name), - 'methods': member_filter_by_name(origin_trial_methods, name)} - for name in feature_names] + features = [{ + 'name': + name, + 'constants': + member_filter_by_name(origin_trial_constants, name), + 'attributes': + member_filter_by_name(origin_trial_attributes, name), + 'methods': + member_filter_by_name(origin_trial_methods, name) + } for name in feature_names] for feature in features: - members = feature['constants'] + feature['attributes'] + feature['methods'] - feature['needs_instance'] = any(member.get('on_instance', False) for member in members) + members = feature['constants'] + feature['attributes'] + feature[ + 'methods'] + feature['needs_instance'] = any( + member.get('on_instance', False) for member in members) # TODO(chasej): Need to handle method overloads? e.g. # (method['overloads']['secure_context_test_all'] if 'overloads' in method else method['secure_context_test']) - feature['needs_secure_context'] = any(member.get('secure_context_test', False) for member in members) - feature['needs_context'] = feature['needs_secure_context'] or any(member.get('exposed_test', False) for member in members) + feature['needs_secure_context'] = any( + member.get('secure_context_test', False) for member in members) + feature['needs_context'] = feature['needs_secure_context'] or any( + member.get('exposed_test', False) for member in members) if features: includes.add('platform/bindings/script_state.h') @@ -166,7 +186,10 @@ def context_enabled_features(attributes): KEY = 'context_enabled_feature_name' # pylint: disable=invalid-name def member_filter(members): - return sorted([member for member in members if member.get(KEY) and not member.get('exposed_test')]) + return sorted([ + member for member in members + if member.get(KEY) and not member.get('exposed_test') + ]) def member_filter_by_name(members, name): return [member for member in members if member[KEY] == name] @@ -174,10 +197,14 @@ def context_enabled_features(attributes): # Collect all members visible on this interface with a defined origin trial context_enabled_attributes = member_filter(attributes) feature_names = set([member[KEY] for member in context_enabled_attributes]) - features = [{'name': name, - 'attributes': member_filter_by_name(context_enabled_attributes, name), - 'needs_instance': False} - for name in feature_names] + features = [{ + 'name': + name, + 'attributes': + member_filter_by_name(context_enabled_attributes, name), + 'needs_instance': + False + } for name in feature_names] if features: includes.add('platform/bindings/script_state.h') return features @@ -186,13 +213,20 @@ def context_enabled_features(attributes): def runtime_call_stats_context(interface): counter_prefix = 'Blink_' + v8_utilities.cpp_name(interface) + '_' return { - 'constructor_counter': counter_prefix + 'Constructor', - 'cross_origin_named_getter_counter': counter_prefix + 'CrossOriginNamedGetter', - 'cross_origin_named_setter_counter': counter_prefix + 'CrossOriginNamedSetter', - 'indexed_property_getter_counter': counter_prefix + 'IndexedPropertyGetter', - 'named_property_getter_counter': counter_prefix + 'NamedPropertyGetter', - 'named_property_query_counter': counter_prefix + 'NamedPropertyQuery', - 'named_property_setter_counter': counter_prefix + 'NamedPropertySetter', + 'constructor_counter': + counter_prefix + 'Constructor', + 'cross_origin_named_getter_counter': + counter_prefix + 'CrossOriginNamedGetter', + 'cross_origin_named_setter_counter': + counter_prefix + 'CrossOriginNamedSetter', + 'indexed_property_getter_counter': + counter_prefix + 'IndexedPropertyGetter', + 'named_property_getter_counter': + counter_prefix + 'NamedPropertyGetter', + 'named_property_query_counter': + counter_prefix + 'NamedPropertyQuery', + 'named_property_setter_counter': + counter_prefix + 'NamedPropertySetter', } @@ -220,11 +254,13 @@ def interface_context(interface, interfaces, component_info): parent_interface = None is_event_target = False # partial interface needs the definition of its original interface. - includes.add('bindings/core/v8/%s' % binding_header_filename(interface.name)) + includes.add( + 'bindings/core/v8/%s' % binding_header_filename(interface.name)) else: parent_interface = interface.parent if parent_interface: - header_includes.update(v8_types.includes_for_interface(parent_interface)) + header_includes.update( + v8_types.includes_for_interface(parent_interface)) is_event_target = inherits_interface(interface.name, 'EventTarget') extended_attributes = interface.extended_attributes @@ -235,19 +271,18 @@ def interface_context(interface, interfaces, component_info): includes.update(('bindings/core/v8/v8_array_buffer.h', 'bindings/core/v8/v8_shared_array_buffer.h')) if interface.name == 'ArrayBufferView': - includes.update(( - 'bindings/core/v8/v8_int8_array.h', - 'bindings/core/v8/v8_int16_array.h', - 'bindings/core/v8/v8_int32_array.h', - 'bindings/core/v8/v8_uint8_array.h', - 'bindings/core/v8/v8_uint8_clamped_array.h', - 'bindings/core/v8/v8_uint16_array.h', - 'bindings/core/v8/v8_uint32_array.h', - 'bindings/core/v8/v8_big_int_64_array.h', - 'bindings/core/v8/v8_big_uint_64_array.h', - 'bindings/core/v8/v8_float32_array.h', - 'bindings/core/v8/v8_float64_array.h', - 'bindings/core/v8/v8_data_view.h')) + includes.update(('bindings/core/v8/v8_int8_array.h', + 'bindings/core/v8/v8_int16_array.h', + 'bindings/core/v8/v8_int32_array.h', + 'bindings/core/v8/v8_uint8_array.h', + 'bindings/core/v8/v8_uint8_clamped_array.h', + 'bindings/core/v8/v8_uint16_array.h', + 'bindings/core/v8/v8_uint32_array.h', + 'bindings/core/v8/v8_big_int_64_array.h', + 'bindings/core/v8/v8_big_uint_64_array.h', + 'bindings/core/v8/v8_float32_array.h', + 'bindings/core/v8/v8_float64_array.h', + 'bindings/core/v8/v8_data_view.h')) # [ActiveScriptWrappable] active_scriptwrappable = 'ActiveScriptWrappable' in extended_attributes @@ -266,12 +301,14 @@ def interface_context(interface, interfaces, component_info): # as in the WebIDL spec? is_immutable_prototype = is_global or 'ImmutablePrototype' in extended_attributes - wrapper_class_id = ('kNodeClassId' if inherits_interface(interface.name, 'Node') else 'kObjectClassId') + wrapper_class_id = ('kNodeClassId' if inherits_interface( + interface.name, 'Node') else 'kObjectClassId') # [LegacyUnenumerableNamedProperties] # pylint: disable=C0103 - has_legacy_unenumerable_named_properties = (interface.has_named_property_getter and - 'LegacyUnenumerableNamedProperties' in extended_attributes) + has_legacy_unenumerable_named_properties = ( + interface.has_named_property_getter + and 'LegacyUnenumerableNamedProperties' in extended_attributes) v8_class_name = v8_utilities.v8_class_name(interface) cpp_class_name = cpp_name(interface) @@ -280,55 +317,93 @@ def interface_context(interface, interfaces, component_info): # TODO(peria): Generate the target list from 'Window' and 'HTMLDocument'. needs_runtime_enabled_installer = v8_class_name in [ - 'V8Window', 'V8HTMLDocument', 'V8Document', 'V8Node', 'V8EventTarget'] + 'V8Window', 'V8HTMLDocument', 'V8Document', 'V8Node', 'V8EventTarget' + ] runtime_features = component_info['runtime_enabled_features'] context = { - 'active_scriptwrappable': active_scriptwrappable, - 'context_enabled_feature_name': context_enabled_feature_name(interface), # [ContextEnabled] - 'cpp_class': cpp_class_name, - 'cpp_class_or_partial': cpp_class_name_or_partial, - 'is_gc_type': True, + 'active_scriptwrappable': + active_scriptwrappable, + 'context_enabled_feature_name': + context_enabled_feature_name(interface), # [ContextEnabled] + 'cpp_class': + cpp_class_name, + 'cpp_class_or_partial': + cpp_class_name_or_partial, + 'is_gc_type': + True, # FIXME: Remove 'EventTarget' special handling, http://crbug.com/383699 - 'has_access_check_callbacks': (is_check_security and - interface.name != 'EventTarget'), - 'has_custom_legacy_call_as_function': has_extended_attribute_value(interface, 'Custom', 'LegacyCallAsFunction'), # [Custom=LegacyCallAsFunction] - 'has_legacy_unenumerable_named_properties': has_legacy_unenumerable_named_properties, - 'has_partial_interface': len(interface.partial_interfaces) > 0, - 'header_includes': header_includes, - 'interface_name': interface.name, - 'internal_namespace': internal_namespace(interface), - 'is_array_buffer_or_view': is_array_buffer_or_view, - 'is_check_security': is_check_security, - 'is_event_target': is_event_target, - 'is_global': is_global, - 'is_immutable_prototype': is_immutable_prototype, - 'is_node': inherits_interface(interface.name, 'Node'), - 'is_partial': interface.is_partial, - 'is_typed_array_type': is_typed_array_type, - 'measure_as': v8_utilities.measure_as(interface, None), # [MeasureAs] - 'needs_runtime_enabled_installer': needs_runtime_enabled_installer, - 'origin_trial_feature_name': v8_utilities.origin_trial_feature_name(interface, runtime_features), - 'parent_interface': parent_interface, - 'pass_cpp_type': cpp_name(interface) + '*', - 'runtime_call_stats': runtime_call_stats_context(interface), - 'runtime_enabled_feature_name': runtime_enabled_feature_name(interface, runtime_features), # [RuntimeEnabled] - 'snake_case_v8_class': NameStyleConverter(v8_class_name).to_snake_case(), - 'v8_class': v8_class_name, - 'v8_class_or_partial': v8_class_name_or_partial, - 'wrapper_class_id': wrapper_class_id, + 'has_access_check_callbacks': (is_check_security + and interface.name != 'EventTarget'), + # [Custom=LegacyCallAsFunction] + 'has_custom_legacy_call_as_function': + has_extended_attribute_value(interface, 'Custom', + 'LegacyCallAsFunction'), + 'has_legacy_unenumerable_named_properties': + has_legacy_unenumerable_named_properties, + 'has_partial_interface': + len(interface.partial_interfaces) > 0, + 'header_includes': + header_includes, + 'interface_name': + interface.name, + 'internal_namespace': + internal_namespace(interface), + 'is_array_buffer_or_view': + is_array_buffer_or_view, + 'is_check_security': + is_check_security, + 'is_event_target': + is_event_target, + 'is_global': + is_global, + 'is_immutable_prototype': + is_immutable_prototype, + 'is_node': + inherits_interface(interface.name, 'Node'), + 'is_partial': + interface.is_partial, + 'is_typed_array_type': + is_typed_array_type, + # [MeasureAs] + 'measure_as': + v8_utilities.measure_as(interface, None), + 'needs_runtime_enabled_installer': + needs_runtime_enabled_installer, + 'origin_trial_feature_name': + v8_utilities.origin_trial_feature_name(interface, runtime_features), + 'parent_interface': + parent_interface, + 'pass_cpp_type': + cpp_name(interface) + '*', + 'runtime_call_stats': + runtime_call_stats_context(interface), + # [RuntimeEnabled] + 'runtime_enabled_feature_name': + runtime_enabled_feature_name(interface, runtime_features), + 'snake_case_v8_class': + NameStyleConverter(v8_class_name).to_snake_case(), + 'v8_class': + v8_class_name, + 'v8_class_or_partial': + v8_class_name_or_partial, + 'wrapper_class_id': + wrapper_class_id, } # Constructors - constructors = [constructor_context(interface, constructor) - for constructor in interface.constructors - # FIXME: shouldn't put named constructors with constructors - # (currently needed for Perl compatibility) - # Handle named constructors separately - if constructor.name == 'Constructor'] + constructors = [ + constructor_context(interface, constructor) + for constructor in interface.constructors + # FIXME: shouldn't put named constructors with constructors + # (currently needed for Perl compatibility) + # Handle named constructors separately + if constructor.name == 'Constructor' + ] if len(constructors) > 1: - context['constructor_overloads'] = overloads_context(interface, constructors) + context['constructor_overloads'] = overloads_context( + interface, constructors) # [CustomConstructor] custom_constructors = [{ # Only needed for computing interface length @@ -340,8 +415,9 @@ def interface_context(interface, interfaces, component_info): has_html_constructor = 'HTMLConstructor' in extended_attributes # https://html.spec.whatwg.org/C/#html-element-constructors if has_html_constructor: - if ('Constructor' in extended_attributes or - 'NoInterfaceObject' in extended_attributes or interface.is_mixin): + if ('Constructor' in extended_attributes + or 'NoInterfaceObject' in extended_attributes + or interface.is_mixin): raise Exception('[HTMLConstructor] cannot be specified with ' '[Constructor] or [NoInterfaceObject], or on ' 'a mixin : %s' % interface.name) @@ -363,21 +439,27 @@ def interface_context(interface, interfaces, component_info): includes.add('core/frame/local_dom_window.h') elif 'Measure' in extended_attributes or 'MeasureAs' in extended_attributes: if not interface.is_partial: - raise Exception('[Measure] or [MeasureAs] specified for interface without a constructor: ' - '%s' % interface.name) + raise Exception( + '[Measure] or [MeasureAs] specified for interface without a constructor: ' + '%s' % interface.name) # [ConstructorCallWith=Document] - if has_extended_attribute_value(interface, 'ConstructorCallWith', 'Document'): + if has_extended_attribute_value(interface, 'ConstructorCallWith', + 'Document'): includes.add('core/dom/document.h') # [Unscopable] attributes and methods unscopables = [] for attribute in interface.attributes: if 'Unscopable' in attribute.extended_attributes: - unscopables.append((attribute.name, runtime_enabled_feature_name(attribute, runtime_features))) + unscopables.append((attribute.name, + runtime_enabled_feature_name( + attribute, runtime_features))) for method in interface.operations: if 'Unscopable' in method.extended_attributes: - unscopables.append((method.name, runtime_enabled_feature_name(method, runtime_features))) + unscopables.append((method.name, + runtime_enabled_feature_name( + method, runtime_features))) # [CEReactions] setter_or_deleters = ( @@ -386,49 +468,77 @@ def interface_context(interface, interfaces, component_info): interface.named_property_setter, interface.named_property_deleter, ) - has_ce_reactions = any(setter_or_deleter and 'CEReactions' in setter_or_deleter.extended_attributes - for setter_or_deleter in setter_or_deleters) + has_ce_reactions = any( + setter_or_deleter + and 'CEReactions' in setter_or_deleter.extended_attributes + for setter_or_deleter in setter_or_deleters) if has_ce_reactions: includes.add('core/html/custom/ce_reactions_scope.h') context.update({ - 'constructors': constructors, - 'has_custom_constructor': bool(custom_constructors), - 'has_html_constructor': has_html_constructor, + 'constructors': + constructors, + 'has_custom_constructor': + bool(custom_constructors), + 'has_html_constructor': + has_html_constructor, 'interface_length': - interface_length(constructors + custom_constructors), - 'is_constructor_raises_exception': extended_attributes.get('RaisesException') == 'Constructor', # [RaisesException=Constructor] - 'named_constructor': named_constructor, - 'unscopables': sorted(unscopables), + interface_length(constructors + custom_constructors), + # [RaisesException=Constructor] + 'is_constructor_raises_exception': + extended_attributes.get('RaisesException') == 'Constructor', + 'named_constructor': + named_constructor, + 'unscopables': + sorted(unscopables), }) # Constants context.update({ - 'constants': [constant_context(constant, interface, component_info) for constant in interface.constants], - 'do_not_check_constants': 'DoNotCheckConstants' in extended_attributes, + 'constants': [ + constant_context(constant, interface, component_info) + for constant in interface.constants + ], + 'do_not_check_constants': + 'DoNotCheckConstants' in extended_attributes, }) # Attributes attributes = attributes_context(interface, interfaces, component_info) context.update({ - 'attributes': attributes, + 'attributes': + attributes, # Elements in attributes are broken in following members. - 'accessors': v8_attributes.filter_accessors(attributes), - 'data_attributes': v8_attributes.filter_data_attributes(attributes), - 'runtime_enabled_attributes': v8_attributes.filter_runtime_enabled(attributes), + 'accessors': + v8_attributes.filter_accessors(attributes), + 'data_attributes': + v8_attributes.filter_data_attributes(attributes), + 'runtime_enabled_attributes': + v8_attributes.filter_runtime_enabled(attributes), }) # Conditionally enabled attributes - conditionally_enabled_attributes = v8_attributes.filter_conditionally_enabled(attributes) - conditional_attributes = [attr for attr in conditionally_enabled_attributes if not attr['constructor_type']] - conditional_interface_objects = [attr for attr in conditionally_enabled_attributes if attr['constructor_type']] + conditionally_enabled_attributes = v8_attributes.filter_conditionally_enabled( + attributes) + conditional_attributes = [ + attr for attr in conditionally_enabled_attributes + if not attr['constructor_type'] + ] + conditional_interface_objects = [ + attr for attr in conditionally_enabled_attributes + if attr['constructor_type'] + ] has_conditional_secure_attributes = any( # pylint: disable=invalid-name - v8_attributes.is_secure_context(attr) for attr in conditionally_enabled_attributes) + v8_attributes.is_secure_context(attr) + for attr in conditionally_enabled_attributes) context.update({ - 'conditional_attributes': conditional_attributes, - 'conditional_interface_objects': conditional_interface_objects, - 'has_conditional_secure_attributes': has_conditional_secure_attributes, + 'conditional_attributes': + conditional_attributes, + 'conditional_interface_objects': + conditional_interface_objects, + 'has_conditional_secure_attributes': + has_conditional_secure_attributes, }) # Methods @@ -436,22 +546,24 @@ def interface_context(interface, interfaces, component_info): methods = context['methods'] # Conditionally enabled methods - conditional_methods = v8_methods.filter_conditionally_enabled(methods, interface.is_partial) + conditional_methods = v8_methods.filter_conditionally_enabled( + methods, interface.is_partial) has_conditional_secure_methods = any( # pylint: disable=invalid-name v8_methods.is_secure_context(method) for method in conditional_methods) context.update({ 'has_conditional_secure_methods': - has_conditional_secure_methods, - 'conditional_methods': conditional_methods, + has_conditional_secure_methods, + 'conditional_methods': + conditional_methods, }) # Window.idl in Blink has indexed properties, but the spec says Window # interface doesn't have indexed properties, instead the WindowProxy exotic # object has indexed properties. Thus, Window interface must not support # iterators. - has_array_iterator = (not interface.is_partial and - interface.has_indexed_elements and - interface.name != 'Window') + has_array_iterator = (not interface.is_partial + and interface.has_indexed_elements + and interface.name != 'Window') context.update({ 'has_array_iterator': has_array_iterator, 'iterable': interface.iterable, @@ -464,27 +576,38 @@ def interface_context(interface, interfaces, component_info): v8_class_name_or_partial + '::InstallConditionalFeatures') context.update({ - 'install_conditional_features_func': install_conditional_features_func, + 'install_conditional_features_func': + install_conditional_features_func, }) context.update({ - 'indexed_property_getter': property_getter(interface.indexed_property_getter, ['index']), - 'indexed_property_setter': property_setter(interface.indexed_property_setter, interface), - 'indexed_property_deleter': property_deleter(interface.indexed_property_deleter), - 'is_override_builtins': 'OverrideBuiltins' in extended_attributes, - 'named_property_getter': property_getter(interface.named_property_getter, ['name']), - 'named_property_setter': property_setter(interface.named_property_setter, interface), - 'named_property_deleter': property_deleter(interface.named_property_deleter), + 'indexed_property_getter': + property_getter(interface.indexed_property_getter, ['index']), + 'indexed_property_setter': + property_setter(interface.indexed_property_setter, interface), + 'indexed_property_deleter': + property_deleter(interface.indexed_property_deleter), + 'is_override_builtins': + 'OverrideBuiltins' in extended_attributes, + 'named_property_getter': + property_getter(interface.named_property_getter, ['name']), + 'named_property_setter': + property_setter(interface.named_property_setter, interface), + 'named_property_deleter': + property_deleter(interface.named_property_deleter), }) context.update({ - 'has_named_properties_object': is_global and context['named_property_getter'], + 'has_named_properties_object': + is_global and context['named_property_getter'], }) # Origin Trials and ContextEnabled features context.update({ 'optional_features': - sorted(origin_trial_features(interface, context['constants'], context['attributes'], context['methods']) + - context_enabled_features(context['attributes'])), + sorted( + origin_trial_features(interface, context['constants'], + context['attributes'], context['methods']) + + context_enabled_features(context['attributes'])), }) if context['optional_features']: includes.add('platform/bindings/v8_per_context_data.h') @@ -510,17 +633,23 @@ def interface_context(interface, interfaces, component_info): has_cross_origin_named_enumerator = has_cross_origin_named_getter or has_cross_origin_named_setter # pylint: disable=invalid-name - if context['named_property_getter'] and context['named_property_getter']['is_cross_origin']: + if (context['named_property_getter'] + and context['named_property_getter']['is_cross_origin']): has_cross_origin_named_getter = True - if context['indexed_property_getter'] and context['indexed_property_getter']['is_cross_origin']: + if context['indexed_property_getter'] and context[ + 'indexed_property_getter']['is_cross_origin']: has_cross_origin_indexed_getter = True context.update({ - 'has_cross_origin_named_getter': has_cross_origin_named_getter, - 'has_cross_origin_named_setter': has_cross_origin_named_setter, - 'has_cross_origin_named_enumerator': has_cross_origin_named_enumerator, - 'has_cross_origin_indexed_getter': has_cross_origin_indexed_getter, + 'has_cross_origin_named_getter': + has_cross_origin_named_getter, + 'has_cross_origin_named_setter': + has_cross_origin_named_setter, + 'has_cross_origin_named_enumerator': + has_cross_origin_named_enumerator, + 'has_cross_origin_indexed_getter': + has_cross_origin_indexed_getter, }) return context @@ -538,15 +667,19 @@ def attributes_context(interface, interfaces, component_info): A list of attribute contexts """ - attributes = [v8_attributes.attribute_context(interface, attribute, interfaces, component_info) - for attribute in interface.attributes] + attributes = [ + v8_attributes.attribute_context(interface, attribute, interfaces, + component_info) + for attribute in interface.attributes + ] - has_conditional_attributes = any(attribute['exposed_test'] for attribute in attributes) + has_conditional_attributes = any( + attribute['exposed_test'] for attribute in attributes) if has_conditional_attributes and interface.is_partial: raise Exception( 'Conditional attributes between partial interfaces in modules ' - 'and the original interfaces(%s) in core are not allowed.' - % interface.name) + 'and the original interfaces(%s) in core are not allowed.' % + interface.name) # See also comment in methods_context. if not interface.is_partial and (interface.maplike or interface.setlike): @@ -559,8 +692,9 @@ def attributes_context(interface, interfaces, component_info): size_attribute.idl_type = IdlType('unsigned long') size_attribute.is_read_only = True size_attribute.extended_attributes['NotEnumerable'] = None - attributes.append(v8_attributes.attribute_context( - interface, size_attribute, interfaces, component_info)) + attributes.append( + v8_attributes.attribute_context(interface, size_attribute, + interfaces, component_info)) return attributes @@ -583,21 +717,32 @@ def methods_context(interface, component_info): methods = [] if interface.original_interface: - methods.extend([v8_methods.method_context(interface, operation, component_info, is_visible=False) - for operation in interface.original_interface.operations - if operation.name]) - methods.extend([v8_methods.method_context(interface, method, component_info) - for method in interface.operations - if method.name]) # Skip anonymous special operations (methods) + methods.extend([ + v8_methods.method_context( + interface, operation, component_info, is_visible=False) + for operation in interface.original_interface.operations + if operation.name + ]) + methods.extend([ + v8_methods.method_context(interface, method, component_info) + for method in interface.operations if method.name + ]) # Skip anonymous special operations (methods) if interface.partial_interfaces: - assert len(interface.partial_interfaces) == len(set(interface.partial_interfaces)) + assert len(interface.partial_interfaces) == len( + set(interface.partial_interfaces)) for partial_interface in interface.partial_interfaces: - methods.extend([v8_methods.method_context(interface, operation, component_info, is_visible=False) - for operation in partial_interface.operations - if operation.name]) + methods.extend([ + v8_methods.method_context( + interface, operation, component_info, is_visible=False) + for operation in partial_interface.operations if operation.name + ]) compute_method_overloads_context(interface, methods) - def generated_method(return_type, name, arguments=None, extended_attributes=None, implemented_as=None): + def generated_method(return_type, + name, + arguments=None, + extended_attributes=None, + implemented_as=None): operation = IdlOperation() operation.idl_type = return_type operation.name = name @@ -610,7 +755,10 @@ def methods_context(interface, component_info): operation.extended_attributes['ImplementedAs'] = implemented_as return v8_methods.method_context(interface, operation, component_info) - def generated_argument(idl_type, name, is_optional=False, extended_attributes=None): + def generated_argument(idl_type, + name, + is_optional=False, + extended_attributes=None): argument = IdlArgument() argument.idl_type = idl_type argument.name = name @@ -630,23 +778,30 @@ def methods_context(interface, component_info): # need to support iterator overloads between interface and # partial interface definitions. # http://heycam.github.io/webidl/#idl-overloading - if (not interface.is_partial and ( - interface.iterable or interface.maplike or interface.setlike or - interface.has_indexed_elements)): + if (not interface.is_partial + and (interface.iterable or interface.maplike or interface.setlike + or interface.has_indexed_elements)): used_extended_attributes = {} if interface.iterable: - used_extended_attributes.update(interface.iterable.extended_attributes) + used_extended_attributes.update( + interface.iterable.extended_attributes) elif interface.maplike: - used_extended_attributes.update(interface.maplike.extended_attributes) + used_extended_attributes.update( + interface.maplike.extended_attributes) elif interface.setlike: - used_extended_attributes.update(interface.setlike.extended_attributes) + used_extended_attributes.update( + interface.setlike.extended_attributes) if 'RaisesException' in used_extended_attributes: - raise ValueError('[RaisesException] is implied for iterable<>/maplike<>/setlike<>') + raise ValueError( + '[RaisesException] is implied for iterable<>/maplike<>/setlike<>' + ) if 'CallWith' in used_extended_attributes: - raise ValueError('[CallWith=ScriptState] is implied for iterable<>/maplike<>/setlike<>') + raise ValueError( + '[CallWith=ScriptState] is implied for iterable<>/maplike<>/setlike<>' + ) used_extended_attributes.update({ 'RaisesException': None, @@ -666,7 +821,8 @@ def methods_context(interface, component_info): implemented_as=implemented_as) if not interface.has_indexed_elements: - iterator_method = generated_iterator_method('iterator', implemented_as='GetIterator') + iterator_method = generated_iterator_method( + 'iterator', implemented_as='GetIterator') if interface.iterable or interface.maplike or interface.setlike: non_overridable_methods = [] @@ -681,68 +837,101 @@ def methods_context(interface, component_info): if not is_value_iterator: if not interface.setlike: iterator_method_alias = 'entries' - entries_or_values_method = generated_iterator_method('values') + entries_or_values_method = generated_iterator_method( + 'values') else: iterator_method_alias = 'values' - entries_or_values_method = generated_iterator_method('entries') + entries_or_values_method = generated_iterator_method( + 'entries') non_overridable_methods.extend([ generated_iterator_method('keys'), entries_or_values_method, # void forEach(ForEachIteratorCallback callback, [DefaultValue=Undefined] optional any thisArg) - generated_method(IdlType('void'), 'forEach', - arguments=[generated_argument(IdlType('ForEachIteratorCallback'), 'callback'), - generated_argument(IdlType('any'), 'thisArg', - is_optional=True, - extended_attributes={'DefaultValue': 'Undefined'})], - extended_attributes=forEach_extended_attributes), + generated_method( + IdlType('void'), + 'forEach', + arguments=[ + generated_argument( + IdlType('ForEachIteratorCallback'), + 'callback'), + generated_argument( + IdlType('any'), + 'thisArg', + is_optional=True, + extended_attributes={ + 'DefaultValue': 'Undefined' + }) + ], + extended_attributes=forEach_extended_attributes), ]) if interface.maplike: - key_argument = generated_argument(interface.maplike.key_type, 'key') - value_argument = generated_argument(interface.maplike.value_type, 'value') + key_argument = generated_argument(interface.maplike.key_type, + 'key') + value_argument = generated_argument( + interface.maplike.value_type, 'value') non_overridable_methods.extend([ - generated_method(IdlType('boolean'), 'has', - arguments=[key_argument], - extended_attributes=used_extended_attributes), - generated_method(IdlType('any'), 'get', - arguments=[key_argument], - extended_attributes=used_extended_attributes), + generated_method( + IdlType('boolean'), + 'has', + arguments=[key_argument], + extended_attributes=used_extended_attributes), + generated_method( + IdlType('any'), + 'get', + arguments=[key_argument], + extended_attributes=used_extended_attributes), ]) if not interface.maplike.is_read_only: overridable_methods.extend([ - generated_method(IdlType('void'), 'clear', - extended_attributes=used_extended_attributes), - generated_method(IdlType('boolean'), 'delete', - arguments=[key_argument], - extended_attributes=used_extended_attributes), - generated_method(IdlType(interface.name), 'set', - arguments=[key_argument, value_argument], - extended_attributes=used_extended_attributes), + generated_method( + IdlType('void'), + 'clear', + extended_attributes=used_extended_attributes), + generated_method( + IdlType('boolean'), + 'delete', + arguments=[key_argument], + extended_attributes=used_extended_attributes), + generated_method( + IdlType(interface.name), + 'set', + arguments=[key_argument, value_argument], + extended_attributes=used_extended_attributes), ]) if interface.setlike: - value_argument = generated_argument(interface.setlike.value_type, 'value') + value_argument = generated_argument( + interface.setlike.value_type, 'value') non_overridable_methods.extend([ - generated_method(IdlType('boolean'), 'has', - arguments=[value_argument], - extended_attributes=used_extended_attributes), + generated_method( + IdlType('boolean'), + 'has', + arguments=[value_argument], + extended_attributes=used_extended_attributes), ]) if not interface.setlike.is_read_only: overridable_methods.extend([ - generated_method(IdlType(interface.name), 'add', - arguments=[value_argument], - extended_attributes=used_extended_attributes), - generated_method(IdlType('void'), 'clear', - extended_attributes=used_extended_attributes), - generated_method(IdlType('boolean'), 'delete', - arguments=[value_argument], - extended_attributes=used_extended_attributes), + generated_method( + IdlType(interface.name), + 'add', + arguments=[value_argument], + extended_attributes=used_extended_attributes), + generated_method( + IdlType('void'), + 'clear', + extended_attributes=used_extended_attributes), + generated_method( + IdlType('boolean'), + 'delete', + arguments=[value_argument], + extended_attributes=used_extended_attributes), ]) methods_by_name = {} @@ -776,11 +965,12 @@ def methods_context(interface, component_info): implemented_as = stringifier.operation.name else: implemented_as = 'toString' - methods.append(generated_method( - return_type=IdlType('DOMString'), - name='toString', - extended_attributes=stringifier_ext_attrs, - implemented_as=implemented_as)) + methods.append( + generated_method( + return_type=IdlType('DOMString'), + name='toString', + extended_attributes=stringifier_ext_attrs, + implemented_as=implemented_as)) for method in methods: # The value of the Function object’s “length” property is a Number @@ -794,7 +984,8 @@ def methods_context(interface, component_info): # enabled overloads are actually enabled, so length may be incorrect. # E.g., [RuntimeEnabled=Foo] void f(); void f(long x); # should have length 1 if Foo is not enabled, but length 0 if it is. - method['length'] = (method['overloads']['length'] if 'overloads' in method else + method['length'] = (method['overloads']['length'] + if 'overloads' in method else method['number_of_required_arguments']) return { @@ -822,22 +1013,36 @@ def constant_context(constant, interface, component_info): runtime_features = component_info['runtime_enabled_features'] return { - 'camel_case_name': NameStyleConverter(constant.name).to_upper_camel_case(), - 'cpp_class': extended_attributes.get('PartialInterfaceImplementedAs'), - 'cpp_type': constant.idl_type.cpp_type, - 'deprecate_as': v8_utilities.deprecate_as(constant), # [DeprecateAs] - 'idl_type': constant.idl_type.name, - 'measure_as': v8_utilities.measure_as(constant, interface), # [MeasureAs] - 'high_entropy': v8_utilities.high_entropy(constant), # [HighEntropy] - 'name': constant.name, - 'origin_trial_feature_name': v8_utilities.origin_trial_feature_name(constant, - runtime_features), # [RuntimeEnabled] for origin trial + 'camel_case_name': + NameStyleConverter(constant.name).to_upper_camel_case(), + 'cpp_class': + extended_attributes.get('PartialInterfaceImplementedAs'), + 'cpp_type': + constant.idl_type.cpp_type, + 'deprecate_as': + v8_utilities.deprecate_as(constant), # [DeprecateAs] + 'idl_type': + constant.idl_type.name, + 'measure_as': + v8_utilities.measure_as(constant, interface), # [MeasureAs] + 'high_entropy': + v8_utilities.high_entropy(constant), # [HighEntropy] + 'name': + constant.name, + # [RuntimeEnabled] for origin trial + 'origin_trial_feature_name': + v8_utilities.origin_trial_feature_name(constant, runtime_features), # FIXME: use 'reflected_name' as correct 'name' - 'rcs_counter': 'Blink_' + v8_utilities.cpp_name(interface) + '_' + constant.name + '_ConstantGetter', - 'reflected_name': extended_attributes.get('Reflect', reflected_name(constant.name)), - 'runtime_enabled_feature_name': runtime_enabled_feature_name(constant, - runtime_features), # [RuntimeEnabled] if not in origin trial - 'value': constant.value, + 'rcs_counter': + 'Blink_' + v8_utilities.cpp_name(interface) + '_' + constant.name + + '_ConstantGetter', + 'reflected_name': + extended_attributes.get('Reflect', reflected_name(constant.name)), + # [RuntimeEnabled] if not in origin trial + 'runtime_enabled_feature_name': + runtime_enabled_feature_name(constant, runtime_features), + 'value': + constant.value, } @@ -845,6 +1050,7 @@ def constant_context(constant, interface, component_info): # Overloads ################################################################################ + def compute_method_overloads_context(interface, methods): # Regular methods compute_method_overloads_context_by_type( @@ -870,7 +1076,8 @@ def compute_method_overloads_context_by_type(interface, methods): # package necessary information into |method.overloads| for that method. overloads[-1]['overloads'] = overloads_context(interface, overloads) overloads[-1]['overloads']['name'] = name - overloads[-1]['overloads']['camel_case_name'] = NameStyleConverter(name).to_upper_camel_case() + overloads[-1]['overloads']['camel_case_name'] = NameStyleConverter( + name).to_upper_camel_case() def overloads_context(interface, overloads): @@ -887,8 +1094,10 @@ def overloads_context(interface, overloads): # TODO(iclelland): Allow origin trials on method overloads # (crbug.com/621641) if any(method.get('origin_trial_feature_name') for method in overloads): - raise Exception('[RuntimeEnabled] for origin trial cannot be specified on ' - 'overloaded methods: %s.%s' % (interface.name, overloads[0]['name'])) + raise Exception( + '[RuntimeEnabled] for origin trial cannot be specified on ' + 'overloaded methods: %s.%s' % (interface.name, + overloads[0]['name'])) effective_overloads_by_length = effective_overload_set_by_length(overloads) lengths = [length for length, _ in effective_overloads_by_length] @@ -907,7 +1116,8 @@ def overloads_context(interface, overloads): # runtime enabled, in which case we need to have a runtime determined # Function.length. shortest_overloads = effective_overloads_by_length[0][1] - if (all(method.get('runtime_enabled_feature_name') + if (all( + method.get('runtime_enabled_feature_name') for method, _, _ in shortest_overloads)): # Generate a list of (length, runtime_enabled_feature_names) tuples. runtime_determined_lengths = [] @@ -921,19 +1131,21 @@ def overloads_context(interface, overloads): break runtime_determined_lengths.append( (length, sorted(runtime_enabled_feature_names))) - function_length = ('%s::%sMethodLength()' - % (internal_namespace(interface), camel_case_name)) + function_length = ('%s::%sMethodLength()' % ( + internal_namespace(interface), camel_case_name)) # Check if all overloads with the longest required arguments list are # runtime enabled, in which case we need to have a runtime determined # maximum distinguishing argument index. longest_overloads = effective_overloads_by_length[-1][1] - if (not common_value(overloads, 'runtime_enabled_feature_name') and - all(method.get('runtime_enabled_feature_name') + if (not common_value(overloads, 'runtime_enabled_feature_name') + and all( + method.get('runtime_enabled_feature_name') for method, _, _ in longest_overloads)): # Generate a list of (length, runtime_enabled_feature_name) tuples. runtime_determined_maxargs = [] - for length, effective_overloads in reversed(effective_overloads_by_length): + for length, effective_overloads in reversed( + effective_overloads_by_length): runtime_enabled_feature_names = set( method['runtime_enabled_feature_name'] for method, _, _ in effective_overloads @@ -944,15 +1156,17 @@ def overloads_context(interface, overloads): break runtime_determined_maxargs.append( (length, sorted(runtime_enabled_feature_names))) - maxarg = ('%s::%sMethodMaxArg()' % - (internal_namespace(interface), camel_case_name)) + maxarg = ('%s::%sMethodMaxArg()' % (internal_namespace(interface), + camel_case_name)) # Check and fail if overloads disagree about whether the return type # is a Promise or not. - promise_overload_count = sum(1 for method in overloads if method.get('returns_promise')) + promise_overload_count = sum( + 1 for method in overloads if method.get('returns_promise')) if promise_overload_count not in (0, len(overloads)): - raise ValueError('Overloads of %s have conflicting Promise/non-Promise types' - % (name)) + raise ValueError( + 'Overloads of %s have conflicting Promise/non-Promise types' % + (name)) has_overload_visible = False has_overload_not_visible = False @@ -969,30 +1183,45 @@ def overloads_context(interface, overloads): has_partial_overloads = has_overload_visible and has_overload_not_visible return { - 'deprecate_all_as': common_value(overloads, 'deprecate_as'), # [DeprecateAs] - 'exposed_test_all': common_value(overloads, 'exposed_test'), # [Exposed] - 'length': function_length, - 'length_tests_methods': length_tests_methods(effective_overloads_by_length), + 'deprecate_all_as': + common_value(overloads, 'deprecate_as'), # [DeprecateAs] + 'exposed_test_all': + common_value(overloads, 'exposed_test'), # [Exposed] + 'length': + function_length, + 'length_tests_methods': + length_tests_methods(effective_overloads_by_length), # 1. Let maxarg be the length of the longest type list of the # entries in S. - 'maxarg': maxarg, - 'measure_all_as': common_value(overloads, 'measure_as'), # [MeasureAs] - 'returns_promise_all': promise_overload_count > 0, - 'runtime_determined_lengths': runtime_determined_lengths, - 'runtime_determined_maxargs': runtime_determined_maxargs, - 'runtime_enabled_all': common_value(overloads, 'runtime_enabled_feature_name'), # [RuntimeEnabled] - 'secure_context_test_all': common_value(overloads, 'secure_context_test'), # [SecureContext] - 'valid_arities': (lengths - # Only need to report valid arities if there is a gap in the - # sequence of possible lengths, otherwise invalid length means - # "not enough arguments". - if lengths[-1] - lengths[0] != len(lengths) - 1 else None), - 'visible': has_overload_visible, - 'has_partial_overloads': has_partial_overloads, + 'maxarg': + maxarg, + 'measure_all_as': + common_value(overloads, 'measure_as'), # [MeasureAs] + 'returns_promise_all': + promise_overload_count > 0, + 'runtime_determined_lengths': + runtime_determined_lengths, + 'runtime_determined_maxargs': + runtime_determined_maxargs, + # [RuntimeEnabled] + 'runtime_enabled_all': + common_value(overloads, 'runtime_enabled_feature_name'), + # [SecureContext] + 'secure_context_test_all': + common_value(overloads, 'secure_context_test'), + 'valid_arities': ( + lengths + # Only need to report valid arities if there is a gap in the + # sequence of possible lengths, otherwise invalid length means + # "not enough arguments". + if lengths[-1] - lengths[0] != len(lengths) - 1 else None), + 'visible': + has_overload_visible, + 'has_partial_overloads': + has_partial_overloads, } - def distinguishing_argument_index(entries): """Returns the distinguishing argument index for a sequence of entries. @@ -1017,9 +1246,10 @@ def distinguishing_argument_index(entries): return idl_type.inner_type.name return idl_type.name - type_lists = [tuple(typename_without_nullable(idl_type) - for idl_type in entry[1]) - for entry in entries] + type_lists = [ + tuple(typename_without_nullable(idl_type) for idl_type in entry[1]) + for entry in entries + ] type_list_length = len(type_lists[0]) # Only applicable for entries that “[have] a given type list length” assert all(len(type_list) == type_list_length for type_list in type_lists) @@ -1039,8 +1269,8 @@ def distinguishing_argument_index(entries): # “In addition, for each index j, where j is less than the # distinguishing argument index for a given type list length, the types # at index j in all of the entries’ type lists must be the same” - index = next(i for i, types in enumerate(types_by_index) - if len(types) > 1) + index = next( + i for i, types in enumerate(types_by_index) if len(types) > 1) except StopIteration: raise ValueError('No distinguishing index found for %s, length %s:\n' 'All entries have the same type list:\n' @@ -1055,15 +1285,16 @@ def distinguishing_argument_index(entries): raise ValueError( 'Invalid optionality lists for %s, length %s:\n' 'Optionality lists differ below distinguishing argument index %s:\n' - '%s' - % (name, type_list_length, index, set(initial_optionality_lists))) + '%s' % (name, type_list_length, index, + set(initial_optionality_lists))) # Check distinguishability # http://heycam.github.io/webidl/#dfn-distinguishable # Use names to check for distinct types, since objects are distinct # FIXME: check distinguishability more precisely, for validation - distinguishing_argument_type_names = [type_list[index] - for type_list in type_lists] + distinguishing_argument_type_names = [ + type_list[index] for type_list in type_lists + ] if (len(set(distinguishing_argument_type_names)) != len(distinguishing_argument_type_names)): raise ValueError('Types in distinguishing argument are not distinct:\n' @@ -1100,8 +1331,9 @@ def resolution_tests_methods(effective_overloads): Returns: [(test, method)] """ - methods = [effective_overload[0] - for effective_overload in effective_overloads] + methods = [ + effective_overload[0] for effective_overload in effective_overloads + ] if len(methods) == 1: # If only one method with a given length, no test needed yield 'true', methods[0] @@ -1251,9 +1483,8 @@ def resolution_tests_methods(effective_overloads): # ... try: method = next(method for idl_type, method in idl_types_methods - if idl_type.is_callback_interface or - idl_type.is_dictionary or idl_type.name == 'Dictionary' or - idl_type.is_record_type) + if idl_type.is_callback_interface + or idl_type.is_dictionary or idl_type.is_record_type) test = '%s->IsObject()' % cpp_value yield test, method except StopIteration: @@ -1288,9 +1519,10 @@ def resolution_tests_methods(effective_overloads): # • a string type # ... try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.is_string_type or idl_type.is_enum - or (idl_type.is_union_type and idl_type.string_member_type)) + method = next( + method for idl_type, method in idl_types_methods + if idl_type.is_string_type or idl_type.is_enum or ( + idl_type.is_union_type and idl_type.string_member_type)) yield 'true', method except StopIteration: pass @@ -1322,6 +1554,7 @@ def resolution_tests_methods(effective_overloads): # Utility functions ################################################################################ + def common(dicts, f): """Returns common result of f across an iterable of dicts, or None. @@ -1361,6 +1594,7 @@ def internal_namespace(interface): # Constructors ################################################################################ + # [Constructor] def constructor_context(interface, constructor): # [RaisesException=Constructor] @@ -1369,39 +1603,46 @@ def constructor_context(interface, constructor): argument_contexts = [ v8_methods.argument_context(interface, constructor, argument, index) - for index, argument in enumerate(constructor.arguments)] + for index, argument in enumerate(constructor.arguments) + ] return { - 'arguments': argument_contexts, - 'cpp_type': cpp_name(interface) + '*', - 'cpp_value': v8_methods.cpp_value( - interface, constructor, len(constructor.arguments)), + 'arguments': + argument_contexts, + 'cpp_type': + cpp_name(interface) + '*', + 'cpp_value': + v8_methods.cpp_value(interface, constructor, + len(constructor.arguments)), 'has_exception_state': - is_constructor_raises_exception or - any(argument for argument in constructor.arguments - if argument.idl_type.name == 'SerializedScriptValue' or - argument.idl_type.v8_conversion_needs_exception_state), + is_constructor_raises_exception + or any(argument for argument in constructor.arguments + if argument.idl_type.v8_conversion_needs_exception_state), 'has_optional_argument_without_default_value': - any(True for argument_context in argument_contexts - if argument_context['is_optional_without_default_value']), + any(True for argument_context in argument_contexts + if argument_context['is_optional_without_default_value']), 'is_call_with_document': - # [ConstructorCallWith=Document] - has_extended_attribute_value(interface, - 'ConstructorCallWith', 'Document'), + # [ConstructorCallWith=Document] + has_extended_attribute_value(interface, 'ConstructorCallWith', + 'Document'), 'is_call_with_execution_context': - # [ConstructorCallWith=ExecutionContext] - has_extended_attribute_value(interface, - 'ConstructorCallWith', 'ExecutionContext'), + # [ConstructorCallWith=ExecutionContext] + has_extended_attribute_value(interface, 'ConstructorCallWith', + 'ExecutionContext'), 'is_call_with_script_state': - # [ConstructorCallWith=ScriptState] - has_extended_attribute_value( - interface, 'ConstructorCallWith', 'ScriptState'), - 'is_constructor': True, - 'is_named_constructor': False, - 'is_raises_exception': is_constructor_raises_exception, + # [ConstructorCallWith=ScriptState] + has_extended_attribute_value(interface, 'ConstructorCallWith', + 'ScriptState'), + 'is_constructor': + True, + 'is_named_constructor': + False, + 'is_raises_exception': + is_constructor_raises_exception, 'number_of_required_arguments': - number_of_required_arguments(constructor), - 'rcs_counter': 'Blink_' + v8_utilities.cpp_name(interface) + '_ConstructorCallback' + number_of_required_arguments(constructor), + 'rcs_counter': + 'Blink_' + v8_utilities.cpp_name(interface) + '_ConstructorCallback' } @@ -1424,8 +1665,10 @@ def named_constructor_context(interface): def number_of_required_arguments(constructor): - return len([argument for argument in constructor.arguments - if not (argument.is_optional or argument.is_variadic)]) + return len([ + argument for argument in constructor.arguments + if not (argument.is_optional or argument.is_variadic) + ]) def interface_length(constructors): @@ -1441,6 +1684,7 @@ def interface_length(constructors): # http://heycam.github.io/webidl/#idl-special-operations ################################################################################ + def property_getter(getter, cpp_arguments): if not getter: return None @@ -1455,10 +1699,12 @@ def property_getter(getter, cpp_arguments): return '' extended_attributes = getter.extended_attributes - has_no_side_effect = v8_utilities.has_extended_attribute_value(getter, 'Affects', 'Nothing') + has_no_side_effect = v8_utilities.has_extended_attribute_value( + getter, 'Affects', 'Nothing') idl_type = getter.idl_type idl_type.add_includes_for_type(extended_attributes) - is_call_with_script_state = v8_utilities.has_extended_attribute_value(getter, 'CallWith', 'ScriptState') + is_call_with_script_state = v8_utilities.has_extended_attribute_value( + getter, 'CallWith', 'ScriptState') is_raises_exception = 'RaisesException' in extended_attributes use_output_parameter_for_result = idl_type.use_output_parameter_for_result @@ -1475,27 +1721,41 @@ def property_getter(getter, cpp_arguments): cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments)) return { - 'cpp_type': idl_type.cpp_type, - 'cpp_value': cpp_value, - 'has_no_side_effect': has_no_side_effect, - 'is_call_with_script_state': is_call_with_script_state, - 'is_cross_origin': 'CrossOrigin' in extended_attributes, + 'cpp_type': + idl_type.cpp_type, + 'cpp_value': + cpp_value, + 'has_no_side_effect': + has_no_side_effect, + 'is_call_with_script_state': + is_call_with_script_state, + 'is_cross_origin': + 'CrossOrigin' in extended_attributes, 'is_custom': - 'Custom' in extended_attributes and - (not extended_attributes['Custom'] or - has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')), - 'is_custom_property_enumerator': has_extended_attribute_value( - getter, 'Custom', 'PropertyEnumerator'), - 'is_custom_property_query': has_extended_attribute_value( - getter, 'Custom', 'PropertyQuery'), + 'Custom' in extended_attributes and + (not extended_attributes['Custom'] + or has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')), + 'is_custom_property_enumerator': + has_extended_attribute_value(getter, 'Custom', 'PropertyEnumerator'), + 'is_custom_property_query': + has_extended_attribute_value(getter, 'Custom', 'PropertyQuery'), # TODO(rakuco): [NotEnumerable] does not make sense here and is only # used in non-standard IDL operations. We need to get rid of them. - 'is_enumerable': 'NotEnumerable' not in extended_attributes, - 'is_null_expression': is_null_expression(idl_type), - 'is_raises_exception': is_raises_exception, - 'name': cpp_name(getter), - 'use_output_parameter_for_result': use_output_parameter_for_result, - 'v8_set_return_value': idl_type.v8_set_return_value('result', extended_attributes=extended_attributes, script_wrappable='impl'), + 'is_enumerable': + 'NotEnumerable' not in extended_attributes, + 'is_null_expression': + is_null_expression(idl_type), + 'is_raises_exception': + is_raises_exception, + 'name': + cpp_name(getter), + 'use_output_parameter_for_result': + use_output_parameter_for_result, + 'v8_set_return_value': + idl_type.v8_set_return_value( + 'result', + extended_attributes=extended_attributes, + script_wrappable='impl'), } @@ -1506,25 +1766,35 @@ def property_setter(setter, interface): extended_attributes = setter.extended_attributes idl_type = setter.arguments[1].idl_type idl_type.add_includes_for_type(extended_attributes) - is_call_with_script_state = v8_utilities.has_extended_attribute_value(setter, 'CallWith', 'ScriptState') + is_call_with_script_state = v8_utilities.has_extended_attribute_value( + setter, 'CallWith', 'ScriptState') is_raises_exception = 'RaisesException' in extended_attributes is_ce_reactions = 'CEReactions' in extended_attributes has_type_checking_interface = idl_type.is_wrapper_type return { - 'has_exception_state': (is_raises_exception or - idl_type.v8_conversion_needs_exception_state), - 'has_type_checking_interface': has_type_checking_interface, - 'idl_type': idl_type.base_type, - 'is_call_with_script_state': is_call_with_script_state, - 'is_ce_reactions': is_ce_reactions, - 'is_custom': 'Custom' in extended_attributes, - 'is_nullable': idl_type.is_nullable, - 'is_raises_exception': is_raises_exception, - 'name': cpp_name(setter), - 'v8_value_to_local_cpp_value': idl_type.v8_value_to_local_cpp_value( - extended_attributes, 'v8_value', 'property_value'), + 'has_exception_state': + (is_raises_exception or idl_type.v8_conversion_needs_exception_state), + 'has_type_checking_interface': + has_type_checking_interface, + 'idl_type': + idl_type.base_type, + 'is_call_with_script_state': + is_call_with_script_state, + 'is_ce_reactions': + is_ce_reactions, + 'is_custom': + 'Custom' in extended_attributes, + 'is_nullable': + idl_type.is_nullable, + 'is_raises_exception': + is_raises_exception, + 'name': + cpp_name(setter), + 'v8_value_to_local_cpp_value': + idl_type.v8_value_to_local_cpp_value(extended_attributes, 'v8_value', + 'property_value'), } @@ -1533,7 +1803,8 @@ def property_deleter(deleter): return None extended_attributes = deleter.extended_attributes - is_call_with_script_state = v8_utilities.has_extended_attribute_value(deleter, 'CallWith', 'ScriptState') + is_call_with_script_state = v8_utilities.has_extended_attribute_value( + deleter, 'CallWith', 'ScriptState') is_ce_reactions = 'CEReactions' in extended_attributes return { 'is_call_with_script_state': is_call_with_script_state, diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py index 07fcc8d0f8e..22f9a93432c 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_methods.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Generate template values for methods. Extends IdlArgument with property |default_cpp_value|. @@ -37,8 +36,8 @@ Design doc: http://www.chromium.org/developers/design-documents/idl-compiler import os import sys -sys.path.append(os.path.join(os.path.dirname(__file__), - '..', '..', 'build', 'scripts')) +sys.path.append( + os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'scripts')) from blinkbuild.name_style_converter import NameStyleConverter from idl_definitions import IdlArgument, IdlOperation from idl_types import IdlTypeBase, IdlUnionType, inherits_interface @@ -50,7 +49,9 @@ from v8_utilities import (has_extended_attribute_value, is_unforgeable) def method_is_visible(method, interface_is_partial): if 'overloads' in method: - return method['overloads']['visible'] and not (method['overloads']['has_partial_overloads'] and interface_is_partial) + return method['overloads']['visible'] and not ( + method['overloads']['has_partial_overloads'] + and interface_is_partial) return method['visible'] and 'overload_index' not in method @@ -59,19 +60,23 @@ def is_origin_trial_enabled(method): def is_secure_context(method): - return bool(method['overloads']['secure_context_test_all'] if 'overloads' in method else method['secure_context_test']) + return bool(method['overloads']['secure_context_test_all'] if 'overloads' + in method else method['secure_context_test']) def is_conditionally_enabled(method): - exposed = method['overloads']['exposed_test_all'] if 'overloads' in method else method['exposed_test'] + exposed = method['overloads']['exposed_test_all'] \ + if 'overloads' in method else method['exposed_test'] return exposed or is_secure_context(method) def filter_conditionally_enabled(methods, interface_is_partial): - return [method for method in methods if ( - method_is_visible(method, interface_is_partial) and - is_conditionally_enabled(method) and - not is_origin_trial_enabled(method))] + return [ + method for method in methods + if (method_is_visible(method, interface_is_partial) + and is_conditionally_enabled(method) + and not is_origin_trial_enabled(method)) + ] def custom_registration(method): @@ -81,48 +86,65 @@ def custom_registration(method): if method['is_cross_origin']: return True if 'overloads' in method: - return (method['overloads']['runtime_determined_lengths'] or - (method['overloads']['runtime_enabled_all'] and not is_conditionally_enabled(method))) - return method['runtime_enabled_feature_name'] and not is_conditionally_enabled(method) + return (method['overloads']['runtime_determined_lengths'] + or (method['overloads']['runtime_enabled_all'] + and not is_conditionally_enabled(method))) + return method[ + 'runtime_enabled_feature_name'] and not is_conditionally_enabled( + method) def filter_custom_registration(methods, interface_is_partial): - return [method for method in methods if ( - method_is_visible(method, interface_is_partial) and custom_registration(method))] + return [ + method for method in methods + if (method_is_visible(method, interface_is_partial) + and custom_registration(method)) + ] def filter_method_configuration(methods, interface_is_partial): - return [method for method in methods if - method_is_visible(method, interface_is_partial) and - not is_origin_trial_enabled(method) and - not is_conditionally_enabled(method) and - not custom_registration(method)] + return [ + method for method in methods + if method_is_visible(method, interface_is_partial) + and not is_origin_trial_enabled(method) + and not is_conditionally_enabled(method) + and not custom_registration(method) + ] def method_filters(): - return {'custom_registration': filter_custom_registration, - 'has_method_configuration': filter_method_configuration} + return { + 'custom_registration': filter_custom_registration, + 'has_method_configuration': filter_method_configuration + } def use_local_result(method): extended_attributes = method.extended_attributes idl_type = method.idl_type - return (has_extended_attribute_value(method, 'CallWith', 'ScriptState') or - 'NewObject' in extended_attributes or - 'RaisesException' in extended_attributes or - idl_type.is_union_type or - idl_type.is_dictionary or - idl_type.is_explicit_nullable) + return (has_extended_attribute_value(method, 'CallWith', 'ScriptState') + or 'NewObject' in extended_attributes + or 'RaisesException' in extended_attributes + or idl_type.is_union_type or idl_type.is_dictionary + or idl_type.is_explicit_nullable) def runtime_call_stats_context(interface, method): includes.add('platform/bindings/runtime_call_stats.h') - generic_counter_name = 'Blink_' + v8_utilities.cpp_name(interface) + '_' + method.name - (method_counter, extended_attribute_defined) = v8_utilities.rcs_counter_name(method, generic_counter_name) + generic_counter_name = ( + 'Blink_' + v8_utilities.cpp_name(interface) + '_' + method.name) + (method_counter, extended_attribute_defined) = \ + v8_utilities.rcs_counter_name(method, generic_counter_name) + trace_event_name = interface.name + '.' + method.name return { - 'extended_attribute_defined': extended_attribute_defined, - 'method_counter': method_counter, - 'origin_safe_method_getter_counter': generic_counter_name + '_OriginSafeMethodGetter' + 'extended_attribute_defined': + extended_attribute_defined, + 'method_counter': + method_counter, + 'origin_safe_method_getter_counter': + generic_counter_name + '_OriginSafeMethodGetter', + 'trace_event_name': + trace_event_name, } @@ -138,18 +160,19 @@ def method_context(interface, method, component_info, is_visible=True): this_cpp_value = cpp_value(interface, method, len(arguments)) - is_call_with_script_state = has_extended_attribute_value(method, 'CallWith', 'ScriptState') - is_call_with_this_value = has_extended_attribute_value(method, 'CallWith', 'ThisValue') + is_call_with_script_state = has_extended_attribute_value( + method, 'CallWith', 'ScriptState') + is_call_with_this_value = has_extended_attribute_value( + method, 'CallWith', 'ThisValue') if is_call_with_script_state or is_call_with_this_value: includes.add('platform/bindings/script_state.h') # [CheckSecurity] is_cross_origin = 'CrossOrigin' in extended_attributes - is_check_security_for_receiver = ( - has_extended_attribute_value(interface, 'CheckSecurity', 'Receiver') and - not is_cross_origin) - is_check_security_for_return_value = ( - has_extended_attribute_value(method, 'CheckSecurity', 'ReturnValue')) + is_check_security_for_receiver = (has_extended_attribute_value( + interface, 'CheckSecurity', 'Receiver') and not is_cross_origin) + is_check_security_for_return_value = (has_extended_attribute_value( + method, 'CheckSecurity', 'ReturnValue')) if is_check_security_for_receiver or is_check_security_for_return_value: includes.add('bindings/core/v8/binding_security.h') if is_check_security_for_return_value: @@ -164,8 +187,6 @@ def method_context(interface, method, component_info, is_visible=True): includes.add('core/html/custom/v0_custom_element_processing_stack.h') is_raises_exception = 'RaisesException' in extended_attributes - is_custom_call_prologue = has_extended_attribute_value(method, 'Custom', 'CallPrologue') - is_custom_call_epilogue = has_extended_attribute_value(method, 'Custom', 'CallEpilogue') if 'LenientThis' in extended_attributes: raise Exception('[LenientThis] is not supported for operations.') @@ -180,89 +201,142 @@ def method_context(interface, method, component_info, is_visible=True): includes.add('platform/bindings/v8_per_context_data.h') argument_contexts = [ - argument_context(interface, method, argument, index, is_visible=is_visible) - for index, argument in enumerate(arguments)] + argument_context( + interface, method, argument, index, is_visible=is_visible) + for index, argument in enumerate(arguments) + ] runtime_features = component_info['runtime_enabled_features'] return { - 'activity_logging_world_list': v8_utilities.activity_logging_world_list(method), # [ActivityLogging] - 'arguments': argument_contexts, - 'camel_case_name': NameStyleConverter(name).to_upper_camel_case(), - 'cpp_type': (v8_types.cpp_template_type('base::Optional', idl_type.cpp_type) - if idl_type.is_explicit_nullable - else v8_types.cpp_type(idl_type, extended_attributes=extended_attributes)), - 'cpp_value': this_cpp_value, - 'cpp_type_initializer': idl_type.cpp_type_initializer, - 'high_entropy': v8_utilities.high_entropy(method), # [HighEntropy] - 'deprecate_as': v8_utilities.deprecate_as(method), # [DeprecateAs] - 'do_not_test_new_object': 'DoNotTestNewObject' in extended_attributes, - 'exposed_test': v8_utilities.exposed(method, interface), # [Exposed] + 'activity_logging_world_list': + v8_utilities.activity_logging_world_list(method), # [ActivityLogging] + 'arguments': + argument_contexts, + 'camel_case_name': + NameStyleConverter(name).to_upper_camel_case(), + 'cpp_type': + (v8_types.cpp_template_type('base::Optional', idl_type.cpp_type) + if idl_type.is_explicit_nullable else v8_types.cpp_type( + idl_type, extended_attributes=extended_attributes)), + 'cpp_value': + this_cpp_value, + 'cpp_type_initializer': + idl_type.cpp_type_initializer, + 'high_entropy': + v8_utilities.high_entropy(method), # [HighEntropy] + 'deprecate_as': + v8_utilities.deprecate_as(method), # [DeprecateAs] + 'do_not_test_new_object': + 'DoNotTestNewObject' in extended_attributes, + 'exposed_test': + v8_utilities.exposed(method, interface), # [Exposed] 'has_exception_state': - is_raises_exception or - is_check_security_for_receiver or - any(argument for argument in arguments - if (argument.idl_type.name == 'SerializedScriptValue' or - argument_conversion_needs_exception_state(method, argument))), + is_raises_exception or is_check_security_for_receiver or any( + argument for argument in arguments + if argument_conversion_needs_exception_state(method, argument)), 'has_optional_argument_without_default_value': - any(True for argument_context in argument_contexts - if argument_context['is_optional_without_default_value']), - 'idl_type': idl_type.base_type, - 'is_call_with_execution_context': has_extended_attribute_value(method, 'CallWith', 'ExecutionContext'), - 'is_call_with_script_state': is_call_with_script_state, - 'is_call_with_this_value': is_call_with_this_value, - 'is_ce_reactions': is_ce_reactions, - 'is_check_security_for_receiver': is_check_security_for_receiver, - 'is_check_security_for_return_value': is_check_security_for_return_value, - 'is_cross_origin': 'CrossOrigin' in extended_attributes, - 'is_custom': 'Custom' in extended_attributes and - not (is_custom_call_prologue or is_custom_call_epilogue), - 'is_custom_call_prologue': is_custom_call_prologue, - 'is_custom_call_epilogue': is_custom_call_epilogue, - 'is_custom_element_callbacks': is_custom_element_callbacks, - 'is_explicit_nullable': idl_type.is_explicit_nullable, - 'is_new_object': 'NewObject' in extended_attributes, + any(True for argument_context in argument_contexts + if argument_context['is_optional_without_default_value']), + 'idl_type': + idl_type.base_type, + 'is_call_with_execution_context': + has_extended_attribute_value(method, 'CallWith', 'ExecutionContext'), + 'is_call_with_script_state': + is_call_with_script_state, + 'is_call_with_this_value': + is_call_with_this_value, + 'is_ce_reactions': + is_ce_reactions, + 'is_check_security_for_receiver': + is_check_security_for_receiver, + 'is_check_security_for_return_value': + is_check_security_for_return_value, + 'is_cross_origin': + 'CrossOrigin' in extended_attributes, + 'is_custom': + 'Custom' in extended_attributes, + 'is_custom_element_callbacks': + is_custom_element_callbacks, + 'is_explicit_nullable': + idl_type.is_explicit_nullable, + 'is_new_object': + 'NewObject' in extended_attributes, 'is_partial_interface_member': - 'PartialInterfaceImplementedAs' in extended_attributes, - 'is_per_world_bindings': 'PerWorldBindings' in extended_attributes, - 'is_raises_exception': is_raises_exception, - 'is_static': is_static, - 'is_unforgeable': is_unforgeable(method), - 'is_variadic': arguments and arguments[-1].is_variadic, - 'measure_as': v8_utilities.measure_as(method, interface), # [MeasureAs] - 'name': name, - 'number_of_arguments': len(arguments), - 'number_of_required_arguments': len([ + 'PartialInterfaceImplementedAs' in extended_attributes, + 'is_per_world_bindings': + 'PerWorldBindings' in extended_attributes, + 'is_raises_exception': + is_raises_exception, + 'is_static': + is_static, + 'is_unforgeable': + is_unforgeable(method), + 'is_variadic': + arguments and arguments[-1].is_variadic, + 'measure_as': + v8_utilities.measure_as(method, interface), # [MeasureAs] + 'name': + name, + 'number_of_arguments': + len(arguments), + 'number_of_required_arguments': + len([ argument for argument in arguments - if not (argument.is_optional or argument.is_variadic)]), - 'number_of_required_or_variadic_arguments': len([ - argument for argument in arguments - if not argument.is_optional]), - 'on_instance': v8_utilities.on_instance(interface, method), - 'on_interface': v8_utilities.on_interface(interface, method), - 'on_prototype': v8_utilities.on_prototype(interface, method), + if not (argument.is_optional or argument.is_variadic) + ]), + 'number_of_required_or_variadic_arguments': + len([argument for argument in arguments if not argument.is_optional]), + 'on_instance': + v8_utilities.on_instance(interface, method), + 'on_interface': + v8_utilities.on_interface(interface, method), + 'on_prototype': + v8_utilities.on_prototype(interface, method), + # [RuntimeEnabled] for origin trial 'origin_trial_feature_name': - v8_utilities.origin_trial_feature_name(method, runtime_features), # [RuntimeEnabled] for origin trial - 'property_attributes': property_attributes(interface, method), - 'returns_promise': method.returns_promise, - 'runtime_call_stats': runtime_call_stats_context(interface, method), + v8_utilities.origin_trial_feature_name(method, runtime_features), + 'property_attributes': + property_attributes(interface, method), + 'returns_promise': + method.returns_promise, + 'runtime_call_stats': + runtime_call_stats_context(interface, method), + # [RuntimeEnabled] if not in origin trial 'runtime_enabled_feature_name': - v8_utilities.runtime_enabled_feature_name(method, runtime_features), # [RuntimeEnabled] if not in origin trial - 'secure_context_test': v8_utilities.secure_context(method, interface), # [SecureContext] - 'side_effect_type': side_effect_type, # [Affects] - 'snake_case_name': NameStyleConverter(name).to_snake_case(), - 'use_output_parameter_for_result': idl_type.use_output_parameter_for_result, - 'use_local_result': use_local_result(method), - 'v8_set_return_value': v8_set_return_value(interface.name, method, this_cpp_value), - 'v8_set_return_value_for_main_world': v8_set_return_value(interface.name, method, this_cpp_value, for_main_world=True), - 'visible': is_visible, - 'world_suffixes': ['', 'ForMainWorld'] if 'PerWorldBindings' in extended_attributes else [''], # [PerWorldBindings], + v8_utilities.runtime_enabled_feature_name(method, runtime_features), + # [SecureContext] + 'secure_context_test': + v8_utilities.secure_context(method, interface), + # [Affects] + 'side_effect_type': + side_effect_type, + 'snake_case_name': + NameStyleConverter(name).to_snake_case(), + 'use_output_parameter_for_result': + idl_type.use_output_parameter_for_result, + 'use_local_result': + use_local_result(method), + 'v8_set_return_value': + v8_set_return_value(interface.name, method, this_cpp_value), + 'v8_set_return_value_for_main_world': + v8_set_return_value( + interface.name, method, this_cpp_value, for_main_world=True), + 'visible': + is_visible, + 'world_suffixes': + ['', 'ForMainWorld'] if 'PerWorldBindings' in extended_attributes else + [''], # [PerWorldBindings], } def argument_context(interface, method, argument, index, is_visible=True): extended_attributes = argument.extended_attributes idl_type = argument.idl_type + if idl_type.has_string_context: + includes.add( + 'third_party/blink/renderer/bindings/core/v8/generated_code_helper.h' + ) if is_visible: idl_type.add_includes_for_type(extended_attributes) this_cpp_value = cpp_value(interface, method, index) @@ -271,52 +345,77 @@ def argument_context(interface, method, argument, index, is_visible=True): has_type_checking_interface = idl_type.is_wrapper_type set_default_value = argument.set_default_value - this_cpp_type = idl_type.cpp_type_args(extended_attributes=extended_attributes, - raw_type=True, - used_as_variadic_argument=argument.is_variadic) + this_cpp_type = idl_type.cpp_type_args( + extended_attributes=extended_attributes, + raw_type=True, + used_as_variadic_argument=argument.is_variadic) snake_case_name = NameStyleConverter(argument.name).to_snake_case() context = { - 'cpp_type': ( - v8_types.cpp_template_type('base::Optional', this_cpp_type) - if idl_type.is_explicit_nullable and not argument.is_variadic - else this_cpp_type), - 'cpp_value': this_cpp_value, + 'cpp_type': (v8_types.cpp_template_type( + 'base::Optional', this_cpp_type) if idl_type.is_explicit_nullable + and not argument.is_variadic else this_cpp_type), + 'cpp_value': + this_cpp_value, # FIXME: check that the default value's type is compatible with the argument's - 'enum_type': idl_type.enum_type, - 'enum_values': idl_type.enum_values, - 'handle': '%s_handle' % snake_case_name, + 'enum_type': + idl_type.enum_type, + 'enum_values': + idl_type.enum_values, + 'handle': + '%s_handle' % snake_case_name, # TODO(peria): remove once [DefaultValue] removed and just use # argument.default_value. https://crbug.com/924419 - 'has_default': 'DefaultValue' in extended_attributes or set_default_value, - 'has_type_checking_interface': has_type_checking_interface, + 'has_default': + 'DefaultValue' in extended_attributes or set_default_value, + 'has_type_checking_interface': + has_type_checking_interface, # Dictionary is special-cased, but arrays and sequences shouldn't be - 'idl_type': idl_type.base_type, - 'idl_type_object': idl_type, - 'index': index, - 'is_callback_function': idl_type.is_callback_function, - 'is_callback_interface': idl_type.is_callback_interface, + 'idl_type': + idl_type.base_type, + 'idl_type_object': + idl_type, + 'index': + index, + 'is_callback_function': + idl_type.is_callback_function, + 'is_callback_interface': + idl_type.is_callback_interface, # FIXME: Remove generic 'Dictionary' special-casing - 'is_dictionary': idl_type.is_dictionary or idl_type.base_type == 'Dictionary', - 'is_explicit_nullable': idl_type.is_explicit_nullable, - 'is_nullable': idl_type.is_nullable, - 'is_optional': argument.is_optional, - 'is_variadic': argument.is_variadic, - 'is_variadic_wrapper_type': is_variadic_wrapper_type, - 'is_wrapper_type': idl_type.is_wrapper_type, - 'local_cpp_variable': snake_case_name, - 'name': argument.name, - 'set_default_value': set_default_value, - 'use_permissive_dictionary_conversion': 'PermissiveDictionaryConversion' in extended_attributes, - 'v8_set_return_value': v8_set_return_value(interface.name, method, this_cpp_value), - 'v8_set_return_value_for_main_world': v8_set_return_value(interface.name, method, this_cpp_value, for_main_world=True), - 'v8_value_to_local_cpp_value': v8_value_to_local_cpp_value(interface.name, method, argument, index), + 'is_dictionary': + idl_type.is_dictionary, + 'is_explicit_nullable': + idl_type.is_explicit_nullable, + 'is_nullable': + idl_type.is_nullable, + 'is_optional': + argument.is_optional, + 'is_variadic': + argument.is_variadic, + 'is_variadic_wrapper_type': + is_variadic_wrapper_type, + 'is_wrapper_type': + idl_type.is_wrapper_type, + 'local_cpp_variable': + snake_case_name, + 'name': + argument.name, + 'set_default_value': + set_default_value, + 'use_permissive_dictionary_conversion': + 'PermissiveDictionaryConversion' in extended_attributes, + 'v8_set_return_value': + v8_set_return_value(interface.name, method, this_cpp_value), + 'v8_set_return_value_for_main_world': + v8_set_return_value( + interface.name, method, this_cpp_value, for_main_world=True), + 'v8_value_to_local_cpp_value': + v8_value_to_local_cpp_value(interface.name, method, argument, index), } context.update({ 'is_optional_without_default_value': - context['is_optional'] and - not context['has_default'] and - not context['is_dictionary'] and - not context['is_callback_interface'], + context['is_optional'] and not context['has_default'] + and not context['is_dictionary'] + and not context['is_callback_interface'], }) return context @@ -325,13 +424,15 @@ def argument_context(interface, method, argument, index, is_visible=True): # Value handling ################################################################################ + def cpp_value(interface, method, number_of_arguments): # Truncate omitted optional arguments arguments = method.arguments[:number_of_arguments] cpp_arguments = [] if method.is_constructor: - call_with_values = interface.extended_attributes.get('ConstructorCallWith') + call_with_values = interface.extended_attributes.get( + 'ConstructorCallWith') else: call_with_values = method.extended_attributes.get('CallWith') cpp_arguments.extend(v8_utilities.call_with_arguments(call_with_values)) @@ -339,20 +440,12 @@ def cpp_value(interface, method, number_of_arguments): # Members of IDL partial interface definitions are implemented in C++ as # static member functions, which for instance members (non-static members) # take *impl as their first argument - if ('PartialInterfaceImplementedAs' in method.extended_attributes and - not method.is_static): + if ('PartialInterfaceImplementedAs' in method.extended_attributes + and not method.is_static): cpp_arguments.append('*impl') for argument in arguments: variable_name = NameStyleConverter(argument.name).to_snake_case() - if argument.idl_type.base_type == 'SerializedScriptValue': - cpp_arguments.append('std::move(%s)' % variable_name) - else: - cpp_arguments.append(variable_name) - - if ('RaisesException' in method.extended_attributes or - (method.is_constructor and - has_extended_attribute_value(interface, 'RaisesException', 'Constructor'))): - cpp_arguments.append('exception_state') + cpp_arguments.append(variable_name) # If a method returns an IDL dictionary or union type, the return value is # passed as an argument to impl classes. @@ -360,6 +453,11 @@ def cpp_value(interface, method, number_of_arguments): if idl_type and idl_type.use_output_parameter_for_result: cpp_arguments.append('result') + if ('RaisesException' in method.extended_attributes + or (method.is_constructor and has_extended_attribute_value( + interface, 'RaisesException', 'Constructor'))): + cpp_arguments.append('exception_state') + if method.name == 'Constructor': base_name = 'Create' elif method.name == 'NamedConstructor': @@ -371,7 +469,10 @@ def cpp_value(interface, method, number_of_arguments): return '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments)) -def v8_set_return_value(interface_name, method, cpp_value, for_main_world=False): +def v8_set_return_value(interface_name, + method, + cpp_value, + for_main_world=False): idl_type = method.idl_type extended_attributes = method.extended_attributes if not idl_type or idl_type.name == 'void': @@ -386,75 +487,61 @@ def v8_set_return_value(interface_name, method, cpp_value, for_main_world=False) else: cpp_value = 'result' - script_wrappable = 'impl' if inherits_interface(interface_name, 'Node') else '' - return idl_type.v8_set_return_value(cpp_value, extended_attributes, script_wrappable=script_wrappable, for_main_world=for_main_world, is_static=method.is_static) + script_wrappable = 'impl' if inherits_interface(interface_name, + 'Node') else '' + return idl_type.v8_set_return_value( + cpp_value, + extended_attributes, + script_wrappable=script_wrappable, + for_main_world=for_main_world, + is_static=method.is_static) -def v8_value_to_local_cpp_variadic_value(argument, index): +def v8_value_to_local_cpp_variadic_value(argument, + index, + for_constructor_callback=False): assert argument.is_variadic - idl_type = v8_types.native_value_traits_type_name(argument.idl_type, - argument.extended_attributes, True) - + idl_type = v8_types.native_value_traits_type_name( + argument.idl_type, argument.extended_attributes, True) + execution_context_if_needed = '' + if argument.idl_type.has_string_context: + execution_context_if_needed = ', bindings::ExecutionContextFromV8Wrappable(impl)' + if for_constructor_callback: + execution_context_if_needed = ', CurrentExecutionContext(info.GetIsolate())' + assign_expression = 'ToImplArguments<%s>(info, %s, exception_state%s)' % ( + idl_type, index, execution_context_if_needed) return { - 'assign_expression': 'ToImplArguments<%s>(info, %s, exception_state)' % (idl_type, index), + 'assign_expression': assign_expression, 'check_expression': 'exception_state.HadException()', 'cpp_name': NameStyleConverter(argument.name).to_snake_case(), 'declare_variable': False, } -def v8_value_to_local_cpp_ssv_value(extended_attributes, idl_type, v8_value, variable_name, for_storage): - this_cpp_type = idl_type.cpp_type_args(extended_attributes=extended_attributes, raw_type=True) - - storage_policy = 'kForStorage' if for_storage else 'kNotForStorage' - arguments = ', '.join([ - 'info.GetIsolate()', - v8_value, - '{ssv}::SerializeOptions({ssv}::{storage_policy})', - 'exception_state' - ]) - cpp_expression_format = 'NativeValueTraits<{ssv}>::NativeValue(%s)' % arguments - this_cpp_value = cpp_expression_format.format( - ssv='SerializedScriptValue', - storage_policy=storage_policy - ) - - return { - 'assign_expression': this_cpp_value, - 'check_expression': 'exception_state.HadException()', - 'cpp_type': this_cpp_type, - 'cpp_name': variable_name, - 'declare_variable': False, - } - - def v8_value_to_local_cpp_value(interface_name, method, argument, index): extended_attributes = argument.extended_attributes idl_type = argument.idl_type name = NameStyleConverter(argument.name).to_snake_case() v8_value = 'info[{index}]'.format(index=index) - - # History.pushState and History.replaceState are explicitly specified as - # serializing the value for storage. The default is to not serialize for - # storage. See https://html.spec.whatwg.org/C/#dom-history-pushstate - if idl_type.name == 'SerializedScriptValue': - for_storage = (interface_name == 'History' and - method.name in ('pushState', 'replaceState')) - return v8_value_to_local_cpp_ssv_value(extended_attributes, idl_type, - v8_value, name, - for_storage=for_storage) + for_constructor_callback = method.name == 'Constructor' if argument.is_variadic: - return v8_value_to_local_cpp_variadic_value(argument, index) - return idl_type.v8_value_to_local_cpp_value(extended_attributes, v8_value, - name, declare_variable=False, - use_exception_state=method.returns_promise) + return v8_value_to_local_cpp_variadic_value( + argument, index, for_constructor_callback=for_constructor_callback) + return idl_type.v8_value_to_local_cpp_value( + extended_attributes, + v8_value, + name, + declare_variable=False, + use_exception_state=method.returns_promise, + for_constructor_callback=for_constructor_callback) ################################################################################ # Auxiliary functions ################################################################################ + # [NotEnumerable], [Unforgeable] def property_attributes(interface, method): extended_attributes = method.extended_attributes @@ -481,7 +568,8 @@ def argument_set_default_value(argument): raise Exception('invalid default value for dictionary type') if idl_type.is_array_or_sequence_type: if default_value.value != '[]': - raise Exception('invalid default value for sequence type: %s' % default_value.value) + raise Exception('invalid default value for sequence type: %s' % + default_value.value) # Nothing to do when we set an empty sequence as default value, but we # need to return non-empty value so that we don't generate method calls # without this argument. @@ -489,11 +577,14 @@ def argument_set_default_value(argument): if idl_type.is_union_type: if argument.default_value.is_null: if not idl_type.includes_nullable_type: - raise Exception('invalid default value for union type: null for %s' - % idl_type.name) + raise Exception( + 'invalid default value for union type: null for %s' % + idl_type.name) # Union container objects are "null" initially. return '/* null default value */' - if isinstance(default_value.value, basestring): + if default_value.value == "{}": + member_type = idl_type.dictionary_member_type + elif isinstance(default_value.value, basestring): member_type = idl_type.string_member_type elif isinstance(default_value.value, (int, float)): member_type = idl_type.numeric_member_type @@ -502,27 +593,28 @@ def argument_set_default_value(argument): else: member_type = None if member_type is None: - raise Exception('invalid default value for union type: %r for %s' - % (default_value.value, idl_type.name)) + raise Exception('invalid default value for union type: %r for %s' % + (default_value.value, idl_type.name)) member_type_name = (member_type.inner_type.name - if member_type.is_nullable else - member_type.name) + if member_type.is_nullable else member_type.name) return '%s.Set%s(%s)' % (variable_name, member_type_name, member_type.literal_cpp_value(default_value)) return '%s = %s' % (variable_name, idl_type.literal_cpp_value(default_value)) + IdlArgument.set_default_value = property(argument_set_default_value) def method_returns_promise(method): return method.idl_type and method.idl_type.name == 'Promise' + IdlOperation.returns_promise = property(method_returns_promise) def argument_conversion_needs_exception_state(method, argument): idl_type = argument.idl_type - return (idl_type.v8_conversion_needs_exception_state or - argument.is_variadic or - (method.returns_promise and idl_type.is_string_type)) + return (idl_type.v8_conversion_needs_exception_state + or argument.is_variadic + or (method.returns_promise and idl_type.is_string_type)) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py index 5b7aae6f0fd..a2007d860b9 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_types.py @@ -27,7 +27,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # pylint: disable=relative-import - """Functions for type handling and type conversion (Blink/C++ <-> V8/JS). Extends IdlType and IdlUnionType with V8-specific properties, methods, and @@ -41,6 +40,7 @@ Design doc: http://www.chromium.org/developers/design-documents/idl-compiler import posixpath +from idl_types import IdlAnnotatedType from idl_types import IdlArrayOrSequenceType from idl_types import IdlNullableType from idl_types import IdlRecordType @@ -52,16 +52,13 @@ import v8_attributes # for IdlType.constructor_type_name from v8_globals import includes from v8_utilities import binding_header_filename, extended_attribute_value_contains - ################################################################################ # V8-specific handling of IDL types ################################################################################ NON_WRAPPER_TYPES = frozenset([ - 'Dictionary', 'EventHandler', 'NodeFilter', - 'SerializedScriptValue', ]) TYPED_ARRAY_TYPES = frozenset([ 'Float32Array', @@ -76,15 +73,15 @@ TYPED_ARRAY_TYPES = frozenset([ 'BigInt64Array', 'BigUint64Array', ]) -ARRAY_BUFFER_VIEW_AND_TYPED_ARRAY_TYPES = TYPED_ARRAY_TYPES.union(frozenset([ - 'ArrayBufferView' -])) -ARRAY_BUFFER_AND_VIEW_TYPES = TYPED_ARRAY_TYPES.union(frozenset([ - 'ArrayBuffer', - 'ArrayBufferView', - 'DataView', - 'SharedArrayBuffer', -])) +ARRAY_BUFFER_VIEW_AND_TYPED_ARRAY_TYPES = TYPED_ARRAY_TYPES.union( + frozenset(['ArrayBufferView'])) +ARRAY_BUFFER_AND_VIEW_TYPES = TYPED_ARRAY_TYPES.union( + frozenset([ + 'ArrayBuffer', + 'ArrayBufferView', + 'DataView', + 'SharedArrayBuffer', + ])) # We have an unfortunate hack that treats types whose name ends with # 'Constructor' as aliases to IDL interface object. This white list is used to # disable the hack. @@ -105,10 +102,8 @@ IdlType.is_typed_array = property( lambda self: self.base_type in TYPED_ARRAY_TYPES) IdlType.is_wrapper_type = property( - lambda self: (self.is_interface_type and - not self.is_callback_interface and - self.base_type not in NON_WRAPPER_TYPES)) - + lambda self: (self.is_interface_type and not self.is_callback_interface and self.base_type not in NON_WRAPPER_TYPES) +) ################################################################################ # C++ types @@ -129,13 +124,13 @@ CPP_INTEGER_CONVERSION_RULES = { 'unsigned long long': 'uint64_t', } CPP_SPECIAL_CONVERSION_RULES = { - 'Dictionary': 'Dictionary', 'EventHandler': 'EventListener*', 'Promise': 'ScriptPromise', 'ScriptValue': 'ScriptValue', # FIXME: Eliminate custom bindings for XPathNSResolver http://crbug.com/345529 'XPathNSResolver': 'XPathNSResolver*', 'boolean': 'bool', + 'object': 'ScriptValue', 'unrestricted double': 'double', 'unrestricted float': 'float', } @@ -154,11 +149,18 @@ def string_resource_mode(idl_type): treat_null_as = idl_type.extended_attributes.get('TreatNullAs') if treat_null_as == 'EmptyString': return 'kTreatNullAsEmptyString' - raise ValueError('Unknown value for [TreatNullAs]: %s' % treat_null_as) + elif treat_null_as: + raise ValueError( + 'Unknown value for [TreatNullAs]: %s' % treat_null_as) return '' -def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_type=False, used_as_variadic_argument=False, used_in_cpp_sequence=False): +def cpp_type(idl_type, + extended_attributes=None, + raw_type=False, + used_as_rvalue_type=False, + used_as_variadic_argument=False, + used_in_cpp_sequence=False): """Returns C++ type corresponding to IDL type. |idl_type| argument is of type IdlType, while return value is a string @@ -198,9 +200,12 @@ def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_ # integrated null state that can be distinguished from a present but # empty dictionary. It's unclear whether this will ever come up in # real spec WebIDL. - raise NotImplementedError('Sequences of nullable dictionary, sequence or record types are not yet supported.') + raise NotImplementedError( + 'Sequences of nullable dictionary, sequence or record types are not yet supported.' + ) return 'base::Optional<%s>' % inner_type.cpp_type_args( - extended_attributes, raw_type, used_as_rvalue_type, used_as_variadic_argument, used_in_cpp_sequence) + extended_attributes, raw_type, used_as_rvalue_type, + used_as_variadic_argument, used_in_cpp_sequence) # Array or sequence types if used_as_variadic_argument: @@ -208,18 +213,23 @@ def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_ else: native_array_element_type = idl_type.native_array_element_type if native_array_element_type: - vector_type = cpp_ptr_type('Vector', 'HeapVector', native_array_element_type.is_traceable) - vector_template_type = cpp_template_type(vector_type, native_array_element_type.cpp_type_args(used_in_cpp_sequence=True)) + vector_type = cpp_ptr_type('Vector', 'HeapVector', + native_array_element_type.is_traceable) + vector_template_type = cpp_template_type( + vector_type, + native_array_element_type.cpp_type_args(used_in_cpp_sequence=True)) if used_as_rvalue_type: return 'const %s&' % vector_template_type return vector_template_type # Record types. if idl_type.is_record_type: - vector_type = cpp_ptr_type('Vector', 'HeapVector', idl_type.value_type.is_traceable) - value_type = idl_type.value_type.cpp_type_args(used_in_cpp_sequence=True) - vector_template_type = cpp_template_type(vector_type, - 'std::pair<String, %s>' % value_type) + vector_type = cpp_ptr_type('Vector', 'HeapVector', + idl_type.value_type.is_traceable) + value_type = idl_type.value_type.cpp_type_args( + used_in_cpp_sequence=True) + vector_template_type = cpp_template_type( + vector_type, 'std::pair<String, %s>' % value_type) if used_as_rvalue_type: return 'const %s&' % vector_template_type return vector_template_type @@ -234,9 +244,9 @@ def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_ if base_idl_type in CPP_SPECIAL_CONVERSION_RULES: return CPP_SPECIAL_CONVERSION_RULES[base_idl_type] - if base_idl_type == 'SerializedScriptValue': - return 'scoped_refptr<%s>' % base_idl_type if idl_type.is_string_type: + if idl_type.has_string_context: + return 'String' if not raw_type: return 'const String&' if used_as_rvalue_type else 'String' return 'V8StringResource<%s>' % string_resource_mode(idl_type) @@ -244,13 +254,12 @@ def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_ if base_idl_type == 'ArrayBufferView' and 'FlexibleArrayBufferView' in extended_attributes: return 'FlexibleArrayBufferView' if base_idl_type in TYPED_ARRAY_TYPES and 'FlexibleArrayBufferView' in extended_attributes: - return 'Flexible' + base_idl_type + 'View' - if base_idl_type in ARRAY_BUFFER_VIEW_AND_TYPED_ARRAY_TYPES: - if not used_in_cpp_sequence: - if 'AllowShared' in extended_attributes: - return cpp_template_type('MaybeShared', idl_type.implemented_as) - else: - return cpp_template_type('NotShared', idl_type.implemented_as) + return 'Flexible' + base_idl_type + if base_idl_type in ARRAY_BUFFER_VIEW_AND_TYPED_ARRAY_TYPES or base_idl_type == 'DataView': + if 'AllowShared' in extended_attributes: + return cpp_template_type('MaybeShared', idl_type.implemented_as) + else: + return cpp_template_type('NotShared', idl_type.implemented_as) if idl_type.is_interface_type or idl_type.is_dictionary: implemented_as_class = idl_type.implemented_as if raw_type or not used_in_cpp_sequence: @@ -267,8 +276,9 @@ def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_ if idl_type.is_nullable: return idl_type.inner_type.name return idl_type.name - idl_type_name = 'Or'.join(member_cpp_name(member) - for member in idl_type.member_types) + + idl_type_name = 'Or'.join( + member_cpp_name(member) for member in idl_type.member_types) return 'const %s&' % idl_type_name if used_as_rvalue_type else idl_type_name if idl_type.is_callback_function: v8_type_name = 'V8' + base_idl_type @@ -295,15 +305,16 @@ def cpp_type_initializer(idl_type): if idl_type.native_array_element_type: return '' + if idl_type.is_explicit_nullable: + return '' if idl_type.is_numeric_type: return ' = 0' if base_idl_type == 'boolean': return ' = false' - if (base_idl_type in NON_WRAPPER_TYPES or - base_idl_type in CPP_SPECIAL_CONVERSION_RULES or - base_idl_type == 'any' or - idl_type.is_string_type or - idl_type.is_enum): + if (base_idl_type in NON_WRAPPER_TYPES + or base_idl_type in CPP_SPECIAL_CONVERSION_RULES + or base_idl_type == 'any' or idl_type.is_string_type + or idl_type.is_enum): return '' return ' = nullptr' @@ -314,7 +325,6 @@ IdlTypeBase.cpp_type_initializer = property(cpp_type_initializer) IdlTypeBase.cpp_type_args = cpp_type IdlUnionType.cpp_type_initializer = '' - IdlArrayOrSequenceType.native_array_element_type = property( lambda self: self.element_type) @@ -358,9 +368,9 @@ def implemented_as(idl_type): IdlType.implemented_as = property(implemented_as) IdlType.set_implemented_as_interfaces = classmethod( - lambda cls, new_implemented_as_interfaces: - cls.implemented_as_interfaces.update(new_implemented_as_interfaces)) - + lambda cls, new_implemented_as_interfaces: \ + cls.implemented_as_interfaces.update(new_implemented_as_interfaces) +) # [GarbageCollected] IdlType.garbage_collected_types = set() @@ -369,8 +379,9 @@ IdlType.is_garbage_collected = property( lambda self: self.base_type in IdlType.garbage_collected_types) IdlType.set_garbage_collected_types = classmethod( - lambda cls, new_garbage_collected_types: - cls.garbage_collected_types.update(new_garbage_collected_types)) + lambda cls, new_garbage_collected_types: \ + cls.garbage_collected_types.update(new_garbage_collected_types) +) def is_gc_type(idl_type): @@ -381,7 +392,9 @@ IdlTypeBase.is_gc_type = property(is_gc_type) def is_traceable(idl_type): - return idl_type.is_garbage_collected or idl_type.is_callback_function or idl_type.cpp_type in ('ScriptValue', 'ScriptPromise') + return (idl_type.is_garbage_collected or idl_type.is_callback_function + or idl_type.cpp_type in ('ScriptValue', 'ScriptPromise')) + IdlTypeBase.is_traceable = property(is_traceable) IdlUnionType.is_traceable = property(lambda self: True) @@ -392,34 +405,39 @@ IdlRecordType.is_traceable = property( IdlNullableType.is_traceable = property( lambda self: self.inner_type.is_traceable) - ################################################################################ # Includes ################################################################################ INCLUDES_FOR_TYPE = { - 'object': set(), - 'ArrayBufferView': set(['bindings/core/v8/v8_array_buffer_view.h', - 'core/typed_arrays/array_buffer_view_helpers.h', - 'core/typed_arrays/flexible_array_buffer_view.h']), - 'Dictionary': set(['bindings/core/v8/dictionary.h']), - 'EventHandler': set(['bindings/core/v8/js_event_handler.h']), - 'HTMLCollection': set(['bindings/core/v8/v8_html_collection.h', - 'core/dom/class_collection.h', - 'core/dom/tag_collection.h', - 'core/html/html_collection.h', - 'core/html/html_table_rows_collection.h', - 'core/html/forms/html_data_list_options_collection.h', - 'core/html/forms/html_form_controls_collection.h']), - 'NodeList': set(['bindings/core/v8/v8_node_list.h', - 'core/dom/name_node_list.h', - 'core/dom/node_list.h', - 'core/dom/static_node_list.h', - 'core/html/forms/labels_node_list.h']), - 'Promise': set(['bindings/core/v8/script_promise.h']), - 'SerializedScriptValue': set(['bindings/core/v8/serialization/serialized_script_value.h', - 'bindings/core/v8/serialization/serialized_script_value_factory.h']), - 'ScriptValue': set(['bindings/core/v8/script_value.h']), + 'object': + set(['bindings/core/v8/script_value.h']), + 'ArrayBufferView': + set([ + 'bindings/core/v8/v8_array_buffer_view.h', + 'core/typed_arrays/array_buffer_view_helpers.h', + 'core/typed_arrays/flexible_array_buffer_view.h' + ]), + 'EventHandler': + set(['bindings/core/v8/js_event_handler.h']), + 'HTMLCollection': + set([ + 'bindings/core/v8/v8_html_collection.h', 'core/dom/class_collection.h', + 'core/dom/tag_collection.h', 'core/html/html_collection.h', + 'core/html/html_table_rows_collection.h', + 'core/html/forms/html_data_list_options_collection.h', + 'core/html/forms/html_form_controls_collection.h' + ]), + 'NodeList': + set([ + 'bindings/core/v8/v8_node_list.h', 'core/dom/name_node_list.h', + 'core/dom/node_list.h', 'core/dom/static_node_list.h', + 'core/html/forms/labels_node_list.h' + ]), + 'Promise': + set(['bindings/core/v8/script_promise.h']), + 'ScriptValue': + set(['bindings/core/v8/script_value.h']), } @@ -433,11 +451,15 @@ def includes_for_type(idl_type, extended_attributes=None): return INCLUDES_FOR_TYPE[base_idl_type] if base_idl_type in TYPED_ARRAY_TYPES: return INCLUDES_FOR_TYPE['ArrayBufferView'].union( - set(['bindings/%s/v8/%s' % (component_dir[base_idl_type], binding_header_filename(base_idl_type))]) - ) + set([ + 'bindings/%s/v8/%s' % (component_dir[base_idl_type], + binding_header_filename(base_idl_type)) + ])) if idl_type.is_basic_type: - return set(['bindings/core/v8/idl_types.h', - 'bindings/core/v8/native_value_traits_impl.h']) + return set([ + 'bindings/core/v8/idl_types.h', + 'bindings/core/v8/native_value_traits_impl.h' + ]) if base_idl_type.endswith('ConstructorConstructor'): # FIXME: rename to NamedConstructor # FIXME: replace with a [NamedConstructorAttribute] extended attribute @@ -445,41 +467,55 @@ def includes_for_type(idl_type, extended_attributes=None): # and these do not have header files, as they are part of the generated # bindings for the interface return set() - if (base_idl_type.endswith('Constructor') and - base_idl_type not in _CALLBACK_CONSTRUCTORS): + if (base_idl_type.endswith('Constructor') + and base_idl_type not in _CALLBACK_CONSTRUCTORS): # FIXME: replace with a [ConstructorAttribute] extended attribute base_idl_type = idl_type.constructor_type_name if idl_type.is_custom_callback_function: return set() if idl_type.is_callback_function: component = IdlType.callback_functions[base_idl_type]['component_dir'] - return set(['bindings/%s/v8/%s' % (component, binding_header_filename(base_idl_type))]) + return set([ + 'bindings/%s/v8/%s' % (component, + binding_header_filename(base_idl_type)) + ]) if base_idl_type not in component_dir: return set() - return set(['bindings/%s/v8/%s' % (component_dir[base_idl_type], - binding_header_filename(base_idl_type))]) + return set([ + 'bindings/%s/v8/%s' % (component_dir[base_idl_type], + binding_header_filename(base_idl_type)) + ]) + IdlType.includes_for_type = includes_for_type def includes_for_union_type(idl_type, extended_attributes=None): - return set.union(*[member_type.includes_for_type(extended_attributes) - for member_type in idl_type.member_types]) + return set.union(*[ + member_type.includes_for_type(extended_attributes) + for member_type in idl_type.member_types + ]) + IdlUnionType.includes_for_type = includes_for_union_type def includes_for_array_or_sequence_type(idl_type, extended_attributes=None): - return set.union(set(['bindings/core/v8/idl_types.h', - 'bindings/core/v8/native_value_traits_impl.h']), - idl_type.element_type.includes_for_type(extended_attributes)) + return set.union( + set([ + 'bindings/core/v8/idl_types.h', + 'bindings/core/v8/native_value_traits_impl.h' + ]), idl_type.element_type.includes_for_type(extended_attributes)) + IdlArrayOrSequenceType.includes_for_type = includes_for_array_or_sequence_type def includes_for_record_type(idl_type, extended_attributes=None): - return set.union(idl_type.key_type.includes_for_type(extended_attributes), - idl_type.value_type.includes_for_type(extended_attributes)) + return set.union( + idl_type.key_type.includes_for_type(extended_attributes), + idl_type.value_type.includes_for_type(extended_attributes)) + IdlRecordType.includes_for_type = includes_for_record_type @@ -487,6 +523,7 @@ IdlRecordType.includes_for_type = includes_for_record_type def add_includes_for_type(idl_type, extended_attributes=None): includes.update(idl_type.includes_for_type(extended_attributes)) + IdlTypeBase.add_includes_for_type = add_includes_for_type @@ -504,8 +541,8 @@ def impl_includes_for_type(idl_type, interfaces_info): idl_type = idl_type.preprocessed_type native_array_element_type = idl_type.native_array_element_type if native_array_element_type: - includes_for_type.update(impl_includes_for_type( - native_array_element_type, interfaces_info)) + includes_for_type.update( + impl_includes_for_type(native_array_element_type, interfaces_info)) includes_for_type.add('platform/wtf/vector.h') base_idl_type = idl_type.base_type @@ -513,24 +550,31 @@ def impl_includes_for_type(idl_type, interfaces_info): includes_for_type.add('platform/wtf/text/wtf_string.h') if idl_type.is_callback_function: component = IdlType.callback_functions[base_idl_type]['component_dir'] - return set(['bindings/%s/v8/%s' % (component, binding_header_filename(base_idl_type))]) + return set([ + 'bindings/%s/v8/%s' % (component, + binding_header_filename(base_idl_type)) + ]) if base_idl_type in interfaces_info: interface_info = interfaces_info[base_idl_type] includes_for_type.add(interface_info['include_path']) if base_idl_type in INCLUDES_FOR_TYPE: includes_for_type.update(INCLUDES_FOR_TYPE[base_idl_type]) if idl_type.is_array_buffer_view_or_typed_array: - return set(['core/typed_arrays/dom_typed_array.h', - 'core/typed_arrays/array_buffer_view_helpers.h']) + return set([ + 'core/typed_arrays/dom_typed_array.h', + 'core/typed_arrays/array_buffer_view_helpers.h' + ]) return includes_for_type def impl_includes_for_type_union(idl_type, interfaces_info): includes_for_type = set() for member_type in idl_type.member_types: - includes_for_type.update(member_type.impl_includes_for_type(interfaces_info)) + includes_for_type.update( + member_type.impl_includes_for_type(interfaces_info)) return includes_for_type + IdlTypeBase.impl_includes_for_type = impl_includes_for_type IdlUnionType.impl_includes_for_type = impl_includes_for_type_union @@ -549,7 +593,6 @@ def impl_forward_declaration_name(idl_type): IdlTypeBase.impl_forward_declaration_name = property( impl_forward_declaration_name) - component_dir = {} @@ -566,49 +609,55 @@ def set_component_dirs(new_component_dirs): # to introduce any performance regressions. V8_VALUE_TO_CPP_VALUE = { # Basic - 'DOMString': '{v8_value}', + 'DOMString': + '{v8_value}', # Interface types - 'FlexibleArrayBufferView': 'ToFlexibleArrayBufferView({isolate}, {v8_value}, {variable_name}, allocateFlexibleArrayBufferViewStorage({v8_value}))', - 'Promise': 'ScriptPromise::Cast(ScriptState::Current({isolate}), {v8_value})', - 'ScriptValue': 'ScriptValue({isolate}, {v8_value})', - 'Window': 'ToDOMWindow({isolate}, {v8_value})', - 'XPathNSResolver': 'ToXPathNSResolver(ScriptState::Current({isolate}), {v8_value})', + 'FlexibleArrayBufferView': + 'ToFlexibleArrayBufferView({isolate}, {v8_value}, {variable_name})', + 'Promise': + 'ScriptPromise::Cast(ScriptState::Current({isolate}), {v8_value})', + 'ScriptValue': + 'ScriptValue({isolate}, {v8_value})', + 'Window': + 'ToDOMWindow({isolate}, {v8_value})', + 'XPathNSResolver': + 'ToXPathNSResolver(ScriptState::Current({isolate}), {v8_value})', } def v8_conversion_needs_exception_state(idl_type): - return (idl_type.is_numeric_type or - idl_type.is_enum or - idl_type.is_dictionary or - idl_type.is_array_buffer_view_or_typed_array or - idl_type.name in ('Boolean', 'ByteString', 'Dictionary', 'USVString', 'SerializedScriptValue')) + return (idl_type.is_numeric_type or idl_type.is_enum + or idl_type.is_dictionary + or idl_type.is_array_buffer_view_or_typed_array + or idl_type.has_string_context or + idl_type.name in ('Boolean', 'ByteString', 'Object', 'USVString')) + -IdlType.v8_conversion_needs_exception_state = property(v8_conversion_needs_exception_state) +IdlType.v8_conversion_needs_exception_state = property( + v8_conversion_needs_exception_state) +IdlAnnotatedType.v8_conversion_needs_exception_state = property( + v8_conversion_needs_exception_state) IdlArrayOrSequenceType.v8_conversion_needs_exception_state = True IdlRecordType.v8_conversion_needs_exception_state = True IdlUnionType.v8_conversion_needs_exception_state = True - -TRIVIAL_CONVERSIONS = frozenset([ - 'any', - 'boolean', - 'Dictionary', - 'NodeFilter', - 'XPathNSResolver', - 'Promise' -]) +TRIVIAL_CONVERSIONS = frozenset( + ['any', 'boolean', 'NodeFilter', 'XPathNSResolver', 'Promise']) def v8_conversion_is_trivial(idl_type): # The conversion is a simple expression that returns the converted value and # cannot raise an exception. - return (idl_type.base_type in TRIVIAL_CONVERSIONS or - idl_type.is_wrapper_type) + return (idl_type.base_type in TRIVIAL_CONVERSIONS + or idl_type.is_wrapper_type) + IdlType.v8_conversion_is_trivial = property(v8_conversion_is_trivial) -def native_value_traits_type_name(idl_type, extended_attributes, in_sequence_or_record=False): +def native_value_traits_type_name(idl_type, + extended_attributes, + in_sequence_or_record=False): idl_type = idl_type.preprocessed_type if idl_type.is_string_type: @@ -617,24 +666,25 @@ def native_value_traits_type_name(idl_type, extended_attributes, in_sequence_or_ # attribute and nullable string types. name = 'IDL%s' % idl_type.name elif idl_type.is_nullable: - inner_type = native_value_traits_type_name(idl_type.inner_type, extended_attributes) - # IDLNullable is only required for sequences and such. - # The IDL compiler already has special cases for nullable operation + inner_type = idl_type.inner_type + inner_type_nvt_type = native_value_traits_type_name( + inner_type, extended_attributes) + # The IDL compiler has special cases to handle some nullable types in operation # parameters, dictionary fields, etc. - if in_sequence_or_record: - name = 'IDLNullable<%s>' % native_value_traits_type_name(idl_type.inner_type, - extended_attributes) + if in_sequence_or_record or inner_type.name == 'Object': + name = 'IDLNullable<%s>' % inner_type_nvt_type else: - name = inner_type + name = inner_type_nvt_type elif idl_type.native_array_element_type: - name = 'IDLSequence<%s>' % native_value_traits_type_name(idl_type.native_array_element_type, - extended_attributes, True) + name = 'IDLSequence<%s>' % native_value_traits_type_name( + idl_type.native_array_element_type, extended_attributes, True) elif idl_type.is_record_type: - name = 'IDLRecord<%s, %s>' % (native_value_traits_type_name(idl_type.key_type, - extended_attributes), - native_value_traits_type_name(idl_type.value_type, - extended_attributes, True)) - elif idl_type.is_basic_type or idl_type.name == 'Promise': + name = 'IDLRecord<%s, %s>' % (native_value_traits_type_name( + idl_type.key_type, extended_attributes), + native_value_traits_type_name( + idl_type.value_type, + extended_attributes, True)) + elif idl_type.is_basic_type or idl_type.name in ['Object', 'Promise']: name = 'IDL%s' % idl_type.name elif idl_type.implemented_as is not None: name = idl_type.implemented_as @@ -643,7 +693,8 @@ def native_value_traits_type_name(idl_type, extended_attributes, in_sequence_or_ return name -def v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, variable_name, isolate): +def v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, + variable_name, isolate, for_constructor_callback): if idl_type.name == 'void': return '' @@ -653,45 +704,58 @@ def v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, variable_name if 'FlexibleArrayBufferView' in extended_attributes: if base_idl_type not in ARRAY_BUFFER_VIEW_AND_TYPED_ARRAY_TYPES: - raise ValueError('Unrecognized base type for extended attribute "FlexibleArrayBufferView": %s' % (idl_type.base_type)) + raise ValueError( + 'Unrecognized base type for extended attribute "FlexibleArrayBufferView": %s' + % (idl_type.base_type)) if 'AllowShared' not in extended_attributes: - raise ValueError('"FlexibleArrayBufferView" extended attribute requires "AllowShared" on %s' % (idl_type.base_type)) + raise ValueError( + '"FlexibleArrayBufferView" extended attribute requires "AllowShared" on %s' + % (idl_type.base_type)) base_idl_type = 'FlexibleArrayBufferView' if 'AllowShared' in extended_attributes and not idl_type.is_array_buffer_view_or_typed_array: - raise ValueError('Unrecognized base type for extended attribute "AllowShared": %s' % (idl_type.base_type)) + raise ValueError( + 'Unrecognized base type for extended attribute "AllowShared": %s' % + (idl_type.base_type)) if idl_type.is_integer_type: arguments = ', '.join([v8_value, 'exception_state']) - elif base_idl_type == 'SerializedScriptValue': - arguments = ', '.join([ - v8_value, - 'SerializedScriptValue::SerializeOptions(SerializedScriptValue::kNotForStorage)', - 'exception_state']) elif idl_type.v8_conversion_needs_exception_state: arguments = ', '.join([v8_value, 'exception_state']) else: arguments = v8_value - if base_idl_type in V8_VALUE_TO_CPP_VALUE: + if idl_type.has_string_context: + execution_context = 'bindings::ExecutionContextFromV8Wrappable(impl)' + if for_constructor_callback: + execution_context = 'CurrentExecutionContext(info.GetIsolate())' + cpp_expression_format = 'NativeValueTraits<IDL%s>::NativeValue(%s, %s, exception_state, %s)' % ( + idl_type.name, isolate, v8_value, execution_context) + elif base_idl_type in V8_VALUE_TO_CPP_VALUE: cpp_expression_format = V8_VALUE_TO_CPP_VALUE[base_idl_type] elif idl_type.name == 'ArrayBuffer': cpp_expression_format = ( '{v8_value}->Is{idl_type}() ? ' - 'V8{idl_type}::ToImpl(v8::Local<v8::{idl_type}>::Cast({v8_value})) : 0') - elif idl_type.is_array_buffer_view_or_typed_array: - this_cpp_type = idl_type.cpp_type_args(extended_attributes=extended_attributes) + 'V8{idl_type}::ToImpl(v8::Local<v8::{idl_type}>::Cast({v8_value})) : 0' + ) + elif idl_type.is_array_buffer_view_or_typed_array or base_idl_type == 'DataView': + this_cpp_type = idl_type.cpp_type_args( + extended_attributes=extended_attributes) if 'AllowShared' in extended_attributes: - cpp_expression_format = ('ToMaybeShared<%s>({isolate}, {v8_value}, exception_state)' % this_cpp_type) + cpp_expression_format = ( + 'ToMaybeShared<%s>({isolate}, {v8_value}, exception_state)' % + this_cpp_type) else: - cpp_expression_format = ('ToNotShared<%s>({isolate}, {v8_value}, exception_state)' % this_cpp_type) - + cpp_expression_format = ( + 'ToNotShared<%s>({isolate}, {v8_value}, exception_state)' % + this_cpp_type) elif idl_type.is_union_type: nullable = 'UnionTypeConversionMode::kNullable' if idl_type.includes_nullable_type \ else 'UnionTypeConversionMode::kNotNullable' # We need to consider the moving of the null through the union in order # to generate the correct V8* class name. - this_cpp_type = idl_type.cpp_type_args(extended_attributes=extended_attributes) + this_cpp_type = idl_type.cpp_type_args( + extended_attributes=extended_attributes) cpp_expression_format = '%s::ToImpl({isolate}, {v8_value}, {variable_name}, %s, exception_state)' % \ (v8_type(this_cpp_type), nullable) elif idl_type.use_output_parameter_for_result: @@ -701,26 +765,47 @@ def v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, variable_name elif idl_type.v8_conversion_needs_exception_state: # Effectively, this if branch means everything with v8_conversion_needs_exception_state == True # except for unions and dictionary interfaces. - base_idl_type = native_value_traits_type_name(idl_type, extended_attributes) + base_idl_type = native_value_traits_type_name(idl_type, + extended_attributes) cpp_expression_format = ( - 'NativeValueTraits<{idl_type}>::NativeValue({isolate}, {arguments})') + 'NativeValueTraits<{idl_type}>::NativeValue({isolate}, {arguments})' + ) else: cpp_expression_format = ( 'V8{idl_type}::ToImplWithTypeCheck({isolate}, {v8_value})') - return cpp_expression_format.format(arguments=arguments, idl_type=base_idl_type, v8_value=v8_value, variable_name=variable_name, isolate=isolate) + return cpp_expression_format.format( + arguments=arguments, + idl_type=base_idl_type, + v8_value=v8_value, + variable_name=variable_name, + isolate=isolate) # FIXME: this function should be refactored, as this takes too many flags. -def v8_value_to_local_cpp_value(idl_type, extended_attributes, v8_value, variable_name, declare_variable=True, - isolate='info.GetIsolate()', bailout_return_value=None, use_exception_state=False, - code_generation_target=None): +def v8_value_to_local_cpp_value(idl_type, + extended_attributes, + v8_value, + variable_name, + declare_variable=True, + isolate='info.GetIsolate()', + bailout_return_value=None, + use_exception_state=False, + code_generation_target=None, + for_constructor_callback=False): """Returns an expression that converts a V8 value to a C++ value and stores it as a local value.""" - this_cpp_type = idl_type.cpp_type_args(extended_attributes=extended_attributes, raw_type=True) + this_cpp_type = idl_type.cpp_type_args( + extended_attributes=extended_attributes, raw_type=True) idl_type = idl_type.preprocessed_type - cpp_value = v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, variable_name, isolate) + cpp_value = v8_value_to_cpp_value( + idl_type, + extended_attributes, + v8_value, + variable_name, + isolate, + for_constructor_callback=for_constructor_callback) # Optional expression that returns a value to be assigned to the local variable. assign_expression = None @@ -734,7 +819,9 @@ def v8_value_to_local_cpp_value(idl_type, extended_attributes, v8_value, variabl if 'FlexibleArrayBufferView' in extended_attributes: if idl_type.base_type not in ARRAY_BUFFER_VIEW_AND_TYPED_ARRAY_TYPES: - raise ValueError('Unrecognized base type for extended attribute "FlexibleArrayBufferView": %s' % (idl_type.base_type)) + raise ValueError( + 'Unrecognized base type for extended attribute "FlexibleArrayBufferView": %s' + % (idl_type.base_type)) set_expression = cpp_value elif idl_type.is_string_type or idl_type.v8_conversion_needs_exception_state: # Types for which conversion can fail and that need error handling. @@ -756,7 +843,8 @@ def v8_value_to_local_cpp_value(idl_type, extended_attributes, v8_value, variabl check_expression = '!%s.Prepare()' % variable_name elif not idl_type.v8_conversion_is_trivial and not idl_type.is_callback_function: return { - 'error_message': 'no V8 -> C++ conversion for IDL type: %s' % idl_type.name + 'error_message': + 'no V8 -> C++ conversion for IDL type: %s' % idl_type.name } else: assign_expression = cpp_value @@ -766,10 +854,12 @@ def v8_value_to_local_cpp_value(idl_type, extended_attributes, v8_value, variabl if (idl_type.is_explicit_nullable and code_generation_target == 'attribute_set'): - assign_expression = ( - "is_null " - "? {cpp_type}() " - ": {expr}".format(cpp_type=this_cpp_type, expr=assign_expression)) + this_cpp_type = cpp_template_type('base::Optional', this_cpp_type) + expr = '{cpp_type}({expr})'.format( + cpp_type=this_cpp_type, expr=assign_expression) + assign_expression = ("is_null " + "? base::nullopt " + ": {expr}".format(expr=expr)) return { 'assign_expression': assign_expression, @@ -791,25 +881,28 @@ def use_output_parameter_for_result(idl_type): """ return idl_type.is_union_type -IdlTypeBase.use_output_parameter_for_result = property(use_output_parameter_for_result) +IdlTypeBase.use_output_parameter_for_result = property( + use_output_parameter_for_result) ################################################################################ # C++ -> V8 ################################################################################ + def preprocess_idl_type(idl_type): if idl_type.is_nullable: return IdlNullableType(idl_type.inner_type.preprocessed_type) if idl_type.is_enum: # Enumerations are internally DOMStrings return IdlType('DOMString') - if idl_type.base_type in ['any', 'object'] or idl_type.is_custom_callback_function: + if idl_type.base_type == 'any' or idl_type.is_custom_callback_function: return IdlType('ScriptValue') if idl_type.is_callback_function: return idl_type return idl_type + IdlTypeBase.preprocessed_type = property(preprocess_idl_type) @@ -830,8 +923,8 @@ def preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes): # [0, 2^31). When a value isn't in this range, a default value (or 0) # should be returned instead. extended_attributes = extended_attributes or {} - if ('Reflect' in extended_attributes and - idl_type.base_type in ['unsigned long', 'unsigned short']): + if ('Reflect' in extended_attributes + and idl_type.base_type in ['unsigned long', 'unsigned short']): cpp_value = cpp_value.replace('GetUnsignedIntegralAttribute', 'GetIntegralAttribute') cpp_value = 'std::max(0, static_cast<int>(%s))' % cpp_value @@ -873,11 +966,10 @@ def v8_conversion_type(idl_type, extended_attributes): if idl_type.is_nullable: return 'StringOrNull' return base_idl_type - if idl_type.is_basic_type or base_idl_type == 'ScriptValue': + if idl_type.is_basic_type: return base_idl_type - # Generic dictionary type - if base_idl_type == 'Dictionary': - return 'Dictionary' + if base_idl_type in ['object', 'ScriptValue']: + return 'ScriptValue' # Data type with potential additional includes if base_idl_type in V8_SET_RETURN_VALUE: # Special V8SetReturnValue treatment @@ -886,44 +978,68 @@ def v8_conversion_type(idl_type, extended_attributes): # Pointer type return 'DOMWrapper' -IdlTypeBase.v8_conversion_type = v8_conversion_type +IdlTypeBase.v8_conversion_type = v8_conversion_type V8_SET_RETURN_VALUE = { - 'boolean': 'V8SetReturnValueBool(info, {cpp_value})', - 'DOMString': 'V8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', - 'ByteString': 'V8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', - 'USVString': 'V8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', - 'StringOrNull': 'V8SetReturnValueStringOrNull(info, {cpp_value}, info.GetIsolate())', - 'void': '', + 'boolean': + 'V8SetReturnValueBool(info, {cpp_value})', + 'DOMString': + 'V8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', + 'ByteString': + 'V8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', + 'USVString': + 'V8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', + 'StringOrNull': + 'V8SetReturnValueStringOrNull(info, {cpp_value}, info.GetIsolate())', + 'void': + '', # All the int types below are converted to (u)int32_t in the V8SetReturnValue{Int,Unsigned}() calls. # The 64-bit int types have already been converted to double when V8_SET_RETURN_VALUE is used, so they are not # listed here. - 'int8_t': 'V8SetReturnValueInt(info, {cpp_value})', - 'int16_t': 'V8SetReturnValueInt(info, {cpp_value})', - 'int32_t': 'V8SetReturnValueInt(info, {cpp_value})', - 'uint8_t': 'V8SetReturnValueUnsigned(info, {cpp_value})', - 'uint16_t': 'V8SetReturnValueUnsigned(info, {cpp_value})', - 'uint32_t': 'V8SetReturnValueUnsigned(info, {cpp_value})', + 'int8_t': + 'V8SetReturnValueInt(info, {cpp_value})', + 'int16_t': + 'V8SetReturnValueInt(info, {cpp_value})', + 'int32_t': + 'V8SetReturnValueInt(info, {cpp_value})', + 'uint8_t': + 'V8SetReturnValueUnsigned(info, {cpp_value})', + 'uint16_t': + 'V8SetReturnValueUnsigned(info, {cpp_value})', + 'uint32_t': + 'V8SetReturnValueUnsigned(info, {cpp_value})', # No special V8SetReturnValue* function (set value directly) - 'float': 'V8SetReturnValue(info, {cpp_value})', - 'unrestricted float': 'V8SetReturnValue(info, {cpp_value})', - 'double': 'V8SetReturnValue(info, {cpp_value})', - 'unrestricted double': 'V8SetReturnValue(info, {cpp_value})', + 'float': + 'V8SetReturnValue(info, {cpp_value})', + 'unrestricted float': + 'V8SetReturnValue(info, {cpp_value})', + 'double': + 'V8SetReturnValue(info, {cpp_value})', + 'unrestricted double': + 'V8SetReturnValue(info, {cpp_value})', # No special V8SetReturnValue* function, but instead convert value to V8 # and then use general V8SetReturnValue. - 'sequence': 'V8SetReturnValue(info, {cpp_value})', - 'FrozenArray': 'V8SetReturnValue(info, {cpp_value})', - 'EventHandler': 'V8SetReturnValue(info, {cpp_value})', - 'NodeFilter': 'V8SetReturnValue(info, {cpp_value})', - 'ScriptValue': 'V8SetReturnValue(info, {cpp_value})', - 'SerializedScriptValue': 'V8SetReturnValue(info, {cpp_value})', + 'sequence': + 'V8SetReturnValue(info, {cpp_value})', + 'FrozenArray': + 'V8SetReturnValue(info, {cpp_value})', + 'EventHandler': + 'V8SetReturnValue(info, {cpp_value})', + 'NodeFilter': + 'V8SetReturnValue(info, {cpp_value})', + 'ScriptValue': + 'V8SetReturnValue(info, {cpp_value})', # Records. - 'Record': 'V8SetReturnValue(info, ToV8({cpp_value}, info.Holder(), info.GetIsolate()))', + 'Record': + 'V8SetReturnValue(info, ToV8({cpp_value}, info.Holder(), info.GetIsolate()))', # DOMWrapper - 'DOMWrapperForMainWorld': 'V8SetReturnValueForMainWorld(info, {cpp_value})', - 'DOMWrapperFast': 'V8SetReturnValueFast(info, {cpp_value}, {script_wrappable})', - 'DOMWrapperDefault': 'V8SetReturnValue(info, {cpp_value})', + 'DOMWrapperForMainWorld': + 'V8SetReturnValueForMainWorld(info, {cpp_value})', + 'DOMWrapperFast': + 'V8SetReturnValueFast(info, {cpp_value}, {script_wrappable})', + 'DOMWrapperDefault': + 'V8SetReturnValue(info, {cpp_value})', # If [CheckSecurity=ReturnValue] is specified, the returned object must be # wrapped in its own realm, which can be different from the realm of the # receiver object. @@ -935,34 +1051,42 @@ V8_SET_RETURN_VALUE = { # contentWindow(). Note that DOMWindow* has its own realm and there is no # need to pass |creationContext| in for ToV8(DOMWindow*). # Window.frameElement is implemented with [Custom]. - 'DOMWrapperAcrossContext': ( - 'V8SetReturnValue(info, ToV8({cpp_value}, ' + - 'ToV8(impl->contentWindow(), v8::Local<v8::Object>(), ' + - 'info.GetIsolate()).As<v8::Object>(), info.GetIsolate()))'), + 'DOMWrapperAcrossContext': + ('V8SetReturnValue(info, ToV8({cpp_value}, ' + + 'ToV8(impl->contentWindow(), v8::Local<v8::Object>(), ' + + 'info.GetIsolate()).As<v8::Object>(), info.GetIsolate()))'), # Note that static attributes and operations do not check whether |this| is # an instance of the interface nor |this|'s creation context is the same as # the current context. So we must always use the current context as the # creation context of the DOM wrapper for the return value. - 'DOMWrapperStatic': 'V8SetReturnValue(info, {cpp_value}, info.GetIsolate()->GetCurrentContext()->Global())', - # Generic dictionary type - 'Dictionary': 'V8SetReturnValue(info, {cpp_value})', - 'DictionaryStatic': '#error not implemented yet', + 'DOMWrapperStatic': + 'V8SetReturnValue(info, {cpp_value}, info.GetIsolate()->GetCurrentContext()->Global())', # Nullable dictionaries - 'NullableDictionary': 'V8SetReturnValue(info, result)', - 'NullableDictionaryStatic': 'V8SetReturnValue(info, result, info.GetIsolate()->GetCurrentContext()->Global())', + 'NullableDictionary': + 'V8SetReturnValue(info, result)', + 'NullableDictionaryStatic': + 'V8SetReturnValue(info, result, info.GetIsolate()->GetCurrentContext()->Global())', # Union types or dictionaries - 'DictionaryOrUnion': 'V8SetReturnValue(info, result)', - 'DictionaryOrUnionStatic': 'V8SetReturnValue(info, result, info.GetIsolate()->GetCurrentContext()->Global())', + 'DictionaryOrUnion': + 'V8SetReturnValue(info, result)', + 'DictionaryOrUnionStatic': + 'V8SetReturnValue(info, result, info.GetIsolate()->GetCurrentContext()->Global())', } -def v8_set_return_value(idl_type, cpp_value, extended_attributes=None, script_wrappable='', for_main_world=False, is_static=False): +def v8_set_return_value(idl_type, + cpp_value, + extended_attributes=None, + script_wrappable='', + for_main_world=False, + is_static=False): """Returns a statement that converts a C++ value to a V8 value and sets it as a return value. """ + def dom_wrapper_conversion_type(): - if ('CheckSecurity' in extended_attributes and - extended_attribute_value_contains( + if ('CheckSecurity' in extended_attributes + and extended_attribute_value_contains( extended_attributes['CheckSecurity'], 'ReturnValue')): return 'DOMWrapperAcrossContext' if is_static: @@ -973,59 +1097,81 @@ def v8_set_return_value(idl_type, cpp_value, extended_attributes=None, script_wr return 'DOMWrapperForMainWorld' return 'DOMWrapperFast' - idl_type, cpp_value = preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes) + idl_type, cpp_value = preprocess_idl_type_and_value( + idl_type, cpp_value, extended_attributes) this_v8_conversion_type = idl_type.v8_conversion_type(extended_attributes) # SetReturn-specific overrides if this_v8_conversion_type in ('EventHandler', 'NodeFilter', 'ScriptValue', - 'SerializedScriptValue', 'sequence', 'FrozenArray'): + 'sequence', 'FrozenArray'): # Convert value to V8 and then use general V8SetReturnValue - cpp_value = idl_type.cpp_value_to_v8_value(cpp_value, extended_attributes=extended_attributes) + cpp_value = idl_type.cpp_value_to_v8_value( + cpp_value, extended_attributes=extended_attributes) if this_v8_conversion_type == 'DOMWrapper': this_v8_conversion_type = dom_wrapper_conversion_type() - if is_static and this_v8_conversion_type in ('Dictionary', 'NullableDictionary', 'DictionaryOrUnion'): + if is_static and this_v8_conversion_type in ('NullableDictionary', + 'DictionaryOrUnion'): this_v8_conversion_type += 'Static' format_string = V8_SET_RETURN_VALUE[this_v8_conversion_type] - statement = format_string.format(cpp_value=cpp_value, script_wrappable=script_wrappable) + statement = format_string.format( + cpp_value=cpp_value, script_wrappable=script_wrappable) return statement IdlTypeBase.v8_set_return_value = v8_set_return_value - CPP_VALUE_TO_V8_VALUE = { # Built-in types - 'DOMString': 'V8String({isolate}, {cpp_value})', - 'ByteString': 'V8String({isolate}, {cpp_value})', - 'USVString': 'V8String({isolate}, {cpp_value})', - 'boolean': 'v8::Boolean::New({isolate}, {cpp_value})', + 'DOMString': + 'V8String({isolate}, {cpp_value})', + 'ByteString': + 'V8String({isolate}, {cpp_value})', + 'USVString': + 'V8String({isolate}, {cpp_value})', + 'boolean': + 'v8::Boolean::New({isolate}, {cpp_value})', # All the int types below are converted to (u)int32_t in the v8::Integer::New*() calls. # The 64-bit int types have already been converted to double when CPP_VALUE_TO_V8_VALUE is used, so they are not # listed here. - 'int8_t': 'v8::Integer::New({isolate}, {cpp_value})', - 'int16_t': 'v8::Integer::New({isolate}, {cpp_value})', - 'int32_t': 'v8::Integer::New({isolate}, {cpp_value})', - 'uint8_t': 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})', - 'uint16_t': 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})', - 'uint32_t': 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})', - 'float': 'v8::Number::New({isolate}, {cpp_value})', - 'unrestricted float': 'v8::Number::New({isolate}, {cpp_value})', - 'double': 'v8::Number::New({isolate}, {cpp_value})', - 'unrestricted double': 'v8::Number::New({isolate}, {cpp_value})', - 'StringOrNull': ('({cpp_value}.IsNull() ? ' + - 'v8::Null({isolate}).As<v8::Value>() : ' + - 'V8String({isolate}, {cpp_value}).As<v8::Value>())'), + 'int8_t': + 'v8::Integer::New({isolate}, {cpp_value})', + 'int16_t': + 'v8::Integer::New({isolate}, {cpp_value})', + 'int32_t': + 'v8::Integer::New({isolate}, {cpp_value})', + 'uint8_t': + 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})', + 'uint16_t': + 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})', + 'uint32_t': + 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})', + 'float': + 'v8::Number::New({isolate}, {cpp_value})', + 'unrestricted float': + 'v8::Number::New({isolate}, {cpp_value})', + 'double': + 'v8::Number::New({isolate}, {cpp_value})', + 'unrestricted double': + 'v8::Number::New({isolate}, {cpp_value})', + 'StringOrNull': + ('({cpp_value}.IsNull() ? ' + 'v8::Null({isolate}).As<v8::Value>() : ' + + 'V8String({isolate}, {cpp_value}).As<v8::Value>())'), # Special cases - 'Dictionary': '{cpp_value}.V8Value()', - 'EventHandler': 'JSEventHandler::AsV8Value({isolate}, impl, {cpp_value})', - 'NodeFilter': 'ToV8({cpp_value}, {creation_context}, {isolate})', - 'Record': 'ToV8({cpp_value}, {creation_context}, {isolate})', - 'ScriptValue': '{cpp_value}.V8Value()', - 'SerializedScriptValue': 'V8Deserialize({isolate}, {cpp_value}.get())', + 'EventHandler': + 'JSEventHandler::AsV8Value({isolate}, impl, {cpp_value})', + 'NodeFilter': + 'ToV8({cpp_value}, {creation_context}, {isolate})', + 'Record': + 'ToV8({cpp_value}, {creation_context}, {isolate})', + 'ScriptValue': + '{cpp_value}.V8Value()', # General - 'sequence': 'ToV8({cpp_value}, {creation_context}, {isolate})', - 'FrozenArray': 'FreezeV8Object(ToV8({cpp_value}, {creation_context}, {isolate}), {isolate})', - 'DOMWrapper': 'ToV8({cpp_value}, {creation_context}, {isolate})', + 'sequence': + 'ToV8({cpp_value}, {creation_context}, {isolate})', + 'FrozenArray': + 'FreezeV8Object(ToV8({cpp_value}, {creation_context}, {isolate}), {isolate})', + 'DOMWrapper': + 'ToV8({cpp_value}, {creation_context}, {isolate})', # Passing nullable dictionaries isn't a pattern currently used # anywhere in the web platform, and more work would be needed in # the code generator to distinguish between passing null, and @@ -1036,19 +1182,29 @@ CPP_VALUE_TO_V8_VALUE = { # nullable dictionary type. # # Union types or dictionaries - 'DictionaryOrUnion': 'ToV8({cpp_value}, {creation_context}, {isolate})', + 'DictionaryOrUnion': + 'ToV8({cpp_value}, {creation_context}, {isolate})', } -def cpp_value_to_v8_value(idl_type, cpp_value, isolate='info.GetIsolate()', creation_context='info.Holder()', extended_attributes=None): +def cpp_value_to_v8_value(idl_type, + cpp_value, + isolate='info.GetIsolate()', + creation_context='info.Holder()', + extended_attributes=None): """Returns an expression that converts a C++ value to a V8 value.""" # the isolate parameter is needed for callback interfaces - idl_type, cpp_value = preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes) + idl_type, cpp_value = preprocess_idl_type_and_value( + idl_type, cpp_value, extended_attributes) this_v8_conversion_type = idl_type.v8_conversion_type(extended_attributes) format_string = CPP_VALUE_TO_V8_VALUE[this_v8_conversion_type] - statement = format_string.format(cpp_value=cpp_value, isolate=isolate, creation_context=creation_context) + statement = format_string.format( + cpp_value=cpp_value, + isolate=isolate, + creation_context=creation_context) return statement + IdlTypeBase.cpp_value_to_v8_value = cpp_value_to_v8_value @@ -1096,7 +1252,6 @@ IdlType.literal_cpp_value = literal_cpp_value IdlUnionType.literal_cpp_value = union_literal_cpp_value IdlArrayOrSequenceType.literal_cpp_value = array_or_sequence_literal_cpp_value - _IDL_TYPE_TO_NATIVE_VALUE_TRAITS_TAG_MAP = { 'DOMString': 'IDLString', 'USVString': 'IDLUSVString', @@ -1133,15 +1288,13 @@ def cpp_type_has_null_value(idl_type): # - Interface types and Dictionary types represent null as a null pointer. # - Union types, as thier container classes can represent null value. # - 'Object' and 'any' type. We use ScriptValue for object type. - return (idl_type.is_string_type - or idl_type.is_enum - or idl_type.is_interface_type - or idl_type.is_callback_interface + return (idl_type.is_string_type or idl_type.is_enum + or idl_type.is_interface_type or idl_type.is_callback_interface or idl_type.is_callback_function - or idl_type.is_custom_callback_function - or idl_type.is_dictionary - or idl_type.is_union_type - or idl_type.base_type == 'object' or idl_type.base_type == 'any') + or idl_type.is_custom_callback_function or idl_type.is_dictionary + or idl_type.is_union_type or idl_type.base_type == 'object' + or idl_type.base_type == 'any') + IdlTypeBase.cpp_type_has_null_value = property(cpp_type_has_null_value) @@ -1156,6 +1309,7 @@ def is_explicit_nullable(idl_type): # we use base::Optional<T> or similar explicit ways to represent a null value. return idl_type.is_nullable and not idl_type.is_implicit_nullable + IdlTypeBase.is_implicit_nullable = property(is_implicit_nullable) IdlUnionType.is_implicit_nullable = False IdlTypeBase.is_explicit_nullable = property(is_explicit_nullable) @@ -1165,6 +1319,7 @@ def includes_nullable_type_union(idl_type): # http://heycam.github.io/webidl/#dfn-includes-a-nullable-type return idl_type.number_of_nullable_member_types == 1 + IdlTypeBase.includes_nullable_type = False IdlNullableType.includes_nullable_type = True IdlUnionType.includes_nullable_type = property(includes_nullable_type_union) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_union.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_union.py index ffacd12235c..54d50871d5a 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_union.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_union.py @@ -6,9 +6,9 @@ from utilities import to_snake_case import v8_types import v8_utilities - UNION_CPP_INCLUDES = frozenset([ 'base/stl_util.h', + 'bindings/core/v8/native_value_traits_impl.h', 'bindings/core/v8/to_v8_for_core.h', ]) @@ -21,7 +21,6 @@ UNION_H_INCLUDES = frozenset([ 'platform/heap/handle.h', ]) - cpp_includes = set() header_forward_decls = set() header_includes = set() @@ -47,7 +46,8 @@ def container_context(union_type, info_provider): object_type = None record_type = None string_type = None - for member in sorted(union_type.flattened_member_types, key=lambda m: m.name): + for member in sorted( + union_type.flattened_member_types, key=lambda m: m.name): context = member_context(member, info_provider) members.append(context) if member.base_type == 'ArrayBuffer': @@ -66,8 +66,7 @@ def container_context(union_type, info_provider): if array_or_sequence_type: raise Exception('%s is ambiguous.' % union_type.name) array_or_sequence_type = context - # "Dictionary" is an object, rather than an IDL dictionary. - elif member.base_type == 'Dictionary': + elif member.base_type == 'object': if object_type or record_type: raise Exception('%s is ambiguous.' % union_type.name) object_type = context @@ -84,14 +83,17 @@ def container_context(union_type, info_provider): elif member is union_type.string_member_type: string_type = context else: - raise Exception('%s is not supported as an union member.' % member.name) + raise Exception( + '%s is not supported as an union member.' % member.name) # Nullable restriction checks nullable_members = union_type.number_of_nullable_member_types if nullable_members > 1: - raise Exception('%s contains more than one nullable members' % union_type.name) + raise Exception( + '%s contains more than one nullable members' % union_type.name) if dictionary_type and nullable_members == 1: - raise Exception('%s has a dictionary and a nullable member' % union_type.name) + raise Exception( + '%s has a dictionary and a nullable member' % union_type.name) cpp_class = union_type.cpp_type return { @@ -119,8 +121,8 @@ def container_context(union_type, info_provider): def _update_includes_and_forward_decls(member, info_provider): interface_info = info_provider.interfaces_info.get(member.name, None) if interface_info: - cpp_includes.update(interface_info.get( - 'dependencies_include_paths', [])) + cpp_includes.update( + interface_info.get('dependencies_include_paths', [])) # We need complete types for IDL dictionaries in union containers. if member.is_dictionary or member.is_array_buffer_view_or_typed_array: header_includes.update(member.includes_for_type()) @@ -130,15 +132,18 @@ def _update_includes_and_forward_decls(member, info_provider): else: if member.is_record_type: _update_includes_and_forward_decls(member.key_type, info_provider) - _update_includes_and_forward_decls(member.value_type, info_provider) + _update_includes_and_forward_decls(member.value_type, + info_provider) elif member.is_array_or_sequence_type: - _update_includes_and_forward_decls(member.element_type, info_provider) + _update_includes_and_forward_decls(member.element_type, + info_provider) cpp_includes.add('bindings/core/v8/script_iterator.h') elif member.is_union_type: # Reaching this block means we have a union that is inside a # record or sequence. header_forward_decls.add(member.name) - cpp_includes.update([info_provider.include_path_for_union_types(member)]) + cpp_includes.update( + [info_provider.include_path_for_union_types(member)]) cpp_includes.update(member.includes_for_type()) @@ -146,7 +151,8 @@ def member_context(member, info_provider): _update_includes_and_forward_decls(member, info_provider) if member.is_nullable: member = member.inner_type - type_name = (member.inner_type if member.is_annotated_type else member).name + type_name = (member.inner_type + if member.is_annotated_type else member).name # When converting a sequence or frozen array, we need to call the GetMethod(V, @@iterator) # ES abstract operation and then use the result of that call to create a sequence from an # iterable. For the purposes of this method, it means we need to pass |script_iterator| @@ -156,21 +162,37 @@ def member_context(member, info_provider): else: v8_value_name = 'v8_value' return { - 'cpp_name': to_snake_case(v8_utilities.cpp_name(member)), - 'cpp_type': member.cpp_type_args(used_in_cpp_sequence=True), - 'cpp_local_type': member.cpp_type, - 'cpp_value_to_v8_value': member.cpp_value_to_v8_value( - cpp_value='impl.GetAs%s()' % type_name, isolate='isolate', + 'cpp_name': + to_snake_case(v8_utilities.cpp_name(member)), + 'cpp_type': + member.cpp_type_args(used_in_cpp_sequence=True), + 'cpp_local_type': + member.cpp_type, + 'cpp_value_to_v8_value': + member.cpp_value_to_v8_value( + cpp_value='impl.GetAs%s()' % type_name, + isolate='isolate', creation_context='creationContext'), - 'enum_type': member.enum_type, - 'enum_values': member.enum_values, - 'is_array_buffer_or_view_type': member.is_array_buffer_or_view, - 'is_array_buffer_view_or_typed_array': member.is_array_buffer_view_or_typed_array, - 'is_traceable': member.is_traceable, - 'rvalue_cpp_type': member.cpp_type_args(used_as_rvalue_type=True), - 'specific_type_enum': 'k' + member.name, - 'type_name': type_name, - 'v8_value_to_local_cpp_value': member.v8_value_to_local_cpp_value( - {}, v8_value_name, 'cpp_value', isolate='isolate', - use_exception_state=True) + 'enum_type': + member.enum_type, + 'enum_values': + member.enum_values, + 'is_array_buffer_or_view_type': + member.is_array_buffer_or_view, + 'is_array_buffer_view_or_typed_array': + member.is_array_buffer_view_or_typed_array, + 'is_traceable': + member.is_traceable, + 'rvalue_cpp_type': + member.cpp_type_args(used_as_rvalue_type=True), + 'specific_type_enum': + 'k' + member.name, + 'type_name': + type_name, + 'v8_value_to_local_cpp_value': + member.v8_value_to_local_cpp_value({}, + v8_value_name, + 'cpp_value', + isolate='isolate', + use_exception_state=True) } diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py index ec31d27da23..d6a53c6538a 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/v8_utilities.py @@ -25,7 +25,6 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """Functions shared by various parts of the code generator. Design doc: http://www.chromium.org/developers/design-documents/idl-compiler @@ -56,15 +55,15 @@ ACRONYMS = [ 'XSLT', ] - ################################################################################ # Extended attribute parsing ################################################################################ + def extended_attribute_value_contains(extended_attribute_value, key): - return (extended_attribute_value == key or - (isinstance(extended_attribute_value, list) and - key in extended_attribute_value)) + return (extended_attribute_value == key + or (isinstance(extended_attribute_value, list) + and key in extended_attribute_value)) def has_extended_attribute(definition_or_member, extended_attribute_list): @@ -74,8 +73,8 @@ def has_extended_attribute(definition_or_member, extended_attribute_list): def has_extended_attribute_value(definition_or_member, name, value): extended_attributes = definition_or_member.extended_attributes - return (name in extended_attributes and - extended_attribute_value_contains(extended_attributes[name], value)) + return (name in extended_attributes and extended_attribute_value_contains( + extended_attributes[name], value)) def extended_attribute_value_as_list(definition_or_member, name): @@ -92,6 +91,7 @@ def extended_attribute_value_as_list(definition_or_member, name): # String handling ################################################################################ + def capitalize(name): """Capitalize first letter or initial acronym (used in setter names).""" for acronym in ACRONYMS: @@ -126,14 +126,16 @@ def runtime_enabled_function(name): # C++ ################################################################################ + def scoped_name(interface, definition, base_name): # partial interfaces are implemented as separate classes, with their members # implemented as static member functions - partial_interface_implemented_as = definition.extended_attributes.get('PartialInterfaceImplementedAs') + partial_interface_implemented_as = definition.extended_attributes.get( + 'PartialInterfaceImplementedAs') if partial_interface_implemented_as: return '%s::%s' % (partial_interface_implemented_as, base_name) - if (definition.is_static or - definition.name in ('Constructor', 'NamedConstructor')): + if (definition.is_static + or definition.name in ('Constructor', 'NamedConstructor')): return '%s::%s' % (cpp_name(interface), base_name) return 'impl->%s' % base_name @@ -168,6 +170,7 @@ def binding_header_filename(name): # Specific extended attributes ################################################################################ + # [ActivityLogging] def activity_logging_world_list(member, access_type=''): """Returns a set of world suffixes for which a definition member has activity logging, for specified access type. @@ -198,8 +201,8 @@ def activity_logging_world_check(member): extended_attributes = member.extended_attributes if 'LogActivity' not in extended_attributes: return False - if ('PerWorldBindings' not in extended_attributes and - 'LogAllWorlds' not in extended_attributes): + if ('PerWorldBindings' not in extended_attributes + and 'LogAllWorlds' not in extended_attributes): return True return False @@ -225,16 +228,17 @@ CALL_WITH_VALUES = [ def call_with_arguments(call_with_values): if not call_with_values: return [] - return [CALL_WITH_ARGUMENTS[value] - for value in CALL_WITH_VALUES - if extended_attribute_value_contains(call_with_values, value)] + return [ + CALL_WITH_ARGUMENTS[value] for value in CALL_WITH_VALUES + if extended_attribute_value_contains(call_with_values, value) + ] # [Constructor], [NamedConstructor] def is_constructor_attribute(member): # TODO(yukishiino): replace this with [Constructor] and [NamedConstructor] extended attribute - return (type(member) == IdlAttribute and - member.idl_type.name.endswith('Constructor')) + return (type(member) == IdlAttribute + and member.idl_type.name.endswith('Constructor')) # [DeprecateAs] @@ -260,7 +264,6 @@ EXPOSED_EXECUTION_CONTEXT_METHOD = { 'Worklet': 'IsWorkletGlobalScope', } - EXPOSED_WORKERS = set([ 'DedicatedWorker', 'SharedWorker', @@ -270,6 +273,7 @@ EXPOSED_WORKERS = set([ class ExposureSet: """An ExposureSet is a collection of Exposure instructions.""" + def __init__(self, exposures=None): self.exposures = set(exposures) if exposures else set() @@ -301,9 +305,10 @@ class ExposureSet: @staticmethod def _code(exposure): condition = ('execution_context->%s()' % - EXPOSED_EXECUTION_CONTEXT_METHOD[exposure.exposed]) + EXPOSED_EXECUTION_CONTEXT_METHOD[exposure.exposed]) if exposure.runtime_enabled is not None: - runtime_enabled = (runtime_enabled_function(exposure.runtime_enabled)) + runtime_enabled = (runtime_enabled_function( + exposure.runtime_enabled)) return '({0} && {1})'.format(condition, runtime_enabled) return condition @@ -338,7 +343,9 @@ def exposed(member, interface): # Methods must not be exposed to a broader scope than their interface. if not exposure_set.issubset(interface_exposure_set): - raise ValueError('Interface members\' exposure sets must be a subset of the interface\'s.') + raise ValueError( + 'Interface members\' exposure sets must be a subset of the interface\'s.' + ) return exposure_set.code() @@ -349,9 +356,9 @@ def secure_context(member, interface): to the current context. Requires that the surrounding code defines an |is_secure_context| variable prior to this check.""" member_is_secure_context = 'SecureContext' in member.extended_attributes - interface_is_secure_context = ((member.defined_in is None or - member.defined_in == interface.name) and - 'SecureContext' in interface.extended_attributes) + interface_is_secure_context = ( + (member.defined_in is None or member.defined_in == interface.name) + and 'SecureContext' in interface.extended_attributes) if not (member_is_secure_context or interface_is_secure_context): return None @@ -361,12 +368,14 @@ def secure_context(member, interface): if member_is_secure_context: conditional = member.extended_attributes['SecureContext'] if conditional: - conditions.append('!{}'.format(runtime_enabled_function(conditional))) + conditions.append('!{}'.format( + runtime_enabled_function(conditional))) if interface_is_secure_context: conditional = interface.extended_attributes['SecureContext'] if conditional: - conditions.append('!{}'.format(runtime_enabled_function(conditional))) + conditions.append('!{}'.format( + runtime_enabled_function(conditional))) return ' || '.join(conditions) @@ -381,7 +390,8 @@ def cpp_name(definition_or_member): # # [1] https://heycam.github.io/webidl/#prod-identifier if '-' in definition_or_member.name: - return NameStyleConverter(definition_or_member.name).to_lower_camel_case() + return NameStyleConverter( + definition_or_member.name).to_lower_camel_case() return definition_or_member.name @@ -396,6 +406,25 @@ def cpp_name_or_partial(interface): return cpp_class_name +def cpp_encoded_property_name(member): + """ + Returns a property name that the bindings generator can use in generated + code internally. + + Note that Web IDL allows '-' (hyphen-minus) and '_' (low line) in + identifiers but C++ does not allow or recommend them. This function + encodes these characters. + """ + property_name = member.name + # We're optimistic about name conflict. It's highly unlikely that these + # replacements will cause a conflict. + assert "Dec45" not in property_name + assert "Dec95" not in property_name + property_name = property_name.replace("-", "Dec45") + property_name = property_name.replace("_", "Dec95") + return property_name + + # [MeasureAs] def measure_as(definition_or_member, interface): extended_attributes = definition_or_member.extended_attributes @@ -408,7 +437,8 @@ def measure_as(definition_or_member, interface): includes.add('platform/instrumentation/use_counter.h') measure_as_name = capitalize(definition_or_member.name) if interface is not None: - measure_as_name = '%s_%s' % (capitalize(interface.name), measure_as_name) + measure_as_name = '%s_%s' % (capitalize(interface.name), + measure_as_name) return lambda suffix: 'V8%s_%s' % (measure_as_name, suffix) return None @@ -418,10 +448,11 @@ def high_entropy(definition_or_member): extended_attributes = definition_or_member.extended_attributes if 'HighEntropy' in extended_attributes: includes.add('core/frame/dactyloscoper.h') - if not ('Measure' in extended_attributes or 'MeasureAs' in extended_attributes): - raise Exception('%s specified [HighEntropy], but does not include ' - 'either [Measure] or [MeasureAs]' - % definition_or_member.name) + if not ('Measure' in extended_attributes + or 'MeasureAs' in extended_attributes): + raise Exception( + '%s specified [HighEntropy], but does not include ' + 'either [Measure] or [MeasureAs]' % definition_or_member.name) return True return False @@ -440,7 +471,8 @@ def origin_trial_feature_name(definition_or_member, runtime_features): """ extended_attributes = definition_or_member.extended_attributes feature_name = extended_attributes.get('RuntimeEnabled') - if feature_name and _is_origin_trial_feature(feature_name, runtime_features): + if feature_name and _is_origin_trial_feature(feature_name, + runtime_features): return feature_name @@ -448,7 +480,8 @@ def origin_trial_function_call(feature_name, execution_context=None): """Returns a function call to determine if an origin trial is enabled.""" return 'RuntimeEnabledFeatures::{feature_name}Enabled({context})'.format( feature_name=feature_name, - context=execution_context if execution_context else "execution_context") + context=execution_context + if execution_context else "execution_context") # [ContextEnabled] @@ -470,7 +503,8 @@ def rcs_counter_name(member, generic_counter_name): def runtime_enabled_feature_name(definition_or_member, runtime_features): extended_attributes = definition_or_member.extended_attributes feature_name = extended_attributes.get('RuntimeEnabled') - if feature_name and not _is_origin_trial_feature(feature_name, runtime_features): + if feature_name and not _is_origin_trial_feature(feature_name, + runtime_features): includes.add('platform/runtime_enabled_features.h') return feature_name @@ -502,8 +536,8 @@ def on_instance(interface, member): if is_constructor_attribute(member): return True - if ('Global' in interface.extended_attributes or - 'Unforgeable' in member.extended_attributes): + if ('Global' in interface.extended_attributes + or 'Unforgeable' in member.extended_attributes): return True return False @@ -532,8 +566,8 @@ def on_prototype(interface, member): if is_constructor_attribute(member): return False - if ('Global' in interface.extended_attributes or - 'Unforgeable' in member.extended_attributes): + if ('Global' in interface.extended_attributes + or 'Unforgeable' in member.extended_attributes): return False return True @@ -556,16 +590,15 @@ def on_interface(interface, member): # http://heycam.github.io/webidl/#idl-indexed-properties ################################################################################ + def indexed_property_getter(interface): try: # Find indexed property getter, if present; has form: # getter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1) return next( - method - for method in interface.operations - if ('getter' in method.specials and - len(method.arguments) == 1 and - str(method.arguments[0].idl_type) == 'unsigned long')) + method for method in interface.operations + if ('getter' in method.specials and len(method.arguments) == 1 + and str(method.arguments[0].idl_type) == 'unsigned long')) except StopIteration: return None @@ -575,11 +608,9 @@ def indexed_property_setter(interface): # Find indexed property setter, if present; has form: # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE ARG2) return next( - method - for method in interface.operations - if ('setter' in method.specials and - len(method.arguments) == 2 and - str(method.arguments[0].idl_type) == 'unsigned long')) + method for method in interface.operations + if ('setter' in method.specials and len(method.arguments) == 2 + and str(method.arguments[0].idl_type) == 'unsigned long')) except StopIteration: return None @@ -589,11 +620,9 @@ def indexed_property_deleter(interface): # Find indexed property deleter, if present; has form: # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG) return next( - method - for method in interface.operations - if ('deleter' in method.specials and - len(method.arguments) == 1 and - str(method.arguments[0].idl_type) == 'unsigned long')) + method for method in interface.operations + if ('deleter' in method.specials and len(method.arguments) == 1 + and str(method.arguments[0].idl_type) == 'unsigned long')) except StopIteration: return None @@ -603,16 +632,15 @@ def indexed_property_deleter(interface): # http://heycam.github.io/webidl/#idl-named-properties ################################################################################ + def named_property_getter(interface): try: # Find named property getter, if present; has form: # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1) getter = next( - method - for method in interface.operations - if ('getter' in method.specials and - len(method.arguments) == 1 and - str(method.arguments[0].idl_type) == 'DOMString')) + method for method in interface.operations + if ('getter' in method.specials and len(method.arguments) == 1 + and str(method.arguments[0].idl_type) == 'DOMString')) getter.name = getter.name or 'AnonymousNamedGetter' return getter except StopIteration: @@ -624,11 +652,9 @@ def named_property_setter(interface): # Find named property setter, if present; has form: # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2) return next( - method - for method in interface.operations - if ('setter' in method.specials and - len(method.arguments) == 2 and - str(method.arguments[0].idl_type) == 'DOMString')) + method for method in interface.operations + if ('setter' in method.specials and len(method.arguments) == 2 + and str(method.arguments[0].idl_type) == 'DOMString')) except StopIteration: return None @@ -638,11 +664,9 @@ def named_property_deleter(interface): # Find named property deleter, if present; has form: # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG) return next( - method - for method in interface.operations - if ('deleter' in method.specials and - len(method.arguments) == 1 and - str(method.arguments[0].idl_type) == 'DOMString')) + method for method in interface.operations + if ('deleter' in method.specials and len(method.arguments) == 1 + and str(method.arguments[0].idl_type) == 'DOMString')) except StopIteration: return None diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf index 0169b9a6487..2ae9158e446 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/.style.yapf @@ -1,3 +1,4 @@ [style] # https://www.chromium.org/blink/coding-style based_on_style = pep8 +column_limit = 79 diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py index 4dacc398b45..387fef30bff 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py @@ -12,8 +12,10 @@ def _setup_sys_path(): expected_path = 'third_party/blink/renderer/bindings/scripts/web_idl/' this_dir = os.path.dirname(__file__) - root_dir = os.path.join(this_dir, *(['..'] * expected_path.count('/'))) - sys.path = [ + root_dir = os.path.abspath( + os.path.join(this_dir, *(['..'] * expected_path.count('/')))) + + module_dirs = ( # //third_party/blink/renderer/build/scripts/blinkbuild os.path.join(root_dir, 'third_party', 'blink', 'renderer', 'build', 'scripts'), @@ -23,17 +25,23 @@ def _setup_sys_path(): os.path.join(root_dir, 'third_party', 'pyjson5', 'src'), # //tools/idl_parser os.path.join(root_dir, 'tools'), - ] + sys.path + ) + for module_dir in reversed(module_dirs): + # Preserve sys.path[0] as is. + # https://docs.python.org/3/library/sys.html?highlight=path[0]#sys.path + sys.path.insert(1, module_dir) _setup_sys_path() - +from . import file_io from .ast_group import AstGroup from .attribute import Attribute from .callback_function import CallbackFunction from .callback_interface import CallbackInterface from .composition_parts import Component +from .composition_parts import DebugInfo +from .composition_parts import Identifier from .constant import Constant from .constructor import Constructor from .constructor import ConstructorGroup @@ -43,10 +51,18 @@ from .dictionary import Dictionary from .dictionary import DictionaryMember from .enumeration import Enumeration from .exposure import Exposure +from .extended_attribute import ExtendedAttribute +from .extended_attribute import ExtendedAttributes from .function_like import FunctionLike from .function_like import OverloadGroup from .idl_type import IdlType +from .interface import IndexedAndNamedProperties from .interface import Interface +from .interface import Iterable +from .interface import LegacyWindowAlias +from .interface import Maplike +from .interface import Setlike +from .interface import Stringifier from .literal_constant import LiteralConstant from .namespace import Namespace from .operation import Operation diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py index 1d3f9d74fc1..467e1006463 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py @@ -55,7 +55,7 @@ class Attribute(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, ir = make_copy(ir) WithIdentifier.__init__(self, ir) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithOwner.__init__(self, owner) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_function.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_function.py index 3536a9e67c6..b82196d6b7b 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_function.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_function.py @@ -47,7 +47,7 @@ class CallbackFunction(UserDefinedType, FunctionLike, WithExtendedAttributes, ir = make_copy(ir) UserDefinedType.__init__(self, ir.identifier) FunctionLike.__init__(self, ir) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithComponent.__init__(self, ir, readonly=True) WithDebugInfo.__init__(self, ir) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py index e3792d16520..42249966d1c 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/callback_interface.py @@ -52,17 +52,19 @@ class CallbackInterface(UserDefinedType, WithExtendedAttributes, self.attributes = [] self.constants = constants - self.operations = operations - self.operation_groups = [] self.constructors = [] self.constructor_groups = [] + self.named_constructors = [] + self.named_constructor_groups = [] + self.operations = operations + self.operation_groups = [] def __init__(self, ir): assert isinstance(ir, CallbackInterface.IR) ir = make_copy(ir) UserDefinedType.__init__(self, ir.identifier) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithComponent.__init__(self, ir, readonly=True) WithDebugInfo.__init__(self, ir) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/code_generator_info.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/code_generator_info.py index 98a491d27b2..9c1d2784440 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/code_generator_info.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/code_generator_info.py @@ -5,8 +5,11 @@ # The list of attributes that CodeGeneratorInfo supports. CodeGeneratorInfo's # attributes are auto-generated from this list because they're boilerplated. _CODE_GENERATOR_INFO_ATTRIBUTES = ( - 'defined_in_mixin', - 'defined_in_partial', + 'blink_headers', + 'defined_in_mixin', # [LegacyTreatAsPartialInterface] makes this False + 'defined_in_partial', # [LegacyTreatAsPartialInterface] makes this True + 'is_active_script_wrappable', + 'is_legacy_unenumerable_named_properties', 'property_implemented_as', 'receiver_implemented_as', ) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py index a999bca7d7e..29add032724 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py @@ -2,11 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import posixpath + from .code_generator_info import CodeGeneratorInfo from .code_generator_info import CodeGeneratorInfoMutable from .exposure import Exposure from .exposure import ExposureMutable from .extended_attribute import ExtendedAttributes +from .extended_attribute import ExtendedAttributesMutable class Identifier(str): @@ -31,14 +34,18 @@ class WithIdentifier(object): class WithExtendedAttributes(object): """Implements |extended_attributes| as a readonly attribute.""" - def __init__(self, extended_attributes=None): + def __init__(self, extended_attributes=None, readonly=False): if isinstance(extended_attributes, WithExtendedAttributes): extended_attributes = extended_attributes.extended_attributes elif extended_attributes is None: extended_attributes = ExtendedAttributes() assert isinstance(extended_attributes, ExtendedAttributes) - self._extended_attributes = extended_attributes + if readonly: + self._extended_attributes = ExtendedAttributes(extended_attributes) + else: + self._extended_attributes = ExtendedAttributesMutable( + extended_attributes) @property def extended_attributes(self): @@ -133,10 +140,22 @@ class WithComponent(object): class Location(object): + _blink_path_prefix = posixpath.sep + posixpath.join( + 'third_party', 'blink', 'renderer', '') + def __init__(self, filepath=None, line_number=None, position=None): assert filepath is None or isinstance(filepath, str) assert line_number is None or isinstance(line_number, int) assert position is None or isinstance(position, int) + + # idl_parser produces paths based on the working directory, which may + # not be the project root directory, e.g. "../../third_party/blink/...". + # Canonicalize the paths heuristically. + if filepath is not None: + index = filepath.find(self._blink_path_prefix) + if index >= 0: + filepath = filepath[index + 1:] + self._filepath = filepath self._line_number = line_number self._position = position # Position number in a file diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constant.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constant.py index 3a4a85ea710..c54fef0b472 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constant.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constant.py @@ -50,7 +50,7 @@ class Constant(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, ir = make_copy(ir) WithIdentifier.__init__(self, ir) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithOwner.__init__(self, owner) @@ -67,6 +67,14 @@ class Constant(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, return self._idl_type @property + def is_static(self): + return True + + @property + def is_readonly(self): + return True + + @property def value(self): """Returns the value.""" return self._value diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constructor.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constructor.py index 486ee910d11..ceacd261c7c 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constructor.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/constructor.py @@ -27,14 +27,16 @@ class Constructor(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo, class IR(FunctionLike.IR, WithExtendedAttributes, WithCodeGeneratorInfo, WithExposure, WithOwnerMixin, WithComponent, WithDebugInfo): def __init__(self, + identifier, arguments, return_type, extended_attributes=None, component=None, debug_info=None): + assert identifier is None or isinstance(identifier, Identifier) FunctionLike.IR.__init__( self, - identifier=Identifier('constructor'), + identifier=(identifier or Identifier('constructor')), arguments=arguments, return_type=return_type) WithExtendedAttributes.__init__(self, extended_attributes) @@ -48,7 +50,7 @@ class Constructor(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo, assert isinstance(ir, Constructor.IR) FunctionLike.__init__(self, ir) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithOwner.__init__(self, owner) @@ -57,22 +59,25 @@ class Constructor(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo.__init__(self, ir) -class ConstructorGroup(OverloadGroup, WithCodeGeneratorInfo, WithExposure, - WithOwner, WithComponent, WithDebugInfo): +class ConstructorGroup(OverloadGroup, WithExtendedAttributes, + WithCodeGeneratorInfo, WithExposure, WithOwner, + WithComponent, WithDebugInfo): """ - Represents a group of constructors for an interface. + Represents a group of constructors of an interface. The number of constructors in this group may be 1 or 2+. In the latter case, the constructors are overloaded. """ - class IR(OverloadGroup.IR, WithCodeGeneratorInfo, WithExposure, - WithDebugInfo): + class IR(OverloadGroup.IR, WithExtendedAttributes, WithCodeGeneratorInfo, + WithExposure, WithDebugInfo): def __init__(self, constructors, + extended_attributes=None, code_generator_info=None, debug_info=None): OverloadGroup.IR.__init__(self, constructors) + WithExtendedAttributes.__init__(self, extended_attributes) WithCodeGeneratorInfo.__init__(self, code_generator_info) WithExposure.__init__(self) WithDebugInfo.__init__(self, debug_info) @@ -92,6 +97,7 @@ class ConstructorGroup(OverloadGroup, WithCodeGeneratorInfo, WithExposure, ir = make_copy(ir) OverloadGroup.__init__(self, functions=constructors) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithOwner.__init__(self, owner) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py index b9ecfe5632e..c92cf48eb2a 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/database.py @@ -48,17 +48,17 @@ class DatabaseBody(object): ) @classmethod - def itervalues(cls): + def values(cls): return cls._ALL_ENTRIES.__iter__() def __init__(self): self._defs = {} - for kind in DatabaseBody.Kind.itervalues(): + for kind in DatabaseBody.Kind.values(): self._defs[kind] = {} def register(self, kind, user_defined_type): assert isinstance(user_defined_type, (Typedef, Union, UserDefinedType)) - assert kind in DatabaseBody.Kind.itervalues() + assert kind in DatabaseBody.Kind.values() try: self.find_by_identifier(user_defined_type.identifier) assert False, user_defined_type.identifier @@ -67,7 +67,7 @@ class DatabaseBody(object): self._defs[kind][user_defined_type.identifier] = user_defined_type def find_by_identifier(self, identifier): - for defs_per_kind in self._defs.itervalues(): + for defs_per_kind in self._defs.values(): if identifier in defs_per_kind: return defs_per_kind[identifier] raise KeyError(identifier) @@ -107,6 +107,26 @@ class Database(object): return self._impl.find_by_identifier(identifier) @property + def callback_functions(self): + """Returns all callback functions.""" + return self._view_by_kind(Database._Kind.CALLBACK_FUNCTION) + + @property + def callback_interfaces(self): + """Returns all callback interfaces.""" + return self._view_by_kind(Database._Kind.CALLBACK_INTERFACE) + + @property + def dictionaries(self): + """Returns all dictionaries.""" + return self._view_by_kind(Database._Kind.DICTIONARY) + + @property + def enumerations(self): + """Returns all enumerations.""" + return self._view_by_kind(Database._Kind.ENUMERATION) + + @property def interfaces(self): """ Returns all interfaces. @@ -121,26 +141,11 @@ class Database(object): return self._view_by_kind(Database._Kind.INTERFACE_MIXIN) @property - def dictionaries(self): - """Returns all dictionaries.""" - return self._view_by_kind(Database._Kind.DICTIONARY) - - @property def namespaces(self): """Returns all namespaces.""" return self._view_by_kind(Database._Kind.NAMESPACE) @property - def callback_functions(self): - """Returns all callback functions.""" - return self._view_by_kind(Database._Kind.CALLBACK_FUNCTION) - - @property - def callback_interfaces(self): - """Returns all callback interfaces.""" - return self._view_by_kind(Database._Kind.CALLBACK_INTERFACE) - - @property def typedefs(self): """Returns all typedef definitions.""" return self._view_by_kind(Database._Kind.TYPEDEF) @@ -151,4 +156,4 @@ class Database(object): return self._view_by_kind(Database._Kind.UNION) def _view_by_kind(self, kind): - return self._impl.find_by_kind(kind).viewvalues() + return self._impl.find_by_kind(kind).values() diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/demonstration_and_testing.idl b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/demonstration_and_testing.idl index 1f94e76ad3b..766bfe7a7cf 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/demonstration_and_testing.idl +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/demonstration_and_testing.idl @@ -12,7 +12,7 @@ Exposed=Window ] interface TestInterfaceConstructor { constructor(); - constructor(DOMString arg1); + [HTMLConstructor] constructor(DOMString arg1); [Custom] constructor(Node node); [RuntimeEnabled=TestFeature1] constructor(long num); }; diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py index 1f536e99b0d..01d2cdedcd6 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py @@ -62,7 +62,7 @@ class Dictionary(UserDefinedType, WithExtendedAttributes, ir = make_copy(ir) UserDefinedType.__init__(self, ir.identifier) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithComponent.__init__(self, ir, readonly=True) @@ -143,7 +143,7 @@ class DictionaryMember(WithIdentifier, WithExtendedAttributes, ir = make_copy(ir) WithIdentifier.__init__(self, ir) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithOwner.__init__(self, owner) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/enumeration.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/enumeration.py index b402d14c2d7..f141e86e05d 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/enumeration.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/enumeration.py @@ -42,7 +42,7 @@ class Enumeration(UserDefinedType, WithExtendedAttributes, ir = make_copy(ir) UserDefinedType.__init__(self, ir.identifier) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithComponent.__init__(self, ir, readonly=True) WithDebugInfo.__init__(self, ir) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py index 266b7388a18..46e2e45af49 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py @@ -5,13 +5,29 @@ from .runtime_enabled_features import RuntimeEnabledFeatures +class _Feature(str): + """Represents a runtime-enabled feature.""" + + def __init__(self, value): + str.__init__(self, value) + self._is_context_dependent = ( + RuntimeEnabledFeatures.is_context_dependent(self)) + + @property + def is_context_dependent(self): + return self._is_context_dependent + + class _GlobalNameAndFeature(object): def __init__(self, global_name, feature=None): assert isinstance(global_name, str) assert feature is None or isinstance(feature, str) self._global_name = global_name - self._feature = feature + if feature is None: + self._feature = None + else: + self._feature = _Feature(feature) @property def global_name(self): @@ -23,6 +39,8 @@ class _GlobalNameAndFeature(object): class Exposure(object): + """Represents a set of conditions under which the construct is exposed.""" + def __init__(self, other=None): assert other is None or isinstance(other, Exposure) @@ -94,6 +112,34 @@ class Exposure(object): return False return self._only_in_secure_contexts + def is_context_dependent(self, global_names=None): + """ + Returns True if the exposure of this construct depends on a context. + + Args: + global_names: When specified, it's taken into account that the + global object implements |global_names|. + """ + assert (global_names is None + or (isinstance(global_names, (list, tuple)) + and all(isinstance(name, str) for name in global_names))) + + if (self.context_dependent_runtime_enabled_features + or self.context_enabled_features + or self.only_in_secure_contexts): + return True + + if not global_names: + return bool(self.global_names_and_features) + + is_context_dependent = False + for entry in self.global_names_and_features: + if entry.global_name not in global_names: + continue + if entry.feature and entry.feature.is_context_dependent: + is_context_dependent = True + return is_context_dependent + class ExposureMutable(Exposure): def __init__(self): @@ -118,11 +164,12 @@ class ExposureMutable(Exposure): def add_runtime_enabled_feature(self, name): assert isinstance(name, str) - if RuntimeEnabledFeatures.is_context_dependent(name): - self._context_dependent_runtime_enabled_features.append(name) + feature = _Feature(name) + if feature.is_context_dependent: + self._context_dependent_runtime_enabled_features.append(feature) else: - self._context_independent_runtime_enabled_features.append(name) - self._runtime_enabled_features.append(name) + self._context_independent_runtime_enabled_features.append(feature) + self._runtime_enabled_features.append(feature) def add_context_enabled_feature(self, name): assert isinstance(name, str) @@ -136,6 +183,6 @@ class ExposureMutable(Exposure): if isinstance(value, bool): self._only_in_secure_contexts = value elif isinstance(value, str): - self._only_in_secure_contexts = (value, ) + self._only_in_secure_contexts = (_Feature(value), ) else: - self._only_in_secure_contexts = tuple(value) + self._only_in_secure_contexts = tuple(map(_Feature, value)) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py index ee6967af9b1..36eec862f47 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py @@ -169,10 +169,12 @@ class ExtendedAttributes(object): """ def __init__(self, extended_attributes=None): - assert extended_attributes is None or (isinstance( - extended_attributes, (list, tuple)) and all( - isinstance(attr, ExtendedAttribute) - for attr in extended_attributes)) + assert (extended_attributes is None + or isinstance(extended_attributes, ExtendedAttributes) + or (isinstance(extended_attributes, (list, tuple)) and all( + isinstance(attr, ExtendedAttribute) + for attr in extended_attributes))) + sorted_ext_attrs = sorted( extended_attributes or [], key=lambda x: x.key) @@ -181,8 +183,15 @@ class ExtendedAttributes(object): for key, ext_attrs in itertools.groupby( sorted_ext_attrs, key=lambda x: x.key) } + self._keys = None + self._length = None + self._on_ext_attrs_updated() + + def _on_ext_attrs_updated(self): self._keys = tuple(sorted(self._ext_attrs.keys())) - self._length = len(sorted_ext_attrs) + self._length = 0 + for ext_attrs in self._ext_attrs.values(): + self._length += len(ext_attrs) @classmethod def equals(cls, lhs, rhs): @@ -256,3 +265,26 @@ class ExtendedAttributes(object): """Returns self.get(key).values if the key exists or an empty list.""" ext_attr = self.get(key) return ext_attr.values if ext_attr else () + + def _append(self, ext_attr): + assert isinstance(ext_attr, ExtendedAttribute) + + if ext_attr.key not in self._ext_attrs: + self._ext_attrs[ext_attr.key] = (ext_attr, ) + else: + self._ext_attrs[ext_attr.key] = (tuple( + sorted( + self._ext_attrs[ext_attr.key] + (ext_attr, ), + key=lambda x: x.syntactic_form))) + self._on_ext_attrs_updated() + + +class ExtendedAttributesMutable(ExtendedAttributes): + def __getstate__(self): + assert False, "ExtendedAttributesMutable must not be pickled." + + def __setstate__(self, state): + assert False, "ExtendedAttributesMutable must not be pickled." + + def append(self, ext_attr): + self._append(ext_attr) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute_test.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute_test.py index b4d4876ec74..2e4144f0477 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute_test.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute_test.py @@ -1,7 +1,6 @@ # Copyright 2019 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Unit tests for extended_attributes.py.""" import unittest diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/file_io.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/file_io.py index 9136a41a3b0..19e3327a8fb 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/file_io.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/file_io.py @@ -3,14 +3,19 @@ # found in the LICENSE file. import os -import pickle +import sys + +if sys.version_info.major == 2: + import cPickle as pickle # 'cPickle' is faster than 'pickle' on Py2 +else: + import pickle def read_pickle_file(filepath): """ Reads the content of the file as a pickled object. """ - with open(filepath, 'r') as file_obj: + with open(filepath, 'rb') as file_obj: return pickle.load(file_obj) @@ -30,7 +35,7 @@ def write_to_file_if_changed(filepath, contents): Returns True if the data is written to the file, and False if skipped. """ try: - with open(filepath, 'r') as file_obj: + with open(filepath, 'rb') as file_obj: old_contents = file_obj.read() except (OSError, EnvironmentError): pass @@ -38,6 +43,10 @@ def write_to_file_if_changed(filepath, contents): if contents == old_contents: return False os.remove(filepath) - with open(filepath, 'w') as file_obj: + + if not os.path.exists(os.path.dirname(filepath)): + os.makedirs(os.path.dirname(filepath)) + + with open(filepath, 'wb') as file_obj: file_obj.write(contents) return True diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py index 223a93fa09b..648c70d803d 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py @@ -242,11 +242,10 @@ class OverloadGroup(WithIdentifier): # step 1. If one type includes a nullable type and the other type either # includes a nullable type, is a union type with flattened member # types including a dictionary type, or is a dictionary type, ... - type1_nullable = (idl_type1.does_include_nullable_type - or idl_type1.unwrap().is_dictionary) - type2_nullable = (idl_type2.does_include_nullable_type - or idl_type2.unwrap().is_dictionary) - if type1_nullable and type2_nullable: + if ((idl_type1.does_include_nullable_type + and idl_type2.does_include_nullable_or_dict) + or (idl_type2.does_include_nullable_type + and idl_type1.does_include_nullable_or_dict)): return False type1 = idl_type1.unwrap() @@ -272,6 +271,9 @@ class OverloadGroup(WithIdentifier): return True # step 4. Consider the two "innermost" types ... + def is_string_type(idl_type): + return idl_type.is_string or idl_type.is_enumeration + def is_interface_like(idl_type): return idl_type.is_interface or idl_type.is_buffer_source_type @@ -292,11 +294,11 @@ class OverloadGroup(WithIdentifier): return not type2.is_boolean if type1.is_numeric: return not type2.is_numeric - if type1.is_string: - return not type2.is_string + if is_string_type(type1): + return not is_string_type(type2) if type1.is_object: - return (type2.is_boolean or type2.is_numeric or type2.is_string - or type2.is_symbol) + return (type2.is_boolean or type2.is_numeric + or is_string_type(type2) or type2.is_symbol) if type1.is_symbol: return not type2.is_symbol if is_interface_like(type1): diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py index 847ba334683..e7c2cd0f615 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py @@ -4,6 +4,9 @@ import functools import itertools +import posixpath + +from blinkbuild.name_style_converter import NameStyleConverter from .callback_function import CallbackFunction from .callback_interface import CallbackInterface @@ -13,8 +16,12 @@ from .database import Database from .database import DatabaseBody from .dictionary import Dictionary from .enumeration import Enumeration +from .exposure import ExposureMutable +from .extended_attribute import ExtendedAttribute +from .extended_attribute import ExtendedAttributesMutable from .idl_type import IdlTypeFactory from .interface import Interface +from .interface import LegacyWindowAlias from .ir_map import IRMap from .make_copy import make_copy from .namespace import Namespace @@ -76,9 +83,15 @@ class IdlCompiler(object): assert not self._did_run self._did_run = True + # Remove the interface members that are specific to the old bindings + # generator, i.e. that are not necessary for (or even harmful to) the + # new bindings generator. + self._remove_legacy_interface_members() + # Merge partial definitions. self._record_defined_in_partial_and_mixin() self._propagate_extattrs_per_idl_fragment() + self._determine_blink_headers() self._merge_partial_interface_likes() self._merge_partial_dictionaries() # Merge mixins. @@ -88,10 +101,15 @@ class IdlCompiler(object): # Process inheritances. self._process_interface_inheritances() + self._copy_named_constructor_extattrs() + # Make groups of overloaded functions including inherited ones. self._group_overloaded_functions() + self._propagate_extattrs_to_overload_group() self._calculate_group_exposure() + self._fill_exposed_constructs() + self._sort_dictionary_members() # Updates on IRs are finished. Create API objects. @@ -107,6 +125,28 @@ class IdlCompiler(object): return Database(self._db) + def _maybe_make_copy(self, ir): + # You can make this function return make_copy(ir) for debugging + # purpose, etc. + return ir # Skip copying as an optimization. + + def _remove_legacy_interface_members(self): + old_irs = self._ir_map.irs_of_kinds( + IRMap.IR.Kind.INTERFACE, IRMap.IR.Kind.INTERFACE_MIXIN, + IRMap.IR.Kind.PARTIAL_INTERFACE, + IRMap.IR.Kind.PARTIAL_INTERFACE_MIXIN) + + not_disabled = ( + lambda x: 'DisableInNewIDLCompiler' not in x.extended_attributes) + + self._ir_map.move_to_new_phase() + + for old_ir in old_irs: + new_ir = make_copy(old_ir) + self._ir_map.add(new_ir) + new_ir.attributes = filter(not_disabled, new_ir.attributes) + new_ir.operations = filter(not_disabled, new_ir.operations) + def _record_defined_in_partial_and_mixin(self): old_irs = self._ir_map.irs_of_kinds( IRMap.IR.Kind.DICTIONARY, IRMap.IR.Kind.INTERFACE, @@ -118,13 +158,19 @@ class IdlCompiler(object): self._ir_map.move_to_new_phase() for old_ir in old_irs: - new_ir = make_copy(old_ir) + new_ir = self._maybe_make_copy(old_ir) self._ir_map.add(new_ir) + is_partial = False + is_mixin = False + if 'LegacyTreatAsPartialInterface' in new_ir.extended_attributes: + is_partial = True + elif hasattr(new_ir, 'is_partial') and new_ir.is_partial: + is_partial = True + elif hasattr(new_ir, 'is_mixin') and new_ir.is_mixin: + is_mixin = True for member in new_ir.iter_all_members(): - member.code_generator_info.set_defined_in_partial( - hasattr(new_ir, 'is_partial') and new_ir.is_partial) - member.code_generator_info.set_defined_in_mixin( - hasattr(new_ir, 'is_mixin') and new_ir.is_mixin) + member.code_generator_info.set_defined_in_partial(is_partial) + member.code_generator_info.set_defined_in_mixin(is_mixin) def _propagate_extattrs_per_idl_fragment(self): def propagate_extattr(extattr_key_and_attr_name, @@ -164,14 +210,14 @@ class IdlCompiler(object): if not hasattr(ir, 'iter_all_members'): return if (only_to_members_of_partial_or_mixin - and ((hasattr(ir, 'is_partial') and ir.is_partial) or - (hasattr(ir, 'is_mixin') and ir.is_mixin))): + and not ((hasattr(ir, 'is_partial') and ir.is_partial) or + (hasattr(ir, 'is_mixin') and ir.is_mixin))): return for member in ir.iter_all_members(): apply_to(member) def process_interface_like(ir): - ir = make_copy(ir) + ir = self._maybe_make_copy(ir) self._ir_map.add(ir) propagate = functools.partial(propagate_extattr, ir=ir) @@ -207,6 +253,33 @@ class IdlCompiler(object): map(process_interface_like, old_irs) + def _determine_blink_headers(self): + irs = self._ir_map.irs_of_kinds( + IRMap.IR.Kind.INTERFACE, IRMap.IR.Kind.INTERFACE_MIXIN, + IRMap.IR.Kind.NAMESPACE, IRMap.IR.Kind.PARTIAL_INTERFACE, + IRMap.IR.Kind.PARTIAL_INTERFACE_MIXIN, + IRMap.IR.Kind.PARTIAL_NAMESPACE) + + self._ir_map.move_to_new_phase() + + for old_ir in irs: + new_ir = self._maybe_make_copy(old_ir) + self._ir_map.add(new_ir) + + if (new_ir.is_mixin and 'LegacyTreatAsPartialInterface' not in + new_ir.extended_attributes): + continue + + basepath, _ = posixpath.splitext( + new_ir.debug_info.location.filepath) + dirpath, filename = posixpath.split(basepath) + impl_class = new_ir.extended_attributes.value_of('ImplementedAs') + if impl_class: + filename = NameStyleConverter(impl_class).to_snake_case() + header = posixpath.join(dirpath, + posixpath.extsep.join([filename, 'h'])) + new_ir.code_generator_info.set_blink_headers([header]) + def _merge_partial_interface_likes(self): irs = self._ir_map.irs_of_kinds(IRMap.IR.Kind.INTERFACE, IRMap.IR.Kind.INTERFACE_MIXIN, @@ -231,7 +304,7 @@ class IdlCompiler(object): self._ir_map.move_to_new_phase() - for identifier, old_dictionary in old_dictionaries.iteritems(): + for identifier, old_dictionary in old_dictionaries.items(): new_dictionary = make_copy(old_dictionary) self._ir_map.add(new_dictionary) for partial_dictionary in old_partial_dictionaries.get( @@ -248,7 +321,7 @@ class IdlCompiler(object): self._ir_map.move_to_new_phase() for old_ir in mixins: - new_ir = make_copy(old_ir) + new_ir = self._maybe_make_copy(old_ir) self._ir_map.add(new_ir) ref_to_mixin = self._ref_to_idl_def_factory.create( new_ir.identifier) @@ -263,7 +336,7 @@ class IdlCompiler(object): ir_sets_to_merge = [(interface, [ mixins[include.mixin_identifier] for include in includes.get(identifier, []) - ]) for identifier, interface in interfaces.iteritems()] + ]) for identifier, interface in interfaces.items()] self._ir_map.move_to_new_phase() @@ -275,33 +348,56 @@ class IdlCompiler(object): self._ir_map.add(new_ir) for ir in irs_to_be_merged: to_be_merged = make_copy(ir) - new_ir.add_components(to_be_merged.components) + if new_ir.is_mixin == to_be_merged.is_mixin: + new_ir.add_components(to_be_merged.components) new_ir.debug_info.add_locations( to_be_merged.debug_info.all_locations) new_ir.attributes.extend(to_be_merged.attributes) new_ir.constants.extend(to_be_merged.constants) new_ir.operations.extend(to_be_merged.operations) - def _process_interface_inheritances(self): - def is_own_member(member): - return 'Unforgeable' in member.extended_attributes + new_ir_headers = new_ir.code_generator_info.blink_headers + to_be_merged_headers = ( + to_be_merged.code_generator_info.blink_headers) + if (new_ir_headers is not None + and to_be_merged_headers is not None): + new_ir_headers.extend(to_be_merged_headers) - def create_inheritance_stack(obj, table): + def _process_interface_inheritances(self): + def create_inheritance_chain(obj, table): if obj.inherited is None: return [obj] - return [obj] + create_inheritance_stack( + return [obj] + create_inheritance_chain( table[obj.inherited.identifier], table) + inherited_ext_attrs = ( + # (IDL extended attribute to be inherited, + # CodeGeneratorInfoMutable's set function) + ('ActiveScriptWrappable', 'set_is_active_script_wrappable'), + ('LegacyUnenumerableNamedProperties', + 'set_is_legacy_unenumerable_named_properties'), + ) + + def is_own_member(member): + return 'Unforgeable' in member.extended_attributes + old_interfaces = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE) self._ir_map.move_to_new_phase() - for old_interface in old_interfaces.itervalues(): + for old_interface in old_interfaces.values(): new_interface = make_copy(old_interface) self._ir_map.add(new_interface) - inheritance_stack = create_inheritance_stack( + inheritance_chain = create_inheritance_chain( old_interface, old_interfaces) - for interface in inheritance_stack[1:]: + + for interface in inheritance_chain: + for ext_attr, set_func in inherited_ext_attrs: + if ext_attr in interface.extended_attributes: + getattr(new_interface.code_generator_info, + set_func)(True) + + for interface in inheritance_chain[1:]: new_interface.attributes.extend([ make_copy(attribute) for attribute in interface.attributes if is_own_member(attribute) @@ -311,6 +407,28 @@ class IdlCompiler(object): if is_own_member(operation) ]) + def _copy_named_constructor_extattrs(self): + old_irs = self._ir_map.irs_of_kind(IRMap.IR.Kind.INTERFACE) + + self._ir_map.move_to_new_phase() + + def copy_extattrs(ext_attrs, ir): + if 'NamedConstructor_CallWith' in ext_attrs: + ir.extended_attributes.append( + ExtendedAttribute( + key='CallWith', + values=ext_attrs.values_of( + 'NamedConstructor_CallWith'))) + if 'NamedConstructor_RaisesException' in ext_attrs: + ir.extended_attributes.append( + ExtendedAttribute(key='RaisesException')) + + for old_ir in old_irs: + new_ir = self._maybe_make_copy(old_ir) + self._ir_map.add(new_ir) + for named_constructor_ir in new_ir.named_constructors: + copy_extattrs(new_ir.extended_attributes, named_constructor_ir) + def _group_overloaded_functions(self): old_irs = self._ir_map.irs_of_kinds(IRMap.IR.Kind.CALLBACK_INTERFACE, IRMap.IR.Kind.INTERFACE, @@ -320,8 +438,9 @@ class IdlCompiler(object): for old_ir in old_irs: assert not old_ir.constructor_groups + assert not old_ir.named_constructor_groups assert not old_ir.operation_groups - new_ir = make_copy(old_ir) + new_ir = self._maybe_make_copy(old_ir) self._ir_map.add(new_ir) sort_key = lambda x: x.identifier new_ir.constructor_groups = [ @@ -329,6 +448,12 @@ class IdlCompiler(object): for identifier, constructors in itertools.groupby( sorted(new_ir.constructors, key=sort_key), key=sort_key) ] + new_ir.named_constructor_groups = [ + ConstructorGroup.IR(constructors=list(constructors)) + for identifier, constructors in itertools.groupby( + sorted(new_ir.named_constructors, key=sort_key), + key=sort_key) + ] new_ir.operation_groups = [ OperationGroup.IR(operations=list(operations)) for identifier, operations in itertools.groupby( @@ -336,6 +461,33 @@ class IdlCompiler(object): if identifier ] + def _propagate_extattrs_to_overload_group(self): + ANY_OF = ('CrossOrigin', 'Custom', 'LenientThis', 'NotEnumerable', + 'PerWorldBindings', 'SecureContext', 'Unforgeable', + 'Unscopable') + + old_irs = self._ir_map.irs_of_kinds(IRMap.IR.Kind.INTERFACE, + IRMap.IR.Kind.NAMESPACE) + + self._ir_map.move_to_new_phase() + + for old_ir in old_irs: + new_ir = self._maybe_make_copy(old_ir) + self._ir_map.add(new_ir) + + for group in itertools.chain(new_ir.constructor_groups, + new_ir.named_constructor_groups, + new_ir.operation_groups): + for key in ANY_OF: + if any(key in overload.extended_attributes + for overload in group): + group.extended_attributes.append( + ExtendedAttribute(key=key)) + if all((overload.extended_attributes.value_of('Affects') == + 'Nothing') for overload in group): + group.extended_attributes.append( + ExtendedAttribute(key='Affects', values='Nothing')) + def _calculate_group_exposure(self): old_irs = self._ir_map.irs_of_kinds(IRMap.IR.Kind.INTERFACE, IRMap.IR.Kind.NAMESPACE) @@ -343,10 +495,12 @@ class IdlCompiler(object): self._ir_map.move_to_new_phase() for old_ir in old_irs: - new_ir = make_copy(old_ir) + new_ir = self._maybe_make_copy(old_ir) self._ir_map.add(new_ir) - for group in new_ir.constructor_groups + new_ir.operation_groups: + for group in itertools.chain(new_ir.constructor_groups, + new_ir.named_constructor_groups, + new_ir.operation_groups): exposures = map(lambda overload: overload.exposure, group) # [Exposed] @@ -393,6 +547,66 @@ class IdlCompiler(object): ])) group.exposure.set_only_in_secure_contexts(flag_names) + def _fill_exposed_constructs(self): + old_interfaces = self._ir_map.irs_of_kind(IRMap.IR.Kind.INTERFACE) + old_namespaces = self._ir_map.irs_of_kind(IRMap.IR.Kind.NAMESPACE) + + def make_legacy_window_alias(ir): + ext_attrs = ir.extended_attributes + identifier = Identifier(ext_attrs.value_of('LegacyWindowAlias')) + original = self._ref_to_idl_def_factory.create(ir.identifier) + extended_attributes = ExtendedAttributesMutable() + exposure = ExposureMutable() + if 'LegacyWindowAlias_Measure' in ext_attrs: + extended_attributes.append( + ExtendedAttribute( + key='Measure', + values=ext_attrs.value_of( + 'LegacyWindowAlias_Measure'))) + if 'LegacyWindowAlias_RuntimeEnabled' in ext_attrs: + feature_name = ext_attrs.value_of( + 'LegacyWindowAlias_RuntimeEnabled') + extended_attributes.append( + ExtendedAttribute( + key='RuntimeEnabled', values=feature_name)) + exposure.add_runtime_enabled_feature(feature_name) + return LegacyWindowAlias( + identifier=identifier, + original=original, + extended_attributes=extended_attributes, + exposure=exposure) + + exposed_map = {} # global name: [construct's identifier...] + legacy_window_aliases = [] + for ir in itertools.chain(old_interfaces, old_namespaces): + for pair in ir.exposure.global_names_and_features: + exposed_map.setdefault(pair.global_name, + []).append(ir.identifier) + if 'LegacyWindowAlias' in ir.extended_attributes: + legacy_window_aliases.append(make_legacy_window_alias(ir)) + + self._ir_map.move_to_new_phase() + + for old_ir in old_interfaces: + new_ir = self._maybe_make_copy(old_ir) + self._ir_map.add(new_ir) + + assert not new_ir.exposed_constructs + global_names = new_ir.extended_attributes.values_of('Global') + if not global_names: + continue + constructs = set() + for global_name in global_names: + constructs.update(exposed_map.get(global_name, [])) + new_ir.exposed_constructs = map( + self._ref_to_idl_def_factory.create, sorted(constructs)) + + assert not new_ir.legacy_window_aliases + if new_ir.identifier != 'Window': + continue + new_ir.legacy_window_aliases = sorted( + legacy_window_aliases, key=lambda x: x.identifier) + def _sort_dictionary_members(self): """Sorts dictionary members in alphabetical order.""" old_irs = self._ir_map.irs_of_kind(IRMap.IR.Kind.DICTIONARY) @@ -400,7 +614,7 @@ class IdlCompiler(object): self._ir_map.move_to_new_phase() for old_ir in old_irs: - new_ir = make_copy(old_ir) + new_ir = self._maybe_make_copy(old_ir) self._ir_map.add(new_ir) new_ir.own_members.sort(key=lambda x: x.identifier) @@ -455,9 +669,10 @@ class IdlCompiler(object): idl_def = StubUserDefinedType(ref.identifier) if isinstance(idl_def, UserDefinedType): idl_type = self._idl_type_factory.definition_type( - user_defined_type=idl_def) + reference_type=ref, user_defined_type=idl_def) elif isinstance(idl_def, Typedef): - idl_type = self._idl_type_factory.typedef_type(typedef=idl_def) + idl_type = self._idl_type_factory.typedef_type( + reference_type=ref, typedef=idl_def) else: assert False ref.set_target_object(idl_type) @@ -478,12 +693,20 @@ class IdlCompiler(object): Returns an unique (but meaningless) key. Returns the same key for the identical union types. """ - key_pieces = sorted([ - idl_type.syntactic_form - for idl_type in union_type.flattened_member_types - ]) - if union_type.does_include_nullable_type: - key_pieces.append('type null') # something unique + # TODO(peria, yukishiino): Produce unique union names. Trying to + # produce the names compatible to the old bindings generator for + # the time being. + key_pieces = [] + + def flatten_member_types(idl_type): + idl_type = idl_type.unwrap() + if idl_type.is_union: + for member_type in idl_type.member_types: + flatten_member_types(member_type) + else: + key_pieces.append(idl_type.syntactic_form) + + flatten_member_types(union_type) return '|'.join(key_pieces) grouped_unions = {} # {unique key: list of union types} @@ -493,16 +716,15 @@ class IdlCompiler(object): grouped_typedefs = {} # {unique key: list of typedefs to the union} all_typedefs = self._db.find_by_kind(DatabaseBody.Kind.TYPEDEF) - for typedef in all_typedefs.itervalues(): + for typedef in all_typedefs.values(): if not typedef.idl_type.is_union: continue key = unique_key(typedef.idl_type) grouped_typedefs.setdefault(key, []).append(typedef) - for key, union_types in grouped_unions.iteritems(): + for key, union_types in grouped_unions.items(): self._db.register( DatabaseBody.Kind.UNION, Union( - Identifier(key), # dummy identifier union_types=union_types, typedef_backrefs=grouped_typedefs.get(key, []))) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py index 8c63a4998bd..1d7ae802659 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py @@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import exceptions import functools from blinkbuild.name_style_converter import NameStyleConverter @@ -48,13 +47,8 @@ class IdlTypeFactory(object): def __init__(self): self._idl_types = [] # Factory to initialize instances of ReferenceType. - attrs_to_be_proxied = ( - set(RefById.get_all_attributes(IdlType)).difference( - # attributes not to be proxied - set(('debug_info', 'extended_attributes', 'is_optional', - 'optionality')))) self._ref_by_id_factory = RefByIdFactory( - target_attrs_with_priority=attrs_to_be_proxied) + target_attrs_with_priority=RefById.get_all_attributes(IdlType)) # |_is_frozen| is initially False and you can create new instances of # IdlType. The first invocation of |for_each| freezes the factory and # you can no longer create a new instance of IdlType. @@ -167,7 +161,8 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): pass_key=None): assert isinstance(is_optional, bool) assert pass_key is _IDL_TYPE_PASS_KEY - WithExtendedAttributes.__init__(self, extended_attributes) + WithExtendedAttributes.__init__( + self, extended_attributes, readonly=True) WithDebugInfo.__init__(self, debug_info) self._is_optional = is_optional @@ -182,7 +177,7 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): return not self == other def __hash__(self): - raise exceptions.NotImplementedError() + raise NotImplementedError() def make_copy(self, memo): return self @@ -192,7 +187,7 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): """ Returns a text representation of the type in the form of Web IDL syntax. """ - raise exceptions.NotImplementedError() + raise NotImplementedError() @property def type_name(self): @@ -201,7 +196,23 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): https://heycam.github.io/webidl/#dfn-type-name Note that a type name is not necessarily unique. """ - raise exceptions.NotImplementedError() + return '{}{}'.format( + self.type_name_without_extended_attributes, ''.join( + sorted(self.effective_annotations.keys()))) + + @property + def type_name_with_extended_attribute_key_values(self): + name_pieces = [] + name_pieces.append(self.type_name_without_extended_attributes) + annotations = self.effective_annotations + for key in sorted(annotations.keys()): + name_pieces.append(key) + name_pieces.extend(annotations.values_of(key)) + return ''.join(name_pieces) + + @property + def type_name_without_extended_attributes(self): + raise NotImplementedError() @property def keyword_typename(self): @@ -220,8 +231,16 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): In case of x.apply_to_all_composing_elements(callback), |callback| will be recursively called back on x, x.inner_type, x.element_type, x.result_type.original_type, etc. if any. + + If |callback| raises a StopIteration, then this function stops + traversing deeper than this type (inner type, etc.), however, siblings + are still traversed. E.g. For record<K, V>, raising a StopIteration at + K doesn't prevent from traversing V. """ - callback(self) + try: + callback(self) + except StopIteration: + return def unwrap(self, nullable=None, typedef=None, variadic=None): """ @@ -231,6 +250,7 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): Args: nullable: typedef: + variadic: All these arguments take tri-state value: True, False, or None. True unwraps that type, False stops unwrapping that type. All of specified arguments' values must be consistent, and mixture @@ -245,25 +265,51 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): } value_counts = {None: 0, False: 0, True: 0} - for value in switches.itervalues(): + for value in switches.values(): assert value is None or isinstance(value, bool) value_counts[value] += 1 assert value_counts[False] == 0 or value_counts[True] == 0, ( "Specify only True or False arguments. Unspecified arguments are " "automatically set to the opposite value.") default = value_counts[True] == 0 - for arg, value in switches.iteritems(): + for arg, value in switches.items(): if value is None: switches[arg] = default return self._unwrap(switches) @property + def effective_annotations(self): + """ + Returns the extended attributes associated with this IDL type. + https://heycam.github.io/webidl/#idl-type-extended-attribute-associated-with + + For example, given the following IDL fragments, + + typedef [ExtAttr1] long NewLong; + void f([ExtAttr2] NewLong arg); + + arg.idl_type.extended_attributes returns [ExtAttr2], + arg.idl_type.unwrap().extended_attributes returns [ExtAttr1], and + arg.idl_type.effective_annotations returns [ExtAttr1, ExtAttr2]. + """ + return self.extended_attributes + + @property def does_include_nullable_type(self): """ - Returns True if |self| includes a nulllable type. + Returns True if this type includes a nulllable type. https://heycam.github.io/webidl/#dfn-includes-a-nullable-type - @return bool + """ + return False + + @property + def does_include_nullable_or_dict(self): + """ + Returns True if this type includes a nullable type or a dictionary type. + + IdlType's own definition of "includes a dictionary type" just follows + the definition of "includes a nullable type". """ return False @@ -307,6 +353,11 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): return False @property + def is_array_buffer_view(self): + """Returns True if this is ArrayBufferView.""" + return False + + @property def is_data_view(self): """Returns True if this is DataView.""" return False @@ -414,11 +465,6 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): return False @property - def is_annotated(self): - """Returns True if this is annotated.""" - return bool(self.extended_attributes) - - @property def is_optional(self): """ Returns True if this type is used for a non-required dictionary member @@ -506,6 +552,15 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): """ return None + @property + def union_definition_object(self): + """ + Returns an object that represents an union or None. + + Note that a returned object is not an IdlType. It's of type Union. + """ + return None + def _format_syntactic_form(self, syntactic_form_inner): """Helper function to implement |syntactic_form|.""" optional_form = 'optional ' if self.is_optional else '' @@ -514,11 +569,6 @@ class IdlType(WithExtendedAttributes, WithDebugInfo): return '{}{}{}'.format(optional_form, ext_attr_form, syntactic_form_inner) - def _format_type_name(self, type_name_inner): - """Helper function to implement |type_name|.""" - return '{}{}'.format(type_name_inner, ''.join( - sorted(self.extended_attributes.keys()))) - def _unwrap(self, switches): return self @@ -539,7 +589,17 @@ class SimpleType(IdlType): _TYPED_ARRAY_TYPES = ('Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Uint8ClampedArray', 'Float32Array', 'Float64Array') - _BUFFER_SOURCE_TYPES = ('ArrayBuffer', 'DataView') + _TYPED_ARRAY_TYPES + # ArrayBufferView is not defined as a buffer source type in Web IDL, it's + # defined as an union type of all typed array types. However, practically + # it's much more convenient and reasonable for most of (if not all) use + # cases to treat ArrayBufferView as a buffer source type than as an union + # type. + # https://heycam.github.io/webidl/#ArrayBufferView + # + # Note that BufferSource is an union type as defined in Web IDL. + # https://heycam.github.io/webidl/#BufferSource + _BUFFER_SOURCE_TYPES = ( + ('ArrayBuffer', 'ArrayBufferView', 'DataView') + _TYPED_ARRAY_TYPES) _MISC_TYPES = ('any', 'boolean', 'object', 'symbol', 'void') _VALID_TYPES = set(_NUMERIC_TYPES + _STRING_TYPES + _BUFFER_SOURCE_TYPES + _MISC_TYPES) @@ -567,16 +627,14 @@ class SimpleType(IdlType): def __hash__(self): return hash(self._name) - # IdlType overrides @property def syntactic_form(self): return self._format_syntactic_form(self._name) @property - def type_name(self): + def type_name_without_extended_attributes(self): name = 'String' if self._name == 'DOMString' else self._name - return self._format_type_name( - NameStyleConverter(name).to_upper_camel_case()) + return NameStyleConverter(name).to_upper_camel_case() @property def keyword_typename(self): @@ -611,6 +669,10 @@ class SimpleType(IdlType): return self._name == 'ArrayBuffer' @property + def is_array_buffer_view(self): + return self._name == 'ArrayBufferView' + + @property def is_data_view(self): return self._name == 'DataView' @@ -672,6 +734,9 @@ class ReferenceType(IdlType, RefById): def __hash__(self): return hash(self.identifier) + def _unwrap(self, switches): + return self.target_object._unwrap(switches) + class DefinitionType(IdlType, WithIdentifier): """ @@ -682,14 +747,14 @@ class DefinitionType(IdlType, WithIdentifier): TypedefType and UnionType respectively. """ - def __init__(self, - user_defined_type, - debug_info=None, - pass_key=None): + def __init__(self, reference_type, user_defined_type, pass_key=None): + assert isinstance(reference_type, ReferenceType) assert isinstance(user_defined_type, UserDefinedType) IdlType.__init__( self, - debug_info=debug_info, + is_optional=reference_type.is_optional, + extended_attributes=reference_type.extended_attributes, + debug_info=reference_type.debug_info, pass_key=pass_key) WithIdentifier.__init__(self, user_defined_type.identifier) self._type_definition_object = user_defined_type @@ -701,20 +766,19 @@ class DefinitionType(IdlType, WithIdentifier): def __hash__(self): return hash(self.identifier) - # IdlType overrides @property def syntactic_form(self): - assert not self.extended_attributes - assert not self.is_optional - return self.identifier + return self._format_syntactic_form(self.identifier) @property - def type_name(self): - assert not self.extended_attributes - assert not self.is_optional + def type_name_without_extended_attributes(self): return self.identifier @property + def does_include_nullable_or_dict(self): + return self.is_dictionary + + @property def is_interface(self): return self.type_definition_object.is_interface @@ -750,14 +814,14 @@ class TypedefType(IdlType, WithIdentifier): can track down the typedef'ed type to |original_type|. """ - def __init__(self, - typedef, - debug_info=None, - pass_key=None): + def __init__(self, reference_type, typedef, pass_key=None): + assert isinstance(reference_type, ReferenceType) assert isinstance(typedef, Typedef) IdlType.__init__( self, - debug_info=debug_info, + is_optional=reference_type.is_optional, + extended_attributes=reference_type.extended_attributes, + debug_info=reference_type.debug_info, pass_key=pass_key) WithIdentifier.__init__(self, typedef.identifier) self._typedef = typedef @@ -769,28 +833,40 @@ class TypedefType(IdlType, WithIdentifier): def __hash__(self): return hash(self.identifier) - # IdlType overrides @property def syntactic_form(self): - assert not self.extended_attributes - assert not self.is_optional - return self.identifier + return self._format_syntactic_form(self.identifier) @property - def type_name(self): - assert not self.extended_attributes - assert not self.is_optional - return self.original_type.type_name + def type_name_without_extended_attributes(self): + return self.original_type.type_name_without_extended_attributes def apply_to_all_composing_elements(self, callback): - callback(self) + try: + callback(self) + except StopIteration: + return self.original_type.apply_to_all_composing_elements(callback) @property + def effective_annotations(self): + original_annotations = self.original_type.effective_annotations + if not self.extended_attributes: + return original_annotations + if not original_annotations: + return self.extended_attributes + return ExtendedAttributes( + list(self.extended_attributes) + list(original_annotations)) + + @property def does_include_nullable_type(self): return self.original_type.does_include_nullable_type @property + def does_include_nullable_or_dict(self): + return self.original_type.does_include_nullable_or_dict + + @property def is_typedef(self): return True @@ -827,9 +903,11 @@ class _ArrayLikeType(IdlType): def __hash__(self): return hash((self.__class__, self.element_type)) - # IdlType overrides def apply_to_all_composing_elements(self, callback): - callback(self) + try: + callback(self) + except StopIteration: + return self.element_type.apply_to_all_composing_elements(callback) @property @@ -854,16 +932,14 @@ class SequenceType(_ArrayLikeType): debug_info=debug_info, pass_key=pass_key) - # IdlType overrides @property def syntactic_form(self): return self._format_syntactic_form('sequence<{}>'.format( self.element_type.syntactic_form)) @property - def type_name(self): - return self._format_type_name('{}Sequence'.format( - self.element_type.type_name)) + def type_name_without_extended_attributes(self): + return '{}Sequence'.format(self.element_type.type_name) @property def is_sequence(self): @@ -887,16 +963,14 @@ class FrozenArrayType(_ArrayLikeType): debug_info=debug_info, pass_key=pass_key) - # IdlType overrides @property def syntactic_form(self): return self._format_syntactic_form('FrozenArray<{}>'.format( self.element_type.syntactic_form)) @property - def type_name(self): - return self._format_type_name('{}Array'.format( - self.element_type.type_name)) + def type_name_without_extended_attributes(self): + return '{}Array'.format(self.element_type.type_name) @property def is_frozen_array(self): @@ -906,17 +980,10 @@ class FrozenArrayType(_ArrayLikeType): class VariadicType(_ArrayLikeType): """Represents a type used for variadic arguments.""" - def __init__(self, - element_type, - debug_info=None, - pass_key=None): + def __init__(self, element_type, debug_info=None, pass_key=None): _ArrayLikeType.__init__( - self, - element_type, - debug_info=debug_info, - pass_key=pass_key) + self, element_type, debug_info=debug_info, pass_key=pass_key) - # IdlType overrides @property def syntactic_form(self): assert not self.extended_attributes @@ -924,10 +991,11 @@ class VariadicType(_ArrayLikeType): return '{}...'.format(self.element_type.syntactic_form) @property - def type_name(self): + def type_name_without_extended_attributes(self): # Blink-specific expansion of type name # The type name of a variadic type is the concatenation of the type # name of the element type and the string "Variadic". + assert not self.extended_attributes return '{}Variadic'.format(self.element_type.type_name) @property @@ -968,19 +1036,21 @@ class RecordType(IdlType): def __hash__(self): return hash((self.__class__, self.key_type, self.value_type)) - # IdlType overrides @property def syntactic_form(self): return self._format_syntactic_form('record<{}, {}>'.format( self.key_type.syntactic_form, self.value_type.syntactic_form)) @property - def type_name(self): - return self._format_type_name('{}{}Record'.format( - self.key_type.type_name, self.value_type.type_name)) + def type_name_without_extended_attributes(self): + return '{}{}Record'.format(self.key_type.type_name, + self.value_type.type_name) def apply_to_all_composing_elements(self, callback): - callback(self) + try: + callback(self) + except StopIteration: + return self.key_type.apply_to_all_composing_elements(callback) self.value_type.apply_to_all_composing_elements(callback) @@ -1022,19 +1092,20 @@ class PromiseType(IdlType): def __hash__(self): return hash((self.__class__, self.result_type)) - # IdlType overrides @property def syntactic_form(self): return self._format_syntactic_form('Promise<{}>'.format( self.result_type.syntactic_form)) @property - def type_name(self): - return self._format_type_name('{}Promise'.format( - self.result_type.type_name)) + def type_name_without_extended_attributes(self): + return '{}Promise'.format(self.result_type.type_name) def apply_to_all_composing_elements(self, callback): - callback(self) + try: + callback(self) + except StopIteration: + return self.result_type.apply_to_all_composing_elements(callback) @property @@ -1043,10 +1114,7 @@ class PromiseType(IdlType): @property def result_type(self): - """ - Returns the result type. - @return IdlType - """ + """Returns the result type.""" return self._result_type @@ -1068,6 +1136,7 @@ class UnionType(IdlType): debug_info=debug_info, pass_key=pass_key) self._member_types = tuple(member_types) + self._union_definition_object = None def __eq__(self, other): """ @@ -1089,19 +1158,20 @@ class UnionType(IdlType): functools.reduce(lambda x, idl_type: x + hash(idl_type), self.member_types, 0))) - # IdlType overrides @property def syntactic_form(self): return self._format_syntactic_form('({})'.format(' or '.join( [member.syntactic_form for member in self.member_types]))) @property - def type_name(self): - return self._format_type_name('Or'.join( - [member.type_name for member in self.member_types])) + def type_name_without_extended_attributes(self): + return 'Or'.join([member.type_name for member in self.member_types]) def apply_to_all_composing_elements(self, callback): - callback(self) + try: + callback(self) + except StopIteration: + return for member_type in self.member_types: member_type.apply_to_all_composing_elements(callback) @@ -1111,6 +1181,11 @@ class UnionType(IdlType): member.does_include_nullable_type for member in self.member_types) @property + def does_include_nullable_or_dict(self): + return any(member.does_include_nullable_or_dict + for member in self.member_types) + + @property def is_union(self): return True @@ -1134,6 +1209,17 @@ class UnionType(IdlType): return set(flatten(self)) + @property + def union_definition_object(self): + return self._union_definition_object + + def set_union_definition_object(self, union_definition_object): + # In Python2, we need to avoid circular imports. + from .union import Union + assert isinstance(union_definition_object, Union) + assert self._union_definition_object is None + self._union_definition_object = union_definition_object + class NullableType(IdlType): """https://heycam.github.io/webidl/#idl-nullable-type""" @@ -1160,35 +1246,44 @@ class NullableType(IdlType): def __hash__(self): return hash((self.__class__, self.inner_type)) - # IdlType overrides @property def syntactic_form(self): assert not self.extended_attributes return '{}?'.format(self.inner_type.syntactic_form) @property - def type_name(self): - assert not self.extended_attributes + def type_name_without_extended_attributes(self): # https://heycam.github.io/webidl/#idl-annotated-types # Web IDL seems not supposing a case of [X] ([Y] Type)?, i.e. something # like [X] nullable<[Y] Type>, which should turn into "TypeYOrNullX". # # In case of '[Clamp] long?', it's interpreted as '([Clamp] long)?' but # the type name must be "LongOrNullClamp" instead of "LongClampOrNull". - name = self.inner_type.type_name - ext_attrs = ''.join(sorted(self.inner_type.extended_attributes.keys())) - sep_index = len(name) - len(ext_attrs) - return '{}OrNull{}'.format(name[0:sep_index], name[sep_index:]) + assert not self.extended_attributes + return '{}OrNull'.format( + self.inner_type.type_name_without_extended_attributes) def apply_to_all_composing_elements(self, callback): - callback(self) + try: + callback(self) + except StopIteration: + return self.inner_type.apply_to_all_composing_elements(callback) @property + def effective_annotations(self): + assert not self.extended_attributes + return self.inner_type.effective_annotations + + @property def does_include_nullable_type(self): return True @property + def does_include_nullable_or_dict(self): + return True + + @property def is_nullable(self): return True diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type_test.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type_test.py index b8e71989991..b3d097a7442 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type_test.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/idl_type_test.py @@ -54,7 +54,7 @@ class IdlTypesTest(unittest.TestCase): ext_attrs = ExtendedAttributes([ExtendedAttribute('Clamp')]) annotated_type = factory.simple_type( 'short', extended_attributes=ext_attrs) - self.assertTrue(annotated_type.is_annotated) + self.assertTrue(annotated_type.extended_attributes) self.assertTrue(annotated_type.is_numeric) optional_type = factory.simple_type('DOMString', is_optional=True) @@ -63,7 +63,7 @@ class IdlTypesTest(unittest.TestCase): annotated_optional = factory.simple_type( 'long', is_optional=True, extended_attributes=ext_attrs) - self.assertTrue(annotated_optional.is_annotated) + self.assertTrue(annotated_optional.extended_attributes) self.assertTrue(annotated_optional.is_optional) self.assertTrue(annotated_optional.is_numeric) @@ -83,7 +83,7 @@ class IdlTypesTest(unittest.TestCase): 'void': 'Void', 'symbol': 'Symbol', } - for name, expect in type_names.iteritems(): + for name, expect in type_names.items(): self.assertEqual(expect, factory.simple_type(name).type_name) short_type = factory.simple_type('short') diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py index f3f81408a0e..ae67aab3fc9 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/interface.py @@ -9,6 +9,7 @@ from .composition_parts import WithComponent from .composition_parts import WithDebugInfo from .composition_parts import WithExposure from .composition_parts import WithExtendedAttributes +from .composition_parts import WithIdentifier from .composition_parts import WithOwner from .constant import Constant from .constructor import Constructor @@ -37,7 +38,9 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, attributes=None, constants=None, constructors=None, + named_constructors=None, operations=None, + indexed_and_named_properties=None, stringifier=None, iterable=None, maplike=None, @@ -52,7 +55,11 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, assert constants is None or isinstance(constants, (list, tuple)) assert constructors is None or isinstance(constructors, (list, tuple)) + assert named_constructors is None or isinstance( + named_constructors, (list, tuple)) assert operations is None or isinstance(operations, (list, tuple)) + assert indexed_and_named_properties is None or isinstance( + indexed_and_named_properties, IndexedAndNamedProperties.IR) assert stringifier is None or isinstance(stringifier, Stringifier.IR) assert iterable is None or isinstance(iterable, Iterable) @@ -62,6 +69,7 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, attributes = attributes or [] constants = constants or [] constructors = constructors or [] + named_constructors = named_constructors or [] operations = operations or [] assert all( isinstance(attribute, Attribute.IR) @@ -72,6 +80,9 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, isinstance(constructor, Constructor.IR) for constructor in constructors) assert all( + isinstance(named_constructor, Constructor.IR) + for named_constructor in named_constructors) + assert all( isinstance(operation, Operation.IR) for operation in operations) @@ -100,8 +111,13 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, self.constants = list(constants) self.constructors = list(constructors) self.constructor_groups = [] + self.named_constructors = list(named_constructors) + self.named_constructor_groups = [] self.operations = list(operations) self.operation_groups = [] + self.exposed_constructs = [] + self.legacy_window_aliases = [] + self.indexed_and_named_properties = indexed_and_named_properties self.stringifier = stringifier self.iterable = iterable self.maplike = maplike @@ -114,6 +130,8 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, yield constant for constructor in self.constructors: yield constructor + for named_constructor in self.named_constructors: + yield named_constructor for operation in self.operations: yield operation @@ -123,7 +141,7 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, ir = make_copy(ir) UserDefinedType.__init__(self, ir.identifier) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithComponent.__init__(self, ir, readonly=True) @@ -144,24 +162,43 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, ]) self._constructor_groups = tuple([ ConstructorGroup( - constructor_group_ir, - filter( - lambda x: x.identifier == constructor_group_ir.identifier, - self._constructors), - owner=self) for constructor_group_ir in ir.constructor_groups + group_ir, + filter(lambda x: x.identifier == group_ir.identifier, + self._constructors), + owner=self) for group_ir in ir.constructor_groups ]) assert len(self._constructor_groups) <= 1 + self._named_constructors = tuple([ + Constructor(named_constructor_ir, owner=self) + for named_constructor_ir in ir.named_constructors + ]) + self._named_constructor_groups = tuple([ + ConstructorGroup( + group_ir, + filter(lambda x: x.identifier == group_ir.identifier, + self._named_constructors), + owner=self) for group_ir in ir.named_constructor_groups + ]) self._operations = tuple([ Operation(operation_ir, owner=self) for operation_ir in ir.operations ]) self._operation_groups = tuple([ OperationGroup( - operation_group_ir, - filter(lambda x: x.identifier == operation_group_ir.identifier, + group_ir, + filter(lambda x: x.identifier == group_ir.identifier, self._operations), - owner=self) for operation_group_ir in ir.operation_groups + owner=self) for group_ir in ir.operation_groups ]) + self._exposed_constructs = tuple(ir.exposed_constructs) + self._legacy_window_aliases = tuple(ir.legacy_window_aliases) + self._indexed_and_named_properties = None + if ir.indexed_and_named_properties: + operations = filter( + lambda x: x.is_indexed_or_named_property_operation, + self._operations) + self._indexed_and_named_properties = IndexedAndNamedProperties( + ir.indexed_and_named_properties, operations, owner=self) self._stringifier = None if ir.stringifier: operations = filter(lambda x: x.is_stringifier, self._operations) @@ -205,6 +242,17 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, interface = interface.inherited return result + def does_implement(self, identifier): + """ + Returns True if this is or inherits from the given interface. + """ + assert isinstance(identifier, str) + + for interface in self.inclusive_inherited_interfaces: + if interface.identifier == identifier: + return True + return False + @property def attributes(self): """ @@ -232,6 +280,16 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, return self._constructor_groups @property + def named_constructors(self): + """Returns named constructors.""" + return self._named_constructors + + @property + def named_constructor_groups(self): + """Returns groups of overloaded named constructors.""" + return self._named_constructor_groups + + @property def operations(self): """ Returns all operations, including special operations without an @@ -254,38 +312,22 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, return self._operation_groups @property - def named_constructor(self): - """Returns a named constructor or None.""" - assert False, "Not implemented yet." - - @property - def exposed_interfaces(self): + def exposed_constructs(self): """ - Returns a tuple of interfaces that are exposed to this interface, if - this is a global interface. Returns None otherwise. + Returns a list of the constructs that are exposed on this global object. """ - assert False, "Not implemented yet." + return tuple( + map(lambda ref: ref.target_object, self._exposed_constructs)) - # Special operations @property - def indexed_property_handler(self): - """ - Returns a set of handlers (getter/setter/deleter) for the indexed - property. - @return IndexedPropertyHandler? - """ - # TODO: Include anonymous handlers of ancestors. https://crbug.com/695972 - assert False, "Not implemented yet." + def legacy_window_aliases(self): + """Returns a list of properties exposed as [LegacyWindowAlias].""" + return self._legacy_window_aliases @property - def named_property_handler(self): - """ - Returns a set of handlers (getter/setter/deleter) for the named - property. - @return NamedPropertyHandler? - """ - # TODO: Include anonymous handlers of ancestors. https://crbug.com/695972 - assert False, "Not implemented yet." + def indexed_and_named_properties(self): + """Returns a IndexedAndNamedProperties or None.""" + return self._indexed_and_named_properties @property def stringifier(self): @@ -313,6 +355,183 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, return True +class LegacyWindowAlias(WithIdentifier, WithExtendedAttributes, WithExposure): + """ + Represents a property exposed on a Window object as [LegacyWindowAlias]. + """ + + def __init__(self, identifier, original, extended_attributes, exposure): + assert isinstance(original, RefById) + + WithIdentifier.__init__(self, identifier) + WithExtendedAttributes.__init__( + self, extended_attributes, readonly=True) + WithExposure.__init__(self, exposure, readonly=True) + + self._original = original + + @property + def original(self): + """Returns the original object of this alias.""" + return self._original.target_object + + +class IndexedAndNamedProperties(WithOwner, WithDebugInfo): + """ + Represents a set of indexed/named getter/setter/deleter. + + https://heycam.github.io/webidl/#idl-indexed-properties + https://heycam.github.io/webidl/#idl-named-properties + """ + + class IR(WithDebugInfo): + def __init__(self, operations, debug_info=None): + assert isinstance(operations, (list, tuple)) + assert all( + isinstance(operation, Operation.IR) + for operation in operations) + + WithDebugInfo.__init__(self, debug_info) + + self.indexed_getter = None + self.indexed_setter = None + self.named_getter = None + self.named_setter = None + self.named_deleter = None + + for operation in operations: + arg1_type = operation.arguments[0].idl_type + if arg1_type.is_integer: + if operation.is_getter: + assert self.indexed_getter is None + self.indexed_getter = operation + elif operation.is_setter: + assert self.indexed_setter is None + self.indexed_setter = operation + else: + assert False + elif arg1_type.is_string: + if operation.is_getter: + assert self.named_getter is None + self.named_getter = operation + elif operation.is_setter: + assert self.named_setter is None + self.named_setter = operation + elif operation.is_deleter: + assert self.named_deleter is None + self.named_deleter = operation + else: + assert False + else: + assert False + + def __init__(self, ir, operations, owner): + assert isinstance(ir, IndexedAndNamedProperties.IR) + assert isinstance(operations, (list, tuple)) + assert all( + isinstance(operation, Operation) for operation in operations) + + WithOwner.__init__(self, owner) + WithDebugInfo.__init__(self, ir) + + self._own_indexed_getter = None + self._own_indexed_setter = None + self._own_named_getter = None + self._own_named_setter = None + self._own_named_deleter = None + + for operation in operations: + arg1_type = operation.arguments[0].idl_type + if arg1_type.is_integer: + if operation.is_getter: + assert self._own_indexed_getter is None + self._own_indexed_getter = operation + elif operation.is_setter: + assert self._own_indexed_setter is None + self._own_indexed_setter = operation + else: + assert False + elif arg1_type.is_string: + if operation.is_getter: + assert self._own_named_getter is None + self._own_named_getter = operation + elif operation.is_setter: + assert self._own_named_setter is None + self._own_named_setter = operation + elif operation.is_deleter: + assert self._own_named_deleter is None + self._own_named_deleter = operation + else: + assert False + else: + assert False + + @property + def has_indexed_properties(self): + return self.indexed_getter or self.indexed_setter + + @property + def has_named_properties(self): + return self.named_getter or self.named_setter or self.named_deleter + + @property + def is_named_property_enumerable(self): + named_getter = self.named_getter + return bool(named_getter + and 'NotEnumerable' not in named_getter.extended_attributes + and 'LegacyUnenumerableNamedProperties' not in self.owner. + extended_attributes) + + @property + def indexed_getter(self): + return self._find_accessor('own_indexed_getter') + + @property + def indexed_setter(self): + return self._find_accessor('own_indexed_setter') + + @property + def named_getter(self): + return self._find_accessor('own_named_getter') + + @property + def named_setter(self): + return self._find_accessor('own_named_setter') + + @property + def named_deleter(self): + return self._find_accessor('own_named_deleter') + + @property + def own_indexed_getter(self): + return self._own_indexed_getter + + @property + def own_indexed_setter(self): + return self._own_indexed_setter + + @property + def own_named_getter(self): + return self._own_named_getter + + @property + def own_named_setter(self): + return self._own_named_setter + + @property + def own_named_deleter(self): + return self._own_named_deleter + + def _find_accessor(self, attr): + for interface in self.owner.inclusive_inherited_interfaces: + props = interface.indexed_and_named_properties + if props: + accessor = getattr(props, attr) + if accessor: + return accessor + return None + + class Stringifier(WithOwner, WithDebugInfo): """https://heycam.github.io/webidl/#idl-stringifiers""" @@ -349,10 +568,7 @@ class Stringifier(WithOwner, WithDebugInfo): class Iterable(WithDebugInfo): """https://heycam.github.io/webidl/#idl-iterable""" - def __init__(self, - key_type=None, - value_type=None, - debug_info=None): + def __init__(self, key_type=None, value_type=None, debug_info=None): assert key_type is None or isinstance(key_type, IdlType) # iterable is declared in either form of # iterable<value_type> @@ -423,10 +639,7 @@ class Maplike(WithDebugInfo): class Setlike(WithDebugInfo): """https://heycam.github.io/webidl/#idl-setlike""" - def __init__(self, - value_type, - is_readonly=False, - debug_info=None): + def __init__(self, value_type, is_readonly=False, debug_info=None): assert isinstance(value_type, IdlType) assert isinstance(is_readonly, bool) @@ -450,55 +663,3 @@ class Setlike(WithDebugInfo): @return bool """ return self._is_readonly - - -class IndexedPropertyHandler(object): - @property - def getter(self): - """ - Returns an Operation for indexed property getter. - @return Operation? - """ - assert False, "Not implemented yet." - - @property - def setter(self): - """ - Returns an Operation for indexed property setter. - @return Operation? - """ - assert False, "Not implemented yet." - - @property - def deleter(self): - """ - Returns an Operation for indexed property deleter. - @return Operation? - """ - assert False, "Not implemented yet." - - -class NamedPropertyHandler(object): - @property - def getter(self): - """ - Returns an Operation for named property getter. - @return Operation? - """ - assert False, "Not implemented yet." - - @property - def setter(self): - """ - Returns an Operation for named property setter. - @return Operation? - """ - assert False, "Not implemented yet." - - @property - def deleter(self): - """ - Returns an Operation for named property deleter. - @return Operation? - """ - assert False, "Not implemented yet." diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py index bc69ffff13e..5f2fe5f13aa 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py @@ -20,6 +20,7 @@ from .extended_attribute import ExtendedAttribute from .extended_attribute import ExtendedAttributes from .idl_type import IdlTypeFactory from .includes import Includes +from .interface import IndexedAndNamedProperties from .interface import Interface from .interface import Iterable from .interface import Maplike @@ -114,6 +115,7 @@ class _IRBuilder(object): constants = [] constructors = [] operations = [] + indexed_and_named_property_operations = [] for member in members: if isinstance(member, Attribute.IR): attributes.append(member) @@ -122,16 +124,24 @@ class _IRBuilder(object): elif isinstance(member, Constructor.IR): constructors.append(member) elif isinstance(member, Operation.IR): - if member.identifier: - operations.append(member) + operations.append(member) + if member.is_getter or member.is_setter or member.is_deleter: + indexed_and_named_property_operations.append(member) else: assert False + named_constructors = self._build_named_constructors(node) + + indexed_and_named_properties = None + if indexed_and_named_property_operations: + indexed_and_named_properties = IndexedAndNamedProperties.IR( + indexed_and_named_property_operations, + self._build_debug_info(node)) + if stringifier: operations.append(stringifier.operation) if stringifier.attribute: attributes.append(stringifier.attribute) - # TODO(peria): Create indexed/named property handlers from |operations|. return Interface.IR( identifier=identifier, @@ -141,7 +151,9 @@ class _IRBuilder(object): attributes=attributes, constants=constants, constructors=constructors, + named_constructors=named_constructors, operations=operations, + indexed_and_named_properties=indexed_and_named_properties, stringifier=stringifier, iterable=iterable, maplike=maplike, @@ -189,7 +201,7 @@ class _IRBuilder(object): idl_type = self._take_type(child_nodes) extended_attributes = self._take_extended_attributes( child_nodes) or fallback_extended_attributes - assert len(child_nodes) == 0 + assert not child_nodes return Attribute.IR( identifier=Identifier(node.GetName()), idl_type=idl_type, @@ -223,10 +235,11 @@ class _IRBuilder(object): arguments = self._take_arguments(child_nodes) extended_attributes = self._take_extended_attributes( child_nodes) or fallback_extended_attributes - assert len(child_nodes) == 0 + assert not child_nodes return_type = self._idl_type_factory.reference_type( interface_identifier) return Constructor.IR( + identifier=None, arguments=arguments, return_type=return_type, extended_attributes=extended_attributes, @@ -239,12 +252,15 @@ class _IRBuilder(object): return_type = self._take_type(child_nodes) extended_attributes = self._take_extended_attributes( child_nodes) or fallback_extended_attributes - assert len(child_nodes) == 0 + assert not child_nodes return Operation.IR( identifier=Identifier(node.GetName()), arguments=arguments, return_type=return_type, is_static=bool(node.GetProperty('STATIC')), + is_getter=bool(node.GetProperty('GETTER')), + is_setter=bool(node.GetProperty('SETTER')), + is_deleter=bool(node.GetProperty('DELETER')), extended_attributes=extended_attributes, component=self._component, debug_info=self._build_debug_info(node)) @@ -257,6 +273,37 @@ class _IRBuilder(object): } return build_functions[node.GetClass()](node) + def _build_named_constructors(self, node): + assert node.GetClass() == 'Interface' + named_constructors = [] + + for child in node.GetChildren(): + if child.GetClass() == 'ExtAttributes': + interface_ext_attrs = child.GetChildren() + break + else: + return named_constructors + + for ext_attr in interface_ext_attrs: + if ext_attr.GetName() != 'NamedConstructor': + continue + call_node = ext_attr.GetChildren()[0] + assert call_node.GetClass() == 'Call' + child_nodes = list(call_node.GetChildren()) + arguments = self._take_arguments(child_nodes) + return_type = self._idl_type_factory.reference_type( + Identifier(node.GetName())) + assert not child_nodes + named_constructors.append( + Constructor.IR( + identifier=Identifier(call_node.GetName()), + arguments=arguments, + return_type=return_type, + component=self._component, + debug_info=self._build_debug_info(node))) + + return named_constructors + def _build_dictionary(self, node): child_nodes = list(node.GetChildren()) inherited = self._take_inheritance(child_nodes) @@ -280,7 +327,7 @@ class _IRBuilder(object): idl_type = self._take_type(child_nodes, is_optional=(not is_required)) default_value = self._take_default_value(child_nodes) extended_attributes = self._take_extended_attributes(child_nodes) - assert len(child_nodes) == 0 + assert not child_nodes return DictionaryMember.IR( identifier=Identifier(node.GetName()), @@ -319,7 +366,7 @@ class _IRBuilder(object): arguments = self._take_arguments(child_nodes) return_type = self._take_type(child_nodes) extended_attributes = self._take_extended_attributes(child_nodes) - assert len(child_nodes) == 0 + assert not child_nodes return CallbackFunction.IR( identifier=Identifier(node.GetName()), arguments=arguments, @@ -343,7 +390,7 @@ class _IRBuilder(object): def _build_typedef(self, node): child_nodes = list(node.GetChildren()) idl_type = self._take_type(child_nodes) - assert len(child_nodes) == 0 + assert not child_nodes return Typedef.IR( identifier=Identifier(node.GetName()), @@ -375,7 +422,7 @@ class _IRBuilder(object): is_variadic=is_variadic, extended_attributes=extended_attributes) default_value = self._take_default_value(child_nodes) - assert len(child_nodes) == 0 + assert not child_nodes return Argument.IR( identifier=Identifier(node.GetName()), index=index, @@ -408,21 +455,27 @@ class _IRBuilder(object): key = node.GetName() values = node.GetProperty('VALUE', default=None) arguments = None - - # Drop constructors as they do not fit in ExtendedAttribute which - # doesn't support IdlType. - if key in ('Constructor', 'CustomConstructor', 'NamedConstructor'): - return None + name = None child_nodes = node.GetChildren() if child_nodes: assert len(child_nodes) == 1 - assert child_nodes[0].GetClass() == 'Arguments' - arguments = map(build_extattr_argument, - child_nodes[0].GetChildren()) + child = child_nodes[0] + if child.GetClass() == 'Arguments': + arguments = map(build_extattr_argument, + child.GetChildren()) + elif child.GetClass() == 'Call': + assert len(child.GetChildren()) == 1 + grand_child = child.GetChildren()[0] + assert grand_child.GetClass() == 'Arguments' + # ExtendedAttribute is not designed to represent an + # operation, especially a complicated argument list. + # Discard the arguments. + arguments = () + name = child.GetName() return ExtendedAttribute( - key=key, values=values, arguments=arguments) + key=key, values=values, arguments=arguments, name=name) def build_extattr_argument(node): assert node.GetClass() == 'Argument' @@ -469,7 +522,7 @@ class _IRBuilder(object): debug_info=self._build_debug_info(node)) def _build_literal_constant(self, node): - assert len(node.GetChildren()) == 0 + assert not node.GetChildren() type_token = node.GetProperty('TYPE') value_token = node.GetProperty('VALUE') @@ -523,7 +576,7 @@ class _IRBuilder(object): value = dict() literal = '{}' else: - assert False, 'Unknown literal type: {}'.format(type_token) + assert False, "Unknown literal type: {}".format(type_token) return LiteralConstant(idl_type=idl_type, value=value, literal=literal) @@ -688,6 +741,7 @@ class _IRBuilder(object): buffer_source_types = set([ 'ArrayBuffer', + 'ArrayBufferView', # Blink-specific ArrayBufferView definition 'DataView', 'Int8Array', 'Int16Array', diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_map.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_map.py index 4651900f8a6..91806523243 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_map.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/ir_map.py @@ -190,11 +190,11 @@ class IRMap(object): """Returns a flattened list of IRs of the given kind.""" if IRMap.IR.Kind.does_support_multiple_defs(kind): accumulated = [] - for irs in self.find_by_kind(kind).itervalues(): + for irs in self.find_by_kind(kind).values(): accumulated.extend(irs) return accumulated else: - return self.find_by_kind(kind).itervalues() + return list(self.find_by_kind(kind).values()) def irs_of_kinds(self, *kinds): """ diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py index b9a22ebfaaf..a7a2b11f3f0 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py @@ -48,11 +48,11 @@ def make_copy(obj, memo=None): if isinstance(obj, dict): return memoize( cls([(make_copy(key, memo), make_copy(value, memo)) - for key, value in obj.iteritems()])) + for key, value in obj.items()])) if hasattr(obj, '__dict__'): copy = memoize(cls.__new__(cls)) - for name, value in obj.__dict__.iteritems(): + for name, value in obj.__dict__.items(): setattr(copy, name, make_copy(value, memo)) return copy diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/migration_adapter.idl b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/migration_adapter.idl index 38eacc2cfdf..7ede71f3a06 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/migration_adapter.idl +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/migration_adapter.idl @@ -8,10 +8,6 @@ // and the *.idl files get updated to be spec conformant, almost all (if not // really all) the followings will be gone. -typedef object SerializedScriptValue; - -typedef object? Dictionary; - typedef EventHandlerNonNull? EventHandler; typedef DOMMatrix DOMMatrixConstructor; diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py index c00d88890cc..6c146122bdf 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py @@ -60,10 +60,13 @@ class Namespace(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo.__init__(self, debug_info) self.is_partial = is_partial + self.is_mixin = False self.attributes = list(attributes) self.constants = list(constants) self.constructors = [] self.constructor_groups = [] + self.named_constructors = [] + self.named_constructor_groups = [] self.operations = list(operations) self.operation_groups = [] @@ -81,7 +84,7 @@ class Namespace(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, ir = make_copy(ir) UserDefinedType.__init__(self, ir.identifier) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithComponent.__init__(self, ir, readonly=True) @@ -140,3 +143,8 @@ class Namespace(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, def operation_groups(self): """Returns a list of OperationGroups.""" return self._operation_groups + + @property + def exposed_constructs(self): + """Returns exposed constructs.""" + return () diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/operation.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/operation.py index d4c66a00041..7613451d93e 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/operation.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/operation.py @@ -32,9 +32,17 @@ class Operation(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo, arguments, return_type, is_static=False, + is_getter=False, + is_setter=False, + is_deleter=False, extended_attributes=None, component=None, debug_info=None): + assert isinstance(is_getter, bool) + assert isinstance(is_setter, bool) + assert isinstance(is_deleter, bool) + assert is_getter + is_setter + is_deleter <= 1 # At most 1 True + FunctionLike.IR.__init__( self, identifier=identifier, @@ -48,13 +56,16 @@ class Operation(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo, WithComponent.__init__(self, component) WithDebugInfo.__init__(self, debug_info) + self.is_getter = is_getter + self.is_setter = is_setter + self.is_deleter = is_deleter self.is_stringifier = False def __init__(self, ir, owner): assert isinstance(ir, Operation.IR) FunctionLike.__init__(self, ir) - WithExtendedAttributes.__init__(self, ir) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithOwner.__init__(self, owner) @@ -62,15 +73,44 @@ class Operation(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo, WithComponent.__init__(self, ir, readonly=True) WithDebugInfo.__init__(self, ir) + self._is_getter = ir.is_getter + self._is_setter = ir.is_setter + self._is_deleter = ir.is_deleter self._is_stringifier = ir.is_stringifier @property + def is_special_operation(self): + return (self.is_getter or self.is_setter or self.is_deleter + or self.is_stringifier) + + @property + def is_indexed_or_named_property_operation(self): + """ + Returns True if this is an indexed or named property special operation + (one of getter, setter, or deleter). + """ + return self.is_getter or self.is_setter or self.is_deleter + + @property + def is_getter(self): + return self._is_getter + + @property + def is_setter(self): + return self._is_setter + + @property + def is_deleter(self): + return self._is_deleter + + @property def is_stringifier(self): return self._is_stringifier -class OperationGroup(OverloadGroup, WithCodeGeneratorInfo, WithExposure, - WithOwner, WithComponent, WithDebugInfo): +class OperationGroup(OverloadGroup, WithExtendedAttributes, + WithCodeGeneratorInfo, WithExposure, WithOwner, + WithComponent, WithDebugInfo): """ Represents a group of operations with the same identifier. @@ -78,13 +118,15 @@ class OperationGroup(OverloadGroup, WithCodeGeneratorInfo, WithExposure, the operations are overloaded. """ - class IR(OverloadGroup.IR, WithCodeGeneratorInfo, WithExposure, - WithDebugInfo): + class IR(OverloadGroup.IR, WithExtendedAttributes, WithCodeGeneratorInfo, + WithExposure, WithDebugInfo): def __init__(self, operations, + extended_attributes=None, code_generator_info=None, debug_info=None): OverloadGroup.IR.__init__(self, operations) + WithExtendedAttributes.__init__(self, extended_attributes) WithCodeGeneratorInfo.__init__(self, code_generator_info) WithExposure.__init__(self) WithDebugInfo.__init__(self, debug_info) @@ -103,6 +145,7 @@ class OperationGroup(OverloadGroup, WithCodeGeneratorInfo, WithExposure, ir = make_copy(ir) OverloadGroup.__init__(self, functions=operations) + WithExtendedAttributes.__init__(self, ir, readonly=True) WithCodeGeneratorInfo.__init__(self, ir, readonly=True) WithExposure.__init__(self, ir, readonly=True) WithOwner.__init__(self, owner) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py index 02f00b111ca..9bb06e94cd9 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/union.py @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from .composition_parts import Identifier +from .composition_parts import WithCodeGeneratorInfo from .composition_parts import WithComponent from .composition_parts import WithDebugInfo from .composition_parts import WithIdentifier @@ -9,7 +11,8 @@ from .idl_type import IdlType from .typedef import Typedef -class Union(WithIdentifier, WithComponent, WithDebugInfo): +class Union(WithIdentifier, WithCodeGeneratorInfo, WithComponent, + WithDebugInfo): """ Union class makes a group of union types with the same flattened member types and the same result whether it includes a nullable type or not. @@ -28,7 +31,7 @@ class Union(WithIdentifier, WithComponent, WithDebugInfo): expected to define an implementation class for each Union instance. """ - def __init__(self, identifier, union_types, typedef_backrefs): + def __init__(self, union_types, typedef_backrefs): """ Args: union_types: Union types of which this object consists. All types @@ -56,6 +59,7 @@ class Union(WithIdentifier, WithComponent, WithDebugInfo): assert union_type.flattened_member_types == flattened_members assert (union_type.does_include_nullable_type == does_include_nullable_type) + union_type.set_union_definition_object(self) for direct_member in union_type.member_types: if direct_member.is_nullable: nullable_members.add(direct_member) @@ -68,16 +72,49 @@ class Union(WithIdentifier, WithComponent, WithDebugInfo): components = set() - def collect_components(idl_type): - user_defined_type = idl_type.type_definition_object - if user_defined_type: - components.update(user_defined_type.components) + def collect_primary_component(idl_type): + type_definition_object = idl_type.type_definition_object + if type_definition_object and type_definition_object.components: + components.add(type_definition_object.components[0]) for idl_type in flattened_members: - idl_type.apply_to_all_composing_elements(collect_components) + idl_type.apply_to_all_composing_elements(collect_primary_component) + # Make this union type look defined in 'modules' if the union type is + # used in 'modules' in order to keep the backward compatibility with + # the old bindings generator. + is_defined_in_core = False + is_defined_in_modules = False + for idl_type in union_types: + filepath = idl_type.debug_info.location.filepath + if filepath.startswith('third_party/blink/renderer/core/'): + is_defined_in_core = True + if filepath.startswith('third_party/blink/renderer/modules/'): + is_defined_in_modules = True + if not is_defined_in_core and is_defined_in_modules: + from .composition_parts import Component + components.add(Component('modules')) + + # TODO(peria, yukishiino): Produce unique union names. Trying to + # produce the names compatible to the old bindings generator for the + # time being. + # + # type_names = sorted( + # [idl_type.type_name for idl_type in flattened_members]) + def backward_compatible_member_name(idl_type): + name = idl_type.unwrap().type_name + if name == 'StringTreatNullAs': + return 'StringTreatNullAsEmptyString' + else: + return name + + identifier = Identifier('Or'.join([ + backward_compatible_member_name(idl_type) + for idl_type in union_types[0].member_types + ])) WithIdentifier.__init__(self, identifier) - WithComponent.__init__(self, sorted(components)) + WithCodeGeneratorInfo.__init__(self, readonly=True) + WithComponent.__init__(self, sorted(components), readonly=True) WithDebugInfo.__init__(self) # Sort improves reproducibility. diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py index 30837f2f31e..e7858c07ad6 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py @@ -45,4 +45,4 @@ class UserDefinedType(WithIdentifier): class StubUserDefinedType(UserDefinedType, WithComponent): def __init__(self, identifier): UserDefinedType.__init__(self, identifier) - WithComponent.__init__(self, components=[]) + WithComponent.__init__(self, []) diff --git a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/validator.py b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/validator.py index d9f15672f20..cb0290909b8 100644 --- a/chromium/third_party/blink/renderer/bindings/scripts/web_idl/validator.py +++ b/chromium/third_party/blink/renderer/bindings/scripts/web_idl/validator.py @@ -24,6 +24,7 @@ def _all_function_likes(ir_map): IRMap.IR.Kind.INTERFACE, IRMap.IR.Kind.NAMESPACE) for ir in irs: accumulated.extend(ir.constructors) + accumulated.extend(ir.named_constructors) accumulated.extend(ir.operations) accumulated.extend(ir_map.irs_of_kinds(IRMap.IR.Kind.CALLBACK_FUNCTION)) return accumulated |