Home | History | Annotate | Download | only in framer
      1 """Functions."""
      2 
      3 from framer import template
      4 from framer.util import cstring, unindent
      5 
      6 METH_O = "METH_O"
      7 METH_NOARGS = "METH_NOARGS"
      8 METH_VARARGS = "METH_VARARGS"
      9 
     10 def parsefmt(fmt):
     11     for c in fmt:
     12         if c == '|':
     13             continue
     14         yield c
     15 
     16 class Argument:
     17 
     18     def __init__(self, name):
     19         self.name = name
     20         self.ctype = "PyObject *"
     21         self.default = None
     22 
     23     def __str__(self):
     24         return "%s%s" % (self.ctype, self.name)
     25 
     26     def setfmt(self, code):
     27         self.ctype = self._codes[code]
     28         if self.ctype[-1] != "*":
     29             self.ctype += " "
     30 
     31     _codes = {"O": "PyObject *",
     32               "i": "int",
     33               }
     34 
     35     def decl(self):
     36         if self.default is None:
     37             return str(self) + ";"
     38         else:
     39             return "%s = %s;" % (self, self.default)
     40 
     41 class _ArgumentList(object):
     42 
     43     # these instance variables should be initialized by subclasses
     44     ml_meth = None
     45     fmt = None
     46 
     47     def __init__(self, args):
     48         self.args = map(Argument, args)
     49 
     50     def __len__(self):
     51         return len(self.args)
     52 
     53     def __getitem__(self, i):
     54         return self.args[i]
     55 
     56     def dump_decls(self, f):
     57         pass
     58 
     59 class NoArgs(_ArgumentList):
     60 
     61     def __init__(self, args):
     62         assert len(args) == 0
     63         super(NoArgs, self).__init__(args)
     64         self.ml_meth = METH_NOARGS
     65 
     66     def c_args(self):
     67         return "PyObject *self"
     68 
     69 class OneArg(_ArgumentList):
     70 
     71     def __init__(self, args):
     72         assert len(args) == 1
     73         super(OneArg, self).__init__(args)
     74         self.ml_meth = METH_O
     75 
     76     def c_args(self):
     77         return "PyObject *self, %s" % self.args[0]
     78 
     79 class VarArgs(_ArgumentList):
     80 
     81     def __init__(self, args, fmt=None):
     82         super(VarArgs, self).__init__(args)
     83         self.ml_meth = METH_VARARGS
     84         if fmt is not None:
     85             self.fmt = fmt
     86             i = 0
     87             for code in parsefmt(fmt):
     88                 self.args[i].setfmt(code)
     89                 i += 1
     90 
     91     def c_args(self):
     92         return "PyObject *self, PyObject *args"
     93 
     94     def targets(self):
     95         return ", ".join(["&%s" % a.name for a in self.args])
     96 
     97     def dump_decls(self, f):
     98         for a in self.args:
     99             print >> f, "        %s" % a.decl()
    100 
    101 def ArgumentList(func, method):
    102     code = func.func_code
    103     args = code.co_varnames[:code.co_argcount]
    104     if method:
    105         args = args[1:]
    106     pyarg = getattr(func, "pyarg", None)
    107     if pyarg is not None:
    108         args = VarArgs(args, pyarg)
    109         if func.func_defaults:
    110             L = list(func.func_defaults)
    111             ndefault = len(L)
    112             i = len(args) - ndefault
    113             while L:
    114                 args[i].default = L.pop(0)
    115         return args
    116     else:
    117         if len(args) == 0:
    118             return NoArgs(args)
    119         elif len(args) == 1:
    120             return OneArg(args)
    121         else:
    122             return VarArgs(args)
    123 
    124 class Function:
    125 
    126     method = False
    127 
    128     def __init__(self, func, parent):
    129         self._func = func
    130         self._parent = parent
    131         self.analyze()
    132         self.initvars()
    133 
    134     def dump(self, f):
    135         def p(templ, vars=None): # helper function to generate output
    136             if vars is None:
    137                 vars = self.vars
    138             print >> f, templ % vars
    139 
    140         if self.__doc__:
    141             p(template.docstring)
    142 
    143         d = {"name" : self.vars["CName"],
    144              "args" : self.args.c_args(),
    145              }
    146         p(template.funcdef_start, d)
    147 
    148         self.args.dump_decls(f)
    149 
    150         if self.args.ml_meth == METH_VARARGS:
    151             p(template.varargs)
    152 
    153         p(template.funcdef_end)
    154 
    155     def analyze(self):
    156         self.__doc__ = self._func.__doc__
    157         self.args = ArgumentList(self._func, self.method)
    158 
    159     def initvars(self):
    160         v = self.vars = {}
    161         v["PythonName"] = self._func.__name__
    162         s = v["CName"] = "%s_%s" % (self._parent.name, self._func.__name__)
    163         v["DocstringVar"] = s + "_doc"
    164         v["MethType"] = self.args.ml_meth
    165         if self.__doc__:
    166             v["Docstring"] = cstring(unindent(self.__doc__))
    167         if self.args.fmt is not None:
    168             v["ArgParse"] = self.args.fmt
    169             v["ArgTargets"] = self.args.targets()
    170 
    171 class Method(Function):
    172 
    173     method = True
    174