• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from bgenOutput import *
2from bgenType import *
3from bgenVariable import *
4
5
6Error = "bgenGenerator.Error"
7
8DEBUG=0
9
10# Strings to specify argument transfer modes in generator calls
11IN = "in"
12OUT = "out"
13INOUT = IN_OUT = "in-out"
14
15
16class BaseFunctionGenerator:
17
18    def __init__(self, name, condition=None, callname=None, modifiers=None):
19        if DEBUG: print "<--", name
20        self.name = name
21        if callname:
22            self.callname = callname
23        else:
24            self.callname = name
25        self.prefix = name
26        self.objecttype = "PyObject" # Type of _self argument to function
27        self.condition = condition
28        self.modifiers = modifiers
29
30    def setprefix(self, prefix):
31        self.prefix = prefix
32
33    def checkgenerate(self):
34        return True
35
36    def generate(self):
37        if not self.checkgenerate():
38            return
39        if DEBUG: print "-->", self.name
40        if self.condition:
41            Output()
42            Output(self.condition)
43        self.functionheader()
44        self.functionbody()
45        self.functiontrailer()
46        if self.condition:
47            Output("#endif")
48
49    def functionheader(self):
50        Output()
51        Output("static PyObject *%s_%s(%s *_self, PyObject *_args)",
52               self.prefix, self.name, self.objecttype)
53        OutLbrace()
54        Output("PyObject *_res = NULL;")
55
56    def functionbody(self):
57        Output("/* XXX To be provided */")
58
59    def functiontrailer(self):
60        OutRbrace()
61
62    def reference(self, name = None):
63        if not self.checkgenerate():
64            return
65        if name is None:
66            name = self.name
67        docstring = self.docstring()
68        if self.condition:
69            Output()
70            Output(self.condition)
71        Output("{\"%s\", (PyCFunction)%s_%s, 1,", name, self.prefix, self.name)
72        Output(" PyDoc_STR(%s)},", stringify(docstring))
73        if self.condition:
74            Output("#endif")
75
76    def docstring(self):
77        return None
78
79    def __cmp__(self, other):
80        if not hasattr(other, 'name'):
81            return cmp(id(self), id(other))
82        return cmp(self.name, other.name)
83
84_stringify_map = {'\n': '\\n', '\t': '\\t', '\r': '\\r', '\b': '\\b',
85                  '\e': '\\e', '\a': '\\a', '\f': '\\f', '"': '\\"'}
86def stringify(str):
87    if str is None: return "NULL"
88    res = '"'
89    map = _stringify_map
90    for c in str:
91        if map.has_key(c): res = res + map[c]
92        elif ' ' <= c <= '~': res = res + c
93        else: res = res + '\\%03o' % ord(c)
94    res = res + '"'
95    return res
96
97
98class ManualGenerator(BaseFunctionGenerator):
99
100    def __init__(self, name, body, condition=None):
101        BaseFunctionGenerator.__init__(self, name, condition=condition)
102        self.body = body
103
104    def functionbody(self):
105        Output("%s", self.body)
106
107    def setselftype(self, selftype, itselftype):
108        self.objecttype = selftype
109        self.itselftype = itselftype
110
111
112class FunctionGenerator(BaseFunctionGenerator):
113
114    def __init__(self, returntype, name, *argumentList, **conditionlist):
115        BaseFunctionGenerator.__init__(self, name, **conditionlist)
116        self.returntype = returntype
117        self.argumentList = []
118        self.setreturnvar()
119        self.parseArgumentList(argumentList)
120        self.prefix     = "XXX"    # Will be changed by setprefix() call
121        self.itselftype = None     # Type of _self->ob_itself, if defined
122
123    def setreturnvar(self):
124        if self.returntype:
125            self.rv = self.makereturnvar()
126            self.argumentList.append(self.rv)
127        else:
128            self.rv = None
129
130    def makereturnvar(self):
131        return Variable(self.returntype, "_rv", OutMode)
132
133    def setselftype(self, selftype, itselftype):
134        self.objecttype = selftype
135        self.itselftype = itselftype
136
137    def parseArgumentList(self, argumentList):
138        iarg = 0
139        for type, name, mode in argumentList:
140            iarg = iarg + 1
141            if name is None: name = "_arg%d" % iarg
142            arg = Variable(type, name, mode)
143            self.argumentList.append(arg)
144
145    def docstring(self):
146        input = []
147        output = []
148        for arg in self.argumentList:
149            if arg.flags == ErrorMode or arg.flags == SelfMode:
150                continue
151            if arg.type is None:
152                str = 'void'
153            else:
154                if hasattr(arg.type, 'typeName'):
155                    typeName = arg.type.typeName
156                    if typeName is None: # Suppressed type
157                        continue
158                else:
159                    typeName = "?"
160                    print "Nameless type", arg.type
161
162                str = typeName + ' ' + arg.name
163            if arg.mode in (InMode, InOutMode):
164                input.append(str)
165            if arg.mode in (InOutMode, OutMode):
166                output.append(str)
167        if not input:
168            instr = "()"
169        else:
170            instr = "(%s)" % ", ".join(input)
171        if not output or output == ["void"]:
172            outstr = "None"
173        else:
174            outstr = "(%s)" % ", ".join(output)
175        return instr + " -> " + outstr
176
177    def functionbody(self):
178        self.declarations()
179        self.precheck()
180        self.getargs()
181        self.callit()
182        self.checkit()
183        self.returnvalue()
184
185    def declarations(self):
186        for arg in self.argumentList:
187            arg.declare()
188
189    def getargs(self):
190        sep = ",\n" + ' '*len("if (!PyArg_ParseTuple(")
191        fmt, lst = self.getargsFormatArgs(sep)
192        Output("if (!PyArg_ParseTuple(_args, \"%s\"%s))", fmt, lst)
193        IndentLevel()
194        Output("return NULL;")
195        DedentLevel()
196        for arg in self.argumentList:
197            if arg.flags == SelfMode:
198                continue
199            if arg.mode in (InMode, InOutMode):
200                arg.getargsCheck()
201
202    def getargsFormatArgs(self, sep):
203        fmt = ""
204        lst = ""
205        for arg in self.argumentList:
206            if arg.flags == SelfMode:
207                continue
208            if arg.mode in (InMode, InOutMode):
209                arg.getargsPreCheck()
210                fmt = fmt + arg.getargsFormat()
211                args = arg.getargsArgs()
212                if args:
213                    lst = lst + sep + args
214        return fmt, lst
215
216    def precheck(self):
217        pass
218
219    def beginallowthreads(self):
220        pass
221
222    def endallowthreads(self):
223        pass
224
225    def callit(self):
226        args = ""
227        s = "%s%s(" % (self.getrvforcallit(), self.callname)
228        sep = ",\n" + ' '*len(s)
229        for arg in self.argumentList:
230            if arg is self.rv:
231                continue
232            s = arg.passArgument()
233            if args: s = sep + s
234            args = args + s
235        self.beginallowthreads()
236        Output("%s%s(%s);",
237               self.getrvforcallit(), self.callname, args)
238        self.endallowthreads()
239
240    def getrvforcallit(self):
241        if self.rv:
242            return "%s = " % self.rv.name
243        else:
244            return ""
245
246    def checkit(self):
247        for arg in self.argumentList:
248            arg.errorCheck()
249
250    def returnvalue(self):
251        sep = ",\n" + ' '*len("return Py_BuildValue(")
252        fmt, lst = self.mkvalueFormatArgs(sep)
253        if fmt == "":
254            Output("Py_INCREF(Py_None);")
255            Output("_res = Py_None;");
256        else:
257            Output("_res = Py_BuildValue(\"%s\"%s);", fmt, lst)
258        tmp = self.argumentList[:]
259        tmp.reverse()
260        for arg in tmp:
261            if not arg: continue
262            arg.cleanup()
263        Output("return _res;")
264
265    def mkvalueFormatArgs(self, sep):
266        fmt = ""
267        lst = ""
268        for arg in self.argumentList:
269            if not arg: continue
270            if arg.flags == ErrorMode: continue
271            if arg.mode in (OutMode, InOutMode):
272                arg.mkvaluePreCheck()
273                fmt = fmt + arg.mkvalueFormat()
274                lst = lst + sep + arg.mkvalueArgs()
275        return fmt, lst
276
277class MethodGenerator(FunctionGenerator):
278
279    def parseArgumentList(self, args):
280        a0, args = args[0], args[1:]
281        t0, n0, m0 = a0
282        if m0 != InMode:
283            raise ValueError, "method's 'self' must be 'InMode'"
284        self.itself = Variable(t0, "_self->ob_itself", SelfMode)
285        self.argumentList.append(self.itself)
286        FunctionGenerator.parseArgumentList(self, args)
287
288def _test():
289    void = None
290    eggs = FunctionGenerator(void, "eggs",
291                 (stringptr, 'cmd', InMode),
292                 (int, 'x', InMode),
293                 (double, 'y', InOutMode),
294                 (int, 'status', ErrorMode),
295                 )
296    eggs.setprefix("spam")
297    print "/* START */"
298    eggs.generate()
299
300
301if __name__ == "__main__":
302    _test()
303