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]) |