577047329ee0fac26837019f8eaae540fdcd6c1e
[WebKit-https.git] / Source / WebCore / inspector / CodeGeneratorInspector.py
1 #!/usr/bin/env python
2 # Copyright (c) 2011 Google Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 #     * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 #     * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 #     * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 import os.path
31 import sys
32 import string
33 import optparse
34 from string import join
35 try:
36     import json
37 except ImportError:
38     import simplejson as json
39
40
41 DOMAIN_DEFINE_NAME_MAP = {
42     "Database": "ENABLE_SQL_DATABASE",
43     "Debugger": "ENABLE_JAVASCRIPT_DEBUGGER",
44     "DOMDebugger": "ENABLE_JAVASCRIPT_DEBUGGER",
45     "FileSystem": "ENABLE_FILE_SYSTEM",
46     "Profiler": "ENABLE_JAVASCRIPT_DEBUGGER",
47     "Worker": "ENABLE_WORKERS",
48 }
49
50
51 # Manually-filled map of type name replacements.
52 TYPE_NAME_FIX_MAP = {
53     "RGBA": "Rgba",  # RGBA is reported to be conflicting with a define name in Windows CE.
54 }
55
56
57 cmdline_parser = optparse.OptionParser()
58 cmdline_parser.add_option("--defines")
59 cmdline_parser.add_option("--output_h_dir")
60 cmdline_parser.add_option("--output_cpp_dir")
61
62 try:
63     arg_options, arg_values = cmdline_parser.parse_args()
64     if (len(arg_values) != 1):
65         raise Exception("Exactly one plain argument expected (found %s)" % len(arg_values))
66     input_json_filename = arg_values[0]
67     output_header_dirname = arg_options.output_h_dir
68     output_cpp_dirname = arg_options.output_cpp_dir
69     if not output_header_dirname:
70         raise Exception("Output .h directory must be specified")
71     if not output_cpp_dirname:
72         raise Exception("Output .cpp directory must be specified")
73 except Exception, e:
74     sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % e)
75     sys.stderr.write("Usage: <script> Inspector.json --output_h_dir <output_header_dir> --output_cpp_dir <output_cpp_dir> [--defines <defines string>]\n")
76     exit(1)
77
78
79 def dash_to_camelcase(word):
80     return ''.join(x.capitalize() or '-' for x in word.split('-'))
81
82 def parse_defines(str):
83     if not str:
84         return {}
85
86     items = str.split()
87     result = {}
88     for item in items:
89         if item[0] == '"' and item[-1] == '"' and len(item) >= 2:
90             item = item[1:-1]
91         eq_pos = item.find("=")
92         if eq_pos == -1:
93             key = item
94             value = True
95         else:
96             key = item[:eq_pos]
97             value_str = item[eq_pos + 1:]
98             if value_str == "0":
99                 value = False
100             elif value_str == "1":
101                 value = True
102             else:
103                 # Should we support other values?
104                 raise Exception("Unrecognized define value: '%s' (key: '%s')" % (value_str, key))
105         result[key] = value
106     return result
107
108 defines_map = parse_defines(arg_options.defines)
109
110
111 class Capitalizer:
112     @staticmethod
113     def lower_camel_case_to_upper(str):
114         if len(str) > 0 and str[0].islower():
115             str = str[0].upper() + str[1:]
116         return str
117
118     @staticmethod
119     def upper_camel_case_to_lower(str):
120         pos = 0
121         while pos < len(str) and str[pos].isupper():
122             pos += 1
123         if pos == 0:
124             return str
125         if pos == 1:
126             return str[0].lower() + str[1:]
127         if pos < len(str):
128             pos -= 1
129         possible_abbreviation = str[0:pos]
130         if possible_abbreviation not in Capitalizer.ABBREVIATION:
131             raise Exception("Unknown abbreviation %s" % possible_abbreviation)
132         str = possible_abbreviation.lower() + str[pos:]
133         return str
134
135     @staticmethod
136     def camel_case_to_capitalized_with_underscores(str):
137         if len(str) == 0:
138             return str
139         output = Capitalizer.split_camel_case_(str)
140         return "_".join(output).upper()
141
142     @staticmethod
143     def split_camel_case_(str):
144         output = []
145         pos_being = 0
146         pos = 1
147         has_oneletter = False
148         while pos < len(str):
149             if str[pos].isupper():
150                 output.append(str[pos_being:pos].upper())
151                 if pos - pos_being == 1:
152                     has_oneletter = True
153                 pos_being = pos
154             pos += 1
155         output.append(str[pos_being:])
156         if has_oneletter:
157             array_pos = 0
158             while array_pos < len(output) - 1:
159                 if len(output[array_pos]) == 1:
160                     array_pos_end = array_pos + 1
161                     while array_pos_end < len(output) and len(output[array_pos_end]) == 1:
162                         array_pos_end += 1
163                     if array_pos_end - array_pos > 1:
164                         possible_abbreviation = "".join(output[array_pos:array_pos_end])
165                         if possible_abbreviation.upper() in Capitalizer.ABBREVIATION:
166                             output[array_pos:array_pos_end] = [possible_abbreviation]
167                         else:
168                             array_pos = array_pos_end - 1
169                 array_pos += 1
170         return output
171
172     ABBREVIATION = frozenset(["XHR", "DOM", "CSS"])
173
174
175 class DomainNameFixes:
176     @classmethod
177     def get_fixed_data(cls, domain_name):
178         if domain_name in cls.agent_type_map:
179             agent_name_res = cls.agent_type_map[domain_name]
180         else:
181             agent_name_res = "Inspector%sAgent" % domain_name
182
183         field_name_res = Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent"
184
185         class Res(object):
186             agent_type_name = agent_name_res
187             skip_js_bind = domain_name in cls.skip_js_bind_domains
188             agent_field_name = field_name_res
189
190             @staticmethod
191             def is_disabled(defines):
192                 if not domain_name in DOMAIN_DEFINE_NAME_MAP:
193                     # Has not corresponding preprocessor symbol.
194                     return False
195
196                 define_name = DOMAIN_DEFINE_NAME_MAP[domain_name]
197
198                 if not define_name in defines:
199                     # Disabled when not mentioned
200                     return True
201
202                 define_value = defines[define_name]
203                 return not bool(define_value)
204
205         return Res
206
207     skip_js_bind_domains = set(["Runtime", "DOMDebugger"])
208     agent_type_map = {"Network": "InspectorResourceAgent", "Inspector": "InspectorAgent", }
209
210
211 class CParamType(object):
212     def __init__(self, type, setter_format="%s"):
213         self.type = type
214         self.setter_format = setter_format
215
216     def get_text(self):
217         return self.type
218
219     def get_setter_format(self):
220         return self.setter_format
221
222
223 class RawTypes(object):
224     @staticmethod
225     def get(json_type):
226         if json_type == "boolean":
227             return RawTypes.Bool
228         elif json_type == "string":
229             return RawTypes.String
230         elif json_type == "array":
231             return RawTypes.Array
232         elif json_type == "object":
233             return RawTypes.Object
234         elif json_type == "integer":
235             return RawTypes.Int
236         elif json_type == "number":
237             return RawTypes.Number
238         elif json_type == "any":
239             return RawTypes.Any
240         else:
241             raise Exception("Unknown type: %s" % json_type)
242
243     class BaseType(object):
244         @classmethod
245         def get_c_param_type(cls, param_type, optional):
246             return cls.default_c_param_type
247
248         @staticmethod
249         def is_event_param_check_optional():
250             return False
251
252     class String(BaseType):
253         @classmethod
254         def get_c_param_type(cls, param_type, optional):
255             if param_type == ParamType.EVENT or param_type == ParamType.TYPE_BUILDER_OUTPUT:
256                 return cls._ref_c_type
257             else:
258                 return cls._plain_c_type
259
260         @staticmethod
261         def get_getter_name():
262             return "String"
263
264         get_setter_name = get_getter_name
265
266         @staticmethod
267         def get_c_initializer():
268             return "\"\""
269
270         @staticmethod
271         def get_js_bind_type():
272             return "string"
273
274         _plain_c_type = CParamType("String")
275         _ref_c_type = CParamType("const String&")
276
277     class Int(BaseType):
278         @staticmethod
279         def get_getter_name():
280             return "Int"
281
282         @staticmethod
283         def get_setter_name():
284             return "Number"
285
286         @staticmethod
287         def get_c_initializer():
288             return "0"
289
290         @staticmethod
291         def get_js_bind_type():
292             return "number"
293
294         default_c_param_type = CParamType("int")
295
296     class Number(BaseType):
297         @staticmethod
298         def get_getter_name():
299             return "Object"
300
301         @staticmethod
302         def get_setter_name():
303             return "Number"
304
305         @staticmethod
306         def get_c_initializer():
307             raise Exception("Unsupported")
308
309         @staticmethod
310         def get_js_bind_type():
311             raise Exception("Unsupported")
312
313         default_c_param_type = CParamType("double")
314
315     class Bool(BaseType):
316         @classmethod
317         def get_c_param_type(cls, param_type, optional):
318             if (param_type == ParamType.EVENT):
319                 if optional:
320                     return cls._ref_c_type
321                 else:
322                     return cls._plain_c_type
323             else:
324                 return cls._plain_c_type
325
326         @staticmethod
327         def get_getter_name():
328             return "Boolean"
329
330         get_setter_name = get_getter_name
331
332         @staticmethod
333         def get_c_initializer():
334             return "false"
335
336         @staticmethod
337         def get_js_bind_type():
338             return "boolean"
339
340         @staticmethod
341         def is_event_param_check_optional():
342             return True
343
344         _plain_c_type = CParamType("bool")
345         _ref_c_type = CParamType("const bool* const", "*%s")
346
347     class Object(BaseType):
348         @classmethod
349         def get_c_param_type(cls, param_type, optional):
350             if param_type == ParamType.EVENT or param_type == ParamType.TYPE_BUILDER_OUTPUT:
351                 return cls._ref_c_type
352             else:
353                 return cls._plain_c_type
354
355         @staticmethod
356         def get_getter_name():
357             return "Object"
358
359         get_setter_name = get_getter_name
360
361         @staticmethod
362         def get_c_initializer():
363             return "InspectorObject::create()"
364
365         @staticmethod
366         def get_js_bind_type():
367             return "object"
368
369         @staticmethod
370         def is_event_param_check_optional():
371             return True
372
373         _plain_c_type = CParamType("RefPtr<InspectorObject>")
374         _ref_c_type = CParamType("PassRefPtr<InspectorObject>")
375
376     class Any(BaseType):
377         @classmethod
378         def get_c_param_type(cls, param_type, optional):
379             if param_type == ParamType.EVENT or param_type == ParamType.TYPE_BUILDER_OUTPUT:
380                 return cls._ref_c_type
381             else:
382                 return cls._plain_c_type
383
384         @staticmethod
385         def get_getter_name():
386             return "Value"
387
388         get_setter_name = get_getter_name
389
390         @staticmethod
391         def get_c_initializer():
392             return "InspectorValue::create()"
393
394         @staticmethod
395         def get_js_bind_type():
396             raise Exception("Unsupported")
397
398         @staticmethod
399         def is_event_param_check_optional():
400             return True
401
402         _plain_c_type = CParamType("RefPtr<InspectorValue>")
403         _ref_c_type = CParamType("PassRefPtr<InspectorValue>")
404
405     class Array(BaseType):
406         @classmethod
407         def get_c_param_type(cls, param_type, optional):
408             if param_type == ParamType.OUTPUT:
409                 return cls._plain_c_type
410             elif param_type == ParamType.INPUT:
411                 return cls._plain_c_type
412             else:
413                 return cls._ref_c_type
414
415         @staticmethod
416         def get_getter_name():
417             return "Array"
418
419         get_setter_name = get_getter_name
420
421         @staticmethod
422         def get_c_initializer():
423             return "InspectorArray::create()"
424
425         @staticmethod
426         def get_js_bind_type():
427             return "object"
428
429         @staticmethod
430         def is_event_param_check_optional():
431             return True
432
433         _plain_c_type = CParamType("RefPtr<InspectorArray>")
434         _ref_c_type = CParamType("PassRefPtr<InspectorArray>")
435
436
437 class ParamType(object):
438     INPUT = "input"
439     OUTPUT = "output"
440     EVENT = "event"
441     TYPE_BUILDER_OUTPUT = "typeBuilderOutput"
442
443 # Collection of InspectorObject class methods that are likely to be overloaded in generated class.
444 # We must explicitly import all overloaded methods or they won't be available to user.
445 INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"])
446
447
448 def fix_type_name(json_name):
449     if json_name in TYPE_NAME_FIX_MAP:
450         fixed = TYPE_NAME_FIX_MAP[json_name]
451
452         class Result(object):
453             class_name = fixed
454
455             @staticmethod
456             def output_comment(output):
457                 output.append("// Type originally was named '%s'.\n" % json_name)
458     else:
459
460         class Result(object):
461             class_name = json_name
462
463             @staticmethod
464             def output_comment(output):
465                 pass
466
467     return Result
468
469
470
471 class TypeBindings:
472     @staticmethod
473     def create_for_named_type_declaration(json_type, context_domain_name):
474         fixed_type_name = fix_type_name(json_type["id"])
475
476         def write_doc(output):
477             if "description" in json_type:
478                 output.append("/* ")
479                 output.append(json_type["description"])
480                 output.append(" */\n")
481
482         if json_type["type"] == "string":
483             if "enum" in json_type:
484
485                 class EnumBinding:
486                     @staticmethod
487                     def generate_type_builder(output, forward_listener):
488                         enum = json_type["enum"]
489                         write_doc(output)
490                         enum_name = fixed_type_name.class_name
491                         fixed_type_name.output_comment(output)
492                         output.append("namespace ")
493                         output.append(enum_name)
494                         output.append(" {\n")
495                         for enum_item in enum:
496                             item_c_name = enum_item.replace('-', '_')
497                             output.append("const char* const ")
498                             output.append(Capitalizer.upper_camel_case_to_lower(item_c_name))
499                             output.append(" = \"")
500                             output.append(enum_item)
501                             output.append("\";\n")
502                         output.append("} // namespace ")
503                         output.append(enum_name)
504                         output.append("\n\n")
505
506                 return EnumBinding
507             else:
508
509                 class PlainString:
510                     @staticmethod
511                     def generate_type_builder(output, forward_listener):
512                         write_doc(output)
513                         fixed_type_name.output_comment(output)
514                         output.append("typedef String ")
515                         output.append(fixed_type_name.class_name)
516                         output.append(";\n\n")
517                 return PlainString
518
519         elif json_type["type"] == "object":
520             if "properties" in json_type:
521
522                 class ClassBinding:
523                     @staticmethod
524                     def generate_type_builder(output, forward_listener):
525                         write_doc(output)
526                         class_name = fixed_type_name.class_name
527                         fixed_type_name.output_comment(output)
528                         output.append("class ")
529                         output.append(class_name)
530                         output.append(" : public InspectorObject {\n")
531                         output.append("public:\n")
532
533                         properties = json_type["properties"]
534                         main_properties = []
535                         optional_properties = []
536                         for p in properties:
537                             if "optional" in p and p["optional"]:
538                                 optional_properties.append(p)
539                             else:
540                                 main_properties.append(p)
541
542                         output.append(
543 """    enum {
544         NO_FIELDS_SET = 0,
545 """)
546
547                         state_enum_items = []
548                         if len(main_properties) > 0:
549                             pos = 0
550                             for p in main_properties:
551                                 item_name = Capitalizer.camel_case_to_capitalized_with_underscores(p["name"]) + "_SET"
552                                 state_enum_items.append(item_name)
553                                 output.append("        %s = 1 << %s,\n" % (item_name, pos))
554                                 pos += 1
555                             all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")"
556                         else:
557                             all_fields_set_value = "0"
558
559                         output.append(
560 """        ALL_FIELDS_SET = %s
561     };
562
563     template<int STATE>
564     class Builder {
565     private:
566         RefPtr<InspectorObject> m_result;
567
568         template<int STEP> Builder<STATE | STEP>& castState()
569         {
570             return *reinterpret_cast<Builder<STATE | STEP>*>(this);
571         }
572
573         Builder(PassRefPtr<%s> ptr)
574         {
575             COMPILE_ASSERT(STATE == NO_FIELDS_SET, builder_created_in_non_init_state);
576             m_result = ptr;
577         }
578         friend class %s;
579     public:
580 """ % (all_fields_set_value, class_name, class_name))
581
582                         pos = 0
583                         for prop in main_properties:
584                             prop_name = prop["name"]
585                             param_raw_type = resolve_param_raw_type(prop, context_domain_name)
586                             output.append("""
587         Builder<STATE | %s>& set%s(%s value)
588         {
589             COMPILE_ASSERT(!(STATE & %s), property_%s_already_set);
590             m_result->set%s("%s", value);
591             return castState<%s>();
592         }
593 """
594                             % (state_enum_items[pos],
595                                Capitalizer.lower_camel_case_to_upper(prop_name),
596                                param_raw_type.get_c_param_type(ParamType.TYPE_BUILDER_OUTPUT, False).get_text(),
597                                state_enum_items[pos], prop_name,
598                                param_raw_type.get_setter_name(), prop_name, state_enum_items[pos]))
599
600                             pos += 1
601
602                         output.append("""
603         operator RefPtr<%s>& ()
604         {
605             COMPILE_ASSERT(STATE == ALL_FIELDS_SET, result_is_not_ready);
606             return *reinterpret_cast<RefPtr<%s>*>(&m_result);
607         }
608
609         operator PassRefPtr<%s> ()
610         {
611             return RefPtr<%s>(*this);
612         }
613     };
614
615 """
616                         % (class_name, class_name, class_name, class_name))
617
618                         output.append("    /*\n")
619                         output.append("     * Synthetic constructor:\n")
620                         output.append("     * RefPtr<%s> result = %s::create()" % (class_name, class_name))
621                         for prop in main_properties:
622                             output.append("\n     *     .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop["name"]))
623                         output.append(";\n     */\n")
624
625                         output.append(
626 """    static Builder<NO_FIELDS_SET> create()
627     {
628         return Builder<NO_FIELDS_SET>(adoptRef(new %s()));
629     }
630 """ % class_name)
631
632                         for prop in optional_properties:
633                             param_raw_type = resolve_param_raw_type(prop, context_domain_name)
634                             setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop["name"])
635                             output.append("\n    void %s" % setter_name)
636                             output.append("(%s value)\n" % param_raw_type.get_c_param_type(ParamType.TYPE_BUILDER_OUTPUT, False).get_text())
637                             output.append("    {\n")
638                             output.append("        this->set%s(\"%s\", value);\n" % (param_raw_type.get_setter_name(), prop["name"]))
639                             output.append("    }\n")
640
641                             if setter_name in INSPECTOR_OBJECT_SETTER_NAMES:
642                                 output.append("    using InspectorObject::%s;\n\n" % setter_name)
643
644                         output.append("};\n\n")
645                 return ClassBinding
646             else:
647
648                 class PlainObjectBinding:
649                     @staticmethod
650                     def generate_type_builder(output, forward_listener):
651                         # No-op
652                         pass
653                 return PlainObjectBinding
654         else:
655             raw_type = RawTypes.get(json_type["type"])
656
657             class RawTypesBinding:
658                 @staticmethod
659                 def generate_type_builder(output, forward_listener):
660                     # No-op
661                     pass
662             return RawTypesBinding
663
664
665 class TypeData(object):
666     def __init__(self, json_type, json_domain, domain_data):
667         self.json_type_ = json_type
668         self.json_domain_ = json_domain
669         self.domain_data_ = domain_data
670
671         if "type" not in json_type:
672             raise Exception("Unknown type")
673
674         json_type_name = json_type["type"]
675         raw_type = RawTypes.get(json_type_name)
676         self.raw_type_ = raw_type
677         self.binding_ = TypeBindings.create_for_named_type_declaration(json_type, json_domain["domain"])
678
679     def get_raw_type(self):
680         return self.raw_type_
681
682     def get_binding(self):
683         return self.binding_
684
685
686 class DomainData:
687     def __init__(self, json_domain):
688         self.json_domain = json_domain
689         self.types_ = []
690
691     def add_type(self, type_data):
692         self.types_.append(type_data)
693
694     def name(self):
695         return self.json_domain["domain"]
696
697     def types(self):
698         return self.types_
699
700
701 class TypeMap:
702     def __init__(self, api):
703         self.map_ = {}
704         self.domains_ = []
705         for json_domain in api["domains"]:
706             domain_name = json_domain["domain"]
707
708             domain_map = {}
709             self.map_[domain_name] = domain_map
710
711             domain_data = DomainData(json_domain)
712             self.domains_.append(domain_data)
713
714             if "types" in json_domain:
715                 for json_type in json_domain["types"]:
716                     type_name = json_type["id"]
717                     type_data = TypeData(json_type, json_domain, domain_data)
718                     domain_map[type_name] = type_data
719                     domain_data.add_type(type_data)
720
721     def domains(self):
722         return self.domains_
723
724     def get(self, domain_name, type_name):
725         return self.map_[domain_name][type_name]
726
727
728 def resolve_param_raw_type(json_parameter, scope_domain_name):
729     if "$ref" in json_parameter:
730         json_ref = json_parameter["$ref"]
731         type_data = get_ref_data(json_ref, scope_domain_name)
732         return type_data.get_raw_type()
733     elif "type" in json_parameter:
734         json_type = json_parameter["type"]
735         return RawTypes.get(json_type)
736     else:
737         raise Exception("Unknown type")
738
739
740 def get_ref_data(json_ref, scope_domain_name):
741     dot_pos = json_ref.find(".")
742     if dot_pos == -1:
743         domain_name = scope_domain_name
744         type_name = json_ref
745     else:
746         domain_name = json_ref[:dot_pos]
747         type_name = json_ref[dot_pos + 1:]
748
749     return type_map.get(domain_name, type_name)
750
751
752 input_file = open(input_json_filename, "r")
753 json_string = input_file.read()
754 json_api = json.loads(json_string)
755
756
757 class Templates:
758     def get_this_script_path_(absolute_path):
759         absolute_path = os.path.abspath(absolute_path)
760         components = []
761
762         def fill_recursive(path_part, depth):
763             if depth <= 0 or path_part == '/':
764                 return
765             fill_recursive(os.path.dirname(path_part), depth - 1)
766             components.append(os.path.basename(path_part))
767
768         # Typical path is /Source/WebCore/inspector/CodeGeneratorInspector.py
769         # Let's take 4 components from the real path then.
770         fill_recursive(absolute_path, 4)
771
772         return "/".join(components)
773
774     file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) +
775 """// Copyright (c) 2011 The Chromium Authors. All rights reserved.
776 // Use of this source code is governed by a BSD-style license that can be
777 // found in the LICENSE file.
778 """)
779
780
781
782     frontend_domain_class = string.Template(
783 """    class $domainClassName {
784     public:
785         $domainClassName(InspectorFrontendChannel* inspectorFrontendChannel) : m_inspectorFrontendChannel(inspectorFrontendChannel) { }
786 ${frontendDomainMethodDeclarations}        void setInspectorFrontendChannel(InspectorFrontendChannel* inspectorFrontendChannel) { m_inspectorFrontendChannel = inspectorFrontendChannel; }
787         InspectorFrontendChannel* getInspectorFrontendChannel() { return m_inspectorFrontendChannel; }
788     private:
789         InspectorFrontendChannel* m_inspectorFrontendChannel;
790     };
791
792     $domainClassName* $domainFieldName() { return &m_$domainFieldName; }
793
794 """)
795
796     backend_method = string.Template(
797 """void InspectorBackendDispatcher::${domainName}_$methodName(long callId, InspectorObject*$requestMessageObject)
798 {
799     RefPtr<InspectorArray> protocolErrors = InspectorArray::create();
800
801     if (!$agentField)
802         protocolErrors->pushString("${domainName} handler is not available.");
803 $methodOutCode
804     ErrorString error;
805 $methodInCode
806     if (!protocolErrors->length())
807         $agentField->$methodName(&error$agentCallParams);
808
809     RefPtr<InspectorObject> result = InspectorObject::create();
810 ${responseCook}    sendResponse(callId, result, String::format("Some arguments of method '%s' can't be processed", "$domainName.$methodName"), protocolErrors, error);
811 }
812 """)
813
814     frontend_method = string.Template("""void InspectorFrontend::$domainName::$eventName($parameters)
815 {
816     RefPtr<InspectorObject> ${eventName}Message = InspectorObject::create();
817     ${eventName}Message->setString("method", "$domainName.$eventName");
818 $code    if (m_inspectorFrontendChannel)
819         m_inspectorFrontendChannel->sendMessageToFrontend(${eventName}Message->toJSONString());
820 }
821 """)
822
823     frontend_h = string.Template(file_header_ +
824 """#ifndef InspectorFrontend_h
825 #define InspectorFrontend_h
826
827 #include "InspectorValues.h"
828 #include <PlatformString.h>
829 #include <wtf/PassRefPtr.h>
830
831 namespace WebCore {
832
833 class InspectorFrontendChannel;
834
835 // Both InspectorObject and InspectorArray may or may not be declared at this point as defined by ENABLED_INSPECTOR.
836 // Double-check we have them at least as forward declaration.
837 class InspectorArray;
838 class InspectorObject;
839
840 typedef String ErrorString;
841
842 #if ENABLE(INSPECTOR)
843
844 namespace TypeBuilder {
845 ${typeBuilders}
846 } // namespace TypeBuilder
847
848 #endif // ENABLE(INSPECTOR)
849
850 class InspectorFrontend {
851 public:
852     InspectorFrontend(InspectorFrontendChannel*);
853
854
855 $domainClassList
856 private:
857     InspectorFrontendChannel* m_inspectorFrontendChannel;
858 ${fieldDeclarations}};
859
860 } // namespace WebCore
861 #endif // !defined(InspectorFrontend_h)
862 """)
863
864     backend_h = string.Template(file_header_ +
865 """#ifndef InspectorBackendDispatcher_h
866 #define InspectorBackendDispatcher_h
867
868 #include <wtf/PassRefPtr.h>
869 #include <wtf/RefCounted.h>
870 #include <wtf/text/WTFString.h>
871
872 namespace WebCore {
873
874 class InspectorAgent;
875 class InspectorObject;
876 class InspectorArray;
877 class InspectorFrontendChannel;
878
879 $forwardDeclarations
880
881 typedef String ErrorString;
882
883 class InspectorBackendDispatcher: public RefCounted<InspectorBackendDispatcher> {
884 public:
885     InspectorBackendDispatcher(InspectorFrontendChannel* inspectorFrontendChannel)
886         : m_inspectorFrontendChannel(inspectorFrontendChannel)
887 $constructorInit
888     { }
889
890 $setters
891
892     void clearFrontend() { m_inspectorFrontendChannel = 0; }
893
894     enum CommonErrorCode {
895         ParseError = 0,
896         InvalidRequest,
897         MethodNotFound,
898         InvalidParams,
899         InternalError,
900         ServerError,
901         LastEntry,
902     };
903
904     void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage) const;
905     void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage, PassRefPtr<InspectorArray> data) const;
906     void dispatch(const String& message);
907     static bool getCommandName(const String& message, String* result);
908
909     enum MethodNames {
910 $methodNamesEnumContent
911 };
912
913     static const char* commandNames[];
914
915 private:
916     static int getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
917     static String getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
918     static bool getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
919     static PassRefPtr<InspectorObject> getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
920     static PassRefPtr<InspectorArray> getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
921     void sendResponse(long callId, PassRefPtr<InspectorObject> result, const String& errorMessage, PassRefPtr<InspectorArray> protocolErrors, ErrorString invocationError);
922
923 $methodDeclarations
924
925     InspectorFrontendChannel* m_inspectorFrontendChannel;
926 $fieldDeclarations
927 };
928
929 } // namespace WebCore
930 #endif // !defined(InspectorBackendDispatcher_h)
931
932
933 """)
934
935     backend_cpp = string.Template(file_header_ +
936 """
937
938 #include "config.h"
939 #include "InspectorBackendDispatcher.h"
940 #include <wtf/text/WTFString.h>
941 #include <wtf/text/CString.h>
942
943 #if ENABLE(INSPECTOR)
944
945 #include "InspectorAgent.h"
946 #include "InspectorValues.h"
947 #include "InspectorFrontendChannel.h"
948 #include <wtf/text/WTFString.h>
949 $includes
950
951 namespace WebCore {
952
953 const char* InspectorBackendDispatcher::commandNames[] = {
954 $methodNameDeclarations
955 };
956
957
958 $methods
959 void InspectorBackendDispatcher::dispatch(const String& message)
960 {
961     RefPtr<InspectorBackendDispatcher> protect = this;
962     typedef void (InspectorBackendDispatcher::*CallHandler)(long callId, InspectorObject* messageObject);
963     typedef HashMap<String, CallHandler> DispatchMap;
964     DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, );
965     long callId = 0;
966
967     if (dispatchMap.isEmpty()) {
968         static CallHandler handlers[] = {
969 $messageHandlers
970         };
971         size_t length = sizeof(commandNames) / sizeof(commandNames[0]);
972         for (size_t i = 0; i < length; ++i)
973             dispatchMap.add(commandNames[i], handlers[i]);
974     }
975
976     RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
977     if (!parsedMessage) {
978         reportProtocolError(0, ParseError, "Message must be in JSON format");
979         return;
980     }
981
982     RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
983     if (!messageObject) {
984         reportProtocolError(0, InvalidRequest, "Message must be a JSONified object");
985         return;
986     }
987
988     RefPtr<InspectorValue> callIdValue = messageObject->get("id");
989     if (!callIdValue) {
990         reportProtocolError(0, InvalidRequest, "'id' property was not found");
991         return;
992     }
993
994     if (!callIdValue->asNumber(&callId)) {
995         reportProtocolError(0, InvalidRequest, "The type of 'id' property must be number");
996         return;
997     }
998
999     RefPtr<InspectorValue> methodValue = messageObject->get("method");
1000     if (!methodValue) {
1001         reportProtocolError(&callId, InvalidRequest, "'method' property wasn't found");
1002         return;
1003     }
1004
1005     String method;
1006     if (!methodValue->asString(&method)) {
1007         reportProtocolError(&callId, InvalidRequest, "The type of 'method' property must be string");
1008         return;
1009     }
1010
1011     HashMap<String, CallHandler>::iterator it = dispatchMap.find(method);
1012     if (it == dispatchMap.end()) {
1013         reportProtocolError(&callId, MethodNotFound, "'" + method + "' wasn't found");
1014         return;
1015     }
1016
1017     ((*this).*it->second)(callId, messageObject.get());
1018 }
1019
1020 void InspectorBackendDispatcher::sendResponse(long callId, PassRefPtr<InspectorObject> result, const String& errorMessage, PassRefPtr<InspectorArray> protocolErrors, ErrorString invocationError)
1021 {
1022     if (protocolErrors->length()) {
1023         reportProtocolError(&callId, InvalidParams, errorMessage, protocolErrors);
1024         return;
1025     }
1026     if (invocationError.length()) {
1027         reportProtocolError(&callId, ServerError, invocationError);
1028         return;
1029     }
1030
1031     RefPtr<InspectorObject> responseMessage = InspectorObject::create();
1032     responseMessage->setObject("result", result);
1033     responseMessage->setNumber("id", callId);
1034     if (m_inspectorFrontendChannel)
1035         m_inspectorFrontendChannel->sendMessageToFrontend(responseMessage->toJSONString());
1036 }
1037
1038 void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode code, const String& errorMessage) const
1039 {
1040     reportProtocolError(callId, code, errorMessage, 0);
1041 }
1042
1043 void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<InspectorArray> data) const
1044 {
1045     DEFINE_STATIC_LOCAL(Vector<int>,s_commonErrors,);
1046     if (!s_commonErrors.size()) {
1047         s_commonErrors.insert(ParseError, -32700);
1048         s_commonErrors.insert(InvalidRequest, -32600);
1049         s_commonErrors.insert(MethodNotFound, -32601);
1050         s_commonErrors.insert(InvalidParams, -32602);
1051         s_commonErrors.insert(InternalError, -32603);
1052         s_commonErrors.insert(ServerError, -32000);
1053     }
1054     ASSERT(code >=0);
1055     ASSERT((unsigned)code < s_commonErrors.size());
1056     ASSERT(s_commonErrors[code]);
1057     RefPtr<InspectorObject> error = InspectorObject::create();
1058     error->setNumber("code", s_commonErrors[code]);
1059     error->setString("message", errorMessage);
1060     ASSERT(error);
1061     if (data)
1062         error->setArray("data", data);
1063     RefPtr<InspectorObject> message = InspectorObject::create();
1064     message->setObject("error", error);
1065     if (callId)
1066         message->setNumber("id", *callId);
1067     else
1068         message->setValue("id", InspectorValue::null());
1069     if (m_inspectorFrontendChannel)
1070         m_inspectorFrontendChannel->sendMessageToFrontend(message->toJSONString());
1071 }
1072
1073 int InspectorBackendDispatcher::getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1074 {
1075     ASSERT(protocolErrors);
1076
1077     if (valueFound)
1078         *valueFound = false;
1079
1080     int value = 0;
1081
1082     if (!object) {
1083         if (!valueFound) {
1084             // Required parameter in missing params container.
1085             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Number'.", name.utf8().data()));
1086         }
1087         return value;
1088     }
1089
1090     InspectorObject::const_iterator end = object->end();
1091     InspectorObject::const_iterator valueIterator = object->find(name);
1092
1093     if (valueIterator == end) {
1094         if (!valueFound)
1095             protocolErrors->pushString(String::format("Parameter '%s' with type 'Number' was not found.", name.utf8().data()));
1096         return value;
1097     }
1098
1099     if (!valueIterator->second->asNumber(&value))
1100         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Number'.", name.utf8().data()));
1101     else
1102         if (valueFound)
1103             *valueFound = true;
1104     return value;
1105 }
1106
1107 String InspectorBackendDispatcher::getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1108 {
1109     ASSERT(protocolErrors);
1110
1111     if (valueFound)
1112         *valueFound = false;
1113
1114     String value = "";
1115
1116     if (!object) {
1117         if (!valueFound) {
1118             // Required parameter in missing params container.
1119             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'String'.", name.utf8().data()));
1120         }
1121         return value;
1122     }
1123
1124     InspectorObject::const_iterator end = object->end();
1125     InspectorObject::const_iterator valueIterator = object->find(name);
1126
1127     if (valueIterator == end) {
1128         if (!valueFound)
1129             protocolErrors->pushString(String::format("Parameter '%s' with type 'String' was not found.", name.utf8().data()));
1130         return value;
1131     }
1132
1133     if (!valueIterator->second->asString(&value))
1134         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'String'.", name.utf8().data()));
1135     else
1136         if (valueFound)
1137             *valueFound = true;
1138     return value;
1139 }
1140
1141 bool InspectorBackendDispatcher::getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1142 {
1143     ASSERT(protocolErrors);
1144
1145     if (valueFound)
1146         *valueFound = false;
1147
1148     bool value = false;
1149
1150     if (!object) {
1151         if (!valueFound) {
1152             // Required parameter in missing params container.
1153             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Boolean'.", name.utf8().data()));
1154         }
1155         return value;
1156     }
1157
1158     InspectorObject::const_iterator end = object->end();
1159     InspectorObject::const_iterator valueIterator = object->find(name);
1160
1161     if (valueIterator == end) {
1162         if (!valueFound)
1163             protocolErrors->pushString(String::format("Parameter '%s' with type 'Boolean' was not found.", name.utf8().data()));
1164         return value;
1165     }
1166
1167     if (!valueIterator->second->asBoolean(&value))
1168         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Boolean'.", name.utf8().data()));
1169     else
1170         if (valueFound)
1171             *valueFound = true;
1172     return value;
1173 }
1174
1175 PassRefPtr<InspectorObject> InspectorBackendDispatcher::getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1176 {
1177     ASSERT(protocolErrors);
1178
1179     if (valueFound)
1180         *valueFound = false;
1181
1182     RefPtr<InspectorObject> value = InspectorObject::create();
1183
1184     if (!object) {
1185         if (!valueFound) {
1186             // Required parameter in missing params container.
1187             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Object'.", name.utf8().data()));
1188         }
1189         return value;
1190     }
1191
1192     InspectorObject::const_iterator end = object->end();
1193     InspectorObject::const_iterator valueIterator = object->find(name);
1194
1195     if (valueIterator == end) {
1196         if (!valueFound)
1197             protocolErrors->pushString(String::format("Parameter '%s' with type 'Object' was not found.", name.utf8().data()));
1198         return value;
1199     }
1200
1201     if (!valueIterator->second->asObject(&value))
1202         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Object'.", name.utf8().data()));
1203     else
1204         if (valueFound)
1205             *valueFound = true;
1206     return value;
1207 }
1208
1209 PassRefPtr<InspectorArray> InspectorBackendDispatcher::getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1210 {
1211     ASSERT(protocolErrors);
1212
1213     if (valueFound)
1214         *valueFound = false;
1215
1216     RefPtr<InspectorArray> value = InspectorArray::create();
1217
1218     if (!object) {
1219         if (!valueFound) {
1220             // Required parameter in missing params container.
1221             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Array'.", name.utf8().data()));
1222         }
1223         return value;
1224     }
1225
1226     InspectorObject::const_iterator end = object->end();
1227     InspectorObject::const_iterator valueIterator = object->find(name);
1228
1229     if (valueIterator == end) {
1230         if (!valueFound)
1231             protocolErrors->pushString(String::format("Parameter '%s' with type 'Array' was not found.", name.utf8().data()));
1232         return value;
1233     }
1234
1235     if (!valueIterator->second->asArray(&value))
1236         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Array'.", name.utf8().data()));
1237     else
1238         if (valueFound)
1239             *valueFound = true;
1240     return value;
1241 }
1242 bool InspectorBackendDispatcher::getCommandName(const String& message, String* result)
1243 {
1244     RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
1245     if (!value)
1246         return false;
1247
1248     RefPtr<InspectorObject> object = value->asObject();
1249     if (!object)
1250         return false;
1251
1252     if (!object->getString("method", result))
1253         return false;
1254
1255     return true;
1256 }
1257
1258
1259 } // namespace WebCore
1260
1261 #endif // ENABLE(INSPECTOR)
1262 """)
1263
1264     frontend_cpp = string.Template(file_header_ +
1265 """
1266
1267 #include "config.h"
1268 #include "InspectorFrontend.h"
1269 #include <wtf/text/WTFString.h>
1270 #include <wtf/text/CString.h>
1271
1272 #if ENABLE(INSPECTOR)
1273
1274 #include "InspectorFrontendChannel.h"
1275 #include "InspectorValues.h"
1276 #include <wtf/text/WTFString.h>
1277
1278 namespace WebCore {
1279
1280 InspectorFrontend::InspectorFrontend(InspectorFrontendChannel* inspectorFrontendChannel)
1281     : m_inspectorFrontendChannel(inspectorFrontendChannel)
1282 $constructorInit{
1283 }
1284
1285 $methods
1286
1287 } // namespace WebCore
1288
1289 #endif // ENABLE(INSPECTOR)
1290 """)
1291
1292     backend_js = string.Template(file_header_ +
1293 """
1294
1295 $delegates
1296 $eventArgs
1297 $domainDispatchers
1298 """)
1299
1300     param_container_access_code = """
1301     RefPtr<InspectorObject> paramsContainer = requestMessageObject->getObject("params");
1302     InspectorObject* paramsContainerPtr = paramsContainer.get();
1303     InspectorArray* protocolErrorsPtr = protocolErrors.get();
1304 """
1305
1306
1307 type_map = TypeMap(json_api)
1308
1309 class Generator:
1310     frontend_class_field_lines = []
1311     frontend_domain_class_lines = []
1312
1313     method_name_enum_list = []
1314     backend_method_declaration_list = []
1315     backend_method_implementation_list = []
1316     backend_method_name_declaration_list = []
1317     method_handler_list = []
1318     frontend_method_list = []
1319     backend_js_initializer_list = []
1320     backend_js_event_list = []
1321     backend_js_domain_dispatcher_list = []
1322
1323     backend_setters_list = []
1324     backend_constructor_init_list = []
1325     backend_field_list = []
1326     backend_forward_list = []
1327     backend_include_list = []
1328     frontend_constructor_init_list = []
1329     type_builder_fragments = []
1330
1331     @staticmethod
1332     def go():
1333         Generator.process_types(type_map)
1334
1335         for json_domain in json_api["domains"]:
1336             domain_name = json_domain["domain"]
1337             domain_name_lower = domain_name.lower()
1338
1339             domain_data = DomainNameFixes.get_fixed_data(domain_name)
1340
1341             if domain_data.is_disabled(defines_map):
1342                 continue
1343
1344             agent_field_name = domain_data.agent_field_name
1345
1346             frontend_method_declaration_lines = []
1347
1348             if "events" in json_domain:
1349                 for json_event in json_domain["events"]:
1350                     Generator.process_event(json_event, domain_name, frontend_method_declaration_lines)
1351
1352             Generator.frontend_class_field_lines.append("    %s m_%s;\n" % (domain_name, domain_name_lower))
1353             Generator.frontend_constructor_init_list.append("    , m_%s(inspectorFrontendChannel)\n" % domain_name_lower)
1354             Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None,
1355                 domainClassName=domain_name,
1356                 domainFieldName=domain_name_lower,
1357                 frontendDomainMethodDeclarations=join(frontend_method_declaration_lines, "")))
1358
1359             if "commands" in json_domain:
1360                 for json_command in json_domain["commands"]:
1361                     Generator.process_command(json_command, domain_name, agent_field_name)
1362
1363             if not domain_data.skip_js_bind:
1364                 Generator.backend_js_domain_dispatcher_list.append("InspectorBackend.register%sDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"%s\");\n" % (domain_name, domain_name))
1365
1366         sorted_json_domains = list(json_api["domains"])
1367         sorted_json_domains.sort(key=lambda o: o["domain"])
1368
1369         for json_domain in sorted_json_domains:
1370             domain_name = json_domain["domain"]
1371
1372             domain_data = DomainNameFixes.get_fixed_data(domain_name)
1373             if domain_data.is_disabled(defines_map):
1374                 continue
1375
1376             agent_type_name = domain_data.agent_type_name
1377             agent_field_name = domain_data.agent_field_name
1378             Generator.backend_constructor_init_list.append("        , m_%s(0)" % agent_field_name)
1379             Generator.backend_setters_list.append("    void registerAgent(%s* %s) { ASSERT(!m_%s); m_%s = %s; }" % (agent_type_name, agent_field_name, agent_field_name, agent_field_name, agent_field_name))
1380             Generator.backend_field_list.append("    %s* m_%s;" % (agent_type_name, agent_field_name))
1381             Generator.backend_forward_list.append("class %s;" % agent_type_name)
1382             Generator.backend_include_list.append("#include \"%s.h\"" % agent_type_name)
1383
1384     @staticmethod
1385     def process_event(json_event, domain_name, frontend_method_declaration_lines):
1386         event_name = json_event["name"]
1387         parameter_list = []
1388         method_line_list = []
1389         backend_js_event_param_list = []
1390         if "parameters" in json_event:
1391             method_line_list.append("    RefPtr<InspectorObject> paramsObject = InspectorObject::create();\n")
1392             for json_parameter in json_event["parameters"]:
1393                 parameter_name = json_parameter["name"]
1394
1395                 raw_type = resolve_param_raw_type(json_parameter, domain_name)
1396
1397                 json_optional = "optional" in json_parameter and json_parameter["optional"]
1398
1399                 optional_mask = raw_type.is_event_param_check_optional()
1400                 c_type = raw_type.get_c_param_type(ParamType.EVENT, json_optional)
1401
1402                 setter_type = raw_type.get_setter_name()
1403
1404                 optional = optional_mask and json_optional
1405
1406                 parameter_list.append("%s %s" % (c_type.get_text(), parameter_name))
1407
1408                 setter_argument = c_type.get_setter_format() % parameter_name
1409
1410                 setter_code = "    paramsObject->set%s(\"%s\", %s);\n" % (setter_type, parameter_name, setter_argument)
1411                 if optional:
1412                     setter_code = ("    if (%s)\n    " % parameter_name) + setter_code
1413                 method_line_list.append(setter_code)
1414
1415                 backend_js_event_param_list.append("\"%s\"" % parameter_name)
1416             method_line_list.append("    %sMessage->setObject(\"params\", paramsObject);\n" % event_name)
1417         frontend_method_declaration_lines.append(
1418             "        void %s(%s);\n" % (event_name, join(parameter_list, ", ")))
1419
1420         Generator.frontend_method_list.append(Templates.frontend_method.substitute(None,
1421             domainName=domain_name, eventName=event_name,
1422             parameters=join(parameter_list, ", "),
1423             code=join(method_line_list, "")))
1424
1425         Generator.backend_js_event_list.append("InspectorBackend.registerEvent(\"%s.%s\", [%s]);\n" % (
1426             domain_name, event_name, join(backend_js_event_param_list, ", ")))
1427
1428     @staticmethod
1429     def process_command(json_command, domain_name, agent_field_name):
1430         json_command_name = json_command["name"]
1431         Generator.method_name_enum_list.append("        k%s_%sCmd," % (domain_name, json_command["name"]))
1432         Generator.method_handler_list.append("            &InspectorBackendDispatcher::%s_%s," % (domain_name, json_command_name))
1433         Generator.backend_method_declaration_list.append("    void %s_%s(long callId, InspectorObject* requestMessageObject);" % (domain_name, json_command_name))
1434
1435         method_in_code = ""
1436         method_out_code = ""
1437         agent_call_param_list = []
1438         response_cook_list = []
1439         backend_js_reply_param_list = []
1440         request_message_param = ""
1441         js_parameters_text = ""
1442         if "parameters" in json_command:
1443             json_params = json_command["parameters"]
1444             method_in_code += Templates.param_container_access_code
1445             request_message_param = " requestMessageObject"
1446             js_param_list = []
1447
1448             for json_parameter in json_params:
1449                 json_param_name = json_parameter["name"]
1450                 param_raw_type = resolve_param_raw_type(json_parameter, domain_name)
1451
1452                 var_type = param_raw_type.get_c_param_type(ParamType.INPUT, None)
1453                 getter_name = param_raw_type.get_getter_name()
1454
1455                 if "optional" in json_parameter and json_parameter["optional"]:
1456                     code = ("    bool %s_valueFound = false;\n"
1457                             "    %s in_%s = get%s(paramsContainerPtr, \"%s\", &%s_valueFound, protocolErrorsPtr);\n" %
1458                            (json_param_name, var_type.get_text(), json_param_name, getter_name, json_param_name, json_param_name))
1459                     param = ", %s_valueFound ? &in_%s : 0" % (json_param_name, json_param_name)
1460                 else:
1461                     code = ("    %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrorsPtr);\n" %
1462                             (var_type.get_text(), json_param_name, getter_name, json_param_name))
1463                     param = ", in_%s" % json_param_name
1464
1465                 method_in_code += code
1466                 agent_call_param_list.append(param)
1467
1468                 js_bind_type = param_raw_type.get_js_bind_type()
1469                 js_param_text = "{\"name\": \"%s\", \"type\": \"%s\", \"optional\": %s}" % (
1470                     json_param_name,
1471                     js_bind_type,
1472                     ("true" if ("optional" in json_parameter and json_parameter["optional"]) else "false"))
1473
1474                 js_param_list.append(js_param_text)
1475
1476             js_parameters_text = join(js_param_list, ", ")
1477
1478         response_cook_text = ""
1479         js_reply_list = "[]"
1480         if "returns" in json_command:
1481             method_out_code += "\n"
1482             for json_return in json_command["returns"]:
1483
1484                 json_return_name = json_return["name"]
1485                 raw_type = resolve_param_raw_type(json_return, domain_name)
1486                 setter_type = raw_type.get_setter_name()
1487                 initializer = raw_type.get_c_initializer()
1488                 var_type = raw_type.get_c_param_type(ParamType.OUTPUT, None)
1489
1490                 code = "    %s out_%s = %s;\n" % (var_type.get_text(), json_return_name, initializer)
1491                 param = ", &out_%s" % json_return_name
1492                 cook = "        result->set%s(\"%s\", out_%s);\n" % (setter_type, json_return_name, json_return_name)
1493                 if var_type.get_text() == "bool" and "optional" in json_return and json_return["optional"]:
1494                     cook = ("        if (out_%s)\n    " % json_return_name) + cook
1495
1496                 method_out_code += code
1497                 agent_call_param_list.append(param)
1498                 response_cook_list.append(cook)
1499
1500                 backend_js_reply_param_list.append("\"%s\"" % json_return_name)
1501
1502             js_reply_list = "[%s]" % join(backend_js_reply_param_list, ", ")
1503
1504             response_cook_text = "    if (!protocolErrors->length() && !error.length()) {\n%s    }\n" % join(response_cook_list, "")
1505
1506         Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None,
1507             domainName=domain_name, methodName=json_command_name,
1508             agentField="m_" + agent_field_name,
1509             methodInCode=method_in_code,
1510             methodOutCode=method_out_code,
1511             agentCallParams=join(agent_call_param_list, ""),
1512             requestMessageObject=request_message_param,
1513             responseCook=response_cook_text))
1514         Generator.backend_method_name_declaration_list.append("    \"%s.%s\"," % (domain_name, json_command_name))
1515
1516         Generator.backend_js_initializer_list.append("InspectorBackend.registerCommand(\"%s.%s\", [%s], %s);\n" % (domain_name, json_command_name, js_parameters_text, js_reply_list))
1517
1518     @staticmethod
1519     def process_types(type_map):
1520         output = Generator.type_builder_fragments
1521
1522         class ForwardListener:
1523             pass
1524
1525         for domain_data in type_map.domains():
1526             output.append("namespace ")
1527             output.append(domain_data.name())
1528             output.append(" {\n")
1529             for type_data in domain_data.types():
1530                 type_data.get_binding().generate_type_builder(output, ForwardListener)
1531
1532             output.append("} // ")
1533             output.append(domain_data.name())
1534             output.append("\n\n")
1535
1536 Generator.go()
1537
1538 backend_h_file = open(output_header_dirname + "/InspectorBackendDispatcher.h", "w")
1539 backend_cpp_file = open(output_cpp_dirname + "/InspectorBackendDispatcher.cpp", "w")
1540
1541 frontend_h_file = open(output_header_dirname + "/InspectorFrontend.h", "w")
1542 frontend_cpp_file = open(output_cpp_dirname + "/InspectorFrontend.cpp", "w")
1543
1544 backend_js_file = open(output_cpp_dirname + "/InspectorBackendStub.js", "w")
1545
1546
1547 frontend_h_file.write(Templates.frontend_h.substitute(None,
1548          fieldDeclarations=join(Generator.frontend_class_field_lines, ""),
1549          domainClassList=join(Generator.frontend_domain_class_lines, ""),
1550          typeBuilders=join(Generator.type_builder_fragments, "")))
1551
1552 backend_h_file.write(Templates.backend_h.substitute(None,
1553     constructorInit=join(Generator.backend_constructor_init_list, "\n"),
1554     setters=join(Generator.backend_setters_list, "\n"),
1555     methodNamesEnumContent=join(Generator.method_name_enum_list, "\n"),
1556     methodDeclarations=join(Generator.backend_method_declaration_list, "\n"),
1557     fieldDeclarations=join(Generator.backend_field_list, "\n"),
1558     forwardDeclarations=join(Generator.backend_forward_list, "\n")))
1559
1560 frontend_cpp_file.write(Templates.frontend_cpp.substitute(None,
1561     constructorInit=join(Generator.frontend_constructor_init_list, ""),
1562     methods=join(Generator.frontend_method_list, "\n")))
1563
1564 backend_cpp_file.write(Templates.backend_cpp.substitute(None,
1565     methodNameDeclarations=join(Generator.backend_method_name_declaration_list, "\n"),
1566     includes=join(Generator.backend_include_list, "\n"),
1567     methods=join(Generator.backend_method_implementation_list, "\n"),
1568     messageHandlers=join(Generator.method_handler_list, "\n")))
1569
1570 backend_js_file.write(Templates.backend_js.substitute(None,
1571     delegates=join(Generator.backend_js_initializer_list, ""),
1572     eventArgs=join(Generator.backend_js_event_list, ""),
1573     domainDispatchers=join(Generator.backend_js_domain_dispatcher_list, "")))
1574
1575 backend_h_file.close()
1576 backend_cpp_file.close()
1577
1578 frontend_h_file.close()
1579 frontend_cpp_file.close()
1580
1581 backend_js_file.close()