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

Unified Diff: Source/bindings/scripts/code_generator_v8.py

Issue 17572008: WIP IDL compiler rewrite (Closed) Base URL: https://chromium.googlesource.com/chromium/blink@master
Patch Set: non-callback headers working Created 7 years, 6 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: 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
new file mode 100644
index 0000000000000000000000000000000000000000..20912339d6b22310c3f29b644b6d7a7c5c00cd3c
--- /dev/null
+++ b/Source/bindings/scripts/code_generator_v8.py
@@ -0,0 +1,986 @@
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+
+import os
+import os.path
+import sys
+import json
+import re
+
+import generate_bindings
+
+import pprint
+pp = pprint.PrettyPrinter(indent=2, width=80)
+
+
+_current_dir = os.path.dirname(os.path.realpath(__file__))
+# jinja2 is in chromium's third_party directory
+sys.path.append(os.path.join(_current_dir, *([os.pardir] * 4)))
+import jinja2
+
+
+### basic utility
+
+def pathsplit(path):
+ dirs = []
+ while True:
+ (dirname, basename) = os.path.split(path)
+ if basename=="":
+ break
+ dirs.append(basename)
+ path = dirname
+ dirs.reverse()
+ return dirs
+
+def abs2rel(path, basedir):
+ path_dirs = pathsplit(os.path.abspath(path))
+ basedir_dirs = pathsplit(os.path.abspath(basedir))
+ common_dirs = 0
+ for i in range(min(len(path_dirs), len(basedir_dirs))):
+ if path_dirs[i] != basedir_dirs[i]:
+ break
+ common_dirs += 1
+ relpath = []
+ for i in range(len(basedir_dirs)-common_dirs):
+ relpath.append("..")
+ relpath.extend(path_dirs[common_dirs:])
+ return os.sep.join(relpath)
+
+def get_path(dic, keys):
+ node = dic
+ for key in keys:
+ if key not in node:
+ return None
+ node = node[key]
+ return node
+
+def apply_template(path_to_template, params):
+ dirname, basename = os.path.split(path_to_template)
+ path_to_templates = os.path.join(_current_dir, "templates")
+ jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader([dirname, path_to_templates]))
+ template = jinja_env.get_template(basename)
+ return template.render(params)
+
+
+
+### subroutine for code generator
+
+def create_arguments(arguments):
+ return ", ".join([argument for argument in arguments if argument])
+
+def get_v8_class_name(interface):
+ return "V8" + interface.name
+
+def get_impl_name(interface):
+ implementedAs = interface.extended_attributes.get("ImplementedAs")
+ if implementedAs is not None:
+ return implementedAs
+ return interface.name
+
+def get_conditional_string(interface_or_attribute_or_operation):
+ conditional = interface_or_attribute_or_operation.extended_attributes.get("Conditional");
+ if conditional is None:
+ return ""
+ else:
+ operator = ""
+ if "&" in operator:
+ operator = "&"
+ if "|" in operator:
+ operator = "|"
+ if operator == "":
+ return "ENABLE(%s)" % conditional;
+ else:
+ # Avoid duplicated conditions.
+ conditions = dict([(expression, True) for expression in conditional.split(operator)])
+ return (operator + operator).join(["ENABLE(%s)" % expression for expression in sorted(conditions.keys())])
+
+def get_includes_for_type(type):
+ if skip_include_header(type):
+ return []
+
+ # Default includes
+ includes = []
+ if type == "EventListener":
+ includes.append("core/dom/EventListener.h")
+ elif type == "SerializedScriptValue":
+ includes.append("bindings/v8/SerializedScriptValue.h")
+ elif type == "any" or is_callback_function_type(type):
+ includes.append("bindings/v8/ScriptValue.h")
+ else:
+ includes.append("V8%s.h" % type)
+
+ # Additional includes
+ if type == "CSSStyleSheet":
+ includes.append("core/css/CSSImportRule.h")
+
+ if not is_dom_node_type(type):
+ includes.append("wtf/RefCounted.h")
+ includes.append("wtf/RefPtr.h")
+ includes.append("wtf/GetPtr.h")
+
+ print "[get_includes_for_type]", pp.pformat(includes)
+ return includes
+
+def get_includes_for_parameter(parameter):
+ includes = []
+ array_or_sequence_type = get_array_type(parameter.data_type) or get_sequence_type(parameter.data_type)
+ if array_or_sequence_type:
+ if is_ref_ptr_type(array_or_sequence_type):
+ includes += get_includes_for_type(array_or_sequence_type)
+ else:
+ includes += get_includes_for_type(parameter.data_type)
+ return includes
+
+
+def get_includes_for_operation(operation):
+ includes = get_includes_for_type(operation.data_type)
+ for parameter in operation.parameters:
+ includes += get_includes_for_parameter(parameter)
+ return includes
+
+def link_overloaded_functions(interface):
+ name_to_operations = {}
+ for operation in interface.functions:
+ name = operation.name
+ if not name:
+ operation.overloads = []
+ operation.overload_index = 0
+ continue
+ if name not in name_to_operations:
+ name_to_operations[name] = []
+ name_to_operations[name].append(operation)
+ operation.overloads = name_to_operations[name]
+ operation.overload_index = len(name_to_operations[name])
+
+def apply_conditional(operation_or_attribute, code):
+ conditional_string = get_conditional_string(operation_or_attribute)
+ if conditional_string:
+ wrapped_code = "#if %s\n" % conditional_string
+ wrapped_code += code
+ wrapped_code += "#endif // %s\n" % conditional_string
+ return wrapped_code
+ else:
+ return code
+
+def get_namespace_for_interface(interface):
+ if is_typed_array_type(interface.name):
+ return "WTF"
+ return "WebCore"
+
+
+### Types
+
+# IDL type: [element's C++ type, V8 type]
+typed_arrays = {
+ "ArrayBuffer": [],
+ "ArrayBufferView": [],
+ "Uint8Array": ["unsigned char", "v8::kExternalUnsignedByteArray"],
+ "Uint8ClampedArray": ["unsigned char", "v8::kExternalPixelArray"],
+ "Uint16Array": ["unsigned short", "v8::kExternalUnsignedShortArray"],
+ "Uint32Array": ["unsigned int", "v8::kExternalUnsignedIntArray"],
+ "Int8Array": ["signed char", "v8::kExternalByteArray"],
+ "Int16Array": ["short", "v8::kExternalShortArray"],
+ "Int32Array": ["int", "v8::kExternalIntArray"],
+ "Float32Array": ["float", "v8::kExternalFloatArray"],
+ "Float64Array": ["double", "v8::kExternalDoubleArray"],
+}
+
+primitive_types = {
+ "boolean": True,
+ "void": True,
+ "Date": True,
+ "byte": True,
+ "octet": True,
+ "short": True,
+ "long": True,
+ "long long": True,
+ "unsigned short": True,
+ "unsigned long": True,
+ "unsigned long long": True,
+ "float": True,
+ "double": True,
+}
+
+enum_types = {
+}
+
+callback_function_types = {
+}
+
+non_wrapper_types = {
+ "CompareHow": True,
+ "DOMTimeStamp": True,
+ "Dictionary": True,
+ "EventListener": True,
+ # FIXME: When EventTarget is an interface and not a mixin, fix this so that
+ # EventTarget is treated as a wrapper type.
+ "EventTarget": True,
+ "MediaQueryListListener": True,
+ "NodeFilter": True,
+ "SerializedScriptValue": True,
+ "any": True,
+}
+
+dom_node_types = {
+ "Attr": True,
+ "CDATASection": True,
+ "CharacterData": True,
+ "Comment": True,
+ "Document": True,
+ "DocumentFragment": True,
+ "DocumentType": True,
+ "Element": True,
+ "Entity": True,
+ "HTMLDocument": True,
+ "Node": True,
+ "Notation": True,
+ "ProcessingInstruction": True,
+ "ShadowRoot": True,
+ "SVGDocument": True,
+ "Text": True,
+ "TestNode": True,
+}
+
+def get_sequence_type(type):
+ matched = re.match("^sequence<([\w\d_\s]+)>.*", type)
+ if matched:
+ return matched.group(1)
+ return "";
+
+def get_array_type(type):
+ matched = re.match("^([\w\d_\s]+)\[\]", type)
+ if matched:
+ return matched.group(1)
+ return "";
+
+def is_wrapper_type(type):
+ if get_array_type(type):
+ return False
+ if get_sequence_type(type):
+ return False
+ if is_callback_function_type(type):
+ return False
+ if is_enum_type(type):
+ return False
+ if is_primitive_type(type):
+ return False
+ if type == "DOMString":
+ return False
+ return not non_wrapper_types.get(type);
+
+def is_typed_array_type(type):
+ return type in typed_arrays
+
+def is_primitive_type(type):
+ if type in primitive_types:
+ return True
+ return False
+
+def is_enum_type(type):
+ if type in enum_types:
+ return True
+ return False
+
+def is_callback_function_type(type):
+ if type in callback_function_types:
+ return True
+ return False
+
+def is_dom_node_type(type):
+ if type in dom_node_types:
+ return True
+ if re.match("/^HTML.*Element$/", type):
+ return True
+ if re.match("/^SVG.*Element$/", type):
+ return True
+ return False
+
+def skip_include_header(type):
+ if is_primitive_type(type):
+ return True
+ if is_enum_type(type):
+ return True
+ if is_callback_function_type(type):
+ return True
+ if type=="DOMString":
+ return True
+ return False
+
+def is_constructable(interface):
+ for name in ["CustomConstructor", "Constructor", "ConstructorTemplate"]:
+ if name in interface.extended_attributes:
+ return True
+ return False
+
+
+def has_custom_getter(extended_attributes):
+ return "Custom" in extended_attributes or "CustomGetter" in extended_attributes
+
+def has_custom_setter(extended_attributes):
+ return "Custom" in extended_attributes or "CustomSetter" in extended_attributes
+
+def has_custom_method(extended_attributes):
+ return "Custom" in extended_attributes
+
+def is_constructor_template(interface, template_name):
+ return interface.extended_attributes.get("ConstructorTemplate")==template_name
+
+def needs_opaque_root_for_gc(interface):
+ for name in ["GenerateIsReachable", "CustomIsReachable"]:
+ if name in interface.extended_attributes:
+ return True
+ return False
+
+# URL becomes url, but SetURL becomes setURL.
+def to_method_name(name):
+ new_name = name[0].lower() + name[1:]
+ for keyword in ["HTML", "URL", "JS", "XML", "XSLT", "CSS", ]:
+ keyword_lcfirst = keyword[0].lower() + name[1:]
+ new_name = re.sub("/^"+keyword_lcfirst+"/", keyword, new_name)
+
+ # For HTML5 FileSystem API Flags attributes.
+ # (create is widely used to instantiate an object and must be avoided.)
+ new_name = re.sub("/^create$/", "isCreate", new_name)
+ new_name = re.sub("/^exclusive$/", "isExclusive", new_name)
+
+ return new_name
+
+# Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
+def get_runtime_enable_function_name(interface_or_attribute_or_function):
+ # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method.
+ enabled_at_runtime = interface_or_attribute_or_function.extended_attributes.get("EnabledAtRuntime")
+ if enabled_at_runtime:
+ return "RuntimeEnabledFeatures::%sEnabled" % to_method_name(enabled_at_runtime)
+
+ # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled().
+ return "RuntimeEnabledFeatures::%sEnabled" % to_method_name(interface_or_attribute_or_function.name)
+
+def requires_custom_signature(function):
+ # No signature needed for Custom function
+ if has_custom_method(function.extended_attributes):
+ return False
+ # No signature needed for overloaded function
+ if len(function.overloads) > 1:
+ return False
+ if function.is_static:
+ return False
+ # Type checking is performed in the generated code
+ if function.extended_attributes.get("StrictTypeChecking"):
+ return False
+ for parameter in function.parameters:
+ if parameter.is_optional and not parameter.extended_attributes.get("Default") or is_callback_interface(parameter.type):
+ return False
+
+ for parameter in function.parameters:
+ if is_wrapper_type(parameter.type):
+ return True
+ return False
+
+def is_standard_function(interface, function):
+ for key in ["Unforgeable", "EnabledAtRuntime", "EnabledPerContext", "DoNotCheckSignature", "NotEnumerable", "ReadOnly"]:
+ if function.extended_attributes.get(key):
+ return False
+ if function.is_static:
+ return False
+ if requires_custom_signature(function):
+ return False
+ if function.extended_attributes.get("DoNotCheckSecurity") and interface.extended_attributes.get("CheckSecurity") or interface.name == "Window":
+ return False
+ return True
+
+
+
+###
+
+
+### main
+class code_generator_v8:
+ def __init__(self, document, idl_directories, dependent_idl_files, options):
+ self.document = document
+ self.dependent_idl_files = dependent_idl_files
+ self.idl_directories = idl_directories
+ self.idl_files = {}
+ self.options = options
+ self.header = ""
+ self.implementation = ""
+ self.cached_interfaces = {}
+
+ enum_types = dict([ [enum["name"], enum["values"]] for enum in self.document.enumerations ])
+# print "enum_types", pp.pformat(enum_types)
+ callback_function_types = dict([ [enum["name"], enum] for enum in self.document.callback_functions ])
+ self.prepare_idl_files()
+
+ def prepare_idl_files(self):
+ directories = [ os.getcwd() + os.sep + directory for directory in self.idl_directories ]
+ directories = filter(lambda path: os.path.isdir(path), directories)
+ directories.append(".")
+# print "[prepare_idl_files] directories", directories
+ for idl_file in self.dependent_idl_files:
+ basename, ext = os.path.splitext(os.path.basename(idl_file))
+ self.idl_files[basename] = idl_file
+ # print("[idl_files]", idl_files)
+ for directory in directories:
+ for root, dirs, files in os.walk(directory):
+ for file in files:
+ basename, ext = os.path.splitext(file)
+ if ext==".idl":
+ fullpath = root + os.sep + file
+ self.idl_files[basename] = fullpath
+# for key, value in enumerate(self.idl_files):
+# print("[idl_files]", key, value)
+
+ def idl_file_for_interface(self, interface_name):
+ # print "[idl_file_for_interface]", interface_name, len(idl_files)
+ # print("[idl_files]", idl_files)
+ return self.idl_files.get(interface_name)
+
+ def parse_interface(self, interface_name):
+ if interface_name in self.cached_interfaces:
+ self.cached_interfaces[interface_name]
+
+ # Step #1: Find the IDL file associated with 'interface'
+ filename = self.idl_file_for_interface(interface_name)
+ if filename is None:
+ raise Exception("Could NOT find IDL file for interface \"%s\"" % interface_name);
+
+ if self.options.verbose:
+ print " | |> Parsing parent IDL \"%s\" for interface \"%s\"" % (filename, interface_name)
+
+ # Step #2: Parse the found IDL file (in quiet mode).
+ document = generate_bindings.read_pickled_idl(interface_name)
+ for interface in document.interfaces:
+ if interface.name == interface_name or interface.is_partial:
+ self.cached_interfaces[interface_name] = interface
+ return interface
+
+ raise Exception("Could NOT find interface definition for %s in %s" % (interface_name, filename));
+
+ def for_all_parents(self, interface):
+ for direct_parent_interface_name in interface.parents:
+ direct_parent_interface = self.parse_interface(direct_parent_interface_name)
+ yield direct_parent_interface
+ for parent_interface in self.for_all_parents(direct_parent_interface):
+ yield parent_interface
+
+ def inherits_interface(self, interface, interface_name):
+ if interface.name == interface_name:
+ return True
+ for parent_interface in self.for_all_parents(self.interface):
+ if parent_interface.name == interface_name:
+ return True
+ return False
+
+ def interface_inherits_extended_attribute(self, interface, extended_attribute):
+ if extended_attribute in interface.extended_attributes:
+ return True
+ for parent_interface in self.for_all_parents(interface):
+ if extended_attribute in parent_interface.extended_attributes:
+ return True
+ return False
+
+
+ def get_parameter_declaration(self, operation):
+ parameters = [ "%s %s" % (self.get_native_type(parameter.data_type, used_as_parameter=True, called_by_webcore=True), parameter.name) for parameter in operation.parameters ]
+ return ", ".join(parameters)
+
+ def get_native_to_js_value(self, type, extended_attributes, native_value, indent, receiver, creation_context, \
+ isolate, holder_container="", script_wrappable="", return_handle_type="", for_main_world_suffix="", return_value_arg=""):
+ """
+ Create statement which convert native(C++) value into JS value.
+
+ @param[in] type
+ @param[in] extended_attributes
+ @param[in] native_value
+ @param[in] indent
+ @param[in] receiver must contain one "%s". to return something: v8SetReturnValue(<holder_container>, %s);
+ @param[in] creation_context
+ @param[in] isolate
+ @param[in] holder_container
+ @param[in] script_wrappable
+ @param[in] return_handle_type
+ @param[in] for_main_world_suffix
+ @param[in] return_value_arg
+ """
+ def create_statement(js_value):
+ return indent + receiver % js_value
+
+ if not isolate:
+ raise Exception("An Isolate is mandatory for native value => JS value conversion.")
+
+ # long long and unsigned long long are not representable in ECMAScript.
+ if type == "long long" or type == "unsigned long long" or type == "DOMTimeStamp":
+ return create_statement("v8::Number::New(static_cast<double>(%s))" % native_value)
+
+ if is_primitive_type(type):
+ if not (type=="float" or type=="double"):
+ raise Exception("unexpected type %s" % type)
+ return create_statement("v8::Number::New(%s)" % native_value)
+
+ if type=="DOMString" or is_enum_type(type):
+ conversion = extended_attributes.get("TreatReturnedNullStringAs")
+ js_value = ""
+ arguments = create_arguments([native_value, isolate, return_handle_type])
+ if conversion is None:
+ js_value = "v8String(%s)" % arguments
+ elif conversion == "Null":
+ js_value = "v8StringOrNull(%s)" % arguments
+ elif conversion == "Undefined":
+ js_value = "v8StringOrUndefined(%s)" % arguments
+ else:
+ raise Exception("Unknown value for TreatReturnedNullStringAs extended attribute")
+
+ # FIXME: Use safe handles
+ return create_statement(js_value)
+
+ # FIXME: Use safe handles
+ return create_statement("toV8(%s, %s, %s)" % (native_value, creation_context, isolate))
+
+ def get_native_type(self, type, called_by_webcore=False, used_as_parameter=False):
+ """
+ Return native type corresponds to IDL type.
+ @param[in] type
+ @param[in] called_by_webcore
+ @param[in] used_as_parameter
+ """
+ print "[get_native_type]", type
+ if type=="float":
+ return "float"
+ if type=="double":
+ return "double"
+ if type=="int" or type=="long" or type=="short" or type=="byte":
+ return "int"
+ if type=="unsigned long" or type=="unsigned int" or type=="unsigned short" or type=="octet":
+ return "unsigned"
+ if type=="long long":
+ return "long long"
+ if type=="unsigned long long":
+ return "unsigned long long"
+ if type=="boolean":
+ return "bool"
+ if type=="DOMString":
+ if used_as_parameter:
+ if called_by_webcore:
+ return "const String&"
+ else:
+ return "V8StringResource"
+ return "String"
+ # We need to check [ImplementedAs] extended attribute for wrapper types.
+ if is_wrapper_type(type):
+ interface = self.parse_interface(type)
+ type = get_impl_name(interface)
+
+ if used_as_parameter:
+ if called_by_webcore:
+ return type + "*"
+ else:
+ return "PassRefPtr<%s>" % type
+ else:
+ return "RefPtr<%s>" % type
+
+
+ def header_files_for_interface(self, interface_name, impl_class_name):
+# print "[header_files_for_interface]", interface_name, impl_class_name
+ includes = []
+ if is_typed_array_type(interface_name):
+ includes.append("wtf/%s.h" % interface_name)
+ elif not skip_include_header(interface_name):
+ idl_filename = self.idl_file_for_interface(interface_name)
+ assert idl_filename
+ idlRelPath = "bindings/" + abs2rel(idl_filename, os.getcwd())
+# print "idlRelPath", idl_filename, idlRelPath, os.getcwd()
+ includes.append(os.path.dirname(idlRelPath) + os.sep + impl_class_name + ".h")
+ print "[header_files_for_interface] result", pp.pformat(includes)
+ return includes
+
+ def generate_interface(self, interface):
+ self.interface = interface
+
+ self.common_template_parameters = {
+ "conditional_if": "",
+ "conditional_endif": "",
+ }
+ conditional_string = get_conditional_string(self.interface)
+ if conditional_string != "":
+ self.common_template_parameters["conditional_if"] = "#if " + conditional_string
+ self.common_template_parameters["conditional_endif"] = "#endif // " + conditional_string
+
+ if self.options.no_h is None:
+ if interface.is_callback:
+ self.generate_callback_header()
+ else:
+ self.generate_header()
+
+ if self.options.no_cpp is None:
+ if interface.is_callback:
+ self.generate_callback_implementation()
+ else:
+ self.generate_implementation()
+
+ def write_interfaces(self):
+ for interface in self.document.interfaces:
+ self.generate_interface(interface)
+ self.write_data()
+
+ def write_data(self):
+ """
+ options.output_directory
+ options.output_headers_directory
+ """
+# print self.header
+ if self.options.no_h is None:
+ header_filename = self.options.output_headers_directory + os.sep + get_v8_class_name(self.interface) + ".h"
+ with open(header_filename, "w") as f:
+ f.write(self.header)
+
+ if self.options.no_cpp is None:
+ implementation_filename = self.options.output_directory + os.sep + get_v8_class_name(self.interface) + ".cpp"
+ with open(implementation_filename, "w") as f:
+ f.write(self.implementation)
+
+
+
+ def generate_to_v8_converters(self, interface, v8_class_name, impl_class_name_as_parameter):
+ includes = []
+ code = ""
+ if interface.extended_attributes.get("DoNotGenerateWrap") or interface.extended_attributes.get("DoNotGenerateToV8"):
+ return includes, code
+ includes.append("bindings/v8/ScriptController.h")
+ includes.append("core/page/Frame.h")
+ # TODO.....
+ return includes, code
+
+
+ def generate_callback_header(self):
+ impl_class_name = get_impl_name(self.interface);
+ v8_class_name = get_v8_class_name(self.interface);
+
+ template_parameters = self.common_template_parameters.copy()
+ template_parameters.update({
+ "interface_name": self.interface.name,
+ "impl_class_name": impl_class_name,
+ "v8_class_name": v8_class_name,
+ "includes": [
+ "bindings/v8/ActiveDOMCallback.h",
+ "bindings/v8/DOMWrapperWorld.h",
+ "bindings/v8/ScopedPersistent.h",
+ ],
+ "class_public_definitions": [],
+ })
+ template_parameters["includes"].extend(self.header_files_for_interface(self.interface.name, impl_class_name))
+ template_parameters["includes"].sort()
+ for operation in self.interface.functions:
+ code = "virtual %s %s(%s);" % (self.get_native_type(operation.data_type), operation.name, self.get_parameter_declaration(operation))
+ template_parameters["class_public_definitions"].append(code)
+
+ self.header = apply_template("scripts/callbackHeader.template", template_parameters)
+
+ def generate_callback_implementation(self):
+# pp.pprint(self.interface)
+ impl_class_name = get_impl_name(self.interface);
+ v8_class_name = get_v8_class_name(self.interface);
+
+ template_parameters = self.common_template_parameters.copy()
+ template_parameters.update({
+ "interface_name": self.interface.name,
+ "impl_class_name": impl_class_name,
+ "v8_class_name": v8_class_name,
+ "main_includes": [
+ v8_class_name+".h",
+ ],
+ "sub_includes": [
+ "core/dom/ScriptExecutionContext.h",
+ "bindings/v8/V8Binding.h",
+ "bindings/v8/V8Callback.h",
+ "wtf/Assertions.h",
+ ],
+ "class_public_definitions": [],
+ "web_core_definitions": [],
+ })
+
+ template_parameters["interface_name"] = self.interface.name
+
+ for operation in self.interface.functions:
+ code = {}
+ if "Custom" in operation.extended_attributes:
+ continue
+ template_parameters["sub_includes"] += get_includes_for_operation(operation)
+ if operation.data_type != "boolean":
+ raise Exception("We don't yet support callbacks that return non-boolean values.")
+ code["signature"] = "%s %s::%s(%s)" % (self.get_native_type(operation.data_type), v8_class_name, operation.name, self.get_parameter_declaration(operation))
+
+ prepare_parameter_statements = []
+ code["prepare_js_parameters"] = ""
+ for parameter in operation.parameters:
+ receiver = "v8::Handle<v8::Value> %sHandle = %%s;" % parameter.name
+ subcode = self.get_native_to_js_value(parameter.data_type, parameter.extended_attributes, parameter.name, "", receiver, "v8::Handle<v8::Object>()", "isolate", "") + "\n"
+ subcode += "if (%sHandle.IsEmpty()) {\n" % parameter.name
+ subcode += " if (!isScriptControllerTerminating())\n"
+ subcode += " CRASH();\n"
+ subcode += " return true;\n"
+ subcode += "}\n"
+ code["prepare_js_parameters"] += subcode
+ prepare_parameter_statements.append(" %sHandle" % parameter.name)
+
+ if len(prepare_parameter_statements) > 0:
+ subcode = "v8::Handle<v8::Value> argv[] = {\n";
+ subcode += ",\n".join(prepare_parameter_statements)
+ subcode += "\n};";
+ code["prepare_js_parameters"] += subcode
+ else:
+ code["prepare_js_parameters"] += "v8::Handle<v8::Value> *argv = 0;"
+
+ code["number_of_parameters"] = len(operation.parameters)
+ template_parameters["web_core_definitions"].append(code)
+
+ template_parameters["sub_includes"] = list(set(template_parameters["sub_includes"]))
+ template_parameters["sub_includes"].sort()
+ self.implementation = apply_template("scripts/callbackImplementation.template", template_parameters)
+
+ def get_internal_fields(self):
+ custom_internal_fields = []
+ # Event listeners on DOM nodes are explicitly supported in the GC controller.
+ if not self.inherits_interface(self.interface, "Node") and self.interface_inherits_extended_attribute(self.interface, "EventTarget"):
+ custom_internal_fields.append("eventListenerCacheIndex")
+ return custom_internal_fields
+
+ def generate_header_custom_internal_field_indices(self):
+ custom_internal_fields = self.get_internal_fields()
+ codes = []
+ custom_field_counter = 0
+ for custom_internal_field in custom_internal_fields:
+ codes.append("static const int %s = v8DefaultWrapperInternalFieldCount + %d;" % (custom_internal_field, custom_field_counter))
+ custom_field_counter += 1
+ codes.append("static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + %d;" % custom_field_counter)
+ return codes
+
+ def generate_header(self):
+ impl_class_name = get_impl_name(self.interface);
+ v8_class_name = get_v8_class_name(self.interface);
+
+ template_parameters = self.common_template_parameters.copy()
+ template_parameters.update({
+ "interface_name": self.interface.name,
+ "impl_class_name": impl_class_name,
+ "v8_class_name": v8_class_name,
+ "impl_class_name_as_parameter": self.get_native_type(self.interface.name, used_as_parameter=True),
+ "is_constructor_template_of_event": is_constructor_template(self.interface, "Event"),
+ "needs_opaque_root_for_gc": needs_opaque_root_for_gc(self.interface),
+ "inherits_extended_attribute_active_dom_object": self.interface_inherits_extended_attribute(self.interface, "ActiveDOMObject"),
+ "inherits_extended_attribute_event_target": self.interface_inherits_extended_attribute(self.interface, "EventTarget"),
+ "is_constructable": is_constructable(self.interface),
+ "custom_internal_field_indices": self.generate_header_custom_internal_field_indices(),
+ "includes": [
+ "bindings/v8/WrapperTypeInfo.h",
+ "bindings/v8/V8Binding.h",
+ "bindings/v8/V8DOMWrapper.h",
+ ],
+ "operation_definitions": [],
+ "attribute_definitions": [],
+ })
+
+ link_overloaded_functions(self.interface);
+
+ # Ensure the IsDOMNodeType function is in sync.
+ if is_dom_node_type(self.interface.name) != self.inherits_interface(self.interface, "Node"):
+ inh = self.inherits_interface(self.interface, "Node") and "INHERIT" or ""
+ dom = is_dom_node_type(self.interface.name) and "DOM" or ""
+ print "[IsDOMNodeType]", dom, inh
+ raise Exception("IsDOMNodeType is out of date with respect to %s" % self.interface.name)
+
+ print "Parents", pp.pformat(self.interface.parents)
+ for parent_interface_name in self.interface.parents:
+# print "ADD H", parent_interface_name
+ template_parameters["includes"].append("V8%s.h" % parent_interface_name)
+
+ # TODO Window
+
+ enabled_per_context_functions = [ operation for operation in self.interface.functions if operation.name and operation.extended_attributes.get("EnabledPerContext") ]
+ enabled_per_context_attributes = [ attribute for attribute in self.interface.attributes if attribute.extended_attributes.get("EnabledPerContext") ]
+
+ for operation in self.interface.functions:
+ if not operation.name:
+ continue
+ if has_custom_method(operation.extended_attributes) and operation.overload_index==1:
+ code = "static void %sMethodCustom(const v8::FunctionCallbackInfo<v8::Value>&);" % operation.name
+ template_parameters["operation_definitions"].append(apply_conditional(operation, code))
+
+ for attribute in self.interface.attributes:
+ if has_custom_getter(attribute.extended_attributes):
+ code = "static void %sAttrGetterCustom(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>&);" % attribute.name
+ template_parameters["attribute_definitions"].append(apply_conditional(attribute, code))
+ if has_custom_setter(attribute.extended_attributes):
+ code = "static void %sAttrSetterCustom(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<void>&);" % attribute.name
+ template_parameters["attribute_definitions"].append(apply_conditional(attribute, code))
+
+
+
+
+
+
+
+ # TODO HasCustomConstructor
+
+ # TODO GenerateHeaderNamedAndIndexedPropertyAccessors
+ # TODO GenerateHeaderLegacyCall
+
+ # TODO Window
+
+ template_parameters["install_per_context_properties_body"] = len(enabled_per_context_attributes) > 0 and ";" or " { }"
+ template_parameters["install_per_context_prototype_properties_body"] = len(enabled_per_context_functions) > 0 and ";" or " { }"
+
+ # TODO HTMLElement
+ # TODO SVGElement
+ # TODO HTMLUnknownElement
+ # TODO Element
+
+ no_to_v8 = "DoNotGenerateToV8" in self.interface.extended_attributes
+ no_wrap = "DoNotGenerateWrap" in self.interface.extended_attributes or no_to_v8
+ template_parameters["wrap"] = not no_wrap
+ template_parameters["custom_wrap"] = custom_wrap = "CustomToV8" in self.interface.extended_attributes
+ if no_to_v8:
+ if len(list(self.for_all_parents(self.interface))) > 0:
+ raise Exception("Can't suppress toV8 for subclass")
+ elif no_wrap:
+ if not custom_wrap:
+ raise Exception("Must have custom toV8")
+ template_parameters["generate_to_v8"] = True
+
+ template_parameters["includes"].extend(self.header_files_for_interface(self.interface.name, impl_class_name))
+ template_parameters["includes"] = list(set(template_parameters["includes"]))
+ template_parameters["includes"].sort()
+
+ self.header = apply_template("scripts/header.template", template_parameters)
+
+ # __IMPL__
+ def generate_implementation(self):
+ impl_class_name = get_impl_name(self.interface);
+ v8_class_name = get_v8_class_name(self.interface);
+
+ normal_functions = []
+ enabled_per_context_functions = []
+ for operation in self.interface.functions:
+ if operation.name=="":
+ continue
+ if operation.extended_attributes.get("EnabledPerContext"):
+ enabled_per_context_functions.append(operation)
+ else:
+ normal_functions.append(operation)
+ has_callbacks = False
+ for operation in normal_functions:
+ # Only one table entry is needed for overloaded methods:
+ if operation.overload_index > 1:
+ continue
+ # Don't put any nonstandard functions into this table:
+ if not is_standard_function(self.interface, operation):
+ continue
+ has_callbacks = True
+
+
+
+ inherits_extended_attribute_active_dom_object = self.interface_inherits_extended_attribute(self.interface, "ActiveDOMObject")
+ inherits_extended_attribute_event_target = self.interface_inherits_extended_attribute(self.interface, "EventTarget")
+ has_attributes = len(self.interface.attributes) > 0
+ impl_class_name_as_parameter = self.get_native_type(self.interface.name, used_as_parameter=True)
+
+ template_parameters = self.common_template_parameters.copy()
+ template_parameters.update({
+ "interface_name": self.interface.name,
+ "impl_class_name": impl_class_name,
+ "v8_class_name": v8_class_name,
+ "impl_class_name_as_parameter": impl_class_name_as_parameter,
+ "is_constructor_template_of_event": is_constructor_template(self.interface, "Event"),
+ "needs_opaque_root_for_gc": needs_opaque_root_for_gc(self.interface),
+ "inherits_extended_attribute_active_dom_object": inherits_extended_attribute_active_dom_object,
+ "inherits_extended_attribute_event_target": inherits_extended_attribute_event_target,
+ "is_constructable": is_constructable(self.interface),
+ "custom_internal_field_indices": self.generate_header_custom_internal_field_indices(),
+ "namespace_for_interface": get_namespace_for_interface(self.interface),
+ "wrapper_type_prototype": self.interface.is_exception and "WrapperTypeErrorPrototype" or "WrapperTypeObjectPrototype",
+ "enabled_at_runtime": "EnabledAtRuntime" in self.interface.extended_attributes,
+ "enable_function": get_runtime_enable_function_name(self.interface),
+ "configure_template_batched_attribute": has_attributes and v8_class_name + "Attrs" or "0",
+ "configure_template_attribute_count": has_attributes and "WTF_ARRAY_LENGTH(%sAttrs)" % v8_class_name or "0",
+ "configure_template_batched_method": has_callbacks and v8_class_name + "Methods" or "0",
+ "configure_template_method_count": has_callbacks and "WTF_ARRAY_LENGTH(%sMethods)" % v8_class_name or "0",
+ "includes": [
+ "bindings/v8/V8Binding.h",
+ "bindings/v8/V8DOMWrapper.h",
+ "core/dom/ContextFeatures.h",
+ "core/dom/Document.h",
+ "RuntimeEnabledFeatures.h",
+ "wtf/UnusedParam.h",
+ ],
+ "operation_definitions": [],
+ "attribute_definitions": [],
+ })
+ template_parameters["to_active_dom_object"] = inherits_extended_attribute_active_dom_object and v8_class_name + "::toActiveDOMObject" or "0"
+ template_parameters["to_event_target"] = inherits_extended_attribute_event_target and v8_class_name + "::toEventTarget" or "0"
+ template_parameters["root_for_gc"] = needs_opaque_root_for_gc(self.interface) and v8_class_name + "::opaqueRootForGC" or "0"
+
+ self.generate_to_v8_converters(self.interface, v8_class_name, impl_class_name_as_parameter)
+
+ template_parameters["includes"] += get_includes_for_type(self.interface.name)
+
+ parent_class_name = ""
+ parent_class_template = ""
+ if len(self.interface.parents) > 0:
+ parent_interface_name = self.interface.parents[0]
+ parent_class_name = "V8" + parent_interface_name
+ print "ADD H", parent_interface_name
+ template_parameters["includes"].append("V8%s.h" % parent_interface_name)
+ parent_class_template = parent_class_name + "::GetTemplate(isolate, currentWorldType)"
+
+ template_parameters["parent_class_info"] = parent_class_info = parent_class_name and "&%s::info" % parent_class_name or "0"
+ template_parameters["parent_class_template"] = parent_class_template
+
+ template_parameters["includes"] = filter(lambda include: include != v8_class_name+".h", list(set(template_parameters["includes"])))
+ template_parameters["includes"].sort()
+ self.implementation = apply_template("scripts/implementation.template", template_parameters)
+
+
+
+if __name__ == '__main__':
+ # HTMLTitleElement
+ doc = json.loads("""
+ {"idlDocument::callbackFunctions":[],"idlDocument::enumerations":[],"idlDocument::fileName":"/mnt/hdd/chromium/src/third_party/WebKit/Source/core/html/HTMLTitleElement.idl","idlDocument::interfaces":[{"domInterface::attributes":[{"domAttribute::extendedAttributes":{"TreatNullAs":"NullString"},"domAttribute::getterExceptions":[],"domAttribute::isNullable":null,"domAttribute::isReadOnly":null,"domAttribute::isStatic":null,"domAttribute::name":"text","domAttribute::setterExceptions":[],"domAttribute::type":"DOMString"}],"domInterface::constants":[],"domInterface::constructors":[],"domInterface::customConstructors":[],"domInterface::extendedAttributes":{},"domInterface::isCallback":null,"domInterface::isException":null,"domInterface::isPartial":null,"domInterface::name":"HTMLTitleElement","domInterface::operations":[],"domInterface::parents":["HTMLElement"]}]}
+ """)
+ # print("HTMLTitleElement")
+ # pp.pprint(doc)
+
+ # VoidCallback
+ doc = json.loads("""
+ {"idlDocument::callbackFunctions":[],"idlDocument::enumerations":[],"idlDocument::fileName":"/mnt/hdd/chromium/src/third_party/WebKit/Source/core/html/VoidCallback.idl","idlDocument::interfaces":[{"domInterface::attributes":[],"domInterface::constants":[],"domInterface::constructors":[],"domInterface::customConstructors":[],"domInterface::extendedAttributes":{},"domInterface::functions":[{"domFunction::extendedAttributes":{},"domFunction::isStatic":null,"domFunction::name":"handleEvent","domFunction::overloadedIndex":null,"domFunction::parameters":[],"domFunction::specials":[],"domFunction::type":"boolean"}],"domInterface::isCallback":1,"domInterface::isException":null,"domInterface::isPartial":null,"domInterface::name":"VoidCallback","domInterface::parents":[]}]}
+ """)
+ # print("VoidCallback")
+ # pp.pprint(doc)
+
+ cg = code_generator_v8(doc, ["../modules"], ["/mnt/hdd/chromium/src/third_party/WebKit/Source/core/html/VoidCallback.idl"])
+ for interface in doc["idlDocument::interfaces"]:
+ cg.generate_interface(interface)
+ cg.write_data()
+
+
+ def test_abs2rel(a, b, ref):
+ result = abs2rel(a, b)
+ assert result==ref, "abs2rel(%s, %s) should be %s but actually %s" % (a, b, ref, result)
+
+ test_abs2rel("./a/b/c", ".", "a/b/c")
+ test_abs2rel("/a/b/c", "/a/b/d", "../c")
+
+
+
+
« no previous file with comments | « Source/bindings/scripts/callbackImplementation.template ('k') | Source/bindings/scripts/generate-bindings.pl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698