Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Unified Diff: third_party/WebKit/Source/bindings/scripts/code_generator.py

Issue 2345083004: Split Jinja-related CodeGeneratorV8 guts into a separate class. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/bindings/scripts/code_generator.py
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator.py b/third_party/WebKit/Source/bindings/scripts/code_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..02448dd131ea5b95fad46c1fb50aa766d00e02ac
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator.py
@@ -0,0 +1,184 @@
+# 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.
+
+# pylint: disable=import-error,print-statement,relative-import
+
+"""Plumbing for a Jinja-based code generator, including CodeGeneratorBase, a base class for all generators."""
+
+import os
+import posixpath
+import re
+import sys
+
+from idl_types import set_ancestors, IdlType
+from v8_attributes import attribute_filters
+from v8_globals import includes
+from v8_interface import constant_filters
+from v8_types import set_component_dirs
+from v8_methods import method_filters
+from v8_utilities import capitalize, for_origin_trial_feature, unique_by
+from utilities import (idl_filename_to_component, is_valid_component_dependency,
+ format_remove_duplicates, format_blink_cpp_source_code)
+
+# Path handling for libraries and templates
+# Paths have to be normalized because Jinja uses the exact template path to
+# determine the hash used in the cache filename, and we need a pre-caching step
+# to be concurrency-safe. Use absolute path because __file__ is absolute if
+# module is imported, and relative if executed directly.
+# If paths differ between pre-caching and individual file compilation, the cache
+# 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'))
+
+# jinja2 is in chromium's third_party directory.
+# Insert at 1 so at front to override system libraries, and
+# after path[0] == invoking script dir
+sys.path.insert(1, THIRD_PARTY_DIR)
+import jinja2
+
+
+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)
+
+
+# [Exposed]
+def exposed_if(code, exposed_test):
+ if not exposed_test:
+ return code
+ return generate_indented_conditional(code, 'executionContext && (%s)' % exposed_test)
+
+
+# [SecureContext]
+def secure_context_if(code, secure_context_test):
+ if not secure_context_test:
+ return code
+ return generate_indented_conditional(code, 'executionContext && (%s)' % secure_context_test)
+
+
+# [RuntimeEnabled]
+def runtime_enabled_if(code, runtime_enabled_function_name):
+ if not runtime_enabled_function_name:
+ return code
+ return generate_indented_conditional(code, '%s()' % runtime_enabled_function_name)
+
+
+def initialize_jinja_env(cache_dir):
+ jinja_env = jinja2.Environment(
+ loader=jinja2.FileSystemLoader(TEMPLATES_DIR),
+ # Bytecode cache is not concurrency-safe unless pre-cached:
+ # if pre-cached this is read-only, but writing creates a race condition.
+ bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir),
+ keep_trailing_newline=True, # newline-terminate generated files
+ lstrip_blocks=True, # so can indent control flow tags
+ trim_blocks=True)
+ jinja_env.filters.update({
+ 'blink_capitalize': capitalize,
+ 'exposed': exposed_if,
+ 'for_origin_trial_feature': for_origin_trial_feature,
+ 'format_blink_cpp_source_code': format_blink_cpp_source_code,
+ 'format_remove_duplicates': format_remove_duplicates,
+ 'runtime_enabled': runtime_enabled_if,
+ 'secure_context': secure_context_if,
+ 'unique_by': unique_by})
+ jinja_env.filters.update(attribute_filters())
+ jinja_env.filters.update(constant_filters())
+ jinja_env.filters.update(method_filters())
+ return jinja_env
+
+
+def normalize_and_sort_includes(include_paths):
+ normalized_include_paths = []
+ for include_path in include_paths:
+ match = re.search(r'/gen/blink/(.*)$', posixpath.abspath(include_path))
+ if match:
+ include_path = match.group(1)
+ normalized_include_paths.append(include_path)
+ return sorted(normalized_include_paths)
+
+
+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
+ self.jinja_env = initialize_jinja_env(cache_dir)
+ self.output_dir = output_dir
+ self.set_global_type_info()
+
+ def should_generate_code(self, definitions):
+ return definitions.interfaces or definitions.dictionaries
+
+ def set_global_type_info(self):
+ interfaces_info = self.info_provider.interfaces_info
+ set_ancestors(interfaces_info['ancestors'])
+ IdlType.set_callback_interfaces(interfaces_info['callback_interfaces'])
+ IdlType.set_dictionaries(interfaces_info['dictionaries'])
+ IdlType.set_enums(self.info_provider.enumerations)
+ IdlType.set_implemented_as_interfaces(interfaces_info['implemented_as_interfaces'])
+ IdlType.set_garbage_collected_types(interfaces_info['garbage_collected_interfaces'])
+ set_component_dirs(interfaces_info['component_dirs'])
+
+ def render_template(self, include_paths, header_template, cpp_template,
+ template_context, component=None):
+ template_context['code_generator'] = self.generator_name
+
+ # Add includes for any dependencies
+ template_context['header_includes'] = normalize_and_sort_includes(
+ template_context['header_includes'])
+
+ for include_path in include_paths:
+ if component:
+ dependency = idl_filename_to_component(include_path)
+ assert is_valid_component_dependency(component, dependency)
+ includes.add(include_path)
+
+ template_context['cpp_includes'] = normalize_and_sort_includes(includes)
+
+ header_text = header_template.render(template_context)
+ cpp_text = cpp_template.render(template_context)
+ return header_text, cpp_text
+
+ def generate_code(self, definitions, definition_name):
+ """Invokes code generation. The [definitions] argument is a list of definitions,
+ and the [definition_name] is the name of the definition
+ """
+ # This should be implemented in subclasses.
+ raise NotImplementedError()
+
+
+def main(argv):
+ # If file itself executed, cache templates
+ try:
+ cache_dir = argv[1]
+ dummy_filename = argv[2]
+ except IndexError:
+ 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(('.cpp', '.h'))]
+ for template_filename in template_filenames:
+ jinja_env.get_template(template_filename)
+
+ # Create a dummy file as output for the build system,
+ # since filenames of individual cache files are unpredictable and opaque
+ # (they are hashes of the template path, which varies based on environment)
+ with open(dummy_filename, 'w') as dummy_file:
+ pass # |open| creates or touches the file
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
« no previous file with comments | « third_party/WebKit/Source/bindings/scripts/BUILD.gn ('k') | third_party/WebKit/Source/bindings/scripts/code_generator_v8.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698