| # 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 web_idl |
| |
| 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 .package_initializer import package_initializer |
| from .path_manager import PathManager |
| from .task_queue import TaskQueue |
| |
| |
| def make_factory_methods(cg_context): |
| assert isinstance(cg_context, CodeGenContext) |
| |
| T = TextNode |
| |
| decls = ListNode() |
| |
| func_def = CxxFuncDefNode( |
| name="Create", |
| arg_decls=[ |
| "v8::Isolate* isolate", |
| "v8::Local<v8::Value> value", |
| "ExceptionState& exception_state", |
| ], |
| return_type="${class_name}", |
| static=True) |
| func_def.set_base_template_vars(cg_context.template_bindings()) |
| decls.append(func_def) |
| |
| func_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}();"), |
| ]) |
| |
| func_def = CxxFuncDefNode( |
| name="Create", |
| arg_decls=["const String& value"], |
| return_type="base::Optional<${class_name}>", |
| static=True) |
| func_def.set_base_template_vars(cg_context.template_bindings()) |
| decls.append(func_def) |
| |
| func_def.body.extend([ |
| T("const auto& result = bindings::FindIndexInEnumStringTable" |
| "(value, string_table_);"), |
| T("if (!result)\n" |
| " return base::nullopt;"), |
| T("return ${class_name}(static_cast<Enum>(result.value()));"), |
| ]) |
| |
| return decls, 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]) |
| |
| 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_identifier): |
| assert isinstance(enumeration_identifier, web_idl.Identifier) |
| |
| web_idl_database = package_initializer().web_idl_database() |
| enumeration = web_idl_database.find(enumeration_identifier) |
| |
| path_manager = PathManager(enumeration) |
| assert path_manager.api_component == path_manager.impl_component |
| api_component = path_manager.api_component |
| for_testing = enumeration.code_generator_info.for_testing |
| |
| # 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, for_testing)) |
| class_def.set_base_template_vars(cg_context.template_bindings()) |
| |
| # Implementation parts |
| factory_decls, factory_defs = make_factory_methods(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(), |
| ]) |
| |
| # Assemble the parts. |
| header_node.accumulator.add_include_headers([ |
| component_export_header(api_component, for_testing), |
| "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h", |
| "third_party/blink/renderer/platform/bindings/enumeration_base.h", |
| ]) |
| |
| 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(task_queue): |
| assert isinstance(task_queue, TaskQueue) |
| |
| web_idl_database = package_initializer().web_idl_database() |
| |
| for enumeration in web_idl_database.enumerations: |
| task_queue.post_task(generate_enumeration, enumeration.identifier) |