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

Side by Side 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, 4 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 unified diff | Download patch
OLDNEW
1 # Copyright (C) 2013 Google Inc. All rights reserved. 1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer 10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the 11 # in the documentation and/or other materials provided with the
12 # distribution. 12 # distribution.
13 # * Neither the name of Google Inc. nor the names of its 13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from 14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission. 15 # this software without specific prior written permission.
16 # 16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 28
29 """Generate Blink V8 bindings (.h and .cpp files). 29 """
30 Generate Blink V8 bindings (.h and .cpp files).
30 31
31 Input: An object of class IdlDefinitions, containing an IDL interface X 32 Input: An object of class IdlDefinitions, containing an IDL interface X
32 Output: V8X.h and V8X.cpp 33 Output: V8X.h and V8X.cpp
33
34 FIXME: Currently a stub, as part of landing the parser and code generator
35 incrementally. Only implements generation of dummy .cpp and .h files.
36 """ 34 """
37 35
36 import os
38 import os.path 37 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
38 import sys
39 import re
40
41 import idl_definitions
42 import idl_reader
43
44 current_dir = os.path.dirname(os.path.realpath(__file__))
45 # jinja2 is in chromium's third_party directory
46 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
47 import jinja2
48
49
50 def pathsplit(path):
51 dirs = []
52 while True:
53 (dirname, basename) = os.path.split(path)
54 if basename == "":
55 break
56 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.
57 path = dirname
58 dirs.reverse()
59 return dirs
do-not-use 2013/07/24 10:56:20 return reversed(dirs) ?
60
61
62 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!
63 path_dirs = pathsplit(os.path.abspath(path))
64 basedir_dirs = pathsplit(os.path.abspath(basedir))
65 common_dirs = 0
66 for i in range(min(len(path_dirs), len(basedir_dirs))):
67 if path_dirs[i] != basedir_dirs[i]:
68 break
69 common_dirs += 1
70 relpath = []
Nils Barth (inactive) 2013/07/25 03:30:54 Naming-wise (if we still need this), relpath_dirs,
71 for i in range(len(basedir_dirs) - common_dirs):
72 relpath.append("..")
Nils Barth (inactive) 2013/07/24 11:41:20 os.pardir instead of '..' ?
73 relpath.extend(path_dirs[common_dirs:])
74 return os.sep.join(relpath)
do-not-use 2013/07/24 10:56:20 Shouldn't this be '/'.join(relpath)? We don't want
75
76
77 def get_path(dic, keys):
do-not-use 2013/07/24 10:56:20 This function is a bit obscure and does not appear
78 node = dic
79 for key in keys:
80 if key not in node:
81 return None
82 node = node[key]
83 return node
84
85
86 def apply_template(path_to_template, params):
87 dirname, basename = os.path.split(path_to_template)
88 path_to_templates = os.path.join(current_dir, "templates")
89 jinja_env = jinja2.Environment(trim_blocks=True, loader=jinja2.FileSystemLoa der([dirname, path_to_templates]))
90 template = jinja_env.get_template(basename)
91 return template.render(params)
92
93
94 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.
95 return ", ".join([argument for argument in arguments if argument])
96
97
98 def get_v8_class_name(interface):
99 return "V8" + interface.name
100
101
102 def get_impl_name(interface_or_function):
103 implementedAs = interface_or_function.extended_attributes.get("ImplementedAs ")
104 if implementedAs is not None:
105 return implementedAs
106 return interface_or_function.name
107
108
109 def get_conditional_string(interface_or_attribute_or_operation):
110 conditional = interface_or_attribute_or_operation.extended_attributes.get("C onditional")
111 if conditional is None:
112 return ""
113 else:
114 operator = ""
115 if "&" in conditional:
116 operator = "&"
117 if "|" in conditional:
118 operator = "|"
119 if operator == "":
120 return "ENABLE(%s)" % conditional
121 else:
122 # Avoid duplicated conditions.
123 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.
124 return (" %s%s " % (operator, operator)).join(["ENABLE(%s)" % expres sion for expression in sorted(conditions.keys())])
125
126
127 def get_includes_for_type(data_type):
128 if skip_include_header(data_type):
129 return []
130 includes = []
131 if data_type == "EventListener":
132 includes.append("core/dom/EventListener.h")
133 elif data_type == "SerializedScriptValue":
134 includes.append("bindings/v8/SerializedScriptValue.h")
135 elif data_type == "any" or is_callback_function_type(data_type):
136 includes.append("bindings/v8/ScriptValue.h")
137 else:
138 includes.append("V8%s.h" % data_type)
139 return includes
140
141
142 def get_includes_for_parameter(parameter):
143 includes = []
144 array_or_sequence_type = get_array_type(parameter.data_type) or get_sequence _type(parameter.data_type)
145 if array_or_sequence_type:
146 if is_ref_ptr_type(array_or_sequence_type):
147 includes += get_includes_for_type(array_or_sequence_type)
148 else:
149 includes += get_includes_for_type(parameter.data_type)
150 return includes
151
152
153 def link_overloaded_functions(interface):
154 name_to_operations = {}
155 for operation in interface.operations:
156 name = operation.name
157 if not name:
158 operation.overloads = []
159 operation.overload_index = 0
160 continue
161 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
162 name_to_operations[name] = []
163 name_to_operations[name].append(operation)
164 operation.overloads = name_to_operations[name]
165 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
166
167
168 def sort_and_remove_duplicate(includes):
169 return sorted(list(set(includes)))
170
171
172 def get_pass_owner_expression(data_type, expression):
173 if is_ref_ptr_type(data_type):
174 return expression + ".release()"
175 return expression
176
177
178 def get_convert_to_V8StringResource(attribute_or_parameter, native_type, native_ variable_name, native_value):
179 if not re.match("^V8StringResource", native_type):
180 raise Exception("Wrong native data_type passed: %s" % native_type)
181 if attribute_or_parameter.data_type == "DOMString" or is_enum_type(attribute _or_parameter.data_type):
182 return "V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(%s, %s, %s);" % (native_typ e, native_variable_name, native_value)
183 else:
184 return "%s %s(%s, true);" % (native_type, native_variable_name, native_v alue)
185
186 # IDL data_type: [element's C++ data_type, V8 data_type]
187 typed_arrays = {
188 "ArrayBuffer": [],
189 "ArrayBufferView": [],
190 "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
191 "Uint8ClampedArray": ["unsigned char", "v8::kExternalPixelArray"],
192 "Uint16Array": ["unsigned short", "v8::kExternalUnsignedShortArray"],
193 "Uint32Array": ["unsigned int", "v8::kExternalUnsignedIntArray"],
194 "Int8Array": ["signed char", "v8::kExternalByteArray"],
195 "Int16Array": ["short", "v8::kExternalShortArray"],
196 "Int32Array": ["int", "v8::kExternalIntArray"],
197 "Float32Array": ["float", "v8::kExternalFloatArray"],
198 "Float64Array": ["double", "v8::kExternalDoubleArray"],
199 }
200
201 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.
202 "boolean": True,
203 "void": True,
204 "Date": True,
205 "byte": True,
206 "octet": True,
207 "short": True,
208 "long": True,
209 "long long": True,
210 "unsigned short": True,
211 "unsigned long": True,
212 "unsigned long long": True,
213 "float": True,
214 "double": True,
215 }
216
217 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.
218 }
219
220 callback_function_types = {
221 }
222
223 non_wrapper_types = {
do-not-use 2013/07/24 10:56:20 Ditto.
224 "CompareHow": True,
225 "DOMTimeStamp": True,
226 "Dictionary": True,
227 "EventListener": True,
228 "MediaQueryListListener": True,
229 "NodeFilter": True,
230 "SerializedScriptValue": True,
231 "any": True,
232 }
233
234 dom_node_types = {
do-not-use 2013/07/24 10:56:20 Ditto.
235 "Attr": True,
236 "CDATASection": True,
237 "CharacterData": True,
238 "Comment": True,
239 "Document": True,
240 "DocumentFragment": True,
241 "DocumentType": True,
242 "Element": True,
243 "Entity": True,
244 "HTMLDocument": True,
245 "Node": True,
246 "Notation": True,
247 "ProcessingInstruction": True,
248 "ShadowRoot": True,
249 "SVGDocument": True,
250 "Text": True,
251 "TestNode": True,
252 }
253
254
255 def get_sequence_type(data_type):
256 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.
257 if matched:
258 return matched.group(1)
259 return ""
do-not-use 2013/07/24 10:56:20 Why not return None?
260
261
262 def get_array_type(data_type):
263 matched = re.match("^([\w\d_\s]+)\[\]", data_type)
do-not-use 2013/07/24 10:56:20 White space in array type?
264 if matched:
265 return matched.group(1)
266 return ""
do-not-use 2013/07/24 10:56:20 Ditto.
267
268
269 def is_wrapper_type(data_type):
270 if is_union_type(data_type):
271 return False
272 if get_array_type(data_type):
273 return False
274 if get_sequence_type(data_type):
275 return False
276 if is_callback_function_type(data_type):
277 return False
278 if is_enum_type(data_type):
279 return False
280 if is_primitive_type(data_type):
281 return False
282 if data_type == "DOMString":
283 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.
284 return not non_wrapper_types.get(data_type)
285
286
287 def is_typed_array_type(data_type):
288 return data_type in typed_arrays
289
290
291 def is_ref_ptr_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto re: boolean expression
292 if is_union_type(data_type):
293 return False
294 if data_type == "any" or data_type == "DOMString":
295 return False
296 if is_primitive_type(data_type):
297 return False
298 if get_array_type(data_type):
299 return False
300 if get_sequence_type(data_type):
301 return False
302 if is_callback_function_type(data_type):
303 return False
304 if is_enum_type(data_type):
305 return False
306 return True
307
308
309 def is_primitive_type(data_type):
310 if data_type in primitive_types:
Nils Barth (inactive) 2013/07/24 11:41:20 return data_type in primitive_types
311 return True
312 return False
313
314
315 def is_enum_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
316 if data_type in enum_types:
317 return True
318 return False
319
320
321 def is_callback_function_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
322 if data_type in callback_function_types:
323 return True
324 return False
325
326
327 def is_union_type(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
328 if isinstance(data_type, idl_definitions.IdlUnionType):
329 return True
330 return False
331
332
333 def skip_include_header(data_type):
Nils Barth (inactive) 2013/07/24 11:41:20 Ditto.
334 if is_primitive_type(data_type):
335 return True
336 if is_enum_type(data_type):
337 return True
338 if is_callback_function_type(data_type):
339 return True
340 if data_type == "DOMString":
341 return True
342 return False
343
344
345 class code_generator_v8:
Nils Barth (inactive) 2013/07/25 03:30:54 Class names are in CamelCase: http://www.chromium.
346 def __init__(self, definitions, interface_name, output_directory, idl_direct ories, generate_h=True, generate_cpp=True, verbose=False):
347 global enum_types
348 global callback_function_types
349 self.idl_definitions = definitions
350 self.interface_name = interface_name
351 self.idl_directories = idl_directories
352 self.idl_files = {}
353 self.output_directory = output_directory
354 self.generate_h = generate_h
355 self.generate_cpp = generate_cpp
356 self.verbose = verbose
357 self.header = ""
358 self.implementation = ""
359 self.cached_interfaces = {}
360 self.common_template_parameters = {}
361 self.interface = None
362
363 enum_types = dict([[enum.name, enum.values] for enum in self.idl_definit ions.enumerations.values()])
364 callback_function_types = self.idl_definitions.callback_functions
365 self.prepare_idl_files()
366
367 def prepare_idl_files(self):
368 directories = [os.getcwd() + os.sep + directory for directory in self.id l_directories]
369 directories = [path for path in directories if os.path.isdir(path)]
370 directories.append(".")
371 for directory in directories:
372 for root, _, filenames in os.walk(directory):
373 for filename in filenames:
374 basename, ext = os.path.splitext(filename)
375 if ext == ".idl":
376 fullpath = root + os.sep + filename
do-not-use 2013/07/24 10:56:20 could use os.path.join()
377 self.idl_files[basename] = fullpath
378
379 def idl_file_for_interface(self, interface_name):
380 return self.idl_files.get(interface_name)
381
382 def parse_interface(self, interface_name):
383 if interface_name in self.cached_interfaces:
384 return self.cached_interfaces[interface_name]
385
386 # Step #1: Find the IDL file associated with 'interface'
387 filename = self.idl_file_for_interface(interface_name)
388 if filename is None:
Nils Barth (inactive) 2013/07/24 11:41:20 'if not filename' is preferred (we're not distingu
389 raise Exception("Could NOT find IDL file for interface \"%s\"" % int erface_name)
390
391 if self.verbose:
392 print " | |> Parsing parent IDL \"%s\" for interface \"%s\"" % (f ilename, interface_name)
393
394 # Step #2: Parse the found IDL file (in quiet mode).
395 definitions = idl_reader.read_idl_file(filename)
396 for interface in definitions.interfaces.values():
397 if interface.name == interface_name or interface.is_partial:
398 self.cached_interfaces[interface_name] = interface
399 return interface
400
401 raise Exception("Could NOT find interface definition for %s in %s" % (in terface_name, filename))
402
403 def get_callback_parameter_declaration(self, operation):
404 parameters = ["%s %s" % (self.get_native_type(parameter.data_type, used_ as_parameter=True, called_by_webcore=True), parameter.name) for parameter in ope ration.arguments]
405 return ", ".join(parameters)
do-not-use 2013/07/24 11:17:59 You could reuse create_arguments()
406
407 def get_js_value_to_native_statement(self, data_type, extended_attributes, j s_value, variable_name, isolate):
408 native_type = self.get_native_type(data_type, extended_attributes=extend ed_attributes, used_to_assign_js_value=True)
409 if data_type == "unsigned long" and "IsIndex" in extended_attributes:
410 # Special-case index arguments because we need to check that they ar en't < 0.
411 native_type = "int"
412 native_value, includes = self.__get_js_value_to_native(data_type, extend ed_attributes, js_value, isolate)
413 code = ""
414 if data_type == "DOMString" or is_enum_type(data_type):
415 if not re.search("^V8StringResource", native_type):
416 raise Exception("Wrong native data_type passed: " + native_type)
417 code = "V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(%s, %s, %s);" % (native _type, variable_name, native_value)
418 elif "EnforceRange" in extended_attributes:
419 code = "V8TRYCATCH_WITH_TYPECHECK_VOID(%s, %s, %s, %s);" % (native_t ype, variable_name, native_value, isolate)
420 else:
421 code = "V8TRYCATCH_VOID(%s, %s, %s);" % (native_type, variable_name, native_value)
422 return code, includes
423
424 def __get_js_value_to_native(self, data_type, extended_attributes, js_value, isolate):
425 """
426 @return native_expression, additional_includes
427 """
428 int_conversion = "EnforceRange" in extended_attributes and "EnforceRange " or "NormalConversion"
429 includes = []
430
431 if data_type == "boolean":
432 return "%s->BooleanValue()" % js_value, includes
433 if data_type == "float" or data_type == "double":
434 return "static_cast<%s>(%s->NumberValue())" % (data_type, js_value), includes
435
436 arguments = [js_value]
437 if int_conversion != "NormalConversion":
438 arguments.append(int_conversion)
439 arguments.append("ok")
440 arguments_string = ", ".join(arguments)
do-not-use 2013/07/24 11:17:59 You could reuse create_arguments()
441
442 if data_type == "byte":
443 return "toInt8(%s)" % arguments_string, includes
444 if data_type == "octet":
445 return "toUInt8(%s)" % arguments_string, includes
446 if data_type == "long" or data_type == "short":
447 return "toInt32(%s)" % arguments_string, includes
448 if data_type == "unsigned long" or data_type == "unsigned short":
449 return "toUInt32(%s)" % arguments_string, includes
450 if data_type == "long long":
451 return "toInt64(%s)" % arguments_string, includes
452 if data_type == "unsigned long long":
453 return "toUInt64(%s)" % arguments_string, includes
454 if data_type == "CompareHow":
455 return "static_cast<Range::CompareHow>(%s->Int32Value())" % js_value , includes
456 if data_type == "Date":
457 return "toWebCoreDate(%s)" % js_value, includes
458 if data_type == "DOMStringList":
459 return "toDOMStringList(%s, %s)" % (js_value, isolate), includes
460 if data_type == "DOMString" or is_enum_type(data_type):
461 return js_value, includes
462 if data_type == "SerializedScriptValue":
463 includes.append("bindings/v8/SerializedScriptValue.h")
464 return "SerializedScriptValue::create(%s, %s)" % (js_value, isolate) , includes
465 if data_type == "Dictionary":
466 includes.append("bindings/v8/Dictionary.h")
467 return "Dictionary(%s, %s)" % (js_value, isolate), includes
468 if data_type == "any" or is_callback_function_type(data_type):
469 includes.append("bindings/v8/ScriptValue.h")
470 return "ScriptValue(%s)" % js_value, includes
471 if data_type == "NodeFilter":
472 return "toNodeFilter(%s)" % js_value, includes
473 if data_type == "MediaQueryListListener":
474 includes.append("core/css/MediaQueryListListener.h")
475 return "MediaQueryListListener::create(%s)" % js_value, includes
476 if data_type == "EventTarget":
477 return "V8DOMWrapper::isDOMWrapper(%s) ? toWrapperTypeInfo(v8::Handl e<v8::Object>::Cast(%s))->toEventTarget(v8::Handle<v8::Object>::Cast(%s)) : 0" % (js_value, js_value, js_value), includes
478 if data_type == "ArrayBuffer":
479 includes += get_includes_for_type(data_type)
480 return "$value->IsArrayBuffer() ? V8ArrayBuffer::toNative(v8::Handle <v8::ArrayBuffer>::Cast(%s)) : 0" % js_value, includes
481 if data_type == "XPathNSResolver":
482 return "toXPathNSResolver(%s, %s)" % (js_value, isolate), includes
483
484 array_or_sequence_type = get_array_type(data_type) or get_sequence_type( data_type)
485 if array_or_sequence_type:
486 if is_ref_ptr_type(array_or_sequence_type):
487 includes.append("V8%s.h" % array_or_sequence_type)
488 return "(toRefPtrNativeArray<%s, V8%s>(%s, %s))" % (array_or_seq uence_type, array_or_sequence_type, js_value, isolate), includes
489 return "toNativeArray<%s>(%s)" % (self.get_native_type(array_or_sequ ence_type), js_value), includes
490
491 includes += get_includes_for_type(data_type)
492 includes.append("V8%s.h" % data_type)
493 return "V8%s::HasInstance(%s, %s, worldType(%s)) ? V8%s::toNative(v8::Ha ndle<v8::Object>::Cast(%s)) : 0" % (data_type, js_value, isolate, isolate, data_ type, js_value), includes
494
495 def get_native_to_js_value_statement(self, data_type, extended_attributes, n ative_value, \
496 receiver="", creation_context="", isolate="", cal lback_info="", \
497 script_wrappable="", for_main_world_suffix="", \
498 indent="", used_as_return_value=False):
499 """
500 Create statement which convert native(C++) value into JS value.
501
502 @param[in] data_type IDL data_type
503 @param[in] extended_attributes
504 @param[in] native_value e.g. "imp->getImte(index)"
505 @param[in] indent
506 @param[in] receiver "%s" will be replaced with JS value. to return something, use used_as_return_value=True
507 @param[in] creation_context
508 @param[in] isolate
509 @param[in] callback_info
510 @param[in] script_wrappable
511 @param[in] for_main_world_suffix
512 @param[in] used_as_return_value
513 """
514 def create_statement(receiver, js_value):
515 if "%s" in receiver:
516 return receiver % js_value
517 return receiver
518
519 def create_statements(receiver, js_value):
520 if isinstance(receiver, str):
521 return create_statement(receiver, js_value)
522 if isinstance(receiver, list):
523 return "\n".join([create_statement(each_receiver, js_value) for each_receiver in receiver])
524 raise Exception("receiver should be string or list")
525
526 if not isolate:
527 raise Exception("An Isolate is mandatory for native value => JS valu e conversion.")
528
529 includes = []
530
531 if is_union_type(data_type):
532 codes = []
533 for i, union_member_type in enumerate(data_type.union_member_types):
534 union_member_number = i
535 union_member_variable = "%s%d" % (native_value, union_member_num ber)
536 union_member_enabled_variable = "%s%dEnabled" % (native_value, u nion_member_number)
537 union_member_native_value = get_pass_owner_expression(union_memb er_type, union_member_variable)
538 return_js_value_code, union_member_includes = self.get_native_to _js_value_statement(union_member_type, extended_attributes, union_member_native_ value, \
539 receiver=receiver, creation_context=creation_cont ext, isolate=isolate, callback_info=callback_info, \
540 script_wrappable=script_wrappable, for_main_world _suffix=for_main_world_suffix, \
541 indent=indent + indent, used_as_return_value=used _as_return_value)
542 includes += union_member_includes
543 code = ""
544 if used_as_return_value:
545 code += indent + "if (%s) {\n" % union_member_enabled_variab le
546 code += indent + indent + return_js_value_code + "\n"
547 code += indent + indent + "return;\n"
548 code += indent + "}\n"
549 else:
550 code += indent + "if (%s) {\n" % union_member_enabled_variab le
551 code += return_js_value_code + "\n"
552 codes.append(code)
553 return "\n".join(codes), includes
554
555 native_type = self.get_native_type(data_type)
556
557 if data_type == "boolean":
558 if used_as_return_value:
559 receiver = ["%s;"]
560 return create_statements(receiver, "v8SetReturnValueBool(%s, %s) " % (callback_info, native_value)), includes
561 return create_statements(receiver, "v8Boolean(%s, %s)" % (native_val ue, isolate)), includes
562
563 if data_type == "void":
564 if used_as_return_value:
565 return "", includes
566 return create_statements(receiver, "v8Undefined()"), includes
567
568 # HTML5 says that unsigned reflected attributes should be in the range
569 # [0, 2^31). When a value isn't in this range, a default value (or 0)
570 # 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
571 if "Reflect" in extended_attributes and (data_type == "unsigned long" or data_type == "unsigned short"):
572 native_value = native_value.replace("getUnsignedIntegralAttribute", "getIntegralAttribute")
573 if used_as_return_value:
574 receiver = ["%s;"]
575 return create_statements(receiver, "v8SetReturnValueUnsigned(%s, std::max(0, %s))" % (callback_info, native_value)), includes
576 return create_statements(receiver, "v8::Integer::NewFromUnsigned(std ::max(0, %s), %s);" % (native_value, isolate)), includes
577
578 if native_type == "int":
579 if used_as_return_value:
580 receiver = ["%s;"]
581 return create_statements(receiver, "v8SetReturnValueInt(%s, %s)" % (callback_info, native_value)), includes
582 return create_statements(receiver, "v8::Integer::New(%s, %s)" % (nat ive_value, isolate)), includes
583
584 if native_type == "unsigned":
585 if used_as_return_value:
586 receiver = ["%s;"]
587 return create_statements(receiver, "v8SetReturnValueUnsigned(%s, %s)" % (callback_info, native_value)), includes
588 return create_statements(receiver, "v8::Integer::NewFromUnsigned(%s, %s)" % (native_value, isolate)), includes
589
590 if data_type == "Date":
591 if used_as_return_value:
592 receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
593 return create_statements(receiver, "v8DateOrNull(%s, %s)" % (native_ value, isolate)), includes
594
595 # long long and unsigned long long are not representable in ECMAScript.
596 if data_type == "long long" or data_type == "unsigned long long" or data _type == "DOMTimeStamp":
597 if used_as_return_value:
598 receiver = ["%s;"]
599 return create_statements(receiver, "v8SetReturnValue(%s, static_ cast<double>(%s))" % (callback_info, native_value)), includes
600 return create_statements(receiver, "v8::Number::New(static_cast<doub le>(%s))" % native_value), includes
601
602 if is_primitive_type(data_type):
603 if not (data_type == "float" or data_type == "double"):
604 raise Exception("unexpected data_type %s" % data_type)
605 if used_as_return_value:
606 receiver = ["%s;"]
607 return create_statements(receiver, "v8SetReturnValue(%s, %s)" % (callback_info, native_value)), includes
608 return create_statements(receiver, "v8::Number::New(%s)" % native_va lue), includes
609
610 if native_type == "ScriptValue":
611 if used_as_return_value:
612 receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
613 js_value = "%s.v8Value()" % native_value
614 return create_statements(receiver, js_value), includes
615
616 if data_type == "DOMString" or is_enum_type(data_type):
617 conversion = extended_attributes.get("TreatReturnedNullStringAs")
618 js_value = ""
619 function_suffix = ""
620 arguments = create_arguments([native_value, isolate])
621 if conversion is None:
622 js_value = "v8String(%s)" % arguments
623 elif conversion == "Null":
624 js_value = "v8StringOrNull(%s)" % arguments
625 function_suffix = "OrNull"
626 elif conversion == "Undefined":
627 js_value = "v8StringOrUndefined(%s)" % arguments
628 function_suffix = "OrUndefined"
629 else:
630 raise Exception("Unknown value for TreatReturnedNullStringAs ext ended attribute")
631
632 if used_as_return_value:
633 receiver = ["v8SetReturnValueString%s(%s, %%s, %s);" % (function _suffix, callback_info, isolate)]
634 return create_statements(receiver, native_value), includes
635 return create_statements(receiver, js_value), includes
636
637 array_or_sequence_type = get_array_type(data_type) or get_sequence_type( data_type)
638 if array_or_sequence_type:
639 if is_ref_ptr_type(array_or_sequence_type):
640 includes += get_includes_for_type(array_or_sequence_type)
641 if used_as_return_value:
642 receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
643 return create_statements(receiver, "v8Array(%s, %s)" % (native_value , isolate)), includes
644
645 includes += get_includes_for_type(data_type)
646
647 if data_type == "SerializedScriptValue":
648 includes.append("%s.h" % data_type)
649 if used_as_return_value:
650 receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
651 js_value = "%s ? %s->deserialize() : v8::Handle<v8::Value>(v8::Null( %s))" % (native_value, native_value, isolate)
652 return create_statements(receiver, js_value), includes
653
654 includes.append("wtf/RefPtr.h")
655 includes.append("wtf/GetPtr.h")
656
657 if used_as_return_value:
658 receiver = ["v8SetReturnValue(%s, %%s);" % callback_info]
659
660 if script_wrappable:
661 # FIXME: Use safe handles
662 if for_main_world_suffix == "ForMainWorld":
663 return create_statements(receiver, "toV8ForMainWorld(%s, %s.Hold er(), %s.GetIsolate())" % (native_value, callback_info, callback_info)), include s
664 return create_statements(receiver, "toV8Fast(%s, %s, %s)" % (native_ value, callback_info, script_wrappable)), includes
665
666 # FIXME: Use safe handles
667 return create_statements(receiver, "toV8(%s, %s, %s)" % (native_value, c reation_context, isolate)), includes
668
669 def get_native_type(self, data_type, called_by_webcore=False, used_as_parame ter=False, used_to_assign_js_value=False, extended_attributes=None):
670 """
671 Return native data_type corresponds to IDL data_type.
672 @param[in] data_type ... IDL data_type
673 @param[in] called_by_webcore
674 @param[in] used_as_parameter
675 """
676 if extended_attributes is None:
677 extended_attributes = {}
678 if data_type == "float":
679 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.
680 if data_type == "double":
681 return "double"
682 if data_type == "int" or data_type == "long" or data_type == "short" or data_type == "byte":
683 return "int"
Nils Barth (inactive) 2013/07/24 11:41:20 How about: if data_type in ['int', 'long', 'short'
684 if data_type == "unsigned long" or data_type == "unsigned int" or data_t ype == "unsigned short" or data_type == "octet":
685 return "unsigned"
686 if data_type == "long long":
687 return "long long"
688 if data_type == "unsigned long long":
689 return "unsigned long long"
690 if data_type == "boolean":
691 return "bool"
692 if data_type == "DOMString" or is_enum_type(data_type):
693 if used_to_assign_js_value:
694 # FIXME: This implements [TreatNullAs=NullString] and [TreatUnde finedAs=NullString],
695 # but the Web IDL spec requires [TreatNullAs=EmptyString] and [T reatUndefinedAs=EmptyString].
696 mode = ""
697 if extended_attributes.get("TreatNullAs") == "NullString" and ex tended_attributes.get("TreatUndefinedAs") == "NullString":
698 mode = "WithUndefinedOrNullCheck"
699 elif extended_attributes.get("TreatNullAs") == "NullString" or " Reflect" in extended_attributes:
700 mode = "WithNullCheck"
701 # FIXME: Add the case for 'elsif ($attributeOrParameter->extende dAttributes->{"TreatUndefinedAs"} and $attributeOrParameter->extendedAttributes- >{"TreatUndefinedAs"} eq "NullString"))'.
702 return "V8StringResource<%s>" % mode
703 if called_by_webcore:
704 return "const String&"
705 return "String"
706
707 # FIXME: remove this
708 adhoc_rules = {
709 "CompareHow": "Range::CompareHow",
710 "DOMTimeStamp": "DOMTimeStamp",
711 "Date": "double",
712 "Dictionary": "Dictionary",
713 "DOMStringList": "RefPtr<DOMStringList>",
714 "MediaQueryListListener": "RefPtr<MediaQueryListListener>",
715 "NodeFilter": "RefPtr<NodeFilter>",
716 "SerializedScriptValue": "RefPtr<SerializedScriptValue>",
717 "XPathNSResolver": "RefPtr<XPathNSResolver>",
718 }
719 if data_type in adhoc_rules:
720 if used_as_parameter:
721 return adhoc_rules[data_type].replace("RefPtr", "PassRefPtr")
722 return adhoc_rules[data_type]
723 if data_type == "any" or is_callback_function_type(data_type):
724 return "ScriptValue"
725
726 if is_union_type(data_type):
727 raise Exception("UnionType is not supported")
728
729 if data_type == "ArrayBuffer":
730 if used_as_parameter:
731 return "ArrayBuffer*"
732 else:
733 return "RefPtr<ArrayBuffer>"
734
735 # We need to check [ImplementedAs] extended attribute for wrapper types.
736 if is_wrapper_type(data_type):
737 interface = self.parse_interface(data_type)
738 data_type = get_impl_name(interface)
739
740 array_or_sequence_type = get_array_type(data_type) or get_sequence_type( data_type)
741 if array_or_sequence_type:
742 data_type = self.get_native_type(array_or_sequence_type)
743 data_type = data_type.replace(">", "> ")
744 return "Vector<%s>" % data_type
745
746 if called_by_webcore:
747 return data_type + "*"
748 elif used_to_assign_js_value:
749 return data_type + "*"
750 elif used_as_parameter:
751 if re.search(">$", data_type):
752 data_type += " "
753 return "PassRefPtr<%s>" % data_type
754 else:
755 return "RefPtr<%s>" % data_type
756
757 def header_files_for_interface(self, interface_name, impl_class_name):
758 includes = []
759 if is_typed_array_type(interface_name):
760 includes.append("wtf/%s.h" % interface_name)
761 elif not skip_include_header(interface_name):
762 idl_filename = self.idl_file_for_interface(interface_name)
763 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.
764 idlRelPath = "bindings/" + abs2rel(idl_filename, os.getcwd())
765 includes.append(os.path.dirname(idlRelPath) + os.sep + impl_class_na me + ".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.
766 return includes
767
768 def generate_interface(self, interface):
769 self.interface = interface
770 link_overloaded_functions(self.interface)
771 self.common_template_parameters = {
772 "conditional_string": get_conditional_string(self.interface),
773 }
774 if self.generate_h:
775 if interface.is_callback:
776 self.generate_callback_header()
777 else:
778 self.generate_header()
779 if self.generate_cpp:
780 if interface.is_callback:
781 self.generate_callback_implementation()
782 else:
783 self.generate_implementation()
784
785 def write_interface(self):
786 if self.interface_name in self.idl_definitions.interfaces:
787 interface = self.idl_definitions.interfaces[self.interface_name]
788 self.generate_interface(interface)
789 if self.generate_h:
790 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.
791 with open(header_filename, "w") as f:
792 f.write(self.header)
793 if self.generate_cpp:
794 implementation_filename = self.output_directory + os.sep + get_v 8_class_name(self.interface) + ".cpp"
do-not-use 2013/07/24 11:17:59 Could use os.path.join()
795 with open(implementation_filename, "w") as f:
796 f.write(self.implementation)
797 else:
798 raise Exception("%s not in IDL definitions" % self.interface_name)
799
800 def generate_callback_header(self):
801 impl_class_name = get_impl_name(self.interface)
802 v8_class_name = get_v8_class_name(self.interface)
803 includes = [
804 "bindings/v8/ActiveDOMCallback.h",
805 "bindings/v8/DOMWrapperWorld.h",
806 "bindings/v8/ScopedPersistent.h",
807 ]
808 includes += self.header_files_for_interface(self.interface.name, impl_cl ass_name)
809 includes = sort_and_remove_duplicate(includes)
810 class_public_definitions = []
811 for operation in self.interface.operations:
812 # only bool used for callback .h
813 code = "virtual %s %s(%s);" % (self.get_native_type(operation.data_t ype), operation.name, self.get_callback_parameter_declaration(operation))
814 class_public_definitions.append(code)
815
816 template_parameters = self.common_template_parameters.copy()
817 template_parameters.update({
818 "interface_name": self.interface.name,
819 "impl_class_name": impl_class_name,
820 "v8_class_name": v8_class_name,
821 "includes": includes,
822 "class_public_definitions": class_public_definitions,
823 })
824
825 self.header = apply_template("templates/callback.h", template_parameters )
826
827 def generate_callback_implementation(self):
828 impl_class_name = get_impl_name(self.interface)
829 v8_class_name = get_v8_class_name(self.interface)
830 includes = [
831 "core/dom/ScriptExecutionContext.h",
832 "bindings/v8/V8Binding.h",
833 "bindings/v8/V8Callback.h",
834 "wtf/Assertions.h",
835 ]
836 functions = []
837 for operation in self.interface.operations:
838 if "Custom" in operation.extended_attributes:
839 continue
840 includes += get_includes_for_type(operation.data_type)
841 for parameter in operation.arguments:
842 includes += get_includes_for_parameter(parameter)
843 if operation.data_type != "boolean":
844 raise Exception("We don't yet support callbacks that return non- boolean values.")
845 parameters = []
846 for parameter in operation.arguments:
847 receiver = "v8::Handle<v8::Value> %sHandle = %%s;" % parameter.n ame
848 native_to_js_value_statement, additional_includes = self.get_nat ive_to_js_value_statement(parameter.data_type, parameter.extended_attributes, pa rameter.name, receiver=receiver, creation_context="v8::Handle<v8::Object>()", is olate="isolate")
849 includes += additional_includes
850 parameters.append({
851 "name": parameter.name,
852 "native_to_js_value_statement": native_to_js_value_statement ,
853 })
854 definition = {
855 "return_type": self.get_native_type(operation.data_type),
856 "name": operation.name,
857 "parameter_declaration": self.get_callback_parameter_declaration (operation),
858 "prepare_js_parameters": "",
859 "handles": ",\n".join(["%sHandle" % parameter.name for parameter in operation.arguments]),
860 "parameters": parameters,
861 }
862 functions.append(definition)
863
864 includes = sort_and_remove_duplicate(includes)
865
866 template_parameters = self.common_template_parameters.copy()
867 template_parameters.update({
868 "interface_name": self.interface.name,
869 "impl_class_name": impl_class_name,
870 "v8_class_name": v8_class_name,
871 "includes": includes,
872 "functions": functions,
873 })
874 self.implementation = apply_template("templates/callback.cpp", template_ parameters)
875
876 def generate_header(self):
877 # TODO: implement
878 self.header = ""
879
880 def generate_implementation(self):
881 # TODO: implement
882 self.implementation = ""
39 883
40 884
41 def generate_dummy_header_and_cpp(target_interface_name, output_directory): 885 def generate_dummy_header_and_cpp(target_interface_name, output_directory):
42 header_basename = 'V8%s.h' % target_interface_name 886 header_basename = 'V8%s.h' % target_interface_name
43 cpp_basename = 'V8%s.cpp' % target_interface_name 887 cpp_basename = 'V8%s.cpp' % target_interface_name
44 header_fullname = os.path.join(output_directory, header_basename) 888 header_fullname = os.path.join(output_directory, header_basename)
45 cpp_fullname = os.path.join(output_directory, cpp_basename) 889 cpp_fullname = os.path.join(output_directory, cpp_basename)
46 contents = """/* 890 contents = """/*
47 This file is generated just to tell build scripts that {header_basename} and 891 This file is generated just to tell build scripts that {header_basename} and
48 {cpp_basename} are created for {target_interface_name}.idl, and thus 892 {cpp_basename} are created for {target_interface_name}.idl, and thus
49 prevent the build scripts from trying to generate {header_basename} and 893 prevent the build scripts from trying to generate {header_basename} and
50 {cpp_basename} at every build. This file must not be tried to compile. 894 {cpp_basename} at every build. This file must not be tried to compile.
51 */ 895 */
52 """.format(**locals()) 896 """.format(**locals())
53 with open(header_fullname, 'w') as header_file: 897 with open(header_fullname, 'w') as header_file:
54 header_file.write(contents) 898 header_file.write(contents)
55 with open(cpp_fullname, 'w') as cpp_file: 899 with open(cpp_fullname, 'w') as cpp_file:
56 cpp_file.write(contents) 900 cpp_file.write(contents)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698