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,
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,
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
))
302 print >>depfd
, "%s:" % dep