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