summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/bindings/scripts/bind_gen/typedef.py
blob: 3d9c00b0c5132e14c38b5ba3fe057555727adbd0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# Copyright 2021 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 CxxNamespaceNode
from .codegen_accumulator import CodeGenAccumulator
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_typedefs_to_unions(typedefs, component_selector):
    assert isinstance(typedefs, (list, tuple))
    assert all(isinstance(typedef, web_idl.Typedef) for typedef in typedefs)
    assert callable(component_selector)

    new_and_old_names = list(
        map(
            lambda typedef: (blink_class_name(typedef),
                             blink_class_name(typedef.idl_type.
                                              union_definition_object)),
            filter(
                lambda typedef: component_selector(
                    [typedef, typedef.idl_type.union_definition_object]),
                filter(lambda typedef: typedef.idl_type.is_union, typedefs))))
    node = ListNode([
        TextNode("using {} = {};".format(new_name, old_name))
        for new_name, old_name in new_and_old_names
    ])
    node.accumulate(
        CodeGenAccumulator.require_class_decls(
            [old_name for _, old_name in new_and_old_names]))
    return node


def make_typedefs(typedefs, component_selector):
    assert isinstance(typedefs, (list, tuple))
    assert all(isinstance(typedef, web_idl.Typedef) for typedef in typedefs)
    assert callable(component_selector)

    return ListNode([
        TextNode("// Typedefs to IDL unions"),
        _make_typedefs_to_unions(typedefs, component_selector),
    ])


def _make_unions_of_typedefed_member_types(unions, component_selector):
    assert isinstance(unions, (list, tuple))
    assert all(isinstance(union, web_idl.Union) for union in unions)
    assert callable(component_selector)

    def union_name_of_typedefed_members(idl_type, union):
        for member_type in idl_type.member_types:
            if member_type.unwrap(nullable=True).is_typedef:
                break
        else:
            return None

        pieces = []
        def_objs = [union]
        for member_type in idl_type.member_types:
            body_type = member_type.unwrap(nullable=True)
            if body_type.is_typedef:
                pieces.append(body_type.typedef_object.identifier)
                def_objs.append(body_type.typedef_object)
            else:
                pieces.append(
                    body_type.type_name_with_extended_attribute_key_values)
        if not component_selector(def_objs):
            return None
        pieces = sorted(pieces)
        if idl_type.does_include_nullable_type:
            pieces.append("Null")
        return "V8Union{}".format("Or".join(pieces))

    node = ListNode()
    fwd_decl_names = []

    for union in unions:
        if not union.typedef_members:
            continue
        new_names = sorted(
            set(
                filter(
                    None,
                    map(
                        lambda idl_type: union_name_of_typedefed_members(
                            idl_type, union), union.idl_types))))
        old_name = blink_class_name(union)
        for new_name in new_names:
            node.append(TextNode("using {} = {};".format(new_name, old_name)))
        if new_names:
            fwd_decl_names.append(old_name)
    node.accumulate(CodeGenAccumulator.require_class_decls(fwd_decl_names))

    return node


def make_unions(unions, component_selector):
    assert isinstance(unions, (list, tuple))
    assert all(isinstance(union, web_idl.Union) for union in unions)
    assert callable(component_selector)

    return ListNode([
        TextNode("// Unions including typedef'ed member types"),
        _make_unions_of_typedefed_member_types(unions, component_selector),
    ])


def generate_typedefs_all(filepath_basename):
    assert isinstance(filepath_basename, str)

    web_idl_database = package_initializer().web_idl_database()

    # Components
    c1 = web_idl.Component("core")
    c2 = web_idl.Component("modules")
    components = (c1, c2)

    # Filepaths
    header_path = {}
    for component in components:
        header_path[component] = PathManager.component_path(
            component, "{}.h".format(filepath_basename))

    # Root nodes
    header_node = {}
    for component in components:
        node = ListNode(tail="\n")
        node.set_accumulator(CodeGenAccumulator())
        node.set_renderer(MakoRenderer())
        header_node[component] = node

    # Namespaces
    header_blink_ns = {}
    for component in components:
        node = CxxNamespaceNode(name_style.namespace("blink"))
        header_blink_ns[component] = node

    # Header part (copyright, include directives, and forward declarations)
    for component in components:
        header_node[component].extend([
            make_copyright_header(),
            EmptyNode(),
            enclose_with_header_guard(
                ListNode([
                    make_header_include_directives(
                        header_node[component].accumulator),
                    EmptyNode(),
                    header_blink_ns[component],
                ]), name_style.header_guard(header_path[component])),
        ])
        header_blink_ns[component].body.extend([
            make_forward_declarations(header_node[component].accumulator),
            EmptyNode(),
        ])

    # Implementation parts
    component_selectors = {
        c1: lambda xs: all(c2 not in x.components for x in xs),
        c2: lambda xs: any(c2 in x.components for x in xs),
    }

    all_typedefs = sorted(web_idl_database.typedefs,
                          key=lambda x: x.identifier)
    for component in components:
        header_blink_ns[component].body.extend([
            make_typedefs(all_typedefs, component_selectors[component]),
            EmptyNode(),
        ])

    all_unions = sorted(web_idl_database.union_types,
                        key=lambda x: x.identifier)
    for component in components:
        header_blink_ns[component].body.extend([
            make_unions(all_unions, component_selectors[component]),
            EmptyNode(),
        ])

    # Write down to the files.
    for component in components:
        write_code_node_to_file(
            header_node[component],
            PathManager.gen_path_to(header_path[component]))


def generate_typedefs(task_queue):
    assert isinstance(task_queue, TaskQueue)

    task_queue.post_task(generate_typedefs_all, "v8_typedefs")