blob: f22fde177a9e237e66db4996bc4b696ea476381b [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:
133 if arg[0] == -1701: # errAEDescNotFound
134 print "GetAppTerminology failed with errAEDescNotFound, trying manually"
135 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,
153 creatorsignature=creatorsignature)
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)
164 # Now get the signature of the application, hoping it is a bundle
165 pkginfo = os.path.join(fullname, 'Contents', 'PkgInfo')
166 if not os.path.exists(pkginfo):
167 raise RuntimeError, "No PkgInfo file found"
168 tp_cr = open(pkginfo, 'rb').read()
169 cr = tp_cr[4:8]
170 # Let's talk to it and ask for its AETE
171 talker = aetools.TalkTo(cr)
172 talker._start()
173 reply = talker.send("ascr", "gdte")
174 # Now pick the bits out of the return that we need.
175 return reply[1]['----'], cr
176
Jack Jansenfa1bf1c2003-03-06 23:04:38 +0000177
Jack Jansen59cdbce2003-03-21 16:28:09 +0000178def compileaetelist(aetelist, fullname, output=None, basepkgname=None,
179 edit_modnames=None, creatorsignature=None):
Jack Jansen60762cb2000-08-17 22:11:45 +0000180 for aete, resinfo in aetelist:
Jack Jansen714caa02003-03-21 16:07:39 +0000181 compileaete(aete, resinfo, fullname, output=output,
Jack Jansen59cdbce2003-03-21 16:28:09 +0000182 basepkgname=basepkgname, edit_modnames=edit_modnames,
183 creatorsignature=creatorsignature)
Jack Jansen60762cb2000-08-17 22:11:45 +0000184
Jack Jansen5ccd8261995-07-17 11:43:20 +0000185def decode(data):
186 """Decode a resource into a python data structure"""
187 f = StringIO.StringIO(data)
188 aete = generic(getaete, f)
189 aete = simplify(aete)
190 processed = f.tell()
191 unprocessed = len(f.read())
192 total = f.tell()
193 if unprocessed:
194 sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
195 (processed, unprocessed, total))
196 return aete
197
198def simplify(item):
199 """Recursively replace singleton tuples by their constituent item"""
200 if type(item) is types.ListType:
201 return map(simplify, item)
202 elif type(item) == types.TupleType and len(item) == 2:
203 return simplify(item[1])
204 else:
205 return item
206
207
208# Here follows the aete resource decoder.
209# It is presented bottom-up instead of top-down because there are direct
210# references to the lower-level part-decoders from the high-level part-decoders.
211
212def getbyte(f, *args):
213 c = f.read(1)
214 if not c:
215 raise EOFError, 'in getbyte' + str(args)
216 return ord(c)
217
218def getword(f, *args):
219 getalign(f)
220 s = f.read(2)
221 if len(s) < 2:
222 raise EOFError, 'in getword' + str(args)
223 return (ord(s[0])<<8) | ord(s[1])
224
225def getlong(f, *args):
226 getalign(f)
227 s = f.read(4)
228 if len(s) < 4:
229 raise EOFError, 'in getlong' + str(args)
230 return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
231
232def getostype(f, *args):
233 getalign(f)
234 s = f.read(4)
235 if len(s) < 4:
236 raise EOFError, 'in getostype' + str(args)
237 return s
238
239def getpstr(f, *args):
240 c = f.read(1)
241 if len(c) < 1:
242 raise EOFError, 'in getpstr[1]' + str(args)
243 nbytes = ord(c)
244 if nbytes == 0: return ''
245 s = f.read(nbytes)
246 if len(s) < nbytes:
247 raise EOFError, 'in getpstr[2]' + str(args)
248 return s
249
250def getalign(f):
251 if f.tell() & 1:
252 c = f.read(1)
253 ##if c <> '\0':
254 ## print 'align:', `c`
255
256def getlist(f, description, getitem):
257 count = getword(f)
258 list = []
259 for i in range(count):
260 list.append(generic(getitem, f))
261 getalign(f)
262 return list
263
264def alt_generic(what, f, *args):
265 print "generic", `what`, args
266 res = vageneric(what, f, args)
267 print '->', `res`
268 return res
269
270def generic(what, f, *args):
271 if type(what) == types.FunctionType:
272 return apply(what, (f,) + args)
273 if type(what) == types.ListType:
274 record = []
275 for thing in what:
276 item = apply(generic, thing[:1] + (f,) + thing[1:])
277 record.append((thing[1], item))
278 return record
279 return "BAD GENERIC ARGS: %s" % `what`
280
281getdata = [
282 (getostype, "type"),
283 (getpstr, "description"),
284 (getword, "flags")
285 ]
286getargument = [
287 (getpstr, "name"),
288 (getostype, "keyword"),
289 (getdata, "what")
290 ]
291getevent = [
292 (getpstr, "name"),
293 (getpstr, "description"),
294 (getostype, "suite code"),
295 (getostype, "event code"),
296 (getdata, "returns"),
297 (getdata, "accepts"),
298 (getlist, "optional arguments", getargument)
299 ]
300getproperty = [
301 (getpstr, "name"),
302 (getostype, "code"),
303 (getdata, "what")
304 ]
305getelement = [
306 (getostype, "type"),
307 (getlist, "keyform", getostype)
308 ]
309getclass = [
310 (getpstr, "name"),
311 (getostype, "class code"),
312 (getpstr, "description"),
313 (getlist, "properties", getproperty),
314 (getlist, "elements", getelement)
315 ]
316getcomparison = [
317 (getpstr, "operator name"),
318 (getostype, "operator ID"),
319 (getpstr, "operator comment"),
320 ]
321getenumerator = [
322 (getpstr, "enumerator name"),
323 (getostype, "enumerator ID"),
324 (getpstr, "enumerator comment")
325 ]
326getenumeration = [
327 (getostype, "enumeration ID"),
328 (getlist, "enumerator", getenumerator)
329 ]
330getsuite = [
331 (getpstr, "suite name"),
332 (getpstr, "suite description"),
333 (getostype, "suite ID"),
334 (getword, "suite level"),
335 (getword, "suite version"),
336 (getlist, "events", getevent),
337 (getlist, "classes", getclass),
338 (getlist, "comparisons", getcomparison),
339 (getlist, "enumerations", getenumeration)
340 ]
341getaete = [
342 (getword, "major/minor version in BCD"),
343 (getword, "language code"),
344 (getword, "script code"),
345 (getlist, "suites", getsuite)
346 ]
347
Jack Jansen59cdbce2003-03-21 16:28:09 +0000348def compileaete(aete, resinfo, fname, output=None, basepkgname=None,
349 edit_modnames=None, creatorsignature=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000350 """Generate code for a full aete resource. fname passed for doc purposes"""
351 [version, language, script, suites] = aete
352 major, minor = divmod(version, 256)
Jack Jansen59cdbce2003-03-21 16:28:09 +0000353 if not creatorsignature:
354 creatorsignature, dummy = MacOS.GetCreatorAndType(fname)
Jack Jansen40926062002-03-30 23:43:04 +0000355 packagename = identify(os.path.splitext(os.path.basename(fname))[0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000356 if language:
357 packagename = packagename+'_lang%d'%language
358 if script:
359 packagename = packagename+'_script%d'%script
360 if len(packagename) > 27:
361 packagename = packagename[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000362 if output:
363 # XXXX Put this in site-packages if it isn't a full pathname?
364 if not os.path.exists(output):
365 os.mkdir(output)
366 pathname = output
367 else:
368 pathname = EasyDialogs.AskFolder(message='Create and select package folder for %s'%packagename,
369 defaultLocation=DEFAULT_USER_PACKAGEFOLDER)
Jack Jansen0e85e7a2003-03-26 23:14:44 +0000370 output = pathname
Jack Jansendf976ca2003-01-26 20:35:47 +0000371 if not pathname:
Jack Jansen60762cb2000-08-17 22:11:45 +0000372 return
Jack Jansen60762cb2000-08-17 22:11:45 +0000373 packagename = os.path.split(os.path.normpath(pathname))[1]
Jack Jansen714caa02003-03-21 16:07:39 +0000374 if not basepkgname:
375 basepkgname = EasyDialogs.AskFolder(message='Package folder for base suite (usually StdSuites)',
376 defaultLocation=DEFAULT_STANDARD_PACKAGEFOLDER)
Jack Jansendf976ca2003-01-26 20:35:47 +0000377 if basepkgname:
378 dirname, basepkgname = os.path.split(os.path.normpath(basepkgname))
Jack Jansen714caa02003-03-21 16:07:39 +0000379 if dirname and not dirname in sys.path:
Jack Jansen60762cb2000-08-17 22:11:45 +0000380 sys.path.insert(0, dirname)
381 basepackage = __import__(basepkgname)
382 else:
383 basepackage = None
Jack Jansen60762cb2000-08-17 22:11:45 +0000384 suitelist = []
Jack Jansen12b2b762000-08-20 19:30:56 +0000385 allprecompinfo = []
386 allsuites = []
Jack Jansen5ccd8261995-07-17 11:43:20 +0000387 for suite in suites:
Jack Jansen714caa02003-03-21 16:07:39 +0000388 code, suite, pathname, modname, precompinfo = precompilesuite(suite, basepackage,
389 output=output, edit_modnames=edit_modnames)
Jack Jansen12b2b762000-08-20 19:30:56 +0000390 if not code:
391 continue
392 allprecompinfo = allprecompinfo + precompinfo
Jack Jansendf976ca2003-01-26 20:35:47 +0000393 suiteinfo = suite, pathname, modname
Jack Jansen12b2b762000-08-20 19:30:56 +0000394 suitelist.append((code, modname))
395 allsuites.append(suiteinfo)
396 for suiteinfo in allsuites:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000397 compilesuite(suiteinfo, major, minor, language, script, fname, basepackage,
398 allprecompinfo, interact=(edit_modnames is None))
Jack Jansen714caa02003-03-21 16:07:39 +0000399 initfilename = os.path.join(output, '__init__.py')
Jack Jansendf976ca2003-01-26 20:35:47 +0000400 fp = open(initfilename, 'w')
401 MacOS.SetCreatorAndType(initfilename, 'Pyth', 'TEXT')
Jack Jansen60762cb2000-08-17 22:11:45 +0000402 fp.write('"""\n')
403 fp.write("Package generated from %s\n"%fname)
Jack Jansen8b777672002-08-07 14:49:00 +0000404 if resinfo:
405 fp.write("Resource %s resid %d %s\n"%(ascii(resinfo[1]), resinfo[0], ascii(resinfo[2])))
Jack Jansen60762cb2000-08-17 22:11:45 +0000406 fp.write('"""\n')
407 fp.write('import aetools\n')
Jack Jansen6aa92c52000-08-20 21:59:03 +0000408 fp.write('Error = aetools.Error\n')
Jack Jansen60762cb2000-08-17 22:11:45 +0000409 for code, modname in suitelist:
410 fp.write("import %s\n" % modname)
411 fp.write("\n\n_code_to_module = {\n")
412 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000413 fp.write("\t'%s' : %s,\n"%(ascii(code), modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000414 fp.write("}\n\n")
415 fp.write("\n\n_code_to_fullname = {\n")
416 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000417 fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(ascii(code), packagename, modname, modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000418 fp.write("}\n\n")
419 for code, modname in suitelist:
420 fp.write("from %s import *\n"%modname)
Jack Jansen8b777672002-08-07 14:49:00 +0000421
422 # Generate property dicts and element dicts for all types declared in this module
Jack Jansen7e0bc112003-03-21 12:04:19 +0000423 fp.write("\ndef getbaseclasses(v):\n")
Jack Jansen7cb016d2003-03-23 22:05:53 +0000424 fp.write("\tif not getattr(v, '_propdict', None):\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000425 fp.write("\t\tv._propdict = {}\n")
426 fp.write("\t\tv._elemdict = {}\n")
Jack Jansen7e0bc112003-03-21 12:04:19 +0000427 fp.write("\t\tfor superclassname in getattr(v, '_superclassnames', []):\n")
428 fp.write("\t\t\tsuperclass = eval(superclassname)\n")
429 fp.write("\t\t\tgetbaseclasses(superclass)\n")
430 fp.write("\t\t\tv._propdict.update(getattr(superclass, '_propdict', {}))\n")
431 fp.write("\t\t\tv._elemdict.update(getattr(superclass, '_elemdict', {}))\n")
Jack Jansen7cb016d2003-03-23 22:05:53 +0000432 fp.write("\t\tv._propdict.update(getattr(v, '_privpropdict', {}))\n")
433 fp.write("\t\tv._elemdict.update(getattr(v, '_privelemdict', {}))\n")
Jack Jansen21f67582002-08-07 15:44:53 +0000434 fp.write("\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000435 fp.write("import StdSuites\n")
436 if allprecompinfo:
437 fp.write("\n#\n# Set property and element dictionaries now that all classes have been defined\n#\n")
438 for codenamemapper in allprecompinfo:
439 for k, v in codenamemapper.getall('class'):
440 fp.write("getbaseclasses(%s)\n" % v)
441
442 # Generate a code-to-name mapper for all of the types (classes) declared in this module
443 if allprecompinfo:
444 fp.write("\n#\n# Indices of types declared in this module\n#\n")
445 fp.write("_classdeclarations = {\n")
446 for codenamemapper in allprecompinfo:
447 for k, v in codenamemapper.getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000448 fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen8b777672002-08-07 14:49:00 +0000449 fp.write("}\n")
450
Jack Jansen60762cb2000-08-17 22:11:45 +0000451 if suitelist:
452 fp.write("\n\nclass %s(%s_Events"%(packagename, suitelist[0][1]))
453 for code, modname in suitelist[1:]:
Jack Jansen12b2b762000-08-20 19:30:56 +0000454 fp.write(",\n\t\t%s_Events"%modname)
455 fp.write(",\n\t\taetools.TalkTo):\n")
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000456 fp.write("\t_signature = %s\n\n"%`creatorsignature`)
Jack Jansen8b777672002-08-07 14:49:00 +0000457 fp.write("\t_moduleName = '%s'\n\n"%packagename)
Jack Jansen60762cb2000-08-17 22:11:45 +0000458 fp.close()
Jack Jansen12b2b762000-08-20 19:30:56 +0000459
Jack Jansen714caa02003-03-21 16:07:39 +0000460def precompilesuite(suite, basepackage=None, edit_modnames=None, output=None):
Jack Jansen12b2b762000-08-20 19:30:56 +0000461 """Parse a single suite without generating the output. This step is needed
462 so we can resolve recursive references by suites to enums/comps/etc declared
463 in other suites"""
Jack Jansen5ccd8261995-07-17 11:43:20 +0000464 [name, desc, code, level, version, events, classes, comps, enums] = suite
465
466 modname = identify(name)
Jack Jansen60762cb2000-08-17 22:11:45 +0000467 if len(modname) > 28:
468 modname = modname[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000469 if edit_modnames is None:
470 pathname = EasyDialogs.AskFileForSave(message='Python output file',
471 savedFileName=modname+'.py')
472 else:
473 for old, new in edit_modnames:
474 if old == modname:
475 modname = new
476 if modname:
477 pathname = os.path.join(output, modname + '.py')
478 else:
479 pathname = None
Jack Jansendf976ca2003-01-26 20:35:47 +0000480 if not pathname:
Jack Jansen12b2b762000-08-20 19:30:56 +0000481 return None, None, None, None, None
482
Jack Jansen60762cb2000-08-17 22:11:45 +0000483 modname = os.path.splitext(os.path.split(pathname)[1])[0]
Jack Jansen12b2b762000-08-20 19:30:56 +0000484
485 if basepackage and basepackage._code_to_module.has_key(code):
486 # We are an extension of a baseclass (usually an application extending
487 # Standard_Suite or so). Import everything from our base module
488 basemodule = basepackage._code_to_module[code]
489 else:
490 # We are not an extension.
491 basemodule = None
492
493 enumsneeded = {}
494 for event in events:
495 findenumsinevent(event, enumsneeded)
496
Jack Jansen59cdbce2003-03-21 16:28:09 +0000497 objc = ObjectCompiler(None, basemodule, interact=(edit_modnames is None))
Jack Jansen12b2b762000-08-20 19:30:56 +0000498 for cls in classes:
499 objc.compileclass(cls)
500 for cls in classes:
501 objc.fillclasspropsandelems(cls)
502 for comp in comps:
503 objc.compilecomparison(comp)
504 for enum in enums:
505 objc.compileenumeration(enum)
506
507 for enum in enumsneeded.keys():
508 objc.checkforenum(enum)
509
510 objc.dumpindex()
511
512 precompinfo = objc.getprecompinfo(modname)
513
Jack Jansendf976ca2003-01-26 20:35:47 +0000514 return code, suite, pathname, modname, precompinfo
Jack Jansen12b2b762000-08-20 19:30:56 +0000515
Jack Jansen59cdbce2003-03-21 16:28:09 +0000516def compilesuite((suite, pathname, modname), major, minor, language, script,
517 fname, basepackage, precompinfo, interact=1):
Jack Jansen12b2b762000-08-20 19:30:56 +0000518 """Generate code for a single suite"""
519 [name, desc, code, level, version, events, classes, comps, enums] = suite
520
Jack Jansendf976ca2003-01-26 20:35:47 +0000521 fp = open(pathname, 'w')
522 MacOS.SetCreatorAndType(pathname, 'Pyth', 'TEXT')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000523
Jack Jansen8b777672002-08-07 14:49:00 +0000524 fp.write('"""Suite %s: %s\n' % (ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000525 fp.write("Level %d, version %d\n\n" % (level, version))
Jack Jansen8b777672002-08-07 14:49:00 +0000526 fp.write("Generated from %s\n"%ascii(fname))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000527 fp.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
528 (major, minor, language, script))
529 fp.write('"""\n\n')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000530
531 fp.write('import aetools\n')
532 fp.write('import MacOS\n\n')
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000533 fp.write("_code = %s\n\n"% `code`)
Jack Jansen60762cb2000-08-17 22:11:45 +0000534 if basepackage and basepackage._code_to_module.has_key(code):
535 # We are an extension of a baseclass (usually an application extending
536 # Standard_Suite or so). Import everything from our base module
Jack Jansen12b2b762000-08-20 19:30:56 +0000537 fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000538 basemodule = basepackage._code_to_module[code]
Jack Jansen7ebcbf52002-01-22 23:24:03 +0000539 elif basepackage and basepackage._code_to_module.has_key(code.lower()):
540 # This is needed by CodeWarrior and some others.
541 fp.write('from %s import *\n'%basepackage._code_to_fullname[code.lower()][0])
542 basemodule = basepackage._code_to_module[code.lower()]
Jack Jansen60762cb2000-08-17 22:11:45 +0000543 else:
544 # We are not an extension.
545 basemodule = None
546 compileclassheader(fp, modname, basemodule)
Jack Jansen66544221997-08-08 14:49:02 +0000547
548 enumsneeded = {}
Jack Jansen5ccd8261995-07-17 11:43:20 +0000549 if events:
550 for event in events:
Jack Jansen66544221997-08-08 14:49:02 +0000551 compileevent(fp, event, enumsneeded)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000552 else:
553 fp.write("\tpass\n\n")
Jack Jansen66544221997-08-08 14:49:02 +0000554
Jack Jansen59cdbce2003-03-21 16:28:09 +0000555 objc = ObjectCompiler(fp, basemodule, precompinfo, interact=interact)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000556 for cls in classes:
Jack Jansen66544221997-08-08 14:49:02 +0000557 objc.compileclass(cls)
558 for cls in classes:
559 objc.fillclasspropsandelems(cls)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000560 for comp in comps:
Jack Jansen66544221997-08-08 14:49:02 +0000561 objc.compilecomparison(comp)
562 for enum in enums:
563 objc.compileenumeration(enum)
564
565 for enum in enumsneeded.keys():
566 objc.checkforenum(enum)
567
568 objc.dumpindex()
Jack Jansen60762cb2000-08-17 22:11:45 +0000569
570 return code, modname
Jack Jansen5ccd8261995-07-17 11:43:20 +0000571
Jack Jansen60762cb2000-08-17 22:11:45 +0000572def compileclassheader(fp, name, module=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000573 """Generate class boilerplate"""
Jack Jansen60762cb2000-08-17 22:11:45 +0000574 classname = '%s_Events'%name
Jack Jansen12b2b762000-08-20 19:30:56 +0000575 if module:
576 modshortname = string.split(module.__name__, '.')[-1]
577 baseclassname = '%s_Events'%modshortname
578 fp.write("class %s(%s):\n\n"%(classname, baseclassname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000579 else:
580 fp.write("class %s:\n\n"%classname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000581
Jack Jansen66544221997-08-08 14:49:02 +0000582def compileevent(fp, event, enumsneeded):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000583 """Generate code for a single event"""
584 [name, desc, code, subcode, returns, accepts, arguments] = event
585 funcname = identify(name)
586 #
587 # generate name->keyword map
588 #
589 if arguments:
590 fp.write("\t_argmap_%s = {\n"%funcname)
591 for a in arguments:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000592 fp.write("\t\t%s : %s,\n"%(`identify(a[0])`, `a[1]`))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000593 fp.write("\t}\n\n")
594
595 #
596 # Generate function header
597 #
598 has_arg = (not is_null(accepts))
599 opt_arg = (has_arg and is_optional(accepts))
600
Jack Jansen84264771995-10-03 14:35:58 +0000601 fp.write("\tdef %s(self, "%funcname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000602 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000603 if not opt_arg:
604 fp.write("_object, ") # Include direct object, if it has one
605 else:
606 fp.write("_object=None, ") # Also include if it is optional
Jack Jansen5ccd8261995-07-17 11:43:20 +0000607 else:
Jack Jansen84264771995-10-03 14:35:58 +0000608 fp.write("_no_object=None, ") # For argument checking
609 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
Jack Jansen5ccd8261995-07-17 11:43:20 +0000610 #
611 # Generate doc string (important, since it may be the only
612 # available documentation, due to our name-remaping)
613 #
Jack Jansen21f67582002-08-07 15:44:53 +0000614 fp.write('\t\t"""%s: %s\n'%(ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000615 if has_arg:
616 fp.write("\t\tRequired argument: %s\n"%getdatadoc(accepts))
617 elif opt_arg:
618 fp.write("\t\tOptional argument: %s\n"%getdatadoc(accepts))
619 for arg in arguments:
620 fp.write("\t\tKeyword argument %s: %s\n"%(identify(arg[0]),
621 getdatadoc(arg[2])))
622 fp.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
623 if not is_null(returns):
624 fp.write("\t\tReturns: %s\n"%getdatadoc(returns))
625 fp.write('\t\t"""\n')
626 #
627 # Fiddle the args so everything ends up in 'arguments' dictionary
628 #
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000629 fp.write("\t\t_code = %s\n"% `code`)
630 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
Jack Jansen73215141995-10-09 23:09:23 +0000631 #
632 # Do keyword name substitution
633 #
634 if arguments:
635 fp.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname)
636 else:
637 fp.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
638 #
639 # Stuff required arg (if there is one) into arguments
640 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000641 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000642 fp.write("\t\t_arguments['----'] = _object\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000643 elif opt_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000644 fp.write("\t\tif _object:\n")
645 fp.write("\t\t\t_arguments['----'] = _object\n")
646 else:
647 fp.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000648 fp.write("\n")
649 #
Jack Jansen73215141995-10-09 23:09:23 +0000650 # Do enum-name substitution
Jack Jansen5ccd8261995-07-17 11:43:20 +0000651 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000652 for a in arguments:
653 if is_enum(a[2]):
654 kname = a[1]
655 ename = a[2][0]
Jack Jansena2408e91996-04-16 14:36:46 +0000656 if ename <> '****':
657 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000658 (`kname`, identify(ename)))
Jack Jansen66544221997-08-08 14:49:02 +0000659 enumsneeded[ename] = 1
Jack Jansen5ccd8261995-07-17 11:43:20 +0000660 fp.write("\n")
661 #
662 # Do the transaction
663 #
Jack Jansen84264771995-10-03 14:35:58 +0000664 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
665 fp.write("\t\t\t\t_arguments, _attributes)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000666 #
667 # Error handling
668 #
Jack Jansen18983532002-04-23 21:03:21 +0000669 fp.write("\t\tif _arguments.get('errn', 0):\n")
Jack Jansen977fbf21996-09-20 15:29:59 +0000670 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000671 fp.write("\t\t# XXXX Optionally decode result\n")
672 #
673 # Decode result
674 #
Jack Jansen84264771995-10-03 14:35:58 +0000675 fp.write("\t\tif _arguments.has_key('----'):\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000676 if is_enum(returns):
677 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
Jack Jansen84264771995-10-03 14:35:58 +0000678 fp.write("\t\t\treturn _arguments['----']\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000679 fp.write("\n")
680
681# print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
682# print "# returns", compiledata(returns)
683# print "# accepts", compiledata(accepts)
684# for arg in arguments:
685# compileargument(arg)
686
687def compileargument(arg):
688 [name, keyword, what] = arg
689 print "# %s (%s)" % (name, `keyword`), compiledata(what)
690
Jack Jansen12b2b762000-08-20 19:30:56 +0000691def findenumsinevent(event, enumsneeded):
692 """Find all enums for a single event"""
693 [name, desc, code, subcode, returns, accepts, arguments] = event
694 for a in arguments:
695 if is_enum(a[2]):
696 ename = a[2][0]
697 if ename <> '****':
698 enumsneeded[ename] = 1
699
700#
701# This class stores the code<->name translations for a single module. It is used
702# to keep the information while we're compiling the module, but we also keep these objects
703# around so if one suite refers to, say, an enum in another suite we know where to
704# find it. Finally, if we really can't find a code, the user can add modules by
705# hand.
706#
707class CodeNameMapper:
708
Jack Jansen59cdbce2003-03-21 16:28:09 +0000709 def __init__(self, interact=1):
Jack Jansen12b2b762000-08-20 19:30:56 +0000710 self.code2name = {
711 "property" : {},
712 "class" : {},
713 "enum" : {},
714 "comparison" : {},
715 }
716 self.name2code = {
717 "property" : {},
718 "class" : {},
719 "enum" : {},
720 "comparison" : {},
721 }
722 self.modulename = None
723 self.star_imported = 0
Jack Jansen59cdbce2003-03-21 16:28:09 +0000724 self.can_interact = interact
Jack Jansen12b2b762000-08-20 19:30:56 +0000725
726 def addnamecode(self, type, name, code):
727 self.name2code[type][name] = code
728 if not self.code2name[type].has_key(code):
729 self.code2name[type][code] = name
730
731 def hasname(self, type, name):
732 return self.name2code[type].has_key(name)
733
734 def hascode(self, type, code):
735 return self.code2name[type].has_key(code)
736
737 def findcodename(self, type, code):
738 if not self.hascode(type, code):
739 return None, None, None
740 name = self.code2name[type][code]
741 if self.modulename and not self.star_imported:
742 qualname = '%s.%s'%(self.modulename, name)
743 else:
744 qualname = name
745 return name, qualname, self.modulename
746
747 def getall(self, type):
748 return self.code2name[type].items()
749
750 def addmodule(self, module, name, star_imported):
751 self.modulename = name
752 self.star_imported = star_imported
753 for code, name in module._propdeclarations.items():
754 self.addnamecode('property', name, code)
755 for code, name in module._classdeclarations.items():
756 self.addnamecode('class', name, code)
757 for code in module._enumdeclarations.keys():
758 self.addnamecode('enum', '_Enum_'+identify(code), code)
759 for code, name in module._compdeclarations.items():
760 self.addnamecode('comparison', name, code)
761
762 def prepareforexport(self, name=None):
763 if not self.modulename:
764 self.modulename = name
765 return self
766
Jack Jansen66544221997-08-08 14:49:02 +0000767class ObjectCompiler:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000768 def __init__(self, fp, basesuite=None, othernamemappers=None, interact=1):
Jack Jansen66544221997-08-08 14:49:02 +0000769 self.fp = fp
Jack Jansen60762cb2000-08-17 22:11:45 +0000770 self.basesuite = basesuite
Jack Jansen59cdbce2003-03-21 16:28:09 +0000771 self.can_interact = interact
772 self.namemappers = [CodeNameMapper(self.can_interact)]
Jack Jansen12b2b762000-08-20 19:30:56 +0000773 if othernamemappers:
774 self.othernamemappers = othernamemappers[:]
775 else:
776 self.othernamemappers = []
777 if basesuite:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000778 basemapper = CodeNameMapper(self.can_interact)
Jack Jansen12b2b762000-08-20 19:30:56 +0000779 basemapper.addmodule(basesuite, '', 1)
780 self.namemappers.append(basemapper)
781
782 def getprecompinfo(self, modname):
783 list = []
784 for mapper in self.namemappers:
785 emapper = mapper.prepareforexport(modname)
786 if emapper:
787 list.append(emapper)
788 return list
Jack Jansen66544221997-08-08 14:49:02 +0000789
790 def findcodename(self, type, code):
791 while 1:
Jack Jansen12b2b762000-08-20 19:30:56 +0000792 # First try: check whether we already know about this code.
793 for mapper in self.namemappers:
794 if mapper.hascode(type, code):
795 return mapper.findcodename(type, code)
796 # Second try: maybe one of the other modules knows about it.
797 for mapper in self.othernamemappers:
798 if mapper.hascode(type, code):
799 self.othernamemappers.remove(mapper)
800 self.namemappers.append(mapper)
801 if self.fp:
802 self.fp.write("import %s\n"%mapper.modulename)
803 break
804 else:
805 # If all this has failed we ask the user for a guess on where it could
806 # be and retry.
807 if self.fp:
808 m = self.askdefinitionmodule(type, code)
809 else:
810 m = None
811 if not m: return None, None, None
Jack Jansen59cdbce2003-03-21 16:28:09 +0000812 mapper = CodeNameMapper(self.can_interact)
Jack Jansen12b2b762000-08-20 19:30:56 +0000813 mapper.addmodule(m, m.__name__, 0)
814 self.namemappers.append(mapper)
Jack Jansen66544221997-08-08 14:49:02 +0000815
816 def askdefinitionmodule(self, type, code):
Jack Jansen59cdbce2003-03-21 16:28:09 +0000817 if not self.can_interact:
818 print "** No definition for %s '%s' found" % (type, code)
819 return None
Jack Jansendf976ca2003-01-26 20:35:47 +0000820 path = EasyDialogs.AskFileForSave(message='Where is %s %s declared?'%(type, code))
821 if not path: return
822 path, file = os.path.split(path)
Jack Jansen66544221997-08-08 14:49:02 +0000823 modname = os.path.splitext(file)[0]
824 if not path in sys.path:
825 sys.path.insert(0, path)
826 m = __import__(modname)
827 self.fp.write("import %s\n"%modname)
828 return m
829
830 def compileclass(self, cls):
831 [name, code, desc, properties, elements] = cls
832 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000833 if self.namemappers[0].hascode('class', code):
Jack Jansen66544221997-08-08 14:49:02 +0000834 # plural forms and such
Jack Jansen12b2b762000-08-20 19:30:56 +0000835 othername, dummy, dummy = self.namemappers[0].findcodename('class', code)
836 if self.fp:
837 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000838 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000839 if self.fp:
840 self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000841 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(desc)))
Jack Jansen12b2b762000-08-20 19:30:56 +0000842 self.fp.write('\twant = %s\n' % `code`)
843 self.namemappers[0].addnamecode('class', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000844 for prop in properties:
845 self.compileproperty(prop)
846 for elem in elements:
847 self.compileelement(elem)
848
849 def compileproperty(self, prop):
850 [name, code, what] = prop
851 if code == 'c@#!':
852 # Something silly with plurals. Skip it.
853 return
854 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000855 if self.namemappers[0].hascode('property', code):
Jack Jansen2eda2442000-08-20 19:42:52 +0000856 # plural forms and such
857 othername, dummy, dummy = self.namemappers[0].findcodename('property', code)
Jack Jansen9d6d2c02000-08-22 20:34:35 +0000858 if pname == othername:
859 return
Jack Jansen12b2b762000-08-20 19:30:56 +0000860 if self.fp:
Jack Jansen2eda2442000-08-20 19:42:52 +0000861 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000862 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000863 if self.fp:
864 self.fp.write("class %s(aetools.NProperty):\n" % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000865 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(what[1])))
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000866 self.fp.write("\twhich = %s\n" % `code`)
867 self.fp.write("\twant = %s\n" % `what[0]`)
Jack Jansen2eda2442000-08-20 19:42:52 +0000868 self.namemappers[0].addnamecode('property', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000869
870 def compileelement(self, elem):
871 [code, keyform] = elem
Jack Jansen12b2b762000-08-20 19:30:56 +0000872 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000873 self.fp.write("# element %s as %s\n" % (`code`, keyform))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000874
Jack Jansen66544221997-08-08 14:49:02 +0000875 def fillclasspropsandelems(self, cls):
876 [name, code, desc, properties, elements] = cls
877 cname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000878 if self.namemappers[0].hascode('class', code) and \
879 self.namemappers[0].findcodename('class', code)[0] != cname:
Jack Jansen66544221997-08-08 14:49:02 +0000880 # This is an other name (plural or so) for something else. Skip.
881 return
882 plist = []
883 elist = []
Jack Jansen8b777672002-08-07 14:49:00 +0000884 superclasses = []
Jack Jansen66544221997-08-08 14:49:02 +0000885 for prop in properties:
886 [pname, pcode, what] = prop
Jack Jansen8b777672002-08-07 14:49:00 +0000887 if pcode == "c@#^":
888 superclasses.append(what)
Jack Jansen66544221997-08-08 14:49:02 +0000889 if pcode == 'c@#!':
890 continue
891 pname = identify(pname)
892 plist.append(pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000893
894 superclassnames = []
895 for superclass in superclasses:
896 superId, superDesc, dummy = superclass
897 superclassname, fullyqualifiedname, module = self.findcodename("class", superId)
898 superclassnames.append(superclassname)
899
900 if self.fp:
901 self.fp.write("%s._superclassnames = %s\n"%(cname, `superclassnames`))
902
Jack Jansen66544221997-08-08 14:49:02 +0000903 for elem in elements:
904 [ecode, keyform] = elem
905 if ecode == 'c@#!':
906 continue
907 name, ename, module = self.findcodename('class', ecode)
908 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000909 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000910 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
Jack Jansen66544221997-08-08 14:49:02 +0000911 else:
Jack Jansen34d11f02000-03-07 23:40:13 +0000912 elist.append((name, ename))
Jack Jansen12b2b762000-08-20 19:30:56 +0000913
914 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000915 self.fp.write("%s._privpropdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000916 for n in plist:
917 self.fp.write("\t'%s' : %s,\n"%(n, n))
918 self.fp.write("}\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000919 self.fp.write("%s._privelemdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000920 for n, fulln in elist:
921 self.fp.write("\t'%s' : %s,\n"%(n, fulln))
922 self.fp.write("}\n")
Jack Jansen66544221997-08-08 14:49:02 +0000923
924 def compilecomparison(self, comp):
925 [name, code, comment] = comp
926 iname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000927 self.namemappers[0].addnamecode('comparison', iname, code)
928 if self.fp:
929 self.fp.write("class %s(aetools.NComparison):\n" % iname)
Jack Jansen8b777672002-08-07 14:49:00 +0000930 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(comment)))
Jack Jansen66544221997-08-08 14:49:02 +0000931
932 def compileenumeration(self, enum):
933 [code, items] = enum
934 name = "_Enum_%s" % identify(code)
Jack Jansen12b2b762000-08-20 19:30:56 +0000935 if self.fp:
936 self.fp.write("%s = {\n" % name)
937 for item in items:
938 self.compileenumerator(item)
939 self.fp.write("}\n\n")
940 self.namemappers[0].addnamecode('enum', name, code)
Jack Jansen66544221997-08-08 14:49:02 +0000941 return code
942
943 def compileenumerator(self, item):
944 [name, code, desc] = item
Jack Jansen21f67582002-08-07 15:44:53 +0000945 self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, ascii(desc)))
Jack Jansen66544221997-08-08 14:49:02 +0000946
947 def checkforenum(self, enum):
948 """This enum code is used by an event. Make sure it's available"""
949 name, fullname, module = self.findcodename('enum', enum)
950 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000951 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000952 self.fp.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum), ascii(enum)))
Jack Jansen66544221997-08-08 14:49:02 +0000953 return
954 if module:
Jack Jansen12b2b762000-08-20 19:30:56 +0000955 if self.fp:
956 self.fp.write("from %s import %s\n"%(module, name))
Jack Jansen66544221997-08-08 14:49:02 +0000957
958 def dumpindex(self):
Jack Jansen12b2b762000-08-20 19:30:56 +0000959 if not self.fp:
960 return
Jack Jansen66544221997-08-08 14:49:02 +0000961 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
962 self.fp.write("_classdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000963 for k, v in self.namemappers[0].getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000964 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000965 self.fp.write("}\n")
966 self.fp.write("\n_propdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000967 for k, v in self.namemappers[0].getall('property'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000968 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000969 self.fp.write("}\n")
970 self.fp.write("\n_compdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000971 for k, v in self.namemappers[0].getall('comparison'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000972 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000973 self.fp.write("}\n")
974 self.fp.write("\n_enumdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000975 for k, v in self.namemappers[0].getall('enum'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000976 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000977 self.fp.write("}\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000978
979def compiledata(data):
980 [type, description, flags] = data
981 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
982
983def is_null(data):
984 return data[0] == 'null'
985
986def is_optional(data):
987 return (data[2] & 0x8000)
988
989def is_enum(data):
990 return (data[2] & 0x2000)
991
992def getdatadoc(data):
993 [type, descr, flags] = data
994 if descr:
Jack Jansen8b777672002-08-07 14:49:00 +0000995 return ascii(descr)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000996 if type == '****':
997 return 'anything'
998 if type == 'obj ':
999 return 'an AE object reference'
Jack Jansen2f7f8c42002-08-07 15:05:42 +00001000 return "undocumented, typecode %s"%`type`
Jack Jansen5ccd8261995-07-17 11:43:20 +00001001
1002dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
1003def compiledataflags(flags):
1004 bits = []
1005 for i in range(16):
1006 if flags & (1<<i):
1007 if i in dataflagdict.keys():
1008 bits.append(dataflagdict[i])
1009 else:
1010 bits.append(`i`)
1011 return '[%s]' % string.join(bits)
1012
Jack Jansen8b777672002-08-07 14:49:00 +00001013def ascii(str):
1014 """Return a string with all non-ascii characters hex-encoded"""
1015 if type(str) != type(''):
1016 return map(ascii, str)
1017 rv = ''
1018 for c in str:
1019 if c in ('\t', '\n', '\r') or ' ' <= c < chr(0x7f):
1020 rv = rv + c
1021 else:
Jack Jansen2f7f8c42002-08-07 15:05:42 +00001022 rv = rv + '\\' + 'x%02.2x' % ord(c)
Jack Jansen8b777672002-08-07 14:49:00 +00001023 return rv
1024
Jack Jansen5ccd8261995-07-17 11:43:20 +00001025def identify(str):
1026 """Turn any string into an identifier:
1027 - replace space by _
1028 - replace other illegal chars by _xx_ (hex code)
1029 - prepend _ if the result is a python keyword
1030 """
Jack Jansen66544221997-08-08 14:49:02 +00001031 if not str:
Jack Jansen21f67582002-08-07 15:44:53 +00001032 return "empty_ae_name_"
Jack Jansen5ccd8261995-07-17 11:43:20 +00001033 rv = ''
Fred Drake79e75e12001-07-20 19:05:50 +00001034 ok = string.ascii_letters + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +00001035 ok2 = ok + string.digits
1036 for c in str:
1037 if c in ok:
1038 rv = rv + c
1039 elif c == ' ':
1040 rv = rv + '_'
1041 else:
1042 rv = rv + '_%02.2x_'%ord(c)
1043 ok = ok2
Jack Jansenb2ecc2c2002-01-24 22:44:07 +00001044 if keyword.iskeyword(rv):
Jack Jansen21f67582002-08-07 15:44:53 +00001045 rv = rv + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +00001046 return rv
1047
1048# Call the main program
1049
1050if __name__ == '__main__':
1051 main()
1052 sys.exit(1)