1 #!/usr/bin/env python 2 # Copyright (c) 2011 Google Inc. All rights reserved. 3 # Copyright (c) 2012 Intel Corporation. All rights reserved. 4 # 5 # Redistribution and use in source and binary forms, with or without 6 # modification, are permitted provided that the following conditions are 7 # met: 8 # 9 # * Redistributions of source code must retain the above copyright 10 # notice, this list of conditions and the following disclaimer. 11 # * Redistributions in binary form must reproduce the above 12 # copyright notice, this list of conditions and the following disclaimer 13 # in the documentation and/or other materials provided with the 14 # distribution. 15 # * Neither the name of Google Inc. nor the names of its 16 # contributors may be used to endorse or promote products derived from 17 # this software without specific prior written permission. 18 # 19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 import os.path 32 import sys 33 import string 34 import optparse 35 import re 36 try: 37 import json 38 except ImportError: 39 import simplejson as json 40 41 import CodeGeneratorInspectorStrings 42 43 # Manually-filled map of type name replacements. 44 TYPE_NAME_FIX_MAP = { 45 "RGBA": "Rgba", # RGBA is reported to be conflicting with a define name in Windows CE. 46 "": "Empty", 47 } 48 49 50 TYPES_WITH_RUNTIME_CAST_SET = frozenset(["Runtime.RemoteObject", "Runtime.PropertyDescriptor", "Runtime.InternalPropertyDescriptor", 51 "Debugger.FunctionDetails", "Debugger.CallFrame", "Debugger.Location", 52 "Canvas.TraceLog", "Canvas.ResourceState"]) 53 54 TYPES_WITH_OPEN_FIELD_LIST_SET = frozenset([ 55 # InspectorStyleSheet not only creates this property but wants to read it and modify it. 56 "CSS.CSSProperty", 57 # InspectorResourceAgent needs to update mime-type. 58 "Network.Response"]) 59 60 EXACTLY_INT_SUPPORTED = False 61 62 cmdline_parser = optparse.OptionParser() 63 cmdline_parser.add_option("--output_dir") 64 65 try: 66 arg_options, arg_values = cmdline_parser.parse_args() 67 if (len(arg_values) != 1): 68 raise Exception("Exactly one plain argument expected (found %s)" % len(arg_values)) 69 input_json_filename = arg_values[0] 70 output_dirname = arg_options.output_dir 71 if not output_dirname: 72 raise Exception("Output directory must be specified") 73 except Exception: 74 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html 75 exc = sys.exc_info()[1] 76 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) 77 sys.stderr.write("Usage: <script> --output_dir <output_dir> protocol.json\n") 78 exit(1) 79 80 81 # FIXME: move this methods under Capitalizer class below and remove duplications. 82 def dash_to_camelcase(word): 83 return ''.join(x.capitalize() or '-' for x in word.split('-')) 84 85 86 def fix_camel_case(name): 87 refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name) 88 refined = to_title_case(refined) 89 return re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), refined) 90 91 92 def to_title_case(name): 93 return name[:1].upper() + name[1:] 94 95 96 class Capitalizer: 97 @staticmethod 98 def lower_camel_case_to_upper(str): 99 if len(str) > 0 and str[0].islower(): 100 str = str[0].upper() + str[1:] 101 return str 102 103 @staticmethod 104 def upper_camel_case_to_lower(str): 105 pos = 0 106 while pos < len(str) and str[pos].isupper(): 107 pos += 1 108 if pos == 0: 109 return str 110 if pos == 1: 111 return str[0].lower() + str[1:] 112 if pos < len(str): 113 pos -= 1 114 possible_abbreviation = str[0:pos] 115 if possible_abbreviation not in Capitalizer.ABBREVIATION: 116 raise Exception("Unknown abbreviation %s" % possible_abbreviation) 117 str = possible_abbreviation.lower() + str[pos:] 118 return str 119 120 @staticmethod 121 def camel_case_to_capitalized_with_underscores(str): 122 if len(str) == 0: 123 return str 124 output = Capitalizer.split_camel_case_(str) 125 return "_".join(output).upper() 126 127 @staticmethod 128 def split_camel_case_(str): 129 output = [] 130 pos_being = 0 131 pos = 1 132 has_oneletter = False 133 while pos < len(str): 134 if str[pos].isupper(): 135 output.append(str[pos_being:pos].upper()) 136 if pos - pos_being == 1: 137 has_oneletter = True 138 pos_being = pos 139 pos += 1 140 output.append(str[pos_being:]) 141 if has_oneletter: 142 array_pos = 0 143 while array_pos < len(output) - 1: 144 if len(output[array_pos]) == 1: 145 array_pos_end = array_pos + 1 146 while array_pos_end < len(output) and len(output[array_pos_end]) == 1: 147 array_pos_end += 1 148 if array_pos_end - array_pos > 1: 149 possible_abbreviation = "".join(output[array_pos:array_pos_end]) 150 if possible_abbreviation.upper() in Capitalizer.ABBREVIATION: 151 output[array_pos:array_pos_end] = [possible_abbreviation] 152 else: 153 array_pos = array_pos_end - 1 154 array_pos += 1 155 return output 156 157 ABBREVIATION = frozenset(["XHR", "DOM", "CSS"]) 158 159 VALIDATOR_IFDEF_NAME = "ASSERT_ENABLED" 160 161 162 class DomainNameFixes: 163 @classmethod 164 def get_fixed_data(cls, domain_name): 165 field_name_res = Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent" 166 167 class Res(object): 168 agent_field_name = field_name_res 169 170 return Res 171 172 173 class RawTypes(object): 174 @staticmethod 175 def get(json_type): 176 if json_type == "boolean": 177 return RawTypes.Bool 178 elif json_type == "string": 179 return RawTypes.String 180 elif json_type == "array": 181 return RawTypes.Array 182 elif json_type == "object": 183 return RawTypes.Object 184 elif json_type == "integer": 185 return RawTypes.Int 186 elif json_type == "number": 187 return RawTypes.Number 188 elif json_type == "any": 189 return RawTypes.Any 190 else: 191 raise Exception("Unknown type: %s" % json_type) 192 193 # For output parameter all values are passed by pointer except RefPtr-based types. 194 class OutputPassModel: 195 class ByPointer: 196 @staticmethod 197 def get_argument_prefix(): 198 return "&" 199 200 @staticmethod 201 def get_parameter_type_suffix(): 202 return "*" 203 204 class ByReference: 205 @staticmethod 206 def get_argument_prefix(): 207 return "" 208 209 @staticmethod 210 def get_parameter_type_suffix(): 211 return "&" 212 213 class BaseType(object): 214 need_internal_runtime_cast_ = False 215 216 @classmethod 217 def request_raw_internal_runtime_cast(cls): 218 if not cls.need_internal_runtime_cast_: 219 cls.need_internal_runtime_cast_ = True 220 221 @classmethod 222 def get_raw_validator_call_text(cls): 223 return "RuntimeCastHelper::assertType<JSONValue::Type%s>" % cls.get_validate_method_params().template_type 224 225 @staticmethod 226 def get_validate_method_params(): 227 raise Exception("Abstract method") 228 229 class String(BaseType): 230 @staticmethod 231 def get_getter_name(): 232 return "String" 233 234 get_setter_name = get_getter_name 235 236 @staticmethod 237 def get_constructor_pattern(): 238 return "InspectorString::create(%s)" 239 240 @staticmethod 241 def get_c_initializer(): 242 return "\"\"" 243 244 @staticmethod 245 def get_validate_method_params(): 246 class ValidateMethodParams: 247 template_type = "String" 248 return ValidateMethodParams 249 250 @staticmethod 251 def get_output_pass_model(): 252 return RawTypes.OutputPassModel.ByPointer 253 254 @staticmethod 255 def is_heavy_value(): 256 return True 257 258 @staticmethod 259 def get_array_item_raw_c_type_text(): 260 return "String" 261 262 @staticmethod 263 def get_raw_type_model(): 264 return TypeModel.String 265 266 class Int(BaseType): 267 @staticmethod 268 def get_getter_name(): 269 return "Int" 270 271 @staticmethod 272 def get_setter_name(): 273 return "Number" 274 275 @staticmethod 276 def get_constructor_pattern(): 277 return "InspectorBasicValue::create(%s)" 278 279 @staticmethod 280 def get_c_initializer(): 281 return "0" 282 283 @classmethod 284 def get_raw_validator_call_text(cls): 285 return "RuntimeCastHelper::assertInt" 286 287 @staticmethod 288 def get_output_pass_model(): 289 return RawTypes.OutputPassModel.ByPointer 290 291 @staticmethod 292 def is_heavy_value(): 293 return False 294 295 @staticmethod 296 def get_array_item_raw_c_type_text(): 297 return "int" 298 299 @staticmethod 300 def get_raw_type_model(): 301 return TypeModel.Int 302 303 class Number(BaseType): 304 @staticmethod 305 def get_getter_name(): 306 return "Double" 307 308 @staticmethod 309 def get_setter_name(): 310 return "Number" 311 312 @staticmethod 313 def get_constructor_pattern(): 314 return "InspectorBasicValue::create(%s)" 315 316 @staticmethod 317 def get_c_initializer(): 318 return "0" 319 320 @staticmethod 321 def get_validate_method_params(): 322 class ValidateMethodParams: 323 template_type = "Number" 324 return ValidateMethodParams 325 326 @staticmethod 327 def get_output_pass_model(): 328 return RawTypes.OutputPassModel.ByPointer 329 330 @staticmethod 331 def is_heavy_value(): 332 return False 333 334 @staticmethod 335 def get_array_item_raw_c_type_text(): 336 return "double" 337 338 @staticmethod 339 def get_raw_type_model(): 340 return TypeModel.Number 341 342 class Bool(BaseType): 343 @staticmethod 344 def get_getter_name(): 345 return "Boolean" 346 347 get_setter_name = get_getter_name 348 349 @staticmethod 350 def get_constructor_pattern(): 351 return "InspectorBasicValue::create(%s)" 352 353 @staticmethod 354 def get_c_initializer(): 355 return "false" 356 357 @staticmethod 358 def get_validate_method_params(): 359 class ValidateMethodParams: 360 template_type = "Boolean" 361 return ValidateMethodParams 362 363 @staticmethod 364 def get_output_pass_model(): 365 return RawTypes.OutputPassModel.ByPointer 366 367 @staticmethod 368 def is_heavy_value(): 369 return False 370 371 @staticmethod 372 def get_array_item_raw_c_type_text(): 373 return "bool" 374 375 @staticmethod 376 def get_raw_type_model(): 377 return TypeModel.Bool 378 379 class Object(BaseType): 380 @staticmethod 381 def get_getter_name(): 382 return "Object" 383 384 @staticmethod 385 def get_setter_name(): 386 return "Value" 387 388 @staticmethod 389 def get_constructor_pattern(): 390 return "%s" 391 392 @staticmethod 393 def get_c_initializer(): 394 return "JSONObject::create()" 395 396 @staticmethod 397 def get_output_argument_prefix(): 398 return "" 399 400 @staticmethod 401 def get_validate_method_params(): 402 class ValidateMethodParams: 403 template_type = "Object" 404 return ValidateMethodParams 405 406 @staticmethod 407 def get_output_pass_model(): 408 return RawTypes.OutputPassModel.ByReference 409 410 @staticmethod 411 def is_heavy_value(): 412 return True 413 414 @staticmethod 415 def get_array_item_raw_c_type_text(): 416 return "JSONObject" 417 418 @staticmethod 419 def get_raw_type_model(): 420 return TypeModel.Object 421 422 class Any(BaseType): 423 @staticmethod 424 def get_getter_name(): 425 return "Value" 426 427 get_setter_name = get_getter_name 428 429 @staticmethod 430 def get_c_initializer(): 431 raise Exception("Unsupported") 432 433 @staticmethod 434 def get_constructor_pattern(): 435 raise Exception("Unsupported") 436 437 @staticmethod 438 def get_raw_validator_call_text(): 439 return "RuntimeCastHelper::assertAny" 440 441 @staticmethod 442 def get_output_pass_model(): 443 return RawTypes.OutputPassModel.ByReference 444 445 @staticmethod 446 def is_heavy_value(): 447 return True 448 449 @staticmethod 450 def get_array_item_raw_c_type_text(): 451 return "JSONValue" 452 453 @staticmethod 454 def get_raw_type_model(): 455 return TypeModel.Any 456 457 class Array(BaseType): 458 @staticmethod 459 def get_getter_name(): 460 return "Array" 461 462 @staticmethod 463 def get_setter_name(): 464 return "Value" 465 466 @staticmethod 467 def get_constructor_pattern(): 468 return "%s" 469 470 @staticmethod 471 def get_c_initializer(): 472 return "JSONArray::create()" 473 474 @staticmethod 475 def get_output_argument_prefix(): 476 return "" 477 478 @staticmethod 479 def get_validate_method_params(): 480 class ValidateMethodParams: 481 template_type = "Array" 482 return ValidateMethodParams 483 484 @staticmethod 485 def get_output_pass_model(): 486 return RawTypes.OutputPassModel.ByReference 487 488 @staticmethod 489 def is_heavy_value(): 490 return True 491 492 @staticmethod 493 def get_array_item_raw_c_type_text(): 494 return "JSONArray" 495 496 @staticmethod 497 def get_raw_type_model(): 498 return TypeModel.Array 499 500 501 def replace_right_shift(input_str): 502 return input_str.replace(">>", "> >") 503 504 505 class CommandReturnPassModel: 506 class ByReference: 507 def __init__(self, var_type, set_condition): 508 self.var_type = var_type 509 self.set_condition = set_condition 510 511 def get_return_var_type(self): 512 return self.var_type 513 514 @staticmethod 515 def get_output_argument_prefix(): 516 return "" 517 518 @staticmethod 519 def get_output_to_raw_expression(): 520 return "%s" 521 522 def get_output_parameter_type(self): 523 return self.var_type + "&" 524 525 def get_set_return_condition(self): 526 return self.set_condition 527 528 class ByPointer: 529 def __init__(self, var_type): 530 self.var_type = var_type 531 532 def get_return_var_type(self): 533 return self.var_type 534 535 @staticmethod 536 def get_output_argument_prefix(): 537 return "&" 538 539 @staticmethod 540 def get_output_to_raw_expression(): 541 return "%s" 542 543 def get_output_parameter_type(self): 544 return self.var_type + "*" 545 546 @staticmethod 547 def get_set_return_condition(): 548 return None 549 550 class OptOutput: 551 def __init__(self, var_type): 552 self.var_type = var_type 553 554 def get_return_var_type(self): 555 return "TypeBuilder::OptOutput<%s>" % self.var_type 556 557 @staticmethod 558 def get_output_argument_prefix(): 559 return "&" 560 561 @staticmethod 562 def get_output_to_raw_expression(): 563 return "%s.getValue()" 564 565 def get_output_parameter_type(self): 566 return "TypeBuilder::OptOutput<%s>*" % self.var_type 567 568 @staticmethod 569 def get_set_return_condition(): 570 return "%s.isAssigned()" 571 572 573 class TypeModel: 574 class RefPtrBased(object): 575 def __init__(self, class_name): 576 self.class_name = class_name 577 self.optional = False 578 579 def get_optional(self): 580 result = TypeModel.RefPtrBased(self.class_name) 581 result.optional = True 582 return result 583 584 def get_command_return_pass_model(self): 585 if self.optional: 586 set_condition = "%s" 587 else: 588 set_condition = None 589 return CommandReturnPassModel.ByReference(replace_right_shift("RefPtr<%s>" % self.class_name), set_condition) 590 591 def get_input_param_type_text(self): 592 return replace_right_shift("PassRefPtr<%s>" % self.class_name) 593 594 @staticmethod 595 def get_event_setter_expression_pattern(): 596 return "%s" 597 598 class Enum(object): 599 def __init__(self, base_type_name): 600 self.type_name = base_type_name + "::Enum" 601 602 def get_optional(base_self): 603 class EnumOptional: 604 @classmethod 605 def get_optional(cls): 606 return cls 607 608 @staticmethod 609 def get_command_return_pass_model(): 610 return CommandReturnPassModel.OptOutput(base_self.type_name) 611 612 @staticmethod 613 def get_input_param_type_text(): 614 return base_self.type_name + "*" 615 616 @staticmethod 617 def get_event_setter_expression_pattern(): 618 raise Exception("TODO") 619 return EnumOptional 620 621 def get_command_return_pass_model(self): 622 return CommandReturnPassModel.ByPointer(self.type_name) 623 624 def get_input_param_type_text(self): 625 return self.type_name 626 627 @staticmethod 628 def get_event_setter_expression_pattern(): 629 return "%s" 630 631 class ValueType(object): 632 def __init__(self, type_name, is_heavy): 633 self.type_name = type_name 634 self.is_heavy = is_heavy 635 636 def get_optional(self): 637 return self.ValueOptional(self) 638 639 def get_command_return_pass_model(self): 640 return CommandReturnPassModel.ByPointer(self.type_name) 641 642 def get_input_param_type_text(self): 643 if self.is_heavy: 644 return "const %s&" % self.type_name 645 else: 646 return self.type_name 647 648 def get_opt_output_type_(self): 649 return self.type_name 650 651 @staticmethod 652 def get_event_setter_expression_pattern(): 653 return "%s" 654 655 class ValueOptional: 656 def __init__(self, base): 657 self.base = base 658 659 def get_optional(self): 660 return self 661 662 def get_command_return_pass_model(self): 663 return CommandReturnPassModel.OptOutput(self.base.get_opt_output_type_()) 664 665 def get_input_param_type_text(self): 666 return "const %s* const" % self.base.type_name 667 668 @staticmethod 669 def get_event_setter_expression_pattern(): 670 return "*%s" 671 672 class ExactlyInt(ValueType): 673 def __init__(self): 674 TypeModel.ValueType.__init__(self, "int", False) 675 676 def get_input_param_type_text(self): 677 return "TypeBuilder::ExactlyInt" 678 679 def get_opt_output_type_(self): 680 return "TypeBuilder::ExactlyInt" 681 682 @classmethod 683 def init_class(cls): 684 cls.Bool = cls.ValueType("bool", False) 685 if EXACTLY_INT_SUPPORTED: 686 cls.Int = cls.ExactlyInt() 687 else: 688 cls.Int = cls.ValueType("int", False) 689 cls.Number = cls.ValueType("double", False) 690 cls.String = cls.ValueType("String", True,) 691 cls.Object = cls.RefPtrBased("JSONObject") 692 cls.Array = cls.RefPtrBased("JSONArray") 693 cls.Any = cls.RefPtrBased("JSONValue") 694 695 TypeModel.init_class() 696 697 698 # Collection of JSONObject class methods that are likely to be overloaded in generated class. 699 # We must explicitly import all overloaded methods or they won't be available to user. 700 INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"]) 701 702 703 def fix_type_name(json_name): 704 if json_name in TYPE_NAME_FIX_MAP: 705 fixed = TYPE_NAME_FIX_MAP[json_name] 706 707 class Result(object): 708 class_name = fixed 709 710 @staticmethod 711 def output_comment(writer): 712 writer.newline("// Type originally was named '%s'.\n" % json_name) 713 else: 714 715 class Result(object): 716 class_name = json_name 717 718 @staticmethod 719 def output_comment(writer): 720 pass 721 722 return Result 723 724 725 class Writer: 726 def __init__(self, output, indent): 727 self.output = output 728 self.indent = indent 729 730 def newline(self, str): 731 if (self.indent): 732 self.output.append(self.indent) 733 self.output.append(str) 734 735 def append(self, str): 736 self.output.append(str) 737 738 def newline_multiline(self, str): 739 parts = str.split('\n') 740 self.newline(parts[0]) 741 for p in parts[1:]: 742 self.output.append('\n') 743 if p: 744 self.newline(p) 745 746 def append_multiline(self, str): 747 parts = str.split('\n') 748 self.append(parts[0]) 749 for p in parts[1:]: 750 self.output.append('\n') 751 if p: 752 self.newline(p) 753 754 def get_indent(self): 755 return self.indent 756 757 def get_indented(self, additional_indent): 758 return Writer(self.output, self.indent + additional_indent) 759 760 def insert_writer(self, additional_indent): 761 new_output = [] 762 self.output.append(new_output) 763 return Writer(new_output, self.indent + additional_indent) 764 765 766 class EnumConstants: 767 map_ = {} 768 constants_ = [] 769 770 @classmethod 771 def add_constant(cls, value): 772 if value in cls.map_: 773 return cls.map_[value] 774 else: 775 pos = len(cls.map_) 776 cls.map_[value] = pos 777 cls.constants_.append(value) 778 return pos 779 780 @classmethod 781 def get_enum_constant_code(cls): 782 output = [] 783 for item in cls.constants_: 784 output.append(" \"" + item + "\"") 785 return ",\n".join(output) + "\n" 786 787 788 # Typebuilder code is generated in several passes: first typedefs, then other classes. 789 # Manual pass management is needed because we cannot have forward declarations for typedefs. 790 class TypeBuilderPass: 791 TYPEDEF = "typedef" 792 MAIN = "main" 793 794 795 class TypeBindings: 796 @staticmethod 797 def create_named_type_declaration(json_typable, context_domain_name, type_data): 798 json_type = type_data.get_json_type() 799 800 class Helper: 801 is_ad_hoc = False 802 full_name_prefix_for_use = "TypeBuilder::" + context_domain_name + "::" 803 full_name_prefix_for_impl = "TypeBuilder::" + context_domain_name + "::" 804 805 @staticmethod 806 def write_doc(writer): 807 if "description" in json_type: 808 writer.newline("/* ") 809 writer.append(json_type["description"]) 810 writer.append(" */\n") 811 812 @staticmethod 813 def add_to_forward_listener(forward_listener): 814 forward_listener.add_type_data(type_data) 815 816 817 fixed_type_name = fix_type_name(json_type["id"]) 818 return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper) 819 820 @staticmethod 821 def create_ad_hoc_type_declaration(json_typable, context_domain_name, ad_hoc_type_context): 822 class Helper: 823 is_ad_hoc = True 824 full_name_prefix_for_use = ad_hoc_type_context.container_relative_name_prefix 825 full_name_prefix_for_impl = ad_hoc_type_context.container_full_name_prefix 826 827 @staticmethod 828 def write_doc(writer): 829 pass 830 831 @staticmethod 832 def add_to_forward_listener(forward_listener): 833 pass 834 fixed_type_name = ad_hoc_type_context.get_type_name_fix() 835 return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper) 836 837 @staticmethod 838 def create_type_declaration_(json_typable, context_domain_name, fixed_type_name, helper): 839 if json_typable["type"] == "string": 840 if "enum" in json_typable: 841 842 class EnumBinding: 843 need_user_runtime_cast_ = False 844 need_internal_runtime_cast_ = False 845 846 @classmethod 847 def resolve_inner(cls, resolve_context): 848 pass 849 850 @classmethod 851 def request_user_runtime_cast(cls, request): 852 if request: 853 cls.need_user_runtime_cast_ = True 854 request.acknowledge() 855 856 @classmethod 857 def request_internal_runtime_cast(cls): 858 cls.need_internal_runtime_cast_ = True 859 860 @classmethod 861 def get_code_generator(enum_binding_cls): 862 #FIXME: generate ad-hoc enums too once we figure out how to better implement them in C++. 863 comment_out = helper.is_ad_hoc 864 865 class CodeGenerator: 866 @staticmethod 867 def generate_type_builder(writer, generate_context): 868 enum = json_typable["enum"] 869 helper.write_doc(writer) 870 enum_name = fixed_type_name.class_name 871 fixed_type_name.output_comment(writer) 872 writer.newline("struct ") 873 writer.append(enum_name) 874 writer.append(" {\n") 875 writer.newline(" enum Enum {\n") 876 for enum_item in enum: 877 enum_pos = EnumConstants.add_constant(enum_item) 878 879 item_c_name = enum_item.replace('-', '_') 880 item_c_name = Capitalizer.lower_camel_case_to_upper(item_c_name) 881 if item_c_name in TYPE_NAME_FIX_MAP: 882 item_c_name = TYPE_NAME_FIX_MAP[item_c_name] 883 writer.newline(" ") 884 writer.append(item_c_name) 885 writer.append(" = ") 886 writer.append("%s" % enum_pos) 887 writer.append(",\n") 888 writer.newline(" };\n") 889 if enum_binding_cls.need_user_runtime_cast_: 890 raise Exception("Not yet implemented") 891 892 if enum_binding_cls.need_internal_runtime_cast_: 893 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME) 894 writer.newline(" static void assertCorrectValue(JSONValue* value);\n") 895 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME) 896 897 validator_writer = generate_context.validator_writer 898 899 domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name) 900 901 validator_writer.newline("void %s%s::assertCorrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, enum_name)) 902 validator_writer.newline("{\n") 903 validator_writer.newline(" WTF::String s;\n") 904 validator_writer.newline(" bool cast_res = value->asString(&s);\n") 905 validator_writer.newline(" ASSERT(cast_res);\n") 906 if len(enum) > 0: 907 condition_list = [] 908 for enum_item in enum: 909 enum_pos = EnumConstants.add_constant(enum_item) 910 condition_list.append("s == \"%s\"" % enum_item) 911 validator_writer.newline(" ASSERT(%s);\n" % " || ".join(condition_list)) 912 validator_writer.newline("}\n") 913 914 validator_writer.newline("\n\n") 915 916 writer.newline("}; // struct ") 917 writer.append(enum_name) 918 writer.append("\n\n") 919 920 @staticmethod 921 def register_use(forward_listener): 922 pass 923 924 @staticmethod 925 def get_generate_pass_id(): 926 return TypeBuilderPass.MAIN 927 928 return CodeGenerator 929 930 @classmethod 931 def get_validator_call_text(cls): 932 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue" 933 934 @classmethod 935 def get_array_item_c_type_text(cls): 936 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::Enum" 937 938 @staticmethod 939 def get_setter_value_expression_pattern(): 940 return "TypeBuilder::getEnumConstantValue(%s)" 941 942 @staticmethod 943 def reduce_to_raw_type(): 944 return RawTypes.String 945 946 @staticmethod 947 def get_type_model(): 948 return TypeModel.Enum(helper.full_name_prefix_for_use + fixed_type_name.class_name) 949 950 return EnumBinding 951 else: 952 if helper.is_ad_hoc: 953 954 class PlainString: 955 @classmethod 956 def resolve_inner(cls, resolve_context): 957 pass 958 959 @staticmethod 960 def request_user_runtime_cast(request): 961 raise Exception("Unsupported") 962 963 @staticmethod 964 def request_internal_runtime_cast(): 965 pass 966 967 @staticmethod 968 def get_code_generator(): 969 return None 970 971 @classmethod 972 def get_validator_call_text(cls): 973 return RawTypes.String.get_raw_validator_call_text() 974 975 @staticmethod 976 def reduce_to_raw_type(): 977 return RawTypes.String 978 979 @staticmethod 980 def get_type_model(): 981 return TypeModel.String 982 983 @staticmethod 984 def get_setter_value_expression_pattern(): 985 return None 986 987 @classmethod 988 def get_array_item_c_type_text(cls): 989 return cls.reduce_to_raw_type().get_array_item_raw_c_type_text() 990 991 return PlainString 992 993 else: 994 995 class TypedefString: 996 @classmethod 997 def resolve_inner(cls, resolve_context): 998 pass 999 1000 @staticmethod 1001 def request_user_runtime_cast(request): 1002 raise Exception("Unsupported") 1003 1004 @staticmethod 1005 def request_internal_runtime_cast(): 1006 RawTypes.String.request_raw_internal_runtime_cast() 1007 1008 @staticmethod 1009 def get_code_generator(): 1010 class CodeGenerator: 1011 @staticmethod 1012 def generate_type_builder(writer, generate_context): 1013 helper.write_doc(writer) 1014 fixed_type_name.output_comment(writer) 1015 writer.newline("typedef String ") 1016 writer.append(fixed_type_name.class_name) 1017 writer.append(";\n\n") 1018 1019 @staticmethod 1020 def register_use(forward_listener): 1021 pass 1022 1023 @staticmethod 1024 def get_generate_pass_id(): 1025 return TypeBuilderPass.TYPEDEF 1026 1027 return CodeGenerator 1028 1029 @classmethod 1030 def get_validator_call_text(cls): 1031 return RawTypes.String.get_raw_validator_call_text() 1032 1033 @staticmethod 1034 def reduce_to_raw_type(): 1035 return RawTypes.String 1036 1037 @staticmethod 1038 def get_type_model(): 1039 return TypeModel.ValueType("%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name), True) 1040 1041 @staticmethod 1042 def get_setter_value_expression_pattern(): 1043 return None 1044 1045 @classmethod 1046 def get_array_item_c_type_text(cls): 1047 return "%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name) 1048 1049 return TypedefString 1050 1051 elif json_typable["type"] == "object": 1052 if "properties" in json_typable: 1053 1054 class ClassBinding: 1055 resolve_data_ = None 1056 need_user_runtime_cast_ = False 1057 need_internal_runtime_cast_ = False 1058 1059 @classmethod 1060 def resolve_inner(cls, resolve_context): 1061 if cls.resolve_data_: 1062 return 1063 1064 properties = json_typable["properties"] 1065 main = [] 1066 optional = [] 1067 1068 ad_hoc_type_list = [] 1069 1070 for prop in properties: 1071 prop_name = prop["name"] 1072 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) 1073 binding = resolve_param_type(prop, context_domain_name, ad_hoc_type_context) 1074 1075 code_generator = binding.get_code_generator() 1076 if code_generator: 1077 code_generator.register_use(resolve_context.forward_listener) 1078 1079 class PropertyData: 1080 param_type_binding = binding 1081 p = prop 1082 1083 if prop.get("optional"): 1084 optional.append(PropertyData) 1085 else: 1086 main.append(PropertyData) 1087 1088 class ResolveData: 1089 main_properties = main 1090 optional_properties = optional 1091 ad_hoc_types = ad_hoc_type_list 1092 1093 cls.resolve_data_ = ResolveData 1094 1095 for ad_hoc in ad_hoc_type_list: 1096 ad_hoc.resolve_inner(resolve_context) 1097 1098 @classmethod 1099 def request_user_runtime_cast(cls, request): 1100 if not request: 1101 return 1102 cls.need_user_runtime_cast_ = True 1103 request.acknowledge() 1104 cls.request_internal_runtime_cast() 1105 1106 @classmethod 1107 def request_internal_runtime_cast(cls): 1108 if cls.need_internal_runtime_cast_: 1109 return 1110 cls.need_internal_runtime_cast_ = True 1111 for p in cls.resolve_data_.main_properties: 1112 p.param_type_binding.request_internal_runtime_cast() 1113 for p in cls.resolve_data_.optional_properties: 1114 p.param_type_binding.request_internal_runtime_cast() 1115 1116 @classmethod 1117 def get_code_generator(class_binding_cls): 1118 class CodeGenerator: 1119 @classmethod 1120 def generate_type_builder(cls, writer, generate_context): 1121 resolve_data = class_binding_cls.resolve_data_ 1122 helper.write_doc(writer) 1123 class_name = fixed_type_name.class_name 1124 1125 is_open_type = (context_domain_name + "." + class_name) in TYPES_WITH_OPEN_FIELD_LIST_SET 1126 1127 fixed_type_name.output_comment(writer) 1128 writer.newline("class ") 1129 writer.append(class_name) 1130 writer.append(" : public ") 1131 if is_open_type: 1132 writer.append("JSONObject") 1133 else: 1134 writer.append("JSONObjectBase") 1135 writer.append(" {\n") 1136 writer.newline("public:\n") 1137 ad_hoc_type_writer = writer.insert_writer(" ") 1138 1139 for ad_hoc_type in resolve_data.ad_hoc_types: 1140 code_generator = ad_hoc_type.get_code_generator() 1141 if code_generator: 1142 code_generator.generate_type_builder(ad_hoc_type_writer, generate_context) 1143 1144 writer.newline_multiline( 1145 """ enum { 1146 NoFieldsSet = 0, 1147 """) 1148 1149 state_enum_items = [] 1150 if len(resolve_data.main_properties) > 0: 1151 pos = 0 1152 for prop_data in resolve_data.main_properties: 1153 item_name = Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]) + "Set" 1154 state_enum_items.append(item_name) 1155 writer.newline(" %s = 1 << %s,\n" % (item_name, pos)) 1156 pos += 1 1157 all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")" 1158 else: 1159 all_fields_set_value = "0" 1160 1161 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_1 1162 % (all_fields_set_value, class_name, class_name)) 1163 1164 pos = 0 1165 for prop_data in resolve_data.main_properties: 1166 prop_name = prop_data.p["name"] 1167 1168 param_type_binding = prop_data.param_type_binding 1169 param_raw_type = param_type_binding.reduce_to_raw_type() 1170 1171 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_2 1172 % (state_enum_items[pos], 1173 Capitalizer.lower_camel_case_to_upper(prop_name), 1174 param_type_binding.get_type_model().get_input_param_type_text(), 1175 state_enum_items[pos], prop_name, 1176 param_raw_type.get_setter_name(), prop_name, 1177 format_setter_value_expression(param_type_binding, "value"), 1178 state_enum_items[pos])) 1179 1180 pos += 1 1181 1182 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_3 1183 % (class_name, class_name, class_name, class_name, class_name)) 1184 1185 writer.newline(" /*\n") 1186 writer.newline(" * Synthetic constructor:\n") 1187 writer.newline(" * RefPtr<%s> result = %s::create()" % (class_name, class_name)) 1188 for prop_data in resolve_data.main_properties: 1189 writer.append_multiline("\n * .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop_data.p["name"])) 1190 writer.append_multiline(";\n */\n") 1191 1192 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_4) 1193 1194 writer.newline(" typedef TypeBuilder::StructItemTraits ItemTraits;\n") 1195 1196 for prop_data in resolve_data.main_properties: 1197 prop_name = prop_data.p["name"] 1198 param_type_binding = prop_data.param_type_binding 1199 raw_type = param_type_binding.reduce_to_raw_type() 1200 if isinstance(param_type_binding.get_type_model(), TypeModel.ValueType): 1201 writer.append_multiline("\n void %s" % prop_name) 1202 writer.append("(%s value)\n" % param_type_binding.get_type_model().get_command_return_pass_model().get_output_parameter_type()) 1203 writer.newline(" {\n") 1204 writer.newline(" JSONObjectBase::get%s(\"%s\", value);\n" 1205 % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"])) 1206 writer.newline(" }\n") 1207 1208 for prop_data in resolve_data.optional_properties: 1209 prop_name = prop_data.p["name"] 1210 param_type_binding = prop_data.param_type_binding 1211 setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop_name) 1212 1213 writer.append_multiline("\n void %s" % setter_name) 1214 writer.append("(%s value)\n" % param_type_binding.get_type_model().get_input_param_type_text()) 1215 writer.newline(" {\n") 1216 writer.newline(" this->set%s(\"%s\", %s);\n" 1217 % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"], 1218 format_setter_value_expression(param_type_binding, "value"))) 1219 writer.newline(" }\n") 1220 1221 if setter_name in INSPECTOR_OBJECT_SETTER_NAMES: 1222 writer.newline(" using JSONObjectBase::%s;\n\n" % setter_name) 1223 1224 if class_binding_cls.need_user_runtime_cast_: 1225 writer.newline(" static PassRefPtr<%s> runtimeCast(PassRefPtr<JSONValue> value)\n" % class_name) 1226 writer.newline(" {\n") 1227 writer.newline(" RefPtr<JSONObject> object;\n") 1228 writer.newline(" bool castRes = value->asObject(&object);\n") 1229 writer.newline(" ASSERT_UNUSED(castRes, castRes);\n") 1230 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME) 1231 writer.newline(" assertCorrectValue(object.get());\n") 1232 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME) 1233 writer.newline(" COMPILE_ASSERT(sizeof(%s) == sizeof(JSONObjectBase), type_cast_problem);\n" % class_name) 1234 writer.newline(" return static_cast<%s*>(static_cast<JSONObjectBase*>(object.get()));\n" % class_name) 1235 writer.newline(" }\n") 1236 writer.append("\n") 1237 1238 if class_binding_cls.need_internal_runtime_cast_: 1239 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME) 1240 writer.newline(" static void assertCorrectValue(JSONValue* value);\n") 1241 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME) 1242 1243 closed_field_set = (context_domain_name + "." + class_name) not in TYPES_WITH_OPEN_FIELD_LIST_SET 1244 1245 validator_writer = generate_context.validator_writer 1246 1247 domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name) 1248 1249 validator_writer.newline("void %s%s::assertCorrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, class_name)) 1250 validator_writer.newline("{\n") 1251 validator_writer.newline(" RefPtr<JSONObject> object;\n") 1252 validator_writer.newline(" bool castRes = value->asObject(&object);\n") 1253 validator_writer.newline(" ASSERT_UNUSED(castRes, castRes);\n") 1254 for prop_data in resolve_data.main_properties: 1255 validator_writer.newline(" {\n") 1256 it_name = "%sPos" % prop_data.p["name"] 1257 validator_writer.newline(" JSONObject::iterator %s;\n" % it_name) 1258 validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"])) 1259 validator_writer.newline(" ASSERT(%s != object->end());\n" % it_name) 1260 validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name)) 1261 validator_writer.newline(" }\n") 1262 1263 if closed_field_set: 1264 validator_writer.newline(" int foundPropertiesCount = %s;\n" % len(resolve_data.main_properties)) 1265 1266 for prop_data in resolve_data.optional_properties: 1267 validator_writer.newline(" {\n") 1268 it_name = "%sPos" % prop_data.p["name"] 1269 validator_writer.newline(" JSONObject::iterator %s;\n" % it_name) 1270 validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"])) 1271 validator_writer.newline(" if (%s != object->end()) {\n" % it_name) 1272 validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name)) 1273 if closed_field_set: 1274 validator_writer.newline(" ++foundPropertiesCount;\n") 1275 validator_writer.newline(" }\n") 1276 validator_writer.newline(" }\n") 1277 1278 if closed_field_set: 1279 validator_writer.newline(" if (foundPropertiesCount != object->size()) {\n") 1280 validator_writer.newline(" FATAL(\"Unexpected properties in object: %s\\n\", object->toJSONString().ascii().data());\n") 1281 validator_writer.newline(" }\n") 1282 validator_writer.newline("}\n") 1283 1284 validator_writer.newline("\n\n") 1285 1286 if is_open_type: 1287 cpp_writer = generate_context.cpp_writer 1288 writer.append("\n") 1289 writer.newline(" // Property names for type generated as open.\n") 1290 for prop_data in resolve_data.main_properties + resolve_data.optional_properties: 1291 prop_name = prop_data.p["name"] 1292 prop_field_name = Capitalizer.lower_camel_case_to_upper(prop_name) 1293 writer.newline(" static const char %s[];\n" % (prop_field_name)) 1294 cpp_writer.newline("const char %s%s::%s[] = \"%s\";\n" % (helper.full_name_prefix_for_impl, class_name, prop_field_name, prop_name)) 1295 1296 1297 writer.newline("};\n\n") 1298 1299 @staticmethod 1300 def generate_forward_declaration(writer): 1301 class_name = fixed_type_name.class_name 1302 writer.newline("class ") 1303 writer.append(class_name) 1304 writer.append(";\n") 1305 1306 @staticmethod 1307 def register_use(forward_listener): 1308 helper.add_to_forward_listener(forward_listener) 1309 1310 @staticmethod 1311 def get_generate_pass_id(): 1312 return TypeBuilderPass.MAIN 1313 1314 return CodeGenerator 1315 1316 @staticmethod 1317 def get_validator_call_text(): 1318 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue" 1319 1320 @classmethod 1321 def get_array_item_c_type_text(cls): 1322 return helper.full_name_prefix_for_use + fixed_type_name.class_name 1323 1324 @staticmethod 1325 def get_setter_value_expression_pattern(): 1326 return None 1327 1328 @staticmethod 1329 def reduce_to_raw_type(): 1330 return RawTypes.Object 1331 1332 @staticmethod 1333 def get_type_model(): 1334 return TypeModel.RefPtrBased(helper.full_name_prefix_for_use + fixed_type_name.class_name) 1335 1336 class AdHocTypeContextImpl: 1337 def __init__(self, property_name, class_name, resolve_context, ad_hoc_type_list, parent_full_name_prefix): 1338 self.property_name = property_name 1339 self.class_name = class_name 1340 self.resolve_context = resolve_context 1341 self.ad_hoc_type_list = ad_hoc_type_list 1342 self.container_full_name_prefix = parent_full_name_prefix + class_name + "::" 1343 self.container_relative_name_prefix = "" 1344 1345 def get_type_name_fix(self): 1346 class NameFix: 1347 class_name = Capitalizer.lower_camel_case_to_upper(self.property_name) 1348 1349 @staticmethod 1350 def output_comment(writer): 1351 writer.newline("// Named after property name '%s' while generating %s.\n" % (self.property_name, self.class_name)) 1352 1353 return NameFix 1354 1355 def add_type(self, binding): 1356 self.ad_hoc_type_list.append(binding) 1357 1358 return ClassBinding 1359 else: 1360 1361 class PlainObjectBinding: 1362 @classmethod 1363 def resolve_inner(cls, resolve_context): 1364 pass 1365 1366 @staticmethod 1367 def request_user_runtime_cast(request): 1368 pass 1369 1370 @staticmethod 1371 def request_internal_runtime_cast(): 1372 RawTypes.Object.request_raw_internal_runtime_cast() 1373 1374 @staticmethod 1375 def get_code_generator(): 1376 pass 1377 1378 @staticmethod 1379 def get_validator_call_text(): 1380 return "RuntimeCastHelper::assertType<JSONValue::TypeObject>" 1381 1382 @classmethod 1383 def get_array_item_c_type_text(cls): 1384 return cls.reduce_to_raw_type().get_array_item_raw_c_type_text() 1385 1386 @staticmethod 1387 def get_setter_value_expression_pattern(): 1388 return None 1389 1390 @staticmethod 1391 def reduce_to_raw_type(): 1392 return RawTypes.Object 1393 1394 @staticmethod 1395 def get_type_model(): 1396 return TypeModel.Object 1397 1398 return PlainObjectBinding 1399 elif json_typable["type"] == "array": 1400 if "items" in json_typable: 1401 1402 ad_hoc_types = [] 1403 1404 class AdHocTypeContext: 1405 container_full_name_prefix = "<not yet defined>" 1406 container_relative_name_prefix = "" 1407 1408 @staticmethod 1409 def get_type_name_fix(): 1410 return fixed_type_name 1411 1412 @staticmethod 1413 def add_type(binding): 1414 ad_hoc_types.append(binding) 1415 1416 item_binding = resolve_param_type(json_typable["items"], context_domain_name, AdHocTypeContext) 1417 1418 class ArrayBinding: 1419 resolve_data_ = None 1420 need_internal_runtime_cast_ = False 1421 1422 @classmethod 1423 def resolve_inner(cls, resolve_context): 1424 if cls.resolve_data_: 1425 return 1426 1427 class ResolveData: 1428 item_type_binding = item_binding 1429 ad_hoc_type_list = ad_hoc_types 1430 1431 cls.resolve_data_ = ResolveData 1432 1433 for t in ad_hoc_types: 1434 t.resolve_inner(resolve_context) 1435 1436 @classmethod 1437 def request_user_runtime_cast(cls, request): 1438 raise Exception("Not implemented yet") 1439 1440 @classmethod 1441 def request_internal_runtime_cast(cls): 1442 if cls.need_internal_runtime_cast_: 1443 return 1444 cls.need_internal_runtime_cast_ = True 1445 cls.resolve_data_.item_type_binding.request_internal_runtime_cast() 1446 1447 @classmethod 1448 def get_code_generator(array_binding_cls): 1449 1450 class CodeGenerator: 1451 @staticmethod 1452 def generate_type_builder(writer, generate_context): 1453 ad_hoc_type_writer = writer 1454 1455 resolve_data = array_binding_cls.resolve_data_ 1456 1457 for ad_hoc_type in resolve_data.ad_hoc_type_list: 1458 code_generator = ad_hoc_type.get_code_generator() 1459 if code_generator: 1460 code_generator.generate_type_builder(ad_hoc_type_writer, generate_context) 1461 1462 @staticmethod 1463 def generate_forward_declaration(writer): 1464 pass 1465 1466 @staticmethod 1467 def register_use(forward_listener): 1468 item_code_generator = item_binding.get_code_generator() 1469 if item_code_generator: 1470 item_code_generator.register_use(forward_listener) 1471 1472 @staticmethod 1473 def get_generate_pass_id(): 1474 return TypeBuilderPass.MAIN 1475 1476 return CodeGenerator 1477 1478 @classmethod 1479 def get_validator_call_text(cls): 1480 return cls.get_array_item_c_type_text() + "::assertCorrectValue" 1481 1482 @classmethod 1483 def get_array_item_c_type_text(cls): 1484 return replace_right_shift("TypeBuilder::Array<%s>" % cls.resolve_data_.item_type_binding.get_array_item_c_type_text()) 1485 1486 @staticmethod 1487 def get_setter_value_expression_pattern(): 1488 return None 1489 1490 @staticmethod 1491 def reduce_to_raw_type(): 1492 return RawTypes.Array 1493 1494 @classmethod 1495 def get_type_model(cls): 1496 return TypeModel.RefPtrBased(cls.get_array_item_c_type_text()) 1497 1498 return ArrayBinding 1499 else: 1500 # Fall-through to raw type. 1501 pass 1502 1503 raw_type = RawTypes.get(json_typable["type"]) 1504 1505 return RawTypeBinding(raw_type) 1506 1507 1508 class RawTypeBinding: 1509 def __init__(self, raw_type): 1510 self.raw_type_ = raw_type 1511 1512 def resolve_inner(self, resolve_context): 1513 pass 1514 1515 def request_user_runtime_cast(self, request): 1516 raise Exception("Unsupported") 1517 1518 def request_internal_runtime_cast(self): 1519 self.raw_type_.request_raw_internal_runtime_cast() 1520 1521 def get_code_generator(self): 1522 return None 1523 1524 def get_validator_call_text(self): 1525 return self.raw_type_.get_raw_validator_call_text() 1526 1527 def get_array_item_c_type_text(self): 1528 return self.raw_type_.get_array_item_raw_c_type_text() 1529 1530 def get_setter_value_expression_pattern(self): 1531 return None 1532 1533 def reduce_to_raw_type(self): 1534 return self.raw_type_ 1535 1536 def get_type_model(self): 1537 return self.raw_type_.get_raw_type_model() 1538 1539 1540 class TypeData(object): 1541 def __init__(self, json_type, json_domain, domain_data): 1542 self.json_type_ = json_type 1543 self.json_domain_ = json_domain 1544 self.domain_data_ = domain_data 1545 1546 if "type" not in json_type: 1547 raise Exception("Unknown type") 1548 1549 json_type_name = json_type["type"] 1550 raw_type = RawTypes.get(json_type_name) 1551 self.raw_type_ = raw_type 1552 self.binding_being_resolved_ = False 1553 self.binding_ = None 1554 1555 def get_raw_type(self): 1556 return self.raw_type_ 1557 1558 def get_binding(self): 1559 if not self.binding_: 1560 if self.binding_being_resolved_: 1561 raise Error("Type %s is already being resolved" % self.json_type_["type"]) 1562 # Resolve only lazily, because resolving one named type may require resolving some other named type. 1563 self.binding_being_resolved_ = True 1564 try: 1565 self.binding_ = TypeBindings.create_named_type_declaration(self.json_type_, self.json_domain_["domain"], self) 1566 finally: 1567 self.binding_being_resolved_ = False 1568 1569 return self.binding_ 1570 1571 def get_json_type(self): 1572 return self.json_type_ 1573 1574 def get_name(self): 1575 return self.json_type_["id"] 1576 1577 def get_domain_name(self): 1578 return self.json_domain_["domain"] 1579 1580 1581 class DomainData: 1582 def __init__(self, json_domain): 1583 self.json_domain = json_domain 1584 self.types_ = [] 1585 1586 def add_type(self, type_data): 1587 self.types_.append(type_data) 1588 1589 def name(self): 1590 return self.json_domain["domain"] 1591 1592 def types(self): 1593 return self.types_ 1594 1595 1596 class TypeMap: 1597 def __init__(self, api): 1598 self.map_ = {} 1599 self.domains_ = [] 1600 for json_domain in api["domains"]: 1601 domain_name = json_domain["domain"] 1602 1603 domain_map = {} 1604 self.map_[domain_name] = domain_map 1605 1606 domain_data = DomainData(json_domain) 1607 self.domains_.append(domain_data) 1608 1609 if "types" in json_domain: 1610 for json_type in json_domain["types"]: 1611 type_name = json_type["id"] 1612 type_data = TypeData(json_type, json_domain, domain_data) 1613 domain_map[type_name] = type_data 1614 domain_data.add_type(type_data) 1615 1616 def domains(self): 1617 return self.domains_ 1618 1619 def get(self, domain_name, type_name): 1620 return self.map_[domain_name][type_name] 1621 1622 1623 def resolve_param_type(json_parameter, scope_domain_name, ad_hoc_type_context): 1624 if "$ref" in json_parameter: 1625 json_ref = json_parameter["$ref"] 1626 type_data = get_ref_data(json_ref, scope_domain_name) 1627 return type_data.get_binding() 1628 elif "type" in json_parameter: 1629 result = TypeBindings.create_ad_hoc_type_declaration(json_parameter, scope_domain_name, ad_hoc_type_context) 1630 ad_hoc_type_context.add_type(result) 1631 return result 1632 else: 1633 raise Exception("Unknown type") 1634 1635 def resolve_param_raw_type(json_parameter, scope_domain_name): 1636 if "$ref" in json_parameter: 1637 json_ref = json_parameter["$ref"] 1638 type_data = get_ref_data(json_ref, scope_domain_name) 1639 return type_data.get_raw_type() 1640 elif "type" in json_parameter: 1641 json_type = json_parameter["type"] 1642 return RawTypes.get(json_type) 1643 else: 1644 raise Exception("Unknown type") 1645 1646 1647 def get_ref_data(json_ref, scope_domain_name): 1648 dot_pos = json_ref.find(".") 1649 if dot_pos == -1: 1650 domain_name = scope_domain_name 1651 type_name = json_ref 1652 else: 1653 domain_name = json_ref[:dot_pos] 1654 type_name = json_ref[dot_pos + 1:] 1655 1656 return type_map.get(domain_name, type_name) 1657 1658 1659 input_file = open(input_json_filename, "r") 1660 json_string = input_file.read() 1661 json_api = json.loads(json_string) 1662 1663 1664 class Templates: 1665 def get_this_script_path_(absolute_path): 1666 absolute_path = os.path.abspath(absolute_path) 1667 components = [] 1668 1669 def fill_recursive(path_part, depth): 1670 if depth <= 0 or path_part == '/': 1671 return 1672 fill_recursive(os.path.dirname(path_part), depth - 1) 1673 components.append(os.path.basename(path_part)) 1674 1675 # Typical path is /Source/WebCore/inspector/CodeGeneratorInspector.py 1676 # Let's take 4 components from the real path then. 1677 fill_recursive(absolute_path, 4) 1678 1679 return "/".join(components) 1680 1681 file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) + 1682 """// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1683 // Use of this source code is governed by a BSD-style license that can be 1684 // found in the LICENSE file. 1685 """) 1686 1687 frontend_domain_class = string.Template(CodeGeneratorInspectorStrings.frontend_domain_class) 1688 backend_method = string.Template(CodeGeneratorInspectorStrings.backend_method) 1689 frontend_method = string.Template(CodeGeneratorInspectorStrings.frontend_method) 1690 callback_main_methods = string.Template(CodeGeneratorInspectorStrings.callback_main_methods) 1691 callback_failure_method = string.Template(CodeGeneratorInspectorStrings.callback_failure_method) 1692 frontend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_h) 1693 backend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_h) 1694 backend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_cpp) 1695 frontend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_cpp) 1696 typebuilder_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_h) 1697 typebuilder_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_cpp) 1698 param_container_access_code = CodeGeneratorInspectorStrings.param_container_access_code 1699 1700 1701 1702 1703 1704 type_map = TypeMap(json_api) 1705 1706 1707 class NeedRuntimeCastRequest: 1708 def __init__(self): 1709 self.ack_ = None 1710 1711 def acknowledge(self): 1712 self.ack_ = True 1713 1714 def is_acknowledged(self): 1715 return self.ack_ 1716 1717 1718 def resolve_all_types(): 1719 runtime_cast_generate_requests = {} 1720 for type_name in TYPES_WITH_RUNTIME_CAST_SET: 1721 runtime_cast_generate_requests[type_name] = NeedRuntimeCastRequest() 1722 1723 class ForwardListener: 1724 type_data_set = set() 1725 already_declared_set = set() 1726 1727 @classmethod 1728 def add_type_data(cls, type_data): 1729 if type_data not in cls.already_declared_set: 1730 cls.type_data_set.add(type_data) 1731 1732 class ResolveContext: 1733 forward_listener = ForwardListener 1734 1735 for domain_data in type_map.domains(): 1736 for type_data in domain_data.types(): 1737 # Do not generate forwards for this type any longer. 1738 ForwardListener.already_declared_set.add(type_data) 1739 1740 binding = type_data.get_binding() 1741 binding.resolve_inner(ResolveContext) 1742 1743 for domain_data in type_map.domains(): 1744 for type_data in domain_data.types(): 1745 full_type_name = "%s.%s" % (type_data.get_domain_name(), type_data.get_name()) 1746 request = runtime_cast_generate_requests.pop(full_type_name, None) 1747 binding = type_data.get_binding() 1748 if request: 1749 binding.request_user_runtime_cast(request) 1750 1751 if request and not request.is_acknowledged(): 1752 raise Exception("Failed to generate runtimeCast in " + full_type_name) 1753 1754 for full_type_name in runtime_cast_generate_requests: 1755 raise Exception("Failed to generate runtimeCast. Type " + full_type_name + " not found") 1756 1757 return ForwardListener 1758 1759 1760 global_forward_listener = resolve_all_types() 1761 1762 1763 def get_annotated_type_text(raw_type, annotated_type): 1764 if annotated_type != raw_type: 1765 return "/*%s*/ %s" % (annotated_type, raw_type) 1766 else: 1767 return raw_type 1768 1769 1770 def format_setter_value_expression(param_type_binding, value_ref): 1771 pattern = param_type_binding.get_setter_value_expression_pattern() 1772 if pattern: 1773 return pattern % value_ref 1774 else: 1775 return value_ref 1776 1777 class Generator: 1778 frontend_class_field_lines = [] 1779 frontend_domain_class_lines = [] 1780 1781 method_name_enum_list = [] 1782 backend_method_declaration_list = [] 1783 backend_method_implementation_list = [] 1784 backend_method_name_declaration_list = [] 1785 backend_method_name_declaration_index_list = [] 1786 backend_method_name_declaration_current_index = 0 1787 method_handler_list = [] 1788 frontend_method_list = [] 1789 1790 backend_virtual_setters_list = [] 1791 backend_agent_interface_list = [] 1792 backend_setters_list = [] 1793 backend_constructor_init_list = [] 1794 backend_field_list = [] 1795 frontend_constructor_init_list = [] 1796 type_builder_fragments = [] 1797 type_builder_forwards = [] 1798 validator_impl_list = [] 1799 type_builder_impl_list = [] 1800 1801 1802 @staticmethod 1803 def go(): 1804 Generator.process_types(type_map) 1805 1806 first_cycle_guardable_list_list = [ 1807 Generator.backend_method_declaration_list, 1808 Generator.backend_method_implementation_list, 1809 Generator.backend_method_name_declaration_list, 1810 Generator.backend_method_name_declaration_index_list, 1811 Generator.backend_agent_interface_list, 1812 Generator.frontend_class_field_lines, 1813 Generator.frontend_constructor_init_list, 1814 Generator.frontend_domain_class_lines, 1815 Generator.frontend_method_list, 1816 Generator.method_handler_list, 1817 Generator.method_name_enum_list, 1818 Generator.backend_constructor_init_list, 1819 Generator.backend_virtual_setters_list, 1820 Generator.backend_setters_list, 1821 Generator.backend_field_list] 1822 1823 for json_domain in json_api["domains"]: 1824 domain_name = json_domain["domain"] 1825 domain_name_lower = domain_name.lower() 1826 1827 domain_fixes = DomainNameFixes.get_fixed_data(domain_name) 1828 1829 agent_field_name = domain_fixes.agent_field_name 1830 1831 frontend_method_declaration_lines = [] 1832 1833 if "events" in json_domain: 1834 for json_event in json_domain["events"]: 1835 Generator.process_event(json_event, domain_name, frontend_method_declaration_lines) 1836 1837 Generator.frontend_class_field_lines.append(" %s m_%s;\n" % (domain_name, domain_name_lower)) 1838 if Generator.frontend_constructor_init_list: 1839 Generator.frontend_constructor_init_list.append(" , ") 1840 Generator.frontend_constructor_init_list.append("m_%s(inspectorFrontendChannel)\n" % domain_name_lower) 1841 Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None, 1842 domainClassName=domain_name, 1843 domainFieldName=domain_name_lower, 1844 frontendDomainMethodDeclarations="".join(flatten_list(frontend_method_declaration_lines)))) 1845 1846 agent_interface_name = Capitalizer.lower_camel_case_to_upper(domain_name) + "CommandHandler" 1847 Generator.backend_agent_interface_list.append(" class %s {\n" % agent_interface_name) 1848 Generator.backend_agent_interface_list.append(" public:\n") 1849 if "commands" in json_domain: 1850 for json_command in json_domain["commands"]: 1851 Generator.process_command(json_command, domain_name, agent_field_name, agent_interface_name) 1852 Generator.backend_agent_interface_list.append("\n protected:\n") 1853 Generator.backend_agent_interface_list.append(" virtual ~%s() { }\n" % agent_interface_name) 1854 Generator.backend_agent_interface_list.append(" };\n\n") 1855 1856 Generator.backend_constructor_init_list.append(" , m_%s(0)" % agent_field_name) 1857 Generator.backend_virtual_setters_list.append(" virtual void registerAgent(%s* %s) = 0;" % (agent_interface_name, agent_field_name)) 1858 Generator.backend_setters_list.append(" virtual void registerAgent(%s* %s) { ASSERT(!m_%s); m_%s = %s; }" % (agent_interface_name, agent_field_name, agent_field_name, agent_field_name, agent_field_name)) 1859 Generator.backend_field_list.append(" %s* m_%s;" % (agent_interface_name, agent_field_name)) 1860 1861 @staticmethod 1862 def process_event(json_event, domain_name, frontend_method_declaration_lines): 1863 if (("handlers" in json_event) and (not ("renderer" in json_event["handlers"]))): 1864 return 1865 1866 event_name = json_event["name"] 1867 1868 ad_hoc_type_output = [] 1869 frontend_method_declaration_lines.append(ad_hoc_type_output) 1870 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ") 1871 1872 decl_parameter_list = [] 1873 1874 json_parameters = json_event.get("parameters") 1875 Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer, 1876 decl_parameter_list, 1877 Generator.EventMethodStructTemplate, 1878 Generator.frontend_method_list, Templates.frontend_method, {"eventName": event_name}) 1879 1880 frontend_method_declaration_lines.append( 1881 " void %s(%s);\n" % (event_name, ", ".join(decl_parameter_list))) 1882 1883 class EventMethodStructTemplate: 1884 @staticmethod 1885 def append_prolog(line_list): 1886 line_list.append(" RefPtr<JSONObject> paramsObject = JSONObject::create();\n") 1887 1888 @staticmethod 1889 def append_epilog(line_list): 1890 line_list.append(" jsonMessage->setObject(\"params\", paramsObject);\n") 1891 1892 container_name = "paramsObject" 1893 1894 @staticmethod 1895 def process_command(json_command, domain_name, agent_field_name, agent_interface_name): 1896 if (("handlers" in json_command) and (not ("renderer" in json_command["handlers"]))): 1897 return 1898 1899 json_command_name = json_command["name"] 1900 1901 cmd_enum_name = "k%s_%sCmd" % (domain_name, json_command["name"]) 1902 1903 Generator.method_name_enum_list.append(" %s," % cmd_enum_name) 1904 Generator.method_handler_list.append(" &InspectorBackendDispatcherImpl::%s_%s," % (domain_name, json_command_name)) 1905 Generator.backend_method_declaration_list.append(" void %s_%s(long callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);" % (domain_name, json_command_name)) 1906 1907 backend_agent_interface_list = [] if "redirect" in json_command else Generator.backend_agent_interface_list 1908 1909 ad_hoc_type_output = [] 1910 backend_agent_interface_list.append(ad_hoc_type_output) 1911 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ") 1912 1913 backend_agent_interface_list.append(" virtual void %s(ErrorString*" % json_command_name) 1914 1915 method_in_code = "" 1916 method_out_code = "" 1917 result_object_declaration = "" 1918 agent_call_param_list = ["&error"] 1919 agent_call_params_declaration_list = [" ErrorString error;"] 1920 send_response_call_params_list = ["error"] 1921 request_message_param = "" 1922 normal_response_cook_text = "" 1923 error_type_binding = None 1924 if "error" in json_command: 1925 json_error = json_command["error"] 1926 error_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_error, json_command_name + "Error", json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::") 1927 error_type_model = error_type_binding.get_type_model().get_optional() 1928 error_annotated_type = error_type_model.get_command_return_pass_model().get_output_parameter_type() 1929 agent_call_param_list.append("%serrorData" % error_type_model.get_command_return_pass_model().get_output_argument_prefix()) 1930 backend_agent_interface_list.append(", %s errorData" % error_annotated_type) 1931 method_in_code += " %s errorData;\n" % error_type_model.get_command_return_pass_model().get_return_var_type() 1932 send_response_call_params_list.append("errorData") 1933 1934 if "parameters" in json_command: 1935 json_params = json_command["parameters"] 1936 request_message_param = " requestMessageObject" 1937 1938 if json_params: 1939 method_in_code += Templates.param_container_access_code 1940 1941 for json_parameter in json_params: 1942 json_param_name = json_parameter["name"] 1943 param_raw_type = resolve_param_raw_type(json_parameter, domain_name) 1944 1945 getter_name = param_raw_type.get_getter_name() 1946 1947 optional = json_parameter.get("optional") 1948 1949 non_optional_type_model = param_raw_type.get_raw_type_model() 1950 if optional: 1951 type_model = non_optional_type_model.get_optional() 1952 else: 1953 type_model = non_optional_type_model 1954 1955 if optional: 1956 code = (" bool %s_valueFound = false;\n" 1957 " %s in_%s = get%s(paramsContainerPtr, \"%s\", &%s_valueFound, protocolErrors);\n" % 1958 (json_param_name, non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name, json_param_name)) 1959 param = "%s_valueFound ? &in_%s : 0" % (json_param_name, json_param_name) 1960 # FIXME: pass optional refptr-values as PassRefPtr 1961 formal_param_type_pattern = "const %s*" 1962 else: 1963 code = (" %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrors);\n" % 1964 (non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name)) 1965 param = "in_%s" % json_param_name 1966 # FIXME: pass not-optional refptr-values as NonNullPassRefPtr 1967 if param_raw_type.is_heavy_value(): 1968 formal_param_type_pattern = "const %s&" 1969 else: 1970 formal_param_type_pattern = "%s" 1971 1972 method_in_code += code 1973 agent_call_param_list.append(param) 1974 backend_agent_interface_list.append(", %s in_%s" % (formal_param_type_pattern % non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name)) 1975 1976 if json_command.get("async") == True: 1977 callback_name = Capitalizer.lower_camel_case_to_upper(json_command_name) + "Callback" 1978 1979 callback_output = [] 1980 callback_writer = Writer(callback_output, ad_hoc_type_writer.get_indent()) 1981 1982 decl_parameter_list = [] 1983 Generator.generate_send_method(json_command.get("returns"), json_command_name, domain_name, ad_hoc_type_writer, 1984 decl_parameter_list, 1985 Generator.CallbackMethodStructTemplate, 1986 Generator.backend_method_implementation_list, Templates.callback_main_methods, 1987 {"callbackName": callback_name, "agentName": agent_interface_name}) 1988 1989 callback_writer.newline("class " + callback_name + " : public CallbackBase {\n") 1990 callback_writer.newline("public:\n") 1991 callback_writer.newline(" " + callback_name + "(PassRefPtr<InspectorBackendDispatcherImpl>, int id);\n") 1992 callback_writer.newline(" void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n") 1993 error_part_writer = callback_writer.insert_writer("") 1994 callback_writer.newline("};\n") 1995 1996 if error_type_binding: 1997 annotated_type = error_type_model.get_input_param_type_text() 1998 error_part_writer.newline(" void sendFailure(const ErrorString&, %s);\n" % annotated_type) 1999 error_part_writer.newline(" using CallbackBase::sendFailure;\n") 2000 2001 assigment_value = error_type_model.get_event_setter_expression_pattern() % "errorData" 2002 assigment_value = error_type_binding.reduce_to_raw_type().get_constructor_pattern() % assigment_value 2003 2004 Generator.backend_method_implementation_list.append(Templates.callback_failure_method.substitute(None, 2005 agentName=agent_interface_name, 2006 callbackName=callback_name, 2007 parameter=annotated_type + " errorData", 2008 argument=assigment_value)) 2009 2010 ad_hoc_type_output.append(callback_output) 2011 2012 method_out_code += " RefPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRef(new " + agent_interface_name + "::" + callback_name + "(this, callId));\n" 2013 agent_call_param_list.append("callback") 2014 normal_response_cook_text += " if (!error.length()) \n" 2015 normal_response_cook_text += " return;\n" 2016 normal_response_cook_text += " callback->disable();\n" 2017 backend_agent_interface_list.append(", PassRefPtr<%s> callback" % callback_name) 2018 else: 2019 if "returns" in json_command: 2020 method_out_code += "\n" 2021 agent_call_params_declaration_list.append(" RefPtr<JSONObject> result = JSONObject::create();") 2022 send_response_call_params_list.append("result") 2023 response_cook_list = [] 2024 for json_return in json_command["returns"]: 2025 2026 json_return_name = json_return["name"] 2027 2028 optional = bool(json_return.get("optional")) 2029 2030 return_type_binding = Generator.resolve_param_type_and_generate_ad_hoc(json_return, json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::") 2031 2032 raw_type = return_type_binding.reduce_to_raw_type() 2033 setter_type = raw_type.get_setter_name() 2034 initializer = raw_type.get_c_initializer() 2035 2036 type_model = return_type_binding.get_type_model() 2037 if optional: 2038 type_model = type_model.get_optional() 2039 2040 code = " %s out_%s;\n" % (type_model.get_command_return_pass_model().get_return_var_type(), json_return_name) 2041 param = "%sout_%s" % (type_model.get_command_return_pass_model().get_output_argument_prefix(), json_return_name) 2042 var_name = "out_%s" % json_return_name 2043 setter_argument = type_model.get_command_return_pass_model().get_output_to_raw_expression() % var_name 2044 if return_type_binding.get_setter_value_expression_pattern(): 2045 setter_argument = return_type_binding.get_setter_value_expression_pattern() % setter_argument 2046 2047 cook = " result->set%s(\"%s\", %s);\n" % (setter_type, json_return_name, 2048 setter_argument) 2049 2050 set_condition_pattern = type_model.get_command_return_pass_model().get_set_return_condition() 2051 if set_condition_pattern: 2052 cook = (" if (%s)\n " % (set_condition_pattern % var_name)) + cook 2053 annotated_type = type_model.get_command_return_pass_model().get_output_parameter_type() 2054 2055 param_name = var_name 2056 if optional: 2057 param_name = "opt_" + param_name 2058 2059 backend_agent_interface_list.append(", %s %s" % (annotated_type, param_name)) 2060 response_cook_list.append(cook) 2061 2062 method_out_code += code 2063 agent_call_param_list.append(param) 2064 2065 normal_response_cook_text += "".join(response_cook_list) 2066 2067 if len(normal_response_cook_text) != 0: 2068 normal_response_cook_text = " if (!error.length()) {\n" + normal_response_cook_text + " }" 2069 2070 # Redirect to another agent's implementation. 2071 agent_field = "m_" + agent_field_name 2072 if "redirect" in json_command: 2073 domain_fixes = DomainNameFixes.get_fixed_data(json_command.get("redirect")) 2074 agent_field = "m_" + domain_fixes.agent_field_name 2075 2076 Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None, 2077 domainName=domain_name, methodName=json_command_name, 2078 agentField=agent_field, 2079 methodCode="".join([method_in_code, method_out_code]), 2080 agentCallParamsDeclaration="\n".join(agent_call_params_declaration_list), 2081 agentCallParams=", ".join(agent_call_param_list), 2082 requestMessageObject=request_message_param, 2083 responseCook=normal_response_cook_text, 2084 sendResponseCallParams=", ".join(send_response_call_params_list), 2085 commandNameIndex=cmd_enum_name)) 2086 declaration_command_name = "%s.%s\\0" % (domain_name, json_command_name) 2087 Generator.backend_method_name_declaration_list.append(" \"%s\"" % declaration_command_name) 2088 Generator.backend_method_name_declaration_index_list.append(" %d," % Generator.backend_method_name_declaration_current_index) 2089 Generator.backend_method_name_declaration_current_index += len(declaration_command_name) - 1 2090 2091 backend_agent_interface_list.append(") = 0;\n") 2092 2093 class CallbackMethodStructTemplate: 2094 @staticmethod 2095 def append_prolog(line_list): 2096 pass 2097 2098 @staticmethod 2099 def append_epilog(line_list): 2100 pass 2101 2102 container_name = "jsonMessage" 2103 2104 # Generates common code for event sending and callback response data sending. 2105 @staticmethod 2106 def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_writer, decl_parameter_list, 2107 method_struct_template, 2108 generator_method_list, method_template, template_params): 2109 method_line_list = [] 2110 if parameters: 2111 method_struct_template.append_prolog(method_line_list) 2112 for json_parameter in parameters: 2113 parameter_name = json_parameter["name"] 2114 2115 param_type_binding = Generator.resolve_param_type_and_generate_ad_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "") 2116 2117 raw_type = param_type_binding.reduce_to_raw_type() 2118 raw_type_binding = RawTypeBinding(raw_type) 2119 2120 optional = bool(json_parameter.get("optional")) 2121 2122 setter_type = raw_type.get_setter_name() 2123 2124 type_model = param_type_binding.get_type_model() 2125 raw_type_model = raw_type_binding.get_type_model() 2126 if optional: 2127 type_model = type_model.get_optional() 2128 raw_type_model = raw_type_model.get_optional() 2129 2130 annotated_type = type_model.get_input_param_type_text() 2131 mode_type_binding = param_type_binding 2132 2133 decl_parameter_list.append("%s %s" % (annotated_type, parameter_name)) 2134 2135 setter_argument = raw_type_model.get_event_setter_expression_pattern() % parameter_name 2136 if mode_type_binding.get_setter_value_expression_pattern(): 2137 setter_argument = mode_type_binding.get_setter_value_expression_pattern() % setter_argument 2138 2139 setter_code = " %s->set%s(\"%s\", %s);\n" % (method_struct_template.container_name, setter_type, parameter_name, setter_argument) 2140 if optional: 2141 setter_code = (" if (%s)\n " % parameter_name) + setter_code 2142 method_line_list.append(setter_code) 2143 2144 method_struct_template.append_epilog(method_line_list) 2145 2146 generator_method_list.append(method_template.substitute(None, 2147 domainName=domain_name, 2148 parameters=", ".join(decl_parameter_list), 2149 code="".join(method_line_list), **template_params)) 2150 2151 @classmethod 2152 def resolve_param_type_and_generate_ad_hoc(cls, json_param, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param): 2153 param_name = json_param["name"] 2154 return cls.resolve_type_and_generate_ad_hoc(json_param, param_name, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param) 2155 2156 @staticmethod 2157 def resolve_type_and_generate_ad_hoc(typable_element, element_name, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param): 2158 ad_hoc_type_list = [] 2159 2160 class AdHocTypeContext: 2161 container_full_name_prefix = "<not yet defined>" 2162 container_relative_name_prefix = container_relative_name_prefix_param 2163 2164 @staticmethod 2165 def get_type_name_fix(): 2166 class NameFix: 2167 class_name = Capitalizer.lower_camel_case_to_upper(element_name) 2168 2169 @staticmethod 2170 def output_comment(writer): 2171 writer.newline("// Named after parameter '%s' while generating command/event %s.\n" % (element_name, method_name)) 2172 2173 return NameFix 2174 2175 @staticmethod 2176 def add_type(binding): 2177 ad_hoc_type_list.append(binding) 2178 2179 type_binding = resolve_param_type(typable_element, domain_name, AdHocTypeContext) 2180 2181 class InterfaceForwardListener: 2182 @staticmethod 2183 def add_type_data(type_data): 2184 pass 2185 2186 class InterfaceResolveContext: 2187 forward_listener = InterfaceForwardListener 2188 2189 for type in ad_hoc_type_list: 2190 type.resolve_inner(InterfaceResolveContext) 2191 2192 class InterfaceGenerateContext: 2193 validator_writer = "not supported in InterfaceGenerateContext" 2194 cpp_writer = validator_writer 2195 2196 for type in ad_hoc_type_list: 2197 generator = type.get_code_generator() 2198 if generator: 2199 generator.generate_type_builder(ad_hoc_type_writer, InterfaceGenerateContext) 2200 2201 return type_binding 2202 2203 @staticmethod 2204 def process_types(type_map): 2205 output = Generator.type_builder_fragments 2206 2207 class GenerateContext: 2208 validator_writer = Writer(Generator.validator_impl_list, "") 2209 cpp_writer = Writer(Generator.type_builder_impl_list, "") 2210 2211 def generate_all_domains_code(out, type_data_callback): 2212 writer = Writer(out, "") 2213 for domain_data in type_map.domains(): 2214 domain_fixes = DomainNameFixes.get_fixed_data(domain_data.name()) 2215 2216 namespace_declared = [] 2217 2218 def namespace_lazy_generator(): 2219 if not namespace_declared: 2220 writer.newline("namespace ") 2221 writer.append(domain_data.name()) 2222 writer.append(" {\n") 2223 # What is a better way to change value from outer scope? 2224 namespace_declared.append(True) 2225 return writer 2226 2227 for type_data in domain_data.types(): 2228 type_data_callback(type_data, namespace_lazy_generator) 2229 2230 if namespace_declared: 2231 writer.append("} // ") 2232 writer.append(domain_data.name()) 2233 writer.append("\n\n") 2234 2235 def create_type_builder_caller(generate_pass_id): 2236 def call_type_builder(type_data, writer_getter): 2237 code_generator = type_data.get_binding().get_code_generator() 2238 if code_generator and generate_pass_id == code_generator.get_generate_pass_id(): 2239 writer = writer_getter() 2240 2241 code_generator.generate_type_builder(writer, GenerateContext) 2242 return call_type_builder 2243 2244 generate_all_domains_code(output, create_type_builder_caller(TypeBuilderPass.MAIN)) 2245 2246 Generator.type_builder_forwards.append("// Forward declarations.\n") 2247 2248 def generate_forward_callback(type_data, writer_getter): 2249 if type_data in global_forward_listener.type_data_set: 2250 binding = type_data.get_binding() 2251 binding.get_code_generator().generate_forward_declaration(writer_getter()) 2252 generate_all_domains_code(Generator.type_builder_forwards, generate_forward_callback) 2253 2254 Generator.type_builder_forwards.append("// End of forward declarations.\n\n") 2255 2256 Generator.type_builder_forwards.append("// Typedefs.\n") 2257 2258 generate_all_domains_code(Generator.type_builder_forwards, create_type_builder_caller(TypeBuilderPass.TYPEDEF)) 2259 2260 Generator.type_builder_forwards.append("// End of typedefs.\n\n") 2261 2262 2263 def flatten_list(input): 2264 res = [] 2265 2266 def fill_recursive(l): 2267 for item in l: 2268 if isinstance(item, list): 2269 fill_recursive(item) 2270 else: 2271 res.append(item) 2272 fill_recursive(input) 2273 return res 2274 2275 2276 # A writer that only updates file if it actually changed to better support incremental build. 2277 class SmartOutput: 2278 def __init__(self, file_name): 2279 self.file_name_ = file_name 2280 self.output_ = "" 2281 2282 def write(self, text): 2283 self.output_ += text 2284 2285 def close(self): 2286 text_changed = True 2287 2288 try: 2289 read_file = open(self.file_name_, "r") 2290 old_text = read_file.read() 2291 read_file.close() 2292 text_changed = old_text != self.output_ 2293 except: 2294 # Ignore, just overwrite by default 2295 pass 2296 2297 if text_changed: 2298 out_file = open(self.file_name_, "w") 2299 out_file.write(self.output_) 2300 out_file.close() 2301 2302 2303 def output_file(file_name): 2304 # For now, disable the incremental build optimisation in all cases. 2305 if False: 2306 return SmartOutput(file_name) 2307 else: 2308 return open(file_name, "w") 2309 2310 2311 Generator.go() 2312 2313 backend_h_file = output_file(output_dirname + "/InspectorBackendDispatcher.h") 2314 backend_cpp_file = output_file(output_dirname + "/InspectorBackendDispatcher.cpp") 2315 2316 frontend_h_file = output_file(output_dirname + "/InspectorFrontend.h") 2317 frontend_cpp_file = output_file(output_dirname + "/InspectorFrontend.cpp") 2318 2319 typebuilder_h_file = output_file(output_dirname + "/InspectorTypeBuilder.h") 2320 typebuilder_cpp_file = output_file(output_dirname + "/InspectorTypeBuilder.cpp") 2321 2322 2323 backend_h_file.write(Templates.backend_h.substitute(None, 2324 virtualSetters="\n".join(Generator.backend_virtual_setters_list), 2325 agentInterfaces="".join(flatten_list(Generator.backend_agent_interface_list)), 2326 methodNamesEnumContent="\n".join(Generator.method_name_enum_list))) 2327 2328 backend_cpp_file.write(Templates.backend_cpp.substitute(None, 2329 constructorInit="\n".join(Generator.backend_constructor_init_list), 2330 setters="\n".join(Generator.backend_setters_list), 2331 fieldDeclarations="\n".join(Generator.backend_field_list), 2332 methodNameDeclarations="\n".join(Generator.backend_method_name_declaration_list), 2333 methodNameDeclarationsIndex="\n".join(Generator.backend_method_name_declaration_index_list), 2334 methods="\n".join(Generator.backend_method_implementation_list), 2335 methodDeclarations="\n".join(Generator.backend_method_declaration_list), 2336 messageHandlers="\n".join(Generator.method_handler_list))) 2337 2338 frontend_h_file.write(Templates.frontend_h.substitute(None, 2339 fieldDeclarations="".join(Generator.frontend_class_field_lines), 2340 domainClassList="".join(Generator.frontend_domain_class_lines))) 2341 2342 frontend_cpp_file.write(Templates.frontend_cpp.substitute(None, 2343 constructorInit="".join(Generator.frontend_constructor_init_list), 2344 methods="\n".join(Generator.frontend_method_list))) 2345 2346 typebuilder_h_file.write(Templates.typebuilder_h.substitute(None, 2347 typeBuilders="".join(flatten_list(Generator.type_builder_fragments)), 2348 forwards="".join(Generator.type_builder_forwards), 2349 validatorIfdefName=VALIDATOR_IFDEF_NAME)) 2350 2351 typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None, 2352 enumConstantValues=EnumConstants.get_enum_constant_code(), 2353 implCode="".join(flatten_list(Generator.type_builder_impl_list)), 2354 validatorCode="".join(flatten_list(Generator.validator_impl_list)), 2355 validatorIfdefName=VALIDATOR_IFDEF_NAME)) 2356 2357 backend_h_file.close() 2358 backend_cpp_file.close() 2359 2360 frontend_h_file.close() 2361 frontend_cpp_file.close() 2362 2363 typebuilder_h_file.close() 2364 typebuilder_cpp_file.close() 2365