diff options
Diffstat (limited to 'Mac/scripts/gensuitemodule.py')
-rw-r--r-- | Mac/scripts/gensuitemodule.py | 356 |
1 files changed, 239 insertions, 117 deletions
diff --git a/Mac/scripts/gensuitemodule.py b/Mac/scripts/gensuitemodule.py index 85cbe0d..df1e455 100644 --- a/Mac/scripts/gensuitemodule.py +++ b/Mac/scripts/gensuitemodule.py @@ -247,10 +247,18 @@ def compileaete(aete, resinfo, fname): basepackage = None macfs.SetFolder(pathname) suitelist = [] + allprecompinfo = [] + allsuites = [] for suite in suites: - code, modname = compilesuite(suite, major, minor, language, script, fname, basepackage) - if modname: - suitelist.append((code, modname)) + code, suite, fss, modname, precompinfo = precompilesuite(suite, basepackage) + if not code: + continue + allprecompinfo = allprecompinfo + precompinfo + suiteinfo = suite, fss, modname + suitelist.append((code, modname)) + allsuites.append(suiteinfo) + for suiteinfo in allsuites: + compilesuite(suiteinfo, major, minor, language, script, fname, basepackage, allprecompinfo) fss, ok = macfs.StandardPutFile('Package module', '__init__.py') if not ok: return @@ -269,20 +277,22 @@ def compileaete(aete, resinfo, fname): fp.write("}\n\n") fp.write("\n\n_code_to_fullname = {\n") for code, modname in suitelist: - fp.write("\t'%s' : '%s.%s',\n"%(code, packagename, modname)) + fp.write("\t'%s' : ('%s.%s', '%s'),\n"%(code, packagename, modname, modname)) fp.write("}\n\n") for code, modname in suitelist: fp.write("from %s import *\n"%modname) if suitelist: fp.write("\n\nclass %s(%s_Events"%(packagename, suitelist[0][1])) for code, modname in suitelist[1:]: - fp.write(",\n\t%s_Events"%modname) - fp.write(",\n\taetools.TalkTo):\n") + fp.write(",\n\t\t%s_Events"%modname) + fp.write(",\n\t\taetools.TalkTo):\n") fp.write("\t_signature = '%s'\n\n"%creatorsignature) fp.close() - -def compilesuite(suite, major, minor, language, script, fname, basepackage=None): - """Generate code for a single suite""" + +def precompilesuite(suite, basepackage=None): + """Parse a single suite without generating the output. This step is needed + so we can resolve recursive references by suites to enums/comps/etc declared + in other suites""" [name, desc, code, level, version, events, classes, comps, enums] = suite modname = identify(name) @@ -290,9 +300,47 @@ def compilesuite(suite, major, minor, language, script, fname, basepackage=None) modname = modname[:27] fss, ok = macfs.StandardPutFile('Python output file', modname+'.py') if not ok: - return None, None + return None, None, None, None, None + pathname = fss.as_pathname() modname = os.path.splitext(os.path.split(pathname)[1])[0] + + if basepackage and basepackage._code_to_module.has_key(code): + # We are an extension of a baseclass (usually an application extending + # Standard_Suite or so). Import everything from our base module + basemodule = basepackage._code_to_module[code] + else: + # We are not an extension. + basemodule = None + + enumsneeded = {} + for event in events: + findenumsinevent(event, enumsneeded) + + objc = ObjectCompiler(None, basemodule) + for cls in classes: + objc.compileclass(cls) + for cls in classes: + objc.fillclasspropsandelems(cls) + for comp in comps: + objc.compilecomparison(comp) + for enum in enums: + objc.compileenumeration(enum) + + for enum in enumsneeded.keys(): + objc.checkforenum(enum) + + objc.dumpindex() + + precompinfo = objc.getprecompinfo(modname) + + return code, suite, fss, modname, precompinfo + +def compilesuite((suite, fss, modname), major, minor, language, script, fname, basepackage, precompinfo): + """Generate code for a single suite""" + [name, desc, code, level, version, events, classes, comps, enums] = suite + + pathname = fss.as_pathname() fp = open(fss.as_pathname(), 'w') fss.SetCreatorType('Pyth', 'TEXT') @@ -309,7 +357,7 @@ def compilesuite(suite, major, minor, language, script, fname, basepackage=None) if basepackage and basepackage._code_to_module.has_key(code): # We are an extension of a baseclass (usually an application extending # Standard_Suite or so). Import everything from our base module - fp.write('from %s import *\n'%basepackage._code_to_fullname[code]) + fp.write('from %s import *\n'%basepackage._code_to_fullname[code][0]) basemodule = basepackage._code_to_module[code] else: # We are not an extension. @@ -323,7 +371,7 @@ def compilesuite(suite, major, minor, language, script, fname, basepackage=None) else: fp.write("\tpass\n\n") - objc = ObjectCompiler(fp, basemodule) + objc = ObjectCompiler(fp, basemodule, precompinfo) for cls in classes: objc.compileclass(cls) for cls in classes: @@ -343,8 +391,10 @@ def compilesuite(suite, major, minor, language, script, fname, basepackage=None) def compileclassheader(fp, name, module=None): """Generate class boilerplate""" classname = '%s_Events'%name - if module and hasattr(module, classname): - fp.write("class %s(%s):\n\n"%(classname, classname)) + if module: + modshortname = string.split(module.__name__, '.')[-1] + baseclassname = '%s_Events'%modshortname + fp.write("class %s(%s):\n\n"%(classname, baseclassname)) else: fp.write("class %s:\n\n"%classname) @@ -457,69 +507,128 @@ def compileargument(arg): [name, keyword, what] = arg print "# %s (%s)" % (name, `keyword`), compiledata(what) +def findenumsinevent(event, enumsneeded): + """Find all enums for a single event""" + [name, desc, code, subcode, returns, accepts, arguments] = event + for a in arguments: + if is_enum(a[2]): + ename = a[2][0] + if ename <> '****': + enumsneeded[ename] = 1 + +# +# This class stores the code<->name translations for a single module. It is used +# to keep the information while we're compiling the module, but we also keep these objects +# around so if one suite refers to, say, an enum in another suite we know where to +# find it. Finally, if we really can't find a code, the user can add modules by +# hand. +# +class CodeNameMapper: + + def __init__(self): + self.code2name = { + "property" : {}, + "class" : {}, + "enum" : {}, + "comparison" : {}, + } + self.name2code = { + "property" : {}, + "class" : {}, + "enum" : {}, + "comparison" : {}, + } + self.modulename = None + self.star_imported = 0 + + def addnamecode(self, type, name, code): + self.name2code[type][name] = code + if not self.code2name[type].has_key(code): + self.code2name[type][code] = name + + def hasname(self, type, name): + return self.name2code[type].has_key(name) + + def hascode(self, type, code): + return self.code2name[type].has_key(code) + + def findcodename(self, type, code): + if not self.hascode(type, code): + return None, None, None + name = self.code2name[type][code] + if self.modulename and not self.star_imported: + qualname = '%s.%s'%(self.modulename, name) + else: + qualname = name + return name, qualname, self.modulename + + def getall(self, type): + return self.code2name[type].items() + + def addmodule(self, module, name, star_imported): + self.modulename = name + self.star_imported = star_imported + for code, name in module._propdeclarations.items(): + self.addnamecode('property', name, code) + for code, name in module._classdeclarations.items(): + self.addnamecode('class', name, code) + for code in module._enumdeclarations.keys(): + self.addnamecode('enum', '_Enum_'+identify(code), code) + for code, name in module._compdeclarations.items(): + self.addnamecode('comparison', name, code) + + def prepareforexport(self, name=None): + if not self.modulename: + self.modulename = name + return self + class ObjectCompiler: - def __init__(self, fp, basesuite=None): + def __init__(self, fp, basesuite=None, othernamemappers=None): self.fp = fp - self.propnames = {} - self.classnames = {} - self.propcodes = {} - self.classcodes = {} - self.compcodes = {} - self.enumcodes = {} - self.othersuites = [] self.basesuite = basesuite + self.namemappers = [CodeNameMapper()] + if othernamemappers: + self.othernamemappers = othernamemappers[:] + else: + self.othernamemappers = [] + if basesuite: + basemapper = CodeNameMapper() + basemapper.addmodule(basesuite, '', 1) + self.namemappers.append(basemapper) + + def getprecompinfo(self, modname): + list = [] + for mapper in self.namemappers: + emapper = mapper.prepareforexport(modname) + if emapper: + list.append(emapper) + return list def findcodename(self, type, code): while 1: - if type == 'property': - # First we check whether we ourselves have defined it - if self.propcodes.has_key(code): - return self.propcodes[code], self.propcodes[code], None - # Next we check whether our base suite module has defined it - if self.basesuite and self.basesuite._propdeclarations.has_key(code): - name = self.basesuite._propdeclarations[code].__name__ - return name, name, None - # Finally we test whether one of the other suites we know about has defined - # it. - for s in self.othersuites: - if s._propdeclarations.has_key(code): - name = s._propdeclarations[code].__name__ - return name, '%s.%s' % (s.__name__, name), s.__name__ - if type == 'class': - if self.classcodes.has_key(code): - return self.classcodes[code], self.classcodes[code], None - if self.basesuite and self.basesuite._classdeclarations.has_key(code): - name = self.basesuite._classdeclarations[code].__name__ - return name, name, None - for s in self.othersuites: - if s._classdeclarations.has_key(code): - name = s._classdeclarations[code].__name__ - return name, '%s.%s' % (s.__name__, name), s.__name__ - if type == 'enum': - if self.enumcodes.has_key(code): - return self.enumcodes[code], self.enumcodes[code], None - if self.basesuite and self.basesuite._enumdeclarations.has_key(code): - name = '_Enum_' + identify(code) - return name, name, None - for s in self.othersuites: - if s._enumdeclarations.has_key(code): - name = '_Enum_' + identify(code) - return name, '%s.%s' % (s.__name__, name), s.__name__ - if type == 'comparison': - if self.compcodes.has_key(code): - return self.compcodes[code], self.compcodes[code], None - if self.basesuite and self.basesuite._compdeclarations.has_key(code): - name = self.basesuite._compdeclarations[code].__name__ - return name, name, None - for s in self.othersuites: - if s._compdeclarations.has_key(code): - name = s._compdeclarations[code].__name__ - return name, '%s.%s' % (s.__name__, name), s.__name__ - # If all this has failed we ask the user for a guess on where it could - # be and retry. - m = self.askdefinitionmodule(type, code) - if not m: return None, None, None - self.othersuites.append(m) + # First try: check whether we already know about this code. + for mapper in self.namemappers: + if mapper.hascode(type, code): + return mapper.findcodename(type, code) + # Second try: maybe one of the other modules knows about it. + for mapper in self.othernamemappers: + if mapper.hascode(type, code): + self.othernamemappers.remove(mapper) + self.namemappers.append(mapper) + if self.fp: + self.fp.write("import %s\n"%mapper.modulename) + break + else: + # If all this has failed we ask the user for a guess on where it could + # be and retry. + if self.fp: + m = self.askdefinitionmodule(type, code) + else: + m = None + if not m: return None, None, None + mapper = CodeNameMapper() + mapper.addmodule(m, m.__name__, 0) + self.namemappers.append(mapper) def askdefinitionmodule(self, type, code): fss, ok = macfs.PromptGetFile('Where is %s %s declared?'%(type, code)) @@ -535,16 +644,17 @@ class ObjectCompiler: def compileclass(self, cls): [name, code, desc, properties, elements] = cls pname = identify(name) - if self.classcodes.has_key(code): + if self.namemappers[0].hascode('class', code): # plural forms and such - self.fp.write("\n%s = %s\n"%(pname, self.classcodes[code])) - self.classnames[pname] = code + othername, dummy, dummy = self.namemappers[0].findcodename('class', code) + if self.fp: + self.fp.write("\n%s = %s\n"%(pname, othername)) else: - self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname) - self.fp.write('\t"""%s - %s """\n' % (name, desc)) - self.fp.write('\twant = %s\n' % `code`) - self.classnames[pname] = code - self.classcodes[code] = pname + if self.fp: + self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname) + self.fp.write('\t"""%s - %s """\n' % (name, desc)) + self.fp.write('\twant = %s\n' % `code`) + self.namemappers[0].addnamecode('class', pname, code) for prop in properties: self.compileproperty(prop) for elem in elements: @@ -556,24 +666,28 @@ class ObjectCompiler: # Something silly with plurals. Skip it. return pname = identify(name) - if self.propcodes.has_key(code): - self.fp.write("# repeated property %s %s\n"%(pname, what[1])) + if self.namemappers[0].hascode('property', code): + # XXXX Why don't we handle these the same as classes?? + if self.fp: + self.fp.write("# repeated property %s %s\n"%(pname, what[1])) else: - self.fp.write("class %s(aetools.NProperty):\n" % pname) - self.fp.write('\t"""%s - %s """\n' % (name, what[1])) - self.fp.write("\twhich = %s\n" % `code`) - self.fp.write("\twant = %s\n" % `what[0]`) - self.propnames[pname] = code - self.propcodes[code] = pname + if self.fp: + self.fp.write("class %s(aetools.NProperty):\n" % pname) + self.fp.write('\t"""%s - %s """\n' % (name, what[1])) + self.fp.write("\twhich = %s\n" % `code`) + self.fp.write("\twant = %s\n" % `what[0]`) + self.namemappers[0].addnamecode('property', pname, code) def compileelement(self, elem): [code, keyform] = elem - self.fp.write("# element %s as %s\n" % (`code`, keyform)) + if self.fp: + self.fp.write("# element %s as %s\n" % (`code`, keyform)) def fillclasspropsandelems(self, cls): [name, code, desc, properties, elements] = cls cname = identify(name) - if self.classcodes[code] != cname: + if self.namemappers[0].hascode('class', code) and \ + self.namemappers[0].findcodename('class', code)[0] != cname: # This is an other name (plural or so) for something else. Skip. return plist = [] @@ -590,34 +704,38 @@ class ObjectCompiler: continue name, ename, module = self.findcodename('class', ecode) if not name: - self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`)) + if self.fp: + self.fp.write("# XXXX %s element %s not found!!\n"%(cname, `ecode`)) else: elist.append((name, ename)) - - self.fp.write("%s._propdict = {\n"%cname) - for n in plist: - self.fp.write("\t'%s' : %s,\n"%(n, n)) - self.fp.write("}\n") - self.fp.write("%s._elemdict = {\n"%cname) - for n, fulln in elist: - self.fp.write("\t'%s' : %s,\n"%(n, fulln)) - self.fp.write("}\n") + + if self.fp: + self.fp.write("%s._propdict = {\n"%cname) + for n in plist: + self.fp.write("\t'%s' : %s,\n"%(n, n)) + self.fp.write("}\n") + self.fp.write("%s._elemdict = {\n"%cname) + for n, fulln in elist: + self.fp.write("\t'%s' : %s,\n"%(n, fulln)) + self.fp.write("}\n") def compilecomparison(self, comp): [name, code, comment] = comp iname = identify(name) - self.compcodes[code] = iname - self.fp.write("class %s(aetools.NComparison):\n" % iname) - self.fp.write('\t"""%s - %s """\n' % (name, comment)) + self.namemappers[0].addnamecode('comparison', iname, code) + if self.fp: + self.fp.write("class %s(aetools.NComparison):\n" % iname) + self.fp.write('\t"""%s - %s """\n' % (name, comment)) def compileenumeration(self, enum): [code, items] = enum name = "_Enum_%s" % identify(code) - self.fp.write("%s = {\n" % name) - for item in items: - self.compileenumerator(item) - self.fp.write("}\n\n") - self.enumcodes[code] = name + if self.fp: + self.fp.write("%s = {\n" % name) + for item in items: + self.compileenumerator(item) + self.fp.write("}\n\n") + self.namemappers[0].addnamecode('enum', name, code) return code def compileenumerator(self, item): @@ -628,28 +746,32 @@ class ObjectCompiler: """This enum code is used by an event. Make sure it's available""" name, fullname, module = self.findcodename('enum', enum) if not name: - self.fp.write("# XXXX enum %s not found!!\n"%(enum)) + if self.fp: + self.fp.write("# XXXX enum %s not found!!\n"%(enum)) return if module: - self.fp.write("from %s import %s\n"%(module, name)) + if self.fp: + self.fp.write("from %s import %s\n"%(module, name)) def dumpindex(self): + if not self.fp: + return self.fp.write("\n#\n# Indices of types declared in this module\n#\n") self.fp.write("_classdeclarations = {\n") - for k in self.classcodes.keys(): - self.fp.write("\t%s : %s,\n" % (`k`, self.classcodes[k])) + for k, v in self.namemappers[0].getall('class'): + self.fp.write("\t%s : %s,\n" % (`k`, v)) self.fp.write("}\n") self.fp.write("\n_propdeclarations = {\n") - for k in self.propcodes.keys(): - self.fp.write("\t%s : %s,\n" % (`k`, self.propcodes[k])) + for k, v in self.namemappers[0].getall('property'): + self.fp.write("\t%s : %s,\n" % (`k`, v)) self.fp.write("}\n") self.fp.write("\n_compdeclarations = {\n") - for k in self.compcodes.keys(): - self.fp.write("\t%s : %s,\n" % (`k`, self.compcodes[k])) + for k, v in self.namemappers[0].getall('comparison'): + self.fp.write("\t%s : %s,\n" % (`k`, v)) self.fp.write("}\n") self.fp.write("\n_enumdeclarations = {\n") - for k in self.enumcodes.keys(): - self.fp.write("\t%s : %s,\n" % (`k`, self.enumcodes[k])) + for k, v in self.namemappers[0].getall('enum'): + self.fp.write("\t%s : %s,\n" % (`k`, v)) self.fp.write("}\n") def compiledata(data): |