Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | #!/usr/bin/env python |
michael@0 | 2 | # |
michael@0 | 3 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 6 | |
michael@0 | 7 | import sys, os, xpidl, makeutils |
michael@0 | 8 | |
michael@0 | 9 | def findIDL(includePath, interfaceFileName): |
michael@0 | 10 | for d in includePath: |
michael@0 | 11 | # Not os.path.join: we need a forward slash even on Windows because |
michael@0 | 12 | # this filename ends up in makedepend output. |
michael@0 | 13 | path = d + '/' + interfaceFileName |
michael@0 | 14 | if os.path.exists(path): |
michael@0 | 15 | return path |
michael@0 | 16 | raise BaseException("No IDL file found for interface %s " |
michael@0 | 17 | "in include path %r" |
michael@0 | 18 | % (interfaceFileName, includePath)) |
michael@0 | 19 | |
michael@0 | 20 | def loadEventIDL(parser, includePath, eventname): |
michael@0 | 21 | eventidl = ("nsIAccessible%s.idl" % eventname) |
michael@0 | 22 | idlFile = findIDL(includePath, eventidl) |
michael@0 | 23 | if not idlFile in makeutils.dependencies: |
michael@0 | 24 | makeutils.dependencies.append(idlFile) |
michael@0 | 25 | idl = p.parse(open(idlFile).read(), idlFile) |
michael@0 | 26 | idl.resolve(includePath, p) |
michael@0 | 27 | return idl |
michael@0 | 28 | |
michael@0 | 29 | class Configuration: |
michael@0 | 30 | def __init__(self, filename): |
michael@0 | 31 | config = {} |
michael@0 | 32 | execfile(filename, config) |
michael@0 | 33 | self.simple_events = config.get('simple_events', []) |
michael@0 | 34 | |
michael@0 | 35 | def readConfigFile(filename): |
michael@0 | 36 | return Configuration(filename) |
michael@0 | 37 | |
michael@0 | 38 | def firstCap(str): |
michael@0 | 39 | return str[0].upper() + str[1:] |
michael@0 | 40 | |
michael@0 | 41 | def writeAttributeParams(a): |
michael@0 | 42 | return ("%s a%s" % (a.realtype.nativeType('in'), firstCap(a.name))) |
michael@0 | 43 | |
michael@0 | 44 | def print_header_file(fd, conf): |
michael@0 | 45 | fd.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n") |
michael@0 | 46 | fd.write("#ifndef _mozilla_a11y_generated_AccEvents_h_\n" |
michael@0 | 47 | "#define _mozilla_a11y_generated_AccEvents_h_\n\n") |
michael@0 | 48 | fd.write("#include \"nscore.h\"\n") |
michael@0 | 49 | fd.write("#include \"nsCOMPtr.h\"\n") |
michael@0 | 50 | fd.write("#include \"nsCycleCollectionParticipant.h\"\n") |
michael@0 | 51 | fd.write("#include \"nsString.h\"\n") |
michael@0 | 52 | for e in conf.simple_events: |
michael@0 | 53 | fd.write("#include \"nsIAccessible%s.h\"\n" % e) |
michael@0 | 54 | for e in conf.simple_events: |
michael@0 | 55 | idl = loadEventIDL(p, options.incdirs, e) |
michael@0 | 56 | for iface in filter(lambda p: p.kind == "interface", idl.productions): |
michael@0 | 57 | classname = ("xpcAcc%s" % e) |
michael@0 | 58 | baseinterfaces = interfaces(iface) |
michael@0 | 59 | |
michael@0 | 60 | fd.write("\nclass %s MOZ_FINAL : public %s\n" % (classname, iface.name)) |
michael@0 | 61 | fd.write("{\n") |
michael@0 | 62 | fd.write("public:\n") |
michael@0 | 63 | |
michael@0 | 64 | attributes = allAttributes(iface) |
michael@0 | 65 | args = map(writeAttributeParams, attributes) |
michael@0 | 66 | fd.write(" %s(%s) :\n" % (classname, ", ".join(args))) |
michael@0 | 67 | |
michael@0 | 68 | initializers = [] |
michael@0 | 69 | for a in attributes: |
michael@0 | 70 | initializers.append("m%s(a%s)" % (firstCap(a.name), firstCap(a.name))) |
michael@0 | 71 | fd.write(" %s\n {}\n" % ", ".join(initializers)) |
michael@0 | 72 | fd.write(" ~%s() {}\n\n" % classname) |
michael@0 | 73 | fd.write(" NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n") |
michael@0 | 74 | fd.write(" NS_DECL_CYCLE_COLLECTION_CLASS(%s)\n" % (classname)) |
michael@0 | 75 | |
michael@0 | 76 | for iface in filter(lambda i: i.name != "nsISupports", baseinterfaces): |
michael@0 | 77 | fd.write(" NS_DECL_%s\n" % iface.name.upper()) |
michael@0 | 78 | |
michael@0 | 79 | fd.write("private:\n") |
michael@0 | 80 | for a in attributes: |
michael@0 | 81 | fd.write(" %s\n" % attributeVariableTypeAndName(a)) |
michael@0 | 82 | fd.write("};\n\n") |
michael@0 | 83 | |
michael@0 | 84 | fd.write("#endif\n") |
michael@0 | 85 | |
michael@0 | 86 | def interfaceAttributeTypes(idl): |
michael@0 | 87 | ifaces = filter(lambda p: p.kind == "interface", idl.productions) |
michael@0 | 88 | attributes = [] |
michael@0 | 89 | for i in ifaces: |
michael@0 | 90 | ifaceAttributes = allAttributes(i) |
michael@0 | 91 | attributes.extend(ifaceAttributes) |
michael@0 | 92 | ifaceAttrs = filter(lambda a: a.realtype.nativeType("in").endswith("*"), attributes) |
michael@0 | 93 | return map(lambda a: a.realtype.nativeType("in").strip(" *"), ifaceAttrs) |
michael@0 | 94 | |
michael@0 | 95 | def print_cpp(idl, fd, conf, eventname): |
michael@0 | 96 | for p in idl.productions: |
michael@0 | 97 | if p.kind == 'interface': |
michael@0 | 98 | write_cpp(eventname, p, fd) |
michael@0 | 99 | |
michael@0 | 100 | def print_cpp_file(fd, conf): |
michael@0 | 101 | fd.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n") |
michael@0 | 102 | fd.write('#include "xpcAccEvents.h"\n') |
michael@0 | 103 | |
michael@0 | 104 | includes = [] |
michael@0 | 105 | for e in conf.simple_events: |
michael@0 | 106 | if not e in includes: |
michael@0 | 107 | includes.append(("nsIAccessible%s" % e)) |
michael@0 | 108 | |
michael@0 | 109 | types = [] |
michael@0 | 110 | for e in conf.simple_events: |
michael@0 | 111 | idl = loadEventIDL(p, options.incdirs, e) |
michael@0 | 112 | types.extend(interfaceAttributeTypes(idl)) |
michael@0 | 113 | |
michael@0 | 114 | for c in types: |
michael@0 | 115 | fd.write("#include \"%s.h\"\n" % c) |
michael@0 | 116 | |
michael@0 | 117 | fd.write("\n") |
michael@0 | 118 | for e in conf.simple_events: |
michael@0 | 119 | print_cpp(loadEventIDL(p, options.incdirs, e), fd, conf, e) |
michael@0 | 120 | |
michael@0 | 121 | def attributeVariableTypeAndName(a): |
michael@0 | 122 | if a.realtype.nativeType('in').endswith('*'): |
michael@0 | 123 | l = ["nsCOMPtr<%s> m%s;" % (a.realtype.nativeType('in').strip('* '), |
michael@0 | 124 | firstCap(a.name))] |
michael@0 | 125 | elif a.realtype.nativeType('in').count("nsAString"): |
michael@0 | 126 | l = ["nsString m%s;" % firstCap(a.name)] |
michael@0 | 127 | elif a.realtype.nativeType('in').count("nsACString"): |
michael@0 | 128 | l = ["nsCString m%s;" % firstCap(a.name)] |
michael@0 | 129 | else: |
michael@0 | 130 | l = ["%sm%s;" % (a.realtype.nativeType('in'), |
michael@0 | 131 | firstCap(a.name))] |
michael@0 | 132 | return ", ".join(l) |
michael@0 | 133 | |
michael@0 | 134 | def writeAttributeGetter(fd, classname, a): |
michael@0 | 135 | fd.write("NS_IMETHODIMP\n") |
michael@0 | 136 | fd.write("%s::Get%s(" % (classname, firstCap(a.name))) |
michael@0 | 137 | if a.realtype.nativeType('in').endswith('*'): |
michael@0 | 138 | fd.write("%s** a%s" % (a.realtype.nativeType('in').strip('* '), firstCap(a.name))) |
michael@0 | 139 | elif a.realtype.nativeType('in').count("nsAString"): |
michael@0 | 140 | fd.write("nsAString& a%s" % firstCap(a.name)) |
michael@0 | 141 | elif a.realtype.nativeType('in').count("nsACString"): |
michael@0 | 142 | fd.write("nsACString& a%s" % firstCap(a.name)) |
michael@0 | 143 | else: |
michael@0 | 144 | fd.write("%s*a%s" % (a.realtype.nativeType('in'), firstCap(a.name))) |
michael@0 | 145 | fd.write(")\n"); |
michael@0 | 146 | fd.write("{\n"); |
michael@0 | 147 | if a.realtype.nativeType('in').endswith('*'): |
michael@0 | 148 | fd.write(" NS_IF_ADDREF(*a%s = m%s);\n" % (firstCap(a.name), firstCap(a.name))) |
michael@0 | 149 | elif a.realtype.nativeType('in').count("nsAString"): |
michael@0 | 150 | fd.write(" a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name))) |
michael@0 | 151 | elif a.realtype.nativeType('in').count("nsACString"): |
michael@0 | 152 | fd.write(" a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name))) |
michael@0 | 153 | else: |
michael@0 | 154 | fd.write(" *a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name))) |
michael@0 | 155 | fd.write(" return NS_OK;\n"); |
michael@0 | 156 | fd.write("}\n\n"); |
michael@0 | 157 | |
michael@0 | 158 | def interfaces(iface): |
michael@0 | 159 | interfaces = [] |
michael@0 | 160 | while iface.base: |
michael@0 | 161 | interfaces.append(iface) |
michael@0 | 162 | iface = iface.idl.getName(iface.base, iface.location) |
michael@0 | 163 | interfaces.append(iface) |
michael@0 | 164 | interfaces.reverse() |
michael@0 | 165 | return interfaces |
michael@0 | 166 | |
michael@0 | 167 | def allAttributes(iface): |
michael@0 | 168 | attributes = [] |
michael@0 | 169 | for i in interfaces(iface): |
michael@0 | 170 | attrs = filter(lambda m: isinstance(m, xpidl.Attribute), i.members) |
michael@0 | 171 | attributes.extend(attrs) |
michael@0 | 172 | |
michael@0 | 173 | return attributes |
michael@0 | 174 | |
michael@0 | 175 | def write_cpp(eventname, iface, fd): |
michael@0 | 176 | classname = "xpcAcc%s" % eventname |
michael@0 | 177 | attributes = allAttributes(iface) |
michael@0 | 178 | ccattributes = filter(lambda m: m.realtype.nativeType('in').endswith('*'), attributes) |
michael@0 | 179 | fd.write("NS_IMPL_CYCLE_COLLECTION(%s" % classname) |
michael@0 | 180 | for c in ccattributes: |
michael@0 | 181 | fd.write(", m%s" % firstCap(c.name)) |
michael@0 | 182 | fd.write(")\n\n"); |
michael@0 | 183 | |
michael@0 | 184 | fd.write("NS_IMPL_CYCLE_COLLECTING_ADDREF(%s)\n" % classname) |
michael@0 | 185 | fd.write("NS_IMPL_CYCLE_COLLECTING_RELEASE(%s)\n\n" % classname) |
michael@0 | 186 | |
michael@0 | 187 | fd.write("NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(%s)\n" % classname) |
michael@0 | 188 | for baseiface in interfaces(iface): |
michael@0 | 189 | fd.write(" NS_INTERFACE_MAP_ENTRY(%s)\n" % baseiface.name) |
michael@0 | 190 | fd.write("NS_INTERFACE_MAP_END\n\n") |
michael@0 | 191 | |
michael@0 | 192 | for a in attributes: |
michael@0 | 193 | writeAttributeGetter(fd, classname, a) |
michael@0 | 194 | |
michael@0 | 195 | |
michael@0 | 196 | def main(): |
michael@0 | 197 | from optparse import OptionParser |
michael@0 | 198 | o = OptionParser(usage="usage: %prog [options] configfile") |
michael@0 | 199 | o.add_option('-I', action='append', dest='incdirs', default=['.'], |
michael@0 | 200 | help="Directory to search for imported files") |
michael@0 | 201 | o.add_option('-o', "--stub-output", |
michael@0 | 202 | type='string', dest='stub_output', default=None, |
michael@0 | 203 | help="C++ source output file", metavar="FILE") |
michael@0 | 204 | o.add_option('--header-output', type='string', default=None, |
michael@0 | 205 | help="Quick stub header output file", metavar="FILE") |
michael@0 | 206 | o.add_option('--makedepend-output', type='string', default=None, |
michael@0 | 207 | help="gnumake dependencies output file", metavar="FILE") |
michael@0 | 208 | o.add_option('--cachedir', dest='cachedir', default=None, |
michael@0 | 209 | help="Directory in which to cache lex/parse tables.") |
michael@0 | 210 | global options |
michael@0 | 211 | (options, filenames) = o.parse_args() |
michael@0 | 212 | if len(filenames) != 1: |
michael@0 | 213 | o.error("Exactly one config filename is needed.") |
michael@0 | 214 | filename = filenames[0] |
michael@0 | 215 | |
michael@0 | 216 | if options.cachedir is not None: |
michael@0 | 217 | if not os.path.isdir(options.cachedir): |
michael@0 | 218 | os.mkdir(options.cachedir) |
michael@0 | 219 | sys.path.append(options.cachedir) |
michael@0 | 220 | |
michael@0 | 221 | # Instantiate the parser. |
michael@0 | 222 | global p |
michael@0 | 223 | p = xpidl.IDLParser(outputdir=options.cachedir) |
michael@0 | 224 | |
michael@0 | 225 | conf = readConfigFile(filename) |
michael@0 | 226 | |
michael@0 | 227 | if options.stub_output is not None: |
michael@0 | 228 | makeutils.targets.append(options.stub_output) |
michael@0 | 229 | outfd = open(options.stub_output, 'w') |
michael@0 | 230 | print_cpp_file(outfd, conf) |
michael@0 | 231 | outfd.close() |
michael@0 | 232 | if options.makedepend_output is not None: |
michael@0 | 233 | makeutils.writeMakeDependOutput(options.makedepend_output) |
michael@0 | 234 | if options.header_output is not None: |
michael@0 | 235 | outfd = open(options.header_output, 'w') |
michael@0 | 236 | print_header_file(outfd, conf) |
michael@0 | 237 | outfd.close() |
michael@0 | 238 | |
michael@0 | 239 | if __name__ == '__main__': |
michael@0 | 240 | main() |