Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: third_party/WebKit/Source/platform/inspector_protocol/CodeGenerator.py

Issue 1702673002: DevTools: migrate remote debugging protocol generators to jinja2. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Copyright (c) 2011 Google Inc. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be
3 # Copyright (c) 2012 Intel Corporation. All rights reserved. 3 # found in the LICENSE file.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
8 #
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
14 # distribution.
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 4
31 import os.path 5 import os.path
32 import sys 6 import sys
33 import string 7 import string
34 import optparse 8 import optparse
35 import re 9 import re
36 try: 10 try:
37 import json 11 import json
38 except ImportError: 12 except ImportError:
39 import simplejson as json 13 import simplejson as json
40 14
41 import CodeGeneratorStrings 15 # Path handling for libraries and templates
16 # Paths have to be normalized because Jinja uses the exact template path to
17 # determine the hash used in the cache filename, and we need a pre-caching step
18 # to be concurrency-safe. Use absolute path because __file__ is absolute if
19 # module is imported, and relative if executed directly.
20 # If paths differ between pre-caching and individual file compilation, the cache
21 # is regenerated, which causes a race condition and breaks concurrent build,
22 # since some compile processes will try to read the partially written cache.
23 module_path, module_filename = os.path.split(os.path.realpath(__file__))
24 templates_dir = module_path
25 third_party_dir = os.path.normpath(os.path.join(
26 module_path, os.pardir, os.pardir, os.pardir, os.pardir))
42 27
43 # Manually-filled map of type name replacements. 28 # jinja2 is in chromium's third_party directory.
44 TYPE_NAME_FIX_MAP = { 29 # Insert at 1 so at front to override system libraries, and
45 "RGBA": "Rgba", # RGBA is reported to be conflicting with a define name in Windows CE. 30 # after path[0] == invoking script dir
46 "": "Empty", 31 sys.path.insert(1, third_party_dir)
47 } 32 import jinja2
48
49
50 TYPES_WITH_RUNTIME_CAST_SET = frozenset(["Runtime.RemoteObject", "Runtime.Proper tyDescriptor", "Runtime.InternalPropertyDescriptor",
51 "Debugger.FunctionDetails", "Debugger.G eneratorObjectDetails", "Debugger.CollectionEntry", "Debugger.CallFrame", "Debug ger.Location"])
52 33
53 cmdline_parser = optparse.OptionParser() 34 cmdline_parser = optparse.OptionParser()
54 cmdline_parser.add_option("--output_dir") 35 cmdline_parser.add_option("--output_dir")
36 cmdline_parser.add_option("--template_dir")
55 37
56 try: 38 try:
57 arg_options, arg_values = cmdline_parser.parse_args() 39 arg_options, arg_values = cmdline_parser.parse_args()
58 if (len(arg_values) != 1): 40 if (len(arg_values) != 1):
59 raise Exception("Exactly one plain argument expected (found %s)" % len(a rg_values)) 41 raise Exception("Exactly one plain argument expected (found %s)" % len(a rg_values))
60 input_json_filename = arg_values[0] 42 input_json_filename = arg_values[0]
61 output_dirname = arg_options.output_dir 43 output_dirname = arg_options.output_dir
62 if not output_dirname: 44 if not output_dirname:
63 raise Exception("Output directory must be specified") 45 raise Exception("Output directory must be specified")
64 except Exception: 46 except Exception:
65 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html 47 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
66 exc = sys.exc_info()[1] 48 exc = sys.exc_info()[1]
67 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) 49 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
68 sys.stderr.write("Usage: <script> --output_dir <output_dir> protocol.json\n" ) 50 sys.stderr.write("Usage: <script> --output_dir <output_dir> protocol.json\n" )
69 exit(1) 51 exit(1)
70 52
71
72 # FIXME: move this methods under Capitalizer class below and remove duplications .
73 def dash_to_camelcase(word):
74 return ''.join(x.capitalize() or '-' for x in word.split('-'))
75
76
77 def fix_camel_case(name):
78 refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name)
79 refined = to_title_case(refined)
80 return re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), ref ined)
81
82
83 def to_title_case(name):
84 return name[:1].upper() + name[1:]
85
86
87 class Capitalizer:
88 @staticmethod
89 def lower_camel_case_to_upper(str):
90 if len(str) > 0 and str[0].islower():
91 str = str[0].upper() + str[1:]
92 return str
93
94 @staticmethod
95 def upper_camel_case_to_lower(str):
96 pos = 0
97 while pos < len(str) and str[pos].isupper():
98 pos += 1
99 if pos == 0:
100 return str
101 if pos == 1:
102 return str[0].lower() + str[1:]
103 if pos < len(str):
104 pos -= 1
105 possible_abbreviation = str[0:pos]
106 if possible_abbreviation not in Capitalizer.ABBREVIATION:
107 raise Exception("Unknown abbreviation %s" % possible_abbreviation)
108 str = possible_abbreviation.lower() + str[pos:]
109 return str
110
111 ABBREVIATION = frozenset(["XHR", "DOM", "CSS", "IO"])
112
113 VALIDATOR_IFDEF_NAME = "ENABLE(ASSERT)"
114
115
116 class DomainNameFixes:
117 @staticmethod
118 def get_fixed_data(domain_name):
119 return Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent"
120
121 class RawTypes(object):
122 @staticmethod
123 def get(json_type):
124 if json_type == "boolean":
125 return RawTypes.Bool
126 elif json_type == "string":
127 return RawTypes.String
128 elif json_type == "array":
129 return RawTypes.Array
130 elif json_type == "object":
131 return RawTypes.Object
132 elif json_type == "integer":
133 return RawTypes.Int
134 elif json_type == "number":
135 return RawTypes.Number
136 elif json_type == "any":
137 return RawTypes.Any
138 else:
139 raise Exception("Unknown type: %s" % json_type)
140
141 class BaseType(object):
142 @classmethod
143 def get_raw_validator_call_text(cls):
144 return "RuntimeCastHelper::assertType<JSONValue::Type%s>" % cls.get_ getter_name()
145
146 @staticmethod
147 def get_getter_name():
148 raise Exception("Unsupported")
149
150 class String(BaseType):
151 @staticmethod
152 def get_getter_name():
153 return "String"
154
155 get_setter_name = get_getter_name
156
157 @staticmethod
158 def get_constructor_pattern():
159 return "InspectorString::create(%s)"
160
161 @staticmethod
162 def is_heavy_value():
163 return True
164
165 @staticmethod
166 def get_array_item_raw_c_type_text():
167 return "String"
168
169 @staticmethod
170 def get_raw_type_model():
171 return TypeModel.String
172
173 class Int(BaseType):
174 @staticmethod
175 def get_getter_name():
176 return "Int"
177
178 @staticmethod
179 def get_setter_name():
180 return "Number"
181
182 @staticmethod
183 def get_constructor_pattern():
184 return "InspectorBasicValue::create(%s)"
185
186 @classmethod
187 def get_raw_validator_call_text(cls):
188 return "RuntimeCastHelper::assertInt"
189
190 @staticmethod
191 def is_heavy_value():
192 return False
193
194 @staticmethod
195 def get_array_item_raw_c_type_text():
196 return "int"
197
198 @staticmethod
199 def get_raw_type_model():
200 return TypeModel.Int
201
202 class Number(BaseType):
203 @staticmethod
204 def get_getter_name():
205 return "Double"
206
207 @staticmethod
208 def get_setter_name():
209 return "Number"
210
211 @staticmethod
212 def get_constructor_pattern():
213 return "InspectorBasicValue::create(%s)"
214
215 @staticmethod
216 def get_raw_validator_call_text():
217 return "RuntimeCastHelper::assertType<JSONValue::TypeNumber>"
218
219 @staticmethod
220 def is_heavy_value():
221 return False
222
223 @staticmethod
224 def get_array_item_raw_c_type_text():
225 return "double"
226
227 @staticmethod
228 def get_raw_type_model():
229 return TypeModel.Number
230
231 class Bool(BaseType):
232 @staticmethod
233 def get_getter_name():
234 return "Boolean"
235
236 get_setter_name = get_getter_name
237
238 @staticmethod
239 def get_constructor_pattern():
240 return "InspectorBasicValue::create(%s)"
241
242 @staticmethod
243 def is_heavy_value():
244 return False
245
246 @staticmethod
247 def get_array_item_raw_c_type_text():
248 return "bool"
249
250 @staticmethod
251 def get_raw_type_model():
252 return TypeModel.Bool
253
254 class Object(BaseType):
255 @staticmethod
256 def get_getter_name():
257 return "Object"
258
259 @staticmethod
260 def get_setter_name():
261 return "Value"
262
263 @staticmethod
264 def get_constructor_pattern():
265 return "%s"
266
267 @staticmethod
268 def get_output_argument_prefix():
269 return ""
270
271 @staticmethod
272 def is_heavy_value():
273 return True
274
275 @staticmethod
276 def get_array_item_raw_c_type_text():
277 return "JSONObject"
278
279 @staticmethod
280 def get_raw_type_model():
281 return TypeModel.Object
282
283 class Any(BaseType):
284 @staticmethod
285 def get_getter_name():
286 return "Value"
287
288 get_setter_name = get_getter_name
289
290 @staticmethod
291 def get_constructor_pattern():
292 raise Exception("Unsupported")
293
294 @staticmethod
295 def get_raw_validator_call_text():
296 return "RuntimeCastHelper::assertAny"
297
298 @staticmethod
299 def is_heavy_value():
300 return True
301
302 @staticmethod
303 def get_array_item_raw_c_type_text():
304 return "JSONValue"
305
306 @staticmethod
307 def get_raw_type_model():
308 return TypeModel.Any
309
310 class Array(BaseType):
311 @staticmethod
312 def get_getter_name():
313 return "Array"
314
315 @staticmethod
316 def get_setter_name():
317 return "Value"
318
319 @staticmethod
320 def get_constructor_pattern():
321 return "%s"
322
323 @staticmethod
324 def get_output_argument_prefix():
325 return ""
326
327 @staticmethod
328 def is_heavy_value():
329 return True
330
331 @staticmethod
332 def get_array_item_raw_c_type_text():
333 return "JSONArray"
334
335 @staticmethod
336 def get_raw_type_model():
337 return TypeModel.Array
338
339
340 class CommandReturnPassModel:
341 class ByReference:
342 def __init__(self, var_type, set_condition):
343 self.var_type = var_type
344 self.set_condition = set_condition
345
346 def get_return_var_type(self):
347 return self.var_type
348
349 @staticmethod
350 def get_output_argument_prefix():
351 return ""
352
353 @staticmethod
354 def get_output_to_raw_expression():
355 return "%s"
356
357 def get_output_parameter_type(self):
358 return self.var_type + "&"
359
360 def get_set_return_condition(self):
361 return self.set_condition
362
363 class ByPointer:
364 def __init__(self, var_type):
365 self.var_type = var_type
366
367 def get_return_var_type(self):
368 return self.var_type
369
370 @staticmethod
371 def get_output_argument_prefix():
372 return "&"
373
374 @staticmethod
375 def get_output_to_raw_expression():
376 return "%s"
377
378 def get_output_parameter_type(self):
379 return self.var_type + "*"
380
381 @staticmethod
382 def get_set_return_condition():
383 return None
384
385 class OptOutput:
386 def __init__(self, var_type):
387 self.var_type = var_type
388
389 def get_return_var_type(self):
390 return "TypeBuilder::OptOutput<%s>" % self.var_type
391
392 @staticmethod
393 def get_output_argument_prefix():
394 return "&"
395
396 @staticmethod
397 def get_output_to_raw_expression():
398 return "%s.getValue()"
399
400 def get_output_parameter_type(self):
401 return "TypeBuilder::OptOutput<%s>*" % self.var_type
402
403 @staticmethod
404 def get_set_return_condition():
405 return "%s.isAssigned()"
406
407
408 class TypeModel:
409 class RefPtrBased(object):
410 def __init__(self, class_name):
411 self.class_name = class_name
412 self.optional = False
413
414 def get_optional(self):
415 result = TypeModel.RefPtrBased(self.class_name)
416 result.optional = True
417 return result
418
419 def get_command_return_pass_model(self):
420 if self.optional:
421 set_condition = "%s"
422 else:
423 set_condition = None
424 return CommandReturnPassModel.ByReference("RefPtr<%s>" % self.class_ name, set_condition)
425
426 def get_input_param_type_text(self):
427 return "PassRefPtr<%s>" % self.class_name
428
429 @staticmethod
430 def get_event_setter_expression_pattern():
431 return "%s"
432
433 class Enum(object):
434 def __init__(self, base_type_name):
435 self.type_name = base_type_name + "::Enum"
436
437 def get_optional(base_self):
438 class EnumOptional:
439 @classmethod
440 def get_optional(cls):
441 return cls
442
443 @staticmethod
444 def get_command_return_pass_model():
445 return CommandReturnPassModel.OptOutput(base_self.type_name)
446
447 @staticmethod
448 def get_input_param_type_text():
449 return base_self.type_name + "*"
450
451 @staticmethod
452 def get_event_setter_expression_pattern():
453 raise Exception("TODO")
454 return EnumOptional
455
456 def get_command_return_pass_model(self):
457 return CommandReturnPassModel.ByPointer(self.type_name)
458
459 def get_input_param_type_text(self):
460 return self.type_name
461
462 @staticmethod
463 def get_event_setter_expression_pattern():
464 return "%s"
465
466 class ValueType(object):
467 def __init__(self, type_name, is_heavy):
468 self.type_name = type_name
469 self.is_heavy = is_heavy
470
471 def get_optional(self):
472 return self.ValueOptional(self)
473
474 def get_command_return_pass_model(self):
475 return CommandReturnPassModel.ByPointer(self.type_name)
476
477 def get_input_param_type_text(self):
478 if self.is_heavy:
479 return "const %s&" % self.type_name
480 else:
481 return self.type_name
482
483 def get_opt_output_type_(self):
484 return self.type_name
485
486 @staticmethod
487 def get_event_setter_expression_pattern():
488 return "%s"
489
490 class ValueOptional:
491 def __init__(self, base):
492 self.base = base
493
494 def get_optional(self):
495 return self
496
497 def get_command_return_pass_model(self):
498 return CommandReturnPassModel.OptOutput(self.base.get_opt_output _type_())
499
500 def get_input_param_type_text(self):
501 return "const %s* const" % self.base.type_name
502
503 @staticmethod
504 def get_event_setter_expression_pattern():
505 return "*%s"
506
507 @classmethod
508 def init_class(cls):
509 cls.Bool = cls.ValueType("bool", False)
510 cls.Int = cls.ValueType("int", False)
511 cls.Number = cls.ValueType("double", False)
512 cls.String = cls.ValueType("String", True,)
513 cls.Object = cls.RefPtrBased("JSONObject")
514 cls.Array = cls.RefPtrBased("JSONArray")
515 cls.Any = cls.RefPtrBased("JSONValue")
516
517 TypeModel.init_class()
518
519
520 # Collection of JSONObject class methods that are likely to be overloaded in gen erated class.
521 # We must explicitly import all overloaded methods or they won't be available to user.
522 INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber" , "setString", "setValue", "setObject", "setArray"])
523
524
525 def fix_type_name(json_name):
526 if json_name in TYPE_NAME_FIX_MAP:
527 fixed = TYPE_NAME_FIX_MAP[json_name]
528
529 class Result(object):
530 class_name = fixed
531
532 @staticmethod
533 def output_comment(writer):
534 writer.newline("// Type originally was named '%s'.\n" % json_nam e)
535 else:
536
537 class Result(object):
538 class_name = json_name
539
540 @staticmethod
541 def output_comment(writer):
542 pass
543
544 return Result
545
546
547 class Writer:
548 def __init__(self, output, indent):
549 self.output = output
550 self.indent = indent
551
552 def newline(self, str):
553 if (self.indent):
554 self.output.append(self.indent)
555 self.output.append(str)
556
557 def append(self, str):
558 self.output.append(str)
559
560 def newline_multiline(self, str):
561 parts = str.split('\n')
562 self.newline(parts[0])
563 for p in parts[1:]:
564 self.output.append('\n')
565 if p:
566 self.newline(p)
567
568 def append_multiline(self, str):
569 parts = str.split('\n')
570 self.append(parts[0])
571 for p in parts[1:]:
572 self.output.append('\n')
573 if p:
574 self.newline(p)
575
576 def get_indent(self):
577 return self.indent
578
579 def insert_writer(self, additional_indent):
580 new_output = []
581 self.output.append(new_output)
582 return Writer(new_output, self.indent + additional_indent)
583
584
585 class EnumConstants:
586 map_ = {}
587 constants_ = []
588
589 @classmethod
590 def add_constant(cls, value):
591 if value in cls.map_:
592 return cls.map_[value]
593 else:
594 pos = len(cls.map_)
595 cls.map_[value] = pos
596 cls.constants_.append(value)
597 return pos
598
599 @classmethod
600 def get_enum_constant_code(cls):
601 output = []
602 for item in cls.constants_:
603 output.append(" \"" + item + "\"")
604 return ",\n".join(output) + "\n"
605
606
607 # Typebuilder code is generated in several passes: first typedefs, then other cl asses.
608 # Manual pass management is needed because we cannot have forward declarations f or typedefs.
609 class TypeBuilderPass:
610 TYPEDEF = "typedef"
611 MAIN = "main"
612
613
614 class TypeBindings:
615 @staticmethod
616 def create_named_type_declaration(json_typable, context_domain_name, type_da ta):
617 json_type = type_data.get_json_type()
618
619 class Helper:
620 is_ad_hoc = False
621 full_name_prefix_for_use = "TypeBuilder::" + context_domain_name + " ::"
622 full_name_prefix_for_impl = "TypeBuilder::" + context_domain_name + "::"
623
624 @staticmethod
625 def write_doc(writer):
626 if "description" in json_type:
627 writer.newline("/* ")
628 writer.append(json_type["description"])
629 writer.append(" */\n")
630
631 @staticmethod
632 def add_to_forward_listener(forward_listener):
633 forward_listener.add_type_data(type_data)
634
635
636 fixed_type_name = fix_type_name(json_type["id"])
637 return TypeBindings.create_type_declaration_(json_typable, context_domai n_name, fixed_type_name, Helper)
638
639 @staticmethod
640 def create_ad_hoc_type_declaration(json_typable, context_domain_name, ad_hoc _type_context):
641 class Helper:
642 is_ad_hoc = True
643 full_name_prefix_for_use = ad_hoc_type_context.container_relative_na me_prefix
644 full_name_prefix_for_impl = ad_hoc_type_context.container_full_name_ prefix
645
646 @staticmethod
647 def write_doc(writer):
648 pass
649
650 @staticmethod
651 def add_to_forward_listener(forward_listener):
652 pass
653 fixed_type_name = ad_hoc_type_context.get_type_name_fix()
654 return TypeBindings.create_type_declaration_(json_typable, context_domai n_name, fixed_type_name, Helper)
655
656 @staticmethod
657 def create_type_declaration_(json_typable, context_domain_name, fixed_type_n ame, helper):
658 if json_typable["type"] == "string":
659 if "enum" in json_typable:
660
661 class EnumBinding:
662 need_user_runtime_cast_ = False
663 need_internal_runtime_cast_ = False
664
665 @classmethod
666 def resolve_inner(cls, resolve_context):
667 pass
668
669 @classmethod
670 def request_user_runtime_cast(cls, request):
671 if request:
672 cls.need_user_runtime_cast_ = True
673 request.acknowledge()
674
675 @classmethod
676 def request_internal_runtime_cast(cls):
677 cls.need_internal_runtime_cast_ = True
678
679 @classmethod
680 def get_code_generator(enum_binding_cls):
681
682 class CodeGenerator:
683 @staticmethod
684 def generate_type_builder(writer, generate_context):
685 enum = json_typable["enum"]
686 helper.write_doc(writer)
687 enum_name = fixed_type_name.class_name
688 fixed_type_name.output_comment(writer)
689 writer.newline("struct ")
690 writer.append(enum_name)
691 writer.append(" {\n")
692 writer.newline(" enum Enum {\n")
693 for enum_item in enum:
694 enum_pos = EnumConstants.add_constant(enum_i tem)
695
696 item_c_name = enum_item.replace('-', '_')
697 item_c_name = Capitalizer.lower_camel_case_t o_upper(item_c_name)
698 if item_c_name in TYPE_NAME_FIX_MAP:
699 item_c_name = TYPE_NAME_FIX_MAP[item_c_n ame]
700 writer.newline(" ")
701 writer.append(item_c_name)
702 writer.append(" = ")
703 writer.append("%s" % enum_pos)
704 writer.append(",\n")
705 writer.newline(" };\n")
706 if enum_binding_cls.need_user_runtime_cast_:
707 raise Exception("Not yet implemented")
708
709 if enum_binding_cls.need_internal_runtime_cast_:
710 writer.append("#if %s\n" % VALIDATOR_IFDEF_N AME)
711 writer.newline(" static void assertCorrec tValue(JSONValue* value);\n")
712 writer.append("#endif // %s\n" % VALIDATOR_ IFDEF_NAME)
713
714 validator_writer = generate_context.validato r_writer
715
716 validator_writer.newline("void %s%s::assertC orrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, enum_name) )
717 validator_writer.newline("{\n")
718 validator_writer.newline(" WTF::String s; \n")
719 validator_writer.newline(" bool cast_res = value->asString(&s);\n")
720 validator_writer.newline(" ASSERT(cast_re s);\n")
721 if len(enum) > 0:
722 condition_list = []
723 for enum_item in enum:
724 enum_pos = EnumConstants.add_constan t(enum_item)
725 condition_list.append("s == \"%s\"" % enum_item)
726 validator_writer.newline(" ASSERT(%s) ;\n" % " || ".join(condition_list))
727 validator_writer.newline("}\n")
728
729 validator_writer.newline("\n\n")
730
731 writer.newline("}; // struct ")
732 writer.append(enum_name)
733 writer.append("\n\n")
734
735 @staticmethod
736 def register_use(forward_listener):
737 pass
738
739 @staticmethod
740 def get_generate_pass_id():
741 return TypeBuilderPass.MAIN
742
743 return CodeGenerator
744
745 @classmethod
746 def get_validator_call_text(cls):
747 return helper.full_name_prefix_for_use + fixed_type_name .class_name + "::assertCorrectValue"
748
749 @classmethod
750 def get_array_item_c_type_text(cls):
751 return helper.full_name_prefix_for_use + fixed_type_name .class_name + "::Enum"
752
753 @staticmethod
754 def get_setter_value_expression_pattern():
755 return "TypeBuilder::getEnumConstantValue(%s)"
756
757 @staticmethod
758 def reduce_to_raw_type():
759 return RawTypes.String
760
761 @staticmethod
762 def get_type_model():
763 return TypeModel.Enum(helper.full_name_prefix_for_use + fixed_type_name.class_name)
764
765 return EnumBinding
766 else:
767 if helper.is_ad_hoc:
768
769 class PlainString:
770 @classmethod
771 def resolve_inner(cls, resolve_context):
772 pass
773
774 @staticmethod
775 def request_user_runtime_cast(request):
776 raise Exception("Unsupported")
777
778 @staticmethod
779 def request_internal_runtime_cast():
780 pass
781
782 @staticmethod
783 def get_code_generator():
784 return None
785
786 @classmethod
787 def get_validator_call_text(cls):
788 return RawTypes.String.get_raw_validator_call_text()
789
790 @staticmethod
791 def reduce_to_raw_type():
792 return RawTypes.String
793
794 @staticmethod
795 def get_type_model():
796 return TypeModel.String
797
798 @staticmethod
799 def get_setter_value_expression_pattern():
800 return None
801
802 @classmethod
803 def get_array_item_c_type_text(cls):
804 return cls.reduce_to_raw_type().get_array_item_raw_c _type_text()
805
806 return PlainString
807
808 else:
809
810 class TypedefString:
811 @classmethod
812 def resolve_inner(cls, resolve_context):
813 pass
814
815 @staticmethod
816 def request_user_runtime_cast(request):
817 raise Exception("Unsupported")
818
819 @staticmethod
820 def request_internal_runtime_cast():
821 pass
822
823 @staticmethod
824 def get_code_generator():
825 class CodeGenerator:
826 @staticmethod
827 def generate_type_builder(writer, generate_conte xt):
828 helper.write_doc(writer)
829 fixed_type_name.output_comment(writer)
830 writer.newline("typedef String ")
831 writer.append(fixed_type_name.class_name)
832 writer.append(";\n\n")
833
834 @staticmethod
835 def register_use(forward_listener):
836 pass
837
838 @staticmethod
839 def get_generate_pass_id():
840 return TypeBuilderPass.TYPEDEF
841
842 return CodeGenerator
843
844 @classmethod
845 def get_validator_call_text(cls):
846 return RawTypes.String.get_raw_validator_call_text()
847
848 @staticmethod
849 def reduce_to_raw_type():
850 return RawTypes.String
851
852 @staticmethod
853 def get_type_model():
854 return TypeModel.ValueType("%s%s" % (helper.full_nam e_prefix_for_use, fixed_type_name.class_name), True)
855
856 @staticmethod
857 def get_setter_value_expression_pattern():
858 return None
859
860 @classmethod
861 def get_array_item_c_type_text(cls):
862 return "%s%s" % (helper.full_name_prefix_for_use, fi xed_type_name.class_name)
863
864 return TypedefString
865
866 elif json_typable["type"] == "object":
867 if "properties" in json_typable:
868
869 class ClassBinding:
870 resolve_data_ = None
871 need_user_runtime_cast_ = False
872 need_internal_runtime_cast_ = False
873
874 @classmethod
875 def resolve_inner(cls, resolve_context):
876 if cls.resolve_data_:
877 return
878
879 properties = json_typable["properties"]
880 main = []
881 optional = []
882
883 ad_hoc_type_list = []
884
885 for prop in properties:
886 prop_name = prop["name"]
887 ad_hoc_type_context = cls.AdHocTypeContextImpl(prop_ name, fixed_type_name.class_name, resolve_context, ad_hoc_type_list, helper.full _name_prefix_for_impl)
888 binding = resolve_param_type(prop, context_domain_na me, ad_hoc_type_context)
889
890 code_generator = binding.get_code_generator()
891 if code_generator:
892 code_generator.register_use(resolve_context.forw ard_listener)
893
894 class PropertyData:
895 param_type_binding = binding
896 p = prop
897
898 if prop.get("optional"):
899 optional.append(PropertyData)
900 else:
901 main.append(PropertyData)
902
903 class ResolveData:
904 main_properties = main
905 optional_properties = optional
906 ad_hoc_types = ad_hoc_type_list
907
908 cls.resolve_data_ = ResolveData
909
910 for ad_hoc in ad_hoc_type_list:
911 ad_hoc.resolve_inner(resolve_context)
912
913 @classmethod
914 def request_user_runtime_cast(cls, request):
915 if not request:
916 return
917 cls.need_user_runtime_cast_ = True
918 request.acknowledge()
919 cls.request_internal_runtime_cast()
920
921 @classmethod
922 def request_internal_runtime_cast(cls):
923 if cls.need_internal_runtime_cast_:
924 return
925 cls.need_internal_runtime_cast_ = True
926 for p in cls.resolve_data_.main_properties:
927 p.param_type_binding.request_internal_runtime_cast()
928 for p in cls.resolve_data_.optional_properties:
929 p.param_type_binding.request_internal_runtime_cast()
930
931 @classmethod
932 def get_code_generator(class_binding_cls):
933 class CodeGenerator:
934 @classmethod
935 def generate_type_builder(cls, writer, generate_cont ext):
936 resolve_data = class_binding_cls.resolve_data_
937 helper.write_doc(writer)
938 class_name = fixed_type_name.class_name
939
940 fixed_type_name.output_comment(writer)
941 writer.newline("class PLATFORM_EXPORT %s : publi c JSONObjectBase {\n" % class_name)
942 writer.newline("public:\n")
943 ad_hoc_type_writer = writer.insert_writer(" " )
944
945 for ad_hoc_type in resolve_data.ad_hoc_types:
946 code_generator = ad_hoc_type.get_code_genera tor()
947 if code_generator:
948 code_generator.generate_type_builder(ad_ hoc_type_writer, generate_context)
949
950 writer.newline_multiline(
951 """ enum {
952 NoFieldsSet = 0,
953 """)
954
955 state_enum_items = []
956 if len(resolve_data.main_properties) > 0:
957 pos = 0
958 for prop_data in resolve_data.main_propertie s:
959 item_name = Capitalizer.lower_camel_case _to_upper(prop_data.p["name"]) + "Set"
960 state_enum_items.append(item_name)
961 writer.newline(" %s = 1 << %s,\n" % (item_name, pos))
962 pos += 1
963 all_fields_set_value = "(" + (" | ".join(sta te_enum_items)) + ")"
964 else:
965 all_fields_set_value = "0"
966
967 writer.newline_multiline(CodeGeneratorStrings.cl ass_binding_builder_part_1
968 % (all_fields_set_value , class_name, class_name))
969
970 pos = 0
971 for prop_data in resolve_data.main_properties:
972 prop_name = prop_data.p["name"]
973
974 param_type_binding = prop_data.param_type_bi nding
975 param_raw_type = param_type_binding.reduce_t o_raw_type()
976
977 writer.newline_multiline(CodeGeneratorString s.class_binding_builder_part_2
978 % (state_enum_items[pos],
979 Capitalizer.lower_camel_case_to_upper (prop_name),
980 param_type_binding.get_type_model().g et_input_param_type_text(),
981 state_enum_items[pos], prop_name,
982 param_raw_type.get_setter_name(), pro p_name,
983 format_setter_value_expression(param_ type_binding, "value"),
984 state_enum_items[pos]))
985
986 pos += 1
987
988 writer.newline_multiline(CodeGeneratorStrings.cl ass_binding_builder_part_3
989 % (class_name, class_na me, class_name, class_name, class_name, class_name))
990
991 writer.newline(" /*\n")
992 writer.newline(" * Synthetic constructor:\n" )
993 writer.newline(" * RefPtr<%s> result = %s::c reate()" % (class_name, class_name))
994 for prop_data in resolve_data.main_properties:
995 writer.append_multiline("\n * .set%s (...)" % Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]))
996 writer.append_multiline(";\n */\n")
997
998 writer.newline_multiline(CodeGeneratorStrings.cl ass_binding_builder_part_4)
999
1000 writer.newline(" typedef TypeBuilder::StructI temTraits ItemTraits;\n")
1001
1002 for prop_data in resolve_data.main_properties:
1003 prop_name = prop_data.p["name"]
1004 param_type_binding = prop_data.param_type_bi nding
1005 if isinstance(param_type_binding.get_type_mo del(), TypeModel.ValueType):
1006 writer.append_multiline("\n void %s" % prop_name)
1007 writer.append("(%s value)\n" % param_typ e_binding.get_type_model().get_command_return_pass_model().get_output_parameter_ type())
1008 writer.newline(" {\n")
1009 writer.newline(" JSONObjectBase:: get%s(\"%s\", value);\n"
1010 % (param_type_binding.reduce_to_raw_ type().get_setter_name(), prop_data.p["name"]))
1011 writer.newline(" }\n")
1012
1013 for prop_data in resolve_data.optional_propertie s:
1014 prop_name = prop_data.p["name"]
1015 param_type_binding = prop_data.param_type_bi nding
1016 setter_name = "set%s" % Capitalizer.lower_ca mel_case_to_upper(prop_name)
1017
1018 writer.append_multiline("\n void %s" % se tter_name)
1019 writer.append("(%s value)\n" % param_type_bi nding.get_type_model().get_input_param_type_text())
1020 writer.newline(" {\n")
1021 writer.newline(" this->set%s(\"%s\", %s);\n"
1022 % (param_type_binding.reduce_to_raw_type ().get_setter_name(), prop_data.p["name"],
1023 format_setter_value_expression(param_ type_binding, "value")))
1024 writer.newline(" }\n")
1025
1026 if setter_name in INSPECTOR_OBJECT_SETTER_NA MES:
1027 writer.newline(" using JSONObjectBase ::%s;\n\n" % setter_name)
1028
1029 if class_binding_cls.need_user_runtime_cast_:
1030 writer.newline(" static PassRefPtr<%s> ru ntimeCast(PassRefPtr<JSONValue> value)\n" % class_name)
1031 writer.newline(" {\n")
1032 writer.newline(" RefPtr<JSONObject> o bject;\n")
1033 writer.newline(" bool castRes = value ->asObject(&object);\n")
1034 writer.newline(" ASSERT_UNUSED(castRe s, castRes);\n")
1035 writer.append("#if %s\n" % VALIDATOR_IFDEF_N AME)
1036 writer.newline(" assertCorrectValue(o bject.get());\n")
1037 writer.append("#endif // %s\n" % VALIDATOR_ IFDEF_NAME)
1038 writer.newline(" static_assert(sizeof (%s) == sizeof(JSONObjectBase), \"%s should be the same size as JSONObjectBase\" );\n" % (class_name, class_name))
1039 writer.newline(" return static_cast<% s*>(static_cast<JSONObjectBase*>(object.get()));\n" % class_name)
1040 writer.newline(" }\n")
1041 writer.append("\n")
1042
1043 if class_binding_cls.need_internal_runtime_cast_ :
1044 writer.append("#if %s\n" % VALIDATOR_IFDEF_N AME)
1045 writer.newline(" static void assertCorrec tValue(JSONValue* value);\n")
1046 writer.append("#endif // %s\n" % VALIDATOR_ IFDEF_NAME)
1047
1048 validator_writer = generate_context.validato r_writer
1049
1050 validator_writer.newline("void %s%s::assertC orrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, class_name ))
1051 validator_writer.newline("{\n")
1052 validator_writer.newline(" RefPtr<JSONObj ect> object;\n")
1053 validator_writer.newline(" bool castRes = value->asObject(&object);\n")
1054 validator_writer.newline(" ASSERT_UNUSED( castRes, castRes);\n")
1055 for prop_data in resolve_data.main_propertie s:
1056 validator_writer.newline(" {\n")
1057 it_name = "%sPos" % prop_data.p["name"]
1058 validator_writer.newline(" JSONOb ject::iterator %s;\n" % it_name)
1059 validator_writer.newline(" %s = o bject->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
1060 validator_writer.newline(" ASSERT (%s != object->end());\n" % it_name)
1061 validator_writer.newline(" %s(%s- >value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_ name))
1062 validator_writer.newline(" }\n")
1063
1064 validator_writer.newline(" int foundPrope rtiesCount = %s;\n" % len(resolve_data.main_properties))
1065
1066 for prop_data in resolve_data.optional_prope rties:
1067 validator_writer.newline(" {\n")
1068 it_name = "%sPos" % prop_data.p["name"]
1069 validator_writer.newline(" JSONOb ject::iterator %s;\n" % it_name)
1070 validator_writer.newline(" %s = o bject->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
1071 validator_writer.newline(" if (%s != object->end()) {\n" % it_name)
1072 validator_writer.newline(" %s (%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
1073 validator_writer.newline(" ++ foundPropertiesCount;\n")
1074 validator_writer.newline(" }\n")
1075 validator_writer.newline(" }\n")
1076
1077 validator_writer.newline(" if (foundPrope rtiesCount != object->size()) {\n")
1078 validator_writer.newline(" FATAL(\"Unex pected properties in object: %s\\n\", object->toJSONString().ascii().data());\n" )
1079 validator_writer.newline(" }\n")
1080 validator_writer.newline("}\n")
1081
1082 validator_writer.newline("\n\n")
1083
1084 writer.newline("};\n\n")
1085
1086 @staticmethod
1087 def generate_forward_declaration(writer):
1088 class_name = fixed_type_name.class_name
1089 writer.newline("class ")
1090 writer.append(class_name)
1091 writer.append(";\n")
1092
1093 @staticmethod
1094 def register_use(forward_listener):
1095 helper.add_to_forward_listener(forward_listener)
1096
1097 @staticmethod
1098 def get_generate_pass_id():
1099 return TypeBuilderPass.MAIN
1100
1101 return CodeGenerator
1102
1103 @staticmethod
1104 def get_validator_call_text():
1105 return helper.full_name_prefix_for_use + fixed_type_name .class_name + "::assertCorrectValue"
1106
1107 @classmethod
1108 def get_array_item_c_type_text(cls):
1109 return helper.full_name_prefix_for_use + fixed_type_name .class_name
1110
1111 @staticmethod
1112 def get_setter_value_expression_pattern():
1113 return "static_pointer_cast<JSONValue>(%s)"
1114
1115 @staticmethod
1116 def reduce_to_raw_type():
1117 return RawTypes.Object
1118
1119 @staticmethod
1120 def get_type_model():
1121 return TypeModel.RefPtrBased(helper.full_name_prefix_for _use + fixed_type_name.class_name)
1122
1123 class AdHocTypeContextImpl:
1124 def __init__(self, property_name, class_name, resolve_co ntext, ad_hoc_type_list, parent_full_name_prefix):
1125 self.property_name = property_name
1126 self.class_name = class_name
1127 self.resolve_context = resolve_context
1128 self.ad_hoc_type_list = ad_hoc_type_list
1129 self.container_full_name_prefix = parent_full_name_p refix + class_name + "::"
1130 self.container_relative_name_prefix = ""
1131
1132 def get_type_name_fix(self):
1133 class NameFix:
1134 class_name = Capitalizer.lower_camel_case_to_upp er(self.property_name)
1135
1136 @staticmethod
1137 def output_comment(writer):
1138 writer.newline("// Named after property name '%s' while generating %s.\n" % (self.property_name, self.class_name))
1139
1140 return NameFix
1141
1142 def add_type(self, binding):
1143 self.ad_hoc_type_list.append(binding)
1144
1145 return ClassBinding
1146 else:
1147
1148 class PlainObjectBinding:
1149 @classmethod
1150 def resolve_inner(cls, resolve_context):
1151 pass
1152
1153 @staticmethod
1154 def request_user_runtime_cast(request):
1155 pass
1156
1157 @staticmethod
1158 def request_internal_runtime_cast():
1159 pass
1160
1161 @staticmethod
1162 def get_code_generator():
1163 pass
1164
1165 @staticmethod
1166 def get_validator_call_text():
1167 return "RuntimeCastHelper::assertType<JSONValue::TypeObj ect>"
1168
1169 @classmethod
1170 def get_array_item_c_type_text(cls):
1171 return cls.reduce_to_raw_type().get_array_item_raw_c_typ e_text()
1172
1173 @staticmethod
1174 def get_setter_value_expression_pattern():
1175 return None
1176
1177 @staticmethod
1178 def reduce_to_raw_type():
1179 return RawTypes.Object
1180
1181 @staticmethod
1182 def get_type_model():
1183 return TypeModel.Object
1184
1185 return PlainObjectBinding
1186 elif json_typable["type"] == "array":
1187 if "items" in json_typable:
1188
1189 ad_hoc_types = []
1190
1191 class AdHocTypeContext:
1192 container_full_name_prefix = "<not yet defined>"
1193 container_relative_name_prefix = ""
1194
1195 @staticmethod
1196 def get_type_name_fix():
1197 return fixed_type_name
1198
1199 @staticmethod
1200 def add_type(binding):
1201 ad_hoc_types.append(binding)
1202
1203 item_binding = resolve_param_type(json_typable["items"], context _domain_name, AdHocTypeContext)
1204
1205 class ArrayBinding:
1206 resolve_data_ = None
1207 need_internal_runtime_cast_ = False
1208
1209 @classmethod
1210 def resolve_inner(cls, resolve_context):
1211 if cls.resolve_data_:
1212 return
1213
1214 class ResolveData:
1215 item_type_binding = item_binding
1216 ad_hoc_type_list = ad_hoc_types
1217
1218 cls.resolve_data_ = ResolveData
1219
1220 for t in ad_hoc_types:
1221 t.resolve_inner(resolve_context)
1222
1223 @classmethod
1224 def request_user_runtime_cast(cls, request):
1225 raise Exception("Not implemented yet")
1226
1227 @classmethod
1228 def request_internal_runtime_cast(cls):
1229 if cls.need_internal_runtime_cast_:
1230 return
1231 cls.need_internal_runtime_cast_ = True
1232 cls.resolve_data_.item_type_binding.request_internal_run time_cast()
1233
1234 @classmethod
1235 def get_code_generator(array_binding_cls):
1236
1237 class CodeGenerator:
1238 @staticmethod
1239 def generate_type_builder(writer, generate_context):
1240 ad_hoc_type_writer = writer
1241
1242 resolve_data = array_binding_cls.resolve_data_
1243
1244 for ad_hoc_type in resolve_data.ad_hoc_type_list :
1245 code_generator = ad_hoc_type.get_code_genera tor()
1246 if code_generator:
1247 code_generator.generate_type_builder(ad_ hoc_type_writer, generate_context)
1248
1249 @staticmethod
1250 def generate_forward_declaration(writer):
1251 pass
1252
1253 @staticmethod
1254 def register_use(forward_listener):
1255 item_code_generator = item_binding.get_code_gene rator()
1256 if item_code_generator:
1257 item_code_generator.register_use(forward_lis tener)
1258
1259 @staticmethod
1260 def get_generate_pass_id():
1261 return TypeBuilderPass.MAIN
1262
1263 return CodeGenerator
1264
1265 @classmethod
1266 def get_validator_call_text(cls):
1267 return cls.get_array_item_c_type_text() + "::assertCorre ctValue"
1268
1269 @classmethod
1270 def get_array_item_c_type_text(cls):
1271 return "TypeBuilder::Array<%s>" % cls.resolve_data_.item _type_binding.get_array_item_c_type_text()
1272
1273 @staticmethod
1274 def get_setter_value_expression_pattern():
1275 return None
1276
1277 @staticmethod
1278 def reduce_to_raw_type():
1279 return RawTypes.Array
1280
1281 @classmethod
1282 def get_type_model(cls):
1283 return TypeModel.RefPtrBased(cls.get_array_item_c_type_t ext())
1284
1285 return ArrayBinding
1286 else:
1287 # Fall-through to raw type.
1288 pass
1289
1290 raw_type = RawTypes.get(json_typable["type"])
1291
1292 return RawTypeBinding(raw_type)
1293
1294
1295 class RawTypeBinding:
1296 def __init__(self, raw_type):
1297 self.raw_type_ = raw_type
1298
1299 def resolve_inner(self, resolve_context):
1300 pass
1301
1302 def request_user_runtime_cast(self, request):
1303 raise Exception("Unsupported")
1304
1305 def request_internal_runtime_cast(self):
1306 pass
1307
1308 def get_code_generator(self):
1309 return None
1310
1311 def get_validator_call_text(self):
1312 return self.raw_type_.get_raw_validator_call_text()
1313
1314 def get_array_item_c_type_text(self):
1315 return self.raw_type_.get_array_item_raw_c_type_text()
1316
1317 def get_setter_value_expression_pattern(self):
1318 return None
1319
1320 def reduce_to_raw_type(self):
1321 return self.raw_type_
1322
1323 def get_type_model(self):
1324 return self.raw_type_.get_raw_type_model()
1325
1326
1327 class TypeData(object):
1328 def __init__(self, json_type, json_domain, domain_data):
1329 self.json_type_ = json_type
1330 self.json_domain_ = json_domain
1331 self.domain_data_ = domain_data
1332
1333 if "type" not in json_type:
1334 raise Exception("Unknown type")
1335
1336 json_type_name = json_type["type"]
1337 raw_type = RawTypes.get(json_type_name)
1338 self.raw_type_ = raw_type
1339 self.binding_being_resolved_ = False
1340 self.binding_ = None
1341
1342 def get_raw_type(self):
1343 return self.raw_type_
1344
1345 def get_binding(self):
1346 if not self.binding_:
1347 if self.binding_being_resolved_:
1348 raise Error("Type %s is already being resolved" % self.json_type _["type"])
1349 # Resolve only lazily, because resolving one named type may require resolving some other named type.
1350 self.binding_being_resolved_ = True
1351 try:
1352 self.binding_ = TypeBindings.create_named_type_declaration(self. json_type_, self.json_domain_["domain"], self)
1353 finally:
1354 self.binding_being_resolved_ = False
1355
1356 return self.binding_
1357
1358 def get_json_type(self):
1359 return self.json_type_
1360
1361 def get_name(self):
1362 return self.json_type_["id"]
1363
1364 def get_domain_name(self):
1365 return self.json_domain_["domain"]
1366
1367
1368 class DomainData:
1369 def __init__(self, json_domain):
1370 self.json_domain = json_domain
1371 self.types_ = []
1372
1373 def add_type(self, type_data):
1374 self.types_.append(type_data)
1375
1376 def name(self):
1377 return self.json_domain["domain"]
1378
1379 def types(self):
1380 return self.types_
1381
1382
1383 class TypeMap:
1384 def __init__(self, api):
1385 self.map_ = {}
1386 self.domains_ = []
1387 for json_domain in api["domains"]:
1388 domain_name = json_domain["domain"]
1389
1390 domain_map = {}
1391 self.map_[domain_name] = domain_map
1392
1393 domain_data = DomainData(json_domain)
1394 self.domains_.append(domain_data)
1395
1396 if "types" in json_domain:
1397 for json_type in json_domain["types"]:
1398 type_name = json_type["id"]
1399 type_data = TypeData(json_type, json_domain, domain_data)
1400 domain_map[type_name] = type_data
1401 domain_data.add_type(type_data)
1402
1403 def domains(self):
1404 return self.domains_
1405
1406 def get(self, domain_name, type_name):
1407 return self.map_[domain_name][type_name]
1408
1409
1410 def resolve_param_type(json_parameter, scope_domain_name, ad_hoc_type_context):
1411 if "$ref" in json_parameter:
1412 json_ref = json_parameter["$ref"]
1413 type_data = get_ref_data(json_ref, scope_domain_name)
1414 return type_data.get_binding()
1415 elif "type" in json_parameter:
1416 result = TypeBindings.create_ad_hoc_type_declaration(json_parameter, sco pe_domain_name, ad_hoc_type_context)
1417 ad_hoc_type_context.add_type(result)
1418 return result
1419 else:
1420 raise Exception("Unknown type")
1421
1422 def resolve_param_raw_type(json_parameter, scope_domain_name):
1423 if "$ref" in json_parameter:
1424 json_ref = json_parameter["$ref"]
1425 type_data = get_ref_data(json_ref, scope_domain_name)
1426 return type_data.get_raw_type()
1427 elif "type" in json_parameter:
1428 json_type = json_parameter["type"]
1429 return RawTypes.get(json_type)
1430 else:
1431 raise Exception("Unknown type")
1432
1433
1434 def get_ref_data(json_ref, scope_domain_name):
1435 dot_pos = json_ref.find(".")
1436 if dot_pos == -1:
1437 domain_name = scope_domain_name
1438 type_name = json_ref
1439 else:
1440 domain_name = json_ref[:dot_pos]
1441 type_name = json_ref[dot_pos + 1:]
1442
1443 return type_map.get(domain_name, type_name)
1444
1445
1446 input_file = open(input_json_filename, "r") 53 input_file = open(input_json_filename, "r")
1447 json_string = input_file.read() 54 json_string = input_file.read()
1448 json_api = json.loads(json_string) 55 json_api = json.loads(json_string)
1449 56
1450 57
1451 class Templates: 58 def to_title_case(name):
1452 def get_this_script_path_(absolute_path): 59 return name[:1].upper() + name[1:]
1453 absolute_path = os.path.abspath(absolute_path) 60
1454 components = [] 61
1455 62 def dash_to_camelcase(word):
1456 def fill_recursive(path_part, depth): 63 return ''.join(to_title_case(x) or '-' for x in word.split('-'))
1457 if depth <= 0 or path_part == '/': 64
1458 return 65
1459 fill_recursive(os.path.dirname(path_part), depth - 1) 66 def initialize_jinja_env(cache_dir):
1460 components.append(os.path.basename(path_part)) 67 jinja_env = jinja2.Environment(
1461 68 loader=jinja2.FileSystemLoader(templates_dir),
1462 # Typical path is /Source/platform/inspector_protocol/CodeGenerator.py 69 # Bytecode cache is not concurrency-safe unless pre-cached:
1463 # Let's take 4 components from the real path then. 70 # if pre-cached this is read-only, but writing creates a race condition.
1464 fill_recursive(absolute_path, 4) 71 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir),
1465 72 keep_trailing_newline=True, # newline-terminate generated files
1466 return "/".join(components) 73 lstrip_blocks=True, # so can indent control flow tags
1467 74 trim_blocks=True)
1468 file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys .argv[0]) + 75 jinja_env.filters.update({"to_title_case": to_title_case, "dash_to_camelcase ": dash_to_camelcase})
1469 """// Copyright (c) 2011 The Chromium Authors. All rights reserved. 76 jinja_env.add_extension('jinja2.ext.loopcontrols')
1470 // Use of this source code is governed by a BSD-style license that can be 77 return jinja_env
1471 // found in the LICENSE file. 78
1472 """)
1473
1474 frontend_domain_class = string.Template(CodeGeneratorStrings.frontend_domain _class)
1475 backend_method = string.Template(CodeGeneratorStrings.backend_method)
1476 frontend_method = string.Template(CodeGeneratorStrings.frontend_method)
1477 callback_main_methods = string.Template(CodeGeneratorStrings.callback_main_m ethods)
1478 frontend_h = string.Template(file_header_ + CodeGeneratorStrings.frontend_h)
1479 backend_h = string.Template(file_header_ + CodeGeneratorStrings.backend_h)
1480 backend_cpp = string.Template(file_header_ + CodeGeneratorStrings.backend_cp p)
1481 frontend_cpp = string.Template(file_header_ + CodeGeneratorStrings.frontend_ cpp)
1482 typebuilder_h = string.Template(file_header_ + CodeGeneratorStrings.typebuil der_h)
1483 typebuilder_cpp = string.Template(file_header_ + CodeGeneratorStrings.typebu ilder_cpp)
1484 param_container_access_code = CodeGeneratorStrings.param_container_access_co de
1485
1486
1487
1488
1489
1490 type_map = TypeMap(json_api)
1491
1492
1493 class NeedRuntimeCastRequest:
1494 def __init__(self):
1495 self.ack_ = None
1496
1497 def acknowledge(self):
1498 self.ack_ = True
1499
1500 def is_acknowledged(self):
1501 return self.ack_
1502
1503
1504 def resolve_all_types():
1505 runtime_cast_generate_requests = {}
1506 for type_name in TYPES_WITH_RUNTIME_CAST_SET:
1507 runtime_cast_generate_requests[type_name] = NeedRuntimeCastRequest()
1508
1509 class ForwardListener:
1510 type_data_set = set()
1511 already_declared_set = set()
1512
1513 @classmethod
1514 def add_type_data(cls, type_data):
1515 if type_data not in cls.already_declared_set:
1516 cls.type_data_set.add(type_data)
1517
1518 class ResolveContext:
1519 forward_listener = ForwardListener
1520
1521 for domain_data in type_map.domains():
1522 for type_data in domain_data.types():
1523 # Do not generate forwards for this type any longer.
1524 ForwardListener.already_declared_set.add(type_data)
1525
1526 binding = type_data.get_binding()
1527 binding.resolve_inner(ResolveContext)
1528
1529 for domain_data in type_map.domains():
1530 for type_data in domain_data.types():
1531 full_type_name = "%s.%s" % (type_data.get_domain_name(), type_data.g et_name())
1532 request = runtime_cast_generate_requests.pop(full_type_name, None)
1533 binding = type_data.get_binding()
1534 if request:
1535 binding.request_user_runtime_cast(request)
1536
1537 if request and not request.is_acknowledged():
1538 raise Exception("Failed to generate runtimeCast in " + full_type _name)
1539
1540 for full_type_name in runtime_cast_generate_requests:
1541 raise Exception("Failed to generate runtimeCast. Type " + full_type_name + " not found")
1542
1543 return ForwardListener
1544
1545
1546 global_forward_listener = resolve_all_types()
1547
1548
1549 def get_annotated_type_text(raw_type, annotated_type):
1550 if annotated_type != raw_type:
1551 return "/*%s*/ %s" % (annotated_type, raw_type)
1552 else:
1553 return raw_type
1554
1555
1556 def format_setter_value_expression(param_type_binding, value_ref):
1557 pattern = param_type_binding.get_setter_value_expression_pattern()
1558 if pattern:
1559 return pattern % value_ref
1560 else:
1561 return value_ref
1562
1563 class Generator:
1564 frontend_class_field_lines = []
1565 frontend_domain_class_lines = []
1566
1567 method_name_enum_list = []
1568 backend_method_declaration_list = []
1569 backend_method_implementation_list = []
1570 backend_method_name_declaration_list = []
1571 backend_method_name_declaration_index_list = []
1572 backend_method_name_declaration_current_index = 0
1573 method_handler_list = []
1574 frontend_method_list = []
1575
1576 backend_virtual_setters_list = []
1577 backend_agent_interface_list = []
1578 backend_setters_list = []
1579 backend_constructor_init_list = []
1580 backend_field_list = []
1581 frontend_constructor_init_list = []
1582 type_builder_fragments = []
1583 type_builder_forwards = []
1584 validator_impl_list = []
1585 type_builder_impl_list = []
1586
1587
1588 @staticmethod
1589 def go():
1590 Generator.process_types(type_map)
1591
1592 for json_domain in json_api["domains"]:
1593 domain_name = json_domain["domain"]
1594 domain_name_lower = domain_name.lower()
1595
1596 agent_field_name = DomainNameFixes.get_fixed_data(domain_name)
1597
1598 frontend_method_declaration_lines = []
1599
1600 if "events" in json_domain:
1601 for json_event in json_domain["events"]:
1602 Generator.process_event(json_event, domain_name, frontend_me thod_declaration_lines)
1603
1604 Generator.frontend_class_field_lines.append(" %s m_%s;\n" % (doma in_name, domain_name_lower))
1605 if Generator.frontend_constructor_init_list:
1606 Generator.frontend_constructor_init_list.append(" , ")
1607 Generator.frontend_constructor_init_list.append("m_%s(frontendChanne l)\n" % domain_name_lower)
1608 Generator.frontend_domain_class_lines.append(Templates.frontend_doma in_class.substitute(None,
1609 domainClassName=domain_name,
1610 domainFieldName=domain_name_lower,
1611 frontendDomainMethodDeclarations="".join(flatten_list(frontend_m ethod_declaration_lines))))
1612
1613 agent_interface_name = Capitalizer.lower_camel_case_to_upper(domain_ name) + "CommandHandler"
1614 Generator.backend_agent_interface_list.append(" class PLATFORM_EX PORT %s {\n" % agent_interface_name)
1615 Generator.backend_agent_interface_list.append(" public:\n")
1616 if "commands" in json_domain:
1617 for json_command in json_domain["commands"]:
1618 Generator.process_command(json_command, domain_name, agent_f ield_name, agent_interface_name)
1619 Generator.backend_agent_interface_list.append("\n protected:\n")
1620 Generator.backend_agent_interface_list.append(" virtual ~%s() { }\n" % agent_interface_name)
1621 Generator.backend_agent_interface_list.append(" };\n\n")
1622
1623 Generator.backend_constructor_init_list.append(" , m_%s(0)" % agent_field_name)
1624 Generator.backend_virtual_setters_list.append(" virtual void regi sterAgent(%s* %s) = 0;" % (agent_interface_name, agent_field_name))
1625 Generator.backend_setters_list.append(" virtual void registerAgen t(%s* %s) { ASSERT(!m_%s); m_%s = %s; }" % (agent_interface_name, agent_field_na me, agent_field_name, agent_field_name, agent_field_name))
1626 Generator.backend_field_list.append(" %s* m_%s;" % (agent_interfa ce_name, agent_field_name))
1627
1628 @staticmethod
1629 def process_event(json_event, domain_name, frontend_method_declaration_lines ):
1630 if (("handlers" in json_event) and (not ("renderer" in json_event["handl ers"]))):
1631 return
1632
1633 event_name = json_event["name"]
1634
1635 ad_hoc_type_output = []
1636 frontend_method_declaration_lines.append(ad_hoc_type_output)
1637 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
1638
1639 decl_parameter_list = []
1640
1641 json_parameters = json_event.get("parameters")
1642 Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer,
1643 decl_parameter_list,
1644 Generator.EventMethodStructTemplate,
1645 Generator.frontend_method_list, Templates .frontend_method, {"eventName": event_name})
1646
1647 frontend_method_declaration_lines.append(
1648 " void %s(%s);\n" % (event_name, ", ".join(decl_parameter_lis t)))
1649
1650 class EventMethodStructTemplate:
1651 @staticmethod
1652 def append_prolog(line_list):
1653 line_list.append(" RefPtr<JSONObject> paramsObject = JSONObject:: create();\n")
1654
1655 @staticmethod
1656 def append_epilog(line_list):
1657 line_list.append(" jsonMessage->setObject(\"params\", paramsObjec t);\n")
1658
1659 container_name = "paramsObject"
1660
1661 @staticmethod
1662 def process_command(json_command, domain_name, agent_field_name, agent_inter face_name):
1663 if (("handlers" in json_command) and (not ("renderer" in json_command["h andlers"]))):
1664 return
1665
1666 json_command_name = json_command["name"]
1667
1668 cmd_enum_name = "k%s_%sCmd" % (domain_name, json_command["name"])
1669
1670 Generator.method_name_enum_list.append(" %s," % cmd_enum_name)
1671 Generator.method_handler_list.append(" &DispatcherImpl::%s_%s ," % (domain_name, json_command_name))
1672 Generator.backend_method_declaration_list.append(" void %s_%s(int ses sionId, int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors) ;" % (domain_name, json_command_name))
1673
1674 backend_agent_interface_list = [] if "redirect" in json_command else Gen erator.backend_agent_interface_list
1675
1676 ad_hoc_type_output = []
1677 backend_agent_interface_list.append(ad_hoc_type_output)
1678 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
1679
1680 backend_agent_interface_list.append(" virtual void %s(ErrorString *" % json_command_name)
1681
1682 method_in_code = ""
1683 method_out_code = ""
1684 agent_call_param_list = ["&error"]
1685 agent_call_params_declaration_list = [" ErrorString error;"]
1686 send_response_call_params_list = ["error"]
1687 request_message_param = ""
1688 normal_response_cook_text = ""
1689
1690 if "parameters" in json_command:
1691 json_params = json_command["parameters"]
1692 request_message_param = " requestMessageObject"
1693
1694 if json_params:
1695 method_in_code += Templates.param_container_access_code
1696
1697 for json_parameter in json_params:
1698 json_param_name = json_parameter["name"]
1699 param_raw_type = resolve_param_raw_type(json_parameter, domain_n ame)
1700
1701 getter_name = param_raw_type.get_getter_name()
1702
1703 optional = json_parameter.get("optional")
1704
1705 non_optional_type_model = param_raw_type.get_raw_type_model()
1706
1707 if optional:
1708 code = (" bool %s_valueFound = false;\n"
1709 " %s in_%s = get%s(paramsContainerPtr, \"%s\", &% s_valueFound, protocolErrors);\n" %
1710 (json_param_name, non_optional_type_model.get_command _return_pass_model().get_return_var_type(), json_param_name, getter_name, json_p aram_name, json_param_name))
1711 param = "%s_valueFound ? &in_%s : 0" % (json_param_name, jso n_param_name)
1712 # FIXME: pass optional refptr-values as PassRefPtr
1713 formal_param_type_pattern = "const %s*"
1714 else:
1715 code = (" %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrors);\n" %
1716 (non_optional_type_model.get_command_return_pass_mod el().get_return_var_type(), json_param_name, getter_name, json_param_name))
1717 param = "in_%s" % json_param_name
1718 # FIXME: pass not-optional refptr-values as NonNullPassRefPt r
1719 if param_raw_type.is_heavy_value():
1720 formal_param_type_pattern = "const %s&"
1721 else:
1722 formal_param_type_pattern = "%s"
1723
1724 method_in_code += code
1725 agent_call_param_list.append(param)
1726 backend_agent_interface_list.append(", %s in_%s" % (formal_param _type_pattern % non_optional_type_model.get_command_return_pass_model().get_retu rn_var_type(), json_param_name))
1727
1728 if json_command.get("async") == True:
1729 callback_name = Capitalizer.lower_camel_case_to_upper(json_command_n ame) + "Callback"
1730
1731 callback_output = []
1732 callback_writer = Writer(callback_output, ad_hoc_type_writer.get_ind ent())
1733
1734 decl_parameter_list = []
1735 Generator.generate_send_method(json_command.get("returns"), json_com mand_name, domain_name, ad_hoc_type_writer,
1736 decl_parameter_list,
1737 Generator.CallbackMethodStructTemplat e,
1738 Generator.backend_method_implementati on_list, Templates.callback_main_methods,
1739 {"callbackName": callback_name, "agen tName": agent_interface_name})
1740
1741 callback_writer.newline("class " + callback_name + " : public Callba ckBase {\n")
1742 callback_writer.newline("public:\n")
1743 callback_writer.newline(" " + callback_name + "(PassRefPtr<Dispat cherImpl>, int sessionId, int id);\n")
1744 callback_writer.newline(" PLATFORM_EXPORT void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
1745 callback_writer.newline("};\n")
1746
1747 ad_hoc_type_output.append(callback_output)
1748
1749 method_out_code += " RefPtr<" + agent_interface_name + "::" + cal lback_name + "> callback = adoptRef(new " + agent_interface_name + "::" + callba ck_name + "(this, sessionId, callId));\n"
1750 agent_call_param_list.append("callback")
1751 normal_response_cook_text += " if (!error.length()) \n"
1752 normal_response_cook_text += " return;\n"
1753 normal_response_cook_text += " callback->disable();\n"
1754 backend_agent_interface_list.append(", PassRefPtr<%s> callback" % ca llback_name)
1755 else:
1756 if "returns" in json_command:
1757 method_out_code += "\n"
1758 agent_call_params_declaration_list.append(" RefPtr<JSONObject > result = JSONObject::create();")
1759 send_response_call_params_list.append("result")
1760 response_cook_list = []
1761 for json_return in json_command["returns"]:
1762
1763 json_return_name = json_return["name"]
1764
1765 optional = bool(json_return.get("optional"))
1766
1767 return_type_binding = Generator.resolve_param_type_and_gener ate_ad_hoc(json_return, json_command_name, domain_name, ad_hoc_type_writer, agen t_interface_name + "::")
1768
1769 raw_type = return_type_binding.reduce_to_raw_type()
1770 setter_type = raw_type.get_setter_name()
1771
1772 type_model = return_type_binding.get_type_model()
1773 if optional:
1774 type_model = type_model.get_optional()
1775
1776 code = " %s out_%s;\n" % (type_model.get_command_return_p ass_model().get_return_var_type(), json_return_name)
1777 param = "%sout_%s" % (type_model.get_command_return_pass_mod el().get_output_argument_prefix(), json_return_name)
1778 var_name = "out_%s" % json_return_name
1779 setter_argument = type_model.get_command_return_pass_model() .get_output_to_raw_expression() % var_name
1780 if return_type_binding.get_setter_value_expression_pattern() :
1781 setter_argument = return_type_binding.get_setter_value_e xpression_pattern() % setter_argument
1782
1783 cook = " result->set%s(\"%s\", %s);\n" % (setter_type , json_return_name,
1784 setter_ argument)
1785
1786 set_condition_pattern = type_model.get_command_return_pass_m odel().get_set_return_condition()
1787 if set_condition_pattern:
1788 cook = (" if (%s)\n " % (set_condition_pattern % var_name)) + cook
1789 annotated_type = type_model.get_command_return_pass_model(). get_output_parameter_type()
1790
1791 param_name = var_name
1792 if optional:
1793 param_name = "opt_" + param_name
1794
1795 backend_agent_interface_list.append(", %s %s" % (annotated_t ype, param_name))
1796 response_cook_list.append(cook)
1797
1798 method_out_code += code
1799 agent_call_param_list.append(param)
1800
1801 normal_response_cook_text += "".join(response_cook_list)
1802
1803 if len(normal_response_cook_text) != 0:
1804 normal_response_cook_text = " if (!error.length()) {\n" + normal_response_cook_text + " }"
1805
1806 # Redirect to another agent's implementation.
1807 agent_field = "m_" + agent_field_name
1808 if "redirect" in json_command:
1809 agent_field = "m_" + DomainNameFixes.get_fixed_data(json_command.get ("redirect"))
1810
1811 Generator.backend_method_implementation_list.append(Templates.backend_me thod.substitute(None,
1812 domainName=domain_name, methodName=json_command_name,
1813 agentField=agent_field,
1814 methodCode="".join([method_in_code, method_out_code]),
1815 agentCallParamsDeclaration="\n".join(agent_call_params_declaration_l ist),
1816 agentCallParams=", ".join(agent_call_param_list),
1817 requestMessageObject=request_message_param,
1818 responseCook=normal_response_cook_text,
1819 sendResponseCallParams=", ".join(send_response_call_params_list),
1820 commandNameIndex=cmd_enum_name))
1821 declaration_command_name = "%s.%s\\0" % (domain_name, json_command_name)
1822 Generator.backend_method_name_declaration_list.append(" \"%s\"" % dec laration_command_name)
1823 assert Generator.backend_method_name_declaration_current_index < 2 ** 16 , "Number too large for unsigned short."
1824 Generator.backend_method_name_declaration_index_list.append(" %d," % Generator.backend_method_name_declaration_current_index)
1825 Generator.backend_method_name_declaration_current_index += len(declarati on_command_name) - 1
1826
1827 backend_agent_interface_list.append(") = 0;\n")
1828
1829 class CallbackMethodStructTemplate:
1830 @staticmethod
1831 def append_prolog(line_list):
1832 pass
1833
1834 @staticmethod
1835 def append_epilog(line_list):
1836 pass
1837
1838 container_name = "jsonMessage"
1839
1840 # Generates common code for event sending and callback response data sending .
1841 @staticmethod
1842 def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_wr iter, decl_parameter_list,
1843 method_struct_template,
1844 generator_method_list, method_template, template_pa rams):
1845 method_line_list = []
1846 if parameters:
1847 method_struct_template.append_prolog(method_line_list)
1848 for json_parameter in parameters:
1849 parameter_name = json_parameter["name"]
1850
1851 param_type_binding = Generator.resolve_param_type_and_generate_a d_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "")
1852
1853 raw_type = param_type_binding.reduce_to_raw_type()
1854 raw_type_binding = RawTypeBinding(raw_type)
1855
1856 optional = bool(json_parameter.get("optional"))
1857
1858 setter_type = raw_type.get_setter_name()
1859
1860 type_model = param_type_binding.get_type_model()
1861 raw_type_model = raw_type_binding.get_type_model()
1862 if optional:
1863 type_model = type_model.get_optional()
1864 raw_type_model = raw_type_model.get_optional()
1865
1866 annotated_type = type_model.get_input_param_type_text()
1867 mode_type_binding = param_type_binding
1868
1869 decl_parameter_list.append("%s %s" % (annotated_type, parameter_ name))
1870
1871 setter_argument = raw_type_model.get_event_setter_expression_pat tern() % parameter_name
1872 if mode_type_binding.get_setter_value_expression_pattern():
1873 setter_argument = mode_type_binding.get_setter_value_express ion_pattern() % setter_argument
1874
1875 setter_code = " %s->set%s(\"%s\", %s);\n" % (method_struct_te mplate.container_name, setter_type, parameter_name, setter_argument)
1876 if optional:
1877 setter_code = (" if (%s)\n " % parameter_name) + sette r_code
1878 method_line_list.append(setter_code)
1879
1880 method_struct_template.append_epilog(method_line_list)
1881
1882 generator_method_list.append(method_template.substitute(None,
1883 domainName=domain_name,
1884 parameters=", ".join(decl_parameter_list),
1885 code="".join(method_line_list), **template_params))
1886
1887 @classmethod
1888 def resolve_param_type_and_generate_ad_hoc(cls, json_param, method_name, dom ain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
1889 param_name = json_param["name"]
1890 return cls.resolve_type_and_generate_ad_hoc(json_param, param_name, meth od_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param)
1891
1892 @staticmethod
1893 def resolve_type_and_generate_ad_hoc(typable_element, element_name, method_n ame, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
1894 ad_hoc_type_list = []
1895
1896 class AdHocTypeContext:
1897 container_full_name_prefix = "<not yet defined>"
1898 container_relative_name_prefix = container_relative_name_prefix_para m
1899
1900 @staticmethod
1901 def get_type_name_fix():
1902 class NameFix:
1903 class_name = Capitalizer.lower_camel_case_to_upper(element_n ame)
1904
1905 @staticmethod
1906 def output_comment(writer):
1907 writer.newline("// Named after parameter '%s' while gene rating command/event %s.\n" % (element_name, method_name))
1908
1909 return NameFix
1910
1911 @staticmethod
1912 def add_type(binding):
1913 ad_hoc_type_list.append(binding)
1914
1915 type_binding = resolve_param_type(typable_element, domain_name, AdHocTyp eContext)
1916
1917 class InterfaceForwardListener:
1918 @staticmethod
1919 def add_type_data(type_data):
1920 pass
1921
1922 class InterfaceResolveContext:
1923 forward_listener = InterfaceForwardListener
1924
1925 for type in ad_hoc_type_list:
1926 type.resolve_inner(InterfaceResolveContext)
1927
1928 class InterfaceGenerateContext:
1929 validator_writer = "not supported in InterfaceGenerateContext"
1930 cpp_writer = validator_writer
1931
1932 for type in ad_hoc_type_list:
1933 generator = type.get_code_generator()
1934 if generator:
1935 generator.generate_type_builder(ad_hoc_type_writer, InterfaceGen erateContext)
1936
1937 return type_binding
1938
1939 @staticmethod
1940 def process_types(type_map):
1941 output = Generator.type_builder_fragments
1942
1943 class GenerateContext:
1944 validator_writer = Writer(Generator.validator_impl_list, "")
1945 cpp_writer = Writer(Generator.type_builder_impl_list, "")
1946
1947 def generate_all_domains_code(out, type_data_callback):
1948 writer = Writer(out, "")
1949 for domain_data in type_map.domains():
1950 namespace_declared = []
1951
1952 def namespace_lazy_generator():
1953 if not namespace_declared:
1954 writer.newline("namespace ")
1955 writer.append(domain_data.name())
1956 writer.append(" {\n")
1957 # What is a better way to change value from outer scope?
1958 namespace_declared.append(True)
1959 return writer
1960
1961 for type_data in domain_data.types():
1962 type_data_callback(type_data, namespace_lazy_generator)
1963
1964 if namespace_declared:
1965 writer.append("} // ")
1966 writer.append(domain_data.name())
1967 writer.append("\n\n")
1968
1969 def create_type_builder_caller(generate_pass_id):
1970 def call_type_builder(type_data, writer_getter):
1971 code_generator = type_data.get_binding().get_code_generator()
1972 if code_generator and generate_pass_id == code_generator.get_gen erate_pass_id():
1973 writer = writer_getter()
1974
1975 code_generator.generate_type_builder(writer, GenerateContext )
1976 return call_type_builder
1977
1978 generate_all_domains_code(output, create_type_builder_caller(TypeBuilder Pass.MAIN))
1979
1980 Generator.type_builder_forwards.append("// Forward declarations.\n")
1981
1982 def generate_forward_callback(type_data, writer_getter):
1983 if type_data in global_forward_listener.type_data_set:
1984 binding = type_data.get_binding()
1985 binding.get_code_generator().generate_forward_declaration(writer _getter())
1986 generate_all_domains_code(Generator.type_builder_forwards, generate_forw ard_callback)
1987
1988 Generator.type_builder_forwards.append("// End of forward declarations.\ n\n")
1989
1990 Generator.type_builder_forwards.append("// Typedefs.\n")
1991
1992 generate_all_domains_code(Generator.type_builder_forwards, create_type_b uilder_caller(TypeBuilderPass.TYPEDEF))
1993
1994 Generator.type_builder_forwards.append("// End of typedefs.\n\n")
1995
1996
1997 def flatten_list(input):
1998 res = []
1999
2000 def fill_recursive(l):
2001 for item in l:
2002 if isinstance(item, list):
2003 fill_recursive(item)
2004 else:
2005 res.append(item)
2006 fill_recursive(input)
2007 return res
2008 79
2009 def output_file(file_name): 80 def output_file(file_name):
2010 return open(file_name, "w") 81 return open(file_name, "w")
2011 82
2012 83
2013 Generator.go() 84 def patch_full_qualified_refs():
2014 85 def patch_full_qualified_refs_in_domain(json, domain_name):
2015 backend_h_file = output_file(output_dirname + "/Dispatcher.h") 86 if isinstance(json, list):
2016 backend_cpp_file = output_file(output_dirname + "/Dispatcher.cpp") 87 for item in json:
2017 88 patch_full_qualified_refs_in_domain(item, domain_name)
2018 frontend_h_file = output_file(output_dirname + "/Frontend.h") 89
2019 frontend_cpp_file = output_file(output_dirname + "/Frontend.cpp") 90 if not isinstance(json, dict):
2020 91 return
2021 typebuilder_h_file = output_file(output_dirname + "/TypeBuilder.h") 92 for key in json:
2022 typebuilder_cpp_file = output_file(output_dirname + "/TypeBuilder.cpp") 93 if key != "$ref":
2023 94 patch_full_qualified_refs_in_domain(json[key], domain_name)
2024 95 continue
2025 backend_h_file.write(Templates.backend_h.substitute(None, 96 if json["$ref"].find(".") == -1:
2026 virtualSetters="\n".join(Generator.backend_virtual_setters_list), 97 json["$ref"] = domain_name + "." + json["$ref"]
2027 agentInterfaces="".join(flatten_list(Generator.backend_agent_interface_list) ), 98
2028 methodNamesEnumContent="\n".join(Generator.method_name_enum_list))) 99 for domain in json_api["domains"]:
2029 100 patch_full_qualified_refs_in_domain(domain, domain["domain"])
2030 backend_cpp_file.write(Templates.backend_cpp.substitute(None, 101
2031 constructorInit="\n".join(Generator.backend_constructor_init_list), 102
2032 setters="\n".join(Generator.backend_setters_list), 103 def create_user_type_definition(domain_name, type):
2033 fieldDeclarations="\n".join(Generator.backend_field_list), 104 return {
2034 methodNameDeclarations="\n".join(Generator.backend_method_name_declaration_l ist), 105 "return_type": "PassOwnPtr<protocol::%s::%s>" % (domain_name, type["id"] ),
2035 methodNameDeclarationsIndex="\n".join(Generator.backend_method_name_declarat ion_index_list), 106 "pass_type": "PassOwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
2036 methods="\n".join(Generator.backend_method_implementation_list), 107 "to_pass_type": "%s.release()",
2037 methodDeclarations="\n".join(Generator.backend_method_declaration_list), 108 "type": "OwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
2038 messageHandlers="\n".join(Generator.method_handler_list))) 109 "raw_type": "protocol::%s::%s" % (domain_name, type["id"]),
2039 110 "create_type": "adoptPtr(new protocol::%s::%s())" % (domain_name, type[" id"]),
2040 frontend_h_file.write(Templates.frontend_h.substitute(None, 111 "optional_type": "OwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
2041 fieldDeclarations="".join(Generator.frontend_class_field_lines), 112 "optional_pass_type": "PassOwnPtr<protocol::%s::%s>" % (domain_name, typ e["id"]),
2042 domainClassList="".join(Generator.frontend_domain_class_lines))) 113 "from_optional_out": "%s.release()",
2043 114 "json_getter": "FromValue<protocol::%s::%s>::convert(getObject(%%s))" % (domain_name, type["id"]),
2044 frontend_cpp_file.write(Templates.frontend_cpp.substitute(None, 115 "json_type": "TypeObject",
2045 constructorInit="".join(Generator.frontend_constructor_init_list), 116 "nullable": True,
2046 methods="\n".join(Generator.frontend_method_list))) 117 }
2047 118
2048 typebuilder_h_file.write(Templates.typebuilder_h.substitute(None, 119
2049 typeBuilders="".join(flatten_list(Generator.type_builder_fragments)), 120 def create_object_type_definition():
2050 forwards="".join(Generator.type_builder_forwards), 121 return {
2051 validatorIfdefName=VALIDATOR_IFDEF_NAME)) 122 "return_type": "PassRefPtr<JSONObject>",
2052 123 "pass_type": "PassRefPtr<JSONObject>",
2053 typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None, 124 "to_pass_type": "%s.release()",
2054 enumConstantValues=EnumConstants.get_enum_constant_code(), 125 "type": "RefPtr<JSONObject>",
2055 implCode="".join(flatten_list(Generator.type_builder_impl_list)), 126 "raw_type": "RefPtr<JSONObject>",
2056 validatorCode="".join(flatten_list(Generator.validator_impl_list)), 127 "optional_type": "RefPtr<JSONObject>",
2057 validatorIfdefName=VALIDATOR_IFDEF_NAME)) 128 "optional_pass_type": "PassRefPtr<JSONObject>",
2058 129 "from_optional_out": "%s.release()",
2059 backend_h_file.close() 130 "json_getter": "getObject(%s)",
2060 backend_cpp_file.close() 131 "json_type": "TypeObject",
2061 132 "nullable": True,
2062 frontend_h_file.close() 133 }
2063 frontend_cpp_file.close() 134
2064 135
2065 typebuilder_h_file.close() 136 def create_any_type_definition():
2066 typebuilder_cpp_file.close() 137 return {
138 "return_type": "PassRefPtr<JSONValue>",
139 "pass_type": "PassRefPtr<JSONValue>",
140 "to_pass_type": "%s.release()",
141 "type": "RefPtr<JSONValue>",
142 "raw_type": "RefPtr<JSONValue>",
143 "optional_type": "RefPtr<JSONValue>",
144 "optional_pass_type": "PassRefPtr<JSONValue>",
145 "from_optional_out": "%s.release()",
146 "json_getter": "getValue(%s)",
147 "nullable": True,
148 }
149
150
151 def create_primitive_type_definition(type):
152 if type == "string":
153 return {
154 "return_type": "String",
155 "pass_type": "const String&",
156 "to_pass_type": "%s",
157 "type": "String",
158 "raw_type": "String",
159 "optional_type": "protocol::OptionalValue<String>",
160 "optional_pass_type": "const protocol::OptionalValue<String>&",
161 "from_optional_out": "%s.get()",
162 "json_getter": "getString(%s)",
163 "json_type": "TypeString",
164 "nullable": False,
165 }
166
167 typedefs = {
168 "number": "double",
169 "integer": "int",
170 "boolean": "bool"
171 }
172 jsontypes = {
173 "number": "TypeNumber",
174 "integer": "TypeNumber",
175 "boolean": "TypeBoolean",
176 }
177 return {
178 "return_type": typedefs[type],
179 "pass_type": typedefs[type],
180 "to_pass_type": "%s",
181 "type": typedefs[type],
182 "raw_type": typedefs[type],
183 "optional_type": "protocol::OptionalValue<" + typedefs[type] + ">",
184 "optional_pass_type": "const protocol::OptionalValue<" + typedefs[type] + ">&",
185 "from_optional_out": "%s.get()",
186 "json_getter": "get" + to_title_case(type) + "(%s)",
187 "json_type": jsontypes[type],
188 "nullable": False,
189 }
190
191 type_definitions = {}
192 type_definitions["string"] = create_primitive_type_definition("string")
193 type_definitions["number"] = create_primitive_type_definition("number")
194 type_definitions["integer"] = create_primitive_type_definition("integer")
195 type_definitions["boolean"] = create_primitive_type_definition("boolean")
196 type_definitions["object"] = create_object_type_definition()
197 type_definitions["any"] = create_any_type_definition()
198
199
200 def wrap_array_definition(type):
201 return {
202 "return_type": "PassOwnPtr<protocol::Array<%s>>" % type["raw_type"],
203 "pass_type": "PassOwnPtr<protocol::Array<%s>>" % type["raw_type"],
204 "to_pass_type": "%s.release()",
205 "type": "OwnPtr<protocol::Array<%s>>" % type["raw_type"],
206 "raw_type": "protocol::Array<%s>" % type["raw_type"],
207 "create_type": "adoptPtr(new protocol::Array<%s>())" % type["raw_type"],
208 "out_type": "protocol::Array<%s>&" % type["raw_type"],
209 "optional_type": "OwnPtr<protocol::Array<%s>>" % type["raw_type"],
210 "optional_pass_type": "PassOwnPtr<protocol::Array<%s>>" % type["raw_type "],
211 "from_optional_out": "%s.release()",
212 "json_getter": "protocol::Array<%s>::runtimeCast(getArray(%%s))" % type[ "raw_type"],
213 "json_type": "TypeArray",
214 "nullable": True,
215 }
216
217
218 def create_type_definitions():
219 for domain in json_api["domains"]:
220 if not ("types" in domain):
221 continue
222 for type in domain["types"]:
223 if type["type"] == "object":
224 type_definitions[domain["domain"] + "." + type["id"]] = create_u ser_type_definition(domain["domain"], type)
225 elif type["type"] == "array":
226 items_type = type["items"]["type"]
227 type_definitions[domain["domain"] + "." + type["id"]] = wrap_arr ay_definition(type_definitions[items_type])
228 else:
229 type_definitions[domain["domain"] + "." + type["id"]] = create_p rimitive_type_definition(type["type"])
230
231 patch_full_qualified_refs()
232 create_type_definitions()
233
234
235 def type_definition(name):
236 return type_definitions[name]
237
238
239 def resolve_type(property):
240 if "$ref" in property:
241 return type_definitions[property["$ref"]]
242 if property["type"] == "array":
243 return wrap_array_definition(resolve_type(property["items"]))
244 return type_definitions[property["type"]]
245
246
247 def join_arrays(dict, keys):
248 result = []
249 for key in keys:
250 if key in dict:
251 result += dict[key]
252 return result
253
254
255 def generate(class_name):
256 template_context = {
257 "class_name": class_name,
258 "api": json_api,
259 "join_arrays": join_arrays,
260 "resolve_type": resolve_type,
261 "type_definition": type_definition
262 }
263 h_template = jinja_env.get_template("/%s_h.template" % class_name)
264 cpp_template = jinja_env.get_template("/%s_cpp.template" % class_name)
265 h_file = output_file(output_dirname + "/" + class_name + ".h")
266 cpp_file = output_file(output_dirname + "/" + class_name + ".cpp")
267 h_file.write(h_template.render(template_context))
268 cpp_file.write(cpp_template.render(template_context))
269 h_file.close()
270 cpp_file.close()
271
272
273 jinja_env = initialize_jinja_env(output_dirname)
274 generate("Dispatcher")
275 generate("Frontend")
276 generate("TypeBuilder")
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698