]> git.saurik.com Git - apple/javascriptcore.git/blame - inspector/scripts/CodeGeneratorInspector.py
JavaScriptCore-7600.1.4.13.1.tar.gz
[apple/javascriptcore.git] / inspector / scripts / CodeGeneratorInspector.py
CommitLineData
81345200
A
1#!/usr/bin/env python
2# Copyright (c) 2011 Google Inc. All rights reserved.
3# Copyright (c) 2012 Intel Corporation. All rights reserved.
4# Copyright (c) 2013 Apple Inc. All Rights Reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met:
9#
10# * Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer.
12# * Redistributions in binary form must reproduce the above
13# copyright notice, this list of conditions and the following disclaimer
14# in the documentation and/or other materials provided with the
15# distribution.
16# * Neither the name of Google Inc. nor the names of its
17# contributors may be used to endorse or promote products derived from
18# this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32import os.path
33import sys
34import string
35import optparse
36import re
37try:
38 import json
39except ImportError:
40 import simplejson as json
41
42import CodeGeneratorInspectorStrings
43
44
45DOMAIN_DEFINE_NAME_MAP = {
46 "Database": "SQL_DATABASE",
47 "IndexedDB": "INDEXED_DATABASE",
48 "Replay": "WEB_REPLAY",
49}
50
51
52# Manually-filled map of type name replacements.
53TYPE_NAME_FIX_MAP = {
54 "RGBA": "Rgba", # RGBA is reported to be conflicting with a define name in Windows CE.
55 "": "Empty",
56}
57
58
59TYPES_WITH_RUNTIME_CAST_SET = frozenset(["Runtime.RemoteObject", "Runtime.PropertyDescriptor", "Runtime.InternalPropertyDescriptor",
60 "Debugger.FunctionDetails", "Debugger.CallFrame",
61 "Canvas.TraceLog", "Canvas.ResourceInfo", "Canvas.ResourceState",
62 # This should be a temporary hack. TimelineEvent should be created via generated C++ API.
63 "Timeline.TimelineEvent"])
64
65TYPES_WITH_OPEN_FIELD_LIST_SET = frozenset(["Timeline.TimelineEvent",
66 # InspectorStyleSheet not only creates this property but wants to read it and modify it.
67 "CSS.CSSProperty",
68 # InspectorResourceAgent needs to update mime-type.
69 "Network.Response"])
70
71EXACTLY_INT_SUPPORTED = False
72
73INSPECTOR_TYPES_GENERATOR_CONFIG_MAP = {
74 "JavaScript": {
75 "prefix": "JS",
76 "typebuilder_dependency": "",
77 "export_macro": "JS_EXPORT_PRIVATE",
78 },
79 "Web": {
80 "prefix": "Web",
81 "typebuilder_dependency": "#include <inspector/InspectorJSTypeBuilders.h>",
82 "export_macro": "",
83 },
84}
85
86cmdline_parser = optparse.OptionParser(usage="usage: %prog [options] <Inspector.json>")
87cmdline_parser.add_option("--output_h_dir")
88cmdline_parser.add_option("--output_cpp_dir")
89cmdline_parser.add_option("--output_js_dir")
90cmdline_parser.add_option("--output_type") # JavaScript, Web
91cmdline_parser.add_option("--write_always", action="store_true")
92cmdline_parser.add_option("--no_verification", action="store_true")
93
94try:
95 arg_options, arg_values = cmdline_parser.parse_args()
96 if (len(arg_values) < 1):
97 raise Exception("At least one plain argument expected")
98
99 input_json_filename = arg_values[0]
100 dependency_json_filenames = arg_values[1:]
101
102 output_header_dirname = arg_options.output_h_dir
103 output_cpp_dirname = arg_options.output_cpp_dir
104 output_js_dirname = arg_options.output_js_dir
105 output_type = arg_options.output_type
106
107 write_always = arg_options.write_always
108 verification = not arg_options.no_verification
109 if not output_header_dirname:
110 raise Exception("Output .h directory must be specified")
111 if not output_cpp_dirname:
112 raise Exception("Output .cpp directory must be specified")
113 if not output_js_dirname:
114 raise Exception("Output .js directory must be specified")
115 if output_type not in INSPECTOR_TYPES_GENERATOR_CONFIG_MAP.keys():
116 raise Exception("Unknown output type. Allowed types are: %s" % INSPECTOR_TYPES_GENERATOR_CONFIG_MAP.keys())
117except Exception:
118 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
119 exc = sys.exc_info()[1]
120 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
121 sys.stderr.write("Usage: <script> Inspector.json --output_h_dir <output_header_dir> --output_cpp_dir <output_cpp_dir> --output_js_dir <output_js_dir> [--write_always] [--no_verification]\n")
122 exit(1)
123
124
125def dash_to_camelcase(word):
126 return ''.join(x.capitalize() or '-' for x in word.split('-'))
127
128
129def fix_camel_case(name):
130 refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name)
131 refined = to_title_case(refined)
132 return re.sub(r'(?i)HTML|XML|WML|API|GC|XHR|DOM|CSS', lambda pat: pat.group(0).upper(), refined)
133
134
135def to_title_case(name):
136 return name[:1].upper() + name[1:]
137
138
139class Capitalizer:
140 @staticmethod
141 def lower_camel_case_to_upper(str):
142 if len(str) > 0 and str[0].islower():
143 str = str[0].upper() + str[1:]
144 return str
145
146 @staticmethod
147 def upper_camel_case_to_lower(str):
148 pos = 0
149 while pos < len(str) and str[pos].isupper():
150 pos += 1
151 if pos == 0:
152 return str
153 if pos == 1:
154 return str[0].lower() + str[1:]
155 if pos < len(str):
156 pos -= 1
157 possible_abbreviation = str[0:pos]
158 if possible_abbreviation not in Capitalizer.ABBREVIATION:
159 raise Exception("Unknown abbreviation %s" % possible_abbreviation)
160 str = possible_abbreviation.lower() + str[pos:]
161 return str
162
163 @staticmethod
164 def camel_case_to_capitalized_with_underscores(str):
165 if len(str) == 0:
166 return str
167 output = Capitalizer.split_camel_case_(str)
168 return "_".join(output).upper()
169
170 @staticmethod
171 def split_camel_case_(str):
172 output = []
173 pos_being = 0
174 pos = 1
175 has_oneletter = False
176 while pos < len(str):
177 if str[pos].isupper():
178 output.append(str[pos_being:pos].upper())
179 if pos - pos_being == 1:
180 has_oneletter = True
181 pos_being = pos
182 pos += 1
183 output.append(str[pos_being:])
184 if has_oneletter:
185 array_pos = 0
186 while array_pos < len(output) - 1:
187 if len(output[array_pos]) == 1:
188 array_pos_end = array_pos + 1
189 while array_pos_end < len(output) and len(output[array_pos_end]) == 1:
190 array_pos_end += 1
191 if array_pos_end - array_pos > 1:
192 possible_abbreviation = "".join(output[array_pos:array_pos_end])
193 if possible_abbreviation.upper() in Capitalizer.ABBREVIATION:
194 output[array_pos:array_pos_end] = [possible_abbreviation]
195 else:
196 array_pos = array_pos_end - 1
197 array_pos += 1
198 return output
199
200 ABBREVIATION = frozenset(["XHR", "DOM", "CSS"])
201
202VALIDATOR_IFDEF_NAME = "!ASSERT_DISABLED"
203
204
205class DomainNameFixes:
206 @classmethod
207 def get_fixed_data(cls, domain_name):
208 field_name_res = Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent"
209
210 class Res(object):
211 skip_js_bind = domain_name in cls.skip_js_bind_domains
212
213 @staticmethod
214 def get_guard():
215 if domain_name in DOMAIN_DEFINE_NAME_MAP:
216 define_name = DOMAIN_DEFINE_NAME_MAP[domain_name]
217
218 class Guard:
219 @staticmethod
220 def generate_open(output):
221 output.append("#if ENABLE(%s)\n" % define_name)
222
223 @staticmethod
224 def generate_close(output):
225 output.append("#endif // ENABLE(%s)\n" % define_name)
226
227 return Guard
228
229 return Res
230
231 skip_js_bind_domains = set(["DOMDebugger"])
232
233
234class RawTypes(object):
235 @staticmethod
236 def get(json_type):
237 if json_type == "boolean":
238 return RawTypes.Bool
239 elif json_type == "string":
240 return RawTypes.String
241 elif json_type == "array":
242 return RawTypes.Array
243 elif json_type == "object":
244 return RawTypes.Object
245 elif json_type == "integer":
246 return RawTypes.Int
247 elif json_type == "number":
248 return RawTypes.Number
249 elif json_type == "any":
250 return RawTypes.Any
251 else:
252 raise Exception("Unknown type: %s" % json_type)
253
254 # For output parameter all values are passed by pointer except RefPtr-based types.
255 class OutputPassModel:
256 class ByPointer:
257 @staticmethod
258 def get_argument_prefix():
259 return "&"
260
261 @staticmethod
262 def get_parameter_type_suffix():
263 return "*"
264
265 class ByReference:
266 @staticmethod
267 def get_argument_prefix():
268 return ""
269
270 @staticmethod
271 def get_parameter_type_suffix():
272 return "&"
273
274 class BaseType(object):
275 need_internal_runtime_cast_ = False
276
277 @classmethod
278 def request_raw_internal_runtime_cast(cls):
279 if not cls.need_internal_runtime_cast_:
280 cls.need_internal_runtime_cast_ = True
281
282 @classmethod
283 def get_raw_validator_call_text(cls):
284 return "RuntimeCastHelper::assertType<Inspector::InspectorValue::Type%s>" % cls.get_validate_method_params().template_type
285
286 class String(BaseType):
287 @staticmethod
288 def get_getter_name():
289 return "String"
290
291 get_setter_name = get_getter_name
292
293 @staticmethod
294 def get_c_initializer():
295 return "\"\""
296
297 @staticmethod
298 def get_js_bind_type():
299 return "string"
300
301 @staticmethod
302 def get_validate_method_params():
303 class ValidateMethodParams:
304 template_type = "String"
305 return ValidateMethodParams
306
307 @staticmethod
308 def get_output_pass_model():
309 return RawTypes.OutputPassModel.ByPointer
310
311 @staticmethod
312 def is_heavy_value():
313 return True
314
315 @staticmethod
316 def get_array_item_raw_c_type_text():
317 return "String"
318
319 @staticmethod
320 def get_raw_type_model():
321 return TypeModel.String
322
323 class Int(BaseType):
324 @staticmethod
325 def get_getter_name():
326 return "Int"
327
328 @staticmethod
329 def get_setter_name():
330 return "Number"
331
332 @staticmethod
333 def get_c_initializer():
334 return "0"
335
336 @staticmethod
337 def get_js_bind_type():
338 return "number"
339
340 @classmethod
341 def get_raw_validator_call_text(cls):
342 return "RuntimeCastHelper::assertInt"
343
344 @staticmethod
345 def get_output_pass_model():
346 return RawTypes.OutputPassModel.ByPointer
347
348 @staticmethod
349 def is_heavy_value():
350 return False
351
352 @staticmethod
353 def get_array_item_raw_c_type_text():
354 return "int"
355
356 @staticmethod
357 def get_raw_type_model():
358 return TypeModel.Int
359
360 class Number(BaseType):
361 @staticmethod
362 def get_getter_name():
363 return "Double"
364
365 @staticmethod
366 def get_setter_name():
367 return "Number"
368
369 @staticmethod
370 def get_c_initializer():
371 return "0"
372
373 @staticmethod
374 def get_js_bind_type():
375 return "number"
376
377 @staticmethod
378 def get_validate_method_params():
379 class ValidateMethodParams:
380 template_type = "Number"
381 return ValidateMethodParams
382
383 @staticmethod
384 def get_output_pass_model():
385 return RawTypes.OutputPassModel.ByPointer
386
387 @staticmethod
388 def is_heavy_value():
389 return False
390
391 @staticmethod
392 def get_array_item_raw_c_type_text():
393 return "double"
394
395 @staticmethod
396 def get_raw_type_model():
397 return TypeModel.Number
398
399 class Bool(BaseType):
400 @staticmethod
401 def get_getter_name():
402 return "Boolean"
403
404 get_setter_name = get_getter_name
405
406 @staticmethod
407 def get_c_initializer():
408 return "false"
409
410 @staticmethod
411 def get_js_bind_type():
412 return "boolean"
413
414 @staticmethod
415 def get_validate_method_params():
416 class ValidateMethodParams:
417 template_type = "Boolean"
418 return ValidateMethodParams
419
420 @staticmethod
421 def get_output_pass_model():
422 return RawTypes.OutputPassModel.ByPointer
423
424 @staticmethod
425 def is_heavy_value():
426 return False
427
428 @staticmethod
429 def get_array_item_raw_c_type_text():
430 return "bool"
431
432 @staticmethod
433 def get_raw_type_model():
434 return TypeModel.Bool
435
436 class Object(BaseType):
437 @staticmethod
438 def get_getter_name():
439 return "Object"
440
441 @staticmethod
442 def get_setter_name():
443 return "Value"
444
445 @staticmethod
446 def get_c_initializer():
447 return "InspectorObject::create()"
448
449 @staticmethod
450 def get_js_bind_type():
451 return "object"
452
453 @staticmethod
454 def get_output_argument_prefix():
455 return ""
456
457 @staticmethod
458 def get_validate_method_params():
459 class ValidateMethodParams:
460 template_type = "Object"
461 return ValidateMethodParams
462
463 @staticmethod
464 def get_output_pass_model():
465 return RawTypes.OutputPassModel.ByReference
466
467 @staticmethod
468 def is_heavy_value():
469 return True
470
471 @staticmethod
472 def get_array_item_raw_c_type_text():
473 return "Inspector::InspectorObject"
474
475 @staticmethod
476 def get_raw_type_model():
477 return TypeModel.Object
478
479 class Any(BaseType):
480 @staticmethod
481 def get_getter_name():
482 return "Value"
483
484 get_setter_name = get_getter_name
485
486 @staticmethod
487 def get_c_initializer():
488 raise Exception("Unsupported")
489
490 @staticmethod
491 def get_js_bind_type():
492 raise Exception("Unsupported")
493
494 @staticmethod
495 def get_raw_validator_call_text():
496 return "RuntimeCastHelper::assertAny"
497
498 @staticmethod
499 def get_output_pass_model():
500 return RawTypes.OutputPassModel.ByReference
501
502 @staticmethod
503 def is_heavy_value():
504 return True
505
506 @staticmethod
507 def get_array_item_raw_c_type_text():
508 return "Inspector::InspectorValue"
509
510 @staticmethod
511 def get_raw_type_model():
512 return TypeModel.Any
513
514 class Array(BaseType):
515 @staticmethod
516 def get_getter_name():
517 return "Array"
518
519 @staticmethod
520 def get_setter_name():
521 return "Value"
522
523 @staticmethod
524 def get_c_initializer():
525 return "InspectorArray::create()"
526
527 @staticmethod
528 def get_js_bind_type():
529 return "object"
530
531 @staticmethod
532 def get_output_argument_prefix():
533 return ""
534
535 @staticmethod
536 def get_validate_method_params():
537 class ValidateMethodParams:
538 template_type = "Array"
539 return ValidateMethodParams
540
541 @staticmethod
542 def get_output_pass_model():
543 return RawTypes.OutputPassModel.ByReference
544
545 @staticmethod
546 def is_heavy_value():
547 return True
548
549 @staticmethod
550 def get_array_item_raw_c_type_text():
551 return "Inspector::InspectorArray"
552
553 @staticmethod
554 def get_raw_type_model():
555 return TypeModel.Array
556
557
558def replace_right_shift(input_str):
559 return input_str.replace(">>", "> >")
560
561
562class CommandReturnPassModel:
563 class ByReference:
564 def __init__(self, var_type, set_condition):
565 self.var_type = var_type
566 self.set_condition = set_condition
567
568 def get_return_var_type(self):
569 return self.var_type
570
571 @staticmethod
572 def get_output_argument_prefix():
573 return ""
574
575 @staticmethod
576 def get_output_to_raw_expression():
577 return "%s"
578
579 def get_output_parameter_type(self):
580 return self.var_type + "&"
581
582 def get_set_return_condition(self):
583 return self.set_condition
584
585 class ByPointer:
586 def __init__(self, var_type):
587 self.var_type = var_type
588
589 def get_return_var_type(self):
590 return self.var_type
591
592 @staticmethod
593 def get_output_argument_prefix():
594 return "&"
595
596 @staticmethod
597 def get_output_to_raw_expression():
598 return "%s"
599
600 def get_output_parameter_type(self):
601 return self.var_type + "*"
602
603 @staticmethod
604 def get_set_return_condition():
605 return None
606
607 class OptOutput:
608 def __init__(self, var_type):
609 self.var_type = var_type
610
611 def get_return_var_type(self):
612 return "Inspector::TypeBuilder::OptOutput<%s>" % self.var_type
613
614 @staticmethod
615 def get_output_argument_prefix():
616 return "&"
617
618 @staticmethod
619 def get_output_to_raw_expression():
620 return "%s.getValue()"
621
622 def get_output_parameter_type(self):
623 return "Inspector::TypeBuilder::OptOutput<%s>*" % self.var_type
624
625 @staticmethod
626 def get_set_return_condition():
627 return "%s.isAssigned()"
628
629
630class TypeModel:
631 class RefPtrBased(object):
632 def __init__(self, class_name):
633 self.class_name = class_name
634 self.optional = False
635
636 def get_optional(self):
637 result = TypeModel.RefPtrBased(self.class_name)
638 result.optional = True
639 return result
640
641 def get_command_return_pass_model(self):
642 if self.optional:
643 set_condition = "%s"
644 else:
645 set_condition = None
646 return CommandReturnPassModel.ByReference(replace_right_shift("RefPtr<%s>" % self.class_name), set_condition)
647
648 def get_input_param_type_text(self):
649 return replace_right_shift("PassRefPtr<%s>" % self.class_name)
650
651 @staticmethod
652 def get_event_setter_expression_pattern():
653 return "%s"
654
655 class Enum(object):
656 def __init__(self, base_type_name):
657 self.type_name = base_type_name + "::Enum"
658
659 def get_optional(base_self):
660 class EnumOptional:
661 @classmethod
662 def get_optional(cls):
663 return cls
664
665 @staticmethod
666 def get_command_return_pass_model():
667 return CommandReturnPassModel.OptOutput(base_self.type_name)
668
669 @staticmethod
670 def get_input_param_type_text():
671 return base_self.type_name + "*"
672
673 @staticmethod
674 def get_event_setter_expression_pattern():
675 raise Exception("TODO")
676 return EnumOptional
677
678 def get_command_return_pass_model(self):
679 return CommandReturnPassModel.ByPointer(self.type_name)
680
681 def get_input_param_type_text(self):
682 return self.type_name
683
684 @staticmethod
685 def get_event_setter_expression_pattern():
686 return "%s"
687
688 class ValueType(object):
689 def __init__(self, type_name, is_heavy):
690 self.type_name = type_name
691 self.is_heavy = is_heavy
692
693 def get_optional(self):
694 return self.ValueOptional(self)
695
696 def get_command_return_pass_model(self):
697 return CommandReturnPassModel.ByPointer(self.type_name)
698
699 def get_input_param_type_text(self):
700 if self.is_heavy:
701 return "const %s&" % self.type_name
702 else:
703 return self.type_name
704
705 def get_opt_output_type_(self):
706 return self.type_name
707
708 @staticmethod
709 def get_event_setter_expression_pattern():
710 return "%s"
711
712 class ValueOptional:
713 def __init__(self, base):
714 self.base = base
715
716 def get_optional(self):
717 return self
718
719 def get_command_return_pass_model(self):
720 return CommandReturnPassModel.OptOutput(self.base.get_opt_output_type_())
721
722 def get_input_param_type_text(self):
723 return "const %s* const" % self.base.type_name
724
725 @staticmethod
726 def get_event_setter_expression_pattern():
727 return "*%s"
728
729 class ExactlyInt(ValueType):
730 def __init__(self):
731 TypeModel.ValueType.__init__(self, "int", False)
732
733 def get_input_param_type_text(self):
734 return "Inspector::TypeBuilder::ExactlyInt"
735
736 def get_opt_output_type_(self):
737 return "Inspector::TypeBuilder::ExactlyInt"
738
739 @classmethod
740 def init_class(cls):
741 cls.Bool = cls.ValueType("bool", False)
742 if EXACTLY_INT_SUPPORTED:
743 cls.Int = cls.ExactlyInt()
744 else:
745 cls.Int = cls.ValueType("int", False)
746 cls.Number = cls.ValueType("double", False)
747 cls.String = cls.ValueType("String", True,)
748 cls.Object = cls.RefPtrBased("Inspector::InspectorObject")
749 cls.Array = cls.RefPtrBased("Inspector::InspectorArray")
750 cls.Any = cls.RefPtrBased("Inspector::InspectorValue")
751
752TypeModel.init_class()
753
754
755# Collection of InspectorObject class methods that are likely to be overloaded in generated class.
756# We must explicitly import all overloaded methods or they won't be available to user.
757INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"])
758
759
760def fix_type_name(json_name):
761 if json_name in TYPE_NAME_FIX_MAP:
762 fixed = TYPE_NAME_FIX_MAP[json_name]
763
764 class Result(object):
765 class_name = fixed
766
767 @staticmethod
768 def output_comment(writer):
769 writer.newline("// Type originally was named '%s'.\n" % json_name)
770 else:
771
772 class Result(object):
773 class_name = json_name
774
775 @staticmethod
776 def output_comment(writer):
777 pass
778
779 return Result
780
781
782class Writer:
783 def __init__(self, output, indent):
784 self.output = output
785 self.indent = indent
786
787 def newline(self, str):
788 if (self.indent):
789 self.output.append(self.indent)
790 self.output.append(str)
791
792 def append(self, str):
793 self.output.append(str)
794
795 def newline_multiline(self, str):
796 parts = str.split('\n')
797 self.newline(parts[0])
798 for p in parts[1:]:
799 self.output.append('\n')
800 if p:
801 self.newline(p)
802
803 def append_multiline(self, str):
804 parts = str.split('\n')
805 self.append(parts[0])
806 for p in parts[1:]:
807 self.output.append('\n')
808 if p:
809 self.newline(p)
810
811 def get_indent(self):
812 return self.indent
813
814 def get_indented(self, additional_indent):
815 return Writer(self.output, self.indent + additional_indent)
816
817 def insert_writer(self, additional_indent):
818 new_output = []
819 self.output.append(new_output)
820 return Writer(new_output, self.indent + additional_indent)
821
822
823class EnumConstants:
824 map_ = {}
825 constants_ = []
826
827 @classmethod
828 def add_constant(cls, value):
829 if value in cls.map_:
830 return cls.map_[value]
831 else:
832 pos = len(cls.map_)
833 cls.map_[value] = pos
834 cls.constants_.append(value)
835 return pos
836
837 @classmethod
838 def get_enum_constant_code(cls):
839 output = []
840 for item in cls.constants_:
841 output.append(" \"" + item + "\"")
842 return ",\n".join(output) + "\n"
843
844
845# Typebuilder code is generated in several passes: first typedefs, then other classes.
846# Manual pass management is needed because we cannot have forward declarations for typedefs.
847class TypeBuilderPass:
848 TYPEDEF = "typedef"
849 MAIN = "main"
850
851
852class TypeBindings:
853 @staticmethod
854 def create_named_type_declaration(json_typable, context_domain_name, type_data):
855 json_type = type_data.get_json_type()
856
857 class Helper:
858 is_ad_hoc = False
859 full_name_prefix_for_use = "Inspector::TypeBuilder::" + context_domain_name + "::"
860 full_name_prefix_for_impl = "Inspector::TypeBuilder::" + context_domain_name + "::"
861
862 @staticmethod
863 def write_doc(writer):
864 if "description" in json_type:
865 writer.newline("/* ")
866 writer.append(json_type["description"])
867 writer.append(" */\n")
868
869 @staticmethod
870 def add_to_forward_listener(forward_listener):
871 forward_listener.add_type_data(type_data)
872
873
874 fixed_type_name = fix_type_name(json_type["id"])
875 return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
876
877 @staticmethod
878 def create_ad_hoc_type_declaration(json_typable, context_domain_name, ad_hoc_type_context):
879 class Helper:
880 is_ad_hoc = True
881 full_name_prefix_for_use = ad_hoc_type_context.container_relative_name_prefix
882 full_name_prefix_for_impl = ad_hoc_type_context.container_full_name_prefix
883
884 @staticmethod
885 def write_doc(writer):
886 pass
887
888 @staticmethod
889 def add_to_forward_listener(forward_listener):
890 pass
891 fixed_type_name = ad_hoc_type_context.get_type_name_fix()
892 return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
893
894 @staticmethod
895 def create_type_declaration_(json_typable, context_domain_name, fixed_type_name, helper):
896 if json_typable["type"] == "string":
897 if "enum" in json_typable:
898
899 class EnumBinding:
900 need_user_runtime_cast_ = False
901 need_internal_runtime_cast_ = False
902
903 @classmethod
904 def resolve_inner(cls, resolve_context):
905 pass
906
907 @classmethod
908 def request_user_runtime_cast(cls, request):
909 if request:
910 cls.need_user_runtime_cast_ = True
911 request.acknowledge()
912
913 @classmethod
914 def request_internal_runtime_cast(cls):
915 cls.need_internal_runtime_cast_ = True
916
917 @classmethod
918 def get_code_generator(enum_binding_cls):
919 #FIXME: generate ad-hoc enums too once we figure out how to better implement them in C++.
920 comment_out = helper.is_ad_hoc
921
922 class CodeGenerator:
923 @staticmethod
924 def generate_type_builder(writer, generate_context):
925 enum = json_typable["enum"]
926 helper.write_doc(writer)
927 enum_name = fixed_type_name.class_name
928 fixed_type_name.output_comment(writer)
929 writer.newline("struct ")
930 writer.append(enum_name)
931 writer.append(" {\n")
932 writer.newline(" enum Enum {\n")
933 for enum_item in enum:
934 enum_pos = EnumConstants.add_constant(enum_item)
935
936 item_c_name = fix_camel_case(enum_item)
937 if item_c_name in TYPE_NAME_FIX_MAP:
938 item_c_name = TYPE_NAME_FIX_MAP[item_c_name]
939 writer.newline(" ")
940 writer.append(item_c_name)
941 writer.append(" = ")
942 writer.append("%s" % enum_pos)
943 writer.append(",\n")
944 writer.newline(" };\n")
945 if enum_binding_cls.need_user_runtime_cast_:
946 raise Exception("Not yet implemented")
947
948 if enum_binding_cls.need_internal_runtime_cast_:
949 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
950 writer.newline(" static void assertCorrectValue(Inspector::InspectorValue* value);\n")
951 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
952
953 validator_writer = generate_context.validator_writer
954
955 domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name)
956 domain_guard = domain_fixes.get_guard()
957 if domain_guard:
958 domain_guard.generate_open(validator_writer)
959
960 validator_writer.newline("void %s%s::assertCorrectValue(Inspector::InspectorValue* value)\n" % (helper.full_name_prefix_for_impl, enum_name))
961 validator_writer.newline("{\n")
962 validator_writer.newline(" WTF::String s;\n")
963 validator_writer.newline(" bool cast_res = value->asString(&s);\n")
964 validator_writer.newline(" ASSERT(cast_res);\n")
965 if len(enum) > 0:
966 condition_list = []
967 for enum_item in enum:
968 enum_pos = EnumConstants.add_constant(enum_item)
969 condition_list.append("s == \"%s\"" % enum_item)
970 validator_writer.newline(" ASSERT(%s);\n" % " || ".join(condition_list))
971 validator_writer.newline("}\n")
972
973 if domain_guard:
974 domain_guard.generate_close(validator_writer)
975
976 validator_writer.newline("\n\n")
977
978 writer.newline("}; // struct ")
979 writer.append(enum_name)
980 writer.append("\n")
981
982 @staticmethod
983 def register_use(forward_listener):
984 pass
985
986 @staticmethod
987 def get_generate_pass_id():
988 return TypeBuilderPass.MAIN
989
990 return CodeGenerator
991
992 @classmethod
993 def get_validator_call_text(cls):
994 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
995
996 @classmethod
997 def get_array_item_c_type_text(cls):
998 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::Enum"
999
1000 @staticmethod
1001 def get_setter_value_expression_pattern():
1002 return "Inspector::TypeBuilder::get%sEnumConstantValue(%s)"
1003
1004 @staticmethod
1005 def reduce_to_raw_type():
1006 return RawTypes.String
1007
1008 @staticmethod
1009 def get_type_model():
1010 return TypeModel.Enum(helper.full_name_prefix_for_use + fixed_type_name.class_name)
1011
1012 return EnumBinding
1013 else:
1014 if helper.is_ad_hoc:
1015
1016 class PlainString:
1017 @classmethod
1018 def resolve_inner(cls, resolve_context):
1019 pass
1020
1021 @staticmethod
1022 def request_user_runtime_cast(request):
1023 raise Exception("Unsupported")
1024
1025 @staticmethod
1026 def request_internal_runtime_cast():
1027 pass
1028
1029 @staticmethod
1030 def get_code_generator():
1031 return None
1032
1033 @classmethod
1034 def get_validator_call_text(cls):
1035 return RawTypes.String.get_raw_validator_call_text()
1036
1037 @staticmethod
1038 def reduce_to_raw_type():
1039 return RawTypes.String
1040
1041 @staticmethod
1042 def get_type_model():
1043 return TypeModel.String
1044
1045 @staticmethod
1046 def get_setter_value_expression_pattern():
1047 return None
1048
1049 @classmethod
1050 def get_array_item_c_type_text(cls):
1051 return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
1052
1053 return PlainString
1054
1055 else:
1056
1057 class TypedefString:
1058 @classmethod
1059 def resolve_inner(cls, resolve_context):
1060 pass
1061
1062 @staticmethod
1063 def request_user_runtime_cast(request):
1064 raise Exception("Unsupported")
1065
1066 @staticmethod
1067 def request_internal_runtime_cast():
1068 RawTypes.String.request_raw_internal_runtime_cast()
1069
1070 @staticmethod
1071 def get_code_generator():
1072 class CodeGenerator:
1073 @staticmethod
1074 def generate_type_builder(writer, generate_context):
1075 helper.write_doc(writer)
1076 fixed_type_name.output_comment(writer)
1077 writer.newline("typedef String ")
1078 writer.append(fixed_type_name.class_name)
1079 writer.append(";\n\n")
1080
1081 @staticmethod
1082 def register_use(forward_listener):
1083 pass
1084
1085 @staticmethod
1086 def get_generate_pass_id():
1087 return TypeBuilderPass.TYPEDEF
1088
1089 return CodeGenerator
1090
1091 @classmethod
1092 def get_validator_call_text(cls):
1093 return RawTypes.String.get_raw_validator_call_text()
1094
1095 @staticmethod
1096 def reduce_to_raw_type():
1097 return RawTypes.String
1098
1099 @staticmethod
1100 def get_type_model():
1101 return TypeModel.ValueType("%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name), True)
1102
1103 @staticmethod
1104 def get_setter_value_expression_pattern():
1105 return None
1106
1107 @classmethod
1108 def get_array_item_c_type_text(cls):
1109 return "const %s%s&" % (helper.full_name_prefix_for_use, fixed_type_name.class_name)
1110
1111 return TypedefString
1112
1113 elif json_typable["type"] == "integer":
1114 if helper.is_ad_hoc:
1115
1116 class PlainInteger:
1117 @classmethod
1118 def resolve_inner(cls, resolve_context):
1119 pass
1120
1121 @staticmethod
1122 def request_user_runtime_cast(request):
1123 raise Exception("Unsupported")
1124
1125 @staticmethod
1126 def request_internal_runtime_cast():
1127 pass
1128
1129 @staticmethod
1130 def get_code_generator():
1131 return None
1132
1133 @classmethod
1134 def get_validator_call_text(cls):
1135 return RawTypes.Int.get_raw_validator_call_text()
1136
1137 @staticmethod
1138 def reduce_to_raw_type():
1139 return RawTypes.Int
1140
1141 @staticmethod
1142 def get_type_model():
1143 return TypeModel.Int
1144
1145 @staticmethod
1146 def get_setter_value_expression_pattern():
1147 return None
1148
1149 @classmethod
1150 def get_array_item_c_type_text(cls):
1151 return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
1152
1153 return PlainInteger
1154
1155 else:
1156
1157 class TypedefInteger:
1158 @classmethod
1159 def resolve_inner(cls, resolve_context):
1160 pass
1161
1162 @staticmethod
1163 def request_user_runtime_cast(request):
1164 raise Exception("Unsupported")
1165
1166 @staticmethod
1167 def request_internal_runtime_cast():
1168 RawTypes.Int.request_raw_internal_runtime_cast()
1169
1170 @staticmethod
1171 def get_code_generator():
1172 class CodeGenerator:
1173 @staticmethod
1174 def generate_type_builder(writer, generate_context):
1175 helper.write_doc(writer)
1176 fixed_type_name.output_comment(writer)
1177 writer.newline("typedef int ")
1178 writer.append(fixed_type_name.class_name)
1179 writer.append(";\n\n")
1180
1181 @staticmethod
1182 def register_use(forward_listener):
1183 pass
1184
1185 @staticmethod
1186 def get_generate_pass_id():
1187 return TypeBuilderPass.TYPEDEF
1188
1189 return CodeGenerator
1190
1191 @classmethod
1192 def get_validator_call_text(cls):
1193 return RawTypes.Int.get_raw_validator_call_text()
1194
1195 @staticmethod
1196 def reduce_to_raw_type():
1197 return RawTypes.Int
1198
1199 @staticmethod
1200 def get_type_model():
1201 return TypeModel.Int
1202
1203 @staticmethod
1204 def get_setter_value_expression_pattern():
1205 return None
1206
1207 @classmethod
1208 def get_array_item_c_type_text(cls):
1209 return helper.full_name_prefix_for_use + fixed_type_name.class_name
1210
1211 return TypedefInteger
1212
1213 elif json_typable["type"] == "object":
1214 if "properties" in json_typable:
1215
1216 class ClassBinding:
1217 resolve_data_ = None
1218 need_user_runtime_cast_ = False
1219 need_internal_runtime_cast_ = False
1220
1221 @classmethod
1222 def resolve_inner(cls, resolve_context):
1223 if cls.resolve_data_:
1224 return
1225
1226 properties = json_typable["properties"]
1227 main = []
1228 optional = []
1229
1230 ad_hoc_type_list = []
1231
1232 for prop in properties:
1233 prop_name = prop["name"]
1234 ad_hoc_type_context = cls.AdHocTypeContextImpl(prop_name, fixed_type_name.class_name, resolve_context, ad_hoc_type_list, helper.full_name_prefix_for_impl)
1235 binding = resolve_param_type(prop, context_domain_name, ad_hoc_type_context)
1236
1237 code_generator = binding.get_code_generator()
1238 if code_generator:
1239 code_generator.register_use(resolve_context.forward_listener)
1240
1241 class PropertyData:
1242 param_type_binding = binding
1243 p = prop
1244
1245 if prop.get("optional"):
1246 optional.append(PropertyData)
1247 else:
1248 main.append(PropertyData)
1249
1250 class ResolveData:
1251 main_properties = main
1252 optional_properties = optional
1253 ad_hoc_types = ad_hoc_type_list
1254
1255 cls.resolve_data_ = ResolveData
1256
1257 for ad_hoc in ad_hoc_type_list:
1258 ad_hoc.resolve_inner(resolve_context)
1259
1260 @classmethod
1261 def request_user_runtime_cast(cls, request):
1262 if not request:
1263 return
1264 cls.need_user_runtime_cast_ = True
1265 request.acknowledge()
1266 cls.request_internal_runtime_cast()
1267
1268 @classmethod
1269 def request_internal_runtime_cast(cls):
1270 if cls.need_internal_runtime_cast_:
1271 return
1272 cls.need_internal_runtime_cast_ = True
1273 for p in cls.resolve_data_.main_properties:
1274 p.param_type_binding.request_internal_runtime_cast()
1275 for p in cls.resolve_data_.optional_properties:
1276 p.param_type_binding.request_internal_runtime_cast()
1277
1278 @classmethod
1279 def get_code_generator(class_binding_cls):
1280 class CodeGenerator:
1281 @classmethod
1282 def generate_type_builder(cls, writer, generate_context):
1283 resolve_data = class_binding_cls.resolve_data_
1284 helper.write_doc(writer)
1285 class_name = fixed_type_name.class_name
1286
1287 is_open_type = (context_domain_name + "." + class_name) in TYPES_WITH_OPEN_FIELD_LIST_SET
1288
1289 fixed_type_name.output_comment(writer)
1290 writer.newline("class ")
1291 writer.append(class_name)
1292 writer.append(" : public ")
1293 if is_open_type:
1294 writer.append("Inspector::InspectorObject")
1295 else:
1296 writer.append("Inspector::InspectorObjectBase")
1297 writer.append(" {\n")
1298 writer.newline("public:\n")
1299 ad_hoc_type_writer = writer.insert_writer(" ")
1300
1301 for ad_hoc_type in resolve_data.ad_hoc_types:
1302 code_generator = ad_hoc_type.get_code_generator()
1303 if code_generator:
1304 code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
1305
1306 writer.newline_multiline(
1307""" enum {
1308 NoFieldsSet = 0,
1309""")
1310
1311 state_enum_items = []
1312 if len(resolve_data.main_properties) > 0:
1313 pos = 0
1314 for prop_data in resolve_data.main_properties:
1315 item_name = Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]) + "Set"
1316 state_enum_items.append(item_name)
1317 writer.newline(" %s = 1 << %s,\n" % (item_name, pos))
1318 pos += 1
1319 all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")"
1320 else:
1321 all_fields_set_value = "0"
1322
1323 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_1
1324 % (all_fields_set_value, class_name, class_name))
1325
1326 pos = 0
1327 for prop_data in resolve_data.main_properties:
1328 prop_name = prop_data.p["name"]
1329
1330 param_type_binding = prop_data.param_type_binding
1331 param_raw_type = param_type_binding.reduce_to_raw_type()
1332
1333 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_2
1334 % (state_enum_items[pos],
1335 Capitalizer.lower_camel_case_to_upper(prop_name),
1336 param_type_binding.get_type_model().get_input_param_type_text(),
1337 state_enum_items[pos], prop_name,
1338 param_raw_type.get_setter_name(), prop_name,
1339 format_setter_value_expression(param_type_binding, "value"),
1340 state_enum_items[pos]))
1341
1342 pos += 1
1343
1344 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_3
1345 % (class_name, class_name, class_name, class_name, class_name))
1346
1347 writer.newline(" /*\n")
1348 writer.newline(" * Synthetic constructor:\n")
1349 writer.newline(" * RefPtr<%s> result = %s::create()" % (class_name, class_name))
1350 for prop_data in resolve_data.main_properties:
1351 writer.append_multiline("\n * .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]))
1352 writer.append_multiline(";\n */\n")
1353
1354 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_4)
1355
1356 writer.newline(" typedef Inspector::TypeBuilder::StructItemTraits ItemTraits;\n")
1357
1358 for prop_data in resolve_data.optional_properties:
1359 prop_name = prop_data.p["name"]
1360 param_type_binding = prop_data.param_type_binding
1361 setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop_name)
1362
1363 writer.append_multiline("\n void %s" % setter_name)
1364 writer.append("(%s value)\n" % param_type_binding.get_type_model().get_input_param_type_text())
1365 writer.newline(" {\n")
1366 writer.newline(" this->set%s(ASCIILiteral(\"%s\"), %s);\n"
1367 % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"],
1368 format_setter_value_expression(param_type_binding, "value")))
1369 writer.newline(" }\n")
1370
1371
1372 if setter_name in INSPECTOR_OBJECT_SETTER_NAMES:
1373 writer.newline(" using Inspector::InspectorObjectBase::%s;\n\n" % setter_name)
1374
1375 if class_binding_cls.need_user_runtime_cast_:
1376 writer.newline(" static PassRefPtr<%s> runtimeCast(PassRefPtr<Inspector::InspectorValue> value)\n" % class_name)
1377 writer.newline(" {\n")
1378 writer.newline(" RefPtr<Inspector::InspectorObject> object;\n")
1379 writer.newline(" bool castRes = value->asObject(&object);\n")
1380 writer.newline(" ASSERT_UNUSED(castRes, castRes);\n")
1381 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
1382 writer.newline(" assertCorrectValue(object.get());\n")
1383 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
1384 writer.newline(" COMPILE_ASSERT(sizeof(%s) == sizeof(Inspector::InspectorObjectBase), type_cast_problem);\n" % class_name)
1385 writer.newline(" return static_cast<%s*>(static_cast<Inspector::InspectorObjectBase*>(object.get()));\n" % class_name)
1386 writer.newline(" }\n")
1387 writer.append("\n")
1388
1389 if class_binding_cls.need_internal_runtime_cast_:
1390 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
1391 writer.newline(" static %s void assertCorrectValue(Inspector::InspectorValue* value);\n" % INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"])
1392 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
1393
1394 closed_field_set = (context_domain_name + "." + class_name) not in TYPES_WITH_OPEN_FIELD_LIST_SET
1395
1396 validator_writer = generate_context.validator_writer
1397
1398 domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name)
1399 domain_guard = domain_fixes.get_guard()
1400 if domain_guard:
1401 domain_guard.generate_open(validator_writer)
1402
1403 validator_writer.newline("void %s%s::assertCorrectValue(Inspector::InspectorValue* value)\n" % (helper.full_name_prefix_for_impl, class_name))
1404 validator_writer.newline("{\n")
1405 validator_writer.newline(" RefPtr<InspectorObject> object;\n")
1406 validator_writer.newline(" bool castRes = value->asObject(&object);\n")
1407 validator_writer.newline(" ASSERT_UNUSED(castRes, castRes);\n")
1408 for prop_data in resolve_data.main_properties:
1409 validator_writer.newline(" {\n")
1410 it_name = "%sPos" % prop_data.p["name"]
1411 validator_writer.newline(" InspectorObject::iterator %s;\n" % it_name)
1412 validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
1413 validator_writer.newline(" ASSERT(%s != object->end());\n" % it_name)
1414 validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
1415 validator_writer.newline(" }\n")
1416
1417 if closed_field_set:
1418 validator_writer.newline(" int foundPropertiesCount = %s;\n" % len(resolve_data.main_properties))
1419
1420 for prop_data in resolve_data.optional_properties:
1421 validator_writer.newline(" {\n")
1422 it_name = "%sPos" % prop_data.p["name"]
1423 validator_writer.newline(" InspectorObject::iterator %s;\n" % it_name)
1424 validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
1425 validator_writer.newline(" if (%s != object->end()) {\n" % it_name)
1426 validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
1427 if closed_field_set:
1428 validator_writer.newline(" ++foundPropertiesCount;\n")
1429 validator_writer.newline(" }\n")
1430 validator_writer.newline(" }\n")
1431
1432 if closed_field_set:
1433 validator_writer.newline(" if (foundPropertiesCount != object->size())\n")
1434 validator_writer.newline(" FATAL(\"Unexpected properties in object: %s\\n\", object->toJSONString().ascii().data());\n")
1435 validator_writer.newline("}\n")
1436
1437 if domain_guard:
1438 domain_guard.generate_close(validator_writer)
1439
1440 validator_writer.newline("\n\n")
1441
1442 if is_open_type:
1443 cpp_writer = generate_context.cpp_writer
1444 writer.append("\n")
1445 writer.newline(" // Property names for type generated as open.\n")
1446 for prop_data in resolve_data.main_properties + resolve_data.optional_properties:
1447 prop_name = prop_data.p["name"]
1448 prop_field_name = Capitalizer.lower_camel_case_to_upper(prop_name)
1449 writer.newline(" static const char* %s;\n" % (prop_field_name))
1450 cpp_writer.newline("const char* %s%s::%s = \"%s\";\n" % (helper.full_name_prefix_for_impl, class_name, prop_field_name, prop_name))
1451
1452
1453 writer.newline("};\n\n")
1454
1455 @staticmethod
1456 def generate_forward_declaration(writer):
1457 class_name = fixed_type_name.class_name
1458 writer.newline("class ")
1459 writer.append(class_name)
1460 writer.append(";\n")
1461
1462 @staticmethod
1463 def register_use(forward_listener):
1464 helper.add_to_forward_listener(forward_listener)
1465
1466 @staticmethod
1467 def get_generate_pass_id():
1468 return TypeBuilderPass.MAIN
1469
1470 return CodeGenerator
1471
1472 @staticmethod
1473 def get_validator_call_text():
1474 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
1475
1476 @classmethod
1477 def get_array_item_c_type_text(cls):
1478 return helper.full_name_prefix_for_use + fixed_type_name.class_name
1479
1480 @staticmethod
1481 def get_setter_value_expression_pattern():
1482 return None
1483
1484 @staticmethod
1485 def reduce_to_raw_type():
1486 return RawTypes.Object
1487
1488 @staticmethod
1489 def get_type_model():
1490 return TypeModel.RefPtrBased(helper.full_name_prefix_for_use + fixed_type_name.class_name)
1491
1492 class AdHocTypeContextImpl:
1493 def __init__(self, property_name, class_name, resolve_context, ad_hoc_type_list, parent_full_name_prefix):
1494 self.property_name = property_name
1495 self.class_name = class_name
1496 self.resolve_context = resolve_context
1497 self.ad_hoc_type_list = ad_hoc_type_list
1498 self.container_full_name_prefix = parent_full_name_prefix + class_name + "::"
1499 self.container_relative_name_prefix = ""
1500
1501 def get_type_name_fix(self):
1502 class NameFix:
1503 class_name = Capitalizer.lower_camel_case_to_upper(self.property_name)
1504
1505 @staticmethod
1506 def output_comment(writer):
1507 writer.newline("// Named after property name '%s' while generating %s.\n" % (self.property_name, self.class_name))
1508
1509 return NameFix
1510
1511 def add_type(self, binding):
1512 self.ad_hoc_type_list.append(binding)
1513
1514 return ClassBinding
1515 else:
1516
1517 class PlainObjectBinding:
1518 @classmethod
1519 def resolve_inner(cls, resolve_context):
1520 pass
1521
1522 @staticmethod
1523 def request_user_runtime_cast(request):
1524 pass
1525
1526 @staticmethod
1527 def request_internal_runtime_cast():
1528 RawTypes.Object.request_raw_internal_runtime_cast()
1529
1530 @staticmethod
1531 def get_code_generator():
1532 pass
1533
1534 @staticmethod
1535 def get_validator_call_text():
1536 return "RuntimeCastHelper::assertType<InspectorValue::TypeObject>"
1537
1538 @classmethod
1539 def get_array_item_c_type_text(cls):
1540 return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
1541
1542 @staticmethod
1543 def get_setter_value_expression_pattern():
1544 return None
1545
1546 @staticmethod
1547 def reduce_to_raw_type():
1548 return RawTypes.Object
1549
1550 @staticmethod
1551 def get_type_model():
1552 return TypeModel.Object
1553
1554 return PlainObjectBinding
1555 elif json_typable["type"] == "array":
1556 if "items" in json_typable:
1557
1558 ad_hoc_types = []
1559
1560 class AdHocTypeContext:
1561 container_full_name_prefix = "<not yet defined>"
1562 container_relative_name_prefix = ""
1563
1564 @staticmethod
1565 def get_type_name_fix():
1566 return fixed_type_name
1567
1568 @staticmethod
1569 def add_type(binding):
1570 ad_hoc_types.append(binding)
1571
1572 item_binding = resolve_param_type(json_typable["items"], context_domain_name, AdHocTypeContext)
1573
1574 class ArrayBinding:
1575 resolve_data_ = None
1576 need_internal_runtime_cast_ = False
1577
1578 @classmethod
1579 def resolve_inner(cls, resolve_context):
1580 if cls.resolve_data_:
1581 return
1582
1583 class ResolveData:
1584 item_type_binding = item_binding
1585 ad_hoc_type_list = ad_hoc_types
1586
1587 cls.resolve_data_ = ResolveData
1588
1589 for t in ad_hoc_types:
1590 t.resolve_inner(resolve_context)
1591
1592 @classmethod
1593 def request_user_runtime_cast(cls, request):
1594 raise Exception("Not implemented yet")
1595
1596 @classmethod
1597 def request_internal_runtime_cast(cls):
1598 if cls.need_internal_runtime_cast_:
1599 return
1600 cls.need_internal_runtime_cast_ = True
1601 cls.resolve_data_.item_type_binding.request_internal_runtime_cast()
1602
1603 @classmethod
1604 def get_code_generator(array_binding_cls):
1605
1606 class CodeGenerator:
1607 @staticmethod
1608 def generate_type_builder(writer, generate_context):
1609 ad_hoc_type_writer = writer
1610
1611 resolve_data = array_binding_cls.resolve_data_
1612
1613 for ad_hoc_type in resolve_data.ad_hoc_type_list:
1614 code_generator = ad_hoc_type.get_code_generator()
1615 if code_generator:
1616 code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
1617
1618 @staticmethod
1619 def generate_forward_declaration(writer):
1620 pass
1621
1622 @staticmethod
1623 def register_use(forward_listener):
1624 item_code_generator = item_binding.get_code_generator()
1625 if item_code_generator:
1626 item_code_generator.register_use(forward_listener)
1627
1628 @staticmethod
1629 def get_generate_pass_id():
1630 return TypeBuilderPass.MAIN
1631
1632 return CodeGenerator
1633
1634 @classmethod
1635 def get_validator_call_text(cls):
1636 return cls.get_array_item_c_type_text() + "::assertCorrectValue"
1637
1638 @classmethod
1639 def get_array_item_c_type_text(cls):
1640 return replace_right_shift("Inspector::TypeBuilder::Array<%s>" % cls.resolve_data_.item_type_binding.get_array_item_c_type_text())
1641
1642 @staticmethod
1643 def get_setter_value_expression_pattern():
1644 return None
1645
1646 @staticmethod
1647 def reduce_to_raw_type():
1648 return RawTypes.Array
1649
1650 @classmethod
1651 def get_type_model(cls):
1652 return TypeModel.RefPtrBased(cls.get_array_item_c_type_text())
1653
1654 return ArrayBinding
1655 else:
1656 # Fall-through to raw type.
1657 pass
1658
1659 raw_type = RawTypes.get(json_typable["type"])
1660
1661 return RawTypeBinding(raw_type)
1662
1663
1664class RawTypeBinding:
1665 def __init__(self, raw_type):
1666 self.raw_type_ = raw_type
1667
1668 def resolve_inner(self, resolve_context):
1669 pass
1670
1671 def request_user_runtime_cast(self, request):
1672 raise Exception("Unsupported")
1673
1674 def request_internal_runtime_cast(self):
1675 self.raw_type_.request_raw_internal_runtime_cast()
1676
1677 def get_code_generator(self):
1678 return None
1679
1680 def get_validator_call_text(self):
1681 return self.raw_type_.get_raw_validator_call_text()
1682
1683 def get_array_item_c_type_text(self):
1684 return self.raw_type_.get_array_item_raw_c_type_text()
1685
1686 def get_setter_value_expression_pattern(self):
1687 return None
1688
1689 def reduce_to_raw_type(self):
1690 return self.raw_type_
1691
1692 def get_type_model(self):
1693 return self.raw_type_.get_raw_type_model()
1694
1695
1696class TypeData(object):
1697 def __init__(self, json_type, json_domain, domain_data):
1698 self.json_type_ = json_type
1699 self.json_domain_ = json_domain
1700 self.domain_data_ = domain_data
1701
1702 if "type" not in json_type:
1703 raise Exception("Unknown type")
1704
1705 json_type_name = json_type["type"]
1706 self.raw_type_ = RawTypes.get(json_type_name)
1707 self.binding_being_resolved_ = False
1708 self.binding_ = None
1709
1710 def get_raw_type(self):
1711 return self.raw_type_
1712
1713 def get_binding(self):
1714 if not self.binding_:
1715 if self.binding_being_resolved_:
1716 raise Exception("Type %s is already being resolved" % self.json_type_["type"])
1717 # Resolve only lazily, because resolving one named type may require resolving some other named type.
1718 self.binding_being_resolved_ = True
1719 try:
1720 self.binding_ = TypeBindings.create_named_type_declaration(self.json_type_, self.json_domain_["domain"], self)
1721 finally:
1722 self.binding_being_resolved_ = False
1723
1724 return self.binding_
1725
1726 def get_json_type(self):
1727 return self.json_type_
1728
1729 def get_name(self):
1730 return self.json_type_["id"]
1731
1732 def get_domain_name(self):
1733 return self.json_domain_["domain"]
1734
1735
1736class DomainData:
1737 def __init__(self, json_domain):
1738 self.json_domain = json_domain
1739 self.types_ = []
1740
1741 def add_type(self, type_data):
1742 self.types_.append(type_data)
1743
1744 def name(self):
1745 return self.json_domain["domain"]
1746
1747 def types(self):
1748 return self.types_
1749
1750
1751class TypeMap:
1752 def __init__(self, api, dependency_api):
1753 self.map_ = {}
1754 self.domains_ = []
1755 self.domains_to_generate_ = []
1756 for json_domain in api["domains"]:
1757 self.add_domain(json_domain, True)
1758 for json_domain in dependency_api["domains"]:
1759 self.add_domain(json_domain, False)
1760
1761 def add_domain(self, json_domain, should_generate):
1762 domain_name = json_domain["domain"]
1763
1764 domain_map = {}
1765 self.map_[domain_name] = domain_map
1766
1767 domain_data = DomainData(json_domain)
1768 self.domains_.append(domain_data)
1769
1770 if should_generate:
1771 # FIXME: The order of types should not matter. The generated code should work regardless of the order of types.
1772 if domain_name == "Page":
1773 self.domains_to_generate_.insert(0, domain_data)
1774 else:
1775 self.domains_to_generate_.append(domain_data)
1776
1777 if "types" in json_domain:
1778 for json_type in json_domain["types"]:
1779 type_name = json_type["id"]
1780 type_data = TypeData(json_type, json_domain, domain_data)
1781 domain_map[type_name] = type_data
1782 domain_data.add_type(type_data)
1783
1784 def domains(self):
1785 return self.domains_
1786
1787 def domains_to_generate(self):
1788 return self.domains_to_generate_
1789
1790 def get(self, domain_name, type_name):
1791 return self.map_[domain_name][type_name]
1792
1793
1794def resolve_param_type(json_parameter, scope_domain_name, ad_hoc_type_context):
1795 if "$ref" in json_parameter:
1796 json_ref = json_parameter["$ref"]
1797 type_data = get_ref_data(json_ref, scope_domain_name)
1798 return type_data.get_binding()
1799 elif "type" in json_parameter:
1800 result = TypeBindings.create_ad_hoc_type_declaration(json_parameter, scope_domain_name, ad_hoc_type_context)
1801 ad_hoc_type_context.add_type(result)
1802 return result
1803 else:
1804 raise Exception("Unknown type")
1805
1806
1807def resolve_param_raw_type(json_parameter, scope_domain_name):
1808 if "$ref" in json_parameter:
1809 json_ref = json_parameter["$ref"]
1810 type_data = get_ref_data(json_ref, scope_domain_name)
1811 return type_data.get_raw_type()
1812 elif "type" in json_parameter:
1813 json_type = json_parameter["type"]
1814 return RawTypes.get(json_type)
1815 else:
1816 raise Exception("Unknown type")
1817
1818
1819def get_ref_data(json_ref, scope_domain_name):
1820 dot_pos = json_ref.find(".")
1821 if dot_pos == -1:
1822 domain_name = scope_domain_name
1823 type_name = json_ref
1824 else:
1825 domain_name = json_ref[:dot_pos]
1826 type_name = json_ref[dot_pos + 1:]
1827
1828 return type_map.get(domain_name, type_name)
1829
1830
1831input_file = open(input_json_filename, "r")
1832json_string = input_file.read()
1833json_api = json.loads(json_string)
1834input_file.close()
1835if not "domains" in json_api:
1836 json_api = {"domains": [json_api]}
1837
1838dependency_api = {"domains": []}
1839for dependency_json_filename in dependency_json_filenames:
1840 dependency_input_file = open(dependency_json_filename, "r")
1841 dependency_json_string = dependency_input_file.read()
1842 dependency_json_api = json.loads(dependency_json_string)
1843 dependency_input_file.close()
1844 if not "domains" in dependency_json_api:
1845 dependency_json_api = {"domains": [dependency_json_api]}
1846 dependency_api["domains"] += dependency_json_api["domains"]
1847
1848
1849class Templates:
1850 def get_this_script_path_(absolute_path):
1851 absolute_path = os.path.abspath(absolute_path)
1852 components = []
1853
1854 def fill_recursive(path_part, depth):
1855 if depth <= 0 or path_part == '/':
1856 return
1857 fill_recursive(os.path.dirname(path_part), depth - 1)
1858 components.append(os.path.basename(path_part))
1859
1860 # Typical path is /Source/WebCore/inspector/CodeGeneratorInspector.py
1861 # Let's take 4 components from the real path then.
1862 fill_recursive(absolute_path, 4)
1863
1864 return "/".join(components)
1865
1866 file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) +
1867"""// Copyright (c) 2013 Apple Inc. All Rights Reserved.
1868// Copyright (c) 2011 The Chromium Authors. All rights reserved.
1869// Use of this source code is governed by a BSD-style license that can be
1870// found in the LICENSE file.
1871""")
1872
1873 frontend_domain_class = string.Template(CodeGeneratorInspectorStrings.frontend_domain_class)
1874 backend_dispatcher_constructor = string.Template(CodeGeneratorInspectorStrings.backend_dispatcher_constructor)
1875 backend_dispatcher_dispatch_method = string.Template(CodeGeneratorInspectorStrings.backend_dispatcher_dispatch_method)
1876 backend_dispatcher_dispatch_method_simple = string.Template(CodeGeneratorInspectorStrings.backend_dispatcher_dispatch_method_simple)
1877 backend_method = string.Template(CodeGeneratorInspectorStrings.backend_method)
1878 frontend_method = string.Template(CodeGeneratorInspectorStrings.frontend_method)
1879 callback_method = string.Template(CodeGeneratorInspectorStrings.callback_method)
1880 frontend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_h)
1881 backend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_h)
1882 backend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_cpp)
1883 frontend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_cpp)
1884 typebuilder_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_h)
1885 typebuilder_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_cpp)
1886 backend_js = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_js)
1887 param_container_access_code = CodeGeneratorInspectorStrings.param_container_access_code
1888
1889
1890
1891
1892
1893type_map = TypeMap(json_api, dependency_api)
1894
1895
1896class NeedRuntimeCastRequest:
1897 def __init__(self):
1898 self.ack_ = None
1899
1900 def acknowledge(self):
1901 self.ack_ = True
1902
1903 def is_acknowledged(self):
1904 return self.ack_
1905
1906
1907def resolve_all_types():
1908 runtime_cast_generate_requests = {}
1909 for type_name in TYPES_WITH_RUNTIME_CAST_SET:
1910 runtime_cast_generate_requests[type_name] = NeedRuntimeCastRequest()
1911
1912 class ForwardListener:
1913 type_data_set = set()
1914 already_declared_set = set()
1915
1916 @classmethod
1917 def add_type_data(cls, type_data):
1918 if type_data not in cls.already_declared_set:
1919 cls.type_data_set.add(type_data)
1920
1921 class ResolveContext:
1922 forward_listener = ForwardListener
1923
1924 for domain_data in type_map.domains():
1925 for type_data in domain_data.types():
1926 binding = type_data.get_binding()
1927 binding.resolve_inner(ResolveContext)
1928 # Do not generate forwards for this type any longer.
1929 ForwardListener.already_declared_set.add(type_data)
1930
1931 for domain_data in type_map.domains():
1932 for type_data in domain_data.types():
1933 full_type_name = "%s.%s" % (type_data.get_domain_name(), type_data.get_name())
1934 request = runtime_cast_generate_requests.pop(full_type_name, None)
1935 binding = type_data.get_binding()
1936 if request:
1937 binding.request_user_runtime_cast(request)
1938
1939 if request and not request.is_acknowledged():
1940 raise Exception("Failed to generate runtimeCast in " + full_type_name)
1941
1942 # FIXME: This assumes all the domains are processed at once. Change this verification
1943 # to only verify runtime casts for the domains being generated.
1944 # if verification:
1945 # for full_type_name in runtime_cast_generate_requests:
1946 # raise Exception("Failed to generate runtimeCast. Type " + full_type_name + " not found")
1947
1948 return ForwardListener
1949
1950
1951global_forward_listener = resolve_all_types()
1952
1953
1954def get_annotated_type_text(raw_type, annotated_type):
1955 if annotated_type != raw_type:
1956 return "/*%s*/ %s" % (annotated_type, raw_type)
1957 else:
1958 return raw_type
1959
1960
1961def format_setter_value_expression(param_type_binding, value_ref):
1962 pattern = param_type_binding.get_setter_value_expression_pattern()
1963 if pattern:
1964 return pattern % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"], value_ref)
1965 else:
1966 return value_ref
1967
1968
1969class Generator:
1970 frontend_domain_class_lines = []
1971
1972 backend_method_implementation_list = []
1973 frontend_method_list = []
1974 backend_js_domain_initializer_list = []
1975
1976 backend_handler_interface_list = []
1977 backend_handler_implementation_list = []
1978 backend_dispatcher_interface_list = []
1979 type_builder_fragments = []
1980 type_builder_forwards = []
1981 validator_impl_list = []
1982 type_builder_impl_list = []
1983
1984
1985 @staticmethod
1986 def go():
1987 Generator.process_types(type_map)
1988
1989 first_cycle_guardable_list_list = [
1990 Generator.backend_method_implementation_list,
1991 Generator.backend_handler_interface_list,
1992 Generator.backend_handler_implementation_list,
1993 Generator.backend_dispatcher_interface_list]
1994
1995 for json_domain in json_api["domains"]:
1996 domain_name = json_domain["domain"]
1997 domain_name_lower = domain_name.lower()
1998
1999 domain_fixes = DomainNameFixes.get_fixed_data(domain_name)
2000
2001 domain_guard = domain_fixes.get_guard()
2002
2003 if domain_guard:
2004 for l in first_cycle_guardable_list_list:
2005 domain_guard.generate_open(l)
2006
2007 frontend_method_declaration_lines = []
2008
2009 if ("commands" in json_domain or "events" in json_domain):
2010 Generator.backend_js_domain_initializer_list.append("// %s.\n" % domain_name)
2011 if not domain_fixes.skip_js_bind:
2012 Generator.backend_js_domain_initializer_list.append("InspectorBackend.register%sDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"%s\");\n" % (domain_name, domain_name))
2013
2014 if "types" in json_domain:
2015 for json_type in json_domain["types"]:
2016 if "type" in json_type and json_type["type"] == "string" and "enum" in json_type:
2017 enum_name = "%s.%s" % (domain_name, json_type["id"])
2018 Generator.process_enum(json_type, enum_name)
2019 elif json_type["type"] == "object":
2020 if "properties" in json_type:
2021 for json_property in json_type["properties"]:
2022 if "type" in json_property and json_property["type"] == "string" and "enum" in json_property:
2023 enum_name = "%s.%s%s" % (domain_name, json_type["id"], to_title_case(json_property["name"]))
2024 Generator.process_enum(json_property, enum_name)
2025
2026 if "events" in json_domain:
2027 if domain_guard:
2028 domain_guard.generate_open(Generator.frontend_method_list)
2029 domain_guard.generate_open(Generator.frontend_domain_class_lines)
2030
2031 for json_event in json_domain["events"]:
2032 Generator.process_event(json_event, domain_name, frontend_method_declaration_lines)
2033
2034 Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None,
2035 exportMacro=INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"],
2036 domainClassName="Inspector%sFrontendDispatcher" % domain_name,
2037 frontendDomainMethodDeclarations="".join(flatten_list(frontend_method_declaration_lines))))
2038
2039 if domain_guard:
2040 domain_guard.generate_close(Generator.frontend_method_list)
2041 domain_guard.generate_close(Generator.frontend_domain_class_lines)
2042
2043 dispatcher_name = "Inspector" + Capitalizer.lower_camel_case_to_upper(domain_name) + "BackendDispatcher"
2044 agent_interface_name = dispatcher_name + "Handler"
2045
2046 if "commands" in json_domain:
2047 Generator.backend_dispatcher_interface_list.append("class %s %s final : public Inspector::InspectorSupplementalBackendDispatcher {\n" % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"], dispatcher_name))
2048 Generator.backend_dispatcher_interface_list.append("public:\n")
2049 Generator.backend_dispatcher_interface_list.append(" static PassRefPtr<%s> create(Inspector::InspectorBackendDispatcher*, %s*);\n" % (dispatcher_name, agent_interface_name))
2050 Generator.backend_dispatcher_interface_list.append(" virtual void dispatch(long callId, const String& method, PassRefPtr<Inspector::InspectorObject> message) override;\n")
2051 Generator.backend_dispatcher_interface_list.append("private:\n")
2052
2053 Generator.backend_handler_interface_list.append("class %s %s {\n" % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"], agent_interface_name))
2054 Generator.backend_handler_interface_list.append("public:\n")
2055
2056 backend_method_count = len(Generator.backend_method_implementation_list)
2057
2058 dispatcher_if_chain = []
2059 dispatcher_commands_list = []
2060 for json_command in json_domain["commands"]:
2061 Generator.process_command(json_command, domain_name, agent_interface_name, dispatcher_name, dispatcher_if_chain, dispatcher_commands_list)
2062
2063 Generator.backend_handler_interface_list.append("protected:\n")
2064 Generator.backend_handler_interface_list.append(" virtual ~%s();\n" % agent_interface_name)
2065 Generator.backend_handler_interface_list.append("};\n\n")
2066
2067 Generator.backend_handler_implementation_list.append("%s::~%s() { }\n" % (agent_interface_name, agent_interface_name))
2068
2069 Generator.backend_dispatcher_interface_list.append("private:\n")
2070 Generator.backend_dispatcher_interface_list.append(" %s(Inspector::InspectorBackendDispatcher*, %s*);\n" % (dispatcher_name, agent_interface_name))
2071 Generator.backend_dispatcher_interface_list.append(" %s* m_agent;\n" % agent_interface_name)
2072 Generator.backend_dispatcher_interface_list.append("};\n\n")
2073
2074 Generator.backend_method_implementation_list.insert(backend_method_count, Templates.backend_dispatcher_constructor.substitute(None,
2075 domainName=domain_name,
2076 dispatcherName=dispatcher_name,
2077 agentName=agent_interface_name))
2078
2079 if len(json_domain["commands"]) <= 5:
2080 Generator.backend_method_implementation_list.insert(backend_method_count + 1, Templates.backend_dispatcher_dispatch_method_simple.substitute(None,
2081 domainName=domain_name,
2082 dispatcherName=dispatcher_name,
2083 ifChain="\n".join(dispatcher_if_chain)))
2084 else:
2085 Generator.backend_method_implementation_list.insert(backend_method_count + 1, Templates.backend_dispatcher_dispatch_method.substitute(None,
2086 domainName=domain_name,
2087 dispatcherName=dispatcher_name,
2088 dispatcherCommands="\n".join(dispatcher_commands_list)))
2089
2090 if domain_guard:
2091 for l in reversed(first_cycle_guardable_list_list):
2092 domain_guard.generate_close(l)
2093 Generator.backend_js_domain_initializer_list.append("\n")
2094
2095 @staticmethod
2096 def process_enum(json_enum, enum_name):
2097 enum_members = []
2098 for member in json_enum["enum"]:
2099 enum_members.append("%s: \"%s\"" % (fix_camel_case(member), member))
2100
2101 Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerEnum(\"%s\", {%s});\n" % (
2102 enum_name, ", ".join(enum_members)))
2103
2104 @staticmethod
2105 def process_event(json_event, domain_name, frontend_method_declaration_lines):
2106 event_name = json_event["name"]
2107
2108 ad_hoc_type_output = []
2109 frontend_method_declaration_lines.append(ad_hoc_type_output)
2110 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
2111
2112 decl_parameter_list = []
2113
2114 json_parameters = json_event.get("parameters")
2115 Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer,
2116 decl_parameter_list,
2117 Generator.EventMethodStructTemplate,
2118 Generator.frontend_method_list, Templates.frontend_method, {"eventName": event_name})
2119
2120 backend_js_event_param_list = []
2121 if json_parameters:
2122 for parameter in json_parameters:
2123 parameter_name = parameter["name"]
2124 backend_js_event_param_list.append("\"%s\"" % parameter_name)
2125
2126 frontend_method_declaration_lines.append(
2127 " void %s(%s);\n" % (event_name, ", ".join(decl_parameter_list)))
2128
2129 Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerEvent(\"%s.%s\", [%s]);\n" % (
2130 domain_name, event_name, ", ".join(backend_js_event_param_list)))
2131
2132 class EventMethodStructTemplate:
2133 @staticmethod
2134 def append_prolog(line_list):
2135 line_list.append(" RefPtr<InspectorObject> paramsObject = InspectorObject::create();\n")
2136
2137 @staticmethod
2138 def append_epilog(line_list):
2139 line_list.append(" jsonMessage->setObject(ASCIILiteral(\"params\"), paramsObject);\n")
2140
2141 container_name = "paramsObject"
2142
2143 @staticmethod
2144 def process_command(json_command, domain_name, agent_interface_name, dispatcher_name, dispatcher_if_chain, dispatcher_commands_list):
2145 json_command_name = json_command["name"]
2146
2147 ad_hoc_type_output = []
2148 Generator.backend_handler_interface_list.append(ad_hoc_type_output)
2149 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
2150
2151 Generator.backend_dispatcher_interface_list.append(" void %s(long callId, const Inspector::InspectorObject& message);\n" % json_command_name)
2152
2153 Generator.backend_handler_interface_list.append(" virtual void %s(ErrorString*" % json_command_name)
2154
2155 if not dispatcher_if_chain:
2156 dispatcher_if_chain.append(" if (method == \"%s\")" % json_command_name)
2157 else:
2158 dispatcher_if_chain.append(" else if (method == \"%s\")" % json_command_name)
2159 dispatcher_if_chain.append(" %s(callId, *message.get());" % json_command_name)
2160 dispatcher_commands_list.append(" { \"%s\", &%s::%s }," % (json_command_name, dispatcher_name, json_command_name))
2161
2162 method_in_params_handling = []
2163 method_dispatch_handling = []
2164 method_out_params_handling = []
2165 method_ending_handling = []
2166 method_request_message_param_name = ""
2167 agent_call_param_list = []
2168 js_parameters_text = ""
2169 if "parameters" in json_command:
2170 json_params = json_command["parameters"]
2171 method_request_message_param_name = " message"
2172 method_in_params_handling.append(" RefPtr<InspectorArray> protocolErrors = InspectorArray::create();\n")
2173 method_in_params_handling.append(" RefPtr<InspectorObject> paramsContainer = message.getObject(ASCIILiteral(\"params\"));\n")
2174 method_in_params_handling.append(" InspectorObject* paramsContainerPtr = paramsContainer.get();\n")
2175 method_in_params_handling.append(" InspectorArray* protocolErrorsPtr = protocolErrors.get();\n")
2176 js_param_list = []
2177
2178 for json_parameter in json_params:
2179 json_param_name = json_parameter["name"]
2180 param_raw_type = resolve_param_raw_type(json_parameter, domain_name)
2181
2182 getter_name = param_raw_type.get_getter_name()
2183
2184 optional = json_parameter.get("optional")
2185
2186 non_optional_type_model = param_raw_type.get_raw_type_model()
2187 if optional:
2188 type_model = non_optional_type_model.get_optional()
2189 else:
2190 type_model = non_optional_type_model
2191
2192 if optional:
2193 code = (" bool %s_valueFound = false;\n"
2194 " %s in_%s = InspectorBackendDispatcher::get%s(paramsContainerPtr, ASCIILiteral(\"%s\"), &%s_valueFound, protocolErrorsPtr);\n" %
2195 (json_param_name, non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name, json_param_name))
2196 param = ", %s_valueFound ? &in_%s : nullptr" % (json_param_name, json_param_name)
2197 # FIXME: pass optional refptr-values as PassRefPtr
2198 formal_param_type_pattern = "const %s*"
2199 else:
2200 code = (" %s in_%s = InspectorBackendDispatcher::get%s(paramsContainerPtr, ASCIILiteral(\"%s\"), nullptr, protocolErrorsPtr);\n" %
2201 (non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name))
2202 param = ", in_%s" % json_param_name
2203 # FIXME: pass not-optional refptr-values as NonNullPassRefPtr
2204 if param_raw_type.is_heavy_value():
2205 formal_param_type_pattern = "const %s&"
2206 else:
2207 formal_param_type_pattern = "%s"
2208
2209 method_in_params_handling.append(code)
2210 agent_call_param_list.append(param)
2211 Generator.backend_handler_interface_list.append(", %s in_%s" % (formal_param_type_pattern % non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name))
2212
2213 js_bind_type = param_raw_type.get_js_bind_type()
2214 js_param_text = "{\"name\": \"%s\", \"type\": \"%s\", \"optional\": %s}" % (
2215 json_param_name,
2216 js_bind_type,
2217 ("true" if ("optional" in json_parameter and json_parameter["optional"]) else "false"))
2218
2219 js_param_list.append(js_param_text)
2220
2221 method_in_params_handling.append(" if (protocolErrors->length()) {\n")
2222 method_in_params_handling.append(" String errorMessage = String::format(\"Some arguments of method '%%s' can't be processed\", \"%s.%s\");\n" % (domain_name, json_command_name))
2223 method_in_params_handling.append(" m_backendDispatcher->reportProtocolError(&callId, InspectorBackendDispatcher::InvalidParams, errorMessage, protocolErrors.release());\n")
2224 method_in_params_handling.append(" return;\n")
2225 method_in_params_handling.append(" }\n")
2226 method_in_params_handling.append("\n")
2227
2228 js_parameters_text = ", ".join(js_param_list)
2229
2230 method_dispatch_handling.append(" ErrorString error;\n")
2231 method_dispatch_handling.append(" RefPtr<InspectorObject> result = InspectorObject::create();\n")
2232
2233 if json_command.get("async") == True:
2234 callback_name = Capitalizer.lower_camel_case_to_upper(json_command_name) + "Callback"
2235
2236 callback_output = []
2237 callback_writer = Writer(callback_output, ad_hoc_type_writer.get_indent())
2238
2239 decl_parameter_list = []
2240 Generator.generate_send_method(json_command.get("returns"), json_command_name, domain_name, ad_hoc_type_writer,
2241 decl_parameter_list,
2242 Generator.CallbackMethodStructTemplate,
2243 Generator.backend_method_implementation_list, Templates.callback_method,
2244 {"callbackName": callback_name, "handlerName": agent_interface_name})
2245
2246 callback_writer.newline("class " + callback_name + " : public Inspector::InspectorBackendDispatcher::CallbackBase {\n")
2247 callback_writer.newline("public:\n")
2248 callback_writer.newline(" " + callback_name + "(PassRefPtr<Inspector::InspectorBackendDispatcher>, int id);\n")
2249 callback_writer.newline(" void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
2250 callback_writer.newline("};\n")
2251
2252 ad_hoc_type_output.append(callback_output)
2253
2254 method_dispatch_handling.append(" RefPtr<%s::%s> callback = adoptRef(new %s::%s(m_backendDispatcher,callId));\n" % (agent_interface_name, callback_name, agent_interface_name, callback_name))
2255 method_ending_handling.append(" if (error.length()) {\n")
2256 method_ending_handling.append(" callback->disable();\n")
2257 method_ending_handling.append(" m_backendDispatcher->reportProtocolError(&callId, Inspector::InspectorBackendDispatcher::ServerError, error);\n")
2258 method_ending_handling.append(" return;\n")
2259 method_ending_handling.append(" }")
2260
2261 agent_call_param_list.append(", callback")
2262 Generator.backend_handler_interface_list.append(", PassRefPtr<%s> callback" % callback_name)
2263 elif "returns" in json_command:
2264 has_multiple_returns = len(json_command["returns"]) > 1
2265 if has_multiple_returns:
2266 method_out_params_handling.append(" if (!error.length()) {\n")
2267 else:
2268 method_out_params_handling.append(" if (!error.length())\n")
2269
2270 for json_return in json_command["returns"]:
2271
2272 json_return_name = json_return["name"]
2273
2274 optional = bool(json_return.get("optional"))
2275
2276 return_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_return, json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::")
2277
2278 raw_type = return_type_binding.reduce_to_raw_type()
2279 setter_type = raw_type.get_setter_name()
2280 initializer = raw_type.get_c_initializer()
2281
2282 type_model = return_type_binding.get_type_model()
2283 if optional:
2284 type_model = type_model.get_optional()
2285
2286 code = " %s out_%s;\n" % (type_model.get_command_return_pass_model().get_return_var_type(), json_return_name)
2287 param = ", %sout_%s" % (type_model.get_command_return_pass_model().get_output_argument_prefix(), json_return_name)
2288 var_name = "out_%s" % json_return_name
2289 setter_argument = type_model.get_command_return_pass_model().get_output_to_raw_expression() % var_name
2290 if return_type_binding.get_setter_value_expression_pattern():
2291 setter_argument = return_type_binding.get_setter_value_expression_pattern() % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"], setter_argument)
2292
2293 cook = " result->set%s(ASCIILiteral(\"%s\"), %s);\n" % (setter_type, json_return_name, setter_argument)
2294
2295 set_condition_pattern = type_model.get_command_return_pass_model().get_set_return_condition()
2296 if set_condition_pattern:
2297 cook = (" if (%s)\n " % (set_condition_pattern % var_name)) + cook
2298 annotated_type = type_model.get_command_return_pass_model().get_output_parameter_type()
2299
2300 param_name = "out_%s" % json_return_name
2301 if optional:
2302 param_name = "opt_" + param_name
2303
2304 Generator.backend_handler_interface_list.append(", %s %s" % (annotated_type, param_name))
2305 method_out_params_handling.append(cook)
2306 method_dispatch_handling.append(code)
2307
2308 agent_call_param_list.append(param)
2309
2310 if has_multiple_returns:
2311 method_out_params_handling.append(" }\n")
2312 method_out_params_handling.append("\n")
2313
2314 method_dispatch_handling.append(" m_agent->%s(&error%s);\n" % (json_command_name, "".join(agent_call_param_list)))
2315 method_dispatch_handling.append("\n")
2316
2317 if not method_ending_handling:
2318 method_ending_handling.append(" m_backendDispatcher->sendResponse(callId, result.release(), error);")
2319
2320 backend_js_reply_param_list = []
2321 if "returns" in json_command:
2322 for json_return in json_command["returns"]:
2323 json_return_name = json_return["name"]
2324 backend_js_reply_param_list.append("\"%s\"" % json_return_name)
2325
2326 js_reply_list = "[%s]" % ", ".join(backend_js_reply_param_list)
2327
2328 Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None,
2329 dispatcherName=dispatcher_name,
2330 methodName=json_command_name,
2331 requestMessageObject=method_request_message_param_name,
2332 methodInParametersHandling="".join(method_in_params_handling),
2333 methodDispatchHandling="".join(method_dispatch_handling),
2334 methodOutParametersHandling="".join(method_out_params_handling),
2335 methodEndingHandling="".join(method_ending_handling)))
2336
2337 Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerCommand(\"%s.%s\", [%s], %s);\n" % (domain_name, json_command_name, js_parameters_text, js_reply_list))
2338 Generator.backend_handler_interface_list.append(") = 0;\n")
2339
2340 class CallbackMethodStructTemplate:
2341 @staticmethod
2342 def append_prolog(line_list):
2343 pass
2344
2345 @staticmethod
2346 def append_epilog(line_list):
2347 pass
2348
2349 container_name = "jsonMessage"
2350
2351 # Generates common code for event sending and callback response data sending.
2352 @staticmethod
2353 def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_writer, decl_parameter_list,
2354 method_struct_template,
2355 generator_method_list, method_template, template_params):
2356 method_line_list = []
2357 if parameters:
2358 method_struct_template.append_prolog(method_line_list)
2359 for json_parameter in parameters:
2360 parameter_name = json_parameter["name"]
2361
2362 param_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "")
2363
2364 raw_type = param_type_binding.reduce_to_raw_type()
2365 raw_type_binding = RawTypeBinding(raw_type)
2366
2367 optional = bool(json_parameter.get("optional"))
2368
2369 setter_type = raw_type.get_setter_name()
2370
2371 type_model = param_type_binding.get_type_model()
2372 raw_type_model = raw_type_binding.get_type_model()
2373 if optional:
2374 type_model = type_model.get_optional()
2375 raw_type_model = raw_type_model.get_optional()
2376
2377 annotated_type = type_model.get_input_param_type_text()
2378 mode_type_binding = param_type_binding
2379
2380 decl_parameter_list.append("%s %s" % (annotated_type, parameter_name))
2381
2382 setter_argument = raw_type_model.get_event_setter_expression_pattern() % parameter_name
2383 if mode_type_binding.get_setter_value_expression_pattern():
2384 setter_argument = mode_type_binding.get_setter_value_expression_pattern() % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"], setter_argument)
2385
2386 setter_code = " %s->set%s(ASCIILiteral(\"%s\"), %s);\n" % (method_struct_template.container_name, setter_type, parameter_name, setter_argument)
2387 if optional:
2388 setter_code = (" if (%s)\n " % parameter_name) + setter_code
2389 method_line_list.append(setter_code)
2390
2391 method_struct_template.append_epilog(method_line_list)
2392
2393 generator_method_list.append(method_template.substitute(None,
2394 domainName=domain_name,
2395 parameters=", ".join(decl_parameter_list),
2396 code="".join(method_line_list), **template_params))
2397
2398 @staticmethod
2399 def resolve_type_and_generate_ad_hoc(json_param, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
2400 param_name = json_param["name"]
2401 ad_hoc_type_list = []
2402
2403 class AdHocTypeContext:
2404 container_full_name_prefix = "<not yet defined>"
2405 container_relative_name_prefix = container_relative_name_prefix_param
2406
2407 @staticmethod
2408 def get_type_name_fix():
2409 class NameFix:
2410 class_name = Capitalizer.lower_camel_case_to_upper(param_name)
2411
2412 @staticmethod
2413 def output_comment(writer):
2414 writer.newline("// Named after parameter '%s' while generating command/event %s.\n" % (param_name, method_name))
2415
2416 return NameFix
2417
2418 @staticmethod
2419 def add_type(binding):
2420 ad_hoc_type_list.append(binding)
2421
2422 type_binding = resolve_param_type(json_param, domain_name, AdHocTypeContext)
2423
2424 class InterfaceForwardListener:
2425 @staticmethod
2426 def add_type_data(type_data):
2427 pass
2428
2429 class InterfaceResolveContext:
2430 forward_listener = InterfaceForwardListener
2431
2432 for type in ad_hoc_type_list:
2433 type.resolve_inner(InterfaceResolveContext)
2434
2435 class InterfaceGenerateContext:
2436 validator_writer = "not supported in InterfaceGenerateContext"
2437 cpp_writer = validator_writer
2438
2439 for type in ad_hoc_type_list:
2440 generator = type.get_code_generator()
2441 if generator:
2442 generator.generate_type_builder(ad_hoc_type_writer, InterfaceGenerateContext)
2443
2444 return type_binding
2445
2446 @staticmethod
2447 def process_types(type_map):
2448 output = Generator.type_builder_fragments
2449
2450 class GenerateContext:
2451 validator_writer = Writer(Generator.validator_impl_list, "")
2452 cpp_writer = Writer(Generator.type_builder_impl_list, "")
2453
2454 def generate_all_domains_code(out, type_data_callback):
2455 writer = Writer(out, "")
2456 for domain_data in type_map.domains_to_generate():
2457 domain_fixes = DomainNameFixes.get_fixed_data(domain_data.name())
2458 domain_guard = domain_fixes.get_guard()
2459
2460 namespace_declared = []
2461
2462 def namespace_lazy_generator():
2463 if not namespace_declared:
2464 if domain_guard:
2465 domain_guard.generate_open(out)
2466 writer.newline("namespace ")
2467 writer.append(domain_data.name())
2468 writer.append(" {\n")
2469 # What is a better way to change value from outer scope?
2470 namespace_declared.append(True)
2471 return writer
2472
2473 for type_data in domain_data.types():
2474 type_data_callback(type_data, namespace_lazy_generator)
2475
2476 if namespace_declared:
2477 writer.append("} // ")
2478 writer.append(domain_data.name())
2479 writer.append("\n\n")
2480
2481 if domain_guard:
2482 domain_guard.generate_close(out)
2483
2484 def create_type_builder_caller(generate_pass_id):
2485 def call_type_builder(type_data, writer_getter):
2486 code_generator = type_data.get_binding().get_code_generator()
2487 if code_generator and generate_pass_id == code_generator.get_generate_pass_id():
2488 writer = writer_getter()
2489
2490 code_generator.generate_type_builder(writer, GenerateContext)
2491 return call_type_builder
2492
2493 generate_all_domains_code(output, create_type_builder_caller(TypeBuilderPass.MAIN))
2494
2495 Generator.type_builder_forwards.append("// Forward declarations.\n")
2496
2497 def generate_forward_callback(type_data, writer_getter):
2498 if type_data in global_forward_listener.type_data_set:
2499 binding = type_data.get_binding()
2500 binding.get_code_generator().generate_forward_declaration(writer_getter())
2501 generate_all_domains_code(Generator.type_builder_forwards, generate_forward_callback)
2502
2503 Generator.type_builder_forwards.append("// End of forward declarations.\n\n")
2504
2505 Generator.type_builder_forwards.append("// Typedefs.\n")
2506
2507 generate_all_domains_code(Generator.type_builder_forwards, create_type_builder_caller(TypeBuilderPass.TYPEDEF))
2508
2509 Generator.type_builder_forwards.append("// End of typedefs.\n\n")
2510
2511
2512def flatten_list(input):
2513 res = []
2514
2515 def fill_recursive(l):
2516 for item in l:
2517 if isinstance(item, list):
2518 fill_recursive(item)
2519 else:
2520 res.append(item)
2521 fill_recursive(input)
2522 return res
2523
2524
2525# A writer that only updates file if it actually changed to better support incremental build.
2526class SmartOutput:
2527 def __init__(self, file_name):
2528 self.file_name_ = file_name
2529 self.output_ = ""
2530
2531 def write(self, text):
2532 self.output_ += text
2533
2534 def close(self):
2535 text_changed = True
2536 self.output_ = self.output_.rstrip() + "\n"
2537
2538 try:
2539 read_file = open(self.file_name_, "r")
2540 old_text = read_file.read()
2541 read_file.close()
2542 text_changed = old_text != self.output_
2543 except:
2544 # Ignore, just overwrite by default
2545 pass
2546
2547 if text_changed or write_always:
2548 out_file = open(self.file_name_, "w")
2549 out_file.write(self.output_)
2550 out_file.close()
2551
2552
2553Generator.go()
2554
2555output_file_name_prefix = INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"]
2556
2557backend_h_file = SmartOutput(output_header_dirname + ("/Inspector%sBackendDispatchers.h" % output_file_name_prefix))
2558backend_cpp_file = SmartOutput(output_cpp_dirname + ("/Inspector%sBackendDispatchers.cpp" % output_file_name_prefix))
2559
2560frontend_h_file = SmartOutput(output_header_dirname + ("/Inspector%sFrontendDispatchers.h" % output_file_name_prefix))
2561frontend_cpp_file = SmartOutput(output_cpp_dirname + ("/Inspector%sFrontendDispatchers.cpp" % output_file_name_prefix))
2562
2563typebuilder_h_file = SmartOutput(output_header_dirname + ("/Inspector%sTypeBuilders.h" % output_file_name_prefix))
2564typebuilder_cpp_file = SmartOutput(output_cpp_dirname + ("/Inspector%sTypeBuilders.cpp" % output_file_name_prefix))
2565
2566backend_js_file = SmartOutput(output_js_dirname + ("/Inspector%sBackendCommands.js" % output_file_name_prefix))
2567
2568
2569backend_h_file.write(Templates.backend_h.substitute(None,
2570 outputFileNamePrefix=output_file_name_prefix,
2571 handlerInterfaces="".join(flatten_list(Generator.backend_handler_interface_list)),
2572 dispatcherInterfaces="".join(flatten_list(Generator.backend_dispatcher_interface_list))))
2573
2574backend_cpp_file.write(Templates.backend_cpp.substitute(None,
2575 outputFileNamePrefix=output_file_name_prefix,
2576 handlerImplementations="".join(flatten_list(Generator.backend_handler_implementation_list)),
2577 methods="\n".join(Generator.backend_method_implementation_list)))
2578
2579frontend_h_file.write(Templates.frontend_h.substitute(None,
2580 outputFileNamePrefix=output_file_name_prefix,
2581 domainClassList="".join(Generator.frontend_domain_class_lines)))
2582
2583frontend_cpp_file.write(Templates.frontend_cpp.substitute(None,
2584 outputFileNamePrefix=output_file_name_prefix,
2585 methods="\n".join(Generator.frontend_method_list)))
2586
2587typebuilder_h_file.write(Templates.typebuilder_h.substitute(None,
2588 outputFileNamePrefix=output_file_name_prefix,
2589 typeBuilderDependencies=INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["typebuilder_dependency"],
2590 exportMacro=INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"],
2591 typeBuilders="".join(flatten_list(Generator.type_builder_fragments)),
2592 forwards="".join(Generator.type_builder_forwards),
2593 validatorIfdefName=VALIDATOR_IFDEF_NAME))
2594
2595typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None,
2596 outputFileNamePrefix=output_file_name_prefix,
2597 enumConstantValues=EnumConstants.get_enum_constant_code(),
2598 implCode="".join(flatten_list(Generator.type_builder_impl_list)),
2599 validatorCode="".join(flatten_list(Generator.validator_impl_list)),
2600 validatorIfdefName=VALIDATOR_IFDEF_NAME))
2601
2602backend_js_file.write(Templates.backend_js.substitute(None,
2603 domainInitializers="".join(Generator.backend_js_domain_initializer_list)))
2604
2605backend_h_file.close()
2606backend_cpp_file.close()
2607
2608frontend_h_file.close()
2609frontend_cpp_file.close()
2610
2611typebuilder_h_file.close()
2612typebuilder_cpp_file.close()
2613
2614backend_js_file.close()