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