PageRenderTime 95ms CodeModel.GetById 38ms app.highlight 38ms RepoModel.GetById 15ms app.codeStats 0ms

/Tools/bgen/bgen/bgenGenerator.py

http://unladen-swallow.googlecode.com/
Python | 302 lines | 266 code | 35 blank | 1 comment | 45 complexity | b39ae914f3d2298b61dfd055d0745cc4 MD5 | raw file
  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()