| 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")
|
| +
|
| +
|
| +
|
| +
|
|
|