2 # Copyright (c) 2011 Google Inc. All rights reserved.
3 # Copyright (c) 2012 Intel Corporation. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
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
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.
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.
39 import simplejson as json
41 import CodeGeneratorInspectorStrings
43 # Manually-filled map of type name replacements.
45 "RGBA": "Rgba", # RGBA is reported to be conflicting with a define name in Windows CE.
50 TYPES_WITH_RUNTIME_CAST_SET = frozenset(["Runtime.RemoteObject", "Runtime.PropertyDescriptor", "Runtime.InternalPropertyDescriptor",
51 "Debugger.FunctionDetails", "Debugger.CallFrame", "Debugger.Location",
52 "Canvas.TraceLog", "Canvas.ResourceState"])
54 TYPES_WITH_OPEN_FIELD_LIST_SET = frozenset([
55 # InspectorStyleSheet not only creates this property but wants to read it and modify it.
57 # InspectorResourceAgent needs to update mime-type.
60 EXACTLY_INT_SUPPORTED = False
62 cmdline_parser = optparse.OptionParser()
63 cmdline_parser.add_option("--output_dir")
66 arg_options, arg_values = cmdline_parser.parse_args()
67 if (len(arg_values) != 1):
68 raise Exception("Exactly one plain argument expected (found %s)" % len(arg_values))
69 input_json_filename = arg_values[0]
70 output_dirname = arg_options.output_dir
71 if not output_dirname:
72 raise Exception("Output directory must be specified")
74 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
75 exc = sys.exc_info()[1]
76 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
77 sys.stderr.write("Usage: <script> --output_dir <output_dir> protocol.json\n")
81 # FIXME: move this methods under Capitalizer class below and remove duplications.
82 def dash_to_camelcase(word):
83 return ''.join(x.capitalize() or '-' for x in word.split('-'))
86 def fix_camel_case(name):
87 refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name)
88 refined = to_title_case(refined)
89 return re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), refined)
92 def to_title_case(name):
93 return name[:1].upper() + name[1:]
98 def lower_camel_case_to_upper(str):
99 if len(str) > 0 and str[0].islower():
100 str = str[0].upper() + str[1:]
104 def upper_camel_case_to_lower(str):
106 while pos < len(str) and str[pos].isupper():
111 return str[0].lower() + str[1:]
114 possible_abbreviation = str[0:pos]
115 if possible_abbreviation not in Capitalizer.ABBREVIATION:
116 raise Exception("Unknown abbreviation %s" % possible_abbreviation)
117 str = possible_abbreviation.lower() + str[pos:]
121 def camel_case_to_capitalized_with_underscores(str):
124 output = Capitalizer.split_camel_case_(str)
125 return "_".join(output).upper()
128 def split_camel_case_(str):
132 has_oneletter = False
133 while pos < len(str):
134 if str[pos].isupper():
135 output.append(str[pos_being:pos].upper())
136 if pos - pos_being == 1:
140 output.append(str[pos_being:])
143 while array_pos < len(output) - 1:
144 if len(output[array_pos]) == 1:
145 array_pos_end = array_pos + 1
146 while array_pos_end < len(output) and len(output[array_pos_end]) == 1:
148 if array_pos_end - array_pos > 1:
149 possible_abbreviation = "".join(output[array_pos:array_pos_end])
150 if possible_abbreviation.upper() in Capitalizer.ABBREVIATION:
151 output[array_pos:array_pos_end] = [possible_abbreviation]
153 array_pos = array_pos_end - 1
157 ABBREVIATION = frozenset(["XHR", "DOM", "CSS"])
159 VALIDATOR_IFDEF_NAME = "ASSERT_ENABLED"
162 class DomainNameFixes:
164 def get_fixed_data(cls, domain_name):
165 field_name_res = Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent"
168 agent_field_name = field_name_res
173 class RawTypes(object):
176 if json_type == "boolean":
178 elif json_type == "string":
179 return RawTypes.String
180 elif json_type == "array":
181 return RawTypes.Array
182 elif json_type == "object":
183 return RawTypes.Object
184 elif json_type == "integer":
186 elif json_type == "number":
187 return RawTypes.Number
188 elif json_type == "any":
191 raise Exception("Unknown type: %s" % json_type)
193 # For output parameter all values are passed by pointer except RefPtr-based types.
194 class OutputPassModel:
197 def get_argument_prefix():
201 def get_parameter_type_suffix():
206 def get_argument_prefix():
210 def get_parameter_type_suffix():
213 class BaseType(object):
214 need_internal_runtime_cast_ = False
217 def request_raw_internal_runtime_cast(cls):
218 if not cls.need_internal_runtime_cast_:
219 cls.need_internal_runtime_cast_ = True
222 def get_raw_validator_call_text(cls):
223 return "RuntimeCastHelper::assertType<JSONValue::Type%s>" % cls.get_validate_method_params().template_type
226 def get_validate_method_params():
227 raise Exception("Abstract method")
229 class String(BaseType):
231 def get_getter_name():
234 get_setter_name = get_getter_name
237 def get_constructor_pattern():
238 return "InspectorString::create(%s)"
241 def get_c_initializer():
245 def get_validate_method_params():
246 class ValidateMethodParams:
247 template_type = "String"
248 return ValidateMethodParams
251 def get_output_pass_model():
252 return RawTypes.OutputPassModel.ByPointer
255 def is_heavy_value():
259 def get_array_item_raw_c_type_text():
263 def get_raw_type_model():
264 return TypeModel.String
268 def get_getter_name():
272 def get_setter_name():
276 def get_constructor_pattern():
277 return "InspectorBasicValue::create(%s)"
280 def get_c_initializer():
284 def get_raw_validator_call_text(cls):
285 return "RuntimeCastHelper::assertInt"
288 def get_output_pass_model():
289 return RawTypes.OutputPassModel.ByPointer
292 def is_heavy_value():
296 def get_array_item_raw_c_type_text():
300 def get_raw_type_model():
303 class Number(BaseType):
305 def get_getter_name():
309 def get_setter_name():
313 def get_constructor_pattern():
314 return "InspectorBasicValue::create(%s)"
317 def get_c_initializer():
321 def get_validate_method_params():
322 class ValidateMethodParams:
323 template_type = "Number"
324 return ValidateMethodParams
327 def get_output_pass_model():
328 return RawTypes.OutputPassModel.ByPointer
331 def is_heavy_value():
335 def get_array_item_raw_c_type_text():
339 def get_raw_type_model():
340 return TypeModel.Number
342 class Bool(BaseType):
344 def get_getter_name():
347 get_setter_name = get_getter_name
350 def get_constructor_pattern():
351 return "InspectorBasicValue::create(%s)"
354 def get_c_initializer():
358 def get_validate_method_params():
359 class ValidateMethodParams:
360 template_type = "Boolean"
361 return ValidateMethodParams
364 def get_output_pass_model():
365 return RawTypes.OutputPassModel.ByPointer
368 def is_heavy_value():
372 def get_array_item_raw_c_type_text():
376 def get_raw_type_model():
377 return TypeModel.Bool
379 class Object(BaseType):
381 def get_getter_name():
385 def get_setter_name():
389 def get_constructor_pattern():
393 def get_c_initializer():
394 return "JSONObject::create()"
397 def get_output_argument_prefix():
401 def get_validate_method_params():
402 class ValidateMethodParams:
403 template_type = "Object"
404 return ValidateMethodParams
407 def get_output_pass_model():
408 return RawTypes.OutputPassModel.ByReference
411 def is_heavy_value():
415 def get_array_item_raw_c_type_text():
419 def get_raw_type_model():
420 return TypeModel.Object
424 def get_getter_name():
427 get_setter_name = get_getter_name
430 def get_c_initializer():
431 raise Exception("Unsupported")
434 def get_constructor_pattern():
435 raise Exception("Unsupported")
438 def get_raw_validator_call_text():
439 return "RuntimeCastHelper::assertAny"
442 def get_output_pass_model():
443 return RawTypes.OutputPassModel.ByReference
446 def is_heavy_value():
450 def get_array_item_raw_c_type_text():
454 def get_raw_type_model():
457 class Array(BaseType):
459 def get_getter_name():
463 def get_setter_name():
467 def get_constructor_pattern():
471 def get_c_initializer():
472 return "JSONArray::create()"
475 def get_output_argument_prefix():
479 def get_validate_method_params():
480 class ValidateMethodParams:
481 template_type = "Array"
482 return ValidateMethodParams
485 def get_output_pass_model():
486 return RawTypes.OutputPassModel.ByReference
489 def is_heavy_value():
493 def get_array_item_raw_c_type_text():
497 def get_raw_type_model():
498 return TypeModel.Array
501 def replace_right_shift(input_str):
502 return input_str.replace(">>", "> >")
505 class CommandReturnPassModel:
507 def __init__(self, var_type, set_condition):
508 self.var_type = var_type
509 self.set_condition = set_condition
511 def get_return_var_type(self):
515 def get_output_argument_prefix():
519 def get_output_to_raw_expression():
522 def get_output_parameter_type(self):
523 return self.var_type + "&"
525 def get_set_return_condition(self):
526 return self.set_condition
529 def __init__(self, var_type):
530 self.var_type = var_type
532 def get_return_var_type(self):
536 def get_output_argument_prefix():
540 def get_output_to_raw_expression():
543 def get_output_parameter_type(self):
544 return self.var_type + "*"
547 def get_set_return_condition():
551 def __init__(self, var_type):
552 self.var_type = var_type
554 def get_return_var_type(self):
555 return "TypeBuilder::OptOutput<%s>" % self.var_type
558 def get_output_argument_prefix():
562 def get_output_to_raw_expression():
563 return "%s.getValue()"
565 def get_output_parameter_type(self):
566 return "TypeBuilder::OptOutput<%s>*" % self.var_type
569 def get_set_return_condition():
570 return "%s.isAssigned()"
574 class RefPtrBased(object):
575 def __init__(self, class_name):
576 self.class_name = class_name
577 self.optional = False
579 def get_optional(self):
580 result = TypeModel.RefPtrBased(self.class_name)
581 result.optional = True
584 def get_command_return_pass_model(self):
589 return CommandReturnPassModel.ByReference(replace_right_shift("RefPtr<%s>" % self.class_name), set_condition)
591 def get_input_param_type_text(self):
592 return replace_right_shift("PassRefPtr<%s>" % self.class_name)
595 def get_event_setter_expression_pattern():
599 def __init__(self, base_type_name):
600 self.type_name = base_type_name + "::Enum"
602 def get_optional(base_self):
605 def get_optional(cls):
609 def get_command_return_pass_model():
610 return CommandReturnPassModel.OptOutput(base_self.type_name)
613 def get_input_param_type_text():
614 return base_self.type_name + "*"
617 def get_event_setter_expression_pattern():
618 raise Exception("TODO")
621 def get_command_return_pass_model(self):
622 return CommandReturnPassModel.ByPointer(self.type_name)
624 def get_input_param_type_text(self):
625 return self.type_name
628 def get_event_setter_expression_pattern():
631 class ValueType(object):
632 def __init__(self, type_name, is_heavy):
633 self.type_name = type_name
634 self.is_heavy = is_heavy
636 def get_optional(self):
637 return self.ValueOptional(self)
639 def get_command_return_pass_model(self):
640 return CommandReturnPassModel.ByPointer(self.type_name)
642 def get_input_param_type_text(self):
644 return "const %s&" % self.type_name
646 return self.type_name
648 def get_opt_output_type_(self):
649 return self.type_name
652 def get_event_setter_expression_pattern():
656 def __init__(self, base):
659 def get_optional(self):
662 def get_command_return_pass_model(self):
663 return CommandReturnPassModel.OptOutput(self.base.get_opt_output_type_())
665 def get_input_param_type_text(self):
666 return "const %s* const" % self.base.type_name
669 def get_event_setter_expression_pattern():
672 class ExactlyInt(ValueType):
674 TypeModel.ValueType.__init__(self, "int", False)
676 def get_input_param_type_text(self):
677 return "TypeBuilder::ExactlyInt"
679 def get_opt_output_type_(self):
680 return "TypeBuilder::ExactlyInt"
684 cls.Bool = cls.ValueType("bool", False)
685 if EXACTLY_INT_SUPPORTED:
686 cls.Int = cls.ExactlyInt()
688 cls.Int = cls.ValueType("int", False)
689 cls.Number = cls.ValueType("double", False)
690 cls.String = cls.ValueType("String", True,)
691 cls.Object = cls.RefPtrBased("JSONObject")
692 cls.Array = cls.RefPtrBased("JSONArray")
693 cls.Any = cls.RefPtrBased("JSONValue")
695 TypeModel.init_class()
698 # Collection of JSONObject class methods that are likely to be overloaded in generated class.
699 # We must explicitly import all overloaded methods or they won't be available to user.
700 INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"])
703 def fix_type_name(json_name):
704 if json_name in TYPE_NAME_FIX_MAP:
705 fixed = TYPE_NAME_FIX_MAP[json_name]
707 class Result(object):
711 def output_comment(writer):
712 writer.newline("// Type originally was named '%s'.\n" % json_name)
715 class Result(object):
716 class_name = json_name
719 def output_comment(writer):
726 def __init__(self, output, indent):
730 def newline(self, str):
732 self.output.append(self.indent)
733 self.output.append(str)
735 def append(self, str):
736 self.output.append(str)
738 def newline_multiline(self, str):
739 parts = str.split('\n')
740 self.newline(parts[0])
742 self.output.append('\n')
746 def append_multiline(self, str):
747 parts = str.split('\n')
748 self.append(parts[0])
750 self.output.append('\n')
754 def get_indent(self):
757 def get_indented(self, additional_indent):
758 return Writer(self.output, self.indent + additional_indent)
760 def insert_writer(self, additional_indent):
762 self.output.append(new_output)
763 return Writer(new_output, self.indent + additional_indent)
771 def add_constant(cls, value):
772 if value in cls.map_:
773 return cls.map_[value]
776 cls.map_[value] = pos
777 cls.constants_.append(value)
781 def get_enum_constant_code(cls):
783 for item in cls.constants_:
784 output.append(" \"" + item + "\"")
785 return ",\n".join(output) + "\n"
788 # Typebuilder code is generated in several passes: first typedefs, then other classes.
789 # Manual pass management is needed because we cannot have forward declarations for typedefs.
790 class TypeBuilderPass:
797 def create_named_type_declaration(json_typable, context_domain_name, type_data):
798 json_type = type_data.get_json_type()
802 full_name_prefix_for_use = "TypeBuilder::" + context_domain_name + "::"
803 full_name_prefix_for_impl = "TypeBuilder::" + context_domain_name + "::"
806 def write_doc(writer):
807 if "description" in json_type:
808 writer.newline("/* ")
809 writer.append(json_type["description"])
810 writer.append(" */\n")
813 def add_to_forward_listener(forward_listener):
814 forward_listener.add_type_data(type_data)
817 fixed_type_name = fix_type_name(json_type["id"])
818 return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
821 def create_ad_hoc_type_declaration(json_typable, context_domain_name, ad_hoc_type_context):
824 full_name_prefix_for_use = ad_hoc_type_context.container_relative_name_prefix
825 full_name_prefix_for_impl = ad_hoc_type_context.container_full_name_prefix
828 def write_doc(writer):
832 def add_to_forward_listener(forward_listener):
834 fixed_type_name = ad_hoc_type_context.get_type_name_fix()
835 return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
838 def create_type_declaration_(json_typable, context_domain_name, fixed_type_name, helper):
839 if json_typable["type"] == "string":
840 if "enum" in json_typable:
843 need_user_runtime_cast_ = False
844 need_internal_runtime_cast_ = False
847 def resolve_inner(cls, resolve_context):
851 def request_user_runtime_cast(cls, request):
853 cls.need_user_runtime_cast_ = True
854 request.acknowledge()
857 def request_internal_runtime_cast(cls):
858 cls.need_internal_runtime_cast_ = True
861 def get_code_generator(enum_binding_cls):
862 #FIXME: generate ad-hoc enums too once we figure out how to better implement them in C++.
863 comment_out = helper.is_ad_hoc
867 def generate_type_builder(writer, generate_context):
868 enum = json_typable["enum"]
869 helper.write_doc(writer)
870 enum_name = fixed_type_name.class_name
871 fixed_type_name.output_comment(writer)
872 writer.newline("struct ")
873 writer.append(enum_name)
874 writer.append(" {\n")
875 writer.newline(" enum Enum {\n")
876 for enum_item in enum:
877 enum_pos = EnumConstants.add_constant(enum_item)
879 item_c_name = enum_item.replace('-', '_')
880 item_c_name = Capitalizer.lower_camel_case_to_upper(item_c_name)
881 if item_c_name in TYPE_NAME_FIX_MAP:
882 item_c_name = TYPE_NAME_FIX_MAP[item_c_name]
884 writer.append(item_c_name)
886 writer.append("%s" % enum_pos)
888 writer.newline(" };\n")
889 if enum_binding_cls.need_user_runtime_cast_:
890 raise Exception("Not yet implemented")
892 if enum_binding_cls.need_internal_runtime_cast_:
893 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
894 writer.newline(" static void assertCorrectValue(JSONValue* value);\n")
895 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
897 validator_writer = generate_context.validator_writer
899 domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name)
901 validator_writer.newline("void %s%s::assertCorrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, enum_name))
902 validator_writer.newline("{\n")
903 validator_writer.newline(" WTF::String s;\n")
904 validator_writer.newline(" bool cast_res = value->asString(&s);\n")
905 validator_writer.newline(" ASSERT(cast_res);\n")
908 for enum_item in enum:
909 enum_pos = EnumConstants.add_constant(enum_item)
910 condition_list.append("s == \"%s\"" % enum_item)
911 validator_writer.newline(" ASSERT(%s);\n" % " || ".join(condition_list))
912 validator_writer.newline("}\n")
914 validator_writer.newline("\n\n")
916 writer.newline("}; // struct ")
917 writer.append(enum_name)
918 writer.append("\n\n")
921 def register_use(forward_listener):
925 def get_generate_pass_id():
926 return TypeBuilderPass.MAIN
931 def get_validator_call_text(cls):
932 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
935 def get_array_item_c_type_text(cls):
936 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::Enum"
939 def get_setter_value_expression_pattern():
940 return "TypeBuilder::getEnumConstantValue(%s)"
943 def reduce_to_raw_type():
944 return RawTypes.String
947 def get_type_model():
948 return TypeModel.Enum(helper.full_name_prefix_for_use + fixed_type_name.class_name)
956 def resolve_inner(cls, resolve_context):
960 def request_user_runtime_cast(request):
961 raise Exception("Unsupported")
964 def request_internal_runtime_cast():
968 def get_code_generator():
972 def get_validator_call_text(cls):
973 return RawTypes.String.get_raw_validator_call_text()
976 def reduce_to_raw_type():
977 return RawTypes.String
980 def get_type_model():
981 return TypeModel.String
984 def get_setter_value_expression_pattern():
988 def get_array_item_c_type_text(cls):
989 return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
997 def resolve_inner(cls, resolve_context):
1001 def request_user_runtime_cast(request):
1002 raise Exception("Unsupported")
1005 def request_internal_runtime_cast():
1006 RawTypes.String.request_raw_internal_runtime_cast()
1009 def get_code_generator():
1010 class CodeGenerator:
1012 def generate_type_builder(writer, generate_context):
1013 helper.write_doc(writer)
1014 fixed_type_name.output_comment(writer)
1015 writer.newline("typedef String ")
1016 writer.append(fixed_type_name.class_name)
1017 writer.append(";\n\n")
1020 def register_use(forward_listener):
1024 def get_generate_pass_id():
1025 return TypeBuilderPass.TYPEDEF
1027 return CodeGenerator
1030 def get_validator_call_text(cls):
1031 return RawTypes.String.get_raw_validator_call_text()
1034 def reduce_to_raw_type():
1035 return RawTypes.String
1038 def get_type_model():
1039 return TypeModel.ValueType("%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name), True)
1042 def get_setter_value_expression_pattern():
1046 def get_array_item_c_type_text(cls):
1047 return "%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name)
1049 return TypedefString
1051 elif json_typable["type"] == "object":
1052 if "properties" in json_typable:
1055 resolve_data_ = None
1056 need_user_runtime_cast_ = False
1057 need_internal_runtime_cast_ = False
1060 def resolve_inner(cls, resolve_context):
1061 if cls.resolve_data_:
1064 properties = json_typable["properties"]
1068 ad_hoc_type_list = []
1070 for prop in properties:
1071 prop_name = prop["name"]
1072 ad_hoc_type_context = cls.AdHocTypeContextImpl(prop_name, fixed_type_name.class_name, resolve_context, ad_hoc_type_list, helper.full_name_prefix_for_impl)
1073 binding = resolve_param_type(prop, context_domain_name, ad_hoc_type_context)
1075 code_generator = binding.get_code_generator()
1077 code_generator.register_use(resolve_context.forward_listener)
1080 param_type_binding = binding
1083 if prop.get("optional"):
1084 optional.append(PropertyData)
1086 main.append(PropertyData)
1089 main_properties = main
1090 optional_properties = optional
1091 ad_hoc_types = ad_hoc_type_list
1093 cls.resolve_data_ = ResolveData
1095 for ad_hoc in ad_hoc_type_list:
1096 ad_hoc.resolve_inner(resolve_context)
1099 def request_user_runtime_cast(cls, request):
1102 cls.need_user_runtime_cast_ = True
1103 request.acknowledge()
1104 cls.request_internal_runtime_cast()
1107 def request_internal_runtime_cast(cls):
1108 if cls.need_internal_runtime_cast_:
1110 cls.need_internal_runtime_cast_ = True
1111 for p in cls.resolve_data_.main_properties:
1112 p.param_type_binding.request_internal_runtime_cast()
1113 for p in cls.resolve_data_.optional_properties:
1114 p.param_type_binding.request_internal_runtime_cast()
1117 def get_code_generator(class_binding_cls):
1118 class CodeGenerator:
1120 def generate_type_builder(cls, writer, generate_context):
1121 resolve_data = class_binding_cls.resolve_data_
1122 helper.write_doc(writer)
1123 class_name = fixed_type_name.class_name
1125 is_open_type = (context_domain_name + "." + class_name) in TYPES_WITH_OPEN_FIELD_LIST_SET
1127 fixed_type_name.output_comment(writer)
1128 writer.newline("class ")
1129 writer.append(class_name)
1130 writer.append(" : public ")
1132 writer.append("JSONObject")
1134 writer.append("JSONObjectBase")
1135 writer.append(" {\n")
1136 writer.newline("public:\n")
1137 ad_hoc_type_writer = writer.insert_writer(" ")
1139 for ad_hoc_type in resolve_data.ad_hoc_types:
1140 code_generator = ad_hoc_type.get_code_generator()
1142 code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
1144 writer.newline_multiline(
1149 state_enum_items = []
1150 if len(resolve_data.main_properties) > 0:
1152 for prop_data in resolve_data.main_properties:
1153 item_name = Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]) + "Set"
1154 state_enum_items.append(item_name)
1155 writer.newline(" %s = 1 << %s,\n" % (item_name, pos))
1157 all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")"
1159 all_fields_set_value = "0"
1161 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_1
1162 % (all_fields_set_value, class_name, class_name))
1165 for prop_data in resolve_data.main_properties:
1166 prop_name = prop_data.p["name"]
1168 param_type_binding = prop_data.param_type_binding
1169 param_raw_type = param_type_binding.reduce_to_raw_type()
1171 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_2
1172 % (state_enum_items[pos],
1173 Capitalizer.lower_camel_case_to_upper(prop_name),
1174 param_type_binding.get_type_model().get_input_param_type_text(),
1175 state_enum_items[pos], prop_name,
1176 param_raw_type.get_setter_name(), prop_name,
1177 format_setter_value_expression(param_type_binding, "value"),
1178 state_enum_items[pos]))
1182 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_3
1183 % (class_name, class_name, class_name, class_name, class_name))
1185 writer.newline(" /*\n")
1186 writer.newline(" * Synthetic constructor:\n")
1187 writer.newline(" * RefPtr<%s> result = %s::create()" % (class_name, class_name))
1188 for prop_data in resolve_data.main_properties:
1189 writer.append_multiline("\n * .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]))
1190 writer.append_multiline(";\n */\n")
1192 writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_4)
1194 writer.newline(" typedef TypeBuilder::StructItemTraits ItemTraits;\n")
1196 for prop_data in resolve_data.main_properties:
1197 prop_name = prop_data.p["name"]
1198 param_type_binding = prop_data.param_type_binding
1199 raw_type = param_type_binding.reduce_to_raw_type()
1200 if isinstance(param_type_binding.get_type_model(), TypeModel.ValueType):
1201 writer.append_multiline("\n void %s" % prop_name)
1202 writer.append("(%s value)\n" % param_type_binding.get_type_model().get_command_return_pass_model().get_output_parameter_type())
1203 writer.newline(" {\n")
1204 writer.newline(" JSONObjectBase::get%s(\"%s\", value);\n"
1205 % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"]))
1206 writer.newline(" }\n")
1208 for prop_data in resolve_data.optional_properties:
1209 prop_name = prop_data.p["name"]
1210 param_type_binding = prop_data.param_type_binding
1211 setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop_name)
1213 writer.append_multiline("\n void %s" % setter_name)
1214 writer.append("(%s value)\n" % param_type_binding.get_type_model().get_input_param_type_text())
1215 writer.newline(" {\n")
1216 writer.newline(" this->set%s(\"%s\", %s);\n"
1217 % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"],
1218 format_setter_value_expression(param_type_binding, "value")))
1219 writer.newline(" }\n")
1221 if setter_name in INSPECTOR_OBJECT_SETTER_NAMES:
1222 writer.newline(" using JSONObjectBase::%s;\n\n" % setter_name)
1224 if class_binding_cls.need_user_runtime_cast_:
1225 writer.newline(" static PassRefPtr<%s> runtimeCast(PassRefPtr<JSONValue> value)\n" % class_name)
1226 writer.newline(" {\n")
1227 writer.newline(" RefPtr<JSONObject> object;\n")
1228 writer.newline(" bool castRes = value->asObject(&object);\n")
1229 writer.newline(" ASSERT_UNUSED(castRes, castRes);\n")
1230 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
1231 writer.newline(" assertCorrectValue(object.get());\n")
1232 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
1233 writer.newline(" COMPILE_ASSERT(sizeof(%s) == sizeof(JSONObjectBase), type_cast_problem);\n" % class_name)
1234 writer.newline(" return static_cast<%s*>(static_cast<JSONObjectBase*>(object.get()));\n" % class_name)
1235 writer.newline(" }\n")
1238 if class_binding_cls.need_internal_runtime_cast_:
1239 writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
1240 writer.newline(" static void assertCorrectValue(JSONValue* value);\n")
1241 writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
1243 closed_field_set = (context_domain_name + "." + class_name) not in TYPES_WITH_OPEN_FIELD_LIST_SET
1245 validator_writer = generate_context.validator_writer
1247 domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name)
1249 validator_writer.newline("void %s%s::assertCorrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, class_name))
1250 validator_writer.newline("{\n")
1251 validator_writer.newline(" RefPtr<JSONObject> object;\n")
1252 validator_writer.newline(" bool castRes = value->asObject(&object);\n")
1253 validator_writer.newline(" ASSERT_UNUSED(castRes, castRes);\n")
1254 for prop_data in resolve_data.main_properties:
1255 validator_writer.newline(" {\n")
1256 it_name = "%sPos" % prop_data.p["name"]
1257 validator_writer.newline(" JSONObject::iterator %s;\n" % it_name)
1258 validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
1259 validator_writer.newline(" ASSERT(%s != object->end());\n" % it_name)
1260 validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
1261 validator_writer.newline(" }\n")
1263 if closed_field_set:
1264 validator_writer.newline(" int foundPropertiesCount = %s;\n" % len(resolve_data.main_properties))
1266 for prop_data in resolve_data.optional_properties:
1267 validator_writer.newline(" {\n")
1268 it_name = "%sPos" % prop_data.p["name"]
1269 validator_writer.newline(" JSONObject::iterator %s;\n" % it_name)
1270 validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
1271 validator_writer.newline(" if (%s != object->end()) {\n" % it_name)
1272 validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
1273 if closed_field_set:
1274 validator_writer.newline(" ++foundPropertiesCount;\n")
1275 validator_writer.newline(" }\n")
1276 validator_writer.newline(" }\n")
1278 if closed_field_set:
1279 validator_writer.newline(" if (foundPropertiesCount != object->size()) {\n")
1280 validator_writer.newline(" FATAL(\"Unexpected properties in object: %s\\n\", object->toJSONString().ascii().data());\n")
1281 validator_writer.newline(" }\n")
1282 validator_writer.newline("}\n")
1284 validator_writer.newline("\n\n")
1287 cpp_writer = generate_context.cpp_writer
1289 writer.newline(" // Property names for type generated as open.\n")
1290 for prop_data in resolve_data.main_properties + resolve_data.optional_properties:
1291 prop_name = prop_data.p["name"]
1292 prop_field_name = Capitalizer.lower_camel_case_to_upper(prop_name)
1293 writer.newline(" static const char %s[];\n" % (prop_field_name))
1294 cpp_writer.newline("const char %s%s::%s[] = \"%s\";\n" % (helper.full_name_prefix_for_impl, class_name, prop_field_name, prop_name))
1297 writer.newline("};\n\n")
1300 def generate_forward_declaration(writer):
1301 class_name = fixed_type_name.class_name
1302 writer.newline("class ")
1303 writer.append(class_name)
1304 writer.append(";\n")
1307 def register_use(forward_listener):
1308 helper.add_to_forward_listener(forward_listener)
1311 def get_generate_pass_id():
1312 return TypeBuilderPass.MAIN
1314 return CodeGenerator
1317 def get_validator_call_text():
1318 return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
1321 def get_array_item_c_type_text(cls):
1322 return helper.full_name_prefix_for_use + fixed_type_name.class_name
1325 def get_setter_value_expression_pattern():
1329 def reduce_to_raw_type():
1330 return RawTypes.Object
1333 def get_type_model():
1334 return TypeModel.RefPtrBased(helper.full_name_prefix_for_use + fixed_type_name.class_name)
1336 class AdHocTypeContextImpl:
1337 def __init__(self, property_name, class_name, resolve_context, ad_hoc_type_list, parent_full_name_prefix):
1338 self.property_name = property_name
1339 self.class_name = class_name
1340 self.resolve_context = resolve_context
1341 self.ad_hoc_type_list = ad_hoc_type_list
1342 self.container_full_name_prefix = parent_full_name_prefix + class_name + "::"
1343 self.container_relative_name_prefix = ""
1345 def get_type_name_fix(self):
1347 class_name = Capitalizer.lower_camel_case_to_upper(self.property_name)
1350 def output_comment(writer):
1351 writer.newline("// Named after property name '%s' while generating %s.\n" % (self.property_name, self.class_name))
1355 def add_type(self, binding):
1356 self.ad_hoc_type_list.append(binding)
1361 class PlainObjectBinding:
1363 def resolve_inner(cls, resolve_context):
1367 def request_user_runtime_cast(request):
1371 def request_internal_runtime_cast():
1372 RawTypes.Object.request_raw_internal_runtime_cast()
1375 def get_code_generator():
1379 def get_validator_call_text():
1380 return "RuntimeCastHelper::assertType<JSONValue::TypeObject>"
1383 def get_array_item_c_type_text(cls):
1384 return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
1387 def get_setter_value_expression_pattern():
1391 def reduce_to_raw_type():
1392 return RawTypes.Object
1395 def get_type_model():
1396 return TypeModel.Object
1398 return PlainObjectBinding
1399 elif json_typable["type"] == "array":
1400 if "items" in json_typable:
1404 class AdHocTypeContext:
1405 container_full_name_prefix = "<not yet defined>"
1406 container_relative_name_prefix = ""
1409 def get_type_name_fix():
1410 return fixed_type_name
1413 def add_type(binding):
1414 ad_hoc_types.append(binding)
1416 item_binding = resolve_param_type(json_typable["items"], context_domain_name, AdHocTypeContext)
1419 resolve_data_ = None
1420 need_internal_runtime_cast_ = False
1423 def resolve_inner(cls, resolve_context):
1424 if cls.resolve_data_:
1428 item_type_binding = item_binding
1429 ad_hoc_type_list = ad_hoc_types
1431 cls.resolve_data_ = ResolveData
1433 for t in ad_hoc_types:
1434 t.resolve_inner(resolve_context)
1437 def request_user_runtime_cast(cls, request):
1438 raise Exception("Not implemented yet")
1441 def request_internal_runtime_cast(cls):
1442 if cls.need_internal_runtime_cast_:
1444 cls.need_internal_runtime_cast_ = True
1445 cls.resolve_data_.item_type_binding.request_internal_runtime_cast()
1448 def get_code_generator(array_binding_cls):
1450 class CodeGenerator:
1452 def generate_type_builder(writer, generate_context):
1453 ad_hoc_type_writer = writer
1455 resolve_data = array_binding_cls.resolve_data_
1457 for ad_hoc_type in resolve_data.ad_hoc_type_list:
1458 code_generator = ad_hoc_type.get_code_generator()
1460 code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
1463 def generate_forward_declaration(writer):
1467 def register_use(forward_listener):
1468 item_code_generator = item_binding.get_code_generator()
1469 if item_code_generator:
1470 item_code_generator.register_use(forward_listener)
1473 def get_generate_pass_id():
1474 return TypeBuilderPass.MAIN
1476 return CodeGenerator
1479 def get_validator_call_text(cls):
1480 return cls.get_array_item_c_type_text() + "::assertCorrectValue"
1483 def get_array_item_c_type_text(cls):
1484 return replace_right_shift("TypeBuilder::Array<%s>" % cls.resolve_data_.item_type_binding.get_array_item_c_type_text())
1487 def get_setter_value_expression_pattern():
1491 def reduce_to_raw_type():
1492 return RawTypes.Array
1495 def get_type_model(cls):
1496 return TypeModel.RefPtrBased(cls.get_array_item_c_type_text())
1500 # Fall-through to raw type.
1503 raw_type = RawTypes.get(json_typable["type"])
1505 return RawTypeBinding(raw_type)
1508 class RawTypeBinding:
1509 def __init__(self, raw_type):
1510 self.raw_type_ = raw_type
1512 def resolve_inner(self, resolve_context):
1515 def request_user_runtime_cast(self, request):
1516 raise Exception("Unsupported")
1518 def request_internal_runtime_cast(self):
1519 self.raw_type_.request_raw_internal_runtime_cast()
1521 def get_code_generator(self):
1524 def get_validator_call_text(self):
1525 return self.raw_type_.get_raw_validator_call_text()
1527 def get_array_item_c_type_text(self):
1528 return self.raw_type_.get_array_item_raw_c_type_text()
1530 def get_setter_value_expression_pattern(self):
1533 def reduce_to_raw_type(self):
1534 return self.raw_type_
1536 def get_type_model(self):
1537 return self.raw_type_.get_raw_type_model()
1540 class TypeData(object):
1541 def __init__(self, json_type, json_domain, domain_data):
1542 self.json_type_ = json_type
1543 self.json_domain_ = json_domain
1544 self.domain_data_ = domain_data
1546 if "type" not in json_type:
1547 raise Exception("Unknown type")
1549 json_type_name = json_type["type"]
1550 raw_type = RawTypes.get(json_type_name)
1551 self.raw_type_ = raw_type
1552 self.binding_being_resolved_ = False
1553 self.binding_ = None
1555 def get_raw_type(self):
1556 return self.raw_type_
1558 def get_binding(self):
1559 if not self.binding_:
1560 if self.binding_being_resolved_:
1561 raise Error("Type %s is already being resolved" % self.json_type_["type"])
1562 # Resolve only lazily, because resolving one named type may require resolving some other named type.
1563 self.binding_being_resolved_ = True
1565 self.binding_ = TypeBindings.create_named_type_declaration(self.json_type_, self.json_domain_["domain"], self)
1567 self.binding_being_resolved_ = False
1569 return self.binding_
1571 def get_json_type(self):
1572 return self.json_type_
1575 return self.json_type_["id"]
1577 def get_domain_name(self):
1578 return self.json_domain_["domain"]
1582 def __init__(self, json_domain):
1583 self.json_domain = json_domain
1586 def add_type(self, type_data):
1587 self.types_.append(type_data)
1590 return self.json_domain["domain"]
1597 def __init__(self, api):
1600 for json_domain in api["domains"]:
1601 domain_name = json_domain["domain"]
1604 self.map_[domain_name] = domain_map
1606 domain_data = DomainData(json_domain)
1607 self.domains_.append(domain_data)
1609 if "types" in json_domain:
1610 for json_type in json_domain["types"]:
1611 type_name = json_type["id"]
1612 type_data = TypeData(json_type, json_domain, domain_data)
1613 domain_map[type_name] = type_data
1614 domain_data.add_type(type_data)
1617 return self.domains_
1619 def get(self, domain_name, type_name):
1620 return self.map_[domain_name][type_name]
1623 def resolve_param_type(json_parameter, scope_domain_name, ad_hoc_type_context):
1624 if "$ref" in json_parameter:
1625 json_ref = json_parameter["$ref"]
1626 type_data = get_ref_data(json_ref, scope_domain_name)
1627 return type_data.get_binding()
1628 elif "type" in json_parameter:
1629 result = TypeBindings.create_ad_hoc_type_declaration(json_parameter, scope_domain_name, ad_hoc_type_context)
1630 ad_hoc_type_context.add_type(result)
1633 raise Exception("Unknown type")
1635 def resolve_param_raw_type(json_parameter, scope_domain_name):
1636 if "$ref" in json_parameter:
1637 json_ref = json_parameter["$ref"]
1638 type_data = get_ref_data(json_ref, scope_domain_name)
1639 return type_data.get_raw_type()
1640 elif "type" in json_parameter:
1641 json_type = json_parameter["type"]
1642 return RawTypes.get(json_type)
1644 raise Exception("Unknown type")
1647 def get_ref_data(json_ref, scope_domain_name):
1648 dot_pos = json_ref.find(".")
1650 domain_name = scope_domain_name
1651 type_name = json_ref
1653 domain_name = json_ref[:dot_pos]
1654 type_name = json_ref[dot_pos + 1:]
1656 return type_map.get(domain_name, type_name)
1659 input_file = open(input_json_filename, "r")
1660 json_string = input_file.read()
1661 json_api = json.loads(json_string)
1665 def get_this_script_path_(absolute_path):
1666 absolute_path = os.path.abspath(absolute_path)
1669 def fill_recursive(path_part, depth):
1670 if depth <= 0 or path_part == '/':
1672 fill_recursive(os.path.dirname(path_part), depth - 1)
1673 components.append(os.path.basename(path_part))
1675 # Typical path is /Source/WebCore/inspector/CodeGeneratorInspector.py
1676 # Let's take 4 components from the real path then.
1677 fill_recursive(absolute_path, 4)
1679 return "/".join(components)
1681 file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) +
1682 """// Copyright (c) 2011 The Chromium Authors. All rights reserved.
1683 // Use of this source code is governed by a BSD-style license that can be
1684 // found in the LICENSE file.
1687 frontend_domain_class = string.Template(CodeGeneratorInspectorStrings.frontend_domain_class)
1688 backend_method = string.Template(CodeGeneratorInspectorStrings.backend_method)
1689 frontend_method = string.Template(CodeGeneratorInspectorStrings.frontend_method)
1690 callback_main_methods = string.Template(CodeGeneratorInspectorStrings.callback_main_methods)
1691 callback_failure_method = string.Template(CodeGeneratorInspectorStrings.callback_failure_method)
1692 frontend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_h)
1693 backend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_h)
1694 backend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_cpp)
1695 frontend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_cpp)
1696 typebuilder_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_h)
1697 typebuilder_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_cpp)
1698 param_container_access_code = CodeGeneratorInspectorStrings.param_container_access_code
1704 type_map = TypeMap(json_api)
1707 class NeedRuntimeCastRequest:
1711 def acknowledge(self):
1714 def is_acknowledged(self):
1718 def resolve_all_types():
1719 runtime_cast_generate_requests = {}
1720 for type_name in TYPES_WITH_RUNTIME_CAST_SET:
1721 runtime_cast_generate_requests[type_name] = NeedRuntimeCastRequest()
1723 class ForwardListener:
1724 type_data_set = set()
1725 already_declared_set = set()
1728 def add_type_data(cls, type_data):
1729 if type_data not in cls.already_declared_set:
1730 cls.type_data_set.add(type_data)
1732 class ResolveContext:
1733 forward_listener = ForwardListener
1735 for domain_data in type_map.domains():
1736 for type_data in domain_data.types():
1737 # Do not generate forwards for this type any longer.
1738 ForwardListener.already_declared_set.add(type_data)
1740 binding = type_data.get_binding()
1741 binding.resolve_inner(ResolveContext)
1743 for domain_data in type_map.domains():
1744 for type_data in domain_data.types():
1745 full_type_name = "%s.%s" % (type_data.get_domain_name(), type_data.get_name())
1746 request = runtime_cast_generate_requests.pop(full_type_name, None)
1747 binding = type_data.get_binding()
1749 binding.request_user_runtime_cast(request)
1751 if request and not request.is_acknowledged():
1752 raise Exception("Failed to generate runtimeCast in " + full_type_name)
1754 for full_type_name in runtime_cast_generate_requests:
1755 raise Exception("Failed to generate runtimeCast. Type " + full_type_name + " not found")
1757 return ForwardListener
1760 global_forward_listener = resolve_all_types()
1763 def get_annotated_type_text(raw_type, annotated_type):
1764 if annotated_type != raw_type:
1765 return "/*%s*/ %s" % (annotated_type, raw_type)
1770 def format_setter_value_expression(param_type_binding, value_ref):
1771 pattern = param_type_binding.get_setter_value_expression_pattern()
1773 return pattern % value_ref
1778 frontend_class_field_lines = []
1779 frontend_domain_class_lines = []
1781 method_name_enum_list = []
1782 backend_method_declaration_list = []
1783 backend_method_implementation_list = []
1784 backend_method_name_declaration_list = []
1785 backend_method_name_declaration_index_list = []
1786 backend_method_name_declaration_current_index = 0
1787 method_handler_list = []
1788 frontend_method_list = []
1790 backend_virtual_setters_list = []
1791 backend_agent_interface_list = []
1792 backend_setters_list = []
1793 backend_constructor_init_list = []
1794 backend_field_list = []
1795 frontend_constructor_init_list = []
1796 type_builder_fragments = []
1797 type_builder_forwards = []
1798 validator_impl_list = []
1799 type_builder_impl_list = []
1804 Generator.process_types(type_map)
1806 first_cycle_guardable_list_list = [
1807 Generator.backend_method_declaration_list,
1808 Generator.backend_method_implementation_list,
1809 Generator.backend_method_name_declaration_list,
1810 Generator.backend_method_name_declaration_index_list,
1811 Generator.backend_agent_interface_list,
1812 Generator.frontend_class_field_lines,
1813 Generator.frontend_constructor_init_list,
1814 Generator.frontend_domain_class_lines,
1815 Generator.frontend_method_list,
1816 Generator.method_handler_list,
1817 Generator.method_name_enum_list,
1818 Generator.backend_constructor_init_list,
1819 Generator.backend_virtual_setters_list,
1820 Generator.backend_setters_list,
1821 Generator.backend_field_list]
1823 for json_domain in json_api["domains"]:
1824 domain_name = json_domain["domain"]
1825 domain_name_lower = domain_name.lower()
1827 domain_fixes = DomainNameFixes.get_fixed_data(domain_name)
1829 agent_field_name = domain_fixes.agent_field_name
1831 frontend_method_declaration_lines = []
1833 if "events" in json_domain:
1834 for json_event in json_domain["events"]:
1835 Generator.process_event(json_event, domain_name, frontend_method_declaration_lines)
1837 Generator.frontend_class_field_lines.append(" %s m_%s;\n" % (domain_name, domain_name_lower))
1838 if Generator.frontend_constructor_init_list:
1839 Generator.frontend_constructor_init_list.append(" , ")
1840 Generator.frontend_constructor_init_list.append("m_%s(inspectorFrontendChannel)\n" % domain_name_lower)
1841 Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None,
1842 domainClassName=domain_name,
1843 domainFieldName=domain_name_lower,
1844 frontendDomainMethodDeclarations="".join(flatten_list(frontend_method_declaration_lines))))
1846 agent_interface_name = Capitalizer.lower_camel_case_to_upper(domain_name) + "CommandHandler"
1847 Generator.backend_agent_interface_list.append(" class %s {\n" % agent_interface_name)
1848 Generator.backend_agent_interface_list.append(" public:\n")
1849 if "commands" in json_domain:
1850 for json_command in json_domain["commands"]:
1851 Generator.process_command(json_command, domain_name, agent_field_name, agent_interface_name)
1852 Generator.backend_agent_interface_list.append("\n protected:\n")
1853 Generator.backend_agent_interface_list.append(" virtual ~%s() { }\n" % agent_interface_name)
1854 Generator.backend_agent_interface_list.append(" };\n\n")
1856 Generator.backend_constructor_init_list.append(" , m_%s(0)" % agent_field_name)
1857 Generator.backend_virtual_setters_list.append(" virtual void registerAgent(%s* %s) = 0;" % (agent_interface_name, agent_field_name))
1858 Generator.backend_setters_list.append(" virtual void registerAgent(%s* %s) { ASSERT(!m_%s); m_%s = %s; }" % (agent_interface_name, agent_field_name, agent_field_name, agent_field_name, agent_field_name))
1859 Generator.backend_field_list.append(" %s* m_%s;" % (agent_interface_name, agent_field_name))
1862 def process_event(json_event, domain_name, frontend_method_declaration_lines):
1863 if (("handlers" in json_event) and (not ("renderer" in json_event["handlers"]))):
1866 event_name = json_event["name"]
1868 ad_hoc_type_output = []
1869 frontend_method_declaration_lines.append(ad_hoc_type_output)
1870 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
1872 decl_parameter_list = []
1874 json_parameters = json_event.get("parameters")
1875 Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer,
1876 decl_parameter_list,
1877 Generator.EventMethodStructTemplate,
1878 Generator.frontend_method_list, Templates.frontend_method, {"eventName": event_name})
1880 frontend_method_declaration_lines.append(
1881 " void %s(%s);\n" % (event_name, ", ".join(decl_parameter_list)))
1883 class EventMethodStructTemplate:
1885 def append_prolog(line_list):
1886 line_list.append(" RefPtr<JSONObject> paramsObject = JSONObject::create();\n")
1889 def append_epilog(line_list):
1890 line_list.append(" jsonMessage->setObject(\"params\", paramsObject);\n")
1892 container_name = "paramsObject"
1895 def process_command(json_command, domain_name, agent_field_name, agent_interface_name):
1896 if (("handlers" in json_command) and (not ("renderer" in json_command["handlers"]))):
1899 json_command_name = json_command["name"]
1901 cmd_enum_name = "k%s_%sCmd" % (domain_name, json_command["name"])
1903 Generator.method_name_enum_list.append(" %s," % cmd_enum_name)
1904 Generator.method_handler_list.append(" &InspectorBackendDispatcherImpl::%s_%s," % (domain_name, json_command_name))
1905 Generator.backend_method_declaration_list.append(" void %s_%s(long callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);" % (domain_name, json_command_name))
1907 backend_agent_interface_list = [] if "redirect" in json_command else Generator.backend_agent_interface_list
1909 ad_hoc_type_output = []
1910 backend_agent_interface_list.append(ad_hoc_type_output)
1911 ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
1913 backend_agent_interface_list.append(" virtual void %s(ErrorString*" % json_command_name)
1916 method_out_code = ""
1917 result_object_declaration = ""
1918 agent_call_param_list = ["&error"]
1919 agent_call_params_declaration_list = [" ErrorString error;"]
1920 send_response_call_params_list = ["error"]
1921 request_message_param = ""
1922 normal_response_cook_text = ""
1923 error_type_binding = None
1924 if "error" in json_command:
1925 json_error = json_command["error"]
1926 error_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_error, json_command_name + "Error", json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::")
1927 error_type_model = error_type_binding.get_type_model().get_optional()
1928 error_annotated_type = error_type_model.get_command_return_pass_model().get_output_parameter_type()
1929 agent_call_param_list.append("%serrorData" % error_type_model.get_command_return_pass_model().get_output_argument_prefix())
1930 backend_agent_interface_list.append(", %s errorData" % error_annotated_type)
1931 method_in_code += " %s errorData;\n" % error_type_model.get_command_return_pass_model().get_return_var_type()
1932 send_response_call_params_list.append("errorData")
1934 if "parameters" in json_command:
1935 json_params = json_command["parameters"]
1936 request_message_param = " requestMessageObject"
1939 method_in_code += Templates.param_container_access_code
1941 for json_parameter in json_params:
1942 json_param_name = json_parameter["name"]
1943 param_raw_type = resolve_param_raw_type(json_parameter, domain_name)
1945 getter_name = param_raw_type.get_getter_name()
1947 optional = json_parameter.get("optional")
1949 non_optional_type_model = param_raw_type.get_raw_type_model()
1951 type_model = non_optional_type_model.get_optional()
1953 type_model = non_optional_type_model
1956 code = (" bool %s_valueFound = false;\n"
1957 " %s in_%s = get%s(paramsContainerPtr, \"%s\", &%s_valueFound, protocolErrors);\n" %
1958 (json_param_name, non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name, json_param_name))
1959 param = "%s_valueFound ? &in_%s : 0" % (json_param_name, json_param_name)
1960 # FIXME: pass optional refptr-values as PassRefPtr
1961 formal_param_type_pattern = "const %s*"
1963 code = (" %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrors);\n" %
1964 (non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name))
1965 param = "in_%s" % json_param_name
1966 # FIXME: pass not-optional refptr-values as NonNullPassRefPtr
1967 if param_raw_type.is_heavy_value():
1968 formal_param_type_pattern = "const %s&"
1970 formal_param_type_pattern = "%s"
1972 method_in_code += code
1973 agent_call_param_list.append(param)
1974 backend_agent_interface_list.append(", %s in_%s" % (formal_param_type_pattern % non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name))
1976 if json_command.get("async") == True:
1977 callback_name = Capitalizer.lower_camel_case_to_upper(json_command_name) + "Callback"
1979 callback_output = []
1980 callback_writer = Writer(callback_output, ad_hoc_type_writer.get_indent())
1982 decl_parameter_list = []
1983 Generator.generate_send_method(json_command.get("returns"), json_command_name, domain_name, ad_hoc_type_writer,
1984 decl_parameter_list,
1985 Generator.CallbackMethodStructTemplate,
1986 Generator.backend_method_implementation_list, Templates.callback_main_methods,
1987 {"callbackName": callback_name, "agentName": agent_interface_name})
1989 callback_writer.newline("class " + callback_name + " : public CallbackBase {\n")
1990 callback_writer.newline("public:\n")
1991 callback_writer.newline(" " + callback_name + "(PassRefPtr<InspectorBackendDispatcherImpl>, int id);\n")
1992 callback_writer.newline(" void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
1993 error_part_writer = callback_writer.insert_writer("")
1994 callback_writer.newline("};\n")
1996 if error_type_binding:
1997 annotated_type = error_type_model.get_input_param_type_text()
1998 error_part_writer.newline(" void sendFailure(const ErrorString&, %s);\n" % annotated_type)
1999 error_part_writer.newline(" using CallbackBase::sendFailure;\n")
2001 assigment_value = error_type_model.get_event_setter_expression_pattern() % "errorData"
2002 assigment_value = error_type_binding.reduce_to_raw_type().get_constructor_pattern() % assigment_value
2004 Generator.backend_method_implementation_list.append(Templates.callback_failure_method.substitute(None,
2005 agentName=agent_interface_name,
2006 callbackName=callback_name,
2007 parameter=annotated_type + " errorData",
2008 argument=assigment_value))
2010 ad_hoc_type_output.append(callback_output)
2012 method_out_code += " RefPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRef(new " + agent_interface_name + "::" + callback_name + "(this, callId));\n"
2013 agent_call_param_list.append("callback")
2014 normal_response_cook_text += " if (!error.length()) \n"
2015 normal_response_cook_text += " return;\n"
2016 normal_response_cook_text += " callback->disable();\n"
2017 backend_agent_interface_list.append(", PassRefPtr<%s> callback" % callback_name)
2019 if "returns" in json_command:
2020 method_out_code += "\n"
2021 agent_call_params_declaration_list.append(" RefPtr<JSONObject> result = JSONObject::create();")
2022 send_response_call_params_list.append("result")
2023 response_cook_list = []
2024 for json_return in json_command["returns"]:
2026 json_return_name = json_return["name"]
2028 optional = bool(json_return.get("optional"))
2030 return_type_binding = Generator.resolve_param_type_and_generate_ad_hoc(json_return, json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::")
2032 raw_type = return_type_binding.reduce_to_raw_type()
2033 setter_type = raw_type.get_setter_name()
2034 initializer = raw_type.get_c_initializer()
2036 type_model = return_type_binding.get_type_model()
2038 type_model = type_model.get_optional()
2040 code = " %s out_%s;\n" % (type_model.get_command_return_pass_model().get_return_var_type(), json_return_name)
2041 param = "%sout_%s" % (type_model.get_command_return_pass_model().get_output_argument_prefix(), json_return_name)
2042 var_name = "out_%s" % json_return_name
2043 setter_argument = type_model.get_command_return_pass_model().get_output_to_raw_expression() % var_name
2044 if return_type_binding.get_setter_value_expression_pattern():
2045 setter_argument = return_type_binding.get_setter_value_expression_pattern() % setter_argument
2047 cook = " result->set%s(\"%s\", %s);\n" % (setter_type, json_return_name,
2050 set_condition_pattern = type_model.get_command_return_pass_model().get_set_return_condition()
2051 if set_condition_pattern:
2052 cook = (" if (%s)\n " % (set_condition_pattern % var_name)) + cook
2053 annotated_type = type_model.get_command_return_pass_model().get_output_parameter_type()
2055 param_name = var_name
2057 param_name = "opt_" + param_name
2059 backend_agent_interface_list.append(", %s %s" % (annotated_type, param_name))
2060 response_cook_list.append(cook)
2062 method_out_code += code
2063 agent_call_param_list.append(param)
2065 normal_response_cook_text += "".join(response_cook_list)
2067 if len(normal_response_cook_text) != 0:
2068 normal_response_cook_text = " if (!error.length()) {\n" + normal_response_cook_text + " }"
2070 # Redirect to another agent's implementation.
2071 agent_field = "m_" + agent_field_name
2072 if "redirect" in json_command:
2073 domain_fixes = DomainNameFixes.get_fixed_data(json_command.get("redirect"))
2074 agent_field = "m_" + domain_fixes.agent_field_name
2076 Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None,
2077 domainName=domain_name, methodName=json_command_name,
2078 agentField=agent_field,
2079 methodCode="".join([method_in_code, method_out_code]),
2080 agentCallParamsDeclaration="\n".join(agent_call_params_declaration_list),
2081 agentCallParams=", ".join(agent_call_param_list),
2082 requestMessageObject=request_message_param,
2083 responseCook=normal_response_cook_text,
2084 sendResponseCallParams=", ".join(send_response_call_params_list),
2085 commandNameIndex=cmd_enum_name))
2086 declaration_command_name = "%s.%s\\0" % (domain_name, json_command_name)
2087 Generator.backend_method_name_declaration_list.append(" \"%s\"" % declaration_command_name)
2088 Generator.backend_method_name_declaration_index_list.append(" %d," % Generator.backend_method_name_declaration_current_index)
2089 Generator.backend_method_name_declaration_current_index += len(declaration_command_name) - 1
2091 backend_agent_interface_list.append(") = 0;\n")
2093 class CallbackMethodStructTemplate:
2095 def append_prolog(line_list):
2099 def append_epilog(line_list):
2102 container_name = "jsonMessage"
2104 # Generates common code for event sending and callback response data sending.
2106 def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_writer, decl_parameter_list,
2107 method_struct_template,
2108 generator_method_list, method_template, template_params):
2109 method_line_list = []
2111 method_struct_template.append_prolog(method_line_list)
2112 for json_parameter in parameters:
2113 parameter_name = json_parameter["name"]
2115 param_type_binding = Generator.resolve_param_type_and_generate_ad_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "")
2117 raw_type = param_type_binding.reduce_to_raw_type()
2118 raw_type_binding = RawTypeBinding(raw_type)
2120 optional = bool(json_parameter.get("optional"))
2122 setter_type = raw_type.get_setter_name()
2124 type_model = param_type_binding.get_type_model()
2125 raw_type_model = raw_type_binding.get_type_model()
2127 type_model = type_model.get_optional()
2128 raw_type_model = raw_type_model.get_optional()
2130 annotated_type = type_model.get_input_param_type_text()
2131 mode_type_binding = param_type_binding
2133 decl_parameter_list.append("%s %s" % (annotated_type, parameter_name))
2135 setter_argument = raw_type_model.get_event_setter_expression_pattern() % parameter_name
2136 if mode_type_binding.get_setter_value_expression_pattern():
2137 setter_argument = mode_type_binding.get_setter_value_expression_pattern() % setter_argument
2139 setter_code = " %s->set%s(\"%s\", %s);\n" % (method_struct_template.container_name, setter_type, parameter_name, setter_argument)
2141 setter_code = (" if (%s)\n " % parameter_name) + setter_code
2142 method_line_list.append(setter_code)
2144 method_struct_template.append_epilog(method_line_list)
2146 generator_method_list.append(method_template.substitute(None,
2147 domainName=domain_name,
2148 parameters=", ".join(decl_parameter_list),
2149 code="".join(method_line_list), **template_params))
2152 def resolve_param_type_and_generate_ad_hoc(cls, json_param, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
2153 param_name = json_param["name"]
2154 return cls.resolve_type_and_generate_ad_hoc(json_param, param_name, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param)
2157 def resolve_type_and_generate_ad_hoc(typable_element, element_name, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
2158 ad_hoc_type_list = []
2160 class AdHocTypeContext:
2161 container_full_name_prefix = "<not yet defined>"
2162 container_relative_name_prefix = container_relative_name_prefix_param
2165 def get_type_name_fix():
2167 class_name = Capitalizer.lower_camel_case_to_upper(element_name)
2170 def output_comment(writer):
2171 writer.newline("// Named after parameter '%s' while generating command/event %s.\n" % (element_name, method_name))
2176 def add_type(binding):
2177 ad_hoc_type_list.append(binding)
2179 type_binding = resolve_param_type(typable_element, domain_name, AdHocTypeContext)
2181 class InterfaceForwardListener:
2183 def add_type_data(type_data):
2186 class InterfaceResolveContext:
2187 forward_listener = InterfaceForwardListener
2189 for type in ad_hoc_type_list:
2190 type.resolve_inner(InterfaceResolveContext)
2192 class InterfaceGenerateContext:
2193 validator_writer = "not supported in InterfaceGenerateContext"
2194 cpp_writer = validator_writer
2196 for type in ad_hoc_type_list:
2197 generator = type.get_code_generator()
2199 generator.generate_type_builder(ad_hoc_type_writer, InterfaceGenerateContext)
2204 def process_types(type_map):
2205 output = Generator.type_builder_fragments
2207 class GenerateContext:
2208 validator_writer = Writer(Generator.validator_impl_list, "")
2209 cpp_writer = Writer(Generator.type_builder_impl_list, "")
2211 def generate_all_domains_code(out, type_data_callback):
2212 writer = Writer(out, "")
2213 for domain_data in type_map.domains():
2214 domain_fixes = DomainNameFixes.get_fixed_data(domain_data.name())
2216 namespace_declared = []
2218 def namespace_lazy_generator():
2219 if not namespace_declared:
2220 writer.newline("namespace ")
2221 writer.append(domain_data.name())
2222 writer.append(" {\n")
2223 # What is a better way to change value from outer scope?
2224 namespace_declared.append(True)
2227 for type_data in domain_data.types():
2228 type_data_callback(type_data, namespace_lazy_generator)
2230 if namespace_declared:
2231 writer.append("} // ")
2232 writer.append(domain_data.name())
2233 writer.append("\n\n")
2235 def create_type_builder_caller(generate_pass_id):
2236 def call_type_builder(type_data, writer_getter):
2237 code_generator = type_data.get_binding().get_code_generator()
2238 if code_generator and generate_pass_id == code_generator.get_generate_pass_id():
2239 writer = writer_getter()
2241 code_generator.generate_type_builder(writer, GenerateContext)
2242 return call_type_builder
2244 generate_all_domains_code(output, create_type_builder_caller(TypeBuilderPass.MAIN))
2246 Generator.type_builder_forwards.append("// Forward declarations.\n")
2248 def generate_forward_callback(type_data, writer_getter):
2249 if type_data in global_forward_listener.type_data_set:
2250 binding = type_data.get_binding()
2251 binding.get_code_generator().generate_forward_declaration(writer_getter())
2252 generate_all_domains_code(Generator.type_builder_forwards, generate_forward_callback)
2254 Generator.type_builder_forwards.append("// End of forward declarations.\n\n")
2256 Generator.type_builder_forwards.append("// Typedefs.\n")
2258 generate_all_domains_code(Generator.type_builder_forwards, create_type_builder_caller(TypeBuilderPass.TYPEDEF))
2260 Generator.type_builder_forwards.append("// End of typedefs.\n\n")
2263 def flatten_list(input):
2266 def fill_recursive(l):
2268 if isinstance(item, list):
2269 fill_recursive(item)
2272 fill_recursive(input)
2276 # A writer that only updates file if it actually changed to better support incremental build.
2278 def __init__(self, file_name):
2279 self.file_name_ = file_name
2282 def write(self, text):
2283 self.output_ += text
2289 read_file = open(self.file_name_, "r")
2290 old_text = read_file.read()
2292 text_changed = old_text != self.output_
2294 # Ignore, just overwrite by default
2298 out_file = open(self.file_name_, "w")
2299 out_file.write(self.output_)
2303 def output_file(file_name):
2304 # For now, disable the incremental build optimisation in all cases.
2306 return SmartOutput(file_name)
2308 return open(file_name, "w")
2313 backend_h_file = output_file(output_dirname + "/InspectorBackendDispatcher.h")
2314 backend_cpp_file = output_file(output_dirname + "/InspectorBackendDispatcher.cpp")
2316 frontend_h_file = output_file(output_dirname + "/InspectorFrontend.h")
2317 frontend_cpp_file = output_file(output_dirname + "/InspectorFrontend.cpp")
2319 typebuilder_h_file = output_file(output_dirname + "/InspectorTypeBuilder.h")
2320 typebuilder_cpp_file = output_file(output_dirname + "/InspectorTypeBuilder.cpp")
2323 backend_h_file.write(Templates.backend_h.substitute(None,
2324 virtualSetters="\n".join(Generator.backend_virtual_setters_list),
2325 agentInterfaces="".join(flatten_list(Generator.backend_agent_interface_list)),
2326 methodNamesEnumContent="\n".join(Generator.method_name_enum_list)))
2328 backend_cpp_file.write(Templates.backend_cpp.substitute(None,
2329 constructorInit="\n".join(Generator.backend_constructor_init_list),
2330 setters="\n".join(Generator.backend_setters_list),
2331 fieldDeclarations="\n".join(Generator.backend_field_list),
2332 methodNameDeclarations="\n".join(Generator.backend_method_name_declaration_list),
2333 methodNameDeclarationsIndex="\n".join(Generator.backend_method_name_declaration_index_list),
2334 methods="\n".join(Generator.backend_method_implementation_list),
2335 methodDeclarations="\n".join(Generator.backend_method_declaration_list),
2336 messageHandlers="\n".join(Generator.method_handler_list)))
2338 frontend_h_file.write(Templates.frontend_h.substitute(None,
2339 fieldDeclarations="".join(Generator.frontend_class_field_lines),
2340 domainClassList="".join(Generator.frontend_domain_class_lines)))
2342 frontend_cpp_file.write(Templates.frontend_cpp.substitute(None,
2343 constructorInit="".join(Generator.frontend_constructor_init_list),
2344 methods="\n".join(Generator.frontend_method_list)))
2346 typebuilder_h_file.write(Templates.typebuilder_h.substitute(None,
2347 typeBuilders="".join(flatten_list(Generator.type_builder_fragments)),
2348 forwards="".join(Generator.type_builder_forwards),
2349 validatorIfdefName=VALIDATOR_IFDEF_NAME))
2351 typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None,
2352 enumConstantValues=EnumConstants.get_enum_constant_code(),
2353 implCode="".join(flatten_list(Generator.type_builder_impl_list)),
2354 validatorCode="".join(flatten_list(Generator.validator_impl_list)),
2355 validatorIfdefName=VALIDATOR_IFDEF_NAME))
2357 backend_h_file.close()
2358 backend_cpp_file.close()
2360 frontend_h_file.close()
2361 frontend_cpp_file.close()
2363 typebuilder_h_file.close()
2364 typebuilder_cpp_file.close()