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

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

Issue 19607011: Generate binding code for VoidCallback.idl with code generator in python (Closed) Base URL: https://chromium.googlesource.com/chromium/blink@master
Patch Set: Created 7 years, 5 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
index d2f933044a5a171b5f1109ef2dc94fa95f660842..a7f00c03085f9e4c54cdad094e9600ea1909ac82 100644
--- a/Source/bindings/scripts/code_generator_v8.py
+++ b/Source/bindings/scripts/code_generator_v8.py
@@ -26,16 +26,860 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Generate Blink V8 bindings (.h and .cpp files).
+"""
+Generate Blink V8 bindings (.h and .cpp files).
Input: An object of class IdlDefinitions, containing an IDL interface X
Output: V8X.h and V8X.cpp
-
-FIXME: Currently a stub, as part of landing the parser and code generator
-incrementally. Only implements generation of dummy .cpp and .h files.
"""
+import os
import os.path
Nils Barth (inactive) 2013/07/24 11:41:20 If you import os, you don't need to also import os
Nils Barth (inactive) 2013/07/25 03:30:54 For manipulating paths for C++ #include statements
+import sys
+import re
+
+import idl_definitions
+import idl_reader
+
+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)))
Nils Barth (inactive) 2013/07/24 11:41:20 Slick! Maybe a bit too slick (compared with just l
kojih 2013/07/25 09:08:37 I'll use code below from blink_idl_parser.py: mod
+import jinja2
+
+
+def pathsplit(path):
+ dirs = []
+ while True:
+ (dirname, basename) = os.path.split(path)
+ if basename == "":
+ break
+ dirs.append(basename)
do-not-use 2013/07/24 11:17:59 Or we could simply dir.insert(0, baseline) to avoi
kojih 2013/07/25 09:08:37 I'll use dir.insert(0, basename) here.
+ path = dirname
+ dirs.reverse()
+ return dirs
do-not-use 2013/07/24 10:56:20 return reversed(dirs) ?
+
+
+def abs2rel(path, basedir):
Nils Barth (inactive) 2013/07/25 03:30:54 os.path.relpath ...or rather: posixpath.relpath ..
kojih 2013/07/25 09:08:37 Oh thanks!
+ 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 = []
Nils Barth (inactive) 2013/07/25 03:30:54 Naming-wise (if we still need this), relpath_dirs,
+ for i in range(len(basedir_dirs) - common_dirs):
+ relpath.append("..")
Nils Barth (inactive) 2013/07/24 11:41:20 os.pardir instead of '..' ?
+ relpath.extend(path_dirs[common_dirs:])
+ return os.sep.join(relpath)
do-not-use 2013/07/24 10:56:20 Shouldn't this be '/'.join(relpath)? We don't want
+
+
+def get_path(dic, keys):
do-not-use 2013/07/24 10:56:20 This function is a bit obscure and does not appear
+ 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(trim_blocks=True, loader=jinja2.FileSystemLoader([dirname, path_to_templates]))
+ template = jinja_env.get_template(basename)
+ return template.render(params)
+
+
+def create_arguments(arguments):
do-not-use 2013/07/24 11:17:59 something like create_arguments_string(arguments)
kojih 2013/07/25 09:08:37 ok.
+ return ", ".join([argument for argument in arguments if argument])
+
+
+def get_v8_class_name(interface):
+ return "V8" + interface.name
+
+
+def get_impl_name(interface_or_function):
+ implementedAs = interface_or_function.extended_attributes.get("ImplementedAs")
+ if implementedAs is not None:
+ return implementedAs
+ return interface_or_function.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 conditional:
+ operator = "&"
+ if "|" in conditional:
+ operator = "|"
+ if operator == "":
+ return "ENABLE(%s)" % conditional
+ else:
+ # Avoid duplicated conditions.
+ conditions = dict([(expression, True) for expression in conditional.split(operator)])
do-not-use 2013/07/24 10:56:20 Can we use a set to avoid duplicated conditions?
kojih 2013/07/25 09:08:37 done.
+ return (" %s%s " % (operator, operator)).join(["ENABLE(%s)" % expression for expression in sorted(conditions.keys())])
+
+
+def get_includes_for_type(data_type):
+ if skip_include_header(data_type):
+ return []
+ includes = []
+ if data_type == "EventListener":
+ includes.append("core/dom/EventListener.h")
+ elif data_type == "SerializedScriptValue":
+ includes.append("bindings/v8/SerializedScriptValue.h")
+ elif data_type == "any" or is_callback_function_type(data_type):
+ includes.append("bindings/v8/ScriptValue.h")
+ else:
+ includes.append("V8%s.h" % data_type)
+ 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 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
+ if name not in name_to_operations:
do-not-use 2013/07/24 10:56:20 I believe you can write these 3 lines as one: name
+ name_to_operations[name] = []
+ name_to_operations[name].append(operation)
+ operation.overloads = name_to_operations[name]
+ operation.overload_index = len(name_to_operations[name])
do-not-use 2013/07/24 11:17:59 What is overload_index for? Seems it is just the l
kojih 2013/07/25 09:08:37 overload_index is identifier among set of overload
+
+
+def sort_and_remove_duplicate(includes):
+ return sorted(list(set(includes)))
+
+
+def get_pass_owner_expression(data_type, expression):
+ if is_ref_ptr_type(data_type):
+ return expression + ".release()"
+ return expression
+
+
+def get_convert_to_V8StringResource(attribute_or_parameter, native_type, native_variable_name, native_value):
+ if not re.match("^V8StringResource", native_type):
+ raise Exception("Wrong native data_type passed: %s" % native_type)
+ if attribute_or_parameter.data_type == "DOMString" or is_enum_type(attribute_or_parameter.data_type):
+ return "V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(%s, %s, %s);" % (native_type, native_variable_name, native_value)
+ else:
+ return "%s %s(%s, true);" % (native_type, native_variable_name, native_value)
+
+# IDL data_type: [element's C++ data_type, V8 data_type]
+typed_arrays = {
+ "ArrayBuffer": [],
+ "ArrayBufferView": [],
+ "Uint8Array": ["unsigned char", "v8::kExternalUnsignedByteArray"],
do-not-use 2013/07/24 10:56:20 Seems like we could use tuples instead of lists?
Nils Barth (inactive) 2013/07/25 03:30:54 Good point. We could even use dictionaries or obje
kojih 2013/07/25 09:08:37 I'll use class NativeTypeAndJSType
+ "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 = {
do-not-use 2013/07/24 10:56:20 Maybe we can use a set? We don't really need the a
kojih 2013/07/25 09:08:37 done.
+ "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 = {
Nils Barth (inactive) 2013/07/25 03:30:54 enum_types and callback_function_types should prop
kojih 2013/07/25 09:08:37 moved to CodeGeneratorV8.
+}
+
+callback_function_types = {
+}
+
+non_wrapper_types = {
do-not-use 2013/07/24 10:56:20 Ditto.
+ "CompareHow": True,
+ "DOMTimeStamp": True,
+ "Dictionary": True,
+ "EventListener": True,
+ "MediaQueryListListener": True,
+ "NodeFilter": True,
+ "SerializedScriptValue": True,
+ "any": True,
+}
+
+dom_node_types = {
do-not-use 2013/07/24 10:56:20 Ditto.
+ "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(data_type):
+ matched = re.match("^sequence<([\w\d_\s]+)>.*", data_type)
do-not-use 2013/07/24 10:56:20 Why do we accept whitespace in the sequence type?
Nils Barth (inactive) 2013/07/24 11:41:20 You need to use raw strings for regexes with backs
kojih 2013/07/25 09:08:37 whitespace is necessary to deal with "sequence<uns
kojih 2013/07/25 09:08:37 done.
+ if matched:
+ return matched.group(1)
+ return ""
do-not-use 2013/07/24 10:56:20 Why not return None?
+
+
+def get_array_type(data_type):
+ matched = re.match("^([\w\d_\s]+)\[\]", data_type)
do-not-use 2013/07/24 10:56:20 White space in array type?
+ if matched:
+ return matched.group(1)
+ return ""
do-not-use 2013/07/24 10:56:20 Ditto.
+
+
+def is_wrapper_type(data_type):
+ if is_union_type(data_type):
+ return False
+ if get_array_type(data_type):
+ return False
+ if get_sequence_type(data_type):
+ return False
+ if is_callback_function_type(data_type):
+ return False
+ if is_enum_type(data_type):
+ return False
+ if is_primitive_type(data_type):
+ return False
+ if data_type == "DOMString":
+ return False
Nils Barth (inactive) 2013/07/24 11:41:20 This long string of if's would be clearer as a sin
kojih 2013/07/25 09:08:37 ok.
+ return not non_wrapper_types.get(data_type)
+
+
+def is_typed_array_type(data_type):
+ return data_type in typed_arrays
+
+
+def is_ref_ptr_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto re: boolean expression
+ if is_union_type(data_type):
+ return False
+ if data_type == "any" or data_type == "DOMString":
+ return False
+ if is_primitive_type(data_type):
+ return False
+ if get_array_type(data_type):
+ return False
+ if get_sequence_type(data_type):
+ return False
+ if is_callback_function_type(data_type):
+ return False
+ if is_enum_type(data_type):
+ return False
+ return True
+
+
+def is_primitive_type(data_type):
+ if data_type in primitive_types:
Nils Barth (inactive) 2013/07/24 11:41:20 return data_type in primitive_types
+ return True
+ return False
+
+
+def is_enum_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
+ if data_type in enum_types:
+ return True
+ return False
+
+
+def is_callback_function_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
+ if data_type in callback_function_types:
+ return True
+ return False
+
+
+def is_union_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
+ if isinstance(data_type, idl_definitions.IdlUnionType):
+ return True
+ return False
+
+
+def skip_include_header(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
+ if is_primitive_type(data_type):
+ return True
+ if is_enum_type(data_type):
+ return True
+ if is_callback_function_type(data_type):
+ return True
+ if data_type == "DOMString":
+ return True
+ return False
+
+
+class code_generator_v8:
Nils Barth (inactive) 2013/07/25 03:30:54 Class names are in CamelCase: http://www.chromium.
+ def __init__(self, definitions, interface_name, output_directory, idl_directories, generate_h=True, generate_cpp=True, verbose=False):
+ global enum_types
+ global callback_function_types
+ self.idl_definitions = definitions
+ self.interface_name = interface_name
+ self.idl_directories = idl_directories
+ self.idl_files = {}
+ self.output_directory = output_directory
+ self.generate_h = generate_h
+ self.generate_cpp = generate_cpp
+ self.verbose = verbose
+ self.header = ""
+ self.implementation = ""
+ self.cached_interfaces = {}
+ self.common_template_parameters = {}
+ self.interface = None
+
+ enum_types = dict([[enum.name, enum.values] for enum in self.idl_definitions.enumerations.values()])
+ callback_function_types = self.idl_definitions.callback_functions
+ self.prepare_idl_files()
+
+ def prepare_idl_files(self):
+ directories = [os.getcwd() + os.sep + directory for directory in self.idl_directories]
+ directories = [path for path in directories if os.path.isdir(path)]
+ directories.append(".")
+ for directory in directories:
+ for root, _, filenames in os.walk(directory):
+ for filename in filenames:
+ basename, ext = os.path.splitext(filename)
+ if ext == ".idl":
+ fullpath = root + os.sep + filename
do-not-use 2013/07/24 10:56:20 could use os.path.join()
+ self.idl_files[basename] = fullpath
+
+ def idl_file_for_interface(self, interface_name):
+ return self.idl_files.get(interface_name)
+
+ def parse_interface(self, interface_name):
+ if interface_name in self.cached_interfaces:
+ return 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:
Nils Barth (inactive) 2013/07/24 11:41:20 'if not filename' is preferred (we're not distingu
+ raise Exception("Could NOT find IDL file for interface \"%s\"" % interface_name)
+
+ if self.verbose:
+ print " | |> Parsing parent IDL \"%s\" for interface \"%s\"" % (filename, interface_name)
+
+ # Step #2: Parse the found IDL file (in quiet mode).
+ definitions = idl_reader.read_idl_file(filename)
+ for interface in definitions.interfaces.values():
+ 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 get_callback_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.arguments]
+ return ", ".join(parameters)
do-not-use 2013/07/24 11:17:59 You could reuse create_arguments()
+
+ def get_js_value_to_native_statement(self, data_type, extended_attributes, js_value, variable_name, isolate):
+ native_type = self.get_native_type(data_type, extended_attributes=extended_attributes, used_to_assign_js_value=True)
+ if data_type == "unsigned long" and "IsIndex" in extended_attributes:
+ # Special-case index arguments because we need to check that they aren't < 0.
+ native_type = "int"
+ native_value, includes = self.__get_js_value_to_native(data_type, extended_attributes, js_value, isolate)
+ code = ""
+ if data_type == "DOMString" or is_enum_type(data_type):
+ if not re.search("^V8StringResource", native_type):
+ raise Exception("Wrong native data_type passed: " + native_type)
+ code = "V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(%s, %s, %s);" % (native_type, variable_name, native_value)
+ elif "EnforceRange" in extended_attributes:
+ code = "V8TRYCATCH_WITH_TYPECHECK_VOID(%s, %s, %s, %s);" % (native_type, variable_name, native_value, isolate)
+ else:
+ code = "V8TRYCATCH_VOID(%s, %s, %s);" % (native_type, variable_name, native_value)
+ return code, includes
+
+ def __get_js_value_to_native(self, data_type, extended_attributes, js_value, isolate):
+ """
+ @return native_expression, additional_includes
+ """
+ int_conversion = "EnforceRange" in extended_attributes and "EnforceRange" or "NormalConversion"
+ includes = []
+
+ if data_type == "boolean":
+ return "%s->BooleanValue()" % js_value, includes
+ if data_type == "float" or data_type == "double":
+ return "static_cast<%s>(%s->NumberValue())" % (data_type, js_value), includes
+
+ arguments = [js_value]
+ if int_conversion != "NormalConversion":
+ arguments.append(int_conversion)
+ arguments.append("ok")
+ arguments_string = ", ".join(arguments)
do-not-use 2013/07/24 11:17:59 You could reuse create_arguments()
+
+ if data_type == "byte":
+ return "toInt8(%s)" % arguments_string, includes
+ if data_type == "octet":
+ return "toUInt8(%s)" % arguments_string, includes
+ if data_type == "long" or data_type == "short":
+ return "toInt32(%s)" % arguments_string, includes
+ if data_type == "unsigned long" or data_type == "unsigned short":
+ return "toUInt32(%s)" % arguments_string, includes
+ if data_type == "long long":
+ return "toInt64(%s)" % arguments_string, includes
+ if data_type == "unsigned long long":
+ return "toUInt64(%s)" % arguments_string, includes
+ if data_type == "CompareHow":
+ return "static_cast<Range::CompareHow>(%s->Int32Value())" % js_value, includes
+ if data_type == "Date":
+ return "toWebCoreDate(%s)" % js_value, includes
+ if data_type == "DOMStringList":
+ return "toDOMStringList(%s, %s)" % (js_value, isolate), includes
+ if data_type == "DOMString" or is_enum_type(data_type):
+ return js_value, includes
+ if data_type == "SerializedScriptValue":
+ includes.append("bindings/v8/SerializedScriptValue.h")
+ return "SerializedScriptValue::create(%s, %s)" % (js_value, isolate), includes
+ if data_type == "Dictionary":
+ includes.append("bindings/v8/Dictionary.h")
+ return "Dictionary(%s, %s)" % (js_value, isolate), includes
+ if data_type == "any" or is_callback_function_type(data_type):
+ includes.append("bindings/v8/ScriptValue.h")
+ return "ScriptValue(%s)" % js_value, includes
+ if data_type == "NodeFilter":
+ return "toNodeFilter(%s)" % js_value, includes
+ if data_type == "MediaQueryListListener":
+ includes.append("core/css/MediaQueryListListener.h")
+ return "MediaQueryListListener::create(%s)" % js_value, includes
+ if data_type == "EventTarget":
+ return "V8DOMWrapper::isDOMWrapper(%s) ? toWrapperTypeInfo(v8::Handle<v8::Object>::Cast(%s))->toEventTarget(v8::Handle<v8::Object>::Cast(%s)) : 0" % (js_value, js_value, js_value), includes
+ if data_type == "ArrayBuffer":
+ includes += get_includes_for_type(data_type)
+ return "$value->IsArrayBuffer() ? V8ArrayBuffer::toNative(v8::Handle<v8::ArrayBuffer>::Cast(%s)) : 0" % js_value, includes
+ if data_type == "XPathNSResolver":
+ return "toXPathNSResolver(%s, %s)" % (js_value, isolate), includes
+
+ array_or_sequence_type = get_array_type(data_type) or get_sequence_type(data_type)
+ if array_or_sequence_type:
+ if is_ref_ptr_type(array_or_sequence_type):
+ includes.append("V8%s.h" % array_or_sequence_type)
+ return "(toRefPtrNativeArray<%s, V8%s>(%s, %s))" % (array_or_sequence_type, array_or_sequence_type, js_value, isolate), includes
+ return "toNativeArray<%s>(%s)" % (self.get_native_type(array_or_sequence_type), js_value), includes
+
+ includes += get_includes_for_type(data_type)
+ includes.append("V8%s.h" % data_type)
+ return "V8%s::HasInstance(%s, %s, worldType(%s)) ? V8%s::toNative(v8::Handle<v8::Object>::Cast(%s)) : 0" % (data_type, js_value, isolate, isolate, data_type, js_value), includes
+
+ def get_native_to_js_value_statement(self, data_type, extended_attributes, native_value, \
+ receiver="", creation_context="", isolate="", callback_info="", \
+ script_wrappable="", for_main_world_suffix="", \
+ indent="", used_as_return_value=False):
+ """
+ Create statement which convert native(C++) value into JS value.
+
+ @param[in] data_type IDL data_type
+ @param[in] extended_attributes
+ @param[in] native_value e.g. "imp->getImte(index)"
+ @param[in] indent
+ @param[in] receiver "%s" will be replaced with JS value. to return something, use used_as_return_value=True
+ @param[in] creation_context
+ @param[in] isolate
+ @param[in] callback_info
+ @param[in] script_wrappable
+ @param[in] for_main_world_suffix
+ @param[in] used_as_return_value
+ """
+ def create_statement(receiver, js_value):
+ if "%s" in receiver:
+ return receiver % js_value
+ return receiver
+
+ def create_statements(receiver, js_value):
+ if isinstance(receiver, str):
+ return create_statement(receiver, js_value)
+ if isinstance(receiver, list):
+ return "\n".join([create_statement(each_receiver, js_value) for each_receiver in receiver])
+ raise Exception("receiver should be string or list")
+
+ if not isolate:
+ raise Exception("An Isolate is mandatory for native value => JS value conversion.")
+
+ includes = []
+
+ if is_union_type(data_type):
+ codes = []
+ for i, union_member_type in enumerate(data_type.union_member_types):
+ union_member_number = i
+ union_member_variable = "%s%d" % (native_value, union_member_number)
+ union_member_enabled_variable = "%s%dEnabled" % (native_value, union_member_number)
+ union_member_native_value = get_pass_owner_expression(union_member_type, union_member_variable)
+ return_js_value_code, union_member_includes = self.get_native_to_js_value_statement(union_member_type, extended_attributes, union_member_native_value, \
+ receiver=receiver, creation_context=creation_context, isolate=isolate, callback_info=callback_info, \
+ script_wrappable=script_wrappable, for_main_world_suffix=for_main_world_suffix, \
+ indent=indent + indent, used_as_return_value=used_as_return_value)
+ includes += union_member_includes
+ code = ""
+ if used_as_return_value:
+ code += indent + "if (%s) {\n" % union_member_enabled_variable
+ code += indent + indent + return_js_value_code + "\n"
+ code += indent + indent + "return;\n"
+ code += indent + "}\n"
+ else:
+ code += indent + "if (%s) {\n" % union_member_enabled_variable
+ code += return_js_value_code + "\n"
+ codes.append(code)
+ return "\n".join(codes), includes
+
+ native_type = self.get_native_type(data_type)
+
+ if data_type == "boolean":
+ if used_as_return_value:
+ receiver = ["%s;"]
+ return create_statements(receiver, "v8SetReturnValueBool(%s, %s)" % (callback_info, native_value)), includes
+ return create_statements(receiver, "v8Boolean(%s, %s)" % (native_value, isolate)), includes
+
+ if data_type == "void":
+ if used_as_return_value:
+ return "", includes
+ return create_statements(receiver, "v8Undefined()"), includes
+
+ # HTML5 says that unsigned reflected attributes should be in the range
+ # [0, 2^31). When a value isn't in this range, a default value (or 0)
+ # should be returned instead.
Nils Barth (inactive) 2013/07/24 11:41:20 Spec link?
kojih 2013/07/25 09:08:37 It seems: http://www.whatwg.org/specs/web-apps/cur
+ if "Reflect" in extended_attributes and (data_type == "unsigned long" or data_type == "unsigned short"):
+ native_value = native_value.replace("getUnsignedIntegralAttribute", "getIntegralAttribute")
+ if used_as_return_value:
+ receiver = ["%s;"]
+ return create_statements(receiver, "v8SetReturnValueUnsigned(%s, std::max(0, %s))" % (callback_info, native_value)), includes
+ return create_statements(receiver, "v8::Integer::NewFromUnsigned(std::max(0, %s), %s);" % (native_value, isolate)), includes
+
+ if native_type == "int":
+ if used_as_return_value:
+ receiver = ["%s;"]
+ return create_statements(receiver, "v8SetReturnValueInt(%s, %s)" % (callback_info, native_value)), includes
+ return create_statements(receiver, "v8::Integer::New(%s, %s)" % (native_value, isolate)), includes
+
+ if native_type == "unsigned":
+ if used_as_return_value:
+ receiver = ["%s;"]
+ return create_statements(receiver, "v8SetReturnValueUnsigned(%s, %s)" % (callback_info, native_value)), includes
+ return create_statements(receiver, "v8::Integer::NewFromUnsigned(%s, %s)" % (native_value, isolate)), includes
+
+ if data_type == "Date":
+ if used_as_return_value:
+ receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
+ return create_statements(receiver, "v8DateOrNull(%s, %s)" % (native_value, isolate)), includes
+
+ # long long and unsigned long long are not representable in ECMAScript.
+ if data_type == "long long" or data_type == "unsigned long long" or data_type == "DOMTimeStamp":
+ if used_as_return_value:
+ receiver = ["%s;"]
+ return create_statements(receiver, "v8SetReturnValue(%s, static_cast<double>(%s))" % (callback_info, native_value)), includes
+ return create_statements(receiver, "v8::Number::New(static_cast<double>(%s))" % native_value), includes
+
+ if is_primitive_type(data_type):
+ if not (data_type == "float" or data_type == "double"):
+ raise Exception("unexpected data_type %s" % data_type)
+ if used_as_return_value:
+ receiver = ["%s;"]
+ return create_statements(receiver, "v8SetReturnValue(%s, %s)" % (callback_info, native_value)), includes
+ return create_statements(receiver, "v8::Number::New(%s)" % native_value), includes
+
+ if native_type == "ScriptValue":
+ if used_as_return_value:
+ receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
+ js_value = "%s.v8Value()" % native_value
+ return create_statements(receiver, js_value), includes
+
+ if data_type == "DOMString" or is_enum_type(data_type):
+ conversion = extended_attributes.get("TreatReturnedNullStringAs")
+ js_value = ""
+ function_suffix = ""
+ arguments = create_arguments([native_value, isolate])
+ if conversion is None:
+ js_value = "v8String(%s)" % arguments
+ elif conversion == "Null":
+ js_value = "v8StringOrNull(%s)" % arguments
+ function_suffix = "OrNull"
+ elif conversion == "Undefined":
+ js_value = "v8StringOrUndefined(%s)" % arguments
+ function_suffix = "OrUndefined"
+ else:
+ raise Exception("Unknown value for TreatReturnedNullStringAs extended attribute")
+
+ if used_as_return_value:
+ receiver = ["v8SetReturnValueString%s(%s, %%s, %s);" % (function_suffix, callback_info, isolate)]
+ return create_statements(receiver, native_value), includes
+ return create_statements(receiver, js_value), includes
+
+ array_or_sequence_type = get_array_type(data_type) or get_sequence_type(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)
+ if used_as_return_value:
+ receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
+ return create_statements(receiver, "v8Array(%s, %s)" % (native_value, isolate)), includes
+
+ includes += get_includes_for_type(data_type)
+
+ if data_type == "SerializedScriptValue":
+ includes.append("%s.h" % data_type)
+ if used_as_return_value:
+ receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
+ js_value = "%s ? %s->deserialize() : v8::Handle<v8::Value>(v8::Null(%s))" % (native_value, native_value, isolate)
+ return create_statements(receiver, js_value), includes
+
+ includes.append("wtf/RefPtr.h")
+ includes.append("wtf/GetPtr.h")
+
+ if used_as_return_value:
+ receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
+
+ if script_wrappable:
+ # FIXME: Use safe handles
+ if for_main_world_suffix == "ForMainWorld":
+ return create_statements(receiver, "toV8ForMainWorld(%s, %s.Holder(), %s.GetIsolate())" % (native_value, callback_info, callback_info)), includes
+ return create_statements(receiver, "toV8Fast(%s, %s, %s)" % (native_value, callback_info, script_wrappable)), includes
+
+ # FIXME: Use safe handles
+ return create_statements(receiver, "toV8(%s, %s, %s)" % (native_value, creation_context, isolate)), includes
+
+ def get_native_type(self, data_type, called_by_webcore=False, used_as_parameter=False, used_to_assign_js_value=False, extended_attributes=None):
+ """
+ Return native data_type corresponds to IDL data_type.
+ @param[in] data_type ... IDL data_type
+ @param[in] called_by_webcore
+ @param[in] used_as_parameter
+ """
+ if extended_attributes is None:
+ extended_attributes = {}
+ if data_type == "float":
+ return "float"
Nils Barth (inactive) 2013/07/24 11:41:20 How about: if data_type in ['float', 'double', 'lo
kojih 2013/07/25 09:08:37 ok. later.
+ if data_type == "double":
+ return "double"
+ if data_type == "int" or data_type == "long" or data_type == "short" or data_type == "byte":
+ return "int"
Nils Barth (inactive) 2013/07/24 11:41:20 How about: if data_type in ['int', 'long', 'short'
+ if data_type == "unsigned long" or data_type == "unsigned int" or data_type == "unsigned short" or data_type == "octet":
+ return "unsigned"
+ if data_type == "long long":
+ return "long long"
+ if data_type == "unsigned long long":
+ return "unsigned long long"
+ if data_type == "boolean":
+ return "bool"
+ if data_type == "DOMString" or is_enum_type(data_type):
+ if used_to_assign_js_value:
+ # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString],
+ # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString].
+ mode = ""
+ if extended_attributes.get("TreatNullAs") == "NullString" and extended_attributes.get("TreatUndefinedAs") == "NullString":
+ mode = "WithUndefinedOrNullCheck"
+ elif extended_attributes.get("TreatNullAs") == "NullString" or "Reflect" in extended_attributes:
+ mode = "WithNullCheck"
+ # FIXME: Add the case for 'elsif ($attributeOrParameter->extendedAttributes->{"TreatUndefinedAs"} and $attributeOrParameter->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'.
+ return "V8StringResource<%s>" % mode
+ if called_by_webcore:
+ return "const String&"
+ return "String"
+
+ # FIXME: remove this
+ adhoc_rules = {
+ "CompareHow": "Range::CompareHow",
+ "DOMTimeStamp": "DOMTimeStamp",
+ "Date": "double",
+ "Dictionary": "Dictionary",
+ "DOMStringList": "RefPtr<DOMStringList>",
+ "MediaQueryListListener": "RefPtr<MediaQueryListListener>",
+ "NodeFilter": "RefPtr<NodeFilter>",
+ "SerializedScriptValue": "RefPtr<SerializedScriptValue>",
+ "XPathNSResolver": "RefPtr<XPathNSResolver>",
+ }
+ if data_type in adhoc_rules:
+ if used_as_parameter:
+ return adhoc_rules[data_type].replace("RefPtr", "PassRefPtr")
+ return adhoc_rules[data_type]
+ if data_type == "any" or is_callback_function_type(data_type):
+ return "ScriptValue"
+
+ if is_union_type(data_type):
+ raise Exception("UnionType is not supported")
+
+ if data_type == "ArrayBuffer":
+ if used_as_parameter:
+ return "ArrayBuffer*"
+ else:
+ return "RefPtr<ArrayBuffer>"
+
+ # We need to check [ImplementedAs] extended attribute for wrapper types.
+ if is_wrapper_type(data_type):
+ interface = self.parse_interface(data_type)
+ data_type = get_impl_name(interface)
+
+ array_or_sequence_type = get_array_type(data_type) or get_sequence_type(data_type)
+ if array_or_sequence_type:
+ data_type = self.get_native_type(array_or_sequence_type)
+ data_type = data_type.replace(">", "> ")
+ return "Vector<%s>" % data_type
+
+ if called_by_webcore:
+ return data_type + "*"
+ elif used_to_assign_js_value:
+ return data_type + "*"
+ elif used_as_parameter:
+ if re.search(">$", data_type):
+ data_type += " "
+ return "PassRefPtr<%s>" % data_type
+ else:
+ return "RefPtr<%s>" % data_type
+
+ def header_files_for_interface(self, 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
Nils Barth (inactive) 2013/07/25 03:30:54 Assert is only for internal consistency, not catch
kojih 2013/07/25 09:08:37 ok.
+ idlRelPath = "bindings/" + abs2rel(idl_filename, os.getcwd())
+ includes.append(os.path.dirname(idlRelPath) + os.sep + impl_class_name + ".h")
do-not-use 2013/07/24 11:17:59 We likely want '/' not os.sep for include paths
kojih 2013/07/25 09:08:37 done.
+ return includes
+
+ def generate_interface(self, interface):
+ self.interface = interface
+ link_overloaded_functions(self.interface)
+ self.common_template_parameters = {
+ "conditional_string": get_conditional_string(self.interface),
+ }
+ if self.generate_h:
+ if interface.is_callback:
+ self.generate_callback_header()
+ else:
+ self.generate_header()
+ if self.generate_cpp:
+ if interface.is_callback:
+ self.generate_callback_implementation()
+ else:
+ self.generate_implementation()
+
+ def write_interface(self):
+ if self.interface_name in self.idl_definitions.interfaces:
+ interface = self.idl_definitions.interfaces[self.interface_name]
+ self.generate_interface(interface)
+ if self.generate_h:
+ header_filename = self.output_directory + os.sep + get_v8_class_name(self.interface) + ".h"
do-not-use 2013/07/24 11:17:59 Could use os.path.join()
kojih 2013/07/25 09:08:37 done.
+ with open(header_filename, "w") as f:
+ f.write(self.header)
+ if self.generate_cpp:
+ implementation_filename = self.output_directory + os.sep + get_v8_class_name(self.interface) + ".cpp"
do-not-use 2013/07/24 11:17:59 Could use os.path.join()
+ with open(implementation_filename, "w") as f:
+ f.write(self.implementation)
+ else:
+ raise Exception("%s not in IDL definitions" % self.interface_name)
+
+ def generate_callback_header(self):
+ impl_class_name = get_impl_name(self.interface)
+ v8_class_name = get_v8_class_name(self.interface)
+ includes = [
+ "bindings/v8/ActiveDOMCallback.h",
+ "bindings/v8/DOMWrapperWorld.h",
+ "bindings/v8/ScopedPersistent.h",
+ ]
+ includes += self.header_files_for_interface(self.interface.name, impl_class_name)
+ includes = sort_and_remove_duplicate(includes)
+ class_public_definitions = []
+ for operation in self.interface.operations:
+ # only bool used for callback .h
+ code = "virtual %s %s(%s);" % (self.get_native_type(operation.data_type), operation.name, self.get_callback_parameter_declaration(operation))
+ class_public_definitions.append(code)
+
+ 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": includes,
+ "class_public_definitions": class_public_definitions,
+ })
+
+ self.header = apply_template("templates/callback.h", template_parameters)
+
+ def generate_callback_implementation(self):
+ impl_class_name = get_impl_name(self.interface)
+ v8_class_name = get_v8_class_name(self.interface)
+ includes = [
+ "core/dom/ScriptExecutionContext.h",
+ "bindings/v8/V8Binding.h",
+ "bindings/v8/V8Callback.h",
+ "wtf/Assertions.h",
+ ]
+ functions = []
+ for operation in self.interface.operations:
+ if "Custom" in operation.extended_attributes:
+ continue
+ includes += get_includes_for_type(operation.data_type)
+ for parameter in operation.arguments:
+ includes += get_includes_for_parameter(parameter)
+ if operation.data_type != "boolean":
+ raise Exception("We don't yet support callbacks that return non-boolean values.")
+ parameters = []
+ for parameter in operation.arguments:
+ receiver = "v8::Handle<v8::Value> %sHandle = %%s;" % parameter.name
+ native_to_js_value_statement, additional_includes = self.get_native_to_js_value_statement(parameter.data_type, parameter.extended_attributes, parameter.name, receiver=receiver, creation_context="v8::Handle<v8::Object>()", isolate="isolate")
+ includes += additional_includes
+ parameters.append({
+ "name": parameter.name,
+ "native_to_js_value_statement": native_to_js_value_statement,
+ })
+ definition = {
+ "return_type": self.get_native_type(operation.data_type),
+ "name": operation.name,
+ "parameter_declaration": self.get_callback_parameter_declaration(operation),
+ "prepare_js_parameters": "",
+ "handles": ",\n".join(["%sHandle" % parameter.name for parameter in operation.arguments]),
+ "parameters": parameters,
+ }
+ functions.append(definition)
+
+ includes = sort_and_remove_duplicate(includes)
+
+ 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": includes,
+ "functions": functions,
+ })
+ self.implementation = apply_template("templates/callback.cpp", template_parameters)
+
+ def generate_header(self):
+ # TODO: implement
+ self.header = ""
+
+ def generate_implementation(self):
+ # TODO: implement
+ self.implementation = ""
def generate_dummy_header_and_cpp(target_interface_name, output_directory):

Powered by Google App Engine
This is Rietveld 408576698