Use full package paths in imports.
[python/dscho.git] / Mac / scripts / gensuitemodule.py
blob3e2366165ff71773854474910edfdead62eec8cf
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
16 import keyword
17 import macresource
19 from Carbon.Res import *
21 DEFAULT_PACKAGEFOLDER=os.path.join(sys.prefix, 'Mac', 'Lib', 'lib-scriptpackages')
23 def main():
24 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())
33 def processfile(fullname):
34 """Process all resources in a single file"""
35 cur = CurResFile()
36 print "Processing", fullname
37 rf = macresource.open_pathname(fullname)
38 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`
48 aetelist = []
49 for res in resources:
50 print "decoding", res.GetResInfo(), "..."
51 data = res.data
52 aete = decode(data)
53 aetelist.append((aete, res.GetResInfo()))
54 finally:
55 if rf <> cur:
56 CloseResFile(rf)
57 UseResFile(cur)
58 # switch back (needed for dialogs in Python)
59 UseResFile(cur)
60 compileaetelist(aetelist, fullname)
62 def compileaetelist(aetelist, fullname):
63 for aete, resinfo in aetelist:
64 compileaete(aete, resinfo, fullname)
66 def 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
79 def 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
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.
93 def getbyte(f, *args):
94 c = f.read(1)
95 if not c:
96 raise EOFError, 'in getbyte' + str(args)
97 return ord(c)
99 def 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])
106 def 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])
113 def 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
120 def 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
131 def getalign(f):
132 if f.tell() & 1:
133 c = f.read(1)
134 ##if c <> '\0':
135 ## print 'align:', `c`
137 def 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
145 def alt_generic(what, f, *args):
146 print "generic", `what`, args
147 res = vageneric(what, f, args)
148 print '->', `res`
149 return res
151 def 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`
162 getdata = [
163 (getostype, "type"),
164 (getpstr, "description"),
165 (getword, "flags")
167 getargument = [
168 (getpstr, "name"),
169 (getostype, "keyword"),
170 (getdata, "what")
172 getevent = [
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)
181 getproperty = [
182 (getpstr, "name"),
183 (getostype, "code"),
184 (getdata, "what")
186 getelement = [
187 (getostype, "type"),
188 (getlist, "keyform", getostype)
190 getclass = [
191 (getpstr, "name"),
192 (getostype, "class code"),
193 (getpstr, "description"),
194 (getlist, "properties", getproperty),
195 (getlist, "elements", getelement)
197 getcomparison = [
198 (getpstr, "operator name"),
199 (getostype, "operator ID"),
200 (getpstr, "operator comment"),
202 getenumerator = [
203 (getpstr, "enumerator name"),
204 (getostype, "enumerator ID"),
205 (getpstr, "enumerator comment")
207 getenumeration = [
208 (getostype, "enumeration ID"),
209 (getlist, "enumerator", getenumerator)
211 getsuite = [
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)
222 getaete = [
223 (getword, "major/minor version in BCD"),
224 (getword, "language code"),
225 (getword, "script code"),
226 (getlist, "suites", getsuite)
229 def compileaete(aete, resinfo, fname):
230 """Generate code for a full aete resource. fname passed for doc purposes"""
231 [version, language, script, suites] = aete
232 major, minor = divmod(version, 256)
233 fss = macfs.FSSpec(fname)
234 creatorsignature, dummy = fss.GetCreatorType()
235 packagename = identify(os.path.splitext(os.path.basename(fname))[0])
236 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]
242 macfs.SetFolder(DEFAULT_PACKAGEFOLDER)
243 fss, ok = macfs.GetDirectory('Create and select package folder for %s'%packagename)
244 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 = []
258 allprecompinfo = []
259 allsuites = []
260 for suite in suites:
261 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)
270 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')
280 fp.write('Error = aetools.Error\n')
281 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:
289 fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(code, packagename, modname, modname))
290 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:]:
296 fp.write(",\n\t\t%s_Events"%modname)
297 fp.write(",\n\t\taetools.TalkTo):\n")
298 fp.write("\t_signature = %s\n\n"%`creatorsignature`)
299 fp.close()
301 def 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"""
305 [name, desc, code, level, version, events, classes, comps, enums] = suite
307 modname = identify(name)
308 if len(modname) > 28:
309 modname = modname[:27]
310 fss, ok = macfs.StandardPutFile('Python output file', modname+'.py')
311 if not ok:
312 return None, None, None, None, None
314 pathname = fss.as_pathname()
315 modname = os.path.splitext(os.path.split(pathname)[1])[0]
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
325 enumsneeded = {}
326 for event in events:
327 findenumsinevent(event, enumsneeded)
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)
339 for enum in enumsneeded.keys():
340 objc.checkforenum(enum)
342 objc.dumpindex()
344 precompinfo = objc.getprecompinfo(modname)
346 return code, suite, fss, modname, precompinfo
348 def 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
352 pathname = fss.as_pathname()
353 fp = open(fss.as_pathname(), 'w')
354 fss.SetCreatorType('Pyth', 'TEXT')
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')
363 fp.write('import aetools\n')
364 fp.write('import MacOS\n\n')
365 fp.write("_code = %s\n\n"% `code`)
366 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
369 fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0])
370 basemodule = basepackage._code_to_module[code]
371 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()]
375 else:
376 # We are not an extension.
377 basemodule = None
378 compileclassheader(fp, modname, basemodule)
380 enumsneeded = {}
381 if events:
382 for event in events:
383 compileevent(fp, event, enumsneeded)
384 else:
385 fp.write("\tpass\n\n")
387 objc = ObjectCompiler(fp, basemodule, precompinfo)
388 for cls in classes:
389 objc.compileclass(cls)
390 for cls in classes:
391 objc.fillclasspropsandelems(cls)
392 for comp in comps:
393 objc.compilecomparison(comp)
394 for enum in enums:
395 objc.compileenumeration(enum)
397 for enum in enumsneeded.keys():
398 objc.checkforenum(enum)
400 objc.dumpindex()
402 return code, modname
404 def compileclassheader(fp, name, module=None):
405 """Generate class boilerplate"""
406 classname = '%s_Events'%name
407 if module:
408 modshortname = string.split(module.__name__, '.')[-1]
409 baseclassname = '%s_Events'%modshortname
410 fp.write("class %s(%s):\n\n"%(classname, baseclassname))
411 else:
412 fp.write("class %s:\n\n"%classname)
414 def compileevent(fp, event, enumsneeded):
415 """Generate code for a single event"""
416 [name, desc, code, subcode, returns, accepts, arguments] = event
417 funcname = identify(name)
419 # generate name->keyword map
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")
428 # Generate function header
430 has_arg = (not is_null(accepts))
431 opt_arg = (has_arg and is_optional(accepts))
433 fp.write("\tdef %s(self, "%funcname)
434 if has_arg:
435 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
439 else:
440 fp.write("_no_object=None, ") # For argument checking
441 fp.write("_attributes={}, **_arguments):\n") # include attribute dict and args
443 # Generate doc string (important, since it may be the only
444 # available documentation, due to our name-remaping)
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')
459 # Fiddle the args so everything ends up in 'arguments' dictionary
461 fp.write("\t\t_code = %s\n"% `code`)
462 fp.write("\t\t_subcode = %s\n\n"% `subcode`)
464 # Do keyword name substitution
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")
471 # Stuff required arg (if there is one) into arguments
473 if has_arg:
474 fp.write("\t\t_arguments['----'] = _object\n")
475 elif opt_arg:
476 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")
480 fp.write("\n")
482 # Do enum-name substitution
484 for a in arguments:
485 if is_enum(a[2]):
486 kname = a[1]
487 ename = a[2][0]
488 if ename <> '****':
489 fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
490 (`kname`, identify(ename)))
491 enumsneeded[ename] = 1
492 fp.write("\n")
494 # Do the transaction
496 fp.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
497 fp.write("\t\t\t\t_arguments, _attributes)\n")
499 # Error handling
501 fp.write("\t\tif _arguments.get('errn', 0):\n")
502 fp.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
503 fp.write("\t\t# XXXX Optionally decode result\n")
505 # Decode result
507 fp.write("\t\tif _arguments.has_key('----'):\n")
508 if is_enum(returns):
509 fp.write("\t\t\t# XXXX Should do enum remapping here...\n")
510 fp.write("\t\t\treturn _arguments['----']\n")
511 fp.write("\n")
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)
519 def compileargument(arg):
520 [name, keyword, what] = arg
521 print "# %s (%s)" % (name, `keyword`), compiledata(what)
523 def 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
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.
539 class CodeNameMapper:
541 def __init__(self):
542 self.code2name = {
543 "property" : {},
544 "class" : {},
545 "enum" : {},
546 "comparison" : {},
548 self.name2code = {
549 "property" : {},
550 "class" : {},
551 "enum" : {},
552 "comparison" : {},
554 self.modulename = None
555 self.star_imported = 0
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
562 def hasname(self, type, name):
563 return self.name2code[type].has_key(name)
565 def hascode(self, type, code):
566 return self.code2name[type].has_key(code)
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
578 def getall(self, type):
579 return self.code2name[type].items()
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)
593 def prepareforexport(self, name=None):
594 if not self.modulename:
595 self.modulename = name
596 return self
598 class ObjectCompiler:
599 def __init__(self, fp, basesuite=None, othernamemappers=None):
600 self.fp = fp
601 self.basesuite = basesuite
602 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)
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
620 def findcodename(self, type, code):
621 while 1:
622 # 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)
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
657 def compileclass(self, cls):
658 [name, code, desc, properties, elements] = cls
659 pname = identify(name)
660 if self.namemappers[0].hascode('class', code):
661 # plural forms and such
662 othername, dummy, dummy = self.namemappers[0].findcodename('class', code)
663 if self.fp:
664 self.fp.write("\n%s = %s\n"%(pname, othername))
665 else:
666 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)
671 for prop in properties:
672 self.compileproperty(prop)
673 for elem in elements:
674 self.compileelement(elem)
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)
682 if self.namemappers[0].hascode('property', code):
683 # plural forms and such
684 othername, dummy, dummy = self.namemappers[0].findcodename('property', code)
685 if pname == othername:
686 return
687 if self.fp:
688 self.fp.write("\n%s = %s\n"%(pname, othername))
689 else:
690 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]`)
695 self.namemappers[0].addnamecode('property', pname, code)
697 def compileelement(self, elem):
698 [code, keyform] = elem
699 if self.fp:
700 self.fp.write("# element %s as %s\n" % (`code`, keyform))
702 def fillclasspropsandelems(self, cls):
703 [name, code, desc, properties, elements] = cls
704 cname = identify(name)
705 if self.namemappers[0].hascode('class', code) and \
706 self.namemappers[0].findcodename('class', code)[0] != cname:
707 # 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:
723 if self.fp:
724 self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`))
725 else:
726 elist.append((name, ename))
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")
738 def compilecomparison(self, comp):
739 [name, code, comment] = comp
740 iname = identify(name)
741 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))
746 def compileenumeration(self, enum):
747 [code, items] = enum
748 name = "_Enum_%s" % identify(code)
749 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)
755 return code
757 def compileenumerator(self, item):
758 [name, code, desc] = item
759 self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, desc))
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:
765 if self.fp:
766 self.fp.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum), enum))
767 return
768 if module:
769 if self.fp:
770 self.fp.write("from %s import %s\n"%(module, name))
772 def dumpindex(self):
773 if not self.fp:
774 return
775 self.fp.write("\n#\n# Indices of types declared in this module\n#\n")
776 self.fp.write("_classdeclarations = {\n")
777 for k, v in self.namemappers[0].getall('class'):
778 self.fp.write("\t%s : %s,\n" % (`k`, v))
779 self.fp.write("}\n")
780 self.fp.write("\n_propdeclarations = {\n")
781 for k, v in self.namemappers[0].getall('property'):
782 self.fp.write("\t%s : %s,\n" % (`k`, v))
783 self.fp.write("}\n")
784 self.fp.write("\n_compdeclarations = {\n")
785 for k, v in self.namemappers[0].getall('comparison'):
786 self.fp.write("\t%s : %s,\n" % (`k`, v))
787 self.fp.write("}\n")
788 self.fp.write("\n_enumdeclarations = {\n")
789 for k, v in self.namemappers[0].getall('enum'):
790 self.fp.write("\t%s : %s,\n" % (`k`, v))
791 self.fp.write("}\n")
793 def compiledata(data):
794 [type, description, flags] = data
795 return "%s -- %s %s" % (`type`, `description`, compiledataflags(flags))
797 def is_null(data):
798 return data[0] == 'null'
800 def is_optional(data):
801 return (data[2] & 0x8000)
803 def is_enum(data):
804 return (data[2] & 0x2000)
806 def 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`
816 dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
817 def 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)
827 def 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
833 if not str:
834 return "_empty_ae_name"
835 rv = ''
836 ok = string.ascii_letters + '_'
837 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
846 if keyword.iskeyword(rv):
847 rv = '_' + rv
848 return rv
850 # Call the main program
852 if __name__ == '__main__':
853 main()
854 sys.exit(1)
855 print identify('for')