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