Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / xpcom / idl-parser / typelib.py
blobf387b71ac64f1864d0d659e1918892f5730255d9
1 #!/usr/bin/env python
2 # typelib.py - Generate XPCOM typelib files from IDL.
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v. 2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 """Generate an XPIDL typelib for the IDL files specified on the command line"""
10 import os
11 import sys
12 import xpidl, xpt
14 # A map of xpidl.py types to xpt.py types
15 TypeMap = {
16 # nsresult is not strictly an xpidl.py type, but it's useful here
17 'nsresult': xpt.Type.Tags.uint32,
18 # builtins
19 'boolean': xpt.Type.Tags.boolean,
20 'void': xpt.Type.Tags.void,
21 'int16_t': xpt.Type.Tags.int16,
22 'int32_t': xpt.Type.Tags.int32,
23 'int64_t': xpt.Type.Tags.int64,
24 'uint8_t': xpt.Type.Tags.uint8,
25 'uint16_t': xpt.Type.Tags.uint16,
26 'uint32_t': xpt.Type.Tags.uint32,
27 'uint64_t': xpt.Type.Tags.uint64,
28 'octet': xpt.Type.Tags.uint8,
29 'short': xpt.Type.Tags.int16,
30 'long': xpt.Type.Tags.int32,
31 'long long': xpt.Type.Tags.int64,
32 'unsigned short': xpt.Type.Tags.uint16,
33 'unsigned long': xpt.Type.Tags.uint32,
34 'unsigned long long': xpt.Type.Tags.uint64,
35 'float': xpt.Type.Tags.float,
36 'double': xpt.Type.Tags.double,
37 'char': xpt.Type.Tags.char,
38 'string': xpt.Type.Tags.char_ptr,
39 'wchar': xpt.Type.Tags.wchar_t,
40 'wstring': xpt.Type.Tags.wchar_t_ptr,
41 # special types
42 'nsid': xpt.Type.Tags.nsIID,
43 'domstring': xpt.Type.Tags.DOMString,
44 'astring': xpt.Type.Tags.AString,
45 'utf8string': xpt.Type.Tags.UTF8String,
46 'cstring': xpt.Type.Tags.CString,
47 'jsval': xpt.Type.Tags.jsval
50 # XXXkhuey dipper types should go away (bug 677784)
51 def isDipperType(type):
52 return type == xpt.Type.Tags.DOMString or type == xpt.Type.Tags.AString or type == xpt.Type.Tags.CString or type == xpt.Type.Tags.UTF8String
54 def build_interface(iface, ifaces):
55 def get_type(type, calltype, iid_is=None, size_is=None):
56 """ Return the appropriate xpt.Type object for this param """
58 while isinstance(type, xpidl.Typedef):
59 type = type.realtype
61 if isinstance(type, xpidl.Builtin):
62 if type.name == 'string' and size_is != None:
63 return xpt.StringWithSizeType(size_is, size_is)
64 elif type.name == 'wstring' and size_is != None:
65 return xpt.WideStringWithSizeType(size_is, size_is)
66 else:
67 tag = TypeMap[type.name]
68 isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr)
69 return xpt.SimpleType(tag,
70 pointer=isPtr,
71 reference=False)
73 if isinstance(type, xpidl.Array):
74 # NB: For an Array<T> we pass down the iid_is to get the type of T.
75 # This allows Arrays of InterfaceIs types to work.
76 return xpt.ArrayType(get_type(type.type, calltype, iid_is), size_is,
77 #XXXkhuey length_is duplicates size_is (bug 677788),
78 size_is)
80 if isinstance(type, xpidl.Interface) or isinstance(type, xpidl.Forward):
81 xptiface = None
82 for i in ifaces:
83 if i.name == type.name:
84 xptiface = i
86 if not xptiface:
87 xptiface = xpt.Interface(name=type.name)
88 ifaces.append(xptiface)
90 return xpt.InterfaceType(xptiface)
92 if isinstance(type, xpidl.Native):
93 if type.specialtype:
94 # XXXkhuey jsval is marked differently in the typelib and in the headers :-(
95 isPtr = (type.isPtr(calltype) or type.isRef(calltype)) and not type.specialtype == 'jsval'
96 isRef = type.isRef(calltype) and not type.specialtype == 'jsval'
97 return xpt.SimpleType(TypeMap[type.specialtype],
98 pointer=isPtr,
99 reference=isRef)
100 elif iid_is != None:
101 return xpt.InterfaceIsType(iid_is)
102 else:
103 # void ptr
104 return xpt.SimpleType(TypeMap['void'],
105 pointer=True,
106 reference=False)
108 raise Exception("Unknown type!")
110 def get_nsresult():
111 return xpt.SimpleType(TypeMap['nsresult'])
113 def build_nsresult_param():
114 return xpt.Param(get_nsresult())
116 def get_result_type(m):
117 if not m.notxpcom:
118 return get_nsresult()
120 return get_type(m.realtype, '')
122 def build_result_param(m):
123 return xpt.Param(get_result_type(m))
125 def build_retval_param(m):
126 type = get_type(m.realtype, 'out')
127 if isDipperType(type.tag):
128 # NB: The retval bit needs to be set here, contrary to what the
129 # xpt spec says.
130 return xpt.Param(type, in_=True, retval=True, dipper=True)
131 return xpt.Param(type, in_=False, out=True, retval=True)
133 def build_attr_param(a, getter=False, setter=False):
134 if not (getter or setter):
135 raise Exception("Attribute param must be for a getter or a setter!")
137 type = get_type(a.realtype, getter and 'out' or 'in')
138 if setter:
139 return xpt.Param(type)
140 else:
141 if isDipperType(type.tag):
142 # NB: The retval bit needs to be set here, contrary to what the
143 # xpt spec says.
144 return xpt.Param(type, in_=True, retval=True, dipper=True)
145 return xpt.Param(type, in_=False, out=True, retval=True)
147 if iface.namemap is None:
148 raise Exception("Interface was not resolved.")
150 consts = []
151 methods = []
153 def build_const(c):
154 consts.append(xpt.Constant(c.name, get_type(c.basetype, ''), c.getValue()))
156 def build_method(m):
157 params = []
159 def build_param(p):
160 def findattr(p, attr):
161 if hasattr(p, attr) and getattr(p, attr):
162 for i, param in enumerate(m.params):
163 if param.name == getattr(p, attr):
164 return i
165 return None
167 iid_is = findattr(p, 'iid_is')
168 size_is = findattr(p, 'size_is')
170 in_ = p.paramtype.count("in")
171 out = p.paramtype.count("out")
172 dipper = False
173 type = get_type(p.realtype, p.paramtype, iid_is=iid_is, size_is=size_is)
174 if out and isDipperType(type.tag):
175 out = False
176 dipper = True
178 return xpt.Param(type, in_, out, p.retval, p.shared, dipper, p.optional)
180 for p in m.params:
181 params.append(build_param(p))
183 if not m.notxpcom and m.realtype.name != 'void':
184 params.append(build_retval_param(m))
186 methods.append(xpt.Method(m.name, build_result_param(m), params,
187 getter=False, setter=False, notxpcom=m.notxpcom,
188 constructor=False, hidden=m.noscript,
189 optargc=m.optional_argc,
190 implicit_jscontext=m.implicit_jscontext))
192 def build_attr(a):
193 # Write the getter
194 methods.append(xpt.Method(a.name, build_nsresult_param(),
195 [build_attr_param(a, getter=True)],
196 getter=True, setter=False,
197 constructor=False, hidden=a.noscript,
198 optargc=False,
199 implicit_jscontext=a.implicit_jscontext))
201 # And maybe the setter
202 if not a.readonly:
203 methods.append(xpt.Method(a.name, build_nsresult_param(),
204 [build_attr_param(a, setter=True)],
205 getter=False, setter=True,
206 constructor=False, hidden=a.noscript,
207 optargc=False,
208 implicit_jscontext=a.implicit_jscontext))
210 for member in iface.members:
211 if isinstance(member, xpidl.ConstMember):
212 build_const(member)
213 elif isinstance(member, xpidl.Attribute):
214 build_attr(member)
215 elif isinstance(member, xpidl.Method):
216 build_method(member)
217 elif isinstance(member, xpidl.CDATA):
218 pass
219 else:
220 raise Exception("Unexpected interface member: %s" % member)
222 parent = None
223 if iface.base:
224 for i in ifaces:
225 if i.name == iface.base:
226 parent = i
227 if not parent:
228 parent = xpt.Interface(name=iface.base)
229 ifaces.append(parent)
231 return xpt.Interface(iface.name, iface.attributes.uuid, methods=methods,
232 constants=consts, resolved=True, parent=parent,
233 scriptable=iface.attributes.scriptable,
234 function=iface.attributes.function,
235 builtinclass=iface.attributes.builtinclass)
237 def write_typelib(idl, fd, filename):
238 """ Generate the typelib. """
240 # We only care about interfaces
241 ifaces = []
242 for p in idl.productions:
243 if p.kind == 'interface':
244 ifaces.append(build_interface(p, ifaces))
246 typelib = xpt.Typelib(interfaces=ifaces)
247 typelib.writefd(fd)
249 if __name__ == '__main__':
250 from optparse import OptionParser
251 o = OptionParser()
252 o.add_option('-I', action='append', dest='incdirs', default=['.'],
253 help="Directory to search for imported files")
254 o.add_option('--cachedir', dest='cachedir', default=None,
255 help="Directory in which to cache lex/parse tables.")
256 o.add_option('-o', dest='outfile', default=None,
257 help="Output file")
258 o.add_option('-d', dest='depfile', default=None,
259 help="Generate a make dependency file")
260 o.add_option('--regen', action='store_true', dest='regen', default=False,
261 help="Regenerate IDL Parser cache")
262 options, args = o.parse_args()
263 file = args[0] if args else None
265 if options.cachedir is not None:
266 if not os.path.isdir(options.cachedir):
267 os.mkdir(options.cachedir)
268 sys.path.append(options.cachedir)
270 if options.regen:
271 if options.cachedir is None:
272 print >>sys.stderr, "--regen requires --cachedir"
273 sys.exit(1)
275 p = xpidl.IDLParser(outputdir=options.cachedir, regen=True)
276 sys.exit(0)
278 if options.depfile is not None and options.outfile is None:
279 print >>sys.stderr, "-d requires -o"
280 sys.exit(1)
282 if options.outfile is not None:
283 outfd = open(options.outfile, 'wb')
284 closeoutfd = True
285 else:
286 raise "typelib generation requires an output file"
288 p = xpidl.IDLParser(outputdir=options.cachedir)
289 idl = p.parse(open(file).read(), filename=file)
290 idl.resolve(options.incdirs, p)
291 write_typelib(idl, outfd, file)
293 if closeoutfd:
294 outfd.close()
296 if options.depfile is not None:
297 depfd = open(options.depfile, 'w')
298 deps = [dep.replace('\\', '/') for dep in idl.deps]
300 print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))
301 for dep in deps:
302 print >>depfd, "%s:" % dep