Web Inspector: CodeGeneratorInspector.py: use generated types in method parameters
[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                     @classmethod
509                     def get_in_c_type_text(cls, optional):
510                         return cls.reduce_to_raw_type().get_c_param_type(ParamType.EVENT, optional).get_text()
511
512                     @staticmethod
513                     def reduce_to_raw_type():
514                         return RawTypes.String
515
516                 return EnumBinding
517             else:
518
519                 class PlainString:
520                     @staticmethod
521                     def generate_type_builder(output, forward_listener):
522                         write_doc(output)
523                         fixed_type_name.output_comment(output)
524                         output.append("typedef String ")
525                         output.append(fixed_type_name.class_name)
526                         output.append(";\n\n")
527
528                     @staticmethod
529                     def reduce_to_raw_type():
530                         return RawTypes.String
531
532                     @classmethod
533                     def get_in_c_type_text(cls, optional):
534                         return cls.reduce_to_raw_type().get_c_param_type(ParamType.EVENT, optional).get_text()
535
536                 return PlainString
537
538         elif json_type["type"] == "object":
539             if "properties" in json_type:
540
541                 class ClassBinding:
542                     class_name_ = json_type["id"]
543
544                     @staticmethod
545                     def generate_type_builder(output, forward_listener):
546                         write_doc(output)
547                         class_name = fixed_type_name.class_name
548                         fixed_type_name.output_comment(output)
549                         output.append("class ")
550                         output.append(class_name)
551                         output.append(" : public InspectorObject {\n")
552                         output.append("public:\n")
553
554                         properties = json_type["properties"]
555                         main_properties = []
556                         optional_properties = []
557                         for p in properties:
558                             if "optional" in p and p["optional"]:
559                                 optional_properties.append(p)
560                             else:
561                                 main_properties.append(p)
562
563                         output.append(
564 """    enum {
565         NO_FIELDS_SET = 0,
566 """)
567
568                         state_enum_items = []
569                         if len(main_properties) > 0:
570                             pos = 0
571                             for p in main_properties:
572                                 item_name = Capitalizer.camel_case_to_capitalized_with_underscores(p["name"]) + "_SET"
573                                 state_enum_items.append(item_name)
574                                 output.append("        %s = 1 << %s,\n" % (item_name, pos))
575                                 pos += 1
576                             all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")"
577                         else:
578                             all_fields_set_value = "0"
579
580                         output.append(
581 """        ALL_FIELDS_SET = %s
582     };
583
584     template<int STATE>
585     class Builder {
586     private:
587         RefPtr<InspectorObject> m_result;
588
589         template<int STEP> Builder<STATE | STEP>& castState()
590         {
591             return *reinterpret_cast<Builder<STATE | STEP>*>(this);
592         }
593
594         Builder(PassRefPtr<%s> ptr)
595         {
596             COMPILE_ASSERT(STATE == NO_FIELDS_SET, builder_created_in_non_init_state);
597             m_result = ptr;
598         }
599         friend class %s;
600     public:
601 """ % (all_fields_set_value, class_name, class_name))
602
603                         pos = 0
604                         for prop in main_properties:
605                             prop_name = prop["name"]
606                             param_raw_type = resolve_param_raw_type(prop, context_domain_name)
607                             output.append("""
608         Builder<STATE | %s>& set%s(%s value)
609         {
610             COMPILE_ASSERT(!(STATE & %s), property_%s_already_set);
611             m_result->set%s("%s", value);
612             return castState<%s>();
613         }
614 """
615                             % (state_enum_items[pos],
616                                Capitalizer.lower_camel_case_to_upper(prop_name),
617                                param_raw_type.get_c_param_type(ParamType.TYPE_BUILDER_OUTPUT, False).get_text(),
618                                state_enum_items[pos], prop_name,
619                                param_raw_type.get_setter_name(), prop_name, state_enum_items[pos]))
620
621                             pos += 1
622
623                         output.append("""
624         operator RefPtr<%s>& ()
625         {
626             COMPILE_ASSERT(STATE == ALL_FIELDS_SET, result_is_not_ready);
627             return *reinterpret_cast<RefPtr<%s>*>(&m_result);
628         }
629
630         operator PassRefPtr<%s> ()
631         {
632             return RefPtr<%s>(*this);
633         }
634     };
635
636 """
637                         % (class_name, class_name, class_name, class_name))
638
639                         output.append("    /*\n")
640                         output.append("     * Synthetic constructor:\n")
641                         output.append("     * RefPtr<%s> result = %s::create()" % (class_name, class_name))
642                         for prop in main_properties:
643                             output.append("\n     *     .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop["name"]))
644                         output.append(";\n     */\n")
645
646                         output.append(
647 """    static Builder<NO_FIELDS_SET> create()
648     {
649         return Builder<NO_FIELDS_SET>(adoptRef(new %s()));
650     }
651 """ % class_name)
652
653                         for prop in optional_properties:
654                             param_raw_type = resolve_param_raw_type(prop, context_domain_name)
655                             setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop["name"])
656                             output.append("\n    void %s" % setter_name)
657                             output.append("(%s value)\n" % param_raw_type.get_c_param_type(ParamType.TYPE_BUILDER_OUTPUT, False).get_text())
658                             output.append("    {\n")
659                             output.append("        this->set%s(\"%s\", value);\n" % (param_raw_type.get_setter_name(), prop["name"]))
660                             output.append("    }\n")
661
662                             if setter_name in INSPECTOR_OBJECT_SETTER_NAMES:
663                                 output.append("    using InspectorObject::%s;\n\n" % setter_name)
664
665                         output.append("};\n\n")
666
667                     @classmethod
668                     def get_in_c_type_text(cls, optional):
669                         return "PassRefPtr<TypeBuilder::" + context_domain_name + "::" + cls.class_name_ + ">"
670
671                     @staticmethod
672                     def reduce_to_raw_type():
673                         return RawTypes.Object
674
675                         output.append("};\n\n")
676                 return ClassBinding
677             else:
678
679                 class PlainObjectBinding:
680                     @staticmethod
681                     def generate_type_builder(output, forward_listener):
682                         # No-op
683                         pass
684
685                     @classmethod
686                     def get_in_c_type_text(cls, optional):
687                         return cls.reduce_to_raw_type().get_c_param_type(ParamType.EVENT, optional).get_text()
688
689                     @staticmethod
690                     def reduce_to_raw_type():
691                         return RawTypes.Object
692
693                 return PlainObjectBinding
694         else:
695             raw_type = RawTypes.get(json_type["type"])
696
697             class RawTypesBinding:
698                 @staticmethod
699                 def generate_type_builder(output, forward_listener):
700                     # No-op
701                     pass
702
703                 @classmethod
704                 def get_in_c_type_text(cls, optional):
705                     return cls.reduce_to_raw_type().get_c_param_type(ParamType.EVENT, optional).get_text()
706
707                 @staticmethod
708                 def reduce_to_raw_type():
709                     return raw_type
710
711             return RawTypesBinding
712
713
714 class TypeData(object):
715     def __init__(self, json_type, json_domain, domain_data):
716         self.json_type_ = json_type
717         self.json_domain_ = json_domain
718         self.domain_data_ = domain_data
719
720         if "type" not in json_type:
721             raise Exception("Unknown type")
722
723         json_type_name = json_type["type"]
724         raw_type = RawTypes.get(json_type_name)
725         self.raw_type_ = raw_type
726         self.binding_ = TypeBindings.create_for_named_type_declaration(json_type, json_domain["domain"])
727
728     def get_raw_type(self):
729         return self.raw_type_
730
731     def get_binding(self):
732         return self.binding_
733
734
735 class DomainData:
736     def __init__(self, json_domain):
737         self.json_domain = json_domain
738         self.types_ = []
739
740     def add_type(self, type_data):
741         self.types_.append(type_data)
742
743     def name(self):
744         return self.json_domain["domain"]
745
746     def types(self):
747         return self.types_
748
749
750 class TypeMap:
751     def __init__(self, api):
752         self.map_ = {}
753         self.domains_ = []
754         for json_domain in api["domains"]:
755             domain_name = json_domain["domain"]
756
757             domain_map = {}
758             self.map_[domain_name] = domain_map
759
760             domain_data = DomainData(json_domain)
761             self.domains_.append(domain_data)
762
763             if "types" in json_domain:
764                 for json_type in json_domain["types"]:
765                     type_name = json_type["id"]
766                     type_data = TypeData(json_type, json_domain, domain_data)
767                     domain_map[type_name] = type_data
768                     domain_data.add_type(type_data)
769
770     def domains(self):
771         return self.domains_
772
773     def get(self, domain_name, type_name):
774         return self.map_[domain_name][type_name]
775
776
777 def resolve_param_type(json_parameter, scope_domain_name):
778     if "$ref" in json_parameter:
779         json_ref = json_parameter["$ref"]
780         type_data = get_ref_data(json_ref, scope_domain_name)
781         return type_data.get_binding()
782     elif "type" in json_parameter:
783         json_type = json_parameter["type"]
784         raw_type = RawTypes.get(json_type)
785
786         class RawTypeBinding:
787             @staticmethod
788             def reduce_to_raw_type():
789                 return raw_type
790
791             @staticmethod
792             def get_in_c_type_text(optional):
793                 return raw_type.get_c_param_type(ParamType.EVENT, optional).get_text()
794
795         return RawTypeBinding
796     else:
797         raise Exception("Unknown type")
798
799 def resolve_param_raw_type(json_parameter, scope_domain_name):
800     if "$ref" in json_parameter:
801         json_ref = json_parameter["$ref"]
802         type_data = get_ref_data(json_ref, scope_domain_name)
803         return type_data.get_raw_type()
804     elif "type" in json_parameter:
805         json_type = json_parameter["type"]
806         return RawTypes.get(json_type)
807     else:
808         raise Exception("Unknown type")
809
810
811 def get_ref_data(json_ref, scope_domain_name):
812     dot_pos = json_ref.find(".")
813     if dot_pos == -1:
814         domain_name = scope_domain_name
815         type_name = json_ref
816     else:
817         domain_name = json_ref[:dot_pos]
818         type_name = json_ref[dot_pos + 1:]
819
820     return type_map.get(domain_name, type_name)
821
822
823 input_file = open(input_json_filename, "r")
824 json_string = input_file.read()
825 json_api = json.loads(json_string)
826
827
828 class Templates:
829     def get_this_script_path_(absolute_path):
830         absolute_path = os.path.abspath(absolute_path)
831         components = []
832
833         def fill_recursive(path_part, depth):
834             if depth <= 0 or path_part == '/':
835                 return
836             fill_recursive(os.path.dirname(path_part), depth - 1)
837             components.append(os.path.basename(path_part))
838
839         # Typical path is /Source/WebCore/inspector/CodeGeneratorInspector.py
840         # Let's take 4 components from the real path then.
841         fill_recursive(absolute_path, 4)
842
843         return "/".join(components)
844
845     file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) +
846 """// Copyright (c) 2011 The Chromium Authors. All rights reserved.
847 // Use of this source code is governed by a BSD-style license that can be
848 // found in the LICENSE file.
849 """)
850
851
852
853     frontend_domain_class = string.Template(
854 """    class $domainClassName {
855     public:
856         $domainClassName(InspectorFrontendChannel* inspectorFrontendChannel) : m_inspectorFrontendChannel(inspectorFrontendChannel) { }
857 ${frontendDomainMethodDeclarations}        void setInspectorFrontendChannel(InspectorFrontendChannel* inspectorFrontendChannel) { m_inspectorFrontendChannel = inspectorFrontendChannel; }
858         InspectorFrontendChannel* getInspectorFrontendChannel() { return m_inspectorFrontendChannel; }
859     private:
860         InspectorFrontendChannel* m_inspectorFrontendChannel;
861     };
862
863     $domainClassName* $domainFieldName() { return &m_$domainFieldName; }
864
865 """)
866
867     backend_method = string.Template(
868 """void InspectorBackendDispatcher::${domainName}_$methodName(long callId, InspectorObject*$requestMessageObject)
869 {
870     RefPtr<InspectorArray> protocolErrors = InspectorArray::create();
871
872     if (!$agentField)
873         protocolErrors->pushString("${domainName} handler is not available.");
874 $methodOutCode
875     ErrorString error;
876 $methodInCode
877     if (!protocolErrors->length())
878         $agentField->$methodName(&error$agentCallParams);
879
880     RefPtr<InspectorObject> result = InspectorObject::create();
881 ${responseCook}    sendResponse(callId, result, String::format("Some arguments of method '%s' can't be processed", "$domainName.$methodName"), protocolErrors, error);
882 }
883 """)
884
885     frontend_method = string.Template("""void InspectorFrontend::$domainName::$eventName($parameters)
886 {
887     RefPtr<InspectorObject> ${eventName}Message = InspectorObject::create();
888     ${eventName}Message->setString("method", "$domainName.$eventName");
889 $code    if (m_inspectorFrontendChannel)
890         m_inspectorFrontendChannel->sendMessageToFrontend(${eventName}Message->toJSONString());
891 }
892 """)
893
894     frontend_h = string.Template(file_header_ +
895 """#ifndef InspectorFrontend_h
896 #define InspectorFrontend_h
897
898 #include "InspectorValues.h"
899 #include <PlatformString.h>
900 #include <wtf/PassRefPtr.h>
901
902 namespace WebCore {
903
904 class InspectorFrontendChannel;
905
906 // Both InspectorObject and InspectorArray may or may not be declared at this point as defined by ENABLED_INSPECTOR.
907 // Double-check we have them at least as forward declaration.
908 class InspectorArray;
909 class InspectorObject;
910
911 typedef String ErrorString;
912
913 #if ENABLE(INSPECTOR)
914
915 namespace TypeBuilder {
916 ${typeBuilders}
917 } // namespace TypeBuilder
918
919 #endif // ENABLE(INSPECTOR)
920
921 class InspectorFrontend {
922 public:
923     InspectorFrontend(InspectorFrontendChannel*);
924
925
926 $domainClassList
927 private:
928     InspectorFrontendChannel* m_inspectorFrontendChannel;
929 ${fieldDeclarations}};
930
931 } // namespace WebCore
932 #endif // !defined(InspectorFrontend_h)
933 """)
934
935     backend_h = string.Template(file_header_ +
936 """#ifndef InspectorBackendDispatcher_h
937 #define InspectorBackendDispatcher_h
938
939 #include <wtf/PassRefPtr.h>
940 #include <wtf/RefCounted.h>
941 #include <wtf/text/WTFString.h>
942
943 namespace WebCore {
944
945 class InspectorAgent;
946 class InspectorObject;
947 class InspectorArray;
948 class InspectorFrontendChannel;
949
950 $forwardDeclarations
951
952 typedef String ErrorString;
953
954 class InspectorBackendDispatcher: public RefCounted<InspectorBackendDispatcher> {
955 public:
956     InspectorBackendDispatcher(InspectorFrontendChannel* inspectorFrontendChannel)
957         : m_inspectorFrontendChannel(inspectorFrontendChannel)
958 $constructorInit
959     { }
960
961 $setters
962
963     void clearFrontend() { m_inspectorFrontendChannel = 0; }
964
965     enum CommonErrorCode {
966         ParseError = 0,
967         InvalidRequest,
968         MethodNotFound,
969         InvalidParams,
970         InternalError,
971         ServerError,
972         LastEntry,
973     };
974
975     void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage) const;
976     void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage, PassRefPtr<InspectorArray> data) const;
977     void dispatch(const String& message);
978     static bool getCommandName(const String& message, String* result);
979
980     enum MethodNames {
981 $methodNamesEnumContent
982 };
983
984     static const char* commandNames[];
985
986 private:
987     static int getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
988     static String getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
989     static bool getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
990     static PassRefPtr<InspectorObject> getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
991     static PassRefPtr<InspectorArray> getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
992     void sendResponse(long callId, PassRefPtr<InspectorObject> result, const String& errorMessage, PassRefPtr<InspectorArray> protocolErrors, ErrorString invocationError);
993
994 $methodDeclarations
995
996     InspectorFrontendChannel* m_inspectorFrontendChannel;
997 $fieldDeclarations
998 };
999
1000 } // namespace WebCore
1001 #endif // !defined(InspectorBackendDispatcher_h)
1002
1003
1004 """)
1005
1006     backend_cpp = string.Template(file_header_ +
1007 """
1008
1009 #include "config.h"
1010 #include "InspectorBackendDispatcher.h"
1011 #include <wtf/text/WTFString.h>
1012 #include <wtf/text/CString.h>
1013
1014 #if ENABLE(INSPECTOR)
1015
1016 #include "InspectorAgent.h"
1017 #include "InspectorValues.h"
1018 #include "InspectorFrontendChannel.h"
1019 #include <wtf/text/WTFString.h>
1020 $includes
1021
1022 namespace WebCore {
1023
1024 const char* InspectorBackendDispatcher::commandNames[] = {
1025 $methodNameDeclarations
1026 };
1027
1028
1029 $methods
1030 void InspectorBackendDispatcher::dispatch(const String& message)
1031 {
1032     RefPtr<InspectorBackendDispatcher> protect = this;
1033     typedef void (InspectorBackendDispatcher::*CallHandler)(long callId, InspectorObject* messageObject);
1034     typedef HashMap<String, CallHandler> DispatchMap;
1035     DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, );
1036     long callId = 0;
1037
1038     if (dispatchMap.isEmpty()) {
1039         static CallHandler handlers[] = {
1040 $messageHandlers
1041         };
1042         size_t length = sizeof(commandNames) / sizeof(commandNames[0]);
1043         for (size_t i = 0; i < length; ++i)
1044             dispatchMap.add(commandNames[i], handlers[i]);
1045     }
1046
1047     RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
1048     if (!parsedMessage) {
1049         reportProtocolError(0, ParseError, "Message must be in JSON format");
1050         return;
1051     }
1052
1053     RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
1054     if (!messageObject) {
1055         reportProtocolError(0, InvalidRequest, "Message must be a JSONified object");
1056         return;
1057     }
1058
1059     RefPtr<InspectorValue> callIdValue = messageObject->get("id");
1060     if (!callIdValue) {
1061         reportProtocolError(0, InvalidRequest, "'id' property was not found");
1062         return;
1063     }
1064
1065     if (!callIdValue->asNumber(&callId)) {
1066         reportProtocolError(0, InvalidRequest, "The type of 'id' property must be number");
1067         return;
1068     }
1069
1070     RefPtr<InspectorValue> methodValue = messageObject->get("method");
1071     if (!methodValue) {
1072         reportProtocolError(&callId, InvalidRequest, "'method' property wasn't found");
1073         return;
1074     }
1075
1076     String method;
1077     if (!methodValue->asString(&method)) {
1078         reportProtocolError(&callId, InvalidRequest, "The type of 'method' property must be string");
1079         return;
1080     }
1081
1082     HashMap<String, CallHandler>::iterator it = dispatchMap.find(method);
1083     if (it == dispatchMap.end()) {
1084         reportProtocolError(&callId, MethodNotFound, "'" + method + "' wasn't found");
1085         return;
1086     }
1087
1088     ((*this).*it->second)(callId, messageObject.get());
1089 }
1090
1091 void InspectorBackendDispatcher::sendResponse(long callId, PassRefPtr<InspectorObject> result, const String& errorMessage, PassRefPtr<InspectorArray> protocolErrors, ErrorString invocationError)
1092 {
1093     if (protocolErrors->length()) {
1094         reportProtocolError(&callId, InvalidParams, errorMessage, protocolErrors);
1095         return;
1096     }
1097     if (invocationError.length()) {
1098         reportProtocolError(&callId, ServerError, invocationError);
1099         return;
1100     }
1101
1102     RefPtr<InspectorObject> responseMessage = InspectorObject::create();
1103     responseMessage->setObject("result", result);
1104     responseMessage->setNumber("id", callId);
1105     if (m_inspectorFrontendChannel)
1106         m_inspectorFrontendChannel->sendMessageToFrontend(responseMessage->toJSONString());
1107 }
1108
1109 void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode code, const String& errorMessage) const
1110 {
1111     reportProtocolError(callId, code, errorMessage, 0);
1112 }
1113
1114 void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<InspectorArray> data) const
1115 {
1116     DEFINE_STATIC_LOCAL(Vector<int>,s_commonErrors,);
1117     if (!s_commonErrors.size()) {
1118         s_commonErrors.insert(ParseError, -32700);
1119         s_commonErrors.insert(InvalidRequest, -32600);
1120         s_commonErrors.insert(MethodNotFound, -32601);
1121         s_commonErrors.insert(InvalidParams, -32602);
1122         s_commonErrors.insert(InternalError, -32603);
1123         s_commonErrors.insert(ServerError, -32000);
1124     }
1125     ASSERT(code >=0);
1126     ASSERT((unsigned)code < s_commonErrors.size());
1127     ASSERT(s_commonErrors[code]);
1128     RefPtr<InspectorObject> error = InspectorObject::create();
1129     error->setNumber("code", s_commonErrors[code]);
1130     error->setString("message", errorMessage);
1131     ASSERT(error);
1132     if (data)
1133         error->setArray("data", data);
1134     RefPtr<InspectorObject> message = InspectorObject::create();
1135     message->setObject("error", error);
1136     if (callId)
1137         message->setNumber("id", *callId);
1138     else
1139         message->setValue("id", InspectorValue::null());
1140     if (m_inspectorFrontendChannel)
1141         m_inspectorFrontendChannel->sendMessageToFrontend(message->toJSONString());
1142 }
1143
1144 int InspectorBackendDispatcher::getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1145 {
1146     ASSERT(protocolErrors);
1147
1148     if (valueFound)
1149         *valueFound = false;
1150
1151     int value = 0;
1152
1153     if (!object) {
1154         if (!valueFound) {
1155             // Required parameter in missing params container.
1156             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Number'.", name.utf8().data()));
1157         }
1158         return value;
1159     }
1160
1161     InspectorObject::const_iterator end = object->end();
1162     InspectorObject::const_iterator valueIterator = object->find(name);
1163
1164     if (valueIterator == end) {
1165         if (!valueFound)
1166             protocolErrors->pushString(String::format("Parameter '%s' with type 'Number' was not found.", name.utf8().data()));
1167         return value;
1168     }
1169
1170     if (!valueIterator->second->asNumber(&value))
1171         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Number'.", name.utf8().data()));
1172     else
1173         if (valueFound)
1174             *valueFound = true;
1175     return value;
1176 }
1177
1178 String InspectorBackendDispatcher::getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1179 {
1180     ASSERT(protocolErrors);
1181
1182     if (valueFound)
1183         *valueFound = false;
1184
1185     String value = "";
1186
1187     if (!object) {
1188         if (!valueFound) {
1189             // Required parameter in missing params container.
1190             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'String'.", name.utf8().data()));
1191         }
1192         return value;
1193     }
1194
1195     InspectorObject::const_iterator end = object->end();
1196     InspectorObject::const_iterator valueIterator = object->find(name);
1197
1198     if (valueIterator == end) {
1199         if (!valueFound)
1200             protocolErrors->pushString(String::format("Parameter '%s' with type 'String' was not found.", name.utf8().data()));
1201         return value;
1202     }
1203
1204     if (!valueIterator->second->asString(&value))
1205         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'String'.", name.utf8().data()));
1206     else
1207         if (valueFound)
1208             *valueFound = true;
1209     return value;
1210 }
1211
1212 bool InspectorBackendDispatcher::getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1213 {
1214     ASSERT(protocolErrors);
1215
1216     if (valueFound)
1217         *valueFound = false;
1218
1219     bool value = false;
1220
1221     if (!object) {
1222         if (!valueFound) {
1223             // Required parameter in missing params container.
1224             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Boolean'.", name.utf8().data()));
1225         }
1226         return value;
1227     }
1228
1229     InspectorObject::const_iterator end = object->end();
1230     InspectorObject::const_iterator valueIterator = object->find(name);
1231
1232     if (valueIterator == end) {
1233         if (!valueFound)
1234             protocolErrors->pushString(String::format("Parameter '%s' with type 'Boolean' was not found.", name.utf8().data()));
1235         return value;
1236     }
1237
1238     if (!valueIterator->second->asBoolean(&value))
1239         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Boolean'.", name.utf8().data()));
1240     else
1241         if (valueFound)
1242             *valueFound = true;
1243     return value;
1244 }
1245
1246 PassRefPtr<InspectorObject> InspectorBackendDispatcher::getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1247 {
1248     ASSERT(protocolErrors);
1249
1250     if (valueFound)
1251         *valueFound = false;
1252
1253     RefPtr<InspectorObject> value = InspectorObject::create();
1254
1255     if (!object) {
1256         if (!valueFound) {
1257             // Required parameter in missing params container.
1258             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Object'.", name.utf8().data()));
1259         }
1260         return value;
1261     }
1262
1263     InspectorObject::const_iterator end = object->end();
1264     InspectorObject::const_iterator valueIterator = object->find(name);
1265
1266     if (valueIterator == end) {
1267         if (!valueFound)
1268             protocolErrors->pushString(String::format("Parameter '%s' with type 'Object' was not found.", name.utf8().data()));
1269         return value;
1270     }
1271
1272     if (!valueIterator->second->asObject(&value))
1273         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Object'.", name.utf8().data()));
1274     else
1275         if (valueFound)
1276             *valueFound = true;
1277     return value;
1278 }
1279
1280 PassRefPtr<InspectorArray> InspectorBackendDispatcher::getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
1281 {
1282     ASSERT(protocolErrors);
1283
1284     if (valueFound)
1285         *valueFound = false;
1286
1287     RefPtr<InspectorArray> value = InspectorArray::create();
1288
1289     if (!object) {
1290         if (!valueFound) {
1291             // Required parameter in missing params container.
1292             protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type 'Array'.", name.utf8().data()));
1293         }
1294         return value;
1295     }
1296
1297     InspectorObject::const_iterator end = object->end();
1298     InspectorObject::const_iterator valueIterator = object->find(name);
1299
1300     if (valueIterator == end) {
1301         if (!valueFound)
1302             protocolErrors->pushString(String::format("Parameter '%s' with type 'Array' was not found.", name.utf8().data()));
1303         return value;
1304     }
1305
1306     if (!valueIterator->second->asArray(&value))
1307         protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be 'Array'.", name.utf8().data()));
1308     else
1309         if (valueFound)
1310             *valueFound = true;
1311     return value;
1312 }
1313 bool InspectorBackendDispatcher::getCommandName(const String& message, String* result)
1314 {
1315     RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
1316     if (!value)
1317         return false;
1318
1319     RefPtr<InspectorObject> object = value->asObject();
1320     if (!object)
1321         return false;
1322
1323     if (!object->getString("method", result))
1324         return false;
1325
1326     return true;
1327 }
1328
1329
1330 } // namespace WebCore
1331
1332 #endif // ENABLE(INSPECTOR)
1333 """)
1334
1335     frontend_cpp = string.Template(file_header_ +
1336 """
1337
1338 #include "config.h"
1339 #include "InspectorFrontend.h"
1340 #include <wtf/text/WTFString.h>
1341 #include <wtf/text/CString.h>
1342
1343 #if ENABLE(INSPECTOR)
1344
1345 #include "InspectorFrontendChannel.h"
1346 #include "InspectorValues.h"
1347 #include <wtf/text/WTFString.h>
1348
1349 namespace WebCore {
1350
1351 InspectorFrontend::InspectorFrontend(InspectorFrontendChannel* inspectorFrontendChannel)
1352     : m_inspectorFrontendChannel(inspectorFrontendChannel)
1353 $constructorInit{
1354 }
1355
1356 $methods
1357
1358 } // namespace WebCore
1359
1360 #endif // ENABLE(INSPECTOR)
1361 """)
1362
1363     backend_js = string.Template(file_header_ +
1364 """
1365
1366 $domainInitializers
1367 """)
1368
1369     param_container_access_code = """
1370     RefPtr<InspectorObject> paramsContainer = requestMessageObject->getObject("params");
1371     InspectorObject* paramsContainerPtr = paramsContainer.get();
1372     InspectorArray* protocolErrorsPtr = protocolErrors.get();
1373 """
1374
1375
1376 type_map = TypeMap(json_api)
1377
1378
1379 def get_annotated_type_text(raw_type, annotated_type):
1380     if annotated_type != raw_type:
1381         return "/*%s*/ %s" % (annotated_type, raw_type)
1382     else:
1383         return raw_type
1384
1385 class Generator:
1386     frontend_class_field_lines = []
1387     frontend_domain_class_lines = []
1388
1389     method_name_enum_list = []
1390     backend_method_declaration_list = []
1391     backend_method_implementation_list = []
1392     backend_method_name_declaration_list = []
1393     method_handler_list = []
1394     frontend_method_list = []
1395     backend_js_domain_initializer_list = []
1396
1397     backend_setters_list = []
1398     backend_constructor_init_list = []
1399     backend_field_list = []
1400     backend_forward_list = []
1401     backend_include_list = []
1402     frontend_constructor_init_list = []
1403     type_builder_fragments = []
1404
1405     @staticmethod
1406     def go():
1407         Generator.process_types(type_map)
1408
1409         first_cycle_guardable_list_list = [
1410             Generator.backend_method_declaration_list,
1411             Generator.backend_method_implementation_list,
1412             Generator.backend_method_name_declaration_list,
1413             Generator.frontend_class_field_lines,
1414             Generator.frontend_constructor_init_list,
1415             Generator.frontend_domain_class_lines,
1416             Generator.frontend_method_list,
1417             Generator.method_handler_list,
1418             Generator.method_name_enum_list]
1419
1420         for json_domain in json_api["domains"]:
1421             domain_name = json_domain["domain"]
1422             domain_name_lower = domain_name.lower()
1423
1424             domain_fixes = DomainNameFixes.get_fixed_data(domain_name)
1425
1426             domain_guard = domain_fixes.get_guard()
1427
1428             if domain_guard:
1429                 for l in first_cycle_guardable_list_list:
1430                     domain_guard.generate_open(l)
1431
1432             agent_field_name = domain_fixes.agent_field_name
1433
1434             frontend_method_declaration_lines = []
1435
1436             Generator.backend_js_domain_initializer_list.append("// %s.\n" % domain_name)
1437
1438             if not domain_fixes.skip_js_bind:
1439                 Generator.backend_js_domain_initializer_list.append("InspectorBackend.register%sDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"%s\");\n" % (domain_name, domain_name))
1440
1441             if "events" in json_domain:
1442                 for json_event in json_domain["events"]:
1443                     Generator.process_event(json_event, domain_name, frontend_method_declaration_lines)
1444
1445             Generator.frontend_class_field_lines.append("    %s m_%s;\n" % (domain_name, domain_name_lower))
1446             Generator.frontend_constructor_init_list.append("    , m_%s(inspectorFrontendChannel)\n" % domain_name_lower)
1447             Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None,
1448                 domainClassName=domain_name,
1449                 domainFieldName=domain_name_lower,
1450                 frontendDomainMethodDeclarations=join(frontend_method_declaration_lines, "")))
1451
1452             if "commands" in json_domain:
1453                 for json_command in json_domain["commands"]:
1454                     Generator.process_command(json_command, domain_name, agent_field_name)
1455
1456             if domain_guard:
1457                 for l in reversed(first_cycle_guardable_list_list):
1458                     domain_guard.generate_close(l)
1459             Generator.backend_js_domain_initializer_list.append("\n")
1460
1461         sorted_json_domains = list(json_api["domains"])
1462         sorted_json_domains.sort(key=lambda o: o["domain"])
1463
1464         sorted_cycle_guardable_list_list = [
1465             Generator.backend_constructor_init_list,
1466             Generator.backend_setters_list,
1467             Generator.backend_field_list,
1468             Generator.backend_forward_list,
1469             Generator.backend_include_list]
1470
1471         for json_domain in sorted_json_domains:
1472             domain_name = json_domain["domain"]
1473
1474             domain_fixes = DomainNameFixes.get_fixed_data(domain_name)
1475             domain_guard = domain_fixes.get_guard()
1476
1477             if domain_guard:
1478                 for l in sorted_cycle_guardable_list_list:
1479                     domain_guard.generate_open(l)
1480
1481             agent_type_name = domain_fixes.agent_type_name
1482             agent_field_name = domain_fixes.agent_field_name
1483             Generator.backend_constructor_init_list.append("        , m_%s(0)" % agent_field_name)
1484             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))
1485             Generator.backend_field_list.append("    %s* m_%s;" % (agent_type_name, agent_field_name))
1486             Generator.backend_forward_list.append("class %s;" % agent_type_name)
1487             Generator.backend_include_list.append("#include \"%s.h\"" % agent_type_name)
1488
1489             if domain_guard:
1490                 for l in reversed(sorted_cycle_guardable_list_list):
1491                     domain_guard.generate_close(l)
1492
1493     @staticmethod
1494     def process_event(json_event, domain_name, frontend_method_declaration_lines):
1495         event_name = json_event["name"]
1496         parameter_list = []
1497         method_line_list = []
1498         backend_js_event_param_list = []
1499         if "parameters" in json_event:
1500             method_line_list.append("    RefPtr<InspectorObject> paramsObject = InspectorObject::create();\n")
1501             for json_parameter in json_event["parameters"]:
1502                 parameter_name = json_parameter["name"]
1503
1504                 raw_type = resolve_param_raw_type(json_parameter, domain_name)
1505
1506                 json_optional = "optional" in json_parameter and json_parameter["optional"]
1507
1508                 optional_mask = raw_type.is_event_param_check_optional()
1509                 c_type = raw_type.get_c_param_type(ParamType.EVENT, json_optional)
1510
1511                 setter_type = raw_type.get_setter_name()
1512
1513                 optional = optional_mask and json_optional
1514
1515                 param_type_binding = resolve_param_type(json_parameter, domain_name)
1516
1517                 annotated_type = get_annotated_type_text(c_type.get_text(), param_type_binding.get_in_c_type_text(json_optional))
1518
1519                 parameter_list.append("%s %s" % (annotated_type, parameter_name))
1520
1521                 setter_argument = c_type.get_setter_format() % parameter_name
1522
1523                 setter_code = "    paramsObject->set%s(\"%s\", %s);\n" % (setter_type, parameter_name, setter_argument)
1524                 if optional:
1525                     setter_code = ("    if (%s)\n    " % parameter_name) + setter_code
1526                 method_line_list.append(setter_code)
1527
1528                 backend_js_event_param_list.append("\"%s\"" % parameter_name)
1529             method_line_list.append("    %sMessage->setObject(\"params\", paramsObject);\n" % event_name)
1530         frontend_method_declaration_lines.append(
1531             "        void %s(%s);\n" % (event_name, join(parameter_list, ", ")))
1532
1533         Generator.frontend_method_list.append(Templates.frontend_method.substitute(None,
1534             domainName=domain_name, eventName=event_name,
1535             parameters=join(parameter_list, ", "),
1536             code=join(method_line_list, "")))
1537
1538         Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerEvent(\"%s.%s\", [%s]);\n" % (
1539             domain_name, event_name, join(backend_js_event_param_list, ", ")))
1540
1541     @staticmethod
1542     def process_command(json_command, domain_name, agent_field_name):
1543         json_command_name = json_command["name"]
1544         Generator.method_name_enum_list.append("        k%s_%sCmd," % (domain_name, json_command["name"]))
1545         Generator.method_handler_list.append("            &InspectorBackendDispatcher::%s_%s," % (domain_name, json_command_name))
1546         Generator.backend_method_declaration_list.append("    void %s_%s(long callId, InspectorObject* requestMessageObject);" % (domain_name, json_command_name))
1547
1548         method_in_code = ""
1549         method_out_code = ""
1550         agent_call_param_list = []
1551         response_cook_list = []
1552         backend_js_reply_param_list = []
1553         request_message_param = ""
1554         js_parameters_text = ""
1555         if "parameters" in json_command:
1556             json_params = json_command["parameters"]
1557             method_in_code += Templates.param_container_access_code
1558             request_message_param = " requestMessageObject"
1559             js_param_list = []
1560
1561             for json_parameter in json_params:
1562                 json_param_name = json_parameter["name"]
1563                 param_raw_type = resolve_param_raw_type(json_parameter, domain_name)
1564
1565                 var_type = param_raw_type.get_c_param_type(ParamType.INPUT, None)
1566                 getter_name = param_raw_type.get_getter_name()
1567
1568                 if "optional" in json_parameter and json_parameter["optional"]:
1569                     code = ("    bool %s_valueFound = false;\n"
1570                             "    %s in_%s = get%s(paramsContainerPtr, \"%s\", &%s_valueFound, protocolErrorsPtr);\n" %
1571                            (json_param_name, var_type.get_text(), json_param_name, getter_name, json_param_name, json_param_name))
1572                     param = ", %s_valueFound ? &in_%s : 0" % (json_param_name, json_param_name)
1573                 else:
1574                     code = ("    %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrorsPtr);\n" %
1575                             (var_type.get_text(), json_param_name, getter_name, json_param_name))
1576                     param = ", in_%s" % json_param_name
1577
1578                 method_in_code += code
1579                 agent_call_param_list.append(param)
1580
1581                 js_bind_type = param_raw_type.get_js_bind_type()
1582                 js_param_text = "{\"name\": \"%s\", \"type\": \"%s\", \"optional\": %s}" % (
1583                     json_param_name,
1584                     js_bind_type,
1585                     ("true" if ("optional" in json_parameter and json_parameter["optional"]) else "false"))
1586
1587                 js_param_list.append(js_param_text)
1588
1589             js_parameters_text = join(js_param_list, ", ")
1590
1591         response_cook_text = ""
1592         js_reply_list = "[]"
1593         if "returns" in json_command:
1594             method_out_code += "\n"
1595             for json_return in json_command["returns"]:
1596
1597                 json_return_name = json_return["name"]
1598                 raw_type = resolve_param_raw_type(json_return, domain_name)
1599                 setter_type = raw_type.get_setter_name()
1600                 initializer = raw_type.get_c_initializer()
1601                 var_type = raw_type.get_c_param_type(ParamType.OUTPUT, None)
1602
1603                 code = "    %s out_%s = %s;\n" % (var_type.get_text(), json_return_name, initializer)
1604                 param = ", &out_%s" % json_return_name
1605                 cook = "        result->set%s(\"%s\", out_%s);\n" % (setter_type, json_return_name, json_return_name)
1606                 if var_type.get_text() == "bool" and "optional" in json_return and json_return["optional"]:
1607                     cook = ("        if (out_%s)\n    " % json_return_name) + cook
1608
1609                 method_out_code += code
1610                 agent_call_param_list.append(param)
1611                 response_cook_list.append(cook)
1612
1613                 backend_js_reply_param_list.append("\"%s\"" % json_return_name)
1614
1615             js_reply_list = "[%s]" % join(backend_js_reply_param_list, ", ")
1616
1617             response_cook_text = "    if (!protocolErrors->length() && !error.length()) {\n%s    }\n" % join(response_cook_list, "")
1618
1619         Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None,
1620             domainName=domain_name, methodName=json_command_name,
1621             agentField="m_" + agent_field_name,
1622             methodInCode=method_in_code,
1623             methodOutCode=method_out_code,
1624             agentCallParams=join(agent_call_param_list, ""),
1625             requestMessageObject=request_message_param,
1626             responseCook=response_cook_text))
1627         Generator.backend_method_name_declaration_list.append("    \"%s.%s\"," % (domain_name, json_command_name))
1628
1629         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))
1630
1631     @staticmethod
1632     def process_types(type_map):
1633         output = Generator.type_builder_fragments
1634
1635         class ForwardListener:
1636             pass
1637
1638         for domain_data in type_map.domains():
1639
1640             domain_fixes = DomainNameFixes.get_fixed_data(domain_data.name())
1641             domain_guard = domain_fixes.get_guard()
1642
1643             if domain_guard:
1644                 domain_guard.generate_open(output)
1645
1646             output.append("namespace ")
1647             output.append(domain_data.name())
1648             output.append(" {\n")
1649             for type_data in domain_data.types():
1650                 type_data.get_binding().generate_type_builder(output, ForwardListener)
1651
1652             output.append("} // ")
1653             output.append(domain_data.name())
1654             output.append("\n\n")
1655
1656             if domain_guard:
1657                 domain_guard.generate_close(output)
1658
1659 Generator.go()
1660
1661 backend_h_file = open(output_header_dirname + "/InspectorBackendDispatcher.h", "w")
1662 backend_cpp_file = open(output_cpp_dirname + "/InspectorBackendDispatcher.cpp", "w")
1663
1664 frontend_h_file = open(output_header_dirname + "/InspectorFrontend.h", "w")
1665 frontend_cpp_file = open(output_cpp_dirname + "/InspectorFrontend.cpp", "w")
1666
1667 backend_js_file = open(output_cpp_dirname + "/InspectorBackendStub.js", "w")
1668
1669
1670 frontend_h_file.write(Templates.frontend_h.substitute(None,
1671          fieldDeclarations=join(Generator.frontend_class_field_lines, ""),
1672          domainClassList=join(Generator.frontend_domain_class_lines, ""),
1673          typeBuilders=join(Generator.type_builder_fragments, "")))
1674
1675 backend_h_file.write(Templates.backend_h.substitute(None,
1676     constructorInit=join(Generator.backend_constructor_init_list, "\n"),
1677     setters=join(Generator.backend_setters_list, "\n"),
1678     methodNamesEnumContent=join(Generator.method_name_enum_list, "\n"),
1679     methodDeclarations=join(Generator.backend_method_declaration_list, "\n"),
1680     fieldDeclarations=join(Generator.backend_field_list, "\n"),
1681     forwardDeclarations=join(Generator.backend_forward_list, "\n")))
1682
1683 frontend_cpp_file.write(Templates.frontend_cpp.substitute(None,
1684     constructorInit=join(Generator.frontend_constructor_init_list, ""),
1685     methods=join(Generator.frontend_method_list, "\n")))
1686
1687 backend_cpp_file.write(Templates.backend_cpp.substitute(None,
1688     methodNameDeclarations=join(Generator.backend_method_name_declaration_list, "\n"),
1689     includes=join(Generator.backend_include_list, "\n"),
1690     methods=join(Generator.backend_method_implementation_list, "\n"),
1691     messageHandlers=join(Generator.method_handler_list, "\n")))
1692
1693 backend_js_file.write(Templates.backend_js.substitute(None,
1694     domainInitializers=join(Generator.backend_js_domain_initializer_list, "")))
1695
1696 backend_h_file.close()
1697 backend_cpp_file.close()
1698
1699 frontend_h_file.close()
1700 frontend_cpp_file.close()
1701
1702 backend_js_file.close()