blob: 50dd20737577a6c8877ca7c04c73be5520dbe520 [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"""
130 aedescobj, launched = OSATerminology.GetSysTerminology(fullname)
131 if launched:
132 print "Launched", fullname
133 raw = aetools.unpack(aedescobj)
134 if not raw:
135 print 'Unpack returned empty value:', raw
136 return
137 if not raw[0].data:
138 print 'Unpack returned value without data:', raw
139 return
140 aedata = raw[0]
141 aete = decode(aedata.data)
Jack Jansen59cdbce2003-03-21 16:28:09 +0000142 compileaete(aete, None, fullname, output=output, basepkgname=basepkgname,
143 creatorsignature=creatorsignature)
Jack Jansenfa1bf1c2003-03-06 23:04:38 +0000144
Jack Jansen59cdbce2003-03-21 16:28:09 +0000145def compileaetelist(aetelist, fullname, output=None, basepkgname=None,
146 edit_modnames=None, creatorsignature=None):
Jack Jansen60762cb2000-08-17 22:11:45 +0000147 for aete, resinfo in aetelist:
Jack Jansen714caa02003-03-21 16:07:39 +0000148 compileaete(aete, resinfo, fullname, output=output,
Jack Jansen59cdbce2003-03-21 16:28:09 +0000149 basepkgname=basepkgname, edit_modnames=edit_modnames,
150 creatorsignature=creatorsignature)
Jack Jansen60762cb2000-08-17 22:11:45 +0000151
Jack Jansen5ccd8261995-07-17 11:43:20 +0000152def decode(data):
153 """Decode a resource into a python data structure"""
154 f = StringIO.StringIO(data)
155 aete = generic(getaete, f)
156 aete = simplify(aete)
157 processed = f.tell()
158 unprocessed = len(f.read())
159 total = f.tell()
160 if unprocessed:
161 sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
162 (processed, unprocessed, total))
163 return aete
164
165def simplify(item):
166 """Recursively replace singleton tuples by their constituent item"""
167 if type(item) is types.ListType:
168 return map(simplify, item)
169 elif type(item) == types.TupleType and len(item) == 2:
170 return simplify(item[1])
171 else:
172 return item
173
174
175# Here follows the aete resource decoder.
176# It is presented bottom-up instead of top-down because there are direct
177# references to the lower-level part-decoders from the high-level part-decoders.
178
179def getbyte(f, *args):
180 c = f.read(1)
181 if not c:
182 raise EOFError, 'in getbyte' + str(args)
183 return ord(c)
184
185def getword(f, *args):
186 getalign(f)
187 s = f.read(2)
188 if len(s) < 2:
189 raise EOFError, 'in getword' + str(args)
190 return (ord(s[0])<<8) | ord(s[1])
191
192def getlong(f, *args):
193 getalign(f)
194 s = f.read(4)
195 if len(s) < 4:
196 raise EOFError, 'in getlong' + str(args)
197 return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
198
199def getostype(f, *args):
200 getalign(f)
201 s = f.read(4)
202 if len(s) < 4:
203 raise EOFError, 'in getostype' + str(args)
204 return s
205
206def getpstr(f, *args):
207 c = f.read(1)
208 if len(c) < 1:
209 raise EOFError, 'in getpstr[1]' + str(args)
210 nbytes = ord(c)
211 if nbytes == 0: return ''
212 s = f.read(nbytes)
213 if len(s) < nbytes:
214 raise EOFError, 'in getpstr[2]' + str(args)
215 return s
216
217def getalign(f):
218 if f.tell() & 1:
219 c = f.read(1)
220 ##if c <> '\0':
221 ## print 'align:', `c`
222
223def getlist(f, description, getitem):
224 count = getword(f)
225 list = []
226 for i in range(count):
227 list.append(generic(getitem, f))
228 getalign(f)
229 return list
230
231def alt_generic(what, f, *args):
232 print "generic", `what`, args
233 res = vageneric(what, f, args)
234 print '->', `res`
235 return res
236
237def generic(what, f, *args):
238 if type(what) == types.FunctionType:
239 return apply(what, (f,) + args)
240 if type(what) == types.ListType:
241 record = []
242 for thing in what:
243 item = apply(generic, thing[:1] + (f,) + thing[1:])
244 record.append((thing[1], item))
245 return record
246 return "BAD GENERIC ARGS: %s" % `what`
247
248getdata = [
249 (getostype, "type"),
250 (getpstr, "description"),
251 (getword, "flags")
252 ]
253getargument = [
254 (getpstr, "name"),
255 (getostype, "keyword"),
256 (getdata, "what")
257 ]
258getevent = [
259 (getpstr, "name"),
260 (getpstr, "description"),
261 (getostype, "suite code"),
262 (getostype, "event code"),
263 (getdata, "returns"),
264 (getdata, "accepts"),
265 (getlist, "optional arguments", getargument)
266 ]
267getproperty = [
268 (getpstr, "name"),
269 (getostype, "code"),
270 (getdata, "what")
271 ]
272getelement = [
273 (getostype, "type"),
274 (getlist, "keyform", getostype)
275 ]
276getclass = [
277 (getpstr, "name"),
278 (getostype, "class code"),
279 (getpstr, "description"),
280 (getlist, "properties", getproperty),
281 (getlist, "elements", getelement)
282 ]
283getcomparison = [
284 (getpstr, "operator name"),
285 (getostype, "operator ID"),
286 (getpstr, "operator comment"),
287 ]
288getenumerator = [
289 (getpstr, "enumerator name"),
290 (getostype, "enumerator ID"),
291 (getpstr, "enumerator comment")
292 ]
293getenumeration = [
294 (getostype, "enumeration ID"),
295 (getlist, "enumerator", getenumerator)
296 ]
297getsuite = [
298 (getpstr, "suite name"),
299 (getpstr, "suite description"),
300 (getostype, "suite ID"),
301 (getword, "suite level"),
302 (getword, "suite version"),
303 (getlist, "events", getevent),
304 (getlist, "classes", getclass),
305 (getlist, "comparisons", getcomparison),
306 (getlist, "enumerations", getenumeration)
307 ]
308getaete = [
309 (getword, "major/minor version in BCD"),
310 (getword, "language code"),
311 (getword, "script code"),
312 (getlist, "suites", getsuite)
313 ]
314
Jack Jansen59cdbce2003-03-21 16:28:09 +0000315def compileaete(aete, resinfo, fname, output=None, basepkgname=None,
316 edit_modnames=None, creatorsignature=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000317 """Generate code for a full aete resource. fname passed for doc purposes"""
318 [version, language, script, suites] = aete
319 major, minor = divmod(version, 256)
Jack Jansen59cdbce2003-03-21 16:28:09 +0000320 if not creatorsignature:
321 creatorsignature, dummy = MacOS.GetCreatorAndType(fname)
Jack Jansen40926062002-03-30 23:43:04 +0000322 packagename = identify(os.path.splitext(os.path.basename(fname))[0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000323 if language:
324 packagename = packagename+'_lang%d'%language
325 if script:
326 packagename = packagename+'_script%d'%script
327 if len(packagename) > 27:
328 packagename = packagename[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000329 if output:
330 # XXXX Put this in site-packages if it isn't a full pathname?
331 if not os.path.exists(output):
332 os.mkdir(output)
333 pathname = output
334 else:
335 pathname = EasyDialogs.AskFolder(message='Create and select package folder for %s'%packagename,
336 defaultLocation=DEFAULT_USER_PACKAGEFOLDER)
Jack Jansendf976ca2003-01-26 20:35:47 +0000337 if not pathname:
Jack Jansen60762cb2000-08-17 22:11:45 +0000338 return
Jack Jansen60762cb2000-08-17 22:11:45 +0000339 packagename = os.path.split(os.path.normpath(pathname))[1]
Jack Jansen714caa02003-03-21 16:07:39 +0000340 if not basepkgname:
341 basepkgname = EasyDialogs.AskFolder(message='Package folder for base suite (usually StdSuites)',
342 defaultLocation=DEFAULT_STANDARD_PACKAGEFOLDER)
Jack Jansendf976ca2003-01-26 20:35:47 +0000343 if basepkgname:
344 dirname, basepkgname = os.path.split(os.path.normpath(basepkgname))
Jack Jansen714caa02003-03-21 16:07:39 +0000345 if dirname and not dirname in sys.path:
Jack Jansen60762cb2000-08-17 22:11:45 +0000346 sys.path.insert(0, dirname)
347 basepackage = __import__(basepkgname)
348 else:
349 basepackage = None
Jack Jansen60762cb2000-08-17 22:11:45 +0000350 suitelist = []
Jack Jansen12b2b762000-08-20 19:30:56 +0000351 allprecompinfo = []
352 allsuites = []
Jack Jansen5ccd8261995-07-17 11:43:20 +0000353 for suite in suites:
Jack Jansen714caa02003-03-21 16:07:39 +0000354 code, suite, pathname, modname, precompinfo = precompilesuite(suite, basepackage,
355 output=output, edit_modnames=edit_modnames)
Jack Jansen12b2b762000-08-20 19:30:56 +0000356 if not code:
357 continue
358 allprecompinfo = allprecompinfo + precompinfo
Jack Jansendf976ca2003-01-26 20:35:47 +0000359 suiteinfo = suite, pathname, modname
Jack Jansen12b2b762000-08-20 19:30:56 +0000360 suitelist.append((code, modname))
361 allsuites.append(suiteinfo)
362 for suiteinfo in allsuites:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000363 compilesuite(suiteinfo, major, minor, language, script, fname, basepackage,
364 allprecompinfo, interact=(edit_modnames is None))
Jack Jansen714caa02003-03-21 16:07:39 +0000365 initfilename = os.path.join(output, '__init__.py')
Jack Jansendf976ca2003-01-26 20:35:47 +0000366 fp = open(initfilename, 'w')
367 MacOS.SetCreatorAndType(initfilename, 'Pyth', 'TEXT')
Jack Jansen60762cb2000-08-17 22:11:45 +0000368 fp.write('"""\n')
369 fp.write("Package generated from %s\n"%fname)
Jack Jansen8b777672002-08-07 14:49:00 +0000370 if resinfo:
371 fp.write("Resource %s resid %d %s\n"%(ascii(resinfo[1]), resinfo[0], ascii(resinfo[2])))
Jack Jansen60762cb2000-08-17 22:11:45 +0000372 fp.write('"""\n')
373 fp.write('import aetools\n')
Jack Jansen6aa92c52000-08-20 21:59:03 +0000374 fp.write('Error = aetools.Error\n')
Jack Jansen60762cb2000-08-17 22:11:45 +0000375 for code, modname in suitelist:
376 fp.write("import %s\n" % modname)
377 fp.write("\n\n_code_to_module = {\n")
378 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000379 fp.write("\t'%s' : %s,\n"%(ascii(code), modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000380 fp.write("}\n\n")
381 fp.write("\n\n_code_to_fullname = {\n")
382 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000383 fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(ascii(code), packagename, modname, modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000384 fp.write("}\n\n")
385 for code, modname in suitelist:
386 fp.write("from %s import *\n"%modname)
Jack Jansen8b777672002-08-07 14:49:00 +0000387
388 # Generate property dicts and element dicts for all types declared in this module
Jack Jansen7e0bc112003-03-21 12:04:19 +0000389 fp.write("\ndef getbaseclasses(v):\n")
390 fp.write("\tif not v._propdict:\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000391 fp.write("\t\tv._propdict = {}\n")
392 fp.write("\t\tv._elemdict = {}\n")
Jack Jansen7e0bc112003-03-21 12:04:19 +0000393 fp.write("\t\tfor superclassname in getattr(v, '_superclassnames', []):\n")
394 fp.write("\t\t\tsuperclass = eval(superclassname)\n")
395 fp.write("\t\t\tgetbaseclasses(superclass)\n")
396 fp.write("\t\t\tv._propdict.update(getattr(superclass, '_propdict', {}))\n")
397 fp.write("\t\t\tv._elemdict.update(getattr(superclass, '_elemdict', {}))\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000398 fp.write("\t\tv._propdict.update(v._privpropdict)\n")
399 fp.write("\t\tv._elemdict.update(v._privelemdict)\n")
Jack Jansen21f67582002-08-07 15:44:53 +0000400 fp.write("\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000401 fp.write("import StdSuites\n")
402 if allprecompinfo:
403 fp.write("\n#\n# Set property and element dictionaries now that all classes have been defined\n#\n")
404 for codenamemapper in allprecompinfo:
405 for k, v in codenamemapper.getall('class'):
406 fp.write("getbaseclasses(%s)\n" % v)
407
408 # Generate a code-to-name mapper for all of the types (classes) declared in this module
409 if allprecompinfo:
410 fp.write("\n#\n# Indices of types declared in this module\n#\n")
411 fp.write("_classdeclarations = {\n")
412 for codenamemapper in allprecompinfo:
413 for k, v in codenamemapper.getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000414 fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen8b777672002-08-07 14:49:00 +0000415 fp.write("}\n")
416
Jack Jansen60762cb2000-08-17 22:11:45 +0000417 if suitelist:
418 fp.write("\n\nclass %s(%s_Events"%(packagename, suitelist[0][1]))
419 for code, modname in suitelist[1:]:
Jack Jansen12b2b762000-08-20 19:30:56 +0000420 fp.write(",\n\t\t%s_Events"%modname)
421 fp.write(",\n\t\taetools.TalkTo):\n")
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000422 fp.write("\t_signature = %s\n\n"%`creatorsignature`)
Jack Jansen8b777672002-08-07 14:49:00 +0000423 fp.write("\t_moduleName = '%s'\n\n"%packagename)
Jack Jansen60762cb2000-08-17 22:11:45 +0000424 fp.close()
Jack Jansen12b2b762000-08-20 19:30:56 +0000425
Jack Jansen714caa02003-03-21 16:07:39 +0000426def precompilesuite(suite, basepackage=None, edit_modnames=None, output=None):
Jack Jansen12b2b762000-08-20 19:30:56 +0000427 """Parse a single suite without generating the output. This step is needed
428 so we can resolve recursive references by suites to enums/comps/etc declared
429 in other suites"""
Jack Jansen5ccd8261995-07-17 11:43:20 +0000430 [name, desc, code, level, version, events, classes, comps, enums] = suite
431
432 modname = identify(name)
Jack Jansen60762cb2000-08-17 22:11:45 +0000433 if len(modname) > 28:
434 modname = modname[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000435 if edit_modnames is None:
436 pathname = EasyDialogs.AskFileForSave(message='Python output file',
437 savedFileName=modname+'.py')
438 else:
439 for old, new in edit_modnames:
440 if old == modname:
441 modname = new
442 if modname:
443 pathname = os.path.join(output, modname + '.py')
444 else:
445 pathname = None
Jack Jansendf976ca2003-01-26 20:35:47 +0000446 if not pathname:
Jack Jansen12b2b762000-08-20 19:30:56 +0000447 return None, None, None, None, None
448
Jack Jansen60762cb2000-08-17 22:11:45 +0000449 modname = os.path.splitext(os.path.split(pathname)[1])[0]
Jack Jansen12b2b762000-08-20 19:30:56 +0000450
451 if basepackage and basepackage._code_to_module.has_key(code):
452 # We are an extension of a baseclass (usually an application extending
453 # Standard_Suite or so). Import everything from our base module
454 basemodule = basepackage._code_to_module[code]
455 else:
456 # We are not an extension.
457 basemodule = None
458
459 enumsneeded = {}
460 for event in events:
461 findenumsinevent(event, enumsneeded)
462
Jack Jansen59cdbce2003-03-21 16:28:09 +0000463 objc = ObjectCompiler(None, basemodule, interact=(edit_modnames is None))
Jack Jansen12b2b762000-08-20 19:30:56 +0000464 for cls in classes:
465 objc.compileclass(cls)
466 for cls in classes:
467 objc.fillclasspropsandelems(cls)
468 for comp in comps:
469 objc.compilecomparison(comp)
470 for enum in enums:
471 objc.compileenumeration(enum)
472
473 for enum in enumsneeded.keys():
474 objc.checkforenum(enum)
475
476 objc.dumpindex()
477
478 precompinfo = objc.getprecompinfo(modname)
479
Jack Jansendf976ca2003-01-26 20:35:47 +0000480 return code, suite, pathname, modname, precompinfo
Jack Jansen12b2b762000-08-20 19:30:56 +0000481
Jack Jansen59cdbce2003-03-21 16:28:09 +0000482def compilesuite((suite, pathname, modname), major, minor, language, script,
483 fname, basepackage, precompinfo, interact=1):
Jack Jansen12b2b762000-08-20 19:30:56 +0000484 """Generate code for a single suite"""
485 [name, desc, code, level, version, events, classes, comps, enums] = suite
486
Jack Jansendf976ca2003-01-26 20:35:47 +0000487 fp = open(pathname, 'w')
488 MacOS.SetCreatorAndType(pathname, 'Pyth', 'TEXT')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000489
Jack Jansen8b777672002-08-07 14:49:00 +0000490 fp.write('"""Suite %s: %s\n' % (ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000491 fp.write("Level %d, version %d\n\n" % (level, version))
Jack Jansen8b777672002-08-07 14:49:00 +0000492 fp.write("Generated from %s\n"%ascii(fname))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000493 fp.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
494 (major, minor, language, script))
495 fp.write('"""\n\n')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000496
497 fp.write('import aetools\n')
498 fp.write('import MacOS\n\n')
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000499 fp.write("_code = %s\n\n"% `code`)
Jack Jansen60762cb2000-08-17 22:11:45 +0000500 if basepackage and basepackage._code_to_module.has_key(code):
501 # We are an extension of a baseclass (usually an application extending
502 # Standard_Suite or so). Import everything from our base module
Jack Jansen12b2b762000-08-20 19:30:56 +0000503 fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000504 basemodule = basepackage._code_to_module[code]
Jack Jansen7ebcbf52002-01-22 23:24:03 +0000505 elif basepackage and basepackage._code_to_module.has_key(code.lower()):
506 # This is needed by CodeWarrior and some others.
507 fp.write('from %s import *\n'%basepackage._code_to_fullname[code.lower()][0])
508 basemodule = basepackage._code_to_module[code.lower()]
Jack Jansen60762cb2000-08-17 22:11:45 +0000509 else:
510 # We are not an extension.
511 basemodule = None
512 compileclassheader(fp, modname, basemodule)
Jack Jansen66544221997-08-08 14:49:02 +0000513
514 enumsneeded = {}
Jack Jansen5ccd8261995-07-17 11:43:20 +0000515 if events:
516 for event in events:
Jack Jansen66544221997-08-08 14:49:02 +0000517 compileevent(fp, event, enumsneeded)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000518 else:
519 fp.write("\tpass\n\n")
Jack Jansen66544221997-08-08 14:49:02 +0000520
Jack Jansen59cdbce2003-03-21 16:28:09 +0000521 objc = ObjectCompiler(fp, basemodule, precompinfo, interact=interact)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000522 for cls in classes:
Jack Jansen66544221997-08-08 14:49:02 +0000523 objc.compileclass(cls)
524 for cls in classes:
525 objc.fillclasspropsandelems(cls)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000526 for comp in comps:
Jack Jansen66544221997-08-08 14:49:02 +0000527 objc.compilecomparison(comp)
528 for enum in enums:
529 objc.compileenumeration(enum)
530
531 for enum in enumsneeded.keys():
532 objc.checkforenum(enum)
533
534 objc.dumpindex()
Jack Jansen60762cb2000-08-17 22:11:45 +0000535
536 return code, modname
Jack Jansen5ccd8261995-07-17 11:43:20 +0000537
Jack Jansen60762cb2000-08-17 22:11:45 +0000538def compileclassheader(fp, name, module=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000539 """Generate class boilerplate"""
Jack Jansen60762cb2000-08-17 22:11:45 +0000540 classname = '%s_Events'%name
Jack Jansen12b2b762000-08-20 19:30:56 +0000541 if module:
542 modshortname = string.split(module.__name__, '.')[-1]
543 baseclassname = '%s_Events'%modshortname
544 fp.write("class %s(%s):\n\n"%(classname, baseclassname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000545 else:
546 fp.write("class %s:\n\n"%classname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000547
Jack Jansen66544221997-08-08 14:49:02 +0000548def compileevent(fp, event, enumsneeded):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000549 """Generate code for a single event"""
550 [name, desc, code, subcode, returns, accepts, arguments] = event
551 funcname = identify(name)
552 #
553 # generate name->keyword map
554 #
555 if arguments:
556 fp.write("\t_argmap_%s = {\n"%funcname)
557 for a in arguments:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000558 fp.write("\t\t%s : %s,\n"%(`identify(a[0])`, `a[1]`))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000559 fp.write("\t}\n\n")
560
561 #
562 # Generate function header
563 #
564 has_arg = (not is_null(accepts))
565 opt_arg = (has_arg and is_optional(accepts))
566
Jack Jansen84264771995-10-03 14:35:58 +0000567 fp.write("\tdef %s(self, "%funcname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000568 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000569 if not opt_arg:
570 fp.write("_object, ") # Include direct object, if it has one
571 else:
572 fp.write("_object=None, ") # Also include if it is optional
Jack Jansen5ccd8261995-07-17 11:43:20 +0000573 else:
Jack Jansen84264771995-10-03 14:35:58 +0000574 fp.write("_no_object=None, ") # For argument checking
575 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
Jack Jansen5ccd8261995-07-17 11:43:20 +0000576 #
577 # Generate doc string (important, since it may be the only
578 # available documentation, due to our name-remaping)
579 #
Jack Jansen21f67582002-08-07 15:44:53 +0000580 fp.write('\t\t"""%s: %s\n'%(ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000581 if has_arg:
582 fp.write("\t\tRequired argument: %s\n"%getdatadoc(accepts))
583 elif opt_arg:
584 fp.write("\t\tOptional argument: %s\n"%getdatadoc(accepts))
585 for arg in arguments:
586 fp.write("\t\tKeyword argument %s: %s\n"%(identify(arg[0]),
587 getdatadoc(arg[2])))
588 fp.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
589 if not is_null(returns):
590 fp.write("\t\tReturns: %s\n"%getdatadoc(returns))
591 fp.write('\t\t"""\n')
592 #
593 # Fiddle the args so everything ends up in 'arguments' dictionary
594 #
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000595 fp.write("\t\t_code = %s\n"% `code`)
596 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
Jack Jansen73215141995-10-09 23:09:23 +0000597 #
598 # Do keyword name substitution
599 #
600 if arguments:
601 fp.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname)
602 else:
603 fp.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
604 #
605 # Stuff required arg (if there is one) into arguments
606 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000607 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000608 fp.write("\t\t_arguments['----'] = _object\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000609 elif opt_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000610 fp.write("\t\tif _object:\n")
611 fp.write("\t\t\t_arguments['----'] = _object\n")
612 else:
613 fp.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000614 fp.write("\n")
615 #
Jack Jansen73215141995-10-09 23:09:23 +0000616 # Do enum-name substitution
Jack Jansen5ccd8261995-07-17 11:43:20 +0000617 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000618 for a in arguments:
619 if is_enum(a[2]):
620 kname = a[1]
621 ename = a[2][0]
Jack Jansena2408e91996-04-16 14:36:46 +0000622 if ename <> '****':
623 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000624 (`kname`, identify(ename)))
Jack Jansen66544221997-08-08 14:49:02 +0000625 enumsneeded[ename] = 1
Jack Jansen5ccd8261995-07-17 11:43:20 +0000626 fp.write("\n")
627 #
628 # Do the transaction
629 #
Jack Jansen84264771995-10-03 14:35:58 +0000630 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
631 fp.write("\t\t\t\t_arguments, _attributes)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000632 #
633 # Error handling
634 #
Jack Jansen18983532002-04-23 21:03:21 +0000635 fp.write("\t\tif _arguments.get('errn', 0):\n")
Jack Jansen977fbf21996-09-20 15:29:59 +0000636 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000637 fp.write("\t\t# XXXX Optionally decode result\n")
638 #
639 # Decode result
640 #
Jack Jansen84264771995-10-03 14:35:58 +0000641 fp.write("\t\tif _arguments.has_key('----'):\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000642 if is_enum(returns):
643 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
Jack Jansen84264771995-10-03 14:35:58 +0000644 fp.write("\t\t\treturn _arguments['----']\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000645 fp.write("\n")
646
647# print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
648# print "# returns", compiledata(returns)
649# print "# accepts", compiledata(accepts)
650# for arg in arguments:
651# compileargument(arg)
652
653def compileargument(arg):
654 [name, keyword, what] = arg
655 print "# %s (%s)" % (name, `keyword`), compiledata(what)
656
Jack Jansen12b2b762000-08-20 19:30:56 +0000657def findenumsinevent(event, enumsneeded):
658 """Find all enums for a single event"""
659 [name, desc, code, subcode, returns, accepts, arguments] = event
660 for a in arguments:
661 if is_enum(a[2]):
662 ename = a[2][0]
663 if ename <> '****':
664 enumsneeded[ename] = 1
665
666#
667# This class stores the code<->name translations for a single module. It is used
668# to keep the information while we're compiling the module, but we also keep these objects
669# around so if one suite refers to, say, an enum in another suite we know where to
670# find it. Finally, if we really can't find a code, the user can add modules by
671# hand.
672#
673class CodeNameMapper:
674
Jack Jansen59cdbce2003-03-21 16:28:09 +0000675 def __init__(self, interact=1):
Jack Jansen12b2b762000-08-20 19:30:56 +0000676 self.code2name = {
677 "property" : {},
678 "class" : {},
679 "enum" : {},
680 "comparison" : {},
681 }
682 self.name2code = {
683 "property" : {},
684 "class" : {},
685 "enum" : {},
686 "comparison" : {},
687 }
688 self.modulename = None
689 self.star_imported = 0
Jack Jansen59cdbce2003-03-21 16:28:09 +0000690 self.can_interact = interact
Jack Jansen12b2b762000-08-20 19:30:56 +0000691
692 def addnamecode(self, type, name, code):
693 self.name2code[type][name] = code
694 if not self.code2name[type].has_key(code):
695 self.code2name[type][code] = name
696
697 def hasname(self, type, name):
698 return self.name2code[type].has_key(name)
699
700 def hascode(self, type, code):
701 return self.code2name[type].has_key(code)
702
703 def findcodename(self, type, code):
704 if not self.hascode(type, code):
705 return None, None, None
706 name = self.code2name[type][code]
707 if self.modulename and not self.star_imported:
708 qualname = '%s.%s'%(self.modulename, name)
709 else:
710 qualname = name
711 return name, qualname, self.modulename
712
713 def getall(self, type):
714 return self.code2name[type].items()
715
716 def addmodule(self, module, name, star_imported):
717 self.modulename = name
718 self.star_imported = star_imported
719 for code, name in module._propdeclarations.items():
720 self.addnamecode('property', name, code)
721 for code, name in module._classdeclarations.items():
722 self.addnamecode('class', name, code)
723 for code in module._enumdeclarations.keys():
724 self.addnamecode('enum', '_Enum_'+identify(code), code)
725 for code, name in module._compdeclarations.items():
726 self.addnamecode('comparison', name, code)
727
728 def prepareforexport(self, name=None):
729 if not self.modulename:
730 self.modulename = name
731 return self
732
Jack Jansen66544221997-08-08 14:49:02 +0000733class ObjectCompiler:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000734 def __init__(self, fp, basesuite=None, othernamemappers=None, interact=1):
Jack Jansen66544221997-08-08 14:49:02 +0000735 self.fp = fp
Jack Jansen60762cb2000-08-17 22:11:45 +0000736 self.basesuite = basesuite
Jack Jansen59cdbce2003-03-21 16:28:09 +0000737 self.can_interact = interact
738 self.namemappers = [CodeNameMapper(self.can_interact)]
Jack Jansen12b2b762000-08-20 19:30:56 +0000739 if othernamemappers:
740 self.othernamemappers = othernamemappers[:]
741 else:
742 self.othernamemappers = []
743 if basesuite:
Jack Jansen59cdbce2003-03-21 16:28:09 +0000744 basemapper = CodeNameMapper(self.can_interact)
Jack Jansen12b2b762000-08-20 19:30:56 +0000745 basemapper.addmodule(basesuite, '', 1)
746 self.namemappers.append(basemapper)
747
748 def getprecompinfo(self, modname):
749 list = []
750 for mapper in self.namemappers:
751 emapper = mapper.prepareforexport(modname)
752 if emapper:
753 list.append(emapper)
754 return list
Jack Jansen66544221997-08-08 14:49:02 +0000755
756 def findcodename(self, type, code):
757 while 1:
Jack Jansen12b2b762000-08-20 19:30:56 +0000758 # First try: check whether we already know about this code.
759 for mapper in self.namemappers:
760 if mapper.hascode(type, code):
761 return mapper.findcodename(type, code)
762 # Second try: maybe one of the other modules knows about it.
763 for mapper in self.othernamemappers:
764 if mapper.hascode(type, code):
765 self.othernamemappers.remove(mapper)
766 self.namemappers.append(mapper)
767 if self.fp:
768 self.fp.write("import %s\n"%mapper.modulename)
769 break
770 else:
771 # If all this has failed we ask the user for a guess on where it could
772 # be and retry.
773 if self.fp:
774 m = self.askdefinitionmodule(type, code)
775 else:
776 m = None
777 if not m: return None, None, None
Jack Jansen59cdbce2003-03-21 16:28:09 +0000778 mapper = CodeNameMapper(self.can_interact)
Jack Jansen12b2b762000-08-20 19:30:56 +0000779 mapper.addmodule(m, m.__name__, 0)
780 self.namemappers.append(mapper)
Jack Jansen66544221997-08-08 14:49:02 +0000781
782 def askdefinitionmodule(self, type, code):
Jack Jansen59cdbce2003-03-21 16:28:09 +0000783 if not self.can_interact:
784 print "** No definition for %s '%s' found" % (type, code)
785 return None
Jack Jansendf976ca2003-01-26 20:35:47 +0000786 path = EasyDialogs.AskFileForSave(message='Where is %s %s declared?'%(type, code))
787 if not path: return
788 path, file = os.path.split(path)
Jack Jansen66544221997-08-08 14:49:02 +0000789 modname = os.path.splitext(file)[0]
790 if not path in sys.path:
791 sys.path.insert(0, path)
792 m = __import__(modname)
793 self.fp.write("import %s\n"%modname)
794 return m
795
796 def compileclass(self, cls):
797 [name, code, desc, properties, elements] = cls
798 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000799 if self.namemappers[0].hascode('class', code):
Jack Jansen66544221997-08-08 14:49:02 +0000800 # plural forms and such
Jack Jansen12b2b762000-08-20 19:30:56 +0000801 othername, dummy, dummy = self.namemappers[0].findcodename('class', code)
802 if self.fp:
803 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000804 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000805 if self.fp:
806 self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000807 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(desc)))
Jack Jansen12b2b762000-08-20 19:30:56 +0000808 self.fp.write('\twant = %s\n' % `code`)
809 self.namemappers[0].addnamecode('class', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000810 for prop in properties:
811 self.compileproperty(prop)
812 for elem in elements:
813 self.compileelement(elem)
814
815 def compileproperty(self, prop):
816 [name, code, what] = prop
817 if code == 'c@#!':
818 # Something silly with plurals. Skip it.
819 return
820 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000821 if self.namemappers[0].hascode('property', code):
Jack Jansen2eda2442000-08-20 19:42:52 +0000822 # plural forms and such
823 othername, dummy, dummy = self.namemappers[0].findcodename('property', code)
Jack Jansen9d6d2c02000-08-22 20:34:35 +0000824 if pname == othername:
825 return
Jack Jansen12b2b762000-08-20 19:30:56 +0000826 if self.fp:
Jack Jansen2eda2442000-08-20 19:42:52 +0000827 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000828 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000829 if self.fp:
830 self.fp.write("class %s(aetools.NProperty):\n" % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000831 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(what[1])))
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000832 self.fp.write("\twhich = %s\n" % `code`)
833 self.fp.write("\twant = %s\n" % `what[0]`)
Jack Jansen2eda2442000-08-20 19:42:52 +0000834 self.namemappers[0].addnamecode('property', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000835
836 def compileelement(self, elem):
837 [code, keyform] = elem
Jack Jansen12b2b762000-08-20 19:30:56 +0000838 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000839 self.fp.write("# element %s as %s\n" % (`code`, keyform))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000840
Jack Jansen66544221997-08-08 14:49:02 +0000841 def fillclasspropsandelems(self, cls):
842 [name, code, desc, properties, elements] = cls
843 cname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000844 if self.namemappers[0].hascode('class', code) and \
845 self.namemappers[0].findcodename('class', code)[0] != cname:
Jack Jansen66544221997-08-08 14:49:02 +0000846 # This is an other name (plural or so) for something else. Skip.
847 return
848 plist = []
849 elist = []
Jack Jansen8b777672002-08-07 14:49:00 +0000850 superclasses = []
Jack Jansen66544221997-08-08 14:49:02 +0000851 for prop in properties:
852 [pname, pcode, what] = prop
Jack Jansen8b777672002-08-07 14:49:00 +0000853 if pcode == "c@#^":
854 superclasses.append(what)
Jack Jansen66544221997-08-08 14:49:02 +0000855 if pcode == 'c@#!':
856 continue
857 pname = identify(pname)
858 plist.append(pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000859
860 superclassnames = []
861 for superclass in superclasses:
862 superId, superDesc, dummy = superclass
863 superclassname, fullyqualifiedname, module = self.findcodename("class", superId)
864 superclassnames.append(superclassname)
865
866 if self.fp:
867 self.fp.write("%s._superclassnames = %s\n"%(cname, `superclassnames`))
868
Jack Jansen66544221997-08-08 14:49:02 +0000869 for elem in elements:
870 [ecode, keyform] = elem
871 if ecode == 'c@#!':
872 continue
873 name, ename, module = self.findcodename('class', ecode)
874 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000875 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000876 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
Jack Jansen66544221997-08-08 14:49:02 +0000877 else:
Jack Jansen34d11f02000-03-07 23:40:13 +0000878 elist.append((name, ename))
Jack Jansen12b2b762000-08-20 19:30:56 +0000879
880 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000881 self.fp.write("%s._privpropdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000882 for n in plist:
883 self.fp.write("\t'%s' : %s,\n"%(n, n))
884 self.fp.write("}\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000885 self.fp.write("%s._privelemdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000886 for n, fulln in elist:
887 self.fp.write("\t'%s' : %s,\n"%(n, fulln))
888 self.fp.write("}\n")
Jack Jansen66544221997-08-08 14:49:02 +0000889
890 def compilecomparison(self, comp):
891 [name, code, comment] = comp
892 iname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000893 self.namemappers[0].addnamecode('comparison', iname, code)
894 if self.fp:
895 self.fp.write("class %s(aetools.NComparison):\n" % iname)
Jack Jansen8b777672002-08-07 14:49:00 +0000896 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(comment)))
Jack Jansen66544221997-08-08 14:49:02 +0000897
898 def compileenumeration(self, enum):
899 [code, items] = enum
900 name = "_Enum_%s" % identify(code)
Jack Jansen12b2b762000-08-20 19:30:56 +0000901 if self.fp:
902 self.fp.write("%s = {\n" % name)
903 for item in items:
904 self.compileenumerator(item)
905 self.fp.write("}\n\n")
906 self.namemappers[0].addnamecode('enum', name, code)
Jack Jansen66544221997-08-08 14:49:02 +0000907 return code
908
909 def compileenumerator(self, item):
910 [name, code, desc] = item
Jack Jansen21f67582002-08-07 15:44:53 +0000911 self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, ascii(desc)))
Jack Jansen66544221997-08-08 14:49:02 +0000912
913 def checkforenum(self, enum):
914 """This enum code is used by an event. Make sure it's available"""
915 name, fullname, module = self.findcodename('enum', enum)
916 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000917 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000918 self.fp.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum), ascii(enum)))
Jack Jansen66544221997-08-08 14:49:02 +0000919 return
920 if module:
Jack Jansen12b2b762000-08-20 19:30:56 +0000921 if self.fp:
922 self.fp.write("from %s import %s\n"%(module, name))
Jack Jansen66544221997-08-08 14:49:02 +0000923
924 def dumpindex(self):
Jack Jansen12b2b762000-08-20 19:30:56 +0000925 if not self.fp:
926 return
Jack Jansen66544221997-08-08 14:49:02 +0000927 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
928 self.fp.write("_classdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000929 for k, v in self.namemappers[0].getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000930 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000931 self.fp.write("}\n")
932 self.fp.write("\n_propdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000933 for k, v in self.namemappers[0].getall('property'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000934 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000935 self.fp.write("}\n")
936 self.fp.write("\n_compdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000937 for k, v in self.namemappers[0].getall('comparison'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000938 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000939 self.fp.write("}\n")
940 self.fp.write("\n_enumdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000941 for k, v in self.namemappers[0].getall('enum'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000942 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000943 self.fp.write("}\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000944
945def compiledata(data):
946 [type, description, flags] = data
947 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
948
949def is_null(data):
950 return data[0] == 'null'
951
952def is_optional(data):
953 return (data[2] & 0x8000)
954
955def is_enum(data):
956 return (data[2] & 0x2000)
957
958def getdatadoc(data):
959 [type, descr, flags] = data
960 if descr:
Jack Jansen8b777672002-08-07 14:49:00 +0000961 return ascii(descr)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000962 if type == '****':
963 return 'anything'
964 if type == 'obj ':
965 return 'an AE object reference'
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000966 return "undocumented, typecode %s"%`type`
Jack Jansen5ccd8261995-07-17 11:43:20 +0000967
968dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
969def compiledataflags(flags):
970 bits = []
971 for i in range(16):
972 if flags & (1<<i):
973 if i in dataflagdict.keys():
974 bits.append(dataflagdict[i])
975 else:
976 bits.append(`i`)
977 return '[%s]' % string.join(bits)
978
Jack Jansen8b777672002-08-07 14:49:00 +0000979def ascii(str):
980 """Return a string with all non-ascii characters hex-encoded"""
981 if type(str) != type(''):
982 return map(ascii, str)
983 rv = ''
984 for c in str:
985 if c in ('\t', '\n', '\r') or ' ' <= c < chr(0x7f):
986 rv = rv + c
987 else:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000988 rv = rv + '\\' + 'x%02.2x' % ord(c)
Jack Jansen8b777672002-08-07 14:49:00 +0000989 return rv
990
Jack Jansen5ccd8261995-07-17 11:43:20 +0000991def identify(str):
992 """Turn any string into an identifier:
993 - replace space by _
994 - replace other illegal chars by _xx_ (hex code)
995 - prepend _ if the result is a python keyword
996 """
Jack Jansen66544221997-08-08 14:49:02 +0000997 if not str:
Jack Jansen21f67582002-08-07 15:44:53 +0000998 return "empty_ae_name_"
Jack Jansen5ccd8261995-07-17 11:43:20 +0000999 rv = ''
Fred Drake79e75e12001-07-20 19:05:50 +00001000 ok = string.ascii_letters + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +00001001 ok2 = ok + string.digits
1002 for c in str:
1003 if c in ok:
1004 rv = rv + c
1005 elif c == ' ':
1006 rv = rv + '_'
1007 else:
1008 rv = rv + '_%02.2x_'%ord(c)
1009 ok = ok2
Jack Jansenb2ecc2c2002-01-24 22:44:07 +00001010 if keyword.iskeyword(rv):
Jack Jansen21f67582002-08-07 15:44:53 +00001011 rv = rv + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +00001012 return rv
1013
1014# Call the main program
1015
1016if __name__ == '__main__':
1017 main()
1018 sys.exit(1)