This commit was manufactured by cvs2svn to create tag 'r22a4-fork'.
[python/dscho.git] / Mac / scripts / gensuitemodule.py
bloba1ae7744387281bfe0c762533afb3118316f64dd
1 """
2 gensuitemodule - Generate an AE suite module from an aete/aeut resource
4 Based on aete.py.
6 Reading and understanding this code is left as an exercise to the reader.
7 """
9 import MacOS
10 import os
11 import string
12 import sys
13 import types
14 import StringIO
15 import macfs
17 from Carbon.Res import *
19 def main():
20 fss, ok = macfs.PromptGetFile('Select file with aeut/aete resource:')
21 if not ok:
22 sys.exit(0)
23 processfile(fss.as_pathname())
25 def processfile(fullname):
26 """Process all resources in a single file"""
27 cur = CurResFile()
28 print fullname
29 rf = OpenRFPerm(fullname, 0, 1)
30 try:
31 UseResFile(rf)
32 resources = []
33 for i in range(Count1Resources('aete')):
34 res = Get1IndResource('aete', 1+i)
35 resources.append(res)
36 for i in range(Count1Resources('aeut')):
37 res = Get1IndResource('aeut', 1+i)
38 resources.append(res)
39 print "\nLISTING aete+aeut RESOURCES IN", `fullname`
40 aetelist = []
41 for res in resources:
42 print "decoding", res.GetResInfo(), "..."
43 data = res.data
44 aete = decode(data)
45 aetelist.append((aete, res.GetResInfo()))
46 finally:
47 if rf <> cur:
48 CloseResFile(rf)
49 UseResFile(cur)
50 # switch back (needed for dialogs in Python)
51 UseResFile(cur)
52 compileaetelist(aetelist, fullname)
54 def compileaetelist(aetelist, fullname):
55 for aete, resinfo in aetelist:
56 compileaete(aete, resinfo, fullname)
58 def decode(data):
59 """Decode a resource into a python data structure"""
60 f = StringIO.StringIO(data)
61 aete = generic(getaete, f)
62 aete = simplify(aete)
63 processed = f.tell()
64 unprocessed = len(f.read())
65 total = f.tell()
66 if unprocessed:
67 sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
68 (processed, unprocessed, total))
69 return aete
71 def simplify(item):
72 """Recursively replace singleton tuples by their constituent item"""
73 if type(item) is types.ListType:
74 return map(simplify, item)
75 elif type(item) == types.TupleType and len(item) == 2:
76 return simplify(item[1])
77 else:
78 return item
81 # Here follows the aete resource decoder.
82 # It is presented bottom-up instead of top-down because there are direct
83 # references to the lower-level part-decoders from the high-level part-decoders.
85 def getbyte(f, *args):
86 c = f.read(1)
87 if not c:
88 raise EOFError, 'in getbyte' + str(args)
89 return ord(c)
91 def getword(f, *args):
92 getalign(f)
93 s = f.read(2)
94 if len(s) < 2:
95 raise EOFError, 'in getword' + str(args)
96 return (ord(s[0])<<8) | ord(s[1])
98 def getlong(f, *args):
99 getalign(f)
100 s = f.read(4)
101 if len(s) < 4:
102 raise EOFError, 'in getlong' + str(args)
103 return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
105 def getostype(f, *args):
106 getalign(f)
107 s = f.read(4)
108 if len(s) < 4:
109 raise EOFError, 'in getostype' + str(args)
110 return s
112 def getpstr(f, *args):
113 c = f.read(1)
114 if len(c) < 1:
115 raise EOFError, 'in getpstr[1]' + str(args)
116 nbytes = ord(c)
117 if nbytes == 0: return ''
118 s = f.read(nbytes)
119 if len(s) < nbytes:
120 raise EOFError, 'in getpstr[2]' + str(args)
121 return s
123 def getalign(f):
124 if f.tell() & 1:
125 c = f.read(1)
126 ##if c <> '\0':
127 ## print 'align:', `c`
129 def getlist(f, description, getitem):
130 count = getword(f)
131 list = []
132 for i in range(count):
133 list.append(generic(getitem, f))
134 getalign(f)
135 return list
137 def alt_generic(what, f, *args):
138 print "generic", `what`, args
139 res = vageneric(what, f, args)
140 print '->', `res`
141 return res
143 def generic(what, f, *args):
144 if type(what) == types.FunctionType:
145 return apply(what, (f,) + args)
146 if type(what) == types.ListType:
147 record = []
148 for thing in what:
149 item = apply(generic, thing[:1] + (f,) + thing[1:])
150 record.append((thing[1], item))
151 return record
152 return "BAD GENERIC ARGS: %s" % `what`
154 getdata = [
155 (getostype, "type"),
156 (getpstr, "description"),
157 (getword, "flags")
159 getargument = [
160 (getpstr, "name"),
161 (getostype, "keyword"),
162 (getdata, "what")
164 getevent = [
165 (getpstr, "name"),
166 (getpstr, "description"),
167 (getostype, "suite code"),
168 (getostype, "event code"),
169 (getdata, "returns"),
170 (getdata, "accepts"),
171 (getlist, "optional arguments", getargument)
173 getproperty = [
174 (getpstr, "name"),
175 (getostype, "code"),
176 (getdata, "what")
178 getelement = [
179 (getostype, "type"),
180 (getlist, "keyform", getostype)
182 getclass = [
183 (getpstr, "name"),
184 (getostype, "class code"),
185 (getpstr, "description"),
186 (getlist, "properties", getproperty),
187 (getlist, "elements", getelement)
189 getcomparison = [
190 (getpstr, "operator name"),
191 (getostype, "operator ID"),
192 (getpstr, "operator comment"),
194 getenumerator = [
195 (getpstr, "enumerator name"),
196 (getostype, "enumerator ID"),
197 (getpstr, "enumerator comment")
199 getenumeration = [
200 (getostype, "enumeration ID"),
201 (getlist, "enumerator", getenumerator)
203 getsuite = [
204 (getpstr, "suite name"),
205 (getpstr, "suite description"),
206 (getostype, "suite ID"),
207 (getword, "suite level"),
208 (getword, "suite version"),
209 (getlist, "events", getevent),
210 (getlist, "classes", getclass),
211 (getlist, "comparisons", getcomparison),
212 (getlist, "enumerations", getenumeration)
214 getaete = [
215 (getword, "major/minor version in BCD"),
216 (getword, "language code"),
217 (getword, "script code"),
218 (getlist, "suites", getsuite)
221 def compileaete(aete, resinfo, fname):
222 """Generate code for a full aete resource. fname passed for doc purposes"""
223 [version, language, script, suites] = aete
224 major, minor = divmod(version, 256)
225 fss = macfs.FSSpec(fname)
226 creatorsignature, dummy = fss.GetCreatorType()
227 packagename = identify(os.path.basename(fname))
228 if language:
229 packagename = packagename+'_lang%d'%language
230 if script:
231 packagename = packagename+'_script%d'%script
232 if len(packagename) > 27:
233 packagename = packagename[:27]
234 macfs.SetFolder(os.path.join(sys.prefix, ':Mac:Lib:lib-scriptpackages'))
235 fss, ok = macfs.GetDirectory('Package folder for %s'%packagename)
236 if not ok:
237 return
238 pathname = fss.as_pathname()
239 packagename = os.path.split(os.path.normpath(pathname))[1]
240 fss, ok = macfs.GetDirectory('Package folder for base suite (usually StdSuites)')
241 if ok:
242 dirname, basepkgname = os.path.split(os.path.normpath(fss.as_pathname()))
243 if not dirname in sys.path:
244 sys.path.insert(0, dirname)
245 basepackage = __import__(basepkgname)
246 else:
247 basepackage = None
248 macfs.SetFolder(pathname)
249 suitelist = []
250 allprecompinfo = []
251 allsuites = []
252 for suite in suites:
253 code, suite, fss, modname, precompinfo = precompilesuite(suite, basepackage)
254 if not code:
255 continue
256 allprecompinfo = allprecompinfo + precompinfo
257 suiteinfo = suite, fss, modname
258 suitelist.append((code, modname))
259 allsuites.append(suiteinfo)
260 for suiteinfo in allsuites:
261 compilesuite(suiteinfo, major, minor, language, script, fname, basepackage, allprecompinfo)
262 fss, ok = macfs.StandardPutFile('Package module', '__init__.py')
263 if not ok:
264 return
265 fp = open(fss.as_pathname(), 'w')
266 fss.SetCreatorType('Pyth', 'TEXT')
267 fp.write('"""\n')
268 fp.write("Package generated from %s\n"%fname)
269 fp.write("Resource %s resid %d %s\n"%(resinfo[1], resinfo[0], resinfo[2]))
270 fp.write('"""\n')
271 fp.write('import aetools\n')
272 fp.write('Error = aetools.Error\n')
273 for code, modname in suitelist:
274 fp.write("import %s\n" % modname)
275 fp.write("\n\n_code_to_module = {\n")
276 for code, modname in suitelist:
277 fp.write("\t'%s' : %s,\n"%(code, modname))
278 fp.write("}\n\n")
279 fp.write("\n\n_code_to_fullname = {\n")
280 for code, modname in suitelist:
281 fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(code, packagename, modname, modname))
282 fp.write("}\n\n")
283 for code, modname in suitelist:
284 fp.write("from %s import *\n"%modname)
285 if suitelist:
286 fp.write("\n\nclass %s(%s_Events"%(packagename, suitelist[0][1]))
287 for code, modname in suitelist[1:]:
288 fp.write(",\n\t\t%s_Events"%modname)
289 fp.write(",\n\t\taetools.TalkTo):\n")
290 fp.write("\t_signature = '%s'\n\n"%creatorsignature)
291 fp.close()
293 def precompilesuite(suite, basepackage=None):
294 """Parse a single suite without generating the output. This step is needed
295 so we can resolve recursive references by suites to enums/comps/etc declared
296 in other suites"""
297 [name, desc, code, level, version, events, classes, comps, enums] = suite
299 modname = identify(name)
300 if len(modname) > 28:
301 modname = modname[:27]
302 fss, ok = macfs.StandardPutFile('Python output file', modname+'.py')
303 if not ok:
304 return None, None, None, None, None
306 pathname = fss.as_pathname()
307 modname = os.path.splitext(os.path.split(pathname)[1])[0]
309 if basepackage and basepackage._code_to_module.has_key(code):
310 # We are an extension of a baseclass (usually an application extending
311 # Standard_Suite or so). Import everything from our base module
312 basemodule = basepackage._code_to_module[code]
313 else:
314 # We are not an extension.
315 basemodule = None
317 enumsneeded = {}
318 for event in events:
319 findenumsinevent(event, enumsneeded)
321 objc = ObjectCompiler(None, basemodule)
322 for cls in classes:
323 objc.compileclass(cls)
324 for cls in classes:
325 objc.fillclasspropsandelems(cls)
326 for comp in comps:
327 objc.compilecomparison(comp)
328 for enum in enums:
329 objc.compileenumeration(enum)
331 for enum in enumsneeded.keys():
332 objc.checkforenum(enum)
334 objc.dumpindex()
336 precompinfo = objc.getprecompinfo(modname)
338 return code, suite, fss, modname, precompinfo
340 def compilesuite((suite, fss, modname), major, minor, language, script, fname, basepackage, precompinfo):
341 """Generate code for a single suite"""
342 [name, desc, code, level, version, events, classes, comps, enums] = suite
344 pathname = fss.as_pathname()
345 fp = open(fss.as_pathname(), 'w')
346 fss.SetCreatorType('Pyth', 'TEXT')
348 fp.write('"""Suite %s: %s\n' % (name, desc))
349 fp.write("Level %d, version %d\n\n" % (level, version))
350 fp.write("Generated from %s\n"%fname)
351 fp.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
352 (major, minor, language, script))
353 fp.write('"""\n\n')
355 fp.write('import aetools\n')
356 fp.write('import MacOS\n\n')
357 fp.write("_code = %s\n\n"% `code`)
358 if basepackage and basepackage._code_to_module.has_key(code):
359 # We are an extension of a baseclass (usually an application extending
360 # Standard_Suite or so). Import everything from our base module
361 fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0])
362 basemodule = basepackage._code_to_module[code]
363 else:
364 # We are not an extension.
365 basemodule = None
366 compileclassheader(fp, modname, basemodule)
368 enumsneeded = {}
369 if events:
370 for event in events:
371 compileevent(fp, event, enumsneeded)
372 else:
373 fp.write("\tpass\n\n")
375 objc = ObjectCompiler(fp, basemodule, precompinfo)
376 for cls in classes:
377 objc.compileclass(cls)
378 for cls in classes:
379 objc.fillclasspropsandelems(cls)
380 for comp in comps:
381 objc.compilecomparison(comp)
382 for enum in enums:
383 objc.compileenumeration(enum)
385 for enum in enumsneeded.keys():
386 objc.checkforenum(enum)
388 objc.dumpindex()
390 return code, modname
392 def compileclassheader(fp, name, module=None):
393 """Generate class boilerplate"""
394 classname = '%s_Events'%name
395 if module:
396 modshortname = string.split(module.__name__, '.')[-1]
397 baseclassname = '%s_Events'%modshortname
398 fp.write("class %s(%s):\n\n"%(classname, baseclassname))
399 else:
400 fp.write("class %s:\n\n"%classname)
402 def compileevent(fp, event, enumsneeded):
403 """Generate code for a single event"""
404 [name, desc, code, subcode, returns, accepts, arguments] = event
405 funcname = identify(name)
407 # generate name->keyword map
409 if arguments:
410 fp.write("\t_argmap_%s = {\n"%funcname)
411 for a in arguments:
412 fp.write("\t\t%s : %s,\n"%(`identify(a[0])`, `a[1]`))
413 fp.write("\t}\n\n")
416 # Generate function header
418 has_arg = (not is_null(accepts))
419 opt_arg = (has_arg and is_optional(accepts))
421 fp.write("\tdef %s(self, "%funcname)
422 if has_arg:
423 if not opt_arg:
424 fp.write("_object, ") # Include direct object, if it has one
425 else:
426 fp.write("_object=None, ") # Also include if it is optional
427 else:
428 fp.write("_no_object=None, ") # For argument checking
429 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
431 # Generate doc string (important, since it may be the only
432 # available documentation, due to our name-remaping)
434 fp.write('\t\t"""%s: %s\n'%(name, desc))
435 if has_arg:
436 fp.write("\t\tRequired argument: %s\n"%getdatadoc(accepts))
437 elif opt_arg:
438 fp.write("\t\tOptional argument: %s\n"%getdatadoc(accepts))
439 for arg in arguments:
440 fp.write("\t\tKeyword argument %s: %s\n"%(identify(arg[0]),
441 getdatadoc(arg[2])))
442 fp.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
443 if not is_null(returns):
444 fp.write("\t\tReturns: %s\n"%getdatadoc(returns))
445 fp.write('\t\t"""\n')
447 # Fiddle the args so everything ends up in 'arguments' dictionary
449 fp.write("\t\t_code = %s\n"% `code`)
450 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
452 # Do keyword name substitution
454 if arguments:
455 fp.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname)
456 else:
457 fp.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
459 # Stuff required arg (if there is one) into arguments
461 if has_arg:
462 fp.write("\t\t_arguments['----'] = _object\n")
463 elif opt_arg:
464 fp.write("\t\tif _object:\n")
465 fp.write("\t\t\t_arguments['----'] = _object\n")
466 else:
467 fp.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
468 fp.write("\n")
470 # Do enum-name substitution
472 for a in arguments:
473 if is_enum(a[2]):
474 kname = a[1]
475 ename = a[2][0]
476 if ename <> '****':
477 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
478 (`kname`, identify(ename)))
479 enumsneeded[ename] = 1
480 fp.write("\n")
482 # Do the transaction
484 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
485 fp.write("\t\t\t\t_arguments, _attributes)\n")
487 # Error handling
489 fp.write("\t\tif _arguments.has_key('errn'):\n")
490 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
491 fp.write("\t\t# XXXX Optionally decode result\n")
493 # Decode result
495 fp.write("\t\tif _arguments.has_key('----'):\n")
496 if is_enum(returns):
497 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
498 fp.write("\t\t\treturn _arguments['----']\n")
499 fp.write("\n")
501 # print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
502 # print "# returns", compiledata(returns)
503 # print "# accepts", compiledata(accepts)
504 # for arg in arguments:
505 # compileargument(arg)
507 def compileargument(arg):
508 [name, keyword, what] = arg
509 print "# %s (%s)" % (name, `keyword`), compiledata(what)
511 def findenumsinevent(event, enumsneeded):
512 """Find all enums for a single event"""
513 [name, desc, code, subcode, returns, accepts, arguments] = event
514 for a in arguments:
515 if is_enum(a[2]):
516 ename = a[2][0]
517 if ename <> '****':
518 enumsneeded[ename] = 1
521 # This class stores the code<->name translations for a single module. It is used
522 # to keep the information while we're compiling the module, but we also keep these objects
523 # around so if one suite refers to, say, an enum in another suite we know where to
524 # find it. Finally, if we really can't find a code, the user can add modules by
525 # hand.
527 class CodeNameMapper:
529 def __init__(self):
530 self.code2name = {
531 "property" : {},
532 "class" : {},
533 "enum" : {},
534 "comparison" : {},
536 self.name2code = {
537 "property" : {},
538 "class" : {},
539 "enum" : {},
540 "comparison" : {},
542 self.modulename = None
543 self.star_imported = 0
545 def addnamecode(self, type, name, code):
546 self.name2code[type][name] = code
547 if not self.code2name[type].has_key(code):
548 self.code2name[type][code] = name
550 def hasname(self, type, name):
551 return self.name2code[type].has_key(name)
553 def hascode(self, type, code):
554 return self.code2name[type].has_key(code)
556 def findcodename(self, type, code):
557 if not self.hascode(type, code):
558 return None, None, None
559 name = self.code2name[type][code]
560 if self.modulename and not self.star_imported:
561 qualname = '%s.%s'%(self.modulename, name)
562 else:
563 qualname = name
564 return name, qualname, self.modulename
566 def getall(self, type):
567 return self.code2name[type].items()
569 def addmodule(self, module, name, star_imported):
570 self.modulename = name
571 self.star_imported = star_imported
572 for code, name in module._propdeclarations.items():
573 self.addnamecode('property', name, code)
574 for code, name in module._classdeclarations.items():
575 self.addnamecode('class', name, code)
576 for code in module._enumdeclarations.keys():
577 self.addnamecode('enum', '_Enum_'+identify(code), code)
578 for code, name in module._compdeclarations.items():
579 self.addnamecode('comparison', name, code)
581 def prepareforexport(self, name=None):
582 if not self.modulename:
583 self.modulename = name
584 return self
586 class ObjectCompiler:
587 def __init__(self, fp, basesuite=None, othernamemappers=None):
588 self.fp = fp
589 self.basesuite = basesuite
590 self.namemappers = [CodeNameMapper()]
591 if othernamemappers:
592 self.othernamemappers = othernamemappers[:]
593 else:
594 self.othernamemappers = []
595 if basesuite:
596 basemapper = CodeNameMapper()
597 basemapper.addmodule(basesuite, '', 1)
598 self.namemappers.append(basemapper)
600 def getprecompinfo(self, modname):
601 list = []
602 for mapper in self.namemappers:
603 emapper = mapper.prepareforexport(modname)
604 if emapper:
605 list.append(emapper)
606 return list
608 def findcodename(self, type, code):
609 while 1:
610 # First try: check whether we already know about this code.
611 for mapper in self.namemappers:
612 if mapper.hascode(type, code):
613 return mapper.findcodename(type, code)
614 # Second try: maybe one of the other modules knows about it.
615 for mapper in self.othernamemappers:
616 if mapper.hascode(type, code):
617 self.othernamemappers.remove(mapper)
618 self.namemappers.append(mapper)
619 if self.fp:
620 self.fp.write("import %s\n"%mapper.modulename)
621 break
622 else:
623 # If all this has failed we ask the user for a guess on where it could
624 # be and retry.
625 if self.fp:
626 m = self.askdefinitionmodule(type, code)
627 else:
628 m = None
629 if not m: return None, None, None
630 mapper = CodeNameMapper()
631 mapper.addmodule(m, m.__name__, 0)
632 self.namemappers.append(mapper)
634 def askdefinitionmodule(self, type, code):
635 fss, ok = macfs.PromptGetFile('Where is %s %s declared?'%(type, code))
636 if not ok: return
637 path, file = os.path.split(fss.as_pathname())
638 modname = os.path.splitext(file)[0]
639 if not path in sys.path:
640 sys.path.insert(0, path)
641 m = __import__(modname)
642 self.fp.write("import %s\n"%modname)
643 return m
645 def compileclass(self, cls):
646 [name, code, desc, properties, elements] = cls
647 pname = identify(name)
648 if self.namemappers[0].hascode('class', code):
649 # plural forms and such
650 othername, dummy, dummy = self.namemappers[0].findcodename('class', code)
651 if self.fp:
652 self.fp.write("\n%s = %s\n"%(pname, othername))
653 else:
654 if self.fp:
655 self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
656 self.fp.write('\t"""%s - %s """\n' % (name, desc))
657 self.fp.write('\twant = %s\n' % `code`)
658 self.namemappers[0].addnamecode('class', pname, code)
659 for prop in properties:
660 self.compileproperty(prop)
661 for elem in elements:
662 self.compileelement(elem)
664 def compileproperty(self, prop):
665 [name, code, what] = prop
666 if code == 'c@#!':
667 # Something silly with plurals. Skip it.
668 return
669 pname = identify(name)
670 if self.namemappers[0].hascode('property', code):
671 # plural forms and such
672 othername, dummy, dummy = self.namemappers[0].findcodename('property', code)
673 if pname == othername:
674 return
675 if self.fp:
676 self.fp.write("\n%s = %s\n"%(pname, othername))
677 else:
678 if self.fp:
679 self.fp.write("class %s(aetools.NProperty):\n" % pname)
680 self.fp.write('\t"""%s - %s """\n' % (name, what[1]))
681 self.fp.write("\twhich = %s\n" % `code`)
682 self.fp.write("\twant = %s\n" % `what[0]`)
683 self.namemappers[0].addnamecode('property', pname, code)
685 def compileelement(self, elem):
686 [code, keyform] = elem
687 if self.fp:
688 self.fp.write("# element %s as %s\n" % (`code`, keyform))
690 def fillclasspropsandelems(self, cls):
691 [name, code, desc, properties, elements] = cls
692 cname = identify(name)
693 if self.namemappers[0].hascode('class', code) and \
694 self.namemappers[0].findcodename('class', code)[0] != cname:
695 # This is an other name (plural or so) for something else. Skip.
696 return
697 plist = []
698 elist = []
699 for prop in properties:
700 [pname, pcode, what] = prop
701 if pcode == 'c@#!':
702 continue
703 pname = identify(pname)
704 plist.append(pname)
705 for elem in elements:
706 [ecode, keyform] = elem
707 if ecode == 'c@#!':
708 continue
709 name, ename, module = self.findcodename('class', ecode)
710 if not name:
711 if self.fp:
712 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
713 else:
714 elist.append((name, ename))
716 if self.fp:
717 self.fp.write("%s._propdict = {\n"%cname)
718 for n in plist:
719 self.fp.write("\t'%s' : %s,\n"%(n, n))
720 self.fp.write("}\n")
721 self.fp.write("%s._elemdict = {\n"%cname)
722 for n, fulln in elist:
723 self.fp.write("\t'%s' : %s,\n"%(n, fulln))
724 self.fp.write("}\n")
726 def compilecomparison(self, comp):
727 [name, code, comment] = comp
728 iname = identify(name)
729 self.namemappers[0].addnamecode('comparison', iname, code)
730 if self.fp:
731 self.fp.write("class %s(aetools.NComparison):\n" % iname)
732 self.fp.write('\t"""%s - %s """\n' % (name, comment))
734 def compileenumeration(self, enum):
735 [code, items] = enum
736 name = "_Enum_%s" % identify(code)
737 if self.fp:
738 self.fp.write("%s = {\n" % name)
739 for item in items:
740 self.compileenumerator(item)
741 self.fp.write("}\n\n")
742 self.namemappers[0].addnamecode('enum', name, code)
743 return code
745 def compileenumerator(self, item):
746 [name, code, desc] = item
747 self.fp.write("\t%s : %s,\t# %s\n" % (`name`, `code`, desc))
749 def checkforenum(self, enum):
750 """This enum code is used by an event. Make sure it's available"""
751 name, fullname, module = self.findcodename('enum', enum)
752 if not name:
753 if self.fp:
754 self.fp.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum), enum))
755 return
756 if module:
757 if self.fp:
758 self.fp.write("from %s import %s\n"%(module, name))
760 def dumpindex(self):
761 if not self.fp:
762 return
763 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
764 self.fp.write("_classdeclarations = {\n")
765 for k, v in self.namemappers[0].getall('class'):
766 self.fp.write("\t%s : %s,\n" % (`k`, v))
767 self.fp.write("}\n")
768 self.fp.write("\n_propdeclarations = {\n")
769 for k, v in self.namemappers[0].getall('property'):
770 self.fp.write("\t%s : %s,\n" % (`k`, v))
771 self.fp.write("}\n")
772 self.fp.write("\n_compdeclarations = {\n")
773 for k, v in self.namemappers[0].getall('comparison'):
774 self.fp.write("\t%s : %s,\n" % (`k`, v))
775 self.fp.write("}\n")
776 self.fp.write("\n_enumdeclarations = {\n")
777 for k, v in self.namemappers[0].getall('enum'):
778 self.fp.write("\t%s : %s,\n" % (`k`, v))
779 self.fp.write("}\n")
781 def compiledata(data):
782 [type, description, flags] = data
783 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
785 def is_null(data):
786 return data[0] == 'null'
788 def is_optional(data):
789 return (data[2] & 0x8000)
791 def is_enum(data):
792 return (data[2] & 0x2000)
794 def getdatadoc(data):
795 [type, descr, flags] = data
796 if descr:
797 return descr
798 if type == '****':
799 return 'anything'
800 if type == 'obj ':
801 return 'an AE object reference'
802 return "undocumented, typecode %s"%`type`
804 dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
805 def compiledataflags(flags):
806 bits = []
807 for i in range(16):
808 if flags & (1<<i):
809 if i in dataflagdict.keys():
810 bits.append(dataflagdict[i])
811 else:
812 bits.append(`i`)
813 return '[%s]' % string.join(bits)
815 # XXXX Do we have a set of python keywords somewhere?
816 illegal_ids = [ "for", "in", "from", "and", "or", "not", "print", "class", "return",
817 "def" ]
819 def identify(str):
820 """Turn any string into an identifier:
821 - replace space by _
822 - replace other illegal chars by _xx_ (hex code)
823 - prepend _ if the result is a python keyword
825 if not str:
826 return "_empty_ae_name"
827 rv = ''
828 ok = string.ascii_letters + '_'
829 ok2 = ok + string.digits
830 for c in str:
831 if c in ok:
832 rv = rv + c
833 elif c == ' ':
834 rv = rv + '_'
835 else:
836 rv = rv + '_%02.2x_'%ord(c)
837 ok = ok2
838 if rv in illegal_ids:
839 rv = '_' + rv
840 return rv
842 # Call the main program
844 if __name__ == '__main__':
845 main()
846 sys.exit(1)