Home | History | Annotate | Download | only in bgen
      1 from bgenOutput import *
      2 from bgenType import *
      3 from bgenVariable import *
      4 
      5 
      6 Error = "bgenGenerator.Error"
      7 
      8 DEBUG=0
      9 
     10 # Strings to specify argument transfer modes in generator calls

     11 IN = "in"
     12 OUT = "out"
     13 INOUT = IN_OUT = "in-out"
     14 
     15 
     16 class 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', '"': '\\"'}
     86 def 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 
     98 class 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 
    112 class 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 
    277 class 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 
    288 def _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 
    301 if __name__ == "__main__":
    302     _test()
    303