Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / scripts / generate_injected_script_externs.py
blob91e5a63bb225e9fe54da4287fd10100a625ef77c
1 #!/usr/bin/env python
3 # Copyright 2014 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 import re
9 interface_name_map = {
10 'InjectedScriptHost': 'InjectedScriptHostClass'
13 type_map = {
14 'any': '*',
15 'DOMString': 'string',
16 'short': 'number',
17 'unsigned short': 'number',
18 'long': 'number',
19 'unsigned long': 'number',
20 'boolean': 'boolean',
21 'object': 'Object',
22 'void': ''
25 idl_type_exprs = [
26 r'any',
27 r'DOMString',
28 r'short',
29 r'unsigned\s+short',
30 r'long',
31 r'unsigned\s+long',
32 r'boolean',
33 r'object',
34 r'void',
35 r'\w+' # Non IDL-specific object types.
38 # Groups:
39 # 1: type name
40 # 2: array (optional)
41 # 3: nullable (optional)
42 type_expr = r'\b(' + r'|'.join(idl_type_exprs) + r')\b(\[\])?(\?)?'
44 # Groups:
45 # 1: return type
46 # 2: array (optional)
47 # 3: nullable (optional)
48 # 4: method name
49 # 5: method arguments
50 method_expr = r'^\s*(?:\[.+\])?\s+' + type_expr + r'\s+(\w+)\s*\(([^)]*)\)\s*;\s*$'
51 method_regex = re.compile(method_expr)
53 # Groups:
54 # 1: type name
55 # 2: array (optional)
56 # 3: nullable (optional)
57 # 4: attribute name
58 attribute_expr = r'^\s*(?:\[.+\]\s+)?(?:\breadonly\s+)?\battribute\s+' + type_expr + r'\s+(\w+)\s*;'
59 attribute_regex = re.compile(attribute_expr)
61 # Groups:
62 # 1: optional (optional)
63 # 2: type name
64 # 3: array (optional)
65 # 4: nullable (optional)
66 # 5: arg name
67 arg_regex = re.compile(r'\s*(?:\[[^]]+\]\s*)?(\boptional\s+)?' + type_expr + r'\s+(\w+)')
69 interface_regex = r'\binterface\s+(\w+)'
71 other_externs = """
72 /** @type {!Window} */
73 var inspectedWindow;
74 /** @type {number} */
75 var injectedScriptId;
76 """
79 class Type:
80 def __init__(self, type_name, is_array, is_nullable):
81 self.type_name = re.sub(r'\s+', ' ', type_name)
82 self.is_array = is_array
83 self.is_nullable = is_nullable
85 def as_js_type(self):
86 if self.type_name == 'void':
87 return ''
88 result = ''
89 if self.is_nullable:
90 result = '?'
91 elif self._is_object_type():
92 result = '!'
93 if self.is_array:
94 result += 'Array.<%s>' % Type(self.type_name, False, False).as_js_type()
95 else:
96 result += type_map.get(self.type_name, self.type_name)
97 return result
99 def _is_object_type(self):
100 return self.is_array or self.type_name == 'object' or not type_map.get(self.type_name)
103 class Attribute:
104 def __init__(self, type, name):
105 self.type = type
106 self.name = name
109 class Argument:
110 def __init__(self, type, optional, name):
111 self.type = type
112 self.optional = optional
113 self.name = name
115 def as_js_param_type(self):
116 result = self.type.as_js_type()
117 if self.optional:
118 result += '='
119 return result
122 class Method:
123 def __init__(self, return_type, name, args):
124 self.return_type = return_type
125 self.name = name
126 self.args = args
128 def js_argument_names(self):
129 result = []
130 for arg in self.args:
131 result.append(arg.name)
132 return ', '.join(result)
135 class Interface:
136 def __init__(self, name, methods, attributes):
137 self.name = name
138 self.methods = methods
139 self.attributes = attributes
142 def parse_args(text):
143 arguments = []
144 for (optional, type_name, is_array, is_nullable, arg_name) in re.findall(arg_regex, text):
145 arguments.append(Argument(Type(type_name, is_array, is_nullable), optional != '', arg_name))
146 return arguments
149 def read_interface(idl):
150 methods = []
151 attributes = []
152 with open(idl, "r") as input_file:
153 for line in input_file.readlines():
154 match = re.search(method_regex, line)
155 if match:
156 return_type = Type(match.group(1), match.group(2) is not None, match.group(3) is not None)
157 name = match.group(4)
158 methods.append(Method(return_type, name, parse_args(match.group(5))))
159 continue
160 match = re.search(attribute_regex, line)
161 if match:
162 type = Type(match.group(1), match.group(2) is not None, match.group(3) is not None)
163 name = match.group(4)
164 attributes.append(Attribute(type, name))
165 continue
166 match = re.search(interface_regex, line)
167 if match:
168 interface_name = match.group(1)
169 return Interface(interface_name, methods, attributes)
172 def generate_injected_script_externs(input_idls, output):
173 for idl in input_idls:
174 ifc = read_interface(idl)
175 interface_name = interface_name_map.get(ifc.name, ifc.name)
176 output.write('/** @interface */\nfunction %s()\n{\n' % interface_name)
177 for attribute in ifc.attributes:
178 output.write(' /** @type {%s} */\n' % attribute.type.as_js_type())
179 output.write(' this.%s;\n' % attribute.name)
180 output.write('}\n')
181 for method in ifc.methods:
182 output.write('\n/**\n')
183 for arg in method.args:
184 output.write(' * @param {%s} %s\n' % (arg.as_js_param_type(), arg.name))
185 return_type = method.return_type.as_js_type()
186 if return_type:
187 output.write(' * @return {%s}\n' % return_type)
188 output.write(' */\n')
189 output.write('%s.prototype.%s = function(%s) {}\n' % (interface_name, method.name, method.js_argument_names()))
190 if interface_name != ifc.name:
191 output.write('\n/** @type {!%s} */\nvar %s;\n' % (interface_name, ifc.name))
192 output.write('\n')
193 output.write(other_externs)
196 def generate_injected_script_externs_to_file(input_idls, output_name):
197 with open(output_name, 'w') as output:
198 generate_injected_script_externs(input_idls, output)
201 def main(argv):
202 import os.path
203 program_name = os.path.basename(__file__)
204 if len(argv) < 3:
205 sys.stderr.write("Usage: %s IDL_1 ... IDL_N OUTPUT_FILE\n" % program_name)
206 exit(1)
207 input_idls = argv[1:-1]
208 generate_injected_script_externs_to_file(input_idls, argv[-1])
211 if __name__ == "__main__":
212 import sys
213 sys.exit(main(sys.argv))