blob: fd55db39ce7f07e14028385d11118f5ef99bf0b6 [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)
36""")
37 sys.exit(1)
38
Jack Jansen5ccd8261995-07-17 11:43:20 +000039def main():
Jack Jansen40926062002-03-30 23:43:04 +000040 if len(sys.argv) > 1:
Jack Jansen714caa02003-03-21 16:07:39 +000041 SHORTOPTS = "rb:o:e:"
42 LONGOPTS = ("resource", "base=", "output=", "edit=")
43 try:
44 opts, args = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS)
45 except getopt.GetoptError:
46 usage()
47
48 process_func = processfile
49 basepkgname = 'StdSuites'
50 output = None
51 edit_modnames = []
52
53 for o, a in opts:
54 if o in ('-r', '--resource'):
55 process_func = processfile_fromresource
56 if o in ('-b', '--base'):
57 basepkgname = a
58 if o in ('-o', '--output'):
59 output = a
60 if o in ('-e', '--edit'):
61 split = a.split('=')
62 if len(split) != 2:
63 usage()
64 edit_modnames.append(split)
65
66 if output and len(args) > 1:
67 sys.stderr.write("%s: cannot specify --output with multiple inputs\n" % sys.argv[0])
68 sys.exit(1)
69
70 for filename in args:
71 process_func(filename, output=output, basepkgname=basepkgname,
72 edit_modnames=edit_modnames)
Jack Jansen40926062002-03-30 23:43:04 +000073 else:
Jack Jansenfa1bf1c2003-03-06 23:04:38 +000074 # The dialogOptionFlags below allows selection of .app bundles.
75 filename = EasyDialogs.AskFileForOpen(
76 message='Select scriptable application',
77 dialogOptionFlags=0x1056)
Jack Jansendf976ca2003-01-26 20:35:47 +000078 if not filename:
Jack Jansen40926062002-03-30 23:43:04 +000079 sys.exit(0)
Jack Jansenfa1bf1c2003-03-06 23:04:38 +000080 try:
81 processfile(filename)
82 except MacOS.Error, arg:
83 print "Error getting terminology:", arg
84 print "Retry, manually parsing resources"
85 processfile_fromresource(filename)
Jack Jansen5ccd8261995-07-17 11:43:20 +000086
Jack Jansen714caa02003-03-21 16:07:39 +000087def processfile_fromresource(fullname, output=None, basepkgname=None, edit_modnames=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +000088 """Process all resources in a single file"""
89 cur = CurResFile()
Jack Jansen40926062002-03-30 23:43:04 +000090 print "Processing", fullname
91 rf = macresource.open_pathname(fullname)
Jack Jansen5ccd8261995-07-17 11:43:20 +000092 try:
93 UseResFile(rf)
94 resources = []
95 for i in range(Count1Resources('aete')):
96 res = Get1IndResource('aete', 1+i)
97 resources.append(res)
98 for i in range(Count1Resources('aeut')):
99 res = Get1IndResource('aeut', 1+i)
100 resources.append(res)
101 print "\nLISTING aete+aeut RESOURCES IN", `fullname`
Jack Jansen60762cb2000-08-17 22:11:45 +0000102 aetelist = []
Jack Jansen5ccd8261995-07-17 11:43:20 +0000103 for res in resources:
104 print "decoding", res.GetResInfo(), "..."
105 data = res.data
106 aete = decode(data)
Jack Jansen60762cb2000-08-17 22:11:45 +0000107 aetelist.append((aete, res.GetResInfo()))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000108 finally:
109 if rf <> cur:
110 CloseResFile(rf)
111 UseResFile(cur)
Jack Jansen60762cb2000-08-17 22:11:45 +0000112 # switch back (needed for dialogs in Python)
113 UseResFile(cur)
Jack Jansen714caa02003-03-21 16:07:39 +0000114 compileaetelist(aetelist, fullname, output=output,
115 basepkgname=basepkgname, edit_modnames=edit_modnames)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000116
Jack Jansen714caa02003-03-21 16:07:39 +0000117def processfile(fullname, output=None, basepkgname=None, edit_modnames=None):
Jack Jansenfa1bf1c2003-03-06 23:04:38 +0000118 """Ask an application for its terminology and process that"""
119 aedescobj, launched = OSATerminology.GetSysTerminology(fullname)
120 if launched:
121 print "Launched", fullname
122 raw = aetools.unpack(aedescobj)
123 if not raw:
124 print 'Unpack returned empty value:', raw
125 return
126 if not raw[0].data:
127 print 'Unpack returned value without data:', raw
128 return
129 aedata = raw[0]
130 aete = decode(aedata.data)
Jack Jansen714caa02003-03-21 16:07:39 +0000131 compileaete(aete, None, fullname, output=output, basepkgname=basepkgname)
Jack Jansenfa1bf1c2003-03-06 23:04:38 +0000132
Jack Jansen714caa02003-03-21 16:07:39 +0000133def compileaetelist(aetelist, fullname, output=None, basepkgname=None, edit_modnames=None):
Jack Jansen60762cb2000-08-17 22:11:45 +0000134 for aete, resinfo in aetelist:
Jack Jansen714caa02003-03-21 16:07:39 +0000135 compileaete(aete, resinfo, fullname, output=output,
136 basepkgname=basepkgname, edit_modnames=edit_modnames)
Jack Jansen60762cb2000-08-17 22:11:45 +0000137
Jack Jansen5ccd8261995-07-17 11:43:20 +0000138def decode(data):
139 """Decode a resource into a python data structure"""
140 f = StringIO.StringIO(data)
141 aete = generic(getaete, f)
142 aete = simplify(aete)
143 processed = f.tell()
144 unprocessed = len(f.read())
145 total = f.tell()
146 if unprocessed:
147 sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
148 (processed, unprocessed, total))
149 return aete
150
151def simplify(item):
152 """Recursively replace singleton tuples by their constituent item"""
153 if type(item) is types.ListType:
154 return map(simplify, item)
155 elif type(item) == types.TupleType and len(item) == 2:
156 return simplify(item[1])
157 else:
158 return item
159
160
161# Here follows the aete resource decoder.
162# It is presented bottom-up instead of top-down because there are direct
163# references to the lower-level part-decoders from the high-level part-decoders.
164
165def getbyte(f, *args):
166 c = f.read(1)
167 if not c:
168 raise EOFError, 'in getbyte' + str(args)
169 return ord(c)
170
171def getword(f, *args):
172 getalign(f)
173 s = f.read(2)
174 if len(s) < 2:
175 raise EOFError, 'in getword' + str(args)
176 return (ord(s[0])<<8) | ord(s[1])
177
178def getlong(f, *args):
179 getalign(f)
180 s = f.read(4)
181 if len(s) < 4:
182 raise EOFError, 'in getlong' + str(args)
183 return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
184
185def getostype(f, *args):
186 getalign(f)
187 s = f.read(4)
188 if len(s) < 4:
189 raise EOFError, 'in getostype' + str(args)
190 return s
191
192def getpstr(f, *args):
193 c = f.read(1)
194 if len(c) < 1:
195 raise EOFError, 'in getpstr[1]' + str(args)
196 nbytes = ord(c)
197 if nbytes == 0: return ''
198 s = f.read(nbytes)
199 if len(s) < nbytes:
200 raise EOFError, 'in getpstr[2]' + str(args)
201 return s
202
203def getalign(f):
204 if f.tell() & 1:
205 c = f.read(1)
206 ##if c <> '\0':
207 ## print 'align:', `c`
208
209def getlist(f, description, getitem):
210 count = getword(f)
211 list = []
212 for i in range(count):
213 list.append(generic(getitem, f))
214 getalign(f)
215 return list
216
217def alt_generic(what, f, *args):
218 print "generic", `what`, args
219 res = vageneric(what, f, args)
220 print '->', `res`
221 return res
222
223def generic(what, f, *args):
224 if type(what) == types.FunctionType:
225 return apply(what, (f,) + args)
226 if type(what) == types.ListType:
227 record = []
228 for thing in what:
229 item = apply(generic, thing[:1] + (f,) + thing[1:])
230 record.append((thing[1], item))
231 return record
232 return "BAD GENERIC ARGS: %s" % `what`
233
234getdata = [
235 (getostype, "type"),
236 (getpstr, "description"),
237 (getword, "flags")
238 ]
239getargument = [
240 (getpstr, "name"),
241 (getostype, "keyword"),
242 (getdata, "what")
243 ]
244getevent = [
245 (getpstr, "name"),
246 (getpstr, "description"),
247 (getostype, "suite code"),
248 (getostype, "event code"),
249 (getdata, "returns"),
250 (getdata, "accepts"),
251 (getlist, "optional arguments", getargument)
252 ]
253getproperty = [
254 (getpstr, "name"),
255 (getostype, "code"),
256 (getdata, "what")
257 ]
258getelement = [
259 (getostype, "type"),
260 (getlist, "keyform", getostype)
261 ]
262getclass = [
263 (getpstr, "name"),
264 (getostype, "class code"),
265 (getpstr, "description"),
266 (getlist, "properties", getproperty),
267 (getlist, "elements", getelement)
268 ]
269getcomparison = [
270 (getpstr, "operator name"),
271 (getostype, "operator ID"),
272 (getpstr, "operator comment"),
273 ]
274getenumerator = [
275 (getpstr, "enumerator name"),
276 (getostype, "enumerator ID"),
277 (getpstr, "enumerator comment")
278 ]
279getenumeration = [
280 (getostype, "enumeration ID"),
281 (getlist, "enumerator", getenumerator)
282 ]
283getsuite = [
284 (getpstr, "suite name"),
285 (getpstr, "suite description"),
286 (getostype, "suite ID"),
287 (getword, "suite level"),
288 (getword, "suite version"),
289 (getlist, "events", getevent),
290 (getlist, "classes", getclass),
291 (getlist, "comparisons", getcomparison),
292 (getlist, "enumerations", getenumeration)
293 ]
294getaete = [
295 (getword, "major/minor version in BCD"),
296 (getword, "language code"),
297 (getword, "script code"),
298 (getlist, "suites", getsuite)
299 ]
300
Jack Jansen714caa02003-03-21 16:07:39 +0000301def compileaete(aete, resinfo, fname, output=None, basepkgname=None, edit_modnames=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000302 """Generate code for a full aete resource. fname passed for doc purposes"""
303 [version, language, script, suites] = aete
304 major, minor = divmod(version, 256)
Jack Jansendf976ca2003-01-26 20:35:47 +0000305 creatorsignature, dummy = MacOS.GetCreatorAndType(fname)
Jack Jansen40926062002-03-30 23:43:04 +0000306 packagename = identify(os.path.splitext(os.path.basename(fname))[0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000307 if language:
308 packagename = packagename+'_lang%d'%language
309 if script:
310 packagename = packagename+'_script%d'%script
311 if len(packagename) > 27:
312 packagename = packagename[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000313 if output:
314 # XXXX Put this in site-packages if it isn't a full pathname?
315 if not os.path.exists(output):
316 os.mkdir(output)
317 pathname = output
318 else:
319 pathname = EasyDialogs.AskFolder(message='Create and select package folder for %s'%packagename,
320 defaultLocation=DEFAULT_USER_PACKAGEFOLDER)
Jack Jansendf976ca2003-01-26 20:35:47 +0000321 if not pathname:
Jack Jansen60762cb2000-08-17 22:11:45 +0000322 return
Jack Jansen60762cb2000-08-17 22:11:45 +0000323 packagename = os.path.split(os.path.normpath(pathname))[1]
Jack Jansen714caa02003-03-21 16:07:39 +0000324 if not basepkgname:
325 basepkgname = EasyDialogs.AskFolder(message='Package folder for base suite (usually StdSuites)',
326 defaultLocation=DEFAULT_STANDARD_PACKAGEFOLDER)
Jack Jansendf976ca2003-01-26 20:35:47 +0000327 if basepkgname:
328 dirname, basepkgname = os.path.split(os.path.normpath(basepkgname))
Jack Jansen714caa02003-03-21 16:07:39 +0000329 if dirname and not dirname in sys.path:
Jack Jansen60762cb2000-08-17 22:11:45 +0000330 sys.path.insert(0, dirname)
331 basepackage = __import__(basepkgname)
332 else:
333 basepackage = None
Jack Jansen60762cb2000-08-17 22:11:45 +0000334 suitelist = []
Jack Jansen12b2b762000-08-20 19:30:56 +0000335 allprecompinfo = []
336 allsuites = []
Jack Jansen5ccd8261995-07-17 11:43:20 +0000337 for suite in suites:
Jack Jansen714caa02003-03-21 16:07:39 +0000338 code, suite, pathname, modname, precompinfo = precompilesuite(suite, basepackage,
339 output=output, edit_modnames=edit_modnames)
Jack Jansen12b2b762000-08-20 19:30:56 +0000340 if not code:
341 continue
342 allprecompinfo = allprecompinfo + precompinfo
Jack Jansendf976ca2003-01-26 20:35:47 +0000343 suiteinfo = suite, pathname, modname
Jack Jansen12b2b762000-08-20 19:30:56 +0000344 suitelist.append((code, modname))
345 allsuites.append(suiteinfo)
346 for suiteinfo in allsuites:
347 compilesuite(suiteinfo, major, minor, language, script, fname, basepackage, allprecompinfo)
Jack Jansen714caa02003-03-21 16:07:39 +0000348 initfilename = os.path.join(output, '__init__.py')
Jack Jansendf976ca2003-01-26 20:35:47 +0000349 fp = open(initfilename, 'w')
350 MacOS.SetCreatorAndType(initfilename, 'Pyth', 'TEXT')
Jack Jansen60762cb2000-08-17 22:11:45 +0000351 fp.write('"""\n')
352 fp.write("Package generated from %s\n"%fname)
Jack Jansen8b777672002-08-07 14:49:00 +0000353 if resinfo:
354 fp.write("Resource %s resid %d %s\n"%(ascii(resinfo[1]), resinfo[0], ascii(resinfo[2])))
Jack Jansen60762cb2000-08-17 22:11:45 +0000355 fp.write('"""\n')
356 fp.write('import aetools\n')
Jack Jansen6aa92c52000-08-20 21:59:03 +0000357 fp.write('Error = aetools.Error\n')
Jack Jansen60762cb2000-08-17 22:11:45 +0000358 for code, modname in suitelist:
359 fp.write("import %s\n" % modname)
360 fp.write("\n\n_code_to_module = {\n")
361 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000362 fp.write("\t'%s' : %s,\n"%(ascii(code), modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000363 fp.write("}\n\n")
364 fp.write("\n\n_code_to_fullname = {\n")
365 for code, modname in suitelist:
Jack Jansen8b777672002-08-07 14:49:00 +0000366 fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(ascii(code), packagename, modname, modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000367 fp.write("}\n\n")
368 for code, modname in suitelist:
369 fp.write("from %s import *\n"%modname)
Jack Jansen8b777672002-08-07 14:49:00 +0000370
371 # Generate property dicts and element dicts for all types declared in this module
Jack Jansen7e0bc112003-03-21 12:04:19 +0000372 fp.write("\ndef getbaseclasses(v):\n")
373 fp.write("\tif not v._propdict:\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000374 fp.write("\t\tv._propdict = {}\n")
375 fp.write("\t\tv._elemdict = {}\n")
Jack Jansen7e0bc112003-03-21 12:04:19 +0000376 fp.write("\t\tfor superclassname in getattr(v, '_superclassnames', []):\n")
377 fp.write("\t\t\tsuperclass = eval(superclassname)\n")
378 fp.write("\t\t\tgetbaseclasses(superclass)\n")
379 fp.write("\t\t\tv._propdict.update(getattr(superclass, '_propdict', {}))\n")
380 fp.write("\t\t\tv._elemdict.update(getattr(superclass, '_elemdict', {}))\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000381 fp.write("\t\tv._propdict.update(v._privpropdict)\n")
382 fp.write("\t\tv._elemdict.update(v._privelemdict)\n")
Jack Jansen21f67582002-08-07 15:44:53 +0000383 fp.write("\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000384 fp.write("import StdSuites\n")
385 if allprecompinfo:
386 fp.write("\n#\n# Set property and element dictionaries now that all classes have been defined\n#\n")
387 for codenamemapper in allprecompinfo:
388 for k, v in codenamemapper.getall('class'):
389 fp.write("getbaseclasses(%s)\n" % v)
390
391 # Generate a code-to-name mapper for all of the types (classes) declared in this module
392 if allprecompinfo:
393 fp.write("\n#\n# Indices of types declared in this module\n#\n")
394 fp.write("_classdeclarations = {\n")
395 for codenamemapper in allprecompinfo:
396 for k, v in codenamemapper.getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000397 fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen8b777672002-08-07 14:49:00 +0000398 fp.write("}\n")
399
Jack Jansen60762cb2000-08-17 22:11:45 +0000400 if suitelist:
401 fp.write("\n\nclass %s(%s_Events"%(packagename, suitelist[0][1]))
402 for code, modname in suitelist[1:]:
Jack Jansen12b2b762000-08-20 19:30:56 +0000403 fp.write(",\n\t\t%s_Events"%modname)
404 fp.write(",\n\t\taetools.TalkTo):\n")
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000405 fp.write("\t_signature = %s\n\n"%`creatorsignature`)
Jack Jansen8b777672002-08-07 14:49:00 +0000406 fp.write("\t_moduleName = '%s'\n\n"%packagename)
Jack Jansen60762cb2000-08-17 22:11:45 +0000407 fp.close()
Jack Jansen12b2b762000-08-20 19:30:56 +0000408
Jack Jansen714caa02003-03-21 16:07:39 +0000409def precompilesuite(suite, basepackage=None, edit_modnames=None, output=None):
Jack Jansen12b2b762000-08-20 19:30:56 +0000410 """Parse a single suite without generating the output. This step is needed
411 so we can resolve recursive references by suites to enums/comps/etc declared
412 in other suites"""
Jack Jansen5ccd8261995-07-17 11:43:20 +0000413 [name, desc, code, level, version, events, classes, comps, enums] = suite
414
415 modname = identify(name)
Jack Jansen60762cb2000-08-17 22:11:45 +0000416 if len(modname) > 28:
417 modname = modname[:27]
Jack Jansen714caa02003-03-21 16:07:39 +0000418 if edit_modnames is None:
419 pathname = EasyDialogs.AskFileForSave(message='Python output file',
420 savedFileName=modname+'.py')
421 else:
422 for old, new in edit_modnames:
423 if old == modname:
424 modname = new
425 if modname:
426 pathname = os.path.join(output, modname + '.py')
427 else:
428 pathname = None
Jack Jansendf976ca2003-01-26 20:35:47 +0000429 if not pathname:
Jack Jansen12b2b762000-08-20 19:30:56 +0000430 return None, None, None, None, None
431
Jack Jansen60762cb2000-08-17 22:11:45 +0000432 modname = os.path.splitext(os.path.split(pathname)[1])[0]
Jack Jansen12b2b762000-08-20 19:30:56 +0000433
434 if basepackage and basepackage._code_to_module.has_key(code):
435 # We are an extension of a baseclass (usually an application extending
436 # Standard_Suite or so). Import everything from our base module
437 basemodule = basepackage._code_to_module[code]
438 else:
439 # We are not an extension.
440 basemodule = None
441
442 enumsneeded = {}
443 for event in events:
444 findenumsinevent(event, enumsneeded)
445
446 objc = ObjectCompiler(None, basemodule)
447 for cls in classes:
448 objc.compileclass(cls)
449 for cls in classes:
450 objc.fillclasspropsandelems(cls)
451 for comp in comps:
452 objc.compilecomparison(comp)
453 for enum in enums:
454 objc.compileenumeration(enum)
455
456 for enum in enumsneeded.keys():
457 objc.checkforenum(enum)
458
459 objc.dumpindex()
460
461 precompinfo = objc.getprecompinfo(modname)
462
Jack Jansendf976ca2003-01-26 20:35:47 +0000463 return code, suite, pathname, modname, precompinfo
Jack Jansen12b2b762000-08-20 19:30:56 +0000464
Jack Jansendf976ca2003-01-26 20:35:47 +0000465def compilesuite((suite, pathname, modname), major, minor, language, script, fname, basepackage, precompinfo):
Jack Jansen12b2b762000-08-20 19:30:56 +0000466 """Generate code for a single suite"""
467 [name, desc, code, level, version, events, classes, comps, enums] = suite
468
Jack Jansendf976ca2003-01-26 20:35:47 +0000469 fp = open(pathname, 'w')
470 MacOS.SetCreatorAndType(pathname, 'Pyth', 'TEXT')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000471
Jack Jansen8b777672002-08-07 14:49:00 +0000472 fp.write('"""Suite %s: %s\n' % (ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000473 fp.write("Level %d, version %d\n\n" % (level, version))
Jack Jansen8b777672002-08-07 14:49:00 +0000474 fp.write("Generated from %s\n"%ascii(fname))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000475 fp.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
476 (major, minor, language, script))
477 fp.write('"""\n\n')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000478
479 fp.write('import aetools\n')
480 fp.write('import MacOS\n\n')
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000481 fp.write("_code = %s\n\n"% `code`)
Jack Jansen60762cb2000-08-17 22:11:45 +0000482 if basepackage and basepackage._code_to_module.has_key(code):
483 # We are an extension of a baseclass (usually an application extending
484 # Standard_Suite or so). Import everything from our base module
Jack Jansen12b2b762000-08-20 19:30:56 +0000485 fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000486 basemodule = basepackage._code_to_module[code]
Jack Jansen7ebcbf52002-01-22 23:24:03 +0000487 elif basepackage and basepackage._code_to_module.has_key(code.lower()):
488 # This is needed by CodeWarrior and some others.
489 fp.write('from %s import *\n'%basepackage._code_to_fullname[code.lower()][0])
490 basemodule = basepackage._code_to_module[code.lower()]
Jack Jansen60762cb2000-08-17 22:11:45 +0000491 else:
492 # We are not an extension.
493 basemodule = None
494 compileclassheader(fp, modname, basemodule)
Jack Jansen66544221997-08-08 14:49:02 +0000495
496 enumsneeded = {}
Jack Jansen5ccd8261995-07-17 11:43:20 +0000497 if events:
498 for event in events:
Jack Jansen66544221997-08-08 14:49:02 +0000499 compileevent(fp, event, enumsneeded)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000500 else:
501 fp.write("\tpass\n\n")
Jack Jansen66544221997-08-08 14:49:02 +0000502
Jack Jansen12b2b762000-08-20 19:30:56 +0000503 objc = ObjectCompiler(fp, basemodule, precompinfo)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000504 for cls in classes:
Jack Jansen66544221997-08-08 14:49:02 +0000505 objc.compileclass(cls)
506 for cls in classes:
507 objc.fillclasspropsandelems(cls)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000508 for comp in comps:
Jack Jansen66544221997-08-08 14:49:02 +0000509 objc.compilecomparison(comp)
510 for enum in enums:
511 objc.compileenumeration(enum)
512
513 for enum in enumsneeded.keys():
514 objc.checkforenum(enum)
515
516 objc.dumpindex()
Jack Jansen60762cb2000-08-17 22:11:45 +0000517
518 return code, modname
Jack Jansen5ccd8261995-07-17 11:43:20 +0000519
Jack Jansen60762cb2000-08-17 22:11:45 +0000520def compileclassheader(fp, name, module=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000521 """Generate class boilerplate"""
Jack Jansen60762cb2000-08-17 22:11:45 +0000522 classname = '%s_Events'%name
Jack Jansen12b2b762000-08-20 19:30:56 +0000523 if module:
524 modshortname = string.split(module.__name__, '.')[-1]
525 baseclassname = '%s_Events'%modshortname
526 fp.write("class %s(%s):\n\n"%(classname, baseclassname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000527 else:
528 fp.write("class %s:\n\n"%classname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000529
Jack Jansen66544221997-08-08 14:49:02 +0000530def compileevent(fp, event, enumsneeded):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000531 """Generate code for a single event"""
532 [name, desc, code, subcode, returns, accepts, arguments] = event
533 funcname = identify(name)
534 #
535 # generate name->keyword map
536 #
537 if arguments:
538 fp.write("\t_argmap_%s = {\n"%funcname)
539 for a in arguments:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000540 fp.write("\t\t%s : %s,\n"%(`identify(a[0])`, `a[1]`))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000541 fp.write("\t}\n\n")
542
543 #
544 # Generate function header
545 #
546 has_arg = (not is_null(accepts))
547 opt_arg = (has_arg and is_optional(accepts))
548
Jack Jansen84264771995-10-03 14:35:58 +0000549 fp.write("\tdef %s(self, "%funcname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000550 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000551 if not opt_arg:
552 fp.write("_object, ") # Include direct object, if it has one
553 else:
554 fp.write("_object=None, ") # Also include if it is optional
Jack Jansen5ccd8261995-07-17 11:43:20 +0000555 else:
Jack Jansen84264771995-10-03 14:35:58 +0000556 fp.write("_no_object=None, ") # For argument checking
557 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
Jack Jansen5ccd8261995-07-17 11:43:20 +0000558 #
559 # Generate doc string (important, since it may be the only
560 # available documentation, due to our name-remaping)
561 #
Jack Jansen21f67582002-08-07 15:44:53 +0000562 fp.write('\t\t"""%s: %s\n'%(ascii(name), ascii(desc)))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000563 if has_arg:
564 fp.write("\t\tRequired argument: %s\n"%getdatadoc(accepts))
565 elif opt_arg:
566 fp.write("\t\tOptional argument: %s\n"%getdatadoc(accepts))
567 for arg in arguments:
568 fp.write("\t\tKeyword argument %s: %s\n"%(identify(arg[0]),
569 getdatadoc(arg[2])))
570 fp.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
571 if not is_null(returns):
572 fp.write("\t\tReturns: %s\n"%getdatadoc(returns))
573 fp.write('\t\t"""\n')
574 #
575 # Fiddle the args so everything ends up in 'arguments' dictionary
576 #
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000577 fp.write("\t\t_code = %s\n"% `code`)
578 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
Jack Jansen73215141995-10-09 23:09:23 +0000579 #
580 # Do keyword name substitution
581 #
582 if arguments:
583 fp.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname)
584 else:
585 fp.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
586 #
587 # Stuff required arg (if there is one) into arguments
588 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000589 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000590 fp.write("\t\t_arguments['----'] = _object\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000591 elif opt_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000592 fp.write("\t\tif _object:\n")
593 fp.write("\t\t\t_arguments['----'] = _object\n")
594 else:
595 fp.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000596 fp.write("\n")
597 #
Jack Jansen73215141995-10-09 23:09:23 +0000598 # Do enum-name substitution
Jack Jansen5ccd8261995-07-17 11:43:20 +0000599 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000600 for a in arguments:
601 if is_enum(a[2]):
602 kname = a[1]
603 ename = a[2][0]
Jack Jansena2408e91996-04-16 14:36:46 +0000604 if ename <> '****':
605 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000606 (`kname`, identify(ename)))
Jack Jansen66544221997-08-08 14:49:02 +0000607 enumsneeded[ename] = 1
Jack Jansen5ccd8261995-07-17 11:43:20 +0000608 fp.write("\n")
609 #
610 # Do the transaction
611 #
Jack Jansen84264771995-10-03 14:35:58 +0000612 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
613 fp.write("\t\t\t\t_arguments, _attributes)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000614 #
615 # Error handling
616 #
Jack Jansen18983532002-04-23 21:03:21 +0000617 fp.write("\t\tif _arguments.get('errn', 0):\n")
Jack Jansen977fbf21996-09-20 15:29:59 +0000618 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000619 fp.write("\t\t# XXXX Optionally decode result\n")
620 #
621 # Decode result
622 #
Jack Jansen84264771995-10-03 14:35:58 +0000623 fp.write("\t\tif _arguments.has_key('----'):\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000624 if is_enum(returns):
625 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
Jack Jansen84264771995-10-03 14:35:58 +0000626 fp.write("\t\t\treturn _arguments['----']\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000627 fp.write("\n")
628
629# print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
630# print "# returns", compiledata(returns)
631# print "# accepts", compiledata(accepts)
632# for arg in arguments:
633# compileargument(arg)
634
635def compileargument(arg):
636 [name, keyword, what] = arg
637 print "# %s (%s)" % (name, `keyword`), compiledata(what)
638
Jack Jansen12b2b762000-08-20 19:30:56 +0000639def findenumsinevent(event, enumsneeded):
640 """Find all enums for a single event"""
641 [name, desc, code, subcode, returns, accepts, arguments] = event
642 for a in arguments:
643 if is_enum(a[2]):
644 ename = a[2][0]
645 if ename <> '****':
646 enumsneeded[ename] = 1
647
648#
649# This class stores the code<->name translations for a single module. It is used
650# to keep the information while we're compiling the module, but we also keep these objects
651# around so if one suite refers to, say, an enum in another suite we know where to
652# find it. Finally, if we really can't find a code, the user can add modules by
653# hand.
654#
655class CodeNameMapper:
656
657 def __init__(self):
658 self.code2name = {
659 "property" : {},
660 "class" : {},
661 "enum" : {},
662 "comparison" : {},
663 }
664 self.name2code = {
665 "property" : {},
666 "class" : {},
667 "enum" : {},
668 "comparison" : {},
669 }
670 self.modulename = None
671 self.star_imported = 0
672
673 def addnamecode(self, type, name, code):
674 self.name2code[type][name] = code
675 if not self.code2name[type].has_key(code):
676 self.code2name[type][code] = name
677
678 def hasname(self, type, name):
679 return self.name2code[type].has_key(name)
680
681 def hascode(self, type, code):
682 return self.code2name[type].has_key(code)
683
684 def findcodename(self, type, code):
685 if not self.hascode(type, code):
686 return None, None, None
687 name = self.code2name[type][code]
688 if self.modulename and not self.star_imported:
689 qualname = '%s.%s'%(self.modulename, name)
690 else:
691 qualname = name
692 return name, qualname, self.modulename
693
694 def getall(self, type):
695 return self.code2name[type].items()
696
697 def addmodule(self, module, name, star_imported):
698 self.modulename = name
699 self.star_imported = star_imported
700 for code, name in module._propdeclarations.items():
701 self.addnamecode('property', name, code)
702 for code, name in module._classdeclarations.items():
703 self.addnamecode('class', name, code)
704 for code in module._enumdeclarations.keys():
705 self.addnamecode('enum', '_Enum_'+identify(code), code)
706 for code, name in module._compdeclarations.items():
707 self.addnamecode('comparison', name, code)
708
709 def prepareforexport(self, name=None):
710 if not self.modulename:
711 self.modulename = name
712 return self
713
Jack Jansen66544221997-08-08 14:49:02 +0000714class ObjectCompiler:
Jack Jansen12b2b762000-08-20 19:30:56 +0000715 def __init__(self, fp, basesuite=None, othernamemappers=None):
Jack Jansen66544221997-08-08 14:49:02 +0000716 self.fp = fp
Jack Jansen60762cb2000-08-17 22:11:45 +0000717 self.basesuite = basesuite
Jack Jansen12b2b762000-08-20 19:30:56 +0000718 self.namemappers = [CodeNameMapper()]
719 if othernamemappers:
720 self.othernamemappers = othernamemappers[:]
721 else:
722 self.othernamemappers = []
723 if basesuite:
724 basemapper = CodeNameMapper()
725 basemapper.addmodule(basesuite, '', 1)
726 self.namemappers.append(basemapper)
727
728 def getprecompinfo(self, modname):
729 list = []
730 for mapper in self.namemappers:
731 emapper = mapper.prepareforexport(modname)
732 if emapper:
733 list.append(emapper)
734 return list
Jack Jansen66544221997-08-08 14:49:02 +0000735
736 def findcodename(self, type, code):
737 while 1:
Jack Jansen12b2b762000-08-20 19:30:56 +0000738 # First try: check whether we already know about this code.
739 for mapper in self.namemappers:
740 if mapper.hascode(type, code):
741 return mapper.findcodename(type, code)
742 # Second try: maybe one of the other modules knows about it.
743 for mapper in self.othernamemappers:
744 if mapper.hascode(type, code):
745 self.othernamemappers.remove(mapper)
746 self.namemappers.append(mapper)
747 if self.fp:
748 self.fp.write("import %s\n"%mapper.modulename)
749 break
750 else:
751 # If all this has failed we ask the user for a guess on where it could
752 # be and retry.
753 if self.fp:
754 m = self.askdefinitionmodule(type, code)
755 else:
756 m = None
757 if not m: return None, None, None
758 mapper = CodeNameMapper()
759 mapper.addmodule(m, m.__name__, 0)
760 self.namemappers.append(mapper)
Jack Jansen66544221997-08-08 14:49:02 +0000761
762 def askdefinitionmodule(self, type, code):
Jack Jansendf976ca2003-01-26 20:35:47 +0000763 path = EasyDialogs.AskFileForSave(message='Where is %s %s declared?'%(type, code))
764 if not path: return
765 path, file = os.path.split(path)
Jack Jansen66544221997-08-08 14:49:02 +0000766 modname = os.path.splitext(file)[0]
767 if not path in sys.path:
768 sys.path.insert(0, path)
769 m = __import__(modname)
770 self.fp.write("import %s\n"%modname)
771 return m
772
773 def compileclass(self, cls):
774 [name, code, desc, properties, elements] = cls
775 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000776 if self.namemappers[0].hascode('class', code):
Jack Jansen66544221997-08-08 14:49:02 +0000777 # plural forms and such
Jack Jansen12b2b762000-08-20 19:30:56 +0000778 othername, dummy, dummy = self.namemappers[0].findcodename('class', code)
779 if self.fp:
780 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000781 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000782 if self.fp:
783 self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000784 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(desc)))
Jack Jansen12b2b762000-08-20 19:30:56 +0000785 self.fp.write('\twant = %s\n' % `code`)
786 self.namemappers[0].addnamecode('class', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000787 for prop in properties:
788 self.compileproperty(prop)
789 for elem in elements:
790 self.compileelement(elem)
791
792 def compileproperty(self, prop):
793 [name, code, what] = prop
794 if code == 'c@#!':
795 # Something silly with plurals. Skip it.
796 return
797 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000798 if self.namemappers[0].hascode('property', code):
Jack Jansen2eda2442000-08-20 19:42:52 +0000799 # plural forms and such
800 othername, dummy, dummy = self.namemappers[0].findcodename('property', code)
Jack Jansen9d6d2c02000-08-22 20:34:35 +0000801 if pname == othername:
802 return
Jack Jansen12b2b762000-08-20 19:30:56 +0000803 if self.fp:
Jack Jansen2eda2442000-08-20 19:42:52 +0000804 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000805 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000806 if self.fp:
807 self.fp.write("class %s(aetools.NProperty):\n" % pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000808 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(what[1])))
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000809 self.fp.write("\twhich = %s\n" % `code`)
810 self.fp.write("\twant = %s\n" % `what[0]`)
Jack Jansen2eda2442000-08-20 19:42:52 +0000811 self.namemappers[0].addnamecode('property', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000812
813 def compileelement(self, elem):
814 [code, keyform] = elem
Jack Jansen12b2b762000-08-20 19:30:56 +0000815 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000816 self.fp.write("# element %s as %s\n" % (`code`, keyform))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000817
Jack Jansen66544221997-08-08 14:49:02 +0000818 def fillclasspropsandelems(self, cls):
819 [name, code, desc, properties, elements] = cls
820 cname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000821 if self.namemappers[0].hascode('class', code) and \
822 self.namemappers[0].findcodename('class', code)[0] != cname:
Jack Jansen66544221997-08-08 14:49:02 +0000823 # This is an other name (plural or so) for something else. Skip.
824 return
825 plist = []
826 elist = []
Jack Jansen8b777672002-08-07 14:49:00 +0000827 superclasses = []
Jack Jansen66544221997-08-08 14:49:02 +0000828 for prop in properties:
829 [pname, pcode, what] = prop
Jack Jansen8b777672002-08-07 14:49:00 +0000830 if pcode == "c@#^":
831 superclasses.append(what)
Jack Jansen66544221997-08-08 14:49:02 +0000832 if pcode == 'c@#!':
833 continue
834 pname = identify(pname)
835 plist.append(pname)
Jack Jansen8b777672002-08-07 14:49:00 +0000836
837 superclassnames = []
838 for superclass in superclasses:
839 superId, superDesc, dummy = superclass
840 superclassname, fullyqualifiedname, module = self.findcodename("class", superId)
841 superclassnames.append(superclassname)
842
843 if self.fp:
844 self.fp.write("%s._superclassnames = %s\n"%(cname, `superclassnames`))
845
Jack Jansen66544221997-08-08 14:49:02 +0000846 for elem in elements:
847 [ecode, keyform] = elem
848 if ecode == 'c@#!':
849 continue
850 name, ename, module = self.findcodename('class', ecode)
851 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000852 if self.fp:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000853 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
Jack Jansen66544221997-08-08 14:49:02 +0000854 else:
Jack Jansen34d11f02000-03-07 23:40:13 +0000855 elist.append((name, ename))
Jack Jansen12b2b762000-08-20 19:30:56 +0000856
857 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000858 self.fp.write("%s._privpropdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000859 for n in plist:
860 self.fp.write("\t'%s' : %s,\n"%(n, n))
861 self.fp.write("}\n")
Jack Jansen8b777672002-08-07 14:49:00 +0000862 self.fp.write("%s._privelemdict = {\n"%cname)
Jack Jansen12b2b762000-08-20 19:30:56 +0000863 for n, fulln in elist:
864 self.fp.write("\t'%s' : %s,\n"%(n, fulln))
865 self.fp.write("}\n")
Jack Jansen66544221997-08-08 14:49:02 +0000866
867 def compilecomparison(self, comp):
868 [name, code, comment] = comp
869 iname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000870 self.namemappers[0].addnamecode('comparison', iname, code)
871 if self.fp:
872 self.fp.write("class %s(aetools.NComparison):\n" % iname)
Jack Jansen8b777672002-08-07 14:49:00 +0000873 self.fp.write('\t"""%s - %s """\n' % (ascii(name), ascii(comment)))
Jack Jansen66544221997-08-08 14:49:02 +0000874
875 def compileenumeration(self, enum):
876 [code, items] = enum
877 name = "_Enum_%s" % identify(code)
Jack Jansen12b2b762000-08-20 19:30:56 +0000878 if self.fp:
879 self.fp.write("%s = {\n" % name)
880 for item in items:
881 self.compileenumerator(item)
882 self.fp.write("}\n\n")
883 self.namemappers[0].addnamecode('enum', name, code)
Jack Jansen66544221997-08-08 14:49:02 +0000884 return code
885
886 def compileenumerator(self, item):
887 [name, code, desc] = item
Jack Jansen21f67582002-08-07 15:44:53 +0000888 self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, ascii(desc)))
Jack Jansen66544221997-08-08 14:49:02 +0000889
890 def checkforenum(self, enum):
891 """This enum code is used by an event. Make sure it's available"""
892 name, fullname, module = self.findcodename('enum', enum)
893 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000894 if self.fp:
Jack Jansen8b777672002-08-07 14:49:00 +0000895 self.fp.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum), ascii(enum)))
Jack Jansen66544221997-08-08 14:49:02 +0000896 return
897 if module:
Jack Jansen12b2b762000-08-20 19:30:56 +0000898 if self.fp:
899 self.fp.write("from %s import %s\n"%(module, name))
Jack Jansen66544221997-08-08 14:49:02 +0000900
901 def dumpindex(self):
Jack Jansen12b2b762000-08-20 19:30:56 +0000902 if not self.fp:
903 return
Jack Jansen66544221997-08-08 14:49:02 +0000904 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
905 self.fp.write("_classdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000906 for k, v in self.namemappers[0].getall('class'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000907 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000908 self.fp.write("}\n")
909 self.fp.write("\n_propdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000910 for k, v in self.namemappers[0].getall('property'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000911 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000912 self.fp.write("}\n")
913 self.fp.write("\n_compdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000914 for k, v in self.namemappers[0].getall('comparison'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000915 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000916 self.fp.write("}\n")
917 self.fp.write("\n_enumdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000918 for k, v in self.namemappers[0].getall('enum'):
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000919 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000920 self.fp.write("}\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000921
922def compiledata(data):
923 [type, description, flags] = data
924 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
925
926def is_null(data):
927 return data[0] == 'null'
928
929def is_optional(data):
930 return (data[2] & 0x8000)
931
932def is_enum(data):
933 return (data[2] & 0x2000)
934
935def getdatadoc(data):
936 [type, descr, flags] = data
937 if descr:
Jack Jansen8b777672002-08-07 14:49:00 +0000938 return ascii(descr)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000939 if type == '****':
940 return 'anything'
941 if type == 'obj ':
942 return 'an AE object reference'
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000943 return "undocumented, typecode %s"%`type`
Jack Jansen5ccd8261995-07-17 11:43:20 +0000944
945dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
946def compiledataflags(flags):
947 bits = []
948 for i in range(16):
949 if flags & (1<<i):
950 if i in dataflagdict.keys():
951 bits.append(dataflagdict[i])
952 else:
953 bits.append(`i`)
954 return '[%s]' % string.join(bits)
955
Jack Jansen8b777672002-08-07 14:49:00 +0000956def ascii(str):
957 """Return a string with all non-ascii characters hex-encoded"""
958 if type(str) != type(''):
959 return map(ascii, str)
960 rv = ''
961 for c in str:
962 if c in ('\t', '\n', '\r') or ' ' <= c < chr(0x7f):
963 rv = rv + c
964 else:
Jack Jansen2f7f8c42002-08-07 15:05:42 +0000965 rv = rv + '\\' + 'x%02.2x' % ord(c)
Jack Jansen8b777672002-08-07 14:49:00 +0000966 return rv
967
Jack Jansen5ccd8261995-07-17 11:43:20 +0000968def identify(str):
969 """Turn any string into an identifier:
970 - replace space by _
971 - replace other illegal chars by _xx_ (hex code)
972 - prepend _ if the result is a python keyword
973 """
Jack Jansen66544221997-08-08 14:49:02 +0000974 if not str:
Jack Jansen21f67582002-08-07 15:44:53 +0000975 return "empty_ae_name_"
Jack Jansen5ccd8261995-07-17 11:43:20 +0000976 rv = ''
Fred Drake79e75e12001-07-20 19:05:50 +0000977 ok = string.ascii_letters + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +0000978 ok2 = ok + string.digits
979 for c in str:
980 if c in ok:
981 rv = rv + c
982 elif c == ' ':
983 rv = rv + '_'
984 else:
985 rv = rv + '_%02.2x_'%ord(c)
986 ok = ok2
Jack Jansenb2ecc2c2002-01-24 22:44:07 +0000987 if keyword.iskeyword(rv):
Jack Jansen21f67582002-08-07 15:44:53 +0000988 rv = rv + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +0000989 return rv
990
991# Call the main program
992
993if __name__ == '__main__':
994 main()
995 sys.exit(1)