| Index: Source/bindings/scripts/code_generator_v8.py
|
| diff --git a/Source/bindings/scripts/code_generator_v8.py b/Source/bindings/scripts/code_generator_v8.py
|
| index 0cfaec9bdf5bab4a464e0b30ccb960d27ad1a0ff..c93972ce219c0594a2c6073095462b1079447bd6 100644
|
| --- a/Source/bindings/scripts/code_generator_v8.py
|
| +++ b/Source/bindings/scripts/code_generator_v8.py
|
| @@ -15,7 +15,7 @@
|
| # this software without specific prior written permission.
|
| #
|
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +# 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| @@ -33,8 +33,6 @@ Output: V8X.h and V8X.cpp
|
| """
|
|
|
| import os
|
| -import posixpath
|
| -import re
|
| import sys
|
|
|
| # jinja2 is in chromium's third_party directory.
|
| @@ -43,207 +41,78 @@ third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pard
|
| sys.path.append(third_party)
|
| import jinja2
|
|
|
| +templates_dir = os.path.join(module_path, os.pardir, 'templates')
|
|
|
| -CALLBACK_INTERFACE_CPP_INCLUDES = set([
|
| - 'core/dom/ScriptExecutionContext.h',
|
| - 'bindings/v8/V8Binding.h',
|
| - 'bindings/v8/V8Callback.h',
|
| - 'wtf/Assertions.h',
|
| -])
|
| -
|
| -
|
| -CALLBACK_INTERFACE_H_INCLUDES = set([
|
| - 'bindings/v8/ActiveDOMCallback.h',
|
| - 'bindings/v8/DOMWrapperWorld.h',
|
| - 'bindings/v8/ScopedPersistent.h',
|
| -])
|
| -
|
| -
|
| -INTERFACE_CPP_INCLUDES = set([
|
| - 'RuntimeEnabledFeatures.h',
|
| - 'bindings/v8/ScriptController.h',
|
| - 'bindings/v8/V8Binding.h',
|
| - 'core/dom/ContextFeatures.h',
|
| - 'core/dom/Document.h',
|
| - 'core/page/Frame.h',
|
| - 'core/platform/chromium/TraceEvent.h',
|
| - 'wtf/UnusedParam.h',
|
| -])
|
| -
|
| -
|
| -INTERFACE_H_INCLUDES = set([
|
| - 'bindings/v8/V8Binding.h',
|
| -])
|
| -
|
| -
|
| -CPP_TYPE_SPECIAL_CONVERSION_RULES = {
|
| - 'float': 'float',
|
| - 'double': 'double',
|
| - 'long long': 'long long',
|
| - 'unsigned long long': 'unsigned long long',
|
| - 'long': 'int',
|
| - 'short': 'int',
|
| - 'byte': 'int',
|
| - 'boolean': 'bool',
|
| - 'DOMString': 'const String&',
|
| -}
|
| -
|
| -
|
| -PRIMITIVE_TYPES = set([
|
| - 'boolean',
|
| - 'void',
|
| - 'Date',
|
| - 'byte',
|
| - 'octet',
|
| - 'short',
|
| - 'long',
|
| - 'long long',
|
| - 'unsigned short',
|
| - 'unsigned long',
|
| - 'unsigned long long',
|
| - 'float',
|
| - 'double',
|
| -])
|
| -
|
| -
|
| -def apply_template(path_to_template, contents):
|
| - dirname, basename = os.path.split(path_to_template)
|
| - jinja_env = jinja2.Environment(trim_blocks=True, loader=jinja2.FileSystemLoader([dirname]))
|
| - template = jinja_env.get_template(basename)
|
| - return template.render(contents)
|
| -
|
| -
|
| -def cpp_value_to_js_value(data_type, cpp_value, isolate, creation_context=''):
|
| - """Returns a expression that represent JS value corresponding to a C++ value."""
|
| - if data_type == 'boolean':
|
| - return 'v8Boolean(%s, %s)' % (cpp_value, isolate)
|
| - if data_type in ['long long', 'unsigned long long', 'DOMTimeStamp']:
|
| - # long long and unsigned long long are not representable in ECMAScript.
|
| - return 'v8::Number::New(static_cast<double>(%s))' % cpp_value
|
| - if primitive_type(data_type):
|
| - if data_type not in ['float', 'double']:
|
| - raise Exception('unexpected data_type %s' % data_type)
|
| - return 'v8::Number::New(%s)' % cpp_value
|
| - if data_type == 'DOMString':
|
| - return 'v8String(%s, %s)' % (cpp_value, isolate)
|
| - if array_or_sequence_type(data_type):
|
| - return 'v8Array(%s, %s)' % (cpp_value, isolate)
|
| - return 'toV8(%s, %s, %s)' % (cpp_value, creation_context, isolate)
|
|
|
| +import v8_attributes
|
| +import v8_includes
|
| +from v8_interface import generate_constants
|
| +import v8_types
|
| +from v8_types import cpp_type
|
| +from v8_utilities import generate_conditional_string, implemented_as_cpp_name
|
| +from v8_values import cpp_value_to_js_value
|
|
|
| -def generate_conditional_string(interface_or_attribute_or_operation):
|
| - if 'Conditional' not in interface_or_attribute_or_operation.extended_attributes:
|
| - return ''
|
| - conditional = interface_or_attribute_or_operation.extended_attributes['Conditional']
|
| - for operator in ['&', '|']:
|
| - if operator in conditional:
|
| - conditions = set(conditional.split(operator))
|
| - operator_separator = ' %s%s ' % (operator, operator)
|
| - return operator_separator.join(['ENABLE(%s)' % expression for expression in sorted(conditions)])
|
| - return 'ENABLE(%s)' % conditional
|
| -
|
| -
|
| -def includes_for_type(data_type):
|
| - if primitive_type(data_type) or data_type == 'DOMString':
|
| - return set()
|
| - if array_or_sequence_type(data_type):
|
| - return includes_for_type(array_or_sequence_type(data_type))
|
| - return set(['V8%s.h' % data_type])
|
| -
|
| -
|
| -def includes_for_cpp_class(class_name, relative_dir_posix):
|
| - return set([posixpath.join('bindings', relative_dir_posix, class_name + '.h')])
|
| -
|
| -
|
| -def includes_for_operation(operation):
|
| - includes = includes_for_type(operation.data_type)
|
| - for parameter in operation.arguments:
|
| - includes |= includes_for_type(parameter.data_type)
|
| - return includes
|
| -
|
| -
|
| -def primitive_type(data_type):
|
| - return data_type in PRIMITIVE_TYPES
|
| -
|
| -
|
| -def sequence_type(data_type):
|
| - matched = re.match(r'sequence<([\w\d_\s]+)>', data_type)
|
| - if not matched:
|
| - return None
|
| - return matched.group(1)
|
| -
|
| -
|
| -def array_type(data_type):
|
| - matched = re.match(r'([\w\d_\s]+)\[\]', data_type)
|
| - if not matched:
|
| - return None
|
| - return matched.group(1)
|
| -
|
| -
|
| -def array_or_sequence_type(data_type):
|
| - return array_type(data_type) or sequence_type(data_type)
|
| -
|
| -def cpp_type(data_type, pointer_type):
|
| - """Returns the C++ type corresponding to the IDL type.
|
| -
|
| - Args:
|
| - pointer_type:
|
| - 'raw': return raw pointer form (e.g. Foo*)
|
| - 'RefPtr': return RefPtr form (e.g. RefPtr<Foo>)
|
| - 'PassRefPtr': return PassRefPtr form (e.g. RefPtr<Foo>)
|
| - """
|
| - if data_type in CPP_TYPE_SPECIAL_CONVERSION_RULES:
|
| - return CPP_TYPE_SPECIAL_CONVERSION_RULES[data_type]
|
| - if array_or_sequence_type(data_type):
|
| - return 'const Vector<%s >&' % cpp_type(array_or_sequence_type(data_type), 'RefPtr')
|
| - if pointer_type == 'raw':
|
| - return data_type + '*'
|
| - if pointer_type in ['RefPtr', 'PassRefPtr']:
|
| - return '%s<%s>' % (pointer_type, data_type)
|
| - raise Exception('Unrecognized pointer type: "%s"' % pointer_type)
|
| -
|
| -
|
| -def v8_type(data_type):
|
| - return 'V8' + data_type
|
| -
|
| -
|
| -def cpp_method_name(attribute_or_operation):
|
| - return attribute_or_operation.extended_attributes.get('ImplementedAs', attribute_or_operation.name)
|
| -
|
| -
|
| -def cpp_class_name(interface):
|
| - return interface.extended_attributes.get('ImplementedAs', interface.name)
|
| -
|
| -
|
| -def v8_class_name(interface):
|
| - return v8_type(interface.name)
|
| +# WIP
|
| +import code_generator_idl_reader
|
| +from v8_interface import generate_implementation
|
| +import v8_interface_header
|
|
|
|
|
| class CodeGeneratorV8:
|
| def __init__(self, definitions, interface_name, output_directory, relative_dir_posix, idl_directories, verbose=False):
|
| self.idl_definitions = definitions
|
| self.interface_name = interface_name
|
| - self.idl_directories = idl_directories
|
| self.output_directory = output_directory
|
| self.relative_dir_posix = relative_dir_posix
|
| self.verbose = verbose
|
| self.interface = None
|
| self.header_includes = set()
|
| self.cpp_includes = set()
|
| - if definitions: # FIXME: remove check when remove write_dummy_header_and_cpp
|
| - try:
|
| - self.interface = definitions.interfaces[interface_name]
|
| - except KeyError:
|
| - raise Exception('%s not in IDL definitions' % interface_name)
|
|
|
| - def generate_cpp_to_js_conversion(self, data_type, cpp_value, format_string, isolate, creation_context=''):
|
| - """Returns a statement that converts a C++ value to a JS value.
|
| + # WIP = True
|
| + WIP = False
|
|
|
| - Also add necessary includes to self.cpp_includes.
|
| - """
|
| - self.cpp_includes |= includes_for_type(data_type)
|
| - js_value = cpp_value_to_js_value(data_type, cpp_value, isolate, creation_context)
|
| - return format_string % js_value
|
| + # FIXME: remove check when remove write_dummy_header_and_cpp
|
| + if not definitions:
|
| + return
|
| +
|
| + try:
|
| + if definitions.exceptions:
|
| + # FIXME: support exceptions
|
| + self.exception = definitions.exceptions[interface_name]
|
| + raise Exception('Exceptions not supported: "%s"' % interface_name)
|
| + else:
|
| + self.interface = definitions.interfaces[interface_name]
|
| + except KeyError:
|
| + raise Exception('%s not in IDL definitions' % interface_name)
|
| + self.v8_class_name = v8_types.get_v8_class_name(self.interface)
|
| + if self.interface.is_callback:
|
| + header_template_filename = 'callback_interface.h'
|
| + cpp_template_filename = 'callback_interface.cpp'
|
| + self.generate_contents = self.generate_callback_interface
|
| + else:
|
| + if WIP:
|
| + header_template_filename = 'interface_wip.h'
|
| + cpp_template_filename = 'interface_wip.cpp'
|
| + self.generate_contents = self.generate_interface_wip
|
| + else:
|
| + header_template_filename = 'interface.h'
|
| + cpp_template_filename = 'interface.cpp'
|
| + self.generate_contents = self.generate_interface
|
| + # FIXME: update to Jinja 2.7 and use:
|
| + # keep_trailing_newline=True, # so generated files are newline-terminated
|
| + # lstrip_blocks=True, # so can indent expression tags
|
| + jinja_env = jinja2.Environment(
|
| + loader=jinja2.FileSystemLoader(templates_dir),
|
| + trim_blocks=True)
|
| + self.header_template = jinja_env.get_template(header_template_filename)
|
| + self.cpp_template = jinja_env.get_template(cpp_template_filename)
|
| +
|
| + if WIP:
|
| + v8_types.set_callback_function_types(definitions.callback_functions)
|
| + v8_types.set_enum_types(definitions.enumerations)
|
| + code_generator_idl_reader.find_idl_files(idl_directories)
|
| + link_overloaded_functions(self.interface)
|
|
|
| def write_dummy_header_and_cpp(self):
|
| # FIXME: fix GYP so these files aren't needed and remove this method
|
| @@ -257,69 +126,72 @@ class CodeGeneratorV8:
|
| {cpp_basename} at every build. This file must not be tried to compile.
|
| */
|
| """.format(**locals())
|
| - self.write_header_code(header_basename, contents)
|
| - self.write_cpp_code(cpp_basename, contents)
|
| + self.write_file(header_basename, contents)
|
| + self.write_file(cpp_basename, contents)
|
|
|
| def write_header_and_cpp(self):
|
| - header_basename = v8_class_name(self.interface) + '.h'
|
| - cpp_basename = v8_class_name(self.interface) + '.cpp'
|
| - if self.interface.is_callback:
|
| - header_template = 'templates/callback_interface.h'
|
| - cpp_template = 'templates/callback_interface.cpp'
|
| - template_contents = self.generate_callback_interface()
|
| - else:
|
| - header_template = 'templates/interface.h'
|
| - cpp_template = 'templates/interface.cpp'
|
| - template_contents = self.generate_interface()
|
| - template_contents['conditional_string'] = generate_conditional_string(self.interface)
|
| - header_file_text = apply_template(header_template, template_contents)
|
| - cpp_file_text = apply_template(cpp_template, template_contents)
|
| - self.write_header_code(header_basename, header_file_text)
|
| - self.write_cpp_code(cpp_basename, cpp_file_text)
|
| -
|
| - def write_header_code(self, header_basename, header_file_text):
|
| - header_filename = os.path.join(self.output_directory, header_basename)
|
| - with open(header_filename, 'w') as header_file:
|
| - header_file.write(header_file_text)
|
| -
|
| - def write_cpp_code(self, cpp_basename, cpp_file_text):
|
| - cpp_filename = os.path.join(self.output_directory, cpp_basename)
|
| - with open(cpp_filename, 'w') as cpp_file:
|
| - cpp_file.write(cpp_file_text)
|
| -
|
| - def generate_attribute(self, attribute):
|
| - self.cpp_includes |= includes_for_type(attribute.data_type)
|
| + template_contents = self.generate_contents()
|
| + template_contents.update(self.common_contents())
|
| +
|
| + header_basename = self.v8_class_name + '.h'
|
| + header_file_text = self.header_template.render(template_contents)
|
| + self.write_file(header_basename, header_file_text)
|
| +
|
| + cpp_basename = self.v8_class_name + '.cpp'
|
| + cpp_file_text = self.cpp_template.render(template_contents)
|
| + self.write_file(cpp_basename, cpp_file_text)
|
| +
|
| + def write_file(self, basename, file_text):
|
| + filename = os.path.join(self.output_directory, basename)
|
| + with open(filename, 'w') as output_file:
|
| + output_file.write(file_text)
|
| +
|
| + def common_contents(self):
|
| return {
|
| - 'name': attribute.name,
|
| - 'conditional_string': generate_conditional_string(attribute),
|
| - 'cpp_method_name': cpp_method_name(attribute),
|
| - 'cpp_type': cpp_type(attribute.data_type, pointer_type='RefPtr'),
|
| - 'v8_type': v8_type(attribute.data_type),
|
| - }
|
| + 'conditional_string': generate_conditional_string(self.interface),
|
| + 'v8_class_name': self.v8_class_name,
|
| + }
|
| +
|
| + def generate_attributes(self):
|
| + attributes_contents, attributes_includes = v8_attributes.generate_attributes(self.interface)
|
| + self.cpp_includes |= attributes_includes
|
| + return attributes_contents
|
|
|
| def generate_interface(self):
|
| - self.header_includes = INTERFACE_H_INCLUDES
|
| - self.header_includes |= includes_for_cpp_class(cpp_class_name(self.interface), self.relative_dir_posix)
|
| - self.cpp_includes = INTERFACE_CPP_INCLUDES
|
| + cpp_class_name = implemented_as_cpp_name(self.interface)
|
| + self.header_includes = v8_includes.INTERFACE_H_INCLUDES
|
| + self.header_includes |= v8_includes.includes_for_cpp_class(cpp_class_name, self.relative_dir_posix)
|
| + self.cpp_includes = v8_includes.INTERFACE_CPP_INCLUDES
|
|
|
| template_contents = {
|
| 'interface_name': self.interface.name,
|
| - 'cpp_class_name': cpp_class_name(self.interface),
|
| - 'v8_class_name': v8_class_name(self.interface),
|
| - 'attributes': [self.generate_attribute(attribute) for attribute in self.interface.attributes],
|
| - # Size 0 constant array is not allowed in VC++
|
| - 'number_of_attributes': 'WTF_ARRAY_LENGTH(%sAttributes)' % v8_class_name(self.interface) if self.interface.attributes else '0',
|
| - 'attribute_templates': v8_class_name(self.interface) + 'Attributes' if self.interface.attributes else '0',
|
| + 'cpp_class_name': cpp_class_name,
|
| }
|
| - # Add includes afterwards, as they are modified by generate_attribute etc.
|
| - template_contents['header_includes'] = sorted(list(self.header_includes))
|
| - template_contents['cpp_includes'] = sorted(list(self.cpp_includes))
|
| + template_contents.update(self.generate_attributes())
|
| + template_contents['constants'] = generate_constants(self.interface)
|
| + # Add includes at the end, as they depend on attributes etc.
|
| + template_contents['header_includes'] = sorted(self.header_includes)
|
| + template_contents['cpp_includes'] = sorted(self.cpp_includes)
|
| return template_contents
|
|
|
| + def generate_cpp_to_js_conversion(self, data_type, cpp_value, format_string, isolate, creation_context=''):
|
| + """Returns a statement that converts a C++ value to a JS value.
|
| +
|
| + Also add necessary includes to self.cpp_includes.
|
| + """
|
| + self.cpp_includes |= v8_includes.includes_for_type(data_type)
|
| + # FIXME: Perl legacy, eliminate this
|
| + if (data_type not in ['DOMString', 'double', 'unsigned long long'] and
|
| + not v8_types.get_array_or_sequence_type(data_type)):
|
| + self.cpp_includes |= set(['wtf/GetPtr.h', 'wtf/RefPtr.h'])
|
| + js_value = cpp_value_to_js_value(data_type, cpp_value, isolate, creation_context)
|
| + return format_string % js_value
|
| +
|
| def generate_callback_interface(self):
|
| - self.header_includes = CALLBACK_INTERFACE_H_INCLUDES
|
| - self.header_includes |= includes_for_cpp_class(cpp_class_name(self.interface), self.relative_dir_posix)
|
| - self.cpp_includes = CALLBACK_INTERFACE_CPP_INCLUDES
|
| + cpp_class_name = implemented_as_cpp_name(self.interface)
|
| + self.header_includes = v8_includes.CALLBACK_INTERFACE_H_INCLUDES
|
| + self.header_includes |= v8_includes.includes_for_cpp_class(cpp_class_name, self.relative_dir_posix)
|
| + self.cpp_includes = v8_includes.CALLBACK_INTERFACE_CPP_INCLUDES
|
|
|
| def generate_argument(argument):
|
| receiver = 'v8::Handle<v8::Value> %sHandle = %%s;' % argument.name
|
| @@ -333,19 +205,20 @@ class CodeGeneratorV8:
|
| def argument_declaration(argument):
|
| return '%s %s' % (cpp_type(argument.data_type, 'raw'), argument.name)
|
|
|
| - arguments = []
|
| custom = 'Custom' in operation.extended_attributes
|
| - if not custom:
|
| - self.cpp_includes |= includes_for_operation(operation)
|
| + if custom:
|
| + arguments = []
|
| + else:
|
| if operation.data_type != 'boolean':
|
| raise Exception("We don't yet support callbacks that return non-boolean values.")
|
| + self.cpp_includes |= v8_includes.includes_for_operation(operation)
|
| arguments = [generate_argument(argument) for argument in operation.arguments]
|
| method = {
|
| 'return_cpp_type': cpp_type(operation.data_type, 'RefPtr'),
|
| 'name': operation.name,
|
| 'arguments': arguments,
|
| 'argument_declaration': ', '.join([argument_declaration(argument) for argument in operation.arguments]),
|
| - 'handles': ', '.join(['%sHandle' % argument.name for argument in operation.arguments]),
|
| + 'handles': ',\n'.join(['%sHandle' % argument.name for argument in operation.arguments]),
|
| 'custom': custom,
|
| }
|
| return method
|
| @@ -353,9 +226,31 @@ class CodeGeneratorV8:
|
| methods = [generate_method(operation) for operation in self.interface.operations]
|
| template_contents = {
|
| 'cpp_class_name': self.interface.name,
|
| - 'v8_class_name': v8_class_name(self.interface),
|
| - 'cpp_includes': sorted(list(self.cpp_includes)),
|
| - 'header_includes': sorted(list(self.header_includes)),
|
| + 'cpp_includes': sorted(self.cpp_includes),
|
| + 'header_includes': sorted(self.header_includes),
|
| 'methods': methods,
|
| }
|
| return template_contents
|
| +
|
| +################################################################################
|
| +# WIP
|
| +################################################################################
|
| +
|
| + def generate_interface_wip(self):
|
| + template_contents = v8_interface_header.generate_header(self.interface)
|
| + template_contents.update(generate_implementation(self.interface))
|
| + template_contents['constants'] = generate_constants(self.interface)
|
| + return template_contents
|
| +
|
| +
|
| +def link_overloaded_functions(interface):
|
| + name_to_operations = {}
|
| + for operation in interface.operations:
|
| + name = operation.name
|
| + if not name:
|
| + operation.overloads = []
|
| + operation.overload_index = 0
|
| + continue
|
| + name_to_operations.setdefault(name, []).append(operation)
|
| + operation.overloads = name_to_operations[name]
|
| + operation.overload_index = len(name_to_operations[name])
|
|
|