genmodule.py 4.71 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#
# Genmodule - A python program to help you build (template) modules.
#
# Usage:
#
# o = genmodule.object()
# o.name = 'dwarve object'
# o.abbrev = 'dw'
# o.funclist = ['new', 'dealloc', 'getattr', 'setattr']
# o.methodlist = ['dig']
#
# m = genmodule.module()
# m.name = 'beings'
# m.abbrev = 'be'
# m.methodlist = ['newdwarve']
# m.objects = [o]
#
# genmodule.write(sys.stdout, m)
#
import sys
import os
import varsubst

error = 'genmodule.error'

#
# Names of functions in the object-description struct.
#
FUNCLIST = ['new', 'tp_dealloc', 'tp_print', 'tp_getattr', 'tp_setattr',
Guido van Rossum's avatar
Guido van Rossum committed
30
            'tp_compare', 'tp_repr', 'tp_hash', 'tp_call', 'tp_str']
31 32 33 34 35 36 37 38
TYPELIST = ['tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'structure']

#
# writer is a base class for the object and module classes
# it contains code common to both.
#
class writer:
    def __init__(self):
Guido van Rossum's avatar
Guido van Rossum committed
39
        self._subst = None
40 41

    def makesubst(self):
Guido van Rossum's avatar
Guido van Rossum committed
42 43 44
        if not self._subst:
            if not self.__dict__.has_key('abbrev'):
                self.abbrev = self.name
45
            self.Abbrev = self.abbrev[0].upper()+self.abbrev[1:]
Guido van Rossum's avatar
Guido van Rossum committed
46 47 48
            subst = varsubst.Varsubst(self.__dict__)
            subst.useindent(1)
            self._subst = subst.subst
49 50

    def addcode(self, name, fp):
Guido van Rossum's avatar
Guido van Rossum committed
51 52 53 54 55
        ifp = self.opentemplate(name)
        self.makesubst()
        d = ifp.read()
        d = self._subst(d)
        fp.write(d)
56 57

    def opentemplate(self, name):
Guido van Rossum's avatar
Guido van Rossum committed
58 59 60 61 62 63 64 65 66 67
        for p in sys.path:
            fn = os.path.join(p, name)
            if os.path.exists(fn):
                return open(fn, 'r')
            fn = os.path.join(p, 'Templates')
            fn = os.path.join(fn, name)
            if os.path.exists(fn):
                return open(fn, 'r')
        raise error, 'Template '+name+' not found for '+self._type+' '+ \
                     self.name
68

69 70 71 72
class module(writer):
    _type = 'module'

    def writecode(self, fp):
Guido van Rossum's avatar
Guido van Rossum committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
        self.addcode('copyright', fp)
        self.addcode('module_head', fp)
        for o in self.objects:
            o.writehead(fp)
        for o in self.objects:
            o.writebody(fp)
        new_ml = ''
        for fn in self.methodlist:
            self.method = fn
            self.addcode('module_method', fp)
            new_ml = new_ml + (
                      '{"%s",\t(PyCFunction)%s_%s,\tMETH_VARARGS,\t%s_%s__doc__},\n'
                      %(fn, self.abbrev, fn, self.abbrev, fn))
        self.methodlist = new_ml
        self.addcode('module_tail', fp)
88 89 90 91

class object(writer):
    _type = 'object'
    def __init__(self):
Guido van Rossum's avatar
Guido van Rossum committed
92 93 94 95
        self.typelist = []
        self.methodlist = []
        self.funclist = ['new']
        writer.__init__(self)
96 97

    def writecode(self, fp):
Guido van Rossum's avatar
Guido van Rossum committed
98 99 100
        self.addcode('copyright', fp)
        self.writehead(fp)
        self.writebody(fp)
101 102

    def writehead(self, fp):
Guido van Rossum's avatar
Guido van Rossum committed
103
        self.addcode('object_head', fp)
104 105

    def writebody(self, fp):
Guido van Rossum's avatar
Guido van Rossum committed
106 107 108 109 110 111 112 113 114
        new_ml = ''
        for fn in self.methodlist:
            self.method = fn
            self.addcode('object_method', fp)
            new_ml = new_ml + (
                      '{"%s",\t(PyCFunction)%s_%s,\tMETH_VARARGS,\t%s_%s__doc__},\n'
                      %(fn, self.abbrev, fn, self.abbrev, fn))
        self.methodlist = new_ml
        self.addcode('object_mlist', fp)
115

Guido van Rossum's avatar
Guido van Rossum committed
116 117 118
        # Add getattr if we have methods
        if self.methodlist and not 'tp_getattr' in self.funclist:
            self.funclist.insert(0, 'tp_getattr')
119

Guido van Rossum's avatar
Guido van Rossum committed
120 121
        for fn in FUNCLIST:
            setattr(self, fn, '0')
122

Guido van Rossum's avatar
Guido van Rossum committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
        #
        # Special case for structure-access objects: put getattr in the
        # list of functions but don't generate code for it directly,
        # the code is obtained from the object_structure template.
        # The same goes for setattr.
        #
        if 'structure' in self.typelist:
            if 'tp_getattr' in self.funclist:
                self.funclist.remove('tp_getattr')
            if 'tp_setattr' in self.funclist:
                self.funclist.remove('tp_setattr')
            self.tp_getattr = self.abbrev + '_getattr'
            self.tp_setattr = self.abbrev + '_setattr'
        for fn in self.funclist:
            self.addcode('object_'+fn, fp)
            setattr(self, fn, '%s_%s'%(self.abbrev, fn[3:]))
        for tn in TYPELIST:
            setattr(self, tn, '0')
        for tn in self.typelist:
            self.addcode('object_'+tn, fp)
            setattr(self, tn, '&%s_%s'%(self.abbrev, tn[3:]))
        self.addcode('object_tail', fp)
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

def write(fp, obj):
    obj.writecode(fp)

if __name__ == '__main__':
    o = object()
    o.name = 'dwarve object'
    o.abbrev = 'dw'
    o.funclist = ['new', 'tp_dealloc']
    o.methodlist = ['dig']
    m = module()
    m.name = 'beings'
    m.abbrev = 'be'
    m.methodlist = ['newdwarve']
    m.objects = [o]
    write(sys.stdout, m)