]> granicus.if.org Git - python/commitdiff
Generate class, property and comparison code (finally!). The resulting
authorJack Jansen <jack.jansen@cwi.nl>
Fri, 8 Aug 1997 14:49:02 +0000 (14:49 +0000)
committerJack Jansen <jack.jansen@cwi.nl>
Fri, 8 Aug 1997 14:49:02 +0000 (14:49 +0000)
code isn't ideal yet: xxx.Window(1).Paragraph(3).font will only work
if all the classes and properties are declared in the same suite, but
at least font(Paragraph(3, Window(1))) always works.

Mac/scripts/gensuitemodule.py

index ff818fc585cf2db61f590e338ae380b3bfc0a974..53da22c1cea424fe76391402738d955b35596901 100644 (file)
@@ -39,7 +39,10 @@ def process(fullname):
                        print "decoding", res.GetResInfo(), "..."
                        data = res.data
                        aete = decode(data)
+                       # switch back (needed for dialogs in Python)
+                       UseResFile(cur)
                        compileaete(aete, fullname)
+                       UseResFile(rf)
        finally:
                if rf <> cur:
                        CloseResFile(rf)
@@ -237,27 +240,35 @@ def compilesuite(suite, major, minor, language, script, fname):
        fp.write('import MacOS\n\n')
        fp.write("_code = %s\n\n"% `code`)
        
-       enum_names = []
-       for enum in enums:
-               name = compileenumeration(fp, enum)
-               enum_names.append(enum)
-               
        compileclassheader(fp, modname)
+
+       enumsneeded = {}
        if events:
                for event in events:
-                       compileevent(fp, event)
+                       compileevent(fp, event, enumsneeded)
        else:
                fp.write("\tpass\n\n")
+
+       objc = ObjectCompiler(fp)
+       for cls in classes:
+               objc.compileclass(cls)
        for cls in classes:
-               compileclass(fp, cls)
+               objc.fillclasspropsandelems(cls)
        for comp in comps:
-               compilecomparison(fp, comp)
+               objc.compilecomparison(comp)
+       for enum in enums:
+               objc.compileenumeration(enum)
+       
+       for enum in enumsneeded.keys():
+               objc.checkforenum(enum)
+               
+       objc.dumpindex()
 
 def compileclassheader(fp, name):
        """Generate class boilerplate"""
        fp.write("class %s:\n\n"%name)
        
-def compileevent(fp, event):
+def compileevent(fp, event, enumsneeded):
        """Generate code for a single event"""
        [name, desc, code, subcode, returns, accepts, arguments] = event
        funcname = identify(name)
@@ -334,6 +345,7 @@ def compileevent(fp, event):
                        if ename <> '****':
                                fp.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
                                        (`kname`, ename))
+                               enumsneeded[ename] = 1
        fp.write("\n")
        #
        # Do the transaction
@@ -365,37 +377,182 @@ def compileargument(arg):
        [name, keyword, what] = arg
        print "#        %s (%s)" % (name, `keyword`), compiledata(what)
 
