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