blob: 25f31ef4740bf41ea7bfc75fe7b87a85615d8070 [file] [log] [blame]
Jack Jansen5ccd8261995-07-17 11:43:20 +00001"""
2gensuitemodule - Generate an AE suite module from an aete/aeut resource
3
Jack Jansen60762cb2000-08-17 22:11:45 +00004Based on aete.py.
5
6Reading and understanding this code is left as an exercise to the reader.
Jack Jansen5ccd8261995-07-17 11:43:20 +00007"""
8
9import MacOS
Jack Jansendf976ca2003-01-26 20:35:47 +000010import EasyDialogs
Jack Jansen5ccd8261995-07-17 11:43:20 +000011import os
12import string
13import sys
14import types
15import StringIO
Jack Jansenb2ecc2c2002-01-24 22:44:07 +000016import keyword
Jack Jansen40926062002-03-30 23:43:04 +000017import macresource
Jack Jansenfa1bf1c2003-03-06 23:04:38 +000018import aetools
19import distutils.sysconfig
20import OSATerminology
Jack Jansen5a6fdcd2001-08-25 12:15:04 +000021from Carbon.Res import *
Jack Jansenfa1bf1c2003-03-06 23:04:38 +000022import MacOS
Jack Jansen714caa02003-03-21 16:07:39 +000023import getopt
Jack Jansen5ccd8261995-07-17 11:43:20 +000024
Jack Jansenfa1bf1c2003-03-06 23:04:38 +000025_MAC_LIB_FOLDER=os.path.dirname(aetools.__file__)
26DEFAULT_STANDARD_PACKAGEFOLDER=os.path.join(_MAC_LIB_FOLDER, 'lib-scriptpackages')
27DEFAULT_USER_PACKAGEFOLDER=distutils.sysconfig.get_python_lib()
Jack Jansen40926062002-03-30 23:43:04 +000028
Jack Jansen714caa02003-03-21 16:07:39 +000029def usage():
30 sys.stderr.write("Usage: %s [opts] application-or-resource-file\n" % sys.argv[0])
31 sys.stderr.write("""Options:
32--output pkgdir Pathname of the output package (short: -o)
33--resource Parse resource file in stead of launching application (-r)
34--base package Use another base package in stead of default StdSuites (-b)
35--edit old=new Edit suite names, use empty new to skip a suite (-e)
Jack Jansen59cdbce2003-03-21 16:28:09 +000036--creator code Set creator code for package (-c)
Jack Jansen714caa02003-03-21 16:07:39 +000037""")
38 sys.exit(1)
39
Jack Jansen5ccd8261995-07-17 11:43:20 +000040def main():
Jack Jansen40926062002-03-30 23:43:04 +000041 if len(sys.argv) > 1:
Jack Jansen59cdbce2003-03-21 16:28:09 +000042 SHORTOPTS = "rb:o:e:c:"
43 LONGOPTS = ("resource", "base=", "output=", "edit=", "creator=")
Jack Jansen714caa02003-03-21 16:07:39 +000044 try:
45 opts, args = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS)
46 except getopt.GetoptError:
47 usage()
48
49 process_func = processfile
50 basepkgname = 'StdSuites'
51 output = None
52 edit_modnames = []
Jack Jansen59cdbce2003-03-21 16:28:09 +000053 creatorsignature = None
Jack Jansen714caa02003-03-21 16:07:39 +000054
55 for o, a in opts:
56 if o in ('-r', '--resource'):
57 process_func = processfile_fromresource
58 if o in ('-b', '--base'):
59 basepkgname = a
60 if o in ('-o', '--output'):
61 output = a
62 if o in ('-e', '--edit'):
63 split = a.split('=')
64 if len(split) != 2:
65 usage()
66 edit_modnames.append(split)
Jack Jansen59cdbce2003-03-21 16:28:09 +000067 if o in ('-c', '--creator'):
68 if len(a) != 4:
69 sys.stderr.write("creator must be 4-char string\n")
70 sys.exit(1)
71 creatorsignature = a
72
Jack Jansen714caa02003-03-21 16:07:39 +000073
74 if output and len(args) > 1:
75 sys.stderr.write("%s: cannot specify --output with multiple inputs\n" % sys.argv[0])
76 sys.exit(1)
77
78 for filename in args:
79 process_func(filename, output=output, basepkgname=basepkgname,
Jack Jansen59cdbce2003-03-21 16:28:09 +000080 edit_modnames=edit_modnames, creatorsignature=creatorsignature)
Jack Jansen40926062002-03-30 23:43:04 +000081 else:
Jack Jansenfa1bf1c2003-03-06 23:04:38 +000082 # The dialogOptionFlags below allows selection of .app bundles.
83 filename = EasyDialogs.AskFileForOpen(
84 message='Select scriptable application',
85 dialogOptionFlags=0x1056)
Jack Jansendf976ca2003-01-26 20:35:47 +000086 if not filename:
Jack Jansen40926062002-03-30 23:43:04 +000087 sys.exit(0)
Jack Jansenfa1bf1c2003-03-06 23:04:38 +000088 try:
89 processfile(filename)
90 except MacOS.Error, arg:
91 print "Error getting terminology:", arg
92 print "Retry, manually parsing resources"
93 processfile_fromresource(filename)
Jack Jansen5ccd8261995-07-17 11:43:20 +000094
Jack Jansen59cdbce2003-03-21 16:28:09 +000095def processfile_fromresource(fullname, output=None, basepkgname=None,
96 edit_modnames=None, creatorsignature=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +000097 """Process all resources in a single file"""
98 cur = CurResFile()
Jack Jansen40926062002-03-30 23:43:04 +000099 print "Processing", fullname
100 rf = macresource.open_pathname(fullname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000101 try:
102 UseResFile(rf)
103 resources = []
104 for i in range(Count1Resources('aete')):
105 res = Get1IndResource('aete', 1+i)
106 resources.append(res)
107 for i in range(Count1Resources('aeut')):
108 res = Get1IndResource('aeut', 1+i)
109 resources.append(res)
110 print "\nLISTING aete+aeut RESOURCES IN", `fullname`
Jack Jansen60762cb2000-08-17 22:11:45 +0000111 aetelist = []
Jack Jansen5ccd8261995-07-17 11:43:20 +0000112 for res in resources:
113 print "decoding", res.GetResInfo(), "..."
114 data = res.data
115 aete = decode(data)
Jack Jansen60762cb2000-08-17 22:11:45 +0000116 aetelist.append((aete, res.GetResInfo()))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000117 finally:
118 if rf <> cur:
119 CloseResFile(rf)
120 UseResFile(cur)
Jack Jansen60762cb2000-08-17 22:11:45 +0000121 # switch back (needed for dialogs in Python)
122 UseResFile(cur)
Jack Jansen714caa02003-03-21 16:07:39 +0000123 compileaetelist(aetelist, fullname, output=output,
Jack Jansen59cdbce2003-03-21 16:28:09 +0000124 basepkgname=basepkgname, edit_modnames=edit_modnames,
125 creatorsignature=creatorsignature)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000126
Jack Jansen59cdbce2003-03-21 16:28:09 +0000127def processfile(fullname, output=None, basepkgname=None,
128 edit_modnames=None, creatorsignature=None):
Jack Jansenfa1bf1c2003-03-06 23:04:38 +0000129 """Ask an application for its terminology and process that"""
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000130 try:
131 aedescobj, launched = OSATerminology.GetAppTerminology(fullname)
132 except MacOS.Error, arg:
Jack Jansen03b9c912003-03-28 22:04:22 +0000133 if arg[0] in (-1701, -192): # errAEDescNotFound, resNotFound
134 print "GetAppTerminology failed with errAEDescNotFound/resNotFound, trying manually"
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000135 aedata, sig = getappterminology(fullname)
136 if not creatorsignature:
137 creatorsignature = sig
138 else:
139 raise
140 else:
141 if launched:
142 print "Launched", fullname
143 raw = aetools.unpack(aedescobj)
144 if not raw:
145 print 'Unpack returned empty value:', raw
146 return
147 if not raw[0].data:
148 print 'Unpack returned value without data:', raw
149 return
150 aedata = raw[0]
Jack Jansenfa1bf1c2003-03-06 23:04:38 +0000151 aete = decode(aedata.data)
Jack Jansen59cdbce2003-03-21 16:28:09 +0000152 compileaete(aete, None, fullname, output=output, basepkgname=basepkgname,
Jack Jansen03b9c912003-03-28 22:04:22 +0000153 creatorsignature=creatorsignature, edit_modnames=edit_modnames)
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000154
155def getappterminology(fullname):
156 """Get application terminology by sending an AppleEvent"""
157 # First check that we actually can send AppleEvents
158 if not MacOS.WMAvailable():
159 raise RuntimeError, "Cannot send AppleEvents, no access to window manager"
160 # Next, a workaround for a bug in MacOS 10.2: sending events will hang unless
161 # you have created an event loop first.
162 import Carbon.Evt
163 Carbon.Evt.WaitNextEvent(0,0)
Jack Jansen03b9c912003-03-28 22:04:22 +0000164 if os.path.isdir(fullname):
165 # Now get the signature of the application, hoping it is a bundle
166 pkginfo = os.path.join(fullname, 'Contents', 'PkgInfo')
167 if not os.path.exists(pkginfo):
168 raise RuntimeError, "No PkgInfo file found"
169 tp_cr = open(pkginfo, 'rb').read()
170 cr = tp_cr[4:8]
171 else:
172 # Assume it is a file
173 cr, tp = MacOS.GetCreatorAndType(fullname)
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000174 # Let's talk to it and ask for its AETE
175 talker = aetools.TalkTo(cr)
Jack Jansen03b9c912003-03-28 22:04:22 +0000176 try:
177 talker._start()
178 except (MacOS.Error, aetools.Error), arg:
179 print 'Warning: start() failed, continuing anyway:', arg
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000180 reply = talker.send("ascr", "gdte")
Jack Jansen03b9c912003-03-28 22:04:22 +0000181 #reply2 = talker.send("ascr", "gdut")
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000182 # Now pick the bits out of the return that we need.
183 return reply[1]['----'], cr
184
Jack Jansenfa1bf1c2003-03-06 23:04:38 +0000185
Jack Jansen59cdbce2003-03-21 16:28:09 +0000186def compileaetelist(aetelist, fullname, output=None, basepkgname=None,
187 edit_modnames=None, creatorsignature=None):
Jack Jansen60762cb2000-08-17 22:11:45 +0000188 for aete, resinfo in aetelist:
Jack Jansen714caa02003-03-21 16:07:39 +0000189 compileaete(aete, resinfo, fullname, output=output,
Jack Jansen59cdbce2003-03-21 16:28:09 +0000190 basepkgname=basepkgname, edit_modnames=edit_modnames,
191 creatorsignature=creatorsignature)
Jack Jansen60762cb2000-08-17 22:11:45 +0000192
Jack Jansen5ccd8261995-07-17 11:43:20 +0000193def decode(data):
194 """Decode a resource into a python data structure"""
195 f = StringIO.StringIO(data)
196 aete = generic(getaete, f)
197 aete = simplify(aete)
198 processed = f.tell()
199 unprocessed = len(f.read())
200 total = f.tell()
201 if unprocessed:
202 sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
203 (processed, unprocessed, total))
204 return aete
205
206def simplify(item):
207 """Recursively replace singleton tuples by their constituent item"""
208 if type(item) is types.ListType:
209 return map(simplify, item)
210 elif type(item) == types.TupleType and len(item) == 2:
211 return simplify(item[1])
212 else:
213 return item
214
215
216# Here follows the aete resource decoder.
217# It is presented bottom-up instead of top-down because there are direct
218# references to the lower-level part-decoders from the high-level part-decoders.
219
220def getbyte(f, *args):
221 c = f.read(1)
222 if not c:
223 raise EOFError, 'in getbyte' + str(args)
224 return ord(c)
225
226def getword(f, *args):
227 getalign(f)
228 s = f.read(2)
229 if len(s) < 2:
230 raise EOFError, 'in getword' + str(args)
231 return (ord(s[0])<<8) | ord(s[1])
232
233def getlong(f, *args):
234 getalign(f)
235 s = f.read(4)
236 if len(s) < 4:
237 raise EOFError, 'in getlong' + str(args)
238 return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
239
240def getostype(f, *args):
241 getalign(f)
242 s = f.read(4)
243 if len(s) < 4:
244 raise EOFError, 'in getostype' + str(args)
245 return s
246
247def getpstr(f, *args):
248 c = f.read(1)
249 if len(c) < 1:
250 raise EOFError, 'in getpstr[1]' + str(args)
251 nbytes = ord(c)
252 if nbytes == 0: return ''
253 s = f.read(nbytes)
254 if len(s) < nbytes:
255 raise EOFError, 'in getpstr[2]' + str(args)
256 return s
257
258def getalign(f):
259 if f.tell() & 1:
260 c = f.read(1)
261 ##if c <> '\0':
262 ## print 'align:', `c`
263
264def getlist(f, description, getitem):
265 count = getword(f)
266 list = []
267 for i in range(count):
268 list.append(generic(getitem, f))
269 getalign(f)
270 return list
271
272def alt_generic(what, f, *args):
273 print "generic", `what`, args
274 res = vageneric(what, f, args)
275 print '->', `res`
276 return res
277
278def generic(what, f, *args):
279 if type(what) == types.FunctionType:
280 return apply(what, (f,) + args)
281 if type(what) == types.ListType:
282 record = []
283 for thing in what:
284 item = apply(generic, thing[:1] + (f,) + thing[1:])
285 record.append((thing[1], item))
286 return record
287 return "BAD GENERIC ARGS: %s" % `what`
288
289getdata = [
290 (getostype, "type"),
291 (getpstr, "description"),
292 (getword, "flags")
293 ]
294getargument = [
295 (getpstr, "name"),
296 (getostype, "keyword"),
297 (getdata, "what")
298 ]
299getevent = [
300 (getpstr, "name"),
301 (getpstr, "description"),
302 (getostype, "suite code"),
303 (getostype, "event code"),
304 (getdata, "returns"),
305 (getdata, "accepts"),
306 (getlist, "optional arguments", getargument)
307 ]
308getproperty = [
309 (getpstr, "name"),
310 (getostype, "code"),
311 (getdata, "what")
312 ]
313getelement = [
314 (getostype, "type"),
315 (getlist, "keyform", getostype)
316 ]
317getclass = [
318 (getpstr, "name"),
319 (getostype, "class code"),
320 (getpstr, "description"),
321 (getlist, "properties", getproperty),
322 (getlist, "elements", getelement)
323 ]
324getcomparison = [
325 (getpstr, "operator name"),
326 (getostype, "operator ID"),
327 (getpstr, "operator comment"),
328 ]
329getenumerator = [
330 (getpstr, "enumerator name"),
331 (getostype, "enumerator ID"),
332 (getpstr, "enumerator comment")
333 ]
334getenumeration = [
335 (getostype, "enumeration ID"),
336 (getlist, "enumerator", getenumerator)
337 ]
338getsuite = [
339 (getpstr, "suite name"),
340 (getpstr, "suite description"),
341 (getostype, "suite ID"),
342 (getword, "suite level"),
343 (getword, "suite version"),
344 (getlist, "events", getevent),
345 (getlist, "classes", getclass),
346 (getlist, "comparisons", getcomparison),
347 (getlist, "enumerations", getenumeration)
348 ]
349getaete = [
350 (getword, "major/minor version in BCD"),
351 (getword, "language code"),
352 (getword, "script code"),
353 (getlist, "suites", getsuite)
354 ]
355
Jack Jansen59cdbce2003-03-21 16:28:09 +0000356def compileaete(aete, resinfo, fname, output=None, basepkgname=None,
357 edit_modnames=None, creatorsignature=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000358 """Generate code for a full aete resource. fname passed for doc purposes"""
359 [version, language, script, suites] = aete
360 major, minor = divmod(version, 256)
Jack Jansen59cdbce2003-03-21 16:28:09 +0000361 if not creatorsignature:
362 creatorsignature, dummy = MacOS.GetCreatorAndType(fname)
Jack Jansen40926062002-03-30 23:43:04 +0000363 packagename = identify(os.path.splitext(os.path.basename(fname))[0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000364 if language:
365 packagename = packagename+'_lang%d'%language
366 if script:
367 packagename = packagename+'_script%d'%script
368 if len(packagename) > 27:
369 packagename = packagename[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000370 if output:
371 # XXXX Put this in site-packages if it isn't a full pathname?
372 if not os.path.exists(output):
373 os.mkdir(output)
374 pathname = output
375 else:
376 pathname = EasyDialogs.AskFolder(message='Create and select package folder for %s'%packagename,
377 defaultLocation=DEFAULT_USER_PACKAGEFOLDER)
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000378 output = pathname
Jack Jansendf976ca2003-01-26 20:35:47 +0000379 if not pathname:
Jack Jansen60762cb2000-08-17 22:11:45 +0000380 return
Jack Jansen60762cb2000-08-17 22:11:45 +0000381 packagename = os.path.split(os.path.normpath(pathname))[1]
Jack Jansen714caa02003-03-21 16:07:39 +0000382 if not basepkgname:
383 basepkgname = EasyDialogs.AskFolder(message='Package folder for base suite (usually StdSuites)',
384 defaultLocation=DEFAULT_STANDARD_PACKAGEFOLDER)
Jack Jansendf976ca2003-01-26 20:35:47 +0000385 if basepkgname:
386 dirname, basepkgname = os.path.split(os.path.normpath(basepkgname))
Jack Jansen714caa02003-03-21 16:07:39 +0000387 if dirname and not dirname in sys.path:
Jack Jansen60762cb2000-08-17 22:11:45 +0000388 sys.path.insert(0, dirname)
389 basepackage = __import__(basepkgname)
390 else:
391 basepackage = None
Jack Jansen60762cb2000-08-17 22:11:45 +0000392 suitelist = []
Jack Jansen12b2b762000-08-20 19:30:56 +0000393 allprecompinfo = []
394 allsuites = []
Jack Jansen5ccd8261995-07-17 11:43:20 +0000395 for suite in suites:
Jack Jansen714caa02003-03-21 16:07:39 +0000396 code, suite, pathname, modname, precompinfo = precompilesuite(suite, basepackage,
397 output=output, edit_modnames=edit_modnames)
Jack Jansen12b2b762000-08-20 19:30:56 +0000398 if not code:
399 continue
400 allprecompinfo = allprecompinfo + precompinfo
Jack Jansendf976ca2003-01-26 20:35:47 +0000401 suiteinfo = suite, pathname, modname
Jack Jansen12b2b762000-08-20 19:30:56 +0000402 suitelist.append((code, modname))
403 allsuites.append(suiteinfo)
404 for suiteinfo in allsuites:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000405 compilesuite(suiteinfo, major, minor, language, script, fname, basepackage,
406 allprecompinfo, interact=(edit_modnames is None))
Jack Jansen714caa02003-03-21 16:07:39 +0000407 initfilename = os.path.join(output, '__init__.py')
Jack Jansendf976ca2003-01-26 20:35:47 +0000408 fp = open(initfilename, 'w')
409 MacOS.SetCreatorAndType(initfilename, 'Pyth', 'TEXT')
Jack Jansen60762cb2000-08-17 22:11:45 +0000410 fp.write('"""\n')
411 fp.write("Package generated from %s\n"%fname)
Jack Jansen8b777672002-08-07 14:49:00 +0000412 if resinfo:
413 fp.write("Resource %s resid %d %s\n"%(ascii(resinfo[1]), resinfo[0], ascii(resinfo[2])))
Jack Jansen60762cb2000-08-17 22:11:45 +0000414 fp.write('"""\n')
415 fp.write('import aetools\n')
Jack Jansen6aa92c52000-08-20 21:59:03 +0000416 fp.write('Error = aetools.Error\n')
Jack Jansen03b9c912003-03-28 22:04:22 +0000417 suitelist.sort()
Jack Jansen60762cb2000-08-17 22:11:45 +0000418 for code, modname in suitelist:
419 fp.write("import %s\n" % modname)
420 fp.write("\n\n_code_to_module = {\n")
421 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000422 fp.write("\t'%s' : %s,\n"%(ascii(code), modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000423 fp.write("}\n\n")
424 fp.write("\n\n_code_to_fullname = {\n")
425 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000426 fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(ascii(code), packagename, modname, modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000427 fp.write("}\n\n")
428 for code, modname in suitelist:
429 fp.write("from %s import *\n"%modname)
Jack Jansen8b777672002-08-07 14:49:00 +0000430
431 # Generate property dicts and element dicts for all types declared in this module
Jack Jansen7e0bc112003-03-21 12:04:19 +0000432 fp.write("\ndef getbaseclasses(v):\n")
Jack Jansen7cb016d2003-03-23 22:05:53 +0000433 fp.write("\tif not getattr(v, '_propdict', None):\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000434 fp.write("\t\tv._propdict = {}\n")
435 fp.write("\t\tv._elemdict = {}\n")
Jack Jansen7e0bc112003-03-21 12:04:19 +0000436 fp.write("\t\tfor superclassname in getattr(v, '_superclassnames', []):\n")
437 fp.write("\t\t\tsuperclass = eval(superclassname)\n")
438 fp.write("\t\t\tgetbaseclasses(superclass)\n")
439 fp.write("\t\t\tv._propdict.update(getattr(superclass, '_propdict', {}))\n")
440 fp.write("\t\t\tv._elemdict.update(getattr(superclass, '_elemdict', {}))\n")
Jack Jansen7cb016d2003-03-23 22:05:53 +0000441 fp.write("\t\tv._propdict.update(getattr(v, '_privpropdict', {}))\n")
442 fp.write("\t\tv._elemdict.update(getattr(v, '_privelemdict', {}))\n")
Jack Jansen21f67582002-08-07 15:44:53 +0000443 fp.write("\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000444 fp.write("import StdSuites\n")
Jack Jansen03b9c912003-03-28 22:04:22 +0000445 allprecompinfo.sort()
Jack Jansen8b777672002-08-07 14:49:00 +0000446 if allprecompinfo:
447 fp.write("\n#\n# Set property and element dictionaries now that all classes have been defined\n#\n")
448 for codenamemapper in allprecompinfo:
449 for k, v in codenamemapper.getall('class'):
450 fp.write("getbaseclasses(%s)\n" % v)
451
452 # Generate a code-to-name mapper for all of the types (classes) declared in this module
453 if allprecompinfo:
454 fp.write("\n#\n# Indices of types declared in this module\n#\n")
455 fp.write("_classdeclarations = {\n")
456 for codenamemapper in allprecompinfo:
457 for k, v in codenamemapper.getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000458 fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen8b777672002-08-07 14:49:00 +0000459 fp.write("}\n")
460
Jack Jansen60762cb2000-08-17 22:11:45 +0000461 if suitelist:
462 fp.write("\n\nclass %s(%s_Events"%(packagename, suitelist[0][1]))
463 for code, modname in suitelist[1:]:
Jack Jansen12b2b762000-08-20 19:30:56 +0000464 fp.write(",\n\t\t%s_Events"%modname)
465 fp.write(",\n\t\taetools.TalkTo):\n")
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000466 fp.write("\t_signature = %s\n\n"%`creatorsignature`)
Jack Jansen8b777672002-08-07 14:49:00 +0000467 fp.write("\t_moduleName = '%s'\n\n"%packagename)
Jack Jansen60762cb2000-08-17 22:11:45 +0000468 fp.close()
Jack Jansen12b2b762000-08-20 19:30:56 +0000469
Jack Jansen714caa02003-03-21 16:07:39 +0000470def precompilesuite(suite, basepackage=None, edit_modnames=None, output=None):
Jack Jansen12b2b762000-08-20 19:30:56 +0000471 """Parse a single suite without generating the output. This step is needed
472 so we can resolve recursive references by suites to enums/comps/etc declared
473 in other suites"""
Jack Jansen5ccd8261995-07-17 11:43:20 +0000474 [name, desc, code, level, version, events, classes, comps, enums] = suite
475
476 modname = identify(name)
Jack Jansen60762cb2000-08-17 22:11:45 +0000477 if len(modname) > 28:
478 modname = modname[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000479 if edit_modnames is None:
480 pathname = EasyDialogs.AskFileForSave(message='Python output file',
481 savedFileName=modname+'.py')
482 else:
483 for old, new in edit_modnames:
484 if old == modname:
485 modname = new
486 if modname:
487 pathname = os.path.join(output, modname + '.py')
488 else:
489 pathname = None
Jack Jansendf976ca2003-01-26 20:35:47 +0000490 if not pathname:
Jack Jansen12b2b762000-08-20 19:30:56 +0000491 return None, None, None, None, None
492
Jack Jansen60762cb2000-08-17 22:11:45 +0000493 modname = os.path.splitext(os.path.split(pathname)[1])[0]
Jack Jansen12b2b762000-08-20 19:30:56 +0000494
495 if basepackage and basepackage._code_to_module.has_key(code):
496 # We are an extension of a baseclass (usually an application extending
497 # Standard_Suite or so). Import everything from our base module
498 basemodule = basepackage._code_to_module[code]
499 else:
500 # We are not an extension.
501 basemodule = None
502
503 enumsneeded = {}
504 for event in events:
505 findenumsinevent(event, enumsneeded)
506
Jack Jansen59cdbce2003-03-21 16:28:09 +0000507 objc = ObjectCompiler(None, basemodule, interact=(edit_modnames is None))
Jack Jansen12b2b762000-08-20 19:30:56 +0000508 for cls in classes:
509 objc.compileclass(cls)
510 for cls in classes:
511 objc.fillclasspropsandelems(cls)
512 for comp in comps:
513 objc.compilecomparison(comp)
514 for enum in enums:
515 objc.compileenumeration(enum)
516
517 for enum in enumsneeded.keys():
518 objc.checkforenum(enum)
519
520 objc.dumpindex()
521
522 precompinfo = objc.getprecompinfo(modname)
523
Jack Jansendf976ca2003-01-26 20:35:47 +0000524 return code, suite, pathname, modname, precompinfo
Jack Jansen12b2b762000-08-20 19:30:56 +0000525
Jack Jansen59cdbce2003-03-21 16:28:09 +0000526def compilesuite((suite, pathname, modname), major, minor, language, script,
527 fname, basepackage, precompinfo, interact=1):
Jack Jansen12b2b762000-08-20 19:30:56 +0000528 """Generate code for a single suite"""
529 [name, desc, code, level, version, events, classes, comps, enums] = suite
Jack Jansen03b9c912003-03-28 22:04:22 +0000530 # Sort various lists, so re-generated source is easier compared
531 events.sort()
532 classes.sort()
533 comps.sort()
534 enums.sort()
Jack Jansen12b2b762000-08-20 19:30:56 +0000535
Jack Jansendf976ca2003-01-26 20:35:47 +0000536 fp = open(pathname, 'w')
537 MacOS.SetCreatorAndType(pathname, 'Pyth', 'TEXT')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000538
Jack Jansen8b777672002-08-07 14:49:00 +0000539 fp.write('"""Suite %s: %s\n' % (ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000540 fp.write("Level %d, version %d\n\n" % (level, version))
Jack Jansen8b777672002-08-07 14:49:00 +0000541 fp.write("Generated from %s\n"%ascii(fname))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000542 fp.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
543 (major, minor, language, script))
544 fp.write('"""\n\n')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000545
546 fp.write('import aetools\n')
547 fp.write('import MacOS\n\n')
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000548 fp.write("_code = %s\n\n"% `code`)
Jack Jansen60762cb2000-08-17 22:11:45 +0000549 if basepackage and basepackage._code_to_module.has_key(code):
550 # We are an extension of a baseclass (usually an application extending
551 # Standard_Suite or so). Import everything from our base module
Jack Jansen12b2b762000-08-20 19:30:56 +0000552 fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000553 basemodule = basepackage._code_to_module[code]
Jack Jansen7ebcbf52002-01-22 23:24:03 +0000554 elif basepackage and basepackage._code_to_module.has_key(code.lower()):
555 # This is needed by CodeWarrior and some others.
556 fp.write('from %s import *\n'%basepackage._code_to_fullname[code.lower()][0])
557 basemodule = basepackage._code_to_module[code.lower()]
Jack Jansen60762cb2000-08-17 22:11:45 +0000558 else:
559 # We are not an extension.
560 basemodule = None
561 compileclassheader(fp, modname, basemodule)
Jack Jansen66544221997-08-08 14:49:02 +0000562
563 enumsneeded = {}
Jack Jansen5ccd8261995-07-17 11:43:20 +0000564 if events:
565 for event in events:
Jack Jansen66544221997-08-08 14:49:02 +0000566 compileevent(fp, event, enumsneeded)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000567 else:
568 fp.write("\tpass\n\n")
Jack Jansen66544221997-08-08 14:49:02 +0000569
Jack Jansen59cdbce2003-03-21 16:28:09 +0000570 objc = ObjectCompiler(fp, basemodule, precompinfo, interact=interact)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000571 for cls in classes:
Jack Jansen66544221997-08-08 14:49:02 +0000572 objc.compileclass(cls)
573 for cls in classes:
574 objc.fillclasspropsandelems(cls)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000575 for comp in comps:
Jack Jansen66544221997-08-08 14:49:02 +0000576 objc.compilecomparison(comp)
577 for enum in enums:
578 objc.compileenumeration(enum)
579
580 for enum in enumsneeded.keys():
581 objc.checkforenum(enum)
582
583 objc.dumpindex()
Jack Jansen60762cb2000-08-17 22:11:45 +0000584
585 return code, modname
Jack Jansen5ccd8261995-07-17 11:43:20 +0000586
Jack Jansen60762cb2000-08-17 22:11:45 +0000587def compileclassheader(fp, name, module=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000588 """Generate class boilerplate"""
Jack Jansen60762cb2000-08-17 22:11:45 +0000589 classname = '%s_Events'%name
Jack Jansen12b2b762000-08-20 19:30:56 +0000590 if module:
591 modshortname = string.split(module.__name__, '.')[-1]
592 baseclassname = '%s_Events'%modshortname
593 fp.write("class %s(%s):\n\n"%(classname, baseclassname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000594 else:
595 fp.write("class %s:\n\n"%classname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000596
Jack Jansen66544221997-08-08 14:49:02 +0000597def compileevent(fp, event, enumsneeded):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000598 """Generate code for a single event"""
599 [name, desc, code, subcode, returns, accepts, arguments] = event
600 funcname = identify(name)
601 #
602 # generate name->keyword map
603 #
604 if arguments:
605 fp.write("\t_argmap_%s = {\n"%funcname)
606 for a in arguments:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000607 fp.write("\t\t%s : %s,\n"%(`identify(a[0])`, `a[1]`))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000608 fp.write("\t}\n\n")
609
610 #
611 # Generate function header
612 #
613 has_arg = (not is_null(accepts))
614 opt_arg = (has_arg and is_optional(accepts))
615
Jack Jansen84264771995-10-03 14:35:58 +0000616 fp.write("\tdef %s(self, "%funcname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000617 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000618 if not opt_arg:
619 fp.write("_object, ") # Include direct object, if it has one
620 else:
621 fp.write("_object=None, ") # Also include if it is optional
Jack Jansen5ccd8261995-07-17 11:43:20 +0000622 else:
Jack Jansen84264771995-10-03 14:35:58 +0000623 fp.write("_no_object=None, ") # For argument checking
624 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
Jack Jansen5ccd8261995-07-17 11:43:20 +0000625 #
626 # Generate doc string (important, since it may be the only
627 # available documentation, due to our name-remaping)
628 #
Jack Jansen21f67582002-08-07 15:44:53 +0000629 fp.write('\t\t"""%s: %s\n'%(ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000630 if has_arg:
631 fp.write("\t\tRequired argument: %s\n"%getdatadoc(accepts))
632 elif opt_arg:
633 fp.write("\t\tOptional argument: %s\n"%getdatadoc(accepts))
634 for arg in arguments:
635 fp.write("\t\tKeyword argument %s: %s\n"%(identify(arg[0]),
636 getdatadoc(arg[2])))
637 fp.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
638 if not is_null(returns):
639 fp.write("\t\tReturns: %s\n"%getdatadoc(returns))
640 fp.write('\t\t"""\n')
641 #
642 # Fiddle the args so everything ends up in 'arguments' dictionary
643 #
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000644 fp.write("\t\t_code = %s\n"% `code`)
645 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
Jack Jansen73215141995-10-09 23:09:23 +0000646 #
647 # Do keyword name substitution
648 #
649 if arguments:
650 fp.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname)
651 else:
652 fp.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
653 #
654 # Stuff required arg (if there is one) into arguments
655 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000656 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000657 fp.write("\t\t_arguments['----'] = _object\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000658 elif opt_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000659 fp.write("\t\tif _object:\n")
660 fp.write("\t\t\t_arguments['----'] = _object\n")
661 else:
662 fp.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000663 fp.write("\n")
664 #
Jack Jansen73215141995-10-09 23:09:23 +0000665 # Do enum-name substitution
Jack Jansen5ccd8261995-07-17 11:43:20 +0000666 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000667 for a in arguments:
668 if is_enum(a[2]):
669 kname = a[1]
670 ename = a[2][0]
Jack Jansena2408e91996-04-16 14:36:46 +0000671 if ename <> '****':
672 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000673 (`kname`, identify(ename)))
Jack Jansen66544221997-08-08 14:49:02 +0000674 enumsneeded[ename] = 1
Jack Jansen5ccd8261995-07-17 11:43:20 +0000675 fp.write("\n")
676 #
677 # Do the transaction
678 #
Jack Jansen84264771995-10-03 14:35:58 +0000679 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
680 fp.write("\t\t\t\t_arguments, _attributes)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000681 #
682 # Error handling
683 #
Jack Jansen18983532002-04-23 21:03:21 +0000684 fp.write("\t\tif _arguments.get('errn', 0):\n")
Jack Jansen977fbf21996-09-20 15:29:59 +0000685 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000686 fp.write("\t\t# XXXX Optionally decode result\n")
687 #
688 # Decode result
689 #
Jack Jansen84264771995-10-03 14:35:58 +0000690 fp.write("\t\tif _arguments.has_key('----'):\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000691 if is_enum(returns):
692 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
Jack Jansen84264771995-10-03 14:35:58 +0000693 fp.write("\t\t\treturn _arguments['----']\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000694 fp.write("\n")
695
696# print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
697# print "# returns", compiledata(returns)
698# print "# accepts", compiledata(accepts)
699# for arg in arguments:
700# compileargument(arg)
701
702def compileargument(arg):
703 [name, keyword, what] = arg
704 print "# %s (%s)" % (name, `keyword`), compiledata(what)
705
Jack Jansen12b2b762000-08-20 19:30:56 +0000706def findenumsinevent(event, enumsneeded):
707 """Find all enums for a single event"""
708 [name, desc, code, subcode, returns, accepts, arguments] = event
709 for a in arguments:
710 if is_enum(a[2]):
711 ename = a[2][0]
712 if ename <> '****':
713 enumsneeded[ename] = 1
714
715#
716# This class stores the code<->name translations for a single module. It is used
717# to keep the information while we're compiling the module, but we also keep these objects
718# around so if one suite refers to, say, an enum in another suite we know where to
719# find it. Finally, if we really can't find a code, the user can add modules by
720# hand.
721#
722class CodeNameMapper:
723
Jack Jansen59cdbce2003-03-21 16:28:09 +0000724 def __init__(self, interact=1):
Jack Jansen12b2b762000-08-20 19:30:56 +0000725 self.code2name = {
726 "property" : {},
727 "class" : {},
728 "enum" : {},
729 "comparison" : {},
730 }
731 self.name2code = {
732 "property" : {},
733 "class" : {},
734 "enum" : {},
735 "comparison" : {},
736 }
737 self.modulename = None
738 self.star_imported = 0
Jack Jansen59cdbce2003-03-21 16:28:09 +0000739 self.can_interact = interact
Jack Jansen12b2b762000-08-20 19:30:56 +0000740
741 def addnamecode(self, type, name, code):
742 self.name2code[type][name] = code
743 if not self.code2name[type].has_key(code):
744 self.code2name[type][code] = name
745
746 def hasname(self, type, name):
747 return self.name2code[type].has_key(name)
748
749 def hascode(self, type, code):
750 return self.code2name[type].has_key(code)
751
752 def findcodename(self, type, code):
753 if not self.hascode(type, code):
754 return None, None, None
755 name = self.code2name[type][code]
756 if self.modulename and not self.star_imported:
757 qualname = '%s.%s'%(self.modulename, name)
758 else:
759 qualname = name
760 return name, qualname, self.modulename
761
762 def getall(self, type):
763 return self.code2name[type].items()
764
765 def addmodule(self, module, name, star_imported):
766 self.modulename = name
767 self.star_imported = star_imported
768 for code, name in module._propdeclarations.items():
769 self.addnamecode('property', name, code)
770 for code, name in module._classdeclarations.items():
771 self.addnamecode('class', name, code)
772 for code in module._enumdeclarations.keys():
773 self.addnamecode('enum', '_Enum_'+identify(code), code)
774 for code, name in module._compdeclarations.items():
775 self.addnamecode('comparison', name, code)
776
777 def prepareforexport(self, name=None):
778 if not self.modulename:
779 self.modulename = name
780 return self
781
Jack Jansen66544221997-08-08 14:49:02 +0000782class ObjectCompiler:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000783 def __init__(self, fp, basesuite=None, othernamemappers=None, interact=1):
Jack Jansen66544221997-08-08 14:49:02 +0000784 self.fp = fp
Jack Jansen60762cb2000-08-17 22:11:45 +0000785 self.basesuite = basesuite
Jack Jansen59cdbce2003-03-21 16:28:09 +0000786 self.can_interact = interact
787 self.namemappers = [CodeNameMapper(self.can_interact)]
Jack Jansen12b2b762000-08-20 19:30:56 +0000788 if othernamemappers:
789 self.othernamemappers = othernamemappers[:]
790 else:
791 self.othernamemappers = []
792 if basesuite:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000793 basemapper = CodeNameMapper(self.can_interact)
Jack Jansen12b2b762000-08-20 19:30:56 +0000794 basemapper.addmodule(basesuite, '', 1)
795 self.namemappers.append(basemapper)
796
797 def getprecompinfo(self, modname):
798 list = []
799 for mapper in self.namemappers:
800 emapper = mapper.prepareforexport(modname)
801 if emapper:
802 list.append(emapper)
803 return list
Jack Jansen66544221997-08-08 14:49:02 +0000804
805 def findcodename(self, type, code):
806 while 1:
Jack Jansen12b2b762000-08-20 19:30:56 +0000807 # First try: check whether we already know about this code.
808 for mapper in self.namemappers:
809 if mapper.hascode(type, code):
810 return mapper.findcodename(type, code)
811 # Second try: maybe one of the other modules knows about it.
812 for mapper in self.othernamemappers:
813 if mapper.hascode(type, code):
814 self.othernamemappers.remove(mapper)
815 self.namemappers.append(mapper)
816 if self.fp:
817 self.fp.write("import %s\n"%mapper.modulename)
818 break
819 else:
820 # If all this has failed we ask the user for a guess on where it could
821 # be and retry.
822 if self.fp:
823 m = self.askdefinitionmodule(type, code)
824 else:
825 m = None
826 if not m: return None, None, None
Jack Jansen59cdbce2003-03-21 16:28:09 +0000827 mapper = CodeNameMapper(self.can_interact)
Jack Jansen12b2b762000-08-20 19:30:56 +0000828 mapper.addmodule(m, m.__name__, 0)
829 self.namemappers.append(mapper)
Jack Jansen66544221997-08-08 14:49:02 +0000830
831 def askdefinitionmodule(self, type, code):
Jack Jansen59cdbce2003-03-21 16:28:09 +0000832 if not self.can_interact:
833 print "** No definition for %s '%s' found" % (type, code)
834 return None
Jack Jansendf976ca2003-01-26 20:35:47 +0000835 path = EasyDialogs.AskFileForSave(message='Where is %s %s declared?'%(type, code))
836 if not path: return
837 path, file = os.path.split(path)
Jack Jansen66544221997-08-08 14:49:02 +0000838 modname = os.path.splitext(file)[0]
839 if not path in sys.path:
840 sys.path.insert(0, path)
841 m = __import__(modname)
842 self.fp.write("import %s\n"%modname)
843 return m
844
845 def compileclass(self, cls):
846 [name, code, desc, properties, elements] = cls
847 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000848 if self.namemappers[0].hascode('class', code):
Jack Jansen66544221997-08-08 14:49:02 +0000849 # plural forms and such
Jack Jansen12b2b762000-08-20 19:30:56 +0000850 othername, dummy, dummy = self.namemappers[0].findcodename('class', code)
851 if self.fp:
852 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000853 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000854 if self.fp:
855 self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000856 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(desc)))
Jack Jansen12b2b762000-08-20 19:30:56 +0000857 self.fp.write('\twant = %s\n' % `code`)
858 self.namemappers[0].addnamecode('class', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000859 for prop in properties:
860 self.compileproperty(prop)
861 for elem in elements:
862 self.compileelement(elem)
863
864 def compileproperty(self, prop):
865 [name, code, what] = prop
866 if code == 'c@#!':
867 # Something silly with plurals. Skip it.
868 return
869 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000870 if self.namemappers[0].hascode('property', code):
Jack Jansen2eda2442000-08-20 19:42:52 +0000871 # plural forms and such
872 othername, dummy, dummy = self.namemappers[0].findcodename('property', code)
Jack Jansen9d6d2c02000-08-22 20:34:35 +0000873 if pname == othername:
874 return
Jack Jansen12b2b762000-08-20 19:30:56 +0000875 if self.fp:
Jack Jansen2eda2442000-08-20 19:42:52 +0000876 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000877 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000878 if self.fp:
879 self.fp.write("class %s(aetools.NProperty):\n" % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000880 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(what[1])))
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000881 self.fp.write("\twhich = %s\n" % `code`)
882 self.fp.write("\twant = %s\n" % `what[0]`)
Jack Jansen2eda2442000-08-20 19:42:52 +0000883 self.namemappers[0].addnamecode('property', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000884
885 def compileelement(self, elem):
886 [code, keyform] = elem
Jack Jansen12b2b762000-08-20 19:30:56 +0000887 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000888 self.fp.write("# element %s as %s\n" % (`code`, keyform))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000889
Jack Jansen66544221997-08-08 14:49:02 +0000890 def fillclasspropsandelems(self, cls):
891 [name, code, desc, properties, elements] = cls
892 cname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000893 if self.namemappers[0].hascode('class', code) and \
894 self.namemappers[0].findcodename('class', code)[0] != cname:
Jack Jansen66544221997-08-08 14:49:02 +0000895 # This is an other name (plural or so) for something else. Skip.
896 return
897 plist = []
898 elist = []
Jack Jansen8b777672002-08-07 14:49:00 +0000899 superclasses = []
Jack Jansen66544221997-08-08 14:49:02 +0000900 for prop in properties:
901 [pname, pcode, what] = prop
Jack Jansen8b777672002-08-07 14:49:00 +0000902 if pcode == "c@#^":
903 superclasses.append(what)
Jack Jansen66544221997-08-08 14:49:02 +0000904 if pcode == 'c@#!':
905 continue
906 pname = identify(pname)
907 plist.append(pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000908
909 superclassnames = []
910 for superclass in superclasses:
911 superId, superDesc, dummy = superclass
912 superclassname, fullyqualifiedname, module = self.findcodename("class", superId)
913 superclassnames.append(superclassname)
914
915 if self.fp:
916 self.fp.write("%s._superclassnames = %s\n"%(cname, `superclassnames`))
917
Jack Jansen66544221997-08-08 14:49:02 +0000918 for elem in elements:
919 [ecode, keyform] = elem
920 if ecode == 'c@#!':
921 continue
922 name, ename, module = self.findcodename('class', ecode)
923 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000924 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000925 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
Jack Jansen66544221997-08-08 14:49:02 +0000926 else:
Jack Jansen34d11f02000-03-07 23:40:13 +0000927 elist.append((name, ename))
Jack Jansen12b2b762000-08-20 19:30:56 +0000928
929 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000930 self.fp.write("%s._privpropdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000931 for n in plist:
932 self.fp.write("\t'%s' : %s,\n"%(n, n))
933 self.fp.write("}\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000934 self.fp.write("%s._privelemdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000935 for n, fulln in elist:
936 self.fp.write("\t'%s' : %s,\n"%(n, fulln))
937 self.fp.write("}\n")
Jack Jansen66544221997-08-08 14:49:02 +0000938
939 def compilecomparison(self, comp):
940 [name, code, comment] = comp
941 iname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000942 self.namemappers[0].addnamecode('comparison', iname, code)
943 if self.fp:
944 self.fp.write("class %s(aetools.NComparison):\n" % iname)
Jack Jansen8b777672002-08-07 14:49:00 +0000945 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(comment)))
Jack Jansen66544221997-08-08 14:49:02 +0000946
947 def compileenumeration(self, enum):
948 [code, items] = enum
949 name = "_Enum_%s" % identify(code)
Jack Jansen12b2b762000-08-20 19:30:56 +0000950 if self.fp:
951 self.fp.write("%s = {\n" % name)
952 for item in items:
953 self.compileenumerator(item)
954 self.fp.write("}\n\n")
955 self.namemappers[0].addnamecode('enum', name, code)
Jack Jansen66544221997-08-08 14:49:02 +0000956 return code
957
958 def compileenumerator(self, item):
959 [name, code, desc] = item
Jack Jansen21f67582002-08-07 15:44:53 +0000960 self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, ascii(desc)))
Jack Jansen66544221997-08-08 14:49:02 +0000961
962 def checkforenum(self, enum):
963 """This enum code is used by an event. Make sure it's available"""
964 name, fullname, module = self.findcodename('enum', enum)
965 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000966 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000967 self.fp.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum), ascii(enum)))
Jack Jansen66544221997-08-08 14:49:02 +0000968 return
969 if module:
Jack Jansen12b2b762000-08-20 19:30:56 +0000970 if self.fp:
971 self.fp.write("from %s import %s\n"%(module, name))
Jack Jansen66544221997-08-08 14:49:02 +0000972
973 def dumpindex(self):
Jack Jansen12b2b762000-08-20 19:30:56 +0000974 if not self.fp:
975 return
Jack Jansen66544221997-08-08 14:49:02 +0000976 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
977 self.fp.write("_classdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000978 for k, v in self.namemappers[0].getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000979 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000980 self.fp.write("}\n")
981 self.fp.write("\n_propdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000982 for k, v in self.namemappers[0].getall('property'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000983 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000984 self.fp.write("}\n")
985 self.fp.write("\n_compdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000986 for k, v in self.namemappers[0].getall('comparison'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000987 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000988 self.fp.write("}\n")
989 self.fp.write("\n_enumdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000990 for k, v in self.namemappers[0].getall('enum'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000991 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000992 self.fp.write("}\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000993
994def compiledata(data):
995 [type, description, flags] = data
996 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
997
998def is_null(data):
999 return data[0] == 'null'
1000
1001def is_optional(data):
1002 return (data[2] & 0x8000)
1003
1004def is_enum(data):
1005 return (data[2] & 0x2000)
1006
1007def getdatadoc(data):
1008 [type, descr, flags] = data
1009 if descr:
Jack Jansen8b777672002-08-07 14:49:00 +00001010 return ascii(descr)
Jack Jansen5ccd8261995-07-17 11:43:20 +00001011 if type == '****':
1012 return 'anything'
1013 if type == 'obj ':
1014 return 'an AE object reference'
Jack Jansen2f7f8c42002-08-07 15:05:42 +00001015 return "undocumented, typecode %s"%`type`
Jack Jansen5ccd8261995-07-17 11:43:20 +00001016
1017dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
1018def compiledataflags(flags):
1019 bits = []
1020 for i in range(16):
1021 if flags & (1<<i):
1022 if i in dataflagdict.keys():
1023 bits.append(dataflagdict[i])
1024 else:
1025 bits.append(`i`)
1026 return '[%s]' % string.join(bits)
1027
Jack Jansen8b777672002-08-07 14:49:00 +00001028def ascii(str):
1029 """Return a string with all non-ascii characters hex-encoded"""
1030 if type(str) != type(''):
1031 return map(ascii, str)
1032 rv = ''
1033 for c in str:
1034 if c in ('\t', '\n', '\r') or ' ' <= c < chr(0x7f):
1035 rv = rv + c
1036 else:
Jack Jansen2f7f8c42002-08-07 15:05:42 +00001037 rv = rv + '\\' + 'x%02.2x' % ord(c)
Jack Jansen8b777672002-08-07 14:49:00 +00001038 return rv
1039
Jack Jansen5ccd8261995-07-17 11:43:20 +00001040def identify(str):
1041 """Turn any string into an identifier:
1042 - replace space by _
1043 - replace other illegal chars by _xx_ (hex code)
1044 - prepend _ if the result is a python keyword
1045 """
Jack Jansen66544221997-08-08 14:49:02 +00001046 if not str:
Jack Jansen21f67582002-08-07 15:44:53 +00001047 return "empty_ae_name_"
Jack Jansen5ccd8261995-07-17 11:43:20 +00001048 rv = ''
Fred Drake79e75e12001-07-20 19:05:50 +00001049 ok = string.ascii_letters + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +00001050 ok2 = ok + string.digits
1051 for c in str:
1052 if c in ok:
1053 rv = rv + c
1054 elif c == ' ':
1055 rv = rv + '_'
1056 else:
1057 rv = rv + '_%02.2x_'%ord(c)
1058 ok = ok2
Jack Jansenb2ecc2c2002-01-24 22:44:07 +00001059 if keyword.iskeyword(rv):
Jack Jansen21f67582002-08-07 15:44:53 +00001060 rv = rv + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +00001061 return rv
1062
1063# Call the main program
1064
1065if __name__ == '__main__':
1066 main()
1067 sys.exit(1)