Home | History | Annotate | Download | only in inspector
      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 
     31 import os.path
     32 import sys
     33 import string
     34 import optparse
     35 import re
     36 try:
     37     import json
     38 except ImportError:
     39     import simplejson as json
     40 
     41 import CodeGeneratorInspectorStrings
     42 
     43 # Manually-filled map of type name replacements.
     44 TYPE_NAME_FIX_MAP = {
     45     "RGBA": "Rgba",  # RGBA is reported to be conflicting with a define name in Windows CE.
     46     "": "Empty",
     47 }
     48 
     49 
     50 TYPES_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 
     56 TYPES_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 
     62 EXACTLY_INT_SUPPORTED = False
     63 
     64 cmdline_parser = optparse.OptionParser()
     65 cmdline_parser.add_option("--output_dir")
     66 
     67 try:
     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")
     75 except 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.
     84 def dash_to_camelcase(word):
     85     return ''.join(x.capitalize() or '-' for x in word.split('-'))
     86 
     87 
     88 def 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 
     94 def to_title_case(name):
     95     return name[:1].upper() + name[1:]
     96 
     97 
     98 class 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 
    161 VALIDATOR_IFDEF_NAME = "!ASSERT_DISABLED"
    162 
    163 
    164 class 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 
    175 class 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 
    503 def replace_right_shift(input_str):
    504     return input_str.replace(">>", "> >")
    505 
    506 
    507 class 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 
    575 class 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 
    697 TypeModel.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.
    702 INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"])
    703 
    704 
    705 def 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 
    727 class 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 
    768 class 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.
    792 class TypeBuilderPass:
    793     TYPEDEF = "typedef"
    794     MAIN = "main"
    795 
    796 
    797 class 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 
   1499 class 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 
   1531 class 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 
   1572 class 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 
   1587 class 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 
   1614 def 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 
   1626 def 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 
   1638 def 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 
   1650 input_file = open(input_json_filename, "r")
   1651 json_string = input_file.read()
   1652 json_api = json.loads(json_string)
   1653 
   1654 
   1655 class 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 
   1695 type_map = TypeMap(json_api)
   1696 
   1697 
   1698 class 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 
   1709 def 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 
   1751 global_forward_listener = resolve_all_types()
   1752 
   1753 
   1754 def 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 
   1761 def 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 
   1768 class 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     method_handler_list = []
   1777     frontend_method_list = []
   1778 
   1779     backend_virtual_setters_list = []
   1780     backend_agent_interface_list = []
   1781     backend_setters_list = []
   1782     backend_constructor_init_list = []
   1783     backend_field_list = []
   1784     frontend_constructor_init_list = []
   1785     type_builder_fragments = []
   1786     type_builder_forwards = []
   1787     validator_impl_list = []
   1788     type_builder_impl_list = []
   1789 
   1790 
   1791     @staticmethod
   1792     def go():
   1793         Generator.process_types(type_map)
   1794 
   1795         first_cycle_guardable_list_list = [
   1796             Generator.backend_method_declaration_list,
   1797             Generator.backend_method_implementation_list,
   1798             Generator.backend_method_name_declaration_list,
   1799             Generator.backend_agent_interface_list,
   1800             Generator.frontend_class_field_lines,
   1801             Generator.frontend_constructor_init_list,
   1802             Generator.frontend_domain_class_lines,
   1803             Generator.frontend_method_list,
   1804             Generator.method_handler_list,
   1805             Generator.method_name_enum_list,
   1806             Generator.backend_constructor_init_list,
   1807             Generator.backend_virtual_setters_list,
   1808             Generator.backend_setters_list,
   1809             Generator.backend_field_list]
   1810 
   1811         for json_domain in json_api["domains"]:
   1812             domain_name = json_domain["domain"]
   1813             domain_name_lower = domain_name.lower()
   1814 
   1815             domain_fixes = DomainNameFixes.get_fixed_data(domain_name)
   1816 
   1817             agent_field_name = domain_fixes.agent_field_name
   1818 
   1819             frontend_method_declaration_lines = []
   1820 
   1821             if "events" in json_domain:
   1822                 for json_event in json_domain["events"]:
   1823                     Generator.process_event(json_event, domain_name, frontend_method_declaration_lines)
   1824 
   1825             Generator.frontend_class_field_lines.append("    %s m_%s;\n" % (domain_name, domain_name_lower))
   1826             if Generator.frontend_constructor_init_list:
   1827                 Generator.frontend_constructor_init_list.append("    , ")
   1828             Generator.frontend_constructor_init_list.append("m_%s(inspectorFrontendChannel)\n" % domain_name_lower)
   1829             Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None,
   1830                 domainClassName=domain_name,
   1831                 domainFieldName=domain_name_lower,
   1832                 frontendDomainMethodDeclarations="".join(flatten_list(frontend_method_declaration_lines))))
   1833 
   1834             agent_interface_name = Capitalizer.lower_camel_case_to_upper(domain_name) + "CommandHandler"
   1835             Generator.backend_agent_interface_list.append("    class %s {\n" % agent_interface_name)
   1836             Generator.backend_agent_interface_list.append("    public:\n")
   1837             if "commands" in json_domain:
   1838                 for json_command in json_domain["commands"]:
   1839                     Generator.process_command(json_command, domain_name, agent_field_name, agent_interface_name)
   1840             Generator.backend_agent_interface_list.append("\n    protected:\n")
   1841             Generator.backend_agent_interface_list.append("        virtual ~%s() { }\n" % agent_interface_name)
   1842             Generator.backend_agent_interface_list.append("    };\n\n")
   1843 
   1844             Generator.backend_constructor_init_list.append("        , m_%s(0)" % agent_field_name)
   1845             Generator.backend_virtual_setters_list.append("    virtual void registerAgent(%s* %s) = 0;" % (agent_interface_name, agent_field_name))
   1846             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))
   1847             Generator.backend_field_list.append("    %s* m_%s;" % (agent_interface_name, agent_field_name))
   1848 
   1849     @staticmethod
   1850     def process_event(json_event, domain_name, frontend_method_declaration_lines):
   1851         event_name = json_event["name"]
   1852 
   1853         ad_hoc_type_output = []
   1854         frontend_method_declaration_lines.append(ad_hoc_type_output)
   1855         ad_hoc_type_writer = Writer(ad_hoc_type_output, "        ")
   1856 
   1857         decl_parameter_list = []
   1858 
   1859         json_parameters = json_event.get("parameters")
   1860         Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer,
   1861                                        decl_parameter_list,
   1862                                        Generator.EventMethodStructTemplate,
   1863                                        Generator.frontend_method_list, Templates.frontend_method, {"eventName": event_name})
   1864 
   1865         frontend_method_declaration_lines.append(
   1866             "        void %s(%s);\n" % (event_name, ", ".join(decl_parameter_list)))
   1867 
   1868     class EventMethodStructTemplate:
   1869         @staticmethod
   1870         def append_prolog(line_list):
   1871             line_list.append("    RefPtr<JSONObject> paramsObject = JSONObject::create();\n")
   1872 
   1873         @staticmethod
   1874         def append_epilog(line_list):
   1875             line_list.append("    jsonMessage->setObject(\"params\", paramsObject);\n")
   1876 
   1877         container_name = "paramsObject"
   1878 
   1879     @staticmethod
   1880     def process_command(json_command, domain_name, agent_field_name, agent_interface_name):
   1881         json_command_name = json_command["name"]
   1882 
   1883         cmd_enum_name = "k%s_%sCmd" % (domain_name, json_command["name"])
   1884 
   1885         Generator.method_name_enum_list.append("        %s," % cmd_enum_name)
   1886         Generator.method_handler_list.append("            &InspectorBackendDispatcherImpl::%s_%s," % (domain_name, json_command_name))
   1887         Generator.backend_method_declaration_list.append("    void %s_%s(long callId, JSONObject* requestMessageObject);" % (domain_name, json_command_name))
   1888 
   1889         ad_hoc_type_output = []
   1890         Generator.backend_agent_interface_list.append(ad_hoc_type_output)
   1891         ad_hoc_type_writer = Writer(ad_hoc_type_output, "        ")
   1892 
   1893         Generator.backend_agent_interface_list.append("        virtual void %s(ErrorString*" % json_command_name)
   1894 
   1895         method_in_code = ""
   1896         method_out_code = ""
   1897         agent_call_param_list = []
   1898         request_message_param = ""
   1899         normal_response_cook_text = ""
   1900         error_response_cook_text = ""
   1901         error_type_binding = None
   1902         if "error" in json_command:
   1903             json_error = json_command["error"]
   1904             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 + "::")
   1905             error_type_model = error_type_binding.get_type_model().get_optional()
   1906             error_annotated_type = error_type_model.get_command_return_pass_model().get_output_parameter_type()
   1907             agent_call_param_list.append(", %serrorData" % error_type_model.get_command_return_pass_model().get_output_argument_prefix())
   1908             Generator.backend_agent_interface_list.append(", %s errorData" % error_annotated_type)
   1909             method_in_code += "    %s errorData;\n" % error_type_model.get_command_return_pass_model().get_return_var_type()
   1910 
   1911             setter_argument = error_type_model.get_command_return_pass_model().get_output_to_raw_expression() % "errorData"
   1912             if error_type_binding.get_setter_value_expression_pattern():
   1913                 setter_argument = error_type_binding.get_setter_value_expression_pattern() % setter_argument
   1914             error_assigment_value = error_type_binding.reduce_to_raw_type().get_constructor_pattern() % setter_argument
   1915 
   1916             cook = "            resultErrorData = %s;\n" % error_assigment_value
   1917 
   1918             error_condition_pattern = error_type_model.get_command_return_pass_model().get_set_return_condition()
   1919             cook = ("            if (%s)\n    " % (error_condition_pattern % "errorData")) + cook
   1920             error_response_cook_text = "        if (error.length()) {\n" + cook + "        }\n"
   1921 
   1922         if "parameters" in json_command:
   1923             json_params = json_command["parameters"]
   1924             method_in_code += Templates.param_container_access_code
   1925             request_message_param = " requestMessageObject"
   1926 
   1927             for json_parameter in json_params:
   1928                 json_param_name = json_parameter["name"]
   1929                 param_raw_type = resolve_param_raw_type(json_parameter, domain_name)
   1930 
   1931                 getter_name = param_raw_type.get_getter_name()
   1932 
   1933                 optional = json_parameter.get("optional")
   1934 
   1935                 non_optional_type_model = param_raw_type.get_raw_type_model()
   1936                 if optional:
   1937                     type_model = non_optional_type_model.get_optional()
   1938                 else:
   1939                     type_model = non_optional_type_model
   1940 
   1941                 if optional:
   1942                     code = ("    bool %s_valueFound = false;\n"
   1943                             "    %s in_%s = get%s(paramsContainerPtr, \"%s\", &%s_valueFound, protocolErrorsPtr);\n" %
   1944                            (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))
   1945                     param = ", %s_valueFound ? &in_%s : 0" % (json_param_name, json_param_name)
   1946                     # FIXME: pass optional refptr-values as PassRefPtr
   1947                     formal_param_type_pattern = "const %s*"
   1948                 else:
   1949                     code = ("    %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrorsPtr);\n" %
   1950                             (non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name))
   1951                     param = ", in_%s" % json_param_name
   1952                     # FIXME: pass not-optional refptr-values as NonNullPassRefPtr
   1953                     if param_raw_type.is_heavy_value():
   1954                         formal_param_type_pattern = "const %s&"
   1955                     else:
   1956                         formal_param_type_pattern = "%s"
   1957 
   1958                 method_in_code += code
   1959                 agent_call_param_list.append(param)
   1960                 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))
   1961 
   1962         if json_command.get("async") == True:
   1963             callback_name = Capitalizer.lower_camel_case_to_upper(json_command_name) + "Callback"
   1964 
   1965             callback_output = []
   1966             callback_writer = Writer(callback_output, ad_hoc_type_writer.get_indent())
   1967 
   1968             decl_parameter_list = []
   1969             Generator.generate_send_method(json_command.get("returns"), json_command_name, domain_name, ad_hoc_type_writer,
   1970                                            decl_parameter_list,
   1971                                            Generator.CallbackMethodStructTemplate,
   1972                                            Generator.backend_method_implementation_list, Templates.callback_main_methods,
   1973                                            {"callbackName": callback_name, "agentName": agent_interface_name})
   1974 
   1975             callback_writer.newline("class " + callback_name + " : public CallbackBase {\n")
   1976             callback_writer.newline("public:\n")
   1977             callback_writer.newline("    " + callback_name + "(PassRefPtr<InspectorBackendDispatcherImpl>, int id);\n")
   1978             callback_writer.newline("    void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
   1979             error_part_writer = callback_writer.insert_writer("")
   1980             callback_writer.newline("};\n")
   1981 
   1982             if error_type_binding:
   1983                 annotated_type = error_type_model.get_input_param_type_text()
   1984                 error_part_writer.newline("    void sendFailure(const ErrorString&, %s);\n" % annotated_type)
   1985                 error_part_writer.newline("    using CallbackBase::sendFailure;\n")
   1986 
   1987                 assigment_value = error_type_model.get_event_setter_expression_pattern() % "errorData"
   1988                 assigment_value = error_type_binding.reduce_to_raw_type().get_constructor_pattern() % assigment_value
   1989 
   1990                 Generator.backend_method_implementation_list.append(Templates.callback_failure_method.substitute(None,
   1991                     agentName=agent_interface_name,
   1992                     callbackName=callback_name,
   1993                     parameter=annotated_type + " errorData",
   1994                     argument=assigment_value))
   1995 
   1996 
   1997 
   1998             ad_hoc_type_output.append(callback_output)
   1999 
   2000             method_out_code += "    RefPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRef(new " + agent_interface_name + "::" + callback_name + "(this, callId));\n"
   2001             agent_call_param_list.append(", callback")
   2002             normal_response_cook_text += "        if (!error.length()) \n"
   2003             normal_response_cook_text += "            return;\n"
   2004             normal_response_cook_text += "        callback->disable();\n"
   2005             Generator.backend_agent_interface_list.append(", PassRefPtr<%s> callback" % callback_name)
   2006         else:
   2007             if "returns" in json_command:
   2008                 method_out_code += "\n"
   2009                 response_cook_list = []
   2010                 for json_return in json_command["returns"]:
   2011 
   2012                     json_return_name = json_return["name"]
   2013 
   2014                     optional = bool(json_return.get("optional"))
   2015 
   2016                     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 + "::")
   2017 
   2018                     raw_type = return_type_binding.reduce_to_raw_type()
   2019                     setter_type = raw_type.get_setter_name()
   2020                     initializer = raw_type.get_c_initializer()
   2021 
   2022                     type_model = return_type_binding.get_type_model()
   2023                     if optional:
   2024                         type_model = type_model.get_optional()
   2025 
   2026                     code = "    %s out_%s;\n" % (type_model.get_command_return_pass_model().get_return_var_type(), json_return_name)
   2027                     param = ", %sout_%s" % (type_model.get_command_return_pass_model().get_output_argument_prefix(), json_return_name)
   2028                     var_name = "out_%s" % json_return_name
   2029                     setter_argument = type_model.get_command_return_pass_model().get_output_to_raw_expression() % var_name
   2030                     if return_type_binding.get_setter_value_expression_pattern():
   2031                         setter_argument = return_type_binding.get_setter_value_expression_pattern() % setter_argument
   2032 
   2033                     cook = "            result->set%s(\"%s\", %s);\n" % (setter_type, json_return_name,
   2034                                                                          setter_argument)
   2035 
   2036                     set_condition_pattern = type_model.get_command_return_pass_model().get_set_return_condition()
   2037                     if set_condition_pattern:
   2038                         cook = ("            if (%s)\n    " % (set_condition_pattern % var_name)) + cook
   2039                     annotated_type = type_model.get_command_return_pass_model().get_output_parameter_type()
   2040 
   2041                     param_name = var_name
   2042                     if optional:
   2043                         param_name = "opt_" + param_name
   2044 
   2045                     Generator.backend_agent_interface_list.append(", %s %s" % (annotated_type, param_name))
   2046                     response_cook_list.append(cook)
   2047 
   2048                     method_out_code += code
   2049                     agent_call_param_list.append(param)
   2050 
   2051                 normal_response_cook_text += "".join(response_cook_list)
   2052 
   2053                 if len(normal_response_cook_text) != 0:
   2054                     normal_response_cook_text = "        if (!error.length()) {\n" + normal_response_cook_text + "        }"
   2055 
   2056         Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None,
   2057             domainName=domain_name, methodName=json_command_name,
   2058             agentField="m_" + agent_field_name,
   2059             methodInCode=method_in_code,
   2060             methodOutCode=method_out_code,
   2061             agentCallParams="".join(agent_call_param_list),
   2062             requestMessageObject=request_message_param,
   2063             responseCook=normal_response_cook_text,
   2064             errorCook=error_response_cook_text,
   2065             commandNameIndex=cmd_enum_name))
   2066         Generator.backend_method_name_declaration_list.append("    \"%s.%s\"," % (domain_name, json_command_name))
   2067 
   2068         Generator.backend_agent_interface_list.append(") = 0;\n")
   2069 
   2070     class CallbackMethodStructTemplate:
   2071         @staticmethod
   2072         def append_prolog(line_list):
   2073             pass
   2074 
   2075         @staticmethod
   2076         def append_epilog(line_list):
   2077             pass
   2078 
   2079         container_name = "jsonMessage"
   2080 
   2081     # Generates common code for event sending and callback response data sending.
   2082     @staticmethod
   2083     def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_writer, decl_parameter_list,
   2084                              method_struct_template,
   2085                              generator_method_list, method_template, template_params):
   2086         method_line_list = []
   2087         if parameters:
   2088             method_struct_template.append_prolog(method_line_list)
   2089             for json_parameter in parameters:
   2090                 parameter_name = json_parameter["name"]
   2091 
   2092                 param_type_binding = Generator.resolve_param_type_and_generate_ad_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "")
   2093 
   2094                 raw_type = param_type_binding.reduce_to_raw_type()
   2095                 raw_type_binding = RawTypeBinding(raw_type)
   2096 
   2097                 optional = bool(json_parameter.get("optional"))
   2098 
   2099                 setter_type = raw_type.get_setter_name()
   2100 
   2101                 type_model = param_type_binding.get_type_model()
   2102                 raw_type_model = raw_type_binding.get_type_model()
   2103                 if optional:
   2104                     type_model = type_model.get_optional()
   2105                     raw_type_model = raw_type_model.get_optional()
   2106 
   2107                 annotated_type = type_model.get_input_param_type_text()
   2108                 mode_type_binding = param_type_binding
   2109 
   2110                 decl_parameter_list.append("%s %s" % (annotated_type, parameter_name))
   2111 
   2112                 setter_argument = raw_type_model.get_event_setter_expression_pattern() % parameter_name
   2113                 if mode_type_binding.get_setter_value_expression_pattern():
   2114                     setter_argument = mode_type_binding.get_setter_value_expression_pattern() % setter_argument
   2115 
   2116                 setter_code = "    %s->set%s(\"%s\", %s);\n" % (method_struct_template.container_name, setter_type, parameter_name, setter_argument)
   2117                 if optional:
   2118                     setter_code = ("    if (%s)\n    " % parameter_name) + setter_code
   2119                 method_line_list.append(setter_code)
   2120 
   2121             method_struct_template.append_epilog(method_line_list)
   2122 
   2123         generator_method_list.append(method_template.substitute(None,
   2124             domainName=domain_name,
   2125             parameters=", ".join(decl_parameter_list),
   2126             code="".join(method_line_list), **template_params))
   2127 
   2128     @classmethod
   2129     def resolve_param_type_and_generate_ad_hoc(cls, json_param, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
   2130         param_name = json_param["name"]
   2131         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)
   2132 
   2133     @staticmethod
   2134     def resolve_type_and_generate_ad_hoc(typable_element, element_name, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
   2135         ad_hoc_type_list = []
   2136 
   2137         class AdHocTypeContext:
   2138             container_full_name_prefix = "<not yet defined>"
   2139             container_relative_name_prefix = container_relative_name_prefix_param
   2140 
   2141             @staticmethod
   2142             def get_type_name_fix():
   2143                 class NameFix:
   2144                     class_name = Capitalizer.lower_camel_case_to_upper(element_name)
   2145 
   2146                     @staticmethod
   2147                     def output_comment(writer):
   2148                         writer.newline("// Named after parameter '%s' while generating command/event %s.\n" % (element_name, method_name))
   2149 
   2150                 return NameFix
   2151 
   2152             @staticmethod
   2153             def add_type(binding):
   2154                 ad_hoc_type_list.append(binding)
   2155 
   2156         type_binding = resolve_param_type(typable_element, domain_name, AdHocTypeContext)
   2157 
   2158         class InterfaceForwardListener:
   2159             @staticmethod
   2160             def add_type_data(type_data):
   2161                 pass
   2162 
   2163         class InterfaceResolveContext:
   2164             forward_listener = InterfaceForwardListener
   2165 
   2166         for type in ad_hoc_type_list:
   2167             type.resolve_inner(InterfaceResolveContext)
   2168 
   2169         class InterfaceGenerateContext:
   2170             validator_writer = "not supported in InterfaceGenerateContext"
   2171             cpp_writer = validator_writer
   2172 
   2173         for type in ad_hoc_type_list:
   2174             generator = type.get_code_generator()
   2175             if generator:
   2176                 generator.generate_type_builder(ad_hoc_type_writer, InterfaceGenerateContext)
   2177 
   2178         return type_binding
   2179 
   2180     @staticmethod
   2181     def process_types(type_map):
   2182         output = Generator.type_builder_fragments
   2183 
   2184         class GenerateContext:
   2185             validator_writer = Writer(Generator.validator_impl_list, "")
   2186             cpp_writer = Writer(Generator.type_builder_impl_list, "")
   2187 
   2188         def generate_all_domains_code(out, type_data_callback):
   2189             writer = Writer(out, "")
   2190             for domain_data in type_map.domains():
   2191                 domain_fixes = DomainNameFixes.get_fixed_data(domain_data.name())
   2192 
   2193                 namespace_declared = []
   2194 
   2195                 def namespace_lazy_generator():
   2196                     if not namespace_declared:
   2197                         writer.newline("namespace ")
   2198                         writer.append(domain_data.name())
   2199                         writer.append(" {\n")
   2200                         # What is a better way to change value from outer scope?
   2201                         namespace_declared.append(True)
   2202                     return writer
   2203 
   2204                 for type_data in domain_data.types():
   2205                     type_data_callback(type_data, namespace_lazy_generator)
   2206 
   2207                 if namespace_declared:
   2208                     writer.append("} // ")
   2209                     writer.append(domain_data.name())
   2210                     writer.append("\n\n")
   2211 
   2212         def create_type_builder_caller(generate_pass_id):
   2213             def call_type_builder(type_data, writer_getter):
   2214                 code_generator = type_data.get_binding().get_code_generator()
   2215                 if code_generator and generate_pass_id == code_generator.get_generate_pass_id():
   2216                     writer = writer_getter()
   2217 
   2218                     code_generator.generate_type_builder(writer, GenerateContext)
   2219             return call_type_builder
   2220 
   2221         generate_all_domains_code(output, create_type_builder_caller(TypeBuilderPass.MAIN))
   2222 
   2223         Generator.type_builder_forwards.append("// Forward declarations.\n")
   2224 
   2225         def generate_forward_callback(type_data, writer_getter):
   2226             if type_data in global_forward_listener.type_data_set:
   2227                 binding = type_data.get_binding()
   2228                 binding.get_code_generator().generate_forward_declaration(writer_getter())
   2229         generate_all_domains_code(Generator.type_builder_forwards, generate_forward_callback)
   2230 
   2231         Generator.type_builder_forwards.append("// End of forward declarations.\n\n")
   2232 
   2233         Generator.type_builder_forwards.append("// Typedefs.\n")
   2234 
   2235         generate_all_domains_code(Generator.type_builder_forwards, create_type_builder_caller(TypeBuilderPass.TYPEDEF))
   2236 
   2237         Generator.type_builder_forwards.append("// End of typedefs.\n\n")
   2238 
   2239 
   2240 def flatten_list(input):
   2241     res = []
   2242 
   2243     def fill_recursive(l):
   2244         for item in l:
   2245             if isinstance(item, list):
   2246                 fill_recursive(item)
   2247             else:
   2248                 res.append(item)
   2249     fill_recursive(input)
   2250     return res
   2251 
   2252 
   2253 # A writer that only updates file if it actually changed to better support incremental build.
   2254 class SmartOutput:
   2255     def __init__(self, file_name):
   2256         self.file_name_ = file_name
   2257         self.output_ = ""
   2258 
   2259     def write(self, text):
   2260         self.output_ += text
   2261 
   2262     def close(self):
   2263         text_changed = True
   2264 
   2265         try:
   2266             read_file = open(self.file_name_, "r")
   2267             old_text = read_file.read()
   2268             read_file.close()
   2269             text_changed = old_text != self.output_
   2270         except:
   2271             # Ignore, just overwrite by default
   2272             pass
   2273 
   2274         if text_changed:
   2275             out_file = open(self.file_name_, "w")
   2276             out_file.write(self.output_)
   2277             out_file.close()
   2278 
   2279 
   2280 def output_file(file_name):
   2281     # For now, disable the incremental build optimisation in all cases.
   2282     if False:
   2283         return SmartOutput(file_name)
   2284     else:
   2285         return open(file_name, "w")
   2286 
   2287 
   2288 Generator.go()
   2289 
   2290 backend_h_file = output_file(output_dirname + "/InspectorBackendDispatcher.h")
   2291 backend_cpp_file = output_file(output_dirname + "/InspectorBackendDispatcher.cpp")
   2292 
   2293 frontend_h_file = output_file(output_dirname + "/InspectorFrontend.h")
   2294 frontend_cpp_file = output_file(output_dirname + "/InspectorFrontend.cpp")
   2295 
   2296 typebuilder_h_file = output_file(output_dirname + "/InspectorTypeBuilder.h")
   2297 typebuilder_cpp_file = output_file(output_dirname + "/InspectorTypeBuilder.cpp")
   2298 
   2299 
   2300 backend_h_file.write(Templates.backend_h.substitute(None,
   2301     virtualSetters="\n".join(Generator.backend_virtual_setters_list),
   2302     agentInterfaces="".join(flatten_list(Generator.backend_agent_interface_list)),
   2303     methodNamesEnumContent="\n".join(Generator.method_name_enum_list)))
   2304 
   2305 backend_cpp_file.write(Templates.backend_cpp.substitute(None,
   2306     constructorInit="\n".join(Generator.backend_constructor_init_list),
   2307     setters="\n".join(Generator.backend_setters_list),
   2308     fieldDeclarations="\n".join(Generator.backend_field_list),
   2309     methodNameDeclarations="\n".join(Generator.backend_method_name_declaration_list),
   2310     methods="\n".join(Generator.backend_method_implementation_list),
   2311     methodDeclarations="\n".join(Generator.backend_method_declaration_list),
   2312     messageHandlers="\n".join(Generator.method_handler_list)))
   2313 
   2314 frontend_h_file.write(Templates.frontend_h.substitute(None,
   2315     fieldDeclarations="".join(Generator.frontend_class_field_lines),
   2316     domainClassList="".join(Generator.frontend_domain_class_lines)))
   2317 
   2318 frontend_cpp_file.write(Templates.frontend_cpp.substitute(None,
   2319     constructorInit="".join(Generator.frontend_constructor_init_list),
   2320     methods="\n".join(Generator.frontend_method_list)))
   2321 
   2322 typebuilder_h_file.write(Templates.typebuilder_h.substitute(None,
   2323     typeBuilders="".join(flatten_list(Generator.type_builder_fragments)),
   2324     forwards="".join(Generator.type_builder_forwards),
   2325     validatorIfdefName=VALIDATOR_IFDEF_NAME))
   2326 
   2327 typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None,
   2328     enumConstantValues=EnumConstants.get_enum_constant_code(),
   2329     implCode="".join(flatten_list(Generator.type_builder_impl_list)),
   2330     validatorCode="".join(flatten_list(Generator.validator_impl_list)),
   2331     validatorIfdefName=VALIDATOR_IFDEF_NAME))
   2332 
   2333 backend_h_file.close()
   2334 backend_cpp_file.close()
   2335 
   2336 frontend_h_file.close()
   2337 frontend_cpp_file.close()
   2338 
   2339 typebuilder_h_file.close()
   2340 typebuilder_cpp_file.close()
   2341