summaryrefslogtreecommitdiffstats
path: root/Tools/modulator/genmodule.py
blob: f8703efe698724d5eb9cadb07e2d3bea19d177f3 (plain)
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#
# 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',
            'tp_compare', 'tp_repr', 'tp_hash', 'tp_call', 'tp_str']
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):
        self._subst = None

    def makesubst(self):
        if not self._subst:
            if 'abbrev' not in self.__dict__:
                self.abbrev = self.name
            self.Abbrev = self.abbrev[0].upper()+self.abbrev[1:]
            subst = varsubst.Varsubst(self.__dict__)
            subst.useindent(1)
            self._subst = subst.subst

    def addcode(self, name, fp):
        ifp = self.opentemplate(name)
        self.makesubst()
        d = ifp.read()
        d = self._subst(d)
        fp.write(d)

    def opentemplate(self, name):
        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)

class module(writer):
    _type = 'module'

    def writecode(self, fp):
        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)

class object(writer):
    _type = 'object'
    def __init__(self):
        self.typelist = []
        self.methodlist = []
        self.funclist = ['new']
        writer.__init__(self)

    def writecode(self, fp):
        self.addcode('copyright', fp)
        self.writehead(fp)
        self.writebody(fp)

    def writehead(self, fp):
        self.addcode('object_head', fp)

    def writebody(self, fp):
        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)

        # Add getattr if we have methods
        if self.methodlist and not 'tp_getattr' in self.funclist:
            self.funclist.insert(0, 'tp_getattr')

        for fn in FUNCLIST:
            setattr(self, fn, '0')

        #
        # 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)

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)