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