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