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