Add better error reporting for MemoryErrors caused by str->float conversions.
[python.git] / Tools / framer / framer / function.py
blob306f7e986d30fe450c190f030e2602ed869f29f3
1 """Functions."""
3 from framer import template
4 from framer.util import cstring, unindent
6 METH_O = "METH_O"
7 METH_NOARGS = "METH_NOARGS"
8 METH_VARARGS = "METH_VARARGS"
10 def parsefmt(fmt):
11 for c in fmt:
12 if c == '|':
13 continue
14 yield c
16 class Argument:
18 def __init__(self, name):
19 self.name = name
20 self.ctype = "PyObject *"
21 self.default = None
23 def __str__(self):
24 return "%s%s" % (self.ctype, self.name)
26 def setfmt(self, code):
27 self.ctype = self._codes[code]
28 if self.ctype[-1] != "*":
29 self.ctype += " "
31 _codes = {"O": "PyObject *",
32 "i": "int",
35 def decl(self):
36 if self.default is None:
37 return str(self) + ";"
38 else:
39 return "%s = %s;" % (self, self.default)
41 class _ArgumentList(object):
43 # these instance variables should be initialized by subclasses
44 ml_meth = None
45 fmt = None
47 def __init__(self, args):
48 self.args = map(Argument, args)
50 def __len__(self):
51 return len(self.args)
53 def __getitem__(self, i):
54 return self.args[i]
56 def dump_decls(self, f):
57 pass
59 class NoArgs(_ArgumentList):
61 def __init__(self, args):
62 assert len(args) == 0
63 super(NoArgs, self).__init__(args)
64 self.ml_meth = METH_NOARGS
66 def c_args(self):
67 return "PyObject *self"
69 class OneArg(_ArgumentList):
71 def __init__(self, args):
72 assert len(args) == 1
73 super(OneArg, self).__init__(args)
74 self.ml_meth = METH_O
76 def c_args(self):
77 return "PyObject *self, %s" % self.args[0]
79 class VarArgs(_ArgumentList):
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
91 def c_args(self):
92 return "PyObject *self, PyObject *args"
94 def targets(self):
95 return ", ".join(["&%s" % a.name for a in self.args])
97 def dump_decls(self, f):
98 for a in self.args:
99 print >> f, " %s" % a.decl()
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)
124 class Function:
126 method = False
128 def __init__(self, func, parent):
129 self._func = func
130 self._parent = parent
131 self.analyze()
132 self.initvars()
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
140 if self.__doc__:
141 p(template.docstring)
143 d = {"name" : self.vars["CName"],
144 "args" : self.args.c_args(),
146 p(template.funcdef_start, d)
148 self.args.dump_decls(f)
150 if self.args.ml_meth == METH_VARARGS:
151 p(template.varargs)
153 p(template.funcdef_end)
155 def analyze(self):
156 self.__doc__ = self._func.__doc__
157 self.args = ArgumentList(self._func, self.method)
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()
171 class Method(Function):
173 method = True