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