-def compileclass(fp, cls):
-       [name, code, desc, properties, elements] = cls
-       fp.write("\n#    Class %s (%s) -- %s\n" % (`name`, `code`, `desc`))
-       for prop in properties:
-               compileproperty(fp, prop)
-       for elem in elements:
-               compileelement(fp, elem)
-
-def compileproperty(fp, prop):
-       [name, code, what] = prop
-       fp.write("#        property %s (%s) %s\n" % (`name`, `code`, compiledata(what)))
-
-def compileelement(fp, elem):
-       [code, keyform] = elem
-       fp.write("#        element %s as %s\n" % (`code`, keyform))
-
-def compilecomparison(fp, comp):
-       [name, code, comment] = comp
-       fp.write("#    comparison  %s (%s) -- %s\n" % (`name`, `code`, comment))
-
-def compileenumeration(fp, enum):
-       [code, items] = enum
-       fp.write("_Enum_%s = {\n" % identify(code))
-       for item in items:
-               compileenumerator(fp, item)
-       fp.write("}\n\n")
-       return code
-
-def compileenumerator(fp, item):
-       [name, code, desc] = item
-       fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, desc))
+class ObjectCompiler:
+       def __init__(self, fp):
+               self.fp = fp
+               self.propnames = {}
+               self.classnames = {}
+               self.propcodes = {}
+               self.classcodes = {}
+               self.compcodes = {}
+               self.enumcodes = {}
+               self.othersuites = []
+               
+       def findcodename(self, type, code):
+               while 1:
+                       if type == 'property':
+                               if self.propcodes.has_key(code):
+                                       return self.propcodes[code], self.propcodes[code], None
+                               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
+                               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
+                               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
+                               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__
+                                               
+                       m = self.askdefinitionmodule(type, code)
+                       if not m: return None, None, None
+                       self.othersuites.append(m)
+       
+       def askdefinitionmodule(self, type, code):
+               fss, ok = macfs.PromptGetFile('Where is %s %s declared?'%(type, code))
+               if not ok: return
+               path, file = os.path.split(fss.as_pathname())
+               modname = os.path.splitext(file)[0]
+               if not path in sys.path:
+                       sys.path.insert(0, path)
+               m = __import__(modname)
+               self.fp.write("import %s\n"%modname)
+               return m
+               
+       def compileclass(self, cls):
+               [name, code, desc, properties, elements] = cls
+               pname = identify(name)
+               if self.classcodes.has_key(code):
+                       # plural forms and such
+                       self.fp.write("\n%s = %s\n"%(pname, self.classcodes[code]))
+                       self.classnames[pname] = code
+               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
+               for prop in properties:
+                       self.compileproperty(prop)
+               for elem in elements:
+                       self.compileelement(elem)
+       
+       def compileproperty(self, prop):
+               [name, code, what] = prop
+               if code == 'c@#!':
+                       # 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]))
+               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
+       
+       def compileelement(self, elem):
+               [code, keyform] = elem
+               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:
+                       # This is an other name (plural or so) for something else. Skip.
+                       return
+               plist = []
+               elist = []
+               for prop in properties:
+                       [pname, pcode, what] = prop
+                       if pcode == 'c@#!':
+                               continue
+                       pname = identify(pname)
+                       plist.append(pname)
+               for elem in elements:
+                       [ecode, keyform] = elem
+                       if ecode == 'c@#!':
+                               continue
+                       name, ename, module = self.findcodename('class', ecode)
+                       if not name:
+                               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")
+       
+       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))
+               
+       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
+               return code
+       
+       def compileenumerator(self, item):
+               [name, code, desc] = item
+               self.fp.write("\t%s : %s,\t# %s\n" % (`identify(name)`, `code`, desc))
+               
+       def checkforenum(self, enum):
+               """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))
+                       return
+               if module:
+                       self.fp.write("from %s import %s\n"%(module, name))
+               
+       def dumpindex(self):
+               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]))
+               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]))
+               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]))
+               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]))
+               self.fp.write("}\n")
 
 def compiledata(data):
        [type, description, flags] = data
@@ -432,7 +589,8 @@ def compiledataflags(flags):
        return '[%s]' % string.join(bits)
        
 # XXXX Do we have a set of python keywords somewhere?
-illegal_ids = [ "for", "in", "from", "and", "or", "not", "print" ]
+illegal_ids = [ "for", "in", "from", "and", "or", "not", "print", "class", "return",
+       "def" ]
 
 def identify(str):
        """Turn any string into an identifier:
@@ -440,6 +598,8 @@ def identify(str):
        - replace other illegal chars by _xx_ (hex code)
        - prepend _ if the result is a python keyword
        """
+       if not str:
+               return "_empty_ae_name"
        rv = ''
        ok = string.letters  + '_'
        ok2 = ok + string.digits