Commit f38f8994 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

IDL compiler: Refactor the build environment

Stops scripts depending on web_idl module's internals, and
makes scripts only use public API of web_idl module.

Fixes (probably was missing) dependencies of build settings,
also refactors gn files (less distributed).

Bug: 839389
Change-Id: I54df6a2cbf92dc1efe5a1cac9427d067e114f329
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1710235Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#679917}
parent e9cd086d
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import("//third_party/blink/renderer/bindings/scripts/scripts.gni") import("//third_party/blink/renderer/bindings/scripts/scripts.gni")
import("//third_party/blink/renderer/build/scripts/scripts.gni") import("//third_party/blink/renderer/build/scripts/scripts.gni")
import("//third_party/blink/renderer/core/core_idl_files.gni")
import("//third_party/blink/renderer/modules/modules_idl_files.gni") import("//third_party/blink/renderer/modules/modules_idl_files.gni")
action("interfaces_info") { action("interfaces_info") {
...@@ -46,31 +47,75 @@ generate_global_constructors("global_constructors_idls") { ...@@ -46,31 +47,75 @@ generate_global_constructors("global_constructors_idls") {
] ]
} }
blink_python_runner("web_idl_database") { template("collect_idl_files") {
script = "$bindings_scripts_dir/build_web_idl_database.py" action(target_name) {
script = "${bindings_scripts_dir}/collect_idl_files.py"
sources = invoker.sources
outputs = [
invoker.output,
]
deps = [
"${bindings_scripts_dir}:web_idl_pylib",
]
if (defined(invoker.deps)) {
deps += invoker.deps
}
inputs = # List input file names in a temporary file.
[ response_file_contents = rebase_path(sources, root_build_dir)
"$bindings_core_output_dir/web_idl_collection_for_core.pickle", args = [
"$bindings_modules_output_dir/web_idl_collection_for_modules.pickle", "--idl-list-file",
] + web_idl_scripts "{{response_file_name}}",
outputs = [ "--component",
"$bindings_output_dir/web_idl_database.pickle", invoker.component,
"--output",
rebase_path(invoker.output, root_build_dir),
]
}
}
collect_idl_files("web_idl_in_core") {
# all IDL files in 'core' component
sources = core_static_interface_idl_files +
core_generated_interface_idl_files + core_all_dependency_idl_files
component = "core"
output = "${bindings_output_dir}/web_idl_in_core.pickle"
deps = [
"core:core_global_constructors_idls",
"//third_party/blink/renderer/core:generated_testing_idls_internal_runtime_flags",
"//third_party/blink/renderer/core:generated_testing_idls_settings",
] ]
}
args = [ collect_idl_files("web_idl_in_modules") {
"--output", # all IDL files in 'modules' component
rebase_path("$bindings_output_dir/web_idl_database.pickle", root_build_dir), sources = modules_definition_idl_files + modules_static_interface_idl_files +
"--", modules_static_dependency_idl_files
rebase_path("$bindings_core_output_dir/web_idl_collection_for_core.pickle", component = "modules"
root_build_dir), output = "${bindings_output_dir}/web_idl_in_modules.pickle"
rebase_path( }
"$bindings_modules_output_dir/web_idl_collection_for_modules.pickle",
root_build_dir), blink_python_runner("web_idl_database") {
script = "${bindings_scripts_dir}/build_web_idl_database.py"
input_data_files = get_target_outputs(":web_idl_in_core") +
get_target_outputs(":web_idl_in_modules")
inputs = input_data_files
output_data_file = "${bindings_output_dir}/web_idl_database.pickle"
outputs = [
output_data_file,
] ]
deps = [ deps = [
"//third_party/blink/renderer/bindings/core:core_web_idl_collection", ":web_idl_in_core",
"//third_party/blink/renderer/bindings/modules:modules_web_idl_collection", ":web_idl_in_modules",
"${bindings_scripts_dir}:web_idl_pylib",
] ]
args = [
"--output",
rebase_path(output_data_file, root_build_dir),
"--",
] + rebase_path(input_data_files, root_build_dir)
} }
...@@ -38,17 +38,3 @@ generate_global_constructors("core_global_constructors_idls") { ...@@ -38,17 +38,3 @@ generate_global_constructors("core_global_constructors_idls") {
":core_global_objects", ":core_global_objects",
] ]
} }
generate_web_idl_collection("core_web_idl_collection") {
# |sources| contains all IDL files under core/.
sources = core_static_interface_idl_files +
core_generated_interface_idl_files + core_all_dependency_idl_files
output = "web_idl_collection_for_core.pickle"
component = "core"
output_dir = bindings_core_output_dir
deps = [
":core_global_constructors_idls",
"//third_party/blink/renderer/core:generated_testing_idls_internal_runtime_flags",
"//third_party/blink/renderer/core:generated_testing_idls_settings",
]
}
...@@ -170,12 +170,3 @@ source_set("generated") { ...@@ -170,12 +170,3 @@ source_set("generated") {
"//v8", "//v8",
] ]
} }
generate_web_idl_collection("modules_web_idl_collection") {
# |sources| contains all IDL files under modules/.
sources = modules_definition_idl_files + modules_static_interface_idl_files +
modules_static_dependency_idl_files
output = "web_idl_collection_for_modules.pickle"
component = "modules"
output_dir = bindings_modules_output_dir
}
...@@ -46,3 +46,51 @@ action("cached_jinja_templates") { ...@@ -46,3 +46,51 @@ action("cached_jinja_templates") {
rebase_path(stamp_file, root_build_dir), rebase_path(stamp_file, root_build_dir),
] ]
} }
# Python library that supports Web IDL compiler and database
group("web_idl_pylib") {
data = [
"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/common.py",
"web_idl/constant.py",
"web_idl/constructor.py",
"web_idl/database.py",
"web_idl/dictionary.py",
"web_idl/enumeration.py",
"web_idl/exposure.py",
"web_idl/extended_attribute.py",
"web_idl/identifier_ir_map.py",
"web_idl/idl_compiler.py",
"web_idl/idl_member.py",
"web_idl/idl_type.py",
"web_idl/includes.py",
"web_idl/interface.py",
"web_idl/ir_builder.py",
"web_idl/namespace.py",
"web_idl/operation.py",
"web_idl/reference.py",
"web_idl/typedef.py",
"web_idl/user_defined_type.py",
"web_idl/values.py",
]
data += [ # dependencies to Python libraries
"//third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py",
# PLY (Python Lex-Yacc)
"//third_party/ply/lex.py",
"//third_party/ply/yacc.py",
# Web IDL lexer/parser (base parser)
"//tools/idl_parser/idl_lexer.py",
"//tools/idl_parser/idl_node.py",
"//tools/idl_parser/idl_parser.py",
# Blink IDL lexer/parser/constructor
"blink_idl_lexer.py",
"blink_idl_parser.py",
]
}
#!/usr/bin/python
#
# Copyright 2019 The Chromium Authors. All rights reserved. # Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Generates a data collection of IDL information per component. """
This scripts parses IDL files and stores the result ASTs in a pickle file. Builds Web IDL database.
The output file may contain information about component, too.
Web IDL database is a Python object that supports a variety of accessors to
IDL definitions such as IDL interface and IDL attribute.
""" """
import optparse import optparse
import utilities import utilities
import web_idl
from web_idl.identifier_ir_map import IdentifierIRMap
from web_idl.idl_compiler import IdlCompiler
from web_idl.idl_type import IdlTypeFactory
from web_idl.ir_builder import load_and_register_idl_definitions
from web_idl.reference import RefByIdFactory
def parse_options(): def parse_options():
...@@ -34,19 +29,10 @@ def parse_options(): ...@@ -34,19 +29,10 @@ def parse_options():
def main(): def main():
options, filepaths = parse_options() options, filepaths = parse_options()
ir_map = IdentifierIRMap()
ref_to_idl_type_factory = RefByIdFactory() database = web_idl.build_database(filepaths)
ref_to_idl_def_factory = RefByIdFactory()
idl_type_factory = IdlTypeFactory() utilities.write_pickle_file(options.output, database)
load_and_register_idl_definitions(
filepaths,
ir_map.register,
ref_to_idl_type_factory.create,
ref_to_idl_def_factory.create,
idl_type_factory)
idl_compiler = IdlCompiler(ir_map)
idl_database = idl_compiler.build_database()
utilities.write_pickle_file(options.output, idl_database)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -2,48 +2,55 @@ ...@@ -2,48 +2,55 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Generates a data collection of IDL information per component. """
This scripts parses IDL files and stores the result ASTs in a pickle file. Collects Web IDL definitions in IDL files into a Python object per Blink
The output file may contain information about component, too. component.
Collected IDL definitions are parsed into ASTs and saved into a file with
a label of Blink component.
""" """
import blink_idl_parser
import optparse import optparse
import blink_idl_parser
import utilities import utilities
from web_idl.collector import Collector import web_idl
from web_idl.collection import Collection
_VALID_COMPONENTS = ("core", "modules") _VALID_COMPONENTS = ("core", "modules")
def parse_options(): def parse_options():
parser = optparse.OptionParser() parser = optparse.OptionParser()
parser.add_option('--idl-list-file', type='string', parser.add_option('--idl-list-file', type='string',
help='a file path which lists IDL file paths to process') help='a file path which lists IDL file paths to process')
parser.add_option('--component', type='choice', choices=_VALID_COMPONENTS, parser.add_option('--component', type='choice', choices=_VALID_COMPONENTS,
help='specify a component name where IDLs belong') help='specify a component name')
parser.add_option('--output', type='string', parser.add_option('--output', type='string',
help='pickle file to write down') help='the output file path')
options, args = parser.parse_args() options, args = parser.parse_args()
if options.idl_list_file is None: if options.idl_list_file is None:
parser.error('Must specify a file listing IDL files using --idl-list-file.') parser.error('Specify a file listing IDL files with --idl-list-file.')
if options.output is None: if options.output is None:
parser.error('Must specify a pickle file to output using --output.') parser.error('Specify the output file path with --output.')
if options.component is None: if options.component is None:
parser.error('Must specify a component using --component.') parser.error('Specify a component with --component.')
return options, args return options, args
def main(): def main():
options, _ = parse_options() options, args = parse_options()
idl_file_names = utilities.read_idl_files_list_from_file(options.idl_list_file) if args:
raise RuntimeError('unknown arguments {}'.format(args))
filepaths = utilities.read_idl_files_list_from_file(options.idl_list_file)
parser = blink_idl_parser.BlinkIDLParser() parser = blink_idl_parser.BlinkIDLParser()
collector = Collector(component=options.component, parser=parser) ast_group = web_idl.AstGroup(options.component)
collector.collect_from_idl_files(idl_file_names) for filepath in filepaths:
Collection.write_to_file(collector.get_collection(), options.output) ast_group.add_ast_node(blink_idl_parser.parse_file(parser, filepath))
ast_group.write_to_file(options.output)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import("//third_party/blink/renderer/build/scripts/scripts.gni")
import("//third_party/blink/renderer/core/core_idl_files.gni") import("//third_party/blink/renderer/core/core_idl_files.gni")
import("//third_party/blink/renderer/modules/modules_idl_files.gni") import("//third_party/blink/renderer/modules/modules_idl_files.gni")
bindings_scripts_dir = get_path_info(".", "abspath") bindings_scripts_dir = get_path_info(".", "abspath")
bindings_scripts_output_dir = bindings_scripts_output_dir = get_path_info(".", "gen_dir")
"$root_gen_dir/third_party/blink/renderer/bindings/scripts"
jinja_module_files = [ jinja_module_files = [
"//third_party/jinja2/__init__.py", "//third_party/jinja2/__init__.py",
...@@ -57,37 +57,6 @@ idl_compiler_files = get_path_info( ...@@ -57,37 +57,6 @@ idl_compiler_files = get_path_info(
], ],
"abspath") "abspath")
web_idl_scripts = get_path_info([
"web_idl/argument.py",
"web_idl/attribute.py",
"web_idl/callback_function.py",
"web_idl/callback_interface.py",
"web_idl/collection.py",
"web_idl/collector.py",
"web_idl/common.py",
"web_idl/constant.py",
"web_idl/constructor.py",
"web_idl/database.py",
"web_idl/dictionary.py",
"web_idl/enumeration.py",
"web_idl/exposure.py",
"web_idl/extended_attribute.py",
"web_idl/identifier_ir_map.py",
"web_idl/idl_compiler.py",
"web_idl/idl_member.py",
"web_idl/idl_type.py",
"web_idl/includes.py",
"web_idl/interface.py",
"web_idl/ir_builder.py",
"web_idl/namespace.py",
"web_idl/operation.py",
"web_idl/reference.py",
"web_idl/typedef.py",
"web_idl/user_defined_type.py",
"web_idl/values.py",
],
"abspath")
# Calls the compute_interfaces_info_individual script. # Calls the compute_interfaces_info_individual script.
# #
# Parameters: # Parameters:
...@@ -505,34 +474,3 @@ template("generate_origin_trial_features") { ...@@ -505,34 +474,3 @@ template("generate_origin_trial_features") {
invoker.deps invoker.deps
} }
} }
template("generate_web_idl_collection") {
action(target_name) {
script = "${bindings_scripts_dir}/generate_web_idl_collection.py"
output_dir = invoker.output_dir
output_file_name = invoker.output
output_path = "${output_dir}/${output_file_name}"
inputs = [
script,
"${bindings_scripts_dir}/web_idl/collection.py",
"${bindings_scripts_dir}/web_idl/collector.py",
] + idl_lexer_parser_files + invoker.sources
outputs = [
output_path,
]
if (defined(invoker.deps)) {
deps = invoker.deps
}
# List input file names in a temporary file.
response_file_contents = rebase_path(invoker.sources, root_build_dir)
args = [
"--idl-list-file",
"{{response_file_name}}",
"--component",
invoker.component,
"--output",
rebase_path(output_path, root_build_dir),
]
}
}
# Copyright 2017 The Chromium Authors. All rights reserved. # Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
from .ast_group import AstGroup
from .database import Database
from .database_builder import build_database
__all__ = [
"AstGroup",
"Database",
"build_database",
]
...@@ -3,43 +3,37 @@ ...@@ -3,43 +3,37 @@
# found in the LICENSE file. # found in the LICENSE file.
import pickle import pickle
import idl_parser
from .common import Component from .common import Component
class Collection(object): class AstGroup(object):
""" """A set of Web IDL ASTs grouped by component."""
Collection class stores ASTs of Web IDL files and meta information
like component.
"""
def __init__(self, component=None): def __init__(self, component=None):
assert component is None or isinstance(component, Component) assert component is None or isinstance(component, Component)
self._asts = [] self._nodes = []
self._component = component self._component = component
def add_ast(self, ast): def __iter__(self):
assert isinstance(ast, idl_parser.idl_node.IDLNode) return self._nodes.__iter__()
assert ast.GetClass() == 'File', (
'Root node of an AST must be a File node., but is %s.' % ast.GetClass())
self._asts.append(ast)
@staticmethod @staticmethod
def load_from_file(filepath): def read_from_file(filepath):
with open(filepath, 'r') as pickle_file: with open(filepath, 'r') as pickle_file:
collection = pickle.load(pickle_file) ast_group = pickle.load(pickle_file)
assert isinstance(collection, Collection) assert isinstance(ast_group, AstGroup)
return collection return ast_group
@staticmethod def write_to_file(self, filepath):
def write_to_file(collection, filepath):
assert isinstance(collection, Collection)
with open(filepath, 'w') as pickle_file: with open(filepath, 'w') as pickle_file:
pickle.dump(collection, pickle_file) pickle.dump(self, pickle_file)
@property def add_ast_node(self, node):
def asts(self): assert node.GetClass() == 'File', (
return self._asts 'Root node of an AST must be a File node, but is %s.' %
node.GetClass())
self._nodes.append(node)
@property @property
def component(self): def component(self):
......
# 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.
import blink_idl_parser
from .collection import Collection
class Collector(object):
def __init__(self, component, parser=blink_idl_parser.BlinkIDLParser()):
self._component = component
self._collection = Collection(component)
self._parser = parser
def collect_from_idl_files(self, filepaths):
if isinstance(filepaths, str):
filepaths = [filepaths]
for filepath in filepaths:
try:
ast = blink_idl_parser.parse_file(self._parser, filepath)
self.collect_from_ast(ast)
except ValueError as ve:
raise ValueError('%s\nin file %s' % (str(ve), filepath))
def collect_from_idl_text(self, text, filename='TEXT'):
ast = self._parser.ParseText(filename, text) # pylint: disable=no-member
self.collect_from_ast(ast)
def collect_from_ast(self, node):
self._collection.add_ast(node)
def get_collection(self):
return self._collection
# 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.
from .identifier_ir_map import IdentifierIRMap
from .idl_compiler import IdlCompiler
from .idl_type import IdlTypeFactory
from .ir_builder import load_and_register_idl_definitions
from .reference import RefByIdFactory
def build_database(filepaths):
"""Compiles IDL definitions in |filepaths| and builds a database."""
ir_map = IdentifierIRMap()
ref_to_idl_type_factory = RefByIdFactory()
ref_to_idl_def_factory = RefByIdFactory()
idl_type_factory = IdlTypeFactory()
load_and_register_idl_definitions(
filepaths, ir_map.register, ref_to_idl_type_factory.create,
ref_to_idl_def_factory.create, idl_type_factory)
compiler = IdlCompiler(ir_map, ref_to_idl_type_factory,
ref_to_idl_def_factory, idl_type_factory)
return compiler.build_database()
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# found in the LICENSE file. # found in the LICENSE file.
from .identifier_ir_map import IdentifierIRMap from .identifier_ir_map import IdentifierIRMap
from .idl_type import IdlTypeFactory
from .reference import RefByIdFactory
class IdlCompiler(object): class IdlCompiler(object):
...@@ -26,8 +28,27 @@ class IdlCompiler(object): ...@@ -26,8 +28,27 @@ class IdlCompiler(object):
the details. the details.
""" """
def __init__(self, ir_map): def __init__(self, ir_map, ref_to_idl_type_factory, ref_to_idl_def_factory,
idl_type_factory):
"""
Args:
ir_map: IdentifierIRMap filled with the initial IRs of IDL
definitions.
ref_to_idl_type_factory: RefByIdFactory that created all references
to IdlType.
ref_to_idl_def_factory: RefByIdFactory that created all references
to UserDefinedType.
idl_type_factory: IdlTypeFactory that created all instances of
IdlType.
"""
assert isinstance(ir_map, IdentifierIRMap)
assert isinstance(ref_to_idl_type_factory, RefByIdFactory)
assert isinstance(ref_to_idl_def_factory, RefByIdFactory)
assert isinstance(idl_type_factory, IdlTypeFactory)
self._ir_map = ir_map self._ir_map = ir_map
self._ref_to_idl_type_factory = ref_to_idl_type_factory
self._ref_to_idl_def_factory = ref_to_idl_def_factory
self._idl_type_factory = idl_type_factory
def build_database(self): def build_database(self):
self._merge_partials() self._merge_partials()
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
# found in the LICENSE file. # found in the LICENSE file.
from .argument import Argument from .argument import Argument
from .ast_group import AstGroup
from .attribute import Attribute from .attribute import Attribute
from .callback_function import CallbackFunction from .callback_function import CallbackFunction
from .callback_interface import CallbackInterface from .callback_interface import CallbackInterface
from .collection import Collection
from .common import DebugInfo from .common import DebugInfo
from .constant import Constant from .constant import Constant
from .dictionary import Dictionary from .dictionary import Dictionary
...@@ -46,12 +46,12 @@ def load_and_register_idl_definitions(filepaths, register_ir, ...@@ -46,12 +46,12 @@ def load_and_register_idl_definitions(filepaths, register_ir,
assert callable(register_ir) assert callable(register_ir)
for filepath in filepaths: for filepath in filepaths:
asts_per_component = Collection.load_from_file(filepath) asts_per_component = AstGroup.read_from_file(filepath)
component = asts_per_component.component component = asts_per_component.component
builder = _IRBuilder(component, create_ref_to_idl_type, builder = _IRBuilder(component, create_ref_to_idl_type,
create_ref_to_idl_def, idl_type_factory) create_ref_to_idl_def, idl_type_factory)
for file_node in asts_per_component.asts: for file_node in asts_per_component:
assert file_node.GetClass() == 'File' assert file_node.GetClass() == 'File'
for top_level_node in file_node.GetChildren(): for top_level_node in file_node.GetChildren():
register_ir(builder.build_top_level_def(top_level_node)) register_ir(builder.build_top_level_def(top_level_node))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment