blob: 4f2ddc0d741f041480620523228fb7aed978037d [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
10import os
11import string
12import sys
13import types
14import StringIO
15import macfs
Jack Jansenb2ecc2c2002-01-24 22:44:07 +000016import keyword
Jack Jansen40926062002-03-30 23:43:04 +000017import macresource
Jack Jansen5ccd8261995-07-17 11:43:20 +000018
Jack Jansen5a6fdcd2001-08-25 12:15:04 +000019from Carbon.Res import *
Jack Jansen5ccd8261995-07-17 11:43:20 +000020
Jack Jansen40926062002-03-30 23:43:04 +000021DEFAULT_PACKAGEFOLDER=os.path.join(sys.prefix, 'Mac', 'Lib', 'lib-scriptpackages')
22
Jack Jansen5ccd8261995-07-17 11:43:20 +000023def main():
Jack Jansen40926062002-03-30 23:43:04 +000024 if len(sys.argv) > 1:
25 for filename in sys.argv[1:]:
26 processfile(filename)
27 else:
28 fss, ok = macfs.PromptGetFile('Select file with aeut/aete resource:')
29 if not ok:
30 sys.exit(0)
31 processfile(fss.as_pathname())
Jack Jansen5ccd8261995-07-17 11:43:20 +000032
Jack Jansen60762cb2000-08-17 22:11:45 +000033def processfile(fullname):
Jack Jansen5ccd8261995-07-17 11:43:20 +000034 """Process all resources in a single file"""
35 cur = CurResFile()
Jack Jansen40926062002-03-30 23:43:04 +000036 print "Processing", fullname
37 rf = macresource.open_pathname(fullname)
Jack Jansen5ccd8261995-07-17 11:43:20 +000038 try:
39 UseResFile(rf)
40 resources = []
41 for i in range(Count1Resources('aete')):
42 res = Get1IndResource('aete', 1+i)
43 resources.append(res)
44 for i in range(Count1Resources('aeut')):
45 res = Get1IndResource('aeut', 1+i)
46 resources.append(res)
47 print "\nLISTING aete+aeut RESOURCES IN", `fullname`
Jack Jansen60762cb2000-08-17 22:11:45 +000048 aetelist = []
Jack Jansen5ccd8261995-07-17 11:43:20 +000049 for res in resources:
50 print "decoding", res.GetResInfo(), "..."
51 data = res.data
52 aete = decode(data)
Jack Jansen60762cb2000-08-17 22:11:45 +000053 aetelist.append((aete, res.GetResInfo()))
Jack Jansen5ccd8261995-07-17 11:43:20 +000054 finally:
55 if rf <> cur:
56 CloseResFile(rf)
57 UseResFile(cur)
Jack Jansen60762cb2000-08-17 22:11:45 +000058 # switch back (needed for dialogs in Python)
59 UseResFile(cur)
60 compileaetelist(aetelist, fullname)
Jack Jansen5ccd8261995-07-17 11:43:20 +000061
Jack Jansen60762cb2000-08-17 22:11:45 +000062def compileaetelist(aetelist, fullname):
63 for aete, resinfo in aetelist:
64 compileaete(aete, resinfo, fullname)
65
Jack Jansen5ccd8261995-07-17 11:43:20 +000066def decode(data):
67 """Decode a resource into a python data structure"""
68 f = StringIO.StringIO(data)
69 aete = generic(getaete, f)
70 aete = simplify(aete)
71 processed = f.tell()
72 unprocessed = len(f.read())
73 total = f.tell()
74 if unprocessed:
75 sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
76 (processed, unprocessed, total))
77 return aete
78
79def simplify(item):
80 """Recursively replace singleton tuples by their constituent item"""
81 if type(item) is types.ListType:
82 return map(simplify, item)
83 elif type(item) == types.TupleType and len(item) == 2:
84 return simplify(item[1])
85 else:
86 return item
87
88
89# Here follows the aete resource decoder.
90# It is presented bottom-up instead of top-down because there are direct
91# references to the lower-level part-decoders from the high-level part-decoders.
92
93def getbyte(f, *args):
94 c = f.read(1)
95 if not c:
96 raise EOFError, 'in getbyte' + str(args)
97 return ord(c)
98
99def getword(f, *args):
100 getalign(f)
101 s = f.read(2)
102 if len(s) < 2:
103 raise EOFError, 'in getword' + str(args)
104 return (ord(s[0])<<8) | ord(s[1])
105
106def getlong(f, *args):
107 getalign(f)
108 s = f.read(4)
109 if len(s) < 4:
110 raise EOFError, 'in getlong' + str(args)
111 return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
112
113def getostype(f, *args):
114 getalign(f)
115 s = f.read(4)
116 if len(s) < 4:
117 raise EOFError, 'in getostype' + str(args)
118 return s
119
120def getpstr(f, *args):
121 c = f.read(1)
122 if len(c) < 1:
123 raise EOFError, 'in getpstr[1]' + str(args)
124 nbytes = ord(c)
125 if nbytes == 0: return ''
126 s = f.read(nbytes)
127 if len(s) < nbytes:
128 raise EOFError, 'in getpstr[2]' + str(args)
129 return s
130
131def getalign(f):
132 if f.tell() & 1:
133 c = f.read(1)
134 ##if c <> '\0':
135 ## print 'align:', `c`
136
137def getlist(f, description, getitem):
138 count = getword(f)
139 list = []
140 for i in range(count):
141 list.append(generic(getitem, f))
142 getalign(f)
143 return list
144
145def alt_generic(what, f, *args):
146 print "generic", `what`, args
147 res = vageneric(what, f, args)
148 print '->', `res`
149 return res
150
151def generic(what, f, *args):
152 if type(what) == types.FunctionType:
153 return apply(what, (f,) + args)
154 if type(what) == types.ListType:
155 record = []
156 for thing in what:
157 item = apply(generic, thing[:1] + (f,) + thing[1:])
158 record.append((thing[1], item))
159 return record
160 return "BAD GENERIC ARGS: %s" % `what`
161
162getdata = [
163 (getostype, "type"),
164 (getpstr, "description"),
165 (getword, "flags")
166 ]
167getargument = [
168 (getpstr, "name"),
169 (getostype, "keyword"),
170 (getdata, "what")
171 ]
172getevent = [
173 (getpstr, "name"),
174 (getpstr, "description"),
175 (getostype, "suite code"),
176 (getostype, "event code"),
177 (getdata, "returns"),
178 (getdata, "accepts"),
179 (getlist, "optional arguments", getargument)
180 ]
181getproperty = [
182 (getpstr, "name"),
183 (getostype, "code"),
184 (getdata, "what")
185 ]
186getelement = [
187 (getostype, "type"),
188 (getlist, "keyform", getostype)
189 ]
190getclass = [
191 (getpstr, "name"),
192 (getostype, "class code"),
193 (getpstr, "description"),
194 (getlist, "properties", getproperty),
195 (getlist, "elements", getelement)
196 ]
197getcomparison = [
198 (getpstr, "operator name"),
199 (getostype, "operator ID"),
200 (getpstr, "operator comment"),
201 ]
202getenumerator = [
203 (getpstr, "enumerator name"),
204 (getostype, "enumerator ID"),
205 (getpstr, "enumerator comment")
206 ]
207getenumeration = [
208 (getostype, "enumeration ID"),
209 (getlist, "enumerator", getenumerator)
210 ]
211getsuite = [
212 (getpstr, "suite name"),
213 (getpstr, "suite description"),
214 (getostype, "suite ID"),
215 (getword, "suite level"),
216 (getword, "suite version"),
217 (getlist, "events", getevent),
218 (getlist, "classes", getclass),
219 (getlist, "comparisons", getcomparison),
220 (getlist, "enumerations", getenumeration)
221 ]
222getaete = [
223 (getword, "major/minor version in BCD"),
224 (getword, "language code"),
225 (getword, "script code"),
226 (getlist, "suites", getsuite)
227 ]
228
Jack Jansen60762cb2000-08-17 22:11:45 +0000229def compileaete(aete, resinfo, fname):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000230 """Generate code for a full aete resource. fname passed for doc purposes"""
231 [version, language, script, suites] = aete
232 major, minor = divmod(version, 256)
Jack Jansen60762cb2000-08-17 22:11:45 +0000233 fss = macfs.FSSpec(fname)
234 creatorsignature, dummy = fss.GetCreatorType()
Jack Jansen40926062002-03-30 23:43:04 +0000235 packagename = identify(os.path.splitext(os.path.basename(fname))[0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000236 if language:
237 packagename = packagename+'_lang%d'%language
238 if script:
239 packagename = packagename+'_script%d'%script
240 if len(packagename) > 27:
241 packagename = packagename[:27]
Jack Jansen40926062002-03-30 23:43:04 +0000242 macfs.SetFolder(DEFAULT_PACKAGEFOLDER)
243 fss, ok = macfs.GetDirectory('Create and select package folder for %s'%packagename)
Jack Jansen60762cb2000-08-17 22:11:45 +0000244 if not ok:
245 return
246 pathname = fss.as_pathname()
247 packagename = os.path.split(os.path.normpath(pathname))[1]
248 fss, ok = macfs.GetDirectory('Package folder for base suite (usually StdSuites)')
249 if ok:
250 dirname, basepkgname = os.path.split(os.path.normpath(fss.as_pathname()))
251 if not dirname in sys.path:
252 sys.path.insert(0, dirname)
253 basepackage = __import__(basepkgname)
254 else:
255 basepackage = None
256 macfs.SetFolder(pathname)
257 suitelist = []
Jack Jansen12b2b762000-08-20 19:30:56 +0000258 allprecompinfo = []
259 allsuites = []
Jack Jansen5ccd8261995-07-17 11:43:20 +0000260 for suite in suites:
Jack Jansen12b2b762000-08-20 19:30:56 +0000261 code, suite, fss, modname, precompinfo = precompilesuite(suite, basepackage)
262 if not code:
263 continue
264 allprecompinfo = allprecompinfo + precompinfo
265 suiteinfo = suite, fss, modname
266 suitelist.append((code, modname))
267 allsuites.append(suiteinfo)
268 for suiteinfo in allsuites:
269 compilesuite(suiteinfo, major, minor, language, script, fname, basepackage, allprecompinfo)
Jack Jansen60762cb2000-08-17 22:11:45 +0000270 fss, ok = macfs.StandardPutFile('Package module', '__init__.py')
271 if not ok:
272 return
273 fp = open(fss.as_pathname(), 'w')
274 fss.SetCreatorType('Pyth', 'TEXT')
275 fp.write('"""\n')
276 fp.write("Package generated from %s\n"%fname)
277 fp.write("Resource %s resid %d %s\n"%(resinfo[1], resinfo[0], resinfo[2]))
278 fp.write('"""\n')
279 fp.write('import aetools\n')
Jack Jansen6aa92c52000-08-20 21:59:03 +0000280 fp.write('Error = aetools.Error\n')
Jack Jansen60762cb2000-08-17 22:11:45 +0000281 for code, modname in suitelist:
282 fp.write("import %s\n" % modname)
283 fp.write("\n\n_code_to_module = {\n")
284 for code, modname in suitelist:
285 fp.write("\t'%s' : %s,\n"%(code, modname))
286 fp.write("}\n\n")
287 fp.write("\n\n_code_to_fullname = {\n")
288 for code, modname in suitelist:
Jack Jansen12b2b762000-08-20 19:30:56 +0000289 fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(code, packagename, modname, modname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000290 fp.write("}\n\n")
291 for code, modname in suitelist:
292 fp.write("from %s import *\n"%modname)
293 if suitelist:
294 fp.write("\n\nclass %s(%s_Events"%(packagename, suitelist[0][1]))
295 for code, modname in suitelist[1:]:
Jack Jansen12b2b762000-08-20 19:30:56 +0000296 fp.write(",\n\t\t%s_Events"%modname)
297 fp.write(",\n\t\taetools.TalkTo):\n")
Jack Jansen40926062002-03-30 23:43:04 +0000298 fp.write("\t_signature = %s\n\n"%`creatorsignature`)
Jack Jansen60762cb2000-08-17 22:11:45 +0000299 fp.close()
Jack Jansen12b2b762000-08-20 19:30:56 +0000300
301def precompilesuite(suite, basepackage=None):
302 """Parse a single suite without generating the output. This step is needed
303 so we can resolve recursive references by suites to enums/comps/etc declared
304 in other suites"""
Jack Jansen5ccd8261995-07-17 11:43:20 +0000305 [name, desc, code, level, version, events, classes, comps, enums] = suite
306
307 modname = identify(name)
Jack Jansen60762cb2000-08-17 22:11:45 +0000308 if len(modname) > 28:
309 modname = modname[:27]
Jack Jansen5ccd8261995-07-17 11:43:20 +0000310 fss, ok = macfs.StandardPutFile('Python output file', modname+'.py')
311 if not ok:
Jack Jansen12b2b762000-08-20 19:30:56 +0000312 return None, None, None, None, None
313
Jack Jansen60762cb2000-08-17 22:11:45 +0000314 pathname = fss.as_pathname()
315 modname = os.path.splitext(os.path.split(pathname)[1])[0]
Jack Jansen12b2b762000-08-20 19:30:56 +0000316
317 if basepackage and basepackage._code_to_module.has_key(code):
318 # We are an extension of a baseclass (usually an application extending
319 # Standard_Suite or so). Import everything from our base module
320 basemodule = basepackage._code_to_module[code]
321 else:
322 # We are not an extension.
323 basemodule = None
324
325 enumsneeded = {}
326 for event in events:
327 findenumsinevent(event, enumsneeded)
328
329 objc = ObjectCompiler(None, basemodule)
330 for cls in classes:
331 objc.compileclass(cls)
332 for cls in classes:
333 objc.fillclasspropsandelems(cls)
334 for comp in comps:
335 objc.compilecomparison(comp)
336 for enum in enums:
337 objc.compileenumeration(enum)
338
339 for enum in enumsneeded.keys():
340 objc.checkforenum(enum)
341
342 objc.dumpindex()
343
344 precompinfo = objc.getprecompinfo(modname)
345
346 return code, suite, fss, modname, precompinfo
347
348def compilesuite((suite, fss, modname), major, minor, language, script, fname, basepackage, precompinfo):
349 """Generate code for a single suite"""
350 [name, desc, code, level, version, events, classes, comps, enums] = suite
351
352 pathname = fss.as_pathname()
Jack Jansen5ccd8261995-07-17 11:43:20 +0000353 fp = open(fss.as_pathname(), 'w')
Jack Jansen18a99f51996-03-18 13:35:00 +0000354 fss.SetCreatorType('Pyth', 'TEXT')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000355
356 fp.write('"""Suite %s: %s\n' % (name, desc))
357 fp.write("Level %d, version %d\n\n" % (level, version))
358 fp.write("Generated from %s\n"%fname)
359 fp.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
360 (major, minor, language, script))
361 fp.write('"""\n\n')
Jack Jansen5ccd8261995-07-17 11:43:20 +0000362
363 fp.write('import aetools\n')
364 fp.write('import MacOS\n\n')
365 fp.write("_code = %s\n\n"% `code`)
Jack Jansen60762cb2000-08-17 22:11:45 +0000366 if basepackage and basepackage._code_to_module.has_key(code):
367 # We are an extension of a baseclass (usually an application extending
368 # Standard_Suite or so). Import everything from our base module
Jack Jansen12b2b762000-08-20 19:30:56 +0000369 fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0])
Jack Jansen60762cb2000-08-17 22:11:45 +0000370 basemodule = basepackage._code_to_module[code]
Jack Jansen7ebcbf52002-01-22 23:24:03 +0000371 elif basepackage and basepackage._code_to_module.has_key(code.lower()):
372 # This is needed by CodeWarrior and some others.
373 fp.write('from %s import *\n'%basepackage._code_to_fullname[code.lower()][0])
374 basemodule = basepackage._code_to_module[code.lower()]
Jack Jansen60762cb2000-08-17 22:11:45 +0000375 else:
376 # We are not an extension.
377 basemodule = None
378 compileclassheader(fp, modname, basemodule)
Jack Jansen66544221997-08-08 14:49:02 +0000379
380 enumsneeded = {}
Jack Jansen5ccd8261995-07-17 11:43:20 +0000381 if events:
382 for event in events:
Jack Jansen66544221997-08-08 14:49:02 +0000383 compileevent(fp, event, enumsneeded)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000384 else:
385 fp.write("\tpass\n\n")
Jack Jansen66544221997-08-08 14:49:02 +0000386
Jack Jansen12b2b762000-08-20 19:30:56 +0000387 objc = ObjectCompiler(fp, basemodule, precompinfo)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000388 for cls in classes:
Jack Jansen66544221997-08-08 14:49:02 +0000389 objc.compileclass(cls)
390 for cls in classes:
391 objc.fillclasspropsandelems(cls)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000392 for comp in comps:
Jack Jansen66544221997-08-08 14:49:02 +0000393 objc.compilecomparison(comp)
394 for enum in enums:
395 objc.compileenumeration(enum)
396
397 for enum in enumsneeded.keys():
398 objc.checkforenum(enum)
399
400 objc.dumpindex()
Jack Jansen60762cb2000-08-17 22:11:45 +0000401
402 return code, modname
Jack Jansen5ccd8261995-07-17 11:43:20 +0000403
Jack Jansen60762cb2000-08-17 22:11:45 +0000404def compileclassheader(fp, name, module=None):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000405 """Generate class boilerplate"""
Jack Jansen60762cb2000-08-17 22:11:45 +0000406 classname = '%s_Events'%name
Jack Jansen12b2b762000-08-20 19:30:56 +0000407 if module:
408 modshortname = string.split(module.__name__, '.')[-1]
409 baseclassname = '%s_Events'%modshortname
410 fp.write("class %s(%s):\n\n"%(classname, baseclassname))
Jack Jansen60762cb2000-08-17 22:11:45 +0000411 else:
412 fp.write("class %s:\n\n"%classname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000413
Jack Jansen66544221997-08-08 14:49:02 +0000414def compileevent(fp, event, enumsneeded):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000415 """Generate code for a single event"""
416 [name, desc, code, subcode, returns, accepts, arguments] = event
417 funcname = identify(name)
418 #
419 # generate name->keyword map
420 #
421 if arguments:
422 fp.write("\t_argmap_%s = {\n"%funcname)
423 for a in arguments:
424 fp.write("\t\t%s : %s,\n"%(`identify(a[0])`, `a[1]`))
425 fp.write("\t}\n\n")
426
427 #
428 # Generate function header
429 #
430 has_arg = (not is_null(accepts))
431 opt_arg = (has_arg and is_optional(accepts))
432
Jack Jansen84264771995-10-03 14:35:58 +0000433 fp.write("\tdef %s(self, "%funcname)
Jack Jansen5ccd8261995-07-17 11:43:20 +0000434 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000435 if not opt_arg:
436 fp.write("_object, ") # Include direct object, if it has one
437 else:
438 fp.write("_object=None, ") # Also include if it is optional
Jack Jansen5ccd8261995-07-17 11:43:20 +0000439 else:
Jack Jansen84264771995-10-03 14:35:58 +0000440 fp.write("_no_object=None, ") # For argument checking
441 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
Jack Jansen5ccd8261995-07-17 11:43:20 +0000442 #
443 # Generate doc string (important, since it may be the only
444 # available documentation, due to our name-remaping)
445 #
446 fp.write('\t\t"""%s: %s\n'%(name, desc))
447 if has_arg:
448 fp.write("\t\tRequired argument: %s\n"%getdatadoc(accepts))
449 elif opt_arg:
450 fp.write("\t\tOptional argument: %s\n"%getdatadoc(accepts))
451 for arg in arguments:
452 fp.write("\t\tKeyword argument %s: %s\n"%(identify(arg[0]),
453 getdatadoc(arg[2])))
454 fp.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
455 if not is_null(returns):
456 fp.write("\t\tReturns: %s\n"%getdatadoc(returns))
457 fp.write('\t\t"""\n')
458 #
459 # Fiddle the args so everything ends up in 'arguments' dictionary
460 #
461 fp.write("\t\t_code = %s\n"% `code`)
462 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
Jack Jansen73215141995-10-09 23:09:23 +0000463 #
464 # Do keyword name substitution
465 #
466 if arguments:
467 fp.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname)
468 else:
469 fp.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
470 #
471 # Stuff required arg (if there is one) into arguments
472 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000473 if has_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000474 fp.write("\t\t_arguments['----'] = _object\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000475 elif opt_arg:
Jack Jansen84264771995-10-03 14:35:58 +0000476 fp.write("\t\tif _object:\n")
477 fp.write("\t\t\t_arguments['----'] = _object\n")
478 else:
479 fp.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000480 fp.write("\n")
481 #
Jack Jansen73215141995-10-09 23:09:23 +0000482 # Do enum-name substitution
Jack Jansen5ccd8261995-07-17 11:43:20 +0000483 #
Jack Jansen5ccd8261995-07-17 11:43:20 +0000484 for a in arguments:
485 if is_enum(a[2]):
486 kname = a[1]
487 ename = a[2][0]
Jack Jansena2408e91996-04-16 14:36:46 +0000488 if ename <> '****':
489 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
Jack Jansen6aa92c52000-08-20 21:59:03 +0000490 (`kname`, identify(ename)))
Jack Jansen66544221997-08-08 14:49:02 +0000491 enumsneeded[ename] = 1
Jack Jansen5ccd8261995-07-17 11:43:20 +0000492 fp.write("\n")
493 #
494 # Do the transaction
495 #
Jack Jansen84264771995-10-03 14:35:58 +0000496 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
497 fp.write("\t\t\t\t_arguments, _attributes)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000498 #
499 # Error handling
500 #
Jack Jansen84264771995-10-03 14:35:58 +0000501 fp.write("\t\tif _arguments.has_key('errn'):\n")
Jack Jansen977fbf21996-09-20 15:29:59 +0000502 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000503 fp.write("\t\t# XXXX Optionally decode result\n")
504 #
505 # Decode result
506 #
Jack Jansen84264771995-10-03 14:35:58 +0000507 fp.write("\t\tif _arguments.has_key('----'):\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000508 if is_enum(returns):
509 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
Jack Jansen84264771995-10-03 14:35:58 +0000510 fp.write("\t\t\treturn _arguments['----']\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000511 fp.write("\n")
512
513# print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
514# print "# returns", compiledata(returns)
515# print "# accepts", compiledata(accepts)
516# for arg in arguments:
517# compileargument(arg)
518
519def compileargument(arg):
520 [name, keyword, what] = arg
521 print "# %s (%s)" % (name, `keyword`), compiledata(what)
522
Jack Jansen12b2b762000-08-20 19:30:56 +0000523def findenumsinevent(event, enumsneeded):
524 """Find all enums for a single event"""
525 [name, desc, code, subcode, returns, accepts, arguments] = event
526 for a in arguments:
527 if is_enum(a[2]):
528 ename = a[2][0]
529 if ename <> '****':
530 enumsneeded[ename] = 1
531
532#
533# This class stores the code<->name translations for a single module. It is used
534# to keep the information while we're compiling the module, but we also keep these objects
535# around so if one suite refers to, say, an enum in another suite we know where to
536# find it. Finally, if we really can't find a code, the user can add modules by
537# hand.
538#
539class CodeNameMapper:
540
541 def __init__(self):
542 self.code2name = {
543 "property" : {},
544 "class" : {},
545 "enum" : {},
546 "comparison" : {},
547 }
548 self.name2code = {
549 "property" : {},
550 "class" : {},
551 "enum" : {},
552 "comparison" : {},
553 }
554 self.modulename = None
555 self.star_imported = 0
556
557 def addnamecode(self, type, name, code):
558 self.name2code[type][name] = code
559 if not self.code2name[type].has_key(code):
560 self.code2name[type][code] = name
561
562 def hasname(self, type, name):
563 return self.name2code[type].has_key(name)
564
565 def hascode(self, type, code):
566 return self.code2name[type].has_key(code)
567
568 def findcodename(self, type, code):
569 if not self.hascode(type, code):
570 return None, None, None
571 name = self.code2name[type][code]
572 if self.modulename and not self.star_imported:
573 qualname = '%s.%s'%(self.modulename, name)
574 else:
575 qualname = name
576 return name, qualname, self.modulename
577
578 def getall(self, type):
579 return self.code2name[type].items()
580
581 def addmodule(self, module, name, star_imported):
582 self.modulename = name
583 self.star_imported = star_imported
584 for code, name in module._propdeclarations.items():
585 self.addnamecode('property', name, code)
586 for code, name in module._classdeclarations.items():
587 self.addnamecode('class', name, code)
588 for code in module._enumdeclarations.keys():
589 self.addnamecode('enum', '_Enum_'+identify(code), code)
590 for code, name in module._compdeclarations.items():
591 self.addnamecode('comparison', name, code)
592
593 def prepareforexport(self, name=None):
594 if not self.modulename:
595 self.modulename = name
596 return self
597
Jack Jansen66544221997-08-08 14:49:02 +0000598class ObjectCompiler:
Jack Jansen12b2b762000-08-20 19:30:56 +0000599 def __init__(self, fp, basesuite=None, othernamemappers=None):
Jack Jansen66544221997-08-08 14:49:02 +0000600 self.fp = fp
Jack Jansen60762cb2000-08-17 22:11:45 +0000601 self.basesuite = basesuite
Jack Jansen12b2b762000-08-20 19:30:56 +0000602 self.namemappers = [CodeNameMapper()]
603 if othernamemappers:
604 self.othernamemappers = othernamemappers[:]
605 else:
606 self.othernamemappers = []
607 if basesuite:
608 basemapper = CodeNameMapper()
609 basemapper.addmodule(basesuite, '', 1)
610 self.namemappers.append(basemapper)
611
612 def getprecompinfo(self, modname):
613 list = []
614 for mapper in self.namemappers:
615 emapper = mapper.prepareforexport(modname)
616 if emapper:
617 list.append(emapper)
618 return list
Jack Jansen66544221997-08-08 14:49:02 +0000619
620 def findcodename(self, type, code):
621 while 1:
Jack Jansen12b2b762000-08-20 19:30:56 +0000622 # First try: check whether we already know about this code.
623 for mapper in self.namemappers:
624 if mapper.hascode(type, code):
625 return mapper.findcodename(type, code)
626 # Second try: maybe one of the other modules knows about it.
627 for mapper in self.othernamemappers:
628 if mapper.hascode(type, code):
629 self.othernamemappers.remove(mapper)
630 self.namemappers.append(mapper)
631 if self.fp:
632 self.fp.write("import %s\n"%mapper.modulename)
633 break
634 else:
635 # If all this has failed we ask the user for a guess on where it could
636 # be and retry.
637 if self.fp:
638 m = self.askdefinitionmodule(type, code)
639 else:
640 m = None
641 if not m: return None, None, None
642 mapper = CodeNameMapper()
643 mapper.addmodule(m, m.__name__, 0)
644 self.namemappers.append(mapper)
Jack Jansen66544221997-08-08 14:49:02 +0000645
646 def askdefinitionmodule(self, type, code):
647 fss, ok = macfs.PromptGetFile('Where is %s %s declared?'%(type, code))
648 if not ok: return
649 path, file = os.path.split(fss.as_pathname())
650 modname = os.path.splitext(file)[0]
651 if not path in sys.path:
652 sys.path.insert(0, path)
653 m = __import__(modname)
654 self.fp.write("import %s\n"%modname)
655 return m
656
657 def compileclass(self, cls):
658 [name, code, desc, properties, elements] = cls
659 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000660 if self.namemappers[0].hascode('class', code):
Jack Jansen66544221997-08-08 14:49:02 +0000661 # plural forms and such
Jack Jansen12b2b762000-08-20 19:30:56 +0000662 othername, dummy, dummy = self.namemappers[0].findcodename('class', code)
663 if self.fp:
664 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000665 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000666 if self.fp:
667 self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
668 self.fp.write('\t"""%s - %s """\n' % (name, desc))
669 self.fp.write('\twant = %s\n' % `code`)
670 self.namemappers[0].addnamecode('class', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000671 for prop in properties:
672 self.compileproperty(prop)
673 for elem in elements:
674 self.compileelement(elem)
675
676 def compileproperty(self, prop):
677 [name, code, what] = prop
678 if code == 'c@#!':
679 # Something silly with plurals. Skip it.
680 return
681 pname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000682 if self.namemappers[0].hascode('property', code):
Jack Jansen2eda2442000-08-20 19:42:52 +0000683 # plural forms and such
684 othername, dummy, dummy = self.namemappers[0].findcodename('property', code)
Jack Jansen9d6d2c02000-08-22 20:34:35 +0000685 if pname == othername:
686 return
Jack Jansen12b2b762000-08-20 19:30:56 +0000687 if self.fp:
Jack Jansen2eda2442000-08-20 19:42:52 +0000688 self.fp.write("\n%s = %s\n"%(pname, othername))
Jack Jansen66544221997-08-08 14:49:02 +0000689 else:
Jack Jansen12b2b762000-08-20 19:30:56 +0000690 if self.fp:
691 self.fp.write("class %s(aetools.NProperty):\n" % pname)
692 self.fp.write('\t"""%s - %s """\n' % (name, what[1]))
693 self.fp.write("\twhich = %s\n" % `code`)
694 self.fp.write("\twant = %s\n" % `what[0]`)
Jack Jansen2eda2442000-08-20 19:42:52 +0000695 self.namemappers[0].addnamecode('property', pname, code)
Jack Jansen66544221997-08-08 14:49:02 +0000696
697 def compileelement(self, elem):
698 [code, keyform] = elem
Jack Jansen12b2b762000-08-20 19:30:56 +0000699 if self.fp:
700 self.fp.write("# element %s as %s\n" % (`code`, keyform))
Jack Jansen5ccd8261995-07-17 11:43:20 +0000701
Jack Jansen66544221997-08-08 14:49:02 +0000702 def fillclasspropsandelems(self, cls):
703 [name, code, desc, properties, elements] = cls
704 cname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000705 if self.namemappers[0].hascode('class', code) and \
706 self.namemappers[0].findcodename('class', code)[0] != cname:
Jack Jansen66544221997-08-08 14:49:02 +0000707 # This is an other name (plural or so) for something else. Skip.
708 return
709 plist = []
710 elist = []
711 for prop in properties:
712 [pname, pcode, what] = prop
713 if pcode == 'c@#!':
714 continue
715 pname = identify(pname)
716 plist.append(pname)
717 for elem in elements:
718 [ecode, keyform] = elem
719 if ecode == 'c@#!':
720 continue
721 name, ename, module = self.findcodename('class', ecode)
722 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000723 if self.fp:
724 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
Jack Jansen66544221997-08-08 14:49:02 +0000725 else:
Jack Jansen34d11f02000-03-07 23:40:13 +0000726 elist.append((name, ename))
Jack Jansen12b2b762000-08-20 19:30:56 +0000727
728 if self.fp:
729 self.fp.write("%s._propdict = {\n"%cname)
730 for n in plist:
731 self.fp.write("\t'%s' : %s,\n"%(n, n))
732 self.fp.write("}\n")
733 self.fp.write("%s._elemdict = {\n"%cname)
734 for n, fulln in elist:
735 self.fp.write("\t'%s' : %s,\n"%(n, fulln))
736 self.fp.write("}\n")
Jack Jansen66544221997-08-08 14:49:02 +0000737
738 def compilecomparison(self, comp):
739 [name, code, comment] = comp
740 iname = identify(name)
Jack Jansen12b2b762000-08-20 19:30:56 +0000741 self.namemappers[0].addnamecode('comparison', iname, code)
742 if self.fp:
743 self.fp.write("class %s(aetools.NComparison):\n" % iname)
744 self.fp.write('\t"""%s - %s """\n' % (name, comment))
Jack Jansen66544221997-08-08 14:49:02 +0000745
746 def compileenumeration(self, enum):
747 [code, items] = enum
748 name = "_Enum_%s" % identify(code)
Jack Jansen12b2b762000-08-20 19:30:56 +0000749 if self.fp:
750 self.fp.write("%s = {\n" % name)
751 for item in items:
752 self.compileenumerator(item)
753 self.fp.write("}\n\n")
754 self.namemappers[0].addnamecode('enum', name, code)
Jack Jansen66544221997-08-08 14:49:02 +0000755 return code
756
757 def compileenumerator(self, item):
758 [name, code, desc] = item
Jack Jansen7ebcbf52002-01-22 23:24:03 +0000759 self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, desc))
Jack Jansen66544221997-08-08 14:49:02 +0000760
761 def checkforenum(self, enum):
762 """This enum code is used by an event. Make sure it's available"""
763 name, fullname, module = self.findcodename('enum', enum)
764 if not name:
Jack Jansen12b2b762000-08-20 19:30:56 +0000765 if self.fp:
Jack Jansen2eda2442000-08-20 19:42:52 +0000766 self.fp.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum), enum))
Jack Jansen66544221997-08-08 14:49:02 +0000767 return
768 if module:
Jack Jansen12b2b762000-08-20 19:30:56 +0000769 if self.fp:
770 self.fp.write("from %s import %s\n"%(module, name))
Jack Jansen66544221997-08-08 14:49:02 +0000771
772 def dumpindex(self):
Jack Jansen12b2b762000-08-20 19:30:56 +0000773 if not self.fp:
774 return
Jack Jansen66544221997-08-08 14:49:02 +0000775 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
776 self.fp.write("_classdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000777 for k, v in self.namemappers[0].getall('class'):
778 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000779 self.fp.write("}\n")
780 self.fp.write("\n_propdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000781 for k, v in self.namemappers[0].getall('property'):
782 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000783 self.fp.write("}\n")
784 self.fp.write("\n_compdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000785 for k, v in self.namemappers[0].getall('comparison'):
786 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000787 self.fp.write("}\n")
788 self.fp.write("\n_enumdeclarations = {\n")
Jack Jansen12b2b762000-08-20 19:30:56 +0000789 for k, v in self.namemappers[0].getall('enum'):
790 self.fp.write("\t%s : %s,\n" % (`k`, v))
Jack Jansen66544221997-08-08 14:49:02 +0000791 self.fp.write("}\n")
Jack Jansen5ccd8261995-07-17 11:43:20 +0000792
793def compiledata(data):
794 [type, description, flags] = data
795 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
796
797def is_null(data):
798 return data[0] == 'null'
799
800def is_optional(data):
801 return (data[2] & 0x8000)
802
803def is_enum(data):
804 return (data[2] & 0x2000)
805
806def getdatadoc(data):
807 [type, descr, flags] = data
808 if descr:
809 return descr
810 if type == '****':
811 return 'anything'
812 if type == 'obj ':
813 return 'an AE object reference'
814 return "undocumented, typecode %s"%`type`
815
816dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
817def compiledataflags(flags):
818 bits = []
819 for i in range(16):
820 if flags & (1<<i):
821 if i in dataflagdict.keys():
822 bits.append(dataflagdict[i])
823 else:
824 bits.append(`i`)
825 return '[%s]' % string.join(bits)
826
Jack Jansen5ccd8261995-07-17 11:43:20 +0000827def identify(str):
828 """Turn any string into an identifier:
829 - replace space by _
830 - replace other illegal chars by _xx_ (hex code)
831 - prepend _ if the result is a python keyword
832 """
Jack Jansen66544221997-08-08 14:49:02 +0000833 if not str:
834 return "_empty_ae_name"
Jack Jansen5ccd8261995-07-17 11:43:20 +0000835 rv = ''
Fred Drake79e75e12001-07-20 19:05:50 +0000836 ok = string.ascii_letters + '_'
Jack Jansen5ccd8261995-07-17 11:43:20 +0000837 ok2 = ok + string.digits
838 for c in str:
839 if c in ok:
840 rv = rv + c
841 elif c == ' ':
842 rv = rv + '_'
843 else:
844 rv = rv + '_%02.2x_'%ord(c)
845 ok = ok2
Jack Jansenb2ecc2c2002-01-24 22:44:07 +0000846 if keyword.iskeyword(rv):
Jack Jansen5ccd8261995-07-17 11:43:20 +0000847 rv = '_' + rv
848 return rv
849
850# Call the main program
851
852if __name__ == '__main__':
853 main()
854 sys.exit(1)
Jack Jansenb2ecc2c2002-01-24 22:44:07 +0000855print identify('for')