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

Side by Side Diff: Source/bindings/scripts/code_generator_v8.py

Issue 17572008: WIP IDL compiler rewrite (Closed) Base URL: https://chromium.googlesource.com/chromium/blink@master
Patch Set: non-callback headers working Created 7 years, 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 unified diff | Download patch
OLDNEW
(Empty)
1 # This library is free software; you can redistribute it and/or
2 # modify it under the terms of the GNU Library General Public
3 # License as published by the Free Software Foundation; either
4 # version 2 of the License, or (at your option) any later version.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Library General Public License for more details.
10 #
11 # You should have received a copy of the GNU Library General Public License
12 # along with this library; see the file COPYING.LIB. If not, write to
13 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 # Boston, MA 02111-1307, USA.
15 #
16
17
18 import os
19 import os.path
20 import sys
21 import json
22 import re
23
24 import generate_bindings
25
26 import pprint
27 pp = pprint.PrettyPrinter(indent=2, width=80)
28
29
30 _current_dir = os.path.dirname(os.path.realpath(__file__))
31 # jinja2 is in chromium's third_party directory
32 sys.path.append(os.path.join(_current_dir, *([os.pardir] * 4)))
33 import jinja2
34
35
36 ### basic utility
37
38 def pathsplit(path):
39 dirs = []
40 while True:
41 (dirname, basename) = os.path.split(path)
42 if basename=="":
43 break
44 dirs.append(basename)
45 path = dirname
46 dirs.reverse()
47 return dirs
48
49 def abs2rel(path, basedir):
50 path_dirs = pathsplit(os.path.abspath(path))
51 basedir_dirs = pathsplit(os.path.abspath(basedir))
52 common_dirs = 0
53 for i in range(min(len(path_dirs), len(basedir_dirs))):
54 if path_dirs[i] != basedir_dirs[i]:
55 break
56 common_dirs += 1
57 relpath = []
58 for i in range(len(basedir_dirs)-common_dirs):
59 relpath.append("..")
60 relpath.extend(path_dirs[common_dirs:])
61 return os.sep.join(relpath)
62
63 def get_path(dic, keys):
64 node = dic
65 for key in keys:
66 if key not in node:
67 return None
68 node = node[key]
69 return node
70
71 def apply_template(path_to_template, params):
72 dirname, basename = os.path.split(path_to_template)
73 path_to_templates = os.path.join(_current_dir, "templates")
74 jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader([dirname, path _to_templates]))
75 template = jinja_env.get_template(basename)
76 return template.render(params)
77
78
79
80 ### subroutine for code generator
81
82 def create_arguments(arguments):
83 return ", ".join([argument for argument in arguments if argument])
84
85 def get_v8_class_name(interface):
86 return "V8" + interface.name
87
88 def get_impl_name(interface):
89 implementedAs = interface.extended_attributes.get("ImplementedAs")
90 if implementedAs is not None:
91 return implementedAs
92 return interface.name
93
94 def get_conditional_string(interface_or_attribute_or_operation):
95 conditional = interface_or_attribute_or_operation.extended_attributes.get("C onditional");
96 if conditional is None:
97 return ""
98 else:
99 operator = ""
100 if "&" in operator:
101 operator = "&"
102 if "|" in operator:
103 operator = "|"
104 if operator == "":
105 return "ENABLE(%s)" % conditional;
106 else:
107 # Avoid duplicated conditions.
108 conditions = dict([(expression, True) for expression in conditional. split(operator)])
109 return (operator + operator).join(["ENABLE(%s)" % expression for exp ression in sorted(conditions.keys())])
110
111 def get_includes_for_type(type):
112 if skip_include_header(type):
113 return []
114
115 # Default includes
116 includes = []
117 if type == "EventListener":
118 includes.append("core/dom/EventListener.h")
119 elif type == "SerializedScriptValue":
120 includes.append("bindings/v8/SerializedScriptValue.h")
121 elif type == "any" or is_callback_function_type(type):
122 includes.append("bindings/v8/ScriptValue.h")
123 else:
124 includes.append("V8%s.h" % type)
125
126 # Additional includes
127 if type == "CSSStyleSheet":
128 includes.append("core/css/CSSImportRule.h")
129
130 if not is_dom_node_type(type):
131 includes.append("wtf/RefCounted.h")
132 includes.append("wtf/RefPtr.h")
133 includes.append("wtf/GetPtr.h")
134
135 print "[get_includes_for_type]", pp.pformat(includes)
136 return includes
137
138 def get_includes_for_parameter(parameter):
139 includes = []
140 array_or_sequence_type = get_array_type(parameter.data_type) or get_sequence _type(parameter.data_type)
141 if array_or_sequence_type:
142 if is_ref_ptr_type(array_or_sequence_type):
143 includes += get_includes_for_type(array_or_sequence_type)
144 else:
145 includes += get_includes_for_type(parameter.data_type)
146 return includes
147
148
149 def get_includes_for_operation(operation):
150 includes = get_includes_for_type(operation.data_type)
151 for parameter in operation.parameters:
152 includes += get_includes_for_parameter(parameter)
153 return includes
154
155 def link_overloaded_functions(interface):
156 name_to_operations = {}
157 for operation in interface.functions:
158 name = operation.name
159 if not name:
160 operation.overloads = []
161 operation.overload_index = 0
162 continue
163 if name not in name_to_operations:
164 name_to_operations[name] = []
165 name_to_operations[name].append(operation)
166 operation.overloads = name_to_operations[name]
167 operation.overload_index = len(name_to_operations[name])
168
169 def apply_conditional(operation_or_attribute, code):
170 conditional_string = get_conditional_string(operation_or_attribute)
171 if conditional_string:
172 wrapped_code = "#if %s\n" % conditional_string
173 wrapped_code += code
174 wrapped_code += "#endif // %s\n" % conditional_string
175 return wrapped_code
176 else:
177 return code
178
179 def get_namespace_for_interface(interface):
180 if is_typed_array_type(interface.name):
181 return "WTF"
182 return "WebCore"
183
184
185 ### Types
186
187 # IDL type: [element's C++ type, V8 type]
188 typed_arrays = {
189 "ArrayBuffer": [],
190 "ArrayBufferView": [],
191 "Uint8Array": ["unsigned char", "v8::kExternalUnsignedByteArray"],
192 "Uint8ClampedArray": ["unsigned char", "v8::kExternalPixelArray"],
193 "Uint16Array": ["unsigned short", "v8::kExternalUnsignedShortArray"],
194 "Uint32Array": ["unsigned int", "v8::kExternalUnsignedIntArray"],
195 "Int8Array": ["signed char", "v8::kExternalByteArray"],
196 "Int16Array": ["short", "v8::kExternalShortArray"],
197 "Int32Array": ["int", "v8::kExternalIntArray"],
198 "Float32Array": ["float", "v8::kExternalFloatArray"],
199 "Float64Array": ["double", "v8::kExternalDoubleArray"],
200 }
201
202 primitive_types = {
203 "boolean": True,
204 "void": True,
205 "Date": True,
206 "byte": True,
207 "octet": True,
208 "short": True,
209 "long": True,
210 "long long": True,
211 "unsigned short": True,
212 "unsigned long": True,
213 "unsigned long long": True,
214 "float": True,
215 "double": True,
216 }
217
218 enum_types = {
219 }
220
221 callback_function_types = {
222 }
223
224 non_wrapper_types = {
225 "CompareHow": True,
226 "DOMTimeStamp": True,
227 "Dictionary": True,
228 "EventListener": True,
229 # FIXME: When EventTarget is an interface and not a mixin, fix this so that
230 # EventTarget is treated as a wrapper type.
231 "EventTarget": True,
232 "MediaQueryListListener": True,
233 "NodeFilter": True,
234 "SerializedScriptValue": True,
235 "any": True,
236 }
237
238 dom_node_types = {
239 "Attr": True,
240 "CDATASection": True,
241 "CharacterData": True,
242 "Comment": True,
243 "Document": True,
244 "DocumentFragment": True,
245 "DocumentType": True,
246 "Element": True,
247 "Entity": True,
248 "HTMLDocument": True,
249 "Node": True,
250 "Notation": True,
251 "ProcessingInstruction": True,
252 "ShadowRoot": True,
253 "SVGDocument": True,
254 "Text": True,
255 "TestNode": True,
256 }
257
258 def get_sequence_type(type):
259 matched = re.match("^sequence<([\w\d_\s]+)>.*", type)
260 if matched:
261 return matched.group(1)
262 return "";
263
264 def get_array_type(type):
265 matched = re.match("^([\w\d_\s]+)\[\]", type)
266 if matched:
267 return matched.group(1)
268 return "";
269
270 def is_wrapper_type(type):
271 if get_array_type(type):
272 return False
273 if get_sequence_type(type):
274 return False
275 if is_callback_function_type(type):
276 return False
277 if is_enum_type(type):
278 return False
279 if is_primitive_type(type):
280 return False
281 if type == "DOMString":
282 return False
283 return not non_wrapper_types.get(type);
284
285 def is_typed_array_type(type):
286 return type in typed_arrays
287
288 def is_primitive_type(type):
289 if type in primitive_types:
290 return True
291 return False
292
293 def is_enum_type(type):
294 if type in enum_types:
295 return True
296 return False
297
298 def is_callback_function_type(type):
299 if type in callback_function_types:
300 return True
301 return False
302
303 def is_dom_node_type(type):
304 if type in dom_node_types:
305 return True
306 if re.match("/^HTML.*Element$/", type):
307 return True
308 if re.match("/^SVG.*Element$/", type):
309 return True
310 return False
311
312 def skip_include_header(type):
313 if is_primitive_type(type):
314 return True
315 if is_enum_type(type):
316 return True
317 if is_callback_function_type(type):
318 return True
319 if type=="DOMString":
320 return True
321 return False
322
323 def is_constructable(interface):
324 for name in ["CustomConstructor", "Constructor", "ConstructorTemplate"]:
325 if name in interface.extended_attributes:
326 return True
327 return False
328
329
330 def has_custom_getter(extended_attributes):
331 return "Custom" in extended_attributes or "CustomGetter" in extended_attribu tes
332
333 def has_custom_setter(extended_attributes):
334 return "Custom" in extended_attributes or "CustomSetter" in extended_attribu tes
335
336 def has_custom_method(extended_attributes):
337 return "Custom" in extended_attributes
338
339 def is_constructor_template(interface, template_name):
340 return interface.extended_attributes.get("ConstructorTemplate")==template_na me
341
342 def needs_opaque_root_for_gc(interface):
343 for name in ["GenerateIsReachable", "CustomIsReachable"]:
344 if name in interface.extended_attributes:
345 return True
346 return False
347
348 # URL becomes url, but SetURL becomes setURL.
349 def to_method_name(name):
350 new_name = name[0].lower() + name[1:]
351 for keyword in ["HTML", "URL", "JS", "XML", "XSLT", "CSS", ]:
352 keyword_lcfirst = keyword[0].lower() + name[1:]
353 new_name = re.sub("/^"+keyword_lcfirst+"/", keyword, new_name)
354
355 # For HTML5 FileSystem API Flags attributes.
356 # (create is widely used to instantiate an object and must be avoided.)
357 new_name = re.sub("/^create$/", "isCreate", new_name)
358 new_name = re.sub("/^exclusive$/", "isExclusive", new_name)
359
360 return new_name
361
362 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
363 def get_runtime_enable_function_name(interface_or_attribute_or_function):
364 # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the R untimeEnabledFeatures::{FeatureName}Enabled() method.
365 enabled_at_runtime = interface_or_attribute_or_function.extended_attributes. get("EnabledAtRuntime")
366 if enabled_at_runtime:
367 return "RuntimeEnabledFeatures::%sEnabled" % to_method_name(enabled_at_r untime)
368
369 # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enab led().
370 return "RuntimeEnabledFeatures::%sEnabled" % to_method_name(interface_or_att ribute_or_function.name)
371
372 def requires_custom_signature(function):
373 # No signature needed for Custom function
374 if has_custom_method(function.extended_attributes):
375 return False
376 # No signature needed for overloaded function
377 if len(function.overloads) > 1:
378 return False
379 if function.is_static:
380 return False
381 # Type checking is performed in the generated code
382 if function.extended_attributes.get("StrictTypeChecking"):
383 return False
384 for parameter in function.parameters:
385 if parameter.is_optional and not parameter.extended_attributes.get("Defa ult") or is_callback_interface(parameter.type):
386 return False
387
388 for parameter in function.parameters:
389 if is_wrapper_type(parameter.type):
390 return True
391 return False
392
393 def is_standard_function(interface, function):
394 for key in ["Unforgeable", "EnabledAtRuntime", "EnabledPerContext", "DoNotCh eckSignature", "NotEnumerable", "ReadOnly"]:
395 if function.extended_attributes.get(key):
396 return False
397 if function.is_static:
398 return False
399 if requires_custom_signature(function):
400 return False
401 if function.extended_attributes.get("DoNotCheckSecurity") and interface.exte nded_attributes.get("CheckSecurity") or interface.name == "Window":
402 return False
403 return True
404
405
406
407 ###
408
409
410 ### main
411 class code_generator_v8:
412 def __init__(self, document, idl_directories, dependent_idl_files, options):
413 self.document = document
414 self.dependent_idl_files = dependent_idl_files
415 self.idl_directories = idl_directories
416 self.idl_files = {}
417 self.options = options
418 self.header = ""
419 self.implementation = ""
420 self.cached_interfaces = {}
421
422 enum_types = dict([ [enum["name"], enum["values"]] for enum in self.docu ment.enumerations ])
423 # print "enum_types", pp.pformat(enum_types)
424 callback_function_types = dict([ [enum["name"], enum] for enum in self.d ocument.callback_functions ])
425 self.prepare_idl_files()
426
427 def prepare_idl_files(self):
428 directories = [ os.getcwd() + os.sep + directory for directory in self.i dl_directories ]
429 directories = filter(lambda path: os.path.isdir(path), directories)
430 directories.append(".")
431 # print "[prepare_idl_files] directories", directories
432 for idl_file in self.dependent_idl_files:
433 basename, ext = os.path.splitext(os.path.basename(idl_file))
434 self.idl_files[basename] = idl_file
435 # print("[idl_files]", idl_files)
436 for directory in directories:
437 for root, dirs, files in os.walk(directory):
438 for file in files:
439 basename, ext = os.path.splitext(file)
440 if ext==".idl":
441 fullpath = root + os.sep + file
442 self.idl_files[basename] = fullpath
443 # for key, value in enumerate(self.idl_files):
444 # print("[idl_files]", key, value)
445
446 def idl_file_for_interface(self, interface_name):
447 # print "[idl_file_for_interface]", interface_name, len(idl_files)
448 # print("[idl_files]", idl_files)
449 return self.idl_files.get(interface_name)
450
451 def parse_interface(self, interface_name):
452 if interface_name in self.cached_interfaces:
453 self.cached_interfaces[interface_name]
454
455 # Step #1: Find the IDL file associated with 'interface'
456 filename = self.idl_file_for_interface(interface_name)
457 if filename is None:
458 raise Exception("Could NOT find IDL file for interface \"%s\"" % int erface_name);
459
460 if self.options.verbose:
461 print " | |> Parsing parent IDL \"%s\" for interface \"%s\"" % (f ilename, interface_name)
462
463 # Step #2: Parse the found IDL file (in quiet mode).
464 document = generate_bindings.read_pickled_idl(interface_name)
465 for interface in document.interfaces:
466 if interface.name == interface_name or interface.is_partial:
467 self.cached_interfaces[interface_name] = interface
468 return interface
469
470 raise Exception("Could NOT find interface definition for %s in %s" % (in terface_name, filename));
471
472 def for_all_parents(self, interface):
473 for direct_parent_interface_name in interface.parents:
474 direct_parent_interface = self.parse_interface(direct_parent_interfa ce_name)
475 yield direct_parent_interface
476 for parent_interface in self.for_all_parents(direct_parent_interface ):
477 yield parent_interface
478
479 def inherits_interface(self, interface, interface_name):
480 if interface.name == interface_name:
481 return True
482 for parent_interface in self.for_all_parents(self.interface):
483 if parent_interface.name == interface_name:
484 return True
485 return False
486
487 def interface_inherits_extended_attribute(self, interface, extended_attribut e):
488 if extended_attribute in interface.extended_attributes:
489 return True
490 for parent_interface in self.for_all_parents(interface):
491 if extended_attribute in parent_interface.extended_attributes:
492 return True
493 return False
494
495
496 def get_parameter_declaration(self, operation):
497 parameters = [ "%s %s" % (self.get_native_type(parameter.data_type, used _as_parameter=True, called_by_webcore=True), parameter.name) for parameter in op eration.parameters ]
498 return ", ".join(parameters)
499
500 def get_native_to_js_value(self, type, extended_attributes, native_value, in dent, receiver, creation_context, \
501 isolate, holder_container="", script_wrappable="" , return_handle_type="", for_main_world_suffix="", return_value_arg=""):
502 """
503 Create statement which convert native(C++) value into JS value.
504
505 @param[in] type
506 @param[in] extended_attributes
507 @param[in] native_value
508 @param[in] indent
509 @param[in] receiver must contain one "%s". to return someth ing: v8SetReturnValue(<holder_container>, %s);
510 @param[in] creation_context
511 @param[in] isolate
512 @param[in] holder_container
513 @param[in] script_wrappable
514 @param[in] return_handle_type
515 @param[in] for_main_world_suffix
516 @param[in] return_value_arg
517 """
518 def create_statement(js_value):
519 return indent + receiver % js_value
520
521 if not isolate:
522 raise Exception("An Isolate is mandatory for native value => JS valu e conversion.")
523
524 # long long and unsigned long long are not representable in ECMAScript.
525 if type == "long long" or type == "unsigned long long" or type == "DOMTi meStamp":
526 return create_statement("v8::Number::New(static_cast<double>(%s))" % native_value)
527
528 if is_primitive_type(type):
529 if not (type=="float" or type=="double"):
530 raise Exception("unexpected type %s" % type)
531 return create_statement("v8::Number::New(%s)" % native_value)
532
533 if type=="DOMString" or is_enum_type(type):
534 conversion = extended_attributes.get("TreatReturnedNullStringAs")
535 js_value = ""
536 arguments = create_arguments([native_value, isolate, return_handle_t ype])
537 if conversion is None:
538 js_value = "v8String(%s)" % arguments
539 elif conversion == "Null":
540 js_value = "v8StringOrNull(%s)" % arguments
541 elif conversion == "Undefined":
542 js_value = "v8StringOrUndefined(%s)" % arguments
543 else:
544 raise Exception("Unknown value for TreatReturnedNullStringAs ext ended attribute")
545
546 # FIXME: Use safe handles
547 return create_statement(js_value)
548
549 # FIXME: Use safe handles
550 return create_statement("toV8(%s, %s, %s)" % (native_value, creation_con text, isolate))
551
552 def get_native_type(self, type, called_by_webcore=False, used_as_parameter=F alse):
553 """
554 Return native type corresponds to IDL type.
555 @param[in] type
556 @param[in] called_by_webcore
557 @param[in] used_as_parameter
558 """
559 print "[get_native_type]", type
560 if type=="float":
561 return "float"
562 if type=="double":
563 return "double"
564 if type=="int" or type=="long" or type=="short" or type=="byte":
565 return "int"
566 if type=="unsigned long" or type=="unsigned int" or type=="unsigned shor t" or type=="octet":
567 return "unsigned"
568 if type=="long long":
569 return "long long"
570 if type=="unsigned long long":
571 return "unsigned long long"
572 if type=="boolean":
573 return "bool"
574 if type=="DOMString":
575 if used_as_parameter:
576 if called_by_webcore:
577 return "const String&"
578 else:
579 return "V8StringResource"
580 return "String"
581 # We need to check [ImplementedAs] extended attribute for wrapper types.
582 if is_wrapper_type(type):
583 interface = self.parse_interface(type)
584 type = get_impl_name(interface)
585
586 if used_as_parameter:
587 if called_by_webcore:
588 return type + "*"
589 else:
590 return "PassRefPtr<%s>" % type
591 else:
592 return "RefPtr<%s>" % type
593
594
595 def header_files_for_interface(self, interface_name, impl_class_name):
596 # print "[header_files_for_interface]", interface_name, impl_class_name
597 includes = []
598 if is_typed_array_type(interface_name):
599 includes.append("wtf/%s.h" % interface_name)
600 elif not skip_include_header(interface_name):
601 idl_filename = self.idl_file_for_interface(interface_name)
602 assert idl_filename
603 idlRelPath = "bindings/" + abs2rel(idl_filename, os.getcwd())
604 # print "idlRelPath", idl_filename, idlRelPath, os.getcwd()
605 includes.append(os.path.dirname(idlRelPath) + os.sep + impl_class_na me + ".h")
606 print "[header_files_for_interface] result", pp.pformat(includes)
607 return includes
608
609 def generate_interface(self, interface):
610 self.interface = interface
611
612 self.common_template_parameters = {
613 "conditional_if": "",
614 "conditional_endif": "",
615 }
616 conditional_string = get_conditional_string(self.interface)
617 if conditional_string != "":
618 self.common_template_parameters["conditional_if"] = "#if " + conditi onal_string
619 self.common_template_parameters["conditional_endif"] = "#endif // " + conditional_string
620
621 if self.options.no_h is None:
622 if interface.is_callback:
623 self.generate_callback_header()
624 else:
625 self.generate_header()
626
627 if self.options.no_cpp is None:
628 if interface.is_callback:
629 self.generate_callback_implementation()
630 else:
631 self.generate_implementation()
632
633 def write_interfaces(self):
634 for interface in self.document.interfaces:
635 self.generate_interface(interface)
636 self.write_data()
637
638 def write_data(self):
639 """
640 options.output_directory
641 options.output_headers_directory
642 """
643 # print self.header
644 if self.options.no_h is None:
645 header_filename = self.options.output_headers_directory + os.sep + g et_v8_class_name(self.interface) + ".h"
646 with open(header_filename, "w") as f:
647 f.write(self.header)
648
649 if self.options.no_cpp is None:
650 implementation_filename = self.options.output_directory + os.sep + g et_v8_class_name(self.interface) + ".cpp"
651 with open(implementation_filename, "w") as f:
652 f.write(self.implementation)
653
654
655
656 def generate_to_v8_converters(self, interface, v8_class_name, impl_class_nam e_as_parameter):
657 includes = []
658 code = ""
659 if interface.extended_attributes.get("DoNotGenerateWrap") or interface.e xtended_attributes.get("DoNotGenerateToV8"):
660 return includes, code
661 includes.append("bindings/v8/ScriptController.h")
662 includes.append("core/page/Frame.h")
663 # TODO.....
664 return includes, code
665
666
667 def generate_callback_header(self):
668 impl_class_name = get_impl_name(self.interface);
669 v8_class_name = get_v8_class_name(self.interface);
670
671 template_parameters = self.common_template_parameters.copy()
672 template_parameters.update({
673 "interface_name": self.interface.name,
674 "impl_class_name": impl_class_name,
675 "v8_class_name": v8_class_name,
676 "includes": [
677 "bindings/v8/ActiveDOMCallback.h",
678 "bindings/v8/DOMWrapperWorld.h",
679 "bindings/v8/ScopedPersistent.h",
680 ],
681 "class_public_definitions": [],
682 })
683 template_parameters["includes"].extend(self.header_files_for_interface(s elf.interface.name, impl_class_name))
684 template_parameters["includes"].sort()
685 for operation in self.interface.functions:
686 code = "virtual %s %s(%s);" % (self.get_native_type(operation.data_t ype), operation.name, self.get_parameter_declaration(operation))
687 template_parameters["class_public_definitions"].append(code)
688
689 self.header = apply_template("scripts/callbackHeader.template", template _parameters)
690
691 def generate_callback_implementation(self):
692 # pp.pprint(self.interface)
693 impl_class_name = get_impl_name(self.interface);
694 v8_class_name = get_v8_class_name(self.interface);
695
696 template_parameters = self.common_template_parameters.copy()
697 template_parameters.update({
698 "interface_name": self.interface.name,
699 "impl_class_name": impl_class_name,
700 "v8_class_name": v8_class_name,
701 "main_includes": [
702 v8_class_name+".h",
703 ],
704 "sub_includes": [
705 "core/dom/ScriptExecutionContext.h",
706 "bindings/v8/V8Binding.h",
707 "bindings/v8/V8Callback.h",
708 "wtf/Assertions.h",
709 ],
710 "class_public_definitions": [],
711 "web_core_definitions": [],
712 })
713
714 template_parameters["interface_name"] = self.interface.name
715
716 for operation in self.interface.functions:
717 code = {}
718 if "Custom" in operation.extended_attributes:
719 continue
720 template_parameters["sub_includes"] += get_includes_for_operation(op eration)
721 if operation.data_type != "boolean":
722 raise Exception("We don't yet support callbacks that return non- boolean values.")
723 code["signature"] = "%s %s::%s(%s)" % (self.get_native_type(operatio n.data_type), v8_class_name, operation.name, self.get_parameter_declaration(oper ation))
724
725 prepare_parameter_statements = []
726 code["prepare_js_parameters"] = ""
727 for parameter in operation.parameters:
728 receiver = "v8::Handle<v8::Value> %sHandle = %%s;" % parameter.n ame
729 subcode = self.get_native_to_js_value(parameter.data_type, para meter.extended_attributes, parameter.name, "", receiver, "v8::Handle<v8::Object> ()", "isolate", "") + "\n"
730 subcode += "if (%sHandle.IsEmpty()) {\n" % parameter.name
731 subcode += " if (!isScriptControllerTerminating())\n"
732 subcode += " CRASH();\n"
733 subcode += " return true;\n"
734 subcode += "}\n"
735 code["prepare_js_parameters"] += subcode
736 prepare_parameter_statements.append(" %sHandle" % parameter.n ame)
737
738 if len(prepare_parameter_statements) > 0:
739 subcode = "v8::Handle<v8::Value> argv[] = {\n";
740 subcode += ",\n".join(prepare_parameter_statements)
741 subcode += "\n};";
742 code["prepare_js_parameters"] += subcode
743 else:
744 code["prepare_js_parameters"] += "v8::Handle<v8::Value> *argv = 0;"
745
746 code["number_of_parameters"] = len(operation.parameters)
747 template_parameters["web_core_definitions"].append(code)
748
749 template_parameters["sub_includes"] = list(set(template_parameters["sub_ includes"]))
750 template_parameters["sub_includes"].sort()
751 self.implementation = apply_template("scripts/callbackImplementation.tem plate", template_parameters)
752
753 def get_internal_fields(self):
754 custom_internal_fields = []
755 # Event listeners on DOM nodes are explicitly supported in the GC contro ller.
756 if not self.inherits_interface(self.interface, "Node") and self.interfac e_inherits_extended_attribute(self.interface, "EventTarget"):
757 custom_internal_fields.append("eventListenerCacheIndex")
758 return custom_internal_fields
759
760 def generate_header_custom_internal_field_indices(self):
761 custom_internal_fields = self.get_internal_fields()
762 codes = []
763 custom_field_counter = 0
764 for custom_internal_field in custom_internal_fields:
765 codes.append("static const int %s = v8DefaultWrapperInternalFieldCou nt + %d;" % (custom_internal_field, custom_field_counter))
766 custom_field_counter += 1
767 codes.append("static const int internalFieldCount = v8DefaultWrapperInte rnalFieldCount + %d;" % custom_field_counter)
768 return codes
769
770 def generate_header(self):
771 impl_class_name = get_impl_name(self.interface);
772 v8_class_name = get_v8_class_name(self.interface);
773
774 template_parameters = self.common_template_parameters.copy()
775 template_parameters.update({
776 "interface_name": self.interface.name,
777 "impl_class_name": impl_class_name,
778 "v8_class_name": v8_class_name,
779 "impl_class_name_as_parameter": self.get_native_type(self.interface. name, used_as_parameter=True),
780 "is_constructor_template_of_event": is_constructor_template(self.int erface, "Event"),
781 "needs_opaque_root_for_gc": needs_opaque_root_for_gc(self.interface) ,
782 "inherits_extended_attribute_active_dom_object": self.interface_inhe rits_extended_attribute(self.interface, "ActiveDOMObject"),
783 "inherits_extended_attribute_event_target": self.interface_inherits_ extended_attribute(self.interface, "EventTarget"),
784 "is_constructable": is_constructable(self.interface),
785 "custom_internal_field_indices": self.generate_header_custom_interna l_field_indices(),
786 "includes": [
787 "bindings/v8/WrapperTypeInfo.h",
788 "bindings/v8/V8Binding.h",
789 "bindings/v8/V8DOMWrapper.h",
790 ],
791 "operation_definitions": [],
792 "attribute_definitions": [],
793 })
794
795 link_overloaded_functions(self.interface);
796
797 # Ensure the IsDOMNodeType function is in sync.
798 if is_dom_node_type(self.interface.name) != self.inherits_interface(self .interface, "Node"):
799 inh = self.inherits_interface(self.interface, "Node") and "INHERIT" or ""
800 dom = is_dom_node_type(self.interface.name) and "DOM" or ""
801 print "[IsDOMNodeType]", dom, inh
802 raise Exception("IsDOMNodeType is out of date with respect to %s" % self.interface.name)
803
804 print "Parents", pp.pformat(self.interface.parents)
805 for parent_interface_name in self.interface.parents:
806 # print "ADD H", parent_interface_name
807 template_parameters["includes"].append("V8%s.h" % parent_interface_n ame)
808
809 # TODO Window
810
811 enabled_per_context_functions = [ operation for operation in self.interf ace.functions if operation.name and operation.extended_attributes.get("EnabledPe rContext") ]
812 enabled_per_context_attributes = [ attribute for attribute in self.inter face.attributes if attribute.extended_attributes.get("EnabledPerContext") ]
813
814 for operation in self.interface.functions:
815 if not operation.name:
816 continue
817 if has_custom_method(operation.extended_attributes) and operation.ov erload_index==1:
818 code = "static void %sMethodCustom(const v8::FunctionCallbackInf o<v8::Value>&);" % operation.name
819 template_parameters["operation_definitions"].append(apply_condit ional(operation, code))
820
821 for attribute in self.interface.attributes:
822 if has_custom_getter(attribute.extended_attributes):
823 code = "static void %sAttrGetterCustom(v8::Local<v8::String> nam e, const v8::PropertyCallbackInfo<v8::Value>&);" % attribute.name
824 template_parameters["attribute_definitions"].append(apply_condit ional(attribute, code))
825 if has_custom_setter(attribute.extended_attributes):
826 code = "static void %sAttrSetterCustom(v8::Local<v8::String> nam e, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<void>&);" % attribute.na me
827 template_parameters["attribute_definitions"].append(apply_condit ional(attribute, code))
828
829
830
831
832
833
834
835 # TODO HasCustomConstructor
836
837 # TODO GenerateHeaderNamedAndIndexedPropertyAccessors
838 # TODO GenerateHeaderLegacyCall
839
840 # TODO Window
841
842 template_parameters["install_per_context_properties_body"] = len(enabled _per_context_attributes) > 0 and ";" or " { }"
843 template_parameters["install_per_context_prototype_properties_body"] = l en(enabled_per_context_functions) > 0 and ";" or " { }"
844
845 # TODO HTMLElement
846 # TODO SVGElement
847 # TODO HTMLUnknownElement
848 # TODO Element
849
850 no_to_v8 = "DoNotGenerateToV8" in self.interface.extended_attributes
851 no_wrap = "DoNotGenerateWrap" in self.interface.extended_attributes or n o_to_v8
852 template_parameters["wrap"] = not no_wrap
853 template_parameters["custom_wrap"] = custom_wrap = "CustomToV8" in self. interface.extended_attributes
854 if no_to_v8:
855 if len(list(self.for_all_parents(self.interface))) > 0:
856 raise Exception("Can't suppress toV8 for subclass")
857 elif no_wrap:
858 if not custom_wrap:
859 raise Exception("Must have custom toV8")
860 template_parameters["generate_to_v8"] = True
861
862 template_parameters["includes"].extend(self.header_files_for_interface(s elf.interface.name, impl_class_name))
863 template_parameters["includes"] = list(set(template_parameters["includes "]))
864 template_parameters["includes"].sort()
865
866 self.header = apply_template("scripts/header.template", template_paramet ers)
867
868 # __IMPL__
869 def generate_implementation(self):
870 impl_class_name = get_impl_name(self.interface);
871 v8_class_name = get_v8_class_name(self.interface);
872
873 normal_functions = []
874 enabled_per_context_functions = []
875 for operation in self.interface.functions:
876 if operation.name=="":
877 continue
878 if operation.extended_attributes.get("EnabledPerContext"):
879 enabled_per_context_functions.append(operation)
880 else:
881 normal_functions.append(operation)
882 has_callbacks = False
883 for operation in normal_functions:
884 # Only one table entry is needed for overloaded methods:
885 if operation.overload_index > 1:
886 continue
887 # Don't put any nonstandard functions into this table:
888 if not is_standard_function(self.interface, operation):
889 continue
890 has_callbacks = True
891
892
893
894 inherits_extended_attribute_active_dom_object = self.interface_inherits_ extended_attribute(self.interface, "ActiveDOMObject")
895 inherits_extended_attribute_event_target = self.interface_inherits_exten ded_attribute(self.interface, "EventTarget")
896 has_attributes = len(self.interface.attributes) > 0
897 impl_class_name_as_parameter = self.get_native_type(self.interface.name, used_as_parameter=True)
898
899 template_parameters = self.common_template_parameters.copy()
900 template_parameters.update({
901 "interface_name": self.interface.name,
902 "impl_class_name": impl_class_name,
903 "v8_class_name": v8_class_name,
904 "impl_class_name_as_parameter": impl_class_name_as_parameter,
905 "is_constructor_template_of_event": is_constructor_template(self.int erface, "Event"),
906 "needs_opaque_root_for_gc": needs_opaque_root_for_gc(self.interface) ,
907 "inherits_extended_attribute_active_dom_object": inherits_extended_a ttribute_active_dom_object,
908 "inherits_extended_attribute_event_target": inherits_extended_attrib ute_event_target,
909 "is_constructable": is_constructable(self.interface),
910 "custom_internal_field_indices": self.generate_header_custom_interna l_field_indices(),
911 "namespace_for_interface": get_namespace_for_interface(self.interfac e),
912 "wrapper_type_prototype": self.interface.is_exception and "WrapperTy peErrorPrototype" or "WrapperTypeObjectPrototype",
913 "enabled_at_runtime": "EnabledAtRuntime" in self.interface.extended_ attributes,
914 "enable_function": get_runtime_enable_function_name(self.interface),
915 "configure_template_batched_attribute": has_attributes and v8_class_ name + "Attrs" or "0",
916 "configure_template_attribute_count": has_attributes and "WTF_ARRAY_ LENGTH(%sAttrs)" % v8_class_name or "0",
917 "configure_template_batched_method": has_callbacks and v8_class_name + "Methods" or "0",
918 "configure_template_method_count": has_callbacks and "WTF_ARRAY_LENG TH(%sMethods)" % v8_class_name or "0",
919 "includes": [
920 "bindings/v8/V8Binding.h",
921 "bindings/v8/V8DOMWrapper.h",
922 "core/dom/ContextFeatures.h",
923 "core/dom/Document.h",
924 "RuntimeEnabledFeatures.h",
925 "wtf/UnusedParam.h",
926 ],
927 "operation_definitions": [],
928 "attribute_definitions": [],
929 })
930 template_parameters["to_active_dom_object"] = inherits_extended_attribut e_active_dom_object and v8_class_name + "::toActiveDOMObject" or "0"
931 template_parameters["to_event_target"] = inherits_extended_attribute_eve nt_target and v8_class_name + "::toEventTarget" or "0"
932 template_parameters["root_for_gc"] = needs_opaque_root_for_gc(self.inter face) and v8_class_name + "::opaqueRootForGC" or "0"
933
934 self.generate_to_v8_converters(self.interface, v8_class_name, impl_class _name_as_parameter)
935
936 template_parameters["includes"] += get_includes_for_type(self.interface. name)
937
938 parent_class_name = ""
939 parent_class_template = ""
940 if len(self.interface.parents) > 0:
941 parent_interface_name = self.interface.parents[0]
942 parent_class_name = "V8" + parent_interface_name
943 print "ADD H", parent_interface_name
944 template_parameters["includes"].append("V8%s.h" % parent_interface_n ame)
945 parent_class_template = parent_class_name + "::GetTemplate(isolate, currentWorldType)"
946
947 template_parameters["parent_class_info"] = parent_class_info = parent_cl ass_name and "&%s::info" % parent_class_name or "0"
948 template_parameters["parent_class_template"] = parent_class_template
949
950 template_parameters["includes"] = filter(lambda include: include != v8_c lass_name+".h", list(set(template_parameters["includes"])))
951 template_parameters["includes"].sort()
952 self.implementation = apply_template("scripts/implementation.template", template_parameters)
953
954
955
956 if __name__ == '__main__':
957 # HTMLTitleElement
958 doc = json.loads("""
959 {"idlDocument::callbackFunctions":[],"idlDocument::enumerations":[],"idlDocu ment::fileName":"/mnt/hdd/chromium/src/third_party/WebKit/Source/core/html/HTMLT itleElement.idl","idlDocument::interfaces":[{"domInterface::attributes":[{"domAt tribute::extendedAttributes":{"TreatNullAs":"NullString"},"domAttribute::getterE xceptions":[],"domAttribute::isNullable":null,"domAttribute::isReadOnly":null,"d omAttribute::isStatic":null,"domAttribute::name":"text","domAttribute::setterExc eptions":[],"domAttribute::type":"DOMString"}],"domInterface::constants":[],"dom Interface::constructors":[],"domInterface::customConstructors":[],"domInterface: :extendedAttributes":{},"domInterface::isCallback":null,"domInterface::isExcepti on":null,"domInterface::isPartial":null,"domInterface::name":"HTMLTitleElement", "domInterface::operations":[],"domInterface::parents":["HTMLElement"]}]}
960 """)
961 # print("HTMLTitleElement")
962 # pp.pprint(doc)
963
964 # VoidCallback
965 doc = json.loads("""
966 {"idlDocument::callbackFunctions":[],"idlDocument::enumerations":[],"idlDocu ment::fileName":"/mnt/hdd/chromium/src/third_party/WebKit/Source/core/html/VoidC allback.idl","idlDocument::interfaces":[{"domInterface::attributes":[],"domInter face::constants":[],"domInterface::constructors":[],"domInterface::customConstru ctors":[],"domInterface::extendedAttributes":{},"domInterface::functions":[{"dom Function::extendedAttributes":{},"domFunction::isStatic":null,"domFunction::name ":"handleEvent","domFunction::overloadedIndex":null,"domFunction::parameters":[] ,"domFunction::specials":[],"domFunction::type":"boolean"}],"domInterface::isCal lback":1,"domInterface::isException":null,"domInterface::isPartial":null,"domInt erface::name":"VoidCallback","domInterface::parents":[]}]}
967 """)
968 # print("VoidCallback")
969 # pp.pprint(doc)
970
971 cg = code_generator_v8(doc, ["../modules"], ["/mnt/hdd/chromium/src/third_pa rty/WebKit/Source/core/html/VoidCallback.idl"])
972 for interface in doc["idlDocument::interfaces"]:
973 cg.generate_interface(interface)
974 cg.write_data()
975
976
977 def test_abs2rel(a, b, ref):
978 result = abs2rel(a, b)
979 assert result==ref, "abs2rel(%s, %s) should be %s but actually %s" % (a, b, ref, result)
980
981 test_abs2rel("./a/b/c", ".", "a/b/c")
982 test_abs2rel("/a/b/c", "/a/b/d", "../c")
983
984
985
986
OLDNEW
« no previous file with comments | « Source/bindings/scripts/callbackImplementation.template ('k') | Source/bindings/scripts/generate-bindings.pl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698