• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2013 Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7#     * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9#     * Redistributions in binary form must reproduce the above
10# copyright notice, this list of conditions and the following disclaimer
11# in the documentation and/or other materials provided with the
12# distribution.
13#     * Neither the name of Google Inc. nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29"""Generate Blink V8 bindings (.h and .cpp files).
30
31FIXME: Not currently used in build.
32This is a rewrite of the Perl IDL compiler in Python, but is not complete.
33Once it is complete, we will switch all IDL files over to Python at once.
34Until then, please work on the Perl IDL compiler.
35For details, see bug http://crbug.com/239771
36
37Input: An object of class IdlDefinitions, containing an IDL interface X
38Output: V8X.h and V8X.cpp
39"""
40
41import os
42import posixpath
43import re
44import sys
45
46# jinja2 is in chromium's third_party directory.
47module_path, module_name = os.path.split(__file__)
48third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir)
49# Insert at front to override system libraries, and after path[0] == script dir
50sys.path.insert(1, third_party)
51import jinja2
52
53templates_dir = os.path.join(module_path, os.pardir, os.pardir, 'templates')
54
55import v8_callback_interface
56from v8_globals import includes
57import v8_interface
58import v8_types
59from v8_utilities import capitalize, cpp_name, conditional_string, v8_class_name
60
61
62class CodeGeneratorV8:
63    def __init__(self, definitions, interface_name, output_directory, relative_dir_posix, idl_directories, verbose=False):
64        self.idl_definitions = definitions
65        self.interface_name = interface_name
66        self.idl_directories = idl_directories
67        self.output_directory = output_directory
68        self.verbose = verbose
69        # FIXME: remove definitions check when remove write_dummy_header_and_cpp
70        if not definitions:
71            return
72        try:
73            self.interface = definitions.interfaces[interface_name]
74        except KeyError:
75            raise Exception('%s not in IDL definitions' % interface_name)
76        if self.interface.is_callback:
77            header_template_filename = 'callback_interface.h'
78            cpp_template_filename = 'callback_interface.cpp'
79            self.generate_contents = v8_callback_interface.generate_callback_interface
80        else:
81            header_template_filename = 'interface.h'
82            cpp_template_filename = 'interface.cpp'
83            self.generate_contents = v8_interface.generate_interface
84        jinja_env = jinja2.Environment(
85            loader=jinja2.FileSystemLoader(templates_dir),
86            keep_trailing_newline=True,  # newline-terminate generated files
87            lstrip_blocks=True,  # so can indent control flow tags
88            trim_blocks=True)
89        jinja_env.filters.update({
90            'blink_capitalize': capitalize,
91            'conditional': conditional_if_endif,
92            'runtime_enabled': runtime_enabled_if,
93            })
94        self.header_template = jinja_env.get_template(header_template_filename)
95        self.cpp_template = jinja_env.get_template(cpp_template_filename)
96
97        class_name = cpp_name(self.interface)
98        self.include_for_cpp_class = posixpath.join(relative_dir_posix, class_name + '.h')
99        enumerations = definitions.enumerations
100        if enumerations:
101            v8_types.set_enum_types(enumerations)
102
103    def write_dummy_header_and_cpp(self):
104        # FIXME: fix GYP so these files aren't needed and remove this method
105        target_interface_name = self.interface_name
106        header_basename = 'V8%s.h' % target_interface_name
107        cpp_basename = 'V8%s.cpp' % target_interface_name
108        contents = """/*
109    This file is generated just to tell build scripts that {header_basename} and
110    {cpp_basename} are created for {target_interface_name}.idl, and thus
111    prevent the build scripts from trying to generate {header_basename} and
112    {cpp_basename} at every build. This file must not be tried to compile.
113*/
114""".format(**locals())
115        self.write_file(header_basename, contents)
116        self.write_file(cpp_basename, contents)
117
118    def write_header_and_cpp(self):
119        interface = self.interface
120        template_contents = self.generate_contents(interface)
121        template_contents['header_includes'].add(self.include_for_cpp_class)
122        template_contents['header_includes'] = sorted(template_contents['header_includes'])
123        template_contents['cpp_includes'] = sorted(includes)
124
125        header_basename = v8_class_name(interface) + '.h'
126        header_file_text = self.header_template.render(template_contents)
127        self.write_file(header_basename, header_file_text)
128
129        cpp_basename = v8_class_name(interface) + '.cpp'
130        cpp_file_text = self.cpp_template.render(template_contents)
131        self.write_file(cpp_basename, cpp_file_text)
132
133    def write_file(self, basename, file_text):
134        filename = os.path.join(self.output_directory, basename)
135        with open(filename, 'w') as output_file:
136            output_file.write(file_text)
137
138
139# [Conditional]
140def conditional_if_endif(code, conditional_string):
141    # Jinja2 filter to generate if/endif directive blocks
142    if not conditional_string:
143        return code
144    return ('#if %s\n' % conditional_string +
145            code +
146            '#endif // %s\n' % conditional_string)
147
148
149# [RuntimeEnabled]
150def runtime_enabled_if(code, runtime_enabled_function_name):
151    if not runtime_enabled_function_name:
152        return code
153    # Indent if statement to level of original code
154    indent = re.match(' *', code).group(0)
155    return ('%sif (%s())\n' % (indent, runtime_enabled_function_name) +
156            '    %s' % code)
157