Commit 60762cb9 authored by Jack Jansen's avatar Jack Jansen

Generate packages in stead of separate modules. The package main module...

Generate packages in stead of separate modules. The package main module imports everything, it knows about the app signature, suites can extend standard suites, and lots more. Automatically finding declarations in other suites TBD.
parent fb106c8c
""" """
gensuitemodule - Generate an AE suite module from an aete/aeut resource gensuitemodule - Generate an AE suite module from an aete/aeut resource
Based on aete.py Based on aete.py.
Reading and understanding this code is left as an exercise to the reader.
""" """
import MacOS import MacOS
...@@ -18,9 +20,9 @@ def main(): ...@@ -18,9 +20,9 @@ def main():
fss, ok = macfs.PromptGetFile('Select file with aeut/aete resource:') fss, ok = macfs.PromptGetFile('Select file with aeut/aete resource:')
if not ok: if not ok:
sys.exit(0) sys.exit(0)
process(fss.as_pathname()) processfile(fss.as_pathname())
def process(fullname): def processfile(fullname):
"""Process all resources in a single file""" """Process all resources in a single file"""
cur = CurResFile() cur = CurResFile()
print fullname print fullname
...@@ -35,18 +37,23 @@ def process(fullname): ...@@ -35,18 +37,23 @@ def process(fullname):
res = Get1IndResource('aeut', 1+i) res = Get1IndResource('aeut', 1+i)
resources.append(res) resources.append(res)
print "\nLISTING aete+aeut RESOURCES IN", `fullname` print "\nLISTING aete+aeut RESOURCES IN", `fullname`
aetelist = []
for res in resources: for res in resources:
print "decoding", res.GetResInfo(), "..." print "decoding", res.GetResInfo(), "..."
data = res.data data = res.data
aete = decode(data) aete = decode(data)
# switch back (needed for dialogs in Python) aetelist.append((aete, res.GetResInfo()))
UseResFile(cur)
compileaete(aete, fullname)
UseResFile(rf)
finally: finally:
if rf <> cur: if rf <> cur:
CloseResFile(rf) CloseResFile(rf)
UseResFile(cur) UseResFile(cur)
# switch back (needed for dialogs in Python)
UseResFile(cur)
compileaetelist(aetelist, fullname)
def compileaetelist(aetelist, fullname):
for aete, resinfo in aetelist:
compileaete(aete, resinfo, fullname)
def decode(data): def decode(data):
"""Decode a resource into a python data structure""" """Decode a resource into a python data structure"""
...@@ -211,21 +218,81 @@ getaete = [ ...@@ -211,21 +218,81 @@ getaete = [
(getlist, "suites", getsuite) (getlist, "suites", getsuite)
] ]
def compileaete(aete, fname): def compileaete(aete, resinfo, fname):
"""Generate code for a full aete resource. fname passed for doc purposes""" """Generate code for a full aete resource. fname passed for doc purposes"""
[version, language, script, suites] = aete [version, language, script, suites] = aete
major, minor = divmod(version, 256) major, minor = divmod(version, 256)
fss = macfs.FSSpec(fname)
creatorsignature, dummy = fss.GetCreatorType()
packagename = identify(os.path.basename(fname))
if language:
packagename = packagename+'_lang%d'%language
if script:
packagename = packagename+'_script%d'%script
if len(packagename) > 27:
packagename = packagename[:27]
macfs.SetFolder(os.path.join(sys.prefix, ':Mac:Lib:lib-scriptpackages'))
fss, ok = macfs.GetDirectory('Package folder for %s'%packagename)
if not ok:
return
pathname = fss.as_pathname()
packagename = os.path.split(os.path.normpath(pathname))[1]
fss, ok = macfs.GetDirectory('Package folder for base suite (usually StdSuites)')
if ok:
dirname, basepkgname = os.path.split(os.path.normpath(fss.as_pathname()))
if not dirname in sys.path:
sys.path.insert(0, dirname)
basepackage = __import__(basepkgname)
else:
basepackage = None
macfs.SetFolder(pathname)
suitelist = []
for suite in suites: for suite in suites:
compilesuite(suite, major, minor, language, script, fname) code, modname = compilesuite(suite, major, minor, language, script, fname, basepackage)
if modname:
def compilesuite(suite, major, minor, language, script, fname): suitelist.append((code, modname))
fss, ok = macfs.StandardPutFile('Package module', '__init__.py')
if not ok:
return
fp = open(fss.as_pathname(), 'w')
fss.SetCreatorType('Pyth', 'TEXT')
fp.write('"""\n')
fp.write("Package generated from %s\n"%fname)
fp.write("Resource %s resid %d %s\n"%(resinfo[1], resinfo[0], resinfo[2]))
fp.write('"""\n')
fp.write('import aetools\n')
for code, modname in suitelist:
fp.write("import %s\n" % modname)
fp.write("\n\n_code_to_module = {\n")
for code, modname in suitelist:
fp.write("\t'%s' : %s,\n"%(code, modname))
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("}\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("\t_signature = '%s'\n\n"%creatorsignature)
fp.close()
def compilesuite(suite, major, minor, language, script, fname, basepackage=None):
"""Generate code for a single suite""" """Generate code for a single suite"""
[name, desc, code, level, version, events, classes, comps, enums] = suite [name, desc, code, level, version, events, classes, comps, enums] = suite
modname = identify(name) modname = identify(name)
if len(modname) > 28:
modname = modname[:27]
fss, ok = macfs.StandardPutFile('Python output file', modname+'.py') fss, ok = macfs.StandardPutFile('Python output file', modname+'.py')
if not ok: if not ok:
return return None, None
pathname = fss.as_pathname()
modname = os.path.splitext(os.path.split(pathname)[1])[0]
fp = open(fss.as_pathname(), 'w') fp = open(fss.as_pathname(), 'w')
fss.SetCreatorType('Pyth', 'TEXT') fss.SetCreatorType('Pyth', 'TEXT')
...@@ -239,8 +306,15 @@ def compilesuite(suite, major, minor, language, script, fname): ...@@ -239,8 +306,15 @@ def compilesuite(suite, major, minor, language, script, fname):
fp.write('import aetools\n') fp.write('import aetools\n')
fp.write('import MacOS\n\n') fp.write('import MacOS\n\n')
fp.write("_code = %s\n\n"% `code`) fp.write("_code = %s\n\n"% `code`)
if basepackage and basepackage._code_to_module.has_key(code):
compileclassheader(fp, modname) # 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])
basemodule = basepackage._code_to_module[code]
else:
# We are not an extension.
basemodule = None
compileclassheader(fp, modname, basemodule)
enumsneeded = {} enumsneeded = {}
if events: if events:
...@@ -249,7 +323,7 @@ def compilesuite(suite, major, minor, language, script, fname): ...@@ -249,7 +323,7 @@ def compilesuite(suite, major, minor, language, script, fname):
else: else:
fp.write("\tpass\n\n") fp.write("\tpass\n\n")
objc = ObjectCompiler(fp) objc = ObjectCompiler(fp, basemodule)
for cls in classes: for cls in classes:
objc.compileclass(cls) objc.compileclass(cls)
for cls in classes: for cls in classes:
...@@ -264,9 +338,15 @@ def compilesuite(suite, major, minor, language, script, fname): ...@@ -264,9 +338,15 @@ def compilesuite(suite, major, minor, language, script, fname):
objc.dumpindex() objc.dumpindex()
def compileclassheader(fp, name): return code, modname
def compileclassheader(fp, name, module=None):
"""Generate class boilerplate""" """Generate class boilerplate"""
fp.write("class %s:\n\n"%name) classname = '%s_Events'%name
if module and hasattr(module, classname):
fp.write("class %s(%s):\n\n"%(classname, classname))
else:
fp.write("class %s:\n\n"%classname)
def compileevent(fp, event, enumsneeded): def compileevent(fp, event, enumsneeded):
"""Generate code for a single event""" """Generate code for a single event"""
...@@ -378,7 +458,7 @@ def compileargument(arg): ...@@ -378,7 +458,7 @@ def compileargument(arg):
print "# %s (%s)" % (name, `keyword`), compiledata(what) print "# %s (%s)" % (name, `keyword`), compiledata(what)
class ObjectCompiler: class ObjectCompiler:
def __init__(self, fp): def __init__(self, fp, basesuite=None):
self.fp = fp self.fp = fp
self.propnames = {} self.propnames = {}
self.classnames = {} self.classnames = {}
...@@ -387,12 +467,20 @@ class ObjectCompiler: ...@@ -387,12 +467,20 @@ class ObjectCompiler:
self.compcodes = {} self.compcodes = {}
self.enumcodes = {} self.enumcodes = {}
self.othersuites = [] self.othersuites = []
self.basesuite = basesuite
def findcodename(self, type, code): def findcodename(self, type, code):
while 1: while 1:
if type == 'property': if type == 'property':
# First we check whether we ourselves have defined it
if self.propcodes.has_key(code): if self.propcodes.has_key(code):
return self.propcodes[code], self.propcodes[code], None 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: for s in self.othersuites:
if s._propdeclarations.has_key(code): if s._propdeclarations.has_key(code):
name = s._propdeclarations[code].__name__ name = s._propdeclarations[code].__name__
...@@ -400,6 +488,9 @@ class ObjectCompiler: ...@@ -400,6 +488,9 @@ class ObjectCompiler:
if type == 'class': if type == 'class':
if self.classcodes.has_key(code): if self.classcodes.has_key(code):
return self.classcodes[code], self.classcodes[code], None 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: for s in self.othersuites:
if s._classdeclarations.has_key(code): if s._classdeclarations.has_key(code):
name = s._classdeclarations[code].__name__ name = s._classdeclarations[code].__name__
...@@ -407,6 +498,9 @@ class ObjectCompiler: ...@@ -407,6 +498,9 @@ class ObjectCompiler:
if type == 'enum': if type == 'enum':
if self.enumcodes.has_key(code): if self.enumcodes.has_key(code):
return self.enumcodes[code], self.enumcodes[code], None 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: for s in self.othersuites:
if s._enumdeclarations.has_key(code): if s._enumdeclarations.has_key(code):
name = '_Enum_' + identify(code) name = '_Enum_' + identify(code)
...@@ -414,11 +508,15 @@ class ObjectCompiler: ...@@ -414,11 +508,15 @@ class ObjectCompiler:
if type == 'comparison': if type == 'comparison':
if self.compcodes.has_key(code): if self.compcodes.has_key(code):
return self.compcodes[code], self.compcodes[code], None 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: for s in self.othersuites:
if s._compdeclarations.has_key(code): if s._compdeclarations.has_key(code):
name = s._compdeclarations[code].__name__ name = s._compdeclarations[code].__name__
return name, '%s.%s' % (s.__name__, name), s.__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) m = self.askdefinitionmodule(type, code)
if not m: return None, None, None if not m: return None, None, None
self.othersuites.append(m) self.othersuites.append(m)
...@@ -443,7 +541,7 @@ class ObjectCompiler: ...@@ -443,7 +541,7 @@ class ObjectCompiler:
self.classnames[pname] = code self.classnames[pname] = code
else: else:
self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname) self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
self.fp.write('\t"""%s - %s"""\n' % (name, desc)) self.fp.write('\t"""%s - %s """\n' % (name, desc))
self.fp.write('\twant = %s\n' % `code`) self.fp.write('\twant = %s\n' % `code`)
self.classnames[pname] = code self.classnames[pname] = code
self.classcodes[code] = pname self.classcodes[code] = pname
...@@ -462,7 +560,7 @@ class ObjectCompiler: ...@@ -462,7 +560,7 @@ class ObjectCompiler:
self.fp.write("# repeated property %s %s\n"%(pname, what[1])) self.fp.write("# repeated property %s %s\n"%(pname, what[1]))
else: else:
self.fp.write("class %s(aetools.NProperty):\n" % pname) self.fp.write("class %s(aetools.NProperty):\n" % pname)
self.fp.write('\t"""%s - %s"""\n' % (name, what[1])) self.fp.write('\t"""%s - %s """\n' % (name, what[1]))
self.fp.write("\twhich = %s\n" % `code`) self.fp.write("\twhich = %s\n" % `code`)
self.fp.write("\twant = %s\n" % `what[0]`) self.fp.write("\twant = %s\n" % `what[0]`)
self.propnames[pname] = code self.propnames[pname] = code
...@@ -510,7 +608,7 @@ class ObjectCompiler: ...@@ -510,7 +608,7 @@ class ObjectCompiler:
iname = identify(name) iname = identify(name)
self.compcodes[code] = iname self.compcodes[code] = iname
self.fp.write("class %s(aetools.NComparison):\n" % iname) self.fp.write("class %s(aetools.NComparison):\n" % iname)
self.fp.write('\t"""%s - %s"""\n' % (name, comment)) self.fp.write('\t"""%s - %s """\n' % (name, comment))
def compileenumeration(self, enum): def compileenumeration(self, enum):
[code, items] = enum [code, items] = enum
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment