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