1"""Functions.""" 2 3from framer import template 4from framer.util import cstring, unindent 5 6METH_O = "METH_O" 7METH_NOARGS = "METH_NOARGS" 8METH_VARARGS = "METH_VARARGS" 9 10def parsefmt(fmt): 11 for c in fmt: 12 if c == '|': 13 continue 14 yield c 15 16class 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 41class _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 59class 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 69class 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 79class 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 101def 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 124class 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 171class Method(Function): 172 173 method = True 174