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"""
14
# A map of xpidl.py types to xpt.py types
16
# nsresult is not strictly an xpidl.py type, but it's useful here
17
'nsresult': xpt.Type.Tags.uint32,
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,
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):
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)
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,
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),
80
if isinstance(type, xpidl.Interface) or isinstance(type, xpidl.Forward):
83
if i.name == type.name:
87
xptiface = xpt.Interface(name=type.name)
88
ifaces.append(xptiface)
90
return xpt.InterfaceType(xptiface)
92
if isinstance(type, xpidl.Native):
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],
101
return xpt.InterfaceIsType(iid_is)
104
return xpt.SimpleType(TypeMap['void'],
108
raise Exception("Unknown type!")
111
return xpt.SimpleType(TypeMap['nsresult'])
113
def build_nsresult_param():
114
return xpt.Param(get_nsresult())
116
def get_result_type(m):
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
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')
139
return xpt.Param(type)
141
if isDipperType(type.tag):
142
# NB: The retval bit needs to be set here, contrary to what the
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.")
154
consts.append(xpt.Constant(c.name, get_type(c.basetype, ''), c.getValue()))
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):
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")
173
type = get_type(p.realtype, p.paramtype, iid_is=iid_is, size_is=size_is)
174
if out and isDipperType(type.tag):
178
return xpt.Param(type, in_, out, p.retval, p.shared, dipper, p.optional)
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))
194
methods.append(xpt.Method(a.name, build_nsresult_param(),
195
[build_attr_param(a, getter=True)],
196
getter=True, setter=False, notxpcom=a.notxpcom,
197
constructor=False, hidden=a.noscript,
199
implicit_jscontext=a.implicit_jscontext))
201
# And maybe the setter
203
methods.append(xpt.Method(a.name, build_nsresult_param(),
204
[build_attr_param(a, setter=True)],
205
getter=False, setter=True, notxpcom=a.notxpcom,
206
constructor=False, hidden=a.noscript,
208
implicit_jscontext=a.implicit_jscontext))
210
for member in iface.members:
211
if isinstance(member, xpidl.ConstMember):
213
elif isinstance(member, xpidl.Attribute):
215
elif isinstance(member, xpidl.Method):
217
elif isinstance(member, xpidl.CDATA):
220
raise Exception("Unexpected interface member: %s" % member)
225
if i.name == iface.base:
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
242
for p in idl.productions:
243
if p.kind == 'interface':
244
ifaces.append(build_interface(p, ifaces))
246
typelib = xpt.Typelib(interfaces=ifaces)
249
if __name__ == '__main__':
250
from optparse import 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,
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)
271
if options.cachedir is None:
272
print >>sys.stderr, "--regen requires --cachedir"
275
p = xpidl.IDLParser(outputdir=options.cachedir, regen=True)
278
if options.depfile is not None and options.outfile is None:
279
print >>sys.stderr, "-d requires -o"
282
if options.outfile is not None:
283
outfd = open(options.outfile, 'wb')
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)
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))