1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/idl-parser/typelib.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,302 @@ 1.4 +#!/usr/bin/env python 1.5 +# typelib.py - Generate XPCOM typelib files from IDL. 1.6 +# 1.7 +# This Source Code Form is subject to the terms of the Mozilla Public 1.8 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.10 + 1.11 +"""Generate an XPIDL typelib for the IDL files specified on the command line""" 1.12 + 1.13 +import os 1.14 +import sys 1.15 +import xpidl, xpt 1.16 + 1.17 +# A map of xpidl.py types to xpt.py types 1.18 +TypeMap = { 1.19 + # nsresult is not strictly an xpidl.py type, but it's useful here 1.20 + 'nsresult': xpt.Type.Tags.uint32, 1.21 + # builtins 1.22 + 'boolean': xpt.Type.Tags.boolean, 1.23 + 'void': xpt.Type.Tags.void, 1.24 + 'int16_t': xpt.Type.Tags.int16, 1.25 + 'int32_t': xpt.Type.Tags.int32, 1.26 + 'int64_t': xpt.Type.Tags.int64, 1.27 + 'uint8_t': xpt.Type.Tags.uint8, 1.28 + 'uint16_t': xpt.Type.Tags.uint16, 1.29 + 'uint32_t': xpt.Type.Tags.uint32, 1.30 + 'uint64_t': xpt.Type.Tags.uint64, 1.31 + 'octet': xpt.Type.Tags.uint8, 1.32 + 'short': xpt.Type.Tags.int16, 1.33 + 'long': xpt.Type.Tags.int32, 1.34 + 'long long': xpt.Type.Tags.int64, 1.35 + 'unsigned short': xpt.Type.Tags.uint16, 1.36 + 'unsigned long': xpt.Type.Tags.uint32, 1.37 + 'unsigned long long': xpt.Type.Tags.uint64, 1.38 + 'float': xpt.Type.Tags.float, 1.39 + 'double': xpt.Type.Tags.double, 1.40 + 'char': xpt.Type.Tags.char, 1.41 + 'string': xpt.Type.Tags.char_ptr, 1.42 + 'wchar': xpt.Type.Tags.wchar_t, 1.43 + 'wstring': xpt.Type.Tags.wchar_t_ptr, 1.44 + # special types 1.45 + 'nsid': xpt.Type.Tags.nsIID, 1.46 + 'domstring': xpt.Type.Tags.DOMString, 1.47 + 'astring': xpt.Type.Tags.AString, 1.48 + 'utf8string': xpt.Type.Tags.UTF8String, 1.49 + 'cstring': xpt.Type.Tags.CString, 1.50 + 'jsval': xpt.Type.Tags.jsval 1.51 +} 1.52 + 1.53 +# XXXkhuey dipper types should go away (bug 677784) 1.54 +def isDipperType(type): 1.55 + return type == xpt.Type.Tags.DOMString or type == xpt.Type.Tags.AString or type == xpt.Type.Tags.CString or type == xpt.Type.Tags.UTF8String 1.56 + 1.57 +def build_interface(iface, ifaces): 1.58 + def get_type(type, calltype, iid_is=None, size_is=None): 1.59 + """ Return the appropriate xpt.Type object for this param """ 1.60 + 1.61 + while isinstance(type, xpidl.Typedef): 1.62 + type = type.realtype 1.63 + 1.64 + if isinstance(type, xpidl.Builtin): 1.65 + if type.name == 'string' and size_is != None: 1.66 + return xpt.StringWithSizeType(size_is, size_is) 1.67 + elif type.name == 'wstring' and size_is != None: 1.68 + return xpt.WideStringWithSizeType(size_is, size_is) 1.69 + else: 1.70 + tag = TypeMap[type.name] 1.71 + isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr) 1.72 + return xpt.SimpleType(tag, 1.73 + pointer=isPtr, 1.74 + reference=False) 1.75 + 1.76 + if isinstance(type, xpidl.Array): 1.77 + # NB: For an Array<T> we pass down the iid_is to get the type of T. 1.78 + # This allows Arrays of InterfaceIs types to work. 1.79 + return xpt.ArrayType(get_type(type.type, calltype, iid_is), size_is, 1.80 + #XXXkhuey length_is duplicates size_is (bug 677788), 1.81 + size_is) 1.82 + 1.83 + if isinstance(type, xpidl.Interface) or isinstance(type, xpidl.Forward): 1.84 + xptiface = None 1.85 + for i in ifaces: 1.86 + if i.name == type.name: 1.87 + xptiface = i 1.88 + 1.89 + if not xptiface: 1.90 + xptiface = xpt.Interface(name=type.name) 1.91 + ifaces.append(xptiface) 1.92 + 1.93 + return xpt.InterfaceType(xptiface) 1.94 + 1.95 + if isinstance(type, xpidl.Native): 1.96 + if type.specialtype: 1.97 + # XXXkhuey jsval is marked differently in the typelib and in the headers :-( 1.98 + isPtr = (type.isPtr(calltype) or type.isRef(calltype)) and not type.specialtype == 'jsval' 1.99 + isRef = type.isRef(calltype) and not type.specialtype == 'jsval' 1.100 + return xpt.SimpleType(TypeMap[type.specialtype], 1.101 + pointer=isPtr, 1.102 + reference=isRef) 1.103 + elif iid_is != None: 1.104 + return xpt.InterfaceIsType(iid_is) 1.105 + else: 1.106 + # void ptr 1.107 + return xpt.SimpleType(TypeMap['void'], 1.108 + pointer=True, 1.109 + reference=False) 1.110 + 1.111 + raise Exception("Unknown type!") 1.112 + 1.113 + def get_nsresult(): 1.114 + return xpt.SimpleType(TypeMap['nsresult']) 1.115 + 1.116 + def build_nsresult_param(): 1.117 + return xpt.Param(get_nsresult()) 1.118 + 1.119 + def get_result_type(m): 1.120 + if not m.notxpcom: 1.121 + return get_nsresult() 1.122 + 1.123 + return get_type(m.realtype, '') 1.124 + 1.125 + def build_result_param(m): 1.126 + return xpt.Param(get_result_type(m)) 1.127 + 1.128 + def build_retval_param(m): 1.129 + type = get_type(m.realtype, 'out') 1.130 + if isDipperType(type.tag): 1.131 + # NB: The retval bit needs to be set here, contrary to what the 1.132 + # xpt spec says. 1.133 + return xpt.Param(type, in_=True, retval=True, dipper=True) 1.134 + return xpt.Param(type, in_=False, out=True, retval=True) 1.135 + 1.136 + def build_attr_param(a, getter=False, setter=False): 1.137 + if not (getter or setter): 1.138 + raise Exception("Attribute param must be for a getter or a setter!") 1.139 + 1.140 + type = get_type(a.realtype, getter and 'out' or 'in') 1.141 + if setter: 1.142 + return xpt.Param(type) 1.143 + else: 1.144 + if isDipperType(type.tag): 1.145 + # NB: The retval bit needs to be set here, contrary to what the 1.146 + # xpt spec says. 1.147 + return xpt.Param(type, in_=True, retval=True, dipper=True) 1.148 + return xpt.Param(type, in_=False, out=True, retval=True) 1.149 + 1.150 + if iface.namemap is None: 1.151 + raise Exception("Interface was not resolved.") 1.152 + 1.153 + consts = [] 1.154 + methods = [] 1.155 + 1.156 + def build_const(c): 1.157 + consts.append(xpt.Constant(c.name, get_type(c.basetype, ''), c.getValue())) 1.158 + 1.159 + def build_method(m): 1.160 + params = [] 1.161 + 1.162 + def build_param(p): 1.163 + def findattr(p, attr): 1.164 + if hasattr(p, attr) and getattr(p, attr): 1.165 + for i, param in enumerate(m.params): 1.166 + if param.name == getattr(p, attr): 1.167 + return i 1.168 + return None 1.169 + 1.170 + iid_is = findattr(p, 'iid_is') 1.171 + size_is = findattr(p, 'size_is') 1.172 + 1.173 + in_ = p.paramtype.count("in") 1.174 + out = p.paramtype.count("out") 1.175 + dipper = False 1.176 + type = get_type(p.realtype, p.paramtype, iid_is=iid_is, size_is=size_is) 1.177 + if out and isDipperType(type.tag): 1.178 + out = False 1.179 + dipper = True 1.180 + 1.181 + return xpt.Param(type, in_, out, p.retval, p.shared, dipper, p.optional) 1.182 + 1.183 + for p in m.params: 1.184 + params.append(build_param(p)) 1.185 + 1.186 + if not m.notxpcom and m.realtype.name != 'void': 1.187 + params.append(build_retval_param(m)) 1.188 + 1.189 + methods.append(xpt.Method(m.name, build_result_param(m), params, 1.190 + getter=False, setter=False, notxpcom=m.notxpcom, 1.191 + constructor=False, hidden=m.noscript, 1.192 + optargc=m.optional_argc, 1.193 + implicit_jscontext=m.implicit_jscontext)) 1.194 + 1.195 + def build_attr(a): 1.196 + # Write the getter 1.197 + methods.append(xpt.Method(a.name, build_nsresult_param(), 1.198 + [build_attr_param(a, getter=True)], 1.199 + getter=True, setter=False, 1.200 + constructor=False, hidden=a.noscript, 1.201 + optargc=False, 1.202 + implicit_jscontext=a.implicit_jscontext)) 1.203 + 1.204 + # And maybe the setter 1.205 + if not a.readonly: 1.206 + methods.append(xpt.Method(a.name, build_nsresult_param(), 1.207 + [build_attr_param(a, setter=True)], 1.208 + getter=False, setter=True, 1.209 + constructor=False, hidden=a.noscript, 1.210 + optargc=False, 1.211 + implicit_jscontext=a.implicit_jscontext)) 1.212 + 1.213 + for member in iface.members: 1.214 + if isinstance(member, xpidl.ConstMember): 1.215 + build_const(member) 1.216 + elif isinstance(member, xpidl.Attribute): 1.217 + build_attr(member) 1.218 + elif isinstance(member, xpidl.Method): 1.219 + build_method(member) 1.220 + elif isinstance(member, xpidl.CDATA): 1.221 + pass 1.222 + else: 1.223 + raise Exception("Unexpected interface member: %s" % member) 1.224 + 1.225 + parent = None 1.226 + if iface.base: 1.227 + for i in ifaces: 1.228 + if i.name == iface.base: 1.229 + parent = i 1.230 + if not parent: 1.231 + parent = xpt.Interface(name=iface.base) 1.232 + ifaces.append(parent) 1.233 + 1.234 + return xpt.Interface(iface.name, iface.attributes.uuid, methods=methods, 1.235 + constants=consts, resolved=True, parent=parent, 1.236 + scriptable=iface.attributes.scriptable, 1.237 + function=iface.attributes.function, 1.238 + builtinclass=iface.attributes.builtinclass) 1.239 + 1.240 +def write_typelib(idl, fd, filename): 1.241 + """ Generate the typelib. """ 1.242 + 1.243 + # We only care about interfaces 1.244 + ifaces = [] 1.245 + for p in idl.productions: 1.246 + if p.kind == 'interface': 1.247 + ifaces.append(build_interface(p, ifaces)) 1.248 + 1.249 + typelib = xpt.Typelib(interfaces=ifaces) 1.250 + typelib.writefd(fd) 1.251 + 1.252 +if __name__ == '__main__': 1.253 + from optparse import OptionParser 1.254 + o = OptionParser() 1.255 + o.add_option('-I', action='append', dest='incdirs', default=['.'], 1.256 + help="Directory to search for imported files") 1.257 + o.add_option('--cachedir', dest='cachedir', default=None, 1.258 + help="Directory in which to cache lex/parse tables.") 1.259 + o.add_option('-o', dest='outfile', default=None, 1.260 + help="Output file") 1.261 + o.add_option('-d', dest='depfile', default=None, 1.262 + help="Generate a make dependency file") 1.263 + o.add_option('--regen', action='store_true', dest='regen', default=False, 1.264 + help="Regenerate IDL Parser cache") 1.265 + options, args = o.parse_args() 1.266 + file = args[0] if args else None 1.267 + 1.268 + if options.cachedir is not None: 1.269 + if not os.path.isdir(options.cachedir): 1.270 + os.mkdir(options.cachedir) 1.271 + sys.path.append(options.cachedir) 1.272 + 1.273 + if options.regen: 1.274 + if options.cachedir is None: 1.275 + print >>sys.stderr, "--regen requires --cachedir" 1.276 + sys.exit(1) 1.277 + 1.278 + p = xpidl.IDLParser(outputdir=options.cachedir, regen=True) 1.279 + sys.exit(0) 1.280 + 1.281 + if options.depfile is not None and options.outfile is None: 1.282 + print >>sys.stderr, "-d requires -o" 1.283 + sys.exit(1) 1.284 + 1.285 + if options.outfile is not None: 1.286 + outfd = open(options.outfile, 'wb') 1.287 + closeoutfd = True 1.288 + else: 1.289 + raise "typelib generation requires an output file" 1.290 + 1.291 + p = xpidl.IDLParser(outputdir=options.cachedir) 1.292 + idl = p.parse(open(file).read(), filename=file) 1.293 + idl.resolve(options.incdirs, p) 1.294 + write_typelib(idl, outfd, file) 1.295 + 1.296 + if closeoutfd: 1.297 + outfd.close() 1.298 + 1.299 + if options.depfile is not None: 1.300 + depfd = open(options.depfile, 'w') 1.301 + deps = [dep.replace('\\', '/') for dep in idl.deps] 1.302 + 1.303 + print >>depfd, "%s: %s" % (options.outfile, " ".join(deps)) 1.304 + for dep in deps: 1.305 + print >>depfd, "%s:" % dep